[Scummvm-git-logs] scummvm master -> 52e97492b88e1e32661927767562208a7649f2a3
dreammaster
noreply at scummvm.org
Mon Apr 20 05:32:59 UTC 2026
This automated email contains information about 198 new commits which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .
Summary:
39cb737e24 MADS: PHANTOM: Remove existing Phantom codebase
8657c26940 MADS: PHANTOM: Adding main_menu.cpp, dependent headers
fe4d1049b4 MADS: PHANTOM: Engine class, start of main menu startup code
ad3a8d9574 MADS: PHANTOM: In progress hooking up startup code dependencies
49ac71da4c MADS: PHANTOM: Further import of dependent code
185ccb3bd3 MADS: PHANTOM: Adding more core dependencies
69c92fb768 MADS: PHANTOM: Adding more core dependencies
2718a5cdc3 MADS: PHANTOM: Adding sprite drawing code
e6007be109 MADS: PHANTOM: Added kernel
85daa9bf61 MADS: PHANTOM: Added more core files
cc5467ce47 MADS: PHANTOM: Added more core files
8df8ff83e8 MADS: PHANTOM: Added more core files
e9568f29d5 MADS: PHANTOM: Added more core files
820abaa025 MADS: PHANTOM: Added remainder of main menu main function
fb55f2460e MADS: PHANTOM: Fix setting g_engine global on engine creation
a5e3fc2ec2 MADS: PHANTOM: Disable EMS/XMS initializations
e5d081d318 MADS: PHANTOM: Fix crash in palette routines
621c1344a5 MADS: PHANTOM: Fix env_open for reading .hag resources
38046d6a93 MADS: PHANTOM: Endian safe reading of hag file index
151a99a32b MADS: PHANTOM: Fix EMS crash when an error is generated
0591db5a98 MADS: PHANTOM: Properly setup decompressors on startup
817d3e973c MADS: Create common base engine class shared with Rex Nebular
24e2d5b6d9 MADS: Separate out HagArchive class
ec9190612f MADS: PHANTOM: Kernel startup cleanups, added dummy timer stack
4aecd060fa MADS: PHANTOM: Fixes to FAB decompression
68fe4b7ec5 MADS: PHANTOM: Implement endian safe sprite series loading
400266d293 MADS: PHANTOM: Endian safe tile loading
406d7d7300 MADS: PHANTOM: Fix decompressing last tile in tile_load
47079f0d2e MADS: PHANTOM: Implementing timer read functions
1f63de2eeb MADS: PHANTOM: Hotspots loading code
27a29711d3 MADS: PHANTOM: Don't load hotspots for Phantom title screen
3f690b1757 MADS: PHANTOM: Added ERROR_MESSAGES array
6ee9525750 MADS: PHANTOM: Fixes for anim_load
d353e1817f MADS: PHANTOM: Fix sprite drawing with depth buffer
d671f0d399 MADS: PHANTOM: Screen updates
5d20c04353 MADS: PHANTOM: Translate 6-bit palette RGBs to 8-bit
bb07d87b95 MADS: PHANTOM: Hook up mouse events to update mouse fields
94a5023aa9 MADS: PHANTOM: Implement mouse cursor display
c9f03bec94 MADS: PHANTOM: Beginning of sound handling
efce444c99 MADS: PHANTOM: Creating shared SoundManager and ASound classes
fac67af9a9 MADS: PHANTOM: Skeleton sound manager implementation
db0f091b41 MADS: PHANTOM: Create derived PhantomEngine class
f6a1a4c0cf MADS: PHANTOM: Asound files md5 validation
f42abd58f5 MADS: PHANTOM: Skeleton command functions for ASound9 class
7e66f79f8c MADS: PHANTOM: Figure out data segment offsets for sound files
c100027c44 MADS: PHANTOM: Claude implementation of ASound9
1a167ac273 MADS: PHANTOM: Hooking up sound driver calls
3d3a3e5568 MADS: PHANTOM: Add Claude AI files to .gitignore
837805ca4d MADS: PHANTOM: Added room 101
cc86c12ea2 MADS: PHANTOM: Added room 102
385f660c23 MADS: PHANTOM: Added room 103
879ea943ba MADS: PHANTOM: Added Claude generated ASound implementations
d82257eb05 MADS: PHANTOM: Added room 104
5e6a12748f MADS: PHANTOM: Added room 105
d2fdb01bba MADS: PHANTOM: Added room 106
7815cb5a9a MADS: PHANTOM: Added room 107
460ec4839d MADS: PHANTOM: Added room 108
75ecc6136e MADS: PHANTOM: Added room 109
3afcb36f58 MADS: PHANTOM: Minor header file cleanups
78341c751d MADS: PHANTOM: Added room 110
153d136029 MADS: PHANTOM: Added room 111
62c5545ce7 MADS: PHANTOM: Added room 112
52496755a6 MADS: PHANTOM: Added room 113
ba78a7454c MADS: PHANTOM: Added room 114
211acca44e MADS: PHANTOM: Change room Scratch fields from int to int16
8a64f7da46 MADS: PHANTOM: Added room 150
b499cdfd37 MADS: PHANTOM: Added room 201
66e2e88e47 MADS: PHANTOM: Added room 202
56c05a5a0f MADS: PHANTOM: Added room 203
2b366bdf7e MADS: PHANTOM: Added room 204
702dd37cbd MADS: PHANTOM: Added room 205
430e3c3382 MADS: PHANTOM: Added room 206
4d57e59009 MADS: PHANTOM: Added room 207
117ce24649 MADS: PHANTOM: Added room 208
cbdb0f6bc8 MADS: PHANTOM: Added room 250
ae4217a7cc MADS: PHANTOM: Added room 301
253c061160 MADS: PHANTOM: Added room 302
9c1547975e MADS: PHANTOM: Added room 303
5e6eade975 MADS: PHANTOM: Added room 304
b764cf8a5d MADS: PHANTOM: Added room 305
dade73d3c7 MADS: PHANTOM: Added room 306
dff5b3da8c MADS: PHANTOM: Added room 307
a9fcf43af1 MADS: PHANTOM: Added room 308
bc0ac3867c MADS: PHANTOM: Added room 309
f98c7081ad MADS: PHANTOM: Added room 310
963967034f MADS: PHANTOM: Added room 401
1eca97ab61 MADS: PHANTOM: Added room 403
1308e97d07 MADS: PHANTOM: Added room 404
ff5904ecf8 MADS: PHANTOM: Added room 406
747aca50e8 MADS: PHANTOM: Added room 407
685b1440e8 MADS: PHANTOM: Added room 408
e2de73f229 MADS: PHANTOM: Added room 409
c5cd112150 MADS: PHANTOM: Added room 410
93e5b9875b MADS: PHANTOM: Added room 453
421d5671c7 MADS: PHANTOM: Added room 456
a1d41ae887 MADS: PHANTOM: Added section 5 rooms
7445927a07 MADS: PHANTOM: Implement section handlers
787fd241a5 MADS: PHANTOM: Seperating out and completing catacombs code
0c78f02d08 MADS: PHANTOM: Hooking up global_section_constructor
2c34c280c5 MADS: PHANTOM: Implementing main_cold_data_init
7c5f5cc0bb MADS: PHANTOM: Janitorial
f6be220385 MADS: PHANTOM: Added global_init_code
26ff0267bd MADS: PHANTOM: Hooked up section_music
a4bf87a787 MADS: PHANTOM: game_control_loop is not game-specific
05bd6c9b17 MADS: PHANTOM: Clean up key callback functions
0bb1d70975 MADS: PHANTOM: Hooking up game_main
8f39c1f651 MADS: PHANTOM: Tentative hookup of game_main
0823b401c3 MADS: PHANTOM: Shifting conv.cpp from phantom/ to core/
3aa5ab8bd1 MADS: PHANTOM: Added global daemon code
f17a8b0a72 MADS: PHANTOM: Added global parser code
7023b3c755 MADS: PHANTOM: Added global_error_code
2d388747ed MADS: PHANTOM: Added global_room_init
8d2aad7c70 MADS: PHANTOM: Added global_verb_filter
73fd108173 MADS: PHANTOM: Adding config code
c71754606f MADS: PHANTOM: Implemented Phantom version of global_copy_verify
f3f61f1659 MADS: PHANTOM: Added Phantom game menus
8c07739708 MADS: PHANTOM: Fix cursor loading and object_load
3fbadd3daa MADS: PHANTOM: Re-enable needed game_control conv code
682efb4f68 MADS: PHANTOM: Fix incorrect starting room
9ef4647d67 MADS: PHANTOM: Dummy EMS implementation
82a7e0ad78 MADS: PHANTOM: Fix loading hotspots
dabef2b231 MADS: PHANTOM: Match max hotspots to original
b195f24cef MADS: PHANTOM: Fix font loading
d02bf3e3c7 MADS: PHANTOM: Room startup sound fixes
90736ad938 MADS: PHANTOM: Fix buffer overrun in tile_buffer from tile_pan
3185ffc838 MADS: PHANTOM: Ifdef out unused code
d4a7497671 MADS: PHANTOM: Fix duplication of rails globals
9d6a6cba81 MAP: PHANTOM: Properly map a000:0 pointers to use _screen surface
06708e46a0 MADS: PHANTOM: Stop the game in response to quit events
16c4fd6ecb MADS: PHANTOM: Change tiles to using direct memory blocks
83ee9fe558 MADS: PHANTOM: Fix rendering backgrounds
c4d4fc5b1d MADS: PHANTOM: Fix playback speed
519732a3ee MADS: PHANTOM: Fixes for showing the difficulty menu on startup
607b346b02 MADS: PHANTOM: Fix quitting directly from Difficulty dialog
75df90fb2a MADS: PHANTOM: Fix palette for initial Difficulty dialog
2b205a4ee3 MADS: PHANTOM: ConfMan option to directly specify difficulty
c3b3ec7350 MADS: PHANTOM: Re-enable missing conv system calls
c172f6ac0b MADS: PHANTOM: Fixes to interface display
ed1a06e39f MADS: PHANTOM: Implementing conv code
d00f73cca8 MADS: PHANTOM: More conv init code
32ddacaaba MADS: PHANTOM: Changing conv/conv data to use Common::Array
93381d50d9 MADS: PHANTOM: Adding more conv functions
ef604c7179 MADS: PHANTOM: In progress conv script processing
e94aa52b17 MADS: PHANTOM: Conv message functions
49b7586aac MADS: PHANTOM: Further conv functions
3e63834f60 MADS: PHANTOM: Conv reading/writing
569407b1a2 MADS: PHANTOM: Conv opening fixes
f8c27b550a MADS: PHANTOM: Conv data structure loading fixes
86bd5391a0 MADS: PHANTOM: Fix loading conv data
f6910e5d07 MADS: PHANTOM: Fix conv scripts declaration
bff3e2b120 MADS: PHANTOM: Properly flag conv as done
65c54c9d8f MADS: PHANTOM: Fix loading room hotspot list
d26d9ee9f2 MADS: PHANTOM: Remove deprecated popup_create stub
a89d91a57d MADS: PHANTOM: Don't save/restore popup screen areas using EMS
ffb08436fa MADS: PHANTOM: Fix mouse movement tracking
27ed3ad830 MADS: PHANTOM: Fix display of interface tooltips
512f29b976 MADS: PHANTOM: Simplify text_load to match the original
7ed2003266 MADS: PHANTOM: Fix quitting when a dialog is on-screen
9b023c137f MADS: PHANTOM: Remove un-used digi.cpp/.h
5f049aea48 MADS: PHANTOM: Properly initialize sound driver
2c5404b90d MADS: PHANTOM: Refactoring channel commands to be game specific
2fe9311066 MADS: PHANTOM: Claude generated Phantom channel commands
efd3d0b476 MADS: PHANTOM: Load sound driver sample list
81a2aaa030 MADS: PHANTOM: Cleanup of config file reading
d109e396a8 MADS: PHANTOM: Fix main menu event handling
4b10f801c4 MADS: PHANTOM: Remove unused midi.cpp/.h
0ba693202e MADS: PHANTOM: Fix loading interface backgrounds
c2132a8505 MADS: PHANTOM: Fixes for conversation variable loading
f927e5c5a2 MADS: PHANTOM: Handle seralizing ConvVariable pointers
9326926020 MADS: PHANTOM: Preliminary can save/load currently checks
5ba0a96969 MADS: PHANTOM: Hooking up engine saving/loading
3713880be1 ENGINES: Added getGameId for getting gameId from a target
65903463e3 MADS: PHANTOM: Fix savegame loading
babf34cb6b MADS: PHANTOM: Fix crash changing rooms
b4c6e27517 MADS: PHANTOM: Fix caching conversation data for savegames
30289ce04b MADS: PHANTOM: Replace original autosave on exit
9c764d56c0 MADS: PHANTOM: Implement loading savegames from launcher
d2564fb84e MADS: PHANTOM: Remove duplicated conv.h file
aa51e0b1cc MADS: PHANTOM: Fix duration of conversation response dialogs
4056f6a091 MADS: PHANTOM: Adding speech data loading
a38facbef0 MADS: PHANTOM: Fixes for startup speech init
7b5353a578 MADS: PHANTOM: Got speech code working using Audio::makeRawStream
56ba643484 MADS: PHANTOM: Implement Exit button on main menu
434ca5a7f2 MADS: PHANTOM: Fix interface command list display
181ea1767e MADS: PHANTOM: Minor fixes to pal_allocate
7684e51bff MADS: PHANTOM: Fix incorrect type sizes in insertion_sort
8edeee181f MADS: PHANTOM: Added sizeof(byte) to sort functions for better clarity
e376e303e9 MADS: PHANTOM: Fix drawing of horizontally flipped sprites
6eaf1e4af5 MADS: PHANTOM: Disable original cheat keys for now
881a3d1578 MADS: PHANTOM: Fix key constants, mapping keybinding to keys
db02f972f0 MADS: PHANTOM: Fix Game Menu quit button
637bae78f1 MADS: PHANTOM: Fix cursors showing stray pixels
9b8d50ec51 MADS: PHANTOM: Implement delete_sprite_in_interface
fe59a46927 MADS: PHANTOM: Fix loading room depth table
4f6b997522 MADS: PHANTOM: Fix getting small note in room 113
feab44b02d MADS: PHANTOM: Ignore dummy ptr variables when entering manager's office
e4abb70e55 MADS: PHANTOM: Added debugger console class
52e97492b8 MADS: PHANTOM: Fix walker appearing all black after '5 minutes later' cutscene
Commit: 39cb737e2405303e1a7fec86b4f0f339ac73964f
https://github.com/scummvm/scummvm/commit/39cb737e2405303e1a7fec86b4f0f339ac73964f
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:18:57+10:00
Commit Message:
MADS: PHANTOM: Remove existing Phantom codebase
Changed paths:
A engines/mads/madsv2/phantom/main_menu.cpp
A engines/mads/madsv2/phantom/main_menu.h
R engines/mads/phantom/dialogs_phantom.cpp
R engines/mads/phantom/dialogs_phantom.h
R engines/mads/phantom/game_phantom.cpp
R engines/mads/phantom/game_phantom.h
R engines/mads/phantom/globals_phantom.cpp
R engines/mads/phantom/globals_phantom.h
R engines/mads/phantom/menu_phantom.cpp
R engines/mads/phantom/menu_phantom.h
R engines/mads/phantom/phantom_scenes.cpp
R engines/mads/phantom/phantom_scenes.h
R engines/mads/phantom/phantom_scenes1.cpp
R engines/mads/phantom/phantom_scenes1.h
R engines/mads/phantom/phantom_scenes2.cpp
R engines/mads/phantom/phantom_scenes2.h
R engines/mads/phantom/phantom_scenes3.cpp
R engines/mads/phantom/phantom_scenes3.h
R engines/mads/phantom/phantom_scenes4.cpp
R engines/mads/phantom/phantom_scenes4.h
R engines/mads/phantom/phantom_scenes5.cpp
R engines/mads/phantom/phantom_scenes5.h
engines/mads/dialogs.cpp
engines/mads/game.cpp
engines/mads/module.mk
engines/mads/scene.cpp
engines/mads/scene_data.cpp
diff --git a/engines/mads/dialogs.cpp b/engines/mads/dialogs.cpp
index adab11a1510..906b7eb574d 100644
--- a/engines/mads/dialogs.cpp
+++ b/engines/mads/dialogs.cpp
@@ -26,9 +26,6 @@
#include "mads/screen.h"
#include "mads/msurface.h"
#include "mads/nebular/dialogs_nebular.h"
-#ifdef ENABLE_MADSV2
-#include "mads/phantom/dialogs_phantom.h"
-#endif
namespace MADS {
@@ -458,8 +455,6 @@ Dialogs *Dialogs::init(MADSEngine *vm) {
case GType_RexNebular:
return new Nebular::DialogsNebular(vm);
#ifdef ENABLE_MADSV2
- case GType_Phantom:
- return new Phantom::DialogsPhantom(vm);
case GType_Dragonsphere:
// return new DragonSphere::DialogsDragonSphere(vm);
case GType_Forest:
diff --git a/engines/mads/game.cpp b/engines/mads/game.cpp
index b1f2f58a7c8..81ce50fce6c 100644
--- a/engines/mads/game.cpp
+++ b/engines/mads/game.cpp
@@ -37,7 +37,6 @@
#ifdef ENABLE_MADSV2
#include "mads/dragonsphere/game_dragonsphere.h"
#include "mads/forest/game_forest.h"
-#include "mads/phantom/game_phantom.h"
#endif
namespace MADS {
@@ -50,7 +49,7 @@ Game *Game::init(MADSEngine *vm) {
case GType_Dragonsphere:
return new Dragonsphere::GameDragonsphere(vm);
case GType_Phantom:
- return new Phantom::GamePhantom(vm);
+ return nullptr; // new Phantom::GamePhantom(vm);
case GType_Forest:
return new Forest::GameForest(vm);
#endif
diff --git a/engines/mads/madsv2/phantom/main_menu.cpp b/engines/mads/madsv2/phantom/main_menu.cpp
new file mode 100644
index 00000000000..a9ce39cf807
--- /dev/null
+++ b/engines/mads/madsv2/phantom/main_menu.cpp
@@ -0,0 +1,27 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "mads/madsv2/phantom/main_menu.h"
+
+namespace MADS {
+
+
+} // namespace MADS
diff --git a/engines/mads/phantom/globals_phantom.cpp b/engines/mads/madsv2/phantom/main_menu.h
similarity index 65%
rename from engines/mads/phantom/globals_phantom.cpp
rename to engines/mads/madsv2/phantom/main_menu.h
index ff357cf7db2..3262add2dfa 100644
--- a/engines/mads/phantom/globals_phantom.cpp
+++ b/engines/mads/madsv2/phantom/main_menu.h
@@ -19,27 +19,14 @@
*
*/
-#include "mads/phantom/globals_phantom.h"
+#ifndef MADS_PHANTOM_MAIN_MENU_H
+#define MADS_PHANTOM_MAIN_MENU_H
-namespace MADS {
-namespace Phantom {
-
-PhantomGlobals::PhantomGlobals() : Globals() {
- // Initialize lists
- resize(210);
- _spriteIndexes.resize(30);
- _sequenceIndexes.resize(30);
- _animationIndexes.resize(30);
-}
+#include "common/str.h"
-void PhantomGlobals::synchronize(Common::Serializer &s) {
- Globals::synchronize(s);
+namespace MADS {
- _spriteIndexes.synchronize(s);
- _sequenceIndexes.synchronize(s);
- _animationIndexes.synchronize(s);
-}
+} // namespace MADS
-} // End of namespace Phantom
-} // End of namespace MADS
+#endif
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index d60d33291ac..6173ef037d5 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -59,16 +59,7 @@ MODULE_OBJS += \
forest/game_forest.o \
forest/forest_scenes.o \
forest/globals_forest.o \
- phantom/dialogs_phantom.o \
- phantom/game_phantom.o \
- phantom/globals_phantom.o \
- phantom/menu_phantom.o \
- phantom/phantom_scenes.o \
- phantom/phantom_scenes1.o \
- phantom/phantom_scenes2.o \
- phantom/phantom_scenes3.o \
- phantom/phantom_scenes4.o \
- phantom/phantom_scenes5.o
+ madsv2/phantom/main_menu.o
endif
# This module can be built as a plugin
diff --git a/engines/mads/phantom/dialogs_phantom.cpp b/engines/mads/phantom/dialogs_phantom.cpp
deleted file mode 100644
index 0692e2661f8..00000000000
--- a/engines/mads/phantom/dialogs_phantom.cpp
+++ /dev/null
@@ -1,1210 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include "common/scummsys.h"
-#include "common/config-manager.h"
-#include "common/util.h"
-#include "backends/keymapper/keymapper.h"
-#include "gui/saveload.h"
-#include "mads/mads.h"
-#include "mads/screen.h"
-#include "mads/msurface.h"
-#include "mads/staticres.h"
-#include "mads/phantom/dialogs_phantom.h"
-#include "mads/phantom/game_phantom.h"
-#include "mads/phantom/menu_phantom.h"
-
-namespace MADS {
-namespace Phantom {
-
-bool DialogsPhantom::show(int messageId, int objectId) {
- MADSAction &action = _vm->_game->_scene._action;
- Common::StringArray msg = _vm->_game->getMessage(messageId);
- Common::String title;
- Common::String commandText;
- Common::String valStr;
- Common::String dialogText;
- bool result = true;
- bool centerFlag = false;
- bool underlineFlag = false;
- bool commandFlag = false;
- bool crFlag = false;
- TextDialog *dialog = nullptr;
- _dialogWidth = 17;
- _capitalizationMode = kUppercase;
-
- // Loop through the lines of the returned text
- for (uint idx = 0; idx < msg.size(); ++idx) {
- Common::String srcLine = msg[idx];
- const char *srcP = srcLine.c_str();
-
- // Loop through the text of the line
- while (srcP < srcLine.c_str() + srcLine.size()) {
- if (*srcP == '[') {
- // Starting a command
- commandText = "";
- commandFlag = true;
- } else if (*srcP == ']') {
- // Ending a command
- if (commandFlag) {
- if (commandCheck("CENTER", valStr, commandText)) {
- centerFlag = true;
- } else if (commandCheck("TITLE", valStr, commandText)) {
- centerFlag = true;
- underlineFlag = true;
- crFlag = true;
- int v = atoi(valStr.c_str());
- if (v != 0)
- _dialogWidth = v;
- } else if (commandCheck("CR", valStr, commandText)) {
- if (centerFlag) {
- crFlag = true;
- } else {
- if (dialog)
- delete dialog;
-
- if (objectId == -1)
- dialog = new TextDialog(_vm, FONT_INTERFACE, _defaultPosition, _dialogWidth);
- else
- dialog = new PictureDialog(_vm, _defaultPosition, _dialogWidth, objectId);
-
- dialog->wordWrap(dialogText);
- dialog->incNumLines();
- }
- } else if (commandCheck("ASK", valStr, commandText)) {
- if (!dialog)
- error("DialogsPhantom::show - Uninitialized dialog");
- dialog->addInput();
- } else if (commandCheck("VERB", valStr, commandText)) {
- dialogText += getVocab(action._activeAction._verbId);
- } else if (commandCheck("INDEX", valStr, commandText)) {
- int idxLocal = atoi(valStr.c_str());
- if (_indexList[idxLocal])
- dialogText += getVocab(_indexList[idxLocal]);
- } else if (commandCheck("NUMBER", valStr, commandText)) {
- int idxLocal = atoi(valStr.c_str());
- dialogText += Common::String::format("%.4d", _indexList[idxLocal]);
- } else if (commandCheck("NOUN1", valStr, commandText)) {
- if (!textNoun(dialogText, 1, valStr))
- dialogText += getVocab(action._activeAction._objectNameId);
- } else if (commandCheck("NOUN2", valStr, commandText)) {
- if (!textNoun(dialogText, 2, valStr))
- dialogText += getVocab(action._activeAction._indirectObjectId);
- } else if (commandCheck("PREP", valStr, commandText)) {
- dialogText += kArticleList[action._savedFields._articleNumber];
- } else if (commandCheck("SENTENCE", valStr, commandText)) {
- dialogText += action._sentence;
- } else if (commandCheck("WIDTH", valStr, commandText)) {
- _dialogWidth = atoi(valStr.c_str());
- } else if (commandCheck("BAR", valStr, commandText)) {
- if (!dialog)
- error("DialogsPhantom::show - Uninitialized dialog");
- dialog->addBarLine();
- } else if (commandCheck("UNDER", valStr, commandText)) {
- underlineFlag = true;
- } else if (commandCheck("DOWN", valStr, commandText)) {
- if (!dialog)
- error("DialogsPhantom::show - Uninitialized dialog");
- dialog->downPixelLine();
- } else if (commandCheck("TAB", valStr, commandText)) {
- if (!dialog)
- error("DialogsPhantom::show - Uninitialized dialog");
- int xp = atoi(valStr.c_str());
- dialog->setLineXp(xp);
- }
- }
-
- commandFlag = false;
- } else if (commandFlag) {
- // Add the next character to the command
- commandText += *srcP;
- } else {
- // Add to the text to be displayed in the dialog
- dialogText += *srcP;
- }
-
- ++srcP;
- }
-
- if (!dialog) {
- if (objectId == -1)
- dialog = new TextDialog(_vm, FONT_INTERFACE, _defaultPosition, _dialogWidth);
- else
- dialog = new PictureDialog(_vm, _defaultPosition, _dialogWidth, objectId);
- }
-
- if (centerFlag) {
- dialog->addLine(dialogText, underlineFlag);
- if (crFlag)
- dialog->incNumLines();
- } else {
- dialog->wordWrap(dialogText);
- }
-
- // Reset line processing flags in preparation for next line
- dialogText = "";
- commandFlag = false;
- underlineFlag = false;
- centerFlag = false;
- crFlag = false;
- }
-
- if (!dialog)
- error("DialogsPhantom::show - Uninitialized dialog");
-
- if (!centerFlag)
- dialog->incNumLines();
-
- // Show the dialog
- _vm->_events->setCursor(CURSOR_ARROW);
- dialog->show();
-
- delete dialog;
- return result;
-}
-
-void DialogsPhantom::showItem(int objectId, int messageId, int speech) {
- // MADS engine doesn't currently support speech
- assert(!speech);
-
- show(messageId, objectId);
-}
-
-Common::String DialogsPhantom::getVocab(int vocabId) {
- assert(vocabId > 0);
-
- Common::String vocab = _vm->_game->_scene.getVocab(vocabId);
-
- switch (_capitalizationMode) {
- case kUppercase:
- vocab.toUppercase();
- break;
- case kLowercase:
- vocab.toLowercase();
- break;
- case kUpperAndLower:
- vocab.toLowercase();
- vocab.setChar(toupper(vocab[0]), 0);
- default:
- break;
- }
-
- return vocab;
-}
-
-bool DialogsPhantom::textNoun(Common::String &dest, int nounId, const Common::String &source) {
- // Ensure the destination has parameter specifications
- if (!source.hasPrefix(":"))
- return false;
-
- // Extract the first (singular) result value
- Common::String param1 = Common::String(source.c_str() + 1);
- Common::String param2;
- const char *sepChar = strchr(source.c_str() + 1, ':');
- if (sepChar) {
- param1 = Common::String(source.c_str() + 1, sepChar);
-
- // Get the second, plural form
- param2 = Common::String(sepChar + 1);
- }
-
- // Get the vocab to use
- MADSAction &action = _vm->_game->_scene._action;
- Common::String vocab = _vm->_dialogs->getVocab(action._activeAction._verbId);
- Common::String *str;
-
- if (vocab.hasSuffix("s") || vocab.hasSuffix("S")) {
- str = ¶m2;
- } else {
- str = ¶m1;
-
- if (param1 == "a ") {
- switch (toupper(vocab[0])) {
- case 'A':
- case 'E':
- case 'I':
- case 'O':
- case 'U':
- param1 = "an ";
- break;
- default:
- break;
- }
- }
- }
-
- dest += *str;
- return true;
-}
-
-bool DialogsPhantom::commandCheck(const char *idStr, Common::String &valStr,
- const Common::String &command) {
- uint idLen = strlen(idStr);
-
- valStr = (command.size() <= idLen) ? "" : Common::String(command.c_str() + idLen);
-
- // Check whether the command starts with the given Id
- int result = scumm_strnicmp(idStr, command.c_str(), idLen) == 0;
- if (!result)
- return false;
-
- // It does, so set the command case mode
- if (Common::isUpper(command[0]) && Common::isUpper(command[1])) {
- _capitalizationMode = kUppercase;
- } else if (Common::isUpper(command[0])) {
- _capitalizationMode = kUpperAndLower;
- } else {
- _capitalizationMode = kLowercase;
- }
-
- return true;
-}
-
-void DialogsPhantom::showDialog() {
- while (_pendingDialog != DIALOG_NONE && !_vm->shouldQuit()) {
- DialogId dialogId = _pendingDialog;
- _pendingDialog = DIALOG_NONE;
-
- Common::Keymapper *keymapper = _vm->getEventManager()->getKeymapper();
- if (dialogId == MADS::DIALOG_MAIN_MENU) {
- keymapper->getKeymap("menu-shortcuts")->setEnabled(true);
- } else {
- keymapper->getKeymap("menu-shortcuts")->setEnabled(false);
- }
-
- switch (dialogId) {
- case DIALOG_MAIN_MENU: {
- MainMenu *menu = new MainMenu(_vm);
- menu->show();
- delete menu;
- break;
- }
- case DIALOG_DIFFICULTY: {
- DifficultyDialog *dlg = new DifficultyDialog(_vm);
- dlg->show();
- delete dlg;
- break;
- }
- case DIALOG_GAME_MENU: {
- GameMenuDialog *dlg = new GameMenuDialog(_vm);
- dlg->show();
- delete dlg;
- break;
- }
- case DIALOG_SAVE: {
- showScummVMSaveDialog();
- break;
- }
- case DIALOG_RESTORE: {
- showScummVMRestoreDialog();
- break;
- }
- case DIALOG_OPTIONS: {
- OptionsDialog *dlg = new OptionsDialog(_vm);
- dlg->show();
- delete dlg;
- break;
- }
- case DIALOG_ADVERT: {
- AdvertView *dlg = new AdvertView(_vm);
- dlg->show();
- delete dlg;
- break;
- }
- case DIALOG_TEXTVIEW: {
- TextView *dlg = new PhantomTextView(_vm);
- dlg->show();
- delete dlg;
- return;
- }
- case DIALOG_ANIMVIEW: {
- AnimationView *dlg = new PhantomAnimationView(_vm);
- dlg->show();
- delete dlg;
- break;
- }
- default:
- break;
- }
- }
-}
-
-void DialogsPhantom::showScummVMSaveDialog() {
- auto &game = *(Phantom::GamePhantom *)_vm->_game;
- Scene &scene = game._scene;
- GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(true);
-
- int slot = dialog->runModalWithCurrentTarget();
- if (slot >= 0) {
- Common::String desc = dialog->getResultString();
-
- if (desc.empty()) {
- // create our own description for the saved game, the user didn't enter it
- desc = dialog->createDefaultSaveDescription(slot);
- }
-
- scene._spriteSlots.reset();
- scene.loadScene(scene._currentSceneId, game._aaName, true);
- scene._userInterface.noInventoryAnim();
- game._scene.drawElements(kTransitionFadeIn, false);
-
- game.saveGame(slot, desc);
- }
-
- // Flag for scene loading that we're returning from a dialog
- scene._currentSceneId = RETURNING_FROM_DIALOG;
-
- delete dialog;
-}
-
-void DialogsPhantom::showScummVMRestoreDialog() {
- auto &game = *(Phantom::GamePhantom *)_vm->_game;
- GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(false);
- Scene &scene = game._scene;
-
- int slot = dialog->runModalWithCurrentTarget();
- if (slot >= 0) {
- game._loadGameSlot = slot;
- game._scene._currentSceneId = RETURNING_FROM_LOADING;
- game._currentSectionNumber = -1;
- } else {
- // Flag for scene loading that we're returning from a dialog
- scene._currentSceneId = RETURNING_FROM_DIALOG;
- }
-
- delete dialog;
-}
-
-/*------------------------------------------------------------------------*/
-
-CopyProtectionDialog::CopyProtectionDialog(MADSEngine *vm, bool priorAnswerWrong) :
-TextDialog(vm, FONT_INTERFACE, Common::Point(-1, -1), 32) {
- getHogAnusEntry(_hogEntry);
-
- if (priorAnswerWrong) {
- addLine("ANSWER INCORRECT!", true);
- wordWrap("\n");
- addLine("(But we'll give you another chance!)");
- } else {
- addLine("REX NEBULAR version 8.43", true);
- wordWrap("\n");
- addLine("(Copy Protection, for your convenience)");
- }
- wordWrap("\n");
-
- wordWrap("Now comes the part that everybody hates. But if we don't");
- wordWrap("do this, nasty rodent-like people will pirate this game");
- wordWrap("and a whole generation of talented designers, programmers,");
- wordWrap("artists, and playtesters will go hungry, and will wander");
- wordWrap("aimlessly through the land at night searching for peace.");
- wordWrap("So let's grit our teeth and get it over with. Just get");
-
- Common::String line = "out your copy of ";
- line += _hogEntry._bookId == 103 ? "the GAME MANUAL" : "REX'S LOGBOOK";
- line += ". See! That was easy. ";
- wordWrap(line);
-
- line = Common::String::format("Next, just turn to page %d. On line %d, find word number %d, ",
- _hogEntry._pageNum, _hogEntry._lineNum, _hogEntry._wordNum);
- wordWrap(line);
-
- wordWrap("and type it on the line below (we've even given you");
- wordWrap("first letter as a hint). As soon as you do that, we can get");
- wordWrap("right into this really COOL adventure game!\n");
- wordWrap("\n");
- wordWrap(" ");
- addInput();
- wordWrap("\n");
-}
-
-void CopyProtectionDialog::show() {
- draw();
-
- Common::KeyState curKey;
- const Common::Rect inputArea(110, 165, 210, 175);
- MSurface *origInput = new MSurface(inputArea.width(), inputArea.height());
- _vm->_screen->frameRect(inputArea, TEXTDIALOG_BLACK);
- origInput->blitFrom(*_vm->_screen, inputArea, Common::Point(0, 0));
- _font->setColors(TEXTDIALOG_FE, TEXTDIALOG_FE, TEXTDIALOG_FE, TEXTDIALOG_FE);
- _vm->_screen->update();
-
- bool firstTime = true;
-
- while (!_vm->shouldQuit()) {
- if (!firstTime) {
- while (!_vm->shouldQuit() && !_vm->_events->isKeyPressed()) {
- _vm->_events->delay(1);
- }
-
- if (_vm->shouldQuit())
- break;
-
- curKey = _vm->_events->getKey();
-
- if (curKey.keycode == Common::KEYCODE_RETURN || curKey.keycode == Common::KEYCODE_KP_ENTER)
- break;
- else if (curKey.keycode == Common::KEYCODE_BACKSPACE)
- _textInput.deleteLastChar();
- else if (_textInput.size() < 14)
- _textInput += curKey.ascii;
-
- _vm->_events->_pendingKeys.clear();
- } else {
- firstTime = false;
- _textInput = _hogEntry._word[0];
- }
-
- _vm->_screen->blitFrom(*origInput, Common::Point(inputArea.left, inputArea.top));
- _font->writeString(_vm->_screen, _textInput,
- Common::Point(inputArea.left + 2, inputArea.top + 1), 1);
- _vm->_screen->update();
- }
-
- origInput->free();
- delete origInput;
-}
-
-bool CopyProtectionDialog::isCorrectAnswer() {
- return _hogEntry._word == _textInput;
-}
-
-
-bool CopyProtectionDialog::getHogAnusEntry(HOGANUS &entry) {
- File f;
- f.open("*HOGANUS.DAT");
-
- // Read in the total number of entries, and randomly pick an entry to use
- int numEntries = f.readUint16LE();
- int entryIndex = _vm->getRandomNumber(1, numEntries);
-
- // Read in the encrypted entry
- f.seek(28 * entryIndex + 2);
- byte entryData[28];
- f.read(entryData, 28);
-
- // Decrypt it
- for (int i = 0; i < 28; ++i)
- entryData[i] = ~entryData[i];
-
- // Fill out the fields
- entry._bookId = entryData[0];
- entry._pageNum = READ_LE_UINT16(&entryData[2]);
- entry._lineNum = READ_LE_UINT16(&entryData[4]);
- entry._wordNum = READ_LE_UINT16(&entryData[6]);
- entry._word = Common::String((char *)&entryData[8]);
-
- f.close();
- return true;
-}
-
-/*------------------------------------------------------------------------*/
-
-PictureDialog::PictureDialog(MADSEngine *vm, const Common::Point &pos,
- int maxChars, int objectId) :
- TextDialog(vm, FONT_INTERFACE, pos, maxChars), _objectId(objectId) {
- // Turn off cycling if active
- Scene &scene = _vm->_game->_scene;
- _cyclingActive = scene._cyclingActive;
- scene._cyclingActive = false;
-}
-
-PictureDialog::~PictureDialog() {
- // Restore cycling flag
- Scene &scene = _vm->_game->_scene;
- scene._cyclingActive = _cyclingActive;
-}
-
-void PictureDialog::save() {
- Palette &palette = *_vm->_palette;
- byte map[PALETTE_COUNT];
-
- // Save the entire screen
- _savedSurface = new MSurface(MADS_SCREEN_WIDTH, MADS_SCREEN_HEIGHT);
- _savedSurface->blitFrom(*_vm->_screen);
-
- // Save palette information
- Common::copy(&palette._mainPalette[0], &palette._mainPalette[PALETTE_SIZE], &_palette[0]);
- Common::copy(&palette._palFlags[0], &palette._palFlags[PALETTE_COUNT], &_palFlags[0]);
- _rgbList.copy(palette._rgbList);
-
- // Set up palette allocation
- Common::fill(&palette._colorFlags[0], &palette._colorFlags[3], true);
-
- uint32 *palFlagP = &palette._palFlags[0];
- for (int idx = 0; idx < PALETTE_COUNT; ++idx, ++palFlagP) {
- if (idx < PALETTE_RESERVED_LOW_COUNT ||
- idx >= (PALETTE_COUNT - PALETTE_RESERVED_HIGH_COUNT - 10)) {
- *palFlagP = 1;
- map[idx] = idx;
- } else {
- *palFlagP = 0;
- }
- }
-
- // Reset the flag list
- palette._rgbList.reset();
-
- // Fade the screen to grey
- int numColors = PALETTE_COUNT - PALETTE_RESERVED_LOW_COUNT - PALETTE_RESERVED_HIGH_COUNT;
- palette.fadeOut(palette._mainPalette, &map[PALETTE_RESERVED_LOW_COUNT],
- PALETTE_RESERVED_LOW_COUNT, numColors, 248, 8, 1, 16);
-
- // Remap the greyed out screen to use the small greyscale range
- // at the top end of the palette
- _vm->_screen->translate(map);
-
- // Load the inventory picture
- Common::Path setName(Common::String::format("*OB%.3d.SS", _objectId));
- SpriteAsset *asset = new SpriteAsset(_vm, setName, 0x8000);
- palette.setFullPalette(palette._mainPalette);
-
- // Get the inventory frame, and adjust the dialog position to allow for it
- MSprite *frame = asset->getFrame(0);
- _position.y = frame->h + 12;
- if ((_position.y + _height) > _vm->_screen->h)
- _position.y -= (_position.y + _height) - _vm->_screen->h;
-
- // Draw the inventory picture
- _vm->_screen->transBlitFrom(*frame, Common::Point(160 - frame->w / 2, 6),
- frame->getTransparencyIndex());
-
- // Adjust the dialog colors to use
- TEXTDIALOG_CONTENT1 -= 10;
- TEXTDIALOG_CONTENT2 -= 10;
- TEXTDIALOG_EDGE -= 10;
- TEXTDIALOG_BACKGROUND -= 10;
- TEXTDIALOG_FC -= 10;
- TEXTDIALOG_FD -= 10;
- TEXTDIALOG_FE -= 10;
-}
-
-void PictureDialog::restore() {
- if (_savedSurface) {
- _vm->_screen->blitFrom(*_savedSurface);
- _savedSurface->free();
- delete _savedSurface;
- _savedSurface = nullptr;
-
- // Restore palette information
- Palette &palette = *_vm->_palette;
- Common::copy(&_palette[0], &_palette[PALETTE_SIZE], &palette._mainPalette[0]);
- _vm->_palette->setFullPalette(palette._mainPalette);
- Common::copy(&_palFlags[0], &_palFlags[PALETTE_COUNT], &palette._palFlags[0]);
- palette._rgbList.copy(_rgbList);
-
- _vm->_dialogs->_defaultPosition.y = -1;
- }
-}
-
-/*------------------------------------------------------------------------*/
-
-GameDialog::DialogLine::DialogLine() {
- _active = true;
- _state = DLGSTATE_UNSELECTED;
- _textDisplayIndex = -1;
- _font = nullptr;
- _widthAdjust = 0;
- _msg = "";
-}
-
-GameDialog::DialogLine::DialogLine(const Common::String &s) {
- _active = true;
- _state = DLGSTATE_UNSELECTED;
- _textDisplayIndex = -1;
- _font = nullptr;
- _widthAdjust = -1;
- _msg = s;
-}
-
-/*------------------------------------------------------------------------*/
-
-GameDialog::GameDialog(MADSEngine *vm) : FullScreenDialog(vm) {
- Game &game = *_vm->_game;
- Scene &scene = game._scene;
-
- _tempLine = 0;
- _movedFlag = false;
- _redrawFlag = false;
- _selectedLine = -1;
- _dirFlag = false;
- _textLineCount = 0;
- _lineIndex = -1;
- _screenId = 920;
-
- chooseBackground();
- game.loadQuoteSet(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
- 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
- 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 0);
- game._kernelMode = KERNEL_ROOM_PRELOAD;
- _vm->_events->waitCursor();
- scene.clearVocab();
- scene._dynamicHotspots.clear();
- // Clear scene sprites and objects
- scene._spriteSlots.reset();
- _vm->_game->_screenObjects.clear();
- _vm->_dialogs->_defaultPosition = Common::Point(-1, -1);
- _menuSpritesIndex = 0;
-}
-
-void GameDialog::display() {
- Palette &palette = *_vm->_palette;
- palette.initPalette();
- palette.resetGamePalette(18, 10);
-
- FullScreenDialog::display();
-
- palette.setEntry(10, 0, 63, 0);
- palette.setEntry(11, 0, 45, 0);
- palette.setEntry(12, 63, 63, 0);
- palette.setEntry(13, 45, 45, 0);
- palette.setEntry(14, 63, 63, 63);
- palette.setEntry(15, 45, 45, 45);
-
- Scene &scene = _vm->_game->_scene;
- SpriteAsset *menuSprites = new SpriteAsset(_vm, "*MENU", 0);
- _menuSpritesIndex = scene._sprites.add(menuSprites);
-
- _lineIndex = -1;
- setClickableLines();
-
- _vm->_events->setCursor(CURSOR_ARROW);
-}
-
-GameDialog::~GameDialog() {
- _vm->_game->_scene._currentSceneId = RETURNING_FROM_DIALOG;
-}
-
-void GameDialog::clearLines() {
- Scene &scene = _vm->_game->_scene;
- _movedFlag = false;
- _lines.clear();
- scene._spriteSlots.fullRefresh(true);
-}
-
-void GameDialog::setClickableLines() {
- ScreenObjects &screenObjects = _vm->_game->_screenObjects;
-
- for (uint idx = 0; idx < _lines.size(); ++idx) {
- if (_lines[idx]._active) {
- const Common::Point &pt = _lines[idx]._pos;
- int strWidth = _lines[idx]._font->getWidth(_lines[idx]._msg);
- int maxHeight = _lines[idx]._font->getHeight();
-
- screenObjects.add(Common::Rect(pt.x, pt.y, pt.x + strWidth, pt.y + maxHeight - 1),
- SCREENMODE_VGA, CAT_COMMAND, idx);
- }
- }
-
- if (_vm->_dialogs->_pendingDialog == DIALOG_SAVE ||
- _vm->_dialogs->_pendingDialog == DIALOG_RESTORE) {
- screenObjects.add(Common::Rect(293, 26, 312, 75), SCREENMODE_VGA, CAT_INV_LIST, 50);
- screenObjects.add(Common::Rect(293, 78, 312, 127), SCREENMODE_VGA, CAT_INV_LIST, 51);
- }
-}
-
-void GameDialog::addQuote(int id1, int id2, DialogTextAlign align,
- const Common::Point &pt, Font *font) {
- Common::String msg = _vm->_game->getQuote(id1).c_str(); // c_str() because we need a copy
-
- if (id2 > 0)
- msg += _vm->_game->getQuote(id2);
-
- addLine(msg, align, pt, font);
-}
-
-void GameDialog::addLine(const Common::String &msg, DialogTextAlign align,
- const Common::Point &pt, Font *font) {
- Scene &scene = _vm->_game->_scene;
- DialogLine *line;
-
- if (font == nullptr)
- font = _vm->_font->getFont(FONT_CONVERSATION);
-
- if (_lineIndex < (int)_lines.size()) {
- if (_lines.size() >= 20) {
- ++_lineIndex;
- return;
- }
-
- _lines.push_back(msg);
- line = &_lines[_lines.size() - 1];
- } else {
- line = &_lines[_lineIndex];
- if (msg.compareToIgnoreCase(msg)) {
- ++_lineIndex;
- return;
- }
-
- if (line->_textDisplayIndex >= 0) {
- TextDisplay &textDisplay = scene._textDisplay[line->_textDisplayIndex];
- if (textDisplay._active) {
- textDisplay._expire = -1;
- if (_textLineCount < 20) {
- textDisplay._msg = msg;
- ++_textLineCount;
- }
- }
- }
- }
-
- line->_font = font;
- line->_state = DLGSTATE_UNSELECTED;
- line->_pos = pt;
- line->_widthAdjust = -1;
- line->_textDisplayIndex = -1;
-
- int xOffset;
- switch (align) {
- case ALIGN_NONE:
- // No adjustment
- break;
-
- case ALIGN_CENTER:
- xOffset = (MADS_SCREEN_WIDTH / 2) - font->getWidth(msg, -1) / 2;
- line->_pos.x += xOffset;
- break;
-
- case ALIGN_AT_CENTER: {
- const char *msgP = msg.c_str();
- const char *ch = strchr(msgP, '@');
- if (ch) {
- xOffset = (MADS_SCREEN_WIDTH / 2) - font->getWidth(
- Common::String(msgP, ch), line->_widthAdjust);
- line->_pos.x += xOffset;
-
- Common::String newMsg = msg.c_str();
- newMsg.deleteChar(ch - msgP);
- line->_msg = newMsg;
- }
- break;
- }
-
- case ALIGN_RIGHT:
- xOffset = font->getWidth(msg, -1);
- line->_pos.x -= xOffset;
- break;
-
- default:
- break;
- }
-
- ++_lineIndex;
-}
-
-void GameDialog::initVars() {
- _tempLine = -1;
- _selectedLine = -1;
- _lineIndex = 0;
- _textLineCount = 0;
-}
-
-void GameDialog::chooseBackground() {
- switch (_vm->_game->_currentSectionNumber) {
- case 1:
- case 2:
- _screenId = 921;
- break;
- case 3:
- case 4:
- _screenId = 922;
- break;
- case 5:
- case 6:
- case 7:
- _screenId = 923;
- break;
- case 8:
- _screenId = 924;
- break;
- default:
- _screenId = 920;
- break;
- }
-}
-
-void GameDialog::setFrame(int frameNumber, int depth) {
- Scene &scene = _vm->_game->_scene;
- SpriteAsset *menuSprites = scene._sprites[_menuSpritesIndex];
- MSprite *frame = menuSprites->getFrame(frameNumber - 1);
-
- SpriteSlot &spriteSlot = scene._spriteSlots[scene._spriteSlots.add()];
- spriteSlot._flags = IMG_UPDATE;
- spriteSlot._seqIndex = 1;
- spriteSlot._spritesIndex = _menuSpritesIndex;
- spriteSlot._frameNumber = frameNumber;
- spriteSlot._position = frame->_offset;
- spriteSlot._depth = depth;
- spriteSlot._scale = 100;
-}
-
-void GameDialog::show() {
- display();
-
- Scene &scene = _vm->_game->_scene;
-
- while (_selectedLine == -1 && !_vm->shouldQuit()) {
- handleEvents();
- if (_redrawFlag) {
- if (!_tempLine)
- _tempLine = -1;
-
- refreshText();
- scene.drawElements(_vm->_game->_fx, _vm->_game->_fx);
- _redrawFlag = false;
- }
-
- _vm->_events->waitForNextFrame();
- _vm->_game->_fx = kTransitionNone;
- }
-}
-
-void GameDialog::handleEvents() {
- ScreenObjects &screenObjects = _vm->_game->_screenObjects;
- EventsManager &events = *_vm->_events;
- auto &dialogs = *(Phantom::DialogsPhantom *)_vm->_dialogs;
- int tempLine = _tempLine;
-
- // Mark all the lines as initially unselected
- for (uint i = 0; i < _lines.size(); ++i)
- _lines[i]._state = DLGSTATE_UNSELECTED;
-
- // Process pending events
- events.pollEvents();
-
- if (events.isActionTriggered()) {
- switch (events.getAction()) {
- case kActionEscape:
- _selectedLine = 0;
- break;
- default:
- break;
- }
- }
-
- // Scan for objects in the dialog
- Common::Point mousePos = events.currentPos() - Common::Point(0, DIALOG_TOP);
- int objIndex = screenObjects.scan(mousePos, SCREENMODE_VGA);
-
- if (_movedFlag) {
- int yp = mousePos.y;
- if (yp < screenObjects[1]._bounds.top) {
- if (!events._mouseReleased)
- _lines[1]._state = DLGSTATE_SELECTED;
- objIndex = 19;
- }
-
- if (yp < screenObjects[7]._bounds.bottom) {
- if (!events._mouseReleased)
- _lines[1]._state = DLGSTATE_SELECTED;
- objIndex = 20;
- }
- }
-
- int line = -1;
- if (objIndex > 0 && (events._mouseStatus || events._mouseReleased)) {
- line = screenObjects[objIndex]._descId;
- if (dialogs._pendingDialog == DIALOG_SAVE || dialogs._pendingDialog == DIALOG_RESTORE) {
- if (line > 7 && line <= 14) {
- _lines[line]._state = DLGSTATE_UNSELECTED;
- line -= 7;
- }
-
- bool movedFlag = line > 0 && line < 8;
- if (events._mouseMoved)
- _movedFlag = movedFlag;
- }
-
- if (screenObjects[objIndex]._category == CAT_COMMAND) {
- _lines[line]._state = DLGSTATE_SELECTED;
- }
- }
- if (!line)
- line = -1;
-
- if (dialogs._pendingDialog == DIALOG_ERROR && line == 1)
- line = -1;
-
- if (events._mouseReleased) {
- if (!_movedFlag || line <= 18)
- _selectedLine = line;
- _redrawFlag = true;
- }
-
- _tempLine = line;
- if (tempLine != line || _selectedLine >= 0)
- _redrawFlag = true;
-}
-
-void GameDialog::refreshText() {
- Scene &scene = _vm->_game->_scene;
-
- for (uint i = 0; i < _lines.size(); ++i) {
- if (_lines[i]._active) {
- int fontColor;
- switch (_lines[i]._state) {
- case DLGSTATE_UNSELECTED:
- fontColor = 0xB0A;
- break;
- case DLGSTATE_SELECTED:
- fontColor = 0xD0C;
- break;
- default:
- fontColor = 0xF0E;
- break;
- }
-
- bool skipFlag = false;
- if (_lines[i]._textDisplayIndex >= 0) {
- TextDisplay &textDisplay = scene._textDisplay[_lines[i]._textDisplayIndex];
- int currCol = textDisplay._color1;
- if (currCol != fontColor) {
- scene._textDisplay.expire(_lines[i]._textDisplayIndex);
- _lines[i]._textDisplayIndex = -1;
- } else {
- skipFlag = true;
- }
- }
-
- if (!skipFlag) {
- _lines[i]._textDisplayIndex = scene._textDisplay.add(_lines[i]._pos.x, _lines[i]._pos.y,
- fontColor, _lines[i]._widthAdjust, _lines[i]._msg, _lines[i]._font);
- }
- }
- }
-}
-
-/*------------------------------------------------------------------------*/
-
-DifficultyDialog::DifficultyDialog(MADSEngine *vm) : GameDialog(vm) {
- setLines();
- _vm->_palette->resetGamePalette(18, 10);
-}
-
-void DifficultyDialog::setLines() {
- Font *font = _vm->_font->getFont(FONT_CONVERSATION);
- int yp = 78 - ((font->getHeight() + 1) * 4 + 6) / 2;
-
- addQuote(41, 0, ALIGN_CENTER, Common::Point(0, yp), font);
- yp += 6;
-
- for (int id = 42; id <= 44; ++id) {
- yp += font->getHeight();
- addQuote(id, 0, ALIGN_CENTER, Common::Point(0, yp));
- }
-}
-
-void DifficultyDialog::display() {
- GameDialog::display();
- setFrame(8, 2);
-}
-
-void DifficultyDialog::show() {
- GameDialog::show();
- auto &game = *(Phantom::GamePhantom *)_vm->_game;
-
- switch (_selectedLine) {
- case 1:
- game._difficulty = Phantom::DIFFICULTY_EASY;
- break;
- case 2:
- game._difficulty = Phantom::DIFFICULTY_HARD;
- break;
- default:
- _vm->quitGame();
- }
-}
-
-/*------------------------------------------------------------------------*/
-
-GameMenuDialog::GameMenuDialog(MADSEngine *vm) : GameDialog(vm) {
- setLines();
-}
-
-void GameMenuDialog::setLines() {
- Font *font = _vm->_font->getFont(FONT_CONVERSATION);
-
- int yp = 64 - ((font->getHeight() + 1) * 4 + 6) / 2;
-
- addQuote(10, 0, ALIGN_CENTER, Common::Point(0, yp), font);
- yp += 6;
-
- for (int id = 11; id <= 15; ++id) {
- yp += font->getHeight();
- addQuote(id, 0, ALIGN_CENTER, Common::Point(0, yp));
- }
-}
-
-void GameMenuDialog::display() {
- GameDialog::display();
- setFrame(1, 2);
-}
-
-void GameMenuDialog::show() {
- GameDialog::show();
-
- switch (_selectedLine) {
- case 1:
- _vm->_dialogs->_pendingDialog = DIALOG_SAVE;
- _vm->_dialogs->showDialog();
- break;
- case 2:
- _vm->_dialogs->_pendingDialog = DIALOG_RESTORE;
- _vm->_dialogs->showDialog();
- break;
- case 3:
- _vm->_dialogs->_pendingDialog = DIALOG_OPTIONS;
- _vm->_dialogs->showDialog();
- break;
- case 5:
- _vm->quitGame();
- break;
- case 4:
- default:
- // Resume game
- break;
- }
-}
-
-/*------------------------------------------------------------------------*/
-
-OptionsDialog::OptionsDialog(MADSEngine *vm) : GameDialog(vm) {
- setLines();
-}
-
-int OptionsDialog::getOptionQuote(int option) {
-#ifdef TODO
- auto &game = *(Phantom::GamePhantom *)_vm->_game;
-
- switch (option) {
- case 17: // Music
- return _vm->_musicFlag ? 24 : 25; // 24: ON, 25: OFF
- case 18: // Sound
- return _vm->_soundFlag ? 26 : 27; // 26: ON, 27: OFF
- case 19: // Interface
- return !_vm->_easyMouse ? 28 : 29; // 28: Standard, 29: Easy
- case 20: // Inventory
- return _vm->_invObjectsAnimated ? 30 : 31; // 30: Spinning, 31: Still
- case 21: // Text window
- return !_vm->_textWindowStill ? 32 : 33; // 32: Animated, 33: Still
- case 22: // Screen fade
- return 34 + _vm->_screenFade; // 34: Smooth, 35: Medium, 36: Fast
- case 23: // Storyline
- return (game._storyMode == STORYMODE_NAUGHTY) ? 37 : 38; // 37: Naughty, 38: Nice
- default:
- error("getOptionQuote: Unknown option");
- }
-#endif
- return 0;
-}
-
-void OptionsDialog::setLines() {
- Font *font = _vm->_font->getFont(FONT_CONVERSATION);
-
- int yp = 40 - ((font->getHeight() + 1) * 4 + 6) / 2;
-
- addQuote(16, 0, ALIGN_CENTER, Common::Point(0, yp), font);
- yp += 6;
-
- for (int id = 17; id <= 23; ++id) {
- yp += font->getHeight();
- addQuote(id, getOptionQuote(id), ALIGN_AT_CENTER, Common::Point(0, yp));
- }
-
- yp += 28;
- addQuote(1, 0, ALIGN_NONE, Common::Point(90, yp));
- addQuote(2, 0, ALIGN_NONE, Common::Point(190, yp));
-}
-
-void OptionsDialog::display() {
- GameDialog::display();
- setFrame(2, 2);
-}
-
-void OptionsDialog::show() {
-// auto &game = *(Phantom::GamePhantom *)_vm->_game;
-
- // Previous options, restored when cancel is selected
- bool prevMusicFlag = _vm->_musicFlag;
- bool prevEasyMouse = _vm->_easyMouse;
- bool prevInvObjectsAnimated = _vm->_invObjectsAnimated;
- bool prevTextWindowStill = _vm->_textWindowStill;
- ScreenFade prevScreenFade = _vm->_screenFade;
-// StoryMode prevStoryMode = game._storyMode;
-
- do {
- _selectedLine = -1;
- GameDialog::show();
-
- switch (_selectedLine) {
- case 1: // Music
- _vm->_musicFlag = _vm->_soundFlag = !_vm->_musicFlag;
- break;
- case 2: // Sound
- _vm->_musicFlag = _vm->_soundFlag = !_vm->_musicFlag;
- break;
- case 3: // Interface
- _vm->_easyMouse = !_vm->_easyMouse;
- break;
- case 4: // Inventory
- _vm->_invObjectsAnimated = !_vm->_invObjectsAnimated;
- break;
- case 5: // Text window
- _vm->_textWindowStill = !_vm->_textWindowStill;
- break;
- case 6: // Screen fade
- if (_vm->_screenFade == SCREEN_FADE_FAST)
- _vm->_screenFade = SCREEN_FADE_MEDIUM;
- else if (_vm->_screenFade == SCREEN_FADE_MEDIUM)
- _vm->_screenFade = SCREEN_FADE_SMOOTH;
- else
- _vm->_screenFade = SCREEN_FADE_FAST;
- break;
-// case 7: // Storyline
-// game._storyMode = (game._storyMode == STORYMODE_NAUGHTY) ? STORYMODE_NICE : STORYMODE_NAUGHTY;
-// break;
- default:
- break;
- }
-
- // Reload menu
- _lineIndex = -1;
- clearLines();
- _vm->_game->_screenObjects.clear();
- _vm->_game->_scene._spriteSlots.reset();
- setLines();
- } while (!_vm->shouldQuit() && _selectedLine != 0 && _selectedLine <= 7);
-
- if (_selectedLine == 8) {
- // OK button, save settings
- _vm->saveOptions();
- } else if (_selectedLine == 9) {
- // Cancel button, revert all options from the saved ones
- _vm->_musicFlag = _vm->_soundFlag = prevMusicFlag;
- _vm->_easyMouse = prevEasyMouse;
- _vm->_invObjectsAnimated = prevInvObjectsAnimated;
- _vm->_textWindowStill = prevTextWindowStill;
- _vm->_screenFade = prevScreenFade;
- //game._storyMode = prevStoryMode;
- }
-}
-
-} // namespace Phantom
-} // namespace MADS
diff --git a/engines/mads/phantom/dialogs_phantom.h b/engines/mads/phantom/dialogs_phantom.h
deleted file mode 100644
index f669aa42754..00000000000
--- a/engines/mads/phantom/dialogs_phantom.h
+++ /dev/null
@@ -1,269 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#ifndef MADS_DIALOGS_PHANTOM_H
-#define MADS_DIALOGS_PHANTOM_H
-
-#include "common/scummsys.h"
-#include "mads/game.h"
-#include "mads/dialogs.h"
-
-namespace MADS {
-namespace Phantom {
-
-enum CapitalizationMode { kUppercase = 0, kLowercase = 1, kUpperAndLower = 2 };
-
-class DialogsPhantom : public Dialogs {
- friend class Dialogs;
-private:
- int _dialogWidth;
- CapitalizationMode _capitalizationMode;
-
- DialogsPhantom(MADSEngine *vm): Dialogs(vm), _capitalizationMode(kUppercase), _dialogWidth(0) {}
-
- Common::String getVocab(int vocabId) override;
-
- bool textNoun(Common::String &dest, int nounId, const Common::String &source);
-
- bool commandCheck(const char *idStr, Common::String &valStr, const Common::String &command);
-
- void showScummVMSaveDialog();
- void showScummVMRestoreDialog();
-
-public:
- void showDialog() override;
-
- void showItem(int objectId, int messageId, int speech = -1) override;
-
- bool show(int messageId, int objectId = -1) override;
-};
-
-struct HOGANUS {
- int _bookId;
- int _pageNum;
- int _lineNum;
- int _wordNum;
- Common::String _word;
-};
-
-class CopyProtectionDialog : public TextDialog {
-private:
- HOGANUS _hogEntry;
- Common::String _textInput;
-
- /**
- * Get a random copy protection entry from the HOGANUS resource
- */
- bool getHogAnusEntry(HOGANUS &entry);
-public:
- /**
- * Constructor
- */
- CopyProtectionDialog(MADSEngine *vm, bool priorAnswerWrong);
-
- /**
- * Show the dialog
- */
- void show() override;
-
- bool isCorrectAnswer();
-};
-
-class PictureDialog : public TextDialog {
-private:
- int _objectId;
- bool _cyclingActive;
- byte _palette[PALETTE_SIZE];
- uint32 _palFlags[PALETTE_COUNT];
- RGBList _rgbList;
-protected:
- void save() override;
-
- void restore() override;
-public:
- PictureDialog(MADSEngine *vm, const Common::Point &pos, int maxChars, int objectId);
-
- ~PictureDialog() override;
-};
-
-enum DialogTextAlign { ALIGN_NONE = 0, ALIGN_CENTER = -1, ALIGN_AT_CENTER = -2, ALIGN_RIGHT = -3 };
-
-enum DialogState { DLGSTATE_UNSELECTED = 0, DLGSTATE_SELECTED = 1, DLGSTATE_FOCUSED = 2 };
-
-class GameDialog: public FullScreenDialog {
- struct DialogLine {
- bool _active;
- DialogState _state;
- Common::Point _pos;
- int _textDisplayIndex;
- Common::String _msg;
- Font *_font;
- int _widthAdjust;
-
- DialogLine();
- DialogLine(const Common::String &s);
- };
-protected:
- Common::Array<DialogLine> _lines;
- int _tempLine;
- bool _movedFlag;
- bool _redrawFlag;
- int _selectedLine;
- bool _dirFlag;
- int _menuSpritesIndex;
- int _lineIndex;
- int _textLineCount;
-
- /**
- * Display the dialog
- */
- void display() override;
-
- /**
- * Reset the lines list for the dialog
- */
- void clearLines();
-
- /**
- * Setup lines to be clickable
- */
- void setClickableLines();
-
- /**
- * Add a quote to the lines list
- */
- void addQuote(int id1, int id2, DialogTextAlign align, const Common::Point &pt, Font *font = nullptr);
-
- /**
- * Adds a line to the lines list
- */
- void addLine(const Common::String &msg, DialogTextAlign align, const Common::Point &pt, Font *font = nullptr);
-
- /**
- * Initializes variables
- */
- void initVars();
-
- /**
- * Sets the display for the screen background behind the dialog
- */
- void setFrame(int frameNumber, int depth);
-
- /**
- * Choose the background to display for the dialog
- */
- void chooseBackground();
-
- /**
- * Handle events whilst the dialog is active
- */
- void handleEvents();
-
- /**
- * Refresh the display of the dialog's text
- */
- void refreshText();
-public:
- /**
- * Constructor
- */
- GameDialog(MADSEngine *vm);
-
- /**
- * Destructor
- */
- ~GameDialog() override;
-
- /**
- * Show the dialog
- */
- virtual void show();
-};
-
-class DifficultyDialog : public GameDialog {
-private:
- /**
- * Set the lines for the dialog
- */
- void setLines();
-public:
- DifficultyDialog(MADSEngine *vm);
-
- /**
- * Display the dialog
- */
- void display() override;
-
- /**
- * Show the dialog
- */
- void show() override;
-};
-
-class GameMenuDialog : public GameDialog {
-private:
- /**
- * Set the lines for the dialog
- */
- void setLines();
-public:
- GameMenuDialog(MADSEngine *vm);
-
- /**
- * Display the dialog
- */
- void display() override;
-
- /**
- * Show the dialog
- */
- void show() override;
-};
-
-class OptionsDialog : public GameDialog {
-private:
- /**
- * Set the lines for the dialog
- */
- void setLines();
-
- /**
- * Gets the quote to be shown for an option
- */
- int getOptionQuote(int option);
-public:
- OptionsDialog(MADSEngine *vm);
-
- /**
- * Display the dialog
- */
- void display() override;
-
- /**
- * Show the dialog
- */
- void show() override;
-};
-
-} // namespace Phantom
-} // namespace MADS
-
-#endif
diff --git a/engines/mads/phantom/game_phantom.cpp b/engines/mads/phantom/game_phantom.cpp
deleted file mode 100644
index daa31b51ba3..00000000000
--- a/engines/mads/phantom/game_phantom.cpp
+++ /dev/null
@@ -1,987 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include "mads/mads.h"
-#include "mads/game.h"
-#include "mads/screen.h"
-#include "mads/msurface.h"
-#include "mads/menu_views.h"
-#include "mads/phantom/game_phantom.h"
-#include "mads/phantom/globals_phantom.h"
-#include "mads/phantom/phantom_scenes.h"
-
-namespace MADS {
-namespace Phantom {
-
-static const Catacombs EASY_CATACOMBS[32] = {
- { 401, { -1, 1, 2, 6 }, { 2, 3, 0, 1 }, MAZE_EVENT_BRICK },
- { 404, { 10, 11, 3, 0 }, { 2, 3, 0, 1 }, MAZE_EVENT_PUDDLE },
- { 404, { 0, 3, 4, -2 }, { 2, 3, 0, 1 }, MAZE_EVENT_BLOCK },
- { 401, { 1, 14, 5, 2 }, { 2, 3, 0, 1 }, MAZE_EVENT_POT },
- { 453, { 2, 4, -1, 4 }, { 2, 3, 0, 1 }, MAZE_EVENT_DRAIN },
- { 403, { 3, 6, -1, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_BRICK | MAZE_EVENT_PLANK },
- { 406, { -1, 0, -1, 5 }, { 2, 3, 0, 1 }, MAZE_EVENT_NONE },
- { 453, { -1, 8, -1, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_BRICK },
- { 406, { -1, 9, -1, 7 }, { 2, 3, 0, 1 }, MAZE_EVENT_NONE },
- { 401, { 1, -1, 10, 8 }, { 2, 3, 0, 1 }, MAZE_EVENT_RAT_NEST | MAZE_EVENT_SKULL },
- { 408, { 9, -1, 1, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_NONE },
- { 453, { 12, -1, -1, 1 }, { 2, 3, 0, 1 }, MAZE_EVENT_BRICK | MAZE_EVENT_STONE },
- { 408, { 13, -1, 11, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_BRICK },
- { 401, { 13, 20, 12, 13 }, { 3, 3, 0, 0 }, MAZE_EVENT_BRICK },
- { 453, { 16, 15, -1, 3 }, { 2, 3, 0, 1 }, MAZE_EVENT_BRICK | MAZE_EVENT_RAT_NEST },
- { 456, { -1, -1, -1, 14 }, { 2, 3, 0, 1 }, MAZE_EVENT_NONE },
- { 404, { -1, 17, 14, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_WEB | MAZE_EVENT_POT },
- { 401, { 18, -1, 19, 16 }, { 2, 3, 0, 1 }, MAZE_EVENT_BRICK },
- { 408, { -1, -1, 17, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_BRICK },
- { 403, { 17, -1, -1, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_HOLE | MAZE_EVENT_WEB },
- { 403, { 21, 22, -1, 13 }, { 2, 3, 0, 1 }, MAZE_EVENT_WEB | MAZE_EVENT_SKULL },
- { 404, { -1, -1, 20, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_NONE },
- { 406, { -1, 23, -1, 20 }, { 2, 3, 0, 1 }, MAZE_EVENT_NONE },
- { 404, { 24, 23, 23, 22 }, { 2, 2, 1, 1 }, MAZE_EVENT_RAT_NEST | MAZE_EVENT_BRICK },
- { 401, { -1, 1, 23, 25 }, { 2, 1, 0, 1 }, MAZE_EVENT_PUDDLE | MAZE_EVENT_POT | MAZE_EVENT_BRICK },
- { 407, { 29, 24, 28, 26 }, { 3, 3, 1, 1 }, MAZE_EVENT_NONE },
- { 401, { 27, 25, 23, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_SKULL },
- { 404, { -1, 28, 26, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_WEB | MAZE_EVENT_FALLEN_BLOCK },
- { 456, { -1, 25, -1, 27 }, { 2, 2, 0, 1 }, MAZE_EVENT_NONE },
- { 406, { -1, 30, -1, 25 }, { 2, 3, 0, 0 }, MAZE_EVENT_NONE },
- { 453, { -3, 30, -1, 29 }, { 2, 3, 0, 1 }, MAZE_EVENT_STONE | MAZE_EVENT_RAT_NEST | MAZE_EVENT_WEB },
- { 408, { -5, -1, -4, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_WEB | MAZE_EVENT_BRICK }
-};
-
-static const Catacombs HARD_CATACOMBS[62] = {
- { 401, { -1, 1, 2, 6 }, { 2, 3, 0, 1 }, MAZE_EVENT_BRICK },
- { 404, { 10, 11, 3, 0 }, { 2, 3, 0, 1 }, MAZE_EVENT_PUDDLE },
- { 404, { 0, 3, 4, -2 }, { 2, 3, 0, 1 }, MAZE_EVENT_BLOCK },
- { 401, { 1, 20, 5, 2 }, { 2, 0, 0, 1 }, MAZE_EVENT_POT },
- { 453, { 2, 4, -1, 4 }, { 2, 3, 0, 1 }, MAZE_EVENT_DRAIN },
- { 403, { 3, 6, -1, 4 }, { 2, 3, 0, 1 }, MAZE_EVENT_BRICK | MAZE_EVENT_PLANK },
- { 406, { -1, 0, -1, 5 }, { 2, 3, 0, 1 }, MAZE_EVENT_NONE },
- { 453, { -1, 8, -1, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_BRICK },
- { 406, { -1, 9, -1, 7 }, { 2, 3, 0, 1 }, MAZE_EVENT_NONE },
- { 401, { 1, -1, 10, 8 }, { 0, 3, 0, 1 }, MAZE_EVENT_RAT_NEST | MAZE_EVENT_SKULL },
- { 408, { 9, -1, 1, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_NONE },
- { 453, { 12, -1, -1, 1 }, { 2, 3, 0, 1 }, MAZE_EVENT_BRICK | MAZE_EVENT_STONE },
- { 408, { 13, -1, 11, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_BRICK },
- { 401, { 13, 21, 12, 13 }, { 3, 3, 0, 0 }, MAZE_EVENT_BRICK },
- { 453, { 16, 15, -1, 20 }, { 2, 3, 0, 2 }, MAZE_EVENT_RAT_NEST | MAZE_EVENT_BRICK },
- { 456, { -1, -1, -1, 14 }, { 2, 3, 0, 1 }, MAZE_EVENT_NONE },
- { 404, { -1, 17, 14, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_WEB | MAZE_EVENT_POT },
- { 401, { 18, -1, 19, 16 }, { 2, 3, 0, 1 }, MAZE_EVENT_BRICK },
- { 408, { -1, -1, 17, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_BRICK },
- { 403, { 17, -1, -1, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_HOLE | MAZE_EVENT_WEB },
- { 408, { 3, -1, 14, -1 }, { 1, 3, 3, 1 }, MAZE_EVENT_NONE },
- { 404, { 9, 30, 22, 13 }, { 0, 3, 0, 1 }, MAZE_EVENT_RAT_NEST },
- { 403, { 21, 23, -1, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_HOLE | MAZE_EVENT_WEB },
- { 401, { -1, -1, 24, 22 }, { 2, 3, 3, 1 }, MAZE_EVENT_BRICK },
- { 406, { -1, 26, -1, 23 }, { 2, 0, 0, 2 }, MAZE_EVENT_NONE },
- { 407, { 36, 33, 35, 34 }, { 3, 3, 1, 1 }, MAZE_EVENT_NONE },
- { 453, { 24, 27, -1, -1 }, { 1, 0, 0, 1 }, MAZE_EVENT_BRICK },
- { 403, { 26, -1, -1, 28 }, { 1, 3, 0, 0 }, MAZE_EVENT_BRICK | MAZE_EVENT_SKULL },
- { 404, { 27, 28, 28, 29 }, { 3, 2, 1, 2 }, MAZE_EVENT_NONE },
- { 408, { -1, -1, 28, -1 }, { 2, 3, 3, 1 }, MAZE_EVENT_BRICK },
- { 406, { -1, 31, -1, 21 }, { 2, 0, 0, 1 }, MAZE_EVENT_NONE },
- { 401, { 30, 33, 1, -1 }, { 1, 2, 1, 1 }, MAZE_EVENT_PUDDLE | MAZE_EVENT_POT },
- { 456, { -1, 31, -1, 33 }, { 2, 1, 0, 0 }, MAZE_EVENT_NONE },
- { 404, { 32, -1, 31, 25 }, { 3, 3, 1, 1 }, MAZE_EVENT_NONE },
- { 401, { 46, 25, 31, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_SKULL },
- { 401, { -1, 25, 41, -1 }, { 2, 2, 1, 1 }, MAZE_EVENT_BRICK | MAZE_EVENT_POT },
- { 406, { -1, 37, -1, 25 }, { 2, 3, 0, 0 }, MAZE_EVENT_NONE },
- { 453, { -3, 37, -1, 36 }, { 2, 3, 0, 1 }, MAZE_EVENT_STONE | MAZE_EVENT_RAT_NEST | MAZE_EVENT_WEB },
- { 408, { 57, -1, 54, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_NONE },
- { 408, { 40, -1, -4, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_BRICK | MAZE_EVENT_WEB },
- { 404, { 40, 40, 39, 53 }, { 1, 0, 0, 1 }, MAZE_EVENT_BLOCK | MAZE_EVENT_FALLEN_BLOCK },
- { 456, { -1, 35, -1, 42 }, { 2, 2, 0, 2 }, MAZE_EVENT_NONE },
- { 408, { 43, -1, 41, -1 }, { 1, 3, 3, 1 }, MAZE_EVENT_BRICK },
- { 406, { -1, 42, -1, 61 }, { 2, 0, 0, 1 }, MAZE_EVENT_NONE },
- { 403, { 58, 45, -1, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_BRICK | MAZE_EVENT_RAT_NEST },
- { 401, { 34, -1, 46, 44 }, { 0, 3, 0, 1 }, MAZE_EVENT_RAT_NEST | MAZE_EVENT_BRICK },
- { 404, { 45, -1, 34, 47 }, { 2, 3, 0, 1 }, MAZE_EVENT_WEB | MAZE_EVENT_FALLEN_BLOCK },
- { 406, { -1, 46, -1, 48 }, { 2, 3, 0, 1 }, MAZE_EVENT_NONE },
- { 403, { 49, 47, -1, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_BRICK | MAZE_EVENT_SKULL | MAZE_EVENT_WEB },
- { 408, { 50, -1, 48, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_BRICK },
- { 408, { 51, -1, 49, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_NONE },
- { 408, { 52, -1, 50, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_BRICK },
- { 408, { -1, -1, 51, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_BRICK },
- { 406, { -1, 40, -1, 54 }, { 2, 3, 0, 1 }, MAZE_EVENT_NONE },
- { 403, { 38, 53, -1, 55 }, { 2, 3, 0, 1 }, MAZE_EVENT_SKULL },
- { 453, { 56, 54, -1, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_BRICK | MAZE_EVENT_WEB },
- { 401, { 56, -5, 55, 56 }, { 3, 3, 0, 0 }, MAZE_EVENT_BRICK | MAZE_EVENT_SKULL },
- { 404, { -1, 57, 38, 57 }, { 2, 3, 0, 1 }, MAZE_EVENT_POT | MAZE_EVENT_BLOCK },
- { 404, { 59, 59, 44, 60 }, { 2, 3, 0, 1 }, MAZE_EVENT_NONE },
- { 404, { 59, 60, 59, 58 }, { 2, 3, 0, 1 }, MAZE_EVENT_NONE },
- { 404, { 61, 58, 59, 59 }, { 2, 3, 0, 1 }, MAZE_EVENT_NONE },
- { 404, { 34, 43, 60, 44 }, { 0, 3, 0, 1 }, MAZE_EVENT_NONE }
-};
-
-GamePhantom::GamePhantom(MADSEngine *vm) : Game(vm) {
- _surface = new MSurface(MADS_SCREEN_WIDTH, MADS_SCENE_HEIGHT);
- _difficulty = DIFFICULTY_HARD;
- _catacombs = nullptr;
- _catacombSize = -1;
-}
-
-void GamePhantom::startGame() {
- // First handle any ending credits from a just finished game session.
- // Note that, with the exception of the decompression ending, which doesn't
- // use animations, the remaining animations will automatically launch their
- // own text view credits when the animation is completed
- switch (_winStatus) {
- case 1:
- // No shields failure ending
- AnimationView::execute(_vm, "rexend1");
- break;
- case 2:
- // Shields, but no targeting failure ending
- AnimationView::execute(_vm, "rexend2");
- break;
- case 3:
- AnimationView::execute(_vm, "rexend3");
- break;
- case 4:
- // Decompression ending
- TextView::execute(_vm, "ending4");
- break;
- default:
- break;
- }
-
- do {
- checkShowDialog();
- _winStatus = 0;
-
- _sectionNumber = 1;
- initSection(_sectionNumber);
- _vm->_events->setCursor(CURSOR_ARROW);
- _statusFlag = true;
-
- // Show the main menu
- _vm->_dialogs->_pendingDialog = DIALOG_MAIN_MENU;
- _vm->_dialogs->showDialog();
- } while (!_vm->shouldQuit() && _vm->_dialogs->_pendingDialog != DIALOG_NONE);
-
- if (_vm->shouldQuit())
- return;
-
- _scene._priorSceneId = 0;
- _scene._currentSceneId = -1;
- _scene._nextSceneId = 101;
-
- initializeGlobals();
-}
-
-void GamePhantom::initializeGlobals() {
- _globals.reset();
- setupCatacombs();
-
- _player._facing = FACING_NORTH;
- _player._turnToFacing = FACING_NORTH;
-
- _globals[kTempVar] = false;
- _globals[kRoom103104Transition] = 1; // new room
- _globals[kCurrentYear] = 1993;
- _globals[kTrapDoorStatus] = 0; // open
- _globals[kChristineDoorStatus] = 0; // Christine is in her room
- _globals[kSandbagStatus] = 0; // sandbag is secure
- _globals[kJacquesStatus] = 0; // alive
- _globals[kChrisFStatus] = 1; // Christine F. is alive in 1993
- _globals[kBrieTalkStatus] = 0; // before Brie motions
- _globals[kPanelIn206] = 0; // not discovered
- _globals[kFightStatus] = 0;
- _globals[kJuliesDoor] = 1; // cracked open
- _globals[kPrompterStandStatus] = 0;
- _globals[kChrisDStatus] = 0; // before love
- _globals[kJulieNameIsKnown] = 0;
- _globals[kDoorsIn205] = 0; // both locked
- _globals[kMadameGiryLocation] = 1; // middle
- _globals[kTicketPeoplePresent] = 0;
- _globals[kCoffinStatus] = 0; // closed and locked
- _globals[kDoneBrieConv203] = 0;
- _globals[kFlorentNameIsKnown] = 0;
- _globals[kDegasNameIsKnown] = 0;
- _globals[kMadameGiryShowsUp] = false;
- _globals[kJacquesNameIsKnown] = 0;
- _globals[kCharlesNameIsKnown] = false;
- _globals[kTopFloorLocked] = true;
- _globals[kMadameNameIsKnown] = 0;
- _globals[kChrisKickedRaoulOut] = false;
- _globals[kLookedAtCase] = false;
- _globals[kRingIsOnFinger] = false;
- _globals[kHeListened] = false;
- _globals[kKnockedOverHead] = false;
- _globals[kObservedPhan104] = false;
- _globals[kReadBook] = false;
- _globals[kCanFindBookInLibrary] = false;
- _globals[kLookedAtSkullFace] = false;
- _globals[kScannedBookcase] = false;
- _globals[kRanConvIn205] = false;
- _globals[kDoneRichConv203] = false;
- _globals[kHintThatDaaeIsHome1] = false;
- _globals[kHintThatDaaeIsHome2] = false;
- _globals[kMakeBrieLeave203] = false;
- _globals[kMakeRichLeave203] = false;
- _globals[kCameFromFade] = false;
- _globals[kChristineToldEnvelope] = false;
- _globals[kLeaveAngelMusicOn] = false;
- _globals[kDoorIn409IsOpen] = false;
- _globals[kPriestPistonPuke] = false;
- _globals[kCobwebIsCut] = false;
- _globals[kChristineIsInBoat] = false;
- _globals[kRightDoorIsOpen504] = false;
- _globals[kChrisLeft505] = false;
- _globals[kChrisWillTakeSeat] = true;
- _globals[kFlickedLever1] = 0;
- _globals[kFlickedLever2] = 0;
- _globals[kFlickedLever3] = 0;
- _globals[kFlickedLever4] = 0;
- _globals[kPlayerScore] = 0;
- _globals[kPlayerScoreFlags] = 0;
-
- _globals[kMusicSelected] = _vm->getRandomNumber(1, 4);
-
- _player._spritesPrefix = "RAL"; // Fixed prefix
- Player::preloadSequences("RAL", 1);
-
- static const char *SEQ[] = {
- "*BOX", "*LOGO", "*MENU", "*CURSOR", "*FACERAL", "*RRD_8", "*RRD_9",
- "*RDR_6", "*RDR_9", "*RTK_6", "*RTK_9", "*RALRH_9", nullptr
- };
- for (const char **seq = SEQ; *seq; ++seq)
- Player::himem_preload_series(*seq, 1);
-}
-
-void GamePhantom::setSectionHandler() {
- delete _sectionHandler;
-
- switch (_sectionNumber) {
- case 1:
- _sectionHandler = new Section1Handler(_vm);
- break;
- case 2:
- _sectionHandler = new Section2Handler(_vm);
- break;
- case 3:
- _sectionHandler = new Section3Handler(_vm);
- break;
- case 4:
- _sectionHandler = new Section4Handler(_vm);
- break;
- case 5:
- _sectionHandler = new Section5Handler(_vm);
- break;
- default:
- break;
- }
-}
-
-void GamePhantom::checkShowDialog() {
- // TODO: Copied from Nebular
- if (_vm->_dialogs->_pendingDialog && _player._stepEnabled && !_globals[5]) {
- _player.releasePlayerSprites();
-
- // HACK: Skip the main menu (since it'll then try to show Rex's main menu)
- if (_vm->_dialogs->_pendingDialog == DIALOG_MAIN_MENU)
- _vm->_dialogs->_pendingDialog = DIALOG_NONE;
-
- _vm->_dialogs->showDialog();
- _vm->_dialogs->_pendingDialog = DIALOG_NONE;
- }
-}
-
-void GamePhantom::genericObjectExamine() {
- MADSAction &action = _scene._action;
- int id = _objects.getIdFromDesc(action._activeAction._objectNameId);
-
- if (action.isAction(VERB_LOOK, NOUN_RED_FRAME))
- _vm->_dialogs->showItem(id, (_globals[kCurrentYear] == 1993) ? 802 : 842, 0);
- else if (action.isAction(VERB_LOOK, NOUN_YELLOW_FRAME))
- _vm->_dialogs->showItem(id, (_globals[kCurrentYear] == 1993) ? 804 : 843, 0);
- else if (action.isAction(VERB_LOOK, NOUN_BLUE_FRAME))
- _vm->_dialogs->showItem(id, (_globals[kCurrentYear] == 1993) ? 817 : 844, 0);
- else if (action.isAction(VERB_LOOK, NOUN_GREEN_FRAME))
- _vm->_dialogs->showItem(id, (_globals[kCurrentYear] == 1993) ? 819 : 845, 0);
- else if (action.isAction(VERB_LOOK, NOUN_LANTERN))
- _vm->_dialogs->showItem(id, (_globals[kLanternStatus] == 1) ? 831 : 801, 0);
- else if (action.isAction(VERB_LOOK, NOUN_SMALL_NOTE))
- _vm->_dialogs->showItem(OBJ_SMALL_NOTE, 846, 2);
- else if (action.isAction(VERB_LOOK, NOUN_PARCHMENT))
- _vm->_dialogs->showItem(OBJ_PARCHMENT, 812, 3);
- else if (action.isAction(VERB_LOOK, NOUN_LETTER))
- _vm->_dialogs->showItem(OBJ_LETTER, 813, 4);
- else if (action.isAction(VERB_LOOK, NOUN_NOTICE))
- _vm->_dialogs->showItem(OBJ_NOTICE, 814, 5);
- else if (action.isAction(VERB_LOOK, NOUN_CRUMPLED_NOTE))
- _vm->_dialogs->showItem(OBJ_CRUMPLED_NOTE, 816, 6);
- else if (action.isAction(VERB_LOOK, NOUN_LARGE_NOTE))
- _vm->_dialogs->showItem(OBJ_LARGE_NOTE, 818, 7);
- else
- _vm->_dialogs->showItem(id, 800 + id, 0);
-}
-
-void GamePhantom::doObjectAction() {
- MADSAction &action = _scene._action;
-
- if ((_scene._currentSceneId >= 401) && (_scene._currentSceneId <= 456)
- && (action.isObject(NOUN_RED_FRAME) || action.isObject(NOUN_YELLOW_FRAME) || action.isObject(NOUN_GREEN_FRAME) || action.isObject(NOUN_BLUE_FRAME))
- && action.isAction(VERB_PUT)) {
- if (action.isTarget(NOUN_UNLUCKY_ADVENTURER)) {
- _vm->_dialogs->show(35);
- action._inProgress = false;
- return;
- } else if (action.isTarget(NOUN_HOLE)) {
- _vm->_dialogs->show(36);
- action._inProgress = false;
- return;
- } else if (action.isTarget(NOUN_GRATE)) {
- _vm->_dialogs->show(37);
- action._inProgress = false;
- return;
- } else if (action.isTarget(NOUN_WALL)) {
- _vm->_dialogs->show(38);
- action._inProgress = false;
- return;
- }
- }
-
- if (action._lookFlag) {
- _vm->_dialogs->show(810);
- action._inProgress = false;
- return;
- }
-
- if (action.isAction(VERB_PUT, NOUN_RED_FRAME) || action.isAction(VERB_PUT, NOUN_BLUE_FRAME) || action.isAction(VERB_PUT, NOUN_YELLOW_FRAME) || action.isAction(VERB_PUT, NOUN_GREEN_FRAME)) {
- _vm->_dialogs->show((action.isTarget(NOUN_PUDDLE)) ? 40124 : 40125);
- action._inProgress = false;
- return;
- }
-
- if (action.isAction(VERB_WEAR, NOUN_WEDDING_RING)) {
- if (_globals[kRingIsOnFinger])
- _vm->_dialogs->show(849);
- else {
- _vm->_dialogs->show(835);
- _globals[kRingIsOnFinger] = true;
- }
- action._inProgress = false;
- return;
- }
-
- if (action.isAction(VERB_REMOVE, NOUN_WEDDING_RING)) {
- if (!_globals[kRingIsOnFinger])
- _vm->_dialogs->show(848);
- else {
- _vm->_dialogs->show(836);
- _globals[kRingIsOnFinger] = false;
- }
- action._inProgress = false;
- return;
- }
-
- if (action.isAction(VERB_LOOK, NOUN_ARCHWAY_TO_WEST) || action.isAction(VERB_LOOK, NOUN_ARCHWAY_TO_EAST) || action.isAction(VERB_LOOK, NOUN_ARCHWAY_TO_NORTH)) {
- _vm->_dialogs->show(34);
- action._inProgress = false;
- return;
- }
-
- if (action.isAction(VERB_ATTACK, NOUN_CHRISTINE)) {
- _vm->_dialogs->show(33);
- action._inProgress = false;
- return;
- }
-
- if (action.isAction(VERB_LOOK, NOUN_KEY)) {
- _vm->_dialogs->showItem(OBJ_KEY, 800, 0);
- action._inProgress = false;
- return;
- }
-
- if (action.isAction(VERB_LOOK, NOUN_SANDBAG)) {
- _vm->_dialogs->showItem(OBJ_SANDBAG, 803, 0);
- action._inProgress = false;
- return;
- }
-
- if (action.isAction(VERB_LOOK, NOUN_SMALL_NOTE) || action.isAction(VERB_READ, NOUN_SMALL_NOTE)) {
- _vm->_dialogs->showItem(OBJ_SMALL_NOTE, 806, 2);
- action._inProgress = false;
- return;
- }
-
- if (action.isAction(VERB_LOOK, NOUN_ROPE)) {
- _vm->_dialogs->showItem(OBJ_ROPE, 807, 0);
- action._inProgress = false;
- return;
- }
-
- if (action.isAction(VERB_LOOK, NOUN_SWORD)) {
- _vm->_dialogs->showItem(OBJ_SWORD, 808, 0);
- action._inProgress = false;
- return;
- }
-
- if (action.isAction(VERB_LOOK, NOUN_ENVELOPE) || action.isAction(VERB_READ, NOUN_ENVELOPE)) {
- _vm->_dialogs->showItem(OBJ_ENVELOPE, 809, 0);
- action._inProgress = false;
- return;
- }
-
- if (action.isAction(VERB_LOOK, NOUN_TICKET) || action.isAction(VERB_READ, NOUN_TICKET)) {
- _vm->_dialogs->showItem(OBJ_TICKET, 810, 0);
- action._inProgress = false;
- return;
- }
-
- if (action.isAction(VERB_LOOK, NOUN_PIECE_OF_PAPER) || action.isAction(VERB_READ, NOUN_PIECE_OF_PAPER)) {
- _vm->_dialogs->showItem(OBJ_PIECE_OF_PAPER, 811, 1);
- action._inProgress = false;
- return;
- }
-
- if (action.isAction(VERB_LOOK, NOUN_PARCHMENT) || action.isAction(VERB_READ, NOUN_PARCHMENT)) {
- _vm->_dialogs->showItem(OBJ_PARCHMENT, 812, 3);
- action._inProgress = false;
- return;
- }
-
- if (action.isAction(VERB_LOOK, NOUN_LETTER) || action.isAction(VERB_READ, NOUN_LETTER)) {
- _vm->_dialogs->showItem(OBJ_LETTER, 813, 4);
- action._inProgress = false;
- return;
- }
-
- if (action.isAction(VERB_LOOK, NOUN_NOTICE) || action.isAction(VERB_READ, NOUN_NOTICE)) {
- _vm->_dialogs->showItem(OBJ_NOTICE, 814, 5);
- action._inProgress = false;
- return;
- }
-
- if (action.isAction(VERB_LOOK, NOUN_BOOK) || action.isAction(VERB_READ, NOUN_BOOK)) {
- _vm->_dialogs->showItem(OBJ_BOOK, 815, 0);
- action._inProgress = false;
- return;
- }
-
- if (action.isAction(VERB_LOOK, NOUN_CRUMPLED_NOTE) || action.isAction(VERB_READ, NOUN_CRUMPLED_NOTE)) {
- _vm->_dialogs->showItem(OBJ_CRUMPLED_NOTE, 816, 6);
- action._inProgress = false;
- return;
- }
-
- if (action.isAction(VERB_LOOK, NOUN_LARGE_NOTE) || action.isAction(VERB_READ, NOUN_LARGE_NOTE)) {
- _vm->_dialogs->showItem(OBJ_LARGE_NOTE, 818, 7);
- action._inProgress = false;
- return;
- }
-
- if (action.isAction(VERB_LOOK, NOUN_MUSIC_SCORE) || action.isAction(VERB_READ, NOUN_MUSIC_SCORE)) {
- _vm->_dialogs->showItem(OBJ_MUSIC_SCORE, 820, 0);
- action._inProgress = false;
- return;
- }
-
- if (action.isAction(VERB_LOOK, NOUN_WEDDING_RING)) {
- _vm->_dialogs->showItem(OBJ_WEDDING_RING, 821, 0);
- action._inProgress = false;
- return;
- }
-
- if (action.isAction(VERB_LOOK, NOUN_CABLE_HOOK)) {
- _vm->_dialogs->showItem(OBJ_CABLE_HOOK, 822, 0);
- action._inProgress = false;
- return;
- }
-
- if (action.isAction(VERB_LOOK, NOUN_ROPE_WITH_HOOK)) {
- _vm->_dialogs->showItem(OBJ_ROPE_WITH_HOOK, 823, 0);
- action._inProgress = false;
- return;
- }
-
- if (action.isAction(VERB_LOOK, NOUN_OAR)) {
- _vm->_dialogs->showItem(OBJ_OAR, 824, 0);
- action._inProgress = false;
- return;
- }
-
- if (action.isAction(VERB_LOOK) && _objects.isInInventory(_objects.getIdFromDesc(action._activeAction._objectNameId))) {
- genericObjectExamine();
- action._inProgress = false;
- return;
- }
-
- if (action.isAction(VERB_TURN_ON, NOUN_LANTERN)) {
- if ((_globals[kLanternStatus] == 1) && !_trigger)
- _vm->_dialogs->show(828);
- else {
- switch (_trigger) {
- case 0:
- _scene._sequences.addTimer(4, 1);
- _globals[kLanternStatus] = 1;
- _vm->_dialogs->spinObject(OBJ_LANTERN);
- break;
-
- case 1:
- _vm->_dialogs->show(825);
- break;
-
- default:
- break;
- }
- }
- action._inProgress = false;
- return;
- }
-
- if (action.isAction(VERB_TURN_OFF, NOUN_LANTERN)) {
- if ((_globals[kLanternStatus] == 0) && !_trigger)
- _vm->_dialogs->show(829);
- else if ((_scene._currentSceneId / 100) == 4)
- _vm->_dialogs->show(826);
- else {
- switch (_trigger) {
- case 0:
- _scene._sequences.addTimer(4, 1);
- _globals[kLanternStatus] = 0;
- _vm->_dialogs->spinObject(OBJ_LANTERN);
- break;
-
- case 1:
- _vm->_dialogs->show(827);
- break;
-
- default:
- break;
- }
- }
- action._inProgress = false;
- return;
- }
-
- if (action.isAction(VERB_OPEN, NOUN_ENVELOPE)) {
- _objects.setRoom(OBJ_ENVELOPE, NOWHERE);
- _objects.addToInventory(OBJ_TICKET);
- _objects.addToInventory(OBJ_PIECE_OF_PAPER);
- _vm->_dialogs->show(833);
- action._inProgress = false;
- return;
- }
-
- if (action.isAction(VERB_ATTACH, NOUN_CABLE_HOOK, NOUN_ROPE)) {
- if (!_objects.isInInventory(OBJ_ROPE))
- _vm->_dialogs->show(11438);
- else {
- _objects.setRoom(OBJ_CABLE_HOOK, NOWHERE);
- _objects.setRoom(OBJ_ROPE, NOWHERE);
- _objects.addToInventory(OBJ_ROPE_WITH_HOOK);
- _vm->_dialogs->showItem(OBJ_ROPE_WITH_HOOK, 823, 0);
- }
- action._inProgress = false;
- }
-}
-
-void GamePhantom::unhandledAction() {
- int messageId = 0;
- int rndNum = _vm->getRandomNumber(1, 1000);
- MADSAction &action = _scene._action;
-
- if (action.isAction(VERB_PUT, NOUN_CHANDELIER, NOUN_SEATS))
- _vm->_dialogs->show(10123);
- else if (action.isAction(VERB_TAKE)) {
- if (_objects.isInInventory(_objects.getIdFromDesc(action._activeAction._objectNameId)))
- messageId = 25;
- else {
- if (rndNum <= 333)
- messageId = 1;
- else if (rndNum <= 666)
- messageId = 2;
- else
- messageId = 3;
- }
- } else if (action.isAction(VERB_PUSH)) {
- if (rndNum < 750)
- messageId = 4;
- else
- messageId = 5;
- } else if (action.isAction(VERB_PULL)) {
- if (rndNum < 750)
- messageId = 6;
- else
- messageId = 7;
- } else if (action.isAction(VERB_OPEN)) {
- if (rndNum <= 500)
- messageId = 8;
- else if (rndNum <= 750)
- messageId = 9;
- else
- messageId = 10;
- } else if (action.isAction(VERB_CLOSE)) {
- if (rndNum <= 500)
- messageId = 11;
- else if (rndNum <= 750)
- messageId = 12;
- else
- messageId = 13;
- } else if (action.isAction(VERB_PUT)) {
- if (_objects.isInInventory(_objects.getIdFromDesc(action._activeAction._objectNameId)))
- messageId = 26;
- else if (rndNum < 500)
- messageId = 14;
- else
- messageId = 15;
- } else if (action.isAction(VERB_TALK_TO)) {
- if (rndNum <= 500)
- messageId = 16;
- else
- messageId = 17;
- } else if (action.isAction(VERB_GIVE)) {
- if (_objects.isInInventory(_objects.getIdFromDesc(action._activeAction._objectNameId)))
- messageId = 27;
- else
- messageId = 18;
- } else if (action.isAction(VERB_THROW)) {
- if (_objects.isInInventory(_objects.getIdFromDesc(action._activeAction._objectNameId)))
- messageId = 19;
- else
- messageId = 28;
- } else if (action.isAction(VERB_LOOK)) {
- if (rndNum <= 333)
- messageId = 20;
- else if (rndNum <= 666)
- messageId = 21;
- else
- messageId = 22;
- } else if ((action.isAction(VERB_UNLOCK) || action.isAction(VERB_LOCK))
- && (action.isObject(NOUN_DOOR) || action.isObject(NOUN_LEFT_DOOR) || action.isObject(NOUN_MIDDLE_DOOR) || action.isObject(NOUN_RIGHT_DOOR) || action.isObject(NOUN_TRAP_DOOR)))
- messageId = 32;
- else if (!action.isAction(VERB_WALK_TO) && !action.isAction(VERB_WALK_ACROSS) && !action.isAction(VERB_WALK_DOWN) && !action.isAction(VERB_WALK_UP)) {
- if (rndNum < 500)
- messageId = 23;
- else
- messageId = 24;
- }
-
- if (messageId)
- _vm->_dialogs->show(messageId);
-}
-
-void GamePhantom::stopWalker() {
- int state = _globals[kWalkerConverseState];
- int command = _globals[kWalkerConverse];
-
- _globals[kWalkerConverseNow] = state;
-
- if ((_player._facing != FACING_NORTHEAST) && (_player._facing != FACING_NORTHWEST)) {
- state = 0;
- command = 0;
- }
-
- switch (state) {
- case 1:
- switch (command) {
- case 1:
- _player.addWalker(3, 0);
- break;
-
- case 2:
- case 3:
- _player.addWalker(6, 0);
- _player.addWalker(5, 0);
- _player.addWalker(4, 0);
- state = 2;
- break;
-
- case 4:
- _player.addWalker(8, 0);
- _player.addWalker(4, 0);
- state = 4;
- break;
-
- default:
- _player.addWalker(-2, 0);
- state = 0;
- break;
- }
- break;
-
- case 2:
- case 3:
- switch (command) {
- case 2:
- case 3:
- if (state == 2) {
- if (_vm->getRandomNumber(1, 30000) < 2000) {
- _player.addWalker(10, 0);
- _player.addWalker(7, 0);
- state = 3;
- } else
- _player.addWalker(6, 0);
- } else {
- if (_vm->getRandomNumber(1, 30000) < 1000) {
- _player.addWalker(6, 0);
- _player.addWalker(7, 0);
- state = 2;
- } else
- _player.addWalker(10, 0);
- }
- break;
-
- default:
- _player.addWalker(-4, 0);
- _player.addWalker(-5, 0);
- if (state == 3) {
- _player.addWalker(6, 0);
- _player.addWalker(7, 0);
- }
- state = 1;
- break;
- }
- break;
-
- case 4:
- if (command == 4)
- _player.addWalker(9, 0);
- else {
- _player.addWalker(-4, 0);
- _player.addWalker(-8, 0);
- state = 1;
- }
- break;
-
- case 0:
- default:
- switch (command) {
- case 1:
- case 2:
- case 3:
- case 4:
- _player.addWalker(2, 0);
- state = 1;
- break;
-
- default:
- stopWalkerBasic();
- break;
- }
- break;
- }
-
- _globals[kWalkerConverse] = command;
- _globals[kWalkerConverseState] = state;
-}
-
-void GamePhantom::step() {
- if (_player._visible && !_globals[kStopWalkerDisabled]
- && (_player._stepEnabled || (_vm->_gameConv->activeConvId() >= 0))
- && !_player._moving && (_player._facing == _player._turnToFacing)
- && (_scene._frameStartTime >= (uint32)_globals[kWalkerTiming])) {
- if (_player._stopWalkers.empty())
- stopWalker();
-
- _globals[kWalkerTiming] += 6;
- }
-}
-
-void GamePhantom::stopWalkerBasic() {
- int rndVal = _vm->getRandomNumber(1, 30000);
-
- switch (_player._facing) {
- case FACING_SOUTH:
- if (rndVal < 500) {
- int maxSteps = _vm->getRandomNumber(4, 10);
- for (int i = 0; i < maxSteps; i++)
- _player.addWalker((rndVal < 250) ? 1 : 2, 0);
- } else if (rndVal < 750) {
- for (int i = 0; i < 4; i++)
- _player.addWalker(1, 0);
-
- _player.addWalker(0, 0);
-
- for (int i = 0; i < 4; i++)
- _player.addWalker(2, 0);
-
- _player.addWalker(0, 0);
- }
- break;
-
- case FACING_SOUTHEAST:
- case FACING_SOUTHWEST:
- case FACING_NORTHEAST:
- case FACING_NORTHWEST:
- if (rndVal < 150) {
- _player.addWalker(-1, 0);
- _player.addWalker(1, 0);
- for (int i = 0; i < 6; i++)
- _player.addWalker(0, 0);
- }
- break;
-
- case FACING_EAST:
- case FACING_WEST:
- if (rndVal < 250) {
- _player.addWalker(-1, 0);
- int maxSteps = _vm->getRandomNumber(2, 6);
- for (int i = 0; i < maxSteps; i++)
- _player.addWalker(2, 0);
- _player.addWalker(1, 0);
- _player.addWalker(0, 0);
- _player.addWalker(0, 0);
- } else if (rndVal < 500)
- _globals[kWalkerTiming] = (int)_scene._frameStartTime;
- break;
-
- case FACING_NORTH:
- if (rndVal < 250) {
- _player.addWalker(-1, 0);
- int maxSteps = _vm->getRandomNumber(3, 7);
- for (int i = 0; i < maxSteps; i++)
- _player.addWalker(2, 0);
- _player.addWalker(1, 0);
- _player.addWalker(0, 0);
- }
- break;
-
- default:
- break;
- }
-}
-
-void GamePhantom::synchronize(Common::Serializer &s, bool phase1) {
- Game::synchronize(s, phase1);
-
- // TODO: Copied from Nebular
- if (!phase1) {
- _globals.synchronize(s);
- }
-}
-
-void GamePhantom::enterCatacombs(bool val) {
- setupCatacombs();
-
- int var4, var2;
- if (_scene._currentSceneId == 409) {
- if (val) {
- var4 = _globals[kCatacombs409b];
- var2 = _globals[kCatacombs409bFrom];
- } else {
- var4 = _globals[kCatacombs409a];
- var2 = _globals[kCatacombs409aFrom];
- }
- } else if (_scene._currentSceneId == 501) {
- var4 = _globals[kCatacombs501];
- var2 = _globals[kCatacombs501From];
- } else {
- var4 = _globals[kCatacombs309];
- var2 = _globals[kCatacombs309From];
- }
-
- newCatacombRoom(var4, var2);
-}
-
-void GamePhantom::initCatacombs() {
- _globals[kCatacombsRoom] = _globals[kCatacombsNextRoom];
-}
-
-void GamePhantom::setupCatacombs() {
- switch (_difficulty) {
- case DIFFICULTY_EASY:
- _catacombs = EASY_CATACOMBS;
- _catacombSize = 32;
-
- _globals[kCatacombs309] = 2;
- _globals[kCatacombs309From] = 3;
- _globals[kCatacombs409a] = 30;
- _globals[kCatacombs409aFrom] = 0;
- _globals[kCatacombs409b] = 31;
- _globals[kCatacombs409bFrom] = 2;
- _globals[kCatacombs501] = 31;
- _globals[kCatacombs501From] = 0;
- break;
-
- case DIFFICULTY_HARD:
- default:
- _catacombs = HARD_CATACOMBS;
- _catacombSize = 62;
-
- _globals[kCatacombs309] = 2;
- _globals[kCatacombs309From] = 3;
- _globals[kCatacombs409a] = 37;
- _globals[kCatacombs409aFrom] = 0;
- _globals[kCatacombs409b] = 39;
- _globals[kCatacombs409bFrom] = 2;
- _globals[kCatacombs501] = 56;
- _globals[kCatacombs501From] = 1;
- break;
- }
-}
-
-int GamePhantom::exitCatacombs(int dir) {
- assert(_globals[kCatacombsRoom] == CLIP(_globals[kCatacombsRoom], 0, _catacombSize - 1));
- assert(dir == CLIP(dir, 0, 3));
-
- return (_catacombs[_globals[kCatacombsRoom]]._exit[dir]);
-}
-
-void GamePhantom::moveCatacombs(int dir) {
- assert(_globals[kCatacombsRoom] == CLIP(_globals[kCatacombsRoom], 0, _catacombSize - 1));
- assert(dir == CLIP(dir, 0, 3));
-
- newCatacombRoom(_catacombs[_globals[kCatacombsRoom]]._fromDirection[dir], _catacombs[_globals[kCatacombsRoom]]._exit[dir]);
-}
-
-void GamePhantom::newCatacombRoom(int toRoom, int fromExit) {
- _globals[kCatacombsNextRoom] = toRoom;
- _globals[kCatacombsFrom] = fromExit & 0x03;
- _globals[kCatacombsFlag] = fromExit & 0xFC;
-
- int newSceneNum = -1;
-
- if (toRoom < 0) {
- switch (toRoom) {
- case -5:
- newSceneNum = 501;
- break;
-
- case -4:
- case -3:
- newSceneNum = 409;
- break;
-
- case -2:
- newSceneNum = 309;
- break;
-
- default:
- error("Unexpected room in newCatacombRoom");
- }
- } else {
- newSceneNum = _catacombs[toRoom]._sceneNum;
- _globals[81] = _catacombs[toRoom]._flags;
- }
-
- if (_triggerSetupMode == SEQUENCE_TRIGGER_PREPARE) {
- _player._walkOffScreenSceneId = newSceneNum;
- } else {
- _scene._reloadSceneFlag = true;
- _scene._nextSceneId = newSceneNum;
- }
-}
-
-} // End of namespace Phantom
-} // End of namespace MADS
diff --git a/engines/mads/phantom/game_phantom.h b/engines/mads/phantom/game_phantom.h
deleted file mode 100644
index c4076474c40..00000000000
--- a/engines/mads/phantom/game_phantom.h
+++ /dev/null
@@ -1,150 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#ifndef MADS_GAME_PHANTOM_H
-#define MADS_GAME_PHANTOM_H
-
-#include "mads/game.h"
-#include "mads/globals.h"
-#include "mads/phantom/globals_phantom.h"
-
-namespace MADS {
-namespace Phantom {
-
-enum Difficulty {
- DIFFICULTY_HARD = 1, DIFFICULTY_MEDIUM = 2, DIFFICULTY_EASY = 3
-};
-
-enum InventoryObject {
- OBJ_NONE = -1,
- OBJ_KEY = 0,
- OBJ_LANTERN = 1,
- OBJ_RED_FRAME = 2,
- OBJ_SANDBAG = 3,
- OBJ_YELLOW_FRAME = 4,
- OBJ_FIRE_AXE = 5,
- OBJ_SMALL_NOTE = 6,
- OBJ_ROPE = 7,
- OBJ_SWORD = 8,
- OBJ_ENVELOPE = 9,
- OBJ_TICKET = 10,
- OBJ_PIECE_OF_PAPER = 11,
- OBJ_PARCHMENT = 12,
- OBJ_LETTER = 13,
- OBJ_NOTICE = 14,
- OBJ_BOOK = 15,
- OBJ_CRUMPLED_NOTE = 16,
- OBJ_BLUE_FRAME = 17,
- OBJ_LARGE_NOTE = 18,
- OBJ_GREEN_FRAME = 19,
- OBJ_MUSIC_SCORE = 20,
- OBJ_WEDDING_RING = 21,
- OBJ_CABLE_HOOK = 22,
- OBJ_ROPE_WITH_HOOK = 23,
- OBJ_OAR = 24
-};
-
-enum MazeEvent {
- MAZE_EVENT_NONE = 0,
- MAZE_EVENT_PUDDLE = 0x0001,
- MAZE_EVENT_RAT_NEST = 0x0002,
- MAZE_EVENT_SKULL = 0x0004,
- MAZE_EVENT_POT = 0x0008,
- MAZE_EVENT_BRICK = 0x0010,
- MAZE_EVENT_HOLE = 0x0020,
- MAZE_EVENT_WEB = 0x0040,
- MAZE_EVENT_PLANK = 0x0080,
- MAZE_EVENT_DRAIN = 0x0100,
- MAZE_EVENT_STONE = 0x0200,
- MAZE_EVENT_BLOCK = 0x0400,
- MAZE_EVENT_FALLEN_BLOCK = 0x0800
-};
-
-struct Catacombs {
- uint16 _sceneNum;
- int8 _exit[4];
- int8 _fromDirection[4];
- uint16 _flags;
-};
-
-class GamePhantom : public Game {
- friend class Game;
-
-private:
- void genericObjectExamine();
- void stopWalker();
- void stopWalkerBasic();
-
- const Catacombs *_catacombs;
- int _catacombSize;
-
-protected:
- GamePhantom(MADSEngine *vm);
-
- void startGame() override;
-
- void initializeGlobals() override;
-
- void setSectionHandler() override;
-
- void checkShowDialog() override;
-public:
- PhantomGlobals _globals;
- Difficulty _difficulty;
-
-
- Globals &globals() override { return _globals; }
-
- void doObjectAction() override;
-
- void unhandledAction() override;
-
- void step() override;
-
- void synchronize(Common::Serializer &s, bool phase1) override;
-
- void setupCatacombs();
- void enterCatacombs(bool val);
- void initCatacombs();
- void moveCatacombs(int dir);
- int exitCatacombs(int dir);
- void newCatacombRoom(int fromRoom, int fromExit);
-};
-
-// Section handlers aren't needed in ScummVM implementation
-class Section1Handler : public SectionHandler {
-public:
- Section1Handler(MADSEngine *vm) : SectionHandler(vm) {}
-
- void preLoadSection() override {}
- void sectionPtr2() override {}
- void postLoadSection() override {}
-};
-
-typedef Section1Handler Section2Handler;
-typedef Section1Handler Section3Handler;
-typedef Section1Handler Section4Handler;
-typedef Section1Handler Section5Handler;
-
-} // End of namespace Phantom
-} // End of namespace MADS
-
-#endif
diff --git a/engines/mads/phantom/globals_phantom.h b/engines/mads/phantom/globals_phantom.h
deleted file mode 100644
index 5a40f546465..00000000000
--- a/engines/mads/phantom/globals_phantom.h
+++ /dev/null
@@ -1,150 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#ifndef MADS_GLOBALS_PHANTOM_H
-#define MADS_GLOBALS_PHANTOM_H
-
-#include "mads/game.h"
-#include "mads/resources.h"
-
-namespace MADS {
-namespace Phantom {
-
-enum GlobalId {
- // Global variables
-
- kWalkerTiming = 0,
- kWalkerTiming2 = 1,
- kStopWalkerDisabled = 2, // disable walker idle animations
- kTempInterface = 3,
- kWalkerConverse = 4, // conversation started with an NPC
- kWalkerConverseState = 5,
- kWalkerConverseNow = 6,
-
- kCurrentYear = 10, // current year (1881 or 1993)
- kMusicSelected = 11,
- kPlayerScore = 12,
- kPlayerScoreFlags = 13,
- kDoneBrieConv203 = 14,
- kLanternStatus = 15,
-
- // Section #1 variables
- kLeaveAngelMusicOn = 19,
- kTrapDoorStatus = 20,
- kChristineDoorStatus = 21,
- kSandbagStatus = 22,
- kChrisFStatus = 23,
- kBrieTalkStatus = 24,
- kJuliesDoor = 25,
- kPrompterStandStatus = 26,
- kChrisDStatus = 27,
- kJulieNameIsKnown = 28,
- kChrisKickedRaoulOut = 29,
- kJacquesNameIsKnown = 30,
- kJacquesStatus = 31,
- kFlorentNameIsKnown = 32,
- kCharlesNameIsKnown = 33,
- kRoom103104Transition = 34,
- kObservedPhan104 = 35,
- kDeathLocation = 36,
- kMakeBrieLeave203 = 37,
- kHintThatDaaeIsHome1 = 38,
- kHintThatDaaeIsHome2 = 39,
-
- // Section #2 variables
- kChristineToldEnvelope = 40,
- kReadBook = 41,
- kScannedBookcase = 42,
- kRanConvIn205 = 43,
- kDoorsIn205 = 44,
- kPanelIn206 = 45,
- kMadameNameIsKnown = 46,
- kMadameGiryLocation = 47,
- kLookedAtCase = 48,
- kMadameGiryShowsUp = 49,
- kDoneRichConv203 = 50,
- kCameFromFade = 51,
- kTicketPeoplePresent = 52,
- kDegasNameIsKnown = 53,
- kTempVar = 54,
- kFlickedLever1 = 55,
- kFlickedLever2 = 56,
- kFlickedLever3 = 57,
- kFlickedLever4 = 58,
-
- // Section #3 Variables
- kTopFloorLocked = 60,
-
- // Section #4 Variables
- kCatacombsRoom = 80,
- kCatacombsMisc = 81,
- kCatacombsFlag = 82,
- kCatacombsFrom = 83,
- kCatacombs309 = 84,
- kCatacombs409a = 85,
- kCatacombs409b = 86,
- kCatacombs501 = 87,
- kCatacombs309From = 88,
- kCatacombs409aFrom = 89,
- kCatacombs409bFrom = 90,
- kCatacombs501From = 91,
- kCatacombsNextRoom = 92,
- kDoorIn409IsOpen = 93,
- kPriestPistonPuke = 94,
- kCobwebIsCut = 95,
-
- // Section #5 Variables
- kChristineIsInBoat = 100,
- kChrisWillTakeSeat = 101,
- kRightDoorIsOpen504 = 102,
- kCoffinStatus = 103,
- kChrisLeft505 = 104,
- kKnockedOverHead = 105,
- kFightStatus = 106,
- kHeListened = 107,
- kCanFindBookInLibrary = 108,
- kRingIsOnFinger = 109,
- kLookedAtSkullFace = 110,
- kCableHookWasSeparate = 111,
- kMakeRichLeave203 = 112
-};
-
-class PhantomGlobals : public Globals {
-public:
- SynchronizedList _spriteIndexes;
- SynchronizedList _sequenceIndexes;
- SynchronizedList _animationIndexes;
-public:
- /**
- * Constructor
- */
- PhantomGlobals();
-
- /**
- * Synchronize the globals data
- */
- virtual void synchronize(Common::Serializer &s);
-};
-
-} // End of namespace Phantom
-} // End of namespace MADS
-
-#endif
diff --git a/engines/mads/phantom/menu_phantom.cpp b/engines/mads/phantom/menu_phantom.cpp
deleted file mode 100644
index 413b64f58e5..00000000000
--- a/engines/mads/phantom/menu_phantom.cpp
+++ /dev/null
@@ -1,364 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include "common/scummsys.h"
-#include "common/config-manager.h"
-#include "mads/game.h"
-#include "mads/mads.h"
-#include "mads/menu_views.h"
-#include "mads/resources.h"
-#include "mads/scene.h"
-#include "mads/screen.h"
-#include "mads/phantom/menu_phantom.h"
-
-namespace MADS {
-namespace Phantom {
-
-#define MADS_MENU_Y ((MADS_SCREEN_HEIGHT - MADS_SCENE_HEIGHT) / 2)
-#define MADS_MENU_ANIM_DELAY 70
-
-MainMenu::MainMenu(MADSEngine *vm): MenuView(vm) {
-}
-
-MainMenu::~MainMenu() {
- Scene &scene = _vm->_game->_scene;
- for (int i = 0; i < 7; ++i) {
- if (_menuItems[i]._handle != -1)
- scene._sprites.remove(_menuItems[i]._handle);
- }
-
- scene._spriteSlots.reset();
-}
-
-void MainMenu::display() {
- MenuView::display();
- Scene &scene = _vm->_game->_scene;
- ScreenObjects &screenObjects = _vm->_game->_screenObjects;
- screenObjects.clear();
-
- // Load each of the menu item assets and add to the scene sprites list
- for (int i = 0; i < 7; ++i) {
- Common::Path spritesName(Common::String::format("*MAIN%d.SS", i));
- _menuItems[i]._sprites = new SpriteAsset(_vm, spritesName, 0);
- _menuItems[i]._handle = scene._sprites.add(_menuItems[i]._sprites);
-
- // Register the menu item area in the screen objects
- MSprite *frame0 = _menuItems[i]._sprites->getFrame(0);
- Common::Point pt(frame0->_offset.x - (frame0->w / 2),
- frame0->_offset.y - frame0->h);
- screenObjects.add(
- Common::Rect(pt.x, pt.y + DIALOG_TOP, pt.x + frame0->w,
- pt.y + frame0->h + DIALOG_TOP), SCREENMODE_VGA, CAT_COMMAND, i);
- }
-
- // Set the cursor for when it's shown
- _vm->_events->setCursor(CURSOR_ARROW);
-}
-
-void MainMenu::doFrame() {
- // Delay between animation frames on the menu
- uint32 currTime = g_system->getMillis();
- if (currTime < _delayTimeout)
- return;
- _delayTimeout = currTime + MADS_MENU_ANIM_DELAY;
-
- // If an item has already been selected, handle rotating out the other menu items
- if (_selectedIndex != -1) {
- if (_frameIndex == _menuItems[0]._sprites->getCount()) {
- handleAction((MADSGameAction)_selectedIndex);
- } else {
- for (_menuItemIndex = 0; _menuItemIndex < 6; ++_menuItemIndex) {
- if (_menuItemIndex != _selectedIndex) {
- addSpriteSlot();
- }
- }
-
- // Move the menu items to the next frame
- ++_frameIndex;
- }
- return;
- }
-
- // If we've alerady reached the end of the menuitem animation, exit immediately
- if (_menuItemIndex == 6)
- return;
-
- // If the user has chosen to skip the animation, show the full menu immediately
- if (_skipFlag && _menuItemIndex >= 0) {
- // Quickly loop through all the menu items to display each's final frame
- for (; _menuItemIndex < 6; ++_menuItemIndex) {
- // Draw the final frame of the menuitem
- _frameIndex = 0;
- addSpriteSlot();
- }
-
- _vm->_events->showCursor();
-
- } else {
- if ((_menuItemIndex == -1) || (_frameIndex == 0)) {
- if (++_menuItemIndex == 6) {
-
- // Reached end of display animation
- _vm->_events->showCursor();
- return;
- }
-
- _frameIndex = _menuItems[_menuItemIndex]._sprites->getCount() - 1;
- } else {
- --_frameIndex;
- }
-
- // Move to the next menuitem frame
- addSpriteSlot();
- }
-}
-
-void MainMenu::addSpriteSlot() {
- Scene &scene = _vm->_game->_scene;
- SpriteSlots &spriteSlots = scene._spriteSlots;
-
- int seqIndex = (_menuItemIndex < 6) ? _menuItemIndex : _frameIndex;
- spriteSlots.deleteTimer(seqIndex);
-
- SpriteAsset *menuItem = _menuItems[_menuItemIndex]._sprites;
- MSprite *spr = menuItem->getFrame(_frameIndex);
-
- SpriteSlot &slot = spriteSlots[spriteSlots.add()];
- slot._flags = IMG_UPDATE;
- slot._seqIndex = seqIndex;
- slot._spritesIndex = _menuItems[_menuItemIndex]._handle;
- slot._frameNumber = _frameIndex + 1;
- slot._position = spr->_offset;
- slot._depth = 1;
- slot._scale = 100;
-
- _redrawFlag = true;
-}
-
-bool MainMenu::onEvent(Common::Event &event) {
- Scene &scene = _vm->_game->_scene;
- if (_selectedIndex != -1)
- return false;
-
- // Handle keypresses - these can be done at any time, even when the menu items are being drawn
- if (event.type == Common::EVENT_CUSTOM_ENGINE_ACTION_START) {
- switch (event.customType) {
- case kActionEscape:
- handleAction(EXIT);
- break;
-
- case kActionStartGame:
- handleAction(START_GAME);
- break;
-
- case kActionResumeGame:
- handleAction(RESUME_GAME);
- break;
-
- case kActionShowIntro:
- handleAction(SHOW_INTRO);
- break;
-
- case kActionCredits:
- handleAction(CREDITS);
- break;
-
- default:
- _skipFlag = true;
- return false;
- }
-
- return true;
- } else if (event.type == Common::EVENT_KEYDOWN) {
- // Any other key skips the menu animation
- _skipFlag = true;
- return false;
- }
-
- switch (event.type) {
- case Common::EVENT_LBUTTONDOWN:
- if (_vm->_events->isCursorVisible()) {
- _buttonDown = true;
- int menuIndex = getHighlightedItem(event.mouse);
-
- if (menuIndex != _highlightedIndex) {
- scene._spriteSlots.deleteTimer(menuIndex);
-
- _highlightedIndex = menuIndex;
- if (_highlightedIndex != -1) {
- _frameIndex = _highlightedIndex;
- addSpriteSlot();
- }
- }
- } else {
- // Skip the menu animation
- _skipFlag = true;
- }
- return true;
-
- case Common::EVENT_MOUSEMOVE:
- if (_buttonDown) {
- int menuIndex = getHighlightedItem(event.mouse);
- if (menuIndex != _highlightedIndex) {
- if (_highlightedIndex != -1) {
- // Revert to the unselected menu item
- unhighlightItem();
- }
-
- if (menuIndex != -1) {
- // Highlight new item
- _highlightedIndex = menuIndex;
- _frameIndex = _highlightedIndex;
- addSpriteSlot();
- }
- }
- }
- break;
-
- case Common::EVENT_LBUTTONUP:
- _buttonDown = false;
- if (_highlightedIndex != -1) {
- _selectedIndex = _highlightedIndex;
- unhighlightItem();
- _frameIndex = 0;
- }
-
- return true;
-
- default:
- break;
- }
-
- return false;
-}
-
-int MainMenu::getHighlightedItem(const Common::Point &pt) {
- return _vm->_game->_screenObjects.scan(pt, SCREENMODE_VGA) - 1;
-}
-
-void MainMenu::unhighlightItem() {
- // Revert to the unselected menu item
- _vm->_game->_scene._spriteSlots.deleteTimer(_highlightedIndex);
- _menuItemIndex = _highlightedIndex;
- _frameIndex = 0;
- addSpriteSlot();
-
- _menuItemIndex = 6;
- _highlightedIndex = -1;
-}
-
-void MainMenu::handleAction(MADSGameAction action) {
- _vm->_events->hideCursor();
- _breakFlag = true;
-
- switch (action) {
- case START_GAME:
- // Show the difficulty dialog
- _vm->_dialogs->_pendingDialog = DIALOG_DIFFICULTY;
- break;
-
- case RESUME_GAME:
- // The original resumed the most recently saved game. Instead,
- // just show the load game scren
- _vm->_dialogs->_pendingDialog = DIALOG_RESTORE;
- return;
-
- case SHOW_INTRO:
- AnimationView::execute(_vm, "phantom");
- break;
-
- case CREDITS:
- TextView::execute(_vm, "credits");
- return;
-
- case EXIT:
- _vm->_dialogs->_pendingDialog = DIALOG_ADVERT;
- break;
- default:
- break;
- }
-}
-
-/*------------------------------------------------------------------------*/
-
-AdvertView::AdvertView(MADSEngine *vm): EventTarget(), _vm(vm) {
- _breakFlag = false;
-}
-
-void AdvertView::show() {
- bool altAdvert = _vm->getRandomNumber(1000) >= 500;
- int screenId = altAdvert ? 995 : 996;
- uint32 expiryTime = g_system->getMillis() + 10 * 1000;
-
- _vm->_palette->resetGamePalette(4, 8);
-
- // Load the advert background onto the screen
- SceneInfo *sceneInfo = SceneInfo::init(_vm);
- sceneInfo->load(screenId, 0, Common::String(), 0, _vm->_game->_scene._depthSurface,
- *_vm->_screen);
- _vm->_screen->markAllDirty();
- _vm->_palette->setFullPalette(_vm->_palette->_mainPalette);
-
- delete sceneInfo;
-
- EventsManager &events = *_vm->_events;
- events.setEventTarget(this);
- events.hideCursor();
-
- while (!_breakFlag && !_vm->shouldQuit()) {
- _vm->_events->waitForNextFrame();
- _vm->_game->_fx = kTransitionNone;
-
- _breakFlag |= g_system->getMillis() >= expiryTime;
- }
-
- events.setEventTarget(nullptr);
- _vm->quitGame();
- events.pollEvents();
-}
-
-bool AdvertView::onEvent(Common::Event &event) {
- if (event.type == Common::EVENT_CUSTOM_ENGINE_ACTION_START || event.type == Common::EVENT_KEYDOWN
- || event.type == Common::EVENT_JOYBUTTON_DOWN || event.type == Common::EVENT_LBUTTONDOWN) {
- _breakFlag = true;
- return true;
- }
-
- return false;
-}
-
-/*------------------------------------------------------------------------*/
-
-void PhantomAnimationView::scriptDone() {
- AnimationView::scriptDone();
-
- Common::String s = getResourceName();
- if (s == "rexend1") {
- TextView::execute(_vm, "ending1");
- } else if (s == "rexend2") {
- TextView::execute(_vm, "ending2");
- } else if (s == "rexend3") {
- TextView::execute(_vm, "credits");
- }
-}
-
-} // namespace Phantom
-} // namespace MADS
diff --git a/engines/mads/phantom/menu_phantom.h b/engines/mads/phantom/menu_phantom.h
deleted file mode 100644
index 5a5ad360db6..00000000000
--- a/engines/mads/phantom/menu_phantom.h
+++ /dev/null
@@ -1,153 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#ifndef MADS_MENU_PHANTOM_H
-#define MADS_MENU_PHANTOM_H
-
-#include "common/scummsys.h"
-#include "mads/game.h"
-#include "mads/menu_views.h"
-#include "mads/msurface.h"
-#include "mads/phantom/dialogs_phantom.h"
-
-namespace MADS {
-
-class MADSEngine;
-
-namespace Phantom {
-
-enum MADSGameAction {
- START_GAME, RESUME_GAME, RESTORE_GAME, SHOW_INTRO, EXIT, CREDITS
-};
-
-class MainMenu: public MenuView {
- struct MenuItem {
- SpriteAsset *_sprites = nullptr;
- int _handle = -1;
- bool _active = false;
- int _status = 0;
- };
-private:
- MenuItem _menuItems[7];
- int _menuItemIndex = -1;
- int _frameIndex = -1;
- uint32 _delayTimeout = 0;
- bool _skipFlag = false;
-
- /**
- * Currently highlighted menu item
- */
- int _highlightedIndex = -1;
-
- /**
- * Flag for mouse button being pressed
- */
- bool _buttonDown = false;
-
- /**
- * Stores menu item selection
- */
- int _selectedIndex = -1;
-
- /**
- * Get the highlighted menu item under the cursor
- */
- int getHighlightedItem(const Common::Point &pt);
-
- /**
- * Un-highlight a currently highlighted item
- */
- void unhighlightItem();
-
- /**
- * Execute a given menuitem
- */
- void handleAction(MADSGameAction action);
-
- /**
- * Add a sprite slot for the current menuitem frame
- */
- void addSpriteSlot();
-
-protected:
- /**
- * Display the menu
- */
- void display() override;
-
- /**
- * Handle the menu item animations
- */
- void doFrame() override;
-
- /**
- * Event handler
- */
- bool onEvent(Common::Event &event) override;
-public:
- MainMenu(MADSEngine *vm);
-
- ~MainMenu() override;
-};
-
-class AdvertView : public EventTarget {
-private:
- /**
- * Engine reference
- */
- MADSEngine *_vm;
-
- /**
- * Signals when to close the dialog
- */
- bool _breakFlag;
-protected:
- /**
- * Event handler
- */
- bool onEvent(Common::Event &event) override;
-public:
- AdvertView(MADSEngine *vm);
-
- ~AdvertView() override {}
-
- /**
- * Show the dialog
- */
- void show();
-};
-
-class PhantomAnimationView : public AnimationView {
-protected:
- void scriptDone() override;
-public:
- PhantomAnimationView(MADSEngine *vm) : AnimationView(vm) {}
-};
-
-class PhantomTextView : public TextView {
-public:
- PhantomTextView(MADSEngine *vm) : TextView(vm) {}
-};
-
-} // namespace Phantom
-} // namespace MADS
-
-#endif
diff --git a/engines/mads/phantom/phantom_scenes.cpp b/engines/mads/phantom/phantom_scenes.cpp
deleted file mode 100644
index 71cfdb0fb0b..00000000000
--- a/engines/mads/phantom/phantom_scenes.cpp
+++ /dev/null
@@ -1,209 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include "common/config-manager.h"
-#include "mads/mads.h"
-#include "mads/compression.h"
-#include "mads/resources.h"
-#include "mads/scene.h"
-#include "mads/phantom/game_phantom.h"
-#include "mads/phantom/phantom_scenes.h"
-#include "mads/phantom/phantom_scenes1.h"
-#include "mads/phantom/phantom_scenes2.h"
-#include "mads/phantom/phantom_scenes3.h"
-#include "mads/phantom/phantom_scenes4.h"
-#include "mads/phantom/phantom_scenes5.h"
-
-namespace MADS {
-namespace Phantom {
-
-SceneLogic *SceneFactory::createScene(MADSEngine *vm) {
- Scene &scene = vm->_game->_scene;
-
- // When changing from one section to the other, set the scaling velocity
- if ((scene._nextSceneId / 100) != (scene._priorSceneId / 100))
- vm->_game->_player._scalingVelocity = true;
-
- switch (scene._nextSceneId) {
- // Scene group #1 (theater, stage and dressing rooms)
- case 101: // seats
- return new Scene101(vm);
- case 102: // music stands
- return new Scene102(vm);
- case 103: // below stage
- return new Scene103(vm);
- case 104: // stage
- return new Scene104(vm);
- case 105: // ground floor, storage room
- return new Scene105(vm);
- case 106: // behind stage
- return new Scene106(vm);
- case 107: // stage right wing
- return new Scene107(vm);
- case 108: // stage left wing
- return new Scene108(vm);
- case 109: // upper floor, staircase
- return new Scene109(vm);
- case 110: // outside dressing rooms 1
- return new Scene110(vm);
- case 111: // outside dressing rooms 2
- return new Scene111(vm);
- case 112: // inside dressing room 1
- return new Scene112(vm);
- case 113: // inside dressing room 2
- return new Scene113(vm);
- case 114: // lower floor, storage room
- return new Scene114(vm);
- case 150: // cutscene
- return new Scene150(vm);
-
- // Scene group #2 (theater entrance, offices, balcony)
- case 201: // entrance / ticket office
- return new Scene201(vm);
- case 202: // outside offices / paintings room
- return new Scene202(vm);
- case 203: // office
- return new Scene203(vm);
- case 204: // library
- return new Scene204(vm);
- case 205: // upper floor, outside balcony boxes
- return new Scene205(vm);
- case 206: // balcony box #1
- return new Scene206(vm);
- case 207: // balcony box #2
- return new Scene207(vm);
- case 208: // stage and balcony view
- return new Scene208(vm);
- case 250: // cutscene
- return new Scene250(vm);
-
- // Scene group #3 (catwalks, chandelier, lake / catacombs entrance)
- case 301: // catwalk #1 above stage
- return new Scene301(vm);
- case 302: // catwalk #2 above stage
- return new Scene302(vm);
- case 303: // above chandelier
- return new Scene303(vm);
- case 304: // chandelier
- return new Scene304(vm);
- case 305: // chandelier fight, phantom closeup
- return new Scene305(vm);
- case 306: // chandelier #2
- return new Scene306(vm);
- case 307: // catwalk #3 above stage
- return new Scene307(vm);
- case 308: // hidden staircase behind balcony box
- return new Scene308(vm);
- case 309: // lake and archway
- return new Scene309(vm);
- case 310: // lake
- return new Scene310(vm);
-
- // Scene group #4 (labyrinth)
- case 401: // labyrinth room, 3 exits
- return new Scene401(vm);
- case 403: // labyrinth room (big), 4 exits + 1 bricked door, left
- return new Scene403(vm);
- case 404: // labyrinth room, 3 exits
- return new Scene404(vm);
- case 406: // labyrinth room, 2 exits
- return new Scene406(vm);
- case 407: // catacomb room / lake
- return new Scene407(vm);
- case 408: // catacomb corridor
- return new Scene408(vm);
- case 409: // catacomb room, door with switch panel
- return new Scene409(vm);
- case 410: // skull switch panel
- return new Scene410(vm);
- case 453: // Labyrinth room (big), 4 exits + 1 bricked door, right
- return new Scene453(vm);
- case 456: // Labyrinth room, 2 exits
- return new Scene456(vm);
-
- // Scene group #5 (Phantom's hideout)
- case 501: // catacombs, outside phantom's hideout, lake and boat
- return new Scene501(vm);
- case 502: // push panel trap
- return new Scene502(vm);
- case 504: // Phantom's hideout, church organ
- return new Scene504(vm);
- case 505: // Phantom's hideout, sarcophagus
- return new Scene505(vm);
- case 506: // catacomb room with ramp
- return new Scene506(vm);
-
- default:
- error("Invalid scene %d called", scene._nextSceneId);
- }
-}
-
-/*------------------------------------------------------------------------*/
-
-PhantomScene::PhantomScene(MADSEngine *vm) : SceneLogic(vm),
- _globals(static_cast<GamePhantom *>(vm->_game)->_globals),
- _game(*static_cast<GamePhantom *>(vm->_game)),
- _action(vm->_game->_scene._action) {
-}
-
-Common::Path PhantomScene::formAnimName(char sepChar, int suffixNum) {
- return Resources::formatName(_scene->_currentSceneId, sepChar, suffixNum,
- EXT_NONE, "");
-}
-
-/*------------------------------------------------------------------------*/
-
-void SceneInfoPhantom::loadCodes(BaseSurface &depthSurface, int variant) {
- Common::String ext = Common::String::format(".WW%d", variant);
- Common::Path fileName = Resources::formatName(RESPREFIX_RM, _sceneId, ext);
- if (!Common::File::exists(fileName))
- return;
-
- File f(fileName);
- MadsPack codesPack(&f);
- Common::SeekableReadStream *stream = codesPack.getItemStream(0);
-
- loadCodes(depthSurface, stream);
-
- delete stream;
- f.close();
-}
-
-void SceneInfoPhantom::loadCodes(BaseSurface &depthSurface, Common::SeekableReadStream *stream) {
- byte *destP = (byte *)depthSurface.getPixels();
- byte *walkMap = new byte[stream->size()];
- stream->read(walkMap, stream->size());
-
- for (int y = 0; y < 156; ++y) {
- for (int x = 0; x < 320; ++x) {
- int offset = x + (y * 320);
- if ((walkMap[offset / 8] << (offset % 8)) & 0x80)
- *destP++ = 1; // walkable
- else
- *destP++ = 0;
- }
- }
-
- delete[] walkMap;
-}
-
-} // End of namespace Phantom
-} // End of namespace MADS
diff --git a/engines/mads/phantom/phantom_scenes.h b/engines/mads/phantom/phantom_scenes.h
deleted file mode 100644
index 05e0f911804..00000000000
--- a/engines/mads/phantom/phantom_scenes.h
+++ /dev/null
@@ -1,485 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#ifndef MADS_PHANTOM_SCENES_H
-#define MADS_PHANTOM_SCENES_H
-
-#include "mads/scene.h"
-#include "mads/phantom/game_phantom.h"
-//#include "mads/phantom/globals_phantom.h"
-
-namespace MADS {
-namespace Phantom {
-
-enum Verb {
- VERB_LOOK = 0x3,
- VERB_TAKE = 0x4,
- VERB_PUSH = 0x5,
- VERB_OPEN = 0x6,
- VERB_PUT = 0x7,
- VERB_TALK_TO = 0x8,
- VERB_GIVE = 0x9,
- VERB_PULL = 0xA,
- VERB_CLOSE = 0xB,
- VERB_THROW = 0xC,
- VERB_WALK_TO = 0xD,
- VERB_ATTACK = 0x14,
- VERB_CLIMB_DOWN = 0x21,
- VERB_CLIMB_INTO = 0x22,
- VERB_CLIMB_THROUGH = 0x23,
- VERB_EXIT = 0x34,
- VERB_EXIT_TO = 0x37,
- VERB_JUMP_INTO = 0x53,
- VERB_LASSO = 0x59,
- VERB_LOCK = 0x5D,
- VERB_LOOK_AT = 0x60,
- VERB_LOOK_THROUGH = 0x61,
- VERB_READ = 0x7A,
- VERB_REMOVE = 0x7C,
- VERB_TURN_OFF = 0x95,
- VERB_TURN_ON = 0x96,
- VERB_UNLOCK = 0x97,
- VERB_WALK_ACROSS = 0x99,
- VERB_WALK_DOWN = 0x9A,
- VERB_WALK_THROUGH = 0x9B,
- VERB_WALK_UP = 0x9C,
- VERB_WEAR = 0xA1,
- VERB_CLIMB_UP = 0xA5,
- VERB_WALK_ONTO = 0xA6,
- VERB_WALK = 0xA7,
- VERB_ENTER = 0xEC,
- VERB_WALK_BEHIND = 0xF3,
- VERB_CLIMB = 0x120,
- VERB_ATTACH = 0x131,
- VERB_GRAPPLE = 0x133,
- VERB_SIT_ON = 0x138,
- VERB_SIT_IN = 0x13A,
- VERB_WALK_DOWN_STAIRS_TO = 0x153
-};
-
-enum Noun {
- NOUN_GAME = 0x1,
- NOUN_QSAVE = 0x2,
- NOUN_ = 0xE,
- NOUN_IN_ONE = 0xF,
- NOUN_IN_TWO = 0x10,
- NOUN_ACT_CURTAIN = 0x11,
- NOUN_AISLE = 0x12,
- NOUN_APRON = 0x13,
- NOUN_BACKSTAGE = 0x15,
- NOUN_BEAR_PROP = 0x16,
- NOUN_BLUE_FRAME = 0x17,
- NOUN_BOOK = 0x18,
- NOUN_BUST = 0x19,
- NOUN_CABLE = 0x1A,
- NOUN_CARPET = 0x1B,
- NOUN_CARTON = 0x1C,
- NOUN_CARTONS = 0x1D,
- NOUN_CEILING = 0x1E,
- NOUN_CHAIR = 0x1F,
- NOUN_CIRCULAR_STAIRCASE = 0x20,
- NOUN_COLUMN_PROP = 0x24,
- NOUN_CONDUCTORS_STAND = 0x25,
- NOUN_CORRIDOR = 0x26,
- NOUN_COUCH = 0x27,
- NOUN_COUNTERWEIGHT_SYSTEM = 0x28,
- NOUN_CRATE = 0x29,
- NOUN_CRATES = 0x2A,
- NOUN_CRUMPLED_NOTE = 0x2B,
- NOUN_CYCLORAMA = 0x2C,
- NOUN_CYLINDER = 0x2D,
- NOUN_DOOR = 0x2E,
- NOUN_DRESSING_ROOM_DOOR = 0x2F,
- NOUN_DRESSING_SCREEN = 0x30,
- NOUN_DRESSING_TABLE = 0x31,
- NOUN_ELEPHANT_PROP = 0x32,
- NOUN_ENVELOPE = 0x33,
- NOUN_EXIT_DOWN = 0x35,
- NOUN_EXIT_SIGN = 0x36,
- NOUN_EXIT_TO_BACKSTAGE = 0x38,
- NOUN_EXIT_TO_CELLAR = 0x39,
- NOUN_EXIT_TO_CORRIDOR = 0x3A,
- NOUN_EXIT_TO_DRESSING_RMS = 0x3B,
- NOUN_EXIT_TO_LEFT_WING = 0x3C,
- NOUN_EXIT_TO_PIT = 0x3D,
- NOUN_EXIT_TO_RIGHT_WING = 0x3E,
- NOUN_EXIT_TO_STAGE = 0x3F,
- NOUN_EXIT_TO_STAIRWELL = 0x40,
- NOUN_EXIT_TO_TRAP_ROOM = 0x41,
- NOUN_EXIT_UP = 0x42,
- NOUN_EXPOSED_BRICK = 0x43,
- NOUN_FAN = 0x44,
- NOUN_FIRE_AXE = 0x45,
- NOUN_FL = 0x46,
- NOUN_FLAT = 0x47,
- NOUN_FLATS = 0x48,
- NOUN_FLOOR = 0x49,
- NOUN_FOLDING_CHAIRS = 0x4A,
- NOUN_GARBAGE_CAN = 0x4B,
- NOUN_GRAFFITI = 0x4C,
- NOUN_GREEN_FRAME = 0x4D,
- NOUN_HEMP = 0x4E,
- NOUN_HOLE = 0x4F,
- NOUN_HOUSE = 0x50,
- NOUN_IN_ONE2 = 0x51,
- NOUN_IN_TWO2 = 0x52,
- NOUN_JUNK = 0x54,
- NOUN_KEY = 0x55,
- NOUN_LAMP = 0x56,
- NOUN_LANTERN = 0x57,
- NOUN_LARGE_NOTE = 0x58,
- NOUN_LEG = 0x5A,
- NOUN_LETTER = 0x5B,
- NOUN_LIGHT_FIXTURE = 0x5C,
- NOUN_LOCKING_RAIL = 0x5E,
- NOUN_LOCKRAIL = 0x5F,
- NOUN_MANNEQUINS = 0x62,
- NOUN_MIRROR = 0x63,
- NOUN_MUMMY_PROP = 0x64,
- NOUN_MURAL = 0x65,
- NOUN_MUSIC_SCORE = 0x66,
- NOUN_MUSIC_STAND = 0x67,
- NOUN_MUSIC_STANDS = 0x68,
- NOUN_NOTHING = 0x69,
- NOUN_NOTICE = 0x6A,
- NOUN_ORCHESTRA_DOOR = 0x6B,
- NOUN_ORCHESTRA_PIT = 0x6C,
- NOUN_PAINTING = 0x6D,
- NOUN_PARCHMENT = 0x6E,
- NOUN_PIECE_OF_PAPER = 0x6F,
- NOUN_PIPE = 0x70,
- NOUN_PIT = 0x71,
- NOUN_PLANT = 0x72,
- NOUN_POSTER = 0x73,
- NOUN_PROMPTERS_BOX = 0x74,
- NOUN_PROP_TABLE = 0x75,
- NOUN_PROPS = 0x76,
- NOUN_PROSCENIUM_ARCH = 0x77,
- NOUN_PURCHASE_LINES = 0x78,
- NOUN_RAILING = 0x79,
- NOUN_RED_FRAME = 0x7B,
- NOUN_ROPE = 0x7D,
- NOUN_RUG = 0x7E,
- NOUN_SANDBAG = 0x7F,
- NOUN_SCAFFOLDING = 0x80,
- NOUN_SEATS = 0x81,
- NOUN_SIDE_WALL = 0x82,
- NOUN_SMALL_NOTE = 0x83,
- NOUN_STAGE = 0x84,
- NOUN_STAGE_EXIT = 0x85,
- NOUN_STAGE_LEFT = 0x86,
- NOUN_STAGE_RIGHT = 0x87,
- NOUN_STAGEMANAGERS_POST = 0x88,
- NOUN_STAIR_UNIT = 0x89,
- NOUN_STAIRCASE = 0x8A,
- NOUN_STAIRWELL = 0x8B,
- NOUN_STOOL = 0x8C,
- NOUN_STRIKE = 0x8D,
- NOUN_SWORD = 0x8E,
- NOUN_TABLE = 0x8F,
- NOUN_THE_HOUSE = 0x90,
- NOUN_THUNDER_MACHINE = 0x91,
- NOUN_TICKET = 0x92,
- NOUN_TRAP_CEILING = 0x93,
- NOUN_TRAP_DOOR = 0x94,
- NOUN_URN = 0x98,
- NOUN_WALL = 0x9D,
- NOUN_WARDROBE = 0x9E,
- NOUN_WASTE_BASKET = 0x9F,
- NOUN_WATER_PIPE = 0xA0,
- NOUN_WEDDING_RING = 0xA2,
- NOUN_YELLOW_FRAME = 0xA3,
- NOUN_PROP = 0xA4,
- NOUN_LEFT_DOOR = 0xA8,
- NOUN_RIGHT_DOOR = 0xA9,
- NOUN_DOOR_TO_PIT = 0xAA,
- NOUN_HEADPHONES = 0xAB,
- NOUN_BOXES = 0xAC,
- NOUN_MUG = 0xAD,
- NOUN_DINETTE_SET = 0xAE,
- NOUN_BOX = 0xAF,
- NOUN_CASES = 0xB0,
- NOUN_TRASH_BUCKET = 0xB1,
- NOUN_CORK_BOARD = 0xB2,
- NOUN_HEADSET = 0xB3,
- NOUN_GRAND_FOYER = 0xB4,
- NOUN_BACK_WALL = 0xB5,
- NOUN_BALLET_BAR = 0xB6,
- NOUN_THROW_RUGS = 0xB7,
- NOUN_COSTUME_RACK = 0xB8,
- NOUN_COAT_RACK = 0xB9,
- NOUN_PAINTINGS = 0xBA,
- NOUN_UMBRELLA = 0xBB,
- NOUN_SHELF = 0xBC,
- NOUN_CONTAINER = 0xBD,
- NOUN_TORN_POSTER = 0xBE,
- NOUN_REVIEW = 0xBF,
- NOUN_REVIEWS = 0xC0,
- NOUN_STAGE_RIGHT_WING = 0xC1,
- NOUN_STAGE_LEFT_WING = 0xC2,
- NOUN_PEDESTAL = 0xC3,
- NOUN_PLANT_PROP = 0xC4,
- NOUN_STATUE = 0xC5,
- NOUN_BATTEN = 0xC6,
- NOUN_BIG_PROP = 0xC7,
- NOUN_VENTILATION_DUCT = 0xC8,
- NOUN_CHANDELIER = 0xC9,
- NOUN_BARRIER = 0xCA,
- NOUN_PLACARD = 0xCB,
- NOUN_TICKET_WINDOW = 0xCC,
- NOUN_ARCHWAY = 0xCD,
- NOUN_COLUMN = 0xCE,
- NOUN_RAIL = 0xCF,
- NOUN_SEAT = 0xD0,
- NOUN_LOGE_CORRIDOR = 0xD1,
- NOUN_HOUSE_LIGHT = 0xD2,
- NOUN_FLOV = 0xD3,
- NOUN_LEFT_COLUMN = 0xD4,
- NOUN_RIGHT_COLUMN = 0xD5,
- NOUN_BOOKCASE = 0xD6,
- NOUN_DOORWAY = 0xD7,
- NOUN_COMFY_CHAIR = 0xD8,
- NOUN_DESK = 0xD9,
- NOUN_MANAGERS_CHAIR = 0xDA,
- NOUN_DESK_LAMP = 0xDB,
- NOUN_WINDOW = 0xDC,
- NOUN_SHEERS = 0xDD,
- NOUN_TAPESTRY = 0xDE,
- NOUN_OVERDOOR_MEDALLION = 0xDF,
- NOUN_LATTICEWORK = 0xE0,
- NOUN_DECORATIVE_MOLDING = 0xE1,
- NOUN_LEFT_DOORWAY = 0xE2,
- NOUN_LEFT_ARCHWAY = 0xE3,
- NOUN_RIGHT_DOORWAY = 0xE4,
- NOUN_RIGHT_ARCHWAY = 0xE5,
- NOUN_SOFA = 0xE6,
- NOUN_END_TABLE = 0xE7,
- NOUN_COFFEE_TABLE = 0xE8,
- NOUN_DECORATIVE_VASE = 0xE9,
- NOUN_MARBLE_COLUMN = 0xEA,
- NOUN_BOX_FIVE = 0xEB,
- NOUN_BOX_SIX = 0xED,
- NOUN_BOX_SEVEN = 0xEE,
- NOUN_BOX_EIGHT = 0xEF,
- NOUN_BOX_NINE = 0xF0,
- NOUN_STEP = 0xF1,
- NOUN_PANEL = 0xF2,
- NOUN_MIDDLE_DOORWAY = 0xF4,
- NOUN_LIGHT = 0xF5,
- NOUN_CANDLE = 0xF6,
- NOUN_CASE = 0xF7,
- NOUN_HANDLE = 0xF8,
- NOUN_AXE = 0xF9,
- NOUN_DOOR_CHUNKS = 0xFA,
- NOUN_FLO = 0xFB,
- NOUN_BULLETIN_BOARD = 0xFC,
- NOUN_JULIE = 0xFD,
- NOUN_GLASS_CASE = 0xFE,
- NOUN_KEYHOLE = 0xFF,
- NOUN_MIDDLE_DOOR = 0x100,
- NOUN_DRESSING_GOWN = 0x101,
- NOUN_MONSIEUR_BRIE = 0x102,
- NOUN_CATWALK = 0x103,
- NOUN_GRID = 0x104,
- NOUN_GIRDER = 0x105,
- NOUN_GRIDWORK = 0x106,
- NOUN_DUCTWORK = 0x107,
- NOUN_OPENING = 0x108,
- NOUN_DOME = 0x109,
- NOUN_ALCOVE = 0x10A,
- NOUN_CHRISTINE_DAAE = 0x10B,
- NOUN_CHRISTINE = 0x10C,
- NOUN_WOMAN = 0x10D,
- NOUN_PROMPTERS_STAND = 0x10E,
- NOUN_SUPPORT = 0x10F,
- NOUN_OTHER_CATWALK = 0x110,
- NOUN_SLOT = 0x111,
- NOUN_BEAM_POSITION = 0x112,
- NOUN_LIGHTING_INSTRUMENT = 0x113,
- NOUN_TARP = 0x114,
- NOUN_FACE = 0x115,
- NOUN_CATWALK_OVER_HOUSE = 0x116,
- NOUN_STAIRCASE_POST = 0x117,
- NOUN_JACQUES = 0x118,
- NOUN_GENTLEMAN = 0x119,
- NOUN_BODY = 0x11A,
- NOUN_HOLLOW_COLUMN = 0x11B,
- NOUN_UPPER_LEVEL = 0x11C,
- NOUN_MIDDLE_LEVEL = 0x11D,
- NOUN_LOWER_LEVEL = 0x11E,
- NOUN_LADDER = 0x11F,
- NOUN_CHANDELIER_TRAP = 0x121,
- NOUN_PIECE_OF_WOOD = 0x122,
- NOUN_CUT_HEMP = 0x123,
- NOUN_STONE_WALL = 0x124,
- NOUN_LAKE = 0x125,
- NOUN_STONE_COLUMN = 0x126,
- NOUN_EXIT_THROUGH = 0x127,
- NOUN_STONE_FLOOR = 0x128,
- NOUN_STONE_ARCHWAY = 0x129,
- NOUN_CHARLES = 0x12A,
- NOUN_SWITCH = 0x12B,
- NOUN_PROMPTERS_SEAT = 0x12C,
- NOUN_LEVER = 0x12D,
- NOUN_MONSIEUR_RICHARD = 0x12E,
- NOUN_JULIE2 = 0x12F,
- NOUN_CABLE_HOOK = 0x130,
- NOUN_ROPE_WITH_HOOK = 0x132,
- NOUN_OAR = 0x134,
- NOUN_ORGAN = 0x135,
- NOUN_SIT_AT = 0x136,
- NOUN_ORGAN_BENCH = 0x137,
- NOUN_LARGE_CHAIR = 0x139,
- NOUN_SARCOPHAGUS = 0x13B,
- NOUN_SKULL = 0x13C,
- NOUN_SKULLS = 0x13D,
- NOUN_TOTEM = 0x13E,
- NOUN_POLE = 0x13F,
- NOUN_CURTAIN = 0x140,
- NOUN_TORCH = 0x141,
- NOUN_RAMP = 0x142,
- NOUN_MADAME_GIRY = 0x143,
- NOUN_PANELS = 0x144,
- NOUN_MORE_CATACOMBS = 0x145,
- NOUN_BLOCKED_ARCHWAY = 0x146,
- NOUN_GRATE = 0x147,
- NOUN_CATACOMBS = 0x148,
- NOUN_TICKET_SELLER = 0x149,
- NOUN_USHER = 0x14A,
- NOUN_UNLUCKY_ADVENTURER = 0x14B,
- NOUN_SWITCH_PANEL = 0x14C,
- NOUN_SKULL_SWITCH = 0x14D,
- NOUN_TOGGLE = 0x14E,
- NOUN_CATACOMB_ROOM = 0x14F,
- NOUN_BOX_TEN = 0x150,
- NOUN_FOYER = 0x151,
- NOUN_WALK_DOWN_STAIRCASE = 0x152,
- NOUN_HAT_RACK = 0x154,
- NOUN_VASE = 0x155,
- NOUN_CLOTHES_DUMMY = 0x156,
- NOUN_NOTICES = 0x157,
- NOUN_ARCHWAY_TO_NORTH = 0x158,
- NOUN_ARCHWAY_TO_WEST = 0x159,
- NOUN_ARCHWAY_TO_EAST = 0x15A,
- NOUN_GATE = 0x15B,
- NOUN_NEST = 0x15C,
- NOUN_POT = 0x15D,
- NOUN_PUDDLE = 0x15E,
- NOUN_WEB = 0x15F,
- NOUN_PLANK = 0x160,
- NOUN_BLOCK = 0x161,
- NOUN_RATS_NEST = 0x162,
- NOUN_BROKEN_POT = 0x163,
- NOUN_STONE = 0x164,
- NOUN_DRAIN = 0x165,
- NOUN_FATE = 0x166,
- NOUN_SKULL_SWITCH_1 = 0x167,
- NOUN_SKULL_SWITCH_2 = 0x168,
- NOUN_SKULL_SWITCH_3 = 0x169,
- NOUN_SKULL_SWITCH_4 = 0x16A,
- NOUN_SKULL_SWITCH_5 = 0x16B,
- NOUN_SKULL_SWITCH_6 = 0x16C,
- NOUN_SKULL_SWITCH_7 = 0x16D,
- NOUN_SKULL_SWITCH_8 = 0x16E,
- NOUN_SKULL_SWITCH_9 = 0x16F,
- NOUN_SKULL_SWITCH_10 = 0x170,
- NOUN_SKULL_SWITCH_11 = 0x171,
- NOUN_SKULL_SWITCH_12 = 0x172,
- NOUN_SKULL_SWITCH_13 = 0x173,
- NOUN_SKULL_SWITCH_14 = 0x174,
- NOUN_SKULL_SWITCH_15 = 0x175,
- NOUN_SKULL_SWITCH_16 = 0x176,
- NOUN_SKULL_SWITCH_17 = 0x177,
- NOUN_SKULL_SWITCH_18 = 0x178,
- NOUN_SKULL_SWITCH_19 = 0x179,
- NOUN_SKULL_SWITCH_20 = 0x17A,
- NOUN_SKULL_SWITCH_21 = 0x17B,
- NOUN_SKULL_SWITCH_22 = 0x17C,
- NOUN_SKULL_SWITCH_23 = 0x17D,
- NOUN_SKULL_SWITCH_24 = 0x17E,
- NOUN_SKULL_SWITCH_25 = 0x17F,
- NOUN_SKULL_SWITCH_26 = 0x180,
- NOUN_EDGAR_DEGAS = 0x181,
- NOUN_CHANDELIER_CABLE = 0x182,
- NOUN_COB_WEB = 0x183,
- NOUN_SKULL_FACE = 0x184,
- NOUN_BOAT = 0x185,
- NOUN_HOOK = 0x186,
- NOUN_AROUND = 0x187,
- NOUN_CANE = 0x188,
- NOUN_MASK = 0x189,
- NOUN_COVER = 0x18A,
- NOUN_PADLOCK = 0x18B,
- NOUN_LID = 0x18C,
- NOUN_COBWEB = 0x18D,
- NOUN_PHANTOM = 0x18E,
- NOUN_PAPER = 0x18F
-};
-
-class SceneFactory {
-public:
- static SceneLogic *createScene(MADSEngine *vm);
-};
-
-/**
- * Specialized base class for Dragonsphere game scenes
- */
-class PhantomScene : public SceneLogic {
-protected:
- PhantomGlobals &_globals;
- GamePhantom &_game;
- MADSAction &_action;
-
- /**
- * Forms an animation resource name
- */
- Common::Path formAnimName(char sepChar, int suffixNum);
-
- /**
- * Plays appropriate sound for entering varous rooms
- */
- void lowRoomsEntrySound();
-public:
- /**
- * Constructor
- */
- PhantomScene(MADSEngine *vm);
-
- void sub7178C();
-};
-
-class SceneInfoPhantom : public SceneInfo {
- friend class SceneInfo;
-protected:
- void loadCodes(BaseSurface &depthSurface, int variant) override;
-
- void loadCodes(BaseSurface &depthSurface, Common::SeekableReadStream *stream) override;
-
- /**
- * Constructor
- */
- SceneInfoPhantom(MADSEngine *vm) : SceneInfo(vm) {}
-};
-
-} // End of namespace Phantom
-} // End of namespace MADS
-
-#endif
diff --git a/engines/mads/phantom/phantom_scenes1.cpp b/engines/mads/phantom/phantom_scenes1.cpp
deleted file mode 100644
index b3938fd0c9a..00000000000
--- a/engines/mads/phantom/phantom_scenes1.cpp
+++ /dev/null
@@ -1,9574 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include "mads/mads.h"
-#include "mads/conversations.h"
-#include "mads/scene.h"
-#include "mads/phantom/phantom_scenes.h"
-#include "mads/phantom/phantom_scenes1.h"
-
-namespace MADS {
-namespace Phantom {
-
-void Scene1xx::setAAName() {
- _game._aaName = Resources::formatAAName(_globals[kTempInterface]);
- _vm->_palette->setEntry(254, 43, 47, 51);
-}
-
-void Scene1xx::sceneEntrySound() {
- if (!_vm->_musicFlag)
- return;
-
- if (_globals[kDoneBrieConv203] == 3) {
- _vm->_sound->command(39);
- } else {
- switch (_scene->_nextSceneId) {
- case 101:
- if (!_game._visitedScenes._sceneRevisited)
- _vm->_sound->command(38);
- else
- _vm->_sound->command(16);
- break;
-
- case 102:
- if (_scene->_priorSceneId == 104)
- _vm->_sound->command(27);
- else
- _vm->_sound->command(16);
- break;
-
- case 103:
- if (_globals[kJacquesStatus] == 2) {
- _vm->_sound->command(32);
- _globals[kJacquesStatus] = 3;
- } else
- _vm->_sound->command(16);
- break;
-
- case 104:
- if ((_vm->_gameConv->restoreRunning() == 7) || (_scene->_priorSceneId == 301)) {
- _vm->_sound->command(33);
- } else if (!_globals[kRoom103104Transition] && !_globals[kObservedPhan104]) {
- _vm->_sound->command(37);
- _globals[kObservedPhan104] = true;
- } else
- _vm->_sound->command(16);
- break;
-
- case 111:
- if (_scene->_priorSceneId == 150)
- _vm->_sound->command(38);
- else if (_globals[kLeaveAngelMusicOn])
- _vm->_sound->command(34);
- else
- _vm->_sound->command(16);
- break;
- case 113:
- if (_globals[kLeaveAngelMusicOn])
- _vm->_sound->command(34);
- else if (_globals[kCurrentYear] == 1993)
- _vm->_sound->command(36);
- else
- _vm->_sound->command(35);
- break;
-
- default:
- if ((_scene->_priorSceneId != 204) && (_scene->_nextSceneId != 150))
- _vm->_sound->command(16);
- break;
- }
- }
-}
-
-void Scene1xx::setPlayerSpritesPrefix() {
- _vm->_sound->command(5);
-
- Common::String oldName = _game._player._spritesPrefix;
-
- if (!_game._player._forcePrefix)
- _game._player._spritesPrefix = "RAL";
-
- if (oldName != _game._player._spritesPrefix)
- _game._player._spritesChanged = true;
-
- _game._player._scalingVelocity = true;
-}
-
-/*------------------------------------------------------------------------*/
-
-Scene101::Scene101(MADSEngine *vm) : Scene1xx(vm) {
- _chanStatus = -1;
- _wipeStatus = -1;
- _callingStatus = -1;
- _chandelierStatus = -1;
- _callingFrame = -1;
- _chandelierFrame = -1;
- _convCounter = 0;
- _talkCounter = -1;
- _brieAnimId = 0;
- _startWalkingFl = false;
- _startWalking0Fl = false;
- _anim0Running = false;
- _anim1Running = false;
- _startSittingFl = false;
-}
-
-void Scene101::synchronize(Common::Serializer &s) {
- Scene1xx::synchronize(s);
- s.syncAsSint16LE(_chanStatus);
- s.syncAsSint16LE(_wipeStatus);
- s.syncAsSint16LE(_callingStatus);
- s.syncAsSint16LE(_chandelierStatus);
- s.syncAsSint16LE(_callingFrame);
- s.syncAsSint16LE(_chandelierFrame);
- s.syncAsSint16LE(_convCounter);
- s.syncAsSint16LE(_talkCounter);
- s.syncAsSint16LE(_brieAnimId);
- s.syncAsByte(_startWalkingFl);
- s.syncAsByte(_startWalking0Fl);
- s.syncAsByte(_anim0Running);
- s.syncAsByte(_anim1Running);
- s.syncAsByte(_startSittingFl);
-}
-
-void Scene101::setup() {
- setPlayerSpritesPrefix();
- setAAName();
- _scene->addActiveVocab(NOUN_MONSIEUR_BRIE);
-}
-
-void Scene101::enter() {
- _vm->_disableFastwalk = true;
-
- if (_scene->_priorSceneId != RETURNING_FROM_DIALOG) {
- _chanStatus = _wipeStatus = -1;
- _startWalkingFl = _startWalking0Fl = false;
- _anim0Running = _anim1Running = false;
- _startSittingFl = false;
- }
-
- // Load conversations
- _vm->_gameConv->load(0);
- _vm->_gameConv->load(1);
-
- if (_globals[kCurrentYear] == 1993) {
- _globals._spriteIndexes[0] = _scene->_sprites.addSprites(formAnimName('z', -1));
- _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, 1);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 14);
- } else {
- _scene->_hotspots.activate(NOUN_CHANDELIER, false);
- }
-
- if (_globals[kBrieTalkStatus] == 0) {
- _game._player.firstWalk(Common::Point(-20, 75), FACING_EAST, Common::Point(18, 79), FACING_EAST, true);
- _callingStatus = 0;
- _chandelierStatus = 3;
- _game._player.setWalkTrigger(50);
-
- _globals._animationIndexes[1] = _scene->loadAnimation(formAnimName('b', 9), 1);
- _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('b', 8), 1);
-
- _anim0Running = true;
- _anim1Running = true;
-
- _brieAnimId = _scene->_dynamicHotspots.add(NOUN_MONSIEUR_BRIE, VERB_WALKTO, SYNTAX_SINGULAR_MASC, EXT_NONE, Common::Rect(0, 0, 0, 0));
- _scene->_dynamicHotspots[_brieAnimId]._articleNumber = PREP_ON;
- _scene->_dynamicHotspots.setPosition(_brieAnimId, Common::Point(490, 119), FACING_NONE);
- _scene->setDynamicAnim(_brieAnimId, _globals._animationIndexes[0], 0);
- _scene->setDynamicAnim(_brieAnimId, _globals._animationIndexes[0], 1);
- _scene->setDynamicAnim(_brieAnimId, _globals._animationIndexes[0], 2);
- _scene->setDynamicAnim(_brieAnimId, _globals._animationIndexes[0], 3);
- _scene->setDynamicAnim(_brieAnimId, _globals._animationIndexes[0], 4);
-
- int tmpIdx = _scene->_dynamicHotspots.add(NOUN_MONSIEUR_BRIE, VERB_WALKTO, SYNTAX_SINGULAR_MASC, EXT_NONE, Common::Rect(0, 0, 0, 0));
- _scene->_dynamicHotspots[tmpIdx]._articleNumber = PREP_ON;
- _scene->_dynamicHotspots.setPosition(tmpIdx, Common::Point(25, 80), FACING_NONE);
- _scene->setDynamicAnim(tmpIdx, _globals._animationIndexes[1], 1);
- _scene->setDynamicAnim(tmpIdx, _globals._animationIndexes[1], 2);
-
- _talkCounter = 0;
- } else if (_globals[kBrieTalkStatus] == 1) {
- _globals._animationIndexes[1] = _scene->loadAnimation(formAnimName('b', 9), 1);
- _brieAnimId = _scene->_dynamicHotspots.add(NOUN_MONSIEUR_BRIE, VERB_WALKTO, SYNTAX_SINGULAR_MASC, EXT_NONE, Common::Rect(0, 0, 0, 0));
- _scene->_dynamicHotspots[_brieAnimId]._articleNumber = PREP_ON;
- _scene->setDynamicAnim(_brieAnimId, _globals._animationIndexes[1], 1);
- _scene->setDynamicAnim(_brieAnimId, _globals._animationIndexes[1], 2);
- _anim1Running = true;
- _talkCounter = 0;
- _chandelierStatus = 3;
-
- if (_vm->_gameConv->restoreRunning() == 1) {
- _vm->_gameConv->run(1);
- _vm->_gameConv->exportPointer(&_globals[kPlayerScore]);
- _chandelierStatus = 4;
- _scene->setAnimFrame(_globals._animationIndexes[1], 25);
- }
- } else if (_scene->_priorSceneId == 202) {
- if (_globals[kJacquesStatus] == 1)
- _globals[kJacquesStatus] = 2;
- _game._player.firstWalk(Common::Point(-20, 75), FACING_EAST, Common::Point(18, 79), FACING_EAST, true);
- } else if ((_scene->_priorSceneId == 102) || (_scene->_priorSceneId != RETURNING_FROM_LOADING)) {
- _game._player.firstWalk(Common::Point(655, 130), FACING_WEST, Common::Point(625, 127), FACING_WEST, true);
- _scene->setCamera(Common::Point(320, 0));
- }
-
- sceneEntrySound();
-}
-
-void Scene101::step() {
- if (_anim0Running)
- handleAnimation0();
-
- if ((_globals[kWalkerConverse] == 2) || (_globals[kWalkerConverse] == 3)) {
- ++_convCounter;
- if (_convCounter > 200)
- _globals[kWalkerConverse] = _vm->getRandomNumber(1, 4);
- }
-
- if (_anim1Running) {
- handleAnimation1();
-
- if (_scene->getAnimFrame(_globals._animationIndexes[1]) == 80) {
- _game._player._stepEnabled = true;
- _game._player.setWalkTrigger(55);
- }
- }
-
- if (_scene->_posAdjust.x > 200 && !_startSittingFl && (_globals[kBrieTalkStatus] != 2)) {
- _startSittingFl = true;
- _game._player.walk(Common::Point(490, 119), FACING_NORTHEAST);
- _game._player._stepEnabled = false;
- _game._player.setWalkTrigger(55);
- _chandelierStatus = 4;
- }
-
- if (_game._trigger == 55) {
- _game._player._stepEnabled = true;
- _vm->_gameConv->run(1);
- _vm->_gameConv->exportPointer(&_globals[kPlayerScore]);
- _chandelierFrame = -1;
- _talkCounter = 0;
- }
-
- // Monsieur Brie beckons Raul
- if (_game._trigger == 50) {
- _vm->_gameConv->run(0);
- _callingStatus = 1;
- }
-}
-
-void Scene101::preActions() {
- if (_action.isAction(VERB_EXIT_TO, NOUN_ORCHESTRA_PIT)) {
- if ((_globals[kBrieTalkStatus] == 2) || _startWalkingFl) {
- _game._player._walkOffScreenSceneId = 102;
- _globals[kBrieTalkStatus] = 2;
- } else {
- _vm->_gameConv->run(0);
- _game._player._needToWalk = false;
- }
- } else if (_action.isAction(VERB_EXIT_TO, NOUN_GRAND_FOYER)) {
- if ((_globals[kBrieTalkStatus] == 2) || _startWalkingFl)
- _game._player._walkOffScreenSceneId = 202;
- else {
- _vm->_gameConv->run(0);
- _game._player._needToWalk = false;
- }
- } else if (_action.isAction(VERB_TAKE, NOUN_MONSIEUR_BRIE))
- _vm->_dialogs->show(10121);
- else if (_action.isAction(VERB_TALK_TO, NOUN_MONSIEUR_BRIE) && (_globals[kBrieTalkStatus] == 2))
- _game._player._needToWalk = false;
-}
-
-void Scene101::actions() {
- if (_vm->_gameConv->activeConvId() == 0)
- handleConversation0();
- else if (_vm->_gameConv->activeConvId() == 1)
- handleConversation1();
- else if (_action._lookFlag) {
- if (_globals[kCurrentYear] == 1993)
- _vm->_dialogs->show(10110);
- else
- _vm->_dialogs->show(10111);
- } else if (_action.isAction(VERB_LOOK) || _action.isAction(VERB_LOOK_AT)) {
- if (_action.isObject(NOUN_AISLE)) {
- _vm->_dialogs->show(10112);
- } else if (_action.isObject(NOUN_CHANDELIER)) {
- _vm->_dialogs->show(10113);
- } else if (_action.isObject(NOUN_BACK_WALL)) {
- _vm->_dialogs->show(10114);
- } else if (_action.isObject(NOUN_SIDE_WALL)) {
- _vm->_dialogs->show(10115);
- } else if (_action.isObject(NOUN_SEATS)) {
- if ((_globals[kBrieTalkStatus] > 1) || _startWalkingFl)
- _vm->_dialogs->show(10119);
- else
- _vm->_dialogs->show(10116);
- } else if (_action.isObject(NOUN_GRAND_FOYER)) {
- _vm->_dialogs->show(10117);
- } else if (_action.isObject(NOUN_ORCHESTRA_PIT)) {
- _vm->_dialogs->show(10118);
- } else if (_action.isObject(NOUN_MONSIEUR_BRIE)) {
- _vm->_dialogs->show(10120);
- }
- } else if (_action.isAction(VERB_TALK_TO, NOUN_MONSIEUR_BRIE)) {
- if (_globals[kBrieTalkStatus] == 2)
- _vm->_dialogs->show(10122);
- } else if (!_action.isAction(VERB_TAKE, NOUN_MONSIEUR_BRIE))
- return;
-
- _action._inProgress = false;
-}
-
-void Scene101::handleConversation0() {
- _vm->_gameConv->setHeroTrigger(90);
-
- if (_game._trigger == 90) {
- _globals[kBrieTalkStatus] = 1;
- _startWalking0Fl = true;
- }
-}
-
-void Scene101::handleConversation1() {
- if ((_action._activeAction._verbId >= 0) && (_action._activeAction._verbId <= 27)) {
- bool interlocutorFl = false;
-
- if (_game._trigger == 60) {
- switch (_action._activeAction._verbId) {
- case 0:
- _chandelierStatus = 6;
- _wipeStatus = 2;
- break;
-
- case 1:
- _chandelierStatus = 2;
- _chanStatus = 9;
- break;
-
- case 4:
- _chandelierStatus = 0;
- _chanStatus = -1;
- _wipeStatus = -1;
- break;
-
- case 8:
- case 10:
- case 18:
- case 22:
- case 24:
- _startWalkingFl = true;
- _chanStatus = -1;
- _wipeStatus = -1;
- _globals[kWalkerConverse] = 0;
- _vm->_gameConv->setInterlocutorTrigger(105);
- interlocutorFl = true;
- break;
-
- case 12:
- _chandelierStatus = 5;
- _chanStatus = -1;
- _wipeStatus = -1;
- break;
-
- default:
- break;
- }
- }
-
- if (!interlocutorFl)
- _vm->_gameConv->setInterlocutorTrigger(60);
-
- _vm->_gameConv->setHeroTrigger(70);
-
- _talkCounter = 0;
-
- if (_game._trigger == 60) {
- if (!_startWalkingFl)
- _globals[kWalkerConverse] = _vm->getRandomNumber(1, 4);
-
- _chandelierStatus = 2;
- } else if ((_game._trigger == 70) && !_startWalkingFl) {
- _chandelierStatus = 4;
- _chanStatus = -1;
- _wipeStatus = -1;
- if (!_startWalkingFl)
- _globals[kWalkerConverse] = _vm->getRandomNumber(2, 3);
-
- _convCounter = 0;
- }
- }
-}
-
-void Scene101::handleAnimation0() {
- if (_scene->getAnimFrame(_globals._animationIndexes[0]) == _callingFrame)
- return;
-
- _callingFrame = _scene->getAnimFrame(_globals._animationIndexes[0]);
- int resetFrame = -1;
- switch (_callingFrame) {
- case 1:
- case 9:
- case 12:
- if (_callingStatus == 1) {
- if (_callingFrame == 9) {
- if (_startWalking0Fl) {
- resetFrame = 13;
- _callingStatus = 3;
- } else
- _callingStatus = 2;
- } else
- resetFrame = 1;
- }
-
- if (_callingStatus == 0) {
- if (_startWalking0Fl) {
- resetFrame = 60;
- _callingStatus = 3;
- } else
- resetFrame = 0;
- }
-
- if (_callingStatus == 2) {
- if (_startWalking0Fl) {
- resetFrame = 13;
- _callingStatus = 3;
- } else {
- ++_talkCounter;
-
- if (_talkCounter < 18) {
- if (_vm->getRandomNumber(1, 2) == 1)
- resetFrame = 7;
- else
- resetFrame = 10;
- } else {
- resetFrame = 54;
- _callingStatus = 0;
- }
- }
- }
- break;
-
- case 53:
- _anim0Running = false;
- _scene->freeAnimation(0);
- break;
-
- case 59:
- if (_startWalking0Fl) {
- resetFrame = 60;
- _callingStatus = 3;
- } else {
- resetFrame = 0;
- _callingStatus = 0;
- }
- break;
-
- case 66:
- resetFrame = 24;
- break;
-
- default:
- break;
- }
-
- if (resetFrame >= 0) {
- _scene->setAnimFrame(_globals._animationIndexes[0], resetFrame);
- _callingFrame = resetFrame;
- }
-}
-
-void Scene101::handleAnimation1() {
- if (_scene->getAnimFrame(_globals._animationIndexes[1]) == _chandelierFrame)
- return;
-
- _chandelierFrame = _scene->getAnimFrame(_globals._animationIndexes[1]);
- int resetFrame = -1;
- switch (_chandelierFrame) {
- case 1:
- if (_chandelierStatus == 3)
- resetFrame = 0;
- break;
-
- case 11:
- case 14:
- case 17:
- case 19:
- case 26:
- case 44:
- case 333:
- if (_talkCounter == _chanStatus) {
- _chandelierStatus = 0;
- ++_talkCounter;
- _chanStatus = -1;
- }
-
- if (_talkCounter == _wipeStatus) {
- _chandelierStatus = 6;
- ++_talkCounter;
- _wipeStatus = -1;
- }
-
- if (_startWalkingFl) {
- if (_vm->_gameConv->activeConvId() == 1) {
- if (_talkCounter > 13)
- _chandelierStatus = 1;
- } else
- _chandelierStatus = 1;
- }
-
- switch (_chandelierStatus) {
- case 0:
- resetFrame = 27;
- _chandelierStatus = 2;
- break;
-
- case 1:
- _globals[kBrieTalkStatus] = 2;
- resetFrame = 45;
- if (_vm->_gameConv->activeConvId() == 1)
- _vm->_gameConv->stop();
- _scene->_dynamicHotspots.remove(_brieAnimId);
- _game._player._stepEnabled = false;
- break;
-
- case 2:
- ++_talkCounter;
- if (_talkCounter < 15) {
- switch (_vm->getRandomNumber(1, 3)) {
- case 1:
- resetFrame = 12;
- break;
-
- case 2:
- resetFrame = 14;
- break;
-
- case 3:
- resetFrame = 17;
- break;
-
- default:
- break;
- }
- } else {
- _chandelierStatus = 4;
- resetFrame = 25;
- }
- break;
-
- case 4:
- resetFrame = 25;
- break;
-
- case 5:
- resetFrame = 21;
- _chandelierStatus = 2;
- break;
-
- case 6:
- resetFrame = 316;
- _chandelierStatus = 2;
- break;
-
- default:
- break;
- }
- break;
-
- case 315:
- _scene->freeAnimation(1);
- break;
-
- default:
- break;
- }
-
- if (resetFrame >= 0) {
- _scene->setAnimFrame(_globals._animationIndexes[1], resetFrame);
- _chandelierFrame = resetFrame;
- }
-}
-
-/*------------------------------------------------------------------------*/
-
-Scene102::Scene102(MADSEngine *vm) : Scene1xx(vm) {
- _anim0Running = false;
-}
-
-void Scene102::synchronize(Common::Serializer &s) {
- Scene1xx::synchronize(s);
-
- s.syncAsByte(_anim0Running);
-}
-
-void Scene102::setup() {
- setPlayerSpritesPrefix();
- setAAName();
-}
-
-void Scene102::enter() {
- _anim0Running = false;
-
- _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('x', 0));
- _globals._spriteIndexes[3] = _scene->_sprites.addSprites("*RAL86");
-
- if (_globals[kCurrentYear] == 1993) {
- _globals._spriteIndexes[0] = _scene->_sprites.addSprites(formAnimName('z', -1));
- _scene->drawToBackground(_globals._spriteIndexes[0], 1, Common::Point(-32000, -32000), 0, 100);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 14);
- } else {
- _scene->_hotspots.activate(NOUN_CHANDELIER, false);
- }
-
- if (_scene->_priorSceneId == 101) {
- _game._player._playerPos = Common::Point(97, 79);
- _game._player._facing = FACING_SOUTHEAST;
- _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, 4);
- _game._player.walk(Common::Point(83, 87), FACING_SOUTHEAST);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 14);
- } else if (_scene->_priorSceneId == 104) {
- // Player fell from pit -> death
- Common::Point deathPos = Common::Point(0, 0);
- int deathScale = 0;
- int deathDepth = 0;
- _game._player._stepEnabled = false;
- _game._player._visible = false;
-
- switch (_globals[36]) {
- case 0:
- deathPos = Common::Point(221, 57);
- deathScale = 50;
- deathDepth = 14;
- break;
-
- case 1:
- deathPos = Common::Point(219, 85);
- deathScale = 60;
- deathDepth = 6;
- break;
-
- case 2:
- deathPos = Common::Point(257, 138);
- deathScale = 76;
- deathDepth = 1;
- break;
-
- default:
- break;
- }
- _scene->_userInterface.emptyConversationList();
- _scene->_userInterface.setup(kInputConversation);
- _globals._sequenceIndexes[3] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[3], false, 1);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[3], deathDepth);
- _scene->_sequences.setPosition(_globals._sequenceIndexes[3], deathPos);
- _scene->_sequences.setScale(_globals._sequenceIndexes[3], deathScale);
- _scene->_sequences.addTimer(120, 65);
- _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, 4);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 14);
- } else if (_scene->_priorSceneId == 103 || _scene->_priorSceneId != RETURNING_FROM_LOADING) {
- _game._player._playerPos = Common::Point(282, 145);
- _game._player._facing = FACING_WEST;
- _anim0Running = true;
- _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('d', 1), 60);
- } else if (_scene->_priorSceneId == -1) {
- _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, 4);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 14);
- }
-
- sceneEntrySound();
-}
-
-void Scene102::step() {
- if (_game._trigger == 60) {
- // Door closes
- _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, 4);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 14);
- _anim0Running = false;
- } else if (_game._trigger == 65) {
- // Death
- if (_globals[kDeathLocation] == 0)
- _vm->_dialogs->show(10232);
- else
- _vm->_dialogs->show(10229);
-
- _vm->_sound->command(16);
- _scene->_nextSceneId = 104;
- }
-}
-
-void Scene102::preActions() {
- if (_action.isAction(VERB_OPEN, NOUN_ORCHESTRA_DOOR) || _action.isAction(VERB_PUSH, NOUN_ORCHESTRA_DOOR))
- _game._player.walk(Common::Point(282, 145), FACING_EAST);
-}
-
-void Scene102::actions() {
- if (_action.isAction(VERB_WALK_DOWN, NOUN_AISLE)) {
- _scene->_nextSceneId = 101;
- } else if (_action.isAction(VERB_WALK_THROUGH, NOUN_ORCHESTRA_DOOR) ||
- _action.isAction(VERB_PUSH, NOUN_ORCHESTRA_DOOR) ||
- _action.isAction(VERB_OPEN, NOUN_ORCHESTRA_DOOR)) {
- if (_anim0Running) {
- _scene->_sequences.addTimer(15, 70);
- _game._player._stepEnabled = false;
- } else {
- switch (_game._trigger) {
- case 70: // try again
- case 0:
- _scene->deleteSequence(_globals._sequenceIndexes[2]);
- _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('d', 0), 1);
- _game._player._stepEnabled = false;
- _game._player._visible = false;
- break;
- case 1:
- _scene->_nextSceneId = 103;
- break;
- default:
- break;
- }
- }
- } else if (_action._lookFlag)
- _vm->_dialogs->show(10210);
- else if (_action.isAction(VERB_LOOK) || _action.isAction(VERB_LOOK_AT)) {
- if (_action.isObject(NOUN_PIT))
- _vm->_dialogs->show(10211);
- else if (_action.isObject(NOUN_SEATS))
- if (_globals[kCurrentYear] == 1881)
- _vm->_dialogs->show(10212);
- else
- _vm->_dialogs->show(10230);
- else if (_action.isObject(NOUN_ORCHESTRA_DOOR))
- _vm->_dialogs->show(10213);
- else if (_action.isObject(NOUN_CONDUCTORS_STAND))
- _vm->_dialogs->show(10214);
- else if (_action.isObject(NOUN_MUSIC_STAND) || _action.isObject(NOUN_MUSIC_STANDS))
- _vm->_dialogs->show(10215);
- else if (_action.isObject(NOUN_PROMPTERS_BOX))
- _vm->_dialogs->show(10217);
- else if (_action.isObject(NOUN_STAGE))
- _vm->_dialogs->show(10218);
- else if (_action.isObject(NOUN_APRON))
- _vm->_dialogs->show(10219);
- else if (_action.isObject(NOUN_SIDE_WALL))
- _vm->_dialogs->show(10220);
- else if (_action.isObject(NOUN_FOLDING_CHAIRS))
- _vm->_dialogs->show(10221);
- else if (_action.isObject(NOUN_AISLE))
- _vm->_dialogs->show(10222);
- else if (_action.isObject(NOUN_PROSCENIUM_ARCH))
- _vm->_dialogs->show(10223);
- else if (_action.isObject(NOUN_ACT_CURTAIN))
- _vm->_dialogs->show(10224);
- else if (_action.isObject(NOUN_IN_ONE))
- _vm->_dialogs->show(10225);
- else if (_action.isObject(NOUN_IN_TWO))
- _vm->_dialogs->show(10226);
- else if (_action.isObject(NOUN_LEG))
- _vm->_dialogs->show(10227);
- else if (_action.isObject(NOUN_CHANDELIER))
- _vm->_dialogs->show(10231);
- } else if (_action.isAction(VERB_CLOSE, NOUN_ORCHESTRA_DOOR))
- _vm->_dialogs->show(10228);
-
- _game._player._stepEnabled = false;
-}
-
-/*------------------------------------------------------------------------*/
-
-Scene103::Scene103(MADSEngine *vm) : Scene1xx(vm) {
- _jacquesAction = -1;
- _lastRandom = -1;
- _standPosition = -1;
- _hotspotPrompt1 = -1;
- _hotspotPrompt2 = -1;
- _hotspotPrompt3 = -1;
- _hotspotPrompt4 = -1;
- _hotspotPrompt5 = -1;
- _hotspotRightFloor1 = -1;
- _hotspotRightFloor2 = -1;
- _hotspotLeftFloor1 = -1;
- _hotspotLeftFloor2 = -1;
- _hotspotGentleman = -1;
- _convCount = -1;
- _lastStairFrame = -1;
- _lastJacquesFrame = -1;
- _talkCount = -1;
-
- _anim0ActvFl = false;
- _anim1ActvFl = false;
- _anim2ActvFl = false;
- _anim3ActvFl = false;
- _anim4ActvFl = false;
- _anim5ActvFl = false;
- _anim6ActvFl = false;
- _climbThroughTrapFl = false;
- _guardFrameFl = false;
- _sitFl = false;
-}
-
-void Scene103::synchronize(Common::Serializer &s) {
- Scene1xx::synchronize(s);
-
- s.syncAsSint16LE(_jacquesAction);
- s.syncAsSint16LE(_lastRandom);
- s.syncAsSint16LE(_standPosition);
- s.syncAsSint16LE(_hotspotPrompt1);
- s.syncAsSint16LE(_hotspotPrompt2);
- s.syncAsSint16LE(_hotspotPrompt3);
- s.syncAsSint16LE(_hotspotPrompt4);
- s.syncAsSint16LE(_hotspotPrompt5);
- s.syncAsSint16LE(_hotspotRightFloor1);
- s.syncAsSint16LE(_hotspotRightFloor2);
- s.syncAsSint16LE(_hotspotLeftFloor1);
- s.syncAsSint16LE(_hotspotLeftFloor2);
- s.syncAsSint16LE(_convCount);
- s.syncAsSint16LE(_lastStairFrame);
-
- s.syncAsByte(_anim0ActvFl);
- s.syncAsByte(_anim1ActvFl);
- s.syncAsByte(_anim2ActvFl);
- s.syncAsByte(_anim3ActvFl);
- s.syncAsByte(_anim4ActvFl);
- s.syncAsByte(_anim5ActvFl);
- s.syncAsByte(_anim6ActvFl);
- s.syncAsByte(_climbThroughTrapFl);
- s.syncAsByte(_guardFrameFl);
- s.syncAsByte(_sitFl);
-}
-
-void Scene103::setup() {
- setPlayerSpritesPrefix();
- setAAName();
-
- _scene->_variant = 0;
-
- if ((_globals[kPrompterStandStatus] == 1) || (_globals[kCurrentYear] == 1881)) {
- _scene->_variant = 1;
- if ((_globals[kJacquesStatus] == 0) && (_globals[kCurrentYear] == 1881))
- _scene->_variant = 2;
- else if ((_globals[kJacquesStatus] >= 1) && (_globals[kCurrentYear] == 1881))
- _scene->_variant = 3;
- }
-
- _scene->addActiveVocab(NOUN_PROMPTERS_STAND);
- _scene->addActiveVocab(NOUN_JACQUES);
- _scene->addActiveVocab(NOUN_GENTLEMAN);
- _scene->addActiveVocab(VERB_CLIMB);
-}
-
-void Scene103::enter() {
- if (_scene->_priorSceneId != RETURNING_FROM_LOADING) {
- _anim0ActvFl = false;
- _anim1ActvFl = false;
- _anim2ActvFl = false;
- _anim3ActvFl = false;
- _anim4ActvFl = false;
- _anim5ActvFl = false;
- _anim6ActvFl = false;
- _climbThroughTrapFl = false;
- _guardFrameFl = false;
- _sitFl = false;
- _jacquesAction = 1;
- _lastRandom = 0;
- _standPosition = 0;
- }
-
- if (_globals[kJacquesStatus] >= 1) {
- if (_game._objects.isInRoom(OBJ_KEY)) {
- _globals._spriteIndexes[5] = _scene->_sprites.addSprites(formAnimName('x', 2));
- _globals._spriteIndexes[8] = _scene->_sprites.addSprites("*RRD_9");
- }
- _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('f', 3));
- _globals._spriteIndexes[6] = _scene->_sprites.addSprites(formAnimName('c', 1));
- _globals._spriteIndexes[7] = _scene->_sprites.addSprites(formAnimName('f', 1));
- } else {
- _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('f', 0));
- _globals._spriteIndexes[10] = _scene->_sprites.addSprites(formAnimName('a', 3));
- }
-
- _globals._spriteIndexes[9] = _scene->_sprites.addSprites(formAnimName('x', 3));
- _globals._spriteIndexes[11] = _scene->_sprites.addSprites(formAnimName('a', 2));
- _globals._spriteIndexes[12] = _scene->_sprites.addSprites(formAnimName('f', 2));
- _globals._spriteIndexes[0] = _scene->_sprites.addSprites(formAnimName('x', 0));
- _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('x', 1));
- _globals._spriteIndexes[2] = _scene->_sprites.addSprites("*RDR_6");
-
- adjustRails(_scene->_variant);
-
- _scene->_hotspots.activate(NOUN_JACQUES, false);
- _scene->_hotspots.activate(NOUN_KEY, false);
-
- _vm->_gameConv->load(12);
-
- if (_globals[kTrapDoorStatus] == 0) {
- _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, 5);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 14);
-
- _globals._sequenceIndexes[9] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[9], false, 2);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[9], 3);
- } else if (_globals[kTrapDoorStatus] == 1) {
- _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, 1);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 14);
-
- _globals._sequenceIndexes[9] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[9], false, 1);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[9], 3);
- }
-
- Common::Point promptPos;
- Facing promptFacing;
-
- if (_globals[kJacquesStatus] == 0) {
- promptPos = Common::Point(115, 142);
- promptFacing = FACING_NORTHEAST;
- } else {
- promptPos = Common::Point(171, 142);
- promptFacing = FACING_NORTHWEST;
- }
-
- if ((_globals[kPrompterStandStatus] == 1) || (_globals[kCurrentYear] == 1881)) {
- if (_globals[kJacquesStatus] >= 1) {
- _globals._sequenceIndexes[7] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[7], false, 1);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[7], 1);
-
- _globals._sequenceIndexes[3] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[3], false, 1);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 4);
- _scene->_sequences.setPosition(_globals._sequenceIndexes[3], Common::Point(154, 139));
-
- } else {
- _globals._sequenceIndexes[3] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[3], false, 1);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 4);
- _scene->_sequences.setPosition(_globals._sequenceIndexes[3], Common::Point(154, 139));
-
- _globals._sequenceIndexes[12] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[12], false, 1);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[12], 1);
- }
-
- _hotspotPrompt1 = _scene->_dynamicHotspots.add(NOUN_PROMPTERS_STAND, VERB_WALKTO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(121, 79, 121 + 40, 79 + 63));
- _scene->_dynamicHotspots[_hotspotPrompt1]._articleNumber = PREP_ON;
- _scene->_dynamicHotspots.setPosition(_hotspotPrompt1, promptPos, promptFacing);
-
- _hotspotPrompt2 = _scene->_dynamicHotspots.add(NOUN_PROMPTERS_STAND, VERB_WALKTO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(161, 67, 161 + 16, 67 + 75));
- _scene->_dynamicHotspots[_hotspotPrompt2]._articleNumber = PREP_ON;
- _scene->_dynamicHotspots.setPosition(_hotspotPrompt2, promptPos, promptFacing);
-
- _hotspotPrompt3 = _scene->_dynamicHotspots.add(NOUN_PROMPTERS_STAND, VERB_WALKTO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(177, 90, 177 + 18, 90 + 52));
- _scene->_dynamicHotspots[_hotspotPrompt3]._articleNumber = PREP_ON;
- _scene->_dynamicHotspots.setPosition(_hotspotPrompt3, promptPos, promptFacing);
-
- _hotspotPrompt4 = _scene->_dynamicHotspots.add(NOUN_PROMPTERS_STAND, VERB_WALKTO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(114, 100, 114 + 7, 100 + 38));
- _scene->_dynamicHotspots[_hotspotPrompt4]._articleNumber = PREP_ON;
- _scene->_dynamicHotspots.setPosition(_hotspotPrompt4, promptPos, promptFacing);
-
- _hotspotPrompt5 = _scene->_dynamicHotspots.add(NOUN_PROMPTERS_STAND, VERB_CLIMB, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(121, 49, 121 + 40, 49 + 30));
- _scene->_dynamicHotspots[_hotspotPrompt5]._articleNumber = PREP_ON;
- _scene->_dynamicHotspots.setPosition(_hotspotPrompt5, Common::Point(196, 134), FACING_SOUTHWEST);
- _scene->_dynamicHotspots.setCursor(_hotspotPrompt5, CURSOR_GO_UP);
-
- _hotspotRightFloor1 = _scene->_dynamicHotspots.add(NOUN_FLOOR, VERB_WALK_ACROSS, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(154, 6, 154 + 41, 6 + 6));
- _scene->_dynamicHotspots[_hotspotRightFloor1]._articleNumber = PREP_ON;
- _scene->_dynamicHotspots.setPosition(_hotspotRightFloor1, Common::Point(171, 142), FACING_NONE);
-
- _hotspotRightFloor2 = _scene->_dynamicHotspots.add(NOUN_FLOOR, VERB_WALK_ACROSS, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(114, 136, 114 + 32, 136 + 6));
- _scene->_dynamicHotspots[_hotspotRightFloor2]._articleNumber = PREP_ON;
- _scene->_dynamicHotspots.setPosition(_hotspotRightFloor2, Common::Point(127, 140), FACING_NONE);
-
- if ((_globals[kJacquesStatus] == 0) && (_globals[kCurrentYear] == 1881)) {
- if (_globals[kJacquesNameIsKnown] >= 1) {
- _hotspotGentleman = _scene->_dynamicHotspots.add(NOUN_JACQUES, VERB_WALKTO, SYNTAX_SINGULAR_MASC, EXT_NONE, Common::Rect(156, 116, 156 + 33, 116 + 31));
- _scene->_dynamicHotspots[_hotspotGentleman]._articleNumber = PREP_ON;
- _scene->_dynamicHotspots.setPosition(_hotspotGentleman, Common::Point(206, 148), FACING_NORTHWEST);
- } else {
- _hotspotGentleman = _scene->_dynamicHotspots.add(NOUN_GENTLEMAN, VERB_WALKTO, SYNTAX_MASC_NOT_PROPER, -1, Common::Rect(156, 116, 156 + 33, 116 + 31));
- _scene->_dynamicHotspots[_hotspotGentleman]._articleNumber = PREP_ON;
- _scene->_dynamicHotspots.setPosition(_hotspotGentleman, Common::Point(206, 148), FACING_NORTHWEST);
- }
- int tmpIdx = _scene->_dynamicHotspots.add(NOUN_FLOOR, VERB_WALK_ACROSS, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(149, 140, 149 + 13, 140 + 7));
- _scene->_dynamicHotspots[tmpIdx]._articleNumber = PREP_ON;
- _scene->_dynamicHotspots.setPosition(tmpIdx, Common::Point(155, 144), FACING_NONE);
-
- tmpIdx = _scene->_dynamicHotspots.add(NOUN_FLOOR, VERB_WALK_ACROSS, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(187, 136, 187 + 8, 136 + 7));
- _scene->_dynamicHotspots[tmpIdx]._articleNumber = PREP_ON;
- _scene->_dynamicHotspots.setPosition(tmpIdx, Common::Point(195, 139), FACING_NONE);
- } else if ((_globals[kJacquesStatus] >= 1) && (_globals[kCurrentYear] == 1881)) {
- _globals._sequenceIndexes[6] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[6], false, 1);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[6], 3);
- if (_game._objects.isInRoom(OBJ_KEY)) {
- _globals._sequenceIndexes[5] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[5], false, 1);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[5], 14);
- _scene->_hotspots.activate(NOUN_KEY, true);
- }
- _scene->_hotspots.activate(NOUN_JACQUES, true);
- _scene->_dynamicHotspots.remove(_hotspotRightFloor2);
-
- int tmpIdx = _scene->_dynamicHotspots.add(NOUN_JACQUES, VERB_WALKTO, SYNTAX_SINGULAR_MASC, EXT_NONE, Common::Rect(114, 132, 114 + 30, 132 + 10));
- _scene->_dynamicHotspots[tmpIdx]._articleNumber = PREP_ON;
- _scene->_dynamicHotspots.setPosition(tmpIdx, Common::Point(95, 144), FACING_NORTHEAST);
-
- tmpIdx = _scene->_dynamicHotspots.add(NOUN_FLOOR, VERB_WALK_ACROSS, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(94, 129, 94 + 18, 129 + 4));
- _scene->_dynamicHotspots[tmpIdx]._articleNumber = PREP_ON;
- _scene->_dynamicHotspots.setPosition(tmpIdx, Common::Point(95, 133), FACING_NONE);
-
- tmpIdx = _scene->_dynamicHotspots.add(NOUN_FLOOR, VERB_WALK_ACROSS, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(94, 132, 94 + 3, 132 + 9));
- _scene->_dynamicHotspots[tmpIdx]._articleNumber = PREP_ON;
- _scene->_dynamicHotspots.setPosition(tmpIdx, Common::Point(93, 135), FACING_NONE);
-
- tmpIdx = _scene->_dynamicHotspots.add(NOUN_FLOOR, VERB_WALK_ACROSS, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(112, 150, 112 + 21, 150 + 3));
- _scene->_dynamicHotspots[tmpIdx]._articleNumber = PREP_ON;
- _scene->_dynamicHotspots.setPosition(tmpIdx, Common::Point(118, 154), FACING_NONE);
-
- tmpIdx = _scene->_dynamicHotspots.add(NOUN_FLOOR, VERB_WALK_ACROSS, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(98, 146, 98 + 21, 146 + 4));
- _scene->_dynamicHotspots[tmpIdx]._articleNumber = PREP_ON;
- _scene->_dynamicHotspots.setPosition(tmpIdx, Common::Point(104, 148), FACING_NONE);
- }
- } else if (_globals[kPrompterStandStatus] == 0) {
- _globals._sequenceIndexes[3] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[3], false, 1);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 4);
- _scene->_sequences.setPosition(_globals._sequenceIndexes[3], Common::Point(37, 139));
-
- _hotspotPrompt1 = _scene->_dynamicHotspots.add(NOUN_PROMPTERS_STAND, VERB_WALKTO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(2, 79, 2 + 40, 79 + 63));
- _scene->_dynamicHotspots[_hotspotPrompt1]._articleNumber = PREP_ON;
- _scene->_dynamicHotspots.setPosition(_hotspotPrompt1, Common::Point(59, 140), FACING_NORTHWEST);
-
- _hotspotPrompt2 = _scene->_dynamicHotspots.add(NOUN_PROMPTERS_STAND, VERB_WALKTO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(42, 67, 42 + 16, 67 + 75));
- _scene->_dynamicHotspots[_hotspotPrompt2]._articleNumber = PREP_ON;
- _scene->_dynamicHotspots.setPosition(_hotspotPrompt2, Common::Point(59, 140), FACING_NORTHWEST);
-
- _hotspotPrompt3 = _scene->_dynamicHotspots.add(NOUN_PROMPTERS_STAND, VERB_WALKTO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(58, 90, 58 + 18, 90 + 52));
- _scene->_dynamicHotspots[_hotspotPrompt3]._articleNumber = PREP_ON;
- _scene->_dynamicHotspots.setPosition(_hotspotPrompt3, Common::Point(59, 140), FACING_NORTHWEST);
-
- _hotspotPrompt5 = _scene->_dynamicHotspots.add(NOUN_PROMPTERS_STAND, VERB_CLIMB, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(2, 49, 2 + 40, 49 + 30));
- _scene->_dynamicHotspots[_hotspotPrompt5]._articleNumber = PREP_ON;
- _scene->_dynamicHotspots.setPosition(_hotspotPrompt5, Common::Point(79, 132), FACING_SOUTHWEST);
- _scene->_dynamicHotspots.setCursor(_hotspotPrompt5, CURSOR_GO_UP);
-
- _hotspotLeftFloor1 = _scene->_dynamicHotspots.add(NOUN_FLOOR, VERB_WALK_ACROSS, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(35, 137, 35 + 40, 137 + 5));
- _scene->_dynamicHotspots[_hotspotLeftFloor1]._articleNumber = PREP_ON;
- _scene->_dynamicHotspots.setPosition(_hotspotLeftFloor1, Common::Point(59, 140), FACING_NONE);
- _hotspotLeftFloor2 = _scene->_dynamicHotspots.add(NOUN_FLOOR, VERB_WALK_ACROSS, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(76, 129, 76 + 6, 129 + 6));
- _scene->_dynamicHotspots[_hotspotLeftFloor2]._articleNumber = PREP_ON;
- _scene->_dynamicHotspots.setPosition(_hotspotLeftFloor2, Common::Point(80, 135), FACING_NONE);
- }
-
- if ((_globals[kJacquesStatus] == 0) && (_globals[kCurrentYear] == 1881)) {
- _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('j', 1), 1);
- _anim0ActvFl = true;
- _scene->setAnimFrame(_globals._animationIndexes[0], 9);
- }
-
- if (_scene->_priorSceneId == 104) {
- _game._player._stepEnabled = false;
- _game._player._visible = false;
- if (_globals[kRoom103104Transition] == 0) {
- _globals[kRoom103104Transition] = 1;
- _globals._sequenceIndexes[10] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[10], false, -2);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[10], 4);
- _standPosition = 1;
- _game._player._playerPos = Common::Point(79, 132);
- _scene->_sequences.addTimer(1, 100);
- } else {
- _standPosition = 2;
- _globals._animationIndexes[3] = _scene->loadAnimation(formAnimName('w', 1), 0);
- _anim3ActvFl = true;
- _game._player._stepEnabled = true;
- _game._player._playerPos = Common::Point(196, 134);
- _scene->setAnimFrame(_globals._animationIndexes[3], 36);
-
- _scene->deleteSequence(_globals._sequenceIndexes[3]);
- _globals._sequenceIndexes[3] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[3], false, 1);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 13);
- _scene->_sequences.setPosition(_globals._sequenceIndexes[3], Common::Point(154, 139));
- }
-
- _globals._sequenceIndexes[1] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[1], false, -1);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 14);
- } else if (_scene->_priorSceneId == 102) {
- _game._player.firstWalk(Common::Point(-20, 140), FACING_EAST, Common::Point(15, 147), FACING_EAST, true);
- _globals._sequenceIndexes[1] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[1], false, 1);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 14);
- } else if ((_scene->_priorSceneId == 105) || (_scene->_priorSceneId != RETURNING_FROM_LOADING)) {
- _game._player._playerPos = Common::Point(287, 135);
- _game._player._facing = FACING_WEST;
- _game._player._stepEnabled = false;
- _game._player.walk(Common::Point(252, 134), FACING_WEST);
- _game._player.setWalkTrigger(65);
- _globals._sequenceIndexes[1] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[1], false, 6);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 14);
- } else if (_scene->_priorSceneId == -1) {
- if (_standPosition == 1) {
- _game._player._visible = false;
- _globals._animationIndexes[5] = _scene->loadAnimation(formAnimName('w', 3), 0);
- _anim5ActvFl = true;
- _scene->setAnimFrame(_globals._animationIndexes[5], 33);
- } else if (_standPosition == 2) {
- _scene->deleteSequence(_globals._sequenceIndexes[3]);
- _globals._sequenceIndexes[3] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[3], false, 1);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 13);
- _scene->_sequences.setPosition(_globals._sequenceIndexes[3], Common::Point(154, 139));
- _game._player._visible = false;
- _globals._animationIndexes[3] = _scene->loadAnimation(formAnimName('w', 1), 0);
- _anim3ActvFl = true;
- _game._player._stepEnabled = true;
- _scene->setAnimFrame(_globals._animationIndexes[3], 36);
- } else if (_vm->_gameConv->restoreRunning() == 12) {
- _vm->_gameConv->run(12);
- _vm->_gameConv->exportPointer(&_globals[kPlayerScore]);
- _vm->_gameConv->exportValue(_globals[kMusicSelected]);
- _globals[kWalkerConverse] = _vm->getRandomNumber(1, 4);
- }
- _globals._sequenceIndexes[1] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[1], false, -1);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 14);
- }
-
- sceneEntrySound();
-}
-
-void Scene103::step() {
- if (_anim0ActvFl)
- handleJacquesAnim();
-
- if (_anim3ActvFl)
- climbRightStairs();
-
- if (_anim5ActvFl)
- climbLeftStairs();
-
- if (_anim4ActvFl)
- descendRightStairs();
-
- if (_anim6ActvFl)
- descendLeftStairs();
-
- if ((_globals[kWalkerConverse] == 2) || (_globals[kWalkerConverse] == 3)) {
- ++_convCount;
- if (_convCount > 200)
- _globals[kWalkerConverse] = _vm->getRandomNumber(1, 4);
- }
-
- switch (_game._trigger) {
- case 65:
- _scene->deleteSequence(_globals._sequenceIndexes[1]);
- _globals._sequenceIndexes[1] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[1], false, 8, 1);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 14);
- _scene->_sequences.setAnimRange(_globals._sequenceIndexes[1], 1, 6);
- _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 66);
- _vm->_sound->command(66);
- break;
-
- case 66: {
- int syncIdx = _globals._sequenceIndexes[1];
- _vm->_sound->command(25);
- _globals._sequenceIndexes[1] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[1], false, 1);
- _game.syncTimers(SYNC_SEQ, _globals._sequenceIndexes[1], SYNC_SEQ, syncIdx);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 14);
- _game._player._stepEnabled = true;
- }
- break;
-
- case 80:
- _scene->_nextSceneId = 104;
- _scene->_reloadSceneFlag = true;
- break;
-
- default:
- break;
- }
-
- switch (_game._trigger) {
- case 100:
- _scene->deleteSequence(_globals._sequenceIndexes[10]);
- _globals._sequenceIndexes[10] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[10], false, 6, 1);
- _scene->_sequences.addSubEntry(_globals._sequenceIndexes[10], SEQUENCE_TRIGGER_EXPIRE, 0, 101);
- _scene->_sequences.setAnimRange(_globals._sequenceIndexes[10], -1, -2);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[10], 4);
- break;
-
- case 101:
- _globals._animationIndexes[5] = _scene->loadAnimation(formAnimName('w', 3), 0);
- _anim5ActvFl = true;
- _scene->setAnimFrame(_globals._animationIndexes[5], 33);
- _game._player._stepEnabled = true;
- _game.syncTimers(SYNC_ANIM, _globals._animationIndexes[5], SYNC_SEQ, _globals._sequenceIndexes[10]);
- break;
-
- default:
- break;
- }
-
- switch (_game._trigger) {
- case 0:
- if (_anim1ActvFl) {
- if ((_scene->getAnimFrame(_globals._animationIndexes[1]) == 10) && !_guardFrameFl) {
- _vm->_sound->command(64);
- _guardFrameFl = true;
- _scene->deleteSequence(_globals._sequenceIndexes[0]);
- _scene->deleteSequence(_globals._sequenceIndexes[9]);
- _globals._sequenceIndexes[0] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[0], false, 6, 1);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 14);
- _scene->_sequences.setAnimRange(_globals._sequenceIndexes[0], -1, -2);
- _scene->_sequences.addSubEntry(_globals._sequenceIndexes[0], SEQUENCE_TRIGGER_EXPIRE, 0, 105);
- }
- } else if (_anim2ActvFl) {
- if ((_scene->getAnimFrame(_globals._animationIndexes[2]) == 7) && !_guardFrameFl) {
- _vm->_sound->command(64);
- _guardFrameFl = true;
- _scene->deleteSequence(_globals._sequenceIndexes[0]);
- _scene->deleteSequence(_globals._sequenceIndexes[9]);
- _globals._sequenceIndexes[0] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[0], false, 6, 1);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 14);
- _scene->_sequences.setAnimRange(_globals._sequenceIndexes[0], -1, -2);
- _scene->_sequences.addSubEntry(_globals._sequenceIndexes[0], SEQUENCE_TRIGGER_EXPIRE, 0, 110);
- }
- }
- break;
-
- case 105:
- _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, -2);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 14);
- _globals._sequenceIndexes[9] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[9], false, -2);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[9], 2);
- _guardFrameFl = false;
- break;
-
- case 110:
- _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, -1);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 14);
- _globals._sequenceIndexes[9] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[9], false, -1);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[9], 2);
- _guardFrameFl = false;
- break;
-
- default:
- break;
- }
-
- if (_globals[kJacquesStatus] == 3) {
- warning("TODO: add a check on the return value of _vm->_sound->command ???");
- _vm->_sound->command(38);
- }
-}
-
-void Scene103::preActions() {
- if (_action.isAction(VERB_OPEN, NOUN_DOOR))
- _game._player._needToWalk = true;
-
- if (_action.isAction(VERB_OPEN, NOUN_DOOR_TO_PIT)) {
- _game._player.walk(Common::Point(0, 150), FACING_WEST);
- _game._player._walkOffScreenSceneId = 102;
- }
-
- if ((_standPosition != 0) && !_action.isAction(VERB_CLIMB_THROUGH, NOUN_TRAP_DOOR) &&
- !_action.isAction(VERB_OPEN, NOUN_TRAP_DOOR) &&
- !_action.isAction(VERB_CLIMB, NOUN_PROMPTERS_STAND) &&
- !_action.isAction(VERB_PUSH, NOUN_TRAP_DOOR) &&
- !_action.isAction(VERB_LOOK_THROUGH, NOUN_PROMPTERS_BOX) &&
- !_action.isAction(VERB_PULL, NOUN_TRAP_DOOR)) {
-
- if (_action.isAction(VERB_PULL) || _action.isAction(VERB_PUSH)) {
- if (!_action.isObject(NOUN_LEVER) && !_game._trigger)
- _game._player._needToWalk = false;
- }
-
- if ((_action.isAction(VERB_PUSH, NOUN_PROMPTERS_STAND)) || (_action.isAction(VERB_PULL, NOUN_PROMPTERS_STAND))) {
- if (!_game._trigger)
- _game._player._needToWalk = true;
- }
-
- if (_game._player._needToWalk) {
- if (_globals[kPrompterStandStatus] == 0) {
- switch (_game._trigger) {
- case 0:
- _scene->freeAnimation(5);
- _game._player._readyToWalk = false;
- _game._player._visible = false;
- _game._player._stepEnabled = false;
- _anim5ActvFl = false;
- _anim6ActvFl = true;
- _globals._animationIndexes[6] = _scene->loadAnimation(formAnimName('w', 4), 1);
- break;
-
- case 1:
- _game._player._playerPos = Common::Point(79, 132);
- _game._player._stepEnabled = true;
- _game._player._visible = true;
- _standPosition = 0;
- _game._player._readyToWalk = true;
- if (_action.isAction(VERB_PUSH, NOUN_PROMPTERS_STAND))
- _game._player._needToWalk = false;
- _anim6ActvFl = false;
- _game._player.resetFacing(FACING_NORTHEAST);
- _game.syncTimers(SYNC_PLAYER, 0, SYNC_ANIM, _globals._animationIndexes[6]);
- break;
-
- default:
- break;
- }
- } else {
- switch (_game._trigger) {
- case 0:
- _scene->freeAnimation(3);
- _game._player._readyToWalk = false;
- if (_action.isAction(VERB_PUSH, NOUN_PROMPTERS_STAND))
- _game._player._needToWalk = true;
- _game._player._visible = false;
- _game._player._stepEnabled = false;
- _anim3ActvFl = false;
- _anim4ActvFl = true;
- _globals._animationIndexes[4] = _scene->loadAnimation(formAnimName('w', 2), 1);
- break;
-
- case 1:
- _game._player._playerPos = Common::Point(196, 134);
- _game._player._stepEnabled = true;
- _game._player._readyToWalk = true;
- if (_action.isAction(VERB_PUSH, NOUN_PROMPTERS_STAND))
- _game._player._needToWalk = false;
- _game._player._visible = true;
- _standPosition = 0;
- _anim4ActvFl = false;
- _game._player.resetFacing(FACING_NORTHEAST);
- _game.syncTimers(SYNC_PLAYER, 0, SYNC_ANIM, _globals._animationIndexes[4]);
- break;
-
- default:
- break;
- }
- }
- }
- }
-
- if (_standPosition == 0) {
- if ((_action.isAction(VERB_PUSH, NOUN_PROMPTERS_STAND)) || (_action.isAction(VERB_PULL, NOUN_PROMPTERS_STAND))) {
- if (_globals[kCurrentYear] == 1993) {
- if (_globals[kPrompterStandStatus] == 0)
- _game._player.walk(Common::Point(2, 138), FACING_WEST);
- else
- _game._player.walk(Common::Point(176, 142), FACING_WEST);
- }
- }
- }
-
- if (_action.isAction(VERB_LOOK_THROUGH, NOUN_PROMPTERS_BOX) && (_standPosition == 0) && (_globals[kPrompterStandStatus] == 0) && (_globals[kCurrentYear] == 1993))
- _game._player.walk(Common::Point(79, 132), FACING_SOUTHWEST);
-
- if (_action.isAction(VERB_CLIMB_THROUGH, NOUN_TRAP_DOOR) && (_standPosition == 0) && (_globals[kPrompterStandStatus] == 1) && (_globals[kTrapDoorStatus] == 0))
- _game._player.walk(Common::Point(196, 134), FACING_SOUTHWEST);
-
- if (_action.isAction(VERB_WALK_THROUGH, NOUN_DOOR_TO_PIT))
- _game._player._walkOffScreenSceneId = 102;
-
- if ((_action.isAction(VERB_OPEN, NOUN_DOOR) || _action.isAction(VERB_UNLOCK, NOUN_DOOR) || _action.isAction(VERB_LOCK, NOUN_DOOR)) && (_standPosition == 0))
- _game._player.walk(Common::Point(252, 134), FACING_EAST);
-}
-
-void Scene103::actions() {
- if (_action.isAction(VERB_OPEN, NOUN_DOOR_TO_PIT)) {
- _scene->_nextSceneId = 102;
- _action._inProgress = false;
- return;
- }
-
- if (_vm->_gameConv->activeConvId() == 12) {
- process_conv_jacques();
- _action._inProgress = false;
- return;
- }
-
- if (_action.isAction(VERB_CLIMB_THROUGH, NOUN_TRAP_DOOR)) {
- if (_globals[kTrapDoorStatus] == 1) {
- _vm->_dialogs->show(10333);
- _action._inProgress = false;
- return;
- } else if (_globals[kPrompterStandStatus] == 0) {
- _vm->_dialogs->show(10341);
- _action._inProgress = false;
- return;
- }
- }
-
- if ((_action.isAction(VERB_LOOK_THROUGH, NOUN_PROMPTERS_BOX)) && (_globals[kPrompterStandStatus] == 1)) {
- _vm->_dialogs->show(10342);
- _action._inProgress = false;
- return;
- }
-
- if ((_action.isAction(VERB_CLIMB, NOUN_PROMPTERS_STAND) && _standPosition == 0) ||
- (_action.isAction(VERB_LOOK_THROUGH, NOUN_PROMPTERS_BOX) && (_standPosition == 0)) ||
- (_action.isAction(VERB_CLIMB_THROUGH, NOUN_TRAP_DOOR) && (_standPosition == 0))) {
- if (_globals[kPrompterStandStatus] == 0) {
- if (_game._trigger == 0) {
- if (_action.isAction(VERB_LOOK_THROUGH, NOUN_PROMPTERS_BOX)) {
- _sitFl = true;
- _globals._animationIndexes[5] = _scene->loadAnimation(formAnimName('w', 3), 115);
- } else
- _globals._animationIndexes[5] = _scene->loadAnimation(formAnimName('w', 3), 0);
-
- _game._player._visible = false;
- _game._player._stepEnabled = false;
- _anim5ActvFl = true;
- _game.syncTimers(SYNC_ANIM, _globals._animationIndexes[5], SYNC_PLAYER, 0);
- _action._inProgress = false;
- return;
- }
- } else if (_game._trigger == 0) {
- if (_action.isAction(VERB_CLIMB_THROUGH, NOUN_TRAP_DOOR)) {
- _climbThroughTrapFl = true;
- _globals._animationIndexes[3] = _scene->loadAnimation(formAnimName('w', 1), 120);
- } else
- _globals._animationIndexes[3] = _scene->loadAnimation(formAnimName('w', 1), 0);
-
- _game._player._visible = false;
- _game._player._stepEnabled = false;
- _anim3ActvFl = true;
- _game.syncTimers(SYNC_ANIM, _globals._animationIndexes[3], SYNC_PLAYER, 0);
- _action._inProgress = false;
- return;
- }
- }
-
- if (_action.isAction(VERB_CLIMB, NOUN_PROMPTERS_STAND) && (_standPosition != 0)) {
- _action._inProgress = false;
- return;
- }
-
- if ((_action.isAction(VERB_PUSH, NOUN_PROMPTERS_STAND)) || (_action.isAction(VERB_PULL, NOUN_PROMPTERS_STAND))) {
- if (_globals[kCurrentYear] == 1993) {
- if (_globals[kPrompterStandStatus] == 0) {
- switch (_game._trigger) {
- case 0:
- if (_globals[kPrompterStandStatus] == 0) {
- _game._player._stepEnabled = false;
- _game._player._visible = false;
- _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('s', 1), 75);
- _game._player._priorTimer = _scene->_frameStartTime;
- _game.syncTimers(SYNC_ANIM, _globals._animationIndexes[0], SYNC_PLAYER, 0);
- _scene->deleteSequence(_globals._sequenceIndexes[3]);
- }
- break;
-
- case 75:
- if (_globals[kPrompterStandStatus] == 0) {
- _globals._sequenceIndexes[12] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[12], false, 1);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[12], 1);
- _globals._sequenceIndexes[3] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[3], false, 1);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 4);
- _scene->_sequences.setPosition(_globals._sequenceIndexes[3], Common::Point(154, 139));
- _game.syncTimers(SYNC_SEQ, _globals._sequenceIndexes[3], SYNC_ANIM, _globals._animationIndexes[0]);
- _globals[kPrompterStandStatus] = 1;
- _game._player._stepEnabled = true;
- _game._player._visible = true;
- _game._player._playerPos = Common::Point(117, 139);
- _game._player.resetFacing(FACING_EAST);
- _game.syncTimers(SYNC_PLAYER, 0, SYNC_ANIM, _globals._animationIndexes[0]);
-
- _scene->_dynamicHotspots.remove(_hotspotPrompt1);
- _scene->_dynamicHotspots.remove(_hotspotPrompt2);
- _scene->_dynamicHotspots.remove(_hotspotPrompt3);
- _scene->_dynamicHotspots.remove(_hotspotPrompt5);
- _scene->_dynamicHotspots.remove(_hotspotLeftFloor1);
- _scene->_dynamicHotspots.remove(_hotspotLeftFloor2);
-
- _hotspotPrompt1 = _scene->_dynamicHotspots.add(NOUN_PROMPTERS_STAND, VERB_WALKTO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(121, 79, 121 + 40, 79 + 63));
- _scene->_dynamicHotspots[_hotspotPrompt1]._articleNumber = PREP_ON;
- _scene->_dynamicHotspots.setPosition(_hotspotPrompt1, Common::Point(171, 142), FACING_NORTHWEST);
-
- _hotspotPrompt2 = _scene->_dynamicHotspots.add(NOUN_PROMPTERS_STAND, VERB_WALKTO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(161, 67, 161 + 16, 67 + 75));
- _scene->_dynamicHotspots[_hotspotPrompt2]._articleNumber = PREP_ON;
- _scene->_dynamicHotspots.setPosition(_hotspotPrompt2, Common::Point(171, 142), FACING_NORTHWEST);
-
- _hotspotPrompt3 = _scene->_dynamicHotspots.add(NOUN_PROMPTERS_STAND, VERB_WALKTO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(177, 90, 177 + 18, 90 + 52));
- _scene->_dynamicHotspots[_hotspotPrompt3]._articleNumber = PREP_ON;
- _scene->_dynamicHotspots.setPosition(_hotspotPrompt3, Common::Point(171, 142), FACING_NORTHWEST);
-
- _hotspotPrompt4 = _scene->_dynamicHotspots.add(NOUN_PROMPTERS_STAND, VERB_WALKTO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(114, 100, 114 + 7, 100 + 38));
- _scene->_dynamicHotspots[_hotspotPrompt4]._articleNumber = PREP_ON;
- _scene->_dynamicHotspots.setPosition(_hotspotPrompt4, Common::Point(171, 142), FACING_NORTHWEST);
-
- _hotspotPrompt5 = _scene->_dynamicHotspots.add(NOUN_PROMPTERS_STAND, VERB_CLIMB, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(121, 49, 121 + 40, 49 + 30));
- _scene->_dynamicHotspots[_hotspotPrompt5]._articleNumber = PREP_ON;
- _scene->_dynamicHotspots.setPosition(_hotspotPrompt5, Common::Point(196, 134), FACING_SOUTHWEST);
- _scene->_dynamicHotspots.setCursor(_hotspotPrompt5, CURSOR_GO_UP);
-
- _hotspotRightFloor1 = _scene->_dynamicHotspots.add(NOUN_FLOOR, VERB_WALK_ACROSS, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(154, 6, 154 + 41, 6 + 6));
- _scene->_dynamicHotspots[_hotspotRightFloor1]._articleNumber = PREP_ON;
- _scene->_dynamicHotspots.setPosition(_hotspotRightFloor1, Common::Point(171, 142), FACING_NONE);
-
- _hotspotRightFloor2 = _scene->_dynamicHotspots.add(NOUN_FLOOR, VERB_WALK_ACROSS, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(114, 136, 114 + 32, 132 + 6));
- _scene->_dynamicHotspots[_hotspotRightFloor2]._articleNumber = PREP_ON;
- _scene->_dynamicHotspots.setPosition(_hotspotRightFloor2, Common::Point(127, 140), FACING_NONE);
-
- _scene->changeVariant(1);
- adjustRails(1);
- }
- break;
-
- default:
- break;
- }
- } else {
- switch (_game._trigger) {
- case 0:
- if (_globals[kPrompterStandStatus] == 1) {
- _game._player._stepEnabled = false;
- _game._player._visible = false;
- _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('s', 2), 75);
- _game._player._priorTimer = _scene->_frameStartTime;
- _game.syncTimers(SYNC_ANIM, _globals._animationIndexes[0], SYNC_PLAYER, 0);
- _scene->deleteSequence(_globals._sequenceIndexes[12]);
- _scene->deleteSequence(_globals._sequenceIndexes[3]);
- }
- break;
-
- case 75:
- if (_globals[kPrompterStandStatus] == 1) {
- _globals._sequenceIndexes[3] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[3], false, 1);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 4);
- _scene->_sequences.setPosition(_globals._sequenceIndexes[3], Common::Point(37, 139));
- _game.syncTimers(SYNC_SEQ, _globals._sequenceIndexes[3], SYNC_ANIM, _globals._animationIndexes[0]);
- _globals[kPrompterStandStatus] = 0;
- _game._player._stepEnabled = true;
- _game._player._visible = true;
- _game._player._playerPos = Common::Point(62, 142);
- _game._player.resetFacing(FACING_WEST);
- _game.syncTimers(SYNC_PLAYER, 0, SYNC_ANIM, _globals._animationIndexes[0]);
- _scene->_dynamicHotspots.remove(_hotspotPrompt1);
- _scene->_dynamicHotspots.remove(_hotspotPrompt2);
- _scene->_dynamicHotspots.remove(_hotspotPrompt3);
- _scene->_dynamicHotspots.remove(_hotspotPrompt4);
- _scene->_dynamicHotspots.remove(_hotspotPrompt5);
- _scene->_dynamicHotspots.remove(_hotspotRightFloor1);
- _scene->_dynamicHotspots.remove(_hotspotRightFloor2);
-
- _hotspotPrompt1 = _scene->_dynamicHotspots.add(NOUN_PROMPTERS_STAND, VERB_WALKTO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(2, 79, 2 + 40, 79 + 63));
- _scene->_dynamicHotspots[_hotspotPrompt1]._articleNumber = PREP_ON;
- _scene->_dynamicHotspots.setPosition(_hotspotPrompt1, Common::Point(59, 140), FACING_NORTHWEST);
-
- _hotspotPrompt2 = _scene->_dynamicHotspots.add(NOUN_PROMPTERS_STAND, VERB_WALKTO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(42, 67, 42 + 16, 67 + 75));
- _scene->_dynamicHotspots[_hotspotPrompt2]._articleNumber = PREP_ON;
- _scene->_dynamicHotspots.setPosition(_hotspotPrompt2, Common::Point(59, 140), FACING_NORTHWEST);
-
- _hotspotPrompt3 = _scene->_dynamicHotspots.add(NOUN_PROMPTERS_STAND, VERB_WALKTO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(58, 90, 58 + 18, 90 + 52));
- _scene->_dynamicHotspots[_hotspotPrompt3]._articleNumber = PREP_ON;
- _scene->_dynamicHotspots.setPosition(_hotspotPrompt3, Common::Point(59, 140), FACING_NORTHWEST);
-
- _hotspotLeftFloor1 = _scene->_dynamicHotspots.add(NOUN_FLOOR, VERB_WALK_ACROSS, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(35, 137, 35 + 40, 137 + 5));
- _scene->_dynamicHotspots[_hotspotLeftFloor1]._articleNumber = PREP_ON;
- _scene->_dynamicHotspots.setPosition(_hotspotLeftFloor1, Common::Point(59, 140), FACING_NONE);
-
- _hotspotLeftFloor2 = _scene->_dynamicHotspots.add(NOUN_FLOOR, VERB_WALK_ACROSS, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(76, 129, 76 + 6, 129 + 6));
- _scene->_dynamicHotspots[_hotspotLeftFloor2]._articleNumber = PREP_ON;
- _scene->_dynamicHotspots.setPosition(_hotspotLeftFloor2, Common::Point(80, 135), FACING_NONE);
-
- _hotspotPrompt5 = _scene->_dynamicHotspots.add(NOUN_PROMPTERS_STAND, VERB_CLIMB, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(2, 49, 2 + 40, 49 + 30));
- _scene->_dynamicHotspots[_hotspotPrompt5]._articleNumber = PREP_ON;
- _scene->_dynamicHotspots.setPosition(_hotspotPrompt5, Common::Point(79, 132), FACING_SOUTHWEST);
- _scene->_dynamicHotspots.setCursor(_hotspotPrompt5, CURSOR_GO_UP);
-
- _scene->changeVariant(0);
- adjustRails(0);
- }
- break;
-
- default:
- break;
- }
- }
- } else if (_globals[kJacquesNameIsKnown])
- _vm->_dialogs->show(10340);
- else
- _vm->_dialogs->show(10350);
-
- _action._inProgress = false;
- return;
- }
-
- if (_action.isAction(VERB_WALK_THROUGH, NOUN_DOOR) || _action.isAction(VERB_OPEN, NOUN_DOOR) || _action.isAction(VERB_UNLOCK, NOUN_DOOR) || _action.isAction(VERB_LOCK, NOUN_DOOR)) {
- if ((_globals[kCurrentYear] == 1881) && !_action.isAction(VERB_LOCK, NOUN_DOOR) && !_action.isAction(VERB_UNLOCK, NOUN_DOOR)) {
- switch (_game._trigger) {
- case (0):
- _game._player._stepEnabled = false;
- _game._player._visible = false;
- _globals._sequenceIndexes[2] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[2], false, 5, 2);
- _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], -1, -2);
- _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[2], true);
- _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
- _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_SPRITE, 3, 70);
- break;
-
- case 2:
- _game._player._visible = true;
- _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[2]);
- _game._player.walk(Common::Point(295, 132), FACING_WEST);
- _scene->_sequences.addTimer(180, 3);
- break;
-
- case 3:
- _scene->_nextSceneId = 105;
- break;
-
- case 70:
- _vm->_sound->command(24);
- _scene->deleteSequence(_globals._sequenceIndexes[1]);
- _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 8, 1);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 14);
- _scene->_sequences.setAnimRange(_globals._sequenceIndexes[1], -1, -2);
- _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 71);
- _vm->_sound->command(66);
- break;
-
- case 71: {
- int oldIdx = _globals._sequenceIndexes[1];
- _globals._sequenceIndexes[1] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[1], false, -2);
- _game.syncTimers(SYNC_SEQ, _globals._sequenceIndexes[1], SYNC_SEQ, oldIdx);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 14);
- }
- break;
-
- default:
- break;
- }
- } else {
- switch (_game._trigger) {
- case (0):
- _game._player._stepEnabled = false;
- _game._player._visible = false;
- _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 5, 1);
- _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], 1, 4);
- _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[2], true);
- _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
- break;
-
- case 1: {
- int oldIdx = _globals._sequenceIndexes[2];
- _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, 4);
- _game.syncTimers(SYNC_SEQ, _globals._sequenceIndexes[2], SYNC_SEQ, oldIdx);
- _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[2], false);
- _scene->_sequences.addTimer(15, 2);
- _vm->_sound->command(73);
- }
- break;
-
- case 2:
- _scene->deleteSequence(_globals._sequenceIndexes[2]);
- _globals._sequenceIndexes[2] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[2], false, 5, 1);
- _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], 1, 4);
- _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[2], false);
- _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 3);
- break;
-
- case 3:
- _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[2]);
- _game._player._visible = true;
- if (_action.isAction(VERB_LOCK) || _action.isAction(VERB_UNLOCK))
- _vm->_dialogs->show(00032);
- else
- _vm->_dialogs->show(10335);
-
- _game._player._stepEnabled = true;
- break;
-
- default:
- break;
- }
- }
- _action._inProgress = false;
- return;
- }
-
- if (_action.isAction(VERB_TAKE, NOUN_KEY) && (_game._objects.isInRoom(OBJ_KEY) || _game._trigger)) {
- switch (_game._trigger) {
- case (0):
- _game._player._stepEnabled = false;
- _game._player._visible = false;
- _globals._sequenceIndexes[8] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[8], false, 5, 2);
- _scene->_sequences.setAnimRange(_globals._sequenceIndexes[8], 1, 5);
- _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[8], true);
- _scene->_sequences.addSubEntry(_globals._sequenceIndexes[8], SEQUENCE_TRIGGER_SPRITE, 5, 1);
- _scene->_sequences.addSubEntry(_globals._sequenceIndexes[8], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
- _action._inProgress = false;
- return;
-
- case 1:
- _scene->deleteSequence(_globals._sequenceIndexes[5]);
- _scene->_hotspots.activate(NOUN_KEY, false);
- _game._objects.addToInventory(OBJ_KEY);
- _vm->_sound->command(26);
- _action._inProgress = false;
- return;
-
- case 2:
- _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[8]);
- _game._player._visible = true;
- _scene->_sequences.addTimer(20, 3);
- _action._inProgress = false;
- return;
-
- case 3:
- _globals[kPlayerScore] += 5;
- _vm->_dialogs->showItem(OBJ_KEY, 800, 0);
- _game._player._stepEnabled = true;
- _action._inProgress = false;
- return;
-
- default:
- break;
- }
- }
-
- if (_action.isAction(VERB_TALK_TO, NOUN_GENTLEMAN) || _action.isAction(VERB_TALK_TO, NOUN_JACQUES)) {
- if (_globals[kJacquesStatus] == 0) {
- _vm->_gameConv->run(12);
- _vm->_gameConv->exportPointer(&_globals[kPlayerScore]);
- _vm->_gameConv->exportValue(_globals[kMusicSelected]);
- } else
- _vm->_dialogs->show(10343);
-
- _action._inProgress = false;
- return;
- }
-
- if (_action.isAction(VERB_CLIMB_THROUGH, NOUN_TRAP_DOOR) || _climbThroughTrapFl) {
- if ((_standPosition == 2) && (_globals[kTrapDoorStatus] == 0)) {
- switch (_game._trigger) {
- case 0:
- case 120:
- if (!(_globals[kPlayerScoreFlags] & 1)) {
- _globals[kPlayerScoreFlags] |= 1;
- _globals[kPlayerScore] += 3;
- }
-
- _scene->freeAnimation(3);
- _anim3ActvFl = false;
- _climbThroughTrapFl = false;
- _game._player._stepEnabled = false;
- _globals._sequenceIndexes[11] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[11], false, 6, 1);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[11], 5);
- _scene->_sequences.setAnimRange(_globals._sequenceIndexes[11], -1, -2);
- _scene->_sequences.addSubEntry(_globals._sequenceIndexes[11], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
- break;
-
- case 1:
- _globals[kRoom103104Transition] = 1;
- _scene->_nextSceneId = 104;
- break;
-
- default:
- break;
- }
- }
- _action._inProgress = false;
- return;
- }
-
- if (_action.isAction(VERB_LOOK_THROUGH, NOUN_PROMPTERS_BOX) || _sitFl) {
- if (_standPosition == 1) {
- switch (_game._trigger) {
- case 0:
- case 115:
- _scene->freeAnimation(5);
- _anim5ActvFl = false;
- _game._player._stepEnabled = false;
- _globals._sequenceIndexes[10] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[10], false, 6, 1);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[10], 4);
- _scene->_sequences.setAnimRange(_globals._sequenceIndexes[10], -1, -2);
- _scene->_sequences.addSubEntry(_globals._sequenceIndexes[10], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
- if (!_sitFl)
- _game.syncTimers(SYNC_SEQ, _globals._sequenceIndexes[10], SYNC_ANIM, _globals._animationIndexes[5]);
- _sitFl = false;
- break;
-
- case 1:
- _globals[kRoom103104Transition] = 0;
- _scene->_nextSceneId = 104;
- break;
-
- default:
- break;
- }
- }
- _action._inProgress = false;
- return;
- }
-
- if (_action.isAction(VERB_PUSH, NOUN_LEVER) || _action.isAction(VERB_PULL, NOUN_LEVER)) {
- if (_globals[kTrapDoorStatus] == 1) {
- switch (_game._trigger) {
- case 0:
- _globals._animationIndexes[1] = _scene->loadAnimation(formAnimName('l', 1), 1);
- _anim1ActvFl = true;
- _game._player._visible = false;
- _game._player._stepEnabled = false;
- _game.syncTimers(SYNC_ANIM, _globals._animationIndexes[1], SYNC_PLAYER, 0);
- break;
-
- case 1:
- _anim1ActvFl = false;
- _game._player._visible = true;
- _globals[kTrapDoorStatus] = 0;
- _game._player._stepEnabled = true;
- _game.syncTimers(SYNC_PLAYER, 0, SYNC_ANIM, _globals._animationIndexes[1]);
- break;
-
- default:
- break;
- }
- } else {
- switch (_game._trigger) {
- case 0:
- _globals._animationIndexes[2] = _scene->loadAnimation(formAnimName('l', 2), 1);
- _anim2ActvFl = true;
- _game._player._visible = false;
- _game._player._stepEnabled = false;
- _game.syncTimers(SYNC_ANIM, _globals._animationIndexes[2], SYNC_PLAYER, 0);
- break;
-
- case 1:
- _anim2ActvFl = false;
- _game._player._visible = true;
- _globals[kTrapDoorStatus] = 1;
- _game._player._stepEnabled = true;
- _game.syncTimers(SYNC_PLAYER, 0, SYNC_ANIM, _globals._animationIndexes[2]);
- break;
-
- default:
- break;
- }
- }
- _action._inProgress = false;
- return;
- }
-
- if (_action._lookFlag) {
- if ((_globals[kCurrentYear] == 1881) && (_globals[kJacquesStatus] >= 1))
- _vm->_dialogs->show(10311);
- else
- _vm->_dialogs->show(10310);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isAction(VERB_LOOK) || _action.isAction(VERB_LOOK_AT)) {
- if (_action.isObject(NOUN_PROMPTERS_STAND)) {
- if (_globals[kJacquesStatus] >= 1)
- _vm->_dialogs->show(10349);
- else if (_globals[kCurrentYear] == 1993)
- _vm->_dialogs->show(10312);
- else
- _vm->_dialogs->show(10345);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_FLOOR)) {
- _vm->_dialogs->show(10313);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_TRAP_CEILING)) {
- _vm->_dialogs->show(10314);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_DOOR)) {
- _vm->_dialogs->show(10315);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_DOOR_TO_PIT)) {
- _vm->_dialogs->show(10316);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_WALL)) {
- _vm->_dialogs->show(10317);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_PROMPTERS_BOX)) {
- _vm->_dialogs->show(10318);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_TRAP_DOOR)) {
- _vm->_dialogs->show(10319);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_JUNK)) {
- if (_globals[kCurrentYear] == 1993)
- _vm->_dialogs->show(10320);
- else
- _vm->_dialogs->show(10346);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_CARTON)) {
- if (_globals[kCurrentYear] == 1993)
- _vm->_dialogs->show(10321);
- else
- _vm->_dialogs->show(10347);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_GARBAGE_CAN)) {
- if (_globals[kCurrentYear] == 1993)
- _vm->_dialogs->show(10322);
- else
- _vm->_dialogs->show(10348);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_CABLE)) {
- _vm->_dialogs->show(10323);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_JACQUES) || _action.isObject(NOUN_GENTLEMAN)) {
- if (_globals[kJacquesStatus] == 0)
- _vm->_dialogs->show(10324);
- else
- _vm->_dialogs->show(10325);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_KEY) && _game._objects.isInRoom(OBJ_KEY)) {
- _vm->_dialogs->show(10326);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_STAIR_UNIT)) {
- _vm->_dialogs->show(10327);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_EXPOSED_BRICK)) {
- _vm->_dialogs->show(10328);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_WATER_PIPE)) {
- _vm->_dialogs->show(10329);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_PROMPTERS_SEAT)) {
- _vm->_dialogs->show(10338);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_LEVER)) {
- _vm->_dialogs->show(10339);
- _action._inProgress = false;
- return;
- }
-
- }
-
- if (_action.isAction(VERB_CLOSE, NOUN_DOOR_TO_PIT)) {
- _vm->_dialogs->show(10331);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isAction(VERB_CLOSE, NOUN_DOOR)) {
- _vm->_dialogs->show(10331);
- _action._inProgress = false;
- return;
- }
-
- if ((_action.isAction(VERB_OPEN, NOUN_TRAP_DOOR)) || (_action.isAction(VERB_CLOSE, NOUN_TRAP_DOOR))) {
- _vm->_dialogs->show(10344);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isAction(VERB_TAKE, NOUN_JACQUES) || _action.isAction(VERB_TAKE, NOUN_GENTLEMAN)) {
- if (_globals[kJacquesStatus] == 0) {
- if (_globals[kJacquesNameIsKnown])
- _vm->_dialogs->show(10336);
- else
- _vm->_dialogs->show(10351);
- } else
- _vm->_dialogs->show(10337);
- _action._inProgress = false;
- return;
- }
-}
-
-void Scene103::adjustRails(int variant) {
- switch (variant) {
- case 0:
- _scene->_rails.disableNode(3);
- _scene->_rails.disableNode(4);
- _scene->_rails.disableNode(5);
- _scene->_rails.disableNode(6);
- _scene->_rails.disableNode(12);
- _scene->_rails.disableNode(13);
- _scene->_rails.disableNode(14);
- break;
-
- case 1:
- _scene->_rails.disableNode(1);
- _scene->_rails.disableNode(2);
- _scene->_rails.disableNode(3);
- _scene->_rails.disableNode(4);
- _scene->_rails.disableNode(5);
- _scene->_rails.disableNode(6);
- _scene->_rails.disableNode(7);
- _scene->_rails.disableNode(9);
- _scene->_rails.disableNode(10);
- _scene->_rails.disableNode(11);
- break;
-
- case 2:
- _scene->_rails.disableNode(1);
- _scene->_rails.disableNode(2);
- _scene->_rails.disableNode(5);
- _scene->_rails.disableNode(6);
- _scene->_rails.disableNode(7);
- _scene->_rails.disableNode(9);
- _scene->_rails.disableNode(10);
- _scene->_rails.disableNode(11);
- break;
-
- case 3:
- _scene->_rails.disableNode(1);
- _scene->_rails.disableNode(2);
- _scene->_rails.disableNode(3);
- _scene->_rails.disableNode(4);
- _scene->_rails.disableNode(10);
- _scene->_rails.disableNode(11);
- break;
-
- default:
- break;
- }
-}
-
-void Scene103::handleJacquesAnim() {
- if (_scene->getAnimFrame(_globals._animationIndexes[0]) == _lastJacquesFrame)
- return;
-
- _lastJacquesFrame = _scene->getAnimFrame(_globals._animationIndexes[0]);
- int resetFrame = -1;
- int random;
-
- switch (_lastJacquesFrame) {
- case 1:
- case 2:
- case 3:
- case 9:
- case 17:
- case 23:
- case 33:
- case 51:
- switch (_jacquesAction) {
- case 2:
- random = 4;
- _jacquesAction = 0;
- break;
-
- case 3:
- random = 5;
- _jacquesAction = 0;
- break;
-
- case 4:
- random = 6;
- break;
-
- case 0:
- random = _vm->getRandomNumber(1, 3);
- ++_talkCount;
- if (_talkCount > 22) {
- _jacquesAction = 1;
- random = 9;
- }
- break;
-
- default:
- random = _vm->getRandomNumber(6, 50);
- while (_lastRandom == random)
- random = _vm->getRandomNumber(6, 50);
-
- _lastRandom = random;
- break;
- }
-
- switch (random) {
- case 1:
- resetFrame = 0;
- break;
-
- case 2:
- resetFrame = 1;
- break;
-
- case 3:
- resetFrame = 2;
- break;
-
- case 4:
- resetFrame = 4;
- break;
-
- case 5:
- resetFrame = 10;
- break;
-
- case 6:
- resetFrame = 34;
- break;
-
- case 7:
- resetFrame = 24;
- break;
-
- case 8:
- resetFrame = 18;
- break;
-
- default:
- resetFrame = 8;
- break;
- }
- break;
-
- case 36:
- case 40:
- case 48:
- switch (_jacquesAction) {
- case 0:
- case 2:
- case 3:
- random = 2;
- break;
-
- case 4:
- random = 1;
- _jacquesAction = 0;
- break;
-
- default:
- random = _vm->getRandomNumber(2, 50);
- while (_lastRandom == random)
- random = _vm->getRandomNumber(2, 50);
- _lastRandom = random;
- break;
- }
-
- switch (random) {
- case 1:
- resetFrame = 37;
- break;
-
- case 2:
- resetFrame = 49;
- break;
-
- case 3:
- resetFrame = 41;
- break;
-
- default:
- resetFrame = 35;
- break;
- }
- break;
-
- case 44:
- random = _vm->getRandomNumber(1, 50);
- while (_lastRandom == random)
- random = _vm->getRandomNumber(1, 50);
-
- _lastRandom = random;
-
- switch (_jacquesAction) {
- case 0:
- case 2:
- case 3:
- case 4:
- random = 1;
- break;
-
- default:
- random = _vm->getRandomNumber(1, 50);
- while (_lastRandom == random)
- random = _vm->getRandomNumber(1, 50);
- _lastRandom = random;
- break;
- }
-
- switch (random) {
- case 1:
- resetFrame = 45;
- break;
-
- default:
- resetFrame = 43;
- break;
- }
- break;
-
- default:
- break;
- }
-
- if (resetFrame >= 0) {
- _scene->setAnimFrame(_globals._animationIndexes[0], resetFrame);
- _lastJacquesFrame = resetFrame;
- }
-}
-
-void Scene103::climbRightStairs() {
- if (_scene->getAnimFrame(_globals._animationIndexes[3]) == _lastStairFrame)
- return;
-
- _lastStairFrame = _scene->getAnimFrame(_globals._animationIndexes[3]);
- int stairsResetFrame = -1;
-
- if (_lastStairFrame == 37) {
- stairsResetFrame = 36;
- _standPosition = 2;
- _game._player._stepEnabled = true;
- }
-
- if (_lastStairFrame == 2) {
- _scene->deleteSequence(3);
- _globals._sequenceIndexes[3] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[3], false, 1);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 13);
- _scene->_sequences.setPosition(_globals._sequenceIndexes[3], Common::Point(154, 139));
- }
-
- if (stairsResetFrame >= 0) {
- _scene->setAnimFrame(_globals._animationIndexes[3], stairsResetFrame);
- _lastStairFrame = stairsResetFrame;
- }
-}
-
-void Scene103::climbLeftStairs() {
- if (_scene->getAnimFrame(_globals._animationIndexes[5]) == _lastStairFrame)
- return;
-
- _lastStairFrame = _scene->getAnimFrame(_globals._animationIndexes[5]);
- int stairsResetFrame = -1;
-
- if (_lastStairFrame == 34) {
- stairsResetFrame = 33;
- _standPosition = 1;
- _game._player._stepEnabled = true;
- }
-
- if (_lastStairFrame == 2) {
- _scene->deleteSequence(3);
- _globals._sequenceIndexes[3] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[3], false, 1);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 13);
- _scene->_sequences.setPosition(_globals._sequenceIndexes[3], Common::Point(37, 139));
- }
-
- if (stairsResetFrame >= 0) {
- _scene->setAnimFrame(_globals._animationIndexes[5], stairsResetFrame);
- _lastStairFrame = stairsResetFrame;
- }
-}
-
-void Scene103::descendRightStairs() {
- if (_scene->getAnimFrame(_globals._animationIndexes[4]) == _lastStairFrame)
- return;
-
- _lastStairFrame = _scene->getAnimFrame(_globals._animationIndexes[4]);
-
- if (_lastStairFrame == 2) {
- _scene->deleteSequence(3);
- _globals._sequenceIndexes[3] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[3], false, 1);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 4);
- _scene->_sequences.setPosition(_globals._sequenceIndexes[3], Common::Point(154, 139));
- }
-}
-
-void Scene103::descendLeftStairs() {
- if (_scene->getAnimFrame(_globals._animationIndexes[6]) == _lastStairFrame)
- return;
-
- _lastStairFrame = _scene->getAnimFrame(_globals._animationIndexes[6]);
-
- if (_lastStairFrame == 2) {
- _scene->deleteSequence(3);
- _globals._sequenceIndexes[3] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[3], false, 1);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 4);
- _scene->_sequences.setPosition(_globals._sequenceIndexes[3], Common::Point(37, 139));
- }
-}
-
-void Scene103::process_conv_jacques() {
- bool quitConversationFl = false;
-
- switch (_action._activeAction._verbId) {
- case 1:
- _vm->_gameConv->setInterlocutorTrigger(96);
- if (_globals[kJacquesNameIsKnown] == 0) {
- _globals[kJacquesNameIsKnown] = 1;
- _scene->_dynamicHotspots.remove(_hotspotGentleman);
- _hotspotGentleman = _scene->_dynamicHotspots.add(NOUN_JACQUES, VERB_WALKTO, SYNTAX_SINGULAR_MASC, EXT_NONE, Common::Rect(156, 116, 156 + 33, 116 + 31));
- _scene->_dynamicHotspots[_hotspotGentleman]._articleNumber = PREP_ON;
- _scene->_dynamicHotspots.setPosition(_hotspotGentleman, Common::Point(206, 148), FACING_NORTHWEST);
- }
- break;
-
- case 4:
- case 6:
- case 7:
- case 10:
- case 19:
- case 30: {
- _globals[kWalkerConverse] = 0;
- int *val = _vm->_gameConv->getVariable(26);
- if (*val)
- _globals[kJacquesNameIsKnown] = 2;
-
- quitConversationFl = true;
- }
- break;
-
- case 8:
- _vm->_gameConv->setInterlocutorTrigger(94);
- break;
-
- case 12:
- _vm->_gameConv->setInterlocutorTrigger(96);
- break;
-
- case 29:
- _vm->_gameConv->setInterlocutorTrigger(98);
- break;
-
- default:
- break;
- }
-
- if ((_action._activeAction._verbId != 1) && (_action._activeAction._verbId != 8)
- && (_action._activeAction._verbId != 12) && (_action._activeAction._verbId != 29))
- _vm->_gameConv->setInterlocutorTrigger(90);
-
- _vm->_gameConv->setHeroTrigger(92);
-
- switch (_game._trigger) {
- case 90:
- if (!quitConversationFl)
- _globals[kWalkerConverse] = _vm->getRandomNumber(1, 4);
- _jacquesAction = 0;
- break;
-
- case 92:
- if (!quitConversationFl)
- _globals[kWalkerConverse] = _vm->getRandomNumber(2, 3);
- _convCount = 0;
- _jacquesAction = 1;
- break;
-
- case 94:
- if (!quitConversationFl)
- _globals[kWalkerConverse] = _vm->getRandomNumber(1, 4);
- _jacquesAction = 2;
- break;
-
- case 96:
- if (!quitConversationFl)
- _globals[kWalkerConverse] = _vm->getRandomNumber(1, 4);
- _jacquesAction = 3;
- break;
-
- case 98:
- if (!quitConversationFl)
- _globals[kWalkerConverse] = _vm->getRandomNumber(1, 4);
- _jacquesAction = 4;
- break;
-
- default:
- break;
- }
-
- _talkCount = 0;
-}
-
-/*------------------------------------------------------------------------*/
-
-Scene104::Scene104(MADSEngine *vm) : Scene1xx(vm) {
- _anim0ActvFl = _anim1ActvFl = _anim2ActvFl = false;
- _needToTalk = false;
- _needToGetUp = false;
- _sittingUp = false;
- _beforeHeLeaves = false;
- _beforeSheLeaves = false;
- _needToStandUp = false;
-
- _walkStatus = -1;
- _walkFrame = -1;
- _coupleStatus = -1;
- _richStatus = -1;
- _richTalkCount = -1;
- _manTalkCount = -1;
- _womanTalkCount = -1;
- _lookCount = -1;
- _coupleFrame = -1;
- _lastPlayerFrame = -1;
- _richFrame = -1;
-}
-
-void Scene104::synchronize(Common::Serializer &s) {
- Scene1xx::synchronize(s);
-
- s.syncAsByte(_anim0ActvFl);
- s.syncAsByte(_anim1ActvFl);
- s.syncAsByte(_anim2ActvFl);
- s.syncAsByte(_needToTalk);
- s.syncAsByte(_needToGetUp);
- s.syncAsByte(_sittingUp);
- s.syncAsByte(_beforeHeLeaves);
- s.syncAsByte(_beforeSheLeaves);
- s.syncAsByte(_needToStandUp);
-
- s.syncAsSint16LE(_walkStatus);
- s.syncAsSint16LE(_walkFrame);
- s.syncAsSint16LE(_coupleStatus);
- s.syncAsSint16LE(_richStatus);
- s.syncAsSint16LE(_richTalkCount);
- s.syncAsSint16LE(_manTalkCount);
- s.syncAsSint16LE(_womanTalkCount);
- s.syncAsSint16LE(_lookCount);
- s.syncAsSint16LE(_coupleFrame);
- s.syncAsSint16LE(_lastPlayerFrame);
-}
-
-void Scene104::setup() {
- setPlayerSpritesPrefix();
- setAAName();
-
- if (_globals[kTrapDoorStatus] == 1)
- _scene->_variant = 1;
-
- _scene->addActiveVocab(NOUN_MONSIEUR_RICHARD);
-}
-
-void Scene104::enter() {
- _vm->_disableFastwalk = true;
-
- if (_scene->_priorSceneId != RETURNING_FROM_LOADING) {
- _anim0ActvFl = false;
- _anim1ActvFl = false;
- _anim2ActvFl = false;
- _needToTalk = false;
- _needToGetUp = false;
- _sittingUp = false;
- _beforeSheLeaves = false;
- _needToStandUp = false;
- }
-
- _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('a', 0));
- _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('a', 6));
- _globals._spriteIndexes[0] = _scene->_sprites.addSprites(formAnimName('x', 0));
-
- if (_globals[kCurrentYear] == 1993)
- _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('z', 0));
-
- _vm->_gameConv->load(7);
-
- if (_globals[kTrapDoorStatus] == 1) {
- _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, 1);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 15);
- } else {
- _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, 2);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 15);
- }
-
- if (_scene->_priorSceneId == RETURNING_FROM_LOADING) {
- if (_vm->_gameConv->restoreRunning() == 7) {
- _globals._animationIndexes[1] = _scene->loadAnimation(formAnimName('r', 1), 1);
- _globals._animationIndexes[2] = _scene->loadAnimation(formAnimName('d', 1), 1);
- _walkStatus = 0;
- _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('m', 1), 1);
- if (_coupleStatus < 11) {
- _coupleStatus = 1;
- _richStatus = 0;
- _scene->setAnimFrame(_globals._animationIndexes[1], 14);
- } else {
- _coupleStatus = 17;
- _richStatus = 4;
- _scene->setAnimFrame(_globals._animationIndexes[1], 105);
- _scene->setAnimFrame(_globals._animationIndexes[0], 216);
- }
-
- _vm->_gameConv->run(7);
- _vm->_gameConv->exportPointer(&_globals[kPlayerScore]);
- _game._player._visible = false;
- }
-
- } else if (_scene->_priorSceneId == 301) {
- _globals._animationIndexes[1] = _scene->loadAnimation(formAnimName('r', 1), 1);
- _anim1ActvFl = true;
- _coupleStatus = 11;
-
- _globals._animationIndexes[2] = _scene->loadAnimation(formAnimName('d', 1), 1);
- _anim2ActvFl = true;
- _walkStatus = 0;
-
- _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('m', 1), 1);
- _anim0ActvFl = true;
- _richStatus = 0;
-
- cleanInventory();
-
- _game._player._visible = false;
- _game._visitedScenes.pop_back();
- _globals[kTrapDoorStatus] = 1;
- _globals[kCurrentYear] = 1881;
- _globals[kPrompterStandStatus] = 1;
- _globals[kTicketPeoplePresent] = 1;
- _globals[kMakeBrieLeave203] = false;
- _game._player._playerPos.x = 161;
-
- _game._visitedScenes.add(301);
- _game._visitedScenes.add(101);
-
- _scene->setCamera(Common::Point(60, 0));
- _scene->_sequences.addTimer(1, 91);
-
- } else if (_scene->_priorSceneId == 103) {
- if (_globals[kRoom103104Transition] == 0) {
- _scene->_userInterface.emptyConversationList();
- _scene->_userInterface.setup(kInputConversation);
-
- if (!_globals[kObservedPhan104]) {
- _globals._animationIndexes[4] = _scene->loadAnimation(formAnimName('p', 1), 93);
- _game._player._playerPos.x = 319;
- _game._player._stepEnabled = false;
- _game._player._visible = false;
- _scene->setCamera(Common::Point(158, 0));
- } else {
- _globals._animationIndexes[5] = _scene->loadAnimation(formAnimName('p', 2), 94);
- _game._player._playerPos.x = 319;
- _game._player._stepEnabled = false;
- _game._player._visible = false;
- _scene->setCamera(Common::Point(158, 0));
- }
- } else {
- _game._player._playerPos = Common::Point(319, 96);
- _game._player._facing = FACING_SOUTH;
- _scene->setCamera(Common::Point(158, 0));
- }
- } else if (_scene->_priorSceneId == 102) {
- switch (_globals[kDeathLocation]) {
- case 0:
- _game._player._playerPos = Common::Point(496, 79);
- _scene->setCamera(Common::Point(320, 0));
- break;
-
- case 1:
- _game._player._playerPos = Common::Point(346, 71);
- _scene->setCamera(Common::Point(158, 0));
- break;
-
- case 2:
- _game._player._playerPos = Common::Point(172, 73);
- break;
-
- default:
- break;
- }
- } else if (_scene->_priorSceneId == 108) {
- if (_game._player._playerPos.x > 213)
- _game._player._playerPos.y = 97;
- else if (_game._player._playerPos.x > 110)
- _game._player._playerPos.y = 128;
- else
- _game._player._playerPos.y = 148;
-
- _game._player.firstWalk(Common::Point(-20, _game._player._playerPos.y), FACING_EAST, Common::Point(12, _game._player._playerPos.y), FACING_EAST, true);
- } else if ((_scene->_priorSceneId == 107) || (_scene->_priorSceneId != RETURNING_FROM_LOADING)) {
- if (_game._player._playerPos.x > 191)
- _game._player._playerPos.y = 142;
- else if (_game._player._playerPos.x > 104)
- _game._player._playerPos.y = 120;
- else
- _game._player._playerPos.y = 95;
-
- _game._player.firstWalk(Common::Point(655, _game._player._playerPos.y), FACING_WEST, Common::Point(627, _game._player._playerPos.y), FACING_WEST, true);
- _scene->setCamera(Common::Point(320, 0));
- }
-
- if (_globals[kCurrentYear] == 1993) {
- _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, 1);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 14);
- } else
- _scene->_hotspots.activate(NOUN_CHANDELIER, false);
-
- if (_globals[kTrapDoorStatus] == 1) {
- _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, 1);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 15);
- } else {
- _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, 2);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 15);
- }
-
- sceneEntrySound();
-}
-
-void Scene104::step() {
- if (_anim0ActvFl)
- handleRichAnimations();
-
- if (_anim1ActvFl)
- handleCoupleAnimations();
-
- if (_anim2ActvFl)
- handleWalkAnimation();
-
- if (_game._player._moving)
- handlePlayerWalk();
-
- if (_game._trigger == 91) {
- _vm->_dialogs->show(10434);
- _vm->_gameConv->run(7);
- _vm->_gameConv->exportPointer(&_globals[kPlayerScore]);
- }
-
- if (_game._trigger == 93) {
- _scene->_nextSceneId = 103;
- _game._player._playerPos.x = 400;
- _globals[kRoom103104Transition] = 0;
- }
-
- if (_game._trigger == 94) {
- _scene->_nextSceneId = 103;
- _globals[kRoom103104Transition] = 0;
- }
-}
-
-void Scene104::preActions() {
- if (_action.isAction(VERB_EXIT, NOUN_STAGE_LEFT))
- _game._player._walkOffScreenSceneId = 108;
-
- if (_action.isAction(VERB_EXIT, NOUN_STAGE_RIGHT))
- _game._player._walkOffScreenSceneId = 107;
-
- if (_action.isAction(VERB_OPEN, NOUN_TRAP_DOOR) || _action.isAction(VERB_CLOSE, NOUN_TRAP_DOOR))
- _game._player.walk(Common::Point(320, 92), FACING_NORTH);
-}
-
-void Scene104::actions() {
- if (_vm->_gameConv->activeConvId() == 7) {
- processConversations();
- _action._inProgress = false;
- return;
- }
-
- if (_action.isAction(VERB_CLIMB_THROUGH, NOUN_TRAP_DOOR)) {
- if (_globals[kTrapDoorStatus] == 0) {
- switch (_game._trigger) {
- case 0:
- _game._player._visible = false;
- _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 8, 1);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 13);
- _scene->_sequences.setAnimRange(_globals._sequenceIndexes[1], 1, 16);
- _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 60);
- break;
-
- case 60:
- _scene->_nextSceneId = 103;
- _globals[kRoom103104Transition] = 1;
- _game._player._stepEnabled = true;
- break;
-
- default:
- break;
- }
- } else {
- _vm->_dialogs->show(10429);
- }
- _action._inProgress = false;
- return;
- }
-
- if (_action.isAction(VERB_JUMP_INTO, NOUN_ORCHESTRA_PIT)) {
- switch (_game._trigger) {
- case 0:
- if (_game._player._playerPos.x > 400)
- _globals[kDeathLocation] = 0;
- else if (_game._player._playerPos.x > 200)
- _globals[kDeathLocation] = 1;
- else
- _globals[kDeathLocation] = 2;
-
- _scene->changeVariant(2);
-
- if (_globals[kTrapDoorStatus] == 1)
- _scene->drawToBackground(_globals._spriteIndexes[0], 1, Common::Point(-32000, -32000), 0, 100);
- else
- _scene->drawToBackground(_globals._spriteIndexes[0], 2, Common::Point(-32000, -32000), 0, 100);
-
- _vm->_dialogs->show(10426);
- _game._player._visible = false;
- _game._player._stepEnabled = false;
- _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 7, 1);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 15);
- _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], -1, 4);
- _scene->_sequences.setPosition(_globals._sequenceIndexes[3], _game._player._playerPos);
- _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[3], true);
- _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
- break;
-
- case 1:
- _globals._sequenceIndexes[3] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[3], false, 1, 10);
- _scene->_sequences.addTimer(60, 2);
- _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 4, 4);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 15);
- _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[3], true);
- _scene->_sequences.setMotion(_globals._sequenceIndexes[3], 0, 0, 200);
- break;
-
- case 2:
- _vm->_sound->command(1);
- _vm->_sound->command(67);
- _scene->_nextSceneId = 102;
- break;
-
- default:
- break;
- }
- _action._inProgress = false;
- return;
- }
-
- if (_action._lookFlag) {
- if (_globals[kCurrentYear] == 1993)
- _vm->_dialogs->show(10410);
- else
- _vm->_dialogs->show(10411);
-
- _action._inProgress = false;
- return;
- }
-
- if (_action.isAction(VERB_LOOK) || _action.isAction(VERB_LOOK_AT)) {
- if (_action.isObject(NOUN_STAGE)) {
- _vm->_dialogs->show(10412);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_APRON)) {
- _vm->_dialogs->show(10413);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_PROSCENIUM_ARCH)) {
- _vm->_dialogs->show(10414);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_ACT_CURTAIN)) {
- _vm->_dialogs->show(10415);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_ORCHESTRA_PIT)) {
- _vm->_dialogs->show(10416);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_CONDUCTORS_STAND)) {
- _vm->_dialogs->show(10417);
- _action._inProgress = false;
- return;
- }
-
- if ((_action.isObject(NOUN_MUSIC_STAND)) || (_action.isObject(NOUN_MUSIC_STANDS))) {
- _vm->_dialogs->show(10418);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_PROMPTERS_BOX)) {
- _vm->_dialogs->show(10419);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_TRAP_DOOR)) {
- _vm->_dialogs->show(10420);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_HOUSE)) {
- if (_globals[kCurrentYear] == 1881)
- _vm->_dialogs->show(10421);
- else
- _vm->_dialogs->show(10427);
-
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_STAGE_LEFT)) {
- _vm->_dialogs->show(10422);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_STAGE_RIGHT)) {
- _vm->_dialogs->show(10423);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_CHANDELIER)) {
- _vm->_dialogs->show(10428);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_MONSIEUR_RICHARD)) {
- _vm->_dialogs->show(10433);
- _action._inProgress = false;
- return;
- }
- }
-
- if (_action.isAction(VERB_JUMP_INTO, NOUN_ORCHESTRA_PIT)) {
- _vm->_dialogs->show(10426);
- _scene->_nextSceneId = 102;
- _action._inProgress = false;
- return;
- }
-
- if (_action.isAction(VERB_OPEN, NOUN_PROMPTERS_BOX) || _action.isAction(VERB_CLOSE, NOUN_PROMPTERS_BOX)) {
- _vm->_dialogs->show(10430);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isAction(VERB_OPEN, NOUN_TRAP_DOOR)) {
- if (_globals[kTrapDoorStatus] == 0)
- _vm->_dialogs->show(10424);
- else
- _vm->_dialogs->show(10432);
-
- _action._inProgress = false;
- return;
- }
-
- if (_action.isAction(VERB_CLOSE, NOUN_TRAP_DOOR)) {
- if (_globals[kTrapDoorStatus] == 1)
- _vm->_dialogs->show(10425);
- else
- _vm->_dialogs->show(10433);
-
- _action._inProgress = false;
- return;
- }
-
- if (_action.isAction(VERB_TAKE, NOUN_CHANDELIER)) {
- _vm->_dialogs->show(10435);
- _action._inProgress = false;
- return;
- }
-}
-
-void Scene104::cleanInventory() {
- if (_game._objects.isInInventory(OBJ_LARGE_NOTE))
- _game._objects.setRoom(OBJ_LARGE_NOTE, NOWHERE);
-
- if (_game._objects.isInInventory(OBJ_SANDBAG))
- _game._objects.setRoom(OBJ_SANDBAG, NOWHERE);
-
- if (_game._objects.isInInventory(OBJ_SMALL_NOTE))
- _game._objects.setRoom(OBJ_SMALL_NOTE, NOWHERE);
-
- if (_game._objects.isInInventory(OBJ_PARCHMENT))
- _game._objects.setRoom(OBJ_PARCHMENT, NOWHERE);
-
- if (_game._objects.isInInventory(OBJ_BOOK))
- _game._objects.setRoom(OBJ_BOOK, NOWHERE);
-
- if (_game._objects.isInInventory(OBJ_RED_FRAME))
- _game._objects.setRoom(OBJ_RED_FRAME, 105);
-
- if (_game._objects.isInInventory(OBJ_YELLOW_FRAME))
- _game._objects.setRoom(OBJ_YELLOW_FRAME, 107);
-
- if (_game._objects.isInInventory(OBJ_BLUE_FRAME))
- _game._objects.setRoom(OBJ_BLUE_FRAME, 302);
-
- if (_game._objects.isInInventory(OBJ_GREEN_FRAME))
- _game._objects.setRoom(OBJ_GREEN_FRAME, 307);
-}
-
-void Scene104::processConversations() {
- bool interlocutorTriggerFl = false;
- bool heroTriggerFl = false;
-
- switch (_action._activeAction._verbId) {
- case 2:
- case 10:
- case 12:
- case 16:
- case 20:
- case 21:
- case 24:
- _vm->_gameConv->setInterlocutorTrigger(75);
- interlocutorTriggerFl = true;
- break;
-
- case 3:
- if (!_needToGetUp) {
- _vm->_gameConv->setInterlocutorTrigger(67);
- interlocutorTriggerFl = true;
- _needToGetUp = true;
- }
- break;
-
- case 8:
- _vm->_gameConv->setInterlocutorTrigger(87);
- interlocutorTriggerFl = true;
- break;
-
- case 11:
- _vm->_gameConv->setInterlocutorTrigger(77);
- interlocutorTriggerFl = true;
- break;
-
- case 14:
- case 25:
- if (!_game._trigger) {
- _richStatus = 0;
- _coupleStatus = 5;
- _vm->_gameConv->hold();
- }
- break;
-
- case 22:
- _vm->_gameConv->setInterlocutorTrigger(75);
- _vm->_gameConv->setHeroTrigger(79);
- interlocutorTriggerFl = true;
- heroTriggerFl = true;
- break;
-
- case 23:
- _vm->_gameConv->setInterlocutorTrigger(89);
- interlocutorTriggerFl = true;
- break;
-
- case 28:
- _vm->_gameConv->setInterlocutorTrigger(81);
- interlocutorTriggerFl = true;
- break;
-
- case 30:
- if (!_game._trigger) {
- _vm->_gameConv->hold();
- _richStatus = 4;
- }
- break;
-
- case 32:
- _coupleStatus = 14;
- heroTriggerFl = true;
- interlocutorTriggerFl = true;
- _vm->_gameConv->hold();
- break;
-
- default:
- break;
- }
-
- switch (_game._trigger) {
- case 67:
- _vm->_gameConv->hold();
- _coupleStatus = 12;
- break;
-
- case 69:
- if (!_beforeSheLeaves && !_beforeHeLeaves && (_coupleStatus != 14) && !_needToStandUp) {
- _richStatus = 0;
- if (_sittingUp)
- _coupleStatus = 4;
- else
- _coupleStatus = 12;
- }
- break;
-
- case 71:
- if (!_beforeSheLeaves && !_beforeHeLeaves && (_coupleStatus != 14) && !_needToStandUp) {
- _richStatus = 0;
- if (_sittingUp && !_beforeSheLeaves) {
- _coupleStatus = 3;
- _richStatus = 0;
- }
- }
- break;
-
- case 75:
- _richStatus = 1;
-
- if (_sittingUp) {
- if (_action._activeAction._verbId == 20) {
- _lookCount = 0;
- _coupleStatus = 9;
- } else if ((_action._activeAction._verbId == 21) || (_action._activeAction._verbId == 22)) {
- _lookCount = 0;
- _coupleStatus = 10;
- } else {
- _coupleStatus = 1;
- }
- } else {
- _coupleStatus = 11;
- }
- break;
-
- case 77:
- _richStatus = 0;
- _coupleStatus = 8;
- break;
-
- case 79:
- _richStatus = 0;
- _coupleStatus = 7;
- break;
-
- case 81:
- _richStatus = 1;
- _beforeHeLeaves = true;
- _coupleStatus = 15;
- break;
-
- case 83:
- _vm->_gameConv->release();
- if (_coupleStatus != 17)
- _game._player._stepEnabled = false;
- break;
-
- case 87:
- _richStatus = 3;
- break;
-
- case 89:
- _richStatus = 2;
- break;
-
- default:
- break;
- }
-
- if (!heroTriggerFl && !_beforeSheLeaves)
- _vm->_gameConv->setHeroTrigger(71);
-
- if (!interlocutorTriggerFl)
- _vm->_gameConv->setInterlocutorTrigger(69);
-
- _richTalkCount = 0;
- _manTalkCount = 0;
- _womanTalkCount = 0;
-}
-
-void Scene104::handleWalkAnimation() {
- if (_scene->_animation[_globals._animationIndexes[2]]->getCurrentFrame() == _walkFrame)
- return;
-
- _walkFrame = _scene->_animation[_globals._animationIndexes[2]]->getCurrentFrame();
- int daaeResetFrame = -1;
-
- switch (_walkFrame) {
- case 1:
- if (_walkStatus == 0) {
- daaeResetFrame = 0;
- } else {
- _game.syncTimers(SYNC_ANIM, _globals._animationIndexes[2], SYNC_ANIM, _globals._animationIndexes[1]);
- daaeResetFrame = 1;
- }
- break;
-
- case 138:
- _walkStatus = 0;
- daaeResetFrame = 0;
- break;
-
- default:
- break;
- }
-
- if (daaeResetFrame >= 0) {
- _scene->setAnimFrame(_globals._animationIndexes[2], daaeResetFrame);
- _walkFrame = daaeResetFrame;
- }
-}
-
-void Scene104::handleRichAnimations() {
- if (_scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame() == _richFrame)
- return;
-
- _richFrame = _scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame();
- int random;
- int resetFrame = -1;
-
- switch (_richFrame) {
- case 1:
- case 2:
- case 3:
- case 4:
- case 8:
- case 14:
- case 22:
- case 34:
- case 40:
- case 44:
- case 48:
- random = -1;
- if (_richStatus == 1) {
- random = _vm->getRandomNumber(1, 3);
- ++_richTalkCount;
- if (_richTalkCount > 15) {
- _richStatus = 0;
- random = 40;
- }
- }
-
- if (_richStatus == 0)
- random = _vm->getRandomNumber(7, 80);
-
- if (_richStatus == 2) {
- random = 4;
- _richStatus = 1;
- _richTalkCount = 8;
- }
-
- if (_richStatus == 3) {
- random = 5;
- _richStatus = 1;
- _richTalkCount = 8;
- }
-
- if (_richStatus == 4)
- random = 6;
-
- if (_richStatus == 5)
- random = 7;
-
- switch (random) {
- case 1:
- resetFrame = 1;
- break;
-
- case 2:
- resetFrame = 2;
- break;
-
- case 3:
- resetFrame = 3;
- break;
-
- case 4:
- resetFrame = 23;
- break;
-
- case 5:
- resetFrame = 35;
- break;
-
- case 6:
- resetFrame = 49;
- break;
-
- case 7:
- resetFrame = 41;
- break;
-
- case 8:
- resetFrame = 45;
- break;
-
- case 9:
- resetFrame = 9;
- break;
-
- case 10:
- resetFrame = 5;
- break;
-
- case 11:
- resetFrame = 15;
- break;
-
- default:
- resetFrame = 0;
- break;
- }
- break;
-
- case 117:
- _coupleStatus = 13;
- break;
-
- case 125:
- resetFrame = 124;
- break;
-
- default:
- break;
- }
-
- if (resetFrame >= 0) {
- _scene->setAnimFrame(_globals._animationIndexes[0], resetFrame);
- _richFrame = resetFrame;
- }
-}
-
-void Scene104::handleCoupleAnimations() {
- if (_scene->_animation[_globals._animationIndexes[1]]->getCurrentFrame() == _coupleFrame)
- return;
-
- _coupleFrame = _scene->_animation[_globals._animationIndexes[1]]->getCurrentFrame();
- int resetFrame = -1;
- int random;
-
- switch (_coupleFrame) {
- case 1:
- case 103:
- case 104:
- case 105:
- if (_coupleStatus == 11)
- resetFrame = 0;
- else {
- resetFrame = _vm->getRandomNumber(102, 104);
- ++_womanTalkCount;
- if (_womanTalkCount > 15) {
- if (_needToGetUp) {
- _coupleStatus = 6;
- resetFrame = 1;
- } else {
- _coupleStatus = 11;
- resetFrame = 0;
- }
- }
- }
- break;
-
- case 9:
- case 10:
- case 11:
- case 12:
- case 13:
- case 14:
- case 15:
- case 25:
- case 33:
- case 41:
- switch (_coupleFrame) {
- case 9:
- _coupleStatus = 6;
- break;
-
- case 33:
- _vm->_gameConv->release();
- if (_action._activeAction._verbId == 13)
- _coupleStatus = 4;
-
- break;
-
- case 41:
- _vm->_gameConv->release();
- _sittingUp = true;
- if (_needToTalk)
- _coupleStatus = 3;
- else
- _coupleStatus = 1;
- break;
-
- default:
- break;
- }
-
- random = -1;
-
- switch (_coupleStatus) {
- case 1:
- random = 12;
- break;
-
- case 2:
- case 7:
- case 8:
- random = 11;
- break;
-
- case 3:
- random = _vm->getRandomNumber(4, 6);
- ++_manTalkCount;
- if (_manTalkCount > 15) {
- _coupleStatus = 1;
- random = 12;
- }
- break;
-
- case 4:
- if (_beforeSheLeaves) {
- random = 10;
- } else {
- random = _vm->getRandomNumber(1, 3);
- ++_womanTalkCount;
- if (_womanTalkCount > 15) {
- _coupleStatus = 1;
- random = 12;
- }
- }
- break;
-
- case 5:
- _coupleStatus = 1;
- random = 8;
- break;
-
- case 6:
- _coupleStatus = 1;
- random = 7;
- break;
-
- case 13:
- random = 9;
- break;
-
- case 15:
- random = 10;
- break;
-
- default:
- break;
- }
-
- switch (random) {
- case 1:
- resetFrame = 12;
- break;
-
- case 2:
- resetFrame = 13;
- break;
-
- case 3:
- resetFrame = 14;
- break;
-
- case 4:
- resetFrame = 9;
- break;
-
- case 5:
- resetFrame = 10;
- break;
-
- case 6:
- resetFrame = 11;
- break;
-
- case 7:
- resetFrame = 33;
- break;
-
- case 8:
- resetFrame = 25;
- break;
-
- case 9:
- resetFrame = 54;
- break;
-
- case 10:
- resetFrame = 41;
- break;
-
- case 11:
- resetFrame = 15;
- break;
-
- case 12:
- resetFrame = 14;
- break;
-
- default:
- break;
- }
- break;
-
- case 17:
- case 18:
- case 19:
- case 20:
- case 21:
- case 22:
- case 23:
- random = -1;
- switch (_coupleStatus) {
- case 1:
- case 3:
- case 4:
- case 5:
- case 6:
- case 15:
- case 16:
- random = 7;
- break;
-
- case 2:
- random = 8;
- break;
-
- case 7:
- random = _vm->getRandomNumber(4, 6);
- ++_manTalkCount;
- if (_manTalkCount > 15) {
- _coupleStatus = 2;
- random = 8;
- }
- break;
-
- case 8:
- random = _vm->getRandomNumber(1, 3);
- ++_womanTalkCount;
- if (_womanTalkCount > 15) {
- _coupleStatus = 1;
- random = 7;
- }
- break;
-
- case 9:
- random = 1;
- ++_lookCount;
- if (_lookCount > 6) {
- _coupleStatus = 1;
- random = 7;
- }
- break;
-
- case 10:
- random = 1;
- break;
-
- default:
- break;
- }
-
- switch (random) {
- case 1:
- resetFrame = 20;
- break;
-
- case 2:
- resetFrame = 21;
- break;
-
- case 3:
- resetFrame = 22;
- break;
-
- case 4:
- resetFrame = 17;
- break;
-
- case 5:
- resetFrame = 18;
- break;
-
- case 6:
- resetFrame = 19;
- break;
-
- case 7:
- resetFrame = 23;
- break;
-
- case 8:
- resetFrame = 20;
- break;
-
- default:
- break;
- }
- break;
-
- case 52:
- _walkStatus = 1;
- resetFrame = 54;
- break;
-
- case 55:
- if (_coupleStatus != 13)
- resetFrame = 54;
-
- break;
-
- case 89:
- _vm->_gameConv->release();
- break;
-
- case 90:
- if (_coupleStatus != 14) {
- resetFrame = 89;
- } else {
- resetFrame = 90;
- _globals[kTempVar] = 200;
- }
- break;
-
- case 102:
- _vm->_gameConv->release();
- _game._player._playerPos = Common::Point(166, 126);
- _game._player.resetFacing(FACING_SOUTH);
- resetFrame = 105;
- _game._player._visible = true;
- _game.syncTimers(SYNC_PLAYER, 0, SYNC_ANIM, _globals._animationIndexes[1]);
- break;
-
- case 106:
- _coupleStatus = 17;
- resetFrame = 105;
- break;
-
- default:
- break;
- }
-
- if (resetFrame >= 0) {
- _scene->setAnimFrame(_globals._animationIndexes[1], resetFrame);
- _coupleFrame = resetFrame;
- }
-}
-
-void Scene104::handlePlayerWalk() {
- if (_game._player._frameNumber == _lastPlayerFrame)
- return;
-
- _lastPlayerFrame = _game._player._frameNumber;
- switch (_game._player._facing) {
- case FACING_NORTH:
- case FACING_SOUTH:
- if ((_game._player._frameNumber == 5) || (_game._player._frameNumber == 11))
- _vm->_sound->command(68);
- break;
-
- case FACING_NORTHEAST:
- case FACING_NORTHWEST:
- case FACING_SOUTHEAST:
- case FACING_SOUTHWEST:
- if ((_game._player._frameNumber == 7) || (_game._player._frameNumber == 14))
- _vm->_sound->command(68);
- break;
-
- case FACING_EAST:
- case FACING_WEST:
- if ((_game._player._frameNumber == 8) || (_game._player._frameNumber == 16))
- _vm->_sound->command(68);
- break;
-
- default:
- break;
- }
-}
-
-/*------------------------------------------------------------------------*/
-
-Scene105::Scene105(MADSEngine *vm) : Scene1xx(vm) {
-}
-
-void Scene105::synchronize(Common::Serializer &s) {
- Scene1xx::synchronize(s);
-
-}
-
-void Scene105::setup() {
- if (_globals[kCurrentYear] == 1993)
- _scene->_variant = 1;
-
- setPlayerSpritesPrefix();
- setAAName();
-
- _scene->addActiveVocab(NOUN_LIGHT_FIXTURE);
-}
-
-void Scene105::enter() {
- _scene->loadSpeech(8);
-
- _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('x', 2));
- _globals._spriteIndexes[4] = _scene->_sprites.addSprites(formAnimName('x', 3));
- _globals._spriteIndexes[5] = _scene->_sprites.addSprites("*RRD_9");
- _globals._spriteIndexes[6] = _scene->_sprites.addSprites("*RDR_9");
- _globals._spriteIndexes[7] = _scene->_sprites.addSprites(formAnimName('a', 0));
- _globals._spriteIndexes[8] = _scene->_sprites.addSprites(formAnimName('a', 1));
- if (_globals[kCurrentYear] == 1993)
- _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('z', -1));
-
- if ((_globals[kCurrentYear] == 1881) && (!_globals[kHintThatDaaeIsHome2])) {
- if ((_globals[kJacquesNameIsKnown] == 2) && (_globals[kMadameNameIsKnown] == 2) &&
- _globals[kPanelIn206] && _globals[kDoneRichConv203] && _game._objects.isInInventory(OBJ_LANTERN) &&
- ((_game._objects.isInInventory(OBJ_CABLE_HOOK) && _game._objects.isInInventory(OBJ_ROPE)) || _game._objects.isInInventory(OBJ_ROPE_WITH_HOOK))) {
- _globals[kHintThatDaaeIsHome2] = true;
- _scene->_sequences.addTimer(300, 75);
- }
- }
-
- if ((_game._objects.isInRoom(OBJ_LANTERN)) && (_globals[kCurrentYear] == 1881)) {
- _globals._spriteIndexes[0] = _scene->_sprites.addSprites(formAnimName('x', 0));
- _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, 1);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 14);
- } else {
- _scene->_hotspots.activate(NOUN_LANTERN, false);
- }
-
- if (_game._objects.isInRoom(OBJ_RED_FRAME)) {
- _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('x', 1));
- _globals._sequenceIndexes[1] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[1], false, 1);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 14);
- } else {
- _scene->_hotspots.activate(NOUN_RED_FRAME, false);
- }
-
- if (_globals[kCurrentYear] == 1993) {
- _scene->drawToBackground(_globals._spriteIndexes[3], 1, Common::Point(-32000, -32000), 0, 100);
- _scene->_hotspots.activate(NOUN_PROPS, false);
- _scene->_hotspots.activate(NOUN_BEAR_PROP, false);
- _scene->_hotspots.activate(NOUN_STAIR_UNIT, false);
- _scene->_hotspots.activate(NOUN_PROP, false);
- _scene->_hotspots.activate(NOUN_ELEPHANT_PROP, false);
- _scene->_hotspots.activate(NOUN_COLUMN_PROP, false);
-
- int tmpIdx = _scene->_dynamicHotspots.add(NOUN_COLUMN_PROP, VERB_WALKTO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(132, 24, 132 + 21, 24 + 105));
- _scene->_dynamicHotspots.setPosition(tmpIdx, Common::Point(159, 133), FACING_NORTHWEST);
-
- tmpIdx = _scene->_dynamicHotspots.add(NOUN_COLUMN_PROP, VERB_WALKTO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(56, 45, 56 + 11, 45 + 77));
- _scene->_dynamicHotspots.setPosition(tmpIdx, Common::Point(72, 126), FACING_NORTHWEST);
-
- _scene->_dynamicHotspots.add(NOUN_PROP, VERB_WALKTO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(0, 125, 29, 125 + 31));
- _scene->_dynamicHotspots.add(NOUN_PROP, VERB_WALKTO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(29, 136, 29 + 50, 136 + 20));
- _scene->_dynamicHotspots.add(NOUN_PROP, VERB_WALKTO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(79, 141, 79 + 53, 141 + 15));
-
- _scene->_dynamicHotspots.add(NOUN_BEAR_PROP, VERB_WALKTO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(278, 132, 278 + 21, 132 + 24));
- _scene->_dynamicHotspots.add(NOUN_BEAR_PROP, VERB_WALKTO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(299, 146, 299 + 8, 146 + 10));
- _scene->_dynamicHotspots.add(NOUN_BEAR_PROP, VERB_WALKTO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(269, 142, 269 + 8, 142 + 8));
-
- _scene->_dynamicHotspots.add(NOUN_LIGHT_FIXTURE, VERB_LOOK_AT, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(102, 14, 102 + 24, 102 + 10));
- }
-
- _globals._sequenceIndexes[4] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[4], false, 2);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 14);
-
- if ((_scene->_priorSceneId == 106) || (_scene->_priorSceneId == 114)) {
- _game._player._playerPos = Common::Point(198, 132);
- _game._player._facing = FACING_WEST;
- _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, 1);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 10);
- } else if ((_scene->_priorSceneId == 103) || (_scene->_priorSceneId != RETURNING_FROM_LOADING)) {
- _game._player._playerPos = Common::Point(3, 112);
- _game._player._facing = FACING_SOUTHEAST;
- _game._player.walk(Common::Point(45, 131), FACING_SOUTHEAST);
- _game._player.setWalkTrigger(60);
- _game._player._stepEnabled = false;
- _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, 8);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 10);
- } else if (_scene->_priorSceneId == RETURNING_FROM_LOADING) {
- _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, -1);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 10);
- }
-
- sceneEntrySound();
-}
-
-void Scene105::step() {
- switch (_game._trigger) {
- case 60:
- _scene->deleteSequence(_globals._sequenceIndexes[2]);
- _globals._sequenceIndexes[2] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[2], false, 8, 1);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 10);
- _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], 1, 8);
- _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 61);
- _vm->_sound->command(66);
- break;
-
- case 61:
- _vm->_sound->command(25);
- _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, 1);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 10);
- _game._player._stepEnabled = true;
- break;
-
- case 75:
- _scene->playSpeech(8);
- _scene->_sequences.addTimer(120, 76);
- break;
-
- case 76:
- _vm->_dialogs->show(10537);
- break;
-
- default:
- break;
- }
-}
-
-void Scene105::actions() {
- if ((_action.isAction(VERB_PUSH, NOUN_THUNDER_MACHINE)) || (_action.isAction(VERB_PULL, NOUN_THUNDER_MACHINE))) {
- switch (_game._trigger) {
- case 0:
- _game._player._stepEnabled = false;
- _game._player._visible = false;
- _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('t', 1), 70);
- _scene->deleteSequence(_globals._sequenceIndexes[4]);
- _game.syncTimers(SYNC_SEQ, _globals._sequenceIndexes[4], SYNC_ANIM, _globals._animationIndexes[0]);
- _scene->_sequences.setSeqPlayer(_globals._animationIndexes[0], false);
- break;
-
- case 70:
- _globals._sequenceIndexes[4] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[4], false, 2);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 14);
- _game.syncTimers(SYNC_SEQ, _globals._sequenceIndexes[4], SYNC_ANIM, _globals._animationIndexes[0]);
- _game._player._stepEnabled = true;
- _game._player._visible = true;
- _game.syncTimers(SYNC_PLAYER, 0, SYNC_ANIM, _globals._animationIndexes[0]);
- break;
-
- default:
- break;
- }
- _action._inProgress = false;
- return;
- }
-
- if (_action.isAction(VERB_CLIMB_UP, NOUN_CIRCULAR_STAIRCASE)) {
- switch (_game._trigger) {
- case 0:
- _game._player._stepEnabled = false;
- _game._player._visible = false;
- _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('u', 1), 1);
- _game.syncTimers(SYNC_ANIM, _globals._animationIndexes[0], SYNC_PLAYER, 0);
- break;
-
- case 1:
- _scene->_nextSceneId = 106;
- break;
-
- default:
- break;
- }
- _action._inProgress = false;
- return;
- }
-
- if (_action.isAction(VERB_CLIMB_DOWN, NOUN_CIRCULAR_STAIRCASE)) {
- switch (_game._trigger) {
- case 0:
- _game._player._stepEnabled = false;
- _game._player._visible = false;
- _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('d', 1), 1);
- _game.syncTimers(SYNC_ANIM, _globals._animationIndexes[0], SYNC_PLAYER, 0);
- break;
-
- case 1:
- _scene->_nextSceneId = 114;
- break;
-
- default:
- break;
- }
- _action._inProgress = false;
- return;
- }
-
- if (_action.isAction(VERB_TAKE, NOUN_RED_FRAME) && (_game._objects.isInRoom(OBJ_RED_FRAME) || _game._trigger)) {
- switch (_game._trigger) {
- case (0):
- if (_globals[kCurrentYear] == 1881) {
- int count = 0;
-
- if (_game._objects.isInInventory(NOUN_YELLOW_FRAME))
- ++count;
-
- if (_game._objects.isInInventory(NOUN_GREEN_FRAME))
- ++count;
-
- if (_game._objects.isInInventory(NOUN_BLUE_FRAME))
- ++count;
-
- if (count < 3)
- _globals[kPlayerScore] += 5;
- }
-
- _game._player._stepEnabled = false;
- _game._player._visible = false;
- _globals._sequenceIndexes[5] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[5], true, 5, 2);
- _scene->_sequences.setAnimRange(_globals._sequenceIndexes[5], 1, 5);
- _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[5], true);
- _scene->_sequences.addSubEntry(_globals._sequenceIndexes[5], SEQUENCE_TRIGGER_SPRITE, 5, 1);
- _scene->_sequences.addSubEntry(_globals._sequenceIndexes[5], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
- break;
-
- case 1:
- _scene->deleteSequence(_globals._sequenceIndexes[1]);
- _scene->_hotspots.activate(NOUN_RED_FRAME, false);
- _game._objects.addToInventory(OBJ_RED_FRAME);
- _vm->_sound->command(26);
- break;
-
- case 2:
- _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[5]);
- _game._player._visible = true;
- _scene->_sequences.addTimer(20, 3);
- break;
-
- case 3:
- if (_globals[kCurrentYear] == 1881)
- _vm->_dialogs->showItem(OBJ_RED_FRAME, 842, 0);
- else
- _vm->_dialogs->showItem(OBJ_RED_FRAME, 802, 0);
-
- _game._player._stepEnabled = true;
- break;
-
- default:
- break;
- }
- _action._inProgress = false;
- return;
- }
-
- if (_action.isAction(VERB_TAKE, NOUN_LANTERN) && (_game._objects.isInRoom(OBJ_LANTERN) || _game._trigger)) {
- switch (_game._trigger) {
- case (0):
- _globals[kPlayerScore] += 5;
- _game._player._stepEnabled = false;
- _game._player._visible = false;
- _globals._sequenceIndexes[6] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[6], true, 5, 2);
- _scene->_sequences.setAnimRange(_globals._sequenceIndexes[6], 1, 4);
- _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[6], true);
- _scene->_sequences.addSubEntry(_globals._sequenceIndexes[6], SEQUENCE_TRIGGER_SPRITE, 4, 1);
- _scene->_sequences.addSubEntry(_globals._sequenceIndexes[6], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
- break;
-
- case 1:
- _scene->deleteSequence(_globals._sequenceIndexes[0]);
- _scene->_hotspots.activate(NOUN_LANTERN, false);
- _game._objects.addToInventory(OBJ_LANTERN);
- _vm->_sound->command(26);
- break;
-
- case 2:
- _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[6]);
- _game._player._visible = true;
- _scene->_sequences.addTimer(20, 3);
- break;
-
- case 3:
- _vm->_dialogs->showItem(OBJ_LANTERN, 801, 0);
- _game._player._stepEnabled = true;
- break;
-
- default:
- break;
- }
- _action._inProgress = false;
- return;
- }
-
- if (_action.isAction(VERB_WALK_THROUGH, NOUN_DOOR) || _action.isAction(VERB_OPEN, NOUN_DOOR) || (_game._trigger) ||
- _action.isAction(VERB_UNLOCK, NOUN_DOOR) || _action.isAction(VERB_LOCK, NOUN_DOOR)) {
- if ((_globals[kCurrentYear] == 1881) && !_action.isAction(VERB_UNLOCK) && !_action.isAction(VERB_LOCK)){
- switch (_game._trigger) {
- case (0):
- _game._player._stepEnabled = false;
- _game._player._visible = false;
- _globals._sequenceIndexes[6] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[6], true, 5, 2);
- _scene->_sequences.setAnimRange(_globals._sequenceIndexes[6], 1, 4);
- _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[6], true);
- _scene->_sequences.addSubEntry(_globals._sequenceIndexes[6], SEQUENCE_TRIGGER_SPRITE, 4, 65);
- _scene->_sequences.addSubEntry(_globals._sequenceIndexes[6], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
- break;
-
- case 2:
- _game._player._visible = true;
- _scene->_sequences.addTimer(180, 3);
- break;
-
- case 3:
- _scene->_nextSceneId = 103;
- break;
-
- case 65:
- _vm->_sound->command(24);
- _scene->deleteSequence(_globals._sequenceIndexes[2]);
- _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 8, 1);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 14);
- _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], 1, 8);
- _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 66);
- _vm->_sound->command(66);
- break;
-
- case 66: {
- int tmpIdx = _globals._sequenceIndexes[2];
- _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, 8);
- _game.syncTimers(SYNC_SEQ, _globals._sequenceIndexes[2], SYNC_SEQ, tmpIdx);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 14);
- _game._player.walk(Common::Point(0, 111), FACING_NORTHWEST);
- }
- break;
-
- default:
- break;
- }
- } else {
- switch (_game._trigger) {
- case (0):
- _game._player._stepEnabled = false;
- _game._player._visible = false;
- _globals._sequenceIndexes[6] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[6], true, 5, 1);
- _scene->_sequences.setAnimRange(_globals._sequenceIndexes[6], 1, 4);
- _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[6], true);
- _scene->_sequences.addSubEntry(_globals._sequenceIndexes[6], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
- break;
-
- case 1: {
- int tmpIdx = _globals._sequenceIndexes[6];
- _globals._sequenceIndexes[6] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[6], true, 4);
- _game.syncTimers(SYNC_SEQ, _globals._sequenceIndexes[6], SYNC_SEQ, tmpIdx);
- _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[6], false);
- _vm->_sound->command(73);
- _scene->_sequences.addTimer(15, 2);
- }
- break;
-
- case 2:
- _scene->deleteSequence(_globals._sequenceIndexes[6]);
- _globals._sequenceIndexes[6] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[6], true, 5, 1);
- _scene->_sequences.setAnimRange(_globals._sequenceIndexes[6], 1, 4);
- _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[6], false);
- _scene->_sequences.addSubEntry(_globals._sequenceIndexes[6], SEQUENCE_TRIGGER_EXPIRE, 0, 3);
- break;
-
- case 3:
- _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[6]);
- _game._player._visible = true;
- if (_action.isAction(VERB_LOCK) || _action.isAction(VERB_UNLOCK))
- _vm->_dialogs->show(32);
- else
- _vm->_dialogs->show(10536);
-
- _game._player._stepEnabled = true;
- break;
-
- default:
- break;
- }
- }
- _action._inProgress = false;
- return;
- }
-
- if (_action._lookFlag) {
- if (_globals[kCurrentYear] == 1993)
- _vm->_dialogs->show(10510);
- else
- _vm->_dialogs->show(10511);
-
- _action._inProgress = false;
- return;
- }
-
- if (_action.isAction(VERB_LOOK) || _action.isAction(VERB_LOOK_AT)) {
- if (_action.isObject(NOUN_FLOOR)) {
- _vm->_dialogs->show(10512);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_CIRCULAR_STAIRCASE)) {
- _vm->_dialogs->show(10513);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_LANTERN) && _game._objects.isInRoom(OBJ_LANTERN)) {
- _vm->_dialogs->show(10514);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_RED_FRAME) && _game._objects.isInRoom(OBJ_RED_FRAME)){
- if (_globals[kCurrentYear] == 1881)
- _vm->_dialogs->show(10530);
- else
- _vm->_dialogs->show(10515);
-
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_DOOR)) {
- _vm->_dialogs->show(10516);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_WALL)) {
- _vm->_dialogs->show(10517);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_PROP_TABLE)) {
- _vm->_dialogs->show(10518);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_BEAR_PROP)) {
- if (_globals[kCurrentYear] == 1993)
- _vm->_dialogs->show(10519);
- else
- _vm->_dialogs->show(10538);
-
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_ELEPHANT_PROP)) {
- _vm->_dialogs->show(10520);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_COLUMN_PROP)) {
- if (_globals[kCurrentYear] == 1993)
- _vm->_dialogs->show(10521);
- else
- _vm->_dialogs->show(10539);
-
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_THUNDER_MACHINE)) {
- if (_globals[kCurrentYear] == 1993)
- _vm->_dialogs->show(10522);
- else
- _vm->_dialogs->show(10540);
-
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_STAIR_UNIT)) {
- _vm->_dialogs->show(10523);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_PROP)) {
- _vm->_dialogs->show(10524);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_PROPS)) {
- _vm->_dialogs->show(10525);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_EXIT_SIGN)) {
- _vm->_dialogs->show(10526);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_FLATS)) {
- _vm->_dialogs->show(10527);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_HEMP)) {
- _vm->_dialogs->show(10528);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_PIPE)) {
- _vm->_dialogs->show(10529);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_GRAFFITI)) {
- _vm->_dialogs->show(10531);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_LIGHT_FIXTURE)) {
- _vm->_dialogs->show(10535);
- _action._inProgress = false;
- return;
- }
- }
-
- if (_action.isAction(VERB_TALK_TO, NOUN_BEAR_PROP)) {
- _vm->_dialogs->show(10532);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isAction(VERB_TAKE, NOUN_BEAR_PROP)) {
- _vm->_dialogs->show(10533);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isAction(VERB_CLOSE, NOUN_DOOR)) {
- _vm->_dialogs->show(10534);
- _action._inProgress = false;
- return;
- }
-}
-
-void Scene105::preActions() {
- if (_action.isAction(VERB_WALK_THROUGH, NOUN_DOOR_TO_PIT))
- _game._player._walkOffScreenSceneId = 102;
-
- if (_action.isAction(VERB_OPEN, NOUN_DOOR) || _action.isAction(VERB_UNLOCK, NOUN_DOOR) || _action.isAction(VERB_LOCK, NOUN_DOOR))
- _game._player.walk(Common::Point(33, 128), FACING_NORTHWEST);
-}
-
-/*------------------------------------------------------------------------*/
-
-Scene106::Scene106(MADSEngine *vm) : Scene1xx(vm) {
- _sandbagHostpotId = -1;
-}
-
-void Scene106::synchronize(Common::Serializer &s) {
- Scene1xx::synchronize(s);
-
- s.syncAsSint16LE(_sandbagHostpotId);
-}
-
-void Scene106::setup() {
- if (_globals[kCurrentYear] == 1881)
- _scene->_variant = 1;
-
- setPlayerSpritesPrefix();
- setAAName();
-}
-
-void Scene106::enter() {
- _scene->loadSpeech(8);
-
- if (_globals[kCurrentYear] == 1993) {
- if (!_game._objects.isInInventory(OBJ_SANDBAG)) {
- _globals._spriteIndexes[5] = _scene->_sprites.addSprites("*RRD_9");
- _globals._spriteIndexes[0] = _scene->_sprites.addSprites(formAnimName('x', 0));
- }
- } else {
- _globals._spriteIndexes[7] = _scene->_sprites.addSprites(formAnimName('z', -1));
- if (_game._objects.isInRoom(OBJ_CABLE_HOOK) && !_game._objects.isInInventory(OBJ_ROPE_WITH_HOOK)) {
- _globals._spriteIndexes[5] = _scene->_sprites.addSprites("*RRD_9");
- _globals._spriteIndexes[8] = _scene->_sprites.addSprites(formAnimName('p', 0));
- }
- }
-
- _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('a', 0));
- _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('x', 1));
- _globals._spriteIndexes[3] = _scene->_sprites.addSprites("*RDR_9");
- _globals._spriteIndexes[4] = _scene->_sprites.addSprites(formAnimName('a', 1));
- _globals._spriteIndexes[6] = _scene->_sprites.addSprites(formAnimName('a', 2));
-
- if ((_globals[kCurrentYear] == 1881) && (!_globals[kHintThatDaaeIsHome1])) {
- if ((_globals[kJacquesNameIsKnown] == 2) && (_globals[kMadameNameIsKnown] == 2)
- && (_globals[kPanelIn206]) && (_globals[kDoneRichConv203]) && (_game._objects.isInInventory(OBJ_LANTERN))
- && ((_game._objects.isInInventory(OBJ_CABLE_HOOK) && _game._objects.isInInventory(OBJ_ROPE))
- || _game._objects.isInInventory(OBJ_ROPE_WITH_HOOK))) {
- _globals[kHintThatDaaeIsHome1] = true;
- _scene->_sequences.addTimer(300, 85);
- }
- }
-
- if ((_globals[kSandbagStatus] == 1) && (_globals[kCurrentYear] == 1993) && _game._objects.isInRoom(OBJ_SANDBAG)) {
- _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, -2);
- _sandbagHostpotId = _scene->_dynamicHotspots.add(NOUN_SANDBAG, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(227, 140, 227 + 18, 140 + 11));
- _scene->_dynamicHotspots.setPosition(_sandbagHostpotId, Common::Point(224, 152), FACING_NORTHEAST);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 2);
- }
-
- if (_globals[kCurrentYear] == 1881) {
- _scene->drawToBackground(_globals._spriteIndexes[7], 1, Common::Point(-32000, -32000), 0, 100);
- _scene->_hotspots.activate(NOUN_BIG_PROP, false);
- _scene->_hotspots.activate(NOUN_STATUE, false);
- _scene->_hotspots.activate(NOUN_PLANT_PROP, false);
- _scene->_hotspots.activate(NOUN_PEDESTAL, false);
- _scene->_hotspots.activate(NOUN_SANDBAG, false);
- _scene->_hotspots.activate(NOUN_CRATE, false);
-
- _scene->_dynamicHotspots.add(NOUN_SANDBAG, VERB_LOOK_AT, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(40, 47, 40 + 11, 47 + 17));
- _scene->_dynamicHotspots.add(NOUN_SANDBAG, VERB_LOOK_AT, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(98, 14, 98 + 5, 14 + 10));
- _scene->_dynamicHotspots.add(NOUN_SANDBAG, VERB_LOOK_AT, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(111, 23, 111 + 6, 23 + 9));
- _scene->_dynamicHotspots.add(NOUN_SANDBAG, VERB_LOOK_AT, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(119, 12, 119 + 5, 12 + 8));
-
- int idx = _scene->_dynamicHotspots.add(NOUN_STAGE, VERB_WALK_ACROSS, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(80, 114, 80 + 24, 114 + 4));
- _scene->_dynamicHotspots.setPosition(idx, Common::Point(93, 121), FACING_NONE);
-
- idx = _scene->_dynamicHotspots.add(NOUN_STAGE, VERB_WALK_ACROSS, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(106, 102, 106 + 5, 102 + 10));
- _scene->_dynamicHotspots.setPosition(idx, Common::Point(108, 109), FACING_NONE);
- } else {
- _scene->_hotspots.activate(NOUN_BOXES, false);
- _scene->_hotspots.activate(NOUN_CASE, false);
- }
-
- if ((_game._objects.isInRoom(OBJ_CABLE_HOOK)) && (_globals[kCurrentYear] == 1881) && !_game._objects.isInInventory(OBJ_ROPE_WITH_HOOK)){
- _globals._sequenceIndexes[8] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[8], false, 1);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[8], 3);
- } else {
- _scene->_hotspots.activate(NOUN_CABLE_HOOK, false);
- }
-
- if (_scene->_priorSceneId == 109) {
- _game._player._playerPos = Common::Point(180, 58);
- _game._player._facing = FACING_SOUTH;
- _game._player.walk(Common::Point(179, 63), FACING_SOUTH);
- _game._player.setWalkTrigger(60);
- _game._player._stepEnabled = false;
- _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, 5);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 14);
- } else if ((_scene->_priorSceneId == 105) || (_scene->_priorSceneId == 301)) {
- _game._player._playerPos = Common::Point(235, 142);
- _game._player._facing = FACING_WEST;
- _game._player.walk(Common::Point(227, 143), FACING_WEST);
- _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, 1);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 14);
- } else if (_scene->_priorSceneId == 107) {
- _game._player._playerPos = Common::Point(143, 68);
- _game._player._facing = FACING_WEST;
- _game._player.walk(Common::Point(163, 68), FACING_SOUTHEAST);
- _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, 1);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 14);
- } else if ((_scene->_priorSceneId == 108) || (_scene->_priorSceneId != RETURNING_FROM_LOADING)) {
- _game._player.firstWalk(Common::Point(-20, 130), FACING_SOUTHEAST, Common::Point(19, 147), FACING_NORTHEAST, true);
- _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, 1);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 14);
- } else if (_scene->_priorSceneId == RETURNING_FROM_LOADING) {
- _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, -1);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 14);
- }
-
- sceneEntrySound();
-}
-
-void Scene106::step() {
- switch (_game._trigger) {
- case 85:
- _scene->playSpeech(8);
- _scene->_sequences.addTimer(120, 86);
- break;
-
- case 86:
- _vm->_dialogs->show(10637);
- break;
-
- case 60:
- _scene->deleteSequence(_globals._sequenceIndexes[2]);
- _globals._sequenceIndexes[2] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[2], false, 8, 1);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 14);
- _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], 1, 5);
- _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 61);
- break;
-
- case 61:
- _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, 1);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 14);
- _vm->_sound->command(25);
- _game._player._stepEnabled = true;
- break;
-
- default:
- break;
- }
-}
-
-void Scene106::actions() {
- if ((_action.isAction(VERB_TAKE, NOUN_SANDBAG)) && (_scene->_customDest.y < 61)) {
- _vm->_dialogs->show(10635);
- _action._inProgress = false;
- return;
- } else if (_action.isAction(VERB_TAKE, NOUN_SANDBAG)) {
- if (_game._objects.isInRoom(OBJ_SANDBAG)) {
- switch (_game._trigger) {
- case (0):
- _game._player._stepEnabled = false;
- _game._player._visible = false;
- _globals._sequenceIndexes[5] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[5], false, 5, 2);
- _scene->_sequences.setAnimRange(_globals._sequenceIndexes[5], 1, 5);
- _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[5], true);
- _scene->_sequences.addSubEntry(_globals._sequenceIndexes[5], SEQUENCE_TRIGGER_SPRITE, 5, 1);
- _scene->_sequences.addSubEntry(_globals._sequenceIndexes[5], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
- break;
-
- case 1:
- _scene->deleteSequence(_globals._sequenceIndexes[0]);
- _scene->_dynamicHotspots.remove(_sandbagHostpotId);
- _vm->_sound->command(26);
- break;
-
- case 2:
- _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[5]);
- _game._player._visible = true;
- _scene->_sequences.addTimer(20, 3);
- break;
-
- case 3:
- _game._objects.addToInventory(OBJ_SANDBAG);
- _vm->_dialogs->showItem(OBJ_SANDBAG, 803, 0);
- _game._player._stepEnabled = true;
- break;
-
- default:
- break;
- }
- _action._inProgress = false;
- return;
- }
- }
-
- if (_action.isAction(VERB_TAKE, NOUN_CABLE_HOOK)) {
- if (_game._objects.isInRoom(OBJ_CABLE_HOOK)) {
- switch (_game._trigger) {
- case (0):
- _game._player._stepEnabled = false;
- _game._player._visible = false;
- _globals._sequenceIndexes[5] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[5], true, 5, 2);
- _scene->_sequences.setAnimRange(_globals._sequenceIndexes[5], 1, 5);
- _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[5], true);
- _scene->_sequences.addSubEntry(_globals._sequenceIndexes[5], SEQUENCE_TRIGGER_SPRITE, 5, 1);
- _scene->_sequences.addSubEntry(_globals._sequenceIndexes[5], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
- _globals[kPlayerScore] += 5;
- break;
-
- case 1:
- _scene->deleteSequence(_globals._sequenceIndexes[8]);
- _scene->_hotspots.activate(NOUN_CABLE_HOOK, false);
- _vm->_sound->command(26);
- break;
-
- case 2:
- _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[5]);
- _game._player._visible = true;
- _scene->_sequences.addTimer(20, 3);
- break;
-
- case 3:
- _game._objects.addToInventory(OBJ_CABLE_HOOK);
- _vm->_dialogs->showItem(OBJ_CABLE_HOOK, 822, 0);
- _game._player._stepEnabled = true;
- break;
-
- default:
- break;
- }
- _action._inProgress = false;
- return;
- }
- }
-
- switch (_game._trigger) {
- case 75:
- _game._player._stepEnabled = false;
- _game._player._visible = false;
- _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('d', 1), 76);
- _game.syncTimers(SYNC_ANIM, _globals._animationIndexes[0], SYNC_PLAYER, 0);
- _action._inProgress = false;
- return;
-
- case 76:
- _scene->_nextSceneId = 105;
- _action._inProgress = false;
- return;
-
- case 80:
- _game._player._stepEnabled = false;
- _game._player._visible = false;
- _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('u', 1), 81);
- _game.syncTimers(SYNC_ANIM, _globals._animationIndexes[0], SYNC_PLAYER, 0);
- _action._inProgress = false;
- return;
-
- case 81:
- _scene->_sequences.addTimer(120, 82);
- _action._inProgress = false;
- return;
-
- case 82:
- _scene->_nextSceneId = 301;
- _action._inProgress = false;
- return;
-
- default:
- break;
- }
-
- if (_action.isAction(VERB_EXIT_TO, NOUN_STAGE_RIGHT_WING)) {
- _scene->_nextSceneId = 107;
- _action._inProgress = false;
- return;
- }
-
- if (_action.isAction(VERB_CLIMB_DOWN) || _action.isAction(VERB_CLIMB_UP)) {
- if (_globals[kSandbagStatus] == 1) {
- switch (_game._trigger) {
- case 0:
- _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('s',-1), 1);
- _game._player._stepEnabled = false;
- _game._player._visible = false;
- break;
-
- case 1:
- _game.syncTimers(SYNC_PLAYER, 0, SYNC_ANIM, _globals._animationIndexes[0]);
- _game._player._visible = true;
- _game._player._playerPos = Common::Point(225, 143);
- _game._player.resetFacing(FACING_EAST);
- _game._player.walk(Common::Point(236, 142), FACING_EAST);
-
- if (_action.isAction(VERB_CLIMB_DOWN))
- _game._player.setWalkTrigger(75);
- else
- _game._player.setWalkTrigger(80);
- break;
-
- default:
- break;
- }
- } else {
- switch (_game._trigger) {
- case 0:
- _globals._sequenceIndexes[0] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[0], false, 4, 1);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 2);
- _scene->_sequences.setAnimRange(_globals._sequenceIndexes[0], 1, 9);
- _scene->_sequences.addTimer(6, 2);
- _scene->_sequences.addSubEntry(_globals._sequenceIndexes[0], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
- break;
-
- case 1:
- _vm->_sound->command(70);
- _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, -2);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 2);
- _sandbagHostpotId = _scene->_dynamicHotspots.add(NOUN_SANDBAG, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(227, 140, 227 + 18, 140 + 11));
- _scene->_dynamicHotspots.setPosition(_sandbagHostpotId, Common::Point(224, 152), FACING_NORTHEAST);
- break;
-
- case 2:
- _game._player._stepEnabled = false;
- _game._player._visible = false;
- _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('s', 1), 3);
- _game.syncTimers(SYNC_ANIM, _globals._animationIndexes[0], SYNC_PLAYER, 0);
- break;
-
- case 3:
- _game.syncTimers(SYNC_PLAYER, 0, SYNC_ANIM, _globals._animationIndexes[0]);
- _game._player._visible = true;
- _game._player._stepEnabled = true;
- _game._player._playerPos = Common::Point(228, 140);
- _game._player.resetFacing(FACING_SOUTHEAST);
- _globals[kSandbagStatus] = 1;
- _vm->_dialogs->show(10632);
- break;
-
- default:
- break;
- }
- }
- _action._inProgress = false;
- return;
- }
-
- if (_action.isAction(VERB_WALK_THROUGH, NOUN_DOOR) || _action.isAction(VERB_OPEN, NOUN_DOOR)) {
- switch (_game._trigger) {
- case (0):
- _game._player._stepEnabled = false;
- _game._player._visible = false;
- _globals._sequenceIndexes[3] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[3], false, 5, 2);
- _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 1, 4);
- _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[3], true);
- _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_SPRITE, 4, 65);
- _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 67);
- break;
-
- case 65:
- _vm->_sound->command(24);
- _scene->deleteSequence(_globals._sequenceIndexes[2]);
- _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 8, 1);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 14);
- _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], 1, 5);
- _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 66);
- break;
-
- case 66: {
- int idx = _globals._sequenceIndexes[2];
- _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, 5);
- _game.syncTimers(SYNC_SEQ, _globals._sequenceIndexes[2], SYNC_SEQ, idx);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 14);
- }
- break;
-
- case 67:
- _game._player._visible = true;
- _game._player.walk(Common::Point(180, 60), FACING_NORTH);
- _game._player.setWalkTrigger(68);
- break;
-
- case 68:
- _scene->deleteSequence(_globals._sequenceIndexes[2]);
- _globals._sequenceIndexes[2] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[2], false, 8, 1);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 1);
- _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], -1, -2);
- _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 69);
- break;
-
- case 69:
- _vm->_sound->command(25);
- _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, -1);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 1);
- _scene->_nextSceneId = 109;
- break;
-
- default:
- break;
- }
- _action._inProgress = false;
- return;
- }
-
- if (_action._lookFlag) {
- _vm->_dialogs->show(10610);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isAction(VERB_LOOK) || _action.isAction(VERB_LOOK_AT)) {
- if (_action.isObject(NOUN_STAGE_RIGHT_WING)) {
- _vm->_dialogs->show(10611);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_STAGE_LEFT_WING)) {
- _vm->_dialogs->show(10612);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_IN_TWO)) {
- _vm->_dialogs->show(10613);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_CYCLORAMA)) {
- _vm->_dialogs->show(10614);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_STAGE)) {
- _vm->_dialogs->show(10615);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_PEDESTAL)) {
- _vm->_dialogs->show(10616);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_PLANT_PROP)) {
- _vm->_dialogs->show(10617);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_SANDBAG)) {
- if (_scene->_customDest.y < 60) {
- _vm->_dialogs->show(10618);
- _action._inProgress = false;
- return;
- } else if (_game._objects.isInRoom(OBJ_SANDBAG)) {
- _vm->_dialogs->show(10633);
- _action._inProgress = false;
- return;
- }
- }
-
- if (_action.isObject(NOUN_STATUE)) {
- _vm->_dialogs->show(10619);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_CIRCULAR_STAIRCASE)) {
- _vm->_dialogs->show(10620);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_BATTEN)) {
- _vm->_dialogs->show(10621);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_DOOR)) {
- _vm->_dialogs->show(10622);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_BOXES) || _action.isObject(NOUN_BOX)) {
- _vm->_dialogs->show(10623);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_BIG_PROP)) {
- _vm->_dialogs->show(10624);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_CRATE)) {
- _vm->_dialogs->show(10625);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_CASE)) {
- if (_globals[kCurrentYear] == 1881)
- _vm->_dialogs->show(10638);
- else
- _vm->_dialogs->show(10636);
-
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_VENTILATION_DUCT)) {
- _vm->_dialogs->show(10626);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_JUNK)) {
- _vm->_dialogs->show(10627);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_FLATS)) {
- _vm->_dialogs->show(10628);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_WALL)) {
- _vm->_dialogs->show(10629);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_CABLE_HOOK) && _game._objects.isInRoom(OBJ_CABLE_HOOK)) {
- _vm->_dialogs->show(10639);
- _action._inProgress = false;
- return;
- }
- }
-
- if (_action.isAction(VERB_TALK_TO, NOUN_STATUE)) {
- _vm->_dialogs->show(10630);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isAction(VERB_CLOSE, NOUN_DOOR)) {
- _vm->_dialogs->show(10634);
- _action._inProgress = false;
- return;
- }
-}
-
-void Scene106::preActions() {
- if (_action.isAction(VERB_EXIT_TO, NOUN_STAGE_LEFT_WING))
- _game._player._walkOffScreenSceneId = 108;
-
- if (_action.isAction(VERB_OPEN, NOUN_DOOR))
- _game._player.walk(Common::Point(179, 63), FACING_NORTHWEST);
-}
-
-/*------------------------------------------------------------------------*/
-
-Scene107::Scene107(MADSEngine *vm) : Scene1xx(vm) {
-}
-
-void Scene107::synchronize(Common::Serializer &s) {
- Scene1xx::synchronize(s);
-}
-
-void Scene107::setup() {
- setPlayerSpritesPrefix();
- setAAName();
-}
-
-void Scene107::enter() {
- if (_globals[kCurrentYear] == 1993)
- _globals._spriteIndexes[0] = _scene->_sprites.addSprites(formAnimName('z', -1));
-
- if (_game._objects.isInRoom(OBJ_YELLOW_FRAME)) {
- _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('f', 0));
- _globals._spriteIndexes[1] = _scene->_sprites.addSprites("*RRD_9");
- }
-
- if (_game._objects.isInRoom(OBJ_YELLOW_FRAME)) {
- _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, 1);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 14);
- } else {
- _scene->_hotspots.activate(NOUN_YELLOW_FRAME, false);
- }
-
- if (_globals[kCurrentYear] == 1993) {
- _scene->drawToBackground(_globals._spriteIndexes[0], 1, Common::Point(-32000, -32000), 0, 100);
- _scene->_hotspots.activate(NOUN_PROP_TABLE, false);
- } else {
- _scene->_hotspots.activate(NOUN_HEADSET, false);
- }
-
- if (_scene->_priorSceneId == 106) {
- _game._player._playerPos = Common::Point(276, 73);
- _game._player._facing = FACING_SOUTHWEST;
- _game._player.walk(Common::Point(248, 75), FACING_SOUTHWEST);
- } else if ((_scene->_priorSceneId == 104) || (_scene->_priorSceneId != RETURNING_FROM_LOADING)) {
- if (_game._player._playerPos.y > 128) {
- _game._player._playerPos.x = 216;
- _game._player._facing = FACING_NORTHWEST;
- } else if (_game._player._playerPos.y > 99) {
- _game._player._playerPos.x = 127;
- _game._player._facing = FACING_NORTHWEST;
- } else {
- _game._player._playerPos.x = 44;
- _game._player._facing = FACING_NORTHEAST;
- }
- _game._player._playerPos.y = 143;
- }
-
- sceneEntrySound();
-}
-
-void Scene107::step() {
-}
-
-void Scene107::actions() {
- if (_action.isAction(VERB_WALK_ONTO, NOUN_STAGE)) {
- _scene->_nextSceneId = 104;
- _action._inProgress = false;
- return;
- }
-
- if (_action.isAction(VERB_WALK, NOUN_BACKSTAGE)) {
- _scene->_nextSceneId = 106;
- _action._inProgress = false;
- return;
- }
-
- if (_action.isAction(VERB_TAKE, NOUN_YELLOW_FRAME) && (_game._objects.isInRoom(OBJ_YELLOW_FRAME) || _game._trigger)) {
- switch (_game._trigger) {
- case (0):
- if (_globals[kCurrentYear] == 1881) {
- int count = 0;
- if (_game._objects.isInInventory(OBJ_GREEN_FRAME))
- ++count;
- if (_game._objects.isInInventory(OBJ_RED_FRAME))
- ++count;
- if (_game._objects.isInInventory(OBJ_BLUE_FRAME))
- ++count;
-
- if (count < 3)
- _globals[kPlayerScore] += 5;
- }
-
- _game._player._stepEnabled = false;
- _game._player._visible = false;
- _globals._sequenceIndexes[1] = _scene->_sequences.startPingPongCycle(_globals._spriteIndexes[1], false, 5, 2);
- _scene->_sequences.setAnimRange(_globals._sequenceIndexes[1], 1, 5);
- _scene->_sequences.setSeqPlayer(_globals._sequenceIndexes[1], true);
- _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_SPRITE, 5, 1);
- _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
- break;
-
- case 1:
- _scene->deleteSequence(_globals._sequenceIndexes[2]);
- _scene->_hotspots.activate(NOUN_YELLOW_FRAME, false);
- _game._objects.addToInventory(OBJ_YELLOW_FRAME);
- _vm->_sound->command(26);
- break;
-
- case 2:
- _game.syncTimers(SYNC_PLAYER, 0, SYNC_SEQ, _globals._sequenceIndexes[1]);
- _game._player._visible = true;
- _scene->_sequences.addTimer(20, 3);
- break;
-
- case 3:
- if (_globals[kCurrentYear] == 1881)
- _vm->_dialogs->showItem(OBJ_YELLOW_FRAME, 843, 0);
- else
- _vm->_dialogs->showItem(OBJ_YELLOW_FRAME, 804, 0);
-
- _game._player._stepEnabled = true;
- break;
-
- default:
- break;
- }
- _action._inProgress = false;
- return;
- }
-
- if (_action._lookFlag) {
- _vm->_dialogs->show(10710);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isAction(VERB_LOOK) || _action.isAction(VERB_LOOK_AT)) {
- if (_action.isObject(NOUN_STAGE)) {
- _vm->_dialogs->show(10711);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_IN_TWO)) {
- _vm->_dialogs->show(10712);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_IN_ONE)) {
- _vm->_dialogs->show(10713);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_CYCLORAMA)) {
- _vm->_dialogs->show(10714);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_COUNTERWEIGHT_SYSTEM)) {
- _vm->_dialogs->show(10715);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_PURCHASE_LINES)) {
- _vm->_dialogs->show(10716);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_LOCKRAIL)) {
- _vm->_dialogs->show(10717);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_STAGE)) {
- _vm->_dialogs->show(10718);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_PROP_TABLE)) {
- _vm->_dialogs->show(10719);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_ACT_CURTAIN)) {
- _vm->_dialogs->show(10720);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_LEG)) {
- _vm->_dialogs->show(10721);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_APRON)) {
- _vm->_dialogs->show(10722);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_PROSCENIUM_ARCH)) {
- _vm->_dialogs->show(10723);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_STAGE)) {
- _vm->_dialogs->show(10724);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_BACKSTAGE)) {
- _vm->_dialogs->show(10725);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_YELLOW_FRAME) && _game._objects.isInRoom(OBJ_YELLOW_FRAME)) {
- if (_globals[kCurrentYear] == 1881)
- _vm->_dialogs->show(10727);
- else
- _vm->_dialogs->show(10726);
-
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_HEADSET)) {
- _vm->_dialogs->show(10728);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_WALL)) {
- _vm->_dialogs->show(10730);
- _action._inProgress = false;
- return;
- }
- }
-
- if (_action.isAction(VERB_TAKE, NOUN_HEADSET)) {
- _vm->_dialogs->show(10729);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isAction(VERB_TALK_TO, NOUN_HEADSET)) {
- _vm->_dialogs->show(10732);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isAction(VERB_PULL, NOUN_PURCHASE_LINES)) {
- _vm->_dialogs->show(10731);
- _action._inProgress = false;
- return;
- }
-}
-
-void Scene107::preActions() {
-}
-
-/*------------------------------------------------------------------------*/
-
-Scene108::Scene108(MADSEngine *vm) : Scene1xx(vm) {
- _anim0ActvFl = false;
- _handRaisedFl = false;
- _shutUpCount = -1;
- _maxTalkCount = -1;
- _charAction = -1;
- _charFrame = -1;
- _charHotspotId = -1;
- _charTalkCount = -1;
- _conversationCount = -1;
- _prevShutUpFrame = -1;
-}
-
-void Scene108::synchronize(Common::Serializer &s) {
- Scene1xx::synchronize(s);
-
- s.syncAsByte(_anim0ActvFl);
- s.syncAsByte(_handRaisedFl);
- s.syncAsSint16LE(_shutUpCount);
- s.syncAsSint16LE(_maxTalkCount);
- s.syncAsSint16LE(_charAction);
- s.syncAsSint16LE(_charFrame);
- s.syncAsSint16LE(_charHotspotId);
- s.syncAsSint16LE(_charTalkCount);
- s.syncAsSint16LE(_conversationCount);
- s.syncAsSint16LE(_prevShutUpFrame);
-}
-
-void Scene108::setup() {
- setPlayerSpritesPrefix();
- setAAName();
-
- if (_globals[kCurrentYear] == 1993)
- _scene->_variant = 1;
-
- _scene->addActiveVocab(NOUN_GENTLEMAN);
- _scene->addActiveVocab(NOUN_CHARLES);
-}
-
-void Scene108::enter() {
- if (_scene->_priorSceneId != RETURNING_FROM_LOADING) {
- _anim0ActvFl = false;
- _handRaisedFl = false;
- _charTalkCount = 0;
- _shutUpCount = 40;
- _maxTalkCount = 15;
- }
-
- _vm->_gameConv->load(2);
-
- if (_globals[kCurrentYear] == 1993) {
- _globals._spriteIndexes[0] = _scene->_sprites.addSprites(formAnimName('z', -1));
- _scene->_hotspots.activate(NOUN_STOOL, false);
- int idx = _scene->_dynamicHotspots.add(NOUN_STOOL, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(250, 68, 250 + 8, 68 + 21));
- _scene->_dynamicHotspots[idx]._articleNumber = PREP_ON;
- _scene->_dynamicHotspots.setPosition(idx, Common::Point(253, 75), FACING_SOUTHEAST);
- _scene->drawToBackground(_globals._spriteIndexes[0], 1, Common::Point(-32000, -32000), 0, 100);
- } else {
- _scene->_hotspots.activate(NOUN_HEADSET, false);
- int idx = _scene->_dynamicHotspots.add(NOUN_WALL, VERB_WALK_TO, SYNTAX_SINGULAR, EXT_NONE, Common::Rect(258, 58, 258 + 6, 58 + 10));
- _scene->_dynamicHotspots[idx]._articleNumber = PREP_ON;
- _scene->_dynamicHotspots.setPosition(idx, Common::Point(236, 69), FACING_NORTHEAST);
- }
-
- if ((_globals[kCurrentYear] == 1993) && (_globals[kDoneBrieConv203] == 0)) {
- _globals._animationIndexes[0] = _scene->loadAnimation(formAnimName('c', 1), 1);
- _anim0ActvFl = true;
-
- if (_vm->_gameConv->activeConvId() == 2) {
- _globals[kWalkerConverse] = _vm->getRandomNumber(1, 4);
- _charAction = 0;
- _vm->_gameConv->run(2);
- _vm->_gameConv->exportPointer(&_globals[kPlayerScore]);
- _vm->_gameConv->exportValue(_globals[kJulieNameIsKnown]);
- _vm->_gameConv->exportValue(_globals[kObservedPhan104]);
- _scene->setAnimFrame(_globals._animationIndexes[0], 55);
- _shutUpCount = 40;
- } else {
- _charAction = 2;
- }
-
- if (_globals[kCharlesNameIsKnown]) {
- _charHotspotId = _scene->_dynamicHotspots.add(NOUN_CHARLES, VERB_WALK_TO, SYNTAX_SINGULAR_MASC, EXT_NONE, Common::Rect(253, 52, 253 + 15, 52 + 34));
- _scene->_dynamicHotspots[_charHotspotId]._articleNumber = PREP_ON;
- } else {
- _charHotspotId = _scene->_dynamicHotspots.add(NOUN_GENTLEMAN, VERB_WALK_TO, SYNTAX_MASC_NOT_PROPER, EXT_NONE, Common::Rect(253, 52, 253 + 15, 52 + 34));
- _scene->_dynamicHotspots[_charHotspotId]._articleNumber = PREP_ON;
- }
- _scene->_dynamicHotspots.setPosition(_charHotspotId, Common::Point(235, 102), FACING_NORTHEAST);
- }
-
- if (_scene->_priorSceneId == 106) {
- _game._player._playerPos = Common::Point(48, 81);
- _game._player._facing = FACING_SOUTHEAST;
- _game._player.walk(Common::Point(71, 76), FACING_SOUTHEAST);
- } else if ((_scene->_priorSceneId == 104) || (_scene->_priorSceneId != RETURNING_FROM_LOADING)) {
- if (_game._player._playerPos.y > 128) {
- _game._player._playerPos.x = 124;
- _game._player._facing = FACING_NORTHEAST;
- } else if (_game._player._playerPos.y > 99) {
- _game._player._playerPos.x = 185;
- _game._player._facing = FACING_NORTHEAST;
- } else {
- _game._player._playerPos.x = 243;
- _game._player._facing = FACING_NORTHWEST;
- }
-
- _game._player._playerPos.y = 143;
- }
-
- sceneEntrySound();
-}
-
-void Scene108::step() {
- if (_anim0ActvFl)
- handleCharAnimation();
-
- if ((_globals[kWalkerConverse] == 2) || (_globals[kWalkerConverse] == 3)) {
- ++_conversationCount;
- if (_conversationCount > 200)
- _globals[kWalkerConverse] = _vm->getRandomNumber(1, 4);
- }
-}
-
-void Scene108::actions() {
- if (_vm->_gameConv->activeConvId() == 2) {
- handleCharlesConversation();
- _action._inProgress = false;
- return;
- }
-
- if (_action.isAction(VERB_TALK_TO, NOUN_GENTLEMAN) || _action.isAction(VERB_TALK_TO, NOUN_CHARLES)) {
- _charAction = 6;
- _game._player._stepEnabled = false;
- _action._inProgress = false;
- return;
- }
-
- if (_action.isAction(VERB_WALK_ONTO, NOUN_STAGE)) {
- _scene->_nextSceneId = 104;
- _action._inProgress = false;
- return;
- }
-
- if (_action.isAction(VERB_WALK, NOUN_BACKSTAGE)) {
- _scene->_nextSceneId = 106;
- _action._inProgress = false;
- return;
- }
-
- if (_action._lookFlag) {
- _vm->_dialogs->show(10810);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isAction(VERB_LOOK) || _action.isAction(VERB_LOOK_AT)) {
- if (_action.isObject(NOUN_WALL)) {
- _vm->_dialogs->show(10730);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_STAGE)) {
- _vm->_dialogs->show(10811);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_IN_TWO)) {
- _vm->_dialogs->show(10812);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_IN_ONE)) {
- _vm->_dialogs->show(10813);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_PROSCENIUM_ARCH)) {
- _vm->_dialogs->show(10814);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_ACT_CURTAIN)) {
- _vm->_dialogs->show(10815);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_LEG)) {
- _vm->_dialogs->show(10816);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_CYCLORAMA)) {
- _vm->_dialogs->show(10817);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_FLATS)) {
- _vm->_dialogs->show(10818);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_STAGEMANAGERS_POST)) {
- if (_globals[kCurrentYear] == 1993)
- _vm->_dialogs->show(10819);
- else
- _vm->_dialogs->show(10820);
-
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_STOOL)) {
- _vm->_dialogs->show(10821);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_BACKSTAGE)) {
- _vm->_dialogs->show(10822);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_STAGE)) {
- _vm->_dialogs->show(10823);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_HEADSET)) {
- _vm->_dialogs->show(10824);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_WALL)) {
- _vm->_dialogs->show(10826);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isObject(NOUN_CHARLES) || _action.isObject(NOUN_GENTLEMAN)) {
- _vm->_dialogs->show(10827);
- _action._inProgress = false;
- return;
- }
- }
-
- if (_action.isAction(VERB_TAKE, NOUN_CHARLES) || _action.isAction(VERB_TAKE, NOUN_GENTLEMAN)) {
- _vm->_dialogs->show(10828);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isAction(VERB_TAKE, NOUN_HEADSET)) {
- _vm->_dialogs->show(10825);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isAction(VERB_TAKE, NOUN_STOOL) && (_globals[kCurrentYear] == 1993)) {
- _vm->_dialogs->show(10829);
- _action._inProgress = false;
- return;
- }
-
- if (_action.isAction(VERB_TALK_TO, NOUN_HEADSET)) {
- _vm->_dialogs->show(10830);
- _action._inProgress = false;
- return;
- }
-}
-
-void Scene108::preActions() {
-}
-
-void Scene108::handleCharAnimation() {
- if (_scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame() == _charFrame)
- return;
-
- _charFrame = _scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame();
- int resetFrame = -1;
- int random = -1;
-
- switch (_charFrame) {
- case 1:
- case 2:
- case 3:
- case 4:
- case 92:
- if (_charAction == 2)
- random = _vm->getRandomNumber(2, 15);
-
- if (_charAction == 6) {
- _charTalkCount = 0;
- _charAction = 1;
- random = 1;
- }
-
- switch (random) {
- case 1:
- resetFrame = 5;
- break;
-
- case 2:
- resetFrame = 0;
- break;
-
- case 3:
- resetFrame = 1;
- break;
-
- case 4:
- resetFrame = 2;
- break;
-
- default:
- resetFrame = 3;
- break;
- }
- break;
-
- case 18:
- case 19:
- case 20:
- case 21:
- case 27:
- case 33:
- case 41:
- case 51:
- case 52:
- case 53:
- case 54:
- case 55:
- case 56:
- case 57:
- case 62:
- case 73:
- if (_charFrame == 18) {
- _game._player._stepEnabled = true;
- _vm->_gameConv->run(2);
- _vm->_gameConv->exportPointer(&_globals[kPlayerScore]);
- _vm->_gameConv->exportValue(_globals[kJulieNameIsKnown]);
- _vm->_gameConv->exportValue(_globals[kObservedPhan104]);
- }
-
- if (_charAction == 1) {
- if (_handRaisedFl) {
- random = _vm->getRandomNumber(1, 3);
- } else {
- random = _vm->getRandomNumber(1, 4);
- if (random == 4)
- random = _vm->getRandomNumber(1, 4);
- }
-
- if (random == 4)
- _handRaisedFl = true;
-
- ++_charTalkCount;
- if (_charTalkCount > _maxTalkCount) {
- _charAction = 0;
- _shutUpCount = 0;
- _prevShutUpFrame = 10;
- random = 12;
- }
- } else if (_charAction == 0) {
- int delay = _vm->getRandomNumber(10, 15);
- ++_shutUpCount;
- if (_shutUpCount > delay) {
- random = _vm->getRandomNumber(10, 16);
- _prevShutUpFrame = random;
- if (random == 15)
- _shutUpCount = 16;
- else
- _shutUpCount = 0;
- } else {
- random = _prevShutUpFrame;
- }
- } else if (_charAction == 7) {
- _charAction = 1;
- random = 5;
- } else if (_charAction == 3) {
- _charAction = 1;
- random = 6;
- } else if (_charAction == 5) {
- _charAction = 1;
- random = 7;
- } else if (_charAction == 4) {
- _charAction = 1;
- random = 8;
- } else if (_charAction == 2) {
- random = 9;
- }
-
- switch (random) {
- case 1:
- resetFrame = 18;
- break;
-
- case 2:
- resetFrame = 19;
- break;
-
- case 3:
- resetFrame = 20;
- break;
-
- case 4:
- resetFrame = 62;
- _charTalkCount += 5;
- break;
-
- case 5:
- resetFrame = 21;
- break;
-
- case 6:
- resetFrame = 41;
- break;
-
- case 7:
- resetFrame = 33;
- break;
-
- case 8:
- resetFrame = 27;
- break;
-
- case 9:
- resetFrame = 74;
- break;
-
- case 10:
- resetFrame = 51;
- break;
-
- case 11:
- resetFrame = 53;
- break;
-
- case 12:
- resetFrame = 54;
- break;
-
- case 13:
- resetFrame = 55;
- break;
-
- case 14:
- resetFrame = 56;
- break;
-
- case 15:
- resetFrame = 57;
- break;
-
- case 16:
- resetFrame = 52;
- break;
-
- default:
- break;
- }
- break;
-
- default:
- break;
- }
-
- if (resetFrame >= 0) {
- _scene->setAnimFrame(_globals._animationIndexes[0], resetFrame);
- _charFrame = resetFrame;
- }
-}
-
-void Scene108::handleCharlesConversation() {
- switch (_action._activeAction._verbId) {
- case 1:
- case 25:
- case 26:
- _globals[kWalkerConverse] = 0;
- _vm->_gameConv->setHeroTrigger(64);
- if (_action._activeAction._verbId == 26)
- _globals[kCharlesNameIsKnown] = 2;
- break;
-
- case 2:
- if (!_globals[kCharlesNameIsKnown]) {
- _scene->_dynamicHotspots.remove(_charHotspotId);
- _charHotspotId = _scene->_dynamicHotspots.add(NOUN_CHARLES, VERB_WALK_TO, SYNTAX_SINGULAR_MASC, EXT_NONE, Common::Rect(253, 52, 253 + 15, 52 + 34));
- _scene->_dynamicHotspots[_charHotspotId]._articleNumber = PREP_ON;
- _scene->_dynamicHotspots.setPosition(_charHotspotId, Common::Point(235, 102), FACING_NORTHEAST);
- _globals[kCharlesNameIsKnown] = true;
- }
- break;
-
- case 5:
- _vm->_gameConv->setInterlocutorTrigger(66);
- _maxTalkCount = 35;
- break;
-
- case 6:
- case 8:
- case 9:
- case 10:
- case 11:
- case 12:
- case 15:
- _maxTalkCount = 35;
- break;
-
- case 16:
- _vm->_gameConv->setInterlocutorTrigger(68);
- _maxTalkCount = 35;
- break;
-
- case 19:
- _vm->_gameConv->setInterlocutorTrigger(72);
- break;
-
- case 22:
- _vm->_gameConv->setInterlocutorTrigger(70);
- break;
-
- default:
- _maxTalkCount = 15;
- break;
- }
-
- switch (_game._trigger) {
- case 60:
- _charAction = 1;
- _globals[kWalkerConverse] = _vm->getRandomNumber(1, 4);
- break;
-
- case 62:
- _globals[kWalkerConverse] = _vm->getRandomNumber(2, 3);
- _conversationCount = 0;
- _charAction = 0;
- break;
-
- case 64:
- _charAction = 2;
- break;
-
- case 66:
- _charAction = 5;
- break;
-
- case 68:
- _charAction = 4;
- break;
-
- case 70:
- _charAction = 7;
- break;
-
- case 72:
- _charAction = 3;
- break;
-
- default:
- break;
- }
-
- if ((_action._activeAction._verbId != 1) && (_action._activeAction._verbId != 5) &&
- (_action._activeAction._verbId != 16) && (_action._activeAction._verbId != 19) &&
- (_action._activeAction._verbId != 22) && (_action._activeAction._verbId != 25) &&
- (_action._activeAction._verbId != 26) && (_charAction != 2)) {
- _vm->_gameConv->setInterlocutorTrigger(60);
- _vm->_gameConv->setHeroTrigger(62);
- }
-
- _charTalkCount = 0;
- _shutUpCount = 40;
- _handRaisedFl = false;
-}
-
-/*------------------------------------------------------------------------*/
-
-Scene109::Scene109(MADSEngine *vm) : Scene1xx(vm) {
- _anim0ActvFl = false;
- _anim1ActvFl = false;
- _anim2ActvFl = false;
- _anim3ActvFl = false;
-
- _currentFloor = -1;
-}
-
-void Scene109::synchronize(Common::Serializer &s) {
- Scene1xx::synchronize(s);
-
- s.syncAsByte(_anim0ActvFl);
- s.syncAsByte(_anim1ActvFl);
- s.syncAsByte(_anim2ActvFl);
- s.syncAsByte(_anim3ActvFl);
-
- s.syncAsSint16LE(_currentFloor);
-}
-
-void Scene109::setup() {
- setPlayerSpritesPrefix();
- setAAName();
-}
-
-void Scene109::enter() {
- _anim0ActvFl = false;
- _anim1ActvFl = false;
- _anim2ActvFl = false;
- _anim3ActvFl = false;
-
- _globals._spriteIndexes[0] = _scene->_sprites.addSprites(formAnimName('x', 0));
- _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('x', 2));
- _globals._spriteIndexes[8] = _scene->_sprites.addSprites("*RDR_6");
-
- if (_globals[kCurrentYear] == 1881) {
- _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('x', 1));
- _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('x', 3));
- _globals._spriteIndexes[4] = _scene->_sprites.addSprites(formAnimName('x', 4));
-
- _scene->_hotspots.activate(NOUN_LIGHT_FIXTURE, false);
- _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, 1);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 14);
- _globals._sequenceIndexes[3] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[3], false, 1);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 14);
- _globals._sequenceIndexes[4] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[4], false, 1);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 14);
- _scene->_sequences.addTimer(1, 70);
- } else {
- _globals._spriteIndexes[5] = _scene->_sprites.addSprites(formAnimName('z', 0));
- _globals._spriteIndexes[6] = _scene->_sprites.addSprites(formAnimName('z', 1));
- _globals._spriteIndexes[7] = _scene->_sprites.addSprites(formAnimName('z', 2));
-
- _scene->_hotspots.activate(NOUN_LAMP, false);
- _globals._sequenceIndexes[5] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[5], false, 1);
- _globals._sequenceIndexes[6] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[6], false, 1);
- _globals._sequenceIndexes[7] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[7], false, 1);
- }
-
- if (_scene->_priorSceneId == 106) {
- _game._player._playerPos = Common::Point(31, 459);
- _game._player._facing = FACING_NORTHEAST;
- _scene->setCamera(Common::Point(0, 312));
- _scene->sceneScale(467, 95, 442, 78);
- _currentFloor = 1;
- } else if (_scene->_priorSceneId == 111) {
- if (_globals[kLeaveAngelMusicOn]) {
- _globals[kLeaveAngelMusicOn] = false;
- sceneEntrySound();
- }
- _game._player._playerPos = Common::Point(4, 136);
- _game._player._facing = FACING_EAST;
- _game._player.walk(Common::Point(32, 138), FACING_EAST);
- _game._player.setWalkTrigger(60);
- _game._player._stepEnabled = false;
- _scene->setCamera(Common::Point(0, 0));
- _scene->sceneScale(155, 95, 130, 78);
- _globals._sequenceIndexes[0] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[0], false, 3);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 14);
- _currentFloor = 3;
- } else if ((_scene->_priorSceneId == 110) || (_scene->_priorSceneId != RETURNING_FROM_LOADING)) {
- _game._player._playerPos = Common::Point(3, 292);
- _game._player._facing = FACING_EAST;
- _game._player.walk(Common::Point(31, 295), FACING_EAST);
- _game._player.setWalkTrigger(65);
- _game._player._stepEnabled = false;
- _scene->setCamera(Common::Point(0, 156));
- _scene->sceneScale(311, 95, 286, 78);
- _globals._sequenceIndexes[1] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[1], false, 3);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 14);
- _currentFloor = 2;
- } else if (_scene->_priorSceneId == RETURNING_FROM_LOADING) {
- if (_currentFloor == 2) {
- _scene->setCamera(Common::Point(0, 156));
- _scene->sceneScale(311, 95, 286, 78);
- } else if (_currentFloor == 3) {
- _scene->setCamera(Common::Point(0, 0));
- _scene->sceneScale(155, 95, 130, 78);
- } else {
- _scene->setCamera(Common::Point(0, 312));
- _scene->sceneScale(467, 95, 442, 78);
- }
- }
-
- sceneEntrySound();
-}
-
-void Scene109::step() {
- if (_anim0ActvFl) {
- if (_scene->_animation[_globals._animationIndexes[0]]->getCurrentFrame() == 80)
- _game._camY.camPanTo(156);
- }
-
- if (_anim1ActvFl) {
- if (_scene->_animation[_globals._animationIndexes[1]]->getCurrentFrame() == 80)
- _game._camY.camPanTo(0);
- }
-
- if (_anim2ActvFl) {
- if (_scene->_animation[_globals._animationIndexes[2]]->getCurrentFrame() == 7)
- _game._camY.camPanTo(312);
- }
-
- if (_anim3ActvFl) {
- if (_scene->_animation[_globals._animationIndexes[3]]->getCurrentFrame() == 14)
- _game._camY.camPanTo(156);
- }
-
- switch (_game._trigger) {
- case 60:
- _scene->deleteSequence(_globals._sequenceIndexes[0]);
- _globals._sequenceIndexes[0] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[0], false, 8, 1);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 14);
- _scene->_sequences.setAnimRange(_globals._sequenceIndexes[0], 1, 3);
- _scene->_sequences.addSubEntry(_globals._sequenceIndexes[0], SEQUENCE_TRIGGER_EXPIRE, 0, 61);
- break;
-
- case 61:
- _vm->_sound->command(25);
- _game._player._stepEnabled = true;
- break;
-
- default:
- break;
- }
-
- switch (_game._trigger) {
- case 65:
- _scene->deleteSequence(_globals._sequenceIndexes[1]);
- _globals._sequenceIndexes[1] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[1], false, 8, 1);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 14);
- _scene->_sequences.setAnimRange(_globals._sequenceIndexes[1], 1, 3);
- _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 66);
- break;
-
- case 66:
- _vm->_sound->command(25);
- _game._player._stepEnabled = true;
- break;
-
- default:
- break;
- }
-
- if (_game._trigger == 70) {
- int rndFrame = _vm->getRandomNumber(1, 3);
- int rndDelay = _vm->getRandomNumber(4, 7);
- _scene->deleteSequence(_globals._sequenceIndexes[2]);
- _scene->deleteSequence(_globals._sequenceIndexes[3]);
- _scene->deleteSequence(_globals._sequenceIndexes[4]);
-
- _globals._sequenceIndexes[2] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[2], false, rndFrame);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 14);
-
- _globals._sequenceIndexes[3] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[3], false, rndFrame);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 14);
-
- _globals._sequenceIndexes[4] = _scene->_sequences.addStampCycle(_globals._spriteIndexes[4], false, rndFrame);
- _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 14);
-
- _scene->_sequences.addTimer(rndDelay, 70);
- }
-}
-
-void Scene109::actions() {
- if (_action.isAction(VERB_WALK, NOUN_BACKSTAGE)) {
- _scene->_nextSceneId = 106;
- _action._inProgress = false;
- return;
- }
-
- if (_action.isAction(VERB_CLIMB_UP, NOUN_STAIRCASE)) {
- if (_currentFloor == 2) {
- switch (_game._trigger) {
- case 0:
- _game._player.walk(Common::Point(58, 295), FACING_EAST);
- _game._player.setWalkTrigger(1);
- break;
-
- case 1:
- _anim1ActvFl = true;
- _game._player._stepEnabled = false;
- _game._player._visible = false;
- _globals._animationIndexes[1] = _scene->loadAnimation(formAnimName('w', 2), 2);
- _game.syncTimers(SYNC_ANIM, _globals._animationIndexes[1], SYNC_PLAYER, 0);
- break;
-
- case 2:
- _game.syncTimers(SYNC_PLAYER, 0, SYNC_ANIM, _globals._animationIndexes[1]);
Commit: 8657c269407753b2121aaaa8e7f448670a613509
https://github.com/scummvm/scummvm/commit/8657c269407753b2121aaaa8e7f448670a613509
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:19:03+10:00
Commit Message:
MADS: PHANTOM: Adding main_menu.cpp, dependent headers
Changed paths:
A engines/mads/madsv2/core/anim.h
A engines/mads/madsv2/core/btype.h
A engines/mads/madsv2/core/buffer.h
A engines/mads/madsv2/core/color.h
A engines/mads/madsv2/core/config.h
A engines/mads/madsv2/core/cycle.h
A engines/mads/madsv2/core/ems.h
A engines/mads/madsv2/core/env.h
A engines/mads/madsv2/core/error.h
A engines/mads/madsv2/core/fileio.h
A engines/mads/madsv2/core/font.h
A engines/mads/madsv2/core/game.h
A engines/mads/madsv2/core/general.h
A engines/mads/madsv2/core/heap.h
A engines/mads/madsv2/core/hspot.h
A engines/mads/madsv2/core/image.h
A engines/mads/madsv2/core/imath.h
A engines/mads/madsv2/core/inter.h
A engines/mads/madsv2/core/kernel.h
A engines/mads/madsv2/core/keys.h
A engines/mads/madsv2/core/lib.h
A engines/mads/madsv2/core/loader.h
A engines/mads/madsv2/core/mads.h
A engines/mads/madsv2/core/magic.h
A engines/mads/madsv2/core/matte.h
A engines/mads/madsv2/core/mcga.h
A engines/mads/madsv2/core/mem.h
A engines/mads/madsv2/core/mouse.h
A engines/mads/madsv2/core/pack.h
A engines/mads/madsv2/core/pal.h
A engines/mads/madsv2/core/player.h
A engines/mads/madsv2/core/popup.h
A engines/mads/madsv2/core/quote.h
A engines/mads/madsv2/core/room.h
A engines/mads/madsv2/core/screen.h
A engines/mads/madsv2/core/sound.h
A engines/mads/madsv2/core/speech.cpp
A engines/mads/madsv2/core/speech.h
A engines/mads/madsv2/core/sprite.h
A engines/mads/madsv2/core/tile.h
A engines/mads/madsv2/core/timer.h
A engines/mads/madsv2/core/video.h
A engines/mads/madsv2/core/vocab.h
A engines/mads/madsv2/core/xms.h
A engines/mads/madsv2/phantom/mads/quotes.h
A engines/mads/madsv2/phantom/mads/sounds.h
A engines/mads/madsv2/phantom/mads/speeches.h
engines/mads/madsv2/phantom/main_menu.cpp
engines/mads/madsv2/phantom/main_menu.h
engines/mads/module.mk
diff --git a/engines/mads/madsv2/core/anim.h b/engines/mads/madsv2/core/anim.h
new file mode 100644
index 00000000000..ce76b2f9672
--- /dev/null
+++ b/engines/mads/madsv2/core/anim.h
@@ -0,0 +1,496 @@
+/* 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 MADS_CORE_ANIM_H
+#define MADS_CORE_ANIM_H
+
+#include "mads/madsv2/core/font.h"
+#include "mads/madsv2/core/image.h"
+#include "mads/madsv2/core/room.h"
+#include "mads/madsv2/core/sprite.h"
+#include "mads/madsv2/core/tile.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+
+#define anim_file_version "3.02" /* Animate definition file version */
+
+/* Flags to be passed to anim_load(). Note that all PAL_MAP... flags */
+/* can be passed through as well. */
+
+#define ANIM_LOAD_TRANSLATE 0x0001 /* Translate to 16 colors */
+#define ANIM_LOAD_BACKGROUND 0x0100 /* Load background picture */
+#define ANIM_LOAD_BACK_ONLY 0x0200 /* Load background only */
+
+/* these are mapped to misc[] in the AnimFile structure below */
+
+#define depth_coded misc[0]
+#define misc_any_packed misc[1]
+#define misc_packed_series misc[2]
+#define misc_peel_x misc[3]
+#define misc_peel_y misc[4]
+#define misc_peel_rate misc[5]
+#define misc_slow_fade misc[6]
+
+#define misc_no_catchup misc[7]
+
+#define seg_misc_coordinate_style misc[0]
+#define seg_misc_displace_x misc[1]
+#define seg_misc_displace_y misc[2]
+
+#define seg_misc_disp_good_1 misc[3] /* holds magic number (problem w/ uninitialized data) */
+#define seg_misc_disp_good_2 misc[4]
+#define SEG_MAGIC_1 0x1234
+#define SEG_MAGIC_2 0x5678
+
+#define seg_misc_accel_x misc[5]
+#define seg_misc_accel_y misc[6]
+
+#define seg_misc_special_scale misc[7]
+
+#define SEG_SPECIAL_SCALE_UP 0x8000
+#define SEG_SPECIAL_SCALE_DOWN 0x4000
+#define SEG_SPECIAL_SCALE_MASK 0xf000
+
+#define AA_MAX_SERIES 50 /* Maximum # of series */
+#define AA_MAX_SEGMENTS 25 /* Maximum # of segments */
+#define AA_MAX_FRAMES 500 /* Maximum # of frames */
+#define AA_MAX_IMAGES 500 /* Maximum # of images */
+#define AA_MAX_SPEECH 25 /* Maximum # of speech queues */
+
+#define AA_MAX_IMAGES_PER_FRAME 250 /* Maximum images in one frame */
+
+#define AA_MAX_SPAWNED 2 /* Maximum # of spawns in random */
+
+#define AA_MAX_CHANGES 100 /* Maximum # of speech changes */
+
+
+#define AA_ROOM 1 /* Use MADS room as background */
+#define AA_FULLSIZE 2 /* Use MADS full screen room */
+#define AA_BLACKSCREEN 3 /* Black screen background */
+#define AA_INTERFACE 4 /* Use MADS interface screen */
+
+
+#define AA_DONTCARE -1
+
+#define AA_LINEAR 1 /* loop_mode settings */
+#define AA_PINGPONG 2
+#define AA_STAMP 9 /* FOR KERNEL SEQUENCES ONLY */
+
+#define AA_ONCE 1 /* repeat_mode settings */
+#define AA_MULTIPLE 2
+
+#define AA_ROOMBASED -1 /* depth/scale settings */
+#define AA_MANUAL -2
+
+#define AA_ABSOLUTEFRAME 1 /* framing settings */
+#define AA_DELTAFIRST 2
+#define AA_DELTALAST 3
+#define AA_ABSOLUTEFIRST 4
+#define AA_ABSOLUTELAST 5
+#define AA_RANDOMACCESS 6
+
+#define AA_NOTHING 0 /* No timing marks */
+#define AA_MARK 0x8000 /* Timing MARK portion */
+#define AA_TIMING 0x7fff /* Timing TICKS portion */
+
+#define AA_LOAD_SOUND 0x8000 /* Load sound file */
+#define AA_LOAD_SPEECH 0x4000 /* Load speech file */
+#define AA_LOAD_FONT 0x2000 /* Load font file */
+
+#define AA_NO_SPEECH (-1) /* No speech queue */
+
+#define AA_SPEECH 0x8000 /* Use speech always */
+#define AA_TEXT 0x4000 /* Use text always */
+#define AA_SPEECH_XOR_TEXT 0x2000 /* Use speech or text */
+#define AA_SPEECH_AND_TEXT 0x1000 /* Use speech and text */
+#define AA_SPEECH_NOR_TEXT 0x0800 /* Use neither */
+
+#define AA_ABORTABLE 0x8000 /* Segment can be aborted */
+#define AA_CONVENTIONAL 0x4000 /* Segment uses conventional memory */
+#define AA_PRELOAD 0x2000 /* Segment preloads (conv. only) */
+
+
+#define AA_ERR_OPENFILE -128
+#define AA_ERR_WRITEFILE -129
+#define AA_ERR_READFILE -130
+#define AA_ERR_NOMOREMEMORY -131
+#define AA_ERR_MAKEDIALOG -132
+#define AA_ERR_TOOMANYIMAGES -133
+#define AA_ERR_TOOMANYFRAMES -134
+#define AA_ERR_TOOMANYSEGMENTS -135
+#define AA_ERR_TOOMANYSPEECH -136
+#define AA_ERR_NODAMNFONT -137
+#define AA_ERR_BADDEFINITION -138
+#define AA_ERR_OLDDEFINITION -139
+
+
+#define IMAGE_UNSCALED 0xff
+
+#define IMAGE_UPDATE_READY 0x40 /* Ready for live screen */
+
+#define IMAGE_UPDATE 1 /* Image needs redraw */
+#define IMAGE_STATIC 0 /* Image remains on screen */
+#define IMAGE_ERASE -1 /* Image erased & removed */
+#define IMAGE_REFRESH -2 /* Full buffer refresh */
+#define IMAGE_OVERPRINT -3 /* Interface overprint */
+#define IMAGE_DELTA -4 /* Image drawn to scr_orig */
+#define IMAGE_FULLUPDATE -5 /* Interface area erasure */
+
+#define IMAGE_UPDATE_ONLY -20 /* Update live screen only */
+
+
+struct SegmentBuf {
+ int seg_id;
+
+ char name[32];
+
+ int series_id;
+ int mirror_series;
+ int start_sprite;
+ int end_sprite;
+ int sprite_loop_mode;
+ int sprite_repeat_mode;
+ double loop_direction;
+
+ int framing;
+ int first_frame;
+ int last_frame;
+
+ byte depth_mode;
+ byte low_level_change;
+
+ int scale_mode;
+ int front_y, back_y;
+ int front_scale, back_scale;
+
+ int probability;
+
+ byte spawn[AA_MAX_SPAWNED];
+ int spawn_frame[AA_MAX_SPAWNED];
+ byte sound;
+ int sound_frame;
+
+ int start_x, start_y;
+ int end_x, end_y;
+
+ double delta_x, delta_y;
+
+ int auto_locating;
+
+ int speech;
+
+ word misc[10];
+
+ int num_sprite_changes;
+ word sprite_change_frame[AA_MAX_CHANGES];
+ word sprite_change_target[AA_MAX_CHANGES];
+};
+
+typedef struct SegmentBuf Segment;
+typedef Segment *SegmentPtr;
+
+
+#define zone_low spawn_frame[0]
+#define zone_high spawn_frame[1]
+
+
+struct ImageEditBuf {
+ int frame_id;
+ byte segment_id;
+
+ byte series_id;
+ int sprite_id;
+ int x, y;
+ byte depth;
+ byte scale;
+};
+
+typedef struct ImageEditBuf ImageEdit;
+typedef ImageEdit *ImageEditPtr;
+
+struct ImageInterBuf {
+ int flags;
+ byte segment_id;
+ byte series_id;
+ byte sprite_id;
+ int x;
+ byte y;
+};
+typedef struct ImageInterBuf ImageInter;
+typedef ImageInter *ImageInterPtr;
+
+
+struct MessageBuf {
+ char active;
+ char spacing;
+ int x, y;
+ int xs, ys;
+ int status;
+ int main_color;
+ FontPtr font;
+ char *text;
+};
+
+typedef struct MessageBuf Message;
+typedef Message *MessagePtr;
+
+
+
+struct FrameEditBuf {
+ byte sound;
+ word ticks;
+ word timing;
+ word view_x;
+ word view_y;
+ char yank_x;
+ char yank_y;
+};
+
+typedef struct FrameEditBuf FrameEdit;
+typedef FrameEdit *FrameEditPtr;
+
+
+struct FrameBuf {
+ byte sound; /* what sound cue to play */
+ byte speech; /* what speech record to activate */
+ word ticks; /* how many ticks for this frame (before? after?) */
+ word view_x; /* where the pan set currently */
+ word view_y;
+ char yank_x; /* for backgrounds which wrap around, like starfields */
+ char yank_y;
+};
+
+typedef struct FrameBuf Frame;
+typedef Frame *FramePtr;
+
+
+struct SegmentInterBuf {
+ int probability;
+ int num_images;
+ int first_image;
+ int last_image;
+ int counter;
+ byte spawn[AA_MAX_SPAWNED];
+ int spawn_frame[AA_MAX_SPAWNED];
+ byte sound;
+ int sound_frame;
+};
+
+typedef struct SegmentInterBuf SegmentInter;
+typedef SegmentInter *SegmentInterPtr;
+
+
+typedef struct {
+ int resource_id; /* Speech segment id in resource file */
+ char text[60]; /* Text to be displayed */
+ byte misc[3]; /* 3 extra bonus bytes */
+ byte sound; /* Sound to be used */
+ /* pl SpeechDirPtr speech; */ /* Binary speech pointer */
+ int x, y; /* Text coordinates */
+ int display_condition; /* Condition for display */
+ RGBcolor color[2]; /* Colors for text display */
+ word flags; /* Segment flags */
+ int speech_loops; /* Loops if speech active */
+ int non_speech_loops; /* Loops if speech inactive */
+ int segment_to_loop; /* Segment ID to be looped */
+ int first_frame; /* First frame of segment */
+ int last_frame; /* Last frame of segment */
+ int first_image; /* First image number */
+} Speech;
+
+typedef Speech *SpeechPtr;
+
+/* daa file header */
+
+struct AnimDefBuf {
+ int num_series;
+ int num_segments;
+ int num_frames;
+ int num_images;
+ int num_speech;
+
+ int timing_mode;
+
+ int misc[10];
+
+ word load_flags;
+ int font_auto_spacing;
+
+ int background_type;
+ int background_xs;
+ int background_ys;
+ int background_room;
+ char background_name[80];
+
+ char sound_file_name[80];
+
+ char name[80];
+ char desc[80];
+
+ char series_name[AA_MAX_SERIES][80];
+
+ char background_depth[80];
+
+ char speech_file[80];
+ char font_file[80];
+};
+
+
+typedef struct AnimDefBuf AnimDef;
+typedef AnimDef *AnimDefPtr;
+
+/* aa file header */
+
+struct AnimFileBuf {
+ int num_series;
+ int num_frames;
+ int num_images;
+ int num_speech;
+ word load_flags;
+ int font_auto_spacing;
+ int background_type; /* black, or room, or whatever */
+ int background_room; /* room number to load */
+ int misc[10]; /* see MISC_ defines above */
+ char background_name[13]; /* if needed */
+ char series_name[AA_MAX_SERIES][13]; /* filenames for all your series */
+ char sound_file_name[13];
+ char background_depth[13];
+ char speech_file[13];
+ char font_file[13];
+};
+
+typedef struct AnimFileBuf AnimFile;
+
+/* runtime memory image for an animation */
+
+struct AnimBuf {
+ int num_series;
+ int num_frames;
+ int num_images;
+ int num_speech;
+ word load_flags;
+ int font_auto_spacing;
+ int background_type;
+ int background_room;
+ int misc[10];
+
+ char background_name[13];
+ char series_name[AA_MAX_SERIES][13];
+
+ char sound_file_name[13];
+ char background_depth[13];
+ char speech_file[13];
+ char font_file[13];
+
+ FontPtr font;
+ SpeechPtr speech;
+
+ ImagePtr image; /* to the array of images */
+ FramePtr frame; /* to the array of frames */
+ SeriesPtr series[AA_MAX_SERIES]; /* pointers to series */
+
+ int series_id[AA_MAX_SERIES];
+};
+
+typedef struct AnimBuf Anim;
+typedef Anim *AnimPtr;
+
+/* the interface version of the above */
+
+struct AnimInterBuf {
+ int num_series;
+ int num_segments;
+ int num_images;
+ int num_speech;
+ word load_flags;
+ int font_auto_spacing;
+ int background_type;
+ int background_room;
+ int misc[10];
+
+ char background_name[13];
+ char series_name[AA_MAX_SERIES][13];
+
+ char sound_file_name[13];
+ char background_depth[13];
+ char speech_file[13];
+ char font_file[13];
+
+ FontPtr font;
+ SpeechPtr speech;
+
+ ImageInterPtr image;
+ SegmentInterPtr segment;
+ SeriesPtr series[AA_MAX_SERIES];
+
+ int series_id[AA_MAX_SERIES];
+};
+
+typedef struct AnimInterBuf AnimInter;
+typedef AnimInter *AnimInterPtr;
+
+
+extern int anim_error;
+
+/* anim_1.cpp */
+int anim_load_background(AnimFile *anim_in,
+ Buffer *this_orig,
+ Buffer *this_depth,
+ TileMapHeader *picture_map,
+ TileMapHeader *depth_map,
+ TileResource *picture_resource,
+ TileResource *depth_resource,
+ RoomPtr *room,
+ CycleListPtr cycle_list,
+ int load_flags, int star_search);
+
+
+/* anim_2.cpp */
+void anim_unload(AnimPtr anim);
+
+AnimPtr anim_load(char *file_name,
+ Buffer *orig, Buffer *depth,
+ TileMapHeader *picture_map,
+ TileMapHeader *depth_map,
+ TileResource *picture_resource,
+ TileResource *depth_resource,
+ RoomPtr *room, CycleListPtr cycle_list,
+ int load_flags);
+
+/* anim_3.cpp */
+int anim_get_sound_info(char *file_name,
+ char *sound_file_buffer,
+ int *sound_load_flag);
+
+/* anim_4.cpp */
+int anim_get_header_info(char *file_name,
+ AnimFile *anim_in);
+
+
+/* anim_5.cpp */
+int anim_himem_preload(char *name, int level);
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/btype.h b/engines/mads/madsv2/core/btype.h
new file mode 100644
index 00000000000..a80c02944c8
--- /dev/null
+++ b/engines/mads/madsv2/core/btype.h
@@ -0,0 +1,48 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef MADS_CORE_BTYPE_H
+#define MADS_CORE_BTYPE_H
+
+#include "common/scummsys.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+/* btype_1.c */
+byte upcaseb(byte inp);
+
+/* btype_2.c */
+int upcasei(int inp);
+
+/* btype_3.c */
+int xtoi(char *string);
+
+/* btype_4.c */
+int btoi(char *string);
+
+/* btype_5.c */
+int stoi(char *string);
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/buffer.h b/engines/mads/madsv2/core/buffer.h
new file mode 100644
index 00000000000..e734219ba30
--- /dev/null
+++ b/engines/mads/madsv2/core/buffer.h
@@ -0,0 +1,207 @@
+/* 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 MADS_CORE_BUFFER_H
+#define MADS_CORE_BUFFER_H
+
+#include "mads/madsv2/core/general.h"
+#include "mads/madsv2/core/font.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+#define MAX_PEEL_VALUE 80
+
+#define BUFFER_CREATED_PAGE_HANDLE 16384 /* Mask if EMS page handle created on the fly */
+
+#define BUFFER_PRESERVE -1 /* Normal preserve attempt (EMS or disk) */
+#define BUFFER_PRESERVE_RAM -2 /* Disallows disk preservation */
+#define BUFFER_ATTEMPT_CONVENTIONAL -8 /* Attempt conventional preserve */
+
+#define BUFFER_PRESERVED_CONVENTIONAL -1 /* Preserved in conventional memory */
+#define BUFFER_NOT_PRESERVED -3 /* All attempts to preserve failed */
+#define BUFFER_PRESERVED_DISK -10 /* Preserved on disk */
+
+
+extern int buffer_restore_keep_flag;
+
+
+/* buffer_1.c */
+int buffer_init(Buffer *buf, word x, word y);
+int buffer_init_name(Buffer *buf, word x, word y,
+ char *block_name);
+
+/* buffer_2.c */
+int buffer_free(Buffer *buf);
+
+/* buffer_3.c */
+int buffer_fill(Buffer target, byte value);
+
+/* buffer_4.c */
+int buffer_rect_copy(Buffer from, Buffer unto,
+ int ul_x, int ul_y,
+ int size_x, int size_y);
+
+/* buffer_5.c */
+int buffer_rect_fill(Buffer target,
+ int ul_x, int ul_y,
+ int size_x, int size_y,
+ byte value);
+/* buffer_6.c */
+int buffer_rect_copy_2(Buffer from, Buffer unto,
+ int from_x, int from_y,
+ int unto_x, int unto_y,
+ int size_x, int size_y);
+
+/* buffer_7.c */
+void buffer_put_pixel(Buffer buf, word x,
+ word y, byte c);
+
+/* buffer_8.c */
+byte buffer_get_pixel(Buffer buf, word x, word y);
+
+/* buffer_9.c */
+void buffer_hline(Buffer buf, word x1, word x2,
+ word y, byte color);
+
+/* buffer_a.c */
+void buffer_vline(Buffer buf, word x, word y1,
+ word y2, byte color);
+
+/* buffer_b.c */
+void buffer_draw_box(Buffer buf, word x1, word y1,
+ word x2, word y2, byte color);
+
+/* buffer_d.c */
+void buffer_hline_xor(Buffer buf, int x1, int x2, int y);
+
+/* buffer_e.c */
+void buffer_vline_xor(Buffer buf, int x, int y1, int y2);
+
+/* buffer_f.c */
+void buffer_draw_crosshair(Buffer buf, int x, int y);
+
+/* buffer_g.c */
+void buffer_draw_box_xor(Buffer buf, int x1, int y1, int x2, int y2);
+
+/* buffer_h.c */
+int buffer_get_delta_bounds(Buffer buf1, Buffer buf2,
+ byte newcol, word *xl, word *xh,
+ word *yl, word *yh);
+
+/* buffer_i.c */
+byte *fastcall buffer_pointer(Buffer *buf, int x, int y);
+int buffer_conform(Buffer *buffer, int *x, int *y,
+ int *xs, int *ys);
+
+/* buffer_j.c */
+int buffer_inter_merge_2(Buffer from, Buffer unto,
+ int from_x, int from_y,
+ int unto_x, int unto_y,
+ int size_x, int size_y);
+
+/* buffer_k.c */
+void buffer_line(Buffer target, int x1, int y1, int x2, int y2,
+ int color);
+
+/* buffer_l.c */
+void buffer_line_xor(Buffer target, int x1, int y1,
+ int x2, int y2);
+
+/* buffer_m.c */
+int buffer_legal(Buffer walk, int orig_wrap,
+ int x1, int y1, int x2, int y2);
+
+/* buffer_n.c */
+extern word pattern_control_value;
+extern int auto_pattern;
+
+word buffer_rect_fill_pattern(Buffer target,
+ int ul_x, int ul_y,
+ int size_x, int size_y,
+ int base_x, int base_y,
+ int base_xs,
+ byte value1, byte value2,
+ word start_accum,
+ word note_line);
+
+
+/* buffer_o.c */
+int buffer_rect_fill_swap(Buffer target,
+ int ul_x, int ul_y,
+ int size_x, int size_y,
+ byte value1, byte value2);
+
+/* buffer_p.c */
+void buffer_peel_horiz(Buffer *target, int peel);
+
+/* buffer_q.c */
+void buffer_peel_vert(Buffer *target, int peel,
+ byte *work_memory, long work_size);
+
+/* buffer_r.c */
+int buffer_to_disk(Buffer *source, int x, int y,
+ int xs, int ys);
+void buffer_from_disk(Buffer *source, int buffer_id,
+ int keep_flag,
+ int x, int y,
+ int xs, int ys);
+
+/* buffer_s.c */
+int buffer_to_ems(Buffer *source, int page_handle,
+ int source_ems_handle,
+ int x, int y, int xs, int ys);
+int buffer_from_ems(Buffer *source, int page_handle,
+ int target_ems_handle,
+ int x, int y, int xs, int ys);
+
+/* buffer_t.c */
+int buffer_preserve(Buffer *source, int flags,
+ int source_ems_handle,
+ int x, int y, int xs, int ys);
+void buffer_restore(Buffer *source, int preserve_handle,
+ int target_ems_handle,
+ int x, int y, int xs, int ys);
+
+
+/* buffer_u.c */
+int buffer_rect_translate(Buffer from, Buffer unto,
+ int from_x, int from_y,
+ int unto_x, int unto_y,
+ int size_x, int size_y,
+ byte *table);
+
+
+/* buffer_w.c */
+int buffer_scan(Buffer *buffer, int magic,
+ int base_x, int base_y,
+ int size_x, int size_y);
+
+/* buffer_w.c */
+int buffer_compare(Buffer *buffer0, Buffer *buffer1,
+ int base_x, int base_y,
+ int base_x2, int base_y2,
+ int size_x, int size_y);
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/color.h b/engines/mads/madsv2/core/color.h
new file mode 100644
index 00000000000..8ffedf45790
--- /dev/null
+++ b/engines/mads/madsv2/core/color.h
@@ -0,0 +1,167 @@
+/* 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 MADS_CORE_COLOR_H
+#define MADS_CORE_COLOR_H
+
+#include "mads/madsv2/core/general.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+
+#define COLOR_MAX_USER_COLORS 256
+#define COLOR_FIRST_USER_COLOR 16
+
+#define COLOR_MAX_SHADOW_COLORS 3
+
+#define COLOR_MAX_CYCLES 8
+
+#define COLOR_HIGHEST 254
+#define COLOR_TRANSPARENT 255
+
+#define COLOR_SOLID 0
+#define COLOR_BLACK_THATCH 0x0d
+#define COLOR_NO_X16 0x0ff
+
+#define COLOR_ERR_LISTOVERFLOW -1
+
+#define COLOR_GROUP_MAP_TO_CYCLE 0x80 /* Map to cycling colors */
+#define COLOR_GROUP_MAP_TO_CLOSEST 0x40 /* Map to closest color */
+#define COLOR_GROUP_FORCE_TO_CLOSEST 0x20 /* Force to closest color */
+#define COLOR_GROUP_MAP_TO_SHADOW 0x10 /* Map to shadow color */
+#define COLOR_GROUP_FORCE_TO_SKIP 0x08 /* Force to skip code */
+
+#define COLOR_GROUP_SPECIAL_2 0x02 /* Special color group 2 */
+#define COLOR_GROUP_SPECIAL_1 0x01 /* Special color group 1 */
+
+#define COLOR_DP(x) (((((x + 1) * 101) + 26) / 64) - 1)
+
+
+/* A fully parameterized color (in contrast to a plain RGBcolor as */
+/* defined in general.mac) */
+
+typedef struct {
+ byte r, g, b; /* RGB values */
+ byte x16; /* 16 color dither translation */
+ byte cycle; /* Color cycling handle */
+ byte group; /* Color grouping flags */
+} Color;
+
+typedef Color *ColorPtr;
+
+
+/* Palette-independent color list; ready to map into palette */
+
+typedef struct {
+ int num_colors;
+ Color table[COLOR_MAX_USER_COLORS];
+} ColorList;
+
+typedef ColorList *ColorListPtr;
+
+
+/* Palette-independent color cycling range & timing information */
+
+typedef struct {
+ byte num_colors; /* Number of colors in the cycle */
+ byte first_list_color; /* First color in color list */
+ byte first_palette_color; /* First color in final palette */
+ byte ticks; /* 60/s ticks between cycles */
+} Cycle;
+
+typedef Cycle *CyclePtr;
+
+
+/* List of color cycling ranges */
+
+typedef struct {
+ int num_cycles;
+ Cycle table[COLOR_MAX_CYCLES];
+} CycleList;
+
+typedef CycleList *CycleListPtr;
+
+
+typedef struct {
+ int num_shadow_colors;
+ int shadow_color[COLOR_MAX_SHADOW_COLORS];
+} ShadowList;
+
+typedef ShadowList *ShadowListPtr;
+
+
+/* color_1.c */
+byte color_thatch(int color, int thatching);
+
+void color_list_start_scan(byte *list_flags);
+
+int color_list_update(ColorListPtr list, Buffer *scan_buf,
+ Palette *scan_pal, byte *list_flags,
+ byte *palette_map, CycleListPtr cycle);
+
+void color_list_purge(ColorListPtr list, byte *list_flags);
+
+int color_list_palette(ColorListPtr list, Buffer *scan_buf,
+ Palette *scan_pal, int base_color,
+ byte *palette_map, CycleListPtr cycle);
+
+void color_list_conform(ColorListPtr list, Buffer *scan_buf,
+ Palette *scan_pal, Palette *main_pal,
+ int base_color);
+
+void color_trans_fill_buf(Buffer unto,
+ int unto_x, int unto_y,
+ int size_x, int size_y,
+ byte thatch_color);
+
+void color_trans_show_buf(Buffer from, Buffer unto,
+ int from_x, int from_y,
+ int unto_x, int unto_y,
+ int size_x, int size_y,
+ ColorListPtr list,
+ byte *palette_map, int mask_flag);
+
+void color_buffer_palette_to_list(ColorListPtr list,
+ Buffer *scan_buf,
+ byte *palette_map);
+
+void color_buffer_list_to_palette(Buffer *scan_buf, int marker);
+
+void color_transparent_swap(Buffer *scan_buf,
+ Palette *scan_pal,
+ byte transparent);
+
+
+/* color_2.c */
+void color_buffer_list_to_main(ColorListPtr color_list,
+ Buffer *scan_buf);
+
+/* color_3.c */
+void color_buffer_list_to_x16(ColorListPtr color_list,
+ Buffer *scan_buf);
+
+void color_split_thatch(int thatch, int *color, int *thatching);
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/config.h b/engines/mads/madsv2/core/config.h
new file mode 100644
index 00000000000..7e2947b01dd
--- /dev/null
+++ b/engines/mads/madsv2/core/config.h
@@ -0,0 +1,106 @@
+/* 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 MADS_CORE_CONFIG_H
+#define MADS_CORE_CONFIG_H
+
+#include "common/scummsys.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+/* #define CONFIG_FILE_NAME "CONFIG.REX" */
+
+#define INTERFACE_MACINTOSH 0 /* Macintosh interface */
+#define INTERFACE_BRAINDEAD 1 /* The "other" interface */
+
+#define INVENTORY_SPINNING 0 /* Inventory objects spin */
+#define INVENTORY_SQUAT 1 /* Inventory objects squat */
+
+#define INTERFACE_ANIMATED 0 /* Interface animations on */
+#define INTERFACE_STILL 1 /* Interface still */
+
+#define SCREEN_FADE_SMOOTH 0 /* Smooth fade (thru black) */
+#define SCREEN_FADE_MEDIUM 1 /* Medium fade (Detmar-o-matic) */
+#define SCREEN_FADE_FAST 2 /* Fast fade (thru black) */
+
+#define MEMORY_ALL 0 /* Use all available memory */
+#define MEMORY_NO_EMS 1 /* Do not use EMS memory */
+#define MEMORY_NO_XMS 2 /* Do not use XMS memory */
+#define MEMORY_CONVENTIONAL 3 /* Use conventional only */
+
+#define PANNING_SMOOTH 0 /* Panning speeds */
+#define PANNING_MEDIUM 1
+#define PANNING_INSTANT 2
+
+#define MOUSE_MICROSOFT 0 /* Mouse cursor fixes */
+#define MOUSE_NOT_MICROSOFT 1
+
+struct ConfigFile {
+ int sound_card_type; /* Sound card configuration */
+ int sound_card_address;
+
+ int speech_card_type; /* Speech card configuration */
+ int speech_card_address;
+ int speech_card_irq;
+ int speech_card_drq;
+
+ int music_flag; /* Music on/off */
+ int sound_flag; /* Sound on/off */
+ int interface_hotspots; /* Easy / Standard */
+ int inventory_mode; /* Spinning / Still */
+ int animated_interface; /* On / Off */
+
+ int quotes_enabled; /* Quotes option enabled */
+
+ int high_memory_mode; /* High memory mode */
+
+ int screen_fade; /* Screen fade */
+
+ int speech_flag; /* Speech on/off */
+
+ int panning_speed; /* Panning speed flag */
+
+ int mouse_cursor_fix; /* Mouse halfway problem */
+
+ int cd_version_installed; /* CD version installed */
+ int cd_drive; /* CD drive letter */
+
+ int speech_version_installed; /* Version with speech installed */
+
+ int show_speech_boxes; /* Show text during speech */
+
+ int sound_card_irq;
+ int misc2;
+ int misc3;
+ int misc4;
+ int misc5;
+};
+
+extern ConfigFile config_file;
+
+#define music_off (!config_file.music_flag)
+#define sound_off (!config_file.sound_flag)
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/cycle.h b/engines/mads/madsv2/core/cycle.h
new file mode 100644
index 00000000000..8df81e5b497
--- /dev/null
+++ b/engines/mads/madsv2/core/cycle.h
@@ -0,0 +1,47 @@
+/* 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 MADS_CORE_CYCLE_H
+#define MADS_CORE_CYCLE_H
+
+#include "mads/madsv2/core/color.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+extern Palette cycling_palette; /* Palette being used for cycling */
+
+extern CycleList cycle_list; /* List of cycles being performed */
+extern int cycling_active; /* Flag if cycling active */
+extern int cycling_delay; /* Cycling delay countdown */
+extern int cycling_threshold; /* Cycling reset threshold */
+extern int total_cycle_colors; /* Total # of colors being cycled */
+
+extern long cycle_timing[COLOR_MAX_CYCLES]; /* Timing for each cycle */
+
+/* cycle_1.c */
+void cycle_init(CycleListPtr new_cycle_list, int activate);
+void cycle_colors(void);
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/ems.h b/engines/mads/madsv2/core/ems.h
new file mode 100644
index 00000000000..7ddf612e814
--- /dev/null
+++ b/engines/mads/madsv2/core/ems.h
@@ -0,0 +1,137 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef MADS_CORE_EMS_H
+#define MADS_CORE_EMS_H
+
+#include "mads/madsv2/core/pack.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+#define EMS_PAGING_CLASSES 4 /* # of paging classes */
+
+#define EMS_PAGING_SYSTEM 0 /* System class - fully available */
+#define EMS_PAGING_ROOM 1 /* Room class */
+#define EMS_PAGING_SECTION 2 /* Section class */
+#define EMS_PAGING_GLOBAL 3 /* Global class */
+
+#define EMS_TILE_PAGE 0
+#define EMS_PAGE_MAP_PAGE 1
+#define EMS_PRELOAD_PAGE 2
+
+#define EMS_MAX_RESIDENT 150
+#define EMS_PAGE_SIZE 16384
+
+#define EMS_DIRECTORY_ADDRESS 2048
+
+
+typedef struct {
+ byte flag;
+ byte level;
+ char list[14];
+ long size;
+ int num_packets;
+ long packet_size[PACK_MAX_LIST_LENGTH];
+} EmsDirectory;
+
+
+typedef struct {
+ int handle; /* EMS block handle */
+ int page_marker; /* Page marker in EMS block */
+ int page_offset; /* Offset within the page */
+} EmsPtr;
+
+
+extern int ems_driver; /* Flag if EMS driver is installed */
+extern int ems_exists; /* Flag if we've got some EMS available */
+extern word ems_page_frame; /* Segment address of EMS page frame */
+extern word ems_handle; /* EMS handle of our allocated pages */
+extern word ems_pages; /* # of pages EMS allocated for us */
+extern int ems_disabled; /* Flag if EMS disabled altogether */
+
+extern word ems_high_version; /* High (integer) part of EMS version # */
+extern word ems_low_version; /* Low (fraction) part of EMS version # */
+
+extern byte *ems_page[4]; /* Pointers to EMS physical pages */
+
+extern word ems_paging_active; /* EMS paging system is active */
+extern word ems_pages_free; /* # of pages available now */
+extern word ems_pages_reserved; /* # of pages reserved */
+extern byte *ems_page_flag; /* Page allocation flag array */
+
+extern word ems_paging_reserve[EMS_PAGING_CLASSES]; /* Reserve pages */
+
+
+extern int ems_mapping_changed;/* EMS mapping has changed */
+
+extern int ems_page_mapped[4];
+extern int ems_page_stack[4];
+
+
+
+/* ems_1.c */
+int ems_detect(void);
+void ems_shutdown(void);
+int ems_map_page(word physical, word logical);
+void ems_unmap_all(void);
+void ems_push(void);
+void ems_pop(void);
+
+
+
+/* ems_2.c */
+int ems_activate_directory(void);
+int ems_activate_page_map(void);
+int ems_paging_setup(void);
+void ems_free_page_handle(word handle);
+int ems_get_page_handle(word pages_needed);
+int ems_next_handle_page(int handle, int page_marker);
+void ems_paging_mode(int paging_mode);
+void ems_paging_shutdown(void);
+
+/* ems_3.c */
+int ems_copy_it_up(int ems_paging_handle,
+ int *ems_page_marker,
+ int *ems_page_offset,
+ byte *source,
+ long read_size);
+
+/* ems_4.c */
+int ems_copy_it_down(int ems_paging_handle,
+ int *ems_page_marker,
+ int *ems_page_offset,
+ byte *target,
+ long write_size);
+
+/* ems_5.c */
+int ems_map_buffer(int buffer_page_handle);
+
+/* ems_6.c */
+int ems_search_page(int ems_handle, int page_number);
+
+/* ems_7.c */
+void ems_buffer_to_buffer(int source_handle, int target_handle);
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/env.h b/engines/mads/madsv2/core/env.h
new file mode 100644
index 00000000000..fc26f20a300
--- /dev/null
+++ b/engines/mads/madsv2/core/env.h
@@ -0,0 +1,134 @@
+/* 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 MADS_CORE_ENV_H
+#define MADS_CORE_ENV_H
+
+#include "mads/madsv2/core/general.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+#define MADS_ENV "MADS"
+#define MADS_PRIV_ENV "MADSPRIV"
+#define MADS_SOUND_ENV "MADSOUND"
+
+#define MADS_PRIV_ARTIST 0x01
+#define MADS_PRIV_DESIGNER 0x02
+#define MADS_PRIV_PROGRAM 0x04
+#define MADS_PRIV_SYSTEM 0x08
+
+#define ENV_CONFIGNAME "*options.cfg"
+
+#define ENV_SEARCH_MADS_PATH 0
+#define ENV_SEARCH_CONCAT_FILES 1
+
+#define ENV_OBJECTS 16
+#define ENV_INTERFACE 17
+#define ENV_TEXT 18
+#define ENV_QUOTES 19
+#define ENV_FONT 20
+#define ENV_ART 21
+#define ENV_SOUND 22
+#define ENV_CONV 23
+#define ENV_SPEECH 24
+
+
+struct env_options_type
+{
+ int linemode; /* 50/25/0=auto */
+ int compile_final; /* TRUE if compilation is to final set */
+ int compile_debug; /* TRUE for debugging mode */
+ int current_room; /* User's current room */
+ long game_revision; /* Version of game */
+ char game_name[25]; /* Game's working title */
+ int mono_on_right; /* Is monochrome monitor on right? */
+};
+
+
+extern int env_search_mode;
+extern int env_search_cd;
+extern char env_cd_drive;
+extern int env_privileges;
+
+extern int env_sound_override;
+
+extern long env_concat_file_size; /* Size of last concat file opened */
+
+
+
+/* env_0.c */
+int env_verify(void);
+
+/* env_1.c */
+Common::Stream * env_open(char *file_path, char *options);
+int env_exist(char *file_name);
+long env_get_file_size(Common::Stream *handle);
+
+
+/* env_1.c */
+char *env_get_path(char *madspath,
+ char *infile);
+
+/* env_1.c */
+char *env_catint(char *out, int value, int digits);
+
+/* env_1.c */
+char * env_fill_path(char *path, int env_mode, int env_room);
+
+
+/* env_2.c */
+char * env_dos_error_name(char *error_buf);
+
+/* env_3.c */
+char * env_get_level_path(char *out, int item_type,
+ char *file_spec,
+ int first_level,
+ int second_level);
+
+Common::Stream * env_open_level(int item_type,
+ char *file_spec,
+ int level_one, int level_two,
+ char *options);
+
+
+/* env_4.c */
+extern char env_null[7];
+
+char *env_get(char *target, char *env);
+
+
+/* env_5.c */
+char * env_next(char *variable);
+char * env_find_end(char *environment);
+int env_size(char *environment);
+int env_free(char *environment);
+
+/* env_5.c */
+char * env_find(char *environment, char *variable);
+void env_delete(char *environment, char *variable);
+int env_insert(char *environment, char *variable,
+ char *value);
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/error.h b/engines/mads/madsv2/core/error.h
new file mode 100644
index 00000000000..91ea141f1c2
--- /dev/null
+++ b/engines/mads/madsv2/core/error.h
@@ -0,0 +1,170 @@
+/* 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 MADS_CORE_ERROR_H
+#define MADS_CORE_ERROR_H
+
+#include "mads/madsv2/core/general.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+#define NONE 0
+#define WARNING 1
+#define ERROR 2
+#define SEVERE 3
+
+#define ERROR_SERIES_LIST_FULL -1
+#define ERROR_MESSAGE_LIST_FULL -2
+#define ERROR_IMAGE_LIST_FULL -3
+#define ERROR_IMAGE_INTER_LIST_FULL -4
+#define ERROR_NO_MORE_PALETTE_FLAGS -5
+#define ERROR_NO_MORE_COLORS -6
+#define ERROR_SERIES_LOAD_FAILED -7
+#define ERROR_NO_MORE_MEMORY -8
+#define ERROR_WRONG_SERIES_UNLOAD_ORDER -9
+#define ERROR_PLAYER_INVENTORY_FULL -10
+#define ERROR_SEQUENCE_LIST_FULL -11
+#define ERROR_VOCAB_ACTIVE_LIST_FULL -12
+#define ERROR_NO_SUCH_OBJECT -13
+#define ERROR_NO_SUCH_MESSAGE -14
+#define ERROR_POPUP_TOO_MANY_LINES -15
+#define ERROR_KERNEL_MESSAGE_LIST_FULL -16
+#define ERROR_MESSAGE_TOO_LONG -17
+#define ERROR_DEMO_PROTECTION -18
+#define ERROR_BEEN_IN_TOO_MANY_ROOMS -19
+#define ERROR_COPY_PROTECTION -20
+#define ERROR_QUOTE_LOAD_FAILED -21
+#define ERROR_TIME_LIMIT_EXPIRED -22
+#define ERROR_QUOTE_DUPLICATE_LOAD -23
+#define ERROR_DYNAMIC_HOTSPOT_OVERFLOW -24
+#define ERROR_SPRITE_DATA_LOAD_FAILED -25
+#define ERROR_CHAIN_FAILURE -26
+#define ERROR_RESTORE_GAME_FAILURE -27
+#define ERROR_EXPLODER_EXPLODED -28
+#define ERROR_EXPLODER_NULL -29
+#define ERROR_ANIMATION_LOAD_FAILURE -30
+
+#define ERROR_BREAK_POINT -31
+
+#define ERROR_KERNEL_NO_FONTS -32
+#define ERROR_KERNEL_NO_CURSOR -33
+#define ERROR_KERNEL_NO_OBJECTS -34
+#define ERROR_KERNEL_NO_ROOM -35
+#define ERROR_KERNEL_NO_HOTSPOTS -36
+#define ERROR_KERNEL_NO_VOCAB -37
+#define ERROR_KERNEL_NO_INTERFACE -38
+#define ERROR_KERNEL_NO_ANIMATION -39
+#define ERROR_KERNEL_NO_EMS -40
+#define ERROR_KERNEL_NO_POPUP -41
+
+#define ERROR_CONV_BAD_PCODE -50
+#define ERROR_CONV_BAD_OPERATOR -51
+#define ERROR_CONV_VARIABLE_RANGE -52
+#define ERROR_POPUP_OVERFLOW -53
+#define ERROR_CONV_FLUSH -54
+#define ERROR_CONV_GET -55
+#define ERROR_CONV_RUN -56
+#define ERROR_CONV_MENU -57
+#define ERROR_CONV_NO_TEXT_LINE -58
+#define ERROR_NO_MORE_EMS -59
+#define ERROR_HEAP_REQUEST_FAILED -60
+#define ERROR_NO_MORE_HEAP -61
+#define ERROR_ORPHANED_TRIGGER -62
+#define ERROR_PEELING_DISABLED -63
+#define ERROR_POPUP_NO_ITEMS -64
+#define ERROR_WRITE_SAVE_DIRECTORY -65
+#define ERROR_MEMORY_CHAIN_CORRUPT -66
+#define ERROR_POPUP_PRESERVE_FAILURE -67
+#define ERROR_TOO_MANY_DAMN_HOTSPOTS -68
+#define ERROR_VARIANT_LOAD_FAILURE -69
+
+
+#define MODULE_MATTE 1
+#define MODULE_INTER 2
+#define MODULE_PAL 3
+#define MODULE_ROOM 4
+#define MODULE_KERNEL 5
+#define MODULE_OBJECT 6
+#define MODULE_UNKNOWN 7
+#define MODULE_VOCAB 8
+#define MODULE_TEXT 9
+#define MODULE_POPUP 10
+#define MODULE_MEMORY 11
+#define MODULE_ROOM_LOADER 12
+#define MODULE_SPRITE_LOADER 13
+#define MODULE_ANIM_LOADER 14
+#define MODULE_FONT_LOADER 15
+#define MODULE_TEXT_LOADER 16
+#define MODULE_VOCAB_LOADER 17
+#define MODULE_DEMO 18
+#define MODULE_PLAYER 19
+#define MODULE_LOCK 20
+#define MODULE_QUOTE 21
+#define MODULE_GAME 22
+#define MODULE_GAME_MENU 23
+#define MODULE_EXPLODER 24
+#define MODULE_ANIM 25
+#define MODULE_CONV 26
+#define MODULE_POPUP_DIALOG 27
+#define MODULE_HOTSPOT 28
+
+
+extern int error_abort;
+extern char error_string[80];
+
+extern void (*error_service_routine)();
+extern void (*error_service_routine_2)();
+
+
+/* error_1.cpp */
+void error_report(int error, int severity, int module,
+ long data1, long data2);
+
+int error_scan(char *target, char *name, int number);
+
+void error_dump_file(char *file_name);
+
+/* error_2.cpp */
+void error_break_point(int data1, int data2);
+
+
+/* error_3.cpp */
+void error_watch_point(char *message, long data1, long data2);
+
+
+/* error_4.cpp */
+void error_check_memory(void);
+
+
+/* error_5.cpp */
+void error_file_point(char *message, long data1, long data2);
+
+
+/* error_6.cpp */
+void error_entry(char *name, char *message);
+void error_exit(char *name, char *message);
+void error_put(char *name, int item);
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/fileio.h b/engines/mads/madsv2/core/fileio.h
new file mode 100644
index 00000000000..e2916d4bb1c
--- /dev/null
+++ b/engines/mads/madsv2/core/fileio.h
@@ -0,0 +1,151 @@
+/* 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 MADS_CORE_FILEIO_H
+#define MADS_CORE_FILEIO_H
+
+namespace MADS {
+namespace MADSV2 {
+
+#define fread_bufsize 1024
+
+extern int fileio_suppress_unbuffering;
+
+
+/* fileio_1 */
+void fileio_purge_trailing_spaces(char *myline);
+
+/* fileio_2 */
+void fileio_name_new_ext(char *bakfile,
+ char *mainfile,
+ char *new_ext);
+
+/* fileio_3 */
+char *fileio_ffgets(char *mystring,
+ int num,
+ Common::Stream *stream);
+
+/* fileio_4 */
+int fileio_ffputs(char *mystring,
+ Common::Stream *stream);
+
+/* fileio_5 */
+char *fileio_fix_lf_input(char *mystring);
+
+/* fileio_6 */
+void fileio_fix_lf_output(char *mystring);
+
+int fileio_copy(char *source, char *dest);
+
+
+/* fileio_7 */
+long fileio_setpos(Common::Stream *handle, long pos);
+
+
+/* fileio_8 */
+long fileio_fread_f(void *buffer, long size,
+ long count, Common::Stream *stream);
+
+/* fileio_9 */
+long fileio_fwrite_f(void *buffer, long size,
+ long count, Common::Stream *stream);
+
+/* fileio_a */
+long fileio_file_to_file(Common::Stream *from, Common::Stream *to, long count);
+
+/* fileio_b */
+long fileio_get_file_size(char *filename);
+
+/* fileio_c */
+int fileio_exist(char *inp);
+
+/* fileio_d */
+char * fileio_get_filetype(char *outp, char *inp);
+
+/* fileio_e */
+long fileio_get_file_time(char *filename);
+
+/* fileio_f */
+char * fileio_read_header(char *target, Common::Stream *handle);
+void fileio_write_header(char *text, Common::Stream *handle);
+
+/* fileio_g */
+char *fileio_get_line(char *target, Common::Stream *handle);
+int fileio_put_line(char *source, Common::Stream *handle);
+
+/* fileio_h */
+long fileio_get_disk_free(char drive);
+
+/* fileio_i */
+void fileio_add_ext(char *name, char *ext);
+void fileio_new_ext(char *target,
+ char *name,
+ char *ext);
+
+/* fileio_j */
+int fileio_logpath(char *path);
+
+/* fileio_k */
+char *fileio_parse_filename(char *target,
+ char *filepath);
+char *fileio_parse_path(char *target,
+ char *filepath);
+
+/* fileio_l */
+char *fileio_swap_path(char *target,
+ char *base,
+ char *file);
+
+/* fileio_m */
+char *fileio_join_path(char *target,
+ char *path,
+ char *file);
+
+/* fileio_n */
+void fileio_get_volume_label(char *volume_label, char drive_letter);
+
+/* fileio_o */
+int fileio_set_file_time(char *filename, long new_time);
+
+/* fileio_p */
+int fileio_get_file_attributes(char *filename, word *attributes);
+
+/* fileio_q */
+int fileio_set_file_attributes(char *filename, word attributes);
+
+/* fileio_r */
+int fileio_read_till_null(char *target, Common::Stream *handle);
+
+/* fileio_s */
+char *fileio_prepend(char *target,
+ char *source,
+ char *prepend);
+
+/* fileio_t */
+char *fileio_chop_ext(char *target, char *source);
+
+/* fileio_u */
+void fileio_purge_all_spaces(char *text);
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/font.h b/engines/mads/madsv2/core/font.h
new file mode 100644
index 00000000000..51766490895
--- /dev/null
+++ b/engines/mads/madsv2/core/font.h
@@ -0,0 +1,78 @@
+/* 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 MADS_CORE_FONT_H
+#define MADS_CORE_FONT_H
+
+#include "common/scummsys.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+#define FONT_SIZE 128
+#define FONT_MAX_WIDTH 255
+#define FONT_MAX_HEIGHT 200
+
+struct FontBuf {
+ byte max_y_size;
+ byte max_x_size;
+
+ byte width[FONT_SIZE];
+ byte *data[FONT_SIZE];
+};
+
+typedef struct FontBuf Font;
+typedef Font *FontPtr;
+
+extern byte font_colors[4];
+
+extern FontPtr font_inter; /* Font handle for interface text */
+extern FontPtr font_main; /* Font handle for main sentence */
+extern FontPtr font_conv; /* Font handle for conversations */
+extern FontPtr font_menu; /* Font handle for menu stuff */
+extern FontPtr font_misc; /* Font handle for symbols & icons */
+
+/* font_1.cpp */
+FontPtr font_load(char *name);
+
+/* font_2.cpp */
+int font_write(FontPtr font, Buffer *target,
+ char *out_string, int x, int y,
+ int auto_spacing);
+
+/* font_3.cpp */
+void font_set_colors(int background,
+ int high_intense,
+ int med_intense,
+ int low_intense);
+
+/* font_4.cpp */
+int font_string_width(FontPtr font,
+ char *out_string,
+ int auto_spacing);
+
+/* font_5.cpp */
+void font_init(FontPtr font);
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/game.h b/engines/mads/madsv2/core/game.h
new file mode 100644
index 00000000000..fb5aecd9087
--- /dev/null
+++ b/engines/mads/madsv2/core/game.h
@@ -0,0 +1,294 @@
+/* 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 MADS_CORE_GAME_H
+#define MADS_CORE_GAME_H
+
+#include "mads/madsv2/core/general.h"
+#include "mads/madsv2/core/player.h"
+#include "mads/madsv2/core/mads.h"
+#include "mads/madsv2/core/heap.h"
+#include "mads/madsv2/core/popup.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+#define game_version "1.22" /* Version of game control code */
+#define game_date "27-Jul-92"
+
+#define HARD_MODE 0 /* Difficulty levels */
+#define EASY_MODE 1
+
+#define TENTH_SECOND 6 /* Timing definitions */
+#define QUARTER_SECOND 15
+#define THIRD_SECOND 20
+#define HALF_SECOND 30
+
+#define ONE_SECOND 60
+#define TWO_SECONDS 120
+#define THREE_SECONDS 180
+#define FOUR_SECONDS 240
+#define FIVE_SECONDS 300
+#define SIX_SECONDS 360
+#define SEVEN_SECONDS 420
+#define EIGHT_SECONDS 480
+#define NINE_SECONDS 540
+#define TEN_SECONDS 600
+#define FIFTEEN_SECONDS 900
+#define THIRTY_SECONDS 1800
+#define ONE_MINUTE 3600
+#define TWO_MINUTES 7200
+#define THREE_MINUTES 10800
+#define UNTIL_THE_COW_EXPLODES 9999999
+
+#define CURSOR_NORMAL 1 /* Cursor types */
+#define CURSOR_WAIT 2
+#define CURSOR_DOWN 3
+#define CURSOR_UP 4
+#define CURSOR_LEFT 5
+#define CURSOR_RIGHT 6
+
+#define FACING_NORTH 8 /* Player facings */
+#define FACING_SOUTH 2
+#define FACING_EAST 6
+#define FACING_WEST 4
+#define FACING_NORTHEAST 9
+#define FACING_SOUTHEAST 3
+#define FACING_SOUTHWEST 1
+#define FACING_NORTHWEST 7
+#define FACING_NONE 5
+
+
+#define DEBUGGER_NONE -1
+#define DEBUGGER_MAIN 0
+#define DEBUGGER_HELP 1
+#define DEBUGGER_PALETTE 2
+#define DEBUGGER_SCRATCH 3
+#define DEBUGGER_GLOBAL 4
+#define DEBUGGER_CONVERSATION 5
+#define DEBUGGER_MATTE 6
+#define DEBUGGER_MEMORY 7
+#define DEBUGGER_STATE 8
+#define DEBUGGER_PAL_LIST_1 9
+#define DEBUGGER_PAL_LIST_2 10
+
+#define DEBUGGER_MAX_WATCH 12
+
+
+int int_sprite[6];
+
+extern int selected_intro;
+
+#define fx_int_journal 0
+#define fx_int_backpack 1
+#define fx_int_candle 2
+#define fx_int_exit 3
+#define fx_int_dooropen 4
+#define fx_int_candle_on 5
+
+
+#define EXTRA_MAX_INV_OBJECTS 18 /* 16, + background, + open backpack */
+
+/* int inven_ss[EXTRA_MAX_INV_OBJECTS]; */
+/* int inven_seq[EXTRA_MAX_INV_OBJECTS]; */
+
+
+/* Declared by Taranjeet for OUAF Journal */
+Player journal_player;
+int journal_room;
+
+#define GAME_MAIN_MENU 1 /* Game menus */
+#define GAME_SAVE_MENU 2
+#define GAME_RESTORE_MENU 3
+#define GAME_OPTIONS_MENU 4
+#define GAME_DIFFICULTY_MENU 5
+#define GAME_ALERT_MENU 6
+#define GAME_SCORE_MENU 7
+#define GAME_CD_MENU 8
+
+#define GAME_MENU_MAX_ITEMS 20 /* Max number of menu items */
+#define GAME_MAX_SAVE_SLOTS 99 /* Max number of save slots */
+#define GAME_MAX_SAVE_LENGTH 63 /* Max length of save name */
+#define GAME_MAX_SAVE_WIDTH 255 /* Max pixel width of save name*/
+#define GAME_MAX_SAVES_ON_SCREEN 7 /* Max saves on screen at once */
+
+#define GAME_SAVE_SLOT_MEMORY (GAME_MAX_SAVE_SLOTS * (GAME_MAX_SAVE_LENGTH + 1))
+#define GAME_DIALOG_HEAP 4096
+#define GAME_FUDGE_FACTOR 256
+#define GAME_MENU_HEAP (GAME_SAVE_SLOT_MEMORY + GAME_DIALOG_HEAP + GAME_FUDGE_FACTOR)
+
+
+#define GAME_MENU_SCROLL_FIRST 20 /* Scrolling delays */
+#define GAME_MENU_SCROLL_SECOND 8
+
+#define GAME_MENU_CENTER -1 /* Center item on menu */
+#define GAME_MENU_SPECIAL -2 /* Center on special character */
+#define GAME_MENU_RIGHT -3 /* Right-justify text */
+
+#define WIN_NOTHING 0
+#define WIN_QUICK_DEATH 1
+#define WIN_SLOW_DEATH 2
+#define WIN_ALL_THE_MONEY 3
+#define WIN_A_HEAD_POW 4
+
+extern byte game_restore_flag; /* Flag if restoring game */
+extern byte game_autosaved; /* Flag if autosaved */
+
+extern byte game_mouse_cursor_fix; /* Mouse cursor fix */
+
+extern word abort_value;
+extern long abort_clock;
+
+extern int logfile_enabled;
+extern Common::Stream *logfile_handle;
+
+extern int sound_board_address;
+extern int sound_board_type;
+extern int sound_board_irq;
+
+extern char chain_line[80];
+extern int chain_flag;
+extern int force_chain;
+extern int key_abort_level;
+
+extern int game_keystroke;
+extern int game_any_keystroke;
+
+extern int win_status;
+
+extern long correction_clock;
+
+
+extern char config_file_name[20];
+extern char save_game_key[8];
+extern char restart_game_key[40];
+extern char save_game_buf[20];
+
+extern void (*game_menu_routine)(); /* Game Menu routines */
+extern void (*game_menu_init)();
+extern void (*game_menu_exit)();
+extern void (*game_emergency_save)();
+
+
+extern int debugger;
+extern int debugger_state;
+extern int debugger_matte_before;
+extern int debugger_memory_skip;
+extern int debugger_memory_all;
+extern int debugger_memory_keywait;
+extern void (*debugger_reset)(); /* Debugger reset routine */
+extern void (*debugger_update)(); /* Debugger update routine */
+
+
+extern void (*section_preload_code_pointer)();
+extern void (*section_init_code_pointer)();
+extern void (*section_room_constructor)();
+extern void (*section_daemon_code_pointer)();
+extern void (*section_pre_parser_code_pointer)();
+extern void (*section_parser_code_pointer)();
+extern void (*section_error_code_pointer)();
+extern void (*section_music_reset_pointer)();
+
+
+extern void (*room_preload_code_pointer)();
+extern void (*room_init_code_pointer)();
+extern void (*room_daemon_code_pointer)();
+extern void (*room_pre_parser_code_pointer)();
+extern void (*room_parser_code_pointer)();
+extern void (*room_error_code_pointer)();
+extern void (*room_shutdown_code_pointer)();
+
+
+
+/* global.c */
+extern char global_release_name[];
+extern char global_release_version[];
+extern char global_release_date[];
+extern char global_release_copyright[];
+
+extern int global[];
+extern int global_list_size;
+
+/* global.c */
+void global_init_code(void);
+void global_daemon_code(void);
+void global_pre_parser_code(void);
+void global_parser_code(void);
+void global_error_code(void);
+
+void global_room_init(void);
+void global_verb_filter(void);
+
+void global_sound_driver(void);
+
+void global_section_constructor(void);
+
+/* global_4.c */
+void global_game_menu(void);
+void global_menu_system_init(void);
+void global_menu_system_shutdown(void);
+void global_emergency_save(void);
+
+/* global_5.c */
+void global_read_config_file(void);
+void global_write_config_file(void);
+void global_load_config_parameters(void);
+void global_unload_config_parameters(void);
+
+/* global_6.c */
+int global_copy_verify(void);
+
+
+/* game_1.c */
+void game_main(int argc, char **argv);
+
+
+/* game_2.c */
+void game_save_name(int id);
+
+/* game_4.c */
+void game_exec_function(void (*(target))());
+
+
+/* game_6.c */
+void game_debugger_reset(void);
+void game_debugger(void);
+
+
+/* game_5.c */
+extern char game_save_file[13]; /* Save directory file */
+extern char *game_save_directory; /* Save directory pointer */
+
+extern int game_preserve_handle; /* scr_depth preserve */
+
+extern Heap game_menu_heap; /* Custom heap for menu */
+extern Popup *game_menu_popup; /* Popup structure for menu */
+
+
+/* game_5.c */
+void game_write_save_directory(void);
+void game_menu_setup(void);
+void game_menu_shutdown(void);
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/general.h b/engines/mads/madsv2/core/general.h
new file mode 100644
index 00000000000..2e7a42c0716
--- /dev/null
+++ b/engines/mads/madsv2/core/general.h
@@ -0,0 +1,140 @@
+/* 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 MADS_CORE_GENERAL_H
+#define MADS_CORE_GENERAL_H
+
+#include "common/scummsys.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+/* Code optimization parameters */
+
+#define fastcall /* register calling convention */
+#define aggressive true /* allow "Z" optimizations */
+
+/* universal interlanguage data types */
+
+typedef uint32 dword; /* generic 32 bit data */
+typedef uint16 word; /* generic 16 bit data */
+
+/* vertical data types */
+
+typedef struct {
+ byte r, g, b;
+} RGBcolor; /* A single palette color */
+typedef RGBcolor Palette[256]; /* An entire Mcga palette */
+typedef byte PaletteMap[256][3]; /* An entire Mcga palette #2 */
+
+#define pal_color(p,i,c) (*(((byte *)&p[i])+c))
+
+typedef struct { /* Video buffer structure */
+ int y; /* Wrap value for buffer (y size) */
+ int x; /* X size of buffer */
+ byte *data; /* Pointer to actual data */
+} Buffer;
+
+#define far_string(v,s) char _based(_segname("FARSTRING")) v[] = s;
+
+
+/* Timer and clock stuff */
+
+#define clock_address 0x0040006c /* BIOS clock address */
+#define dos_timer_address (long *)clock_address
+
+#define interrupt_controller 0x20 /* Interrupt controller */
+#define end_of_interrupt 0x20 /* End of interrupt ack */
+
+#define timer_controller 0x43 /* Timer controller port */
+#define timer_channel_0 0x40 /* Timer channel 0 data */
+#define timer_channel_1 0x41 /* Timer channel 1 data */
+#define timer_channel_2 0x42 /* Timer channel 2 data */
+
+#define time_set 0x36 /* Set timer countdown 00110110b */
+
+#define timer_speed_600 1880 /* 600/s 1960? */
+#define timer_speed_300 3920 /* 300/s */
+#define timer_speed_60 19600 /* 60/s */
+
+#define wait_state() _asm {jmp short $+2}
+
+
+/* video defines */
+
+#define video_x 320 /* Screen max X size */
+#define video_y 200 /* Screen max Y size */
+
+#define display_y 156 /* Picture area max Y size */
+
+#define color_text_video (byte *)0xb8000000 /* text mode address */
+#define mono_text_video (byte *)0xb0000000 /* herc/mono address */
+#define mcga_video (byte *)0xa0000000 /* 256 color address */
+#define tandy_video (byte *)0xb8000000 /* Tandy clr address */
+#define ega_video (byte *)0xa0000000 /* EGA color address */
+#define iaca (byte *)0x004000f0 /* The bad place */
+
+#define text_mode 0x03
+#define mono_text_mode 0x07
+#define tandy_mode 0x09
+#define ega_mode 0x0d
+#define mcga_mode 0x13
+
+#define secret_video_area ((color_text_video) + (PACK_EXPLODE_SIZE))
+#define secret_video_size (32768L - PACK_EXPLODE_SIZE)
+
+/* Things-you-need-for-Tandy */
+
+#define dos_memory (byte *)0x00400013 /* Dos memory # */
+#define abs_memory (byte *)0x00400015 /* Abs memory # */
+
+/* logical defines (boolean etc) */
+#define yes true //(-1)
+#define no false //0
+#if 0
+#define true (-1)
+#define false 0
+#endif
+
+#define none 0
+#define stop 99
+
+
+/* misc functional defines */
+
+#define getrandom( min, max ) ((rand() % (int)(((max)+1) - (min))) + (min))
+
+
+#define hibyte(x) ( (byte) ( (x) >> 8 ) )
+#define lobyte(x) ( (byte) ( ( (word) ( (x) << 8 ) ) >> 8 ) )
+
+#define neg(x) ((~(x))+1) /* Negate w/o multiply */
+#define abs(x) ( ((x)>0) ? (x) : neg(x) ) /* Abs val w/o multiply */
+
+#define sgn(x) ( ((x)>0) ? 1 : ( ((x)<0) ? -1 : 0 ) ) /* sign */
+#define sign(x) ( ((x) > 0.0) ? 1 : ( ((x) < 0.0) ? -1 : 0 ) ) /* sign (double) */
+
+#define sgn_in(x,s) ( ((s) >= 0) ? (x) : (neg(x)) ) /* Incorporate sign */
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/heap.h b/engines/mads/madsv2/core/heap.h
new file mode 100644
index 00000000000..cfd0eb94dad
--- /dev/null
+++ b/engines/mads/madsv2/core/heap.h
@@ -0,0 +1,52 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef MADS_CORE_HEAP_H
+#define MADS_CORE_HEAP_H
+
+#include "mads/madsv2/core/general.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+typedef struct {
+ byte module; /* Identifier for heap module */
+ byte destruct; /* Flag if can be destroyed */
+ char *base; /* Base memory pointer for heap */
+ char *marker; /* Pointer to free area */
+ long base_size; /* Original size of the heap */
+ long size; /* Free space remaining */
+} Heap;
+
+/* heap_1.c */
+int heap_create(Heap *heap, int module_id,
+ long heap_size, char *heap_name);
+void heap_destroy(Heap *heap);
+void heap_declare(Heap *heap, int module_id,
+ char *buffer, long heap_size);
+
+/* heap_1.c */
+void *heap_get(Heap *heap, long size);
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/hspot.h b/engines/mads/madsv2/core/hspot.h
new file mode 100644
index 00000000000..b3c0fcb31d8
--- /dev/null
+++ b/engines/mads/madsv2/core/hspot.h
@@ -0,0 +1,88 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef MADS_CORE_HSPOT_H
+#define MADS_CORE_HSPOT_H
+
+#include "mads/madsv2/core/general.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+#define max_hot_spots 80 /* Size of hotspot list */
+#define max_hot_lists 2 /* Maximum # of lists */
+
+#define HS_ALL -1 /* Pass in ERASE to wipe entire class */
+#define HS_DEATH -1 /* Used for marking spots to be killed */
+#define HS_STACK_SIZE 5 /* Size of stack */
+
+typedef struct {
+ int ul_x, ul_y; /* Upper Left */
+ int lr_x, lr_y; /* Lower Right */
+ int _class; /* Clasification */
+ int num; /* Spot number */
+ int video_mode; /* Spot video mode */
+ int active; /* TRUE if active */
+} Spot;
+
+#define HS_SIZE 16 /* Size of above structure */
+
+
+extern Spot spot[max_hot_spots + 1];
+extern int numspots;
+
+
+extern int hotkeys[max_hot_spots + 1];
+
+
+/* hspot_1.c */
+int hspot_add(int ul_x, int ul_y,
+ int lr_x, int lr_y,
+ int class_, int num, int video_mode);
+
+/* hspot_2.c */
+int hspot_push(void);
+int hspot_pop(void);
+
+/* hspot_4.c */
+int hspot_remove(int class_, int num);
+
+/* hspot_5.c */
+void hspot_toggle(int class_, int num, int active);
+
+/* hspot_6.c */
+void hspot_wipe(void);
+int hspot_key(int key);
+int hspot_begin(int x, int y, int class_, int num, int hotkey);
+int hspot_end(void);
+
+void hspot_dummy(void);
+
+/* hspot_7.c */
+int hspot_which(int x, int y, int video_mode);
+
+/* hspot_8.c */
+int hspot_which_reverse(int x, int y, int video_mode);
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/image.h b/engines/mads/madsv2/core/image.h
new file mode 100644
index 00000000000..ab14844b1f8
--- /dev/null
+++ b/engines/mads/madsv2/core/image.h
@@ -0,0 +1,50 @@
+/* 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 MADS_CORE_IMAGE_H
+#define MADS_CORE_IMAGE_H
+
+#include "common/scummsys.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+struct ImageBuf {
+ int flags; /* refers to the index of the corresponding frame in the anim struct */
+ /* ^^ only true for images which have been anim_loaded... */
+ /* anim_view dumps these images into lists using flags to tell */
+ /* when they should be put; the flags then become actual flags */
+ /* like IMAGE_INCOMING, IMAGE_STATIC, or about to be erased, or ... */
+ byte segment_id; /* i'm a part of this segment */
+ byte series_id; /* this is my series */
+ int sprite_id; /* sprite within the series */
+ int x, y;
+ byte depth;
+ byte scale;
+};
+
+typedef struct ImageBuf Image;
+typedef Image *ImagePtr;
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/imath.h b/engines/mads/madsv2/core/imath.h
new file mode 100644
index 00000000000..48b36c1cabe
--- /dev/null
+++ b/engines/mads/madsv2/core/imath.h
@@ -0,0 +1,48 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef MADS_CORE_IMATH_H
+#define MADS_CORE_IMATH_H
+
+#include "mads/madsv2/core/general.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+/*
+/* imath_1.asm: integer math routines out of the MPS libraries
+*/
+int imath_distance(int side_a, int side_b, int threshold);
+int imath_hypot(int side_a, int side_b);
+word imath_isqrt(long square);
+
+
+/* imath_2.c */
+void imath_circular_arc(word *buffer, int radius);
+
+
+/* imath_3.c */
+int imath_random(int from, int unto);
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/inter.h b/engines/mads/madsv2/core/inter.h
new file mode 100644
index 00000000000..f8f0ad7555b
--- /dev/null
+++ b/engines/mads/madsv2/core/inter.h
@@ -0,0 +1,297 @@
+/* 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 MADS_CORE_INTER_H
+#define MADS_CORE_INTER_H
+
+#include "mads/madsv2/core/general.h"
+#include "mads/madsv2/core/anim.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+#define inter_columns 5
+#define inter_delta_y 8
+
+#define inter_base_x 0
+#define inter_size_y (video_y - display_y)
+#define inter_base_y (video_y - inter_size_y)
+
+#define command_base_x 2
+#define command_base_y 3
+#define command_delta_x 32
+
+#define inven_base_x 90
+#define inven_base_y 3
+#define inven_delta_x 69
+
+#define action_base_x 240
+#define action_base_y 3
+#define action_delta_x (video_x - action_base_x)
+
+#define dialog_delta_x 318
+
+#define inter_object_base_x 160
+#define inter_object_base_y 3
+#define inter_object_size_x 72
+#define inter_object_size_y 36
+
+#define INTER_SPINNING_OBJECT 200
+#define INTER_TEXT_UPDATE 201
+#define INTER_OBJECT_SPACE 1200 /* Memory region for objects */
+
+#define INTER_STRING_LENGTH 64
+
+#define INTER_COMMANDS (inter_columns * 2)
+
+#define INVEN_MAX_OBJECTS 20 /* Can only carry ... objects */
+
+#define INTER_BUILDING_SENTENCES 0 /* Normal sentence building mode */
+#define INTER_CONVERSATION 1 /* Special conversation mode */
+#define INTER_LIMITED_SENTENCES 2 /* Build only from room hotspots */
+
+#define ABSOLUTE_MODE 0 /* Hotspot mouse cursor is absolute */
+#define RELATIVE_MODE 1 /* Hotspot mouse cursor is relative */
+
+#define NORMAL 0
+#define LEFT_SELECT 1
+#define RIGHT_SELECT 2
+
+#define VERB_ONLY 0
+#define VERB_THIS 1
+#define VERB_THAT 2
+
+
+#define PREP_NONE 0
+#define PREP_WITH 1
+#define PREP_TO 2
+#define PREP_AT 3
+#define PREP_FROM 4
+
+#define PREP_ON 5
+#define PREP_IN 6
+#define PREP_UNDER 7
+#define PREP_BEHIND 8
+
+#define PREP_RELATIONAL 255
+
+
+#define SYNTAX_SINGULAR 0 /* "Give me that ...." */
+#define SYNTAX_PLURAL 1 /* "Give me those ...." */
+#define SYNTAX_PARTITIVE 2 /* "Give me some ...." */
+#define SYNTAX_SINGULAR_MASC 3 /* Singular masculine (him) */
+#define SYNTAX_SINGULAR_FEM 4 /* Singular feminine (her) */
+#define SYNTAX_SINGULAR_LIVING 5 /* Singular living (it) */
+#define SYNTAX_MASC_NOT_PROPER 6 /* Masculine, non-proper */
+#define SYNTAX_FEM_NOT_PROPER 7 /* Feminine, non-proper */
+
+#define MAX_SYNTAX 8 /* Number of syntax forms */
+
+/* Mouse stroke type categories */
+
+#define STROKE_NONE 0 /* Unknown or none */
+#define STROKE_COMMAND 1 /* In main verb list */
+#define STROKE_INVEN 2 /* In user inventory */
+#define STROKE_ACTION 3 /* In object-verb list */
+#define STROKE_INTERFACE 4 /* In room hotspot area */
+#define STROKE_SPECIAL_INVEN 5 /* On spinning object box */
+#define STROKE_DIALOG 6 /* Dialog conversation */
+#define STROKE_SCROLL 7 /* Stroke in scroll box */
+
+#define STROKE_DYNAMIC 8 /* Special mask for dynamic */
+
+#define STROKE_MASK 7 /* Masks out dynamic */
+#define STROKE_MAX 7 /* Highest stroke class */
+
+#define SCROLL_UP 1 /* Scroll up button */
+#define SCROLL_DOWN 2 /* Scroll down button */
+#define SCROLL_ELEVATOR 3 /* Elevator bar */
+#define SCROLL_THUMB 4 /* Thumb mark (pseudo-item) */
+
+#define inter_scroll_x1 73 /* Scroll bar hotspot boundaries */
+#define inter_scroll_x2 81
+#define inter_up_y1 3
+#define inter_up_y2 9
+#define inter_down_y1 35
+#define inter_down_y2 41
+#define inter_elevator_y1 11
+#define inter_elevator_y2 33
+#define inter_thumb_y1 14
+#define inter_thumb_y2 31
+
+#define inter_thumb_range ((inter_thumb_y2 - inter_thumb_y1) + 1)
+
+/* Interface status categories */
+
+#define AWAITING_NONE 0
+#define AWAITING_COMMAND 1 /* Virgin: waiting for a verb */
+#define AWAITING_THIS 2 /* Waiting for 1st object */
+#define AWAITING_THAT 3 /* Waiting for second object */
+#define AWAITING_RIGHT_MOUSE 4 /* Waiting for button release */
+
+#define INTER_MESSAGE_COLOR 254
+
+
+#define inter_verb inter_words[0]
+#define inter_main_noun inter_words[1]
+#define inter_second_noun inter_words[2]
+
+
+
+struct VerbBuf {
+ word id;
+ byte verb_type;
+ byte prep_type;
+};
+typedef struct VerbBuf Verb;
+
+extern AnimInterPtr inter_anim; /* Background animation script */
+
+extern int inter_auxiliary_click; /* Clicks during downtime */
+
+extern int inter_mouse_x; /* Cooked mouse location X */
+extern int inter_mouse_y; /* Cooked mouse location Y */
+extern int inter_mouse_type; /* Hotspot list identifier */
+
+extern int inter_object_sprite;
+extern int inter_object_series;
+
+extern int inter_spinning_objects; /* Flag if objects rotating */
+extern int inter_animation_running; /* Flag if background animation */
+
+extern byte *inter_objects_block; /* Place for loading object series */
+extern long inter_objects_block_size;
+
+
+extern int inter_input_mode; /* Interface input mode */
+
+extern char *inter_dialog_strings[inter_columns]; /* String pointers for dialog mode */
+extern int inter_dialog_results[inter_columns]; /* Result numbers for dialog mode */
+
+
+extern Verb command[INTER_COMMANDS]; /* Main Verb List */
+
+extern int inven[INVEN_MAX_OBJECTS]; /* Inventory index */
+extern int inven_num_objects; /* Inventory size */
+
+extern int active_inven; /* The selected inventory item */
+
+extern int right_command; /* Right mouse main verb */
+extern int left_command; /* Left mouse main verb */
+extern int left_inven; /* Left mouse inventory */
+extern int left_action; /* Left mouse secondary verb */
+extern int right_action; /* Right mouse secondary verb */
+
+
+extern int inter_command; /* Command # index */
+extern int inter_main_object; /* Object # index */
+extern int inter_second_object; /* Object # index */
+extern int inter_prep; /* Prep # of sentence's preposition */
+
+extern int inter_main_syntax; /* Syntax form of first noun */
+extern int inter_second_syntax; /* Syntax form of second noun */
+
+extern int inter_command_source; /* Stroke types for sentence components */
+extern int inter_main_object_source;
+extern int inter_second_object_source;
+
+extern int inter_look_around; /* "Look around" command */
+
+extern int inter_point_established; /* Clicked point for possible walk-to */
+extern int inter_point_x;
+extern int inter_point_y;
+
+extern int inter_awaiting; /* Current awaiting status */
+
+
+extern int inter_words[3]; /* Vocabulary words for sentence */
+extern char inter_sentence[64]; /* Sentence building buffer */
+
+extern int inter_sentence_ready; /* Flag if a sentence ready to go */
+extern int inter_report_hotspots; /* True = show hotspots even with no button pressed */
+
+extern int inter_force_rescan; /* Force mouse rescan even if not changed */
+extern int inter_base_hotspots; /* Number of basic room hotspots */
+
+extern long inter_base_time; /* Timing marker for interface */
+
+
+extern int scrollbar_active; /* Active scrollbar item */
+extern int scrollbar_elevator;
+extern int scrollbar_old_active;
+extern int scrollbar_old_elevator;
+
+extern int scrollbar_stroke_type;
+extern int scrollbar_quickly;
+extern long scrollbar_base_timing;
+
+
+extern int inter_spot_class;
+extern int inter_spot_index;
+extern int inter_spot_id;
+
+extern byte spot_base[STROKE_MAX]; /* Hotspot list base markers (by stroke type) */
+
+
+extern char istring_prep_names[9][7]; /* Preposition strings */
+
+extern char istring_look_around[12]; /* Misc. hard coded */
+extern char istring_use[5];
+extern char istring_to[4];
+extern char istring_walk_to[9];
+extern char istring_space[2];
+
+extern char istring_object_pronoun[MAX_SYNTAX][8]; /* Object pronouns */
+extern char istring_subject_pronoun[MAX_SYNTAX][8]; /* Subject pronouns */
+extern char istring_demonstrative[MAX_SYNTAX][8]; /* Demonstratives */
+
+extern int inter_object_id;
+extern char inter_object_buf[20];
+extern void (*inter_object_routine)();
+
+
+/* inter_1.c */
+void inter_prepare_background(void);
+void inter_setup_hotspots(void);
+void inter_set_active_inven(int inven_id);
+void inter_give_to_player(int this_);
+void inter_move_object(int object_id, int location);
+void inter_init_sentence(void);
+void inter_main_loop(int allow_input);
+
+void inter_refresh(void);
+void inter_screen_update(void);
+
+void inter_turn_off_object(void);
+void inter_spin_object(int object_id);
+int inter_allocate_objects(void);
+void inter_deallocate_objects(void);
+
+void inter_reset_dialog(void);
+int inter_add_dialog(char *string, int result);
+
+/* inter_2.c */
+int inter_load_background(char *name, Buffer *target);
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/kernel.h b/engines/mads/madsv2/core/kernel.h
new file mode 100644
index 00000000000..da834707515
--- /dev/null
+++ b/engines/mads/madsv2/core/kernel.h
@@ -0,0 +1,670 @@
+/* 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 MADS_CORE_KERNEL_H
+#define MADS_CORE_KERNEL_H
+
+#include "mads/madsv2/core/general.h"
+#include "mads/madsv2/core/anim.h"
+#include "mads/madsv2/core/color.h"
+#include "mads/madsv2/core/room.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+/* Some handy location macros */
+
+#define NOWHERE 1 /* Does not exist */
+#define PLAYER 2 /* Player's posession */
+#define HERE room_id /* In current room */
+
+#define KERNEL_INTERRUPT_STACK_SIZE 256 /* Size of interrupt stack */
+
+#define KERNEL_RESERVED_LOW_COLORS 26 /* Colors to reserve at bottom of palette */
+#define KERNEL_RESERVED_HIGH_COLORS 10 /* Colors to reserve at top of palette */
+
+#define KERNEL_MESSAGE_COLOR_BASE 16 /* 1st color to use for messages */
+#define KERNEL_MESSAGE_COLOR_BASE_2 252 /* 1st color to use for second message */
+#define KERNEL_MESSAGE_COLOR_BASE_3 254 /* 1st color to use for third message */
+
+#define KERNEL_OBJECT_COLOR_BASE 246 /* 1st color to use for rotating objects */
+
+#define KERNEL_SEGMENT_SYSTEM 0xff /* System related images */
+#define KERNEL_SEGMENT_PLAYER 0xfe /* Player sprite images */
+#define KERNEL_SEGMENT_ANIMATION_HIGH 0xfd /* Highest possible anim */
+#define KERNEL_SEGMENT_ANIMATION 0x80 /* Animation based images */
+
+#define KERNEL_MAX_SEQUENCES 30 /* Max concurrent sequences */
+
+#define KERNEL_MAX_TRIGGERS 5 /* Max triggers for a sequence */
+
+#define KERNEL_TRIGGER_EXPIRE 0 /* Trigger when sequence expires */
+#define KERNEL_TRIGGER_LOOP 1 /* Trigger when sequence loops around */
+#define KERNEL_TRIGGER_SPRITE 2 /* Trigger when sequence reaches sprite */
+
+#define KERNEL_TRIGGER_PARSER 0 /* Sequence triggers parser code */
+#define KERNEL_TRIGGER_DAEMON 1 /* Sequence triggers daemon code */
+#define KERNEL_TRIGGER_PREPARSE 2 /* Sequence triggers preparser */
+
+#define KERNEL_DEFAULT 0 /* Default for parameter */
+#define KERNEL_FIRST -1 /* Use first sprite in series */
+#define KERNEL_LAST -2 /* Use last sprite in series */
+
+#define KERNEL_SPECIAL_TIMING 0xff /* Special sequence type for */
+ /* "timing only" triggers */
+
+#define KERNEL_MESSAGE_ANIM 0x100 /* Message attached to anim */
+#define KERNEL_MESSAGE_ACTIVE 0x80 /* Flag if message is active */
+#define KERNEL_MESSAGE_EXPIRED 0x40 /* Flag if message expired */
+#define KERNEL_MESSAGE_CENTER 0x20 /* Message centered at coord */
+#define KERNEL_MESSAGE_RIGHT 0x10 /* Message to right of coord */
+#define KERNEL_MESSAGE_TELETYPE 0x08 /* Message teletypes in */
+#define KERNEL_MESSAGE_ATTACHED 0x04 /* Message attached to sprite*/
+#define KERNEL_MESSAGE_PLAYER 0x02 /* Message attached to player*/
+#define KERNEL_MESSAGE_QUOTE 0x01 /* Message has trailing quote*/
+
+#define KERNEL_NONE -1 /* No file extension */
+#define KERNEL_SS 1 /* Sprite series .SS */
+#define KERNEL_AA 2 /* Animation .AA */
+#define KERNEL_DAT 3 /* Room data .DAT */
+#define KERNEL_HH 4 /* Hot spot list .HH */
+#define KERNEL_ART 5 /* Room artwork .ART */
+#define KERNEL_INT 6 /* Interface .INT */
+#define KERNEL_TT 7 /* Tile .TT */
+#define KERNEL_MM 8 /* Map .MM */
+#define KERNEL_WW 9 /* Walk codes .WW? */
+
+#define KERNEL_MAX_MESSAGES 10 /* Maximum messages on screen at once */
+#define KERNEL_MAX_MESSAGE_LEN 40 /* Maximum length of text messages */
+#define KERNEL_MESSAGE_INTERVAL 3 /* Ticks between message updates */
+
+#define KERNEL_GAME_LOAD 0 /* Kernel load state */
+#define KERNEL_SECTION_PRELOAD 1
+#define KERNEL_SECTION_INIT 2
+#define KERNEL_ROOM_PRELOAD 3
+#define KERNEL_ROOM_INIT 4
+#define KERNEL_ACTIVE_CODE 5
+
+#define KERNEL_MOTION 0x01 /* Series is in motion */
+#define KERNEL_MOTION_OFFSCREEN 0x02 /* Series expires if moves off screen */
+
+#define KERNEL_MAX_DYNAMIC 16 /* Maximum dynamic hotspots */
+
+#define KERNEL_DYNAMIC_MAX_SEGMENTS 10 /* Max segments triggered by dynamic hotspot */
+#define KERNEL_DYNAMIC_NO_ANIM 0xff /* When no animation segment */
+
+#define KERNEL_STARTING_GAME -1 /* Previous room when starting fresh */
+#define KERNEL_RESTORING_GAME -2 /* Previous room when restoring game */
+
+#define KERNEL_SERIES 1 /* Synchronize sprite sequence */
+#define KERNEL_PLAYER 2 /* Synchronize PLAYER sprite series */
+#define KERNEL_ANIM 3 /* Synchronize animation */
+#define KERNEL_NOW 4 /* Synchronize with current time */
+
+#define KERNEL_MAX_RANDOM_MESSAGES 4 /* Max # of idle chatter msgs at once */
+#define KERNEL_MAX_RANDOM_QUOTES 8 /* Max # of available idle chatter quotes */
+#define KERNEL_RANDOM_MESSAGE_TRIGGER 240 /* Trigger base for idle chatter */
+
+#define KERNEL_MAX_CONVERSATION 16 /* Max items in a conversation */
+
+#define KERNEL_MAX_ANIMATIONS 10 /* Max number of animations */
+
+#define KERNEL_SCRATCH_SIZE 256 /* Size of game scratch area */
+
+#define KERNEL_HOME -32000 /* Sprite home location */
+
+#define KERNEL_STARTUP_POPUP 0x8000
+#define KERNEL_STARTUP_FONT 0x4000
+#define KERNEL_STARTUP_INTERRUPT 0x2000
+#define KERNEL_STARTUP_DEMO 0x1000
+#define KERNEL_STARTUP_OBJECTS 0x0800
+#define KERNEL_STARTUP_PLAYER 0x0400
+#define KERNEL_STARTUP_CURSOR 0x0200
+#define KERNEL_STARTUP_CURSOR_SHOW 0x0100
+#define KERNEL_STARTUP_VOCAB 0x0080
+#define KERNEL_STARTUP_INTERFACE 0x0040
+
+
+typedef struct {
+ byte active_flag; /* Sequence is active */
+
+ byte series_id; /* Series list handle */
+ byte mirror; /* Mirroring flag */
+
+ int sprite; /* Current sprite of sequence */
+
+ int start_sprite; /* Lowest sprite to be used */
+ int end_sprite; /* Highest sprite to be used */
+
+ int loop_mode; /* Looping mode (AA_LINEAR/AA_PINGPONG) */
+ int loop_direction; /* Looping direction (1,-1) */
+
+ byte depth; /* Sequence depth (0-15) */
+ byte scale; /* Sequence scale (0-100) */
+
+ int dynamic_hotspot; /* Dynamic hotspot (if any) */
+
+ byte auto_locating; /* Sequence runs at home location */
+ byte motion; /* Sequence moves */
+ int x, y; /* Specific location for sequence */
+ int delta_x, delta_y; /* Delta values (*100) */
+ int sign_x, sign_y; /* Delta signs */
+ int accum_x, accum_y; /* Delta accumulators (*100) */
+
+ byte expire; /* Loops left till expiration */
+ byte expired; /* Expiration flag */
+
+ byte num_triggers; /* Number of triggers */
+ byte trigger_type[KERNEL_MAX_TRIGGERS]; /* Trigger info */
+ int trigger_sprite[KERNEL_MAX_TRIGGERS];
+ byte trigger_code[KERNEL_MAX_TRIGGERS];
+
+ byte trigger_dest; /* Type of code to activate for trigger */
+ int trigger_words[3]; /* vocabulary words for reactivating parser code */
+
+ word ticks; /* Ticks between frames */
+ word interval_ticks; /* Ticks between loops */
+
+ long base_time; /* Clock time of next scheduled update */
+
+ Image last_image; /* Copy of last image entered */
+} Sequence;
+
+typedef Sequence *SequencePtr;
+
+
+typedef struct {
+ word flags; /* Message flags */
+ byte sequence_id; /* Attached sequence number */
+ byte segment_id; /* Animation segment id */
+ byte strobe_save; /* Saved strobe character */
+ byte strobe_save_2; /* Second saved strobe character */
+ int color; /* Message color */
+ int x, y; /* X and Y position */
+ int matte_message_handle; /* Handle in matte message list */
+ int strobe_marker; /* Marker in strobe message */
+ int strobe_rate; /* Number of ticks between strobes */
+ long strobe_time; /* Time for next strobe */
+ long update_time; /* Clock time of next update */
+ long expire_ticks; /* Number of ticks until expiration */
+ byte trigger_code; /* Trigger code, if any. */
+ byte trigger_dest; /* Type of code to activate for trigger */
+ int trigger_words[3]; /* Vocabulary words for reactivating parser code */
+ char *message; /* Pointer to message text */
+} KernelMessage;
+
+typedef KernelMessage *KernelMessagePtr;
+
+
+typedef struct {
+ byte flags;
+ int auto_sequence;
+ int x, y, xs, ys;
+ int feet_x, feet_y;
+ byte facing;
+ int vocab_id;
+ int verb_id;
+ byte valid;
+ byte prep;
+ byte cursor;
+ byte syntax;
+ char auto_anim;
+ byte auto_segment[KERNEL_DYNAMIC_MAX_SEGMENTS];
+} KernelDynamicHotSpot;
+
+typedef KernelDynamicHotSpot *KernelDynamicHotSpotPtr;
+
+
+
+typedef struct {
+ AnimPtr anim; /* Animation pointer */
+ int repeat; /* Animation should repeat continuously */
+ int cycled; /* Animation has cycled back to start */
+ int sprite_loaded; /* Current sprite loaded (for streamers)*/
+ byte *buffer[2]; /* Double buffering pointers (streamers)*/
+ int buffer_id; /* Double buffering index (streamers)*/
+ int messages; /* Messages currently active from anim */
+ int frame; /* Current frame */
+ int image; /* Animation image marker */
+ int doomed; /* Animation expires this round */
+
+ int view_changes; /* Animation can change picture view */
+
+ int trigger_code; /* Trigger code on expiration */
+ int trigger_mode; /* Trigger mode (parser/daemon/etc.) */
+ int trigger_words[3]; /* Trigger parser words */
+
+ long next_clock; /* Next animation update */
+
+ int dynamic_hotspot; /* Attached dynamic hotspot */
+
+ int last_frame; /* Most recent frame viewed */
+} Animation;
+
+
+typedef struct {
+ long clock; /* Current game timing clock */
+ byte fx; /* Special FX for this frame */
+
+ byte video_mode; /* Video mode for game */
+ byte translating; /* Flag if translating to 16 colors */
+
+ char sound_card; /* Game sound card character */
+
+ byte force_restart; /* Forces restart of room if true */
+
+ int trigger; /* Game trigger code, if any */
+ int trigger_setup_mode; /* Mode which sets up trigger */
+ int trigger_mode; /* Mode which activated trigger */
+
+ byte cheating; /* Flag if cheating enabled. */
+
+ int cursor_x[2]; /* Keyboard cursor locs. */
+ int cursor_y[2];
+
+ byte paused; /* Flag if game paused at current frame */
+ byte cause_pause; /* Flag if game should pause this frame */
+ byte frame_by_frame; /* Flag if game should run frame/frame */
+
+ byte mouse_cursor_point; /* Flag if mouse cursor loc should be displayed */
+ byte memory_tracking; /* Flag if memory amount should be displayed */
+
+ byte teleported_in; /* Flag if player teleported to room */
+
+ char interface[20]; /* Name of current interface animation */
+ /* char sound_driver[20]; */ /* Name of current sound driver */
+
+ char *quotes; /* Quote list */
+
+ /* char global_message[80]; */ /* Global message storage area */
+
+ int activate_menu; /* Flag to activate a game menu */
+
+ byte player_tracking; /* Flag if tracking player location */
+ byte disable_fastwalk; /* Flag if fastwalk disabled */
+
+} Kernel;
+
+
+typedef struct {
+ byte going; /* Game is running OK */
+ int scratch[KERNEL_SCRATCH_SIZE]; /* Scratch variables for room */
+ char difficulty; /* Difficulty level */
+ int last_save; /* Most recent save slot # */
+} KernelGame;
+
+
+#ifdef old_animation
+#define kernel_animation kernel_anim[0].anim
+#define kernel_animation_cycled kernel_anim[0].cycled
+#define kernel_repeat_animation kernel_anim[0].repeat
+#define kernel_animation_sprite_loaded kernel_anim[0].sprite_loaded
+#define kernel_animation_buffer_id kernel_anim[0].buffer_id
+#define kernel_animation_buffer kernel_anim[0].buffer
+#define kernel_animation_frame kernel_anim[0].frame
+#define kernel_animation_image kernel_anim[0].image
+#define kernel_animation_doomed kernel_anim[0].doomed
+#define kernel_animation_trigger_code kernel_anim[0].trigger_code
+#define kernel_animation_trigger_mode kernel_anim[0].trigger_mode
+#define kernel_animation_trigger_words kernel_anim[0].trigger_words
+#define kernel_animation_next_clock kernel_anim[0].next_clock
+#endif
+
+
+#define kernel_init_dialog() inter_reset_dialog()
+#define kernel_dialog(q) inter_add_dialog(quote_string(kernel.quotes, q), q)
+
+
+/* kernel_1.c */
+extern RoomPtr room; /* Pointer to current room's data */
+extern int room_id; /* Current room # */
+extern int section_id; /* Current section # */
+extern int room_variant; /* Current room attribute variant */
+
+extern int new_room; /* New room # to enter */
+extern int new_section; /* New section # to enter */
+
+extern int previous_room; /* Last room # */
+extern int previous_section; /* Last section # */
+
+extern int kernel_initial_variant; /* Initial variant to load */
+
+extern HotPtr room_spots; /* Pointer to hotspots for this room */
+extern int room_num_spots; /* Number of hotspots for this room */
+
+extern int kernel_room_series_marker; /* Flag for room background series */
+
+extern int kernel_room_bound_dif;
+extern int kernel_room_scale_dif;
+
+extern int kernel_allow_peel; /* Flag if peeling buffers allowed */
+
+extern int kernel_panning_speed;
+extern int kernel_screen_fade;
+
+
+extern Animation kernel_anim[KERNEL_MAX_ANIMATIONS];
+
+/* Old animation stuff
+extern AnimPtr kernel_animation;
+extern int kernel_repeat_animation;
+
+extern int kernel_animation_sprite_loaded;
+extern int kernel_animation_buffer_id;
+extern byte *kernel_animation_buffer[2];
+
+extern int kernel_animation_messages;
+
+extern int kernel_animation_cycled;
+extern int kernel_animation_frame;
+extern int kernel_animation_image;
+extern int kernel_animation_doomed;
+extern int kernel_animation_trigger_code;
+extern int kernel_animation_trigger_mode;
+extern int kernel_animation_trigger_words[3];
+extern long kernel_animation_next_clock;
+*/
+
+extern ShadowList kernel_shadow_main;
+extern ShadowList kernel_shadow_inter;
+
+extern int kernel_ok_to_fail_load;
+
+extern int kernel_mode;
+
+extern char kernel_cheating_password[16];
+extern int kernel_cheating_allowed;
+extern int kernel_cheating_forbidden;
+
+extern KernelDynamicHotSpot kernel_dynamic_hot[KERNEL_MAX_DYNAMIC];
+extern int kernel_num_dynamic;
+extern int kernel_dynamic_changed;
+
+extern SeriesPtr cursor; /* Mouse cursor series */
+
+extern int cursor_id;
+extern int cursor_last;
+
+extern Kernel kernel;
+extern KernelGame game; /* Kernel level game data */
+
+
+
+
+
+/* kernel_2.c */
+int kernel_load_vocab(void);
+
+/* kernel_3.c */
+int kernel_game_shutdown(void);
+void kernel_force_refresh(void);
+int kernel_game_startup(int game_video_mode, int load_flag,
+ char *release_version, char *release_date);
+
+/* kernel_4.c */
+void kernel_section_shutdown(void);
+int kernel_section_startup(int new_section);
+
+/* kernel_5.c */
+void kernel_room_shutdown(void);
+int kernel_room_startup(int new_room, int initial_variant,
+ char *interface, int new_palette);
+
+/* kernel_6.c */
+void kernel_unload_all_series(void);
+int kernel_load_series(const char *name, int load_flags);
+
+/* kernel_7.c */
+void kernel_flip_hotspot(int vocab_code, int active);
+void kernel_flip_hotspot_loc(int vocab_code, int active,
+ int x, int y);
+
+/* kernel_8.c */
+extern Sequence sequence_list[KERNEL_MAX_SEQUENCES];
+
+/* kernel_8.c */
+void kernel_seq_init(void);
+void kernel_seq_correction(long old_clock, long new_clock);
+
+/* kernel_8.c */
+int kernel_seq_add(int series_id, int mirror,
+ int initial_sprite,
+ int low_sprite, int high_sprite,
+ int loop_mode, int loop_direction,
+ int depth, int scale,
+ int auto_locating,
+ int x, int y,
+ word ticks, word interval_ticks,
+ word start_ticks,
+ int expire);
+
+/* kernel_8.c */
+int kernel_seq_forward(int series_id, int mirror,
+ word ticks, word interval_ticks,
+ word start_ticks, int expire);
+
+int kernel_seq_forward_scroll(int series_id, int mirror,
+ word ticks, word interval_ticks,
+ word start_ticks, int expire);
+
+/* kernel_8.c */
+int kernel_seq_pingpong(int series_id, int mirror,
+ word ticks, word interval_ticks,
+ word start_ticks, int expire);
+
+int kernel_seq_pingpong_scroll(int series_id, int mirror,
+ word ticks, word interval_ticks,
+ word start_ticks, int expire);
+
+/* kernel_8.c */
+int kernel_seq_backward(int series_id, int mirror,
+ word ticks, word interval_ticks,
+ word start_ticks, int expire);
+
+int kernel_seq_backward_scroll(int series_id, int mirror,
+ word ticks, word interval_ticks,
+ word start_ticks, int expire);
+
+/* kernel_8.c */
+int kernel_seq_stamp(int series_id, int mirror, int sprite);
+int kernel_seq_stamp_scroll(int series_id, int mirror, int sprite);
+
+/* kernel_8.c */
+void kernel_synch(int slave_type, int slave_id,
+ int master_type, int master_id);
+void kernel_player_expire(int sequence_id);
+
+/* kernel_8.c */
+void kernel_seq_depth(int sequence_id, int depth);
+void kernel_seq_scale(int sequence_id, int scale);
+void kernel_seq_loc(int sequence_id, int x, int y);
+void kernel_seq_range(int sequence_id,
+ int first, int last);
+
+/* kernel_8.c */
+void kernel_seq_motion(int sequence_id, int flags,
+ int delta_x_times_100,
+ int delta_y_times_100);
+
+
+/* kernel_8.c */
+int kernel_seq_trigger(int sequence_id,
+ int trigger_type,
+ int trigger_sprite,
+ int trigger_code);
+
+/* kernel_8.c */
+int kernel_timing_trigger(int ticks, int trigger_code);
+
+/* kernel_8.c */
+void kernel_seq_purge(int sequence_id);
+void kernel_seq_full_update(void);
+
+/* kernel_8.c */
+void kernel_draw_to_background(int series_id, int sprite_id,
+ int x, int y,
+ int depth, int scale);
+
+
+/* kernel_9.c */
+void kernel_seq_delete(int sequence_id);
+int kernel_seq_update(SequencePtr sequence,
+ int sequence_id);
+void kernel_seq_update_all(void);
+
+
+/* kernel_a.c */
+void kernel_seq_player(int sequence_id, int synch_me);
+
+
+/* kernel_b.c */
+void kernel_animation_init(void);
+int kernel_run_animation(const char *name, int trigger_code);
+int kernel_run_animation_disp(char thing, int num, int trigger_code);
+int kernel_run_animation_talk(char thing, int num, int trigger_code);
+int kernel_run_animation_write(int trigger_code);
+int kernel_run_animation_point(int num, int trigger_code);
+
+
+/* kernel_c.c */
+void kernel_reset_animation(int handle, int frame);
+void kernel_abort_animation(int handle);
+void kernel_abort_all_animations(void);
+void kernel_doom_all_animations(void);
+void kernel_abort_doomed_animations(void);
+void kernel_process_all_animations(void);
+
+
+/* kernel_d.c */
+extern KernelMessage kernel_message[KERNEL_MAX_MESSAGES];
+extern FontPtr kernel_message_font;
+extern int kernel_message_spacing;
+
+/* kernel_d.c */
+void kernel_message_init(void);
+int kernel_message_add(char *text, int x, int y,
+ int color,
+ long time_on_screen,
+ int trigger_code,
+ int flags);
+/* kernel_d.c */
+void kernel_message_teletype(int id, int rate, int quote);
+void kernel_message_attach(int id, int sequence);
+void kernel_message_delete(int id);
+void kernel_message_purge(void);
+
+/* kernel_d.c */
+void kernel_message_anim(int id, int anim, int segment);
+int kernel_message_player(int quote_id, long delay, int trigger);
+
+
+/* kernel_e.c */
+void kernel_message_update(KernelMessagePtr my_message);
+void kernel_message_update_all(void);
+void kernel_message_correction(long old_clock, long new_clock);
+
+
+/* kernel_f.c */
+int kernel_add_dynamic(int vocab_id, int verb_id, byte syntax,
+ int auto_sequence,
+ int x, int y, int xs, int ys);
+/* kernel_f.c */
+int kernel_dynamic_walk(int id, int feet_x, int feet_y,
+ int facing);
+void kernel_dynamic_anim(int id, int anim_id, int segment);
+
+/* kernel_f.c */
+int kernel_dynamic_cursor(int id, int cursor);
+void kernel_delete_dynamic(int id);
+void kernel_purge_dynamic(void);
+void kernel_init_dynamic(void);
+
+/* kernel_g.c */
+int kernel_dynamic_consecutive(int id);
+void kernel_refresh_dynamic(void);
+
+/* kernel_h.c */
+char *fastcall kernel_full_name(int my_room,
+ char type, int num, char *text,
+ int ext);
+char *fastcall kernel_name(char type, int num);
+char *fastcall kernel_interface_name(int num);
+
+
+/* kernel_i.c */
+void kernel_unload_sound_driver(void);
+int kernel_load_sound_driver(const char *name, char sound_card,
+ int sound_board_address,
+ int sound_board_type,
+ int sound_board_irq);
+
+/* kernel_j.c */
+void kernel_load_variant(int variant);
+
+
+/* kernel_k.c */
+void kernel_new_palette(void);
+
+
+/* kernel_l.c */
+void kernel_dump_quotes(void);
+void kernel_dump_all(void);
+void kernel_dump_walker_only(void);
+
+/* kernel_m.c */
+int kernel_save_game(char *filename);
+int kernel_load_game(char *filename);
+
+/* kernel_n.c */
+void kernel_random_messages_init(int max_messages_at_once,
+ int min_x, int max_x,
+ int min_y, int max_y,
+ int min_y_spacing,
+ int teletype_rate,
+ int color,
+ int duration,
+ int quote_id, ...);
+/* kernel_n.c */
+int kernel_check_random(void);
+void kernel_random_message_server(void);
+int kernel_generate_random_message(int chance_major,
+ int chance_minor);
+void kernel_random_purge(void);
+
+
+/* kernel_o.c */
+void kernel_load_interface(void);
+void kernel_set_interface_mode(int mode);
+
+
+/* kernel_q.c */
+void kernel_room_scale(int front_y, int front_scale,
+ int back_y, int back_scale);
+
+/* kernel_r.c */
+void kernel_background_shutdown(void);
+int kernel_background_startup(int new_room,
+ int initial_variant);
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/keys.h b/engines/mads/madsv2/core/keys.h
new file mode 100644
index 00000000000..e7df32a36b4
--- /dev/null
+++ b/engines/mads/madsv2/core/keys.h
@@ -0,0 +1,239 @@
+/* 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 MADS_CORE_KEYS_H
+#define MADS_CORE_KEYS_H
+
+#include "mads/madsv2/core/general.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+/* keystroke defines */
+
+#define key_status_1 (byte *) 0x00400017 /* key status 1 */
+#define key_status_2 (byte *) 0x00400018 /* key status 2 */
+
+#define KS1_INSERT 0x80 /* Insert state */
+#define KS1_CAPSLOCK 0x40 /* Caps Lock state */
+#define KS1_NUMLOCK 0x20 /* Num Lock state */
+#define KS1_SCROLLLOCK 0x10 /* Scroll Lock state */
+#define KS1_ALT 0x08 /* Alt key state */
+#define KS1_CTRL 0x04 /* Ctrl key state */
+#define KS1_LEFTSHIFT 0x02 /* Left shift state */
+#define KS1_RIGHTSHIFT 0x01 /* Right shift state */
+
+#define left_key 0x14b
+#define right_key 0x14d
+#define up_key 0x148
+#define down_key 0x150
+
+#define ins_key 0x152
+#define del_key 0x153
+#define delete_key 0x153
+
+#define home_key 0x147
+#define end_key 0x14f
+
+#define pgup_key 0x149
+#define pgdn_key 0x151
+
+#define enter_key 0x0d
+#define esc_key 0x1b
+#define bksp_key 0x08
+#define ctrl_del_key 0x193
+#define tab_key 0x09
+#define backtab_key 0x10f
+
+#define space_key 0x20
+
+#define A_key 0x41
+#define B_key 0x42
+#define C_key 0x43
+#define D_key 0x44
+#define E_key 0x45
+#define F_key 0x46
+#define G_key 0x47
+#define H_key 0x48
+#define I_key 0x49
+#define J_key 0x4a
+#define K_key 0x4b
+#define L_key 0x4c
+#define M_key 0x4d
+#define N_key 0x4e
+#define O_key 0x4f
+#define P_key 0x50
+#define Q_key 0x51
+#define R_key 0x52
+#define S_key 0x53
+#define T_key 0x54
+#define U_key 0x55
+#define V_key 0x56
+#define W_key 0x57
+#define X_key 0x58
+#define Y_key 0x59
+#define Z_key 0x5a
+
+#define a_key 0x61
+#define b_key 0x62
+#define g_key 0x67
+#define i_key 0x69
+#define j_key 0x6a
+#define m_key 0x6d
+#define z_key 0x7a
+
+#define alt_a_key 0x11e
+#define alt_b_key 0x130
+#define alt_c_key 0x12e
+#define alt_d_key 0x120
+#define alt_e_key 0x112
+#define alt_f_key 0x121
+#define alt_g_key 0x122
+#define alt_h_key 0x123
+#define alt_i_key 0x117
+#define alt_j_key 0x124
+#define alt_k_key 0x125
+#define alt_l_key 0x126
+#define alt_m_key 0x132
+#define alt_n_key 0x131
+#define alt_o_key 0x118
+#define alt_p_key 0x119
+#define alt_q_key 0x110
+#define alt_r_key 0x113
+#define alt_s_key 0x11f
+#define alt_t_key 0x114
+#define alt_u_key 0x116
+#define alt_v_key 0x12f
+#define alt_w_key 0x111
+#define alt_x_key 0x12d
+#define alt_y_key 0x115
+#define alt_z_key 0x12c
+
+#define f1_key 0x13b
+#define f2_key 0x13c
+#define f3_key 0x13d
+#define f4_key 0x13e
+#define f5_key 0x13f
+#define f6_key 0x140
+#define f7_key 0x141
+#define f8_key 0x142
+#define f9_key 0x143
+#define f10_key 0x144
+
+#define shift_f1_key 0x154
+#define shift_f2_key 0x155
+#define shift_f3_key 0x156
+#define shift_f4_key 0x157
+#define shift_f5_key 0x158
+#define shift_f6_key 0x159
+#define shift_f7_key 0x15a
+#define shift_f8_key 0x15b
+#define shift_f9_key 0x15c
+#define shift_f10_key 0x15d
+
+#define ctrl_f1_key 0x15e
+#define ctrl_f2_key 0x15f
+#define ctrl_f3_key 0x160
+#define ctrl_f4_key 0x161
+#define ctrl_f5_key 0x162
+#define ctrl_f6_key 0x163
+#define ctrl_f7_key 0x164
+#define ctrl_f8_key 0x165
+#define ctrl_f9_key 0x166
+#define ctrl_f10_key 0x167
+
+#define alt_f1_key 0x168
+#define alt_f2_key 0x169
+#define alt_f3_key 0x16a
+#define alt_f4_key 0x16b
+#define alt_f5_key 0x16c
+#define alt_f6_key 0x16d
+#define alt_f7_key 0x16e
+#define alt_f8_key 0x16f
+#define alt_f9_key 0x170
+#define alt_f10_key 0x171
+
+#define ctrl_a_key 0x01
+#define ctrl_b_key 0x02
+#define ctrl_c_key 0x03
+#define ctrl_d_key 0x04
+#define ctrl_e_key 0x05
+#define ctrl_f_key 0x06
+#define ctrl_g_key 0x07
+#define ctrl_h_key 0x08
+#define ctrl_i_key 0x09
+#define ctrl_j_key 0x0a
+#define ctrl_k_key 0x0b
+#define ctrl_l_key 0x0c
+#define ctrl_m_key 0x0d
+#define ctrl_n_key 0x0e
+#define ctrl_o_key 0x0f
+#define ctrl_p_key 0x10
+#define ctrl_q_key 0x11
+#define ctrl_r_key 0x12
+#define ctrl_s_key 0x13
+#define ctrl_t_key 0x14
+#define ctrl_u_key 0x15
+#define ctrl_v_key 0x16
+#define ctrl_w_key 0x17
+#define ctrl_x_key 0x18
+#define ctrl_y_key 0x19
+#define ctrl_z_key 0x1a
+
+#define KEYS_MAX_BUF_CHARS 32
+
+struct KeyBuffer {
+ int buf[KEYS_MAX_BUF_CHARS];
+ int len;
+};
+
+typedef struct KeyBuffer *KeyPtr;
+
+
+/* keys_1.c */
+int keys_any(void);
+int keys_get(void);
+void keys_flush(void);
+
+/* keys_2.c */
+void keys_flush_buffer(KeyPtr key_buf);
+void keys_fill_buffer(KeyPtr key_buf);
+int keys_read_buffer(KeyPtr key_buf);
+int keys_append_buffer(KeyPtr key_buf, int newchar);
+int keys_insert_buffer(KeyPtr key_buf, int newchar, int before);
+void keys_stuff_buffer(KeyPtr key_buf, int *newstuff);
+
+/* keys_3.c */
+int keys_fix_alt(int target);
+
+/* keys_4.c */
+extern word keys_special_button;
+
+void keys_install(void);
+void keys_remove(void);
+int keys_check_install(void);
+void keys_enable(void);
+void keys_disable(void);
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/lib.h b/engines/mads/madsv2/core/lib.h
new file mode 100644
index 00000000000..5636a6f0e0a
--- /dev/null
+++ b/engines/mads/madsv2/core/lib.h
@@ -0,0 +1,44 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 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 MADS_CORE_LIB_H
+#define MADS_CORE_LIB_H
+
+#include "common/scummsys.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+#define lib_version "4.35"
+#define lib_date "10-Aug-93"
+
+#ifndef lib_data_segment
+extern char mads_dev_lib_version[5];
+extern char mads_dev_lib_date[11];
+#endif
+
+/* lib.c */
+void lib_show_version(void);
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/loader.h b/engines/mads/madsv2/core/loader.h
new file mode 100644
index 00000000000..5934997f4f6
--- /dev/null
+++ b/engines/mads/madsv2/core/loader.h
@@ -0,0 +1,98 @@
+/* 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 MADS_CORE_LOADER_H
+#define MADS_CORE_LOADER_H
+
+#include "common/stream.h"
+#include "mads/madsv2/core/general.h"
+#include "mads/madsv2/core/pack.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+#define LOADER_DISK 0 /* File being read from disk */
+#define LOADER_EMS 1 /* File being read from ems */
+#define LOADER_XMS 2 /* File being read from xms */
+
+
+typedef struct {
+ int open; /* Open status (true = open) */
+ int reading; /* Read/Write status (true = reading) */
+ byte mode; /* Access mode (LOADER_EMS/LOADER_DISK) */
+ Common::SeekableReadStream *handle; /* File handle (if LOADER_DISK) */
+ int ems_handle; /* EMS handle (if LOADER_EMS) */
+ int xms_handle; /* XMS handle (if LOADER_XMS) */
+ long xms_offset; /* XMS offset (if LOADER_XMS) */
+ int ems_page_marker; /* Current EMS logical page # */
+ word ems_page_offset; /* Current EMS logical page offset */
+ long decompress_size; /* Decompressed size of file */
+ int pack_list_marker; /* Packing list marker */
+ PackList pack; /* Packing list */
+} Load;
+
+typedef Load *LoadHandle;
+
+/* Debug tracking variables */
+#ifndef disable_statistics
+extern long loader_found_in_ems;
+extern long loader_found_in_xms;
+extern long loader_found_on_disk;
+extern long loader_timing_ems;
+extern long loader_timing_xms;
+extern long loader_timing_disk;
+extern long loader_size_ems;
+extern long loader_size_xms;
+extern long loader_size_disk;
+#endif
+
+extern int loader_ems_search_disabled;
+extern char loader_last[14];
+
+
+/* loader_1.c */
+int loader_open(LoadHandle handle, char *filename,
+ char *options, int flags);
+
+int loader_close(LoadHandle handle);
+
+void loader_set_priority(LoadHandle handle, int priority);
+
+/* loader_2.c */
+long loader_read(void *target,
+ long record_size,
+ long record_count,
+ LoadHandle handle);
+
+/* loader_3.c */
+long loader_write(void *target,
+ long record_size,
+ long record_count,
+ LoadHandle handle);
+
+/* loader_4.c */
+long loader_write_2(Common::WriteStream *source_handle, long total_size,
+ LoadHandle handle);
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/mads.h b/engines/mads/madsv2/core/mads.h
new file mode 100644
index 00000000000..72e81053e96
--- /dev/null
+++ b/engines/mads/madsv2/core/mads.h
@@ -0,0 +1,36 @@
+/* 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 MADS_CORE_MADS_H
+#define MADS_CORE_MADS_H
+
+namespace MADS {
+namespace MADSV2 {
+
+#define GLOBAL 1
+#define SECTION 2
+#define ROOM 3
+#define OBJECT 4
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/magic.h b/engines/mads/madsv2/core/magic.h
new file mode 100644
index 00000000000..26b268f5b04
--- /dev/null
+++ b/engines/mads/madsv2/core/magic.h
@@ -0,0 +1,153 @@
+/* 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 MADS_CORE_MAGIC_H
+#define MADS_CORE_MAGIC_H
+
+#include "common/scummsys.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+#define MAGIC_LOWER_LEFT 1
+#define MAGIC_LOWER_RIGHT 2
+#define MAGIC_UPPER_LEFT 3
+#define MAGIC_UPPER_RIGHT 4
+
+#define MAGIC_LEFT 0
+#define MAGIC_RIGHT 1
+
+#define MAGIC_IMMEDIATE 0
+#define MAGIC_THRU_BLACK 1
+#define MAGIC_SECRET_FUJI 2
+
+#define MAGIC_SWAP_BACKGROUND 0
+#define MAGIC_SWAP_FOREGROUND 1
+
+typedef struct {
+ byte intensity;
+ byte map_color;
+ word accum[3];
+} MagicGrey;
+
+typedef MagicGrey *MagicGreyPtr;
+
+extern byte magic_color_flags[3];
+extern byte magic_color_values[3];
+
+
+/* magic_1.c */
+void magic_get_grey_values(Palette *pal, byte *grey_value,
+ int base_color, int num_colors);
+
+/* magic_2.c */
+void magic_grey_palette(Palette pal);
+
+
+/* magic_3.c */
+void magic_grey_popularity(byte *grey_list,
+ byte *grey_table,
+ int num_colors);
+void magic_set_color_flags(byte r, byte g, byte b);
+void magic_set_color_values(byte r, byte g, byte b);
+void magic_map_to_grey_ramp(Palette *pal,
+ int base_color, int num_colors,
+ int base_grey, int num_greys,
+ MagicGreyPtr magic_map);
+
+/* magic_4.c */
+void magic_grey_ramp_palette(Palette pal, int num_greys);
+
+
+/* magic_5.c */
+void magic_fade_to_grey(Palette pal, byte *map_pointer,
+ int base_color, int num_colors,
+ int base_grey, int num_greys,
+ int tick_delay, int steps);
+/* magic_6.c */
+void magic_fade_from_grey(RGBcolor *pal, Palette target,
+ int base_color, int num_colors,
+ int base_grey, int num_greys,
+ int tick_delay, int steps);
+
+/* magic_7.c */
+void magic_screen_change_corner(Buffer *new_screen, Palette pal,
+ int corner_id,
+ int buffer_base_x, int buffer_base_y,
+ int screen_base_x, int screen_base_y,
+ int thru_black, int set_palette,
+ int tick_delay);
+
+/* magic_8.c */
+void magic_screen_change_edge(Buffer *new_screen, Palette pal,
+ int edge_id,
+ int buffer_base_x, int buffer_base_y,
+ int screen_base_x, int screen_base_y,
+ int thru_black, int set_palette,
+ int tick_delay);
+
+/* magic_9.c */
+
+extern int magic_special_center_x;
+extern int magic_special_center_y;
+
+void magic_screen_change_circle(Buffer *new_screen, Palette pal,
+ int inward_flag,
+ int buffer_base_x, int buffer_base_y,
+ int screen_base_x, int screen_base_y,
+ int thru_black, int set_palette,
+ int tick_delay, int pixel_rate);
+
+
+/* magic_a.c */
+void magic_shrink_buffer(Buffer *from, Buffer *unto);
+
+
+/* magic_b.c */
+int magic_shrinking_buffer(Buffer *source, Buffer *rear,
+ int grow_flag,
+ int buffer_base_x, int buffer_base_y,
+ int screen_base_x, int screen_base_y,
+ int tick_delay);
+
+/* magic_c.c */
+extern int magic_low_fade_bound;
+extern int magic_high_fade_bound;
+
+void magic_swap_me_in_the_dark_baby(byte *swap,
+ Palette pal,
+ int start);
+void magic_swap_foreground(byte *background_table,
+ Palette background_palette);
+
+/* magic_d.c */
+int magic_closest_color(RGBcolor *match_color,
+ byte *list,
+ int list_wrap,
+ int list_length);
+
+/* magic_e.c */
+int magic_hash_color(RGBcolor *hash_color);
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/matte.h b/engines/mads/madsv2/core/matte.h
new file mode 100644
index 00000000000..ce77aa33bcb
--- /dev/null
+++ b/engines/mads/madsv2/core/matte.h
@@ -0,0 +1,165 @@
+/* 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 MADS_CORE_MATTE_H
+#define MADS_CORE_MATTE_H
+
+#include "mads/madsv2/core/general.h"
+#include "mads/madsv2/core/anim.h"
+#include "mads/madsv2/core/tile.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+#define SERIES_LIST_SIZE 50
+
+#define SERIES_BONUS_SIZE 1
+#define SERIES_BONUS_OBJECT 1 /* Bonus number of spinning objects */
+
+
+#define IMAGE_LIST_SIZE 50
+#define MESSAGE_LIST_SIZE 40
+
+#define IMAGE_INTER_LIST_SIZE 50
+
+#define MATTE_LIST_SIZE (IMAGE_LIST_SIZE + MESSAGE_LIST_SIZE)
+#define FIRST_MESSAGE_MATTE IMAGE_LIST_SIZE
+
+#define MATTE_FX_FADE_FROM_BLACK 1
+#define MATTE_FX_FADE_THRU_BLACK 2
+#define MATTE_FX_CORNER_LOWER_LEFT 3
+#define MATTE_FX_CORNER_LOWER_RIGHT 4
+#define MATTE_FX_CORNER_UPPER_LEFT 5
+#define MATTE_FX_CORNER_UPPER_RIGHT 6
+#define MATTE_FX_EDGE_LEFT 7
+#define MATTE_FX_EDGE_RIGHT 8
+#define MATTE_FX_CIRCLE_OUT_SLOW 9
+#define MATTE_FX_CIRCLE_IN_SLOW 10
+#define MATTE_FX_CIRCLE_OUT_FAST 11
+#define MATTE_FX_CIRCLE_IN_FAST 12
+
+#define MATTE_FX_FAST_THRU_BLACK 20
+#define MATTE_FX_FAST_AND_FANCY 21
+
+
+typedef struct MatteBuf {
+ int x, y; /* upper left coords */
+ int xs, ys; /* sizes */
+ int xh, yh; /* half sizes */
+ int xc, yc; /* centers */
+ byte changed; /* changed this update? */
+ byte valid; /* contains valid matte?*/
+} Matte;
+
+typedef Matte *MattePtr;
+
+extern SeriesPtr series_list[SERIES_LIST_SIZE]; /* Master sprite list */
+
+extern char series_name[SERIES_LIST_SIZE][9]; /* Master sprite name list*/
+extern byte series_user[SERIES_LIST_SIZE]; /* Master sprite user list*/
+
+extern Image image_list[IMAGE_LIST_SIZE]; /* Master image list */
+extern Matte matte_list[MATTE_LIST_SIZE]; /* Master matte list */
+
+byte depth_list_id[MATTE_LIST_SIZE]; /* Depth list for sorting */
+word depth_list[MATTE_LIST_SIZE];
+
+extern Message message_list[MESSAGE_LIST_SIZE];
+
+extern ImageInter image_inter_list[IMAGE_INTER_LIST_SIZE]; /* Interface lists */
+extern Matte matte_inter_list[IMAGE_INTER_LIST_SIZE];
+
+extern int series_list_marker; /* # of series list entries in use */
+
+extern int picture_view_x; /* Current viewing offset for upper left */
+extern int picture_view_y;
+
+extern int viewing_at_x; /* Screen X coordinate of left window column */
+extern int viewing_at_y; /* Screen Y coordinate of upper window line */
+extern int inter_viewing_at_y; /* Screen Y coordinate of upper interface line */
+
+extern int matte_disable_screen_update; /* Matte driver updates live screen */
+
+extern byte attr_packed; /* Flag if attributes packed */
+
+extern byte image_marker; /* Number of active images */
+extern byte image_inter_marker; /* Number of active interface images */
+
+extern Buffer scr_main; /* Full-screen sized work buffer */
+extern Buffer scr_work; /* Background picture sized buffer */
+extern Buffer scr_inter; /* Interface screen sized buffer */
+
+extern Buffer scr_orig; /* Buffer to hold full background picture */
+extern Buffer scr_depth; /* Buffer to hold depth codes */
+extern Buffer scr_walk; /* Buffer to hold walk codes */
+extern Buffer scr_special; /* Buffer to hold special codes */
+
+extern Buffer scr_inter_orig; /* Buffer to hold original interface */
+
+extern int matte_guard_depth_0; /* Guard popup window depth */
+
+extern int work_screen_ems_handle; /* Work screen in EMS */
+
+extern TileMapHeader picture_map, depth_map; /* Tile maps */
+extern TileResource picture_resource, depth_resource; /* Tile resources */
+
+
+
+
+/* matte_1.c */
+void matte_init(int init_series);
+int matte_map_work_screen(void);
+
+
+/* matte_1.c */
+void matte_frame(int special_effect, int full_screen);
+
+/* matte_1.c */
+void matte_init_series(void);
+int matte_load_series(char *name,
+ int load_flags,
+ int bonus_series_number);
+void matte_deallocate_series(int id, int free_memory);
+int matte_allocate_series(SeriesPtr series,
+ int bonus_series_number);
+
+/* matte_1.c */
+void matte_init_messages(void);
+int matte_add_message(FontPtr font, char *text,
+ int x, int y, int message_color,
+ int auto_spacing);
+void matte_clear_message(int handle);
+
+/* matte_1.c */
+int matte_allocate_image(void);
+
+/* matte_1.c */
+void matte_refresh_work(void);
+
+/* matte_2.c */
+void matte_inter_frame(int update_live, int clear_chaff);
+int matte_allocate_inter_image(void);
+void matte_refresh_inter(void);
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/mcga.h b/engines/mads/madsv2/core/mcga.h
new file mode 100644
index 00000000000..5c4fa4ed277
--- /dev/null
+++ b/engines/mads/madsv2/core/mcga.h
@@ -0,0 +1,80 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 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 MADS_CORE_MCGA_H
+#define MADS_CORE_MCGA_H
+
+#include "mads/madsv2/core/general.h"
+#include "mads/madsv2/core/font.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+extern int mcga_retrace_computed;
+extern word mcga_retrace_ticks;
+extern int mcga_retrace_max_colors;
+extern int mcga_retrace_max_bytes;
+
+extern word mcga_palette_update;
+extern int mcga_palette_fast;
+
+
+/* mcga_1.c */
+void mcga_put_pixel(word x, word y, byte c);
+
+/* mcga_2.c */
+byte mcga_get_pixel(word x, word y);
+
+/* mcga_3.c */
+byte *fastcall mcga_open_window(word x, word y,
+ word xsize, word ysize);
+void mcga_close_window(byte *win);
+
+/* mcga_7.c */
+void mcga_setpal(Palette *pal);
+
+/* mcga_8.c */
+void mcga_getpal(Palette *pal);
+
+/* mcga_9.c */
+void mcga_cls(byte inp);
+
+/* mcga_b.c */
+void mcga_retrace(void);
+void mcga_setpal_range(Palette *pal,
+ int first_color,
+ int num_colors);
+
+/* mcga_c.c */
+void mcga_compute_retrace_parameters(void);
+
+/* mcga_d.c */
+extern word mcga_shakes;
+
+void mcga_shake(void);
+
+/* mcga_e.c */
+void mcga_reset(void);
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/mem.h b/engines/mads/madsv2/core/mem.h
new file mode 100644
index 00000000000..1eb430e5745
--- /dev/null
+++ b/engines/mads/madsv2/core/mem.h
@@ -0,0 +1,81 @@
+/* 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 MADS_CORE_MEM_H
+#define MADS_CORE_MEM_H
+
+#include "mads/madsv2/core/general.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+#define MEM_NONE 0xff /* Undefined (himem) */
+
+#define MEM_CONV 0 /* Conventional Memory */
+#define MEM_UMB 1 /* Upper memory block */
+#define MEM_HMA 2 /* High memory area */
+#define MEM_EMS 3 /* Expanded memory */
+#define MEM_XMS 4 /* Extended memory */
+
+
+extern byte mem_max_free_set;
+extern byte umb_max_free_set;
+
+extern byte mem_last_alloc_failed; /* True if last mem_get() failed */
+extern int mem_last_alloc_loader; /* Last loader to use mem_get() */
+extern long mem_last_alloc_size; /* Last size attempted by mem_get */
+extern long mem_last_alloc_avail; /* Last available memory */
+extern long mem_max_free; /* Most memory that was ever free */
+extern long mem_min_free; /* Least memory that was ever free */
+extern long umb_max_free; /* Most UMB that was ever free */
+extern long umb_min_free; /* Least UMB that was ever free */
+
+extern void (*mem_manager_update)(); /* Called at memory updates */
+extern int mem_manager_active; /* Flag if memory manager active */
+
+/* mem_1.c */
+void *fastcall mem_normalize(void *in);
+
+/* mem_2.c */
+void *fastcall mem_get(long size);
+void *fastcall mem_get_name(long size, char *block_name);
+int mem_free(void *block);
+int mem_adjust(void *target, long size);
+void mem_save_free(void);
+void mem_restore_free(void);
+void mem_get_block_name(byte *block,
+ char *block_name);
+
+/* mem_3.c */
+void *fastcall mem_check_overflow(void *in);
+
+/* mem_4.c */
+long mem_get_avail(void);
+long mem_conv_get_avail(void);
+void mem_set_video_mode(int mode);
+
+/* mem_5.c */
+long mem_program_block(void);
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/mouse.h b/engines/mads/madsv2/core/mouse.h
new file mode 100644
index 00000000000..88c6136bd9e
--- /dev/null
+++ b/engines/mads/madsv2/core/mouse.h
@@ -0,0 +1,144 @@
+/* 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 MADS_CORE_MOUSE_H
+#define MADS_CORE_MOUSE_H
+
+#include "mads/madsv2/core/general.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+#define MOUSE_TIMING_ONE 7 /* Mouse 1st repeat delay (ticks) */
+#define MOUSE_TIMING_TWO 2 /* Mouse 2nd repeat delay (ticks) */
+
+#define MOUSE_DOUBLE_TIMING 5 /* Double click threshold (ticks) */
+#define MOUSE_BALLISTIC_TIMING 36 /* Ballistic threshold (ticks) */
+
+extern Buffer mouse_cursor_buffer; /* Points at cursor pixel map */
+
+extern word mouse_driver; /* True if mouse driver is currently active */
+extern word mouse_known_mode; /* True if mouse in a 320x200 graphics mode */
+extern int mouse_video_mode; /* Rom BIOS video mode # of current cursor */
+extern byte mouse_showing; /* Mouse cursor showing status (0 = show) */
+
+extern int mouse_button; /* Last button pressed (0 = left, 1 = right) */
+extern int mouse_status; /* Button status flags */
+extern int mouse_x, mouse_y; /* Most recent cursor position */
+extern int mouse_start_stroke; /* True if new button press this round */
+extern int mouse_stroke_going; /* True if any button currently down */
+extern int mouse_changed; /* True if position or any button changed */
+extern int mouse_latched; /* Internal use (same as mouse_stroke_going) */
+extern int mouse_stop_stroke; /* True if button released this round */
+extern int mouse_any_stroke; /* True if button down or just now released */
+extern int mouse_old_x; /* Cursor X position on previous round */
+extern int mouse_old_y; /* Cursor Y position on previous round */
+extern long mouse_clock; /* Timing clock to insure at least 1 tick */
+
+
+/* mouse_1.asm */
+int mouse_init(int driver_flag, int mouse_video_mode);
+
+/* mouse_1.asm */
+int mouse_set_hotspot(int spot_x, int spot_y);
+
+void mouse_change_cursor_begin(void);
+void mouse_change_cursor_end(void);
+
+/* mouse_1.asm */
+void mouse_screen_swap(int mouse_video_mode);
+int mouse_get_video_mode(void);
+
+/* mouse_1.asm */
+void mouse_begin_double(int first_video_mode, int second_video_mode,
+ int mono_to_right, int auto_freedom);
+void mouse_check_double(void);
+void mouse_end_double(void);
+void mouse_double_freedom(int freedom_flag);
+
+/* mouse_1.asm */
+void mouse_show(void);
+void mouse_hide(void);
+int mouse_get_status(int *x, int *y);
+
+/*
+int mouse_press_info (int button, int *status, int *x, int *y);
+int mouse_release_info (int button, int *status, int *x, int *y);
+
+int mouse_in_box_now (int ul_x, int ul_y, int lr_x, int lr_y);
+*/
+
+/* mouse_1.asm */
+void mouse_timing(void);
+
+/* mouse_1.asm */
+void mouse_freeze(void);
+void mouse_thaw(void);
+
+
+/* mouse_1.asm */
+void mouse_horiz_bound(int min_x, int max_x);
+void mouse_vert_bound(int min_y, int max_y);
+
+/* mouse_1.asm */
+void mouse_force(int x, int y);
+
+/* mouse_1.asm */
+void mouse_set_work_buffer(byte *work_buffer,
+ int wrap_value);
+void mouse_set_view_port_loc(int x1, int y1, int x2, int y2);
+void mouse_set_view_port(int dx, int dy);
+
+/* mouse_1.asm */
+int mouse_refresh_view_port(void);
+void mouse_refresh_done(void);
+
+/* mouse_1.asm */
+void mouse_disable_scale(void);
+
+/* mouse_1.asm */
+void mouse_hard_cursor_mode(int mode, Palette *mypal);
+
+byte *mouse_get_stack(void);
+
+
+
+/* mouse_2.c */
+int mouse_in_box(int ul_x, int ul_y, int lr_x, int lr_y);
+void mouse_init_cycle(void);
+void mouse_begin_cycle(int double_flag);
+void mouse_end_cycle(int double_flag, int timing_flag);
+
+
+/* mouse_3.c */
+void mouse_cursor_sprite(void *series, int id);
+
+
+/* mouse_4.c */
+void mouse_video_init(void);
+void mouse_video_update(int from_x, int from_y,
+ int unto_x, int unto_y,
+ int size_x, int size_y);
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/pack.h b/engines/mads/madsv2/core/pack.h
new file mode 100644
index 00000000000..b55799b21cd
--- /dev/null
+++ b/engines/mads/madsv2/core/pack.h
@@ -0,0 +1,234 @@
+/* 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 MADS_CORE_PACK_H
+#define MADS_CORE_PACK_H
+
+#include "common/stream.h"
+#include "mads/madsv2/core/general.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+#define PACK_ID_STRING "MADSPACK 2.0\032"
+#define PACK_ID_LENGTH 14
+#define PACK_ID_CHECK 12
+
+#define PACK_IMPLODE 0 /* Currently imploding */
+#define PACK_EXPLODE 1 /* Currently exploding */
+#define PACK_RAW_COPY 2 /* Currently copying */
+
+#define FROM_MEMORY 0 /* Read memory */
+#define FROM_DISK 1 /* Read disk */
+#define TO_MEMORY 0 /* Write memory */
+#define TO_DISK 1 /* Write disk */
+#define TO_EMS 2 /* Write EMS */
+
+#define PACK_NONE 0 /* No compression */
+#define PACK_PFAB 1 /* Dave's Stuff */
+#define PACK_ZIP 2 /* Zipped */
+
+#define PACK_IMPLODE_SIZE 35256 /* pkzip implode buffer */
+#define PACK_EXPLODE_SIZE 12574 /* pkzip explode buffer */
+
+#define PACK_PFABCOMP_SIZE 0x71be
+#define PACK_PFABEXP0_SIZE 0x382c
+#define PACK_PFABEXP1_SIZE 0x0820
+#define PACK_PFABEXP2_SIZE 0x0004
+/*
+#define PACK_PFABCOMP_SIZE 0xd1d0
+#define PACK_PFABEXP0_SIZE 0x382e
+#define PACK_PFABEXP1_SIZE 0x0822
+#define PACK_PFABEXP2_SIZE 0x0004
+*/
+
+#define PACK_RAW_COPY_SIZE 0x1000
+
+#define PACK_WINDOW_SIZE 4096 /* sliding window size */
+#define PACK_MIN_WINDOW_SIZE 1024 /* minimum possible size */
+
+#define PACK_MAX_PACKET_SIZE 0xfc00 /* Max size of a packet */
+
+#define PACK_MAX_LIST_LENGTH 16 /* Max # blocks in one file */
+
+
+#define PACK_PRIORITY_SPRITE_SERIES 4
+#define PACK_PRIORITY_ANIMATIONS 5
+
+#define PACK_PRIORITY_FONTS 7
+#define PACK_PRIORITY_ROOM_DATA 8
+#define PACK_PRIORITY_ROOM_HOTSPOTS 9
+#define PACK_PRIORITY_INTERFACES 10
+#define PACK_PRIORITY_ROOM_ART 11
+
+#define PACK_OVERHEAD sizeof(PackList)
+
+typedef struct {
+ byte type;
+ byte priority;
+ long size;
+ long compressed_size;
+} PackStrategy;
+
+typedef PackStrategy *PackStrategyPtr;
+
+
+typedef struct {
+ char id_string[PACK_ID_LENGTH];
+ word num_records;
+ PackStrategy strategy[PACK_MAX_LIST_LENGTH];
+} PackList;
+
+#define PACK_HEADER (PACK_ID_LENGTH + 2)
+
+typedef PackList *PackListPtr;
+
+
+extern byte *pack_read_memory_ptr; /* Current read memory location */
+extern byte *pack_write_memory_ptr; /* Current write memory location */
+
+extern Common::SeekableReadStream *pack_read_file_handle; /* Current read file handle */
+extern Common::WriteStream *pack_write_file_handle; /* Current write file handle */
+
+extern long pack_read_size; /* Size left to read */
+extern long pack_read_count; /* Size read so */
+extern long pack_write_size; /* Size left to write */
+extern long pack_write_count; /* Size written so */
+
+extern word(*pack_read_routine)(char *buffer, word *size);
+/* Pointer to read routine */
+extern void (*pack_write_routine)
+(char *buffer, word *size);
+/* Pointer to write routine */
+
+extern word pack_mode; /* Packing mode (zip/none) */
+extern byte *pack_buffer; /* Packing scrap buffer */
+extern word pack_buffer_size; /* Size of packing buffer */
+
+extern int pack_default; /* Default packing mode */
+
+extern byte pack_zip_enabled; /* ZIP packing enabled */
+extern byte pack_pfab_enabled; /* PFAB packing enabled */
+extern int pack_strategy; /* Current packing strategy */
+
+/* All compression routines called through function pointers, so that */
+/* we can determine at compile time which compression modules will be */
+/* linked. */
+
+extern unsigned short (*pack_implode_routine)
+(unsigned (*read_buff)(char *buffer, unsigned short *size),
+ void (*write_buff)(char *buffer, unsigned short *size),
+ char *work_buff,
+ unsigned short int *type,
+ unsigned short int *dsize);
+
+extern unsigned (*pack_explode_routine)
+(unsigned (*read_buff)(char *buffer, unsigned short *size),
+ void (*write_buff)(char *buffer, unsigned short *size),
+ char *work_buff);
+
+extern unsigned short (*pack_pFABcomp_routine)
+(unsigned (*read_buff)(char *buffer, unsigned short *size),
+ void (*write_buff)(char *buffer, unsigned short *size),
+ char *work_buff,
+ unsigned short int *type,
+ unsigned short int *dsize);
+
+extern unsigned (*pack_pFABexp0_routine)
+(unsigned (*read_buff)(char *buffer, unsigned short *size),
+ void (*write_buff)(char *buffer, unsigned short *size),
+ char *work_buff);
+
+extern unsigned (*pack_pFABexp1_routine)
+(unsigned (*read_buff)(char *buffer, unsigned short *size),
+ char *write_buf,
+ char *work_buff);
+
+extern unsigned (*pack_pFABexp2_routine)
+(byte *read_buf,
+ byte *write_buf,
+ char *work_buff);
+
+
+extern byte *pack_special_buffer;
+extern void (*(pack_special_function))();
+
+
+
+
+/* pack_1.c */
+word pack_read_memory(char *buffer, word *size);
+
+/* pack_2.c */
+void pack_write_memory(char *buffer, word *size);
+
+/* pack_3.c */
+word pack_read_file(char *buffer, word *size);
+
+/* pack_4.c */
+void pack_write_file(char *buffer, word *size);
+
+/* pack_5.c */
+word pack_a_packet(int packing_flag, int explode_mode);
+
+/* pack_6.c */
+long pack_data(int packing_flag, long size,
+ int source_type, void *source,
+ int dest_type, void *dest);
+
+/* pack_6.c */
+void pack_set_special_buffer(byte *buffer_address,
+ void (*(special_function))());
+
+
+/* pack_7.c */
+int pack_check(void);
+
+/* pack_8.c */
+void pack_enable_zip(void);
+
+/* pack_9.c */
+void pack_enable_pfab(void);
+
+/* pack_a.c */
+void pack_enable_pfab_explode(void);
+
+/* pack_b.c */
+void pack_enable_zip_explode(void);
+
+/* pack_c.c */
+long pack_rle(byte *target,
+ byte *source,
+ word source_size);
+
+
+/* pack_d.c */
+extern int pack_ems_page_handle;
+extern int pack_ems_page_marker;
+extern int pack_ems_page_offset;
+
+/* pack_d.c */
+word pack_write_ems(char *buffer, word *mysize);
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/pal.h b/engines/mads/madsv2/core/pal.h
new file mode 100644
index 00000000000..73ed743279b
--- /dev/null
+++ b/engines/mads/madsv2/core/pal.h
@@ -0,0 +1,131 @@
+/* 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 MADS_CORE_PAL_H
+#define MADS_CORE_PAL_H
+
+#include "mads/madsv2/core/general.h"
+#include "mads/madsv2/core/color.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+/* Palette mapping options to be passed to pal_allocate */
+
+#define PAL_MAP_BACKGROUND 0x8000 /* Loading initial background */
+#define PAL_MAP_RESERVED 0x4000 /* Allow mapping of reserved colors */
+#define PAL_MAP_ANY_TO_CLOSEST 0x2000 /* Any color can map to closest */
+#define PAL_MAP_ALL_TO_CLOSEST 0x1000 /* Any colors that can map must map */
+#define PAL_MAP_TOP_COLORS 0x0800 /* Allow mapping to top four colors */
+#define PAL_MAP_DEFINE_RESERVED 0x0400 /* Define initial reserved color */
+
+#define PAL_MAP_MASK 0xfc00 /* Mask for all palette flags on, */
+ /* so that a routine can accept PAL */
+ /* flags along with other flags of */
+ /* its own in the same register, & */
+ /* then forward a clean copy of the */
+ /* PAL flags to pal_allocate(). */
+
+
+#define PAL_FORCE_SHADOW 240
+
+/* Internal facts */
+
+#define PAL_MAXFLAGS 0x20 /* Number of available flags */
+
+#define PAL_RESERVED 0x0001 /* ... 0001 */
+#define PAL_CYCLE 0x0002 /* ... 0010 */
+
+
+/* Returned by pal_deallocate */
+
+#define PAL_ERR_BADFLAG -1 /* Flag number out of range */
+#define PAL_ERR_FLAGNOTUSED -2 /* Attempt to clear unused flag */
+
+
+/* Returned by pal_allocate */
+
+#define PAL_ERR_OUTOFFLAGS -10 /* No available usage flags */
+#define PAL_ERR_OUTOFCOLORS -11 /* Not enough available colors */
+
+
+/* Data available to system: */
+
+extern Palette master_palette; /* Main global palette for program */
+extern ShadowListPtr master_shadow; /* Main global shadow color list */
+
+extern dword color_status[256]; /* Mapping status of each palette color */
+extern int flag_used[PAL_MAXFLAGS];/* Mapping status of each palette handle*/
+
+extern int palette_locked;
+
+extern int palette_low_search_limit; /* Artificial search boundaries */
+extern int palette_high_search_limit;
+
+extern void (*pal_manager_update)();
+extern int pal_manager_active;
+extern int pal_manager_colors;
+
+
+/* pal_1.c */
+
+void pal_init(int reserve_bottom, int reserve_top);
+
+void pal_lock(void);
+void pal_unlock(void);
+
+int pal_allocate(ColorListPtr new_list,
+ ShadowListPtr shadow_list,
+ int pal_flags);
+
+int pal_deallocate(int use_flag);
+void pal_compact(word master_handle, int num_slaves, word *slave);
+
+int pal_get_hash(RGBcolor *one, RGBcolor *two);
+void pal_shadow_sort(ShadowListPtr shadow, ColorListPtr list);
+void pal_init_shadow(ShadowListPtr shadow, ColorListPtr new_list);
+void pal_activate_shadow(ShadowListPtr shadow);
+
+
+/* pal_2.c */
+int pal_get_flags(void);
+
+/* pal_3.c */
+int pal_get_colors(void);
+
+/* pal_4.c */
+void pal_interface(Palette fixpal);
+void pal_white(Palette fixpal);
+void pal_grey(Palette fixpal, int base_color, int num_colors,
+ int low_grey, int high_grey);
+
+/* pal_5.c */
+int pal_get_color(RGBcolor color, int color_handle,
+ int override_reserved, int *color_number);
+
+
+/* pal_6.c */
+void pal_change_color(int color, int r, int g, int b);
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/player.h b/engines/mads/madsv2/core/player.h
new file mode 100644
index 00000000000..5d58faee07c
--- /dev/null
+++ b/engines/mads/madsv2/core/player.h
@@ -0,0 +1,222 @@
+/* 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 MADS_CORE_PLAYER_H
+#define MADS_CORE_PLAYER_H
+
+#include "common/scummsys.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+#define player_verb player2.words[0]/* Player's recent verb */
+#define player_main_noun player2.words[1]/* Player's recent noun 1 */
+#define player_second_noun player2.words[2]/* Player's recent noun 2 */
+
+#define PLAYER_VERTICAL 1 /* Player moving vertically */
+#define PLAYER_DIAGONAL 2 /* Player moving diagonally */
+#define PLAYER_HORIZONTAL 3 /* Player moving horizontally */
+
+#define PLAYER_DIAGONAL_THRESHOLD 141 /* sqrt(2) * 100 */
+
+#define PLAYER_MAX_ROOMS 120 /* Max rooms player can go to */
+
+#define PLAYER_MAX_STOP 12 /* Max items in stop-walker stack */
+
+
+typedef struct {
+ int walking; /* Player is "on the move" */
+ int x, y; /* Player's current screen location */
+ int target_x, target_y; /* Player's screen destination */
+ int sign_x, sign_y; /* Axis pixel signs of movement */
+ int x_count, y_count; /* Internal motion tracking info */
+ int x_counter, y_counter; /* Internal motion tracking info */
+ int target_facing; /* Facing to assume at destination */
+ int special_code; /* Special code currently on top of */
+ int sprite_changed; /* Flag if sprite changes this frame */
+ int frame_delay; /* Tick delay between player frames */
+ int center_of_gravity; /* Center of gravity displacement */
+
+ int walk_freedom; /* Player can always walk anywhere */
+
+ int walk_anywhere; /* Player can walk anywhere */
+
+ int walk_off_edge_to_room; /* Player should walk off edge unless told */
+ /* otherwise. */
+ int walk_off_edge; /* Player walking off edge of screen */
+
+ int need_to_walk; /* Player needs to walk somewhere */
+ int ready_to_walk; /* Player is ready to perform that walk */
+ int prepare_walk_facing; /* Facing preparing to walk to */
+ int prepare_walk_x; /* Destination preparing to walk to */
+ int prepare_walk_y;
+
+ int commands_allowed; /* Flag if accepting player input */
+ int walker_visible; /* Flag if player's sprite is visible */
+ int walker_previously_visible;/* Flag if player's sprite was visible */
+ int series_base; /* Lowest series list handle for walker */
+ int available[8]; /* Flag if series are available or mirrored*/
+ int facing; /* Player's current directional facing */
+ int turn_to_facing; /* Player is turning to this facing */
+ int series; /* Player's current active series # */
+ int mirror; /* Flag if player series is now mirrored */
+ int sprite; /* Current sprite # being displayed */
+
+ byte depth; /* Depth of current player image */
+ byte scale; /* Scale of current player image */
+
+ int stop_walker_sequence; /* Active stop-walker sequence number. */
+ int stop_walker_stack[PLAYER_MAX_STOP]; /* Stack of future stop walkers*/
+ int stop_walker_trigger[PLAYER_MAX_STOP]; /* Trigger codes when complete */
+ int stop_walker_pointer; /* Stack pointer */
+
+ int upcoming_trigger; /* Impending stop-walker trigger code */
+ int trigger; /* Active stop-walker trigger code */
+
+ int next_special_code; /* Next special code player will pass over */
+
+ int scaling_velocity; /* Flag if scaling player velocity */
+ int pixel_accum; /* Internal bresenham motion tracking */
+ int dist_accum; /* Internal bresenham distance tracking */
+ word delta_distance; /* Internal bresenham distance tracking */
+ word total_distance; /* Internal total distance current segment */
+ int velocity; /* Player movement velocity (pix/frame) */
+ int high_sprite; /* Highest sprite # in primary progression */
+
+ int command_ready; /* Flag if a player command is ready to go */
+ int command_error; /* Flag if player command is an error */
+ int command_source; /* Interface stroke type for player verb */
+ int command;
+ int main_object;
+ int second_object;
+ int main_object_source; /* Interface stroke type for player noun 1 */
+ int second_object_source; /* Interface stroke type for player noun 2 */
+ int prep; /* Preposition */
+ int look_around; /* Flag for special "look around" command */
+
+ int main_syntax; /* Syntax of player's main noun */
+ int second_syntax; /* Syntax of player's second noun */
+
+ char series_name[20]; /* Major series name for player walker */
+
+ char sentence[64]; /* Player's most recent sentence. */
+
+ long clock; /* Timing clock for player frame rate */
+
+ byte been_here_before; /* Flag if player has been here before */
+ int num_rooms_been_in; /* # of rooms player has been in */
+ int rooms_been_in[PLAYER_MAX_ROOMS]; /* List of rooms player has been in*/
+
+ int num_series; /* Number of player series */
+ byte walker_loads_first; /* Walker should be loaded first */
+ byte walker_loaded_first; /* Walker walker is loaded first */
+ byte walker_is_loaded; /* Flag if walker is loaded */
+ byte walker_must_reload; /* Flag if walker must reload */
+
+ int walker_been_visible; /* Flag if has been visible this room */
+
+ byte force_series; /* Flag to force player series */
+
+ int walk_trigger; /* Trigger when reach destination */
+ byte walk_trigger_dest; /* Type of code to activate for trigger */
+ int walk_trigger_words[3]; /* Vocabulary words for reactivating parser*/
+
+ int enable_at_target; /* Enable commands at walk target */
+
+} Player;
+
+
+typedef struct {
+ int words[3]; /* Vocab word array of player's sentence */
+} Player2;
+
+
+extern Player player;
+extern Player2 player2;
+
+extern byte player_facing_to_series[10];
+extern byte player_clockwise[10];
+extern byte player_counter_clockwise[10];
+
+
+/* player.h */
+#define player_said_1(aa) (player_parse (words_##aa , 0) )
+#define player_said_2(aa, bb) (player_parse (words_##aa, words_##bb, 0) )
+#define player_said_3(aa, bb, cc) (player_parse (words_##aa, words_##bb, words_##cc, 0) )
+
+
+/* player_1.c */
+void player_new_stop_walker(void);
+void player_stationary_update(void);
+void player_set_facing(void);
+void player_set_final_facing(void);
+void player_select_series(void);
+void player_set_sprite(void);
+void player_keep_walking(void);
+int player_search_image(void);
+void player_set_image(void);
+
+/* player_2.c */
+int player_load_series(char *name);
+void player_himem_preload(char *name, int level);
+void player_dump_walker(void);
+void player_preserve_palette(void);
+
+/* player_3.c */
+void player_new_command(void);
+void player_new_walk(void);
+int player_parse(int vocab_word, ...);
+
+/* player_4.c */
+void player_cancel_walk(void);
+void player_cancel_command(void);
+
+/* player_5.c */
+int player_has_been_in_room(int id);
+void player_discover_room(int id);
+
+/* player_6.c */
+int player_has(int object_id);
+
+/* player_7.c */
+void player_clear_stop_walkers(void);
+void player_init(void);
+void player_start_walking(int walk_x, int walk_y,
+ int walk_facing);
+
+/* player_7.c */
+int player_add_stop_walker(int walker, int trigger);
+void player_walk(int x, int y, int facing);
+void player_walk_trigger(int trigger);
+
+/* player_7.c */
+void player_demand_facing(int facing);
+void player_demand_location(int x, int y);
+
+/* player_7.c */
+void player_first_walk(int from_x, int from_y, int from_facing,
+ int to_x, int to_y, int to_facing,
+ int enable_at_target);
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/popup.h b/engines/mads/madsv2/core/popup.h
new file mode 100644
index 00000000000..d0b2f2641a9
--- /dev/null
+++ b/engines/mads/madsv2/core/popup.h
@@ -0,0 +1,503 @@
+/* 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 MADS_CORE_POPUP_H
+#define MADS_CORE_POPUP_H
+
+#include "mads/madsv2/core/general.h"
+#include "mads/madsv2/core/font.h"
+#include "mads/madsv2/core/sprite.h"
+#include "mads/madsv2/core/heap.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+#define POPUP_UPPER_LEFT 1 /* Pieces of border box */
+#define POPUP_UPPER_RIGHT 2
+#define POPUP_LOWER_LEFT 3
+#define POPUP_LOWER_RIGHT 4
+#define POPUP_LEFT 5
+#define POPUP_RIGHT 6
+#define POPUP_TOP 7
+#define POPUP_BOTTOM 8
+#define POPUP_UPPER_CENTER 9
+
+#define pop_xs(piece) (box_param.series->index[piece-1].xs)
+#define pop_ys(piece) (box_param.series->index[piece-1].ys)
+
+#define pop_y2(piece) (box_param.series->index[piece-1].y)
+#define pop_y(piece) (pop_y2(piece) - pop_ys(piece) + 1)
+
+#define pop_m(piece) (box_param.series->index[piece-1].x)
+#define pop_x(piece) (pop_m(piece) - (pop_xs(piece) >> 1))
+#define pop_x2(piece) (pop_x(piece) + pop_xs(piece) - 1)
+
+#define POPUP_BASE_COLOR 18 /* Popup palette location */
+#define POPUP_NUM_COLORS 8
+
+#define POPUP_FILL_COLOR popup_colors[8] /* Popup fill color */
+#define POPUP_FILL_COLOR_2 popup_colors[9]
+#define POPUP_TEXT_COLOR popup_colors[10]
+#define POPUP_HILITE_COLOR popup_colors[11]
+#define POPUP_HILITE_COLOR_2 popup_colors[12]
+#define POPUP_ASK_COLOR popup_colors[13]
+
+#define popup_normal_color_1 popup_colors[0]
+#define popup_normal_color_2 popup_colors[1]
+#define popup_shadow_color_1 popup_colors[2]
+#define popup_shadow_color_2 popup_colors[3]
+#define popup_hilite_color_1 popup_colors[4]
+#define popup_hilite_color_2 popup_colors[5]
+#define popup_ask_color popup_colors[6]
+#define popup_text_color popup_colors[7]
+
+#define POPUP_DIALOG_TEXT_COLOR popup_colors[14]
+#define POPUP_DIALOG_BUTTON_COLOR_1 popup_colors[15]
+#define POPUP_DIALOG_BUTTON_COLOR_2 popup_colors[16]
+#define POPUP_DIALOG_BORDER_COLOR_1 popup_colors[17]
+#define POPUP_DIALOG_BORDER_COLOR_2 popup_colors[18]
+#define POPUP_DIALOG_SELECT_COLOR popup_colors[19]
+#define POPUP_DIALOG_STRING_COLOR popup_colors[20]
+
+#define POPUP_DIALOG_MENU_TEXT_1 popup_colors[21]
+#define POPUP_DIALOG_MENU_TEXT_2 popup_colors[22]
+#define POPUP_DIALOG_MENU_TEXT_3 popup_colors[23]
+
+#define POPUP_MAX_LINES 20
+#define POPUP_SPACING 1
+
+#define POPUP_CENTER 0x8000 /* General centering */
+#define POPUP_BUTTON_ROW 0x4000 /* Popup buttons only */
+#define POPUP_RIGHT_JUST 0x2000 /* Right side */
+
+#define POPUP_BUTTON_RIGHT 0x0800
+#define POPUP_BUTTON_LEFT 0x0400
+
+#define POPUP_FILL -1 /* Fill on next line */
+
+#define POPUP_BAR 0xffff /* Bar across line */
+#define POPUP_UNDERLINE 0x8000 /* Underline text */
+#define POPUP_DOWNPIXEL 0x4000 /* Down a pixel */
+
+
+#define popup_padding_width 3 /* Extra space on each side */
+
+
+
+typedef struct {
+ SeriesPtr series; /* Sprite series for popup box */
+
+ char name[16]; /* Sprite series name */
+
+ FontPtr font; /* Box font */
+ int font_spacing; /* Box font spacing */
+
+ int top_adjust_y; /* Coordinate adjustments for */
+ int center_adjust_y; /* box pieces (to get them in */
+ int upper_right_adjust_y; /* line). */
+ int left_adjust_x;
+ int lower_left_adjust_x;
+ int bottom_adjust_y;
+ int lower_right_adjust_y;
+ int right_adjust_x;
+
+ int offset_x; /* Window offset within box */
+ int offset_y;
+
+ int extra_x; /* Extra width/height provided by */
+ int extra_y; /* corner pieces */
+
+ int pieces_per_center; /* Number of bottom pieces in center */
+
+ int erase_on_first; /* If true, erases default during ask */
+
+ SeriesPtr logo; /* Logo sprite series, if any */
+ SeriesPtr menu; /* Menu sprite series, if any */
+ FontPtr menu_font; /* Menu font */
+ int menu_font_spacing; /* Menu font spacing */
+
+ int menu_left_width; /* Menu sprite series size */
+ int menu_right_width;
+ int menu_middle_width;
+
+ int menu_text_x_offset; /* Menu text offsets */
+ int menu_text_y_offset;
+ int menu_text_x_bonus; /* Bonus offsets when selected */
+ int menu_text_y_bonus;
+
+} BoxParam;
+
+
+typedef struct {
+ int active;
+
+ int base_x, base_y; /* Box base screen location */
+
+ int x, y; /* Box upper left extremity */
+ int xs, ys; /* Box size */
+
+ int window_x, window_y; /* Window screen location */
+ int window_xs, window_ys; /* Window size */
+
+ int text_xs; /* Horizontal size of actual text */
+ int text_extra; /* Extra padding space (total) */
+
+ int depth_x, depth_xs; /* Depth preserve coordinates */
+
+ int horiz_pieces; /* # of horiz pieces each side */
+ int vert_pieces; /* # of vertical pieces */
+
+ int text_width;
+ int text_x, text_y;
+ int ask_x, ask_y;
+ int cursor_x;
+ word tab[POPUP_MAX_LINES];
+ byte *text[POPUP_MAX_LINES];
+
+ int dont_add_space;
+
+ int preserve_handle;
+ int depth_preserve_handle;
+
+ int screen_saved;
+ int depth_saved;
+
+ word fill_accum;
+
+ SeriesPtr icon; /* Sprite displayed in box */
+ int icon_id;
+ int icon_width;
+ int icon_height;
+
+ int dialog_system; /* Dialog system hooks */
+ long request_y_size;
+
+ int icon_center;
+
+} Box;
+
+
+/* Item types defined so */
+#define ITEM_BLANK 0 /* Null item */
+#define ITEM_BUTTON 1 /* Button */
+#define ITEM_MESSAGE 2 /* String message */
+#define ITEM_SAVELIST 3 /* Saved game list*/
+#define ITEM_SPRITE 4 /* Static sprite */
+#define ITEM_MENU 5 /* Menu item */
+
+/*
+#define ITEM_CHECKBOX 5
+#define ITEM_RADIO 6
+#define ITEM_STRING 7
+*/
+
+
+typedef struct {
+ char *data; /* Heap pointer for buffer space */
+ int max_length; /* Buffer max string width */
+ int width; /* Buffer width in pixels */
+ int base_x; /* Buffer base position */
+ int text_x; /* Buffer base text position */
+ int cursor; /* Buffer cursor location */
+ int select_base;
+ int select_target;
+} PopupBuffer;
+
+
+#define SCROLL_AXIS_HORIZONTAL 0
+#define SCROLL_AXIS_VERTICAL 1
+
+#define SCROLL_STATUS_UP 0x80
+#define SCROLL_STATUS_DOWN 0x40
+
+typedef struct {
+ int axis;
+
+ int status;
+
+ int x, y;
+ int xs, ys;
+
+ int arrow_size;
+ int arrow_1_base;
+ int arrow_2_base;
+
+ int thumb_base;
+ int thumb_item;
+ int thumb_size;
+
+} PopupScrollBar;
+
+
+typedef struct {
+ int box_x, box_y; /* Size of box around list */
+ int box_xs, box_ys;
+
+ int list_x, list_y; /* List item base location */
+ int list_xs, list_ys; /* List item size */
+ int list_xw, list_yw; /* List item width of entry */
+
+ int font_x, font_y; /* Font base location */
+
+ int extra_x, extra_y; /* Extra item (number list) */
+ int extra_xs, extra_ys;
+
+ int rows, columns; /* List rows and columnts */
+ int element_max_length; /* List text length of entry */
+
+ int elements; /* List # of elements */
+ int element_offset; /* List offset to elements */
+
+ int base_element; /* Upper left element */
+ int picked_element; /* Selected element */
+
+ PopupScrollBar scroll; /* ScrollBar info */
+
+ /* ItemPtr attached_string; */
+
+ char *data; /* List string data */
+
+ long double_clock; /* Double click clock */
+ int double_element; /* Double click element */
+
+} PopupList;
+
+#define POPUP_DOUBLE_CLICK_THRESHOLD 20
+
+
+#define POPUP_ITEM_VECTORS 7 /* Item-specific function vectors */
+
+#define VECTOR_X_SIZE 0 /* Compute item X size */
+#define VECTOR_Y_SIZE 1 /* Compute item Y size */
+#define VECTOR_ADJUST 2 /* Adjust coordinates to absolute */
+#define VECTOR_DRAW 3 /* Draw item */
+#define VECTOR_UPDATE 4 /* Update item */
+#define VECTOR_MOUSE 5 /* Accept mouse input */
+#define VECTOR_KEY 6 /* Accept keyboard input */
+
+#define ITEM_STATUS_ACTIVE 0x01
+#define ITEM_STATUS_CLOCK 0x02
+#define ITEM_STATUS_FORCED 0x04
+#define ITEM_STATUS_IN_RANGE 0x08
+
+#define ITEM_STATUS_STRING 0x10
+
+#define ITEM_STATUS_VIRGIN 0x20
+#define ITEM_STATUS_DIRTY 0x40
+#define ITEM_STATUS_INPUT 0x80
+
+#define ITEM_STATUS_INERT 0x100
+
+
+typedef struct {
+ byte type; /* Type of item */
+
+ word status; /* Status of item */
+
+ int misc[10]; /* Item specific */
+
+ int x, y; /* Item location */
+ int xs, ys; /* Item base size */
+
+ int font_x; /* Font X base */
+ int font_y; /* Font Y base */
+
+ int keystroke; /* Hotkey for item */
+
+ long mouse_interval; /* Mouse interval */
+
+ char *prompt; /* Item label */
+
+ PopupBuffer *buffer; /* Item buffer */
+ PopupList *list; /* Item list */
+
+ SeriesPtr series; /* Sprite series */
+ int sprite; /* Sprite id */
+
+ void (*vector[POPUP_ITEM_VECTORS])(); /* Vectors */
+
+} PopupItem;
+
+
+#define POPUP_MOUSE_SCROLL 0x8000 /* Mouse in scroll bar */
+#define POPUP_MOUSE_UP 0x4000 /* Mouse scrolling up */
+#define POPUP_MOUSE_DOWN 0x2000 /* Mouse scrolling down */
+
+
+#define POPUP_STATUS_DYNAMIC 0x8000 /* Popup created dynamically */
+#define POPUP_STATUS_VALID 0x4000 /* Popup valid */
+#define POPUP_STATUS_EXIT 0x2000 /* Popup ready to exit */
+
+#define POPUP_STATUS_BAR 0x0004 /* Popup bar should be drawn */
+#define POPUP_STATUS_STEAL 0x0002 /* Popup bar should steal color */
+#define POPUP_STATUS_BUTTON 0x0001 /* Popup button row in use */
+
+
+typedef struct {
+ Heap heap; /* Popup heap space */
+
+ word status; /* Popup status flags */
+
+ int x, y; /* X location */
+ int width; /* X minimum width */
+ int y_position; /* Y current usage */
+ int y_spacing; /* Y spacing */
+ int xs, ys; /* Window size information */
+
+ int button_y; /* Button Y location */
+ int button_spacing; /* Button spacing */
+ int button_left_fill; /* Button row left fill */
+ int button_right_fill; /* Button row right fill */
+ int button_bar_color; /* Button bar color */
+
+ int key; /* Last keyboard input */
+ int key_handled; /* Flag if key handled */
+
+ int mouse_status; /* Mouse status word */
+ long mouse_clock; /* Mouse action clock */
+
+ PopupItem *enter_item; /* ENTER key button */
+ PopupItem *cancel_item; /* CANCEL (ESC key) item */
+
+ PopupItem *string_item; /* STRING item, if any */
+
+ PopupItem *mouse_item; /* Mouse active item */
+ PopupItem *active_item; /* Active item */
+
+ PopupItem *list_item; /* List item */
+ PopupItem *clear_item; /* Clear list item */
+
+ int max_items; /* Maximum # of items */
+ int num_items; /* Number of items in popup */
+
+ PopupItem *item; /* Item list */
+} Popup;
+
+
+extern Box text_box;
+extern Box *box;
+
+extern int popup_key;
+extern int popup_esc_key;
+extern int popup_asking_number;
+
+extern int popup_available;
+
+
+extern int popup_preserve_initiator[3];
+
+extern byte popup_colors[8];
+extern byte popup_num_colors;
+
+extern BoxParam box_param;
+
+
+/* popup_1.c */
+int popup_create(int horiz_pieces, int x, int y);
+void popup_add_icon(SeriesPtr series, int id, int center);
+int popup_draw(int save_screen, int depth_code);
+void popup_destroy(void);
+
+/* popup_1.c */
+void popup_next_line(void);
+void popup_set_ask(void);
+void popup_add_string(char *string);
+void popup_write_string(char *string);
+void popup_bar(void);
+void popup_underline(void);
+void popup_downpixel(void);
+void popup_tab(int tab_level);
+void popup_center_string(char *string, int underline);
+
+/* popup_1.c */
+int popup_and_wait(int save_screen);
+int popup_and_dont_wait(int save_screen);
+
+/* popup_1.c */
+void popup_update_ask(char *string, int maxlen);
+int popup_ask_string(char *target, int maxlen, int save_screen);
+int popup_ask_number(long *value, int maxlen, int save_screen);
+
+
+/* popup_2.c */
+int popup_estimate_pieces(int maxlen);
+int popup_get_string(char *target, char *top,
+ char *left, int maxlen);
+int popup_get_long(long *value, char *top,
+ char *left, int maxlen);
+int popup_get_number(int *value, char *top,
+ char *left, int maxlen);
+
+/* popup_3.c */
+int popup_alert(int width, char *message_line, ...);
+
+/* popup_4.c */
+int popup_box_load(void);
+
+/* popup_5.c */
+Popup *popup_activate(Popup *newpop);
+int popup_exec_function(PopupItem *item, int function);
+char *popup_heap(long mem_to_get);
+
+/* popup_5.c */
+Popup *popup_dialog_create(void *memory,
+ long heap_size,
+ int max_items);
+Popup *popup_dialog_destroy(void);
+
+/* popup_5.c */
+PopupItem *popup_button(char *prompt, int x);
+PopupItem *popup_cancel_button(char *prompt);
+PopupItem *popup_message(char *prompt, int x, int y);
+PopupItem *popup_execute(void);
+
+/* popup_5.c */
+PopupItem *popup_savelist(byte *data,
+ byte *empty_string,
+ int elements,
+ int element_offset,
+ int element_max_length,
+ int pixel_width,
+ int rows,
+ int accept_input,
+ int default_element);
+
+/* popup_5.c */
+void popup_blank(int num_lines);
+void popup_blank_line(void);
+void popup_width_force(int width);
+
+
+/* popup_5.c */
+void popup_menu_option(PopupItem *item, char *option);
+PopupItem *popup_menu(char *prompt,
+ int x, int y, int pixel_width,
+ int off_center_x,
+ int elements, int element_max_length,
+ int default_element);
+
+/* popup_5.c */
+PopupItem *popup_sprite(SeriesPtr series, int sprite, int x, int y);
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/quote.h b/engines/mads/madsv2/core/quote.h
new file mode 100644
index 00000000000..61adfa45772
--- /dev/null
+++ b/engines/mads/madsv2/core/quote.h
@@ -0,0 +1,48 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef MADS_CORE_QUOTE_H
+#define MADS_CORE_QUOTE_H
+
+#include "mads/madsv2/core/general.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+#define QUOTE_MAX_LIST_LENGTH 200
+
+extern int quote_emergency;
+
+/* quote_1.c */
+char *quote_load(int quote_id, ...);
+
+/* quote_2.c */
+char *quote_string(const char *quote_list, int quote_id);
+
+/* quote_3.c */
+void quote_split_string(char *source,
+ char *target1,
+ char *target2);
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/room.h b/engines/mads/madsv2/core/room.h
new file mode 100644
index 00000000000..79e45c3dd18
--- /dev/null
+++ b/engines/mads/madsv2/core/room.h
@@ -0,0 +1,338 @@
+/* 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 MADS_CORE_ROOM_H
+#define MADS_CORE_ROOM_H
+
+#include "mads/madsv2/core/general.h"
+#include "mads/madsv2/core/vocab.h"
+#include "mads/madsv2/core/color.h"
+#include "mads/madsv2/core/anim.h"
+#include "mads/madsv2/core/image.h"
+#include "mads/madsv2/core/loader.h"
+#include "mads/madsv2/core/tile.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+#define room_file_version "4.01"
+#define pict_file_version "4.01"
+
+/* Flags to be passed to room_load(). Note that any of the PAL_MAP... */
+/* flags can be passed to this routine as well. */
+
+#define ROOM_LOAD_TRANSLATE 0x0001 /* Translate to 16 colors */
+#define ROOM_LOAD_HARD_SHADOW 0x0010 /* Load hard shadow */
+
+#define ROOM_MAX_VARIANTS 10
+#define ROOM_MAX_HOTSPOTS 40
+#define ROOM_MAX_RAILS 20
+
+#define ROOM_MAX_SERIES 10
+#define ROOM_MAX_IMAGES 50
+
+#define ROOM_FORMAT_NORMAL 1
+#define ROOM_FORMAT_PANNING 2
+
+#define ROOM_PICTURE 0
+#define ROOM_WALK 1
+#define ROOM_DEPTH 2
+#define ROOM_SPECIAL 3
+
+#define ROOM_DEFAULT_ATTRIBUTE 0x0f
+
+#define LEGALITY_MASK 0xc000
+#define WEIGHT_MASK 0x3fff
+
+#define LEGAL 0x8000
+#define ILLEGAL 0x4000
+#define TOTALLY_ILLEGAL 0x0000
+
+#define WALK_DIRECT -1 /* Walk to clicked point */
+ /* (but only for default) */
+#define WALK_NONE -2 /* Don't walk at all */
+#define WALK_DIRECT_2 -3 /* Walk to clicked, always */
+
+#define artwork_file series_name[ROOM_MAX_SERIES-1]
+
+
+/* Develop-time structure for hotspots (.HOT files) */
+
+typedef struct HotEdit {
+ int ul_x, ul_y, lr_x, lr_y; /* Hotspot screen coordinates */
+ int feet_x, feet_y; /* Walk-to target for player */
+ byte facing; /* Direction player should face */
+ byte prep; /* Preposition */
+ byte cursor_number; /* Mouse cursor number */
+ byte syntax; /* Word syntax */
+ char vocab[VC_MAXWORDLEN + 1]; /* Vocabulary name of hotspot */
+ char verb[VC_MAXWORDLEN + 1]; /* Vocabulary default verb name */
+} HotSpotEdit;
+
+typedef HotSpotEdit *HotEditPtr;
+
+
+/* Run-time structure for hotspots (.HH files) */
+
+typedef struct {
+ int ul_x, ul_y, lr_x, lr_y; /* Hotspot screen coordinates */
+ int feet_x, feet_y; /* Walk-to target for player */
+ byte facing; /* Direction player should face */
+ byte prep; /* Preposition */
+ byte active; /* Flag if hotspot is active */
+ byte cursor_number; /* Mouse cursor number */
+ byte syntax; /* Syntax */
+ int vocab; /* Vocabulary id of hotspot name */
+ int verb; /* Vocabulary id of default verb */
+} HotSpot;
+
+typedef HotSpot *HotPtr;
+
+
+/* "Rail" nodes for smart walk */
+
+typedef struct Rail {
+ int x, y; /* Screen location of node */
+ word weight[ROOM_MAX_RAILS + 2]; /* Distance to other nodes in room */
+} Rail;
+
+typedef Rail *RailPtr;
+
+
+/* Room artwork definition structure (.ART files) */
+
+typedef struct {
+ int xs; /* Size of picture (follows this... */
+ int ys; /* ...structure in the .ART file) */
+ ColorList color_list; /* List of colors used in picture */
+ CycleList cycle_list; /* List of color cycling ranges */
+} RoomArt;
+typedef RoomArt *RoomArtPtr;
+
+
+/* Room picture definition structure (.PCT files) */
+
+typedef struct {
+ int id; /* Room id */
+ int picture_id; /* Room picture id */
+ int format; /* Attribute format*/
+ int xs, ys; /* Size */
+
+ int misc[10]; /* padding */
+
+ int num_variants; /* # of variants */
+ char variant_desc[ROOM_MAX_VARIANTS][64]; /* descriptions */
+
+ int num_series;
+ int num_images;
+ char series_name[ROOM_MAX_SERIES][64]; /* # of series */
+ Image image_list[ROOM_MAX_IMAGES]; /* # of images */
+
+ int num_translated; /* Number of colors translated to 16 */
+ ColorList color_list; /* Room's color list */
+
+ CycleList cycle_list; /* Room's color cycling information */
+} RoomPict;
+
+typedef RoomPict RoomPictPtr;
+
+
+/* Room definition structure (.DEF files) */
+
+typedef struct {
+
+ char picture_base[80]; /* Picture base */
+
+ int misc[10]; /* Room padding */
+
+ int num_hotspots; /* # of hotspots */
+ HotSpotEdit hotspot[ROOM_MAX_HOTSPOTS]; /* definitions */
+
+ int front_y, back_y; /* Player scaling baselines */
+ int front_scale, back_scale;/* Player scaling factors */
+
+ int depth_table[16]; /* Player sprite depth table */
+
+ int num_rails; /* # of rails */
+ Rail rail[ROOM_MAX_RAILS + 2];/* Smart walk rails */
+
+ ShadowList shadow; /* Shadow list */
+
+} RoomDef;
+
+
+
+/* Loadable Room definition (.DAT files) */
+
+typedef struct {
+ /* int id; Room number */
+ /* int picture_id; Room whose ART file is needed */
+ /* int format; Room format (panning/normal) */
+ /* int xs, ys; X and Y size of room picture */
+ char picture_base[80]; /* Picture base name */
+ int misc[10]; /* Padding for future updates */
+ int num_variants; /* Number of attribute variants */
+ int num_hotspots; /* Number of hot spots */
+ int num_rails; /* Number of rail nodes */
+ int front_y, back_y; /* Player scaling baselines */
+ int front_scale, back_scale; /* Player scaling factors */
+ int depth_table[16]; /* Player depth table */
+ Rail rail[ROOM_MAX_RAILS]; /* Rail nodes for room */
+
+ /* int num_series; Number of background series */
+ /* int num_images; Number of background images */
+
+ /* char series_name[ROOM_MAX_SERIES][64]; Sprite series needed */
+ /* Image image_list [ROOM_MAX_IMAGES]; Images to be drawn */
+
+ ShadowList shadow; /* Shadow list */
+} RoomFile;
+
+
+
+/* Run-time room definition structure (in memory) */
+
+typedef struct {
+ /* int id; Room number */
+ /* int picture_id; Room whose ART file is needed */
+ /* int format; Room format (panning/normal) */
+ int xs, ys; /* X and Y size of room picture */
+
+ int misc[10]; /* Padding for future updates */
+ int num_variants; /* Number of attribute variants */
+ int num_hotspots; /* Number of hotspots */
+ int num_rails; /* Number of rail nodes */
+ int front_y, back_y; /* Player scaling baselines */
+ int front_scale, back_scale; /* Player scaling factors */
+ int depth_table[16]; /* Player depth table */
+
+ int color_handle; /* Background color handle */
+ int variant_loaded; /* Current attribute variant */
+
+ CycleList cycle_list; /* Active color cycling ranges */
+
+ Rail rail[1]; /* Rail nodes begin here... */
+} Room;
+
+typedef Room *RoomPtr;
+
+
+extern RoomDef roomdef;
+
+extern int room_load_error;
+
+
+/* room_1.cpp */
+int room_read_def(int room_code, char *room_file,
+ char *picture_base, int mads_mode);
+
+int room_write_def(int room_code, char *room_file,
+ int mads_mode);
+
+/* room_2.cpp */
+RoomPtr room_load(int id,
+ int variant,
+ char *base_path,
+ Buffer *picture,
+ Buffer *depth,
+ Buffer *walk,
+ Buffer *special,
+ TileMapHeader *picture_map,
+ TileMapHeader *depth_map,
+ TileResource *picture_resource,
+ TileResource *depth_resource,
+ int picture_ems_handle,
+ int depth_ems_handle,
+ int load_flags);
+
+
+/* room_2.cpp */
+void room_unload(RoomPtr room,
+ Buffer *picture,
+ Buffer *depth,
+ Buffer *walk,
+ Buffer *special,
+ TileMapHeader *picture_map,
+ TileMapHeader *depth_map);
+
+
+
+/* room_3.cpp */
+extern byte room_loaded_depth;
+extern byte room_loaded_walk;
+extern byte room_loaded_special;
+
+int room_load_variant(int id,
+ int variant,
+ char *base_path,
+ RoomPtr room,
+ Buffer *depth,
+ Buffer *walk,
+ Buffer *special,
+ TileMapHeader *depth_map,
+ TileResource *depth_resource,
+ int depth_ems_handle);
+
+/* room_3.cpp */
+void room_dump_attribute(Buffer *depth,
+ Buffer *walk,
+ Buffer *special,
+ TileMapHeader *depth_map);
+
+/* room_4.cpp */
+int room_compile_hotspots(int id, int compression);
+
+/* room_5.cpp */
+HotPtr room_load_hotspots(int id, int *num_spots);
+
+/* room_6.cpp */
+int room_read_pict(int room_code, char *room_file,
+ int mads_mode);
+
+int room_write_pict(int room_code, char *room_file,
+ int mads_mode);
+
+/* room_7.cpp */
+void room_file_name(char *target, char *suffix,
+ int code, char *main_name, int mads_mode);
+
+
+/* room_8.cpp */
+void room_himem_preload(int room, int level);
+
+
+/* room_9.cpp */
+RoomPtr room_dummy_init(int xs, int ys);
+
+/* room_a.cpp */
+int room_picture_load(int room_id, Buffer *picture, int load_flags);
+
+/* room_b.cpp */
+void room_resolve_base(char *base, char *file, int id, char *base_path);
+
+
+/* room_c.cpp */
+int room_invert(void);
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/screen.h b/engines/mads/madsv2/core/screen.h
new file mode 100644
index 00000000000..92a99377853
--- /dev/null
+++ b/engines/mads/madsv2/core/screen.h
@@ -0,0 +1,157 @@
+/* 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 MADS_CORE_SPEECH_H
+#define MADS_CORE_SPEECH_H
+
+#include "mads/madsv2/core/general.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+/* some colors */
+
+#define black 0x00
+#define blue 0x01
+#define green 0x02
+#define cyan 0x03
+#define red 0x04
+#define magenta 0x05
+#define yellow 0x06
+#define white 0x07
+#define hi_black 0x08
+#define hi_blue 0x09
+#define hi_green 0x0a
+#define hi_cyan 0x0b
+#define hi_red 0x0c
+#define hi_magenta 0x0d
+#define hi_yellow 0x0e
+#define hi_white 0x0f
+
+#define colorbyte(f,b) ( ( (b) << 4) + f )
+
+#define colorhash(color) ((long) ((((long)color.r) << 16) + (((long)color.g) << 8) + (((long)color.b) ) ))
+
+#define screen_char_add(x,y) ( ( ( (y) * 80) + x) * 2 )
+#define screen_color_add(x,y) ( ( ( ( (y) * 80) + x) * 2 ) + 1 )
+
+extern byte *screen;
+extern int *screen_bound_x;
+
+extern int screen_video_mode;
+extern int screen_max_x;
+extern int screen_max_y;
+
+extern int screen_center_x;
+extern int screen_center_y;
+
+extern int screen_save_mode;
+extern int screen_save_size;
+
+extern int screen_normal_color;
+extern int screen_hilite_color;
+
+extern int screen_line_width;
+
+extern Palette pal_orig;
+extern Buffer scr_live;
+
+extern Window screen_active;
+
+/* screen_1.c */
+void screen_set_size(short numlines);
+
+/* screen_2.c */
+void screen_wipe_line(short ul_x, short ul_y, short len,
+ short wipe_color, byte wipe_char);
+
+/* screen_3.c */
+short screen_out(char *outstring, short strcolor,
+ short selcolor, short str_x, short str_y);
+
+/* screen_4.c */
+short screen_put(char *outstring,
+ short strcolor, short selcolor,
+ short str_x, short str_y);
+
+/* screen_5.c */
+void screen_set_colors(int normal_color, int hilite_color);
+void screen_set_line_width(int line_width);
+
+/* screen_6.c ... DO NOT USE */
+short screen_show(char *outstring, short locx, short locy);
+
+/* screen_7.c */
+short screen_show_line(char *outstring,
+ short locx, short locy);
+
+/* screen_8.c */
+short screen_write(char *outstring);
+
+/* screen_9.c */
+short screen_write_line(char *outstring);
+
+/* screen_a.c */
+void screen_clear(int clear_color);
+
+/* screen_b.c */
+void screen_dominant_mode(int dominant_mode);
+
+/* screen_c.c */
+void screen_init(int video_mode);
+
+/* screen_d.c */
+void screen_init_dual(int mono_left);
+void screen_shutdown_dual(int clear_flag);
+
+/* screen_e.c */
+void screen_init_graphics(int which_mode);
+void screen_shutdown_graphics(int clear_flag);
+
+/* screen_f.c */
+void screen_show_spot(char *message, int wx, int wy,
+ int class, int num);
+
+/* screen_g.c ... DO NOT USE */
+int screen_printf(int x, int y, char *string, ...);
+int screen_print(char *string, ...);
+
+
+/* screen_h.c */
+void screen_init_text(int which_mode);
+void screen_shutdown_text(int clear_flag);
+
+
+/* screen_i.c */
+void screen_save(void);
+void screen_restore(void);
+
+
+/* screen_j.c */
+short screen_show_wide(char *outstring,
+ short locx,
+ short locy,
+ short width);
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/sound.h b/engines/mads/madsv2/core/sound.h
new file mode 100644
index 00000000000..c14278959d6
--- /dev/null
+++ b/engines/mads/madsv2/core/sound.h
@@ -0,0 +1,37 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef MADS_CORE_SOUND_H
+#define MADS_CORE_SOUND_H
+
+#include "common/scummsys.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+constexpr int sound_board_roland = 1;
+
+extern void sound_queue(int soundNum);
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/speech.cpp b/engines/mads/madsv2/core/speech.cpp
new file mode 100644
index 00000000000..6987230872a
--- /dev/null
+++ b/engines/mads/madsv2/core/speech.cpp
@@ -0,0 +1,54 @@
+/* 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/textconsole.h"
+#include "mads/madsv2/core/speech.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+bool speech_system_active = false;
+bool speech_on = false;
+int speech_ems_handle;
+
+SpeechDirPtr speech_load(const char *resName, int id, bool) {
+ warning("TODO: speech_load");
+ return nullptr;
+}
+
+void speech_ems_play(const char *resName, int id) {
+ warning("TODO: global_speech_resource");
+}
+
+void speech_all_off() {
+ warning("TODO: speech_all_off");
+}
+
+void speech_sample_rate(int rate) {
+ warning("TODO: speech_sample_rate");
+}
+
+void speech_ems_go(int handle, int size) {
+ warning("TODO: speech_ems_go");
+}
+
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/core/speech.h b/engines/mads/madsv2/core/speech.h
new file mode 100644
index 00000000000..d58c98f4fad
--- /dev/null
+++ b/engines/mads/madsv2/core/speech.h
@@ -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/>.
+ *
+ */
+
+#ifndef MADS_CORE_SPEECH_H
+#define MADS_CORE_SPEECH_H
+
+#include "mads/madsv2/core/general.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+struct SpeechBuffer {
+ int sample_rate;
+ int decompress_size;
+};
+
+typedef void *SpeechDirPtr;
+
+extern bool speech_system_active;
+extern bool speech_on;
+extern int speech_ems_handle;
+extern SpeechBuffer speech_main_buffer;
+
+extern SpeechDirPtr speech_load(const char *resName, int id, bool);
+extern void speech_ems_play(const char *resName, int id);
+extern void speech_all_off();
+extern void speech_sample_rate(int rate);
+extern void speech_ems_go(int handle, int size);
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/sprite.h b/engines/mads/madsv2/core/sprite.h
new file mode 100644
index 00000000000..da1c5f5ccd2
--- /dev/null
+++ b/engines/mads/madsv2/core/sprite.h
@@ -0,0 +1,432 @@
+/* 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 MADS_CORE_SPRITE_H
+#define MADS_CORE_SPRITE_H
+
+#include "common/stream.h"
+#include "mads/madsv2/core/color.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+#define sprite_file_version "3.02"
+
+#define misc_largest_block misc[0]
+/* LONG ... uses misc[1] also */
+#define misc_is_a_walker misc[2]
+
+/* Flags to be passed to sprite_series_load(). Note that all of the */
+/* PAL_MAP_... flags can also be passed to this routine (see pal.mac). */
+
+#define SPRITE_LOAD_TRANSLATE 0x0001 /* Translate to 16 colors */
+#define SPRITE_LOAD_HEADER_ONLY 0x0002 /* Load nothing but header */
+#define SPRITE_LOAD_WALKER_INFO 0x0004 /* Load walker information */
+#define SPRITE_LOAD_SPINNING_OBJECT 0x0008 /* Load spinning object */
+
+
+/* Sprite ID masking values for mirroring */
+
+#define SPRITE_MASK 0x7fff /* Sprite ID mask */
+#define MIRROR_MASK 0x8000 /* Sprite mirror mask */
+
+#define HALF_MIRROR_MASK 0x80 /* Mirror mask for bytes */
+#define HALF_SPRITE_MASK 0x7f /* Sprite mask for bytes */
+
+
+/* Sprite line packing types: */
+#define SS_DUMP 251 /* Defines a line as DUMP type */
+#define SS_RLE 253 /* Defines a line as RLE type */
+#define SS_IRLE 254 /* Defines a line as IRLE type */
+#define SS_LASTVALID 252 /* Last valid non-macro byte value */
+
+/* Control characters: */
+#define SS_EOI 252 /* End Of Image */
+#define SS_EOL 255 /* End of line */
+#define SS_RUN 254 /* Marks begining of a run in IRLE */
+#define SS_SKIP 253 /* Used as SKIP color */
+ /* -- Never set SS_SKIP to 255! -- (RBR) */
+ /* -- Would explode color list crap -- */
+ /* -- SS_SKIP must not = COLOR_TRANSPARENT */
+
+
+#define SPRITE_COLOR_TABLE_SIZE 252
+
+#define MAX_SECONDARY 16 /* Maximum secondary walker sequences */
+
+
+
+
+ /* Legal values for x->source_type */
+#define SS_LBM 1 /* Source file is one frame LBM */
+#define SS_LBM_MULT 2 /* Source file is several LBMs */
+#define SS_ANM 3 /* Source file is an .ANM file */
+#define SS_FLI 4 /* Source file is a .FLI file */
+
+ /* Legal values for x->base_mode */
+#define SS_FIRSTFRAME 1 /* If relative to first frame of ANM */
+#define SS_STATICLBM 2 /* If relative to an LBM */
+#define SS_BACKCOL 3 /* If relative to background color */
+#define SS_INDIVIDUAL 4 /* Individual frames relative to first */
+#define SS_PANNING_ANM 5 /* Relative to panning ANM */
+#define SS_PANNING_FLI 6 /* Relative to panning FLI */
+
+
+/* STRUCTURES FOR ALL SPRITE LEVELS */
+
+typedef struct {
+ int num_primary; /* Number of primary sequence frames */
+ int num_secondary; /* Number of secondary sequences */
+ int sequence_start[MAX_SECONDARY]; /* Secondary sequence start frames */
+ int sequence_stop[MAX_SECONDARY]; /* Secondary sequence stop frames */
+ int sequence_chance[MAX_SECONDARY];/* Secondary sequence probability */
+
+ int velocity; /* Pixel velocity for walker */
+ byte frame_rate; /* Frame rate for walker */
+ byte center_of_gravity; /* Center of gravity displacement */
+} WalkerInfo;
+
+typedef WalkerInfo *WalkerInfoPtr;
+
+
+
+/* DEVELOP TIME STRUCTURES (.DSS Files) */
+
+/* Develop-time definition of a single sprite */
+
+typedef struct {
+ char name[9]; /* Sprite name */
+ int x, y; /* Sprite location */
+ int xs, ys; /* Size of sprite */
+} HagSprite;
+
+typedef HagSprite *HagSpritePtr;
+
+
+/* Develop-time definition of a sprite series */
+
+typedef struct {
+ char name[80]; /* Name */
+ char desc[80]; /* Description */
+
+ int source_type; /* Type of source data (see above) */
+ char source_name[80]; /* Filename of source file (LBM or ANM) */
+
+ int delta_series; /* Boolean: delta vice absolute */
+
+ int base_mode; /* Sprites relative to what? (see above) */
+ char base_lbm[80]; /* Name of LBM if base_mode==SS_STATICLBM */
+
+ int pack_by_sprite; /* Packed by sprite vice series? */
+
+ WalkerInfo walker; /* Walker information. */
+
+ int offset_x_view; /* View offsets for sprites intended */
+ int offset_y_view; /* for extra-wide screen animations */
+
+ int series_is_font; /* Flag if series is a font */
+
+ int misc[16]; /* 16 words of miscellaneous data */
+
+ int num_sprites; /* Number of sprites in series */
+
+ byte transparent; /* Transparent color */
+ byte border; /* Border color */
+
+ int num_translated; /* Number of colors translated */
+ int color_list_valid; /* Color list is valid flag */
+
+ ColorList color_list; /* Series master color list */
+
+ HagSprite index[1]; /* Sprites */
+} HagSeries;
+
+typedef HagSeries *HagSeriesPtr;
+
+
+/* LOADABLE FILE STRUCTURES (.SS files) */
+
+/* Loadable sprite record */
+
+typedef struct {
+ long file_offset; /* Location of sprite data in file */
+ long memory_needed; /* Memory needed to hold sprite data */
+ int x, y;
+ int xs, ys;
+} FileSprite;
+
+typedef FileSprite *FileSpritePtr;
+
+
+/* Loadable sprite series record */
+
+typedef struct FileSeriesBuf {
+ byte pack_by_sprite; /* Overall series packing strategy */
+ byte compression; /* Type of compression */
+ int delta_series; /* Flag if series is a delta series */
+ int base_mode; /* Base mode optimization type */
+
+ int misc[16]; /* Miscellaneous data for updates */
+
+ int num_sprites; /* Number of sprites in series */
+
+ WalkerInfo walker; /* Walker information */
+
+ int offset_x_view; /* View offsets for sprites intended */
+ int offset_y_view; /* for extra-wide animations */
+
+ long total_data_size; /* Total uncompressed data size */
+ FileSprite index[1]; /* Sprite records begin here */
+} FileSeries;
+
+typedef FileSeries *FileSeriesPtr;
+
+
+/* RUNTIME STRUCTURES -- MEMORY */
+
+/* Global paging information for a stream-loaded sprite series */
+
+typedef struct {
+ byte paging_source; /* Is source EMS, XMS, or hard disk? */
+ byte packing_mode; /* Type of compression involved */
+ Common::SeekableReadStream *handle; /* File handle for hard disk load */
+ long base_sprite_offset; /* Base file offset for sprite data */
+ int ems_handle; /* EMS handle for preloaded sprites */
+ int ems_page_marker; /* EMS page number of current read */
+ int ems_page_offset; /* EMS page offset of current read */
+ int xms_handle; /* XMS handle for preloaded sprites */
+ long xms_offset; /* XMS offset for current read */
+} SpritePageInfo;
+
+typedef SpritePageInfo *SpritePageInfoPtr;
+
+
+/* Sprite-specific paging informatio for stream-loaded series */
+
+typedef struct {
+ long file_offset; /* Offset in file for sprite's data */
+ long memory_needed; /* Amount of memory needed for sprite */
+} SpritePageTable;
+
+typedef SpritePageTable *SpritePageTablePtr;
+
+
+/* Runtime memory structure for an individual sprite */
+
+typedef struct {
+ byte *data; /* Pointer to sprite's actual data */
+ int x, y; /* Home position on screen */
+ int xs, ys; /* Sprite box size */
+} Sprite;
+
+typedef Sprite *SpritePtr;
+
+
+/* Runtime memory structure for a sprite series */
+
+typedef struct {
+ int delta_series; /* Flag if series is a delta series */
+ int base_mode; /* Series base mode optimization scheme */
+
+ int num_sprites; /* Number of sprites in series */
+
+ int color_handle; /* Palette handle for loaded colors */
+ int misc[16]; /* Miscellaneous data for future updates */
+
+ int offset_x_view; /* View offsets for sprites intended for */
+ int offset_y_view; /* ... extra wide background pictures. */
+
+ byte pack_by_sprite; /* Overall sprite packing strategy */
+ SpritePageInfoPtr page_info; /* Pointer to global paging data, if any */
+ SpritePageTablePtr page_table; /* Pointer to sprite paging table,if any */
+ byte *color_table; /* Pointer to sprite color table ,if any */
+ byte *arena; /* Pointer to sprite data load arena,if any */
+
+ WalkerInfoPtr walker; /* Pointer to walker information ,if any */
+
+ Sprite index[1]; /* Individual sprite records begin here */
+} Series;
+
+typedef Series *SeriesPtr;
+
+#define SS_ERR_OPENFILE -1
+#define SS_ERR_READFILE -2
+#define SS_ERR_WRITEFILE -3
+#define SS_ERR_NOMOREMEMORY -4
+#define SS_ERR_MAKEDIALOG -5
+#define SS_ERR_PALETTEMISMATCH -6
+#define SS_ERR_BOUNDARY -7
+#define SS_ERR_TOOMANYSPRITES -8
+#define SS_ERR_TOOMANYCOLORS -9
+#define SS_ERR_BADDEFINITION -10
+#define SS_ERR_OLDDEFINITION -11
+
+
+extern byte *sprite_force_memory;
+extern long sprite_force_size;
+
+/* sprite_1.c */
+void sprite_draw(SeriesPtr series, int id, Buffer *buf,
+ int target_x, int target_y);
+
+
+/* sprite_2.c */
+void sprite_draw_scaled(SeriesPtr series, int id, Buffer *buf,
+ int target_x, int target_y, int scale_factor);
+
+
+/* sprite_3.c */
+void sprite_draw_3d_scaled(SeriesPtr series, int id,
+ Buffer *buf, Buffer *attr,
+ int target_x, int target_y,
+ int target_depth, int scale_factor);
+
+/* sprite_4.c */
+void sprite_draw_3d_big(SeriesPtr series, int id,
+ Buffer *buf, Buffer *attr,
+ int target_x, int target_y, int target_depth,
+ int view_port_x, int view_port_y);
+
+
+/* sprite_5.c */
+void sprite_draw_3d_scaled_big(SeriesPtr series, int id,
+ Buffer *buf, Buffer *attr,
+ int target_x, int target_y,
+ int target_depth, int scale_factor,
+ int view_port_x, int view_port_y);
+
+/* sprite_6.c */
+void sprite_draw_3d_x16(SeriesPtr series, int id,
+ Buffer *buf, Buffer *attr,
+ int target_x, int target_y, int target_depth);
+
+/* sprite_7.c */
+void sprite_draw_3d_scaled_x16(SeriesPtr series, int id,
+ Buffer *buf, Buffer *attr,
+ int target_x, int target_y,
+ int target_depth, int scale_factor);
+
+
+/* sprite_8.c */
+void sprite_draw_3d_big_x16(SeriesPtr series, int id,
+ Buffer *buf, Buffer *attr,
+ int target_x, int target_y, int target_depth,
+ int view_port_x, int view_port_y);
+
+
+/* sprite_9.c */
+void sprite_draw_3d_scaled_big_x16(SeriesPtr series, int id,
+ Buffer *buf, Buffer *attr,
+ int target_x, int target_y,
+ int target_depth, int scale_factor,
+ int view_port_x, int view_port_y);
+
+
+/* sprite_a.c */
+void sprite_draw_x16(SeriesPtr series, int id, Buffer *buf,
+ int target_x, int target_y);
+
+
+/* sprite_b.c */
+void sprite_draw_interface(SeriesPtr series, int id,
+ Buffer *buf,
+ int target_x, int target_y);
+
+
+/* sprite_c.c */
+void sprite_draw_3d_scaled_to_attr
+(SeriesPtr series, int id,
+ Buffer *buf, Buffer *attr,
+ int target_x, int target_y, int target_depth,
+ int scale_factor, int view_port_x, int view_port_y);
+
+
+/* sprite_d.c */
+void sprite_draw_3d_scaled_mono
+(SeriesPtr series, int id,
+ Buffer *buf, Buffer *attr,
+ int target_x, int target_y, int target_depth,
+ int scale_factor, byte color);
+
+
+/* sprite_e.c */
+SeriesPtr sprite_series_load(char *filename, int load_flags);
+
+extern int sprite_error;
+
+
+/* sprite_f.c */
+void sprite_get_scaled_matte(SeriesPtr series, int id,
+ int target_x, int target_y,
+ int scale_factor, SpritePtr matte);
+
+
+/* sprite_g.c */
+word sprite_pack_line_rle(byte *target, Buffer *source,
+ byte *palette_map, byte transparent,
+ int x1, int x2, int y);
+
+word sprite_pack_line_irle(byte *target, Buffer *source,
+ byte *palette_map, byte transparent,
+ int x1, int x2, int y);
+
+void sprite_set_bounds(HagSpritePtr sprite, int x, int y,
+ int xs, int ys);
+
+void sprite_merge_background(Buffer *source, Buffer *background,
+ byte transparent);
+
+void sprite_delta_compute(HagSpritePtr sprite,
+ Buffer *source, Buffer *delta);
+
+void sprite_remove_non_delta(Buffer *source, Buffer *delta,
+ byte transparent);
+
+long sprite_pack_image(byte *target,
+ FileSpritePtr sprite,
+ Buffer *source,
+ byte *palette_map,
+ byte transparent);
+
+
+/* sprite_h.c */
+void sprite_color_translate(SeriesPtr series, ColorListPtr list);
+
+/* sprite_i.c */
+void sprite_single_color_translate(SeriesPtr series, int id);
+
+/* sprite_j.c */
+int sprite_data_load(SeriesPtr series, int id, byte *target);
+
+/* sprite_k.c */
+/* if called, wont remove the colors from the palette list. It is */
+/* used during kernel_abort_animation. */
+void dont_frag_the_palette(void);
+/* this will be called from the end of kernel_abort_animation to */
+/* make it so the colors will be freed from the palette. */
+void go_ahead_and_frag_the_palette(void);
+
+void sprite_free(SeriesPtr *series, int free_memory);
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/tile.h b/engines/mads/madsv2/core/tile.h
new file mode 100644
index 00000000000..57afcecb02e
--- /dev/null
+++ b/engines/mads/madsv2/core/tile.h
@@ -0,0 +1,143 @@
+/* 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 MADS_CORE_TILE_H
+#define MADS_CORE_TILE_H
+
+#include "mads/madsv2/core/general.h"
+#include "mads/madsv2/core/color.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+
+#define DEFAULT_TILE_X 20
+#define DEFAULT_TILE_Y 12
+
+#define TILE_MAX_PAGES 14 /* Max EMS pages for a picture */
+/* (14 is enough for 4 screens) */
+#define EMPTY_TILE -1
+#define REPEAT_TILE 0x8000
+
+#define TILE_PICTURE -1
+#define TILE_ATTRIBUTE 0
+
+#define TILE_MAP_SHADOW 0x0020 /* Load shadow for tile */
+
+#define tile_ems_page 0
+#define tile_ems_address ems_page[tile_ems_page]
+
+typedef struct {
+ int num_tiles; /* Number of tiles in resource */
+ int tile_x; /* Tile X size */
+ int tile_y; /* Tile Y size */
+ int compression; /* Compression in resource file */
+ int ems_handle; /* EMS handle of resource */
+ int num_pages; /* Number of pages needed */
+ int tiles_per_page; /* Tiles stored per page */
+ long chunk_size; /* Tile size in bytes (x*y) */
+ int color_handle; /* Color handle for loaded resource */
+} TileResource;
+
+typedef struct {
+ long file_offset;
+} Tile;
+
+typedef struct {
+ int tile_type; /* Type of tile */
+ int one_to_one; /* One-to-one ratio with scr_orig */
+ int num_x_tiles; /* Number of X tiles in map */
+ int num_y_tiles; /* Number of Y tiles in map */
+ int tile_x_size; /* Tile X size */
+ int tile_y_size; /* Tile Y size */
+ int viewport_x; /* Viewport X size */
+ int viewport_y; /* Viewport Y size */
+ int orig_x_size; /* Orig buffer X pixel size */
+ int orig_y_size; /* Orig buffer Y pixel size */
+ int orig_x_tiles; /* Orig buffer X tile size */
+ int orig_y_tiles; /* Orig buffer Y tile size */
+ int total_x_size; /* Total picture X size (pixels) */
+ int total_y_size; /* Total picture Y size (pixels) */
+
+ int pan_x; /* Panned to pixel X value */
+ int pan_y; /* Panned to pixel Y value */
+ int pan_tile_x; /* Panned to tile X value */
+ int pan_tile_y; /* Panned to tile Y value */
+ int pan_base_x; /* Base orig screen pixel X value */
+ int pan_base_y; /* Base orig screen pixel Y value */
+ int pan_offset_x; /* Panning orig offset to work X */
+ int pan_offset_y; /* Panning orig offset to work Y */
+
+ TileResource *resource; /* Resource pointer */
+ Buffer *buffer; /* Buffer pointer */
+
+ int *map; /* Picture tile map pointer */
+} TileMapHeader;
+
+extern ShadowList tile_shadow;
+
+
+/* tile_1.c */
+int tile_load(char *base,
+ int tile_type,
+ TileResource *tile_resource,
+ TileMapHeader *map,
+ Buffer *picture,
+ ColorListPtr color_list,
+ CycleListPtr cycle_list,
+ int ems_handle,
+ int load_flags);
+
+extern int tile_load_error;
+
+/* tile_2.c */
+int tile_buffer(Buffer *target,
+ TileResource *tile_resource,
+ TileMapHeader *map,
+ int tile_x,
+ int tile_y);
+
+/* tile_3.c */
+extern int tile_ems_available;
+extern int tile_picture_handle;
+extern int tile_attribute_handle;
+
+int tile_setup(void);
+
+/* tile_4.c */
+void tile_map_free(TileMapHeader *map);
+
+/* tile_5.c */
+void tile_pan(TileMapHeader *tile_map,
+ int x,
+ int y);
+
+/* tile_6.c */
+int tile_fake_map(int tile_type,
+ TileMapHeader *tile_map,
+ Buffer *buffer,
+ int x,
+ int y);
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/timer.h b/engines/mads/madsv2/core/timer.h
new file mode 100644
index 00000000000..0d2d51435c5
--- /dev/null
+++ b/engines/mads/madsv2/core/timer.h
@@ -0,0 +1,75 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef MADS_CORE_TIMER_H
+#define MADS_CORE_TIMER_H
+
+#include "common/scummsys.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+extern long *timer_address; /* "Default" timer count address */
+extern word timer_rate; /* Current timer ticks/sec */
+extern int timer_service_active; /* Flag if timer service active */
+
+extern word timer_sound_on; /* Flag if sound service active */
+extern word timer_noise_on; /* Flag if sound in noise mode */
+
+extern word timer_low_priority; /* Flag if low priority routine active */
+extern word timer_low_semaphore; /* Low priority activity semaphore */
+extern word timer_low_stacking; /* Low priority stacking count */
+extern word timer_low_deferred; /* Low priority deferred DOS flag */
+extern void *timer_low_routine; /* Low priority function pointer */
+
+extern long timer_600_low; /* 600/s timer count */
+extern long timer_60_low; /* 60/s timer_count */
+extern long timer_dos_low;
+
+
+/* extern byte *interrupt_stack_pointer; */
+/* extern word interrupt_stack_size; */
+
+/* timer_1.c */
+long timer_read(void);
+long timer_read_dos(void);
+long timer_read_600(void);
+long timer_read_60(void);
+
+
+/* timer_2.c */
+void timer_set_rate(word count_down);
+
+
+/* timer_3.asm */
+void timer_install(void);
+void timer_remove(void);
+void timer_set_sound_flag(int sound_flag);
+void timer_activate_low_priority(void (*(routine))());
+byte *timer_get_interrupt_stack(void);
+
+int timer_set_copy_protect(int protect);
+int timer_get_copy_protect(void);
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/video.h b/engines/mads/madsv2/core/video.h
new file mode 100644
index 00000000000..02ced502130
--- /dev/null
+++ b/engines/mads/madsv2/core/video.h
@@ -0,0 +1,60 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef MADS_CORE_VIDEO_H
+#define MADS_CORE_VIDEO_H
+
+#include "mads/madsv2/core/general.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+int video_mode;
+
+/* video.asm */
+void video_init(int mode, int set_mode);
+
+void video_update(Buffer *from, int from_x, int from_y,
+ int unto_x, int unto_y,
+ int size_x, int size_y);
+
+void video_flush_ega(int start_y, int size_y);
+
+
+
+/* Mode-specific versions */
+
+void video_update_vga(Buffer *from, int from_x, int from_y,
+ int unto_x, int unto_y,
+ int size_x, int size_y);
+
+void video_update_ega(Buffer *from, int from_x, int from_y,
+ int unto_x, int unto_y,
+ int size_x, int size_y);
+
+void video_update_tandy(Buffer *from, int from_x, int from_y,
+ int unto_x, int unto_y,
+ int size_x, int size_y);
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/vocab.h b/engines/mads/madsv2/core/vocab.h
new file mode 100644
index 00000000000..f8ee5103890
--- /dev/null
+++ b/engines/mads/madsv2/core/vocab.h
@@ -0,0 +1,108 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef MADS_CORE_VOCAB_H
+#define MADS_CORE_VOCAB_H
+
+#include "mads/madsv2/core/general.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+#define vocab_version "1.01"
+#define vocab_date "13-Jun-91"
+
+#define VOCAB_MAX_ACTIVE 200
+
+
+#define VC_MAXWORDS 1200 /* Maximum words in vocabulary */
+
+#define VC_MAXWORDLEN 20 /* Maximum word length */
+
+#define VC_FUDGEFACTOR 50 /* Number of words slack space */
+
+#define VC_MAINFILENAME "*VOCAB.DB"
+#define VC_HARDFILENAME "*VOCABH.DB"
+
+#define VC_ERR_OPENMAINFILE -1 /* Failed to open main file */
+#define VC_ERR_OPENHARDFILE -2 /* Failed to open hard file */
+#define VC_ERR_READMAINFILE -3 /* Read error on main file */
+#define VC_ERR_READHARDFILE -4 /* Read error on hard file */
+#define VC_ERR_WORDTOOLONG -5 /* Max. word length exceeded */
+#define VC_ERR_SYNTAXHARDFILE -6 /* Improper format hard file */
+#define VC_ERR_NOMOREMEMORY -7 /* Failed to allocate memory */
+#define VC_ERR_MEMORYOVERFLOW -8 /* No memory to add a word */
+#define VC_ERR_WORDALREADYEXISTS -9 /* Word alread in vocab list */
+#define VC_ERR_WRITEMAINFILE -10 /* Failed to write main file */
+#define VC_ERR_RENAMEOUTFILE -11 /* Failed to rename out file */
+#define VC_ERR_TOOMANYWORDS -12 /* VC_MAXWORDS exceeded */
+#define VC_ERR_NOSUCHWORD -13 /* Word not in list */
+
+
+int vocab_allocation;
+char *vocab;
+
+/* vocab_1.c */
+int vocab_destroy(void);
+
+/* vocab_2.c */
+int vocab_load(int allocation_flag);
+int vocab_get_code(char *inp);
+char *vocab_get_word(char *out, int inp);
+
+/* vocab_3.c */
+int vocab_write_file(char *last_word);
+int vocab_add_word(char *inp);
+
+/* vocab_4.c */
+void vocab_report_error(int number);
+
+/* vocab_5.c */
+char * vocab_select_word(char *out, char *prompt,
+ char *default_word);
+
+/* vocab_6.c */
+void vocab_maint(void);
+
+/* vocab_7.c */
+int vocab_build(void);
+
+/* vocab_8.c */
+void vocab_unload_active(void);
+void vocab_init_active(void);
+int vocab_active_id(word id);
+int vocab_make_active(word id);
+int vocab_load_active(void);
+
+extern int vocab_emergency;
+
+extern char *vocab_text;
+extern word vocab_active;
+extern word vocab_list_id[VOCAB_MAX_ACTIVE];
+extern word vocab_list_pointer[VOCAB_MAX_ACTIVE];
+
+/* vocab_9.c */
+char *vocab_string(int vocab_id);
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/xms.h b/engines/mads/madsv2/core/xms.h
new file mode 100644
index 00000000000..c2b9e29f892
--- /dev/null
+++ b/engines/mads/madsv2/core/xms.h
@@ -0,0 +1,71 @@
+/* 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 MADS_CORE_XMS_H
+#define MADS_CORE_XMS_H
+
+#include "common/scummsys.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+#define XMS_MAX_UMB 16 /* Max UMB blocks to allocate */
+
+#define XMS byte * /* XMS fake pointer type */
+
+extern int xms_exists; /* Flag if we've got some XMS memory */
+extern int xms_disabled; /* Flag to disable XMS altogether */
+extern word xms_version; /* XMS driver version # */
+extern dword xms_controller; /* XMS controller address */
+extern word xms_chain_seg; /* First UMB MCB segment for us */
+
+extern word xms_umb_list[XMS_MAX_UMB];
+extern word xms_umb_mark;
+
+/* xms_1.c */
+int xms_detect(void);
+
+/* xms_2.c */
+long xms_umb_get_avail(void);
+
+/* xms_3.c */
+void *xms_umb_get(long mem_to_get);
+void xms_umb_free(void *mem_to_free);
+
+/* xms_4.c */
+void xms_umb_purge(void);
+
+/* xms_5.c */
+long xms_get_avail(void);
+
+/* xms_6.c */
+int xms_get(long size_in_bytes);
+void xms_free(int xms_handle);
+
+/* xms_7.c */
+int xms_copy(long copy_size,
+ word source_handle, void *source,
+ word dest_handle, void *dest);
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/phantom/mads/quotes.h b/engines/mads/madsv2/phantom/mads/quotes.h
new file mode 100644
index 00000000000..5c52829dfab
--- /dev/null
+++ b/engines/mads/madsv2/phantom/mads/quotes.h
@@ -0,0 +1,39 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef MADS_PHANTOM_MADS_QUOTES_H
+#define MADS_PHANTOM_MADS_QUOTES_H
+
+#include "common/scummsys.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+
+enum {
+ quote_mainmenu_phantom_1 = 66
+};
+
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/phantom/mads/sounds.h b/engines/mads/madsv2/phantom/mads/sounds.h
new file mode 100644
index 00000000000..fa061fa6775
--- /dev/null
+++ b/engines/mads/madsv2/phantom/mads/sounds.h
@@ -0,0 +1,40 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef MADS_PHANTOM_MADS_SOUNDS_H
+#define MADS_PHANTOM_MADS_SOUNDS_H
+
+#include "common/scummsys.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+
+enum {
+ N_AllFade = 1,
+ N_PlayerFalls = 67
+};
+
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/phantom/mads/speeches.h b/engines/mads/madsv2/phantom/mads/speeches.h
new file mode 100644
index 00000000000..ff88f99a9d1
--- /dev/null
+++ b/engines/mads/madsv2/phantom/mads/speeches.h
@@ -0,0 +1,39 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef MADS_PHANTOM_MADS_SPEECHES_H
+#define MADS_PHANTOM_MADS_SPEECHES_H
+
+#include "common/scummsys.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+
+enum {
+ speech_phantom_cackle = 9
+};
+
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/phantom/main_menu.cpp b/engines/mads/madsv2/phantom/main_menu.cpp
index a9ce39cf807..135cfdfa341 100644
--- a/engines/mads/madsv2/phantom/main_menu.cpp
+++ b/engines/mads/madsv2/phantom/main_menu.cpp
@@ -19,9 +19,668 @@
*
*/
+#include "mads/madsv2/core/general.h"
+#include "mads/madsv2/core/config.h"
+#include "mads/madsv2/core/font.h"
+#include "mads/madsv2/core/speech.h"
+#include "mads/madsv2/core/matte.h"
+#include "mads/madsv2/core/sprite.h"
+#include "mads/madsv2/core/error.h"
+#include "mads/madsv2/core/room.h"
+#include "mads/madsv2/core/fileio.h"
+#include "mads/madsv2/core/env.h"
+#include "mads/madsv2/core/buffer.h"
+#include "mads/madsv2/core/mem.h"
+#include "mads/madsv2/core/pal.h"
+#include "mads/madsv2/core/timer.h"
+#include "mads/madsv2/core/mcga.h"
+#include "mads/madsv2/core/cycle.h"
+#include "mads/madsv2/core/mouse.h"
+#include "mads/madsv2/core/screen.h"
+#include "mads/madsv2/core/video.h"
+#include "mads/madsv2/core/lib.h"
+#include "mads/madsv2/core/keys.h"
+#include "mads/madsv2/core/sound.h"
+#include "mads/madsv2/core/btype.h"
+#include "mads/madsv2/core/hspot.h"
+#include "mads/madsv2/core/magic.h"
+#include "mads/madsv2/core/ems.h"
+#include "mads/madsv2/core/xms.h"
+#include "mads/madsv2/core/imath.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/pack.h"
+#include "mads/madsv2/core/quote.h"
+#include "mads/madsv2/phantom/mads/sounds.h"
+#include "mads/madsv2/phantom/mads/quotes.h"
+#include "mads/madsv2/phantom/mads/speeches.h"
#include "mads/madsv2/phantom/main_menu.h"
namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+#define menu_version "1.08"
+#define menu_date "26-May-93"
+#define WIN 16
+#define WIN2 32
+#define WIN3 48
+
+#define FIRST_TIME_FILE "PHANTOM.RTN"
+#define CONFIG_FILE_NAME "CONFIG.PHA"
+
+#define EYE_QUOTES 16
+#define EYE_HOTSPOT 32
+#define EYE_MESSAGES 2
+
+#define MESSAGE_COLOR 1284
+
+
+ConfigFile config_file;
+
+int mads_mode = false;
+
+Buffer scr_live = { video_y, video_x, mcga_video };
+
+FontPtr font = NULL;
+int font_auto_spacing = -1;
+
+int new_background = false;
+int room_number = 0;
+
+int win_status = 0;
+
+int force_opening = false;
+
+int dont_return = false;
+
+int white_bars = true;
+byte white_border = 2;
+
+char command_line[COMMAND_LINE_MAX][80];
+char *command_list[COMMAND_LINE_MAX+1];
+int command_line_size = 0;
+
+int use_mouse_cursor_fix = false;
+
+int going;
+int menu_mode;
+int must_perform_matte;
+
+long frame_clock;
+long now_clock;
+long menu_clock;
+
+int menu_state;
+int menu_appear_state;
+
+int highest_y = -1;
+int next_x = -1;
+
+char sound_file[80] = "*#SOUND.PH9";
+char sound_letter = 'N';
+
+int sound_board_address = 0x220; /* Default sound board address */
+int sound_board_type = sound_board_roland; /* Default sound board type */
+
+int swapping = false; /* Flag when swapping in new background */
+int swap_line; /* Currently active swap line */
+long swap_clock; /* Time for next swap */
+
+int current_item;
+int current_eye = false;
+int eye_latch = false;
+int selected_item = -1;
+
+#define LEFT_EYE 0
+#define RIGHT_EYE 1
+
+char *quotes = NULL;
+int eye_message[2];
+int eye_pokes = 0;
+int recent_eye = 0;
+int rebel_base = 0;
+int poke_count_message = -1;
+int poke_count = 0;
+int poke_counting = false;
+
+char poke_count_buf[2][20];
+
+char bonus_buf[80] = "";
+
+Palette special_pal; /* Palette for fadeout */
+
+
+MenuItem menu_item[NUM_MENU_ITEMS+1]; /* Menu item array */
+
+char global_speech_resource[16] = "*PHAN009.DSR";
+int global_speech_ready = -1;
+
+void global_speech(int id) {
+ if (speech_system_active && speech_on) {
+ speech_ems_play(global_speech_resource, id);
+ }
+}
+
+void global_speech_load(int id) {
+ SpeechDirPtr chunk;
+
+ if (speech_system_active && speech_on) {
+ speech_all_off();
+ chunk = speech_load(global_speech_resource, id, false);
+ if (chunk != NULL) {
+ global_speech_ready = id;
+ } else {
+ global_speech_ready = -1;
+ }
+ } else {
+ global_speech_ready = -1;
+ }
+}
+
+void global_speech_go(int id) {
+ if (speech_system_active && speech_on) {
+ if (global_speech_ready == id) {
+ speech_all_off();
+ speech_sample_rate(speech_main_buffer.sample_rate);
+ speech_ems_go(speech_ems_handle, speech_main_buffer.decompress_size);
+ } else {
+ global_speech(id);
+ }
+ }
+}
+
+void start_series() {
+ int error_flag = true;
+ int count;
+ int handle;
+ char temp_buf[80];
+
+ for (count = 0; count < NUM_MENU_ITEMS; count++) {
+ handle = -1;
+ Common::strcpy_s(temp_buf, "*MAIN0.SS");
+ temp_buf[5] = (char)('0' + count);
+
+ handle = matte_load_series(temp_buf, 0, 0);
+ if (handle < 0) goto done;
+
+ menu_item[count].handle = handle;
+ menu_item[count].active = true;
+ menu_item[count].status = 0;
+ }
+
+ if (menu_item[6].active) {
+ /* menu_item[6].active = config_file.quotes_enabled; */
+ menu_item[6].active = false;
+ }
+
+ error_flag = false;
+
+done:
+ if (error_flag) {
+ Common::strcpy_s(error_string, temp_buf);
+ error_report(ERROR_SERIES_LOAD_FAILED, WARNING, MODULE_UNKNOWN, count, handle);
+ }
+}
+
+void stop_series(void) {
+ int count;
+
+ for (count = NUM_MENU_ITEMS - 1; count >= 0; count--) {
+ matte_deallocate_series(menu_item[count].handle, true);
+ }
+}
+
+void start_hotspots(void) {
+ int count;
+ int x1, x2, y1, y2;
+ int xs, ys;
+ SeriesPtr series;
+
+ numspots = 0;
+
+ for (count = 0; count < NUM_MENU_ITEMS; count++) {
+ series = series_list[menu_item[count].handle];
+ xs = series->index[0].xs;
+ ys = series->index[0].ys;
+ x1 = series->index[0].x - (xs >> 1);
+ y1 = series->index[0].y - (ys - 1);
+ x2 = x1 + xs - 1;
+ y2 = y1 + ys - 1;
+ hspot_add(x1, y1, x2, y2, 1, count, mcga_mode);
+ }
+
+ hspot_add(135, 77, 148, 83, 2, EYE_HOTSPOT, mcga_mode);
+ hspot_add(156, 77, 170, 83, 2, EYE_HOTSPOT + 1, mcga_mode);
+}
+
+void process_menu(void) {
+ int myspot;
+
+ myspot = hspot_which(mouse_x, mouse_y - viewing_at_y, mcga_mode);
+
+ current_eye = false;
+
+ if ((myspot > 0) && mouse_any_stroke && (menu_mode == MENU_ACCEPTING_COMMANDS)) {
+ current_item = spot[myspot].num;
+ if (current_item >= EYE_HOTSPOT) {
+ current_item = -1;
+ current_eye = true;
+ }
+ } else {
+ current_item = -1;
+ }
+
+ if (mouse_stop_stroke && (current_item >= 0) && (menu_mode == MENU_ACCEPTING_COMMANDS)) {
+ selected_item = current_item;
+ menu_mode = MENU_DISAPPEARING;
+ menu_state = 1;
+ sound_queue(N_AllFade);
+ }
+}
+
+void process_sprites(void) {
+ int count;
+ int sprite;
+ int series;
+ int look, match;
+ Image image;
+
+ for (count = 0; count < (int)image_marker; count++) {
+ if ((image_list[count].segment_id < KERNEL_SEGMENT_ANIMATION) ||
+ (image_list[count].segment_id > KERNEL_SEGMENT_ANIMATION_HIGH)) {
+ if (image_list[count].flags >= IMAGE_STATIC) {
+ image_list[count].flags = IMAGE_ERASE;
+ }
+ }
+ }
+
+ if (menu_mode == MENU_APPEARING) goto done;
+
+ for (count = 0; count < NUM_MENU_ITEMS; count++) {
+ if (menu_item[count].active) {
+ image.flags = IMAGE_UPDATE;
+ image.segment_id = (byte)(count + 1);
+
+ series = count;
+ if (menu_mode == MENU_ACCEPTING_COMMANDS) {
+ if (count != current_item) {
+ sprite = 1;
+ } else {
+ sprite = 2;
+ }
+ } else {
+ sprite = 1;
+ /*
+ if (count != selected_item) {
+ sprite = 1;
+ } else {
+ sprite = 2;
+ }
+ */
+ }
+
+ image.series_id = (byte)menu_item[series].handle;
+ image.sprite_id = sprite;
+
+ image.x = series_list[series]->index[sprite - 1].x;
+ image.y = series_list[series]->index[sprite - 1].y;
+
+ image.depth = 0;
+ image.scale = 100;
+
+ match = !(sprite <= MENU_HIGH_SPRITE);
+
+ for (look = 0; !match && (look < (int)image_marker); look++) {
+ if (image_list[look].segment_id == image.segment_id) {
+ if (memcmp(&image_list[look].series_id,
+ &image.series_id, 9) == 0) {
+ image_list[look].flags = IMAGE_STATIC;
+ match = true;
+ }
+ }
+ }
+
+ if (!match) {
+ image_list[image_marker] = image;
+ image_marker++;
+ }
+ }
+ }
+
+done:
+ ;
+}
+
+void process_messages(int anim) {
+ int total;
+ int count;
+ int id, x, y;
+ int flags;
+ int special_check;
+ int buf;
+
+ if (!current_eye) goto done;
+ if (eye_latch) goto done;
+
+ total = 0;
+
+ for (count = 0; count < KERNEL_MAX_MESSAGES; count++) {
+ if (kernel_message[count].flags) total++;
+ }
+
+ if (total > 6) goto done;
+
+ eye_pokes++;
+
+ if (eye_pokes < 6) {
+ id = eye_pokes - 1;
+ } else {
+ id = imath_random(0, EYE_QUOTES - 1);
+ }
+
+ if (poke_counting) {
+ if (poke_count_message >= 0) {
+ kernel_message_delete(poke_count_message);
+ }
+ poke_count++;
+ buf = (poke_count & 1);
+ Common::sprintf_s(poke_count_buf[buf], "%d", poke_count);
+ poke_count_message = kernel_message_add(poke_count_buf[buf], 160, 40,
+ MESSAGE_COLOR, 180, 0, KERNEL_MESSAGE_CENTER);
+ }
+
+ id += quote_mainmenu_phantom_1;
+
+ recent_eye = 1 - recent_eye;
+
+ if (((total > 1) && !poke_counting) || (total > 2)) {
+ if (!poke_counting || (eye_message[recent_eye] != poke_count_message)) {
+ kernel_message_delete(eye_message[recent_eye]);
+ }
+ }
+
+ if (recent_eye == LEFT_EYE) {
+ x = 120;
+ flags = KERNEL_MESSAGE_RIGHT;
+ } else {
+ x = 184;
+ flags = 0;
+ }
+
+ special_check = eye_pokes % 4;
+ if ((special_check == 1) || (special_check == 2)) {
+ y = 90;
+ } else {
+ y = 66;
+ }
+
+ eye_message[recent_eye] = kernel_message_add(quote_string(quotes, id), x, y,
+ MESSAGE_COLOR, 180, 0, flags);
+
+done:
+ eye_latch = current_eye;
+
+ if (current_eye) {
+ kernel_reset_animation(anim, 140);
+ kernel_anim[anim].next_clock = kernel.clock;
+ }
+}
+
+void menu_control(void) {
+ int fx;
+ int mykey;
+ int last_frame = -1;
+ int now_frame;
+ int reset_frame;
+ int random;
+ int anim;
+ int initial_reset = false;
+
+ menu_mode = MENU_APPEARING;
+ menu_state = MENU_HIGH_SPRITE;
+ menu_appear_state = 0;
+ menu_clock = 999999999;
+
+ going = true;
+ must_perform_matte = false;
+
+ frame_clock = 0;
+
+ start_series();
+ start_hotspots();
+
+ anim = kernel_run_animation("*RM922A.AA", 0);
+
+ mouse_init_cycle();
+
+ while (going) {
+ if (keys_any()) {
+ mykey = keys_get();
+ switch (toupper(mykey)) {
+ case esc_key:
+ selected_item = 4;
+ going = false;
+ break;
+
+ case alt_x_key:
+ case alt_q_key:
+ case ctrl_x_key:
+ case ctrl_q_key:
+ going = false;
+ break;
+
+ case 'S':
+ menu_mode = MENU_APPEARING;
+ menu_state = MENU_HIGH_SPRITE;
+ menu_appear_state = 0;
+ break;
+
+ default:
+ if (menu_mode == MENU_APPEARING) {
+ menu_mode = MENU_ACCEPTING_COMMANDS;
+ kernel_reset_animation(anim, 136);
+ kernel_anim[anim].next_clock = kernel.clock;
+ global_speech_go(speech_phantom_cackle);
+ }
+ break;
+ }
+ }
+
+ mouse_begin_cycle(false);
+
+ if (mouse_stroke_going) {
+ if (menu_mode == MENU_APPEARING) {
+ menu_mode = MENU_ACCEPTING_COMMANDS;
+ global_speech_go(speech_phantom_cackle);
+ kernel_reset_animation(anim, 136);
+ kernel_anim[anim].next_clock = kernel.clock;
+ mouse_init_cycle();
+ }
+ }
+
+ if (menu_mode != MENU_APPEARING) {
+ mouse_show();
+ }
+
+ now_clock = timer_read();
+ kernel.clock = now_clock;
+
+ if (now_clock >= menu_clock) {
+ switch (menu_mode) {
+ case MENU_APPEARING:
+ /*
+ menu_state -= 1;
+ if (menu_state <= 1) {
+ menu_state = MENU_HIGH_SPRITE;
+ do {
+ menu_appear_state += 1;
+ } while ((menu_appear_state < NUM_MENU_ITEMS) &&
+ (!menu_item[menu_appear_state].active));
+ if (menu_appear_state >= NUM_MENU_ITEMS) {
+ menu_mode = MENU_ACCEPTING_COMMANDS;
+ }
+ }
+ */
+ break;
+
+ case MENU_ACCEPTING_COMMANDS:
+ break;
+
+ case MENU_DISAPPEARING:
+ going = false;
+ /*
+ menu_state += 1;
+ if (menu_state > MENU_HIGH_SPRITE + 1) {
+ going = false;
+ }
+ */
+ break;
+ }
+ menu_clock = now_clock + MENU_FRAME_RATE;
+ }
+
+ process_menu();
+ kernel_message_update_all();
+ kernel_process_all_animations();
+
+ process_messages(anim);
+
+ reset_frame = -1;
+ now_frame = kernel_anim[anim].frame;
+ if (now_frame != last_frame) {
+ last_frame = now_frame;
+
+ if (now_frame == 64) {
+ global_speech_go(speech_phantom_cackle);
+ }
+
+ if (now_frame < 136) {
+ if (menu_mode != MENU_APPEARING) {
+ if (!initial_reset) {
+ reset_frame = 136;
+ initial_reset = true;
+ }
+ }
+ }
+
+ if (now_frame >= 161) {
+ if (menu_mode == MENU_APPEARING) {
+ menu_mode = MENU_ACCEPTING_COMMANDS;
+ global_speech_go(speech_phantom_cackle);
+ }
+
+ random = imath_random(1, 1000);
+
+ if (random <= 250) {
+ reset_frame = 136;
+ } else if (random <= 500) {
+ reset_frame = 150;
+ } else {
+ reset_frame = 159;
+ }
+
+ }
+
+ if (reset_frame >= 0) {
+ kernel_reset_animation(anim, reset_frame);
+ last_frame = reset_frame;
+ }
+ }
+
+ if (now_clock >= frame_clock) {
+
+ process_sprites();
+
+ fx = new_background ? 1 : 0;
+ matte_frame(fx, false);
+
+ if (fx) {
+ now_clock = timer_read();
+ menu_clock = now_clock + MENU_FRAME_RATE;
+ }
+
+ must_perform_matte = false;
+ new_background = false;
+
+ frame_clock = now_clock + FRAME_RATE;
+ }
+
+ mouse_end_cycle(false, going);
+ }
+
+ kernel_abort_animation(anim);
+
+ stop_series();
+}
+
+void add_parameter(char *parameter) {
+ if (command_line_size < COMMAND_LINE_MAX) {
+ Common::strcpy_s(command_line[command_line_size], parameter);
+ command_list[command_line_size] = command_line[command_line_size];
+ command_line_size++;
+ }
+}
+
+void add_sound_parameter(void) {
+ char temp_buf[80];
+ char work_buf[80];
+
+ Common::strcpy_s(temp_buf, "-c:n");
+ temp_buf[3] = sound_letter;
+
+ Common::strcat_s(temp_buf, ",");
+ Common::sprintf_s(work_buf, "%x", config_file.sound_card_address);
+ Common::strcat_s(temp_buf, work_buf);
+ Common::strcat_s(temp_buf, ",");
+ Common::sprintf_s(work_buf, "%x", config_file.sound_card_type);
+ Common::strcat_s(temp_buf, work_buf);
+
+ add_parameter(temp_buf);
+}
+
+void add_speech_parameter(void) {
+ char temp_buf[80];
+ char work_buf[80];
+
+ if (config_file.speech_card_type > 0) {
+ Common::strcpy_s(temp_buf, "-u:");
+
+ Common::sprintf_s(work_buf, "%x", config_file.speech_card_address);
+ Common::strcat_s(temp_buf, work_buf);
+ Common::strcat_s(temp_buf, ",");
+ Common::sprintf_s(work_buf, "%x", config_file.speech_card_type);
+ Common::strcat_s(temp_buf, work_buf);
+ Common::strcat_s(temp_buf, ",");
+ env_catint(temp_buf, config_file.speech_card_irq, 2);
+ Common::strcat_s(temp_buf, ",");
+ env_catint(temp_buf, config_file.speech_card_drq, 2);
+
+ add_parameter(temp_buf);
+ }
+}
+
+void add_chain_parameter(void) {
+ char temp_buf[80];
+ int added_dash = false;
+
+ Common::strcpy_s(temp_buf, "-a:\"mainmenu");
+
+ if (env_search_mode == ENV_SEARCH_CONCAT_FILES) {
+ Common::strcat_s(temp_buf, " -p");
+ added_dash = true;
+ }
+
+ if (use_mouse_cursor_fix) {
+ if (!added_dash) {
+ Common::strcat_s(temp_buf, " -");
+ added_dash = true;
+ }
+ Common::strcat_s(temp_buf, "u");
+ }
+}
+
+} // namespace Phantom
+} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/main_menu.h b/engines/mads/madsv2/phantom/main_menu.h
index 3262add2dfa..e27d31634d2 100644
--- a/engines/mads/madsv2/phantom/main_menu.h
+++ b/engines/mads/madsv2/phantom/main_menu.h
@@ -25,8 +25,31 @@
#include "common/str.h"
namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+#define COMMAND_LINE_MAX 10
+#define FRAME_RATE 1
+#define MENU_FRAME_RATE 3
+
+#define NUM_MENU_ITEMS 7
+
+#define MENU_APPEARING 0
+#define MENU_ACCEPTING_COMMANDS 1
+#define MENU_DISAPPEARING 2
+
+#define MENU_HIGH_SPRITE 15
+
+
+typedef struct {
+ int handle; /* Sprite series handle */
+ int active; /* Menu item is active */
+ int status; /* Current status */
+} MenuItem;
+
+} // namespace Phantom
+} // namespace MADSV2
} // namespace MADS
#endif
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index 6173ef037d5..f91aa8805a9 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -59,6 +59,7 @@ MODULE_OBJS += \
forest/game_forest.o \
forest/forest_scenes.o \
forest/globals_forest.o \
+ madsv2/core/speech.o \
madsv2/phantom/main_menu.o
endif
Commit: fe4d1049b4a1b38f50c30019e2ce029630cffe87
https://github.com/scummvm/scummvm/commit/fe4d1049b4a1b38f50c30019e2ce029630cffe87
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:19:03+10:00
Commit Message:
MADS: PHANTOM: Engine class, start of main menu startup code
Changed paths:
A engines/mads/madsv2/engine.cpp
A engines/mads/madsv2/engine.h
A engines/mads/madsv2/phantom/mads/mads.cpp
A engines/mads/madsv2/phantom/main.cpp
A engines/mads/madsv2/phantom/main.h
engines/mads/madsv2/core/matte.h
engines/mads/madsv2/core/vocab.h
engines/mads/madsv2/phantom/mads/quotes.h
engines/mads/madsv2/phantom/main_menu.cpp
engines/mads/madsv2/phantom/main_menu.h
engines/mads/metaengine.cpp
engines/mads/module.mk
diff --git a/engines/mads/madsv2/core/matte.h b/engines/mads/madsv2/core/matte.h
index ce77aa33bcb..261649416fb 100644
--- a/engines/mads/madsv2/core/matte.h
+++ b/engines/mads/madsv2/core/matte.h
@@ -79,8 +79,8 @@ extern byte series_user[SERIES_LIST_SIZE]; /* Master sprite user list*/
extern Image image_list[IMAGE_LIST_SIZE]; /* Master image list */
extern Matte matte_list[MATTE_LIST_SIZE]; /* Master matte list */
-byte depth_list_id[MATTE_LIST_SIZE]; /* Depth list for sorting */
-word depth_list[MATTE_LIST_SIZE];
+extern byte depth_list_id[MATTE_LIST_SIZE]; /* Depth list for sorting */
+extern word depth_list[MATTE_LIST_SIZE];
extern Message message_list[MESSAGE_LIST_SIZE];
diff --git a/engines/mads/madsv2/core/vocab.h b/engines/mads/madsv2/core/vocab.h
index f8ee5103890..2b04338ca4c 100644
--- a/engines/mads/madsv2/core/vocab.h
+++ b/engines/mads/madsv2/core/vocab.h
@@ -57,8 +57,8 @@ namespace MADSV2 {
#define VC_ERR_NOSUCHWORD -13 /* Word not in list */
-int vocab_allocation;
-char *vocab;
+extern int vocab_allocation;
+extern char *vocab;
/* vocab_1.c */
int vocab_destroy(void);
diff --git a/engines/mads/madsv2/engine.cpp b/engines/mads/madsv2/engine.cpp
new file mode 100644
index 00000000000..c3362cdca6e
--- /dev/null
+++ b/engines/mads/madsv2/engine.cpp
@@ -0,0 +1,41 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "mads/madsv2/engine.h"
+#include "mads/madsv2/phantom/main.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+MADSV2Engine *g_engine;
+
+MADSV2Engine::MADSV2Engine(OSystem *syst, const MADSGameDescription *gameDesc) :
+ Engine(syst), _gameDescription(gameDesc) {
+}
+
+Common::Error MADSV2Engine::run() {
+ Phantom::phantom_main();
+
+ return Common::kNoError;
+}
+
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/engine.h b/engines/mads/madsv2/engine.h
new file mode 100644
index 00000000000..2499b2e70de
--- /dev/null
+++ b/engines/mads/madsv2/engine.h
@@ -0,0 +1,48 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef MADSV2_ENGINE_H
+#define MADSV2_ENGINE_H
+
+#include "engines/engine.h"
+#include "mads/detection.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+class MADSV2Engine : public Engine {
+private:
+ const MADSGameDescription *_gameDescription;
+
+public:
+ MADSV2Engine(OSystem *syst, const MADSGameDescription *gameDesc);
+ ~MADSV2Engine() override {
+ }
+
+ Common::Error run() override;
+};
+
+extern MADSV2Engine *g_engine;
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/phantom/mads/mads.cpp b/engines/mads/madsv2/phantom/mads/mads.cpp
new file mode 100644
index 00000000000..ef477ef7b98
--- /dev/null
+++ b/engines/mads/madsv2/phantom/mads/mads.cpp
@@ -0,0 +1,24 @@
+/* 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 "mads/madsv2/phantom/mads/quotes.h"
+#include "mads/madsv2/phantom/mads/sounds.h"
+#include "mads/madsv2/phantom/mads/speeches.h"
diff --git a/engines/mads/madsv2/phantom/mads/quotes.h b/engines/mads/madsv2/phantom/mads/quotes.h
index 5c52829dfab..81554c951a1 100644
--- a/engines/mads/madsv2/phantom/mads/quotes.h
+++ b/engines/mads/madsv2/phantom/mads/quotes.h
@@ -30,6 +30,62 @@ namespace Phantom {
enum {
quote_mainmenu_phantom_1 = 66
+
+#if 0
+ quote_menu_done,
+ quote_menu_cancel,
+ quote_menu_save,
+ quote_menu_restore,
+ quote_menu_clear,
+ quote_menu_yes,
+ quote_menu_no,
+ quote_menu_ok,
+ quote_menu_empty,
+ quote_menu_unnamed,
+ quote_main_title,
+ quote_main_item1,
+ quote_main_item2,
+ quote_main_item3,
+ quote_main_item4,
+ quote_main_item5,
+ quote_main_item6,
+ quote_options_title,
+ quote_options_item1,
+ quote_options_item2,
+ quote_options_item3,
+ quote_options_item4,
+ quote_options_item5,
+ quote_options_item6,
+ quote_options_item1a,
+ quote_options_item1b,
+ quote_options_item2a,
+ quote_options_item2b,
+ quote_options_item3a,
+ quote_options_item3b,
+ quote_options_item4a,
+ quote_options_item4b,
+ quote_options_item4c,
+ quote_options_item5a,
+ quote_options_item5b,
+ quote_options_item5c,
+ quote_options_item6a,
+ quote_options_item6b,
+ quote_save_title,
+ quote_restore_title,
+ quote_difficulty_title,
+ quote_difficulty_item1,
+ quote_difficulty_item2,
+ quote_save_successful,
+ quote_restore_successful,
+ quote_save_failed,
+ quote_restore_failed,
+ quote_emergency_save_1a,
+ quote_emergency_save_1b,
+ quote_emergency_save_success,
+ quote_emergency_save_failure,
+ quote_emergency_save_attempt,
+ quote_emergency_save_resume
+#endif
};
} // namespace Phantom
diff --git a/engines/mads/madsv2/phantom/main.cpp b/engines/mads/madsv2/phantom/main.cpp
new file mode 100644
index 00000000000..a458ab99179
--- /dev/null
+++ b/engines/mads/madsv2/phantom/main.cpp
@@ -0,0 +1,73 @@
+/* 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 "mads/madsv2/phantom/main.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/matte.h"
+#include "mads/madsv2/core/mouse.h"
+#include "mads/madsv2/core/quote.h"
+#include "mads/madsv2/phantom/main_menu.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+
+char *quotes;
+
+static void main_menu_main() {
+ if (kernel_game_startup(19, KERNEL_STARTUP_CURSOR | KERNEL_STARTUP_INTERRUPT | KERNEL_STARTUP_FONT,
+ nullptr, nullptr)) {
+ viewing_at_y = (200 - scr_work.y) >> 1;
+
+ mouse_cursor_sprite(cursor, 7);
+ mouse_show();
+ mouse_force(280, 126);
+ mouse_hide();
+
+ mouse_cursor_sprite(cursor, 1);
+ matte_init(0xFFFF);
+ kernel_seq_init();
+ kernel_message_init();
+ kernel_animation_init();
+ kernel_init_dynamic();
+
+ picture_view_x = 0;
+ picture_view_y = 0;
+
+ quotes = quote_load(0, 68, 69, 70, 71, 72, 73, 74, 75, 76,
+ 77, 78, 79, 80, 81, 82, 83, 84, 85, 86,
+ 87, 88, 89, 90, 91, 92, 93, 94, 95, 96,
+ 97, 98, 99, 0);
+
+ global_speech_load(9);
+#if 0
+ kernel_room_startup(922);
+#endif
+ }
+}
+
+void phantom_main() {
+ main_menu_main();
+}
+
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/main.h b/engines/mads/madsv2/phantom/main.h
new file mode 100644
index 00000000000..99da05a8756
--- /dev/null
+++ b/engines/mads/madsv2/phantom/main.h
@@ -0,0 +1,37 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef MADS_PHANTOM_MAIN_H
+#define MADS_PHANTOM_MAIN_H
+
+#include "common/scummsys.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+
+extern void phantom_main();
+
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/phantom/main_menu.cpp b/engines/mads/madsv2/phantom/main_menu.cpp
index 135cfdfa341..b1102994af6 100644
--- a/engines/mads/madsv2/phantom/main_menu.cpp
+++ b/engines/mads/madsv2/phantom/main_menu.cpp
@@ -136,7 +136,7 @@ int selected_item = -1;
#define LEFT_EYE 0
#define RIGHT_EYE 1
-char *quotes = NULL;
+extern char *quotes;
int eye_message[2];
int eye_pokes = 0;
int recent_eye = 0;
diff --git a/engines/mads/madsv2/phantom/main_menu.h b/engines/mads/madsv2/phantom/main_menu.h
index e27d31634d2..4b6e19b87f0 100644
--- a/engines/mads/madsv2/phantom/main_menu.h
+++ b/engines/mads/madsv2/phantom/main_menu.h
@@ -41,13 +41,15 @@ namespace Phantom {
#define MENU_HIGH_SPRITE 15
-
typedef struct {
int handle; /* Sprite series handle */
int active; /* Menu item is active */
int status; /* Current status */
} MenuItem;
+extern void global_speech_load(int id);
+extern void menu_control();
+
} // namespace Phantom
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/metaengine.cpp b/engines/mads/metaengine.cpp
index 1c9339612bb..8ea055d7741 100644
--- a/engines/mads/metaengine.cpp
+++ b/engines/mads/metaengine.cpp
@@ -39,6 +39,9 @@
#include "mads/events.h"
#include "mads/game.h"
#include "mads/detection.h"
+#ifdef ENABLE_MADSV2
+#include "mads/madsv2/engine.h"
+#endif
#define MAX_SAVES 99
@@ -199,6 +202,12 @@ bool MADS::MADSEngine::hasFeature(EngineFeature f) const {
}
Common::Error MADSMetaEngine::createInstance(OSystem *syst, Engine **engine, const MADS::MADSGameDescription *desc) const {
+#ifdef ENABLE_MADSV2
+ if (desc->gameID == MADS::GType_Phantom)
+ *engine = new MADS::MADSV2::MADSV2Engine(syst, desc);
+ else
+#endif
+
*engine = new MADS::MADSEngine(syst,desc);
return Common::kNoError;
}
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index f91aa8805a9..043f01d479e 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -59,8 +59,11 @@ MODULE_OBJS += \
forest/game_forest.o \
forest/forest_scenes.o \
forest/globals_forest.o \
+ madsv2/engine.o \
madsv2/core/speech.o \
- madsv2/phantom/main_menu.o
+ madsv2/phantom/mads/mads.o \
+ madsv2/phantom/main_menu.o \
+ madsv2/phantom/main.o
endif
# This module can be built as a plugin
Commit: ad3a8d9574701b3897416c27d3db65885e302ccf
https://github.com/scummvm/scummvm/commit/ad3a8d9574701b3897416c27d3db65885e302ccf
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:19:03+10:00
Commit Message:
MADS: PHANTOM: In progress hooking up startup code dependencies
Changed paths:
A engines/mads/madsv2/core/attr.h
A engines/mads/madsv2/core/demo.h
A engines/mads/madsv2/core/digi.h
A engines/mads/madsv2/core/echo.h
A engines/mads/madsv2/core/himem.h
A engines/mads/madsv2/core/kernel_1.cpp
A engines/mads/madsv2/core/kernel_1.h
A engines/mads/madsv2/core/kernel_2.cpp
A engines/mads/madsv2/core/kernel_2.h
A engines/mads/madsv2/core/kernel_3.cpp
A engines/mads/madsv2/core/kernel_4.cpp
A engines/mads/madsv2/core/kernel_5.cpp
A engines/mads/madsv2/core/kernel_6.cpp
A engines/mads/madsv2/core/kernel_6.h
A engines/mads/madsv2/core/kernel_7.cpp
A engines/mads/madsv2/core/kernel_8.cpp
A engines/mads/madsv2/core/kernel_8.h
A engines/mads/madsv2/core/kernel_9.cpp
A engines/mads/madsv2/core/kernel_9.h
A engines/mads/madsv2/core/kernel_a.cpp
A engines/mads/madsv2/core/kernel_b.cpp
A engines/mads/madsv2/core/kernel_c.cpp
A engines/mads/madsv2/core/kernel_c.h
A engines/mads/madsv2/core/kernel_d.cpp
A engines/mads/madsv2/core/kernel_d.h
A engines/mads/madsv2/core/kernel_e.cpp
A engines/mads/madsv2/core/kernel_f.cpp
A engines/mads/madsv2/core/kernel_f.h
A engines/mads/madsv2/core/kernel_g.cpp
A engines/mads/madsv2/core/kernel_g.h
A engines/mads/madsv2/core/kernel_h.cpp
A engines/mads/madsv2/core/kernel_h.h
A engines/mads/madsv2/core/kernel_i.cpp
A engines/mads/madsv2/core/kernel_i.h
A engines/mads/madsv2/core/kernel_j.cpp
A engines/mads/madsv2/core/kernel_k.cpp
A engines/mads/madsv2/core/kernel_k.h
A engines/mads/madsv2/core/kernel_l.cpp
A engines/mads/madsv2/core/kernel_m.cpp
A engines/mads/madsv2/core/kernel_n.cpp
A engines/mads/madsv2/core/kernel_n.h
A engines/mads/madsv2/core/kernel_o.cpp
A engines/mads/madsv2/core/kernel_o.h
A engines/mads/madsv2/core/kernel_q.cpp
A engines/mads/madsv2/core/kernel_r.cpp
A engines/mads/madsv2/core/lock.h
A engines/mads/madsv2/core/matte_1.cpp
A engines/mads/madsv2/core/midi.h
A engines/mads/madsv2/core/mouse_1.cpp
A engines/mads/madsv2/core/mouse_1.h
A engines/mads/madsv2/core/mouse_2.cpp
A engines/mads/madsv2/core/object.h
A engines/mads/madsv2/core/qual.h
A engines/mads/madsv2/core/sort.h
A engines/mads/madsv2/core/window.h
engines/mads/madsv2/core/buffer.h
engines/mads/madsv2/core/font.h
engines/mads/madsv2/core/general.h
engines/mads/madsv2/core/kernel.h
engines/mads/madsv2/core/matte.h
engines/mads/madsv2/core/mem.h
engines/mads/madsv2/core/screen.h
engines/mads/madsv2/core/sprite.h
engines/mads/madsv2/core/video.h
engines/mads/module.mk
diff --git a/engines/mads/madsv2/core/attr.h b/engines/mads/madsv2/core/attr.h
new file mode 100644
index 00000000000..d9acef14a60
--- /dev/null
+++ b/engines/mads/madsv2/core/attr.h
@@ -0,0 +1,58 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef MADS_CORE_ATTR_H
+#define MADS_CORE_ATTR_H
+
+#include "mads/madsv2/core/buffer.h"
+#include "mads/madsv2/core/room.h"
+#include "mads/madsv2/core/tile.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+#define ATTR_WALK_MASK 0x80
+#define ATTR_SPECIAL_MASK 0x70
+#define ATTR_DEPTH_MASK 0x0f
+
+#define ATTR_PACKED_ATTR_MASK 0x03
+#define ATTR_PACKED_WALK_MASK 0x02
+#define ATTR_PACKED_DEPTH_MASK 0x01
+
+/* attr_1.cpp */
+extern int attr_walk(Buffer *attr, int x, int y);
+
+/* attr_2.cpp */
+extern int attr_depth(TileMapHeader *depth_map, int x, int y);
+
+/* attr_3.cpp */
+extern int attr_special(Buffer *attr, int x, int y);
+
+/* attr_4.c */
+extern int attr_load(char *base_name, int item_type, int variant,
+ Buffer *target, int size_x, int size_y);
+
+extern int attr_load_error;
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/buffer.h b/engines/mads/madsv2/core/buffer.h
index e734219ba30..29bbe324da3 100644
--- a/engines/mads/madsv2/core/buffer.h
+++ b/engines/mads/madsv2/core/buffer.h
@@ -44,93 +44,92 @@ namespace MADSV2 {
extern int buffer_restore_keep_flag;
-/* buffer_1.c */
+/* buffer_1.cpp */
int buffer_init(Buffer *buf, word x, word y);
-int buffer_init_name(Buffer *buf, word x, word y,
- char *block_name);
+int buffer_init_name(Buffer *buf, word x, word y, const char *block_name);
-/* buffer_2.c */
+/* buffer_2.cpp */
int buffer_free(Buffer *buf);
-/* buffer_3.c */
-int buffer_fill(Buffer target, byte value);
+/* buffer_3.cpp */
+int buffer_fill(Buffer target, byte value);
-/* buffer_4.c */
+/* buffer_4.cpp */
int buffer_rect_copy(Buffer from, Buffer unto,
int ul_x, int ul_y,
int size_x, int size_y);
-/* buffer_5.c */
+/* buffer_5.cpp */
int buffer_rect_fill(Buffer target,
int ul_x, int ul_y,
int size_x, int size_y,
byte value);
-/* buffer_6.c */
+/* buffer_6.cpp */
int buffer_rect_copy_2(Buffer from, Buffer unto,
int from_x, int from_y,
int unto_x, int unto_y,
int size_x, int size_y);
-/* buffer_7.c */
+/* buffer_7.cpp */
void buffer_put_pixel(Buffer buf, word x,
word y, byte c);
-/* buffer_8.c */
+/* buffer_8.cpp */
byte buffer_get_pixel(Buffer buf, word x, word y);
-/* buffer_9.c */
+/* buffer_9.cpp */
void buffer_hline(Buffer buf, word x1, word x2,
word y, byte color);
-/* buffer_a.c */
+/* buffer_a.cpp */
void buffer_vline(Buffer buf, word x, word y1,
word y2, byte color);
-/* buffer_b.c */
+/* buffer_b.cpp */
void buffer_draw_box(Buffer buf, word x1, word y1,
word x2, word y2, byte color);
-/* buffer_d.c */
+/* buffer_d.cpp */
void buffer_hline_xor(Buffer buf, int x1, int x2, int y);
-/* buffer_e.c */
+/* buffer_e.cpp */
void buffer_vline_xor(Buffer buf, int x, int y1, int y2);
-/* buffer_f.c */
+/* buffer_f.cpp */
void buffer_draw_crosshair(Buffer buf, int x, int y);
-/* buffer_g.c */
+/* buffer_g.cpp */
void buffer_draw_box_xor(Buffer buf, int x1, int y1, int x2, int y2);
-/* buffer_h.c */
+/* buffer_h.cpp */
int buffer_get_delta_bounds(Buffer buf1, Buffer buf2,
byte newcol, word *xl, word *xh,
word *yl, word *yh);
-/* buffer_i.c */
+/* buffer_i.cpp */
byte *fastcall buffer_pointer(Buffer *buf, int x, int y);
int buffer_conform(Buffer *buffer, int *x, int *y,
int *xs, int *ys);
-/* buffer_j.c */
+/* buffer_j.cpp */
int buffer_inter_merge_2(Buffer from, Buffer unto,
int from_x, int from_y,
int unto_x, int unto_y,
int size_x, int size_y);
-/* buffer_k.c */
+/* buffer_k.cpp */
void buffer_line(Buffer target, int x1, int y1, int x2, int y2,
int color);
-/* buffer_l.c */
+/* buffer_l.cpp */
void buffer_line_xor(Buffer target, int x1, int y1,
int x2, int y2);
-/* buffer_m.c */
+/* buffer_m.cpp */
int buffer_legal(Buffer walk, int orig_wrap,
int x1, int y1, int x2, int y2);
-/* buffer_n.c */
+/* buffer_n.cpp */
extern word pattern_control_value;
extern int auto_pattern;
@@ -144,20 +143,20 @@ word buffer_rect_fill_pattern(Buffer target,
word note_line);
-/* buffer_o.c */
+/* buffer_o.cpp */
int buffer_rect_fill_swap(Buffer target,
int ul_x, int ul_y,
int size_x, int size_y,
byte value1, byte value2);
-/* buffer_p.c */
+/* buffer_p.cpp */
void buffer_peel_horiz(Buffer *target, int peel);
-/* buffer_q.c */
+/* buffer_q.cpp */
void buffer_peel_vert(Buffer *target, int peel,
byte *work_memory, long work_size);
-/* buffer_r.c */
+/* buffer_r.cpp */
int buffer_to_disk(Buffer *source, int x, int y,
int xs, int ys);
void buffer_from_disk(Buffer *source, int buffer_id,
@@ -165,7 +164,7 @@ void buffer_from_disk(Buffer *source, int buffer_id,
int x, int y,
int xs, int ys);
-/* buffer_s.c */
+/* buffer_s.cpp */
int buffer_to_ems(Buffer *source, int page_handle,
int source_ems_handle,
int x, int y, int xs, int ys);
@@ -173,7 +172,7 @@ int buffer_from_ems(Buffer *source, int page_handle,
int target_ems_handle,
int x, int y, int xs, int ys);
-/* buffer_t.c */
+/* buffer_t.cpp */
int buffer_preserve(Buffer *source, int flags,
int source_ems_handle,
int x, int y, int xs, int ys);
@@ -182,7 +181,7 @@ void buffer_restore(Buffer *source, int preserve_handle,
int x, int y, int xs, int ys);
-/* buffer_u.c */
+/* buffer_u.cpp */
int buffer_rect_translate(Buffer from, Buffer unto,
int from_x, int from_y,
int unto_x, int unto_y,
@@ -190,12 +189,12 @@ int buffer_rect_translate(Buffer from, Buffer unto,
byte *table);
-/* buffer_w.c */
+/* buffer_w.cpp */
int buffer_scan(Buffer *buffer, int magic,
int base_x, int base_y,
int size_x, int size_y);
-/* buffer_w.c */
+/* buffer_w.cpp */
int buffer_compare(Buffer *buffer0, Buffer *buffer1,
int base_x, int base_y,
int base_x2, int base_y2,
diff --git a/engines/mads/madsv2/core/demo.h b/engines/mads/madsv2/core/demo.h
new file mode 100644
index 00000000000..8ee83080b77
--- /dev/null
+++ b/engines/mads/madsv2/core/demo.h
@@ -0,0 +1,41 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef MADS_CORE_DEMO_H
+#define MADS_CORE_DEMO_H
+
+#include "mads/madsv2/core/general.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+/* demo_1.asm */
+int demo_checksum(byte **source, int *pack_size, int *unpack_size);
+int demo_check(void);
+
+/* demo_2.cpp */
+void fastcall demo_log_in(char *release_version, char *release_date);
+void fastcall demo_verify(void);
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/digi.h b/engines/mads/madsv2/core/digi.h
new file mode 100644
index 00000000000..1a4816a347d
--- /dev/null
+++ b/engines/mads/madsv2/core/digi.h
@@ -0,0 +1,43 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef MADS_CORE_DIGI_H
+#define MADS_CORE_DIGI_H
+
+#include "mads/madsv2/core/general.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+void digi_install(void);
+void digi_play(char name[30], int slot);
+void digi_play_build(int room, char thing, int num, int slot);
+void digi_play_build_ii(char thing, int num, int slot);
+void digi_stop(int which_one);
+void digi_uninstall(void);
+void digi_read_another_chunk(void);
+void digi_initial_volume(int vol);
+void digi_set_volume(int vol, int slot);
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/echo.h b/engines/mads/madsv2/core/echo.h
new file mode 100644
index 00000000000..87f8c97e83c
--- /dev/null
+++ b/engines/mads/madsv2/core/echo.h
@@ -0,0 +1,36 @@
+/* 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 MADS_CORE_ECHO_H
+#define MADS_CORE_ECHO_H
+
+#include "common/scummsys.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+/* echo_1.cpp */
+void echo(char *item, int carriage_return);
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/font.h b/engines/mads/madsv2/core/font.h
index 51766490895..1c80ecfd96b 100644
--- a/engines/mads/madsv2/core/font.h
+++ b/engines/mads/madsv2/core/font.h
@@ -51,7 +51,7 @@ extern FontPtr font_menu; /* Font handle for menu stuff */
extern FontPtr font_misc; /* Font handle for symbols & icons */
/* font_1.cpp */
-FontPtr font_load(char *name);
+FontPtr font_load(const char *name);
/* font_2.cpp */
int font_write(FontPtr font, Buffer *target,
diff --git a/engines/mads/madsv2/core/general.h b/engines/mads/madsv2/core/general.h
index 2e7a42c0716..1bc9c807830 100644
--- a/engines/mads/madsv2/core/general.h
+++ b/engines/mads/madsv2/core/general.h
@@ -134,6 +134,16 @@ typedef struct { /* Video buffer structure */
#define sgn_in(x,s) ( ((s) >= 0) ? (x) : (neg(x)) ) /* Incorporate sign */
+inline void mads_strupr(char *s) {
+ for (; *s; ++s)
+ *s = toupper(*s);
+}
+
+inline void mads_strlwr(char *s) {
+ for (; *s; ++s)
+ *s = tolower(*s);
+}
+
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/core/himem.h b/engines/mads/madsv2/core/himem.h
new file mode 100644
index 00000000000..10501ce7c46
--- /dev/null
+++ b/engines/mads/madsv2/core/himem.h
@@ -0,0 +1,94 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef MADS_CORE_HIMEM_H
+#define MADS_CORE_HIMEM_H
+
+#include "mads/madsv2/core/pack.h"
+#include "mads/madsv2/core/ems.h"
+#include "mads/madsv2/core/mem.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+#define HIMEM_MAX_RESIDENT 150
+
+typedef struct {
+ byte memory_type; /* Memory type */
+ byte ems_page_handle; /* EMS paging info */
+ byte level; /* Preload level */
+ char list[14]; /* File name info */
+ word xms_handle; /* Handle in XMS */
+ long size; /* Size in bytes */
+ int num_packets; /* Number of packets */
+ long packet_size[PACK_MAX_LIST_LENGTH]; /* Sizes of packets */
+} HimemDirectory;
+
+
+extern byte himem_preload_ems_disabled;
+extern byte himem_preload_xms_disabled;
+
+extern byte himem_directory_allocation;
+extern HimemDirectory himem_directory_save_area;
+extern HimemDirectory *himem_directory;
+extern HimemDirectory *himem_directory_entry;
+extern HimemDirectory *himem_ems_directory;
+
+extern int himem_directory_xms_handle;
+extern int himem_directory_ems_active;
+extern int himem_active;
+
+extern int himem_ems_preloaded;
+extern int himem_xms_preloaded;
+
+/* himem_1.cpp */
+int himem_activate_directory(void);
+
+/* himem_2.cpp */
+int fastcall himem_get_directory_entry(int id);
+
+/* himem_3.cpp */
+int fastcall himem_put_directory_entry(int id);
+
+/* himem_4.cpp */
+int himem_resident(char *filename);
+void himem_catalog(void);
+
+/* himem_5.cpp */
+int himem_directory_setup(void);
+
+/* himem_6.cpp */
+void himem_shutdown(void);
+void himem_startup(void);
+
+/* himem_7.cpp */
+int fastcall himem_preload(char *filename, int level);
+
+/* himem_8.cpp */
+int fastcall himem_preload_series(char *filename, int level);
+
+/* himem_9.cpp */
+void fastcall himem_flush(int level);
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/kernel.h b/engines/mads/madsv2/core/kernel.h
index da834707515..490a561b943 100644
--- a/engines/mads/madsv2/core/kernel.h
+++ b/engines/mads/madsv2/core/kernel.h
@@ -333,7 +333,7 @@ typedef struct {
#define kernel_dialog(q) inter_add_dialog(quote_string(kernel.quotes, q), q)
-/* kernel_1.c */
+/* kernel_1.cpp */
extern RoomPtr room; /* Pointer to current room's data */
extern int room_id; /* Current room # */
extern int section_id; /* Current section # */
@@ -410,41 +410,41 @@ extern KernelGame game; /* Kernel level game data */
-/* kernel_2.c */
-int kernel_load_vocab(void);
+/* kernel_2.cpp */
+int kernel_load_vocab();
-/* kernel_3.c */
-int kernel_game_shutdown(void);
-void kernel_force_refresh(void);
+/* kernel_3.cpp */
+void kernel_game_shutdown();
+void kernel_force_refresh();
int kernel_game_startup(int game_video_mode, int load_flag,
char *release_version, char *release_date);
-/* kernel_4.c */
-void kernel_section_shutdown(void);
+/* kernel_4.cpp */
+void kernel_section_shutdown();
int kernel_section_startup(int new_section);
-/* kernel_5.c */
-void kernel_room_shutdown(void);
+/* kernel_5.cpp */
+void kernel_room_shutdown();
int kernel_room_startup(int new_room, int initial_variant,
char *interface, int new_palette);
-/* kernel_6.c */
-void kernel_unload_all_series(void);
+/* kernel_6.cpp */
+void kernel_unload_all_series();
int kernel_load_series(const char *name, int load_flags);
-/* kernel_7.c */
+/* kernel_7.cpp */
void kernel_flip_hotspot(int vocab_code, int active);
void kernel_flip_hotspot_loc(int vocab_code, int active,
int x, int y);
-/* kernel_8.c */
+/* kernel_8.cpp */
extern Sequence sequence_list[KERNEL_MAX_SEQUENCES];
-/* kernel_8.c */
-void kernel_seq_init(void);
+/* kernel_8.cpp */
+void kernel_seq_init();
void kernel_seq_correction(long old_clock, long new_clock);
-/* kernel_8.c */
+/* kernel_8.cpp */
int kernel_seq_add(int series_id, int mirror,
int initial_sprite,
int low_sprite, int high_sprite,
@@ -456,7 +456,7 @@ int kernel_seq_add(int series_id, int mirror,
word start_ticks,
int expire);
-/* kernel_8.c */
+/* kernel_8.cpp */
int kernel_seq_forward(int series_id, int mirror,
word ticks, word interval_ticks,
word start_ticks, int expire);
@@ -465,7 +465,7 @@ int kernel_seq_forward_scroll(int series_id, int mirror,
word ticks, word interval_ticks,
word start_ticks, int expire);
-/* kernel_8.c */
+/* kernel_8.cpp */
int kernel_seq_pingpong(int series_id, int mirror,
word ticks, word interval_ticks,
word start_ticks, int expire);
@@ -474,7 +474,7 @@ int kernel_seq_pingpong_scroll(int series_id, int mirror,
word ticks, word interval_ticks,
word start_ticks, int expire);
-/* kernel_8.c */
+/* kernel_8.cpp */
int kernel_seq_backward(int series_id, int mirror,
word ticks, word interval_ticks,
word start_ticks, int expire);
@@ -483,186 +483,164 @@ int kernel_seq_backward_scroll(int series_id, int mirror,
word ticks, word interval_ticks,
word start_ticks, int expire);
-/* kernel_8.c */
+/* kernel_8.cpp */
int kernel_seq_stamp(int series_id, int mirror, int sprite);
int kernel_seq_stamp_scroll(int series_id, int mirror, int sprite);
-/* kernel_8.c */
+/* kernel_8.cpp */
void kernel_synch(int slave_type, int slave_id,
int master_type, int master_id);
void kernel_player_expire(int sequence_id);
-/* kernel_8.c */
+/* kernel_8.cpp */
void kernel_seq_depth(int sequence_id, int depth);
void kernel_seq_scale(int sequence_id, int scale);
void kernel_seq_loc(int sequence_id, int x, int y);
void kernel_seq_range(int sequence_id,
int first, int last);
-/* kernel_8.c */
+/* kernel_8.cpp */
void kernel_seq_motion(int sequence_id, int flags,
int delta_x_times_100,
int delta_y_times_100);
-/* kernel_8.c */
-int kernel_seq_trigger(int sequence_id,
+/* kernel_8.cpp */
+extern int kernel_seq_trigger(int sequence_id,
int trigger_type,
int trigger_sprite,
int trigger_code);
-/* kernel_8.c */
-int kernel_timing_trigger(int ticks, int trigger_code);
+/* kernel_8.cpp */
+extern int kernel_timing_trigger(int ticks, int trigger_code);
-/* kernel_8.c */
-void kernel_seq_purge(int sequence_id);
-void kernel_seq_full_update(void);
+/* kernel_8.cpp */
+extern int kernel_seq_purge(int sequence_id);
+extern void kernel_seq_full_update();
-/* kernel_8.c */
-void kernel_draw_to_background(int series_id, int sprite_id,
- int x, int y,
- int depth, int scale);
-
-
-/* kernel_9.c */
-void kernel_seq_delete(int sequence_id);
-int kernel_seq_update(SequencePtr sequence,
- int sequence_id);
-void kernel_seq_update_all(void);
+/* kernel_8.cpp */
+extern void kernel_draw_to_background(int series_id, int sprite_id,
+ int x, int y, int depth, int scale);
-/* kernel_a.c */
-void kernel_seq_player(int sequence_id, int synch_me);
+/* kernel_9.cpp */
+extern void kernel_seq_delete(int sequence_id);
+extern int kernel_seq_update(SequencePtr sequence, int sequence_id);
+extern void kernel_seq_update_all();
+/* kernel_a.cpp */
+extern void kernel_seq_player(int sequence_id, int synch_me);
-/* kernel_b.c */
-void kernel_animation_init(void);
-int kernel_run_animation(const char *name, int trigger_code);
-int kernel_run_animation_disp(char thing, int num, int trigger_code);
-int kernel_run_animation_talk(char thing, int num, int trigger_code);
-int kernel_run_animation_write(int trigger_code);
-int kernel_run_animation_point(int num, int trigger_code);
+/* kernel_b.cpp */
+extern void kernel_animation_init();
+extern int kernel_run_animation(const char *name, int trigger_code);
+extern int kernel_run_animation_disp(char thing, int num, int trigger_code);
+extern int kernel_run_animation_talk(char thing, int num, int trigger_code);
+extern int kernel_run_animation_write(int trigger_code);
+extern int kernel_run_animation_point(int num, int trigger_code);
+/* kernel_c.cpp */
+extern void kernel_reset_animation(int handle, int frame);
+extern void kernel_abort_animation(int handle);
+extern void kernel_abort_all_animations();
+extern void kernel_doom_all_animations();
+extern void kernel_abort_doomed_animations();
+extern void kernel_process_all_animations();
-/* kernel_c.c */
-void kernel_reset_animation(int handle, int frame);
-void kernel_abort_animation(int handle);
-void kernel_abort_all_animations(void);
-void kernel_doom_all_animations(void);
-void kernel_abort_doomed_animations(void);
-void kernel_process_all_animations(void);
-
-/* kernel_d.c */
+/* kernel_d.cpp */
extern KernelMessage kernel_message[KERNEL_MAX_MESSAGES];
extern FontPtr kernel_message_font;
extern int kernel_message_spacing;
-/* kernel_d.c */
-void kernel_message_init(void);
-int kernel_message_add(char *text, int x, int y,
- int color,
- long time_on_screen,
- int trigger_code,
- int flags);
-/* kernel_d.c */
-void kernel_message_teletype(int id, int rate, int quote);
-void kernel_message_attach(int id, int sequence);
-void kernel_message_delete(int id);
-void kernel_message_purge(void);
-
-/* kernel_d.c */
-void kernel_message_anim(int id, int anim, int segment);
-int kernel_message_player(int quote_id, long delay, int trigger);
-
-
-/* kernel_e.c */
-void kernel_message_update(KernelMessagePtr my_message);
-void kernel_message_update_all(void);
-void kernel_message_correction(long old_clock, long new_clock);
-
-
-/* kernel_f.c */
-int kernel_add_dynamic(int vocab_id, int verb_id, byte syntax,
- int auto_sequence,
- int x, int y, int xs, int ys);
-/* kernel_f.c */
-int kernel_dynamic_walk(int id, int feet_x, int feet_y,
+/* kernel_d.cpp */
+extern void kernel_message_init();
+extern int kernel_message_add(char *text, int x, int y, int color,
+ long time_on_screen, int trigger_code, int flags);
+
+/* kernel_d.cpp */
+extern void kernel_message_teletype(int id, int rate, int quote);
+extern void kernel_message_attach(int id, int sequence);
+extern void kernel_message_delete(int id);
+extern void kernel_message_purge();
+
+/* kernel_d.cpp */
+extern void kernel_message_anim(int id, int anim, int segment);
+extern int kernel_message_player(int quote_id, long delay, int trigger);
+
+
+/* kernel_e.cpp */
+extern void kernel_message_update(KernelMessagePtr my_message);
+extern void kernel_message_update_all();
+extern void kernel_message_correction(long old_clock, long new_clock);
+
+
+/* kernel_f.cpp */
+extern int kernel_add_dynamic(int vocab_id, int verb_id, byte syntax,
+ int auto_sequence, int x, int y, int xs, int ys);
+
+/* kernel_f.cpp */
+extern int kernel_dynamic_walk(int id, int feet_x, int feet_y,
int facing);
-void kernel_dynamic_anim(int id, int anim_id, int segment);
+extern void kernel_dynamic_anim(int id, int anim_id, int segment);
-/* kernel_f.c */
+/* kernel_f.cpp */
int kernel_dynamic_cursor(int id, int cursor);
void kernel_delete_dynamic(int id);
-void kernel_purge_dynamic(void);
-void kernel_init_dynamic(void);
-
-/* kernel_g.c */
-int kernel_dynamic_consecutive(int id);
-void kernel_refresh_dynamic(void);
-
-/* kernel_h.c */
-char *fastcall kernel_full_name(int my_room,
- char type, int num, char *text,
- int ext);
-char *fastcall kernel_name(char type, int num);
-char *fastcall kernel_interface_name(int num);
-
-
-/* kernel_i.c */
-void kernel_unload_sound_driver(void);
-int kernel_load_sound_driver(const char *name, char sound_card,
- int sound_board_address,
- int sound_board_type,
- int sound_board_irq);
-
-/* kernel_j.c */
-void kernel_load_variant(int variant);
-
-
-/* kernel_k.c */
-void kernel_new_palette(void);
-
-
-/* kernel_l.c */
-void kernel_dump_quotes(void);
-void kernel_dump_all(void);
-void kernel_dump_walker_only(void);
-
-/* kernel_m.c */
-int kernel_save_game(char *filename);
-int kernel_load_game(char *filename);
-
-/* kernel_n.c */
-void kernel_random_messages_init(int max_messages_at_once,
- int min_x, int max_x,
- int min_y, int max_y,
- int min_y_spacing,
- int teletype_rate,
- int color,
- int duration,
- int quote_id, ...);
-/* kernel_n.c */
-int kernel_check_random(void);
-void kernel_random_message_server(void);
-int kernel_generate_random_message(int chance_major,
- int chance_minor);
-void kernel_random_purge(void);
-
-
-/* kernel_o.c */
-void kernel_load_interface(void);
-void kernel_set_interface_mode(int mode);
-
-
-/* kernel_q.c */
-void kernel_room_scale(int front_y, int front_scale,
- int back_y, int back_scale);
-
-/* kernel_r.c */
-void kernel_background_shutdown(void);
-int kernel_background_startup(int new_room,
- int initial_variant);
+void kernel_purge_dynamic();
+void kernel_init_dynamic();
+
+/* kernel_g.cpp */
+extern int kernel_dynamic_consecutive(int id);
+extern void kernel_refresh_dynamic();
+
+/* kernel_h.cpp */
+extern char *kernel_full_name(int my_room, char type, int num, char *text, int ext);
+extern char *kernel_name(char type, int num);
+extern char *kernel_interface_name(int num);
+
+/* kernel_i.cpp */
+extern void kernel_unload_sound_driver();
+extern int kernel_load_sound_driver(const char *name, char sound_card,
+ int sound_board_address, int sound_board_type, int sound_board_irq);
+
+/* kernel_j.cpp */
+extern void kernel_load_variant(int variant);
+
+/* kernel_k.cpp */
+extern void kernel_new_palette();
+
+/* kernel_l.cpp */
+extern void kernel_dump_quotes();
+extern void kernel_dump_all();
+extern void kernel_dump_walker_only();
+
+/* kernel_m.cpp */
+extern int kernel_save_game(char *filename);
+extern int kernel_load_game(char *filename);
+
+/* kernel_n.cpp */
+extern void kernel_random_messages_init(int max_messages_at_once,
+ int min_x, int max_x, int min_y, int max_y,
+ int min_y_spacing, int teletype_rate, int color,
+ int duration, int quote_id, ...);
+
+/* kernel_n.cpp */
+extern int kernel_check_random();
+extern void kernel_random_message_server();
+extern int kernel_generate_random_message(int chance_major, int chance_minor);
+extern void kernel_random_purge();
+
+/* kernel_o.cpp */
+extern void kernel_load_interface();
+extern void kernel_set_interface_mode(int mode);
+
+/* kernel_q.cpp */
+extern void kernel_room_scale(int front_y, int front_scale, int back_y, int back_scale);
+
+/* kernel_r.cpp */
+extern void kernel_background_shutdown();
+extern int kernel_background_startup(int new_room, int initial_variant);
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/core/kernel_1.cpp b/engines/mads/madsv2/core/kernel_1.cpp
new file mode 100644
index 00000000000..eb4cf103a42
--- /dev/null
+++ b/engines/mads/madsv2/core/kernel_1.cpp
@@ -0,0 +1,83 @@
+/*
+/* kernel_1.c by Brian Reynolds 5-Nov-91
+*/
+
+#include <general.mac>
+#include <room.mac>
+#include <color.mac>
+
+#include "kernel.mac"
+
+RoomPtr room = NULL;
+int room_id = KERNEL_STARTING_GAME;
+int section_id = KERNEL_STARTING_GAME;
+int room_variant = 0;
+
+int new_room = 101;
+int new_section = 1;
+
+int previous_room = 0;
+int previous_section = 0;
+
+int kernel_initial_variant = 0;
+
+HotPtr room_spots = NULL;
+int room_num_spots = 0;
+
+int kernel_room_series_marker = 0;
+
+int kernel_room_bound_dif;
+int kernel_room_scale_dif;
+
+int kernel_allow_peel = false;
+
+int kernel_panning_speed = 0;
+int kernel_screen_fade = 0;
+
+Animation kernel_anim[KERNEL_MAX_ANIMATIONS];
+
+/*
+AnimPtr kernel_animation = NULL;
+int kernel_animation_cycled = false;
+int kernel_repeat_animation = false;
+
+int kernel_animation_sprite_loaded;
+int kernel_animation_buffer_id;
+byte *kernel_animation_buffer[2];
+
+int kernel_animation_messages;
+
+int kernel_animation_frame;
+int kernel_animation_image;
+int kernel_animation_doomed = false;
+int kernel_animation_trigger_code;
+int kernel_animation_trigger_mode;
+int kernel_animation_trigger_words[3];
+long kernel_animation_next_clock;
+*/
+
+ShadowList kernel_shadow_main = { 0 };
+ShadowList kernel_shadow_inter = { 1, { 15 } };
+
+int kernel_ok_to_fail_load = false;
+
+byte kernel_mode = KERNEL_GAME_LOAD;
+
+char kernel_cheating_password[64];
+int kernel_cheating_allowed = 0;
+int kernel_cheating_forbidden = 0;
+
+KernelDynamicHotSpot kernel_dynamic_hot[KERNEL_MAX_DYNAMIC];
+int kernel_num_dynamic = 0;
+int kernel_dynamic_changed = 0;
+
+
+SeriesPtr cursor = NULL; /* Mouse cursor series */
+
+int cursor_id = 1;
+int cursor_last = -1;
+
+Kernel kernel; /* Kernel data */
+KernelGame game; /* Kernel level game data */
+
+
\ No newline at end of file
diff --git a/engines/mads/madsv2/core/kernel_1.h b/engines/mads/madsv2/core/kernel_1.h
new file mode 100644
index 00000000000..afa6d724601
--- /dev/null
+++ b/engines/mads/madsv2/core/kernel_1.h
@@ -0,0 +1,107 @@
+/* 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 MADS_CORE_KERNEL_1_H
+#define MADS_CORE_KERNEL_1_H
+
+#include "mads/madsv2/core/general.h"
+#include "mads/madsv2/core/room.h"
+#include "mads/madsv2/core/color.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+extern RoomPtr room;
+extern int room_id;
+extern int section_id;
+extern int room_variant;
+
+extern int new_room;
+extern int new_section;
+
+extern int previous_room;
+extern int previous_section;
+
+extern int kernel_initial_variant;
+
+extern HotPtr room_spots;
+extern int room_num_spots;
+
+extern int kernel_room_series_marker;
+
+extern int kernel_room_bound_dif;
+extern int kernel_room_scale_dif;
+
+extern int kernel_allow_peel; /* Flag if peeling buffers allowed */
+
+extern int kernel_panning_speed;
+extern int kernel_screen_fade;
+
+
+extern Animation kernel_anim[KERNEL_MAX_ANIMATIONS];
+
+/*
+extern AnimPtr kernel_animation;
+extern int kernel_animation_cycled;
+extern int kernel_repeat_animation;
+
+extern int kernel_animation_sprite_loaded;
+extern int kernel_animation_buffer_id;
+extern byte *kernel_animation_buffer[2];
+
+extern int kernel_animation_messages;
+
+extern int kernel_animation_frame;
+extern int kernel_animation_image;
+extern int kernel_animation_doomed;
+extern int kernel_animation_trigger_code;
+extern int kernel_animation_trigger_mode;
+extern int kernel_animation_trigger_words[3];
+extern long kernel_animation_next_clock;
+*/
+
+extern ShadowList kernel_shadow_main;
+extern ShadowList kernel_shadow_inter;
+
+extern int kernel_ok_to_fail_load;
+
+extern int kernel_mode;
+
+extern char kernel_cheating_password[16];
+extern int kernel_cheating_allowed;
+extern int kernel_cheating_forbidden;
+
+extern KernelDynamicHotSpot kernel_dynamic_hot[KERNEL_MAX_DYNAMIC];
+extern int kernel_num_dynamic;
+extern int kernel_dynamic_changed;
+
+extern SeriesPtr cursor; /* Mouse cursor series */
+
+extern int cursor_id;
+extern int cursor_last;
+
+extern Kernel kernel;
+extern KernelGame game; /* Kernel level game data */
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/kernel_2.cpp b/engines/mads/madsv2/core/kernel_2.cpp
new file mode 100644
index 00000000000..289ef5e6741
--- /dev/null
+++ b/engines/mads/madsv2/core/kernel_2.cpp
@@ -0,0 +1,81 @@
+/*
+/* kernel_2.c by Brian Reynolds 5-Nov-91
+/*
+/* Makes active any vocab words that will be needed for this room,
+/* and loads their text into memory.
+/*
+/* Call after room definition and object list are loaded.
+*/
+
+#include <general.mac>
+
+#include <vocab.h>
+#include <object.h>
+#include <room.h>
+#include <inter.h>
+#include <mem.h>
+#include <fileio.h>
+
+#include "kernel.mac"
+#include "kernel_1.h"
+
+
+
+#pragma optimize ("weglt", on)
+
+
+int fastcall kernel_load_vocab (void)
+{
+ int error_flag;
+ int count;
+ int count2;
+ #ifdef log_vocab
+ FILE *handle;
+ long before, after;
+ #endif
+
+ /* Load all main command verbs */
+
+ for (count = 0; count < INTER_COMMANDS; count++) {
+ vocab_make_active (command[count].id);
+ }
+
+ /* Load all object names, and all verbs associated with objects */
+
+ for (count = 0; count < num_objects; count++) {
+ vocab_make_active (object[count].vocab_id);
+
+ for (count2 = 0; count2 < (int)object[count].num_verbs; count2++) {
+ vocab_make_active (object[count].verb[count2].id);
+ }
+ }
+
+ /* Load vocabulary for this room's hot spots */
+
+ for (count = 0; count < room_num_spots; count++) {
+ vocab_make_active(room_spots[count].vocab);
+ if (room_spots[count].verb > 0) {
+ vocab_make_active(room_spots[count].verb);
+ }
+ }
+
+ #ifdef log_vocab
+ before = mem_get_avail();
+ #endif
+
+ error_flag = vocab_load_active();
+
+ #ifdef log_vocab
+ after = mem_get_avail();
+ if (fileio_exist("vocab.log")) {
+ handle = fopen("vocab.log", "wt");
+ fprintf (handle, "Room %d Vocab words: %d Memory: %ld\n",
+ room_id, vocab_active, before-after);
+ fclose (handle);
+ }
+ #endif
+
+ return (error_flag);
+}
+
+
diff --git a/engines/mads/madsv2/core/kernel_2.h b/engines/mads/madsv2/core/kernel_2.h
new file mode 100644
index 00000000000..0dbffae97b8
--- /dev/null
+++ b/engines/mads/madsv2/core/kernel_2.h
@@ -0,0 +1,35 @@
+/* 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 MADS_CORE_KERNEL_2_H
+#define MADS_CORE_KERNEL_2_H
+
+#include "mads/madsv2/core/general.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+extern int kernel_load_vocab();
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/kernel_3.cpp b/engines/mads/madsv2/core/kernel_3.cpp
new file mode 100644
index 00000000000..5a9efabc0b7
--- /dev/null
+++ b/engines/mads/madsv2/core/kernel_3.cpp
@@ -0,0 +1,459 @@
+/* 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 "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/general.h"
+#include "mads/madsv2/core/mem.h"
+#include "mads/madsv2/core/buffer.h"
+#include "mads/madsv2/core/font.h"
+#include "mads/madsv2/core/video.h"
+#include "mads/madsv2/core/matte.h"
+#include "mads/madsv2/core/inter.h"
+#include "mads/madsv2/core/mouse.h"
+#include "mads/madsv2/core/object.h"
+#include "mads/madsv2/core/error.h"
+#include "mads/madsv2/core/screen.h"
+#include "mads/madsv2/core/ems.h"
+#include "mads/madsv2/core/himem.h"
+#include "mads/madsv2/core/echo.h"
+#include "mads/madsv2/core/mcga.h"
+#include "mads/madsv2/core/timer.h"
+#include "mads/madsv2/core/cycle.h"
+#include "mads/madsv2/core/player.h"
+#include "mads/madsv2/core/keys.h"
+#include "mads/madsv2/core/pack.h"
+#include "mads/madsv2/core/room.h"
+#include "mads/madsv2/core/demo.h"
+#include "mads/madsv2/core/xms.h"
+#include "mads/madsv2/core/lock.h"
+#include "mads/madsv2/core/tile.h"
+#include "mads/madsv2/core/popup.h"
+#include "mads/madsv2/core/pal.h"
+#include "mads/madsv2/core/env.h"
+#include "mads/madsv2/core/fileio.h"
+#include "mads/madsv2/core/vocab.h"
+#include "mads/madsv2/core/kernel_1.h"
+#include "mads/madsv2/core/midi.h"
+#include "mads/madsv2/core/digi.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+/*
+/* kernel_game_shutdown()
+/*
+/* Game level system shutdown.
+*/
+void kernel_game_shutdown() {
+ int check_mode;
+
+
+ sprite_free(&box_param.menu, true);
+ sprite_free(&box_param.logo, true);
+ sprite_free(&box_param.series, true);
+
+ buffer_free(&scr_inter_orig);
+
+ vocab_unload_active();
+
+ /* Drop cursor */
+
+ if (cursor != NULL) mem_free(cursor);
+ cursor = NULL;
+
+ /* Free main video work buffer */
+
+ pack_set_special_buffer(NULL, NULL);
+
+ object_unload();
+ /* inter_deallocate_objects(); */
+
+ popup_available = false;
+
+ /* Remove special keyboard handler */
+
+ keys_remove();
+
+ /* Unload interface fonts */
+
+ if (font_misc != NULL) mem_free(font_misc);
+ if (font_menu != NULL) mem_free(font_menu);
+ if (font_conv != NULL) mem_free(font_conv);
+ if (font_inter != NULL) mem_free(font_inter);
+ if (font_main != NULL) mem_free(font_main);
+
+ font_main = font_conv = font_inter = NULL;
+
+ /* Deallocate main screen buffer */
+
+ if (work_screen_ems_handle < 0) buffer_free(&scr_main);
+
+ /* Turn of speech system */
+
+ /* pl if (speech_system_active) speech_shutdown(); */
+
+ /* Return video to text mode */
+
+ mouse_hide();
+ check_mode = video_mode;
+ mouse_init(false, text_mode);
+ video_init(text_mode, (check_mode != text_mode));
+
+ /* Deallocate EMS/XMS memory */
+
+ himem_shutdown();
+
+ /* Remove timer interrupt stuff */
+
+ midi_uninstall();
+ digi_uninstall();
+
+ timer_activate_low_priority(NULL);
+
+ timer_remove();
+
+ /* mem_free (interrupt_stack_pointer); */
+}
+
+
+void kernel_force_refresh(void) {
+ int count;
+ int purge_flag = true;
+
+ for (count = 0; count < (int)image_marker; count++) {
+ if (image_list[count].flags == IMAGE_REFRESH) {
+ purge_flag = false;
+ }
+ }
+
+ if (purge_flag) matte_refresh_work();
+}
+
+
+
+static char digital_name[12] = "digital.aga";
+
+/*
+/* kernel_game_startup()
+/*
+/* Game level system startup.
+*/
+int kernel_game_startup(int game_video_mode, int load_flag,
+ char *release_version, char *release_date) {
+ int error_flag = true;
+ int count, count2;
+ int ems_temp;
+ int ems_error;
+ int pages;
+ int reserve[EMS_PAGING_CLASSES];
+ byte *interrupt_stack;
+#ifdef demo
+ char temp_buf[20];
+#endif
+#ifndef disable_error_check
+ int error_code = 0;
+#endif
+
+ /*
+ interrupt_stack_pointer = mem_get_name(KERNEL_INTERRUPT_STACK_SIZE, "$istack$");
+ if (interrupt_stack_pointer == NULL) goto done;
+
+ interrupt_stack_size = KERNEL_INTERRUPT_STACK_SIZE;
+ */
+
+ /* Set up EMS/XMS paging system, if any */
+
+ himem_startup();
+
+ ems_error = true;
+
+ if (ems_exists) {
+ work_screen_ems_handle = ems_get_page_handle(4);
+ if (work_screen_ems_handle >= 0) {
+ ems_error = false;
+ }
+ }
+
+ if (tile_setup()) ems_error = true;
+
+ if (ems_error) {
+ if (ems_exists) {
+ error_report(ERROR_NO_MORE_EMS, SEVERE, MODULE_KERNEL, ems_pages, work_screen_ems_handle);
+ } else {
+ error_report(ERROR_KERNEL_NO_EMS, SEVERE, MODULE_KERNEL, ems_exists, work_screen_ems_handle);
+ }
+ }
+
+ /* pl if (speech_system_requested) {
+ char digital_search[20];
+ char digital_path[80];
+ speech_ems_status = SPEECH_DELUXE;
+ digital_search[0] = 0;
+ if (!fileio_exist(digital_name)) {
+ strcat (digital_search, "*");
+ }
+ strcat (digital_search, digital_name);
+ env_get_path (digital_path, digital_search);
+ speech_init (digital_path, speech_board_address,
+ speech_board_type,
+ speech_board_irq,
+ speech_board_drq);
+ }
+ */
+
+ if (ems_exists) {
+ if (load_flag & KERNEL_STARTUP_POPUP) {
+ object_ems_handle = ems_get_page_handle(4);
+
+ ems_temp = ems_get_page_handle(4);
+ if (ems_temp >= 0) popup_preserve_initiator[0] = ems_temp;
+
+ ems_temp = ems_get_page_handle(4);
+ if (ems_temp >= 0) popup_preserve_initiator[1] = ems_temp;
+
+ ems_temp = ems_get_page_handle(4);
+ if (ems_temp >= 0) popup_preserve_initiator[2] = ems_temp;
+ }
+ }
+
+
+ if (ems_exists) {
+ pages = ems_pages_free;
+ for (count = 0; count < EMS_PAGING_CLASSES; count++) {
+ reserve[EMS_PAGING_CLASSES] = 0;
+ }
+ if (pages >= 4) {
+ reserve[EMS_PAGING_SYSTEM] = 4;
+ pages -= 4;
+ }
+ ems_temp = MIN(pages >> 1, 64);
+ reserve[EMS_PAGING_ROOM] = ems_temp;
+ pages -= ems_temp;
+
+ ems_temp = pages >> 2;
+ reserve[EMS_PAGING_SECTION] = ems_temp;
+ pages -= ems_temp;
+
+ for (count = 0; count < EMS_PAGING_CLASSES; count++) {
+ ems_paging_reserve[count] = 0;
+ for (count2 = count - 1; count2 >= 0; count2--) {
+ ems_paging_reserve[count] += reserve[count2];
+ }
+ }
+ }
+
+ /* Some preliminary copy protection stuff */
+
+ /* lock_preliminary_check(); */
+
+ /* Initialize sound driver jump table */
+
+ /* pl sound_driver_null(); */
+ timer_set_sound_flag(0);
+
+ /* Video initialization */
+
+ screen_dominant_mode(game_video_mode);
+ video_init(game_video_mode, (game_video_mode != text_mode));
+ mouse_init(true, game_video_mode);
+
+ if (game_video_mode == mcga_mode) {
+ mcga_compute_retrace_parameters();
+ }
+
+ /* Initialize the main screen work buffer & its sub-buffers */
+
+ if (work_screen_ems_handle >= 0) {
+ scr_main.x = video_x;
+ scr_main.y = video_y;
+ scr_main.data = ems_page[0];
+ ems_map_buffer(work_screen_ems_handle);
+ } else {
+ buffer_init_name(&scr_main, video_x, video_y, "$scrmain");
+ }
+ if (scr_main.data == NULL) {
+#ifndef disable_error_check
+ error_code = ERROR_NO_MORE_MEMORY;
+#endif
+ goto done;
+ }
+
+ scr_work.x = scr_inter.x = video_x;
+ scr_work.y = display_y;
+ scr_inter.y = inter_size_y;
+
+ scr_work.data = scr_main.data;
+ scr_inter.data = (byte *)mem_normalize(buffer_pointer(&scr_main, 0, inter_base_y));
+
+ buffer_fill(scr_main, 0);
+
+ /* Load the main interface fonts */
+
+ if (load_flag & KERNEL_STARTUP_FONT) {
+ font_main = font_load("*FONTMAIN.FF");
+ font_inter = font_load("*FONTINTR.FF");
+ font_conv = font_load("*FONTCONV.FF");
+ font_menu = font_load("*FONTMENU.FF");
+ font_misc = font_load("*FONTMISC.FF");
+
+ if ((font_main == NULL) || (font_inter == NULL) ||
+ (font_conv == NULL) || (font_menu == NULL) ||
+ (font_misc == NULL)) {
+#ifndef disable_error_check
+ error_code = ERROR_KERNEL_NO_FONTS;
+#endif
+ goto done;
+ }
+ }
+
+
+ /* Install timer handler & low priority cycling interrupt */
+
+ if (load_flag & KERNEL_STARTUP_INTERRUPT) {
+ timer_install();
+
+ midi_install();
+ digi_install();
+
+ /*
+ if (!lock_verification()) {
+ error_report (ERROR_COPY_PROTECTION, SEVERE, MODULE_LOCK, 0, 0);
+ }
+ timer_remove();
+ timer_install();
+ */
+
+ cycling_active = false;
+ timer_activate_low_priority(cycle_colors);
+ keys_install();
+ }
+
+ /* Log in demo copy */
+
+#ifdef demo
+ if (game_video_mode != text_mode) demo_log_in(release_version, release_date);
+#endif
+
+ /* Mention EMS paging situation */
+
+#ifdef demo
+ if (ems_paging_active) {
+ ltoa(((long)ems_pages * EMS_PAGE_SIZE) >> 10, temp_buf, 10);
+ echo(temp_buf, false);
+ echo("K of EMS memory available.", true);
+ } else {
+ echo("EMS memory not available.", true);
+ }
+
+ if (xms_exists) {
+ echo("XMS memory system detected.", true);
+ }
+#endif
+
+ /* Load the objects list */
+
+ if (load_flag & KERNEL_STARTUP_OBJECTS) {
+ /* inter_allocate_objects(); */
+ if (object_load()) {
+#ifndef disable_error_check
+ error_code = ERROR_KERNEL_NO_OBJECTS;
+#endif
+ goto done;
+ }
+ if (inven_num_objects > 0) {
+ active_inven = 0;
+ }
+ }
+
+ /* Allow packing routines to use lower interrupt stack */
+
+ interrupt_stack = timer_get_interrupt_stack();
+ pack_set_special_buffer(interrupt_stack, NULL);
+
+ /* Initialize player data structures */
+
+ if (load_flag & KERNEL_STARTUP_PLAYER) player_init();
+
+ popup_available = true;
+
+ /* video_update (&scr_main, 0, 0, 0, 0, video_x, video_y); */
+
+ Common::strcpy_s(box_param.name, "*BOX.SS");
+
+ if (load_flag & KERNEL_STARTUP_CURSOR) {
+ /* Wipe palette & prepare for cursor */
+ pal_init(KERNEL_RESERVED_LOW_COLORS, KERNEL_RESERVED_HIGH_COLORS);
+ pal_white(master_palette);
+ if (video_mode == mcga_mode) {
+ mcga_setpal_range(&master_palette, 0, 4);
+ }
+
+ /* Load cursor sprite series */
+
+ cursor = sprite_series_load("*CURSOR.SS", PAL_MAP_RESERVED | PAL_MAP_DEFINE_RESERVED);
+ if (cursor == NULL) {
+#ifndef disable_error_check
+ error_code = ERROR_KERNEL_NO_CURSOR;
+#endif
+ goto done;
+ }
+
+ /* Activate main cursor sprite as mouse cursor */
+
+ cursor_last = cursor_id = (cursor->num_sprites > 1) ? 2 : 1;
+ mouse_cursor_sprite(cursor, cursor_id);
+ }
+
+ if (load_flag & KERNEL_STARTUP_VOCAB) {
+ vocab_load_active();
+ }
+
+ if (load_flag & KERNEL_STARTUP_INTERFACE) {
+ buffer_init_name(&scr_inter_orig, video_x, inter_size_y, "$scrintr");
+ if (scr_inter_orig.data == NULL) {
+ error_code = ERROR_NO_MORE_MEMORY;
+ goto done;
+ }
+ }
+
+ if (load_flag & KERNEL_STARTUP_POPUP) {
+ if (popup_box_load()) {
+ error_code = ERROR_KERNEL_NO_POPUP;
+ goto done;
+ }
+ }
+
+ error_flag = false;
+
+done:
+ if (load_flag & KERNEL_STARTUP_CURSOR_SHOW) mouse_show();
+ if (error_flag) {
+#ifndef disable_error_check
+ error_check_memory();
+ error_report(error_code, ERROR, MODULE_KERNEL, 0, 0);
+#endif
+ kernel_game_shutdown();
+ }
+ return (error_flag);
+}
+
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/core/kernel_4.cpp b/engines/mads/madsv2/core/kernel_4.cpp
new file mode 100644
index 00000000000..8f504714afe
--- /dev/null
+++ b/engines/mads/madsv2/core/kernel_4.cpp
@@ -0,0 +1,68 @@
+/*
+/* kernel_4.c by Brian Reynolds 6-Nov-91
+*/
+
+#include <string.h>
+
+#include <general.mac>
+#include <pal.h>
+#include <mouse.h>
+#include <sprite.h>
+#include <mem.h>
+#include <inter.h>
+#include <error.h>
+#include <video.h>
+#include <mcga.h>
+#include <sprite.h>
+#include <popup.h>
+
+#include "kernel.mac"
+#include "kernel_1.h"
+
+
+#pragma optimize ("weglt", on)
+
+
+/*
+/* kernel_section_shutdown()
+/*
+/* Section level system shutdown.
+*/
+void fastcall kernel_section_shutdown(void)
+{
+ ;
+}
+
+
+/*
+/* kernel_section_startup()
+/*
+/* Section level system startup.
+*/
+int fastcall kernel_section_startup (int new_section)
+{
+ int error_flag = true;
+ #ifndef disable_error_check
+ int error_code = 0;
+ #endif
+
+ /* Make note of new section number */
+
+ previous_section = section_id;
+ section_id = new_section;
+
+ error_flag = false;
+
+done:
+ /*
+ if (error_flag) {
+ #ifndef disable_error_check
+ error_check_memory ();
+ error_report (error_code, ERROR, MODULE_KERNEL, new_section, 0);
+ #endif
+ kernel_section_shutdown();
+ }
+ */
+ return (error_flag);
+}
+
diff --git a/engines/mads/madsv2/core/kernel_5.cpp b/engines/mads/madsv2/core/kernel_5.cpp
new file mode 100644
index 00000000000..a09d6904f85
--- /dev/null
+++ b/engines/mads/madsv2/core/kernel_5.cpp
@@ -0,0 +1,276 @@
+/*
+/* kernel_5.c by Brian Reynolds 7-Nov-91
+*/
+
+#include <string.h>
+
+#include <general.mac>
+
+#include <matte.h>
+#include <inter.h>
+#include <mem.h>
+#include <buffer.h>
+#include <room.h>
+#include <pal.h>
+#include <error.h>
+#include <anim.h>
+#include <vocab.h>
+#include <timer.h>
+#include <mouse.h>
+#include <video.h>
+#include <mcga.h>
+#include <rail.h>
+#include <cycle.h>
+#include <tile.h>
+#include <sprite.h>
+#include <popup.h>
+
+#include "kernel.mac"
+#include "kernel_1.h"
+#include "kernel_2.h"
+#include "kernel_8.h"
+#include "kernel_d.h"
+#include "kernel_o.h"
+
+
+#pragma optimize ("weglt", on)
+
+
+/*
+/* kernel_room_shutdown()
+/*
+/* Room level system shutdown.
+*/
+void fastcall kernel_room_shutdown (void)
+{
+ inter_deallocate_objects();
+
+ /* Dump all active series, followed by the interface animation */
+
+ /*
+ if (inter_anim != NULL) {
+ anim_unload ((AnimPtr)inter_anim);
+ buffer_free (&scr_inter_orig);
+ mem_free (inter_anim);
+ inter_anim = NULL;
+ } else {
+ if (scr_inter_orig.data != NULL) {
+ buffer_free (&scr_inter_orig);
+ }
+ }
+ */
+
+ /* Dump the vocabulary list */
+ /* vocab_unload_active(); */
+
+ /* Dump the room hot spots */
+
+ if (room_spots != NULL) {
+ mem_free (room_spots);
+ room_spots = NULL;
+ room_num_spots = 0;
+ }
+
+ /* Remove our palette shadowing list */
+
+ pal_activate_shadow (NULL);
+
+ /* Dump the picture & attribute buffers, along with the room header */
+
+ if (room != NULL) {
+ room_unload (room,
+ &scr_orig,
+ &scr_depth,
+ &scr_walk,
+ &scr_special,
+ &picture_map,
+ &depth_map);
+ room = NULL;
+ }
+
+ /*
+ sprite_free (&box_param.menu, true);
+ sprite_free (&box_param.logo, true);
+ sprite_free (&box_param.series, true);
+ */
+}
+
+
+int fastcall kernel_room_startup (int new_room, int initial_variant, char *interface, int new_palette)
+{
+ int error_flag = true;
+ int load_flags;
+ #ifndef disable_error_check
+ int error_code = 0;
+ int error_data = 0;
+ #endif
+
+ /* Make a note of the new room number & variant */
+
+ previous_room = room_id;
+ room_id = new_room;
+ room_variant = initial_variant;
+
+ /* Start a brand new palette, reserving the proper # of colors */
+
+ if (new_palette) pal_init (KERNEL_RESERVED_LOW_COLORS, KERNEL_RESERVED_HIGH_COLORS);
+
+ pal_white (master_palette);
+
+ /* Load up popup box frame */
+
+ /*
+ if (popup_box_load()) {
+ error_code = ERROR_KERNEL_NO_POPUP;
+ goto done;
+ }
+ */
+
+ /* Initialize the matteing system */
+
+ matte_init (false);
+
+ /* Initialize graphics sequence data structures */
+
+ kernel_seq_init();
+ kernel_message_init();
+
+ /* Activate the main shadow list */
+
+ pal_activate_shadow (&kernel_shadow_main);
+
+ /* Load header, picture, and attribute screen for this room */
+
+ load_flags = ROOM_LOAD_HARD_SHADOW;
+ if (kernel.translating) load_flags |= ROOM_LOAD_TRANSLATE;
+
+ room = room_load (room_id, room_variant, NULL,
+ &scr_orig,
+ &scr_depth,
+ &scr_walk,
+ &scr_special,
+ &picture_map,
+ &depth_map,
+ &picture_resource,
+ &depth_resource,
+ tile_picture_handle,
+ tile_attribute_handle,
+ load_flags);
+ if (room == NULL) {
+ #ifndef disable_error_check
+ error_data = room_load_error;
+ error_code = ERROR_KERNEL_NO_ROOM;
+ #endif
+ goto done;
+ }
+
+ tile_pan (&picture_map, picture_view_x, picture_view_y);
+ tile_pan (&depth_map, picture_view_x, picture_view_y);
+
+ /* Set up color cycling table for this room */
+
+ cycle_init (&room->cycle_list, false);
+
+ /* Initialize rail-system parameters for this room */
+
+ rail_num_nodes = room->num_rails + 2;
+ rail_base = (byte *) &room->rail[0];
+
+ rail_connect_all_nodes();
+
+ /* Load up the room's hotspot table */
+
+ room_spots = room_load_hotspots (room_id, &room_num_spots);
+ if (room_spots == NULL) {
+ #ifndef disable_error_check
+ error_code = ERROR_KERNEL_NO_HOTSPOTS;
+ #endif
+ goto done;
+ }
+
+ /* Load the necessary part of the vocabulary list */
+ /*
+ if (kernel_load_vocab()) {
+ #ifndef disable_error_check
+ error_code = ERROR_KERNEL_NO_VOCAB;
+ #endif
+ goto done;
+ }
+ */
+
+ /* Load up an interface animation w/ background */
+
+ /* scr_inter_orig.data = NULL; */
+
+ /*
+ pal_activate_shadow (&kernel_shadow_inter);
+
+ load_flags = PAL_MAP_RESERVED | ANIM_LOAD_BACKGROUND;
+ if (kernel.translating) load_flags |= ANIM_LOAD_TRANSLATE;
+ if (!inter_animation_running) load_flags |= ANIM_LOAD_BACK_ONLY;
+
+ inter_anim = (AnimInterPtr) anim_load (interface,
+ &scr_inter_orig, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL, load_flags);
+ if (inter_anim == NULL) {
+ #ifndef disable_error_check
+ error_code = ERROR_KERNEL_NO_INTERFACE;
+ strcpy (error_string, interface);
+ #endif
+ goto done;
+ }
+
+ if (!inter_anim->num_series) {
+ mem_free (inter_anim);
+ inter_anim = NULL;
+ }
+
+ pal_activate_shadow (&kernel_shadow_main);
+ */
+
+ inter_anim = NULL;
+
+ /* Make preliminary scaling computations */
+
+ kernel_room_bound_dif = room->front_y - room->back_y;
+ kernel_room_scale_dif = room->front_scale - room->back_scale;
+
+ /* Initialize the graphics image lists */
+
+ image_marker = 1;
+ image_list[0].flags = IMAGE_REFRESH;
+ image_list[0].segment_id = KERNEL_SEGMENT_SYSTEM;
+
+ /* Set up graphics window locations */
+
+ viewing_at_y = 0;
+ inter_viewing_at_y = inter_base_y;
+
+ /* Mark the boundary between interface and room sprite series */
+
+ kernel_room_series_marker = series_list_marker;
+
+ /* Set up interface background screen */
+
+ kernel_set_interface_mode (inter_input_mode);
+
+ /* Mouse cursor on */
+
+ while ((char)mouse_showing > 0) mouse_show();
+
+ inter_allocate_objects();
+
+ error_flag = false;
+
+done:
+ if (error_flag) {
+ #ifndef disable_error_check
+ error_check_memory();
+ error_report (error_code, ERROR, MODULE_KERNEL, room_id, error_data);
+ #endif
+ kernel_room_shutdown();
+ }
+ return (error_flag);
+}
diff --git a/engines/mads/madsv2/core/kernel_6.cpp b/engines/mads/madsv2/core/kernel_6.cpp
new file mode 100644
index 00000000000..950ae7e05b1
--- /dev/null
+++ b/engines/mads/madsv2/core/kernel_6.cpp
@@ -0,0 +1,61 @@
+/*
+/* kernel_6.c by Brian Reynolds 7-Nov-91
+*/
+
+#include <string.h>
+
+#include <general.mac>
+#include <matte.h>
+#include <sprite.h>
+#include <mem.h>
+#include <error.h>
+#include <pal.h>
+#include <mcga.h>
+
+#include "kernel.mac"
+#include "kernel_1.h"
+
+#pragma optimize ("weglt", on)
+
+/*
+/* kernel_unload_all_series(void)
+/*
+/* Unloads all room series.
+*/
+void fastcall kernel_unload_all_series(void)
+{
+ int count;
+
+ /* Unload all series (but don't unload those for the interface background) */
+
+ for (count = series_list_marker - 1; count >= kernel_room_series_marker; count--) {
+ if (series_user[count] > 1) series_user[count] = 1;
+ matte_deallocate_series (count, true);
+ }
+}
+
+
+/*
+/* kernel_load_series()
+/*
+/* Loads a sprite series for the room.
+*/
+int fastcall kernel_load_series (char *name, int load_flags)
+{
+ int handle = -2;
+
+ if (kernel.translating) load_flags |= SPRITE_LOAD_TRANSLATE;
+
+ handle = matte_load_series (name, load_flags, 0);
+
+done:
+ if ((handle < 0) && !kernel_ok_to_fail_load) {
+ #ifndef disable_error_check
+ strcpy (error_string, name);
+ error_report (ERROR_SERIES_LOAD_FAILED, WARNING, MODULE_KERNEL, handle, sprite_error);
+ #endif
+ }
+
+ return (handle);
+}
+
diff --git a/engines/mads/madsv2/core/kernel_6.h b/engines/mads/madsv2/core/kernel_6.h
new file mode 100644
index 00000000000..52b0dcdc27f
--- /dev/null
+++ b/engines/mads/madsv2/core/kernel_6.h
@@ -0,0 +1,35 @@
+/* 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 MADS_CORE_KERNEL_6_H
+#define MADS_CORE_KERNEL_6_H
+
+#include "mads/madsv2/core/general.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+extern void kernel_unload_all_series();
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/kernel_7.cpp b/engines/mads/madsv2/core/kernel_7.cpp
new file mode 100644
index 00000000000..d1883fc57ad
--- /dev/null
+++ b/engines/mads/madsv2/core/kernel_7.cpp
@@ -0,0 +1,60 @@
+/*
+/* kernel_7.c by Brian Reynolds 14-Nov-91
+*/
+
+#include <general.mac>
+#include <inter.h>
+#include <hspot.h>
+#include <error.h>
+#include "kernel.mac"
+#include "kernel_1.h"
+
+
+#pragma optimize ("weglt", on)
+/*
+/* kernel_flip_hotspot()
+/*
+/* Toggles an interface hotspot (referenced by its vocabulary word)
+/* on or off. Hotspots that are off do not interact with the mouse
+/* cursor.
+*/
+void fastcall kernel_flip_hotspot (int vocab_code, int active)
+{
+ int count;
+
+ for (count = 0; count < room_num_spots; count++) {
+ if (room_spots[count].vocab == vocab_code) {
+ room_spots[count].active = (byte) active;
+ hspot_toggle(STROKE_INTERFACE, count, active);
+ }
+ }
+}
+
+
+
+/*
+/* kernel_flip_hotspot()
+/*
+/* Toggles an interface hotspot (referenced by its vocabulary word)
+/* on or off. Hotspots that are off do not interact with the mouse
+/* cursor.
+/*
+/* Only hotspots which contain the point (X, Y) are affected.
+*/
+void fastcall kernel_flip_hotspot_loc (int vocab_code, int active, int x, int y)
+{
+ int count;
+
+ for (count = 0; count < room_num_spots; count++) {
+ if (room_spots[count].vocab == vocab_code) {
+ if ((x >= room_spots[count].ul_x) &&
+ (x <= room_spots[count].lr_x) &&
+ (y >= room_spots[count].ul_y) &&
+ (y <= room_spots[count].lr_y)) {
+ room_spots[count].active = (byte) active;
+ hspot_toggle(STROKE_INTERFACE, count, active);
+ }
+ }
+ }
+}
+
diff --git a/engines/mads/madsv2/core/kernel_8.cpp b/engines/mads/madsv2/core/kernel_8.cpp
new file mode 100644
index 00000000000..0ba69b8f422
--- /dev/null
+++ b/engines/mads/madsv2/core/kernel_8.cpp
@@ -0,0 +1,466 @@
+/* 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 "mads/madsv2/core/general.h"
+#include "mads/madsv2/core/anim.h"
+#include "mads/madsv2/core/matte.h"
+#include "mads/madsv2/core/error.h"
+#include "mads/madsv2/core/player.h"
+#include "mads/madsv2/core/sprite.h"
+#include "mads/madsv2/core/attr.h"
+
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/kernel_1.h"
+#include "mads/madsv2/core/kernel_f.h"
+#include "mads/madsv2/core/kernel_9.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+Sequence sequence_list[KERNEL_MAX_SEQUENCES];
+
+void kernel_seq_init(void) {
+ int count;
+
+ for (count = 0; count < KERNEL_MAX_SEQUENCES; count++) {
+ sequence_list[count].active_flag = false;
+ sequence_list[count].dynamic_hotspot = -1;
+ }
+}
+
+int kernel_seq_add(int series_id, int mirror, int initial_sprite,
+ int low_sprite, int high_sprite, int loop_mode, int loop_direction,
+ int depth, int scale, int auto_locating, int x, int y,
+ word ticks, word interval_ticks, word start_ticks, int expire) {
+ int result = -1;
+ int id = -1;
+ int found = false;
+ int count;
+
+ for (count = 0; !found && (count < KERNEL_MAX_SEQUENCES); count++) {
+ id = count;
+ found = !sequence_list[count].active_flag;
+ }
+
+ if (!found) {
+#if !defined(disable_error_check)
+ error_report(ERROR_SEQUENCE_LIST_FULL, WARNING, MODULE_KERNEL, KERNEL_MAX_SEQUENCES, 0);
+#endif
+ goto done;
+ }
+
+ if (low_sprite <= 0) {
+ low_sprite = 1;
+ }
+
+ if (high_sprite <= 0) {
+ high_sprite = series_list[series_id]->num_sprites;
+ }
+
+ if (high_sprite == low_sprite) {
+ loop_direction = 0;
+ }
+
+ sequence_list[id].active_flag = true;
+ sequence_list[id].series_id = (byte)series_id;
+ sequence_list[id].mirror = (byte)mirror;
+ sequence_list[id].sprite = initial_sprite;
+ sequence_list[id].start_sprite = low_sprite;
+ sequence_list[id].end_sprite = high_sprite;
+ sequence_list[id].loop_mode = loop_mode;
+ sequence_list[id].loop_direction = loop_direction;
+ sequence_list[id].depth = (byte)depth;
+ sequence_list[id].scale = (byte)scale;
+ sequence_list[id].auto_locating = (byte)auto_locating;
+ sequence_list[id].x = x;
+ sequence_list[id].y = y;
+ sequence_list[id].ticks = ticks;
+ sequence_list[id].interval_ticks = interval_ticks;
+ sequence_list[id].base_time = kernel.clock + start_ticks;
+ sequence_list[id].expire = (byte)expire;
+ sequence_list[id].expired = false;
+
+ sequence_list[id].motion = 0;
+ sequence_list[id].dynamic_hotspot = -1;
+
+ sequence_list[id].num_triggers = 0;
+ sequence_list[id].trigger_dest = (byte)kernel.trigger_setup_mode;
+
+ for (count = 0; count < 3; count++) {
+ sequence_list[id].trigger_words[count] = player2.words[count];
+ }
+
+ sequence_list[id].last_image.flags = -1;
+
+ result = id;
+
+done:
+ return result;
+}
+
+int kernel_seq_forward(int series_id, int mirror, word ticks,
+ word interval_ticks, word start_ticks, int expire) {
+ int depth;
+ SpritePtr sprite;
+
+ sprite = &series_list[series_id]->index[0];
+
+ depth = attr_depth(&depth_map,
+ sprite->x + (sprite->xs >> 1),
+ sprite->y + (sprite->ys >> 1)) - 1;
+
+ return kernel_seq_add(series_id, mirror, 1, 0, 0, AA_LINEAR, 1,
+ depth, 100, true, 0, 0, ticks, interval_ticks,
+ start_ticks, expire);
+}
+
+int kernel_seq_forward_scroll(int series_id, int mirror, word ticks,
+ word interval_ticks, word start_ticks, int expire) {
+ // TODO: depth isn't initialized?
+ int depth = 0;
+ SpritePtr sprite;
+
+ sprite = &series_list[series_id]->index[0];
+
+ return kernel_seq_add(series_id, mirror, 1, 0, 0, AA_LINEAR, 1,
+ depth, 100, true, 0, 0, ticks, interval_ticks,
+ start_ticks, expire);
+}
+
+int kernel_seq_pingpong(int series_id, int mirror, word ticks,
+ word interval_ticks, word start_ticks, int expire) {
+ int depth;
+ SpritePtr sprite;
+
+ sprite = &series_list[series_id]->index[0];
+
+ depth = attr_depth(&depth_map,
+ sprite->x + (sprite->xs >> 1),
+ sprite->y + (sprite->ys >> 1)) - 1;
+
+ return kernel_seq_add(series_id, mirror, 1, 0, 0, AA_PINGPONG, 1,
+ depth, 100, true, 0, 0, ticks, interval_ticks,
+ start_ticks, expire);
+}
+
+
+int kernel_seq_pingpong_scroll(int series_id, int mirror, word ticks,
+ word interval_ticks, word start_ticks, int expire) {
+ // TODO: depth isn't initialized?
+ int depth = 0;
+ SpritePtr sprite;
+
+ sprite = &series_list[series_id]->index[0];
+
+ return kernel_seq_add(series_id, mirror, 1, 0, 0, AA_PINGPONG, 1,
+ depth, 100, true, 0, 0, ticks, interval_ticks,
+ start_ticks, expire);
+}
+
+int kernel_seq_backward(int series_id, int mirror, word ticks,
+ word interval_ticks, word start_ticks, int expire) {
+ int depth;
+ SpritePtr sprite;
+
+ sprite = &series_list[series_id]->index[0];
+
+ depth = attr_depth(&depth_map,
+ sprite->x + (sprite->xs >> 1),
+ sprite->y + (sprite->ys >> 1)) - 1;
+
+ return kernel_seq_add(series_id, mirror,
+ series_list[series_id]->num_sprites,
+ 0, 0, AA_LINEAR, -1, depth, 100, true, 0, 0,
+ ticks, interval_ticks, start_ticks, expire);
+}
+
+int kernel_seq_backward_scroll(int series_id, int mirror,
+ word ticks, word interval_ticks, word start_ticks, int expire) {
+ // TODO: depth isn't initialized?
+ int depth = 0;
+ SpritePtr sprite;
+
+ sprite = &series_list[series_id]->index[0];
+
+ return kernel_seq_add(series_id, mirror,
+ series_list[series_id]->num_sprites,
+ 0, 0, AA_LINEAR, -1, depth, 100, true, 0, 0,
+ ticks, interval_ticks, start_ticks, expire);
+}
+
+void kernel_synch(int slave_type, int slave_id, int master_type, int master_id) {
+ long master_time;
+
+ switch (master_type) {
+ case KERNEL_SERIES:
+ master_time = sequence_list[master_id].base_time;
+ break;
+
+ case KERNEL_ANIM:
+ master_time = kernel_anim[master_id].next_clock;
+ break;
+
+ case KERNEL_NOW:
+ master_time = kernel.clock + (long)master_id;
+ break;
+
+ case KERNEL_PLAYER:
+ default:
+ master_time = player.clock;
+ break;
+ }
+
+
+ switch (slave_type) {
+ case KERNEL_SERIES:
+ sequence_list[slave_id].base_time = master_time;
+ break;
+
+ case KERNEL_PLAYER:
+ player.clock = master_time;
+ break;
+
+ case KERNEL_ANIM:
+ kernel_anim[slave_id].next_clock = master_time;
+ break;
+ }
+}
+
+void kernel_player_expire(int sequence_id) {
+ sequence_list[sequence_id].expired = true;
+ sequence_list[sequence_id].base_time = player.clock;
+}
+
+void kernel_seq_depth(int sequence_id, int depth) {
+ sequence_list[sequence_id].depth = (byte)depth;
+}
+
+void kernel_seq_scale(int sequence_id, int scale) {
+ sequence_list[sequence_id].scale = (byte)scale;
+}
+
+void kernel_seq_loc(int sequence_id, int x, int y) {
+ sequence_list[sequence_id].x = x;
+ sequence_list[sequence_id].y = y;
+ sequence_list[sequence_id].auto_locating = false;
+}
+
+void kernel_seq_motion(int sequence_id, int flags,
+ int delta_x_times_100, int delta_y_times_100) {
+ sequence_list[sequence_id].motion = (byte)(KERNEL_MOTION | flags);
+ sequence_list[sequence_id].sign_x = sgn(delta_x_times_100);
+ sequence_list[sequence_id].sign_y = sgn(delta_y_times_100);
+ sequence_list[sequence_id].delta_x = abs(delta_x_times_100);
+ sequence_list[sequence_id].delta_y = abs(delta_y_times_100);
+ sequence_list[sequence_id].accum_x = 0;
+ sequence_list[sequence_id].accum_y = 0;
+}
+
+void kernel_seq_range(int sequence_id, int first, int last) {
+ int num_sprites;
+ int from, unto;
+ SequencePtr sequence;
+
+ sequence = &sequence_list[sequence_id];
+
+ num_sprites = series_list[sequence->series_id]->num_sprites;
+
+ switch (first) {
+ case KERNEL_FIRST:
+ case KERNEL_DEFAULT:
+ from = 1;
+ break;
+ case KERNEL_LAST:
+ from = num_sprites;
+ break;
+ default:
+ from = first;
+ break;
+ }
+
+ switch (last) {
+ case KERNEL_FIRST:
+ unto = 1;
+ break;
+ case KERNEL_LAST:
+ case KERNEL_DEFAULT:
+ unto = num_sprites;
+ break;
+ default:
+ unto = last;
+ break;
+ }
+
+ sequence->start_sprite = from;
+ sequence->end_sprite = unto;
+
+ sequence->sprite = (sequence->loop_direction >= 0) ? from : unto;
+}
+
+int kernel_seq_stamp(int series_id, int mirror, int sprite) {
+ int id;
+
+ id = kernel_seq_forward(series_id, mirror, 32767, 0, 0, 0);
+ if (id >= 0) {
+ kernel_seq_range(id, sprite, sprite);
+ sequence_list[id].loop_direction = AA_STAMP;
+ }
+ return id;
+}
+
+int kernel_seq_stamp_scroll(int series_id, int mirror, int sprite) {
+ int id;
+
+ id = kernel_seq_forward_scroll(series_id, mirror, 32767, 0, 0, 0);
+ if (id >= 0) {
+ kernel_seq_range(id, sprite, sprite);
+ sequence_list[id].loop_direction = AA_STAMP;
+ }
+ return id;
+}
+
+int kernel_seq_trigger(int sequence_id, int trigger_type,
+ int trigger_sprite, int trigger_code) {
+ int error_code = true;
+ int id;
+ SequencePtr sequence;
+
+ sequence = &sequence_list[sequence_id];
+
+ if (sequence->num_triggers >= KERNEL_MAX_TRIGGERS) goto done;
+
+ id = sequence->num_triggers++;
+
+ sequence->trigger_type[id] = (byte)trigger_type;
+ sequence->trigger_sprite[id] = trigger_sprite;
+ sequence->trigger_code[id] = (byte)trigger_code;
+
+ error_code = false;
+
+done:
+ return error_code;
+}
+
+int kernel_timing_trigger(int ticks, int trigger_code) {
+ int id = -1;
+ int found = false;
+ int count;
+
+ for (count = 0; !found && (count < KERNEL_MAX_SEQUENCES); count++) {
+ id = count;
+ found = !sequence_list[count].active_flag;
+ }
+
+ if (!found) {
+#if !defined(disable_error_check)
+ error_report(ERROR_SEQUENCE_LIST_FULL, WARNING, MODULE_KERNEL, KERNEL_MAX_SEQUENCES, 0);
+#endif
+ goto done;
+ }
+
+ sequence_list[id].active_flag = true;
+ sequence_list[id].series_id = KERNEL_SPECIAL_TIMING;
+
+ sequence_list[id].ticks = ticks;
+ sequence_list[id].interval_ticks = 0;
+ sequence_list[id].base_time = kernel.clock + ticks;
+ sequence_list[id].expire = 1;
+ sequence_list[id].expired = false;
+
+ sequence_list[id].num_triggers = 0;
+ sequence_list[id].trigger_dest = (byte)kernel.trigger_setup_mode;
+
+ for (count = 0; count < 3; count++) {
+ sequence_list[id].trigger_words[count] = player2.words[count];
+ }
+
+ kernel_seq_trigger(id, KERNEL_TRIGGER_EXPIRE, 0, trigger_code);
+
+done:
+ return id;
+}
+
+int kernel_seq_purge(int sequence_id) {
+ int count;
+ int purged_any = -1;
+
+ for (count = 0; count < (int)image_marker; count++) {
+ if (image_list[count].segment_id == (byte)sequence_id) {
+ image_list[count].flags = IMAGE_ERASE;
+ purged_any = count;
+ }
+ }
+
+ return purged_any;
+}
+
+void kernel_seq_full_update(void) {
+ int count, id;
+
+ for (count = 0; count < KERNEL_MAX_SEQUENCES; count++) {
+ if (sequence_list[count].active_flag) {
+ if ((int)(sequence_list[count].series_id) != KERNEL_SPECIAL_TIMING) {
+ id = matte_allocate_image();
+ if (id >= 0) {
+ if (sequence_list[count].last_image.flags >= 0) {
+ image_list[id] = sequence_list[count].last_image;
+ } else {
+ kernel_seq_image(&sequence_list[count], &image_list[id], count);
+ }
+ }
+ }
+ }
+ }
+}
+
+void kernel_seq_correction(long old_clock, long new_clock) {
+ int count;
+ SequencePtr sequence;
+
+ for (count = 0; count < KERNEL_MAX_SEQUENCES; count++) {
+ sequence = &sequence_list[count];
+ if (sequence->active_flag) {
+ sequence->base_time += (new_clock - old_clock);
+ }
+ }
+}
+
+void kernel_draw_to_background(int series_id, int sprite_id,
+ int x, int y, int depth, int scale) {
+ if (x == KERNEL_HOME) {
+ x = series_list[series_id]->index[sprite_id - 1].x;
+ }
+
+ if (y == KERNEL_HOME) {
+ y = series_list[series_id]->index[sprite_id - 1].y;
+ }
+
+ sprite_draw_3d_scaled_big(series_list[series_id],
+ sprite_id, &scr_orig, &scr_depth,
+ x - picture_map.pan_base_x,
+ y - picture_map.pan_base_y,
+ depth, scale, 0, 0);
+
+ matte_refresh_work();
+}
+
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/core/kernel_8.h b/engines/mads/madsv2/core/kernel_8.h
new file mode 100644
index 00000000000..180f337a132
--- /dev/null
+++ b/engines/mads/madsv2/core/kernel_8.h
@@ -0,0 +1,79 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef MADS_CORE_KERNEL_8_H
+#define MADS_CORE_KERNEL_8_H
+
+#include "mads/madsv2/core/kernel.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+
+extern Sequence sequence_list[KERNEL_MAX_SEQUENCES];
+
+extern void kernel_seq_init(void);
+
+extern int kernel_seq_add(int series_id, int mirror,
+ int initial_sprite, int low_sprite, int high_sprite, int loop_mode,
+ int loop_direction, int depth, int scale, int auto_locating, int x, int y,
+ word ticks, word interval_ticks, word start_ticks, int expire);
+
+int fastcall kernel_seq_forward(int series_id, int mirror,
+ word ticks, word interval_ticks, word start_ticks, int expire);
+
+int fastcall kernel_seq_forward_scroll(int series_id, int mirror,
+ word ticks, word interval_ticks, word start_ticks, int expire);
+
+int fastcall kernel_seq_pingpong(int series_id, int mirror,
+ word ticks, word interval_ticks, word start_ticks, int expire);
+
+int fastcall kernel_seq_pingpong_scroll(int series_id, int mirror,
+ word ticks, word interval_ticks, word start_ticks, int expire);
+
+int fastcall kernel_seq_backward(int series_id, int mirror,
+ word ticks, word interval_ticks, word start_ticks, int expire);
+
+int fastcall kernel_seq_backward_scroll(int series_id, int mirror,
+ word ticks, word interval_ticks, word start_ticks, int expire);
+
+int fastcall kernel_seq_trigger(int sequence_id,
+ int trigger_type, int trigger_sprite, int trigger_code);
+
+extern void kernel_seq_loc(int sequence_id, int x, int y);
+extern void kernel_seq_depth(int sequence_id, int depth);
+extern void kernel_seq_scale(int sequence_id, int scale);
+
+
+extern int kernel_seq_purge(int sequence_id);
+
+extern void kernel_seq_full_update(void);
+
+extern void kernel_synch(int slave_type, int slave_id,
+ int master_type, int master_id);
+
+extern void kernel_draw_to_background(int series_id, int sprite_id,
+ int x, int y, int depth, int scale);
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/kernel_9.cpp b/engines/mads/madsv2/core/kernel_9.cpp
new file mode 100644
index 00000000000..99f0975593a
--- /dev/null
+++ b/engines/mads/madsv2/core/kernel_9.cpp
@@ -0,0 +1,252 @@
+/*
+/* kernel_9.c by Brian Reynolds 16-May-92
+*/
+
+#include <stdlib.h>
+
+#include <general.mac>
+#include <anim.mac>
+#include <matte.h>
+#include <error.h>
+#include <player.h>
+#include <sprite.h>
+#include <attr.h>
+
+#include "kernel.mac"
+#include "kernel_1.h"
+#include "kernel_8.h"
+#include "kernel_c.h"
+#include "kernel_f.h"
+
+#pragma optimize ("weglt", on)
+
+
+void fastcall kernel_seq_delete (int sequence_id)
+{
+ if (sequence_list[sequence_id].active_flag) {
+ if (sequence_list[sequence_id].dynamic_hotspot >= 0) {
+ kernel_delete_dynamic(sequence_list[sequence_id].dynamic_hotspot);
+ }
+ }
+
+ sequence_list[sequence_id].active_flag = false;
+
+ if (!sequence_list[sequence_id].expired) {
+ kernel_reconstruct_screen (-1);
+ } else {
+ kernel_seq_purge (sequence_id);
+ }
+}
+
+
+void fastcall kernel_seq_image (SequencePtr sequence, ImagePtr image, int sequence_id)
+{
+ image->flags = series_list[sequence->series_id]->delta_series ? IMAGE_DELTA : IMAGE_UPDATE;
+ image->segment_id = (byte) sequence_id;
+ image->series_id = sequence->series_id;
+ image->sprite_id = sequence->sprite | (sequence->mirror ? MIRROR_MASK : 0);
+
+ image->depth = sequence->depth;
+ image->scale = sequence->scale;
+
+ if (!sequence->auto_locating) {
+ image->x = sequence->x;
+ image->y = sequence->y;
+ } else {
+ image->x = series_list[image->series_id]->index[sequence->sprite - 1].x;
+ image->y = series_list[image->series_id]->index[sequence->sprite - 1].y;
+ }
+
+ sequence->last_image = *image;
+}
+
+
+
+static int near fastcall kernel_seq_update (SequencePtr sequence, int sequence_id)
+{
+ int id;
+ int count;
+ int cycling = false;
+ int trigger = -1;
+ int x, y, xs, ys;
+ int x1, y1;
+ int x2, y2;
+ int purged;
+ ImagePtr image;
+
+ purged = kernel_seq_purge(sequence_id);
+
+ if (purged >= 0) {
+ if (sequence->loop_direction == AA_STAMP) {
+ image_list[purged].flags = IMAGE_STATIC;
+ goto done;
+ }
+ }
+
+ if (sequence->expired) {
+ kernel_seq_delete (sequence_id);
+ goto done;
+ } else {
+ if (sequence->series_id == KERNEL_SPECIAL_TIMING) {
+ sequence->expired = true;
+ goto triggers;
+ }
+
+ id = matte_allocate_image();
+ if (id < 0) {
+ sequence->expired = true;
+ goto triggers;
+ }
+
+ image = &image_list[id];
+
+ kernel_seq_image (sequence, image, sequence_id);
+
+ }
+
+ if (sequence->motion ||
+ (sequence->dynamic_hotspot >= 0)) {
+ xs = (series_list[sequence->series_id]->index[sequence->sprite - 1].xs * sequence->scale) / 200;
+ ys = (series_list[sequence->series_id]->index[sequence->sprite - 1].ys * sequence->scale) / 100;
+ x = image->x;
+ y = image->y;
+
+ if (sequence->motion & KERNEL_MOTION) {
+ sequence->accum_x += sequence->delta_x;
+ while (sequence->accum_x >= 100) {
+ sequence->accum_x -= 100;
+ sequence->x += sequence->sign_x;
+ }
+ sequence->accum_y += sequence->delta_y;
+ while (sequence->accum_y >= 100) {
+ sequence->accum_y -= 100;
+ sequence->y += sequence->sign_y;
+ }
+
+ if (sequence->motion & KERNEL_MOTION_OFFSCREEN) {
+ if ( (((x + xs) < 0) || ((x - xs) >= picture_map.total_x_size)) ||
+ ((y < 0) || ((y - ys) >= picture_map.total_y_size))) {
+ cycling = true;
+ sequence->expired = true;
+ }
+ }
+ }
+
+ if (sequence->dynamic_hotspot >= 0) {
+ x1 = x - xs;
+ x2 = x + xs;
+ y1 = y - ys;
+ y2 = y;
+ x1 = max (0, x1);
+ y1 = max (0, y1);
+ x2 = min (picture_map.total_x_size - 1, x2);
+ y2 = min (picture_map.total_y_size - 1, y2);
+ kernel_dynamic_hot[sequence->dynamic_hotspot].x = x1;
+ kernel_dynamic_hot[sequence->dynamic_hotspot].y = y1;
+ kernel_dynamic_hot[sequence->dynamic_hotspot].xs= (x2 - x1) + 1;
+ kernel_dynamic_hot[sequence->dynamic_hotspot].ys= (y2 - y1) + 1;
+ kernel_dynamic_hot[sequence->dynamic_hotspot].valid = true;
+ kernel_dynamic_changed = true;
+ }
+ }
+
+ if (sequence->start_sprite != sequence->end_sprite) {
+ sequence->sprite += sequence->loop_direction;
+ }
+
+ if (sequence->sprite < sequence->start_sprite) {
+ cycling = true;
+ if (sequence->loop_mode == AA_PINGPONG) {
+ sequence->sprite = sequence->start_sprite + 1;
+ sequence->loop_direction = 1;
+ } else {
+ sequence->sprite = sequence->end_sprite;
+ }
+ } else if (sequence->sprite > sequence->end_sprite) {
+ cycling = true;
+ if (sequence->loop_mode == AA_PINGPONG) {
+ sequence->sprite = sequence->end_sprite - 1;
+ sequence->loop_direction = -1;
+ } else {
+ sequence->sprite = sequence->start_sprite;
+ }
+ }
+
+ if (cycling) {
+ if (sequence->expire) {
+ sequence->expire--;
+ if (!sequence->expire) {
+ sequence->expired = true;
+ }
+ }
+ }
+
+triggers:
+ for (count = 0; count < (int) sequence->num_triggers; count++) {
+ switch(sequence->trigger_type[count]) {
+ case KERNEL_TRIGGER_EXPIRE:
+ if (sequence->expired) trigger = count;
+ break;
+ case KERNEL_TRIGGER_LOOP:
+ if (cycling) trigger = count;
+ break;
+ case KERNEL_TRIGGER_SPRITE:
+ default:
+ if ((sequence->sprite == sequence->trigger_sprite[count]) ||
+ (sequence->trigger_sprite[count] == 0)) {
+ trigger = count;
+ }
+ break;
+ }
+ }
+
+ if (trigger >= 0) {
+ kernel.trigger = sequence->trigger_code[trigger];
+ kernel.trigger_mode = sequence->trigger_dest;
+ if (kernel.trigger_mode != KERNEL_TRIGGER_DAEMON) {
+ for (count = 0; count < 3; count++) {
+ player2.words[count] = sequence->trigger_words[count];
+ }
+ }
+ }
+
+ if (sequence->series_id == KERNEL_SPECIAL_TIMING) {
+ sequence->active_flag = false;
+ }
+
+done:
+ return (cycling);
+}
+
+
+
+void fastcall kernel_seq_update_all (void)
+{
+ int count;
+ int ok_to_update;
+ SequencePtr sequence;
+
+ for (count = 0; (count < KERNEL_MAX_SEQUENCES); count++) {
+ sequence = &sequence_list[count];
+ if (sequence->active_flag) {
+ if (kernel.clock >= sequence->base_time) {
+ ok_to_update = (kernel.fx || !kernel.trigger ||
+ sequence->expired || !sequence->num_triggers);
+ if (ok_to_update) {
+ sequence->base_time = kernel.clock + sequence->ticks;
+ if (kernel_seq_update (sequence, count)) {
+ sequence->base_time += sequence->interval_ticks;
+ }
+ }
+ }
+ }
+ }
+}
+
+
+
+
+
+
+
+
diff --git a/engines/mads/madsv2/core/kernel_9.h b/engines/mads/madsv2/core/kernel_9.h
new file mode 100644
index 00000000000..a5b5ff6913b
--- /dev/null
+++ b/engines/mads/madsv2/core/kernel_9.h
@@ -0,0 +1,36 @@
+/* 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 MADS_CORE_KERNEL_9_H
+#define MADS_CORE_KERNEL_9_H
+
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/image.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+extern void kernel_seq_image(SequencePtr sequence, ImagePtr image, int sequence_id);
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/kernel_a.cpp b/engines/mads/madsv2/core/kernel_a.cpp
new file mode 100644
index 00000000000..2893209bd71
--- /dev/null
+++ b/engines/mads/madsv2/core/kernel_a.cpp
@@ -0,0 +1,26 @@
+/*
+/* kernel_a.c by Brian Reynolds 8-Apr-92
+*/
+
+#include <general.mac>
+#include <player.h>
+#include <matte.h>
+#include <timer.h>
+#include "kernel.mac"
+#include "kernel_8.h"
+
+#pragma optimize ("weglt", on)
+
+
+void fastcall kernel_seq_player (int sequence_id, int synch_me)
+{
+ kernel_seq_loc (sequence_id, player.x, player.y + ((player.center_of_gravity * player.scale) / 100));
+ kernel_seq_depth (sequence_id, player.depth);
+ kernel_seq_scale (sequence_id, player.scale);
+
+ if (synch_me) {
+ kernel_synch (KERNEL_SERIES, sequence_id,
+ KERNEL_PLAYER, 0);
+ }
+}
+
diff --git a/engines/mads/madsv2/core/kernel_b.cpp b/engines/mads/madsv2/core/kernel_b.cpp
new file mode 100644
index 00000000000..71c9db8e88a
--- /dev/null
+++ b/engines/mads/madsv2/core/kernel_b.cpp
@@ -0,0 +1,191 @@
+/* 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 "mads/madsv2/core/general.h"
+#include "mads/madsv2/core/anim.h"
+#include "mads/madsv2/core/player.h"
+#include "mads/madsv2/core/matte.h"
+#include "mads/madsv2/core/mem.h"
+#include "mads/madsv2/core/error.h"
+#include "mads/madsv2/core/buffer.h"
+#include "mads/madsv2/core/digi.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/kernel_1.h"
+#include "mads/madsv2/core/kernel_c.h"
+#include "mads/madsv2/core/kernel_k.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+int stop_speech_on_run_anim = true;
+
+void kernel_animation_init(void) {
+ int count;
+
+ for (count = 0; count < KERNEL_MAX_ANIMATIONS; count++) {
+ kernel_anim[count].anim = NULL;
+ kernel_anim[count].cycled = false;
+ kernel_anim[count].repeat = false;
+ }
+}
+
+int kernel_run_animation(char *name, int trigger_code) {
+ int result = -1;
+ int found = -1;
+ int error_flag = true;
+ int count;
+ int load_flags;
+ int id;
+ long largest_block;
+
+
+ if (stop_speech_on_run_anim) {
+ digi_stop(1);
+ digi_stop(2);
+ digi_stop(3);
+ }
+
+ anim_error = -2;
+
+ for (count = 0; (found < 0) && (count < KERNEL_MAX_ANIMATIONS); count++) {
+ if (kernel_anim[count].anim == NULL) {
+ found = count;
+ }
+ }
+
+ if (found < 0) goto done;
+
+ load_flags = 0;
+ if (kernel.translating) load_flags |= ANIM_LOAD_TRANSLATE;
+ kernel_anim[found].anim = anim_load(name,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL, load_flags);
+ if (kernel_anim[found].anim == NULL) goto done;
+
+ kernel_anim[found].messages = 0;
+ kernel_anim[found].dynamic_hotspot = -1;
+
+ kernel_anim[found].sprite_loaded = -1;
+ if (kernel_anim[found].anim->misc_any_packed) {
+ kernel_anim[found].buffer_id = -1;
+ id = kernel_anim[found].anim->series_id[kernel_anim[found].anim->misc_packed_series];
+ memcpy(&largest_block, &series_list[id]->misc_largest_block, sizeof(long));
+ if (mem_get_avail() - 128 >= largest_block) {
+ mem_free(series_list[id]->arena);
+ series_list[id]->arena = (byte *)mem_get_name(largest_block * 2, "$arena$");
+ if (series_list[id]->arena == NULL) {
+ series_list[id]->arena = (byte *)mem_get_name(largest_block, "$arena$");
+ anim_error = -1;
+ if (series_list[id]->arena == NULL) goto done;
+ } else {
+ kernel_anim[found].buffer[0] = series_list[id]->arena;
+ kernel_anim[found].buffer[1] = (byte *)mem_normalize(series_list[id]->arena + largest_block);
+ kernel_anim[found].buffer_id = 0;
+ }
+ }
+ kernel_animation_get_sprite(found, 1);
+ }
+
+ if (kernel_mode == KERNEL_ACTIVE_CODE) kernel_new_palette();
+
+ kernel_anim[found].frame = 0;
+ kernel_anim[found].image = 0;
+ kernel_anim[found].next_clock = kernel.clock;
+
+ kernel_anim[found].view_changes = false;
+
+ kernel_anim[found].trigger_code = trigger_code;
+ kernel_anim[found].trigger_mode = kernel.trigger_setup_mode;
+ for (count = 0; count < 3; count++) {
+ kernel_anim[found].trigger_words[count] = player2.words[count];
+ }
+
+ for (count = 0; count < kernel_anim[found].anim->num_speech; count++) {
+ kernel_anim[found].anim->speech[count].flags = (word)-1;
+ }
+
+ error_flag = false;
+ result = found;
+
+ kernel_anim[found].last_frame = -1;
+
+done:
+ if (error_flag) {
+ if (found >= 0) kernel_abort_animation(found);
+#ifndef disable_error_check
+ Common::strcpy_s(error_string, name);
+ error_report(ERROR_KERNEL_NO_ANIMATION, WARNING, MODULE_KERNEL, trigger_code, anim_error);
+#endif
+ }
+
+ anim_error = 0;
+ return found;
+}
+
+/* run a talking animation */
+int kernel_run_animation_talk(char thing, int num, int trigger_code) {
+ Common::String test = "*talk_";
+ if (thing == 'r')
+ test += "r";
+ else if (thing == 'b')
+ test += "b";
+ else if (thing == 'e')
+ test += "e";
+
+ test += Common::String::format("%d", num);
+
+ return kernel_run_animation(test.c_str(), trigger_code);
+}
+
+/* run a displacement animation */
+int kernel_run_animation_disp(char thing, int num, int trigger_code) {
+ Common::String test = "*disp_";
+
+ if (thing == 'r')
+ test += "ru";
+ else if (thing == 'b')
+ test += "ab";
+ else if (thing == 'e')
+ test += "ed";
+
+ test += Common::String::format("%d", num);
+
+ return kernel_run_animation(test.c_str(), trigger_code);
+}
+
+/* run a writing anim (always edgar) */
+int kernel_run_animation_write(int trigger_code) {
+ int feedback;
+
+ feedback = kernel_run_animation("*write_e", trigger_code);
+ return feedback;
+}
+
+/* run a pointing animation (always abigail) */
+int kernel_run_animation_point(int num, int trigger_code) {
+ Common::String test = Common::String::format("*point_b%d", num);
+ return kernel_run_animation(test.c_str(), trigger_code);
+}
+
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/core/kernel_c.cpp b/engines/mads/madsv2/core/kernel_c.cpp
new file mode 100644
index 00000000000..3764843ea75
--- /dev/null
+++ b/engines/mads/madsv2/core/kernel_c.cpp
@@ -0,0 +1,506 @@
+/*
+/* kernel_c.c by Brian Reynolds 13-Jan-92
+*/
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <general.mac>
+
+#include <anim.h>
+#include <player.h>
+#include <matte.h>
+#include <mem.h>
+/* pl #include <sound.h> */
+#include <error.h>
+#include <buffer.h>
+#include <pal.h>
+#include <sprite.h>
+#include <config.h>
+#include <attr.h>
+#include <camera.h>
+
+#pragma optimize ("weglt", on)
+
+#include "kernel.mac"
+#include "kernel_1.h"
+#include "kernel_8.h"
+#include "kernel_d.h"
+#include "kernel_f.h"
+
+#define MESSAGE_COLOR_3 (((KERNEL_MESSAGE_COLOR_BASE_3 + 1) << 8) + KERNEL_MESSAGE_COLOR_BASE_3)
+
+
+
+
+
+void fastcall kernel_animation_get_sprite (int handle, int id)
+{
+ int series_id;
+ byte *pointer;
+
+ if (id != kernel_anim[handle].sprite_loaded) {
+ series_id = kernel_anim[handle].anim->series_id[kernel_anim[handle].anim->misc_packed_series];
+ if (kernel_anim[handle].buffer_id >= 0) {
+ pointer = kernel_anim[handle].buffer[kernel_anim[handle].buffer_id];
+ kernel_anim[handle].buffer_id = 1 - kernel_anim[handle].buffer_id;
+ } else {
+ pointer = series_list[series_id]->arena;
+ }
+ if (sprite_data_load(series_list[series_id], id, pointer)) {
+ error_report (ERROR_SPRITE_DATA_LOAD_FAILED, ERROR, MODULE_KERNEL, id, series_id);
+ }
+ kernel_anim[handle].sprite_loaded = id;
+ }
+}
+
+
+
+
+
+void fastcall kernel_reset_animation (int handle, int frame)
+{
+ if (kernel_anim[handle].anim != NULL) {
+ kernel_anim[handle].frame = frame;
+ kernel_anim[handle].image = 0;
+ kernel_anim[handle].doomed = false;
+ }
+}
+
+
+static void near fastcall kernel_hot_check (int hot, int id, int seg_id)
+{
+ int count;
+ int x, y, xs, ys;
+ int x1, y1, x2, y2;
+ byte scale;
+
+ for (count = 0; count < KERNEL_DYNAMIC_MAX_SEGMENTS; count++) {
+ if (seg_id == (int)kernel_dynamic_hot[hot].auto_segment[count]) {
+
+ scale = image_list[id].scale;
+ if (scale == IMAGE_UNSCALED) {
+ xs = series_list[image_list[id].series_id]->index[image_list[id].sprite_id - 1].xs;
+ ys = series_list[image_list[id].series_id]->index[image_list[id].sprite_id - 1].ys;
+ x = image_list[id].x;
+ y = image_list[id].y;
+ x1 = x;
+ y1 = y;
+ x2 = x + xs - 1;
+ y2 = y + ys - 1;
+ } else {
+ xs = (series_list[image_list[id].series_id]->index[image_list[id].sprite_id - 1].xs * image_list[id].scale) / 200;
+ ys = (series_list[image_list[id].series_id]->index[image_list[id].sprite_id - 1].ys * image_list[id].scale) / 100;
+ x = image_list[id].x;
+ y = image_list[id].y;
+ x1 = x - xs;
+ x2 = x + xs;
+ y1 = y - ys;
+ y2 = y;
+ }
+
+ if ((xs > 0) && (ys > 0)) {
+ x1 = max (0, x1);
+ y1 = max (0, y1);
+ x2 = min (picture_map.total_x_size - 1, x2);
+ y2 = min (picture_map.total_y_size - 1, y2);
+ xs = (x2 - x1) + 1;
+ ys = (y2 - y1) + 1;
+ if ((xs > 0) && (ys > 0)) {
+ kernel_dynamic_hot[hot].x = x1;
+ kernel_dynamic_hot[hot].y = y1;
+ kernel_dynamic_hot[hot].xs= xs;
+ kernel_dynamic_hot[hot].ys= ys;
+ kernel_dynamic_hot[hot].valid = true;
+ }
+ }
+ }
+ }
+}
+
+
+
+static void near fastcall kernel_process_animation (int handle, int asynchronous)
+{
+ int view_changed = false;
+ int image_base;
+ int count;
+ int match;
+ int id;
+ int clock_frame;
+ int hot, seg_id;
+ word temp1, temp2;
+
+ if (kernel_anim[handle].anim->misc_any_packed) {
+ id = -1;
+ match = kernel_anim[handle].anim->series_id[kernel_anim[handle].anim->misc_packed_series];
+ for (count = kernel_anim[handle].image;
+ (count < kernel_anim[handle].anim->num_images) &&
+ (kernel_anim[handle].anim->image[count].flags <= kernel_anim[handle].frame);
+ count++) {
+ if (kernel_anim[handle].anim->image[count].series_id == (byte)match) {
+ id = kernel_anim[handle].anim->image[count].sprite_id;
+ }
+ }
+ if (id >= 0) {
+ kernel_animation_get_sprite(handle, id);
+ }
+ }
+
+ if (kernel.clock < kernel_anim[handle].next_clock) goto done;
+
+ for (count = 0; count < (int) image_marker; count++) {
+ if (image_list[count].segment_id == (byte)(KERNEL_SEGMENT_ANIMATION + handle)) {
+ image_list[count].flags = IMAGE_ERASE;
+ }
+ }
+
+ kernel_anim[handle].cycled = false;
+ if (kernel_anim[handle].frame >= kernel_anim[handle].anim->num_frames) {
+ if (kernel_anim[handle].repeat) {
+ kernel_anim[handle].frame = 0;
+ kernel_anim[handle].image = 0;
+ kernel_anim[handle].cycled = true;
+ } else {
+ kernel_anim[handle].doomed = true;
+ goto done;
+ }
+ }
+
+ if (!asynchronous) {
+ if (kernel_anim[handle].anim->frame[kernel_anim[handle].frame].sound) {
+ /* pl sound_play(kernel_anim[handle].anim->frame[kernel_anim[handle].frame].sound); */
+ }
+
+ if ((kernel_anim[handle].anim->misc_peel_x != 0) || (kernel_anim[handle].anim->misc_peel_y != 0)) {
+ buffer_peel_horiz (&scr_orig, kernel_anim[handle].anim->misc_peel_x);
+ buffer_peel_vert (&scr_orig, kernel_anim[handle].anim->misc_peel_y, NULL, 0);
+ matte_refresh_work();
+ if (!kernel_allow_peel) error_report (ERROR_PEELING_DISABLED, ERROR, MODULE_KERNEL, handle, 0);
+ }
+
+ if (kernel_anim[handle].view_changes) {
+ if (kernel_anim[handle].anim->frame[kernel_anim[handle].frame].view_x != (word) picture_view_x) {
+ picture_view_x = kernel_anim[handle].anim->frame[kernel_anim[handle].frame].view_x;
+ view_changed = true;
+ }
+
+ if (kernel_anim[handle].anim->frame[kernel_anim[handle].frame].view_y != (word) picture_view_y) {
+ picture_view_y = kernel_anim[handle].anim->frame[kernel_anim[handle].frame].view_y;
+ view_changed = true;
+ }
+ }
+ }
+
+ if (view_changed) {
+ id = matte_allocate_image();
+ image_list[id].segment_id = KERNEL_SEGMENT_SYSTEM;
+ image_list[id].flags = IMAGE_REFRESH;
+ camera_jump_to (picture_view_x, picture_view_y);
+ }
+
+ image_base = image_marker;
+
+ hot = kernel_anim[handle].dynamic_hotspot;
+ if (hot >= 0) {
+ kernel_dynamic_hot[hot].x = 0;
+ kernel_dynamic_hot[hot].y = 0;
+ kernel_dynamic_hot[hot].xs= 0;
+ kernel_dynamic_hot[hot].ys= 0;
+ kernel_dynamic_hot[hot].valid = false;
+ kernel_dynamic_changed = true;
+ }
+
+ while ((kernel_anim[handle].image < kernel_anim[handle].anim->num_images) &&
+ (kernel_anim[handle].anim->image[kernel_anim[handle].image].flags <= kernel_anim[handle].frame)) {
+ if (kernel_anim[handle].anim->image[kernel_anim[handle].image].flags == kernel_anim[handle].frame) {
+ match = false;
+ for (count = 0; !match && (count < image_base); count++) {
+ if (image_list[count].segment_id == (byte)(KERNEL_SEGMENT_ANIMATION + handle)) {
+ if (_fmemcmp (&image_list[count].series_id,
+ &kernel_anim[handle].anim->image[kernel_anim[handle].image].series_id, 9) == 0) {
+ image_list[count].flags = 0;
+
+ if (hot >= 0) {
+ seg_id = kernel_anim[handle].anim->image[kernel_anim[handle].image].segment_id;
+ kernel_hot_check (hot, count, seg_id);
+ }
+
+ match = true;
+ }
+ }
+ }
+
+ if (!match) {
+ id = matte_allocate_image();
+ image_list[id] = kernel_anim[handle].anim->image[kernel_anim[handle].image];
+
+ seg_id = image_list[id].segment_id;
+
+ /* image_list[id].segment_id += KERNEL_SEGMENT_ANIMATION; */
+ image_list[id].segment_id = (byte)(KERNEL_SEGMENT_ANIMATION + handle);
+ image_list[id].flags = series_list[image_list[id].series_id]->delta_series ? IMAGE_DELTA : IMAGE_UPDATE;
+ /*
+ if (kernel_anim[handle].anim->misc_any_packed) {
+ if (image_list[id].series_id == (byte)kernel_anim[handle].anim->series_id[kernel_anim[handle].anim->misc_packed_series]) {
+ series_id = image_list[id].series_id;
+ sprite_data_load (series_list[series_id], image_list[id].sprite_id, series_list[series_id]->arena);
+ }
+ }
+ */
+
+ if (hot >= 0) {
+ kernel_hot_check (hot, id, seg_id);
+ }
+ }
+ }
+ kernel_anim[handle].image++;
+ }
+
+ for (count = 0; count < kernel_anim[handle].anim->num_speech; count++) {
+ if ((int)(kernel_anim[handle].anim->speech[count].flags) >= 0) {
+ if ((kernel_anim[handle].frame < kernel_anim[handle].anim->speech[count].first_frame) ||
+ (kernel_anim[handle].frame > kernel_anim[handle].anim->speech[count].last_frame)) {
+ kernel_message_delete (kernel_anim[handle].anim->speech[count].flags);
+ kernel_anim[handle].anim->speech[count].flags = -1;
+ kernel_anim[handle].messages--;
+ }
+ } else {
+ if ((kernel_anim[handle].frame >= kernel_anim[handle].anim->speech[count].first_frame) &&
+ (kernel_anim[handle].frame <= kernel_anim[handle].anim->speech[count].last_frame)) {
+
+ switch (kernel_anim[handle].messages) {
+ case 1:
+ temp1 = KERNEL_MESSAGE_COLOR_BASE_2;
+ break;
+
+ case 2:
+ temp1 = KERNEL_MESSAGE_COLOR_BASE;
+ break;
+
+ default:
+ temp1 = KERNEL_MESSAGE_COLOR_BASE_3;
+ break;
+ }
+
+ pal_change_color (temp1,
+ kernel_anim[handle].anim->speech[count].color[0].r,
+ kernel_anim[handle].anim->speech[count].color[0].g,
+ kernel_anim[handle].anim->speech[count].color[0].b);
+
+ pal_change_color (temp1 + 1,
+ kernel_anim[handle].anim->speech[count].color[1].r,
+ kernel_anim[handle].anim->speech[count].color[1].g,
+ kernel_anim[handle].anim->speech[count].color[1].b);
+
+ temp2 = ((temp1 + 1) << 8) + temp1;
+
+ kernel_anim[handle].anim->speech[count].flags =
+ kernel_message_add (kernel_anim[handle].anim->speech[count].text,
+ kernel_anim[handle].anim->speech[count].x,
+ kernel_anim[handle].anim->speech[count].y,
+ temp2, 9999999, 0, 0);
+
+ kernel_anim[handle].messages++;
+ }
+ }
+ }
+
+ kernel_anim[handle].last_frame = kernel_anim[handle].frame;
+ kernel_anim[handle].frame++;
+
+ if (!asynchronous) {
+ if (kernel_anim[handle].frame == kernel_anim[handle].anim->num_frames) {
+ if (kernel_anim[handle].trigger_code) {
+ kernel.trigger = kernel_anim[handle].trigger_code;
+ kernel.trigger_mode = kernel_anim[handle].trigger_mode;
+ if (kernel.trigger_mode != KERNEL_TRIGGER_DAEMON) {
+ for (count = 0; count < 3; count++) {
+ player2.words[count] = kernel_anim[handle].trigger_words[count];
+ }
+ }
+ }
+ }
+ }
+
+ clock_frame = min (kernel_anim[handle].frame, kernel_anim[handle].anim->num_frames - 1);
+ kernel_anim[handle].next_clock = kernel.clock + kernel_anim[handle].anim->frame[clock_frame].ticks;
+
+done:
+ ;
+}
+
+
+void fastcall kernel_process_all_animations (void)
+{
+ int count;
+ int ok_to_update;
+
+ for (count = 0; count < KERNEL_MAX_ANIMATIONS; count++) {
+ if (kernel_anim[count].anim != NULL) {
+ ok_to_update = (kernel.fx || !kernel.trigger ||
+ (kernel_anim[count].frame != kernel_anim[count].anim->num_frames - 1));
+ if (ok_to_update) {
+ kernel_process_animation (count, false);
+ }
+ }
+ }
+}
+
+
+void fastcall kernel_reconstruct_screen (int anim_handle)
+{
+ int count;
+ int player_found;
+ int old_frame;
+ long old_clock;
+
+ player_found = false;
+ for (count = 0; count < (int)image_marker; count++) {
+ if (image_list[count].flags >= 0) {
+ if (image_list[count].segment_id == KERNEL_SEGMENT_PLAYER) {
+ player_found = true;
+ }
+ }
+ }
+
+ image_marker = 0;
+ matte_refresh_work();
+ kernel_seq_full_update();
+
+ for (count = 0; count < KERNEL_MAX_ANIMATIONS; count++) {
+ if (!kernel_anim[count].doomed) {
+ if (kernel_anim[count].anim != NULL) {
+ if (count != anim_handle) {
+ if (kernel_anim[count].last_frame >= 0) {
+ old_frame = kernel_anim[count].frame;
+ old_clock = kernel_anim[count].next_clock;
+ kernel_anim[count].frame = kernel_anim[count].last_frame;
+ kernel_anim[count].image = 0;
+ kernel_anim[count].next_clock = kernel.clock;
+
+ kernel_process_animation (count, true);
+
+ kernel_anim[count].next_clock = old_clock;
+ kernel_anim[count].frame = old_frame;
+ kernel_anim[count].image = 0;
+ }
+ }
+ }
+ }
+ }
+
+ if (player.walker_visible && player_found) {
+ player.sprite_changed = true;
+ player_set_image();
+ }
+}
+
+
+
+
+
+
+void fastcall kernel_abort_animation (int handle)
+{
+ int count;
+ int old_frame;
+ long old_clock;
+
+ if (kernel_anim[handle].anim != NULL) {
+ if (!kernel_anim[handle].doomed) {
+
+ kernel_reconstruct_screen (handle);
+
+ /*
+ image_marker = 0;
+ matte_refresh_work();
+ kernel_seq_full_update();
+
+ for (count = 0; count < KERNEL_MAX_ANIMATIONS; count++) {
+ if (!kernel_anim[count].doomed) {
+ if (kernel_anim[count].anim != NULL) {
+ if (count != handle) {
+ if (kernel_anim[count].last_frame >= 0) {
+ old_frame = kernel_anim[count].frame;
+ old_clock = kernel_anim[count].next_clock;
+ kernel_anim[count].frame = kernel_anim[count].last_frame;
+ kernel_anim[count].image = 0;
+ kernel_anim[count].next_clock = kernel.clock;
+
+ kernel_process_animation (count, true);
+
+ kernel_anim[count].next_clock = old_clock;
+ kernel_anim[count].frame = old_frame;
+ kernel_anim[count].image = 0;
+ }
+ }
+ }
+ }
+ }
+
+ */
+ }
+
+ /*
+ if (player.walker_visible) {
+ player.sprite_changed = true;
+ player_set_image();
+ }
+ */
+
+ for (count = 0; count < kernel_anim[handle].anim->num_speech; count++) {
+ if ((int)(kernel_anim[handle].anim->speech[count].flags) >= 0) {
+ kernel_message_delete (kernel_anim[handle].anim->speech[count].flags);
+ }
+ }
+
+ if (kernel_anim[handle].dynamic_hotspot >= 0) {
+ kernel_delete_dynamic(kernel_anim[handle].dynamic_hotspot);
+ }
+
+ kernel_anim[handle].repeat = false;
+ anim_unload (kernel_anim[handle].anim);
+ kernel_anim[handle].anim = NULL;
+ }
+
+ kernel_anim[handle].doomed = false;
+
+ go_ahead_and_frag_the_palette();
+}
+
+
+void fastcall kernel_abort_all_animations (void)
+{
+ int count;
+
+ for (count = KERNEL_MAX_ANIMATIONS - 1; count >= 0; count--) {
+ kernel_abort_animation (count);
+ }
+}
+
+
+void fastcall kernel_doom_all_animations (void)
+{
+ int count;
+
+ for (count = 0; count < KERNEL_MAX_ANIMATIONS; count++) {
+ kernel_anim[count].doomed = true;
+ }
+}
+
+
+void fastcall kernel_abort_doomed_animations (void)
+{
+ int count;
+
+ for (count = KERNEL_MAX_ANIMATIONS - 1; count >= 0; count--) {
+ if (kernel_anim[count].doomed) {
+ kernel_abort_animation (count);
+ }
+ }
+}
+
+
+
+
\ No newline at end of file
diff --git a/engines/mads/madsv2/core/kernel_c.h b/engines/mads/madsv2/core/kernel_c.h
new file mode 100644
index 00000000000..5281048374f
--- /dev/null
+++ b/engines/mads/madsv2/core/kernel_c.h
@@ -0,0 +1,35 @@
+/* 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 MADS_CORE_KERNEL_C_H
+#define MADS_CORE_KERNEL_C_H
+
+namespace MADS {
+namespace MADSV2 {
+
+extern void kernel_reconstruct_screen(int anim_handle);
+extern void kernel_abort_animation(int handle);
+extern void kernel_animation_get_sprite(int handle, int id);
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/kernel_d.cpp b/engines/mads/madsv2/core/kernel_d.cpp
new file mode 100644
index 00000000000..f38efe813cb
--- /dev/null
+++ b/engines/mads/madsv2/core/kernel_d.cpp
@@ -0,0 +1,160 @@
+/* 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 "mads/madsv2/core/general.h"
+#include "mads/madsv2/core/error.h"
+#include "mads/madsv2/core/matte.h"
+#include "mads/madsv2/core/font.h"
+#include "mads/madsv2/core/player.h"
+#include "mads/madsv2/core/quote.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/kernel_1.h"
+#include "mads/madsv2/core/kernel_8.h"
+#include "mads/madsv2/core/kernel_n.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+#define MESSAGE_COLOR (((KERNEL_MESSAGE_COLOR_BASE + 1) << 8) + KERNEL_MESSAGE_COLOR_BASE)
+
+KernelMessage kernel_message[KERNEL_MAX_MESSAGES];
+FontPtr kernel_message_font;
+int kernel_message_spacing;
+
+void kernel_message_init(void) {
+ int count;
+
+ for (count = 0; count < KERNEL_MAX_MESSAGES; count++) {
+ kernel_message[count].flags = 0;
+ }
+
+ kernel_message_font = font_conv;
+ kernel_message_spacing = -1;
+}
+
+int kernel_message_add(char *text, int x, int y, int color,
+ long time_on_screen, int trigger_code, int flags) {
+ int result = -1;
+ int id = -1;
+ int count;
+ KernelMessagePtr my_message = NULL;
+
+ for (count = 0; (id < 0) && (count < KERNEL_MAX_MESSAGES); count++) {
+ my_message = &kernel_message[count];
+ if (!(my_message->flags & KERNEL_MESSAGE_ACTIVE)) id = count;
+ }
+
+ if (id < 0) {
+ if (trigger_code) {
+ error_report(ERROR_KERNEL_MESSAGE_LIST_FULL, ERROR, MODULE_KERNEL, KERNEL_MAX_MESSAGES, trigger_code);
+ }
+ goto done;
+ }
+
+ my_message->message = text;
+
+ my_message->flags = (KERNEL_MESSAGE_ACTIVE | flags);
+ my_message->color = color;
+ my_message->x = x;
+ my_message->y = y;
+ my_message->matte_message_handle = -1;
+ my_message->expire_ticks = time_on_screen;
+ my_message->update_time = kernel.clock;
+ my_message->trigger_code = (byte)trigger_code;
+ my_message->trigger_dest = (byte)kernel.trigger_setup_mode;
+
+ for (count = 0; count < 3; count++) {
+ my_message->trigger_words[count] = player2.words[count];
+ }
+
+ if (flags & KERNEL_MESSAGE_PLAYER) my_message->update_time = player.clock;
+
+ result = id;
+
+done:
+ return result;
+}
+
+void kernel_message_teletype(int id, int rate, int quote) {
+ if (id >= 0) {
+ kernel_message[id].flags |= KERNEL_MESSAGE_TELETYPE;
+ if (quote) kernel_message[id].flags |= KERNEL_MESSAGE_QUOTE;
+ kernel_message[id].strobe_marker = 0;
+ kernel_message[id].strobe_rate = rate;
+ kernel_message[id].strobe_time = kernel.clock;
+ kernel_message[id].strobe_save = *kernel_message[id].message;
+ kernel_message[id].strobe_save_2 = *(kernel_message[id].message + 1);
+ if (kernel_message[id].flags & KERNEL_MESSAGE_PLAYER) {
+ kernel_message[id].strobe_time = player.clock;
+ }
+ kernel_message[id].update_time = kernel_message[id].strobe_time;
+ }
+}
+
+void kernel_message_attach(int id, int sequence) {
+ if (id >= 0) {
+ kernel_message[id].flags |= KERNEL_MESSAGE_ATTACHED;
+ kernel_message[id].sequence_id = (byte)sequence;
+ }
+}
+
+void kernel_message_anim(int id, int anim, int segment) {
+ if (id >= 0) {
+ kernel_message[id].flags |= KERNEL_MESSAGE_ANIM;
+ kernel_message[id].sequence_id = (byte)anim;
+ kernel_message[id].segment_id = (byte)segment;
+ }
+}
+
+void kernel_message_delete(int id) {
+ if (kernel_message[id].flags & KERNEL_MESSAGE_ACTIVE) {
+ if (kernel_message[id].flags & KERNEL_MESSAGE_TELETYPE) {
+ kernel_message[id].message[kernel_message[id].strobe_marker] = kernel_message[id].strobe_save;
+ kernel_message[id].message[kernel_message[id].strobe_marker + 1] = kernel_message[id].strobe_save_2;
+ }
+ if (kernel_message[id].matte_message_handle >= 0) {
+ matte_clear_message(kernel_message[id].matte_message_handle);
+ }
+ kernel_message[id].flags &= ~KERNEL_MESSAGE_ACTIVE;
+ }
+}
+
+void kernel_message_purge(void) {
+ int count;
+ for (count = 0; count < KERNEL_MAX_MESSAGES; count++) {
+ kernel_message_delete(count);
+ }
+
+ kernel_random_purge();
+}
+
+int kernel_message_player(int quote_id, long delay, int trigger) {
+ int id;
+
+ id = kernel_message_add(quote_string(kernel.quotes, quote_id),
+ 0, 0, MESSAGE_COLOR, delay, trigger,
+ KERNEL_MESSAGE_PLAYER | KERNEL_MESSAGE_CENTER);
+
+ return id;
+}
+
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/core/kernel_d.h b/engines/mads/madsv2/core/kernel_d.h
new file mode 100644
index 00000000000..36eb38af8ec
--- /dev/null
+++ b/engines/mads/madsv2/core/kernel_d.h
@@ -0,0 +1,46 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef MADS_CORE_KERNEL_D_H
+#define MADS_CORE_KERNEL_D_H
+
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/font.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+extern KernelMessage kernel_message[KERNEL_MAX_MESSAGES];
+extern FontPtr kernel_message_font;
+extern int kernel_message_spacing;
+
+extern void kernel_message_init(void);
+extern int kernel_message_add(char far *text, int x, int y,
+ int color, long time_on_screen, int trigger_code, int flags);
+extern void kernel_message_teletype(int id, int rate, int quote);
+extern void kernel_message_attach(int id, int sequence);
+extern void kernel_message_delete(int id);
+extern void kernel_message_purge(void);
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/kernel_e.cpp b/engines/mads/madsv2/core/kernel_e.cpp
new file mode 100644
index 00000000000..346fd3427ae
--- /dev/null
+++ b/engines/mads/madsv2/core/kernel_e.cpp
@@ -0,0 +1,204 @@
+/*
+/* kernel_e.c by Brian Reynolds 16-May-92
+*/
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <general.mac>
+#include <error.h>
+#include <matte.h>
+#include <font.h>
+#include <player.h>
+
+#include "kernel.mac"
+#include "kernel_1.h"
+#include "kernel_8.h"
+#include "kernel_d.h"
+
+#pragma optimize ("weglt", on)
+
+
+static void near fastcall kernel_message_update (KernelMessagePtr my_message)
+{
+ int count;
+ int x, y;
+ int xx, yy;
+ int x2;
+ int ys;
+ int width;
+ int matte_id;
+ int segment_id;
+ int strobe_flag = false;
+ int frame;
+ int image = -1;
+ Animation *anim = NULL;
+ SequencePtr sequence = NULL;
+ ImagePtr image_list = NULL;
+
+ if (my_message->flags & KERNEL_MESSAGE_EXPIRED) {
+ matte_clear_message (my_message->matte_message_handle);
+ my_message->flags &= ~KERNEL_MESSAGE_ACTIVE;
+ goto done;
+ }
+
+ if (!(my_message->flags & KERNEL_MESSAGE_TELETYPE)) {
+ my_message->expire_ticks -= KERNEL_MESSAGE_INTERVAL;
+ }
+
+ if (my_message->flags & KERNEL_MESSAGE_ATTACHED) {
+ sequence = &sequence_list[my_message->sequence_id];
+ if (sequence->expired || !sequence->active_flag) my_message->expire_ticks = 0;
+ }
+
+ if (my_message->flags & KERNEL_MESSAGE_ANIM) {
+ anim = &kernel_anim[my_message->sequence_id];
+ segment_id = my_message->segment_id;
+ if (anim->doomed || (anim->anim == NULL)) {
+ my_message->expire_ticks = 0;
+ } else {
+ frame = anim->last_frame;
+ image_list = anim->anim->image;
+ for (count = 0; (image < 0) && (count < anim->anim->num_images); count++) {
+ if (image_list[count].flags == frame) {
+ if (image_list[count].segment_id == (byte)segment_id) {
+ image = count;
+ }
+ }
+ }
+ if (image < 0) my_message->expire_ticks = 0;
+ }
+ }
+
+ if (my_message->expire_ticks <= 0) {
+ if (!kernel.trigger) {
+ my_message->flags |= KERNEL_MESSAGE_EXPIRED;
+ if (my_message->trigger_code) {
+ kernel.trigger = my_message->trigger_code;
+ kernel.trigger_mode = my_message->trigger_dest;
+ if (kernel.trigger_mode != KERNEL_TRIGGER_DAEMON) {
+ for (count = 0; count < 3; count++) {
+ player2.words[count] = my_message->trigger_words[count];
+ }
+ }
+ }
+ }
+ }
+
+ my_message->update_time = kernel.clock + KERNEL_MESSAGE_INTERVAL;
+
+ x = my_message->x;
+ y = my_message->y;
+
+ xx = 0;
+ yy = 0;
+
+ if (my_message->flags & KERNEL_MESSAGE_ANIM) {
+ xx = image_list[image].x - picture_view_x;
+ yy = image_list[image].y - picture_view_y;
+ }
+
+ if (my_message->flags & KERNEL_MESSAGE_ATTACHED) {
+ if (!sequence->auto_locating) {
+ xx = sequence->x;
+ yy = sequence->y;
+ } else {
+ xx = series_list[sequence->series_id]->index[sequence->sprite - 1].x;
+ yy = series_list[sequence->series_id]->index[sequence->sprite - 1].y;
+ }
+ }
+
+ if (my_message->flags & KERNEL_MESSAGE_PLAYER) {
+ if (player.walker_been_visible) {
+ ys = (50 + (series_list[player.series_base + player.series]->index[player.sprite - 1].ys * player.scale)) / 100;
+ xx = player.x;
+ yy = player.y + ((50 + (player.center_of_gravity * player.scale)) / 100) - ys;
+ yy-= 15;
+ } else {
+ xx = video_x >> 1;
+ yy = display_y >> 1;
+ }
+ }
+
+ xx += x;
+ yy += y;
+
+ if (my_message->flags & KERNEL_MESSAGE_TELETYPE) {
+ if (kernel.clock >= my_message->strobe_time) {
+ my_message->message[my_message->strobe_marker++] = my_message->strobe_save;
+ my_message->message[my_message->strobe_marker] = my_message->strobe_save_2;
+ my_message->strobe_save = my_message->message[my_message->strobe_marker];
+ my_message->strobe_save_2 = my_message->message[my_message->strobe_marker+1];
+ if (!my_message->strobe_save) {
+ my_message->message[my_message->strobe_marker] = 0;
+ my_message->flags &= ~KERNEL_MESSAGE_TELETYPE;
+ } else if (my_message->flags & KERNEL_MESSAGE_QUOTE) {
+ my_message->message[my_message->strobe_marker] = '"';
+ my_message->message[my_message->strobe_marker+1] = 0;
+ }
+ my_message->update_time = my_message->strobe_time = kernel.clock + my_message->strobe_rate;
+ strobe_flag = true;
+ }
+ }
+
+ width = font_string_width (kernel_message_font, my_message->message, kernel_message_spacing);
+
+ if (my_message->flags & (KERNEL_MESSAGE_CENTER | KERNEL_MESSAGE_RIGHT)) {
+ if (my_message->flags & KERNEL_MESSAGE_CENTER) {
+ xx -= (width >> 1);
+ } else {
+ xx -= width;
+ }
+ }
+
+ x2 = xx + width;
+ if (x2 > video_x) xx -= (x2 - video_x);
+
+ xx = max (0, min (video_x - 1, xx));
+ yy = max (0, min (display_y - 1, yy));
+
+ if (my_message->matte_message_handle >= 0) {
+ if (strobe_flag ||
+ (xx != message_list[my_message->matte_message_handle].x) ||
+ (yy != message_list[my_message->matte_message_handle].y)) {
+ matte_clear_message(my_message->matte_message_handle);
+ my_message->matte_message_handle = -1;
+ }
+ }
+
+ if (my_message->matte_message_handle < 0) {
+ matte_id = matte_add_message(kernel_message_font, my_message->message, xx, yy, my_message->color, kernel_message_spacing);
+ if (matte_id < 0) goto done;
+ my_message->matte_message_handle = matte_id;
+ }
+
+done:
+ ;
+}
+
+
+
+void fastcall kernel_message_update_all (void)
+{
+ int count;
+
+ for (count = 0; (count < KERNEL_MAX_MESSAGES) && !kernel.trigger; count++) {
+ if (kernel_message[count].flags & KERNEL_MESSAGE_ACTIVE) {
+ if (kernel.clock >= kernel_message[count].update_time) {
+ kernel_message_update (&kernel_message[count]);
+ }
+ }
+ }
+}
+
+
+void fastcall kernel_message_correction (long old_clock, long new_clock)
+{
+ int count;
+
+ for (count = 0; (count < KERNEL_MAX_MESSAGES); count++) {
+ if (kernel_message[count].flags & KERNEL_MESSAGE_ACTIVE) {
+ kernel_message[count].update_time += (new_clock - old_clock);
+ }
+ }
+}
diff --git a/engines/mads/madsv2/core/kernel_f.cpp b/engines/mads/madsv2/core/kernel_f.cpp
new file mode 100644
index 00000000000..5128f5bfa15
--- /dev/null
+++ b/engines/mads/madsv2/core/kernel_f.cpp
@@ -0,0 +1,167 @@
+/* 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 "mads/madsv2/core/general.h"
+#include "mads/madsv2/core/vocab.h"
+#include "mads/madsv2/core/inter.h"
+#include "mads/madsv2/core/error.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/kernel_1.h"
+#include "mads/madsv2/core/kernel_8.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+int kernel_add_dynamic(int vocab_id, int verb_id, byte syntax,
+ int auto_sequence, int x, int y, int xs, int ys) {
+ int id = -1;
+ int count;
+
+ for (count = 0; (id < 0) && (count < KERNEL_MAX_DYNAMIC); count++) {
+ if (!kernel_dynamic_hot[count].flags) {
+ id = count;
+ }
+ }
+
+ if (id < 0) {
+ error_report(ERROR_DYNAMIC_HOTSPOT_OVERFLOW, WARNING, MODULE_KERNEL, id, KERNEL_MAX_DYNAMIC);
+ goto done;
+ }
+
+ kernel_dynamic_hot[id].flags = true;
+ kernel_dynamic_hot[id].vocab_id = vocab_id;
+ kernel_dynamic_hot[id].auto_sequence = auto_sequence;
+ kernel_dynamic_hot[id].x = x;
+ kernel_dynamic_hot[id].y = y;
+ kernel_dynamic_hot[id].xs = xs;
+ kernel_dynamic_hot[id].ys = ys;
+
+ kernel_dynamic_hot[id].feet_x = WALK_DIRECT_2;
+ kernel_dynamic_hot[id].feet_y = 0;
+ kernel_dynamic_hot[id].facing = 5;
+
+ kernel_dynamic_hot[id].verb_id = verb_id;
+ kernel_dynamic_hot[id].prep = PREP_IN;
+ kernel_dynamic_hot[id].syntax = syntax;
+
+ kernel_dynamic_hot[id].cursor = 0;
+
+ kernel_dynamic_hot[id].valid = true;
+
+ kernel_dynamic_hot[id].auto_anim = -1;
+ for (count = 0; count < KERNEL_DYNAMIC_MAX_SEGMENTS; count++) {
+ kernel_dynamic_hot[id].auto_segment[count] = KERNEL_DYNAMIC_NO_ANIM;
+ }
+
+
+ kernel_num_dynamic++;
+ kernel_dynamic_changed = true;
+
+ if (auto_sequence >= 0) {
+ sequence_list[auto_sequence].dynamic_hotspot = id;
+ kernel_dynamic_hot[id].valid = false;
+ }
+
+done:
+ return id;
+}
+
+void kernel_dynamic_anim(int id, int anim_id, int segment) {
+ int count;
+ int found = false;
+
+ if ((id >= 0) && (id < KERNEL_MAX_DYNAMIC)) {
+ if (kernel_anim[anim_id].anim != NULL) {
+ kernel_anim[anim_id].dynamic_hotspot = id;
+ if (kernel_dynamic_hot[id].auto_anim < 0) {
+ kernel_dynamic_hot[id].valid = false;
+ }
+ kernel_dynamic_hot[id].auto_anim = (char)anim_id;
+ for (count = 0; !found && (count < KERNEL_DYNAMIC_MAX_SEGMENTS); count++) {
+ if (kernel_dynamic_hot[id].auto_segment[count] == KERNEL_DYNAMIC_NO_ANIM) {
+ kernel_dynamic_hot[id].auto_segment[count] = (byte)segment;
+ found = true;
+ }
+ }
+
+ if (!found) {
+ error_report(ERROR_DYNAMIC_HOTSPOT_OVERFLOW, ERROR, MODULE_KERNEL, -9999, id);
+ }
+
+ kernel_dynamic_changed = true;
+ }
+ }
+}
+
+int kernel_dynamic_walk(int id, int feet_x, int feet_y, int facing) {
+ if (id >= 0) {
+ kernel_dynamic_hot[id].feet_x = feet_x;
+ kernel_dynamic_hot[id].feet_y = feet_y;
+ kernel_dynamic_hot[id].facing = (byte)facing;
+ }
+
+ return id;
+}
+
+int kernel_dynamic_cursor(int id, int cursor_) {
+ if (id >= 0) {
+ kernel_dynamic_hot[id].cursor = (byte)cursor_;
+ }
+
+ return id;
+}
+
+void kernel_delete_dynamic(int id) {
+ if (kernel_dynamic_hot[id].flags) {
+ if (kernel_dynamic_hot[id].auto_sequence >= 0) {
+ sequence_list[kernel_dynamic_hot[id].auto_sequence].dynamic_hotspot = -1;
+ }
+ if (kernel_dynamic_hot[id].auto_anim >= 0) {
+ kernel_anim[kernel_dynamic_hot[id].auto_anim].dynamic_hotspot = -1;
+ }
+ kernel_dynamic_hot[id].flags = false;
+ kernel_num_dynamic--;
+ kernel_dynamic_changed = true;
+ }
+}
+
+void kernel_purge_dynamic() {
+ int count;
+
+ for (count = 0; count < KERNEL_MAX_DYNAMIC; count++) {
+ kernel_delete_dynamic(count);
+ }
+ kernel_num_dynamic = 0;
+ kernel_dynamic_changed = true;
+}
+
+void kernel_init_dynamic() {
+ int count;
+
+ for (count = 0; count < KERNEL_MAX_DYNAMIC; count++) {
+ kernel_dynamic_hot[count].flags = false;
+ }
+ kernel_num_dynamic = 0;
+ kernel_dynamic_changed = 0;
+}
+
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/core/kernel_f.h b/engines/mads/madsv2/core/kernel_f.h
new file mode 100644
index 00000000000..1f1eb088d64
--- /dev/null
+++ b/engines/mads/madsv2/core/kernel_f.h
@@ -0,0 +1,38 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef MADS_CORE_KERNEL_F_H
+#define MADS_CORE_KERNEL_F_H
+
+namespace MADS {
+namespace MADSV2 {
+
+extern int kernel_add_dynamic(int vocab_id, int auto_sequence,
+ int x, int y, int xs, int ys);
+extern int kernel_dynamic_walk(int id, int feet_x, int feet_y, int facing);
+extern void kernel_delete_dynamic(int id);
+extern void kernel_purge_dynamic();
+extern void kernel_init_dynamic();
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/kernel_g.cpp b/engines/mads/madsv2/core/kernel_g.cpp
new file mode 100644
index 00000000000..a1f1d90bc1f
--- /dev/null
+++ b/engines/mads/madsv2/core/kernel_g.cpp
@@ -0,0 +1,54 @@
+/*
+/* kernel_g.c by Brian Reynolds 22-Apr-92
+*/
+
+#include <general.mac>
+
+#include <inter.h>
+#include <hspot.h>
+#include <video.h>
+#include <error.h>
+
+#include "kernel.mac"
+#include "kernel_1.h"
+
+#pragma optimize ("weglt", on)
+
+
+int fastcall kernel_dynamic_consecutive(int id)
+{
+ int scan;
+
+ for (scan = 0; (id >= 0) && (scan < KERNEL_MAX_DYNAMIC); scan++) {
+ if (kernel_dynamic_hot[scan].flags && kernel_dynamic_hot[scan].valid) {
+ id--;
+ if (id < 0) goto done;
+ }
+ }
+
+ if (id >= 0) scan = -1;
+
+done:
+ return (scan);
+}
+
+
+void fastcall kernel_refresh_dynamic (void)
+{
+ int count;
+
+ numspots = inter_base_hotspots;
+
+ for (count = 0; count < KERNEL_MAX_DYNAMIC; count++) {
+ if (kernel_dynamic_hot[count].flags && kernel_dynamic_hot[count].valid && ((inter_input_mode == INTER_BUILDING_SENTENCES) || (inter_input_mode == INTER_LIMITED_SENTENCES)) ) {
+ hspot_add (kernel_dynamic_hot[count].x, kernel_dynamic_hot[count].y,
+ kernel_dynamic_hot[count].x + kernel_dynamic_hot[count].xs - 1,
+ kernel_dynamic_hot[count].y + kernel_dynamic_hot[count].ys - 1,
+ STROKE_DYNAMIC | STROKE_INTERFACE, kernel_dynamic_hot[count].vocab_id,
+ RELATIVE_MODE);
+ inter_force_rescan = true;
+ }
+ }
+
+ kernel_dynamic_changed = false;
+}
diff --git a/engines/mads/madsv2/core/kernel_g.h b/engines/mads/madsv2/core/kernel_g.h
new file mode 100644
index 00000000000..01d2ef2c86d
--- /dev/null
+++ b/engines/mads/madsv2/core/kernel_g.h
@@ -0,0 +1,34 @@
+/* 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 MADS_CORE_KERNEL_G_H
+#define MADS_CORE_KERNEL_G_H
+
+namespace MADS {
+namespace MADSV2 {
+
+extern int kernel_dynamic_consecutive(int id);
+extern void kernel_refresh_dynamic();
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/kernel_h.cpp b/engines/mads/madsv2/core/kernel_h.cpp
new file mode 100644
index 00000000000..679efcdf078
--- /dev/null
+++ b/engines/mads/madsv2/core/kernel_h.cpp
@@ -0,0 +1,99 @@
+/*
+/* kernel_h.c by Brian Reynolds 14-Jan-92
+*/
+
+#include <string.h>
+
+#include <general.mac>
+#include <env.h>
+
+#include "kernel.mac"
+#include "kernel_1.h"
+
+#pragma optimize ("weglt", on)
+
+static char kernel_work_name[20];
+
+
+
+char * fastcall kernel_full_name(int my_room, char type, int num, char *text, int ext)
+{
+ char temp[2];
+
+ if (my_room > 0) {
+ if (my_room >= 100) {
+ strcpy (kernel_work_name, "*RM");
+ } else {
+ strcpy (kernel_work_name, "*SC");
+ }
+ env_catint (kernel_work_name, my_room, 3);
+ } else {
+ strcpy (kernel_work_name, "*");
+ }
+
+ temp[0] = type;
+ temp[1] = 0;
+ strcat (kernel_work_name, temp);
+
+ if ((num >= 0) && (ext < KERNEL_TT)) {
+ if (num > 9) {
+ env_catint (kernel_work_name, num, 2);
+ } else {
+ env_catint (kernel_work_name, num, 1);
+ }
+ }
+
+ if (text != NULL) _fstrcat (kernel_work_name, text);
+
+ switch (ext) {
+ case KERNEL_SS:
+ strcat (kernel_work_name, ".SS");
+ break;
+ case KERNEL_AA:
+ strcat (kernel_work_name, ".AA");
+ break;
+ case KERNEL_DAT:
+ strcat (kernel_work_name, ".DAT");
+ break;
+ case KERNEL_HH:
+ strcat (kernel_work_name, ".HH");
+ break;
+ case KERNEL_ART:
+ strcat (kernel_work_name, ".ART");
+ break;
+ case KERNEL_INT:
+ strcat (kernel_work_name, ".INT");
+ break;
+ case KERNEL_TT:
+ strcat (kernel_work_name, ".TT");
+ break;
+ case KERNEL_MM:
+ strcat (kernel_work_name, ".MM");
+ break;
+ case KERNEL_WW:
+ strcat (kernel_work_name, ".WW");
+ break;
+ }
+
+ if ((num >= 0) && (ext >= KERNEL_TT)) {
+ temp[0] = (byte)num;
+ temp[1] = 0;
+ strcat (kernel_work_name, temp);
+ }
+
+ return (kernel_work_name);
+}
+
+
+char * fastcall kernel_name(char type, int num)
+{
+ return (kernel_full_name(room_id, type, num, NULL, KERNEL_NONE));
+}
+
+
+char * fastcall kernel_interface_name (int num)
+{
+ return (kernel_full_name(0, 'I', num, NULL, KERNEL_AA));
+}
+
+
\ No newline at end of file
diff --git a/engines/mads/madsv2/core/kernel_h.h b/engines/mads/madsv2/core/kernel_h.h
new file mode 100644
index 00000000000..7b001e1ea23
--- /dev/null
+++ b/engines/mads/madsv2/core/kernel_h.h
@@ -0,0 +1,34 @@
+/* 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 MADS_CORE_KERNEL_H_H
+#define MADS_CORE_KERNEL_H_H
+
+namespace MADS {
+namespace MADSV2 {
+
+extern int kernel_dynamic_consecutive(int id);
+extern void kernel_refresh_dynamic();
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/kernel_i.cpp b/engines/mads/madsv2/core/kernel_i.cpp
new file mode 100644
index 00000000000..f61477ccd77
--- /dev/null
+++ b/engines/mads/madsv2/core/kernel_i.cpp
@@ -0,0 +1,76 @@
+/*
+/* kernel_i.c by Brian Reynolds 31-Mar-92
+*/
+
+#include <string.h>
+
+#include <general.mac>
+/* pl #include <sound.h> */
+#include <timer.h>
+#include <env.h>
+#include <error.h>
+
+#pragma optimize ("weglt", on)
+
+int kernel_sound_handle = 0;
+
+
+void fastcall kernel_unload_sound_driver(void)
+{
+/* pl if (kernel_sound_handle) {
+ sound_queue(0);
+
+ timer_set_sound_flag (false);
+
+ sound_system_shutdown();
+ sound_driver_remove(kernel_sound_handle);
+
+ sound_driver_null();
+ }
+
+ kernel_sound_handle = 0;
+*/
+}
+
+
+int fastcall kernel_load_sound_driver(char *name, char sound_card, int sound_board_address, int sound_board_type, int sound_board_irq)
+{
+/* pl char temp_buf[80];
+ char temp_buf_2[80];
+ char *mark;
+
+ strcpy (temp_buf, name);
+ for (mark = temp_buf; *mark; mark++) {
+ if (*mark == '#') {
+ *mark = sound_card;
+ }
+ }
+
+ if (env_search_mode == ENV_SEARCH_MADS_PATH) {
+ env_get_path (temp_buf_2, temp_buf);
+ } else {
+ if (temp_buf[0] == '*') {
+ strcpy (temp_buf_2, &temp_buf[1]);
+ } else {
+ strcpy (temp_buf_2, temp_buf);
+ }
+ }
+
+ kernel_unload_sound_driver();
+
+ kernel_sound_handle = sound_driver_load(temp_buf_2);
+
+ if (kernel_sound_handle) {
+ sound_driver_init (kernel_sound_handle);
+ while (sound_system_setup(sound_board_address, sound_board_type, sound_board_irq) != 0);
+ } else {
+ sound_driver_null();
+ }
+
+ timer_set_sound_flag (kernel_sound_handle);
+
+ return (kernel_sound_handle);
+ */
+}
+
+
\ No newline at end of file
diff --git a/engines/mads/madsv2/core/kernel_i.h b/engines/mads/madsv2/core/kernel_i.h
new file mode 100644
index 00000000000..337b62da718
--- /dev/null
+++ b/engines/mads/madsv2/core/kernel_i.h
@@ -0,0 +1,36 @@
+/* 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 MADS_CORE_KERNEL_I_H
+#define MADS_CORE_KERNEL_I_H
+
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/image.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+extern void kernel_seq_image(SequencePtr sequence, ImagePtr image, int sequence_id);
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/kernel_j.cpp b/engines/mads/madsv2/core/kernel_j.cpp
new file mode 100644
index 00000000000..393b5819dfb
--- /dev/null
+++ b/engines/mads/madsv2/core/kernel_j.cpp
@@ -0,0 +1,35 @@
+/*
+/* kernel_j.c by Brian Reynolds 7-Apr-92
+*/
+
+#include <general.mac>
+#include <room.h>
+#include <matte.h>
+#include <tile.h>
+#include <error.h>
+#include <camera.h>
+#include <rail.h>
+
+#include "kernel.mac"
+#include "kernel_1.h"
+
+#pragma optimize ("weglt", on)
+
+void fastcall kernel_load_variant (int variant)
+{
+ room_variant = variant;
+
+ if (room_load_variant (room_id, room_variant, NULL, room,
+ &scr_depth,
+ &scr_walk,
+ &scr_special,
+ &depth_map,
+ &depth_resource,
+ tile_attribute_handle)) {
+ error_report (ERROR_VARIANT_LOAD_FAILURE, WARNING, MODULE_KERNEL, room_load_error, (room_id * 10) + room_variant);
+ }
+
+ rail_connect_all_nodes();
+
+ camera_jump_to (picture_view_x, picture_view_y);
+}
diff --git a/engines/mads/madsv2/core/kernel_k.cpp b/engines/mads/madsv2/core/kernel_k.cpp
new file mode 100644
index 00000000000..4db0b6d31ac
--- /dev/null
+++ b/engines/mads/madsv2/core/kernel_k.cpp
@@ -0,0 +1,32 @@
+/*
+/* kernel_k.c by Brian Reynolds 10-Apr-92
+/*
+/* Changes palette to reflect newly loaded sprite series, but does
+/* not affect cycling color ranges.
+*/
+
+#include <general.mac>
+#include <mcga.h>
+#include <pal.h>
+#include <cycle.h>
+#include "kernel.mac"
+
+#pragma optimize ("weglt", on)
+
+void fastcall kernel_new_palette (void)
+{
+ int palette_base, palette_size;
+
+ palette_base = KERNEL_RESERVED_LOW_COLORS;
+ if (cycling_active) {
+ if (cycle_list.num_cycles) {
+ palette_base = cycle_list.table[0].first_palette_color + total_cycle_colors;
+ }
+ }
+ palette_size = 256 - palette_base;
+
+ mcga_setpal_range(&master_palette, palette_base, palette_size);
+}
+
+
+
\ No newline at end of file
diff --git a/engines/mads/madsv2/core/kernel_k.h b/engines/mads/madsv2/core/kernel_k.h
new file mode 100644
index 00000000000..beb01a22593
--- /dev/null
+++ b/engines/mads/madsv2/core/kernel_k.h
@@ -0,0 +1,33 @@
+/* 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 MADS_CORE_KERNEL_K_H
+#define MADS_CORE_KERNEL_K_H
+
+namespace MADS {
+namespace MADSV2 {
+
+extern void kernel_new_palette();
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/kernel_l.cpp b/engines/mads/madsv2/core/kernel_l.cpp
new file mode 100644
index 00000000000..fb1b545aa56
--- /dev/null
+++ b/engines/mads/madsv2/core/kernel_l.cpp
@@ -0,0 +1,55 @@
+/*
+/* kernel_l.c by Brian Reynolds 27-May-92
+*/
+
+#include <general.mac>
+#include <mem.h>
+#include <matte.h>
+#include <player.h>
+#include <sprite.h>
+
+#include "kernel.mac"
+#include "kernel_1.h"
+#include "kernel_6.h"
+#include "kernel_8.h"
+
+
+void fastcall kernel_dump_quotes (void)
+{
+ if (kernel.quotes != NULL) {
+ mem_free (kernel.quotes);
+ kernel.quotes = NULL;
+ }
+}
+
+
+void fastcall kernel_dump_all (void)
+{
+ kernel_dump_quotes();
+ kernel_unload_all_series();
+ kernel_seq_init();
+ image_marker = 0;
+ matte_refresh_work();
+}
+
+
+void fastcall kernel_dump_walker_only (void)
+{
+ int count;
+ int marker;
+
+ marker = player.series_base;
+
+ for (count = 0; count < 8; count++) {
+ if (player.available[count]) {
+ sprite_free(&series_list[marker++], true);
+ player.available[count] = false;
+ }
+ }
+
+ image_marker = 0;
+ matte_refresh_work();
+
+ player.walker_visible = false;
+}
+
diff --git a/engines/mads/madsv2/core/kernel_m.cpp b/engines/mads/madsv2/core/kernel_m.cpp
new file mode 100644
index 00000000000..e433c23a4ca
--- /dev/null
+++ b/engines/mads/madsv2/core/kernel_m.cpp
@@ -0,0 +1,145 @@
+/*
+/* kernel_m.c by Brian Reynolds 29-May-92
+*/
+
+#include <general.mac>
+#include <loader.h>
+#include <player.h>
+#include <object.h>
+#include <inter.h>
+#include <timer.h>
+#include <game.h>
+/* pl #include <conv.h> */
+#include <camera.h>
+#include <error.h>
+#include <matte.h>
+
+#include "kernel.mac"
+#include "kernel_1.h"
+
+#pragma optimize ("weglt", on)
+
+extern int first_inven;
+
+#define OMR 40 /* OUAF_MAX_ROOMS in global.mac */
+
+extern int room_state[OMR];
+
+
+int fastcall kernel_save_game (char *filename)
+{
+ int error_flag = true;
+ Load load_handle;
+
+ load_handle.open = false;
+
+ if (loader_open(&load_handle, filename, "wb", PACK_NONE)) goto done;
+
+ if (!loader_write(&game, sizeof(KernelGame), 1, &load_handle)) goto done;
+ if (!loader_write(&room_id, sizeof(int), 1, &load_handle)) goto done;
+ if (!loader_write(&player2, sizeof(Player2), 1, &load_handle)) goto done;
+ if (!loader_write(&inven_num_objects, sizeof(int), 1, &load_handle)) goto done;
+ if (inven_num_objects) {
+ if (!loader_write(inven, sizeof(int) * inven_num_objects, 1, &load_handle)) goto done;
+ }
+ if (!loader_write(&player, sizeof(Player), 1, &load_handle)) goto done;
+ if (!loader_write(global, sizeof(int) * global_list_size, 1, &load_handle)) goto done;
+ if (!loader_write(object, sizeof(Object) * num_objects, 1, &load_handle)) goto done;
+ if (!loader_write(0, sizeof(int), 1, &load_handle)) goto done;
+ /* pl (see above line) if (!loader_write(&conv_control.running, sizeof(int), 1, &load_handle)) goto done; */
+
+ if (!loader_write(&picture_view_x, sizeof(int), 1, &load_handle)) goto done;
+ if (!loader_write(&picture_view_y, sizeof(int), 1, &load_handle)) goto done;
+ if (!loader_write(room_state, sizeof(int) * OMR, 1, &load_handle)) goto done;
+ if (!loader_write(&previous_room, sizeof(int), 1, &load_handle)) goto done;
+
+ /* pl if (conv_append(load_handle.handle)) goto done; */
+
+ error_flag = false;
+
+done:
+ if (load_handle.open) loader_close (&load_handle);
+ return (error_flag);
+}
+
+
+int fastcall kernel_load_game (char *filename)
+{
+ int error_flag = true;
+ Load load_handle;
+ byte keep_video_mode;
+ byte keep_sound_card;
+ byte *keep_quotes;
+ int save;
+
+ save = player.walker_is_loaded;
+
+ /*
+ keep_video_mode = kernel.video_mode;
+ keep_sound_card = kernel.sound_card;
+ keep_quotes = kernel.quotes;
+ */
+
+ load_handle.open = false;
+
+ if (loader_open(&load_handle, filename, "rb", false)) goto done;
+
+ if (!loader_read(&game, sizeof(KernelGame), 1, &load_handle)) goto done;
+ if (!loader_read(&new_room, sizeof(int), 1, &load_handle)) goto done;
+ if (!loader_read(&player2, sizeof(Player2), 1, &load_handle)) goto done;
+ if (!loader_read(&inven_num_objects, sizeof(int), 1, &load_handle)) goto done;
+ if (inven_num_objects) {
+ if (!loader_read(inven, sizeof(int) * inven_num_objects, 1, &load_handle)) goto done;
+ }
+ if (!loader_read(&player, sizeof(Player), 1, &load_handle)) goto done;
+ if (!loader_read(global, sizeof(int) * global_list_size, 1, &load_handle)) goto done;
+ if (!loader_read(object, sizeof(Object) * num_objects, 1, &load_handle)) goto done;
+ if (!loader_read(0, sizeof(int), 1, &load_handle)) goto done;
+ /* pl (see above line) if (!loader_read(&conv_restore_running, sizeof(int), 1, &load_handle)) goto done; */
+
+ /* Temporary support for old save file format */
+ if (load_handle.pack_list_marker >= (int)load_handle.pack.num_records) goto expand;
+
+ if (!loader_read(&camera_old_x_target, sizeof(int), 1, &load_handle)) goto done;
+ if (!loader_read(&camera_old_y_target, sizeof(int), 1, &load_handle)) goto done;
+ if (!loader_read(room_state, sizeof(int) * OMR, 1, &load_handle)) goto done;
+ if (!loader_read(&previous_room, sizeof(int), 1, &load_handle)) goto done;
+
+expand:
+ /* pl if (conv_expand(load_handle.handle)) goto done; */
+
+ if (inven_num_objects > 0) {
+ active_inven = 0;
+ } else {
+ active_inven = -1;
+ }
+
+ first_inven = 0;
+
+ section_id = KERNEL_RESTORING_GAME;
+ room_id = KERNEL_RESTORING_GAME;
+
+ new_section = new_room / 100;
+
+ kernel.clock = timer_read();
+ game.going = true;
+
+ error_flag = false;
+
+done:
+ if (load_handle.open) loader_close (&load_handle);
+
+ /*
+ kernel.video_mode = keep_video_mode;
+ kernel.sound_card = keep_sound_card;
+ kernel.quotes = keep_quotes;
+ */
+
+
+ player.walker_is_loaded = save;
+ /* player.walker_is_loaded = false; */
+ /* player.walker_must_reload = true; */
+
+ return (error_flag);
+}
+
\ No newline at end of file
diff --git a/engines/mads/madsv2/core/kernel_n.cpp b/engines/mads/madsv2/core/kernel_n.cpp
new file mode 100644
index 00000000000..74bcbcd8dce
--- /dev/null
+++ b/engines/mads/madsv2/core/kernel_n.cpp
@@ -0,0 +1,231 @@
+/*
+/* kernel_n.c by Brian Reynolds 17-Jun-92
+/*
+/* Facility to generate "idle chatter" messages randomly within
+/* a predefined region of the screen.
+*/
+
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include <general.mac>
+#include <quote.h>
+#include <imath.h>
+
+#include "kernel.mac"
+#include "kernel_1.h"
+#include "kernel_d.h"
+
+#pragma optimize ("weglt", on)
+
+
+int random_message_handle[KERNEL_MAX_RANDOM_MESSAGES]; /* List of active handles */
+int random_message_quote [KERNEL_MAX_RANDOM_MESSAGES]; /* List of active quote id's */
+int random_max_messages = 1; /* # of active handles/ids */
+
+int random_quote_list[KERNEL_MAX_RANDOM_QUOTES]; /* List of available quote id's */
+int random_quote_list_size = 0; /* # of available quote id's */
+
+int random_min_x = 0; /* X location allowable range */
+int random_max_x = video_x;
+
+int random_min_y = 0; /* Y location allowable range */
+int random_max_y = display_y;
+int random_spacing; /* Y location minimum spacing */
+
+int random_teletype_rate = 0; /* Rate for teletype */
+
+int random_message_color; /* Color scheme for message */
+int random_message_duration; /* Duration of messages */
+
+
+void fastcall kernel_random_purge (void)
+{
+ int count;
+
+ for (count = 0; count < KERNEL_MAX_RANDOM_MESSAGES; count++) {
+ random_message_handle[count] = -1;
+ random_message_quote [count] = -1;
+ }
+}
+
+
+/*
+/* kernel_random_messages_init()
+/*
+/* Initializes a random chatter sequence. (Parameters end with
+/* a zero-terminated list of already loaded quote id's to be
+/* used for messages).
+*/
+void kernel_random_messages_init (int max_messages_at_once,
+ int min_x, int max_x,
+ int min_y, int max_y,
+ int min_y_spacing,
+ int teletype_rate,
+ int color,
+ int duration,
+ int quote_id, ...)
+{
+ va_list marker;
+ int my_quote = quote_id;
+
+ random_max_messages = max_messages_at_once;
+ random_min_x = min_x;
+ random_max_x = max_x;
+ random_min_y = min_y;
+ random_max_y = max_y;
+ random_spacing = min_y_spacing;
+ random_teletype_rate = teletype_rate;
+ random_message_color = color;
+ random_message_duration = duration;
+
+ random_quote_list_size = 0;
+
+ va_start (marker, quote_id);
+ while (my_quote > 0) {
+ if (random_quote_list_size < KERNEL_MAX_RANDOM_QUOTES) {
+ random_quote_list[random_quote_list_size++] = my_quote;
+ }
+
+ my_quote = va_arg (marker, int);
+ }
+
+ kernel_random_purge();
+}
+
+
+
+/*
+/* kernel_check_random()
+/*
+/* Returns the number of idle chatter messages currently being
+/* displayed.
+*/
+int fastcall kernel_check_random (void)
+{
+ int count;
+ int sum = 0;
+
+ for (count = 0; count < random_max_messages; count++) {
+ if (random_message_handle[count] >= 0) sum++;
+ }
+ return (sum);
+}
+
+
+
+/*
+/* kernel_random_message_server()
+/*
+/* Should be called regularly from daemon code whenever a random
+/* message sequence is running (intercepts triggers from terminating
+/* messages to determine when to free up control space).
+*/
+void fastcall kernel_random_message_server (void)
+{
+ if ((kernel.trigger >= KERNEL_RANDOM_MESSAGE_TRIGGER) &&
+ (kernel.trigger < KERNEL_RANDOM_MESSAGE_TRIGGER + random_max_messages)) {
+ random_message_handle[kernel.trigger - KERNEL_RANDOM_MESSAGE_TRIGGER] = -1;
+ random_message_quote [kernel.trigger - KERNEL_RANDOM_MESSAGE_TRIGGER] = -1;
+ }
+}
+
+
+
+/*
+/* kernel_generate_random_message()
+/*
+/* Called occasionally to (possibly) generate a random message.
+/*
+/* (generated whenever random(chance_major) <= chance_minor)
+*/
+int fastcall kernel_generate_random_message (int chance_major, int chance_minor)
+{
+ int count, count2, scan;
+ int bad;
+ int generated_one;
+ int idx, quote;
+ int last_y;
+ int message_x, message_y;
+ int crash_timeout = 0;
+
+ generated_one = false;
+
+ for (count = 0; count < random_max_messages; count++) {
+ if (random_message_handle[count] < 0) {
+
+ /* Don't allow two phrases to teletype at once */
+
+ bad = false;
+ for (scan = 0; scan < random_max_messages; scan++) {
+ if (random_message_handle[scan] >= 0) {
+ if (kernel_message[random_message_handle[scan]].flags & KERNEL_MESSAGE_TELETYPE) {
+ bad = true;
+ }
+ }
+ }
+
+ /* Check random chance for message to appear */
+
+ if ((imath_random (1, chance_major) <= chance_minor) && !bad) {
+
+ /* Pick randomly from our list of allowable quotes */
+
+ do {
+ idx = imath_random(0, random_quote_list_size - 1);
+ quote = random_quote_list[idx];
+ bad = false;
+ for (scan = 0; scan < random_max_messages; scan++) {
+ if (quote == random_message_quote[scan]) {
+ bad = true;
+ }
+ }
+ } while (bad);
+
+ random_message_quote[count] = quote;
+
+ /* Put message in a random location */
+
+ message_x = imath_random (random_min_x, random_max_x);
+
+ /* Be sure Y values are properly spaced */
+
+ crash_timeout = 0;
+
+ do {
+ if (crash_timeout++ > 100) goto done;
+ bad = false;
+ message_y = imath_random (random_min_y, random_max_y);
+ for (count2 = 0; count2 < random_max_messages; count2++) {
+ if (random_message_handle[count2] >= 0) {
+ last_y = kernel_message[random_message_handle[count2]].y;
+ if ((message_y >= (last_y - random_spacing)) &&
+ (message_y <= (last_y + random_spacing))) {
+ bad = true;
+ }
+ }
+ }
+ } while (bad);
+
+ /* Put our new message in the list */
+
+ random_message_handle[count] =
+ kernel_message_add(quote_string(kernel.quotes, random_message_quote[count]),
+ message_x, message_y, random_message_color, random_message_duration,
+ KERNEL_RANDOM_MESSAGE_TRIGGER + count, 0);
+ if (random_teletype_rate > 0) {
+ if (random_message_handle[count] >= 0) {
+ kernel_message_teletype (random_message_handle[count], random_teletype_rate, true);
+ }
+ }
+
+ generated_one = true;
+ }
+ }
+ }
+
+done:
+ return (generated_one);
+}
+
+
diff --git a/engines/mads/madsv2/core/kernel_n.h b/engines/mads/madsv2/core/kernel_n.h
new file mode 100644
index 00000000000..8143258c85e
--- /dev/null
+++ b/engines/mads/madsv2/core/kernel_n.h
@@ -0,0 +1,40 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef MADS_CORE_KERNEL_N_H
+#define MADS_CORE_KERNEL_N_H
+
+namespace MADS {
+namespace MADSV2 {
+
+extern void kernel_random_messages_init(int max_messages_at_once,
+ int min_x, int max_x, int min_y, int max_y, int min_y_spacing,
+ int teletype_rate, int color, int duration, int quote_id, ...);
+extern int kernel_check_random(void);
+extern void kernel_random_message_server(void);
+extern int kernel_generate_random_message(int chance_major,
+ int chance_minor);
+extern void kernel_random_purge(void);
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/kernel_o.cpp b/engines/mads/madsv2/core/kernel_o.cpp
new file mode 100644
index 00000000000..a2d7eed0f7c
--- /dev/null
+++ b/engines/mads/madsv2/core/kernel_o.cpp
@@ -0,0 +1,111 @@
+/*
+/* kernel_o.c by Brian Reynolds 26-Jun-92
+*/
+
+#include <string.h>
+
+#include <general.mac>
+
+#include <matte.h>
+#include <inter.h>
+#include <mem.h>
+#include <buffer.h>
+#include <room.h>
+#include <pal.h>
+#include <error.h>
+#include <anim.h>
+#include <vocab.h>
+#include <timer.h>
+#include <mouse.h>
+#include <video.h>
+#include <mcga.h>
+#include <rail.h>
+#include <cycle.h>
+
+#include "kernel.mac"
+#include "kernel_1.h"
+#include "kernel_2.h"
+#include "kernel_8.h"
+#include "kernel_d.h"
+#include "kernel_g.h"
+
+#pragma optimize ("weglt", on)
+
+char kernel_interface_loaded[40] = "";
+
+
+void fastcall kernel_load_interface (void)
+{
+ char temp_buf[80];
+ char *mark;
+
+ _fstrcpy (temp_buf, kernel.interface);
+ mark = strchr(temp_buf, '.');
+ if (mark != NULL) {
+ *mark = 0;
+ }
+ if (inter_input_mode != INTER_BUILDING_SENTENCES) {
+ strcat (temp_buf, "A");
+ }
+ strcat (temp_buf, ".INT");
+
+ if (strcmp(kernel_interface_loaded, temp_buf)) {
+ buffer_free (&scr_inter_orig);
+ pal_activate_shadow (&kernel_shadow_inter);
+ if (inter_load_background (temp_buf, &scr_inter_orig)) {
+ error_report (ERROR_KERNEL_NO_INTERFACE, SEVERE, MODULE_KERNEL, inter_input_mode, 0);
+ }
+ strcpy (kernel_interface_loaded, temp_buf);
+ pal_activate_shadow (&kernel_shadow_main);
+ }
+}
+
+
+
+
+
+/*
+/* kernel_set_interface_mode()
+/*
+/* Switches interface modes (INTER_BUILDING_SENTENCES is the
+/* normal mode; INTER_CONVERSATION is for dialog scenes), and
+/* properly updates the graphic structures.
+*/
+void fastcall kernel_set_interface_mode (int mode)
+{
+ char temp_buf[80];
+ char *mark;
+
+ inter_input_mode = mode;
+ kernel_load_interface();
+
+ image_inter_marker = 1;
+ image_inter_list[0].flags = IMAGE_REFRESH;
+ image_inter_list[0].segment_id = -1;
+
+ /* Set up interface animation clock */
+
+ inter_base_time = timer_read();
+
+ left_command = -1;
+ left_action = -1;
+ left_inven = -1;
+
+ /* Initialize interface work area */
+
+ if (!viewing_at_y) {
+ buffer_rect_copy (scr_inter_orig, scr_inter, 0, 0, video_x, inter_size_y);
+
+ /* Initialize interface grammar driver */
+
+ if (kernel_mode == KERNEL_ACTIVE_CODE) matte_inter_frame (false, false);
+ }
+
+ inter_init_sentence();
+ inter_setup_hotspots();
+
+ if (!viewing_at_y) inter_prepare_background();
+
+ kernel_refresh_dynamic();
+}
+
diff --git a/engines/mads/madsv2/core/kernel_o.h b/engines/mads/madsv2/core/kernel_o.h
new file mode 100644
index 00000000000..f07b9a673df
--- /dev/null
+++ b/engines/mads/madsv2/core/kernel_o.h
@@ -0,0 +1,36 @@
+/* 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 MADS_CORE_KERNEL_O_H
+#define MADS_CORE_KERNEL_O_H
+
+namespace MADS {
+namespace MADSV2 {
+
+#define kernel_init_dialog() inter_reset_dialog()
+#define kernel_dialog(q) inter_add_dialog(quote_string(kernel.quotes, q), q)
+
+extern void kernel_set_interface_mode(int mode);
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/kernel_q.cpp b/engines/mads/madsv2/core/kernel_q.cpp
new file mode 100644
index 00000000000..9e145881e85
--- /dev/null
+++ b/engines/mads/madsv2/core/kernel_q.cpp
@@ -0,0 +1,25 @@
+/*
+/* kernel_q.c by Brian Reynolds 11-Jan-93
+/*
+/* Manually adjusts room scaling parameters.
+*/
+
+#include <general.mac>
+
+#include "kernel.mac"
+#include "kernel_1.h"
+
+#pragma optimize ("weglt", on)
+
+void fastcall kernel_room_scale (int front_y, int front_scale,
+ int back_y, int back_scale)
+{
+ room->front_y = front_y;
+ room->front_scale = front_scale;
+ room->back_y = back_y;
+ room->back_scale = back_scale;
+
+ kernel_room_bound_dif = room->front_y - room->back_y;
+ kernel_room_scale_dif = room->front_scale - room->back_scale;
+}
+
diff --git a/engines/mads/madsv2/core/kernel_r.cpp b/engines/mads/madsv2/core/kernel_r.cpp
new file mode 100644
index 00000000000..49dcd80ef78
--- /dev/null
+++ b/engines/mads/madsv2/core/kernel_r.cpp
@@ -0,0 +1,147 @@
+/*
+/* kernel_r.c by Brian Reynolds 1-Apr-93
+*/
+
+#include <string.h>
+
+#include <general.mac>
+
+#include <matte.h>
+#include <inter.h>
+#include <mem.h>
+#include <buffer.h>
+#include <room.h>
+#include <pal.h>
+#include <error.h>
+#include <anim.h>
+#include <vocab.h>
+#include <timer.h>
+#include <mouse.h>
+#include <video.h>
+#include <mcga.h>
+#include <rail.h>
+#include <cycle.h>
+#include <tile.h>
+#include <sprite.h>
+#include <popup.h>
+
+#include "kernel.mac"
+#include "kernel_1.h"
+#include "kernel_2.h"
+#include "kernel_8.h"
+#include "kernel_d.h"
+#include "kernel_o.h"
+
+
+#pragma optimize ("weglt", on)
+
+
+
+/*
+/* kernel_background_shutdown()
+/*
+/* Room level system shutdown.
+*/
+void fastcall kernel_background_shutdown (void)
+{
+ /* Remove our palette shadowing list */
+
+ pal_activate_shadow (NULL);
+
+ /* Dump the picture & attribute buffers, along with the room header */
+
+ if (room != NULL) {
+ room_unload (room,
+ &scr_orig,
+ &scr_depth,
+ &scr_walk,
+ &scr_special,
+ &picture_map,
+ &depth_map);
+ room = NULL;
+ }
+}
+
+
+int fastcall kernel_background_startup (int new_room, int initial_variant)
+{
+ int error_flag = true;
+ int load_flags;
+ int error_code = 0;
+ int error_data = 0;
+
+ /* Make a note of the new room number & variant */
+
+ previous_room = room_id;
+ room_id = new_room;
+ room_variant = initial_variant;
+
+ /* Start a brand new palette, reserving the proper # of colors */
+
+ pal_init (KERNEL_RESERVED_LOW_COLORS, KERNEL_RESERVED_HIGH_COLORS);
+ pal_white (master_palette);
+
+ /* Initialize the matteing system */
+
+ matte_init (false);
+
+ /* Initialize graphics sequence data structures */
+
+ kernel_seq_init();
+ kernel_message_init();
+
+ /* Activate the main shadow list */
+
+ pal_activate_shadow (&kernel_shadow_main);
+
+ /* Load header, picture, and attribute screen for this room */
+
+ load_flags = ROOM_LOAD_HARD_SHADOW;
+ if (kernel.translating) load_flags |= ROOM_LOAD_TRANSLATE;
+
+ room = room_load (room_id, room_variant, NULL,
+ &scr_orig,
+ &scr_depth,
+ &scr_walk,
+ &scr_special,
+ &picture_map,
+ &depth_map,
+ &picture_resource,
+ &depth_resource,
+ tile_picture_handle,
+ tile_attribute_handle,
+ load_flags);
+ if (room == NULL) {
+ error_data = room_load_error;
+ error_code = ERROR_KERNEL_NO_ROOM;
+ goto done;
+ }
+
+ tile_pan (&picture_map, picture_view_x, picture_view_y);
+ tile_pan (&depth_map, picture_view_x, picture_view_y);
+
+ /* Set up color cycling table for this room */
+
+ cycle_init (&room->cycle_list, false);
+
+ /* Initialize the graphics image lists */
+
+ image_marker = 1;
+ image_list[0].flags = IMAGE_REFRESH;
+ image_list[0].segment_id = KERNEL_SEGMENT_SYSTEM;
+
+ /* Mark the boundary between interface and room sprite series */
+
+ kernel_room_series_marker = series_list_marker;
+
+ error_flag = false;
+
+done:
+ if (error_flag) {
+ error_check_memory();
+ error_report (error_code, ERROR, MODULE_KERNEL, room_id, error_data);
+ kernel_background_shutdown();
+ }
+ return (error_flag);
+}
+
diff --git a/engines/mads/madsv2/core/lock.h b/engines/mads/madsv2/core/lock.h
new file mode 100644
index 00000000000..acad379e386
--- /dev/null
+++ b/engines/mads/madsv2/core/lock.h
@@ -0,0 +1,66 @@
+/* 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 MADS_CORE_LOCK_H
+#define MADS_CORE_LOCK_H
+
+#include "mads/madsv2/core/general.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+extern char *lock_program_name;
+extern char *lock_search_mark;
+extern int lock_search_length;
+extern word *lock_hash_value;
+
+/* lock_2.cpp */
+word lock_get_disk_hash(void);
+
+/* lock_3.cpp */
+long lock_search_hash_offset(void);
+
+/* lock_4.cpp */
+void lock_write_new_hash(void);
+
+/* lock_5.cpp */
+int lock_get_copy_code(void);
+
+/* lock_6.cpp */
+void lock_short_protection_check(void);
+
+/* lock_7.cpp */
+int lock_verification(void);
+void lock_sabotage(void);
+
+/* lock_8.cpp */
+void lock_long_protection_check(void);
+
+/* lock_9.cpp */
+void lock_secret_protection_check(void);
+
+/* lock_a.cpp */
+void lock_preliminary_check(void);
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/matte.h b/engines/mads/madsv2/core/matte.h
index 261649416fb..924fe643b8d 100644
--- a/engines/mads/madsv2/core/matte.h
+++ b/engines/mads/madsv2/core/matte.h
@@ -71,7 +71,7 @@ typedef struct MatteBuf {
typedef Matte *MattePtr;
-extern SeriesPtr series_list[SERIES_LIST_SIZE]; /* Master sprite list */
+extern SeriesPtr series_list[SERIES_LIST_SIZE + SERIES_BONUS_SIZE]; /* Master sprite list */
extern char series_name[SERIES_LIST_SIZE][9]; /* Master sprite name list*/
extern byte series_user[SERIES_LIST_SIZE]; /* Master sprite user list*/
@@ -133,7 +133,7 @@ int matte_map_work_screen(void);
void matte_frame(int special_effect, int full_screen);
/* matte_1.c */
-void matte_init_series(void);
+//void matte_init_series(void);
int matte_load_series(char *name,
int load_flags,
int bonus_series_number);
@@ -142,7 +142,7 @@ int matte_allocate_series(SeriesPtr series,
int bonus_series_number);
/* matte_1.c */
-void matte_init_messages(void);
+//void matte_init_messages(void);
int matte_add_message(FontPtr font, char *text,
int x, int y, int message_color,
int auto_spacing);
diff --git a/engines/mads/madsv2/core/matte_1.cpp b/engines/mads/madsv2/core/matte_1.cpp
new file mode 100644
index 00000000000..dd8933551cc
--- /dev/null
+++ b/engines/mads/madsv2/core/matte_1.cpp
@@ -0,0 +1,1103 @@
+/* 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 "mads/madsv2/core/general.h"
+#include "mads/madsv2/core/sprite.h"
+#include "mads/madsv2/core/buffer.h"
+#include "mads/madsv2/core/mouse.h"
+#include "mads/madsv2/core/font.h"
+#include "mads/madsv2/core/sort.h"
+#include "mads/madsv2/core/mem.h"
+#include "mads/madsv2/core/pal.h"
+#include "mads/madsv2/core/magic.h"
+#include "mads/madsv2/core/mcga.h"
+#include "mads/madsv2/core/tile.h"
+#include "mads/madsv2/core/ems.h"
+#include "mads/madsv2/core/keys.h"
+#include "mads/madsv2/core/timer.h"
+
+#define word_align_mattes
+#ifndef disable_error_check
+#include "mads/madsv2/core/error.h"
+#endif
+
+#include "mads/madsv2/core/video.h"
+#include "mads/madsv2/core/anim.h"
+#include "mads/madsv2/core/matte.h"
+
+#ifdef show_mattes
+#include "mads/madsv2/core/screen.h"
+#include "mads/madsv2/core/keys.h"
+#endif
+
+namespace MADS {
+namespace MADSV2 {
+
+/* Global data structures */
+
+SeriesPtr series_list[SERIES_LIST_SIZE + SERIES_BONUS_SIZE];
+char series_name[SERIES_LIST_SIZE][9];
+byte series_user[SERIES_LIST_SIZE];
+
+Image image_list [IMAGE_LIST_SIZE];
+Matte matte_list [MATTE_LIST_SIZE];
+
+byte depth_list_id[MATTE_LIST_SIZE];
+word depth_list [MATTE_LIST_SIZE];
+
+Message message_list [MESSAGE_LIST_SIZE];
+
+int series_list_marker = 0;
+
+int picture_view_x = 0; /* Absolute picture view coordinates */
+int picture_view_y = 0;
+
+int viewing_at_x = 0; /* Viewport alignment from top/left screen */
+int viewing_at_y = 0;
+
+int matte_disable_screen_update = false;
+
+byte attr_packed = false;
+
+byte image_marker = 0;
+
+Buffer scr_main = { 0, 0, NULL }; /* Full screen work buffer */
+Buffer scr_work = { 0, 0, NULL }; /* Room art work buffer */
+
+Buffer scr_orig = { 0, 0, NULL }; /* Room original art buffer */
+Buffer scr_depth = { 0, 0, NULL }; /* Depth code buffer */
+Buffer scr_walk = { 0, 0, NULL }; /* Walk code buffer */
+Buffer scr_special={ 0, 0, NULL }; /* Special code buffer */
+
+int matte_guard_depth_0 = false; /* Guard popup window depth */
+
+int work_screen_ems_handle = -1; /* Work screen in EMS */
+
+TileMapHeader picture_map, depth_map; /* Tile maps */
+TileResource picture_resource, depth_resource; /* Tile resources */
+
+
+int matte_map_work_screen() {
+ int error_flag = false;
+
+ if (work_screen_ems_handle >= 0) {
+ if (ems_mapping_changed) {
+ error_flag = ems_map_buffer(work_screen_ems_handle);
+ }
+ ems_mapping_changed = false;
+ }
+
+ return error_flag;
+}
+
+static void matte_init_series() {
+ int count;
+
+ series_list_marker = 0;
+
+ for (count = 0; count < SERIES_LIST_SIZE; count++) {
+ series_list[count] = NULL;
+ series_name[count][0] = 0;
+ series_user[count] = 0;
+ }
+}
+
+int matte_allocate_series(SeriesPtr series, int bonus_series_number) {
+ int handle;
+
+ handle = -1;
+ if (bonus_series_number) {
+ handle = SERIES_LIST_SIZE + bonus_series_number - 1;
+ series_list[handle] = series;
+ } else {
+ if (series_list_marker < SERIES_LIST_SIZE) {
+ handle = series_list_marker++;
+ series_list[handle] = series;
+ }
+ }
+#ifndef disable_error_check
+ if (handle < 0) {
+ error_report(ERROR_SERIES_LIST_FULL, ERROR, MODULE_MATTE, SERIES_LIST_SIZE, 0);
+ }
+#endif
+
+ return handle;
+}
+
+int matte_load_series(char *name, int load_flags, int bonus_series_number) {
+ int found = false;
+ int valid_name = true;
+ int handle = -1;
+ int count;
+ char name_buf[15];
+ char *mark;
+ SeriesPtr series;
+
+
+ strncpy(name_buf, name, 14);
+ name_buf[13] = 0;
+ if (name_buf[0] == '*') {
+ Common::strcpy_s(name_buf, &name_buf[1]);
+ }
+ mark = strchr(name_buf, '.');
+ if (mark != NULL) *mark = 0;
+
+ if ((strlen(name) > 13) || (strlen(name_buf) > 8)) {
+ Common::strcpy_s(name_buf, "%%");
+ valid_name = false;
+ }
+ mads_strupr(name_buf);
+
+ if (valid_name && !bonus_series_number) {
+ for (count = 0; !found && (count < SERIES_LIST_SIZE); count++) {
+ if (series_user[count]) {
+ if (!strcmp(series_name[count], name_buf)) {
+ found = true;
+ handle = count;
+ series_user[count]++;
+ }
+ }
+ }
+ }
+
+ if (!found) {
+
+ series = sprite_series_load(name, load_flags);
+ if (series == NULL) {
+ goto done;
+ }
+
+ handle = matte_allocate_series(series, bonus_series_number);
+ if (handle < 0) {
+ goto done;
+ }
+
+ if (handle < SERIES_LIST_SIZE) {
+ Common::strcpy_s(series_name[handle], name_buf);
+ series_user[handle] = 1;
+ }
+ }
+
+done:
+ return handle;
+}
+
+void matte_deallocate_series(int id, int free_memory) {
+ if (id < 0) goto done;
+
+ if (id < SERIES_LIST_SIZE) {
+ if (series_user[id]) {
+ series_user[id]--;
+ if (series_user[id]) goto done;
+ }
+ }
+
+ sprite_free(&series_list[id], free_memory);
+ series_list[id] = NULL;
+
+ /* Protect against memory fragmentation */
+
+ if (id < SERIES_LIST_SIZE) {
+ if (id == series_list_marker - 1) {
+ series_list_marker--;
+ } else {
+#ifndef disable_error_check
+ error_report(ERROR_WRONG_SERIES_UNLOAD_ORDER, WARNING, MODULE_MATTE, id, series_list_marker);
+#endif
+ }
+ }
+
+done:
+ ;
+}
+
+static void matte_init_messages() {
+ int count;
+ for (count = 0; count < MESSAGE_LIST_SIZE; count++) {
+ message_list[count].active = false;
+ }
+}
+
+void matte_init(int init_series) {
+ matte_init_messages();
+ if (init_series) matte_init_series();
+
+ image_marker = 1;
+ image_list[0].flags = IMAGE_REFRESH;
+ image_list[0].segment_id = (byte)-1;
+}
+
+int matte_allocate_image() {
+ int result;
+
+ if (image_marker >= IMAGE_LIST_SIZE) {
+#if !defined(disable_error_check)
+ error_report(ERROR_IMAGE_LIST_FULL, ERROR, MODULE_MATTE, IMAGE_LIST_SIZE, image_marker);
+#endif
+ result = -1;
+ } else {
+ result = image_marker++;
+ }
+
+ return result;
+}
+
+void matte_refresh_work() {
+ int id;
+
+ id = matte_allocate_image();
+ image_list[id].flags = IMAGE_REFRESH;
+ image_list[id].segment_id = (byte)-1;
+}
+
+int matte_add_message(FontPtr font, char *text, int x, int y, int message_color, int auto_spacing) {
+ int message_handle;
+ int count;
+
+ message_handle = -1;
+ for (count = 0; (count < MESSAGE_LIST_SIZE) && (message_handle < 0); count++) {
+ if (!message_list[count].active) {
+ message_handle = count;
+ message_list[message_handle].x = x;
+ message_list[message_handle].y = y;
+ message_list[message_handle].font = font;
+ message_list[message_handle].text = text;
+ message_list[message_handle].xs = font_string_width(font, text, auto_spacing);
+ message_list[message_handle].ys = font->max_y_size;
+ message_list[message_handle].main_color = message_color;
+ message_list[message_handle].spacing = (char)auto_spacing;
+ message_list[message_handle].status = 1;
+ message_list[message_handle].active = true;
+ }
+ }
+#ifndef disable_error_check
+#ifndef disable_minor_error
+ if (message_handle < 0) {
+ error_report(ERROR_MESSAGE_LIST_FULL, ERROR, MODULE_MATTE, MESSAGE_LIST_SIZE, 0);
+ }
+#endif
+#endif
+ return message_handle;
+}
+
+void matte_clear_message(int handle) {
+ message_list[handle].status = -1;
+}
+
+void bound_matte(MattePtr matte, int xs, int ys, int maxx, int maxy) {
+ int x2, y2;
+
+#if defined(word_align_mattes)
+ if (matte->x & 1) {
+ matte->x -= 1;
+ xs++;
+ }
+ if (xs & 1) {
+ xs++;
+ }
+#endif
+
+ x2 = matte->x + xs - 1; /* Determine right most point */
+ matte->x = MAX(0, matte->x); /* Scale coordinates to work */
+ x2 = MAX(0, x2);
+ x2 = MIN((maxx - 1), x2);
+ matte->xs = (x2 - matte->x) + 1; /* Determine horizontal size */
+
+ matte->xh = matte->xs >> 1; /* Set half-width */
+ matte->xc = matte->x + (((matte->xs + 1) >> 1) - 1); /* Set center mark */
+
+ y2 = matte->y + ys - 1; /* Determine lower most point */
+ matte->y = MAX(0, matte->y); /* Scale coordinates to work */
+ y2 = MAX(0, y2);
+ y2 = MIN((maxy - 1), y2);
+ matte->ys = (y2 - matte->y) + 1; /* Determine vertical size */
+
+ matte->yh = matte->ys >> 1; /* Set half-height */
+ matte->yc = matte->y + (((matte->ys + 1) >> 1) - 1); /* Set center mark */
+
+ matte->valid = true;
+}
+
+/*
+/* static make_matte (ImagePtr image, MattePtr matte)
+/*
+/* Proposes a matte-ing scheme (matte) for the specified image. This
+/* initial matte is the smallest possible rectangle which will completely
+/* enclose its sprite.
+*/
+static void make_matte(ImagePtr image, MattePtr matte) {
+ SpritePtr sprite;
+ int xs, ys;
+
+ if (image->flags == IMAGE_REFRESH) {
+ matte->x = 0;
+ matte->y = 0;
+ xs = scr_work.x;
+ ys = scr_work.y;
+ } else {
+
+ matte->x = image->x - picture_map.pan_x;
+ matte->y = image->y - picture_map.pan_y;
+
+ sprite = &series_list[image->series_id]->index[(image->sprite_id & SPRITE_MASK) - 1];
+
+ if (image->scale == IMAGE_UNSCALED) {
+ xs = sprite->xs;
+ ys = sprite->ys;
+ } else {
+ xs = (50 + (sprite->xs * image->scale)) / 100;
+ ys = (50 + (sprite->ys * image->scale)) / 100;
+ matte->x -= (xs >> 1);
+ matte->y -= (ys - 1);
+ }
+ }
+
+ bound_matte(matte, xs, ys, scr_work.x, scr_work.y);
+}
+
+static void make_message_matte(int handle, MattePtr matte) {
+ matte->x = message_list[handle].x;
+ matte->y = message_list[handle].y;
+ bound_matte(matte, message_list[handle].xs, message_list[handle].ys,
+ scr_work.x, scr_work.y);
+}
+
+/*
+/* static int check_collisions (MattePtr matte1, MattePtr matte2)
+/*
+/* matte1, matte2 = pointers to mattes to be checked for
+/* collisions (i.e. overlapping areas).
+/*
+/* Returns TRUE if the two specified mattes overlap and need to be
+/* combined into one big matte.
+/*
+/* (Algorithm: overlap if on each axis the distance between the centers
+/* of the mattes is less-than/equal-to the sum of the half widths)
+*/
+static int check_collisions(MattePtr matte1, MattePtr matte2) {
+ return (ABS(matte1->xc - matte2->xc) <= (matte1->xh + matte2->xh)) &&
+ (ABS(matte1->yc - matte2->yc) <= (matte1->yh + matte2->yh));
+}
+
+/*
+/* static int combine_mattes (MattePtr matte1, MattePtr matte2)
+/*
+/* matte1, matte2 = pointers to the mattes to be merged (matte1
+/* will receive the combined matte).
+/*
+*/
+static void combine_mattes(MattePtr matte1, MattePtr matte2) {
+ int highx, highy;
+
+ /* Get the maximum x and y values (+1) of the two mattes */
+
+ highx = MAX((matte1->x + matte1->xs), (matte2->x + matte2->xs));
+ highy = MAX((matte1->y + matte1->ys), (matte2->y + matte2->ys));
+
+ /* Get the minimum x and y values of the two mattes; these will */
+ /* serve as the x/y base position of the combined matte. */
+
+ matte1->x = MIN(matte1->x, matte2->x);
+ matte1->y = MIN(matte1->y, matte2->y);
+
+ /* Subtract the minimums from the maximums+1 to get the new matte's */
+ /* size. Then, compute the half heights/widths and the center points. */
+ /* Note that since we are doing integer "division", we must adjust to */
+ /* make sure that lost bits do not result in a failed collision test. */
+
+ matte1->xs = highx - matte1->x;
+ matte1->xh = matte1->xs >> 1;
+ matte1->xc = matte1->x + (((matte1->xs + 1) >> 1) - 1);
+
+ matte1->ys = highy - matte1->y;
+ matte1->yh = matte1->ys >> 1;
+ matte1->yc = matte1->y + (((matte1->ys + 1) >> 1) - 1);
+
+ /* Mark matte2 as EMPTY, but leave behind a pointer to matte1 */
+
+ matte2->valid = false;
+ matte2->y = (int)matte1;
+
+ /* Set matte1's update flag TRUE; we need to redraw everything in */
+ /* this matte. */
+
+ matte1->changed = true;
+}
+
+/*
+/* static void filter_matte_list (MattePtr matte, int size, int base_index)
+/*
+/* size length of the matte list to be filtered
+/* base_index index at which unfiltered mattes begin.
+/*
+/* Filters the matte list, resolving any collisions by combining
+/* the two mattes into one big matte. Since the filter iterates until
+/* no collisions are found, the combined matte could again collide
+/* with another matte, and so forth (so the worst case is one BIG
+/* matte for all of the active series). Note that there is no need
+/* to combine two overlapping mattes when *neither* has its changed
+/* flag set. The "size" parameter is used to specify whether to
+/* filter mattes from this round only, or to merge in the old matte
+/* list from last round (which is used to perform erasures). "Base_index"
+/* can be used when merging an unfiltered list into a pre-filtered list
+/* in order to avoid checking the originals against each other all over
+/* again.
+*/
+void filter_matte_list(MattePtr matte, int size, int base_index) {
+ int index1, index2, any_more;
+ MattePtr matte1;
+ MattePtr matte2;
+
+ /* Loop until we make a perfect pass (no collisions) through list */
+
+ for (any_more = true; any_more;) {
+ any_more = false;
+
+ /* Outer index counts through unfiltered mattes only */
+
+ matte1 = &matte[base_index] - 1;
+ for (index1 = base_index; index1 < size; index1++) {
+ matte1++;
+
+ /* Ignore empty matte blocks */
+
+ if (matte1->valid) {
+
+ /* Inner index counts through all mattes with lower indices */
+ /* than our current outer index. */
+
+ matte2 = matte - 1;
+ for (index2 = 0; index2 < index1; index2++) {
+ matte2++;
+
+ /* Again, ignore empty matte blocks */
+
+ if (matte2->valid) {
+
+ /* We've got two real mattes; check for collisions */
+
+ if (check_collisions(matte1, matte2)) {
+
+ /* Mattes overlap; check if either has changed flag set */
+
+ if (matte1->changed || matte2->changed) {
+
+ /* Active ("changed") matte triggers collision; combine into */
+ /* one big messy matte. */
+
+ combine_mattes(matte1, matte2);
+
+ /* Mark that this is no longer a perfect pass; we'll have to */
+ /* loop through the whole thing again. */
+
+ any_more = true;
+
+ /* And now, for your pleasure, we have no less */
+ /* than EIGHT consecutive close braces!!! What */
+ /* fun! Whoopee! This is C's finest hour! */
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+static void matte_quick_to_black(byte *special_pal, int ticks) {
+ int going;
+ byte *source;
+ byte *dest;
+ long fade_clock;
+ long now_clock;
+ byte increments[768];
+
+ source = special_pal;
+ dest = increments;
+
+ /* Build increment table: each entry is ceil(source[i] / 4), minimum 1 */
+ for (int i = 0; i < 768; i++)
+ {
+ byte inc = (source[i] >> 2) + ((source[i] & 3) ? 1 : 0);
+ if (inc == 0)
+ inc = 1;
+ dest[i] = inc;
+ }
+
+ do {
+ going = false;
+ fade_clock = timer_read_600() + ticks;
+
+ for (int i = 0; i < 768; i++) {
+ byte val = source[i];
+ byte decr = dest[i];
+
+ if (val >= decr)
+ val -= decr;
+ else
+ val = 0;
+
+ source[i] = val;
+
+ if (val != 0)
+ going = true;
+ }
+
+ mcga_setpal((Palette *)special_pal);
+
+ do {
+ now_clock = timer_read_600();
+ } while (now_clock < fade_clock);
+
+ } while (going);
+}
+
+static void matte_quick_from_black(byte *special_pal, int ticks) {
+ int going;
+ byte *source;
+ byte *dest;
+ byte *special;
+ byte increments[768];
+ long fade_clock;
+ long now_clock;
+
+ source = &master_palette[0].r;
+ special = increments;
+ dest = special_pal;
+
+ /* Build increment table from master palette: ceil(source[i] / 4), minimum 1 */
+ for (int i = 0; i < 768; i++) {
+ byte inc = (source[i] >> 2) + ((source[i] & 3) ? 1 : 0);
+ if (inc == 0)
+ inc = 1;
+ special[i] = inc;
+ }
+
+ do {
+ going = false;
+ fade_clock = timer_read_600() + ticks;
+
+ for (int i = 0; i < 768; i++) {
+ byte current = dest[i]; /* current fading value (starts at black) */
+ byte target = source[i]; /* master palette ceiling for this channel */
+ byte inc = special[i];
+
+ if ((int)current + inc >= target)
+ current = target; /* clamp to target; channel is done */
+ else
+ {
+ current += inc;
+ going = true; /* still short of target, keep going */
+ }
+
+ dest[i] = current;
+ }
+
+ mcga_setpal((Palette *)special_pal);
+
+ do {
+ now_clock = timer_read_600();
+ } while (now_clock < fade_clock);
+
+ } while (going);
+}
+
+static void matte_special_effect(int special_effect, int full_screen) {
+ int count;
+ int pixel_rate;
+ byte *background_swap;
+ Palette special_pal;
+ Buffer *work_screen;
+ Buffer scr_live = { video_y, video_x, mcga_video };
+
+ work_screen = full_screen ? &scr_main : &scr_work;
+
+ if (viewing_at_y) {
+ work_screen = &scr_work;
+ }
+
+ mouse_hide();
+
+ if (!timer_low_semaphore) {
+ if ((special_effect == MATTE_FX_FADE_FROM_BLACK) ||
+ (special_effect == MATTE_FX_FADE_THRU_BLACK)) {
+ if (mem_get_avail() < 3600) special_effect = MATTE_FX_FAST_AND_FANCY;
+ }
+
+ if (special_effect == MATTE_FX_FAST_AND_FANCY) {
+ if (viewing_at_y || (mem_get_avail() < sizeof(Palette))) {
+ special_effect = MATTE_FX_FAST_THRU_BLACK;
+ }
+ }
+ }
+
+ switch (special_effect) {
+ case MATTE_FX_FADE_FROM_BLACK:
+ case MATTE_FX_FADE_THRU_BLACK:
+ for (count = 0; count < 3; count++) {
+ magic_color_flags[count] = false;
+ magic_color_values[count] = 0;
+ }
+
+ if (special_effect == MATTE_FX_FADE_THRU_BLACK) {
+ mcga_getpal(&special_pal);
+ matte_quick_to_black(&special_pal[0].r, 1);
+ /* magic_fade_to_grey (special_pal, NULL, 0, 256, 0, 1, 1, 16); */
+
+ buffer_fill(scr_live, 0);
+ }
+
+ memset(special_pal, 0, sizeof(Palette));
+ mcga_setpal(&special_pal);
+
+ video_update(work_screen, 0, 0,
+ viewing_at_x, viewing_at_y,
+ work_screen->x, work_screen->y);
+
+ matte_quick_from_black(&special_pal[0].r, 1);
+ /* magic_fade_from_grey (special_pal, master_palette, 0, 256, 0, 1, 1, 16); */
+ break;
+
+ case MATTE_FX_CORNER_LOWER_LEFT:
+ case MATTE_FX_CORNER_LOWER_RIGHT:
+ case MATTE_FX_CORNER_UPPER_LEFT:
+ case MATTE_FX_CORNER_UPPER_RIGHT:
+ magic_screen_change_corner(work_screen, master_palette,
+ (special_effect - MATTE_FX_CORNER_LOWER_LEFT) + 1,
+ 0, 0,
+ viewing_at_x, viewing_at_y,
+ MAGIC_SECRET_FUJI, true, 1);
+ break;
+
+ case MATTE_FX_EDGE_LEFT:
+ case MATTE_FX_EDGE_RIGHT:
+ magic_screen_change_edge(work_screen, master_palette,
+ special_effect - MATTE_FX_EDGE_LEFT,
+ 0, 0,
+ viewing_at_x, viewing_at_y,
+ MAGIC_SECRET_FUJI, true, 1);
+ break;
+
+ case MATTE_FX_CIRCLE_OUT_SLOW:
+ case MATTE_FX_CIRCLE_IN_SLOW:
+ case MATTE_FX_CIRCLE_OUT_FAST:
+ case MATTE_FX_CIRCLE_IN_FAST:
+ pixel_rate = 1;
+ if (special_effect >= MATTE_FX_CIRCLE_OUT_FAST) {
+ special_effect -= 2;
+ pixel_rate = 2;
+ }
+ magic_screen_change_circle(work_screen, master_palette,
+ special_effect - MATTE_FX_CIRCLE_OUT_SLOW,
+ 0, 0,
+ viewing_at_x, viewing_at_y,
+ MAGIC_SECRET_FUJI, true, 1, pixel_rate);
+ break;
+
+ case MATTE_FX_FAST_THRU_BLACK:
+ memset(special_pal, 0, sizeof(Palette));
+ mcga_setpal(&special_pal);
+ buffer_fill(scr_live, 0);
+ video_update(work_screen, 0, 0, viewing_at_x, viewing_at_y,
+ work_screen->x, work_screen->y);
+ mcga_setpal(&master_palette);
+ break;
+
+ case MATTE_FX_FAST_AND_FANCY:
+ default:
+ background_swap = &special_pal[0].r;
+ magic_swap_foreground(background_swap, master_palette);
+ buffer_rect_translate(*work_screen, scr_live,
+ 0, 0, viewing_at_x, viewing_at_y,
+ work_screen->x, work_screen->y,
+ background_swap);
+ mcga_setpal(&master_palette);
+ video_update(work_screen, 0, 0,
+ viewing_at_x, viewing_at_y,
+ work_screen->x, work_screen->y);
+ break;
+ }
+
+ mouse_show();
+}
+
+void matte_frame(int special_effect, int full_screen) {
+ Matte *matte;
+ Image *image;
+ int id;
+ int id2;
+ int x, y;
+ int depth_size;
+ int beware_the_mouse = false;
+ int any_refresh;
+ byte new_marker;
+ byte high_color, low_color;
+ Matte *matte2;
+ Image *image2;
+ Message *message;
+ SpritePtr sprite;
+#ifdef show_mattes
+ char temp_buf[80];
+ int count;
+#endif
+
+ /* Make sure work buffer is mapped into the page frame */
+ matte_map_work_screen();
+
+ any_refresh = false;
+
+ image = image_list;
+ matte = matte_list;
+ for (id = 0; id < (int)image_marker; id++) {
+ if (image->flags < IMAGE_STATIC) {
+ matte->changed = true;
+ make_matte(image, matte);
+
+ if (image->flags == IMAGE_DELTA) {
+ x = image->x;
+ y = image->y;
+ if (image->scale != IMAGE_UNSCALED) {
+ sprite = &series_list[image->series_id]->index[(image->sprite_id & SPRITE_MASK) - 1];
+ x -= (sprite->xs >> 1);
+ y -= (sprite->ys - 1);
+ }
+
+ if ((image->depth <= 1) && !matte_guard_depth_0) {
+ sprite_draw(series_list[image->series_id], image->sprite_id,
+ &scr_orig,
+ x - picture_map.pan_base_x,
+ y - picture_map.pan_base_y);
+ } else {
+ sprite_draw_3d_big(series_list[image->series_id],
+ image->sprite_id,
+ &scr_orig, &scr_depth,
+ x - picture_map.pan_base_x,
+ y - picture_map.pan_base_y,
+ image->depth, 0, 0);
+ }
+ }
+
+ } else {
+ matte->valid = false;
+ }
+
+ if (image->flags == IMAGE_REFRESH) {
+ any_refresh = true;
+ }
+
+ matte++;
+ image++;
+ }
+
+ for (id = image_marker; id < FIRST_MESSAGE_MATTE; id++) {
+ matte->valid = false;
+ matte++;
+ /* matte_list[id].valid = false; */
+ }
+
+ message = message_list;
+ for (id = 0; id < MESSAGE_LIST_SIZE; id++) {
+ /* index = id + FIRST_MESSAGE_MATTE; */
+ if ((message->status < 0) && message->active) {
+ matte->changed = true;
+ make_message_matte(id, matte);
+ } else {
+ matte->valid = false;
+ }
+ message++;
+ matte++;
+ }
+
+ /* Erasures */
+
+ if (!any_refresh) {
+ filter_matte_list(matte_list, MATTE_LIST_SIZE, 1);
+
+ matte = matte_list;
+
+ for (id = 0; id < MATTE_LIST_SIZE; id++) {
+
+ if (matte->valid) {
+
+ if ((matte->xs > 0) && (matte->ys > 0)) {
+
+ buffer_rect_copy_2(scr_orig, scr_work,
+ matte->x + picture_map.pan_offset_x,
+ matte->y + picture_map.pan_offset_y,
+ matte->x, matte->y,
+ matte->xs, matte->ys);
+
+ }
+ }
+
+ matte++;
+ }
+
+ } else {
+ buffer_rect_copy_2(scr_orig, scr_work,
+ picture_map.pan_offset_x,
+ picture_map.pan_offset_y,
+ 0, 0,
+ video_x, display_y);
+ }
+
+ matte = matte_list;
+ image = image_list;
+ for (id = 0; id < (int)image_marker; id++) {
+ if (image->flags >= IMAGE_STATIC) {
+ make_matte(image, matte);
+ matte->changed = (byte)(image->flags > IMAGE_STATIC);
+ image->flags = IMAGE_STATIC;
+ }
+ matte++;
+ image++;
+ }
+
+ matte = &matte_list[FIRST_MESSAGE_MATTE];
+ message = message_list;
+ for (id = 0; id < MESSAGE_LIST_SIZE; id++) {
+ if (message->active) {
+ if (message->status >= 0) {
+ make_message_matte(id, matte);
+ matte->changed = (byte)(message->status > 0);
+ }
+ }
+ matte++;
+ message++;
+ }
+
+ /* Check our new matte list for collisions */
+
+ if (!any_refresh) filter_matte_list(matte_list, MATTE_LIST_SIZE, 1);
+
+ /* Now, create the depth list for our currently active series. Only */
+ /* create depth list entries for those images which belong to mattes */
+ /* that have their "changed" flags set (i.e. mattes which need to be */
+ /* redrawn this round. */
+
+ image = image_list;
+ matte = matte_list;
+ for (id = depth_size = 0; id < (int)image_marker; id++) {
+
+ if (image->flags >= IMAGE_STATIC) {
+
+ /* Search through the matte list to find the matte of which this */
+ /* image is a part. */
+
+ for (matte2 = matte; !matte2->valid; matte2 = (MattePtr)matte2->y);
+
+ /* If its matte is being updated, make a depth list entry for */
+ /* our sprite. */
+
+ if (matte2->changed || any_refresh) {
+ depth_list_id[depth_size] = (byte)id;
+ depth_list[depth_size] = 16 - image->depth;
+ depth_size++;
+ }
+ }
+ matte++;
+ image++;
+ }
+
+ /* Sort the depth list so that "deeper" sprites will be drawn first */
+ /* and thus appear "behind" the other "nearer" sprites. */
+
+ sort_insertion_16(depth_size, depth_list_id, depth_list);
+
+ /* Now, run through our depth list, and for each entry, draw the */
+ /* indicated sprite into the work buffer. */
+
+ for (id = 0; id < depth_size; id++) {
+
+ /* Get the index for the series for this depth list entry */
+
+ id2 = depth_list_id[id];
+
+ /* Draw the sprite into the work buffer at the appropriate depth */
+
+ if (image_list[id2].scale >= 100) {
+ if (image_list[id2].scale == IMAGE_UNSCALED) {
+ x = image_list[id2].x - picture_map.pan_x;
+ y = image_list[id2].y - picture_map.pan_y;
+ } else {
+ sprite = &series_list[image_list[id2].series_id]->index[(image_list[id2].sprite_id & SPRITE_MASK) - 1];
+ x = image_list[id2].x - picture_map.pan_x - (sprite->xs >> 1);
+ y = image_list[id2].y - picture_map.pan_y - (sprite->ys - 1);
+ }
+ if ((image_list[id2].depth <= 1) && !matte_guard_depth_0) {
+ sprite_draw(series_list[image_list[id2].series_id],
+ image_list[id2].sprite_id,
+ &scr_work, x, y);
+ } else {
+ sprite_draw_3d_big(series_list[image_list[id2].series_id],
+ image_list[id2].sprite_id,
+ &scr_work, &scr_depth,
+ x, y,
+ image_list[id2].depth,
+ picture_map.pan_offset_x,
+ picture_map.pan_offset_y);
+ }
+ } else {
+ sprite_draw_3d_scaled_big(series_list[image_list[id2].series_id],
+ image_list[id2].sprite_id,
+ &scr_work, &scr_depth,
+ image_list[id2].x - picture_map.pan_x,
+ image_list[id2].y - picture_map.pan_y,
+ image_list[id2].depth,
+ image_list[id2].scale,
+ picture_map.pan_offset_x,
+ picture_map.pan_offset_y);
+ }
+ }
+
+ /* Now draw any messages that need to be updated */
+
+ message = message_list;
+ matte = &matte_list[FIRST_MESSAGE_MATTE];
+ for (id = 0; id < MESSAGE_LIST_SIZE; id++) {
+ if (message->active && (message->status >= 0)) {
+ for (matte2 = matte; !matte2->valid; matte2 = (MattePtr)matte2->y);
+ if (matte2->changed || any_refresh) {
+ high_color = (byte)message->main_color;
+ low_color = (byte)(message->main_color >> 8);
+ if (!low_color) low_color = high_color;
+ font_set_colors(-1,
+ high_color,
+ low_color,
+ 0);
+ font_write(message->font,
+ &scr_work, message->text,
+ message->x, message->y, message->spacing);
+ }
+ }
+ message++;
+ matte++;
+ }
+
+ /* Finally, run through our combined matte list, and update any */
+ /* areas of the screen flagged as "changed" by copying from the */
+ /* work screen to the live video screen. */
+
+ mouse_set_work_buffer(scr_work.data, scr_work.x);
+ mouse_set_view_port_loc(viewing_at_x, viewing_at_y,
+ viewing_at_x + scr_work.x - 1,
+ viewing_at_y + scr_work.y - 1);
+
+ mouse_freeze(); /* Lock out mouse driver */
+
+ if ((video_mode != ega_mode) && !special_effect) {
+ beware_the_mouse = mouse_refresh_view_port(); /* Prepare cursor overlay */
+ }
+
+ if (!matte_disable_screen_update) {
+
+ if (!special_effect) {
+
+ if (!any_refresh) {
+
+ matte = matte_list;
+
+ for (id = 0; id < MATTE_LIST_SIZE; id++) {
+
+ /* Get next matte */
+
+#ifdef show_mattes
+ sprintf(temp_buf, "(%d, %d) => (%d, %d) valid: %d changed: %d ",
+ matte->x, matte->y, matte->xs, matte->ys, matte->valid, matte->changed);
+ screen_show(temp_buf, 0, id);
+#endif
+
+ /* Ignore empty mattes, or images which did not change */
+
+ if (matte->valid && matte->changed && (matte->xs > 0) && (matte->ys > 0)) {
+
+ video_update(&scr_work,
+ matte->x, matte->y,
+ matte->x + viewing_at_x,
+ matte->y + viewing_at_y,
+ matte->xs, matte->ys);
+
+ }
+
+ matte++;
+ }
+
+ } else {
+ video_update(&scr_work,
+ 0, 0,
+ viewing_at_x,
+ viewing_at_y,
+ video_x, display_y);
+ }
+
+#ifdef sixteen_colors
+ if (video_mode == ega_mode) {
+ beware_the_mouse = mouse_refresh_view_port(); /* Prepare cursor overlay */
+ video_flush_ega(viewing_at_y, scr_work.y); /* Update the EGA screen */
+ }
+#endif
+ } else {
+ matte_special_effect(special_effect, full_screen);
+ /* pl sound_queue_flush(); */
+ }
+ }
+
+#ifdef show_mattes
+ keys_get();
+#endif
+
+ if (beware_the_mouse) {
+ mouse_refresh_done(); /* Remove cursor image from work buffer */
+ }
+
+ mouse_thaw(); /* Release the mouse driver */
+
+ /* Delete erasures from image list */
+
+ new_marker = 0;
+ image = image_list;
+ image2 = image_list;
+ for (id = 0; id < (int)image_marker; id++) {
+ if (image->flags >= IMAGE_STATIC) {
+ if (image != image2) {
+ *image2 = *image;
+ }
+ image2++;
+ new_marker++;
+ }
+ image++;
+ }
+ image_marker = new_marker;
+
+ /* Delete erasures from message list */
+
+ message = message_list;
+ for (id = 0; id < MESSAGE_LIST_SIZE; id++) {
+ if (message->status < 0) {
+ message->active = false;
+ message->status = 0;
+ }
+ message++;
+ }
+}
+
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/core/mem.h b/engines/mads/madsv2/core/mem.h
index 1eb430e5745..89747e79f48 100644
--- a/engines/mads/madsv2/core/mem.h
+++ b/engines/mads/madsv2/core/mem.h
@@ -51,29 +51,28 @@ extern long umb_min_free; /* Least UMB that was ever free */
extern void (*mem_manager_update)(); /* Called at memory updates */
extern int mem_manager_active; /* Flag if memory manager active */
-/* mem_1.c */
-void *fastcall mem_normalize(void *in);
-
-/* mem_2.c */
-void *fastcall mem_get(long size);
-void *fastcall mem_get_name(long size, char *block_name);
-int mem_free(void *block);
-int mem_adjust(void *target, long size);
-void mem_save_free(void);
-void mem_restore_free(void);
-void mem_get_block_name(byte *block,
- char *block_name);
-
-/* mem_3.c */
-void *fastcall mem_check_overflow(void *in);
-
-/* mem_4.c */
-long mem_get_avail(void);
-long mem_conv_get_avail(void);
-void mem_set_video_mode(int mode);
-
-/* mem_5.c */
-long mem_program_block(void);
+/* mem_1.cpp */
+extern void *mem_normalize(void *in);
+
+/* mem_2.cpp */
+extern void *mem_get(long size);
+extern void *mem_get_name(long size, const char *block_name);
+extern int mem_free(void *block);
+extern int mem_adjust(void *target, long size);
+extern void mem_save_free();
+extern void mem_restore_free();
+extern void mem_get_block_name(byte *block, char *block_name);
+
+/* mem_3.cpp */
+void *mem_check_overflow(void *in);
+
+/* mem_4.cpp */
+extern long mem_get_avail();
+extern long mem_conv_get_avail();
+extern void mem_set_video_mode(int mode);
+
+/* mem_5.cpp */
+extern long mem_program_block();
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/core/midi.h b/engines/mads/madsv2/core/midi.h
new file mode 100644
index 00000000000..577535db268
--- /dev/null
+++ b/engines/mads/madsv2/core/midi.h
@@ -0,0 +1,43 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef MADS_CORE_MIDI_H
+#define MADS_CORE_MIDI_H
+
+#include "mads/madsv2/core/general.h"
+#include "mads/madsv2/core/room.h"
+#include "mads/madsv2/core/color.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+void midi_install(void);
+void midi_play(char name[30]);
+void midi_stop(void);
+void midi_pause(void);
+void midi_resume(void);
+void midi_loop(void);
+void midi_uninstall(void);
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/mouse_1.cpp b/engines/mads/madsv2/core/mouse_1.cpp
new file mode 100644
index 00000000000..d9222c6f92d
--- /dev/null
+++ b/engines/mads/madsv2/core/mouse_1.cpp
@@ -0,0 +1,33 @@
+/* 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 "mads/madsv2/core/general.h"
+#include "mads/madsv2/core/mouse_1.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+
+} // namespace MADSV2
+} // namespace MADS
+
+
+
diff --git a/engines/mads/madsv2/core/mouse_1.h b/engines/mads/madsv2/core/mouse_1.h
new file mode 100644
index 00000000000..4c40a6419b9
--- /dev/null
+++ b/engines/mads/madsv2/core/mouse_1.h
@@ -0,0 +1,98 @@
+/* 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 MADS_CORE_MOUSE_1_H
+#define MADS_CORE_MOUSE_1_H
+
+#include "mads/madsv2/core/general.h"
+#include "mads/madsv2/core/sprite.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+#define MOUSE_TIMING_ONE 7 /* Mouse 1st repeat delay (ticks) */
+#define MOUSE_TIMING_TWO 2 /* Mouse 2nd repeat delay (ticks) */
+
+#define MOUSE_DOUBLE_TIMING 5 /* Double click threshold (ticks) */
+#define MOUSE_BALLISTIC_TIMING 36 /* Ballistic threshold (ticks) */
+
+extern Buffer mouse_cursor_buffer;
+
+extern word mouse_driver, mouse_known_mode;
+extern int mouse_video_mode;
+extern byte mouse_showing;
+
+extern int mouse_button, mouse_status, mouse_x, mouse_y;
+extern int mouse_start_stroke, mouse_stroke_going, mouse_changed;
+extern int mouse_latched, mouse_stop_stroke;
+extern int mouse_old_x, mouse_old_y;
+
+/* mouse_1.cpp */
+
+extern int mouse_init(int driver_flag, int mouse_video_mode);
+
+extern int mouse_set_hotspot(int spot_x, int spot_y);
+
+extern void mouse_change_cursor_begin();
+extern void mouse_change_cursor_end();
+
+extern void mouse_screen_swap(int mouse_video_mode);
+extern int mouse_get_video_mode();
+
+extern void mouse_begin_double(int first_video_mode, int second_video_mode, int mono_to_right, int auto_freedom);
+extern void mouse_check_double();
+extern void mouse_end_double();
+extern void mouse_double_freedom(int freedom_flag);
+
+extern void mouse_show();
+extern void mouse_hide();
+
+extern void mouse_timing();
+
+extern void mouse_freeze();
+extern void mouse_thaw();
+
+extern int mouse_get_status(int *x, int *y);
+
+extern int mouse_press_info(int button, int *status, int *x, int *y);
+extern int mouse_release_info(int button, int *status, int *x, int *y);
+
+extern int mouse_scan(int *status, int *x, int *y);
+
+extern int mouse_in_box_now(int ul_x, int ul_y, int lr_x, int lr_y);
+
+extern void mouse_horiz_bound(int min_x, int max_x);
+extern void mouse_vert_bound(int min_y, int max_y);
+
+extern void mouse_force(int x, int y);
+
+extern void mouse_set_work_buffer(unsigned char *work_buffer, int wrap_value);
+extern void mouse_set_view_port_loc(int x1, int y1, int x2, int y2);
+
+extern void mouse_set_view_port(int dx, int dy);
+
+extern int mouse_refresh_view_port();
+extern void mouse_refresh_done();
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/mouse_2.cpp b/engines/mads/madsv2/core/mouse_2.cpp
new file mode 100644
index 00000000000..8535db0b51d
--- /dev/null
+++ b/engines/mads/madsv2/core/mouse_2.cpp
@@ -0,0 +1,130 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "mads/madsv2/core/general.h"
+#include "mads/madsv2/core/timer.h"
+#include "mads/madsv2/core/mouse_1.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+int mouse_button = -1;
+int mouse_status = 0;
+int mouse_x = 0;
+int mouse_y = 0;
+int mouse_start_stroke = false;
+int mouse_stroke_going = false;
+int mouse_changed = false;
+int mouse_latched = false;
+int mouse_stop_stroke = false;
+int mouse_any_stroke = false;
+int mouse_old_x = 0;
+int mouse_old_y = 0;
+long mouse_clock = 0;
+
+/*
+/* mouse_in_box()
+/*
+/* Returns true if the mouse is in the specified box
+/*
+*/
+int fastcall mouse_in_box(int ul_x, int ul_y, int lr_x, int lr_y) {
+ return (
+ ((mouse_x >= ul_x) && (mouse_x <= lr_x)) &&
+ ((mouse_y >= ul_y) && (mouse_y <= lr_y))
+ );
+}
+
+
+
+/*
+/* mouse_init_cycle()
+/*
+/* Call at beginning of routine which will use double screen
+/* cursor interaction; initializes global variables.
+*/
+void fastcall mouse_init_cycle(void) {
+ mouse_old_x = -1;
+ mouse_old_y = -1;
+
+ mouse_latched = false;
+ mouse_stroke_going = mouse_status;
+ mouse_start_stroke = false;
+}
+
+
+/*
+/* mouse_begin_cycle()
+/*
+/* Call once at beginning of each input loop. Reads mouse cursor
+/* information, and checks double cursor status.
+*/
+void fastcall mouse_begin_cycle(int double_flag) {
+ if (double_flag) mouse_check_double();
+
+ mouse_old_x = mouse_x;
+ mouse_old_y = mouse_y;
+
+ mouse_status = mouse_get_status(&mouse_x, &mouse_y);
+ mouse_clock = timer_read();
+ /* mouse_video_mode = mouse_get_video_mode(); */
+
+ mouse_stop_stroke = (mouse_latched && (!mouse_status));
+ mouse_start_stroke = (mouse_status && !mouse_stroke_going);
+ mouse_stroke_going = mouse_status;
+
+ if (!mouse_stroke_going) mouse_latched = false;
+
+ mouse_changed = ((mouse_x != mouse_old_x) || (mouse_y != mouse_old_y) || mouse_start_stroke || mouse_stop_stroke);
+
+ if (mouse_start_stroke) {
+ mouse_latched = true;
+ if (mouse_status & 1) {
+ mouse_button = 0;
+ } else {
+ mouse_button = 1;
+ }
+ }
+
+ mouse_any_stroke = (mouse_stroke_going || mouse_stop_stroke);
+}
+
+
+/*
+/* mouse_end_cycle()
+/*
+/* Call once each loop at end of loop. Clears cursor freedom
+/* semaphore, and performs any timing that might be necessary.
+*/
+void fastcall mouse_end_cycle(int double_flag, int timing_flag) {
+ if (double_flag) {
+ mouse_double_freedom(true);
+ }
+ if (timing_flag) {
+ while (mouse_clock == timer_read());
+ }
+}
+
+} // namespace MADSV2
+} // namespace MADS
+
+
+
diff --git a/engines/mads/madsv2/core/object.h b/engines/mads/madsv2/core/object.h
new file mode 100644
index 00000000000..9747c040ec0
--- /dev/null
+++ b/engines/mads/madsv2/core/object.h
@@ -0,0 +1,118 @@
+/* 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 MADS_CORE_OBJECT_H
+#define MADS_CORE_OBJECT_H
+
+#include "mads/madsv2/core/general.h"
+#include "mads/madsv2/core/vocab.h"
+#include "mads/madsv2/core/qual.h"
+#include "mads/madsv2/core/inter.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+
+#define OBJECT_FILE_VERSION "4.0" /* Object DEF file format version */
+
+#define OBJECT_MAX_VERBS 5
+#define OBJECT_MAX_QUALITIES 4
+
+#define OBJECT_SHORT_NAME_LEN 5
+
+#define OBJECT_VIEW_OFFSET 6
+#define OBJECT_GREY_BASE 248
+#define OBJECT_GREY_COLORS 8
+#define OBJECT_GREY_SPEED 1
+#define OBJECT_GREY_STEPS 16
+
+
+typedef struct {
+ char name[VC_MAXWORDLEN + 1];
+ byte verb_type;
+ byte prep_type;
+} HagVerb;
+
+
+/* Format for storing objects on disk */
+
+struct FileObjectBuf {
+ int number; /* Official object number */
+ char vocab_name[VC_MAXWORDLEN + 1];
+ char variable_name[VC_MAXWORDLEN + 1];
+ char desc[80];
+ int location;
+ byte prep;
+ byte num_verbs;
+ byte num_qualities;
+ byte syntax;
+ HagVerb verb[OBJECT_MAX_VERBS];
+ char quality_name[OBJECT_MAX_QUALITIES][QU_MAXWORDLEN + 1];
+ long quality_value[OBJECT_MAX_QUALITIES];
+ /* char short_name[OBJECT_SHORT_NAME_LEN + 1]; */
+};
+
+typedef struct FileObjectBuf FileObject;
+typedef FileObject *FileObjectPtr;
+
+struct ObjectBuf {
+ word vocab_id; /* Vocab word for name */
+ int location; /* Current location */
+ byte prep; /* "Put" preposition */
+ byte num_verbs; /* Number of special verbs */
+ byte num_qualities; /* Number of qualities */
+ byte syntax; /* Syntax */
+ Verb verb[OBJECT_MAX_VERBS]; /* Verb list for objects */
+ byte quality_id[OBJECT_MAX_QUALITIES]; /* Quality list */
+ long quality_value[OBJECT_MAX_QUALITIES]; /* Quality values */
+};
+
+typedef struct ObjectBuf Object;
+typedef Object *ObjectPtr;
+
+
+extern ObjectPtr object;
+extern int num_objects;
+
+extern int object_ems_handle;
+
+
+/* object_1.cpp */
+int fastcall object_load(void);
+void fastcall object_unload(void);
+
+/* object_2.cpp */
+int fastcall object_named(int vocab_id);
+int fastcall object_is_here(int object_id);
+
+/* object_3.cpp */
+int fastcall object_has_quality(int object_id, int quality_id);
+long fastcall object_check_quality(int object_id, int quality_id);
+void fastcall object_set_quality(int object_id, int quality_id,
+ long quality_value);
+
+/* object_4.cpp */
+int fastcall object_examine(int number, long message, int speech);
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/qual.h b/engines/mads/madsv2/core/qual.h
new file mode 100644
index 00000000000..a38cea69cb6
--- /dev/null
+++ b/engines/mads/madsv2/core/qual.h
@@ -0,0 +1,106 @@
+/* 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 MADS_CORE_QUAL_H
+#define MADS_CORE_QUAL_H
+
+#include "mads/madsv2/core/general.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+#define qual_version "3.01"
+#define qual_date "28-Oct-91"
+
+
+struct QualBuf {
+ word id;
+ word pointer;
+};
+typedef struct QualBuf Qual;
+
+
+#define QU_MAXWORDS 800 /* Maximum words in vocabulary */
+
+#define QU_MAXWORDLEN 20 /* Maximum word length */
+
+#define QU_FUDGEFACTOR 50 /* Number of words slack space */
+
+#define QU_MAINFILENAME "*QUAL.DB"
+
+#define QU_ERR_OPENMAINFILE -1 /* Failed to open main file */
+#define QU_ERR_OPENHARDFILE -2 /* Failed to open hard file */
+#define QU_ERR_READMAINFILE -3 /* Read error on main file */
+#define QU_ERR_READHARDFILE -4 /* Read error on hard file */
+#define QU_ERR_WORDTOOLONG -5 /* Max. word length exceeded */
+#define QU_ERR_SYNTAXHARDFILE -6 /* Improper format hard file */
+#define QU_ERR_NOMOREMEMORY -7 /* Failed to allocate memory */
+#define QU_ERR_MEMORYOVERFLOW -8 /* No memory to add a word */
+#define QU_ERR_WORDALREADYEXISTS -9 /* Word alread in vocab list */
+#define QU_ERR_WRITEMAINFILE -10 /* Failed to write main file */
+#define QU_ERR_RENAMEOUTFILE -11 /* Failed to rename out file */
+#define QU_ERR_TOOMANYWORDS -12 /* QU_MAXWORDS exceeded */
+#define QU_ERR_NOSUCHWORD -13 /* Word not in list */
+
+extern int qual_allocation;
+extern int qual_words;
+extern char *qual;
+
+/* qual_1.cpp */
+int fastcall qual_destroy(void);
+
+/* qual_2.cpp */
+int fastcall qual_load(int allocation_flag);
+int fastcall qual_get_code(char *inp);
+char *fastcall qual_get_word(char *out, int inp);
+
+/* qual_3.cpp */
+int fastcall qual_write_file(char *last_word);
+int fastcall qual_add_word(char *inp);
+
+/* qual_4.c */
+void fastcall qual_report_error(int number);
+
+/* qual_5.cpp */
+char *fastcall qual_select_word(char *out,
+ char *prompt,
+ char *default_word);
+
+/* qual_6.cpp */
+void fastcall qual_maint(void);
+
+/* qual_7.cpp */
+int fastcall qual_build(void);
+
+/* qual_8.cpp */
+void fastcall qual_unload_active(void);
+void fastcall qual_init_active(void);
+int fastcall qual_active_id(word id);
+int fastcall qual_make_active(word id);
+int fastcall qual_load_active(void);
+
+extern char *qual_text;
+extern word qual_active;
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/screen.h b/engines/mads/madsv2/core/screen.h
index 92a99377853..adf5c92cad2 100644
--- a/engines/mads/madsv2/core/screen.h
+++ b/engines/mads/madsv2/core/screen.h
@@ -19,10 +19,10 @@
*
*/
-#ifndef MADS_CORE_SPEECH_H
-#define MADS_CORE_SPEECH_H
+#ifndef MADS_CORE_SCREEN_H
+#define MADS_CORE_SCREEN_H
-#include "mads/madsv2/core/general.h"
+#include "mads/madsv2/core/window.h"
namespace MADS {
namespace MADSV2 {
@@ -76,76 +76,75 @@ extern Buffer scr_live;
extern Window screen_active;
-/* screen_1.c */
+/* screen_1.cpp */
void screen_set_size(short numlines);
-/* screen_2.c */
+/* screen_2.cpp */
void screen_wipe_line(short ul_x, short ul_y, short len,
short wipe_color, byte wipe_char);
-/* screen_3.c */
+/* screen_3.cpp */
short screen_out(char *outstring, short strcolor,
short selcolor, short str_x, short str_y);
-/* screen_4.c */
+/* screen_4.cpp */
short screen_put(char *outstring,
short strcolor, short selcolor,
short str_x, short str_y);
-/* screen_5.c */
+/* screen_5.cpp */
void screen_set_colors(int normal_color, int hilite_color);
void screen_set_line_width(int line_width);
/* screen_6.c ... DO NOT USE */
short screen_show(char *outstring, short locx, short locy);
-/* screen_7.c */
+/* screen_7.cpp */
short screen_show_line(char *outstring,
short locx, short locy);
-/* screen_8.c */
+/* screen_8.cpp */
short screen_write(char *outstring);
-/* screen_9.c */
+/* screen_9.cpp */
short screen_write_line(char *outstring);
-/* screen_a.c */
+/* screen_a.cpp */
void screen_clear(int clear_color);
-/* screen_b.c */
+/* screen_b.cpp */
void screen_dominant_mode(int dominant_mode);
-/* screen_c.c */
+/* screen_c.cpp */
void screen_init(int video_mode);
-/* screen_d.c */
+/* screen_d.cpp */
void screen_init_dual(int mono_left);
void screen_shutdown_dual(int clear_flag);
-/* screen_e.c */
+/* screen_e.cpp */
void screen_init_graphics(int which_mode);
void screen_shutdown_graphics(int clear_flag);
-/* screen_f.c */
-void screen_show_spot(char *message, int wx, int wy,
- int class, int num);
+/* screen_f.cpp */
+void screen_show_spot(char *message, int wx, int wy, int class_, int num);
/* screen_g.c ... DO NOT USE */
int screen_printf(int x, int y, char *string, ...);
int screen_print(char *string, ...);
-/* screen_h.c */
+/* screen_h.cpp */
void screen_init_text(int which_mode);
void screen_shutdown_text(int clear_flag);
-/* screen_i.c */
+/* screen_i.cpp */
void screen_save(void);
void screen_restore(void);
-/* screen_j.c */
+/* screen_j.cpp */
short screen_show_wide(char *outstring,
short locx,
short locy,
diff --git a/engines/mads/madsv2/core/sort.h b/engines/mads/madsv2/core/sort.h
new file mode 100644
index 00000000000..17f660aa68b
--- /dev/null
+++ b/engines/mads/madsv2/core/sort.h
@@ -0,0 +1,42 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 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 MADS_CORE_SORT_H
+#define MADS_CORE_SORT_H
+
+#include "mads/madsv2/core/general.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+/* sort_1.cpp */
+extern void sort_insertion(int elements, int *id, long *value);
+
+/* sort_2.cpp */
+extern void sort_insertion_16(int elements, byte *id, word *value);
+
+/* sort_3.cpp */
+extern void fastcall sort_insertion_8(int elements, byte *id, byte *value);
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/sprite.h b/engines/mads/madsv2/core/sprite.h
index da1c5f5ccd2..f9db894fe63 100644
--- a/engines/mads/madsv2/core/sprite.h
+++ b/engines/mads/madsv2/core/sprite.h
@@ -283,56 +283,56 @@ typedef Series *SeriesPtr;
extern byte *sprite_force_memory;
extern long sprite_force_size;
-/* sprite_1.c */
+/* sprite_1.cpp */
void sprite_draw(SeriesPtr series, int id, Buffer *buf,
int target_x, int target_y);
-/* sprite_2.c */
+/* sprite_2.cpp */
void sprite_draw_scaled(SeriesPtr series, int id, Buffer *buf,
int target_x, int target_y, int scale_factor);
-/* sprite_3.c */
+/* sprite_3.cpp */
void sprite_draw_3d_scaled(SeriesPtr series, int id,
Buffer *buf, Buffer *attr,
int target_x, int target_y,
int target_depth, int scale_factor);
-/* sprite_4.c */
+/* sprite_4.cpp */
void sprite_draw_3d_big(SeriesPtr series, int id,
Buffer *buf, Buffer *attr,
int target_x, int target_y, int target_depth,
int view_port_x, int view_port_y);
-/* sprite_5.c */
+/* sprite_5.cpp */
void sprite_draw_3d_scaled_big(SeriesPtr series, int id,
Buffer *buf, Buffer *attr,
int target_x, int target_y,
int target_depth, int scale_factor,
int view_port_x, int view_port_y);
-/* sprite_6.c */
+/* sprite_6.cpp */
void sprite_draw_3d_x16(SeriesPtr series, int id,
Buffer *buf, Buffer *attr,
int target_x, int target_y, int target_depth);
-/* sprite_7.c */
+/* sprite_7.cpp */
void sprite_draw_3d_scaled_x16(SeriesPtr series, int id,
Buffer *buf, Buffer *attr,
int target_x, int target_y,
int target_depth, int scale_factor);
-/* sprite_8.c */
+/* sprite_8.cpp */
void sprite_draw_3d_big_x16(SeriesPtr series, int id,
Buffer *buf, Buffer *attr,
int target_x, int target_y, int target_depth,
int view_port_x, int view_port_y);
-/* sprite_9.c */
+/* sprite_9.cpp */
void sprite_draw_3d_scaled_big_x16(SeriesPtr series, int id,
Buffer *buf, Buffer *attr,
int target_x, int target_y,
@@ -340,18 +340,18 @@ void sprite_draw_3d_scaled_big_x16(SeriesPtr series, int id,
int view_port_x, int view_port_y);
-/* sprite_a.c */
+/* sprite_a.cpp */
void sprite_draw_x16(SeriesPtr series, int id, Buffer *buf,
int target_x, int target_y);
-/* sprite_b.c */
+/* sprite_b.cpp */
void sprite_draw_interface(SeriesPtr series, int id,
Buffer *buf,
int target_x, int target_y);
-/* sprite_c.c */
+/* sprite_c.cpp */
void sprite_draw_3d_scaled_to_attr
(SeriesPtr series, int id,
Buffer *buf, Buffer *attr,
@@ -359,7 +359,7 @@ void sprite_draw_3d_scaled_to_attr
int scale_factor, int view_port_x, int view_port_y);
-/* sprite_d.c */
+/* sprite_d.cpp */
void sprite_draw_3d_scaled_mono
(SeriesPtr series, int id,
Buffer *buf, Buffer *attr,
@@ -367,19 +367,19 @@ void sprite_draw_3d_scaled_mono
int scale_factor, byte color);
-/* sprite_e.c */
-SeriesPtr sprite_series_load(char *filename, int load_flags);
+/* sprite_e.cpp */
+SeriesPtr sprite_series_load(const char *filename, int load_flags);
extern int sprite_error;
-/* sprite_f.c */
+/* sprite_f.cpp */
void sprite_get_scaled_matte(SeriesPtr series, int id,
int target_x, int target_y,
int scale_factor, SpritePtr matte);
-/* sprite_g.c */
+/* sprite_g.cpp */
word sprite_pack_line_rle(byte *target, Buffer *source,
byte *palette_map, byte transparent,
int x1, int x2, int y);
@@ -407,16 +407,16 @@ long sprite_pack_image(byte *target,
byte transparent);
-/* sprite_h.c */
+/* sprite_h.cpp */
void sprite_color_translate(SeriesPtr series, ColorListPtr list);
-/* sprite_i.c */
+/* sprite_i.cpp */
void sprite_single_color_translate(SeriesPtr series, int id);
-/* sprite_j.c */
+/* sprite_j.cpp */
int sprite_data_load(SeriesPtr series, int id, byte *target);
-/* sprite_k.c */
+/* sprite_k.cpp */
/* if called, wont remove the colors from the palette list. It is */
/* used during kernel_abort_animation. */
void dont_frag_the_palette(void);
diff --git a/engines/mads/madsv2/core/video.h b/engines/mads/madsv2/core/video.h
index 02ced502130..b3a645f37e0 100644
--- a/engines/mads/madsv2/core/video.h
+++ b/engines/mads/madsv2/core/video.h
@@ -27,7 +27,7 @@
namespace MADS {
namespace MADSV2 {
-int video_mode;
+extern int video_mode;
/* video.asm */
void video_init(int mode, int set_mode);
diff --git a/engines/mads/madsv2/core/window.h b/engines/mads/madsv2/core/window.h
new file mode 100644
index 00000000000..d17f98f1430
--- /dev/null
+++ b/engines/mads/madsv2/core/window.h
@@ -0,0 +1,229 @@
+/* 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 MADS_CORE_WINDOW_H
+#define MADS_CORE_WINDOW_H
+
+#include "mads/madsv2/core/general.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+#define WINDOW_DETECT_VALID 0
+#define WINDOW_DETECT_START -1
+#define WINDOW_DETECT_NOTHING -2
+#define WINDOW_DETECT_SCROLL -3
+#define WINDOW_DETECT_SCROLL_LOWER -4
+#define WINDOW_DETECT_SCROLL_HIGHER -5
+#define WINDOW_DETECT_PAGE_LOWER -6
+#define WINDOW_DETECT_PAGE_HIGHER -7
+#define WINDOW_DETECT_LOWER -8
+#define WINDOW_DETECT_HIGHER -9
+
+/* frame drawing character defines */
+
+#define window_shadow_color colorbyte(hi_black,black)
+#define abort_color colorbyte(black, white)
+
+#define ul_corner 0x0da
+#define ur_corner 0x0bf
+#define ll_corner 0x0c0
+#define lr_corner 0x0d9
+
+#define horiz_frame 0x0c4
+#define vert_frame 0x0b3
+
+#define upper_join 0x0c2
+#define lower_join 0x0c1
+#define left_join 0x0c3
+#define right_join 0x0b4
+
+#define four_way 0x0c5
+
+/* scroll bar drawing character defines */
+
+#define scroll_bar 0x0b2
+#define thumb_mark 0x008
+#define up_mark 0x018
+#define down_mark 0x019
+#define left_mark 0x01b
+#define right_mark 0x01a
+
+#define WINDOW_MAX_TRAP_ROUTINES 8
+
+#define WINDOW_SINGLE 0x01
+#define WINDOW_DOUBLE 0x02
+#define WINDOW_OBESE 0x03
+
+struct WindowBox {
+ int ul_x, ul_y, lr_x, lr_y;
+ byte *storage;
+};
+
+typedef struct WindowBox Window;
+typedef Window *WindowPtr;
+
+typedef struct {
+ WindowPtr window;
+ int vertical;
+ int side;
+ int normal_color;
+ int select_color;
+ long min_value;
+ long max_value;
+ long scroll_value;
+ long page_value;
+} ScrollBar;
+
+typedef ScrollBar *ScrollBarPtr;
+
+
+extern int window_box_mode;
+
+
+/* window_1 */
+void window_set(WindowPtr window, int ul_x, int ul_y, int lr_x, int lr_y);
+
+/* window_2 */
+void window_line_across(WindowPtr window, short line_y);
+
+/* window_3 */
+void window_color(WindowPtr window, short new_color);
+void window_wipe(WindowPtr window);
+void window_shadow(WindowPtr window);
+
+/* window_4 */
+void window_define_scrollbar(WindowPtr window,
+ ScrollBarPtr scroll,
+ int vertical,
+ int left_or_bottom,
+ long min_value,
+ long max_value,
+ long scroll_value,
+ long page_value,
+ int normal_color,
+ int select_color);
+
+/* window_4 */
+void window_draw_scrollbar(ScrollBarPtr scroll);
+
+/* window_4 */
+long window_translate_thumb(ScrollBarPtr scroll,
+ long current_value);
+
+long window_make_thumb(ScrollBarPtr scroll, long current_value);
+long window_draw_thumb(ScrollBarPtr scroll, long current_value);
+
+/* window_4 */
+int window_scrollbar_detect(ScrollBarPtr scroll,
+ int x, int y,
+ long value, long *new_value,
+ int prior_detect);
+
+/* window_4 */
+int window_detect(ScrollBarPtr scroll, int x, int y,
+ long value, long *new_value,
+ int prior_detect,
+ long base_value, long value_mult);
+
+
+int window_vert_detect(WindowPtr window, int x, int y,
+ int tight_vert, int tight_horiz);
+
+/* window_4 */
+void window_horiz_scrollbar(WindowPtr window, short bar_color);
+void window_vert_scrollbar(WindowPtr window, short bar_color);
+
+
+/* window_5 */
+void window_title(WindowPtr window, char *title,
+ short title_color, short background_color);
+
+/* window_6 */
+void window_abort(char *message);
+byte *window_create(WindowPtr window);
+void window_destroy(WindowPtr window);
+
+/* window_7 */
+int window_normal_color(WindowPtr window);
+int window_line_width(WindowPtr window);
+void window_text_setup(WindowPtr window, int follow);
+
+/* window_8 */
+void window_init_screen(WindowPtr main_window, char *prog_name,
+ char *prog_author, char *prog_version,
+ char *lib_version_no, char *compile_date);
+
+/* window_9 */
+void window_draw_box(WindowPtr window, int type);
+
+
+/* window_a */
+extern int window_num_trap_routines;
+extern byte *window_trap_routine[WINDOW_MAX_TRAP_ROUTINES];
+extern char window_trap_string[WINDOW_MAX_TRAP_ROUTINES][80];
+
+extern byte *window_incoming_string;
+extern int window_display_string;
+
+/* window_a */
+void window_trap_output(WindowPtr window,
+ void (*(any_char_routine))(),
+ char *trap_string, ...);
+
+void window_restore_output(void);
+
+
+/* window_c.cpp */
+void window_define(WindowPtr window,
+ int x1, int y1, int x2, int y2,
+ int color, int shadow, int save);
+
+/* window_d.cpp */
+void window_center(WindowPtr window, char *text,
+ int line, int color);
+
+/* window_e.cpp */
+int window_show(WindowPtr window, char *text,
+ int xx, int yy);
+
+/* window_f.cpp */
+void window_repeat(WindowPtr window, char wipe_item,
+ int x1, int x2, int y1);
+void window_wipe_line(WindowPtr window, int yy);
+
+/* window_g.cpp */
+int window_printf(WindowPtr window, int x, int y, char *string, ...);
+
+/* window_h.cpp */
+void window_clear(WindowPtr window);
+
+/* window_i.cpp */
+int window_show_color(WindowPtr window, char *text, int xx, int yy, int color);
+
+/* window_j.cpp */
+void window_10_install(void);
+void window_10_remove(void);
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index 043f01d479e..dd5e7967724 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -60,6 +60,14 @@ MODULE_OBJS += \
forest/forest_scenes.o \
forest/globals_forest.o \
madsv2/engine.o \
+ madsv2/core/kernel_3.o \
+ madsv2/core/kernel_8.o \
+ madsv2/core/kernel_b.o \
+ madsv2/core/kernel_d.o \
+ madsv2/core/kernel_f.o \
+ madsv2/core/matte_1.o \
+ madsv2/core/mouse_1.o \
+ madsv2/core/mouse_2.o \
madsv2/core/speech.o \
madsv2/phantom/mads/mads.o \
madsv2/phantom/main_menu.o \
Commit: 49ac71da4cd97d93788ab6d58db623a50c394fd8
https://github.com/scummvm/scummvm/commit/49ac71da4cd97d93788ab6d58db623a50c394fd8
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:19:04+10:00
Commit Message:
MADS: PHANTOM: Further import of dependent code
Changed paths:
A engines/mads/madsv2/core/buffer.cpp
A engines/mads/madsv2/core/buffer_2.cpp
A engines/mads/madsv2/core/buffer_3.cpp
A engines/mads/madsv2/core/dialog.h
A engines/mads/madsv2/core/font_1.cpp
A engines/mads/madsv2/core/global.h
A engines/mads/madsv2/core/implode.h
A engines/mads/madsv2/core/mem_2.cpp
A engines/mads/madsv2/core/mouse_3.cpp
A engines/mads/madsv2/core/mouse_4.cpp
A engines/mads/madsv2/core/object.cpp
A engines/mads/madsv2/core/pack_1.h
A engines/mads/madsv2/core/pack_5.h
A engines/mads/madsv2/core/pack_6.cpp
A engines/mads/madsv2/core/pack_d.h
A engines/mads/madsv2/core/quote_1.cpp
A engines/mads/madsv2/core/sprite_e.cpp
A engines/mads/madsv2/core/sprite_h.h
A engines/mads/madsv2/core/sprite_k.cpp
A engines/mads/madsv2/core/text.cpp
A engines/mads/madsv2/core/text.h
A engines/mads/madsv2/core/tile_3.cpp
A engines/mads/madsv2/core/video_1.cpp
A engines/mads/madsv2/core/vocab_8.cpp
A engines/mads/madsv2/core/vocab_8.h
engines/mads/madsv2/core/buffer.h
engines/mads/madsv2/core/env.h
engines/mads/madsv2/core/general.h
engines/mads/madsv2/core/kernel_1.cpp
engines/mads/madsv2/core/loader.h
engines/mads/madsv2/core/mem.h
engines/mads/madsv2/core/mouse.h
engines/mads/madsv2/core/mouse_1.cpp
engines/mads/madsv2/core/object.h
engines/mads/madsv2/core/pack.h
engines/mads/madsv2/core/room.h
engines/mads/madsv2/engine.cpp
engines/mads/madsv2/engine.h
engines/mads/module.mk
diff --git a/engines/mads/madsv2/core/buffer.cpp b/engines/mads/madsv2/core/buffer.cpp
new file mode 100644
index 00000000000..2f938894643
--- /dev/null
+++ b/engines/mads/madsv2/core/buffer.cpp
@@ -0,0 +1,728 @@
+/* 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/util.h"
+#include "mads/madsv2/core/general.h"
+#include "mads/madsv2/core/buffer.h"
+#include "mads/madsv2/core/mem.h"
+#include "mads/madsv2/core/room.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+word pattern_control_value = 0x181d;
+word pattern_initial_value = 0xb78e;
+int auto_pattern = true;
+static word accum; /* Pattern accumulator */
+
+
+bool buffer_init(Buffer *buf, word x, word y) {
+ buf->data = (byte *)mem_get((long)x * y);
+ if (buf->data == NULL)
+ return false;
+
+ buf->x = x;
+ buf->y = y;
+ return true;
+}
+
+bool buffer_init_name(Buffer *buf, word x, word y, const char *block_name) {
+ buf->data = (byte *)mem_get_name((long)x * y, block_name);
+ if (buf->data == NULL)
+ return false;
+
+ buf->x = x;
+ buf->y = y;
+ return true;
+}
+
+bool buffer_free(Buffer *buf) {
+ bool flag = false;
+
+ if (buf->data != NULL) {
+ mem_free(buf->data);
+ flag = true;
+ }
+
+ buf->data = NULL;
+ buf->x = 0;
+ buf->y = 0;
+
+ return flag;
+}
+
+bool buffer_fill(Buffer target, byte value) {
+ return buffer_rect_fill(target, 0, 0, target.x, target.y, value);
+}
+
+bool buffer_rect_copy(Buffer from, Buffer unto,
+ int ul_x, int ul_y, int size_x, int size_y) {
+ bool result;
+
+ result = ((from.data != NULL) && (unto.data != NULL));
+
+ if (result && size_x > 0 && size_y > 0) {
+ byte *from_ptr = buffer_pointer(&from, ul_x, ul_y);
+ byte *unto_ptr = buffer_pointer(&unto, ul_x, ul_y);
+ int from_wrap = from.x - size_x;
+ int unto_wrap = unto.x - size_x;
+
+ for (int row = 0; row < size_y; row++) {
+ memcpy(unto_ptr, from_ptr, size_x);
+ from_ptr += from_wrap + size_x; // advance by full source stride
+ unto_ptr += unto_wrap + size_x; // advance by full dest stride
+ }
+ }
+
+ return result;
+}
+
+bool buffer_rect_fill(Buffer target, int ul_x, int ul_y, int size_x, int size_y, byte value) {
+ bool result;
+
+ if (buffer_conform(&target, &ul_x, &ul_y, &size_x, &size_y))
+ return false;
+
+ result = (target.data != NULL);
+
+ if (result && size_x > 0 && size_y > 0) {
+ byte *target_ptr = buffer_pointer(&target, ul_x, ul_y);
+ int target_wrap = target.x - size_x;
+
+ for (int row = 0; row < size_y; row++) {
+ memset(target_ptr, value, size_x);
+ target_ptr += target_wrap + size_x;
+ }
+ }
+
+ return result;
+}
+
+bool buffer_rect_copy_2(Buffer from, Buffer unto,
+ int from_x, int from_y, int unto_x, int unto_y, int size_x, int size_y) {
+ bool result;
+
+ result = ((from.data != NULL) && (unto.data != NULL));
+
+ if (result && size_x > 0 && size_y > 0)
+ {
+ byte *from_ptr = buffer_pointer(&from, from_x, from_y);
+ byte *unto_ptr = buffer_pointer(&unto, unto_x, unto_y);
+ int from_wrap = from.x - size_x;
+ int unto_wrap = unto.x - size_x;
+
+ for (int row = 0; row < size_y; row++)
+ {
+ memcpy(unto_ptr, from_ptr, size_x);
+ from_ptr += from_wrap + size_x;
+ unto_ptr += unto_wrap + size_x;
+ }
+ }
+
+ return result;
+}
+
+void buffer_put_pixel(Buffer buf, word x, word y, byte c) {
+ buf.data[y * buf.x + x] = c;
+}
+
+byte buffer_get_pixel(Buffer buf, word x, word y) {
+ return buf.data[y * buf.x + x];
+}
+
+void buffer_hline(Buffer buf, word x1, word x2, word y, byte color) {
+ byte *ptr = buf.data + (y * buf.x) + x1;
+ int count = x2 - x1 + 1;
+
+ memset(ptr, color, count);
+}
+
+void buffer_vline(Buffer buf, word x, word y1, word y2, byte color) {
+ byte *ptr = buf.data + (y1 * buf.x) + x;
+ int count = y2 - y1 + 1;
+
+ for (int i = 0; i < count; i++, ptr += buf.x)
+ *ptr = color;
+}
+
+void buffer_draw_box(Buffer buf, word x1, word y1, word x2, word y2, byte color) {
+ int tmp;
+
+ if (x1 > x2) {
+ tmp = x1; x1 = x2; x2 = tmp;
+ }
+ if (y1 > y2) {
+ tmp = y1; y1 = y2; y2 = tmp;
+ }
+
+ buffer_hline(buf, x1, x2, y1, color); buffer_hline(buf, x1, x2, y2, color);
+ buffer_vline(buf, x1, y1, y2, color); buffer_vline(buf, x2, y1, y2, color);
+}
+
+void buffer_hline_xor(Buffer buf, int x1, int x2, int y) {
+ if (x1 > x2)
+ {
+ int tmp = x1;
+ x1 = x2;
+ x2 = tmp;
+ }
+
+ int len = x2 - x1 + 1;
+ byte *ptr = buf.data + y * buf.x + x1;
+
+ for (int i = 0; i < len; i++)
+ ptr[i] ^= 0xFF;
+}
+
+void buffer_vline_xor(Buffer buf, int x, int y1, int y2) {
+ if (y1 > y2)
+ {
+ int tmp = y1;
+ y1 = y2;
+ y2 = tmp;
+ }
+
+ int len = y2 - y1 + 1;
+ byte *ptr = buf.data + y1 * buf.x + x;
+
+ for (int i = 0; i < len; i++, ptr += buf.x)
+ *ptr ^= 0xFF;
+}
+
+void buffer_draw_crosshair(Buffer buf, int x, int y) {
+ buffer_hline_xor(buf, 0, buf.x - 1, y);
+ buffer_vline_xor(buf, x, 0, buf.y - 1);
+}
+
+void buffer_draw_box_xor(Buffer buf, int x1, int y1, int x2, int y2) {
+ int tmp;
+
+ if (x1 > x2) {
+ tmp = x1; x1 = x2; x2 = tmp;
+ }
+ if (y1 > y2) {
+ tmp = y1; y1 = y2; y2 = tmp;
+ }
+
+ buffer_hline_xor(buf, x1, x2, y1);
+ buffer_hline_xor(buf, x1, x2, y2);
+ buffer_vline_xor(buf, x1, y1 + 1, y2 - 1);
+ buffer_vline_xor(buf, x2, y1 + 1, y2 - 1);
+}
+
+int buffer_get_delta_bounds(Buffer buf1, Buffer buf2, int newcol,
+ word *xl, word *xh, word *yl, word *yh) {
+ if (buf1.x != buf2.x || buf1.y != buf2.y)
+ return -1;
+
+ word xxl = buf1.x, xxh = 0;
+ word yyl = buf1.y, yyh = 0;
+
+ byte *p1 = buf1.data;
+ byte *p2 = buf2.data;
+
+ for (word runy = 0; runy < buf1.y; runy++) {
+ for (word runx = 0; runx < buf1.x; runx++, p1++, p2++) {
+ if (*p1 != *p2) {
+ if (newcol == 0)
+ *p1 = 0;
+
+ if (runx > xxh) xxh = runx;
+ if (runx < xxl) xxl = runx;
+ if (runy > yyh) yyh = runy;
+ if (runy < yyl) yyl = runy;
+ }
+ }
+ }
+
+ *xl = xxl;
+ *xh = xxh;
+ *yl = yyl;
+ *yh = yyh;
+
+ return 0;
+}
+
+byte *buffer_pointer(Buffer *buf, int x, int y) {
+ return buf->data + y * buf->x + x;
+}
+
+bool buffer_conform(Buffer *buffer, int *x, int *y, int *xs, int *ys) {
+ if (*x < 0)
+ {
+ *xs += *x;
+ *x = 0;
+ }
+ if (*y < 0)
+ {
+ *ys += *y;
+ *y = 0;
+ }
+
+ int temp_x = MIN(*x + *xs - 1, buffer->x - 1);
+ int temp_y = MIN(*y + *ys - 1, buffer->y - 1);
+
+ *xs = (temp_x - *x) + 1;
+ *ys = (temp_y - *y) + 1;
+
+ return ((*xs <= 0) || (*ys <= 0));
+}
+
+int buffer_inter_merge_2(Buffer from, Buffer unto,
+ int from_x, int from_y,
+ int unto_x, int unto_y,
+ int size_x, int size_y) {
+ int result;
+
+ result = ((from.data != NULL) && (unto.data != NULL));
+
+ if (result && size_x > 0 && size_y > 0) {
+ byte *from_ptr = buffer_pointer(&from, from_x, from_y);
+ byte *unto_ptr = buffer_pointer(&unto, unto_x, unto_y);
+ int from_wrap = from.x - size_x;
+ int unto_wrap = unto.x - size_x;
+
+ for (int row = 0; row < size_y; row++) {
+ for (int col = 0; col < size_x; col++) {
+ byte dst = unto_ptr[col];
+ if (dst >= 8 && dst <= 15)
+ unto_ptr[col] = from_ptr[col];
+ }
+
+ from_ptr += from_wrap + size_x;
+ unto_ptr += unto_wrap + size_x;
+ }
+ }
+
+ return result;
+}
+
+void buffer_line(Buffer target, int x1, int y1, int x2, int y2, int color) {
+ int delta_x = abs(x2 - x1);
+ int delta_y = abs(y2 - y1);
+ int x_inc = (x2 >= x1) ? 1 : -1;
+ int y_inc = (y2 >= y1) ? target.x : -target.x;
+
+ byte *ptr = target.data + y1 * target.x + x1;
+
+ int x_count = delta_x + 1;
+ int y_count = delta_y + 1;
+
+ int lineAccum = (delta_x >= delta_y) ? delta_y : delta_x;
+
+ for (int col = 0; col < x_count; col++)
+ {
+ lineAccum += y_count;
+ *ptr = (byte)color;
+
+ while (lineAccum >= x_count)
+ {
+ lineAccum -= x_count;
+ *ptr = (byte)color;
+ ptr += y_inc;
+ }
+
+ ptr += x_inc;
+ }
+}
+
+void buffer_line_xor(Buffer target, int x1, int y1, int x2, int y2) {
+ int delta_x = abs(x2 - x1);
+ int delta_y = abs(y2 - y1);
+ int x_inc = (x2 >= x1) ? 1 : -1;
+ int y_inc = (y2 >= y1) ? target.x : -target.x;
+
+ byte *ptr = target.data + y1 * target.x + x1;
+
+ int x_count = delta_x + 1;
+ int y_count = delta_y + 1;
+
+ int lineAccum = (delta_x >= delta_y) ? delta_y : delta_x;
+
+ for (int col = 0; col < x_count; col++) {
+ lineAccum += y_count;
+ bool written = false;
+ *ptr ^= 0xFF;
+
+ while (lineAccum >= x_count) {
+ lineAccum -= x_count;
+ if (!written) {
+ *ptr ^= 0xFF;
+ written = true;
+ }
+ ptr += y_inc;
+ }
+
+ ptr += x_inc;
+ }
+}
+
+int buffer_legal(Buffer walk, int orig_wrap,
+ int x1, int y1, int x2, int y2) {
+ word legality = LEGAL;
+ word currently_illegal = false;
+
+ if (walk.data == NULL) return legality;
+ if ((x1 < 0) || (x2 < 0) || (y1 < 0) || (y2 < 0)) return legality;
+ if ((x1 >= orig_wrap) || (x2 >= orig_wrap)) return legality;
+ if ((y1 >= walk.y) || (y2 >= walk.y)) return legality;
+
+ int delta_x = abs(x2 - x1);
+ int delta_y = abs(y2 - y1);
+ int x_sign = (x2 >= x1) ? 1 : -1;
+ int y_sign = (y2 >= y1) ? walk.x : -walk.x;
+
+ int x_count = delta_x + 1;
+ int y_count = delta_y + 1;
+ int dAccum = (delta_x >= delta_y) ? delta_y : delta_x;
+
+ /* Each byte in the walk buffer holds 8 packed single-bit walk codes.
+ bit_pos counts from 1..8, where 1 means "rotate 1" i.e. the MSB,
+ and 8 means "rotate 8" i.e. the LSB - matching the ror-by-cl logic. */
+ byte *ptr = walk.data + y1 * walk.x + (x1 / 8);
+ int bit_pos = 8 - (x1 % 8); /* CL in the original: inverted bit index */
+
+ for (int col = 0; col < x_count; col++)
+ {
+ dAccum += y_count;
+
+ /* Test the walk-code bit at the current position */
+ byte val = *ptr;
+ bool blocked = ((val >> (bit_pos - 1)) & 1) != 0; /* ror al,cl then jnc */
+
+ if (blocked)
+ {
+ if (!currently_illegal)
+ {
+ currently_illegal = true;
+ legality -= ILLEGAL;
+ if (legality == 0)
+ return legality;
+ }
+ } else
+ {
+ currently_illegal = false;
+ }
+
+ /* Y steps for this column (Bresenham) */
+ while (dAccum >= x_count)
+ {
+ dAccum -= x_count;
+
+ val = *ptr;
+ blocked = ((val >> (bit_pos - 1)) & 1) != 0;
+
+ if (blocked)
+ {
+ if (!currently_illegal)
+ {
+ currently_illegal = true;
+ legality -= ILLEGAL;
+ if (legality == 0)
+ return legality;
+ }
+ } else
+ {
+ currently_illegal = false;
+ }
+
+ ptr += y_sign;
+ }
+
+ /* Advance one pixel in X within the packed byte */
+ bit_pos -= x_sign;
+
+ if (bit_pos < 1 || bit_pos > 8)
+ {
+ ptr += x_sign; /* crossed a byte boundary */
+ bit_pos += x_sign * 8; /* wrap bit_pos back into 1..8 */
+ }
+ }
+
+ return legality;
+}
+
+/* Advance the pattern accumulator one step. */
+static void pattern_math(void) {
+ word bx = accum;
+ accum += pattern_control_value;
+ bx = (bx >> 9) | (bx << 7); /* ror 9 */
+ accum ^= bx;
+ bx = (bx >> 3) | (bx << 13); /* ror 3 */
+ accum += bx;
+}
+
+static void scale_coord(int *coord, int *size, int boundary, int less_than) {
+ int condition;
+ int difference;
+
+ if (less_than) {
+ difference = boundary - *coord;
+ condition = *coord < boundary;
+ } else {
+ condition = *coord > (boundary - 1);
+ difference = *coord - (boundary - 1);
+ }
+
+ if (condition) {
+ *size = MAX(0, *size - difference);
+ if (less_than)
+ *coord += difference;
+ else
+ *coord -= difference;
+ }
+}
+
+word buffer_rect_fill_pattern(Buffer target, int ul_x, int ul_y, int size_x, int size_y,
+ int base_x, int base_y, int base_xs, byte value1, byte value2,
+ word start_accum, word note_line) {
+ int result;
+ int target_wrap;
+ int x2, base_x2;
+ int y2;
+ int base_ys = 0;
+ int line_wrap;
+ word noted_accum = 0;
+ word line_count = 0;
+
+ x2 = ul_x + size_x - 1;
+ y2 = ul_y + size_y - 1;
+
+ scale_coord(&ul_x, &size_x, 0, true);
+ scale_coord(&x2, &size_x, target.x, false);
+ scale_coord(&ul_y, &size_y, 0, true);
+ scale_coord(&y2, &size_y, target.y, false);
+
+ x2 = base_x + base_xs - 1;
+ y2 = base_y + base_ys;
+
+ scale_coord(&base_x, &base_xs, 0, true);
+ scale_coord(&x2, &base_xs, target.x, false);
+ scale_coord(&base_y, &base_ys, 0, true);
+ scale_coord(&y2, &base_ys, target.y, false);
+
+ if (!size_x || !size_y || !base_xs)
+ goto done;
+
+ if (auto_pattern) {
+ pattern_control_value = 0x181d;
+ pattern_initial_value = 0xb78e;
+
+ if (((base_xs >= 71) && (base_xs <= 73)) ||
+ ((base_xs >= 83) && (base_xs <= 87)) ||
+ ((base_xs >= 107) && (base_xs <= 110)) ||
+ ((base_xs >= 139) && (base_xs <= 148)) ||
+ ((base_xs >= 171) && (base_xs <= 173)) ||
+ ((base_xs >= 212) && (base_xs <= 220)) ||
+ (base_xs == 268)) {
+ pattern_control_value = 0x6164;
+ pattern_initial_value = 0xdd00;
+ }
+
+ if (((base_xs >= 105) && (base_xs <= 106)) ||
+ ((base_xs >= 120) && (base_xs <= 124))) {
+ pattern_control_value = 0x5124;
+ pattern_initial_value = 0xe1e4;
+ }
+
+ if (((base_xs >= 207) && (base_xs <= 211)) ||
+ (base_xs == 184)) {
+ pattern_control_value = 0x90d6;
+ pattern_initial_value = 0x89e0;
+ }
+
+ if (((base_xs >= 256) && (base_xs <= 260)) ||
+ ((base_xs >= 280) && (base_xs <= 291)) ||
+ (base_xs == 161)) {
+ pattern_control_value = 0x6d90;
+ pattern_initial_value = 0xecd7;
+ }
+ }
+
+ target_wrap = target.x - size_x;
+ result = (target.data != NULL);
+
+ if (result) {
+ accum = pattern_initial_value;
+
+ /* Wind the accumulator forward to account for rows above ul_y */
+ for (int row = 0; row < (ul_y - base_y); row++)
+ for (int col = 0; col < base_xs; col++)
+ pattern_math();
+
+ /* Wind the accumulator forward to account for columns left of ul_x */
+ for (int col = 0; col < (ul_x - base_x); col++)
+ pattern_math();
+
+ x2 = ul_x + size_x - 1;
+ base_x2 = base_x + base_xs - 1;
+
+ line_wrap = (base_x2 - x2) + (ul_x - base_x);
+
+ if (start_accum)
+ accum = start_accum;
+
+ byte *target_ptr = buffer_pointer(&target, ul_x, ul_y);
+
+ for (int row = 0; row < size_y; row++)
+ {
+ if (line_count == note_line)
+ noted_accum = accum;
+
+ line_count++;
+
+ for (int col = 0; col < size_x; col++)
+ {
+ pattern_math();
+ *target_ptr++ = (accum & 16) ? value2 : value1;
+ }
+
+ target_ptr += target_wrap;
+
+ /* Wind accumulator past the columns not being drawn */
+ for (int col = 0; col < line_wrap; col++)
+ pattern_math();
+ }
+ }
+
+done:
+ return noted_accum;
+}
+
+bool buffer_rect_fill_swap(Buffer target,
+ int ul_x, int ul_y,
+ int size_x, int size_y,
+ byte value1, byte value2) {
+ bool result = (target.data != NULL);
+
+ if (result && size_x > 0 && size_y > 0) {
+ byte *target_ptr = buffer_pointer(&target, ul_x, ul_y);
+ int target_wrap = target.x - size_x;
+
+ for (int row = 0; row < size_y; row++)
+ {
+ for (int col = 0; col < size_x; col++)
+ {
+ if (target_ptr[col] == value1)
+ target_ptr[col] = value2;
+ }
+ target_ptr += target_wrap + size_x;
+ }
+ }
+
+ return result;
+}
+
+void buffer_peel_horiz(Buffer *target, int peel) {
+ if (!peel) return;
+
+ int peel_sign = (peel > 0) ? 1 : -1;
+ int peel_val = abs(peel);
+
+ if (peel_val > MAX_PEEL_VALUE) return;
+
+ byte temp_buf[MAX_PEEL_VALUE];
+ byte *scan = target->data;
+ int x = target->x;
+ int y = target->y;
+
+ for (int row = 0; row < y; row++)
+ {
+ if (peel_sign > 0) {
+ /* Save the first peel_val bytes, shift row left, append saved bytes at end */
+ memcpy(temp_buf, scan, peel_val);
+ memmove(scan, scan + peel_val, x - peel_val);
+ memcpy(scan + x - peel_val, temp_buf, peel_val);
+ } else {
+ /* Save the last peel_val bytes, shift row right, prepend saved bytes at start */
+ memcpy(temp_buf, scan + x - peel_val, peel_val);
+ memmove(scan + peel_val, scan, x - peel_val);
+ memcpy(scan, temp_buf, peel_val);
+ }
+
+ scan += x;
+ }
+}
+
+void buffer_peel_vert(Buffer *target, int peel, byte *work_memory, long work_size) {
+ if (!peel)
+ return;
+
+ byte *scan = target->data;
+ int x = target->x;
+ int y = target->y;
+
+ int peel_sign = (peel > 0) ? 1 : -1;
+ int peel_val = abs(peel);
+ int peel_memory = peel_val * x;
+
+ byte *work_area = NULL;
+
+ if (work_memory == NULL) {
+ work_area = (byte *)mem_get_name(peel_memory, "$PEEL");
+ if (work_area == NULL) return;
+ } else {
+ work_area = work_memory;
+ if ((long)peel_memory > work_size) return;
+ }
+
+ if (peel_sign > 0) {
+ /* Positive peel: rotate buffer upward by peel_val rows.
+ Save the bottom peel_val rows, shift everything down,
+ then place the saved rows at the top. */
+ byte *deep_scan = buffer_pointer(target, 0, (y - 1) - (peel_val - 1));
+
+ memcpy(work_area, deep_scan, peel_memory);
+
+ for (int count = 0; count < (y - peel_val); count++)
+ {
+ byte *from = buffer_pointer(target, 0, (y - 1) - (count + peel_val));
+ byte *unto = from + peel_memory;
+ memcpy(unto, from, x);
+ }
+
+ memcpy(scan, work_area, peel_memory);
+ } else {
+ /* Negative peel: rotate buffer downward by peel_val rows.
+ Save the top peel_val rows, shift everything up,
+ then place the saved rows at the bottom. */
+ byte *deep_scan = buffer_pointer(target, 0, (y - 1) - (peel_val - 1));
+
+ memcpy(work_area, scan, peel_memory);
+
+ byte *unto = scan;
+ byte *from = scan + peel_memory;
+
+ for (int count = 0; count < (y - peel_val); count++) {
+ memcpy(unto, from, x);
+ unto += x;
+ from += x;
+ }
+
+ memcpy(deep_scan, work_area, peel_memory);
+ }
+
+ if (work_area != NULL && work_memory == NULL)
+ mem_free(work_area);
+}
+
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/core/buffer.h b/engines/mads/madsv2/core/buffer.h
index 29bbe324da3..0250fcfd5f9 100644
--- a/engines/mads/madsv2/core/buffer.h
+++ b/engines/mads/madsv2/core/buffer.h
@@ -42,163 +42,229 @@ namespace MADSV2 {
extern int buffer_restore_keep_flag;
-
+extern word pattern_control_value;
+extern int auto_pattern;
/* buffer_1.cpp */
-int buffer_init(Buffer *buf, word x, word y);
-int buffer_init_name(Buffer *buf, word x, word y, const char *block_name);
-/* buffer_2.cpp */
-int buffer_free(Buffer *buf);
+/**
+ * Allocates space for a buffer, and fills in embedded data.
+ * Returns TRUE if successful.
+ */
+extern bool buffer_init(Buffer *buf, word x, word y);
-/* buffer_3.cpp */
-int buffer_fill(Buffer target, byte value);
+/**
+ * Allocates space for a buffer, and fills in embedded data.
+ * Returns TRUE if successful.
+ */
+extern bool buffer_init_name(Buffer *buf, word x, word y, const char *block_name);
-/* buffer_4.cpp */
-int buffer_rect_copy(Buffer from, Buffer unto,
- int ul_x, int ul_y,
- int size_x, int size_y);
+/**
+ * De-allocates the data associated with the buffer
+ * @param buf
+ * @return Returns true if successful.
+ */
+extern bool buffer_free(Buffer *buf);
-/* buffer_5.cpp */
-int buffer_rect_fill(Buffer target,
- int ul_x, int ul_y,
- int size_x, int size_y,
- byte value);
-/* buffer_6.cpp */
-int buffer_rect_copy_2(Buffer from, Buffer unto,
+/**
+ * Fills an entire buffer with a single byte value.
+ * @return Returns true if successful.
+ */
+extern bool buffer_fill(Buffer target, byte value);
+
+/**
+ * Copies a "rectangular" buffer area from "from" to "unto". Size
+ * of copied rectangle is determined by "size_x, size_y". Upper left
+ * corner in BOTH buffers is indicated by "ul_x, ul_y". (To copy
+ * using separate corner coordinates in each buffer, use
+ * buf_rect_copy_2 ().
+ *
+ * * Handles "null" copies (e.g. one or both sizes are 0) correctly.
+ * * Optimizes for word copies.
+ * @return Returns TRUE if successful.
+ */
+extern bool buffer_rect_copy(Buffer from, Buffer unto,
+ int ul_x, int ul_y, int size_x, int size_y);
+
+/**
+ * Fills a "rectangular" buffer area with the specified byte value.
+ * Upper left corner is determined by "ul_x, ul_y", and sizes are
+ * determined by "size_x, size_y." No range checking is performed,
+ * but "null" copies (x or y size 0) are handled correctly.
+ * @return Returns TRUE if successful; false if buffer invalid.
+ */
+extern bool buffer_rect_fill(Buffer target,
+ int ul_x, int ul_y, int size_x, int size_y, byte value);
+
+/**
+ * Copies a "rectangular" buffer area from "from" to "unto". Size
+ * of copied rectangle is determined by "size_x, size_y". Upper left
+ * corner in source buffer is indicated by "from_x, from_y", and
+ * "unto_x, unto_y" determines upper left corner in destination
+ * buffer (if upper left corner coordinates are the same in both
+ * buffers, buf_rect_copy() can be used instead).
+ *
+ * @return Returns TRUE if successful.
+ */
+extern bool buffer_rect_copy_2(Buffer from, Buffer unto,
int from_x, int from_y,
int unto_x, int unto_y,
int size_x, int size_y);
-/* buffer_7.cpp */
-void buffer_put_pixel(Buffer buf, word x,
- word y, byte c);
+/**
+ * Given X and Y, sets pixel to color C
+ */
+void buffer_put_pixel(Buffer buf, word x, word y, byte c);
-/* buffer_8.cpp */
+/**
+ * Given X and Y, gets the pixel at that position.
+ */
byte buffer_get_pixel(Buffer buf, word x, word y);
-/* buffer_9.cpp */
-void buffer_hline(Buffer buf, word x1, word x2,
- word y, byte color);
+/**
+ * Given starting and ending points on the X axis, and the constant
+ * Y value, draws a line in the given color on the live MCGA screen.
+ */
+void buffer_hline(Buffer buf, word x1, word x2, word y, byte color);
-/* buffer_a.cpp */
-void buffer_vline(Buffer buf, word x, word y1,
- word y2, byte color);
+/**
+ * Given starting and ending points on the Y axis, and the constant
+ * X value, draws a line in the given color on the live MCGA screen.
+ */
+void buffer_vline(Buffer buf, word x, word y1, word y2, byte color);
-/* buffer_b.cpp */
-void buffer_draw_box(Buffer buf, word x1, word y1,
- word x2, word y2, byte color);
+/**
+ * Draws outside edge of retangle given home and size along both axis.
+ */
+void buffer_draw_box(Buffer buf, word x1, word y1, word x2, word y2, byte color);
-/* buffer_d.cpp */
+/**
+ * Draws a horizontal line by xoring/inverting the existing pixels
+ */
void buffer_hline_xor(Buffer buf, int x1, int x2, int y);
-/* buffer_e.cpp */
+/**
+ * Draws a vertical line by xoring/inverting the existing pixels
+ */
void buffer_vline_xor(Buffer buf, int x, int y1, int y2);
-/* buffer_f.cpp */
+/**
+ * Draws a cross-hairs at the specified x, y
+ */
void buffer_draw_crosshair(Buffer buf, int x, int y);
-/* buffer_g.cpp */
+/**
+ * Draws a box using pixel xor inversion
+ */
void buffer_draw_box_xor(Buffer buf, int x1, int y1, int x2, int y2);
-/* buffer_h.cpp */
-int buffer_get_delta_bounds(Buffer buf1, Buffer buf2,
- byte newcol, word *xl, word *xh,
- word *yl, word *yh);
+/**
+ * Scans the two buffers. Locations that are not the same on both buffers
+ * are changed (in buffer 1) to color <newcol>. The outside bounds are returned
+ * in the words pointed to by *XL,*XH,*YL,*YH.
+ * @return Returns -1 if an error occurs.
+ */
+extern bool buffer_get_delta_bounds(Buffer buf1, Buffer buf2,
+ byte newcol, word *xl, word *xh, word *yl, word *yh);
+
+/**
+ * Returns a pointer to the pixels starting at a given X, Y position
+ * @param buf Buffer
+ * @param x x
+ * @param y y
+ * @return Pointer
+ */
+extern byte *fastcall buffer_pointer(Buffer *buf, int x, int y);
-/* buffer_i.cpp */
-byte *fastcall buffer_pointer(Buffer *buf, int x, int y);
-int buffer_conform(Buffer *buffer, int *x, int *y,
+extern bool buffer_conform(Buffer *buffer, int *x, int *y,
int *xs, int *ys);
-/* buffer_j.cpp */
-int buffer_inter_merge_2(Buffer from, Buffer unto,
- int from_x, int from_y,
- int unto_x, int unto_y,
- int size_x, int size_y);
+/**
+ * Copies a "rectangular" buffer area from "from" to "unto". Size
+ * of copied rectangle is determined by "size_x, size_y". Upper left
+ * corner in source buffer is indicated by "from_x, from_y", and
+ * "unto_x, unto_y" determines upper left corner in destination
+ * buffer (if upper left corner coordinates are the same in both
+ * buffers, buf_rect_copy() can be used instead).
+ *
+ * Only copies on top of values 8-11 (the interface background colors)
+ *
+ * @return Returns TRUE if successful.
+ */
+extern int buffer_inter_merge_2(Buffer from, Buffer unto,
+ int from_x, int from_y, int unto_x, int unto_y, int size_x, int size_y);
-/* buffer_k.cpp */
-void buffer_line(Buffer target, int x1, int y1, int x2, int y2,
+/**
+ * This is a column-major Bresenham line drawing algorithm - it iterates along X
+ * as the outer loop and uses the accumulator to decide when to step in Y,
+ * which suits lines that are wider than they are tall.
+ */
+extern void buffer_line(Buffer target, int x1, int y1, int x2, int y2,
int color);
-/* buffer_l.cpp */
-void buffer_line_xor(Buffer target, int x1, int y1,
- int x2, int y2);
-
-/* buffer_m.cpp */
-int buffer_legal(Buffer walk, int orig_wrap,
- int x1, int y1, int x2, int y2);
-
-/* buffer_n.cpp */
-extern word pattern_control_value;
-extern int auto_pattern;
-
-word buffer_rect_fill_pattern(Buffer target,
- int ul_x, int ul_y,
- int size_x, int size_y,
- int base_x, int base_y,
- int base_xs,
- byte value1, byte value2,
- word start_accum,
- word note_line);
-
-
-/* buffer_o.cpp */
-int buffer_rect_fill_swap(Buffer target,
- int ul_x, int ul_y,
- int size_x, int size_y,
- byte value1, byte value2);
+/**
+ * This is a column-major Bresenham line drawing algorithm - it iterates along X
+ * as the outer loop and uses the accumulator to decide when to step in Y,
+ * which suits lines that are wider than they are tall. The only difference between
+ * it and buffer_line, is that this version uses an xor rather than storing a color.
+ */
+extern void buffer_line_xor(Buffer target, int x1, int y1, int x2, int y2);
+
+/**
+ * Traces a Bresenham line from (x1,y1) to (x2,y2) across a packed-bit walk
+ * buffer (8 walk-code bits per byte) and determines whether the path is
+ * legally walkable. Each time the line enters a new contiguous run of blocked
+ * pixels the legality counter is decremented by ILLEGAL; if it reaches zero
+ * the function returns immediately with that value. Paths that stay entirely
+ * clear, or whose legality counter never bottoms out, return LEGAL. Basic
+ * bounds checking is performed first: a NULL buffer or any coordinate outside
+ * the buffer dimensions short-circuits to LEGAL without scanning.
+ */
+extern int buffer_legal(Buffer walk, int orig_wrap, int x1, int y1, int x2, int y2);
+
+word buffer_rect_fill_pattern(Buffer target, int ul_x, int ul_y, int size_x, int size_y,
+ int base_x, int base_y, int base_xs, byte value1, byte value2,
+ word start_accum, word note_line);
+
+/**
+ * Fills a "rectangular" buffer area with the specified byte value.
+ * Upper left corner is determined by "ul_x, ul_y", and sizes are
+ * determined by "size_x, size_y." No range checking is performed,
+ * but "null" copies (x or y size 0) are handled correctly.
+ * @return Returns TRUE if successful; false if buffer invalid.
+ */
+extern bool buffer_rect_fill_swap(Buffer target, int ul_x, int ul_y,
+ int size_x, int size_y, byte value1, byte value2);
-/* buffer_p.cpp */
void buffer_peel_horiz(Buffer *target, int peel);
-/* buffer_q.cpp */
void buffer_peel_vert(Buffer *target, int peel,
byte *work_memory, long work_size);
-/* buffer_r.cpp */
int buffer_to_disk(Buffer *source, int x, int y,
int xs, int ys);
void buffer_from_disk(Buffer *source, int buffer_id,
- int keep_flag,
- int x, int y,
- int xs, int ys);
+ int keep_flag, int x, int y, int xs, int ys);
-/* buffer_s.cpp */
-int buffer_to_ems(Buffer *source, int page_handle,
- int source_ems_handle,
- int x, int y, int xs, int ys);
-int buffer_from_ems(Buffer *source, int page_handle,
- int target_ems_handle,
- int x, int y, int xs, int ys);
+extern bool buffer_to_ems(Buffer *source, int page_handle,
+ int source_ems_handle, int x, int y, int xs, int ys);
+extern bool buffer_from_ems(Buffer *source, int page_handle,
+ int target_ems_handle, int x, int y, int xs, int ys);
-/* buffer_t.cpp */
int buffer_preserve(Buffer *source, int flags,
- int source_ems_handle,
- int x, int y, int xs, int ys);
+ int source_ems_handle, int x, int y, int xs, int ys);
void buffer_restore(Buffer *source, int preserve_handle,
- int target_ems_handle,
- int x, int y, int xs, int ys);
-
-
-/* buffer_u.cpp */
-int buffer_rect_translate(Buffer from, Buffer unto,
- int from_x, int from_y,
- int unto_x, int unto_y,
- int size_x, int size_y,
- byte *table);
+ int target_ems_handle, int x, int y, int xs, int ys);
+extern bool buffer_rect_translate(Buffer from, Buffer unto,
+ int from_x, int from_y, int unto_x, int unto_y,
+ int size_x, int size_y, byte *table);
-/* buffer_w.cpp */
-int buffer_scan(Buffer *buffer, int magic,
- int base_x, int base_y,
- int size_x, int size_y);
+extern bool buffer_scan(Buffer *buffer, int magic,
+ int base_x, int base_y, int size_x, int size_y);
-/* buffer_w.cpp */
-int buffer_compare(Buffer *buffer0, Buffer *buffer1,
- int base_x, int base_y,
- int base_x2, int base_y2,
- int size_x, int size_y);
+extern bool buffer_compare(Buffer *buffer0, Buffer *buffer1,
+ int base_x, int base_y, int base_x2, int base_y2, int size_x, int size_y);
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/core/buffer_2.cpp b/engines/mads/madsv2/core/buffer_2.cpp
new file mode 100644
index 00000000000..74ff0e10b5e
--- /dev/null
+++ b/engines/mads/madsv2/core/buffer_2.cpp
@@ -0,0 +1,44 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 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 "mads/madsv2/core/general.h"
+#include "mads/madsv2/core/mem.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+bool buffer_free(Buffer *buf) {
+ bool flag = false;
+
+ if (buf->data != NULL) {
+ mem_free(buf->data);
+ flag = true;
+ }
+
+ buf->data = NULL;
+ buf->x = 0;
+ buf->y = 0;
+
+ return flag;
+}
+
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/core/buffer_3.cpp b/engines/mads/madsv2/core/buffer_3.cpp
new file mode 100644
index 00000000000..25aad3fa1c5
--- /dev/null
+++ b/engines/mads/madsv2/core/buffer_3.cpp
@@ -0,0 +1,30 @@
+/* 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 "mads/madsv2/core/general.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+
+
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/core/dialog.h b/engines/mads/madsv2/core/dialog.h
new file mode 100644
index 00000000000..f4ac07e9f33
--- /dev/null
+++ b/engines/mads/madsv2/core/dialog.h
@@ -0,0 +1,435 @@
+/* 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 MADS_CORE_DIALOG_H
+#define MADS_CORE_DIALOG_H
+
+#include "mads/madsv2/core/general.h"
+#include "mads/madsv2/core/window.h"
+#include "mads/madsv2/core/keys.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+#define DIALOG_ENGLISH 0 /* English language */
+#define DIALOG_GERMAN 1 /* German language */
+
+#define DIALOG_MAX_ITEM 50 /* Maximum items in a box */
+#define DIALOG_MAX_BUFFER 16 /* Maximum buffer areas in box */
+#define DIALOG_MAX_LIST 4 /* Maximum number of list windows */
+#define DIALOG_MAX_PROMPT_CHARS 72 /* Maximum length of prompt string */
+#define DIALOG_MAX_LIST_CHARS 13 /* Maximum length of list string */
+
+#define DIALOG_DEFAULT_STRING_SPACE 1024/* Default workspace size */
+
+#define DIALOG_FILE_WIDTH 61 /* Proper width for file dialog box*/
+#define DIALOG_FILE_BUFFER 46 /* Proper width for file name buf. */
+
+#define DD_DYNAMIC 0x80 /* Dialog allocated dynamically*/
+#define DD_STATIC 0x00 /* Dialog pre-allocated static */
+#define DD_EXITFLAG 0x40 /* Dialog is terminating */
+#define DD_COMPUTED 0x20 /* Dialog boundaries computed */
+#define DD_SCREENSAVED 0x10 /* Dialog window has saved */
+#define DD_FILEMENU 0x08 /* Dialog uses file functions */
+#define DD_DYNAMICSTRINGS 0x04 /* Dialog has dynamic strings */
+
+#define DD_CENTER -1 /* Dialog centered on axis */
+
+#define DD_AUTO -1 /* Auto-compute (width, etc.) */
+
+#define DD_DEFAULT -1 /* Default color */
+
+#define DD_LINEACROSS 0 /* Line across the box */
+
+#define DD_PAUSE 1 /* Use OK button to exit */
+#define DD_PERMANENT 2 /* No window cleanup */
+#define DD_MANUAL 3 /* Caller calls window_destroy */
+
+#define DD_I_NONE 0 /* Blank item type */
+#define DD_I_STRING 1 /* Item is a string input line */
+#define DD_I_FILENAME 2 /* Item is a filename input */
+#define DD_I_LISTBASED 3 /* Item is a list-based string */
+#define DD_I_CHECKBOX 4 /* Item is a checkoff box */
+#define DD_I_BUTTON 5 /* Item is a bottom-row button */
+#define DD_I_MESSAGE 6 /* Item is a message string */
+
+#define DD_I_FILELIST 7 /* Item is a file list */
+#define DD_I_DIRSLIST 8 /* Item is a directory list */
+#define DD_I_LIST 9 /* Item is a string list */
+
+#define DD_IX_CENTER -1 /* X control: Center this item */
+#define DD_IX_LEFT -2 /* X control: Left margin item */
+#define DD_IX_RIGHT -3 /* X control: Right margin itm */
+
+#define DD_IY_BUTTON -1 /* Y control: button line */
+#define DD_IY_AUTOFILL -2 /* Y control: autofill from top*/
+
+#define DD_C_HOME -257 /* Move cursor home */
+#define DD_C_END -258 /* Move cursor to end */
+
+#define DD_MC_NONE -1 /* Mouse not in any item */
+#define DD_MC_SCROLL -2 /* Mouse in a scroll bar */
+#define DD_MC_SCROLL_UP -3 /* Mouse in scroll up arrow */
+#define DD_MC_SCROLL_DOWN -4 /* Mouse in scroll down arrow */
+#define DD_MC_SCROLL_LEFT -5 /* Mouse in scroll left arrow */
+#define DD_MC_SCROLL_RIGHT -6 /* Mouse in scroll right arrow */
+#define DD_MC_SCROLL_PAGE_UP -7 /* Mouse pageing up */
+#define DD_MC_SCROLL_PAGE_DOWN -8 /* Mouse pageing down */
+#define DD_MC_SCROLL_PAGE_LEFT -9 /* Mouse pageing left */
+#define DD_MC_SCROLL_PAGE_RIGHT -10 /* Mouse pageing right */
+
+#define CANCEL_BUTTON "Cancel"
+#define CANCEL_GERMAN "Abbrechen"
+
+#define DD_CANCEL_BUTTON 0x01 /* Cancel button bit mask */
+#define DD_OK_BUTTON 0x02 /* OK button bit mask */
+#define DD_YES_BUTTON 0x04 /* Yes button bit mask */
+#define DD_NO_BUTTON 0x08 /* No button bit mask */
+#define DD_BEGONE_BUTTON 0x10 /* Begone button bit mask */
+
+#define DD_CHECK_GREY 0x80 /* Greyed out checkbox */
+#define DD_CHECK_RADIO 0x40 /* Checkbox is part of an ex- */
+/* clusive (radio button) group*/
+#define DD_CHECK_TRUE 0x01 /* Checkbox is selected. */
+
+#define DD_ERR_NOMOREITEMS -1 /* Ran out of items */
+#define DD_ERR_NOMOREBUFFERS -2 /* Ran out of string buffers */
+#define DD_ERR_NOMORELISTS -3 /* Ran out of string lists */
+#define DD_ERR_NOMOREMEMORY -4 /* Ran out of memory */
+#define DD_ERR_ABORTEDBYCALLBACK -5 /* Aborted by callback routine */
+#define DD_ERR_NOMORESTRINGS -6 /* Ran out of string space */
+
+#define DD_DEFAULT_NORMAL_COLOR colorbyte (black, white)
+#define DD_DEFAULT_SELECT_COLOR colorbyte (white, black)
+#define DD_DEFAULT_HILITE_COLOR colorbyte (hi_white, white)
+#define DD_DEFAULT_GREYED_COLOR colorbyte (hi_black, white)
+
+
+/* Quick dialog definition macros */
+
+#define dialog_declare(dd) DialogPtr dd = NULL; ItemPtr ok_item, cancel_item, result_item
+#define dialog_buttons(dd) ok_item = dialog_ok_button(dd);cancel_item = dialog_cancel_button(dd)
+#define dialog_exec(dd, ii) result_item = dialog_execute(dd, ii, ok_item, NULL);
+
+
+
+
+struct DialogItem {
+ short id; /* Item ID code */
+ short type; /* Item type */
+ short x, y; /* Item base location */
+ short x2; /* Item secondary x value */
+ short width; /* Item total width */
+ short buf_id; /* Item buffer identifier */
+ short buf_width; /* Item input area width */
+ short status; /* Item status */
+ short keystroke; /* Item keystroke activator */
+ short _class; /* Item checkbox class */
+ char *prompt; /* Item prompt/string */
+};
+
+typedef struct DialogItem Item;
+typedef Item *ItemPtr;
+
+
+
+struct DialogList {
+ char *list;
+ Window window;
+ short base_x, base_y;
+ short rows, columns;
+ short thumb;
+ short base_entry;
+ short picked_entry;
+ short entry_width;
+ short elements, element_offset;
+ short max_elements;
+};
+
+typedef struct DialogList List;
+typedef List *ListPtr;
+
+
+
+struct DialogBox {
+ Window window; /* window boundaries */
+ short base_x, base_y; /* upper left text coords */
+ short width; /* width */
+
+ short normal_color; /* dialog display colors */
+ short select_color;
+ short hilite_color;
+
+ short num_items; /* number of dialog items */
+ short status; /* general status flags */
+ short fill_marker; /* vertical fill marker */
+ short active_button; /* currently active button */
+ short active_item; /* currently active item */
+
+ short cursor_x, cursor_y; /* current cursor coordinates */
+
+ void (*callback)(); /* callback routine for list */
+ /* selection. */
+
+ void (*checkbox_callback)(); /* callback routine for check */
+ /* box modification. */
+
+ Item item[DIALOG_MAX_ITEM]; /* items in this dialog */
+ ItemPtr default_item; /* Item for default button */
+ ItemPtr cancel_item; /* Item for "Cancel" button */
+ ItemPtr path_item; /* Item holding filename path */
+
+ short button_left, button_right; /* button horiz fill markers */
+ short button_flag; /* button row occupied flag */
+ short buffers_allocated; /* # buffers now in use */
+
+ char *buffer[DIALOG_MAX_BUFFER]; /* string i/o buffers */
+ int buf_cursor[DIALOG_MAX_BUFFER]; /* string i/o cursors */
+ int buf_selbase[DIALOG_MAX_BUFFER]; /* string i/o select base */
+ int buf_seltarget[DIALOG_MAX_BUFFER]; /* string i/o select target */
+ int buf_base_x[DIALOG_MAX_BUFFER]; /* string i/o base locations */
+ int buf_status[DIALOG_MAX_BUFFER]; /* string i/o status */
+ int buf_select[DIALOG_MAX_BUFFER]; /* string i/o selection status */
+
+ short lists_allocated; /* # windows now in use */
+
+ List lists[DIALOG_MAX_LIST]; /* list windows */
+
+ char *string_space; /* String space for prompts */
+ char *string_marker; /* Marker for next string */
+ long string_space_remaining; /* Amount of string space left */
+};
+
+typedef struct DialogBox Dialog;
+typedef Dialog *DialogPtr;
+
+
+#define StringMode(x) (((x).type == DD_I_STRING) || ((x).type == DD_I_FILENAME) || ((x).type == DD_I_LISTBASED))
+#define DialogString(x) StringMode(x->item[x->active_item])
+
+
+/* dialog_1.cpp */
+extern int dialog_error;
+extern int dialog_quicksearch_flag;
+extern int dialog_wildcard_exits;
+
+extern long dialog_timeout;
+
+extern int dialog_language;
+
+
+
+ItemPtr dialog_add_button(DialogPtr dialog, int x, int y, const char *prompt);
+
+ItemPtr dialog_add_checkbox(DialogPtr dialog, int x, int y,
+ const char *prompt, int default_val, int class_);
+
+void dialog_grey_checkbox(ItemPtr item);
+
+/* dialog_1.cpp */
+ItemPtr dialog_add_message(DialogPtr dialog, int x, int y, const char *prompt);
+
+void dialog_add_blank(DialogPtr dialog);
+
+/* dialog_1.cpp */
+ItemPtr dialog_add_string(DialogPtr dialog, int x, int y,
+ char *prompt,
+ char *default_val,
+ int width);
+
+/* dialog_1.cpp */
+ItemPtr dialog_add_listbased(DialogPtr dialog, int x, int y,
+ char *prompt,
+ char *default_val, int width,
+ char *title, char *mylist,
+ int elements, int element_offset,
+ int entry_width, int rows, int columns);
+
+/* dialog_1.cpp */
+ItemPtr dialog_add_filename(DialogPtr dialog, int x, int y,
+ char *prompt,
+ char *default_val, char *path,
+ int rows,
+ char *filebuf, int max_file_elements,
+ char *dirsbuf, int max_dirs_elements);
+
+/* dialog_1.cpp */
+ItemPtr dialog_append_list(DialogPtr dialog, int x, int y,
+ ItemPtr base_string,
+ char *title,
+ char *mylist,
+ int elements, int element_offset,
+ int entry_width, int rows, int columns);
+
+/* dialog_1.cpp */
+void dialog_set_colors(int normal, int select,
+ int hilite, int greyed);
+
+/* dialog_1.cpp */
+void dialog_set_workspace_size(long workspace);
+void dialog_set_string_space(DialogPtr dialog,
+ char *space, long size);
+
+
+/* dialog_1.cpp */
+DialogPtr dialog_create(DialogPtr dialog,
+ int ul_x, int ul_y,
+ int width,
+ int normal_color,
+ int select_color,
+ int hilite_color);
+
+void dialog_destroy(DialogPtr dialog);
+void dialog_destroy_persist(DialogPtr dialog);
+
+/* dialog_1.cpp */
+DialogPtr dialog_file_create(DialogPtr dialog,
+ int ul_x, int ul_y,
+ int normal_color, int select_color,
+ int hilite_color,
+ ItemPtr *ok_item, ItemPtr *first_item,
+ char *default_val, char *path,
+ int rows,
+ char *filebuf, int maxfiles,
+ char *dirsbuf, int maxdirs,
+ char *prompt);
+
+/* dialog_1.cpp */
+int dialog_read_dir_to_list(ListPtr target,
+ char *wild,
+ int dirflag);
+
+/* dialog_1.cpp */
+void dialog_set_list_callback(DialogPtr dialog,
+ void (*(callback))());
+
+void dialog_set_mouse_callback(void (*(callback))(),
+ int double_only);
+
+void dialog_set_page_callback(void (*(callback))());
+
+void dialog_set_checkbox_callback(DialogPtr dialog,
+ void (*(callback))());
+
+/* dialog_1.cpp */
+int dialog_read_checkbox(DialogPtr dialog, ItemPtr item);
+char *dialog_read_string(DialogPtr dialog, ItemPtr item);
+char *dialog_read_list(DialogPtr dialog, ItemPtr item);
+char *dialog_read_pathname(DialogPtr dialog, ItemPtr item);
+char *dialog_read_filename(DialogPtr dialog, ItemPtr item);
+char *dialog_read_filepath(DialogPtr dialog, ItemPtr item);
+
+
+/* dialog_1.cpp */
+void dialog_show_all(DialogPtr dialog);
+
+/* dialog_1.cpp */
+ItemPtr dialog_execute(DialogPtr dialog,
+ ItemPtr active_item,
+ ItemPtr default_button,
+ KeyPtr key_buffer);
+
+
+/* dialog_2.cpp */
+char *dialog_select_file(char *prompt,
+ char *path,
+ char *filespec,
+ char *output);
+
+
+/* dialog_3.cpp */
+char *dialog_enter_string(char *reply,
+ char *top_prompt,
+ char *left_prompt,
+ char *my_default,
+ int maxlen);
+
+
+/* dialog_4.cpp */
+int dialog_enter_int(char *top_prompt, int my_default);
+
+
+/* dialog_5.cpp */
+DialogPtr dialog_create_default(void);
+
+
+/* dialog_6.cpp */
+int dialog_alert(int x, int y, int buttons,
+ char *string1,
+ char *string2,
+ char *string3,
+ char *string4);
+
+void dialog_set_alert_colors(int normal,
+ int select,
+ int hilite);
+
+
+/* dialog_7.cpp */
+int dialog_alert_center(int buttons,
+ char *string1,
+ char *string2,
+ char *string3,
+ char *string4);
+
+/* dialog_8.cpp */
+int dialog_alert_ok(char *string1,
+ char *string2,
+ char *string3,
+ char *string4);
+
+/* dialog_9.cpp */
+void dialog_newsay(int x, int y);
+void dialog_say(char *message, int x);
+Window dialog_sayit(int saymode);
+
+
+/* dialog_a.cpp */
+ItemPtr dialog_left_message(DialogPtr dialog, char *prompt);
+ItemPtr dialog_center_message(DialogPtr dialog, char *prompt);
+ItemPtr dialog_left_string(DialogPtr dialog, char *prompt,
+ char *string, int width);
+ItemPtr dialog_left_button(DialogPtr dialog, char *prompt);
+ItemPtr dialog_ok_button(DialogPtr dialog);
+ItemPtr dialog_cancel_button(DialogPtr dialog);
+char *dialog_get_string(DialogPtr dialog, ItemPtr item,
+ char *target);
+
+
+/* dialog_b.cpp */
+ItemPtr dialog_add_number(DialogPtr dialog, int x, int y,
+ char *prompt, int num, int width);
+ItemPtr dialog_left_number(DialogPtr dialog, char *prompt,
+ int num, int width);
+int dialog_get_number(DialogPtr dialog, ItemPtr item);
+
+
+/* dialog_e.cpp */
+void dialog_trap_critical(void);
+void dialog_restore_critical(void);
+
+/* dialog_f.cpp */
+void dialog_watch_point(char *string, long x, long y);
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/env.h b/engines/mads/madsv2/core/env.h
index fc26f20a300..48f4efa4058 100644
--- a/engines/mads/madsv2/core/env.h
+++ b/engines/mads/madsv2/core/env.h
@@ -22,6 +22,7 @@
#ifndef MADS_CORE_ENV_H
#define MADS_CORE_ENV_H
+#include "common/stream.h"
#include "mads/madsv2/core/general.h"
namespace MADS {
@@ -76,17 +77,15 @@ extern long env_concat_file_size; /* Size of last concat file opened */
/* env_0.c */
-int env_verify(void);
+int env_verify(void);
/* env_1.c */
-Common::Stream * env_open(char *file_path, char *options);
-int env_exist(char *file_name);
-long env_get_file_size(Common::Stream *handle);
-
+Common::SeekableReadStream *env_open(const char *file_path, const char *options);
+int env_exist(const char *file_name);
+long env_get_file_size(Common::Stream *handle);
/* env_1.c */
-char *env_get_path(char *madspath,
- char *infile);
+char *env_get_path(char *madspath, char *infile);
/* env_1.c */
char *env_catint(char *out, int value, int digits);
diff --git a/engines/mads/madsv2/core/font_1.cpp b/engines/mads/madsv2/core/font_1.cpp
new file mode 100644
index 00000000000..62c403714e4
--- /dev/null
+++ b/engines/mads/madsv2/core/font_1.cpp
@@ -0,0 +1,84 @@
+/* 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 "mads/madsv2/core/general.h"
+#include "mads/madsv2/core/mem.h"
+#include "mads/madsv2/core/error.h"
+#include "mads/madsv2/core/loader.h"
+#include "mads/madsv2/core/font.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+FontPtr font_inter = NULL;
+FontPtr font_main = NULL; /* Interface & main font handles */
+FontPtr font_conv = NULL;
+FontPtr font_menu = NULL;
+FontPtr font_misc = NULL;
+
+
+FontPtr font_load(const char *name) {
+ char temp_buf_2[80];
+ char *mark;
+ char block_name[20];
+ long size;
+ FontPtr new_font = NULL;
+ FontPtr result = NULL;
+ Load load_handle;
+
+ mem_last_alloc_loader = MODULE_FONT_LOADER;
+
+ load_handle.open = false;
+
+ Common::strcpy_s(temp_buf_2, name);
+ mark = strchr(temp_buf_2, '.');
+ if (mark == NULL) {
+ Common::strcat_s(temp_buf_2, ".FF");
+ }
+
+ mark = temp_buf_2;
+ if (*mark == '*') mark++;
+ strncpy(block_name, mark, 8);
+
+ if (loader_open(&load_handle, temp_buf_2, "rb", true)) goto done;
+
+ size = load_handle.pack.strategy[0].size;
+
+ new_font = (FontPtr)mem_get_name(size, block_name);
+ if (new_font == NULL) goto done;
+
+ if (!loader_read(new_font, size, 1, &load_handle)) goto done;
+
+ result = new_font;
+
+done:
+ if (new_font != NULL) {
+ if (result == NULL)
+ mem_free(new_font);
+ }
+ if (load_handle.open)
+ loader_close(&load_handle);
+
+ return result;
+}
+
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/core/general.h b/engines/mads/madsv2/core/general.h
index 1bc9c807830..1c4d3880ab7 100644
--- a/engines/mads/madsv2/core/general.h
+++ b/engines/mads/madsv2/core/general.h
@@ -22,7 +22,7 @@
#ifndef MADS_CORE_GENERAL_H
#define MADS_CORE_GENERAL_H
-#include "common/scummsys.h"
+#include "common/str.h"
namespace MADS {
namespace MADSV2 {
@@ -143,6 +143,11 @@ inline void mads_strlwr(char *s) {
for (; *s; ++s)
*s = tolower(*s);
}
+inline char *mads_itoa(int value, char *buffer, int radix) {
+ assert(radix == 10);
+ Common::strcpy_s(buffer, 16, Common::String::format("%d", value).c_str());
+ return buffer;
+}
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/core/global.h b/engines/mads/madsv2/core/global.h
new file mode 100644
index 00000000000..56d6dc34b00
--- /dev/null
+++ b/engines/mads/madsv2/core/global.h
@@ -0,0 +1,97 @@
+/* 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 MADS_CORE_GLOBAL_H
+#define MADS_CORE_GLOBAL_H
+
+#include "mads/madsv2/core/general.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+
+#define GLOBAL_LIST_SIZE 210 /* Global variables array size */
+
+#define MESSAGE_COLOR (((KERNEL_MESSAGE_COLOR_BASE + 1) << 8) + KERNEL_MESSAGE_COLOR_BASE)
+#define MESSAGE_COLOR_2 (((KERNEL_MESSAGE_COLOR_BASE_2 + 1) << 8) + KERNEL_MESSAGE_COLOR_BASE_2)
+#define MESSAGE_COLOR_3 (((KERNEL_MESSAGE_COLOR_BASE_3 + 1) << 8) + KERNEL_MESSAGE_COLOR_BASE_3)
+
+/* Global macros */
+
+#define SCORE_LOOK_SPHERE_106 1
+#define SCORE_READ_BOOK_101 2
+#define SCORE_SHIFT_INTO_SEAL_113 4
+#define SCORE_PUSH_BUTTON_119 8
+#define SCORE_WEAR_CROWN_119 16
+#define SCORE_MAKE_ACID_DRIP_605 32
+#define SCORE_CROSS_PILLARS 64
+#define SCORE_ENTER_609 128
+#define SCORE_CROSS_SKY 256
+#define SCORE_JUMP_INTO_WELL 512
+#define SCORE_MAKE_NOISE_BIRDCALL 1024
+#define SCORE_TAKE_BONE 2048
+
+/* section 1 macros */
+
+#define START_MACROS_HERE 1 /* enter description here */
+
+
+/* ==================== System variables ===================== */
+
+#define walker_timing 0 /* Stop walker timing (long) */
+#define walker_timing_2 1
+#define inventory_is_displayed 2 /* T if inventory is being displayed */
+#define player_hyperwalked 3 /* T if player hit spacebar in room */
+#define player_selected_object 4 /* will be >= 0 (to hold selected object) else -1 */
+#define candle_is_on 5 /* T if candle flame is on in interface */
+
+
+/* ================= Global to all sections ================== */
+
+#define player_score 10 /* player's score of the game */
+#define player_score_flags 11 /* 16 flags for checking if player increased score */
+#define dont_load_walker 12 /* if T, will not load walker in section code */
+#define perform_displacements 13 /* if T, will do displacements */
+#define intro 14 /* if T, Intro is in progress */
+#define outro 15 /* if T, Outro is in progress */
+
+/* =================== Section 1 20 - 39 ==================== */
+
+#define section_1_variable 20 /* put description here */
+
+/* =================== Section 2 40 - 59 ==================== */
+
+
+/* =================== Section 3 60 - 79 ==================== */
+
+
+/* =================== Section 4 80 - 99 ==================== */
+
+
+/* ================== Section 5 100 - 119 =================== */
+
+
+/* ================== Section 6 120 - 139 =================== */
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/implode.h b/engines/mads/madsv2/core/implode.h
new file mode 100644
index 00000000000..1d4e683de4f
--- /dev/null
+++ b/engines/mads/madsv2/core/implode.h
@@ -0,0 +1,60 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef MADS_CORE_IMPLODE_H
+#define MADS_CORE_IMPLODE_H
+
+#include "common/scummsys.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+extern unsigned short implode(
+ unsigned (*read_buff)(char *buffer, unsigned short *size),
+ void (*write_buff)(char *buffer, unsigned short *size),
+ char *work_buff,
+ unsigned short int *type,
+ unsigned short int *dsize);
+
+extern unsigned explode(
+ unsigned (*read_buff)(char *buffer, unsigned short *size),
+ void (*write_buff)(char *buffer, unsigned short *size),
+ char *work_buff);
+
+extern unsigned long crc32(
+ unsigned char *buffer,
+ unsigned short int *size,
+ unsigned long *old_crc);
+
+
+#define CMP_BINARY 0
+#define CMP_ASCII 1
+
+#define CMP_NO_ERROR 0
+#define CMP_INVALID_DICTSIZE 1
+#define CMP_INVALID_MODE 2
+#define CMP_BAD_DATA 3
+#define CMP_ABORT 4
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/kernel_1.cpp b/engines/mads/madsv2/core/kernel_1.cpp
index eb4cf103a42..45b9f56cac3 100644
--- a/engines/mads/madsv2/core/kernel_1.cpp
+++ b/engines/mads/madsv2/core/kernel_1.cpp
@@ -1,12 +1,31 @@
-/*
-/* kernel_1.c by Brian Reynolds 5-Nov-91
-*/
-
-#include <general.mac>
-#include <room.mac>
-#include <color.mac>
-
-#include "kernel.mac"
+/* 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 "mads/madsv2/core/general.h"
+#include "mads/madsv2/core/room.h"
+#include "mads/madsv2/core/color.h"
+#include "mads/madsv2/core/kernel.h"
+
+namespace MADS {
+namespace MADSV2 {
RoomPtr room = NULL;
int room_id = KERNEL_STARTING_GAME;
@@ -36,34 +55,14 @@ int kernel_screen_fade = 0;
Animation kernel_anim[KERNEL_MAX_ANIMATIONS];
-/*
-AnimPtr kernel_animation = NULL;
-int kernel_animation_cycled = false;
-int kernel_repeat_animation = false;
-
-int kernel_animation_sprite_loaded;
-int kernel_animation_buffer_id;
-byte *kernel_animation_buffer[2];
-
-int kernel_animation_messages;
-
-int kernel_animation_frame;
-int kernel_animation_image;
-int kernel_animation_doomed = false;
-int kernel_animation_trigger_code;
-int kernel_animation_trigger_mode;
-int kernel_animation_trigger_words[3];
-long kernel_animation_next_clock;
-*/
-
ShadowList kernel_shadow_main = { 0 };
ShadowList kernel_shadow_inter = { 1, { 15 } };
int kernel_ok_to_fail_load = false;
-byte kernel_mode = KERNEL_GAME_LOAD;
+int kernel_mode = KERNEL_GAME_LOAD;
-char kernel_cheating_password[64];
+char kernel_cheating_password[16];
int kernel_cheating_allowed = 0;
int kernel_cheating_forbidden = 0;
@@ -80,4 +79,5 @@ int cursor_last = -1;
Kernel kernel; /* Kernel data */
KernelGame game; /* Kernel level game data */
-
\ No newline at end of file
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/core/loader.h b/engines/mads/madsv2/core/loader.h
index 5934997f4f6..032bc6dc08e 100644
--- a/engines/mads/madsv2/core/loader.h
+++ b/engines/mads/madsv2/core/loader.h
@@ -69,8 +69,7 @@ extern char loader_last[14];
/* loader_1.c */
-int loader_open(LoadHandle handle, char *filename,
- char *options, int flags);
+int loader_open(LoadHandle handle, const char *filename, const char *options, int flags);
int loader_close(LoadHandle handle);
diff --git a/engines/mads/madsv2/core/mem.h b/engines/mads/madsv2/core/mem.h
index 89747e79f48..85bb5ebb6e2 100644
--- a/engines/mads/madsv2/core/mem.h
+++ b/engines/mads/madsv2/core/mem.h
@@ -52,15 +52,40 @@ extern void (*mem_manager_update)(); /* Called at memory updates */
extern int mem_manager_active; /* Flag if memory manager active */
/* mem_1.cpp */
-extern void *mem_normalize(void *in);
+inline void *mem_normalize(void *in) {
+ return in;
+}
/* mem_2.cpp */
extern void *mem_get(long size);
-extern void *mem_get_name(long size, const char *block_name);
-extern int mem_free(void *block);
-extern int mem_adjust(void *target, long size);
+
+/**
+ * Allocates the specified amount of memory and returns a pointer to it.
+ */
+extern void *mem_get_name(long size, const char * /*block_name */= nullptr);
+
+/**
+ * Deallocates a previously allocated chunk of memory. Returns
+ * true if an error occurred (?!), false otherwise.
+ */
+extern bool mem_free(void *block);
+
+/**
+ * Adjusts allocated block size
+ */
+extern int mem_adjust_impl(void *&target, long size);
+
+template <typename T>
+inline int mem_adjust(T *&target, long size) {
+ return mem_adjust_impl(reinterpret_cast<void *&>(target), size);
+}
+
extern void mem_save_free();
extern void mem_restore_free();
+
+/**
+ * Returns the string label of the memory block
+ */
extern void mem_get_block_name(byte *block, char *block_name);
/* mem_3.cpp */
diff --git a/engines/mads/madsv2/core/mem_2.cpp b/engines/mads/madsv2/core/mem_2.cpp
new file mode 100644
index 00000000000..498b034750e
--- /dev/null
+++ b/engines/mads/madsv2/core/mem_2.cpp
@@ -0,0 +1,69 @@
+/* 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/textconsole.h"
+#include "mads/madsv2/core/general.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+void *mem_get_name(long size, const char *) {
+ void *memory_block = nullptr;
+ if (size > 0)
+ memory_block = malloc(size);
+
+ return memory_block;
+}
+
+void *mem_get(long size) {
+ return (mem_get_name(size, "$sys$"));
+}
+
+void mem_get_block_name(byte *block, char *block_name) {
+ // TODO: See if the block_name is needed. If so, we'll need to simulate the
+ // original by allocating extra space to store it
+ error("TODO: mem_get_block_name");
+}
+
+
+bool mem_free(void *memory_block) {
+ free(memory_block);
+ return false;
+}
+
+int mem_adjust_impl(void *&target, long size) {
+ void *p = realloc(target, size);
+ if (p == NULL)
+ return -1;
+ target = p;
+ return 0;
+}
+
+void mem_save_free(void) {
+ // No implementation
+}
+
+void mem_restore_free(void) {
+ // No implementation
+}
+
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/core/mouse.h b/engines/mads/madsv2/core/mouse.h
index 88c6136bd9e..c64c614e85a 100644
--- a/engines/mads/madsv2/core/mouse.h
+++ b/engines/mads/madsv2/core/mouse.h
@@ -23,6 +23,7 @@
#define MADS_CORE_MOUSE_H
#include "mads/madsv2/core/general.h"
+#include "mads/madsv2/core/sprite.h"
namespace MADS {
namespace MADSV2 {
@@ -54,30 +55,30 @@ extern int mouse_old_y; /* Cursor Y position on previous round */
extern long mouse_clock; /* Timing clock to insure at least 1 tick */
-/* mouse_1.asm */
-int mouse_init(int driver_flag, int mouse_video_mode);
+/* mouse_1.cpp */
+extern int mouse_init(int driver_flag, int mouse_video_mode);
-/* mouse_1.asm */
-int mouse_set_hotspot(int spot_x, int spot_y);
+/* mouse_1.cpp */
+extern int mouse_set_hotspot(int spot_x, int spot_y);
-void mouse_change_cursor_begin(void);
-void mouse_change_cursor_end(void);
+void mouse_change_cursor_begin();
+void mouse_change_cursor_end();
-/* mouse_1.asm */
-void mouse_screen_swap(int mouse_video_mode);
-int mouse_get_video_mode(void);
+/* mouse_1.cpp */
+extern void mouse_screen_swap(int mouse_video_mode);
+extern int mouse_get_video_mode();
-/* mouse_1.asm */
-void mouse_begin_double(int first_video_mode, int second_video_mode,
+/* mouse_1.cpp */
+extern void mouse_begin_double(int first_video_mode, int second_video_mode,
int mono_to_right, int auto_freedom);
-void mouse_check_double(void);
-void mouse_end_double(void);
-void mouse_double_freedom(int freedom_flag);
+extern void mouse_check_double();
+extern void mouse_end_double();
+extern void mouse_double_freedom(int freedom_flag);
-/* mouse_1.asm */
-void mouse_show(void);
-void mouse_hide(void);
-int mouse_get_status(int *x, int *y);
+/* mouse_1.cpp */
+extern void mouse_show();
+extern void mouse_hide();
+extern int mouse_get_status(int *x, int *y);
/*
int mouse_press_info (int button, int *status, int *x, int *y);
@@ -86,57 +87,53 @@ int mouse_release_info (int button, int *status, int *x, int *y);
int mouse_in_box_now (int ul_x, int ul_y, int lr_x, int lr_y);
*/
-/* mouse_1.asm */
-void mouse_timing(void);
+/* mouse_1.cpp */
+extern void mouse_timing();
-/* mouse_1.asm */
-void mouse_freeze(void);
-void mouse_thaw(void);
+/* mouse_1.cpp */
+extern void mouse_freeze();
+extern void mouse_thaw();
-/* mouse_1.asm */
-void mouse_horiz_bound(int min_x, int max_x);
-void mouse_vert_bound(int min_y, int max_y);
+/* mouse_1.cpp */
+extern void mouse_horiz_bound(int min_x, int max_x);
+extern void mouse_vert_bound(int min_y, int max_y);
-/* mouse_1.asm */
-void mouse_force(int x, int y);
+/* mouse_1.cpp */
+extern void mouse_force(int x, int y);
-/* mouse_1.asm */
-void mouse_set_work_buffer(byte *work_buffer,
- int wrap_value);
-void mouse_set_view_port_loc(int x1, int y1, int x2, int y2);
-void mouse_set_view_port(int dx, int dy);
+/* mouse_1.cpp */
+extern void mouse_set_work_buffer(byte *work_buffer, int wrap_value);
+extern void mouse_set_view_port_loc(int x1, int y1, int x2, int y2);
+extern void mouse_set_view_port(int dx, int dy);
-/* mouse_1.asm */
-int mouse_refresh_view_port(void);
-void mouse_refresh_done(void);
+/* mouse_1.cpp */
+extern int mouse_refresh_view_port();
+extern void mouse_refresh_done();
-/* mouse_1.asm */
-void mouse_disable_scale(void);
+/* mouse_1.cpp */
+extern void mouse_disable_scale();
-/* mouse_1.asm */
-void mouse_hard_cursor_mode(int mode, Palette *mypal);
+/* mouse_1.cpp */
+extern void mouse_hard_cursor_mode(int mode, Palette *mypal);
-byte *mouse_get_stack(void);
+extern const byte *mouse_get_stack();
+/* mouse_2.cpp */
+extern int mouse_in_box(int ul_x, int ul_y, int lr_x, int lr_y);
+extern void mouse_init_cycle();
+extern void mouse_begin_cycle(int double_flag);
+extern void mouse_end_cycle(int double_flag, int timing_flag);
-/* mouse_2.c */
-int mouse_in_box(int ul_x, int ul_y, int lr_x, int lr_y);
-void mouse_init_cycle(void);
-void mouse_begin_cycle(int double_flag);
-void mouse_end_cycle(int double_flag, int timing_flag);
+/* mouse_3.cpp */
+extern void mouse_cursor_sprite(SeriesPtr series, int id);
-/* mouse_3.c */
-void mouse_cursor_sprite(void *series, int id);
-
-
-/* mouse_4.c */
-void mouse_video_init(void);
-void mouse_video_update(int from_x, int from_y,
- int unto_x, int unto_y,
- int size_x, int size_y);
+/* mouse_4.cpp */
+extern void mouse_video_init();
+extern void mouse_video_update(int from_x, int from_y,
+ int unto_x, int unto_y, int size_x, int size_y);
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/core/mouse_1.cpp b/engines/mads/madsv2/core/mouse_1.cpp
index d9222c6f92d..a45eb72421a 100644
--- a/engines/mads/madsv2/core/mouse_1.cpp
+++ b/engines/mads/madsv2/core/mouse_1.cpp
@@ -19,12 +19,46 @@
*
*/
+#include "common/system.h"
+#include "graphics/cursorman.h"
#include "mads/madsv2/core/general.h"
#include "mads/madsv2/core/mouse_1.h"
namespace MADS {
namespace MADSV2 {
+static const byte cursor_mask[16][16] = {
+ /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 */
+ {255, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ { 0, 7, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ { 0, 7, 7, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ { 0, 7, 15, 7, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ { 0, 7, 15, 15, 7, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ { 0, 7, 15, 15, 15, 7, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ { 0, 7, 15, 15, 15, 15, 7, 0, 255, 255, 255, 255, 255, 255, 255, 255},
+ { 0, 7, 15, 15, 15, 15, 15, 7, 0, 255, 255, 255, 255, 255, 255, 255},
+ { 0, 7, 15, 15, 15, 15, 7, 7, 7, 0, 255, 255, 255, 255, 255, 255},
+ { 0, 7, 15, 7, 15, 15, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255},
+ { 0, 7, 7, 0, 7, 15, 7, 0, 255, 255, 255, 255, 255, 255, 255, 255},
+ {255, 0, 0, 255, 0, 7, 15, 0, 255, 255, 255, 255, 255, 255, 255, 255},
+ {255, 255, 255, 255, 0, 7, 15, 0, 255, 255, 255, 255, 255, 255, 255, 255},
+ {255, 255, 255, 255, 255, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+};
+
+void mouse_show() {
+ if (!CursorMan.isVisible())
+ CursorMan.showMouse(true);
+}
+
+void mouse_hide() {
+ CursorMan.showMouse(false);
+}
+
+void mouse_force(int x, int y) {
+ g_system->warpMouse(x, y);
+}
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/core/mouse_3.cpp b/engines/mads/madsv2/core/mouse_3.cpp
new file mode 100644
index 00000000000..b3c9cbe7e39
--- /dev/null
+++ b/engines/mads/madsv2/core/mouse_3.cpp
@@ -0,0 +1,70 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "mads/madsv2/core/general.h"
+#include "mads/madsv2/core/sprite.h"
+#include "mads/madsv2/core/buffer.h"
+#include "mads/madsv2/core/mouse_1.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+int mouse_hot_x = 0;
+int mouse_hot_y = 0;
+
+void mouse_cursor_sprite(SeriesPtr series, int id) {
+ byte work_area[17][17];
+ Buffer load_buffer = { 17, 17 };
+ int hot_x, hot_y, count;
+
+ load_buffer.data = &work_area[0][0];
+
+ hot_x = 0;
+ hot_y = 0;
+
+ buffer_fill(load_buffer, 255);
+ sprite_draw(series, id, &load_buffer, 0, 0);
+
+ for (count = 0; count < 16; count++) {
+ if (work_area[count][16] != 255) hot_y = count;
+ if (work_area[16][count] != 255) hot_x = count;
+ }
+
+ if ((hot_x != mouse_hot_x) || (hot_y != mouse_hot_y)) {
+ mouse_hot_x = hot_x;
+ mouse_hot_y = hot_y;
+
+ mouse_hide();
+ mouse_set_hotspot(hot_x, hot_y);
+ buffer_rect_copy(load_buffer, mouse_cursor_buffer, 0, 0, 16, 16);
+ mouse_show();
+ } else {
+ mouse_change_cursor_begin();
+ buffer_rect_copy(load_buffer, mouse_cursor_buffer, 0, 0, 16, 16);
+ mouse_change_cursor_end();
+ }
+}
+
+} // namespace MADSV2
+} // namespace MADS
+
+
+
diff --git a/engines/mads/madsv2/core/mouse_4.cpp b/engines/mads/madsv2/core/mouse_4.cpp
new file mode 100644
index 00000000000..853a4840abb
--- /dev/null
+++ b/engines/mads/madsv2/core/mouse_4.cpp
@@ -0,0 +1,54 @@
+/* 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 "mads/madsv2/core/general.h"
+#include "mads/madsv2/core/video.h"
+#include "mads/madsv2/core/mouse.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+extern Buffer scr_work;
+
+void mouse_video_init() {
+ mouse_set_work_buffer(scr_work.data, scr_work.x);
+ mouse_set_view_port_loc(0, 0, scr_work.x - 1, scr_work.y - 1);
+ mouse_set_view_port(0, 0);
+}
+
+void mouse_video_update(int from_x, int from_y, int unto_x, int unto_y,
+ int size_x, int size_y) {
+ int refresh_flag;
+
+ mouse_freeze();
+ refresh_flag = mouse_refresh_view_port();
+
+ video_update(&scr_work, from_x, from_y, unto_x, unto_y, size_x, size_y);
+
+ if (refresh_flag) mouse_refresh_done();
+ mouse_thaw();
+}
+
+} // namespace MADSV2
+} // namespace MADS
+
+
+
diff --git a/engines/mads/madsv2/core/object.cpp b/engines/mads/madsv2/core/object.cpp
new file mode 100644
index 00000000000..0925ff7b005
--- /dev/null
+++ b/engines/mads/madsv2/core/object.cpp
@@ -0,0 +1,480 @@
+/* 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 "mads/madsv2/core/general.h"
+#include "mads/madsv2/core/buffer.h"
+#include "mads/madsv2/core/cycle.h"
+#include "mads/madsv2/core/ems.h"
+#include "mads/madsv2/core/env.h"
+#include "mads/madsv2/core/error.h"
+#include "mads/madsv2/core/fileio.h"
+#include "mads/madsv2/core/inter.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/keys.h"
+#include "mads/madsv2/core/magic.h"
+#include "mads/madsv2/core/matte.h"
+#include "mads/madsv2/core/mcga.h"
+#include "mads/madsv2/core/mem.h"
+#include "mads/madsv2/core/mouse.h"
+#include "mads/madsv2/core/object.h"
+#include "mads/madsv2/core/pack.h"
+#include "mads/madsv2/core/pal.h"
+#include "mads/madsv2/core/popup.h"
+#include "mads/madsv2/core/room.h"
+#include "mads/madsv2/core/sprite.h"
+#include "mads/madsv2/core/text.h"
+#include "mads/madsv2/core/tile.h"
+#include "mads/madsv2/core/video.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+#define object_extra_colors 10
+
+ObjectPtr object = NULL;
+int num_objects = 0;
+
+int object_ems_handle = BUFFER_PRESERVE;
+char object_speech_resource[20] = "*SPCHNOTE.DSR";
+
+
+void object_unload(void) {
+ if (object != NULL) {
+ mem_free(object);
+ object = NULL;
+ }
+}
+
+int object_load(void) {
+ int count;
+ int error_flag = true;
+ long mem_to_get;
+ Common::SeekableReadStream *handle;
+
+ handle = env_open("*OBJECTS.DAT", "rb");
+ if (handle == NULL) goto done;
+
+ if (!fileio_fread_f(&num_objects, sizeof(int), 1, handle)) goto done;
+
+ mem_to_get = sizeof(Object) * num_objects;
+ object = (ObjectPtr)mem_get_name(mem_to_get, "$objects");
+ if (object == NULL) goto done;
+
+ for (count = 0; (count < num_objects); count++) {
+ if (!fileio_fread_f(&object[count], sizeof(Object), 1, handle)) goto done;
+ }
+
+ inven_num_objects = 0;
+ for (count = 0; count < num_objects; count++) {
+ if (object[count].location == PLAYER) {
+ if (inven_num_objects < INVEN_MAX_OBJECTS) {
+ inven[inven_num_objects++] = count;
+ } else {
+ error_report(ERROR_PLAYER_INVENTORY_FULL, ERROR, MODULE_OBJECT, inven_num_objects, count);
+ }
+ }
+ }
+
+ error_flag = false;
+
+done:
+ delete handle;
+ if (error_flag)
+ object_unload();
+
+ return error_flag;
+}
+
+int object_named(int vocab_id) {
+ int named = -1;
+ int count;
+
+ for (count = 0; (named < 0) && (count < num_objects); count++) {
+ if (vocab_id == (int)object[count].vocab_id) {
+ named = count;
+ }
+ }
+
+ return named;
+}
+
+int object_is_here(int object_id) {
+ int here_flag = false;
+
+ if (object_id < 0) goto done;
+
+ if (object[object_id].location != room_id) goto done;
+
+ here_flag = true;
+
+done:
+ return here_flag;
+}
+
+int object_has_quality(int object_id, int quality_id) {
+ int has_quality = false;
+ int count;
+
+ for (count = 0; count < (int)object[object_id].num_qualities; count++) {
+ if (object[object_id].quality_id[count] == (byte)quality_id) {
+ has_quality = true;
+ }
+ }
+
+ return has_quality;
+}
+
+long object_check_quality(int object_id, int quality_id) {
+ long quality_value = 0;
+ int count;
+
+ for (count = 0; count < (int)object[object_id].num_qualities; count++) {
+ if (object[object_id].quality_id[count] == (byte)quality_id) {
+ quality_value = object[object_id].quality_value[count];
+ }
+ }
+
+ return quality_value;
+}
+
+void object_set_quality(int object_id, int quality_id, long quality_value) {
+ int count;
+
+ for (count = 0; count < (int)object[object_id].num_qualities; count++) {
+ if (object[object_id].quality_id[count] == (byte)quality_id) {
+ object[object_id].quality_value[count] = quality_value;
+ }
+ }
+}
+
+/**
+ * Given a buffer and a pointer to a 256 byte map, translates every
+ * color in the buffer using the map.
+ */
+static void object_remap_buffer(Buffer *buffer, byte *map) {
+ byte *data = buffer->data;
+ int size = buffer->x * buffer->y;
+
+ for (int i = 0; i < size; i++)
+ data[i] = map[data[i]];
+}
+
+int object_examine(int number, long message, int speech) {
+ int restored_screen = false;
+ char sprite_name[80];
+ byte *old_master_palette;
+ byte *greyed_master_palette;
+ dword *old_color_status;
+ int old_flag_used[PAL_MAXFLAGS];
+ int num_colors;
+ int cycling_save;
+ int y_base;
+ //int x_size;// , y_size;
+ int count;
+ int refresh_flag;
+ int object_preserve_handle;
+ byte map[256];
+ //SeriesPtr object_series = NULL;
+ RGBcolor top_eight[8];
+
+ /* Wait cursor */
+ cursor_id = 2;
+ if (cursor_id != cursor_last) {
+ mouse_cursor_sprite(cursor, cursor_id);
+ cursor_last = cursor_id;
+ }
+
+ inter_turn_off_object();
+ inter_screen_update();
+
+ memcpy(top_eight, &master_palette[248].r, 8 * sizeof(RGBcolor));
+
+ /* Use attribute buffer to cheat on memory requirements a bit */
+
+ old_master_palette = scr_depth.data;
+ greyed_master_palette = scr_depth.data + sizeof(Palette);
+ old_color_status = (dword *) (greyed_master_palette + sizeof(Palette));
+
+ sprite_force_memory = ((byte *)old_color_status) + (sizeof(dword) * 256);
+ sprite_force_size = 22400; /* Use rest of attribute buffer, at most */
+
+ /* Notify "magic" that we intend to do a grey scale on all guns */
+
+ for (count = 0; count < 3; count++) {
+ magic_color_flags[count] = true;
+ }
+
+ /* Turn off all cycling */
+
+ cycling_save = cycling_active;
+ cycling_active = false;
+
+ /* Get sprite series name */
+
+ Common::strcpy_s(sprite_name, "*OB");
+ env_catint(sprite_name, number, 3);
+ Common::strcat_s(sprite_name, ".SS");
+
+ /* Prepare for flicker-free mouse updates */
+
+ mouse_set_work_buffer(scr_main.data, video_x);
+ mouse_set_view_port_loc(0, 0, video_x - 1, video_y - 1);
+
+ /* Save a copy of our work buffer somewhere (probably in EMS) */
+
+ matte_map_work_screen();
+ object_preserve_handle = buffer_preserve(&scr_main, object_ems_handle, work_screen_ems_handle,
+ 0, 0, video_x, video_y);
+ matte_map_work_screen();
+
+ /* Save a copy of current palette structure */
+
+ memcpy(old_master_palette, master_palette, sizeof(Palette));
+ memcpy(old_color_status, color_status, sizeof(dword) << 8);
+ memcpy(old_flag_used, flag_used, sizeof(int) * PAL_MAXFLAGS);
+
+ /* Clear out all non-reserved colors in the palette */
+
+ num_colors = 256 - (KERNEL_RESERVED_LOW_COLORS + KERNEL_RESERVED_HIGH_COLORS);
+
+ for (count = 0; count < 256; count++) {
+ if ((count < KERNEL_RESERVED_LOW_COLORS) || (count >= (256 - (KERNEL_RESERVED_HIGH_COLORS + object_extra_colors)))) {
+ map[count] = (byte)count;
+ color_status[count] = 1;
+ } else {
+ color_status[count] = 0;
+ }
+ }
+
+ for (count = 0; count < PAL_MAXFLAGS; count++) {
+ flag_used[count] = 0;
+ }
+
+ /* Fade to a grey-scale picture */
+
+ magic_fade_to_grey(master_palette, &map[KERNEL_RESERVED_LOW_COLORS],
+ KERNEL_RESERVED_LOW_COLORS, num_colors,
+ OBJECT_GREY_BASE, OBJECT_GREY_COLORS,
+ OBJECT_GREY_SPEED, OBJECT_GREY_STEPS);
+
+ /* Need to save a copy of greyed out palette */
+
+ memcpy(greyed_master_palette, master_palette, sizeof(Palette));
+
+ /* Remap the contents of the work screen to the top 8 colors of the */
+ /* palette (the true grey scale to which all other colors have been */
+ /* faded). This will allow us to change palettes to load the object */
+ /* sprite. */
+
+ object_remap_buffer(&scr_main, map);
+
+ /* Copy the remapped version of the work buffer onto the screen; this */
+ /* will have no visible effect but will free up a good portion of the */
+ /* palette. */
+
+ mouse_freeze();
+ refresh_flag = mouse_refresh_view_port();
+
+ video_update(&scr_main, 0, 0, 0, 0, video_x, video_y);
+
+ if (refresh_flag) mouse_refresh_done();
+ mouse_thaw();
+
+ mcga_setpal(&master_palette);
+
+ /* Load the object series */
+ /* object_series = sprite_series_load (sprite_name, PAL_MAP_BACKGROUND); */
+
+ matte_map_work_screen();
+
+ /* Now set the palette to include the colors for this series. */
+ /* mcga_setpal (&master_palette); */
+
+ y_base = OBJECT_VIEW_OFFSET;
+
+ /* Draw the object sprite on the screen */
+
+ /*
+ if (object_series != NULL) {
+ x_size = object_series->index[0].xs;
+ y_size = object_series->index[0].ys;
+ x_base = (video_x >> 1) - (x_size >> 1);
+ sprite_draw (object_series, 1, &scr_main, x_base, y_base);
+
+ mouse_hide();
+
+ video_update (&scr_main, x_base, y_base, x_base, y_base, x_size, y_size);
+
+ mouse_show();
+
+ y_base += y_size;
+ }
+ */
+
+ y_base += OBJECT_VIEW_OFFSET;
+
+ if (message) {
+ text_saves_screen = false;
+ /* text_default_y = y_base; */
+
+ /*
+ for (count = 0; count < (popup_num_colors - 1); count++) {
+ popup_colors[count] -= object_extra_colors;
+ }
+ */
+
+ memcpy(&cycling_palette[248].r, &master_palette[248].r, 8 * sizeof(RGBcolor));
+
+ /* pl if (speech) {
+ if (speech_system_active && speech_on) {
+ speech_ems_play (object_speech_resource, speech);
+ }
+ }
+ */
+
+ text_show(message);
+
+ /* pl if (speech && speech_system_active && speech_on) {
+ speech_all_off();
+ }
+ */
+
+ /*
+ for (count = 0; count < (popup_num_colors - 1); count++) {
+ popup_colors[count] += object_extra_colors;
+ }
+ */
+
+ text_saves_screen = true;
+ /* text_default_y = POPUP_CENTER; */
+ } else {
+ keys_get();
+ }
+
+ /* Flush object from memory */
+
+ /*
+ if (object_series != (SeriesPtr) sprite_force_memory) mem_free (object_series);
+ */
+
+ /* If we saved the work buffer in EMS, we can now fade back to the */
+ /* original screen. */
+
+ if (object_preserve_handle != BUFFER_NOT_PRESERVED) {
+
+ /* Restore a copy of the work screen */
+
+ matte_map_work_screen();
+
+ buffer_restore_keep_flag = true;
+ buffer_restore(&scr_main, object_preserve_handle, work_screen_ems_handle, 0, 0, video_x, video_y);
+ buffer_restore_keep_flag = false;
+
+ matte_map_work_screen();
+
+ /* We must remap to the special grey version first, so that we can */
+ /* change back to the first palette. */
+
+ object_remap_buffer(&scr_main, map);
+
+ /* Restore old master palette structure. */
+
+ memcpy(master_palette, old_master_palette, sizeof(Palette));
+ memcpy(color_status, old_color_status, sizeof(dword) << 8);
+ memcpy(flag_used, old_flag_used, sizeof(int) * PAL_MAXFLAGS);
+
+ /* Copy a greyed-out version of picture onto the screen (erasing the */
+ /* object picture). */
+
+ mouse_freeze();
+ refresh_flag = mouse_refresh_view_port();
+
+ video_update(&scr_main, 0, 0, 0, 0, video_x, video_y);
+
+ if (refresh_flag) mouse_refresh_done();
+ mouse_thaw();
+
+ /* Now we can change back to the fully greyed-out version of the */
+ /* original master palette. */
+
+ mcga_setpal((Palette *)greyed_master_palette);
+
+ /* We must copy the work buffer from EMS again, since we have destroyed */
+ /* the first version we brought back (by remapping to grey again). */
+
+ matte_map_work_screen();
+
+ buffer_restore(&scr_main, object_preserve_handle, work_screen_ems_handle, 0, 0, video_x, video_y);
+
+ matte_map_work_screen();
+
+ /* We are ready to copy the true work buffer image back onto the screen. */
+ /* Since the palette is now fully greyed out, there will be no visible */
+ /* change. */
+
+ mouse_freeze();
+ refresh_flag = mouse_refresh_view_port();
+
+ video_update(&scr_main, 0, 0, 0, 0, video_x, video_y);
+
+ if (refresh_flag) mouse_refresh_done();
+ mouse_thaw();
+
+ /* Finally, we can fade back to our original palette. */
+
+ magic_fade_from_grey((RGBcolor *)greyed_master_palette, master_palette,
+ KERNEL_RESERVED_LOW_COLORS, num_colors,
+ OBJECT_GREY_BASE, OBJECT_GREY_COLORS,
+ OBJECT_GREY_SPEED, OBJECT_GREY_STEPS);
+
+ restored_screen = true;
+ }
+
+ /* done: */
+ /* Turn color cycling back on. */
+
+ memcpy(&cycling_palette[248].r, top_eight, 8 * sizeof(RGBcolor));
+ mcga_setpal_range(&cycling_palette, 248, 8);
+
+ cycling_active = cycling_save;
+
+ /* Don't forget to reload the attribute screen which we wrote all */
+ /* over. */
+
+ sprite_force_memory = NULL;
+
+
+ if (room_load_variant(room_id, room_variant, NULL, room,
+ &scr_depth, &scr_walk, &scr_special,
+ &depth_map, &depth_resource, tile_attribute_handle)) {
+ error_report(ERROR_VARIANT_LOAD_FAILURE, WARNING, MODULE_OBJECT, room_load_error, (room_id * 10) + room_variant);
+ }
+ tile_pan(&depth_map, picture_view_x, picture_view_y);
+
+ kernel_force_refresh();
+
+ inter_spin_object(inven[active_inven]);
+
+ return (restored_screen);
+}
+
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/core/object.h b/engines/mads/madsv2/core/object.h
index 9747c040ec0..a7a7906ac5f 100644
--- a/engines/mads/madsv2/core/object.h
+++ b/engines/mads/madsv2/core/object.h
@@ -95,22 +95,22 @@ extern int num_objects;
extern int object_ems_handle;
-/* object_1.cpp */
-int fastcall object_load(void);
-void fastcall object_unload(void);
+extern int object_load(void);
+extern void object_unload(void);
-/* object_2.cpp */
-int fastcall object_named(int vocab_id);
-int fastcall object_is_here(int object_id);
+extern int object_named(int vocab_id);
+extern int object_is_here(int object_id);
/* object_3.cpp */
-int fastcall object_has_quality(int object_id, int quality_id);
-long fastcall object_check_quality(int object_id, int quality_id);
-void fastcall object_set_quality(int object_id, int quality_id,
- long quality_value);
+extern int object_has_quality(int object_id, int quality_id);
+extern long object_check_quality(int object_id, int quality_id);
+extern void object_set_quality(int object_id, int quality_id, long quality_value);
-/* object_4.cpp */
-int fastcall object_examine(int number, long message, int speech);
+/**
+ * Called when the player examines an object from his inventory;
+ * greys out main area, then loads & displays object sprite.
+ */
+extern int object_examine(int number, long message, int speech);
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/core/pack.h b/engines/mads/madsv2/core/pack.h
index b55799b21cd..938f129fc82 100644
--- a/engines/mads/madsv2/core/pack.h
+++ b/engines/mads/madsv2/core/pack.h
@@ -113,11 +113,10 @@ extern long pack_read_count; /* Size read so */
extern long pack_write_size; /* Size left to write */
extern long pack_write_count; /* Size written so */
-extern word(*pack_read_routine)(char *buffer, word *size);
/* Pointer to read routine */
-extern void (*pack_write_routine)
-(char *buffer, word *size);
+extern word (*pack_read_routine)(char *buffer, word *size);
/* Pointer to write routine */
+extern void (*pack_write_routine)(char *buffer, word *size);
extern word pack_mode; /* Packing mode (zip/none) */
extern byte *pack_buffer; /* Packing scrap buffer */
@@ -226,7 +225,7 @@ extern int pack_ems_page_marker;
extern int pack_ems_page_offset;
/* pack_d.c */
-word pack_write_ems(char *buffer, word *mysize);
+void pack_write_ems(char *buffer, word *mysize);
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/core/pack_1.h b/engines/mads/madsv2/core/pack_1.h
new file mode 100644
index 00000000000..9aa4f7cc138
--- /dev/null
+++ b/engines/mads/madsv2/core/pack_1.h
@@ -0,0 +1,44 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 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 MADS_CORE_PACK_1_H
+#define MADS_CORE_PACK_1_H
+
+#include "common/stream.h"
+#include "mads/madsv2/core/general.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+extern byte *pack_read_memory_ptr;
+extern byte *pack_write_memory_ptr;
+extern Common::SeekableReadStream *pack_read_file_handle;
+extern Common::WriteStream *pack_write_file_handle;
+
+word pack_read_memory(char *buffer, word *size);
+void pack_write_memory(char *buffer, word *size);
+word pack_read_file(char *buffer, word *size);
+void pack_write_file(char *buffer, word *size);
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/pack_5.h b/engines/mads/madsv2/core/pack_5.h
new file mode 100644
index 00000000000..94974971cc5
--- /dev/null
+++ b/engines/mads/madsv2/core/pack_5.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 MADS_CORE_PACK_5_H
+#define MADS_CORE_PACK_5_H
+
+#include "mads/madsv2/core/general.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+extern word (*pack_read_routine)(char *buffer, word *size);
+extern void (*pack_write_routine)(char *buffer, word *size);
+
+extern word pack_mode;
+extern byte *pack_buffer;
+extern word pack_buffer_size;
+
+extern long pack_read_size;
+extern long pack_read_count;
+extern long pack_write_size;
+extern long pack_write_count;
+
+extern byte pack_zip_enabled; /* ZIP packing enabled */
+extern byte pack_pfab_enabled; /* PFAB packing enabled */
+extern int pack_strategy; /* Current packing strategy */
+
+/* All compression routines called through function pointers, so that */
+/* we can determine at compile time which compression modules will be */
+/* linked. */
+
+extern unsigned short (*pack_implode_routine)
+ (unsigned (*read_buff)(char *buffer,unsigned short *size),
+ void (*write_buff)(char *buffer,unsigned short *size),
+ char *work_buff,
+ unsigned short int *type,
+ unsigned short int *dsize);
+
+extern unsigned (*pack_explode_routine)
+ (unsigned (*read_buff)(char *buffer,unsigned short *size),
+ void (*write_buff)(char *buffer,unsigned short *size),
+ char *work_buff);
+
+extern unsigned short (*pack_pFABcomp_routine)
+ (unsigned (*read_buff)(char *buffer,unsigned short *size),
+ void (*write_buff)(char *buffer,unsigned short *size),
+ char *work_buff,
+ unsigned short int *type,
+ unsigned short int *dsize);
+
+extern unsigned (*pack_pFABexp0_routine)
+ (unsigned (*read_buff)(char *buffer,unsigned short *size),
+ void (*write_buff)(char *buffer,unsigned short *size),
+ char *work_buff);
+
+extern unsigned (*pack_pFABexp1_routine)
+ (unsigned (*read_buff)(char *buffer,unsigned short *size),
+ char *write_buf,
+ char *work_buff);
+
+extern unsigned (*pack_pFABexp2_routine)
+ (byte *read_buf,
+ byte *write_buf,
+ char *work_buff);
+
+word pack_a_packet(int packing_flag, int explode_mode);
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/pack_6.cpp b/engines/mads/madsv2/core/pack_6.cpp
new file mode 100644
index 00000000000..738e37fa8e0
--- /dev/null
+++ b/engines/mads/madsv2/core/pack_6.cpp
@@ -0,0 +1,238 @@
+/* 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 "mads/madsv2/core/general.h"
+#include "mads/madsv2/core/implode.h"
+#include "mads/madsv2/core/mem.h"
+#include "mads/madsv2/core/keys.h"
+#include "mads/madsv2/core/error.h"
+#include "mads/madsv2/core/ems.h"
+#include "mads/madsv2/core/pack.h"
+#include "mads/madsv2/core/pack_1.h"
+#include "mads/madsv2/core/pack_5.h"
+#include "mads/madsv2/core/pack_d.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+byte *pack_special_buffer = NULL;
+void (*(pack_special_function))() = NULL;
+
+static void pack_activate(void) {
+ if (pack_special_function)
+ pack_special_function();
+}
+
+void pack_set_special_buffer(byte *buffer_address, void (*(special_function))()) {
+ pack_special_buffer = buffer_address;
+ pack_special_function = special_function;
+}
+
+/*
+/* pack_data()
+/*
+/* Transfers a data packet from the specified source to the specified
+/* destination, using the specified packing strategy.
+/*
+/* packing_flag Specifies the packing strategy:
+/* PACK_IMPLODE (Compresses data)
+/* PACK_EXPLODE (Decompresses data)
+/* PACK_RAW_COPY (Copies data)
+/*
+/* size # of bytes to move
+/*
+/* source_type Specifies the source type:
+/* FROM_DISK or FROM_MEMORY.
+/*
+/* source If FROM_DISK, then this is a FILE *handle.
+/* If FROM_MEMORY, this is a far memory pointer.
+/*
+/* dest_type Specifies the destination type:
+/* TO_DISK, TO_MEMORY, or TO_EMS.
+/*
+/* dest Same as "source" but for destination. For
+/* TO_EMS, "dest" is a far pointer to an
+/* EmsPtr structure.
+/*
+/*
+/* Example:
+/*
+/* result =pack_data (PACK_EXPLODE, 132000,
+/* FROM_DISK, file_handle,
+/* TO_MEMORY, memory_pointer);
+/*
+/* (Decompresses 132000 bytes from the already open
+/* disk file "file_handle", and writes it to memory
+/* far the specified address. Size is always the
+/* uncompressed size of the data. Result will be
+/* the # of bytes actually written -- 132000 if successful).
+/*
+*/
+long fastcall pack_data(int packing_flag, long size,
+ int source_type, void *source, int dest_type, void *dest) {
+ int explode_mode = 0;
+ long *loop_value;
+ long *return_value;
+ EmsPtr *ems_dest;
+ int result;
+
+ /* Select the read data routine */
+
+ if (source_type == FROM_MEMORY) {
+ pack_read_routine = pack_read_memory;
+ pack_read_memory_ptr = (byte *)source;
+ } else {
+ /* FROM_DISK */
+ pack_read_routine = pack_read_file;
+ pack_read_file_handle = (Common::SeekableReadStream *)source;
+ }
+
+ /* Select the write data routine */
+
+ if (dest_type == TO_EMS) {
+ pack_write_routine = pack_write_ems;
+ ems_dest = (EmsPtr *)dest;
+ pack_ems_page_handle = ems_dest->handle;
+ pack_ems_page_marker = ems_dest->page_marker;
+ pack_ems_page_offset = ems_dest->page_offset;
+ } else if (dest_type == TO_MEMORY) {
+ pack_write_routine = pack_write_memory;
+ pack_write_memory_ptr = (byte *)dest;
+ } else {
+ /* TO_DISK */
+ pack_write_routine = pack_write_file;
+ pack_write_file_handle = (Common::WriteStream *)dest;
+ }
+
+ /* Set up the packing parameters */
+
+ pack_read_count = pack_write_count = 0;
+
+ switch (packing_flag) {
+ case PACK_IMPLODE:
+ if (pack_strategy == PACK_PFAB) {
+ pack_buffer_size = PACK_PFABCOMP_SIZE;
+ if (pack_pFABcomp_routine == NULL) {
+ error_report(ERROR_EXPLODER_NULL, SEVERE, MODULE_EXPLODER, packing_flag, pack_strategy);
+ }
+ } else {
+ pack_buffer_size = PACK_IMPLODE_SIZE;
+ if (pack_implode_routine == NULL) {
+ error_report(ERROR_EXPLODER_NULL, SEVERE, MODULE_EXPLODER, packing_flag, pack_strategy);
+ }
+ }
+ pack_read_size = size; /* Stop after reading "size" bytes */
+ pack_write_size = -1; /* Write as many bytes as necessary */
+ loop_value = &pack_read_size; /* Loop control is # bytes to read */
+ return_value = &pack_read_count; /* Return value is # bytes read */
+ break;
+
+ case PACK_EXPLODE:
+ pack_read_size = -1; /* Read as many bytes as necessary */
+ pack_write_size = size; /* Stop after writing "size" bytes */
+ loop_value = &pack_write_size; /* Loop control is # bytes to write */
+ if (pack_strategy == PACK_PFAB) {
+ if ((source_type == FROM_MEMORY) && (dest_type == FROM_MEMORY) &&
+ (pack_pFABexp2_routine != NULL)) {
+ return_value = &size; /* Fake return value */
+ pack_buffer_size = PACK_PFABEXP2_SIZE;
+ explode_mode = 2;
+ } else if ((dest_type == TO_DISK) || (dest_type == TO_EMS)) {
+ return_value = &pack_write_count; /* Return value is # bytes written */
+ pack_buffer_size = PACK_PFABEXP0_SIZE;
+ explode_mode = 0;
+ if (pack_pFABexp0_routine == NULL) {
+ error_report(ERROR_EXPLODER_NULL, SEVERE, MODULE_EXPLODER, packing_flag, pack_strategy);
+ }
+ } else {
+ return_value = &size; /* Fake return value for file-to_mem*/
+ pack_buffer_size = PACK_PFABEXP1_SIZE;
+ explode_mode = 1;
+ if (pack_pFABexp1_routine == NULL) {
+ error_report(ERROR_EXPLODER_NULL, SEVERE, MODULE_EXPLODER, packing_flag, pack_strategy);
+ }
+ }
+ } else {
+ return_value = &pack_write_count;
+ pack_buffer_size = PACK_EXPLODE_SIZE;
+ if (pack_explode_routine == NULL) {
+ error_report(ERROR_EXPLODER_NULL, SEVERE, MODULE_EXPLODER, packing_flag, pack_strategy);
+ }
+ }
+ break;
+
+ case PACK_RAW_COPY:
+ default:
+ pack_buffer_size = PACK_RAW_COPY_SIZE;
+ pack_read_size = size; /* Stop after reading "size" bytes */
+ pack_write_size = size; /* ... or after writing "size" bytes */
+ loop_value = &pack_read_size; /* Loop control is # bytes to read */
+ return_value = &pack_write_count; /* Return value is # bytes written */
+ break;
+ }
+
+ /* Get memory for packing buffer if necessary */
+
+ pack_buffer = NULL;
+
+ if (pack_special_buffer == NULL) {
+ pack_buffer = (byte *)mem_get_name(pack_buffer_size, "$pack$");
+ if (pack_buffer == NULL) {
+ *return_value = 0;
+ goto done;
+ }
+ } else {
+ pack_buffer = pack_special_buffer;
+ }
+
+ /* Keep moving records until we run out of data or die */
+
+ if ((packing_flag == PACK_EXPLODE) && (dest_type == TO_MEMORY)) {
+ result = pack_a_packet(packing_flag, explode_mode);
+ if (result != CMP_NO_ERROR) {
+ *return_value = 0;
+ error_report(ERROR_EXPLODER_EXPLODED, SEVERE, MODULE_EXPLODER, (packing_flag * 1000) + explode_mode, result);
+ goto done;
+ }
+ } else {
+ while (*loop_value > 0) {
+ if (pack_a_packet(packing_flag, false) != CMP_NO_ERROR) {
+ *return_value = 0;
+ error_report(ERROR_EXPLODER_EXPLODED, SEVERE, MODULE_EXPLODER, packing_flag, dest_type);
+ goto done;
+ }
+ }
+ }
+
+ /* Free memory and go away */
+
+done:
+ if (pack_special_buffer == NULL) {
+ if (pack_buffer != NULL) mem_free(pack_buffer);
+ } else {
+ pack_activate();
+ }
+
+ return *return_value;
+}
+
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/core/pack_d.h b/engines/mads/madsv2/core/pack_d.h
new file mode 100644
index 00000000000..8508c34f015
--- /dev/null
+++ b/engines/mads/madsv2/core/pack_d.h
@@ -0,0 +1,41 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef MADS_CORE_PACK_D_H
+#define MADS_CORE_PACK_D_H
+
+#include "mads/madsv2/core/general.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+/* pack_d.c */
+extern int pack_ems_page_handle;
+extern int pack_ems_page_marker;
+extern int pack_ems_page_offset;
+
+/* pack_d.cpp */
+extern void pack_write_ems(char *buffer, word *mysize);
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/quote_1.cpp b/engines/mads/madsv2/core/quote_1.cpp
new file mode 100644
index 00000000000..903e88056d8
--- /dev/null
+++ b/engines/mads/madsv2/core/quote_1.cpp
@@ -0,0 +1,144 @@
+/* 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/stream.h"
+#include "mads/madsv2/core/quote.h"
+#include "mads/madsv2/core/fileio.h"
+#include "mads/madsv2/core/env.h"
+#include "mads/madsv2/core/mem.h"
+#include "mads/madsv2/core/sort.h"
+#include "mads/madsv2/core/error.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+int quote_emergency = false;
+
+static int word_get(char *target, Common::SeekableReadStream *handle) {
+ do {
+ *target = (char)handle->readByte();
+ } while (!handle->eos() && !*target++);
+
+ if (handle->err())
+ quote_emergency = true;
+
+ return false;
+}
+
+char *quote_load(int quote_id, ...) {
+ va_list marker;
+ int quote_error = 0;
+ int id;
+ int mark;
+ int now_reading = 0;
+ int now_finding = 0;
+ word list[QUOTE_MAX_LIST_LENGTH];
+ char work[QUOTE_MAX_LIST_LENGTH];
+ char *result = NULL;
+ char *buffer = NULL;
+ char *pointer;
+ long total_mem_avail;
+ long total_mem_needed = 1;
+ long mem_needed;
+ Common::SeekableReadStream *handle = NULL;
+
+ mem_save_free();
+
+ fileio_suppress_unbuffering = true;
+
+ handle = env_open("*quotes.dat", "rb");
+ quote_error = 1;
+ if (handle == NULL) goto done;
+
+ mark = 0;
+ va_start(marker, quote_id);
+ for (id = quote_id; id > 0; id = va_arg(marker, int)) {
+ list[mark++] = id;
+ if (mark > QUOTE_MAX_LIST_LENGTH) {
+ quote_error = 10;
+ goto done;
+ }
+ }
+
+ sort_insertion_16(mark, (byte *)work, list);
+
+ total_mem_avail = mem_get_avail();
+ buffer = pointer = (char *)mem_get_name(total_mem_avail - 64, "$quotes$");
+ if (buffer == NULL) {
+ quote_error = 2;
+ goto done;
+ }
+
+ now_reading = 1;
+ while (now_finding < mark) {
+ if (word_get(work, handle)) {
+ quote_error = 3;
+ goto done;
+ }
+ /*
+ if (!fileio_read_till_null(work, handle)) {
+ goto done;
+ }
+ */
+ if (now_reading == list[now_finding]) {
+ mem_needed = strlen(work) + 3;
+ total_mem_needed += mem_needed;
+ if (total_mem_needed > total_mem_avail) {
+ quote_error = 4;
+ goto done;
+ }
+ Common::strcpy_s(pointer, QUOTE_MAX_LIST_LENGTH, work);
+ pointer += (mem_needed - 2);
+ WRITE_LE_UINT16(pointer, list[now_finding]);
+ pointer += 2;
+ pointer = (char *)mem_normalize(pointer);
+ now_finding++;
+ } else if (now_reading > list[now_finding]) {
+ error_report(ERROR_QUOTE_DUPLICATE_LOAD, WARNING, MODULE_QUOTE, quote_error, list[now_finding]);
+ }
+ now_reading++;
+ }
+
+ if (mem_adjust(buffer, total_mem_needed)) {
+ quote_error = 6;
+ goto done;
+ }
+
+ *pointer = 0;
+ result = buffer;
+
+done:
+ if (result != buffer)
+ mem_free(buffer);
+ delete handle;
+
+ if (result == NULL) {
+ error_report(ERROR_QUOTE_LOAD_FAILED, WARNING, MODULE_QUOTE, now_finding, list[now_finding]);
+ }
+
+ fileio_suppress_unbuffering = false;
+
+ mem_restore_free();
+ return (result);
+}
+
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/core/room.h b/engines/mads/madsv2/core/room.h
index 79e45c3dd18..04d42700eda 100644
--- a/engines/mads/madsv2/core/room.h
+++ b/engines/mads/madsv2/core/room.h
@@ -25,7 +25,6 @@
#include "mads/madsv2/core/general.h"
#include "mads/madsv2/core/vocab.h"
#include "mads/madsv2/core/color.h"
-#include "mads/madsv2/core/anim.h"
#include "mads/madsv2/core/image.h"
#include "mads/madsv2/core/loader.h"
#include "mads/madsv2/core/tile.h"
diff --git a/engines/mads/madsv2/core/sprite_e.cpp b/engines/mads/madsv2/core/sprite_e.cpp
new file mode 100644
index 00000000000..f6b6582358c
--- /dev/null
+++ b/engines/mads/madsv2/core/sprite_e.cpp
@@ -0,0 +1,340 @@
+/* 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 MADS_CORE_SPRITE_E_H
+#define MADS_CORE_SPRITE_E_H
+
+#include "mads/madsv2/core/general.h"
+#include "mads/madsv2/core/mem.h"
+#include "mads/madsv2/core/error.h"
+#include "mads/madsv2/core/pal.h"
+#include "mads/madsv2/core/env.h"
+#include "mads/madsv2/core/loader.h"
+#include "mads/madsv2/core/sprite.h"
+#include "mads/madsv2/core/sprite_h.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+int sprite_error = 0;
+
+byte *sprite_force_memory = NULL;
+long sprite_force_size;
+
+const byte color_table[7] = { 7, 246, 247, 248, 249, 250, 251 };
+
+
+SeriesPtr sprite_series_load(const char *filename, int load_flags) {
+ register int count;
+ int len;
+ int len2;
+ int found, low_color, color_pointer;
+ byte *base_pointer;
+ byte *sprite_marker;
+ char temp_buf[80];
+ char block_name[20];
+ char *mark;
+ long base_quantity, quantity;
+ long initial_quantity;
+ long total_color_size;
+ long largest_block;
+ long total_offset;
+ FileSeries header;
+ FileSpritePtr sprite = NULL;
+ SeriesPtr target = NULL;
+ SeriesPtr result = NULL;
+ SpritePageInfoPtr page_info;
+ SpritePageTablePtr page_table;
+ ColorListPtr color_list = NULL;
+ /* ColorList color_list; */
+ Load load_handle;
+
+ mem_last_alloc_loader = MODULE_SPRITE_LOADER;
+
+ load_handle.open = false;
+
+ Common::strcpy_s(temp_buf, filename);
+ if (strchr(temp_buf, '.') == NULL) {
+ Common::strcat_s(temp_buf, ".SS");
+ }
+
+ Common::strcpy_s(block_name, "S$");
+ mark = temp_buf;
+ mads_strupr(temp_buf);
+ if (*mark == '*') mark++;
+ if ((*mark == 'R') && (*(mark + 1) == 'M')) {
+ mark += 2;
+ }
+ strncat(block_name, mark, 6);
+
+
+ /* Open our input file */
+ if (loader_open(&load_handle, temp_buf, "rb", true)) {
+ sprite_error = SS_ERR_OPENFILE;
+ goto done;
+ }
+
+ /* Set default error condition */
+
+ sprite_error = SS_ERR_READFILE;
+
+ /* Determine length of header, and read it */
+
+ len = sizeof(FileSeries) - sizeof(FileSprite);
+
+ if (!loader_read(&header, len, 1, &load_handle)) goto done;
+
+ if (header.misc_is_a_walker) load_flags |= SPRITE_LOAD_WALKER_INFO;
+
+ /* Determine length of index record array */
+
+ len2 = sizeof(FileSprite) * header.num_sprites;
+
+ base_quantity = sizeof(Series) + (sizeof(Sprite) * (header.num_sprites - 1));
+ if (load_flags & SPRITE_LOAD_WALKER_INFO) {
+ base_quantity += sizeof(WalkerInfo);
+ }
+ initial_quantity = base_quantity;
+ if (header.pack_by_sprite) {
+ base_quantity += (SPRITE_COLOR_TABLE_SIZE + sizeof(SpritePageInfo) + (sizeof(SpritePageTable) * header.num_sprites));
+ }
+ quantity = base_quantity;
+
+ if (!(load_flags & SPRITE_LOAD_HEADER_ONLY)) {
+ if (!header.pack_by_sprite) {
+ quantity += header.total_data_size;
+ }
+ }
+
+ /* Allocate memory for entire series (target) and for the file-formatted */
+ /* index record array (sprite) */
+
+ if (sprite_force_memory != NULL) {
+ if (quantity <= sprite_force_size) {
+ target = (SeriesPtr)sprite_force_memory;
+ }
+ }
+
+ if (target == NULL)
+ // TODO: Check memory alignment
+ target = (SeriesPtr)mem_get_name(quantity, block_name);
+ if (target == NULL) {
+ sprite_error = SS_ERR_NOMOREMEMORY;
+ goto done;
+ }
+
+ // TODO: Check memory alignment
+ sprite = (FileSpritePtr)mem_get_name(len2, "$sp-load");
+ if (sprite == NULL) {
+ sprite_error = SS_ERR_NOMOREMEMORY;
+ goto done;
+ }
+
+ target->walker = NULL;
+ target->color_table = NULL;
+ target->page_info = NULL;
+ target->page_table = NULL;
+ target->arena = NULL;
+
+ /* Read the index record array */
+
+ if (!loader_read(sprite, len2, 1, &load_handle)) {
+ sprite_error = SS_ERR_READFILE;
+ goto done;
+ }
+
+ /* Read the color list */
+
+ total_color_size = load_handle.pack.strategy[load_handle.pack_list_marker].size;
+
+ // TODO: Confirm memory alignment
+ color_list = (ColorListPtr)mem_get_name(total_color_size, "$color$");
+ if (color_list == NULL) {
+ sprite_error = SS_ERR_NOMOREMEMORY;
+ goto done;
+ }
+
+ if (!loader_read(color_list, total_color_size, 1, &load_handle)) goto done;
+
+ /* Copy relevant header data to target header */
+
+ target->pack_by_sprite = header.pack_by_sprite;
+ target->delta_series = header.delta_series && (header.base_mode < SS_INDIVIDUAL);
+ target->base_mode = header.base_mode;
+ target->num_sprites = header.num_sprites;
+ target->offset_x_view = header.offset_x_view;
+ target->offset_y_view = header.offset_y_view;
+
+ for (count = 0; count < 16; count++) {
+ target->misc[count] = header.misc[count];
+ }
+
+ /* Copy walker information, if requested */
+
+ if (load_flags & SPRITE_LOAD_WALKER_INFO) {
+ target->walker = (WalkerInfoPtr)(((byte *)(target)) + (initial_quantity - sizeof(WalkerInfo)));
+ // TODO: Mem alignment check
+ target->walker = (WalkerInfoPtr)mem_normalize(target->walker);
+ memcpy(target->walker, &header.walker, sizeof(WalkerInfo));
+ }
+
+ /* base_pointer points to the beginning of the memory block at which */
+ /* the sprite data will be loaded. */
+
+ base_pointer = (byte *) (((byte *)target) + base_quantity);
+ base_pointer = (byte *)mem_normalize(base_pointer);
+ sprite_marker = base_pointer;
+
+ /* Set up the target index record for each sprite, including a pointer */
+ /* to the memory block designated for its sprite data. */
+
+ for (count = 0; count < target->num_sprites; count++) {
+ target->index[count].x = sprite[count].x;
+ target->index[count].y = sprite[count].y;
+ target->index[count].xs = sprite[count].xs;
+ target->index[count].ys = sprite[count].ys;
+ if (!(load_flags & SPRITE_LOAD_HEADER_ONLY) && !header.pack_by_sprite) {
+ target->index[count].data = sprite_marker;
+ sprite_marker = (byte *)mem_normalize(sprite_marker + sprite[count].memory_needed);
+ } else {
+ target->index[count].data = NULL;
+ }
+ }
+
+ /* Load all of the sprite data in at the base address */
+
+ if (!(load_flags & SPRITE_LOAD_HEADER_ONLY) && !header.pack_by_sprite) {
+ if (!loader_read(base_pointer, header.total_data_size, 1, &load_handle)) goto done;
+ }
+
+ /* Perform palette allocation and color list transformation */
+
+ if (load_flags & (SPRITE_LOAD_TRANSLATE | SPRITE_LOAD_SPINNING_OBJECT)) {
+ target->color_handle = 0;
+ if (load_flags & (SPRITE_LOAD_SPINNING_OBJECT)) {
+ color_pointer = 0;
+ for (count = 0; count < color_list->num_colors; count++) {
+ found = false;
+ for (low_color = 0; !found && (low_color < 4); low_color++) {
+ if (memcmp(&color_list->table[count].r, &master_palette[low_color].r, sizeof(RGBcolor)) == 0) {
+ found = true;
+ color_list->table[count].x16 = (byte)low_color;
+ }
+ }
+ if (!found) {
+ memcpy(&master_palette[color_table[color_pointer]].r,
+ &color_list->table[count].r, sizeof(RGBcolor));
+ color_list->table[count].x16 = (byte)color_table[color_pointer];
+ color_pointer = MIN(6, color_pointer + 1);
+ }
+ }
+ sprite_color_translate(target, color_list);
+ }
+ } else {
+
+ target->color_handle = pal_allocate(color_list, master_shadow, load_flags & PAL_MAP_MASK);
+ if (target->color_handle < 0) {
+ sprite_error = SS_ERR_TOOMANYCOLORS;
+ goto done;
+ }
+
+ if (!(load_flags & SPRITE_LOAD_HEADER_ONLY) && !header.pack_by_sprite) {
+ sprite_color_translate(target, color_list);
+ }
+ }
+
+ /* If series was packed by sprite (and we are therefore expected to */
+ /* stream-load it), we need to set up paging tables for the series. */
+ /* This process is different depending on whether the sprite data */
+ /* is to be loaded from disk or from the EMS preload area. */
+
+ if (header.pack_by_sprite) {
+ target->color_table = ((byte *)target) + initial_quantity;
+ page_info = target->page_info = (SpritePageInfoPtr)(((byte *)target->color_table) + SPRITE_COLOR_TABLE_SIZE);
+ page_table = target->page_table = (SpritePageTablePtr)(((byte *)page_info) + sizeof(SpritePageInfo));
+
+ for (count = 0; count < color_list->num_colors; count++) {
+ target->color_table[count] = color_list->table[count].x16;
+ }
+
+ page_info->packing_mode = header.compression;
+ page_info->paging_source = (byte)load_handle.mode;
+
+ if ((page_info->paging_source == LOADER_EMS) ||
+ (page_info->paging_source == LOADER_XMS)) {
+ page_info->ems_handle = load_handle.ems_handle;
+ page_info->ems_page_marker = load_handle.ems_page_marker;
+ page_info->ems_page_offset = load_handle.ems_page_offset;
+ page_info->xms_handle = load_handle.xms_handle;
+ page_info->xms_offset = load_handle.xms_offset;
+ largest_block = 0;
+ total_offset = 0;
+ for (count = 0; count < target->num_sprites; count++) {
+ page_table[count].file_offset = total_offset;
+ page_table[count].memory_needed = sprite[count].memory_needed;
+ total_offset += page_table[count].memory_needed;
+ largest_block = MAX(largest_block, page_table[count].memory_needed);
+ }
+ } else {
+ page_info->handle = load_handle.handle;
+ total_offset = load_handle.handle->pos();
+ page_info->base_sprite_offset = total_offset;
+
+ largest_block = 0;
+ for (count = 0; count < target->num_sprites; count++) {
+ page_table[count].file_offset = sprite[count].file_offset;
+ page_table[count].memory_needed = sprite[count].memory_needed;
+ largest_block = MAX(largest_block, page_table[count].memory_needed);
+ }
+ }
+
+ if (!(load_flags & SPRITE_LOAD_HEADER_ONLY)) {
+ if (color_list != NULL) mem_free(color_list);
+ color_list = NULL;
+
+ if (sprite != NULL) mem_free(sprite);
+ sprite = NULL;
+
+ target->arena = (byte *)mem_get_name(largest_block, "$arena$");
+ if (target->arena == NULL) goto done;
+
+ memcpy(&target->misc_largest_block, &largest_block, sizeof(long));
+
+ load_handle.open = false; /* Hack handle so it won't get closed */
+ } else {
+ target->arena = NULL;
+ }
+ }
+
+ result = target;
+
+done:
+ if (load_handle.open) loader_close(&load_handle);
+ if (color_list != NULL) mem_free(color_list);
+ if (sprite != NULL) mem_free(sprite);
+ if ((target != NULL) && (target != (SeriesPtr)sprite_force_memory) && (result == NULL)) mem_free(target);
+
+ return (result);
+}
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/sprite_h.h b/engines/mads/madsv2/core/sprite_h.h
new file mode 100644
index 00000000000..1588a99740d
--- /dev/null
+++ b/engines/mads/madsv2/core/sprite_h.h
@@ -0,0 +1,36 @@
+/* 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 MADS_CORE_SPRITE_H_H
+#define MADS_CORE_SPRITE_H_H
+
+#include "mads/madsv2/core/sprite.h"
+#include "mads/madsv2/core/color.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+extern void sprite_color_translate(SeriesPtr series, ColorListPtr list);
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/sprite_k.cpp b/engines/mads/madsv2/core/sprite_k.cpp
new file mode 100644
index 00000000000..b7a7dd3bc24
--- /dev/null
+++ b/engines/mads/madsv2/core/sprite_k.cpp
@@ -0,0 +1,78 @@
+/* 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 "mads/madsv2/core/general.h"
+#include "mads/madsv2/core/loader.h"
+#include "mads/madsv2/core/mem.h"
+#include "mads/madsv2/core/pal.h"
+#include "mads/madsv2/core/sprite.h"
+#include "mads/madsv2/core/keys.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+int kidney = false;
+
+void dont_frag_the_palette(void) {
+ /* this will tell sprite_free to not execute pal_deallocate. This will */
+ /* make it so the colors are not freed and you won't get the */
+ /* palette fragging. */
+
+ kidney = true;
+}
+
+void go_ahead_and_frag_the_palette(void) {
+ kidney = false;
+}
+
+void fastcall sprite_free(SeriesPtr *series, int free_memory) {
+ if (*series == NULL)
+ goto done;
+
+ if ((*series)->pack_by_sprite) {
+ if ((*series)->page_info->paging_source == LOADER_DISK) {
+ delete (*series)->page_info->handle;
+ }
+ if ((*series)->arena != NULL) {
+ if (free_memory)
+ mem_free((*series)->arena);
+ }
+ }
+
+ if (kidney) {
+ /* release the flag - dont deallocate the colors from the list */
+ if ((*series)->color_handle) pal_deallocate((*series)->color_handle);
+ /* flag_used[(*series)->color_handle] = false; */
+ } else {
+ /* deallocate the colors from the list */
+ if ((*series)->color_handle) pal_deallocate((*series)->color_handle);
+ }
+
+ if (free_memory)
+ mem_free(*series);
+ *series = NULL;
+
+done:
+ ;
+}
+
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/core/text.cpp b/engines/mads/madsv2/core/text.cpp
new file mode 100644
index 00000000000..49356925341
--- /dev/null
+++ b/engines/mads/madsv2/core/text.cpp
@@ -0,0 +1,713 @@
+/* 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 "mads/madsv2/core/general.h"
+#include "mads/madsv2/core/general.h"
+#include "mads/madsv2/core/popup.h"
+#include "mads/madsv2/core/vocab.h"
+#include "mads/madsv2/core/error.h"
+#include "mads/madsv2/core/fileio.h"
+#include "mads/madsv2/core/mem.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/player.h"
+#include "mads/madsv2/core/inter.h"
+#include "mads/madsv2/core/font.h"
+#include "mads/madsv2/core/keys.h"
+#include "mads/madsv2/core/pal.h"
+#include "mads/madsv2/core/env.h"
+#include "mads/madsv2/core/object.h"
+#include "mads/madsv2/core/text.h"
+#include "mads/madsv2/core/global.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+char text_filename[80] = TEXT_FILENAME; /* Filename to load from */
+long text_last_id = 0; /* Last ID used */
+int text_last_number = 0; /* Last number used */
+int text_last_num_entries = 0; /* Num entries last time */
+
+char text_build_filename[80] = TEXT_FILENAME;
+
+int text_force_width = 0; /* Force width externally */
+int text_default_width = 17; /* Default width */
+int text_width = 17; /* Last width used */
+
+int text_default_x = POPUP_CENTER; /* Force position externally */
+int text_default_y = POPUP_CENTER;
+int text_force_location = false; /* Forcing mandatory? */
+
+int text_saves_screen = true; /* Text preserves screen */
+
+int text_index[TEXT_MAX_INDEX];
+int text_capitalization = TEXT_UPPER_ONLY;
+
+char text_command_title[6] = TEXT_COMMAND_TITLE;
+char text_command_center[7] = TEXT_COMMAND_CENTER;
+char text_command_cr[3] = TEXT_COMMAND_CR;
+char text_command_ask[4] = TEXT_COMMAND_ASK;
+char text_command_width[6] = TEXT_COMMAND_WIDTH;
+char text_command_verb[5] = TEXT_COMMAND_VERB;
+char text_command_noun1[6] = TEXT_COMMAND_NOUN1;
+char text_command_noun2[6] = TEXT_COMMAND_NOUN2;
+char text_command_prep[5] = TEXT_COMMAND_PREP;
+char text_command_sentence[9] = TEXT_COMMAND_SENTENCE;
+char text_command_bar[4] = TEXT_COMMAND_BAR;
+char text_command_under[6] = TEXT_COMMAND_UNDER;
+char text_command_down[5] = TEXT_COMMAND_DOWN;
+char text_command_tab[4] = TEXT_COMMAND_TAB;
+char text_command_index[6] = TEXT_COMMAND_INDEX;
+char text_command_number[7] = TEXT_COMMAND_NUMBER;
+char text_command_numberx[8] = TEXT_COMMAND_NUMBERX;
+char text_command_xc[3] = TEXT_COMMAND_XC;
+char text_command_x[2] = TEXT_COMMAND_X;
+char text_command_yc[3] = TEXT_COMMAND_YC;
+char text_command_y[2] = TEXT_COMMAND_Y;
+char text_command_iconc[6] = TEXT_COMMAND_ICONC;
+char text_command_icon[5] = TEXT_COMMAND_ICON;
+char text_command_choice[7] = TEXT_COMMAND_CHOICE;
+
+char text_command_object[7] = TEXT_COMMAND_OBJECT;
+char text_command_subject[8] = TEXT_COMMAND_SUBJECT;
+char text_command_custom[7] = TEXT_COMMAND_CUSTOM;
+char text_command_demonstrative[14] = TEXT_COMMAND_DEMONSTRATIVE;
+
+extern int global[GLOBAL_LIST_SIZE];
+
+
+TextPtr text_load(long id, int mode) {
+ TextPtr result = NULL;
+ TextDirectory dir;
+ TextDirectory *table = NULL;
+ char temp_buf[80];
+ word num_entries;
+ long file_offset;
+ long index_offset;
+ long target_offset;
+ long full_mem_size;
+ long mem_avail;
+ /* long high, low; */
+ int count;
+ int short_id;
+ int number = 0;
+ int found = false;
+ Common::SeekableReadStream *handle = NULL;
+
+ dir.id = dir.file_offset = dir.length = 0;
+ mem_last_alloc_loader = MODULE_TEXT_LOADER;
+
+ Common::strcpy_s(temp_buf, text_filename);
+ Common::strcat_s(temp_buf, TEXT_COMPILED);
+
+ handle = env_open(temp_buf, "rb");
+
+
+ if (handle == NULL) goto done;
+
+ file_offset = handle->pos();
+
+ if (!fileio_fread_f(&num_entries, sizeof(word), 1, handle))
+ goto done;
+
+ switch (mode) {
+ case TEXT_LOAD_BY_ORDER:
+ number = short_id = (int)id;
+ if (short_id >= (int)num_entries) goto done;
+
+ index_offset = file_offset + sizeof(word) + (sizeof(TextDirectory) * short_id);
+ fileio_setpos(handle, index_offset);
+
+ if (!fileio_fread_f(&dir, sizeof(TextDirectory), 1, handle)) goto done;
+
+ found = true;
+ break;
+
+ case TEXT_LOAD_BY_ID:
+ case TEXT_LOAD_NEXT:
+ case TEXT_LOAD_PREVIOUS:
+ default:
+ full_mem_size = sizeof(TextDirectory) * num_entries;
+ mem_avail = mem_get_avail();
+
+ if (mem_avail - 128 >= full_mem_size) {
+ table = (TextDirectory *)mem_get_name(full_mem_size, "$table$");
+ }
+
+ if (table != NULL) {
+ if (!fileio_fread_f(table, full_mem_size, 1, handle)) goto done;
+ for (count = 0; (!found) && (count < (int)num_entries); count++) {
+ found = (table[count].id == id);
+ if (found) {
+ number = count;
+ memcpy(&dir, &table[count], sizeof(TextDirectory));
+ }
+ }
+ mem_free(table);
+ table = NULL;
+ } else {
+ for (count = 0; (!found) && (count < (int)num_entries); count++) {
+ if (!fileio_fread_f(&dir, sizeof(TextDirectory), 1, handle)) goto done;
+ found = (dir.id == id);
+ number = count;
+ }
+ }
+
+ if ((mode == TEXT_LOAD_NEXT) || (mode == TEXT_LOAD_PREVIOUS)) {
+ if (!found) goto done;
+ if (mode == TEXT_LOAD_NEXT) {
+ number++;
+ } else {
+ number--;
+ }
+ if (number >= (int)num_entries) goto done;
+ if (number < 0) goto done;
+
+ index_offset = file_offset + sizeof(word) + (sizeof(TextDirectory) * number);
+ fileio_setpos(handle, index_offset);
+
+ if (!fileio_fread_f(&dir, sizeof(TextDirectory), 1, handle)) goto done;
+ }
+ break;
+ }
+
+ /*
+ for (count = 0; (!found) && (count < (int)num_entries); count++) {
+ if (!fileio_fread_f(&dir, sizeof(TextDirectory), 1, handle)) goto done;
+ found = (dir.id == id);
+ }
+ */
+
+ if (!found) {
+ /*
+ #ifndef disable_error_check
+ high = id / 100;
+ low = id - high;
+ error_report (ERROR_NO_SUCH_MESSAGE, WARNING, MODULE_TEXT, (word)high, (word)low);
+ #endif
+ */
+ goto done;
+ }
+
+ text_last_id = dir.id;
+ text_last_number = number;
+ text_last_num_entries = num_entries;
+
+ target_offset = file_offset + dir.file_offset;
+
+ result = (TextPtr)mem_get_name(dir.length + sizeof(word), "$text$");
+ if (result == NULL) goto done;
+
+ result->length = dir.length;
+
+ fileio_setpos(handle, target_offset);
+
+ pack_strategy = PACK_PFAB;
+ if (pack_data(PACK_EXPLODE, dir.length,
+ FROM_DISK, handle,
+ TO_MEMORY, &result->text[0]) != (int)dir.length) {
+ mem_free(result);
+ result = NULL;
+ }
+
+done:
+ if (table != NULL) mem_free(table);
+ if (handle != NULL)
+ delete handle;
+ return result;
+}
+
+void text_append(char **text_ptr, char *new_text) {
+ int going = true;
+
+ while (going) {
+ *((*text_ptr)++) = *new_text;
+ going = *new_text;
+ new_text++;
+ }
+}
+
+static int _fatoi(const char *string) {
+ char temp_buf[40];
+ Common::strcpy_s(temp_buf, string);
+
+ return atoi(temp_buf);
+}
+
+static void text_copy_string(char **mark, char *string) {
+ Common::strcpy_s(*mark, 65536, string);
+
+ switch (text_capitalization) {
+ case TEXT_AS_IS:
+ break;
+ case TEXT_UPPER_ONLY:
+ mads_strupr(*mark);
+ break;
+ case TEXT_LOWER_ONLY:
+ mads_strlwr(*mark);
+ break;
+ case TEXT_UPPER_AND_LOWER:
+ default:
+ mads_strupr(*mark);
+ mads_strlwr((*mark) + 1);
+ break;
+ }
+
+ while (**mark)
+ (*mark)++;
+}
+
+
+static void text_copy_vocab(char **mark, int vocab_id, char *alternative) {
+ char *my_string;
+
+ if (vocab_id > 0) {
+ my_string = vocab_string(vocab_id);
+ if (!strlen(my_string)) my_string = alternative;
+ } else {
+ my_string = alternative;
+ }
+
+ text_copy_string(mark, my_string);
+}
+
+static int text_popup_check(int *popup_created, word width, int x, int y, SeriesPtr icon, int icon_id, int icon_center) {
+ int error_flag = false;
+
+ if (!*popup_created) {
+ error_flag = popup_create(popup_estimate_pieces(width), x, y);
+ *popup_created = !error_flag;
+
+ if (!error_flag) {
+ if (icon != NULL) {
+ popup_add_icon(icon, icon_id, icon_center);
+ }
+ }
+ }
+
+ return error_flag;
+}
+
+static int text_compare(char *text1, char *text2, char **text3) {
+ int len;
+ int success;
+
+ len = strlen(text2);
+
+ if (text3 != NULL) {
+ *text3 = text1 + len;
+ }
+
+ success = !scumm_strnicmp(text1, text2, len);
+
+ if (success) {
+ if (Common::isUpper(*text1) && Common::isUpper(*(text1 + 1))) {
+ text_capitalization = TEXT_UPPER_ONLY;
+ } else if (Common::isUpper(*text1)) {
+ text_capitalization = TEXT_UPPER_AND_LOWER;
+ } else {
+ text_capitalization = TEXT_LOWER_ONLY;
+ }
+ }
+
+ return success;
+}
+
+static void text_noun(char **source, char **dest, int noun_id) {
+ int syntax;
+ int vowel = false;
+ char *finder;
+ char *finder_2;
+ char temp_buf[256];
+
+ syntax = (noun_id != 2) ? player.main_syntax : player.second_syntax;
+
+ /* Check if a simple substitution of word */
+
+ if (**source != ':') {
+ if (syntax >= SYNTAX_SINGULAR_MASC) text_capitalization = TEXT_AS_IS;
+ text_copy_vocab(dest, player2.words[noun_id], (noun_id != 2) ? text_command_noun1 : text_command_noun2);
+ goto done;
+ }
+
+ (*source)++;
+
+ finder = vocab_string(noun_id);
+ if (finder != NULL) {
+ switch (toupper(*finder)) {
+ case 'A':
+ case 'E':
+ case 'I':
+ case 'O':
+ case 'U':
+ vowel = true;
+ break;
+ }
+ }
+
+ /* Check for subject pronoun */
+
+ if (!scumm_strnicmp(*source, text_command_subject, strlen(text_command_subject))) {
+ text_copy_string(dest, istring_subject_pronoun[syntax]);
+ goto done;
+ }
+
+ /* Check for object pronoun */
+
+ if (!scumm_strnicmp(*source, text_command_object, strlen(text_command_object))) {
+ text_copy_string(dest, istring_object_pronoun[syntax]);
+ goto done;
+ }
+
+ /* Check for demonstrative */
+
+ if (!scumm_strnicmp(*source, text_command_demonstrative, strlen(text_command_demonstrative))) {
+ text_copy_string(dest, istring_demonstrative[syntax]);
+ goto done;
+ }
+
+ /* Try for a custom substitution */
+
+ if (scumm_strnicmp(*source, text_command_custom, strlen(text_command_custom))) {
+ goto done;
+ }
+
+ text_capitalization = TEXT_AS_IS;
+
+ do {
+ finder = strchr(*source, ':');
+ if (finder != NULL) {
+ *source = finder + 1;
+ }
+
+ if (syntax >= 0) syntax--;
+ } while (syntax >= 0);
+
+ Common::strcpy_s(temp_buf, *source);
+
+ finder = strchr(temp_buf, ':');
+ if (finder != NULL) *finder = 0;
+
+ finder_2 = strchr(temp_buf, TEXT_CLOSE_COMMAND);
+ if (finder_2 != NULL) *finder_2 = 0;
+
+ if (vowel) {
+ if (!strcmp(temp_buf, "a")) {
+ Common::strcpy_s(temp_buf, "an");
+ }
+ if (!strcmp(temp_buf, "a ")) {
+ Common::strcpy_s(temp_buf, "an ");
+ }
+ }
+ text_copy_string(dest, temp_buf);
+
+done:
+ ;
+}
+
+
+
+static void text_choice(char **source, char **dest) {
+ int index;
+ int index_value;
+ char *finder;
+ char *finder_2;
+ char temp_buf[256];
+
+ text_capitalization = TEXT_AS_IS;
+
+ Common::strcpy_s(temp_buf, *source);
+ index = atoi(temp_buf);
+
+ index_value = text_index[index];
+
+ do {
+ finder = strchr(*source, ':');
+ if (finder != NULL) {
+ *source = finder + 1;
+ }
+
+ if (index_value) index_value--;
+ } while (index_value);
+
+ Common::strcpy_s(temp_buf, *source);
+
+ finder = strchr(temp_buf, ':');
+ if (finder != NULL) *finder = 0;
+
+ finder_2 = strchr(temp_buf, TEXT_CLOSE_COMMAND);
+ if (finder_2 != NULL) *finder_2 = 0;
+
+ text_copy_string(dest, temp_buf);
+}
+
+
+
+static void text_icon(char *my_text, SeriesPtr *icon, int *id) {
+ char name[80];
+ char *mark;
+ int idd;
+
+ while (*my_text == ' ') my_text++;
+ if (*my_text != '=') goto done;
+ my_text++;
+ while (*my_text == ' ') my_text++;
+
+ mark = strchr(my_text, ',');
+ if (mark == NULL) {
+ Common::strcpy_s(name, my_text);
+ *id = 1;
+ } else {
+ *mark = 0;
+ Common::strcpy_s(name, my_text);
+ *mark = ',';
+ mark++;
+ *id = _fatoi(mark);
+ }
+
+
+ if (strcmp(name, "*logo.ss")) {
+
+ idd = object_named(player_main_noun);
+
+ if (idd == 9) { /* if == polystone */
+ if (global[128] != -1) { /* and it's imitating, make icon == what it's imitating */
+ Common::strcpy_s(name, "*OB0");
+ env_catint(name, global[128], 2);
+ Common::strcat_s(name, ".ss");
+ }
+ }
+ }
+
+ *icon = sprite_series_load(name, PAL_MAP_RESERVED);
+ kernel_new_palette();
+
+
+done:
+ ;
+}
+
+int text_show_full(long id, int mode, int key_wait, int report_errors) {
+ int error_flag = true;
+ int center = false;
+ int cr;
+ int tab;
+ int brackets_on = false;
+ int popup_created = false;
+ int underline = false;
+ int index;
+ int count;
+ int x, y;
+ char temp_buf[256];
+ char work1[40];
+ char work2[40];
+ char command_buf[80];
+ char *more;
+ char *mark;
+ char *cmd;
+ char *scan;
+ TextPtr text = NULL;
+ SeriesPtr icon = NULL;
+ int icon_id = 0;
+ int icon_center = false;
+
+ if (!key_wait) popup_destroy();
+
+ x = text_default_x;
+ y = text_default_y;
+
+ text_capitalization = TEXT_UPPER_ONLY;
+
+ text_width = (text_force_width > 0) ? text_force_width : text_default_width;
+
+ text = text_load(id, mode);
+ if (text == NULL) {
+ if (report_errors) {
+#ifndef disable_error_check
+ error_report(ERROR_NO_SUCH_MESSAGE, WARNING, MODULE_TEXT, id, mode);
+#endif
+ }
+ goto done;
+ }
+
+ scan = text->text;
+
+ while ((scan - ((char *)text->text)) < (int)text->length) {
+ mark = temp_buf;
+ cmd = command_buf;
+ center = false;
+ cr = false;
+ tab = false;
+ underline = false;
+ while (*scan) {
+ if (*scan == TEXT_COMMAND) {
+ brackets_on = true;
+ cmd = command_buf;
+ } else if (*scan == TEXT_CLOSE_COMMAND) {
+ if (brackets_on) {
+ *cmd = 0;
+ /* mads_strupr(command_buf); */
+ if (text_compare(command_buf, text_command_center, &more)) {
+ center = true;
+ } else if (text_compare(command_buf, text_command_title, &more)) {
+ center = true;
+ cr = true;
+ underline = true;
+ if (!text_force_width) {
+ if (_fatoi(more) > 0) {
+ text_width = _fatoi(more);
+ }
+ }
+ } else if (text_compare(command_buf, text_command_cr, &more)) {
+ if (center) {
+ cr = true;
+ } else {
+ if (text_popup_check(&popup_created, text_width, x, y, icon, icon_id, icon_center)) goto done;
+ *mark = 0;
+ mark = temp_buf;
+ popup_write_string(temp_buf);
+ popup_next_line();
+ }
+ } else if (text_compare(command_buf, text_command_ask, &more)) {
+ popup_set_ask();
+ } else if (text_compare(command_buf, text_command_verb, &more)) {
+ text_copy_vocab(&mark, player2.words[0], text_command_verb);
+ } else if (text_compare(command_buf, text_command_index, &more)) {
+ index = _fatoi(more);
+ if (text_index[index] > 0) {
+ mads_itoa(index, work1, 10);
+ Common::strcpy_s(work2, "<");
+ Common::strcat_s(work2, text_command_index);
+ Common::strcat_s(work2, work1);
+ Common::strcat_s(work2, ">");
+ text_copy_vocab(&mark, text_index[index], work2);
+ }
+ } else if (text_compare(command_buf, text_command_numberx, &more)) {
+ index = _fatoi(more);
+ mads_itoa(text_index[index], work1, 10);
+ work2[0] = 0;
+ for (count = 0; count < (int)(4 - strlen(work1)); count++) {
+ Common::strcat_s(work2, "0");
+ }
+ Common::strcat_s(work2, work1);
+ Common::strcpy_s(mark, 65536, work2);
+ while (*mark) mark++;
+ } else if (text_compare(command_buf, text_command_number, &more)) {
+ index = _fatoi(more);
+ mads_itoa(text_index[index], work1, 10);
+ Common::strcpy_s(mark, 65536, work1);
+ while (*mark) mark++;
+ } else if (text_compare(command_buf, text_command_noun1, &more)) {
+ text_noun(&more, &mark, 1);
+ } else if (text_compare(command_buf, text_command_noun2, &more)) {
+ text_noun(&more, &mark, 2);
+ } else if (text_compare(command_buf, text_command_prep, &more)) {
+ Common::strcpy_s(mark, 65536, istring_prep_names[player.prep]);
+ while (*mark) mark++;
+ } else if (text_compare(command_buf, text_command_sentence, &more)) {
+ Common::strcpy_s(mark, 65536, player.sentence);
+ mads_strupr(mark);
+ while (*mark) mark++;
+ } else if (text_compare(command_buf, text_command_width, &more)) {
+ if (!text_force_width) {
+ text_width = _fatoi(more);
+ }
+ } else if (text_compare(command_buf, text_command_bar, &more)) {
+ popup_bar();
+ } else if (text_compare(command_buf, text_command_under, &more)) {
+ underline = true;
+ } else if (text_compare(command_buf, text_command_down, &more)) {
+ popup_downpixel();
+ } else if (text_compare(command_buf, text_command_tab, &more)) {
+ popup_tab(_fatoi(more));
+ } else if (text_compare(command_buf, text_command_xc, &more)) {
+ x = _fatoi(more) | POPUP_CENTER;
+ } else if (text_compare(command_buf, text_command_x, &more)) {
+ x = _fatoi(more);
+ } else if (text_compare(command_buf, text_command_yc, &more)) {
+ y = _fatoi(more) | POPUP_CENTER;
+ } else if (text_compare(command_buf, text_command_y, &more)) {
+ y = _fatoi(more);
+ } else if (text_compare(command_buf, text_command_iconc, &more)) {
+ text_icon(more, &icon, &icon_id);
+ icon_center = true;
+ } else if (text_compare(command_buf, text_command_icon, &more)) {
+ text_icon(more, &icon, &icon_id);
+ icon_center = false;
+ } else if (text_compare(command_buf, text_command_choice, &more)) {
+ text_choice(&more, &mark);
+ }
+ }
+ brackets_on = false;
+ } else {
+ if (brackets_on) {
+ *(cmd++) = *scan;
+ } else {
+ *(mark++) = *scan;
+ }
+ }
+ scan++;
+ }
+ *mark = 0;
+ scan++;
+
+ if (text_force_location) {
+ x = text_default_x;
+ y = text_default_y;
+ }
+
+ if (text_popup_check(&popup_created, text_width, x, y, icon, icon_id, icon_center)) goto done;
+
+ if (center) {
+ popup_center_string(temp_buf, underline);
+ if (cr) popup_next_line();
+ } else {
+ popup_write_string(temp_buf);
+ }
+ }
+
+ if (!center) popup_next_line();
+
+ if (key_wait) {
+ if (popup_and_wait(text_saves_screen)) goto done;
+ } else {
+ if (popup_and_dont_wait(text_saves_screen)) goto done;
+ }
+
+ error_flag = false;
+
+done:
+ if (icon != NULL) {
+ sprite_free(&icon, (sprite_force_memory == NULL));
+ }
+ if (error_flag && popup_created) popup_destroy();
+ if (text != NULL) mem_free(text);
+
+ return error_flag;
+}
+
+
+int text_show(long id) {
+ return text_show_full(id, TEXT_LOAD_BY_ID, true, true);
+}
+
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/core/text.h b/engines/mads/madsv2/core/text.h
new file mode 100644
index 00000000000..eaae2ed8a0e
--- /dev/null
+++ b/engines/mads/madsv2/core/text.h
@@ -0,0 +1,130 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef MADS_CORE_TEXT_H
+#define MADS_CORE_TEXT_H
+
+#include "mads/madsv2/core/general.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+
+#define TEXT_FILENAME "*MESSAGES"
+#define TEXT_SOURCE ".TXT"
+#define TEXT_COMPILED ".DAT"
+#define TEXT_HEADER ".H"
+
+#define TEXT_MARKER "text_"
+#define TEXT_COMMENT ';'
+#define TEXT_COMMAND '['
+#define TEXT_CLOSE_COMMAND ']'
+
+/* Allowable commands in file */
+#define TEXT_COMMAND_TITLE "TITLE"
+#define TEXT_COMMAND_CENTER "CENTER"
+#define TEXT_COMMAND_CR "CR"
+#define TEXT_COMMAND_ASK "ASK"
+#define TEXT_COMMAND_WIDTH "WIDTH"
+#define TEXT_COMMAND_VERB "VERB"
+#define TEXT_COMMAND_NOUN1 "NOUN1"
+#define TEXT_COMMAND_NOUN2 "NOUN2"
+#define TEXT_COMMAND_PREP "PREP"
+#define TEXT_COMMAND_SENTENCE "SENTENCE"
+#define TEXT_COMMAND_BAR "BAR"
+#define TEXT_COMMAND_UNDER "UNDER"
+#define TEXT_COMMAND_DOWN "DOWN"
+#define TEXT_COMMAND_TAB "TAB"
+#define TEXT_COMMAND_INDEX "INDEX"
+#define TEXT_COMMAND_NUMBER "NUMBER"
+#define TEXT_COMMAND_NUMBERX "NUMBERX"
+#define TEXT_COMMAND_CHOICE "CHOICE"
+#define TEXT_COMMAND_XC "XC"
+#define TEXT_COMMAND_X "X"
+#define TEXT_COMMAND_YC "YC"
+#define TEXT_COMMAND_Y "Y"
+#define TEXT_COMMAND_ICON "ICON"
+#define TEXT_COMMAND_ICONC "ICONC"
+
+#define TEXT_COMMAND_OBJECT "OBJECT"
+#define TEXT_COMMAND_SUBJECT "SUBJECT"
+#define TEXT_COMMAND_DEMONSTRATIVE "DEMONSTRATIVE"
+#define TEXT_COMMAND_CUSTOM "CUSTOM"
+
+#define TEXT_MAX_INDEX 10
+
+#define TEXT_UPPER_ONLY 0
+#define TEXT_LOWER_ONLY 1
+#define TEXT_UPPER_AND_LOWER 2
+#define TEXT_AS_IS 3
+
+#define TEXT_LOAD_BY_ID 0 /* Load by id # */
+#define TEXT_LOAD_BY_ORDER 1 /* Load by order in file */
+#define TEXT_LOAD_NEXT 2 /* Load next in file */
+#define TEXT_LOAD_PREVIOUS 3 /* Load previous in file */
+
+typedef struct {
+ word length;
+ char text[1];
+} Text;
+
+
+typedef struct {
+ long id;
+ long file_offset;
+ word length;
+} TextDirectory;
+
+typedef Text *TextPtr;
+
+
+extern int text_force_width; /* Force width externally */
+extern int text_default_width; /* Default width */
+extern int text_width; /* Last width used */
+
+extern int text_default_x; /* Force position externally */
+extern int text_default_y;
+extern int text_force_location; /* Forcing or optional? */
+
+extern int text_saves_screen; /* Text preserves screen */
+
+extern int text_index[TEXT_MAX_INDEX]; /* Indexed vocab words. */
+
+extern char text_filename[80]; /* Filename for text_load */
+extern char text_build_filename[80]; /* Filename for text_build */
+
+extern long text_last_id; /* Last text id loaded */
+extern int text_last_number; /* Last text number used */
+extern int text_last_num_entries; /* Number of entries */
+
+
+extern TextPtr text_load(long id, int mode);
+
+extern int text_build(int build_header);
+
+extern void text_copy_vocab(char **mark, int vocab_id);
+extern int text_show_full(long id, int mode, int key_wait, int report_errors);
+extern int text_show(long id);
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/tile_3.cpp b/engines/mads/madsv2/core/tile_3.cpp
new file mode 100644
index 00000000000..59488448783
--- /dev/null
+++ b/engines/mads/madsv2/core/tile_3.cpp
@@ -0,0 +1,60 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "mads/madsv2/core/general.h"
+#include "mads/madsv2/core/ems.h"
+#include "mads/madsv2/core/dialog.h"
+#include "mads/madsv2/core/matte.h"
+#include "mads/madsv2/core/tile.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+int tile_ems_available = false;
+int tile_picture_handle = -1;
+int tile_attribute_handle = -1;
+
+
+int tile_setup(void) {
+ int error_flag = true;
+
+ picture_map.map = NULL;
+ depth_map.map = NULL;
+
+ tile_picture_handle = ems_get_page_handle(TILE_MAX_PAGES);
+ if (tile_picture_handle < 0) goto done;
+
+ tile_attribute_handle = ems_get_page_handle(TILE_MAX_PAGES >> 1);
+ if (tile_attribute_handle < 0) goto done;
+
+ tile_ems_available = true;
+ error_flag = false;
+
+done:
+ if (error_flag) {
+ if (tile_picture_handle >= 0) ems_free_page_handle(tile_picture_handle);
+ }
+
+ return error_flag;
+}
+
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/core/video_1.cpp b/engines/mads/madsv2/core/video_1.cpp
new file mode 100644
index 00000000000..efd2692dea7
--- /dev/null
+++ b/engines/mads/madsv2/core/video_1.cpp
@@ -0,0 +1,38 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "mads/madsv2/core/video.h"
+#include "mads/madsv2/engine.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+void video_init(int mode, int set_mode) {
+ // No implementation in ScummVM
+}
+
+void video_update() {
+ auto &screen = *g_engine->getScreen();
+ screen.update();
+}
+
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/core/vocab_8.cpp b/engines/mads/madsv2/core/vocab_8.cpp
new file mode 100644
index 00000000000..c5ffa85feb4
--- /dev/null
+++ b/engines/mads/madsv2/core/vocab_8.cpp
@@ -0,0 +1,91 @@
+/* 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 "mads/madsv2/core/general.h"
+#include "mads/madsv2/core/mem.h"
+#include "mads/madsv2/core/env.h"
+#include "mads/madsv2/core/error.h"
+#include "mads/madsv2/core/sort.h"
+#include "mads/madsv2/core/fileio.h"
+#include "mads/madsv2/core/vocab.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+char *vocab_text = NULL;
+word vocab_size;
+
+void fastcall vocab_unload_active(void) {
+ vocab_size = 0;
+ if (vocab_text != NULL) {
+ mem_free(vocab_text);
+ vocab_text = NULL;
+ }
+}
+
+
+int fastcall vocab_load_active(void) {
+ int error_flag = true;
+ int vocab_error = 0;
+ Common::SeekableReadStream *handle = NULL;
+
+ mem_last_alloc_loader = MODULE_VOCAB_LOADER;
+
+ vocab_unload_active();
+
+ handle = env_open("*VOCAB.DAT", "rb");
+ if (handle == NULL) {
+ vocab_error = 1;
+ goto done;
+ }
+
+ vocab_size = (word)env_get_file_size(handle);
+
+ vocab_text = (char *)mem_get_name(vocab_size, "$vocab$");
+ if (vocab_text == NULL) {
+ vocab_error = 2;
+ goto done;
+ }
+
+ if (!fileio_fread_f(vocab_text, vocab_size, 1, handle)) {
+ vocab_error = 3;
+ goto done;
+ }
+
+ error_flag = false;
+
+done:
+ delete handle;
+
+ if (error_flag) {
+ vocab_unload_active();
+ error_report(ERROR_KERNEL_NO_VOCAB, SEVERE, MODULE_KERNEL, vocab_error, 0);
+ }
+
+ return error_flag;
+}
+
+int vocab_make_active(int id) {
+ return id;
+}
+
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/core/vocab_8.h b/engines/mads/madsv2/core/vocab_8.h
new file mode 100644
index 00000000000..8602ee07300
--- /dev/null
+++ b/engines/mads/madsv2/core/vocab_8.h
@@ -0,0 +1,45 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef MADS_CORE_VOCAB_8_H
+#define MADS_CORE_VOCAB_8_H
+
+#include "mads/madsv2/core/general.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+extern void vocab_unload_active(); /* vocab_8.c */
+extern void vocab_init_active();
+extern int vocab_active_id(word id);
+extern int vocab_make_active(word id);
+extern int vocab_load_active();
+
+extern char *vocab_text;
+extern word vocab_size;
+extern word vocab_active;
+extern word vocab_list_id[VOCAB_MAX_ACTIVE];
+extern word vocab_list_pointer[VOCAB_MAX_ACTIVE];
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/engine.cpp b/engines/mads/madsv2/engine.cpp
index c3362cdca6e..7365b819405 100644
--- a/engines/mads/madsv2/engine.cpp
+++ b/engines/mads/madsv2/engine.cpp
@@ -19,6 +19,7 @@
*
*/
+#include "engines/util.h"
#include "mads/madsv2/engine.h"
#include "mads/madsv2/phantom/main.h"
@@ -31,7 +32,14 @@ MADSV2Engine::MADSV2Engine(OSystem *syst, const MADSGameDescription *gameDesc) :
Engine(syst), _gameDescription(gameDesc) {
}
+MADSV2Engine::~MADSV2Engine() {
+ delete _screen;
+}
+
Common::Error MADSV2Engine::run() {
+ initGraphics(320, 200);
+ _screen = new Graphics::Screen();
+
Phantom::phantom_main();
return Common::kNoError;
diff --git a/engines/mads/madsv2/engine.h b/engines/mads/madsv2/engine.h
index 2499b2e70de..517b80dd246 100644
--- a/engines/mads/madsv2/engine.h
+++ b/engines/mads/madsv2/engine.h
@@ -22,7 +22,9 @@
#ifndef MADSV2_ENGINE_H
#define MADSV2_ENGINE_H
+#include "common/random.h"
#include "engines/engine.h"
+#include "graphics/screen.h"
#include "mads/detection.h"
namespace MADS {
@@ -31,13 +33,22 @@ namespace MADSV2 {
class MADSV2Engine : public Engine {
private:
const MADSGameDescription *_gameDescription;
+ Graphics::Screen *_screen = nullptr;
+ Common::RandomSource _random = Common::RandomSource("MADS");
public:
MADSV2Engine(OSystem *syst, const MADSGameDescription *gameDesc);
- ~MADSV2Engine() override {
- }
+ ~MADSV2Engine() override;
Common::Error run() override;
+
+ uint getRandomNumber(uint max) {
+ return _random.getRandomNumber(max);
+ }
+
+ Graphics::Screen *getScreen() const {
+ return _screen;
+ }
};
extern MADSV2Engine *g_engine;
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index dd5e7967724..f67a0e89069 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -60,15 +60,30 @@ MODULE_OBJS += \
forest/forest_scenes.o \
forest/globals_forest.o \
madsv2/engine.o \
+ madsv2/core/buffer.o \
+ madsv2/core/font_1.o \
+ madsv2/core/kernel_1.o \
madsv2/core/kernel_3.o \
madsv2/core/kernel_8.o \
madsv2/core/kernel_b.o \
madsv2/core/kernel_d.o \
madsv2/core/kernel_f.o \
madsv2/core/matte_1.o \
+ madsv2/core/mem_2.o \
madsv2/core/mouse_1.o \
madsv2/core/mouse_2.o \
+ madsv2/core/mouse_3.o \
+ madsv2/core/mouse_4.o \
+ madsv2/core/object.o \
+ madsv2/core/pack_6.o \
+ madsv2/core/quote_1.o \
madsv2/core/speech.o \
+ madsv2/core/sprite_e.o \
+ madsv2/core/sprite_k.o \
+ madsv2/core/text.o \
+ madsv2/core/tile_3.o \
+ madsv2/core/video_1.o \
+ madsv2/core/vocab_8.o \
madsv2/phantom/mads/mads.o \
madsv2/phantom/main_menu.o \
madsv2/phantom/main.o
Commit: 185ccb3bd3ba3c7ecdc595e548eee87835bedcc3
https://github.com/scummvm/scummvm/commit/185ccb3bd3ba3c7ecdc595e548eee87835bedcc3
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:19:04+10:00
Commit Message:
MADS: PHANTOM: Adding more core dependencies
Changed paths:
A engines/mads/madsv2/core/error.cpp
engines/mads/madsv2/core/echo.h
engines/mads/madsv2/core/popup.h
engines/mads/module.mk
diff --git a/engines/mads/madsv2/core/echo.h b/engines/mads/madsv2/core/echo.h
index 87f8c97e83c..243723c1786 100644
--- a/engines/mads/madsv2/core/echo.h
+++ b/engines/mads/madsv2/core/echo.h
@@ -22,13 +22,19 @@
#ifndef MADS_CORE_ECHO_H
#define MADS_CORE_ECHO_H
-#include "common/scummsys.h"
+#include "gui/debugger.h"
+#include "mads/madsv2/engine.h"
namespace MADS {
namespace MADSV2 {
-/* echo_1.cpp */
-void echo(char *item, int carriage_return);
+inline void echo(const char *item, bool carriage_return) {
+ auto &dbg = *g_engine->getDebugger();
+
+ dbg.debugPrintf(item);
+ if (carriage_return)
+ dbg.debugPrintf("\n");
+}
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/core/error.cpp b/engines/mads/madsv2/core/error.cpp
new file mode 100644
index 00000000000..646de6e72e0
--- /dev/null
+++ b/engines/mads/madsv2/core/error.cpp
@@ -0,0 +1,121 @@
+/* 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/textconsole.h"
+#include "mads/madsv2/core/general.h"
+#include "mads/madsv2/core/error.h"
+#include "mads/madsv2/core/general.h"
+#include "mads/madsv2/core/mouse.h"
+#include "mads/madsv2/core/screen.h"
+#include "mads/madsv2/core/echo.h"
+#include "mads/madsv2/core/ems.h"
+#include "mads/madsv2/core/himem.h"
+#include "mads/madsv2/core/env.h"
+#include "mads/madsv2/core/screen.h"
+#include "mads/madsv2/core/timer.h"
+#include "mads/madsv2/core/popup.h"
+#include "mads/madsv2/core/keys.h"
+#include "mads/madsv2/core/mem.h"
+#include "mads/madsv2/core/midi.h"
+#include "mads/madsv2/core/digi.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+#define disable_popup_errors DISABLED
+
+void (*error_service_routine)() = NULL;
+void (*error_service_routine_2)() = NULL;
+
+int error_abort = WARNING;
+char error_string[80] = "";
+
+static void error_explode(char *error_buf, char *module_buf, char *data1_buf, char *data2_buf, long avail, int error) {
+ midi_uninstall();
+ digi_uninstall();
+
+ timer_remove();
+ keys_remove();
+ himem_shutdown();
+
+ mouse_init(false, 3);
+ screen_dominant_mode(text_mode);
+
+ ::error("Execution aborted");
+}
+
+
+#pragma optimize ("egl", on)
+
+void error_report(int error, int severity, int module, long data1, long data2) {
+ char error_buf[40], module_buf[40], data1_buf[12], data2_buf[12];
+ int handled = false;
+ int key;
+
+ if (severity >= error_abort) {
+ mads_itoa(error, error_buf, 10);
+ mads_itoa(module, module_buf, 10);
+ ltoa(data1, data1_buf, 10);
+ ltoa(data2, data2_buf, 10);
+
+ if (!handled) {
+ error_explode(error_buf, module_buf, data1_buf, data2_buf, mem_get_avail(), error);
+ }
+ }
+}
+
+void error_break_point(int data1, int data2) {
+ error_report(ERROR_BREAK_POINT, SEVERE, MODULE_UNKNOWN, data1, data2);
+}
+
+void error_watch_point(char *message, long data1, long data2) {
+ char temp_buf[80];
+ int len;
+ int width;
+
+ len = strlen(message);
+
+ width = MAX(len, 12);
+
+ if (popup_create(popup_estimate_pieces(width), POPUP_CENTER, POPUP_CENTER)) goto done;
+
+ popup_center_string(message, true);
+ popup_next_line();
+ Common::sprintf_s(temp_buf, "DATA: %ld %ld", data1, data2);
+ popup_center_string(temp_buf, false);
+ popup_next_line();
+ popup_center_string("HIT ANY KEY", false);
+
+ popup_and_wait(true);
+
+done:
+ ;
+}
+
+void error_check_memory(void) {
+ if (mem_last_alloc_failed) {
+ error_report(ERROR_NO_MORE_MEMORY, ERROR, mem_last_alloc_loader,
+ mem_last_alloc_size, mem_last_alloc_avail);
+ }
+}
+
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/core/popup.h b/engines/mads/madsv2/core/popup.h
index d0b2f2641a9..9c03adb2bb2 100644
--- a/engines/mads/madsv2/core/popup.h
+++ b/engines/mads/madsv2/core/popup.h
@@ -425,7 +425,7 @@ void popup_bar(void);
void popup_underline(void);
void popup_downpixel(void);
void popup_tab(int tab_level);
-void popup_center_string(char *string, int underline);
+void popup_center_string(const char *string, int underline);
/* popup_1.c */
int popup_and_wait(int save_screen);
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index f67a0e89069..94223901c6b 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -61,6 +61,7 @@ MODULE_OBJS += \
forest/globals_forest.o \
madsv2/engine.o \
madsv2/core/buffer.o \
+ madsv2/core/error.o \
madsv2/core/font_1.o \
madsv2/core/kernel_1.o \
madsv2/core/kernel_3.o \
Commit: 69c92fb76829a7c1eef4b8874368601b033560a1
https://github.com/scummvm/scummvm/commit/69c92fb76829a7c1eef4b8874368601b033560a1
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:19:04+10:00
Commit Message:
MADS: PHANTOM: Adding more core dependencies
Changed paths:
A engines/mads/madsv2/core/cycle.cpp
A engines/mads/madsv2/core/ems.cpp
A engines/mads/madsv2/core/extra.h
A engines/mads/madsv2/core/fileio.cpp
A engines/mads/madsv2/core/himem.cpp
A engines/mads/madsv2/core/inter.cpp
A engines/mads/madsv2/core/lbm.h
A engines/mads/madsv2/core/matte.cpp
A engines/mads/madsv2/core/mcga.cpp
A engines/mads/madsv2/core/pal.cpp
A engines/mads/madsv2/core/popup.cpp
A engines/mads/madsv2/core/screen.cpp
A engines/mads/madsv2/core/timer.cpp
A engines/mads/madsv2/core/vocabh.h
A engines/mads/madsv2/core/xms.cpp
R engines/mads/madsv2/core/matte_1.cpp
engines/mads/madsv2/core/buffer.cpp
engines/mads/madsv2/core/ems.h
engines/mads/madsv2/core/error.cpp
engines/mads/madsv2/core/error.h
engines/mads/madsv2/core/fileio.h
engines/mads/madsv2/core/font.h
engines/mads/madsv2/core/game.h
engines/mads/madsv2/core/imath.h
engines/mads/madsv2/core/inter.h
engines/mads/madsv2/core/mcga.h
engines/mads/madsv2/core/mouse.h
engines/mads/madsv2/core/mouse_1.h
engines/mads/madsv2/core/mouse_2.cpp
engines/mads/madsv2/core/pal.h
engines/mads/madsv2/core/popup.h
engines/mads/madsv2/core/screen.h
engines/mads/madsv2/core/xms.h
engines/mads/module.mk
diff --git a/engines/mads/madsv2/core/buffer.cpp b/engines/mads/madsv2/core/buffer.cpp
index 2f938894643..e12a6a1a53a 100644
--- a/engines/mads/madsv2/core/buffer.cpp
+++ b/engines/mads/madsv2/core/buffer.cpp
@@ -31,7 +31,10 @@ namespace MADSV2 {
word pattern_control_value = 0x181d;
word pattern_initial_value = 0xb78e;
int auto_pattern = true;
+int buffer_restore_keep_flag = false;
+
static word accum; /* Pattern accumulator */
+static Buffer buffer_preserve_conventional;
bool buffer_init(Buffer *buf, word x, word y) {
@@ -724,5 +727,86 @@ void buffer_peel_vert(Buffer *target, int peel, byte *work_memory, long work_siz
mem_free(work_area);
}
+int buffer_preserve(Buffer *source, int flags, int source_ems_handle, int x, int y, int xs, int ys) {
+ int preserve_handle = BUFFER_NOT_PRESERVED;
+ int disk_number;
+
+ if (buffer_conform(source, &x, &y, &xs, &ys)) {
+ goto done;
+ }
+
+ /* Try to preserve in conventional memory, if requested */
+
+ if (flags == BUFFER_ATTEMPT_CONVENTIONAL) {
+ buffer_init_name(&buffer_preserve_conventional, xs, ys, "$preserv");
+ if (buffer_preserve_conventional.data != NULL) {
+ buffer_rect_copy_2(*source, buffer_preserve_conventional,
+ x, y, 0, 0, xs, ys);
+ preserve_handle = BUFFER_PRESERVED_CONVENTIONAL;
+ goto done;
+ }
+ }
+
+ /* Try to preserve in EMS memory */
+
+ preserve_handle = buffer_to_ems(source, flags, source_ems_handle, x, y, xs, ys);
+ if (preserve_handle >= 0) {
+ goto done;
+ }
+
+ /* Try to preserve on disk */
+
+ if (flags != BUFFER_PRESERVE_RAM) {
+ disk_number = buffer_to_disk(source, x, y, xs, ys);
+ if (disk_number >= 0) {
+ preserve_handle = BUFFER_PRESERVED_DISK - disk_number;
+ goto done;
+ }
+ }
+
+ preserve_handle = BUFFER_NOT_PRESERVED;
+
+done:
+ return (preserve_handle);
+}
+
+void buffer_restore(Buffer *source, int preserve_handle, int target_ems_handle, int x, int y, int xs, int ys) {
+ if (buffer_conform(source, &x, &y, &xs, &ys)) {
+ goto done;
+ }
+
+ switch (preserve_handle) {
+ case BUFFER_PRESERVED_CONVENTIONAL:
+ buffer_rect_copy_2(buffer_preserve_conventional, *source,
+ 0, 0, x, y, xs, ys);
+ if (!buffer_restore_keep_flag) buffer_free(&buffer_preserve_conventional);
+ break;
+
+ case BUFFER_PRESERVED_DISK:
+ case BUFFER_PRESERVED_DISK - 1:
+ case BUFFER_PRESERVED_DISK - 2:
+ case BUFFER_PRESERVED_DISK - 3:
+ case BUFFER_PRESERVED_DISK - 4:
+ case BUFFER_PRESERVED_DISK - 5:
+ case BUFFER_PRESERVED_DISK - 6:
+ case BUFFER_PRESERVED_DISK - 7:
+ case BUFFER_PRESERVED_DISK - 8:
+ case BUFFER_PRESERVED_DISK - 9:
+ buffer_from_disk(source, neg(preserve_handle - BUFFER_PRESERVED_DISK), buffer_restore_keep_flag, x, y, xs, ys);
+ break;
+
+ case BUFFER_NOT_PRESERVED:
+ break;
+
+ default:
+ if (buffer_restore_keep_flag) preserve_handle &= ~BUFFER_CREATED_PAGE_HANDLE;
+ buffer_from_ems(source, preserve_handle, target_ems_handle, x, y, xs, ys);
+ break;
+ }
+
+done:
+ ;
+}
+
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/core/cycle.cpp b/engines/mads/madsv2/core/cycle.cpp
new file mode 100644
index 00000000000..509a65d1b2b
--- /dev/null
+++ b/engines/mads/madsv2/core/cycle.cpp
@@ -0,0 +1,129 @@
+/* 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 "mads/madsv2/core/general.h"
+#include "mads/madsv2/core/cycle.h"
+#include "mads/madsv2/core/color.h"
+#include "mads/madsv2/core/timer.h"
+#include "mads/madsv2/core/mcga.h"
+#include "mads/madsv2/core/pal.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+Palette cycling_palette;
+
+CycleList cycle_list;
+int cycling_active = false;
+int cycling_delay = 0;
+int cycling_threshold;
+int total_cycle_colors;
+
+long cycle_timing[COLOR_MAX_CYCLES];
+static RGBcolor temp_color;
+
+void cycle_init(CycleListPtr new_cycle_list, int activate) {
+ int count;
+ long current_time;
+
+ current_time = timer_read();
+ for (count = 0; count < COLOR_MAX_CYCLES; count++) {
+ cycle_timing[count] = current_time;
+ }
+
+ memcpy(&cycle_list, new_cycle_list, sizeof(CycleList));
+ memcpy(cycling_palette, master_palette, sizeof(Palette));
+
+ total_cycle_colors = 0;
+ for (count = 0; count < cycle_list.num_cycles; count++) {
+ total_cycle_colors += cycle_list.table[count].num_colors;
+ cycle_list.table[count].first_list_color = 0;
+ }
+
+ cycling_threshold = 3;
+ if (total_cycle_colors <= 16) cycling_threshold = 0;
+
+ cycling_active = activate;
+}
+
+void cycle_colors(void) {
+ int num;
+ int first;
+ int count;
+ int any_changes;
+ int mark;
+ long this_timing;
+
+ if (!cycling_active)
+ return;
+
+ cycling_delay++;
+ if (cycling_delay < cycling_threshold)
+ return;
+
+ if (mcga_palette_update)
+ return;
+
+ this_timing = timer_read();
+ any_changes = false;
+
+ for (count = 0; count < cycle_list.num_cycles; count++) {
+ if (this_timing >= (cycle_timing[count] + cycle_list.table[count].ticks)) {
+ cycle_timing[count] = this_timing;
+ num = cycle_list.table[count].num_colors;
+ first = cycle_list.table[count].first_palette_color;
+ mark = cycle_list.table[count].first_list_color;
+ any_changes = true;
+
+ if (num > 1) {
+ RGBcolor *base = &cycling_palette[first];
+ RGBcolor tmp;
+
+ // Save the last color
+ tmp = base[num - 1];
+
+ // Shift all colors forward by one
+ memmove(&base[1], &base[0], (num - 1) * sizeof(Palette));
+
+ // Write saved last color into the first slot
+ base[0] = tmp;
+
+ // Advance and wrap the cycle position marker
+ mark++;
+ if (mark >= num)
+ mark = 0;
+ }
+
+ cycle_list.table[count].first_list_color = (byte)mark;
+ }
+ }
+
+ if (any_changes) {
+ mcga_setpal_range(&cycling_palette,
+ cycle_list.table[0].first_palette_color,
+ total_cycle_colors);
+ }
+
+ cycling_delay = 0;
+}
+
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/core/ems.cpp b/engines/mads/madsv2/core/ems.cpp
new file mode 100644
index 00000000000..07b06737c5b
--- /dev/null
+++ b/engines/mads/madsv2/core/ems.cpp
@@ -0,0 +1,45 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "mads/madsv2/core/ems.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+word ems_page_frame = 0;
+word ems_handle = 0;
+word ems_pages = 0;
+int ems_disabled = 0;
+word ems_high_version = 0;
+word ems_low_version = 0;
+byte *ems_page[4] = {};
+word ems_paging_active = 0;
+word ems_pages_free = 0;
+word ems_pages_reserved = 0;
+byte *ems_page_flag = nullptr;
+word ems_paging_reserve[EMS_PAGING_CLASSES] = {};
+
+int ems_mapping_changed = 0;
+int ems_page_mapped[4] = {};
+int ems_page_stack[4] = {};
+
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/core/ems.h b/engines/mads/madsv2/core/ems.h
index 7ddf612e814..ff22a3a727b 100644
--- a/engines/mads/madsv2/core/ems.h
+++ b/engines/mads/madsv2/core/ems.h
@@ -61,12 +61,12 @@ typedef struct {
} EmsPtr;
-extern int ems_driver; /* Flag if EMS driver is installed */
-extern int ems_exists; /* Flag if we've got some EMS available */
+constexpr bool ems_driver = false; /* Flag if EMS driver is installed */
+constexpr bool ems_exists = false; /* Flag if we've got some EMS available */
extern word ems_page_frame; /* Segment address of EMS page frame */
extern word ems_handle; /* EMS handle of our allocated pages */
extern word ems_pages; /* # of pages EMS allocated for us */
-extern int ems_disabled; /* Flag if EMS disabled altogether */
+extern int ems_disabled; /* Flag if EMS disabled altogether */
extern word ems_high_version; /* High (integer) part of EMS version # */
extern word ems_low_version; /* Low (fraction) part of EMS version # */
@@ -81,55 +81,53 @@ extern byte *ems_page_flag; /* Page allocation flag array */
extern word ems_paging_reserve[EMS_PAGING_CLASSES]; /* Reserve pages */
-extern int ems_mapping_changed;/* EMS mapping has changed */
+extern int ems_mapping_changed;/* EMS mapping has changed */
-extern int ems_page_mapped[4];
-extern int ems_page_stack[4];
+extern int ems_page_mapped[4];
+extern int ems_page_stack[4];
+/**
+ * Detects whether or not EMS memory is present. If EMS is detected,
+ * attempts to allocate all available pages.
+ * @return "true" if one or more pages were successfully allocated.
+ * Returns "false" if EMS did not exist, if no pages were available,
+ * or if an error occurred.
+ */
+inline bool ems_detect() {
+ return false;
+}
+/**
+ * Frees up any EMS memory that might have been allocated by ems_detect().
+ */
+inline void ems_shutdown() {
+}
-/* ems_1.c */
-int ems_detect(void);
-void ems_shutdown(void);
-int ems_map_page(word physical, word logical);
-void ems_unmap_all(void);
-void ems_push(void);
-void ems_pop(void);
-
-
-
-/* ems_2.c */
-int ems_activate_directory(void);
-int ems_activate_page_map(void);
-int ems_paging_setup(void);
-void ems_free_page_handle(word handle);
-int ems_get_page_handle(word pages_needed);
-int ems_next_handle_page(int handle, int page_marker);
-void ems_paging_mode(int paging_mode);
-void ems_paging_shutdown(void);
-
-/* ems_3.c */
-int ems_copy_it_up(int ems_paging_handle,
- int *ems_page_marker,
- int *ems_page_offset,
- byte *source,
- long read_size);
-
-/* ems_4.c */
-int ems_copy_it_down(int ems_paging_handle,
- int *ems_page_marker,
- int *ems_page_offset,
- byte *target,
- long write_size);
-
-/* ems_5.c */
-int ems_map_buffer(int buffer_page_handle);
-
-/* ems_6.c */
-int ems_search_page(int ems_handle, int page_number);
-
-/* ems_7.c */
-void ems_buffer_to_buffer(int source_handle, int target_handle);
+/**
+ * Maps a logical page (0 - (ems_pages-1)) to a physical page (0-3).
+ * Does not actually generate an EMS interrupt if the page is already
+ * mapped. Call only if EMS memory was detected.
+ */
+inline int ems_map_page(word physical, word logical);
+
+inline void ems_unmap_all() {}
+inline void ems_push() {}
+inline void ems_pop() {}
+inline int ems_activate_directory() { return 0; }
+inline int ems_activate_page_map() { return 0; }
+inline int ems_paging_setup() { return 0; }
+inline void ems_free_page_handle(word handle) {}
+inline int ems_get_page_handle(word pages_needed) { return 0; }
+inline int ems_next_handle_page(int handle, int page_marker) { return 0; }
+inline void ems_paging_mode(int paging_mode) {}
+inline void ems_paging_shutdown() {}
+inline int ems_copy_it_up(int ems_paging_handle, int *ems_page_marker,
+ int *ems_page_offset, byte *source, long read_size) { return 0; }
+inline int ems_copy_it_down(int ems_paging_handle, int *ems_page_marker,
+ int *ems_page_offset, byte *target, long write_size) { return 0; }
+inline int ems_map_buffer(int buffer_page_handle) { return 0; }
+inline int ems_search_page(int ems_handle_, int page_number) { return 0; }
+inline void ems_buffer_to_buffer(int source_handle, int target_handle) {}
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/core/error.cpp b/engines/mads/madsv2/core/error.cpp
index 646de6e72e0..55e7b1ea320 100644
--- a/engines/mads/madsv2/core/error.cpp
+++ b/engines/mads/madsv2/core/error.cpp
@@ -62,13 +62,9 @@ static void error_explode(char *error_buf, char *module_buf, char *data1_buf, ch
::error("Execution aborted");
}
-
-#pragma optimize ("egl", on)
-
void error_report(int error, int severity, int module, long data1, long data2) {
char error_buf[40], module_buf[40], data1_buf[12], data2_buf[12];
int handled = false;
- int key;
if (severity >= error_abort) {
mads_itoa(error, error_buf, 10);
diff --git a/engines/mads/madsv2/core/error.h b/engines/mads/madsv2/core/error.h
index 91ea141f1c2..ddc67f65d36 100644
--- a/engines/mads/madsv2/core/error.h
+++ b/engines/mads/madsv2/core/error.h
@@ -136,33 +136,32 @@ extern void (*error_service_routine_2)();
/* error_1.cpp */
-void error_report(int error, int severity, int module,
- long data1, long data2);
+extern void error_report(int error, int severity, int module, long data1, long data2);
int error_scan(char *target, char *name, int number);
-void error_dump_file(char *file_name);
+extern void error_dump_file(char *file_name);
/* error_2.cpp */
-void error_break_point(int data1, int data2);
+extern void error_break_point(int data1, int data2);
/* error_3.cpp */
-void error_watch_point(char *message, long data1, long data2);
+extern void error_watch_point(char *message, long data1, long data2);
/* error_4.cpp */
-void error_check_memory(void);
+extern void error_check_memory(void);
/* error_5.cpp */
-void error_file_point(char *message, long data1, long data2);
+extern void error_file_point(char *message, long data1, long data2);
/* error_6.cpp */
-void error_entry(char *name, char *message);
-void error_exit(char *name, char *message);
-void error_put(char *name, int item);
+extern void error_entry(char *name, char *message);
+extern void error_exit(char *name, char *message);
+extern void error_put(char *name, int item);
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/core/extra.h b/engines/mads/madsv2/core/extra.h
new file mode 100644
index 00000000000..9730ab99a0e
--- /dev/null
+++ b/engines/mads/madsv2/core/extra.h
@@ -0,0 +1,68 @@
+/* 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 MADS_CORE_EXTRA_H
+#define MADS_CORE_EXTRA_H
+
+#include "mads/madsv2/core/general.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+
+#define JOURNAL_FLY 1
+#define BP_FLY 2
+#define CANDLE_FLY 3
+#define DOOR_FLY 4
+
+/************** NOTE: *********************/
+/** IF following values are changed, then recompile EXTRA.C & GAME_3.C **/
+
+#define JOURNAL_X 8 /* X for top left corner of JOURNAL */
+#define JOURNAL_Y 3 /* Y for top left corner of JOURNAL */
+#define BP_X 68 /* X for top left corner of BP */
+#define BP_Y 1 /* Y for top left corner of BP */
+#define CANDLE_X 194 /* X for top left corner of CANDLE */
+#define CANDLE_Y 4 /* Y for top left corner of CANDLE */
+#define DOOR_X 264 /* X for top left corner of DOOR */
+#define DOOR_Y 2 /* Y for top left corner of DOOR */
+
+extern void fly_on_screen(int flying_object);
+extern void fly_off_screen(int flying_object);
+
+extern void display_inventory(void);
+extern void display_journal(void);
+extern void leave_journal(void);
+extern void solve_me_selected(void);
+extern void door_selected(void);
+
+extern void extra_spinning_object(void);
+extern void extra_inven_preserve_palette(void);
+extern void stamp_sprite_to_interface(int x, int y, int sprite, int series);
+extern void delete_sprite_in_interface(int series);
+extern void extra_change_animation(int handle, int x, int y, byte scale, byte depth);
+extern void extra_shift_animation(int handle, int x, int y, byte scale);
+extern void extra_blank_knothole(void);
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/fileio.cpp b/engines/mads/madsv2/core/fileio.cpp
new file mode 100644
index 00000000000..9b1f4546afd
--- /dev/null
+++ b/engines/mads/madsv2/core/fileio.cpp
@@ -0,0 +1,477 @@
+/* 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/system.h"
+#include "common/file.h"
+#include "common/savefile.h"
+#include "mads/madsv2/core/general.h"
+#include "mads/madsv2/core/fileio.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+#define SLOW_BUFFER_SIZE 256
+
+bool fileio_suppress_unbuffering = false;
+
+void fileio_purge_trailing_spaces(char *myline) {
+ char *search;
+ int again;
+
+ search = &myline[strlen(myline) - 1];
+
+ do {
+ again = true;
+ search = &myline[strlen(myline) - 1];
+ if ((*search == 0x20) || (*search == 0x09)) {
+ *search = 0;
+ } else {
+ again = false;
+ }
+
+ search--;
+ if (search < myline) again = false;
+ } while (again);
+}
+
+void fileio_name_new_ext(char *bakfile, char *mainfile, char *new_ext) {
+ char temp_full[80];
+ char temp_drive[4];
+ char temp_dir[80];
+ char temp_name[10];
+ char temp_ext[8];
+
+ Common::strcpy_s(temp_dir, mainfile);
+
+ _fullpath(temp_full, temp_dir, 80);
+
+ _splitpath(temp_full, temp_drive, temp_dir, temp_name, temp_ext);
+
+ Common::strcpy_s(bakfile, 65536, temp_drive);
+ Common::strcat_s(bakfile, 65536, temp_dir);
+ Common::strcat_s(bakfile, 65536, temp_name);
+ Common::strcat_s(bakfile, 65536, new_ext);
+}
+
+
+char *fileio_ffgets(char *mystring, int num, Common::SeekableReadStream *stream) {
+ char *temp;
+ char *from;
+ char *unto;
+ char workchar;
+ char ffbuf[256];
+ int worklen;
+ int tabstop;
+
+ if (stream->eos()) {
+ temp = nullptr;
+ } else {
+ Common::String line = stream->readLine();
+ Common::strcpy_s(ffbuf, line.c_str());
+ temp = ffbuf;
+ }
+
+ if (temp != NULL) {
+ worklen = 0;
+ from = ffbuf;
+ unto = mystring;
+ workchar = true;
+
+ while (workchar != 0) {
+ if (*from != 0x09) {
+ if (worklen <= num) {
+ workchar = *(unto++) = *(from++);
+ worklen++;
+ } else {
+ workchar = 0;
+ mystring = NULL;
+ }
+ } else {
+ from++;
+ tabstop = (((worklen >> 3) + 1) << 3);
+ if (tabstop < num) {
+ while (worklen < tabstop) {
+ *(unto++) = 0x20;
+ worklen++;
+ }
+ } else {
+ workchar = 0;
+ mystring = NULL;
+ }
+ }
+ }
+ return (mystring);
+ } else {
+ return (NULL);
+ }
+}
+
+int fileio_ffputs(const char *mystring, Common::WriteStream *stream) {
+ char ffbuf[256];
+
+ Common::strcpy_s(ffbuf, mystring);
+ stream->writeString(mystring);
+ return 0;
+}
+
+char *fileio_fix_lf_input(char *mystring) {
+ char *temp;
+
+ temp = strrchr(mystring, 0x0a);
+ if (temp != NULL) {
+ *temp = '\0';
+ }
+
+ return temp;
+}
+
+void fileio_fix_lf_output(char *mystring) {
+ char *temp;
+
+ temp = mystring + strlen(mystring);
+ *(temp++) = 0x0a;
+ *temp = '\0';
+}
+
+int fileio_copy(const char *source, const char *dest) {
+ Common::File src;
+ Common::OutSaveFile *dst;
+
+ if (src.open(source)) {
+ dst = g_system->getSavefileManager()->openForSaving(dest, false);
+ if (dst != nullptr) {
+ dst->writeStream(&src);
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+long fileio_setpos(Common::SeekableReadStream *handle, long pos) {
+ return handle->seek(pos);
+}
+
+long fileio_fread_f(byte *target, long record_size, long record_count, Common::SeekableReadStream *handle) {
+ if (!record_size)
+ return 0;
+
+ const long total_size = record_size * record_count;
+ const long total_read = handle->read(target, total_size);
+
+ return total_read / record_size;
+}
+
+long fileio_fwrite_f(const byte *source, long record_size, long record_count, Common::WriteStream *handle) {
+ if (!record_size)
+ return 0;
+
+ const long total_size = record_size * record_count;
+ const long total_written = handle->write(source, total_size);
+
+ return total_written / record_size;
+}
+
+long fileio_file_to_file(Common::SeekableReadStream *source, Common::WriteStream *dest, long amount) {
+ return dest->writeStream(source, amount);
+}
+
+long fileio_get_file_size(const char *filename) {
+ Common::File f;
+ if (Common::File::exists(filename) && f.open(filename))
+ return f.size();
+
+ Common::InSaveFile *sf = g_system->getSavefileManager()->openForLoading(filename);
+ long result = sf ? sf->size() : -1;
+ delete sf;
+
+ return result;
+}
+
+char *fileio_get_filetype(char *outp, char *inp) {
+ Common::File fcb;
+ char test[20];
+ int a;
+
+ Common::strcpy_s(outp, 65536, "");
+ if (fileio_exist(inp) && fcb.open(inp) && fcb.read(test, 8) == 8) {
+ if ((test[0] == 'D') && (test[1] == '4') && (test[2] == 'A'))
+ Common::strcpy_s(outp, 4, "D4A");
+ else {
+ a = 0;
+ while ((a < 11) && (test[a] != 26) && (test[a] != 0)) {
+ outp[a] = test[a];
+ outp[a + 1] = 0;
+ a++;
+ }
+ }
+
+ fcb.close();
+ return outp;
+ }
+
+ return nullptr;
+}
+
+unsigned long fileio_get_file_time(const char *filename) {
+ error("TODO: fileio_get_file_time");
+}
+
+char *fileio_read_header(char *target, Common::SeekableReadStream *handle) {
+ char *mark = target;
+ int next = 1;
+ int count = 0;
+
+ while (next && (count < 79)) {
+ next = handle->readByte();
+ *mark = (byte)next;
+ mark++;
+ count++;
+ }
+ (void)handle->readByte(); /* Throw away EOF mark */
+
+ return target;
+}
+
+
+void fileio_write_header(char *text, Common::WriteStream *handle) {
+ int next = 1;
+
+ while (next) {
+ next = *text;
+ text++;
+ handle->writeByte(next);
+ }
+ handle->writeByte(26); /* Write fake EOF mark */
+}
+
+char *fileio_get_line(char *target, Common::SeekableReadStream *handle) {
+ bool going = true;
+ byte item;
+
+ while (going) {
+ if (handle->eos()) {
+ *target = 0;
+ target = NULL;
+ going = false;
+ } else {
+ item = handle->readByte();
+
+ if (item == 0x1a) {
+ *target = 0;
+ target = NULL;
+ going = false;
+ } else if (item == 0x0a) {
+ *target = 0;
+ going = false;
+ } else {
+ *(target++) = item;
+ }
+ }
+ }
+
+ return target;
+}
+
+int fileio_put_line(const char *source, Common::WriteStream *handle) {
+ handle->writeString(source);
+ handle->writeByte('\n');
+
+ return 0;
+}
+
+
+long fileio_get_disk_free(char drive) {
+ return 999999;
+}
+
+void fileio_add_ext(char *name, char *ext) {
+ char *mark;
+
+ mark = strrchr(name, '.');
+ if (mark == NULL) {
+ Common::strcat_s(name, 65536, ".");
+ Common::strcat_s(name, 65536, ext);
+ }
+
+ mads_strupr(name);
+}
+
+void fileio_new_ext(char *target, char *name, char *ext) {
+ char *mark;
+
+ if (name != target) {
+ Common::strcpy_s(target, 65536, name);
+ }
+
+ mark = strrchr(target, '.');
+ if (mark != NULL) *mark = 0;
+ Common::strcat_s(target, 65536, ".");
+ Common::strcat_s(target, 65536, ext);
+
+ mads_strupr(target);
+}
+
+int fileio_logpath(const char *path) {
+ // No implementation in ScummVM
+ return 0;
+}
+
+char *fileio_parse_filename(char *target, char *filepath) {
+ char temp_buf[80];
+ char *mark;
+
+ Common::strcpy_s(temp_buf, filepath);
+
+ mark = strrchr(temp_buf, '\\');
+ if (mark != NULL) {
+ mark++;
+ } else {
+ mark = temp_buf;
+ }
+
+ Common::strcpy_s(target, 65536, mark);
+ mads_strupr(target);
+
+ return target;
+}
+
+char *fileio_parse_path(char *target, const char *filepath) {
+ char temp_buf[80];
+ char *mark;
+
+ Common::strcpy_s(temp_buf, filepath);
+
+ mark = strrchr(temp_buf, '\\');
+ if (mark != NULL) {
+ if (*(mark + 1)) {
+ *mark = 0;
+ }
+ Common::strcpy_s(target, 65536, temp_buf);
+ *mark = '\\';
+ } else {
+ Common::strcpy_s(target, 65536, temp_buf);
+ }
+
+ mads_strupr(target);
+
+ return target;
+}
+
+char *fileio_swap_path(char *target, const char *base, const char *file) {
+ char temp_buf[80];
+ char *mark;
+
+ Common::strcpy_s(temp_buf, base);
+
+ mark = strrchr(temp_buf, '\\');
+ if (mark == NULL) {
+ *target = 0;
+ } else {
+ *mark = 0;
+ Common::strcpy_s(target, 65536, temp_buf);
+ Common::strcat_s(target, 65536, "\\");
+ Common::strcat_s(target, 65536, file);
+ mads_strupr(target);
+ }
+
+ return target;
+}
+
+
+char *fileio_join_path(char *target, const char *path, const char *file) {
+ char temp_buf[80];
+ char *mark;
+
+ Common::strcpy_s(temp_buf, path);
+
+ mark = temp_buf;
+ while (*mark) mark++;
+ mark--;
+ if (*mark != '\\')
+ Common::strcat_s(temp_buf, "\\");
+
+ Common::strcpy_s(target, 65536, temp_buf);
+ Common::strcat_s(target, 65536, file);
+ mads_strupr(target);
+
+ return target;
+}
+
+
+void fileio_get_volume_label(char *volume_label, char drive_letter) {
+ error("TODO: fileio_get_volume_label");
+}
+
+int fileio_set_file_time(char *filename, long new_time) {
+ error("TODO: fileio_set_file_time");
+}
+
+int fileio_get_file_attributes(const char *filename, word *attributes) {
+ error("TODO: fileio_get_file_attributes");
+}
+
+int fileio_set_file_attributes(const char *filename, word attributes) {
+ error("TODO: fileio_set_file_attributes");
+}
+
+int fileio_read_till_null(char *target, Common::SeekableReadStream *handle) {
+ return handle->read(target, handle->size());
+}
+
+char *fileio_prepend(char *target, const char *source, const char *prepend) {
+ char temp_buf[256];
+
+ Common::strcpy_s(temp_buf, prepend);
+ Common::strcat_s(temp_buf, source);
+ Common::strcpy_s(target, 65536, temp_buf);
+
+ return target;
+}
+
+char *fileio_chop_ext(char *target, const char *source) {
+ char *mark;
+
+ if (source != target) {
+ Common::strcpy_s(target, 65536, source);
+ }
+
+ mark = strchr(target, '.');
+ if (mark != NULL) *mark = 0;
+
+ return target;
+}
+
+void fileio_purge_all_spaces(char *text) {
+ char work[256];
+ char *mark;
+
+ fileio_purge_trailing_spaces(text);
+
+ mark = text;
+ while (*mark && ((*mark == ' ') || (*mark == 0x09))) mark++;
+
+ Common::strcpy_s(work, mark);
+ Common::strcpy_s(text, 65536, work);
+}
+
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/core/fileio.h b/engines/mads/madsv2/core/fileio.h
index e2916d4bb1c..9b7b76730f8 100644
--- a/engines/mads/madsv2/core/fileio.h
+++ b/engines/mads/madsv2/core/fileio.h
@@ -22,127 +22,61 @@
#ifndef MADS_CORE_FILEIO_H
#define MADS_CORE_FILEIO_H
+#include "common/stream.h"
+
namespace MADS {
namespace MADSV2 {
#define fread_bufsize 1024
-extern int fileio_suppress_unbuffering;
-
-
-/* fileio_1 */
-void fileio_purge_trailing_spaces(char *myline);
-
-/* fileio_2 */
-void fileio_name_new_ext(char *bakfile,
- char *mainfile,
- char *new_ext);
-
-/* fileio_3 */
-char *fileio_ffgets(char *mystring,
- int num,
- Common::Stream *stream);
+extern bool fileio_suppress_unbuffering;
-/* fileio_4 */
-int fileio_ffputs(char *mystring,
- Common::Stream *stream);
-/* fileio_5 */
+void fileio_purge_trailing_spaces(char *myline);
+void fileio_name_new_ext(char *bakfile, char *mainfile, const char *new_ext);
+char *fileio_ffgets(char *mystring, int num, Common::SeekableReadStream *stream);
+int fileio_ffputs(const char *mystring, Common::WriteStream *stream);
char *fileio_fix_lf_input(char *mystring);
+void fileio_fix_lf_output(char *mystring);
+int fileio_copy(const char *source, const char *dest);
+long fileio_setpos(Common::SeekableReadStream *handle, long pos);
+long fileio_fread_f(void *buffer, long size, long count, Common::SeekableReadStream *stream);
+long fileio_fwrite_f(const void *buffer, long size, long count, Common::WriteStream *stream);
+long fileio_file_to_file(Common::SeekableReadStream *from, Common::WriteStream *to, long count);
+long fileio_get_file_size(const char *filename);
+int fileio_exist(const char *inp);
+
+/**
+ * Returns the identifying portion of the file header in OUTP string
+ */
+char *fileio_get_filetype(char *outp, char *inp);
-/* fileio_6 */
-void fileio_fix_lf_output(char *mystring);
-
-int fileio_copy(char *source, char *dest);
-
-
-/* fileio_7 */
-long fileio_setpos(Common::Stream *handle, long pos);
-
-
-/* fileio_8 */
-long fileio_fread_f(void *buffer, long size,
- long count, Common::Stream *stream);
-
-/* fileio_9 */
-long fileio_fwrite_f(void *buffer, long size,
- long count, Common::Stream *stream);
-
-/* fileio_a */
-long fileio_file_to_file(Common::Stream *from, Common::Stream *to, long count);
-
-/* fileio_b */
-long fileio_get_file_size(char *filename);
-
-/* fileio_c */
-int fileio_exist(char *inp);
-
-/* fileio_d */
-char * fileio_get_filetype(char *outp, char *inp);
-
-/* fileio_e */
-long fileio_get_file_time(char *filename);
-
-/* fileio_f */
-char * fileio_read_header(char *target, Common::Stream *handle);
-void fileio_write_header(char *text, Common::Stream *handle);
-
-/* fileio_g */
-char *fileio_get_line(char *target, Common::Stream *handle);
-int fileio_put_line(char *source, Common::Stream *handle);
+/**
+ * Returns the DOS time/date stamp for a given file.
+ * @return Returns 0 if file is not found. Returned 32 bit number contains
+ * the date stamp in it's upper 16 bits, and the time stamp in it's lower.
+ */
+long fileio_get_file_time(char *filename);
-/* fileio_h */
+char *fileio_read_header(char *target, Common::SeekableReadStream *handle);
+void fileio_write_header(char *text, Common::WriteStream *handle);
+char *fileio_get_line(char *target, Common::SeekableReadStream *handle);
+int fileio_put_line(char *source, Common::WriteStream *handle);
long fileio_get_disk_free(char drive);
-
-/* fileio_i */
-void fileio_add_ext(char *name, char *ext);
-void fileio_new_ext(char *target,
- char *name,
- char *ext);
-
-/* fileio_j */
-int fileio_logpath(char *path);
-
-/* fileio_k */
-char *fileio_parse_filename(char *target,
- char *filepath);
-char *fileio_parse_path(char *target,
- char *filepath);
-
-/* fileio_l */
-char *fileio_swap_path(char *target,
- char *base,
- char *file);
-
-/* fileio_m */
-char *fileio_join_path(char *target,
- char *path,
- char *file);
-
-/* fileio_n */
+void fileio_add_ext(char *name, const char *ext);
+void fileio_new_ext(char *target, const char *name, const char *ext);
+int fileio_logpath(const char *path);
+char *fileio_parse_filename(char *target, char *filepath);
+char *fileio_parse_path(char *target, const char *filepath);
+char *fileio_swap_path(char *target, const char *base, const char *file);
+char *fileio_join_path(char *target, const char *path, const char *file);
void fileio_get_volume_label(char *volume_label, char drive_letter);
-
-/* fileio_o */
-int fileio_set_file_time(char *filename, long new_time);
-
-/* fileio_p */
-int fileio_get_file_attributes(char *filename, word *attributes);
-
-/* fileio_q */
-int fileio_set_file_attributes(char *filename, word attributes);
-
-/* fileio_r */
+int fileio_set_file_time(char *filename, long new_time);
+int fileio_get_file_attributes(const char *filename, word *attributes);
+int fileio_set_file_attributes(const char *filename, word attributes);
int fileio_read_till_null(char *target, Common::Stream *handle);
-
-/* fileio_s */
-char *fileio_prepend(char *target,
- char *source,
- char *prepend);
-
-/* fileio_t */
-char *fileio_chop_ext(char *target, char *source);
-
-/* fileio_u */
+char *fileio_prepend(char *target, const char *source, const char *prepend);
+char *fileio_chop_ext(char *target, const char *source);
void fileio_purge_all_spaces(char *text);
} // namespace MADSV2
diff --git a/engines/mads/madsv2/core/font.h b/engines/mads/madsv2/core/font.h
index 1c80ecfd96b..62488b4c313 100644
--- a/engines/mads/madsv2/core/font.h
+++ b/engines/mads/madsv2/core/font.h
@@ -54,8 +54,7 @@ extern FontPtr font_misc; /* Font handle for symbols & icons */
FontPtr font_load(const char *name);
/* font_2.cpp */
-int font_write(FontPtr font, Buffer *target,
- char *out_string, int x, int y,
+int font_write(FontPtr font, Buffer *target, const char *out_string, int x, int y,
int auto_spacing);
/* font_3.cpp */
@@ -65,9 +64,7 @@ void font_set_colors(int background,
int low_intense);
/* font_4.cpp */
-int font_string_width(FontPtr font,
- char *out_string,
- int auto_spacing);
+int font_string_width(FontPtr font, const char *out_string, int auto_spacing);
/* font_5.cpp */
void font_init(FontPtr font);
diff --git a/engines/mads/madsv2/core/game.h b/engines/mads/madsv2/core/game.h
index fb5aecd9087..f1bf5311336 100644
--- a/engines/mads/madsv2/core/game.h
+++ b/engines/mads/madsv2/core/game.h
@@ -93,7 +93,7 @@ namespace MADSV2 {
#define DEBUGGER_MAX_WATCH 12
-int int_sprite[6];
+extern int int_sprite[6];
extern int selected_intro;
@@ -112,8 +112,8 @@ extern int selected_intro;
/* Declared by Taranjeet for OUAF Journal */
-Player journal_player;
-int journal_room;
+extern Player journal_player;
+extern int journal_room;
#define GAME_MAIN_MENU 1 /* Game menus */
#define GAME_SAVE_MENU 2
diff --git a/engines/mads/madsv2/core/himem.cpp b/engines/mads/madsv2/core/himem.cpp
new file mode 100644
index 00000000000..2cf8700a684
--- /dev/null
+++ b/engines/mads/madsv2/core/himem.cpp
@@ -0,0 +1,673 @@
+/* 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 "mads/madsv2/core/general.h"
+#include "mads/madsv2/core/himem.h"
+#include "mads/madsv2/core/ems.h"
+#include "mads/madsv2/core/xms.h"
+#include "mads/madsv2/core/mem.h"
+#include "mads/madsv2/core/loader.h"
+#include "mads/madsv2/core/sprite.h"
+#include "mads/madsv2/core/fileio.h"
+#include "mads/madsv2/core/pack.h"
+#include "mads/madsv2/core/tile.h"
+#include "mads/madsv2/core/env.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+
+byte himem_preload_ems_disabled = false;
+byte himem_preload_xms_disabled = false;
+
+byte himem_directory_allocation = MEM_NONE;
+HimemDirectory himem_directory_save_area;
+HimemDirectory *himem_directory;
+HimemDirectory *himem_directory_entry;
+HimemDirectory *himem_ems_directory = NULL;
+
+int himem_directory_xms_handle = -1;
+int himem_directory_ems_active = false;
+int himem_active = false;
+
+int himem_ems_preloaded = 0;
+int himem_xms_preloaded = 0;
+
+
+int himem_activate_directory(void) {
+ int error_flag = false;
+
+ if (himem_directory_allocation == MEM_EMS) {
+ himem_directory_ems_active = !ems_activate_page_map();
+
+ error_flag = !himem_directory_ems_active;
+ }
+
+ return (error_flag);
+}
+
+
+int himem_get_directory_entry(int id) {
+ int error_flag = true;
+ long dir_offset;
+
+ if (himem_directory_allocation == MEM_EMS) {
+ if (himem_activate_directory()) goto done;
+ himem_directory_entry = &himem_ems_directory[id];
+ } else {
+ dir_offset = ((long)sizeof(HimemDirectory)) * id;
+ if (xms_copy(sizeof(HimemDirectory),
+ himem_directory_xms_handle, (XMS)dir_offset,
+ MEM_CONV, &himem_directory_save_area)) goto done;
+ }
+
+ error_flag = false;
+
+done:
+ return (error_flag);
+}
+
+int himem_put_directory_entry(int id) {
+ int error_flag = true;
+ long dir_offset;
+
+ if (himem_directory_allocation == MEM_EMS) {
+ if (himem_activate_directory()) goto done;
+ if (himem_directory_entry != &himem_ems_directory[id]) {
+ himem_ems_directory[id] = *himem_directory_entry;
+ }
+ } else {
+ dir_offset = ((long)sizeof(HimemDirectory)) * id;
+ if (xms_copy(sizeof(HimemDirectory),
+ MEM_CONV, himem_directory_entry,
+ himem_directory_xms_handle, (XMS)dir_offset)) goto done;
+ }
+
+ error_flag = false;
+
+done:
+ return error_flag;
+}
+
+int himem_resident(char *filename) {
+ int id = -1;
+ int count;
+ char *mark;
+ long dir_size;
+ HimemDirectory *himem_xms_directory = NULL;
+
+ if (!himem_active) goto done;
+
+ mark = strrchr(filename, '\\');
+ if (mark == NULL) mark = strchr(filename, '*');
+ if (mark == NULL) {
+ mark = filename;
+ } else {
+ mark++;
+ }
+
+ if (himem_directory_allocation == MEM_EMS) {
+ if (himem_activate_directory()) goto done;
+ } else {
+ dir_size = ((long)sizeof(HimemDirectory)) * HIMEM_MAX_RESIDENT;
+
+ himem_directory = himem_xms_directory = (HimemDirectory *)mem_get_name(dir_size, "$HIMEM$");
+ if (himem_xms_directory == NULL) goto done;
+
+ if (xms_copy(dir_size,
+ himem_directory_xms_handle, (XMS)0,
+ MEM_CONV, himem_xms_directory)) goto done;
+ }
+
+ for (count = 0; (count < HIMEM_MAX_RESIDENT) && (id < 0); count++) {
+ if (himem_directory[count].memory_type == MEM_NONE) {
+ if (filename == NULL) id = count;
+ } else {
+ if (scumm_stricmp(mark, himem_directory[count].list) == 0) {
+ id = count;
+ }
+ }
+ }
+
+done:
+ if (id >= 0) himem_get_directory_entry(id);
+ if (himem_xms_directory != NULL) mem_free(himem_xms_directory);
+ return id;
+}
+
+int himem_directory_setup(void) {
+ int error_flag = true;
+ int count;
+ long dir_size = 0;
+ HimemDirectory *himem_xms_directory = NULL;
+
+ if (ems_paging_active) {
+ himem_directory_allocation = MEM_EMS;
+ himem_directory = himem_ems_directory = (HimemDirectory *) (ems_page[EMS_PAGE_MAP_PAGE] + EMS_DIRECTORY_ADDRESS);
+ if (himem_activate_directory()) goto done;
+ } else if (!himem_preload_xms_disabled) {
+ himem_directory_allocation = MEM_XMS;
+ dir_size = ((long)sizeof(HimemDirectory)) * HIMEM_MAX_RESIDENT;
+
+ himem_directory_xms_handle = xms_get(dir_size);
+ if (himem_directory_xms_handle <= 0) goto done;
+
+ himem_directory = himem_xms_directory = (HimemDirectory *)mem_get_name(dir_size, "$HIMEM$");
+ if (himem_xms_directory == NULL) goto done;
+
+ himem_directory_entry = &himem_directory_save_area;
+ } else {
+ goto done;
+ }
+
+ for (count = 0; count < HIMEM_MAX_RESIDENT; count++) {
+ himem_directory[count].memory_type = MEM_NONE;
+ }
+
+ if (himem_directory_allocation == MEM_XMS) {
+ if (xms_copy(dir_size,
+ MEM_CONV, himem_xms_directory,
+ himem_directory_xms_handle, (XMS)0)) goto done;
+ }
+
+ himem_active = true;
+ error_flag = false;
+
+done:
+ if (himem_xms_directory != NULL) mem_free(himem_xms_directory);
+ if (error_flag) {
+ himem_directory_allocation = MEM_NONE;
+ if (himem_directory_xms_handle > 0) {
+ xms_free(himem_directory_xms_handle);
+ himem_directory_xms_handle = -1;
+ }
+ }
+
+ return error_flag;
+}
+
+
+void himem_shutdown(void) {
+ int count;
+
+ if (!himem_activate_directory()) {
+ for (count = 0; count < HIMEM_MAX_RESIDENT; count++) {
+ himem_get_directory_entry(count);
+ if (himem_directory_entry->memory_type == MEM_XMS) {
+ xms_free(himem_directory_entry->xms_handle);
+ }
+ }
+ }
+
+ if (himem_directory_allocation == MEM_XMS) {
+ xms_free(himem_directory_xms_handle);
+ }
+
+ himem_active = false;
+
+ xms_umb_purge();
+ ems_shutdown();
+}
+
+void himem_startup(void) {
+ ems_detect();
+ ems_paging_setup();
+
+ xms_detect();
+
+ himem_directory_setup();
+}
+
+int himem_preload(char *filename, int level) {
+ int preload_handle = -1;
+ int new_handle = -1;
+ int page_marker = -1;
+ int page_offset = EMS_PAGE_SIZE;
+ int count;
+ int memory_type = MEM_NONE;
+ int xms_handle = -1;
+ long xms_offset = 0;
+ long size, page_size;
+ long read_size;
+ char *mark;
+ byte *load_buf = NULL;
+ Load handle;
+
+ handle.open = false;
+
+ if ((himem_resident(filename) >= 0) || !himem_active) goto done;
+
+ if (loader_open(&handle, filename, "rb", false)) goto done;
+
+ size = handle.decompress_size;
+ page_size = (size >> 14);
+ if ((page_size << 14) < size) page_size++;
+
+ if (ems_paging_active && !himem_preload_ems_disabled) {
+ new_handle = ems_get_page_handle((word)page_size);
+ if (new_handle >= 0) {
+ memory_type = MEM_EMS;
+ himem_directory_entry->ems_page_handle = (byte)new_handle;
+ }
+ }
+
+ if ((memory_type == MEM_NONE) && !himem_preload_xms_disabled) {
+ xms_handle = xms_get((word)size);
+ if (xms_handle > 0) {
+ new_handle = himem_resident(NULL);
+ if (new_handle >= 0) {
+ memory_type = MEM_XMS;
+ himem_directory_entry->xms_handle = xms_handle;
+ himem_directory_entry->ems_page_handle = (byte)new_handle;
+ } else {
+ xms_free(xms_handle);
+ }
+ }
+ }
+
+ if (memory_type == MEM_NONE) goto done;
+
+ himem_directory_entry->memory_type = (byte)memory_type;
+ himem_directory_entry->size = size;
+ himem_directory_entry->level = (byte)level;
+
+ himem_directory_entry->num_packets = handle.pack.num_records;
+ for (count = 0; count < (int)handle.pack.num_records; count++) {
+ himem_directory_entry->packet_size[count] = handle.pack.strategy[count].size;
+ }
+
+ for (count = 0; count < (int)handle.pack.num_records; count++) {
+ read_size = handle.pack.strategy[count].size;
+ load_buf = (byte *)mem_get_name(read_size, "$PRELOAD");
+ if (load_buf == NULL) goto done;
+
+ if (!loader_read(load_buf, read_size, 1, &handle)) goto done;
+
+ if (memory_type == MEM_EMS) {
+ if (ems_copy_it_up(new_handle, &page_marker, &page_offset, load_buf, read_size)) goto done;
+ } else {
+
+ /* printf ("Record %d (Size: %ld, Offset: %ld)\n", count, read_size, xms_offset); */
+
+ if (xms_copy(read_size,
+ MEM_CONV, load_buf,
+ xms_handle, (XMS)xms_offset)) goto done;
+ xms_offset += read_size;
+ }
+
+ mem_free(load_buf);
+ load_buf = NULL;
+ }
+
+ mark = strrchr(filename, '\\');
+ if (mark == NULL) mark = strchr(filename, '*');
+ if (mark == NULL) {
+ mark = filename;
+ } else {
+ mark++;
+ }
+
+ Common::strcpy_s(himem_directory_entry->list, mark);
+ mads_strlwr(himem_directory_entry->list);
+
+ preload_handle = new_handle;
+
+#ifndef disable_statistics
+ if (memory_type == MEM_EMS) {
+ himem_ems_preloaded++;
+ } else {
+ himem_xms_preloaded++;
+ }
+#endif
+
+done:
+ if (load_buf != NULL) mem_free(load_buf);
+ if (handle.open) loader_close(&handle);
+ if (preload_handle != new_handle) {
+ if (memory_type == MEM_EMS) {
+ ems_free_page_handle(new_handle);
+ } else if (memory_type == MEM_XMS) {
+ xms_free(xms_handle);
+ }
+ if (new_handle >= 0) {
+ himem_directory_entry->memory_type = MEM_NONE;
+ }
+ }
+ if (new_handle >= 0) {
+ himem_put_directory_entry(new_handle);
+ }
+
+ return preload_handle;
+}
+
+int himem_preload_series(char *filename, int level) {
+ int preload_handle = -1;
+ int new_handle = -1;
+ int page_marker = -1;
+ int page_offset = EMS_PAGE_SIZE;
+ int count;
+ int memory_type = 0;
+ int xms_handle = 0;
+ int num_records;
+ int might_be_series = false;
+ int sprite_packed = false;
+ int tile_packed = false;
+ int tile_type = 0;
+ int packing_flag;
+ int already_unpacked = false;
+ long xms_offset = 0;
+ long size, page_size;
+ long read_size;
+ long base_offset;
+ long top_of_file;
+ long compressed_size;
+ char *mark;
+ char *marker;
+ char file_buf[80];
+ char temp_buf[80];
+ byte *load_buf = NULL;
+ byte *decompress_buffer = NULL;
+ Load handle;
+ FileSeriesPtr file_series = NULL;
+ FileSpritePtr file_sprite = NULL;
+ TileResource *tile_resource = NULL;
+ Tile *tile = NULL;
+
+ handle.open = false;
+
+ Common::strcpy_s(file_buf, filename);
+ filename = file_buf;
+
+ fileio_add_ext(filename, "SS"); /* Default to Sprite Series */
+
+ if ((himem_resident(filename) >= 0) || !himem_active) goto done;
+
+ if (loader_open(&handle, filename, "rb", false)) goto done;
+
+ top_of_file = handle.handle->pos();
+
+ Common::strcpy_s(temp_buf, filename);
+ mads_strupr(temp_buf);
+ if (strstr(temp_buf, ".SS") != NULL) might_be_series = true;
+ if (strstr(temp_buf, ".TT") != NULL) {
+ tile_packed = true;
+ tile_type = TILE_PICTURE;
+ marker = strchr(temp_buf, '.');
+ if (marker != NULL) {
+ marker++;
+ while (*marker && (*marker == 'T')) marker++;
+ if (Common::isDigit(*marker)) {
+ tile_type = TILE_ATTRIBUTE;
+ }
+ }
+ }
+
+ size = handle.decompress_size;
+ page_size = (size >> 14);
+ if ((page_size << 14) < size) page_size++;
+
+ memory_type = MEM_NONE;
+ if (ems_paging_active && !himem_preload_ems_disabled) {
+ new_handle = ems_get_page_handle((word)page_size);
+ if (new_handle >= 0) {
+ memory_type = MEM_EMS;
+ himem_directory_entry->ems_page_handle = (byte)new_handle;
+ }
+ }
+
+ if ((memory_type == MEM_NONE) && !himem_preload_xms_disabled) {
+ xms_handle = xms_get((word)size);
+ if (xms_handle > 0) {
+ new_handle = himem_resident(NULL);
+ if (new_handle >= 0) {
+ memory_type = MEM_XMS;
+ himem_directory_entry->xms_handle = xms_handle;
+ } else {
+ xms_free(xms_handle);
+ }
+ }
+ }
+
+ if (memory_type == MEM_NONE) goto done;
+
+ himem_directory_entry->memory_type = (byte)memory_type;
+ himem_directory_entry->size = size;
+ himem_directory_entry->level = (byte)level;
+
+ himem_directory_entry->num_packets = handle.pack.num_records;
+ for (count = 0; count < (int)handle.pack.num_records; count++) {
+ himem_directory_entry->packet_size[count] = handle.pack.strategy[count].size;
+ }
+
+ num_records = handle.pack.num_records;
+
+ for (count = 0; count < (int)num_records; count++) {
+ read_size = handle.pack.strategy[count].size;
+ load_buf = (byte *)mem_get_name(read_size, "$PRELOAD");
+ if (load_buf == NULL) goto done;
+
+ if (!loader_read(load_buf, read_size, 1, &handle)) goto done;
+
+ if ((count == 0) && might_be_series) {
+ file_series = (FileSeriesPtr)load_buf;
+ sprite_packed = file_series->pack_by_sprite;
+ if (sprite_packed) {
+ num_records--;
+ }
+ file_series = NULL;
+ }
+
+
+ if (memory_type == MEM_EMS) {
+ if (ems_copy_it_up(new_handle, &page_marker, &page_offset, load_buf, read_size)) goto done;
+ } else {
+ if (xms_copy(read_size,
+ MEM_CONV, load_buf,
+ xms_handle, (XMS)xms_offset)) goto done;
+ xms_offset += read_size;
+ }
+
+ if (sprite_packed) {
+ if (count == 0) {
+ file_series = (FileSeriesPtr)load_buf;
+ load_buf = NULL;
+ } else if (count == 1) {
+ file_sprite = (FileSpritePtr)load_buf;
+ load_buf = NULL;
+ }
+ }
+
+ if (tile_packed) {
+ if (count == 0) {
+ tile_resource = (TileResource *) load_buf;
+ load_buf = NULL;
+
+ if (tile_type == TILE_PICTURE) {
+ tile_resource->chunk_size = (long)tile_resource->tile_x * (long)tile_resource->tile_y;
+ } else {
+ tile_resource->chunk_size = ((((long)tile_resource->tile_x - 1) >> 1) + 1) * (long)tile_resource->tile_y;
+ }
+ } else if (count == 1) {
+ tile = (Tile *) load_buf;
+ load_buf = NULL;
+ }
+ }
+
+ mem_free(load_buf);
+ load_buf = NULL;
+ }
+
+ if (sprite_packed) {
+ base_offset = handle.handle->pos();
+
+ for (count = 0; count < file_series->num_sprites; count++) {
+ read_size = file_sprite[count].memory_needed;
+
+ load_buf = (byte *)mem_get(read_size);
+ if (load_buf == NULL) goto done;
+
+ fileio_setpos(handle.handle, base_offset + file_sprite[count].file_offset);
+
+ if (pack_data(file_series->compression, read_size,
+ FROM_DISK, handle.handle,
+ TO_MEMORY, load_buf) != read_size) goto done;
+
+ if (memory_type == MEM_EMS) {
+ if (ems_copy_it_up(new_handle, &page_marker, &page_offset, load_buf, read_size)) goto done;
+ } else {
+ if (xms_copy(read_size,
+ MEM_CONV, load_buf,
+ xms_handle, (XMS)xms_offset)) goto done;
+ xms_offset += read_size;
+ }
+
+ mem_free(load_buf);
+ load_buf = NULL;
+ }
+ }
+
+ if (tile_packed) {
+ base_offset = handle.handle->pos();
+
+ for (count = 0; count < tile_resource->num_tiles; count++) {
+ read_size = tile_resource->chunk_size;
+
+ load_buf = (byte *)mem_get(read_size);
+ if (load_buf == NULL) goto done;
+
+ fileio_setpos(handle.handle, base_offset + tile[count].file_offset);
+
+ if (count < (tile_resource->num_tiles - 1)) {
+ compressed_size = tile[count + 1].file_offset - tile[count].file_offset;
+ } else {
+ compressed_size = (env_get_file_size(handle.handle) - PACK_OVERHEAD) -
+ (tile[count].file_offset + (base_offset - top_of_file));
+ }
+
+ pack_strategy = tile_resource->compression;
+ packing_flag = (tile_resource->compression != PACK_NONE) ? PACK_EXPLODE : PACK_RAW_COPY;
+
+ if (packing_flag == PACK_EXPLODE) {
+ decompress_buffer = (byte *)mem_get_name(compressed_size, "$hipack");
+ if (decompress_buffer != NULL) {
+
+ if (!fileio_fread_f(decompress_buffer, compressed_size, 1, handle.handle)) goto done;
+
+ if (pack_data(packing_flag, read_size,
+ FROM_MEMORY, decompress_buffer,
+ TO_MEMORY, load_buf) != read_size) goto done;
+
+ mem_free(decompress_buffer);
+ decompress_buffer = NULL;
+
+ already_unpacked = true;
+ }
+ }
+
+ if (!already_unpacked) {
+ if (pack_data(packing_flag, read_size,
+ FROM_DISK, handle.handle,
+ TO_MEMORY, load_buf) != read_size) goto done;
+ }
+
+ if (memory_type == MEM_EMS) {
+ if (ems_copy_it_up(new_handle, &page_marker, &page_offset, load_buf, read_size)) goto done;
+ } else {
+ if (xms_copy(read_size,
+ MEM_CONV, load_buf,
+ xms_handle, (XMS)xms_offset)) goto done;
+ xms_offset += read_size;
+ }
+
+ mem_free(load_buf);
+ load_buf = NULL;
+ }
+ }
+
+
+ mark = strrchr(filename, '\\');
+ if (mark == NULL) mark = strchr(filename, '*');
+ if (mark == NULL) {
+ mark = filename;
+ } else {
+ mark++;
+ }
+
+ Common::strcpy_s(himem_directory_entry->list, mark);
+ mads_strlwr(himem_directory_entry->list);
+
+ preload_handle = new_handle;
+
+#ifndef disable_statistics
+ if (memory_type == MEM_EMS) {
+ himem_ems_preloaded++;
+ } else {
+ himem_xms_preloaded++;
+ }
+#endif
+
+done:
+ if (decompress_buffer != NULL) mem_free(decompress_buffer);
+ if (load_buf != NULL) mem_free(load_buf);
+ if (file_sprite != NULL) mem_free(file_sprite);
+ if (file_series != NULL) mem_free(file_series);
+ if (tile != NULL) mem_free(tile);
+ if (tile_resource != NULL) mem_free(tile_resource);
+ if (handle.open) loader_close(&handle);
+ if (preload_handle != new_handle) {
+ if (memory_type == MEM_EMS) {
+ ems_free_page_handle(new_handle);
+ } else if (memory_type == MEM_XMS) {
+ xms_free(xms_handle);
+ }
+ if (new_handle >= 0) {
+ himem_directory_entry->memory_type = MEM_NONE;
+ }
+ }
+ if (new_handle >= 0) {
+ himem_put_directory_entry(new_handle);
+ }
+
+ return preload_handle;
+}
+
+void himem_flush(int level) {
+ int count;
+
+ if (!himem_active) return;
+ if (himem_activate_directory()) return;
+
+ for (count = 0; count < HIMEM_MAX_RESIDENT; count++) {
+ himem_get_directory_entry(count);
+ if (himem_directory_entry->level == (byte)level) {
+ if (himem_directory_entry->memory_type == MEM_EMS) {
+ ems_free_page_handle(count);
+ } else if (himem_directory_entry->memory_type == MEM_XMS) {
+ xms_free(himem_directory_entry->xms_handle);
+ }
+ himem_directory_entry->memory_type = MEM_NONE;
+ himem_put_directory_entry(count);
+ }
+ }
+}
+
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/core/imath.h b/engines/mads/madsv2/core/imath.h
index 48b36c1cabe..c6fe34220c8 100644
--- a/engines/mads/madsv2/core/imath.h
+++ b/engines/mads/madsv2/core/imath.h
@@ -27,19 +27,12 @@
namespace MADS {
namespace MADSV2 {
-/*
-/* imath_1.asm: integer math routines out of the MPS libraries
-*/
int imath_distance(int side_a, int side_b, int threshold);
int imath_hypot(int side_a, int side_b);
word imath_isqrt(long square);
-
-/* imath_2.c */
void imath_circular_arc(word *buffer, int radius);
-
-/* imath_3.c */
int imath_random(int from, int unto);
} // namespace MADSV2
diff --git a/engines/mads/madsv2/core/inter.cpp b/engines/mads/madsv2/core/inter.cpp
new file mode 100644
index 00000000000..62a8b39387e
--- /dev/null
+++ b/engines/mads/madsv2/core/inter.cpp
@@ -0,0 +1,2307 @@
+/* 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 "mads/madsv2/core/inter.h"
+#include "mads/madsv2/core/object.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/vocabh.h"
+#include "mads/madsv2/core/buffer.h"
+#include "mads/madsv2/core/mouse.h"
+#include "mads/madsv2/core/font.h"
+#include "mads/madsv2/core/pal.h"
+#include "mads/madsv2/core/lbm.h"
+#include "mads/madsv2/core/keys.h"
+#include "mads/madsv2/core/mcga.h"
+#include "mads/madsv2/core/vocab.h"
+#include "mads/madsv2/core/room.h"
+#include "mads/madsv2/core/anim.h"
+#include "mads/madsv2/core/hspot.h"
+#include "mads/madsv2/core/mem.h"
+#include "mads/madsv2/core/timer.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/player.h"
+#include "mads/madsv2/core/cycle.h"
+#include "mads/madsv2/core/video.h"
+#include "mads/madsv2/core/matte.h"
+#include "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/imath.h"
+#include "mads/madsv2/core/env.h"
+#include "mads/madsv2/core/error.h"
+#include "mads/madsv2/core/extra.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+#define disable_error_check
+
+extern int extra_display_object;
+
+int stroke_type = STROKE_NONE; /* Current stroke type */
+
+int inter_auxiliary_click; /* Clicks during downtime */
+
+AnimInterPtr inter_anim = NULL; /* Background animation script */
+
+int inter_mouse_x; /* Cooked mouse location X */
+int inter_mouse_y; /* Cooked mouse location Y */
+int inter_mouse_type; /* Hotspot list identifier */
+
+int inter_object_sprite = 1;
+int inter_object_series = -1;
+
+int inter_spinning_objects = true; /* Flag if objects rotating */
+int inter_animation_running = true; /* Flag if background animation */
+
+byte *inter_objects_block = NULL; /* Place for loading object series */
+long inter_objects_block_size = 0;
+
+int inter_input_mode = INTER_BUILDING_SENTENCES;
+
+char *inter_dialog_strings[inter_columns];
+int inter_dialog_results[inter_columns];
+
+
+Verb command[INTER_COMMANDS] = { /* Main Verb List */
+ { words_look, VERB_THAT, PREP_NONE },
+ { words_give, VERB_THIS, PREP_TO },
+ { words_take, VERB_THAT, PREP_NONE },
+ { words_talk_to, VERB_THAT, PREP_NONE },
+ { words_push, VERB_THAT, PREP_NONE },
+ { words_pull, VERB_THAT, PREP_NONE },
+ { words_put, VERB_THIS, PREP_RELATIONAL },
+ { words_open, VERB_THAT, PREP_NONE },
+ { words_close, VERB_THAT, PREP_NONE }
+};
+
+
+char istring_prep_names[9][7] = {
+ "", "with", "to", "at", "from", "on", "in", "under", "behind"
+};
+
+char istring_look_around[12] = "Look around";
+char istring_use[5] = "Use ";
+char istring_to[4] = "to ";
+char istring_walk_to[9] = "Walk to ";
+char istring_space[2] = " ";
+
+/* "I like ____. " */
+char istring_object_pronoun[MAX_SYNTAX][8] = {
+ "it", "them", "it", "him", "her", "it", "him", "her"
+};
+
+/* "_____ look(s) ornery." */
+char istring_subject_pronoun[MAX_SYNTAX][8] = {
+ "it", "they", "it", "he", "she", "it", "he", "she"
+};
+
+/* "I don't see _____ here." */
+char istring_demonstrative[MAX_SYNTAX][8] = {
+ "that", "those", "that", "him", "her", "it", "him", "her"
+};
+
+int inven[INVEN_MAX_OBJECTS]; /* Inventory index */
+int inven_num_objects = 0; /* Inventory size */
+
+int right_command = 0; /* Right mouse main verb */
+int left_command = -1; /* Left mouse main verb */
+int left_inven = -1; /* Left mouse inventory */
+int left_action = -1; /* Left mouse secondary verb */
+int right_action = -1; /* Right mouse secondary verb */
+
+int active_inven = -1; /* The selected inventory item */
+int first_inven = 0; /* First inventory item displayed on screen */
+
+long scroll_base_time = 0; /* Scrolling ballistic controls */
+int scroll_active = false;
+int scroll_quickly = false;
+
+int first_inven_changed = false; /* Flag if inventory view has changed */
+int picked_word = 0; /* Word most recently picked. */
+
+char inter_sentence[64]; /* Sentence building buffer */
+int inter_sentence_handle = -1; /* Sentence message handle (for matte) */
+int inter_sentence_changed = false; /* Mark if sentence contents changed */
+
+int inter_look_around; /* "Look around" command */
+
+int inter_command; /* Vocab # of sentence's verb */
+int inter_main_object; /* Vocab # of sentence's #1 object */
+int inter_second_object; /* Vocab # of sentence's #2 object */
+int inter_prep; /* Prep # of sentence's preposition */
+
+int inter_main_syntax; /* Syntax # of sentence's #1 object */
+int inter_second_syntax; /* Syntax # of sentence's #2 object */
+
+byte inter_verb_type; /* Grammatical verb form */
+byte inter_prep_type; /* Grammatical preposition type */
+
+int inter_command_source; /* Stroke type for verb */
+int inter_main_object_source; /* Stroke type for object #1 */
+int inter_second_object_source; /* Stroke type for object #2 */
+
+int inter_words[3]; /* Interface vocabulary words */
+
+int inter_point_established; /* Interface clicked point has been established */
+int inter_point_x; /* Clicked point in interface */
+int inter_point_y;
+
+int inter_recent_command; /* Allows cancellation */
+int inter_recent_command_source;
+
+int inter_sentence_ready = false; /* Flag if a sentence ready to go */
+
+int inter_awaiting = AWAITING_COMMAND; /* Current awaiting status */
+
+int inter_report_hotspots = false; /* True = show hotspots even with no button pressed */
+
+int inter_force_rescan = false; /* Force mouse rescan even if didnt change */
+int inter_base_hotspots; /* Number of basic hotspots */
+
+int inter_no_segments_active = true;
+int inter_some_segments_active = false;
+
+int inter_spot_class;
+int inter_spot_index;
+int inter_spot_id;
+
+long inter_base_time; /* Timing marker for animation */
+
+int end_of_selection = false; /* We are on last pass of this stroke */
+
+byte spot_base[STROKE_MAX]; /* Hotspot list base markers (by stroke type) */
+
+
+int scrollbar_active = 0;
+int scrollbar_elevator = 0;
+int scrollbar_old_active = -1;
+int scrollbar_old_elevator = -1;
+
+int scrollbar_stroke_type = 0;
+int scrollbar_quickly = false;
+long scrollbar_base_timing;
+
+int inter_object_id;
+char inter_object_buf[20];
+void (*inter_object_routine)() = NULL;
+
+int paul_object_showing = -1;
+
+#define OUAF_OBJECT_X 140
+#define OUAF_OBJECT_Y 5
+
+
+void inter_spin_object(int object_id);
+void inter_turn_off_object(void);
+
+
+/*
+/* inter_set_colors()
+/*
+/* Picks out font colors based on the current mode.
+*/
+static void inter_set_colors(int color_code) {
+ switch (color_code) {
+ case NORMAL:
+ font_set_colors(-1, 4, 4, 0);
+ break;
+ case LEFT_SELECT:
+ font_set_colors(-1, 5, 5, 0);
+ break;
+ case RIGHT_SELECT:
+ font_set_colors(-1, 6, 6, 0);
+ break;
+ }
+}
+
+/*
+/* inter_get_spot()
+/*
+/* Returns hot spot coordinates for a particular stroke class and
+/* spot #.
+*/
+static int inter_get_spot(int class_, int id, int *x1, int *y1, int *xs, int *ys) {
+ int row, col;
+ int base_x, base_y, delta_x;
+ int valid_flag;
+
+ valid_flag = false;
+
+ switch (class_) {
+
+ case STROKE_COMMAND:
+ row = id % inter_columns;
+ col = id / inter_columns;
+ base_x = command_base_x;
+ base_y = command_base_y;
+ delta_x = command_delta_x;
+ break;
+
+ case STROKE_INVEN:
+ if ((id < first_inven) || (id >= (first_inven + inter_columns))) {
+ goto done;
+ }
+ row = id - first_inven;
+ col = 0;
+ base_x = inven_base_x;
+ base_y = inven_base_y;
+ delta_x = inven_delta_x;
+ break;
+
+ case STROKE_DIALOG:
+ row = id;
+ col = 0;
+ base_x = command_base_x;
+ base_y = command_base_y;
+ delta_x = dialog_delta_x;
+ break;
+
+ case STROKE_SCROLL:
+ row = 0;
+ col = 0;
+ base_x = inter_scroll_x1;
+ base_y = 0;
+ delta_x = (inter_scroll_x2 - inter_scroll_x1) + 1;
+ if (id == SCROLL_THUMB) {
+ base_x += 2;
+ }
+ break;
+
+ case STROKE_ACTION:
+ default:
+ row = id;
+ col = 0;
+ base_x = action_base_x;
+ base_y = action_base_y;
+ delta_x = action_delta_x;
+ break;
+ }
+
+ if (col > 0) {
+ *x1 = base_x + (col * delta_x);
+ } else {
+ *x1 = base_x;
+ }
+ *xs = delta_x;
+
+ *y1 = base_y + (row * inter_delta_y);
+ *ys = inter_delta_y;
+
+ if (class_ == STROKE_SCROLL) {
+ switch (id) {
+ case SCROLL_UP:
+ *y1 = inter_up_y1;
+ *ys = (inter_up_y2 - inter_up_y1) + 1;
+ break;
+
+ case SCROLL_DOWN:
+ *y1 = inter_down_y1;
+ *ys = (inter_down_y2 - inter_down_y1) + 1;
+ break;
+
+ case SCROLL_ELEVATOR:
+ *y1 = inter_elevator_y1;
+ *ys = (inter_elevator_y2 - inter_elevator_y1) + 1;
+ break;
+
+ case SCROLL_THUMB:
+ *y1 = inter_thumb_y1 + scrollbar_elevator;
+ *ys = 1;
+ break;
+ }
+ }
+
+ valid_flag = true;
+
+done:
+ return(valid_flag);
+}
+
+
+/*
+/* inter_show_word()
+/*
+/* Writes vocabulary word for the particular class_ & id # to the
+/* interface work buffer.
+*/
+static void inter_show_word(int class_, int id) {
+ int x, y, junk;
+ int word_id = 0;
+ char temp_buf[80];
+ int paul_id;
+ int write_it = true;
+
+ if (!inter_get_spot(class_, id, &x, &y, &junk, &junk)) {
+ goto done;
+ }
+
+ switch (class_) {
+ case STROKE_COMMAND:
+ word_id = command[id].id;
+ if (id == left_command) {
+ inter_set_colors(LEFT_SELECT);
+ } else if (id == right_command) {
+ inter_set_colors(RIGHT_SELECT);
+ } else {
+ inter_set_colors(NORMAL);
+ }
+ break;
+
+ case STROKE_INVEN:
+ word_id = object[inven[id]].vocab_id;
+ if (id == left_inven) {
+ inter_set_colors(LEFT_SELECT);
+ } else if (id == active_inven) {
+ inter_set_colors(RIGHT_SELECT);
+ } else {
+ inter_set_colors(NORMAL);
+ }
+ break;
+
+ case STROKE_DIALOG:
+ temp_buf[0] = 0;
+ if (inter_dialog_strings[id] != NULL) {
+ Common::strcpy_s(temp_buf, inter_dialog_strings[id]);
+ }
+ if (id == left_command) {
+ inter_set_colors(LEFT_SELECT);
+ } else {
+ inter_set_colors(NORMAL);
+ }
+ goto write;
+ break;
+
+ case STROKE_SCROLL:
+ switch (id) {
+ case SCROLL_UP:
+ Common::strcpy_s(temp_buf, "a");
+ break;
+
+ case SCROLL_DOWN:
+ Common::strcpy_s(temp_buf, "b");
+ break;
+
+ case SCROLL_THUMB:
+ Common::strcpy_s(temp_buf, "c");
+ break;
+
+ case SCROLL_ELEVATOR:
+ Common::strcpy_s(temp_buf, "d");
+ break;
+ }
+ if ((id == SCROLL_THUMB) && (scrollbar_active != SCROLL_ELEVATOR)) {
+ inter_set_colors(NORMAL);
+ } else {
+ inter_set_colors(LEFT_SELECT);
+ }
+ font_write(font_misc, &scr_inter, temp_buf, x, y, 0);
+ goto done;
+ break;
+
+ case STROKE_ACTION:
+ default:
+
+ paul_id = object[inven[active_inven]].vocab_id;
+ paul_id = object_named(paul_id);
+
+ if (paul_id == 8 && !global[86]) { /* pid doll / global [heal_verbs_visible] */
+ if (id > 0) write_it = false; /* id == second verb, or == third verb */
+ }
+
+ word_id = object[inven[active_inven]].verb[id].id;
+ if (id == left_action) {
+ inter_set_colors(LEFT_SELECT);
+ } else if (id == right_action) {
+ inter_set_colors(RIGHT_SELECT);
+ } else {
+ inter_set_colors(NORMAL);
+ }
+ break;
+
+ }
+
+ Common::strcpy_s(temp_buf, vocab_string(word_id));
+ temp_buf[0] = (char)toupper((int)temp_buf[0]);
+
+write:
+
+ /* if (class_ == STROKE_INVEN) */
+
+ if (class_ == STROKE_COMMAND) {
+ switch (word_id) {
+ case 3: x += 10; break; /* look */
+ case 9: x += 12; break; /* give */
+ case 4: x += 10; break; /* take */
+
+ case 8: x += 4; break; /* talk to */
+ case 5: x += 10; break; /* push */
+ case 10: x += 13; break; /* pull */
+
+ case 7: x += 12; break; /* put */
+ case 6: x += 10; break; /* open */
+ case 11: x += 9; break; /* close */
+ }
+ }
+
+ if (write_it) font_write(font_inter, &scr_inter, temp_buf, x, y, 0);
+
+done:
+ ;
+}
+
+
+static void inter_show_scrollbar(void) {
+ if (scrollbar_active > 0) {
+ inter_show_word(STROKE_SCROLL, scrollbar_active);
+ }
+
+ inter_show_word(STROKE_SCROLL, SCROLL_THUMB);
+}
+
+
+
+/*
+/* inter_show_all_inven()
+/*
+/* Writes the current inventory list to the interface work buffer.
+*/
+static void inter_show_all_inven(void) {
+ int count;
+
+ for (count = first_inven; (count < (first_inven + inter_columns)) && (count < inven_num_objects); count++) {
+ inter_show_word(STROKE_INVEN, count);
+ }
+}
+
+
+/*
+/* inter_show_all_actions()
+/*
+/* Writes the current list of object-specific verbs to the interface
+/* work buffer.
+*/
+static void inter_show_all_actions(void) {
+ int count;
+ int id;
+
+ if (active_inven >= 0) {
+ for (count = 0; count < (int)object[inven[active_inven]].num_verbs; count++) {
+ id = object[inven[active_inven]].vocab_id;
+ id = object_named(id);
+ /* id = object[inven[active_inven]].verb[count].count; */
+ if (id == 8) { /* pid doll */
+ if (global[86]) { /* heal_verbs_visible */
+ inter_show_word(STROKE_ACTION, count);
+ } else if (count == 0) {
+ inter_show_word(STROKE_ACTION, count);
+ }
+
+ } else {
+ inter_show_word(STROKE_ACTION, count);
+ }
+ }
+ }
+}
+
+/*
+/* inter_show_all_dialog()
+*/
+static void inter_show_all_dialog(void) {
+ int count;
+
+ for (count = 0; count < inter_columns; count++) {
+ if (inter_dialog_strings[count] != NULL) {
+ inter_show_word(STROKE_DIALOG, count);
+ }
+ }
+}
+
+
+/*
+/* inter_prepare_background()
+/*
+/* Writes all relevant words to the interface work buffer.
+*/
+void inter_prepare_background(void) {
+ int count;
+
+ inter_auxiliary_click = false;
+
+ if (inter_input_mode == INTER_BUILDING_SENTENCES) {
+
+ for (count = 0; count < INTER_COMMANDS; count++) {
+ inter_show_word(STROKE_COMMAND, count);
+ }
+
+ inter_show_all_inven();
+ inter_show_all_actions();
+ inter_show_scrollbar();
+
+ } else if (inter_input_mode == INTER_CONVERSATION) {
+
+ inter_show_all_dialog();
+
+ }
+}
+
+
+static void inter_refresh(void) {
+ /*
+ int count;
+ for (count = 0; count < (int)image_inter_marker; count++) {
+ if (image_inter_list[count].segment_id == INTER_SPINNING_OBJECT) {
+ image_inter_list[count].flags = IMAGE_REFRESH + IMAGE_UPDATE_ONLY;
+ }
+ }
+ */
+ image_inter_marker = 0;
+ matte_refresh_inter();
+
+ matte_inter_frame(false, false);
+
+ inter_prepare_background();
+}
+
+
+
+void inter_reset_dialog(void) {
+ int count;
+
+ for (count = 0; count < inter_columns; count++) {
+ inter_dialog_strings[count] = NULL;
+ inter_dialog_results[count] = -1;
+ }
+}
+
+
+int inter_add_dialog(char *string, int result) {
+ int count, id;
+ char *mark;
+ char *mark2;
+
+ do { /* Double hyphens to dashes */
+ mark = strstr(string, "--");
+ if (mark != NULL) {
+ *mark = '{';
+ mark++;
+ mark2 = mark + 1;
+ Common::strcpy_s(mark, 65536, mark2);
+ }
+ } while (mark != NULL);
+
+ id = -1;
+ for (count = 0; (id < 0) && (count < inter_columns); count++) {
+ if (inter_dialog_strings[count] == NULL) {
+ id = count;
+ }
+ }
+
+ if (id >= 0) {
+ inter_dialog_strings[id] = string;
+ inter_dialog_results[id] = result;
+ }
+
+ return (id);
+}
+
+
+
+/*
+/* inter_update()
+/*
+/* Updates the specified region of the interface on the live screen.
+*/
+static void inter_update(int x1, int y1, int xs, int ys) {
+ int refresh_flag;
+ int y1a;
+
+ mouse_set_work_buffer(scr_inter.data, scr_inter.x);
+ mouse_set_view_port_loc(0, inter_viewing_at_y, video_x - 1, inter_viewing_at_y + scr_inter.y - 1);
+ mouse_set_view_port(0, 0);
+
+ mouse_freeze();
+ refresh_flag = mouse_refresh_view_port();
+
+ y1a = y1 + inter_base_y;
+
+ video_update(&scr_inter, x1, y1,
+ x1 + inter_base_x, y1a,
+ xs, ys);
+
+#ifdef sixteen_colors
+ if (video_mode == ega_mode) {
+ video_flush_ega(y1a, (y1a + ys - 1));
+ }
+#endif
+
+ if (refresh_flag) mouse_refresh_done();
+ mouse_thaw();
+}
+
+
+static void inter_image(int x1, int y1, int xs, int ys) {
+ if (image_inter_marker < IMAGE_INTER_LIST_SIZE) {
+ image_inter_list[image_inter_marker].flags = IMAGE_OVERPRINT;
+ image_inter_list[image_inter_marker].segment_id = INTER_TEXT_UPDATE;
+ image_inter_list[image_inter_marker].x = x1;
+ image_inter_list[image_inter_marker].y = (byte)y1;
+ image_inter_list[image_inter_marker].sprite_id = (byte)xs;
+ image_inter_list[image_inter_marker].series_id = (byte)ys;
+ image_inter_marker++;
+ }
+#ifndef disable_error_check
+ else {
+ error_report(ERROR_IMAGE_INTER_LIST_FULL, WARNING, MODULE_INTER, IMAGE_INTER_LIST_SIZE, 1);
+ }
+#endif
+}
+
+
+static void inter_scrollbar_refresh(void) {
+ int x1, y1, xs, ys;
+
+ x1 = inter_scroll_x1;
+ y1 = inter_up_y1;
+ xs = (inter_scroll_x2 - inter_scroll_x1) + 1;
+ ys = (inter_down_y2 - inter_up_y1) + 1;
+
+ inter_image(x1, y1, xs, ys);
+
+ matte_inter_frame(false, false);
+
+ inter_show_scrollbar();
+
+ inter_update(x1, y1, xs, ys);
+}
+
+
+/*
+/* inter_set_active_word()
+/*
+/* Sets an active word of the specific class_ to the "new" value.
+/* "old" is a pointer to the main control variable for that value,
+/* which also contains the old value of that variable. The old
+/* word is "turned off" automatically.
+*/
+static void inter_set_active_word(int class_, int *old, int new_) {
+ int x1, y1, xs, ys;
+ int temp;
+
+ if ((class_ == STROKE_INVEN) && first_inven_changed) {
+ *old = new_;
+ x1 = inven_base_x;
+ y1 = inven_base_y;
+ xs = inven_delta_x;
+ ys = (inter_delta_y * inter_columns);
+
+ inter_image(x1, y1, xs, ys);
+
+ matte_inter_frame(false, false);
+
+ inter_show_all_inven();
+ inter_update(x1, y1, xs, ys);
+
+ first_inven_changed = false;
+
+ if (inven_num_objects <= 1) {
+ scrollbar_elevator = 0;
+ } else {
+ scrollbar_elevator = (first_inven * inter_thumb_range) / (inven_num_objects - 1);
+ scrollbar_elevator = MIN(scrollbar_elevator, inter_thumb_range - 1);
+ }
+ } else {
+ temp = *old;
+ *old = new_;
+
+ if (temp >= 0) {
+ inter_show_word(class_, temp);
+ if (inter_get_spot(class_, temp, &x1, &y1, &xs, &ys)) {
+ inter_update(x1, y1, xs, ys);
+ }
+ }
+
+ if (new_ >= 0) {
+ inter_show_word(class_, new_);
+ if (inter_get_spot(class_, new_, &x1, &y1, &xs, &ys)) {
+ inter_update(x1, y1, xs, ys);
+ }
+ }
+ }
+}
+
+
+
+/*
+/* inter_set_active_inven()
+/*
+/* Picks a new active object from the inventory list. This involves
+/* changing the list of object-specific verbs.
+*/
+void inter_set_active_inven(int new_active) {
+ int new_verbs, old_verbs, max_verbs;
+ int x1, y1, xs, ys;
+
+ if ((new_active != active_inven) || first_inven_changed) {
+
+ if ((kernel_mode == KERNEL_ACTIVE_CODE) && (inter_input_mode == INTER_BUILDING_SENTENCES)) {
+ if (active_inven >= 0) {
+ old_verbs = object[inven[active_inven]].num_verbs;
+ } else {
+ old_verbs = 0;
+ }
+
+ if (new_active >= 0) {
+ new_verbs = object[inven[new_active]].num_verbs;
+ } else {
+ new_verbs = 0;
+ }
+
+ max_verbs = MAX(old_verbs, new_verbs);
+
+ inter_set_active_word(STROKE_INVEN, &active_inven, new_active);
+
+ left_action = -1;
+ right_action = -1;
+
+ if (max_verbs > 0) {
+ x1 = action_base_x;
+ y1 = action_base_y;
+ xs = action_delta_x;
+ ys = (inter_delta_y * max_verbs);
+
+
+
+ if (extra_display_object) {
+ if (image_inter_marker < IMAGE_INTER_LIST_SIZE) {
+ image_inter_list[image_inter_marker].flags = IMAGE_OVERPRINT;
+ image_inter_list[image_inter_marker].x = x1;
+ image_inter_list[image_inter_marker].y = (byte)y1;
+ image_inter_list[image_inter_marker].sprite_id = (byte)xs;
+ image_inter_list[image_inter_marker].series_id = (byte)ys;
+ image_inter_marker++;
+ }
+#ifndef disable_error_check
+ else {
+ error_report(ERROR_IMAGE_INTER_LIST_FULL, WARNING, MODULE_INTER, IMAGE_INTER_LIST_SIZE, 2);
+ }
+#endif
+
+ matte_inter_frame(false, false);
+
+ inter_show_all_actions();
+ inter_update(x1, y1, xs, ys);
+ }
+ }
+ }
+ }
+
+
+
+ if (new_active != -1) {
+ if (extra_display_object) {
+ inter_spin_object(inven[new_active]);
+ mcga_setpal_range(&master_palette, 7, 1);
+ mcga_setpal_range(&master_palette, 246, 2);
+ }
+ } else {
+ inter_turn_off_object();
+ }
+}
+
+
+static void inter_purge_inven_stroke(void) {
+ left_inven = -1;
+ mouse_init_cycle();
+ stroke_type = STROKE_NONE;
+}
+
+
+/*
+/* inter_give_to_player ()
+/*
+/* Adds the specified object to the player's inventory.
+*/
+void inter_give_to_player(int this_) {
+ if (inven_num_objects >= INVEN_MAX_OBJECTS) {
+ error_report(ERROR_PLAYER_INVENTORY_FULL, ERROR, MODULE_INTER, this_, INVEN_MAX_OBJECTS);
+ }
+
+ if (player_has(this_)) goto done;
+
+ inven[inven_num_objects] = this_;
+
+ /* if (!inven_num_objects) { */
+
+ active_inven = inven_num_objects;
+
+ /* } */
+
+ first_inven = MAX(0, first_inven);
+
+ if (first_inven > inven_num_objects) first_inven = inven_num_objects;
+
+ if ((first_inven + inter_columns) <= inven_num_objects) {
+ first_inven = inven_num_objects - (inter_columns - 1);
+ }
+
+ first_inven_changed = true;
+
+ object[this_].location = PLAYER;
+
+ inven_num_objects++;
+
+ /* Paul moved this from below */
+done:
+ ;
+
+ /* Paul here */
+ if ((kernel_mode == KERNEL_ACTIVE_CODE) &&
+ (inter_input_mode == INTER_BUILDING_SENTENCES ||
+ inter_input_mode == INTER_LIMITED_SENTENCES)) {
+ inter_purge_inven_stroke();
+ inter_set_active_inven(active_inven);
+ }
+}
+
+
+
+/*
+/* inter_take_from_player ()
+/*
+/* Moves the specified object from the player's inventory to
+/* the designated location.
+*/
+void inter_take_from_player(int this_, int where_to) {
+ int id = -1;
+ int count;
+ int active;
+ int was_negative;
+
+ for (count = 0; count < inven_num_objects; count++) {
+ if (inven[count] == this_) {
+ id = count;
+ }
+ }
+
+ if (id < 0) {
+ error_report(ERROR_NO_SUCH_OBJECT, WARNING, MODULE_INTER, id, inven_num_objects);
+ } else {
+ active = active_inven;
+ was_negative = (active < 0);
+ if ((kernel_mode == KERNEL_ACTIVE_CODE) &&
+ (inter_input_mode == INTER_BUILDING_SENTENCES)) {
+ inter_set_active_inven(-1);
+ }
+ for (count = id; count < inven_num_objects - 1; count++) {
+ inven[count] = inven[count + 1];
+ }
+ inven_num_objects--;
+ if (!was_negative) {
+ if (active >= id) active--;
+ if ((active < 0) && (inven_num_objects > 0)) active = 0;
+ }
+ if (first_inven >= id) first_inven = MAX(0, first_inven - 1);
+ first_inven_changed = true;
+ object[this_].location = where_to;
+ if ((kernel_mode == KERNEL_ACTIVE_CODE) && (inter_input_mode == INTER_BUILDING_SENTENCES)) {
+ inter_purge_inven_stroke();
+ inter_set_active_inven(active);
+ } else {
+ active_inven = active;
+ if (active_inven != -1) {
+ inter_spin_object(inven[active_inven]);
+ mcga_setpal_range(&master_palette, 7, 1);
+ mcga_setpal_range(&master_palette, 246, 2);
+ } else {
+ inter_turn_off_object();
+ }
+ }
+ }
+}
+
+
+/*
+/* inter_move_object()
+/*
+/* Moves an object to a new location, taking into account any
+/* player_inventory problems.
+*/
+void inter_move_object(int object_id, int location) {
+
+ if (object_id == paul_object_showing &&
+ location == 2) goto done;
+
+ if (object[object_id].location == PLAYER) {
+ inter_take_from_player(object_id, NOWHERE);
+ }
+ if (location == PLAYER) {
+ inter_give_to_player(object_id);
+ } else {
+ object[object_id].location = location;
+ }
+
+ /* extra_blank_knothole(); */
+
+done:
+ ;
+
+ extra_display_object = false;
+}
+
+
+
+/*
+/* inter_spot_correct()
+/*
+/* Takes a set of hotspot coordinates that is interface window relative
+/* and converts it to absolute screen coordinates.
+*/
+static void inter_spot_correct(int *x1, int *y1, int *x2, int *y2, int xs, int ys) {
+ *x1 += inter_base_x;
+ *x2 = *x1 + xs - 1;
+ *y1 += inter_base_y;
+ *y2 = *y1 + ys - 1;
+}
+
+
+/*
+/* inter_setup_hotspots()
+/*
+/* Sets up the hotspot list for the interface module. Hotspots only
+/* need to be set up once for each room.
+*/
+void inter_setup_hotspots(void) {
+ int count;
+ int x1, y1, xs, ys;
+ int x2, y2;
+
+ numspots = 0;
+
+ if (inter_input_mode == INTER_BUILDING_SENTENCES) {
+
+ spot_base[STROKE_SCROLL - 1] = (byte)(numspots + 1);
+ for (count = SCROLL_UP; count <= SCROLL_ELEVATOR; count++) {
+ inter_get_spot(STROKE_SCROLL, count, &x1, &y1, &xs, &ys);
+ inter_spot_correct(&x1, &y1, &x2, &y2, xs, ys);
+ hspot_add(x1, y1, x2, y2, STROKE_SCROLL, count, ABSOLUTE_MODE);
+ }
+
+ spot_base[STROKE_COMMAND - 1] = (byte)(numspots + 1);
+ for (count = 0; count < INTER_COMMANDS; count++) {
+ inter_get_spot(STROKE_COMMAND, count, &x1, &y1, &xs, &ys);
+ inter_spot_correct(&x1, &y1, &x2, &y2, xs, ys);
+ hspot_add(x1, y1, x2, y2, STROKE_COMMAND, count, ABSOLUTE_MODE);
+ }
+
+ spot_base[STROKE_INVEN - 1] = (byte)(numspots + 1);
+ for (count = 0; count < inter_columns; count++) {
+ inter_get_spot(STROKE_INVEN, count + first_inven, &x1, &y1, &xs, &ys);
+ inter_spot_correct(&x1, &y1, &x2, &y2, xs, ys);
+ hspot_add(x1, y1, x2, y2, STROKE_INVEN, count, ABSOLUTE_MODE);
+ }
+
+ spot_base[STROKE_ACTION - 1] = (byte)(numspots + 1);
+ for (count = 0; count < inter_columns; count++) {
+ inter_get_spot(STROKE_ACTION, count, &x1, &y1, &xs, &ys);
+ inter_spot_correct(&x1, &y1, &x2, &y2, xs, ys);
+ hspot_add(x1, y1, x2, y2, STROKE_ACTION, count, ABSOLUTE_MODE);
+ }
+
+ spot_base[STROKE_SPECIAL_INVEN - 1] = (byte)(numspots + 1);
+ x1 = inter_base_x + inter_object_base_x;
+ y1 = inter_base_y + inter_object_base_y;
+ x2 = x1 + inter_object_size_x - 1;
+ y2 = y1 + inter_object_size_y - 1;
+ hspot_add(x1, y1, x2, y2, STROKE_SPECIAL_INVEN, 0, ABSOLUTE_MODE);
+ }
+
+ if ((inter_input_mode == INTER_BUILDING_SENTENCES) ||
+ (inter_input_mode == INTER_LIMITED_SENTENCES)) {
+ spot_base[STROKE_INTERFACE - 1] = (byte)(numspots + 1);
+ for (count = room_num_spots - 1; count >= 0; count--) {
+ hspot_add(room_spots[count].ul_x, room_spots[count].ul_y,
+ room_spots[count].lr_x, room_spots[count].lr_y,
+ STROKE_INTERFACE, count, RELATIVE_MODE);
+ if (!room_spots[count].active) spot[numspots].active = false;
+ }
+ }
+
+
+ if (inter_input_mode == INTER_CONVERSATION) {
+ spot_base[STROKE_DIALOG - 1] = (byte)(numspots + 1);
+ for (count = 0; count < inter_columns; count++) {
+ inter_get_spot(STROKE_DIALOG, count, &x1, &y1, &xs, &ys);
+ inter_spot_correct(&x1, &y1, &x2, &y2, xs, ys);
+ hspot_add(x1, y1, x2, y2, STROKE_DIALOG, count, ABSOLUTE_MODE);
+ }
+ }
+
+ inter_base_hotspots = numspots;
+}
+
+
+/*
+/* inter_drag_check()
+/*
+/* Handles up/down "dragging" for inventory list.
+*/
+static void inter_drag_check(void) {
+ long timing_level;
+ long current_time;
+
+ if (mouse_any_stroke && ((inter_mouse_y <= (inter_base_y + inven_base_y)) || (inter_mouse_y == 199))) {
+ timing_level = (long)((scroll_quickly) ? MOUSE_TIMING_TWO : MOUSE_TIMING_ONE);
+ current_time = timer_read_dos();
+ scroll_active = true;
+ if ((current_time - scroll_base_time) >= timing_level) {
+ scroll_base_time = current_time;
+ scroll_quickly = true;
+ if (inter_mouse_y == (video_y - 1)) {
+ if (first_inven < (inven_num_objects - 1)) {
+ first_inven++;
+ first_inven_changed = true;
+ }
+ } else {
+ if (first_inven > 0) {
+ first_inven--;
+ first_inven_changed = true;
+ }
+ }
+ }
+ } else {
+ scroll_active = false;
+ scroll_quickly = false;
+ }
+}
+
+/*
+/* inter_select_word()
+/*
+/* Determines which word is being picked off the screen, and makes
+/* it active.
+*/
+static void inter_select_word(void) {
+ int x1, y1, x2, y2;
+ int junk;
+ int max_x, max_y;
+ int count, new_;
+ int quantity;
+ int mode;
+ int limit = 0;
+ int strict, delta;
+ int tight_boxes;
+ int difference = 0;
+ int *selection;
+ int base_spot, this_spot;
+ int paul_id;
+
+ switch (stroke_type) {
+ case STROKE_COMMAND:
+ quantity = INTER_COMMANDS;
+ limit = INTER_COMMANDS - 1;
+ strict = inter_columns;
+ delta = 0;
+ selection = mouse_button ? &right_command : &left_command;
+ if (mouse_button && (right_action >= 0)) {
+ inter_set_active_word(STROKE_ACTION, &right_action, -1);
+ }
+ /* tight_boxes = (end_of_selection && !mouse_button); */
+ tight_boxes = true;
+ break;
+
+ case STROKE_INVEN:
+ inter_drag_check();
+ quantity = MIN(inter_columns, (inven_num_objects - first_inven));
+ limit = inven_num_objects - 1;
+ strict = 0;
+ delta = first_inven;
+ selection = &left_inven;
+ /* tight_boxes = (end_of_selection && ((!mouse_any_stroke) || !(inter_awaiting == AWAITING_COMMAND))); */
+ tight_boxes = true;
+ break;
+
+ case STROKE_ACTION:
+ if (active_inven >= 0) {
+ paul_id = object[inven[active_inven]].vocab_id;
+ paul_id = object_named(paul_id);
+
+ if (paul_id == 8 && !global[86]) { /* pid doll / global [heal_verbs_visible] */
+ quantity = 1;
+ } else {
+ quantity = object[inven[active_inven]].num_verbs;
+ }
+
+ limit = quantity - 1;
+
+ } else {
+ quantity = 0;
+ }
+ strict = 0;
+ delta = 0;
+ selection = mouse_button ? &right_action : &left_action;
+ if (mouse_button && (right_command >= 0)) {
+ inter_set_active_word(STROKE_COMMAND, &right_command, -1);
+ }
+ /* tight_boxes = end_of_selection && !mouse_button; */
+ tight_boxes = true;
+ break;
+
+ case STROKE_SPECIAL_INVEN:
+ quantity = 1;
+ limit = inven_num_objects - 1;
+ strict = 0;
+ delta = active_inven;
+ selection = &junk;
+ tight_boxes = true;
+ break;
+
+ case STROKE_DIALOG:
+ quantity = 0;
+ for (count = 0; count < inter_columns; count++) {
+ if (inter_dialog_strings[count] != NULL) {
+ quantity++;
+ }
+ }
+ limit = quantity - 1;
+ strict = 0;
+ delta = 0;
+ selection = &left_command;
+ tight_boxes = true;
+ break;
+
+ case STROKE_INTERFACE:
+ default:
+ difference = (numspots - inter_base_hotspots);
+ quantity = room_num_spots + difference;
+ limit = quantity - 1;
+ strict = 0;
+ delta = 0;
+ selection = &junk;
+ tight_boxes = true;
+ break;
+ }
+
+ new_ = -1;
+ max_y = 0;
+ max_x = 0;
+ base_spot = spot_base[stroke_type - 1];
+
+
+ for (count = 0; (count < quantity) && (new_ < 0); count++) {
+ if (stroke_type == STROKE_INTERFACE) {
+ this_spot = base_spot + (quantity - (count + 1));
+ /*
+ if (count >= difference) {
+ this_spot = base_spot + (room_num_spots - ((count - difference) + 1));
+ } else {
+ this_spot = base_spot + room_num_spots + count;
+ }
+ */
+ } else {
+ this_spot = base_spot + count;
+ }
+ x1 = spot[this_spot].ul_x;
+ y1 = spot[this_spot].ul_y;
+ x2 = spot[this_spot].lr_x;
+ y2 = spot[this_spot].lr_y;
+ mode = spot[this_spot].video_mode;
+ max_y = MAX(max_y, y2);
+ max_x = MAX(max_x, x1);
+ if (spot[this_spot].active && (mode == inter_mouse_type)) {
+ if ((inter_mouse_y >= y1) && (inter_mouse_y <= y2)) {
+ if (tight_boxes) {
+ if (((inter_mouse_x) >= x1) && ((inter_mouse_x) <= x2)) {
+ new_ = this_spot - base_spot;
+ if (stroke_type == STROKE_INTERFACE) {
+ if (new_ < room_num_spots) {
+ new_ = room_num_spots - (new_ + 1);
+ }
+ }
+ }
+ } else {
+ if (strict) {
+ if (count < strict) {
+ if ((inter_mouse_x) <= x2) {
+ new_ = count;
+ }
+ } else {
+ if ((inter_mouse_x) >= x1) {
+ new_ = count;
+ }
+ }
+ } else {
+ new_ = count;
+ }
+ }
+ }
+ }
+ }
+
+ if ((new_ < 0) && (quantity > 0) && (!tight_boxes)) {
+ if (inter_mouse_y > max_y) {
+ new_ = quantity - 1;
+ } else {
+ new_ = 0;
+ if (strict && ((inter_mouse_x) >= max_x)) {
+ new_ = strict;
+ }
+ }
+ }
+
+ if (new_ >= 0) {
+ new_ = MIN((new_ + delta), limit);
+ }
+
+ picked_word = new_;
+
+ if (((stroke_type == STROKE_INVEN) || (stroke_type == STROKE_SPECIAL_INVEN)) && (inter_awaiting == AWAITING_COMMAND) && (new_ >= 0)) {
+ if (end_of_selection && (!mouse_stop_stroke || !inter_report_hotspots)) new_ = -1;
+ }
+
+ if (end_of_selection && !mouse_button && (!mouse_stop_stroke || !inter_report_hotspots)) {
+ new_ = -1;
+ }
+
+ if ((stroke_type != STROKE_INTERFACE) && (stroke_type != STROKE_SPECIAL_INVEN)) {
+ inter_set_active_word(stroke_type, selection, new_);
+ }
+}
+
+static void inter_scroll_bar(void) {
+ int junk;
+ int y, new_first_inven;
+ long now_time;
+ long timing_level;
+
+ if (inter_input_mode != INTER_BUILDING_SENTENCES) goto done;
+
+ scrollbar_active = 0;
+
+ if ((inter_spot_class == STROKE_SCROLL) ||
+ ((scrollbar_old_active == SCROLL_ELEVATOR) && mouse_stroke_going)) {
+ if (mouse_stroke_going || inter_report_hotspots) {
+
+ if (mouse_start_stroke || (inter_report_hotspots && !mouse_stroke_going)) {
+ if (inter_spot_class == STROKE_SCROLL) {
+ scrollbar_stroke_type = inter_spot_id;
+ }
+ }
+
+ if ((scrollbar_stroke_type == inter_spot_id) ||
+ (scrollbar_old_active == SCROLL_ELEVATOR)) {
+ scrollbar_active = scrollbar_stroke_type;
+
+ now_time = timer_read_dos();
+ timing_level = scrollbar_quickly ? MOUSE_TIMING_TWO : MOUSE_TIMING_ONE;
+
+ if (mouse_start_stroke || (mouse_stroke_going && (now_time > (scrollbar_base_timing + timing_level)))) {
+
+ scrollbar_quickly = !mouse_start_stroke;
+ scrollbar_base_timing = timer_read_dos();
+
+ switch (scrollbar_stroke_type) {
+ case SCROLL_UP:
+ if ((first_inven > 0) && inven_num_objects) {
+ first_inven--;
+ first_inven_changed = true;
+ }
+ break;
+
+ case SCROLL_DOWN:
+ if ((first_inven < (inven_num_objects - 1)) && inven_num_objects) {
+ first_inven++;
+ first_inven_changed = true;
+ }
+ break;
+
+ case SCROLL_ELEVATOR:
+ y = inter_mouse_y;
+ y -= inter_base_y;
+ y -= inter_thumb_y1;
+ y = MAX(0, y);
+ y = MIN(inter_thumb_range - 1, y);
+ new_first_inven = (y * inven_num_objects) / inter_thumb_range;
+ new_first_inven = MIN(inven_num_objects - 1, new_first_inven);
+ if (inven_num_objects) {
+ first_inven_changed = (new_first_inven != first_inven);
+ first_inven = new_first_inven;
+ }
+ break;
+ }
+
+ if (first_inven_changed) {
+ inter_set_active_word(STROKE_INVEN, &junk, 0);
+ }
+ }
+ }
+ }
+ }
+
+ if ((scrollbar_active != scrollbar_old_active) ||
+ (scrollbar_elevator != scrollbar_old_elevator)) {
+ inter_scrollbar_refresh();
+ }
+
+ scrollbar_old_active = scrollbar_active;
+ scrollbar_old_elevator = scrollbar_elevator;
+
+done:
+ ;
+}
+
+
+
+/*
+/* inter_init_sentence()
+/*
+/* Begins accepting a new sentence.
+*/
+void inter_init_sentence(void) {
+ inter_awaiting = AWAITING_COMMAND;
+
+ inter_command_source = STROKE_NONE;
+ inter_main_object_source = STROKE_NONE;
+ inter_second_object_source = STROKE_NONE;
+ inter_recent_command_source = STROKE_NONE;
+
+ inter_command = -1;
+ inter_main_object = -1;
+ inter_second_object = -1;
+ inter_recent_command = -1;
+ inter_prep = PREP_NONE;
+
+ inter_look_around = false;
+
+ inter_verb = -1;
+ inter_main_noun = -1;
+ inter_second_noun = -1;
+
+ inter_point_established = false;
+
+ inter_sentence[0] = 0;
+ inter_sentence_changed = true;
+}
+
+
+
+/*
+/* inter_add_word_to_sentence()
+/*
+/* Adds the text for a vocabulary word to the current sentence.
+*/
+static void inter_add_word_to_sentence(int vocab_id, int capitalize) {
+ int len;
+
+ len = strlen(inter_sentence);
+ Common::strcat_s(inter_sentence, vocab_string(vocab_id));
+
+ if (capitalize) {
+ inter_sentence[len] = (byte)toupper(inter_sentence[len]);
+ }
+
+ Common::strcat_s(inter_sentence, istring_space);
+}
+
+
+/*
+/* inter_compile_sentence()
+/*
+/* Puts together a string for the current sentence, based on the
+/* information currently available.
+*/
+static void inter_compile_sentence(void) {
+ int prep_special;
+ int verb;
+ int len;
+ char *mark;
+ ObjectPtr my_object;
+
+ prep_special = false;
+
+ inter_sentence[0] = 0;
+ inter_verb = -1;
+ inter_main_noun = -1;
+ inter_second_noun = -1;
+
+ if (inter_command_source == STROKE_DIALOG) {
+ if (inter_command >= 0) {
+ inter_verb = inter_dialog_results[inter_command];
+ if (inter_dialog_strings[inter_command] != NULL) {
+ Common::strcpy_s(inter_sentence, inter_dialog_strings[inter_command]);
+ }
+ }
+ goto done;
+ }
+
+ if (inter_look_around && (inter_command == 0)) {
+ Common::strcat_s(inter_sentence, istring_look_around);
+ goto done;
+ }
+
+ if ((inter_command_source == STROKE_ACTION) && (inter_command >= 0) &&
+ (inter_verb_type == VERB_THAT) && (inter_prep_type == PREP_NONE)) {
+
+
+ my_object = &object[inven[active_inven]];
+ inter_main_noun = my_object->vocab_id;
+ inter_main_syntax = my_object->syntax;
+ inter_verb = my_object->verb[inter_command].id;
+
+ Common::strcat_s(inter_sentence, istring_use);
+ inter_add_word_to_sentence(inter_main_noun, false);
+ Common::strcat_s(inter_sentence, istring_to);
+ inter_add_word_to_sentence(inter_verb, false);
+
+ } else {
+
+ if (inter_command >= 0) {
+ if (inter_command_source == STROKE_COMMAND) {
+ inter_verb = command[inter_command].id;
+
+ } else {
+ inter_verb = object[inven[active_inven]].verb[inter_command].id;
+ }
+
+ inter_add_word_to_sentence(inter_verb, true);
+ if (inter_verb == words_look) {
+ /* inter_prep = PREP_AT; */
+ Common::strcat_s(inter_sentence, istring_prep_names[PREP_AT]);
+ Common::strcat_s(inter_sentence, istring_space);
+ }
+ }
+
+ if ((inter_main_object >= 0) && (inter_command >= 0) && (inter_prep > 0) && (inter_verb_type == VERB_THAT)) {
+ prep_special = true;
+ Common::strcat_s(inter_sentence, istring_prep_names[inter_prep]);
+ Common::strcat_s(inter_sentence, istring_space);
+ }
+
+ if (inter_main_object >= 0) {
+ if (inter_command < 0) {
+ verb = (inter_main_object < room_num_spots) ?
+ room_spots[inter_main_object].verb :
+ kernel_dynamic_hot[kernel_dynamic_consecutive(inter_main_object - room_num_spots)].verb_id;
+ if (verb <= 0) {
+ inter_verb = words_walk_to;
+ Common::strcat_s(inter_sentence, istring_walk_to);
+ } else {
+ inter_verb = verb;
+ inter_add_word_to_sentence(inter_verb, true);
+ }
+ }
+ if ((inter_main_object_source == STROKE_INVEN) || (inter_main_object_source == STROKE_SPECIAL_INVEN)) {
+ my_object = &object[inven[inter_main_object]];
+ inter_main_noun = my_object->vocab_id;
+ inter_main_syntax = my_object->syntax;
+ } else {
+ inter_main_noun = (inter_main_object < room_num_spots) ?
+ room_spots[inter_main_object].vocab :
+ kernel_dynamic_hot[kernel_dynamic_consecutive(inter_main_object - room_num_spots)].vocab_id;
+
+ inter_main_syntax = (inter_main_object < room_num_spots) ?
+ room_spots[inter_main_object].syntax :
+ kernel_dynamic_hot[kernel_dynamic_consecutive(inter_main_object - room_num_spots)].syntax;
+
+ }
+ inter_add_word_to_sentence(inter_main_noun, false);
+ }
+ }
+
+ if (inter_second_object >= 0) {
+ if ((inter_second_object_source == STROKE_INVEN) || (inter_second_object_source == STROKE_SPECIAL_INVEN)) {
+ my_object = &object[inven[inter_second_object]];
+ inter_second_noun = my_object->vocab_id;
+ inter_second_syntax = my_object->syntax;
+ } else {
+ inter_second_noun = (inter_second_object < room_num_spots) ?
+ room_spots[inter_second_object].vocab :
+ kernel_dynamic_hot[kernel_dynamic_consecutive(inter_second_object - room_num_spots)].vocab_id;
+ inter_second_syntax = (inter_second_object < room_num_spots) ?
+ room_spots[inter_second_object].syntax :
+ kernel_dynamic_hot[kernel_dynamic_consecutive(inter_second_object - room_num_spots)].syntax;
+ }
+ }
+
+ if ((inter_main_object >= 0) && (inter_prep > 0) && (!prep_special)) {
+ if (inter_prep != PREP_RELATIONAL) {
+ Common::strcat_s(inter_sentence, istring_prep_names[inter_prep]);
+ Common::strcat_s(inter_sentence, istring_space);
+ } else {
+ if (inter_second_object >= 0) {
+ if ((inter_second_object_source == STROKE_INVEN) || (inter_second_object_source == STROKE_SPECIAL_INVEN)) {
+ inter_prep = object[inven[inter_second_object]].prep;
+ Common::strcat_s(inter_sentence, istring_prep_names[inter_prep]);
+ } else {
+ inter_prep = (inter_second_object < room_num_spots) ?
+ room_spots[inter_second_object].prep :
+ kernel_dynamic_hot[kernel_dynamic_consecutive(inter_second_object - room_num_spots)].prep;
+ Common::strcat_s(inter_sentence, istring_prep_names[inter_prep]);
+ }
+ Common::strcat_s(inter_sentence, istring_space);
+
+ if (!mouse_any_stroke) inter_prep = PREP_RELATIONAL;
+ }
+ }
+ }
+
+ if (inter_second_object >= 0) {
+ inter_add_word_to_sentence(inter_second_noun, false);
+ }
+
+ len = strlen(inter_sentence);
+ if (strlen(inter_sentence)) {
+ mark = &inter_sentence[len - 1];
+ if (*mark == ' ') *mark = 0;
+ }
+
+done:
+ inter_sentence_changed = true;
+}
+
+
+
+/*
+/* inter_analyze_stroke()
+/*
+/* Analyzes the potential effect of the current stroke on the sentence --
+/* w/ the proviso that the stroke is not yet finished.
+*/
+static void inter_analyze_stroke(void) {
+ if ((stroke_type == STROKE_COMMAND) || (stroke_type == STROKE_ACTION)) {
+ if ((inter_awaiting != AWAITING_COMMAND) && (picked_word >= 0)) {
+ if (!((stroke_type == inter_recent_command_source) && (picked_word == inter_recent_command) && ((inter_awaiting == AWAITING_THIS) || (stroke_type == STROKE_ACTION)))) {
+ inter_init_sentence();
+ } else {
+ inter_look_around = ((inter_command == 0) && (stroke_type == STROKE_COMMAND));
+ }
+ }
+ }
+
+ if (mouse_button && mouse_any_stroke) {
+ switch (stroke_type) {
+ case STROKE_COMMAND:
+ case STROKE_ACTION:
+ goto done;
+ break;
+
+ case STROKE_INVEN:
+ case STROKE_INTERFACE:
+ case STROKE_SPECIAL_INVEN:
+ if (inter_awaiting != AWAITING_THAT) {
+ if (right_command >= 0) {
+ inter_command_source = STROKE_COMMAND;
+ inter_command = right_command;
+ inter_verb_type = command[inter_command].verb_type;
+ inter_prep_type = command[inter_command].prep_type;
+ inter_awaiting = AWAITING_THIS;
+ } else if (right_action >= 0) {
+ inter_command_source = STROKE_ACTION;
+ inter_command = right_action;
+ inter_verb_type = object[inven[active_inven]].verb[right_action].verb_type;
+ inter_prep_type = object[inven[active_inven]].verb[right_action].prep_type;
+ inter_main_object_source = STROKE_INVEN;
+ inter_main_object = active_inven;
+ inter_prep = inter_prep_type;
+ if ((inter_verb_type == VERB_THIS) && (inter_prep_type == PREP_NONE)) {
+ inter_awaiting = AWAITING_RIGHT_MOUSE;
+ } else if ((inter_verb_type == VERB_THAT) && (inter_prep_type != PREP_NONE)) {
+ inter_awaiting = AWAITING_RIGHT_MOUSE;
+ } else {
+ inter_awaiting = AWAITING_THAT;
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ switch (inter_awaiting) {
+
+ case AWAITING_COMMAND:
+ inter_prep = PREP_NONE;
+ switch (stroke_type) {
+
+ case STROKE_COMMAND:
+ inter_command_source = STROKE_COMMAND;
+ inter_command = picked_word;
+ if (inter_command >= 0) {
+ inter_verb_type = command[inter_command].verb_type;
+ inter_prep_type = command[inter_command].prep_type;
+ }
+ break;
+
+ case STROKE_DIALOG:
+ inter_command_source = STROKE_DIALOG;
+ inter_command = picked_word;
+ break;
+
+ case STROKE_INVEN:
+ case STROKE_SPECIAL_INVEN:
+ break;
+
+ case STROKE_ACTION:
+ inter_command_source = STROKE_ACTION;
+ inter_command = picked_word;
+
+ if (inter_command >= 0) {
+ inter_verb_type = object[inven[active_inven]].verb[inter_command].verb_type;
+ inter_prep_type = object[inven[active_inven]].verb[inter_command].prep_type;
+ inter_main_object = active_inven;
+ inter_main_object_source = STROKE_INVEN;
+
+ if (inter_verb_type == VERB_THAT) {
+ inter_prep = inter_prep_type;
+ }
+ } else {
+ inter_main_object = -1;
+ inter_main_object_source = STROKE_NONE;
+ }
+ break;
+
+ case STROKE_INTERFACE:
+ inter_command = -1;
+ inter_command_source = STROKE_NONE;
+ inter_main_object_source = STROKE_INTERFACE;
+ inter_main_object = picked_word;
+ break;
+ }
+ break;
+
+ case AWAITING_THIS:
+ inter_prep = PREP_NONE;
+ switch (stroke_type) {
+ case STROKE_INTERFACE:
+ case STROKE_INVEN:
+ case STROKE_SPECIAL_INVEN:
+ inter_main_object_source = stroke_type;
+ inter_main_object = picked_word;
+ break;
+ }
+ break;
+
+ case AWAITING_THAT:
+ switch (stroke_type) {
+ case STROKE_INTERFACE:
+ case STROKE_INVEN:
+ case STROKE_SPECIAL_INVEN:
+ inter_second_object_source = stroke_type;
+ inter_second_object = picked_word;
+ break;
+ }
+ break;
+
+ case AWAITING_RIGHT_MOUSE:
+ break;
+ }
+
+done:
+ ;
+}
+
+
+/*
+/* inter_complete_stroke()
+/*
+/* Determines the final effect of a stroke on the sentence, after
+/* that stroke has been completed.
+*/
+static void inter_complete_stroke(void) {
+ int demand_abort;
+
+ demand_abort = false;
+
+ if ((stroke_type == STROKE_COMMAND) || (stroke_type == STROKE_ACTION)) {
+ if ((inter_awaiting != AWAITING_COMMAND) && (picked_word >= 0)) {
+ if ((stroke_type == inter_recent_command_source) && (picked_word == inter_recent_command) && ((inter_awaiting == AWAITING_THIS) || (stroke_type == STROKE_ACTION))) {
+ demand_abort = true;
+ inter_look_around = inter_sentence_ready = ((inter_command == 0) && (stroke_type == STROKE_COMMAND));
+ if (!inter_look_around) {
+ inter_init_sentence();
+ }
+ }
+ }
+ }
+
+ if (demand_abort) goto done;
+
+ if (mouse_button) {
+ switch (stroke_type) {
+ case STROKE_COMMAND:
+ case STROKE_ACTION:
+ goto done;
+ break;
+ }
+ }
+
+ switch (inter_awaiting) {
+
+ case AWAITING_COMMAND:
+ switch (stroke_type) {
+
+ case STROKE_COMMAND:
+ if (inter_command >= 0) {
+ if (inter_verb_type == VERB_ONLY) {
+ inter_sentence_ready = true;
+ } else {
+ inter_recent_command = inter_command;
+ inter_recent_command_source = inter_command_source;
+ inter_awaiting = AWAITING_THIS;
+ }
+ }
+ break;
+
+ case STROKE_DIALOG:
+ if (inter_command >= 0) {
+ inter_sentence_ready = true;
+ }
+ break;
+
+ case STROKE_SPECIAL_INVEN:
+ /* (Remove break to have clicking on spinning object reset inven list) */
+ break;
+
+ case STROKE_INVEN:
+ if (picked_word >= 0) {
+ inter_set_active_inven(picked_word);
+ }
+ break;
+
+ case STROKE_ACTION:
+ if (inter_command >= 0) {
+ if ((inter_verb_type == VERB_THIS) && (inter_prep_type == PREP_NONE)) {
+ inter_sentence_ready = true;
+ } else if ((inter_verb_type == VERB_THAT) && (inter_prep_type != PREP_NONE)) {
+ inter_prep = inter_prep_type;
+ inter_sentence_ready = true;
+ } else {
+ inter_awaiting = AWAITING_THAT;
+ inter_prep = inter_prep_type;
+ }
+ inter_recent_command = inter_command;
+ inter_recent_command_source = inter_command_source;
+ }
+ break;
+
+ case STROKE_INTERFACE:
+ inter_recent_command = -1;
+ inter_recent_command_source = STROKE_NONE;
+ if (mouse_y < display_y) {
+ inter_sentence_ready = true;
+
+ inter_point_x = mouse_x + picture_view_x;
+ inter_point_y = mouse_y + picture_view_y;
+ inter_point_established = true;
+ }
+ break;
+ }
+ break;
+
+ case AWAITING_THIS:
+ switch (stroke_type) {
+
+ case STROKE_INVEN:
+ case STROKE_INTERFACE:
+ case STROKE_SPECIAL_INVEN:
+ if (inter_main_object >= 0) {
+ if (inter_prep_type == PREP_NONE) {
+ inter_sentence_ready = true;
+ } else {
+ inter_prep = inter_prep_type;
+ inter_awaiting = AWAITING_THAT;
+ }
+ if (stroke_type == STROKE_INTERFACE) {
+ inter_point_x = mouse_x + picture_view_x;
+ inter_point_y = mouse_y + picture_view_y;
+ inter_point_established = true;
+ }
+ }
+ break;
+
+ }
+ break;
+
+ case AWAITING_THAT:
+ switch (stroke_type) {
+ case STROKE_INVEN:
+ case STROKE_INTERFACE:
+ case STROKE_SPECIAL_INVEN:
+ if (inter_second_object >= 0) {
+ inter_sentence_ready = true;
+ if ((stroke_type == STROKE_INTERFACE) && (!inter_point_established)) {
+ inter_point_x = mouse_x + picture_view_x;
+ inter_point_y = mouse_y + picture_view_y;
+ inter_point_established = true;
+ }
+ }
+ break;
+ }
+ break;
+
+ case AWAITING_RIGHT_MOUSE:
+ inter_sentence_ready = true;
+ break;
+ }
+
+done:
+ ;
+}
+
+
+
+/*
+/* inter_background_animation()
+/*
+/* Manages the background animation for the interface screen, by
+/* advancing segment counters and changing matteing lists when
+/* appropriate.
+*/
+static void inter_background_animation(void) {
+ int count, count2;
+ int temp;
+ int prob_check;
+ int image_scan;
+ int myprob;
+
+ if (inter_anim == NULL) goto done;
+
+ inter_no_segments_active = !inter_some_segments_active;
+ inter_some_segments_active = false;
+ for (count = 0; count < inter_anim->num_segments; count++) {
+ if (inter_anim->segment[count].counter < 0) {
+ if (inter_anim->segment[count].counter == -1) {
+ prob_check = imath_random(1, 30000);
+ myprob = inter_anim->segment[count].probability;
+ if (inter_anim->segment[count].probability > 30000) {
+ if (inter_no_segments_active) {
+ myprob -= 30000;
+ } else {
+ myprob = -1;
+ }
+ }
+ if (prob_check <= myprob) {
+ inter_anim->segment[count].counter = inter_anim->segment[count].first_image;
+ inter_some_segments_active = true;
+ }
+ } else {
+ inter_anim->segment[count].counter = inter_anim->segment[count].first_image;
+ inter_some_segments_active = true;
+ }
+ } else {
+ for (count2 = 0; count2 < AA_MAX_SPAWNED; count2++) {
+ if (inter_anim->segment[count].spawn_frame[count2] ==
+ (inter_anim->segment[count].counter - inter_anim->segment[count].first_image)) {
+ temp = inter_anim->segment[count].spawn[count2];
+ if (count >= temp) {
+ inter_anim->segment[temp].counter = inter_anim->segment[temp].first_image;
+ } else {
+ inter_anim->segment[temp].counter = -2;
+ }
+ inter_some_segments_active = true;
+ }
+ }
+ inter_anim->segment[count].counter++;
+ if (inter_anim->segment[count].counter > inter_anim->segment[count].last_image) {
+ inter_anim->segment[count].counter = -1;
+ } else {
+ inter_some_segments_active = true;
+ }
+ }
+ }
+
+ for (count = 0; count < inter_anim->num_segments; count++) {
+ image_scan = inter_anim->segment[count].counter;
+ if (image_scan >= 0) {
+ if (image_inter_marker < IMAGE_INTER_LIST_SIZE) {
+ image_inter_list[image_inter_marker] = inter_anim->image[image_scan];
+ image_inter_list[image_inter_marker].flags = IMAGE_UPDATE;
+ image_inter_marker++;
+ }
+#ifndef disable_error_check
+ else {
+ error_report(ERROR_IMAGE_INTER_LIST_FULL, WARNING, MODULE_INTER, IMAGE_INTER_LIST_SIZE, 3);
+ }
+#endif
+ }
+ }
+
+done:
+ ;
+}
+
+
+void inter_spinning_object(void) {
+ int count;
+
+ if ((inter_input_mode == INTER_CONVERSATION) ||
+ (inter_input_mode == INTER_LIMITED_SENTENCES)) goto done;
+
+ if (inter_object_series >= 0) {
+ inter_object_sprite++;
+ if (inter_object_sprite > series_list[inter_object_series]->num_sprites) inter_object_sprite = 1;
+
+ for (count = 0; count < (int)image_inter_marker; count++) {
+ if (image_inter_list[count].segment_id == INTER_SPINNING_OBJECT) {
+ image_inter_list[count].flags = IMAGE_FULLUPDATE;
+ }
+ }
+
+ if (image_inter_marker < IMAGE_INTER_LIST_SIZE) {
+ image_inter_list[image_inter_marker].flags = IMAGE_UPDATE;
+ image_inter_list[image_inter_marker].segment_id = INTER_SPINNING_OBJECT;
+ image_inter_list[image_inter_marker].sprite_id = (byte)inter_object_sprite;
+ image_inter_list[image_inter_marker].series_id = (byte)inter_object_series;
+ image_inter_list[image_inter_marker].x = inter_object_base_x;
+ image_inter_list[image_inter_marker].y = inter_object_base_y;
+ image_inter_marker++;
+ }
+#ifndef disable_error_check
+ else {
+ error_report(ERROR_IMAGE_INTER_LIST_FULL, WARNING, MODULE_INTER, IMAGE_INTER_LIST_SIZE, 3);
+ }
+#endif
+ }
+
+done:
+ ;
+}
+
+
+
+void inter_turn_off_object(void) {
+ if (inter_object_series >= 0) {
+ delete_sprite_in_interface(inter_object_series);
+ matte_deallocate_series(inter_object_series, false);
+ inter_base_time = timer_read();
+ inter_object_series = -1;
+ }
+
+ /* if last inventory object, copy section of interface */
+ /* over inventory object after removed from list (removed above) */
+ if (active_inven == -1) {
+ if (kernel_mode == KERNEL_ACTIVE_CODE) {
+ video_update(&scr_inter, OUAF_OBJECT_X, 0,
+ OUAF_OBJECT_X, 156,
+ 59, 44);
+ }
+ }
+
+
+ if (new_room == room_id) {
+ paul_object_showing = -1;
+ }
+
+ /* will wipe out other 4 sprites */
+ if (inter_input_mode == INTER_BUILDING_SENTENCES) inter_refresh();
+}
+
+
+int inter_allocate_objects(void) {
+ int error_flag = true;
+
+ if (!inter_spinning_objects) goto done;
+
+ inter_spinning_objects = false;
+
+ inter_objects_block_size = INTER_OBJECT_SPACE;
+
+ inter_objects_block = (byte *)mem_get_name(inter_objects_block_size, "$SPIN$");
+ if (inter_objects_block == NULL) goto done;
+
+ inter_spinning_objects = true;
+
+ error_flag = false;
+
+done:
+ return error_flag;
+}
+
+
+void inter_deallocate_objects(void) {
+ if (inter_objects_block != NULL) {
+ mem_free(inter_objects_block);
+ inter_objects_block = NULL;
+ }
+}
+
+
+void inter_screen_update(void) {
+ if (kernel_mode == KERNEL_ACTIVE_CODE) {
+ if (inter_input_mode == INTER_BUILDING_SENTENCES) {
+ matte_inter_frame(!kernel.fx, kernel.fx);
+ if (kernel.fx) {
+ inter_prepare_background();
+ }
+ }
+ }
+}
+
+
+static void inter_exec_function(void (*(target))()) {
+ target();
+}
+
+void inter_spin_object(int object_id) {
+ int error_flag = true;
+ char temp_buf[80];
+
+ inter_turn_off_object();
+
+ /* update to live screen chunk of interface that selected object */
+ /* is on (it has been deleted in list by now) */
+ if (kernel_mode == KERNEL_ACTIVE_CODE) {
+ video_update(&scr_inter, OUAF_OBJECT_X, 0,
+ OUAF_OBJECT_X, 156,
+ 59, 44);
+ }
+
+ if (!inter_spinning_objects) goto done;
+
+ /* Paul */
+ if (inter_input_mode == INTER_BUILDING_SENTENCES ||
+ inter_input_mode == INTER_LIMITED_SENTENCES) inter_screen_update();
+
+ if (inter_object_routine == NULL) {
+ Common::strcpy_s(temp_buf, "*OB");
+
+ env_catint(temp_buf, object_id, 3);
+
+ Common::strcat_s(temp_buf, "I");
+
+ } else {
+ inter_object_id = object_id;
+ inter_exec_function(inter_object_routine);
+ Common::strcpy_s(temp_buf, inter_object_buf);
+ }
+
+ sprite_force_memory = inter_objects_block;
+ sprite_force_size = inter_objects_block_size;
+
+ inter_object_series = matte_load_series(temp_buf,
+ SPRITE_LOAD_SPINNING_OBJECT,
+ SERIES_BONUS_OBJECT);
+ stamp_sprite_to_interface(OUAF_OBJECT_X, OUAF_OBJECT_Y, 1, inter_object_series);
+ paul_object_showing = object_id;
+ if (inter_object_series < 0) goto done;
+
+ mcga_setpal_range(&master_palette, 7, 1);
+ mcga_setpal_range(&master_palette, 246, 6);
+
+ inter_object_sprite = 1;
+
+ error_flag = false;
+
+done:
+ sprite_force_memory = NULL;
+ sprite_force_size = 0;
+}
+
+
+
+/*
+/* inter_main_loop()
+/*
+/* The main interface loop. Called by run-time kernel to perform one
+/* round of interface checking. Provides mouse interface for the whole
+/* program.
+*/
+void inter_main_loop(int allow_input) {
+ int width, x, y;
+ int count;
+ int end_of_this_selection;
+ int flags;
+ int use_spacing;
+ long now_time;
+ FontPtr use_font;
+
+ end_of_this_selection = false;
+
+ mouse_begin_cycle(false);
+
+ inter_mouse_x = mouse_x;
+ inter_mouse_y = mouse_y;
+ inter_mouse_type = ABSOLUTE_MODE;
+
+ if (allow_input) inter_auxiliary_click = false;
+
+ if (mouse_start_stroke || !mouse_any_stroke) {
+ if (mouse_y < display_y) {
+ inter_mouse_x += picture_view_x;
+ inter_mouse_y += picture_view_y;
+ inter_mouse_type = RELATIVE_MODE;
+ }
+ } else {
+ if (stroke_type == STROKE_INTERFACE) {
+ inter_mouse_x += picture_view_x;
+ inter_mouse_y += picture_view_y;
+ inter_mouse_type = RELATIVE_MODE;
+ }
+ }
+
+ if (!mouse_any_stroke || (inter_input_mode != INTER_BUILDING_SENTENCES)) {
+ mouse_button = 0;
+ }
+
+ if ((mouse_changed || scroll_active || scrollbar_active || inter_force_rescan) && allow_input) {
+
+ inter_spot_class = STROKE_NONE;
+ inter_spot_index = hspot_which_reverse(inter_mouse_x,
+ inter_mouse_y, inter_mouse_type);
+ if (inter_spot_index > 0) {
+ inter_spot_class = spot[inter_spot_index]._class & STROKE_MASK;
+ inter_spot_id = spot[inter_spot_index].num;
+ }
+
+ if (inter_report_hotspots && !mouse_stroke_going && (inter_spot_class != stroke_type) && (stroke_type != STROKE_NONE)) {
+ end_of_selection = end_of_this_selection = true;
+ switch (stroke_type) {
+ case STROKE_INTERFACE:
+ case STROKE_COMMAND:
+ case STROKE_INVEN:
+ case STROKE_ACTION:
+ case STROKE_SPECIAL_INVEN:
+ case STROKE_DIALOG:
+ inter_select_word();
+ break;
+ }
+ inter_analyze_stroke();
+ }
+
+ if (mouse_start_stroke || (inter_report_hotspots && !mouse_stroke_going)) {
+ stroke_type = inter_spot_class;
+ }
+
+ end_of_selection = mouse_stop_stroke;
+
+ if (mouse_any_stroke || inter_report_hotspots) {
+ switch (stroke_type) {
+ case STROKE_INTERFACE:
+ case STROKE_COMMAND:
+ case STROKE_INVEN:
+ case STROKE_ACTION:
+ case STROKE_SPECIAL_INVEN:
+ case STROKE_DIALOG:
+ inter_select_word();
+ break;
+ }
+ }
+
+ if (mouse_any_stroke ||
+ (inter_report_hotspots && (inter_awaiting > AWAITING_COMMAND) && (stroke_type == STROKE_INVEN)) ||
+ (inter_report_hotspots && (stroke_type == STROKE_INTERFACE))) {
+ inter_analyze_stroke();
+ }
+
+ if (mouse_stop_stroke) {
+ inter_complete_stroke();
+ stroke_type = STROKE_NONE;
+ }
+
+ if (mouse_any_stroke || inter_report_hotspots || scrollbar_active) {
+ inter_scroll_bar();
+ }
+
+ if (mouse_any_stroke || inter_report_hotspots) {
+ inter_compile_sentence();
+ }
+
+ inter_force_rescan = false;
+ }
+
+ if (!allow_input) {
+ if (mouse_stop_stroke) {
+ inter_auxiliary_click = true;
+ }
+ }
+
+ if (inter_sentence_changed) {
+ if (inter_sentence_handle >= 0) {
+ matte_clear_message(inter_sentence_handle);
+ inter_sentence_handle = -1;
+ }
+ if ((strlen(inter_sentence) > 0) && ((inter_input_mode == INTER_BUILDING_SENTENCES) || (inter_input_mode == INTER_LIMITED_SENTENCES))) {
+ use_font = font_main;
+ use_spacing = -1;
+ width = font_string_width(use_font, inter_sentence, use_spacing);
+ if (width > video_x) {
+ use_font = font_inter;
+ use_spacing = 0;
+ width = font_string_width(font_inter, inter_sentence, use_spacing);
+ }
+ x = (video_x >> 1) - (width >> 1);
+ y = (viewing_at_y + scr_work.y - 1) - 12;
+ /* inter_sentence_handle = matte_add_message (use_font, inter_sentence, x, y, INTER_MESSAGE_COLOR, use_spacing); */
+ }
+ inter_sentence_changed = false;
+ }
+
+ now_time = timer_read();
+ if (now_time >= inter_base_time) {
+ for (count = 0; count < (int)image_inter_marker; count++) {
+ flags = image_inter_list[count].flags;
+ if ((flags != IMAGE_REFRESH) &&
+ (flags > IMAGE_UPDATE_ONLY) &&
+ (image_inter_list[count].segment_id != INTER_SPINNING_OBJECT)) {
+ image_inter_list[count].flags = IMAGE_ERASE;
+ }
+ }
+ inter_background_animation();
+ inter_spinning_object();
+ inter_base_time = now_time + 6;
+ }
+}
+
+
+int inter_load_background(char *name, Buffer *target) {
+ Color color[16];
+ int count;
+ int error_flag = true;
+ Load load_handle;
+
+ load_handle.open = false;
+
+ if (loader_open(&load_handle, name, "rb", true)) goto done;
+
+ if (!loader_read(&color[0], sizeof(Color) * 16, 1, &load_handle)) goto done;
+
+ for (count = 0; count < 16; count++) {
+ master_palette[count].r = color[count].r;
+ master_palette[count].g = color[count].g;
+ master_palette[count].b = color[count].b;
+ color_status[count] |= PAL_RESERVED;
+ }
+
+ buffer_init_name(target, video_x, inter_size_y, "$scrintr");
+ if (target->data == NULL) goto done;
+
+ if (!loader_read(target->data, (video_x * inter_size_y), 1, &load_handle)) goto done;
+
+ error_flag = false;
+
+done:
+ if (error_flag) {
+ if (target->data != NULL) {
+ buffer_free(target);
+ }
+ }
+ if (load_handle.open) loader_close(&load_handle);
+ return error_flag;
+}
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/core/inter.h b/engines/mads/madsv2/core/inter.h
index f8f0ad7555b..225528ad178 100644
--- a/engines/mads/madsv2/core/inter.h
+++ b/engines/mads/madsv2/core/inter.h
@@ -269,27 +269,26 @@ extern void (*inter_object_routine)();
/* inter_1.c */
-void inter_prepare_background(void);
-void inter_setup_hotspots(void);
-void inter_set_active_inven(int inven_id);
-void inter_give_to_player(int this_);
-void inter_move_object(int object_id, int location);
-void inter_init_sentence(void);
-void inter_main_loop(int allow_input);
+extern void inter_prepare_background(void);
+extern void inter_setup_hotspots(void);
+extern void inter_set_active_inven(int inven_id);
+extern void inter_give_to_player(int this_);
+extern void inter_move_object(int object_id, int location);
+extern void inter_init_sentence(void);
+extern void inter_main_loop(int allow_input);
-void inter_refresh(void);
-void inter_screen_update(void);
+extern void inter_screen_update(void);
-void inter_turn_off_object(void);
-void inter_spin_object(int object_id);
-int inter_allocate_objects(void);
-void inter_deallocate_objects(void);
+extern void inter_turn_off_object(void);
+extern void inter_spin_object(int object_id);
+extern int inter_allocate_objects(void);
+extern void inter_deallocate_objects(void);
-void inter_reset_dialog(void);
-int inter_add_dialog(char *string, int result);
+extern void inter_reset_dialog(void);
+extern int inter_add_dialog(char *string, int result);
/* inter_2.c */
-int inter_load_background(char *name, Buffer *target);
+extern int inter_load_background(char *name, Buffer *target);
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/core/lbm.h b/engines/mads/madsv2/core/lbm.h
new file mode 100644
index 00000000000..7e85a7724ed
--- /dev/null
+++ b/engines/mads/madsv2/core/lbm.h
@@ -0,0 +1,44 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 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 MADS_CORE_LBM_H
+#define MADS_CORE_LBM_H
+
+#include "mads/madsv2/core/general.h"
+#include "mads/madsv2/core/color.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+/* lbm_1.c */
+void lbm_read_page(const char *filename, byte *image, Palette *pal);
+
+/* lbm_2.c */
+Buffer lbm_read_buffer(const char *filename, Palette *pal, CycleListPtr cycle);
+
+/* lbm_3.c */
+int lbm_read_buffer_main(const char *name, Buffer *target, int reserved_flag,
+ CycleListPtr cycle_list);
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/matte_1.cpp b/engines/mads/madsv2/core/matte.cpp
similarity index 79%
rename from engines/mads/madsv2/core/matte_1.cpp
rename to engines/mads/madsv2/core/matte.cpp
index dd8933551cc..b0d9529b12d 100644
--- a/engines/mads/madsv2/core/matte_1.cpp
+++ b/engines/mads/madsv2/core/matte.cpp
@@ -24,6 +24,7 @@
#include "mads/madsv2/core/buffer.h"
#include "mads/madsv2/core/mouse.h"
#include "mads/madsv2/core/font.h"
+#include "mads/madsv2/core/inter.h"
#include "mads/madsv2/core/sort.h"
#include "mads/madsv2/core/mem.h"
#include "mads/madsv2/core/pal.h"
@@ -94,6 +95,16 @@ int work_screen_ems_handle = -1; /* Work screen in EMS */
TileMapHeader picture_map, depth_map; /* Tile maps */
TileResource picture_resource, depth_resource; /* Tile resources */
+ImageInter image_inter_list[IMAGE_INTER_LIST_SIZE];
+Matte matte_inter_list[IMAGE_INTER_LIST_SIZE];
+
+int inter_viewing_at_y = 0; /* Interface base Y loc. */
+
+byte image_inter_marker = 0; /* Interface image list mark */
+
+Buffer scr_inter = { 0, 0, NULL }; /* Interface work buffer */
+Buffer scr_inter_orig = { 0, 0, NULL }; /* Interface original buffer */
+
int matte_map_work_screen() {
int error_flag = false;
@@ -1099,5 +1110,288 @@ void matte_frame(int special_effect, int full_screen) {
}
}
+
+int matte_allocate_inter_image(void) {
+ int result;
+
+ if (image_inter_marker >= IMAGE_INTER_LIST_SIZE) {
+#if !defined(disable_error_check)
+ error_report(ERROR_IMAGE_INTER_LIST_FULL, ERROR, MODULE_MATTE, IMAGE_INTER_LIST_SIZE, image_inter_marker);
+#endif
+ result = -1;
+ } else {
+ result = image_inter_marker++;
+ }
+
+ return (result);
+}
+
+
+void matte_refresh_inter(void) {
+ int id;
+
+ id = matte_allocate_inter_image();
+ image_inter_list[id].flags = IMAGE_REFRESH;
+ image_inter_list[id].segment_id = (byte)-1;
+}
+
+
+static void make_inter_matte(ImageInterPtr image, MattePtr matte) {
+ SpritePtr sprite;
+ int xs, ys;
+ int flags;
+
+ flags = image->flags;
+ if (flags <= IMAGE_UPDATE_ONLY) flags -= IMAGE_UPDATE_ONLY;
+ if (flags >= IMAGE_UPDATE_READY) flags &= ~IMAGE_UPDATE_READY;
+
+ if (flags == IMAGE_REFRESH) {
+ matte->x = 0;
+ matte->y = 0;
+ xs = scr_inter.x;
+ ys = scr_inter.y;
+ } else if (flags == IMAGE_OVERPRINT) {
+ matte->x = image->x;
+ matte->y = image->y;
+ xs = image->sprite_id;
+ ys = image->series_id;
+ } else {
+
+ sprite = &series_list[image->series_id]->index[(image->sprite_id & HALF_SPRITE_MASK) - 1];
+
+ xs = sprite->xs;
+ ys = sprite->ys;
+
+ if (image->segment_id == INTER_SPINNING_OBJECT) {
+ matte->x = image->x;
+ matte->y = image->y;
+ } else {
+ matte->x = image->x - (xs >> 1);
+ matte->y = image->y - (ys - 1);
+ }
+
+ }
+
+ bound_matte(matte, xs, ys, scr_inter.x, scr_inter.y);
+}
+
+
+
+void matte_inter_frame(int update_live, int clear_chaff) {
+ register int id;
+ int x, y;
+ int flags;
+ word mirror;
+ word which;
+ SeriesPtr series;
+ int beware_the_mouse = false;
+ byte new_marker;
+ register MattePtr matte;
+ register MattePtr matte2;
+ MattePtr i_am_the_dog_master = NULL;
+ ImageInter *image;
+ ImageInter *image2;
+#ifdef show_mattes
+ char temp_buf[80];
+ int count;
+#endif
+
+ /* Make sure work buffer is mapped into the page frame */
+ matte_map_work_screen();
+
+ /* Before performing erasures, make a matte for each potential erasure */
+ /* image. */
+
+ image = image_inter_list;
+ matte = matte_inter_list;
+ for (id = 0; id < (int)image_inter_marker; id++) {
+ if (image->flags < IMAGE_STATIC) {
+ make_inter_matte(image, matte);
+ matte->changed = true;
+ if (image->segment_id == INTER_SPINNING_OBJECT) {
+ if (image->flags == IMAGE_FULLUPDATE) {
+ matte->valid = false;
+ i_am_the_dog_master = matte;
+ }
+ }
+ } else {
+ matte->valid = false;
+ }
+ image++;
+ matte++;
+ }
+
+ filter_matte_list(matte_inter_list, image_inter_marker, 1);
+
+ if (i_am_the_dog_master != NULL) i_am_the_dog_master->valid = true;
+
+ /* Erasures */
+
+ matte = matte_inter_list;
+ image = image_inter_list;
+ for (id = 0; id < (int)image_inter_marker; id++) {
+
+ if (matte->valid) {
+
+ if ((matte->xs > 0) && (matte->ys > 0)) {
+
+ if (image->flags > IMAGE_UPDATE_ONLY) {
+ if (image->flags < IMAGE_ERASE) {
+ buffer_rect_copy(scr_inter_orig, scr_inter,
+ matte->x, matte->y,
+ matte->xs, matte->ys);
+ } else {
+ buffer_inter_merge_2(scr_inter_orig, scr_inter,
+ matte->x, matte->y,
+ matte->x, matte->y,
+ matte->xs, matte->ys);
+ }
+ }
+ }
+ }
+ matte++;
+ image++;
+ }
+
+ matte = matte_inter_list;
+ image = image_inter_list;
+ for (id = 0; id < (int)image_inter_marker; id++) {
+ flags = image->flags;
+ if (flags >= IMAGE_STATIC) {
+ make_inter_matte(image, matte);
+ if (!update_live) flags &= ~IMAGE_UPDATE_READY;
+ matte->changed = (byte)(flags > IMAGE_STATIC);
+ image->flags &= IMAGE_UPDATE_READY;
+ }
+ matte++;
+ image++;
+ }
+
+ /* Check our new matte list for collisions */
+
+ filter_matte_list(matte_inter_list, (int)image_inter_marker, 1);
+
+ /* Now, run through our depth list, and for each entry, draw the */
+ /* indicated sprite into the work buffer. */
+
+ image = image_inter_list;
+ matte = matte_inter_list;
+ for (id = 0; id < (int)image_inter_marker; id++) {
+
+ if ((image->flags >= IMAGE_STATIC) && !(image->flags & IMAGE_UPDATE_READY)) {
+
+ /* Search through the matte list to find the matte of which this */
+ /* image is a part. */
+
+ for (matte2 = matte; !matte2->valid; matte2 = (MattePtr)matte2->y);
+
+ if (matte2->changed) {
+ series = series_list[image->series_id];
+ which = image->sprite_id;
+ mirror = (which & HALF_MIRROR_MASK) ? MIRROR_MASK : 0;
+ which &= HALF_SPRITE_MASK;
+ if (image->segment_id == INTER_SPINNING_OBJECT) {
+ sprite_draw(series, which, &scr_inter, image->x, image->y);
+ } else {
+ x = image->x - (series->index[which - 1].xs >> 1);
+ y = image->y - (series->index[which - 1].ys - 1);
+ sprite_draw_interface(series,
+ which | mirror,
+ &scr_inter,
+ x, y);
+ }
+ }
+ }
+ image++;
+ matte++;
+ }
+
+ if (update_live) {
+
+ /* Finally, run through our combined matte list, and update any */
+ /* areas of the screen flagged as "changed" by copying from the */
+ /* work screen to the live video screen. */
+
+ mouse_set_work_buffer(scr_inter.data, scr_inter.x);
+ mouse_set_view_port_loc(0, inter_viewing_at_y, 319, inter_viewing_at_y + scr_inter.y - 1);
+
+ mouse_freeze(); /* Lock out mouse driver */
+
+ if (video_mode != ega_mode) {
+ beware_the_mouse = mouse_refresh_view_port(); /* Prepare cursor overlay */
+ }
+
+ matte = matte_inter_list;
+ for (id = 0; id < (int)image_inter_marker; id++) {
+
+ /* Get next matte */
+
+#ifdef show_mattes
+ sprintf(temp_buf, "(%d, %d) => (%d, %d) valid: %d changed: %d ",
+ matte->x, matte->y, matte->xs, matte->ys, matte->valid, matte->changed);
+ screen_show(temp_buf, 0, id);
+#endif
+
+ /* Ignore empty mattes, or images which did not change */
+
+ if (matte->valid && matte->changed && (matte->xs > 0) && (matte->ys > 0)) {
+
+ video_update(&scr_inter,
+ matte->x, matte->y,
+ matte->x, matte->y + inter_viewing_at_y,
+ matte->xs, matte->ys);
+
+ }
+
+ matte++;
+ }
+
+#ifdef sixteen_colors
+ if (video_mode == ega_mode) {
+ beware_the_mouse = mouse_refresh_view_port(); /* Prepare cursor overlay */
+ video_flush_ega(inter_viewing_at_y, scr_inter.y); /* Update the EGA screen */
+ }
+#endif
+
+#ifdef show_mattes
+ keys_get();
+#endif
+
+ if (beware_the_mouse) {
+ mouse_refresh_done(); /* Remove cursor image from work buffer */
+ }
+
+ mouse_thaw(); /* Release the mouse driver */
+ }
+
+ /* Delete erasures from image list */
+
+ new_marker = 0;
+ image = image_inter_list;
+ image2 = image_inter_list;
+ for (id = 0; id < (int)image_inter_marker; id++) {
+ if (image->flags >= IMAGE_STATIC) {
+ if (update_live) {
+ image->flags &= ~IMAGE_UPDATE_READY;
+ } else {
+ image->flags |= IMAGE_UPDATE_READY;
+ }
+ if (id != (int)new_marker) {
+ *image2 = *image;
+ }
+ new_marker++;
+ image2++;
+ } else if (!update_live && !clear_chaff) {
+ if (image->flags > IMAGE_UPDATE_ONLY) {
+ image->flags += IMAGE_UPDATE_ONLY;
+ }
+ new_marker++;
+ image2++;
+ }
+ image++;
+ }
+ image_inter_marker = new_marker;
+}
+
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/core/mcga.cpp b/engines/mads/madsv2/core/mcga.cpp
new file mode 100644
index 00000000000..32ce3a50949
--- /dev/null
+++ b/engines/mads/madsv2/core/mcga.cpp
@@ -0,0 +1,193 @@
+/* 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/system.h"
+#include "graphics/paletteman.h"
+#include "mads/madsv2/core/general.h"
+#include "mads/madsv2/core/mem.h"
+#include "mads/madsv2/core/pal.h"
+#include "mads/madsv2/engine.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+#define mcga_retrace_magic 14 /* Dave McKibbin's magic heuristic # */
+
+int mcga_retrace_computed = false;
+word mcga_retrace_ticks = 0;
+int mcga_retrace_max_colors = 256;
+int mcga_retrace_max_bytes = 768;
+
+word mcga_palette_update = false;
+int mcga_palette_fast = true;
+
+
+void mcga_put_pixel(word x, word y, byte c) {
+ byte *dest = (byte *)g_engine->getScreen()->getBasePtr(x, y);
+ *dest = c;
+}
+
+byte mcga_get_pixel(word x, word y) {
+ return *(byte *)g_engine->getScreen()->getBasePtr(x, y);
+}
+
+byte *mcga_open_window(word x, word y, word xsize, word ysize) {
+ byte *out;
+ byte *live;
+ byte *work;
+ word *run;
+ word yy, size;
+
+ size = xsize * ysize + 8;
+ out = (byte *)mem_get((long)size);
+ if (out == NULL)
+ return(NULL);
+
+ run = (word *)out;
+ work = out + 8;
+
+ *run++ = x;
+ *run++ = y;
+ *run++ = xsize;
+ *run++ = ysize;
+
+ live = (mcga_video + x + y * 320);
+
+ for (yy = 1; yy <= ysize; yy++) {
+ memcpy(work, live, xsize);
+ work += xsize;
+ live += 320;
+ }
+
+ return out;
+}
+
+void mcga_close_window(byte *inp) {
+ word *run;
+ byte *live;
+ byte *work;
+ word x, y, xsize, ysize, yy;
+
+ run = (word *)inp;
+ work = inp + 8;
+ x = *run++;
+ y = *run++;
+ xsize = *run++;
+ ysize = *run++;
+
+ live = (mcga_video + x + y * 320);
+
+ for (yy = 1; yy <= ysize; yy++) {
+ memcpy(live, work, xsize);
+ work += xsize;
+ live += 320;
+ }
+
+ mem_free(inp);
+}
+
+void mcga_setpal(Palette *pal) {
+ byte tmpPal[Graphics::PALETTE_SIZE];
+ byte *entry = &tmpPal[0];
+
+ for (int i = 0; i < Graphics::PALETTE_COUNT; ++i, entry += 3) {
+ entry[0] = pal[i]->r;
+ entry[1] = pal[i]->g;
+ entry[2] = pal[i]->b;
+ }
+
+ g_system->getPaletteManager()->setPalette(tmpPal, 0, Graphics::PALETTE_COUNT);
+}
+
+void mcga_getpal(Palette *pal) {
+ byte tmpPal[Graphics::PALETTE_SIZE];
+ byte *entry = &tmpPal[0];
+
+ g_system->getPaletteManager()->grabPalette(tmpPal, 0, Graphics::PALETTE_COUNT);
+
+ for (int i = 0; i < Graphics::PALETTE_COUNT; ++i, entry += 3) {
+ pal[i]->r = entry[0];
+ pal[i]->g = entry[1];
+ pal[i]->b = entry[2];
+ }
+}
+
+void mcga_setpal_range(Palette *pal, int first_color, int num_colors) {
+ byte tmpPal[Graphics::PALETTE_SIZE];
+ byte *entry = &tmpPal[0];
+
+ for (int i = 0; i < num_colors; ++i, entry += 3) {
+ entry[0] = pal[i + first_color]->r;
+ entry[1] = pal[i + first_color]->g;
+ entry[2] = pal[i + first_color]->b;
+ }
+
+ g_system->getPaletteManager()->setPalette(tmpPal, first_color, num_colors);
+}
+
+
+void mcga_cls(byte inp) {
+ g_engine->getScreen()->clear(inp);
+}
+
+void mcga_retrace() {
+ g_engine->getScreen()->update();
+}
+
+static word mcga_time_palette_swap(Palette *pal, int first_color, int num_colors) {
+ mcga_setpal(pal);
+ return 0;
+}
+
+void mcga_compute_retrace_parameters(void) {
+ Palette temp_pal;
+
+ mcga_getpal(&temp_pal);
+ memcpy(&master_palette, &temp_pal, sizeof(Palette));
+ mcga_setpal(&temp_pal);
+
+ /* On original hardware this function computed how many palette entries
+ could be written within one vertical retrace interval, and stored the
+ result in mcga_retrace_max_colors / mcga_retrace_max_bytes. Under a
+ modern graphics API there is no retrace constraint, so we set the
+ maximums to the full 256-entry palette and mark the computation done. */
+ mcga_palette_fast = true;
+ mcga_retrace_max_colors = 256;
+ mcga_retrace_max_bytes = 256 * 3;
+ mcga_retrace_computed = true;
+}
+
+void mcga_shake() {
+ warning("TODO: mcga_shake");
+}
+
+void mcga_reset() {
+ Palette temp_palette;
+ pal_interface(temp_palette);
+
+ memcpy(&temp_palette[20], &temp_palette[6], sizeof(RGBcolor));
+ memcpy(&temp_palette[56], &temp_palette[8], sizeof(RGBcolor) << 3);
+
+ mcga_setpal(&temp_palette);
+}
+
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/core/mcga.h b/engines/mads/madsv2/core/mcga.h
index 5c4fa4ed277..fe54ebf7ba1 100644
--- a/engines/mads/madsv2/core/mcga.h
+++ b/engines/mads/madsv2/core/mcga.h
@@ -35,44 +35,47 @@ extern int mcga_retrace_max_bytes;
extern word mcga_palette_update;
extern int mcga_palette_fast;
+extern word mcga_shakes;
+/**
+ * Given X and Y, sets pixel to color C
+ */
+extern void mcga_put_pixel(word x, word y, byte c);
-/* mcga_1.c */
-void mcga_put_pixel(word x, word y, byte c);
-
-/* mcga_2.c */
-byte mcga_get_pixel(word x, word y);
+/**
+ * Given X and Y, gets pixel at that location
+ */
+extern byte mcga_get_pixel(word x, word y);
+
+/**
+ * Given home and size of window, opens it. Returns pointer
+ * to data for that window. This pointer must be passed to
+ * closewindow_mcga to be closed properly. Data is stored
+ * thus: X(l,h),Y(l,h),XSIZE(l,h),YSIZE(l,h),<data>
+ * where <data> is xsize*ysize bytes.
+ */
+extern byte *mcga_open_window(word x, word y, word xsize, word ysize);
-/* mcga_3.c */
-byte *fastcall mcga_open_window(word x, word y,
- word xsize, word ysize);
-void mcga_close_window(byte *win);
+/**
+ * Given a pointer generated by openwindow_mcga, closes the window.
+ */
+extern void mcga_close_window(byte *win);
-/* mcga_7.c */
-void mcga_setpal(Palette *pal);
+extern void mcga_setpal(Palette *pal);
-/* mcga_8.c */
-void mcga_getpal(Palette *pal);
+extern void mcga_getpal(Palette *pal);
-/* mcga_9.c */
-void mcga_cls(byte inp);
+extern void mcga_cls(byte inp);
-/* mcga_b.c */
-void mcga_retrace(void);
-void mcga_setpal_range(Palette *pal,
- int first_color,
- int num_colors);
+extern void mcga_retrace();
-/* mcga_c.c */
-void mcga_compute_retrace_parameters(void);
+extern void mcga_setpal_range(Palette *pal, int first_color, int num_colors);
-/* mcga_d.c */
-extern word mcga_shakes;
+extern void mcga_compute_retrace_parameters();
-void mcga_shake(void);
+extern void mcga_shake();
-/* mcga_e.c */
-void mcga_reset(void);
+extern void mcga_reset();
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/core/mouse.h b/engines/mads/madsv2/core/mouse.h
index c64c614e85a..5bd552b3751 100644
--- a/engines/mads/madsv2/core/mouse.h
+++ b/engines/mads/madsv2/core/mouse.h
@@ -44,12 +44,12 @@ extern byte mouse_showing; /* Mouse cursor showing status (0 = show) */
extern int mouse_button; /* Last button pressed (0 = left, 1 = right) */
extern int mouse_status; /* Button status flags */
extern int mouse_x, mouse_y; /* Most recent cursor position */
-extern int mouse_start_stroke; /* True if new button press this round */
-extern int mouse_stroke_going; /* True if any button currently down */
-extern int mouse_changed; /* True if position or any button changed */
-extern int mouse_latched; /* Internal use (same as mouse_stroke_going) */
-extern int mouse_stop_stroke; /* True if button released this round */
-extern int mouse_any_stroke; /* True if button down or just now released */
+extern bool mouse_start_stroke; /* True if new button press this round */
+extern bool mouse_stroke_going; /* True if any button currently down */
+extern bool mouse_changed; /* True if position or any button changed */
+extern bool mouse_latched; /* Internal use (same as mouse_stroke_going) */
+extern bool mouse_stop_stroke; /* True if button released this round */
+extern bool mouse_any_stroke; /* True if button down or just now released */
extern int mouse_old_x; /* Cursor X position on previous round */
extern int mouse_old_y; /* Cursor Y position on previous round */
extern long mouse_clock; /* Timing clock to insure at least 1 tick */
diff --git a/engines/mads/madsv2/core/mouse_1.h b/engines/mads/madsv2/core/mouse_1.h
index 4c40a6419b9..a32be21e555 100644
--- a/engines/mads/madsv2/core/mouse_1.h
+++ b/engines/mads/madsv2/core/mouse_1.h
@@ -41,8 +41,8 @@ extern int mouse_video_mode;
extern byte mouse_showing;
extern int mouse_button, mouse_status, mouse_x, mouse_y;
-extern int mouse_start_stroke, mouse_stroke_going, mouse_changed;
-extern int mouse_latched, mouse_stop_stroke;
+extern bool mouse_start_stroke, mouse_stroke_going, mouse_changed;
+extern bool mouse_latched, mouse_stop_stroke;
extern int mouse_old_x, mouse_old_y;
/* mouse_1.cpp */
diff --git a/engines/mads/madsv2/core/mouse_2.cpp b/engines/mads/madsv2/core/mouse_2.cpp
index 8535db0b51d..dc3b9ccd009 100644
--- a/engines/mads/madsv2/core/mouse_2.cpp
+++ b/engines/mads/madsv2/core/mouse_2.cpp
@@ -30,12 +30,12 @@ int mouse_button = -1;
int mouse_status = 0;
int mouse_x = 0;
int mouse_y = 0;
-int mouse_start_stroke = false;
-int mouse_stroke_going = false;
-int mouse_changed = false;
-int mouse_latched = false;
-int mouse_stop_stroke = false;
-int mouse_any_stroke = false;
+bool mouse_start_stroke = false;
+bool mouse_stroke_going = false;
+bool mouse_changed = false;
+bool mouse_latched = false;
+bool mouse_stop_stroke = false;
+bool mouse_any_stroke = false;
int mouse_old_x = 0;
int mouse_old_y = 0;
long mouse_clock = 0;
diff --git a/engines/mads/madsv2/core/pal.cpp b/engines/mads/madsv2/core/pal.cpp
new file mode 100644
index 00000000000..9bcec1e0e0f
--- /dev/null
+++ b/engines/mads/madsv2/core/pal.cpp
@@ -0,0 +1,721 @@
+/* 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 "mads/madsv2/core/pal.h"
+#include "mads/madsv2/core/mcga.h"
+#include "mads/madsv2/core/color.h"
+#include "mads/madsv2/core/error.h"
+#include "mads/madsv2/core/sort.h"
+#include "mads/madsv2/core/mem.h"
+#include "mads/madsv2/core/sprite.h"
+#include "mads/madsv2/core/magic.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+
+extern int kidney;
+
+Palette master_palette; /* Main global palette for program */
+ShadowListPtr master_shadow = NULL; /* Main global shadowing color list */
+
+dword color_status[256]; /* Mapping status of each palette color */
+int flag_used[PAL_MAXFLAGS]; /* Mapping status of each palette handle */
+
+int palette_locked = false;
+int palette_ever_initialized = false;
+
+int palette_reserved_bottom;
+int palette_reserved_top;
+
+int palette_low_search_limit;
+int palette_high_search_limit;
+
+void (*pal_manager_update)() = NULL;
+int pal_manager_active = false;
+int pal_manager_colors = 0;
+
+
+static void pal_exec(void (*target)(), int manager_mode) {
+ if (target == NULL)
+ return;
+
+ pal_manager_active = manager_mode;
+ target();
+ pal_manager_active = false;
+}
+
+void pal_init(int reserve_bottom, int reserve_top) {
+ int count;
+
+ palette_low_search_limit = 0;
+ palette_high_search_limit = 256;
+
+ for (count = 0; count < 256; count++) {
+ color_status[count] = 0;
+ }
+
+ if (!palette_ever_initialized) {
+ pal_interface(master_palette);
+ palette_ever_initialized = true;
+ }
+
+ if (reserve_bottom > 0) {
+ for (count = 0; count < reserve_bottom; count++) {
+ color_status[count] = PAL_RESERVED;
+ }
+ }
+
+ if (reserve_top > 0) {
+ for (count = 0; count < reserve_top; count++) {
+ color_status[255 - count] = PAL_RESERVED;
+ }
+ }
+
+ for (count = 0; count < PAL_MAXFLAGS; count++) {
+ flag_used[count] = false;
+ }
+
+ flag_used[0] = true; /* Flag[0] is RESERVED status */
+ flag_used[1] = true; /* Flag[1] is CYCLE status */
+
+ palette_locked = false;
+
+ palette_reserved_bottom = reserve_bottom;
+ palette_reserved_top = reserve_top;
+
+ pal_manager_colors = 0;
+ pal_exec(pal_manager_update, 1);
+}
+
+void pal_lock() {
+ int count;
+
+ if ((flag_used[PAL_MAXFLAGS - 1]) && !palette_locked) {
+ error_report(ERROR_NO_MORE_PALETTE_FLAGS, ERROR, MODULE_PAL, PAL_MAXFLAGS, 66);
+ }
+
+ palette_locked = true;
+
+ flag_used[PAL_MAXFLAGS - 1] = true;
+
+ for (count = 0; count < 256; count++) {
+ if (color_status[count]) color_status[count] |= 0x80000000L;
+ }
+}
+
+void pal_unlock() {
+ int count;
+
+ if (palette_locked) {
+ for (count = 0; count < 256; count++) {
+ color_status[count] &= 0x7fffffffL;
+ }
+ flag_used[PAL_MAXFLAGS - 1] = false;
+ palette_locked = false;
+ }
+}
+
+int pal_deallocate(int use_flag) {
+ int return_code = PAL_ERR_BADFLAG;
+ int count;
+ dword mask;
+
+ if (!kidney) {
+ if ((use_flag >= PAL_MAXFLAGS) || (use_flag <= 0)) goto done;
+
+ /* Get a mask of everything but our special bit */
+
+ mask = ~(1L << (dword)use_flag);
+
+ for (count = 0; count < 256; count++) {
+ color_status[count] &= mask;
+ if (color_status[count] == PAL_CYCLE) {
+ color_status[count] = 0;
+ }
+ }
+ }
+
+ if (!flag_used[use_flag]) {
+ return_code = PAL_ERR_FLAGNOTUSED;
+ goto done;
+ }
+ flag_used[use_flag] = false;
+
+ return_code = false;
+
+ pal_exec(pal_manager_update, 4);
+
+done:
+ return false;
+}
+
+void pal_compact(word master_handle, int num_slaves, word *slave) {
+ dword mask_test;
+ dword mask_out;
+ dword mask_in;
+ int count;
+
+ mask_out = 0xffffffffL;
+ mask_test = 0L;
+ for (count = 0; count < num_slaves; count++) {
+ mask_out ^= (1L << (dword)(slave[count]));
+ mask_test |= (1L << (dword)(slave[count]));
+ flag_used[slave[count]] = false;
+ }
+
+ mask_in = (1L << (dword)master_handle);
+
+ for (count = 0; count < 256; count++) {
+ if (color_status[count] & mask_test) {
+ color_status[count] &= mask_out;
+ color_status[count] |= mask_in;
+ }
+ }
+
+ flag_used[master_handle] = true;
+}
+
+int pal_get_hash(RGBcolor *one, RGBcolor *two) {
+ int dx = 0;
+ signed char diff;
+
+ diff = one->r - two->r;
+ dx += diff * diff;
+
+ diff = one->g - two->g;
+ dx += diff * diff;
+
+ diff = one->b - two->b;
+ dx += diff * diff;
+
+ return dx;
+}
+
+void pal_shadow_sort(ShadowListPtr shadow, ColorListPtr list) {
+ int count;
+ long shadow_hash[COLOR_MAX_SHADOW_COLORS];
+
+ for (count = 0; count < shadow->num_shadow_colors; count++) {
+ shadow_hash[count] = magic_hash_color((RGBcolor *) & list->table[shadow->shadow_color[count]]);
+ }
+
+ sort_insertion(shadow->num_shadow_colors, &shadow->shadow_color[0], &shadow_hash[0]);
+}
+
+void pal_init_shadow(ShadowListPtr shadow, ColorListPtr new_list) {
+ int count;
+
+ shadow->num_shadow_colors = 0;
+ for (count = 0; count < new_list->num_colors; count++) {
+ if (new_list->table[count].group & COLOR_GROUP_MAP_TO_SHADOW) {
+ if (shadow->num_shadow_colors < COLOR_MAX_SHADOW_COLORS) {
+ shadow->shadow_color[shadow->num_shadow_colors] = count;
+ shadow->num_shadow_colors++;
+ }
+ }
+ }
+}
+
+void pal_activate_shadow(ShadowListPtr shadow) {
+ master_shadow = shadow;
+}
+
+static int pal_get_new_flag() {
+ int return_code;
+ int count;
+
+ /* First, we need to find an available color handle for the new list */
+
+ return_code = PAL_ERR_OUTOFFLAGS;
+
+ for (count = 0; (count < PAL_MAXFLAGS); count++) {
+ if (!flag_used[count]) {
+ return_code = count;
+ goto done;
+ }
+ }
+
+ /* If no handles left to allocate: */
+
+ if (return_code < 0) {
+#ifndef disable_error_check
+ error_report(ERROR_NO_MORE_PALETTE_FLAGS, ERROR, MODULE_PAL, PAL_MAXFLAGS, 100);
+#endif
+ }
+
+done:
+ return (return_code);
+}
+
+
+static int pal_free_colors(int *first_free) {
+ int free_colors, count;
+
+ *first_free = -1;
+
+ free_colors = 0;
+ for (count = 0; count < 256; count++) {
+ if (!color_status[count]) {
+ free_colors++;
+ if (*first_free < 0) {
+ *first_free = count;
+ }
+ }
+ }
+
+ if (*first_free < 0) first_free = 0;
+
+ return free_colors;
+}
+
+int pal_allocate(ColorListPtr new_list, ShadowListPtr shadow_list, int pal_flags) {
+ int target_color, list_color;
+ int return_code;
+ int found;
+ int count;
+ int best_target_color;
+ int search_color;
+ int target_shadow;
+ int shadow;
+ int shadowing_enabled;
+ int shadowing_special;
+ int defining_background;
+ int primary_load;
+ int conduct_search, conduct_insert;
+ int free_colors;
+ int hash, best_hash;
+ int palette_limit;
+ int first_free;
+ int search_start;
+ int search_stop;
+ dword mask;
+ dword reserved_mask;
+ dword cycle_mask;
+ dword bonus;
+ ShadowList incoming_shadow;
+ byte reordering_hash[256];
+ byte reordering_index[256];
+
+ incoming_shadow.num_shadow_colors = 0;
+ palette_limit = (pal_flags & PAL_MAP_TOP_COLORS) ? 256 : 252;
+
+ if (pal_flags & PAL_MAP_RESERVED) {
+ search_start = 0;
+ search_stop = palette_limit;
+ } else {
+ search_start = palette_reserved_bottom;
+ search_stop = MIN(256 - palette_reserved_top, palette_limit);
+ }
+
+ search_start = MAX(search_start, palette_low_search_limit);
+ search_stop = MIN(search_stop, palette_high_search_limit);
+
+ /* Get a new color handle */
+
+ return_code = pal_get_new_flag();
+ if (return_code < 0) goto done;
+
+ /* Set up the proper masking bit for our chosen color handle */
+
+ mask = 1L << (dword)return_code;
+
+ /* Check if we are defining a new background picture */
+
+ defining_background = pal_flags & PAL_MAP_BACKGROUND;
+ primary_load = pal_flags & (PAL_MAP_BACKGROUND | PAL_MAP_DEFINE_RESERVED);
+
+ /* If a shadowing description was passed, enable shadow checking */
+
+ shadowing_enabled = (shadow_list != NULL);
+ shadowing_special = false;
+ if (shadowing_enabled) {
+ if (defining_background || (shadow_list->num_shadow_colors == 0)) {
+ shadowing_enabled = false;
+ }
+ if (defining_background && shadow_list->num_shadow_colors) {
+ shadowing_special = true;
+ }
+ }
+
+ /* If we are mapping shadow colors, we need to make a list of all */
+ /* shadowable colors in our color list and then sort it by intensity. */
+
+ if (shadowing_enabled) {
+ pal_init_shadow(&incoming_shadow, new_list);
+ pal_shadow_sort(&incoming_shadow, new_list);
+ }
+
+ /* Get a count of totally free colors in the palette */
+
+ free_colors = pal_free_colors(&first_free);
+
+ first_free = MAX(first_free, search_start);
+
+ /* Sort the color list so that all cycle colors remain at the beginning */
+ /* of the list but that all colors which are allowed to use inexact RGB */
+ /* mappings are placed at the bottom of the list. That way, colors which */
+ /* require an exact RGB mapping are given the first chance to allocate */
+ /* free color space. */
+
+ /*
+ reordering_index = mem_get_name(256, "$palidx");
+ reordering_hash = mem_get_name(256, "$palhash");
+ if ((reordering_index == NULL) || (reordering_hash == NULL)) goto done;
+ */
+
+ for (count = 0; count < new_list->num_colors; count++) {
+ reordering_index[count] = (byte)count;
+ reordering_hash[count] = 0;
+ if (!(new_list->table[count].group & COLOR_GROUP_MAP_TO_CYCLE)) {
+ reordering_hash[count] |= 0x40;
+ }
+ if ((new_list->table[count].group & (COLOR_GROUP_MAP_TO_CLOSEST | COLOR_GROUP_FORCE_TO_CLOSEST))) {
+ reordering_hash[count] |= 0x20;
+ }
+ }
+ sort_insertion_8(new_list->num_colors, reordering_index, reordering_hash);
+
+ if (pal_flags & PAL_MAP_RESERVED) {
+ reserved_mask = 0xffffffff;
+ } else {
+ reserved_mask = 0xfffffffe;
+ }
+
+ /* Now, for each color in our color list, find an appropriate mapping or */
+ /* create a new one from available color space. */
+
+ for (search_color = 0; search_color < new_list->num_colors; search_color++) {
+
+ list_color = reordering_index[search_color];
+
+ found = false;
+ best_target_color = -1;
+
+ /* Don't insert colors that are being forced to skip codes */
+
+ if (new_list->table[list_color].group & COLOR_GROUP_FORCE_TO_SKIP) {
+ found = true;
+ best_target_color = SS_SKIP;
+ }
+
+ /* If we are doing shadowing, check to see if our color is one of the */
+ /* shadow colors. If so, just map it right to the corresponding shadow */
+ /* color in the master palette, without regard for RGB match. */
+
+ if (shadowing_enabled) {
+ if (new_list->table[list_color].group & COLOR_GROUP_MAP_TO_SHADOW) {
+ for (shadow = 0; !found && (shadow < incoming_shadow.num_shadow_colors); shadow++) {
+ if (list_color == incoming_shadow.shadow_color[shadow]) {
+ found = true;
+ target_shadow = MIN(shadow_list->num_shadow_colors - 1, shadow);
+ best_target_color = shadow_list->shadow_color[target_shadow];
+ }
+ }
+ }
+ }
+
+ if (shadowing_special) {
+ if (new_list->table[list_color].group & COLOR_GROUP_MAP_TO_SHADOW) {
+ for (shadow = 0; !found && (shadow < master_shadow->num_shadow_colors); shadow++) {
+ if (list_color == master_shadow->shadow_color[shadow]) {
+ found = true;
+ best_target_color = shadow + PAL_FORCE_SHADOW;
+ memcpy(&(master_palette[best_target_color].r), &(new_list->table[list_color].r), 3);
+ }
+ }
+ }
+ }
+
+ if (new_list->table[list_color].group & COLOR_GROUP_MAP_TO_CYCLE) {
+ cycle_mask = 0;
+ } else {
+ cycle_mask = PAL_CYCLE;
+ }
+
+ /* Now decide if we should search the existing palette for an already */
+ /* existing mapping. The only reasons not to are A) if we have */
+ /* found a (shadowing) match; and B) if we are defining an initial */
+ /* background and therefore should not have any matches. */
+
+ conduct_search = (!found) && (!defining_background);
+
+ if (conduct_search) {
+
+ /* Now, decide whether we need an exact match or are willing to just */
+ /* take the closest. */
+
+ if ((new_list->table[list_color].group & COLOR_GROUP_FORCE_TO_CLOSEST) ||
+ (((pal_flags & PAL_MAP_ANY_TO_CLOSEST) || (new_list->table[list_color].group & COLOR_GROUP_MAP_TO_CLOSEST)) &&
+ ((pal_flags & PAL_MAP_ALL_TO_CLOSEST) || (!free_colors)))
+ ) {
+ best_hash = 0x7fff;
+ } else {
+ best_hash = 1;
+ }
+
+
+ /* Search through the existing palette for an appropriate color */
+
+ for (target_color = search_start; target_color < search_stop; target_color++) {
+
+ if (color_status[target_color]) {
+ if ((!(color_status[target_color] & PAL_RESERVED)) || (pal_flags & PAL_MAP_RESERVED)) {
+ if (!(color_status[target_color] & cycle_mask)) {
+ if (best_hash > 1) {
+ hash = pal_get_hash((RGBcolor *) & new_list->table[list_color], &master_palette[target_color]);
+ } else {
+ /* This is a little hack (or "optimization") to compare the 3 RGB bytes much */
+ /* more quickly when we are looking for an exact match only. */
+ hash = ((*(word *) & new_list->table[list_color] == *(word *) & master_palette[target_color]) &&
+ (*(((byte *) & new_list->table[list_color]) + 2) == *(((byte *) & master_palette[target_color]) + 2))) ? 0 : 1;
+ }
+ if (hash < best_hash) {
+ found = true;
+ best_target_color = target_color;
+ best_hash = hash;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* Now, decide if we should insert a new color into the palette. We */
+ /* need to if we have not yet found a match, but we must also check */
+ /* to see if we are allowed to create a new color for this color list */
+ /* item (we are not if the item is being forced to map to closest). */
+
+ conduct_insert = (!found) &&
+ (!((pal_flags & PAL_MAP_ALL_TO_CLOSEST) &&
+ ((new_list->table[list_color].group & (COLOR_GROUP_MAP_TO_CLOSEST | COLOR_GROUP_FORCE_TO_CLOSEST)) ||
+ (pal_flags & PAL_MAP_ANY_TO_CLOSEST))
+ ));
+
+ if (conduct_insert) {
+ for (target_color = first_free; (!found) && (target_color < search_stop); target_color++) {
+ if (!color_status[target_color]) {
+ free_colors--;
+ first_free++;
+ found = true;
+ best_target_color = target_color;
+ *(RGBcolor *) &master_palette[target_color].r = *(RGBcolor *) & new_list->table[list_color].r;
+ /* memcpy(&(master_palette[target_color].r), &(new_list->table[list_color].r), 3); */
+ }
+ }
+ }
+
+ /* If we found a mapping for this color, flag our handle for it and */
+ /* make a note of the list-to-palette mapping for this color in the */
+ /* "x16" slot of the color list item. */
+
+ if (found) {
+ bonus = (defining_background && (new_list->table[list_color].cycle != 0)) ? PAL_CYCLE : 0;
+ color_status[best_target_color] |= (mask | bonus);
+ new_list->table[list_color].x16 = (byte)best_target_color;
+ } else {
+ pal_manager_colors = new_list->num_colors;
+ pal_exec(pal_manager_update, 3);
+#ifndef disable_error_check
+ error_report(ERROR_NO_MORE_COLORS, ERROR, MODULE_PAL, new_list->num_colors, search_color);
+#endif
+ return_code = PAL_ERR_OUTOFCOLORS;
+ goto done;
+ }
+ }
+
+ flag_used[return_code] = true;
+
+ pal_manager_colors = new_list->num_colors;
+ pal_exec(pal_manager_update, 2);
+
+done:
+ /*
+ if (reordering_hash != NULL) mem_free(reordering_hash);
+ if (reordering_index != NULL) mem_free(reordering_index);
+ */
+#ifdef palette_dumps
+ pal_dump();
+#endif
+ return (return_code);
+}
+
+int pal_get_flags()
+/*
+ Returns number of available flags - checksum use
+*/
+{
+ int a, out;
+
+ out = 0;
+ for (a = 0; a < PAL_MAXFLAGS; a++)
+ if (!flag_used[a])
+ out++;
+ return(out);
+}
+
+int pal_get_colors()
+/*
+ Returns number of colors available in palette
+*/
+{
+ int a, out;
+
+ out = 0;
+ for (a = 0; a < 256; a++)
+ if (color_status[a] == 0)
+ out++;
+ return(out);
+}
+
+void pal_interface(Palette fixpal) {
+ int intensity, red, green, blue;
+ int base, newCol;
+ int color;
+
+ for (intensity = 0; intensity < 2; intensity++) {
+ base = intensity * 21;
+ newCol = intensity ? 63 : 42;
+ for (red = 0; red < 2; red++) {
+ for (green = 0; green < 2; green++) {
+ for (blue = 0; blue < 2; blue++) {
+ color = (intensity << 3) + (red << 2) + (green << 1) + blue;
+ fixpal[color].r = (byte)(red ? newCol : base);
+ fixpal[color].g = (byte)(green ? newCol : base);
+ fixpal[color].b = (byte)(blue ? newCol : base);
+ }
+ }
+ }
+ }
+
+ fixpal[6].g = 21;
+}
+
+
+
+void pal_white(Palette fixpal) {
+ int count;
+ byte num[4] = { 0, 21, 42, 63 };
+
+ for (count = 0; count < 4; count++) {
+ fixpal[count].r = num[count];
+ fixpal[count].g = num[count];
+ fixpal[count].b = num[count];
+ }
+}
+
+
+void pal_grey(Palette fixpal, int base_color, int num_colors,
+ int low_grey, int high_grey) {
+ int count;
+ int dif;
+ int level;
+ word accum = 0;
+
+ dif = (high_grey - low_grey);
+ level = low_grey;
+
+ for (count = 0; count < num_colors; count++) {
+ fixpal[base_color + count].r = (byte)level;
+ fixpal[base_color + count].g = (byte)level;
+ fixpal[base_color + count].b = (byte)level;
+ if (num_colors > 1) {
+ accum += dif;
+ while (accum >= (word)(num_colors - 1)) {
+ accum -= (num_colors - 1);
+ level++;
+ }
+ }
+ }
+}
+
+
+int pal_get_color(RGBcolor color, int color_handle, int override_reserved, int *color_number) {
+ int count;
+ int result;
+ int found;
+ dword mask;
+
+ if (color_handle < 0) {
+ result = PAL_ERR_OUTOFFLAGS; /* Default if next loop fails */
+
+ for (count = 0; count < PAL_MAXFLAGS; count++) {
+ if (!flag_used[count]) {
+ result = count;
+ break;
+ }
+ }
+
+ if (result < 0) {
+#ifndef disable_error_check
+ error_report(ERROR_NO_MORE_PALETTE_FLAGS, ERROR, MODULE_PAL, PAL_MAXFLAGS, 1);
+#endif
+ return result; /* No flags left to allocate */
+ }
+ } else {
+ result = color_handle;
+ }
+
+ mask = 1L << (dword)result;
+
+ found = false;
+ for (count = 0; (!found) && (count < 256); count++) {
+ if (!(color_status[count] & PAL_RESERVED) || override_reserved) {
+ if (!(color_status[count] & PAL_CYCLE)) {
+ if (memcmp(&color, &master_palette[count].r, sizeof(RGBcolor)) == 0) {
+ color_status[count] |= mask;
+ if (color_number != NULL) *color_number = count;
+ found = true;
+ }
+ }
+ }
+ }
+
+ if (!found) {
+ for (count = 0; (!found) && (count < 256); count++) {
+ if (color_status[count] == 0) {
+ memcpy(&master_palette[count].r, &color, sizeof(RGBcolor));
+ color_status[count] = mask;
+ if (color_number != NULL) *color_number = count;
+ found = true;
+ }
+ }
+ }
+
+ if (!found) {
+#ifndef disable_error_check
+ error_report(ERROR_NO_MORE_COLORS, ERROR, MODULE_PAL, 1, 1);
+#endif
+ result = PAL_ERR_OUTOFCOLORS;
+ }
+
+ return result;
+}
+
+void pal_change_color(int color, int r, int g, int b) {
+ master_palette[color].r = (byte)r;
+ master_palette[color].g = (byte)g;
+ master_palette[color].b = (byte)b;
+ mcga_setpal_range((Palette *)master_palette, color, 1);
+}
+
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/core/pal.h b/engines/mads/madsv2/core/pal.h
index 73ed743279b..ce060b8ab54 100644
--- a/engines/mads/madsv2/core/pal.h
+++ b/engines/mads/madsv2/core/pal.h
@@ -85,45 +85,84 @@ extern int pal_manager_active;
extern int pal_manager_colors;
-/* pal_1.c */
-
-void pal_init(int reserve_bottom, int reserve_top);
-
-void pal_lock(void);
-void pal_unlock(void);
+/**
+ * Initializes an empty palette with no owners. Reserves the
+ * first <reserve_bottom> colors and last <reserve_top> colors
+ * for the system. Color 0 is always reserved.
+ */
+extern void pal_init(int reserve_bottom, int reserve_top);
-int pal_allocate(ColorListPtr new_list,
- ShadowListPtr shadow_list,
- int pal_flags);
+extern void pal_lock(void);
+extern void pal_unlock(void);
-int pal_deallocate(int use_flag);
-void pal_compact(word master_handle, int num_slaves, word *slave);
+/**
+ * Given a color list, allocates all its colors in the global palette.
+ * Function returns a color usage handle which can be used later by
+ * pal_deallocate. A negative result signifies an error.
+ * The color list pointed to by new_list is udpated such that when
+ * a color is allocated, its new value is stored in the X16 byte.
+ *
+ * Flags available include:
+ *
+ * PAL_MAP_BACKGROUND set when loading the initial color list
+ * for the room background; allows new cycling
+ * ranges to be created.
+ *
+ * PAL_MAP_RESERVED allows colors to map to the reserved
+ * color areas.
+ *
+ * PAL_MAP_ANY_TO_CLOSEST allows any color to map to the closest
+ * available color instead of an exact match.
+ *
+ * PAL_MAP_ALL_TO_CLOSEST forces any color that is allowed to map
+ * to the closest color to do so even if free
+ * color slots exist. If combined with the
+ * previous flag, no new colors will be added
+ * to the palette.
+ */
+extern int pal_allocate(ColorListPtr new_list, ShadowListPtr shadow_list, int pal_flags);
-int pal_get_hash(RGBcolor *one, RGBcolor *two);
-void pal_shadow_sort(ShadowListPtr shadow, ColorListPtr list);
-void pal_init_shadow(ShadowListPtr shadow, ColorListPtr new_list);
-void pal_activate_shadow(ShadowListPtr shadow);
+/**
+ * Erases usage of of colors marked by use_flag, and returns that
+ * flag to availability. Returns PAL_ error code if failure.
+ *
+ * NOTE: If the FLAGNOTUSED error is returned, the flag's colors
+ * (if any) have ALREADY been removed from the list by the function.
+ * This allows the pal_allocate function to clean up after an
+ * OUTOFCOLORS error.
+ */
+extern int pal_deallocate(int use_flag);
+/**
+ * Compresses a list of handles to a single handle (designed for use
+ * by room loader so that background sprites don't take up lots of handles)
+ */
+extern void pal_compact(word master_handle, int num_slaves, word *slave);
-/* pal_2.c */
-int pal_get_flags(void);
+/**
+ * Computes the sum of squared differences between the two colors
+ */
+extern int pal_get_hash(RGBcolor *one, RGBcolor *two);
-/* pal_3.c */
-int pal_get_colors(void);
+/**
+ * Sorts a shadow color list by intensity.
+ */
+extern void pal_shadow_sort(ShadowListPtr shadow, ColorListPtr list);
-/* pal_4.c */
-void pal_interface(Palette fixpal);
-void pal_white(Palette fixpal);
-void pal_grey(Palette fixpal, int base_color, int num_colors,
+/**
+ * Local routine to find the colors in a list for which shadow mapping is requested.
+ */
+extern void pal_init_shadow(ShadowListPtr shadow, ColorListPtr new_list);
+extern void pal_activate_shadow(ShadowListPtr shadow);
+extern int pal_get_flags(void);
+extern int pal_get_colors(void);
+extern void pal_interface(Palette fixpal);
+extern void pal_white(Palette fixpal);
+extern void pal_grey(Palette fixpal, int base_color, int num_colors,
int low_grey, int high_grey);
-
-/* pal_5.c */
-int pal_get_color(RGBcolor color, int color_handle,
+extern int pal_get_color(RGBcolor color, int color_handle,
int override_reserved, int *color_number);
-
-
-/* pal_6.c */
-void pal_change_color(int color, int r, int g, int b);
+extern void pal_change_color(int color, int r, int g, int b);
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/core/popup.cpp b/engines/mads/madsv2/core/popup.cpp
new file mode 100644
index 00000000000..a9dc8eb4310
--- /dev/null
+++ b/engines/mads/madsv2/core/popup.cpp
@@ -0,0 +1,3472 @@
+/* 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 "mads/madsv2/core/general.h"
+#include "mads/madsv2/core/popup.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/error.h"
+#include "mads/madsv2/core/mem.h"
+#include "mads/madsv2/core/heap.h"
+#include "mads/madsv2/core/font.h"
+#include "mads/madsv2/core/mouse.h"
+#include "mads/madsv2/core/video.h"
+#include "mads/madsv2/core/matte.h"
+#include "mads/madsv2/core/buffer.h"
+#include "mads/madsv2/core/keys.h"
+#include "mads/madsv2/core/timer.h"
+#include "mads/madsv2/core/sprite.h"
+#include "mads/madsv2/core/digi.h"
+#include "mads/madsv2/core/midi.h"
+#include "mads/madsv2/core/screen.h"
+#include "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/pal.h"
+#include "mads/madsv2/core/mcga.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+
+#define popup_padding_width 3 /* Extra space on each side */
+
+Box text_box = { false };
+Box *box = &text_box;
+
+int popup_key = 0;
+int popup_esc_key = false;
+int popup_asking_number = false;
+
+int popup_available = false;
+
+int popup_preserve_initiator[3] = { BUFFER_PRESERVE,
+ BUFFER_PRESERVE,
+ BUFFER_PRESERVE };
+
+byte popup_colors[24] = { 18, 19, 20, 21, 22, 23, 24, 25,
+ 25, 24, 0, 0, 0, 3, 0, 0,
+ 0, 0, 0, 0, 3, 0, 0, 0 };
+
+BoxParam box_param = { NULL };
+Popup *popup = NULL;
+word popup_default_status = POPUP_STATUS_BAR;
+
+static char *popup_savelist_string(PopupItem *item, int element);
+
+
+int popup_create(int horiz_pieces, int x, int y) {
+ int error_flag = true;
+ int middle_width;
+ int count;
+ long mem_to_get;
+
+ if (box == NULL) goto done;
+
+ box->dialog_system = false;
+
+ if (horiz_pieces < 0) {
+ horiz_pieces = neg(horiz_pieces);
+ box->dialog_system = true;
+ }
+
+ box->icon = NULL;
+ box->icon_width = 0;
+ box->icon_height = 0;
+ box->icon_center = false;
+
+ box->base_x = x;
+ box->base_y = y;
+
+ box->horiz_pieces = horiz_pieces;
+
+ middle_width = pop_xs(POPUP_UPPER_CENTER) + ((pop_xs(POPUP_TOP) << 1) * horiz_pieces);
+
+ box->xs = pop_xs(POPUP_UPPER_LEFT) + pop_xs(POPUP_UPPER_RIGHT) + middle_width;
+
+ box->window_xs = box_param.extra_x + middle_width;
+
+ box->cursor_x = 0;
+
+ box->text_x = 0;
+ box->text_y = 0;
+
+ box->dont_add_space = false;
+
+ font_set_colors(-1, POPUP_TEXT_COLOR, POPUP_TEXT_COLOR, POPUP_TEXT_COLOR);
+
+ box->text_xs = box->window_xs - (popup_padding_width << 1);
+
+ box->text_width = (box->text_xs / box_param.font->max_x_size) << 1;
+
+ box->screen_saved = false;
+ box->depth_saved = false;
+
+ box->active = true;
+
+ if (!box->dialog_system) {
+ mem_to_get = (box->text_width + 1) * POPUP_MAX_LINES;
+ box->text[0] = (char *)mem_get_name(mem_to_get, "$poptext");
+
+ if (box->text[0] == NULL) goto done;
+
+ for (count = 1; count < POPUP_MAX_LINES; count++) {
+ box->text[count] = box->text[count - 1] + box->text_width + 1;
+ }
+
+ for (count = 0; count < POPUP_MAX_LINES; count++) {
+ *box->text[count] = 0;
+ box->tab[count] = 0;
+ }
+ } else {
+ box->text[0] = NULL;
+ }
+
+ error_flag = false;
+
+done:
+ return (error_flag);
+}
+
+
+void popup_add_icon(SeriesPtr series, int id, int center) {
+ box->icon = series;
+ box->icon_id = id;
+
+ box->icon_width = series->index[id - 1].xs + popup_padding_width;
+ box->icon_height = series->index[id - 1].ys + popup_padding_width;
+
+ box->icon_center = center;
+
+ if (center) {
+ box->cursor_x = 0;
+ box->text_y = ((box->icon_height - 1) / (box_param.font->max_y_size + 1)) + 2;
+ } else {
+ box->cursor_x = box->icon_width;
+ }
+}
+
+
+
+void popup_next_line(void) {
+ int y_sum;
+
+ box->text_y++;
+
+ y_sum = box->text_y * (box_param.font->max_y_size + 1);
+ if (y_sum > box->icon_height) {
+ box->cursor_x = 0;
+ } else {
+ box->cursor_x = box->icon_width;
+ }
+
+ box->text_x = 0;
+ /* box->dont_add_space = false; */
+
+ if (box->text_y >= POPUP_MAX_LINES) {
+ error_report(ERROR_POPUP_TOO_MANY_LINES, ERROR, MODULE_POPUP, box->text_y, POPUP_MAX_LINES);
+ }
+}
+
+
+void popup_set_ask(void) {
+ box->ask_x = box->text_x + 1;
+ box->ask_y = box->text_y;
+ popup_next_line();
+}
+
+
+void popup_add_string(const char *string) {
+ int len, width;
+
+ len = strlen(string);
+ box->text_x += len;
+
+ width = font_string_width(box_param.font, string, box_param.font_spacing) + box_param.font_spacing;
+ box->cursor_x += width;
+
+ Common::strcat_s(box->text[box->text_y], 65536, string);
+}
+
+
+
+void popup_write_string(const char *string) {
+ char word[80];
+ char word2[80];
+ const char *marker;
+ char *word_ptr;
+ int any_space;
+ int any_hyphen;
+ int stop_on_hyphen = false;
+ int going;
+ int len;
+ int width;
+ int cr;
+
+ marker = string;
+
+ while (*marker != 0) {
+
+ word_ptr = word;
+ any_space = false;
+ any_hyphen = false;
+ cr = false;
+ going = true;
+
+ stop_on_hyphen = false;
+
+ while (going) {
+
+ *word_ptr++ = *marker;
+
+ if (*marker == 0) {
+ going = false;
+ } else if (*marker == '\n') {
+ going = false;
+ cr = true;
+ marker++;
+ word_ptr--;
+ } else if (*marker == 0x20) { /* Soft space */
+ marker++;
+ any_space = true;
+ } else if (*marker == '~') { /* Hard space */
+ word_ptr--;
+ *word_ptr++ = ' ';
+ marker++;
+ } else if (any_space) { /* (Break after space) */
+ word_ptr--;
+ going = false;
+ } else if (*marker == '=') { /* Hard hyphen */
+ word_ptr--;
+ *word_ptr++ = '-';
+ if (*(marker + 1) == '-') {
+ *(word_ptr - 1) = '{';
+ marker++;
+ }
+ marker++;
+ } else if (*marker == '-') { /* Soft hyphen */
+ if (*(marker + 1) == '-') {
+ *(word_ptr - 1) = '{'; /* Double hyphen */
+ marker++;
+ }
+ marker++;
+ any_hyphen = true;
+ } else if (any_hyphen) { /* (Break after hyphen) */
+ word_ptr--;
+ going = false;
+ stop_on_hyphen = true;
+ } else {
+ marker++;
+ }
+ }
+
+ *word_ptr = 0;
+
+ len = strlen(word);
+ if (len > 0) {
+ if (word[len - 1] == 0x20) {
+ word[len - 1] = 0;
+ }
+ }
+
+ word2[0] = 0;
+
+ if ((box->text_x > 0) && !box->dont_add_space) {
+ Common::strcat_s(word2, " ");
+ }
+ Common::strcat_s(word2, word);
+
+ box->dont_add_space = stop_on_hyphen;
+
+ len = strlen(word2);
+ width = font_string_width(box_param.font, word2, POPUP_SPACING) /* - POPUP_SPACING */;
+
+ if (((box->text_x + len) > box->text_width) || ((box->cursor_x + width) > box->text_xs)) {
+ popup_next_line();
+ popup_add_string(word);
+ } else {
+ popup_add_string(word2);
+ }
+ if (cr) popup_next_line();
+ }
+}
+
+
+void popup_bar(void) {
+ if ((box->cursor_x > 0) || (box->text_x > 0)) {
+ popup_next_line();
+ }
+ box->tab[box->text_y] = POPUP_BAR;
+ popup_next_line();
+}
+
+
+void popup_underline(void) {
+ box->tab[box->text_y] |= POPUP_UNDERLINE;
+}
+
+
+void popup_downpixel(void) {
+ box->tab[box->text_y] |= POPUP_DOWNPIXEL;
+}
+
+
+void popup_tab(int tab_level) {
+ box->tab[box->text_y] |= tab_level;
+}
+
+
+void popup_center_string(const char *string, int underline) {
+ int width;
+
+ if ((box->cursor_x > 0) || (box->text_x > 0)) {
+ popup_next_line();
+ }
+
+ width = font_string_width(box_param.font, string, box_param.font_spacing);
+ if ((width >= (int)box->text_xs) || ((int)strlen(string) >= box->text_width)) {
+ popup_write_string(string);
+ } else {
+ box->tab[box->text_y] |= ((box->text_xs >> 1) - (width >> 1));
+
+ Common::strcpy_s(box->text[box->text_y], 65536, string);
+
+ if (underline) popup_underline();
+ }
+
+ popup_next_line();
+}
+
+
+static void pop_draw(int sprite, int x, int y, int depth_code) {
+ matte_map_work_screen();
+
+ sprite_draw(box_param.series, sprite, &scr_main, x, y);
+
+ if (depth_code) {
+ sprite_draw(box_param.series, sprite, &scr_orig, x + picture_map.pan_offset_x,
+ y + picture_map.pan_offset_y);
+
+ x += (pop_xs(sprite) >> 1);
+ y += (pop_ys(sprite) - 1);
+
+ sprite_draw_3d_scaled_to_attr(box_param.series, sprite,
+ &scr_work, &scr_depth,
+ x, y, 0, 100, picture_map.pan_offset_x,
+ picture_map.pan_offset_y);
+ }
+}
+
+
+int popup_draw(int save_screen, int depth_code) {
+ int error_flag = true;
+ int count;
+ int base_text_size;
+ int base_sprite_size;
+ int base_size;
+ int text_size;
+ int top, left, right;
+ int x_bonus, y_bonus;
+ int depth_x2;
+ int bottom_pieces;
+ int x, y;
+ int attr_depth_x;
+ int attr_depth_xs;
+ int attr_depth_x2;
+ int loc_x, loc_y;
+ int temp;
+ int temp_y;
+ int icon_padding;
+ int icon_x;
+ int sum_y;
+
+ /* Arrow cursor */
+ cursor_id = 1;
+ if (cursor_id != cursor_last) {
+ mouse_cursor_sprite(cursor, cursor_id);
+ cursor_last = cursor_id;
+ }
+
+ if (!box->cursor_x) box->text_y--;
+
+ /* Find out how many vertical pieces are needed to contain the text, */
+ /* and determine the resulting size. */
+
+ if (!box->dialog_system) {
+ base_text_size = ((box_param.font->max_y_size + 1) * (box->text_y + 1)) + (popup_padding_width << 1);
+ } else {
+ base_text_size = (int)box->request_y_size;
+ }
+
+ base_sprite_size = 0;
+ if (box->icon != NULL) {
+ base_sprite_size = box->icon->index[box->icon_id - 1].ys + (popup_padding_width << 1);
+ }
+ base_size = MAX(base_text_size, base_sprite_size);
+
+ box->vert_pieces = ((base_size - (box_param.extra_y + 1)) / pop_ys(POPUP_LEFT)) + 1;
+ box->vert_pieces = MAX(0, box->vert_pieces);
+ text_size = (pop_ys(POPUP_LEFT) * box->vert_pieces) + box_param.extra_y;
+
+ box->window_ys = text_size;
+ box->text_extra = text_size - base_text_size;
+
+ box->ys = text_size - (box_param.extra_y)
+ + pop_ys(POPUP_UPPER_LEFT)
+ + pop_ys(POPUP_LOWER_LEFT);
+
+ /* Determine the true size of the entire window (figure out which border */
+ /* pieces extend the furthest). */
+
+ top = pop_y(POPUP_UPPER_LEFT);
+ top = MIN(top, pop_y(POPUP_UPPER_CENTER));
+ top = MIN(top, pop_y(POPUP_TOP));
+
+ y_bonus = pop_y(POPUP_UPPER_LEFT) - top;
+ box->ys += y_bonus;
+
+
+
+ left = pop_x(POPUP_UPPER_LEFT);
+ left = MIN(left, pop_x(POPUP_LEFT));
+ left = MIN(left, pop_x(POPUP_LOWER_LEFT));
+
+ x_bonus = pop_x(POPUP_UPPER_LEFT) - left;
+ box->xs += x_bonus;
+
+ right = pop_x2(POPUP_UPPER_RIGHT);
+ right = MAX(right, pop_x2(POPUP_RIGHT));
+ right = MAX(right, pop_x2(POPUP_LOWER_RIGHT));
+
+ box->xs += (right - pop_x2(POPUP_UPPER_RIGHT));
+
+ /* Determine the popup's coordinates on the screen */
+
+ if (box->base_x & POPUP_CENTER) {
+ temp = (box->base_x & (~POPUP_CENTER));
+ if (!temp) temp = (video_x >> 1);
+ box->x = temp - (box->xs >> 1);
+ } else {
+ box->x = box->base_x;
+ }
+
+ if (box->base_y & POPUP_CENTER) {
+ temp = (box->base_y & (~POPUP_CENTER));
+ if (!temp) temp = (video_y >> 1);
+ box->y = temp - (box->ys >> 1);
+ } else {
+ box->y = box->base_y;
+ }
+
+ while ((box->x > 0) && ((box->x + box->xs) > video_x - 1)) {
+ box->x--;
+ }
+
+ while (((box->x + box->xs) <= video_x) && (box->x < 1)) {
+ box->x++;
+ }
+
+ while ((box->y > 0) && ((box->y + box->ys) > video_y - 1)) {
+ box->y--;
+ }
+
+ while (((box->y + box->ys) <= video_y) && (box->y < 1)) {
+ box->y++;
+ }
+
+ /* Compute base border point */
+
+ box->base_x = box->x + x_bonus;
+ box->base_y = box->y + y_bonus;
+
+ /* Compute window location */
+
+ box->window_x = box->base_x + box_param.offset_x;
+ box->window_y = box->base_y + box_param.offset_y;
+
+ if (save_screen) {
+ matte_map_work_screen();
+
+ if (depth_code) {
+ box->preserve_handle = buffer_preserve(&scr_orig, popup_preserve_initiator[2],
+ -1,
+ box->x + picture_map.pan_offset_x,
+ box->y + picture_map.pan_offset_y,
+ box->xs, box->ys);
+ } else {
+ box->preserve_handle = buffer_preserve(&scr_main, popup_preserve_initiator[0],
+ work_screen_ems_handle,
+ box->x, box->y,
+ box->xs, box->ys);
+ }
+
+ box->screen_saved = true;
+
+ if (box->preserve_handle == BUFFER_NOT_PRESERVED) {
+ error_report(ERROR_POPUP_PRESERVE_FAILURE, WARNING, MODULE_POPUP, box->preserve_handle, 0);
+ }
+
+ if (depth_code) {
+ box->depth_x = box->x + picture_map.pan_offset_x;
+ box->depth_xs = box->xs;
+ if (box->depth_x & 1) {
+ box->depth_x--;
+ box->depth_xs++;
+ }
+ depth_x2 = box->depth_x + box->depth_xs - 1;
+ if (!(depth_x2 & 1)) {
+ box->depth_xs++;
+ }
+ box->depth_x = box->depth_x >> 1;
+ box->depth_xs = box->depth_xs >> 1;
+
+ box->depth_preserve_handle = buffer_preserve(&scr_depth,
+ popup_preserve_initiator[1],
+ -1,
+ box->depth_x,
+ box->y + picture_map.pan_offset_y,
+ box->depth_xs, box->ys);
+
+ if (box->depth_preserve_handle == BUFFER_NOT_PRESERVED) {
+ error_report(ERROR_POPUP_PRESERVE_FAILURE, WARNING, MODULE_POPUP, box->depth_preserve_handle, 1);
+ }
+
+ box->depth_saved = true;
+ }
+ }
+
+ matte_map_work_screen();
+
+ x = box->base_x;
+ y = box->base_y;
+
+ /* Draw top edge */
+
+ pop_draw(POPUP_UPPER_LEFT, x, y, depth_code);
+
+ x += pop_xs(POPUP_UPPER_LEFT);
+
+ for (count = 0; count < box->horiz_pieces; count++) {
+ pop_draw(POPUP_TOP, x, y + box_param.top_adjust_y, depth_code);
+ x += pop_xs(POPUP_TOP);
+ }
+
+ pop_draw(POPUP_UPPER_CENTER, x, y + box_param.center_adjust_y, depth_code);
+ x += pop_xs(POPUP_UPPER_CENTER);
+
+ for (count = 0; count < box->horiz_pieces; count++) {
+ pop_draw(POPUP_TOP, x, y + box_param.top_adjust_y, depth_code);
+ x += pop_xs(POPUP_TOP);
+ }
+
+ pop_draw(POPUP_UPPER_RIGHT, x, y + box_param.upper_right_adjust_y, depth_code);
+
+ /* Draw right edge */
+
+ y += pop_ys(POPUP_UPPER_RIGHT);
+
+ for (count = 0; count < box->vert_pieces; count++) {
+ pop_draw(POPUP_RIGHT, x + box_param.right_adjust_x, y, depth_code);
+ y += pop_ys(POPUP_RIGHT);
+ }
+
+ /* Draw left edge */
+
+ x = box->base_x;
+ y = box->base_y + pop_ys(POPUP_UPPER_LEFT);
+
+ for (count = 0; count < box->vert_pieces; count++) {
+ pop_draw(POPUP_LEFT, x + box_param.left_adjust_x, y, depth_code);
+ y += pop_ys(POPUP_LEFT);
+ }
+
+ pop_draw(POPUP_LOWER_LEFT, x + box_param.lower_left_adjust_x, y, depth_code);
+
+ /* Draw bottom edge */
+
+ x += pop_xs(POPUP_LOWER_LEFT);
+
+ bottom_pieces = (box->horiz_pieces << 1) + box_param.pieces_per_center;
+
+ for (count = 0; count < bottom_pieces; count++) {
+ pop_draw(POPUP_BOTTOM, x, y + box_param.bottom_adjust_y, depth_code);
+ x += pop_xs(POPUP_BOTTOM);
+ }
+
+ pop_draw(POPUP_LOWER_RIGHT, x, y + box_param.lower_right_adjust_y, depth_code);
+
+ /* Fill center */
+
+ loc_y = box->window_y + popup_padding_width + (box->text_extra >> 1);
+ loc_y += ((box_param.font->max_y_size + 1) * box->ask_y);
+
+
+ box->fill_accum = buffer_rect_fill_pattern(scr_main, box->window_x, box->window_y,
+ box->window_xs, box->window_ys,
+ box->window_x, box->window_y, box->window_xs,
+ POPUP_FILL_COLOR, POPUP_FILL_COLOR_2,
+ 0, loc_y);
+
+ if (depth_code) {
+ matte_guard_depth_0 = true;
+ box->fill_accum = buffer_rect_fill_pattern(scr_orig,
+ box->window_x + picture_map.pan_offset_x,
+ box->window_y + picture_map.pan_offset_y,
+ box->window_xs, box->window_ys,
+ box->window_x + picture_map.pan_offset_x,
+ box->window_y + picture_map.pan_offset_y,
+ box->window_xs,
+ POPUP_FILL_COLOR, POPUP_FILL_COLOR_2,
+ 0, loc_y);
+
+ attr_depth_x = box->window_x + picture_map.pan_offset_x;
+ attr_depth_xs = box->window_xs;
+ if (attr_depth_x & 1) {
+ attr_depth_x--;
+ attr_depth_xs++;
+ }
+ attr_depth_x2 = attr_depth_x + attr_depth_xs - 1;
+ if (!(attr_depth_x2 & 1)) {
+ attr_depth_xs++;
+ }
+ attr_depth_x = attr_depth_x >> 1;
+ attr_depth_xs = attr_depth_xs >> 1;
+
+ buffer_rect_fill(scr_depth, attr_depth_x, box->window_y + picture_map.pan_offset_y,
+ attr_depth_xs, box->window_ys, 0);
+ }
+
+ /* Draw icon if any */
+
+ if (box->icon != NULL) {
+ icon_x = 0;
+
+ if (box->icon_center) {
+ icon_x = ((box->window_xs - (popup_padding_width << 1)) - box->icon_width);
+ if (icon_x > 0) {
+ icon_x = icon_x >> 1;
+ } else {
+ icon_x = 0;
+ }
+ }
+
+ sprite_draw(box->icon, box->icon_id, &scr_main,
+ box->window_x + icon_x + popup_padding_width,
+ box->window_y + popup_padding_width);
+
+ if (depth_code) {
+ sprite_draw(box->icon, box->icon_id, &scr_orig,
+ box->window_x + icon_x + popup_padding_width + picture_map.pan_offset_x,
+ box->window_y + popup_padding_width + picture_map.pan_offset_y);
+ }
+ }
+
+ if (box->dialog_system) {
+ error_flag = false;
+ goto done;
+ }
+
+ /* Draw text in box */
+
+ loc_y = box->window_y + popup_padding_width + (box->text_extra >> 1);
+ sum_y = 0;
+
+ for (count = 0; count < box->text_y + 1; count++) {
+ if (box->tab[count] == POPUP_BAR) {
+ buffer_rect_fill(scr_main,
+ box->window_x, loc_y + ((box_param.font->max_y_size + 1) >> 1),
+ box->window_xs, 1, (byte)POPUP_TEXT_COLOR);
+
+ if (depth_code) {
+ buffer_rect_fill(scr_orig,
+ box->window_x + picture_map.pan_offset_x,
+ loc_y + ((box_param.font->max_y_size + 1) >> 1) + picture_map.pan_offset_y,
+ box->window_xs, 1, (byte)POPUP_TEXT_COLOR);
+ }
+ } else {
+ icon_padding = (sum_y > box->icon_height) ? 0 : box->icon_width;
+ loc_x = box->window_x + popup_padding_width + icon_padding +
+ +(box->tab[count] & (~(POPUP_UNDERLINE | POPUP_DOWNPIXEL)));
+ temp_y = loc_y;
+ if (box->tab[count] & POPUP_DOWNPIXEL) {
+ temp_y++;
+ }
+ font_write(box_param.font, &scr_main, box->text[count], loc_x, temp_y, box_param.font_spacing);
+ if (depth_code) {
+ font_write(box_param.font, &scr_orig, box->text[count],
+ loc_x + picture_map.pan_offset_x,
+ temp_y + picture_map.pan_offset_y, box_param.font_spacing);
+ }
+ if (box->tab[count] & POPUP_UNDERLINE) {
+ buffer_rect_fill(scr_main, loc_x, temp_y + box_param.font->max_y_size,
+ font_string_width(box_param.font, box->text[count], box_param.font_spacing),
+ 1, (byte)POPUP_TEXT_COLOR);
+ if (depth_code) {
+ buffer_rect_fill(scr_orig,
+ loc_x + picture_map.pan_offset_x,
+ temp_y + box_param.font->max_y_size + picture_map.pan_offset_y,
+ font_string_width(box_param.font, box->text[count], box_param.font_spacing),
+ 1, (byte)POPUP_TEXT_COLOR);
+ }
+ }
+ }
+
+ loc_y += (box_param.font->max_y_size + 1);
+ sum_y += (box_param.font->max_y_size + 1);
+ }
+
+ /* Update live video */
+
+ mouse_hide();
+ video_update(&scr_main, box->x, box->y, box->x, box->y, box->xs, box->ys);
+ mouse_show();
+
+ error_flag = false;
+
+done:
+ return (error_flag);
+}
+
+
+void popup_destroy(void) {
+ int x, y;
+ int xs, ys;
+
+ if (box->active && box->screen_saved) {
+ if (box->depth_saved) {
+ buffer_restore(&scr_orig, box->preserve_handle, -1,
+ box->x + picture_map.pan_offset_x,
+ box->y + picture_map.pan_offset_y,
+ box->xs, box->ys);
+ buffer_restore(&scr_depth, box->depth_preserve_handle, -1,
+ box->depth_x, box->y + picture_map.pan_offset_y,
+ box->depth_xs, box->ys);
+
+ matte_guard_depth_0 = false;
+
+ matte_refresh_work();
+
+ if (viewing_at_y) {
+ matte_disable_screen_update = true;
+
+ matte_map_work_screen();
+ buffer_rect_fill(scr_main, 0, 0, video_x, viewing_at_y, 0);
+ buffer_rect_fill(scr_main, 0, viewing_at_y + display_y, video_x, video_y, 0);
+ matte_frame(false, false);
+
+ matte_map_work_screen();
+
+ mouse_hide();
+ video_update(&scr_main, 0, 0, 0, 0, video_x, video_y);
+ mouse_show();
+
+ matte_disable_screen_update = false;
+ }
+
+ } else {
+ matte_map_work_screen();
+ buffer_restore(&scr_main, box->preserve_handle, work_screen_ems_handle,
+ box->x, box->y, box->xs, box->ys);
+
+ matte_map_work_screen();
+
+ x = box->x;
+ y = box->y;
+ xs = box->xs;
+ ys = box->ys;
+
+ buffer_conform(&scr_main, &x, &y, &xs, &ys);
+
+ mouse_hide();
+ video_update(&scr_main, x, y,
+ x, y,
+ xs, ys);
+ mouse_show();
+ }
+ }
+
+ if (box->active) {
+ if (box->text[0] != NULL) {
+ mem_free(box->text[0]);
+ }
+ }
+
+ box->screen_saved = false;
+ box->depth_saved = false;
+ box->active = false;
+}
+
+
+int popup_and_wait(int save_screen) {
+ int error_flag = true;
+ int waiting;
+
+ if (cursor != NULL) {
+ cursor_last = 1;
+ mouse_cursor_sprite(cursor, 1);
+ }
+
+ popup_key = 0;
+
+ if (popup_draw(save_screen, false)) goto done;
+
+ waiting = true;
+ mouse_init_cycle();
+
+ while (waiting) {
+
+ mouse_begin_cycle(false);
+
+ if (keys_any()) {
+ popup_key = keys_get();
+ waiting = false;
+ }
+
+ if (mouse_stop_stroke) waiting = false;
+
+ mouse_end_cycle(false, waiting);
+ }
+
+ popup_destroy();
+
+ error_flag = false;
+
+done:
+ return (error_flag);
+}
+
+
+int popup_and_dont_wait(int save_screen) {
+ int error_flag = true;
+
+ if (cursor != NULL) {
+ cursor_last = 1;
+ mouse_cursor_sprite(cursor, 1);
+ }
+
+ popup_key = 0;
+
+ if (popup_draw(save_screen, false)) goto done;
+
+ error_flag = false;
+
+done:
+ return (error_flag);
+}
+
+
+
+void popup_update_ask(char *string, int maxlen) {
+ int x1, y1, x2, x3, xs, ys, xs2, xs3;
+
+ xs = box->text_xs;
+ ys = (box_param.font->max_y_size + 1);
+ x1 = box->window_x + popup_padding_width;
+ y1 = box->window_y + popup_padding_width + (ys * box->ask_y);
+
+ matte_map_work_screen();
+
+ buffer_rect_fill_pattern(scr_main, x1, y1, xs, ys,
+ x1, y1, xs,
+ POPUP_FILL_COLOR, POPUP_FILL_COLOR_2,
+ box->fill_accum, 0);
+
+ font_set_colors(-1, POPUP_TEXT_COLOR, POPUP_TEXT_COLOR, POPUP_TEXT_COLOR);
+
+ x2 = font_write(box_param.font, &scr_main, box->text[box->ask_y], x1, y1, box_param.font_spacing);
+ xs2 = (font_string_width(box_param.font, "W", box_param.font_spacing) * maxlen) + 4;
+
+ x3 = x2 + 2;
+ xs3 = font_string_width(box_param.font, string, box_param.font_spacing) + 2;
+
+ buffer_rect_fill(scr_main, x2 - 1, y1 - 3, xs2, 1, 0);
+ buffer_rect_fill(scr_main, x2 - 1, y1 + ys, xs2, 1, 0);
+ buffer_rect_fill(scr_main, x2 - 1, y1 - 3, 1, ys + 4, 0);
+ buffer_rect_fill(scr_main, x2 + xs2 - 1, y1 - 3, 1, ys + 4, 0);
+
+ buffer_rect_fill_swap(scr_main, x3 - 1, y1 - 1, xs2 - 4, ys, POPUP_FILL_COLOR, POPUP_HILITE_COLOR);
+ buffer_rect_fill_swap(scr_main, x3 - 1, y1 - 1, xs2 - 4, ys, POPUP_FILL_COLOR_2, POPUP_HILITE_COLOR_2);
+
+ font_set_colors(-1, POPUP_ASK_COLOR, POPUP_ASK_COLOR, POPUP_ASK_COLOR);
+ font_write(box_param.font, &scr_main, string, x3, y1, box_param.font_spacing);
+
+ mouse_hide();
+ video_update(&scr_main, x1, y1 - 3, x1, y1 - 3, xs, ys + 4);
+ mouse_show();
+}
+
+
+int popup_ask_string(char *target, int maxlen, int save_screen) {
+ int error_flag = true;
+ int never_ever;
+ int going, len, mykey;
+ int value;
+ char temp_buf[80];
+
+ never_ever = box_param.erase_on_first;
+
+ popup_esc_key = false;
+
+ Common::strcpy_s(temp_buf, target);
+
+ if (box->text[box->ask_y][strlen(box->text[box->ask_y]) - 1] != ' ') {
+ Common::strcat_s(box->text[box->ask_y], 65536, " ");
+ }
+
+ if (popup_draw(save_screen, false)) goto done;
+
+ popup_update_ask(temp_buf, maxlen);
+
+ going = true;
+
+ keys_disable();
+
+ mouse_init_cycle();
+
+ while (going) {
+ len = strlen(temp_buf);
+ while (!keys_any()) {
+ mouse_begin_cycle(false);
+ if (mouse_stop_stroke) {
+ error_flag = 1;
+ popup_esc_key = true;
+ going = false;
+ goto done;
+ }
+ mouse_end_cycle(false, true);
+ }
+ mykey = keys_get();
+ switch (mykey) {
+ case esc_key:
+ case alt_x_key:
+ case alt_q_key:
+ case ctrl_q_key:
+ case ctrl_x_key:
+ error_flag = 1;
+ popup_esc_key = true;
+ going = false;
+ goto done;
+ break;
+ case enter_key:
+ going = false;
+ break;
+ case pgup_key:
+ case pgdn_key:
+ case home_key:
+ case end_key:
+ if (popup_asking_number) {
+ value = atoi(temp_buf);
+ switch (mykey) {
+ case pgup_key:
+ value--;
+ break;
+ case pgdn_key:
+ value++;
+ break;
+ case home_key:
+ value -= 10;
+ break;
+ case end_key:
+ default:
+ value += 10;
+ break;
+ }
+ mads_itoa(value, temp_buf, 10);
+ never_ever = true;
+ }
+ break;
+
+ case bksp_key:
+ never_ever = false;
+ if (len > 0) {
+ temp_buf[len - 1] = 0;
+ }
+ break;
+ default:
+ if (never_ever) {
+ len = 0;
+ temp_buf[0] = 0;
+ never_ever = false;
+ }
+ if (Common::isPrint(mykey)) {
+ if (len < maxlen) {
+ temp_buf[len] = (byte)mykey;
+ temp_buf[len + 1] = 0;
+ }
+ }
+ break;
+ }
+ popup_update_ask(temp_buf, maxlen);
+ }
+
+ error_flag = false;
+
+done:
+ keys_enable();
+ popup_destroy();
+ Common::strcpy_s(target, 65536, temp_buf);
+ return (error_flag);
+}
+
+
+
+int popup_ask_number(long *value, int maxlen, int save_screen) {
+ int error_flag = true;
+ char temp_buf[80];
+
+ popup_asking_number = true;
+
+ if (value) {
+ ltoa(*value, temp_buf, 10);
+ } else {
+ temp_buf[0] = 0;
+ }
+
+ if (popup_ask_string(temp_buf, maxlen, save_screen)) goto done;
+
+ *value = atol(temp_buf);
+
+ error_flag = false;
+
+done:
+ popup_asking_number = false;
+ return (error_flag);
+}
+
+
+
+int popup_estimate_pieces(int maxlen) {
+ int font_len;
+ int pieces;
+ int estimate;
+
+ font_len = maxlen * (box_param.font->max_x_size + box_param.font_spacing);
+ pieces = ((font_len - 1) / pop_xs(POPUP_TOP)) + 1;
+ estimate = (pieces - box_param.pieces_per_center) >> 1;
+ return (estimate);
+}
+
+
+int popup_get_string(char *target, char *top, char *left, int maxlen) {
+ int result = -1;
+
+ if (!popup_create(popup_estimate_pieces(strlen(top) + 4), POPUP_CENTER, POPUP_CENTER)) {
+ popup_center_string(top, true);
+ popup_write_string("\n");
+ popup_write_string(left);
+ popup_set_ask();
+ popup_write_string("\n");
+ result = popup_ask_string(target, maxlen, true);
+ }
+
+ return (result);
+}
+
+
+int popup_get_long(long *value, char *top, char *left, int maxlen) {
+ int error_flag = true;
+
+ if (!popup_create(popup_estimate_pieces(strlen(top) + 4), POPUP_CENTER, POPUP_CENTER)) {
+ popup_center_string(top, true);
+ popup_write_string("\n");
+ popup_write_string(left);
+ popup_set_ask();
+ popup_write_string("\n");
+ error_flag = popup_ask_number(value, maxlen, true);
+ }
+
+ return (error_flag);
+}
+
+
+int popup_get_number(int *value, char *top, char *left, int maxlen) {
+ int result;
+ long temp;
+
+ temp = *value;
+
+ result = popup_get_long(&temp, top, left, maxlen);
+ if (!result) {
+ *value = (int)temp;
+ }
+ return (result);
+}
+
+
+int popup_alert(int width, char *message_line, ...) {
+ int mykey = -1;
+ int error_flag = true;
+ int popup_created = false;
+ int first_time = true;
+ va_list marker;
+ char *my_message = message_line;
+
+ if (popup_create(popup_estimate_pieces(width), POPUP_CENTER, POPUP_CENTER)) goto done;
+ popup_created = true;
+
+ va_start(marker, message_line);
+ while (my_message != NULL) {
+ popup_center_string(my_message, first_time);
+ my_message = va_arg(marker, char *);
+ first_time = false;
+ }
+
+ error_flag = popup_and_wait(true);
+
+ mykey = popup_key;
+
+done:
+ if (error_flag && popup_created) popup_destroy();
+ return (mykey);
+}
+
+
+int popup_box_load(void) {
+ int error_flag = true;
+ int count;
+ int top_base, bottom_base, left_base, right_base;
+ int extra_x1, extra_y1;
+ int extra_x2, extra_y2;
+ byte special_color;
+ Buffer data_buf;
+
+ data_buf.x = 1; /* A one pixel buffer */
+ data_buf.y = 1;
+ data_buf.data = &special_color;
+
+ if (box_param.series != NULL) {
+ sprite_free(&box_param.series, true);
+ }
+
+ palette_low_search_limit = 0;
+ palette_high_search_limit = POPUP_BASE_COLOR + POPUP_NUM_COLORS;
+
+ for (count = 0; count < POPUP_NUM_COLORS; count++) {
+ color_status[POPUP_BASE_COLOR + count] = 0;
+ }
+
+ box_param.series = sprite_series_load(box_param.name, PAL_MAP_RESERVED);
+ if (box_param.series == NULL) goto done;
+
+ box_param.logo = sprite_series_load("*LOGO.SS", PAL_MAP_RESERVED);
+ box_param.menu = sprite_series_load("*MENU.SS", PAL_MAP_RESERVED);
+
+ if (box_param.menu != NULL) {
+ box_param.menu_left_width = box_param.menu->index[0].xs;
+ box_param.menu_middle_width = box_param.menu->index[1].xs;
+ box_param.menu_right_width = box_param.menu->index[2].xs;
+
+ box_param.menu_text_x_offset = 3;
+ box_param.menu_text_y_offset = 5;
+ box_param.menu_text_x_bonus = 1;
+ box_param.menu_text_y_bonus = 1;
+ }
+
+ mcga_setpal_range(&master_palette, POPUP_BASE_COLOR, POPUP_NUM_COLORS);
+
+ for (count = 0; count < POPUP_NUM_COLORS; count++) {
+ color_status[POPUP_BASE_COLOR + count] |= PAL_RESERVED;
+ }
+
+ sprite_draw(box_param.series, 10, &data_buf, 0, 0);
+ POPUP_FILL_COLOR = special_color;
+ sprite_draw(box_param.series, 11, &data_buf, 0, 0);
+ POPUP_FILL_COLOR_2 = special_color;
+ sprite_draw(box_param.series, 12, &data_buf, 0, 0);
+ POPUP_TEXT_COLOR = special_color;
+
+ sprite_draw(box_param.series, 13, &data_buf, 0, 0);
+ POPUP_DIALOG_TEXT_COLOR = special_color;
+ sprite_draw(box_param.series, 14, &data_buf, 0, 0);
+ POPUP_DIALOG_BUTTON_COLOR_1 = special_color;
+ sprite_draw(box_param.series, 15, &data_buf, 0, 0);
+ POPUP_DIALOG_BUTTON_COLOR_2 = special_color;
+ sprite_draw(box_param.series, 16, &data_buf, 0, 0);
+ POPUP_DIALOG_BORDER_COLOR_1 = special_color;
+ sprite_draw(box_param.series, 17, &data_buf, 0, 0);
+ POPUP_DIALOG_BORDER_COLOR_2 = special_color;
+ sprite_draw(box_param.series, 18, &data_buf, 0, 0);
+ POPUP_DIALOG_SELECT_COLOR = special_color;
+ sprite_draw(box_param.series, 19, &data_buf, 0, 0);
+ POPUP_DIALOG_STRING_COLOR = special_color;
+
+ sprite_draw(box_param.series, 20, &data_buf, 0, 0);
+ POPUP_DIALOG_MENU_TEXT_1 = special_color;
+ sprite_draw(box_param.series, 21, &data_buf, 0, 0);
+ POPUP_DIALOG_MENU_TEXT_2 = special_color;
+ sprite_draw(box_param.series, 22, &data_buf, 0, 0);
+ POPUP_DIALOG_MENU_TEXT_3 = special_color;
+
+
+ top_base = pop_y(POPUP_UPPER_LEFT);
+
+ box_param.top_adjust_y = pop_y(POPUP_TOP) - top_base;
+ box_param.center_adjust_y = pop_y(POPUP_UPPER_CENTER) - top_base;
+ box_param.upper_right_adjust_y = pop_y(POPUP_UPPER_RIGHT) - top_base;
+
+ left_base = pop_x(POPUP_UPPER_LEFT);
+
+ box_param.left_adjust_x = pop_x(POPUP_LEFT) - left_base;
+ box_param.lower_left_adjust_x = pop_x(POPUP_LOWER_LEFT) - left_base;
+
+ bottom_base = pop_y(POPUP_LOWER_LEFT);
+
+ box_param.bottom_adjust_y = pop_y(POPUP_BOTTOM) - bottom_base;
+ box_param.lower_right_adjust_y = pop_y(POPUP_LOWER_RIGHT) - bottom_base;
+
+ right_base = pop_x(POPUP_UPPER_RIGHT);
+
+ box_param.right_adjust_x = pop_x(POPUP_RIGHT) - right_base;
+
+ box_param.offset_y = (pop_y2(POPUP_TOP) - pop_y(POPUP_UPPER_LEFT)) + 1;
+ box_param.offset_x = (pop_x2(POPUP_LEFT) - pop_x(POPUP_UPPER_LEFT)) + 1;
+
+ extra_x1 = pop_xs(POPUP_UPPER_LEFT) - box_param.offset_x;
+ extra_y1 = pop_ys(POPUP_UPPER_LEFT) - box_param.offset_y;
+
+ extra_x2 = pop_x(POPUP_RIGHT) - pop_x(POPUP_UPPER_RIGHT);
+ extra_y2 = pop_y2(POPUP_UPPER_RIGHT) - pop_y2(POPUP_TOP);
+
+ box_param.extra_x = extra_x1 + extra_x2;
+ box_param.extra_y = extra_y1 + extra_y2;
+
+ box_param.pieces_per_center = pop_xs(POPUP_UPPER_CENTER) / pop_xs(POPUP_BOTTOM);
+
+ box_param.erase_on_first = true;
+
+ box_param.font = font_inter;
+ box_param.font_spacing = 0;
+
+ box_param.menu_font = font_menu;
+ box_param.menu_font_spacing = 0;
+
+ error_flag = false;
+
+done:
+ palette_low_search_limit = 0;
+ palette_high_search_limit = 256;
+
+ return (error_flag);
+}
+
+
+/*
+/* popup_activate()
+/*
+/* Causes the specified popup structure to become active (the active
+/* popup structure is considered the target of all popup requests
+/* which do not include a Popup structure or pointer in their
+/* parameter lists).
+*/
+static Popup *popup_activate(Popup *newpop) {
+ if (newpop != NULL) {
+ popup = newpop;
+ }
+ return (popup);
+}
+
+/*
+/* popup_exec_function ()
+/*
+/* Executes the specified function vector for the specified item.
+/* Returns function's return value if function exists; if vector
+/* is NULL, always returns 0. A far pointer to the PopupItem structure
+/* is passed on the stack to the function routine.
+*/
+static int popup_exec_function(PopupItem *item, int function) {
+ if (item == NULL || item->vector[function] == NULL)
+ return 0;
+
+ return item->vector[function](item);
+}
+
+/*
+/* popup_item_init();
+/*
+/* Initializes an empty item.
+*/
+static void popup_item_init(PopupItem *item) {
+ int count;
+
+ item->type = ITEM_BLANK;
+ item->status = 0;
+ item->x = 0;
+ item->y = 0;
+ item->xs = 0;
+ item->ys = 0;
+ item->font_x = 0;
+ item->font_y = 0;
+ item->prompt = NULL;
+ item->buffer = NULL;
+ item->list = NULL;
+
+ for (count = 0; count < POPUP_ITEM_VECTORS; count++) {
+ item->vector[count] = NULL;
+ }
+}
+
+
+/*
+/* popup_dialog_create()
+/*
+/* Sets up popup dialog structure, allocating memory dynamically
+/* if necessary.
+*/
+Popup *popup_dialog_create(byte *memory, long heap_size, int max_items) {
+ int count;
+ byte *block = NULL;
+ word status;
+ long item_memory;
+ Popup *result = NULL;
+ Popup *dlg;
+
+ status = popup_default_status;
+
+ if ((heap_size == 0) && (memory == NULL)) heap_size = 2048;
+ if (!max_items) max_items = 10;
+
+ if (heap_size < (sizeof(Popup) + 400)) goto done;
+
+ if (memory == NULL) {
+
+ status |= POPUP_STATUS_DYNAMIC;
+ block = (byte *)mem_get_name(heap_size, "$popheap");
+ if (block == NULL) goto done;
+
+ dlg = (Popup *)block;
+ memory = block;
+
+ } else {
+
+ dlg = (Popup *)memory;
+
+ }
+
+ heap_declare(&dlg->heap, MODULE_POPUP, (char *)memory + sizeof(Popup),
+ heap_size - sizeof(Popup));
+
+ item_memory = sizeof(PopupItem) * max_items;
+ dlg->item = (PopupItem *)heap_get(&dlg->heap, item_memory);
+ dlg->max_items = max_items;
+ dlg->num_items = 0;
+
+ for (count = 0; count < dlg->max_items; count++) {
+ popup_item_init(&dlg->item[count]);
+ }
+
+ dlg->x = POPUP_CENTER;
+ dlg->y = POPUP_CENTER;
+ dlg->width = 0;
+ dlg->y_position = 0;
+
+ dlg->y_spacing = 2;
+
+ dlg->button_spacing = 4;
+ dlg->button_left_fill = 0;
+ dlg->button_right_fill = 0;
+ dlg->button_bar_color = POPUP_DIALOG_BORDER_COLOR_2;
+
+ status |= POPUP_STATUS_VALID;
+
+ dlg->status = status;
+
+ dlg->active_item = NULL;
+ dlg->enter_item = NULL;
+ dlg->cancel_item = NULL;
+ dlg->string_item = NULL;
+
+ dlg->list_item = NULL;
+ dlg->clear_item = NULL;
+
+ dlg->key = 0;
+ dlg->key_handled = true;
+
+ dlg->mouse_status = 0;
+
+ popup_activate(dlg);
+ result = dlg;
+
+done:
+ if ((block != NULL) && (result != (Popup *)block)) {
+ mem_free(block);
+ }
+ return (result);
+}
+
+
+/*
+/* popup_dialog_destroy()
+/*
+/* Destroys a popup dialog, deallocating any dynamic memory.
+*/
+Popup *popup_dialog_destroy(void) {
+ popup->status &= ~(POPUP_STATUS_VALID);
+
+ if (popup->status & POPUP_STATUS_DYNAMIC) {
+ mem_free(popup);
+ }
+
+ return (NULL);
+}
+
+
+static int extract_keystroke(char *string) {
+ int keystroke = 0;
+ char *mark;
+
+ mark = strchr(string, '~');
+ if (mark != NULL) {
+ keystroke = *(mark + 1);
+ Common::strcpy_s(mark, 65536, mark + 1);
+ }
+
+ return keystroke;
+}
+
+
+static void *popup_heap(long mem_to_get) {
+ return (heap_get(&popup->heap, mem_to_get));
+}
+
+
+static char *string_to_heap(char *string) {
+ char *mem_we_got;
+
+ mem_we_got = (char *)popup_heap(strlen(string) + 1);
+
+ Common::strcpy_s(mem_we_got, 65536, string);
+
+ return (mem_we_got);
+}
+
+
+static void set_prompt(PopupItem *item, const char *string) {
+ char temp_buf[80];
+
+ Common::strcpy_s(temp_buf, string);
+
+ item->keystroke = extract_keystroke(temp_buf);
+ item->prompt = string_to_heap(temp_buf);
+}
+
+
+static PopupItem *item_allocate(int can_be_default) {
+ PopupItem *item;
+
+ if (popup->num_items >= popup->max_items) {
+ error_report(ERROR_POPUP_NO_ITEMS, ERROR, MODULE_POPUP, popup->max_items, 0);
+ }
+
+ item = &popup->item[popup->num_items++];
+
+ if (can_be_default && (popup->active_item == NULL)) {
+ popup->active_item = item;
+ }
+
+ return (item);
+}
+
+
+
+static PopupList *list_allocate(void) {
+ PopupList *list;
+
+ list = (PopupList *)popup_heap(sizeof(PopupList));
+ return (list);
+}
+
+
+static PopupBuffer *buffer_allocate(int size) {
+ PopupBuffer *buffer;
+
+ buffer = (PopupBuffer *)popup_heap(sizeof(PopupBuffer));
+ buffer->data = (char *)popup_heap(size);
+ buffer->max_length = size;
+
+ *buffer->data = 0;
+
+ return (buffer);
+}
+
+
+
+static int popup_font_size(const char *string) {
+ return (font_string_width(box_param.font, string, box_param.font_spacing));
+}
+
+
+static void popup_y_placement(PopupItem *item, int y) {
+ int bottom;
+
+ if (y == POPUP_FILL) {
+ item->y = popup->y_position;
+ popup->y_position += item->ys + popup->y_spacing;
+ } else {
+ item->y = y;
+ bottom = item->y + item->ys + popup->y_spacing;
+ popup->y_position = MAX(popup->y_position, bottom);
+ }
+}
+
+
+
+static void popup_x_width_check(PopupItem *item) {
+ int new_width;
+
+ if (item->x & POPUP_CENTER) {
+ new_width = item->xs;
+ new_width += (new_width & 1);
+ } else if (item->x & POPUP_RIGHT_JUST) {
+ new_width = item->xs + (item->x & (~(POPUP_RIGHT_JUST)));
+ } else {
+ new_width = item->x + item->xs;
+ }
+
+ popup->width = MAX(popup->width, new_width);
+}
+
+
+void popup_width_force(int width) {
+ popup->width = MAX(popup->width, width);
+}
+
+
+static void popup_coord_adjust(PopupItem *item) {
+ if (item->x & POPUP_CENTER) {
+ item->x = popup->x + (popup->xs >> 1) - (item->xs >> 1);
+ } else if (item->x & POPUP_BUTTON_RIGHT) {
+ item->x = (popup->x + popup->xs) - (item->x & ~POPUP_BUTTON_RIGHT);
+ } else if (item->x & POPUP_RIGHT_JUST) {
+ item->x = (popup->x + popup->xs) - ((item->x & ~POPUP_RIGHT_JUST) + item->xs);
+ } else {
+ item->x += popup->x;
+ }
+
+ if (item->y == POPUP_BUTTON_ROW) {
+ item->y = popup->button_y + popup->y;
+ } else {
+ item->y += popup->y;
+ }
+
+ item->font_x = item->x + item->font_x;
+ item->font_y = item->y + item->font_y;
+}
+
+
+static int popup_mouse_refresh(void) {
+ mouse_freeze();
+ mouse_set_work_buffer(scr_main.data, video_x);
+ mouse_set_view_port_loc(0, 0, video_x - 1, video_y - 1);
+ mouse_set_view_port(0, 0);
+ return (mouse_refresh_view_port());
+}
+
+
+static void popup_mouse_refresh_2(int refresh) {
+ if (refresh) mouse_refresh_done();
+ mouse_thaw();
+}
+
+
+static void popup_to_screen(void) {
+ int refresh;
+
+ refresh = popup_mouse_refresh();
+ video_update(&scr_main, box->x, box->y,
+ box->x, box->y,
+ box->xs, box->ys);
+ popup_mouse_refresh_2(refresh);
+}
+
+
+static void popup_item_to_screen(PopupItem *item) {
+ int refresh;
+
+ refresh = popup_mouse_refresh();
+ video_update(&scr_main, item->x, item->y,
+ item->x, item->y,
+ item->xs, item->ys);
+ popup_mouse_refresh_2(refresh);
+}
+
+
+static void popup_screen_clear(void) {
+ buffer_rect_fill_pattern(scr_main,
+ box->window_x, box->window_y, box->window_xs, box->window_ys,
+ box->window_x, box->window_y, box->window_xs,
+ POPUP_FILL_COLOR, POPUP_FILL_COLOR_2, 0, 0);
+}
+
+
+static void popup_item_clear(PopupItem *item) {
+ if (mouse_y > 150 && item->y > 150) {
+ buffer_rect_fill(scr_main, item->x, item->y, item->xs, 1, 0);
+ buffer_rect_fill(scr_main, item->x, item->y, 1, item->ys, 0);
+ buffer_rect_fill(scr_main, item->x, item->y + item->ys, item->xs + 1, 1, 0);
+ buffer_rect_fill(scr_main, item->x + item->xs, item->y, 1, item->ys, 0);
+
+ } else {
+ buffer_rect_fill_pattern(scr_main,
+ item->x, item->y, item->xs, item->ys,
+ box->window_x, box->window_y, box->window_xs,
+ POPUP_FILL_COLOR, POPUP_FILL_COLOR_2, 0, 0);
+ }
+
+}
+
+
+static void popup_redraw_item(PopupItem *item) {
+ popup_item_clear(item);
+ popup_exec_function(item, VECTOR_DRAW);
+ popup_item_to_screen(item);
+}
+
+
+static void popup_update_item(PopupItem *item) {
+ if (item->vector[VECTOR_UPDATE] != NULL) {
+ popup_exec_function(item, VECTOR_UPDATE);
+ } else {
+ popup_redraw_item(item);
+ }
+}
+
+
+static void popup_full_draw(void) {
+ int count;
+ int bar_y;
+ int bar_x;
+ int bar_xs;
+
+ popup_screen_clear();
+
+ for (count = 0; count < popup->num_items; count++) {
+ popup_exec_function(&popup->item[count], VECTOR_DRAW);
+ }
+
+ if (popup->status & POPUP_STATUS_BUTTON) {
+ if (popup->status & POPUP_STATUS_BAR) {
+ if (popup->status & POPUP_STATUS_STEAL) {
+ bar_x = box->window_x;
+ bar_xs = box->window_xs;
+ } else {
+ bar_x = popup->x - popup_padding_width;
+ bar_xs = popup->xs + (popup_padding_width << 1);
+ }
+ bar_y = popup->button_y - (popup_padding_width + 1);
+ buffer_rect_fill(scr_main, bar_x, bar_y,
+ bar_xs, 1, (byte)popup->button_bar_color);
+ }
+ }
+
+ popup_to_screen();
+}
+
+
+static void popup_activate_item(PopupItem *item) {
+ PopupItem *old_active;
+
+ old_active = popup->active_item;
+ popup->active_item = item;
+
+ popup_update_item(old_active);
+ popup_update_item(popup->active_item);
+ popup_update_item(popup->enter_item);
+}
+
+
+
+static PopupItem *popup_next_item(PopupItem *item, int activate, int any_non_button) {
+ int count;
+ int found = -1;
+ PopupItem *result;
+
+ if (item == NULL) {
+ result = &popup->item[0];
+ goto done;
+ }
+
+ if (any_non_button != 1) {
+ any_non_button = (any_non_button != 0) || ((item->type != ITEM_BUTTON) && !(item->status & ITEM_STATUS_INERT));
+ if (any_non_button)
+ any_non_button = -1;
+ }
+
+ for (count = 0; (found < 0) && (count < popup->num_items); count++) {
+ if (item == &popup->item[count]) found = count;
+ }
+
+ if ((found >= popup->num_items - 1) || (found < 0)) {
+ result = &popup->item[0];
+ } else {
+ result = &popup->item[found + 1];
+ }
+
+ if (activate && (result->status & ITEM_STATUS_INERT)) {
+ result = popup_next_item(result, true, any_non_button);
+ }
+
+ if (any_non_button != 1) {
+ any_non_button = (any_non_button != 0) || ((result->type != ITEM_BUTTON) && !(result->status & ITEM_STATUS_INERT));
+ if (any_non_button) any_non_button = -1;
+ }
+
+ if (activate && (result == popup->enter_item) && any_non_button && (any_non_button != 1)) {
+ result = popup_next_item(result, true, 1);
+ }
+
+done:
+ return (result);
+}
+
+
+static PopupItem *popup_last_item(PopupItem *item, int activate, int any_non_button) {
+ int found = -1;
+ int count;
+ PopupItem *result;
+
+ if (item == NULL) {
+ result = &popup->item[popup->num_items - 1];
+ goto done;
+ }
+
+ if (any_non_button != 1) {
+ any_non_button = (any_non_button != 0) || ((item->type != ITEM_BUTTON) && !(item->status & ITEM_STATUS_INERT));
+ if (any_non_button) any_non_button = -1;
+ }
+
+ for (count = 0; (found < 0) && (count < popup->num_items); count++) {
+ if (item == &popup->item[count]) found = count;
+ }
+
+ if (found <= 0) {
+ result = &popup->item[popup->num_items - 1];
+ } else {
+ result = &popup->item[found - 1];
+ }
+
+ if (activate && (result->status & ITEM_STATUS_INERT)) {
+ result = popup_last_item(result, true, any_non_button);
+ }
+
+ if (any_non_button != 1) {
+ any_non_button = (any_non_button != 0) || ((result->type != ITEM_BUTTON) && !(result->status & ITEM_STATUS_INERT));
+ if (any_non_button) any_non_button = -1;
+ }
+
+ if (activate && (result == popup->enter_item) && any_non_button && (any_non_button != 1)) {
+ result = popup_last_item(result, true, 1);
+ }
+
+done:
+ return (result);
+}
+
+
+
+static int popup_in_item(PopupItem *item) {
+ int in_item;
+ int x, y;
+ int x2, y2;
+
+ x = item->x;
+ y = item->y;
+ x2 = x + item->xs - 1;
+ y2 = y + item->ys - 1;
+
+ in_item = ((mouse_x >= x) && (mouse_x <= x2) &&
+ (mouse_y >= y) && (mouse_y <= y2));
+
+ return (in_item);
+}
+
+
+static void popup_find_item(void) {
+ int count;
+
+ popup->mouse_item = NULL;
+
+ for (count = 0; (popup->mouse_item == NULL) && (count < popup->num_items); count++) {
+ if (popup_in_item(&popup->item[count])) {
+ popup->mouse_item = &popup->item[count];
+ }
+ }
+
+ if (popup->mouse_item != NULL) {
+ popup_activate_item(popup->mouse_item);
+ }
+}
+
+
+static void popup_double_box(int x, int y, int xs, int ys,
+ byte color, byte color2) {
+ if (popup->status & POPUP_STATUS_BUTTON) {
+ buffer_rect_fill(scr_main, x, y, xs, 1, color);
+ buffer_rect_fill(scr_main, x, y, 1, ys, color);
+ buffer_rect_fill(scr_main, x, y + ys, xs + 1, 1, color);
+ buffer_rect_fill(scr_main, x + xs, y, 1, ys, color);
+
+ } else {
+ buffer_rect_fill(scr_main, x + 1, y, xs - 2, 1, color);
+ buffer_rect_fill(scr_main, x, y + 1, 2, 1, color);
+ buffer_rect_fill(scr_main, x + 2, y + 1, xs - 2, 1, color2);
+
+ buffer_rect_fill(scr_main, x, y + 2, 1, ys - 3, color);
+ buffer_rect_fill(scr_main, x + 1, y + 2, 1, ys - 2, color2);
+
+ buffer_rect_fill(scr_main, x + xs - 2, y + 2, 1, ys - 4, color);
+ buffer_rect_fill(scr_main, x + xs - 1, y + 2, 1, ys - 3, color2);
+
+ buffer_rect_fill(scr_main, x + 2, y + ys - 2, xs - 4, 1, color);
+ buffer_rect_fill(scr_main, x + xs - 2, y + ys - 2, 1, 1, color2);
+ buffer_rect_fill(scr_main, x + 1, y + ys - 1, xs - 2, 1, color2);
+ }
+}
+
+
+static void popup_double_box_2(int x, int y, int xs, int ys,
+ byte color, byte color2) {
+ int count;
+
+ for (count = 0; count < 2; count++) {
+ buffer_rect_fill(scr_main, x, y, xs, 1, color);
+ buffer_rect_fill(scr_main, x, y + ys - 1, xs, 1, color);
+ buffer_rect_fill(scr_main, x, y, 1, ys, color);
+ buffer_rect_fill(scr_main, x + xs - 1, y, 1, ys, color);
+
+ x++;
+ y++;
+ xs -= 2;
+ ys -= 2;
+ color = color2;
+ }
+}
+
+
+
+
+
+/*******************************************************/
+/* Item service routines */
+/*******************************************************/
+
+/***********/
+/* Buttons */
+/***********/
+
+static int popup_button_x_size(PopupItem *item) {
+ int size;
+
+ size = popup_font_size(item->prompt);
+ size += 6 + 2;
+
+ return (size);
+}
+
+
+static int popup_button_y_size(PopupItem *item) {
+ item = NULL; /* delete if this routine is to be used */
+ return (box_param.font->max_y_size + 4 + 2);
+}
+
+
+static int popup_button_draw(PopupItem *item) {
+ byte color;
+ byte color2;
+ byte color_text;
+ int selected;
+ int big_button;
+ int x, y;
+ int refresh;
+
+ selected = (popup->active_item == item) && (item->status & ITEM_STATUS_ACTIVE) != 0;
+
+ if (selected /* && (POPUP_DIALOG_BUTTON_COLOR_1 == POPUP_DIALOG_BUTTON_COLOR_2) */) {
+ buffer_rect_fill(scr_main, item->x, item->y, item->xs, 1, POPUP_DIALOG_TEXT_COLOR);
+ buffer_rect_fill(scr_main, item->x, item->y, 1, item->ys, POPUP_DIALOG_TEXT_COLOR);
+ buffer_rect_fill(scr_main, item->x, item->y + item->ys, item->xs + 1, 1, POPUP_DIALOG_TEXT_COLOR);
+ buffer_rect_fill(scr_main, item->x + item->xs, item->y, 1, item->ys, POPUP_DIALOG_TEXT_COLOR);
+
+ refresh = popup_mouse_refresh();
+ video_update(&scr_main, item->x, item->y,
+ item->x, item->y,
+ item->xs + 5, item->ys + 5);
+ popup_mouse_refresh_2(refresh);
+ }
+
+ /* color = selected ? POPUP_ASK_COLOR : POPUP_TEXT_COLOR; */
+
+ if (popup->active_item->type == ITEM_BUTTON) {
+ big_button = (item == popup->active_item);
+ } else {
+ big_button = (item == popup->enter_item);
+ }
+
+ color_text = POPUP_DIALOG_TEXT_COLOR;
+ if (!selected) {
+ color = POPUP_DIALOG_BUTTON_COLOR_1;
+ color2 = POPUP_DIALOG_BUTTON_COLOR_2;
+ } else {
+ color2 = POPUP_DIALOG_BUTTON_COLOR_1;
+ color = POPUP_DIALOG_BUTTON_COLOR_2;
+ }
+
+ if (!selected) {
+ if (!big_button) {
+ buffer_rect_fill(scr_main, item->x, item->y, item->xs, 1, color2);
+ buffer_rect_fill(scr_main, item->x, item->y, 1, item->ys, color2);
+ buffer_rect_fill(scr_main, item->x, item->y + item->ys, item->xs + 1, 1, color2);
+ buffer_rect_fill(scr_main, item->x + item->xs, item->y, 1, item->ys, color2);
+
+ } else {
+ popup_double_box(item->x, item->y, item->xs, item->ys, color, color2);
+ }
+ }
+
+ font_set_colors(-1, color_text, color_text, color_text);
+
+ x = item->font_x;
+ y = item->font_y;
+
+ font_write(box_param.font, &scr_main, item->prompt,
+ x + 1, y + 1, box_param.font_spacing);
+
+ if (!(popup->status & POPUP_STATUS_EXIT)) {
+ refresh = popup_mouse_refresh();
+ video_update(&scr_main, item->x, item->y,
+ item->x, item->y,
+ item->xs + 5, item->ys + 5);
+ popup_mouse_refresh_2(refresh);
+ }
+
+ return 0;
+}
+
+
+
+
+
+static int popup_button_mouse(PopupItem *item) {
+ int in_item;
+ int count;
+ word status;
+ char *text_locator;
+ PopupList *list;
+ PopupBuffer *buffer;
+
+ status = item->status;
+
+ in_item = popup_in_item(item);
+
+ if (mouse_stroke_going && !in_item) {
+ for (count = 0; count < popup->num_items; count++) {
+ if (popup_in_item(&popup->item[count]) && (popup->item[count].type == ITEM_BUTTON)) {
+ popup->mouse_item = &popup->item[count];
+ popup_activate_item(popup->mouse_item);
+ popup_exec_function(popup->mouse_item, VECTOR_MOUSE);
+ goto done;
+ }
+ }
+ }
+
+ if (mouse_stroke_going && in_item) {
+ item->status |= ITEM_STATUS_ACTIVE;
+ } else {
+ item->status &= ~ITEM_STATUS_ACTIVE;
+ }
+
+ if (status != item->status) {
+ popup_redraw_item(item);
+ }
+
+ if (mouse_stop_stroke && popup_in_item(item)) {
+ if (item == popup->clear_item) {
+ list = popup->list_item->list;
+ popup->list_item->status &= ~(ITEM_STATUS_DIRTY | ITEM_STATUS_VIRGIN);
+ text_locator = popup_savelist_string(popup->list_item, list->picked_element);
+ *text_locator = 0;
+ popup_redraw_item(popup->list_item);
+ } else {
+
+ if (item != popup->cancel_item) {
+ if (popup->list_item != NULL) {
+ if (popup->list_item->status & ITEM_STATUS_DIRTY) {
+ list = popup->list_item->list;
+ buffer = popup->list_item->buffer;
+ Common::strcpy_s(popup_savelist_string(popup->list_item, list->picked_element), 65536, buffer->data);
+ popup->list_item->status &= ~ITEM_STATUS_DIRTY;
+ }
+ }
+ }
+
+ popup->status |= POPUP_STATUS_EXIT;
+ }
+ }
+
+done:
+ ;
+ return 0;
+}
+
+
+static int popup_button_key(PopupItem *item) {
+ int count;
+
+ for (count = 0; count < popup->num_items; count++) {
+ if (popup->item[count].type == ITEM_BUTTON) {
+ if (toupper(popup->key) == popup->item[count].keystroke) {
+ popup_activate_item(&popup->item[count]);
+ popup->status |= POPUP_STATUS_EXIT;
+ popup->key_handled = true;
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+static void popup_button_create(PopupItem *item) {
+ item->vector[VECTOR_X_SIZE] = popup_button_x_size;
+ item->vector[VECTOR_Y_SIZE] = popup_button_y_size;
+ item->vector[VECTOR_DRAW] = popup_button_draw;
+ item->vector[VECTOR_MOUSE] = popup_button_mouse;
+ item->vector[VECTOR_KEY] = popup_button_key;
+}
+
+
+
+
+
+/****************/
+/* Menu Buttons */
+/****************/
+
+static int popup_menu_x_size(PopupItem *item) {
+ int size;
+ int middles;
+ PopupList *list;
+
+ list = item->list;
+
+ size = box_param.menu_left_width + box_param.menu_right_width;
+
+ middles = 0;
+
+ while ((size < list->box_xs) && box_param.menu_middle_width) {
+ size += box_param.menu_middle_width;
+ middles++;
+ }
+
+ item->sprite = middles;
+
+ return (size);
+}
+
+
+static int popup_menu_y_size(PopupItem *item) {
+ item = NULL; /* delete if this routine is to be used */
+ return(box_param.menu->index[0].ys);
+}
+
+
+static int popup_menu_draw(PopupItem *item) {
+ int count;
+ int selected;
+ int x, y;
+ int left_sprite;
+ int middle_sprite;
+ int right_sprite;
+ int font_size;
+ int center_xs = 0;
+ char temp_buf[256];
+ char *mark;
+ char *text_locator;
+ PopupList *list;
+
+ list = item->list;
+
+ selected = (popup->active_item == item) && (item->status & ITEM_STATUS_ACTIVE) != 0;
+
+ left_sprite = 1;
+ middle_sprite = 2;
+ right_sprite = 3;
+
+ if (selected) {
+ left_sprite = 4;
+ middle_sprite = 5;
+ right_sprite = 6;
+ }
+
+ x = item->x;
+ y = item->y;
+
+ sprite_draw(box_param.menu, left_sprite, &scr_main, x, y);
+
+ x += box_param.menu_left_width;
+
+ for (count = 0; count < item->sprite; count++) {
+ sprite_draw(box_param.menu, middle_sprite, &scr_main, x, y);
+ x += box_param.menu_middle_width;
+ }
+
+ sprite_draw(box_param.menu, right_sprite, &scr_main, x, y);
+
+ Common::strcpy_s(temp_buf, 65536, item->prompt);
+ mark = strchr(temp_buf, '@');
+ if (mark != NULL) {
+ *mark = 0;
+ center_xs = font_string_width(box_param.menu_font, temp_buf, box_param.menu_font_spacing);
+ text_locator = list->data + (list->picked_element * list->element_offset);
+ Common::strcat_s(temp_buf, text_locator);
+ }
+
+ font_size = font_string_width(box_param.menu_font, temp_buf, box_param.menu_font_spacing);
+
+ if (mark != NULL) {
+ x = item->x + (((item->xs >> 1) + list->extra_xs) - center_xs);
+ } else {
+ x = item->x + ((item->xs >> 1) - (font_size >> 1));
+ }
+ y = item->font_y;
+
+ if (selected) {
+ x += box_param.menu_text_x_bonus;
+ y += box_param.menu_text_y_bonus;
+ }
+
+ font_set_colors(-1, POPUP_DIALOG_MENU_TEXT_1,
+ POPUP_DIALOG_MENU_TEXT_2,
+ POPUP_DIALOG_MENU_TEXT_3);
+
+ font_write(box_param.menu_font, &scr_main, temp_buf,
+ x, y, box_param.menu_font_spacing);
+
+ return 0;
+}
+
+
+
+
+
+static int popup_menu_mouse(PopupItem *item) {
+ int force_redraw = false;
+ int in_item;
+ int count;
+ word status;
+ PopupList *list;
+
+ list = item->list;
+
+ status = item->status;
+
+ in_item = popup_in_item(item);
+
+ if (mouse_stroke_going && !in_item) {
+ for (count = 0; count < popup->num_items; count++) {
+ if (popup_in_item(&popup->item[count]) && (popup->item[count].type == ITEM_MENU)) {
+ popup->mouse_item = &popup->item[count];
+ popup_activate_item(popup->mouse_item);
+ popup_exec_function(popup->mouse_item, VECTOR_MOUSE);
+ goto done;
+ }
+ }
+ }
+
+ if (mouse_stroke_going && in_item) {
+ item->status |= ITEM_STATUS_ACTIVE;
+ } else {
+ item->status &= ~ITEM_STATUS_ACTIVE;
+ }
+
+ if (mouse_stop_stroke && popup_in_item(item)) {
+ if (list->elements > 1) {
+ list->picked_element = (list->picked_element + 1) % list->elements;
+ } else {
+ popup->status |= POPUP_STATUS_EXIT;
+ }
+ force_redraw = true;
+ }
+
+ if (force_redraw || (status != item->status)) {
+ popup_redraw_item(item);
+ }
+
+done:
+ ;
+ return 0;
+}
+
+
+static int popup_menu_key(PopupItem *item) {
+ return 0;
+}
+
+
+static void popup_menu_create(PopupItem *item) {
+ item->vector[VECTOR_X_SIZE] = popup_menu_x_size;
+ item->vector[VECTOR_Y_SIZE] = popup_menu_y_size;
+ item->vector[VECTOR_DRAW] = popup_menu_draw;
+ item->vector[VECTOR_MOUSE] = popup_menu_mouse;
+ item->vector[VECTOR_KEY] = popup_menu_key;
+}
+
+
+
+/*****************/
+/* Text Messages */
+/*****************/
+
+
+static int popup_message_x_size(PopupItem *item) {
+ return popup_font_size(item->prompt);
+}
+
+
+static int popup_message_y_size(PopupItem *item) {
+ item = NULL; /* delete if this routine is to be used */
+ return box_param.font->max_y_size;
+}
+
+
+static int popup_message_draw(PopupItem *item) {
+ font_set_colors(-1, POPUP_DIALOG_TEXT_COLOR,
+ POPUP_DIALOG_TEXT_COLOR,
+ POPUP_DIALOG_TEXT_COLOR);
+ font_write(box_param.font, &scr_main, item->prompt,
+ item->font_x, item->font_y, box_param.font_spacing);
+ return 0;
+}
+
+
+static void popup_message_create(PopupItem *item) {
+ item->vector[VECTOR_X_SIZE] = popup_message_x_size;
+ item->vector[VECTOR_Y_SIZE] = popup_message_y_size;
+ item->vector[VECTOR_DRAW] = popup_message_draw;
+}
+
+
+/******************/
+/* static Sprites */
+/******************/
+
+static int popup_sprite_x_size(PopupItem *item) {
+ return (item->series->index[item->sprite - 1].xs);
+}
+
+
+static int popup_sprite_y_size(PopupItem *item) {
+ return (item->series->index[item->sprite - 1].ys);
+}
+
+
+static int popup_sprite_draw(PopupItem *item) {
+ sprite_draw(item->series, item->sprite, &scr_main,
+ item->x, item->y);
+ return 0;
+}
+
+static void popup_sprite_create(PopupItem *item) {
+ item->vector[VECTOR_X_SIZE] = popup_sprite_x_size;
+ item->vector[VECTOR_Y_SIZE] = popup_sprite_y_size;
+ item->vector[VECTOR_DRAW] = popup_sprite_draw;
+}
+
+
+/**********************/
+/* Complex Save Lists */
+/**********************/
+
+static int popup_savelist_x_size(PopupItem *item) {
+ int size;
+ int work_size;
+ int number_width;
+ int scroll_width;
+ PopupList *list;
+
+ list = item->list;
+
+ size = list->box_xs;
+
+ work_size = size;
+ work_size -= 2;
+
+ number_width = popup_font_size("94") + 3;
+ scroll_width = popup_font_size("<") + 4;
+
+ list->extra_xs = number_width;
+ list->scroll.xs = scroll_width;
+
+ work_size -= (number_width + scroll_width + 4);
+
+ list->list_xs = work_size;
+
+ return (size);
+}
+
+
+static int popup_savelist_y_size(PopupItem *item) {
+ int size;
+ int row_size;
+ PopupList *list;
+
+ list = item->list;
+
+ row_size = box_param.font->max_y_size + 2;
+ list->list_ys = row_size;
+
+ size = (row_size * list->rows) + 4;
+ list->scroll.ys = size - 4;
+ list->extra_ys = size - 4;
+ list->box_ys = size;
+
+ list->scroll.arrow_size = (box_param.font->max_y_size) + 2;
+
+ return (size);
+}
+
+
+static int popup_savelist_adjust(PopupItem *item) {
+ PopupList *list;
+
+ list = item->list;
+
+ list->box_x += item->x;
+ list->list_x += item->x;
+ list->extra_x += item->x;
+ list->scroll.x += item->x;
+ list->font_x += item->x;
+
+ list->box_y += item->y;
+ list->list_y += item->y;
+ list->extra_y += item->y;
+ list->scroll.y += item->y;
+ list->font_y += item->y;
+
+ list->scroll.arrow_1_base += item->y;
+ list->scroll.arrow_2_base += item->y;
+
+ return 0;
+}
+
+
+static char *popup_savelist_string(PopupItem *item, int element) {
+ char *text_locator;
+ PopupList *list;
+
+ list = item->list;
+
+ text_locator = list->data + (list->element_offset * element);
+
+ return (text_locator);
+}
+
+
+
+static int popup_savelist_vertical(PopupItem *item, int relative) {
+ int y;
+ PopupList *list;
+
+ list = item->list;
+
+ y = list->list_y + (list->list_ys * relative);
+
+ return (y);
+}
+
+
+static void popup_savelist_number_draw(PopupItem *item, int relative, int number) {
+ char temp_buf[10];
+ int x, y;
+ PopupList *list;
+
+ list = item->list;
+
+ mads_itoa(number, temp_buf, 10);
+
+ x = list->extra_x + popup_font_size("94") + 1 - popup_font_size(temp_buf);
+ y = popup_savelist_vertical(item, relative) + 1;
+
+ font_set_colors(-1, POPUP_DIALOG_TEXT_COLOR,
+ POPUP_DIALOG_TEXT_COLOR,
+ POPUP_DIALOG_TEXT_COLOR);
+ font_write(box_param.font, &scr_main,
+ temp_buf, x, y, box_param.font_spacing);
+}
+
+
+static void popup_savelist_element_draw(PopupItem *item, int element) {
+ int relative;
+ int color;
+ int x, y;
+ char temp_buf[256];
+ char *text_locator;
+ PopupList *list;
+
+ list = item->list;
+
+ relative = element - list->base_element;
+ if ((relative < 0) || (relative >= list->rows)) goto done;
+
+ popup_savelist_number_draw(item, relative, element + 1);
+
+ x = list->list_x;
+ y = popup_savelist_vertical(item, relative);
+
+ if (element == list->picked_element) {
+ buffer_rect_fill(scr_main, x, y, list->list_xs, list->list_ys, POPUP_DIALOG_SELECT_COLOR);
+ color = POPUP_DIALOG_STRING_COLOR;
+ } else {
+ color = POPUP_DIALOG_TEXT_COLOR;
+ }
+
+ if ((element == list->picked_element) && (item->status & ITEM_STATUS_DIRTY)) {
+ Common::strcpy_s(temp_buf, item->buffer->data);
+ } else {
+ text_locator = popup_savelist_string(item, element);
+ Common::strcpy_s(temp_buf, text_locator);
+ if (!strlen(temp_buf) && (item->prompt != NULL) && (element != list->picked_element)) {
+ Common::strcpy_s(temp_buf, item->prompt);
+ }
+ }
+
+ if ((element == list->picked_element) &&
+ (item->status & ITEM_STATUS_INPUT) &&
+ !(popup->status & POPUP_STATUS_EXIT)) {
+ Common::strcat_s(temp_buf, "_");
+ }
+
+ while (strlen(temp_buf) && (popup_font_size(temp_buf) > (list->list_xs - 2))) {
+ temp_buf[strlen(temp_buf) - 1] = 0;
+ }
+
+ font_set_colors(-1, color, color, color);
+ font_write(box_param.font, &scr_main,
+ temp_buf, x + 1, y + 1, box_param.font_spacing);
+
+done:
+ ;
+}
+
+
+static void popup_savelist_full_draw(PopupItem *item) {
+ int count;
+ int element;
+
+ for (count = 0; count < item->list->rows; count++) {
+ element = count + item->list->base_element;
+ if (element < item->list->elements) {
+ popup_savelist_element_draw(item, element);
+ }
+ }
+}
+
+
+static void popup_savelist_scroll_draw(PopupItem *item) {
+ int count;
+ int x, y;
+ int mask;
+ byte color;
+ byte color2;
+ char arrow[2];
+ PopupList *list;
+
+ list = item->list;
+
+ color = POPUP_DIALOG_BORDER_COLOR_1;
+ color2 = POPUP_DIALOG_BORDER_COLOR_2;
+
+ /* Scroll Bar */
+ buffer_rect_fill(scr_main, list->scroll.x, list->scroll.y,
+ 1, list->scroll.ys, color);
+ buffer_rect_fill(scr_main, list->scroll.x + 1, list->scroll.y,
+ 1, list->scroll.ys, color2);
+
+ buffer_rect_fill(scr_main, list->scroll.x, list->scroll.arrow_1_base + list->scroll.arrow_size,
+ list->scroll.xs, 1, color);
+ buffer_rect_fill(scr_main, list->scroll.x, list->scroll.arrow_1_base + list->scroll.arrow_size + 1,
+ list->scroll.xs, 1, color2);
+
+ buffer_rect_fill(scr_main, list->scroll.x, list->scroll.arrow_2_base - 2,
+ list->scroll.xs, 1, color);
+ buffer_rect_fill(scr_main, list->scroll.x, list->scroll.arrow_2_base - 1,
+ list->scroll.xs, 1, color2);
+
+ arrow[1] = 0;
+
+ for (count = 0; count < 2; count++) {
+ switch (count) {
+ case 0:
+ y = list->scroll.arrow_1_base;
+ arrow[0] = '<';
+ mask = SCROLL_STATUS_UP;
+ break;
+
+ case 1:
+ default:
+ y = list->scroll.arrow_2_base;
+ arrow[0] = '>';
+ mask = SCROLL_STATUS_DOWN;
+ break;
+ }
+
+ x = list->scroll.x + 2;
+
+ if (list->scroll.status & mask) {
+ buffer_rect_fill(scr_main, x, y,
+ list->scroll.xs - 2, list->scroll.arrow_size,
+ POPUP_DIALOG_SELECT_COLOR);
+ }
+
+ x += 1;
+ y += 1;
+
+ color = POPUP_DIALOG_TEXT_COLOR;
+ font_set_colors(-1, color, color, color);
+ font_write(box_param.font, &scr_main, arrow, x, y, box_param.font_spacing);
+ }
+}
+
+
+static void popup_savelist_scroll_clear(PopupItem *item) {
+ PopupList *list;
+
+ list = item->list;
+
+ buffer_rect_fill_pattern(scr_main,
+ list->scroll.x, list->scroll.y,
+ list->scroll.xs, list->scroll.ys,
+ box->window_x, box->window_y, box->window_xs,
+ POPUP_FILL_COLOR, POPUP_FILL_COLOR_2, 0, 0);
+}
+
+
+static void popup_savelist_item_clear(PopupItem *item, int relative) {
+ int x, y;
+ PopupList *list;
+
+ list = item->list;
+
+ x = list->list_x;
+ y = popup_savelist_vertical(item, relative);
+
+ buffer_rect_fill_pattern(scr_main, x, y,
+ list->list_xs, list->list_ys,
+ box->window_x, box->window_y, box->window_xs,
+ POPUP_FILL_COLOR, POPUP_FILL_COLOR_2, 0, 0);
+
+ x = list->extra_x;
+
+ buffer_rect_fill_pattern(scr_main, x, y,
+ list->extra_xs - 2, list->list_ys,
+ box->window_x, box->window_y, box->window_xs,
+ POPUP_FILL_COLOR, POPUP_FILL_COLOR_2, 0, 0);
+
+}
+
+
+
+
+static void popup_savelist_scroll_to_screen(PopupItem *item) {
+ int refresh;
+ PopupList *list;
+
+ list = item->list;
+
+ refresh = popup_mouse_refresh();
+ video_update(&scr_main, list->scroll.x, list->scroll.y,
+ list->scroll.x, list->scroll.y,
+ list->scroll.xs, list->scroll.ys);
+ popup_mouse_refresh_2(refresh);
+}
+
+
+
+static void popup_savelist_item_to_screen(PopupItem *item, int relative) {
+ int x, y;
+ int refresh;
+ PopupList *list;
+
+ list = item->list;
+
+ x = list->list_x;
+ y = popup_savelist_vertical(item, relative);
+
+ refresh = popup_mouse_refresh();
+ video_update(&scr_main, x, y, x, y, list->list_xs, list->list_ys);
+ popup_mouse_refresh_2(refresh);
+}
+
+
+static void popup_savelist_scroll_refresh(PopupItem *item) {
+ popup_savelist_scroll_clear(item);
+ popup_savelist_scroll_draw(item);
+ popup_savelist_scroll_to_screen(item);
+}
+
+
+static void popup_savelist_item_refresh(PopupItem *item, int element) {
+ int relative;
+
+ relative = element - item->list->base_element;
+
+ popup_savelist_item_clear(item, relative);
+ if (element <= item->list->elements) {
+ popup_savelist_element_draw(item, element);
+ }
+ popup_savelist_item_to_screen(item, relative);
+}
+
+
+static int popup_savelist_draw(PopupItem *item) {
+ byte color;
+ byte color2;
+ PopupList *list;
+
+ list = item->list;
+
+ color = POPUP_DIALOG_BORDER_COLOR_1;
+ color2 = POPUP_DIALOG_BORDER_COLOR_2;
+
+ /* Basic box */
+ popup_double_box_2(item->x, item->y, item->xs, item->ys, color, color2);
+ /*
+ buffer_rect_fill (scr_main, item->x, item->y,
+ item->xs, 1,
+ color);
+ buffer_rect_fill (scr_main, item->x, item->y,
+ 1, item->ys,
+ color);
+ buffer_rect_fill (scr_main, item->x + item->xs - 1, item->y,
+ 1, item->ys,
+ color);
+ buffer_rect_fill (scr_main, item->x, item->y + item->ys - 1,
+ item->xs, 1,
+ color);
+ */
+
+ /* Number list */
+ buffer_rect_fill(scr_main, list->extra_x + list->extra_xs - 2, list->extra_y,
+ 1, list->extra_ys, color);
+ buffer_rect_fill(scr_main, list->extra_x + list->extra_xs - 1, list->extra_y,
+ 1, list->extra_ys, color2);
+
+
+ popup_savelist_full_draw(item);
+ popup_savelist_scroll_draw(item);
+
+ return 0;
+}
+
+
+static void popup_adjust_elements(PopupList *list) {
+ list->base_element = MAX(0, list->base_element);
+ list->base_element = MIN(list->base_element, list->elements - 1);
+ list->picked_element = MAX(list->base_element, list->picked_element);
+ list->picked_element = MIN(list->picked_element, list->base_element + list->rows - 1);
+ list->picked_element = MIN(list->picked_element, list->elements - 1);
+}
+
+
+
+
+static int popup_savelist_mouse(PopupItem *item) {
+ bool in_scroll_bar;
+ bool in_up_arrow;
+ bool in_down_arrow;
+ bool in_main_box;
+ bool in_main_range;
+ int update_sign;
+ int force_update;
+ int old_status;
+ int picked_element;
+ int base_element;
+ int y, relative, actual;
+ long now_clock;
+
+ PopupList *list;
+
+ list = item->list;
+
+ picked_element = list->picked_element;
+ base_element = list->base_element;
+
+ in_scroll_bar = ((mouse_x >= list->scroll.x) &&
+ (mouse_x <= (list->scroll.x + list->scroll.xs - 1)) &&
+ (mouse_y >= list->scroll.y) &&
+ (mouse_y <= (list->scroll.y + list->scroll.ys - 1)));
+
+ in_up_arrow = in_scroll_bar && (mouse_y <= (list->scroll.arrow_1_base + list->scroll.arrow_size));
+ in_down_arrow = in_scroll_bar && (mouse_y >= (list->scroll.arrow_2_base - 1));
+
+ in_main_box = popup_in_item(item) && !in_scroll_bar;
+ in_main_range = ((mouse_y > item->y) && (mouse_y < (item->y + item->ys - 1)));
+
+ force_update = mouse_start_stroke || (item->status & ITEM_STATUS_FORCED) != 0;
+
+ if (mouse_start_stroke) {
+ if (item->status & ITEM_STATUS_DIRTY) {
+ item->status &= ~ITEM_STATUS_DIRTY;
+ }
+
+ item->status &= ~ITEM_STATUS_VIRGIN;
+
+ popup->mouse_status = 0;
+ if (in_scroll_bar) {
+ popup->mouse_status |= POPUP_MOUSE_SCROLL;
+ }
+ if (in_up_arrow) {
+ popup->mouse_status |= POPUP_MOUSE_UP;
+ }
+ if (in_down_arrow) {
+ popup->mouse_status |= POPUP_MOUSE_DOWN;
+ }
+ }
+
+ old_status = list->scroll.status;
+
+ if (mouse_stroke_going) {
+ list->scroll.status = 0;
+ update_sign = 0;
+ if (popup->mouse_status & POPUP_MOUSE_SCROLL) {
+ if (popup->mouse_status & POPUP_MOUSE_UP) {
+ if (in_up_arrow) {
+ list->scroll.status = SCROLL_STATUS_UP;
+ update_sign = -1;
+ }
+ }
+
+ if (popup->mouse_status & POPUP_MOUSE_DOWN) {
+ if (in_down_arrow) {
+ list->scroll.status = SCROLL_STATUS_DOWN;
+ update_sign = 1;
+ }
+ }
+
+ if (mouse_button) update_sign = update_sign << 2;
+
+ if (update_sign && (force_update || (old_status != list->scroll.status))) {
+ list->base_element += update_sign;
+ popup_adjust_elements(list);
+ if ((update_sign < 0) && (list->base_element == base_element)) {
+ list->picked_element--;
+ popup_adjust_elements(list);
+ }
+ }
+
+ } else {
+
+ if (in_main_range) {
+ y = mouse_y - (item->y + 2);
+ relative = y / list->list_ys;
+ if (relative < 0) relative = 0;
+ if (relative >= list->rows) relative = list->rows - 1;
+
+ actual = list->base_element + relative;
+
+ if (actual <= list->elements) {
+ list->picked_element = actual;
+ }
+
+ item->status |= ITEM_STATUS_IN_RANGE;
+
+ } else {
+
+ if (mouse_y <= item->y) {
+ update_sign = -1;
+ } else {
+ update_sign = 1;
+ }
+
+ if (force_update || (item->status & ITEM_STATUS_IN_RANGE)) {
+ list->base_element += update_sign;
+ if (update_sign < 0) {
+ list->picked_element = list->base_element;
+ } else {
+ list->picked_element = list->base_element + list->rows - 1;
+ }
+ popup_adjust_elements(list);
+ }
+
+ item->status &= ~ITEM_STATUS_IN_RANGE;
+ }
+ }
+ }
+
+ if (mouse_stop_stroke && list->scroll.status) {
+ list->scroll.status = 0;
+ }
+
+ if (mouse_stop_stroke && !popup->mouse_status) {
+ now_clock = timer_read();
+ if ((now_clock - list->double_clock) < POPUP_DOUBLE_CLICK_THRESHOLD) {
+ if (list->double_element == list->picked_element) {
+ popup_activate_item(popup->enter_item);
+ popup->status |= POPUP_STATUS_EXIT;
+ }
+ }
+ list->double_clock = now_clock;
+ list->double_element = list->picked_element;
+ }
+
+ if (list->base_element != base_element) {
+ popup_redraw_item(item);
+ } else if (list->picked_element != picked_element) {
+ popup_savelist_item_refresh(item, picked_element);
+ popup_savelist_item_refresh(item, list->picked_element);
+ } else if (list->scroll.status != old_status) {
+ popup_savelist_scroll_refresh(item);
+ }
+
+ return 0;
+}
+
+
+static void popup_savelist_select(PopupItem *item, int element) {
+ PopupList *list;
+
+ list = item->list;
+
+ list->picked_element = element;
+ if ((list->base_element > list->picked_element) ||
+ (list->picked_element >= (list->base_element + list->rows))) {
+ list->base_element = list->picked_element - (list->rows >> 1);
+ }
+
+ popup_adjust_elements(list);
+}
+
+
+
+static void popup_savelist_select_free(PopupItem *item) {
+ int count;
+ int found = -1;
+ char *text_locator;
+ PopupList *list;
+
+ list = item->list;
+
+ for (count = 0; (found < 0) && (count < list->elements); count++) {
+ text_locator = popup_savelist_string(item, count);
+ if (*text_locator == 0) found = count;
+ }
+
+ if (found >= 0) {
+ popup_savelist_select(item, found);
+ }
+}
+
+
+
+static int popup_savelist_key(PopupItem *item) {
+ int base_element;
+ int picked_element;
+ int new_string = false;
+ char newStr[2];
+ PopupList *list;
+ PopupBuffer *buffer;
+
+ if (!(item->status & ITEM_STATUS_INPUT)) goto done;
+
+ list = item->list;
+ buffer = item->buffer;
+
+ base_element = list->base_element;
+ picked_element = list->picked_element;
+
+ switch (popup->key) {
+ case enter_key:
+ if (item->status & ITEM_STATUS_DIRTY) {
+ Common::strcpy_s(popup_savelist_string(item, list->picked_element), 65536, buffer->data);
+ item->status &= ~ITEM_STATUS_DIRTY;
+ }
+ new_string = true;
+ goto skip_handled;
+ break;
+
+ case bksp_key:
+ if (!(item->status & ITEM_STATUS_DIRTY)) {
+ Common::strcpy_s(buffer->data, 65536, popup_savelist_string(item, list->picked_element));
+ item->status |= ITEM_STATUS_DIRTY;
+ }
+
+ if (strlen(buffer->data)) {
+ buffer->data[strlen(buffer->data) - 1] = 0;
+ new_string = true;
+ }
+
+ goto handled;
+ break;
+
+ case ctrl_c_key:
+ item->status |= ITEM_STATUS_DIRTY;
+ *buffer->data = 0;
+ new_string = true;
+ goto handled;
+ break;
+
+ case ctrl_r_key:
+ item->status &= ~ITEM_STATUS_DIRTY;
+ new_string = true;
+ goto handled;
+ break;
+
+ default:
+ if (Common::isPrint(popup->key)) {
+ if (item->status & ITEM_STATUS_VIRGIN) {
+ if (strlen(popup_savelist_string(item, list->picked_element))) {
+ popup_savelist_select_free(item);
+ }
+ }
+
+ if (!(item->status & ITEM_STATUS_DIRTY)) {
+ Common::strcpy_s(buffer->data, 65536, popup_savelist_string(item, list->picked_element));
+ item->status |= ITEM_STATUS_DIRTY;
+ }
+
+ if (!strlen(buffer->data)) popup->key = toupper(popup->key);
+ newStr[0] = (byte)popup->key;
+ newStr[1] = 0;
+
+ if ((popup_font_size(buffer->data) + popup_font_size(newStr)) <= (list->list_xs - 2)) {
+ if ((int)strlen(buffer->data) < (buffer->max_length - 1)) {
+ Common::strcat_s(buffer->data, 65536, newStr);
+ new_string = true;
+ }
+ }
+
+ goto handled;
+
+ }
+ break;
+ }
+
+ goto done;
+
+handled:
+ popup->key_handled = true;
+
+skip_handled:
+ item->status &= ~ITEM_STATUS_VIRGIN;
+
+ if (mouse_latched && mouse_stroke_going) {
+ mouse_init_cycle();
+ popup_redraw_item(item);
+ } else if (list->base_element != base_element) {
+ popup_redraw_item(item);
+ } else if (list->picked_element != picked_element) {
+ popup_savelist_item_refresh(item, picked_element);
+ popup_savelist_item_refresh(item, list->picked_element);
+ } else if (new_string) {
+ popup_savelist_item_refresh(item, list->picked_element);
+ }
+
+done:
+ ;
+ return 0;
+}
+
+
+static int popup_savelist_update(PopupItem *item) {
+ return 0;
+}
+
+
+
+
+static void popup_savelist_create(PopupItem *item) {
+ item->vector[VECTOR_X_SIZE] = popup_savelist_x_size;
+ item->vector[VECTOR_Y_SIZE] = popup_savelist_y_size;
+ item->vector[VECTOR_DRAW] = popup_savelist_draw;
+ item->vector[VECTOR_MOUSE] = popup_savelist_mouse;
+ item->vector[VECTOR_KEY] = popup_savelist_key;
+ item->vector[VECTOR_ADJUST] = popup_savelist_adjust;
+ item->vector[VECTOR_UPDATE] = popup_savelist_update;
+}
+
+
+
+
+static void item_constructor(PopupItem *item, int type) {
+ item->type = (byte)type;
+
+ switch (type) {
+ case ITEM_BUTTON:
+ popup_button_create(item);
+ break;
+ case ITEM_MESSAGE:
+ popup_message_create(item);
+ break;
+ case ITEM_SAVELIST:
+ popup_savelist_create(item);
+ break;
+ case ITEM_SPRITE:
+ popup_sprite_create(item);
+ break;
+ case ITEM_MENU:
+ popup_menu_create(item);
+ break;
+ }
+}
+
+
+
+PopupItem *popup_button(const char *prompt, int x) {
+ int first_button;
+ int new_width;
+ PopupItem *item;
+
+ first_button = (popup->status & POPUP_STATUS_BUTTON) == 0;
+
+ popup->status |= POPUP_STATUS_BUTTON;
+
+ item = item_allocate(true);
+ item_constructor(item, ITEM_BUTTON);
+
+ set_prompt(item, prompt);
+
+ item->y = POPUP_BUTTON_ROW;
+ item->ys = popup_exec_function(item, VECTOR_Y_SIZE);
+
+ item->font_x = 4;
+ item->font_y = 3;
+
+ item->x = x;
+ item->xs = popup_exec_function(item, VECTOR_X_SIZE);
+
+ if (item->x == POPUP_BUTTON_LEFT) {
+ item->x = popup->button_left_fill;
+ popup->button_left_fill += item->xs + popup->button_spacing;
+ } else if (item->x == POPUP_BUTTON_RIGHT) {
+ popup->button_right_fill += item->xs;
+ item->x = POPUP_BUTTON_RIGHT | popup->button_right_fill;
+ popup->button_right_fill += popup->button_spacing;
+ }
+
+ new_width = popup->button_left_fill + popup->button_right_fill;
+ popup->width = MAX(popup->width, new_width);
+
+ if (first_button) popup->enter_item = item;
+
+ return (item);
+}
+
+
+PopupItem *popup_cancel_button(const char *prompt) {
+ PopupItem *item;
+
+ if (prompt == NULL) {
+ item = popup_button("Cancel", POPUP_BUTTON_RIGHT);
+ } else {
+ item = popup_button(prompt, POPUP_BUTTON_RIGHT);
+ }
+
+ popup->cancel_item = item;
+
+ return item;
+}
+
+
+void popup_menu_option(PopupItem *item, char *option) {
+ PopupList *list;
+ char *text_locator;
+
+ list = item->list;
+
+ if (list->base_element < list->elements) {
+ text_locator = list->data + (list->base_element * list->element_offset);
+ Common::strcpy_s(text_locator, 65536, option);
+ list->base_element++;
+ }
+}
+
+
+PopupItem *popup_menu(const char *prompt,
+ int x, int y, int pixel_width,
+ int off_center_x,
+ int elements, int element_max_length,
+ int default_element) {
+ int heap_to_get;
+ PopupItem *item;
+ PopupList *list;
+
+ item = item_allocate(true);
+ item_constructor(item, ITEM_MENU);
+
+ item->status |= ITEM_STATUS_INERT;
+
+ set_prompt(item, prompt);
+
+ item->list = list = list_allocate();
+
+ heap_to_get = elements * (element_max_length + 1);
+
+ if (heap_to_get > 0) {
+ list->data = (char *)popup_heap(heap_to_get);
+ }
+
+ list->elements = elements;
+ list->element_offset = element_max_length + 1;
+ list->element_max_length = element_max_length;
+
+ list->base_element = 0;
+ list->picked_element = default_element;
+ list->picked_element = MAX(list->picked_element, 0);
+ list->picked_element = MIN(list->picked_element, elements - 1);
+
+ list->box_xs = pixel_width;
+
+ list->extra_xs = off_center_x;
+
+ item->xs = popup_exec_function(item, VECTOR_X_SIZE);
+ item->ys = popup_exec_function(item, VECTOR_Y_SIZE);
+
+ item->font_x = box_param.menu_text_x_offset;
+ item->font_y = box_param.menu_text_y_offset;
+
+ popup_y_placement(item, y);
+
+ item->x = x;
+
+ popup_x_width_check(item);
+
+ return (item);
+}
+
+
+
+PopupItem *popup_message(char *prompt, int x, int y) {
+ PopupItem *item;
+
+ item = item_allocate(false);
+ item_constructor(item, ITEM_MESSAGE);
+
+ item->status |= ITEM_STATUS_INERT;
+
+ set_prompt(item, prompt);
+
+ item->ys = popup_exec_function(item, VECTOR_Y_SIZE);
+ item->xs = popup_exec_function(item, VECTOR_X_SIZE);
+
+ popup_y_placement(item, y);
+
+ item->x = x;
+
+ popup_x_width_check(item);
+
+ return (item);
+}
+
+
+
+void popup_blank(int num_lines) {
+ popup->y_position += num_lines;
+}
+
+
+void popup_blank_line(void) {
+ popup_blank(box_param.font->max_y_size + popup->y_spacing);
+}
+
+
+
+PopupItem *popup_sprite(SeriesPtr series, int sprite, int x, int y) {
+ PopupItem *item;
+
+ item = item_allocate(false);
+ item_constructor(item, ITEM_SPRITE);
+
+ item->status |= ITEM_STATUS_INERT;
+
+ item->series = series;
+ item->sprite = sprite;
+
+ item->ys = popup_exec_function(item, VECTOR_Y_SIZE);
+ item->xs = popup_exec_function(item, VECTOR_X_SIZE);
+
+ popup_y_placement(item, y);
+
+ item->x = x;
+
+ popup_x_width_check(item);
+
+ return (item);
+}
+
+
+
+
+
+PopupItem *popup_savelist(byte *data,
+ byte *empty_string,
+ int elements,
+ int element_offset,
+ int element_max_length,
+ int pixel_width,
+ int rows,
+ int accept_input,
+ int default_element) {
+ PopupItem *item;
+ PopupList *list;
+ PopupBuffer *buffer;
+
+ item = item_allocate(true);
+ item_constructor(item, ITEM_SAVELIST);
+
+ item->status |= ITEM_STATUS_CLOCK;
+ item->mouse_interval = 4;
+
+ if (accept_input) {
+ item->status |= ITEM_STATUS_STRING | ITEM_STATUS_INPUT | ITEM_STATUS_VIRGIN;
+ }
+
+ item->buffer = buffer = buffer_allocate(element_max_length + 1);
+
+ item->list = list = list_allocate();
+
+ item->prompt = (char *)empty_string;
+ list->data = (char *)data;
+
+ list->elements = elements;
+ list->element_offset = element_offset;
+ list->element_max_length = element_max_length;
+ list->rows = rows;
+ list->columns = 1;
+
+ list->picked_element = default_element;
+ list->picked_element = MAX(list->picked_element, 0);
+ list->picked_element = MIN(list->picked_element, elements - 1);
+ list->base_element = list->picked_element - ((rows >> 1) - 1);
+ list->base_element = MAX(list->base_element, 0);
+
+ list->box_xs = pixel_width;
+
+ item->ys = popup_exec_function(item, VECTOR_Y_SIZE);
+ item->xs = popup_exec_function(item, VECTOR_X_SIZE);
+
+ popup_y_placement(item, POPUP_FILL);
+
+ item->x = 0;
+
+ list->extra_x = 2;
+ list->list_x = list->extra_x + list->extra_xs + 1;
+ list->font_x = list->list_x + 1;
+ list->scroll.x = list->list_x + list->list_xs + 1;
+
+ list->scroll.y = 2;
+ list->extra_y = 2;
+ list->list_y = 2;
+ list->font_y = 3;
+
+ list->scroll.arrow_1_base = list->scroll.y;
+ list->scroll.arrow_2_base = item->ys - (list->scroll.arrow_size + 2);
+
+ list->scroll.status = 0;
+
+ list->double_clock = 0;
+ list->double_element = 0;
+
+ popup_x_width_check(item);
+
+ popup->list_item = item;
+
+ if (popup->string_item == NULL) {
+ popup->string_item = item;
+ }
+
+ return (item);
+}
+
+
+
+
+
+PopupItem *popup_execute(void) {
+ int base_x_size;
+ int horiz_pieces;
+ int request_pieces;
+ int actual_x_size;
+ int text_x_extra;
+ int count;
+ long now_clock;
+ Box popup_box;
+ Box *keep_box;
+ PopupItem *result_item = NULL;
+
+ keep_box = box;
+ box = &popup_box;
+
+ base_x_size = popup->width + (popup_padding_width << 1);
+
+ horiz_pieces = ((base_x_size - (box_param.extra_x + 1)) / pop_xs(POPUP_TOP)) + 1;
+
+ request_pieces = horiz_pieces - box_param.pieces_per_center;
+ request_pieces = MAX(0, request_pieces);
+ if (request_pieces & 1) request_pieces++;
+ request_pieces = request_pieces >> 1;
+
+ horiz_pieces = (request_pieces << 1) + box_param.pieces_per_center;
+
+ actual_x_size = (horiz_pieces * pop_xs(POPUP_TOP)) + box_param.extra_x;
+ text_x_extra = actual_x_size - base_x_size;
+
+ if (popup->status & POPUP_STATUS_BUTTON) {
+ popup->y_position += popup->y_spacing;
+ if (popup->status & POPUP_STATUS_BAR) {
+ popup->y_position += 1 + popup_padding_width;
+ }
+ popup->button_y = popup->y_position;
+ popup->y_position += popup_exec_function(popup->enter_item, VECTOR_Y_SIZE);
+ }
+
+ box->request_y_size = popup->y_position + (popup_padding_width << 1);
+
+ if (popup_create(0 - request_pieces, popup->x, popup->y)) {
+ error_report(ERROR_KERNEL_NO_POPUP, ERROR, MODULE_POPUP_DIALOG, request_pieces, 1);
+ goto done;
+ }
+
+ if (popup_draw(true, false)) {
+ error_report(ERROR_KERNEL_NO_POPUP, ERROR, MODULE_POPUP_DIALOG, box->request_y_size, 2);
+ goto done;
+ }
+
+ popup->x = box->window_x + popup_padding_width + (text_x_extra >> 1);
+ popup->y = box->window_y + popup_padding_width + (box->text_extra >> 1);
+ popup->xs = popup->width;
+ popup->ys = popup->y_position;
+
+ if (popup->status & POPUP_STATUS_BUTTON) {
+ popup->button_y += (box->text_extra - (box->text_extra >> 1));
+
+ if (popup->status & POPUP_STATUS_STEAL) {
+ popup->button_bar_color = *buffer_pointer(&scr_main,
+ box->window_x - 1,
+ box->window_y);
+ }
+ }
+
+ for (count = 0; count < popup->num_items; count++) {
+ popup_coord_adjust(&popup->item[count]);
+ popup_exec_function(&popup->item[count], VECTOR_ADJUST);
+ }
+
+ popup->button_y += popup->y;
+
+ popup->mouse_item = NULL;
+
+ popup_full_draw();
+
+ mouse_init_cycle();
+
+ do {
+ digi_read_another_chunk();
+ midi_loop();
+
+ mouse_begin_cycle(false);
+
+ if (keys_any()) {
+ popup->key = keys_get();
+ popup->key_handled = false;
+
+ if (Common::isPrint(popup->key) || (popup->key == bksp_key)) {
+ if (!(popup->active_item->status & ITEM_STATUS_STRING)) {
+ if (popup->string_item != NULL) {
+ popup_activate_item(popup->string_item);
+ }
+ }
+ }
+
+ popup_exec_function(popup->active_item, VECTOR_KEY);
+
+ if (!popup->key_handled) {
+ switch (popup->key) {
+
+ case alt_x_key:
+ case alt_q_key:
+ case ctrl_q_key:
+ case ctrl_x_key:
+ case f1_key:
+ case f2_key:
+ case f3_key:
+ case f4_key:
+ case f5_key:
+ case f6_key:
+ case f7_key:
+ case f8_key:
+ case f9_key:
+ case f10_key:
+
+ case esc_key:
+ popup_activate_item(popup->cancel_item);
+ popup->status |= POPUP_STATUS_EXIT;
+ break;
+
+ case enter_key:
+ popup_activate_item(popup->enter_item);
+ popup->status |= POPUP_STATUS_EXIT;
+ break;
+
+ case tab_key:
+ case down_key:
+ popup_activate_item(popup_next_item(popup->active_item, true, false));
+ break;
+
+ case backtab_key:
+ case up_key:
+ popup_activate_item(popup_last_item(popup->active_item, true, false));
+ break;
+
+ }
+ }
+ }
+
+ if (!(popup->status & POPUP_STATUS_EXIT)) {
+ if (mouse_start_stroke) popup_find_item();
+ if (popup->mouse_item != NULL) {
+ popup->mouse_item->status &= ~ITEM_STATUS_FORCED;
+
+ if (popup->mouse_item->status & ITEM_STATUS_CLOCK) {
+ if (mouse_start_stroke) {
+ popup->mouse_clock = timer_read();
+ }
+ now_clock = timer_read();
+ if (now_clock >= popup->mouse_clock) {
+ popup->mouse_item->status |= ITEM_STATUS_FORCED;
+ popup->mouse_clock = now_clock + popup->mouse_item->mouse_interval;
+ }
+ }
+ if (mouse_changed || (popup->mouse_item->status & ITEM_STATUS_FORCED)) {
+ popup_exec_function(popup->mouse_item, VECTOR_MOUSE);
+ }
+ }
+ }
+
+ mouse_end_cycle(false, (popup->status & POPUP_STATUS_EXIT) == 0);
+
+ } while (!(popup->status & POPUP_STATUS_EXIT));
+
+ result_item = popup->active_item;
+
+done:
+ popup_destroy();
+ box = keep_box;
+ return (result_item);
+}
+
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/core/popup.h b/engines/mads/madsv2/core/popup.h
index 9c03adb2bb2..291dff68c9d 100644
--- a/engines/mads/madsv2/core/popup.h
+++ b/engines/mads/madsv2/core/popup.h
@@ -170,7 +170,7 @@ typedef struct {
int ask_x, ask_y;
int cursor_x;
word tab[POPUP_MAX_LINES];
- byte *text[POPUP_MAX_LINES];
+ char *text[POPUP_MAX_LINES];
int dont_add_space;
@@ -306,8 +306,7 @@ typedef struct {
#define ITEM_STATUS_INERT 0x100
-
-typedef struct {
+struct PopupItem {
byte type; /* Type of item */
word status; /* Status of item */
@@ -332,9 +331,8 @@ typedef struct {
SeriesPtr series; /* Sprite series */
int sprite; /* Sprite id */
- void (*vector[POPUP_ITEM_VECTORS])(); /* Vectors */
-
-} PopupItem;
+ int (*vector[POPUP_ITEM_VECTORS])(PopupItem *item); /* Vectors */
+};
#define POPUP_MOUSE_SCROLL 0x8000 /* Mouse in scroll bar */
@@ -404,7 +402,7 @@ extern int popup_available;
extern int popup_preserve_initiator[3];
-extern byte popup_colors[8];
+extern byte popup_colors[24];
extern byte popup_num_colors;
extern BoxParam box_param;
@@ -419,8 +417,8 @@ void popup_destroy(void);
/* popup_1.c */
void popup_next_line(void);
void popup_set_ask(void);
-void popup_add_string(char *string);
-void popup_write_string(char *string);
+void popup_add_string(const char *string);
+void popup_write_string(const char *string);
void popup_bar(void);
void popup_underline(void);
void popup_downpixel(void);
@@ -452,11 +450,6 @@ int popup_alert(int width, char *message_line, ...);
/* popup_4.c */
int popup_box_load(void);
-/* popup_5.c */
-Popup *popup_activate(Popup *newpop);
-int popup_exec_function(PopupItem *item, int function);
-char *popup_heap(long mem_to_get);
-
/* popup_5.c */
Popup *popup_dialog_create(void *memory,
long heap_size,
@@ -464,9 +457,9 @@ Popup *popup_dialog_create(void *memory,
Popup *popup_dialog_destroy(void);
/* popup_5.c */
-PopupItem *popup_button(char *prompt, int x);
-PopupItem *popup_cancel_button(char *prompt);
-PopupItem *popup_message(char *prompt, int x, int y);
+PopupItem *popup_button(const char *prompt, int x);
+PopupItem *popup_cancel_button(const char *prompt);
+PopupItem *popup_message(const char *prompt, int x, int y);
PopupItem *popup_execute(void);
/* popup_5.c */
diff --git a/engines/mads/madsv2/core/screen.cpp b/engines/mads/madsv2/core/screen.cpp
new file mode 100644
index 00000000000..e1c7a09143b
--- /dev/null
+++ b/engines/mads/madsv2/core/screen.cpp
@@ -0,0 +1,150 @@
+/* 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/textconsole.h"
+#include "mads/madsv2/core/screen.h"
+#include "mads/madsv2/core/mouse.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+int screen_video_mode;
+int screen_max_x = 80;
+int screen_max_y = 25;
+
+int screen_center_x = 0;
+int screen_center_y = 0;
+
+Window screen_active = { 0,0,79,24,NULL }; /* The currently active window */
+
+byte *screen = color_text_video;
+
+int *screen_bound_x = &screen_max_x;
+
+void screen_set_size(short numlines) {
+ mouse_hide();
+
+ if (screen_video_mode == text_mode) {
+ // No implementation in ScummVM
+ }
+ if (screen_max_y == 50) {
+ mouse_vert_bound(0, 399);
+ } else {
+ mouse_vert_bound(0, 199);
+ }
+ screen_active.lr_y = screen_max_y - 1;
+
+ mouse_show();
+}
+
+void screen_wipe_line(short ul_x, short ul_y, short len, short wipe_color, byte wipe_char) {
+ warning("TODO: screen_wipe_line");
+}
+
+short screen_out(const char *outstring, short strcolor, short selcolor, short str_x, short str_y) {
+ debug("TODO: screen_out %s", outstring);
+ return 0;
+}
+
+short screen_put(const char *outstring, short strcolor, short selcolor, short str_x, short str_y) {
+ warning("TODO: screen_put");
+ return 0;
+}
+
+void screen_set_colors(int normal_color, int hilite_color) {
+ warning("TODO: screen_set_colors");
+}
+
+void screen_set_line_width(int line_width) {
+ warning("TODO: screen_set_line_width");
+}
+
+short screen_show_line(const char *outstring, short locx, short locy) {
+ warning("TODO: screen_show_line");
+ return 0;
+}
+
+short screen_write(const char *outstring) {
+ warning("TODO: screen_write");
+ return 0;
+}
+
+short screen_write_line(const char *outstring) {
+ warning("TODO: screen_write_line");
+ return 0;
+}
+
+void screen_clear(int clear_color) {
+ warning("TODO: screen_clear");
+}
+
+void screen_dominant_mode(int dominant_mode) {
+ warning("TODO: screen_set_colors");
+}
+
+void screen_init(int video_mode) {
+ warning("TODO: screen_init");
+}
+
+void screen_init_dual(int mono_left) {
+ warning("TODO: screen_init_dual");
+}
+
+void screen_shutdown_dual(int clear_flag) {
+ warning("TODO: screen_shutdown_dual");
+}
+
+void screen_init_graphics(int which_mode) {
+ warning("TODO: screen_init_graphics");
+}
+
+void screen_shutdown_graphics(int clear_flag) {
+ warning("TODO: screen_shutdown_graphics");
+}
+
+void screen_show_spot(const char *message, int wx, int wy, int class_, int num) {
+ warning("TODO: screen_show_spot");
+}
+
+void screen_init_text(int which_mode) {
+ warning("TODO: screen_init_text");
+}
+
+void screen_shutdown_text(int clear_flag) {
+ warning("TODO: screen_shutdown_text");
+}
+
+void screen_save(void) {
+ warning("TODO: screen_save");
+}
+
+void screen_restore(void) {
+ warning("TODO: screen_restore");
+}
+
+short screen_show_wide(const char *outstring, short locx, short locy, short width) {
+ warning("TODO: screen_show_wide");
+ return 0;
+}
+
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/core/screen.h b/engines/mads/madsv2/core/screen.h
index adf5c92cad2..1b2b30e53ad 100644
--- a/engines/mads/madsv2/core/screen.h
+++ b/engines/mads/madsv2/core/screen.h
@@ -76,79 +76,45 @@ extern Buffer scr_live;
extern Window screen_active;
-/* screen_1.cpp */
+/**
+ * Sets # of lines in VGA text mode
+ */
void screen_set_size(short numlines);
-/* screen_2.cpp */
-void screen_wipe_line(short ul_x, short ul_y, short len,
- short wipe_color, byte wipe_char);
-
-/* screen_3.cpp */
-short screen_out(char *outstring, short strcolor,
- short selcolor, short str_x, short str_y);
-
-/* screen_4.cpp */
-short screen_put(char *outstring,
- short strcolor, short selcolor,
- short str_x, short str_y);
+/**
+ * Sets uniform color & character for specified line
+ */
+void screen_wipe_line(short ul_x, short ul_y, short len, short wipe_color, byte wipe_char);
-/* screen_5.cpp */
+short screen_out(const char *outstring, short strcolor, short selcolor, short str_x, short str_y);
+short screen_put(const char *outstring, short strcolor, short selcolor, short str_x, short str_y);
void screen_set_colors(int normal_color, int hilite_color);
void screen_set_line_width(int line_width);
-/* screen_6.c ... DO NOT USE */
-short screen_show(char *outstring, short locx, short locy);
-
-/* screen_7.cpp */
-short screen_show_line(char *outstring,
- short locx, short locy);
+/* DO NOT USE */
+//short screen_show(const char *outstring, short locx, short locy);
-/* screen_8.cpp */
-short screen_write(char *outstring);
-
-/* screen_9.cpp */
-short screen_write_line(char *outstring);
-
-/* screen_a.cpp */
+short screen_show_line(const char *outstring, short locx, short locy);
+short screen_write(const char *outstring);
+short screen_write_line(const char *outstring);
void screen_clear(int clear_color);
-
-/* screen_b.cpp */
void screen_dominant_mode(int dominant_mode);
-
-/* screen_c.cpp */
void screen_init(int video_mode);
-
-/* screen_d.cpp */
void screen_init_dual(int mono_left);
void screen_shutdown_dual(int clear_flag);
-
-/* screen_e.cpp */
void screen_init_graphics(int which_mode);
void screen_shutdown_graphics(int clear_flag);
+void screen_show_spot(const char *message, int wx, int wy, int class_, int num);
-/* screen_f.cpp */
-void screen_show_spot(char *message, int wx, int wy, int class_, int num);
-
-/* screen_g.c ... DO NOT USE */
-int screen_printf(int x, int y, char *string, ...);
-int screen_print(char *string, ...);
-
+/* DO NOT USE */
+//int screen_printf(int x, int y, char *string, ...);
+//int screen_print(char *string, ...);
-/* screen_h.cpp */
void screen_init_text(int which_mode);
void screen_shutdown_text(int clear_flag);
-
-
-/* screen_i.cpp */
void screen_save(void);
void screen_restore(void);
-
-
-/* screen_j.cpp */
-short screen_show_wide(char *outstring,
- short locx,
- short locy,
- short width);
+short screen_show_wide(const char *outstring, short locx, short locy, short width);
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/core/timer.cpp b/engines/mads/madsv2/core/timer.cpp
new file mode 100644
index 00000000000..f4521db8714
--- /dev/null
+++ b/engines/mads/madsv2/core/timer.cpp
@@ -0,0 +1,91 @@
+/* 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/textconsole.h"
+#include "mads/madsv2/core/general.h"
+#include "mads/madsv2/core/timer.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+long *timer_address = dos_timer_address;
+word timer_rate = 20;
+int timer_service_active = false;
+
+extern long timer_600_low;
+extern long timer_60_low;
+
+/*
+/* Reads system clock, returns number of ticks since midnight.
+*/
+long timer_read(void) {
+ return (*timer_address);
+}
+
+
+long timer_read_dos(void) {
+ return (*dos_timer_address);
+}
+
+
+long timer_read_600(void) {
+ return (timer_600_low);
+}
+
+long timer_read_60(void) {
+ return (timer_60_low);
+}
+
+/*
+/* This works around annoying MASM problem requiring us to make
+/* reference to code segment in order to get data segment stuff
+/* linked from an OBJ. This routine does not exist to be called
+/* but rather to make the required references in case the main
+/* program does not.
+*/
+void timer_hack(void) {
+ timer_install();
+ /* pl sound_manager(); */
+ /* pl sound_driver_null(); */
+ timer_remove();
+}
+
+
+void timer_set_rate(word count_down) {
+ warning("TODO: timer_set_rate");
+#ifdef TODO
+ _asm {
+ cli; Interrupts begone
+
+ mov al, 00110110b; Timer chanel 0
+ out 43h, al; Declare our intention to reprogram
+ mov ax, count_down; Get new countdown value
+ out 40h, al; Send low part
+ mov al, ah
+ out 40h, al; Send high part
+
+ sti; Interrupts come hither
+ }
+#endif
+}
+
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/core/vocabh.h b/engines/mads/madsv2/core/vocabh.h
new file mode 100644
index 00000000000..2ebd96c4a8a
--- /dev/null
+++ b/engines/mads/madsv2/core/vocabh.h
@@ -0,0 +1,49 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef MADS_CORE_VOCABH_H
+#define MADS_CORE_VOCABH_H
+
+#include "mads/madsv2/core/general.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+/* Hardcoded vocabulary words */
+
+#define words_game 1
+#define words_qsave 2
+#define words_look 3
+#define words_take 4
+#define words_push 5
+#define words_open 6
+#define words_put 7
+#define words_talk_to 8
+#define words_give 9
+#define words_pull 10
+#define words_close 11
+#define words_throw 12
+#define words_walk_to 13
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/xms.cpp b/engines/mads/madsv2/core/xms.cpp
new file mode 100644
index 00000000000..1e1647432bb
--- /dev/null
+++ b/engines/mads/madsv2/core/xms.cpp
@@ -0,0 +1,34 @@
+/* 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 "mads/madsv2/core/xms.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+word xms_version = 0;
+dword xms_controller = 0;
+word xms_chain_seg = 0;
+word xms_umb_list[XMS_MAX_UMB] = {};
+word xms_umb_mark = 0;
+
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/core/xms.h b/engines/mads/madsv2/core/xms.h
index c2b9e29f892..ed773f97fea 100644
--- a/engines/mads/madsv2/core/xms.h
+++ b/engines/mads/madsv2/core/xms.h
@@ -40,30 +40,39 @@ extern word xms_chain_seg; /* First UMB MCB segment for us */
extern word xms_umb_list[XMS_MAX_UMB];
extern word xms_umb_mark;
-/* xms_1.c */
-int xms_detect(void);
-
-/* xms_2.c */
-long xms_umb_get_avail(void);
-
-/* xms_3.c */
-void *xms_umb_get(long mem_to_get);
-void xms_umb_free(void *mem_to_free);
-
-/* xms_4.c */
-void xms_umb_purge(void);
+inline int xms_detect() { return 0; }
+inline long xms_umb_get_avail() {}
+inline void *xms_umb_get(long mem_to_get) { return nullptr; }
+inline void xms_umb_free(void *mem_to_free) {}
+inline void xms_umb_purge() {}
+
+/**
+ * Returns the size of the largest free XMS block.
+ */
+inline long xms_get_avail() { return 0; }
-/* xms_5.c */
-long xms_get_avail(void);
+/**
+ * Allocates an XMS block of the appropriate size, and returns a handle for it.
+ */
+inline int xms_get(long size_in_bytes) { return 0; }
-/* xms_6.c */
-int xms_get(long size_in_bytes);
-void xms_free(int xms_handle);
+/**
+ * Deallocates an XMS block
+ */
+inline void xms_free(int xms_handle) {}
-/* xms_7.c */
-int xms_copy(long copy_size,
- word source_handle, void *source,
- word dest_handle, void *dest);
+/**
+ * Copy data to/from/between XMS memory blocks. Note that the parameter
+ * stack format corresponds precisely to the XMS function spec, so we
+ * can just point directly at the parameter stack and call XMS.
+ *
+ * For conventional memory, use handle "0", and a traditional
+ * segmented far pointer.
+ *
+ * For extended memory, use the proper handle number, and a full
+ * 32-bit (unsegmented) pointer.
+ */
+inline int xms_copy(long copy_size, word source_handle, void *source, word dest_handle, void *dest) { return 0; }
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index 94223901c6b..7219affdff4 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -61,15 +61,21 @@ MODULE_OBJS += \
forest/globals_forest.o \
madsv2/engine.o \
madsv2/core/buffer.o \
+ madsv2/core/cycle.o \
+ madsv2/core/ems.o \
madsv2/core/error.o \
+ madsv2/core/fileio.o \
madsv2/core/font_1.o \
+ madsv2/core/himem.o \
+ madsv2/core/inter.o \
madsv2/core/kernel_1.o \
madsv2/core/kernel_3.o \
madsv2/core/kernel_8.o \
madsv2/core/kernel_b.o \
madsv2/core/kernel_d.o \
madsv2/core/kernel_f.o \
- madsv2/core/matte_1.o \
+ madsv2/core/matte.o \
+ madsv2/core/mcga.o \
madsv2/core/mem_2.o \
madsv2/core/mouse_1.o \
madsv2/core/mouse_2.o \
@@ -77,12 +83,16 @@ MODULE_OBJS += \
madsv2/core/mouse_4.o \
madsv2/core/object.o \
madsv2/core/pack_6.o \
+ madsv2/core/pal.o \
+ madsv2/core/popup.o \
madsv2/core/quote_1.o \
+ madsv2/core/screen.o \
madsv2/core/speech.o \
madsv2/core/sprite_e.o \
madsv2/core/sprite_k.o \
madsv2/core/text.o \
madsv2/core/tile_3.o \
+ madsv2/core/timer.o \
madsv2/core/video_1.o \
madsv2/core/vocab_8.o \
madsv2/phantom/mads/mads.o \
Commit: 2718a5cdc3046539eff0240dea4f22c35a1f5d3b
https://github.com/scummvm/scummvm/commit/2718a5cdc3046539eff0240dea4f22c35a1f5d3b
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:19:04+10:00
Commit Message:
MADS: PHANTOM: Adding sprite drawing code
Changed paths:
A engines/mads/madsv2/core/sprite.cpp
A engines/mads/madsv2/core/sprite_0.cpp
R engines/mads/madsv2/core/sprite_e.cpp
engines/mads/madsv2/core/kernel_1.cpp
engines/mads/module.mk
diff --git a/engines/mads/madsv2/core/kernel_1.cpp b/engines/mads/madsv2/core/kernel_1.cpp
index 45b9f56cac3..6941dad2c8b 100644
--- a/engines/mads/madsv2/core/kernel_1.cpp
+++ b/engines/mads/madsv2/core/kernel_1.cpp
@@ -27,6 +27,7 @@
namespace MADS {
namespace MADSV2 {
+byte video_mode;
RoomPtr room = NULL;
int room_id = KERNEL_STARTING_GAME;
int section_id = KERNEL_STARTING_GAME;
diff --git a/engines/mads/madsv2/core/sprite.cpp b/engines/mads/madsv2/core/sprite.cpp
new file mode 100644
index 00000000000..740152be5ad
--- /dev/null
+++ b/engines/mads/madsv2/core/sprite.cpp
@@ -0,0 +1,289 @@
+/* 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 "mads/madsv2/core/general.h"
+#include "mads/madsv2/core/mem.h"
+#include "mads/madsv2/core/error.h"
+#include "mads/madsv2/core/pal.h"
+#include "mads/madsv2/core/env.h"
+#include "mads/madsv2/core/loader.h"
+#include "mads/madsv2/core/sprite.h"
+#include "mads/madsv2/core/sprite_h.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+// Disable Visual studio unreferenced local variables warnings
+#pragma warning(push)
+#pragma warning(disable: 4101)
+#pragma warning(disable: 4102)
+#pragma warning(disable: 4189)
+
+//=== sprite_draw =====================================
+#define three_d false /* depth coding OFF */
+#define bresenham false /* bresenham OFF */
+#define packed_attr false /* Attr packing OFF */
+#define translate false /* 16-color OFF */
+#define interface false /* Interface OFF */
+
+
+void sprite_draw(SeriesPtr series, int id, Buffer *buf, int target_x, int target_y) {
+ #include "mads/madsv2/core/sprite_0.cpp"
+}
+
+#undef three_d
+#undef bresenham
+#undef packed_attr
+#undef translate
+#undef interface
+
+//=== sprite_draw_scaled =====================================
+#define three_d false /* depth coding OFF */
+#define bresenham true /* bresenham ON */
+#define packed_attr false /* Attr packing OFF */
+#define translate false /* 16-color OFF */
+
+#define interface false /* Interface OFF */
+
+void fastcall sprite_draw_scaled(SeriesPtr series, int id, Buffer *buf,
+ int target_x, int target_y, int scale_factor) {
+#include "mads/madsv2/core/sprite_0.cpp"
+}
+
+#undef three_d
+#undef bresenham
+#undef packed_attr
+#undef translate
+#undef interface
+
+//=== sprite_draw_3d_big =====================================
+#define three_d true /* depth coding ON */
+#define bresenham false /* bresenham OFF */
+#define packed_attr true /* Attr packing ON */
+#define translate false /* 16-color OFF */
+
+#define interface false /* Interface OFF */
+
+void sprite_draw_3d_big(SeriesPtr series, int id, Buffer *buf, Buffer *attr,
+ int target_x, int target_y, int target_depth, int view_port_x, int view_port_y) {
+#include "mads/madsv2/core/sprite_0.cpp"
+}
+
+#undef three_d
+#undef bresenham
+#undef packed_attr
+#undef translate
+#undef interface
+
+//=== sprite_draw_3d_scaled_big =====================================
+#define three_d true /* depth coding ON */
+#define bresenham true /* bresenham ON */
+#define packed_attr true /* Attr packing ON */
+#define translate false /* 16-color OFF */
+
+#define interface false /* Interface OFF */
+
+void sprite_draw_3d_scaled_big(SeriesPtr series, int id, Buffer *buf, Buffer *attr,
+ int target_x, int target_y, int target_depth, int scale_factor,
+ int view_port_x, int view_port_y) {
+#include "mads/madsv2/core/sprite_0.cpp"
+}
+
+#undef three_d
+#undef bresenham
+#undef packed_attr
+#undef translate
+#undef interface
+
+//=== sprite_draw_3d_x16 =====================================
+#define three_d true /* depth coding ON */
+#define bresenham false /* bresenham OFF */
+#define packed_attr false /* Attr packing OFF */
+#define translate true /* 16-color ON */
+
+#define interface false /* Interface OFF */
+
+void fastcall sprite_draw_3d_x16(SeriesPtr series, int id, Buffer *buf, Buffer *attr,
+ int target_x, int target_y, int target_depth) {
+#include "mads/madsv2/core/sprite_0.cpp"
+}
+
+#undef three_d
+#undef bresenham
+#undef packed_attr
+#undef translate
+#undef interface
+
+//=== sprite_draw_3d_scaled_x16 =====================================
+#define three_d true /* depth coding ON */
+#define bresenham true /* bresenham ON */
+#define packed_attr false /* Attr packing OFF */
+#define translate true /* 16-color ON */
+
+#define interface false /* Interface OFF */
+
+void fastcall sprite_draw_3d_scaled_x16(SeriesPtr series, int id,
+ Buffer *buf, Buffer *attr,
+ int target_x, int target_y, int target_depth,
+ int scale_factor) {
+#include "mads/madsv2/core/sprite_0.cpp"
+}
+
+#undef three_d
+#undef bresenham
+#undef packed_attr
+#undef translate
+#undef interface
+
+//=== sprite_draw_3d_big_x16 =====================================
+#define three_d true /* depth coding ON */
+#define bresenham false /* bresenham OFF */
+#define packed_attr true /* Attr packing ON */
+#define translate true /* 16-color ON */
+
+#define interface false /* Interface OFF */
+
+void fastcall sprite_draw_3d_big_x16(SeriesPtr series, int id, Buffer *buf, Buffer *attr,
+ int target_x, int target_y, int target_depth,
+ int view_port_x, int view_port_y) {
+#include "mads/madsv2/core/sprite_0.cpp"
+}
+
+#undef three_d
+#undef bresenham
+#undef packed_attr
+#undef translate
+#undef interface
+
+//=== sprite_draw_3d_big_x16 =====================================
+#define three_d true /* depth coding ON */
+#define bresenham true /* bresenham ON */
+#define packed_attr true /* Attr packing ON */
+#define translate true /* 16-color ON */
+
+#define interface false /* Interface OFF */
+
+void fastcall sprite_draw_3d_big_x16(SeriesPtr series, int id,
+ Buffer *buf, Buffer *attr, int target_x, int target_y, int target_depth,
+ int scale_factor, int view_port_x, int view_port_y) {
+#include "mads/madsv2/core/sprite_0.cpp"
+}
+
+#undef three_d
+#undef bresenham
+#undef packed_attr
+#undef translate
+#undef interface
+
+//=== sprite_draw_x16 =====================================
+#define three_d false /* depth coding OFF */
+#define bresenham false /* bresenham OFF */
+#define packed_attr false /* Attr packing OFF */
+#define translate true /* 16-color ON */
+
+#define interface false /* Interface OFF */
+
+void fastcall sprite_draw_x16(SeriesPtr series, int id, Buffer * buf,
+ int target_x, int target_y) {
+#include "mads/madsv2/core/sprite_0.cpp"
+}
+
+#undef three_d
+#undef bresenham
+#undef packed_attr
+#undef translate
+#undef interface
+
+//=== sprite_draw_interface =====================================
+#define three_d false /* depth coding OFF */
+#define bresenham false /* bresenham OFF */
+#define packed_attr false /* Attr packing OFF */
+#define translate false /* 16-color OFF */
+
+#define interface true /* Interface ON */
+
+void fastcall sprite_draw_interface(SeriesPtr series, int id, Buffer *buf,
+ int target_x, int target_y) {
+#include "mads/madsv2/core/sprite_0.cpp"
+}
+
+#undef three_d
+#undef bresenham
+#undef packed_attr
+#undef translate
+#undef interface
+
+//=== sprite_draw_3d_scaled_to_attr =====================================
+#define three_d true /* depth coding ON */
+#define bresenham true /* bresenham ON */
+#define packed_attr true /* Attr packing ON */
+#define translate false /* 16-color OFF */
+
+#define interface false /* Interface OFF */
+
+#define attribute true /* Draw to attribute */
+
+void fastcall sprite_draw_3d_scaled_to_attr
+(SeriesPtr series, int id,
+ Buffer *buf, Buffer *attr,
+ int target_x, int target_y, int target_depth,
+ int scale_factor, int view_port_x, int view_port_y) {
+#include "mads/madsv2/core/sprite_0.cpp"
+}
+
+#undef three_d
+#undef bresenham
+#undef packed_attr
+#undef translate
+#undef interface
+#undef attribute
+
+//=== sprite_draw_3d_scaled_mono =====================================
+#define three_d true /* depth coding ON */
+#define bresenham true /* bresenham ON */
+#define packed_attr false /* Attr packing OFF */
+#define translate false /* 16-color OFF */
+
+#define interface false /* Interface OFF */
+
+#define monodraw true /* Draw mono color */
+
+void fastcall sprite_draw_3d_scaled_mono(SeriesPtr series, int id,
+ Buffer *buf, Buffer *attr, int target_x, int target_y, int target_depth,
+ int scale_factor, byte color) {
+#include "mads/madsv2/core/sprite_0.cpp"
+}
+
+#undef three_d
+#undef bresenham
+#undef packed_attr
+#undef translate
+#undef interface
+
+#pragma warning(pop)
+
+//====================================================================
+
+
+
+
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/core/sprite_0.cpp b/engines/mads/madsv2/core/sprite_0.cpp
new file mode 100644
index 00000000000..f1b94ad6e20
--- /dev/null
+++ b/engines/mads/madsv2/core/sprite_0.cpp
@@ -0,0 +1,1116 @@
+/*
+/* sprite_0.c by Brian Reynolds 24-Jul-91
+/*
+/* Master sprite draw include file. Include as main body of each
+/* desired sprite routine, defining macros as appropriate to generate
+/* the correct algorithm:
+/*
+/* Set "three_d" to true for 3d depth coding
+/* Set "bresenham" to true for Bresenham scaling
+/* Set "packed_attr" to true for packed attribute screen (PANNING rooms)
+/* Set "translate" to true for 16 color translation version
+/*
+/* Set "interface" to true for special interface version (exclusive
+/* of all other options)
+/*
+/* Define "attribute" to draw to attribute page (in depth code) instead.
+/* Define "monodraw" to draw in monochrome color
+/*
+/* Define "on_black" to draw only on top of "zero" pixels.
+/*
+/* If "packed_attr" is true, then "three_d" MUST be true also.
+/*
+/* Parameters required:
+/*
+/* NAME TYPE USAGE DESCRIPTION
+/* ===================================================================
+/* series SeriesPtr (all) Series handle
+/* id int (all) Sprite #
+/* buf buffer * (all) Target buffer
+/* target_x int (all) Sprite base X
+/* target_y int (all) Sprite base Y
+/*
+/* attr buffer * (three_d) Attribute Buffer
+/* target_depth int (three_d) Sprite depth code
+/*
+/* view_port_x int (packed_attr) Work/Orig X mapping
+/* view_port_y int (packed_attr) Work/Orig Y mapping
+/*
+/* scale_factor int (bresenham) Scale % size (10-100)
+/*
+/* <Set high bit of sprite "id" for mirror imaging>
+/*
+/*
+/* DRAW ROUTINES three_d packattr bres. trans.
+/* ====================================================================
+/* sprite_draw() - - - -
+/* sprite_draw_3d() * - - -
+/* sprite_draw_3d_scaled() * - * -
+/* sprite_draw_3d_big() * * - -
+/* sprite_draw_3d_scaled_big() * * * -
+/* sprite_draw_x16() - - - *
+/* sprite_draw_3d_x16() * - - *
+/* sprite_draw_3d_scaled_x16() * - * *
+/* sprite_draw_3d_big_x16() * * - *
+/* sprite_draw_3d_scaled_big_x16() * * * *
+/*
+/* sprite_draw_interface()
+/*
+/*
+/* INCLUDE FILES REQUIRED:
+/* #include <stdlib.h> /* Bresenham only */
+/* #include <general.mac>
+/* #include <color.mac>
+/* #include "sprite.mac"
+/*
+*/
+
+/*
+/* Filter out illegal compile combinations
+*/
+
+#if packed_attr
+#if !three_d
+#error Cannot compile packed_attr without three_d!
+#endif
+#endif
+
+#if interface
+#if (three_d || bresenham || translate)
+#error Interface is exclusive of all other options
+#endif
+#endif
+
+#ifdef attribute
+#if (!three_d || !bresenham || translate || !packed_attr)
+#error Attribute draw must be (three_d,bresenham,!translate,packed_attr)
+#endif
+#endif
+
+
+/*
+/* Local variables common to all versions
+*/
+
+byte *sprite_ptr;
+byte *target_ptr;
+int target_wrap;
+int xs, ys;
+int skip_y, draw_y, max_y, stop_y;
+int skip_x, draw_x, max_x, stop_x;
+int line_finished;
+int mirror;
+int draw_count;
+SpritePtr sprite;
+
+/*
+/* Local variables for "three_d" depth coding
+*/
+
+#if three_d
+byte *attr_ptr;
+#endif
+
+#define huge_code (packed_attr && translate)
+
+/*
+/* Local variables for "packed_attr" large attribute screens
+*/
+
+#if packed_attr
+int attr_wrap;
+int attr_start;
+#endif
+
+/*
+/* Local variables for "bresenham" sprite scaling
+*/
+
+#if bresenham
+#define max_bresenham_entries 320
+byte bresenham_table[max_bresenham_entries];
+int bresenham_entries;
+int temp_x, temp_y;
+#endif
+
+/*
+/* Local variables for "translate" 16 color thatching translations
+*/
+
+#if translate
+byte thatch_base;
+byte thatch_flag;
+#endif
+
+/*
+/* In certain configurations, the main draw routine does not need
+/* all of the registers for computations; for those variations,
+/* certain commonly used variables (skip_x & stop_x) are aliased
+/* for clarity. These were originally aliased to CPU registers.
+*/
+
+/* SKIP_X and STOP_X were originally aliased to registers (cx, di)
+ in certain configurations to save memory accesses. In C they are
+ always the plain variables. */
+#define SKIP_X skip_x
+#define STOP_X stop_x
+
+ /* Get maximum clipping coordinates */
+max_x = buf->x - 1;
+max_y = buf->y - 1;
+
+/* Load up sprite pointer info: check high bit of id for mirror flag */
+if (id < 0) {
+ mirror = -1;
+ id &= 0x7fff;
+} else {
+ mirror = 1;
+}
+
+sprite = &series->index[id - 1];
+sprite_ptr = sprite->data;
+
+/* Load up buffer pointer info */
+target_ptr = buf->data;
+target_wrap = buf->x;
+
+/* Load up attribute pointer info */
+#if three_d
+attr_ptr = attr->data;
+#endif
+
+/* Get attribute buffer wrap boundary */
+#if packed_attr
+attr_wrap = attr->x;
+#endif
+
+/* Get sprite size and (if Bresenham) number of table entries */
+#if bresenham
+temp_x = sprite->xs;
+temp_y = sprite->ys;
+
+bresenham_entries = MAX(temp_x, temp_y);
+#else
+xs = sprite->xs;
+ys = sprite->ys;
+#endif
+
+/*
+/* BRESENHAM TABLE
+/*
+/* Generate a Bresenham table useable for both X and Y checks.
+/* Each entry is true if that source pixel maps to a drawn pixel
+/* at the given scale factor.
+*/
+
+#if bresenham
+{
+ int bres_acc = 50; /* Start accumulator at 50 (midpoint) */
+ xs = 0;
+ ys = 0;
+
+ for (int bi = 0; bi < bresenham_entries; bi++) {
+ bres_acc += scale_factor;
+ if (bres_acc >= 100) {
+ bresenham_table[bi] = true;
+ bres_acc -= 100;
+
+ if (bi < temp_x)
+ xs++;
+ if (bi < temp_y)
+ ys++;
+ } else {
+ bresenham_table[bi] = false;
+ }
+ }
+
+ /* Adjust target coordinates: coords are passed as middle-lower;
+ must be changed to upper-left based on scaled matte. */
+ target_x -= xs / 2;
+ target_y -= ys;
+ target_y++;
+}
+#endif
+
+
+/*
+/* SPRITE CLIPPING
+/*
+/* Clip the sprite into the target buffer's boundaries.
+/* Generates skip_x, skip_y, draw_x, draw_y, stop_x, stop_y.
+*/
+
+/* X clipping */
+{
+ int bx = xs; /* proposed X size */
+ int cx = 0; /* assume no left clipping */
+ int ax = target_x;
+ int dx = ax + bx - 1; /* proposed right boundary */
+
+ if (ax < 0) {
+ /* Left clip needed */
+ bx += ax; /* decrease X size by overflow */
+ cx -= ax; /* increase left clip count */
+ }
+
+ dx -= max_x;
+ if (dx > 0) {
+ bx -= dx; /* decrease X size by right overflow */
+ }
+
+ skip_x = cx;
+ draw_x = bx;
+ stop_x = cx + bx;
+
+ if (bx <= 0)
+ goto all_done;
+
+ /* Mirror adjustments */
+ if (mirror != 1) {
+ int di = xs;
+ ax = target_x;
+
+ ax += di;
+ ax--;
+ target_x = ax;
+
+ di -= cx; /* subtract original stop_x from size */
+ di = -di; /* negate for pointer calculations */
+ skip_x = di;
+
+ di = -di; /* make positive again */
+ di += draw_x;
+ stop_x = di;
+ }
+}
+
+/* Y clipping */
+{
+ int bx = ys; /* proposed Y size */
+ int cx = 0; /* assume no top clipping */
+ int ax = target_y;
+ int dx = ax + bx - 1; /* proposed lower boundary */
+
+ if (ax < 0) {
+ bx += ax;
+ cx -= ax;
+ }
+
+ dx -= max_y;
+ if (dx > 0) {
+ bx -= dx;
+ }
+
+ skip_y = cx;
+ draw_y = bx;
+ stop_y = cx + bx;
+
+ if (bx <= 0)
+ goto all_done;
+}
+
+
+/*
+/* POINTER SETUP
+/*
+/* Compute the flat starting offset into target (and attr) buffers,
+/* accounting for target_y rows and target_x+skip_x columns.
+/* The original code used 16-bit real-mode segment:offset arithmetic
+/* with 32k wrap-around tricks; in a flat memory model we simply use
+/* integer offsets.
+*/
+
+#if translate
+{
+ int tx = target_x;
+ int ty = target_y;
+#if packed_attr
+ ty += view_port_y;
+ tx += view_port_x;
+#endif
+ /* XOR X & Y for starting thatch polarity, then flip for first pixel */
+ thatch_base = (byte)(((tx ^ ty) & 1) ^ 1);
+}
+#endif
+
+/* Compute starting target pointer */
+{
+ int start_y = skip_y + target_y;
+ int start_x = target_x + skip_x;
+
+ target_ptr += start_y * target_wrap + start_x;
+}
+
+#if three_d && packed_attr
+{
+ /* Compute starting attr pointer for packed (2-pixels-per-byte) buffer.
+ attr_start holds the sub-byte bit offset (0 or 1) for the first pixel. */
+ int ay = skip_y + target_y + view_port_y;
+ int ax = view_port_x + target_x + skip_x;
+
+ attr_ptr += ay * attr_wrap + (ax / 2);
+ attr_start = ax & 1; /* bit offset within byte (0 or 1) */
+}
+#endif
+
+
+/*
+/* MAIN DRAW LOOP
+/*
+/* Processes the sprite stream row by row.
+/*
+/* draw_y_pos - vertical draw counter (counts pixels actually drawn/clipped,
+/* excluding Bresenham-squeezed rows)
+/* scan_y - vertical scan counter for Bresenham (indexes bresenham_table)
+/* target_row - pointer to start of current target row
+/* attr_row - pointer to start of current attr row (packed_attr only)
+/*
+/* Per row:
+/* draw_x_pos - horizontal draw counter
+/* scan_x - horizontal scan counter for Bresenham
+/* run_count - RLE run counter
+/* sprite_byte - current byte read from sprite stream
+/* depth_code - depth of current sprite pixel (three_d only)
+/* draw_depth - depth at which we are drawing (three_d only)
+*/
+
+{
+ /* Absolute starting skip_x, adjusted for mirror direction */
+ int abs_skip_x = skip_x * mirror; /* undo any negative from mirroring */
+ /* (The original asm did: mov ax,skip_x / imul mirror to make it always
+ positive regardless of mirror direction.) */
+ skip_x = abs_skip_x;
+
+#if three_d
+ byte draw_depth = (byte)target_depth;
+#endif
+
+#if bresenham
+ int scan_x, scan_y = -1;
+#endif
+
+ int draw_x_pos, draw_y_pos = -1;
+ byte *pixel_ptr; /* current horizontal position in target */
+ byte *target_row = target_ptr;
+#if packed_attr
+ byte *attr_row = attr_ptr;
+#endif
+
+ while (1) { /* row_loop */
+
+ line_finished = false;
+
+#if bresenham
+ scan_y++;
+ if (scan_y >= temp_y)
+ goto all_done;
+ if (!bresenham_table[scan_y])
+ goto row_finish;
+#endif /* bresenham row gate */
+
+ /* row_valid: */
+#if translate
+ {
+ byte cl = thatch_base ^ 1;
+ thatch_base = cl;
+ thatch_flag = cl;
+ }
+#endif
+
+ draw_y_pos++;
+ if (draw_y_pos >= stop_y)
+ goto all_done;
+
+ if (draw_y_pos < skip_y)
+ goto row_finish;
+
+ /* row_draw / pixel_begin: */
+
+#if bresenham
+ scan_x = 0;
+#endif
+
+ pixel_ptr = target_row; /* current horizontal position in target */
+ draw_x_pos = 0;
+
+ /* pixel_loop: process one sprite row */
+ while (1) {
+
+ byte sprite_byte = *sprite_ptr++;
+
+ if (sprite_byte == SS_EOL) {
+ /* pixel_EOL */
+ line_finished = true;
+ break; /* goto row_next */
+ }
+
+#ifdef dump_mode
+ if (sprite_byte == SS_DUMP) {
+ /* pixel_DUMP: skip section */
+ int dump_skip, dump_draw;
+ dump_skip = *(int *)sprite_ptr; sprite_ptr += 2;
+
+ while (dump_skip > 0) {
+ if (draw_x_pos >= STOP_X)
+ goto row_next_from_dump;
+
+#if bresenham
+ if (!bresenham_table[scan_x])
+ goto pixel_DUMP_skip_next;
+#endif
+
+ if (draw_x_pos >= SKIP_X) {
+#if translate
+ thatch_flag ^= 1;
+#endif
+ pixel_ptr += mirror;
+ }
+
+ draw_x_pos++;
+
+#if bresenham
+ pixel_DUMP_skip_next :
+ scan_x++;
+#endif
+
+ dump_skip--;
+ }
+
+ /* DUMP draw section */
+ dump_draw = *(int *)sprite_ptr; sprite_ptr += 2;
+ draw_count = dump_draw;
+
+ while (1) {
+ if (draw_x_pos >= STOP_X)
+ goto row_next_from_dump;
+
+ sprite_byte = *sprite_ptr++;
+
+#if bresenham
+ if (!bresenham_table[scan_x])
+ goto pixel_DUMP_draw_next;
+#endif
+
+ if (draw_x_pos < SKIP_X)
+ goto pixel_DUMP_nodraw;
+
+ if (sprite_byte != SS_SKIP) {
+ /* depth / interface / translate checks (shared helper below) */
+#if three_d
+ {
+ byte depth_code;
+#if packed_attr
+ {
+ /* packed attr unpack: 2 pixels per byte, 4 bits each */
+ int attr_col = draw_x_pos - SKIP_X;
+ int byte_off, bit_off;
+ byte attr_byte, full_attr_byte;
+
+ if (mirror == 1) {
+ int rem = attr_col & 1;
+ byte_off = attr_col / 2;
+ bit_off = (-(rem)+attr_start);
+ if (bit_off > 1) {
+ byte_off++; bit_off &= 1;
+ }
+ } else {
+ byte_off = -(attr_col / 2);
+ bit_off = attr_col + attr_start; /* Note: attr_start set at row start for mirror */
+ if (bit_off < 0) {
+ byte_off--; bit_off += 2;
+ }
+ }
+
+ attr_byte = attr_row[byte_off];
+
+ /* Invert bottom bit of bit_off, quadruple for shift, rotate right */
+ int shift = ((bit_off ^ 1) & 1) << 2;
+ /* ror byte by shift */
+ attr_byte = (byte)((attr_byte >> shift) | (attr_byte << (8 - shift)));
+
+#ifdef attribute
+ full_attr_byte = attr_byte;
+#endif
+
+ depth_code = attr_byte & 0x0f;
+
+#ifdef attribute
+ {
+ byte sprite_depth_bits = depth_code;
+ byte stored_depth = draw_depth;
+ if (stored_depth > bit_off) /* reusing bit_off as shift here per asm */
+ goto pixel_DUMP_no_attr;
+ full_attr_byte = (full_attr_byte & 0xf0) | sprite_depth_bits;
+ /* ror full_attr_byte, shift */
+ full_attr_byte = (byte)((full_attr_byte >> shift) | (full_attr_byte << (8 - shift)));
+ attr_row[byte_off] = full_attr_byte;
+pixel_DUMP_no_attr:;
+ }
+#endif
+ }
+#else /* !packed_attr */
+ {
+ depth_code = attr_ptr[pixel_ptr - target_ptr] & 0x0f;
+ }
+#endif
+
+ if (depth_code == 0) goto pixel_DUMP_skip_n_pop;
+ if ((byte)draw_depth > depth_code) goto pixel_DUMP_skip_n_pop;
+ }
+#endif /* three_d */
+
+#if interface
+ {
+ byte cur = *pixel_ptr;
+ if (cur < 8 || cur > 11) goto pixel_DUMP_skip_n_pop;
+ }
+#endif
+
+#if translate
+ {
+ byte full_color = sprite_byte;
+ if (sprite_byte >= 16) {
+ if (thatch_flag != 0) {
+ sprite_byte >>= 4;
+ if (sprite_byte == COLOR_BLACK_THATCH)
+ sprite_byte = 0;
+ } else {
+ sprite_byte &= 0x0f;
+ }
+ }
+ }
+#endif
+
+pixel_DUMP_output:
+#ifdef on_black
+ if (*pixel_ptr != 0) goto pixel_DUMP_no_output;
+#endif
+#ifndef attribute
+#ifdef monodraw
+ sprite_byte = color;
+#endif
+ *pixel_ptr = sprite_byte;
+#endif
+pixel_DUMP_no_output:;
+
+#if translate
+ sprite_byte = full_color; /* restore for thatch counter */
+#endif
+ }
+
+pixel_DUMP_skip_n_pop:;
+pixel_DUMP_skip:
+#if translate
+ thatch_flag ^= 1;
+#endif
+ pixel_ptr += mirror;
+
+pixel_DUMP_nodraw:
+ draw_x_pos++;
+
+pixel_DUMP_draw_next:
+#if bresenham
+ scan_x++;
+#endif
+
+ draw_count--;
+ if (draw_count == 0) {
+ /* DUMP done: consume EOL and mark finished */
+ sprite_ptr++; /* skip the EOL byte that follows a DUMP block */
+ line_finished = true;
+ goto row_next_from_dump;
+ }
+ }
+row_next_from_dump:
+ break; /* goto row_next */
+ }
+#endif /* dump_mode */
+
+ if (sprite_byte == SS_RLE) {
+ /* pixel_RLE: process an RLE run-length encoded segment */
+ goto pixel_RLE;
+ }
+
+ /* Must be IRLE (individual run-length encoded) */
+ goto pixel_IRLE;
+
+
+ /* ============================================================
+ * RLE HANDLER
+ * Each RLE packet: [run_count] [run_value] (until SS_EOL)
+ * ============================================================ */
+pixel_RLE:
+ while (1) { /* pixel_RLE_loop */
+
+ if (draw_x_pos >= STOP_X)
+ break; /* goto row_next */
+
+ {
+ byte rc = *sprite_ptr++;
+ if (rc == SS_EOL) {
+ line_finished = true;
+ break; /* goto row_next */
+ }
+ byte run_count = rc;
+ byte run_value = *sprite_ptr++;
+
+ /* pixel_RLE_run_loop: emit run_count pixels of run_value */
+ while (1) {
+
+#if bresenham
+ if (!bresenham_table[scan_x])
+ goto pixel_RLE_run_next;
+#endif
+
+ if (draw_x_pos < SKIP_X) goto pixel_RLE_run_nodraw;
+ if (draw_x_pos >= STOP_X) goto pixel_RLE_run_nodraw;
+
+ /* pixel_RLE_run_yesdraw */
+ if (run_value != SS_SKIP) {
+ byte out_byte = run_value;
+
+#if three_d
+ {
+ byte depth_code;
+#if packed_attr
+ {
+ int attr_col = draw_x_pos - SKIP_X;
+ int byte_off, bit_off;
+ byte attr_byte;
+
+ if (mirror == 1) {
+ int rem = attr_col & 1;
+ byte_off = attr_col / 2;
+ bit_off = (-rem) + attr_start;
+ if (bit_off > 1) {
+ byte_off++; bit_off &= 1;
+ }
+ } else {
+ byte_off = -(attr_col / 2);
+ bit_off = attr_col + attr_start;
+ if (bit_off < 0) {
+ byte_off--; bit_off += 2;
+ }
+ }
+
+ attr_byte = attr_row[byte_off];
+ int shift = ((bit_off ^ 1) & 1) << 2;
+ attr_byte = (byte)((attr_byte >> shift) | (attr_byte << (8 - shift)));
+
+#ifdef attribute
+ {
+ byte full_ab = attr_byte;
+ byte sprite_d = attr_byte & 0x0f;
+ if (draw_depth > bit_off) goto pixel_RLE_no_attr;
+ full_ab = (full_ab & 0xf0) | sprite_d;
+ full_ab = (byte)((full_ab >> shift) | (full_ab << (8 - shift)));
+ attr_row[byte_off] = full_ab;
+pixel_RLE_no_attr:;
+ }
+#endif
+
+ depth_code = attr_byte & 0x0f;
+ }
+#else
+ {
+ depth_code = attr_ptr[pixel_ptr - target_ptr] & 0x0f;
+ }
+#endif
+
+ if (depth_code == 0) goto pixel_RLE_run_skip_n_pop;
+ if ((byte)draw_depth > depth_code) goto pixel_RLE_run_skip_n_pop;
+ }
+#endif /* three_d */
+
+#if interface
+ {
+ byte cur = *pixel_ptr;
+ if (cur < 8 || cur > 11) goto pixel_RLE_run_skip_n_pop;
+ }
+#endif
+
+#if translate
+ {
+ byte full_color = out_byte;
+ if (out_byte >= 16) {
+ if (thatch_flag != 0) {
+ out_byte >>= 4;
+ if (out_byte == COLOR_BLACK_THATCH)
+ out_byte = 0;
+ } else {
+ out_byte &= 0x0f;
+ }
+ }
+ /* pixel_RLE_run_output: */
+#ifdef on_black
+ if (*pixel_ptr != 0) goto pixel_RLE_no_output;
+#endif
+#ifndef attribute
+#ifdef monodraw
+ out_byte = color;
+#endif
+ *pixel_ptr = out_byte;
+#endif
+pixel_RLE_no_output:;
+ out_byte = full_color; /* restore for thatching */
+ goto pixel_RLE_run_skip_n_pop;
+ }
+#endif
+
+ /* pixel_RLE_run_output (non-translate path) */
+#ifdef on_black
+ if (*pixel_ptr != 0) goto pixel_RLE_no_output2;
+#endif
+#ifndef attribute
+#ifdef monodraw
+ out_byte = color;
+#endif
+ *pixel_ptr = out_byte;
+#endif
+pixel_RLE_no_output2:;
+ }
+
+pixel_RLE_run_skip_n_pop:;
+pixel_RLE_run_skip:
+#if translate
+ thatch_flag ^= 1;
+#endif
+ pixel_ptr += mirror;
+
+pixel_RLE_run_nodraw:
+ draw_x_pos++;
+
+pixel_RLE_run_next:
+#if bresenham
+ scan_x++;
+#endif
+
+ run_count--;
+ if (run_count == 0)
+ break; /* goto pixel_RLE_loop for next run */
+ }
+ /* pixel_RLE_run_done -> loop back to pixel_RLE_loop */
+ }
+ }
+ break; /* row_next */
+
+
+ /* ============================================================
+ * IRLE HANDLER
+ * Each IRLE packet is either:
+ * SS_RUN + [count] + [value] (a run)
+ * SS_EOL (end of line)
+ * <literal byte> (single image pixel)
+ * ============================================================ */
+pixel_IRLE:
+ while (1) { /* pixel_IRLE_loop */
+
+ if (draw_x_pos >= STOP_X)
+ break; /* goto row_next */
+
+ sprite_byte = *sprite_ptr++;
+
+ if (sprite_byte == SS_EOL) {
+ line_finished = true;
+ break; /* goto row_next (same as pixel_RLE_EOL) */
+ }
+
+ if (sprite_byte == SS_RUN) {
+ /* pixel_IRLE_run */
+ byte run_count = *sprite_ptr++;
+ byte run_value = *sprite_ptr++;
+
+ while (1) { /* pixel_IRLE_run_loop */
+
+#if bresenham
+ if (!bresenham_table[scan_x])
+ goto pixel_IRLE_run_next;
+#endif
+
+ if (draw_x_pos < SKIP_X) goto pixel_IRLE_run_nodraw;
+ if (draw_x_pos >= STOP_X) goto pixel_IRLE_run_nodraw;
+
+ /* pixel_IRLE_run_yesdraw */
+ if (run_value != SS_SKIP) {
+ byte out_byte = run_value;
+
+#if three_d
+ {
+ byte depth_code;
+#if packed_attr
+ {
+ int attr_col = draw_x_pos - SKIP_X;
+ int byte_off, bit_off;
+ byte attr_byte;
+
+ if (mirror == 1) {
+ int rem = attr_col & 1;
+ byte_off = attr_col / 2;
+ bit_off = (-rem) + attr_start;
+ if (bit_off > 1) {
+ byte_off++; bit_off &= 1;
+ }
+ } else {
+ byte_off = -(attr_col / 2);
+ bit_off = attr_col + attr_start;
+ if (bit_off < 0) {
+ byte_off--; bit_off += 2;
+ }
+ }
+
+ attr_byte = attr_row[byte_off];
+ int shift = ((bit_off ^ 1) & 1) << 2;
+ attr_byte = (byte)((attr_byte >> shift) | (attr_byte << (8 - shift)));
+
+#ifdef attribute
+ {
+ byte full_ab = attr_byte;
+ byte sprite_d = attr_byte & 0x0f;
+ if (draw_depth > bit_off) goto pixel_IRLE_run_no_attr;
+ full_ab = (full_ab & 0xf0) | sprite_d;
+ full_ab = (byte)((full_ab >> shift) | (full_ab << (8 - shift)));
+ attr_row[byte_off] = full_ab;
+pixel_IRLE_run_no_attr:;
+ }
+#endif
+
+ depth_code = attr_byte & 0x0f;
+ }
+#else
+ {
+ depth_code = attr_ptr[pixel_ptr - target_ptr] & 0x0f;
+ }
+#endif
+
+ if (depth_code == 0) goto pixel_IRLE_run_skip_n_pop;
+ if ((byte)draw_depth > depth_code) goto pixel_IRLE_run_skip_n_pop;
+ }
+#endif /* three_d */
+
+#if interface
+ {
+ byte cur = *pixel_ptr;
+ if (cur < 8 || cur > 11) goto pixel_IRLE_run_skip_n_pop;
+ }
+#endif
+
+#if translate
+ {
+ byte full_color = out_byte;
+ if (out_byte >= 16) {
+ if (thatch_flag != 0) {
+ out_byte >>= 4;
+ if (out_byte == COLOR_BLACK_THATCH)
+ out_byte = 0;
+ } else {
+ out_byte &= 0x0f;
+ }
+ }
+#ifdef on_black
+ if (*pixel_ptr != 0) goto pixel_IRLE_run_no_output;
+#endif
+#ifndef attribute
+#ifdef monodraw
+ out_byte = color;
+#endif
+ *pixel_ptr = out_byte;
+#endif
+pixel_IRLE_run_no_output:;
+ out_byte = full_color;
+ goto pixel_IRLE_run_skip_n_pop;
+ }
+#endif
+
+#ifdef on_black
+ if (*pixel_ptr != 0) goto pixel_IRLE_run_no_output2;
+#endif
+#ifndef attribute
+#ifdef monodraw
+ out_byte = color;
+#endif
+ *pixel_ptr = out_byte;
+#endif
+pixel_IRLE_run_no_output2:;
+ }
+
+pixel_IRLE_run_skip_n_pop:;
+pixel_IRLE_run_skip:
+#if translate
+ thatch_flag ^= 1;
+#endif
+ pixel_ptr += mirror;
+
+pixel_IRLE_run_nodraw:
+ draw_x_pos++;
+
+pixel_IRLE_run_next:
+#if bresenham
+ scan_x++;
+#endif
+
+ run_count--;
+ if (run_count == 0)
+ break; /* pixel_IRLE_next -> loop */
+ }
+ continue; /* pixel_IRLE_next: back to pixel_IRLE_loop */
+ }
+
+ /* pixel_IRLE_image: sprite_byte is a literal pixel */
+ {
+ byte out_byte = sprite_byte;
+
+#if bresenham
+ if (!bresenham_table[scan_x])
+ goto pixel_IRLE_image_next;
+#endif
+
+ /* pixel_IRLE_image_clip */
+ if (draw_x_pos < SKIP_X) goto pixel_IRLE_image_nodraw;
+ if (draw_x_pos >= STOP_X) goto pixel_IRLE_image_nodraw;
+
+ if (out_byte != SS_SKIP) {
+
+#if three_d
+ {
+ byte depth_code;
+#if packed_attr
+ {
+ int attr_col = draw_x_pos - SKIP_X;
+ int byte_off, bit_off;
+ byte attr_byte;
+
+ if (mirror == 1) {
+ int rem = attr_col & 1;
+ byte_off = attr_col / 2;
+ bit_off = (-rem) + attr_start;
+ if (bit_off > 1) {
+ byte_off++; bit_off &= 1;
+ }
+ } else {
+ byte_off = -(attr_col / 2);
+ bit_off = attr_col + attr_start;
+ if (bit_off < 0) {
+ byte_off--; bit_off += 2;
+ }
+ }
+
+ attr_byte = attr_row[byte_off];
+ int shift = ((bit_off ^ 1) & 1) << 2;
+ attr_byte = (byte)((attr_byte >> shift) | (attr_byte << (8 - shift)));
+
+#ifdef attribute
+ {
+ byte full_ab = attr_byte;
+ byte sprite_d = attr_byte & 0x0f;
+ if (draw_depth > bit_off) goto pixel_IRLE_image_no_attr;
+ full_ab = (full_ab & 0xf0) | sprite_d;
+ full_ab = (byte)((full_ab >> shift) | (full_ab << (8 - shift)));
+ attr_row[byte_off] = full_ab;
+pixel_IRLE_image_no_attr:;
+ }
+#endif
+
+ depth_code = attr_byte & 0x0f;
+ }
+#else
+ {
+ depth_code = attr_ptr[pixel_ptr - target_ptr] & 0x0f;
+ }
+#endif
+
+ if (depth_code == 0) goto pixel_IRLE_image_skip_n_pop;
+ if ((byte)draw_depth > depth_code) goto pixel_IRLE_image_skip_n_pop;
+ }
+#endif /* three_d */
+
+#if interface
+ {
+ byte cur = *pixel_ptr;
+ if (cur < 8 || cur > 11) goto pixel_IRLE_image_skip_n_pop;
+ }
+#endif
+
+#if translate
+ {
+ byte full_color = out_byte;
+ if (out_byte >= 16) {
+ if (thatch_flag != 0) {
+ out_byte >>= 4;
+ if (out_byte == COLOR_BLACK_THATCH)
+ out_byte = 0;
+ } else {
+ out_byte &= 0x0f;
+ }
+ }
+ /* pixel_IRLE_image_output: */
+#ifdef on_black
+ if (*pixel_ptr != 0) goto pixel_IRLE_image_no_output;
+#endif
+#ifndef attribute
+#ifdef monodraw
+ out_byte = color;
+#endif
+ *pixel_ptr = out_byte;
+#endif
+pixel_IRLE_image_no_output:;
+ goto pixel_IRLE_image_skip_n_pop;
+ }
+#endif
+
+ /* pixel_IRLE_image_output (non-translate path) */
+#ifdef on_black
+ if (*pixel_ptr != 0) goto pixel_IRLE_image_no_output2;
+#endif
+#ifndef attribute
+#ifdef monodraw
+ out_byte = color;
+#endif
+ *pixel_ptr = out_byte;
+#endif
+pixel_IRLE_image_no_output2:;
+ }
+
+pixel_IRLE_image_skip_n_pop:;
+pixel_IRLE_image_skip:
+#if translate
+ thatch_flag ^= 1;
+#endif
+ pixel_ptr += mirror;
+
+pixel_IRLE_image_nodraw:
+ draw_x_pos++;
+
+pixel_IRLE_image_next:
+#if bresenham
+ scan_x++;
+#endif
+
+ continue; /* pixel_IRLE_loop */
+ }
+ }
+ break; /* row_next */
+
+ } /* end pixel_loop / inner while(1) */
+
+ /* row_next: advance to next row */
+
+ /* row_finish: if this line wasn't completed (e.g. right-clipped early),
+ consume the rest of the sprite row stream until SS_EOL. */
+row_finish:
+ if (!line_finished) {
+ while (*sprite_ptr++ != SS_EOL)
+ ;
+ }
+
+ /* Advance target row pointer by one scanline */
+ target_row += target_wrap;
+
+#if packed_attr
+ /* Advance attr row pointer by one scanline */
+ attr_row += attr_wrap;
+#endif
+
+ } /* end while(1) row_loop */
+}
+
+all_done:;
diff --git a/engines/mads/madsv2/core/sprite_e.cpp b/engines/mads/madsv2/core/sprite_e.cpp
deleted file mode 100644
index f6b6582358c..00000000000
--- a/engines/mads/madsv2/core/sprite_e.cpp
+++ /dev/null
@@ -1,340 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#ifndef MADS_CORE_SPRITE_E_H
-#define MADS_CORE_SPRITE_E_H
-
-#include "mads/madsv2/core/general.h"
-#include "mads/madsv2/core/mem.h"
-#include "mads/madsv2/core/error.h"
-#include "mads/madsv2/core/pal.h"
-#include "mads/madsv2/core/env.h"
-#include "mads/madsv2/core/loader.h"
-#include "mads/madsv2/core/sprite.h"
-#include "mads/madsv2/core/sprite_h.h"
-
-namespace MADS {
-namespace MADSV2 {
-
-int sprite_error = 0;
-
-byte *sprite_force_memory = NULL;
-long sprite_force_size;
-
-const byte color_table[7] = { 7, 246, 247, 248, 249, 250, 251 };
-
-
-SeriesPtr sprite_series_load(const char *filename, int load_flags) {
- register int count;
- int len;
- int len2;
- int found, low_color, color_pointer;
- byte *base_pointer;
- byte *sprite_marker;
- char temp_buf[80];
- char block_name[20];
- char *mark;
- long base_quantity, quantity;
- long initial_quantity;
- long total_color_size;
- long largest_block;
- long total_offset;
- FileSeries header;
- FileSpritePtr sprite = NULL;
- SeriesPtr target = NULL;
- SeriesPtr result = NULL;
- SpritePageInfoPtr page_info;
- SpritePageTablePtr page_table;
- ColorListPtr color_list = NULL;
- /* ColorList color_list; */
- Load load_handle;
-
- mem_last_alloc_loader = MODULE_SPRITE_LOADER;
-
- load_handle.open = false;
-
- Common::strcpy_s(temp_buf, filename);
- if (strchr(temp_buf, '.') == NULL) {
- Common::strcat_s(temp_buf, ".SS");
- }
-
- Common::strcpy_s(block_name, "S$");
- mark = temp_buf;
- mads_strupr(temp_buf);
- if (*mark == '*') mark++;
- if ((*mark == 'R') && (*(mark + 1) == 'M')) {
- mark += 2;
- }
- strncat(block_name, mark, 6);
-
-
- /* Open our input file */
- if (loader_open(&load_handle, temp_buf, "rb", true)) {
- sprite_error = SS_ERR_OPENFILE;
- goto done;
- }
-
- /* Set default error condition */
-
- sprite_error = SS_ERR_READFILE;
-
- /* Determine length of header, and read it */
-
- len = sizeof(FileSeries) - sizeof(FileSprite);
-
- if (!loader_read(&header, len, 1, &load_handle)) goto done;
-
- if (header.misc_is_a_walker) load_flags |= SPRITE_LOAD_WALKER_INFO;
-
- /* Determine length of index record array */
-
- len2 = sizeof(FileSprite) * header.num_sprites;
-
- base_quantity = sizeof(Series) + (sizeof(Sprite) * (header.num_sprites - 1));
- if (load_flags & SPRITE_LOAD_WALKER_INFO) {
- base_quantity += sizeof(WalkerInfo);
- }
- initial_quantity = base_quantity;
- if (header.pack_by_sprite) {
- base_quantity += (SPRITE_COLOR_TABLE_SIZE + sizeof(SpritePageInfo) + (sizeof(SpritePageTable) * header.num_sprites));
- }
- quantity = base_quantity;
-
- if (!(load_flags & SPRITE_LOAD_HEADER_ONLY)) {
- if (!header.pack_by_sprite) {
- quantity += header.total_data_size;
- }
- }
-
- /* Allocate memory for entire series (target) and for the file-formatted */
- /* index record array (sprite) */
-
- if (sprite_force_memory != NULL) {
- if (quantity <= sprite_force_size) {
- target = (SeriesPtr)sprite_force_memory;
- }
- }
-
- if (target == NULL)
- // TODO: Check memory alignment
- target = (SeriesPtr)mem_get_name(quantity, block_name);
- if (target == NULL) {
- sprite_error = SS_ERR_NOMOREMEMORY;
- goto done;
- }
-
- // TODO: Check memory alignment
- sprite = (FileSpritePtr)mem_get_name(len2, "$sp-load");
- if (sprite == NULL) {
- sprite_error = SS_ERR_NOMOREMEMORY;
- goto done;
- }
-
- target->walker = NULL;
- target->color_table = NULL;
- target->page_info = NULL;
- target->page_table = NULL;
- target->arena = NULL;
-
- /* Read the index record array */
-
- if (!loader_read(sprite, len2, 1, &load_handle)) {
- sprite_error = SS_ERR_READFILE;
- goto done;
- }
-
- /* Read the color list */
-
- total_color_size = load_handle.pack.strategy[load_handle.pack_list_marker].size;
-
- // TODO: Confirm memory alignment
- color_list = (ColorListPtr)mem_get_name(total_color_size, "$color$");
- if (color_list == NULL) {
- sprite_error = SS_ERR_NOMOREMEMORY;
- goto done;
- }
-
- if (!loader_read(color_list, total_color_size, 1, &load_handle)) goto done;
-
- /* Copy relevant header data to target header */
-
- target->pack_by_sprite = header.pack_by_sprite;
- target->delta_series = header.delta_series && (header.base_mode < SS_INDIVIDUAL);
- target->base_mode = header.base_mode;
- target->num_sprites = header.num_sprites;
- target->offset_x_view = header.offset_x_view;
- target->offset_y_view = header.offset_y_view;
-
- for (count = 0; count < 16; count++) {
- target->misc[count] = header.misc[count];
- }
-
- /* Copy walker information, if requested */
-
- if (load_flags & SPRITE_LOAD_WALKER_INFO) {
- target->walker = (WalkerInfoPtr)(((byte *)(target)) + (initial_quantity - sizeof(WalkerInfo)));
- // TODO: Mem alignment check
- target->walker = (WalkerInfoPtr)mem_normalize(target->walker);
- memcpy(target->walker, &header.walker, sizeof(WalkerInfo));
- }
-
- /* base_pointer points to the beginning of the memory block at which */
- /* the sprite data will be loaded. */
-
- base_pointer = (byte *) (((byte *)target) + base_quantity);
- base_pointer = (byte *)mem_normalize(base_pointer);
- sprite_marker = base_pointer;
-
- /* Set up the target index record for each sprite, including a pointer */
- /* to the memory block designated for its sprite data. */
-
- for (count = 0; count < target->num_sprites; count++) {
- target->index[count].x = sprite[count].x;
- target->index[count].y = sprite[count].y;
- target->index[count].xs = sprite[count].xs;
- target->index[count].ys = sprite[count].ys;
- if (!(load_flags & SPRITE_LOAD_HEADER_ONLY) && !header.pack_by_sprite) {
- target->index[count].data = sprite_marker;
- sprite_marker = (byte *)mem_normalize(sprite_marker + sprite[count].memory_needed);
- } else {
- target->index[count].data = NULL;
- }
- }
-
- /* Load all of the sprite data in at the base address */
-
- if (!(load_flags & SPRITE_LOAD_HEADER_ONLY) && !header.pack_by_sprite) {
- if (!loader_read(base_pointer, header.total_data_size, 1, &load_handle)) goto done;
- }
-
- /* Perform palette allocation and color list transformation */
-
- if (load_flags & (SPRITE_LOAD_TRANSLATE | SPRITE_LOAD_SPINNING_OBJECT)) {
- target->color_handle = 0;
- if (load_flags & (SPRITE_LOAD_SPINNING_OBJECT)) {
- color_pointer = 0;
- for (count = 0; count < color_list->num_colors; count++) {
- found = false;
- for (low_color = 0; !found && (low_color < 4); low_color++) {
- if (memcmp(&color_list->table[count].r, &master_palette[low_color].r, sizeof(RGBcolor)) == 0) {
- found = true;
- color_list->table[count].x16 = (byte)low_color;
- }
- }
- if (!found) {
- memcpy(&master_palette[color_table[color_pointer]].r,
- &color_list->table[count].r, sizeof(RGBcolor));
- color_list->table[count].x16 = (byte)color_table[color_pointer];
- color_pointer = MIN(6, color_pointer + 1);
- }
- }
- sprite_color_translate(target, color_list);
- }
- } else {
-
- target->color_handle = pal_allocate(color_list, master_shadow, load_flags & PAL_MAP_MASK);
- if (target->color_handle < 0) {
- sprite_error = SS_ERR_TOOMANYCOLORS;
- goto done;
- }
-
- if (!(load_flags & SPRITE_LOAD_HEADER_ONLY) && !header.pack_by_sprite) {
- sprite_color_translate(target, color_list);
- }
- }
-
- /* If series was packed by sprite (and we are therefore expected to */
- /* stream-load it), we need to set up paging tables for the series. */
- /* This process is different depending on whether the sprite data */
- /* is to be loaded from disk or from the EMS preload area. */
-
- if (header.pack_by_sprite) {
- target->color_table = ((byte *)target) + initial_quantity;
- page_info = target->page_info = (SpritePageInfoPtr)(((byte *)target->color_table) + SPRITE_COLOR_TABLE_SIZE);
- page_table = target->page_table = (SpritePageTablePtr)(((byte *)page_info) + sizeof(SpritePageInfo));
-
- for (count = 0; count < color_list->num_colors; count++) {
- target->color_table[count] = color_list->table[count].x16;
- }
-
- page_info->packing_mode = header.compression;
- page_info->paging_source = (byte)load_handle.mode;
-
- if ((page_info->paging_source == LOADER_EMS) ||
- (page_info->paging_source == LOADER_XMS)) {
- page_info->ems_handle = load_handle.ems_handle;
- page_info->ems_page_marker = load_handle.ems_page_marker;
- page_info->ems_page_offset = load_handle.ems_page_offset;
- page_info->xms_handle = load_handle.xms_handle;
- page_info->xms_offset = load_handle.xms_offset;
- largest_block = 0;
- total_offset = 0;
- for (count = 0; count < target->num_sprites; count++) {
- page_table[count].file_offset = total_offset;
- page_table[count].memory_needed = sprite[count].memory_needed;
- total_offset += page_table[count].memory_needed;
- largest_block = MAX(largest_block, page_table[count].memory_needed);
- }
- } else {
- page_info->handle = load_handle.handle;
- total_offset = load_handle.handle->pos();
- page_info->base_sprite_offset = total_offset;
-
- largest_block = 0;
- for (count = 0; count < target->num_sprites; count++) {
- page_table[count].file_offset = sprite[count].file_offset;
- page_table[count].memory_needed = sprite[count].memory_needed;
- largest_block = MAX(largest_block, page_table[count].memory_needed);
- }
- }
-
- if (!(load_flags & SPRITE_LOAD_HEADER_ONLY)) {
- if (color_list != NULL) mem_free(color_list);
- color_list = NULL;
-
- if (sprite != NULL) mem_free(sprite);
- sprite = NULL;
-
- target->arena = (byte *)mem_get_name(largest_block, "$arena$");
- if (target->arena == NULL) goto done;
-
- memcpy(&target->misc_largest_block, &largest_block, sizeof(long));
-
- load_handle.open = false; /* Hack handle so it won't get closed */
- } else {
- target->arena = NULL;
- }
- }
-
- result = target;
-
-done:
- if (load_handle.open) loader_close(&load_handle);
- if (color_list != NULL) mem_free(color_list);
- if (sprite != NULL) mem_free(sprite);
- if ((target != NULL) && (target != (SeriesPtr)sprite_force_memory) && (result == NULL)) mem_free(target);
-
- return (result);
-}
-} // namespace MADSV2
-} // namespace MADS
-
-#endif
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index 7219affdff4..138f695b12c 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -88,8 +88,7 @@ MODULE_OBJS += \
madsv2/core/quote_1.o \
madsv2/core/screen.o \
madsv2/core/speech.o \
- madsv2/core/sprite_e.o \
- madsv2/core/sprite_k.o \
+ madsv2/core/sprite.o \
madsv2/core/text.o \
madsv2/core/tile_3.o \
madsv2/core/timer.o \
Commit: e6007be109459962bfe4d2efb3494cfcd216b643
https://github.com/scummvm/scummvm/commit/e6007be109459962bfe4d2efb3494cfcd216b643
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:19:05+10:00
Commit Message:
MADS: PHANTOM: Added kernel
Changed paths:
A engines/mads/madsv2/core/camera.cpp
A engines/mads/madsv2/core/camera.h
A engines/mads/madsv2/core/kernel.cpp
A engines/mads/madsv2/core/player.cpp
A engines/mads/madsv2/core/rail.cpp
A engines/mads/madsv2/core/rail.h
R engines/mads/madsv2/core/kernel_1.cpp
R engines/mads/madsv2/core/kernel_1.h
R engines/mads/madsv2/core/kernel_2.h
R engines/mads/madsv2/core/kernel_6.h
R engines/mads/madsv2/core/kernel_8.h
R engines/mads/madsv2/core/kernel_9.h
R engines/mads/madsv2/core/kernel_c.h
R engines/mads/madsv2/core/kernel_d.h
R engines/mads/madsv2/core/kernel_f.h
R engines/mads/madsv2/core/kernel_g.h
R engines/mads/madsv2/core/kernel_h.h
R engines/mads/madsv2/core/kernel_i.h
R engines/mads/madsv2/core/kernel_k.h
R engines/mads/madsv2/core/kernel_n.h
R engines/mads/madsv2/core/kernel_o.h
engines/mads/madsv2/core/kernel.h
engines/mads/madsv2/core/matte.cpp
engines/mads/madsv2/core/matte.h
engines/mads/madsv2/core/player.h
engines/mads/madsv2/core/sprite.cpp
engines/mads/madsv2/core/sprite.h
engines/mads/madsv2/core/video.h
engines/mads/module.mk
diff --git a/engines/mads/madsv2/core/camera.cpp b/engines/mads/madsv2/core/camera.cpp
new file mode 100644
index 00000000000..718fe6072b3
--- /dev/null
+++ b/engines/mads/madsv2/core/camera.cpp
@@ -0,0 +1,214 @@
+/* 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 "mads/madsv2/core/camera.h"
+#include "mads/madsv2/core/tile.h"
+#include "mads/madsv2/core/matte.h"
+#include "mads/madsv2/core/player.h"
+#include "mads/madsv2/core/error.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/inter.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+
+Camera camera_x; /* Horizontal panning camera */
+Camera camera_y; /* Vertical panning camera */
+
+int camera_old_x_target = 0;/* For saving/restoring game */
+int camera_old_y_target = 0;
+
+
+void camera_init_default(void) {
+ camera_x.panning = false;
+ camera_y.panning = false;
+
+ if (picture_map.one_to_one) {
+ camera_x.pans = false;
+ camera_y.pans = false;
+ goto done;
+ }
+
+ camera_x.pans = (picture_map.total_x_size > video_x);
+ camera_y.pans = (picture_map.total_y_size > display_y);
+
+ if (camera_x.pans) {
+ camera_x.pan_mode = CAMERA_PLAYER;
+ camera_x.pan_rate = 4;
+ camera_x.pan_velocity = CAMERA_DEFAULT_X_VELOCITY;
+ camera_x.pan_target = 0;
+ camera_x.pan_off_center = CAMERA_DEFAULT_X_OFF_CENTER;
+ camera_x.pan_on_tolerance = CAMERA_DEFAULT_X_START;
+ camera_x.pan_off_tolerance = CAMERA_DEFAULT_X_STOP;
+ camera_x.pan_clock = kernel.clock;
+ }
+
+ if (camera_y.pans) {
+ camera_y.pan_mode = CAMERA_MANUAL;
+ camera_y.pan_rate = 4;
+ camera_y.pan_velocity = CAMERA_DEFAULT_Y_VELOCITY;
+ camera_y.pan_target = 0;
+ camera_y.pan_off_center = CAMERA_DEFAULT_Y_OFF_CENTER;
+ camera_y.pan_on_tolerance = CAMERA_DEFAULT_Y_START;
+ camera_y.pan_off_tolerance = CAMERA_DEFAULT_Y_STOP;
+ camera_y.pan_clock = kernel.clock;
+ }
+
+done:
+ ;
+}
+
+static int camera_pan(Camera *camera, int *picture_view, int *player_loc,
+ int display_size, int picture_size) {
+ int any_pan = false;
+ int loc;
+ int high_edge, low_edge;
+ int dif;
+ int direction;
+ int magnitude;
+ int pan_me = 0;
+ long determining_clock;
+
+ if (camera->pans) {
+ camera->pan_this_frame = false;
+
+ /* Try to keep player & panning in synch */
+
+ if ((abs(camera->pan_clock - player.clock) < camera->pan_rate) &&
+ (player.frame_delay == camera->pan_rate)) {
+ determining_clock = player.clock;
+ } else {
+ determining_clock = camera->pan_clock;
+ }
+
+ if (camera->panning && (kernel.clock < determining_clock)) goto done;
+
+ camera->pan_clock = kernel.clock + camera->pan_rate;
+
+ if (camera->pan_mode == CAMERA_MANUAL) {
+ if (camera->panning) {
+ dif = camera->pan_target - *picture_view;
+ direction = sgn(dif);
+ magnitude = abs(dif);
+
+ magnitude = MIN(magnitude, camera->pan_velocity);
+
+ if (magnitude == 0) {
+ camera->panning = false;
+ } else {
+ pan_me = sgn_in(magnitude, direction);
+ *picture_view += pan_me;
+
+ any_pan = true;
+ camera->pan_this_frame = true;
+ }
+ }
+ } else {
+
+ if (!camera->panning) {
+ low_edge = *picture_view + camera->pan_on_tolerance;
+ high_edge = *picture_view - camera->pan_on_tolerance + display_size - 1;
+
+ if (*player_loc < low_edge) {
+ if (picture_view) {
+ camera->panning = true;
+ camera->pan_direction = -1;
+ }
+ }
+
+ if (*player_loc > high_edge) {
+ if (*picture_view < (picture_size - display_size)) {
+ camera->panning = true;
+ camera->pan_direction = 1;
+ }
+ }
+ }
+
+ loc = *player_loc - (display_size >> 1);
+
+ loc += sgn_in(camera->pan_off_center, camera->pan_direction);
+
+ loc = MAX(0, loc);
+ loc = MIN(loc, (picture_size - display_size));
+
+ camera->pan_target = loc;
+
+ dif = loc - *picture_view;
+ magnitude = abs(dif);
+ direction = sgn(dif);
+
+
+ if (camera->panning) {
+ if (magnitude <= camera->pan_off_tolerance) {
+ camera->panning = false;
+ }
+ }
+
+ if (camera->panning) {
+ magnitude = MIN(magnitude, camera->pan_velocity);
+ pan_me = sgn_in(magnitude, direction);
+
+ if (pan_me) {
+ *picture_view += pan_me;
+ any_pan = true;
+ camera->pan_this_frame = true;
+ }
+ }
+ }
+ }
+
+done:
+ return any_pan;
+}
+
+void camera_jump_to(int x, int y) {
+ picture_view_x = x;
+ picture_view_y = y;
+
+ tile_pan(&picture_map, picture_view_x, picture_view_y);
+ tile_pan(&depth_map, picture_view_x, picture_view_y);
+ matte_refresh_work();
+}
+
+void camera_pan_to(Camera *camera, int target) {
+ if (camera->pans) {
+ camera->panning = true;
+ camera->pan_mode = CAMERA_MANUAL;
+ camera->pan_target = target;
+ camera->pan_clock = kernel.clock;
+ }
+}
+
+void camera_update() {
+ int any_pan = false;
+
+ any_pan |= camera_pan(&camera_x, &picture_view_x, &player.x, video_x, picture_map.total_x_size);
+ any_pan |= camera_pan(&camera_y, &picture_view_y, &player.y, display_y, picture_map.total_y_size);
+
+ if (any_pan) {
+ camera_jump_to(picture_view_x, picture_view_y);
+ inter_force_rescan = true;
+ }
+}
+
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/core/camera.h b/engines/mads/madsv2/core/camera.h
new file mode 100644
index 00000000000..250ddd7352c
--- /dev/null
+++ b/engines/mads/madsv2/core/camera.h
@@ -0,0 +1,75 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef MADS_CORE_CAMERA_H
+#define MADS_CORE_CAMERA_H
+
+#include "mads/madsv2/core/general.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+
+#define CAMERA_PLAYER 0 /* Camera follows player */
+#define CAMERA_MANUAL 1 /* Camera manually panned */
+
+#define CAMERA_DEFAULT_X_VELOCITY 4 /* Camera defaults */
+#define CAMERA_DEFAULT_X_START 80
+#define CAMERA_DEFAULT_X_STOP 4
+#define CAMERA_DEFAULT_X_OFF_CENTER 80
+
+#define CAMERA_DEFAULT_Y_VELOCITY 2
+#define CAMERA_DEFAULT_Y_START 60
+#define CAMERA_DEFAULT_Y_STOP 4
+#define CAMERA_DEFAULT_Y_OFF_CENTER 80
+
+
+typedef struct {
+ int pans; /* Flag if camera can pan in this room */
+ int panning; /* Flag if camera now panning */
+ int pan_mode; /* Panning mode (CAMERA_PLAYER, etc.) */
+ int pan_velocity; /* Pixel velocity of pan */
+ int pan_rate; /* Pan frame rate */
+ int pan_target; /* Pan X or Y target for manual pans */
+ int pan_off_center; /* Pan distance off center */
+ int pan_on_tolerance; /* Pan initiator tolerance */
+ int pan_off_tolerance; /* Pan terminator tolerance */
+ int pan_direction; /* Pan initial direction */
+ long pan_clock; /* Pan clock for next update */
+ int pan_this_frame; /* Flag if panned this frame */
+} Camera;
+
+
+extern Camera camera_x; /* Horizontal panning camera */
+extern Camera camera_y; /* Vertical panning camera */
+
+extern int camera_old_x_target;/* For saving/restoring game */
+extern int camera_old_y_target;
+
+extern void camera_init_default();
+extern void camera_jump_to(int x, int y);
+extern void camera_pan_to(Camera *camera, int target);
+extern void camera_update();
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/kernel.cpp b/engines/mads/madsv2/core/kernel.cpp
new file mode 100644
index 00000000000..19453fa3e2f
--- /dev/null
+++ b/engines/mads/madsv2/core/kernel.cpp
@@ -0,0 +1,3088 @@
+/* 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 "mads/madsv2/core/general.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/mem.h"
+#include "mads/madsv2/core/buffer.h"
+#include "mads/madsv2/core/font.h"
+#include "mads/madsv2/core/video.h"
+#include "mads/madsv2/core/matte.h"
+#include "mads/madsv2/core/inter.h"
+#include "mads/madsv2/core/mouse.h"
+#include "mads/madsv2/core/object.h"
+#include "mads/madsv2/core/error.h"
+#include "mads/madsv2/core/screen.h"
+#include "mads/madsv2/core/ems.h"
+#include "mads/madsv2/core/himem.h"
+#include "mads/madsv2/core/echo.h"
+#include "mads/madsv2/core/mcga.h"
+#include "mads/madsv2/core/timer.h"
+#include "mads/madsv2/core/cycle.h"
+#include "mads/madsv2/core/player.h"
+#include "mads/madsv2/core/keys.h"
+#include "mads/madsv2/core/pack.h"
+#include "mads/madsv2/core/room.h"
+#include "mads/madsv2/core/demo.h"
+#include "mads/madsv2/core/xms.h"
+#include "mads/madsv2/core/lock.h"
+#include "mads/madsv2/core/tile.h"
+#include "mads/madsv2/core/popup.h"
+#include "mads/madsv2/core/pal.h"
+#include "mads/madsv2/core/env.h"
+#include "mads/madsv2/core/fileio.h"
+#include "mads/madsv2/core/vocab.h"
+#include "mads/madsv2/core/midi.h"
+#include "mads/madsv2/core/digi.h"
+#include "mads/madsv2/core/rail.h"
+#include "mads/madsv2/core/hspot.h"
+#include "mads/madsv2/core/attr.h"
+#include "mads/madsv2/core/camera.h"
+#include "mads/madsv2/core/quote.h"
+#include "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/imath.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+#define MESSAGE_COLOR_3 (((KERNEL_MESSAGE_COLOR_BASE_3 + 1) << 8) + KERNEL_MESSAGE_COLOR_BASE_3)
+#define MESSAGE_COLOR (((KERNEL_MESSAGE_COLOR_BASE + 1) << 8) + KERNEL_MESSAGE_COLOR_BASE)
+
+extern int first_inven;
+
+#define OMR 40 /* OUAF_MAX_ROOMS in global.mac */
+extern int room_state[OMR];
+
+byte video_mode;
+RoomPtr room = NULL;
+int room_id = KERNEL_STARTING_GAME;
+int section_id = KERNEL_STARTING_GAME;
+int room_variant = 0;
+
+int new_room = 101;
+int new_section = 1;
+
+int previous_room = 0;
+int previous_section = 0;
+
+int kernel_initial_variant = 0;
+
+HotPtr room_spots = NULL;
+int room_num_spots = 0;
+
+int kernel_room_series_marker = 0;
+
+int kernel_room_bound_dif;
+int kernel_room_scale_dif;
+
+int kernel_allow_peel = false;
+
+int kernel_panning_speed = 0;
+int kernel_screen_fade = 0;
+
+Animation kernel_anim[KERNEL_MAX_ANIMATIONS];
+
+ShadowList kernel_shadow_main = { 0 };
+ShadowList kernel_shadow_inter = { 1, { 15 } };
+
+int kernel_ok_to_fail_load = false;
+
+int kernel_mode = KERNEL_GAME_LOAD;
+
+char kernel_cheating_password[16];
+int kernel_cheating_allowed = 0;
+int kernel_cheating_forbidden = 0;
+
+KernelDynamicHotSpot kernel_dynamic_hot[KERNEL_MAX_DYNAMIC];
+int kernel_num_dynamic = 0;
+int kernel_dynamic_changed = 0;
+
+SeriesPtr cursor = NULL; /* Mouse cursor series */
+
+int cursor_id = 1;
+int cursor_last = -1;
+
+Kernel kernel; /* Kernel data */
+KernelGame game; /* Kernel level game data */
+
+Sequence sequence_list[KERNEL_MAX_SEQUENCES];
+
+int stop_speech_on_run_anim = true;
+
+KernelMessage kernel_message[KERNEL_MAX_MESSAGES];
+FontPtr kernel_message_font;
+int kernel_message_spacing;
+static char kernel_work_name[20];
+int kernel_sound_handle = 0;
+
+int random_message_handle[KERNEL_MAX_RANDOM_MESSAGES]; /* List of active handles */
+int random_message_quote[KERNEL_MAX_RANDOM_MESSAGES]; /* List of active quote id's */
+int random_max_messages = 1; /* # of active handles/ids */
+
+int random_quote_list[KERNEL_MAX_RANDOM_QUOTES]; /* List of available quote id's */
+int random_quote_list_size = 0; /* # of available quote id's */
+
+int random_min_x = 0; /* X location allowable range */
+int random_max_x = video_x;
+
+int random_min_y = 0; /* Y location allowable range */
+int random_max_y = display_y;
+int random_spacing; /* Y location minimum spacing */
+
+int random_teletype_rate = 0; /* Rate for teletype */
+
+int random_message_color; /* Color scheme for message */
+int random_message_duration; /* Duration of messages */
+
+char kernel_interface_loaded[40] = "";
+
+static char digital_name[12] = "digital.aga";
+
+
+static void kernel_seq_image(SequencePtr sequence, ImagePtr image, int sequence_id);
+static void kernel_reconstruct_screen(int anim_handle);
+static void kernel_animation_get_sprite(int handle, int id);
+
+
+int kernel_load_vocab() {
+ int error_flag;
+ int count;
+ int count2;
+#ifdef log_vocab
+ FILE *handle;
+ long before, after;
+#endif
+
+ /* Load all main command verbs */
+
+ for (count = 0; count < INTER_COMMANDS; count++) {
+ vocab_make_active(command[count].id);
+ }
+
+ /* Load all object names, and all verbs associated with objects */
+
+ for (count = 0; count < num_objects; count++) {
+ vocab_make_active(object[count].vocab_id);
+
+ for (count2 = 0; count2 < (int)object[count].num_verbs; count2++) {
+ vocab_make_active(object[count].verb[count2].id);
+ }
+ }
+
+ /* Load vocabulary for this room's hot spots */
+
+ for (count = 0; count < room_num_spots; count++) {
+ vocab_make_active(room_spots[count].vocab);
+ if (room_spots[count].verb > 0) {
+ vocab_make_active(room_spots[count].verb);
+ }
+ }
+
+#ifdef log_vocab
+ before = mem_get_avail();
+#endif
+
+ error_flag = vocab_load_active();
+
+#ifdef log_vocab
+ after = mem_get_avail();
+ if (fileio_exist("vocab.log")) {
+ handle = fopen("vocab.log", "wt");
+ fprintf(handle, "Room %d Vocab words: %d Memory: %ld\n",
+ room_id, vocab_active, before - after);
+ fclose(handle);
+ }
+#endif
+
+ return error_flag;
+}
+
+void kernel_game_shutdown() {
+ int check_mode;
+
+ sprite_free(&box_param.menu, true);
+ sprite_free(&box_param.logo, true);
+ sprite_free(&box_param.series, true);
+
+ buffer_free(&scr_inter_orig);
+
+ vocab_unload_active();
+
+ /* Drop cursor */
+
+ if (cursor != NULL) mem_free(cursor);
+ cursor = NULL;
+
+ /* Free main video work buffer */
+
+ pack_set_special_buffer(NULL, NULL);
+
+ object_unload();
+ /* inter_deallocate_objects(); */
+
+ popup_available = false;
+
+ /* Remove special keyboard handler */
+
+ keys_remove();
+
+ /* Unload interface fonts */
+
+ if (font_misc != NULL) mem_free(font_misc);
+ if (font_menu != NULL) mem_free(font_menu);
+ if (font_conv != NULL) mem_free(font_conv);
+ if (font_inter != NULL) mem_free(font_inter);
+ if (font_main != NULL) mem_free(font_main);
+
+ font_main = font_conv = font_inter = NULL;
+
+ /* Deallocate main screen buffer */
+
+ if (work_screen_ems_handle < 0) buffer_free(&scr_main);
+
+ /* Turn of speech system */
+
+ /* pl if (speech_system_active) speech_shutdown(); */
+
+ /* Return video to text mode */
+
+ mouse_hide();
+ check_mode = video_mode;
+ mouse_init(false, text_mode);
+ video_init(text_mode, (check_mode != text_mode));
+
+ /* Deallocate EMS/XMS memory */
+
+ himem_shutdown();
+
+ /* Remove timer interrupt stuff */
+
+ midi_uninstall();
+ digi_uninstall();
+
+ timer_activate_low_priority(NULL);
+
+ timer_remove();
+}
+
+void kernel_force_refresh() {
+ int count;
+ int purge_flag = true;
+
+ for (count = 0; count < (int)image_marker; count++) {
+ if (image_list[count].flags == IMAGE_REFRESH) {
+ purge_flag = false;
+ }
+ }
+
+ if (purge_flag) matte_refresh_work();
+}
+
+int kernel_game_startup(int game_video_mode, int load_flag,
+ const char *release_version, const char *release_date) {
+ int error_flag = true;
+ int count, count2;
+ int ems_temp;
+ int ems_error;
+ int pages;
+ int reserve[EMS_PAGING_CLASSES];
+ byte *interrupt_stack;
+#ifdef demo
+ char temp_buf[20];
+#endif
+#ifndef disable_error_check
+ int error_code = 0;
+#endif
+
+ /* Set up EMS/XMS paging system, if any */
+
+ himem_startup();
+
+ ems_error = true;
+
+ if (ems_exists) {
+ work_screen_ems_handle = ems_get_page_handle(4);
+ if (work_screen_ems_handle >= 0) {
+ ems_error = false;
+ }
+ }
+
+ if (tile_setup()) ems_error = true;
+
+ if (ems_error) {
+ if (ems_exists) {
+ error_report(ERROR_NO_MORE_EMS, SEVERE, MODULE_KERNEL, ems_pages, work_screen_ems_handle);
+ } else {
+ error_report(ERROR_KERNEL_NO_EMS, SEVERE, MODULE_KERNEL, ems_exists, work_screen_ems_handle);
+ }
+ }
+
+ if (ems_exists) {
+ if (load_flag & KERNEL_STARTUP_POPUP) {
+ object_ems_handle = ems_get_page_handle(4);
+
+ ems_temp = ems_get_page_handle(4);
+ if (ems_temp >= 0) popup_preserve_initiator[0] = ems_temp;
+
+ ems_temp = ems_get_page_handle(4);
+ if (ems_temp >= 0) popup_preserve_initiator[1] = ems_temp;
+
+ ems_temp = ems_get_page_handle(4);
+ if (ems_temp >= 0) popup_preserve_initiator[2] = ems_temp;
+ }
+ }
+
+
+ if (ems_exists) {
+ pages = ems_pages_free;
+ for (count = 0; count < EMS_PAGING_CLASSES; count++) {
+ reserve[EMS_PAGING_CLASSES] = 0;
+ }
+ if (pages >= 4) {
+ reserve[EMS_PAGING_SYSTEM] = 4;
+ pages -= 4;
+ }
+ ems_temp = MIN(pages >> 1, 64);
+ reserve[EMS_PAGING_ROOM] = ems_temp;
+ pages -= ems_temp;
+
+ ems_temp = pages >> 2;
+ reserve[EMS_PAGING_SECTION] = ems_temp;
+ pages -= ems_temp;
+
+ for (count = 0; count < EMS_PAGING_CLASSES; count++) {
+ ems_paging_reserve[count] = 0;
+ for (count2 = count - 1; count2 >= 0; count2--) {
+ ems_paging_reserve[count] += reserve[count2];
+ }
+ }
+ }
+
+ /* Some preliminary copy protection stuff */
+
+ /* lock_preliminary_check(); */
+
+ /* Initialize sound driver jump table */
+
+ /* pl sound_driver_null(); */
+ timer_set_sound_flag(0);
+
+ /* Video initialization */
+
+ screen_dominant_mode(game_video_mode);
+ video_init(game_video_mode, (game_video_mode != text_mode));
+ mouse_init(true, game_video_mode);
+
+ if (game_video_mode == mcga_mode) {
+ mcga_compute_retrace_parameters();
+ }
+
+ /* Initialize the main screen work buffer & its sub-buffers */
+
+ if (work_screen_ems_handle >= 0) {
+ scr_main.x = video_x;
+ scr_main.y = video_y;
+ scr_main.data = ems_page[0];
+ ems_map_buffer(work_screen_ems_handle);
+ } else {
+ buffer_init_name(&scr_main, video_x, video_y, "$scrmain");
+ }
+ if (scr_main.data == NULL) {
+#ifndef disable_error_check
+ error_code = ERROR_NO_MORE_MEMORY;
+#endif
+ goto done;
+ }
+
+ scr_work.x = scr_inter.x = video_x;
+ scr_work.y = display_y;
+ scr_inter.y = inter_size_y;
+
+ scr_work.data = scr_main.data;
+ scr_inter.data = (byte *)mem_normalize(buffer_pointer(&scr_main, 0, inter_base_y));
+
+ buffer_fill(scr_main, 0);
+
+ /* Load the main interface fonts */
+
+ if (load_flag & KERNEL_STARTUP_FONT) {
+ font_main = font_load("*FONTMAIN.FF");
+ font_inter = font_load("*FONTINTR.FF");
+ font_conv = font_load("*FONTCONV.FF");
+ font_menu = font_load("*FONTMENU.FF");
+ font_misc = font_load("*FONTMISC.FF");
+
+ if ((font_main == NULL) || (font_inter == NULL) ||
+ (font_conv == NULL) || (font_menu == NULL) ||
+ (font_misc == NULL)) {
+#ifndef disable_error_check
+ error_code = ERROR_KERNEL_NO_FONTS;
+#endif
+ goto done;
+ }
+ }
+
+
+ /* Install timer handler & low priority cycling interrupt */
+
+ if (load_flag & KERNEL_STARTUP_INTERRUPT) {
+ timer_install();
+
+ midi_install();
+ digi_install();
+
+ /*
+ if (!lock_verification()) {
+ error_report (ERROR_COPY_PROTECTION, SEVERE, MODULE_LOCK, 0, 0);
+ }
+ timer_remove();
+ timer_install();
+ */
+
+ cycling_active = false;
+ timer_activate_low_priority(cycle_colors);
+ keys_install();
+ }
+
+ /* Log in demo copy */
+
+#ifdef demo
+ if (game_video_mode != text_mode) demo_log_in(release_version, release_date);
+#endif
+
+ /* Mention EMS paging situation */
+
+#ifdef demo
+ if (ems_paging_active) {
+ ltoa(((long)ems_pages * EMS_PAGE_SIZE) >> 10, temp_buf, 10);
+ echo(temp_buf, false);
+ echo("K of EMS memory available.", true);
+ } else {
+ echo("EMS memory not available.", true);
+ }
+
+ if (xms_exists) {
+ echo("XMS memory system detected.", true);
+ }
+#endif
+
+ /* Load the objects list */
+
+ if (load_flag & KERNEL_STARTUP_OBJECTS) {
+ /* inter_allocate_objects(); */
+ if (object_load()) {
+#ifndef disable_error_check
+ error_code = ERROR_KERNEL_NO_OBJECTS;
+#endif
+ goto done;
+ }
+ if (inven_num_objects > 0) {
+ active_inven = 0;
+ }
+ }
+
+ /* Allow packing routines to use lower interrupt stack */
+
+ interrupt_stack = timer_get_interrupt_stack();
+ pack_set_special_buffer(interrupt_stack, NULL);
+
+ /* Initialize player data structures */
+
+ if (load_flag & KERNEL_STARTUP_PLAYER) player_init();
+
+ popup_available = true;
+
+ /* video_update (&scr_main, 0, 0, 0, 0, video_x, video_y); */
+
+ Common::strcpy_s(box_param.name, "*BOX.SS");
+
+ if (load_flag & KERNEL_STARTUP_CURSOR) {
+
+ /* Wipe palette & prepare for cursor */
+
+ pal_init(KERNEL_RESERVED_LOW_COLORS, KERNEL_RESERVED_HIGH_COLORS);
+ pal_white(master_palette);
+ if (video_mode == mcga_mode) {
+ mcga_setpal_range(&master_palette, 0, 4);
+ }
+
+ /* Load cursor sprite series */
+
+ cursor = sprite_series_load("*CURSOR.SS", PAL_MAP_RESERVED | PAL_MAP_DEFINE_RESERVED);
+ if (cursor == NULL) {
+#ifndef disable_error_check
+ error_code = ERROR_KERNEL_NO_CURSOR;
+#endif
+ goto done;
+ }
+
+ /* Activate main cursor sprite as mouse cursor */
+
+ cursor_last = cursor_id = (cursor->num_sprites > 1) ? 2 : 1;
+ mouse_cursor_sprite(cursor, cursor_id);
+ }
+
+ if (load_flag & KERNEL_STARTUP_VOCAB) {
+ vocab_load_active();
+ }
+
+ if (load_flag & KERNEL_STARTUP_INTERFACE) {
+ buffer_init_name(&scr_inter_orig, video_x, inter_size_y, "$scrintr");
+ if (scr_inter_orig.data == NULL) {
+ error_code = ERROR_NO_MORE_MEMORY;
+ goto done;
+ }
+ }
+
+ if (load_flag & KERNEL_STARTUP_POPUP) {
+ if (popup_box_load()) {
+ error_code = ERROR_KERNEL_NO_POPUP;
+ goto done;
+ }
+ }
+
+ error_flag = false;
+
+done:
+ if (load_flag & KERNEL_STARTUP_CURSOR_SHOW) mouse_show();
+ if (error_flag) {
+#ifndef disable_error_check
+ error_check_memory();
+ error_report(error_code, ERROR, MODULE_KERNEL, 0, 0);
+#endif
+ kernel_game_shutdown();
+ }
+
+ return error_flag;
+}
+
+void kernel_section_shutdown() {
+}
+
+int kernel_section_startup(int newSection) {
+ int error_flag = true;
+
+ /* Make note of new section number */
+
+ previous_section = section_id;
+ section_id = newSection;
+
+ error_flag = false;
+
+ return error_flag;
+}
+
+void kernel_room_shutdown() {
+ inter_deallocate_objects();
+
+ /* Dump the room hot spots */
+ if (room_spots != NULL) {
+ mem_free(room_spots);
+ room_spots = NULL;
+ room_num_spots = 0;
+ }
+
+ /* Remove our palette shadowing list */
+
+ pal_activate_shadow(NULL);
+
+ if (room != NULL) {
+ room_unload(room,
+ &scr_orig,
+ &scr_depth,
+ &scr_walk,
+ &scr_special,
+ &picture_map,
+ &depth_map);
+ room = NULL;
+ }
+}
+
+int kernel_room_startup(int newRoom, int initial_variant, char *interface, int new_palette) {
+ int error_flag = true;
+ int load_flags;
+#ifndef disable_error_check
+ int error_code = 0;
+ int error_data = 0;
+#endif
+
+ /* Make a note of the new room number & variant */
+
+ previous_room = room_id;
+ room_id = newRoom;
+ room_variant = initial_variant;
+
+ /* Start a brand new palette, reserving the proper # of colors */
+
+ if (new_palette) pal_init(KERNEL_RESERVED_LOW_COLORS, KERNEL_RESERVED_HIGH_COLORS);
+
+ pal_white(master_palette);
+
+ /* Load up popup box frame */
+
+ /*
+ if (popup_box_load()) {
+ error_code = ERROR_KERNEL_NO_POPUP;
+ goto done;
+ }
+ */
+
+ /* Initialize the matteing system */
+
+ matte_init(false);
+
+ /* Initialize graphics sequence data structures */
+
+ kernel_seq_init();
+ kernel_message_init();
+
+ /* Activate the main shadow list */
+
+ pal_activate_shadow(&kernel_shadow_main);
+
+ /* Load header, picture, and attribute screen for this room */
+
+ load_flags = ROOM_LOAD_HARD_SHADOW;
+ if (kernel.translating) load_flags |= ROOM_LOAD_TRANSLATE;
+
+ room = room_load(room_id, room_variant, NULL,
+ &scr_orig,
+ &scr_depth,
+ &scr_walk,
+ &scr_special,
+ &picture_map,
+ &depth_map,
+ &picture_resource,
+ &depth_resource,
+ tile_picture_handle,
+ tile_attribute_handle,
+ load_flags);
+ if (room == NULL) {
+#ifndef disable_error_check
+ error_data = room_load_error;
+ error_code = ERROR_KERNEL_NO_ROOM;
+#endif
+ goto done;
+ }
+
+ tile_pan(&picture_map, picture_view_x, picture_view_y);
+ tile_pan(&depth_map, picture_view_x, picture_view_y);
+
+ /* Set up color cycling table for this room */
+
+ cycle_init(&room->cycle_list, false);
+
+ /* Initialize rail-system parameters for this room */
+
+ rail_num_nodes = room->num_rails + 2;
+ rail_base = (byte *) & room->rail[0];
+
+ rail_connect_all_nodes();
+
+ /* Load up the room's hotspot table */
+
+ room_spots = room_load_hotspots(room_id, &room_num_spots);
+ if (room_spots == NULL) {
+#ifndef disable_error_check
+ error_code = ERROR_KERNEL_NO_HOTSPOTS;
+#endif
+ goto done;
+ }
+
+ inter_anim = NULL;
+
+ /* Make preliminary scaling computations */
+
+ kernel_room_bound_dif = room->front_y - room->back_y;
+ kernel_room_scale_dif = room->front_scale - room->back_scale;
+
+ /* Initialize the graphics image lists */
+
+ image_marker = 1;
+ image_list[0].flags = IMAGE_REFRESH;
+ image_list[0].segment_id = KERNEL_SEGMENT_SYSTEM;
+
+ /* Set up graphics window locations */
+
+ viewing_at_y = 0;
+ inter_viewing_at_y = inter_base_y;
+
+ /* Mark the boundary between interface and room sprite series */
+
+ kernel_room_series_marker = series_list_marker;
+
+ /* Set up interface background screen */
+
+ kernel_set_interface_mode(inter_input_mode);
+
+ /* Mouse cursor on */
+
+ while ((char)mouse_showing > 0) mouse_show();
+
+ inter_allocate_objects();
+
+ error_flag = false;
+
+done:
+ if (error_flag) {
+#ifndef disable_error_check
+ error_check_memory();
+ error_report(error_code, ERROR, MODULE_KERNEL, room_id, error_data);
+#endif
+ kernel_room_shutdown();
+ }
+ return error_flag;
+}
+
+void kernel_unload_all_series() {
+ int count;
+
+ /* Unload all series (but don't unload those for the interface background) */
+
+ for (count = series_list_marker - 1; count >= kernel_room_series_marker; count--) {
+ if (series_user[count] > 1) series_user[count] = 1;
+ matte_deallocate_series(count, true);
+ }
+}
+
+int kernel_load_series(const char *name, int load_flags) {
+ int handle = -2;
+
+ if (kernel.translating) load_flags |= SPRITE_LOAD_TRANSLATE;
+
+ handle = matte_load_series(name, load_flags, 0);
+
+ if ((handle < 0) && !kernel_ok_to_fail_load) {
+#ifndef disable_error_check
+ Common::strcpy_s(error_string, name);
+ error_report(ERROR_SERIES_LOAD_FAILED, WARNING, MODULE_KERNEL, handle, sprite_error);
+#endif
+ }
+
+ return handle;
+}
+
+/*
+/* kernel_flip_hotspot()
+/*
+/* Toggles an interface hotspot (referenced by its vocabulary word)
+/* on or off. Hotspots that are off do not interact with the mouse
+/* cursor.
+*/
+void kernel_flip_hotspot(int vocab_code, int active) {
+ int count;
+
+ for (count = 0; count < room_num_spots; count++) {
+ if (room_spots[count].vocab == vocab_code) {
+ room_spots[count].active = (byte)active;
+ hspot_toggle(STROKE_INTERFACE, count, active);
+ }
+ }
+}
+
+void kernel_flip_hotspot_loc(int vocab_code, int active, int x, int y) {
+ int count;
+
+ for (count = 0; count < room_num_spots; count++) {
+ if (room_spots[count].vocab == vocab_code) {
+ if ((x >= room_spots[count].ul_x) &&
+ (x <= room_spots[count].lr_x) &&
+ (y >= room_spots[count].ul_y) &&
+ (y <= room_spots[count].lr_y)) {
+ room_spots[count].active = (byte)active;
+ hspot_toggle(STROKE_INTERFACE, count, active);
+ }
+ }
+ }
+}
+
+void kernel_seq_init() {
+ int count;
+
+ for (count = 0; count < KERNEL_MAX_SEQUENCES; count++) {
+ sequence_list[count].active_flag = false;
+ sequence_list[count].dynamic_hotspot = -1;
+ }
+}
+
+int kernel_seq_add(int series_id, int mirror, int initial_sprite,
+ int low_sprite, int high_sprite, int loop_mode, int loop_direction,
+ int depth, int scale, int auto_locating, int x, int y,
+ word ticks, word interval_ticks, word start_ticks, int expire) {
+ int result = -1;
+ int id = -1;
+ int found = false;
+ int count;
+
+ for (count = 0; !found && (count < KERNEL_MAX_SEQUENCES); count++) {
+ id = count;
+ found = !sequence_list[count].active_flag;
+ }
+
+ if (!found) {
+#if !defined(disable_error_check)
+ error_report(ERROR_SEQUENCE_LIST_FULL, WARNING, MODULE_KERNEL, KERNEL_MAX_SEQUENCES, 0);
+#endif
+ goto done;
+ }
+
+ if (low_sprite <= 0) {
+ low_sprite = 1;
+ }
+
+ if (high_sprite <= 0) {
+ high_sprite = series_list[series_id]->num_sprites;
+ }
+
+ if (high_sprite == low_sprite) {
+ loop_direction = 0;
+ }
+
+ sequence_list[id].active_flag = true;
+ sequence_list[id].series_id = (byte)series_id;
+ sequence_list[id].mirror = (byte)mirror;
+ sequence_list[id].sprite = initial_sprite;
+ sequence_list[id].start_sprite = low_sprite;
+ sequence_list[id].end_sprite = high_sprite;
+ sequence_list[id].loop_mode = loop_mode;
+ sequence_list[id].loop_direction = loop_direction;
+ sequence_list[id].depth = (byte)depth;
+ sequence_list[id].scale = (byte)scale;
+ sequence_list[id].auto_locating = (byte)auto_locating;
+ sequence_list[id].x = x;
+ sequence_list[id].y = y;
+ sequence_list[id].ticks = ticks;
+ sequence_list[id].interval_ticks = interval_ticks;
+ sequence_list[id].base_time = kernel.clock + start_ticks;
+ sequence_list[id].expire = (byte)expire;
+ sequence_list[id].expired = false;
+
+ sequence_list[id].motion = 0;
+ sequence_list[id].dynamic_hotspot = -1;
+
+ sequence_list[id].num_triggers = 0;
+ sequence_list[id].trigger_dest = (byte)kernel.trigger_setup_mode;
+
+ for (count = 0; count < 3; count++) {
+ sequence_list[id].trigger_words[count] = player2.words[count];
+ }
+
+ sequence_list[id].last_image.flags = -1;
+
+ result = id;
+
+done:
+ return result;
+}
+
+int kernel_seq_forward(int series_id, int mirror, word ticks, word interval_ticks,
+ word start_ticks, int expire) {
+ int depth;
+ SpritePtr sprite;
+
+ sprite = &series_list[series_id]->index[0];
+
+ depth = attr_depth(&depth_map,
+ sprite->x + (sprite->xs >> 1),
+ sprite->y + (sprite->ys >> 1)) - 1;
+
+ return (kernel_seq_add(series_id, mirror, 1, 0, 0, AA_LINEAR, 1,
+ depth, 100, true, 0, 0, ticks, interval_ticks,
+ start_ticks, expire));
+}
+
+int kernel_seq_forward_scroll(int series_id, int mirror, word ticks, word interval_ticks,
+ word start_ticks, int expire) {
+ int depth = 0;
+ SpritePtr sprite;
+
+ sprite = &series_list[series_id]->index[0];
+
+ return (kernel_seq_add(series_id, mirror, 1, 0, 0, AA_LINEAR, 1,
+ depth, 100, true, 0, 0, ticks, interval_ticks,
+ start_ticks, expire));
+}
+
+int kernel_seq_pingpong(int series_id, int mirror,
+ word ticks, word interval_ticks,
+ word start_ticks,
+ int expire) {
+ int depth;
+ SpritePtr sprite;
+
+ sprite = &series_list[series_id]->index[0];
+
+ depth = attr_depth(&depth_map,
+ sprite->x + (sprite->xs >> 1),
+ sprite->y + (sprite->ys >> 1)) - 1;
+
+ return (kernel_seq_add(series_id, mirror, 1, 0, 0, AA_PINGPONG, 1,
+ depth, 100, true, 0, 0, ticks, interval_ticks,
+ start_ticks, expire));
+}
+
+int kernel_seq_pingpong_scroll(int series_id, int mirror,
+ word ticks, word interval_ticks,
+ word start_ticks,
+ int expire) {
+ int depth = 0;
+ SpritePtr sprite;
+
+ sprite = &series_list[series_id]->index[0];
+
+ return kernel_seq_add(series_id, mirror, 1, 0, 0, AA_PINGPONG, 1,
+ depth, 100, true, 0, 0, ticks, interval_ticks,
+ start_ticks, expire);
+}
+
+int kernel_seq_backward(int series_id, int mirror, word ticks, word interval_ticks,
+ word start_ticks, int expire) {
+ int depth;
+ SpritePtr sprite;
+
+ sprite = &series_list[series_id]->index[0];
+
+ depth = attr_depth(&depth_map,
+ sprite->x + (sprite->xs >> 1),
+ sprite->y + (sprite->ys >> 1)) - 1;
+
+ return kernel_seq_add(series_id, mirror,
+ series_list[series_id]->num_sprites,
+ 0, 0, AA_LINEAR, -1, depth, 100, true, 0, 0,
+ ticks, interval_ticks, start_ticks, expire);
+}
+
+int kernel_seq_backward_scroll(int series_id, int mirror,
+ word ticks, word interval_ticks,
+ word start_ticks,
+ int expire) {
+ int depth = 0;
+ SpritePtr sprite;
+
+ sprite = &series_list[series_id]->index[0];
+
+ return (kernel_seq_add(series_id, mirror,
+ series_list[series_id]->num_sprites,
+ 0, 0, AA_LINEAR, -1, depth, 100, true, 0, 0,
+ ticks, interval_ticks, start_ticks, expire));
+}
+void kernel_synch(int slave_type, int slave_id, int master_type, int master_id) {
+ long master_time;
+
+ switch (master_type) {
+ case KERNEL_SERIES:
+ master_time = sequence_list[master_id].base_time;
+ break;
+
+ case KERNEL_ANIM:
+ master_time = kernel_anim[master_id].next_clock;
+ break;
+
+ case KERNEL_NOW:
+ master_time = kernel.clock + (long)master_id;
+ break;
+
+ case KERNEL_PLAYER:
+ default:
+ master_time = player.clock;
+ break;
+ }
+
+
+ switch (slave_type) {
+ case KERNEL_SERIES:
+ sequence_list[slave_id].base_time = master_time;
+ break;
+
+ case KERNEL_PLAYER:
+ player.clock = master_time;
+ break;
+
+ case KERNEL_ANIM:
+ kernel_anim[slave_id].next_clock = master_time;
+ break;
+ }
+}
+
+void kernel_player_expire(int sequence_id) {
+ sequence_list[sequence_id].expired = true;
+ sequence_list[sequence_id].base_time = player.clock;
+}
+
+void kernel_seq_depth(int sequence_id, int depth) {
+ sequence_list[sequence_id].depth = (byte)depth;
+}
+
+void kernel_seq_scale(int sequence_id, int scale) {
+ sequence_list[sequence_id].scale = (byte)scale;
+}
+
+void kernel_seq_loc(int sequence_id, int x, int y) {
+ sequence_list[sequence_id].x = x;
+ sequence_list[sequence_id].y = y;
+ sequence_list[sequence_id].auto_locating = false;
+}
+
+void kernel_seq_motion(int sequence_id, int flags,
+ int delta_x_times_100,
+ int delta_y_times_100) {
+ sequence_list[sequence_id].motion = (byte)(KERNEL_MOTION | flags);
+ sequence_list[sequence_id].sign_x = sgn(delta_x_times_100);
+ sequence_list[sequence_id].sign_y = sgn(delta_y_times_100);
+ sequence_list[sequence_id].delta_x = abs(delta_x_times_100);
+ sequence_list[sequence_id].delta_y = abs(delta_y_times_100);
+ sequence_list[sequence_id].accum_x = 0;
+ sequence_list[sequence_id].accum_y = 0;
+}
+
+void kernel_seq_range(int sequence_id, int first, int last) {
+ int num_sprites;
+ int from, unto;
+ SequencePtr sequence;
+
+ sequence = &sequence_list[sequence_id];
+
+ num_sprites = series_list[sequence->series_id]->num_sprites;
+
+ switch (first) {
+ case KERNEL_FIRST:
+ case KERNEL_DEFAULT:
+ from = 1;
+ break;
+ case KERNEL_LAST:
+ from = num_sprites;
+ break;
+ default:
+ from = first;
+ break;
+ }
+
+ switch (last) {
+ case KERNEL_FIRST:
+ unto = 1;
+ break;
+ case KERNEL_LAST:
+ case KERNEL_DEFAULT:
+ unto = num_sprites;
+ break;
+ default:
+ unto = last;
+ break;
+ }
+
+ sequence->start_sprite = from;
+ sequence->end_sprite = unto;
+
+ sequence->sprite = (sequence->loop_direction >= 0) ? from : unto;
+}
+
+int kernel_seq_stamp(int series_id, int mirror, int sprite) {
+ int id;
+
+ id = kernel_seq_forward(series_id, mirror, 32767, 0, 0, 0);
+ if (id >= 0) {
+ kernel_seq_range(id, sprite, sprite);
+ sequence_list[id].loop_direction = AA_STAMP;
+ }
+ return (id);
+}
+
+int kernel_seq_stamp_scroll(int series_id, int mirror, int sprite) {
+ int id;
+
+ id = kernel_seq_forward_scroll(series_id, mirror, 32767, 0, 0, 0);
+ if (id >= 0) {
+ kernel_seq_range(id, sprite, sprite);
+ sequence_list[id].loop_direction = AA_STAMP;
+ }
+ return (id);
+}
+
+int kernel_seq_trigger(int sequence_id,
+ int trigger_type,
+ int trigger_sprite,
+ int trigger_code) {
+ int error_code = true;
+ int id;
+ SequencePtr sequence;
+
+ sequence = &sequence_list[sequence_id];
+
+ if (sequence->num_triggers >= KERNEL_MAX_TRIGGERS) goto done;
+
+ id = sequence->num_triggers++;
+
+ sequence->trigger_type[id] = (byte)trigger_type;
+ sequence->trigger_sprite[id] = trigger_sprite;
+ sequence->trigger_code[id] = (byte)trigger_code;
+
+ error_code = false;
+
+done:
+ return error_code;
+}
+
+int kernel_timing_trigger(int ticks, int trigger_code) {
+ int id = -1;
+ int found = false;
+ int count;
+
+ for (count = 0; !found && (count < KERNEL_MAX_SEQUENCES); count++) {
+ id = count;
+ found = !sequence_list[count].active_flag;
+ }
+
+ if (!found) {
+#if !defined(disable_error_check)
+ error_report(ERROR_SEQUENCE_LIST_FULL, WARNING, MODULE_KERNEL, KERNEL_MAX_SEQUENCES, 0);
+#endif
+ goto done;
+ }
+
+ sequence_list[id].active_flag = true;
+ sequence_list[id].series_id = KERNEL_SPECIAL_TIMING;
+
+ sequence_list[id].ticks = ticks;
+ sequence_list[id].interval_ticks = 0;
+ sequence_list[id].base_time = kernel.clock + ticks;
+ sequence_list[id].expire = 1;
+ sequence_list[id].expired = false;
+
+ sequence_list[id].num_triggers = 0;
+ sequence_list[id].trigger_dest = (byte)kernel.trigger_setup_mode;
+
+ for (count = 0; count < 3; count++) {
+ sequence_list[id].trigger_words[count] = player2.words[count];
+ }
+
+ kernel_seq_trigger(id, KERNEL_TRIGGER_EXPIRE, 0, trigger_code);
+
+done:
+ return id;
+}
+
+int kernel_seq_purge(int sequence_id) {
+ int count;
+ int purged_any = -1;
+
+ for (count = 0; count < (int)image_marker; count++) {
+ if (image_list[count].segment_id == (byte)sequence_id) {
+ image_list[count].flags = IMAGE_ERASE;
+ purged_any = count;
+ }
+ }
+
+ return purged_any;
+}
+
+void kernel_seq_full_update() {
+ int count, id;
+
+ for (count = 0; count < KERNEL_MAX_SEQUENCES; count++) {
+ if (sequence_list[count].active_flag) {
+ if ((int)(sequence_list[count].series_id) != KERNEL_SPECIAL_TIMING) {
+ id = matte_allocate_image();
+ if (id >= 0) {
+ if (sequence_list[count].last_image.flags >= 0) {
+ image_list[id] = sequence_list[count].last_image;
+ } else {
+ kernel_seq_image(&sequence_list[count], &image_list[id], count);
+ }
+ }
+ }
+ }
+ }
+}
+
+void kernel_seq_correction(long old_clock, long new_clock) {
+ int count;
+ SequencePtr sequence;
+
+ for (count = 0; count < KERNEL_MAX_SEQUENCES; count++) {
+ sequence = &sequence_list[count];
+ if (sequence->active_flag) {
+ sequence->base_time += (new_clock - old_clock);
+ }
+ }
+}
+
+void kernel_draw_to_background(int series_id, int sprite_id,
+ int x, int y,
+ int depth, int scale) {
+ if (x == KERNEL_HOME) {
+ x = series_list[series_id]->index[sprite_id - 1].x;
+ }
+
+ if (y == KERNEL_HOME) {
+ y = series_list[series_id]->index[sprite_id - 1].y;
+ }
+
+ sprite_draw_3d_scaled_big(series_list[series_id],
+ sprite_id,
+ &scr_orig, &scr_depth,
+ x - picture_map.pan_base_x,
+ y - picture_map.pan_base_y,
+ depth, scale, 0, 0);
+
+ matte_refresh_work();
+}
+
+void kernel_seq_delete(int sequence_id) {
+ if (sequence_list[sequence_id].active_flag) {
+ if (sequence_list[sequence_id].dynamic_hotspot >= 0) {
+ kernel_delete_dynamic(sequence_list[sequence_id].dynamic_hotspot);
+ }
+ }
+
+ sequence_list[sequence_id].active_flag = false;
+
+ if (!sequence_list[sequence_id].expired) {
+ kernel_reconstruct_screen(-1);
+ } else {
+ kernel_seq_purge(sequence_id);
+ }
+}
+
+static void kernel_seq_image(SequencePtr sequence, ImagePtr image, int sequence_id) {
+ image->flags = series_list[sequence->series_id]->delta_series ? IMAGE_DELTA : IMAGE_UPDATE;
+ image->segment_id = (byte)sequence_id;
+ image->series_id = sequence->series_id;
+ image->sprite_id = sequence->sprite | (sequence->mirror ? MIRROR_MASK : 0);
+
+ image->depth = sequence->depth;
+ image->scale = sequence->scale;
+
+ if (!sequence->auto_locating) {
+ image->x = sequence->x;
+ image->y = sequence->y;
+ } else {
+ image->x = series_list[image->series_id]->index[sequence->sprite - 1].x;
+ image->y = series_list[image->series_id]->index[sequence->sprite - 1].y;
+ }
+
+ sequence->last_image = *image;
+}
+
+static int kernel_seq_update(SequencePtr sequence, int sequence_id) {
+ int id;
+ int count;
+ int cycling = false;
+ int trigger = -1;
+ int x, y, xs, ys;
+ int x1, y1;
+ int x2, y2;
+ int purged;
+ ImagePtr image;
+
+ purged = kernel_seq_purge(sequence_id);
+
+ if (purged >= 0) {
+ if (sequence->loop_direction == AA_STAMP) {
+ image_list[purged].flags = IMAGE_STATIC;
+ goto done;
+ }
+ }
+
+ if (sequence->expired) {
+ kernel_seq_delete(sequence_id);
+ goto done;
+ } else {
+ if (sequence->series_id == KERNEL_SPECIAL_TIMING) {
+ sequence->expired = true;
+ goto triggers;
+ }
+
+ id = matte_allocate_image();
+ if (id < 0) {
+ sequence->expired = true;
+ goto triggers;
+ }
+
+ image = &image_list[id];
+
+ kernel_seq_image(sequence, image, sequence_id);
+
+ }
+
+ if (sequence->motion ||
+ (sequence->dynamic_hotspot >= 0)) {
+ xs = (series_list[sequence->series_id]->index[sequence->sprite - 1].xs * sequence->scale) / 200;
+ ys = (series_list[sequence->series_id]->index[sequence->sprite - 1].ys * sequence->scale) / 100;
+ x = image->x;
+ y = image->y;
+
+ if (sequence->motion & KERNEL_MOTION) {
+ sequence->accum_x += sequence->delta_x;
+ while (sequence->accum_x >= 100) {
+ sequence->accum_x -= 100;
+ sequence->x += sequence->sign_x;
+ }
+ sequence->accum_y += sequence->delta_y;
+ while (sequence->accum_y >= 100) {
+ sequence->accum_y -= 100;
+ sequence->y += sequence->sign_y;
+ }
+
+ if (sequence->motion & KERNEL_MOTION_OFFSCREEN) {
+ if ((((x + xs) < 0) || ((x - xs) >= picture_map.total_x_size)) ||
+ ((y < 0) || ((y - ys) >= picture_map.total_y_size))) {
+ cycling = true;
+ sequence->expired = true;
+ }
+ }
+ }
+
+ if (sequence->dynamic_hotspot >= 0) {
+ x1 = x - xs;
+ x2 = x + xs;
+ y1 = y - ys;
+ y2 = y;
+ x1 = MAX(0, x1);
+ y1 = MAX(0, y1);
+ x2 = MIN(picture_map.total_x_size - 1, x2);
+ y2 = MIN(picture_map.total_y_size - 1, y2);
+ kernel_dynamic_hot[sequence->dynamic_hotspot].x = x1;
+ kernel_dynamic_hot[sequence->dynamic_hotspot].y = y1;
+ kernel_dynamic_hot[sequence->dynamic_hotspot].xs = (x2 - x1) + 1;
+ kernel_dynamic_hot[sequence->dynamic_hotspot].ys = (y2 - y1) + 1;
+ kernel_dynamic_hot[sequence->dynamic_hotspot].valid = true;
+ kernel_dynamic_changed = true;
+ }
+ }
+
+ if (sequence->start_sprite != sequence->end_sprite) {
+ sequence->sprite += sequence->loop_direction;
+ }
+
+ if (sequence->sprite < sequence->start_sprite) {
+ cycling = true;
+ if (sequence->loop_mode == AA_PINGPONG) {
+ sequence->sprite = sequence->start_sprite + 1;
+ sequence->loop_direction = 1;
+ } else {
+ sequence->sprite = sequence->end_sprite;
+ }
+ } else if (sequence->sprite > sequence->end_sprite) {
+ cycling = true;
+ if (sequence->loop_mode == AA_PINGPONG) {
+ sequence->sprite = sequence->end_sprite - 1;
+ sequence->loop_direction = -1;
+ } else {
+ sequence->sprite = sequence->start_sprite;
+ }
+ }
+
+ if (cycling) {
+ if (sequence->expire) {
+ sequence->expire--;
+ if (!sequence->expire) {
+ sequence->expired = true;
+ }
+ }
+ }
+
+triggers:
+ for (count = 0; count < (int)sequence->num_triggers; count++) {
+ switch (sequence->trigger_type[count]) {
+ case KERNEL_TRIGGER_EXPIRE:
+ if (sequence->expired) trigger = count;
+ break;
+ case KERNEL_TRIGGER_LOOP:
+ if (cycling) trigger = count;
+ break;
+ case KERNEL_TRIGGER_SPRITE:
+ default:
+ if ((sequence->sprite == sequence->trigger_sprite[count]) ||
+ (sequence->trigger_sprite[count] == 0)) {
+ trigger = count;
+ }
+ break;
+ }
+ }
+
+ if (trigger >= 0) {
+ kernel.trigger = sequence->trigger_code[trigger];
+ kernel.trigger_mode = sequence->trigger_dest;
+ if (kernel.trigger_mode != KERNEL_TRIGGER_DAEMON) {
+ for (count = 0; count < 3; count++) {
+ player2.words[count] = sequence->trigger_words[count];
+ }
+ }
+ }
+
+ if (sequence->series_id == KERNEL_SPECIAL_TIMING) {
+ sequence->active_flag = false;
+ }
+
+done:
+ return cycling;
+}
+
+void kernel_seq_update_all() {
+ int count;
+ int ok_to_update;
+ SequencePtr sequence;
+
+ for (count = 0; (count < KERNEL_MAX_SEQUENCES); count++) {
+ sequence = &sequence_list[count];
+ if (sequence->active_flag) {
+ if (kernel.clock >= sequence->base_time) {
+ ok_to_update = (kernel.fx || !kernel.trigger ||
+ sequence->expired || !sequence->num_triggers);
+ if (ok_to_update) {
+ sequence->base_time = kernel.clock + sequence->ticks;
+ if (kernel_seq_update(sequence, count)) {
+ sequence->base_time += sequence->interval_ticks;
+ }
+ }
+ }
+ }
+ }
+}
+
+void kernel_seq_player(int sequence_id, int synch_me) {
+ kernel_seq_loc(sequence_id, player.x, player.y + ((player.center_of_gravity * player.scale) / 100));
+ kernel_seq_depth(sequence_id, player.depth);
+ kernel_seq_scale(sequence_id, player.scale);
+
+ if (synch_me) {
+ kernel_synch(KERNEL_SERIES, sequence_id,
+ KERNEL_PLAYER, 0);
+ }
+}
+
+void kernel_animation_init() {
+ int count;
+
+ for (count = 0; count < KERNEL_MAX_ANIMATIONS; count++) {
+ kernel_anim[count].anim = NULL;
+ kernel_anim[count].cycled = false;
+ kernel_anim[count].repeat = false;
+ }
+}
+
+int kernel_run_animation(char *name, int trigger_code) {
+ int result = -1;
+ int found = -1;
+ int error_flag = true;
+ int count;
+ int load_flags;
+ int id;
+ long largest_block;
+
+
+ if (stop_speech_on_run_anim) {
+ digi_stop(1);
+ digi_stop(2);
+ digi_stop(3);
+ }
+
+ anim_error = -2;
+
+ for (count = 0; (found < 0) && (count < KERNEL_MAX_ANIMATIONS); count++) {
+ if (kernel_anim[count].anim == NULL) {
+ found = count;
+ }
+ }
+
+ if (found < 0) goto done;
+
+ load_flags = 0;
+ if (kernel.translating) load_flags |= ANIM_LOAD_TRANSLATE;
+ kernel_anim[found].anim = anim_load(name,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL, load_flags);
+ if (kernel_anim[found].anim == NULL) goto done;
+
+ kernel_anim[found].messages = 0;
+ kernel_anim[found].dynamic_hotspot = -1;
+
+ kernel_anim[found].sprite_loaded = -1;
+ if (kernel_anim[found].anim->misc_any_packed) {
+ kernel_anim[found].buffer_id = -1;
+ id = kernel_anim[found].anim->series_id[kernel_anim[found].anim->misc_packed_series];
+ memcpy(&largest_block, &series_list[id]->misc_largest_block, sizeof(long));
+ if (mem_get_avail() - 128 >= largest_block) {
+ mem_free(series_list[id]->arena);
+ series_list[id]->arena = (byte *)mem_get_name(largest_block * 2, "$arena$");
+ if (series_list[id]->arena == NULL) {
+ series_list[id]->arena = (byte *)mem_get_name(largest_block, "$arena$");
+ anim_error = -1;
+ if (series_list[id]->arena == NULL) goto done;
+ } else {
+ kernel_anim[found].buffer[0] = series_list[id]->arena;
+ kernel_anim[found].buffer[1] = (byte *)mem_normalize(series_list[id]->arena + largest_block);
+ kernel_anim[found].buffer_id = 0;
+ }
+ }
+
+ kernel_animation_get_sprite(found, 1);
+ }
+
+ if (kernel_mode == KERNEL_ACTIVE_CODE) kernel_new_palette();
+
+ kernel_anim[found].frame = 0;
+ kernel_anim[found].image = 0;
+ kernel_anim[found].next_clock = kernel.clock;
+
+ kernel_anim[found].view_changes = false;
+
+ kernel_anim[found].trigger_code = trigger_code;
+ kernel_anim[found].trigger_mode = kernel.trigger_setup_mode;
+ for (count = 0; count < 3; count++) {
+ kernel_anim[found].trigger_words[count] = player2.words[count];
+ }
+
+ for (count = 0; count < kernel_anim[found].anim->num_speech; count++) {
+ kernel_anim[found].anim->speech[count].flags = (word)-1;
+ }
+
+ error_flag = false;
+ result = found;
+
+ kernel_anim[found].last_frame = -1;
+
+done:
+ if (error_flag) {
+ if (found >= 0) kernel_abort_animation(found);
+#ifndef disable_error_check
+ Common::strcpy_s(error_string, name);
+ error_report(ERROR_KERNEL_NO_ANIMATION, WARNING, MODULE_KERNEL, trigger_code, anim_error);
+#endif
+ }
+
+ anim_error = 0;
+ return found;
+}
+
+int kernel_run_animation_talk(char thing, int num, int trigger_code) {
+ char test[20];
+ char crap[6];
+ int feedback;
+
+ Common::strcpy_s(test, "*talk_");
+
+ if (thing == 'r') {
+ Common::strcat_s(test, "r");
+ } else if (thing == 'b') {
+ Common::strcat_s(test, "b");
+ } else if (thing == 'e') {
+ Common::strcat_s(test, "e");
+ }
+
+ mads_itoa(num, crap, 10);
+ Common::strcat_s(test, crap);
+
+ feedback = kernel_run_animation(test, trigger_code);
+ return feedback;
+}
+
+int kernel_run_animation_disp(char thing, int num, int trigger_code) {
+ char test[20];
+ char crap[6];
+ int feedback;
+
+ Common::strcpy_s(test, "*disp_");
+
+ if (thing == 'r') {
+ Common::strcat_s(test, "ru");
+ } else if (thing == 'b') {
+ Common::strcat_s(test, "ab");
+ } else if (thing == 'e') {
+ Common::strcat_s(test, "ed");
+ }
+
+ mads_itoa(num, crap, 10);
+ Common::strcat_s(test, crap);
+
+ feedback = kernel_run_animation(test, trigger_code);
+ return (feedback);
+}
+
+int kernel_run_animation_write(int trigger_code) {
+ int feedback;
+
+ feedback = kernel_run_animation("*write_e", trigger_code);
+ return (feedback);
+}
+
+int kernel_run_animation_point(int num, int trigger_code) {
+ char test[20];
+ char crap[6];
+ int feedback;
+
+ Common::strcpy_s(test, "*point_b");
+
+ mads_itoa(num, crap, 10);
+ Common::strcat_s(test, crap);
+
+ feedback = kernel_run_animation(test, trigger_code);
+ return feedback;
+}
+
+static void kernel_animation_get_sprite(int handle, int id) {
+ int series_id;
+ byte *pointer;
+
+ if (id != kernel_anim[handle].sprite_loaded) {
+ series_id = kernel_anim[handle].anim->series_id[kernel_anim[handle].anim->misc_packed_series];
+ if (kernel_anim[handle].buffer_id >= 0) {
+ pointer = kernel_anim[handle].buffer[kernel_anim[handle].buffer_id];
+ kernel_anim[handle].buffer_id = 1 - kernel_anim[handle].buffer_id;
+ } else {
+ pointer = series_list[series_id]->arena;
+ }
+ if (sprite_data_load(series_list[series_id], id, pointer)) {
+ error_report(ERROR_SPRITE_DATA_LOAD_FAILED, ERROR, MODULE_KERNEL, id, series_id);
+ }
+
+ kernel_anim[handle].sprite_loaded = id;
+ }
+}
+
+void kernel_reset_animation(int handle, int frame) {
+ if (kernel_anim[handle].anim != NULL) {
+ kernel_anim[handle].frame = frame;
+ kernel_anim[handle].image = 0;
+ kernel_anim[handle].doomed = false;
+ }
+}
+
+static void kernel_hot_check(int hot, int id, int seg_id) {
+ int count;
+ int x, y, xs, ys;
+ int x1, y1, x2, y2;
+ byte scale;
+
+ for (count = 0; count < KERNEL_DYNAMIC_MAX_SEGMENTS; count++) {
+ if (seg_id == (int)kernel_dynamic_hot[hot].auto_segment[count]) {
+
+ scale = image_list[id].scale;
+ if (scale == IMAGE_UNSCALED) {
+ xs = series_list[image_list[id].series_id]->index[image_list[id].sprite_id - 1].xs;
+ ys = series_list[image_list[id].series_id]->index[image_list[id].sprite_id - 1].ys;
+ x = image_list[id].x;
+ y = image_list[id].y;
+ x1 = x;
+ y1 = y;
+ x2 = x + xs - 1;
+ y2 = y + ys - 1;
+ } else {
+ xs = (series_list[image_list[id].series_id]->index[image_list[id].sprite_id - 1].xs * image_list[id].scale) / 200;
+ ys = (series_list[image_list[id].series_id]->index[image_list[id].sprite_id - 1].ys * image_list[id].scale) / 100;
+ x = image_list[id].x;
+ y = image_list[id].y;
+ x1 = x - xs;
+ x2 = x + xs;
+ y1 = y - ys;
+ y2 = y;
+ }
+
+ if ((xs > 0) && (ys > 0)) {
+ x1 = MAX(0, x1);
+ y1 = MAX(0, y1);
+ x2 = MIN(picture_map.total_x_size - 1, x2);
+ y2 = MIN(picture_map.total_y_size - 1, y2);
+ xs = (x2 - x1) + 1;
+ ys = (y2 - y1) + 1;
+ if ((xs > 0) && (ys > 0)) {
+ kernel_dynamic_hot[hot].x = x1;
+ kernel_dynamic_hot[hot].y = y1;
+ kernel_dynamic_hot[hot].xs = xs;
+ kernel_dynamic_hot[hot].ys = ys;
+ kernel_dynamic_hot[hot].valid = true;
+ }
+ }
+ }
+ }
+}
+
+static void kernel_process_animation(int handle, int asynchronous) {
+ int view_changed = false;
+ int image_base;
+ int count;
+ int match;
+ int id;
+ int clock_frame;
+ int hot, seg_id;
+ word temp1, temp2;
+
+ if (kernel_anim[handle].anim->misc_any_packed) {
+ id = -1;
+ match = kernel_anim[handle].anim->series_id[kernel_anim[handle].anim->misc_packed_series];
+ for (count = kernel_anim[handle].image;
+ (count < kernel_anim[handle].anim->num_images) &&
+ (kernel_anim[handle].anim->image[count].flags <= kernel_anim[handle].frame);
+ count++) {
+ if (kernel_anim[handle].anim->image[count].series_id == (byte)match) {
+ id = kernel_anim[handle].anim->image[count].sprite_id;
+ }
+ }
+ if (id >= 0) {
+ kernel_animation_get_sprite(handle, id);
+ }
+ }
+
+ if (kernel.clock < kernel_anim[handle].next_clock) goto done;
+
+ for (count = 0; count < (int)image_marker; count++) {
+ if (image_list[count].segment_id == (byte)(KERNEL_SEGMENT_ANIMATION + handle)) {
+ image_list[count].flags = IMAGE_ERASE;
+ }
+ }
+
+ kernel_anim[handle].cycled = false;
+ if (kernel_anim[handle].frame >= kernel_anim[handle].anim->num_frames) {
+ if (kernel_anim[handle].repeat) {
+ kernel_anim[handle].frame = 0;
+ kernel_anim[handle].image = 0;
+ kernel_anim[handle].cycled = true;
+ } else {
+ kernel_anim[handle].doomed = true;
+ goto done;
+ }
+ }
+
+ if (!asynchronous) {
+ if (kernel_anim[handle].anim->frame[kernel_anim[handle].frame].sound) {
+ /* pl sound_play(kernel_anim[handle].anim->frame[kernel_anim[handle].frame].sound); */
+ }
+
+ if ((kernel_anim[handle].anim->misc_peel_x != 0) || (kernel_anim[handle].anim->misc_peel_y != 0)) {
+ buffer_peel_horiz(&scr_orig, kernel_anim[handle].anim->misc_peel_x);
+ buffer_peel_vert(&scr_orig, kernel_anim[handle].anim->misc_peel_y, NULL, 0);
+ matte_refresh_work();
+ if (!kernel_allow_peel) error_report(ERROR_PEELING_DISABLED, ERROR, MODULE_KERNEL, handle, 0);
+ }
+
+ if (kernel_anim[handle].view_changes) {
+ if (kernel_anim[handle].anim->frame[kernel_anim[handle].frame].view_x != (word)picture_view_x) {
+ picture_view_x = kernel_anim[handle].anim->frame[kernel_anim[handle].frame].view_x;
+ view_changed = true;
+ }
+
+ if (kernel_anim[handle].anim->frame[kernel_anim[handle].frame].view_y != (word)picture_view_y) {
+ picture_view_y = kernel_anim[handle].anim->frame[kernel_anim[handle].frame].view_y;
+ view_changed = true;
+ }
+ }
+ }
+
+ if (view_changed) {
+ id = matte_allocate_image();
+ image_list[id].segment_id = KERNEL_SEGMENT_SYSTEM;
+ image_list[id].flags = IMAGE_REFRESH;
+ camera_jump_to(picture_view_x, picture_view_y);
+ }
+
+ image_base = image_marker;
+
+ hot = kernel_anim[handle].dynamic_hotspot;
+ if (hot >= 0) {
+ kernel_dynamic_hot[hot].x = 0;
+ kernel_dynamic_hot[hot].y = 0;
+ kernel_dynamic_hot[hot].xs = 0;
+ kernel_dynamic_hot[hot].ys = 0;
+ kernel_dynamic_hot[hot].valid = false;
+ kernel_dynamic_changed = true;
+ }
+
+ while ((kernel_anim[handle].image < kernel_anim[handle].anim->num_images) &&
+ (kernel_anim[handle].anim->image[kernel_anim[handle].image].flags <= kernel_anim[handle].frame)) {
+ if (kernel_anim[handle].anim->image[kernel_anim[handle].image].flags == kernel_anim[handle].frame) {
+ match = false;
+ for (count = 0; !match && (count < image_base); count++) {
+ if (image_list[count].segment_id == (byte)(KERNEL_SEGMENT_ANIMATION + handle)) {
+ if (memcmp(&image_list[count].series_id,
+ &kernel_anim[handle].anim->image[kernel_anim[handle].image].series_id, 9) == 0) {
+ image_list[count].flags = 0;
+
+ if (hot >= 0) {
+ seg_id = kernel_anim[handle].anim->image[kernel_anim[handle].image].segment_id;
+ kernel_hot_check(hot, count, seg_id);
+ }
+
+ match = true;
+ }
+ }
+ }
+
+ if (!match) {
+ id = matte_allocate_image();
+ image_list[id] = kernel_anim[handle].anim->image[kernel_anim[handle].image];
+
+ seg_id = image_list[id].segment_id;
+
+ /* image_list[id].segment_id += KERNEL_SEGMENT_ANIMATION; */
+ image_list[id].segment_id = (byte)(KERNEL_SEGMENT_ANIMATION + handle);
+ image_list[id].flags = series_list[image_list[id].series_id]->delta_series ? IMAGE_DELTA : IMAGE_UPDATE;
+ /*
+ if (kernel_anim[handle].anim->misc_any_packed) {
+ if (image_list[id].series_id == (byte)kernel_anim[handle].anim->series_id[kernel_anim[handle].anim->misc_packed_series]) {
+ series_id = image_list[id].series_id;
+ sprite_data_load (series_list[series_id], image_list[id].sprite_id, series_list[series_id]->arena);
+ }
+ }
+ */
+
+ if (hot >= 0) {
+ kernel_hot_check(hot, id, seg_id);
+ }
+ }
+ }
+ kernel_anim[handle].image++;
+ }
+
+ for (count = 0; count < kernel_anim[handle].anim->num_speech; count++) {
+ if ((int)(kernel_anim[handle].anim->speech[count].flags) >= 0) {
+ if ((kernel_anim[handle].frame < kernel_anim[handle].anim->speech[count].first_frame) ||
+ (kernel_anim[handle].frame > kernel_anim[handle].anim->speech[count].last_frame)) {
+ kernel_message_delete(kernel_anim[handle].anim->speech[count].flags);
+ kernel_anim[handle].anim->speech[count].flags = (word)-1;
+ kernel_anim[handle].messages--;
+ }
+ } else {
+ if ((kernel_anim[handle].frame >= kernel_anim[handle].anim->speech[count].first_frame) &&
+ (kernel_anim[handle].frame <= kernel_anim[handle].anim->speech[count].last_frame)) {
+
+ switch (kernel_anim[handle].messages) {
+ case 1:
+ temp1 = KERNEL_MESSAGE_COLOR_BASE_2;
+ break;
+
+ case 2:
+ temp1 = KERNEL_MESSAGE_COLOR_BASE;
+ break;
+
+ default:
+ temp1 = KERNEL_MESSAGE_COLOR_BASE_3;
+ break;
+ }
+
+ pal_change_color(temp1,
+ kernel_anim[handle].anim->speech[count].color[0].r,
+ kernel_anim[handle].anim->speech[count].color[0].g,
+ kernel_anim[handle].anim->speech[count].color[0].b);
+
+ pal_change_color(temp1 + 1,
+ kernel_anim[handle].anim->speech[count].color[1].r,
+ kernel_anim[handle].anim->speech[count].color[1].g,
+ kernel_anim[handle].anim->speech[count].color[1].b);
+
+ temp2 = ((temp1 + 1) << 8) + temp1;
+
+ kernel_anim[handle].anim->speech[count].flags =
+ kernel_message_add(kernel_anim[handle].anim->speech[count].text,
+ kernel_anim[handle].anim->speech[count].x,
+ kernel_anim[handle].anim->speech[count].y,
+ temp2, 9999999, 0, 0);
+
+ kernel_anim[handle].messages++;
+ }
+ }
+ }
+
+ kernel_anim[handle].last_frame = kernel_anim[handle].frame;
+ kernel_anim[handle].frame++;
+
+ if (!asynchronous) {
+ if (kernel_anim[handle].frame == kernel_anim[handle].anim->num_frames) {
+ if (kernel_anim[handle].trigger_code) {
+ kernel.trigger = kernel_anim[handle].trigger_code;
+ kernel.trigger_mode = kernel_anim[handle].trigger_mode;
+ if (kernel.trigger_mode != KERNEL_TRIGGER_DAEMON) {
+ for (count = 0; count < 3; count++) {
+ player2.words[count] = kernel_anim[handle].trigger_words[count];
+ }
+ }
+ }
+ }
+ }
+
+ clock_frame = MIN(kernel_anim[handle].frame, kernel_anim[handle].anim->num_frames - 1);
+ kernel_anim[handle].next_clock = kernel.clock + kernel_anim[handle].anim->frame[clock_frame].ticks;
+
+done:
+ ;
+}
+
+void kernel_process_all_animations() {
+ int count;
+ int ok_to_update;
+
+ for (count = 0; count < KERNEL_MAX_ANIMATIONS; count++) {
+ if (kernel_anim[count].anim != NULL) {
+ ok_to_update = (kernel.fx || !kernel.trigger ||
+ (kernel_anim[count].frame != kernel_anim[count].anim->num_frames - 1));
+ if (ok_to_update) {
+ kernel_process_animation(count, false);
+ }
+ }
+ }
+}
+
+static void kernel_reconstruct_screen(int anim_handle) {
+ int count;
+ int player_found;
+ int old_frame;
+ long old_clock;
+
+ player_found = false;
+ for (count = 0; count < (int)image_marker; count++) {
+ if (image_list[count].flags >= 0) {
+ if (image_list[count].segment_id == KERNEL_SEGMENT_PLAYER) {
+ player_found = true;
+ }
+ }
+ }
+
+ image_marker = 0;
+ matte_refresh_work();
+ kernel_seq_full_update();
+
+ for (count = 0; count < KERNEL_MAX_ANIMATIONS; count++) {
+ if (!kernel_anim[count].doomed) {
+ if (kernel_anim[count].anim != NULL) {
+ if (count != anim_handle) {
+ if (kernel_anim[count].last_frame >= 0) {
+ old_frame = kernel_anim[count].frame;
+ old_clock = kernel_anim[count].next_clock;
+ kernel_anim[count].frame = kernel_anim[count].last_frame;
+ kernel_anim[count].image = 0;
+ kernel_anim[count].next_clock = kernel.clock;
+
+ kernel_process_animation(count, true);
+
+ kernel_anim[count].next_clock = old_clock;
+ kernel_anim[count].frame = old_frame;
+ kernel_anim[count].image = 0;
+ }
+ }
+ }
+ }
+ }
+
+ if (player.walker_visible && player_found) {
+ player.sprite_changed = true;
+ player_set_image();
+ }
+}
+
+void kernel_abort_animation(int handle) {
+ int count;
+
+ if (kernel_anim[handle].anim != NULL) {
+ if (!kernel_anim[handle].doomed) {
+
+ kernel_reconstruct_screen(handle);
+ }
+
+ for (count = 0; count < kernel_anim[handle].anim->num_speech; count++) {
+ if ((int)(kernel_anim[handle].anim->speech[count].flags) >= 0) {
+ kernel_message_delete(kernel_anim[handle].anim->speech[count].flags);
+ }
+ }
+
+ if (kernel_anim[handle].dynamic_hotspot >= 0) {
+ kernel_delete_dynamic(kernel_anim[handle].dynamic_hotspot);
+ }
+
+ kernel_anim[handle].repeat = false;
+ anim_unload(kernel_anim[handle].anim);
+ kernel_anim[handle].anim = NULL;
+ }
+
+ kernel_anim[handle].doomed = false;
+
+ go_ahead_and_frag_the_palette();
+}
+
+void kernel_abort_all_animations() {
+ int count;
+
+ for (count = KERNEL_MAX_ANIMATIONS - 1; count >= 0; count--) {
+ kernel_abort_animation(count);
+ }
+}
+
+void kernel_doom_all_animations() {
+ int count;
+
+ for (count = 0; count < KERNEL_MAX_ANIMATIONS; count++) {
+ kernel_anim[count].doomed = true;
+ }
+}
+
+void kernel_abort_doomed_animations() {
+ int count;
+
+ for (count = KERNEL_MAX_ANIMATIONS - 1; count >= 0; count--) {
+ if (kernel_anim[count].doomed) {
+ kernel_abort_animation(count);
+ }
+ }
+}
+
+void kernel_message_init() {
+ int count;
+
+ for (count = 0; count < KERNEL_MAX_MESSAGES; count++) {
+ kernel_message[count].flags = 0;
+ }
+
+ kernel_message_font = font_conv;
+ kernel_message_spacing = -1;
+}
+
+int kernel_message_add(char *text, int x, int y, int color,
+ long time_on_screen, int trigger_code,
+ int flags) {
+ int result = -1;
+ int id = -1;
+ int count;
+ KernelMessagePtr my_message = NULL;
+
+ for (count = 0; (id < 0) && (count < KERNEL_MAX_MESSAGES); count++) {
+ my_message = &kernel_message[count];
+ if (!(my_message->flags & KERNEL_MESSAGE_ACTIVE)) id = count;
+ }
+
+ if (id < 0) {
+ if (trigger_code) {
+ error_report(ERROR_KERNEL_MESSAGE_LIST_FULL, ERROR, MODULE_KERNEL, KERNEL_MAX_MESSAGES, trigger_code);
+ }
+ goto done;
+ }
+
+ my_message->message = text;
+
+ my_message->flags = (KERNEL_MESSAGE_ACTIVE | flags);
+ my_message->color = color;
+ my_message->x = x;
+ my_message->y = y;
+ my_message->matte_message_handle = -1;
+ my_message->expire_ticks = time_on_screen;
+ my_message->update_time = kernel.clock;
+ my_message->trigger_code = (byte)trigger_code;
+ my_message->trigger_dest = (byte)kernel.trigger_setup_mode;
+
+ for (count = 0; count < 3; count++) {
+ my_message->trigger_words[count] = player2.words[count];
+ }
+
+ if (flags & KERNEL_MESSAGE_PLAYER) my_message->update_time = player.clock;
+
+ result = id;
+
+done:
+ return result;
+}
+
+void kernel_message_teletype(int id, int rate, int quote) {
+ if (id >= 0) {
+ kernel_message[id].flags |= KERNEL_MESSAGE_TELETYPE;
+ if (quote) kernel_message[id].flags |= KERNEL_MESSAGE_QUOTE;
+ kernel_message[id].strobe_marker = 0;
+ kernel_message[id].strobe_rate = rate;
+ kernel_message[id].strobe_time = kernel.clock;
+ kernel_message[id].strobe_save = *kernel_message[id].message;
+ kernel_message[id].strobe_save_2 = *(kernel_message[id].message + 1);
+ if (kernel_message[id].flags & KERNEL_MESSAGE_PLAYER) {
+ kernel_message[id].strobe_time = player.clock;
+ }
+ kernel_message[id].update_time = kernel_message[id].strobe_time;
+ }
+}
+
+void kernel_message_attach(int id, int sequence) {
+ if (id >= 0) {
+ kernel_message[id].flags |= KERNEL_MESSAGE_ATTACHED;
+ kernel_message[id].sequence_id = (byte)sequence;
+ }
+}
+
+void kernel_message_anim(int id, int anim, int segment) {
+ if (id >= 0) {
+ kernel_message[id].flags |= KERNEL_MESSAGE_ANIM;
+ kernel_message[id].sequence_id = (byte)anim;
+ kernel_message[id].segment_id = (byte)segment;
+ }
+}
+
+void kernel_message_delete(int id) {
+ if (kernel_message[id].flags & KERNEL_MESSAGE_ACTIVE) {
+ if (kernel_message[id].flags & KERNEL_MESSAGE_TELETYPE) {
+ kernel_message[id].message[kernel_message[id].strobe_marker] = kernel_message[id].strobe_save;
+ kernel_message[id].message[kernel_message[id].strobe_marker + 1] = kernel_message[id].strobe_save_2;
+ }
+ if (kernel_message[id].matte_message_handle >= 0) {
+ matte_clear_message(kernel_message[id].matte_message_handle);
+ }
+ kernel_message[id].flags &= ~KERNEL_MESSAGE_ACTIVE;
+ }
+}
+
+void kernel_message_purge() {
+ int count;
+ for (count = 0; count < KERNEL_MAX_MESSAGES; count++) {
+ kernel_message_delete(count);
+ }
+
+ kernel_random_purge();
+}
+
+int kernel_message_player(int quote_id, long delay, int trigger) {
+ int id;
+
+ id = kernel_message_add(quote_string(kernel.quotes, quote_id),
+ 0, 0, MESSAGE_COLOR, delay, trigger,
+ KERNEL_MESSAGE_PLAYER | KERNEL_MESSAGE_CENTER);
+
+ return id;
+}
+
+static void kernel_message_update(KernelMessagePtr my_message) {
+ int count;
+ int x, y;
+ int xx, yy;
+ int x2;
+ int ys;
+ int width;
+ int matte_id;
+ int segment_id;
+ int strobe_flag = false;
+ int frame;
+ int image = -1;
+ Animation *anim = NULL;
+ SequencePtr sequence = NULL;
+ ImagePtr imgList = NULL;
+
+ if (my_message->flags & KERNEL_MESSAGE_EXPIRED) {
+ matte_clear_message(my_message->matte_message_handle);
+ my_message->flags &= ~KERNEL_MESSAGE_ACTIVE;
+ goto done;
+ }
+
+ if (!(my_message->flags & KERNEL_MESSAGE_TELETYPE)) {
+ my_message->expire_ticks -= KERNEL_MESSAGE_INTERVAL;
+ }
+
+ if (my_message->flags & KERNEL_MESSAGE_ATTACHED) {
+ sequence = &sequence_list[my_message->sequence_id];
+ if (sequence->expired || !sequence->active_flag) my_message->expire_ticks = 0;
+ }
+
+ if (my_message->flags & KERNEL_MESSAGE_ANIM) {
+ anim = &kernel_anim[my_message->sequence_id];
+ segment_id = my_message->segment_id;
+ if (anim->doomed || (anim->anim == NULL)) {
+ my_message->expire_ticks = 0;
+ } else {
+ frame = anim->last_frame;
+ imgList = anim->anim->image;
+ for (count = 0; (image < 0) && (count < anim->anim->num_images); count++) {
+ if (imgList[count].flags == frame) {
+ if (imgList[count].segment_id == (byte)segment_id) {
+ image = count;
+ }
+ }
+ }
+ if (image < 0) my_message->expire_ticks = 0;
+ }
+ }
+
+ if (my_message->expire_ticks <= 0) {
+ if (!kernel.trigger) {
+ my_message->flags |= KERNEL_MESSAGE_EXPIRED;
+ if (my_message->trigger_code) {
+ kernel.trigger = my_message->trigger_code;
+ kernel.trigger_mode = my_message->trigger_dest;
+ if (kernel.trigger_mode != KERNEL_TRIGGER_DAEMON) {
+ for (count = 0; count < 3; count++) {
+ player2.words[count] = my_message->trigger_words[count];
+ }
+ }
+ }
+ }
+ }
+
+ my_message->update_time = kernel.clock + KERNEL_MESSAGE_INTERVAL;
+
+ x = my_message->x;
+ y = my_message->y;
+
+ xx = 0;
+ yy = 0;
+
+ if (my_message->flags & KERNEL_MESSAGE_ANIM) {
+ xx = imgList[image].x - picture_view_x;
+ yy = imgList[image].y - picture_view_y;
+ }
+
+ if (my_message->flags & KERNEL_MESSAGE_ATTACHED) {
+ if (!sequence->auto_locating) {
+ xx = sequence->x;
+ yy = sequence->y;
+ } else {
+ xx = series_list[sequence->series_id]->index[sequence->sprite - 1].x;
+ yy = series_list[sequence->series_id]->index[sequence->sprite - 1].y;
+ }
+ }
+
+ if (my_message->flags & KERNEL_MESSAGE_PLAYER) {
+ if (player.walker_been_visible) {
+ ys = (50 + (series_list[player.series_base + player.series]->index[player.sprite - 1].ys * player.scale)) / 100;
+ xx = player.x;
+ yy = player.y + ((50 + (player.center_of_gravity * player.scale)) / 100) - ys;
+ yy -= 15;
+ } else {
+ xx = video_x >> 1;
+ yy = display_y >> 1;
+ }
+ }
+
+ xx += x;
+ yy += y;
+
+ if (my_message->flags & KERNEL_MESSAGE_TELETYPE) {
+ if (kernel.clock >= my_message->strobe_time) {
+ my_message->message[my_message->strobe_marker++] = my_message->strobe_save;
+ my_message->message[my_message->strobe_marker] = my_message->strobe_save_2;
+ my_message->strobe_save = my_message->message[my_message->strobe_marker];
+ my_message->strobe_save_2 = my_message->message[my_message->strobe_marker + 1];
+ if (!my_message->strobe_save) {
+ my_message->message[my_message->strobe_marker] = 0;
+ my_message->flags &= ~KERNEL_MESSAGE_TELETYPE;
+ } else if (my_message->flags & KERNEL_MESSAGE_QUOTE) {
+ my_message->message[my_message->strobe_marker] = '"';
+ my_message->message[my_message->strobe_marker + 1] = 0;
+ }
+ my_message->update_time = my_message->strobe_time = kernel.clock + my_message->strobe_rate;
+ strobe_flag = true;
+ }
+ }
+
+ width = font_string_width(kernel_message_font, my_message->message, kernel_message_spacing);
+
+ if (my_message->flags & (KERNEL_MESSAGE_CENTER | KERNEL_MESSAGE_RIGHT)) {
+ if (my_message->flags & KERNEL_MESSAGE_CENTER) {
+ xx -= (width >> 1);
+ } else {
+ xx -= width;
+ }
+ }
+
+ x2 = xx + width;
+ if (x2 > video_x) xx -= (x2 - video_x);
+
+ xx = MAX(0, MIN(video_x - 1, xx));
+ yy = MAX(0, MIN(display_y - 1, yy));
+
+ if (my_message->matte_message_handle >= 0) {
+ if (strobe_flag ||
+ (xx != message_list[my_message->matte_message_handle].x) ||
+ (yy != message_list[my_message->matte_message_handle].y)) {
+ matte_clear_message(my_message->matte_message_handle);
+ my_message->matte_message_handle = -1;
+ }
+ }
+
+ if (my_message->matte_message_handle < 0) {
+ matte_id = matte_add_message(kernel_message_font, my_message->message, xx, yy, my_message->color, kernel_message_spacing);
+ if (matte_id < 0) goto done;
+ my_message->matte_message_handle = matte_id;
+ }
+
+done:
+ ;
+}
+
+void kernel_message_update_all() {
+ int count;
+
+ for (count = 0; (count < KERNEL_MAX_MESSAGES) && !kernel.trigger; count++) {
+ if (kernel_message[count].flags & KERNEL_MESSAGE_ACTIVE) {
+ if (kernel.clock >= kernel_message[count].update_time) {
+ kernel_message_update(&kernel_message[count]);
+ }
+ }
+ }
+}
+
+void kernel_message_correction(long old_clock, long new_clock) {
+ int count;
+
+ for (count = 0; (count < KERNEL_MAX_MESSAGES); count++) {
+ if (kernel_message[count].flags & KERNEL_MESSAGE_ACTIVE) {
+ kernel_message[count].update_time += (new_clock - old_clock);
+ }
+ }
+}
+
+int kernel_add_dynamic(int vocab_id, int verb_id, byte syntax,
+ int auto_sequence,
+ int x, int y, int xs, int ys) {
+ int id = -1;
+ int count;
+
+ for (count = 0; (id < 0) && (count < KERNEL_MAX_DYNAMIC); count++) {
+ if (!kernel_dynamic_hot[count].flags) {
+ id = count;
+ }
+ }
+
+ if (id < 0) {
+ error_report(ERROR_DYNAMIC_HOTSPOT_OVERFLOW, WARNING, MODULE_KERNEL, id, KERNEL_MAX_DYNAMIC);
+ goto done;
+ }
+
+ kernel_dynamic_hot[id].flags = true;
+ kernel_dynamic_hot[id].vocab_id = vocab_id;
+ kernel_dynamic_hot[id].auto_sequence = auto_sequence;
+ kernel_dynamic_hot[id].x = x;
+ kernel_dynamic_hot[id].y = y;
+ kernel_dynamic_hot[id].xs = xs;
+ kernel_dynamic_hot[id].ys = ys;
+
+ kernel_dynamic_hot[id].feet_x = WALK_DIRECT_2;
+ kernel_dynamic_hot[id].feet_y = 0;
+ kernel_dynamic_hot[id].facing = 5;
+
+ kernel_dynamic_hot[id].verb_id = verb_id;
+ kernel_dynamic_hot[id].prep = PREP_IN;
+ kernel_dynamic_hot[id].syntax = syntax;
+
+ kernel_dynamic_hot[id].cursor = 0;
+
+ kernel_dynamic_hot[id].valid = true;
+
+ kernel_dynamic_hot[id].auto_anim = -1;
+ for (count = 0; count < KERNEL_DYNAMIC_MAX_SEGMENTS; count++) {
+ kernel_dynamic_hot[id].auto_segment[count] = KERNEL_DYNAMIC_NO_ANIM;
+ }
+
+
+ kernel_num_dynamic++;
+ kernel_dynamic_changed = true;
+
+ if (auto_sequence >= 0) {
+ sequence_list[auto_sequence].dynamic_hotspot = id;
+ kernel_dynamic_hot[id].valid = false;
+ }
+
+done:
+ return (id);
+}
+
+void kernel_dynamic_anim(int id, int anim_id, int segment) {
+ int count;
+ int found = false;
+
+ if ((id >= 0) && (id < KERNEL_MAX_DYNAMIC)) {
+ if (kernel_anim[anim_id].anim != NULL) {
+ kernel_anim[anim_id].dynamic_hotspot = id;
+ if (kernel_dynamic_hot[id].auto_anim < 0) {
+ kernel_dynamic_hot[id].valid = false;
+ }
+ kernel_dynamic_hot[id].auto_anim = (char)anim_id;
+ for (count = 0; !found && (count < KERNEL_DYNAMIC_MAX_SEGMENTS); count++) {
+ if (kernel_dynamic_hot[id].auto_segment[count] == KERNEL_DYNAMIC_NO_ANIM) {
+ kernel_dynamic_hot[id].auto_segment[count] = (byte)segment;
+ found = true;
+ }
+ }
+
+ if (!found) {
+ error_report(ERROR_DYNAMIC_HOTSPOT_OVERFLOW, ERROR, MODULE_KERNEL, -9999, id);
+ }
+
+ kernel_dynamic_changed = true;
+ }
+ }
+}
+
+int kernel_dynamic_walk(int id, int feet_x, int feet_y, int facing) {
+ if (id >= 0) {
+ kernel_dynamic_hot[id].feet_x = feet_x;
+ kernel_dynamic_hot[id].feet_y = feet_y;
+ kernel_dynamic_hot[id].facing = (byte)facing;
+ }
+ return (id);
+}
+
+int kernel_dynamic_cursor(int id, int cursorNum) {
+ if (id >= 0) {
+ kernel_dynamic_hot[id].cursor = (byte)cursorNum;
+ }
+
+ return id;
+}
+
+void kernel_delete_dynamic(int id) {
+ if (kernel_dynamic_hot[id].flags) {
+ if (kernel_dynamic_hot[id].auto_sequence >= 0) {
+ sequence_list[kernel_dynamic_hot[id].auto_sequence].dynamic_hotspot = -1;
+ }
+ if (kernel_dynamic_hot[id].auto_anim >= 0) {
+ kernel_anim[kernel_dynamic_hot[id].auto_anim].dynamic_hotspot = -1;
+ }
+ kernel_dynamic_hot[id].flags = false;
+ kernel_num_dynamic--;
+ kernel_dynamic_changed = true;
+ }
+}
+
+void kernel_purge_dynamic() {
+ int count;
+
+ for (count = 0; count < KERNEL_MAX_DYNAMIC; count++) {
+ kernel_delete_dynamic(count);
+ }
+ kernel_num_dynamic = 0;
+ kernel_dynamic_changed = true;
+}
+
+void kernel_init_dynamic() {
+ int count;
+
+ for (count = 0; count < KERNEL_MAX_DYNAMIC; count++) {
+ kernel_dynamic_hot[count].flags = false;
+ }
+ kernel_num_dynamic = 0;
+ kernel_dynamic_changed = 0;
+}
+
+int kernel_dynamic_consecutive(int id) {
+ int scan;
+
+ for (scan = 0; (id >= 0) && (scan < KERNEL_MAX_DYNAMIC); scan++) {
+ if (kernel_dynamic_hot[scan].flags && kernel_dynamic_hot[scan].valid) {
+ id--;
+ if (id < 0) goto done;
+ }
+ }
+
+ if (id >= 0) scan = -1;
+
+done:
+ return (scan);
+}
+
+void kernel_refresh_dynamic() {
+ int count;
+
+ numspots = inter_base_hotspots;
+
+ for (count = 0; count < KERNEL_MAX_DYNAMIC; count++) {
+ if (kernel_dynamic_hot[count].flags && kernel_dynamic_hot[count].valid && ((inter_input_mode == INTER_BUILDING_SENTENCES) || (inter_input_mode == INTER_LIMITED_SENTENCES))) {
+ hspot_add(kernel_dynamic_hot[count].x, kernel_dynamic_hot[count].y,
+ kernel_dynamic_hot[count].x + kernel_dynamic_hot[count].xs - 1,
+ kernel_dynamic_hot[count].y + kernel_dynamic_hot[count].ys - 1,
+ STROKE_DYNAMIC | STROKE_INTERFACE, kernel_dynamic_hot[count].vocab_id,
+ RELATIVE_MODE);
+ inter_force_rescan = true;
+ }
+ }
+
+ kernel_dynamic_changed = false;
+}
+
+char *kernel_full_name(int my_room, char type, int num, char *text, int ext) {
+ char temp[2];
+
+ if (my_room > 0) {
+ if (my_room >= 100) {
+ Common::strcpy_s(kernel_work_name, "*RM");
+ } else {
+ Common::strcpy_s(kernel_work_name, "*SC");
+ }
+ env_catint(kernel_work_name, my_room, 3);
+ } else {
+ Common::strcpy_s(kernel_work_name, "*");
+ }
+
+ temp[0] = type;
+ temp[1] = 0;
+ Common::strcat_s(kernel_work_name, temp);
+
+ if ((num >= 0) && (ext < KERNEL_TT)) {
+ if (num > 9) {
+ env_catint(kernel_work_name, num, 2);
+ } else {
+ env_catint(kernel_work_name, num, 1);
+ }
+ }
+
+ if (text != NULL)
+ Common::strcat_s(kernel_work_name, text);
+
+ switch (ext) {
+ case KERNEL_SS:
+ Common::strcat_s(kernel_work_name, ".SS");
+ break;
+ case KERNEL_AA:
+ Common::strcat_s(kernel_work_name, ".AA");
+ break;
+ case KERNEL_DAT:
+ Common::strcat_s(kernel_work_name, ".DAT");
+ break;
+ case KERNEL_HH:
+ Common::strcat_s(kernel_work_name, ".HH");
+ break;
+ case KERNEL_ART:
+ Common::strcat_s(kernel_work_name, ".ART");
+ break;
+ case KERNEL_INT:
+ Common::strcat_s(kernel_work_name, ".INT");
+ break;
+ case KERNEL_TT:
+ Common::strcat_s(kernel_work_name, ".TT");
+ break;
+ case KERNEL_MM:
+ Common::strcat_s(kernel_work_name, ".MM");
+ break;
+ case KERNEL_WW:
+ Common::strcat_s(kernel_work_name, ".WW");
+ break;
+ }
+
+ if ((num >= 0) && (ext >= KERNEL_TT)) {
+ temp[0] = (byte)num;
+ temp[1] = 0;
+ Common::strcat_s(kernel_work_name, temp);
+ }
+
+ return kernel_work_name;
+}
+
+char *kernel_name(char type, int num) {
+ return kernel_full_name(room_id, type, num, NULL, KERNEL_NONE);
+}
+
+char *kernel_interface_name(int num) {
+ return kernel_full_name(0, 'I', num, NULL, KERNEL_AA);
+}
+
+void kernel_unload_sound_driver() {
+}
+
+int kernel_load_sound_driver(const char *name, char sound_card_, int sound_board_address_, int sound_board_type_, int sound_board_irq_) {
+ return 0;
+}
+
+void kernel_load_variant(int variant) {
+ room_variant = variant;
+
+ if (room_load_variant(room_id, room_variant, NULL, room,
+ &scr_depth,
+ &scr_walk,
+ &scr_special,
+ &depth_map,
+ &depth_resource,
+ tile_attribute_handle)) {
+ error_report(ERROR_VARIANT_LOAD_FAILURE, WARNING, MODULE_KERNEL, room_load_error, (room_id * 10) + room_variant);
+ }
+
+ rail_connect_all_nodes();
+
+ camera_jump_to(picture_view_x, picture_view_y);
+}
+
+void kernel_new_palette() {
+ int palette_base, palette_size;
+
+ palette_base = KERNEL_RESERVED_LOW_COLORS;
+ if (cycling_active) {
+ if (cycle_list.num_cycles) {
+ palette_base = cycle_list.table[0].first_palette_color + total_cycle_colors;
+ }
+ }
+ palette_size = 256 - palette_base;
+
+ mcga_setpal_range(&master_palette, palette_base, palette_size);
+}
+
+void kernel_dump_quotes() {
+ if (kernel.quotes != NULL) {
+ mem_free(kernel.quotes);
+ kernel.quotes = NULL;
+ }
+}
+
+void kernel_dump_all() {
+ kernel_dump_quotes();
+ kernel_unload_all_series();
+ kernel_seq_init();
+ image_marker = 0;
+ matte_refresh_work();
+}
+
+void kernel_dump_walker_only() {
+ int count;
+ int marker;
+
+ marker = player.series_base;
+
+ for (count = 0; count < 8; count++) {
+ if (player.available[count]) {
+ sprite_free(&series_list[marker++], true);
+ player.available[count] = false;
+ }
+ }
+
+ image_marker = 0;
+ matte_refresh_work();
+
+ player.walker_visible = false;
+}
+
+int kernel_save_game(char *filename) {
+ int error_flag = true;
+ Load load_handle;
+
+ load_handle.open = false;
+
+ if (loader_open(&load_handle, filename, "wb", PACK_NONE)) goto done;
+
+ if (!loader_write(&game, sizeof(KernelGame), 1, &load_handle)) goto done;
+ if (!loader_write(&room_id, sizeof(int), 1, &load_handle)) goto done;
+ if (!loader_write(&player2, sizeof(Player2), 1, &load_handle)) goto done;
+ if (!loader_write(&inven_num_objects, sizeof(int), 1, &load_handle)) goto done;
+ if (inven_num_objects) {
+ if (!loader_write(inven, sizeof(int) * inven_num_objects, 1, &load_handle)) goto done;
+ }
+ if (!loader_write(&player, sizeof(Player), 1, &load_handle)) goto done;
+ if (!loader_write(global, sizeof(int) * global_list_size, 1, &load_handle)) goto done;
+ if (!loader_write(object, sizeof(Object) * num_objects, 1, &load_handle)) goto done;
+ if (!loader_write(0, sizeof(int), 1, &load_handle)) goto done;
+ /* pl (see above line) if (!loader_write(&conv_control.running, sizeof(int), 1, &load_handle)) goto done; */
+
+ if (!loader_write(&picture_view_x, sizeof(int), 1, &load_handle)) goto done;
+ if (!loader_write(&picture_view_y, sizeof(int), 1, &load_handle)) goto done;
+ if (!loader_write(room_state, sizeof(int) * OMR, 1, &load_handle)) goto done;
+ if (!loader_write(&previous_room, sizeof(int), 1, &load_handle)) goto done;
+
+ /* pl if (conv_append(load_handle.handle)) goto done; */
+
+ error_flag = false;
+
+done:
+ if (load_handle.open) loader_close(&load_handle);
+ return error_flag;
+}
+
+int kernel_load_game(char *filename) {
+ int error_flag = true;
+ Load load_handle;
+ int save;
+
+ save = player.walker_is_loaded;
+
+ /*
+ keep_video_mode = kernel.video_mode;
+ keep_sound_card = kernel.sound_card;
+ keep_quotes = kernel.quotes;
+ */
+
+ load_handle.open = false;
+
+ if (loader_open(&load_handle, filename, "rb", false)) goto done;
+
+ if (!loader_read(&game, sizeof(KernelGame), 1, &load_handle)) goto done;
+ if (!loader_read(&new_room, sizeof(int), 1, &load_handle)) goto done;
+ if (!loader_read(&player2, sizeof(Player2), 1, &load_handle)) goto done;
+ if (!loader_read(&inven_num_objects, sizeof(int), 1, &load_handle)) goto done;
+ if (inven_num_objects) {
+ if (!loader_read(inven, sizeof(int) * inven_num_objects, 1, &load_handle)) goto done;
+ }
+ if (!loader_read(&player, sizeof(Player), 1, &load_handle)) goto done;
+ if (!loader_read(global, sizeof(int) * global_list_size, 1, &load_handle)) goto done;
+ if (!loader_read(object, sizeof(Object) * num_objects, 1, &load_handle)) goto done;
+ if (!loader_read(0, sizeof(int), 1, &load_handle)) goto done;
+ /* pl (see above line) if (!loader_read(&conv_restore_running, sizeof(int), 1, &load_handle)) goto done; */
+
+ /* Temporary support for old save file format */
+ if (load_handle.pack_list_marker >= (int)load_handle.pack.num_records) goto expand;
+
+ if (!loader_read(&camera_old_x_target, sizeof(int), 1, &load_handle)) goto done;
+ if (!loader_read(&camera_old_y_target, sizeof(int), 1, &load_handle)) goto done;
+ if (!loader_read(room_state, sizeof(int) * OMR, 1, &load_handle)) goto done;
+ if (!loader_read(&previous_room, sizeof(int), 1, &load_handle)) goto done;
+
+expand:
+ /* pl if (conv_expand(load_handle.handle)) goto done; */
+
+ if (inven_num_objects > 0) {
+ active_inven = 0;
+ } else {
+ active_inven = -1;
+ }
+
+ first_inven = 0;
+
+ section_id = KERNEL_RESTORING_GAME;
+ room_id = KERNEL_RESTORING_GAME;
+
+ new_section = new_room / 100;
+
+ kernel.clock = timer_read();
+ game.going = true;
+
+ error_flag = false;
+
+done:
+ if (load_handle.open) loader_close(&load_handle);
+
+ /*
+ kernel.video_mode = keep_video_mode;
+ kernel.sound_card = keep_sound_card;
+ kernel.quotes = keep_quotes;
+ */
+
+
+ player.walker_is_loaded = save;
+ /* player.walker_is_loaded = false; */
+ /* player.walker_must_reload = true; */
+
+ return error_flag;
+}
+
+void kernel_random_purge() {
+ int count;
+
+ for (count = 0; count < KERNEL_MAX_RANDOM_MESSAGES; count++) {
+ random_message_handle[count] = -1;
+ random_message_quote[count] = -1;
+ }
+}
+
+void kernel_random_messages_init(int max_messages_at_once,
+ int min_x, int max_x, int min_y, int max_y, int min_y_spacing,
+ int teletype_rate, int color, int duration, int quote_id, ...) {
+ va_list marker;
+ int my_quote = quote_id;
+
+ random_max_messages = max_messages_at_once;
+ random_min_x = min_x;
+ random_max_x = max_x;
+ random_min_y = min_y;
+ random_max_y = max_y;
+ random_spacing = min_y_spacing;
+ random_teletype_rate = teletype_rate;
+ random_message_color = color;
+ random_message_duration = duration;
+
+ random_quote_list_size = 0;
+
+ va_start(marker, quote_id);
+ while (my_quote > 0) {
+ if (random_quote_list_size < KERNEL_MAX_RANDOM_QUOTES) {
+ random_quote_list[random_quote_list_size++] = my_quote;
+ }
+
+ my_quote = va_arg(marker, int);
+ }
+
+ kernel_random_purge();
+}
+
+int kernel_check_random() {
+ int count;
+ int sum = 0;
+
+ for (count = 0; count < random_max_messages; count++) {
+ if (random_message_handle[count] >= 0) sum++;
+ }
+
+ return sum;
+}
+
+void kernel_random_message_server() {
+ if ((kernel.trigger >= KERNEL_RANDOM_MESSAGE_TRIGGER) &&
+ (kernel.trigger < KERNEL_RANDOM_MESSAGE_TRIGGER + random_max_messages)) {
+ random_message_handle[kernel.trigger - KERNEL_RANDOM_MESSAGE_TRIGGER] = -1;
+ random_message_quote[kernel.trigger - KERNEL_RANDOM_MESSAGE_TRIGGER] = -1;
+ }
+}
+
+int kernel_generate_random_message(int chance_major, int chance_minor) {
+ int count, count2, scan;
+ int bad;
+ int generated_one;
+ int idx, quote;
+ int last_y;
+ int message_x, message_y;
+ int crash_timeout = 0;
+
+ generated_one = false;
+
+ for (count = 0; count < random_max_messages; count++) {
+ if (random_message_handle[count] < 0) {
+
+ /* Don't allow two phrases to teletype at once */
+
+ bad = false;
+ for (scan = 0; scan < random_max_messages; scan++) {
+ if (random_message_handle[scan] >= 0) {
+ if (kernel_message[random_message_handle[scan]].flags & KERNEL_MESSAGE_TELETYPE) {
+ bad = true;
+ }
+ }
+ }
+
+ /* Check random chance for message to appear */
+
+ if ((imath_random(1, chance_major) <= chance_minor) && !bad) {
+
+ /* Pick randomly from our list of allowable quotes */
+
+ do {
+ idx = imath_random(0, random_quote_list_size - 1);
+ quote = random_quote_list[idx];
+ bad = false;
+ for (scan = 0; scan < random_max_messages; scan++) {
+ if (quote == random_message_quote[scan]) {
+ bad = true;
+ }
+ }
+ } while (bad);
+
+ random_message_quote[count] = quote;
+
+ /* Put message in a random location */
+
+ message_x = imath_random(random_min_x, random_max_x);
+
+ /* Be sure Y values are properly spaced */
+
+ crash_timeout = 0;
+
+ do {
+ if (crash_timeout++ > 100) goto done;
+ bad = false;
+ message_y = imath_random(random_min_y, random_max_y);
+ for (count2 = 0; count2 < random_max_messages; count2++) {
+ if (random_message_handle[count2] >= 0) {
+ last_y = kernel_message[random_message_handle[count2]].y;
+ if ((message_y >= (last_y - random_spacing)) &&
+ (message_y <= (last_y + random_spacing))) {
+ bad = true;
+ }
+ }
+ }
+ } while (bad);
+
+ /* Put our new message in the list */
+
+ random_message_handle[count] =
+ kernel_message_add(quote_string(kernel.quotes, random_message_quote[count]),
+ message_x, message_y, random_message_color, random_message_duration,
+ KERNEL_RANDOM_MESSAGE_TRIGGER + count, 0);
+ if (random_teletype_rate > 0) {
+ if (random_message_handle[count] >= 0) {
+ kernel_message_teletype(random_message_handle[count], random_teletype_rate, true);
+ }
+ }
+
+ generated_one = true;
+ }
+ }
+ }
+
+done:
+ return generated_one;
+}
+
+void kernel_load_interface() {
+ char temp_buf[80];
+ char *mark;
+
+ Common::strcpy_s(temp_buf, kernel.interface);
+ mark = strchr(temp_buf, '.');
+ if (mark != NULL) {
+ *mark = 0;
+ }
+ if (inter_input_mode != INTER_BUILDING_SENTENCES) {
+ Common::strcat_s(temp_buf, "A");
+ }
+ Common::strcat_s(temp_buf, ".INT");
+
+ if (strcmp(kernel_interface_loaded, temp_buf)) {
+ buffer_free(&scr_inter_orig);
+ pal_activate_shadow(&kernel_shadow_inter);
+ if (inter_load_background(temp_buf, &scr_inter_orig)) {
+ error_report(ERROR_KERNEL_NO_INTERFACE, SEVERE, MODULE_KERNEL, inter_input_mode, 0);
+ }
+ Common::strcpy_s(kernel_interface_loaded, temp_buf);
+ pal_activate_shadow(&kernel_shadow_main);
+ }
+}
+
+void kernel_set_interface_mode(int mode) {
+ inter_input_mode = mode;
+ kernel_load_interface();
+
+ image_inter_marker = 1;
+ image_inter_list[0].flags = IMAGE_REFRESH;
+ image_inter_list[0].segment_id = (byte)-1;
+
+ /* Set up interface animation clock */
+
+ inter_base_time = timer_read();
+
+ left_command = -1;
+ left_action = -1;
+ left_inven = -1;
+
+ /* Initialize interface work area */
+
+ if (!viewing_at_y) {
+ buffer_rect_copy(scr_inter_orig, scr_inter, 0, 0, video_x, inter_size_y);
+
+ /* Initialize interface grammar driver */
+
+ if (kernel_mode == KERNEL_ACTIVE_CODE) matte_inter_frame(false, false);
+ }
+
+ inter_init_sentence();
+ inter_setup_hotspots();
+
+ if (!viewing_at_y) inter_prepare_background();
+
+ kernel_refresh_dynamic();
+}
+
+void kernel_room_scale(int front_y, int front_scale,
+ int back_y, int back_scale) {
+ room->front_y = front_y;
+ room->front_scale = front_scale;
+ room->back_y = back_y;
+ room->back_scale = back_scale;
+
+ kernel_room_bound_dif = room->front_y - room->back_y;
+ kernel_room_scale_dif = room->front_scale - room->back_scale;
+}
+
+void kernel_background_shutdown() {
+ /* Remove our palette shadowing list */
+
+ pal_activate_shadow(NULL);
+
+ /* Dump the picture & attribute buffers, along with the room header */
+
+ if (room != NULL) {
+ room_unload(room,
+ &scr_orig,
+ &scr_depth,
+ &scr_walk,
+ &scr_special,
+ &picture_map,
+ &depth_map);
+ room = NULL;
+ }
+}
+
+int kernel_background_startup(int newRoom, int initial_variant) {
+ int error_flag = true;
+ int load_flags;
+ int error_code = 0;
+ int error_data = 0;
+
+ /* Make a note of the new room number & variant */
+
+ previous_room = room_id;
+ room_id = newRoom;
+ room_variant = initial_variant;
+
+ /* Start a brand new palette, reserving the proper # of colors */
+
+ pal_init(KERNEL_RESERVED_LOW_COLORS, KERNEL_RESERVED_HIGH_COLORS);
+ pal_white(master_palette);
+
+ /* Initialize the matteing system */
+
+ matte_init(false);
+
+ /* Initialize graphics sequence data structures */
+
+ kernel_seq_init();
+ kernel_message_init();
+
+ /* Activate the main shadow list */
+
+ pal_activate_shadow(&kernel_shadow_main);
+
+ /* Load header, picture, and attribute screen for this room */
+
+ load_flags = ROOM_LOAD_HARD_SHADOW;
+ if (kernel.translating) load_flags |= ROOM_LOAD_TRANSLATE;
+
+ room = room_load(room_id, room_variant, NULL,
+ &scr_orig,
+ &scr_depth,
+ &scr_walk,
+ &scr_special,
+ &picture_map,
+ &depth_map,
+ &picture_resource,
+ &depth_resource,
+ tile_picture_handle,
+ tile_attribute_handle,
+ load_flags);
+ if (room == NULL) {
+ error_data = room_load_error;
+ error_code = ERROR_KERNEL_NO_ROOM;
+ goto done;
+ }
+
+ tile_pan(&picture_map, picture_view_x, picture_view_y);
+ tile_pan(&depth_map, picture_view_x, picture_view_y);
+
+ /* Set up color cycling table for this room */
+
+ cycle_init(&room->cycle_list, false);
+
+ /* Initialize the graphics image lists */
+
+ image_marker = 1;
+ image_list[0].flags = IMAGE_REFRESH;
+ image_list[0].segment_id = KERNEL_SEGMENT_SYSTEM;
+
+ /* Mark the boundary between interface and room sprite series */
+
+ kernel_room_series_marker = series_list_marker;
+
+ error_flag = false;
+
+done:
+ if (error_flag) {
+ error_check_memory();
+ error_report(error_code, ERROR, MODULE_KERNEL, room_id, error_data);
+ kernel_background_shutdown();
+ }
+
+ return error_flag;
+}
+
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/core/kernel.h b/engines/mads/madsv2/core/kernel.h
index 490a561b943..2c83c6cae5a 100644
--- a/engines/mads/madsv2/core/kernel.h
+++ b/engines/mads/madsv2/core/kernel.h
@@ -405,240 +405,210 @@ extern int cursor_last;
extern Kernel kernel;
extern KernelGame game; /* Kernel level game data */
+extern KernelMessage kernel_message[KERNEL_MAX_MESSAGES];
+extern FontPtr kernel_message_font;
+extern int kernel_message_spacing;
+extern int kernel_load_vocab();
+/**
+ * Game level system shutdown.
+ */
+extern void kernel_game_shutdown();
+extern void kernel_force_refresh();
-/* kernel_2.cpp */
-int kernel_load_vocab();
+/**
+ * Game level system startup.
+ */
+extern int kernel_game_startup(int game_video_mode, int load_flag,
+ const char *release_version, const char *release_date);
-/* kernel_3.cpp */
-void kernel_game_shutdown();
-void kernel_force_refresh();
-int kernel_game_startup(int game_video_mode, int load_flag,
- char *release_version, char *release_date);
+/**
+ * Section level system shutdown.
+ */
+extern void kernel_section_shutdown();
-/* kernel_4.cpp */
-void kernel_section_shutdown();
-int kernel_section_startup(int new_section);
+/**
+ * Section level system startup.
+ */
+extern int kernel_section_startup(int new_section);
-/* kernel_5.cpp */
-void kernel_room_shutdown();
-int kernel_room_startup(int new_room, int initial_variant,
- char *interface, int new_palette);
+/**
+ * Room level system shutdown.
+ */
+extern void kernel_room_shutdown();
-/* kernel_6.cpp */
-void kernel_unload_all_series();
-int kernel_load_series(const char *name, int load_flags);
+extern int kernel_room_startup(int new_room, int initial_variant,
+ char *interface, int new_palette);
-/* kernel_7.cpp */
-void kernel_flip_hotspot(int vocab_code, int active);
-void kernel_flip_hotspot_loc(int vocab_code, int active,
- int x, int y);
+/**
+ * Unloads all room series.
+ */
+extern void kernel_unload_all_series();
-/* kernel_8.cpp */
-extern Sequence sequence_list[KERNEL_MAX_SEQUENCES];
+/**
+ * Loads a sprite series for the room.
+ */
+extern int kernel_load_series(const char *name, int load_flags);
-/* kernel_8.cpp */
-void kernel_seq_init();
-void kernel_seq_correction(long old_clock, long new_clock);
-
-/* kernel_8.cpp */
-int kernel_seq_add(int series_id, int mirror,
- int initial_sprite,
- int low_sprite, int high_sprite,
- int loop_mode, int loop_direction,
- int depth, int scale,
- int auto_locating,
- int x, int y,
- word ticks, word interval_ticks,
- word start_ticks,
- int expire);
-
-/* kernel_8.cpp */
-int kernel_seq_forward(int series_id, int mirror,
- word ticks, word interval_ticks,
- word start_ticks, int expire);
-
-int kernel_seq_forward_scroll(int series_id, int mirror,
- word ticks, word interval_ticks,
- word start_ticks, int expire);
-
-/* kernel_8.cpp */
-int kernel_seq_pingpong(int series_id, int mirror,
- word ticks, word interval_ticks,
- word start_ticks, int expire);
-
-int kernel_seq_pingpong_scroll(int series_id, int mirror,
- word ticks, word interval_ticks,
- word start_ticks, int expire);
-
-/* kernel_8.cpp */
-int kernel_seq_backward(int series_id, int mirror,
- word ticks, word interval_ticks,
- word start_ticks, int expire);
-
-int kernel_seq_backward_scroll(int series_id, int mirror,
- word ticks, word interval_ticks,
- word start_ticks, int expire);
-
-/* kernel_8.cpp */
-int kernel_seq_stamp(int series_id, int mirror, int sprite);
-int kernel_seq_stamp_scroll(int series_id, int mirror, int sprite);
-
-/* kernel_8.cpp */
-void kernel_synch(int slave_type, int slave_id,
- int master_type, int master_id);
-void kernel_player_expire(int sequence_id);
+extern void kernel_flip_hotspot(int vocab_code, int active);
-/* kernel_8.cpp */
-void kernel_seq_depth(int sequence_id, int depth);
-void kernel_seq_scale(int sequence_id, int scale);
-void kernel_seq_loc(int sequence_id, int x, int y);
-void kernel_seq_range(int sequence_id,
- int first, int last);
+/**
+ * Toggles an interface hotspot (referenced by its vocabulary word)
+ * on or off. Hotspots that are off do not interact with the mouse cursor.
+ *
+ * Only hotspots which contain the point (X, Y) are affected.
+ */
+extern void kernel_flip_hotspot_loc(int vocab_code, int active, int x, int y);
-/* kernel_8.cpp */
+extern Sequence sequence_list[KERNEL_MAX_SEQUENCES];
+extern void kernel_seq_init();
+extern void kernel_seq_correction(long old_clock, long new_clock);
+extern int kernel_seq_add(int series_id, int mirror, int initial_sprite,
+ int low_sprite, int high_sprite, int loop_mode, int loop_direction,
+ int depth, int scale, int auto_locating, int x, int y,
+ word ticks, word interval_ticks, word start_ticks, int expire);
+extern int kernel_seq_forward(int series_id, int mirror,
+ word ticks, word interval_ticks, word start_ticks, int expire);
+extern int kernel_seq_forward_scroll(int series_id, int mirror,
+ word ticks, word interval_ticks, word start_ticks, int expire);
+extern int kernel_seq_pingpong(int series_id, int mirror,
+ word ticks, word interval_ticks, word start_ticks, int expire);
+extern int kernel_seq_pingpong_scroll(int series_id, int mirror,
+ word ticks, word interval_ticks, word start_ticks, int expire);
+extern int kernel_seq_backward(int series_id, int mirror,
+ word ticks, word interval_ticks, word start_ticks, int expire);
+extern int kernel_seq_backward_scroll(int series_id, int mirror,
+ word ticks, word interval_ticks, word start_ticks, int expire);
+extern int kernel_seq_stamp(int series_id, int mirror, int sprite);
+extern int kernel_seq_stamp_scroll(int series_id, int mirror, int sprite);
+extern void kernel_synch(int slave_type, int slave_id,
+ int master_type, int master_id);
+extern void kernel_player_expire(int sequence_id);
+extern void kernel_seq_depth(int sequence_id, int depth);
+extern void kernel_seq_scale(int sequence_id, int scale);
+extern void kernel_seq_loc(int sequence_id, int x, int y);
+extern void kernel_seq_range(int sequence_id, int first, int last);
void kernel_seq_motion(int sequence_id, int flags,
- int delta_x_times_100,
- int delta_y_times_100);
-
-
-/* kernel_8.cpp */
-extern int kernel_seq_trigger(int sequence_id,
- int trigger_type,
- int trigger_sprite,
- int trigger_code);
-
-/* kernel_8.cpp */
+ int delta_x_times_100, int delta_y_times_100);
+extern int kernel_seq_trigger(int sequence_id, int trigger_type,
+ int trigger_sprite, int trigger_code);
extern int kernel_timing_trigger(int ticks, int trigger_code);
-
-/* kernel_8.cpp */
extern int kernel_seq_purge(int sequence_id);
extern void kernel_seq_full_update();
-
-/* kernel_8.cpp */
extern void kernel_draw_to_background(int series_id, int sprite_id,
int x, int y, int depth, int scale);
-
-
-/* kernel_9.cpp */
extern void kernel_seq_delete(int sequence_id);
-extern int kernel_seq_update(SequencePtr sequence, int sequence_id);
extern void kernel_seq_update_all();
-
-/* kernel_a.cpp */
extern void kernel_seq_player(int sequence_id, int synch_me);
-
-/* kernel_b.cpp */
extern void kernel_animation_init();
extern int kernel_run_animation(const char *name, int trigger_code);
+
+/**
+ * Run a displacement animation
+ */
extern int kernel_run_animation_disp(char thing, int num, int trigger_code);
+
+/**
+ * Run a talking animation
+ */
extern int kernel_run_animation_talk(char thing, int num, int trigger_code);
+
+/**
+ * Run a writing anim (always edgar)
+ */
extern int kernel_run_animation_write(int trigger_code);
-extern int kernel_run_animation_point(int num, int trigger_code);
-/* kernel_c.cpp */
+/**
+ * Run a pointing animation (always abigail)
+ */
+extern int kernel_run_animation_point(int num, int trigger_code);
extern void kernel_reset_animation(int handle, int frame);
extern void kernel_abort_animation(int handle);
extern void kernel_abort_all_animations();
extern void kernel_doom_all_animations();
extern void kernel_abort_doomed_animations();
extern void kernel_process_all_animations();
-
-
-/* kernel_d.cpp */
-extern KernelMessage kernel_message[KERNEL_MAX_MESSAGES];
-extern FontPtr kernel_message_font;
-extern int kernel_message_spacing;
-
-/* kernel_d.cpp */
extern void kernel_message_init();
extern int kernel_message_add(char *text, int x, int y, int color,
long time_on_screen, int trigger_code, int flags);
-
-/* kernel_d.cpp */
extern void kernel_message_teletype(int id, int rate, int quote);
extern void kernel_message_attach(int id, int sequence);
extern void kernel_message_delete(int id);
extern void kernel_message_purge();
-
-/* kernel_d.cpp */
extern void kernel_message_anim(int id, int anim, int segment);
extern int kernel_message_player(int quote_id, long delay, int trigger);
-
-
-/* kernel_e.cpp */
-extern void kernel_message_update(KernelMessagePtr my_message);
extern void kernel_message_update_all();
extern void kernel_message_correction(long old_clock, long new_clock);
-
-
-/* kernel_f.cpp */
extern int kernel_add_dynamic(int vocab_id, int verb_id, byte syntax,
int auto_sequence, int x, int y, int xs, int ys);
-
-/* kernel_f.cpp */
-extern int kernel_dynamic_walk(int id, int feet_x, int feet_y,
- int facing);
+extern int kernel_dynamic_walk(int id, int feet_x, int feet_y, int facing);
extern void kernel_dynamic_anim(int id, int anim_id, int segment);
-
-/* kernel_f.cpp */
-int kernel_dynamic_cursor(int id, int cursor);
-void kernel_delete_dynamic(int id);
-void kernel_purge_dynamic();
-void kernel_init_dynamic();
-
-/* kernel_g.cpp */
+extern int kernel_dynamic_cursor(int id, int cursor);
+extern void kernel_delete_dynamic(int id);
+extern void kernel_purge_dynamic();
+extern void kernel_init_dynamic();
extern int kernel_dynamic_consecutive(int id);
extern void kernel_refresh_dynamic();
-
-/* kernel_h.cpp */
extern char *kernel_full_name(int my_room, char type, int num, char *text, int ext);
extern char *kernel_name(char type, int num);
extern char *kernel_interface_name(int num);
-
-/* kernel_i.cpp */
extern void kernel_unload_sound_driver();
-extern int kernel_load_sound_driver(const char *name, char sound_card,
- int sound_board_address, int sound_board_type, int sound_board_irq);
-
-/* kernel_j.cpp */
+extern int kernel_load_sound_driver(const char *name, char sound_card_,
+ int sound_board_address_, int sound_board_type_, int sound_board_irq_);
extern void kernel_load_variant(int variant);
-
-/* kernel_k.cpp */
extern void kernel_new_palette();
-
-/* kernel_l.cpp */
extern void kernel_dump_quotes();
extern void kernel_dump_all();
extern void kernel_dump_walker_only();
-
-/* kernel_m.cpp */
extern int kernel_save_game(char *filename);
extern int kernel_load_game(char *filename);
-/* kernel_n.cpp */
+/**
+ * Initializes a random chatter sequence. (Parameters end with
+ * a zero-terminated list of already loaded quote id's to be
+ * used for messages).
+ */
extern void kernel_random_messages_init(int max_messages_at_once,
int min_x, int max_x, int min_y, int max_y,
int min_y_spacing, int teletype_rate, int color,
int duration, int quote_id, ...);
-/* kernel_n.cpp */
+/**
+ * Returns the number of idle chatter messages currently being displayed.
+ */
extern int kernel_check_random();
+
+/**
+ * Should be called regularly from daemon code whenever a random
+ * message sequence is running (intercepts triggers from terminating
+ * messages to determine when to free up control space).
+ */
extern void kernel_random_message_server();
+
+/**
+ * Called occasionally to (possibly) generate a random message.
+ *
+ * (generated whenever random(chance_major) <= chance_minor)
+ */
extern int kernel_generate_random_message(int chance_major, int chance_minor);
-extern void kernel_random_purge();
-/* kernel_o.cpp */
+extern void kernel_random_purge();
extern void kernel_load_interface();
+
+/**
+ * Switches interface modes (INTER_BUILDING_SENTENCES is the normal mode;
+ * INTER_CONVERSATION is for dialog scenes), and properly updates the graphic structures.
+ */
extern void kernel_set_interface_mode(int mode);
-/* kernel_q.cpp */
extern void kernel_room_scale(int front_y, int front_scale, int back_y, int back_scale);
-/* kernel_r.cpp */
+/**
+ * Room level system shutdown.
+ */
extern void kernel_background_shutdown();
extern int kernel_background_startup(int new_room, int initial_variant);
diff --git a/engines/mads/madsv2/core/kernel_1.cpp b/engines/mads/madsv2/core/kernel_1.cpp
deleted file mode 100644
index 6941dad2c8b..00000000000
--- a/engines/mads/madsv2/core/kernel_1.cpp
+++ /dev/null
@@ -1,84 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include "mads/madsv2/core/general.h"
-#include "mads/madsv2/core/room.h"
-#include "mads/madsv2/core/color.h"
-#include "mads/madsv2/core/kernel.h"
-
-namespace MADS {
-namespace MADSV2 {
-
-byte video_mode;
-RoomPtr room = NULL;
-int room_id = KERNEL_STARTING_GAME;
-int section_id = KERNEL_STARTING_GAME;
-int room_variant = 0;
-
-int new_room = 101;
-int new_section = 1;
-
-int previous_room = 0;
-int previous_section = 0;
-
-int kernel_initial_variant = 0;
-
-HotPtr room_spots = NULL;
-int room_num_spots = 0;
-
-int kernel_room_series_marker = 0;
-
-int kernel_room_bound_dif;
-int kernel_room_scale_dif;
-
-int kernel_allow_peel = false;
-
-int kernel_panning_speed = 0;
-int kernel_screen_fade = 0;
-
-Animation kernel_anim[KERNEL_MAX_ANIMATIONS];
-
-ShadowList kernel_shadow_main = { 0 };
-ShadowList kernel_shadow_inter = { 1, { 15 } };
-
-int kernel_ok_to_fail_load = false;
-
-int kernel_mode = KERNEL_GAME_LOAD;
-
-char kernel_cheating_password[16];
-int kernel_cheating_allowed = 0;
-int kernel_cheating_forbidden = 0;
-
-KernelDynamicHotSpot kernel_dynamic_hot[KERNEL_MAX_DYNAMIC];
-int kernel_num_dynamic = 0;
-int kernel_dynamic_changed = 0;
-
-
-SeriesPtr cursor = NULL; /* Mouse cursor series */
-
-int cursor_id = 1;
-int cursor_last = -1;
-
-Kernel kernel; /* Kernel data */
-KernelGame game; /* Kernel level game data */
-
-} // namespace MADSV2
-} // namespace MADS
diff --git a/engines/mads/madsv2/core/kernel_1.h b/engines/mads/madsv2/core/kernel_1.h
deleted file mode 100644
index afa6d724601..00000000000
--- a/engines/mads/madsv2/core/kernel_1.h
+++ /dev/null
@@ -1,107 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#ifndef MADS_CORE_KERNEL_1_H
-#define MADS_CORE_KERNEL_1_H
-
-#include "mads/madsv2/core/general.h"
-#include "mads/madsv2/core/room.h"
-#include "mads/madsv2/core/color.h"
-
-namespace MADS {
-namespace MADSV2 {
-
-extern RoomPtr room;
-extern int room_id;
-extern int section_id;
-extern int room_variant;
-
-extern int new_room;
-extern int new_section;
-
-extern int previous_room;
-extern int previous_section;
-
-extern int kernel_initial_variant;
-
-extern HotPtr room_spots;
-extern int room_num_spots;
-
-extern int kernel_room_series_marker;
-
-extern int kernel_room_bound_dif;
-extern int kernel_room_scale_dif;
-
-extern int kernel_allow_peel; /* Flag if peeling buffers allowed */
-
-extern int kernel_panning_speed;
-extern int kernel_screen_fade;
-
-
-extern Animation kernel_anim[KERNEL_MAX_ANIMATIONS];
-
-/*
-extern AnimPtr kernel_animation;
-extern int kernel_animation_cycled;
-extern int kernel_repeat_animation;
-
-extern int kernel_animation_sprite_loaded;
-extern int kernel_animation_buffer_id;
-extern byte *kernel_animation_buffer[2];
-
-extern int kernel_animation_messages;
-
-extern int kernel_animation_frame;
-extern int kernel_animation_image;
-extern int kernel_animation_doomed;
-extern int kernel_animation_trigger_code;
-extern int kernel_animation_trigger_mode;
-extern int kernel_animation_trigger_words[3];
-extern long kernel_animation_next_clock;
-*/
-
-extern ShadowList kernel_shadow_main;
-extern ShadowList kernel_shadow_inter;
-
-extern int kernel_ok_to_fail_load;
-
-extern int kernel_mode;
-
-extern char kernel_cheating_password[16];
-extern int kernel_cheating_allowed;
-extern int kernel_cheating_forbidden;
-
-extern KernelDynamicHotSpot kernel_dynamic_hot[KERNEL_MAX_DYNAMIC];
-extern int kernel_num_dynamic;
-extern int kernel_dynamic_changed;
-
-extern SeriesPtr cursor; /* Mouse cursor series */
-
-extern int cursor_id;
-extern int cursor_last;
-
-extern Kernel kernel;
-extern KernelGame game; /* Kernel level game data */
-
-} // namespace MADSV2
-} // namespace MADS
-
-#endif
diff --git a/engines/mads/madsv2/core/kernel_6.h b/engines/mads/madsv2/core/kernel_6.h
deleted file mode 100644
index 52b0dcdc27f..00000000000
--- a/engines/mads/madsv2/core/kernel_6.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#ifndef MADS_CORE_KERNEL_6_H
-#define MADS_CORE_KERNEL_6_H
-
-#include "mads/madsv2/core/general.h"
-
-namespace MADS {
-namespace MADSV2 {
-
-extern void kernel_unload_all_series();
-
-} // namespace MADSV2
-} // namespace MADS
-
-#endif
diff --git a/engines/mads/madsv2/core/kernel_8.h b/engines/mads/madsv2/core/kernel_8.h
deleted file mode 100644
index 180f337a132..00000000000
--- a/engines/mads/madsv2/core/kernel_8.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#ifndef MADS_CORE_KERNEL_8_H
-#define MADS_CORE_KERNEL_8_H
-
-#include "mads/madsv2/core/kernel.h"
-
-namespace MADS {
-namespace MADSV2 {
-
-
-extern Sequence sequence_list[KERNEL_MAX_SEQUENCES];
-
-extern void kernel_seq_init(void);
-
-extern int kernel_seq_add(int series_id, int mirror,
- int initial_sprite, int low_sprite, int high_sprite, int loop_mode,
- int loop_direction, int depth, int scale, int auto_locating, int x, int y,
- word ticks, word interval_ticks, word start_ticks, int expire);
-
-int fastcall kernel_seq_forward(int series_id, int mirror,
- word ticks, word interval_ticks, word start_ticks, int expire);
-
-int fastcall kernel_seq_forward_scroll(int series_id, int mirror,
- word ticks, word interval_ticks, word start_ticks, int expire);
-
-int fastcall kernel_seq_pingpong(int series_id, int mirror,
- word ticks, word interval_ticks, word start_ticks, int expire);
-
-int fastcall kernel_seq_pingpong_scroll(int series_id, int mirror,
- word ticks, word interval_ticks, word start_ticks, int expire);
-
-int fastcall kernel_seq_backward(int series_id, int mirror,
- word ticks, word interval_ticks, word start_ticks, int expire);
-
-int fastcall kernel_seq_backward_scroll(int series_id, int mirror,
- word ticks, word interval_ticks, word start_ticks, int expire);
-
-int fastcall kernel_seq_trigger(int sequence_id,
- int trigger_type, int trigger_sprite, int trigger_code);
-
-extern void kernel_seq_loc(int sequence_id, int x, int y);
-extern void kernel_seq_depth(int sequence_id, int depth);
-extern void kernel_seq_scale(int sequence_id, int scale);
-
-
-extern int kernel_seq_purge(int sequence_id);
-
-extern void kernel_seq_full_update(void);
-
-extern void kernel_synch(int slave_type, int slave_id,
- int master_type, int master_id);
-
-extern void kernel_draw_to_background(int series_id, int sprite_id,
- int x, int y, int depth, int scale);
-
-} // namespace MADSV2
-} // namespace MADS
-
-#endif
diff --git a/engines/mads/madsv2/core/kernel_9.h b/engines/mads/madsv2/core/kernel_9.h
deleted file mode 100644
index a5b5ff6913b..00000000000
--- a/engines/mads/madsv2/core/kernel_9.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#ifndef MADS_CORE_KERNEL_9_H
-#define MADS_CORE_KERNEL_9_H
-
-#include "mads/madsv2/core/kernel.h"
-#include "mads/madsv2/core/image.h"
-
-namespace MADS {
-namespace MADSV2 {
-
-extern void kernel_seq_image(SequencePtr sequence, ImagePtr image, int sequence_id);
-
-} // namespace MADSV2
-} // namespace MADS
-
-#endif
diff --git a/engines/mads/madsv2/core/kernel_c.h b/engines/mads/madsv2/core/kernel_c.h
deleted file mode 100644
index 5281048374f..00000000000
--- a/engines/mads/madsv2/core/kernel_c.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#ifndef MADS_CORE_KERNEL_C_H
-#define MADS_CORE_KERNEL_C_H
-
-namespace MADS {
-namespace MADSV2 {
-
-extern void kernel_reconstruct_screen(int anim_handle);
-extern void kernel_abort_animation(int handle);
-extern void kernel_animation_get_sprite(int handle, int id);
-
-} // namespace MADSV2
-} // namespace MADS
-
-#endif
diff --git a/engines/mads/madsv2/core/kernel_d.h b/engines/mads/madsv2/core/kernel_d.h
deleted file mode 100644
index 36eb38af8ec..00000000000
--- a/engines/mads/madsv2/core/kernel_d.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#ifndef MADS_CORE_KERNEL_D_H
-#define MADS_CORE_KERNEL_D_H
-
-#include "mads/madsv2/core/kernel.h"
-#include "mads/madsv2/core/font.h"
-
-namespace MADS {
-namespace MADSV2 {
-
-extern KernelMessage kernel_message[KERNEL_MAX_MESSAGES];
-extern FontPtr kernel_message_font;
-extern int kernel_message_spacing;
-
-extern void kernel_message_init(void);
-extern int kernel_message_add(char far *text, int x, int y,
- int color, long time_on_screen, int trigger_code, int flags);
-extern void kernel_message_teletype(int id, int rate, int quote);
-extern void kernel_message_attach(int id, int sequence);
-extern void kernel_message_delete(int id);
-extern void kernel_message_purge(void);
-
-} // namespace MADSV2
-} // namespace MADS
-
-#endif
diff --git a/engines/mads/madsv2/core/kernel_f.h b/engines/mads/madsv2/core/kernel_f.h
deleted file mode 100644
index 1f1eb088d64..00000000000
--- a/engines/mads/madsv2/core/kernel_f.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#ifndef MADS_CORE_KERNEL_F_H
-#define MADS_CORE_KERNEL_F_H
-
-namespace MADS {
-namespace MADSV2 {
-
-extern int kernel_add_dynamic(int vocab_id, int auto_sequence,
- int x, int y, int xs, int ys);
-extern int kernel_dynamic_walk(int id, int feet_x, int feet_y, int facing);
-extern void kernel_delete_dynamic(int id);
-extern void kernel_purge_dynamic();
-extern void kernel_init_dynamic();
-
-} // namespace MADSV2
-} // namespace MADS
-
-#endif
diff --git a/engines/mads/madsv2/core/kernel_g.h b/engines/mads/madsv2/core/kernel_g.h
deleted file mode 100644
index 01d2ef2c86d..00000000000
--- a/engines/mads/madsv2/core/kernel_g.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#ifndef MADS_CORE_KERNEL_G_H
-#define MADS_CORE_KERNEL_G_H
-
-namespace MADS {
-namespace MADSV2 {
-
-extern int kernel_dynamic_consecutive(int id);
-extern void kernel_refresh_dynamic();
-
-} // namespace MADSV2
-} // namespace MADS
-
-#endif
diff --git a/engines/mads/madsv2/core/kernel_h.h b/engines/mads/madsv2/core/kernel_h.h
deleted file mode 100644
index 7b001e1ea23..00000000000
--- a/engines/mads/madsv2/core/kernel_h.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#ifndef MADS_CORE_KERNEL_H_H
-#define MADS_CORE_KERNEL_H_H
-
-namespace MADS {
-namespace MADSV2 {
-
-extern int kernel_dynamic_consecutive(int id);
-extern void kernel_refresh_dynamic();
-
-} // namespace MADSV2
-} // namespace MADS
-
-#endif
diff --git a/engines/mads/madsv2/core/kernel_i.h b/engines/mads/madsv2/core/kernel_i.h
deleted file mode 100644
index 337b62da718..00000000000
--- a/engines/mads/madsv2/core/kernel_i.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#ifndef MADS_CORE_KERNEL_I_H
-#define MADS_CORE_KERNEL_I_H
-
-#include "mads/madsv2/core/kernel.h"
-#include "mads/madsv2/core/image.h"
-
-namespace MADS {
-namespace MADSV2 {
-
-extern void kernel_seq_image(SequencePtr sequence, ImagePtr image, int sequence_id);
-
-} // namespace MADSV2
-} // namespace MADS
-
-#endif
diff --git a/engines/mads/madsv2/core/kernel_k.h b/engines/mads/madsv2/core/kernel_k.h
deleted file mode 100644
index beb01a22593..00000000000
--- a/engines/mads/madsv2/core/kernel_k.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#ifndef MADS_CORE_KERNEL_K_H
-#define MADS_CORE_KERNEL_K_H
-
-namespace MADS {
-namespace MADSV2 {
-
-extern void kernel_new_palette();
-
-} // namespace MADSV2
-} // namespace MADS
-
-#endif
diff --git a/engines/mads/madsv2/core/kernel_n.h b/engines/mads/madsv2/core/kernel_n.h
deleted file mode 100644
index 8143258c85e..00000000000
--- a/engines/mads/madsv2/core/kernel_n.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#ifndef MADS_CORE_KERNEL_N_H
-#define MADS_CORE_KERNEL_N_H
-
-namespace MADS {
-namespace MADSV2 {
-
-extern void kernel_random_messages_init(int max_messages_at_once,
- int min_x, int max_x, int min_y, int max_y, int min_y_spacing,
- int teletype_rate, int color, int duration, int quote_id, ...);
-extern int kernel_check_random(void);
-extern void kernel_random_message_server(void);
-extern int kernel_generate_random_message(int chance_major,
- int chance_minor);
-extern void kernel_random_purge(void);
-
-} // namespace MADSV2
-} // namespace MADS
-
-#endif
diff --git a/engines/mads/madsv2/core/kernel_o.h b/engines/mads/madsv2/core/kernel_o.h
deleted file mode 100644
index f07b9a673df..00000000000
--- a/engines/mads/madsv2/core/kernel_o.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#ifndef MADS_CORE_KERNEL_O_H
-#define MADS_CORE_KERNEL_O_H
-
-namespace MADS {
-namespace MADSV2 {
-
-#define kernel_init_dialog() inter_reset_dialog()
-#define kernel_dialog(q) inter_add_dialog(quote_string(kernel.quotes, q), q)
-
-extern void kernel_set_interface_mode(int mode);
-
-} // namespace MADSV2
-} // namespace MADS
-
-#endif
diff --git a/engines/mads/madsv2/core/matte.cpp b/engines/mads/madsv2/core/matte.cpp
index b0d9529b12d..fecf8949e6a 100644
--- a/engines/mads/madsv2/core/matte.cpp
+++ b/engines/mads/madsv2/core/matte.cpp
@@ -153,7 +153,7 @@ int matte_allocate_series(SeriesPtr series, int bonus_series_number) {
return handle;
}
-int matte_load_series(char *name, int load_flags, int bonus_series_number) {
+int matte_load_series(const char *name, int load_flags, int bonus_series_number) {
int found = false;
int valid_name = true;
int handle = -1;
diff --git a/engines/mads/madsv2/core/matte.h b/engines/mads/madsv2/core/matte.h
index 924fe643b8d..c684830ba5d 100644
--- a/engines/mads/madsv2/core/matte.h
+++ b/engines/mads/madsv2/core/matte.h
@@ -134,9 +134,7 @@ void matte_frame(int special_effect, int full_screen);
/* matte_1.c */
//void matte_init_series(void);
-int matte_load_series(char *name,
- int load_flags,
- int bonus_series_number);
+int matte_load_series(const char *name, int load_flags, int bonus_series_number);
void matte_deallocate_series(int id, int free_memory);
int matte_allocate_series(SeriesPtr series,
int bonus_series_number);
diff --git a/engines/mads/madsv2/core/player.cpp b/engines/mads/madsv2/core/player.cpp
new file mode 100644
index 00000000000..17e90a436c2
--- /dev/null
+++ b/engines/mads/madsv2/core/player.cpp
@@ -0,0 +1,1001 @@
+/* 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 "mads/madsv2/core/player.h"
+#include "mads/madsv2/core/general.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/buffer.h"
+#include "mads/madsv2/core/inter.h"
+#include "mads/madsv2/core/timer.h"
+#include "mads/madsv2/core/rail.h"
+#include "mads/madsv2/core/attr.h"
+#include "mads/madsv2/core/imath.h"
+#include "mads/madsv2/core/matte.h"
+#include "mads/madsv2/core/error.h"
+#include "mads/madsv2/core/pal.h"
+#include "mads/madsv2/core/himem.h"
+#include "mads/madsv2/core/object.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+Player player;
+
+byte player_facing_to_series[10] = { 0, 7, 4, 3, 6, 0, 2, 5, 0, 1 };
+byte player_clockwise[10] = { 9, 4, 1, 2, 7, 9, 3, 8, 9, 6 };
+byte player_counter_clockwise[10] = { 7, 2, 3, 6, 1, 7, 9, 4, 7, 8 };
+
+/**
+ * Returns the scaling factor for the player walker, based on the
+ * player's current position
+ */
+static int player_scaling_factor(int y) {
+ int bound, scale;
+
+ bound = y - room->back_y;
+
+ if (kernel_room_bound_dif != 0) {
+ scale = room->back_scale + ((kernel_room_scale_dif * bound) / kernel_room_bound_dif);
+ } else {
+ scale = room->front_scale;
+ }
+
+ scale = MIN(100, scale);
+
+ return (scale);
+}
+
+/**
+ * Loads up the proper frame rate for the current walker series.
+ */
+static void player_set_base_frame_rate() {
+ player.frame_delay = series_list[player.series_base + player.series]->walker->frame_rate;
+ if (!player.frame_delay) player.frame_delay = 6;
+}
+
+void player_new_stop_walker() {
+ int id;
+ int abs_stop;
+ WalkerInfoPtr walker;
+
+ id = player.series_base + player.series;
+ walker = series_list[id]->walker;
+
+ if (!walker->num_secondary) {
+ player.sprite = 1;
+ goto done;
+ }
+
+ player.stop_walker_sequence = player.stop_walker_stack[player.stop_walker_pointer];
+
+ if (!player.walker_visible) {
+ player.upcoming_trigger = 0;
+ } else {
+ player.upcoming_trigger = player.stop_walker_trigger[player.stop_walker_pointer];
+ if (player.stop_walker_pointer) player.stop_walker_pointer--;
+ }
+
+ abs_stop = ABS(player.stop_walker_sequence);
+ if (player.stop_walker_sequence >= 0) {
+ player.sprite = walker->sequence_start[abs_stop];
+ } else {
+ player.sprite = walker->sequence_stop[abs_stop];
+ }
+
+ if (abs_stop == 0) {
+ player_set_base_frame_rate();
+ } else {
+ player.frame_delay = walker->sequence_chance[abs_stop];
+ }
+
+done:
+ player.sprite_changed = true;
+}
+
+void player_select_series() {
+ int id;
+
+ player_clear_stop_walkers();
+
+ player.mirror = 0;
+ player.series = player_facing_to_series[player.facing];
+
+ if (!player.available[player.series]) {
+ player.series -= 4;
+ player.mirror = MIRROR_MASK;
+ }
+
+ id = player.series_base + player.series;
+
+ player.velocity = MAX(series_list[id]->walker->velocity, 100);
+
+ player_set_base_frame_rate();
+
+ player.high_sprite = series_list[id]->walker->num_primary;
+ if (player.high_sprite == 0) player.high_sprite = series_list[id]->num_sprites;
+
+ player.center_of_gravity = series_list[id]->walker->center_of_gravity;
+
+ if ((player.sprite <= 0) || (player.sprite > player.high_sprite)) {
+ player.sprite = 1;
+ }
+
+ player.sprite_changed = true;
+}
+
+static void player_activate_trigger() {
+ int count;
+
+ player.commands_allowed |= player.enable_at_target;
+ player.enable_at_target = false;
+
+ if (player.walk_trigger) {
+ kernel.trigger = player.walk_trigger;
+ kernel.trigger_mode = player.walk_trigger_dest;
+ if (kernel.trigger_mode != KERNEL_TRIGGER_DAEMON) {
+ for (count = 0; count < 3; count++) {
+ player2.words[count] = player.walk_trigger_words[count];
+ }
+ }
+ player.walk_trigger = 0;
+ }
+}
+
+/**
+ * When the player needs to turn to face a different direction
+ * than his current facing, this routine rotates him one place
+ * in the right direction.
+ */
+static void player_keep_turning() {
+ int clockwise_count = 0;
+ int clockwise_sum = 0;
+ int counter_clockwise_count = 0;
+ int counter_clockwise_sum = 0;
+ int temp_facing;
+ int decision;
+
+ player.sprite++;
+
+ for (temp_facing = player.facing;
+ temp_facing != player.turn_to_facing;
+ temp_facing = player_clockwise[temp_facing]) {
+ clockwise_count++;
+ clockwise_sum += temp_facing;
+ }
+
+ for (temp_facing = player.facing;
+ temp_facing != player.turn_to_facing;
+ temp_facing = player_counter_clockwise[temp_facing]) {
+ counter_clockwise_count++;
+ counter_clockwise_sum += temp_facing;
+ }
+
+ decision = (clockwise_count - counter_clockwise_count);
+ if (!decision) decision = clockwise_sum - counter_clockwise_sum;
+
+ if (decision < 0) {
+ player.facing = player_clockwise[player.facing];
+ } else {
+ player.facing = player_counter_clockwise[player.facing];
+ }
+
+ player_select_series();
+
+ if (player.facing == player.turn_to_facing) {
+ if (!player.walking) {
+ player_new_stop_walker();
+ player_activate_trigger();
+ }
+ }
+
+ player.clock++; /* Add 1 to player clock for slightly slower turn */
+}
+
+void player_stationary_update() {
+ int id;
+ int abs_stop;
+ int sgn_stop;
+ WalkerInfoPtr walker;
+
+ if (player.facing != player.turn_to_facing) {
+ player_keep_turning();
+ goto done;
+ }
+
+ id = player.series_base + player.series;
+ walker = series_list[id]->walker;
+
+ if (walker->num_secondary > 0) {
+ abs_stop = ABS(player.stop_walker_sequence);
+ sgn_stop = sgn(player.stop_walker_sequence);
+ if (sgn_stop == 0) sgn_stop = 1;
+
+ if (abs_stop < walker->num_secondary) {
+
+ player.sprite += sgn_stop;
+ player.sprite_changed = true;
+
+ if (player.sprite > walker->sequence_stop[abs_stop]) {
+ player.trigger = player.upcoming_trigger;
+ player_new_stop_walker();
+ }
+ if (player.sprite < walker->sequence_start[abs_stop]) {
+ player.trigger = player.upcoming_trigger;
+ player_new_stop_walker();
+ }
+ } else {
+ player.stop_walker_sequence = 0;
+ }
+ }
+
+done:
+ ;
+}
+
+void player_set_facing() {
+ int dx, dy, ds, sy;
+ int mode;
+ int s1, s2;
+ int angle_factor;
+ word ddx, ddy, dddx;
+ word ssy;
+ word pixels;
+
+ dx = (player.target_x - player.x);
+ dy = (player.target_y - player.y);
+
+ s1 = player_scaling_factor(player.target_y);
+ s2 = player_scaling_factor(player.y);
+
+ s1 = MIN(s1, 100);
+ s2 = MIN(s2, 100);
+
+ player.sign_x = sgn(dx);
+ player.sign_y = sgn(dy);
+
+ dx = ABS(dx);
+ dy = ABS(dy);
+ ds = ABS(s2 - s1);
+
+ ddx = ((word)dx) * 100;
+ ddy = ((word)dy) * 100;
+
+ dddx = ((word)dx) * 33;
+
+ angle_factor = 100 + (player.scaling_velocity ? (ds * 3) : 0);
+
+ sy = (dy * angle_factor) / 100;
+ ssy = ((word)sy) * 100;
+
+ if (dx == 0) {
+ mode = PLAYER_VERTICAL;
+ } else if (dy == 0) {
+ mode = PLAYER_HORIZONTAL;
+ } else if ((dx > sy) && ((dddx / (word)sy) >= PLAYER_DIAGONAL_THRESHOLD)) {
+ mode = PLAYER_HORIZONTAL;
+ } else {
+ if ((dy > dx) && ((ssy / (word)dx) >= PLAYER_DIAGONAL_THRESHOLD)) {
+ mode = PLAYER_VERTICAL;
+ } else {
+ mode = PLAYER_DIAGONAL;
+ }
+ }
+
+ switch (mode) {
+ case PLAYER_VERTICAL:
+ player.turn_to_facing = (player.sign_y > 0) ? 2 : 8;
+ break;
+ case PLAYER_HORIZONTAL:
+ player.turn_to_facing = (player.sign_x > 0) ? 6 : 4;
+ break;
+ case PLAYER_DIAGONAL:
+ player.turn_to_facing = (player.sign_y > 0) ? 3 : 9;
+ player.turn_to_facing -= (player.sign_x > 0) ? 0 : 2;
+ break;
+ }
+
+ player.total_distance = imath_hypot(dx, dy);
+ player.x_count = dx + 1;
+ player.y_count = dy + 1;
+ player.x_counter = dx;
+ player.y_counter = dy;
+
+ pixels = MAX(player.x_counter, player.y_counter);
+ if (pixels > 0) {
+ player.delta_distance = (player.total_distance * 100) / pixels;
+ } else {
+ player.delta_distance = 0;
+ }
+
+ if (player.x <= player.target_x) {
+ player.pixel_accum = 0;
+ } else {
+ player.pixel_accum = MIN(dx, dy);
+ }
+
+ player.dist_accum = 0 - (int)player.delta_distance;
+}
+
+void player_set_final_facing() {
+ if (player.target_facing != 5) {
+ player.turn_to_facing = player.target_facing;
+ }
+}
+
+void player_set_sprite() {
+ if (player.walking) {
+ player.sprite += 1;
+ if (player.sprite > player.high_sprite) player.sprite = 1;
+ player.sprite_changed = true;
+ } else {
+ if (!player.sprite_changed) player_stationary_update();
+ }
+}
+
+void player_keep_walking() {
+ int at_x, at_y;
+ int walk_code;
+ int id;
+ int new_facing = false;
+ int temp_velocity;
+ int angle_scale;
+ int angle_range;
+
+ while (player.walking && !player.walk_off_edge && (player.x == player.target_x) && (player.y == player.target_y)) {
+ if (rail_solution_stack_pointer == 0) {
+ if (player.walk_off_edge_to_room) {
+ player.walk_off_edge = player.walk_off_edge_to_room;
+ player.walk_anywhere = true;
+ player.walk_off_edge_to_room = 0;
+ player.commands_allowed = false;
+ new_facing = false;
+ } else {
+ player.walking = false;
+ player_set_final_facing();
+ new_facing = true;
+ }
+ } else {
+ id = rail_solution_stack[--rail_solution_stack_pointer];
+ player.target_x = room->rail[id].x;
+ player.target_y = room->rail[id].y;
+ new_facing = true;
+ }
+ }
+
+ if (new_facing) {
+ if (player.walking) player_set_facing();
+ }
+
+ if (player.facing != player.turn_to_facing) {
+ player_keep_turning();
+ } else {
+ if (!player.walking) {
+ player_new_stop_walker();
+ player_activate_trigger();
+ }
+ }
+
+ temp_velocity = player.velocity;
+
+ if (player.scaling_velocity && (player.total_distance > 0)) {
+ angle_range = 100 - player.scale;
+ angle_scale = player.scale + ((angle_range * (player.x_count - 1)) / player.total_distance);
+ temp_velocity = (int)(((long)temp_velocity * ((long)player.scale * (long)angle_scale)) / 10000L);
+ temp_velocity = MAX(temp_velocity, 1);
+ }
+
+ if (player.walking && (player.facing == player.turn_to_facing)) {
+ at_x = player.x;
+ at_y = player.y;
+ walk_code = false;
+ player.special_code = 0;
+
+ if (player.dist_accum < temp_velocity) {
+
+ do {
+ if (player.pixel_accum < player.x_count) {
+ player.pixel_accum += player.y_count;
+ }
+ if (player.pixel_accum >= player.x_count) {
+ if ((player.y_counter > 0) || player.walk_off_edge) at_y += player.sign_y;
+ player.y_counter--;
+ player.pixel_accum -= player.x_count;
+ }
+ if (player.pixel_accum < player.x_count) {
+ if ((player.x_counter > 0) || player.walk_off_edge) at_x += player.sign_x;
+ player.x_counter--;
+ }
+
+ if (!player.walk_anywhere && !(player.walk_off_edge || player.walk_off_edge_to_room)) {
+ walk_code |= attr_walk(&scr_walk, at_x, at_y);
+ if (!player.special_code) {
+ player.special_code = attr_special(&scr_special, at_x, at_y);
+ }
+ }
+
+ player.dist_accum += player.delta_distance;
+ } while ((player.dist_accum < temp_velocity) && (!walk_code) &&
+ ((player.x_counter > 0) || (player.y_counter > 0) || (player.walk_off_edge)));
+
+ }
+
+ player.dist_accum -= temp_velocity;
+
+ if (walk_code) {
+ player_cancel_command();
+ } else {
+ if (!player.walk_off_edge) {
+ if (player.x_counter <= 0) at_x = player.target_x;
+ if (player.y_counter <= 0) at_y = player.target_y;
+ }
+ player.x = at_x;
+ player.y = at_y;
+ }
+ }
+}
+
+int player_search_image() {
+ int number = -1;
+ int count;
+
+ for (count = 0; (count < (int)image_marker) && (number < 0); count++) {
+ if ((image_list[count].segment_id == KERNEL_SEGMENT_PLAYER) &&
+ (image_list[count].flags >= 0)) {
+ number = count;
+ }
+ }
+ return number;
+}
+
+void player_set_image() {
+ int count;
+ int scale;
+ int old_image_number;
+ int xs, ys, x, y;
+ int effective_y;
+ byte depth;
+ Image new_image;
+
+ if (!player.sprite_changed && (player.walker_visible == player.walker_previously_visible)) goto done;
+
+ old_image_number = player_search_image();
+ if (old_image_number >= 0) {
+ image_list[old_image_number].flags = IMAGE_ERASE;
+ }
+
+ depth = 1;
+ effective_y = player.y;
+ /* effective_y = MIN (effective_y, display_y - 1); */
+ for (count = 1; count < 15; count++) {
+ if (effective_y <= room->depth_table[depth]) {
+ depth = (byte)(count + 1);
+ }
+ }
+
+ scale = player_scaling_factor(player.y);
+
+ player.depth = (byte)depth;
+ player.scale = (byte)MIN(100, scale);
+
+ if (player.walker_visible) {
+ new_image.flags = IMAGE_UPDATE;
+ new_image.segment_id = KERNEL_SEGMENT_PLAYER;
+ new_image.series_id = (byte)(player.series_base + player.series);
+ new_image.sprite_id = player.sprite | player.mirror;
+ new_image.x = player.x;
+ new_image.y = player.y + ((player.center_of_gravity * scale) / 100);
+ new_image.depth = depth;
+ new_image.scale = (byte)scale;
+
+ if ((old_image_number >= 0) && memcmp(&new_image.segment_id, &image_list[old_image_number].segment_id,
+ sizeof(Image) - sizeof(int)) == 0) {
+ image_list[old_image_number].flags = 0;
+ } else {
+ image_list[image_marker] = new_image;
+ image_marker++;
+ }
+
+ if (player.walk_off_edge) {
+ xs = (series_list[new_image.series_id]->index[player.sprite - 1].xs * scale) / 200;
+ ys = (series_list[new_image.series_id]->index[player.sprite - 1].ys * scale) / 100;
+ x = new_image.x;
+ y = new_image.y;
+
+ if ((((x + xs) < 0) || ((x - xs) >= picture_map.total_x_size)) ||
+ ((y < 0) || ((y - ys) >= picture_map.total_y_size))) {
+ if (room_id == player.walk_off_edge) {
+ kernel.force_restart = true;
+ }
+ new_room = player.walk_off_edge;
+ player.walk_off_edge = 0;
+ player.walk_anywhere = player.walk_freedom;
+ }
+ }
+ }
+
+done:
+ player.walker_previously_visible = player.walker_visible;
+ player.walker_been_visible |= player.walker_visible;
+ player.sprite_changed = false;
+}
+
+int player_load_series(const char *name) {
+ int error_flag = true;
+ int count;
+ int handle;
+ char temp_buf[80];
+ char *mark;
+ char load_buf[8] = { '8', '9', '6', '3', '2', '7', '4', '1' };
+
+ if (name == NULL) {
+ name = player.series_name;
+ } else {
+ Common::strcpy_s(player.series_name, name);
+ }
+
+ player.num_series = 0;
+
+ if (!strlen(player.series_name)) {
+ for (count = 0; count < 8; count++) {
+ player.available[count] = false;
+ }
+ player.walker_visible = false;
+ player.walker_is_loaded = false;
+ player.walker_must_reload = false;
+ goto done;
+ }
+
+ Common::strcpy_s(temp_buf, "*");
+ Common::strcat_s(temp_buf, name);
+ Common::strcat_s(temp_buf, "_0.SS");
+
+ mark = strrchr(temp_buf, '_') + 1;
+
+ for (count = 0; count < 8; count++) {
+ if (count >= 5) kernel_ok_to_fail_load = true;
+ *mark = load_buf[count];
+ player.available[count] = true;
+ handle = kernel_load_series(temp_buf, SPRITE_LOAD_WALKER_INFO);
+ if (handle < 0) {
+ if (count < 5) {
+ goto done;
+ } else {
+ player.available[count] = false;
+ }
+ } else {
+ player.num_series++;
+ }
+ if (count == 0) player.series_base = handle;
+ }
+
+ error_flag = false;
+ player.walker_is_loaded = true;
+ player.walker_must_reload = false;
+
+done:
+ kernel_ok_to_fail_load = false;
+ return(error_flag);
+}
+
+void player_dump_walker() {
+ int high;
+ int count;
+
+ if (player.walker_is_loaded && (player.num_series > 0)) {
+ high = player.series_base + player.num_series - 1;
+ for (count = high; count >= player.series_base; count--) {
+ series_user[count] = 1;
+ matte_deallocate_series(count, true);
+ }
+ }
+
+ player.walker_is_loaded = false;
+ player.walker_must_reload = true;
+}
+
+void player_preserve_palette() {
+ int count;
+ dword flag_mask;
+ dword flag;
+
+ flag_mask = PAL_RESERVED;
+
+ if (player.walker_is_loaded) {
+ for (count = 0; count < player.num_series; count++) {
+ flag = series_list[player.series_base + count]->color_handle;
+ flag = (1L << flag);
+ flag_mask |= flag;
+ }
+ }
+
+ for (count = 0; count < 256; count++) {
+ color_status[count] &= flag_mask;
+ }
+
+ palette_locked = false;
+
+ for (count = 2; count < PAL_MAXFLAGS; count++) {
+ flag = (1L << (dword)count);
+ if (!(flag_mask & flag)) {
+ flag_used[count] = false;
+ } else {
+ flag_used[count] = true;
+ }
+ }
+}
+
+void player_himem_preload(char *name, int level) {
+ char temp_buf[80];
+ int count;
+
+ for (count = 1; count <= 9; count++) {
+ if (count != 5) {
+ Common::strcpy_s(temp_buf, name);
+ Common::strcat_s(temp_buf, "_0");
+ temp_buf[strlen(temp_buf) - 1] += count;
+ himem_preload_series(kernel_full_name(0, 0, -1, temp_buf, KERNEL_SS), level);
+ }
+ }
+}
+
+/**
+ * Puts player on course to mouse click location, if any.
+ */
+static void player_walk_directly(int walk_form) {
+ if (inter_point_established && ((walk_form == WALK_DIRECT_2) || (player.command < 0))) {
+ player.need_to_walk = true;
+ player.prepare_walk_x = inter_point_x;
+ player.prepare_walk_y = inter_point_y;
+ }
+}
+
+void player_new_command() {
+ int count;
+ int walk_spot;
+
+ player_cancel_command();
+
+ player.command_ready = true;
+ player.command_error = false;
+
+ player.command = inter_command;
+ player.main_object = inter_main_object;
+ player.second_object = inter_second_object;
+ player.prep = inter_prep;
+ player.command_source = inter_command_source;
+ player.main_object_source = inter_main_object_source;
+ player.second_object_source = inter_second_object_source;
+ player.look_around = inter_look_around;
+
+ player.main_syntax = inter_main_syntax;
+ player.second_syntax = inter_second_syntax;
+
+ for (count = 0; count < 3; count++) {
+ player2.words[count] = inter_words[count];
+ }
+
+ Common::strcpy_s(player.sentence, inter_sentence);
+
+ walk_spot = -1;
+ player.need_to_walk = false;
+
+ if (!player.look_around && (inter_input_mode != INTER_CONVERSATION)) {
+ if (player.main_object_source == STROKE_INTERFACE) {
+ walk_spot = player.main_object;
+ } else if (player.second_object_source == STROKE_INTERFACE) {
+ walk_spot = player.second_object;
+ }
+ if (walk_spot >= room_num_spots) {
+ walk_spot = kernel_dynamic_consecutive(walk_spot - room_num_spots);
+ if (walk_spot >= 0) {
+ if ((kernel_dynamic_hot[walk_spot].feet_x == WALK_DIRECT) ||
+ (kernel_dynamic_hot[walk_spot].feet_x == WALK_DIRECT_2)) {
+ player_walk_directly(kernel_dynamic_hot[walk_spot].feet_x);
+ } else if (kernel_dynamic_hot[walk_spot].feet_x >= 0) {
+ player.need_to_walk = true;
+ player.prepare_walk_x = kernel_dynamic_hot[walk_spot].feet_x;
+ player.prepare_walk_y = kernel_dynamic_hot[walk_spot].feet_y;
+ }
+ player.prepare_walk_facing = kernel_dynamic_hot[walk_spot].facing;
+ }
+ walk_spot = -1;
+ }
+ }
+
+ if (walk_spot >= 0) {
+ if ((room_spots[walk_spot].feet_x == WALK_DIRECT) ||
+ (room_spots[walk_spot].feet_x == WALK_DIRECT_2)) {
+ player_walk_directly(room_spots[walk_spot].feet_x);
+ } else if (room_spots[walk_spot].feet_x == WALK_NONE) {
+ ;
+ } else if (room_spots[walk_spot].feet_x >= 0) {
+ player.need_to_walk = true;
+ player.prepare_walk_x = room_spots[walk_spot].feet_x;
+ player.prepare_walk_y = room_spots[walk_spot].feet_y;
+ }
+
+ player.prepare_walk_facing = room_spots[walk_spot].facing;
+ }
+
+ player.ready_to_walk = player.need_to_walk;
+
+ /* Be sure player moves immediately even if in the middle of a long */
+ /* stop-walker frame. */
+ player.clock = MIN(player.clock, kernel.clock + series_list[player.series_base + player.series]->walker->frame_rate);
+}
+
+void player_new_walk() {
+ if (player.need_to_walk && player.ready_to_walk) {
+ player_start_walking(player.prepare_walk_x, player.prepare_walk_y, player.prepare_walk_facing);
+ player.need_to_walk = false;
+ }
+}
+
+int player_parse(int vocab_item, ...) {
+ va_list marker;
+ int my_word = vocab_item;
+ int result = true;
+ int matched;
+ int count;
+
+ if (inter_input_mode == INTER_CONVERSATION) {
+ result = false;
+ goto done;
+ }
+
+ va_start(marker, vocab_item);
+ while (my_word > 0) {
+ matched = false;
+ for (count = 0; count < 3; count++) {
+ if (my_word == player2.words[count]) {
+ matched = true;
+ }
+ }
+ result &= matched;
+
+ my_word = va_arg(marker, int);
+ }
+
+done:
+ return result;
+}
+
+void player_cancel_walk() {
+ player.target_x = player.x;
+ player.target_y = player.y;
+
+ player.target_facing = 5;
+ player.turn_to_facing = player.facing;
+
+ player.need_to_walk = false;
+ player.ready_to_walk = false;
+ player.walking = false;
+
+ player.walk_anywhere = player.walk_freedom;
+ player.walk_off_edge = 0;
+ player.walk_off_edge_to_room = 0;
+
+ player.next_special_code = 0;
+
+ player.walk_trigger = 0;
+ player.commands_allowed |= player.enable_at_target;
+ player.enable_at_target = false;
+
+ rail_solution_stack_pointer = 0;
+}
+
+void player_cancel_command() {
+ player_cancel_walk();
+ player.command_ready = false;
+}
+
+int player_has_been_in_room(int id) {
+ int been_there = false;
+ int count;
+
+ for (count = 0; count < player.num_rooms_been_in; count++) {
+ if (id == player.rooms_been_in[count]) {
+ been_there = true;
+ }
+ }
+
+ return been_there;
+}
+
+void player_discover_room(int id) {
+ player.been_here_before = (byte)player_has_been_in_room(id);
+
+ if (!player.been_here_before) {
+ if (player.num_rooms_been_in >= PLAYER_MAX_ROOMS) {
+ error_report(ERROR_BEEN_IN_TOO_MANY_ROOMS, WARNING, MODULE_PLAYER, PLAYER_MAX_ROOMS, id);
+ } else {
+ player.rooms_been_in[player.num_rooms_been_in++] = id;
+ }
+ }
+}
+
+int player_has(int object_id) {
+ int has_flag = false;
+
+ if (object_id < 0) goto done;
+
+ if (object[object_id].location != PLAYER) goto done;
+
+ has_flag = true;
+
+done:
+ return has_flag;
+}
+
+void player_clear_stop_walkers() {
+ player.stop_walker_stack[0] = 0;
+ player.stop_walker_trigger[0] = 0;
+ player.stop_walker_pointer = 0;
+ player.upcoming_trigger = 0;
+ player.trigger = 0;
+}
+
+void player_init() {
+ player.x = video_x >> 1;
+ player.y = display_y >> 1;
+ player.center_of_gravity = 0;
+ player.walking = false;
+ player.need_to_walk = false;
+ player.sprite_changed = true;
+ player.frame_delay = 3;
+ player.commands_allowed = true;
+ player.walker_visible = true;
+ player.walk_freedom = false;
+
+ // jacked up to 5 from 0 so inventory sprites can be loaded before walker
+ player.series_base = 5;
+ player.command_ready = false;
+ player.num_rooms_been_in = 0;
+ player.special_code = 0;
+ player.next_special_code = 0;
+ player.scaling_velocity = false;
+ player.walker_is_loaded = false;
+ player.walker_must_reload = true;
+ player.walker_loads_first = true;
+
+ player.walk_trigger = 0;
+ player.enable_at_target = false;
+
+ player_clear_stop_walkers();
+}
+
+void player_start_walking(int walk_x, int walk_y, int walk_facing) {
+ int allow_one_illegal;
+ int from_x, from_y;
+ int unto_x, unto_y;
+ int temp_stack_pointer;
+#ifdef show_rails
+ Buffer scr_live = { video_y, video_x, mcga_video };
+#endif
+
+ player_clear_stop_walkers();
+ player_set_base_frame_rate();
+
+ player.walking = true;
+ player.target_facing = walk_facing;
+
+ rail_add_node(rail_num_nodes - 2, player.x, player.y);
+ rail_add_node(rail_num_nodes - 1, walk_x, walk_y);
+
+ allow_one_illegal = attr_walk(&scr_walk, walk_x, walk_y);
+
+ rail_check_path(allow_one_illegal);
+
+#ifdef show_rails
+ from_x = player.x;
+ from_y = player.y;
+ temp_stack_pointer = rail_solution_stack_pointer;
+ while (temp_stack_pointer) {
+ temp_stack_pointer--;
+ unto_x = room->rail[rail_solution_stack[temp_stack_pointer]].x;
+ unto_y = room->rail[rail_solution_stack[temp_stack_pointer]].y;
+ buffer_line(scr_live, from_x, from_y, unto_x, unto_y, 3);
+ from_x = unto_x;
+ from_y = unto_y;
+ if (kernel.frame_by_frame) keys_get();
+ }
+#endif
+
+ from_x = player.x;
+ from_y = player.y;
+ player.next_special_code = 0;
+ temp_stack_pointer = rail_solution_stack_pointer;
+ while (temp_stack_pointer && !player.next_special_code) {
+ temp_stack_pointer--;
+ unto_x = room->rail[rail_solution_stack[temp_stack_pointer]].x;
+ unto_y = room->rail[rail_solution_stack[temp_stack_pointer]].y;
+ player.next_special_code = (buffer_legal(scr_special, room->xs,
+ from_x, from_y,
+ unto_x, unto_y) != LEGAL);
+ from_x = unto_x;
+ from_y = unto_y;
+ }
+}
+
+int player_add_stop_walker(int walker, int trigger) {
+ int error_flag = true;
+
+ if (walker >= series_list[player.series_base + player.series]->walker->num_secondary) goto done;
+
+ if (player.stop_walker_pointer < (PLAYER_MAX_STOP - 1)) {
+ player.stop_walker_pointer++;
+ player.stop_walker_stack[player.stop_walker_pointer] = walker;
+ player.stop_walker_trigger[player.stop_walker_pointer] = trigger;
+ error_flag = false;
+ }
+
+done:
+ return error_flag;
+}
+
+void player_walk(int x, int y, int facing) {
+ player_cancel_walk();
+ player.need_to_walk = true;
+ player.ready_to_walk = true;
+ player.prepare_walk_x = x;
+ player.prepare_walk_y = y;
+ player.prepare_walk_facing = facing;
+}
+
+void player_first_walk(int from_x, int from_y, int from_facing,
+ int to_x, int to_y, int to_facing,
+ int enable_at_target) {
+ player.x = from_x;
+ player.y = from_y;
+ player.facing = from_facing;
+
+ player_walk(to_x, to_y, to_facing);
+
+ player.walk_anywhere = true;
+
+ player.commands_allowed = false;
+ player.enable_at_target = enable_at_target;
+}
+
+void player_demand_facing(int facing) {
+ player.facing = facing;
+ player.turn_to_facing = facing;
+ player_select_series();
+}
+
+void player_demand_location(int x, int y) {
+ player_cancel_walk();
+ player.x = player.target_x = x;
+ player.y = player.target_y = y;
+}
+
+void player_walk_trigger(int trigger) {
+ int count;
+
+ player.walk_trigger = trigger;
+ player.walk_trigger_dest = (byte)kernel.trigger_setup_mode;
+ for (count = 0; count < 3; count++) {
+ player.walk_trigger_words[count] = player2.words[count];
+ }
+}
+
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/core/player.h b/engines/mads/madsv2/core/player.h
index 5d58faee07c..b2742f8ee59 100644
--- a/engines/mads/madsv2/core/player.h
+++ b/engines/mads/madsv2/core/player.h
@@ -22,7 +22,7 @@
#ifndef MADS_CORE_PLAYER_H
#define MADS_CORE_PLAYER_H
-#include "common/scummsys.h"
+#include "mads/madsv2/core/general.h"
namespace MADS {
namespace MADSV2 {
@@ -163,58 +163,173 @@ extern byte player_counter_clockwise[10];
#define player_said_3(aa, bb, cc) (player_parse (words_##aa, words_##bb, words_##cc, 0) )
-/* player_1.c */
-void player_new_stop_walker(void);
-void player_stationary_update(void);
-void player_set_facing(void);
-void player_set_final_facing(void);
-void player_select_series(void);
-void player_set_sprite(void);
-void player_keep_walking(void);
-int player_search_image(void);
-void player_set_image(void);
-
-/* player_2.c */
-int player_load_series(char *name);
-void player_himem_preload(char *name, int level);
-void player_dump_walker(void);
-void player_preserve_palette(void);
-
-/* player_3.c */
-void player_new_command(void);
-void player_new_walk(void);
-int player_parse(int vocab_word, ...);
-
-/* player_4.c */
-void player_cancel_walk(void);
-void player_cancel_command(void);
-
-/* player_5.c */
-int player_has_been_in_room(int id);
-void player_discover_room(int id);
-
-/* player_6.c */
-int player_has(int object_id);
-
-/* player_7.c */
-void player_clear_stop_walkers(void);
-void player_init(void);
-void player_start_walking(int walk_x, int walk_y,
- int walk_facing);
-
-/* player_7.c */
-int player_add_stop_walker(int walker, int trigger);
-void player_walk(int x, int y, int facing);
-void player_walk_trigger(int trigger);
-
-/* player_7.c */
-void player_demand_facing(int facing);
-void player_demand_location(int x, int y);
-
-/* player_7.c */
-void player_first_walk(int from_x, int from_y, int from_facing,
- int to_x, int to_y, int to_facing,
- int enable_at_target);
+/**
+ * Loads up the next designated sprite for the active stop walker sequence.
+ */
+extern void player_new_stop_walker();
+
+/**
+ * Player sprite update daemon for when the player is not walking.
+ * Inserts appropriate stop walker frames from the stop walker queue.
+ */
+extern void player_stationary_update();
+
+/**
+ * When the player is scheduled to move down a certain line,
+ * this routine determines which of the player's series should
+ * be used to represent his movement. (I.e. it decides which
+ * facing most closely approximates his actual direction of movement).
+ */
+extern void player_set_facing();
+
+/**
+ * When the player arrives at his destination, begin turning him
+ * to face any designated target facing.
+ */
+extern void player_set_final_facing();
+
+/**
+ * Loads up the walker control parameters for the currently
+ * active walker series (i.e. for the player's current facing)
+ */
+extern void player_select_series();
+
+/**
+ * Picks an appropriate sprite for the current player frame.
+ */
+extern void player_set_sprite();
+
+/**
+ * If the player is walking somewhere, this routine determines the
+ * proper motion for the current frame.
+ */
+extern void player_keep_walking();
+
+/**
+ * Digs through the image list to find the current player image.
+ */
+extern int player_search_image();
+
+/**
+ * Actually makes an image list entry for this frame's player sprite.
+ */
+extern void player_set_image();
+
+/**
+ * Loads a full set of player walkers into memory.
+ */
+extern int player_load_series(const char *name);
+
+/**
+ * Preloads a full set of player walkers to high memory.
+ */
+extern void player_himem_preload(const char *name, int level);
+
+extern void player_dump_walker();
+extern void player_preserve_palette();
+
+/**
+ * Accepts a new sentence from the interface routines; copies all
+ * the necessary data into the player data structure. Sets up
+ * structures and semaphores to process a brand new sentence. Checks
+ * to see if the player needs to walk anywhere based on the command
+ * he has issued.
+ */
+extern void player_new_command();
+
+/**
+ * If a new walk instruction is waiting, and has been cleared
+ * by the preparser, start the ball rolling.
+ */
+extern void player_new_walk();
+
+/**
+ * Returns true if the player's sentence contains all of the passed
+ * vocabulary word numbers (parameter list should be terminated with a 0).
+ */
+extern int player_parse(int vocab_word, ...);
+
+/**
+ * Aborts any ongoing player walk; stops him dead in his tracks.
+ */
+extern void player_cancel_walk();
+
+/**
+ * Cancels any currently outstanding player command sentence. The
+ * sentence will no longer be processed by parser code.
+ */
+extern void player_cancel_command();
+
+/**
+ * Returns true if the player has been in the specified room during the game.
+ */
+extern int player_has_been_in_room(int id);
+
+/**
+ * Makes a note of the fact that the player has been in the current
+ * room (so that henceforth the routine above will return true for this room).
+ */
+extern void player_discover_room(int id);
+
+/**
+ * Returns true if the player is carrying the specified object number.
+ * Negative(invalid) object numbers are permitted (they return false),
+ * so it is safe to form statements such as...
+ *
+ * if (player_has(object_named(player_main_noun))) {
+ *
+ * ...even though it cannot be guaranteed that player_main_noun
+ * actually names a valid object.
+ */
+extern int player_has(int object_id);
+
+/**
+ * Flushes the stop walker stack.
+ */
+extern void player_clear_stop_walkers();
+
+/**
+ * Initializes player data structures (for use at the beginning of the game).
+ */
+extern void player_init();
+
+/**
+ * Computes a rail solution for the player to walk to the
+ * designated location, and starts him walking there.
+ */
+extern void player_start_walking(int walk_x, int walk_y, int walk_facing);
+
+/**
+ * Add a stop walker to the current queue.
+ */
+extern int player_add_stop_walker(int walker, int trigger);
+
+/**
+ * Used by game code to request that the player walk to the
+ * designated location as soon as possible. Should be used
+ * in preference to player_start_walking(), which bypasses
+ * several layers of checking.
+ */
+extern void player_walk(int x, int y, int facing);
+
+extern void player_walk_trigger(int trigger);
+
+/**
+ * Resets the player's facing.
+ */
+extern void player_demand_facing(int facing);
+
+extern void player_demand_location(int x, int y);
+
+/**
+ * Used at room init time to request that the player begin by performing
+ * the specified walk (usually from offscreen). Commands are disabled
+ * during the walk (because the player may be walking over walk code areas).
+ * If "enable_at_target" is true, player commands will be enabled once
+ * he reaches his target.
+ */
+extern void player_first_walk(int from_x, int from_y, int from_facing,
+ int to_x, int to_y, int to_facing, int enable_at_target);
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/core/rail.cpp b/engines/mads/madsv2/core/rail.cpp
new file mode 100644
index 00000000000..1a21252b2cd
--- /dev/null
+++ b/engines/mads/madsv2/core/rail.cpp
@@ -0,0 +1,114 @@
+/* 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 "mads/madsv2/core/general.h"
+#include "rail.h"
+#include "mads/madsv2/core/room.h"
+#include "mads/madsv2/core/buffer.h"
+#include "mads/madsv2/core/imath.h"
+#include "mads/madsv2/core/player.h"
+#include "mads/madsv2/core/error.h"
+#include "mads/madsv2/core/matte.h"
+#include "mads/madsv2/core/kernel.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+byte rail_active[ROOM_MAX_RAILS + 2];
+
+void rail_connect_node(int id) {
+ int count;
+ int x1, y1;
+ int x, y;
+ word legal;
+ word weight;
+
+ x = room->rail[id].x;
+ y = room->rail[id].y;
+
+ rail_active[id] = true;
+
+ for (count = 0; count < (int)rail_num_nodes; count++) {
+ if (count != id) {
+ if (rail_active[count] && rail_active[id]) {
+ x1 = room->rail[count].x;
+ y1 = room->rail[count].y;
+ if (player.walk_anywhere) {
+ legal = LEGAL;
+ } else {
+ legal = buffer_legal(scr_walk, room->xs, x, y, x1, y1);
+ }
+ weight = MIN(imath_hypot(abs(x1 - x), abs(y1 - y)), WEIGHT_MASK) | legal;
+ } else {
+ weight = WEIGHT_MASK | TOTALLY_ILLEGAL;
+ }
+ } else {
+ weight = WEIGHT_MASK | TOTALLY_ILLEGAL;
+ }
+ room->rail[count].weight[id] = weight;
+ room->rail[id].weight[count] = weight;
+ }
+}
+
+static void disconnector(int alpha, int beta) {
+ room->rail[alpha].weight[beta] = WEIGHT_MASK | TOTALLY_ILLEGAL;
+}
+
+void rail_disconnect_line(int from, int unto) {
+ disconnector(from, unto);
+ disconnector(unto, from);
+}
+
+void rail_disconnect_node(int id) {
+ int count;
+
+ rail_active[id] = false;
+
+ for (count = 0; count < (int)rail_num_nodes; count++) {
+ if (count != id) {
+ rail_disconnect_line(count, id);
+ }
+ }
+}
+
+void rail_add_node(int id, int x, int y) {
+ room->rail[id].x = x;
+ room->rail[id].y = y;
+
+ rail_active[id] = true;
+
+ rail_connect_node(id);
+}
+
+void rail_connect_all_nodes(void) {
+ int count;
+
+ for (count = 0; count < ROOM_MAX_RAILS + 2; count++) {
+ rail_active[count] = true;
+ }
+
+ for (count = 0; count < room->num_rails; count++) {
+ rail_connect_node(count);
+ }
+}
+
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/core/kernel_2.h b/engines/mads/madsv2/core/rail.h
similarity index 60%
rename from engines/mads/madsv2/core/kernel_2.h
rename to engines/mads/madsv2/core/rail.h
index 0dbffae97b8..fa492dfb752 100644
--- a/engines/mads/madsv2/core/kernel_2.h
+++ b/engines/mads/madsv2/core/rail.h
@@ -19,17 +19,30 @@
*
*/
-#ifndef MADS_CORE_KERNEL_2_H
-#define MADS_CORE_KERNEL_2_H
-
#include "mads/madsv2/core/general.h"
+#include "mads/madsv2/core/room.h"
namespace MADS {
namespace MADSV2 {
-extern int kernel_load_vocab();
+#define RAIL_MAX_NODES ROOM_MAX_RAILS + 2
+
+extern word rail_solution_stack_pointer;
+extern word rail_solution_stack_weight;
+
+extern byte rail_visited[RAIL_MAX_NODES];
+extern byte rail_working_stack[RAIL_MAX_NODES];
+extern byte rail_solution_stack[RAIL_MAX_NODES];
+
+extern word rail_num_nodes;
+extern byte *rail_base;
+
+extern void rail_add_node(int id, int x, int y);
+extern void rail_connect_node(int id);
+extern void rail_connect_all_nodes(void);
+extern void rail_disconnect_line(int from, int unto);
+extern void rail_disconnect_node(int id);
+extern void rail_check_path (int allow_one_illegal);
} // namespace MADSV2
} // namespace MADS
-
-#endif
diff --git a/engines/mads/madsv2/core/sprite.cpp b/engines/mads/madsv2/core/sprite.cpp
index 740152be5ad..2ea5f82c106 100644
--- a/engines/mads/madsv2/core/sprite.cpp
+++ b/engines/mads/madsv2/core/sprite.cpp
@@ -20,17 +20,26 @@
*/
#include "mads/madsv2/core/general.h"
+#include "mads/madsv2/core/sprite.h"
#include "mads/madsv2/core/mem.h"
#include "mads/madsv2/core/error.h"
#include "mads/madsv2/core/pal.h"
#include "mads/madsv2/core/env.h"
#include "mads/madsv2/core/loader.h"
-#include "mads/madsv2/core/sprite.h"
-#include "mads/madsv2/core/sprite_h.h"
+#include "mads/madsv2/core/ems.h"
+#include "mads/madsv2/core/xms.h"
+#include "mads/madsv2/core/fileio.h"
namespace MADS {
namespace MADSV2 {
+int sprite_error = 0;
+byte *sprite_force_memory = NULL;
+long sprite_force_size;
+byte color_table[7] = { 7, 246, 247, 248, 249, 250, 251 };
+int kidney = false;
+
+
// Disable Visual studio unreferenced local variables warnings
#pragma warning(push)
#pragma warning(disable: 4101)
@@ -63,7 +72,7 @@ void sprite_draw(SeriesPtr series, int id, Buffer *buf, int target_x, int target
#define interface false /* Interface OFF */
-void fastcall sprite_draw_scaled(SeriesPtr series, int id, Buffer *buf,
+void sprite_draw_scaled(SeriesPtr series, int id, Buffer *buf,
int target_x, int target_y, int scale_factor) {
#include "mads/madsv2/core/sprite_0.cpp"
}
@@ -121,7 +130,7 @@ void sprite_draw_3d_scaled_big(SeriesPtr series, int id, Buffer *buf, Buffer *at
#define interface false /* Interface OFF */
-void fastcall sprite_draw_3d_x16(SeriesPtr series, int id, Buffer *buf, Buffer *attr,
+void sprite_draw_3d_x16(SeriesPtr series, int id, Buffer *buf, Buffer *attr,
int target_x, int target_y, int target_depth) {
#include "mads/madsv2/core/sprite_0.cpp"
}
@@ -140,7 +149,7 @@ void fastcall sprite_draw_3d_x16(SeriesPtr series, int id, Buffer *buf, Buffer *
#define interface false /* Interface OFF */
-void fastcall sprite_draw_3d_scaled_x16(SeriesPtr series, int id,
+void sprite_draw_3d_scaled_x16(SeriesPtr series, int id,
Buffer *buf, Buffer *attr,
int target_x, int target_y, int target_depth,
int scale_factor) {
@@ -161,7 +170,7 @@ void fastcall sprite_draw_3d_scaled_x16(SeriesPtr series, int id,
#define interface false /* Interface OFF */
-void fastcall sprite_draw_3d_big_x16(SeriesPtr series, int id, Buffer *buf, Buffer *attr,
+void sprite_draw_3d_big_x16(SeriesPtr series, int id, Buffer *buf, Buffer *attr,
int target_x, int target_y, int target_depth,
int view_port_x, int view_port_y) {
#include "mads/madsv2/core/sprite_0.cpp"
@@ -181,7 +190,7 @@ void fastcall sprite_draw_3d_big_x16(SeriesPtr series, int id, Buffer *buf, Buff
#define interface false /* Interface OFF */
-void fastcall sprite_draw_3d_big_x16(SeriesPtr series, int id,
+void sprite_draw_3d_big_x16(SeriesPtr series, int id,
Buffer *buf, Buffer *attr, int target_x, int target_y, int target_depth,
int scale_factor, int view_port_x, int view_port_y) {
#include "mads/madsv2/core/sprite_0.cpp"
@@ -201,7 +210,7 @@ void fastcall sprite_draw_3d_big_x16(SeriesPtr series, int id,
#define interface false /* Interface OFF */
-void fastcall sprite_draw_x16(SeriesPtr series, int id, Buffer * buf,
+void sprite_draw_x16(SeriesPtr series, int id, Buffer * buf,
int target_x, int target_y) {
#include "mads/madsv2/core/sprite_0.cpp"
}
@@ -220,7 +229,7 @@ void fastcall sprite_draw_x16(SeriesPtr series, int id, Buffer * buf,
#define interface true /* Interface ON */
-void fastcall sprite_draw_interface(SeriesPtr series, int id, Buffer *buf,
+void sprite_draw_interface(SeriesPtr series, int id, Buffer *buf,
int target_x, int target_y) {
#include "mads/madsv2/core/sprite_0.cpp"
}
@@ -241,7 +250,7 @@ void fastcall sprite_draw_interface(SeriesPtr series, int id, Buffer *buf,
#define attribute true /* Draw to attribute */
-void fastcall sprite_draw_3d_scaled_to_attr
+void sprite_draw_3d_scaled_to_attr
(SeriesPtr series, int id,
Buffer *buf, Buffer *attr,
int target_x, int target_y, int target_depth,
@@ -266,7 +275,7 @@ void fastcall sprite_draw_3d_scaled_to_attr
#define monodraw true /* Draw mono color */
-void fastcall sprite_draw_3d_scaled_mono(SeriesPtr series, int id,
+void sprite_draw_3d_scaled_mono(SeriesPtr series, int id,
Buffer *buf, Buffer *attr, int target_x, int target_y, int target_depth,
int scale_factor, byte color) {
#include "mads/madsv2/core/sprite_0.cpp"
@@ -282,8 +291,842 @@ void fastcall sprite_draw_3d_scaled_mono(SeriesPtr series, int id,
//====================================================================
+SeriesPtr sprite_series_load(const char *filename, int load_flags) {
+ register int count;
+ int len;
+ int len2;
+ int found, low_color, color_pointer;
+ byte *base_pointer;
+ byte *sprite_marker;
+ char temp_buf[80];
+ char block_name[20];
+ char *mark;
+ long base_quantity, quantity;
+ long initial_quantity;
+ long total_color_size;
+ long largest_block;
+ long total_offset;
+ FileSeries header;
+ FileSpritePtr sprite = NULL;
+ SeriesPtr target = NULL;
+ SeriesPtr result = NULL;
+ SpritePageInfoPtr page_info;
+ SpritePageTablePtr page_table;
+ ColorListPtr color_list = NULL;
+ /* ColorList color_list; */
+ Load load_handle;
+
+ mem_last_alloc_loader = MODULE_SPRITE_LOADER;
+
+ load_handle.open = false;
+
+ Common::strcpy_s(temp_buf, filename);
+ if (strchr(temp_buf, '.') == NULL) {
+ Common::strcat_s(temp_buf, ".SS");
+ }
+
+ Common::strcpy_s(block_name, "S$");
+ mark = temp_buf;
+ mads_strupr(temp_buf);
+ if (*mark == '*') mark++;
+ if ((*mark == 'R') && (*(mark + 1) == 'M')) {
+ mark += 2;
+ }
+ strncat(block_name, mark, 6);
+
+
+ /* Open our input file */
+ if (loader_open(&load_handle, temp_buf, "rb", true)) {
+ sprite_error = SS_ERR_OPENFILE;
+ goto done;
+ }
+
+ /* Set default error condition */
+
+ sprite_error = SS_ERR_READFILE;
+
+ /* Determine length of header, and read it */
+
+ len = sizeof(FileSeries) - sizeof(FileSprite);
+
+ if (!loader_read(&header, len, 1, &load_handle)) goto done;
+
+ if (header.misc_is_a_walker) load_flags |= SPRITE_LOAD_WALKER_INFO;
+
+ /* Determine length of index record array */
+
+ len2 = sizeof(FileSprite) * header.num_sprites;
+
+ base_quantity = sizeof(Series) + (sizeof(Sprite) * (header.num_sprites - 1));
+ if (load_flags & SPRITE_LOAD_WALKER_INFO) {
+ base_quantity += sizeof(WalkerInfo);
+ }
+ initial_quantity = base_quantity;
+ if (header.pack_by_sprite) {
+ base_quantity += (SPRITE_COLOR_TABLE_SIZE + sizeof(SpritePageInfo) + (sizeof(SpritePageTable) * header.num_sprites));
+ }
+ quantity = base_quantity;
+
+ if (!(load_flags & SPRITE_LOAD_HEADER_ONLY)) {
+ if (!header.pack_by_sprite) {
+ quantity += header.total_data_size;
+ }
+ }
+
+ /* Allocate memory for entire series (target) and for the file-formatted */
+ /* index record array (sprite) */
+
+ if (sprite_force_memory != NULL) {
+ if (quantity <= sprite_force_size) {
+ target = (SeriesPtr)sprite_force_memory;
+ }
+ }
+
+ if (target == NULL) target = (SeriesPtr)mem_get_name(quantity, block_name);
+ if (target == NULL) {
+ sprite_error = SS_ERR_NOMOREMEMORY;
+ goto done;
+ }
+
+ sprite = (FileSpritePtr)mem_get_name(len2, "$sp-load");
+ if (sprite == NULL) {
+ sprite_error = SS_ERR_NOMOREMEMORY;
+ goto done;
+ }
+
+ target->walker = NULL;
+ target->color_table = NULL;
+ target->page_info = NULL;
+ target->page_table = NULL;
+ target->arena = NULL;
+
+ /* Read the index record array */
+
+ if (!loader_read(sprite, len2, 1, &load_handle)) {
+ sprite_error = SS_ERR_READFILE;
+ goto done;
+ }
+
+ /* Read the color list */
+
+ total_color_size = load_handle.pack.strategy[load_handle.pack_list_marker].size;
+
+ color_list = (ColorListPtr)mem_get_name(total_color_size, "$color$");
+ if (color_list == NULL) {
+ sprite_error = SS_ERR_NOMOREMEMORY;
+ goto done;
+ }
+
+ if (!loader_read(color_list, total_color_size, 1, &load_handle)) goto done;
+
+ /* Copy relevant header data to target header */
+
+ target->pack_by_sprite = header.pack_by_sprite;
+ target->delta_series = header.delta_series && (header.base_mode < SS_INDIVIDUAL);
+ target->base_mode = header.base_mode;
+ target->num_sprites = header.num_sprites;
+ target->offset_x_view = header.offset_x_view;
+ target->offset_y_view = header.offset_y_view;
+
+ for (count = 0; count < 16; count++) {
+ target->misc[count] = header.misc[count];
+ }
+
+ /* Copy walker information, if requested */
+
+ if (load_flags & SPRITE_LOAD_WALKER_INFO) {
+ target->walker = (WalkerInfoPtr)(((byte *)(target)) + (initial_quantity - sizeof(WalkerInfo)));
+ target->walker = (WalkerInfoPtr)mem_normalize(target->walker);
+ memcpy(target->walker, &header.walker, sizeof(WalkerInfo));
+ }
+
+ /* base_pointer points to the beginning of the memory block at which */
+ /* the sprite data will be loaded. */
+
+ base_pointer = (byte *) (((byte *)target) + base_quantity);
+ base_pointer = (byte *)mem_normalize(base_pointer);
+ sprite_marker = base_pointer;
+
+ /* Set up the target index record for each sprite, including a pointer */
+ /* to the memory block designated for its sprite data. */
+
+ for (count = 0; count < target->num_sprites; count++) {
+ target->index[count].x = sprite[count].x;
+ target->index[count].y = sprite[count].y;
+ target->index[count].xs = sprite[count].xs;
+ target->index[count].ys = sprite[count].ys;
+ if (!(load_flags & SPRITE_LOAD_HEADER_ONLY) && !header.pack_by_sprite) {
+ target->index[count].data = sprite_marker;
+ sprite_marker = (byte *)mem_normalize(sprite_marker + sprite[count].memory_needed);
+ } else {
+ target->index[count].data = NULL;
+ }
+ }
+
+ /* Load all of the sprite data in at the base address */
+
+ if (!(load_flags & SPRITE_LOAD_HEADER_ONLY) && !header.pack_by_sprite) {
+ if (!loader_read(base_pointer, header.total_data_size, 1, &load_handle)) goto done;
+ }
+
+ /* Perform palette allocation and color list transformation */
+
+ if (load_flags & (SPRITE_LOAD_TRANSLATE | SPRITE_LOAD_SPINNING_OBJECT)) {
+ target->color_handle = 0;
+ if (load_flags & (SPRITE_LOAD_SPINNING_OBJECT)) {
+ color_pointer = 0;
+ for (count = 0; count < color_list->num_colors; count++) {
+ found = false;
+ for (low_color = 0; !found && (low_color < 4); low_color++) {
+ if (memcmp(&color_list->table[count].r, &master_palette[low_color].r, sizeof(RGBcolor)) == 0) {
+ found = true;
+ color_list->table[count].x16 = (byte)low_color;
+ }
+ }
+ if (!found) {
+ memcpy(&master_palette[color_table[color_pointer]].r,
+ &color_list->table[count].r, sizeof(RGBcolor));
+ color_list->table[count].x16 = (byte)color_table[color_pointer];
+ color_pointer = MIN(6, color_pointer + 1);
+ }
+ }
+ sprite_color_translate(target, color_list);
+ }
+ } else {
+
+ target->color_handle = pal_allocate(color_list, master_shadow, load_flags & PAL_MAP_MASK);
+ if (target->color_handle < 0) {
+ sprite_error = SS_ERR_TOOMANYCOLORS;
+ goto done;
+ }
+
+ if (!(load_flags & SPRITE_LOAD_HEADER_ONLY) && !header.pack_by_sprite) {
+ sprite_color_translate(target, color_list);
+ }
+ }
+
+ /* If series was packed by sprite (and we are therefore expected to */
+ /* stream-load it), we need to set up paging tables for the series. */
+ /* This process is different depending on whether the sprite data */
+ /* is to be loaded from disk or from the EMS preload area. */
+
+ if (header.pack_by_sprite) {
+ target->color_table = ((byte *)target) + initial_quantity;
+ page_info = target->page_info = (SpritePageInfoPtr)(((byte *)target->color_table) + SPRITE_COLOR_TABLE_SIZE);
+ page_table = target->page_table = (SpritePageTablePtr)(((byte *)page_info) + sizeof(SpritePageInfo));
+
+ for (count = 0; count < color_list->num_colors; count++) {
+ target->color_table[count] = color_list->table[count].x16;
+ }
+
+ page_info->packing_mode = header.compression;
+ page_info->paging_source = (byte)load_handle.mode;
+
+ if ((page_info->paging_source == LOADER_EMS) ||
+ (page_info->paging_source == LOADER_XMS)) {
+ page_info->ems_handle = load_handle.ems_handle;
+ page_info->ems_page_marker = load_handle.ems_page_marker;
+ page_info->ems_page_offset = load_handle.ems_page_offset;
+ page_info->xms_handle = load_handle.xms_handle;
+ page_info->xms_offset = load_handle.xms_offset;
+ largest_block = 0;
+ total_offset = 0;
+ for (count = 0; count < target->num_sprites; count++) {
+ page_table[count].file_offset = total_offset;
+ page_table[count].memory_needed = sprite[count].memory_needed;
+ total_offset += page_table[count].memory_needed;
+ largest_block = MAX(largest_block, page_table[count].memory_needed);
+ }
+ } else {
+ page_info->handle = load_handle.handle;
+ total_offset = load_handle.handle->pos();
+ page_info->base_sprite_offset = total_offset;
+
+ largest_block = 0;
+ for (count = 0; count < target->num_sprites; count++) {
+ page_table[count].file_offset = sprite[count].file_offset;
+ page_table[count].memory_needed = sprite[count].memory_needed;
+ largest_block = MAX(largest_block, page_table[count].memory_needed);
+ }
+ }
+
+ if (!(load_flags & SPRITE_LOAD_HEADER_ONLY)) {
+ if (color_list != NULL) mem_free(color_list);
+ color_list = NULL;
+
+ if (sprite != NULL) mem_free(sprite);
+ sprite = NULL;
+
+ target->arena = (byte *)mem_get_name(largest_block, "$arena$");
+ if (target->arena == NULL) goto done;
+
+ memcpy(&target->misc_largest_block, &largest_block, sizeof(long));
+
+ load_handle.open = false; /* Hack handle so it won't get closed */
+ } else {
+ target->arena = NULL;
+ }
+ }
+
+ result = target;
+
+done:
+ if (load_handle.open) loader_close(&load_handle);
+ if (color_list != NULL) mem_free(color_list);
+ if (sprite != NULL) mem_free(sprite);
+ if ((target != NULL) && (target != (SeriesPtr)sprite_force_memory) && (result == NULL)) mem_free(target);
+
+ return (result);
+}
+
+void sprite_get_scaled_matte(SeriesPtr series, int id, int target_x, int target_y,
+ int scale_factor, SpritePtr matte) {
+ word xs, ys;
+ SpritePtr sprite;
+
+ sprite = &series->index[id - 1];
+
+ xs = sprite->xs;
+ ys = sprite->ys;
+
+ xs = ((xs * scale_factor) + 50) / 100;
+ ys = ((ys * scale_factor) + 50) / 100;
+
+ matte->xs = xs;
+ matte->ys = ys;
+
+ matte->x = target_x - (xs >> 1);
+ matte->y = (target_y - ys) + 1;
+}
+
+word sprite_pack_line_rle(byte *target, Buffer *source, byte *palette_map, byte transparent, int x1, int x2, int y) {
+ byte run_byte, run_len;
+ byte *from;
+ byte *unto;
+ byte b;
+ int a, rec, lastpel;
+
+ unto = target;
+ run_byte = SS_IRLE; /* Shouldn't match ANY pixels, forces ... */
+ /* start of new run with first pixel. */
+ run_len = 0;
+
+ /* find logical end of line */
+ from = (byte *)(source->data + x2 + y * source->x);
+ for (lastpel = x2; lastpel >= x1; lastpel--, from--)
+ if (*from != transparent)
+ break;
+ lastpel++;
+
+ if (lastpel == x1) /* If no pels on line, don't even mark line type */
+ {
+ *(unto++) = SS_EOL;
+ return((word)(unto - target));
+ }
+
+ *(unto++) = SS_RLE; /* Mark as a RLE type line */
+
+ from = (byte *) (source->data + x1 + y * source->x);
+ for (a = x1; a <= x2; a++, from++) {
+ /* if no more real pixels */
+ if (a == lastpel) {
+ *(unto++) = run_len;
+ *(unto++) = run_byte;
+ *(unto++) = SS_EOL;
+ return ((word)(unto - target));
+ }
+
+ b = *from;
+
+ if (b == transparent) {
+ rec = SS_SKIP;
+ } else {
+ rec = palette_map[b]; /* Translate to relative color */
+ }
+
+ b = (byte)rec;
+
+ /* if a new byte, write run and clear */
+ if (b != run_byte) {
+ /* if run exists, write it */
+ if (run_len > 0) {
+ *(unto++) = run_len;
+ *(unto++) = run_byte;
+ }
+ run_byte = b; /* set up for new run */
+ run_len = 1;
+ } else {
+ /* if same byte as current run */
+ /* if MAX len, write and reset */
+ if (run_len == SS_LASTVALID) {
+ *(unto++) = run_len;
+ *(unto++) = run_byte;
+ run_len = 0;
+ }
+ run_len++;
+ }
+ }
+ *(unto++) = run_len;
+ *(unto++) = run_byte;
+ *(unto++) = SS_EOL;
+
+ return (word)(unto - target);
+}
+
+word sprite_pack_line_irle(byte *target, Buffer *source, byte *palette_map, byte transparent, int x1, int x2, int y) {
+ byte run_byte, run_len;
+ byte *from, *from1;
+ byte *unto; /* 'TO' is reserved word in other languages */
+ byte b;
+ int a, rec, lastpel;
+
+ unto = target;
+ run_byte = SS_IRLE; /* Shouldn't match ANY pixels, forces ... */
+ /* start of new run with first pixel. */
+ run_len = 0;
+
+ /* find logical end of line */
+ from1 = from = (byte *)(source->data + x2 + y * source->x);
+
+ for (lastpel = x2; lastpel >= x1; lastpel--, from--)
+ if (*from != transparent)
+ break;
+ lastpel++;
+
+ /* If no pels on line, don't even mark line type */
+ if (lastpel == x1) {
+ *(unto++) = SS_EOL;
+ return((word)(unto - target));
+ }
+
+ *(unto++) = SS_IRLE; /* Mark as an IRLE type line */
+
+ from = (byte *)(source->data + x1 + y * source->x);
+ for (a = x1; a <= x2; a++, from++) {
+ /* if no more real pixels */
+ if (a == lastpel) {
+ switch (run_len) {
+ case 3: *(unto++) = run_byte;
+ case 2: *(unto++) = run_byte;
+ case 1: *(unto++) = run_byte; break;
+ default:
+ *(unto++) = SS_RUN; /* mark as a run */
+ *(unto++) = run_len;
+ *(unto++) = run_byte;
+ }
+ *(unto++) = SS_EOL;
+ return (word)(unto - target);
+ }
+
+ b = *from;
+
+ if (b == transparent)
+ rec = SS_SKIP;
+ else
+ rec = palette_map[b]; /* Translate to relative color */
+
+ b = (byte)rec;
+
+ /* if a new byte, write run and clear */
+ if (b != run_byte) {
+ /* if run exists, write it */
+ if (run_len > 0) {
+ switch (run_len) {
+ case 3: *(unto++) = run_byte;
+ case 2: *(unto++) = run_byte;
+ case 1: *(unto++) = run_byte; break;
+ default:
+ *(unto++) = SS_RUN; /* mark as a run */
+ *(unto++) = run_len;
+ *(unto++) = run_byte;
+ }
+ }
+
+ run_byte = b; /* set up for new run */
+ run_len = 1;
+ } else {
+ /* if same byte as current run */
+ if (run_len == SS_LASTVALID) {
+ /* if MAX len, write and reset */
+ *(unto++) = SS_RUN;
+ *(unto++) = run_len;
+ *(unto++) = run_byte;
+ run_len = 0;
+ }
+
+ run_len++;
+ }
+ }
+
+ switch (run_len) {
+ case 3: *(unto++) = run_byte; /* intentional fall-through */
+ case 2: *(unto++) = run_byte;
+ case 1: *(unto++) = run_byte; break;
+ default:
+ *(unto++) = SS_RUN; /* mark as a run */
+ *(unto++) = run_len;
+ *(unto++) = run_byte;
+ }
+
+ *(unto++) = SS_EOL;
+ *from1 = 15;
+
+ return (word)(unto - target);
+}
+
+void sprite_set_bounds(HagSpritePtr sprite, int x, int y, int xs, int ys) {
+ sprite->x = x;
+ sprite->y = y;
+ sprite->xs = xs;
+ sprite->ys = ys;
+}
+
+void sprite_merge_background(Buffer *source, Buffer *background, byte transparent) {
+ byte *source_ptr = source->data;
+ byte *delta_ptr = background->data;
+ word total_size = (word)source->x * (word)source->y;
+
+ for (word i = 0; i < total_size; i++) {
+ if (source_ptr[i] == transparent) {
+ byte bg = delta_ptr[i];
+ if (bg != (byte)-1)
+ source_ptr[i] = bg;
+ }
+ }
+}
+
+void sprite_delta_compute(HagSpritePtr sprite, Buffer *source, Buffer *delta) {
+ int ul_x = 10000, ul_y = 10000;
+ int lr_x = -1, lr_y = -1;
+ int wrap = source->x;
+ int done = source->y;
+ byte *source_ptr = source->data;
+ byte *delta_ptr = delta->data;
+
+ for (int y = 0; y < done; y++) {
+ for (int x = 0; x < wrap; x++) {
+ int i = y * wrap + x;
+ byte src = source_ptr[i];
+ byte dlt = delta_ptr[i];
+
+ if (src != dlt) {
+ delta_ptr[i] = src;
+ source_ptr[i] = COLOR_TRANSPARENT;
+
+ if (x < ul_x) ul_x = x;
+ if (x > lr_x) lr_x = x;
+ if (y < ul_y) ul_y = y;
+ if (y > lr_y) lr_y = y;
+ }
+ }
+ }
+
+ if (ul_x > (wrap - 1)) {
+ ul_x = ul_y = 0;
+ lr_x = lr_y = -1;
+ }
+ sprite->x = ul_x;
+ sprite->xs = (lr_x - ul_x) + 1;
+ sprite->y = ul_y;
+ sprite->ys = (lr_y - ul_y) + 1;
+}
+
+void sprite_remove_non_delta(Buffer *source, Buffer *delta, byte transparent) {
+ byte *source_ptr = source->data;
+ byte *delta_ptr = delta->data;
+ int total_size = source->x * source->y;
+
+ for (int i = 0; i < total_size; i++) {
+ byte src = source_ptr[i];
+ byte dlt = delta_ptr[i];
+
+ if (src != dlt)
+ delta_ptr[i] = src;
+ else
+ source_ptr[i] = transparent;
+ }
+}
+
+long sprite_pack_image(byte *target, FileSpritePtr sprite, Buffer *source, byte *palette_map, byte transparent) {
+ word size1, size2;
+ byte buf1[2048];
+ byte buf2[1024];
+ byte *target_ptr;
+ int count_y;
+ int x, y, xs, ys;
+ long out;
+
+ target_ptr = target;
+ out = 0;
+
+ x = sprite->x;
+ y = sprite->y;
+ xs = sprite->xs;
+ ys = sprite->ys;
+
+ for (count_y = y; count_y < y + ys; count_y++) {
+ size1 = sprite_pack_line_rle(buf1, source, palette_map, transparent, x, x + xs - 1, count_y);
+ size2 = sprite_pack_line_irle(buf2, source, palette_map, transparent, x, x + xs - 1, count_y);
+
+ if (size1 < size2) {
+ memcpy(target_ptr, buf1, size1);
+ target_ptr += size1;
+ out += size1;
+ } else {
+ memcpy(target_ptr, buf2, size2);
+ target_ptr += size2;
+ out += size2;
+ }
+ }
+
+ *(target_ptr++) = SS_EOI;
+ out++;
+
+ return out;
+}
+
+void sprite_color_translate(SeriesPtr series, ColorListPtr list) {
+ byte *table = &list->table[0].x16;
+
+ for (int id = 0; id < series->num_sprites; id++) {
+ byte *scan = series->index[id].data;
+ if (scan == NULL)
+ goto done;
+
+ while (1) { /* scan_main_loop */
+ byte ctrl = *scan++;
+
+ if (ctrl == SS_EOI) break; /* scan_finished */
+ if (ctrl == SS_EOL) continue; /* scan_main_loop */
+
+ if (ctrl == SS_RLE) {
+ /* scan_rle_main_loop */
+ while (1) {
+ byte len = *scan++;
+ if (len == SS_EOL)
+ break; /* back to scan_main_loop */
+
+ if (*scan != SS_SKIP) {
+ byte color = *scan;
+ int idx = color * 6;
+ *scan = table[idx];
+ }
+ scan++;
+ }
+ continue;
+ }
+
+ /* scan_irle_main_loop */
+ while (1) {
+ byte b = *scan;
+
+ if (b == SS_EOL) {
+ scan++; /* scan_irle_finished: consume EOL and return to outer */
+ break;
+ }
+
+ if (b == SS_RUN) {
+ scan += 2; /* skip RUN marker and count */
+ b = *scan; /* get the run's color value */
+ }
+
+ if (b != SS_SKIP) {
+ int idx = b * 6;
+ *scan = table[idx];
+ }
+ scan++;
+ }
+ }
+ }
+
+done:
+ ;
+}
+
+void sprite_single_color_translate(SeriesPtr series, int id) {
+ id -= 1;
+ byte *table = series->color_table;
+ byte *scan = series->index[id].data;
+ if (scan == NULL)
+ goto done;
+
+ while (1) { /* scan_main_loop */
+ byte ctrl = *scan++;
+
+ if (ctrl == SS_EOI) break;
+ if (ctrl == SS_EOL) continue;
+
+ if (ctrl == SS_RLE) {
+ while (1) {
+ byte len = *scan++;
+ if (len == SS_EOL)
+ break;
+
+ if (*scan != SS_SKIP)
+ *scan = table[*scan];
+ scan++;
+ }
+ continue;
+ }
+
+ /* IRLE */
+ while (1) {
+ byte b = *scan;
+
+ if (b == SS_EOL) {
+ scan++;
+ break;
+ }
+
+ if (b == SS_RUN) {
+ scan += 2;
+ b = *scan;
+ }
+
+ if (b != SS_SKIP)
+ *scan = table[b];
+ scan++;
+ }
+ }
+
+done:
+ ;
+}
+
+int sprite_data_load(SeriesPtr series, int id, byte *target) {
+ int error_flag = true;
+ int ems_page_marker = -1;
+ int ems_page_offset;
+ int count;
+ int already_unpacked = false;
+ long my_offset;
+ long my_ems_marker;
+ long my_ems_offset;
+ long decompress_size;
+ byte *decompress_buffer = NULL;
+ SpritePageInfoPtr page_info;
+ SpritePageTablePtr page_table;
+
+ id -= 1;
+
+ page_info = series->page_info;
+ page_table = series->page_table;
+
+ if (page_table[id].memory_needed == 0) goto ok;
+
+ if (page_info->paging_source == LOADER_EMS) {
+ my_offset = page_table[id].file_offset;
+ my_ems_marker = my_offset / EMS_PAGE_SIZE;
+ my_ems_offset = my_offset - (my_ems_marker * EMS_PAGE_SIZE);
+ for (count = 0; count < (int)my_ems_marker; count++) {
+ ems_page_marker = ems_next_handle_page(page_info->ems_handle, ems_page_marker);
+ }
+ ems_page_offset = (int)my_ems_offset + page_info->ems_page_offset;
+ if (ems_page_offset >= EMS_PAGE_SIZE) {
+ ems_page_offset -= EMS_PAGE_SIZE;
+ ems_page_marker = ems_next_handle_page(page_info->ems_handle, ems_page_marker);
+ }
+
+ if (!ems_copy_it_down(page_info->ems_handle,
+ &ems_page_marker,
+ &ems_page_offset,
+ target,
+ page_table[id].memory_needed)) goto done;
+ } else if (page_info->paging_source == LOADER_XMS) {
+ my_offset = page_table[id].file_offset;
+ if (!xms_copy(page_table[id].memory_needed,
+ page_info->xms_handle, (XMS)(page_info->xms_offset + my_offset),
+ MEM_CONV, target)) goto done;
+ } else {
+ my_offset = page_info->base_sprite_offset +
+ page_table[id].file_offset;
+
+ fileio_setpos(page_info->handle, my_offset);
+
+ pack_strategy = (page_info->packing_mode == PACK_EXPLODE) ? PACK_PFAB : PACK_NONE;
+
+ if (id < series->num_sprites - 1) {
+ decompress_size = page_table[id + 1].file_offset - page_table[id].file_offset;
+ decompress_buffer = (byte *)mem_get_name(decompress_size, "$sp_data");
+ if (decompress_buffer != NULL) {
+ if (!fileio_fread_f(decompress_buffer, decompress_size, 1, page_info->handle)) goto done;
+
+ if (pack_data(page_info->packing_mode, page_table[id].memory_needed,
+ FROM_MEMORY, decompress_buffer,
+ TO_MEMORY, target) != page_table[id].memory_needed) goto done;
+
+ mem_free(decompress_buffer);
+ decompress_buffer = NULL;
+
+ already_unpacked = true;
+ }
+ }
+
+ if (!already_unpacked) {
+ if (pack_data(page_info->packing_mode, page_table[id].memory_needed,
+ FROM_DISK, page_info->handle,
+ TO_MEMORY, target) != page_table[id].memory_needed) goto done;
+ }
+ }
+
+ok:
+ series->index[id].data = target;
+
+ sprite_single_color_translate(series, id + 1);
+
+ error_flag = false;
+
+done:
+ if (decompress_buffer != NULL) mem_free(decompress_buffer);
+ return (error_flag);
+}
+
+
+void dont_frag_the_palette(void) {
+ /* this will tell sprite_free to not execute pal_deallocate. This will */
+ /* make it so the colors are not freed and you won't get the */
+ /* palette fragging. */
+
+ kidney = true;
+}
+
+void go_ahead_and_frag_the_palette(void) {
+ kidney = false;
+}
+
+void sprite_free(SeriesPtr *series, int free_memory) {
+ if (*series == NULL) goto done;
+
+ if ((*series)->pack_by_sprite) {
+ if ((*series)->page_info->paging_source == LOADER_DISK) {
+ delete (*series)->page_info->handle;
+ }
+ if ((*series)->arena != NULL) {
+ if (free_memory)
+ mem_free((*series)->arena);
+ }
+ }
+
+ if (kidney) {
+ /* release the flag - dont deallocate the colors from the list */
+ if ((*series)->color_handle)
+ pal_deallocate((*series)->color_handle);
+ /* flag_used[(*series)->color_handle] = false; */
+ } else {
+ /* deallocate the colors from the list */
+ if ((*series)->color_handle)
+ pal_deallocate((*series)->color_handle);
+ }
+
+ if (free_memory)
+ mem_free(*series);
+ *series = NULL;
+
+done:
+ ;
+}
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/core/sprite.h b/engines/mads/madsv2/core/sprite.h
index f9db894fe63..cdd32a0e725 100644
--- a/engines/mads/madsv2/core/sprite.h
+++ b/engines/mads/madsv2/core/sprite.h
@@ -282,148 +282,96 @@ typedef Series *SeriesPtr;
extern byte *sprite_force_memory;
extern long sprite_force_size;
-
-/* sprite_1.cpp */
-void sprite_draw(SeriesPtr series, int id, Buffer *buf,
- int target_x, int target_y);
+extern int sprite_error;
-/* sprite_2.cpp */
+void sprite_draw(SeriesPtr series, int id, Buffer *buf, int target_x, int target_y);
void sprite_draw_scaled(SeriesPtr series, int id, Buffer *buf,
int target_x, int target_y, int scale_factor);
-
-
-/* sprite_3.cpp */
-void sprite_draw_3d_scaled(SeriesPtr series, int id,
- Buffer *buf, Buffer *attr,
- int target_x, int target_y,
- int target_depth, int scale_factor);
-
-/* sprite_4.cpp */
-void sprite_draw_3d_big(SeriesPtr series, int id,
- Buffer *buf, Buffer *attr,
- int target_x, int target_y, int target_depth,
+void sprite_draw_3d_scaled(SeriesPtr series, int id, Buffer *buf, Buffer *attr,
+ int target_x, int target_y, int target_depth, int scale_factor);
+void sprite_draw_3d_big(SeriesPtr series, int id, Buffer *buf, Buffer *attr,
+ int target_x, int target_y, int target_depth, int view_port_x, int view_port_y);
+void sprite_draw_3d_scaled_big(SeriesPtr series, int id, Buffer *buf, Buffer *attr,
+ int target_x, int target_y, int target_depth, int scale_factor,
int view_port_x, int view_port_y);
-
-
-/* sprite_5.cpp */
-void sprite_draw_3d_scaled_big(SeriesPtr series, int id,
- Buffer *buf, Buffer *attr,
- int target_x, int target_y,
- int target_depth, int scale_factor,
- int view_port_x, int view_port_y);
-
-/* sprite_6.cpp */
-void sprite_draw_3d_x16(SeriesPtr series, int id,
- Buffer *buf, Buffer *attr,
+void sprite_draw_3d_x16(SeriesPtr series, int id, Buffer *buf, Buffer *attr,
int target_x, int target_y, int target_depth);
-
-/* sprite_7.cpp */
-void sprite_draw_3d_scaled_x16(SeriesPtr series, int id,
- Buffer *buf, Buffer *attr,
- int target_x, int target_y,
- int target_depth, int scale_factor);
-
-
-/* sprite_8.cpp */
-void sprite_draw_3d_big_x16(SeriesPtr series, int id,
- Buffer *buf, Buffer *attr,
- int target_x, int target_y, int target_depth,
+void sprite_draw_3d_scaled_x16(SeriesPtr series, int id, Buffer *buf, Buffer *attr,
+ int target_x, int target_y, int target_depth, int scale_factor);
+void sprite_draw_3d_big_x16(SeriesPtr series, int id, Buffer *buf, Buffer *attr,
+ int target_x, int target_y, int target_depth, int view_port_x, int view_port_y);
+void sprite_draw_3d_scaled_big_x16(SeriesPtr series, int id, Buffer *buf, Buffer *attr,
+ int target_x, int target_y, int target_depth, int scale_factor,
int view_port_x, int view_port_y);
-
-
-/* sprite_9.cpp */
-void sprite_draw_3d_scaled_big_x16(SeriesPtr series, int id,
- Buffer *buf, Buffer *attr,
- int target_x, int target_y,
- int target_depth, int scale_factor,
+void sprite_draw_x16(SeriesPtr series, int id, Buffer *buf, int target_x, int target_y);
+void sprite_draw_interface(SeriesPtr series, int id, Buffer *buf, int target_x, int target_y);
+void sprite_draw_3d_scaled_to_attr(SeriesPtr series, int id, Buffer *buf, Buffer *attr,
+ int target_x, int target_y, int target_depth, int scale_factor,
int view_port_x, int view_port_y);
-
-
-/* sprite_a.cpp */
-void sprite_draw_x16(SeriesPtr series, int id, Buffer *buf,
- int target_x, int target_y);
-
-
-/* sprite_b.cpp */
-void sprite_draw_interface(SeriesPtr series, int id,
- Buffer *buf,
- int target_x, int target_y);
-
-
-/* sprite_c.cpp */
-void sprite_draw_3d_scaled_to_attr
-(SeriesPtr series, int id,
- Buffer *buf, Buffer *attr,
- int target_x, int target_y, int target_depth,
- int scale_factor, int view_port_x, int view_port_y);
-
-
-/* sprite_d.cpp */
-void sprite_draw_3d_scaled_mono
-(SeriesPtr series, int id,
- Buffer *buf, Buffer *attr,
- int target_x, int target_y, int target_depth,
- int scale_factor, byte color);
-
-
-/* sprite_e.cpp */
+void sprite_draw_3d_scaled_mono(SeriesPtr series, int id, Buffer *buf, Buffer *attr,
+ int target_x, int target_y, int target_depth, int scale_factor, byte color);
SeriesPtr sprite_series_load(const char *filename, int load_flags);
-
-extern int sprite_error;
-
-
-/* sprite_f.cpp */
-void sprite_get_scaled_matte(SeriesPtr series, int id,
- int target_x, int target_y,
+void sprite_get_scaled_matte(SeriesPtr series, int id, int target_x, int target_y,
int scale_factor, SpritePtr matte);
-
-/* sprite_g.cpp */
-word sprite_pack_line_rle(byte *target, Buffer *source,
- byte *palette_map, byte transparent,
+/**
+ * Packs line (read from source) to buffer pointer to by BUF,
+ * and returns size. X1,X2 and Y are line on screen to read.
+ * "Transparent" defines the background "skip" color. "Palette_map"
+ * defines the palette-to-color-list mappings.
+ */
+word sprite_pack_line_rle(byte *target, Buffer *source, byte *palette_map, byte transparent,
int x1, int x2, int y);
+/**
+ * Packs line (read from source) to buffer pointer to by BUF,
+ * and returns size. X1,X2 and Y are line of buffer to read.
+ * "Transparent" defines transparent color (instances of which
+ * are converted to "SS_SKIP"). "Palette_map" defines the
+ * palette-to-color-list mappings for the series.
+ */
word sprite_pack_line_irle(byte *target, Buffer *source,
- byte *palette_map, byte transparent,
- int x1, int x2, int y);
-
-void sprite_set_bounds(HagSpritePtr sprite, int x, int y,
- int xs, int ys);
-
-void sprite_merge_background(Buffer *source, Buffer *background,
- byte transparent);
+ byte *palette_map, byte transparent, int x1, int x2, int y);
-void sprite_delta_compute(HagSpritePtr sprite,
- Buffer *source, Buffer *delta);
+void sprite_set_bounds(HagSpritePtr sprite, int x, int y, int xs, int ys);
-void sprite_remove_non_delta(Buffer *source, Buffer *delta,
- byte transparent);
+/**
+ * Given a foreground buffer and a background buffer, merges
+ * background image into transparent areas of foreground image.
+ */
+void sprite_merge_background(Buffer *source, Buffer *background, byte transparent);
+
+/**
+ * Finds differences between "source" and "delta" buffers. When pixels
+ * are different, "source" pixel is copied down to "delta" buffer (to
+ * prepare buffer for next round), and "source" buffer is whited out
+ * to show changes. "sprite"'s boundaries are set to conform to minimum
+ * rectangle needed to contain all changes.
+ */
+void sprite_delta_compute(HagSpritePtr sprite, Buffer *source, Buffer *delta);
-long sprite_pack_image(byte *target,
- FileSpritePtr sprite,
- Buffer *source,
- byte *palette_map,
- byte transparent);
+/**
+ * Compares "source" and "delta" buffers. If a pixel is the same,
+ * "source" buffer is changed to "transparent"; if pixel is different,
+ * "source" pixel is copied to "delta" pixel, which prepares the delta
+ * buffer for use on next round.
+ */
+void sprite_remove_non_delta(Buffer *source, Buffer *delta, byte transparent);
+/**
+ * Given sprite, packs it and writes it to buffer target.
+ * Returns # of bytes output.
+ */
+long sprite_pack_image(byte *target, FileSpritePtr sprite, Buffer *source,
+ byte *palette_map, byte transparent);
-/* sprite_h.cpp */
void sprite_color_translate(SeriesPtr series, ColorListPtr list);
-
-/* sprite_i.cpp */
void sprite_single_color_translate(SeriesPtr series, int id);
-
-/* sprite_j.cpp */
int sprite_data_load(SeriesPtr series, int id, byte *target);
-/* sprite_k.cpp */
-/* if called, wont remove the colors from the palette list. It is */
-/* used during kernel_abort_animation. */
-void dont_frag_the_palette(void);
-/* this will be called from the end of kernel_abort_animation to */
-/* make it so the colors will be freed from the palette. */
-void go_ahead_and_frag_the_palette(void);
-
+void dont_frag_the_palette();
+void go_ahead_and_frag_the_palette();
void sprite_free(SeriesPtr *series, int free_memory);
} // namespace MADSV2
diff --git a/engines/mads/madsv2/core/video.h b/engines/mads/madsv2/core/video.h
index b3a645f37e0..985685b4cdd 100644
--- a/engines/mads/madsv2/core/video.h
+++ b/engines/mads/madsv2/core/video.h
@@ -27,7 +27,7 @@
namespace MADS {
namespace MADSV2 {
-extern int video_mode;
+extern byte video_mode;
/* video.asm */
void video_init(int mode, int set_mode);
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index 138f695b12c..5d062ae5573 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -61,6 +61,7 @@ MODULE_OBJS += \
forest/globals_forest.o \
madsv2/engine.o \
madsv2/core/buffer.o \
+ madsv2/core/camera.o \
madsv2/core/cycle.o \
madsv2/core/ems.o \
madsv2/core/error.o \
@@ -68,12 +69,7 @@ MODULE_OBJS += \
madsv2/core/font_1.o \
madsv2/core/himem.o \
madsv2/core/inter.o \
- madsv2/core/kernel_1.o \
- madsv2/core/kernel_3.o \
- madsv2/core/kernel_8.o \
- madsv2/core/kernel_b.o \
- madsv2/core/kernel_d.o \
- madsv2/core/kernel_f.o \
+ madsv2/core/kernel.o \
madsv2/core/matte.o \
madsv2/core/mcga.o \
madsv2/core/mem_2.o \
@@ -84,8 +80,10 @@ MODULE_OBJS += \
madsv2/core/object.o \
madsv2/core/pack_6.o \
madsv2/core/pal.o \
+ madsv2/core/player.o \
madsv2/core/popup.o \
madsv2/core/quote_1.o \
+ madsv2/core/rail.o \
madsv2/core/screen.o \
madsv2/core/speech.o \
madsv2/core/sprite.o \
Commit: 85daa9bf61c3fc4f9717d932f2936ab541a0290d
https://github.com/scummvm/scummvm/commit/85daa9bf61c3fc4f9717d932f2936ab541a0290d
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:19:05+10:00
Commit Message:
MADS: PHANTOM: Added more core files
Changed paths:
A engines/mads/madsv2/core/concat.h
A engines/mads/madsv2/core/cursor.cpp
A engines/mads/madsv2/core/cursor.h
A engines/mads/madsv2/core/dialog.cpp
A engines/mads/madsv2/core/env.cpp
A engines/mads/madsv2/core/font.cpp
A engines/mads/madsv2/core/hspot.cpp
A engines/mads/madsv2/core/keys.cpp
A engines/mads/madsv2/core/lbm.cpp
A engines/mads/madsv2/core/loader.cpp
A engines/mads/madsv2/core/magic.cpp
A engines/mads/madsv2/core/mem.cpp
A engines/mads/madsv2/core/mouse.cpp
A engines/mads/madsv2/core/pack.cpp
A engines/mads/madsv2/core/pfab.h
A engines/mads/madsv2/core/sort.cpp
A engines/mads/madsv2/core/tile.cpp
A engines/mads/madsv2/core/vocab.cpp
A engines/mads/madsv2/core/window.cpp
R engines/mads/madsv2/core/font_1.cpp
R engines/mads/madsv2/core/kernel_2.cpp
R engines/mads/madsv2/core/kernel_3.cpp
R engines/mads/madsv2/core/kernel_4.cpp
R engines/mads/madsv2/core/kernel_5.cpp
R engines/mads/madsv2/core/kernel_6.cpp
R engines/mads/madsv2/core/kernel_7.cpp
R engines/mads/madsv2/core/kernel_8.cpp
R engines/mads/madsv2/core/kernel_9.cpp
R engines/mads/madsv2/core/kernel_a.cpp
R engines/mads/madsv2/core/kernel_b.cpp
R engines/mads/madsv2/core/kernel_c.cpp
R engines/mads/madsv2/core/kernel_d.cpp
R engines/mads/madsv2/core/kernel_e.cpp
R engines/mads/madsv2/core/kernel_f.cpp
R engines/mads/madsv2/core/kernel_g.cpp
R engines/mads/madsv2/core/kernel_h.cpp
R engines/mads/madsv2/core/kernel_i.cpp
R engines/mads/madsv2/core/kernel_j.cpp
R engines/mads/madsv2/core/kernel_k.cpp
R engines/mads/madsv2/core/kernel_l.cpp
R engines/mads/madsv2/core/kernel_m.cpp
R engines/mads/madsv2/core/kernel_n.cpp
R engines/mads/madsv2/core/kernel_o.cpp
R engines/mads/madsv2/core/kernel_q.cpp
R engines/mads/madsv2/core/kernel_r.cpp
R engines/mads/madsv2/core/mem_2.cpp
R engines/mads/madsv2/core/mouse_1.cpp
R engines/mads/madsv2/core/mouse_1.h
R engines/mads/madsv2/core/mouse_2.cpp
R engines/mads/madsv2/core/mouse_3.cpp
R engines/mads/madsv2/core/mouse_4.cpp
R engines/mads/madsv2/core/pack_1.h
R engines/mads/madsv2/core/pack_5.h
R engines/mads/madsv2/core/pack_6.cpp
R engines/mads/madsv2/core/pack_d.h
R engines/mads/madsv2/core/tile_3.cpp
R engines/mads/madsv2/core/vocab_8.cpp
R engines/mads/madsv2/core/vocab_8.h
engines/mads/madsv2/core/buffer.cpp
engines/mads/madsv2/core/dialog.h
engines/mads/madsv2/core/env.h
engines/mads/madsv2/core/fileio.cpp
engines/mads/madsv2/core/fileio.h
engines/mads/madsv2/core/font.h
engines/mads/madsv2/core/general.h
engines/mads/madsv2/core/himem.cpp
engines/mads/madsv2/core/himem.h
engines/mads/madsv2/core/hspot.h
engines/mads/madsv2/core/implode.h
engines/mads/madsv2/core/keys.h
engines/mads/madsv2/core/loader.h
engines/mads/madsv2/core/magic.h
engines/mads/madsv2/core/mem.h
engines/mads/madsv2/core/pack.h
engines/mads/madsv2/core/vocab.h
engines/mads/madsv2/core/window.h
engines/mads/madsv2/engine.cpp
engines/mads/madsv2/engine.h
engines/mads/module.mk
diff --git a/engines/mads/madsv2/core/buffer.cpp b/engines/mads/madsv2/core/buffer.cpp
index e12a6a1a53a..1464fcbd76c 100644
--- a/engines/mads/madsv2/core/buffer.cpp
+++ b/engines/mads/madsv2/core/buffer.cpp
@@ -22,6 +22,7 @@
#include "common/util.h"
#include "mads/madsv2/core/general.h"
#include "mads/madsv2/core/buffer.h"
+#include "mads/madsv2/core/ems.h"
#include "mads/madsv2/core/mem.h"
#include "mads/madsv2/core/room.h"
@@ -808,5 +809,60 @@ done:
;
}
+bool buffer_to_ems(Buffer *source, int page_handle, int source_ems_handle,
+ int x, int y, int xs, int ys) {
+ int special_page_handle = 0;
+ Buffer ems_buffer = { video_y, video_x, NULL };
+
+ if (page_handle < 0) {
+ page_handle = ems_get_page_handle(4);
+ special_page_handle = BUFFER_CREATED_PAGE_HANDLE;
+ }
+ if (page_handle < 0) {
+ goto done;
+ }
+
+ if (source_ems_handle < 0) {
+ ems_map_buffer(page_handle);
+ ems_buffer.data = ems_page[0];
+
+ buffer_rect_copy_2(*source, ems_buffer, x, y, x, y, xs, ys);
+ } else {
+ ems_buffer_to_buffer(source_ems_handle, page_handle);
+ }
+
+ page_handle |= special_page_handle;
+
+ ems_unmap_all();
+
+done:
+ return page_handle;
+}
+
+bool buffer_from_ems(Buffer *source, int page_handle, int target_ems_handle,
+ int x, int y, int xs, int ys) {
+ Buffer ems_buffer = { video_y, video_x, NULL };
+ int special_page_handle;
+
+ special_page_handle = page_handle & BUFFER_CREATED_PAGE_HANDLE;
+
+ page_handle &= ~(BUFFER_CREATED_PAGE_HANDLE);
+
+ if (target_ems_handle < 0) {
+ ems_map_buffer(page_handle);
+ ems_buffer.data = ems_page[0];
+
+ buffer_rect_copy_2(ems_buffer, *source, x, y, x, y, xs, ys);
+ } else {
+ ems_buffer_to_buffer(page_handle, target_ems_handle);
+ }
+
+ if (special_page_handle) ems_free_page_handle(page_handle);
+
+ ems_unmap_all();
+
+ return page_handle;
+}
+
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/core/vocab_8.h b/engines/mads/madsv2/core/concat.h
similarity index 67%
rename from engines/mads/madsv2/core/vocab_8.h
rename to engines/mads/madsv2/core/concat.h
index 8602ee07300..d312018a886 100644
--- a/engines/mads/madsv2/core/vocab_8.h
+++ b/engines/mads/madsv2/core/concat.h
@@ -19,25 +19,30 @@
*
*/
-#ifndef MADS_CORE_VOCAB_8_H
-#define MADS_CORE_VOCAB_8_H
+#ifndef MADS_CORE_CONCAT_H
+#define MADS_CORE_CONCAT_H
-#include "mads/madsv2/core/general.h"
+#include "common/scummsys.h"
namespace MADS {
namespace MADSV2 {
-extern void vocab_unload_active(); /* vocab_8.c */
-extern void vocab_init_active();
-extern int vocab_active_id(word id);
-extern int vocab_make_active(word id);
-extern int vocab_load_active();
-
-extern char *vocab_text;
-extern word vocab_size;
-extern word vocab_active;
-extern word vocab_list_id[VOCAB_MAX_ACTIVE];
-extern word vocab_list_pointer[VOCAB_MAX_ACTIVE];
+#define CONCAT_ID_STRING "MADSCONCAT 1.0\032"
+#define CONCAT_ID_LENGTH 16
+#define CONCAT_ID_CHECK 10
+
+#define CONCAT_EXT ".HAG"
+
+#define CONCAT_MAX_FILES 750
+#define CONCAT_MAX_OUT 10
+
+typedef struct {
+ long file_offset;
+ long file_size;
+ char name[13];
+} Concat;
+
+typedef Concat *ConcatPtr;
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/core/mouse_4.cpp b/engines/mads/madsv2/core/cursor.cpp
similarity index 58%
rename from engines/mads/madsv2/core/mouse_4.cpp
rename to engines/mads/madsv2/core/cursor.cpp
index 853a4840abb..5280a839e04 100644
--- a/engines/mads/madsv2/core/mouse_4.cpp
+++ b/engines/mads/madsv2/core/cursor.cpp
@@ -19,36 +19,43 @@
*
*/
-#include "mads/madsv2/core/general.h"
-#include "mads/madsv2/core/video.h"
-#include "mads/madsv2/core/mouse.h"
+#include "mads/madsv2/core/cursor.h"
+#include "mads/madsv2/core/screen.h"
namespace MADS {
namespace MADSV2 {
-extern Buffer scr_work;
+int cursor_mode; /* global cursor mode (insert/overwrite) */
+int cursor_follow = false;
+int text_x = 0, text_y = 0;
-void mouse_video_init() {
- mouse_set_work_buffer(scr_work.data, scr_work.x);
- mouse_set_view_port_loc(0, 0, scr_work.x - 1, scr_work.y - 1);
- mouse_set_view_port(0, 0);
+void cursor_set_size(short start, short finish) {
+ // No implementation
}
-void mouse_video_update(int from_x, int from_y, int unto_x, int unto_y,
- int size_x, int size_y) {
- int refresh_flag;
+void cursor_set_pos(short x, short y) {
+ // No implementation
+}
+
+void cursor_get_pos(int *x, int *y) {
+ *x = *y = 0;
+}
- mouse_freeze();
- refresh_flag = mouse_refresh_view_port();
+void cursor_set_mode(int my_type) {
+ // No implementation
+}
- video_update(&scr_work, from_x, from_y, unto_x, unto_y, size_x, size_y);
+void cursor_toggle_insert(void) {
+ if (cursor_mode == CURSOR_OVERWRITE) {
+ cursor_set_mode(CURSOR_INSERT);
+ } else {
+ cursor_set_mode(CURSOR_OVERWRITE);
+ }
+}
- if (refresh_flag) mouse_refresh_done();
- mouse_thaw();
+void cursor_set_follow(int follow) {
+ cursor_follow = follow;
}
} // namespace MADSV2
} // namespace MADS
-
-
-
diff --git a/engines/mads/madsv2/core/cursor.h b/engines/mads/madsv2/core/cursor.h
new file mode 100644
index 00000000000..234f9c636ac
--- /dev/null
+++ b/engines/mads/madsv2/core/cursor.h
@@ -0,0 +1,56 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef MADS_CORE_CURSOR_H
+#define MADS_CORE_CURSOR_H
+
+#include "mads/madsv2/core/general.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+#define CURSOR_OFF 0 /* Cursor off */
+#define CURSOR_ON 1 /* Cursor on */
+#define CURSOR_INSERT 2 /* Cursor in insert mode */
+#define CURSOR_OVERWRITE 3 /* Cursor in overwrite mode */
+
+extern int cursor_mode; /* global cursor insert mode flag */
+extern int cursor_follow; /* global cursor follow flag */
+
+/**
+ * Sets text cursor size
+ */
+extern void cursor_set_size(short start, short finish);
+
+/**
+ * Sets text cursor position
+ */
+extern void cursor_set_pos(short x, short y);
+
+extern void cursor_get_pos(int *x, int *y);
+extern void cursor_set_mode(int my_type);
+extern void cursor_toggle_insert();
+extern void cursor_set_follow(int follow);
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/dialog.cpp b/engines/mads/madsv2/core/dialog.cpp
new file mode 100644
index 00000000000..2bc906fe60e
--- /dev/null
+++ b/engines/mads/madsv2/core/dialog.cpp
@@ -0,0 +1,3640 @@
+/* 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/textconsole.h"
+#include "mads/madsv2/core/dialog.h"
+#include "mads/madsv2/core/fileio.h"
+#include "mads/madsv2/core/mouse.h"
+#include "mads/madsv2/core/screen.h"
+#include "mads/madsv2/core/cursor.h"
+#include "mads/madsv2/core/window.h"
+#include "mads/madsv2/core/keys.h"
+#include "mads/madsv2/core/mem.h"
+#include "mads/madsv2/core/timer.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+
+/* public global variables */
+
+int dialog_error;
+bool dialog_quicksearch_flag = true;
+bool dialog_wildcard_exits = false;
+
+/* private global variables */
+
+static int mouse_stroke_type; /* Where the stroke originated */
+static int mouse_orig_stroke_type; /* First radio button pressed */
+static int mouse_override; /* Override repeat damper */
+static int stroke_going; /* Currently processing a stroke */
+static int resolved_mouse; /* Have resolved stroke this pass */
+static long mouse_timing_clock; /* Stroke timer for logitech */
+static ItemPtr mouse_scroll_item; /* Recent mouse item */
+static ListPtr mouse_scroll_list; /* Recent mouse list */
+static char temp_buf[80]; /* A convenient buffer */
+
+static MouseCallback mouse_callback; /* Mouse callback vector */
+static int mouse_callback_double_only; /* Mouse callback double only flag*/
+
+/* Page callback vector */
+static PageCallback page_callback;
+
+static int allow_list_callbacks; /* Flag if list callbacks allowed */
+
+static int dialog_default_normal = DD_DEFAULT_NORMAL_COLOR;
+static int dialog_default_select = DD_DEFAULT_SELECT_COLOR;
+static int dialog_default_hilite = DD_DEFAULT_HILITE_COLOR;
+static int dialog_default_greyed = DD_DEFAULT_GREYED_COLOR;
+
+static long dialog_string_space = DIALOG_DEFAULT_STRING_SPACE;
+
+long dialog_timeout = 0;
+
+int dialog_language = DIALOG_ENGLISH;
+
+#define ATTR_DIR 10h /* Attribute for subdirectory */
+#define DTA_ATTR 15h /* offset in DTA of attribute */
+#define DTA_NAME 1eh /* offset in DTA of filename */
+
+int alert_normal_color = DD_DEFAULT_NORMAL_COLOR;
+int alert_select_color = DD_DEFAULT_SELECT_COLOR;
+int alert_hilite_color = DD_DEFAULT_HILITE_COLOR;
+
+#define SAY_DIALOG_SIZE 1024
+
+static Dialog say_dialog_box;
+static DialogPtr say_dialog = &say_dialog_box;
+static char say_dialog_work[SAY_DIALOG_SIZE];
+
+#define write_flag 0x01
+#define error_mask 0x06
+#define fail_flag 0x08
+#define retry_flag 0x10
+#define ignore_flag 0x20
+
+#define ignore_option 0x00
+#define retry_option 0x01
+#define abort_option 0x02
+#define fail_option 0x03
+
+Dialog crit_dialog;
+char crit_work[256];
+
+extern void dialog_24_server(void);
+
+static int dialog_server_installed = false;
+static dword dialog_old_24_server;
+
+
+int dialog_read_dir_to_list(ListPtr target, char *wild, int dirflag) {
+ warning("TODO: dialog_read_dir_to_list");
+ target->elements = 0;
+ return 0;
+}
+
+/**
+ * Appends a list of valid drive letters to the end of the specified
+ * list structure. This is done by attempting to "change drive" to
+ * each drive letter beginning with "A", and stopping when an attempt fails.
+ */
+static void dialog_read_drives_to_list(ListPtr dirslist) {
+ char *myptr;
+
+ myptr = dirslist->list + (dirslist->elements * dirslist->element_offset);
+ Common::strcpy_s(myptr, 4, "C:\\");
+ dirslist->elements++;
+}
+
+/**
+ * Loads directory (and subdirectory list w/ drives) for a filename item
+ */
+static void dialog_load_directory(DialogPtr dialog, ItemPtr item) {
+ ItemPtr fileitem, dirsitem;
+ ListPtr filelist, dirslist;
+
+ /* Get our file list item and dirs list item */
+
+ fileitem = &dialog->item[item->status];
+ dirsitem = &dialog->item[fileitem->id + 1];
+
+ /* Get the associated list structures */
+
+ filelist = &dialog->lists[fileitem->buf_id];
+ dirslist = &dialog->lists[dirsitem->buf_id];
+
+ filelist->elements = 0;
+ dirslist->elements = 0;
+
+ /* Try to read them in */
+
+ dialog_read_dir_to_list(dirslist, "*.*", true);
+ dialog_read_dir_to_list(filelist, dialog->buffer[item->buf_id], false);
+
+ dialog_read_drives_to_list(dirslist);
+
+ /* Reset window cursors */
+
+ filelist->base_entry = 0;
+ dirslist->base_entry = 0;
+
+ filelist->picked_entry = -1;
+ dirslist->picked_entry = -1;
+}
+
+/**
+ * Item to determine the proper X and Y values for an item based
+ * on the X and Y values passed by the user (handles the various
+ * special codes).
+ */
+static void item_locate(DialogPtr dialog, ItemPtr item, int x, int y) {
+ switch (x) {
+ case DD_IX_CENTER:
+ x = 0;
+ break;
+
+ case DD_IX_LEFT:
+ if (y == DD_IY_BUTTON) {
+ x = dialog->button_left;
+ dialog->button_left += item->width + 1;
+ } else {
+ x = 1;
+ }
+ break;
+
+ case DD_IX_RIGHT:
+ if (y == DD_IY_BUTTON) {
+ x = dialog->button_right - (item->width + 1);
+ dialog->button_right = x;
+ } else {
+ x = 0 - (item->width + 1);
+ }
+ break;
+ }
+
+ switch (y) {
+ case DD_IY_AUTOFILL:
+ y = dialog->fill_marker++;
+ break;
+
+ default:
+ if (y >= dialog->fill_marker) {
+ dialog->fill_marker = y + 1;
+ }
+ break;
+ }
+
+ item->x = x;
+ item->y = y;
+}
+
+/**
+ * Attempts to allocate a new item handle from the dialog box's
+ * item array. Returns NULL if fails.
+ */
+static ItemPtr item_allocate(DialogPtr dialog, int item_type) {
+ ItemPtr item;
+
+ if (dialog->num_items < DIALOG_MAX_ITEM) {
+ item = &dialog->item[dialog->num_items];
+ item->type = item_type;
+ item->id = (dialog->num_items++);
+ return item;
+ } else {
+ dialog_error = DD_ERR_NOMOREITEMS;
+ return NULL;
+ }
+}
+
+static char *string_allocate(DialogPtr dialog, int length) {
+ char *result = NULL;
+
+ if (dialog->string_space_remaining < (length + 1)) {
+ dialog_error = DD_ERR_NOMORESTRINGS;
+ goto done;
+ }
+
+ result = dialog->string_marker;
+
+ dialog->string_marker += (length + 1);
+ dialog->string_space_remaining -= (length + 1);
+
+done:
+ return result;
+}
+
+/**
+ * Attempts to allocate one of the dialog box's string buffers.
+ * Returns -1 if no buffer was available.
+ */
+static int buffer_allocate(DialogPtr dialog) {
+ int my_buffer = -1;
+ char *space;
+
+ if (dialog->buffers_allocated >= DIALOG_MAX_BUFFER) {
+ dialog_error = DD_ERR_NOMOREBUFFERS;
+ goto done;
+ }
+
+ space = string_allocate(dialog, 80);
+ if (space == NULL) goto done;
+
+ my_buffer = dialog->buffers_allocated;
+ dialog->buffers_allocated++;
+
+ dialog->buffer[my_buffer] = space;
+
+done:
+ return my_buffer;
+}
+
+/**
+ * Attempts to allocate one of the dialog box's list window structures.
+ * Returns -1 if all are in use.
+ */
+static int list_allocate(DialogPtr dialog) {
+ int my_list;
+
+ if (dialog->lists_allocated < DIALOG_MAX_LIST) {
+ my_list = dialog->lists_allocated;
+ dialog->lists_allocated++;
+ } else {
+ dialog_error = DD_ERR_NOMORELISTS;
+ my_list = -1;
+ }
+
+ return my_list;
+}
+
+/**
+ * Returns the "hotkey" keystroke value, if any, for the
+ * passed string. Returns 0 if no hotkey found. Hotkeys
+ * are marked by preceding "~" characters.
+ */
+static int get_keystroke(const char *prompt) {
+ const char *key_finder;
+ int key_stroke;
+
+ key_finder = strchr(prompt, '~');
+ if (key_finder != NULL) {
+ key_finder++;
+ key_stroke = *key_finder;
+ } else {
+ key_stroke = 0;
+ }
+
+ return key_stroke;
+}
+
+ItemPtr dialog_add_button(DialogPtr dialog, int x, int y, char *prompt) {
+ ItemPtr item = NULL;
+ char *space;
+ int space_look;
+
+ space = string_allocate(dialog, strlen(prompt));
+ if (space == NULL) goto done;
+
+ item = item_allocate(dialog, DD_I_BUTTON);
+
+ if (item != NULL) {
+
+ item->prompt = space;
+ Common::strcpy_s(item->prompt, 65536, prompt);
+
+ item->width = strlen(prompt) + 2;
+
+ item_locate(dialog, item, x, y);
+
+ item->x2 = -1;
+
+ /* Adjust cursor location to appear over the first letter (not */
+ /* over a space). */
+
+ for (space_look = 0; ((unsigned)space_look < strlen(prompt)) && (item->x2 < 0); space_look++) {
+ if (prompt[space_look] != ' ') item->x2 = space_look + 1;
+ }
+
+ if (item->x2 < 0) item->x2 = 0;
+
+ item->status = 0;
+
+ item->keystroke = get_keystroke(prompt);
+
+ Common::strcpy_s(item->prompt, 65536, prompt);
+
+ if (dialog_language == DIALOG_GERMAN) {
+ if (strcmp(prompt, CANCEL_GERMAN) == 0) {
+ dialog->cancel_item = item;
+ }
+ } else {
+ if (strcmp(prompt, CANCEL_BUTTON) == 0) {
+ dialog->cancel_item = item;
+ }
+ }
+
+ }
+
+done:
+ return item;
+}
+
+ItemPtr dialog_add_checkbox(DialogPtr dialog, int x, int y, const char *prompt,
+ int default_val, int class_) {
+ ItemPtr item = NULL;
+ char *space;
+
+ space = string_allocate(dialog, strlen(prompt));
+ if (space == NULL) goto done;
+
+ item = item_allocate(dialog, DD_I_CHECKBOX);
+
+ if (item != NULL) {
+ item->width = strlen(prompt) + 4;
+
+ item_locate(dialog, item, x, y);
+
+ item->x2 = 1;
+ item->status = (!!default_val) & DD_CHECK_TRUE; /* (sic) */
+
+ dialog->width = MAX<short>(dialog->width, (item->x + item->width + 1));
+
+ item->prompt = space;
+ Common::strcpy_s(item->prompt, 65536, prompt);
+
+ item->keystroke = get_keystroke(prompt);
+
+ item->_class = class_;
+
+ }
+
+done:
+ return item;
+}
+
+void dialog_grey_checkbox(ItemPtr item) {
+ if (item->type == DD_I_CHECKBOX) {
+ item->status |= DD_CHECK_GREY;
+ }
+}
+
+ItemPtr dialog_add_message(DialogPtr dialog, int x, int y, char *prompt) {
+ ItemPtr item = NULL;
+ char *space = NULL;
+
+ if (prompt != NULL) {
+ space = string_allocate(dialog, strlen(prompt));
+ if (space == NULL) goto done;
+ }
+
+ item = item_allocate(dialog, DD_I_MESSAGE);
+
+ if (item != NULL) {
+ item->prompt = space;
+ if (prompt == NULL) {
+ item->width = DD_LINEACROSS;
+ } else {
+ item->width = strlen(prompt);
+ Common::strcpy_s(item->prompt, 65536, prompt);
+ }
+ item_locate(dialog, item, x, y);
+ dialog->width = MAX<short>(dialog->width, (item->x + item->width + 1));
+ item->status = 0;
+ }
+
+done:
+ return item;
+}
+
+void dialog_add_blank(DialogPtr dialog) {
+ dialog->fill_marker++;
+}
+
+ItemPtr dialog_add_string(DialogPtr dialog, int x, int y, const char *prompt,
+ const char *default_val, int width) {
+ ItemPtr item = NULL;
+ char *space;
+
+ space = string_allocate(dialog, strlen(prompt));
+ if (space == NULL) goto done;
+
+ item = item_allocate(dialog, DD_I_STRING);
+
+ if (item != NULL) {
+
+ item->width = strlen(prompt) + 2 + width;
+
+ item_locate(dialog, item, x, y);
+
+ dialog->width = MAX<short>(dialog->width, (item->x + item->width));
+
+ item->x2 = strlen(prompt) + 1;
+
+ /* Account for any hotkey stroke in setting proper cursor location */
+
+ if (strchr(prompt, '~') != NULL) {
+ item->width--;
+ item->x2--;
+ }
+
+ item->status = 0;
+ item->keystroke = get_keystroke(prompt);
+
+ item->prompt = space;
+ Common::strcpy_s(item->prompt, 65536, prompt);
+
+ /* Set up a buffer in the dialog's buffer space */
+
+ item->buf_width = width;
+ item->buf_id = buffer_allocate(dialog);
+
+ if (item->buf_id < 0) {
+
+ dialog->num_items--;
+ item = NULL;
+
+ } else {
+
+ /* Copy the default value (if any) into the buffer */
+
+ if (default_val != NULL) {
+ Common::strcpy_s(dialog->buffer[item->buf_id], 65536, default_val);
+ if (strlen(default_val) > (unsigned)width) {
+ dialog->buffer[item->buf_id][width] = 0;
+ }
+ dialog->buf_cursor[item->buf_id] = strlen(default_val);
+ } else {
+ dialog->buffer[item->buf_id][0] = 0;
+ default_val = &dialog->buffer[item->buf_id][0];
+ }
+
+ /* Mark the entire buffer contents as "selected" */
+
+ dialog->buf_status[item->buf_id] = 0;
+ dialog->buf_base_x[item->buf_id] = item->x2;
+ if (strlen(default_val) > 0) {
+ dialog->buf_select[item->buf_id] = true;
+ dialog->buf_selbase[item->buf_id] = 0;
+ dialog->buf_seltarget[item->buf_id] = strlen(default_val);
+ } else {
+ dialog->buf_select[item->buf_id] = false;
+ }
+ }
+ }
+
+done:
+ return item;
+}
+
+ItemPtr dialog_add_listbased(DialogPtr dialog, int x, int y, const char *prompt,
+ const char *default_val, int width, const char *title, char *mylist,
+ int elements, int element_offset, int entry_width, int rows, int columns) {
+ ItemPtr item, listitem;
+ ListPtr list;
+ int listnum;
+ int temp_width;
+
+ /* First, just add the normal string entry area part */
+
+ item = dialog_add_string(dialog, x, y, prompt, default_val, width);
+
+ /* Then, do all the additional stuff for a list window */
+
+ if (item != NULL) {
+ item->type = DD_I_LISTBASED;
+
+ listitem = item_allocate(dialog, DD_I_LIST);
+
+ if (listitem != NULL) {
+
+ listnum = list_allocate(dialog);
+
+ if (listnum >= 0) {
+
+ dialog_add_blank(dialog);
+ dialog_add_message(dialog, DD_IX_LEFT, DD_IY_AUTOFILL, title);
+
+ list = &(dialog->lists[listnum]);
+
+ list->rows = rows;
+ list->columns = columns;
+
+ temp_width = (columns * (entry_width + 1)) + 2;
+
+ dialog->width = MAX<short>(dialog->width, (temp_width + 4));
+
+ list->window.ul_x = 0;
+ list->window.ul_y = dialog->fill_marker;
+
+ dialog->fill_marker += (rows + 2);
+
+ listitem->keystroke = get_keystroke(title);
+
+ list->elements = elements;
+ list->element_offset = element_offset;
+ list->entry_width = entry_width;
+
+ list->base_entry = 0;
+ list->picked_entry = -1;
+ list->thumb = -1;
+
+ /* Set items up to point at one another */
+
+ item->status = listitem->id;
+ listitem->status = item->id;
+ listitem->buf_id = listnum;
+
+ list->list = mylist;
+
+ } else {
+ dialog->num_items -= 2;
+ item = NULL;
+ }
+ } else {
+ dialog->num_items--;
+ item = NULL;
+ }
+ }
+
+ return item;
+}
+
+ItemPtr dialog_append_list(DialogPtr dialog, int x, int y, ItemPtr base_string,
+ char *title,
+ char *mylist, int elements, int element_offset,
+ int entry_width, int rows, int columns) {
+ ItemPtr item, listitem = nullptr;
+ ListPtr list;
+ int listnum;
+ int temp_width;
+
+ /* First, just add the normal string entry area part */
+
+ item = base_string;
+
+ /* Then, do all the additional stuff for a list window */
+
+ if (item != NULL) {
+ listitem = item_allocate(dialog, DD_I_LIST);
+
+ if (listitem != NULL) {
+
+ listnum = list_allocate(dialog);
+
+ if (listnum >= 0) {
+
+ dialog_add_blank(dialog);
+ dialog_add_message(dialog, DD_IX_LEFT, DD_IY_AUTOFILL, title);
+
+ list = &(dialog->lists[listnum]);
+
+ list->rows = rows;
+ list->columns = columns;
+
+ temp_width = (columns * (entry_width + 1)) + 2;
+
+ dialog->width = MAX<short>(dialog->width, (temp_width + 4));
+
+ list->window.ul_x = 0;
+ list->window.ul_y = dialog->fill_marker;
+
+ dialog->fill_marker += (rows + 2);
+
+ listitem->keystroke = get_keystroke(title);
+
+ list->elements = elements;
+ list->element_offset = element_offset;
+ list->entry_width = entry_width;
+
+ list->base_entry = 0;
+ list->picked_entry = -1;
+ list->thumb = -1;
+
+ /* Set items up to point at one another */
+
+ listitem->status = item->id;
+ listitem->buf_id = listnum;
+
+ list->list = mylist;
+
+ } else {
+ dialog->num_items -= 1;
+ }
+ }
+ }
+
+ return listitem;
+}
+
+ItemPtr dialog_add_filename(DialogPtr dialog, int x, int y, char *prompt,
+ char *default_val, char *path, int rows,
+ char *filebuf, int max_file_elements,
+ char *dirsbuf, int max_dirs_elements) {
+ ItemPtr item, listitem, dirsitem;
+ ListPtr list, dirs;
+ int list_num, dirs_num;
+ int base_item;
+ int message_line;
+ int savedpath;
+ int savedrive;
+ char savepath[80];
+ char mypath[80];
+ char mypath2[80];
+ int mydrive;
+
+ dialog->status |= DD_FILEMENU; /* Note that we do in fact use files */
+
+ base_item = dialog->num_items;
+
+ item = dialog_add_string(dialog, x, y, prompt, default_val, DIALOG_FILE_BUFFER);
+
+ if (item != NULL) {
+
+ listitem = item_allocate(dialog, DD_I_FILELIST);
+ dirsitem = item_allocate(dialog, DD_I_DIRSLIST);
+
+ if ((listitem == NULL) || (dirsitem == NULL) || (dialog->lists_allocated > 0)) {
+ item = NULL;
+ } else {
+
+ savedpath = (mads_getcwd(savepath, 80) != NULL);
+ savedrive = mads_getdrive();
+
+ list_num = list_allocate(dialog);
+ dirs_num = list_allocate(dialog);
+
+ list = &dialog->lists[list_num];
+ dirs = &dialog->lists[dirs_num];
+
+ item->type = DD_I_FILENAME;
+ listitem->type = DD_I_FILELIST;
+ dirsitem->type = DD_I_DIRSLIST;
+
+ listitem->keystroke = (int)'L';
+ dirsitem->keystroke = (int)'D';
+
+ dialog_add_blank(dialog);
+ dialog->path_item = dialog_add_message(dialog, DD_IX_LEFT, DD_IY_AUTOFILL, path);
+ dialog->string_marker += (80 - strlen(path));
+ dialog_add_blank(dialog);
+
+ message_line = dialog->fill_marker;
+ dialog_add_message(dialog, DD_IX_LEFT, message_line, "File ~List:");
+ dialog_add_message(dialog, 44, message_line, "~Drives / Dirs:");
+
+ list->rows = rows;
+ list->columns = 3;
+ dirs->rows = rows;
+ dirs->columns = 1;
+
+ dialog->width = MAX<short>(dialog->width, DIALOG_FILE_WIDTH);
+
+ list->entry_width = 12;
+ list->element_offset = 13;
+ list->max_elements = max_file_elements;
+ list->base_entry = 0;
+ list->picked_entry = -1;
+ list->thumb = -1;
+
+ dirs->entry_width = 12;
+ dirs->element_offset = 13;
+ dirs->max_elements = max_dirs_elements;
+ dirs->base_entry = 0;
+ dirs->picked_entry = -1;
+ dirs->thumb = -1;
+
+ list->window.ul_x = 0;
+ dirs->window.ul_x = 43;
+
+ list->window.ul_y = dialog->fill_marker;
+ dirs->window.ul_y = dialog->fill_marker;
+
+ item->status = listitem->id;
+ listitem->status = item->id;
+ dirsitem->status = item->id;
+
+ listitem->buf_id = list_num;
+ dirsitem->buf_id = dirs_num;
+
+ list->list = filebuf;
+ dirs->list = dirsbuf;
+
+ dialog->fill_marker += (rows + 2);
+
+ if (savedpath) {
+ Common::strcpy_s(mypath, path);
+ mads_strupr(mypath);
+ mads_fullpath(mypath2, mypath, 80);
+ mydrive = ((int)mypath2[0]) - '@';
+ mads_chdir(mypath2);
+ mads_chdrive(mydrive);
+ }
+
+ dialog_load_directory(dialog, item);
+
+ if (savedpath) {
+ mads_chdir(savepath);
+ mads_chdrive(savedrive);
+ }
+ }
+ }
+
+ if (item == NULL) {
+ dialog->num_items = base_item;
+ }
+
+ return item;
+}
+
+void dialog_set_colors(int normal, int select, int hilite, int greyed) {
+ dialog_default_normal = normal;
+ dialog_default_select = select;
+ dialog_default_hilite = hilite;
+ dialog_default_greyed = greyed;
+}
+
+void dialog_set_workspace_size(long workspace) {
+ dialog_string_space = workspace;
+}
+
+void dialog_set_string_space(DialogPtr dialog, char *space, long size) {
+ dialog->string_space = space;
+ dialog->string_space_remaining = size;
+ dialog->string_marker = space;
+}
+
+DialogPtr dialog_create(DialogPtr dialog, int ul_x, int ul_y, int width,
+ int normal_color, int select_color, int hilite_color) {
+
+ /* Allocate memory for dialog if necessary */
+
+ if (dialog == NULL) {
+ dialog = (DialogPtr)mem_get(sizeof(struct DialogBox));
+ dialog->status = DD_DYNAMIC;
+ dialog->string_space = NULL;
+ } else {
+ dialog->status = DD_STATIC;
+ }
+
+ mouse_callback = NULL;
+ page_callback = NULL;
+
+ if (dialog != NULL) {
+
+ if (dialog->string_space == NULL) {
+ dialog->status |= DD_DYNAMICSTRINGS;
+ dialog->string_space = (char *)mem_get(dialog_string_space);
+ dialog->string_space_remaining = dialog_string_space;
+ if (dialog->string_space == NULL) {
+ dialog_error = DD_ERR_NOMOREMEMORY;
+ if (dialog->status & DD_DYNAMIC) {
+ mem_free(dialog);
+ }
+ dialog = NULL;
+ }
+ }
+
+ if (normal_color == DD_DEFAULT) {
+ dialog->normal_color = dialog_default_normal;
+ } else {
+ dialog->normal_color = normal_color;
+ }
+
+ if (select_color == DD_DEFAULT) {
+ dialog->select_color = dialog_default_select;
+ } else {
+ dialog->select_color = select_color;
+ }
+
+ if (hilite_color == DD_DEFAULT) {
+ if (screen_video_mode == mono_text_mode) {
+ dialog->hilite_color = dialog_default_select;
+ } else {
+ dialog->hilite_color = dialog_default_hilite;
+ }
+ } else {
+ dialog->hilite_color = hilite_color;
+ }
+
+ dialog->width = width;
+
+ window_set(&dialog->window, ul_x, ul_y, ul_x + width + 1, ul_y);
+
+ dialog->base_x = ul_x + 1;
+ dialog->base_y = ul_y + 1;
+
+ dialog->num_items = 0;
+ dialog->fill_marker = 0;
+ dialog->active_button = dialog->active_item = 0;
+
+ dialog->cursor_x = dialog->cursor_y = 0;
+
+ dialog->button_left = 1;
+ dialog->button_right = 0;
+
+ dialog->buffers_allocated = 0;
+ dialog->lists_allocated = 0;
+
+ dialog->callback = NULL;
+ dialog->checkbox_callback = NULL;
+
+ dialog->cancel_item = NULL;
+ dialog->path_item = NULL;
+ dialog->default_item = NULL;
+
+ dialog->string_marker = dialog->string_space;
+
+ } else {
+ dialog_error = DD_ERR_NOMOREMEMORY;
+ }
+
+ return dialog;
+}
+
+void dialog_destroy(DialogPtr dialog) {
+ if (dialog != NULL) {
+ if (dialog->status & DD_SCREENSAVED) {
+ window_destroy(&dialog->window);
+ dialog->status &= ~DD_SCREENSAVED;
+ }
+ if (dialog->status & DD_DYNAMICSTRINGS) {
+ mem_free(dialog->string_space);
+ dialog->string_space = NULL;
+ }
+ if (dialog->status & DD_DYNAMIC) {
+ mem_free(dialog);
+ }
+ }
+}
+
+void dialog_destroy_persist(DialogPtr dialog) {
+ if (dialog != NULL) {
+ if (dialog->status & DD_SCREENSAVED) {
+ mem_free(dialog->window.storage);
+ dialog->status &= ~DD_SCREENSAVED;
+ }
+ if (dialog->status & DD_DYNAMICSTRINGS) {
+ mem_free(dialog->string_space);
+ dialog->string_space = NULL;
+ }
+ if (dialog->status & DD_DYNAMIC) {
+ mem_free(dialog);
+ }
+ }
+}
+
+DialogPtr dialog_file_create(DialogPtr dialog, int ul_x, int ul_y,
+ int normal_color, int select_color, int hilite_color,
+ ItemPtr *ok_item, ItemPtr *first_item, const char *default_val,
+ const char *path, int rows, char *filebuf, int maxfiles,
+ char *dirsbuf, int maxdirs, const char *prompt) {
+ dialog = dialog_create(dialog, ul_x, ul_y, DIALOG_FILE_WIDTH,
+ normal_color, select_color, hilite_color);
+
+ dialog_add_message(dialog, DD_IX_CENTER, DD_IY_AUTOFILL, prompt);
+
+ *ok_item = dialog_add_button(dialog, DD_IX_LEFT, DD_IY_BUTTON, " OK ");
+ dialog_add_button(dialog, DD_IX_RIGHT, DD_IY_BUTTON, CANCEL_BUTTON);
+ *first_item = dialog_add_filename(dialog, DD_IX_LEFT, DD_IY_AUTOFILL, "~File Name: ",
+ default_val, path, rows,
+ filebuf, maxfiles,
+ dirsbuf, maxdirs);
+
+ return dialog;
+}
+
+void dialog_set_list_callback(DialogPtr dialog, void (*(callback))()) {
+ dialog->callback = callback;
+}
+
+void dialog_set_mouse_callback(MouseCallback callback, int double_only) {
+ mouse_callback = callback;
+ mouse_callback_double_only = double_only;
+}
+
+void dialog_set_page_callback(PageCallback callback) {
+ page_callback = callback;
+}
+
+void dialog_set_checkbox_callback(DialogPtr dialog, void (*(callback))()) {
+ dialog->checkbox_callback = callback;
+}
+
+/**
+ *
+ * Computes all necessary item coordinates and sizes => resolves
+ * all "indefinite" coordinates (i.e. centered dialogs, etc) into
+ * proper absolute screen coordinates (or dialog-relative coordinates)
+ * in preparation for actually executing the dialog.
+*/
+static void dialog_compute_window(DialogPtr dialog) {
+ int height;
+ int count;
+ int count2;
+ int center;
+ int button_width;
+ int extra_height;
+ ItemPtr item;
+ ListPtr list;
+
+ /* Find out if there's anything scheduled for the "button row" */
+
+ dialog->button_flag = false;
+ extra_height = 2;
+
+ for (count = 0; count < dialog->num_items; count++) {
+ if (dialog->item[count].y == DD_IY_BUTTON) {
+ dialog->button_flag = true;
+ extra_height = 4;
+ }
+ }
+
+ /* Figure out which checkbox items are in the same class as another */
+ for (count = 0; count < dialog->num_items; count++) {
+ if (dialog->item[count].type == DD_I_CHECKBOX) {
+ for (count2 = 0; count2 < dialog->num_items; count2++) {
+ if (count != count2) {
+ if (dialog->item[count2].type == DD_I_CHECKBOX) {
+ if (dialog->item[count]._class == dialog->item[count2]._class) {
+ dialog->item[count].status |= DD_CHECK_RADIO;
+ dialog->item[count2].status |= DD_CHECK_RADIO;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* Conform the dialog to the width of the button row, if necessary */
+
+ button_width = (dialog->button_left + abs(dialog->button_right) + 1);
+ dialog->width = MAX<short>(dialog->width, button_width);
+
+ /* Center the dialog box, if requested */
+
+ if (dialog->window.ul_x == DD_CENTER) {
+ center = screen_center_x ? screen_center_x : ((screen_max_x + 1) >> 1);
+ dialog->window.ul_x = (center - ((dialog->width + 3) >> 1));
+ dialog->base_x = dialog->window.ul_x + 1;
+ }
+
+ height = dialog->fill_marker + extra_height;
+
+ if (dialog->window.ul_y == DD_CENTER) {
+ center = screen_center_y ? screen_center_y : ((screen_max_y + 1) >> 1);
+ dialog->window.ul_y = (center - ((height + 1) >> 1));
+ dialog->base_y = dialog->window.ul_y + 1;
+ }
+
+ /* Get the lower left dialog coordinates */
+
+ dialog->window.lr_x = dialog->window.ul_x + dialog->width + 1;
+ dialog->window.lr_y = dialog->window.ul_y + height - 1;
+
+ /* Resolve any right-margin relative items and compute all list windows */
+
+ for (count = 0; count < dialog->num_items; count++) {
+ item = &dialog->item[count];
+
+ if (item->x < 0) {
+ item->x += dialog->width;
+ } else if (item->x == 0) {
+ item->x = ((dialog->width + 1) >> 1) - ((item->width + 1) >> 1);
+ }
+
+ switch (item->type) {
+
+ case DD_I_LIST:
+ case DD_I_FILELIST:
+ case DD_I_DIRSLIST:
+ list = &dialog->lists[item->buf_id];
+ item->x = (list->window.ul_x += dialog->window.ul_x + 2);
+ item->y = (list->window.ul_y += dialog->base_y);
+ list->window.lr_x = list->window.ul_x + (list->columns * (list->entry_width + 1)) + 2;
+ list->window.lr_y = list->window.ul_y + list->rows + 1;
+ item->x2 = list->base_x = list->window.ul_x + 1;
+ list->base_y = list->window.ul_y + 1;
+ break;
+
+ default:
+ item->x2 += item->x;
+ break;
+
+ }
+ }
+}
+
+int dialog_read_checkbox(DialogPtr dialog, ItemPtr item) {
+ return item->status & DD_CHECK_TRUE;
+}
+
+char *dialog_read_string(DialogPtr dialog, ItemPtr item) {
+ return dialog->buffer[item->buf_id];
+}
+
+char *dialog_read_list(DialogPtr dialog, ItemPtr item) {
+ return dialog->buffer[item->buf_id];
+}
+
+char *dialog_read_pathname(DialogPtr dialog, ItemPtr item) {
+ return (dialog->path_item)->prompt;
+}
+
+char *dialog_read_filename(DialogPtr dialog, ItemPtr item) {
+ return dialog->buffer[item->buf_id];
+}
+
+char *dialog_read_filepath(DialogPtr dialog, ItemPtr item) {
+ int mylen;
+
+ Common::strcpy_s(temp_buf, (dialog->path_item)->prompt);
+ mylen = strlen(temp_buf);
+
+ if (temp_buf[mylen - 1] != '\\') {
+ Common::strcat_s(temp_buf, "\\");
+ }
+
+ Common::strcat_s(temp_buf, dialog->buffer[item->buf_id]);
+
+ return (temp_buf);
+}
+
+/**
+ * Updates the status of a dialog box based on its status flag
+ */
+static void dialog_update_checkbox(DialogPtr dialog, ItemPtr item) {
+ char temp1[2];
+ int color;
+
+ mouse_hide();
+
+ Common::strcpy_s(temp1, "X");
+
+ if (item->status & DD_CHECK_RADIO) {
+ temp1[0] = (char)0x07;
+ }
+
+ color = (item->status & DD_CHECK_GREY) ? dialog_default_greyed : dialog->normal_color;
+
+ if (item->status & DD_CHECK_TRUE) {
+ screen_put(temp1, color, 0, item->x2 + dialog->base_x, item->y + dialog->base_y);
+ } else {
+ screen_put(" ", color, 0, item->x2 + dialog->base_x, item->y + dialog->base_y);
+ }
+
+ mouse_show();
+}
+
+/**
+ * Displays the specified dialog string item's buffer, highlighting
+ * any selected text if the item is currently active.
+ */
+static void dialog_update_string(DialogPtr dialog, ItemPtr item) {
+ int buf;
+ int cx, cy;
+ int out_count;
+ char *textptr;
+ byte *screenptr;
+
+ mouse_hide();
+
+ buf = item->buf_id;
+ cx = item->x2 + dialog->base_x;
+ cy = item->y + dialog->base_y;
+
+ out_count = 0;
+
+ screenptr = screen + screen_char_add(cx, cy);
+ textptr = dialog->buffer[buf];
+
+ /* First, output as much of the string as we can */
+
+ while ((*textptr != 0) && (out_count < item->buf_width)) {
+ *(screenptr++) = *(textptr++);
+ if (dialog->buf_select[buf] && (item->id == dialog->active_item) &&
+ (((out_count >= dialog->buf_selbase[buf]) && (out_count < dialog->buf_seltarget[buf])) ||
+ ((out_count >= dialog->buf_seltarget[buf]) && (out_count < dialog->buf_selbase[buf])))) {
+ *(screenptr++) = (char)dialog->select_color;
+ } else {
+ *(screenptr++) = (char)dialog->normal_color;
+ }
+ out_count++;
+ }
+
+ /* Then, be sure the rest of the entry area is cleared */
+
+ while (out_count < item->buf_width) {
+ *(screenptr++) = 0x20;
+ if (dialog->buf_select[buf] &&
+ (((out_count >= dialog->buf_selbase[buf]) && (out_count < dialog->buf_seltarget[buf])) ||
+ ((out_count >= dialog->buf_seltarget[buf]) && (out_count < dialog->buf_selbase[buf])))) {
+ *(screenptr++) = (char)dialog->select_color;
+ } else {
+ *(screenptr++) = (char)dialog->normal_color;
+ }
+ out_count++;
+ }
+
+ mouse_show();
+}
+
+/**
+ * Updates the list window associated with an item.
+ */
+static void dialog_update_window(DialogPtr dialog, ItemPtr item) {
+ int row, col;
+ ListPtr list;
+ int out_count;
+ int my_color;
+ int id;
+ int start, dist, new_thumb;
+ int temp_pick;
+ int return_code;
+ byte *screenptr;
+ char *textptr;
+ typedef int (*CallbackFn)(ListPtr list, DialogPtr dialog);
+ CallbackFn callback;
+
+ mouse_hide();
+
+ if ((item->type == DD_I_LISTBASED) || (item->type == DD_I_FILENAME)) {
+ item = &dialog->item[item->status];
+ }
+
+ list = &dialog->lists[item->buf_id];
+
+ /* Clear our old cursor off by wipe-ing the window in a single color */
+
+ window_color(&list->window, dialog->normal_color);
+
+ /* Now, go through the rows and columns one by one, displaying each entry */
+
+ for (col = 0; col < list->columns; col++) {
+ for (row = 0; row < list->rows; row++) {
+ screenptr = screen + screen_char_add(list->base_x + (col * (list->entry_width + 1)),
+ list->base_y + row);
+ id = list->base_entry + row + (col * list->rows);
+
+ /* Point at the text for this entry */
+
+ textptr = list->list + (id * list->element_offset);
+
+ /* Check if the cursor is on this item */
+
+ if (id != list->picked_entry) {
+ my_color = dialog->normal_color;
+ } else {
+ my_color = dialog->select_color;
+ }
+ *screenptr++;
+ if (*screenptr != (char)dialog->select_color) {
+ *(screenptr++) = (char)my_color;
+ } else {
+ screenptr++;
+ }
+ out_count = 0;
+ if (id < list->elements) {
+ while ((out_count < list->entry_width) && (*textptr != 0)) {
+ *(screenptr++) = *(textptr++);
+ *(screenptr++) = (char)my_color;
+ out_count++;
+ }
+ }
+ while (out_count < list->entry_width) {
+ *(screenptr++) = 0x20;
+ *(screenptr++) = (char)my_color;
+ out_count++;
+ }
+ *screenptr++;
+ if (*screenptr != (char)dialog->select_color) {
+ *(screenptr++) = (char)my_color;
+ }
+ }
+ }
+
+
+ /* Update the thumb mark in a scroll bar; routine is different */
+ /* depending on whether bar is vertical or horizontal */
+
+ temp_pick = list->picked_entry;
+ if (temp_pick < 0) temp_pick = 0;
+
+ if (list->elements > 0) {
+
+ if (list->columns > 1) {
+
+ start = list->window.ul_x + 2;
+ dist = list->window.lr_x - list->window.ul_x - 3;
+
+ new_thumb = (dist * temp_pick) / list->elements;
+
+ if (new_thumb != list->thumb) {
+ if (list->thumb >= 0) {
+ screenptr = screen + screen_char_add(start + list->thumb, list->window.lr_y);
+ *screenptr = scroll_bar;
+ }
+ screenptr = screen + screen_char_add(start + new_thumb, list->window.lr_y);
+ *screenptr = thumb_mark;
+ list->thumb = new_thumb;
+ }
+
+ } else {
+
+ start = list->window.ul_y + 2;
+ dist = list->window.lr_y - list->window.ul_y - 3;
+
+ new_thumb = (dist * temp_pick) / list->elements;
+
+ if (new_thumb != list->thumb) {
+ if (list->thumb >= 0) {
+ screenptr = screen + screen_char_add(list->window.lr_x, start + list->thumb);
+ *screenptr = scroll_bar;
+ }
+ screenptr = screen + screen_char_add(list->window.lr_x, start + new_thumb);
+ *screenptr = thumb_mark;
+ list->thumb = new_thumb;
+ }
+
+ }
+
+ }
+
+ if ((dialog->callback != NULL) && (allow_list_callbacks)) {
+ callback = (CallbackFn)dialog->callback;
+ return_code = callback(list, dialog);
+ if (return_code) {
+ dialog->status |= DD_EXITFLAG;
+ dialog_error = DD_ERR_ABORTEDBYCALLBACK;
+ }
+ }
+
+ mouse_show();
+}
+
+/**
+ * Shows a dialog button. "Selected" flags whether the item is
+ * currently being picked by the mouse. Otherwise, the angle
+ * brackets are automatically highlighted if the button is the
+ * active button.
+ */
+static void dialog_show_button(DialogPtr dialog, ItemPtr item, int selected) {
+ int angle_color, text_color, hi_color;
+ int cx, cy;
+
+ mouse_hide();
+
+ if (selected) {
+ angle_color = text_color = hi_color = dialog->select_color;
+ } else {
+ text_color = dialog->normal_color;
+ hi_color = dialog->hilite_color;
+ if (item->id == dialog->active_button) {
+ angle_color = dialog->hilite_color;
+ } else {
+ angle_color = dialog->normal_color;
+ }
+ }
+
+ if (item->y == DD_IY_BUTTON) {
+ cy = dialog->window.lr_y - 1;
+ } else {
+ cy = item->y + dialog->base_y;
+ }
+ cx = item->x + dialog->base_x;
+
+ cx = screen_put("<", angle_color, 0, cx, cy);
+ cx = screen_put(item->prompt, text_color, hi_color, cx, cy);
+ cx = screen_put(">", angle_color, 0, cx, cy);
+
+ mouse_show();
+}
+
+/**
+ * Outputs a dialog message string at the appropriate location
+ * in the dialog box.
+ */
+static void dialog_show_message(DialogPtr dialog, ItemPtr item) {
+ mouse_hide();
+
+ if (item->width != DD_LINEACROSS) {
+ screen_put(item->prompt, dialog->normal_color, dialog->hilite_color,
+ item->x + dialog->base_x, item->y + dialog->base_y);
+ } else {
+ window_line_across(&(dialog->window), item->y + dialog->base_y);
+ }
+
+ mouse_show();
+}
+
+/**
+ * Clears a message previously output with dialog_show_message ().
+ * Currently, the only kind of message that could change (and thus
+ * need to be cleared) is the pathname for file items, which is
+ * handled internally.
+ */
+static void dialog_clear_message(DialogPtr dialog, ItemPtr item) {
+ int cx, cy;
+ int count, bound;
+
+ mouse_hide();
+
+ cx = item->x + dialog->base_x;
+ cy = item->y + dialog->base_y;
+ bound = strlen(item->prompt);
+
+ for (count = 0; count < bound; count++) {
+ cx = screen_put(" ", dialog->normal_color, dialog->normal_color, cx, cy);
+ }
+
+ mouse_show();
+}
+
+/**
+ * Displays (and updates) a checkbox item
+ */
+static void dialog_show_checkbox(DialogPtr dialog, ItemPtr item) {
+ int cx;
+ int color;
+ int hi_color;
+ char temp1[4];
+ char temp2[4];
+
+ mouse_hide();
+
+ if (item->status & DD_CHECK_RADIO) {
+ Common::strcpy_s(temp1, "(");
+ Common::strcpy_s(temp2, ") ");
+ } else {
+ Common::strcpy_s(temp1, "[");
+ Common::strcpy_s(temp2, "] ");
+ }
+
+ color = (item->status & DD_CHECK_GREY) ? dialog_default_greyed : dialog->normal_color;
+ hi_color = (item->status & DD_CHECK_GREY) ? dialog_default_greyed : dialog->hilite_color;
+
+ cx = screen_put(temp1, color, 0, item->x + dialog->base_x, item->y + dialog->base_y);
+ cx++;
+ cx = screen_put(temp2, color, 0, cx, item->y + dialog->base_y);
+ cx = screen_put(item->prompt, color, hi_color,
+ cx, item->y + dialog->base_y);
+
+ dialog_update_checkbox(dialog, item);
+
+ mouse_show();
+}
+
+/**
+ * Displays (and updates) a string item
+ */
+static void dialog_show_string(DialogPtr dialog, ItemPtr item) {
+ int cx;
+
+ mouse_hide();
+
+ cx = screen_put(item->prompt, dialog->normal_color, dialog->hilite_color,
+ item->x + dialog->base_x, item->y + dialog->base_y);
+ cx = screen_put("[", dialog->normal_color, 0, cx, item->y + dialog->base_y);
+
+ cx = screen_put("]", dialog->normal_color, 0, cx + item->buf_width, item->y + dialog->base_y);
+
+ dialog_update_string(dialog, item);
+
+ mouse_show();
+}
+
+/**
+ * Displays (and updates) a list-based item (including file lists)
+ */
+static void dialog_show_window(DialogPtr dialog, ItemPtr item) {
+ ListPtr list;
+
+ mouse_hide();
+
+ if ((item->type == DD_I_LISTBASED) || (item->type == DD_I_FILENAME)) {
+ item = &dialog->item[item->status];
+ }
+
+ list = &dialog->lists[item->buf_id];
+
+ window_wipe(&list->window);
+ window_color(&list->window, dialog->normal_color);
+ window_draw_box(&list->window, WINDOW_SINGLE);
+
+ if (list->columns == 1) {
+ window_vert_scrollbar(&list->window, dialog->normal_color);
+ } else {
+ window_horiz_scrollbar(&list->window, dialog->normal_color);
+ }
+
+ dialog_update_window(dialog, item);
+
+ mouse_show();
+}
+
+/**
+ * Displays the item whose handle is passed, no matter what type
+ * of item it is (calls the appropriate one of the above routines)
+ */
+static void dialog_show_any(DialogPtr dialog, ItemPtr item) {
+ switch (item->type) {
+ case DD_I_BUTTON:
+ dialog_show_button(dialog, item, false);
+ break;
+
+ case DD_I_MESSAGE:
+ dialog_show_message(dialog, item);
+ break;
+
+ case DD_I_CHECKBOX:
+ dialog_show_checkbox(dialog, item);
+ break;
+
+ case DD_I_STRING:
+ dialog_show_string(dialog, item);
+ break;
+
+ case DD_I_FILENAME:
+ dialog_show_string(dialog, item);
+ break;
+
+ case DD_I_LISTBASED:
+ dialog_show_string(dialog, item);
+ break;
+
+ case DD_I_LIST:
+ case DD_I_FILELIST:
+ case DD_I_DIRSLIST:
+ dialog_show_window(dialog, item);
+ break;
+ }
+}
+
+void dialog_show_all(DialogPtr dialog) {
+ ItemPtr item;
+ int item_num;
+
+ if (!(dialog->status & DD_COMPUTED)) {
+ dialog_compute_window(dialog);
+ dialog->status |= DD_COMPUTED;
+ }
+
+ mouse_hide();
+
+ if (!(dialog->status & DD_SCREENSAVED)) {
+ window_create(&dialog->window);
+ dialog->status |= DD_SCREENSAVED;
+ }
+
+ window_wipe(&dialog->window);
+ window_color(&dialog->window, dialog->normal_color);
+ window_draw_box(&dialog->window, WINDOW_SINGLE);
+ window_shadow(&dialog->window);
+
+ if (dialog->button_flag) {
+ window_line_across(&dialog->window, dialog->window.lr_y - 2);
+ }
+
+ for (item_num = 0; item_num < dialog->num_items; item_num++) {
+ item = &dialog->item[item_num];
+ dialog_show_any(dialog, item);
+ }
+
+ mouse_show();
+}
+
+/**
+ * Routine to update the item whose handle is passed to it, no matter
+ * what type of item it is.
+ */
+static void dialog_update_any(DialogPtr dialog, ItemPtr item, int mouse_button_flag) {
+ switch (item->type) {
+ case DD_I_BUTTON:
+ dialog_show_button(dialog, item, mouse_button_flag);
+ break;
+
+ case DD_I_CHECKBOX:
+ dialog_update_checkbox(dialog, item);
+ break;
+
+ case DD_I_STRING:
+ case DD_I_FILENAME:
+ case DD_I_LISTBASED:
+ if (item->id != dialog->active_item) {
+ dialog->buf_select[item->buf_id] = false;
+ }
+ dialog_update_string(dialog, item);
+ break;
+
+ case DD_I_LIST:
+ case DD_I_FILELIST:
+ case DD_I_DIRSLIST:
+ dialog_update_window(dialog, item);
+ break;
+ }
+}
+
+/**
+ * Moves the cursor to the active item, at the appropriate place
+ * within that item (appropriate place depends on item type)
+ */
+static void dialog_update_cursor(DialogPtr dialog) {
+ ListPtr list;
+ int relval, relcol, relrow, relx, rely;
+
+ switch (dialog->item[dialog->active_item].type) {
+ case DD_I_BUTTON:
+ if (dialog->item[dialog->active_item].y == DD_IY_BUTTON) {
+ cursor_set_pos(dialog->base_x + dialog->item[dialog->active_item].x2,
+ dialog->window.lr_y - 1);
+ } else {
+ cursor_set_pos(dialog->base_x + dialog->item[dialog->active_item].x2,
+ dialog->base_y + dialog->item[dialog->active_item].y);
+ }
+ break;
+
+ case DD_I_STRING:
+ case DD_I_LISTBASED:
+ case DD_I_FILENAME:
+ cursor_set_pos(dialog->base_x + dialog->item[dialog->active_item].x2
+ + dialog->buf_cursor[dialog->item[dialog->active_item].buf_id],
+ dialog->base_y + dialog->item[dialog->active_item].y);
+ break;
+
+ case DD_I_LIST:
+ case DD_I_FILELIST:
+ case DD_I_DIRSLIST:
+ list = &dialog->lists[dialog->item[dialog->active_item].buf_id];
+ if (list->picked_entry >= list->base_entry) {
+ relval = list->picked_entry - list->base_entry;
+ } else {
+ relval = 0;
+ }
+ relcol = relval / list->rows;
+ relrow = relval - (relcol * list->rows);
+ relx = list->base_x + 1 + (relcol * (list->entry_width + 1));
+ rely = list->base_y + relrow;
+ cursor_set_pos(relx, rely);
+ break;
+
+ default:
+ cursor_set_pos(dialog->base_x + dialog->item[dialog->active_item].x2,
+ dialog->base_y + dialog->item[dialog->active_item].y);
+ break;
+ }
+}
+
+/**
+ * Routine to update & move the cursor to the active item, after
+ * possibly changing the active item.
+ *
+ * displace = "displacement" by which to change the active item #.
+ * 0 to leave active item unchanged. Item #'s will loop
+ * around.
+ *
+ * If active item changes, then the old active item will be
+ * updated also, to make sure its appearance conforms to its
+ * new, inactive, status.
+ */
+static void dialog_update_active(DialogPtr dialog, int displace, int mouse_button_flag, int out_of_class) {
+ int old_item;
+ int old_button;
+ int buf_num;
+ int prohibited;
+ ItemPtr item;
+ ItemPtr old;
+
+ old_item = dialog->active_item;
+ old_button = dialog->active_button;
+
+ do {
+ dialog->active_item += displace;
+ if (dialog->active_item < 0) dialog->active_item = dialog->num_items - 1;
+ if (dialog->active_item >= dialog->num_items) dialog->active_item = 0;
+ item = &dialog->item[dialog->active_item];
+ old = &dialog->item[old_item];
+ prohibited = (item->type == DD_I_MESSAGE) ||
+ (out_of_class &&
+ ((item->type == DD_I_CHECKBOX) &&
+ (old->type == DD_I_CHECKBOX) &&
+ (item->_class == old->_class)));
+ } while (prohibited && (displace != 0));
+
+ if ((displace != 0) && (!mouse_button_flag)) {
+ if (DialogString(dialog)) {
+ buf_num = dialog->item[dialog->active_item].buf_id;
+ dialog->buf_select[buf_num] = true;
+ dialog->buf_selbase[buf_num] = 0;
+ dialog->buf_seltarget[buf_num] = strlen(dialog->buffer[buf_num]);
+ dialog->buf_cursor[buf_num] = dialog->buf_seltarget[buf_num];
+ }
+ }
+
+ if (item->type == DD_I_BUTTON) {
+ dialog->active_button = dialog->active_item;
+ }
+
+ if (old_item != dialog->active_item) {
+ dialog_update_any(dialog, &dialog->item[old_item], false);
+ dialog_update_any(dialog, item, mouse_button_flag);
+ if ((old_button == old_item) && (item->type != DD_I_BUTTON)) {
+ if (dialog->default_item != NULL) {
+ dialog->active_button = (dialog->default_item)->id;
+ dialog_update_any(dialog, dialog->default_item, false);
+ dialog_update_any(dialog, &dialog->item[old_button], false);
+ }
+ }
+ if ((old_button != old_item) && (old_button != dialog->active_button)) {
+ dialog_update_any(dialog, &dialog->item[old_button], false);
+ }
+ } else {
+ dialog_update_any(dialog, item, mouse_button_flag);
+ }
+
+ dialog_update_cursor(dialog);
+}
+
+void dialog_go_sideways(DialogPtr dialog, int direction) {
+ ItemPtr current;
+ ItemPtr item;
+ int where_to, nearest_x, nearest_y;
+ int x, y;
+ int count;
+ int dx, dy;
+
+ direction = sgn(direction);
+
+ where_to = -1;
+ nearest_x = 99;
+ nearest_y = 99;
+
+ current = &dialog->item[dialog->active_item];
+ x = current->x;
+ y = current->y;
+
+ for (count = 0; count < dialog->num_items; count++) {
+ item = &dialog->item[count];
+ dx = item->x - x;
+ dy = item->y - y;
+ if (item->type != DD_I_MESSAGE) {
+ if (count != current->id) {
+ if ((sgn(dx) == direction) && (dy <= 0)) {
+ if (abs(dx) <= nearest_x) {
+ if ((abs(dx) < nearest_x) || (abs(dy) < nearest_y)) {
+ where_to = count;
+ nearest_x = abs(dx);
+ nearest_y = abs(dy);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (where_to >= 0) {
+ dialog_update_active(dialog, where_to - dialog->active_item, false, false);
+ } else {
+ dialog_update_active(dialog, direction, false, true);
+ }
+}
+
+void dialog_toggle_checkbox(DialogPtr dialog, ItemPtr item) {
+ int count;
+ int status, class_;
+ int return_code;
+ typedef int(*CallbackFn)(ItemPtr item, DialogPtr dialog);
+ CallbackFn callback;
+
+ if (item->status & DD_CHECK_RADIO) {
+ if (item->status & DD_CHECK_TRUE) goto done;
+ }
+
+ item->status ^= DD_CHECK_TRUE;
+ status = (item->status & DD_CHECK_TRUE);
+
+ dialog_update_active(dialog, 0, false, false);
+
+ if (status) {
+ class_ = item->_class;
+
+ for (count = 0; count < dialog->num_items; count++) {
+ if (dialog->item[count]._class == class_) {
+ if (dialog->item[count].id != item->id) {
+ if (dialog->item[count].status & DD_CHECK_TRUE) {
+ dialog->item[count].status &= (~DD_CHECK_TRUE);
+ dialog_update_any(dialog, &dialog->item[count], false);
+ }
+ }
+ }
+ }
+ }
+
+ if (dialog->checkbox_callback != NULL) {
+ callback = (CallbackFn)dialog->checkbox_callback;
+ return_code = callback(item, dialog);
+
+ if (return_code) {
+ dialog->status |= DD_EXITFLAG;
+ dialog_error = DD_ERR_ABORTEDBYCALLBACK;
+ }
+ }
+
+done:
+ ;
+}
+
+/**
+ * If a sub-string was being selected in the dialog box, cancel
+ * that selection.
+ */
+static void dialog_cancel_selection(DialogPtr dialog) {
+ ItemPtr item;
+ int buf;
+
+ item = &dialog->item[dialog->active_item];
+ buf = item->buf_id;
+
+ if (DialogString(dialog)) {
+ if (dialog->buf_select[buf]) {
+ dialog->buf_select[buf] = false;
+ if (dialog->buf_selbase[buf] != dialog->buf_seltarget[buf]) {
+ dialog_update_string(dialog, item);
+ }
+ }
+ }
+}
+
+/**
+ * If a substring was being selected in the dialog, erase that substring.
+ */
+static void dialog_wipe_selection(DialogPtr dialog) {
+ ItemPtr item;
+ int buf;
+ int buflen;
+ int from, unto;
+ char *src, *dest;
+ item = &dialog->item[dialog->active_item];
+ buf = item->buf_id;
+
+ if (DialogString(dialog)) {
+ if (dialog->buf_select[buf]) {
+ dialog_cancel_selection(dialog);
+ if (dialog->buf_selbase[buf] != dialog->buf_seltarget[buf]) {
+ if (dialog->buf_selbase[buf] < dialog->buf_seltarget[buf]) {
+ from = dialog->buf_selbase[buf];
+ unto = dialog->buf_seltarget[buf] - 1;
+ } else {
+ from = dialog->buf_seltarget[buf];
+ unto = dialog->buf_selbase[buf] - 1;
+ }
+ buflen = strlen(dialog->buffer[buf]);
+ if (from >= buflen) {
+ from = buflen - 1;
+ }
+ if (unto >= buflen) {
+ unto = buflen - 1;
+ }
+ if ((from >= 0) && (unto >= 0)) {
+ dest = &dialog->buffer[buf][from];
+ src = &dialog->buffer[buf][unto + 1];
+ *dest = 0x00;
+ Common::strcpy_s(dest, 65536, src);
+ dialog->buf_cursor[buf] = from;
+ dialog_update_string(dialog, item);
+ }
+ }
+ }
+ }
+}
+
+/**
+ * Routine to move the cursor within a string item
+ */
+static void dialog_move_cursor(DialogPtr dialog, int displace) {
+ ItemPtr item;
+ int buf;
+
+ item = &dialog->item[dialog->active_item];
+ buf = item->buf_id;
+
+ dialog_cancel_selection(dialog);
+
+ switch (displace) {
+ case DD_C_HOME:
+ dialog->buf_cursor[buf] = 0;
+ break;
+
+ case DD_C_END:
+ dialog->buf_cursor[buf] = strlen(dialog->buffer[buf]);
+ break;
+
+ default:
+ dialog->buf_cursor[buf] += displace;
+ break;
+ }
+
+ if (dialog->buf_cursor[buf] < 0) dialog->buf_cursor[buf] = 0;
+ if (dialog->buf_cursor[buf] > item->buf_width - 1) dialog->buf_cursor[buf] = item->buf_width - 1;
+
+ dialog_update_cursor(dialog);
+}
+
+/**
+ * Routine to insert a character into the active string item,
+ * at the current cursor location.
+ */
+static void dialog_string_insert(DialogPtr dialog, int mykey) {
+ ItemPtr item;
+ int buf;
+ char *dest, *src;
+ int buflen, count;
+
+ item = &dialog->item[dialog->active_item];
+ buf = item->buf_id;
+
+ if (DialogString(dialog)) {
+ if (dialog->buf_select[buf]) {
+ dialog_wipe_selection(dialog);
+ }
+
+ buflen = strlen(dialog->buffer[buf]);
+
+ if (dialog->buf_cursor[buf] > buflen) {
+ for (count = buflen; count < dialog->buf_cursor[buf]; count++) {
+ dialog->buffer[buf][count] = 0x20;
+ }
+ buflen = dialog->buf_cursor[buf];
+ }
+
+ if (dialog->buf_cursor[buf] == buflen) {
+ if (buflen < item->buf_width) {
+ dialog->buffer[buf][buflen++] = (char)mykey;
+ dialog->buffer[buf][buflen] = 0x00;
+ dialog->buf_cursor[buf]++;
+ }
+ } else {
+ if (cursor_mode == CURSOR_OVERWRITE) {
+ dialog->buffer[buf][dialog->buf_cursor[buf]++] = (char)mykey;
+ } else if (buflen < item->buf_width) {
+ dest = dialog->buffer[buf] + buflen + 1;
+ src = dest - 1;
+ count = (buflen - dialog->buf_cursor[buf]) + 1;
+ memmove(dest, src, count);
+ dialog->buffer[buf][dialog->buf_cursor[buf]++] = (char)mykey;
+ }
+ }
+
+ if (item->buf_width == 1) {
+ dialog->buf_select[buf] = true;
+ dialog->buf_selbase[buf] = 0;
+ dialog->buf_seltarget[buf] = 1;
+ dialog->buf_cursor[buf] = 0;
+ }
+
+ dialog_update_string(dialog, item);
+ dialog_update_cursor(dialog);
+ }
+}
+
+/**
+ * Routine to delete a character or selection from the active
+ * string item, at the current cursor location.
+ */
+static void dialog_string_delete(DialogPtr dialog) {
+ ItemPtr item;
+ int buf;
+
+ item = &dialog->item[dialog->active_item];
+ buf = item->buf_id;
+
+ if (DialogString(dialog)) {
+ if (!dialog->buf_select[buf]) {
+ if ((unsigned)dialog->buf_cursor[buf] < strlen(dialog->buffer[buf])) {
+ dialog->buf_select[buf] = true;
+ dialog->buf_selbase[buf] = dialog->buf_cursor[buf];
+ dialog->buf_seltarget[buf] = dialog->buf_cursor[buf] + 1;
+ }
+ }
+ dialog_wipe_selection(dialog);
+ dialog_update_cursor(dialog);
+ }
+}
+
+/**
+ * Routine to execute the "backspace key" function on the active
+ * string item
+ */
+static void dialog_string_backspace(DialogPtr dialog) {
+ ItemPtr item;
+ int buf;
+ char *dest, *src;
+ int buflen;
+
+ item = &dialog->item[dialog->active_item];
+ buf = item->buf_id;
+
+ if (DialogString(dialog)) {
+ if ((dialog->buf_cursor[buf] >= dialog->buf_selbase[buf]) &&
+ (dialog->buf_cursor[buf] >= dialog->buf_seltarget[buf])) {
+ dialog_cancel_selection(dialog);
+ }
+ dialog_wipe_selection(dialog);
+ if (dialog->buf_cursor[buf] > 0) {
+ buflen = strlen(dialog->buffer[buf]);
+ if (dialog->buf_cursor[buf] > buflen) {
+ dialog->buf_cursor[buf]--;
+ } else {
+ dest = &dialog->buffer[buf][dialog->buf_cursor[buf] - 1];
+ src = dest + 1;
+ Common::strcpy_s(dest, 65536, src);
+ dialog->buf_cursor[buf]--;
+ }
+ dialog_update_string(dialog, item);
+ }
+ dialog_update_cursor(dialog);
+ }
+}
+
+/**
+ * Routine to check if two strings are equivalent for at least
+ * the entire length of the second, shorter, string. Compare
+ * is done without regard for case.
+ */
+static int dialog_quick_compare(const char *big, const char *little) {
+ int biglen, litlen;
+ int count, going;
+ char biggie, littlie;
+
+ biglen = strlen(big);
+ litlen = strlen(little);
+
+ if (biglen >= litlen) {
+ going = true;
+ for (count = 0; going && (count < litlen); count++) {
+ biggie = *(big++);
+ littlie = *(little++);
+ going = (toupper(biggie) == toupper(littlie));
+ }
+ return going;
+ } else {
+ return false;
+ }
+}
+
+/**
+ * Routine to find the item in a list window that most closely matches
+ * a given string.
+ */
+static int dialog_quick_search(DialogPtr dialog, ItemPtr item, const char *checkstring) {
+ ListPtr list;
+ char *search;
+ int result;
+ int count;
+
+ list = &dialog->lists[item->buf_id];
+
+ result = -1;
+ if (!dialog_quicksearch_flag) goto done;
+
+ for (count = 0; (count < list->elements) && (result < 0); count++) {
+ search = list->list + (count * list->element_offset);
+ if (dialog_quick_compare(search, checkstring)) {
+ result = count;
+ }
+ }
+
+done:
+ return result;
+}
+
+/**
+ * Routine to perform the above quick-search function and load
+ * the appropriate string into the item's string entry area. The
+ * extra text of the found entry is loaded to the right of the cursor
+ * and is "selected" so that if the user types another letter key the
+ * extraneous text will be automatically removed.
+ */
+static void dialog_do_search(DialogPtr dialog, ItemPtr item) {
+ ItemPtr listitem;
+ ListPtr list;
+ int buf;
+ int match;
+ int mylen;
+ int newlen;
+ int count;
+
+ int case_magic;
+ int magic_number = 0;
+ int magic_upper = 0;
+
+ buf = item->buf_id;
+ listitem = &dialog->item[item->status];
+ list = &dialog->lists[listitem->buf_id];
+
+ match = dialog_quick_search(dialog, listitem, dialog->buffer[buf]);
+
+ /* Get an appropriate view of the window which will make our entry visible */
+
+ if (match >= 0) {
+ if ((match >= list->base_entry) && (match < (list->base_entry + (list->rows * list->columns)))) {
+ list->picked_entry = match;
+ } else {
+ list->picked_entry = match;
+ if (list->columns == 1) {
+ list->base_entry = list->picked_entry;
+ } else {
+ if (list->base_entry < list->picked_entry) {
+ while (list->picked_entry >= (list->base_entry + (list->rows * list->columns))) {
+ list->base_entry += list->rows;
+ }
+ } else {
+ while (list->picked_entry < list->base_entry) {
+ list->base_entry -= list->rows;
+ if (list->base_entry < 0) list->base_entry = 0;
+ }
+ }
+ }
+ }
+
+ allow_list_callbacks = true;
+
+ dialog_update_any(dialog, listitem, false);
+
+ allow_list_callbacks = false;
+
+ mylen = strlen(dialog->buffer[buf]);
+
+ Common::strcpy_s(temp_buf, dialog->buffer[buf]);
+ strncpy(dialog->buffer[buf], list->list + (list->element_offset * list->picked_entry), item->buf_width);
+ dialog->buffer[buf][item->buf_width] = 0;
+
+ for (count = 0; count < mylen; count++) {
+ dialog->buffer[buf][count] = temp_buf[count];
+ }
+
+ newlen = strlen(dialog->buffer[buf]);
+
+ /* Now, "case magic" attempts to conform the case of the searched-in */
+ /* string to the case format that the user is typing. */
+
+ case_magic = false;
+
+ if (mylen > 0) {
+ if ((mylen > 1) && (Common::isAlpha(dialog->buffer[buf][1]))) {
+ magic_number = 1;
+ case_magic = true;
+ } else if (Common::isAlpha(dialog->buffer[buf][0])) {
+ magic_number = 0;
+ case_magic = true;
+ }
+ }
+
+ if (case_magic) {
+ magic_upper = (Common::isUpper(dialog->buffer[buf][magic_number]));
+ }
+
+ for (count = mylen; (case_magic) && (count < newlen); count++) {
+ if (magic_upper) {
+ dialog->buffer[buf][count] = (char)toupper((char)dialog->buffer[buf][count]);
+ } else {
+ dialog->buffer[buf][count] = (char)tolower((char)dialog->buffer[buf][count]);
+ }
+ }
+
+ dialog->buf_select[buf] = true;
+ dialog->buf_selbase[buf] = mylen;
+ dialog->buf_seltarget[buf] = newlen;
+
+ if (item->buf_width == 1) {
+ dialog->buf_selbase[buf] = 0;
+ dialog->buf_seltarget[buf] = 1;
+ }
+
+ dialog_update_any(dialog, item, false);
+ }
+}
+
+/**
+ * Routine to change the directory of the filename window
+ */
+static void dialog_set_new_directory(DialogPtr dialog, ItemPtr item) {
+ int buf;
+ //int newdrive;
+ ItemPtr baseitem, fileitem, pathitem;
+
+ baseitem = &dialog->item[item->status];
+ fileitem = &dialog->item[baseitem->status];
+ buf = baseitem->buf_id;
+
+ Common::strcpy_s(temp_buf, dialog->buffer[buf]);
+ pathitem = dialog->path_item;
+#ifdef TODO
+ if (temp_buf[1] == ':') {
+ /* Change to a new drive, if requested */
+ newdrive = ((int)temp_buf[0]) - 64;
+ mads_chdrive(newdrive);
+
+ dialog_clear_message(dialog, pathitem);
+ //mads_getcwd(temp_buf, DIALOG_MAX_PROMPT_CHARS);
+ Common::strcpy_s(temp_buf, "");
+ Common::strcpy_s(pathitem->prompt, 65536, temp_buf);
+
+ } else {
+ /* otherwise, change to a new directory */
+ mads_chdir(temp_buf);
+
+ dialog_clear_message(dialog, pathitem);
+
+ if (mads_getcwd(temp_buf, DIALOG_MAX_PROMPT_CHARS) != NULL) {
+ Common::strcpy_s(pathitem->prompt, temp_buf);
+ } else {
+ Common::strcpy_s(temp_buf, pathitem->prompt);
+ mads_chdir(temp_buf);
+ }
+ }
+
+ /* Load a wildcard into the entry area */
+
+ if ((strchr(dialog->buffer[buf], '*') == NULL) &&
+ (strchr(dialog->buffer[buf], '?') == NULL)) {
+ Common::strcpy_s(dialog->buffer[buf], "*.*");
+ dialog->buf_select[buf] = true;
+ dialog->buf_cursor[buf] = 0;
+ dialog->buf_selbase[buf] = 0;
+ dialog->buf_seltarget[buf] = 3;
+ }
+
+ /* Load up the new directory and display */
+
+ dialog_load_directory(dialog, baseitem);
+ dialog_show_any(dialog, pathitem);
+ dialog_update_any(dialog, baseitem, false);
+ dialog_update_any(dialog, fileitem, false);
+ dialog_update_any(dialog, item, false);
+ dialog_update_active(dialog, 0, false, false);
+#else
+ warning("TODO: dialog_set_new_directory");
+#endif
+}
+
+/**
+ * Routine to handle scrolling around in a list window. Used to
+ * drive both mouse and cursor scroll routines.
+ */
+static void dialog_scroll_list(DialogPtr dialog, ItemPtr item, int direction) {
+ int my_dif, my_col, my_row;
+ int scroll_factor;
+ ListPtr list;
+
+ list = &dialog->lists[item->buf_id];
+
+ if (list->picked_entry < 0) {
+ list->picked_entry = list->base_entry;
+ } else {
+ my_dif = list->picked_entry - list->base_entry;
+ my_col = my_dif / list->rows;
+ my_row = my_dif % list->rows;
+
+ switch (direction) {
+ case DD_MC_SCROLL_UP:
+ if (my_row > 0) {
+ list->picked_entry--;
+ } else {
+ if ((list->columns == 1) && (list->base_entry > 0)) {
+ list->base_entry--;
+ list->picked_entry--;
+ }
+ }
+ break;
+
+ case DD_MC_SCROLL_DOWN:
+ if (my_row < list->rows - 1) {
+ if (list->picked_entry < list->elements - 1) {
+ list->picked_entry++;
+ } else {
+ if ((list->columns == 1) && (list->base_entry < list->elements - 1)) {
+ list->base_entry++;
+ }
+ }
+ } else {
+ if ((list->columns == 1) && (list->base_entry < list->elements - 1)) {
+ list->base_entry++;
+ list->picked_entry++;
+ if (list->picked_entry >= list->elements) list->picked_entry = list->elements - 1;
+ }
+ }
+ break;
+
+ case DD_MC_SCROLL_LEFT:
+ if (my_col > 0) {
+ list->picked_entry -= list->rows;
+ } else {
+ if ((list->columns > 1) && (list->base_entry > 0)) {
+ list->base_entry -= list->rows;
+ list->picked_entry -= list->rows;
+ if (list->base_entry < 0) list->base_entry = 0;
+ if (list->picked_entry < 0) list->picked_entry = 0;
+ }
+ }
+ break;
+
+ case DD_MC_SCROLL_RIGHT:
+ if (my_col < list->columns - 1) {
+ list->picked_entry += list->rows;
+ if (list->picked_entry >= list->elements) {
+ list->picked_entry = list->elements - 1;
+ }
+ } else {
+ if ((list->columns > 1) && (list->base_entry < list->elements - 1)) {
+ list->base_entry += list->rows;
+ list->picked_entry += list->rows;
+ if (list->base_entry >= list->elements) {
+ list->base_entry -= list->rows;
+ }
+ if (list->picked_entry >= list->elements) {
+ list->picked_entry = list->elements - 1;
+ }
+ }
+ }
+ break;
+
+ case DD_MC_SCROLL_PAGE_UP:
+ list->base_entry -= list->rows;
+ if (list->base_entry < 0) {
+ list->base_entry = 0;
+ list->picked_entry = 0;
+ } else {
+ if ((list->picked_entry - list->base_entry) >= list->rows) {
+ list->picked_entry = list->base_entry + list->rows - 1;
+ } else {
+ list->picked_entry = list->base_entry;
+ }
+ }
+ break;
+
+ case DD_MC_SCROLL_PAGE_DOWN:
+ list->base_entry += list->rows;
+ if (list->base_entry >= list->elements) {
+ list->base_entry = list->elements - 1;
+ list->picked_entry = list->elements - 1;
+ } else {
+ if (list->picked_entry < list->base_entry) {
+ list->picked_entry = list->base_entry;
+ } else {
+ list->picked_entry = list->base_entry + list->rows - 1;
+ if (list->picked_entry >= list->elements) {
+ list->picked_entry = list->elements;
+ }
+ }
+ }
+ break;
+
+ case DD_MC_SCROLL_PAGE_LEFT:
+ scroll_factor = list->rows * (list->columns - 1);
+ list->base_entry -= scroll_factor;
+ list->picked_entry -= scroll_factor;
+ if (list->base_entry < 0) list->base_entry = 0;
+ if (list->picked_entry < list->base_entry) list->picked_entry = list->base_entry;
+ break;
+
+ case DD_MC_SCROLL_PAGE_RIGHT:
+ scroll_factor = list->rows * (list->columns - 1);
+ if (list->base_entry + scroll_factor < list->elements) {
+ list->base_entry += scroll_factor;
+ list->picked_entry += scroll_factor;
+ if (list->picked_entry >= list->elements) {
+ list->picked_entry = list->elements - 1;
+ }
+ } else {
+ list->picked_entry = list->elements - 1;
+ }
+ break;
+ }
+ }
+}
+
+/**
+ * Routine to allow keyboard scrolling within a list window
+ */
+static void dialog_key_exec_list(DialogPtr dialog, ItemPtr item, int mykey) {
+ ItemPtr baseitem;
+ ListPtr list;
+ int buf;
+
+ switch (mykey) {
+ case up_key:
+ dialog_scroll_list(dialog, item, DD_MC_SCROLL_UP);
+ break;
+
+ case down_key:
+ dialog_scroll_list(dialog, item, DD_MC_SCROLL_DOWN);
+ break;
+
+ case left_key:
+ dialog_scroll_list(dialog, item, DD_MC_SCROLL_LEFT);
+ break;
+
+ case right_key:
+ dialog_scroll_list(dialog, item, DD_MC_SCROLL_RIGHT);
+ break;
+
+ case pgup_key:
+ list = &dialog->lists[item->buf_id];
+ if (list->columns > 1) {
+ dialog_scroll_list(dialog, item, DD_MC_SCROLL_PAGE_LEFT);
+ } else {
+ dialog_scroll_list(dialog, item, DD_MC_SCROLL_PAGE_UP);
+ }
+ break;
+
+ case pgdn_key:
+ list = &dialog->lists[item->buf_id];
+ if (list->columns > 1) {
+ dialog_scroll_list(dialog, item, DD_MC_SCROLL_PAGE_RIGHT);
+ } else {
+ dialog_scroll_list(dialog, item, DD_MC_SCROLL_PAGE_DOWN);
+ }
+ break;
+ }
+
+ baseitem = &dialog->item[item->status];
+ list = &dialog->lists[item->buf_id];
+ buf = baseitem->buf_id;
+ strncpy(dialog->buffer[buf], list->list + (list->picked_entry * list->element_offset), baseitem->buf_width);
+ dialog->buffer[buf][baseitem->buf_width] = 0;
+ fileio_purge_trailing_spaces(dialog->buffer[buf]);
+ allow_list_callbacks = true;
+ dialog_update_any(dialog, baseitem, false);
+ dialog_update_active(dialog, 0, false, false);
+ allow_list_callbacks = false;
+}
+
+/**
+ * Returns true if the mouse is in the specified item.
+ */
+static int in_item(DialogPtr dialog, int count) {
+ ItemPtr item;
+ ListPtr list;
+ int result;
+
+ item = &dialog->item[count];
+
+ switch (item->type) {
+ case DD_I_MESSAGE:
+ result = false;
+ break;
+
+ case DD_I_BUTTON:
+ if (item->y == DD_IY_BUTTON) {
+ result = mouse_in_box(dialog->base_x + item->x, dialog->window.lr_y - 1,
+ dialog->base_x + item->x + item->width - 1, dialog->window.lr_y);
+ } else {
+ result = mouse_in_box(dialog->base_x + item->x, dialog->base_y + item->y,
+ dialog->base_x + item->x + item->width - 1, dialog->base_y + item->y);
+ }
+ break;
+
+ case DD_I_CHECKBOX:
+ result = mouse_in_box(dialog->base_x + item->x, dialog->base_y + item->y,
+ dialog->base_x + item->x + item->width - 1, dialog->base_y + item->y);
+ break;
+
+ case DD_I_STRING:
+ case DD_I_LISTBASED:
+ case DD_I_FILENAME:
+ result = mouse_in_box(dialog->base_x + item->x2, dialog->base_y + item->y,
+ dialog->base_x + item->x2 + item->buf_width, dialog->base_y + item->y);
+ break;
+
+ case DD_I_LIST:
+ case DD_I_FILELIST:
+ case DD_I_DIRSLIST:
+ list = &dialog->lists[item->buf_id];
+ result = mouse_in_box(list->base_x, list->base_y,
+ list->window.lr_x, list->window.lr_y);
+ if ((mouse_x == list->window.lr_x) && (mouse_y == list->window.lr_y)) {
+ result = false;
+ }
+ if (list->elements == 0) result = false;
+
+ break;
+
+ default:
+ result = false;
+ break;
+ }
+
+ return result;
+}
+
+/**
+ * If the mouse has been pressed within a scroll bar area, returns
+ * the proper type of action to be taken.
+ */
+static int in_scroll_box(ListPtr list, int button) {
+ int result;
+ int relx, rely;
+
+ result = 0;
+
+ if (list->columns > 1) {
+ if (mouse_in_box(list->window.ul_x + 1, list->window.lr_y,
+ list->window.lr_x - 1, list->window.lr_y)) {
+ if (mouse_x == list->window.ul_x + 1) {
+ result = DD_MC_SCROLL_LEFT;
+ } else if (mouse_x == list->window.lr_x - 1) {
+ result = DD_MC_SCROLL_RIGHT;
+ } else {
+ relx = mouse_x - (list->window.ul_x + 2);
+ if (((relx < list->thumb) || ((relx == list->thumb) && (mouse_stroke_type == DD_MC_SCROLL_PAGE_LEFT) && (!mouse_start_stroke))) && (button == 0)) {
+ result = DD_MC_SCROLL_PAGE_LEFT;
+ } else if (((relx > list->thumb) || ((relx == list->thumb) && (mouse_stroke_type == DD_MC_SCROLL_PAGE_RIGHT) && (!mouse_start_stroke))) && (button == 0)) {
+ result = DD_MC_SCROLL_PAGE_RIGHT;
+ } else {
+ result = DD_MC_SCROLL;
+ }
+ }
+ }
+ } else {
+ if (mouse_in_box(list->window.lr_x, list->window.ul_y + 1,
+ list->window.lr_x, list->window.lr_y - 1)) {
+ if (mouse_y == list->window.ul_y + 1) {
+ result = DD_MC_SCROLL_UP;
+ } else if (mouse_y == list->window.lr_y - 1) {
+ result = DD_MC_SCROLL_DOWN;
+ } else {
+ rely = mouse_y - (list->window.ul_y + 2);
+ if (((rely < list->thumb) || ((rely == list->thumb) && (mouse_stroke_type == DD_MC_SCROLL_PAGE_UP) && (!mouse_start_stroke))) && (button == 0)) {
+ result = DD_MC_SCROLL_PAGE_UP;
+ } else if (((rely > list->thumb) || ((rely == list->thumb) && (mouse_stroke_type == DD_MC_SCROLL_PAGE_DOWN) && (!mouse_start_stroke))) && (button == 0)) {
+ result = DD_MC_SCROLL_PAGE_DOWN;
+ } else {
+ result = DD_MC_SCROLL;
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+/**
+ * Routine to handle selection of a substring with the mouse
+ */
+static void dialog_exec_mouse_string(DialogPtr dialog, ItemPtr item) {
+ int buf;
+
+ if (mouse_y == (dialog->base_y + item->y)) {
+ buf = item->buf_id;
+ dialog->buf_cursor[buf] = mouse_x - (dialog->base_x + item->x2);
+ if (dialog->buf_cursor[buf] < 0) dialog->buf_cursor[buf] = 0;
+ if (dialog->buf_cursor[buf] > item->buf_width) dialog->buf_cursor[buf] = item->buf_width;
+ if (mouse_start_stroke) {
+ if (dialog->active_item != item->id) {
+ dialog->buf_select[buf] = true;
+ dialog->buf_selbase[buf] = 0;
+ dialog->buf_seltarget[buf] = strlen(dialog->buffer[buf]);
+ dialog->buf_cursor[buf] = dialog->buf_seltarget[buf];
+ } else {
+ dialog->buf_select[buf] = true;
+ dialog->buf_selbase[buf] = dialog->buf_cursor[buf];
+ dialog->buf_seltarget[buf] = dialog->buf_cursor[buf];
+ }
+ } else {
+ dialog->buf_seltarget[buf] = dialog->buf_cursor[buf];
+ }
+ }
+}
+
+/**
+ * Routine to deal with the mouse when it is doing something
+ * in a list window (clicking, double-clicking, or dragging).
+ */
+static void dialog_exec_mouse_list(DialogPtr dialog, ItemPtr item) {
+ ListPtr list;
+ ItemPtr baseitem;
+ int test;
+ int looking, look_x, look_y, look_x2, look_y2;
+ int row, col;
+ int buf;
+ int old_pick;
+ int abort;
+ static long mouse_list_timing;
+ static long mouse_drag_timing;
+
+ if (mouse_start_stroke) mouse_drag_timing = timer_read_dos() + MOUSE_TIMING_TWO;
+
+ list = &dialog->lists[item->buf_id];
+ test = in_scroll_box(list, mouse_button);
+ if (test && mouse_start_stroke) {
+ mouse_stroke_type = test;
+ mouse_scroll_list = list;
+ mouse_scroll_item = item;
+ } else {
+ looking = true;
+
+ /* Find out which list entry is being picked */
+
+ for (col = 0; (col < list->columns) && (looking); col++) {
+ for (row = 0; (row < list->rows) && (looking); row++) {
+ look_x = list->base_x + ((list->entry_width + 1) * col);
+ look_x2 = look_x + list->entry_width + 1;
+ look_y = list->base_y + row;
+ look_y2 = look_y;
+ if (list->columns == 1) {
+ if (col == 0) look_x = 0;
+ if (col == list->columns - 1) look_x2 = screen_max_x;
+ } else {
+ if (row == 0) look_y = 0;
+ if (row == list->rows - 1) look_y2 = screen_max_y;
+ }
+
+ if (mouse_in_box(look_x, look_y, look_x2, look_y2)) {
+ looking = false;
+ old_pick = list->picked_entry;
+ list->picked_entry = list->base_entry + row + (col * list->rows);
+ if (list->picked_entry >= list->elements) {
+ list->picked_entry = list->elements - 1;
+ }
+
+ abort = false;
+
+ /* Handle double-click if any */
+
+ if (mouse_start_stroke && (old_pick == list->picked_entry)) {
+ if ((long)timer_read_dos() <= mouse_list_timing + MOUSE_DOUBLE_TIMING) {
+ if (item->type == DD_I_DIRSLIST) {
+ dialog_set_new_directory(dialog, item);
+ abort = true;
+ } else {
+ dialog->active_item = (dialog->default_item)->id;
+ dialog->status |= DD_EXITFLAG;
+ }
+ }
+ }
+ if (mouse_start_stroke) mouse_list_timing = timer_read_dos();
+
+ if (!abort) {
+ baseitem = &dialog->item[item->status];
+ buf = baseitem->buf_id;
+ strncpy(dialog->buffer[buf], list->list + (list->picked_entry * list->element_offset), baseitem->buf_width);
+ dialog->buffer[buf][baseitem->buf_width] = 0;
+ fileio_purge_trailing_spaces(dialog->buffer[buf]);
+ dialog_update_any(dialog, baseitem, false);
+ }
+ }
+ }
+ }
+
+ /* Handle click-and-drag */
+
+ if (looking && (mouse_start_stroke || ((long)timer_read_dos() >= mouse_drag_timing))) {
+ mouse_override = true;
+ mouse_drag_timing = (long)timer_read_dos() + MOUSE_TIMING_TWO;
+ if (list->columns > 1) {
+ if (mouse_x < list->base_x) {
+ dialog_scroll_list(dialog, item, DD_MC_SCROLL_LEFT);
+ } else if (mouse_x >= list->base_x + ((list->entry_width + 1) * list->columns)) {
+ dialog_scroll_list(dialog, item, DD_MC_SCROLL_RIGHT);
+ }
+ } else {
+ if (mouse_y < list->base_y) {
+ dialog_scroll_list(dialog, item, DD_MC_SCROLL_UP);
+ } else if (mouse_y >= list->base_y + list->rows) {
+ dialog_scroll_list(dialog, item, DD_MC_SCROLL_DOWN);
+ }
+ }
+ baseitem = &dialog->item[item->status];
+ buf = baseitem->buf_id;
+ strncpy(dialog->buffer[buf], list->list + (list->picked_entry * list->element_offset), baseitem->buf_width);
+ dialog->buffer[buf][baseitem->buf_width] = 0;
+ fileio_purge_trailing_spaces(dialog->buffer[buf]);
+ dialog_update_any(dialog, baseitem, false);
+ }
+ }
+}
+
+/**
+ * Deals with the mouse when it is in a scroll bar. Calls
+ * dialog_scroll_list () for most functions, but handles click-and-drag
+ * on the thumb mark itself.
+ */
+static void dialog_exec_mouse_scroll(DialogPtr dialog, ItemPtr item) {
+ ListPtr list;
+ ItemPtr baseitem;
+ int buf;
+ int mouse_thumb, dist;
+ int now_scroll;
+
+ list = mouse_scroll_list;
+ now_scroll = in_scroll_box(mouse_scroll_list, mouse_button);
+ if (mouse_stroke_type != DD_MC_SCROLL) {
+ if (list->picked_entry < 0) list->picked_entry = list->base_entry;
+ if (mouse_stroke_type == now_scroll) {
+ dialog_scroll_list(dialog, item, mouse_stroke_type);
+ }
+ } else {
+ if (list->columns > 1) {
+ mouse_thumb = mouse_x - (list->window.ul_x + 2);
+ dist = list->window.lr_x - list->window.ul_x - 4;
+
+ if (mouse_thumb < 0) mouse_thumb = 0;
+ if (mouse_thumb >= dist) mouse_thumb = dist;
+
+ if ((mouse_thumb != list->thumb) || (mouse_button == 1) || (mouse_start_stroke)) {
+ if (mouse_thumb == 0) {
+ list->base_entry = 0;
+ list->picked_entry = 0;
+ } else if (mouse_thumb >= dist - 1) {
+ list->picked_entry = list->elements - 1;
+ while (list->picked_entry >= list->base_entry + (list->rows * list->columns)) {
+ list->base_entry += list->rows;
+ }
+ } else {
+ list->picked_entry = (mouse_thumb * list->elements) / dist;
+ while (list->picked_entry < list->base_entry) {
+ list->base_entry -= list->rows;
+ if (list->base_entry < 0) list->base_entry = 0;
+ }
+ while (list->picked_entry >= (list->base_entry + (list->rows * list->columns))) {
+ list->base_entry += list->rows;
+ }
+ }
+ }
+
+ } else {
+ mouse_thumb = mouse_y - (list->window.ul_y + 2);
+ dist = list->window.lr_y - list->window.ul_y - 4;
+
+ if (mouse_thumb < 0) mouse_thumb = 0;
+ if (mouse_thumb >= dist) mouse_thumb = dist;
+
+ if ((mouse_thumb != list->thumb) || (mouse_button == 1)) {
+ if (mouse_thumb == 0) {
+ list->base_entry = 0;
+ list->picked_entry = 0;
+ } else if (mouse_thumb >= dist - 1) {
+ list->base_entry = list->elements - list->rows;
+ list->picked_entry = list->elements - 1;
+ if (list->base_entry < 0) list->base_entry = 0;
+ } else {
+ list->picked_entry = (mouse_thumb * list->elements) / dist;
+ if (list->picked_entry < list->base_entry) list->base_entry = list->picked_entry;
+ if (list->picked_entry >= (list->base_entry + list->rows)) {
+ list->base_entry = (list->picked_entry - list->rows) + 1;
+ }
+ }
+ }
+ }
+ }
+
+ baseitem = &dialog->item[mouse_scroll_item->status];
+ buf = baseitem->buf_id;
+ strncpy(dialog->buffer[buf], list->list + (list->picked_entry * list->element_offset), baseitem->buf_width);
+ dialog->buffer[buf][baseitem->buf_width] = 0;
+ fileio_purge_trailing_spaces(dialog->buffer[buf]);
+ dialog_update_any(dialog, baseitem, false);
+}
+
+void dialog_set_stroke_type(DialogPtr dialog, int type, int toggle) {
+ mouse_stroke_type = type;
+ if (toggle) {
+ dialog_toggle_checkbox(dialog, &dialog->item[type]);
+ }
+}
+
+/**
+ * Called whenever a mouse stroke is detected; loops until the
+ * mouse button is released. Performs whatever actions are necessary
+ * to execute the mouse function.
+ */
+static void dialog_exec_mouse(DialogPtr dialog) {
+ int count, count2;
+ int refresh;
+ int radio, s1, s2;
+ ItemPtr item = nullptr;
+ long mouse_scroll_clock;
+ long mouse_ballistic_clock;
+
+ mouse_init_cycle();
+
+ mouse_stroke_going = false; /* (so that "start stroke" will be true) */
+
+ mouse_stroke_type = DD_MC_NONE;
+ mouse_override = false;
+
+ mouse_scroll_clock = 0;
+ mouse_ballistic_clock = 0;
+
+ do {
+ mouse_begin_cycle(false);
+
+ if (mouse_changed ||
+ (mouse_stroke_type < DD_MC_SCROLL) || (mouse_override)) {
+
+ resolved_mouse = false;
+
+ for (count = 0; (count < dialog->num_items) && (!resolved_mouse); count++) {
+ if (in_item(dialog, count)) {
+ if (mouse_start_stroke) {
+ radio = (dialog->item[count].type == DD_I_CHECKBOX) &&
+ (dialog->item[count].status & DD_CHECK_RADIO) != 0;
+ if (radio) {
+ for (count2 = 0; count2 < dialog->num_items; count2++) {
+ if (dialog->item[count2].type == DD_I_CHECKBOX) {
+ if (dialog->item[count2]._class == dialog->item[count]._class) {
+ if (dialog->item[count2].status & DD_CHECK_TRUE) {
+ mouse_orig_stroke_type = count2;
+ }
+ }
+ }
+ }
+ }
+ dialog_set_stroke_type(dialog, count, radio);
+ } else if ((dialog->item[count].type == DD_I_BUTTON) &&
+ (dialog->item[mouse_stroke_type].type == DD_I_BUTTON)) {
+ dialog_set_stroke_type(dialog, count, false);
+ } else if ((dialog->item[count].type == DD_I_CHECKBOX) &&
+ (dialog->item[mouse_stroke_type].type == DD_I_CHECKBOX)) {
+ s1 = dialog->item[count].status;
+ s2 = dialog->item[mouse_stroke_type].status;
+ if ((s1 & DD_CHECK_RADIO) == (s2 & DD_CHECK_RADIO)) {
+ if (s1 & DD_CHECK_RADIO) {
+ if (dialog->item[count]._class == dialog->item[mouse_stroke_type]._class) {
+ dialog_set_stroke_type(dialog, count, !mouse_stop_stroke);
+ }
+ } else {
+ dialog_set_stroke_type(dialog, count, false);
+ }
+ }
+ }
+ if (mouse_stroke_type == count) {
+ resolved_mouse = true;
+ }
+ }
+ }
+
+ if (mouse_stroke_type != DD_MC_NONE) {
+ refresh = false;
+ if (mouse_stroke_type >= 0) {
+ item = &dialog->item[mouse_stroke_type];
+ if ((item->type == DD_I_BUTTON) || (item->type == DD_I_CHECKBOX)) {
+ refresh = true;
+ }
+ if ((item->type == DD_I_STRING) || (item->type == DD_I_LISTBASED) || (item->type == DD_I_FILENAME)) {
+ dialog_exec_mouse_string(dialog, item);
+ refresh = true;
+ }
+ if ((item->type == DD_I_LIST) || (item->type == DD_I_FILELIST) || (item->type == DD_I_DIRSLIST)) {
+ dialog_exec_mouse_list(dialog, item);
+ refresh = true;
+ }
+ }
+ if (mouse_stroke_type <= DD_MC_SCROLL) {
+
+ item = mouse_scroll_item;
+
+ if (mouse_start_stroke ||
+ ((long)timer_read_dos() >= mouse_scroll_clock)) {
+ dialog_exec_mouse_scroll(dialog, item);
+ refresh = true;
+ }
+
+ if (refresh) {
+ if (mouse_start_stroke) {
+ mouse_scroll_clock = timer_read_dos() + MOUSE_TIMING_ONE;
+ mouse_ballistic_clock = timer_read_dos() + MOUSE_BALLISTIC_TIMING;
+ } else {
+ if ((long)timer_read_dos() < mouse_ballistic_clock) {
+ mouse_scroll_clock = timer_read_dos() + MOUSE_TIMING_TWO;
+ }
+ }
+ }
+ }
+ if (refresh && (!(dialog->status & DD_EXITFLAG)))
+ dialog_update_active(dialog, item->id - dialog->active_item, true, false);
+ }
+ }
+
+ stroke_going = mouse_stroke_going && (!(dialog->status & DD_EXITFLAG));
+
+ mouse_end_cycle(false, true);
+
+ } while (stroke_going);
+
+ allow_list_callbacks = true;
+
+ dialog_update_active(dialog, 0, false, false);
+
+ allow_list_callbacks = false;
+
+ if (mouse_stroke_type >= 0) {
+ if (in_item(dialog, mouse_stroke_type)) {
+ item = &dialog->item[mouse_stroke_type];
+
+ switch (item->type) {
+ case DD_I_BUTTON:
+ dialog->status |= DD_EXITFLAG;
+ break;
+
+ case DD_I_CHECKBOX:
+ dialog_toggle_checkbox(dialog, item);
+ break;
+
+ }
+ } else {
+ if ((dialog->item[mouse_orig_stroke_type].type == DD_I_CHECKBOX) &&
+ (dialog->item[mouse_orig_stroke_type].status & DD_CHECK_RADIO)) {
+ dialog_toggle_checkbox(dialog, &dialog->item[mouse_orig_stroke_type]);
+ dialog_update_any(dialog, &dialog->item[mouse_orig_stroke_type], false);
+ }
+ }
+ }
+}
+
+ItemPtr dialog_execute(DialogPtr dialog, ItemPtr active_item, ItemPtr default_button, KeyPtr key_buffer) {
+ int mykey;
+ int count;
+ int buf;
+ int savedpath;
+ int savedrive = 0;
+ int return_code;
+ char savepath[80];
+ char mypath[80];
+ char mypath2[80];
+ long base_time;
+ long now_time;
+ long my_timeout;
+ long diff;
+ int mydrive;
+ ItemPtr item;
+ struct KeyBuffer tempkey;
+
+ allow_list_callbacks = false;
+
+ if (key_buffer == NULL) {
+ key_buffer = &tempkey;
+ tempkey.len = 0;
+ }
+
+ if (dialog->status & DD_FILEMENU) {
+ savedpath = (mads_getcwd(savepath, 80) != NULL);
+ savedrive = mads_getdrive();
+
+ if (dialog->path_item != NULL) {
+ Common::strcpy_s(mypath, (dialog->path_item)->prompt);
+ mads_fullpath(mypath2, mypath, 80);
+ mydrive = ((int)mypath2[0]) - '@';
+ mads_chdrive(mydrive);
+ mads_chdir(mypath2);
+ }
+ }
+
+ return_code = false;
+
+ if (dialog->cancel_item == NULL) dialog->cancel_item = default_button;
+
+ if (default_button == NULL) {
+ dialog->default_item = dialog->cancel_item;
+ dialog->active_button = (dialog->cancel_item)->id;
+ } else {
+ dialog->default_item = default_button;
+ dialog->active_button = default_button->id;
+ }
+
+ if (active_item != NULL) {
+ dialog->active_item = active_item->id;
+ }
+
+ dialog_show_all(dialog);
+
+ dialog_update_active(dialog, 0, false, false);
+
+ mouse_init_cycle();
+
+ base_time = timer_read_dos();
+
+ my_timeout = dialog_timeout;
+
+ while (!(dialog->status & DD_EXITFLAG)) {
+
+ if (my_timeout) {
+ now_time = timer_read_dos();
+ diff = (now_time - base_time);
+ if (diff >= 0) my_timeout--;
+ if (!my_timeout) dialog->status |= DD_EXITFLAG;
+ base_time = now_time;
+ }
+
+ mouse_begin_cycle(true);
+
+ keys_fill_buffer(key_buffer);
+
+ mykey = keys_read_buffer(key_buffer);
+
+ item = &dialog->item[dialog->active_item];
+
+ if (mykey && !DialogString(dialog)) {
+
+ switch (mykey) {
+ case esc_key:
+ dialog->status |= DD_EXITFLAG;
+ dialog->active_item = (dialog->cancel_item)->id;
+ break;
+
+ case tab_key:
+ dialog_update_active(dialog, +1, false, true);
+ break;
+
+ case backtab_key:
+ dialog_update_active(dialog, -1, false, true);
+ break;
+
+ case space_key:
+ switch (item->type) {
+ case DD_I_BUTTON:
+ dialog->status |= DD_EXITFLAG;
+ break;
+ case DD_I_CHECKBOX:
+ dialog_toggle_checkbox(dialog, item);
+ break;
+ }
+ break;
+
+ case up_key:
+ case down_key:
+ case left_key:
+ case right_key:
+ case pgup_key:
+ case pgdn_key:
+ switch (item->type) {
+ case DD_I_LIST:
+ case DD_I_FILELIST:
+ case DD_I_DIRSLIST:
+ dialog_key_exec_list(dialog, item, mykey);
+ break;
+
+ default:
+ switch (mykey) {
+ case up_key:
+ dialog_update_active(dialog, -1, false, false);
+ break;
+
+ case down_key:
+ dialog_update_active(dialog, +1, false, false);
+ break;
+
+ case right_key:
+ dialog_go_sideways(dialog, +1);
+ break;
+
+ case left_key:
+ dialog_go_sideways(dialog, -1);
+ break;
+ }
+ break;
+ }
+ break;
+
+ case enter_key:
+ switch (item->type) {
+ case DD_I_DIRSLIST:
+ dialog_set_new_directory(dialog, item);
+ break;
+
+ case DD_I_BUTTON:
+ dialog->status |= DD_EXITFLAG;
+ break;
+
+ default:
+ dialog->active_item = (dialog->default_item)->id;
+ dialog->status |= DD_EXITFLAG;
+ break;
+ }
+ break;
+
+ case ctrl_q_key:
+ dialog_quicksearch_flag = !dialog_quicksearch_flag;
+ break;
+
+ default:
+ mykey = keys_fix_alt(mykey);
+ if (Common::isPrint(mykey) && (mykey < 0x100)) {
+ for (count = 0; count < dialog->num_items; count++) {
+ if (toupper(mykey) == toupper(dialog->item[count].keystroke)) {
+ dialog_update_active(dialog, count - dialog->active_item, false, false);
+ item = &dialog->item[dialog->active_item];
+ switch (item->type) {
+
+ case DD_I_BUTTON:
+ dialog->status |= DD_EXITFLAG;
+ break;
+
+ case DD_I_CHECKBOX:
+ dialog_toggle_checkbox(dialog, item);
+ break;
+ }
+ }
+ }
+ }
+ break;
+ }
+
+ } else if (mykey) {
+ switch (mykey) {
+ case esc_key:
+ dialog->status |= DD_EXITFLAG;
+ dialog->active_item = (dialog->cancel_item)->id;
+ break;
+
+ case enter_key:
+ switch (item->type) {
+ case DD_I_FILENAME:
+ buf = item->buf_id;
+ if (((strchr(dialog->buffer[buf], '*') != NULL) ||
+ (strchr(dialog->buffer[buf], '?') != NULL)) &&
+ !dialog_wildcard_exits) {
+ dialog_load_directory(dialog, item);
+ dialog->buf_select[buf] = true;
+ dialog->buf_selbase[buf] = 0;
+ dialog->buf_seltarget[buf] = strlen(dialog->buffer[buf]);
+ dialog_update_active(dialog, 0, false, false);
+ dialog_update_any(dialog, &dialog->item[item->status], false);
+ dialog_update_any(dialog, &dialog->item[item->status + 1], false);
+ } else {
+ dialog->status |= DD_EXITFLAG;
+ }
+ break;
+
+ default:
+ dialog->status |= DD_EXITFLAG;
+ break;
+ }
+ break;
+
+ case pgup_key:
+ case pgdn_key:
+ if (page_callback != NULL) {
+ page_callback(mykey, item, dialog);
+ dialog->active_item -= 1;
+ dialog_update_active(dialog, 1, false, false);
+ }
+ break;
+
+ case tab_key:
+ dialog_update_active(dialog, +1, false, true);
+ break;
+
+ case down_key:
+ dialog_update_active(dialog, +1, false, false);
+ break;
+
+ case backtab_key:
+ dialog_update_active(dialog, -1, false, true);
+ break;
+
+ case up_key:
+ dialog_update_active(dialog, -1, false, false);
+ break;
+
+ case ins_key:
+ cursor_toggle_insert();
+ break;
+
+ case del_key:
+ dialog_string_delete(dialog);
+ if ((item->type == DD_I_LISTBASED) || (item->type == DD_I_FILENAME)) {
+ dialog_do_search(dialog, item);
+ }
+ break;
+
+ case bksp_key:
+ dialog_string_backspace(dialog);
+ if ((item->type == DD_I_LISTBASED) || (item->type == DD_I_FILENAME)) {
+ dialog_do_search(dialog, item);
+ }
+ break;
+
+ case left_key:
+ dialog_move_cursor(dialog, -1);
+ break;
+
+ case right_key:
+ dialog_move_cursor(dialog, 1);
+ break;
+
+ case home_key:
+ dialog_move_cursor(dialog, DD_C_HOME);
+ break;
+
+ case end_key:
+ dialog_move_cursor(dialog, DD_C_END);
+ break;
+
+ case ctrl_q_key:
+ dialog_quicksearch_flag = !dialog_quicksearch_flag;
+ break;
+
+ default:
+ if ((mykey >= 0x100) && (keys_fix_alt(mykey) != mykey)) {
+ mykey = keys_fix_alt(mykey);
+ for (count = 0; count < dialog->num_items; count++) {
+ if (toupper(mykey) == toupper(dialog->item[count].keystroke)) {
+ dialog_update_active(dialog, count - dialog->active_item, false, false);
+ item = &dialog->item[dialog->active_item];
+ switch (item->type) {
+
+ case DD_I_BUTTON:
+ dialog->status |= DD_EXITFLAG;
+ break;
+
+ case DD_I_CHECKBOX:
+ dialog_toggle_checkbox(dialog, item);
+ break;
+ }
+ }
+ }
+ } else if (Common::isPrint(mykey) && (mykey < 0x100)) {
+ dialog_string_insert(dialog, mykey);
+ if ((item->type == DD_I_LISTBASED) || (item->type == DD_I_FILENAME)) {
+ dialog_do_search(dialog, item);
+ }
+ }
+ break;
+
+ }
+ }
+
+ if (mouse_status == 0) {
+ mouse_button = -1;
+ }
+
+ if ((mouse_button != -1) && mouse_start_stroke) {
+ if ((mouse_video_mode == screen_video_mode) &&
+ (mouse_in_box(dialog->window.ul_x, dialog->window.ul_y,
+ dialog->window.lr_x, dialog->window.lr_y))) {
+
+ dialog_exec_mouse(dialog);
+
+ } else if ((mouse_video_mode != screen_video_mode) || (!mouse_callback_double_only)) {
+ if (mouse_callback != NULL) {
+ return_code = mouse_callback(mouse_button, mouse_status, mouse_x, mouse_y, mouse_video_mode);
+ if (return_code) {
+ dialog->status |= DD_EXITFLAG;
+ dialog_error = DD_ERR_ABORTEDBYCALLBACK;
+ }
+ }
+ }
+ }
+
+ mouse_end_cycle((!(dialog->status & DD_EXITFLAG)) && !mouse_stroke_going, true);
+ }
+
+ if (dialog->status & DD_FILEMENU) {
+ mads_chdir(savepath);
+ mads_chdrive(savedrive);
+ }
+
+ if (!return_code) {
+ item = &dialog->item[dialog->active_item];
+ } else {
+ item = NULL;
+ }
+
+ return item;
+}
+
+
+char *dialog_select_file(const char *prompt, const char *path, const char *filespec, char *output) {
+ DialogPtr dialog;
+ ItemPtr ok, first_item, result;
+ char *filebuf;
+ char *dirbuf;
+
+ filebuf = (char *)mem_get(3000);
+ if (filebuf == NULL) return NULL;
+
+ dirbuf = (char *)mem_get(1500);
+ if (dirbuf == NULL) {
+ mem_free(filebuf);
+ return NULL;
+ }
+
+ dialog = dialog_file_create(NULL, DD_CENTER, DD_CENTER,
+ DD_DEFAULT, DD_DEFAULT, DD_DEFAULT,
+ &ok, &first_item,
+ filespec, path, screen_max_y - 18,
+ filebuf, 200, dirbuf, 100, prompt);
+
+ result = dialog_execute(dialog, first_item, ok, NULL);
+
+ if (result != dialog->cancel_item) {
+ Common::strcpy_s(output, 65536, dialog_read_filepath(dialog, first_item));
+ } else {
+ output = NULL;
+ }
+
+ dialog_destroy(dialog);
+
+ mem_free(filebuf);
+ mem_free(dirbuf);
+
+ return output;
+}
+
+char *dialog_enter_string(char *reply, const char *top_prompt, const char *left_prompt,
+ char *my_default, int maxlen) {
+ char work[100];
+
+ DialogPtr dialog;
+ ItemPtr string, ok, cancel, result;
+
+ if (strlen(my_default) > (size_t)maxlen)
+ my_default[maxlen - 1] = 0; /* Trim default */
+
+ if (left_prompt == NULL)
+ Common::strcpy_s(work, "~Reply: ");
+ else
+ Common::strcpy_s(work, left_prompt);
+
+ dialog = dialog_create(NULL, DD_CENTER, DD_CENTER, DD_AUTO,
+ DD_DEFAULT, DD_DEFAULT, DD_DEFAULT);
+
+ dialog_add_blank(dialog);
+ dialog_add_message(dialog, DD_IX_CENTER, DD_IY_AUTOFILL, top_prompt);
+ dialog_add_blank(dialog);
+ string = dialog_add_string(dialog, DD_IX_LEFT, DD_IY_AUTOFILL, work,
+ my_default, maxlen);
+ dialog_add_blank(dialog);
+ ok = dialog_add_button(dialog, DD_IX_LEFT, DD_IY_BUTTON, " OK ");
+ cancel = dialog_add_button(dialog, DD_IX_RIGHT, DD_IY_BUTTON, "Cancel");
+
+ result = dialog_execute(dialog, string, ok, NULL);
+
+ Common::strcpy_s(work, dialog_read_string(dialog, string));
+
+ dialog_destroy(dialog);
+
+ if (result == cancel)
+ return(NULL);
+
+ Common::strcpy_s(reply, 65536, work);
+ return(reply);
+}
+
+int dialog_enter_int(char *top_prompt, int my_default) {
+ char work[20], work1[20];
+
+ if (my_default != 0)
+ mads_itoa(my_default, work, 10);
+ else
+ Common::strcpy_s(work, "");
+
+ if (dialog_enter_string(work1, top_prompt, "~Value:", work, 12) == NULL)
+ return(0);
+
+ return atoi(work1);
+}
+
+DialogPtr dialog_create_default(void) {
+ return(dialog_create(NULL, DD_CENTER, DD_CENTER, DD_AUTO,
+ DD_DEFAULT, DD_DEFAULT, DD_DEFAULT));
+}
+
+void dialog_set_alert_colors(int normal, int select, int hilite) {
+ alert_normal_color = normal;
+ alert_select_color = select;
+ alert_hilite_color = hilite;
+}
+
+int dialog_alert(int x, int y, int buttons,
+ char *string1, char *string2,
+ char *string3, char *string4) {
+ DialogPtr dialog;
+ int num_buttons;
+ int button_width;
+ int num_strings;
+ int string_width;
+ int dialog_width;
+ int sw1, sw2, sw3, sw4;
+ int returnval;
+ int normal_x, cancel_x, no_x;
+ char buf[80];
+ struct KeyBuffer key_buf;
+ ItemPtr yesitem, noitem, okitem, cancelitem;
+ ItemPtr begoneitem = nullptr;
+ ItemPtr firstitem, returnitem;
+
+ num_buttons = 0;
+ if (buttons & DD_OK_BUTTON) num_buttons++;
+ if (buttons & DD_YES_BUTTON) num_buttons++;
+ if (buttons & DD_NO_BUTTON) num_buttons++;
+ if (buttons & DD_CANCEL_BUTTON) num_buttons++;
+ if (buttons & DD_BEGONE_BUTTON) num_buttons++;
+
+ button_width = num_buttons * 10;
+
+ num_strings = 1;
+ sw1 = strlen(string1);
+ sw2 = sw3 = sw4 = 0;
+
+ if (string2 != NULL) {
+ sw2 = strlen(string2);
+ num_strings++;
+ }
+
+ if (string3 != NULL) {
+ sw3 = strlen(string3);
+ num_strings++;
+ }
+
+ if (string4 != NULL) {
+ sw4 = strlen(string4);
+ num_strings++;
+ }
+
+ string_width = (MAX(MAX(sw1, sw2), MAX(sw3, sw4))) + 2;
+
+ dialog_width = MAX(string_width, button_width);
+
+ dialog = dialog_create(NULL, x, y, dialog_width,
+ alert_normal_color,
+ alert_select_color,
+ alert_hilite_color);
+
+ if (dialog != NULL) {
+
+ firstitem = NULL;
+
+ if (num_buttons == 1) {
+ normal_x = DD_IX_CENTER;
+ cancel_x = DD_IX_CENTER;
+ no_x = DD_IX_CENTER;
+ } else {
+ normal_x = DD_IX_LEFT;
+ cancel_x = DD_IX_RIGHT;
+ no_x = (buttons & DD_CANCEL_BUTTON) ? DD_IX_LEFT : DD_IX_RIGHT;
+ }
+
+ okitem = NULL;
+ yesitem = NULL;
+ noitem = NULL;
+ cancelitem = NULL;
+
+ if (buttons & DD_OK_BUTTON) {
+ switch (dialog_language) {
+ case DIALOG_GERMAN:
+ Common::strcpy_s(buf, " Ok ");
+ break;
+
+ case DIALOG_ENGLISH:
+ default:
+ Common::strcpy_s(buf, " OK ");
+ break;
+ }
+ okitem = dialog_add_button(dialog, normal_x, DD_IY_BUTTON, buf);
+ firstitem = okitem;
+ }
+
+ if (buttons & DD_YES_BUTTON) {
+ switch (dialog_language) {
+ case DIALOG_GERMAN:
+ Common::strcpy_s(buf, " ~Ja ");
+ break;
+
+ case DIALOG_ENGLISH:
+ default:
+ Common::strcpy_s(buf, " ~Yes ");
+ break;
+ }
+ yesitem = dialog_add_button(dialog, normal_x, DD_IY_BUTTON, buf);
+ if (firstitem == NULL) firstitem = yesitem;
+ }
+
+ if (buttons & DD_NO_BUTTON) {
+ switch (dialog_language) {
+ case DIALOG_GERMAN:
+ Common::strcpy_s(buf, " ~Nein ");
+ break;
+
+ case DIALOG_ENGLISH:
+ default:
+ Common::strcpy_s(buf, " ~No ");
+ break;
+ }
+
+ noitem = dialog_add_button(dialog, no_x, DD_IY_BUTTON, buf);
+ if (firstitem == NULL) firstitem = noitem;
+ }
+
+ if (buttons & DD_BEGONE_BUTTON) {
+ begoneitem = dialog_add_button(dialog, normal_x, DD_IY_BUTTON, "~Begone");
+ if (firstitem == NULL) firstitem = begoneitem;
+ }
+
+ if (buttons & DD_CANCEL_BUTTON) {
+ switch (dialog_language) {
+ case DIALOG_GERMAN:
+ Common::strcpy_s(buf, CANCEL_GERMAN);
+ break;
+
+ case DIALOG_ENGLISH:
+ default:
+ Common::strcpy_s(buf, CANCEL_BUTTON);
+ break;
+ }
+ cancelitem = dialog_add_button(dialog, cancel_x, DD_IY_BUTTON, buf);
+ if (firstitem == NULL) firstitem = cancelitem;
+ }
+
+ dialog_add_blank(dialog);
+ if (string1 != NULL) dialog_add_message(dialog, DD_IX_CENTER, DD_IY_AUTOFILL, string1);
+ if (string2 != NULL) dialog_add_message(dialog, DD_IX_CENTER, DD_IY_AUTOFILL, string2);
+ if (string3 != NULL) dialog_add_message(dialog, DD_IX_CENTER, DD_IY_AUTOFILL, string3);
+ if (string4 != NULL) dialog_add_message(dialog, DD_IX_CENTER, DD_IY_AUTOFILL, string4);
+ dialog_add_blank(dialog);
+
+ key_buf.len = 0;
+
+ returnitem = dialog_execute(dialog, firstitem, firstitem, &key_buf);
+
+ dialog_destroy(dialog);
+
+ returnval = 0;
+
+ if (returnitem == cancelitem) returnval = DD_CANCEL_BUTTON;
+ if (returnitem == okitem) returnval = DD_OK_BUTTON;
+ if (returnitem == yesitem) returnval = DD_YES_BUTTON;
+ if (returnitem == noitem) returnval = DD_NO_BUTTON;
+ if (returnitem == begoneitem) returnval = DD_BEGONE_BUTTON;
+
+ } else {
+ returnval = dialog_error;
+ }
+
+ return returnval;
+}
+
+int dialog_alert_center(int buttons,
+ char *string1, char *string2,
+ char *string3, char *string4) {
+ return dialog_alert(DD_CENTER, DD_CENTER, buttons, string1, string2, string3, string4);
+}
+
+int dialog_alert_ok(char *string1, char *string2,
+ char *string3, char *string4) {
+ return dialog_alert(DD_CENTER, DD_CENTER, DD_OK_BUTTON, string1, string2, string3, string4);
+}
+
+void dialog_newsay(int x, int y) {
+ dialog_set_string_space(say_dialog, &say_dialog_work[0], SAY_DIALOG_SIZE);
+ dialog_create(say_dialog, x, y, DD_AUTO, DD_DEFAULT, DD_DEFAULT, DD_DEFAULT);
+}
+
+void dialog_say(char *message, int x) {
+ dialog_add_message(say_dialog, x, DD_IY_AUTOFILL, message);
+}
+
+Window dialog_sayit(int saymode) {
+ ItemPtr ok_item;
+ struct KeyBuffer key_buf;
+ char buf[80];
+
+ switch (saymode) {
+ case DD_PAUSE:
+ switch (dialog_language) {
+ case DIALOG_GERMAN:
+ Common::strcpy_s(buf, " Ok ");
+ break;
+ case DIALOG_ENGLISH:
+ default:
+ Common::strcpy_s(buf, " OK ");
+ break;
+ }
+ ok_item = dialog_add_button(say_dialog, DD_IX_CENTER, DD_IY_BUTTON,
+ buf);
+ say_dialog->cancel_item = ok_item;
+ key_buf.len = 0;
+ dialog_execute(say_dialog, ok_item, ok_item, &key_buf);
+ dialog_destroy(say_dialog);
+ break;
+
+ case DD_PERMANENT:
+ dialog_show_all(say_dialog);
+ dialog_destroy_persist(say_dialog);
+ break;
+
+ case DD_MANUAL:
+ dialog_show_all(say_dialog);
+ break;
+ }
+
+ return say_dialog->window;
+}
+
+ItemPtr dialog_left_message(DialogPtr dialog, char *prompt) {
+ return dialog_add_message(dialog, DD_IX_LEFT, DD_IY_AUTOFILL, prompt);
+}
+
+ItemPtr dialog_center_message(DialogPtr dialog, char *prompt) {
+ return dialog_add_message(dialog, DD_IX_CENTER, DD_IY_AUTOFILL, prompt);
+}
+
+ItemPtr dialog_left_string(DialogPtr dialog, char *prompt, char *string, int width) {
+ return dialog_add_string(dialog, DD_IX_LEFT, DD_IY_AUTOFILL, prompt, string, width);
+}
+
+ItemPtr dialog_left_button(DialogPtr dialog, char *prompt) {
+ return dialog_add_button(dialog, DD_IX_LEFT, DD_IY_BUTTON, prompt);
+}
+
+ItemPtr dialog_ok_button(DialogPtr dialog) {
+ char buf[80];
+
+ switch (dialog_language) {
+ case DIALOG_GERMAN:
+ Common::strcpy_s(buf, " Ok ");
+ break;
+ case DIALOG_ENGLISH:
+ default:
+ Common::strcpy_s(buf, " OK ");
+ break;
+ }
+
+ return dialog_left_button(dialog, buf);
+}
+
+
+ItemPtr dialog_cancel_button(DialogPtr dialog) {
+ char buf[80];
+
+ switch (dialog_language) {
+ case DIALOG_GERMAN:
+ Common::strcpy_s(buf, CANCEL_GERMAN);
+ break;
+ case DIALOG_ENGLISH:
+ default:
+ Common::strcpy_s(buf, CANCEL_BUTTON);
+ break;
+ }
+
+ return dialog_add_button(dialog, DD_IX_RIGHT, DD_IY_BUTTON, buf);
+}
+
+
+char *dialog_get_string(DialogPtr dialog, ItemPtr item, char *target) {
+ Common::strcpy_s(target, 65536, dialog_read_string(dialog, item));
+ return target;
+}
+
+
+ItemPtr dialog_add_number(DialogPtr dialog, int x, int y, char *prompt, int num, int width) {
+ char buf[80];
+ Common::sprintf_s(buf, "%d", num);
+ return dialog_add_string(dialog, x, y, prompt, buf, width);
+}
+
+
+ItemPtr dialog_left_number(DialogPtr dialog, char *prompt, int num, int width) {
+ char buf[80];
+ Common::sprintf_s(buf, "%d", num);
+ return dialog_left_string(dialog, prompt, buf, width);
+}
+
+int dialog_get_number(DialogPtr dialog, ItemPtr item) {
+ char buf[80];
+ dialog_get_string(dialog, item, buf);
+
+ return atoi(buf);
+}
+
+static void dialog_critical_error_handler() {
+ // No implementation in ScummVM
+}
+
+void dialog_trap_critical() {
+ dialog_server_installed = true;
+}
+
+void dialog_restore_critical(void) {
+ dialog_server_installed = false;
+}
+
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/core/dialog.h b/engines/mads/madsv2/core/dialog.h
index f4ac07e9f33..2057802e40c 100644
--- a/engines/mads/madsv2/core/dialog.h
+++ b/engines/mads/madsv2/core/dialog.h
@@ -125,11 +125,10 @@ namespace MADSV2 {
/* Quick dialog definition macros */
-#define dialog_declare(dd) DialogPtr dd = NULL; ItemPtr ok_item, cancel_item, result_item
-#define dialog_buttons(dd) ok_item = dialog_ok_button(dd);cancel_item = dialog_cancel_button(dd)
-#define dialog_exec(dd, ii) result_item = dialog_execute(dd, ii, ok_item, NULL);
-
-
+#define dialog_declare(dd) DialogPtr dd = NULL; ItemPtr ok_item = nullptr, cancel_item = nullptr, result_item = nullptr
+#define dialog_declare_ok(dd) DialogPtr dd = NULL; ItemPtr ok_item = nullptr, result_item = nullptr
+#define dialog_buttons(dd) ok_item = dialog_ok_button(dd);cancel_item = dialog_cancel_button(dd)
+#define dialog_exec(dd, ii) result_item = dialog_execute(dd, ii, ok_item, NULL);
struct DialogItem {
@@ -149,8 +148,6 @@ struct DialogItem {
typedef struct DialogItem Item;
typedef Item *ItemPtr;
-
-
struct DialogList {
char *list;
Window window;
@@ -167,8 +164,6 @@ struct DialogList {
typedef struct DialogList List;
typedef List *ListPtr;
-
-
struct DialogBox {
Window window; /* window boundaries */
short base_x, base_y; /* upper left text coords */
@@ -221,213 +216,244 @@ struct DialogBox {
typedef struct DialogBox Dialog;
typedef Dialog *DialogPtr;
-
#define StringMode(x) (((x).type == DD_I_STRING) || ((x).type == DD_I_FILENAME) || ((x).type == DD_I_LISTBASED))
#define DialogString(x) StringMode(x->item[x->active_item])
+extern int dialog_error;
+extern bool dialog_quicksearch_flag;
+extern bool dialog_wildcard_exits;
+extern long dialog_timeout;
+extern int dialog_language;
-/* dialog_1.cpp */
-extern int dialog_error;
-extern int dialog_quicksearch_flag;
-extern int dialog_wildcard_exits;
+/**
+ * Adds a button to the dialog box (see external docs).
+ */
+extern ItemPtr dialog_add_button(DialogPtr dialog, int x, int y, const char *prompt);
-extern long dialog_timeout;
+/**
+ * Adds a check box to the dialog.
+ */
+extern ItemPtr dialog_add_checkbox(DialogPtr dialog, int x, int y,
+ const char *prompt, int default_val, int class_);
-extern int dialog_language;
+/**
+ * Causes the specified checkbox to be displayed "greyed out".
+ */
+extern void dialog_grey_checkbox(ItemPtr item);
+/**
+ * Adds a message string to the dialog
+ */
+extern ItemPtr dialog_add_message(DialogPtr dialog, int x, int y, const char *prompt);
+/**
+ * Adds a blank line to an AUTOFILLing dialog
+ */
+extern void dialog_add_blank(DialogPtr dialog);
-ItemPtr dialog_add_button(DialogPtr dialog, int x, int y, const char *prompt);
+/**
+ * Adds a string entry item to the dialog box
+ */
+extern ItemPtr dialog_add_string(DialogPtr dialog, int x, int y,
+ const char *prompt, const char *default_val, int width);
-ItemPtr dialog_add_checkbox(DialogPtr dialog, int x, int y,
- const char *prompt, int default_val, int class_);
+/**
+ * Add a list-based string item to the dialog box
+ */
+extern ItemPtr dialog_add_listbased(DialogPtr dialog, int x, int y, const char *prompt,
+ const char *default_val, int width, const char *title, char *mylist,
+ int elements, int element_offset, int entry_width, int rows, int columns);
-void dialog_grey_checkbox(ItemPtr item);
-
-/* dialog_1.cpp */
-ItemPtr dialog_add_message(DialogPtr dialog, int x, int y, const char *prompt);
-
-void dialog_add_blank(DialogPtr dialog);
-
-/* dialog_1.cpp */
-ItemPtr dialog_add_string(DialogPtr dialog, int x, int y,
- char *prompt,
- char *default_val,
- int width);
-
-/* dialog_1.cpp */
-ItemPtr dialog_add_listbased(DialogPtr dialog, int x, int y,
- char *prompt,
- char *default_val, int width,
- char *title, char *mylist,
- int elements, int element_offset,
- int entry_width, int rows, int columns);
-
-/* dialog_1.cpp */
-ItemPtr dialog_add_filename(DialogPtr dialog, int x, int y,
- char *prompt,
- char *default_val, char *path,
- int rows,
- char *filebuf, int max_file_elements,
+/**
+ * Adds a filename-base string item to the dialog box
+ */
+extern ItemPtr dialog_add_filename(DialogPtr dialog, int x, int y, const char *prompt,
+ const char *default_val, const char *path, int rows, char *filebuf, int max_file_elements,
char *dirsbuf, int max_dirs_elements);
-/* dialog_1.cpp */
-ItemPtr dialog_append_list(DialogPtr dialog, int x, int y,
- ItemPtr base_string,
- char *title,
- char *mylist,
- int elements, int element_offset,
- int entry_width, int rows, int columns);
+/**
+ * Appends a second list to a listbased string
+ */
+extern ItemPtr dialog_append_list(DialogPtr dialog, int x, int y,
+ ItemPtr base_string, const char *title, const char *mylist, int elements,
+ int element_offset, int entry_width, int rows, int columns);
+
+extern void dialog_set_colors(int normal, int select, int hilite, int greyed);
+extern void dialog_set_workspace_size(long workspace);
+extern void dialog_set_string_space(DialogPtr dialog, const char *space, long size);
+
+/**
+ * Begins a new dialog box, and allocates memory for it if necessary
+ */
+extern DialogPtr dialog_create(DialogPtr dialog, int ul_x, int ul_y,
+ int width, int normal_color, int select_color, int hilite_color);
+
+/**
+ * Deallocates memory for a dynamically allocated dialog box
+*/
+extern void dialog_destroy(DialogPtr dialog);
+
+/**
+ * Deallocates memory for dialog, but does not restore screen
+ */
+extern void dialog_destroy_persist(DialogPtr dialog);
+
+/**
+ * Creates a dialog box and adds a filename entry to it
+ */
+extern DialogPtr dialog_file_create(DialogPtr dialog, int ul_x, int ul_y,
+ int normal_color, int select_color, int hilite_color, ItemPtr *ok_item,
+ ItemPtr *first_item, const char *default_val, const char *path, int rows,
+ char *filebuf, int maxfiles, char *dirsbuf, int maxdirs, const char *prompt);
+
+/**
+ * Assembly routine to read a file directory into the specified
+ * list structure. "Wild" is the wildcard spec to match (e.g. "*.*")
+ * in searching, "dirflag" determines whether the list should receive
+ * files or subdirectories (true = just subdirectories, false = just files).
+ */
+extern int dialog_read_dir_to_list(ListPtr target, const char *wild, int dirflag);
+
+/**
+ * Sets up a callback function which is activated each time an
+ * item is highlighted in a list box.
+ *
+ * The proper prototype for a callback function is:
+ * void callback (DialogPtr dialog, ListPtr list);
+ */
+extern void dialog_set_list_callback(DialogPtr dialog, void (*(callback))());
+
+/**
+ * Sets up a callback function which is activated each time a mouse
+ * event is detected on a different video screen from the dialog box
+ * (use when mouse is in double screen mode). The prototype for the
+ * callback function is:
+ *
+ * int callback (int mouse_button, int mouse_status,
+ * int mouse_x, int mouse_y, int mouse_video_mode);
+ * If function returns "false", dialog box will continue
+ * to run as usual; if function returns true, dialog immediately
+ * aborts with NULL item, and dialog_error contains
+ * DD_ERR_ABORTEDBYCALLBACK.
+ *
+ * double_only If true, then callback is only activated when
+ * cursor event occurs on a different *screen* from
+ * the dialog box. If false, then callback occurs
+ * even when cursor is simply outside the dialog box
+ * (on the same screen).
+ *
+ *
+ * Mouse cursor will be visible at the time the callback routine is
+ * activated.
+ */
+typedef int (*MouseCallback)(int mouse_button, int mouse_status, int mouse_x, int mouse_y, int mouse_video_mode);
+extern void dialog_set_mouse_callback(MouseCallback callback, int double_only);
+
+typedef void (*PageCallback)(int mykey, ItemPtr item, DialogPtr dialog);
+extern void dialog_set_page_callback(PageCallback fn);
+
+/**
+ * Sets up a callback function which is activated each time a
+ * check box item is modified.
+ *
+ * The proper prototype for a callback function is:
+ * int callback (DialogPtr dialog, ItemPtr item);
+ *
+ * If the callback routine returns "true", the dialog is
+ * immediately aborted (returns NULL handle, and dialog_error
+ * is set to DD_ERR_ABORTEDBYCALLBACK).
+ */
+extern void dialog_set_checkbox_callback(DialogPtr dialog, void (*(callback))());
+
+/**
+ * Returns the value of the specified checkbox
+ */
+extern int dialog_read_checkbox(DialogPtr dialog, ItemPtr item);
-/* dialog_1.cpp */
-void dialog_set_colors(int normal, int select,
- int hilite, int greyed);
+/**
+ * Returns a pointer to the specified string buffer
+ */
+extern char *dialog_read_string(DialogPtr dialog, ItemPtr item);
-/* dialog_1.cpp */
-void dialog_set_workspace_size(long workspace);
-void dialog_set_string_space(DialogPtr dialog,
- char *space, long size);
+/**
+ * Returns a pointer to the specified list-based string
+ */
+extern char *dialog_read_list(DialogPtr dialog, ItemPtr item);
+/**
+ * Returns the dialog box's path
+ */
+extern char *dialog_read_pathname(DialogPtr dialog, ItemPtr item);
-/* dialog_1.cpp */
-DialogPtr dialog_create(DialogPtr dialog,
- int ul_x, int ul_y,
- int width,
- int normal_color,
- int select_color,
- int hilite_color);
+/**
+ * Returns the filename selected by the user
+ */
+extern char *dialog_read_filename(DialogPtr dialog, ItemPtr item);
-void dialog_destroy(DialogPtr dialog);
-void dialog_destroy_persist(DialogPtr dialog);
-
-/* dialog_1.cpp */
-DialogPtr dialog_file_create(DialogPtr dialog,
- int ul_x, int ul_y,
- int normal_color, int select_color,
- int hilite_color,
- ItemPtr *ok_item, ItemPtr *first_item,
- char *default_val, char *path,
- int rows,
- char *filebuf, int maxfiles,
- char *dirsbuf, int maxdirs,
- char *prompt);
-
-/* dialog_1.cpp */
-int dialog_read_dir_to_list(ListPtr target,
- char *wild,
- int dirflag);
-
-/* dialog_1.cpp */
-void dialog_set_list_callback(DialogPtr dialog,
- void (*(callback))());
-
-void dialog_set_mouse_callback(void (*(callback))(),
- int double_only);
-
-void dialog_set_page_callback(void (*(callback))());
-
-void dialog_set_checkbox_callback(DialogPtr dialog,
- void (*(callback))());
-
-/* dialog_1.cpp */
-int dialog_read_checkbox(DialogPtr dialog, ItemPtr item);
-char *dialog_read_string(DialogPtr dialog, ItemPtr item);
-char *dialog_read_list(DialogPtr dialog, ItemPtr item);
-char *dialog_read_pathname(DialogPtr dialog, ItemPtr item);
-char *dialog_read_filename(DialogPtr dialog, ItemPtr item);
-char *dialog_read_filepath(DialogPtr dialog, ItemPtr item);
-
-
-/* dialog_1.cpp */
-void dialog_show_all(DialogPtr dialog);
-
-/* dialog_1.cpp */
-ItemPtr dialog_execute(DialogPtr dialog,
- ItemPtr active_item,
- ItemPtr default_button,
- KeyPtr key_buffer);
-
-
-/* dialog_2.cpp */
-char *dialog_select_file(char *prompt,
- char *path,
- char *filespec,
- char *output);
-
-
-/* dialog_3.cpp */
-char *dialog_enter_string(char *reply,
- char *top_prompt,
- char *left_prompt,
- char *my_default,
- int maxlen);
-
-
-/* dialog_4.cpp */
-int dialog_enter_int(char *top_prompt, int my_default);
-
-
-/* dialog_5.cpp */
-DialogPtr dialog_create_default(void);
-
-
-/* dialog_6.cpp */
-int dialog_alert(int x, int y, int buttons,
- char *string1,
- char *string2,
- char *string3,
- char *string4);
-
-void dialog_set_alert_colors(int normal,
- int select,
- int hilite);
-
-
-/* dialog_7.cpp */
-int dialog_alert_center(int buttons,
- char *string1,
- char *string2,
- char *string3,
- char *string4);
-
-/* dialog_8.cpp */
-int dialog_alert_ok(char *string1,
- char *string2,
- char *string3,
- char *string4);
+/**
+ * Returns the filename and full path selected by the user
+ */
+extern char *dialog_read_filepath(DialogPtr dialog, ItemPtr item);
-/* dialog_9.cpp */
-void dialog_newsay(int x, int y);
-void dialog_say(char *message, int x);
-Window dialog_sayit(int saymode);
-
-
-/* dialog_a.cpp */
-ItemPtr dialog_left_message(DialogPtr dialog, char *prompt);
-ItemPtr dialog_center_message(DialogPtr dialog, char *prompt);
-ItemPtr dialog_left_string(DialogPtr dialog, char *prompt,
- char *string, int width);
-ItemPtr dialog_left_button(DialogPtr dialog, char *prompt);
-ItemPtr dialog_ok_button(DialogPtr dialog);
-ItemPtr dialog_cancel_button(DialogPtr dialog);
-char *dialog_get_string(DialogPtr dialog, ItemPtr item,
- char *target);
+/**
+ * Routine to display the entire dialog box
+ */
+extern void dialog_show_all(DialogPtr dialog);
+/**
+ * The main loop for executing a dialog. Includes keyboard
+ * handler and mouse scanner.
+ */
+extern ItemPtr dialog_execute(DialogPtr dialog, ItemPtr active_item,
+ ItemPtr default_button, KeyPtr key_buffer);
-/* dialog_b.cpp */
-ItemPtr dialog_add_number(DialogPtr dialog, int x, int y,
- char *prompt, int num, int width);
-ItemPtr dialog_left_number(DialogPtr dialog, char *prompt,
- int num, int width);
-int dialog_get_number(DialogPtr dialog, ItemPtr item);
+extern char *dialog_select_file(const char *prompt, const char *path,
+ const char *filespec, char *output);
+extern char *dialog_enter_string(char *reply, const char *top_prompt,
+ const char *left_prompt, char *my_default, int maxlen);
+
+/**
+ * Prompts user to enter an integer value (displays default).
+ * Returns 0 if user aborted, or entry was out of range.
+ */
+extern int dialog_enter_int(const char *top_prompt, int my_default);
+extern DialogPtr dialog_create_default();
+
+/**
+ * Pops up a quick dialog to inform user of an error or to ask
+ * a yes/no question.
+ */
+extern int dialog_alert(int x, int y, int buttons, const char *string1,
+ const char *string2, const char *string3, const char *string4);
+
+extern void dialog_set_alert_colors(int normal, int select, int hilite);
+extern int dialog_alert_center(int buttons, const char *string1,
+ const char *string2, const char *string3, const char *string4);
+extern int dialog_alert_ok(const char *string1, const char *string2,
+ const char *string3, const char *string4);
+extern void dialog_newsay(int x, int y);
+extern void dialog_say(char *message, int x);
+extern Window dialog_sayit(int saymode);
+
+extern ItemPtr dialog_left_message(DialogPtr dialog, const char *prompt);
+extern ItemPtr dialog_center_message(DialogPtr dialog, const char *prompt);
+extern ItemPtr dialog_left_string(DialogPtr dialog, const char *prompt, const char *string, int width);
+extern ItemPtr dialog_left_button(DialogPtr dialog, const char *prompt);
+extern ItemPtr dialog_ok_button(DialogPtr dialog);
+extern ItemPtr dialog_cancel_button(DialogPtr dialog);
+extern char *dialog_get_string(DialogPtr dialog, ItemPtr item, char *target);
+
+extern ItemPtr dialog_add_number(DialogPtr dialog, int x, int y,
+ const char *prompt, int num, int width);
+extern ItemPtr dialog_left_number(DialogPtr dialog, char *prompt,
+ int num, int width);
+extern int dialog_get_number(DialogPtr dialog, ItemPtr item);
-/* dialog_e.cpp */
-void dialog_trap_critical(void);
-void dialog_restore_critical(void);
+extern void dialog_trap_critical();
+extern void dialog_restore_critical();
-/* dialog_f.cpp */
-void dialog_watch_point(char *string, long x, long y);
+extern void dialog_watch_point(const char *string, long x, long y);
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/core/env.cpp b/engines/mads/madsv2/core/env.cpp
new file mode 100644
index 00000000000..6a48b8719bd
--- /dev/null
+++ b/engines/mads/madsv2/core/env.cpp
@@ -0,0 +1,816 @@
+/* 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/file.h"
+#include "mads/madsv2/core/env.h"
+#include "mads/madsv2/core/mads.h"
+#include "mads/madsv2/core/concat.h"
+#include "mads/madsv2/core/fileio.h"
+#include "mads/madsv2/core/mem.h"
+#include "mads/madsv2/core/error.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+extern int art_hags_are_on_hd;
+
+int env_search_mode = ENV_SEARCH_MADS_PATH;
+int env_search_cd = false;
+char env_cd_drive = 'D';
+int env_sound_override = false;
+long env_concat_file_size = 0;
+char env_null[7] = "<NULL>";
+
+static const char env_sect_string[5] = "SECT";
+static const char env_room_string[5] = "ROOM";
+static const char env_art_string[4] = "ART";
+static const char env_objects_string[8] = "OBJECTS";
+static const char env_inter_string[6] = "INTER";
+static const char env_text_string[5] = "TEXT";
+static const char env_quotes_string[7] = "QUOTES";
+static const char env_font_string[5] = "FONT";
+static const char env_sound_string[6] = "SOUND";
+static const char env_conv_string[5] = "CONV";
+static const char env_speech_string[7] = "SPEECH";
+
+
+static const char env_section_string[8] = "SECTION";
+static const char env_global_string[7] = "GLOBAL";
+static const char env_slash_string[3] = "\\";
+
+static const char env_speech1_string[8] = "SPEECH1";
+static const char env_speech2_string[8] = "SPEECH2";
+
+char *env_catint(char *out, int value, int digits) {
+ int mark;
+ int power;
+ int digit;
+
+ power = 1;
+ for (mark = 0; mark < digits; mark++) {
+ if (mark > 0) power *= 10;
+ Common::strcat_s(out, 65536, "0");
+ }
+
+ for (mark = strlen(out) - digits; (unsigned)mark < strlen(out); mark++) {
+ if (value >= power) {
+ digit = value / power;
+ value = value - (digit * power);
+ out[mark] += digit;
+ }
+ power = power / 10;
+ }
+
+ return (out);
+}
+
+
+static void path_concat(char *target, const char *string) {
+ Common::strcat_s(target, 65536, string);
+ Common::strcat_s(target, 65536, env_slash_string);
+}
+
+
+/* char *path = 'd322u001.rac' */
+char *env_fill_path(char *path, int env_mode, int env_room) {
+ Common::String madsptr;
+ char *infile;
+ char *madspath;
+ char work[80];
+ int madslen;
+ int env_sect = 0;
+
+ madspath = &work[0];
+
+ infile = path;
+
+ madsptr = ConfMan.get(MADS_ENV);
+
+ if (env_sound_override && (env_mode == ENV_SOUND)) {
+ madsptr = ConfMan.get(MADS_SOUND_ENV);
+ }
+
+ if (env_mode == ROOM) {
+ env_sect = env_room / 100;
+ } else if (env_mode == SECTION) {
+ env_sect = env_room;
+ }
+
+ if (madsptr != NULL) {
+
+ madslen = strlen(madsptr.c_str());
+
+ Common::strcpy_s(madspath, 65536, madsptr.c_str());
+
+ if (madsptr[madslen - 1] != '\\') {
+ Common::strcat_s(madspath, 65536, env_slash_string);
+ }
+
+ if ((env_mode == ROOM) || (env_mode == SECTION)) {
+ Common::strcat_s(madspath, 65536, env_sect_string);
+ env_catint(madspath, env_sect, 3);
+ Common::strcat_s(madspath, 65536, env_slash_string);
+ }
+
+ if (env_mode == ROOM) {
+ Common::strcat_s(madspath, 65536, env_room_string);
+ env_catint(madspath, env_room, 3);
+ Common::strcat_s(madspath, 65536, env_slash_string);
+ }
+
+ switch (env_mode) {
+ case ENV_OBJECTS:
+ path_concat(madspath, env_objects_string);
+ break;
+ case ENV_INTERFACE:
+ path_concat(madspath, env_inter_string);
+ break;
+ case ENV_TEXT:
+ path_concat(madspath, env_text_string);
+ break;
+ case ENV_QUOTES:
+ path_concat(madspath, env_quotes_string);
+ break;
+ case ENV_FONT:
+ path_concat(madspath, env_font_string);
+ break;
+ case ENV_ART:
+ path_concat(madspath, env_art_string);
+ break;
+ case ENV_SOUND:
+ if (!env_sound_override) path_concat(madspath, env_sound_string);
+ break;
+ case ENV_CONV:
+ path_concat(madspath, env_conv_string);
+ break;
+ case ENV_SPEECH:
+ path_concat(madspath, env_speech_string);
+ break;
+ }
+
+ if (*infile == '\\') {
+ infile++;
+ }
+
+ Common::strcat_s(madspath, 65536, infile);
+ mads_strupr(madspath);
+
+ Common::strcpy_s(path, 65536, madspath);
+ madspath = path;
+
+ } else {
+ Common::strcpy_s(path, 65536, "");
+ madspath = NULL;
+ }
+
+ return madspath;
+}
+
+char *env_get_path(char *madspath, char *infile) {
+ /* char *madsptr; */
+ char *mark;
+ /* int madslen; */
+ int env_mode;
+ int env_room = 0;
+ int env_sect = 0;
+ char temp_buf_1[80];
+ char temp_buf_2[80];
+
+ if (infile[0] != '*') {
+ Common::strcpy_s(temp_buf_1, infile);
+ mads_fullpath(temp_buf_2, temp_buf_1, 79);
+ Common::strcpy_s(madspath, 65536, temp_buf_2);
+ mads_strupr(madspath);
+
+ } else {
+ /* infile is '*d322u001.rac' */
+ infile++;
+ Common::strcpy_s(temp_buf_1, infile);
+ mads_strupr(temp_buf_1);
+
+ if (strncmp(temp_buf_1, "RM", 2) == 0) {
+ env_mode = ROOM;
+ env_room = atoi(&temp_buf_1[2]);
+ env_sect = env_room / 100;
+
+ } else if (strncmp(temp_buf_1, "SC", 2) == 0) {
+ env_mode = SECTION;
+ env_sect = atoi(&temp_buf_1[2]);
+ env_room = env_sect;
+
+ } else if (strstr(temp_buf_1, ".TXT")) {
+ env_mode = ENV_TEXT;
+
+ } else if (strstr(temp_buf_1, ".QUO")) {
+ env_mode = ENV_QUOTES;
+
+ } else if (strncmp(temp_buf_1, "CONV", 4) == 0) {
+ env_mode = ENV_CONV;
+
+ } else if (temp_buf_1[0] == 'I') {
+ env_mode = ENV_INTERFACE;
+
+ } else if ((temp_buf_1[0] == 'O') && (temp_buf_1[1] == 'B')) {
+ env_mode = ENV_OBJECTS;
+
+ } else if (strncmp(temp_buf_1, "FONT", 4) == 0) {
+ env_mode = ENV_FONT;
+
+ } else if ((strncmp(&temp_buf_1[1], "SOUND", 5) == 0) ||
+ (strstr(temp_buf_1, ".HMI")) ||
+ (strstr(temp_buf_1, ".DRV")) ||
+ (strstr(temp_buf_1, ".BNK"))) {
+ env_mode = ENV_SOUND;
+
+ } else if ((strstr(temp_buf_1, ".RAW")) ||
+ (strstr(temp_buf_1, ".RAC")) ||
+ (strncmp(temp_buf_1, "SPCH", 4) == 0)) {
+ env_mode = ENV_SPEECH;
+
+ } else {
+ env_mode = GLOBAL;
+
+ mark = strchr(temp_buf_1, '.');
+ if (mark != NULL) {
+ mark++;
+ if ((strncmp(mark, "FL", 2) == 0) ||
+ (strncmp(mark, "LBM", 3) == 0) ||
+ (strncmp(mark, "ANM", 3) == 0) ||
+ (strstr(mark, "AA") != NULL) ||
+ (strstr(mark, "SS") != NULL)) {
+ env_mode = ENV_ART;
+ }
+ }
+ }
+
+ if (env_search_mode == ENV_SEARCH_MADS_PATH) {
+ Common::strcpy_s(madspath, 65536, temp_buf_1);
+ madspath = env_fill_path(madspath, env_mode, env_room);
+
+ } else {
+ if ((env_mode == ROOM) || (env_mode == SECTION)) {
+ Common::strcpy_s(madspath, 65536, env_section_string);
+ env_catint(madspath, env_sect, 1);
+ } else if (env_mode == ENV_SPEECH) {
+ Common::strcpy_s(madspath, 65536, env_speech_string);
+ } else if (env_mode == ENV_SOUND) {
+ Common::strcpy_s(madspath, 65536, env_sound_string);
+ } else {
+ Common::strcpy_s(madspath, 65536, env_global_string);
+ }
+ Common::strcat_s(madspath, 65536, CONCAT_EXT);
+
+ /* returns 'global.hag', 'section9.hag', etc */
+ }
+ }
+
+ return madspath;
+}
+
+Common::SeekableReadStream *env_open(char *file_path, const char *options) {
+ int error_flag = true;
+ int count;
+ int found;
+ int num_files;
+ long mem_to_get;
+ char index_file[80];
+ char temp_file[80];
+ char load_file[80];
+ char temp_buf[80];
+ char check_buf[80];
+
+ char *mark;
+ Common::SeekableReadStream *index_handle = NULL;
+ Common::SeekableReadStream *handle = NULL;
+ Concat concat;
+ concat.file_offset = concat.file_size = 0;
+ Concat *concat_array = NULL;
+
+ if (env_get_path(load_file, file_path) == NULL) goto done;
+
+ mark = strchr(file_path, '*');
+
+ mads_strupr(file_path);
+
+ /* if CD version and checking RAW or RAC file */
+ if (env_search_cd && (strstr(file_path, ".RAW") || strstr(file_path, ".RAC"))) {
+ Common::strcpy_s(check_buf, env_speech1_string);
+ Common::strcat_s(check_buf, env_slash_string);
+
+ if (file_path[0] == '*') {
+ Common::strcat_s(check_buf, &file_path[1]);
+ } else {
+ Common::strcat_s(check_buf, file_path);
+ }
+ /* Common::strcat_s (check_buf, temp_buf); */
+ Common::strcpy_s(load_file, check_buf);
+
+ if (fileio_exist(load_file)) {
+ Common::File *f = new Common::File();
+ f->open(load_file);
+
+ if (!f->isOpen()) {
+ delete f;
+ goto done;
+ }
+
+ handle = f;
+
+ } else {
+ Common::strcpy_s(check_buf, env_speech2_string);
+ Common::strcat_s(check_buf, env_slash_string);
+
+ if (file_path[0] == '*') {
+ Common::strcat_s(check_buf, &file_path[1]);
+ } else {
+ Common::strcat_s(check_buf, file_path);
+ }
+
+ /* Common::strcat_s (check_buf, temp_buf); */
+ Common::strcpy_s(load_file, check_buf);
+
+ if (fileio_exist(load_file)) {
+ Common::File *f = new Common::File();
+ f->open(load_file);
+
+ if (handle == NULL) {
+ delete f;
+ goto done;
+ }
+
+ handle = f;
+
+ } else {
+ goto done;
+ }
+ }
+
+ } else if ((env_search_mode == ENV_SEARCH_CONCAT_FILES) && (mark != NULL)) {
+
+ mark++;
+ Common::strcpy_s(temp_buf, mark);
+ mads_strupr(temp_buf);
+
+
+ /* load_file = 'global.hag' */
+ if (art_hags_are_on_hd) {
+ Common::strcpy_s(index_file, load_file);
+ } else {
+ fileio_new_ext(index_file, load_file, "IDX");
+ }
+ /* index_file = 'global.idx' */
+
+ if (env_search_cd && !art_hags_are_on_hd) {
+
+ if (fileio_exist(index_file)) {
+ /* if 'global.idx' exists */
+ Common::File *f = new Common::File();
+ f->open(index_file);
+ handle = f;
+ }
+
+ Common::strcpy_s(temp_file, "X:\\");
+ temp_file[0] = env_cd_drive;
+ Common::strcat_s(temp_file, load_file);
+ Common::strcpy_s(load_file, temp_file);
+ }
+
+ if (!fileio_exist(load_file)) {
+ if (env_verify()) {
+ /* 'MADS' is set in DOS environment */
+ Common::strcpy_s(temp_file, load_file);
+ Common::strcpy_s(load_file, ConfMan.get(MADS_ENV).c_str());
+ Common::strcat_s(load_file, "\\");
+ Common::strcat_s(load_file, temp_file);
+ }
+ }
+
+ if (index_handle == NULL) {
+ Common::File *f = new Common::File();
+ f->open(load_file);
+
+ if (index_handle == NULL) {
+ delete f;
+ goto done;
+ }
+
+ index_handle = f;
+ }
+
+ if (!fileio_fread_f(&check_buf, CONCAT_ID_LENGTH, 1, index_handle)) goto done;
+ if (strncmp(check_buf, CONCAT_ID_STRING, CONCAT_ID_CHECK) != 0) goto done;
+
+ if (!fileio_fread_f(&num_files, sizeof(int), 1, index_handle)) goto done;
+
+ found = false;
+
+ mem_to_get = (long)num_files * sizeof(Concat);
+ concat_array = (Concat *)mem_get(mem_to_get);
+
+ if (concat_array != NULL) {
+ if (!fileio_fread_f(concat_array, mem_to_get, 1, index_handle)) goto done;
+ for (count = 0; !found && (count < num_files); count++) {
+ found = (strcmp(temp_buf, concat_array[count].name) == 0);
+ if (found) {
+ concat = concat_array[count];
+ }
+ }
+ } else {
+ for (count = 0; !found && (count < num_files); count++) {
+ if (!fileio_fread_f(&concat, sizeof(Concat), 1, index_handle)) goto done;
+ found = (strcmp(temp_buf, concat.name) == 0);
+ }
+ }
+
+ delete index_handle;
+ index_handle = NULL;
+
+ if (found) {
+ Common::File *f = new Common::File();
+ f->open(load_file);
+
+ if (handle == NULL) {
+ delete f;
+ goto done;
+ }
+
+ handle = f;
+
+ if (fileio_setpos(handle, concat.file_offset) != concat.file_offset) goto done;
+
+ env_concat_file_size = concat.file_size;
+ }
+
+ } else {
+ Common::File *f = new Common::File();
+ f->open(load_file);
+ handle = f;
+ }
+
+ error_flag = false;
+
+done:
+ if (concat_array != NULL) mem_free(concat_array);
+ delete index_handle;
+
+ if (error_flag) {
+ delete handle;
+ handle = nullptr;
+ }
+
+ return handle;
+}
+
+long env_get_file_size(Common::SeekableReadStream *handle) {
+ long result;
+
+ if (env_search_mode == ENV_SEARCH_CONCAT_FILES) {
+ result = env_concat_file_size;
+
+ } else {
+ result = handle->size();
+ }
+
+ return result;
+}
+
+int env_exist(const char *filename) {
+ int exist = false;
+ Common::SeekableReadStream *handle;
+ char check_buf[80];
+ char file_name[80];
+
+ Common::strcpy_s(file_name, filename);
+ mads_strupr(file_name);
+
+ /* if CD version and checking RAW or RAC file */
+ if (env_search_cd && (strstr(file_name, ".RAW") || strstr(file_name, ".RAC"))) {
+
+ Common::strcpy_s(check_buf, env_speech1_string);
+ Common::strcat_s(check_buf, env_slash_string);
+
+ if (file_name[0] == '*') {
+ Common::strcat_s(check_buf, &file_name[1]);
+ } else {
+ Common::strcat_s(check_buf, file_name);
+ }
+
+ if (fileio_exist(check_buf)) {
+ exist = true;
+
+ } else {
+ Common::strcpy_s(check_buf, env_speech2_string);
+ Common::strcat_s(check_buf, env_slash_string);
+
+ if (file_name[0] == '*') {
+ Common::strcat_s(check_buf, &file_name[1]);
+ } else {
+ Common::strcat_s(check_buf, file_name);
+ }
+
+ if (fileio_exist(check_buf)) {
+ exist = true;
+ }
+ }
+
+ } else if (env_search_mode == ENV_SEARCH_CONCAT_FILES) {
+ handle = env_open(file_name, "rb");
+ if (handle != NULL) {
+ exist = true;
+ delete handle;
+ }
+
+ } else {
+ exist = fileio_exist(file_name);
+ }
+
+ return exist;
+}
+
+char *env_dos_error_name(char *error_buf) {
+ switch (errno) {
+ case EEXIST:
+ Common::strcpy_s(error_buf, 65536, "File already exists.");
+ break;
+
+ case EINVAL:
+ Common::strcpy_s(error_buf, 65536, "Invalid argument.");
+ break;
+
+ case EMFILE:
+ Common::strcpy_s(error_buf, 65536, "Too many open files.");
+ break;
+
+ case ENOENT:
+ Common::strcpy_s(error_buf, 65536, "No such file or directory.");
+ break;
+
+ case ENOSPC:
+ Common::strcpy_s(error_buf, 65536, "Disk full.");
+ break;
+
+ case EACCES:
+ Common::strcpy_s(error_buf, 65536, "Permission denied.");
+ break;
+
+ case EBADF:
+ Common::strcpy_s(error_buf, 65536, "Bad file number.");
+ break;
+
+ default:
+ Common::sprintf_s(error_buf, 65536, "Error Code %d.", errno);
+ break;
+ }
+
+ return error_buf;
+}
+
+char *env_get_level_path(char *out, int item_type, char *file_spec, int first_level, int second_level) {
+ char temp_buf[80];
+ char *result;
+
+ Common::strcpy_s(temp_buf, "*");
+
+ if ((item_type == SECTION) || (item_type == ROOM)) {
+ if ((item_type == ROOM) && (first_level == 0)) {
+ first_level = second_level / 100;
+ /* first_level = room_get_section (second_level); */
+ }
+ }
+
+ if (file_spec != NULL) {
+ switch (item_type) {
+ case GLOBAL:
+ Common::strcat_s(temp_buf, "GL000");
+ break;
+ case SECTION:
+ Common::strcat_s(temp_buf, "SC");
+ env_catint(temp_buf, first_level, 3);
+ break;
+ case ROOM:
+ Common::strcat_s(temp_buf, "RM");
+ env_catint(temp_buf, second_level, 3);
+ break;
+ case OBJECT:
+ break;
+ }
+
+ Common::strcat_s(temp_buf, file_spec);
+ }
+
+ if (env_search_mode == ENV_SEARCH_MADS_PATH) {
+ if (env_get_path(out, temp_buf) != NULL) {
+ result = out;
+ } else {
+ result = NULL;
+ }
+ } else {
+ Common::strcpy_s(out, 65536, temp_buf);
+ result = out;
+ }
+
+ return result;
+}
+
+Common::SeekableReadStream *env_open_level(int item_type, const char *file_spec,
+ int level_one, int level_two, const char *options) {
+ char temp_buf[80];
+ Common::SeekableReadStream *result;
+
+ if (env_get_level_path(temp_buf, item_type, file_spec, level_one, level_two) != NULL) {
+ result = env_open(temp_buf, options);
+ } else {
+ result = NULL;
+ }
+
+ return result;
+}
+
+char *env_get(char *target, const char *env) {
+ Common::String get;
+
+ get = ConfMan.get(env);
+ if (get.empty()) {
+ Common::strcpy_s(target, 65536, env_null);
+ } else {
+ Common::strcpy_s(target, 65536, get.c_str());
+ }
+
+ mads_strupr(target);
+ fileio_purge_all_spaces(target);
+
+ return target;
+}
+
+char *env_next(char *variable) {
+ while (*variable) {
+ variable++;
+ }
+
+ variable++;
+
+ return variable;
+}
+
+char *env_find_end(char *environment) {
+ /* Scan through variables */
+ while (*environment) {
+ environment = env_next(environment);
+ }
+
+ /* Scan past load name if exists */
+ if ((*(environment + 1) == 1) && (*(environment + 2) == 0)) {
+ environment += 3;
+ while (*environment) {
+ environment++;
+ }
+ }
+
+ /* Point to byte after everything */
+ environment++;
+
+ return environment;
+}
+
+int env_size(char *environment) {
+ error("TODO: env_size");
+}
+
+int env_free(char *environment) {
+ char *bottom;
+ int size;
+ int used;
+
+ bottom = env_find_end(environment);
+
+ used = (bottom - environment);
+
+ size = env_size(environment);
+
+ return size - used;
+}
+
+char *env_find(char *environment, char *variable) {
+ char *result = NULL;
+ char *mark;
+ char work_var[256];
+
+ while (*environment && (result == NULL)) {
+ Common::strcpy_s(work_var, environment);
+ mark = strchr(work_var, '=');
+ if (mark != NULL) *mark = 0;
+ if (!scumm_stricmp(work_var, variable)) {
+ result = environment;
+ }
+ environment = env_next(environment);
+ }
+
+ return result;
+}
+
+void env_delete(char *environment, char *variable) {
+ char *target;
+ char *next;
+ char *bottom;
+ int size;
+
+ target = env_find(environment, variable);
+ if (target == NULL) goto done;
+
+ next = env_next(target);
+ bottom = env_find_end(target);
+ size = bottom - next;
+
+ memmove(target, next, size);
+
+done:
+ ;
+}
+
+int env_insert(char *environment, char *variable, char *value) {
+ int error_flag = true;
+ int new_size;
+ int free;
+ int copy_size;
+ char *target;
+ char *bottom;
+ char *new_home;
+ char var_name[80];
+ char var_string[256];
+
+ Common::strcpy_s(var_name, variable);
+ mads_strupr(var_name);
+
+ /* Delete any previous copy of this variable */
+ env_delete(environment, var_name);
+
+ /* Prepare full string for insertion */
+ Common::strcpy_s(var_string, var_name);
+ Common::strcat_s(var_string, "=");
+ Common::strcat_s(var_string, value);
+
+ /* Get size of string & check of there is space in the environment */
+ new_size = strlen(var_string) + 1;
+ free = env_free(environment);
+ if (new_size > free) goto done;
+
+ /* Find end of environment (for new string). Also find end of whole */
+ /* environment structure (must be moved out of the way). */
+
+ target = environment;
+ while (*target) {
+ target = env_next(target);
+ }
+
+ bottom = env_find_end(environment);
+ copy_size = bottom - target;
+ new_home = target + new_size;
+
+ /* Insert string */
+ memmove(new_home, target, copy_size);
+ memmove(target, var_string, new_size);
+
+ error_flag = false;
+
+done:
+ return error_flag;
+}
+
+char *env_level_path(char *string, int first_level, int second_level) {
+ int env_mode;
+ int env_sect;
+ int env_room = 0;
+
+ if (second_level >= 0) {
+ env_mode = ROOM;
+ env_sect = first_level;
+ env_room = second_level;
+ } else {
+ env_mode = SECTION;
+ env_sect = first_level;
+ }
+
+ return env_fill_path(string, env_mode, env_room);
+}
+
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/core/env.h b/engines/mads/madsv2/core/env.h
index 48f4efa4058..f7f81142e07 100644
--- a/engines/mads/madsv2/core/env.h
+++ b/engines/mads/madsv2/core/env.h
@@ -69,63 +69,65 @@ extern int env_search_mode;
extern int env_search_cd;
extern char env_cd_drive;
extern int env_privileges;
-
extern int env_sound_override;
-
extern long env_concat_file_size; /* Size of last concat file opened */
+extern char env_null[7];
-
-/* env_0.c */
-int env_verify(void);
-
-/* env_1.c */
+extern int env_verify(void);
Common::SeekableReadStream *env_open(const char *file_path, const char *options);
int env_exist(const char *file_name);
long env_get_file_size(Common::Stream *handle);
-
-/* env_1.c */
-char *env_get_path(char *madspath, char *infile);
-
-/* env_1.c */
+char *env_get_path(char *madspath, const char *infile);
char *env_catint(char *out, int value, int digits);
+char *env_fill_path(char *path, int env_mode, int env_room);
+char *env_dos_error_name(char *error_buf);
+char *env_get_level_path(char *out, int item_type, const char *file_spec,
+ int first_level, int second_level);
+Common::SeekableReadStream *env_open_level(int item_type, const char *file_spec,
+ int level_one, int level_two, const char *options);
+char *env_get(char *target, char *env);
-/* env_1.c */
-char * env_fill_path(char *path, int env_mode, int env_room);
-
-
-/* env_2.c */
-char * env_dos_error_name(char *error_buf);
-
-/* env_3.c */
-char * env_get_level_path(char *out, int item_type,
- char *file_spec,
- int first_level,
- int second_level);
-
-Common::Stream * env_open_level(int item_type,
- char *file_spec,
- int level_one, int level_two,
- char *options);
+/**
+ * Given a pointer to an environment variable, returns a pointer
+ * to the next variable in the environment list (if pointer is
+ * to a null string, the end of the list has been reached).
+ */
+char *env_next(char *variable);
+/**
+ * Given a pointer to an environment, returns a pointer to one
+ * byte after the end of the entire environment.
+ */
+char *env_find_end(char *environment);
-/* env_4.c */
-extern char env_null[7];
+/**
+ * Given a pointer to the start of an environment, returns the
+ * size in bytes of that environment.
+ */
+int env_size(char *environment);
-char *env_get(char *target, char *env);
+int env_free(char *environment);
+/**
+ * Given a pointer to an environment and a variable, returns a
+ * pointer to that variable name in the environment. Returns
+ * NULL if no match found.
+ */
+char *env_find(char *environment, const char *variable);
-/* env_5.c */
-char * env_next(char *variable);
-char * env_find_end(char *environment);
-int env_size(char *environment);
-int env_free(char *environment);
+/**
+ * Given an environment and a variable name, deletes that
+ * variable from the environment table.
+ */
+void env_delete(char *environment, const char *variable);
-/* env_5.c */
-char * env_find(char *environment, char *variable);
-void env_delete(char *environment, char *variable);
-int env_insert(char *environment, char *variable,
- char *value);
+/**
+ * Given a pointer to an environment, a variable name, and a value,
+ * inserts that variable into the environment table with the
+ * designated value. Returns 0 for success, -1 for failure.
+ */
+int env_insert(char *environment, const char *variable, const char *value);
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/core/fileio.cpp b/engines/mads/madsv2/core/fileio.cpp
index 9b1f4546afd..a8554f31b75 100644
--- a/engines/mads/madsv2/core/fileio.cpp
+++ b/engines/mads/madsv2/core/fileio.cpp
@@ -61,7 +61,7 @@ void fileio_name_new_ext(char *bakfile, char *mainfile, char *new_ext) {
Common::strcpy_s(temp_dir, mainfile);
- _fullpath(temp_full, temp_dir, 80);
+ mads_fullpath(temp_full, temp_dir, 80);
_splitpath(temp_full, temp_drive, temp_dir, temp_name, temp_ext);
@@ -166,11 +166,19 @@ int fileio_copy(const char *source, const char *dest) {
return -1;
}
-long fileio_setpos(Common::SeekableReadStream *handle, long pos) {
- return handle->seek(pos);
+long fileio_setpos(Common::Stream *handle, long pos) {
+ auto *rs = dynamic_cast<Common::SeekableReadStream *>(handle);
+ auto *ws = dynamic_cast<Common::SeekableWriteStream *>(handle);
+
+ if (rs)
+ return rs->pos();
+ if (ws)
+ return ws->pos();
+
+ return -1;
}
-long fileio_fread_f(byte *target, long record_size, long record_count, Common::SeekableReadStream *handle) {
+long fileio_fread_f(void *target, long record_size, long record_count, Common::SeekableReadStream *handle) {
if (!record_size)
return 0;
@@ -180,7 +188,7 @@ long fileio_fread_f(byte *target, long record_size, long record_count, Common::S
return total_read / record_size;
}
-long fileio_fwrite_f(const byte *source, long record_size, long record_count, Common::WriteStream *handle) {
+long fileio_fwrite_f(const void *source, long record_size, long record_count, Common::WriteStream *handle) {
if (!record_size)
return 0;
diff --git a/engines/mads/madsv2/core/fileio.h b/engines/mads/madsv2/core/fileio.h
index 9b7b76730f8..0a775f4eb63 100644
--- a/engines/mads/madsv2/core/fileio.h
+++ b/engines/mads/madsv2/core/fileio.h
@@ -39,7 +39,7 @@ int fileio_ffputs(const char *mystring, Common::WriteStream *stream);
char *fileio_fix_lf_input(char *mystring);
void fileio_fix_lf_output(char *mystring);
int fileio_copy(const char *source, const char *dest);
-long fileio_setpos(Common::SeekableReadStream *handle, long pos);
+long fileio_setpos(Common::Stream *handle, long pos);
long fileio_fread_f(void *buffer, long size, long count, Common::SeekableReadStream *stream);
long fileio_fwrite_f(const void *buffer, long size, long count, Common::WriteStream *stream);
long fileio_file_to_file(Common::SeekableReadStream *from, Common::WriteStream *to, long count);
diff --git a/engines/mads/madsv2/core/font.cpp b/engines/mads/madsv2/core/font.cpp
new file mode 100644
index 00000000000..dbdc3fa356f
--- /dev/null
+++ b/engines/mads/madsv2/core/font.cpp
@@ -0,0 +1,222 @@
+/* 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 "mads/madsv2/core/general.h"
+#include "mads/madsv2/core/mem.h"
+#include "mads/madsv2/core/error.h"
+#include "mads/madsv2/core/loader.h"
+#include "mads/madsv2/core/font.h"
+#include "mads/madsv2/core/buffer.h"
+#include "mads/madsv2/core/color.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+FontPtr font_inter = NULL;
+FontPtr font_main = NULL; /* Interface & main font handles */
+FontPtr font_conv = NULL;
+FontPtr font_menu = NULL;
+FontPtr font_misc = NULL;
+
+byte font_colors[4] = { COLOR_TRANSPARENT, 15, 7, 8 };
+
+
+FontPtr font_load(const char *name) {
+ char temp_buf_2[80];
+ char *mark;
+ char block_name[20];
+ long size;
+ FontPtr new_font = NULL;
+ FontPtr result = NULL;
+ Load load_handle;
+
+ mem_last_alloc_loader = MODULE_FONT_LOADER;
+
+ load_handle.open = false;
+
+ Common::strcpy_s(temp_buf_2, name);
+ mark = strchr(temp_buf_2, '.');
+ if (mark == NULL) {
+ Common::strcat_s(temp_buf_2, ".FF");
+ }
+
+ mark = temp_buf_2;
+ if (*mark == '*') mark++;
+ strncpy(block_name, mark, 8);
+
+ if (loader_open(&load_handle, temp_buf_2, "rb", true)) goto done;
+
+ size = load_handle.pack.strategy[0].size;
+
+ new_font = (FontPtr)mem_get_name(size, block_name);
+ if (new_font == NULL) goto done;
+
+ if (!loader_read(new_font, size, 1, &load_handle)) goto done;
+
+ result = new_font;
+
+done:
+ if (new_font != NULL) {
+ if (result == NULL)
+ mem_free(new_font);
+ }
+ if (load_handle.open)
+ loader_close(&load_handle);
+
+ return result;
+}
+
+int font_write(FontPtr font, Buffer *target, char *out_string,
+ int x, int y, int auto_spacing) {
+ int target_wrap;
+ int screen_loc;
+ int skip_top = 0;
+ int skip_bottom = 0;
+ int bottom;
+ int return_value = 0;
+ char temp_buf[80];
+ byte colors[4];
+ char height;
+ byte *target_ptr;
+
+ *(uint32 *)&colors[0] = *(uint32 *)&font_colors[0];
+
+ Common::strcpy_s(temp_buf, out_string);
+
+ if (y < 0) {
+ skip_top = 0 - y;
+ y = 0;
+ }
+
+ height = (byte)MAX(0, (int)font->max_y_size - skip_top);
+
+ bottom = y + height - 1;
+ if (bottom > (target->y - 1)) {
+ skip_bottom = MIN((int)height, (bottom - (target->y - 1)));
+ height -= skip_bottom;
+ }
+
+ if (height <= 0) goto finish;
+
+ target_ptr = (byte *)buffer_pointer(target, x, y);
+ target_wrap = target->x;
+ screen_loc = x;
+
+ for (char *str = temp_buf; *str != '\0'; str++) {
+ /* char_loop: decrement character for pointer (original did dec dl / jns),
+ so '\0' (0) decrements to -1 (negative) and exits. Characters are
+ 1-based indices into the font table. */
+ byte ch_idx = (byte)(*str - 1);
+
+ byte char_width = font->width[ch_idx];
+
+ if (char_width == 0)
+ continue; /* char_next with zero width: no spacing applied */
+
+ screen_loc += char_width;
+ if (screen_loc >= target_wrap)
+ break; /* terminate */
+
+ /* Locate the character's pixel data in the font, skipping clipped rows.
+ Each row of a character is packed 4 pixels per byte, so row stride
+ is ceil(char_width / 4) = (char_width - 1) / 4 + 1 = (char_width + 3) >> 2 */
+ byte *glyph = font->data[ch_idx];
+
+ if (skip_top > 0) {
+ int row_stride = ((char_width - 1) >> 2) + 1;
+ glyph += skip_top * row_stride;
+ }
+
+ /* Draw the character glyph */
+ byte *row_ptr = target_ptr;
+
+ for (int row = 0; row < height; row++) {
+ byte *pixel_ptr = row_ptr;
+ int pixels_left = char_width;
+ byte data = *glyph++;
+ int pack_count = 4; /* 4 pixels packed per byte, 2 bits each */
+
+ while (pixels_left > 0) {
+ /* Shift next 2-bit color index into the high bits of AX,
+ then read into the low byte. Original: xor ah,ah / shl ax,2
+ with AL holding the packed byte - shifts top 2 bits of AL
+ into AH as the color index (0-3). */
+ byte color_idx = (data >> 6) & 0x03;
+ data <<= 2;
+
+ byte color = colors[color_idx];
+ if (color != COLOR_TRANSPARENT)
+ *pixel_ptr = color;
+
+ pixel_ptr++;
+ pixels_left--;
+
+ if (pixels_left == 0)
+ break;
+
+ pack_count--;
+ if (pack_count == 0) {
+ data = *glyph++;
+ pack_count = 4;
+ }
+ }
+
+ row_ptr += target_wrap;
+ }
+
+ /* char_next: advance target pointer by character width + autospacing */
+ target_ptr += char_width + auto_spacing;
+ screen_loc += auto_spacing;
+ }
+
+ /* Return value is the final X coordinate reached */
+ return_value = (int)(target_ptr - buffer_pointer(target, x, y)) + x;
+
+finish:
+ return return_value;
+}
+
+void font_set_colors(int zero, int one, int two, int three) {
+ font_colors[0] = (byte)zero;
+ font_colors[1] = (byte)one;
+ font_colors[2] = (byte)two;
+ font_colors[3] = (byte)three;
+}
+
+int font_string_width(FontPtr font, const char *out_string, int auto_spacing) {
+ int width;
+ int more_width;
+ int idx;
+
+ width = 0;
+
+ for (; *out_string != 0;) {
+ idx = *(out_string++) - 1;
+ more_width = font->width[idx];
+ if ((more_width > 0) && (*out_string)) more_width += auto_spacing;
+ width += more_width;
+ }
+
+ return (width);
+}
+
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/core/font.h b/engines/mads/madsv2/core/font.h
index 62488b4c313..8f9dae6a46a 100644
--- a/engines/mads/madsv2/core/font.h
+++ b/engines/mads/madsv2/core/font.h
@@ -50,24 +50,12 @@ extern FontPtr font_conv; /* Font handle for conversations */
extern FontPtr font_menu; /* Font handle for menu stuff */
extern FontPtr font_misc; /* Font handle for symbols & icons */
-/* font_1.cpp */
-FontPtr font_load(const char *name);
-/* font_2.cpp */
-int font_write(FontPtr font, Buffer *target, const char *out_string, int x, int y,
- int auto_spacing);
-
-/* font_3.cpp */
-void font_set_colors(int background,
- int high_intense,
- int med_intense,
- int low_intense);
-
-/* font_4.cpp */
-int font_string_width(FontPtr font, const char *out_string, int auto_spacing);
-
-/* font_5.cpp */
-void font_init(FontPtr font);
+extern FontPtr font_load(const char *name);
+extern int font_write(FontPtr font, Buffer *target, const char *out_string,
+ int x, int y, int auto_spacing);
+extern void font_set_colors(int background, int high_intense, int med_intense, int low_intense);
+extern int font_string_width(FontPtr font, const char *out_string, int auto_spacing);
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/core/font_1.cpp b/engines/mads/madsv2/core/font_1.cpp
deleted file mode 100644
index 62c403714e4..00000000000
--- a/engines/mads/madsv2/core/font_1.cpp
+++ /dev/null
@@ -1,84 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include "mads/madsv2/core/general.h"
-#include "mads/madsv2/core/mem.h"
-#include "mads/madsv2/core/error.h"
-#include "mads/madsv2/core/loader.h"
-#include "mads/madsv2/core/font.h"
-
-namespace MADS {
-namespace MADSV2 {
-
-FontPtr font_inter = NULL;
-FontPtr font_main = NULL; /* Interface & main font handles */
-FontPtr font_conv = NULL;
-FontPtr font_menu = NULL;
-FontPtr font_misc = NULL;
-
-
-FontPtr font_load(const char *name) {
- char temp_buf_2[80];
- char *mark;
- char block_name[20];
- long size;
- FontPtr new_font = NULL;
- FontPtr result = NULL;
- Load load_handle;
-
- mem_last_alloc_loader = MODULE_FONT_LOADER;
-
- load_handle.open = false;
-
- Common::strcpy_s(temp_buf_2, name);
- mark = strchr(temp_buf_2, '.');
- if (mark == NULL) {
- Common::strcat_s(temp_buf_2, ".FF");
- }
-
- mark = temp_buf_2;
- if (*mark == '*') mark++;
- strncpy(block_name, mark, 8);
-
- if (loader_open(&load_handle, temp_buf_2, "rb", true)) goto done;
-
- size = load_handle.pack.strategy[0].size;
-
- new_font = (FontPtr)mem_get_name(size, block_name);
- if (new_font == NULL) goto done;
-
- if (!loader_read(new_font, size, 1, &load_handle)) goto done;
-
- result = new_font;
-
-done:
- if (new_font != NULL) {
- if (result == NULL)
- mem_free(new_font);
- }
- if (load_handle.open)
- loader_close(&load_handle);
-
- return result;
-}
-
-} // namespace MADSV2
-} // namespace MADS
diff --git a/engines/mads/madsv2/core/general.h b/engines/mads/madsv2/core/general.h
index 1c4d3880ab7..7c0a093a811 100644
--- a/engines/mads/madsv2/core/general.h
+++ b/engines/mads/madsv2/core/general.h
@@ -134,21 +134,35 @@ typedef struct { /* Video buffer structure */
#define sgn_in(x,s) ( ((s) >= 0) ? (x) : (neg(x)) ) /* Incorporate sign */
-inline void mads_strupr(char *s) {
- for (; *s; ++s)
+inline char *mads_strupr(char *str) {
+ for (char *s = str; *s; ++s)
*s = toupper(*s);
+ return str;
}
-inline void mads_strlwr(char *s) {
- for (; *s; ++s)
+inline char *mads_strlwr(char *str) {
+ for (char *s = str; *s; ++s)
*s = tolower(*s);
+ return str;
}
+
inline char *mads_itoa(int value, char *buffer, int radix) {
assert(radix == 10);
Common::strcpy_s(buffer, 16, Common::String::format("%d", value).c_str());
return buffer;
}
+inline void mads_chdir(const char *path) {}
+inline void mads_chdrive(int drive) {}
+inline int mads_getdrive() { return 3; }
+inline void mads_fullpath(char *buffer, const char *path, uint bufferCount) {
+ Common::strcpy_s(buffer, bufferCount, path);
+}
+inline char *mads_getcwd(char *buffer, int count) {
+ *buffer = '\0';
+ return buffer;
+}
+
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/core/himem.cpp b/engines/mads/madsv2/core/himem.cpp
index 2cf8700a684..825039341d1 100644
--- a/engines/mads/madsv2/core/himem.cpp
+++ b/engines/mads/madsv2/core/himem.cpp
@@ -107,10 +107,10 @@ done:
return error_flag;
}
-int himem_resident(char *filename) {
+int himem_resident(const char *filename) {
int id = -1;
int count;
- char *mark;
+ const char *mark;
long dir_size;
HimemDirectory *himem_xms_directory = NULL;
diff --git a/engines/mads/madsv2/core/himem.h b/engines/mads/madsv2/core/himem.h
index 10501ce7c46..2785339793f 100644
--- a/engines/mads/madsv2/core/himem.h
+++ b/engines/mads/madsv2/core/himem.h
@@ -43,11 +43,11 @@ typedef struct {
} HimemDirectory;
-extern byte himem_preload_ems_disabled;
-extern byte himem_preload_xms_disabled;
+extern byte himem_preload_ems_disabled;
+extern byte himem_preload_xms_disabled;
-extern byte himem_directory_allocation;
-extern HimemDirectory himem_directory_save_area;
+extern byte himem_directory_allocation;
+extern HimemDirectory himem_directory_save_area;
extern HimemDirectory *himem_directory;
extern HimemDirectory *himem_directory_entry;
extern HimemDirectory *himem_ems_directory;
@@ -59,34 +59,18 @@ extern int himem_active;
extern int himem_ems_preloaded;
extern int himem_xms_preloaded;
-/* himem_1.cpp */
-int himem_activate_directory(void);
-/* himem_2.cpp */
-int fastcall himem_get_directory_entry(int id);
-
-/* himem_3.cpp */
-int fastcall himem_put_directory_entry(int id);
-
-/* himem_4.cpp */
-int himem_resident(char *filename);
-void himem_catalog(void);
-
-/* himem_5.cpp */
-int himem_directory_setup(void);
-
-/* himem_6.cpp */
-void himem_shutdown(void);
-void himem_startup(void);
-
-/* himem_7.cpp */
-int fastcall himem_preload(char *filename, int level);
-
-/* himem_8.cpp */
-int fastcall himem_preload_series(char *filename, int level);
-
-/* himem_9.cpp */
-void fastcall himem_flush(int level);
+extern int himem_activate_directory();
+extern int himem_get_directory_entry(int id);
+extern int himem_put_directory_entry(int id);
+extern int himem_resident(const char *filename);
+extern void himem_catalog();
+extern int himem_directory_setup();
+extern void himem_shutdown();
+extern void himem_startup();
+extern int himem_preload(char *filename, int level);
+extern int himem_preload_series(char *filename, int level);
+extern void himem_flush(int level);
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/core/hspot.cpp b/engines/mads/madsv2/core/hspot.cpp
new file mode 100644
index 00000000000..aed044459b9
--- /dev/null
+++ b/engines/mads/madsv2/core/hspot.cpp
@@ -0,0 +1,231 @@
+/* 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 "mads/madsv2/core/hspot.h"
+#include "mads/madsv2/core/cursor.h"
+#include "mads/madsv2/core/error.h"
+#include "mads/madsv2/core/screen.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+Spot spot[max_hot_spots + 1]; /* The list */
+int numspots = 0;
+
+int hs_stack[HS_STACK_SIZE + 1]; /* For push/popping the list */
+int hs_stack_pointer;
+
+static int hspot_special_num;
+int hotkeys[max_hot_spots + 1];
+
+
+int hspot_add(int ul_x, int ul_y, int lr_x, int lr_y,
+ int class_, int num, int video_mode) {
+ if (numspots == max_hot_spots) {
+ error_report(ERROR_TOO_MANY_DAMN_HOTSPOTS, ERROR, MODULE_HOTSPOT, class_, num);
+ return(no);
+ }
+
+ numspots++;
+ spot[numspots].ul_x = ul_x;
+ spot[numspots].ul_y = ul_y;
+ spot[numspots].lr_x = lr_x;
+ spot[numspots].lr_y = lr_y;
+ spot[numspots]._class = class_;
+ spot[numspots].num = num;
+ spot[numspots].active = yes;
+ spot[numspots].video_mode = video_mode;
+
+ return yes;
+}
+
+int hspot_push() {
+ int a;
+
+ if (hs_stack_pointer >= HS_STACK_SIZE)
+ return(no);
+ for (a = 1; a <= numspots; a++)
+ spot[a].active = no;
+ hs_stack[++hs_stack_pointer] = numspots;
+
+ return yes;
+}
+
+int hspot_pop() {
+ int a;
+
+ if (hs_stack_pointer <= 0)
+ return(no);
+ numspots = hs_stack[hs_stack_pointer--];
+ for (a = 1; a <= numspots; a++)
+ spot[a].active = yes;
+ return(yes);
+}
+
+/**
+ * Packs the hotspot list by removing any blank entries
+ */
+void hspot_pack() {
+ int from, unto;
+
+ unto = 0;
+
+ for (from = 1; from <= numspots; from++) {
+ if (spot[from].num != HS_DEATH) /* If it's still alive */
+ {
+ unto++;
+ if (from != unto) /* If it's actually going to move */
+ spot[unto] = spot[from]; /* Shift spot down */
+ }
+ }
+
+ numspots = unto;
+}
+
+
+int hspot_remove(int class_, int num) {
+ int a, cleared;
+
+ /* Clear ALL hotspots */
+ if (class_ == HS_ALL) {
+ a = numspots;
+ numspots = 0;
+ return a;
+ }
+
+ cleared = 0;
+ for (a = 1; a <= numspots; a++) {
+ if ((spot[a]._class == class_) &&
+ (num == HS_ALL || spot[a].num == num)) {
+ spot[a].num = HS_DEATH;
+ if (num != HS_ALL) {
+ hspot_pack();
+ return(1);
+ }
+
+ cleared++;
+ }
+ }
+
+ hspot_pack();
+ return cleared;
+}
+
+void hspot_toggle(int class_, int num, int active) {
+ int count;
+
+ for (count = 1; count <= numspots; count++) {
+ if ((spot[count]._class == class_) && (spot[count].num == num)) {
+ spot[count].active = active;
+ }
+ }
+}
+
+void hspot_wipe() {
+ int count;
+
+ numspots = 0;
+ for (count = 0; count < max_hot_spots; count++) {
+ hotkeys[count] = -1;
+ }
+
+ hotkeys[max_hot_spots] = -1;
+}
+
+
+int hspot_key(int key) {
+ int result = -1;
+ int count;
+
+ for (count = 0; count < max_hot_spots; count++) {
+ if (hotkeys[count] == key) {
+ result = count;
+ }
+ }
+
+ return result;
+}
+
+
+int hspot_begin(int x, int y, int class_, int num, int hotkey) {
+ cursor_set_follow(true);
+ cursor_set_pos(x, y);
+
+ hspot_add(x, y, x, y, class_, num, screen_video_mode);
+ hspot_special_num = numspots;
+ hotkeys[num] = hotkey;
+ return (x);
+}
+
+
+int hspot_end() {
+ int x, y;
+
+ cursor_get_pos(&x, &y);
+
+ spot[hspot_special_num].lr_x = x;
+ spot[hspot_special_num].lr_y = y;
+
+ cursor_set_follow(false);
+ return (x);
+}
+
+
+void hspot_dummy() {
+
+}
+
+int hspot_which(int coord_x, int coord_y, int video_mode) {
+ int a;
+
+ for (a = 1; a <= numspots; a++) {
+ if (spot[a].active &&
+ coord_x >= spot[a].ul_x &&
+ coord_x <= spot[a].lr_x &&
+ coord_y >= spot[a].ul_y &&
+ coord_y <= spot[a].lr_y &&
+ video_mode == spot[a].video_mode) {
+ return a;
+ }
+ }
+
+ return 0;
+}
+
+int hspot_which_reverse(int coord_x, int coord_y, int video_mode) {
+ int a;
+
+ for (a = numspots; a >= 1; a--) {
+ if (spot[a].active &&
+ coord_x >= spot[a].ul_x &&
+ coord_x <= spot[a].lr_x &&
+ coord_y >= spot[a].ul_y &&
+ coord_y <= spot[a].lr_y &&
+ video_mode == spot[a].video_mode) {
+ return a;
+ }
+ }
+
+ return 0;
+}
+
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/core/hspot.h b/engines/mads/madsv2/core/hspot.h
index b3c0fcb31d8..90b41065939 100644
--- a/engines/mads/madsv2/core/hspot.h
+++ b/engines/mads/madsv2/core/hspot.h
@@ -48,39 +48,51 @@ typedef struct {
extern Spot spot[max_hot_spots + 1];
extern int numspots;
-
-
extern int hotkeys[max_hot_spots + 1];
+/**
+ * Adds a spot to the list given it's data.
+ * @return Returns TRUE if successful, FALSE if an error occured.
+ */
+extern int hspot_add(int ul_x, int ul_y, int lr_x, int lr_y, int class_, int num, int video_mode);
-/* hspot_1.c */
-int hspot_add(int ul_x, int ul_y,
- int lr_x, int lr_y,
- int class_, int num, int video_mode);
-
-/* hspot_2.c */
-int hspot_push(void);
-int hspot_pop(void);
-
-/* hspot_4.c */
-int hspot_remove(int class_, int num);
-
-/* hspot_5.c */
-void hspot_toggle(int class_, int num, int active);
-
-/* hspot_6.c */
-void hspot_wipe(void);
-int hspot_key(int key);
-int hspot_begin(int x, int y, int class_, int num, int hotkey);
-int hspot_end(void);
+/**
+ * Marks current spots as inactive, and pushes pointer
+ */
+extern int hspot_push();
-void hspot_dummy(void);
+/**
+ * Restores the hotspot list from a push_spots call
+ */
+extern int hspot_pop();
-/* hspot_7.c */
-int hspot_which(int x, int y, int video_mode);
+/**
+ * Given the class and number, removes that hotspot from the list.
+ *
+ * If <class> is HS_ALL then ALL hotspots are cleared.
+ * If <num> is HS_ALL then ALL hotspots for that class are cleared.
+ * @return Returns number of hotspots that were erased.
+ */
+extern int hspot_remove(int class_, int num);
+extern void hspot_toggle(int class_, int num, int active);
+extern void hspot_wipe();
+extern int hspot_key(int key);
+extern int hspot_begin(int x, int y, int class_, int num, int hotkey);
+extern int hspot_end();
+extern void hspot_dummy();
+
+/**
+ * Given X,Y returns the hotspot the coordinates fall into.
+ * 0 is returned if coords are not in a hotspot.
+ */
+extern int hspot_which(int x, int y, int video_mode);
-/* hspot_8.c */
-int hspot_which_reverse(int x, int y, int video_mode);
+/**
+ * Given X,Y returns the hotspot the coordinates fall into.
+ * 0 is returned if coords are not in a hotspot.
+ *
+ */
+extern int hspot_which_reverse(int x, int y, int video_mode);
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/core/implode.h b/engines/mads/madsv2/core/implode.h
index 1d4e683de4f..35598551289 100644
--- a/engines/mads/madsv2/core/implode.h
+++ b/engines/mads/madsv2/core/implode.h
@@ -27,22 +27,19 @@
namespace MADS {
namespace MADSV2 {
-extern unsigned short implode(
- unsigned (*read_buff)(char *buffer, unsigned short *size),
- void (*write_buff)(char *buffer, unsigned short *size),
+extern word implode(
+ word (*read_buff)(char *buffer, word *size),
+ word (*write_buff)(char *buffer, word *size),
char *work_buff,
- unsigned short int *type,
- unsigned short int *dsize);
+ word *type,
+ word *dsize);
-extern unsigned explode(
- unsigned (*read_buff)(char *buffer, unsigned short *size),
- void (*write_buff)(char *buffer, unsigned short *size),
+extern word explode(
+ word (*read_buff)(char *buffer, word *size),
+ word (*write_buff)(char *buffer, word *size),
char *work_buff);
-extern unsigned long crc32(
- unsigned char *buffer,
- unsigned short int *size,
- unsigned long *old_crc);
+extern long crc32(unsigned char *buffer, word *size, long *old_crc);
#define CMP_BINARY 0
diff --git a/engines/mads/madsv2/core/kernel_2.cpp b/engines/mads/madsv2/core/kernel_2.cpp
deleted file mode 100644
index 289ef5e6741..00000000000
--- a/engines/mads/madsv2/core/kernel_2.cpp
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
-/* kernel_2.c by Brian Reynolds 5-Nov-91
-/*
-/* Makes active any vocab words that will be needed for this room,
-/* and loads their text into memory.
-/*
-/* Call after room definition and object list are loaded.
-*/
-
-#include <general.mac>
-
-#include <vocab.h>
-#include <object.h>
-#include <room.h>
-#include <inter.h>
-#include <mem.h>
-#include <fileio.h>
-
-#include "kernel.mac"
-#include "kernel_1.h"
-
-
-
-#pragma optimize ("weglt", on)
-
-
-int fastcall kernel_load_vocab (void)
-{
- int error_flag;
- int count;
- int count2;
- #ifdef log_vocab
- FILE *handle;
- long before, after;
- #endif
-
- /* Load all main command verbs */
-
- for (count = 0; count < INTER_COMMANDS; count++) {
- vocab_make_active (command[count].id);
- }
-
- /* Load all object names, and all verbs associated with objects */
-
- for (count = 0; count < num_objects; count++) {
- vocab_make_active (object[count].vocab_id);
-
- for (count2 = 0; count2 < (int)object[count].num_verbs; count2++) {
- vocab_make_active (object[count].verb[count2].id);
- }
- }
-
- /* Load vocabulary for this room's hot spots */
-
- for (count = 0; count < room_num_spots; count++) {
- vocab_make_active(room_spots[count].vocab);
- if (room_spots[count].verb > 0) {
- vocab_make_active(room_spots[count].verb);
- }
- }
-
- #ifdef log_vocab
- before = mem_get_avail();
- #endif
-
- error_flag = vocab_load_active();
-
- #ifdef log_vocab
- after = mem_get_avail();
- if (fileio_exist("vocab.log")) {
- handle = fopen("vocab.log", "wt");
- fprintf (handle, "Room %d Vocab words: %d Memory: %ld\n",
- room_id, vocab_active, before-after);
- fclose (handle);
- }
- #endif
-
- return (error_flag);
-}
-
-
diff --git a/engines/mads/madsv2/core/kernel_3.cpp b/engines/mads/madsv2/core/kernel_3.cpp
deleted file mode 100644
index 5a9efabc0b7..00000000000
--- a/engines/mads/madsv2/core/kernel_3.cpp
+++ /dev/null
@@ -1,459 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include "mads/madsv2/core/kernel.h"
-#include "mads/madsv2/core/general.h"
-#include "mads/madsv2/core/mem.h"
-#include "mads/madsv2/core/buffer.h"
-#include "mads/madsv2/core/font.h"
-#include "mads/madsv2/core/video.h"
-#include "mads/madsv2/core/matte.h"
-#include "mads/madsv2/core/inter.h"
-#include "mads/madsv2/core/mouse.h"
-#include "mads/madsv2/core/object.h"
-#include "mads/madsv2/core/error.h"
-#include "mads/madsv2/core/screen.h"
-#include "mads/madsv2/core/ems.h"
-#include "mads/madsv2/core/himem.h"
-#include "mads/madsv2/core/echo.h"
-#include "mads/madsv2/core/mcga.h"
-#include "mads/madsv2/core/timer.h"
-#include "mads/madsv2/core/cycle.h"
-#include "mads/madsv2/core/player.h"
-#include "mads/madsv2/core/keys.h"
-#include "mads/madsv2/core/pack.h"
-#include "mads/madsv2/core/room.h"
-#include "mads/madsv2/core/demo.h"
-#include "mads/madsv2/core/xms.h"
-#include "mads/madsv2/core/lock.h"
-#include "mads/madsv2/core/tile.h"
-#include "mads/madsv2/core/popup.h"
-#include "mads/madsv2/core/pal.h"
-#include "mads/madsv2/core/env.h"
-#include "mads/madsv2/core/fileio.h"
-#include "mads/madsv2/core/vocab.h"
-#include "mads/madsv2/core/kernel_1.h"
-#include "mads/madsv2/core/midi.h"
-#include "mads/madsv2/core/digi.h"
-
-namespace MADS {
-namespace MADSV2 {
-
-/*
-/* kernel_game_shutdown()
-/*
-/* Game level system shutdown.
-*/
-void kernel_game_shutdown() {
- int check_mode;
-
-
- sprite_free(&box_param.menu, true);
- sprite_free(&box_param.logo, true);
- sprite_free(&box_param.series, true);
-
- buffer_free(&scr_inter_orig);
-
- vocab_unload_active();
-
- /* Drop cursor */
-
- if (cursor != NULL) mem_free(cursor);
- cursor = NULL;
-
- /* Free main video work buffer */
-
- pack_set_special_buffer(NULL, NULL);
-
- object_unload();
- /* inter_deallocate_objects(); */
-
- popup_available = false;
-
- /* Remove special keyboard handler */
-
- keys_remove();
-
- /* Unload interface fonts */
-
- if (font_misc != NULL) mem_free(font_misc);
- if (font_menu != NULL) mem_free(font_menu);
- if (font_conv != NULL) mem_free(font_conv);
- if (font_inter != NULL) mem_free(font_inter);
- if (font_main != NULL) mem_free(font_main);
-
- font_main = font_conv = font_inter = NULL;
-
- /* Deallocate main screen buffer */
-
- if (work_screen_ems_handle < 0) buffer_free(&scr_main);
-
- /* Turn of speech system */
-
- /* pl if (speech_system_active) speech_shutdown(); */
-
- /* Return video to text mode */
-
- mouse_hide();
- check_mode = video_mode;
- mouse_init(false, text_mode);
- video_init(text_mode, (check_mode != text_mode));
-
- /* Deallocate EMS/XMS memory */
-
- himem_shutdown();
-
- /* Remove timer interrupt stuff */
-
- midi_uninstall();
- digi_uninstall();
-
- timer_activate_low_priority(NULL);
-
- timer_remove();
-
- /* mem_free (interrupt_stack_pointer); */
-}
-
-
-void kernel_force_refresh(void) {
- int count;
- int purge_flag = true;
-
- for (count = 0; count < (int)image_marker; count++) {
- if (image_list[count].flags == IMAGE_REFRESH) {
- purge_flag = false;
- }
- }
-
- if (purge_flag) matte_refresh_work();
-}
-
-
-
-static char digital_name[12] = "digital.aga";
-
-/*
-/* kernel_game_startup()
-/*
-/* Game level system startup.
-*/
-int kernel_game_startup(int game_video_mode, int load_flag,
- char *release_version, char *release_date) {
- int error_flag = true;
- int count, count2;
- int ems_temp;
- int ems_error;
- int pages;
- int reserve[EMS_PAGING_CLASSES];
- byte *interrupt_stack;
-#ifdef demo
- char temp_buf[20];
-#endif
-#ifndef disable_error_check
- int error_code = 0;
-#endif
-
- /*
- interrupt_stack_pointer = mem_get_name(KERNEL_INTERRUPT_STACK_SIZE, "$istack$");
- if (interrupt_stack_pointer == NULL) goto done;
-
- interrupt_stack_size = KERNEL_INTERRUPT_STACK_SIZE;
- */
-
- /* Set up EMS/XMS paging system, if any */
-
- himem_startup();
-
- ems_error = true;
-
- if (ems_exists) {
- work_screen_ems_handle = ems_get_page_handle(4);
- if (work_screen_ems_handle >= 0) {
- ems_error = false;
- }
- }
-
- if (tile_setup()) ems_error = true;
-
- if (ems_error) {
- if (ems_exists) {
- error_report(ERROR_NO_MORE_EMS, SEVERE, MODULE_KERNEL, ems_pages, work_screen_ems_handle);
- } else {
- error_report(ERROR_KERNEL_NO_EMS, SEVERE, MODULE_KERNEL, ems_exists, work_screen_ems_handle);
- }
- }
-
- /* pl if (speech_system_requested) {
- char digital_search[20];
- char digital_path[80];
- speech_ems_status = SPEECH_DELUXE;
- digital_search[0] = 0;
- if (!fileio_exist(digital_name)) {
- strcat (digital_search, "*");
- }
- strcat (digital_search, digital_name);
- env_get_path (digital_path, digital_search);
- speech_init (digital_path, speech_board_address,
- speech_board_type,
- speech_board_irq,
- speech_board_drq);
- }
- */
-
- if (ems_exists) {
- if (load_flag & KERNEL_STARTUP_POPUP) {
- object_ems_handle = ems_get_page_handle(4);
-
- ems_temp = ems_get_page_handle(4);
- if (ems_temp >= 0) popup_preserve_initiator[0] = ems_temp;
-
- ems_temp = ems_get_page_handle(4);
- if (ems_temp >= 0) popup_preserve_initiator[1] = ems_temp;
-
- ems_temp = ems_get_page_handle(4);
- if (ems_temp >= 0) popup_preserve_initiator[2] = ems_temp;
- }
- }
-
-
- if (ems_exists) {
- pages = ems_pages_free;
- for (count = 0; count < EMS_PAGING_CLASSES; count++) {
- reserve[EMS_PAGING_CLASSES] = 0;
- }
- if (pages >= 4) {
- reserve[EMS_PAGING_SYSTEM] = 4;
- pages -= 4;
- }
- ems_temp = MIN(pages >> 1, 64);
- reserve[EMS_PAGING_ROOM] = ems_temp;
- pages -= ems_temp;
-
- ems_temp = pages >> 2;
- reserve[EMS_PAGING_SECTION] = ems_temp;
- pages -= ems_temp;
-
- for (count = 0; count < EMS_PAGING_CLASSES; count++) {
- ems_paging_reserve[count] = 0;
- for (count2 = count - 1; count2 >= 0; count2--) {
- ems_paging_reserve[count] += reserve[count2];
- }
- }
- }
-
- /* Some preliminary copy protection stuff */
-
- /* lock_preliminary_check(); */
-
- /* Initialize sound driver jump table */
-
- /* pl sound_driver_null(); */
- timer_set_sound_flag(0);
-
- /* Video initialization */
-
- screen_dominant_mode(game_video_mode);
- video_init(game_video_mode, (game_video_mode != text_mode));
- mouse_init(true, game_video_mode);
-
- if (game_video_mode == mcga_mode) {
- mcga_compute_retrace_parameters();
- }
-
- /* Initialize the main screen work buffer & its sub-buffers */
-
- if (work_screen_ems_handle >= 0) {
- scr_main.x = video_x;
- scr_main.y = video_y;
- scr_main.data = ems_page[0];
- ems_map_buffer(work_screen_ems_handle);
- } else {
- buffer_init_name(&scr_main, video_x, video_y, "$scrmain");
- }
- if (scr_main.data == NULL) {
-#ifndef disable_error_check
- error_code = ERROR_NO_MORE_MEMORY;
-#endif
- goto done;
- }
-
- scr_work.x = scr_inter.x = video_x;
- scr_work.y = display_y;
- scr_inter.y = inter_size_y;
-
- scr_work.data = scr_main.data;
- scr_inter.data = (byte *)mem_normalize(buffer_pointer(&scr_main, 0, inter_base_y));
-
- buffer_fill(scr_main, 0);
-
- /* Load the main interface fonts */
-
- if (load_flag & KERNEL_STARTUP_FONT) {
- font_main = font_load("*FONTMAIN.FF");
- font_inter = font_load("*FONTINTR.FF");
- font_conv = font_load("*FONTCONV.FF");
- font_menu = font_load("*FONTMENU.FF");
- font_misc = font_load("*FONTMISC.FF");
-
- if ((font_main == NULL) || (font_inter == NULL) ||
- (font_conv == NULL) || (font_menu == NULL) ||
- (font_misc == NULL)) {
-#ifndef disable_error_check
- error_code = ERROR_KERNEL_NO_FONTS;
-#endif
- goto done;
- }
- }
-
-
- /* Install timer handler & low priority cycling interrupt */
-
- if (load_flag & KERNEL_STARTUP_INTERRUPT) {
- timer_install();
-
- midi_install();
- digi_install();
-
- /*
- if (!lock_verification()) {
- error_report (ERROR_COPY_PROTECTION, SEVERE, MODULE_LOCK, 0, 0);
- }
- timer_remove();
- timer_install();
- */
-
- cycling_active = false;
- timer_activate_low_priority(cycle_colors);
- keys_install();
- }
-
- /* Log in demo copy */
-
-#ifdef demo
- if (game_video_mode != text_mode) demo_log_in(release_version, release_date);
-#endif
-
- /* Mention EMS paging situation */
-
-#ifdef demo
- if (ems_paging_active) {
- ltoa(((long)ems_pages * EMS_PAGE_SIZE) >> 10, temp_buf, 10);
- echo(temp_buf, false);
- echo("K of EMS memory available.", true);
- } else {
- echo("EMS memory not available.", true);
- }
-
- if (xms_exists) {
- echo("XMS memory system detected.", true);
- }
-#endif
-
- /* Load the objects list */
-
- if (load_flag & KERNEL_STARTUP_OBJECTS) {
- /* inter_allocate_objects(); */
- if (object_load()) {
-#ifndef disable_error_check
- error_code = ERROR_KERNEL_NO_OBJECTS;
-#endif
- goto done;
- }
- if (inven_num_objects > 0) {
- active_inven = 0;
- }
- }
-
- /* Allow packing routines to use lower interrupt stack */
-
- interrupt_stack = timer_get_interrupt_stack();
- pack_set_special_buffer(interrupt_stack, NULL);
-
- /* Initialize player data structures */
-
- if (load_flag & KERNEL_STARTUP_PLAYER) player_init();
-
- popup_available = true;
-
- /* video_update (&scr_main, 0, 0, 0, 0, video_x, video_y); */
-
- Common::strcpy_s(box_param.name, "*BOX.SS");
-
- if (load_flag & KERNEL_STARTUP_CURSOR) {
- /* Wipe palette & prepare for cursor */
- pal_init(KERNEL_RESERVED_LOW_COLORS, KERNEL_RESERVED_HIGH_COLORS);
- pal_white(master_palette);
- if (video_mode == mcga_mode) {
- mcga_setpal_range(&master_palette, 0, 4);
- }
-
- /* Load cursor sprite series */
-
- cursor = sprite_series_load("*CURSOR.SS", PAL_MAP_RESERVED | PAL_MAP_DEFINE_RESERVED);
- if (cursor == NULL) {
-#ifndef disable_error_check
- error_code = ERROR_KERNEL_NO_CURSOR;
-#endif
- goto done;
- }
-
- /* Activate main cursor sprite as mouse cursor */
-
- cursor_last = cursor_id = (cursor->num_sprites > 1) ? 2 : 1;
- mouse_cursor_sprite(cursor, cursor_id);
- }
-
- if (load_flag & KERNEL_STARTUP_VOCAB) {
- vocab_load_active();
- }
-
- if (load_flag & KERNEL_STARTUP_INTERFACE) {
- buffer_init_name(&scr_inter_orig, video_x, inter_size_y, "$scrintr");
- if (scr_inter_orig.data == NULL) {
- error_code = ERROR_NO_MORE_MEMORY;
- goto done;
- }
- }
-
- if (load_flag & KERNEL_STARTUP_POPUP) {
- if (popup_box_load()) {
- error_code = ERROR_KERNEL_NO_POPUP;
- goto done;
- }
- }
-
- error_flag = false;
-
-done:
- if (load_flag & KERNEL_STARTUP_CURSOR_SHOW) mouse_show();
- if (error_flag) {
-#ifndef disable_error_check
- error_check_memory();
- error_report(error_code, ERROR, MODULE_KERNEL, 0, 0);
-#endif
- kernel_game_shutdown();
- }
- return (error_flag);
-}
-
-} // namespace MADSV2
-} // namespace MADS
diff --git a/engines/mads/madsv2/core/kernel_4.cpp b/engines/mads/madsv2/core/kernel_4.cpp
deleted file mode 100644
index 8f504714afe..00000000000
--- a/engines/mads/madsv2/core/kernel_4.cpp
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
-/* kernel_4.c by Brian Reynolds 6-Nov-91
-*/
-
-#include <string.h>
-
-#include <general.mac>
-#include <pal.h>
-#include <mouse.h>
-#include <sprite.h>
-#include <mem.h>
-#include <inter.h>
-#include <error.h>
-#include <video.h>
-#include <mcga.h>
-#include <sprite.h>
-#include <popup.h>
-
-#include "kernel.mac"
-#include "kernel_1.h"
-
-
-#pragma optimize ("weglt", on)
-
-
-/*
-/* kernel_section_shutdown()
-/*
-/* Section level system shutdown.
-*/
-void fastcall kernel_section_shutdown(void)
-{
- ;
-}
-
-
-/*
-/* kernel_section_startup()
-/*
-/* Section level system startup.
-*/
-int fastcall kernel_section_startup (int new_section)
-{
- int error_flag = true;
- #ifndef disable_error_check
- int error_code = 0;
- #endif
-
- /* Make note of new section number */
-
- previous_section = section_id;
- section_id = new_section;
-
- error_flag = false;
-
-done:
- /*
- if (error_flag) {
- #ifndef disable_error_check
- error_check_memory ();
- error_report (error_code, ERROR, MODULE_KERNEL, new_section, 0);
- #endif
- kernel_section_shutdown();
- }
- */
- return (error_flag);
-}
-
diff --git a/engines/mads/madsv2/core/kernel_5.cpp b/engines/mads/madsv2/core/kernel_5.cpp
deleted file mode 100644
index a09d6904f85..00000000000
--- a/engines/mads/madsv2/core/kernel_5.cpp
+++ /dev/null
@@ -1,276 +0,0 @@
-/*
-/* kernel_5.c by Brian Reynolds 7-Nov-91
-*/
-
-#include <string.h>
-
-#include <general.mac>
-
-#include <matte.h>
-#include <inter.h>
-#include <mem.h>
-#include <buffer.h>
-#include <room.h>
-#include <pal.h>
-#include <error.h>
-#include <anim.h>
-#include <vocab.h>
-#include <timer.h>
-#include <mouse.h>
-#include <video.h>
-#include <mcga.h>
-#include <rail.h>
-#include <cycle.h>
-#include <tile.h>
-#include <sprite.h>
-#include <popup.h>
-
-#include "kernel.mac"
-#include "kernel_1.h"
-#include "kernel_2.h"
-#include "kernel_8.h"
-#include "kernel_d.h"
-#include "kernel_o.h"
-
-
-#pragma optimize ("weglt", on)
-
-
-/*
-/* kernel_room_shutdown()
-/*
-/* Room level system shutdown.
-*/
-void fastcall kernel_room_shutdown (void)
-{
- inter_deallocate_objects();
-
- /* Dump all active series, followed by the interface animation */
-
- /*
- if (inter_anim != NULL) {
- anim_unload ((AnimPtr)inter_anim);
- buffer_free (&scr_inter_orig);
- mem_free (inter_anim);
- inter_anim = NULL;
- } else {
- if (scr_inter_orig.data != NULL) {
- buffer_free (&scr_inter_orig);
- }
- }
- */
-
- /* Dump the vocabulary list */
- /* vocab_unload_active(); */
-
- /* Dump the room hot spots */
-
- if (room_spots != NULL) {
- mem_free (room_spots);
- room_spots = NULL;
- room_num_spots = 0;
- }
-
- /* Remove our palette shadowing list */
-
- pal_activate_shadow (NULL);
-
- /* Dump the picture & attribute buffers, along with the room header */
-
- if (room != NULL) {
- room_unload (room,
- &scr_orig,
- &scr_depth,
- &scr_walk,
- &scr_special,
- &picture_map,
- &depth_map);
- room = NULL;
- }
-
- /*
- sprite_free (&box_param.menu, true);
- sprite_free (&box_param.logo, true);
- sprite_free (&box_param.series, true);
- */
-}
-
-
-int fastcall kernel_room_startup (int new_room, int initial_variant, char *interface, int new_palette)
-{
- int error_flag = true;
- int load_flags;
- #ifndef disable_error_check
- int error_code = 0;
- int error_data = 0;
- #endif
-
- /* Make a note of the new room number & variant */
-
- previous_room = room_id;
- room_id = new_room;
- room_variant = initial_variant;
-
- /* Start a brand new palette, reserving the proper # of colors */
-
- if (new_palette) pal_init (KERNEL_RESERVED_LOW_COLORS, KERNEL_RESERVED_HIGH_COLORS);
-
- pal_white (master_palette);
-
- /* Load up popup box frame */
-
- /*
- if (popup_box_load()) {
- error_code = ERROR_KERNEL_NO_POPUP;
- goto done;
- }
- */
-
- /* Initialize the matteing system */
-
- matte_init (false);
-
- /* Initialize graphics sequence data structures */
-
- kernel_seq_init();
- kernel_message_init();
-
- /* Activate the main shadow list */
-
- pal_activate_shadow (&kernel_shadow_main);
-
- /* Load header, picture, and attribute screen for this room */
-
- load_flags = ROOM_LOAD_HARD_SHADOW;
- if (kernel.translating) load_flags |= ROOM_LOAD_TRANSLATE;
-
- room = room_load (room_id, room_variant, NULL,
- &scr_orig,
- &scr_depth,
- &scr_walk,
- &scr_special,
- &picture_map,
- &depth_map,
- &picture_resource,
- &depth_resource,
- tile_picture_handle,
- tile_attribute_handle,
- load_flags);
- if (room == NULL) {
- #ifndef disable_error_check
- error_data = room_load_error;
- error_code = ERROR_KERNEL_NO_ROOM;
- #endif
- goto done;
- }
-
- tile_pan (&picture_map, picture_view_x, picture_view_y);
- tile_pan (&depth_map, picture_view_x, picture_view_y);
-
- /* Set up color cycling table for this room */
-
- cycle_init (&room->cycle_list, false);
-
- /* Initialize rail-system parameters for this room */
-
- rail_num_nodes = room->num_rails + 2;
- rail_base = (byte *) &room->rail[0];
-
- rail_connect_all_nodes();
-
- /* Load up the room's hotspot table */
-
- room_spots = room_load_hotspots (room_id, &room_num_spots);
- if (room_spots == NULL) {
- #ifndef disable_error_check
- error_code = ERROR_KERNEL_NO_HOTSPOTS;
- #endif
- goto done;
- }
-
- /* Load the necessary part of the vocabulary list */
- /*
- if (kernel_load_vocab()) {
- #ifndef disable_error_check
- error_code = ERROR_KERNEL_NO_VOCAB;
- #endif
- goto done;
- }
- */
-
- /* Load up an interface animation w/ background */
-
- /* scr_inter_orig.data = NULL; */
-
- /*
- pal_activate_shadow (&kernel_shadow_inter);
-
- load_flags = PAL_MAP_RESERVED | ANIM_LOAD_BACKGROUND;
- if (kernel.translating) load_flags |= ANIM_LOAD_TRANSLATE;
- if (!inter_animation_running) load_flags |= ANIM_LOAD_BACK_ONLY;
-
- inter_anim = (AnimInterPtr) anim_load (interface,
- &scr_inter_orig, NULL,
- NULL, NULL,
- NULL, NULL,
- NULL, NULL, load_flags);
- if (inter_anim == NULL) {
- #ifndef disable_error_check
- error_code = ERROR_KERNEL_NO_INTERFACE;
- strcpy (error_string, interface);
- #endif
- goto done;
- }
-
- if (!inter_anim->num_series) {
- mem_free (inter_anim);
- inter_anim = NULL;
- }
-
- pal_activate_shadow (&kernel_shadow_main);
- */
-
- inter_anim = NULL;
-
- /* Make preliminary scaling computations */
-
- kernel_room_bound_dif = room->front_y - room->back_y;
- kernel_room_scale_dif = room->front_scale - room->back_scale;
-
- /* Initialize the graphics image lists */
-
- image_marker = 1;
- image_list[0].flags = IMAGE_REFRESH;
- image_list[0].segment_id = KERNEL_SEGMENT_SYSTEM;
-
- /* Set up graphics window locations */
-
- viewing_at_y = 0;
- inter_viewing_at_y = inter_base_y;
-
- /* Mark the boundary between interface and room sprite series */
-
- kernel_room_series_marker = series_list_marker;
-
- /* Set up interface background screen */
-
- kernel_set_interface_mode (inter_input_mode);
-
- /* Mouse cursor on */
-
- while ((char)mouse_showing > 0) mouse_show();
-
- inter_allocate_objects();
-
- error_flag = false;
-
-done:
- if (error_flag) {
- #ifndef disable_error_check
- error_check_memory();
- error_report (error_code, ERROR, MODULE_KERNEL, room_id, error_data);
- #endif
- kernel_room_shutdown();
- }
- return (error_flag);
-}
diff --git a/engines/mads/madsv2/core/kernel_6.cpp b/engines/mads/madsv2/core/kernel_6.cpp
deleted file mode 100644
index 950ae7e05b1..00000000000
--- a/engines/mads/madsv2/core/kernel_6.cpp
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
-/* kernel_6.c by Brian Reynolds 7-Nov-91
-*/
-
-#include <string.h>
-
-#include <general.mac>
-#include <matte.h>
-#include <sprite.h>
-#include <mem.h>
-#include <error.h>
-#include <pal.h>
-#include <mcga.h>
-
-#include "kernel.mac"
-#include "kernel_1.h"
-
-#pragma optimize ("weglt", on)
-
-/*
-/* kernel_unload_all_series(void)
-/*
-/* Unloads all room series.
-*/
-void fastcall kernel_unload_all_series(void)
-{
- int count;
-
- /* Unload all series (but don't unload those for the interface background) */
-
- for (count = series_list_marker - 1; count >= kernel_room_series_marker; count--) {
- if (series_user[count] > 1) series_user[count] = 1;
- matte_deallocate_series (count, true);
- }
-}
-
-
-/*
-/* kernel_load_series()
-/*
-/* Loads a sprite series for the room.
-*/
-int fastcall kernel_load_series (char *name, int load_flags)
-{
- int handle = -2;
-
- if (kernel.translating) load_flags |= SPRITE_LOAD_TRANSLATE;
-
- handle = matte_load_series (name, load_flags, 0);
-
-done:
- if ((handle < 0) && !kernel_ok_to_fail_load) {
- #ifndef disable_error_check
- strcpy (error_string, name);
- error_report (ERROR_SERIES_LOAD_FAILED, WARNING, MODULE_KERNEL, handle, sprite_error);
- #endif
- }
-
- return (handle);
-}
-
diff --git a/engines/mads/madsv2/core/kernel_7.cpp b/engines/mads/madsv2/core/kernel_7.cpp
deleted file mode 100644
index d1883fc57ad..00000000000
--- a/engines/mads/madsv2/core/kernel_7.cpp
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
-/* kernel_7.c by Brian Reynolds 14-Nov-91
-*/
-
-#include <general.mac>
-#include <inter.h>
-#include <hspot.h>
-#include <error.h>
-#include "kernel.mac"
-#include "kernel_1.h"
-
-
-#pragma optimize ("weglt", on)
-/*
-/* kernel_flip_hotspot()
-/*
-/* Toggles an interface hotspot (referenced by its vocabulary word)
-/* on or off. Hotspots that are off do not interact with the mouse
-/* cursor.
-*/
-void fastcall kernel_flip_hotspot (int vocab_code, int active)
-{
- int count;
-
- for (count = 0; count < room_num_spots; count++) {
- if (room_spots[count].vocab == vocab_code) {
- room_spots[count].active = (byte) active;
- hspot_toggle(STROKE_INTERFACE, count, active);
- }
- }
-}
-
-
-
-/*
-/* kernel_flip_hotspot()
-/*
-/* Toggles an interface hotspot (referenced by its vocabulary word)
-/* on or off. Hotspots that are off do not interact with the mouse
-/* cursor.
-/*
-/* Only hotspots which contain the point (X, Y) are affected.
-*/
-void fastcall kernel_flip_hotspot_loc (int vocab_code, int active, int x, int y)
-{
- int count;
-
- for (count = 0; count < room_num_spots; count++) {
- if (room_spots[count].vocab == vocab_code) {
- if ((x >= room_spots[count].ul_x) &&
- (x <= room_spots[count].lr_x) &&
- (y >= room_spots[count].ul_y) &&
- (y <= room_spots[count].lr_y)) {
- room_spots[count].active = (byte) active;
- hspot_toggle(STROKE_INTERFACE, count, active);
- }
- }
- }
-}
-
diff --git a/engines/mads/madsv2/core/kernel_8.cpp b/engines/mads/madsv2/core/kernel_8.cpp
deleted file mode 100644
index 0ba69b8f422..00000000000
--- a/engines/mads/madsv2/core/kernel_8.cpp
+++ /dev/null
@@ -1,466 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include "mads/madsv2/core/general.h"
-#include "mads/madsv2/core/anim.h"
-#include "mads/madsv2/core/matte.h"
-#include "mads/madsv2/core/error.h"
-#include "mads/madsv2/core/player.h"
-#include "mads/madsv2/core/sprite.h"
-#include "mads/madsv2/core/attr.h"
-
-#include "mads/madsv2/core/kernel.h"
-#include "mads/madsv2/core/kernel_1.h"
-#include "mads/madsv2/core/kernel_f.h"
-#include "mads/madsv2/core/kernel_9.h"
-
-namespace MADS {
-namespace MADSV2 {
-
-Sequence sequence_list[KERNEL_MAX_SEQUENCES];
-
-void kernel_seq_init(void) {
- int count;
-
- for (count = 0; count < KERNEL_MAX_SEQUENCES; count++) {
- sequence_list[count].active_flag = false;
- sequence_list[count].dynamic_hotspot = -1;
- }
-}
-
-int kernel_seq_add(int series_id, int mirror, int initial_sprite,
- int low_sprite, int high_sprite, int loop_mode, int loop_direction,
- int depth, int scale, int auto_locating, int x, int y,
- word ticks, word interval_ticks, word start_ticks, int expire) {
- int result = -1;
- int id = -1;
- int found = false;
- int count;
-
- for (count = 0; !found && (count < KERNEL_MAX_SEQUENCES); count++) {
- id = count;
- found = !sequence_list[count].active_flag;
- }
-
- if (!found) {
-#if !defined(disable_error_check)
- error_report(ERROR_SEQUENCE_LIST_FULL, WARNING, MODULE_KERNEL, KERNEL_MAX_SEQUENCES, 0);
-#endif
- goto done;
- }
-
- if (low_sprite <= 0) {
- low_sprite = 1;
- }
-
- if (high_sprite <= 0) {
- high_sprite = series_list[series_id]->num_sprites;
- }
-
- if (high_sprite == low_sprite) {
- loop_direction = 0;
- }
-
- sequence_list[id].active_flag = true;
- sequence_list[id].series_id = (byte)series_id;
- sequence_list[id].mirror = (byte)mirror;
- sequence_list[id].sprite = initial_sprite;
- sequence_list[id].start_sprite = low_sprite;
- sequence_list[id].end_sprite = high_sprite;
- sequence_list[id].loop_mode = loop_mode;
- sequence_list[id].loop_direction = loop_direction;
- sequence_list[id].depth = (byte)depth;
- sequence_list[id].scale = (byte)scale;
- sequence_list[id].auto_locating = (byte)auto_locating;
- sequence_list[id].x = x;
- sequence_list[id].y = y;
- sequence_list[id].ticks = ticks;
- sequence_list[id].interval_ticks = interval_ticks;
- sequence_list[id].base_time = kernel.clock + start_ticks;
- sequence_list[id].expire = (byte)expire;
- sequence_list[id].expired = false;
-
- sequence_list[id].motion = 0;
- sequence_list[id].dynamic_hotspot = -1;
-
- sequence_list[id].num_triggers = 0;
- sequence_list[id].trigger_dest = (byte)kernel.trigger_setup_mode;
-
- for (count = 0; count < 3; count++) {
- sequence_list[id].trigger_words[count] = player2.words[count];
- }
-
- sequence_list[id].last_image.flags = -1;
-
- result = id;
-
-done:
- return result;
-}
-
-int kernel_seq_forward(int series_id, int mirror, word ticks,
- word interval_ticks, word start_ticks, int expire) {
- int depth;
- SpritePtr sprite;
-
- sprite = &series_list[series_id]->index[0];
-
- depth = attr_depth(&depth_map,
- sprite->x + (sprite->xs >> 1),
- sprite->y + (sprite->ys >> 1)) - 1;
-
- return kernel_seq_add(series_id, mirror, 1, 0, 0, AA_LINEAR, 1,
- depth, 100, true, 0, 0, ticks, interval_ticks,
- start_ticks, expire);
-}
-
-int kernel_seq_forward_scroll(int series_id, int mirror, word ticks,
- word interval_ticks, word start_ticks, int expire) {
- // TODO: depth isn't initialized?
- int depth = 0;
- SpritePtr sprite;
-
- sprite = &series_list[series_id]->index[0];
-
- return kernel_seq_add(series_id, mirror, 1, 0, 0, AA_LINEAR, 1,
- depth, 100, true, 0, 0, ticks, interval_ticks,
- start_ticks, expire);
-}
-
-int kernel_seq_pingpong(int series_id, int mirror, word ticks,
- word interval_ticks, word start_ticks, int expire) {
- int depth;
- SpritePtr sprite;
-
- sprite = &series_list[series_id]->index[0];
-
- depth = attr_depth(&depth_map,
- sprite->x + (sprite->xs >> 1),
- sprite->y + (sprite->ys >> 1)) - 1;
-
- return kernel_seq_add(series_id, mirror, 1, 0, 0, AA_PINGPONG, 1,
- depth, 100, true, 0, 0, ticks, interval_ticks,
- start_ticks, expire);
-}
-
-
-int kernel_seq_pingpong_scroll(int series_id, int mirror, word ticks,
- word interval_ticks, word start_ticks, int expire) {
- // TODO: depth isn't initialized?
- int depth = 0;
- SpritePtr sprite;
-
- sprite = &series_list[series_id]->index[0];
-
- return kernel_seq_add(series_id, mirror, 1, 0, 0, AA_PINGPONG, 1,
- depth, 100, true, 0, 0, ticks, interval_ticks,
- start_ticks, expire);
-}
-
-int kernel_seq_backward(int series_id, int mirror, word ticks,
- word interval_ticks, word start_ticks, int expire) {
- int depth;
- SpritePtr sprite;
-
- sprite = &series_list[series_id]->index[0];
-
- depth = attr_depth(&depth_map,
- sprite->x + (sprite->xs >> 1),
- sprite->y + (sprite->ys >> 1)) - 1;
-
- return kernel_seq_add(series_id, mirror,
- series_list[series_id]->num_sprites,
- 0, 0, AA_LINEAR, -1, depth, 100, true, 0, 0,
- ticks, interval_ticks, start_ticks, expire);
-}
-
-int kernel_seq_backward_scroll(int series_id, int mirror,
- word ticks, word interval_ticks, word start_ticks, int expire) {
- // TODO: depth isn't initialized?
- int depth = 0;
- SpritePtr sprite;
-
- sprite = &series_list[series_id]->index[0];
-
- return kernel_seq_add(series_id, mirror,
- series_list[series_id]->num_sprites,
- 0, 0, AA_LINEAR, -1, depth, 100, true, 0, 0,
- ticks, interval_ticks, start_ticks, expire);
-}
-
-void kernel_synch(int slave_type, int slave_id, int master_type, int master_id) {
- long master_time;
-
- switch (master_type) {
- case KERNEL_SERIES:
- master_time = sequence_list[master_id].base_time;
- break;
-
- case KERNEL_ANIM:
- master_time = kernel_anim[master_id].next_clock;
- break;
-
- case KERNEL_NOW:
- master_time = kernel.clock + (long)master_id;
- break;
-
- case KERNEL_PLAYER:
- default:
- master_time = player.clock;
- break;
- }
-
-
- switch (slave_type) {
- case KERNEL_SERIES:
- sequence_list[slave_id].base_time = master_time;
- break;
-
- case KERNEL_PLAYER:
- player.clock = master_time;
- break;
-
- case KERNEL_ANIM:
- kernel_anim[slave_id].next_clock = master_time;
- break;
- }
-}
-
-void kernel_player_expire(int sequence_id) {
- sequence_list[sequence_id].expired = true;
- sequence_list[sequence_id].base_time = player.clock;
-}
-
-void kernel_seq_depth(int sequence_id, int depth) {
- sequence_list[sequence_id].depth = (byte)depth;
-}
-
-void kernel_seq_scale(int sequence_id, int scale) {
- sequence_list[sequence_id].scale = (byte)scale;
-}
-
-void kernel_seq_loc(int sequence_id, int x, int y) {
- sequence_list[sequence_id].x = x;
- sequence_list[sequence_id].y = y;
- sequence_list[sequence_id].auto_locating = false;
-}
-
-void kernel_seq_motion(int sequence_id, int flags,
- int delta_x_times_100, int delta_y_times_100) {
- sequence_list[sequence_id].motion = (byte)(KERNEL_MOTION | flags);
- sequence_list[sequence_id].sign_x = sgn(delta_x_times_100);
- sequence_list[sequence_id].sign_y = sgn(delta_y_times_100);
- sequence_list[sequence_id].delta_x = abs(delta_x_times_100);
- sequence_list[sequence_id].delta_y = abs(delta_y_times_100);
- sequence_list[sequence_id].accum_x = 0;
- sequence_list[sequence_id].accum_y = 0;
-}
-
-void kernel_seq_range(int sequence_id, int first, int last) {
- int num_sprites;
- int from, unto;
- SequencePtr sequence;
-
- sequence = &sequence_list[sequence_id];
-
- num_sprites = series_list[sequence->series_id]->num_sprites;
-
- switch (first) {
- case KERNEL_FIRST:
- case KERNEL_DEFAULT:
- from = 1;
- break;
- case KERNEL_LAST:
- from = num_sprites;
- break;
- default:
- from = first;
- break;
- }
-
- switch (last) {
- case KERNEL_FIRST:
- unto = 1;
- break;
- case KERNEL_LAST:
- case KERNEL_DEFAULT:
- unto = num_sprites;
- break;
- default:
- unto = last;
- break;
- }
-
- sequence->start_sprite = from;
- sequence->end_sprite = unto;
-
- sequence->sprite = (sequence->loop_direction >= 0) ? from : unto;
-}
-
-int kernel_seq_stamp(int series_id, int mirror, int sprite) {
- int id;
-
- id = kernel_seq_forward(series_id, mirror, 32767, 0, 0, 0);
- if (id >= 0) {
- kernel_seq_range(id, sprite, sprite);
- sequence_list[id].loop_direction = AA_STAMP;
- }
- return id;
-}
-
-int kernel_seq_stamp_scroll(int series_id, int mirror, int sprite) {
- int id;
-
- id = kernel_seq_forward_scroll(series_id, mirror, 32767, 0, 0, 0);
- if (id >= 0) {
- kernel_seq_range(id, sprite, sprite);
- sequence_list[id].loop_direction = AA_STAMP;
- }
- return id;
-}
-
-int kernel_seq_trigger(int sequence_id, int trigger_type,
- int trigger_sprite, int trigger_code) {
- int error_code = true;
- int id;
- SequencePtr sequence;
-
- sequence = &sequence_list[sequence_id];
-
- if (sequence->num_triggers >= KERNEL_MAX_TRIGGERS) goto done;
-
- id = sequence->num_triggers++;
-
- sequence->trigger_type[id] = (byte)trigger_type;
- sequence->trigger_sprite[id] = trigger_sprite;
- sequence->trigger_code[id] = (byte)trigger_code;
-
- error_code = false;
-
-done:
- return error_code;
-}
-
-int kernel_timing_trigger(int ticks, int trigger_code) {
- int id = -1;
- int found = false;
- int count;
-
- for (count = 0; !found && (count < KERNEL_MAX_SEQUENCES); count++) {
- id = count;
- found = !sequence_list[count].active_flag;
- }
-
- if (!found) {
-#if !defined(disable_error_check)
- error_report(ERROR_SEQUENCE_LIST_FULL, WARNING, MODULE_KERNEL, KERNEL_MAX_SEQUENCES, 0);
-#endif
- goto done;
- }
-
- sequence_list[id].active_flag = true;
- sequence_list[id].series_id = KERNEL_SPECIAL_TIMING;
-
- sequence_list[id].ticks = ticks;
- sequence_list[id].interval_ticks = 0;
- sequence_list[id].base_time = kernel.clock + ticks;
- sequence_list[id].expire = 1;
- sequence_list[id].expired = false;
-
- sequence_list[id].num_triggers = 0;
- sequence_list[id].trigger_dest = (byte)kernel.trigger_setup_mode;
-
- for (count = 0; count < 3; count++) {
- sequence_list[id].trigger_words[count] = player2.words[count];
- }
-
- kernel_seq_trigger(id, KERNEL_TRIGGER_EXPIRE, 0, trigger_code);
-
-done:
- return id;
-}
-
-int kernel_seq_purge(int sequence_id) {
- int count;
- int purged_any = -1;
-
- for (count = 0; count < (int)image_marker; count++) {
- if (image_list[count].segment_id == (byte)sequence_id) {
- image_list[count].flags = IMAGE_ERASE;
- purged_any = count;
- }
- }
-
- return purged_any;
-}
-
-void kernel_seq_full_update(void) {
- int count, id;
-
- for (count = 0; count < KERNEL_MAX_SEQUENCES; count++) {
- if (sequence_list[count].active_flag) {
- if ((int)(sequence_list[count].series_id) != KERNEL_SPECIAL_TIMING) {
- id = matte_allocate_image();
- if (id >= 0) {
- if (sequence_list[count].last_image.flags >= 0) {
- image_list[id] = sequence_list[count].last_image;
- } else {
- kernel_seq_image(&sequence_list[count], &image_list[id], count);
- }
- }
- }
- }
- }
-}
-
-void kernel_seq_correction(long old_clock, long new_clock) {
- int count;
- SequencePtr sequence;
-
- for (count = 0; count < KERNEL_MAX_SEQUENCES; count++) {
- sequence = &sequence_list[count];
- if (sequence->active_flag) {
- sequence->base_time += (new_clock - old_clock);
- }
- }
-}
-
-void kernel_draw_to_background(int series_id, int sprite_id,
- int x, int y, int depth, int scale) {
- if (x == KERNEL_HOME) {
- x = series_list[series_id]->index[sprite_id - 1].x;
- }
-
- if (y == KERNEL_HOME) {
- y = series_list[series_id]->index[sprite_id - 1].y;
- }
-
- sprite_draw_3d_scaled_big(series_list[series_id],
- sprite_id, &scr_orig, &scr_depth,
- x - picture_map.pan_base_x,
- y - picture_map.pan_base_y,
- depth, scale, 0, 0);
-
- matte_refresh_work();
-}
-
-} // namespace MADSV2
-} // namespace MADS
diff --git a/engines/mads/madsv2/core/kernel_9.cpp b/engines/mads/madsv2/core/kernel_9.cpp
deleted file mode 100644
index 99f0975593a..00000000000
--- a/engines/mads/madsv2/core/kernel_9.cpp
+++ /dev/null
@@ -1,252 +0,0 @@
-/*
-/* kernel_9.c by Brian Reynolds 16-May-92
-*/
-
-#include <stdlib.h>
-
-#include <general.mac>
-#include <anim.mac>
-#include <matte.h>
-#include <error.h>
-#include <player.h>
-#include <sprite.h>
-#include <attr.h>
-
-#include "kernel.mac"
-#include "kernel_1.h"
-#include "kernel_8.h"
-#include "kernel_c.h"
-#include "kernel_f.h"
-
-#pragma optimize ("weglt", on)
-
-
-void fastcall kernel_seq_delete (int sequence_id)
-{
- if (sequence_list[sequence_id].active_flag) {
- if (sequence_list[sequence_id].dynamic_hotspot >= 0) {
- kernel_delete_dynamic(sequence_list[sequence_id].dynamic_hotspot);
- }
- }
-
- sequence_list[sequence_id].active_flag = false;
-
- if (!sequence_list[sequence_id].expired) {
- kernel_reconstruct_screen (-1);
- } else {
- kernel_seq_purge (sequence_id);
- }
-}
-
-
-void fastcall kernel_seq_image (SequencePtr sequence, ImagePtr image, int sequence_id)
-{
- image->flags = series_list[sequence->series_id]->delta_series ? IMAGE_DELTA : IMAGE_UPDATE;
- image->segment_id = (byte) sequence_id;
- image->series_id = sequence->series_id;
- image->sprite_id = sequence->sprite | (sequence->mirror ? MIRROR_MASK : 0);
-
- image->depth = sequence->depth;
- image->scale = sequence->scale;
-
- if (!sequence->auto_locating) {
- image->x = sequence->x;
- image->y = sequence->y;
- } else {
- image->x = series_list[image->series_id]->index[sequence->sprite - 1].x;
- image->y = series_list[image->series_id]->index[sequence->sprite - 1].y;
- }
-
- sequence->last_image = *image;
-}
-
-
-
-static int near fastcall kernel_seq_update (SequencePtr sequence, int sequence_id)
-{
- int id;
- int count;
- int cycling = false;
- int trigger = -1;
- int x, y, xs, ys;
- int x1, y1;
- int x2, y2;
- int purged;
- ImagePtr image;
-
- purged = kernel_seq_purge(sequence_id);
-
- if (purged >= 0) {
- if (sequence->loop_direction == AA_STAMP) {
- image_list[purged].flags = IMAGE_STATIC;
- goto done;
- }
- }
-
- if (sequence->expired) {
- kernel_seq_delete (sequence_id);
- goto done;
- } else {
- if (sequence->series_id == KERNEL_SPECIAL_TIMING) {
- sequence->expired = true;
- goto triggers;
- }
-
- id = matte_allocate_image();
- if (id < 0) {
- sequence->expired = true;
- goto triggers;
- }
-
- image = &image_list[id];
-
- kernel_seq_image (sequence, image, sequence_id);
-
- }
-
- if (sequence->motion ||
- (sequence->dynamic_hotspot >= 0)) {
- xs = (series_list[sequence->series_id]->index[sequence->sprite - 1].xs * sequence->scale) / 200;
- ys = (series_list[sequence->series_id]->index[sequence->sprite - 1].ys * sequence->scale) / 100;
- x = image->x;
- y = image->y;
-
- if (sequence->motion & KERNEL_MOTION) {
- sequence->accum_x += sequence->delta_x;
- while (sequence->accum_x >= 100) {
- sequence->accum_x -= 100;
- sequence->x += sequence->sign_x;
- }
- sequence->accum_y += sequence->delta_y;
- while (sequence->accum_y >= 100) {
- sequence->accum_y -= 100;
- sequence->y += sequence->sign_y;
- }
-
- if (sequence->motion & KERNEL_MOTION_OFFSCREEN) {
- if ( (((x + xs) < 0) || ((x - xs) >= picture_map.total_x_size)) ||
- ((y < 0) || ((y - ys) >= picture_map.total_y_size))) {
- cycling = true;
- sequence->expired = true;
- }
- }
- }
-
- if (sequence->dynamic_hotspot >= 0) {
- x1 = x - xs;
- x2 = x + xs;
- y1 = y - ys;
- y2 = y;
- x1 = max (0, x1);
- y1 = max (0, y1);
- x2 = min (picture_map.total_x_size - 1, x2);
- y2 = min (picture_map.total_y_size - 1, y2);
- kernel_dynamic_hot[sequence->dynamic_hotspot].x = x1;
- kernel_dynamic_hot[sequence->dynamic_hotspot].y = y1;
- kernel_dynamic_hot[sequence->dynamic_hotspot].xs= (x2 - x1) + 1;
- kernel_dynamic_hot[sequence->dynamic_hotspot].ys= (y2 - y1) + 1;
- kernel_dynamic_hot[sequence->dynamic_hotspot].valid = true;
- kernel_dynamic_changed = true;
- }
- }
-
- if (sequence->start_sprite != sequence->end_sprite) {
- sequence->sprite += sequence->loop_direction;
- }
-
- if (sequence->sprite < sequence->start_sprite) {
- cycling = true;
- if (sequence->loop_mode == AA_PINGPONG) {
- sequence->sprite = sequence->start_sprite + 1;
- sequence->loop_direction = 1;
- } else {
- sequence->sprite = sequence->end_sprite;
- }
- } else if (sequence->sprite > sequence->end_sprite) {
- cycling = true;
- if (sequence->loop_mode == AA_PINGPONG) {
- sequence->sprite = sequence->end_sprite - 1;
- sequence->loop_direction = -1;
- } else {
- sequence->sprite = sequence->start_sprite;
- }
- }
-
- if (cycling) {
- if (sequence->expire) {
- sequence->expire--;
- if (!sequence->expire) {
- sequence->expired = true;
- }
- }
- }
-
-triggers:
- for (count = 0; count < (int) sequence->num_triggers; count++) {
- switch(sequence->trigger_type[count]) {
- case KERNEL_TRIGGER_EXPIRE:
- if (sequence->expired) trigger = count;
- break;
- case KERNEL_TRIGGER_LOOP:
- if (cycling) trigger = count;
- break;
- case KERNEL_TRIGGER_SPRITE:
- default:
- if ((sequence->sprite == sequence->trigger_sprite[count]) ||
- (sequence->trigger_sprite[count] == 0)) {
- trigger = count;
- }
- break;
- }
- }
-
- if (trigger >= 0) {
- kernel.trigger = sequence->trigger_code[trigger];
- kernel.trigger_mode = sequence->trigger_dest;
- if (kernel.trigger_mode != KERNEL_TRIGGER_DAEMON) {
- for (count = 0; count < 3; count++) {
- player2.words[count] = sequence->trigger_words[count];
- }
- }
- }
-
- if (sequence->series_id == KERNEL_SPECIAL_TIMING) {
- sequence->active_flag = false;
- }
-
-done:
- return (cycling);
-}
-
-
-
-void fastcall kernel_seq_update_all (void)
-{
- int count;
- int ok_to_update;
- SequencePtr sequence;
-
- for (count = 0; (count < KERNEL_MAX_SEQUENCES); count++) {
- sequence = &sequence_list[count];
- if (sequence->active_flag) {
- if (kernel.clock >= sequence->base_time) {
- ok_to_update = (kernel.fx || !kernel.trigger ||
- sequence->expired || !sequence->num_triggers);
- if (ok_to_update) {
- sequence->base_time = kernel.clock + sequence->ticks;
- if (kernel_seq_update (sequence, count)) {
- sequence->base_time += sequence->interval_ticks;
- }
- }
- }
- }
- }
-}
-
-
-
-
-
-
-
-
diff --git a/engines/mads/madsv2/core/kernel_a.cpp b/engines/mads/madsv2/core/kernel_a.cpp
deleted file mode 100644
index 2893209bd71..00000000000
--- a/engines/mads/madsv2/core/kernel_a.cpp
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
-/* kernel_a.c by Brian Reynolds 8-Apr-92
-*/
-
-#include <general.mac>
-#include <player.h>
-#include <matte.h>
-#include <timer.h>
-#include "kernel.mac"
-#include "kernel_8.h"
-
-#pragma optimize ("weglt", on)
-
-
-void fastcall kernel_seq_player (int sequence_id, int synch_me)
-{
- kernel_seq_loc (sequence_id, player.x, player.y + ((player.center_of_gravity * player.scale) / 100));
- kernel_seq_depth (sequence_id, player.depth);
- kernel_seq_scale (sequence_id, player.scale);
-
- if (synch_me) {
- kernel_synch (KERNEL_SERIES, sequence_id,
- KERNEL_PLAYER, 0);
- }
-}
-
diff --git a/engines/mads/madsv2/core/kernel_b.cpp b/engines/mads/madsv2/core/kernel_b.cpp
deleted file mode 100644
index 71c9db8e88a..00000000000
--- a/engines/mads/madsv2/core/kernel_b.cpp
+++ /dev/null
@@ -1,191 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include "mads/madsv2/core/general.h"
-#include "mads/madsv2/core/anim.h"
-#include "mads/madsv2/core/player.h"
-#include "mads/madsv2/core/matte.h"
-#include "mads/madsv2/core/mem.h"
-#include "mads/madsv2/core/error.h"
-#include "mads/madsv2/core/buffer.h"
-#include "mads/madsv2/core/digi.h"
-#include "mads/madsv2/core/kernel.h"
-#include "mads/madsv2/core/kernel_1.h"
-#include "mads/madsv2/core/kernel_c.h"
-#include "mads/madsv2/core/kernel_k.h"
-
-namespace MADS {
-namespace MADSV2 {
-
-int stop_speech_on_run_anim = true;
-
-void kernel_animation_init(void) {
- int count;
-
- for (count = 0; count < KERNEL_MAX_ANIMATIONS; count++) {
- kernel_anim[count].anim = NULL;
- kernel_anim[count].cycled = false;
- kernel_anim[count].repeat = false;
- }
-}
-
-int kernel_run_animation(char *name, int trigger_code) {
- int result = -1;
- int found = -1;
- int error_flag = true;
- int count;
- int load_flags;
- int id;
- long largest_block;
-
-
- if (stop_speech_on_run_anim) {
- digi_stop(1);
- digi_stop(2);
- digi_stop(3);
- }
-
- anim_error = -2;
-
- for (count = 0; (found < 0) && (count < KERNEL_MAX_ANIMATIONS); count++) {
- if (kernel_anim[count].anim == NULL) {
- found = count;
- }
- }
-
- if (found < 0) goto done;
-
- load_flags = 0;
- if (kernel.translating) load_flags |= ANIM_LOAD_TRANSLATE;
- kernel_anim[found].anim = anim_load(name,
- NULL, NULL,
- NULL, NULL,
- NULL, NULL,
- NULL, NULL, load_flags);
- if (kernel_anim[found].anim == NULL) goto done;
-
- kernel_anim[found].messages = 0;
- kernel_anim[found].dynamic_hotspot = -1;
-
- kernel_anim[found].sprite_loaded = -1;
- if (kernel_anim[found].anim->misc_any_packed) {
- kernel_anim[found].buffer_id = -1;
- id = kernel_anim[found].anim->series_id[kernel_anim[found].anim->misc_packed_series];
- memcpy(&largest_block, &series_list[id]->misc_largest_block, sizeof(long));
- if (mem_get_avail() - 128 >= largest_block) {
- mem_free(series_list[id]->arena);
- series_list[id]->arena = (byte *)mem_get_name(largest_block * 2, "$arena$");
- if (series_list[id]->arena == NULL) {
- series_list[id]->arena = (byte *)mem_get_name(largest_block, "$arena$");
- anim_error = -1;
- if (series_list[id]->arena == NULL) goto done;
- } else {
- kernel_anim[found].buffer[0] = series_list[id]->arena;
- kernel_anim[found].buffer[1] = (byte *)mem_normalize(series_list[id]->arena + largest_block);
- kernel_anim[found].buffer_id = 0;
- }
- }
- kernel_animation_get_sprite(found, 1);
- }
-
- if (kernel_mode == KERNEL_ACTIVE_CODE) kernel_new_palette();
-
- kernel_anim[found].frame = 0;
- kernel_anim[found].image = 0;
- kernel_anim[found].next_clock = kernel.clock;
-
- kernel_anim[found].view_changes = false;
-
- kernel_anim[found].trigger_code = trigger_code;
- kernel_anim[found].trigger_mode = kernel.trigger_setup_mode;
- for (count = 0; count < 3; count++) {
- kernel_anim[found].trigger_words[count] = player2.words[count];
- }
-
- for (count = 0; count < kernel_anim[found].anim->num_speech; count++) {
- kernel_anim[found].anim->speech[count].flags = (word)-1;
- }
-
- error_flag = false;
- result = found;
-
- kernel_anim[found].last_frame = -1;
-
-done:
- if (error_flag) {
- if (found >= 0) kernel_abort_animation(found);
-#ifndef disable_error_check
- Common::strcpy_s(error_string, name);
- error_report(ERROR_KERNEL_NO_ANIMATION, WARNING, MODULE_KERNEL, trigger_code, anim_error);
-#endif
- }
-
- anim_error = 0;
- return found;
-}
-
-/* run a talking animation */
-int kernel_run_animation_talk(char thing, int num, int trigger_code) {
- Common::String test = "*talk_";
- if (thing == 'r')
- test += "r";
- else if (thing == 'b')
- test += "b";
- else if (thing == 'e')
- test += "e";
-
- test += Common::String::format("%d", num);
-
- return kernel_run_animation(test.c_str(), trigger_code);
-}
-
-/* run a displacement animation */
-int kernel_run_animation_disp(char thing, int num, int trigger_code) {
- Common::String test = "*disp_";
-
- if (thing == 'r')
- test += "ru";
- else if (thing == 'b')
- test += "ab";
- else if (thing == 'e')
- test += "ed";
-
- test += Common::String::format("%d", num);
-
- return kernel_run_animation(test.c_str(), trigger_code);
-}
-
-/* run a writing anim (always edgar) */
-int kernel_run_animation_write(int trigger_code) {
- int feedback;
-
- feedback = kernel_run_animation("*write_e", trigger_code);
- return feedback;
-}
-
-/* run a pointing animation (always abigail) */
-int kernel_run_animation_point(int num, int trigger_code) {
- Common::String test = Common::String::format("*point_b%d", num);
- return kernel_run_animation(test.c_str(), trigger_code);
-}
-
-} // namespace MADSV2
-} // namespace MADS
diff --git a/engines/mads/madsv2/core/kernel_c.cpp b/engines/mads/madsv2/core/kernel_c.cpp
deleted file mode 100644
index 3764843ea75..00000000000
--- a/engines/mads/madsv2/core/kernel_c.cpp
+++ /dev/null
@@ -1,506 +0,0 @@
-/*
-/* kernel_c.c by Brian Reynolds 13-Jan-92
-*/
-
-#include <stdlib.h>
-#include <string.h>
-
-#include <general.mac>
-
-#include <anim.h>
-#include <player.h>
-#include <matte.h>
-#include <mem.h>
-/* pl #include <sound.h> */
-#include <error.h>
-#include <buffer.h>
-#include <pal.h>
-#include <sprite.h>
-#include <config.h>
-#include <attr.h>
-#include <camera.h>
-
-#pragma optimize ("weglt", on)
-
-#include "kernel.mac"
-#include "kernel_1.h"
-#include "kernel_8.h"
-#include "kernel_d.h"
-#include "kernel_f.h"
-
-#define MESSAGE_COLOR_3 (((KERNEL_MESSAGE_COLOR_BASE_3 + 1) << 8) + KERNEL_MESSAGE_COLOR_BASE_3)
-
-
-
-
-
-void fastcall kernel_animation_get_sprite (int handle, int id)
-{
- int series_id;
- byte *pointer;
-
- if (id != kernel_anim[handle].sprite_loaded) {
- series_id = kernel_anim[handle].anim->series_id[kernel_anim[handle].anim->misc_packed_series];
- if (kernel_anim[handle].buffer_id >= 0) {
- pointer = kernel_anim[handle].buffer[kernel_anim[handle].buffer_id];
- kernel_anim[handle].buffer_id = 1 - kernel_anim[handle].buffer_id;
- } else {
- pointer = series_list[series_id]->arena;
- }
- if (sprite_data_load(series_list[series_id], id, pointer)) {
- error_report (ERROR_SPRITE_DATA_LOAD_FAILED, ERROR, MODULE_KERNEL, id, series_id);
- }
- kernel_anim[handle].sprite_loaded = id;
- }
-}
-
-
-
-
-
-void fastcall kernel_reset_animation (int handle, int frame)
-{
- if (kernel_anim[handle].anim != NULL) {
- kernel_anim[handle].frame = frame;
- kernel_anim[handle].image = 0;
- kernel_anim[handle].doomed = false;
- }
-}
-
-
-static void near fastcall kernel_hot_check (int hot, int id, int seg_id)
-{
- int count;
- int x, y, xs, ys;
- int x1, y1, x2, y2;
- byte scale;
-
- for (count = 0; count < KERNEL_DYNAMIC_MAX_SEGMENTS; count++) {
- if (seg_id == (int)kernel_dynamic_hot[hot].auto_segment[count]) {
-
- scale = image_list[id].scale;
- if (scale == IMAGE_UNSCALED) {
- xs = series_list[image_list[id].series_id]->index[image_list[id].sprite_id - 1].xs;
- ys = series_list[image_list[id].series_id]->index[image_list[id].sprite_id - 1].ys;
- x = image_list[id].x;
- y = image_list[id].y;
- x1 = x;
- y1 = y;
- x2 = x + xs - 1;
- y2 = y + ys - 1;
- } else {
- xs = (series_list[image_list[id].series_id]->index[image_list[id].sprite_id - 1].xs * image_list[id].scale) / 200;
- ys = (series_list[image_list[id].series_id]->index[image_list[id].sprite_id - 1].ys * image_list[id].scale) / 100;
- x = image_list[id].x;
- y = image_list[id].y;
- x1 = x - xs;
- x2 = x + xs;
- y1 = y - ys;
- y2 = y;
- }
-
- if ((xs > 0) && (ys > 0)) {
- x1 = max (0, x1);
- y1 = max (0, y1);
- x2 = min (picture_map.total_x_size - 1, x2);
- y2 = min (picture_map.total_y_size - 1, y2);
- xs = (x2 - x1) + 1;
- ys = (y2 - y1) + 1;
- if ((xs > 0) && (ys > 0)) {
- kernel_dynamic_hot[hot].x = x1;
- kernel_dynamic_hot[hot].y = y1;
- kernel_dynamic_hot[hot].xs= xs;
- kernel_dynamic_hot[hot].ys= ys;
- kernel_dynamic_hot[hot].valid = true;
- }
- }
- }
- }
-}
-
-
-
-static void near fastcall kernel_process_animation (int handle, int asynchronous)
-{
- int view_changed = false;
- int image_base;
- int count;
- int match;
- int id;
- int clock_frame;
- int hot, seg_id;
- word temp1, temp2;
-
- if (kernel_anim[handle].anim->misc_any_packed) {
- id = -1;
- match = kernel_anim[handle].anim->series_id[kernel_anim[handle].anim->misc_packed_series];
- for (count = kernel_anim[handle].image;
- (count < kernel_anim[handle].anim->num_images) &&
- (kernel_anim[handle].anim->image[count].flags <= kernel_anim[handle].frame);
- count++) {
- if (kernel_anim[handle].anim->image[count].series_id == (byte)match) {
- id = kernel_anim[handle].anim->image[count].sprite_id;
- }
- }
- if (id >= 0) {
- kernel_animation_get_sprite(handle, id);
- }
- }
-
- if (kernel.clock < kernel_anim[handle].next_clock) goto done;
-
- for (count = 0; count < (int) image_marker; count++) {
- if (image_list[count].segment_id == (byte)(KERNEL_SEGMENT_ANIMATION + handle)) {
- image_list[count].flags = IMAGE_ERASE;
- }
- }
-
- kernel_anim[handle].cycled = false;
- if (kernel_anim[handle].frame >= kernel_anim[handle].anim->num_frames) {
- if (kernel_anim[handle].repeat) {
- kernel_anim[handle].frame = 0;
- kernel_anim[handle].image = 0;
- kernel_anim[handle].cycled = true;
- } else {
- kernel_anim[handle].doomed = true;
- goto done;
- }
- }
-
- if (!asynchronous) {
- if (kernel_anim[handle].anim->frame[kernel_anim[handle].frame].sound) {
- /* pl sound_play(kernel_anim[handle].anim->frame[kernel_anim[handle].frame].sound); */
- }
-
- if ((kernel_anim[handle].anim->misc_peel_x != 0) || (kernel_anim[handle].anim->misc_peel_y != 0)) {
- buffer_peel_horiz (&scr_orig, kernel_anim[handle].anim->misc_peel_x);
- buffer_peel_vert (&scr_orig, kernel_anim[handle].anim->misc_peel_y, NULL, 0);
- matte_refresh_work();
- if (!kernel_allow_peel) error_report (ERROR_PEELING_DISABLED, ERROR, MODULE_KERNEL, handle, 0);
- }
-
- if (kernel_anim[handle].view_changes) {
- if (kernel_anim[handle].anim->frame[kernel_anim[handle].frame].view_x != (word) picture_view_x) {
- picture_view_x = kernel_anim[handle].anim->frame[kernel_anim[handle].frame].view_x;
- view_changed = true;
- }
-
- if (kernel_anim[handle].anim->frame[kernel_anim[handle].frame].view_y != (word) picture_view_y) {
- picture_view_y = kernel_anim[handle].anim->frame[kernel_anim[handle].frame].view_y;
- view_changed = true;
- }
- }
- }
-
- if (view_changed) {
- id = matte_allocate_image();
- image_list[id].segment_id = KERNEL_SEGMENT_SYSTEM;
- image_list[id].flags = IMAGE_REFRESH;
- camera_jump_to (picture_view_x, picture_view_y);
- }
-
- image_base = image_marker;
-
- hot = kernel_anim[handle].dynamic_hotspot;
- if (hot >= 0) {
- kernel_dynamic_hot[hot].x = 0;
- kernel_dynamic_hot[hot].y = 0;
- kernel_dynamic_hot[hot].xs= 0;
- kernel_dynamic_hot[hot].ys= 0;
- kernel_dynamic_hot[hot].valid = false;
- kernel_dynamic_changed = true;
- }
-
- while ((kernel_anim[handle].image < kernel_anim[handle].anim->num_images) &&
- (kernel_anim[handle].anim->image[kernel_anim[handle].image].flags <= kernel_anim[handle].frame)) {
- if (kernel_anim[handle].anim->image[kernel_anim[handle].image].flags == kernel_anim[handle].frame) {
- match = false;
- for (count = 0; !match && (count < image_base); count++) {
- if (image_list[count].segment_id == (byte)(KERNEL_SEGMENT_ANIMATION + handle)) {
- if (_fmemcmp (&image_list[count].series_id,
- &kernel_anim[handle].anim->image[kernel_anim[handle].image].series_id, 9) == 0) {
- image_list[count].flags = 0;
-
- if (hot >= 0) {
- seg_id = kernel_anim[handle].anim->image[kernel_anim[handle].image].segment_id;
- kernel_hot_check (hot, count, seg_id);
- }
-
- match = true;
- }
- }
- }
-
- if (!match) {
- id = matte_allocate_image();
- image_list[id] = kernel_anim[handle].anim->image[kernel_anim[handle].image];
-
- seg_id = image_list[id].segment_id;
-
- /* image_list[id].segment_id += KERNEL_SEGMENT_ANIMATION; */
- image_list[id].segment_id = (byte)(KERNEL_SEGMENT_ANIMATION + handle);
- image_list[id].flags = series_list[image_list[id].series_id]->delta_series ? IMAGE_DELTA : IMAGE_UPDATE;
- /*
- if (kernel_anim[handle].anim->misc_any_packed) {
- if (image_list[id].series_id == (byte)kernel_anim[handle].anim->series_id[kernel_anim[handle].anim->misc_packed_series]) {
- series_id = image_list[id].series_id;
- sprite_data_load (series_list[series_id], image_list[id].sprite_id, series_list[series_id]->arena);
- }
- }
- */
-
- if (hot >= 0) {
- kernel_hot_check (hot, id, seg_id);
- }
- }
- }
- kernel_anim[handle].image++;
- }
-
- for (count = 0; count < kernel_anim[handle].anim->num_speech; count++) {
- if ((int)(kernel_anim[handle].anim->speech[count].flags) >= 0) {
- if ((kernel_anim[handle].frame < kernel_anim[handle].anim->speech[count].first_frame) ||
- (kernel_anim[handle].frame > kernel_anim[handle].anim->speech[count].last_frame)) {
- kernel_message_delete (kernel_anim[handle].anim->speech[count].flags);
- kernel_anim[handle].anim->speech[count].flags = -1;
- kernel_anim[handle].messages--;
- }
- } else {
- if ((kernel_anim[handle].frame >= kernel_anim[handle].anim->speech[count].first_frame) &&
- (kernel_anim[handle].frame <= kernel_anim[handle].anim->speech[count].last_frame)) {
-
- switch (kernel_anim[handle].messages) {
- case 1:
- temp1 = KERNEL_MESSAGE_COLOR_BASE_2;
- break;
-
- case 2:
- temp1 = KERNEL_MESSAGE_COLOR_BASE;
- break;
-
- default:
- temp1 = KERNEL_MESSAGE_COLOR_BASE_3;
- break;
- }
-
- pal_change_color (temp1,
- kernel_anim[handle].anim->speech[count].color[0].r,
- kernel_anim[handle].anim->speech[count].color[0].g,
- kernel_anim[handle].anim->speech[count].color[0].b);
-
- pal_change_color (temp1 + 1,
- kernel_anim[handle].anim->speech[count].color[1].r,
- kernel_anim[handle].anim->speech[count].color[1].g,
- kernel_anim[handle].anim->speech[count].color[1].b);
-
- temp2 = ((temp1 + 1) << 8) + temp1;
-
- kernel_anim[handle].anim->speech[count].flags =
- kernel_message_add (kernel_anim[handle].anim->speech[count].text,
- kernel_anim[handle].anim->speech[count].x,
- kernel_anim[handle].anim->speech[count].y,
- temp2, 9999999, 0, 0);
-
- kernel_anim[handle].messages++;
- }
- }
- }
-
- kernel_anim[handle].last_frame = kernel_anim[handle].frame;
- kernel_anim[handle].frame++;
-
- if (!asynchronous) {
- if (kernel_anim[handle].frame == kernel_anim[handle].anim->num_frames) {
- if (kernel_anim[handle].trigger_code) {
- kernel.trigger = kernel_anim[handle].trigger_code;
- kernel.trigger_mode = kernel_anim[handle].trigger_mode;
- if (kernel.trigger_mode != KERNEL_TRIGGER_DAEMON) {
- for (count = 0; count < 3; count++) {
- player2.words[count] = kernel_anim[handle].trigger_words[count];
- }
- }
- }
- }
- }
-
- clock_frame = min (kernel_anim[handle].frame, kernel_anim[handle].anim->num_frames - 1);
- kernel_anim[handle].next_clock = kernel.clock + kernel_anim[handle].anim->frame[clock_frame].ticks;
-
-done:
- ;
-}
-
-
-void fastcall kernel_process_all_animations (void)
-{
- int count;
- int ok_to_update;
-
- for (count = 0; count < KERNEL_MAX_ANIMATIONS; count++) {
- if (kernel_anim[count].anim != NULL) {
- ok_to_update = (kernel.fx || !kernel.trigger ||
- (kernel_anim[count].frame != kernel_anim[count].anim->num_frames - 1));
- if (ok_to_update) {
- kernel_process_animation (count, false);
- }
- }
- }
-}
-
-
-void fastcall kernel_reconstruct_screen (int anim_handle)
-{
- int count;
- int player_found;
- int old_frame;
- long old_clock;
-
- player_found = false;
- for (count = 0; count < (int)image_marker; count++) {
- if (image_list[count].flags >= 0) {
- if (image_list[count].segment_id == KERNEL_SEGMENT_PLAYER) {
- player_found = true;
- }
- }
- }
-
- image_marker = 0;
- matte_refresh_work();
- kernel_seq_full_update();
-
- for (count = 0; count < KERNEL_MAX_ANIMATIONS; count++) {
- if (!kernel_anim[count].doomed) {
- if (kernel_anim[count].anim != NULL) {
- if (count != anim_handle) {
- if (kernel_anim[count].last_frame >= 0) {
- old_frame = kernel_anim[count].frame;
- old_clock = kernel_anim[count].next_clock;
- kernel_anim[count].frame = kernel_anim[count].last_frame;
- kernel_anim[count].image = 0;
- kernel_anim[count].next_clock = kernel.clock;
-
- kernel_process_animation (count, true);
-
- kernel_anim[count].next_clock = old_clock;
- kernel_anim[count].frame = old_frame;
- kernel_anim[count].image = 0;
- }
- }
- }
- }
- }
-
- if (player.walker_visible && player_found) {
- player.sprite_changed = true;
- player_set_image();
- }
-}
-
-
-
-
-
-
-void fastcall kernel_abort_animation (int handle)
-{
- int count;
- int old_frame;
- long old_clock;
-
- if (kernel_anim[handle].anim != NULL) {
- if (!kernel_anim[handle].doomed) {
-
- kernel_reconstruct_screen (handle);
-
- /*
- image_marker = 0;
- matte_refresh_work();
- kernel_seq_full_update();
-
- for (count = 0; count < KERNEL_MAX_ANIMATIONS; count++) {
- if (!kernel_anim[count].doomed) {
- if (kernel_anim[count].anim != NULL) {
- if (count != handle) {
- if (kernel_anim[count].last_frame >= 0) {
- old_frame = kernel_anim[count].frame;
- old_clock = kernel_anim[count].next_clock;
- kernel_anim[count].frame = kernel_anim[count].last_frame;
- kernel_anim[count].image = 0;
- kernel_anim[count].next_clock = kernel.clock;
-
- kernel_process_animation (count, true);
-
- kernel_anim[count].next_clock = old_clock;
- kernel_anim[count].frame = old_frame;
- kernel_anim[count].image = 0;
- }
- }
- }
- }
- }
-
- */
- }
-
- /*
- if (player.walker_visible) {
- player.sprite_changed = true;
- player_set_image();
- }
- */
-
- for (count = 0; count < kernel_anim[handle].anim->num_speech; count++) {
- if ((int)(kernel_anim[handle].anim->speech[count].flags) >= 0) {
- kernel_message_delete (kernel_anim[handle].anim->speech[count].flags);
- }
- }
-
- if (kernel_anim[handle].dynamic_hotspot >= 0) {
- kernel_delete_dynamic(kernel_anim[handle].dynamic_hotspot);
- }
-
- kernel_anim[handle].repeat = false;
- anim_unload (kernel_anim[handle].anim);
- kernel_anim[handle].anim = NULL;
- }
-
- kernel_anim[handle].doomed = false;
-
- go_ahead_and_frag_the_palette();
-}
-
-
-void fastcall kernel_abort_all_animations (void)
-{
- int count;
-
- for (count = KERNEL_MAX_ANIMATIONS - 1; count >= 0; count--) {
- kernel_abort_animation (count);
- }
-}
-
-
-void fastcall kernel_doom_all_animations (void)
-{
- int count;
-
- for (count = 0; count < KERNEL_MAX_ANIMATIONS; count++) {
- kernel_anim[count].doomed = true;
- }
-}
-
-
-void fastcall kernel_abort_doomed_animations (void)
-{
- int count;
-
- for (count = KERNEL_MAX_ANIMATIONS - 1; count >= 0; count--) {
- if (kernel_anim[count].doomed) {
- kernel_abort_animation (count);
- }
- }
-}
-
-
-
-
\ No newline at end of file
diff --git a/engines/mads/madsv2/core/kernel_d.cpp b/engines/mads/madsv2/core/kernel_d.cpp
deleted file mode 100644
index f38efe813cb..00000000000
--- a/engines/mads/madsv2/core/kernel_d.cpp
+++ /dev/null
@@ -1,160 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include "mads/madsv2/core/general.h"
-#include "mads/madsv2/core/error.h"
-#include "mads/madsv2/core/matte.h"
-#include "mads/madsv2/core/font.h"
-#include "mads/madsv2/core/player.h"
-#include "mads/madsv2/core/quote.h"
-#include "mads/madsv2/core/kernel.h"
-#include "mads/madsv2/core/kernel_1.h"
-#include "mads/madsv2/core/kernel_8.h"
-#include "mads/madsv2/core/kernel_n.h"
-
-namespace MADS {
-namespace MADSV2 {
-
-#define MESSAGE_COLOR (((KERNEL_MESSAGE_COLOR_BASE + 1) << 8) + KERNEL_MESSAGE_COLOR_BASE)
-
-KernelMessage kernel_message[KERNEL_MAX_MESSAGES];
-FontPtr kernel_message_font;
-int kernel_message_spacing;
-
-void kernel_message_init(void) {
- int count;
-
- for (count = 0; count < KERNEL_MAX_MESSAGES; count++) {
- kernel_message[count].flags = 0;
- }
-
- kernel_message_font = font_conv;
- kernel_message_spacing = -1;
-}
-
-int kernel_message_add(char *text, int x, int y, int color,
- long time_on_screen, int trigger_code, int flags) {
- int result = -1;
- int id = -1;
- int count;
- KernelMessagePtr my_message = NULL;
-
- for (count = 0; (id < 0) && (count < KERNEL_MAX_MESSAGES); count++) {
- my_message = &kernel_message[count];
- if (!(my_message->flags & KERNEL_MESSAGE_ACTIVE)) id = count;
- }
-
- if (id < 0) {
- if (trigger_code) {
- error_report(ERROR_KERNEL_MESSAGE_LIST_FULL, ERROR, MODULE_KERNEL, KERNEL_MAX_MESSAGES, trigger_code);
- }
- goto done;
- }
-
- my_message->message = text;
-
- my_message->flags = (KERNEL_MESSAGE_ACTIVE | flags);
- my_message->color = color;
- my_message->x = x;
- my_message->y = y;
- my_message->matte_message_handle = -1;
- my_message->expire_ticks = time_on_screen;
- my_message->update_time = kernel.clock;
- my_message->trigger_code = (byte)trigger_code;
- my_message->trigger_dest = (byte)kernel.trigger_setup_mode;
-
- for (count = 0; count < 3; count++) {
- my_message->trigger_words[count] = player2.words[count];
- }
-
- if (flags & KERNEL_MESSAGE_PLAYER) my_message->update_time = player.clock;
-
- result = id;
-
-done:
- return result;
-}
-
-void kernel_message_teletype(int id, int rate, int quote) {
- if (id >= 0) {
- kernel_message[id].flags |= KERNEL_MESSAGE_TELETYPE;
- if (quote) kernel_message[id].flags |= KERNEL_MESSAGE_QUOTE;
- kernel_message[id].strobe_marker = 0;
- kernel_message[id].strobe_rate = rate;
- kernel_message[id].strobe_time = kernel.clock;
- kernel_message[id].strobe_save = *kernel_message[id].message;
- kernel_message[id].strobe_save_2 = *(kernel_message[id].message + 1);
- if (kernel_message[id].flags & KERNEL_MESSAGE_PLAYER) {
- kernel_message[id].strobe_time = player.clock;
- }
- kernel_message[id].update_time = kernel_message[id].strobe_time;
- }
-}
-
-void kernel_message_attach(int id, int sequence) {
- if (id >= 0) {
- kernel_message[id].flags |= KERNEL_MESSAGE_ATTACHED;
- kernel_message[id].sequence_id = (byte)sequence;
- }
-}
-
-void kernel_message_anim(int id, int anim, int segment) {
- if (id >= 0) {
- kernel_message[id].flags |= KERNEL_MESSAGE_ANIM;
- kernel_message[id].sequence_id = (byte)anim;
- kernel_message[id].segment_id = (byte)segment;
- }
-}
-
-void kernel_message_delete(int id) {
- if (kernel_message[id].flags & KERNEL_MESSAGE_ACTIVE) {
- if (kernel_message[id].flags & KERNEL_MESSAGE_TELETYPE) {
- kernel_message[id].message[kernel_message[id].strobe_marker] = kernel_message[id].strobe_save;
- kernel_message[id].message[kernel_message[id].strobe_marker + 1] = kernel_message[id].strobe_save_2;
- }
- if (kernel_message[id].matte_message_handle >= 0) {
- matte_clear_message(kernel_message[id].matte_message_handle);
- }
- kernel_message[id].flags &= ~KERNEL_MESSAGE_ACTIVE;
- }
-}
-
-void kernel_message_purge(void) {
- int count;
- for (count = 0; count < KERNEL_MAX_MESSAGES; count++) {
- kernel_message_delete(count);
- }
-
- kernel_random_purge();
-}
-
-int kernel_message_player(int quote_id, long delay, int trigger) {
- int id;
-
- id = kernel_message_add(quote_string(kernel.quotes, quote_id),
- 0, 0, MESSAGE_COLOR, delay, trigger,
- KERNEL_MESSAGE_PLAYER | KERNEL_MESSAGE_CENTER);
-
- return id;
-}
-
-} // namespace MADSV2
-} // namespace MADS
diff --git a/engines/mads/madsv2/core/kernel_e.cpp b/engines/mads/madsv2/core/kernel_e.cpp
deleted file mode 100644
index 346fd3427ae..00000000000
--- a/engines/mads/madsv2/core/kernel_e.cpp
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
-/* kernel_e.c by Brian Reynolds 16-May-92
-*/
-
-#include <stdlib.h>
-#include <string.h>
-
-#include <general.mac>
-#include <error.h>
-#include <matte.h>
-#include <font.h>
-#include <player.h>
-
-#include "kernel.mac"
-#include "kernel_1.h"
-#include "kernel_8.h"
-#include "kernel_d.h"
-
-#pragma optimize ("weglt", on)
-
-
-static void near fastcall kernel_message_update (KernelMessagePtr my_message)
-{
- int count;
- int x, y;
- int xx, yy;
- int x2;
- int ys;
- int width;
- int matte_id;
- int segment_id;
- int strobe_flag = false;
- int frame;
- int image = -1;
- Animation *anim = NULL;
- SequencePtr sequence = NULL;
- ImagePtr image_list = NULL;
-
- if (my_message->flags & KERNEL_MESSAGE_EXPIRED) {
- matte_clear_message (my_message->matte_message_handle);
- my_message->flags &= ~KERNEL_MESSAGE_ACTIVE;
- goto done;
- }
-
- if (!(my_message->flags & KERNEL_MESSAGE_TELETYPE)) {
- my_message->expire_ticks -= KERNEL_MESSAGE_INTERVAL;
- }
-
- if (my_message->flags & KERNEL_MESSAGE_ATTACHED) {
- sequence = &sequence_list[my_message->sequence_id];
- if (sequence->expired || !sequence->active_flag) my_message->expire_ticks = 0;
- }
-
- if (my_message->flags & KERNEL_MESSAGE_ANIM) {
- anim = &kernel_anim[my_message->sequence_id];
- segment_id = my_message->segment_id;
- if (anim->doomed || (anim->anim == NULL)) {
- my_message->expire_ticks = 0;
- } else {
- frame = anim->last_frame;
- image_list = anim->anim->image;
- for (count = 0; (image < 0) && (count < anim->anim->num_images); count++) {
- if (image_list[count].flags == frame) {
- if (image_list[count].segment_id == (byte)segment_id) {
- image = count;
- }
- }
- }
- if (image < 0) my_message->expire_ticks = 0;
- }
- }
-
- if (my_message->expire_ticks <= 0) {
- if (!kernel.trigger) {
- my_message->flags |= KERNEL_MESSAGE_EXPIRED;
- if (my_message->trigger_code) {
- kernel.trigger = my_message->trigger_code;
- kernel.trigger_mode = my_message->trigger_dest;
- if (kernel.trigger_mode != KERNEL_TRIGGER_DAEMON) {
- for (count = 0; count < 3; count++) {
- player2.words[count] = my_message->trigger_words[count];
- }
- }
- }
- }
- }
-
- my_message->update_time = kernel.clock + KERNEL_MESSAGE_INTERVAL;
-
- x = my_message->x;
- y = my_message->y;
-
- xx = 0;
- yy = 0;
-
- if (my_message->flags & KERNEL_MESSAGE_ANIM) {
- xx = image_list[image].x - picture_view_x;
- yy = image_list[image].y - picture_view_y;
- }
-
- if (my_message->flags & KERNEL_MESSAGE_ATTACHED) {
- if (!sequence->auto_locating) {
- xx = sequence->x;
- yy = sequence->y;
- } else {
- xx = series_list[sequence->series_id]->index[sequence->sprite - 1].x;
- yy = series_list[sequence->series_id]->index[sequence->sprite - 1].y;
- }
- }
-
- if (my_message->flags & KERNEL_MESSAGE_PLAYER) {
- if (player.walker_been_visible) {
- ys = (50 + (series_list[player.series_base + player.series]->index[player.sprite - 1].ys * player.scale)) / 100;
- xx = player.x;
- yy = player.y + ((50 + (player.center_of_gravity * player.scale)) / 100) - ys;
- yy-= 15;
- } else {
- xx = video_x >> 1;
- yy = display_y >> 1;
- }
- }
-
- xx += x;
- yy += y;
-
- if (my_message->flags & KERNEL_MESSAGE_TELETYPE) {
- if (kernel.clock >= my_message->strobe_time) {
- my_message->message[my_message->strobe_marker++] = my_message->strobe_save;
- my_message->message[my_message->strobe_marker] = my_message->strobe_save_2;
- my_message->strobe_save = my_message->message[my_message->strobe_marker];
- my_message->strobe_save_2 = my_message->message[my_message->strobe_marker+1];
- if (!my_message->strobe_save) {
- my_message->message[my_message->strobe_marker] = 0;
- my_message->flags &= ~KERNEL_MESSAGE_TELETYPE;
- } else if (my_message->flags & KERNEL_MESSAGE_QUOTE) {
- my_message->message[my_message->strobe_marker] = '"';
- my_message->message[my_message->strobe_marker+1] = 0;
- }
- my_message->update_time = my_message->strobe_time = kernel.clock + my_message->strobe_rate;
- strobe_flag = true;
- }
- }
-
- width = font_string_width (kernel_message_font, my_message->message, kernel_message_spacing);
-
- if (my_message->flags & (KERNEL_MESSAGE_CENTER | KERNEL_MESSAGE_RIGHT)) {
- if (my_message->flags & KERNEL_MESSAGE_CENTER) {
- xx -= (width >> 1);
- } else {
- xx -= width;
- }
- }
-
- x2 = xx + width;
- if (x2 > video_x) xx -= (x2 - video_x);
-
- xx = max (0, min (video_x - 1, xx));
- yy = max (0, min (display_y - 1, yy));
-
- if (my_message->matte_message_handle >= 0) {
- if (strobe_flag ||
- (xx != message_list[my_message->matte_message_handle].x) ||
- (yy != message_list[my_message->matte_message_handle].y)) {
- matte_clear_message(my_message->matte_message_handle);
- my_message->matte_message_handle = -1;
- }
- }
-
- if (my_message->matte_message_handle < 0) {
- matte_id = matte_add_message(kernel_message_font, my_message->message, xx, yy, my_message->color, kernel_message_spacing);
- if (matte_id < 0) goto done;
- my_message->matte_message_handle = matte_id;
- }
-
-done:
- ;
-}
-
-
-
-void fastcall kernel_message_update_all (void)
-{
- int count;
-
- for (count = 0; (count < KERNEL_MAX_MESSAGES) && !kernel.trigger; count++) {
- if (kernel_message[count].flags & KERNEL_MESSAGE_ACTIVE) {
- if (kernel.clock >= kernel_message[count].update_time) {
- kernel_message_update (&kernel_message[count]);
- }
- }
- }
-}
-
-
-void fastcall kernel_message_correction (long old_clock, long new_clock)
-{
- int count;
-
- for (count = 0; (count < KERNEL_MAX_MESSAGES); count++) {
- if (kernel_message[count].flags & KERNEL_MESSAGE_ACTIVE) {
- kernel_message[count].update_time += (new_clock - old_clock);
- }
- }
-}
diff --git a/engines/mads/madsv2/core/kernel_f.cpp b/engines/mads/madsv2/core/kernel_f.cpp
deleted file mode 100644
index 5128f5bfa15..00000000000
--- a/engines/mads/madsv2/core/kernel_f.cpp
+++ /dev/null
@@ -1,167 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include "mads/madsv2/core/general.h"
-#include "mads/madsv2/core/vocab.h"
-#include "mads/madsv2/core/inter.h"
-#include "mads/madsv2/core/error.h"
-#include "mads/madsv2/core/kernel.h"
-#include "mads/madsv2/core/kernel_1.h"
-#include "mads/madsv2/core/kernel_8.h"
-
-namespace MADS {
-namespace MADSV2 {
-
-int kernel_add_dynamic(int vocab_id, int verb_id, byte syntax,
- int auto_sequence, int x, int y, int xs, int ys) {
- int id = -1;
- int count;
-
- for (count = 0; (id < 0) && (count < KERNEL_MAX_DYNAMIC); count++) {
- if (!kernel_dynamic_hot[count].flags) {
- id = count;
- }
- }
-
- if (id < 0) {
- error_report(ERROR_DYNAMIC_HOTSPOT_OVERFLOW, WARNING, MODULE_KERNEL, id, KERNEL_MAX_DYNAMIC);
- goto done;
- }
-
- kernel_dynamic_hot[id].flags = true;
- kernel_dynamic_hot[id].vocab_id = vocab_id;
- kernel_dynamic_hot[id].auto_sequence = auto_sequence;
- kernel_dynamic_hot[id].x = x;
- kernel_dynamic_hot[id].y = y;
- kernel_dynamic_hot[id].xs = xs;
- kernel_dynamic_hot[id].ys = ys;
-
- kernel_dynamic_hot[id].feet_x = WALK_DIRECT_2;
- kernel_dynamic_hot[id].feet_y = 0;
- kernel_dynamic_hot[id].facing = 5;
-
- kernel_dynamic_hot[id].verb_id = verb_id;
- kernel_dynamic_hot[id].prep = PREP_IN;
- kernel_dynamic_hot[id].syntax = syntax;
-
- kernel_dynamic_hot[id].cursor = 0;
-
- kernel_dynamic_hot[id].valid = true;
-
- kernel_dynamic_hot[id].auto_anim = -1;
- for (count = 0; count < KERNEL_DYNAMIC_MAX_SEGMENTS; count++) {
- kernel_dynamic_hot[id].auto_segment[count] = KERNEL_DYNAMIC_NO_ANIM;
- }
-
-
- kernel_num_dynamic++;
- kernel_dynamic_changed = true;
-
- if (auto_sequence >= 0) {
- sequence_list[auto_sequence].dynamic_hotspot = id;
- kernel_dynamic_hot[id].valid = false;
- }
-
-done:
- return id;
-}
-
-void kernel_dynamic_anim(int id, int anim_id, int segment) {
- int count;
- int found = false;
-
- if ((id >= 0) && (id < KERNEL_MAX_DYNAMIC)) {
- if (kernel_anim[anim_id].anim != NULL) {
- kernel_anim[anim_id].dynamic_hotspot = id;
- if (kernel_dynamic_hot[id].auto_anim < 0) {
- kernel_dynamic_hot[id].valid = false;
- }
- kernel_dynamic_hot[id].auto_anim = (char)anim_id;
- for (count = 0; !found && (count < KERNEL_DYNAMIC_MAX_SEGMENTS); count++) {
- if (kernel_dynamic_hot[id].auto_segment[count] == KERNEL_DYNAMIC_NO_ANIM) {
- kernel_dynamic_hot[id].auto_segment[count] = (byte)segment;
- found = true;
- }
- }
-
- if (!found) {
- error_report(ERROR_DYNAMIC_HOTSPOT_OVERFLOW, ERROR, MODULE_KERNEL, -9999, id);
- }
-
- kernel_dynamic_changed = true;
- }
- }
-}
-
-int kernel_dynamic_walk(int id, int feet_x, int feet_y, int facing) {
- if (id >= 0) {
- kernel_dynamic_hot[id].feet_x = feet_x;
- kernel_dynamic_hot[id].feet_y = feet_y;
- kernel_dynamic_hot[id].facing = (byte)facing;
- }
-
- return id;
-}
-
-int kernel_dynamic_cursor(int id, int cursor_) {
- if (id >= 0) {
- kernel_dynamic_hot[id].cursor = (byte)cursor_;
- }
-
- return id;
-}
-
-void kernel_delete_dynamic(int id) {
- if (kernel_dynamic_hot[id].flags) {
- if (kernel_dynamic_hot[id].auto_sequence >= 0) {
- sequence_list[kernel_dynamic_hot[id].auto_sequence].dynamic_hotspot = -1;
- }
- if (kernel_dynamic_hot[id].auto_anim >= 0) {
- kernel_anim[kernel_dynamic_hot[id].auto_anim].dynamic_hotspot = -1;
- }
- kernel_dynamic_hot[id].flags = false;
- kernel_num_dynamic--;
- kernel_dynamic_changed = true;
- }
-}
-
-void kernel_purge_dynamic() {
- int count;
-
- for (count = 0; count < KERNEL_MAX_DYNAMIC; count++) {
- kernel_delete_dynamic(count);
- }
- kernel_num_dynamic = 0;
- kernel_dynamic_changed = true;
-}
-
-void kernel_init_dynamic() {
- int count;
-
- for (count = 0; count < KERNEL_MAX_DYNAMIC; count++) {
- kernel_dynamic_hot[count].flags = false;
- }
- kernel_num_dynamic = 0;
- kernel_dynamic_changed = 0;
-}
-
-} // namespace MADSV2
-} // namespace MADS
diff --git a/engines/mads/madsv2/core/kernel_g.cpp b/engines/mads/madsv2/core/kernel_g.cpp
deleted file mode 100644
index a1f1d90bc1f..00000000000
--- a/engines/mads/madsv2/core/kernel_g.cpp
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
-/* kernel_g.c by Brian Reynolds 22-Apr-92
-*/
-
-#include <general.mac>
-
-#include <inter.h>
-#include <hspot.h>
-#include <video.h>
-#include <error.h>
-
-#include "kernel.mac"
-#include "kernel_1.h"
-
-#pragma optimize ("weglt", on)
-
-
-int fastcall kernel_dynamic_consecutive(int id)
-{
- int scan;
-
- for (scan = 0; (id >= 0) && (scan < KERNEL_MAX_DYNAMIC); scan++) {
- if (kernel_dynamic_hot[scan].flags && kernel_dynamic_hot[scan].valid) {
- id--;
- if (id < 0) goto done;
- }
- }
-
- if (id >= 0) scan = -1;
-
-done:
- return (scan);
-}
-
-
-void fastcall kernel_refresh_dynamic (void)
-{
- int count;
-
- numspots = inter_base_hotspots;
-
- for (count = 0; count < KERNEL_MAX_DYNAMIC; count++) {
- if (kernel_dynamic_hot[count].flags && kernel_dynamic_hot[count].valid && ((inter_input_mode == INTER_BUILDING_SENTENCES) || (inter_input_mode == INTER_LIMITED_SENTENCES)) ) {
- hspot_add (kernel_dynamic_hot[count].x, kernel_dynamic_hot[count].y,
- kernel_dynamic_hot[count].x + kernel_dynamic_hot[count].xs - 1,
- kernel_dynamic_hot[count].y + kernel_dynamic_hot[count].ys - 1,
- STROKE_DYNAMIC | STROKE_INTERFACE, kernel_dynamic_hot[count].vocab_id,
- RELATIVE_MODE);
- inter_force_rescan = true;
- }
- }
-
- kernel_dynamic_changed = false;
-}
diff --git a/engines/mads/madsv2/core/kernel_h.cpp b/engines/mads/madsv2/core/kernel_h.cpp
deleted file mode 100644
index 679efcdf078..00000000000
--- a/engines/mads/madsv2/core/kernel_h.cpp
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
-/* kernel_h.c by Brian Reynolds 14-Jan-92
-*/
-
-#include <string.h>
-
-#include <general.mac>
-#include <env.h>
-
-#include "kernel.mac"
-#include "kernel_1.h"
-
-#pragma optimize ("weglt", on)
-
-static char kernel_work_name[20];
-
-
-
-char * fastcall kernel_full_name(int my_room, char type, int num, char *text, int ext)
-{
- char temp[2];
-
- if (my_room > 0) {
- if (my_room >= 100) {
- strcpy (kernel_work_name, "*RM");
- } else {
- strcpy (kernel_work_name, "*SC");
- }
- env_catint (kernel_work_name, my_room, 3);
- } else {
- strcpy (kernel_work_name, "*");
- }
-
- temp[0] = type;
- temp[1] = 0;
- strcat (kernel_work_name, temp);
-
- if ((num >= 0) && (ext < KERNEL_TT)) {
- if (num > 9) {
- env_catint (kernel_work_name, num, 2);
- } else {
- env_catint (kernel_work_name, num, 1);
- }
- }
-
- if (text != NULL) _fstrcat (kernel_work_name, text);
-
- switch (ext) {
- case KERNEL_SS:
- strcat (kernel_work_name, ".SS");
- break;
- case KERNEL_AA:
- strcat (kernel_work_name, ".AA");
- break;
- case KERNEL_DAT:
- strcat (kernel_work_name, ".DAT");
- break;
- case KERNEL_HH:
- strcat (kernel_work_name, ".HH");
- break;
- case KERNEL_ART:
- strcat (kernel_work_name, ".ART");
- break;
- case KERNEL_INT:
- strcat (kernel_work_name, ".INT");
- break;
- case KERNEL_TT:
- strcat (kernel_work_name, ".TT");
- break;
- case KERNEL_MM:
- strcat (kernel_work_name, ".MM");
- break;
- case KERNEL_WW:
- strcat (kernel_work_name, ".WW");
- break;
- }
-
- if ((num >= 0) && (ext >= KERNEL_TT)) {
- temp[0] = (byte)num;
- temp[1] = 0;
- strcat (kernel_work_name, temp);
- }
-
- return (kernel_work_name);
-}
-
-
-char * fastcall kernel_name(char type, int num)
-{
- return (kernel_full_name(room_id, type, num, NULL, KERNEL_NONE));
-}
-
-
-char * fastcall kernel_interface_name (int num)
-{
- return (kernel_full_name(0, 'I', num, NULL, KERNEL_AA));
-}
-
-
\ No newline at end of file
diff --git a/engines/mads/madsv2/core/kernel_i.cpp b/engines/mads/madsv2/core/kernel_i.cpp
deleted file mode 100644
index f61477ccd77..00000000000
--- a/engines/mads/madsv2/core/kernel_i.cpp
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
-/* kernel_i.c by Brian Reynolds 31-Mar-92
-*/
-
-#include <string.h>
-
-#include <general.mac>
-/* pl #include <sound.h> */
-#include <timer.h>
-#include <env.h>
-#include <error.h>
-
-#pragma optimize ("weglt", on)
-
-int kernel_sound_handle = 0;
-
-
-void fastcall kernel_unload_sound_driver(void)
-{
-/* pl if (kernel_sound_handle) {
- sound_queue(0);
-
- timer_set_sound_flag (false);
-
- sound_system_shutdown();
- sound_driver_remove(kernel_sound_handle);
-
- sound_driver_null();
- }
-
- kernel_sound_handle = 0;
-*/
-}
-
-
-int fastcall kernel_load_sound_driver(char *name, char sound_card, int sound_board_address, int sound_board_type, int sound_board_irq)
-{
-/* pl char temp_buf[80];
- char temp_buf_2[80];
- char *mark;
-
- strcpy (temp_buf, name);
- for (mark = temp_buf; *mark; mark++) {
- if (*mark == '#') {
- *mark = sound_card;
- }
- }
-
- if (env_search_mode == ENV_SEARCH_MADS_PATH) {
- env_get_path (temp_buf_2, temp_buf);
- } else {
- if (temp_buf[0] == '*') {
- strcpy (temp_buf_2, &temp_buf[1]);
- } else {
- strcpy (temp_buf_2, temp_buf);
- }
- }
-
- kernel_unload_sound_driver();
-
- kernel_sound_handle = sound_driver_load(temp_buf_2);
-
- if (kernel_sound_handle) {
- sound_driver_init (kernel_sound_handle);
- while (sound_system_setup(sound_board_address, sound_board_type, sound_board_irq) != 0);
- } else {
- sound_driver_null();
- }
-
- timer_set_sound_flag (kernel_sound_handle);
-
- return (kernel_sound_handle);
- */
-}
-
-
\ No newline at end of file
diff --git a/engines/mads/madsv2/core/kernel_j.cpp b/engines/mads/madsv2/core/kernel_j.cpp
deleted file mode 100644
index 393b5819dfb..00000000000
--- a/engines/mads/madsv2/core/kernel_j.cpp
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
-/* kernel_j.c by Brian Reynolds 7-Apr-92
-*/
-
-#include <general.mac>
-#include <room.h>
-#include <matte.h>
-#include <tile.h>
-#include <error.h>
-#include <camera.h>
-#include <rail.h>
-
-#include "kernel.mac"
-#include "kernel_1.h"
-
-#pragma optimize ("weglt", on)
-
-void fastcall kernel_load_variant (int variant)
-{
- room_variant = variant;
-
- if (room_load_variant (room_id, room_variant, NULL, room,
- &scr_depth,
- &scr_walk,
- &scr_special,
- &depth_map,
- &depth_resource,
- tile_attribute_handle)) {
- error_report (ERROR_VARIANT_LOAD_FAILURE, WARNING, MODULE_KERNEL, room_load_error, (room_id * 10) + room_variant);
- }
-
- rail_connect_all_nodes();
-
- camera_jump_to (picture_view_x, picture_view_y);
-}
diff --git a/engines/mads/madsv2/core/kernel_k.cpp b/engines/mads/madsv2/core/kernel_k.cpp
deleted file mode 100644
index 4db0b6d31ac..00000000000
--- a/engines/mads/madsv2/core/kernel_k.cpp
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
-/* kernel_k.c by Brian Reynolds 10-Apr-92
-/*
-/* Changes palette to reflect newly loaded sprite series, but does
-/* not affect cycling color ranges.
-*/
-
-#include <general.mac>
-#include <mcga.h>
-#include <pal.h>
-#include <cycle.h>
-#include "kernel.mac"
-
-#pragma optimize ("weglt", on)
-
-void fastcall kernel_new_palette (void)
-{
- int palette_base, palette_size;
-
- palette_base = KERNEL_RESERVED_LOW_COLORS;
- if (cycling_active) {
- if (cycle_list.num_cycles) {
- palette_base = cycle_list.table[0].first_palette_color + total_cycle_colors;
- }
- }
- palette_size = 256 - palette_base;
-
- mcga_setpal_range(&master_palette, palette_base, palette_size);
-}
-
-
-
\ No newline at end of file
diff --git a/engines/mads/madsv2/core/kernel_l.cpp b/engines/mads/madsv2/core/kernel_l.cpp
deleted file mode 100644
index fb1b545aa56..00000000000
--- a/engines/mads/madsv2/core/kernel_l.cpp
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
-/* kernel_l.c by Brian Reynolds 27-May-92
-*/
-
-#include <general.mac>
-#include <mem.h>
-#include <matte.h>
-#include <player.h>
-#include <sprite.h>
-
-#include "kernel.mac"
-#include "kernel_1.h"
-#include "kernel_6.h"
-#include "kernel_8.h"
-
-
-void fastcall kernel_dump_quotes (void)
-{
- if (kernel.quotes != NULL) {
- mem_free (kernel.quotes);
- kernel.quotes = NULL;
- }
-}
-
-
-void fastcall kernel_dump_all (void)
-{
- kernel_dump_quotes();
- kernel_unload_all_series();
- kernel_seq_init();
- image_marker = 0;
- matte_refresh_work();
-}
-
-
-void fastcall kernel_dump_walker_only (void)
-{
- int count;
- int marker;
-
- marker = player.series_base;
-
- for (count = 0; count < 8; count++) {
- if (player.available[count]) {
- sprite_free(&series_list[marker++], true);
- player.available[count] = false;
- }
- }
-
- image_marker = 0;
- matte_refresh_work();
-
- player.walker_visible = false;
-}
-
diff --git a/engines/mads/madsv2/core/kernel_m.cpp b/engines/mads/madsv2/core/kernel_m.cpp
deleted file mode 100644
index e433c23a4ca..00000000000
--- a/engines/mads/madsv2/core/kernel_m.cpp
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
-/* kernel_m.c by Brian Reynolds 29-May-92
-*/
-
-#include <general.mac>
-#include <loader.h>
-#include <player.h>
-#include <object.h>
-#include <inter.h>
-#include <timer.h>
-#include <game.h>
-/* pl #include <conv.h> */
-#include <camera.h>
-#include <error.h>
-#include <matte.h>
-
-#include "kernel.mac"
-#include "kernel_1.h"
-
-#pragma optimize ("weglt", on)
-
-extern int first_inven;
-
-#define OMR 40 /* OUAF_MAX_ROOMS in global.mac */
-
-extern int room_state[OMR];
-
-
-int fastcall kernel_save_game (char *filename)
-{
- int error_flag = true;
- Load load_handle;
-
- load_handle.open = false;
-
- if (loader_open(&load_handle, filename, "wb", PACK_NONE)) goto done;
-
- if (!loader_write(&game, sizeof(KernelGame), 1, &load_handle)) goto done;
- if (!loader_write(&room_id, sizeof(int), 1, &load_handle)) goto done;
- if (!loader_write(&player2, sizeof(Player2), 1, &load_handle)) goto done;
- if (!loader_write(&inven_num_objects, sizeof(int), 1, &load_handle)) goto done;
- if (inven_num_objects) {
- if (!loader_write(inven, sizeof(int) * inven_num_objects, 1, &load_handle)) goto done;
- }
- if (!loader_write(&player, sizeof(Player), 1, &load_handle)) goto done;
- if (!loader_write(global, sizeof(int) * global_list_size, 1, &load_handle)) goto done;
- if (!loader_write(object, sizeof(Object) * num_objects, 1, &load_handle)) goto done;
- if (!loader_write(0, sizeof(int), 1, &load_handle)) goto done;
- /* pl (see above line) if (!loader_write(&conv_control.running, sizeof(int), 1, &load_handle)) goto done; */
-
- if (!loader_write(&picture_view_x, sizeof(int), 1, &load_handle)) goto done;
- if (!loader_write(&picture_view_y, sizeof(int), 1, &load_handle)) goto done;
- if (!loader_write(room_state, sizeof(int) * OMR, 1, &load_handle)) goto done;
- if (!loader_write(&previous_room, sizeof(int), 1, &load_handle)) goto done;
-
- /* pl if (conv_append(load_handle.handle)) goto done; */
-
- error_flag = false;
-
-done:
- if (load_handle.open) loader_close (&load_handle);
- return (error_flag);
-}
-
-
-int fastcall kernel_load_game (char *filename)
-{
- int error_flag = true;
- Load load_handle;
- byte keep_video_mode;
- byte keep_sound_card;
- byte *keep_quotes;
- int save;
-
- save = player.walker_is_loaded;
-
- /*
- keep_video_mode = kernel.video_mode;
- keep_sound_card = kernel.sound_card;
- keep_quotes = kernel.quotes;
- */
-
- load_handle.open = false;
-
- if (loader_open(&load_handle, filename, "rb", false)) goto done;
-
- if (!loader_read(&game, sizeof(KernelGame), 1, &load_handle)) goto done;
- if (!loader_read(&new_room, sizeof(int), 1, &load_handle)) goto done;
- if (!loader_read(&player2, sizeof(Player2), 1, &load_handle)) goto done;
- if (!loader_read(&inven_num_objects, sizeof(int), 1, &load_handle)) goto done;
- if (inven_num_objects) {
- if (!loader_read(inven, sizeof(int) * inven_num_objects, 1, &load_handle)) goto done;
- }
- if (!loader_read(&player, sizeof(Player), 1, &load_handle)) goto done;
- if (!loader_read(global, sizeof(int) * global_list_size, 1, &load_handle)) goto done;
- if (!loader_read(object, sizeof(Object) * num_objects, 1, &load_handle)) goto done;
- if (!loader_read(0, sizeof(int), 1, &load_handle)) goto done;
- /* pl (see above line) if (!loader_read(&conv_restore_running, sizeof(int), 1, &load_handle)) goto done; */
-
- /* Temporary support for old save file format */
- if (load_handle.pack_list_marker >= (int)load_handle.pack.num_records) goto expand;
-
- if (!loader_read(&camera_old_x_target, sizeof(int), 1, &load_handle)) goto done;
- if (!loader_read(&camera_old_y_target, sizeof(int), 1, &load_handle)) goto done;
- if (!loader_read(room_state, sizeof(int) * OMR, 1, &load_handle)) goto done;
- if (!loader_read(&previous_room, sizeof(int), 1, &load_handle)) goto done;
-
-expand:
- /* pl if (conv_expand(load_handle.handle)) goto done; */
-
- if (inven_num_objects > 0) {
- active_inven = 0;
- } else {
- active_inven = -1;
- }
-
- first_inven = 0;
-
- section_id = KERNEL_RESTORING_GAME;
- room_id = KERNEL_RESTORING_GAME;
-
- new_section = new_room / 100;
-
- kernel.clock = timer_read();
- game.going = true;
-
- error_flag = false;
-
-done:
- if (load_handle.open) loader_close (&load_handle);
-
- /*
- kernel.video_mode = keep_video_mode;
- kernel.sound_card = keep_sound_card;
- kernel.quotes = keep_quotes;
- */
-
-
- player.walker_is_loaded = save;
- /* player.walker_is_loaded = false; */
- /* player.walker_must_reload = true; */
-
- return (error_flag);
-}
-
\ No newline at end of file
diff --git a/engines/mads/madsv2/core/kernel_n.cpp b/engines/mads/madsv2/core/kernel_n.cpp
deleted file mode 100644
index 74bcbcd8dce..00000000000
--- a/engines/mads/madsv2/core/kernel_n.cpp
+++ /dev/null
@@ -1,231 +0,0 @@
-/*
-/* kernel_n.c by Brian Reynolds 17-Jun-92
-/*
-/* Facility to generate "idle chatter" messages randomly within
-/* a predefined region of the screen.
-*/
-
-#include <stdlib.h>
-#include <stdarg.h>
-
-#include <general.mac>
-#include <quote.h>
-#include <imath.h>
-
-#include "kernel.mac"
-#include "kernel_1.h"
-#include "kernel_d.h"
-
-#pragma optimize ("weglt", on)
-
-
-int random_message_handle[KERNEL_MAX_RANDOM_MESSAGES]; /* List of active handles */
-int random_message_quote [KERNEL_MAX_RANDOM_MESSAGES]; /* List of active quote id's */
-int random_max_messages = 1; /* # of active handles/ids */
-
-int random_quote_list[KERNEL_MAX_RANDOM_QUOTES]; /* List of available quote id's */
-int random_quote_list_size = 0; /* # of available quote id's */
-
-int random_min_x = 0; /* X location allowable range */
-int random_max_x = video_x;
-
-int random_min_y = 0; /* Y location allowable range */
-int random_max_y = display_y;
-int random_spacing; /* Y location minimum spacing */
-
-int random_teletype_rate = 0; /* Rate for teletype */
-
-int random_message_color; /* Color scheme for message */
-int random_message_duration; /* Duration of messages */
-
-
-void fastcall kernel_random_purge (void)
-{
- int count;
-
- for (count = 0; count < KERNEL_MAX_RANDOM_MESSAGES; count++) {
- random_message_handle[count] = -1;
- random_message_quote [count] = -1;
- }
-}
-
-
-/*
-/* kernel_random_messages_init()
-/*
-/* Initializes a random chatter sequence. (Parameters end with
-/* a zero-terminated list of already loaded quote id's to be
-/* used for messages).
-*/
-void kernel_random_messages_init (int max_messages_at_once,
- int min_x, int max_x,
- int min_y, int max_y,
- int min_y_spacing,
- int teletype_rate,
- int color,
- int duration,
- int quote_id, ...)
-{
- va_list marker;
- int my_quote = quote_id;
-
- random_max_messages = max_messages_at_once;
- random_min_x = min_x;
- random_max_x = max_x;
- random_min_y = min_y;
- random_max_y = max_y;
- random_spacing = min_y_spacing;
- random_teletype_rate = teletype_rate;
- random_message_color = color;
- random_message_duration = duration;
-
- random_quote_list_size = 0;
-
- va_start (marker, quote_id);
- while (my_quote > 0) {
- if (random_quote_list_size < KERNEL_MAX_RANDOM_QUOTES) {
- random_quote_list[random_quote_list_size++] = my_quote;
- }
-
- my_quote = va_arg (marker, int);
- }
-
- kernel_random_purge();
-}
-
-
-
-/*
-/* kernel_check_random()
-/*
-/* Returns the number of idle chatter messages currently being
-/* displayed.
-*/
-int fastcall kernel_check_random (void)
-{
- int count;
- int sum = 0;
-
- for (count = 0; count < random_max_messages; count++) {
- if (random_message_handle[count] >= 0) sum++;
- }
- return (sum);
-}
-
-
-
-/*
-/* kernel_random_message_server()
-/*
-/* Should be called regularly from daemon code whenever a random
-/* message sequence is running (intercepts triggers from terminating
-/* messages to determine when to free up control space).
-*/
-void fastcall kernel_random_message_server (void)
-{
- if ((kernel.trigger >= KERNEL_RANDOM_MESSAGE_TRIGGER) &&
- (kernel.trigger < KERNEL_RANDOM_MESSAGE_TRIGGER + random_max_messages)) {
- random_message_handle[kernel.trigger - KERNEL_RANDOM_MESSAGE_TRIGGER] = -1;
- random_message_quote [kernel.trigger - KERNEL_RANDOM_MESSAGE_TRIGGER] = -1;
- }
-}
-
-
-
-/*
-/* kernel_generate_random_message()
-/*
-/* Called occasionally to (possibly) generate a random message.
-/*
-/* (generated whenever random(chance_major) <= chance_minor)
-*/
-int fastcall kernel_generate_random_message (int chance_major, int chance_minor)
-{
- int count, count2, scan;
- int bad;
- int generated_one;
- int idx, quote;
- int last_y;
- int message_x, message_y;
- int crash_timeout = 0;
-
- generated_one = false;
-
- for (count = 0; count < random_max_messages; count++) {
- if (random_message_handle[count] < 0) {
-
- /* Don't allow two phrases to teletype at once */
-
- bad = false;
- for (scan = 0; scan < random_max_messages; scan++) {
- if (random_message_handle[scan] >= 0) {
- if (kernel_message[random_message_handle[scan]].flags & KERNEL_MESSAGE_TELETYPE) {
- bad = true;
- }
- }
- }
-
- /* Check random chance for message to appear */
-
- if ((imath_random (1, chance_major) <= chance_minor) && !bad) {
-
- /* Pick randomly from our list of allowable quotes */
-
- do {
- idx = imath_random(0, random_quote_list_size - 1);
- quote = random_quote_list[idx];
- bad = false;
- for (scan = 0; scan < random_max_messages; scan++) {
- if (quote == random_message_quote[scan]) {
- bad = true;
- }
- }
- } while (bad);
-
- random_message_quote[count] = quote;
-
- /* Put message in a random location */
-
- message_x = imath_random (random_min_x, random_max_x);
-
- /* Be sure Y values are properly spaced */
-
- crash_timeout = 0;
-
Commit: cc5467ce47cfa4bb09dd9946cbf470bef597013c
https://github.com/scummvm/scummvm/commit/cc5467ce47cfa4bb09dd9946cbf470bef597013c
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:19:06+10:00
Commit Message:
MADS: PHANTOM: Added more core files
Changed paths:
engines/mads/madsv2/core/room.h
engines/mads/module.mk
diff --git a/engines/mads/madsv2/core/room.h b/engines/mads/madsv2/core/room.h
index 04d42700eda..c02c7bfa1af 100644
--- a/engines/mads/madsv2/core/room.h
+++ b/engines/mads/madsv2/core/room.h
@@ -230,106 +230,48 @@ typedef struct {
Rail rail[1]; /* Rail nodes begin here... */
} Room;
-
typedef Room *RoomPtr;
-
extern RoomDef roomdef;
-
extern int room_load_error;
-
-/* room_1.cpp */
-int room_read_def(int room_code, char *room_file,
- char *picture_base, int mads_mode);
-
-int room_write_def(int room_code, char *room_file,
- int mads_mode);
-
-/* room_2.cpp */
-RoomPtr room_load(int id,
- int variant,
- char *base_path,
- Buffer *picture,
- Buffer *depth,
- Buffer *walk,
- Buffer *special,
- TileMapHeader *picture_map,
- TileMapHeader *depth_map,
- TileResource *picture_resource,
- TileResource *depth_resource,
- int picture_ems_handle,
- int depth_ems_handle,
- int load_flags);
-
-
-/* room_2.cpp */
-void room_unload(RoomPtr room,
- Buffer *picture,
- Buffer *depth,
- Buffer *walk,
- Buffer *special,
- TileMapHeader *picture_map,
- TileMapHeader *depth_map);
-
-
-
-/* room_3.cpp */
extern byte room_loaded_depth;
extern byte room_loaded_walk;
extern byte room_loaded_special;
-int room_load_variant(int id,
- int variant,
- char *base_path,
- RoomPtr room,
- Buffer *depth,
- Buffer *walk,
- Buffer *special,
- TileMapHeader *depth_map,
- TileResource *depth_resource,
- int depth_ems_handle);
-
-/* room_3.cpp */
-void room_dump_attribute(Buffer *depth,
- Buffer *walk,
- Buffer *special,
+/**
+ * Reads the .DEF file for the specified room into the "room" structure.
+ * @return Returns 0 if successful, or -1 for error.
+ */
+extern int room_read_def(int room_code, char *room_file, char *picture_base, int mads_mode);
+extern int room_write_def(int room_code, const char *room_file, int mads_mode);
+extern RoomPtr room_load(int id, int variant, const char *base_path,
+ Buffer *picture, Buffer *depth, Buffer *walk, Buffer *special,
+ TileMapHeader *picture_map, TileMapHeader *depth_map,
+ TileResource *picture_resource, TileResource *depth_resource,
+ int picture_ems_handle, int depth_ems_handle, int load_flags);
+extern void room_unload(RoomPtr room, Buffer *picture, Buffer *depth, Buffer *walk,
+ Buffer *special, TileMapHeader *picture_map, TileMapHeader *depth_map);
+
+/**
+ * Loads the specified variant for a room.
+ */
+extern int room_load_variant(int id, int variant, const char *base_path, RoomPtr room,
+ Buffer *depth, Buffer *walk, Buffer *special, TileMapHeader *depth_map,
+ TileResource *depth_resource, int depth_ems_handle);
+extern void room_dump_attribute(Buffer *depth, Buffer *walk, Buffer *special,
TileMapHeader *depth_map);
-
-/* room_4.cpp */
-int room_compile_hotspots(int id, int compression);
-
-/* room_5.cpp */
-HotPtr room_load_hotspots(int id, int *num_spots);
-
-/* room_6.cpp */
-int room_read_pict(int room_code, char *room_file,
- int mads_mode);
-
-int room_write_pict(int room_code, char *room_file,
- int mads_mode);
-
-/* room_7.cpp */
-void room_file_name(char *target, char *suffix,
- int code, char *main_name, int mads_mode);
-
-
-/* room_8.cpp */
-void room_himem_preload(int room, int level);
-
-
-/* room_9.cpp */
-RoomPtr room_dummy_init(int xs, int ys);
-
-/* room_a.cpp */
-int room_picture_load(int room_id, Buffer *picture, int load_flags);
-
-/* room_b.cpp */
-void room_resolve_base(char *base, char *file, int id, char *base_path);
-
-
-/* room_c.cpp */
-int room_invert(void);
+extern int room_compile_hotspots(int id, int compression);
+extern HotPtr room_load_hotspots(int id, int *num_spots);
+extern int room_read_pict(int room_code, const char *room_file, int mads_mode);
+extern int room_write_pict(int room_code, const char *room_file, int mads_mode);
+extern void room_file_name(char *target, const char *suffix, int code,
+ char *main_name, int mads_mode);
+extern void room_himem_preload(int room, int level);
+extern RoomPtr room_dummy_init(int xs, int ys);
+extern int room_picture_load(int room_id, Buffer *picture, int load_flags);
+extern void room_resolve_base(char *base, const char *file, int id, const char *base_path);
+extern int room_invert(void);
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index b4d5b1e162e..5a5ae5ae7f2 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -89,6 +89,7 @@ MODULE_OBJS += \
madsv2/core/popup.o \
madsv2/core/quote_1.o \
madsv2/core/rail.o \
+ madsv2/core/room.o \
madsv2/core/screen.o \
madsv2/core/sort.o \
madsv2/core/speech.o \
Commit: 8df8ff83e8d8d08b50dc4309911b219832beacc2
https://github.com/scummvm/scummvm/commit/8df8ff83e8d8d08b50dc4309911b219832beacc2
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:19:07+10:00
Commit Message:
MADS: PHANTOM: Added more core files
Changed paths:
A engines/mads/madsv2/core/anim.cpp
A engines/mads/madsv2/core/attr.cpp
A engines/mads/madsv2/core/copy.cpp
A engines/mads/madsv2/core/copy.h
A engines/mads/madsv2/core/game.cpp
A engines/mads/madsv2/core/heap.cpp
A engines/mads/madsv2/core/imath.cpp
A engines/mads/madsv2/core/quote.cpp
A engines/mads/madsv2/core/room.cpp
R engines/mads/madsv2/core/quote_1.cpp
engines/mads/madsv2/core/anim.h
engines/mads/madsv2/core/dialog.cpp
engines/mads/madsv2/core/error.h
engines/mads/madsv2/core/fileio.cpp
engines/mads/madsv2/core/fileio.h
engines/mads/madsv2/core/font.h
engines/mads/madsv2/core/game.h
engines/mads/madsv2/core/heap.h
engines/mads/madsv2/core/imath.h
engines/mads/madsv2/core/kernel.cpp
engines/mads/madsv2/core/mouse.cpp
engines/mads/madsv2/core/mouse.h
engines/mads/madsv2/core/popup.cpp
engines/mads/madsv2/core/popup.h
engines/mads/madsv2/core/quote.h
engines/mads/madsv2/core/rail.cpp
engines/mads/madsv2/core/screen.cpp
engines/mads/madsv2/core/screen.h
engines/mads/madsv2/core/timer.cpp
engines/mads/madsv2/core/timer.h
engines/mads/madsv2/core/window.cpp
engines/mads/madsv2/core/window.h
engines/mads/madsv2/engine.h
engines/mads/module.mk
diff --git a/engines/mads/madsv2/core/anim.cpp b/engines/mads/madsv2/core/anim.cpp
new file mode 100644
index 00000000000..57fcb6f88b6
--- /dev/null
+++ b/engines/mads/madsv2/core/anim.cpp
@@ -0,0 +1,500 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "mads/madsv2/core/anim.h"
+#include "mads/madsv2/core/himem.h"
+#include "mads/madsv2/core/env.h"
+#include "mads/madsv2/core/sprite.h"
+#include "mads/madsv2/core/room.h"
+#include "mads/madsv2/core/color.h"
+#include "mads/madsv2/core/fileio.h"
+#include "mads/madsv2/core/lbm.h"
+#include "mads/madsv2/core/buffer.h"
+#include "mads/madsv2/core/matte.h"
+#include "mads/madsv2/core/inter.h"
+#include "mads/madsv2/core/pal.h"
+#include "mads/madsv2/core/mads.h"
+#include "mads/madsv2/core/tile.h"
+#include "mads/madsv2/core/error.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+ShadowList anim_shadow = { 0 };
+int anim_error;
+
+
+int anim_load_background(AnimFile *anim_in, Buffer *this_orig,
+ Buffer *this_depth, TileMapHeader *pictureMap, TileMapHeader *depthMap,
+ TileResource *pictureResource, TileResource *depthResource,
+ RoomPtr *room, CycleListPtr cycle_list, int load_flags, int star_search) {
+ int error_flag;
+ char temp_buf[80];
+ RoomPtr my_room = NULL;
+
+ error_flag = false;
+
+ if (anim_in->background_type <= AA_FULLSIZE) {
+
+ pal_activate_shadow(&anim_shadow);
+
+ my_room = room_load(anim_in->background_room, 0, anim_in->background_name,
+ this_orig, this_depth, NULL, NULL,
+ pictureMap,
+ depthMap,
+ pictureResource,
+ depthResource,
+ tile_picture_handle,
+ tile_attribute_handle,
+ load_flags);
+
+ if (my_room == NULL) {
+ error_flag = true;
+ } else {
+ if (cycle_list != NULL) {
+ memcpy(cycle_list, &my_room->cycle_list, sizeof(CycleList));
+ }
+ }
+
+ } else if (anim_in->background_type == AA_INTERFACE) {
+ temp_buf[0] = 0;
+ if (star_search) {
+ Common::strcat_s(temp_buf, "*");
+ }
+ Common::strcat_s(temp_buf, anim_in->background_name);
+ error_flag = inter_load_background(temp_buf, this_orig);
+ if (cycle_list != NULL) {
+ cycle_list->num_cycles = 0;
+ }
+
+ if (pictureMap != NULL) {
+ tile_fake_map(TILE_PICTURE,
+ pictureMap,
+ this_orig,
+ this_orig->x,
+ this_orig->y);
+ }
+
+ if (depthMap != NULL) depthMap->map = NULL;
+
+ } else {
+ buffer_init_name(this_orig, video_x, video_y, "$anmorig");
+ if (this_depth != NULL) buffer_init_name(this_depth, video_x, video_y >> 1, "$anmdpth");
+ if (this_orig->data != NULL) {
+ buffer_fill(*this_orig, 0);
+ } else {
+ error_flag = true;
+ }
+
+ if (this_depth != NULL) {
+ if (this_depth->data != NULL) {
+ buffer_fill(*this_depth, 0xff);
+ }
+ }
+
+ if (pictureMap != NULL) {
+ tile_fake_map(TILE_PICTURE,
+ pictureMap,
+ this_orig,
+ this_orig->x, this_orig->y);
+ }
+
+ if (depthMap != NULL) {
+ tile_fake_map(TILE_ATTRIBUTE,
+ depthMap,
+ this_depth,
+ this_orig->x, this_orig->y);
+ }
+
+ }
+
+ if (error_flag) {
+ if (this_depth != NULL) buffer_free(this_depth);
+ buffer_free(this_orig);
+ if (pictureMap != NULL) tile_map_free(pictureMap);
+ if (pictureMap != NULL) tile_map_free(depthMap);
+ }
+
+ if (room != NULL) *room = my_room;
+
+ return error_flag;
+}
+
+void anim_unload(AnimPtr anim) {
+ int count;
+
+ if (anim != NULL) {
+ if (anim->misc_any_packed) {
+ matte_deallocate_series(anim->series_id[anim->misc_packed_series], true);
+ }
+ for (count = anim->num_series - 1; count >= 0; count--) {
+ if (!anim->misc_any_packed || (count != anim->misc_packed_series)) {
+ matte_deallocate_series(anim->series_id[count], true);
+ }
+ }
+ if (anim->font != NULL) {
+ mem_free(anim->font);
+ }
+
+ mem_free(anim);
+ }
+}
+
+AnimPtr anim_load(const char *file_name, Buffer *orig, Buffer *depth,
+ TileMapHeader *pictureMap, TileMapHeader *depthMap,
+ TileResource *pictureResource, TileResource *depthResource,
+ RoomPtr *room, CycleListPtr cycle_list, int load_flags) {
+ int count;
+ int error_flag = true;
+ int star_search;
+ char temp_buf[80];
+ char block_name[20];
+ char *mark;
+ word *color_slaves = (word *)temp_buf;
+ word num_color_slaves;
+ long image_size, frame_size, speech_size, anim_size;
+ AnimPtr anim = NULL;
+ AnimInterPtr anim2 = NULL;
+ AnimFile anim_in;
+ Load load_handle;
+
+ mem_last_alloc_loader = MODULE_ANIM_LOADER;
+
+ load_handle.open = false;
+
+ Common::strcpy_s(temp_buf, file_name);
+ if (strchr(temp_buf, '.') == NULL) {
+ Common::strcat_s(temp_buf, ".AA");
+ }
+
+ star_search = (temp_buf[0] == '*');
+
+ anim_error = 1;
+ if (loader_open(&load_handle, temp_buf, "rb", true)) goto done;
+
+ anim_error = 2;
+ if (!loader_read(&anim_in, sizeof(AnimFile), 1, &load_handle)) goto done;
+
+ if (anim_in.background_type == AA_INTERFACE) {
+ load_flags |= PAL_MAP_RESERVED;
+ }
+
+ if (load_flags & ANIM_LOAD_BACKGROUND) {
+ if (anim_load_background(&anim_in,
+ orig, depth,
+ pictureMap, depthMap,
+ pictureResource, depthResource,
+ room, cycle_list,
+ load_flags, star_search)) {
+ anim_error = 20000 + room_load_error;
+ goto done;
+ }
+ }
+
+ if (load_flags & ANIM_LOAD_BACK_ONLY) {
+ anim_in.num_speech = 0;
+ anim_in.num_images = 0;
+ anim_in.num_frames = 0;
+ }
+
+ // get how much memory we need to load all the bits
+ // AA_INTERFACE are like the fish in the interface in rex... (quasi supported)
+
+ if (anim_in.background_type != AA_INTERFACE) {
+ speech_size = (long)sizeof(Speech) * (long)anim_in.num_speech;
+ image_size = (long)sizeof(Image) * (long)anim_in.num_images;
+ frame_size = (long)sizeof(Frame) * (long)anim_in.num_frames;
+ anim_size = (long)sizeof(Anim) + speech_size + image_size + frame_size;
+ } else {
+ speech_size = (long)sizeof(Speech) * (long)anim_in.num_speech;
+ image_size = (long)sizeof(ImageInter) * (long)anim_in.num_images;
+ frame_size = (long)sizeof(SegmentInter) * (long)anim_in.num_frames;
+ anim_size = (long)sizeof(AnimInter) + speech_size + image_size + frame_size;
+ }
+
+ Common::strcpy_s(block_name, "A$");
+ mark = temp_buf;
+ if (*mark == '*') mark++;
+ if ((*mark == 'R') && (*(mark + 1) == 'M')) {
+ mark += 2;
+ }
+ strncat(block_name, mark, 6);
+
+ anim = (AnimPtr)mem_get_name(anim_size, block_name);
+ anim2 = (AnimInterPtr)anim;
+
+ anim_error = 4;
+ if (anim == NULL) goto done;
+
+ anim->font = NULL;
+
+ if (anim_in.background_type != AA_INTERFACE) {
+ anim->speech = (SpeechPtr)mem_normalize(((char *)anim) + sizeof(Anim));
+ anim->image = (ImagePtr)mem_normalize(((char *)anim->speech) + speech_size);
+ anim->frame = (FramePtr)mem_normalize(((char *)anim->image) + image_size);
+ } else {
+ anim2->speech = (SpeechPtr)mem_normalize(((char *)anim2) + sizeof(AnimInter));
+ anim2->image = (ImageInterPtr)mem_normalize(((char *)anim2->speech) + speech_size);
+ anim2->segment = (SegmentInterPtr)mem_normalize(((char *)anim2->image) + image_size);
+ }
+
+ // get ready for loading some series
+ for (count = 0; count < AA_MAX_SERIES; count++) {
+ anim->series[count] = NULL;
+ }
+
+ // we read the header before, now get it into our new structure
+ memcpy(anim, &anim_in, sizeof(AnimFile));
+
+ for (count = 0; count < anim->num_series; count++) {
+ anim->series_id[count] = -1;
+ }
+
+ if (speech_size > 0) {
+ anim_error = 5;
+ if (!loader_read(anim->speech, speech_size, 1, &load_handle)) goto done;
+ }
+
+ // x, y, depth, s, series and sprite id comprise an image
+ // read in all images here. image_size is sizeof(Image)* number of images
+
+ if (image_size > 0) {
+ anim_error = 6;
+ if (!loader_read(anim->image, image_size, 1, &load_handle)) goto done;
+ }
+
+ // a frame contains timing information and sound effect information
+ // images know which frame they are a part of
+
+ if (frame_size > 0) {
+ anim_error = 7;
+ if (!loader_read(anim->frame, frame_size, 1, &load_handle)) goto done;
+ }
+
+
+ loader_close(&load_handle);
+
+ if (anim->load_flags & AA_LOAD_FONT) {
+ temp_buf[0] = 0;
+ if (star_search)
+ Common::strcat_s(temp_buf, "*");
+
+ Common::strcat_s(temp_buf, anim_in.font_file);
+ anim->font = font_load(temp_buf);
+ anim_error = 8;
+
+ if (anim->font == NULL)
+ goto done;
+ }
+
+ // we've loaded the anim file, now load the series
+
+ for (count = 0; count < anim->num_series; count++) {
+ if (!anim->misc_any_packed || (count != anim->misc_packed_series)) {
+ temp_buf[0] = 0;
+ if (star_search) {
+ Common::strcat_s(temp_buf, "*");
+ }
+ Common::strcat_s(temp_buf, anim_in.series_name[count]);
+
+ // matte_load_series will check to see if a series was
+ // previously loaded before it goes and gets it from the disk
+ // we'll get back a pointer to the actual sprite series for
+ // each id number
+
+ /* printf("temp_buf=%s",temp_buf); keys_get(); */
+ anim->series_id[count] = matte_load_series(temp_buf, load_flags, 0);
+ if (anim->series_id[count] < 0) {
+ anim_error = 9;
+ goto done;
+ }
+ anim->series[count] = series_list[anim->series_id[count]];
+
+ }
+ }
+
+ // if a separate load was needed for some reason
+ // if we're stream loading, we might need to allocate memory
+ // last so that it is at the end of memory - decrease fragmentation
+ // problems
+
+ if (anim->misc_any_packed) {
+ temp_buf[0] = 0;
+ if (star_search) {
+ Common::strcat_s(temp_buf, "*");
+ }
+ Common::strcat_s(temp_buf, anim_in.series_name[anim->misc_packed_series]);
+
+ count = anim->misc_packed_series;
+ anim->series_id[count] = matte_load_series(temp_buf, load_flags, 0);
+ if (anim->series_id[count] < 0) {
+ anim_error = 11;
+ goto done;
+ }
+
+ anim->series[count] = series_list[anim->series_id[count]];
+ }
+
+ // compact all the colors in the series to a single color handle
+ // so it doesn't take up lots of palette space
+
+ num_color_slaves = 0;
+ for (count = 1; count < anim->num_series; count++) {
+ color_slaves[num_color_slaves] = anim->series[count]->color_handle;
+ num_color_slaves++;
+ }
+
+ if (num_color_slaves > 0) {
+ pal_compact(anim->series[0]->color_handle, num_color_slaves, color_slaves);
+ }
+
+ // translate the numbers we have into actual runtime numbers
+ // in the file they were 0, 1, 2, ... When we translate them they'll
+ // have to be moved not to conflict with series that we might already
+ // have loaded
+
+ if (anim_in.background_type != AA_INTERFACE) {
+ for (count = 0; count < anim->num_images; count++) {
+ anim->image[count].series_id = (byte)anim->series_id[anim->image[count].series_id];
+ }
+ } else {
+ for (count = 0; count < anim2->num_images; count++) {
+ anim2->image[count].series_id = (byte)anim2->series_id[anim2->image[count].series_id];
+ }
+ }
+
+ error_flag = false;
+ anim_error = 0;
+
+done:
+ if (error_flag) {
+ anim_unload(anim);
+ anim = NULL;
+
+ if (load_flags & ANIM_LOAD_BACKGROUND) {
+ if (depth != NULL) buffer_free(depth);
+ if (orig != NULL) buffer_free(orig);
+ if (depthMap != NULL) tile_map_free(depthMap);
+ if (pictureMap != NULL) tile_map_free(pictureMap);
+ }
+ }
+ if (load_handle.open) loader_close(&load_handle);
+
+ return (anim);
+}
+
+int anim_get_sound_info(char *file_name, char *sound_file_buffer, int *sound_load_flag) {
+ int error_flag = true;
+ AnimFile anim_in;
+ Load load_handle;
+
+ load_handle.open = false;
+
+ if (loader_open(&load_handle, file_name, "rb", true)) goto done;
+
+ if (!loader_read(&anim_in, sizeof(AnimFile), 1, &load_handle)) goto done;
+
+ Common::strcpy_s(sound_file_buffer, 65536, anim_in.sound_file_name);
+ *sound_load_flag = (anim_in.load_flags & AA_LOAD_SOUND);
+
+ error_flag = false;
+
+done:
+ if (load_handle.open)
+ loader_close(&load_handle);
+ return error_flag;
+}
+
+int anim_get_header_info(char *file_name,
+ AnimFile *anim_in) {
+ int error_flag = true;
+ Load load_handle;
+
+ load_handle.open = false;
+
+ if (loader_open(&load_handle, file_name, "rb", true))
+ goto done;
+
+ if (!loader_read(anim_in, sizeof(AnimFile), 1, &load_handle))
+ goto done;
+
+ error_flag = false;
+
+done:
+ if (load_handle.open)
+ loader_close(&load_handle);
+
+ return error_flag;
+}
+
+int anim_himem_preload(char *name, int level) {
+ int error_flag = true;
+ char temp_buf[80];
+ AnimFile anim_in;
+ int count2;
+ int mads_mode;
+
+ mads_mode = (name[0] == '*');
+
+ himem_preload_series(name, level);
+
+ if (anim_get_header_info(name, &anim_in)) goto done;
+
+ if (anim_in.load_flags & AA_LOAD_FONT) {
+ temp_buf[0] = 0;
+ if (mads_mode) Common::strcat_s(temp_buf, "*");
+ Common::strcat_s(temp_buf, anim_in.font_file);
+ himem_preload_series(temp_buf, level);
+ }
+
+ for (count2 = 0; count2 < anim_in.num_series; count2++) {
+ temp_buf[0] = 0;
+ if (mads_mode) Common::strcpy_s(temp_buf, "*");
+ Common::strcat_s(temp_buf, anim_in.series_name[count2]);
+ himem_preload_series(temp_buf, level);
+ }
+
+ if (anim_in.background_type == AA_ROOM) {
+ env_get_level_path(temp_buf, ROOM, ".DAT", 0, anim_in.background_room);
+ himem_preload_series(temp_buf, level);
+ env_get_level_path(temp_buf, ROOM, ".TT", 0, anim_in.background_room);
+ himem_preload_series(temp_buf, level);
+ env_get_level_path(temp_buf, ROOM, ".MM", 0, anim_in.background_room);
+ himem_preload_series(temp_buf, level);
+ env_get_level_path(temp_buf, ROOM, ".TT0", 0, anim_in.background_room);
+ himem_preload_series(temp_buf, level);
+ env_get_level_path(temp_buf, ROOM, ".MM0", 0, anim_in.background_room);
+ himem_preload_series(temp_buf, level);
+ } else if (anim_in.background_type == AA_INTERFACE) {
+ temp_buf[0] = 0;
+ if (mads_mode) Common::strcat_s(temp_buf, "*");
+ Common::strcat_s(temp_buf, anim_in.background_name);
+ himem_preload_series(temp_buf, level);
+ }
+
+ error_flag = false;
+
+done:
+ return error_flag;
+}
+
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/core/anim.h b/engines/mads/madsv2/core/anim.h
index ce76b2f9672..77d4efc2ba7 100644
--- a/engines/mads/madsv2/core/anim.h
+++ b/engines/mads/madsv2/core/anim.h
@@ -468,7 +468,7 @@ int anim_load_background(AnimFile *anim_in,
/* anim_2.cpp */
void anim_unload(AnimPtr anim);
-AnimPtr anim_load(char *file_name,
+AnimPtr anim_load(const char *file_name,
Buffer *orig, Buffer *depth,
TileMapHeader *picture_map,
TileMapHeader *depth_map,
diff --git a/engines/mads/madsv2/core/attr.cpp b/engines/mads/madsv2/core/attr.cpp
new file mode 100644
index 00000000000..cd9407381b2
--- /dev/null
+++ b/engines/mads/madsv2/core/attr.cpp
@@ -0,0 +1,173 @@
+/* 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 "mads/madsv2/core/attr.h"
+#include "mads/madsv2/core/buffer.h"
+#include "mads/madsv2/core/loader.h"
+#include "mads/madsv2/core/fileio.h"
+#include "mads/madsv2/core/room.h"
+#include "mads/madsv2/core/env.h"
+#include "mads/madsv2/core/dialog.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+int attr_load_error = 0;
+
+int attr_walk(Buffer *attr, int x, int y) {
+ byte walk_code = 0;
+ byte *scan;
+ int shift_count;
+ int byte_number;
+
+ if (attr == NULL) goto done;
+ if (attr->data == NULL) goto done;
+
+ byte_number = (x >> 3);
+ shift_count = 7 - (x - (byte_number << 3));
+ scan = buffer_pointer(attr, byte_number, y);
+ walk_code = (byte)((*scan >> shift_count) & 1);
+
+done:
+ return (int)walk_code;
+}
+
+int attr_depth(TileMapHeader *depth_map, int x, int y) {
+ byte depth_code = 0x0f;
+ byte *scan;
+ byte shift_count;
+ int pan_to_x = 0, pan_to_y = 0;
+ int view_changed = false;
+
+ if ((depth_map == NULL) || (depth_map->buffer == NULL)) goto done;
+
+ if (!(((x >= depth_map->pan_base_x) && (x < (depth_map->pan_base_x + depth_map->orig_x_size))) &&
+ ((y >= depth_map->pan_base_y) && (y < (depth_map->pan_base_y + depth_map->orig_y_size))))) {
+ view_changed = true;
+ pan_to_x = depth_map->pan_x;
+ pan_to_y = depth_map->pan_y;
+ tile_pan(depth_map, x, y);
+ }
+
+ x = x - depth_map->pan_base_x;
+ y = y - depth_map->pan_base_y;
+
+ scan = buffer_pointer(depth_map->buffer, (x >> 1), y);
+ shift_count = (byte)((x & 1) ? 0 : 4);
+ depth_code = (byte)((*scan >> shift_count) & 0x0f);
+
+ if (view_changed) {
+ tile_pan(depth_map, pan_to_x, pan_to_y);
+ }
+
+done:
+ return (int)depth_code;
+}
+
+int attr_special(Buffer *attr, int x, int y) {
+ byte special_code = 0;
+ byte *scan;
+ int shift_count;
+ int byte_number;
+
+ if (attr == NULL) goto done;
+ if (attr->data == NULL) goto done;
+
+ byte_number = (x >> 3);
+ shift_count = 7 - (x - (byte_number << 3));
+ scan = buffer_pointer(attr, byte_number, y);
+ special_code = (byte)((*scan >> shift_count) & 1);
+
+done:
+ return (int)special_code;
+}
+
+int attr_load(char *base_name,
+ int item_type,
+ int variant,
+ Buffer *target,
+ int size_x,
+ int size_y) {
+ int error_flag = true;
+ long read_size;
+ char temp_buf[80];
+ char block_name[20];
+ Load load_handle;
+
+ load_handle.open = false;
+ attr_load_error = 1;
+
+ size_x = ((size_x - 1) >> 3) + 1;
+
+ switch (item_type) {
+ case ROOM_WALK:
+ Common::strcpy_s(block_name, "$scrwalk");
+ break;
+ case ROOM_SPECIAL:
+ default:
+ Common::strcpy_s(block_name, "$scrspec");
+ break;
+ }
+
+ buffer_init_name(target, size_x, size_y, block_name);
+ if (target->data == NULL) goto done;
+
+ buffer_fill(*target, 0);
+
+ Common::strcpy_s(temp_buf, base_name);
+ if (item_type == ROOM_SPECIAL) {
+ fileio_add_ext(temp_buf, "PP");
+ } else {
+ fileio_add_ext(temp_buf, "WW");
+ }
+
+ env_catint(temp_buf, variant, 1);
+
+ if (!env_exist(temp_buf)) {
+ if (variant > 0) {
+ temp_buf[strlen(temp_buf) - 1] = '0';
+ }
+
+ if (!env_exist(temp_buf)) {
+ attr_load_error = 0;
+ goto done;
+ }
+ }
+
+ if (loader_open(&load_handle, temp_buf, "rb", false)) goto done;
+
+ read_size = (long)size_x * (long)size_y;
+
+ if (!loader_read(target->data, read_size, 1, &load_handle)) goto done;
+
+ error_flag = false;
+
+done:
+ if (load_handle.open) loader_close(&load_handle);
+ if (error_flag) {
+ if (target->data != NULL) buffer_free(target);
+ }
+
+ return error_flag;
+}
+
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/core/copy.cpp b/engines/mads/madsv2/core/copy.cpp
new file mode 100644
index 00000000000..23f5078b73f
--- /dev/null
+++ b/engines/mads/madsv2/core/copy.cpp
@@ -0,0 +1,264 @@
+/* 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/file.h"
+#include "mads/madsv2/core/copy.h"
+#include "mads/madsv2/core/imath.h"
+#include "mads/madsv2/core/env.h"
+#include "mads/madsv2/core/popup.h"
+#include "mads/madsv2/core/font.h"
+#include "mads/madsv2/core/fileio.h"
+#include "mads/madsv2/core/mem.h"
+#include "mads/madsv2/core/error.h"
+#include "mads/madsv2/core/timer.h"
+#include "mads/madsv2/core/font.h"
+#include "mads/madsv2/core/popup.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+extern char global_release_version[10];
+
+char happy_file_name[12] = "XSOUND.000";
+bool popup_vomitation_flag = false;
+
+void CopyProt::load(Common::SeekableReadStream *src) {
+ manual = src->readByte();
+ page = src->readUint16LE();
+ line = src->readUint16LE();
+ word_number = src->readUint16LE();
+ src->read(say, 20);
+}
+
+void copy_mangle(CopyProt *copy_prot) {
+ int count;
+ byte *dog;
+
+ dog = (byte *)copy_prot;
+
+ for (count = 0; count < sizeof(CopyProt); count++) {
+ *dog ^= 0xff;
+ dog++;
+ }
+}
+
+int copy_load(CopyProt *copy_prot) {
+ int error_flag = true;
+ int num_items;
+ int item;
+ int seek_dog;
+ Common::SeekableReadStream *handle = NULL;
+
+ handle = env_open("*HOGANUS.DAT", "rb");
+ if (handle == NULL) goto done;
+
+ num_items = handle->readUint16LE();
+ item = imath_random(1, num_items);
+ if (item < 1) item = 1;
+ if (item > num_items) item = num_items;
+
+ seek_dog = (item - 1) * sizeof(CopyProt);
+ if (seek_dog) {
+ handle->seek(seek_dog, SEEK_CUR);
+ }
+
+ copy_prot->load(handle);
+
+ copy_mangle(copy_prot);
+
+ error_flag = false;
+
+done:
+ delete handle;
+ return error_flag;
+}
+
+int copy_pop_and_ask(void) {
+ int error_flag = COPY_FAIL;
+ int result;
+ int count;
+ char work_buf[80];
+ char page_buf[10];
+ char line_buf[10];
+ char word_buf[10];
+ char entry_buf[80];
+ CopyProt copy_prot;
+
+ popup_vomitation_flag = false; /* Allow keep of first letter */
+
+ if (copy_load(©_prot)) goto finish;
+
+ mads_itoa(copy_prot.page, page_buf, 10);
+ mads_itoa(copy_prot.line, line_buf, 10);
+ mads_itoa(copy_prot.word_number, word_buf, 10);
+
+ for (count = 0; (count < COPY_TRIES_ALLOWED); count++) {
+ if (popup_create(font_inter, 32, POPUP_CENTER, POPUP_CENTER))
+ goto finish;
+
+ if (!count) {
+ Common::strcpy_s(work_buf, "REX NEBULAR version ");
+ Common::strcat_s(work_buf, global_release_version);
+ popup_center_string(work_buf, true);
+ popup_write_string("\n");
+ popup_center_string("(Copy Protection, for your convenience)", false);
+ } else {
+ popup_center_string("ANSWER INCORRECT!", true);
+ popup_write_string("\n");
+ popup_center_string("(But we'll give you another chance!)", false);
+ }
+ popup_write_string("\n");
+
+ Common::strcpy_s(work_buf, "Now comes the part that everybody hates. But if we don't");
+ popup_write_string(work_buf);
+ Common::strcpy_s(work_buf, "do this, nasty rodent-like people will pirate this game,");
+ popup_write_string(work_buf);
+ Common::strcpy_s(work_buf, "and a whole generation of talented designers, programmers,");
+ popup_write_string(work_buf);
+ Common::strcpy_s(work_buf, "artists, and playtesters will go hungry, and will wander");
+ popup_write_string(work_buf);
+ Common::strcpy_s(work_buf, "aimlessly through the land at night searching for peace.");
+ popup_write_string(work_buf);
+ Common::strcpy_s(work_buf, "So let's grit our teeth and get it over with. Just get");
+ popup_write_string(work_buf);
+
+ Common::strcpy_s(work_buf, "out your copy of ");
+ if (copy_prot.manual == 'g') {
+ Common::strcat_s(work_buf, "the GAME MANUAL");
+ } else {
+ Common::strcat_s(work_buf, "REX'S LOGBOOK");
+ }
+ Common::strcat_s(work_buf, ". See! That was easy. ");
+ popup_write_string(work_buf);
+
+ Common::strcpy_s(work_buf, "Next, just turn to page ");
+ Common::strcat_s(work_buf, page_buf);
+ Common::strcat_s(work_buf, ". On line ");
+ Common::strcat_s(work_buf, line_buf);
+ Common::strcat_s(work_buf, ", find word number ");
+ Common::strcat_s(work_buf, word_buf);
+ Common::strcat_s(work_buf, ", ");
+ popup_write_string(work_buf);
+
+ Common::strcpy_s(work_buf, "and type it on the line below (we've even given you");
+ popup_write_string(work_buf);
+ Common::strcpy_s(work_buf, "first letter as a hint). As soon as you do that, we can get");
+ popup_write_string(work_buf);
+ popup_write_string("right into this really COOL adventure game!\n");
+
+ popup_write_string("\n");
+ popup_write_string(" ");
+ popup_set_ask();
+ popup_write_string("\n");
+
+ entry_buf[0] = copy_prot.say[0];
+ entry_buf[1] = 0;
+
+ result = popup_ask_string(entry_buf, 12, true);
+ if (result < 0) goto finish;
+ if (result > 0) {
+ error_flag = COPY_ESCAPE;
+ goto done;
+ }
+
+ mads_strlwr(entry_buf);
+ if (strcmp(entry_buf, copy_prot.say) == 0) goto finish;
+ }
+
+ goto done;
+
+finish:
+ error_flag = COPY_SUCCEED;
+
+done:
+ popup_vomitation_flag = true; /* Reset */
+
+ return (error_flag);
+}
+
+static int copy_read_boot_sector(byte *buffer) {
+ error("TODO: copy_read_boot_sector");
+}
+
+static int copy_read_happy_file(byte *buffer) {
+ int error_flag = true;
+ Common::File handle;
+
+ if (handle.open(happy_file_name)) {
+ if (!fileio_fread_f(buffer, COPY_LENGTH, 1, &handle)) goto done;
+ }
+
+ error_flag = false;
+
+done:
+ handle.close();
+ return error_flag;
+}
+
+static int copy_write_happy_file(byte *buffer) {
+ error("TODO: copy_write_happy_file");
+}
+
+int copy_verify(void) {
+ int error_flag = COPY_FAIL;
+ int dog_master;
+ byte *work1 = NULL;
+ byte *work2 = NULL;
+
+ work1 = (byte *)mem_get(COPY_LENGTH);
+ work2 = (byte *)mem_get(COPY_LENGTH);
+
+ if ((work1 != NULL) && (work2 != NULL)) {
+ //srand((word)timer_read_dos());
+ dog_master = imath_random(1, 1000);
+
+ if (dog_master <= 50) {
+ memset(work1, 0, COPY_LENGTH);
+ copy_write_happy_file(work1);
+ }
+
+ if (!copy_read_boot_sector(work1)) {
+ if (!copy_read_happy_file(work2)) {
+ if (memcmp(work1, work2, COPY_LENGTH) == 0) {
+ goto finish;
+ }
+ }
+ }
+ }
+
+ error_flag = copy_pop_and_ask();
+ if (error_flag != COPY_SUCCEED) goto done;
+
+ if ((work1 != NULL) && (work2 != NULL)) {
+ copy_write_happy_file(work1);
+ }
+
+finish:
+ error_flag = COPY_SUCCEED;
+
+done:
+ if (work2 != NULL) mem_free(work2);
+ if (work1 != NULL) mem_free(work1);
+ return error_flag;
+}
+
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/core/copy.h b/engines/mads/madsv2/core/copy.h
new file mode 100644
index 00000000000..331c564b19a
--- /dev/null
+++ b/engines/mads/madsv2/core/copy.h
@@ -0,0 +1,59 @@
+/* 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 MADS_CORE_COPY_H
+#define MADS_CORE_COPY_H
+
+#include "common/stream.h"
+#include "mads/madsv2/core/general.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+#define COPY_SUCCEED 0
+#define COPY_FAIL 1
+#define COPY_ESCAPE 2
+
+#define COPY_TRIES_ALLOWED 2
+
+#define COPY_LENGTH 4096
+#define COPY_CHECK 256
+
+
+struct CopyProt {
+ char manual;
+ int page;
+ int line;
+ int word_number;
+ char say[20];
+
+ void load(Common::SeekableReadStream *src);
+};
+
+extern void copy_mangle(CopyProt *copy_prot);
+extern int copy_load(CopyProt *copy_prot);
+extern int copy_pop_and_ask();
+extern int copy_verify();
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/dialog.cpp b/engines/mads/madsv2/core/dialog.cpp
index 2bc906fe60e..a5f7318b0fc 100644
--- a/engines/mads/madsv2/core/dialog.cpp
+++ b/engines/mads/madsv2/core/dialog.cpp
@@ -105,7 +105,7 @@ static int dialog_server_installed = false;
static dword dialog_old_24_server;
-int dialog_read_dir_to_list(ListPtr target, char *wild, int dirflag) {
+int dialog_read_dir_to_list(ListPtr target, const char *wild, int dirflag) {
warning("TODO: dialog_read_dir_to_list");
target->elements = 0;
return 0;
diff --git a/engines/mads/madsv2/core/error.h b/engines/mads/madsv2/core/error.h
index ddc67f65d36..fb14dcc166b 100644
--- a/engines/mads/madsv2/core/error.h
+++ b/engines/mads/madsv2/core/error.h
@@ -140,7 +140,7 @@ extern void error_report(int error, int severity, int module, long data1, long d
int error_scan(char *target, char *name, int number);
-extern void error_dump_file(char *file_name);
+extern void error_dump_file(const char *file_name);
/* error_2.cpp */
extern void error_break_point(int data1, int data2);
diff --git a/engines/mads/madsv2/core/fileio.cpp b/engines/mads/madsv2/core/fileio.cpp
index a8554f31b75..dc068afba2f 100644
--- a/engines/mads/madsv2/core/fileio.cpp
+++ b/engines/mads/madsv2/core/fileio.cpp
@@ -214,6 +214,10 @@ long fileio_get_file_size(const char *filename) {
return result;
}
+bool fileio_exist(const char *inp) {
+ return Common::File::exists(inp);
+}
+
char *fileio_get_filetype(char *outp, char *inp) {
Common::File fcb;
char test[20];
diff --git a/engines/mads/madsv2/core/fileio.h b/engines/mads/madsv2/core/fileio.h
index 0a775f4eb63..e5bc6cf3b54 100644
--- a/engines/mads/madsv2/core/fileio.h
+++ b/engines/mads/madsv2/core/fileio.h
@@ -32,52 +32,52 @@ namespace MADSV2 {
extern bool fileio_suppress_unbuffering;
-void fileio_purge_trailing_spaces(char *myline);
-void fileio_name_new_ext(char *bakfile, char *mainfile, const char *new_ext);
-char *fileio_ffgets(char *mystring, int num, Common::SeekableReadStream *stream);
-int fileio_ffputs(const char *mystring, Common::WriteStream *stream);
-char *fileio_fix_lf_input(char *mystring);
-void fileio_fix_lf_output(char *mystring);
-int fileio_copy(const char *source, const char *dest);
-long fileio_setpos(Common::Stream *handle, long pos);
-long fileio_fread_f(void *buffer, long size, long count, Common::SeekableReadStream *stream);
-long fileio_fwrite_f(const void *buffer, long size, long count, Common::WriteStream *stream);
-long fileio_file_to_file(Common::SeekableReadStream *from, Common::WriteStream *to, long count);
-long fileio_get_file_size(const char *filename);
-int fileio_exist(const char *inp);
+extern void fileio_purge_trailing_spaces(char *myline);
+extern void fileio_name_new_ext(char *bakfile, char *mainfile, const char *new_ext);
+extern char *fileio_ffgets(char *mystring, int num, Common::SeekableReadStream *stream);
+extern int fileio_ffputs(const char *mystring, Common::WriteStream *stream);
+extern char *fileio_fix_lf_input(char *mystring);
+extern void fileio_fix_lf_output(char *mystring);
+extern int fileio_copy(const char *source, const char *dest);
+extern long fileio_setpos(Common::Stream *handle, long pos);
+extern long fileio_fread_f(void *buffer, long size, long count, Common::SeekableReadStream *stream);
+extern long fileio_fwrite_f(const void *buffer, long size, long count, Common::WriteStream *stream);
+extern long fileio_file_to_file(Common::SeekableReadStream *from, Common::WriteStream *to, long count);
+extern long fileio_get_file_size(const char *filename);
+extern bool fileio_exist(const char *inp);
/**
* Returns the identifying portion of the file header in OUTP string
*/
-char *fileio_get_filetype(char *outp, char *inp);
+extern char *fileio_get_filetype(char *outp, char *inp);
/**
* Returns the DOS time/date stamp for a given file.
* @return Returns 0 if file is not found. Returned 32 bit number contains
* the date stamp in it's upper 16 bits, and the time stamp in it's lower.
*/
-long fileio_get_file_time(char *filename);
+extern long fileio_get_file_time(char *filename);
-char *fileio_read_header(char *target, Common::SeekableReadStream *handle);
-void fileio_write_header(char *text, Common::WriteStream *handle);
-char *fileio_get_line(char *target, Common::SeekableReadStream *handle);
-int fileio_put_line(char *source, Common::WriteStream *handle);
-long fileio_get_disk_free(char drive);
-void fileio_add_ext(char *name, const char *ext);
-void fileio_new_ext(char *target, const char *name, const char *ext);
-int fileio_logpath(const char *path);
-char *fileio_parse_filename(char *target, char *filepath);
-char *fileio_parse_path(char *target, const char *filepath);
-char *fileio_swap_path(char *target, const char *base, const char *file);
-char *fileio_join_path(char *target, const char *path, const char *file);
-void fileio_get_volume_label(char *volume_label, char drive_letter);
-int fileio_set_file_time(char *filename, long new_time);
-int fileio_get_file_attributes(const char *filename, word *attributes);
-int fileio_set_file_attributes(const char *filename, word attributes);
-int fileio_read_till_null(char *target, Common::Stream *handle);
-char *fileio_prepend(char *target, const char *source, const char *prepend);
-char *fileio_chop_ext(char *target, const char *source);
-void fileio_purge_all_spaces(char *text);
+extern char *fileio_read_header(char *target, Common::SeekableReadStream *handle);
+extern void fileio_write_header(char *text, Common::WriteStream *handle);
+extern char *fileio_get_line(char *target, Common::SeekableReadStream *handle);
+extern int fileio_put_line(char *source, Common::WriteStream *handle);
+extern long fileio_get_disk_free(char drive);
+extern void fileio_add_ext(char *name, const char *ext);
+extern void fileio_new_ext(char *target, const char *name, const char *ext);
+extern int fileio_logpath(const char *path);
+extern char *fileio_parse_filename(char *target, char *filepath);
+extern char *fileio_parse_path(char *target, const char *filepath);
+extern char *fileio_swap_path(char *target, const char *base, const char *file);
+extern char *fileio_join_path(char *target, const char *path, const char *file);
+extern void fileio_get_volume_label(char *volume_label, char drive_letter);
+extern int fileio_set_file_time(char *filename, long new_time);
+extern int fileio_get_file_attributes(const char *filename, word *attributes);
+extern int fileio_set_file_attributes(const char *filename, word attributes);
+extern int fileio_read_till_null(char *target, Common::Stream *handle);
+extern char *fileio_prepend(char *target, const char *source, const char *prepend);
+extern char *fileio_chop_ext(char *target, const char *source);
+extern void fileio_purge_all_spaces(char *text);
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/core/font.h b/engines/mads/madsv2/core/font.h
index 8f9dae6a46a..402ab9ce41b 100644
--- a/engines/mads/madsv2/core/font.h
+++ b/engines/mads/madsv2/core/font.h
@@ -22,7 +22,7 @@
#ifndef MADS_CORE_FONT_H
#define MADS_CORE_FONT_H
-#include "common/scummsys.h"
+#include "mads/madsv2/core/buffer.h"
namespace MADS {
namespace MADSV2 {
diff --git a/engines/mads/madsv2/core/game.cpp b/engines/mads/madsv2/core/game.cpp
new file mode 100644
index 00000000000..bac956c1484
--- /dev/null
+++ b/engines/mads/madsv2/core/game.cpp
@@ -0,0 +1,3352 @@
+/* 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 "mads/madsv2/engine.h"
+#include "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/mads.h"
+#include "mads/madsv2/core/attr.h"
+#include "mads/madsv2/core/lib.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/keys.h"
+#include "mads/madsv2/core/inter.h"
+#include "mads/madsv2/core/matte.h"
+#include "mads/madsv2/core/mouse.h"
+#include "mads/madsv2/core/timer.h"
+#include "mads/madsv2/core/video.h"
+#include "mads/madsv2/core/buffer.h"
+#include "mads/madsv2/core/mem.h"
+#include "mads/madsv2/core/pal.h"
+#include "mads/madsv2/core/mcga.h"
+#include "mads/madsv2/core/echo.h"
+#include "mads/madsv2/core/env.h"
+#include "mads/madsv2/core/player.h"
+#include "mads/madsv2/core/cycle.h"
+#include "mads/madsv2/core/ems.h"
+#include "mads/madsv2/core/xms.h"
+#include "mads/madsv2/core/loader.h"
+#include "mads/madsv2/core/anim.h"
+#include "mads/madsv2/core/error.h"
+#include "mads/madsv2/core/popup.h"
+#include "mads/madsv2/core/object.h"
+#include "mads/madsv2/core/demo.h"
+#include "mads/madsv2/core/himem.h"
+#include "mads/madsv2/core/lock.h"
+#include "mads/madsv2/core/magic.h"
+#include "mads/madsv2/core/btype.h"
+#include "mads/madsv2/core/pack.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/config.h"
+#include "mads/madsv2/core/fileio.h"
+#include "mads/madsv2/core/digi.h"
+#include "mads/madsv2/core/midi.h"
+#include "mads/madsv2/core/copy.h"
+#include "mads/madsv2/core/camera.h"
+#include "mads/madsv2/core/quote.h"
+#include "mads/madsv2/core/text.h"
+#include "mads/madsv2/core/extra.h"
+#include "mads/madsv2/core/imath.h"
+#include "mads/madsv2/core/screen.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+extern long mem_used;
+extern long mem_avail_at_start;
+extern int digi_trigger_dialog;
+extern int digi_trigger_ambiance;
+extern int digi_trigger_effect;
+extern int room_state[40];
+
+
+#define MOVE_YOUR_BUTT_TIMEOUT 3600
+#define MAX_SPEECH_FILES_PER_ROOM 100
+
+Buffer scr_live = { video_y, video_x, mcga_video };
+char config_file_name[20];
+int win_status = WIN_NOTHING;
+
+int art_hags_are_on_hd;
+byte game_restore_flag = false; /* Flag if restoring game */
+byte game_autosaved = false; /* Flag if autosaved */
+byte game_mouse_cursor_fix = false; /* Use special cursor fix */
+word abort_value = 0;
+long abort_clock;
+char chain_line[80];
+int chain_flag = false;
+int force_chain = false;
+int key_abort_level = 0;
+int report_version = false;
+
+void (*game_menu_routine)() = NULL; /* Game Menu routines */
+void (*game_menu_init)() = NULL;
+void (*game_menu_exit)() = NULL;
+void (*game_emergency_save)() = NULL;
+
+int debugger = false;
+int debugger_state = DEBUGGER_MAIN;
+int debugger_matte_before = false;
+int debugger_memory_skip = 0; /* For paging up/down */
+int debugger_memory_all = false; /* Not showing ALL memory */
+int debugger_memory_keywait = false; /* Not waiting for memory */
+void (*debugger_reset)() = NULL; /* Debugger reset routine */
+void (*debugger_update)() = NULL; /* Debugger update routine */
+int selected_intro = false;
+long correction_clock;
+
+char save_game_key[8];
+char restart_game_key[40];
+char save_game_buf[20];
+
+int last_keypressed = -1;
+
+/* section specific overlays */
+void (*section_preload_code_pointer)() = NULL;
+void (*section_init_code_pointer)() = NULL;
+void (*section_room_constructor)() = NULL;
+void (*section_daemon_code_pointer)() = NULL;
+void (*section_pre_parser_code_pointer)() = NULL;
+void (*section_parser_code_pointer)() = NULL;
+void (*section_error_code_pointer)() = NULL;
+void (*section_music_reset_pointer)() = NULL;
+
+/* room specific overlays */
+void (*room_preload_code_pointer)() = NULL;
+void (*room_init_code_pointer)() = NULL;
+void (*room_daemon_code_pointer)() = NULL;
+void (*room_pre_parser_code_pointer)() = NULL;
+void (*room_parser_code_pointer)() = NULL;
+void (*room_error_code_pointer)() = NULL;
+void (*room_shutdown_code_pointer)() = NULL;
+
+int game_any_emergency = false;
+
+struct Heres_A {
+ char speech_file[13];
+ long size;
+};
+
+int game_keystroke;
+int game_any_keystroke;
+
+int lets_get_a_move_on_anim = true;
+
+long noise_clock;
+long noise_timer;
+long noise_length = -1;
+
+byte move_your_butt_enabled = 1;
+long move_your_butt_clock;
+long move_your_butt_timer;
+int move_your_butt_anim_handle = -1;
+int move_your_butt_anim_frame = -1;
+
+byte last_bird_sound = (byte)-1;
+
+char game_save_file[13] = "SAVES.DIR"; /* Save directory file */
+char *game_save_directory; /* Save directory pointer */
+
+int game_preserve_handle; /* scr_depth preserve */
+
+Heap game_menu_heap; /* Custom heap for menu */
+Popup *game_menu_popup; /* Popup structure for menu */
+
+int debugger_previous = DEBUGGER_NONE;
+int debugger_watch = 0;
+int debugger_watch_index[DEBUGGER_MAX_WATCH];
+
+
+static void game_cold_data_init() {
+ game.going = true;
+
+ kernel.fx = 0;
+ kernel.video_mode = mcga_mode;
+ kernel.translating = false;
+ kernel.sound_card = 'R';
+ kernel.force_restart = false;
+
+ kernel.cheating = (byte)kernel_cheating_forbidden;
+
+ kernel.cursor_x[0] = video_x >> 1;
+ kernel.cursor_x[1] = 8;
+ kernel.cursor_y[0] = display_y >> 1;
+ kernel.cursor_y[1] = inter_base_y + 5;
+
+ game.difficulty = -1;
+
+ kernel.paused = false;
+ kernel.cause_pause = false;
+ kernel.frame_by_frame = false;
+
+ kernel.mouse_cursor_point = false;
+ kernel.memory_tracking = false;
+
+ kernel.teleported_in = false;
+ kernel.disable_fastwalk = false;
+
+ game.last_save = -1;
+
+ Common::strcpy_s(kernel.interface, "*I0.AA");
+
+ magic_low_fade_bound = 21;
+ magic_high_fade_bound = 251;
+}
+
+
+static int scan_past(char **myscan, char scan) {
+ int found = false;
+
+ while (**myscan && (**myscan != scan)) (*myscan)++;
+ if ((scan) && (**myscan == scan)) {
+ (*myscan)++;
+ found = true;
+ }
+ if (!**myscan) {
+ (*myscan)--;
+ }
+
+ return found;
+}
+
+
+
+/*
+/* flag_parse()
+/*
+/* Routine to parse command line flags.
+*/
+static void flag_parse(char **myscan) {
+ long mem_max;
+ /* long mem_avail; */
+
+
+ if (kernel.cheating == (byte)kernel_cheating_forbidden) {
+ if (scumm_stricmp(*myscan, kernel_cheating_password) == 0) {
+ kernel.cheating = (byte)kernel_cheating_allowed;
+ scan_past(myscan, 0);
+ goto done;
+ }
+ }
+
+ switch (toupper((int)**myscan)) {
+ case 'A':
+ if (scan_past(myscan, ':')) {
+ chain_flag = true;
+ Common::strcpy_s(chain_line, *myscan);
+ scan_past(myscan, 0);
+ }
+ break;
+
+ /*
+ case 'A':
+ if (scan_past(myscan, ':')) {
+ abort_value = atoi(*myscan);
+ scan_past(myscan, 0);
+ }
+ break;
+ */
+
+ case 'C':
+ if (scan_past(myscan, ':')) {
+ kernel.sound_card = **myscan;
+ if (scan_past(myscan, ',')) {
+ /* pl sound_board_address = xtoi(*myscan); */
+ if (scan_past(myscan, ',')) {
+ /* pl sound_board_type = xtoi(*myscan); */
+ scan_past(myscan, 0);
+ }
+ }
+ }
+ break;
+
+ case 'D':
+ if (scan_past(myscan, ':')) {
+ game.difficulty = (byte)atoi(*myscan);
+ scan_past(myscan, 0);
+ }
+ break;
+
+ case 'F':
+ if (kernel.cheating) {
+ kernel.frame_by_frame = true;
+ }
+ break;
+
+ case 'H':
+ if (scan_past(myscan, ':')) {
+ while (**myscan) {
+ switch (toupper(**myscan)) {
+ case 'E':
+ himem_preload_ems_disabled = true;
+ break;
+ case 'X':
+ himem_preload_xms_disabled = true;
+ break;
+ case 'U':
+ xms_disabled = true;
+ break;
+ }
+ (*myscan)++;
+ }
+ scan_past(myscan, 0);
+ } else {
+ himem_preload_ems_disabled = true;
+ himem_preload_xms_disabled = true;
+ }
+ break;
+
+ case 'I':
+ selected_intro = true;
+ break;
+
+ case 'K':
+ inter_report_hotspots = true;
+ /* config_file.interface_hotspots = INTERFACE_BRAINDEAD; */
+ /* inter_report_hotspots = !inter_report_hotspots; */
+ break;
+
+ case 'L':
+#ifdef debug_enable_logfiles
+ logfile_enabled = true;
+#endif
+ break;
+
+ case 'M':
+ if (scan_past(myscan, ':')) {
+ mem_max = atol(*myscan);
+ mem_get_name(mem_max, "$HIDE$");
+ /*
+ mem_avail = mem_get_avail() - mem_program_block();
+ if (mem_avail > mem_max) {
+ mem_get_name(mem_avail - mem_max, "$HIDE$");
+ }
+ */
+ scan_past(myscan, 0);
+ }
+ break;
+
+ case 'O':
+ /* config_file.inventory_mode = INVENTORY_SQUAT; */
+ /* inter_spinning_objects = false; */
+ break;
+
+ case 'P':
+ env_search_mode = ENV_SEARCH_CONCAT_FILES;
+ break;
+
+ case 'R':
+ if (scan_past(myscan, ':')) {
+ game_save_name(atoi(*myscan));
+ scan_past(myscan, 0);
+ game_restore_flag = 1;
+ }
+ break;
+
+ case 'S':
+ game_restore_flag = 2;
+ break;
+
+ case 'T':
+ if (kernel.cheating) {
+ if (scan_past(myscan, ':')) {
+ kernel.teleported_in = true;
+ new_room = atoi(*myscan);
+ new_section = new_room / 100;
+ if (scan_past(myscan, ',')) {
+ room_id = atoi(*myscan);
+ section_id = room_id / 100;
+ if (scan_past(myscan, ',')) {
+ player.target_facing = atoi(*myscan);
+ scan_past(myscan, 0);
+ }
+ }
+ }
+ }
+ break;
+
+ case 'U':
+ game_mouse_cursor_fix = true;
+ break;
+
+ case 'V':
+ report_version = true;
+ break;
+
+ case 'Y':
+ /* *lock_hash_value = 0; */
+ break;
+
+ case 'Z':
+ if (kernel.cheating) {
+ debugger = true;
+ if (scan_past(myscan, ':')) {
+ debugger_state = atoi(*myscan);
+ if (debugger_state == DEBUGGER_MATTE) {
+ debugger_matte_before = true;
+ }
+ if (debugger_state == DEBUGGER_MEMORY) {
+ game_exec_function(debugger_reset);
+ mem_manager_update = debugger_update;
+ }
+ if (debugger_state == DEBUGGER_PALETTE) {
+ game_exec_function(debugger_reset);
+ pal_manager_update = debugger_update;
+ }
+ if (scan_past(myscan, ':')) {
+ while (**myscan) {
+ switch (toupper((int)**myscan)) {
+ case 'A':
+ debugger_memory_all = true;
+ break;
+ case 'K':
+ debugger_memory_keywait = true;
+ break;
+ }
+ (*myscan)++;
+ }
+ }
+ scan_past(myscan, 0);
+ }
+ }
+ break;
+
+ }
+
+done:
+ ;
+}
+
+
+
+static void show_version() {
+ echo(" ", true);
+ echo(global_release_name, true);
+ echo(" Release Version ", false);
+ echo(global_release_version, false);
+ echo(" -- ", false);
+ echo(global_release_date, true);
+ echo(" MADS Library Version ", false);
+ echo(mads_dev_lib_version, false);
+ echo(" -- ", false);
+ echo(mads_dev_lib_date, true);
+ echo(" Copyright (c) ", false);
+ echo(global_release_copyright, false);
+ echo(" by Sanctuary Woods Multimedia Corp.", true);
+ echo(" ", true);
+ /* echo (" FOR INTERNAL USE ONLY", true); */
+ /* echo (" ", true); */
+}
+
+
+static void show_logo() {
+ show_version();
+}
+
+
+void problem() {
+ debug("\nA slight problem . . .\n\n");
+}
+
+static void show_walk() {
+ int y, x;
+ int xx, yy;
+ int ox, oy;
+ byte *scan;
+ int walk;
+
+ for (y = 0; y < display_y; y++) {
+ ox = picture_map.pan_base_x;
+ oy = y + picture_map.pan_base_y;
+ scan = buffer_pointer(&scr_orig, ox, oy);
+ for (x = 0; x < video_x; x++) {
+ xx = x + picture_view_x;
+ yy = y + picture_view_y;
+ walk = attr_walk(&scr_walk, xx, yy);
+
+ if (walk) {
+ *scan = 2;
+ } else if (*scan == 2) {
+ *scan = 0;
+ }
+
+ scan++;
+ }
+ }
+
+ matte_refresh_work();
+}
+
+
+static void game_fix_save_name() {
+ char *mark;
+
+ mads_strupr(save_game_buf);
+
+ mark = strchr(save_game_buf, '.');
+ if (mark != NULL) *mark = 0;
+ Common::strcat_s(save_game_buf, ".SAV");
+}
+
+
+void game_save_name(int id) {
+ Common::strcpy_s(save_game_buf, save_game_key);
+ env_catint(save_game_buf, id, 3);
+ game_fix_save_name();
+}
+
+
+
+
+static void game_player_status() {
+ int image, flags, count;
+ char work_buf[80];
+ char temp_buf_3[80];
+
+ image = -1;
+ flags = -9;
+ for (count = 0; count < (int)image_marker; count++) {
+ if (image_list[count].segment_id == KERNEL_SEGMENT_PLAYER) {
+ if (image_list[count].flags >= flags) {
+ image = count;
+ flags = image_list[count].flags;
+ }
+ }
+ }
+ Common::strcpy_s(temp_buf_3, "Room: ");
+ Common::strcat_s(temp_buf_3, mads_itoa(room_id, work_buf, 10));
+ Common::strcat_s(temp_buf_3, " (From: ");
+ Common::strcat_s(temp_buf_3, mads_itoa(previous_room, work_buf, 10));
+ Common::strcat_s(temp_buf_3, ")");
+
+ popup_alert(20, "PLAYER GRAPHICS STATUS",
+ " ",
+ temp_buf_3,
+ /* temp_buf, */
+ /* temp_buf_2, */
+ /* temp_buf_4, */
+ /* temp_buf_5, */
+ NULL);
+}
+
+
+
+int game_parse_keystroke(int mykey) {
+ int count;
+ int temp;
+ int move_object;
+ int move_target;
+ int change_flag;
+ int current_mode;
+ int num;
+ int unpause = 0;
+ int x = 0, y = 0;
+ char temp_buf[80], temp_buf_2[80];
+
+ if (kernel.cheating == (byte)kernel_cheating_allowed) {
+
+ mykey = main_cheating_key(mykey);
+
+ switch (mykey) {
+ case ctrl_a_key:
+ kernel.memory_tracking = (byte)(!kernel.memory_tracking);
+ break;
+
+ case ctrl_b_key:
+ kernel.player_tracking = (byte)(!kernel.player_tracking);
+ break;
+
+ case ctrl_d_key:
+ /* temp = game.difficulty; */
+ /* if (!popup_get_number (&temp, "CHANGE DIFFICULTY FACTOR", "New Factor:", 3)) { */
+ /* game.difficulty = (byte)temp; */
+ /* } */
+ break;
+
+ case ctrl_e_key:
+ mcga_shakes = 350;
+ break;
+
+ case ctrl_f_key:
+ kernel.frame_by_frame = (byte)!(int)kernel.frame_by_frame;
+ kernel.paused = false;
+ break;
+
+ case ctrl_g_key:
+ change_flag = 0;
+ if (!popup_get_number(&change_flag, "CHANGE GLOBAL", "Flag #:", 3)) {
+ if (change_flag >= 0) {
+ Common::strcpy_s(temp_buf, "GLOBAL #");
+ mads_itoa(change_flag, temp_buf_2, 10);
+ Common::strcat_s(temp_buf, temp_buf_2);
+ popup_get_number(&global[change_flag], temp_buf, "Value:", 5);
+ }
+ }
+ break;
+
+ case ctrl_j_key:
+ kernel.cheating = 0;
+ popup_alert(22, "Cheating disabled.", NULL);
+ break;
+
+ case ctrl_l_key:
+ /* move_object = 0; */
+ /* if (!popup_get_number(&move_object, "Examine Object", "Object #:", 3)) { */
+ /* big_temp = move_object + 800; */
+ /* if (!popup_get_long(&big_temp, "Object Message", "Message #:", 5)) { */
+ /* object_examine (move_object, big_temp, 0); */
+ /* } */
+ /* } */
+ break;
+
+ case ctrl_n_key:
+ /* temp = 0; */
+ /* if (!popup_get_number(&temp, "Activate Conversation", "Conv #:", 3)) { */
+ /* pl conv_flush();
+ conv_get(temp);
+ conv_run(temp);
+ */
+ /* } */
+ break;
+
+ case ctrl_o_key:
+ move_object = -1;
+ if (active_inven >= 0) move_object = inven[active_inven];
+ if (!popup_get_number(&move_object, "MOVE OBJ", "Obj #:", 3)) {
+ if (move_object >= 0) {
+ move_target = object[move_object].location;
+ popup_get_number(&move_target, "MOVE OBJ TO", "Loc:", 3);
+ inter_move_object(move_object, move_target);
+ /* kernel.force_restart = true; */
+ }
+ }
+ break;
+
+ case ctrl_p_key:
+ game_player_status();
+ break;
+
+ case ctrl_r_key:
+ kernel_panning_speed = (kernel_panning_speed + 1) % 3;
+ game_set_camera_speed();
+ switch (kernel_panning_speed) {
+ case PANNING_INSTANT:
+ /* popup_alert (22, "Pan INS", NULL); */
+ break;
+
+ case PANNING_MEDIUM:
+ /* popup_alert (22, "Pan MEDIUM.", NULL); */
+ break;
+
+ case PANNING_SMOOTH:
+ default:
+ /* popup_alert (22, "Panning = SMOOTH.", NULL); */
+ break;
+ }
+ break;
+
+ /*
+ case ctrl_r_key:
+ box_param.font_spacing = 1 - box_param.font_spacing;
+ break;
+ */
+
+ case ctrl_t_key:
+ popup_get_number(&new_room, "TELEPORT", "New Room:", 3);
+ kernel.teleported_in = (byte)(mykey == ctrl_t_key);
+ break;
+
+ case ctrl_u_key:
+ player.turn_to_facing = player_clockwise[player.turn_to_facing];
+ break;
+
+ case bksp_key:
+ temp = false;
+ for (count = KERNEL_MAX_ANIMATIONS - 1; (!temp) && (count >= 0); count--) {
+ if (kernel_anim[count].anim != NULL) {
+ temp = true;
+ kernel_anim[count].frame = kernel_anim[count].anim->num_frames - 1;
+ }
+ }
+ break;
+
+ case ctrl_w_key:
+ /* popup_get_string (player.series_name, "WALKER SERIES", "Series:", 8); */
+ /* player.force_series = (byte)strlen(player.series_name); */
+ /* if (!scumm_stricmp(player.series_name, "NULL")) player.series_name[0] = 0; */
+ /* kernel.force_restart = true; */
+ break;
+
+ case ctrl_z_key:
+ kernel.force_restart = true;
+ break;
+
+ case alt_b_key:
+ /* if (!popup_get_string (box_param.name, "POPUP BOX SERIES", "Series:", 16)) { */
+ /* kernel.force_restart = true; */
+ /* } */
+ break;
+
+ case ctrl_y_key:
+ break;
+
+ case alt_i_key:
+ player.y--;
+ break;
+
+ case f10_key:
+ break;
+
+ case alt_d_key:
+ mem_manager_update = NULL;
+ pal_manager_update = NULL;
+ if (debugger && (debugger_state != DEBUGGER_MAIN)) {
+ debugger_state = DEBUGGER_MAIN;
+ } else {
+ debugger = !debugger;
+ }
+ game_exec_function(debugger_reset);
+ break;
+
+ case alt_h_key:
+ debugger = true;
+ debugger_state = DEBUGGER_HELP;
+ mem_manager_update = NULL;
+ pal_manager_update = NULL;
+ break;
+
+ case alt_p_key:
+ debugger = true;
+ debugger_state = DEBUGGER_PALETTE;
+ mem_manager_update = NULL;
+ pal_manager_update = debugger_update;
+ break;
+
+ case alt_t_key:
+ debugger = true;
+ debugger_state = DEBUGGER_STATE;
+ mem_manager_update = NULL;
+ pal_manager_update = debugger_update;
+ break;
+
+ case alt_l_key:
+ debugger = true;
+ debugger_state = DEBUGGER_SCRATCH;
+ mem_manager_update = NULL;
+ pal_manager_update = NULL;
+ break;
+
+ case alt_g_key:
+ debugger = true;
+ debugger_state = DEBUGGER_GLOBAL;
+ mem_manager_update = NULL;
+ pal_manager_update = NULL;
+ break;
+
+ case alt_n_key:
+ debugger = true;
+ debugger_state = DEBUGGER_CONVERSATION;
+ mem_manager_update = NULL;
+ pal_manager_update = NULL;
+ break;
+
+ case alt_o_key:
+ debugger = true;
+ debugger_state = DEBUGGER_MEMORY;
+ mem_manager_update = debugger_update;
+ pal_manager_update = NULL;
+ break;
+
+ case alt_y_key:
+ if (!debugger || (debugger_state != DEBUGGER_MATTE)) {
+ debugger_matte_before = false;
+ } else {
+ debugger_matte_before = !debugger_matte_before;
+ }
+ debugger = true;
+ debugger_state = DEBUGGER_MATTE;
+ mem_manager_update = debugger_update;
+ pal_manager_update = NULL;
+ break;
+
+ case alt_f_key:
+ game_exec_function(debugger_reset);
+ break;
+
+ case alt_a_key:
+ /* if (debugger_watch < DEBUGGER_MAX_WATCH) {
+ temp = -1;
+ if (debugger_watch > 0) temp = debugger_watch_index[debugger_watch - 1];
+ if (!popup_get_number (&temp, "ADD GLOBAL WATCH", "Variable #:", 3)) {
+ if ((temp >= 0) && (temp < 500)) {
+ for (count = 0; count < debugger_watch; count++) {
+ if (debugger_watch_index[count] == temp) {
+ temp = -1;
+ }
+ }
+
+ if (temp > 0) {
+ debugger_watch_index[debugger_watch++] = temp;
+ }
+ }
+ }
+ } */
+ break;
+
+ case alt_e_key:
+ if (debugger_watch) debugger_watch--;
+ debugger_previous = DEBUGGER_NONE;
+ break;
+
+ case '{':
+ if (debugger_memory_skip > 0) debugger_memory_skip--;
+ break;
+
+ case '}':
+ if (debugger_memory_skip < 10) debugger_memory_skip++;
+ break;
+
+ case '\\':
+ debugger_memory_all = !debugger_memory_all;
+ break;
+
+ case '?':
+ debugger_memory_keywait = !debugger_memory_keywait;
+ break;
+
+ case 'r':
+ case 'R':
+ if (section_id != 9) {
+ keys_remove();
+ popup_alert(22, "Key int NO.", NULL);
+ }
+ break;
+
+ case ins_key:
+ keys_install();
+ popup_alert(22, "Keyb int YES.", NULL);
+ break;
+
+ case alt_m_key:
+ player.y++;
+ break;
+
+ case alt_k_key:
+ player.x++;
+ break;
+
+ case alt_j_key:
+ player.x--;
+ break;
+
+
+ case alt_c_key:
+ player.commands_allowed = !player.commands_allowed;
+ break;
+
+ case alt_w_key:
+ /* player.walk_freedom = !player.walk_freedom; */
+ /* player.walk_anywhere = player.walk_freedom; */
+ /* if (player.walk_freedom) { */
+ /* popup_alert (26, "Player walks anywhere.", NULL); */
+ /* } else { */
+ /* popup_alert (26, "Player walk restricted.", NULL); */
+ /* } */
+ break;
+
+ case alt_v_key:
+ player.walker_visible = !player.walker_visible;
+ break;
+
+ case alt_z_key:
+ player.x = mouse_x + picture_view_x;
+ player.y = MIN(mouse_y, display_y) + picture_view_y;
+ break;
+
+
+ case '[':
+ camera_jump_to(MAX(0, picture_view_x - 10), picture_view_y);
+ break;
+
+ case ']':
+ camera_jump_to(MIN(picture_view_x + 10, picture_map.total_x_size - video_x), picture_view_y);
+ break;
+
+ case '=':
+ camera_jump_to(picture_view_x, MAX(0, picture_view_y - 10));
+ break;
+
+ case '\'':
+ camera_jump_to(picture_view_x, MIN(picture_view_y + 10, picture_map.total_y_size - display_y));
+ break;
+
+
+ case ctrl_c_key:
+ kernel.mouse_cursor_point = (byte)(!kernel.mouse_cursor_point);
+ break;
+
+ case ctrl_s_key:
+ Common::strcpy_s(temp_buf, "d322u001");
+
+ if (!popup_get_string(temp_buf, "Speech Play", "File:", 14)) {
+ Common::strcpy_s(temp_buf_2, "*");
+ Common::strcat_s(temp_buf_2, temp_buf);
+ Common::strcat_s(temp_buf_2, ".rac");
+
+ /* if exist RAC file */
+ if (env_exist(temp_buf_2)) {
+ digi_play(temp_buf, 1);
+ digi_trigger_dialog = false;
+
+ } else {
+ Common::strcpy_s(temp_buf_2, "*");
+ Common::strcat_s(temp_buf_2, temp_buf);
+ Common::strcat_s(temp_buf_2, ".raw");
+
+ /* if exist RAW */
+ if (env_exist(temp_buf_2)) {
+ digi_play(temp_buf, 1);
+ digi_trigger_dialog = false;
+
+ } else {
+ popup_alert(22, temp_buf, "does not exist!", NULL);
+ }
+ }
+ }
+ break;
+
+ case alt_f1_key:
+ if (room->front_y > room->back_y) room->front_y--;
+ kernel_room_bound_dif = room->front_y - room->back_y;
+ break;
+
+ case alt_f2_key:
+ room->front_y++;
+ kernel_room_bound_dif = room->front_y - room->back_y;
+ break;
+
+ case alt_f3_key:
+ if (room->front_scale > room->back_scale) room->front_scale--;
+ kernel_room_scale_dif = room->front_scale - room->back_scale;
+ break;
+
+ case alt_f4_key:
+ room->front_scale++;
+ kernel_room_scale_dif = room->front_scale - room->back_scale;
+ break;
+
+
+ case alt_f5_key:
+ room->back_y--;
+ kernel_room_bound_dif = room->front_y - room->back_y;
+ break;
+
+ case alt_f6_key:
+ if (room->back_y < room->front_y) room->back_y++;
+ kernel_room_bound_dif = room->front_y - room->back_y;
+ break;
+
+ case alt_f7_key:
+ room->back_scale--;
+ kernel_room_scale_dif = room->front_scale - room->back_scale;
+ break;
+
+ case alt_f8_key:
+ if (room->back_scale < room->front_scale) room->back_scale++;
+ kernel_room_scale_dif = room->front_scale - room->back_scale;
+ break;
+
+
+ case 'I':
+ case 'i':
+ num = (mykey == 'i') ? 1 : 5;
+ /* pl y = conv_control.y[conv_control.person_speaking]; */
+ if (y & POPUP_CENTER) y = 0;
+ y = MAX(y - num, 0);
+ /* pl conv_control.y[conv_control.person_speaking] = y; */
+ /* pl conv_regenerate_last_message(); */
+ break;
+
+ case 'M':
+ case 'm':
+ num = (mykey == 'm') ? 1 : 5;
+ /* pl conv_control.y[conv_control.person_speaking] += num; */
+ /* pl conv_regenerate_last_message(); */
+ break;
+
+ case 'J':
+ case 'j':
+ num = (mykey == 'j') ? 1 : 5;
+ /* pl x = conv_control.x[conv_control.person_speaking]; */
+ if (x & POPUP_CENTER) x = 0;
+ x = MAX(x - num, 0);
+ /* pl conv_control.x[conv_control.person_speaking] = x; */
+ /* pl conv_regenerate_last_message(); */
+ break;
+
+ case 'K':
+ case 'k':
+ num = (mykey == 'k') ? 1 : 5;
+ /* pl conv_control.x[conv_control.person_speaking] += num; */
+ /* pl conv_regenerate_last_message(); */
+ break;
+
+ case ',':
+ case '<':
+ num = (mykey == ',') ? 1 : 5;
+ /* pl x = conv_control.width[conv_control.person_speaking]; */
+ x = MAX(x - num, 10);
+ /* pl conv_control.width[conv_control.person_speaking] = x; */
+ /* pl conv_regenerate_last_message(); */
+ break;
+
+ case '.':
+ case '>':
+ num = (mykey == '.') ? 1 : 5;
+ /* pl x = conv_control.width[conv_control.person_speaking]; */
+ x = MIN(x + num, 35);
+ /* pl conv_control.width[conv_control.person_speaking] = x; */
+ /* pl conv_regenerate_last_message(); */
+ break;
+
+ case 0:
+ break;
+
+ default:
+ unpause++;
+ break;
+ }
+ }
+
+
+ if (kernel.cheating < (byte)kernel_cheating_allowed) {
+ if (mykey == (kernel_cheating_password[kernel.cheating] - '@')) {
+ kernel.cheating++;
+ mykey = 0;
+ if (kernel.cheating >= (byte)kernel_cheating_allowed) {
+ popup_alert(22, "CHEATING ENABLED", NULL);
+ }
+ } else {
+ kernel.cheating = 0;
+ }
+ }
+
+ mykey = main_normal_key(mykey);
+
+ switch (mykey) {
+ case space_key:
+ global[3] = true; /* player_hyperwalked */
+ if (!kernel.paused) {
+ if (player.walking && (new_room == room_id) && (player.walk_off_edge == 0)) {
+ if (!kernel.disable_fastwalk || (kernel.cheating == (byte)kernel_cheating_allowed)) {
+ if (buffer_legal(scr_walk, room->xs,
+ player.x, player.y,
+ player.target_x, player.target_y) == LEGAL) {
+ player.x = player.target_x;
+ player.y = player.target_y;
+ }
+ }
+ }
+ } else {
+ kernel.paused = false;
+ }
+ break;
+
+ case esc_key:
+ case f1_key:
+ if (room_id != 199 && section_id != 9) {
+ if (kernel.activate_menu) {
+ kernel.activate_menu = 0;
+ } else {
+ kernel.activate_menu = GAME_MAIN_MENU;
+ kernel.paused = false;
+ }
+ }
+ break;
+
+ case f2_key:
+ case alt_s_key:
+ if (room_id != 199 && section_id != 9) {
+ kernel.activate_menu = GAME_SAVE_MENU;
+ }
+ break;
+
+ case f3_key:
+ case alt_r_key:
+ if (room_id != 199) {
+ kernel.activate_menu = GAME_RESTORE_MENU;
+ }
+ break;
+
+ case f4_key:
+ /* kernel.activate_menu = GAME_SCORE_MENU; */
+ break;
+
+ case f5_key:
+ if (room_id != 199 && section_id != 9) {
+ kernel.activate_menu = GAME_OPTIONS_MENU;
+ }
+ break;
+
+ case f6_key:
+ if (room_id != 199 && section_id != 9) {
+ kernel.activate_menu = GAME_CD_MENU;
+ }
+ break;
+
+ case alt_q_key:
+ case alt_x_key:
+ case ctrl_q_key:
+ if (room_id != 199) {
+ game.going = false;
+ kernel.paused = false;
+ key_abort_level = 2;
+ }
+ break;
+
+ case tab_key:
+ current_mode = (mouse_y > display_y) ? 1 : 0;
+ kernel.cursor_x[current_mode] = mouse_x;
+ kernel.cursor_y[current_mode] = mouse_y;
+ mouse_force(kernel.cursor_x[1 - current_mode], kernel.cursor_y[1 - current_mode]);
+ break;
+
+ case ctrl_k_key:
+ inter_report_hotspots = !inter_report_hotspots;
+ /* config_file.interface_hotspots = inter_report_hotspots ? INTERFACE_BRAINDEAD : INTERFACE_MACINTOSH; */
+ inter_init_sentence();
+ break;
+
+ case ctrl_v_key:
+ Common::strcpy_s(temp_buf, "Ver: ");
+ Common::strcat_s(temp_buf, global_release_version);
+ Common::strcat_s(temp_buf, " ");
+ Common::strcat_s(temp_buf, global_release_date);
+
+ Common::strcpy_s(temp_buf_2, "Lib ver: ");
+ Common::strcat_s(temp_buf_2, mads_dev_lib_version);
+ Common::strcat_s(temp_buf_2, " ");
+ Common::strcat_s(temp_buf_2, mads_dev_lib_date);
+
+ popup_alert(28, "GAME RELEASE VER INFO",
+ " ",
+ temp_buf,
+ temp_buf_2,
+ NULL);
+ break;
+
+ /* case I_key: */
+ /* case B_key: */
+ /* case i_key: */
+ /* case b_key: */
+ /* if (room_id != 199 && section_id != 9 && */
+ /* player.commands_allowed && */
+ /* !kernel.trigger && */
+ /* inter_input_mode == INTER_LIMITED_SENTENCES && */
+ /* !global[2]) {*/ /* inventory_is_displayed */
+ /* display_inventory(); */
+ /* } */
+ /* break; */
+
+ case 0:
+ break;
+
+ default:
+ unpause++;
+ break;
+ }
+
+ if (mykey >= 0) last_keypressed = mykey;
+
+ if (unpause >= 2) {
+ kernel.paused = false;
+ }
+
+ return (unpause >= 2);
+}
+
+
+
+void game_pause_mode() {
+ int mykey = -1;
+ long clock_save;
+ long clock_now;
+
+ clock_save = timer_read();
+
+ kernel.paused = true;
+
+ while (kernel.paused) {
+ while (!keys_any() && !keys_special_button);
+ while (keys_any()) {
+ mykey = keys_get();
+ game_parse_keystroke(mykey);
+ }
+ if (keys_special_button) kernel.paused = false;
+ }
+
+ kernel.cause_pause = false;
+
+ clock_now = timer_read();
+ if (clock_now - clock_save > player.frame_delay) {
+ *timer_address = kernel.clock = clock_save + player.frame_delay;
+ }
+
+ kernel.paused = false;
+}
+
+
+
+/*
+/* game_error_service ()
+/*
+/* Handle fatal error situations
+*/
+void game_error_service() {
+ if (inter_spinning_objects || inter_animation_running) {
+ if (mem_last_alloc_failed) {
+ error_dump_file("*warn1.dat");
+ }
+ }
+}
+
+static void game_wait_cursor() {
+ cursor_id = 2;
+ cursor_id = MIN(cursor_id, cursor->num_sprites);
+ if (cursor_id != cursor_last) {
+ mouse_cursor_sprite(cursor, cursor_id);
+ cursor_last = cursor_id;
+ }
+}
+
+void game_set_camera_speed() {
+ switch (kernel_panning_speed) {
+ case PANNING_INSTANT:
+ camera_x.pan_velocity = CAMERA_DEFAULT_X_VELOCITY * 80;
+ camera_y.pan_velocity = CAMERA_DEFAULT_Y_VELOCITY * 80;
+ break;
+
+ case PANNING_MEDIUM:
+ camera_x.pan_velocity = CAMERA_DEFAULT_X_VELOCITY << 1;
+ camera_y.pan_velocity = CAMERA_DEFAULT_Y_VELOCITY << 1;
+ break;
+
+ case PANNING_SMOOTH:
+ default:
+ camera_x.pan_velocity = CAMERA_DEFAULT_X_VELOCITY;
+ camera_y.pan_velocity = CAMERA_DEFAULT_Y_VELOCITY;
+ break;
+ }
+}
+
+void nuke_all_speech_files(void) {
+ error("TODO: nuke_all_speech_files");
+}
+
+void start_the_copy_process(char orig_path[80]) {
+ error("TODO: start_the_copy_process");
+}
+
+void game_copy_speech_files(int room_) {
+ error("TODO: game_copy_speech_files");
+}
+
+/*
+/* game_control()
+/*
+/* This is the main outer control structure for the game, that
+/* determines which section and room level information should be
+/* loaded into and out of memory.
+*/
+
+void game_control() {
+ int count, color;
+ int result;
+
+ /* Start up game level functions */
+
+ error_service_routine_2 = game_error_service;
+
+ /*
+ if (config_file.mouse_cursor_fix == MOUSE_NOT_MICROSOFT) {
+ mouse_disable_scale();
+ }
+ */
+ if (game_mouse_cursor_fix) {
+ mouse_disable_scale();
+ }
+
+ game.going = (byte)!kernel_game_startup(mcga_mode, true,
+ global_release_version,
+ global_release_date);
+
+ game_exec_function(game_menu_init);
+
+ /* pl conv_system_init(); */
+
+ result = main_copy_verify();
+ if (result == COPY_FAIL) {
+ game.going = false;
+ force_chain = true;
+ game_restore_flag = false;
+ /* new_room = 804; */
+ /* global_init_code(); */
+ /* global[copy_protect_failed] = true; */
+ error_report(ERROR_COPY_PROTECTION, SEVERE, MODULE_LOCK, 0, 0);
+ } else if (result == COPY_ESCAPE) {
+ game.going = false;
+ force_chain = true;
+ }
+
+ kernel.clock = timer_read();
+
+ if (abort_value > 0) {
+ abort_clock = kernel.clock + ((long)abort_value * 60);
+ }
+
+ if (!game_restore_flag && (result != COPY_FAIL) && (result != COPY_ESCAPE)) {
+ /* Get difficulty level if new game */
+ if (!kernel.teleported_in && (game.difficulty == -1)) {
+ /* Difficulty menu */
+ /* kernel.activate_menu = GAME_DIFFICULTY_MENU; */
+ game_exec_function(game_menu_routine);
+
+ game_wait_cursor();
+
+ previous_section = 0;
+ previous_room = 0;
+
+ section_id = KERNEL_STARTING_GAME;
+ room_id = KERNEL_STARTING_GAME;
+ }
+ }
+
+ if (game.difficulty < 0) game.difficulty = HARD_MODE;
+
+ if ((result != COPY_FAIL) && (result != COPY_ESCAPE)) {
+ ems_paging_mode(EMS_PAGING_GLOBAL);
+ global_init_code();
+ main_global_init_code();
+ }
+
+ if (game_restore_flag && (result != COPY_FAIL) && (result != COPY_ESCAPE)) {
+ if (game_restore_flag == 2) {
+ save_game_buf[0] = 0;
+ kernel.activate_menu = GAME_RESTORE_MENU;
+ game_exec_function(game_menu_routine);
+ if (!save_game_buf[0]) {
+ game.going = false;
+ force_chain = true;
+ }
+ } else {
+ game.going = (byte)!kernel_load_game(save_game_buf);
+ if (!game.going) force_chain = true;
+ }
+ }
+
+ /* Game level control loop */
+
+ int_sprite[fx_int_journal] = -1;
+
+ while (game.going) {
+
+ /* Start up next section */
+
+ kernel_mode = KERNEL_SECTION_PRELOAD;
+
+ /* pl global_sound_driver (); */
+
+ ems_paging_mode(EMS_PAGING_SECTION);
+
+ global_section_constructor();
+ game_exec_function(section_preload_code_pointer);
+
+ game.going = (byte)!kernel_section_startup(new_section);
+
+ /* Load sound driver */
+
+ /* pl kernel_load_sound_driver (kernel.sound_driver, kernel.sound_card, sound_board_address, sound_board_type, sound_board_irq); */
+
+ kernel_mode = KERNEL_SECTION_INIT;
+
+ game_exec_function(section_init_code_pointer);
+
+ matte_init(true);
+
+
+ /* Section level control loop */
+
+ while ((new_section == section_id) && game.going) {
+
+ /* Load up next room */
+
+ kernel_mode = KERNEL_ROOM_PRELOAD;
+
+ player.walker_must_reload = (byte)(!player.walker_is_loaded);
+
+ quote_emergency = false;
+ /* vocab_emergency = false; */
+
+ game_wait_cursor();
+
+#ifdef demo
+ demo_verify();
+#endif
+
+ kernel.quotes = NULL;
+
+ /* vocab_init_active(); */
+ kernel_init_dynamic();
+
+ game_exec_function(section_room_constructor);
+
+ player.commands_allowed = true;
+ player.walker_visible = true;
+ player.walk_anywhere = false;
+
+ text_default_x = POPUP_CENTER;
+ text_default_y = POPUP_CENTER;
+
+ player_discover_room(new_room);
+
+ /* Reset interface mode */
+
+ inter_input_mode = INTER_BUILDING_SENTENCES;
+ inter_force_rescan = true;
+
+ scrollbar_active = 0;
+
+ player.walker_loads_first = true;
+
+ picture_view_x = 0;
+ picture_view_y = 0;
+
+ ems_paging_mode(EMS_PAGING_ROOM);
+
+ kernel_initial_variant = 0;
+
+ kernel.disable_fastwalk = false;
+
+ game_exec_function(room_preload_code_pointer);
+
+ if (player.walker_must_reload || !player.walker_loads_first) {
+
+ if (player.walker_is_loaded) {
+ player_dump_walker();
+ }
+
+ if (int_sprite[fx_int_journal] != -1 && room_id != KERNEL_RESTORING_GAME) {
+ matte_deallocate_series(int_sprite[fx_int_candle_on], true);
+ matte_deallocate_series(int_sprite[fx_int_dooropen], true);
+ matte_deallocate_series(int_sprite[fx_int_exit], true);
+ matte_deallocate_series(int_sprite[fx_int_candle], true);
+ matte_deallocate_series(int_sprite[fx_int_backpack], true);
+ matte_deallocate_series(int_sprite[fx_int_journal], true);
+ int_sprite[fx_int_journal] = -1;
+ }
+
+ g_engine->section_music(section_id);
+
+ pal_init(KERNEL_RESERVED_LOW_COLORS, KERNEL_RESERVED_HIGH_COLORS);
+
+ matte_init(true);
+
+ if (!player.walker_is_loaded) {
+ int_sprite[fx_int_journal] = kernel_load_series("*journal", false);
+ int_sprite[fx_int_backpack] = kernel_load_series("*backpack", false);
+ int_sprite[fx_int_candle] = kernel_load_series("*candle", false);
+ int_sprite[fx_int_exit] = kernel_load_series("*door", false);
+ int_sprite[fx_int_dooropen] = kernel_load_series("*dooropen", false);
+ int_sprite[fx_int_candle_on] = kernel_load_series("*candleon", false);
+ }
+
+ } else {
+ /* paul - call my special preserve palette routine in extra_1 */
+ /* player_preserve_palette(); */
+ extra_inven_preserve_palette();
+ }
+
+ pal_activate_shadow(&kernel_shadow_main);
+ master_shadow->num_shadow_colors = 3;
+ for (count = 0; count < master_shadow->num_shadow_colors; count++) {
+ color = PAL_FORCE_SHADOW + count;
+ master_shadow->shadow_color[count] = color;
+ }
+
+ if (!player.walker_is_loaded) {
+ if (player.walker_loads_first) {
+
+ game.going |= !player_load_series(NULL);
+
+ player.walker_loaded_first = true;
+ }
+ }
+
+ for (count = 0; count < master_shadow->num_shadow_colors; count++) {
+ color = PAL_FORCE_SHADOW + count;
+ color_status[color] = 0;
+ /* error_watch_point ("color_status", count, 0); */
+
+ }
+
+
+ game.going = (byte)!kernel_room_startup(new_room, kernel_initial_variant, kernel.interface, false);
+
+ game_copy_speech_files(new_room);
+
+ camera_init_default();
+
+ game_set_camera_speed();
+
+ /* pl sound_queue_hold(); */
+
+ /* Load current player walker set */
+
+ if (!player.walker_is_loaded) {
+ game.going |= !player_load_series(NULL);
+ player.walker_loaded_first = false;
+ }
+
+ /* Set up control structures for new room */
+
+ mouse_init_cycle();
+
+ left_command = -1; /* Left mouse main verb */
+ left_inven = -1; /* Left mouse inventory */
+ left_action = -1; /* Left mouse secondary verb */
+
+ inter_init_sentence();
+
+ player_set_final_facing();
+ player.facing = player.turn_to_facing;
+
+ player_cancel_command();
+
+ kernel_mode = KERNEL_ROOM_INIT;
+
+ /* Use a graphics fade in for room transition */
+
+ if (kernel_screen_fade == SCREEN_FADE_SMOOTH) {
+ /* kernel.fx = MATTE_FX_CIRCLE_OUT_SLOW; */
+ kernel.fx = MATTE_FX_FADE_THRU_BLACK;
+ } else if (kernel_screen_fade == SCREEN_FADE_FAST) {
+ /* kernel.fx = MATTE_FX_CIRCLE_OUT_SLOW; */
+ kernel.fx = MATTE_FX_FAST_THRU_BLACK;
+ } else {
+ /* kernel.fx = MATTE_FX_CIRCLE_OUT_SLOW; */
+ kernel.fx = MATTE_FX_FAST_AND_FANCY;
+ }
+
+ kernel.trigger = 0;
+
+ correction_clock = kernel.clock = timer_read();
+
+ kernel_animation_init();
+
+ if (previous_room == KERNEL_RESTORING_GAME) {
+ camera_jump_to(camera_old_x_target, camera_old_y_target);
+ }
+
+ for (count = 0; count < IMAGE_INTER_LIST_SIZE; ++count) {
+ image_inter_list[count].series_id = 0;
+ }
+
+
+ kernel.trigger_setup_mode = KERNEL_TRIGGER_DAEMON;
+
+ global_room_init();
+
+ kernel_set_interface_mode(INTER_LIMITED_SENTENCES);
+
+ game_exec_function(room_init_code_pointer);
+
+ /* paul - oh no! magic numbers! */
+ stamp_sprite_to_interface(BP_X, BP_Y, 1, int_sprite[fx_int_backpack]);
+ if (global[5]) { /* candle_is_on */
+ stamp_sprite_to_interface(CANDLE_X, CANDLE_Y, 1, int_sprite[fx_int_candle_on]);
+ } else {
+ stamp_sprite_to_interface(CANDLE_X, CANDLE_Y, 1, int_sprite[fx_int_candle]);
+ }
+ stamp_sprite_to_interface(DOOR_X, DOOR_Y, 1, int_sprite[fx_int_exit]);
+
+ if (room_id != 199) { /* Taranjeet, if this is not journal room */
+ stamp_sprite_to_interface(JOURNAL_X, JOURNAL_Y, 1, int_sprite[fx_int_journal]);
+ }
+
+ scr_work.data = buffer_pointer(&scr_main, 0, viewing_at_y);
+ if (viewing_at_y) {
+ buffer_rect_fill(scr_main, 0, 0, video_x, viewing_at_y, 0);
+ buffer_rect_fill(scr_main, 0, viewing_at_y + scr_work.y, video_x, video_y, 0);
+ }
+
+ /* pl conv_restore_running = -1; */
+
+ player.target_x = player.x;
+ player.target_y = player.y;
+ player.target_facing = player.turn_to_facing = player.facing;
+ player_select_series();
+ player_new_stop_walker();
+
+ player.walker_been_visible = player.walker_visible;
+
+ player.special_code = attr_special(&scr_special, player.x, player.y);
+
+ /* Reset player clock to make sure walker appears in first frame */
+
+ player.clock = kernel.clock;
+ player_stationary_update();
+
+ if (active_inven >= 0) {
+ /* keep inventory turned off until selected */
+ inter_turn_off_object(); /* delete this and uncomment below to return system to original */
+ /* inter_spin_object (inven[active_inven]); */
+ } else {
+ inter_turn_off_object();
+ }
+
+ /* Just in case something goes horribly wrong. */
+
+ error_service_routine = game_emergency_save;
+
+ /* Call main loop as long as player remains in same room */
+
+ kernel_mode = KERNEL_ACTIVE_CODE;
+
+ kernel.teleported_in = false;
+
+ ems_paging_mode(EMS_PAGING_SYSTEM);
+
+ if ((quote_emergency /* || vocab_emergency */) && !game_any_emergency) {
+ room_id = previous_room;
+ game_any_emergency = true;
+ goto emergency;
+ } else {
+ game_any_emergency = false;
+ }
+
+ g_engine->game_control_loop();
+
+ /* ********************************************************************************************** */
+
+ /* LEAVE ROOM */
+
+ /* ********************************************************************************************** */
+
+ global[16] = false; /* dont_load_walker */
+
+ /* pl if (speech_system_active && speech_on) {
+ speech_all_off();
+ }
+ */
+
+emergency:
+ game_wait_cursor();
+
+ kernel_mode = KERNEL_ROOM_PRELOAD;
+
+ /* pl if (!game.going) {
+ aborted_conv = conv_control.running;
+ }
+
+ conv_abort();
+ */
+
+ /* Shutdown the current room structures */
+
+ if (kernel.quotes != NULL) mem_free(kernel.quotes);
+
+ kernel_abort_all_animations();
+
+ kernel.force_restart = false;
+
+ inter_turn_off_object();
+ kernel_unload_all_series();
+
+ game_exec_function(room_shutdown_code_pointer);
+
+ if (!player.walker_loaded_first) {
+ player.walker_is_loaded = false;
+ player.walker_must_reload = true;
+ }
+
+ kernel_room_shutdown();
+
+ /* pl conv_flush(); */
+
+ new_section = new_room / 100;
+
+ /* Flush all EMS/XMS preloads at the room level */
+
+ himem_flush(ROOM);
+
+ if (!game.going && !win_status && section_id != 9 /* && !global[copy_protect_failed] */) {
+ /* pl conv_control.running = aborted_conv; */
+ game_save_name(0);
+ kernel_save_game(save_game_buf);
+ game_autosaved = true;
+ } else {
+ game_autosaved = false;
+ }
+
+ }
+
+ /* remove .RAC and .RAW files */
+ nuke_all_speech_files();
+
+ player_dump_walker();
+
+ if (room_id == KERNEL_RESTORING_GAME) {
+ kernel_room_series_marker = 0;
+ kernel_unload_all_series();
+ }
+
+ /* player_dump_walker(); */
+
+ if (room_id != KERNEL_RESTORING_GAME) {
+ if (int_sprite[fx_int_journal] != -1) {
+ matte_deallocate_series(int_sprite[fx_int_candle_on], true);
+ matte_deallocate_series(int_sprite[fx_int_dooropen], true);
+ matte_deallocate_series(int_sprite[fx_int_exit], true);
+ matte_deallocate_series(int_sprite[fx_int_candle], true);
+ matte_deallocate_series(int_sprite[fx_int_backpack], true);
+ matte_deallocate_series(int_sprite[fx_int_journal], true);
+ int_sprite[fx_int_journal] = -1;
+ }
+ }
+
+ pal_unlock();
+
+ game_wait_cursor();
+
+ /* pl kernel_unload_sound_driver(); */
+
+ /* Shut down current section */
+
+ kernel_section_shutdown();
+
+ /* Flush all EMS/XMS preloads at the section level */
+
+ himem_flush(SECTION);
+ }
+
+ /* Shut down the game */
+
+ game_exec_function(game_menu_exit);
+
+ kernel_game_shutdown();
+
+ /* pl conv_system_cleanup(); */
+
+ mcga_reset();
+}
+
+
+/*
+/* Execute a function-pointer routine.
+*/
+void game_exec_function(void (*(target))()) {
+ if (target)
+ target();
+}
+
+/*
+/* game_system_maintenance()
+/*
+/* Perform any system maintenance for this frame. Mostly involves
+/* reading the keyboard.
+*/
+static void game_system_maintenance() {
+ int unparsed_key = false;
+
+ global[3] = false; /* player_hyperwalked */
+
+ if (keys_any()) {
+ game_any_keystroke = true;
+ game_keystroke = keys_get();
+ unparsed_key = game_parse_keystroke(game_keystroke);
+ } else {
+ game_any_keystroke = false;
+ }
+
+ if (section_id != 9 && room_id != 199) {
+ if (((mouse_status & 3) == 3) && player.commands_allowed) {
+ /* kernel.force_restart = true; */
+ kernel.activate_menu = GAME_MAIN_MENU;
+ inter_init_sentence();
+ inter_sentence_ready = false;
+ matte_refresh_work();
+ }
+ }
+
+ if (unparsed_key || inter_auxiliary_click) {
+ /* pl conv_control.popup_clock = kernel.clock; */
+ inter_auxiliary_click = false;
+ }
+}
+
+
+void do_interface_for_ouaf() {
+ if (mouse_y > 156 &&
+ mouse_stop_stroke &&
+ player.commands_allowed &&
+ /* global[4] == -1 && */
+ !kernel.trigger &&
+ /* player.command_ready && */
+ inter_input_mode == INTER_LIMITED_SENTENCES &&
+ !global[2] /* inventory_is_displayed */
+ /* pl conv_control.running < 0 */) {
+
+ if (room_id == 199) { /* Taranjeet's Journal */
+
+ leave_journal();
+
+ } else if (mouse_x < 64) {
+ display_journal();
+ } else if (mouse_x < 139) {
+ display_inventory();
+ } else if (mouse_x < 195) {
+ } else if (mouse_x < 250) {
+ solve_me_selected();
+ } else {
+ door_selected();
+ }
+ }
+
+
+ if (kernel.trigger == 40) {
+ display_inventory();
+ }
+}
+
+
+/*
+/* game_daemon_code()
+/*
+/* Calls, in proper order, all daemon code for this framing round.
+*/
+static void game_daemon_code() {
+ global[4] = -1; /* turn off global[player_selected_object] */
+
+ digi_read_another_chunk();
+
+ if (global[9]) midi_loop(); /* please loop the damn music */
+
+ if (section_id != 9) {
+ do_interface_for_ouaf();
+ }
+
+ kernel.trigger_setup_mode = KERNEL_TRIGGER_DAEMON;
+
+ game_exec_function(room_daemon_code_pointer);
+ game_exec_function(section_daemon_code_pointer);
+
+ global_daemon_code();
+
+ if (kernel.trigger_mode == KERNEL_TRIGGER_DAEMON) {
+ kernel.trigger = 0;
+ }
+ player.trigger = 0;
+}
+
+
+/*
+/* game_handle_preparse()
+/*
+/* Handles incoming player commands BEFORE any walk action can take
+/* place. Player walk for the command can be postponed by setting
+/* player.ready_to_walk to false, and then returning it to true when
+/* ready for the walk to begin (additional player commands are auto-
+/* matically disabled during the interim period). Player walk for
+/* the command can be cancelled permanently by setting the value of
+/* player.need_to_walk to false.
+*/
+static void game_handle_preparse() {
+ /* if (global[4] >= 0 || global[5]) player.command_ready = true; */
+ /* if (global[4] >= 0 || global[5]) player.command_error = false; */
+
+ /* if (global[4] >= 0 ) player.command_ready = true; */
+ /* if (global[4] >= 0 ) player.command_error = false; */
+
+ if ((inter_input_mode == INTER_BUILDING_SENTENCES) ||
+ (inter_input_mode == INTER_LIMITED_SENTENCES)) {
+ kernel.trigger_setup_mode = KERNEL_TRIGGER_PREPARSE;
+
+ /* if (global[4] >= 0) { */
+ /* player_verb = -1; */
+ /* player_main_noun = -1; */
+ /* player_second_noun = -1; */
+ /* } */
+
+ global_pre_parser_code();
+ game_exec_function(section_pre_parser_code_pointer);
+ game_exec_function(room_pre_parser_code_pointer);
+
+ if (kernel.trigger_mode == KERNEL_TRIGGER_PREPARSE) {
+ kernel.trigger = 0;
+ }
+ }
+}
+
+
+
+/*
+/* game_handle_command()
+/*
+/* Handles incoming player commands -- they are filtered down through
+/* various levels of parser code and error code.
+*/
+static void game_handle_command() {
+ int handled_this_one;
+ int kernel_trigger_in;
+
+ kernel_trigger_in = kernel.trigger;
+
+#ifdef debug_enable_logfiles
+#define LOGFILE_NONE 0
+#define LOGFILE_ROOM_PARSER 1
+#define LOGFILE_SECTION_PARSER 2
+#define LOGFILE_GLOBAL_PARSER 3
+#define LOGFILE_ROOM_ERROR 4
+#define LOGFILE_SECTION_ERROR 5
+#define LOGFILE_GLOBAL_ERROR 6
+ int logfile_handled_level = LOGFILE_NONE;
+ char temp1[20];
+ char temp2[80];
+#endif
+
+ /* pl if (conv_control.running >= 0) {
+ player.look_around = false;
+ if ((conv_control.status == CONV_STATUS_WAIT_AUTO) ||
+ (conv_control.status == CONV_STATUS_WAIT_ENTRY)) {
+ player.commands_allowed = false;
+ }
+ }
+ */
+
+ handled_this_one = false;
+ if (kernel.trigger) player.command_ready = true;
+
+ kernel.trigger_setup_mode = KERNEL_TRIGGER_PARSER;
+
+ if (kernel.trigger && (kernel.trigger_mode == KERNEL_TRIGGER_PARSER) && player.command_error) {
+ error_report(ERROR_ORPHANED_TRIGGER, WARNING, MODULE_KERNEL, kernel.trigger, 0);
+ }
+
+ if ((player.command_ready || kernel.trigger /*|| ((global[4] >= 0) && player.command_ready)*/) &&
+ (!player.command_error)) {
+
+ game_exec_function(room_parser_code_pointer);
+
+ handled_this_one = !player.command_ready;
+#ifdef debug_enable_logfiles
+ if (!player.command_ready) logfile_handled_level = LOGFILE_ROOM_PARSER;
+#endif
+ }
+
+ /* pl if (conv_control.running >= 0) {
+ player.command_ready = false;
+ goto done;
+ }
+ */
+
+ if (player.command_ready || kernel.trigger /*|| ((global[4] >= 0) && player.command_ready)*/) {
+ game_exec_function(section_parser_code_pointer);
+ handled_this_one = !player.command_ready;
+#ifdef debug_enable_logfiles
+ if (!player.command_ready) logfile_handled_level = LOGFILE_SECTION_PARSER;
+#endif
+ }
+
+ if ((player.command_ready || kernel.trigger /*|| ((global[4] >= 0) && player.command_ready)*/) &&
+ (!handled_this_one) && (!player.command_error)) {
+ global_parser_code();
+#ifdef debug_enable_logfiles
+ if (!player.command_ready) logfile_handled_level = LOGFILE_GLOBAL_PARSER;
+#endif
+ }
+
+
+ /* if (global[4] >= 0) */
+ /* player.command_ready = false; */
+
+ if (player.look_around) goto done;
+
+ if (player.command_ready) {
+ player.command_error = true;
+ game_exec_function(room_error_code_pointer);
+#ifdef debug_enable_logfiles
+ if (!player.command_ready) logfile_handled_level = LOGFILE_ROOM_ERROR;
+#endif
+ }
+
+ if (player.command_ready) {
+ player.command_error = true;
+ game_exec_function(section_error_code_pointer);
+#ifdef debug_enable_logfiles
+ if (!player.command_ready) logfile_handled_level = LOGFILE_SECTION_ERROR;
+#endif
+ }
+
+ if (player.command_ready) {
+ global_error_code();
+#ifdef debug_enable_logfiles
+ logfile_handled_level = LOGFILE_GLOBAL_ERROR;
+#endif
+ }
+
+
+done:
+ player.command_ready = false;
+
+#ifdef debug_enable_logfiles
+ if ((!kernel.trigger) && (inter_input_mode == INTER_BUILDING_SENTENCES) && logfile_enabled) {
+ Common::strcpy_s(temp2, "ROOM");
+ temp1[0] = 0;
+ env_catint(temp1, room_id, 3);
+ Common::strcat_s(temp2, temp1);
+ Common::strcat_s(temp2, ".LOG");
+ logfile_handle = fopen(temp2, "at");
+ if (logfile_handle != NULL) {
+ if (player.command_error) {
+ Common::strcpy_s(temp1, "ERROR ");
+ } else {
+ Common::strcpy_s(temp1, "Valid ");
+ }
+ switch (logfile_handled_level) {
+ case LOGFILE_ROOM_PARSER:
+ Common::strcpy_s(temp2, "room parser) ");
+ break;
+ case LOGFILE_SECTION_PARSER:
+ Common::strcpy_s(temp2, "sect. parser) ");
+ break;
+ case LOGFILE_GLOBAL_PARSER:
+ Common::strcpy_s(temp2, "global parser)");
+ break;
+ case LOGFILE_ROOM_ERROR:
+ Common::strcpy_s(temp2, "room error) ");
+ break;
+ case LOGFILE_SECTION_ERROR:
+ Common::strcpy_s(temp2, "sect. error) ");
+ break;
+ case LOGFILE_GLOBAL_ERROR:
+ Common::strcpy_s(temp2, "global error) ");
+ break;
+ case LOGFILE_NONE:
+ default:
+ Common::strcpy_s(temp2, "NOTHING) ");
+ break;
+ }
+ fprintf(logfile_handle, "%s (by: %s \"%s\"\n", temp1, temp2, player.sentence);
+ fclose(logfile_handle);
+ }
+ }
+#endif
+
+ if (kernel.trigger_mode == KERNEL_TRIGGER_PARSER) {
+ if (kernel.trigger == kernel_trigger_in) {
+ kernel.trigger = 0;
+ }
+ }
+
+ /* pl if (conv_control.running >= 0) {
+ if ((conv_control.status == CONV_STATUS_WAIT_AUTO) ||
+ (conv_control.status == CONV_STATUS_WAIT_ENTRY)) {
+ conv_update(true);
+ }
+ }
+ */
+}
+
+
+void do_looping_sounds() {
+ switch (room_id) {
+ case 304:
+ /* do water trickle */
+ kernel.trigger_setup_mode = KERNEL_TRIGGER_DAEMON;
+ kernel_timing_trigger(1, 107); /* PLAY_MORE_TRICKLE */
+ break;
+
+ case 305:
+ /* do bird crowd */
+ kernel.trigger_setup_mode = KERNEL_TRIGGER_DAEMON;
+ kernel_timing_trigger(1, 109); /* DO_CROWD */
+ break;
+
+ case 306:
+ /* if global[phineas_status] <= PHIN_IS_IN_CONTROL_AGAIN) { */
+ if (global[66] <= 2) {
+ /* bird crowd talking */
+ kernel.trigger_setup_mode = KERNEL_TRIGGER_DAEMON;
+ kernel_timing_trigger(1, 117); /* DO_CROWD */
+ } else {
+ /* water flowing */
+ kernel.trigger_setup_mode = KERNEL_TRIGGER_DAEMON;
+ kernel_timing_trigger(1, 118); /* DO_WATER */
+ }
+ break;
+
+ case 401:
+ /* do dragon noise */
+ kernel.trigger_setup_mode = KERNEL_TRIGGER_DAEMON;
+ kernel_timing_trigger(1, 106); /* DRAGON_NOISE */
+ break;
+
+ case 403:
+ /* do water noise */
+ kernel.trigger_setup_mode = KERNEL_TRIGGER_DAEMON;
+ kernel_timing_trigger(1, 105); /* WATER */
+ break;
+
+ case 404:
+ /* do dragon noise */
+ kernel.trigger_setup_mode = KERNEL_TRIGGER_DAEMON;
+ kernel_timing_trigger(1, 110); /* DRAGON_NOISE */
+ break;
+
+ case 405:
+ /* do dragon noise */
+ kernel.trigger_setup_mode = KERNEL_TRIGGER_DAEMON;
+ kernel_timing_trigger(1, 106); /* DRAGON_NOISE */
+ break;
+
+ case 210:
+ /* rush MORE_RUSH_RUSH */
+ kernel.trigger_setup_mode = KERNEL_TRIGGER_DAEMON;
+ kernel_timing_trigger(1, 109); /* MORE_RUSH_RUSH */
+ break;
+
+ }
+}
+
+
+/*
+/* game_main_loop()
+/*
+/* This is the main inner graphics control loop for the game,
+/* and is executed once for each framing round.
+*/
+static void game_main_loop() {
+ int id;
+ int preparse_flag = false;
+ int temp_message = 0;
+ int temp_message_2 = 0;
+ int temp_message_3 = 0;
+ int temp_message_4 = 0;
+ int yy;
+ long one_clock, two_clock;
+ static char temp_buf[20];
+ static char temp_buf_2[20];
+ static char temp_buf_3[20];
+ static char temp_buf_4[20];
+ /* these 3 are for the background efx */
+ long dif;
+
+ if (global[10]) { /* please play the damn targets */
+
+ /* this is for the background sound efx */
+ dif = kernel.clock - noise_clock;
+ if ((dif >= 0) && (dif <= 4)) {
+ noise_timer += dif;
+ } else {
+ noise_timer += 1;
+ }
+ noise_clock = kernel.clock;
+
+ if (noise_length == -1) {
+ if (room_id == 220 || room_id == 221 || room_id == 307 || room_id == 322 || room_id == 420 ||
+ room_id == 308 || room_id == 204 || room_id == 211) {
+ /* night time */
+ noise_length = imath_random(50, 80);
+
+ } else {
+ /* day time */
+ noise_length = imath_random(150, 220);
+ }
+ }
+
+ if (noise_timer >= (noise_length + global[13])) {
+ if (room_id == 220 || room_id == 221 || room_id == 307 || room_id == 322 || room_id == 420 ||
+ room_id == 308 || room_id == 204 || room_id == 211) {
+ /* night time */
+ /* digi_initial_volume (75); */
+ digi_trigger_effect = false;
+ digi_play_build(220, '_', 5, 2); /* EFFECT */
+ /* digi_trigger_ambiance = false; */
+
+ } else {
+ /* day time */
+
+ yy = imath_random(1, 6);
+ while (last_bird_sound == (byte)yy) yy = imath_random(1, 6);
+
+ last_bird_sound = (byte)yy;
+
+ /* digi_initial_volume (imath_random (25, 100)); */
+
+ digi_trigger_effect = false;
+
+ switch (yy) {
+ case 1: digi_play_build(321, '_', 500, 2); break; /* EFFECT */
+ case 2: digi_play_build(321, '_', 501, 2); break; /* EFFECT */
+ case 3: digi_play_build(321, '_', 502, 2); break; /* EFFECT */
+ case 4: digi_play_build(321, '_', 503, 2); break; /* EFFECT */
+ case 5: digi_play_build(321, '_', 504, 2); break; /* EFFECT */
+ case 6: digi_play_build(321, '_', 505, 2); break; /* EFFECT */
+
+ }
+ }
+ /* digi_trigger_ambiance = false; */
+ noise_length = -1;
+ noise_timer = 0;
+ }
+ }
+
+
+ if (player.walker_visible && player.commands_allowed && section_id != 9 && lets_get_a_move_on_anim &&
+ !player.walking && !player.need_to_walk && move_your_butt_anim_handle == -1) {
+ move_your_butt_enabled = 1;
+ } else {
+ move_your_butt_enabled = 0;
+ move_your_butt_timer = 0;
+ }
+
+ if (move_your_butt_enabled) {
+
+ /* this is for the background sound efx */
+ dif = kernel.clock - move_your_butt_clock;
+ if ((dif >= 0) && (dif <= 4)) {
+ move_your_butt_timer += dif;
+ } else {
+ move_your_butt_timer += 1;
+ }
+ move_your_butt_clock = kernel.clock;
+
+ if (move_your_butt_timer >= MOVE_YOUR_BUTT_TIMEOUT) {
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ player.clock = kernel.clock;
+ move_your_butt_anim_handle = kernel_run_animation("*b_2t", 0);
+ extra_change_animation(move_your_butt_anim_handle, player.x, player.y, player.scale, player.depth);
+ kernel_synch(KERNEL_ANIM, move_your_butt_anim_handle, KERNEL_NOW, 0);
+
+ switch (player.facing) {
+ case 8:
+ kernel_reset_animation(move_your_butt_anim_handle, 21);
+ break;
+
+ case 9:
+ kernel_reset_animation(move_your_butt_anim_handle, 22);
+ break;
+
+ case 6:
+ kernel_reset_animation(move_your_butt_anim_handle, 23);
+ break;
+
+ case 7:
+ kernel_reset_animation(move_your_butt_anim_handle, 26);
+ break;
+
+ case 4:
+ kernel_reset_animation(move_your_butt_anim_handle, 27);
+ break;
+
+ default:
+ kernel_reset_animation(move_your_butt_anim_handle, 24);
+ break;
+ }
+
+ do_looping_sounds();
+ }
+ }
+
+ if (move_your_butt_anim_handle != -1) {
+ if (kernel_anim[move_your_butt_anim_handle].frame != move_your_butt_anim_frame) {
+ move_your_butt_anim_frame = kernel_anim[move_your_butt_anim_handle].frame;
+
+ switch (move_your_butt_anim_frame) {
+
+ case 24: /* ab in a 2 */
+ case 28: /* ab in a 2 */
+ /* AB we need to keep moving, michelle needs those herbs */
+ digi_trigger_dialog = false;
+ digi_play_build_ii('b', 4, 1);
+ /* digi_send_dialog_trigger = false; */
+ kernel_reset_animation(move_your_butt_anim_handle, 0);
+ move_your_butt_anim_frame = 0;
+ break;
+
+ case 20: /* end of talking */
+ /* end AB we need to keep moving, michelle needs those herbs */
+ dont_frag_the_palette();
+ kernel_abort_animation(move_your_butt_anim_handle);
+ move_your_butt_anim_handle = -1;
+
+ move_your_butt_timer = 0;
+ player.walker_visible = true;
+ player.commands_allowed = true;
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_NOW, 0);
+ player_demand_facing(FACING_SOUTH);
+
+ if (config_file.misc2) {
+ do_looping_sounds();
+ }
+ break;
+ }
+ }
+ }
+
+
+ /* Clear any remaining player command message from screen */
+
+ if (inter_sentence_ready || !player.commands_allowed) {
+ inter_init_sentence();
+ inter_sentence_ready = false;
+ }
+
+ /* Interface processing -- accept new commands */
+
+
+
+ if (!kernel.trigger && !player.trigger) {
+ if (kernel_dynamic_changed) kernel_refresh_dynamic();
+ inter_main_loop(player.commands_allowed && !player.need_to_walk && !kernel.fx);
+ }
+
+ /* Get official timing clock (in 60th/sec) for this round */
+
+ if (!kernel.fx) {
+ kernel.clock = timer_read();
+ }
+
+ /* Update camera view if necessary */
+
+ camera_update();
+
+ /* If new command came in, accept it and set up to perform any necessary walking */
+
+ if (inter_sentence_ready &&
+ player.commands_allowed &&
+ !player.need_to_walk &&
+ !kernel.trigger &&
+ !player.trigger) {
+ player_new_command();
+ if (inter_input_mode != INTER_CONVERSATION) {
+ global_verb_filter();
+ }
+ preparse_flag = true;
+ }
+
+ if (preparse_flag || /*global[4] >= 0 ||*/
+ ((kernel.trigger) && (kernel.trigger_mode == KERNEL_TRIGGER_PREPARSE))) {
+ game_handle_preparse();
+ }
+
+ preparse_flag = false;
+
+ player_new_walk();
+
+ /* Handle parser commands and parser triggers */
+ if ((player.command_ready && !player.walking && !player.need_to_walk && (player.facing == player.turn_to_facing) && !kernel.trigger) ||
+ (kernel.trigger && (kernel.trigger_mode == KERNEL_TRIGGER_PARSER))/* ||
+ global[4] >= 0*/) {
+ game_handle_command(); /* room,sect,global parser*/
+ }
+
+ if (new_room != room_id) {
+ /* pl conv_abort(); */
+ kernel_doom_all_animations();
+ goto skip_frame;
+ }
+
+ /* Execute daemon code, and do system maintenance */
+
+ if (!kernel.trigger || (kernel.trigger_mode == KERNEL_TRIGGER_DAEMON)) {
+ game_daemon_code(); /* interface, room,sect,global daemon */
+ }
+
+ game_system_maintenance();
+
+ if (new_room != room_id) {
+ /* pl conv_abort(); */
+ kernel_doom_all_animations();
+ goto skip_frame;
+ }
+
+ /* Update all active conversations */
+
+ /* pl if (!kernel.trigger) {
+ if (conv_control.running >= 0) {
+ if (!camera_x.panning && !camera_y.panning) {
+ conv_update (false);
+ }
+ }
+ }
+ */
+
+ /* Update the player image, if it is time to do so */
+
+ if ((kernel.clock >= player.clock) && !kernel.trigger) {
+
+ player.clock = kernel.clock + player.frame_delay;
+
+ if (player.walking) {
+ player_keep_walking();
+ } else {
+ player_stationary_update();
+ }
+
+ player_set_sprite();
+ player_set_image();
+ }
+
+ cursor_id = 1; /* here */
+ if ((inter_awaiting == AWAITING_COMMAND) && !mouse_button) {
+ if (inter_spot_class == STROKE_INTERFACE) {
+ id = inter_spot_index - spot_base[STROKE_INTERFACE - 1];
+ if (id < room_num_spots) {
+ id = room_num_spots - (id + 1);
+ cursor_id = room_spots[id].cursor_number;
+ } else {
+ id -= room_num_spots;
+ cursor_id = kernel_dynamic_hot[id].cursor;
+ }
+ if (!cursor_id) cursor_id = 1;
+ }
+ }
+ if (!player.commands_allowed /*&& ((conv_control.running < 0) || conv_control.status == CONV_STATUS_HOLDING)*/) cursor_id = 2;
+ /* if ((conv_control.running >= 0) && (cursor_id > 2)) cursor_id = 1; */
+
+ if (section_id != 9 || room_id == 904) {
+ cursor_id = MIN(cursor_id, cursor->num_sprites);
+ if (cursor_id != cursor_last) {
+ mouse_cursor_sprite(cursor, cursor_id);
+ cursor_last = cursor_id;
+ }
+ }
+
+
+ /* Update any active graphics sequences */
+
+ kernel_seq_update_all();
+
+ /* Update any active animations */
+
+ kernel_process_all_animations();
+
+ /* Special mouse cursor update mode */
+ if (kernel.mouse_cursor_point) {
+ Common::strcpy_s(temp_buf, "(");
+ mads_itoa(mouse_x, &temp_buf[1], 10);
+ Common::strcat_s(temp_buf, ",");
+ mads_itoa(mouse_y, &temp_buf[strlen(temp_buf)], 10);
+ Common::strcat_s(temp_buf, ") ");
+ temp_message = kernel_message_add(temp_buf, 5, 5, 515, 1, 0, 0);
+ }
+
+ /* if (kernel.memory_tracking) { */
+ /* Common::strcpy_s (temp_buf_2, "(Mem: "); */
+ /* ltoa (mem_get_avail(), &temp_buf_2[6], 10); */
+ /* Common::strcat_s (temp_buf_2, ") "); */
+ /* temp_message_2 = kernel_message_add (temp_buf_2, 315, 5, 515, 1, 0, KERNEL_MESSAGE_RIGHT); */
+ /* } */
+
+ /* if (kernel.player_tracking) { */
+ /* Common::strcpy_s (temp_buf_3, "(Plyr: "); */
+ /* mads_itoa (player.x, &temp_buf_3[strlen(temp_buf_3)], 10); */
+ /* Common::strcat_s (temp_buf_3, ","); */
+ /* mads_itoa (player.y, &temp_buf_3[strlen(temp_buf_3)], 10); */
+ /* Common::strcat_s (temp_buf_3, ")"); */
+ /* yy = 5; */
+ /* if (kernel.mouse_cursor_point) yy += 15; */
+ /* temp_message_3 = kernel_message_add (temp_buf_3, 5, yy, 515, 1, 0, 0); */
+
+ /* Common::strcpy_s (temp_buf_4, "Scale %"); */
+ /* mads_itoa (player.scale, &temp_buf_4[strlen(temp_buf_4)], 10); */
+
+ /* yy += 15; */
+ /* temp_message_4 = kernel_message_add (temp_buf_4, 5, yy, 515, 1, 0, 0); */
+ /* } */
+
+ /* Update any messages */
+
+ if (!kernel.trigger) {
+ if (kernel.force_restart || (new_room != room_id)) kernel_message_purge();
+ kernel_message_update_all();
+ }
+
+ /* Matte out the next graphics frame */
+
+ if (!viewing_at_y) {
+ matte_inter_frame(!kernel.fx, kernel.fx);
+ if (kernel.fx) {
+ inter_prepare_background();
+ }
+ } else {
+ image_inter_marker = 0;
+ }
+
+ if (debugger && (debugger_state == DEBUGGER_MATTE) && debugger_matte_before) game_exec_function(debugger_update);
+
+ matte_frame(kernel.fx, kernel.fx);
+
+ if (debugger && ((debugger_state != DEBUGGER_MATTE) || !debugger_matte_before)) game_exec_function(debugger_update);
+
+ if (kernel.fx) {
+ one_clock = correction_clock;
+ two_clock = timer_read();
+ kernel_seq_correction(one_clock, two_clock);
+ kernel_message_correction(one_clock, two_clock);
+ }
+
+ if (kernel.mouse_cursor_point) {
+ kernel_message_delete(temp_message);
+ }
+
+ if (kernel.memory_tracking) {
+ kernel_message_delete(temp_message_2);
+ }
+
+ if (kernel.player_tracking) {
+ kernel_message_delete(temp_message_3);
+ kernel_message_delete(temp_message_4);
+ }
+
+ if (kernel.cause_pause || kernel.frame_by_frame) game_pause_mode();
+
+skip_frame:
+
+ /* if (mcga_shakes) mcga_shake(); */
+
+ if (kernel.fx) {
+ cycling_active = true;
+ }
+
+ kernel.fx = 0;
+
+ kernel_abort_doomed_animations();
+
+ while ((mouse_clock == timer_read()) && !kernel.trigger);
+}
+
+
+void game_control_loop() {
+ game_any_keystroke = false;
+
+ digi_trigger_dialog = true;
+ digi_trigger_ambiance = true;
+ digi_trigger_effect = true;
+
+ if (debugger) game_exec_function(debugger_reset);
+
+ while ((new_room == room_id) && game.going && !kernel.force_restart) {
+
+ game_main_loop();
+
+ if (kernel.activate_menu) {
+ if (!kernel.trigger && player.commands_allowed) {
+ game_exec_function(game_menu_routine);
+
+ if (game_menu_routine == NULL) game.going = false;
+
+ kernel.activate_menu = 0;
+ }
+ }
+
+ if (abort_value > 0) {
+ if (kernel.clock >= abort_clock) {
+ error_report(ERROR_TIME_LIMIT_EXPIRED, SEVERE, MODULE_GAME, abort_value, 0);
+ }
+ }
+
+ }
+
+ digi_stop(1);
+ digi_stop(2);
+ digi_stop(3);
+
+ if (debugger) game_exec_function(debugger_reset);
+}
+
+
+void chain_execute() {
+ error("TODO: chain_execute");
+}
+
+
+/*
+/* game_read_save_directory()
+/*
+/* Reads the list of save files.
+*/
+static void game_read_save_directory() {
+ int error_flag = true;
+ int mem_to_read;
+ Common::SeekableReadStream *handle = NULL;
+
+ mem_to_read = GAME_SAVE_SLOT_MEMORY;
+
+ handle = env_open(game_save_file, "rb");
+ if (handle == NULL) goto done;
+
+ if (!fileio_fread_f(game_save_directory, mem_to_read, 1, handle)) goto done;
+
+ error_flag = false;
+
+done:
+ delete handle;
+ if (error_flag) {
+ memset(game_save_directory, 0, mem_to_read);
+ }
+}
+
+
+/*
+/* game_write_save_directory()
+/*
+/* Writes the list of save files.
+*/
+void game_write_save_directory() {
+#ifdef TODO
+ int error_flag = true;
+ int mem_to_write;
+ Common::SeekableReadStream *handle = NULL;
+
+ mem_to_write = GAME_SAVE_SLOT_MEMORY;
+
+ handle = env_open(game_save_file, "wb");
+ if (handle == NULL) goto done;
+
+ if (!fileio_fwrite_f(game_save_directory, mem_to_write, 1, handle)) goto done;
+
+ error_flag = false;
+
+done:
+ if (handle != NULL) fclose(handle);
+
+ if (error_flag) {
+ error_report(ERROR_WRITE_SAVE_DIRECTORY, WARNING, MODULE_GAME_MENU, mem_to_write, 0);
+ }
+#else
+ error("TODO: game_write_save_directory");
+#endif
+}
+
+
+
+/*
+/* game_menu_setup()
+/*
+/* Sets up for the main menu routines to run--this mainly involves
+/* getting enough memory to hold the save directory and menu heap.
+*/
+void game_menu_setup() {
+ long mem_to_get;
+
+ game_preserve_handle = BUFFER_NOT_PRESERVED;
+ game_menu_heap.base = NULL;
+
+ /* Get enough memory to work with. If none available from the */
+ /* main heap, attempt to preserve the depth buffer and steal */
+ /* its memory temporarily. */
+
+ if (mem_get_avail() >= GAME_MENU_HEAP) {
+ heap_create(&game_menu_heap, MODULE_GAME_MENU, GAME_MENU_HEAP, "MENUHEAP");
+ } else if (scr_depth.data != NULL) {
+ game_preserve_handle = buffer_preserve(&scr_depth, BUFFER_PRESERVE, -1,
+ 0, 0,
+ scr_orig.x >> 1, scr_depth.y);
+ if (game_preserve_handle != BUFFER_NOT_PRESERVED) {
+ heap_declare(&game_menu_heap, MODULE_GAME_MENU,
+ (char *)scr_depth.data, GAME_MENU_HEAP);
+ }
+ }
+
+ if (game_menu_heap.base == NULL) {
+ error_report(ERROR_NO_MORE_MEMORY, SEVERE, MODULE_GAME_MENU, GAME_MENU_HEAP, 2);
+ }
+
+ /* Get memory for save slots */
+
+ mem_to_get = (long)GAME_MAX_SAVE_SLOTS * (GAME_MAX_SAVE_LENGTH + 1);
+ game_save_directory = (char *)heap_get(&game_menu_heap, mem_to_get);
+
+ /* Get memory for popup */
+
+ mem_to_get = GAME_DIALOG_HEAP;
+ game_menu_popup = (Popup *)heap_get(&game_menu_heap, mem_to_get);
+
+ /* Read the save list */
+
+ game_read_save_directory();
+
+ cursor_id = 1;
+ cursor_id = MIN(cursor_id, cursor->num_sprites);
+ if (cursor_id != cursor_last) {
+ mouse_cursor_sprite(cursor, cursor_id);
+ cursor_last = cursor_id;
+ }
+}
+
+/*
+/* game_menu_shutdown()
+/*
+/* Tells the menu structures to bite down hard.
+*/
+void game_menu_shutdown() {
+ heap_destroy(&game_menu_heap);
+
+ if (game_preserve_handle != BUFFER_NOT_PRESERVED) {
+ buffer_restore(&scr_depth, game_preserve_handle, -1,
+ 0, 0, scr_orig.x >> 1, scr_depth.y);
+ }
+}
+
+
+static void debugger_name(const char *name, int where) {
+ screen_printf(where, 0, "%s", name);
+}
+
+
+static void game_file_show(const char *filename, int show_at) {
+ Common::SeekableReadStream *handle = NULL;
+
+ handle = env_open(filename, "rt");
+ if (handle == NULL) {
+ screen_printf(0, 2, "No open %s", filename);
+ goto done;
+ }
+
+ while (!handle->eos()) {
+ Common::String line = handle->readLine();
+ screen_printf(2, show_at++, "%-79s", line.c_str());
+ }
+
+done:
+ delete handle;
+}
+
+
+
+void game_debugger_reset() {
+ screen = mono_text_video;
+
+ screen_normal_color = colorbyte(hi_white, black);
+ screen_hilite_color = screen_normal_color + 128;
+
+ screen_clear(0);
+
+ debugger_previous = DEBUGGER_NONE;
+}
+
+
+
+static void game_main_update() {
+ char temp_buf[80];
+ char temp_buf_2[80];
+
+ Common::strcpy_s(temp_buf, "");
+ Common::strcpy_s(temp_buf_2, "");
+
+ debugger_name("1", 30);
+
+ screen_printf(0, 2, "%-3d, %-3d Mem: %-6ld Min: %-6ld", room_id, previous_room, mem_get_avail(), mem_min_free);
+
+ screen_printf(0, 4, "%s @ %3d, %3d Dpt: %d ", player.series_name, player.x, player.y, player.depth);
+ /* screen_printf (0, 5, " Series: %d Sprite: %-2d Mirror: %-2d Frame Rate: %d ", player.series, player.sprite, player.mirror, player.frame_delay); */
+
+ screen_printf(0, 7, "Sc: %-3d Fr %d => %d%, Bk %d => %d%", player.scale, room->front_y, room->front_scale, room->back_y, room->back_scale);
+
+ if (!player.walker_visible) {
+ Common::strcat_s(temp_buf, "Invis ");
+ }
+
+ if (attr_walk(&scr_walk, player.x, player.y)) {
+ Common::strcat_s(temp_buf, "WALKCODE!");
+ }
+
+ screen_printf(0, 9, "%-79s", temp_buf);
+
+ screen_printf(0, 13, "%-6ld Tr: %d Mse: (%4d,%4d)", kernel.clock, kernel.trigger, mouse_x, mouse_y);
+
+ if (kernel.frame_by_frame) {
+ Common::strcat_s(temp_buf, "FxFrame ");
+ }
+
+ if (kernel.paused || (kernel.frame_by_frame && !keys_special_button)) {
+ Common::strcat_s(temp_buf, "~P~A~U~S~E ");
+ }
+
+ screen_printf(0, 14, "%-79s", temp_buf);
+}
+
+void update_colors(int offset) {
+}
+
+static void game_palette_update() {
+ int count;
+ int count2;
+ int x, y;
+ long handle;
+ long any_flag;
+ long walker_flag;
+ long picture_flag;
+ long in_walker;
+ long in_picture;
+ long in_any;
+ byte item;
+ byte attr;
+ byte *pointer;
+ byte *pointer2;
+ int free;
+ int delta;
+ int mykey;
+ int shit = 0;
+ static int old_free = 0;
+
+ if (pal_manager_active && debugger_memory_keywait) {
+ screen_normal_color = screen_hilite_color;
+ }
+
+ debugger_name("2", 23);
+
+ screen_normal_color = colorbyte(hi_white, black);
+
+ update_colors(0);
+
+ game_file_show("*PALETTE.DB", 2);
+
+ for (count = 0; count < 256; count++) {
+ y = (count / 16) + 2;
+ x = count % 16;
+
+ pointer = screen + (y * 160) + (x << 1);
+ pointer2 = pointer + 1;
+
+ if (count < 4) {
+ item = 'M';
+ } else if (count < 16) {
+ item = 'I';
+ } else if (count < KERNEL_RESERVED_LOW_COLORS) {
+ item = 'Q';
+ } else if (count >= 252) {
+ item = 'X';
+ } else if (count >= 246) {
+ item = 'O';
+ } else if (color_status[count] & PAL_CYCLE) {
+ item = 'c';
+ } else if (color_status[count]) {
+ handle = picture_resource.color_handle;
+ picture_flag = 1 << handle;
+ any_flag = picture_flag;
+
+ walker_flag = 0;
+ for (count2 = 0; count2 < player.num_series; count2++) {
+ handle = series_list[count2 + player.series_base]->color_handle;
+ walker_flag |= 1 << handle;
+ }
+
+ any_flag |= walker_flag;
+ any_flag = ~any_flag;
+
+ in_picture = color_status[count] & picture_flag;
+ in_walker = color_status[count] & walker_flag;
+ in_any = color_status[count] & any_flag;
+
+ if (color_status[count] & in_picture) {
+ if (color_status[count] & in_any) {
+ if (color_status[count] & in_walker) {
+ item = '!';
+ } else {
+ item = ':';
+ }
+ } else if (color_status[count] & in_walker) {
+ item = '*';
+ } else {
+ item = '+';
+ }
+ } else if (color_status[count] & in_walker) {
+ if (color_status[count] & in_any) {
+ item = '%';
+ } else {
+ item = '/';
+ }
+ } else {
+ item = '?';
+ }
+ } else {
+ item = '-';
+ }
+
+ if (color_status[count] & PAL_RESERVED) {
+ attr = 15;
+ } else if (color_status[count] & PAL_CYCLE) {
+ attr = 7 + 16;
+ } else {
+ attr = 7;
+ }
+
+ *pointer = item;
+ *pointer2 = attr;
+ }
+
+ if (pal_manager_active) {
+
+ if ((pal_manager_active != 2) && (pal_manager_active != 3)) {
+ loader_last[0] = 0;
+ }
+
+ screen_printf(0, 20, "Ldr: %-13s", loader_last);
+ screen_printf(0, 21, "Md: %d", pal_manager_active);
+ screen_printf(0, 22, "Mode: %d", pal_manager_active);
+
+ free = 0;
+ for (count = 0; count < 256; count++) {
+ if (!color_status[count]) free++;
+ }
+
+ if (pal_manager_active == 1) {
+ old_free = 0;
+ delta = 0;
+ } else {
+ delta = old_free - free;
+ }
+
+ /* screen_printf (0, 22, "Free: %-3d", free); */
+ /* screen_printf (0, 23, "Previous: %-3d", old_free); */
+ screen_printf(0, 24, "Added: %-3d", delta);
+
+
+ old_free = free;
+ }
+
+ if (pal_manager_active && debugger_memory_keywait) {
+
+top:
+
+ mykey = keys_get();
+ debugger_name("2", 23);
+ if (mykey == a_key) {
+ shit += 45;
+ if (shit == 255) shit = 0;
+ if ((shit + 45) > 255) {
+ shit = 210;
+ }
+ update_colors(shit);
+ goto top;
+ }
+ if (mykey == esc_key) {
+ pal_manager_update = NULL;
+ debugger_memory_keywait = false;
+ error_report(ERROR_BREAK_POINT, WARNING, MODULE_UNKNOWN, 0, 0);
+ }
+ }
+}
+
+
+
+static void game_scratch_update() {
+ int count;
+
+ debugger_name("3", 23);
+
+ for (count = 0; count < 220; count += 10) {
+ screen_printf(0, (count / 10) + 2, "%4d => %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x",
+ count,
+ game.scratch[count],
+ game.scratch[count + 1],
+ game.scratch[count + 2],
+ game.scratch[count + 3],
+ game.scratch[count + 4],
+ game.scratch[count + 5],
+ game.scratch[count + 6],
+ game.scratch[count + 7],
+ game.scratch[count + 8],
+ game.scratch[count + 9]);
+ }
+}
+
+
+static void game_global_update() {
+ int count;
+
+ debugger_name("4", 23);
+
+ for (count = 0; count < 220; count += 10) {
+ screen_printf(0, (count / 10) + 2, "%4d => %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x",
+ count,
+ global[count],
+ global[count + 1],
+ global[count + 2],
+ global[count + 3],
+ global[count + 4],
+ global[count + 5],
+ global[count + 6],
+ global[count + 7],
+ global[count + 8],
+ global[count + 9]);
+ }
+}
+
+
+
+
+static void game_help_update() {
+ debugger_name("5", 23);
+
+ game_file_show("*HELP.DB", 2);
+}
+
+
+
+static void game_conversation() {
+ /* pl
+ static int previous_running = -1000;
+ int x, y;
+ int count, count2;
+ int temp;
+ int my_status;
+ char temp_buf[80];
+ Conv *my_conv;
+ ConvData *my_data;
+
+ if (conv_control.running != previous_running) {
+ game_debugger_reset();
+ }
+
+ previous_running = conv_control.running;
+
+ debugger_name ("6", 23);
+
+ if (conv_control.running < 0) {
+ screen_printf (0, 2, "(Conversation system inactive).");
+ goto done;
+ } else {
+ screen_printf (0, 2, "Conversation: %d", conv_control.running);
+ }
+
+ my_conv = conv[conv_control.index];
+ my_data = conv_data[conv_control.index];
+
+ temp_buf[0] = 0;
+ if (conv_control.status == CONV_STATUS_HOLDING) {
+ my_status = conv_control.hold_status;
+ } else {
+ my_status = conv_control.status;
+ }
+
+ switch (my_status) {
+ case CONV_STATUS_NEXT_NODE:
+ Common::strcpy_s (temp_buf, "Next");
+ break;
+
+ case CONV_STATUS_WAIT_AUTO:
+ Common::strcpy_s (temp_buf, "W-auto");
+ break;
+
+ case CONV_STATUS_WAIT_ENTRY:
+ Common::strcpy_s (temp_buf, "W-entry");
+ break;
+
+ case CONV_STATUS_EXECUTE:
+ Common::strcpy_s (temp_buf, "Execute");
+ break;
+
+ case CONV_STATUS_REPLY:
+ default:
+ Common::strcpy_s (temp_buf, "Reply");
+ break;
+ }
+
+ if (conv_control.status == CONV_STATUS_HOLDING) {
+ Common::strcat_s (temp_buf, " HOLD");
+ }
+
+ if (conv_control.popup_is_up) {
+ Common::strcat_s (temp_buf, " Popup");
+ }
+
+ screen_printf (0, 4, "Status: %-70s", temp_buf);
+
+ screen_printf (0, 6, "Node: %-3d Entry: %-3d", conv_control.node, conv_control.entry);
+
+ screen_printf (0, 8, "Speaker: %-3d (Me: %-3d You: %-3d)", conv_control.person_speaking, conv_control.me_trigger, conv_control.you_trigger);
+ temp = conv_control.person_speaking;
+
+ screen_printf (0, 9, " X: %-6d <=J K=>", conv_control.x[temp]);
+ screen_printf (0, 10, " Y: %-6d <=I M=>", conv_control.y[temp]);
+ screen_printf (0, 11, " W: %-6d <=, .=>", conv_control.width[temp]);
+
+ for (count = 23; count < 143; count += 10) {
+ y = ((count - 23) / 10) + 13;
+ x = 0;
+ if (count < my_conv->num_variables) {
+ x = screen_printf (x, y, "%4d => ", count);
+ }
+ for (count2 = count; count2 < count + 10; count2++) {
+ if (count2 < my_conv->num_variables) {
+ x = screen_printf (x, y, "%04x ", *conv_get_variable(count2));
+ }
+ }
+ }
+
+ done:
+ ;
+ */
+}
+
+
+static void game_matte() {
+ int count;
+ int image_max;
+ int line;
+ int series_id;
+ char flags_buf[80];
+ char name_buf[80];
+ char sprite_buf[80];
+
+ Common::strcpy_s(flags_buf, "");
+ Common::strcpy_s(name_buf, "");
+ Common::strcpy_s(sprite_buf, "");
+
+ debugger_name("7", 23);
+
+ image_max = MIN<int>(23, image_marker);
+
+ for (count = 0; count < 23; count++) {
+ line = count + 2;
+ if (count < image_max) {
+ switch (image_list[count].flags) {
+ case IMAGE_UPDATE:
+ /* Common::strcpy_s (flags_buf, "Update"); */
+ break;
+
+ case IMAGE_STATIC:
+ /* Common::strcpy_s (flags_buf, "Static"); */
+ break;
+
+ case IMAGE_ERASE:
+ /* Common::strcpy_s (flags_buf, "Erase"); */
+ break;
+
+ case IMAGE_REFRESH:
+ /* Common::strcpy_s (flags_buf, "Refresh"); */
+ break;
+
+ case IMAGE_DELTA:
+ /* Common::strcpy_s (flags_buf, "Delta"); */
+ break;
+
+ default:
+ Common::sprintf_s(flags_buf, "(%d)", image_list[count].flags);
+ break;
+ }
+ if (image_list[count].flags != IMAGE_REFRESH) {
+ series_id = image_list[count].series_id;
+ Common::strcpy_s(name_buf, series_name[series_id]);
+ if (image_list[count].sprite_id & MIRROR_MASK) {
+ Common::sprintf_s(sprite_buf, "%dm", image_list[count].sprite_id & SPRITE_MASK);
+ } else {
+ Common::sprintf_s(sprite_buf, "%d", image_list[count].sprite_id);
+ }
+ } else {
+ series_id = -1;
+ Common::strcpy_s(name_buf, "sys");
+ Common::strcpy_s(sprite_buf, " ");
+ }
+
+ screen_printf(0, line, "%02d) %-8s = %-7s 0x%02x (%4d,%4d) Spr:%-4s Dep:%-2d Sc:%-3d",
+ count,
+ name_buf,
+ flags_buf,
+ image_list[count].segment_id,
+ image_list[count].x,
+ image_list[count].y,
+ sprite_buf,
+ image_list[count].depth,
+ image_list[count].scale);
+
+ } else {
+ screen_printf(0, line, "%02d) %-8s = %-7s %56s", count, "sys", "Empty", " ");
+ }
+ }
+}
+
+static void game_memory() {
+ if (mem_manager_active && debugger_memory_keywait) {
+ screen_normal_color = screen_hilite_color;
+ }
+
+ debugger_name("8", 23);
+
+ screen_normal_color = colorbyte(hi_white, black);
+
+ screen_printf(0, 2, "Cur: %-6ld Min: %-6ld Max: %-6ld",
+ mem_conv_get_avail(), mem_min_free, mem_max_free);
+
+ screen_printf(0, 8, "(DOS MCB memory map not available on this platform)");
+
+ screen_normal_color = colorbyte(hi_white, black);
+
+ if (mem_manager_active && debugger_memory_keywait) {
+ int mykey = keys_get();
+ debugger_name("8", 23);
+ if (mykey == esc_key) {
+ mem_manager_update = NULL;
+ debugger_memory_keywait = false;
+ error_report(ERROR_BREAK_POINT, WARNING, MODULE_UNKNOWN, 0, 0);
+ }
+ }
+}
+
+void state_display(int off, int x, int y) {
+ screen_printf(x, y, "%d", room_state[off]);
+}
+
+static void game_state() {
+ int count;
+
+ debugger_name("9", 23);
+
+ screen_printf(0, 2, "101");
+ screen_printf(0, 3, "103");
+ screen_printf(0, 4, "104");
+ screen_printf(0, 5, "106");
+ screen_printf(0, 6, "107");
+ screen_printf(0, 7, "110");
+ screen_printf(0, 8, "199");
+ screen_printf(0, 9, "201");
+ screen_printf(0, 10, "203");
+ screen_printf(0, 11, "204");
+ screen_printf(0, 12, "205");
+ screen_printf(0, 13, "210");
+ screen_printf(0, 14, "211");
+ screen_printf(0, 15, "220");
+ screen_printf(0, 16, "221");
+ screen_printf(0, 17, "301");
+ screen_printf(0, 18, "302");
+ screen_printf(0, 19, "303");
+ screen_printf(0, 20, "304");
+
+ screen_printf(30, 2, "305");
+ screen_printf(30, 3, "306");
+ screen_printf(30, 4, "307");
+ screen_printf(30, 5, "308");
+ screen_printf(30, 6, "320");
+ screen_printf(30, 7, "321");
+ screen_printf(30, 8, "322");
+ screen_printf(30, 9, "401");
+ screen_printf(30, 10, "402");
+ screen_printf(30, 11, "403");
+ screen_printf(30, 12, "404");
+ screen_printf(30, 13, "405");
+ screen_printf(30, 14, "420");
+ screen_printf(30, 15, "501");
+ screen_printf(30, 16, "503");
+ screen_printf(30, 17, "509");
+ screen_printf(30, 18, "510");
+ screen_printf(30, 19, "520");
+ screen_printf(30, 20, "521");
+
+
+ for (count = 0; count < 19; count++) {
+ state_display(count, 5, 2 + count);
+ }
+
+ for (count = 19; count < 38; count++) {
+ state_display(count, 35, count - 17);
+ }
+}
+
+
+
+void game_debugger() {
+ if (debugger_state != debugger_previous) game_debugger_reset();
+
+ switch (debugger_state) {
+ case DEBUGGER_MAIN:
+ game_main_update();
+ break;
+
+ case DEBUGGER_HELP:
+ if (debugger_state != debugger_previous) {
+ game_help_update();
+ }
+ break;
+
+ case DEBUGGER_PALETTE:
+ if ((debugger_state != debugger_previous) || (pal_manager_active)) {
+ game_palette_update();
+ }
+ break;
+
+ case DEBUGGER_SCRATCH:
+ game_scratch_update();
+ break;
+
+ case DEBUGGER_GLOBAL:
+ game_global_update();
+ break;
+
+ case DEBUGGER_CONVERSATION:
+ /* pl game_conversation(); */
+ break;
+
+ case DEBUGGER_MATTE:
+ game_matte();
+ break;
+
+ case DEBUGGER_MEMORY:
+ game_memory();
+ break;
+
+ case 8: /* DEBUGGER_STATE */
+ game_state();
+ break;
+ }
+
+ debugger_previous = debugger_state;
+}
+
+int main_cheating_key(int mykey) {
+ return g_engine->main_cheating_key(mykey);
+}
+
+int main_normal_key(int mykey) {
+ return g_engine->main_normal_key(mykey);
+}
+
+int main_copy_verify() {
+ return g_engine->main_copy_verify();
+}
+
+void main_cold_data_init() {
+ g_engine->main_cold_data_init();
+}
+
+void main_false_start() {
+ g_engine->main_cold_data_init();
+}
+
+void main_global_init_code() {
+ g_engine->main_global_init_code();
+}
+
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/core/game.h b/engines/mads/madsv2/core/game.h
index f1bf5311336..7fbbca412fc 100644
--- a/engines/mads/madsv2/core/game.h
+++ b/engines/mads/madsv2/core/game.h
@@ -260,10 +260,12 @@ int global_copy_verify(void);
/* game_1.c */
void game_main(int argc, char **argv);
-
/* game_2.c */
void game_save_name(int id);
+/* game_3.c */
+void game_set_camera_speed(void);
+
/* game_4.c */
void game_exec_function(void (*(target))());
@@ -288,6 +290,15 @@ void game_write_save_directory(void);
void game_menu_setup(void);
void game_menu_shutdown(void);
+/* Callback routines in game-specific MAIN module */
+int main_cheating_key(int mykey);
+int main_normal_key(int mykey);
+int main_copy_verify(void);
+void main_cold_data_init(void);
+void main_false_start(void);
+void main_global_init_code(void);
+
+
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/core/heap.cpp b/engines/mads/madsv2/core/heap.cpp
new file mode 100644
index 00000000000..e0ee60b32c6
--- /dev/null
+++ b/engines/mads/madsv2/core/heap.cpp
@@ -0,0 +1,86 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "mads/madsv2/core/heap.h"
+#include "mads/madsv2/core/mem.h"
+#include "mads/madsv2/core/error.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+int heap_create(Heap *heap, int module_id, long heap_size, const char *heap_name) {
+ int error_flag = true;
+
+ heap->module = (byte)module_id;
+
+ heap->base = (char *)mem_get_name(heap_size, heap_name);
+ if (heap->base == NULL) {
+ error_report(ERROR_HEAP_REQUEST_FAILED, ERROR, module_id, heap_size, mem_get_avail());
+ goto done;
+ }
+
+ heap->destruct = true;
+ heap->marker = heap->base;
+ heap->size = heap_size;
+ heap->base_size = heap_size;
+
+ error_flag = false;
+
+done:
+ return error_flag;
+}
+
+void heap_declare(Heap *heap, int module_id, char *buffer, long heap_size) {
+ heap->destruct = false;
+ heap->module = (byte)module_id;
+
+ heap->base = heap->marker = buffer;
+ heap->base_size = heap->size = heap_size;
+}
+
+void heap_destroy(Heap *heap) {
+ if (heap->destruct) {
+ mem_free(heap->base);
+ }
+
+ heap->base = NULL;
+ heap->size = 0;
+ heap->base_size = 0;
+}
+
+void *heap_get(Heap *heap, long size) {
+ char *result = NULL;
+
+ if (size > heap->size) {
+ error_report(ERROR_NO_MORE_HEAP, ERROR, heap->module, size, heap->size);
+ goto done;
+ }
+
+ result = heap->marker;
+ heap->marker += size;
+ heap->size -= size;
+
+done:
+ return (void *)result;
+}
+
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/core/heap.h b/engines/mads/madsv2/core/heap.h
index cfd0eb94dad..d6448d6f1d9 100644
--- a/engines/mads/madsv2/core/heap.h
+++ b/engines/mads/madsv2/core/heap.h
@@ -37,11 +37,9 @@ typedef struct {
} Heap;
/* heap_1.c */
-int heap_create(Heap *heap, int module_id,
- long heap_size, char *heap_name);
+int heap_create(Heap *heap, int module_id, long heap_size, const char *heap_name);
void heap_destroy(Heap *heap);
-void heap_declare(Heap *heap, int module_id,
- char *buffer, long heap_size);
+void heap_declare(Heap *heap, int module_id, char *buffer, long heap_size);
/* heap_1.c */
void *heap_get(Heap *heap, long size);
diff --git a/engines/mads/madsv2/core/imath.cpp b/engines/mads/madsv2/core/imath.cpp
new file mode 100644
index 00000000000..aec30708009
--- /dev/null
+++ b/engines/mads/madsv2/core/imath.cpp
@@ -0,0 +1,96 @@
+/* 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/util.h"
+#include "mads/madsv2/core/imath.h"
+#include "mads/madsv2/engine.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+int imath_isqrt(long square) {
+ if (square <= 0)
+ return 0;
+ return (int)sqrt((double)square);
+}
+
+int imath_hypot(int side_A, int side_B) {
+ long sum = (long)side_A * side_A + (long)side_B * side_B;
+ return imath_isqrt(sum);
+}
+
+int imath_distance(int side_A, int side_B, int thresh) {
+ int dx, dy, ds;
+
+ dx = ABS(side_A);
+ dy = ABS(side_B);
+
+ /* Ensure dx >= dy for the approximation formula. */
+ if (dx < dy) {
+ int tmp = dx; dx = dy; dy = tmp;
+ }
+
+ /* Base approximation: ds = dx + dy/4 */
+ ds = dx + (dy >> 2);
+
+ /* Correction term if 2*dy >= dx: ds += (2*dy - dx) * 3/16 */
+ if (2 * dy > dx) {
+ ds += ((2 * dy - dx) * 3) >> 4;
+ }
+
+ /* Subtract ~3% to ensure result is a lower bound. */
+ ds -= (ds >> 6); /* ds -= ds/64, approximately 1.5% ... */
+ /* Note: assembly uses shr cx,6 but comment says 3% - see below */
+
+ if (ds < thresh)
+ return imath_hypot(side_A, side_B);
+
+ return ds;
+}
+
+void imath_circular_arc(word *buffer, int radius) {
+ long y_value;
+ long radius_squared;
+ long difference;
+ word root;
+ int count;
+
+ radius_squared = ((long)radius << 2L);
+ radius_squared *= radius_squared;
+
+ for (count = 0; count < radius; count++) {
+ y_value = ((long)count << 2L);
+ y_value *= y_value;
+ difference = radius_squared - y_value;
+ root = imath_isqrt(difference);
+ root = root >> 1;
+ root++;
+ root = root >> 1;
+ buffer[count] = root;
+ }
+}
+
+int fastcall imath_random(int from, int unto) {
+ return g_engine->getRandomNumber(from, unto);
+}
+
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/core/imath.h b/engines/mads/madsv2/core/imath.h
index c6fe34220c8..ac0bafe80df 100644
--- a/engines/mads/madsv2/core/imath.h
+++ b/engines/mads/madsv2/core/imath.h
@@ -27,13 +27,28 @@
namespace MADS {
namespace MADSV2 {
-int imath_distance(int side_a, int side_b, int threshold);
-int imath_hypot(int side_a, int side_b);
-word imath_isqrt(long square);
+/**
+ * Distance: fast approximate hypotenuse with exact fallback.
+ * Uses an octagonal approximation with a correction term.
+ * Guaranteed to be a lower bound (underestimates by at most ~3%).
+ * Falls through to exact hypot if the estimate is below thresh.
+ */
+extern int imath_distance(int side_a, int side_b, int threshold);
+
+/**
+ * Exact integer hypotenuse via sum of squares.
+ */
+extern int imath_hypot(int side_a, int side_b);
+
+/**
+ * Integer square root (truncating).
+ * @return Returns 0 for negative input.
+ */
+extern int imath_isqrt(long square);
-void imath_circular_arc(word *buffer, int radius);
+extern void imath_circular_arc(word *buffer, int radius);
-int imath_random(int from, int unto);
+extern int imath_random(int from, int unto);
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/core/kernel.cpp b/engines/mads/madsv2/core/kernel.cpp
index 19453fa3e2f..477e3f7b857 100644
--- a/engines/mads/madsv2/core/kernel.cpp
+++ b/engines/mads/madsv2/core/kernel.cpp
@@ -1479,7 +1479,7 @@ void kernel_animation_init() {
}
}
-int kernel_run_animation(char *name, int trigger_code) {
+int kernel_run_animation(const char *name, int trigger_code) {
int result = -1;
int found = -1;
int error_flag = true;
diff --git a/engines/mads/madsv2/core/mouse.cpp b/engines/mads/madsv2/core/mouse.cpp
index bb66272dd90..d006aa52bdb 100644
--- a/engines/mads/madsv2/core/mouse.cpp
+++ b/engines/mads/madsv2/core/mouse.cpp
@@ -67,8 +67,14 @@ long mouse_clock = 0;
int mouse_hot_x = 0;
int mouse_hot_y = 0;
+int mouse_video_mode = 0;
+int mouse_init(int driverflag, int videomode) {
+ // No implementation
+ return 0;
+}
+
void mouse_show() {
if (!CursorMan.isVisible())
CursorMan.showMouse(true);
diff --git a/engines/mads/madsv2/core/mouse.h b/engines/mads/madsv2/core/mouse.h
index 5bd552b3751..623baedd040 100644
--- a/engines/mads/madsv2/core/mouse.h
+++ b/engines/mads/madsv2/core/mouse.h
@@ -55,82 +55,39 @@ extern int mouse_old_y; /* Cursor Y position on previous round */
extern long mouse_clock; /* Timing clock to insure at least 1 tick */
-/* mouse_1.cpp */
extern int mouse_init(int driver_flag, int mouse_video_mode);
-
-/* mouse_1.cpp */
extern int mouse_set_hotspot(int spot_x, int spot_y);
-
-void mouse_change_cursor_begin();
-void mouse_change_cursor_end();
-
-/* mouse_1.cpp */
+extern void mouse_change_cursor_begin();
+extern void mouse_change_cursor_end();
extern void mouse_screen_swap(int mouse_video_mode);
extern int mouse_get_video_mode();
-
-/* mouse_1.cpp */
extern void mouse_begin_double(int first_video_mode, int second_video_mode,
int mono_to_right, int auto_freedom);
extern void mouse_check_double();
extern void mouse_end_double();
extern void mouse_double_freedom(int freedom_flag);
-
-/* mouse_1.cpp */
extern void mouse_show();
extern void mouse_hide();
extern int mouse_get_status(int *x, int *y);
-
-/*
-int mouse_press_info (int button, int *status, int *x, int *y);
-int mouse_release_info (int button, int *status, int *x, int *y);
-
-int mouse_in_box_now (int ul_x, int ul_y, int lr_x, int lr_y);
-*/
-
-/* mouse_1.cpp */
extern void mouse_timing();
-
-/* mouse_1.cpp */
extern void mouse_freeze();
extern void mouse_thaw();
-
-
-/* mouse_1.cpp */
extern void mouse_horiz_bound(int min_x, int max_x);
extern void mouse_vert_bound(int min_y, int max_y);
-
-/* mouse_1.cpp */
extern void mouse_force(int x, int y);
-
-/* mouse_1.cpp */
extern void mouse_set_work_buffer(byte *work_buffer, int wrap_value);
extern void mouse_set_view_port_loc(int x1, int y1, int x2, int y2);
extern void mouse_set_view_port(int dx, int dy);
-
-/* mouse_1.cpp */
extern int mouse_refresh_view_port();
extern void mouse_refresh_done();
-
-/* mouse_1.cpp */
extern void mouse_disable_scale();
-
-/* mouse_1.cpp */
extern void mouse_hard_cursor_mode(int mode, Palette *mypal);
-
extern const byte *mouse_get_stack();
-
-/* mouse_2.cpp */
extern int mouse_in_box(int ul_x, int ul_y, int lr_x, int lr_y);
extern void mouse_init_cycle();
extern void mouse_begin_cycle(int double_flag);
extern void mouse_end_cycle(int double_flag, int timing_flag);
-
-
-/* mouse_3.cpp */
extern void mouse_cursor_sprite(SeriesPtr series, int id);
-
-
-/* mouse_4.cpp */
extern void mouse_video_init();
extern void mouse_video_update(int from_x, int from_y,
int unto_x, int unto_y, int size_x, int size_y);
diff --git a/engines/mads/madsv2/core/popup.cpp b/engines/mads/madsv2/core/popup.cpp
index a9dc8eb4310..9305b2aea7a 100644
--- a/engines/mads/madsv2/core/popup.cpp
+++ b/engines/mads/madsv2/core/popup.cpp
@@ -19,6 +19,7 @@
*
*/
+#include "common/textconsole.h"
#include "mads/madsv2/core/general.h"
#include "mads/madsv2/core/popup.h"
#include "mads/madsv2/core/kernel.h"
@@ -140,9 +141,12 @@ int popup_create(int horiz_pieces, int x, int y) {
error_flag = false;
done:
- return (error_flag);
+ return error_flag;
}
+int popup_create(FontPtr font, int horiz_pieces, int x, int y) {
+ error("TODO: popup_create");
+}
void popup_add_icon(SeriesPtr series, int id, int center) {
box->icon = series;
@@ -739,7 +743,7 @@ int popup_draw(int save_screen, int depth_code) {
error_flag = false;
done:
- return (error_flag);
+ return error_flag;
}
@@ -847,7 +851,7 @@ int popup_and_wait(int save_screen) {
error_flag = false;
done:
- return (error_flag);
+ return error_flag;
}
@@ -866,7 +870,7 @@ int popup_and_dont_wait(int save_screen) {
error_flag = false;
done:
- return (error_flag);
+ return error_flag;
}
@@ -1020,7 +1024,7 @@ done:
keys_enable();
popup_destroy();
Common::strcpy_s(target, 65536, temp_buf);
- return (error_flag);
+ return error_flag;
}
@@ -1045,7 +1049,7 @@ int popup_ask_number(long *value, int maxlen, int save_screen) {
done:
popup_asking_number = false;
- return (error_flag);
+ return error_flag;
}
@@ -1062,7 +1066,7 @@ int popup_estimate_pieces(int maxlen) {
}
-int popup_get_string(char *target, char *top, char *left, int maxlen) {
+int popup_get_string(char *target, const char *top, const char *left, int maxlen) {
int result = -1;
if (!popup_create(popup_estimate_pieces(strlen(top) + 4), POPUP_CENTER, POPUP_CENTER)) {
@@ -1078,7 +1082,7 @@ int popup_get_string(char *target, char *top, char *left, int maxlen) {
}
-int popup_get_long(long *value, char *top, char *left, int maxlen) {
+int popup_get_long(long *value, const char *top, const char *left, int maxlen) {
int error_flag = true;
if (!popup_create(popup_estimate_pieces(strlen(top) + 4), POPUP_CENTER, POPUP_CENTER)) {
@@ -1090,11 +1094,11 @@ int popup_get_long(long *value, char *top, char *left, int maxlen) {
error_flag = popup_ask_number(value, maxlen, true);
}
- return (error_flag);
+ return error_flag;
}
-int popup_get_number(int *value, char *top, char *left, int maxlen) {
+int popup_get_number(int *value, const char *top, const char *left, int maxlen) {
int result;
long temp;
@@ -1108,13 +1112,13 @@ int popup_get_number(int *value, char *top, char *left, int maxlen) {
}
-int popup_alert(int width, char *message_line, ...) {
+int popup_alert(int width, const char *message_line, ...) {
int mykey = -1;
int error_flag = true;
int popup_created = false;
int first_time = true;
va_list marker;
- char *my_message = message_line;
+ const char *my_message = message_line;
if (popup_create(popup_estimate_pieces(width), POPUP_CENTER, POPUP_CENTER)) goto done;
popup_created = true;
@@ -1132,10 +1136,9 @@ int popup_alert(int width, char *message_line, ...) {
done:
if (error_flag && popup_created) popup_destroy();
- return (mykey);
+ return mykey;
}
-
int popup_box_load(void) {
int error_flag = true;
int count;
@@ -1261,7 +1264,7 @@ done:
palette_low_search_limit = 0;
palette_high_search_limit = 256;
- return (error_flag);
+ return error_flag;
}
diff --git a/engines/mads/madsv2/core/popup.h b/engines/mads/madsv2/core/popup.h
index 291dff68c9d..abbfae1f753 100644
--- a/engines/mads/madsv2/core/popup.h
+++ b/engines/mads/madsv2/core/popup.h
@@ -410,6 +410,7 @@ extern BoxParam box_param;
/* popup_1.c */
int popup_create(int horiz_pieces, int x, int y);
+int popup_create(FontPtr font, int horiz_pieces, int x, int y);
void popup_add_icon(SeriesPtr series, int id, int center);
int popup_draw(int save_screen, int depth_code);
void popup_destroy(void);
@@ -436,16 +437,13 @@ int popup_ask_number(long *value, int maxlen, int save_screen);
/* popup_2.c */
-int popup_estimate_pieces(int maxlen);
-int popup_get_string(char *target, char *top,
- char *left, int maxlen);
-int popup_get_long(long *value, char *top,
- char *left, int maxlen);
-int popup_get_number(int *value, char *top,
- char *left, int maxlen);
+int popup_estimate_pieces(int maxlen);
+int popup_get_string(char *target, const char *top, const char *left, int maxlen);
+int popup_get_long(long *value, const char *top, const char *left, int maxlen);
+int popup_get_number(int *value, const char *top, const char *left, int maxlen);
/* popup_3.c */
-int popup_alert(int width, char *message_line, ...);
+int popup_alert(int width, const char *message_line, ...);
/* popup_4.c */
int popup_box_load(void);
diff --git a/engines/mads/madsv2/core/quote_1.cpp b/engines/mads/madsv2/core/quote.cpp
similarity index 81%
rename from engines/mads/madsv2/core/quote_1.cpp
rename to engines/mads/madsv2/core/quote.cpp
index 903e88056d8..852df82d483 100644
--- a/engines/mads/madsv2/core/quote_1.cpp
+++ b/engines/mads/madsv2/core/quote.cpp
@@ -93,11 +93,7 @@ char *quote_load(int quote_id, ...) {
quote_error = 3;
goto done;
}
- /*
- if (!fileio_read_till_null(work, handle)) {
- goto done;
- }
- */
+
if (now_reading == list[now_finding]) {
mem_needed = strlen(work) + 3;
total_mem_needed += mem_needed;
@@ -137,7 +133,50 @@ done:
fileio_suppress_unbuffering = false;
mem_restore_free();
- return (result);
+ return result;
+}
+
+char *quote_string(char *quote_list, int quote_id) {
+ int id;
+ char *result = NULL;
+ char *search;
+ char *marker;
+
+ for (marker = quote_list; *marker && (result == NULL); marker = search + 2) {
+ for (search = marker; *search; search++);
+ search++;
+ id = *((int *)search);
+ if (id == quote_id) result = marker;
+ }
+
+ return result;
+}
+
+void quote_split_string(const char *source, char *target1, char *target2) {
+ int count, len, half;
+ const char *mark;
+
+ len = strlen(source);
+
+ mark = source;
+ half = len >> 1;
+
+ for (count = 0; count < half; count++) {
+ *(target1++) = *(mark++);
+ }
+
+ while (*mark && (*mark != ' ')) {
+ *(target1++) = *(mark++);
+ }
+
+ while (*mark == ' ') mark++;
+
+ /* *(target1++) = '"'; */
+ *(target1++) = 0;
+
+ do {
+ *(target2++) = *mark;
+ } while (*(mark++));
}
} // namespace MADSV2
diff --git a/engines/mads/madsv2/core/quote.h b/engines/mads/madsv2/core/quote.h
index 61adfa45772..7bfdabcd048 100644
--- a/engines/mads/madsv2/core/quote.h
+++ b/engines/mads/madsv2/core/quote.h
@@ -31,16 +31,9 @@ namespace MADSV2 {
extern int quote_emergency;
-/* quote_1.c */
char *quote_load(int quote_id, ...);
-
-/* quote_2.c */
-char *quote_string(const char *quote_list, int quote_id);
-
-/* quote_3.c */
-void quote_split_string(char *source,
- char *target1,
- char *target2);
+char *quote_string(char *quote_list, int quote_id);
+void quote_split_string(const char *source, char *target1, char *target2);
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/core/rail.cpp b/engines/mads/madsv2/core/rail.cpp
index 1a21252b2cd..ebfcf26355d 100644
--- a/engines/mads/madsv2/core/rail.cpp
+++ b/engines/mads/madsv2/core/rail.cpp
@@ -32,6 +32,13 @@
namespace MADS {
namespace MADSV2 {
+word rail_solution_stack_pointer;
+word rail_solution_stack_weight;
+byte rail_visited[RAIL_MAX_NODES];
+byte rail_working_stack[RAIL_MAX_NODES];
+byte rail_solution_stack[RAIL_MAX_NODES];
+word rail_num_nodes;
+byte *rail_base;
byte rail_active[ROOM_MAX_RAILS + 2];
void rail_connect_node(int id) {
diff --git a/engines/mads/madsv2/core/room.cpp b/engines/mads/madsv2/core/room.cpp
new file mode 100644
index 00000000000..734f9d98562
--- /dev/null
+++ b/engines/mads/madsv2/core/room.cpp
@@ -0,0 +1,750 @@
+/* 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/file.h"
+#include "mads/madsv2/core/room.h"
+#include "mads/madsv2/core/attr.h"
+#include "mads/madsv2/core/env.h"
+#include "mads/madsv2/core/fileio.h"
+#include "mads/madsv2/core/buffer.h"
+#include "mads/madsv2/core/pal.h"
+#include "mads/madsv2/core/color.h"
+#include "mads/madsv2/core/error.h"
+#include "mads/madsv2/core/matte.h"
+#include "mads/madsv2/core/mads.h"
+#include "mads/madsv2/core/mem.h"
+#include "mads/madsv2/core/himem.h"
+#include "mads/madsv2/core/sprite.h"
+#include "mads/madsv2/core/loader.h"
+#include "mads/madsv2/core/tile.h"
+#include "mads/madsv2/core/screen.h"
+#include "mads/madsv2/core/keys.h"
+#include "mads/madsv2/core/mcga.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/inter.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+int room_load_error = 0;
+byte room_loaded_depth = false;
+byte room_loaded_walk = false;
+byte room_loaded_special = false;
+RoomPict roompict;
+
+static const char room_file_extension[5] = ".DAT";
+
+int room_read_def(int room_code, char *room_file, char *picture_base, int mads_mode) {
+ int result = -1;
+ int count;
+ char temp_buf[80];
+ Common::File handle;
+
+ room_file_name(temp_buf, ".DEF", room_code, room_file, mads_mode);
+
+ if (handle.open(temp_buf)) {
+ fileio_read_header(temp_buf, &handle);
+ if (strncmp(temp_buf, "ROOM", 4) != 0) goto done;
+ if (strncmp(&temp_buf[5], room_file_version, 4) != 0) goto done;
+ result = (int)fileio_fread_f(&roomdef, 1, sizeof(RoomDef), &handle);
+ result = (result != sizeof(RoomDef));
+ handle.close();
+ if (!result)
+ Common::strcpy_s(picture_base, 65536, roomdef.picture_base);
+
+ } else {
+ if (errno == ENOENT) {
+
+ roomdef.num_hotspots = 0;
+ roomdef.num_rails = 0;
+
+ for (count = 0; count < 10; count++) {
+ roomdef.misc[count] = 0;
+ }
+
+ roomdef.front_y = display_y - 1;
+ roomdef.back_y = 0;
+ roomdef.front_scale = 100;
+ roomdef.back_scale = 100;
+
+ for (count = 0; count < 16; count++) {
+ roomdef.depth_table[count] = 0;
+ }
+
+ roomdef.shadow.num_shadow_colors = 0;
+
+ Common::strcpy_s(roomdef.picture_base, picture_base);
+
+ result = 0;
+
+ } else {
+ result = -1;
+ }
+ }
+
+done:
+ return result;
+}
+
+void room_unload(RoomPtr roomPtr, Buffer *picture, Buffer *depth, Buffer *walk,
+ Buffer *special, TileMapHeader *pic_map, TileMapHeader *depthMap) {
+ room_dump_attribute(depth, walk, special, depthMap);
+
+ buffer_free(picture);
+ tile_map_free(pic_map);
+
+ if (roomPtr != NULL)
+ mem_free(roomPtr);
+}
+
+RoomPtr room_load(int id, int variant, const char *base_path, Buffer *picture,
+ Buffer *depth, Buffer *walk, Buffer *special, TileMapHeader *picMap,
+ TileMapHeader *depthMap, TileResource *picResource, TileResource *depthResource,
+ int picture_ems_handle, int depth_ems_handle, int load_flags) {
+ int error_flag = true;
+ int count;
+ long mem_needed;
+ Load load_handle;
+ RoomPtr roomPtr = NULL;
+ RoomFile roomfile;
+ char temp_buf[80];
+ char base[80];
+ char block_name[20];
+
+ room_unload(NULL, picture, depth, walk, special, picMap, depthMap);
+
+ /* Initialize structures */
+
+ mem_last_alloc_loader = MODULE_ROOM_LOADER;
+
+ load_handle.open = false;
+
+ /* Open the room data file */
+
+ room_resolve_base(base, temp_buf, id, base_path);
+
+ if (loader_open(&load_handle, temp_buf, "rb", true)) {
+ room_load_error = 1;
+ goto done;
+ }
+
+ /* Load room header block */
+
+ if (!loader_read(&roomfile, sizeof(RoomFile), 1, &load_handle)) {
+ room_load_error = 2;
+ goto done;
+ }
+
+ Common::strcpy_s(block_name, "$ROOM");
+ env_catint(block_name, id, 3);
+
+ /* Determine size needed for room data structure (based on # of rails) */
+
+ mem_needed = (sizeof(Room) - sizeof(Rail)) + (sizeof(Rail) * (roomfile.num_rails + 2));
+ roomPtr = (RoomPtr)mem_get_name(mem_needed, block_name);
+ if (roomPtr == NULL) {
+ room_load_error = 3;
+ goto done;
+ }
+
+ memcpy(&roomPtr->misc[0], &roomfile.misc[0], sizeof(int) * 10);
+ roomPtr->num_variants = roomfile.num_variants;
+ roomPtr->num_hotspots = roomfile.num_hotspots;
+ roomPtr->num_rails = roomfile.num_rails;
+ roomPtr->front_y = roomfile.front_y;
+ roomPtr->back_y = roomfile.back_y;
+ roomPtr->front_scale = roomfile.front_scale;
+ roomPtr->back_scale = roomfile.back_scale;
+ memcpy(&roomPtr->depth_table[0], &roomfile.depth_table[0], sizeof(int) << 4);
+
+ for (count = 0; count < roomfile.num_rails; count++) {
+ memcpy(&roomPtr->rail[count], &roomfile.rail[count], sizeof(Rail));
+ }
+
+ if (master_shadow != NULL) {
+ memcpy(&tile_shadow, &roomfile.shadow, sizeof(ShadowList));
+ load_flags |= TILE_MAP_SHADOW;
+ }
+
+ if (tile_load(base, TILE_PICTURE,
+ picResource,
+ picMap,
+ picture,
+ NULL, /* &color_list, */
+ &roomPtr->cycle_list,
+ picture_ems_handle,
+ load_flags)) {
+ room_load_error = 400 + tile_load_error;
+ goto done;
+ }
+
+ roomPtr->color_handle = picResource->color_handle;
+
+ roomPtr->xs = picMap->total_x_size;
+ roomPtr->ys = picMap->total_y_size;
+
+ if (room_load_variant(id, variant, base_path, roomPtr,
+ depth, walk, special,
+ depthMap, depthResource, depth_ems_handle)) {
+ goto done;
+ }
+
+ error_flag = false;
+
+done:
+ if (load_handle.open) loader_close(&load_handle);
+ if (error_flag) {
+ room_unload(roomPtr, picture, depth, walk, special, picMap, depthMap);
+ roomPtr = NULL;
+ }
+
+ return roomPtr;
+}
+
+void room_dump_attribute(Buffer *depth, Buffer *walk, Buffer *special,
+ TileMapHeader *depthMap) {
+ if (room_loaded_special) {
+ if (special != NULL) buffer_free(special);
+ room_loaded_special = false;
+ }
+
+ if (room_loaded_walk) {
+ if (walk != NULL) buffer_free(walk);
+ room_loaded_walk = false;
+ }
+
+ if (room_loaded_depth) {
+ if (depth != NULL) buffer_free(depth);
+ tile_map_free(depthMap);
+ room_loaded_depth = false;
+ }
+}
+
+int room_load_variant(int id, int variant, const char *base_path, RoomPtr roomPtr,
+ Buffer *depth, Buffer *walk, Buffer *special, TileMapHeader *depthMap,
+ TileResource *depthResource, int depth_ems_handle) {
+ int error_flag = true;
+ int xx, yy;
+ char base[80];
+
+ room_dump_attribute(depth, walk, special, depthMap);
+
+ room_resolve_base(base, NULL, id, base_path);
+
+ if ((depth != NULL) && (depthMap != NULL) && (depthResource != NULL)) {
+ if (tile_load(base, TILE_ATTRIBUTE + variant,
+ depthResource,
+ depthMap,
+ depth,
+ NULL, NULL,
+ depth_ems_handle, 0)) {
+ if ((tile_load_error == 1) && (variant > 0)) {
+ tile_load(base, TILE_ATTRIBUTE,
+ depthResource,
+ depthMap,
+ depth,
+ NULL, NULL,
+ depth_ems_handle, 0);
+ }
+ if (tile_load_error > 1) {
+ room_load_error = 5100 + tile_load_error;
+ goto done;
+ } else if (tile_load_error == 1) {
+ xx = MIN(video_x, roomPtr->xs);
+ yy = MIN(display_y, roomPtr->ys);
+
+ buffer_init_name(depth, xx >> 1, yy, "$scrdpth");
+ if (depth->data == NULL) {
+ room_load_error = 5100;
+ goto done;
+ }
+
+ buffer_fill(*depth, 0xff);
+
+ tile_fake_map(TILE_ATTRIBUTE + variant,
+ depthMap,
+ depth, xx, yy);
+ }
+ }
+
+ room_loaded_depth = true;
+ }
+
+ if (walk != NULL) {
+ if (attr_load(base, ROOM_WALK,
+ variant,
+ walk,
+ roomPtr->xs,
+ roomPtr->ys)) {
+ if (attr_load_error) {
+ room_load_error = 5200 + attr_load_error;
+ goto done;
+ }
+ } else {
+ room_loaded_walk = true;
+ }
+ }
+
+ if (special != NULL) {
+ if (attr_load(base, ROOM_SPECIAL,
+ variant,
+ special,
+ roomPtr->xs,
+ roomPtr->ys)) {
+ if (attr_load_error) {
+ room_load_error = 5300 + attr_load_error;
+ goto done;
+ }
+ } else {
+ room_loaded_special = true;
+ }
+ }
+
+ error_flag = false;
+
+done:
+ if (error_flag) {
+ room_dump_attribute(depth, walk, special, depthMap);
+ }
+
+ return (error_flag);
+}
+
+
+int room_compile_hotspots(int id, int compression) {
+ int error_flag;
+ int num_spots;
+ int loaded_it_here = false;
+ int count;
+ char temp_buf[80];
+ HotSpotEdit hotspotedit;
+ HotSpot hotspot[ROOM_MAX_HOTSPOTS];
+ Common::SeekableReadStream *handle;
+ Load load_handle;
+
+ error_flag = true;
+
+ handle = NULL;
+ load_handle.open = false;
+
+ if (vocab_allocation == 0) {
+ if (vocab_load(true) <= 0) {
+ if (vocab_load(false) <= 0) goto done;
+ }
+ loaded_it_here = true;
+ }
+
+ handle = env_open_level(ROOM, ".HOT", 0, id, "rb");
+ if (handle == NULL) goto done;
+
+ env_get_level_path(temp_buf, ROOM, ".HH", 0, id);
+ if (loader_open(&load_handle, temp_buf, "wb", compression)) goto done;
+ loader_set_priority(&load_handle, PACK_PRIORITY_ROOM_HOTSPOTS);
+
+ if (!fileio_fread_f(&num_spots, sizeof(int), 1, handle)) goto done;
+ if (!loader_write(&num_spots, sizeof(int), 1, &load_handle)) goto done;
+
+ for (count = 0; count < num_spots; count++) {
+ if (!fileio_fread_f(&hotspotedit, sizeof(HotSpotEdit), 1, handle)) goto done;
+ memcpy(&hotspot[count], &hotspotedit, sizeof(HotSpot));
+ hotspot[count].vocab = vocab_get_code(hotspotedit.vocab);
+ if (hotspot[count].vocab == 0) {
+ hotspot[count].vocab = vocab_add_word(hotspotedit.vocab);
+ }
+ if (strlen(hotspotedit.verb) == 0) {
+ hotspot[count].verb = 0;
+ } else {
+ hotspot[count].verb = vocab_get_code(hotspotedit.verb);
+ if (hotspot[count].verb == 0) {
+ hotspot[count].verb = vocab_add_word(hotspotedit.verb);
+ }
+ }
+ hotspot[count].cursor_number = hotspotedit.cursor_number;
+ hotspot[count].syntax = hotspotedit.syntax;
+ hotspot[count].active = true;
+ }
+ num_spots = MAX(num_spots, 1);
+ if (!loader_write(&hotspot[0], sizeof(HotSpot) * num_spots, 1, &load_handle)) goto done;
+
+ error_flag = false;
+
+done:
+ delete handle;
+ if (load_handle.open)
+ loader_close(&load_handle);
+ if (loaded_it_here) {
+ vocab_destroy();
+ }
+ return (error_flag);
+}
+
+
+HotPtr room_load_hotspots(int id, int *num_spots) {
+ HotPtr spots;
+ HotPtr result = NULL;
+ Load load_handle;
+ long memory_needed;
+ int num_to_read;
+ char temp_buf[80];
+
+ load_handle.open = false;
+
+ spots = NULL;
+
+ /* env_get_level_path (temp_buf, ROOM, ".HH", 0, id); */
+ Common::strcpy_s(temp_buf, "*RM");
+ env_catint(temp_buf, id, 3);
+ Common::strcat_s(temp_buf, ".HH");
+ if (loader_open(&load_handle, temp_buf, "rb", true)) goto done;
+
+ if (!loader_read(num_spots, sizeof(int), 1, &load_handle)) goto done;
+
+ num_to_read = MAX(*num_spots, 1);
+ memory_needed = (num_to_read * sizeof(HotSpot));
+
+ spots = (HotPtr)mem_get_name(memory_needed, "$hotspot");
+ if (spots == NULL) goto done;
+
+ if (!loader_read(spots, memory_needed, 1, &load_handle)) goto done;
+
+ result = spots;
+
+done:
+ if (load_handle.open) loader_close(&load_handle);
+ if (result == NULL) {
+ if (spots != NULL) {
+ mem_free(spots);
+ }
+ }
+
+ return result;
+}
+
+
+/*
+/* room_read_pict()
+/*
+/* Reads the . file for the specified room into the "room" structure.
+/*
+/* Returns 0 if successful, or -1 for error.
+*/
+int room_read_pict(int room_code, char *room_file, int mads_mode) {
+ int result = -1;
+ int count;
+ char temp_buf[80];
+ Common::File handle;
+
+ room_file_name(temp_buf, ".PCT", room_code, room_file, mads_mode);
+
+ if (handle.open(temp_buf)) {
+ fileio_read_header(temp_buf, &handle);
+ if (strncmp(temp_buf, "ROOM", 4) != 0) goto done;
+ if (strncmp(&temp_buf[5], pict_file_version, 4) != 0) goto done;
+ result = !fileio_fread_f(&roompict, sizeof(RoomPict), 1, &handle);
+ roompict.id = room_code;
+ } else {
+ if (errno == ENOENT) {
+
+ roompict.id = room_code;
+ roompict.picture_id = room_code;
+ roompict.format = ROOM_FORMAT_NORMAL;
+
+ roompict.xs = video_x;
+ roompict.ys = display_y;
+
+ for (count = 0; count < 10; count++) {
+ roompict.misc[count] = 0;
+ }
+
+ roompict.num_series = 0;
+ roompict.num_images = 0;
+
+ roompict.num_variants = 0;
+ roompict.num_translated = 0;
+
+ roompict.color_list.num_colors = 0;
+ roompict.cycle_list.num_cycles = 0;
+
+ Common::strcpy_s(roompict.variant_desc[0], "The One True Variant");
+ Common::strcpy_s(roompict.variant_desc[1], "False Variant");
+ Common::strcpy_s(roompict.variant_desc[2], "Blasphemous Variant");
+ Common::strcpy_s(roompict.variant_desc[3], "Heretical Variant");
+ Common::strcpy_s(roompict.variant_desc[4], "Usurper Variant");
+ Common::strcpy_s(roompict.variant_desc[5], "Untrue Variant");
+ Common::strcpy_s(roompict.variant_desc[6], "Most Untrue Variant");
+ Common::strcpy_s(roompict.variant_desc[7], "Why so many variants, eh, boy?");
+ Common::strcpy_s(roompict.variant_desc[8], "Geez, guys! C'moff it already!");
+ Common::strcpy_s(roompict.variant_desc[9], "And THAT is absolutely IT, dammit!");
+
+ if (!mads_mode) {
+ Common::strcpy_s(roompict.artwork_file, room_file);
+ }
+
+ result = 0;
+
+ } else {
+ result = -1;
+ }
+ }
+
+done:
+ return result;
+}
+
+void room_file_name(char *target, const char *suffix, int code, char *main_name, int mads_mode) {
+ char *mark;
+
+ if (mads_mode) {
+ env_get_level_path(target, ROOM, suffix, 0, code);
+ } else {
+ mark = strchr(main_name, '.');
+ if (mark != NULL) {
+ *mark = 0;
+ }
+
+ Common::strcpy_s(target, 65536, main_name);
+
+ if (mark != NULL) {
+ *mark = '.';
+ }
+
+ Common::strcat_s(target, 65536, suffix);
+ mads_strupr(target);
+ }
+}
+
+
+void room_himem_preload(int roomNum, int level) {
+ himem_preload_series(kernel_full_name(roomNum, 0, -1, NULL, KERNEL_DAT), level);
+ himem_preload_series(kernel_full_name(roomNum, 0, -1, NULL, KERNEL_HH), level);
+
+ /* himem_preload_series (kernel_full_name (room, 0, -1, NULL, KERNEL_TT), level); */
+ himem_preload_series(kernel_full_name(roomNum, 0, -1, NULL, KERNEL_MM), level);
+ himem_preload_series(kernel_full_name(roomNum, 0, -1, NULL, KERNEL_WW), level);
+
+ /* himem_preload_series (kernel_full_name (room, 0, 0, NULL, KERNEL_TT), level); */
+ himem_preload_series(kernel_full_name(roomNum, 0, 0, NULL, KERNEL_MM), level);
+ himem_preload_series(kernel_full_name(roomNum, 0, 0, NULL, KERNEL_WW), level);
+}
+
+
+int room_picture_load(int roomId, Buffer *picture, int load_flags) {
+ int error_flag = true;
+ int xs, ys;
+ int color_handle;
+ long picture_size;
+ char temp_buf[80];
+ RoomArt art;
+ Load load_handle;
+
+ load_handle.open = false;
+
+ env_get_level_path(temp_buf, ROOM, ".ART", 0, roomId);
+ if (loader_open(&load_handle, temp_buf, "rb", true)) {
+ room_load_error = 1;
+ goto done;
+ }
+
+ if (!loader_read(&art, sizeof(RoomArt), 1, &load_handle)) {
+ room_load_error = 2;
+ goto done;
+ }
+
+ xs = art.xs;
+ ys = art.ys;
+
+ picture_size = (long)xs * (long)ys;
+
+ buffer_init(picture, xs, ys);
+ if (picture->data == NULL) {
+ room_load_error = 3;
+ goto done;
+ }
+
+ /* memcpy (&room->cycle_list, &art.cycle_list, sizeof(CycleList)); */
+
+ if (!(load_flags & ROOM_LOAD_TRANSLATE)) {
+ color_handle = pal_allocate(&art.color_list, NULL, (load_flags & PAL_MAP_MASK));
+ if (color_handle < 0) {
+ room_load_error = 4;
+ goto done;
+ }
+ }
+
+ if (!loader_read(picture->data, picture_size, 1, &load_handle)) {
+ room_load_error = 5;
+ goto done;
+ }
+
+ if (!(load_flags & ROOM_LOAD_TRANSLATE)) {
+ color_buffer_list_to_main(&art.color_list, picture);
+ } else {
+#ifdef sixteen_color
+ color_buffer_list_to_x16(&art.color_list, picture);
+#endif
+ }
+
+ error_flag = false;
+
+done:
+ if (error_flag) {
+ if (picture->data != NULL) buffer_free(picture);
+ }
+ if (load_handle.open) {
+ loader_close(&load_handle);
+ }
+ return (error_flag);
+}
+
+
+void room_resolve_base(char *base, char *file, int id, char *base_path) {
+ int mads_mode;
+
+ mads_mode = !(id < 0);
+
+ if (mads_mode) {
+ Common::strcpy_s(base, 65536, "*RM");
+ env_catint(base, id, 3);
+ if (file != NULL) {
+ env_get_level_path(file, ROOM, room_file_extension, 0, id);
+ }
+ } else {
+ Common::strcpy_s(base, 65536, base_path);
+ if (file != NULL) {
+ file[0] = 0;
+ if (env_search_mode == ENV_SEARCH_CONCAT_FILES) {
+ Common::strcat_s(file, 65536, "*");
+ }
+ Common::strcat_s(file, 65536, base_path);
+ Common::strcat_s(file, 65536, room_file_extension);
+ env_get_path(file, file);
+ }
+ }
+}
+
+static void room_buffer_invert(Buffer *buffer, byte *work, int granularity) {
+ int wrap, y;
+ int count;
+ byte *scan;
+
+ y = buffer->y;
+ wrap = buffer->x;
+ scan = buffer->data;
+
+ for (count = 0; count < y; count++) {
+ byte *src, *dst;
+ int i;
+
+ /* Copy row into work buffer. */
+ memcpy(work, scan, wrap);
+
+ src = work;
+ dst = scan + wrap - 1; /* dst walks right-to-left through scan */
+
+ for (i = 0; i < wrap; i++) {
+ byte al = *src++;
+
+ if (granularity == 8) {
+ /* Reverse all 8 bits. */
+ byte ah = 0;
+ int b;
+ for (b = 0; b < 8; b++) {
+ ah = (ah >> 1) | (al << 7); /* rcr ah,1 / shl al,1 pair */
+ al <<= 1;
+ }
+ al = ah;
+ } else if (granularity == 2) {
+ /* Swap the two nibbles. */
+ al = (al >> 4) | (al << 4); /* ror al,4 */
+ }
+ /* granularity == 1: byte value is used as-is */
+
+ *dst-- = al;
+ }
+
+ scan = (byte *)mem_check_overflow(scan + wrap);
+ }
+}
+
+int room_invert(void) {
+ int error_flag = true;
+ int count;
+ int x1, x2;
+ int facing;
+ byte *work = NULL;
+
+ work = (byte *)mem_get(1024);
+ if (work == NULL) goto done;
+
+ room_buffer_invert(&scr_orig, work, 1);
+ room_buffer_invert(&scr_depth, work, 2);
+ if (scr_walk.data != NULL) room_buffer_invert(&scr_walk, work, 8);
+ if (scr_special.data != NULL) room_buffer_invert(&scr_special, work, 8);
+
+ for (count = 0; count < room->num_rails; count++) {
+ room->rail[count].x = (picture_map.total_x_size - 1) - room->rail[count].x;
+ }
+
+ for (count = 0; count < room_num_spots; count++) {
+ x1 = (picture_map.total_x_size - 1) - room_spots[count].ul_x;
+ x2 = (picture_map.total_x_size - 1) - room_spots[count].lr_x;
+ room_spots[count].ul_x = x2;
+ room_spots[count].lr_x = x1;
+
+ if (room_spots[count].feet_x >= 0) {
+ room_spots[count].feet_x = (picture_map.total_x_size - 1) - room_spots[count].feet_x;
+ }
+
+ facing = room_spots[count].facing;
+ switch (facing) {
+ case 7:
+ case 4:
+ case 1:
+ facing += 2;
+ break;
+
+ case 9:
+ case 6:
+ case 3:
+ facing -= 2;
+ break;
+ }
+
+ room_spots[count].facing = (byte)facing;
+
+ if (room_spots[count].cursor_number == 6) {
+ room_spots[count].cursor_number = 5;
+ } else if (room_spots[count].cursor_number == 5) {
+ room_spots[count].cursor_number = 6;
+ }
+ }
+
+ kernel_set_interface_mode(inter_input_mode);
+
+ error_flag = false;
+
+done:
+ if (work != NULL) mem_free(work);
+ return (error_flag);
+}
+
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/core/screen.cpp b/engines/mads/madsv2/core/screen.cpp
index e1c7a09143b..33bf6e2bea3 100644
--- a/engines/mads/madsv2/core/screen.cpp
+++ b/engines/mads/madsv2/core/screen.cpp
@@ -146,5 +146,30 @@ short screen_show_wide(const char *outstring, short locx, short locy, short widt
return 0;
}
+int screen_show(const char *outstring, int locx, int locy) {
+ locx = screen_put(outstring, screen_normal_color, screen_hilite_color, locx, locy);
+ return (locx);
+}
+
+int screen_printf(int x, int y, const char *string, ...) {
+ va_list va;
+ va_start(va, string);
+ Common::String msg = Common::String::vformat(string, va);
+ va_end(va);
+
+ screen_show(msg.c_str(), x, y);
+ return 0;
+}
+
+int screen_print(const char *string, ...) {
+ va_list va;
+ va_start(va, string);
+ Common::String msg = Common::String::vformat(string, va);
+ va_end(va);
+
+ screen_write(msg.c_str());
+ return 0;
+}
+
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/core/screen.h b/engines/mads/madsv2/core/screen.h
index 1b2b30e53ad..ad8d78e8d5a 100644
--- a/engines/mads/madsv2/core/screen.h
+++ b/engines/mads/madsv2/core/screen.h
@@ -106,9 +106,8 @@ void screen_init_graphics(int which_mode);
void screen_shutdown_graphics(int clear_flag);
void screen_show_spot(const char *message, int wx, int wy, int class_, int num);
-/* DO NOT USE */
-//int screen_printf(int x, int y, char *string, ...);
-//int screen_print(char *string, ...);
+int screen_printf(int x, int y, const char *string, ...);
+int screen_print(const char *string, ...);
void screen_init_text(int which_mode);
void screen_shutdown_text(int clear_flag);
diff --git a/engines/mads/madsv2/core/timer.cpp b/engines/mads/madsv2/core/timer.cpp
index f4521db8714..d19f5ac2b7b 100644
--- a/engines/mads/madsv2/core/timer.cpp
+++ b/engines/mads/madsv2/core/timer.cpp
@@ -29,6 +29,10 @@ namespace MADSV2 {
long *timer_address = dos_timer_address;
word timer_rate = 20;
int timer_service_active = false;
+word timer_sound_on;
+word timer_noise_on;
+byte timer_copy_protect_in = 0;
+byte timer_copy_protect_out = 0;
extern long timer_600_low;
extern long timer_60_low;
@@ -87,5 +91,36 @@ void timer_set_rate(word count_down) {
#endif
}
+void timer_install() {
+ // No implementation in ScummVM
+}
+
+void timer_remove() {
+ // No implementation in ScummVM
+}
+
+void timer_set_sound_flag(int sound_flag) {
+ timer_sound_on = sound_flag;
+ timer_noise_on = sound_flag;
+}
+
+int timer_set_copy_protect(int protect) {
+ timer_copy_protect_in = protect;
+ timer_copy_protect_out = timer_copy_protect_in;
+ return protect;
+}
+
+int timer_get_copy_protect() {
+ return timer_copy_protect_out;
+}
+
+void timer_activate_low_priority(void (*(routine))()) {
+ warning("TODO: timer_activate_low_priority");
+}
+
+byte *timer_get_interrupt_stack(void) {
+ error("TODO: timer_get_interrupt_stack");
+}
+
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/core/timer.h b/engines/mads/madsv2/core/timer.h
index 0d2d51435c5..92d2404046c 100644
--- a/engines/mads/madsv2/core/timer.h
+++ b/engines/mads/madsv2/core/timer.h
@@ -53,17 +53,28 @@ long timer_read(void);
long timer_read_dos(void);
long timer_read_600(void);
long timer_read_60(void);
-
-
-/* timer_2.c */
void timer_set_rate(word count_down);
+/**
+ * Installs the timer interrupt handler
+ */
+void timer_install();
+
+/**
+ * Removes timer interrupt handler
+ */
+void timer_remove();
-/* timer_3.asm */
-void timer_install(void);
-void timer_remove(void);
+/**
+ * Activates or deactivates timer sound support.
+ */
void timer_set_sound_flag(int sound_flag);
+
+/**
+ * Designates a low priority routine. Pass NULL (0) to deactivate.
+ */
void timer_activate_low_priority(void (*(routine))());
+
byte *timer_get_interrupt_stack(void);
int timer_set_copy_protect(int protect);
diff --git a/engines/mads/madsv2/core/window.cpp b/engines/mads/madsv2/core/window.cpp
index bf518981c34..132f222faa1 100644
--- a/engines/mads/madsv2/core/window.cpp
+++ b/engines/mads/madsv2/core/window.cpp
@@ -75,7 +75,7 @@ void window_line_across(WindowPtr window, int line_y) {
}
}
-void window_color(WindowPtr window, short new_col) {
+void window_color(WindowPtr window, int new_col) {
short x_count, y_count;
for (y_count = window->ul_y; y_count <= window->lr_y; y_count++) {
diff --git a/engines/mads/madsv2/core/window.h b/engines/mads/madsv2/core/window.h
index 2cd6f53cc92..d191a905b4f 100644
--- a/engines/mads/madsv2/core/window.h
+++ b/engines/mads/madsv2/core/window.h
@@ -112,12 +112,12 @@ extern void window_set(WindowPtr window, int ul_x, int ul_y, int lr_x, int lr_y)
/**
* Draws a line across a window, joining with the edges
*/
-extern void window_line_across(WindowPtr window, short line_y);
+extern void window_line_across(WindowPtr window, int line_y);
/**
* Sets the color byte for all characters in region
*/
-extern void window_color(WindowPtr window, short new_color);
+extern void window_color(WindowPtr window, int new_color);
/**
* Clears (sets to space) specified region
@@ -146,17 +146,17 @@ extern int window_vert_detect(WindowPtr window, int x, int y,
/**
* Draws up a horizontal scroll bar for the specified window
*/
-extern void window_horiz_scrollbar(WindowPtr window, short bar_color);
+extern void window_horiz_scrollbar(WindowPtr window, int bar_color);
/**
* Draws up a vertical scroll bar for the specified window
*/
-extern void window_vert_scrollbar(WindowPtr window, short bar_color);
+extern void window_vert_scrollbar(WindowPtr window, int bar_color);
/**
* Draws the title of the specified window
*/
-extern void window_title(WindowPtr window, const char *title, short title_color, short background_color);
+extern void window_title(WindowPtr window, const char *title, int title_color, int background_color);
extern void window_abort(const char *message);
extern byte *window_create(WindowPtr window);
extern void window_destroy(WindowPtr window);
diff --git a/engines/mads/madsv2/engine.h b/engines/mads/madsv2/engine.h
index fe7bceb2fd6..a233908cf4b 100644
--- a/engines/mads/madsv2/engine.h
+++ b/engines/mads/madsv2/engine.h
@@ -50,6 +50,9 @@ public:
uint getRandomNumber(uint max) {
return _random.getRandomNumber(max);
}
+ uint getRandomNumber(uint min, uint max) {
+ return min + _random.getRandomNumber(max - min);
+ }
Graphics::Screen *getScreen() const {
return _screen;
@@ -58,6 +61,22 @@ public:
bool hasPendingKey();
int getKey();
void flushKeys();
+
+ /* Callback routines in game-specific MAIN module */
+ int main_cheating_key(int mykey) {
+ return 0;
+ }
+ int main_normal_key(int mykey) {
+ return 0;
+ }
+ int main_copy_verify(void) {
+ return 0;
+ }
+ void main_cold_data_init(void) {}
+ void main_false_start(void) {}
+ void main_global_init_code(void) {}
+ void section_music(int section_num) {}
+ void game_control_loop() {}
};
extern MADSV2Engine *g_engine;
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index 5a5ae5ae7f2..a3457ee3d6d 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -60,8 +60,11 @@ MODULE_OBJS += \
forest/forest_scenes.o \
forest/globals_forest.o \
madsv2/engine.o \
+ madsv2/core/anim.o \
+ madsv2/core/attr.o \
madsv2/core/buffer.o \
madsv2/core/camera.o \
+ madsv2/core/copy.o \
madsv2/core/cursor.o \
madsv2/core/cycle.o \
madsv2/core/dialog.o \
@@ -70,8 +73,11 @@ MODULE_OBJS += \
madsv2/core/error.o \
madsv2/core/fileio.o \
madsv2/core/font.o \
+ madsv2/core/game.o \
+ madsv2/core/heap.o \
madsv2/core/himem.o \
madsv2/core/hspot.o \
+ madsv2/core/imath.o \
madsv2/core/inter.o \
madsv2/core/kernel.o \
madsv2/core/keys.o \
@@ -87,7 +93,7 @@ MODULE_OBJS += \
madsv2/core/pal.o \
madsv2/core/player.o \
madsv2/core/popup.o \
- madsv2/core/quote_1.o \
+ madsv2/core/quote.o \
madsv2/core/rail.o \
madsv2/core/room.o \
madsv2/core/screen.o \
Commit: e9568f29d5718990a98425c1dd13a5991ccd9f7d
https://github.com/scummvm/scummvm/commit/e9568f29d5718990a98425c1dd13a5991ccd9f7d
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:19:07+10:00
Commit Message:
MADS: PHANTOM: Added more core files
Changed paths:
A engines/mads/madsv2/core/color.cpp
A engines/mads/madsv2/core/config.cpp
A engines/mads/madsv2/core/digi.cpp
A engines/mads/madsv2/core/extra.cpp
A engines/mads/madsv2/core/global.cpp
A engines/mads/madsv2/core/implode.cpp
A engines/mads/madsv2/core/lib.cpp
A engines/mads/madsv2/core/midi.cpp
A engines/mads/madsv2/core/pfab.cpp
A engines/mads/madsv2/core/sound.cpp
A engines/mads/madsv2/core/video.cpp
R engines/mads/madsv2/core/buffer_2.cpp
R engines/mads/madsv2/core/buffer_3.cpp
R engines/mads/madsv2/core/video_1.cpp
engines/mads/madsv2/core/buffer.cpp
engines/mads/madsv2/core/buffer.h
engines/mads/madsv2/core/color.h
engines/mads/madsv2/core/demo.h
engines/mads/madsv2/core/dialog.cpp
engines/mads/madsv2/core/dialog.h
engines/mads/madsv2/core/digi.h
engines/mads/madsv2/core/ems.h
engines/mads/madsv2/core/env.cpp
engines/mads/madsv2/core/env.h
engines/mads/madsv2/core/error.cpp
engines/mads/madsv2/core/error.h
engines/mads/madsv2/core/fileio.cpp
engines/mads/madsv2/core/font.cpp
engines/mads/madsv2/core/game.cpp
engines/mads/madsv2/core/game.h
engines/mads/madsv2/core/global.h
engines/mads/madsv2/core/imath.cpp
engines/mads/madsv2/core/implode.h
engines/mads/madsv2/core/inter.cpp
engines/mads/madsv2/core/kernel.cpp
engines/mads/madsv2/core/keys.cpp
engines/mads/madsv2/core/magic.cpp
engines/mads/madsv2/core/mcga.cpp
engines/mads/madsv2/core/mem.cpp
engines/mads/madsv2/core/mouse.cpp
engines/mads/madsv2/core/mouse.h
engines/mads/madsv2/core/pack.cpp
engines/mads/madsv2/core/pfab.h
engines/mads/madsv2/core/player.cpp
engines/mads/madsv2/core/qual.h
engines/mads/madsv2/core/rail.cpp
engines/mads/madsv2/core/rail.h
engines/mads/madsv2/core/room.cpp
engines/mads/madsv2/core/room.h
engines/mads/madsv2/core/screen.cpp
engines/mads/madsv2/core/sort.h
engines/mads/madsv2/core/speech.cpp
engines/mads/madsv2/core/tile.h
engines/mads/madsv2/core/timer.cpp
engines/mads/madsv2/core/vocab.cpp
engines/mads/madsv2/core/vocab.h
engines/mads/madsv2/phantom/main_menu.cpp
engines/mads/module.mk
diff --git a/engines/mads/madsv2/core/buffer.cpp b/engines/mads/madsv2/core/buffer.cpp
index 1464fcbd76c..3da3fa7e3b0 100644
--- a/engines/mads/madsv2/core/buffer.cpp
+++ b/engines/mads/madsv2/core/buffer.cpp
@@ -19,10 +19,14 @@
*
*/
+#include "common/system.h"
+#include "common/savefile.h"
#include "common/util.h"
#include "mads/madsv2/core/general.h"
#include "mads/madsv2/core/buffer.h"
+#include "mads/madsv2/core/env.h"
#include "mads/madsv2/core/ems.h"
+#include "mads/madsv2/core/fileio.h"
#include "mads/madsv2/core/mem.h"
#include "mads/madsv2/core/room.h"
@@ -37,6 +41,10 @@ int buffer_restore_keep_flag = false;
static word accum; /* Pattern accumulator */
static Buffer buffer_preserve_conventional;
+char buffer_disk_filename[8] = "$MPOP.$";
+byte buffer_accum = 0;
+byte buffer_tracking[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
bool buffer_init(Buffer *buf, word x, word y) {
buf->data = (byte *)mem_get((long)x * y);
@@ -864,5 +872,104 @@ bool buffer_from_ems(Buffer *source, int page_handle, int target_ems_handle,
return page_handle;
}
+bool buffer_rect_translate(Buffer from, Buffer unto, int from_x, int from_y,
+ int unto_x, int unto_y, int size_x, int size_y, byte *table) {
+ int from_wrap, unto_wrap;
+ int row_count;
+ int result;
+ byte *from_ptr;
+ byte *unto_ptr;
+
+ from_wrap = from.x - size_x;
+ unto_wrap = unto.x - size_x;
+
+ result = ((from.data != NULL) && (unto.data != NULL));
+ if (result) {
+ if (size_y == 0 || size_x == 0)
+ return result;
+
+ from_ptr = buffer_pointer(&from, from_x, from_y);
+ unto_ptr = buffer_pointer(&unto, unto_x, unto_y);
+
+ for (row_count = size_y; row_count > 0; row_count--) {
+ for (int col = 0; col < size_x; col++) {
+ *unto_ptr++ = table[*from_ptr++];
+ }
+ from_ptr += from_wrap;
+ unto_ptr += unto_wrap;
+ }
+ }
+
+ return result;
+}
+
+int buffer_to_disk(Buffer *source, int x, int y, int xs, int ys) {
+ int buffer_id = -1;
+ Common::OutSaveFile *handle = nullptr;
+ byte *scan;
+ int count;
+ int error_count = 0;
+ int a_ok = false;
+ char file_name[40];
+
+ do {
+ buffer_accum = (byte)((buffer_accum + 1) % 10);
+
+ Common::strcpy_s(file_name, buffer_disk_filename);
+ env_catint(file_name, buffer_accum, 1);
+
+ if (!buffer_tracking[buffer_accum]) {
+ a_ok = true;
+ } else {
+ error_count++;
+ if (error_count > 10) goto done;
+ }
+ } while (!a_ok);
+
+ buffer_tracking[buffer_accum] = true;
+
+ handle = g_system->getSavefileManager()->openForSaving(file_name, false);
+ if (handle = nullptr)
+ goto done;
+
+ for (count = 0; count < ys; count++) {
+ scan = buffer_pointer(source, x, y + count);
+ if (!fileio_fwrite_f(scan, xs, 1, handle)) goto done;
+ }
+
+ buffer_id = buffer_accum;
+
+done:
+ delete handle;
+ return buffer_id;
+}
+
+void buffer_from_disk(Buffer *source, int buffer_id, int keep_flag, int x, int y, int xs, int ys) {
+ Common::InSaveFile *handle = nullptr;
+ byte *scan;
+ int count;
+ char file_name[40];
+
+ Common::strcpy_s(file_name, buffer_disk_filename);
+ env_catint(file_name, buffer_id, 1);
+
+ handle = g_system->getSavefileManager()->openForLoading(file_name);
+ if (handle == NULL) goto done;
+
+ for (count = 0; count < ys; count++) {
+ scan = buffer_pointer(source, x, y + count);
+ if (!fileio_fread_f(scan, xs, 1, handle)) goto done;
+ }
+
+done:
+ if (handle != NULL) {
+ delete handle;
+ if (!keep_flag) {
+ buffer_tracking[buffer_id] = 0;
+ remove(file_name);
+ }
+ }
+}
+
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/core/buffer.h b/engines/mads/madsv2/core/buffer.h
index 0250fcfd5f9..6b5e4b57876 100644
--- a/engines/mads/madsv2/core/buffer.h
+++ b/engines/mads/madsv2/core/buffer.h
@@ -174,7 +174,7 @@ extern bool buffer_get_delta_bounds(Buffer buf1, Buffer buf2,
* @param y y
* @return Pointer
*/
-extern byte *fastcall buffer_pointer(Buffer *buf, int x, int y);
+extern byte *buffer_pointer(Buffer *buf, int x, int y);
extern bool buffer_conform(Buffer *buffer, int *x, int *y,
int *xs, int *ys);
diff --git a/engines/mads/madsv2/core/color.cpp b/engines/mads/madsv2/core/color.cpp
new file mode 100644
index 00000000000..348d90474c3
--- /dev/null
+++ b/engines/mads/madsv2/core/color.cpp
@@ -0,0 +1,593 @@
+/* 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 "mads/madsv2/core/color.h"
+#include "mads/madsv2/core/screen.h"
+#include "mads/madsv2/core/sort.h"
+#include "mads/madsv2/core/mem.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+byte color_thatch(int color, int thatching) {
+ byte thatch;
+
+ if (color == 16) {
+ thatch = COLOR_NO_X16;
+ } else if (color == thatching) {
+ thatch = (byte)color;
+ } else {
+ if (thatching == 0) {
+ thatch = (byte)(((COLOR_BLACK_THATCH) << 4) + color);
+ } else {
+ thatch = (byte)((thatching << 4) + color);
+ }
+ }
+
+ return (thatch);
+}
+
+void color_list_start_scan(byte *list_flags) {
+ int count;
+
+ for (count = 0; count < COLOR_MAX_USER_COLORS; count++) {
+ list_flags[count] = false;
+ }
+}
+
+int color_list_update(ColorListPtr list, Buffer *scan_buf, Palette *scan_pal, byte *list_flags, byte *palette_map, CycleListPtr cycle) {
+ int count;
+ int row, col;
+ int found;
+ int result;
+ int hi, lo;
+ int num;
+ int cycle_color;
+ int cycle_count;
+ byte color_flags[256];
+ byte *scan;
+ byte color;
+ byte r, g, b;
+ word cycle_value;
+ word value[256];
+ byte reverse_map[256];
+ ColorList temp_list;
+
+ result = 0;
+
+ for (count = 0; count <= COLOR_HIGHEST; count++) {
+ color_flags[count] = (byte)false;
+ }
+
+ for (count = COLOR_HIGHEST + 1; count < 256; count++) {
+ color_flags[count] = (byte)true;
+ }
+
+ /* First, deal with any colors involved in cycling */
+
+ if (cycle != NULL) {
+ for (cycle_count = 0; cycle_count < cycle->num_cycles; cycle_count++) {
+ lo = cycle->table[cycle_count].first_palette_color;
+ num = cycle->table[cycle_count].num_colors;
+ hi = lo + num - 1;
+ for (cycle_color = lo; cycle_color <= hi; cycle_color++) {
+ if (!color_flags[cycle_color]) {
+ color_flags[cycle_color] = true;
+ r = (*scan_pal)[cycle_color].r;
+ g = (*scan_pal)[cycle_color].g;
+ b = (*scan_pal)[cycle_color].b;
+ found = false;
+
+ if (!found) {
+ if (list->num_colors < COLOR_MAX_USER_COLORS) {
+ count = list->num_colors;
+ list->table[count].r = r;
+ list->table[count].g = g;
+ list->table[count].b = b;
+ list->table[count].x16 = (byte)COLOR_NO_X16;
+ list->table[count].cycle = (byte)(cycle_count + 1);
+ list->table[count].group = 0;
+ list_flags[count] = true;
+ if (palette_map != NULL) {
+ palette_map[cycle_color] = (byte)count;
+ }
+ reverse_map[count] = (byte)cycle_color;
+ list->num_colors++;
+ } else {
+ result = COLOR_ERR_LISTOVERFLOW;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* Now deal with any other colors used in the picture */
+
+ scan = (byte *)mem_normalize(scan_buf->data);
+
+ for (row = 0; row < scan_buf->y; row++) {
+ for (col = 0; col < scan_buf->x; col++) {
+ color = *scan;
+ if (!color_flags[color]) {
+ r = (*scan_pal)[color].r;
+ g = (*scan_pal)[color].g;
+ b = (*scan_pal)[color].b;
+ found = false;
+ for (count = 0; (count < list->num_colors) && (!found); count++) {
+ if ((r == list->table[count].r) &&
+ (g == list->table[count].g) &&
+ (b == list->table[count].b) &&
+ (list->table[count].cycle == 0)) {
+ found = true;
+ list_flags[count] = true;
+ if (palette_map != NULL) {
+ palette_map[color] = (byte)count;
+ }
+ reverse_map[count] = color;
+ }
+ }
+ if (!found) {
+ if (list->num_colors < COLOR_MAX_USER_COLORS) {
+ count = list->num_colors;
+ list->table[count].r = r;
+ list->table[count].g = g;
+ list->table[count].b = b;
+ list->table[count].x16 = (byte)COLOR_NO_X16;
+ list->table[count].cycle = 0;
+ list->table[count].group = 0;
+ list_flags[count] = true;
+ if (palette_map != NULL) {
+ palette_map[color] = (byte)count;
+ }
+ reverse_map[count] = color;
+ list->num_colors++;
+ } else {
+ result = COLOR_ERR_LISTOVERFLOW;
+ }
+ }
+ color_flags[color] = (byte)true;
+ }
+ scan++;
+ }
+ scan = (byte *)mem_check_overflow(scan);
+ }
+
+ /* Sort color list so that cycle colors appear first */
+ /* The various tables must also be corrected. */
+
+ if (cycle != NULL) {
+ for (count = 0; count < list->num_colors; count++) {
+ cycle_value = list->table[count].cycle;
+ if ((cycle_value == 0) || (!list_flags[count])) cycle_value = 100;
+ value[count] = (cycle_value << 8) + reverse_map[count];
+ color_flags[count] = (byte)count;
+ }
+ sort_insertion_16(list->num_colors, color_flags, value);
+ temp_list.num_colors = list->num_colors;
+ for (count = 0; count < list->num_colors; count++) {
+ memcpy(&temp_list.table[count], &list->table[color_flags[count]], sizeof(Color));
+ }
+ if (palette_map != NULL) {
+ for (count = 0; count < 256; count++) {
+ palette_map[count] = color_flags[palette_map[count]];
+ }
+ }
+ for (count = 0; count < list->num_colors; count++) {
+ value[count] = list_flags[count];
+ }
+ for (count = 0; count < list->num_colors; count++) {
+ list_flags[count] = (byte)value[color_flags[count]];
+ }
+ memcpy(list, &temp_list, sizeof(ColorList));
+
+ /* Switch cycle list color #'s from palette to list */
+
+ for (cycle_count = 0; cycle_count < cycle->num_cycles; cycle_count++) {
+ found = false;
+ for (count = 0; !found && (count < list->num_colors); count++) {
+ if (list->table[count].cycle == (byte)(cycle_count + 1)) {
+ found = true;
+ cycle->table[cycle_count].first_list_color = (byte)count;
+ }
+ }
+ }
+ }
+
+ if (result == 0) {
+ result = list->num_colors;
+ }
+
+ return result;
+}
+
+int color_list_purge(ColorListPtr list, byte *list_flags) {
+ int count, count2;
+
+ for (count = 0; count < list->num_colors; count++) {
+ if (!list_flags[count]) {
+ for (count2 = count; count2 < list->num_colors - 1; count2++) {
+ list_flags[count2] = list_flags[count2 + 1];
+ memcpy(&list->table[count2], &list->table[count2 + 1], sizeof(Color));
+ }
+ list->num_colors--;
+ count--;
+ }
+ }
+
+ return list->num_colors;
+}
+
+int color_list_palette(ColorListPtr list, Buffer *scan_buf, Palette *scan_pal, int base_color, byte *palette_map, CycleListPtr cycle) {
+ int error_flag = false;
+ int mark;
+ int count, count2;
+ int cycle_count;
+ int cycle_id;
+ int row, col;
+ int map_me;
+ int stop_doing_this;
+ byte map[256];
+ byte flags[256];
+ byte r, g, b;
+ byte *scan;
+ RGBcolor *c2ptr;
+ Color *c1ptr;
+ Palette out_pal;
+
+ /* Make a copy of our starting palette */
+
+ memcpy(out_pal, *scan_pal, sizeof(RGBcolor) * 256);
+
+ /* Mark all list colors as unmapped */
+
+ for (count = 0; count < 256; count++) {
+ flags[count] = (byte)false;
+ }
+
+ mark = base_color;
+ for (count = 0; count < list->num_colors; count++) {
+ if (mark > 255) {
+ mark = 255;
+ error_flag = true;
+ }
+ c1ptr = &list->table[count];
+ c2ptr = &out_pal[mark];
+ memcpy(c2ptr, c1ptr, sizeof(RGBcolor));
+ palette_map[mark] = (byte)count;
+ stop_doing_this = false;
+ for (count2 = 0; (count2 <= COLOR_HIGHEST) && (!stop_doing_this); count2++) {
+ r = (*scan_pal)[count2].r;
+ g = (*scan_pal)[count2].g;
+ b = (*scan_pal)[count2].b;
+ if ((r == c2ptr->r) && (g == c2ptr->g) && (b == c2ptr->b)) {
+ if (cycle != NULL) {
+ cycle_id = 0;
+ for (cycle_count = 0; cycle_count < cycle->num_cycles; cycle_count++) {
+ if ((count2 >= (int)cycle->table[cycle_count].first_palette_color) &&
+ (count2 <= (int)(cycle->table[cycle_count].first_palette_color + (cycle->table[cycle_count].num_colors - 1)))) {
+ cycle_id = cycle_count + 1;
+ }
+ }
+ map_me = (list->table[count].cycle == (byte)cycle_id);
+ if (cycle_id != 0) {
+ map_me &= (!flags[count2]);
+ stop_doing_this = map_me;
+ }
+ } else {
+ map_me = true;
+ }
+ if (map_me) {
+ map[count2] = (byte)mark;
+ flags[count2] = (byte)true;
+ }
+ }
+ }
+ mark++;
+ }
+
+ map[COLOR_TRANSPARENT] = COLOR_TRANSPARENT;
+
+ scan = (byte *)mem_normalize(scan_buf->data);
+
+ for (row = 0; row < scan_buf->y; row++) {
+ for (col = 0; col < scan_buf->x; col++) {
+ *scan = map[*scan];
+ scan++;
+ }
+ scan = (byte *)mem_check_overflow(scan);
+ }
+ memcpy(*scan_pal, out_pal, sizeof(RGBcolor) * 256);
+
+ if (cycle != NULL) {
+ mark = base_color;
+ for (cycle_count = 0; cycle_count < cycle->num_cycles; cycle_count++) {
+ cycle->table[cycle_count].first_palette_color = (byte)mark;
+ mark += cycle->table[cycle_count].num_colors;
+ }
+ }
+
+ return error_flag;
+}
+
+void color_list_conform(ColorListPtr list, Buffer *scan_buf, Palette *scan_pal, Palette *main_pal, int base_color) {
+ int mark;
+ int count, count2;
+ int row, col;
+ int found;
+ int finish;
+ byte map[256];
+ byte r, g, b;
+ byte *scan;
+ Palette out_pal;
+
+ memcpy(out_pal, *main_pal, sizeof(RGBcolor) * 256);
+
+ mark = base_color + list->num_colors;
+ for (count = 0; count <= COLOR_HIGHEST; count++) {
+ r = (*scan_pal)[count].r;
+ g = (*scan_pal)[count].g;
+ b = (*scan_pal)[count].b;
+ found = false;
+ finish = (count < 16) ? 0 : COLOR_FIRST_USER_COLOR - 1;
+ for (count2 = COLOR_FIRST_USER_COLOR; (!found) && (count2 != finish); ) {
+ if ((r == out_pal[count2].r) &&
+ (g == out_pal[count2].g) &&
+ (b == out_pal[count2].b)) {
+ found = true;
+ map[count] = (byte)count2;
+ }
+ count2 = (count2 + 1) % mark;
+ }
+ if (!found) {
+ if (mark < 255) {
+ out_pal[mark].r = r;
+ out_pal[mark].g = g;
+ out_pal[mark].b = b;
+ map[count] = (byte)mark;
+ mark++;
+ } else {
+ map[count] = 15;
+ }
+ }
+ }
+
+ for (count = 0; count < 16; count++) {
+ map[count] = (byte)count;
+ }
+
+ scan = (byte *)mem_normalize(scan_buf->data);
+
+ map[COLOR_TRANSPARENT] = COLOR_TRANSPARENT;
+
+ for (row = 0; row < scan_buf->y; row++) {
+ for (col = 0; col < scan_buf->x; col++) {
+ *scan = map[*scan];
+ scan++;
+ }
+ scan = (byte *)mem_check_overflow(scan);
+ }
+
+ memcpy(*main_pal, out_pal, sizeof(RGBcolor) * 256);
+}
+
+void color_trans_show_buf(Buffer from, Buffer unto,
+ int from_x, int from_y,
+ int unto_x, int unto_y,
+ int size_x, int size_y,
+ ColorListPtr list,
+ byte *palette_map, int mask_flag) {
+ int row, col;
+ int hi;
+ byte *source, *dest;
+ byte *source_scan, *dest_scan;
+ byte item;
+ byte trans;
+ byte thatch;
+ int color, thatching;
+
+ source = (byte *)mem_normalize(from.data);
+ for (row = 0; row < from_y; row++) {
+ source = (byte *)mem_check_overflow(source + from.x);
+ }
+ source = source + from_x;
+
+ dest = (byte *)mem_normalize(unto.data);
+ for (row = 0; row < unto_y; row++) {
+ dest = (byte *)mem_check_overflow(dest + unto.x);
+ }
+ dest = dest + unto_x;
+
+ for (row = 0; row < size_y; row++) {
+ source_scan = source;
+ dest_scan = dest;
+ for (col = 0; col < size_x; col++) {
+ item = *source_scan;
+ trans = list->table[palette_map[item]].x16;
+ color_split_thatch((int)trans, &color, &thatching);
+ if (item == COLOR_TRANSPARENT) color = 16;
+ if (color != 16) {
+ hi = ((row + from_y) ^ (col + from_x)) & 1;
+ if (hi) {
+ thatch = (byte)thatching;
+ } else {
+ thatch = (byte)color;
+ }
+ if (mask_flag) {
+ *dest_scan = hi_white;
+ } else {
+ *dest_scan = thatch;
+ }
+ } else {
+ if (mask_flag) {
+ *dest_scan = black;
+ } else {
+ *dest_scan = item;
+ }
+ }
+ source_scan++;
+ dest_scan++;
+ }
+ source = (byte *)mem_check_overflow(source + from.x);
+ dest = (byte *)mem_check_overflow(dest + unto.x);
+ }
+}
+
+void color_trans_fill_buf(Buffer unto, int unto_x, int unto_y,
+ int size_x, int size_y, byte thatch_color) {
+ int row, col;
+ int hi;
+ int color, thatching;
+ byte thatch[2];
+ byte *dest;
+ byte *dest_scan;
+
+ dest = (byte *)mem_normalize(unto.data);
+ for (row = 0; row < unto_y; row++) {
+ dest = (byte *)mem_check_overflow(dest + unto.x);
+ }
+ dest += unto_x;
+
+ color_split_thatch((int)thatch_color, &color, &thatching);
+ thatch[0] = (byte)color;
+ thatch[1] = (byte)thatching;
+ if (thatch[0] == 16) {
+ thatch[0] = 0;
+ thatch[1] = 0;
+ }
+
+ for (row = 0; row < size_y; row++) {
+ dest_scan = dest;
+ for (col = 0; col < size_x; col++) {
+ hi = ((row + unto_y) ^ (col + unto_x)) & 1;
+ *dest_scan = thatch[hi];
+ dest_scan++;
+ }
+ dest = (byte *)mem_check_overflow(dest + unto.x);
+ }
+}
+
+void color_buffer_palette_to_list(ColorListPtr list, Buffer *scan_buf, byte *palette_map) {
+ int row, col;
+ byte *scan_ptr;
+ byte scan;
+
+ scan_ptr = (byte *)mem_normalize(scan_buf->data);
+
+ for (row = 0; row < scan_buf->y; row++) {
+ for (col = 0; col < scan_buf->x; col++) {
+ scan = *scan_ptr;
+ *scan_ptr = palette_map[scan];
+ scan_ptr++;
+ }
+ scan_ptr = (byte *)mem_check_overflow(scan_ptr);
+ }
+}
+
+void color_buffer_list_to_palette(Buffer *scan_buf, int marker) {
+ int row, col;
+ byte scan;
+ byte *scan_ptr;
+
+ scan_ptr = (byte *)mem_normalize(scan_buf->data);
+
+ for (row = 0; row < scan_buf->y; row++) {
+ for (col = 0; col < scan_buf->x; col++) {
+ scan = *scan_ptr;
+ *scan_ptr = (byte)marker + scan;
+ scan_ptr++;
+ }
+ scan_ptr = (byte *)mem_check_overflow(scan_ptr);
+ }
+}
+
+void color_transparent_swap(Buffer *scan_buf, Palette *scan_pal, byte transparent) {
+ byte *scan = scan_buf->data;
+ word mysize = scan_buf->x * scan_buf->y;
+
+ for (word i = 0; i < mysize; i++) {
+ if (scan[i] == transparent)
+ scan[i] = COLOR_TRANSPARENT;
+ }
+
+ memcpy(&(*scan_pal)[COLOR_TRANSPARENT], &(*scan_pal)[transparent], sizeof(RGBcolor));
+}
+void color_buffer_list_to_main(ColorListPtr color_list, Buffer *scan_buf) {
+ byte *scan_ptr = (byte *)mem_normalize(scan_buf->data);
+ int row = scan_buf->y;
+ int col = scan_buf->x;
+ Color *table_ptr = &color_list->table[0];
+
+ // table_ptr->x16 is at offset +3 in the Color struct (skipping 3 bytes
+ // to reach the X16 translated colour field, as the ASM does "add si, 3")
+ byte *table_x16 = (byte *)table_ptr + 3;
+
+ for (int r = 0; r < row; r++) {
+ for (int c = 0; c < col; c++) {
+ byte pixel = scan_ptr[c];
+ // Original: ax = pixel, bx = pixel*2, ax = pixel*4,
+ // bx = pixel*2 + pixel*4 = pixel*6
+ int offset = (int)pixel * 6;
+ scan_ptr[c] = table_x16[offset];
+ }
+ scan_ptr += col;
+ }
+}
+
+void color_split_thatch(int thatch, int *color, int *thatching) {
+ if (thatch == COLOR_NO_X16) {
+ *color = 16;
+ *thatching = *color;
+ } else {
+ *color = thatch & 0x0f;
+ *thatching = thatch >> 4;
+ if (*thatching == 0) {
+ *thatching = *color;
+ } else if (*thatching == COLOR_BLACK_THATCH) {
+ *thatching = 0;
+ }
+ }
+}
+
+void color_buffer_list_to_x16(ColorListPtr color_list, Buffer *scan_buf) {
+ int row, col;
+ int thatch, color_1, color_2;
+ byte thatching;
+ byte scan;
+ byte *scan_ptr;
+
+ scan_ptr = (byte *)mem_normalize(scan_buf->data);
+
+ for (row = 0; row < scan_buf->y; row++) {
+ thatching = (byte)(row & 1);
+ for (col = 0; col < scan_buf->x; col++) {
+ scan = *scan_ptr;
+ thatch = color_list->table[scan].x16;
+ color_split_thatch(thatch, &color_1, &color_2);
+ *scan_ptr = (byte)(thatching ? color_2 : color_1);
+ scan_ptr++;
+ thatching = (byte)(!thatching);
+ }
+ }
+}
+
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/core/color.h b/engines/mads/madsv2/core/color.h
index 8ffedf45790..c61f6ef26c7 100644
--- a/engines/mads/madsv2/core/color.h
+++ b/engines/mads/madsv2/core/color.h
@@ -108,58 +108,91 @@ typedef struct {
typedef ShadowList *ShadowListPtr;
-
-/* color_1.c */
-byte color_thatch(int color, int thatching);
-
-void color_list_start_scan(byte *list_flags);
-
-int color_list_update(ColorListPtr list, Buffer *scan_buf,
+/**
+ * Given a main color (0-15, or 16 for "no translation") and a
+ * thatching color (0-15, same as main color for solid thatch),
+ * produces a valid "thatch" byte.
+ */
+extern byte color_thatch(int color, int thatching);
+extern void color_list_start_scan(byte *list_flags);
+
+/**
+ * Updates a color list <list>, based on colors used in <scan_buf>
+ * and defined in <scan_pal>. Adds any colors used in picture but
+ * not defined in list to the list; sets the corresponding color flag
+ * for each color that is used in the buffer.
+ *
+ * @return Returns # of colors in updated list, or negative for error.
+ */
+extern int color_list_update(ColorListPtr list, Buffer *scan_buf,
Palette *scan_pal, byte *list_flags,
byte *palette_map, CycleListPtr cycle);
-void color_list_purge(ColorListPtr list, byte *list_flags);
-
-int color_list_palette(ColorListPtr list, Buffer *scan_buf,
+/**
+ * Removes from color list "list" any colors whose corresponding
+ * flags are not set. (Use after color_list_update to remove colors
+ * no longer being used). Voids any previously existing palette_map.
+*/
+extern int color_list_purge(ColorListPtr list, byte *list_flags);
+
+/**
+ * Adds the colors in the given list to the given palette, filling
+ * from the specified "base color". Also generates a palette_map
+ * which can be used to map palette colors back into the color list.
+*/
+extern int color_list_palette(ColorListPtr list, Buffer *scan_buf,
Palette *scan_pal, int base_color,
byte *palette_map, CycleListPtr cycle);
-void color_list_conform(ColorListPtr list, Buffer *scan_buf,
+/**
+ * Used by roomedit when loading attribute buffers whose colors
+ * are often based on the main image, but which are not necessarily
+ * consistent and may contain additional, if irrelevant, colors.
+ * Conforms the incoming picture with the available palette. Priority
+ * of actions for each color used is:
+ * (1) Use equivalent color already existing in palette.
+ * (2) Allocate a new palette color if available.
+ * (3) Use "white".
+ */
+extern void color_list_conform(ColorListPtr list, Buffer *scan_buf,
Palette *scan_pal, Palette *main_pal,
int base_color);
-void color_trans_fill_buf(Buffer unto,
- int unto_x, int unto_y,
- int size_x, int size_y,
- byte thatch_color);
-
-void color_trans_show_buf(Buffer from, Buffer unto,
- int from_x, int from_y,
- int unto_x, int unto_y,
- int size_x, int size_y,
- ColorListPtr list,
+/**
+ * Fills the specified area of the specified buffer with the
+ * specified 16-color thatch (analogous to buffer_rect_fill).
+ */
+extern void color_trans_fill_buf(Buffer unto, int unto_x, int unto_y,
+ int size_x, int size_y, byte thatch_color);
+
+/**
+ * Copies a rectangle of the buffer "from" into the buffer "unto",
+ * But uses the specified color list and palette map to perform
+ * 256-to-16 color translations. If "mask_flag" is true, then
+ * displays "white" if a translation exists for a pixel, "black"
+ * otherwise. If "mask_flag" is false, then translated color is
+ * displayed if available, and untranslated color is displayed
+ * otherwise.
+ *
+ * Analogous to buffer_rect_copy();
+ */
+extern void color_trans_show_buf(Buffer from, Buffer unto,
+ int from_x, int from_y, int unto_x, int unto_y,
+ int size_x, int size_y, ColorListPtr list,
byte *palette_map, int mask_flag);
-void color_buffer_palette_to_list(ColorListPtr list,
- Buffer *scan_buf,
- byte *palette_map);
-
-void color_buffer_list_to_palette(Buffer *scan_buf, int marker);
-
-void color_transparent_swap(Buffer *scan_buf,
- Palette *scan_pal,
- byte transparent);
+extern void color_buffer_palette_to_list(ColorListPtr list,
+ Buffer *scan_buf, byte *palette_map);
+extern void color_buffer_list_to_palette(Buffer *scan_buf, int marker);
+extern void color_transparent_swap(Buffer *scan_buf, Palette *scan_pal, byte transparent);
+extern void color_buffer_list_to_main(ColorListPtr color_list, Buffer *scan_buf);
+extern void color_buffer_list_to_x16(ColorListPtr color_list, Buffer *scan_buf);
-
-/* color_2.c */
-void color_buffer_list_to_main(ColorListPtr color_list,
- Buffer *scan_buf);
-
-/* color_3.c */
-void color_buffer_list_to_x16(ColorListPtr color_list,
- Buffer *scan_buf);
-
-void color_split_thatch(int thatch, int *color, int *thatching);
+/**
+ * Given a valid thatch byte, returns a primary "color" and
+ * secondary "thatching" color.
+ */
+extern void color_split_thatch(int thatch, int *color, int *thatching);
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/core/buffer_3.cpp b/engines/mads/madsv2/core/config.cpp
similarity index 94%
rename from engines/mads/madsv2/core/buffer_3.cpp
rename to engines/mads/madsv2/core/config.cpp
index 25aad3fa1c5..cad76ad3f94 100644
--- a/engines/mads/madsv2/core/buffer_3.cpp
+++ b/engines/mads/madsv2/core/config.cpp
@@ -19,12 +19,12 @@
*
*/
-#include "mads/madsv2/core/general.h"
+#include "mads/madsv2/core/config.h"
namespace MADS {
namespace MADSV2 {
-
+ConfigFile config_file;
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/core/demo.h b/engines/mads/madsv2/core/demo.h
index 8ee83080b77..9e8d9bdf430 100644
--- a/engines/mads/madsv2/core/demo.h
+++ b/engines/mads/madsv2/core/demo.h
@@ -32,8 +32,8 @@ int demo_checksum(byte **source, int *pack_size, int *unpack_size);
int demo_check(void);
/* demo_2.cpp */
-void fastcall demo_log_in(char *release_version, char *release_date);
-void fastcall demo_verify(void);
+void demo_log_in(char *release_version, char *release_date);
+void demo_verify(void);
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/core/dialog.cpp b/engines/mads/madsv2/core/dialog.cpp
index a5f7318b0fc..2321fbd071d 100644
--- a/engines/mads/madsv2/core/dialog.cpp
+++ b/engines/mads/madsv2/core/dialog.cpp
@@ -304,7 +304,7 @@ static int get_keystroke(const char *prompt) {
return key_stroke;
}
-ItemPtr dialog_add_button(DialogPtr dialog, int x, int y, char *prompt) {
+ItemPtr dialog_add_button(DialogPtr dialog, int x, int y, const char *prompt) {
ItemPtr item = NULL;
char *space;
int space_look;
@@ -395,7 +395,7 @@ void dialog_grey_checkbox(ItemPtr item) {
}
}
-ItemPtr dialog_add_message(DialogPtr dialog, int x, int y, char *prompt) {
+ItemPtr dialog_add_message(DialogPtr dialog, int x, int y, const char *prompt) {
ItemPtr item = NULL;
char *space = NULL;
@@ -643,10 +643,10 @@ ItemPtr dialog_append_list(DialogPtr dialog, int x, int y, ItemPtr base_string,
return listitem;
}
-ItemPtr dialog_add_filename(DialogPtr dialog, int x, int y, char *prompt,
- char *default_val, char *path, int rows,
- char *filebuf, int max_file_elements,
- char *dirsbuf, int max_dirs_elements) {
+ItemPtr dialog_add_filename(DialogPtr dialog, int x, int y, const char *prompt,
+ const char *default_val, const char *path, int rows,
+ char *filebuf, int max_file_elements,
+ char *dirsbuf, int max_dirs_elements) {
ItemPtr item, listitem, dirsitem;
ListPtr list, dirs;
int list_num, dirs_num;
@@ -3323,9 +3323,8 @@ void dialog_set_alert_colors(int normal, int select, int hilite) {
alert_hilite_color = hilite;
}
-int dialog_alert(int x, int y, int buttons,
- char *string1, char *string2,
- char *string3, char *string4) {
+int dialog_alert(int x, int y, int buttons, const char *string1,
+ const char *string2, const char *string3, const char *string4) {
DialogPtr dialog;
int num_buttons;
int button_width;
@@ -3497,8 +3496,8 @@ int dialog_alert_center(int buttons,
return dialog_alert(DD_CENTER, DD_CENTER, buttons, string1, string2, string3, string4);
}
-int dialog_alert_ok(char *string1, char *string2,
- char *string3, char *string4) {
+int dialog_alert_ok(const char *string1, const char *string2,
+ const char *string3, const char *string4) {
return dialog_alert(DD_CENTER, DD_CENTER, DD_OK_BUTTON, string1, string2, string3, string4);
}
@@ -3507,7 +3506,7 @@ void dialog_newsay(int x, int y) {
dialog_create(say_dialog, x, y, DD_AUTO, DD_DEFAULT, DD_DEFAULT, DD_DEFAULT);
}
-void dialog_say(char *message, int x) {
+void dialog_say(const char *message, int x) {
dialog_add_message(say_dialog, x, DD_IY_AUTOFILL, message);
}
@@ -3548,19 +3547,19 @@ Window dialog_sayit(int saymode) {
return say_dialog->window;
}
-ItemPtr dialog_left_message(DialogPtr dialog, char *prompt) {
+ItemPtr dialog_left_message(DialogPtr dialog, const char *prompt) {
return dialog_add_message(dialog, DD_IX_LEFT, DD_IY_AUTOFILL, prompt);
}
-ItemPtr dialog_center_message(DialogPtr dialog, char *prompt) {
+ItemPtr dialog_center_message(DialogPtr dialog, const char *prompt) {
return dialog_add_message(dialog, DD_IX_CENTER, DD_IY_AUTOFILL, prompt);
}
-ItemPtr dialog_left_string(DialogPtr dialog, char *prompt, char *string, int width) {
+ItemPtr dialog_left_string(DialogPtr dialog, const char *prompt, const char *string, int width) {
return dialog_add_string(dialog, DD_IX_LEFT, DD_IY_AUTOFILL, prompt, string, width);
}
-ItemPtr dialog_left_button(DialogPtr dialog, char *prompt) {
+ItemPtr dialog_left_button(DialogPtr dialog, const char *prompt) {
return dialog_add_button(dialog, DD_IX_LEFT, DD_IY_BUTTON, prompt);
}
diff --git a/engines/mads/madsv2/core/dialog.h b/engines/mads/madsv2/core/dialog.h
index 2057802e40c..cb3f3796397 100644
--- a/engines/mads/madsv2/core/dialog.h
+++ b/engines/mads/madsv2/core/dialog.h
@@ -433,7 +433,7 @@ extern int dialog_alert_center(int buttons, const char *string1,
extern int dialog_alert_ok(const char *string1, const char *string2,
const char *string3, const char *string4);
extern void dialog_newsay(int x, int y);
-extern void dialog_say(char *message, int x);
+extern void dialog_say(const char *message, int x);
extern Window dialog_sayit(int saymode);
extern ItemPtr dialog_left_message(DialogPtr dialog, const char *prompt);
diff --git a/engines/mads/madsv2/core/digi.cpp b/engines/mads/madsv2/core/digi.cpp
new file mode 100644
index 00000000000..e51b7777de6
--- /dev/null
+++ b/engines/mads/madsv2/core/digi.cpp
@@ -0,0 +1,70 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "common/textconsole.h"
+#include "mads/madsv2/core/digi.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+bool digi_trigger_dialog;
+bool digi_trigger_ambiance;
+bool digi_trigger_effect;
+
+
+void digi_install() {
+ // No implementation in ScummVM
+}
+
+void digi_uninstall() {
+ // No implementation in ScummVM
+}
+
+void digi_play(char name[30], int slot) {
+ warning("TODO: digi_play");
+}
+
+void digi_play_build(int room, char thing, int num, int slot) {
+ warning("TODO: digi_play_build");
+}
+
+void digi_play_build_ii(char thing, int num, int slot) {
+ warning("TODO: digi_play_build_ii");
+}
+
+void digi_stop(int which_one) {
+ warning("TODO: digi_stop");
+}
+
+void digi_read_another_chunk() {
+ warning("TODO: digi_read_another_chunk");
+}
+
+void digi_initial_volume(int vol) {
+ warning("TODO: digi_initial_volume");
+}
+
+void digi_set_volume(int vol, int slot) {
+ warning("TODO: digi_set_volume");
+}
+
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/core/digi.h b/engines/mads/madsv2/core/digi.h
index 1a4816a347d..6368b78c7c0 100644
--- a/engines/mads/madsv2/core/digi.h
+++ b/engines/mads/madsv2/core/digi.h
@@ -27,13 +27,18 @@
namespace MADS {
namespace MADSV2 {
-void digi_install(void);
+extern bool digi_trigger_dialog;
+extern bool digi_trigger_ambiance;
+extern bool digi_trigger_effect;
+
+
+void digi_install();
void digi_play(char name[30], int slot);
void digi_play_build(int room, char thing, int num, int slot);
void digi_play_build_ii(char thing, int num, int slot);
void digi_stop(int which_one);
-void digi_uninstall(void);
-void digi_read_another_chunk(void);
+void digi_uninstall();
+void digi_read_another_chunk();
void digi_initial_volume(int vol);
void digi_set_volume(int vol, int slot);
diff --git a/engines/mads/madsv2/core/ems.h b/engines/mads/madsv2/core/ems.h
index ff22a3a727b..3f3c5720b50 100644
--- a/engines/mads/madsv2/core/ems.h
+++ b/engines/mads/madsv2/core/ems.h
@@ -108,7 +108,7 @@ inline void ems_shutdown() {
* Does not actually generate an EMS interrupt if the page is already
* mapped. Call only if EMS memory was detected.
*/
-inline int ems_map_page(word physical, word logical);
+inline int ems_map_page(word physical, word logical) { return 0; }
inline void ems_unmap_all() {}
inline void ems_push() {}
diff --git a/engines/mads/madsv2/core/env.cpp b/engines/mads/madsv2/core/env.cpp
index 6a48b8719bd..ffb82740b06 100644
--- a/engines/mads/madsv2/core/env.cpp
+++ b/engines/mads/madsv2/core/env.cpp
@@ -33,6 +33,7 @@ namespace MADSV2 {
extern int art_hags_are_on_hd;
+int env_privileges;
int env_search_mode = ENV_SEARCH_MADS_PATH;
int env_search_cd = false;
char env_cd_drive = 'D';
@@ -60,6 +61,11 @@ static const char env_slash_string[3] = "\\";
static const char env_speech1_string[8] = "SPEECH1";
static const char env_speech2_string[8] = "SPEECH2";
+
+int env_verify() {
+ return 0;
+}
+
char *env_catint(char *out, int value, int digits) {
int mark;
int power;
@@ -83,14 +89,11 @@ char *env_catint(char *out, int value, int digits) {
return (out);
}
-
static void path_concat(char *target, const char *string) {
Common::strcat_s(target, 65536, string);
Common::strcat_s(target, 65536, env_slash_string);
}
-
-/* char *path = 'd322u001.rac' */
char *env_fill_path(char *path, int env_mode, int env_room) {
Common::String madsptr;
char *infile;
@@ -185,13 +188,11 @@ char *env_fill_path(char *path, int env_mode, int env_room) {
return madspath;
}
-char *env_get_path(char *madspath, char *infile) {
- /* char *madsptr; */
+char *env_get_path(char *madspath, const char *infile) {
char *mark;
- /* int madslen; */
- int env_mode;
- int env_room = 0;
- int env_sect = 0;
+ int env_mode;
+ int env_room = 0;
+ int env_sect = 0;
char temp_buf_1[80];
char temp_buf_2[80];
@@ -286,19 +287,20 @@ char *env_get_path(char *madspath, char *infile) {
return madspath;
}
-Common::SeekableReadStream *env_open(char *file_path, const char *options) {
+Common::SeekableReadStream *env_open(const char *filename, const char *options) {
int error_flag = true;
int count;
int found;
int num_files;
long mem_to_get;
+ char file_path[80];
char index_file[80];
char temp_file[80];
char load_file[80];
char temp_buf[80];
char check_buf[80];
- char *mark;
+ const char *mark;
Common::SeekableReadStream *index_handle = NULL;
Common::SeekableReadStream *handle = NULL;
Concat concat;
@@ -307,6 +309,7 @@ Common::SeekableReadStream *env_open(char *file_path, const char *options) {
if (env_get_path(load_file, file_path) == NULL) goto done;
+ Common::strcpy_s(file_path, filename);
mark = strchr(file_path, '*');
mads_strupr(file_path);
@@ -584,7 +587,7 @@ char *env_dos_error_name(char *error_buf) {
return error_buf;
}
-char *env_get_level_path(char *out, int item_type, char *file_spec, int first_level, int second_level) {
+char *env_get_level_path(char *out, int item_type, const char *file_spec, int first_level, int second_level) {
char temp_buf[80];
char *result;
diff --git a/engines/mads/madsv2/core/env.h b/engines/mads/madsv2/core/env.h
index f7f81142e07..a7a0d0dbd42 100644
--- a/engines/mads/madsv2/core/env.h
+++ b/engines/mads/madsv2/core/env.h
@@ -75,18 +75,18 @@ extern char env_null[7];
extern int env_verify(void);
-Common::SeekableReadStream *env_open(const char *file_path, const char *options);
-int env_exist(const char *file_name);
-long env_get_file_size(Common::Stream *handle);
-char *env_get_path(char *madspath, const char *infile);
-char *env_catint(char *out, int value, int digits);
-char *env_fill_path(char *path, int env_mode, int env_room);
-char *env_dos_error_name(char *error_buf);
-char *env_get_level_path(char *out, int item_type, const char *file_spec,
+extern Common::SeekableReadStream *env_open(const char *file_path, const char *options);
+extern int env_exist(const char *file_name);
+extern long env_get_file_size(Common::SeekableReadStream *handle);
+extern char *env_get_path(char *madspath, const char *infile);
+extern char *env_catint(char *out, int value, int digits);
+extern char *env_fill_path(char *path, int env_mode, int env_room);
+extern char *env_dos_error_name(char *error_buf);
+extern char *env_get_level_path(char *out, int item_type, const char *file_spec,
int first_level, int second_level);
-Common::SeekableReadStream *env_open_level(int item_type, const char *file_spec,
+extern Common::SeekableReadStream *env_open_level(int item_type, const char *file_spec,
int level_one, int level_two, const char *options);
-char *env_get(char *target, char *env);
+extern char *env_get(char *target, const char *env);
/**
* Given a pointer to an environment variable, returns a pointer
diff --git a/engines/mads/madsv2/core/error.cpp b/engines/mads/madsv2/core/error.cpp
index 55e7b1ea320..0e411cc3546 100644
--- a/engines/mads/madsv2/core/error.cpp
+++ b/engines/mads/madsv2/core/error.cpp
@@ -48,6 +48,64 @@ void (*error_service_routine_2)() = NULL;
int error_abort = WARNING;
char error_string[80] = "";
+
+
+int error_scan(char *target, const char *name, int number) {
+ int count;
+ int error_flag = true;
+ Common::SeekableReadStream *handle = NULL;
+ char temp_buf[40];
+
+ handle = env_open(name, "rt");
+ if (handle == NULL) goto done;
+
+ for (count = 1; count <= number; count++) {
+ if (handle->eos()) goto done;
+ Common::String line = handle->readLine();
+ Common::strcpy_s(temp_buf, line.c_str());
+ }
+
+ for (count = 0; count < (int)strlen(temp_buf); count++) {
+ if (temp_buf[count] < 32) temp_buf[count] = 0;
+ }
+
+ Common::strcpy_s(target, 65536, temp_buf);
+
+ error_flag = false;
+
+done:
+ delete handle;
+ return error_flag;
+}
+
+void error_dump_file(const char *file_name) {
+ int count;
+ int going;
+ Common::SeekableReadStream *handle = NULL;
+ char temp_buf[80];
+
+ handle = env_open(file_name, "rt");
+ if (handle == NULL) goto done;
+
+ going = true;
+ while (going && !handle->eos()) {
+ Common::String line = handle->readLine();
+ Common::strcpy_s(temp_buf, line.c_str());
+
+ for (count = 0; count < (int)strlen(temp_buf); count++) {
+ if (temp_buf[count] < 32) temp_buf[count] = 0;
+ }
+ if (strncmp(temp_buf, "***", 3) == 0) {
+ going = false;
+ } else {
+ echo(temp_buf, true);
+ }
+ }
+
+done:
+ delete handle;
+}
+
static void error_explode(char *error_buf, char *module_buf, char *data1_buf, char *data2_buf, long avail, int error) {
midi_uninstall();
digi_uninstall();
diff --git a/engines/mads/madsv2/core/error.h b/engines/mads/madsv2/core/error.h
index fb14dcc166b..38424a5830b 100644
--- a/engines/mads/madsv2/core/error.h
+++ b/engines/mads/madsv2/core/error.h
@@ -135,30 +135,13 @@ extern void (*error_service_routine)();
extern void (*error_service_routine_2)();
-/* error_1.cpp */
extern void error_report(int error, int severity, int module, long data1, long data2);
-
-int error_scan(char *target, char *name, int number);
-
+extern int error_scan(char *target, const char *name, int number);
extern void error_dump_file(const char *file_name);
-
-/* error_2.cpp */
extern void error_break_point(int data1, int data2);
-
-
-/* error_3.cpp */
extern void error_watch_point(char *message, long data1, long data2);
-
-
-/* error_4.cpp */
extern void error_check_memory(void);
-
-
-/* error_5.cpp */
extern void error_file_point(char *message, long data1, long data2);
-
-
-/* error_6.cpp */
extern void error_entry(char *name, char *message);
extern void error_exit(char *name, char *message);
extern void error_put(char *name, int item);
diff --git a/engines/mads/madsv2/core/extra.cpp b/engines/mads/madsv2/core/extra.cpp
new file mode 100644
index 00000000000..3aa1735c701
--- /dev/null
+++ b/engines/mads/madsv2/core/extra.cpp
@@ -0,0 +1,87 @@
+/* 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/textconsole.h"
+#include "mads/madsv2/core/extra.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+
+void fly_on_screen(int flying_object) {
+ error("TODO: fly_on_screen");
+}
+
+void fly_off_screen(int flying_object) {
+ error("TODO: fly_off_screen");
+}
+
+void display_inventory(void) {
+ error("TODO: display_inventory");
+}
+
+void display_journal(void) {
+ error("TODO: display_journal");
+}
+
+void leave_journal(void) {
+ error("TODO: leave_journal");
+}
+
+void solve_me_selected(void) {
+ error("TODO: solve_me_selected");
+}
+
+void door_selected(void) {
+ error("TODO: door_selected");
+}
+
+void extra_spinning_object(void) {
+ error("TODO: extra_spinning_object");
+}
+
+void extra_inven_preserve_palette(void) {
+ error("TODO: extra_inven_preserve_palette");
+}
+
+void stamp_sprite_to_interface(int x, int y, int sprite, int series) {
+ error("TODO: stamp_sprite_to_interface");
+}
+
+void delete_sprite_in_interface(int series) {
+ error("TODO: delete_sprite_in_interface");
+}
+
+void extra_change_animation(int handle, int x, int y, byte scale, byte depth) {
+ error("TODO: extra_change_animation");
+}
+
+void extra_shift_animation(int handle, int x, int y, byte scale) {
+ error("TODO: extra_shift_animation");
+}
+
+void extra_blank_knothole(void) {
+ error("TODO: extra_blank_knothole");
+}
+
+
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/core/fileio.cpp b/engines/mads/madsv2/core/fileio.cpp
index dc068afba2f..4c4a78353d3 100644
--- a/engines/mads/madsv2/core/fileio.cpp
+++ b/engines/mads/madsv2/core/fileio.cpp
@@ -310,12 +310,11 @@ int fileio_put_line(const char *source, Common::WriteStream *handle) {
return 0;
}
-
long fileio_get_disk_free(char drive) {
return 999999;
}
-void fileio_add_ext(char *name, char *ext) {
+void fileio_add_ext(char *name, const char *ext) {
char *mark;
mark = strrchr(name, '.');
@@ -327,7 +326,7 @@ void fileio_add_ext(char *name, char *ext) {
mads_strupr(name);
}
-void fileio_new_ext(char *target, char *name, char *ext) {
+void fileio_new_ext(char *target, const char *name, const char *ext) {
char *mark;
if (name != target) {
diff --git a/engines/mads/madsv2/core/font.cpp b/engines/mads/madsv2/core/font.cpp
index dbdc3fa356f..efe2f02b493 100644
--- a/engines/mads/madsv2/core/font.cpp
+++ b/engines/mads/madsv2/core/font.cpp
@@ -84,7 +84,7 @@ done:
return result;
}
-int font_write(FontPtr font, Buffer *target, char *out_string,
+int font_write(FontPtr font, Buffer *target, const char *out_string,
int x, int y, int auto_spacing) {
int target_wrap;
int screen_loc;
diff --git a/engines/mads/madsv2/core/game.cpp b/engines/mads/madsv2/core/game.cpp
index bac956c1484..e78014c1dad 100644
--- a/engines/mads/madsv2/core/game.cpp
+++ b/engines/mads/madsv2/core/game.cpp
@@ -71,9 +71,6 @@ namespace MADSV2 {
extern long mem_used;
extern long mem_avail_at_start;
-extern int digi_trigger_dialog;
-extern int digi_trigger_ambiance;
-extern int digi_trigger_effect;
extern int room_state[40];
@@ -109,6 +106,7 @@ int debugger_memory_all = false; /* Not showing ALL memory */
int debugger_memory_keywait = false; /* Not waiting for memory */
void (*debugger_reset)() = NULL; /* Debugger reset routine */
void (*debugger_update)() = NULL; /* Debugger update routine */
+int int_sprite[6];
int selected_intro = false;
long correction_clock;
diff --git a/engines/mads/madsv2/core/game.h b/engines/mads/madsv2/core/game.h
index 7fbbca412fc..34b8a988b9b 100644
--- a/engines/mads/madsv2/core/game.h
+++ b/engines/mads/madsv2/core/game.h
@@ -23,6 +23,7 @@
#define MADS_CORE_GAME_H
#include "mads/madsv2/core/general.h"
+#include "mads/madsv2/core/global.h"
#include "mads/madsv2/core/player.h"
#include "mads/madsv2/core/mads.h"
#include "mads/madsv2/core/heap.h"
@@ -216,47 +217,6 @@ extern void (*room_parser_code_pointer)();
extern void (*room_error_code_pointer)();
extern void (*room_shutdown_code_pointer)();
-
-
-/* global.c */
-extern char global_release_name[];
-extern char global_release_version[];
-extern char global_release_date[];
-extern char global_release_copyright[];
-
-extern int global[];
-extern int global_list_size;
-
-/* global.c */
-void global_init_code(void);
-void global_daemon_code(void);
-void global_pre_parser_code(void);
-void global_parser_code(void);
-void global_error_code(void);
-
-void global_room_init(void);
-void global_verb_filter(void);
-
-void global_sound_driver(void);
-
-void global_section_constructor(void);
-
-/* global_4.c */
-void global_game_menu(void);
-void global_menu_system_init(void);
-void global_menu_system_shutdown(void);
-void global_emergency_save(void);
-
-/* global_5.c */
-void global_read_config_file(void);
-void global_write_config_file(void);
-void global_load_config_parameters(void);
-void global_unload_config_parameters(void);
-
-/* global_6.c */
-int global_copy_verify(void);
-
-
/* game_1.c */
void game_main(int argc, char **argv);
diff --git a/engines/mads/madsv2/core/global.cpp b/engines/mads/madsv2/core/global.cpp
new file mode 100644
index 00000000000..971c6c114f3
--- /dev/null
+++ b/engines/mads/madsv2/core/global.cpp
@@ -0,0 +1,110 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "common/textconsole.h"
+#include "mads/madsv2/core/global.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+int global[GLOBAL_LIST_SIZE];
+int global_list_size = GLOBAL_LIST_SIZE;
+
+char global_release_name[] = { "ScummVM" };
+char global_release_version[] = { "ScummVM" };
+char global_release_date[] = { "ScummVM" };
+char global_release_copyright[] = { "ScummVM" };
+
+
+void global_init_code() {
+ error("TODO: void global_init_code(void);");
+}
+
+void global_daemon_code() {
+ error("TODO: void global_daemon_code(void);");
+}
+
+void global_pre_parser_code() {
+ error("TODO: void global_pre_parser_code(void);");
+}
+
+void global_parser_code() {
+ error("TODO: void global_parser_code(void);");
+}
+
+void global_error_code() {
+ error("TODO: void global_error_code(void);");
+}
+
+void global_room_init() {
+ error("TODO: void global_room_init(void);");
+}
+
+void global_verb_filter() {
+ error("TODO: void global_verb_filter(void);");
+}
+
+void global_sound_driver() {
+ error("TODO: void global_sound_driver(void);");
+}
+
+void global_section_constructor() {
+ error("TODO: void global_section_constructor(void);");
+}
+
+void global_game_menu() {
+ error("TODO: void global_game_menu(void);");
+}
+
+void global_menu_system_init() {
+ error("TODO: void global_menu_system_init(void);");
+}
+
+void global_menu_system_shutdown() {
+ error("TODO: void global_menu_system_shutdown(void);");
+}
+
+void global_emergency_save() {
+ error("TODO: void global_emergency_save(void);");
+}
+
+void global_read_config_file() {
+ error("TODO: void global_read_config_file(void);");
+}
+
+void global_write_config_file() {
+ error("TODO: void global_write_config_file(void);");
+}
+
+void global_load_config_parameters() {
+ error("TODO: void global_load_config_parameters(void);");
+}
+
+void global_unload_config_parameters() {
+ error("TODO: void global_unload_config_parameters(void);");
+}
+
+int global_copy_verify() {
+ error("TODO: int global_copy_verify(void);");
+}
+
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/core/global.h b/engines/mads/madsv2/core/global.h
index 56d6dc34b00..066343cd456 100644
--- a/engines/mads/madsv2/core/global.h
+++ b/engines/mads/madsv2/core/global.h
@@ -27,6 +27,10 @@
namespace MADS {
namespace MADSV2 {
+extern char global_release_name[];
+extern char global_release_version[];
+extern char global_release_date[];
+extern char global_release_copyright[];
#define GLOBAL_LIST_SIZE 210 /* Global variables array size */
@@ -91,6 +95,34 @@ namespace MADSV2 {
/* ================== Section 6 120 - 139 =================== */
+
+extern char global_release_name[];
+extern char global_release_version[];
+extern char global_release_date[];
+extern char global_release_copyright[];
+
+extern int global[];
+extern int global_list_size;
+
+void global_init_code(void);
+void global_daemon_code(void);
+void global_pre_parser_code(void);
+void global_parser_code(void);
+void global_error_code(void);
+void global_room_init(void);
+void global_verb_filter(void);
+void global_sound_driver(void);
+void global_section_constructor(void);
+void global_game_menu(void);
+void global_menu_system_init(void);
+void global_menu_system_shutdown(void);
+void global_emergency_save(void);
+void global_read_config_file(void);
+void global_write_config_file(void);
+void global_load_config_parameters(void);
+void global_unload_config_parameters(void);
+int global_copy_verify(void);
+
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/core/imath.cpp b/engines/mads/madsv2/core/imath.cpp
index aec30708009..ce2ed3098a0 100644
--- a/engines/mads/madsv2/core/imath.cpp
+++ b/engines/mads/madsv2/core/imath.cpp
@@ -88,7 +88,7 @@ void imath_circular_arc(word *buffer, int radius) {
}
}
-int fastcall imath_random(int from, int unto) {
+int imath_random(int from, int unto) {
return g_engine->getRandomNumber(from, unto);
}
diff --git a/engines/mads/madsv2/core/implode.cpp b/engines/mads/madsv2/core/implode.cpp
new file mode 100644
index 00000000000..a8f6f106965
--- /dev/null
+++ b/engines/mads/madsv2/core/implode.cpp
@@ -0,0 +1,1067 @@
+/* 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/textconsole.h"
+#include "mads/madsv2/core/implode.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+/*
+ * implode_explode.c
+ *
+ * Translated from IMPLODE.ASM / EXPLODE.ASM
+ * Original author : David McKibbin, MPS Labs / MicroProse Software (1992)
+ * Algorithm : LZexe-style LZ77 with Huffman control bits (FAB/Fabrice format)
+ *
+ * Translation notes:
+ * - All segment-register / far-pointer mechanics removed (flat memory model).
+ * - DS:SI / ES:DI read/write patterns replaced with pointer arithmetic.
+ * - The WORK segment layout is preserved as struct fields in the same order
+ * so buffer-size requirements are unchanged.
+ * - 16-bit wraparound arithmetic preserved where it matters (hash indices,
+ * Qlen/Qoff calculations, GetHuff bit pump).
+ */
+
+#include <string.h>
+#include <stdint.h>
+#include "implode.h" /* extern declarations + CMP_* defines */
+
+typedef unsigned char byte;
+typedef unsigned short word;
+
+/* =========================================================================
+ * EXPLODE
+ *
+ * Memory layout (mirrors the assembly WORK segment, total 14348 bytes):
+ *
+ * [ 0.. 3] Zread (unused in flat C; callback pointer held in struct)
+ * [ 4.. 7] Zwrite (unused in flat C)
+ * [ 8.. 9] RWlen (unused in flat C)
+ * [ 10.. 11] guard word (1 extra word before RBuff)
+ * [ 12..2059] RBuff (RBlen=2048 bytes) RBend = RBuff+RBlen-1
+ * [2060..10251] Lempel (8192 bytes)
+ * [10252..14347] WBuff (WBlen=4096 bytes) WBend = WBuff+WBlen-1
+ *
+ * SI (read ptr) is an index into RBuff[0..RBlen-1] (with guard at [-1]).
+ * DI (write ptr) is an index into the combined Lempel+WBuff flat array,
+ * starting at 0 (=Lempel base); WBuff starts at index 8192.
+ *
+ * ========================================================================= */
+
+#define EXP_RBLEN 2048
+#define EXP_WBLEN 4096
+#define EXP_LEMPEL 8192
+
+ /* explode_RBin:
+ * Guard byte trick: before overwriting RBuff with new data, save the byte
+ * that was at rb[EXP_RBLEN] (one past the last valid byte) into rb[-1]
+ * (guard slot). This lets GetWord safely read a 16-bit value when SI is
+ * positioned at the very last byte of the buffer - the high byte comes from
+ * the guard slot after the new fill lands in rb[0..EXP_RBLEN-1].
+ * In C we allocate rb[EXP_RBLEN+1] and use rb[0] as the guard, rb[1..EXP_RBLEN]
+ * as the data, keeping si pointing into [1..EXP_RBLEN] (mirrors assembly SI
+ * pointing into RBuff[0..RBlen-1], with the guard word sitting just below).
+ */
+typedef struct {
+ word(*read_buff) (char *buf, word *size);
+ word(*write_buff)(char *buf, word *size);
+
+ /* Read buffer: rb[0]=guard, rb[1..EXP_RBLEN]=data */
+ byte rb[EXP_RBLEN + 1];
+ int si; /* current read index into rb[], range [1..EXP_RBLEN] */
+ /* si <= EXP_RBLEN => valid byte at rb[si] (mirrors si <= RBend) */
+
+ /* Huffman bit pump (registers BP and DX in the assembly) */
+ word bp; /* bit accumulator */
+ int dx; /* bits remaining before next word load */
+
+ /* Combined Lempel + WBuff flat array.
+ * flat[0..8191] = Lempel (history window)
+ * flat[8192..12287] = WBuff (output staging buffer)
+ * DI is an index into flat[], starting at EXP_LEMPEL (= WBuff base).
+ * Back-references: src = flat[di + bx] where bx is a negative int16.
+ * Minimum src = EXP_LEMPEL - EXP_LEMPEL = 0. No underflow possible.
+ */
+ byte flat[EXP_LEMPEL + EXP_WBLEN];
+ int di; /* write index into flat[], starts at EXP_LEMPEL */
+} ExpState;
+
+/*
+ * explode_RBin -- fill the read buffer.
+ *
+ * Before reading: save rb[si] (which is rb[EXP_RBLEN+1] after last refill,
+ * i.e. one past end) into rb[0] (the guard slot). Then reset si to 1.
+ */
+static void explode_RBin(ExpState *s) {
+ /* Save the byte just past the current buffer end into the guard slot.
+ * In the assembly this is: mov al,[si]; sub si,RBlen; mov [si],al
+ * which saves rb[EXP_RBLEN] to rb[0] (= guard word low byte). */
+ s->rb[0] = s->rb[s->si]; /* save guard byte */
+ s->si = 1; /* reset to start of data region */
+
+ word size = EXP_RBLEN;
+ s->read_buff((char *)(s->rb + 1), &size);
+ /* If fewer bytes were read than requested, the remainder of rb[]
+ * retains its previous content (harmless for a decompressor consuming
+ * exactly the right number of bytes from a well-formed stream). */
+}
+
+/*
+ * explode_WBout -- flush the write (output) buffer.
+ *
+ * Writes flat[EXP_LEMPEL .. di-1] to the output callback, then performs the
+ * Lempel fixup: copies flat[EXP_LEMPEL-4096 .. EXP_LEMPEL-1] (the second half
+ * of the Lempel window) to flat[0 .. 4095] (the first half), then resets di.
+ *
+ * This preserves the last 4096 bytes of history so back-references up to
+ * -8192 bytes remain valid after the reset. The fixup only happens when a
+ * full WBlen buffer was flushed (matching the assembly's "cmp RWlen,WBlen").
+ */
+static void explode_WBout(ExpState *s) {
+ int bytes = s->di - EXP_LEMPEL; /* bytes currently in WBuff */
+ word size = (word)bytes;
+ s->write_buff((char *)(s->flat + EXP_LEMPEL), &size);
+
+ if (bytes == EXP_WBLEN) {
+ /* Lempel fixup: copy second half of Lempel to first half.
+ * Assembly: lea si, WBuff-4096 (= Lempel+4096)
+ * lea di, WBuff-8192 (= Lempel+0)
+ * mov cx, 4096; rep movsw (copies 8192 bytes) */
+ memmove(s->flat, s->flat + EXP_LEMPEL - 4096, 4096);
+ }
+
+ s->di = EXP_LEMPEL; /* reset write pointer to WBuff base */
+}
+
+/* GetByte: if si > EXP_RBLEN (= RBend+1, one past last byte), refill.
+ * Then return rb[si++].
+ * Assembly: cmp si, RBend; jbe skip; call RBin; skip: lodsb */
+static inline byte exp_get_byte(ExpState *s) {
+ if (s->si > EXP_RBLEN)
+ explode_RBin(s);
+ return s->rb[s->si++];
+}
+
+/* GetWord: if si >= EXP_RBLEN (= RBend, only 1 byte left), refill first.
+ * Assembly: cmp si, RBend; jb skip; call RBin; skip: lodsw
+ * The guard byte at rb[0] ensures the second byte of the word is available
+ * even when si pointed to the very last slot before the refill. */
+static inline word exp_get_word(ExpState *s) {
+ if (s->si >= EXP_RBLEN)
+ explode_RBin(s);
+ word val = (word)s->rb[s->si] | ((word)s->rb[s->si + 1] << 8);
+ s->si += 2;
+ return val;
+}
+
+/* GetHuff: extract one bit from the Huffman bit pump.
+ * Returns the bit in CF position (0 or 1).
+ *
+ * Assembly macro:
+ * dec dx
+ * jnz getc
+ * GetWord ; ax = next word
+ * mov dl, 16
+ * shr bp, 1 ; CF = old bp[0]
+ * mov bp, ax ; bp = new word (CF unchanged)
+ * rcl bp, 1 ; bp = (ax<<1) | old_CF
+ * getc:
+ * rcr bp, 1 ; CF = bp[0], bp = (bp>>1) | (in_CF<<15)
+ *
+ * The shr/rcl/rcr dance on reload:
+ * shr bp,1 captures the carry from the now-exhausted old accumulator.
+ * rcl bp,1 after "mov bp,ax" stitches that carry into bit0 of the new word.
+ * rcr bp,1 then extracts bit0 (= saved carry) as the current bit.
+ * Net effect: we get the saved carry bit as the 17th bit extracted, giving
+ * seamless 16-bit-boundary crossing. Verified by simulation to produce bits
+ * in LSB-first order, one word at a time.
+ */
+static inline int exp_get_huff(ExpState *s) {
+ int bit;
+
+ s->dx--;
+ if (s->dx == 0) {
+ word ax = exp_get_word(s);
+ s->dx = 16;
+ /* shr bp,1 -> CF = bp & 1 */
+ int carry = s->bp & 1;
+ /* mov bp, ax then rcl bp,1 -> bp = (ax<<1)|carry, new CF = ax>>15 */
+ s->bp = (word)((ax << 1) | carry);
+ /* fall through: rcr bp,1 below extracts bp[0] = carry as current bit */
+ }
+
+ /* rcr bp,1: CF = bp[0], bp = (bp >> 1) | (CF_in << 15)
+ * CF_in at this point is the CF left by the last operation above (or the
+ * previous iteration's rcr). In the assembly CF is a real flag and
+ * carries implicitly; here we must track it. But note: the ONLY place
+ * CF matters going into rcr is on the reload path (where it was set by
+ * rcl), and on the non-reload path CF is not used (the rcr just rotates
+ * bit15 in, but since we never inspect bp's high bits, it doesn't matter
+ * what rotates in). We use 0 for CF_in on non-reload iterations; the
+ * high bit of bp is never examined by the decoder. */
+ bit = s->bp & 1;
+ s->bp >>= 1; /* bp >> 1, high bit = 0 (safe: only bit0 is inspected) */
+ return bit;
+}
+
+/* PutByte: if di > WBend (= EXP_LEMPEL + EXP_WBLEN - 1), flush first.
+ * Assembly: cmp di, WBend; jbe skip; call WBout; skip: stosb */
+static inline void exp_put_byte(ExpState *s, byte val) {
+ if (s->di > EXP_LEMPEL + EXP_WBLEN - 1)
+ explode_WBout(s);
+ s->flat[s->di++] = val;
+}
+
+/*
+ * explode -- LZ77 decompressor
+ *
+ * Reads compressed data via read_buff, writes decompressed data via write_buff.
+ * work_buff must point to at least 14364 bytes of writable memory (ignored
+ * in the flat C port; state lives on the stack via ExpState).
+ */
+word explode(
+ word(*read_buff) (char *buffer, word *size),
+ word(*write_buff)(char *buffer, word *size),
+ char *work_buff) {
+ (void)work_buff;
+
+ ExpState s;
+ memset(&s, 0, sizeof s);
+ s.read_buff = read_buff;
+ s.write_buff = write_buff;
+
+ /* Force immediate refill on first GetByte/GetWord.
+ * Assembly: lea si, RBuff; add si, RBlen (si = one past end of RBuff) */
+ s.si = EXP_RBLEN + 1;
+
+ /* ES:DI = WBuff base (flat index EXP_LEMPEL) */
+ s.di = EXP_LEMPEL;
+
+ /* Prime the Huffman pump: GetWord, bp = ax, dx = 16 */
+ s.bp = exp_get_word(&s);
+ s.dx = 16;
+
+ /*
+ * FABin: main decode loop
+ *
+ * GetHuff returns the next control bit in CF (carry).
+ * Bit=1 => literal byte follows.
+ * Bit=0 => back-reference.
+ */
+ for (;;) {
+ int bit = exp_get_huff(&s);
+
+ if (bit) {
+ /* Literal: GetByte then PutByte */
+ byte al = exp_get_byte(&s);
+ exp_put_byte(&s, al);
+ continue;
+ }
+
+ /* Back-reference. Second control bit selects near (<00>) or far (<01>). */
+ int cx = 0;
+ bit = exp_get_huff(&s);
+
+ if (!bit) {
+ /*
+ * Code <00XY>: near copy.
+ * Two more Huffman bits give XY (2-bit length field).
+ * Length = XY + 2, range [2..5].
+ * One raw byte gives the negative offset (BH=-1, BL=byte => BX=0xFF00|byte).
+ *
+ * Assembly:
+ * GetHuff; rcl cx,1 (cx = ...X)
+ * GetHuff; rcl cx,1 (cx = ...XY)
+ * inc cx; inc cx (cx = XY + 2)
+ * GetByte
+ * mov bh,-1; mov bl,al (bx = 0xFF00 | al)
+ */
+ int x = exp_get_huff(&s);
+ cx = (cx << 1) | x;
+ int y = exp_get_huff(&s);
+ cx = (cx << 1) | y;
+ cx += 2; /* length [2..5] */
+
+ byte al = exp_get_byte(&s);
+ int bx = (int)(int16_t)(0xFF00 | (word)al); /* signed 16-bit: [-255..-1] */
+
+ /* LP3: copy cx bytes from flat[di + bx] to flat[di], advancing di.
+ * Overlapping copies are intentional (run-length expansion).
+ * Assembly: mov al, es:[bx+di]; PutByte; loop LP3 */
+ while (cx-- > 0) {
+ /* di+bx: since bx is negative and di>=EXP_LEMPEL, result >= 0 */
+ byte b = s.flat[s.di + bx];
+ exp_put_byte(&s, b);
+ }
+ } else {
+ /*
+ * Code <01>: far copy (or special sentinel).
+ * One raw word encodes offset and length:
+ * BL = low byte of word = offset[7:0]
+ * BH = high byte, after processing:
+ * shr bh,3; or bh,0E0h => offset[12:8] packed into bh
+ * AH & 7 = length field (original high byte before shr):
+ * 0 => read aux byte (exit/normalize/long count)
+ * 1..7 => length = field + 2
+ *
+ * Signed offset reconstruction:
+ * bx = (int16_t)( (((ah >> 3) | 0xE0) << 8) | al )
+ * Range: [-8192..-1]
+ */
+ word ax = exp_get_word(&s);
+ byte ah = (byte)(ax >> 8);
+ byte al = (byte)(ax & 0xFF);
+
+ /* Reconstruct BH: shr bh,3 then or bh,0E0h */
+ byte bh = (byte)((ah >> 3) | 0xE0);
+ /* BX as signed 16-bit */
+ int bx = (int)(int16_t)((word)((word)bh << 8) | al);
+
+ /* Length field = original AH & 7 (before the shr) */
+ int len_field = ah & 7;
+
+ if (len_field != 0) {
+ /* count = len_field + 2.
+ * Assembly: mov cl, ah (ah already anded to 7); inc cx; inc cx */
+ cx = len_field + 2;
+
+ /* LP3 copy */
+ while (cx-- > 0) {
+ byte b = s.flat[s.di + bx];
+ exp_put_byte(&s, b);
+ }
+ } else {
+ /*
+ * LP3a: aux byte determines action.
+ * 0 => EXIT
+ * 1 => NORMALIZE (no-op in flat model; just continue)
+ * n => count = n + 1, then LP3 copy
+ */
+ byte aux = exp_get_byte(&s);
+
+ if (aux == 0) {
+ /* EXIT sentinel */
+ break;
+ } else if (aux == 1) {
+ /* LP4: NORMALIZE. In the original this re-normalised
+ * segment:offset pointers for the decompressor's internal
+ * buffers. In the flat C model this is a no-op. */
+ continue;
+ } else {
+ cx = (int)aux + 1;
+ while (cx-- > 0) {
+ byte b = s.flat[s.di + bx];
+ exp_put_byte(&s, b);
+ }
+ }
+ }
+ }
+ }
+
+ /* Exit: flush any remaining output bytes */
+ explode_WBout(&s);
+
+ return CMP_NO_ERROR;
+}
+
+
+/* =========================================================================
+ * IMPLODE
+ *
+ * Memory layout (mirrors the assembly WORK segment, total ~53670 bytes):
+ *
+ * Zread/Zwrite : callback pointers (held in struct, not in the flat buf)
+ * RBptr/RBcnt : read buffer management
+ * WBptr/WBcnt : write buffer management
+ * Zlen : bytes of valid lookahead remaining
+ * Qlen/Qoff : current match length and offset
+ * Norms : bytes since last NORMALIZE code
+ * Delta/ParaZ : segment-fixup bookkeeping (preserved but output only)
+ * Huffptr/bit/man: Huffman packet state
+ * Lempel[8192] : sliding dictionary window
+ * Ziv[ZIV+1] : shadow of Lempel[0..ZIV-1] for wraparound comparisons
+ * Hash[] : (LEMPEL+1+HASH)*2 bytes, combined collision+key table
+ * UnDo[] : (LEMPEL+1)*2 bytes, reverse-thread for unlinking
+ * RBuff[2048] : raw input buffer
+ * WBuff[2048] : raw output buffer
+ *
+ * ========================================================================= */
+
+#define IMP_ZIV 253
+#define IMP_LEMPEL 8192
+#define IMP_NIL (2*IMP_LEMPEL) /* = 16384 = 0x4000, sentinel value */
+#define IMP_HASH 4096
+#define IMP_RBLEN 2048
+#define IMP_WBLEN 2048
+
+ /* Packet buffer: Huffman word (2 bytes) + up to 128 data bytes */
+#define IMP_PKTMAX (2 + 128)
+
+typedef struct {
+ word(*read_buff) (char *buf, word *size);
+ word(*write_buff)(char *buf, word *size);
+
+ /* Read buffer state */
+ byte rb[IMP_RBLEN];
+ byte *rb_ptr; /* next byte to read from rb[] */
+ word rb_cnt; /* bytes remaining incl. current (mirrors RBcnt) */
+
+ /* Write buffer state */
+ byte wb[IMP_WBLEN];
+ byte *wb_ptr; /* next free slot in wb[] */
+ word wb_cnt; /* free bytes remaining in wb[] */
+
+ /* LZ state variables */
+ word zlen; /* valid lookahead bytes */
+ word qlen; /* match length */
+ int16_t qoff; /* match offset (negative) */
+ word norms; /* bytes since last normalize code */
+ int16_t delta; /* counter for paraz */
+ word paraz; /* extra paragraphs needed by explode */
+
+ /* Huffman packet state */
+ byte *huff_ptr; /* next data byte slot in packet[] */
+ word huff_bit; /* current bit mask (1, 2, 4, ..., 0x8000) */
+ word huff_man; /* current Huffman accumulator word */
+ byte packet[IMP_PKTMAX]; /* packet buffer: [0..1]=huff_man, [2..]=data */
+
+ /* Sliding dictionary */
+ byte lempel[IMP_LEMPEL + IMP_ZIV + 1]; /* Lempel[0..8191] + Ziv[0..253] */
+
+ /* Hash table: (IMP_LEMPEL+1+IMP_HASH) word entries.
+ * Indexed by BYTE OFFSET (= position*2).
+ * [0 .. IMP_LEMPEL-1] : collision chain slots (one per Lempel pos)
+ * [IMP_LEMPEL] : sentinel slot (always holds NIL)
+ * [IMP_LEMPEL+1..IMP_LEMPEL+IMP_HASH] : hash key roots
+ * UnDo[0..IMP_LEMPEL]: reverse-thread, indexed by byte offset.
+ *
+ * Both tables store BYTE OFFSETS (position<<1) as values, with NIL=0x4000
+ * marking empty slots.
+ */
+ word hash[IMP_LEMPEL + 1 + IMP_HASH];
+ word undo[IMP_LEMPEL + 1];
+} ImpState;
+
+/* ---- I/O helpers ---- */
+
+/*
+ * implode_RBin -- fill the read buffer.
+ * Returns bytes read (0 = EOF).
+ * Assembly increments RBcnt by (bytes_read+1) then decrements before each use,
+ * so RBcnt==1 means "need refill on next access".
+ */
+static word imp_rb_refill(ImpState *s) {
+ word size = IMP_RBLEN;
+ s->read_buff((char *)s->rb, &size);
+ s->rb_ptr = s->rb;
+ s->rb_cnt = size + 1; /* +1: assembly sets RBcnt = bytes+1 (see RBin) */
+ return size;
+}
+
+/*
+ * Read one byte from the input. Returns -1 (as int) on EOF.
+ *
+ * Assembly pattern (inside Fabrice loop):
+ * dec RBcnt; jnz Gin; call implode_RBin; or ax,ax; jz Zin; jmp @B
+ * Gin: mov bx,RBptr; inc RBptr; mov al,[bx]
+ *
+ * RBcnt starts at 1 after init; first dec makes it 0, triggering refill.
+ * After refill: RBcnt = bytes_read + 1.
+ */
+static int imp_get_byte(ImpState *s) {
+ for (;;) {
+ s->rb_cnt--;
+ if (s->rb_cnt != 0)
+ return *s->rb_ptr++;
+ /* RBcnt hit 0: refill */
+ word got = imp_rb_refill(s);
+ if (got == 0)
+ return -1; /* EOF */
+ /* rb_cnt = got + 1, loop back to decrement */
+ }
+}
+
+/*
+ * implode_WBout -- flush the write (output) buffer.
+ * Resets wb_ptr and wb_cnt. Assembly version:
+ * WBcnt = WBlen, compute bytes = WBptr - &WBuff, reset WBptr = &WBuff
+ */
+static void imp_wb_flush(ImpState *s) {
+ word bytes = (word)(s->wb_ptr - s->wb);
+ s->wb_ptr = s->wb;
+ s->wb_cnt = IMP_WBLEN;
+ if (bytes > 0)
+ s->write_buff((char *)s->wb, &bytes);
+}
+
+/* Write one byte to the output buffer, flushing when full. */
+static void imp_wb_put(ImpState *s, byte val) {
+ *s->wb_ptr++ = val;
+ s->wb_cnt--;
+ if (s->wb_cnt == 0)
+ imp_wb_flush(s);
+}
+
+/* ---- Packet / Huffman output ---- */
+
+/*
+ * Packet -- flush the current Huffman packet to the write buffer and reset.
+ *
+ * Assembly walks si from offset(Huffman) to Huffptr, writing each byte.
+ * The packet layout is: huff_man word (2 bytes LE) followed by data bytes.
+ * After flush: Huffbit=1, Huffman=0, Huffptr = &Huffman+2 (start of data).
+ */
+static void imp_packet(ImpState *s) {
+ /* Store the current Huffman accumulator into packet[0..1] (little-endian).
+ * Note: packet[] was already reset to 0 at start; partial huff_man is
+ * whatever was accumulated before Huffbit overflowed. */
+ s->packet[0] = (byte)(s->huff_man & 0xFF);
+ s->packet[1] = (byte)(s->huff_man >> 8);
+
+ /* Assembly: inc Delta at start of Packet */
+ s->delta++;
+
+ /* Flush all bytes from packet[0] to huff_ptr-1 */
+ byte *p = s->packet;
+ while (p < s->huff_ptr)
+ imp_wb_put(s, *p++);
+
+ /* Reset packet state */
+ s->huff_bit = 1;
+ s->huff_man = 0;
+ s->packet[0] = 0;
+ s->packet[1] = 0;
+ s->huff_ptr = s->packet + 2; /* data starts after the 2-byte Huffman word */
+}
+
+/*
+ * Huff1 -- emit one Huffman control bit.
+ *
+ * Assembly:
+ * or al,al; jz @F
+ * mov ax,Huffbit; or Huffman,ax (set bit if val != 0)
+ * @@: shl Huffbit,1; jnz @F; call Packet (flush when bit overflows 16-bit)
+ */
+static void imp_huff1(ImpState *s, int val) {
+ if (val)
+ s->huff_man |= s->huff_bit;
+ s->huff_bit <<= 1;
+ if (s->huff_bit == 0) {
+ /* Huffbit has shifted out of 16-bit range: flush packet */
+ imp_packet(s);
+ }
+}
+
+/*
+ * push1 -- append one raw data byte to the current packet buffer.
+ * Assembly: mov di,Huffptr; inc Huffptr; mov [di],al
+ */
+static void imp_push1(ImpState *s, byte val) {
+ *s->huff_ptr++ = val;
+}
+
+/* ---- Dictionary management ---- */
+
+/*
+ * Hash key computation.
+ * Assembly (in Link and Match):
+ * mov si, word ptr Lempel[di] ; 16-bit word at lempel[di]
+ * and si, HASH-1 ; mask to [0..IMP_HASH-1]
+ * add si, LEMPEL+1 ; shift into key-table region
+ * shl si, 1 ; convert to byte offset
+ *
+ * Result is a BYTE OFFSET into hash[] pointing at the key root slot.
+ * In C we use a WORD index = si>>1 into the hash[] word array.
+ */
+static inline int imp_hash_key_idx(ImpState *s, int pos) {
+ word w = (word)s->lempel[pos] | ((word)s->lempel[pos + 1] << 8);
+ return (int)(((w & (IMP_HASH - 1)) + IMP_LEMPEL + 1)); /* word index */
+}
+
+/*
+ * Link -- insert lempel[di] at the root of its hash chain.
+ *
+ * Assembly (byte-offset based):
+ * si = key byte offset (= hash_key_idx * 2)
+ * di2 = di * 2
+ * bx = Hash[si>>1] ; old root byte-offset
+ * Hash[di2>>1] = bx ; di's next = old root
+ * Hash[si>>1] = di2 ; new root = di
+ * UnDo[bx>>1] = di2 ; old root back-ptr = di
+ * UnDo[di2>>1] = si ; di back-ptr = key slot
+ *
+ * All values stored are BYTE OFFSETS (position << 1), with NIL = 0x4000.
+ * We store them directly as word values in hash[]/undo[] word arrays,
+ * using word-index = byte-offset >> 1 to access them.
+ */
+static void imp_link(ImpState *s, int di) {
+ int si_idx = imp_hash_key_idx(s, di); /* word index of key slot */
+ int di2 = di * 2; /* byte offset of di's slot */
+ int si2 = si_idx * 2; /* byte offset of key slot */
+
+ word bx = s->hash[si_idx]; /* old root (byte offset) */
+
+ s->hash[di2 / 2] = bx; /* di's next = old root */
+ s->hash[si_idx] = (word)di2; /* new root = di */
+ s->undo[bx / 2] = (word)di2; /* old root back-ptr = di (byte off) */
+ s->undo[di2 / 2] = (word)si2; /* di's back-ptr = key slot (byte off) */
+}
+
+/*
+ * UnLink -- remove lempel[si] from its hash chain.
+ *
+ * Assembly:
+ * si2 = si << 1
+ * bx = UnDo[si2>>1] ; the slot that currently holds si2
+ * if bx != NIL:
+ * Hash[bx>>1] = NIL ; remove si2 from that slot
+ * UnDo[si2>>1] = NIL
+ */
+static void imp_unlink(ImpState *s, int si) {
+ int si2 = si * 2;
+ word bx = s->undo[si2 / 2];
+ if (bx != IMP_NIL) {
+ s->hash[bx / 2] = IMP_NIL;
+ s->undo[si2 / 2] = IMP_NIL;
+ }
+}
+
+/*
+ * Match -- find the longest matching string and insert lempel[di] into
+ * the hash table. Sets s->qlen and s->qoff.
+ *
+ * Entry: di = current encode position (ring index, not DS offset).
+ *
+ * The assembly proc adds offset(Lempel) to get DS-relative pointers for
+ * string comparison. In C we just index s->lempel[] directly.
+ *
+ * The Ziv[] shadow array (s->lempel[IMP_LEMPEL .. IMP_LEMPEL+IMP_ZIV])
+ * mirrors s->lempel[0..IMP_ZIV-1], so repe cmpsb can cross the ring
+ * boundary without explicit wraparound -- comparisons starting near the
+ * end of lempel[] continue into the shadow without going out of bounds.
+ *
+ * AX encodes "remaining CX after repe cmpsb":
+ * AX = ZIV-1 initially (no match found yet)
+ * AX = 0 (ZIV-1 chars matched after hash char = ZIV total)
+ * AX = 0xFFFF (-1 uint16) set by can1 for a full match (je from repe cmpsb)
+ *
+ * Qlen = (uint16)(ZIV - AX) - 1 (wraps correctly for AX=0xFFFF -> Qlen=ZIV)
+ *
+ * Qoff = -(( (di - best_pos/2) & (IMP_LEMPEL-1) ))
+ * where best_pos is the BYTE OFFSET of the best candidate.
+ *
+ * Match also links lempel[di] into the hash table (same as Link but
+ * inlined at the end of can2, so it does NOT call imp_link separately
+ * before the first Match call -- Fabrice calls Match before the main loop).
+ */
+static void imp_match(ImpState *s, int di) {
+ int si_idx = imp_hash_key_idx(s, di); /* word index of key slot */
+ int di2 = di * 2;
+
+ word ax = (word)(IMP_ZIV - 1); /* best "remaining CX" so far */
+ word bp = IMP_NIL; /* byte offset of best candidate */
+
+ /* Walk the hash chain */
+ word bx = s->hash[si_idx];
+ while (bx != IMP_NIL) {
+ int cand = bx / 2; /* candidate position in lempel[] */
+
+ /* Compare lempel[cand+1 .. cand+ZIV-1] against lempel[di+1 .. di+ZIV-1].
+ * First character is guaranteed to match by the hash function.
+ * The Ziv shadow allows comparisons to run past lempel[8191] safely. */
+ int max_cmp = IMP_ZIV - 1;
+ int matched = 0;
+ while (matched < max_cmp &&
+ s->lempel[cand + 1 + matched] == s->lempel[di + 1 + matched])
+ matched++;
+
+ if (matched == max_cmp) {
+ /* Full ZIV-1 chars matched (= can1: full ZIV match with hash char) */
+ bp = bx;
+ ax = (word)(-1); /* sentinel: 0xFFFF */
+ break;
+ }
+
+ /* Remaining = max_cmp - matched. Lower remaining = longer match. */
+ word cx = (word)(max_cmp - matched);
+ if (cx < ax) {
+ bp = bx;
+ ax = cx;
+ }
+
+ bx = s->hash[bx / 2]; /* follow collision chain */
+ }
+
+ /* Compute Qlen: (uint16)(ZIV - ax) - 1
+ * Works for ax=0xFFFF: (uint16)(253 - 65535) = 254, -1 = 253 = ZIV. */
+ word qlen = (word)(IMP_ZIV - ax) - 1;
+ s->qlen = qlen;
+
+ /* Compute Qoff (only meaningful when qlen >= 2):
+ * Assembly: ax = di2 - bp; shr ax,1; and ax, LEMPEL-1; neg ax */
+ if (qlen >= 2) {
+ word diff = (word)((word)di2 - bp);
+ diff >>= 1;
+ diff &= (IMP_LEMPEL - 1);
+ s->qoff = -(int16_t)diff;
+ }
+
+ /* Insert di into hash table (mirrors the inlined Link at end of can2).
+ * bx here is the current root of the key slot (from the final iteration
+ * of the chain walk, or the initial value if chain was empty). */
+ bx = s->hash[si_idx]; /* re-read current root */
+ s->hash[di2 / 2] = bx;
+ s->hash[si_idx] = (word)di2;
+ s->undo[bx / 2] = (word)di2;
+ s->undo[di2 / 2] = (word)(si_idx * 2);
+}
+
+/*
+ * RWinit -- initialise I/O pointers. Mirrors RWinit proc.
+ */
+static void imp_rwinit(ImpState *s) {
+ s->rb_cnt = 1; /* triggers refill on first access */
+ s->wb_ptr = s->wb;
+ s->wb_cnt = IMP_WBLEN;
+}
+
+/*
+ * Fabrice -- the main LZ77 encode loop.
+ *
+ * Corresponds to the Fabrice proc in IMPLODE.ASM.
+ *
+ * DI (ring pos) = current encode/input position in lempel[] ring.
+ * SI (ring pos) = oldest position (evicted from dictionary as we advance).
+ * Both wrap mod IMP_LEMPEL via "and si/di, LEMPEL-1".
+ */
+static void imp_fabrice(ImpState *s) {
+ int di, si;
+
+ imp_rwinit(s);
+
+ /* Initialise UnDo to NIL */
+ for (int i = 0; i <= IMP_LEMPEL; i++)
+ s->undo[i] = IMP_NIL;
+
+ /* Initialise Hash to NIL */
+ for (int i = 0; i < IMP_LEMPEL + 1 + IMP_HASH; i++)
+ s->hash[i] = IMP_NIL;
+
+ /* Zero Lempel + Ziv area */
+ memset(s->lempel, 0, IMP_LEMPEL + IMP_ZIV - 1);
+
+ /* Initialise Huffman packet state */
+ s->huff_bit = 1;
+ s->huff_man = 0;
+ memset(s->packet, 0, IMP_PKTMAX);
+ s->huff_ptr = s->packet + 2;
+
+ /* Initialise LZ state */
+ s->norms = 0;
+ s->delta = 0;
+ s->paraz = 0;
+
+ /*
+ * Read the first IMP_ZIV bytes into lempel[IMP_LEMPEL-ZIV .. IMP_LEMPEL-1].
+ * Also mirror the first ZIV-1 of them into the Ziv shadow at
+ * lempel[IMP_LEMPEL .. IMP_LEMPEL + ZIV - 2].
+ *
+ * Assembly:
+ * di = offset Ziv - ZIV (= Lempel + LEMPEL - ZIV in DS-relative)
+ * cx = ZIV
+ * Loop1: dec RBcnt; jnz @F; call implode_RBin; jz GotZIV; jmp Loop1
+ * @@: mov si,RBptr; inc RBptr; movsb; loop Loop1
+ *
+ * In flat C: write to lempel[IMP_LEMPEL - ZIV + i], and also to
+ * lempel[IMP_LEMPEL + i] for i < ZIV-1 (the Ziv shadow).
+ */
+ di = IMP_LEMPEL - IMP_ZIV; /* ring index: encode ptr starts here */
+ si = 0; /* ring index: oldest (tail) ptr */
+ s->zlen = 0;
+
+ for (int i = 0; i < IMP_ZIV; i++) {
+ int ch = imp_get_byte(s);
+ if (ch < 0) break;
+ s->lempel[IMP_LEMPEL - IMP_ZIV + i] = (byte)ch;
+ if (i < IMP_ZIV - 1)
+ s->lempel[IMP_LEMPEL + i] = (byte)ch; /* Ziv shadow */
+ s->zlen++;
+ }
+
+ /* GotZIV: Zlen = min(ZIV, file_size). Call initial Match. */
+ imp_match(s, di);
+
+ /*
+ * Main encode loop (Next label in assembly).
+ */
+ while (s->zlen > 0) {
+
+ /* Clip Qlen to available lookahead */
+ if (s->qlen > s->zlen)
+ s->qlen = s->zlen;
+
+ int save_di = di;
+ int save_si = si;
+
+ /*
+ * Decide encoding type.
+ *
+ * Assembly:
+ * cmp ax, 2; jb DoLit => Qlen < 2: literal
+ * ja DoMov => Qlen > 2: copy
+ * ; Qlen == 2:
+ * cmp Qoff, -100h; jg DoMov => Qoff > -256: copy; else literal
+ */
+ int qlen = (int)(int16_t)s->qlen; /* treat as signed for comparison */
+ int qoff = (int)s->qoff;
+
+ if (qlen < 2 || (qlen == 2 && qoff <= -256)) {
+ /*
+ * DoLit: emit a literal byte.
+ * Huff bit 1, then push the raw byte.
+ * Qlen forced to 1 so we advance by exactly 1 character.
+ */
+ s->qlen = 1;
+ imp_huff1(s, 1);
+ imp_push1(s, s->lempel[di]);
+
+ } else {
+ imp_huff1(s, 0); /* first Huff bit = 0 for all copies */
+
+ if (qlen <= 5 && qoff > -256) {
+ /*
+ * NearCopy: Qlen in [2..5], Qoff in [-255..-1].
+ * Code: <00XY>, offset_byte.
+ * XY encodes Qlen-2 as 2 bits: bit1=(enc>>1)&1, bit0=enc&1.
+ * Offset byte = -(Qoff) = positive offset magnitude.
+ *
+ * Assembly:
+ * Huff1(0); Huff1(0)
+ * mov ax,Qlen; dec ax; dec ax; push ax
+ * and al,2; Huff1(al) (= bit1 of enc)
+ * pop ax; and al,1; Huff1(al) (= bit0 of enc)
+ * mov ax,Qoff; call push1 (low byte = -offset)
+ */
+ imp_huff1(s, 0);
+ int enc = qlen - 2; /* 0..3 */
+ imp_huff1(s, (enc >> 1) & 1); /* bit1 */
+ imp_huff1(s, enc & 1); /* bit0 */
+ imp_push1(s, (byte)(-qoff)); /* positive offset byte */
+
+ } else {
+ /*
+ * FarCopy: Qlen in [2..9] and Qoff in [-8191..-1], or Qlen > 5.
+ * Code: <01>, then a 2-byte vector word, then optional length byte.
+ *
+ * Vector word format:
+ * Low byte: Qoff & 0xFF (offset low 8 bits)
+ * High byte: (Qoff >> 8) << 3 ORed with length field
+ * Length field (3 bits):
+ * 0 => LongCopy (aux length byte follows)
+ * 1..7 => FarCopy, length = field + 2 (range [3..9])
+ *
+ * Note: Qlen == 2 and Qoff <= -256 hits DoLit (above), so
+ * minimum FarCopy length is 2 with Qoff <= -256... actually
+ * the assembly checks: DoMov if Qlen>5 OR Qoff<=-256 when Qlen==2.
+ * But "Far5" label handles Qlen>5 OR Qoff<=-255.
+ * For Qlen==2 and Qoff<=-256 we already went to DoLit.
+ * So here Qlen >= 2 and (Qlen > 5 OR Qoff <= -256 OR Qlen==2 case not reached).
+ *
+ * Assembly Far5:
+ * Huff1(1)
+ * mov ax,Qoff; push1(al) [low byte of offset]
+ * mov al,ah; shl al,3 [high byte, shifted up 3]
+ * mov bx,Qlen; cmp bx,9; ja Far9
+ * dec bx; dec bx; or al,bl; push1(al) [length in low 3 bits]
+ * Far9: (LongCopy, Qlen > 9)
+ * push1(al) [high byte with length=0]
+ * mov ax,bx; dec ax; push1(al) [Qlen-1 as aux byte]
+ */
+ imp_huff1(s, 1);
+ imp_push1(s, (byte)(qoff & 0xFF)); /* offset low byte */
+ byte hi = (byte)(((qoff >> 8) & 0xFF) << 3); /* hi byte, length field = 0 */
+
+ if (qlen <= 9) {
+ hi |= (byte)(qlen - 2); /* pack length into low 3 bits */
+ imp_push1(s, hi);
+ } else {
+ imp_push1(s, hi); /* length field = 0 => aux follows */
+ imp_push1(s, (byte)(qlen - 1)); /* aux length byte */
+ }
+ }
+ }
+
+ /*
+ * Cont: bookkeeping after emitting the code.
+ *
+ * Assembly:
+ * sub Delta, Qlen; jge Zok
+ * @@: inc ParaZ; add Delta,10h; cmp Delta,0; jl @B
+ */
+ s->delta -= (int16_t)s->qlen;
+ while (s->delta < 0) {
+ s->paraz++;
+ s->delta += 0x10;
+ }
+
+ /*
+ * Norms tracking: emit a NORMALIZE code every ~40 KB (0xA000 bytes).
+ * The NORMALIZE code tells explode to re-normalise its segment pointers;
+ * in the flat C decompressor it is a no-op, but we must emit it to
+ * keep the bitstream format compatible.
+ *
+ * Code: Huff(0), Huff(1), push(0x00), push(0xF0), push(0x01)
+ */
+ s->norms = (word)(s->norms + s->qlen);
+ if (s->norms >= 0xA000) {
+ imp_huff1(s, 0);
+ imp_huff1(s, 1);
+ imp_push1(s, 0x00);
+ imp_push1(s, 0xF0);
+ imp_push1(s, 0x01);
+ s->norms = 0;
+ }
+
+ /*
+ * Restore DI and SI, then advance through the input by Qlen characters,
+ * maintaining the hash dictionary.
+ *
+ * Assembly (Loop2):
+ * call Link ; add lempel[di] to dict (skipped on first iteration
+ * call UnLink ; via the "jmp short @F" before Loop2)
+ * ; read next character into lempel[si]
+ * if si < ZIV-1: also write lempel[LEMPEL+si] (Ziv shadow)
+ * inc si; inc di; and si,LEMPEL-1; and di,LEMPEL-1
+ * dec Qlen; jnz Loop2
+ *
+ * Note: on the FIRST iteration we skip Link (jump to UnLink directly)
+ * because the current di was already linked by Match().
+ */
+ di = save_di;
+ si = save_si;
+
+ int qlen_advance = (int)(int16_t)s->qlen;
+ for (int k = 0; k < qlen_advance; k++) {
+ if (k > 0) {
+ /* Link lempel[di] into dictionary (skipped on k=0 since
+ * Match already inserted it). */
+ imp_link(s, di);
+ }
+
+ /* UnLink the oldest entry (evict from tail of window) */
+ imp_unlink(s, si);
+
+ /* Read next character and store it at lempel[si] */
+ int ch = imp_get_byte(s);
+ if (ch >= 0) {
+ s->lempel[si] = (byte)ch;
+ if (si < IMP_ZIV - 1)
+ s->lempel[IMP_LEMPEL + si] = (byte)ch; /* Ziv shadow */
+ } else {
+ /* EOF: Zin label -- shrink Zlen */
+ s->zlen--;
+ }
+
+ si = (si + 1) & (IMP_LEMPEL - 1);
+ di = (di + 1) & (IMP_LEMPEL - 1);
+ }
+
+ /* Find next match for the new di position */
+ imp_match(s, di);
+ }
+
+ /*
+ * Exit: emit the EXIT sentinel code, flush packet and write buffer.
+ * Code: Huff(0), Huff(1), push(0x00), push(0xF0), push(0x00)
+ */
+ imp_huff1(s, 0);
+ imp_huff1(s, 1);
+ imp_push1(s, 0x00);
+ imp_push1(s, 0xF0);
+ imp_push1(s, 0x00);
+
+ imp_packet(s); /* WBend: flush final packet */
+ imp_wb_flush(s); /* flush write buffer */
+}
+
+/*
+ * implode -- LZ77 compressor.
+ *
+ * type and dsize are accepted for API compatibility but ignored; the
+ * assembly original also ignored them (always binary mode, 8 KB window).
+ * work_buff is ignored in the flat C port (state lives in heap via ImpState).
+ */
+word implode(
+ word(*read_buff) (char *buffer, word *size),
+ word(*write_buff)(char *buffer, word *size),
+ char *work_buff,
+ word *type,
+ word *dsize) {
+ (void)work_buff;
+ (void)type;
+ (void)dsize;
+
+ /* ImpState is large (~53 KB); allocate on heap, not stack. */
+ ImpState *s = (ImpState *)malloc(sizeof(ImpState));
+ if (!s) return CMP_ABORT;
+ memset(s, 0, sizeof * s);
+
+ s->read_buff = read_buff;
+ s->write_buff = write_buff;
+
+ imp_fabrice(s);
+
+ free(s);
+ return CMP_NO_ERROR;
+}
+
+/* =========================================================================
+ * CRC32
+ *
+ * Standard CRC-32 (ISO 3309, polynomial 0xEDB88320, reflected).
+ * Not present in the two ASM files but declared in the shared header.
+ * ========================================================================= */
+
+long crc32(unsigned char *buffer, word *size, long *old_crc) {
+ /* Build table at first call for polynomial 0xEDB88320 (reflected CRC-32) */
+ static uint32_t crc_table[256];
+ static int table_init = 0;
+ if (!table_init) {
+ for (int i = 0; i < 256; i++) {
+ uint32_t c = (uint32_t)i;
+ for (int j = 0; j < 8; j++)
+ c = (c & 1) ? (0xEDB88320u ^ (c >> 1)) : (c >> 1);
+ crc_table[i] = c;
+ }
+ table_init = 1;
+ }
+
+ uint32_t crc = (uint32_t)(~(*old_crc));
+ word len = *size;
+ for (word i = 0; i < len; i++)
+ crc = (crc >> 8) ^ crc_table[(crc ^ buffer[i]) & 0xFF];
+ *old_crc = (long)(~crc);
+ return *old_crc;
+}
+
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/core/implode.h b/engines/mads/madsv2/core/implode.h
index 35598551289..aaaa5d1b278 100644
--- a/engines/mads/madsv2/core/implode.h
+++ b/engines/mads/madsv2/core/implode.h
@@ -22,7 +22,7 @@
#ifndef MADS_CORE_IMPLODE_H
#define MADS_CORE_IMPLODE_H
-#include "common/scummsys.h"
+#include "mads/madsv2/core/general.h"
namespace MADS {
namespace MADSV2 {
diff --git a/engines/mads/madsv2/core/inter.cpp b/engines/mads/madsv2/core/inter.cpp
index 62a8b39387e..764c3e2d010 100644
--- a/engines/mads/madsv2/core/inter.cpp
+++ b/engines/mads/madsv2/core/inter.cpp
@@ -52,7 +52,7 @@ namespace MADSV2 {
#define disable_error_check
-extern int extra_display_object;
+int extra_display_object;
int stroke_type = STROKE_NONE; /* Current stroke type */
diff --git a/engines/mads/madsv2/core/kernel.cpp b/engines/mads/madsv2/core/kernel.cpp
index 477e3f7b857..5ac6d865c37 100644
--- a/engines/mads/madsv2/core/kernel.cpp
+++ b/engines/mads/madsv2/core/kernel.cpp
@@ -69,7 +69,7 @@ namespace MADSV2 {
extern int first_inven;
#define OMR 40 /* OUAF_MAX_ROOMS in global.mac */
-extern int room_state[OMR];
+int room_state[OMR];
byte video_mode;
RoomPtr room = NULL;
diff --git a/engines/mads/madsv2/core/keys.cpp b/engines/mads/madsv2/core/keys.cpp
index b5bccf65277..88870e0c9d0 100644
--- a/engines/mads/madsv2/core/keys.cpp
+++ b/engines/mads/madsv2/core/keys.cpp
@@ -27,6 +27,28 @@
namespace MADS {
namespace MADSV2 {
+word keys_special_button;
+
+void keys_install() {
+ // No implementation in ScummVM
+}
+
+void keys_remove() {
+ // No implementation in ScummVM
+}
+
+int keys_check_install() {
+ error("TODO: keys_check_install");
+}
+
+void keys_enable() {
+ error("TODO: keys_enable");
+}
+
+void keys_disable() {
+ error("TODO: keys_disable");
+}
+
int keys_any() {
return g_engine->hasPendingKey();
}
diff --git a/engines/mads/madsv2/core/buffer_2.cpp b/engines/mads/madsv2/core/lib.cpp
similarity index 77%
rename from engines/mads/madsv2/core/buffer_2.cpp
rename to engines/mads/madsv2/core/lib.cpp
index 74ff0e10b5e..967103ab013 100644
--- a/engines/mads/madsv2/core/buffer_2.cpp
+++ b/engines/mads/madsv2/core/lib.cpp
@@ -19,25 +19,18 @@
*
*/
-#include "mads/madsv2/core/general.h"
-#include "mads/madsv2/core/mem.h"
+#include "common/debug.h"
+#include "mads/madsv2/core/lib.h"
namespace MADS {
namespace MADSV2 {
-bool buffer_free(Buffer *buf) {
- bool flag = false;
+char mads_dev_lib_version[5] = lib_version;
+char mads_dev_lib_date[11] = lib_date;
- if (buf->data != NULL) {
- mem_free(buf->data);
- flag = true;
- }
-
- buf->data = NULL;
- buf->x = 0;
- buf->y = 0;
-
- return flag;
+void lib_show_version() {
+ debug(1, "(Mads development library version %s as of %s)\n",
+ mads_dev_lib_version, mads_dev_lib_date);
}
} // namespace MADSV2
diff --git a/engines/mads/madsv2/core/magic.cpp b/engines/mads/madsv2/core/magic.cpp
index 7c2999627b1..8a0bed8d599 100644
--- a/engines/mads/madsv2/core/magic.cpp
+++ b/engines/mads/madsv2/core/magic.cpp
@@ -58,7 +58,7 @@ int magic_low_fade_bound = 1;
int magic_high_fade_bound = 252;
-void fastcall magic_get_grey_values(Palette *pal, byte *grey_value,
+void magic_get_grey_values(Palette *pal, byte *grey_value,
int base_color, int num_colors) {
int i;
for (i = 0; i < num_colors; i++) {
@@ -66,7 +66,7 @@ void fastcall magic_get_grey_values(Palette *pal, byte *grey_value,
}
}
-void fastcall magic_grey_palette(Palette *pal) {
+void magic_grey_palette(Palette *pal) {
byte grey[256];
int count;
@@ -87,7 +87,7 @@ void fastcall magic_grey_palette(Palette *pal) {
/* produces a 64-byte "grey_table" containing the number of grey
/* values of each intensity level.
*/
-void fastcall magic_grey_popularity(byte *grey_list, byte *grey_table, int num_colors) {
+void magic_grey_popularity(byte *grey_list, byte *grey_table, int num_colors) {
int i;
memset(grey_table, 0, 64);
for (i = 0; i < num_colors; i++) {
@@ -95,19 +95,19 @@ void fastcall magic_grey_popularity(byte *grey_list, byte *grey_table, int num_c
}
}
-void fastcall magic_set_color_flags(byte r, byte g, byte b) {
+void magic_set_color_flags(byte r, byte g, byte b) {
magic_color_flags[0] = r;
magic_color_flags[1] = g;
magic_color_flags[2] = b;
}
-void fastcall magic_set_color_values(byte r, byte g, byte b) {
+void magic_set_color_values(byte r, byte g, byte b) {
magic_color_values[0] = r;
magic_color_values[1] = g;
magic_color_values[2] = b;
}
-void fastcall magic_map_to_grey_ramp(Palette *pal,
+void magic_map_to_grey_ramp(Palette *pal,
int base_color, int num_colors,
int base_grey, int num_greys,
MagicGreyPtr magic_map) {
@@ -188,7 +188,7 @@ void fastcall magic_map_to_grey_ramp(Palette *pal,
}
-void fastcall magic_grey_ramp_palette(Palette pal, int num_greys) {
+void magic_grey_ramp_palette(Palette pal, int num_greys) {
int base_grey;
int base_color, num_colors;
int count;
@@ -206,7 +206,7 @@ void fastcall magic_grey_ramp_palette(Palette pal, int num_greys) {
}
-void fastcall magic_fade_to_grey(Palette pal, byte *map_pointer,
+void magic_fade_to_grey(Palette pal, byte *map_pointer,
int base_color, int num_colors,
int base_grey, int num_greys,
int tick_delay, int steps) {
@@ -307,7 +307,7 @@ done:
}
-void fastcall magic_fade_from_grey(RGBcolor *pal, Palette target,
+void magic_fade_from_grey(RGBcolor *pal, Palette target,
int base_color, int num_colors,
int base_grey, int num_greys,
int tick_delay, int steps) {
@@ -413,7 +413,7 @@ done:
/* corners is pulled diagonally across the screen to bring in
/* the new view.
*/
-void fastcall magic_screen_change_corner(Buffer *new_screen, Palette pal,
+void magic_screen_change_corner(Buffer *new_screen, Palette pal,
int corner_id,
int buffer_base_x, int buffer_base_y,
int screen_base_x, int screen_base_y,
@@ -568,7 +568,7 @@ void fastcall magic_screen_change_corner(Buffer *new_screen, Palette pal,
/* Picture-to-picture transition in which the new picture sweeps
/* in from either the right or left edge.
*/
-void fastcall magic_screen_change_edge(Buffer *new_screen, Palette pal,
+void magic_screen_change_edge(Buffer *new_screen, Palette pal,
int edge_id,
int buffer_base_x, int buffer_base_y,
int screen_base_x, int screen_base_y,
@@ -678,7 +678,7 @@ void fastcall magic_screen_change_edge(Buffer *new_screen, Palette pal,
/* brought in with either expanding or contracting concentric
* circles.
*/
-void fastcall magic_screen_change_circle(Buffer *new_screen, Palette pal,
+void magic_screen_change_circle(Buffer *new_screen, Palette pal,
int inward_flag,
int buffer_base_x, int buffer_base_y,
int screen_base_x, int screen_base_y,
@@ -840,7 +840,7 @@ void fastcall magic_screen_change_circle(Buffer *new_screen, Palette pal,
mouse_show();
}
-void fastcall magic_shrink_buffer(Buffer *from, Buffer *unto) {
+void magic_shrink_buffer(Buffer *from, Buffer *unto) {
char *from_ptr;
char *unto_ptr;
int x_count, y_count;
@@ -892,7 +892,7 @@ void fastcall magic_shrink_buffer(Buffer *from, Buffer *unto) {
}
-int fastcall magic_shrinking_buffer(Buffer *source, Buffer *rear,
+int magic_shrinking_buffer(Buffer *source, Buffer *rear,
int grow_flag,
int buffer_base_x, int buffer_base_y,
int screen_base_x, int screen_base_y,
@@ -1066,7 +1066,7 @@ done:
}
-void fastcall magic_swap_me_in_the_dark_baby(byte *swap,
+void magic_swap_me_in_the_dark_baby(byte *swap,
RGBcolor *pal,
int start) {
int static_start;
@@ -1095,7 +1095,7 @@ void fastcall magic_swap_me_in_the_dark_baby(byte *swap,
}
-void fastcall magic_swap_foreground(byte *background_table,
+void magic_swap_foreground(byte *background_table,
Palette background_palette) {
int count;
byte *old_palette;
@@ -1145,7 +1145,7 @@ done:
}
}
-int fastcall magic_closest_color(RGBcolor *match_color,
+int magic_closest_color(RGBcolor *match_color,
byte *list,
int list_wrap,
int list_length) {
diff --git a/engines/mads/madsv2/core/mcga.cpp b/engines/mads/madsv2/core/mcga.cpp
index 32ce3a50949..0c0cbffd4a0 100644
--- a/engines/mads/madsv2/core/mcga.cpp
+++ b/engines/mads/madsv2/core/mcga.cpp
@@ -31,6 +31,7 @@ namespace MADSV2 {
#define mcga_retrace_magic 14 /* Dave McKibbin's magic heuristic # */
+word mcga_shakes = false;
int mcga_retrace_computed = false;
word mcga_retrace_ticks = 0;
int mcga_retrace_max_colors = 256;
diff --git a/engines/mads/madsv2/core/mem.cpp b/engines/mads/madsv2/core/mem.cpp
index 1e4dc1378b3..e06fca2c525 100644
--- a/engines/mads/madsv2/core/mem.cpp
+++ b/engines/mads/madsv2/core/mem.cpp
@@ -88,7 +88,7 @@ void mem_restore_free(void) {
// No implementation
}
-long fastcall mem_conv_get_avail() {
+long mem_conv_get_avail() {
return 999999;
}
diff --git a/engines/mads/madsv2/core/midi.cpp b/engines/mads/madsv2/core/midi.cpp
new file mode 100644
index 00000000000..e7cb7ebd7b2
--- /dev/null
+++ b/engines/mads/madsv2/core/midi.cpp
@@ -0,0 +1,57 @@
+/* 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/textconsole.h"
+#include "mads/madsv2/core/midi.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+void midi_install() {
+ // No implementation in ScummVM
+}
+
+void midi_uninstall() {
+ // No implementation in ScummVM
+}
+
+void midi_play(char name[30]) {
+ warning("TODO: midi_play");
+}
+
+void midi_stop() {
+ warning("TODO: midi_stop");
+}
+
+void midi_pause() {
+ warning("TODO: midi_pause");
+}
+
+void midi_resume() {
+ warning("TODO: midi_resume");
+}
+
+void midi_loop() {
+ warning("TODO: midi_loop");
+}
+
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/core/mouse.cpp b/engines/mads/madsv2/core/mouse.cpp
index d006aa52bdb..2c29c54ff1c 100644
--- a/engines/mads/madsv2/core/mouse.cpp
+++ b/engines/mads/madsv2/core/mouse.cpp
@@ -51,6 +51,8 @@ static const byte cursor_mask[16][16] = {
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
};
+Buffer mouse_cursor_buffer;
+
int mouse_button = -1;
int mouse_status = 0;
int mouse_x = 0;
@@ -64,6 +66,7 @@ bool mouse_any_stroke = false;
int mouse_old_x = 0;
int mouse_old_y = 0;
long mouse_clock = 0;
+byte mouse_showing = 0;
int mouse_hot_x = 0;
int mouse_hot_y = 0;
@@ -88,29 +91,12 @@ void mouse_force(int x, int y) {
g_system->warpMouse(x, y);
}
-
-/*
-/* mouse_in_box()
-/*
-/* Returns true if the mouse is in the specified box
-/*
-*/
-int fastcall mouse_in_box(int ul_x, int ul_y, int lr_x, int lr_y) {
- return (
- ((mouse_x >= ul_x) && (mouse_x <= lr_x)) &&
- ((mouse_y >= ul_y) && (mouse_y <= lr_y))
- );
+int mouse_in_box(int ul_x, int ul_y, int lr_x, int lr_y) {
+ return ((mouse_x >= ul_x) && (mouse_x <= lr_x)) &&
+ ((mouse_y >= ul_y) && (mouse_y <= lr_y));
}
-
-
-/*
-/* mouse_init_cycle()
-/*
-/* Call at beginning of routine which will use double screen
-/* cursor interaction; initializes global variables.
-*/
-void fastcall mouse_init_cycle(void) {
+void mouse_init_cycle() {
mouse_old_x = -1;
mouse_old_y = -1;
@@ -119,14 +105,7 @@ void fastcall mouse_init_cycle(void) {
mouse_start_stroke = false;
}
-
-/*
-/* mouse_begin_cycle()
-/*
-/* Call once at beginning of each input loop. Reads mouse cursor
-/* information, and checks double cursor status.
-*/
-void fastcall mouse_begin_cycle(int double_flag) {
+void mouse_begin_cycle(int double_flag) {
if (double_flag) mouse_check_double();
mouse_old_x = mouse_x;
@@ -156,13 +135,7 @@ void fastcall mouse_begin_cycle(int double_flag) {
mouse_any_stroke = (mouse_stroke_going || mouse_stop_stroke);
}
-/*
-/* mouse_end_cycle()
-/*
-/* Call once each loop at end of loop. Clears cursor freedom
-/* semaphore, and performs any timing that might be necessary.
-*/
-void fastcall mouse_end_cycle(int double_flag, int timing_flag) {
+void mouse_end_cycle(int double_flag, int timing_flag) {
if (double_flag) {
mouse_double_freedom(true);
}
@@ -222,6 +195,83 @@ void mouse_video_update(int from_x, int from_y, int unto_x, int unto_y,
if (refresh_flag) mouse_refresh_done();
mouse_thaw();
}
+
+int mouse_set_hotspot(int spot_x, int spot_y) {
+ return 0;
+}
+
+void mouse_change_cursor_begin() {
+}
+
+void mouse_change_cursor_end() {
+}
+
+void mouse_screen_swap(int mode) {
+ mouse_video_mode = mode;
+}
+
+int mouse_get_video_mode() {
+ return mouse_video_mode;
+}
+
+void mouse_begin_double(int first_video_mode, int second_video_mode,
+ int mono_to_right, int auto_freedom) {
+}
+
+void mouse_check_double() {
+}
+
+void mouse_end_double() {
+}
+
+void mouse_double_freedom(int freedom_flag) {
+}
+
+int mouse_get_status(int *x, int *y) {
+ return 0;
+}
+
+void mouse_timing() {
+}
+
+void mouse_freeze() {
+}
+
+void mouse_thaw() {
+}
+
+void mouse_horiz_bound(int min_x, int max_x) {
+}
+
+void mouse_vert_bound(int min_y, int max_y) {
+}
+
+void mouse_set_work_buffer(byte *work_buffer, int wrap_value) {
+}
+
+void mouse_set_view_port_loc(int x1, int y1, int x2, int y2) {
+}
+
+void mouse_set_view_port(int dx, int dy) {
+}
+
+int mouse_refresh_view_port() {
+ return 0;
+}
+
+void mouse_refresh_done() {
+}
+
+void mouse_disable_scale() {
+}
+
+void mouse_hard_cursor_mode(int mode, Palette *mypal) {
+}
+
+const byte *mouse_get_stack() {
+ error("TODO: mouse_get_stack");
+}
+
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/core/mouse.h b/engines/mads/madsv2/core/mouse.h
index 623baedd040..238649b714f 100644
--- a/engines/mads/madsv2/core/mouse.h
+++ b/engines/mads/madsv2/core/mouse.h
@@ -83,10 +83,30 @@ extern void mouse_refresh_done();
extern void mouse_disable_scale();
extern void mouse_hard_cursor_mode(int mode, Palette *mypal);
extern const byte *mouse_get_stack();
+
+/**
+ * Returns true if the mouse is in the specified box
+ */
extern int mouse_in_box(int ul_x, int ul_y, int lr_x, int lr_y);
+
+/**
+ * Call at beginning of routine which will use double screen
+ * cursor interaction; initializes global variables.
+ */
extern void mouse_init_cycle();
+
+/**
+ * Call once at beginning of each input loop. Reads mouse cursor
+ * information, and checks double cursor status.
+ */
extern void mouse_begin_cycle(int double_flag);
+
+/**
+ * Call once each loop at end of loop. Clears cursor freedom
+ * semaphore, and performs any timing that might be necessary.
+ */
extern void mouse_end_cycle(int double_flag, int timing_flag);
+
extern void mouse_cursor_sprite(SeriesPtr series, int id);
extern void mouse_video_init();
extern void mouse_video_update(int from_x, int from_y,
diff --git a/engines/mads/madsv2/core/pack.cpp b/engines/mads/madsv2/core/pack.cpp
index 2bbfb82d094..bf2438ea0ce 100644
--- a/engines/mads/madsv2/core/pack.cpp
+++ b/engines/mads/madsv2/core/pack.cpp
@@ -36,6 +36,7 @@ namespace MADSV2 {
byte *pack_special_buffer = NULL;
void (*(pack_special_function))() = NULL;
byte *pack_read_memory_ptr;
+byte *pack_write_memory_ptr;
long pack_read_size; /* Size left to read */
long pack_read_count; /* Size read so far */
long pack_write_size; /* Size left to write */
@@ -102,7 +103,7 @@ word (*pack_pFABexp2_routine)(
char *work_buff) = NULL;
-word pack_read_memory(void *buffer, word *mysize) {
+word pack_read_memory(char *buffer, word *mysize) {
word cx = *mysize;
uint32 remaining = pack_read_size;
word return_value = 0;
@@ -182,7 +183,7 @@ done:
return read_this_time;
}
-word pack_write_file(void *buffer, word *size) {
+word pack_write_file(char *buffer, word *size) {
word write_this_time;
if (pack_write_size >= 0) {
diff --git a/engines/mads/madsv2/core/pfab.cpp b/engines/mads/madsv2/core/pfab.cpp
new file mode 100644
index 00000000000..3b26f4b1205
--- /dev/null
+++ b/engines/mads/madsv2/core/pfab.cpp
@@ -0,0 +1,828 @@
+/* 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/textconsole.h"
+#include "mads/madsv2/core/pfab.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+/*
+ * pfab.cpp -- LZ77 sliding-dictionary compressor/expander
+ *
+ * Ported from MicroProse "MPS Labs Graphic Library" assembly sources:
+ * pFABcomp.asm (David McKibbin, September 5 1992)
+ * pFABexp0.asm (file-to-file decompressor)
+ * pFABexp1.asm (file-to-memory decompressor)
+ * pFABexp2.asm (memory-to-memory decompressor)
+ *
+ * Copyright (c) 1992 MicroProse Software. All Rights Reserved.
+ * C port preserves all algorithmic behaviour of the original assembly.
+ *
+ * Algorithm notes
+ * ---------------
+ * Compressed stream format (PKWARE/LZexe hybrid, "FAB" magic):
+ *
+ * Header : 'F','A','B', DICT (4 bytes)
+ *
+ * Each encoded unit consists of a Huffman packet. A packet contains
+ * a 16-bit control word followed by up to 16 data items. Each bit in
+ * the control word (LSB first) governs one data item:
+ *
+ * 1 -> LITERAL : one literal byte follows.
+ * 00 -> SHORT COPY: two Huffman bits (length 2-5) then one offset byte
+ * (distance 1-255).
+ * 01 -> LONG COPY: one offset byte + one combined byte:
+ * upper (16-DICT) bits = high offset bits
+ * lower (DICT-4) bits = length - 2 (2..17)
+ * If that length field == (1<<(16-DICT))-1 a second
+ * byte follows as the raw length (length = byte+1).
+ * 01 + offset==0 + len==0 -> NORMALIZE segment fixup marker.
+ * 01 + offset==0 + len==1 -> EXIT (end of stream).
+ *
+ * Dictionary is a circular buffer of LEMPEL (4096) bytes.
+ * Back-references are negative offsets into that buffer.
+ */
+
+#include "pfab.h"
+#include <stddef.h>
+#include <string.h>
+
+ /* -------------------------------------------------------------------------
+ * Compile-time constants (must match compressor and decompressor)
+ * ---------------------------------------------------------------------- */
+#define DICT 12 /* log2 of dictionary size */
+#define ZIV 253 /* max match length (bytes) */
+#define LEMPEL (1 << DICT) /* dictionary window = 4096 */
+#define NIL (LEMPEL * 2) /* sentinel / empty-table entry */
+#define HASH (LEMPEL / 2) /* hash table size (entries) */
+
+#define WBlen 2048 /* compressor write-buffer size */
+#define RBlen 2048 /* compressor read-buffer size */
+
+ /* =========================================================================
+ * I/O callback typedefs (match the original Pascal calling convention
+ * signatures translated to plain C function pointers)
+ * ====================================================================== */
+typedef word (*ReadFn) (char *buffer, word *size);
+typedef word (*WriteFn)(char *buffer, word *size);
+
+
+/* =========================================================================
+ * pFABcomp -- LZ77 compressor (PFABCOMP.ASM)
+ *
+ * Compresses the data returned by read_buff into write_buff.
+ * work_buff must be at least pFABcomp(NULL,NULL,NULL,NULL,NULL) bytes.
+ * On success *dsize receives the compressed byte count and 0 is returned.
+ * ====================================================================== */
+
+ /* ----- compressor work state ------------------------------------------ */
+struct CompWork {
+ /* --- I/O --- */
+ ReadFn zread;
+ WriteFn zwrite;
+
+ unsigned rb_ptr; /* index into rbuff[] */
+ unsigned rb_cnt; /* bytes remaining in rbuff */
+
+ unsigned wb_ptr; /* index into wbuff[] */
+ unsigned wb_cnt; /* bytes remaining in wbuff */
+
+ unsigned long zsize; /* total compressed bytes written */
+
+ /* --- LZ state --- */
+ int zlen; /* current Ziv length */
+ int qlen; /* match length */
+ int qoff; /* match offset (negative) */
+ int norms; /* bytes since last NORMALIZE */
+ int delta; /* counter for paraz */
+ int paraz; /* extra paragraphs for EXPLODE */
+
+ /* --- Huffman packet --- */
+ unsigned huffbit; /* current bit position in acc */
+ unsigned huffman; /* accumulator (control word) */
+ unsigned huffptr; /* index into packet[] */
+ byte packet[130]; /* packet buffer (2 + 128 data bytes) */
+
+ /* --- dictionary --- */
+ byte lempel[LEMPEL];
+ byte ziv[ZIV + 1];
+
+ unsigned hash[LEMPEL + 1 + HASH]; /* collision + sentinel + key table */
+ unsigned undo[LEMPEL + 1];
+
+ /* --- I/O staging --- */
+ word rwlen;
+ byte rbuff[RBlen];
+ byte wbuff[WBlen];
+};
+
+/* Required size of work_buff. Paragraph-align to match original. */
+static unsigned comp_work_size(void) {
+ return (unsigned)(sizeof(CompWork) + 15u);
+}
+
+/* Obtain aligned pointer to CompWork inside work_buff. */
+static CompWork *get_comp_work(char *work_buff) {
+ unsigned long addr = (unsigned long)(byte *)work_buff;
+ addr = (addr + 15u) & ~15u;
+ return (CompWork *)(byte *)addr;
+}
+
+/* ---- internal helpers ------------------------------------------------- */
+
+static void wb_out(CompWork *w) {
+ unsigned cnt = w->wb_ptr; /* bytes written since last flush */
+ w->wb_ptr = 0;
+ w->wb_cnt = WBlen;
+ w->rwlen = (word)cnt;
+ w->zsize += cnt;
+ w->zwrite((char *)w->wbuff, &w->rwlen);
+}
+
+static void wb_put(CompWork *w, byte byte) {
+ w->wbuff[w->wb_ptr++] = byte;
+ if (--w->wb_cnt == 0)
+ wb_out(w);
+}
+
+/* Flush the current Huffman packet to the output stream. */
+static void pkt_flush(CompWork *w) {
+ /* write packet[0..huffptr-1]: control word then data bytes */
+ w->packet[0] = (byte)(w->huffman & 0xFF);
+ w->packet[1] = (byte)(w->huffman >> 8);
+
+ unsigned end = w->huffptr;
+ for (unsigned i = 0; i < end; i++)
+ wb_put(w, w->packet[i]);
+
+ w->huffbit = 1;
+ w->huffman = 0;
+ w->huffptr = 2; /* skip the two control-word bytes */
+}
+
+/* Append one Huffman control bit (0 or non-0). */
+static void huff1(CompWork *w, int bit) {
+ if (bit)
+ w->huffman |= w->huffbit;
+ w->huffbit <<= 1;
+ if (w->huffbit == 0) {
+ /* control word is full (16 bits) - flush packet */
+ /* The packet array already contains the data bytes at [2..ptr) */
+ /* write everything out now */
+ byte tmp_ctrl0 = (byte)(w->huffman & 0xFF);
+ byte tmp_ctrl1 = (byte)(w->huffman >> 8);
+ unsigned save_ptr = w->huffptr;
+
+ /* emit control bytes then data bytes */
+ wb_put(w, tmp_ctrl0);
+ wb_put(w, tmp_ctrl1);
+ for (unsigned i = 2; i < save_ptr; i++)
+ wb_put(w, w->packet[i]);
+
+ w->huffbit = 1;
+ w->huffman = 0;
+ w->huffptr = 2;
+ }
+}
+
+/* Append one literal/copy data byte to the current packet buffer. */
+static void push1(CompWork *w, byte byte) {
+ w->packet[w->huffptr++] = byte;
+}
+
+/* ---- rb_in: fill the read buffer -------------------------------------- */
+
+static unsigned rb_in(CompWork *w) {
+ w->rb_ptr = 0;
+ w->rwlen = (word)RBlen;
+ unsigned got = w->zread((char *)w->rbuff, &w->rwlen);
+ w->rb_cnt = got + 1; /* +1 so the main loop pre-decrements */
+ return got;
+}
+
+/* ---- dictionary link/unlink ------------------------------------------- */
+
+/*
+ * Hash(inword) = (word & (HASH-1)) + LEMPEL + 1
+ * All indices into hash[]/undo[] are in units of unsigned (words).
+ * In the assembly, indices are byte offsets and the arrays are word arrays,
+ * hence the frequent shl/shr 1. Here we use word indices throughout.
+ */
+
+static void dict_link(CompWork *w, unsigned di) {
+ unsigned word = w->lempel[di] | ((unsigned)w->lempel[(di + 1) & (LEMPEL - 1)] << 8);
+ unsigned key = (word & (HASH - 1)) + LEMPEL + 1; /* key index */
+ unsigned di2 = di; /* word index = di */
+
+ unsigned bx = w->hash[key];
+ w->hash[di2] = bx;
+ w->hash[key] = di2;
+ w->undo[bx] = di2;
+ w->undo[di2] = key;
+}
+
+static void dict_unlink(CompWork *w, unsigned si) {
+ unsigned bx = w->undo[si];
+ if (bx != NIL) {
+ w->hash[bx] = NIL;
+ w->undo[si] = NIL;
+ }
+}
+
+/* ---- match: find the longest match at lempel[di] ---------------------- */
+
+static void match(CompWork *w, unsigned di) {
+ /* Compute hash key for the 2-byte word at lempel[di] */
+ unsigned inword = w->lempel[di]
+ | ((unsigned)w->lempel[(di + 1) & (LEMPEL - 1)] << 8);
+ unsigned key = (inword & (HASH - 1)) + LEMPEL + 1;
+
+ int best_len = 0;
+ unsigned best_pos = 0;
+ int rem = ZIV - 1; /* chars still to match */
+
+ unsigned chain = w->hash[key];
+ while (chain != NIL) {
+ /* compare lempel[chain+1 .. chain+ZIV-1] with lempel[di+1 ..] */
+ unsigned ms = (chain + 1) & (LEMPEL - 1);
+ unsigned md = (di + 1) & (LEMPEL - 1);
+ int matched = 0;
+ while (matched < ZIV - 1 && w->lempel[ms] == w->lempel[md]) {
+ ms = (ms + 1) & (LEMPEL - 1);
+ md = (md + 1) & (LEMPEL - 1);
+ matched++;
+ }
+ int this_len = matched + 1; /* +1 for the hashed first char */
+
+ if (matched == ZIV - 1) {
+ /* full ZIV match */
+ best_len = ZIV;
+ best_pos = chain;
+ break;
+ }
+ if (this_len > best_len) {
+ best_len = this_len;
+ best_pos = chain;
+ rem = ZIV - 1 - matched;
+ }
+ chain = w->hash[chain];
+ }
+
+ w->qlen = best_len;
+
+ if (best_len > 0) {
+ /* offset = di - best_pos (mod LEMPEL), stored negative */
+ int off = (int)di - (int)best_pos;
+ off &= (LEMPEL - 1);
+ w->qoff = -off;
+ }
+
+ /* Also link di into the hash table (same as Match does at the end) */
+ unsigned di2 = di;
+ unsigned bx = w->hash[key];
+ unsigned di_hash = di2;
+ w->hash[di_hash] = bx;
+ w->hash[key] = di_hash;
+ w->undo[bx] = di_hash;
+ w->undo[di_hash] = key;
+}
+
+/* ---- Fabrice: main LZ compression loop -------------------------------- */
+
+static unsigned long fabrice(CompWork *w) {
+ unsigned si = 0;
+
+ /* Initialise I/O state */
+ w->rb_cnt = 1; /* force first read */
+ w->wb_ptr = 0;
+ w->wb_cnt = WBlen;
+
+ /* Initialise dictionary */
+ memset(w->undo, 0xFF, sizeof(w->undo)); /* NIL = 0xFFFF (LEMPEL*2)*/
+ memset(w->hash, 0xFF, sizeof(w->hash));
+ memset(w->lempel, 0, sizeof(w->lempel));
+ memset(w->ziv, 0, sizeof(w->ziv));
+
+ /* Initialise Huffman packet */
+ w->huffbit = 1;
+ w->huffman = 0;
+ w->huffptr = 2; /* reserve two bytes for ctrl word */
+
+ w->norms = 0;
+ w->delta = 0;
+ w->paraz = 0;
+ w->zsize = 0;
+
+ /* Write the 4-byte "FAB" header */
+ wb_put(w, 'F');
+ wb_put(w, 'A');
+ wb_put(w, 'B');
+ wb_put(w, (byte)DICT);
+
+ /* Read first ZIV bytes into the top of the Lempel buffer */
+ unsigned di = (unsigned)(LEMPEL - ZIV);
+ unsigned cx = ZIV;
+
+ while (cx > 0) {
+ if (--w->rb_cnt == 0) {
+ if (rb_in(w) == 0)
+ break;
+ }
+ w->lempel[di++] = w->rbuff[w->rb_ptr++];
+ di &= (LEMPEL - 1);
+ cx--;
+ }
+
+ unsigned read_so_far = ZIV - cx;
+ if (read_so_far == 0)
+ goto lz_exit; /* empty input */
+
+ w->zlen = (int)read_so_far;
+
+ di = (unsigned)(LEMPEL - ZIV); /* encode pointer */
+ si = 0; /* end-of-ziv pointer */
+
+ match(w, di);
+
+ /* ---- main encoding loop ------------------------------------------ */
+ for (;;) {
+ /* clip qlen to zlen */
+ if (w->qlen > w->zlen)
+ w->qlen = w->zlen;
+
+ int save_si = (int)si;
+ int save_di = (int)di;
+
+ int qlen = w->qlen;
+ int qoff = w->qoff;
+
+ if (qlen < 2 || (qlen == 2 && qoff >= -0x100)) {
+ /* LITERAL: control bit = 1, then data byte */
+ w->qlen = 1;
+ huff1(w, 1);
+ push1(w, w->lempel[di]);
+ } else {
+ huff1(w, 0);
+
+ if (qlen <= 5 && qoff > -0x100) {
+ /* SHORT COPY: <00XY>, offset_byte (length 2-5, dist 1-255) */
+ huff1(w, 0);
+ int enc_len = qlen - 2; /* 0..3 */
+ huff1(w, enc_len & 2);
+ huff1(w, enc_len & 1);
+ push1(w, (byte)qoff); /* qoff is negative; byte cast = low 8 */
+ } else {
+ /* LONG COPY: <01>, vector_word */
+ huff1(w, 1);
+ push1(w, (byte)qoff); /* low byte of offset */
+
+ byte hi = (byte)((unsigned)(-qoff) >> 8);
+ int zb = 16 - DICT;
+ hi = (byte)(hi << zb);
+
+ int max_short_len = (1 << zb) + 1;
+ if (qlen <= max_short_len) {
+ hi |= (byte)(qlen - 2);
+ push1(w, hi);
+ } else {
+ /* LONG COPY with extra length byte */
+ push1(w, hi);
+ push1(w, (byte)(qlen - 1));
+ }
+ }
+ }
+
+ /* Update delta/paraz counters (track EXPLODE segment boundaries) */
+ w->delta -= w->qlen;
+ while (w->delta < 0) {
+ w->paraz++;
+ w->delta += 16;
+ }
+
+ /* Insert NORMALIZE marker every 40KB of output */
+ w->norms += w->qlen;
+ if (w->norms >= 0xA000) {
+ huff1(w, 0);
+ huff1(w, 1);
+ push1(w, 0);
+ push1(w, 0);
+ push1(w, 1);
+ w->norms = 0;
+ }
+
+ di = (unsigned)save_di;
+ si = (unsigned)save_si;
+
+ /* Advance the dictionary window by qlen positions */
+ int advance = w->qlen;
+ while (advance-- > 0) {
+ dict_link(w, di);
+ dict_unlink(w, si);
+
+ if (--w->rb_cnt == 0) {
+ if (rb_in(w) == 0) {
+ w->zlen--;
+ goto skip_byte;
+ }
+ }
+ {
+ byte c = w->rbuff[w->rb_ptr++];
+ w->lempel[si] = c;
+ if (si < (unsigned)(ZIV - 1))
+ w->ziv[si] = c; /* mirror first ZIV-1 chars */
+ }
+skip_byte:
+ si = (si + 1) & (LEMPEL - 1);
+ di = (di + 1) & (LEMPEL - 1);
+ }
+
+ match(w, di);
+
+ if (w->zlen <= 0)
+ break;
+ }
+
+lz_exit:
+ /* Write EXIT marker: <01>, 0x00, 0x00, 0x00 */
+ huff1(w, 0);
+ huff1(w, 1);
+ push1(w, 0);
+ push1(w, 0);
+ push1(w, 0);
+
+ /* Flush final packet and output buffer */
+ pkt_flush(w);
+ if (w->wb_ptr > 0)
+ wb_out(w);
+
+ return w->zsize;
+}
+
+/* -------------------------------------------------------------------------
+ * Public API: pFABcomp
+ * ---------------------------------------------------------------------- */
+word pFABcomp(ReadFn read_buff, WriteFn write_buff, char *work_buff,
+ word *type, word *dsize) {
+ /* If work_buff is NULL, return required buffer size */
+ if (!work_buff)
+ return comp_work_size();
+
+ CompWork *w = get_comp_work(work_buff);
+
+ w->zread = read_buff;
+ w->zwrite = write_buff;
+
+ unsigned long csize = fabrice(w);
+
+ /* Return compressed size via dsize (two 16-bit words = 32-bit size) */
+ if (dsize) {
+ ((word *)dsize)[0] = (word)(csize & 0xFFFF);
+ ((word *)dsize)[1] = (word)(csize >> 16);
+ }
+
+ return 0; /* CMP_NO_ERROR */
+}
+
+
+/* =========================================================================
+ * pFABexp common decompressor core
+ *
+ * The three assembly EXP variants all include "pFABexp.inc", which is the
+ * actual decompressor state machine. We implement it once here and call
+ * it from each of the three public wrappers with different I/O strategies.
+ *
+ * Stream layout (produced by pFABcomp above):
+ * Bytes 0-3 : 'F','A','B', DICT
+ * Then packets:
+ * Each packet: [ctrl_lo][ctrl_hi] [data bytes...]
+ * Control word is 16 bits, consumed LSB-first.
+ * bit=1 -> literal: read next data byte, write to output.
+ * bit=0, next_bit=0 -> SHORT copy: 2 more bits = len-2, 1 byte = dist.
+ * bit=0, next_bit=1 -> LONG copy: 1 byte low-offset, 1 byte packed:
+ * high bits = high offset, low bits = len-2
+ * if len==0 && off==0 -> NORMALIZE (skip)
+ * if len==1 && off==0 -> EXIT
+ * if low bits all set -> read extra len byte
+ * ====================================================================== */
+
+ /* I/O context passed into the inner decoder. */
+struct ExpIO {
+ /* INPUT: one of two modes */
+ int from_file; /* 1 = stream via read callback */
+ ReadFn rfun; /* file-source read callback */
+ const byte *rptr; /* memory-source read pointer */
+ /* OUTPUT: one of two modes */
+ int to_file; /* 1 = stream via write callback */
+ WriteFn wfun; /* file-dest write callback */
+ byte *wptr; /* memory-dest write pointer */
+
+ /* For file I/O we buffer reads / writes */
+ byte rbuf[2048];
+ unsigned rbuf_pos;
+ unsigned rbuf_end;
+
+ byte wbuf[4096];
+ unsigned wbuf_pos;
+
+ unsigned long out_count; /* total bytes decompressed */
+};
+
+/* ---- Buffered-read helpers ------------------------------------------- */
+
+static byte exp_getbyte(ExpIO *io) {
+ if (io->from_file) {
+ if (io->rbuf_pos >= io->rbuf_end) {
+ word sz = 2048;
+ io->rfun((char *)io->rbuf, &sz);
+ io->rbuf_end = sz;
+ io->rbuf_pos = 0;
+ }
+ return (io->rbuf_pos < io->rbuf_end) ? io->rbuf[io->rbuf_pos++] : 0;
+ } else {
+ return *io->rptr++;
+ }
+}
+
+static unsigned exp_getword(ExpIO *io) {
+ unsigned lo = exp_getbyte(io);
+ unsigned hi = exp_getbyte(io);
+ return lo | (hi << 8);
+}
+
+/* ---- Buffered-write helpers ------------------------------------------ */
+
+static void exp_flush_wbuf(ExpIO *io, int force_all) {
+ if (!io->to_file || io->wbuf_pos == 0)
+ return;
+
+ byte *base = io->wbuf;
+ unsigned len = force_all ? io->wbuf_pos
+ : (io->wbuf_pos & ~(4096u - 1u));
+ if (len == 0)
+ return;
+
+ word sz = (word)len;
+ io->wfun((char *)base, &sz);
+ io->out_count += len;
+
+ /* Shift remaining bytes to front */
+ unsigned remain = io->wbuf_pos - len;
+ if (remain)
+ memmove(base, base + len, remain);
+ io->wbuf_pos = remain;
+}
+
+static void exp_putbyte(ExpIO *io, byte b) {
+ if (io->to_file) {
+ io->wbuf[io->wbuf_pos++] = b;
+ if (io->wbuf_pos == 4096)
+ exp_flush_wbuf(io, 1);
+ } else {
+ *io->wptr++ = b;
+ io->out_count++;
+ }
+}
+
+/* ---- read a byte from the output window (back-reference) ------------- */
+
+static byte exp_readback(ExpIO *io, int dist, unsigned long total_out) {
+ /* dist = 1..LEMPEL (positive, 1 = most recent byte written) */
+ if (!io->to_file) {
+ /* Simple: just look behind in the output buffer */
+ return *(io->wptr - dist);
+ } else {
+ /* For file-to-file we maintain a sliding window in wbuf. */
+ /* wbuf is used as circular output; wbuf_pos is the current head. */
+ unsigned idx = (io->wbuf_pos + 4096u - (unsigned)dist) & (4096u - 1u);
+ return io->wbuf[idx];
+ }
+}
+
+/* ---- Core decompressor ----------------------------------------------- */
+
+static unsigned long fab_explode(ExpIO *io) {
+ io->out_count = 0;
+
+ /* ---- Verify FAB header ------------------------------------------ */
+ if (exp_getbyte(io) != 'F') return 0;
+ if (exp_getbyte(io) != 'A') return 0;
+ if (exp_getbyte(io) != 'B') return 0;
+ byte dict_bits = exp_getbyte(io); /* e.g. 12 */
+
+ int lempel = 1 << dict_bits; /* 4096 */
+ int zbits = 16 - dict_bits; /* 4 */
+ int zmax_len = (1 << zbits) - 1; /* 15 (max short len-2) */
+ //byte umask = (byte)(0xFF << (dict_bits - 8)); /* offset hi mask */
+
+ unsigned ctrl = 0;
+ int cbits = 0; /* bits left in ctrl word */
+
+ auto get_ctrl_bit = [&]() -> int {
+ if (cbits == 0) {
+ ctrl = exp_getword(io);
+ cbits = 16;
+ }
+ int bit = (int)(ctrl & 1);
+ ctrl >>= 1;
+ cbits--;
+ return bit;
+ };
+
+ /* ---- Decode loop ------------------------------------------------- */
+ for (;;) {
+ int bit0 = get_ctrl_bit();
+
+ if (bit0 == 1) {
+ /* LITERAL */
+ byte c = exp_getbyte(io);
+ exp_putbyte(io, c);
+ continue;
+ }
+
+ /* bit0 == 0 */
+ int bit1 = get_ctrl_bit();
+
+ if (bit1 == 0) {
+ /* SHORT COPY: 2 more control bits = length 2-5, 1 byte dist 1-255 */
+ int lb = get_ctrl_bit();
+ int la = get_ctrl_bit();
+ int enc_len = (lb << 1) | la; /* 0..3 = len - 2 */
+ int cplen = enc_len + 2; /* 2..5 */
+ byte off_byte = exp_getbyte(io);
+ int dist = (int)(byte)(-((int)(byte)off_byte));
+ if (dist == 0) dist = 256; /* 0 encodes as 256 */
+
+ for (int i = 0; i < cplen; i++) {
+ byte c = exp_readback(io, dist, io->out_count);
+ exp_putbyte(io, c);
+ }
+ continue;
+ }
+
+ /* bit1 == 1 -> LONG COPY (or NORMALIZE / EXIT) */
+ {
+ byte lo_off = exp_getbyte(io);
+ byte packed = exp_getbyte(io);
+
+ /* High bits of offset: upper zbits of packed, shifted down */
+ unsigned hi_off = (unsigned)(packed >> zbits);
+ unsigned dist = ((unsigned)hi_off << 8) | lo_off;
+
+ /* Length: lower (DICT-4) = zbits-1... actually lower zbits bits */
+ int enc_len = packed & zmax_len;
+
+ if (dist == 0) {
+ if (enc_len == 0) {
+ /* NORMALIZE marker - continue */
+ continue;
+ }
+ if (enc_len == 1) {
+ /* EXIT */
+ break;
+ }
+ }
+
+ int cplen;
+ if (enc_len == zmax_len) {
+ /* Extra length byte follows */
+ byte ext = exp_getbyte(io);
+ cplen = (int)ext + 1;
+ } else {
+ cplen = enc_len + 2;
+ }
+
+ /* dist is the back-reference distance (positive) */
+ unsigned actual_dist = dist ? dist : lempel; /* 0 => lempel */
+
+ for (int i = 0; i < cplen; i++) {
+ byte c = exp_readback(io, (int)actual_dist, io->out_count);
+ exp_putbyte(io, c);
+ }
+ }
+ }
+
+ /* Flush any remaining output */
+ if (io->to_file)
+ exp_flush_wbuf(io, 1);
+
+ return io->out_count;
+}
+
+
+/* =========================================================================
+ * pFABexp0 -- file-to-file decompressor (PFABEXP0.ASM)
+ *
+ * Reads compressed data via read_buff, writes decompressed data via
+ * write_buff. Returns 0 on success; the 32-bit decompressed byte count
+ * is stored as two unsigned shorts at work_buff[0..3].
+ * ====================================================================== */
+
+ /* Minimum work_buff size for pFABexp0 (original needed ~14364 bytes). */
+#define EXP0_WORK_SIZE 16384u
+
+word pFABexp0(ReadFn read_buff, WriteFn write_buff, char *work_buff) {
+ if (!work_buff)
+ return EXP0_WORK_SIZE;
+
+ ExpIO io;
+ memset(&io, 0, sizeof(io));
+
+ io.from_file = 1;
+ io.rfun = read_buff;
+ io.to_file = 1;
+ io.wfun = write_buff;
+
+ unsigned long out_len = fab_explode(&io);
+
+ /* Return decompressed size in work_buff[0..3] */
+ ((word *)work_buff)[0] = (word)(out_len & 0xFFFF);
+ ((word *)work_buff)[1] = (word)(out_len >> 16);
+
+ return 0; /* CMP_NO_ERROR */
+}
+
+
+/* =========================================================================
+ * pFABexp1 -- file-to-memory decompressor (PFABEXP1.ASM)
+ *
+ * Reads compressed data via read_buff, writes decompressed data starting
+ * at write_buf. Returns 0 on success; the 32-bit decompressed byte count
+ * is stored as two unsigned shorts at work_buff[0..3].
+ * ====================================================================== */
+
+ /* Minimum work_buff size for pFABexp1 (original needed ~2072 bytes). */
+#define EXP1_WORK_SIZE 4096u
+
+word pFABexp1(ReadFn read_buff, char *write_buf, char *work_buff) {
+ if (!work_buff)
+ return EXP1_WORK_SIZE;
+
+ ExpIO io;
+ memset(&io, 0, sizeof(io));
+
+ io.from_file = 1;
+ io.rfun = read_buff;
+ io.to_file = 0;
+ io.wptr = (byte *)write_buf;
+
+ unsigned long out_len = fab_explode(&io);
+
+ /* Return decompressed size in work_buff[0..3] */
+ ((word *)work_buff)[0] = (word)(out_len & 0xFFFF);
+ ((word *)work_buff)[1] = (word)(out_len >> 16);
+
+ return 0;
+}
+
+
+/* =========================================================================
+ * pFABexp2 -- memory-to-memory decompressor (PFABEXP2.ASM)
+ *
+ * read_buf points to compressed data.
+ * write_buf points to destination buffer (must be large enough).
+ * work_buff must be at least 4 bytes (for the output length result),
+ * or NULL to query required size.
+ * Returns 0 on success. Decompressed byte count stored at work_buff[0..3].
+ * ====================================================================== */
+word pFABexp2(byte *read_buf, byte *write_buf, char *work_buff) {
+ if (!work_buff)
+ return 4u; /* original returned 4 */
+
+ ExpIO io;
+ memset(&io, 0, sizeof(io));
+
+ io.from_file = 0;
+ io.rptr = read_buf;
+ io.to_file = 0;
+ io.wptr = write_buf;
+
+ unsigned long out_len = fab_explode(&io);
+
+ /* Return decompressed size in work_buff[0..3] */
+ ((word *)work_buff)[0] = (word)(out_len & 0xFFFF);
+ ((word *)work_buff)[1] = (word)(out_len >> 16);
+
+ return 0;
+}
+
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/core/pfab.h b/engines/mads/madsv2/core/pfab.h
index 26392f6824a..775baab8258 100644
--- a/engines/mads/madsv2/core/pfab.h
+++ b/engines/mads/madsv2/core/pfab.h
@@ -27,6 +27,16 @@
namespace MADS {
namespace MADSV2 {
+#define CMP_BINARY 0
+#define CMP_ASCII 1
+
+#define CMP_NO_ERROR 0
+#define CMP_INVALID_DICTSIZE 1
+#define CMP_INVALID_MODE 2
+#define CMP_BAD_DATA 3
+#define CMP_ABORT 4
+
+
extern word pFABcomp(
word (*read_buff)(char *buffer, word *size),
word (*write_buff)(char *buffer, word *size),
@@ -49,15 +59,6 @@ extern word pFABexp2(
byte *write_buf,
char *work_buff);
-#define CMP_BINARY 0
-#define CMP_ASCII 1
-
-#define CMP_NO_ERROR 0
-#define CMP_INVALID_DICTSIZE 1
-#define CMP_INVALID_MODE 2
-#define CMP_BAD_DATA 3
-#define CMP_ABORT 4
-
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/core/player.cpp b/engines/mads/madsv2/core/player.cpp
index 17e90a436c2..86a38a42f5a 100644
--- a/engines/mads/madsv2/core/player.cpp
+++ b/engines/mads/madsv2/core/player.cpp
@@ -37,7 +37,8 @@
namespace MADS {
namespace MADSV2 {
-Player player;
+Player player = { 0 };
+Player2 player2 = { 0 };
byte player_facing_to_series[10] = { 0, 7, 4, 3, 6, 0, 2, 5, 0, 1 };
byte player_clockwise[10] = { 9, 4, 1, 2, 7, 9, 3, 8, 9, 6 };
diff --git a/engines/mads/madsv2/core/qual.h b/engines/mads/madsv2/core/qual.h
index a38cea69cb6..9a4bc015388 100644
--- a/engines/mads/madsv2/core/qual.h
+++ b/engines/mads/madsv2/core/qual.h
@@ -65,37 +65,37 @@ extern int qual_words;
extern char *qual;
/* qual_1.cpp */
-int fastcall qual_destroy(void);
+int qual_destroy(void);
/* qual_2.cpp */
-int fastcall qual_load(int allocation_flag);
-int fastcall qual_get_code(char *inp);
-char *fastcall qual_get_word(char *out, int inp);
+int qual_load(int allocation_flag);
+int qual_get_code(char *inp);
+char *qual_get_word(char *out, int inp);
/* qual_3.cpp */
-int fastcall qual_write_file(char *last_word);
-int fastcall qual_add_word(char *inp);
+int qual_write_file(char *last_word);
+int qual_add_word(char *inp);
/* qual_4.c */
-void fastcall qual_report_error(int number);
+void qual_report_error(int number);
/* qual_5.cpp */
-char *fastcall qual_select_word(char *out,
+char *qual_select_word(char *out,
char *prompt,
char *default_word);
/* qual_6.cpp */
-void fastcall qual_maint(void);
+void qual_maint(void);
/* qual_7.cpp */
-int fastcall qual_build(void);
+int qual_build(void);
/* qual_8.cpp */
-void fastcall qual_unload_active(void);
-void fastcall qual_init_active(void);
-int fastcall qual_active_id(word id);
-int fastcall qual_make_active(word id);
-int fastcall qual_load_active(void);
+void qual_unload_active(void);
+void qual_init_active(void);
+int qual_active_id(word id);
+int qual_make_active(word id);
+int qual_load_active(void);
extern char *qual_text;
extern word qual_active;
diff --git a/engines/mads/madsv2/core/rail.cpp b/engines/mads/madsv2/core/rail.cpp
index ebfcf26355d..998328baed2 100644
--- a/engines/mads/madsv2/core/rail.cpp
+++ b/engines/mads/madsv2/core/rail.cpp
@@ -32,6 +32,54 @@
namespace MADS {
namespace MADSV2 {
+ /* -------------------------------------------------------------------------
+ * Constants
+ * ---------------------------------------------------------------------- */
+
+#define RAIL_STRUCTURE_SIZE 48
+#define RAIL_STRUCTURE_WEIGHT_OFFSET 4 /* byte offset of weight[] within a rail node */
+
+#define RAIL_WEIGHT_MASK 0x3FFF
+#define RAIL_ALLOW_ILLEGAL 0xC000
+#define RAIL_ALLOW_LEGAL_ONLY 0x8000
+
+ /* -------------------------------------------------------------------------
+ * Rail node structure
+ *
+ * Each node is RAIL_STRUCTURE_SIZE (48) bytes. The weight array starts at
+ * byte offset RAIL_STRUCTURE_WEIGHT_OFFSET (4), and is indexed by node
+ * number. Each weight entry is one word (2 bytes).
+ *
+ * The upper two bits of each weight word encode legality:
+ * RAIL_ALLOW_ILLEGAL (0xC000) -- path exists, even through illegal area
+ * RAIL_ALLOW_LEGAL_ONLY (0x8000) -- path exists, legal only
+ * 0x0000 -- no path
+ * The lower 14 bits (RAIL_WEIGHT_MASK) hold the actual traversal weight.
+ *
+ * The struct below matches the 48-byte layout exactly:
+ * 4 bytes of header data before the weight array,
+ * then RAIL_MAX_NODES (12) weight words = 24 bytes,
+ * padding to reach 48 bytes total.
+ * ---------------------------------------------------------------------- */
+typedef struct {
+ unsigned char header[RAIL_STRUCTURE_WEIGHT_OFFSET]; /* 4 bytes */
+ uint16 weight[RAIL_MAX_NODES]; /* 24 bytes (12 words) */
+ unsigned char padding[48 - 4 - 24]; /* 20 bytes padding */
+} RailNode;
+
+/* -------------------------------------------------------------------------
+ * Global variables (COMM in the original -- shared across modules)
+ * ---------------------------------------------------------------------- */
+uint16 _rail_solution_stack_pointer;
+uint16 _rail_solution_stack_weight;
+
+unsigned char _rail_visited[RAIL_MAX_NODES];
+unsigned char _rail_working_stack[RAIL_MAX_NODES];
+unsigned char _rail_solution_stack[RAIL_MAX_NODES];
+
+uint16 _rail_num_nodes;
+RailNode *_rail_base; /* far ptr in original; flat ptr here */
+
word rail_solution_stack_pointer;
word rail_solution_stack_weight;
byte rail_visited[RAIL_MAX_NODES];
@@ -41,6 +89,7 @@ word rail_num_nodes;
byte *rail_base;
byte rail_active[ROOM_MAX_RAILS + 2];
+
void rail_connect_node(int id) {
int count;
int x1, y1;
@@ -117,5 +166,105 @@ void rail_connect_all_nodes(void) {
}
}
+
+/**
+ * Parameters (passed in registers in the original):
+ * node_id -- BX: node currently being evaluated
+ * weight -- DX: cumulative weight for this solution attempt
+ * allow_mode -- AX: RAIL_ALLOW_ILLEGAL or RAIL_ALLOW_LEGAL_ONLY
+ *
+ * Stack state:
+ * working_sp -- SI in the original: index into _rail_working_stack,
+ * acting as a simple push-down stack pointer.
+ *
+ * The function is recursive and modifies the globals directly.
+ */
+static void recursive_check_path(int node_id,
+ uint16 weight,
+ uint16 allow_mode,
+ int working_sp) {
+ /* visited[node_id] = true */
+ _rail_visited[node_id] = 1;
+
+ /* push(node_id) onto working stack */
+ _rail_working_stack[working_sp] = (unsigned char)node_id;
+ working_sp++;
+
+ /* Point at rail[node_id] */
+ RailNode *node = &_rail_base[node_id];
+
+ /* The source node is second-to-last: index = num_nodes - 2.
+ We look up the weight from node_id to the source (from_node). */
+ int from_node = _rail_num_nodes - 2;
+ uint16 raw_weight = node->weight[from_node];
+
+ /* Check whether there is a direct legal path to the destination */
+ if (raw_weight & allow_mode) {
+ uint16 leg_weight = raw_weight & RAIL_WEIGHT_MASK;
+ uint16 total = weight + leg_weight;
+
+ if (total < _rail_solution_stack_weight) {
+ /* This is a better solution -- save it */
+ int stack_len = working_sp; /* number of bytes currently on stack */
+ memcpy(_rail_solution_stack, _rail_working_stack, stack_len);
+ _rail_solution_stack_pointer = (uint16)stack_len;
+ _rail_solution_stack_weight = total;
+ }
+ } else {
+ /*
+ * No direct path -- recurse through every unvisited intermediate node.
+ * Intermediate nodes are indices 0 .. (num_nodes - 3); the last two
+ * entries in the array are the destination and source nodes.
+ */
+ int num_intermediate = _rail_num_nodes - 2;
+
+ for (int i = 0; i < num_intermediate; i++) {
+ int test_node = i; /* loop counter - 1 in the ASM */
+
+ if (_rail_visited[test_node])
+ continue;
+
+ /* Check edge weight from current node to test_node */
+ uint16 edge_raw = node->weight[test_node];
+ uint16 edge_legal = edge_raw & allow_mode;
+
+ if (!edge_legal)
+ continue; /* not a legal connection */
+
+ uint16 edge_weight = edge_raw & RAIL_WEIGHT_MASK;
+
+ /* All further legs must be strictly legal once we step through
+ an intermediate node (the ASM forces RAIL_ALLOW_LEGAL_ONLY) */
+ recursive_check_path(test_node,
+ weight + edge_weight,
+ RAIL_ALLOW_LEGAL_ONLY,
+ working_sp);
+ }
+ }
+
+ /* visited[node_id] = false (unwind) */
+ _rail_visited[node_id] = 0;
+
+ /* pop() -- working_sp is a local copy so this just falls off the frame */
+}
+
+void rail_check_path(int allow_one_illegal) {
+ /* Clear the visited array */
+ memset(_rail_visited, 0, _rail_num_nodes);
+
+ /* Initialise solution state to "no solution yet" */
+ _rail_solution_stack_weight = RAIL_WEIGHT_MASK;
+ _rail_solution_stack_pointer = 0;
+
+ /* The last node in the array (index num_nodes - 1) is the starting
+ node for the search (the destination, in path terms) */
+ int start_node = _rail_num_nodes - 1;
+
+ uint16 allow_mode = allow_one_illegal ? RAIL_ALLOW_ILLEGAL
+ : RAIL_ALLOW_LEGAL_ONLY;
+
+ recursive_check_path(start_node, 0, allow_mode, 0);
+}
+
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/core/rail.h b/engines/mads/madsv2/core/rail.h
index fa492dfb752..180bad8bc29 100644
--- a/engines/mads/madsv2/core/rail.h
+++ b/engines/mads/madsv2/core/rail.h
@@ -42,7 +42,25 @@ extern void rail_connect_node(int id);
extern void rail_connect_all_nodes(void);
extern void rail_disconnect_line(int from, int unto);
extern void rail_disconnect_node(int id);
-extern void rail_check_path (int allow_one_illegal);
+
+/**
+ * Public entry point. Sets up global state and kicks off the recursive
+ * search.
+ *
+ * Preconditions (caller must set before calling):
+ * _rail_base -- pointer to rail node array; last entry is the
+ * destination node, second-to-last is the source.
+ * _rail_num_nodes -- total number of nodes including source & dest.
+ *
+ * Results available after return:
+ * _rail_solution_stack_pointer -- number of nodes in the solution
+ * (0 = no solution found).
+ * _rail_solution_stack -- node indices to traverse, in reverse
+ * order, excluding the source node.
+ * _rail_solution_stack_weight -- total weight of best solution found;
+ * > RAIL_WEIGHT_MASK means no solution.
+ */
+extern void rail_check_path(int allow_one_illegal);
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/core/room.cpp b/engines/mads/madsv2/core/room.cpp
index 734f9d98562..52767efb9e1 100644
--- a/engines/mads/madsv2/core/room.cpp
+++ b/engines/mads/madsv2/core/room.cpp
@@ -44,6 +44,7 @@
namespace MADS {
namespace MADSV2 {
+RoomDef roomdef;
int room_load_error = 0;
byte room_loaded_depth = false;
byte room_loaded_walk = false;
@@ -325,78 +326,13 @@ done:
room_dump_attribute(depth, walk, special, depthMap);
}
- return (error_flag);
+ return error_flag;
}
-
int room_compile_hotspots(int id, int compression) {
- int error_flag;
- int num_spots;
- int loaded_it_here = false;
- int count;
- char temp_buf[80];
- HotSpotEdit hotspotedit;
- HotSpot hotspot[ROOM_MAX_HOTSPOTS];
- Common::SeekableReadStream *handle;
- Load load_handle;
-
- error_flag = true;
-
- handle = NULL;
- load_handle.open = false;
-
- if (vocab_allocation == 0) {
- if (vocab_load(true) <= 0) {
- if (vocab_load(false) <= 0) goto done;
- }
- loaded_it_here = true;
- }
-
- handle = env_open_level(ROOM, ".HOT", 0, id, "rb");
- if (handle == NULL) goto done;
-
- env_get_level_path(temp_buf, ROOM, ".HH", 0, id);
- if (loader_open(&load_handle, temp_buf, "wb", compression)) goto done;
- loader_set_priority(&load_handle, PACK_PRIORITY_ROOM_HOTSPOTS);
-
- if (!fileio_fread_f(&num_spots, sizeof(int), 1, handle)) goto done;
- if (!loader_write(&num_spots, sizeof(int), 1, &load_handle)) goto done;
-
- for (count = 0; count < num_spots; count++) {
- if (!fileio_fread_f(&hotspotedit, sizeof(HotSpotEdit), 1, handle)) goto done;
- memcpy(&hotspot[count], &hotspotedit, sizeof(HotSpot));
- hotspot[count].vocab = vocab_get_code(hotspotedit.vocab);
- if (hotspot[count].vocab == 0) {
- hotspot[count].vocab = vocab_add_word(hotspotedit.vocab);
- }
- if (strlen(hotspotedit.verb) == 0) {
- hotspot[count].verb = 0;
- } else {
- hotspot[count].verb = vocab_get_code(hotspotedit.verb);
- if (hotspot[count].verb == 0) {
- hotspot[count].verb = vocab_add_word(hotspotedit.verb);
- }
- }
- hotspot[count].cursor_number = hotspotedit.cursor_number;
- hotspot[count].syntax = hotspotedit.syntax;
- hotspot[count].active = true;
- }
- num_spots = MAX(num_spots, 1);
- if (!loader_write(&hotspot[0], sizeof(HotSpot) * num_spots, 1, &load_handle)) goto done;
-
- error_flag = false;
-
-done:
- delete handle;
- if (load_handle.open)
- loader_close(&load_handle);
- if (loaded_it_here) {
- vocab_destroy();
- }
- return (error_flag);
+ error("TODO: room_compile_hotspots");
}
-
HotPtr room_load_hotspots(int id, int *num_spots) {
HotPtr spots;
HotPtr result = NULL;
@@ -438,14 +374,6 @@ done:
return result;
}
-
-/*
-/* room_read_pict()
-/*
-/* Reads the . file for the specified room into the "room" structure.
-/*
-/* Returns 0 if successful, or -1 for error.
-*/
int room_read_pict(int room_code, char *room_file, int mads_mode) {
int result = -1;
int count;
@@ -531,7 +459,6 @@ void room_file_name(char *target, const char *suffix, int code, char *main_name,
}
}
-
void room_himem_preload(int roomNum, int level) {
himem_preload_series(kernel_full_name(roomNum, 0, -1, NULL, KERNEL_DAT), level);
himem_preload_series(kernel_full_name(roomNum, 0, -1, NULL, KERNEL_HH), level);
@@ -545,7 +472,6 @@ void room_himem_preload(int roomNum, int level) {
himem_preload_series(kernel_full_name(roomNum, 0, 0, NULL, KERNEL_WW), level);
}
-
int room_picture_load(int roomId, Buffer *picture, int load_flags) {
int error_flag = true;
int xs, ys;
@@ -611,11 +537,11 @@ done:
if (load_handle.open) {
loader_close(&load_handle);
}
- return (error_flag);
-}
+ return error_flag;
+}
-void room_resolve_base(char *base, char *file, int id, char *base_path) {
+void room_resolve_base(char *base, char *file, int id, const char *base_path) {
int mads_mode;
mads_mode = !(id < 0);
@@ -742,8 +668,10 @@ int room_invert(void) {
error_flag = false;
done:
- if (work != NULL) mem_free(work);
- return (error_flag);
+ if (work != NULL)
+ mem_free(work);
+
+ return error_flag;
}
} // namespace MADSV2
diff --git a/engines/mads/madsv2/core/room.h b/engines/mads/madsv2/core/room.h
index c02c7bfa1af..488b5209215 100644
--- a/engines/mads/madsv2/core/room.h
+++ b/engines/mads/madsv2/core/room.h
@@ -263,6 +263,12 @@ extern void room_dump_attribute(Buffer *depth, Buffer *walk, Buffer *special,
TileMapHeader *depth_map);
extern int room_compile_hotspots(int id, int compression);
extern HotPtr room_load_hotspots(int id, int *num_spots);
+
+/**
+ * Reads the . file for the specified room into the "room" structure.
+ *
+ * Returns 0 if successful, or -1 for error.
+ */
extern int room_read_pict(int room_code, const char *room_file, int mads_mode);
extern int room_write_pict(int room_code, const char *room_file, int mads_mode);
extern void room_file_name(char *target, const char *suffix, int code,
@@ -270,7 +276,7 @@ extern void room_file_name(char *target, const char *suffix, int code,
extern void room_himem_preload(int room, int level);
extern RoomPtr room_dummy_init(int xs, int ys);
extern int room_picture_load(int room_id, Buffer *picture, int load_flags);
-extern void room_resolve_base(char *base, const char *file, int id, const char *base_path);
+extern void room_resolve_base(char *base, char *file, int id, const char *base_path);
extern int room_invert(void);
} // namespace MADSV2
diff --git a/engines/mads/madsv2/core/screen.cpp b/engines/mads/madsv2/core/screen.cpp
index 33bf6e2bea3..777c8b8c66f 100644
--- a/engines/mads/madsv2/core/screen.cpp
+++ b/engines/mads/madsv2/core/screen.cpp
@@ -27,6 +27,8 @@
namespace MADS {
namespace MADSV2 {
+int screen_normal_color;
+int screen_hilite_color;
int screen_video_mode;
int screen_max_x = 80;
int screen_max_y = 25;
diff --git a/engines/mads/madsv2/core/sort.h b/engines/mads/madsv2/core/sort.h
index 17f660aa68b..6af4f36075e 100644
--- a/engines/mads/madsv2/core/sort.h
+++ b/engines/mads/madsv2/core/sort.h
@@ -34,7 +34,7 @@ extern void sort_insertion(int elements, int *id, long *value);
extern void sort_insertion_16(int elements, byte *id, word *value);
/* sort_3.cpp */
-extern void fastcall sort_insertion_8(int elements, byte *id, byte *value);
+extern void sort_insertion_8(int elements, byte *id, byte *value);
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/core/video_1.cpp b/engines/mads/madsv2/core/sound.cpp
similarity index 80%
rename from engines/mads/madsv2/core/video_1.cpp
rename to engines/mads/madsv2/core/sound.cpp
index efd2692dea7..de0113e0f11 100644
--- a/engines/mads/madsv2/core/video_1.cpp
+++ b/engines/mads/madsv2/core/sound.cpp
@@ -19,19 +19,14 @@
*
*/
-#include "mads/madsv2/core/video.h"
-#include "mads/madsv2/engine.h"
+#include "common/textconsole.h"
+#include "mads/madsv2/core/sound.h"
namespace MADS {
namespace MADSV2 {
-void video_init(int mode, int set_mode) {
- // No implementation in ScummVM
-}
-
-void video_update() {
- auto &screen = *g_engine->getScreen();
- screen.update();
+void sound_queue(int soundNum) {
+ error("TODO: sound_queue");
}
} // namespace MADSV2
diff --git a/engines/mads/madsv2/core/speech.cpp b/engines/mads/madsv2/core/speech.cpp
index 6987230872a..f01d62130c1 100644
--- a/engines/mads/madsv2/core/speech.cpp
+++ b/engines/mads/madsv2/core/speech.cpp
@@ -28,6 +28,7 @@ namespace MADSV2 {
bool speech_system_active = false;
bool speech_on = false;
int speech_ems_handle;
+SpeechBuffer speech_main_buffer;
SpeechDirPtr speech_load(const char *resName, int id, bool) {
warning("TODO: speech_load");
diff --git a/engines/mads/madsv2/core/tile.h b/engines/mads/madsv2/core/tile.h
index 57afcecb02e..7cf7c8f55d5 100644
--- a/engines/mads/madsv2/core/tile.h
+++ b/engines/mads/madsv2/core/tile.h
@@ -93,49 +93,22 @@ typedef struct {
} TileMapHeader;
extern ShadowList tile_shadow;
-
-
-/* tile_1.c */
-int tile_load(char *base,
- int tile_type,
- TileResource *tile_resource,
- TileMapHeader *map,
- Buffer *picture,
- ColorListPtr color_list,
- CycleListPtr cycle_list,
- int ems_handle,
- int load_flags);
-
extern int tile_load_error;
-
-/* tile_2.c */
-int tile_buffer(Buffer *target,
- TileResource *tile_resource,
- TileMapHeader *map,
- int tile_x,
- int tile_y);
-
-/* tile_3.c */
extern int tile_ems_available;
extern int tile_picture_handle;
extern int tile_attribute_handle;
-int tile_setup(void);
-
-/* tile_4.c */
-void tile_map_free(TileMapHeader *map);
-
-/* tile_5.c */
-void tile_pan(TileMapHeader *tile_map,
- int x,
- int y);
-/* tile_6.c */
-int tile_fake_map(int tile_type,
- TileMapHeader *tile_map,
- Buffer *buffer,
- int x,
- int y);
+extern int tile_load(const char *base, int tile_type, TileResource *tile_resource,
+ TileMapHeader *map, Buffer *picture, ColorListPtr color_list,
+ CycleListPtr cycle_list, int ems_handle, int load_flags);
+extern int tile_buffer(Buffer *target, TileResource *tile_resource,
+ TileMapHeader *map, int tile_x, int tile_y);
+extern int tile_setup(void);
+extern void tile_map_free(TileMapHeader *map);
+extern void tile_pan(TileMapHeader *tile_map, int x, int y);
+extern int tile_fake_map(int tile_type, TileMapHeader *tile_map,
+ Buffer *buffer, int x, int y);
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/core/timer.cpp b/engines/mads/madsv2/core/timer.cpp
index d19f5ac2b7b..b6eaa910af3 100644
--- a/engines/mads/madsv2/core/timer.cpp
+++ b/engines/mads/madsv2/core/timer.cpp
@@ -34,8 +34,16 @@ word timer_noise_on;
byte timer_copy_protect_in = 0;
byte timer_copy_protect_out = 0;
-extern long timer_600_low;
-extern long timer_60_low;
+word timer_low_priority;
+word timer_low_semaphore;
+word timer_low_stacking;
+word timer_low_deferred;
+void *timer_low_routine;
+
+long timer_600_low;
+long timer_60_low;
+long timer_dos_low;
+
/*
/* Reads system clock, returns number of ticks since midnight.
diff --git a/engines/mads/madsv2/core/video.cpp b/engines/mads/madsv2/core/video.cpp
new file mode 100644
index 00000000000..d31f06e1b05
--- /dev/null
+++ b/engines/mads/madsv2/core/video.cpp
@@ -0,0 +1,52 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "mads/madsv2/core/video.h"
+#include "mads/madsv2/engine.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+void video_init(int mode, int set_mode) {
+ // No implementation in ScummVM
+}
+
+void video_update() {
+ auto &screen = *g_engine->getScreen();
+ screen.update();
+}
+
+void video_update(Buffer *from, int from_x, int from_y,
+ int unto_x, int unto_y,
+ int size_x, int size_y) {
+ auto &screen = *g_engine->getScreen();
+ Graphics::Surface subArea = screen.getSubArea(Common::Rect(unto_x, unto_y,
+ unto_x + size_x, unto_y + size_y));
+
+ for (int yp = 0; yp < size_y; ++yp) {
+ const byte *src = from->data + (from_y + yp) * from->x + from_x;
+ byte *dest = (byte *)subArea.getBasePtr(0, yp);
+ Common::copy(src, src + size_x, dest);
+ }
+}
+
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/core/vocab.cpp b/engines/mads/madsv2/core/vocab.cpp
index fb7fee448ea..4c27dbb6365 100644
--- a/engines/mads/madsv2/core/vocab.cpp
+++ b/engines/mads/madsv2/core/vocab.cpp
@@ -19,6 +19,7 @@
*
*/
+#include "common/textconsole.h"
#include "mads/madsv2/core/general.h"
#include "mads/madsv2/core/mem.h"
#include "mads/madsv2/core/env.h"
@@ -274,6 +275,10 @@ char *vocab_get_word(char *word_buf, int word_code) {
return result;
}
+int vocab_write_file(const char *last_word) {
+ error("TODO: vocab_write_file");
+}
+
void vocab_report_error(int number) {
char temp_buf_1[80], temp_buf_2[80], temp_buf_3[80];
int dos_flag;
diff --git a/engines/mads/madsv2/core/vocab.h b/engines/mads/madsv2/core/vocab.h
index 3eeef38025e..d14d79aee13 100644
--- a/engines/mads/madsv2/core/vocab.h
+++ b/engines/mads/madsv2/core/vocab.h
@@ -80,7 +80,7 @@ extern char *vocab_get_word(char *out, int inp);
*/
extern int vocab_write_file(const char *last_word);
-extern int vocab_add_word(char *inp);
+extern int vocab_add_word(const char *inp);
extern void vocab_report_error(int number);
extern char *vocab_select_word(char *out, const char *prompt, const char *default_word);
extern void vocab_maint(void);
diff --git a/engines/mads/madsv2/phantom/main_menu.cpp b/engines/mads/madsv2/phantom/main_menu.cpp
index b1102994af6..0b1ceb4b328 100644
--- a/engines/mads/madsv2/phantom/main_menu.cpp
+++ b/engines/mads/madsv2/phantom/main_menu.cpp
@@ -74,6 +74,7 @@ namespace Phantom {
#define EYE_HOTSPOT 32
#define EYE_MESSAGES 2
+#undef MESSAGE_COLOR
#define MESSAGE_COLOR 1284
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index a3457ee3d6d..047cd88f759 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -64,33 +64,42 @@ MODULE_OBJS += \
madsv2/core/attr.o \
madsv2/core/buffer.o \
madsv2/core/camera.o \
+ madsv2/core/color.o \
+ madsv2/core/config.o \
madsv2/core/copy.o \
madsv2/core/cursor.o \
madsv2/core/cycle.o \
madsv2/core/dialog.o \
+ madsv2/core/digi.o \
madsv2/core/ems.o \
madsv2/core/env.o \
madsv2/core/error.o \
+ madsv2/core/extra.o \
madsv2/core/fileio.o \
madsv2/core/font.o \
madsv2/core/game.o \
+ madsv2/core/global.o \
madsv2/core/heap.o \
madsv2/core/himem.o \
madsv2/core/hspot.o \
madsv2/core/imath.o \
+ madsv2/core/implode.o \
madsv2/core/inter.o \
madsv2/core/kernel.o \
madsv2/core/keys.o \
madsv2/core/lbm.o \
+ madsv2/core/lib.o \
madsv2/core/loader.o \
madsv2/core/magic.o \
madsv2/core/matte.o \
madsv2/core/mcga.o \
madsv2/core/mem.o \
+ madsv2/core/midi.o \
madsv2/core/mouse.o \
madsv2/core/object.o \
madsv2/core/pack.o \
madsv2/core/pal.o \
+ madsv2/core/pfab.o \
madsv2/core/player.o \
madsv2/core/popup.o \
madsv2/core/quote.o \
@@ -98,12 +107,13 @@ MODULE_OBJS += \
madsv2/core/room.o \
madsv2/core/screen.o \
madsv2/core/sort.o \
+ madsv2/core/sound.o \
madsv2/core/speech.o \
madsv2/core/sprite.o \
madsv2/core/text.o \
madsv2/core/tile.o \
madsv2/core/timer.o \
- madsv2/core/video_1.o \
+ madsv2/core/video.o \
madsv2/core/vocab.o \
madsv2/core/window.o \
madsv2/phantom/mads/mads.o \
Commit: 820abaa025208442faf47fc804e84d5a182b940e
https://github.com/scummvm/scummvm/commit/820abaa025208442faf47fc804e84d5a182b940e
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:19:07+10:00
Commit Message:
MADS: PHANTOM: Added remainder of main menu main function
Changed paths:
engines/mads/madsv2/core/kernel.cpp
engines/mads/madsv2/core/kernel.h
engines/mads/madsv2/phantom/main.cpp
engines/mads/madsv2/phantom/main_menu.cpp
engines/mads/madsv2/phantom/main_menu.h
diff --git a/engines/mads/madsv2/core/kernel.cpp b/engines/mads/madsv2/core/kernel.cpp
index 5ac6d865c37..43d6cb16b66 100644
--- a/engines/mads/madsv2/core/kernel.cpp
+++ b/engines/mads/madsv2/core/kernel.cpp
@@ -616,7 +616,7 @@ void kernel_room_shutdown() {
}
}
-int kernel_room_startup(int newRoom, int initial_variant, char *interface, int new_palette) {
+int kernel_room_startup(int newRoom, int initial_variant, char *interface, bool new_palette) {
int error_flag = true;
int load_flags;
#ifndef disable_error_check
@@ -631,8 +631,8 @@ int kernel_room_startup(int newRoom, int initial_variant, char *interface, int n
room_variant = initial_variant;
/* Start a brand new palette, reserving the proper # of colors */
-
- if (new_palette) pal_init(KERNEL_RESERVED_LOW_COLORS, KERNEL_RESERVED_HIGH_COLORS);
+ if (new_palette)
+ pal_init(KERNEL_RESERVED_LOW_COLORS, KERNEL_RESERVED_HIGH_COLORS);
pal_white(master_palette);
diff --git a/engines/mads/madsv2/core/kernel.h b/engines/mads/madsv2/core/kernel.h
index 2c83c6cae5a..7a1583250d9 100644
--- a/engines/mads/madsv2/core/kernel.h
+++ b/engines/mads/madsv2/core/kernel.h
@@ -440,8 +440,8 @@ extern int kernel_section_startup(int new_section);
*/
extern void kernel_room_shutdown();
-extern int kernel_room_startup(int new_room, int initial_variant,
- char *interface, int new_palette);
+extern int kernel_room_startup(int new_room, int initial_variant = 0,
+ char *interface = nullptr, bool new_palette = true);
/**
* Unloads all room series.
diff --git a/engines/mads/madsv2/phantom/main.cpp b/engines/mads/madsv2/phantom/main.cpp
index a458ab99179..5ae96d6d68d 100644
--- a/engines/mads/madsv2/phantom/main.cpp
+++ b/engines/mads/madsv2/phantom/main.cpp
@@ -21,18 +21,29 @@
#include "mads/madsv2/phantom/main.h"
#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/magic.h"
#include "mads/madsv2/core/matte.h"
+#include "mads/madsv2/core/mcga.h"
#include "mads/madsv2/core/mouse.h"
+#include "mads/madsv2/core/pal.h"
#include "mads/madsv2/core/quote.h"
#include "mads/madsv2/phantom/main_menu.h"
+#include "mads/madsv2/engine.h"
namespace MADS {
namespace MADSV2 {
namespace Phantom {
+constexpr bool SHOW_LINES = true;
+constexpr byte LINE_COLOR = 2;
+
char *quotes;
static void main_menu_main() {
+ auto &screen = *g_engine->getScreen();
+ Palette palette;
+ assert(sizeof(palette) == 768);
+
if (kernel_game_startup(19, KERNEL_STARTUP_CURSOR | KERNEL_STARTUP_INTERRUPT | KERNEL_STARTUP_FONT,
nullptr, nullptr)) {
viewing_at_y = (200 - scr_work.y) >> 1;
@@ -58,10 +69,54 @@ static void main_menu_main() {
97, 98, 99, 0);
global_speech_load(9);
-#if 0
- kernel_room_startup(922);
-#endif
+ bool valid = !kernel_room_startup(922);
+
+ master_palette[4].r = 63;
+ master_palette[4].g = 50;
+ master_palette[4].b = 0;
+ master_palette[5].r = 30;
+ master_palette[5].g = 15;
+ master_palette[5].b = 0;
+ mcga_setpal_range(&master_palette, 4, 2);
+
+ new_background = true;
+
+ if (valid) {
+ memset(&palette, 0, sizeof(palette));
+ mcga_setpal(&palette);
+ mouse_cursor_sprite(cursor, 1);
+
+ if (SHOW_LINES && viewing_at_y != 0) {
+ screen.hLine(0, viewing_at_y - 2, 319, LINE_COLOR);
+ screen.hLine(0, scr_work.y + viewing_at_y + 1, 319, LINE_COLOR);
+ }
+
+ kernel_load_sound_driver("*#SOUND.PH9", 'N', 544, 0, 49);
+
+ menu_control();
+
+ if (selected_item >= 0) {
+ // Zero out the first 3 entries of both magic color arrays
+ for (int i = 0; i < 3; i++) {
+ magic_color_values[i] = 0;
+ magic_color_flags[i] = 0;
+ }
+
+ mcga_getpal(&palette);
+
+ magic_fade_to_grey(palette, 0, 0x10, 1, 1, 0, 0, 0);
+ }
+ }
+
+ free(quotes);
+ kernel_unload_sound_driver();
+ kernel_game_shutdown();
}
+
+ mcga_reset();
+
+ // Handle menu item selection
+ warning("Selected item = %d", selected_item);
}
void phantom_main() {
diff --git a/engines/mads/madsv2/phantom/main_menu.cpp b/engines/mads/madsv2/phantom/main_menu.cpp
index 0b1ceb4b328..2f8944295ab 100644
--- a/engines/mads/madsv2/phantom/main_menu.cpp
+++ b/engines/mads/madsv2/phantom/main_menu.cpp
@@ -87,16 +87,14 @@ Buffer scr_live = { video_y, video_x, mcga_video };
FontPtr font = NULL;
int font_auto_spacing = -1;
-int new_background = false;
+bool new_background = false;
int room_number = 0;
int win_status = 0;
-int force_opening = false;
-
-int dont_return = false;
-
-int white_bars = true;
+bool force_opening = false;
+bool dont_return = false;
+bool white_bars = true;
byte white_border = 2;
char command_line[COMMAND_LINE_MAX][80];
diff --git a/engines/mads/madsv2/phantom/main_menu.h b/engines/mads/madsv2/phantom/main_menu.h
index 4b6e19b87f0..e06c6fa8089 100644
--- a/engines/mads/madsv2/phantom/main_menu.h
+++ b/engines/mads/madsv2/phantom/main_menu.h
@@ -47,6 +47,10 @@ typedef struct {
int status; /* Current status */
} MenuItem;
+extern bool new_background;
+extern int selected_item;
+
+
extern void global_speech_load(int id);
extern void menu_control();
Commit: fb55f2460edbab5aabb8af27cb1b4bf8d2e65a44
https://github.com/scummvm/scummvm/commit/fb55f2460edbab5aabb8af27cb1b4bf8d2e65a44
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:19:08+10:00
Commit Message:
MADS: PHANTOM: Fix setting g_engine global on engine creation
Changed paths:
engines/mads/madsv2/engine.cpp
engines/mads/madsv2/phantom/main.cpp
diff --git a/engines/mads/madsv2/engine.cpp b/engines/mads/madsv2/engine.cpp
index 61727c0cb34..90c88c3bdce 100644
--- a/engines/mads/madsv2/engine.cpp
+++ b/engines/mads/madsv2/engine.cpp
@@ -31,10 +31,12 @@ MADSV2Engine *g_engine;
MADSV2Engine::MADSV2Engine(OSystem *syst, const MADSGameDescription *gameDesc) :
Engine(syst), _gameDescription(gameDesc) {
+ g_engine = this;
}
MADSV2Engine::~MADSV2Engine() {
delete _screen;
+ g_engine = nullptr;
}
Common::Error MADSV2Engine::run() {
diff --git a/engines/mads/madsv2/phantom/main.cpp b/engines/mads/madsv2/phantom/main.cpp
index 5ae96d6d68d..f6a2466125b 100644
--- a/engines/mads/madsv2/phantom/main.cpp
+++ b/engines/mads/madsv2/phantom/main.cpp
@@ -42,7 +42,6 @@ char *quotes;
static void main_menu_main() {
auto &screen = *g_engine->getScreen();
Palette palette;
- assert(sizeof(palette) == 768);
if (kernel_game_startup(19, KERNEL_STARTUP_CURSOR | KERNEL_STARTUP_INTERRUPT | KERNEL_STARTUP_FONT,
nullptr, nullptr)) {
Commit: a5e3fc2ec2c1fe419e41df2bba8348ed698bfab7
https://github.com/scummvm/scummvm/commit/a5e3fc2ec2c1fe419e41df2bba8348ed698bfab7
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:19:08+10:00
Commit Message:
MADS: PHANTOM: Disable EMS/XMS initializations
The original throwed an error if EMS was not present, but I'm
hoping that any forced usage later on can be refactored to not
need it. That'll be better than trying to simulate EMS memory.
Changed paths:
engines/mads/madsv2/core/ems.h
engines/mads/madsv2/core/himem.cpp
engines/mads/madsv2/core/kernel.cpp
diff --git a/engines/mads/madsv2/core/ems.h b/engines/mads/madsv2/core/ems.h
index 3f3c5720b50..92a022c54b3 100644
--- a/engines/mads/madsv2/core/ems.h
+++ b/engines/mads/madsv2/core/ems.h
@@ -117,8 +117,8 @@ inline int ems_activate_directory() { return 0; }
inline int ems_activate_page_map() { return 0; }
inline int ems_paging_setup() { return 0; }
inline void ems_free_page_handle(word handle) {}
-inline int ems_get_page_handle(word pages_needed) { return 0; }
-inline int ems_next_handle_page(int handle, int page_marker) { return 0; }
+inline int ems_get_page_handle(word pages_needed) { return -1; }
+inline int ems_next_handle_page(int handle, int page_marker) { return -1; }
inline void ems_paging_mode(int paging_mode) {}
inline void ems_paging_shutdown() {}
inline int ems_copy_it_up(int ems_paging_handle, int *ems_page_marker,
diff --git a/engines/mads/madsv2/core/himem.cpp b/engines/mads/madsv2/core/himem.cpp
index 825039341d1..66ac0aff38d 100644
--- a/engines/mads/madsv2/core/himem.cpp
+++ b/engines/mads/madsv2/core/himem.cpp
@@ -34,9 +34,9 @@
namespace MADS {
namespace MADSV2 {
-
-byte himem_preload_ems_disabled = false;
-byte himem_preload_xms_disabled = false;
+// EMS/XMS disabled in ScummVM
+byte himem_preload_ems_disabled = true;
+byte himem_preload_xms_disabled = true;
byte himem_directory_allocation = MEM_NONE;
HimemDirectory himem_directory_save_area;
@@ -61,10 +61,9 @@ int himem_activate_directory(void) {
error_flag = !himem_directory_ems_active;
}
- return (error_flag);
+ return error_flag;
}
-
int himem_get_directory_entry(int id) {
int error_flag = true;
long dir_offset;
diff --git a/engines/mads/madsv2/core/kernel.cpp b/engines/mads/madsv2/core/kernel.cpp
index 43d6cb16b66..454fa436b6d 100644
--- a/engines/mads/madsv2/core/kernel.cpp
+++ b/engines/mads/madsv2/core/kernel.cpp
@@ -316,6 +316,8 @@ int kernel_game_startup(int game_video_mode, int load_flag,
himem_startup();
+ // ScummVM doesn't need EMS/XMS
+#if 0
ems_error = true;
if (ems_exists) {
@@ -334,7 +336,7 @@ int kernel_game_startup(int game_video_mode, int load_flag,
error_report(ERROR_KERNEL_NO_EMS, SEVERE, MODULE_KERNEL, ems_exists, work_screen_ems_handle);
}
}
-
+#endif
if (ems_exists) {
if (load_flag & KERNEL_STARTUP_POPUP) {
object_ems_handle = ems_get_page_handle(4);
Commit: e5d081d318b436af57a9e789ddcd56eb9d30b335
https://github.com/scummvm/scummvm/commit/e5d081d318b436af57a9e789ddcd56eb9d30b335
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:19:08+10:00
Commit Message:
MADS: PHANTOM: Fix crash in palette routines
Changed paths:
engines/mads/madsv2/core/mcga.cpp
engines/mads/madsv2/core/mouse.cpp
engines/mads/madsv2/core/screen.cpp
diff --git a/engines/mads/madsv2/core/mcga.cpp b/engines/mads/madsv2/core/mcga.cpp
index 0c0cbffd4a0..4b1f8b557d9 100644
--- a/engines/mads/madsv2/core/mcga.cpp
+++ b/engines/mads/madsv2/core/mcga.cpp
@@ -106,42 +106,18 @@ void mcga_close_window(byte *inp) {
}
void mcga_setpal(Palette *pal) {
- byte tmpPal[Graphics::PALETTE_SIZE];
- byte *entry = &tmpPal[0];
-
- for (int i = 0; i < Graphics::PALETTE_COUNT; ++i, entry += 3) {
- entry[0] = pal[i]->r;
- entry[1] = pal[i]->g;
- entry[2] = pal[i]->b;
- }
-
- g_system->getPaletteManager()->setPalette(tmpPal, 0, Graphics::PALETTE_COUNT);
+ const byte *colors = (byte *)&(*pal)[0];
+ g_system->getPaletteManager()->setPalette(colors, 0, Graphics::PALETTE_COUNT);
}
void mcga_getpal(Palette *pal) {
- byte tmpPal[Graphics::PALETTE_SIZE];
- byte *entry = &tmpPal[0];
-
- g_system->getPaletteManager()->grabPalette(tmpPal, 0, Graphics::PALETTE_COUNT);
-
- for (int i = 0; i < Graphics::PALETTE_COUNT; ++i, entry += 3) {
- pal[i]->r = entry[0];
- pal[i]->g = entry[1];
- pal[i]->b = entry[2];
- }
+ byte *colors = (byte *)&(*pal)[0];
+ g_system->getPaletteManager()->grabPalette(colors, 0, Graphics::PALETTE_COUNT);
}
void mcga_setpal_range(Palette *pal, int first_color, int num_colors) {
- byte tmpPal[Graphics::PALETTE_SIZE];
- byte *entry = &tmpPal[0];
-
- for (int i = 0; i < num_colors; ++i, entry += 3) {
- entry[0] = pal[i + first_color]->r;
- entry[1] = pal[i + first_color]->g;
- entry[2] = pal[i + first_color]->b;
- }
-
- g_system->getPaletteManager()->setPalette(tmpPal, first_color, num_colors);
+ byte *colors = (byte *)&(*pal)[first_color];
+ g_system->getPaletteManager()->setPalette(colors, first_color, num_colors);
}
@@ -171,8 +147,8 @@ void mcga_compute_retrace_parameters(void) {
modern graphics API there is no retrace constraint, so we set the
maximums to the full 256-entry palette and mark the computation done. */
mcga_palette_fast = true;
- mcga_retrace_max_colors = 256;
- mcga_retrace_max_bytes = 256 * 3;
+ mcga_retrace_max_colors = Graphics::PALETTE_COUNT;
+ mcga_retrace_max_bytes = Graphics::PALETTE_SIZE;
mcga_retrace_computed = true;
}
diff --git a/engines/mads/madsv2/core/mouse.cpp b/engines/mads/madsv2/core/mouse.cpp
index 2c29c54ff1c..12a8f38a459 100644
--- a/engines/mads/madsv2/core/mouse.cpp
+++ b/engines/mads/madsv2/core/mouse.cpp
@@ -74,7 +74,7 @@ int mouse_video_mode = 0;
int mouse_init(int driverflag, int videomode) {
- // No implementation
+ // No implementation in ScummVM
return 0;
}
diff --git a/engines/mads/madsv2/core/screen.cpp b/engines/mads/madsv2/core/screen.cpp
index 777c8b8c66f..d5db60c6186 100644
--- a/engines/mads/madsv2/core/screen.cpp
+++ b/engines/mads/madsv2/core/screen.cpp
@@ -100,19 +100,19 @@ void screen_clear(int clear_color) {
}
void screen_dominant_mode(int dominant_mode) {
- warning("TODO: screen_set_colors");
+ // No implementation in ScummVM
}
void screen_init(int video_mode) {
- warning("TODO: screen_init");
+ // No implementation in ScummVM
}
void screen_init_dual(int mono_left) {
- warning("TODO: screen_init_dual");
+ error("TODO: screen_init_dual");
}
void screen_shutdown_dual(int clear_flag) {
- warning("TODO: screen_shutdown_dual");
+ error("TODO: screen_shutdown_dual");
}
void screen_init_graphics(int which_mode) {
Commit: 621c1344a5fd532363ca47c2d6cbf46ba8c9c73d
https://github.com/scummvm/scummvm/commit/621c1344a5fd532363ca47c2d6cbf46ba8c9c73d
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:19:08+10:00
Commit Message:
MADS: PHANTOM: Fix env_open for reading .hag resources
Changed paths:
engines/mads/madsv2/core/concat.h
engines/mads/madsv2/core/env.cpp
engines/mads/madsv2/core/fileio.cpp
engines/mads/madsv2/core/font.cpp
engines/mads/madsv2/phantom/main.cpp
diff --git a/engines/mads/madsv2/core/concat.h b/engines/mads/madsv2/core/concat.h
index d312018a886..f5206ba1eb4 100644
--- a/engines/mads/madsv2/core/concat.h
+++ b/engines/mads/madsv2/core/concat.h
@@ -36,11 +36,21 @@ namespace MADSV2 {
#define CONCAT_MAX_FILES 750
#define CONCAT_MAX_OUT 10
-typedef struct {
+struct Concat {
long file_offset;
long file_size;
char name[13];
-} Concat;
+
+ void load(Common::SeekableReadStream *src) {
+ file_offset = src->readSint32LE();
+ file_size = src->readSint32LE();
+ src->read(name, 13);
+ src->skip(1);
+ }
+ static uint size() {
+ return 22;
+ }
+};
typedef Concat *ConcatPtr;
diff --git a/engines/mads/madsv2/core/env.cpp b/engines/mads/madsv2/core/env.cpp
index ffb82740b06..f1123af21bb 100644
--- a/engines/mads/madsv2/core/env.cpp
+++ b/engines/mads/madsv2/core/env.cpp
@@ -63,7 +63,18 @@ static const char env_speech2_string[8] = "SPEECH2";
int env_verify() {
- return 0;
+ Common::String str = ConfMan.get(MADS_PRIV_ENV);
+ str.toUppercase();
+
+ if (str.contains("ARTIST")) env_privileges |= MADS_PRIV_ARTIST;
+ if (str.contains("DESIGNER")) env_privileges |= MADS_PRIV_DESIGNER;
+ if (str.contains("PROGRAM")) env_privileges |= MADS_PRIV_PROGRAM;
+ if (str.contains("SYSTEM")) env_privileges |= MADS_PRIV_PROGRAM | MADS_PRIV_SYSTEM;
+
+ if (ConfMan.hasKey(MADS_SOUND_ENV))
+ env_sound_override = true;
+
+ return ConfMan.hasKey(MADS_ENV);
}
char *env_catint(char *out, int value, int digits) {
@@ -118,10 +129,8 @@ char *env_fill_path(char *path, int env_mode, int env_room) {
env_sect = env_room;
}
- if (madsptr != NULL) {
-
+ if (!madsptr.empty()) {
madslen = strlen(madsptr.c_str());
-
Common::strcpy_s(madspath, 65536, madsptr.c_str());
if (madsptr[madslen - 1] != '\\') {
@@ -203,7 +212,6 @@ char *env_get_path(char *madspath, const char *infile) {
mads_strupr(madspath);
} else {
- /* infile is '*d322u001.rac' */
infile++;
Common::strcpy_s(temp_buf_1, infile);
mads_strupr(temp_buf_1);
@@ -292,7 +300,6 @@ Common::SeekableReadStream *env_open(const char *filename, const char *options)
int count;
int found;
int num_files;
- long mem_to_get;
char file_path[80];
char index_file[80];
char temp_file[80];
@@ -305,8 +312,8 @@ Common::SeekableReadStream *env_open(const char *filename, const char *options)
Common::SeekableReadStream *handle = NULL;
Concat concat;
concat.file_offset = concat.file_size = 0;
- Concat *concat_array = NULL;
+ Common::strcpy_s(file_path, filename);
if (env_get_path(load_file, file_path) == NULL) goto done;
Common::strcpy_s(file_path, filename);
@@ -368,12 +375,10 @@ Common::SeekableReadStream *env_open(const char *filename, const char *options)
}
} else if ((env_search_mode == ENV_SEARCH_CONCAT_FILES) && (mark != NULL)) {
-
mark++;
Common::strcpy_s(temp_buf, mark);
mads_strupr(temp_buf);
-
/* load_file = 'global.hag' */
if (art_hags_are_on_hd) {
Common::strcpy_s(index_file, load_file);
@@ -383,12 +388,12 @@ Common::SeekableReadStream *env_open(const char *filename, const char *options)
/* index_file = 'global.idx' */
if (env_search_cd && !art_hags_are_on_hd) {
-
if (fileio_exist(index_file)) {
/* if 'global.idx' exists */
Common::File *f = new Common::File();
f->open(index_file);
- handle = f;
+ assert(f->isOpen());
+ index_handle = f;
}
Common::strcpy_s(temp_file, "X:\\");
@@ -409,9 +414,7 @@ Common::SeekableReadStream *env_open(const char *filename, const char *options)
if (index_handle == NULL) {
Common::File *f = new Common::File();
- f->open(load_file);
-
- if (index_handle == NULL) {
+ if (!f->open(load_file)) {
delete f;
goto done;
}
@@ -422,47 +425,26 @@ Common::SeekableReadStream *env_open(const char *filename, const char *options)
if (!fileio_fread_f(&check_buf, CONCAT_ID_LENGTH, 1, index_handle)) goto done;
if (strncmp(check_buf, CONCAT_ID_STRING, CONCAT_ID_CHECK) != 0) goto done;
- if (!fileio_fread_f(&num_files, sizeof(int), 1, index_handle)) goto done;
+ num_files = index_handle->readUint16LE();
found = false;
- mem_to_get = (long)num_files * sizeof(Concat);
- concat_array = (Concat *)mem_get(mem_to_get);
-
- if (concat_array != NULL) {
- if (!fileio_fread_f(concat_array, mem_to_get, 1, index_handle)) goto done;
- for (count = 0; !found && (count < num_files); count++) {
- found = (strcmp(temp_buf, concat_array[count].name) == 0);
- if (found) {
- concat = concat_array[count];
- }
- }
- } else {
- for (count = 0; !found && (count < num_files); count++) {
- if (!fileio_fread_f(&concat, sizeof(Concat), 1, index_handle)) goto done;
- found = (strcmp(temp_buf, concat.name) == 0);
- }
+ for (count = 0; !found && (count < num_files); count++) {
+ concat.load(index_handle);
+ found = (strcmp(temp_buf, concat.name) == 0);
}
- delete index_handle;
- index_handle = NULL;
-
if (found) {
- Common::File *f = new Common::File();
- f->open(load_file);
-
- if (handle == NULL) {
- delete f;
- goto done;
- }
-
- handle = f;
-
- if (fileio_setpos(handle, concat.file_offset) != concat.file_offset) goto done;
+ if (!index_handle->seek(concat.file_offset))
+ error("Invalid hag entry offset");
+ handle = index_handle->readStream(concat.file_size);
env_concat_file_size = concat.file_size;
}
+ delete index_handle;
+ index_handle = NULL;
+
} else {
Common::File *f = new Common::File();
f->open(load_file);
@@ -472,7 +454,6 @@ Common::SeekableReadStream *env_open(const char *filename, const char *options)
error_flag = false;
done:
- if (concat_array != NULL) mem_free(concat_array);
delete index_handle;
if (error_flag) {
diff --git a/engines/mads/madsv2/core/fileio.cpp b/engines/mads/madsv2/core/fileio.cpp
index 4c4a78353d3..e865e9bbcd3 100644
--- a/engines/mads/madsv2/core/fileio.cpp
+++ b/engines/mads/madsv2/core/fileio.cpp
@@ -171,9 +171,9 @@ long fileio_setpos(Common::Stream *handle, long pos) {
auto *ws = dynamic_cast<Common::SeekableWriteStream *>(handle);
if (rs)
- return rs->pos();
+ return rs->seek(pos) ? pos : -1;
if (ws)
- return ws->pos();
+ return ws->seek(pos) ? pos : -1;
return -1;
}
diff --git a/engines/mads/madsv2/core/font.cpp b/engines/mads/madsv2/core/font.cpp
index efe2f02b493..801d993f991 100644
--- a/engines/mads/madsv2/core/font.cpp
+++ b/engines/mads/madsv2/core/font.cpp
@@ -61,6 +61,7 @@ FontPtr font_load(const char *name) {
mark = temp_buf_2;
if (*mark == '*') mark++;
strncpy(block_name, mark, 8);
+ block_name[8] = '\0';
if (loader_open(&load_handle, temp_buf_2, "rb", true)) goto done;
diff --git a/engines/mads/madsv2/phantom/main.cpp b/engines/mads/madsv2/phantom/main.cpp
index f6a2466125b..6a153f3cc86 100644
--- a/engines/mads/madsv2/phantom/main.cpp
+++ b/engines/mads/madsv2/phantom/main.cpp
@@ -20,6 +20,7 @@
*/
#include "mads/madsv2/phantom/main.h"
+#include "mads/madsv2/core/env.h"
#include "mads/madsv2/core/kernel.h"
#include "mads/madsv2/core/magic.h"
#include "mads/madsv2/core/matte.h"
@@ -119,6 +120,9 @@ static void main_menu_main() {
}
void phantom_main() {
+ if (!env_verify())
+ env_search_mode = ENV_SEARCH_CONCAT_FILES;
+
main_menu_main();
}
Commit: 38046d6a93d700c7dc95e2be6f5f7691f687f3bd
https://github.com/scummvm/scummvm/commit/38046d6a93d700c7dc95e2be6f5f7691f687f3bd
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:19:09+10:00
Commit Message:
MADS: PHANTOM: Endian safe reading of hag file index
Changed paths:
engines/mads/madsv2/core/concat.h
engines/mads/madsv2/core/loader.cpp
engines/mads/madsv2/core/pack.cpp
engines/mads/madsv2/core/pack.h
diff --git a/engines/mads/madsv2/core/concat.h b/engines/mads/madsv2/core/concat.h
index f5206ba1eb4..b60e85329be 100644
--- a/engines/mads/madsv2/core/concat.h
+++ b/engines/mads/madsv2/core/concat.h
@@ -22,7 +22,7 @@
#ifndef MADS_CORE_CONCAT_H
#define MADS_CORE_CONCAT_H
-#include "common/scummsys.h"
+#include "common/stream.h"
namespace MADS {
namespace MADSV2 {
@@ -47,8 +47,8 @@ struct Concat {
src->read(name, 13);
src->skip(1);
}
- static uint size() {
- return 22;
+ static uint record_size() {
+ return 4 + 4 + 13 + 1;
}
};
diff --git a/engines/mads/madsv2/core/loader.cpp b/engines/mads/madsv2/core/loader.cpp
index 4c32ca2aed8..69a0dd482b7 100644
--- a/engines/mads/madsv2/core/loader.cpp
+++ b/engines/mads/madsv2/core/loader.cpp
@@ -114,16 +114,11 @@ int loader_open(LoadHandle handle, const char *filename, const char *options, in
if (reading) {
base_position = handle->handle->pos();
- if (!fileio_fread_f(&handle->pack, PACK_HEADER, 1, handle->handle)) goto done;
- if (strncmp(handle->pack.id_string, PACK_ID_STRING, PACK_ID_CHECK) != 0) goto done;
- if (!fileio_fread_f(&handle->pack.strategy[0], sizeof(PackStrategy) * handle->pack.num_records, 1, handle->handle)) goto done;
- base_position += sizeof(PackList);
- handle->handle->seek(base_position);
-
- /*
- if (!fileio_fread_f(&handle->pack, sizeof(PackList), 1, handle->handle)) goto done;
- if (strncmp(handle->pack.id_string, PACK_ID_STRING, PACK_ID_CHECK) != 0) goto done;
- */
+
+ if (!handle->pack.load(handle->handle))
+ goto done;
+
+ base_position = handle->handle->pos();
handle->decompress_size = 0;
for (count = 0; count < (int)handle->pack.num_records; count++) {
diff --git a/engines/mads/madsv2/core/pack.cpp b/engines/mads/madsv2/core/pack.cpp
index bf2438ea0ce..f6ddec50837 100644
--- a/engines/mads/madsv2/core/pack.cpp
+++ b/engines/mads/madsv2/core/pack.cpp
@@ -103,6 +103,30 @@ word (*pack_pFABexp2_routine)(
char *work_buff) = NULL;
+void PackStrategy::load(Common::SeekableReadStream *src) {
+ type = src->readByte();
+ priority = src->readByte();
+ size = src->readUint32LE();
+ compressed_size = src->readUint32LE();
+}
+
+bool PackList::load(Common::SeekableReadStream *src) {
+ src->read(id_string, PACK_ID_LENGTH);
+ num_records = src->readUint16LE();
+
+ // Confirm that the ID is correct
+ if (strncmp(id_string, PACK_ID_STRING, PACK_ID_CHECK) != 0)
+ return false;
+
+ // Read in the index. Note that only num_records worth of entries are
+ // valid, but space is left in the file for the maximum amount of entries
+ for (int i = 0; i < PACK_MAX_LIST_LENGTH; ++i)
+ strategy[i].load(src);
+
+ return true;
+}
+
+
word pack_read_memory(char *buffer, word *mysize) {
word cx = *mysize;
uint32 remaining = pack_read_size;
diff --git a/engines/mads/madsv2/core/pack.h b/engines/mads/madsv2/core/pack.h
index 4be5120d6f5..66883108da4 100644
--- a/engines/mads/madsv2/core/pack.h
+++ b/engines/mads/madsv2/core/pack.h
@@ -81,21 +81,31 @@ namespace MADSV2 {
#define PACK_OVERHEAD sizeof(PackList)
-typedef struct {
+struct PackStrategy {
byte type;
byte priority;
long size;
long compressed_size;
-} PackStrategy;
+
+ void load(Common::SeekableReadStream *src);
+ static uint SIZE() {
+ return 1 + 1 + 4 + 4;
+ }
+};
typedef PackStrategy *PackStrategyPtr;
-typedef struct {
+struct PackList {
char id_string[PACK_ID_LENGTH];
word num_records;
PackStrategy strategy[PACK_MAX_LIST_LENGTH];
-} PackList;
+
+ bool load(Common::SeekableReadStream *src);
+ static uint SIZE() {
+ return PACK_ID_LENGTH + 2 + (PackStrategy::SIZE() * PACK_MAX_LIST_LENGTH);
+ }
+};
#define PACK_HEADER (PACK_ID_LENGTH + 2)
Commit: 151a99a32b205093a26be0027685eca6c99f0e2d
https://github.com/scummvm/scummvm/commit/151a99a32b205093a26be0027685eca6c99f0e2d
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:19:09+10:00
Commit Message:
MADS: PHANTOM: Fix EMS crash when an error is generated
Changed paths:
engines/mads/madsv2/core/himem.cpp
diff --git a/engines/mads/madsv2/core/himem.cpp b/engines/mads/madsv2/core/himem.cpp
index 66ac0aff38d..1591d71e77a 100644
--- a/engines/mads/madsv2/core/himem.cpp
+++ b/engines/mads/madsv2/core/himem.cpp
@@ -59,6 +59,9 @@ int himem_activate_directory(void) {
himem_directory_ems_active = !ems_activate_page_map();
error_flag = !himem_directory_ems_active;
+ } else if (himem_directory_allocation == MEM_NONE) {
+ // Added for ScummVM, since we don't have EMS
+ error_flag = true;
}
return error_flag;
Commit: 0591db5a982176a59f51f246ed08f267b212f134
https://github.com/scummvm/scummvm/commit/0591db5a982176a59f51f246ed08f267b212f134
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:19:09+10:00
Commit Message:
MADS: PHANTOM: Properly setup decompressors on startup
Changed paths:
engines/mads/madsv2/phantom/main.cpp
diff --git a/engines/mads/madsv2/phantom/main.cpp b/engines/mads/madsv2/phantom/main.cpp
index 6a153f3cc86..4842e38d586 100644
--- a/engines/mads/madsv2/phantom/main.cpp
+++ b/engines/mads/madsv2/phantom/main.cpp
@@ -120,6 +120,7 @@ static void main_menu_main() {
}
void phantom_main() {
+ pack_enable_pfab_explode();
if (!env_verify())
env_search_mode = ENV_SEARCH_CONCAT_FILES;
Commit: 817d3e973ccd3be9e596f9d235121ec085190fac
https://github.com/scummvm/scummvm/commit/817d3e973ccd3be9e596f9d235121ec085190fac
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:21:15+10:00
Commit Message:
MADS: Create common base engine class shared with Rex Nebular
Changed paths:
A engines/mads/core/action.cpp
A engines/mads/core/action.h
A engines/mads/core/animation.cpp
A engines/mads/core/animation.h
A engines/mads/core/assets.cpp
A engines/mads/core/assets.h
A engines/mads/core/audio.cpp
A engines/mads/core/audio.h
A engines/mads/core/camera.cpp
A engines/mads/core/camera.h
A engines/mads/core/compression.cpp
A engines/mads/core/compression.h
A engines/mads/core/conversations.cpp
A engines/mads/core/conversations.h
A engines/mads/core/dialogs.cpp
A engines/mads/core/dialogs.h
A engines/mads/core/events.cpp
A engines/mads/core/events.h
A engines/mads/core/font.cpp
A engines/mads/core/font.h
A engines/mads/core/game.cpp
A engines/mads/core/game.h
A engines/mads/core/game_data.cpp
A engines/mads/core/game_data.h
A engines/mads/core/globals.cpp
A engines/mads/core/globals.h
A engines/mads/core/hotspots.cpp
A engines/mads/core/hotspots.h
A engines/mads/core/inventory.cpp
A engines/mads/core/inventory.h
A engines/mads/core/menu_views.cpp
A engines/mads/core/menu_views.h
A engines/mads/core/messages.cpp
A engines/mads/core/messages.h
A engines/mads/core/mps_installer.cpp
A engines/mads/core/mps_installer.h
A engines/mads/core/msurface.cpp
A engines/mads/core/msurface.h
A engines/mads/core/palette.cpp
A engines/mads/core/palette.h
A engines/mads/core/player.cpp
A engines/mads/core/player.h
A engines/mads/core/rails.cpp
A engines/mads/core/rails.h
A engines/mads/core/resources.cpp
A engines/mads/core/resources.h
A engines/mads/core/scene.cpp
A engines/mads/core/scene.h
A engines/mads/core/scene_data.cpp
A engines/mads/core/scene_data.h
A engines/mads/core/screen.cpp
A engines/mads/core/screen.h
A engines/mads/core/sequence.cpp
A engines/mads/core/sequence.h
A engines/mads/core/sound.cpp
A engines/mads/core/sound.h
A engines/mads/core/sprites.cpp
A engines/mads/core/sprites.h
A engines/mads/core/staticres.cpp
A engines/mads/core/staticres.h
A engines/mads/core/user_interface.cpp
A engines/mads/core/user_interface.h
A engines/mads/nebular/debugger.cpp
A engines/mads/nebular/debugger.h
A engines/mads/nebular/nebular.cpp
A engines/mads/nebular/nebular.h
R engines/mads/action.cpp
R engines/mads/action.h
R engines/mads/animation.cpp
R engines/mads/animation.h
R engines/mads/assets.cpp
R engines/mads/assets.h
R engines/mads/audio.cpp
R engines/mads/audio.h
R engines/mads/camera.cpp
R engines/mads/camera.h
R engines/mads/compression.cpp
R engines/mads/compression.h
R engines/mads/conversations.cpp
R engines/mads/conversations.h
R engines/mads/debugger.cpp
R engines/mads/debugger.h
R engines/mads/dialogs.cpp
R engines/mads/dialogs.h
R engines/mads/events.cpp
R engines/mads/events.h
R engines/mads/font.cpp
R engines/mads/font.h
R engines/mads/game.cpp
R engines/mads/game.h
R engines/mads/game_data.cpp
R engines/mads/game_data.h
R engines/mads/globals.cpp
R engines/mads/globals.h
R engines/mads/hotspots.cpp
R engines/mads/hotspots.h
R engines/mads/inventory.cpp
R engines/mads/inventory.h
R engines/mads/menu_views.cpp
R engines/mads/menu_views.h
R engines/mads/messages.cpp
R engines/mads/messages.h
R engines/mads/mps_installer.cpp
R engines/mads/mps_installer.h
R engines/mads/msurface.cpp
R engines/mads/msurface.h
R engines/mads/palette.cpp
R engines/mads/palette.h
R engines/mads/player.cpp
R engines/mads/player.h
R engines/mads/rails.cpp
R engines/mads/rails.h
R engines/mads/resources.cpp
R engines/mads/resources.h
R engines/mads/scene.cpp
R engines/mads/scene.h
R engines/mads/scene_data.cpp
R engines/mads/scene_data.h
R engines/mads/screen.cpp
R engines/mads/screen.h
R engines/mads/sequence.cpp
R engines/mads/sequence.h
R engines/mads/sound.cpp
R engines/mads/sound.h
R engines/mads/sprites.cpp
R engines/mads/sprites.h
R engines/mads/staticres.cpp
R engines/mads/staticres.h
R engines/mads/user_interface.cpp
R engines/mads/user_interface.h
engines/mads/dragonsphere/dragonsphere_scenes.cpp
engines/mads/dragonsphere/dragonsphere_scenes.h
engines/mads/dragonsphere/dragonsphere_scenes1.cpp
engines/mads/dragonsphere/dragonsphere_scenes1.h
engines/mads/dragonsphere/game_dragonsphere.cpp
engines/mads/dragonsphere/game_dragonsphere.h
engines/mads/dragonsphere/globals_dragonsphere.h
engines/mads/forest/forest_scenes.cpp
engines/mads/forest/forest_scenes.h
engines/mads/forest/game_forest.cpp
engines/mads/forest/game_forest.h
engines/mads/forest/globals_forest.h
engines/mads/mads.cpp
engines/mads/mads.h
engines/mads/madsv2/core/loader.cpp
engines/mads/madsv2/engine.cpp
engines/mads/madsv2/engine.h
engines/mads/metaengine.cpp
engines/mads/module.mk
engines/mads/nebular/dialogs_nebular.cpp
engines/mads/nebular/dialogs_nebular.h
engines/mads/nebular/game_nebular.cpp
engines/mads/nebular/game_nebular.h
engines/mads/nebular/globals_nebular.h
engines/mads/nebular/menu_nebular.cpp
engines/mads/nebular/menu_nebular.h
engines/mads/nebular/nebular_scenes.cpp
engines/mads/nebular/nebular_scenes.h
engines/mads/nebular/nebular_scenes1.cpp
engines/mads/nebular/nebular_scenes1.h
engines/mads/nebular/nebular_scenes2.cpp
engines/mads/nebular/nebular_scenes2.h
engines/mads/nebular/nebular_scenes3.cpp
engines/mads/nebular/nebular_scenes3.h
engines/mads/nebular/nebular_scenes4.cpp
engines/mads/nebular/nebular_scenes4.h
engines/mads/nebular/nebular_scenes5.cpp
engines/mads/nebular/nebular_scenes5.h
engines/mads/nebular/nebular_scenes6.cpp
engines/mads/nebular/nebular_scenes6.h
engines/mads/nebular/nebular_scenes7.cpp
engines/mads/nebular/nebular_scenes7.h
engines/mads/nebular/nebular_scenes8.cpp
engines/mads/nebular/nebular_scenes8.h
diff --git a/engines/mads/action.cpp b/engines/mads/core/action.cpp
similarity index 98%
rename from engines/mads/action.cpp
rename to engines/mads/core/action.cpp
index abe3b8abb48..0dda3d20ab3 100644
--- a/engines/mads/action.cpp
+++ b/engines/mads/core/action.cpp
@@ -19,12 +19,12 @@
*
*/
-#include "mads/mads.h"
-#include "mads/action.h"
-#include "mads/inventory.h"
-#include "mads/resources.h"
-#include "mads/scene.h"
-#include "mads/staticres.h"
+#include "mads/nebular/nebular.h"
+#include "mads/core/action.h"
+#include "mads/core/inventory.h"
+#include "mads/core/resources.h"
+#include "mads/core/scene.h"
+#include "mads/core/staticres.h"
namespace MADS {
@@ -48,7 +48,7 @@ void ActionSavedFields::synchronize(Common::Serializer &s) {
/*------------------------------------------------------------------------*/
-MADSAction::MADSAction(MADSEngine *vm) : _vm(vm) {
+MADSAction::MADSAction(RexNebularEngine *vm) : _vm(vm) {
clear();
_statusTextIndex = -1;
_selectedAction = 0;
diff --git a/engines/mads/action.h b/engines/mads/core/action.h
similarity index 98%
rename from engines/mads/action.h
rename to engines/mads/core/action.h
index e57b9486014..1eeaf402c59 100644
--- a/engines/mads/action.h
+++ b/engines/mads/core/action.h
@@ -70,7 +70,7 @@ enum ScrCategory {
CAT_12 = 12
};
-class MADSEngine;
+class RexNebularEngine;
struct ActionDetails {
int _verbId;
@@ -102,7 +102,7 @@ struct ActionSavedFields {
class MADSAction {
private:
- MADSEngine *_vm;
+ RexNebularEngine *_vm;
Common::String _statusText;
void appendVocab(int vocabId, bool capitalize = false);
@@ -134,7 +134,7 @@ public:
int _pickedWord;
public:
- MADSAction(MADSEngine *vm);
+ MADSAction(RexNebularEngine *vm);
void clear();
void set();
diff --git a/engines/mads/animation.cpp b/engines/mads/core/animation.cpp
similarity index 98%
rename from engines/mads/animation.cpp
rename to engines/mads/core/animation.cpp
index 946dcac0f02..26d2ae05599 100644
--- a/engines/mads/animation.cpp
+++ b/engines/mads/core/animation.cpp
@@ -19,8 +19,9 @@
*
*/
-#include "mads/animation.h"
-#include "mads/compression.h"
+#include "mads/core/animation.h"
+#include "mads/core/compression.h"
+#include "mads/nebular/nebular.h"
#define FILENAME_SIZE 13
@@ -153,11 +154,11 @@ void AnimUIEntry::load(Common::SeekableReadStream *f) {
/*------------------------------------------------------------------------*/
-Animation *Animation::init(MADSEngine *vm, Scene *scene) {
+Animation *Animation::init(RexNebularEngine *vm, Scene *scene) {
return new Animation(vm, scene);
}
-Animation::Animation(MADSEngine *vm, Scene *scene) : _vm(vm), _scene(scene) {
+Animation::Animation(RexNebularEngine *vm, Scene *scene) : _vm(vm), _scene(scene) {
_flags = 0;
_font = nullptr;
_resetFlag = false;
diff --git a/engines/mads/animation.h b/engines/mads/core/animation.h
similarity index 96%
rename from engines/mads/animation.h
rename to engines/mads/core/animation.h
index 263f62036a4..e41190426f1 100644
--- a/engines/mads/animation.h
+++ b/engines/mads/core/animation.h
@@ -24,9 +24,9 @@
#include "common/array.h"
#include "common/rect.h"
-#include "mads/msurface.h"
-#include "mads/scene_data.h"
-#include "mads/font.h"
+#include "mads/core/msurface.h"
+#include "mads/core/scene_data.h"
+#include "mads/core/font.h"
namespace MADS {
@@ -139,7 +139,7 @@ public:
class Animation {
private:
- MADSEngine *_vm;
+ RexNebularEngine *_vm;
Scene *_scene;
Common::Array<AnimMiscEntry> _miscEntries;
@@ -179,7 +179,7 @@ private:
*/
bool hasScroll() const;
protected:
- Animation(MADSEngine *vm, Scene *scene);
+ Animation(RexNebularEngine *vm, Scene *scene);
public:
AAHeader _header;
Common::Array<int> _spriteListIndexes;
@@ -192,7 +192,8 @@ public:
int _oldFrameEntry;
int _dynamicHotspotIndex;
- static Animation *init(MADSEngine *vm, Scene *scene);
+ static Animation *init(RexNebularEngine *vm, Scene *scene);
+
/*
* Destructor
*/
diff --git a/engines/mads/assets.cpp b/engines/mads/core/assets.cpp
similarity index 94%
rename from engines/mads/assets.cpp
rename to engines/mads/core/assets.cpp
index 9d667ddd954..8a1da96bad0 100644
--- a/engines/mads/assets.cpp
+++ b/engines/mads/core/assets.cpp
@@ -19,14 +19,15 @@
*
*/
-#include "mads/mads.h"
-#include "mads/assets.h"
-#include "mads/compression.h"
-#include "mads/palette.h"
+#include "mads/nebular/nebular.h"
+#include "mads/core/assets.h"
+#include "mads/core/compression.h"
+#include "mads/core/palette.h"
+#include "mads/core/resources.h"
namespace MADS {
-SpriteAsset::SpriteAsset(MADSEngine *vm, const Common::Path &resourceName, int flags) : _vm(vm) {
+SpriteAsset::SpriteAsset(RexNebularEngine *vm, const Common::Path &resourceName, int flags) : _vm(vm) {
Common::Path resName = resourceName;
Common::String baseName(resName.baseName());
if (!baseName.hasSuffix(".SS") && !baseName.hasSuffix(".ss"))
@@ -39,7 +40,7 @@ SpriteAsset::SpriteAsset(MADSEngine *vm, const Common::Path &resourceName, int f
file.close();
}
-SpriteAsset::SpriteAsset(MADSEngine *vm, Common::SeekableReadStream *stream, int flags) : _vm(vm) {
+SpriteAsset::SpriteAsset(RexNebularEngine *vm, Common::SeekableReadStream *stream, int flags) : _vm(vm) {
_srcSize = 0;
load(stream, flags);
diff --git a/engines/mads/assets.h b/engines/mads/core/assets.h
similarity index 91%
rename from engines/mads/assets.h
rename to engines/mads/core/assets.h
index 334cbe0e56b..07f125e4abc 100644
--- a/engines/mads/assets.h
+++ b/engines/mads/core/assets.h
@@ -24,7 +24,8 @@
#include "common/array.h"
#include "common/path.h"
-#include "mads/palette.h"
+#include "common/rect.h"
+#include "mads/core/palette.h"
namespace MADS {
@@ -33,7 +34,7 @@ enum AssetFlags {
ASSET_SPINNING_OBJECT = 8
};
-class MADSEngine;
+class RexNebularEngine;
class MSprite;
class MSurface;
@@ -60,7 +61,7 @@ public:
class SpriteAsset {
private:
- MADSEngine *_vm;
+ RexNebularEngine *_vm;
byte _palette[PALETTE_SIZE];
int _colorCount;
uint32 _srcSize;
@@ -84,12 +85,12 @@ public:
/**
* Constructor
*/
- SpriteAsset(MADSEngine *vm, const Common::Path &resourceName, int flags);
+ SpriteAsset(RexNebularEngine *vm, const Common::Path &resourceName, int flags);
/**
* Constructor
*/
- SpriteAsset(MADSEngine *vm, Common::SeekableReadStream *stream, int flags);
+ SpriteAsset(RexNebularEngine *vm, Common::SeekableReadStream *stream, int flags);
/**
* Destructor
diff --git a/engines/mads/audio.cpp b/engines/mads/core/audio.cpp
similarity index 97%
rename from engines/mads/audio.cpp
rename to engines/mads/core/audio.cpp
index d1f0ae5a410..a75939a6174 100644
--- a/engines/mads/audio.cpp
+++ b/engines/mads/core/audio.cpp
@@ -19,9 +19,9 @@
*
*/
-#include "mads/audio.h"
-#include "mads/compression.h"
-
+#include "mads/core/audio.h"
+#include "mads/core/compression.h"
+#include "mads/detection.h"
#include "common/stream.h"
#include "audio/audiostream.h"
#include "audio/mixer.h"
diff --git a/engines/mads/audio.h b/engines/mads/core/audio.h
similarity index 97%
rename from engines/mads/audio.h
rename to engines/mads/core/audio.h
index 6442a242a8c..6978cb0e6a2 100644
--- a/engines/mads/audio.h
+++ b/engines/mads/core/audio.h
@@ -22,7 +22,7 @@
#ifndef MADS_AUDIO_H
#define MADS_AUDIO_H
-#include "mads/resources.h"
+#include "mads/core/resources.h"
#include "common/array.h"
#include "audio/mixer.h"
diff --git a/engines/mads/camera.cpp b/engines/mads/core/camera.cpp
similarity index 97%
rename from engines/mads/camera.cpp
rename to engines/mads/core/camera.cpp
index ccbc5fac94b..f95087bb925 100644
--- a/engines/mads/camera.cpp
+++ b/engines/mads/core/camera.cpp
@@ -19,12 +19,12 @@
*
*/
-#include "mads/mads.h"
-#include "mads/camera.h"
+#include "mads/nebular/nebular.h"
+#include "mads/core/camera.h"
namespace MADS {
-Camera::Camera(MADSEngine *vm) : _vm(vm) {
+Camera::Camera(RexNebularEngine *vm) : _vm(vm) {
_panAllowedFl = false;
_activeFl = false;
_currentFrameFl = false;
diff --git a/engines/mads/camera.h b/engines/mads/core/camera.h
similarity index 89%
rename from engines/mads/camera.h
rename to engines/mads/core/camera.h
index 0ad5413ce67..770fe448ea8 100644
--- a/engines/mads/camera.h
+++ b/engines/mads/core/camera.h
@@ -22,17 +22,17 @@
#ifndef MADS_CAMERA_H
#define MADS_CAMERA_H
-#include "mads/scene.h"
-#include "mads/player.h"
-#include "mads/camera.h"
+#include "mads/core/scene.h"
+#include "mads/core/player.h"
+#include "mads/core/camera.h"
namespace MADS {
-class MADSEngine;
+class RexNebularEngine;
class Camera {
private:
- MADSEngine *_vm;
+ RexNebularEngine *_vm;
public:
bool _panAllowedFl;
@@ -49,7 +49,7 @@ public:
int _direction;
uint32 _timer;
- Camera(MADSEngine *vm);
+ Camera(RexNebularEngine *vm);
void camPanTo(int target);
bool camPan(int16 *picture_view, int16 *player_loc, int display_size, int picture_size);
diff --git a/engines/mads/compression.cpp b/engines/mads/core/compression.cpp
similarity index 97%
rename from engines/mads/compression.cpp
rename to engines/mads/core/compression.cpp
index 7d626d63dd1..c30b7c3a61d 100644
--- a/engines/mads/compression.cpp
+++ b/engines/mads/core/compression.cpp
@@ -19,7 +19,8 @@
*
*/
-#include "mads/compression.h"
+#include "mads/core/compression.h"
+#include "mads/core/resources.h"
namespace MADS {
@@ -44,7 +45,7 @@ MadsPack::MadsPack(Common::SeekableReadStream *stream) {
initialize(stream);
}
-MadsPack::MadsPack(const Common::Path &resourceName, MADSEngine *vm) {
+MadsPack::MadsPack(const Common::Path &resourceName, RexNebularEngine *vm) {
File file(resourceName);
initialize(&file);
file.close();
diff --git a/engines/mads/compression.h b/engines/mads/core/compression.h
similarity index 94%
rename from engines/mads/compression.h
rename to engines/mads/core/compression.h
index 308b69012ab..ca30debe3e8 100644
--- a/engines/mads/compression.h
+++ b/engines/mads/core/compression.h
@@ -23,12 +23,13 @@
#define MADS_COMPRESSION_H
#include "common/memstream.h"
+#include "common/path.h"
#include "common/stream.h"
-#include "mads/mads.h"
-
namespace MADS {
+class RexNebularEngine;
+
enum CompressionType { COMPRESS_NONE = 0, COMPRESS_FAB = 1 };
struct MadsPackEntry {
@@ -50,7 +51,7 @@ private:
public:
static bool isCompressed(Common::SeekableReadStream *stream);
MadsPack(Common::SeekableReadStream *stream);
- MadsPack(const Common::Path &resourceName, MADSEngine *_vm);
+ MadsPack(const Common::Path &resourceName, RexNebularEngine *_vm);
~MadsPack();
int getCount() const { return _count; }
diff --git a/engines/mads/conversations.cpp b/engines/mads/core/conversations.cpp
similarity index 99%
rename from engines/mads/conversations.cpp
rename to engines/mads/core/conversations.cpp
index b03a0dc1f10..b900e0b3bf9 100644
--- a/engines/mads/conversations.cpp
+++ b/engines/mads/core/conversations.cpp
@@ -19,15 +19,15 @@
*
*/
-#include "mads/conversations.h"
-#include "mads/mads.h"
-#include "mads/compression.h"
+#include "mads/core/conversations.h"
+#include "mads/nebular/nebular.h"
+#include "mads/core/compression.h"
#include "common/file.h"
#include "common/util.h" // for Common::hexdump
namespace MADS {
-GameConversations::GameConversations(MADSEngine *vm) : _vm(vm) {
+GameConversations::GameConversations(RexNebularEngine *vm) : _vm(vm) {
_runningConv = nullptr;
_restoreRunning = 0;
_playerEnabled = false;
diff --git a/engines/mads/conversations.h b/engines/mads/core/conversations.h
similarity index 98%
rename from engines/mads/conversations.h
rename to engines/mads/core/conversations.h
index 56e2c4ca0a1..e1811213adc 100644
--- a/engines/mads/conversations.h
+++ b/engines/mads/core/conversations.h
@@ -25,8 +25,8 @@
#include "common/scummsys.h"
#include "common/array.h"
#include "common/str-array.h"
-#include "mads/screen.h"
-#include "mads/dialogs.h"
+#include "mads/core/screen.h"
+#include "mads/core/dialogs.h"
namespace MADS {
@@ -87,6 +87,7 @@ enum ConditionalOperation {
CONDOP_ABORT = 0xff
};
+class RexNebularEngine;
struct ConversationVar {
bool _isPtr;
@@ -308,7 +309,7 @@ class MADSEngine;
*/
class GameConversations {
private:
- MADSEngine *_vm;
+ RexNebularEngine *_vm;
ConversationEntry _conversations[MAX_CONVERSATIONS];
bool _speakerActive[MAX_SPEAKERS];
int _speakerSeries[MAX_SPEAKERS];
@@ -396,7 +397,7 @@ public:
/**
* Constructor
*/
- GameConversations(MADSEngine *vm);
+ GameConversations(RexNebularEngine *vm);
/**
* Destructor
diff --git a/engines/mads/dialogs.cpp b/engines/mads/core/dialogs.cpp
similarity index 96%
rename from engines/mads/dialogs.cpp
rename to engines/mads/core/dialogs.cpp
index 906b7eb574d..191e99de003 100644
--- a/engines/mads/dialogs.cpp
+++ b/engines/mads/core/dialogs.cpp
@@ -22,9 +22,9 @@
#include "common/scummsys.h"
#include "common/config-manager.h"
#include "common/text-to-speech.h"
-#include "mads/mads.h"
-#include "mads/screen.h"
-#include "mads/msurface.h"
+#include "mads/nebular/nebular.h"
+#include "mads/core/screen.h"
+#include "mads/core/msurface.h"
#include "mads/nebular/dialogs_nebular.h"
namespace MADS {
@@ -35,8 +35,7 @@ enum PopupEdge {
EDGE_BOTTOM = 7, EDGE_UPPER_CENTER = 8
};
-Dialog::Dialog(MADSEngine *vm)
- : _vm(vm), _savedSurface(nullptr), _position(Common::Point(-1, -1)),
+Dialog::Dialog(RexNebularEngine *vm) : _vm(vm), _savedSurface(nullptr), _position(Common::Point(-1, -1)),
_width(0), _height(0) {
TEXTDIALOG_CONTENT1 = 0XF8;
TEXTDIALOG_CONTENT2 = 0XF9;
@@ -142,7 +141,7 @@ void Dialog::drawContent(const Common::Rect &r, int seed, byte color1, byte colo
/*------------------------------------------------------------------------*/
-TextDialog::TextDialog(MADSEngine *vm, const Common::String &fontName,
+TextDialog::TextDialog(RexNebularEngine *vm, const Common::String &fontName,
const Common::Point &pos, int maxChars)
: Dialog(vm) {
_font = _vm->_font->getFont(fontName);
@@ -157,7 +156,7 @@ TextDialog::TextDialog(MADSEngine *vm, const Common::String &fontName,
init(maxChars);
}
-TextDialog::TextDialog(MADSEngine *vm, const Common::String &fontName,
+TextDialog::TextDialog(RexNebularEngine *vm, const Common::String &fontName,
const Common::Point &pos, MSurface *portrait, int maxTextChars): Dialog(vm) {
_font = _vm->_font->getFont(fontName);
_position = pos;
@@ -434,7 +433,7 @@ void TextDialog::show() {
/*------------------------------------------------------------------------*/
-MessageDialog::MessageDialog(MADSEngine *vm, int maxChars, ...)
+MessageDialog::MessageDialog(RexNebularEngine *vm, int maxChars, ...)
: TextDialog(vm, FONT_INTERFACE, Common::Point(-1, -1), maxChars) {
// Add in passed line list
va_list va;
@@ -450,7 +449,7 @@ MessageDialog::MessageDialog(MADSEngine *vm, int maxChars, ...)
/*------------------------------------------------------------------------*/
-Dialogs *Dialogs::init(MADSEngine *vm) {
+Dialogs *Dialogs::init(RexNebularEngine *vm) {
switch (vm->getGameID()) {
case GType_RexNebular:
return new Nebular::DialogsNebular(vm);
@@ -468,14 +467,14 @@ Dialogs *Dialogs::init(MADSEngine *vm) {
}
}
-Dialogs::Dialogs(MADSEngine *vm)
+Dialogs::Dialogs(RexNebularEngine *vm)
: _vm(vm) {
_pendingDialog = DIALOG_NONE;
}
/*------------------------------------------------------------------------*/
-FullScreenDialog::FullScreenDialog(MADSEngine *vm) : _vm(vm) {
+FullScreenDialog::FullScreenDialog(RexNebularEngine *vm) : _vm(vm) {
switch (_vm->getGameID()) {
case GType_RexNebular:
_screenId = 990;
diff --git a/engines/mads/dialogs.h b/engines/mads/core/dialogs.h
similarity index 90%
rename from engines/mads/dialogs.h
rename to engines/mads/core/dialogs.h
index aa01afdef6f..581007009a6 100644
--- a/engines/mads/dialogs.h
+++ b/engines/mads/core/dialogs.h
@@ -23,20 +23,22 @@
#define MADS_DIALOGS_H
#include "common/scummsys.h"
-#include "mads/game.h"
-#include "mads/font.h"
-#include "mads/msurface.h"
+#include "mads/core/game.h"
+#include "mads/core/font.h"
+#include "mads/core/msurface.h"
namespace MADS {
#define DIALOG_TOP 22
#define POPUP_CENTER 0x8000
+class RexNebularEngine;
+
class Dialog {
private:
void setDialogPalette();
protected:
- MADSEngine *_vm;
+ RexNebularEngine *_vm;
MSurface *_savedSurface;
Common::Point _position;
int _width;
@@ -80,7 +82,7 @@ public:
/**
* Constructor
*/
- Dialog(MADSEngine *vm);
+ Dialog(RexNebularEngine *vm);
/**
* Destructor
@@ -142,8 +144,8 @@ public:
* @param pos Position for window top-left
* @param maxChars Horizontal width of window in characters
*/
- TextDialog(MADSEngine *vm, const Common::String &fontName, const Common::Point &pos,
- int maxChars);
+ TextDialog(RexNebularEngine *vm, const Common::String &fontName,
+ const Common::Point &pos, int maxChars);
/**
* Constructor
@@ -153,7 +155,7 @@ public:
* @param portrait Speaker portrait to show in dialog
* @param maxTextChars Horizontal width of text portion of window in characters
*/
- TextDialog(MADSEngine *vm, const Common::String &fontName, const Common::Point &pos,
+ TextDialog(RexNebularEngine *vm, const Common::String &fontName, const Common::Point &pos,
MSurface *portrait, int maxTextChars);
/**
@@ -221,7 +223,7 @@ public:
class MessageDialog : public TextDialog {
public:
- MessageDialog(MADSEngine *vm, int lines, ...);
+ MessageDialog(RexNebularEngine *vm, int lines, ...);
~MessageDialog() override {}
};
@@ -235,11 +237,11 @@ enum DialogId {
class Dialogs {
protected:
- MADSEngine *_vm;
+ RexNebularEngine *_vm;
- Dialogs(MADSEngine *vm);
+ Dialogs(RexNebularEngine *vm);
public:
- static Dialogs *init(MADSEngine *vm);
+ static Dialogs *init(RexNebularEngine *vm);
public:
Common::Point _defaultPosition;
DialogId _pendingDialog;
@@ -263,7 +265,7 @@ protected:
/**
* Engine reference
*/
- MADSEngine *_vm;
+ RexNebularEngine *_vm;
/**
* Screen/scene to show background from
@@ -283,7 +285,7 @@ public:
/**
* Constructor
*/
- FullScreenDialog(MADSEngine *vm);
+ FullScreenDialog(RexNebularEngine *vm);
~FullScreenDialog() override;
};
diff --git a/engines/mads/events.cpp b/engines/mads/core/events.cpp
similarity index 97%
rename from engines/mads/events.cpp
rename to engines/mads/core/events.cpp
index 1bac7100d44..a456acaa548 100644
--- a/engines/mads/events.cpp
+++ b/engines/mads/core/events.cpp
@@ -23,13 +23,13 @@
#include "graphics/cursorman.h"
#include "common/events.h"
#include "engines/util.h"
-#include "mads/mads.h"
-#include "mads/events.h"
-#include "mads/scene.h"
+#include "mads/nebular/nebular.h"
+#include "mads/core/events.h"
+#include "mads/core/scene.h"
namespace MADS {
-EventsManager::EventsManager(MADSEngine *vm) {
+EventsManager::EventsManager(RexNebularEngine *vm) {
_vm = vm;
_cursorSprites = nullptr;
_cursorId = CURSOR_NONE;
diff --git a/engines/mads/events.h b/engines/mads/core/events.h
similarity index 96%
rename from engines/mads/events.h
rename to engines/mads/core/events.h
index 401a2f25e04..60d22b85ab5 100644
--- a/engines/mads/events.h
+++ b/engines/mads/core/events.h
@@ -25,8 +25,8 @@
#include "common/scummsys.h"
#include "common/events.h"
#include "common/stack.h"
-#include "mads/assets.h"
-#include "mads/sprites.h"
+#include "mads/core/assets.h"
+#include "mads/core/sprites.h"
namespace MADS {
@@ -36,7 +36,7 @@ enum CursorType { CURSOR_NONE = 0, CURSOR_ARROW = 1, CURSOR_WAIT = 2, CURSOR_GO_
#define GAME_FRAME_RATE 50
#define GAME_FRAME_TIME (1000 / GAME_FRAME_RATE)
-class MADSEngine;
+class RexNebularEngine;
class EventTarget {
public:
@@ -46,7 +46,7 @@ public:
class EventsManager {
private:
- MADSEngine *_vm;
+ RexNebularEngine *_vm;
uint32 _frameCounter;
uint32 _priorFrameTime;
Common::Point _mousePos;
@@ -75,7 +75,7 @@ public:
/**
* Constructor
*/
- EventsManager(MADSEngine *vm);
+ EventsManager(RexNebularEngine *vm);
/**
* Destructor
diff --git a/engines/mads/font.cpp b/engines/mads/core/font.cpp
similarity index 96%
rename from engines/mads/font.cpp
rename to engines/mads/core/font.cpp
index 4af3e46f61e..5dc28e4b65c 100644
--- a/engines/mads/font.cpp
+++ b/engines/mads/core/font.cpp
@@ -20,20 +20,20 @@
*/
#include "common/scummsys.h"
-#include "mads/mads.h"
-#include "mads/compression.h"
-#include "mads/font.h"
-#include "mads/msurface.h"
+#include "mads/nebular/nebular.h"
+#include "mads/core/compression.h"
+#include "mads/core/font.h"
+#include "mads/core/msurface.h"
namespace MADS {
-MADSEngine *Font::_vm;
+RexNebularEngine *Font::_vm;
Common::HashMap<Common::String, Font *> *Font::_fonts;
uint8 Font::_fontColors[4];
-void Font::init(MADSEngine *vm) {
+void Font::init(RexNebularEngine *vm) {
_vm = vm;
_fontColors[0] = 0xFF;
_fontColors[1] = 0xF;
diff --git a/engines/mads/font.h b/engines/mads/core/font.h
similarity index 96%
rename from engines/mads/font.h
rename to engines/mads/core/font.h
index 2b0eec088d3..cd405892200 100644
--- a/engines/mads/font.h
+++ b/engines/mads/core/font.h
@@ -26,7 +26,7 @@
#include "common/hashmap.h"
#include "common/endian.h"
#include "common/util.h"
-#include "mads/msurface.h"
+#include "mads/core/msurface.h"
namespace MADS {
@@ -47,13 +47,13 @@ class MADSEngine;
class Font {
private:
static uint8 _fontColors[4];
- static MADSEngine *_vm;
+ static RexNebularEngine *_vm;
static Common::HashMap<Common::String, Font *> *_fonts;
public:
/**
* Initialize the font system
*/
- static void init(MADSEngine *vm);
+ static void init(RexNebularEngine *vm);
/**
* Free up the resources used by the font
diff --git a/engines/mads/game.cpp b/engines/mads/core/game.cpp
similarity index 98%
rename from engines/mads/game.cpp
rename to engines/mads/core/game.cpp
index 81ce50fce6c..6c3f91dafb0 100644
--- a/engines/mads/game.cpp
+++ b/engines/mads/core/game.cpp
@@ -25,14 +25,14 @@
#include "common/serializer.h"
#include "graphics/scaler.h"
#include "graphics/thumbnail.h"
-#include "mads/mads.h"
-#include "mads/compression.h"
-#include "mads/game.h"
-#include "mads/game_data.h"
-#include "mads/events.h"
-#include "mads/screen.h"
-#include "mads/msurface.h"
-#include "mads/resources.h"
+#include "mads/nebular/nebular.h"
+#include "mads/core/compression.h"
+#include "mads/core/game.h"
+#include "mads/core/game_data.h"
+#include "mads/core/events.h"
+#include "mads/core/screen.h"
+#include "mads/core/msurface.h"
+#include "mads/core/resources.h"
#include "mads/nebular/game_nebular.h"
#ifdef ENABLE_MADSV2
#include "mads/dragonsphere/game_dragonsphere.h"
@@ -41,7 +41,7 @@
namespace MADS {
-Game *Game::init(MADSEngine *vm) {
+Game *Game::init(RexNebularEngine *vm) {
switch (vm->getGameID()) {
case GType_RexNebular:
return new Nebular::GameNebular(vm);
@@ -60,7 +60,7 @@ Game *Game::init(MADSEngine *vm) {
return nullptr;
}
-Game::Game(MADSEngine *vm)
+Game::Game(RexNebularEngine *vm)
: _vm(vm), _surface(nullptr), _objects(vm), _scene(vm), _screenObjects(vm), _player(vm), _camX(vm), _camY(vm) {
_sectionNumber = 1;
_priorSectionNumber = 0;
diff --git a/engines/mads/game.h b/engines/mads/core/game.h
similarity index 93%
rename from engines/mads/game.h
rename to engines/mads/core/game.h
index e0e9afe3ae9..a205be9f551 100644
--- a/engines/mads/game.h
+++ b/engines/mads/core/game.h
@@ -26,18 +26,18 @@
#include "common/savefile.h"
#include "common/str-array.h"
#include "common/serializer.h"
-#include "mads/audio.h"
-#include "mads/scene.h"
-#include "mads/game_data.h"
-#include "mads/globals.h"
-#include "mads/inventory.h"
-#include "mads/player.h"
-#include "mads/screen.h"
-#include "mads/camera.h"
+#include "mads/core/audio.h"
+#include "mads/core/scene.h"
+#include "mads/core/game_data.h"
+#include "mads/core/globals.h"
+#include "mads/core/inventory.h"
+#include "mads/core/player.h"
+#include "mads/core/screen.h"
+#include "mads/core/camera.h"
namespace MADS {
-class MADSEngine;
+class RexNebularEngine;
enum KernelMode {
KERNEL_GAME_LOAD = 0, KERNEL_SECTION_PRELOAD = 1, KERNEL_SECTION_INIT = 2,
@@ -77,7 +77,7 @@ private:
*/
void loadQuotes();
protected:
- MADSEngine *_vm;
+ RexNebularEngine *_vm;
MSurface *_surface;
int _statusFlag;
Common::StringArray _quotes;
@@ -92,7 +92,7 @@ protected:
/**
* Constructor
*/
- Game(MADSEngine *vm);
+ Game(RexNebularEngine *vm);
/**
* Initializes the current section number of the game
@@ -125,7 +125,7 @@ protected:
//@}
public:
- static Game *init(MADSEngine *vm);
+ static Game *init(RexNebularEngine *vm);
public:
Player _player;
diff --git a/engines/mads/game_data.cpp b/engines/mads/core/game_data.cpp
similarity index 91%
rename from engines/mads/game_data.cpp
rename to engines/mads/core/game_data.cpp
index b83df78c7f9..9c6e736c9a5 100644
--- a/engines/mads/game_data.cpp
+++ b/engines/mads/core/game_data.cpp
@@ -20,12 +20,12 @@
*/
#include "common/scummsys.h"
-#include "mads/mads.h"
-#include "mads/game.h"
+#include "mads/nebular/nebular.h"
+#include "mads/core/game.h"
#include "mads/nebular/game_nebular.h"
-#include "mads/screen.h"
-#include "mads/msurface.h"
-#include "mads/resources.h"
+#include "mads/core/screen.h"
+#include "mads/core/msurface.h"
+#include "mads/core/resources.h"
namespace MADS {
diff --git a/engines/mads/game_data.h b/engines/mads/core/game_data.h
similarity index 93%
rename from engines/mads/game_data.h
rename to engines/mads/core/game_data.h
index 56d4ce21702..ed4e3cff523 100644
--- a/engines/mads/game_data.h
+++ b/engines/mads/core/game_data.h
@@ -24,11 +24,11 @@
#include "common/scummsys.h"
#include "common/array.h"
-#include "mads/resources.h"
+#include "mads/core/resources.h"
namespace MADS {
-class MADSEngine;
+class RexNebularEngine;
class Game;
class VisitedScenes : public SynchronizedList {
@@ -56,9 +56,9 @@ public:
class SectionHandler {
protected:
- MADSEngine *_vm;
+ RexNebularEngine *_vm;
public:
- SectionHandler(MADSEngine *vm) : _vm(vm) {}
+ SectionHandler(RexNebularEngine *vm) : _vm(vm) {}
virtual ~SectionHandler() {}
virtual void preLoadSection() = 0;
diff --git a/engines/mads/globals.cpp b/engines/mads/core/globals.cpp
similarity index 97%
rename from engines/mads/globals.cpp
rename to engines/mads/core/globals.cpp
index 108779a515c..a23826abb1a 100644
--- a/engines/mads/globals.cpp
+++ b/engines/mads/core/globals.cpp
@@ -20,7 +20,7 @@
*/
#include "common/scummsys.h"
-#include "mads/globals.h"
+#include "mads/core/globals.h"
namespace MADS {
diff --git a/engines/mads/globals.h b/engines/mads/core/globals.h
similarity index 97%
rename from engines/mads/globals.h
rename to engines/mads/core/globals.h
index 1e67b4f622b..9a06d4d5e84 100644
--- a/engines/mads/globals.h
+++ b/engines/mads/core/globals.h
@@ -25,7 +25,7 @@
#include "common/scummsys.h"
#include "common/array.h"
#include "common/serializer.h"
-#include "mads/resources.h"
+#include "mads/core/resources.h"
namespace MADS {
diff --git a/engines/mads/hotspots.cpp b/engines/mads/core/hotspots.cpp
similarity index 98%
rename from engines/mads/hotspots.cpp
rename to engines/mads/core/hotspots.cpp
index a50707ff9b5..d127e6ad345 100644
--- a/engines/mads/hotspots.cpp
+++ b/engines/mads/core/hotspots.cpp
@@ -19,8 +19,8 @@
*
*/
-#include "mads/mads.h"
-#include "mads/hotspots.h"
+#include "mads/nebular/nebular.h"
+#include "mads/core/hotspots.h"
namespace MADS {
@@ -43,7 +43,7 @@ void DynamicHotspot::synchronize(Common::Serializer &s) {
/*------------------------------------------------------------------------*/
-DynamicHotspots::DynamicHotspots(MADSEngine *vm) : _vm(vm) {
+DynamicHotspots::DynamicHotspots(RexNebularEngine *vm) : _vm(vm) {
for (int i = 0; i < DYNAMIC_HOTSPOTS_SIZE; ++i) {
DynamicHotspot rec;
rec._active = false;
diff --git a/engines/mads/hotspots.h b/engines/mads/core/hotspots.h
similarity index 93%
rename from engines/mads/hotspots.h
rename to engines/mads/core/hotspots.h
index 62f27d611da..d08aa651cf5 100644
--- a/engines/mads/hotspots.h
+++ b/engines/mads/core/hotspots.h
@@ -23,12 +23,12 @@
#define MADS_HOTSPOTS_H
#include "common/scummsys.h"
-#include "mads/events.h"
-#include "mads/player.h"
+#include "mads/core/events.h"
+#include "mads/core/player.h"
namespace MADS {
-class MADSEngine;
+class RexNebularEngine;
class DynamicHotspot {
public:
@@ -70,13 +70,13 @@ public:
class DynamicHotspots {
private:
- MADSEngine *_vm;
+ RexNebularEngine *_vm;
Common::Array<DynamicHotspot> _entries;
int _count;
public:
bool _changed;
public:
- DynamicHotspots(MADSEngine *vm);
+ DynamicHotspots(RexNebularEngine *vm);
Common::Array<MADS::DynamicHotspot>::size_type size() const { return _entries.size(); }
DynamicHotspot &operator[](uint idx) { return _entries[idx]; }
@@ -119,9 +119,9 @@ public:
class Hotspots : public Common::Array<Hotspot> {
private:
- MADSEngine *_vm;
+ RexNebularEngine *_vm;
public:
- Hotspots(MADSEngine *vm) : _vm(vm) {}
+ Hotspots(RexNebularEngine *vm) : _vm(vm) {}
/**
* Sets the active state of a given hotspot
diff --git a/engines/mads/inventory.cpp b/engines/mads/core/inventory.cpp
similarity index 98%
rename from engines/mads/inventory.cpp
rename to engines/mads/core/inventory.cpp
index e7eb1328dc0..18216959034 100644
--- a/engines/mads/inventory.cpp
+++ b/engines/mads/core/inventory.cpp
@@ -20,8 +20,8 @@
*/
#include "common/scummsys.h"
-#include "mads/mads.h"
-#include "mads/inventory.h"
+#include "mads/nebular/nebular.h"
+#include "mads/core/inventory.h"
namespace MADS {
diff --git a/engines/mads/inventory.h b/engines/mads/core/inventory.h
similarity index 95%
rename from engines/mads/inventory.h
rename to engines/mads/core/inventory.h
index ba145fdb8d2..cf703dbc7d4 100644
--- a/engines/mads/inventory.h
+++ b/engines/mads/core/inventory.h
@@ -25,6 +25,7 @@
#include "common/scummsys.h"
#include "common/array.h"
#include "common/serializer.h"
+#include "mads/core/resources.h"
namespace MADS {
@@ -32,7 +33,7 @@ enum {
PLAYER_INVENTORY = 2, NOWHERE = 1
};
-class MADSEngine;
+class RexNebularEngine;
#define MAX_VOCAB 5
#define MAX_QUALITIES 4
@@ -78,7 +79,7 @@ public:
class InventoryObjects : public Common::Array<InventoryObject> {
private:
- MADSEngine *_vm;
+ RexNebularEngine *_vm;
public:
SynchronizedList _inventoryList;
@@ -86,7 +87,7 @@ public:
/**
* Constructor
*/
- InventoryObjects(MADSEngine *vm) : _vm(vm) {}
+ InventoryObjects(RexNebularEngine *vm) : _vm(vm) {}
/**
* Loads the game's object list
diff --git a/engines/mads/menu_views.cpp b/engines/mads/core/menu_views.cpp
similarity index 97%
rename from engines/mads/menu_views.cpp
rename to engines/mads/core/menu_views.cpp
index 0ce4072fc34..473e3522e2a 100644
--- a/engines/mads/menu_views.cpp
+++ b/engines/mads/core/menu_views.cpp
@@ -20,16 +20,16 @@
*/
#include "common/scummsys.h"
-#include "mads/game.h"
-#include "mads/mads.h"
-#include "mads/menu_views.h"
-#include "mads/resources.h"
-#include "mads/scene.h"
-#include "mads/screen.h"
+#include "mads/core/game.h"
+#include "mads/nebular/nebular.h"
+#include "mads/core/menu_views.h"
+#include "mads/core/resources.h"
+#include "mads/core/scene.h"
+#include "mads/core/screen.h"
namespace MADS {
-MenuView::MenuView(MADSEngine *vm) : FullScreenDialog(vm) {
+MenuView::MenuView(RexNebularEngine *vm) : FullScreenDialog(vm) {
_breakFlag = false;
_redrawFlag = true;
_palFlag = false;
@@ -97,13 +97,13 @@ char TextView::_resourceName[100];
#define TV_NUM_FADE_STEPS 40
#define TV_FADE_DELAY_MILLI 50
-void TextView::execute(MADSEngine *vm, const Common::Path &resName) {
+void TextView::execute(RexNebularEngine *vm, const Common::Path &resName) {
assert(resName.toString('/').size() < 100);
Common::strlcpy(_resourceName, resName.toString('/').c_str(), sizeof(_resourceName));
vm->_dialogs->_pendingDialog = DIALOG_TEXTVIEW;
}
-TextView::TextView(MADSEngine *vm) : MenuView(vm) {
+TextView::TextView(RexNebularEngine *vm) : MenuView(vm) {
_animating = false;
_panSpeed = 0;
_spareScreen = nullptr;
@@ -455,13 +455,13 @@ void TextView::scriptDone() {
char AnimationView::_resourceName[100];
-void AnimationView::execute(MADSEngine *vm, const Common::Path &resName) {
+void AnimationView::execute(RexNebularEngine *vm, const Common::Path &resName) {
assert(resName.toString('/').size() < 100);
Common::strlcpy(_resourceName, resName.toString('/').c_str(), sizeof(_resourceName));
vm->_dialogs->_pendingDialog = DIALOG_ANIMVIEW;
}
-AnimationView::AnimationView(MADSEngine *vm) : MenuView(vm) {
+AnimationView::AnimationView(RexNebularEngine *vm) : MenuView(vm) {
_redrawFlag = false;
_soundDriverLoaded = false;
diff --git a/engines/mads/menu_views.h b/engines/mads/core/menu_views.h
similarity index 92%
rename from engines/mads/menu_views.h
rename to engines/mads/core/menu_views.h
index 63603ec0dfb..77378e31063 100644
--- a/engines/mads/menu_views.h
+++ b/engines/mads/core/menu_views.h
@@ -23,13 +23,13 @@
#define MADS_MENU_VIEWS_H
#include "common/scummsys.h"
-#include "mads/dialogs.h"
-#include "mads/game.h"
-#include "mads/msurface.h"
+#include "mads/core/dialogs.h"
+#include "mads/core/game.h"
+#include "mads/core/msurface.h"
namespace MADS {
-class MADSEngine;
+class RexNebularEngine;
class MenuView: public FullScreenDialog {
protected:
@@ -46,7 +46,7 @@ protected:
*/
bool onEvent(Common::Event &event) override;
public:
- MenuView(MADSEngine *vm);
+ MenuView(RexNebularEngine *vm);
~MenuView() override {}
@@ -125,9 +125,9 @@ public:
/**
* Queue the given text resource for display
*/
- static void execute(MADSEngine *vm, const Common::Path &resName);
+ static void execute(RexNebularEngine *vm, const Common::Path &resName);
- TextView(MADSEngine *vm);
+ TextView(RexNebularEngine *vm);
~TextView() override;
};
@@ -220,9 +220,9 @@ public:
/**
* Queue the given text resource for display
*/
- static void execute(MADSEngine *vm, const Common::Path &resName);
+ static void execute(RexNebularEngine *vm, const Common::Path &resName);
- AnimationView(MADSEngine *vm);
+ AnimationView(RexNebularEngine *vm);
~AnimationView() override;
};
diff --git a/engines/mads/messages.cpp b/engines/mads/core/messages.cpp
similarity index 98%
rename from engines/mads/messages.cpp
rename to engines/mads/core/messages.cpp
index 483dc5d2a91..09f8bcb50e9 100644
--- a/engines/mads/messages.cpp
+++ b/engines/mads/core/messages.cpp
@@ -20,11 +20,11 @@
*/
#include "common/scummsys.h"
-#include "mads/mads.h"
-#include "mads/font.h"
-#include "mads/screen.h"
-#include "mads/messages.h"
-#include "mads/scene_data.h"
+#include "mads/nebular/nebular.h"
+#include "mads/core/font.h"
+#include "mads/core/screen.h"
+#include "mads/core/messages.h"
+#include "mads/core/scene_data.h"
namespace MADS {
@@ -44,7 +44,7 @@ void RandomMessages::reset() {
}
-KernelMessages::KernelMessages(MADSEngine *vm)
+KernelMessages::KernelMessages(RexNebularEngine *vm)
: _vm(vm) {
for (int i = 0; i < KERNEL_MESSAGES_SIZE; ++i) {
KernelMessage rec;
@@ -492,7 +492,7 @@ TextDisplay::TextDisplay() {
/*------------------------------------------------------------------------*/
-TextDisplayList::TextDisplayList(MADSEngine *vm) : _vm(vm) {
+TextDisplayList::TextDisplayList(RexNebularEngine *vm) : _vm(vm) {
for (int i = 0; i < TEXT_DISPLAY_SIZE; ++i) {
TextDisplay rec;
rec._active = false;
diff --git a/engines/mads/messages.h b/engines/mads/core/messages.h
similarity index 94%
rename from engines/mads/messages.h
rename to engines/mads/core/messages.h
index 34b9cc3c16d..9129bb77382 100644
--- a/engines/mads/messages.h
+++ b/engines/mads/core/messages.h
@@ -24,9 +24,9 @@
#include "common/scummsys.h"
#include "common/array.h"
-#include "mads/action.h"
-#include "mads/font.h"
-#include "mads/msurface.h"
+#include "mads/core/action.h"
+#include "mads/core/font.h"
+#include "mads/core/msurface.h"
namespace MADS {
@@ -41,7 +41,7 @@ enum KernelMessageFlags {
KMSG_ACTIVE = 0x80, KMSG_ANIM = 0x100
};
-class MADSEngine;
+class RexNebularEngine;
class KernelMessage {
public:
@@ -86,7 +86,7 @@ public:
class KernelMessages {
private:
- MADSEngine *_vm;
+ RexNebularEngine *_vm;
Common::Array<int> _randomQuotes;
RandomMessages _randomMessages;
@@ -94,7 +94,7 @@ public:
Common::Array<KernelMessage> _entries;
Font *_talkFont;
public:
- KernelMessages(MADSEngine *vm);
+ KernelMessages(RexNebularEngine *vm);
~KernelMessages();
void clear();
@@ -149,9 +149,9 @@ public:
class TextDisplayList : public Common::Array<TextDisplay> {
private:
- MADSEngine *_vm;
+ RexNebularEngine *_vm;
public:
- TextDisplayList(MADSEngine *vm);
+ TextDisplayList(RexNebularEngine *vm);
/**
* Expire a given text display entry
diff --git a/engines/mads/mps_installer.cpp b/engines/mads/core/mps_installer.cpp
similarity index 99%
rename from engines/mads/mps_installer.cpp
rename to engines/mads/core/mps_installer.cpp
index 169948ddb1e..7e6dd29ed8d 100644
--- a/engines/mads/mps_installer.cpp
+++ b/engines/mads/core/mps_installer.cpp
@@ -26,7 +26,7 @@
#include "common/util.h"
#include "common/memstream.h"
#include "common/compression/dcl.h"
-#include "mads/mps_installer.h"
+#include "mads/core/mps_installer.h"
namespace MADS {
diff --git a/engines/mads/mps_installer.h b/engines/mads/core/mps_installer.h
similarity index 100%
rename from engines/mads/mps_installer.h
rename to engines/mads/core/mps_installer.h
diff --git a/engines/mads/msurface.cpp b/engines/mads/core/msurface.cpp
similarity index 98%
rename from engines/mads/msurface.cpp
rename to engines/mads/core/msurface.cpp
index 5b2e0fda5c2..173025db288 100644
--- a/engines/mads/msurface.cpp
+++ b/engines/mads/core/msurface.cpp
@@ -20,16 +20,16 @@
*/
#include "engines/util.h"
-#include "mads/compression.h"
-#include "mads/screen.h"
-#include "mads/mads.h"
-#include "mads/msurface.h"
-#include "mads/resources.h"
-#include "mads/sprites.h"
+#include "mads/core/compression.h"
+#include "mads/core/screen.h"
+#include "mads/nebular/nebular.h"
+#include "mads/core/msurface.h"
+#include "mads/core/resources.h"
+#include "mads/core/sprites.h"
namespace MADS {
-MADSEngine *BaseSurface::_vm = nullptr;
+RexNebularEngine *BaseSurface::_vm = nullptr;
int BaseSurface::scaleValue(int value, int scale, int err) {
int scaled = 0;
diff --git a/engines/mads/msurface.h b/engines/mads/core/msurface.h
similarity index 97%
rename from engines/mads/msurface.h
rename to engines/mads/core/msurface.h
index 25f60dd7f8f..b9e1802ed3e 100644
--- a/engines/mads/msurface.h
+++ b/engines/mads/core/msurface.h
@@ -26,11 +26,11 @@
#include "common/path.h"
#include "common/rect.h"
#include "graphics/screen.h"
-#include "mads/palette.h"
+#include "mads/core/palette.h"
namespace MADS {
-class MADSEngine;
+class RexNebularEngine;
class MSprite;
class DepthSurface;
@@ -59,12 +59,12 @@ private:
*/
int scaleValue(int value, int scale, int err);
protected:
- static MADSEngine *_vm;
+ static RexNebularEngine *_vm;
public:
/**
* Sets the engine reference used all surfaces
*/
- static void setVm(MADSEngine *vm) { _vm = vm; }
+ static void setVm(RexNebularEngine *vm) { _vm = vm; }
/**
* Base method for descendents to load their contents
diff --git a/engines/mads/palette.cpp b/engines/mads/core/palette.cpp
similarity index 98%
rename from engines/mads/palette.cpp
rename to engines/mads/core/palette.cpp
index 1f22fe1206e..0b3a7370b9f 100644
--- a/engines/mads/palette.cpp
+++ b/engines/mads/core/palette.cpp
@@ -23,9 +23,9 @@
#include "engines/util.h"
#include "graphics/palette.h"
#include "graphics/paletteman.h"
-#include "mads/mads.h"
-#include "mads/msurface.h"
-#include "mads/staticres.h"
+#include "mads/nebular/nebular.h"
+#include "mads/core/msurface.h"
+#include "mads/core/staticres.h"
namespace MADS {
@@ -40,7 +40,7 @@ void RGB6::load(Common::SeekableReadStream *f) {
/*------------------------------------------------------------------------*/
-PaletteUsage::PaletteUsage(MADSEngine *vm) {
+PaletteUsage::PaletteUsage(RexNebularEngine *vm) {
_vm = vm;
_data = nullptr;
}
@@ -396,7 +396,7 @@ void RGBList::copy(RGBList &src) {
/*------------------------------------------------------------------------*/
-Fader::Fader(MADSEngine *vm)
+Fader::Fader(RexNebularEngine *vm)
: _vm(vm) {
_colorFlags[0] = _colorFlags[1] = _colorFlags[2] = true;
_colorFlags[3] = false;
@@ -701,7 +701,7 @@ int Fader::rgbMerge(byte r, byte g, byte b) {
/*------------------------------------------------------------------------*/
-Palette::Palette(MADSEngine *vm) : Fader(vm), _paletteUsage(vm) {
+Palette::Palette(RexNebularEngine *vm) : Fader(vm), _paletteUsage(vm) {
_lockFl = false;
_lowRange = 0;
_highRange = 0;
diff --git a/engines/mads/palette.h b/engines/mads/core/palette.h
similarity index 97%
rename from engines/mads/palette.h
rename to engines/mads/core/palette.h
index 97dd076bd50..8f4f03d6bfa 100644
--- a/engines/mads/palette.h
+++ b/engines/mads/core/palette.h
@@ -27,7 +27,7 @@
namespace MADS {
-class MADSEngine;
+class RexNebularEngine;
#define PALETTE_USAGE_COUNT 4
@@ -89,7 +89,7 @@ public:
UsageRange(byte v1, byte v2) { _v1 = v1; _v2 = v2; }
};
private:
- MADSEngine *_vm;
+ RexNebularEngine *_vm;
Common::Array<UsageEntry> *_data;
int getGamePalFreeIndex(int *palIndex);
@@ -101,7 +101,7 @@ public:
/**
* Constructor
*/
- PaletteUsage(MADSEngine *vm);
+ PaletteUsage(RexNebularEngine *vm);
void load(Common::Array<UsageEntry> *data);
@@ -188,7 +188,7 @@ private:
*/
void insertionSort(int size, byte *id, byte *value);
protected:
- MADSEngine *_vm;
+ RexNebularEngine *_vm;
byte _rgb64Map[PALETTE_COUNT];
public:
bool _colorFlags[4];
@@ -197,7 +197,7 @@ public:
/**
* Constructor
*/
- Fader(MADSEngine *vm);
+ Fader(RexNebularEngine *vm);
/**
* Sets a new palette
@@ -264,7 +264,7 @@ public:
/**
* Constructor
*/
- Palette(MADSEngine *vm);
+ Palette(RexNebularEngine *vm);
/**
* Destructor
diff --git a/engines/mads/player.cpp b/engines/mads/core/player.cpp
similarity index 99%
rename from engines/mads/player.cpp
rename to engines/mads/core/player.cpp
index a6b2d8e4915..694a61f199d 100644
--- a/engines/mads/player.cpp
+++ b/engines/mads/core/player.cpp
@@ -20,8 +20,8 @@
*/
#include "common/scummsys.h"
-#include "mads/mads.h"
-#include "mads/player.h"
+#include "mads/nebular/nebular.h"
+#include "mads/core/player.h"
namespace MADS {
@@ -59,8 +59,7 @@ void StopWalkers::synchronize(Common::Serializer &s) {
/*------------------------------------------------------------------------*/
-Player::Player(MADSEngine *vm)
- : _vm(vm) {
+Player::Player(RexNebularEngine *vm) : _vm(vm) {
_action = nullptr;
_facing = FACING_NORTH;
_turnToFacing = FACING_NORTH;
diff --git a/engines/mads/player.h b/engines/mads/core/player.h
similarity index 98%
rename from engines/mads/player.h
rename to engines/mads/core/player.h
index 48bd77384df..8d7b14cb80c 100644
--- a/engines/mads/player.h
+++ b/engines/mads/core/player.h
@@ -28,7 +28,7 @@
namespace MADS {
-class MADSEngine;
+class RexNebularEngine;
class MADSAction;
#define PLAYER_SPRITES_FILE_COUNT 8
@@ -65,7 +65,7 @@ class Player {
private:
static const int _directionListIndexes[32];
private:
- MADSEngine *_vm;
+ RexNebularEngine *_vm;
bool _highSprites;
bool _spriteSetsPresent[PLAYER_SPRITES_FILE_COUNT];
bool _mirror;
@@ -162,7 +162,7 @@ public:
ActionDetails _walkTriggerAction;
StopWalkers _stopWalkers;
public:
- Player(MADSEngine *vm);
+ Player(RexNebularEngine *vm);
/**
* Load sprites for the player
diff --git a/engines/mads/rails.cpp b/engines/mads/core/rails.cpp
similarity index 99%
rename from engines/mads/rails.cpp
rename to engines/mads/core/rails.cpp
index cbca3ab61bc..83e0b6da9d7 100644
--- a/engines/mads/rails.cpp
+++ b/engines/mads/core/rails.cpp
@@ -20,8 +20,8 @@
*/
#include "common/scummsys.h"
-#include "mads/mads.h"
-#include "mads/rails.h"
+#include "mads/nebular/nebular.h"
+#include "mads/core/rails.h"
namespace MADS {
diff --git a/engines/mads/rails.h b/engines/mads/core/rails.h
similarity index 99%
rename from engines/mads/rails.h
rename to engines/mads/core/rails.h
index 6575ea86df3..0e017602d1a 100644
--- a/engines/mads/rails.h
+++ b/engines/mads/core/rails.h
@@ -27,7 +27,7 @@
#include "common/rect.h"
#include "common/serializer.h"
#include "common/stack.h"
-#include "mads/msurface.h"
+#include "mads/core/msurface.h"
namespace MADS {
diff --git a/engines/mads/resources.cpp b/engines/mads/core/resources.cpp
similarity index 97%
rename from engines/mads/resources.cpp
rename to engines/mads/core/resources.cpp
index 29d3240e13a..d210eb71c76 100644
--- a/engines/mads/resources.cpp
+++ b/engines/mads/core/resources.cpp
@@ -22,8 +22,8 @@
#include "common/scummsys.h"
#include "common/archive.h"
#include "common/textconsole.h"
-#include "mads/mads.h"
-#include "mads/resources.h"
+#include "mads/nebular/nebular.h"
+#include "mads/core/resources.h"
namespace MADS {
@@ -60,7 +60,7 @@ private:
/**
* Load the index of all the game's HAG files
*/
- void loadIndex(MADSEngine *vm);
+ void loadIndex(RexNebularEngine *vm);
/**
* Given a resource name, opens up the correct HAG file and returns whether
@@ -78,7 +78,7 @@ private:
*/
ResourceType getResourceType(const Common::String &resourceName) const;
public:
- explicit HagArchive(MADSEngine *vm);
+ explicit HagArchive(RexNebularEngine *vm);
~HagArchive() override;
// Archive implementation
@@ -90,7 +90,7 @@ public:
const char *const MADSCONCAT_STRING = "MADSCONCAT";
-HagArchive::HagArchive(MADSEngine *vm) {
+HagArchive::HagArchive(RexNebularEngine *vm) {
loadIndex(vm);
}
@@ -146,7 +146,7 @@ Common::SeekableReadStream *HagArchive::createReadStreamForMember(const Common::
return nullptr;
}
-void HagArchive::loadIndex(MADSEngine *vm) {
+void HagArchive::loadIndex(RexNebularEngine *vm) {
Common::File hagFile;
for (int sectionIndex = -1; sectionIndex < 11; ++sectionIndex) {
@@ -309,7 +309,7 @@ ResourceType HagArchive::getResourceType(const Common::String &resourceName) con
/*------------------------------------------------------------------------*/
-void Resources::init(MADSEngine *vm) {
+void Resources::init(RexNebularEngine *vm) {
SearchMan.add("HAG", new HagArchive(vm));
}
diff --git a/engines/mads/resources.h b/engines/mads/core/resources.h
similarity index 97%
rename from engines/mads/resources.h
rename to engines/mads/core/resources.h
index 3fd867a8481..0ab7a788415 100644
--- a/engines/mads/resources.h
+++ b/engines/mads/core/resources.h
@@ -29,7 +29,7 @@
namespace MADS {
-class MADSEngine;
+class RexNebularEngine;
enum RESPREFIX {
RESPREFIX_GL = 1, RESPREFIX_SC = 2, RESPREFIX_RM = 3
@@ -45,7 +45,7 @@ public:
/**
* Instantiates the resource manager
*/
- static void init(MADSEngine *vm);
+ static void init(RexNebularEngine *vm);
static Common::Path formatName(RESPREFIX resType, int id, const Common::String &ext);
static Common::Path formatName(int prefix, char asciiCh, int id,
diff --git a/engines/mads/scene.cpp b/engines/mads/core/scene.cpp
similarity index 99%
rename from engines/mads/scene.cpp
rename to engines/mads/core/scene.cpp
index b7ff38fb7a6..8d150337c4e 100644
--- a/engines/mads/scene.cpp
+++ b/engines/mads/core/scene.cpp
@@ -20,10 +20,10 @@
*/
#include "common/scummsys.h"
-#include "mads/scene.h"
-#include "mads/compression.h"
-#include "mads/mads.h"
-#include "mads/audio.h"
+#include "mads/core/scene.h"
+#include "mads/core/compression.h"
+#include "mads/nebular/nebular.h"
+#include "mads/core/audio.h"
#include "mads/nebular/nebular_scenes.h"
#ifdef ENABLE_MADSV2
#include "mads/dragonsphere/dragonsphere_scenes.h"
@@ -32,7 +32,7 @@
namespace MADS {
-Scene::Scene(MADSEngine *vm)
+Scene::Scene(RexNebularEngine *vm)
: _vm(vm), _action(_vm), _depthSurface(),
_dirtyAreas(_vm), _dynamicHotspots(vm), _hotspots(vm),
_kernelMessages(vm), _sequences(vm), _sprites(vm), _spriteSlots(vm),
diff --git a/engines/mads/scene.h b/engines/mads/core/scene.h
similarity index 93%
rename from engines/mads/scene.h
rename to engines/mads/core/scene.h
index ede33136dfb..a34ab66a4a6 100644
--- a/engines/mads/scene.h
+++ b/engines/mads/core/scene.h
@@ -25,17 +25,17 @@
#include "common/scummsys.h"
#include "common/array.h"
#include "common/rect.h"
-#include "mads/assets.h"
-#include "mads/screen.h"
-#include "mads/hotspots.h"
-#include "mads/messages.h"
-#include "mads/msurface.h"
-#include "mads/scene_data.h"
-#include "mads/animation.h"
-#include "mads/rails.h"
-#include "mads/sequence.h"
-#include "mads/sprites.h"
-#include "mads/user_interface.h"
+#include "mads/core/assets.h"
+#include "mads/core/screen.h"
+#include "mads/core/hotspots.h"
+#include "mads/core/messages.h"
+#include "mads/core/msurface.h"
+#include "mads/core/scene_data.h"
+#include "mads/core/animation.h"
+#include "mads/core/rails.h"
+#include "mads/core/sequence.h"
+#include "mads/core/sprites.h"
+#include "mads/core/user_interface.h"
namespace MADS {
@@ -77,7 +77,7 @@ private:
*/
void updateCursor();
protected:
- MADSEngine *_vm;
+ RexNebularEngine *_vm;
public:
SceneLogic *_sceneLogic;
MSurface _sceneSurface;
@@ -130,7 +130,7 @@ public:
/**
* Constructor
*/
- Scene(MADSEngine *vm);
+ Scene(RexNebularEngine *vm);
/**
* Destructor
diff --git a/engines/mads/scene_data.cpp b/engines/mads/core/scene_data.cpp
similarity index 97%
rename from engines/mads/scene_data.cpp
rename to engines/mads/core/scene_data.cpp
index 50dc3a7eebf..9e511df22db 100644
--- a/engines/mads/scene_data.cpp
+++ b/engines/mads/core/scene_data.cpp
@@ -20,11 +20,11 @@
*/
#include "common/scummsys.h"
-#include "mads/scene_data.h"
-#include "mads/mads.h"
-#include "mads/compression.h"
-#include "mads/screen.h"
-#include "mads/resources.h"
+#include "mads/core/scene_data.h"
+#include "mads/nebular/nebular.h"
+#include "mads/core/compression.h"
+#include "mads/core/screen.h"
+#include "mads/core/resources.h"
#include "mads/nebular/nebular_scenes.h"
#ifdef ENABLE_MADSV2
#include "mads/dragonsphere/dragonsphere_scenes.h"
@@ -97,7 +97,7 @@ void SceneInfo::SpriteInfo::load(Common::SeekableReadStream *f) {
/*------------------------------------------------------------------------*/
-SceneInfo::SceneInfo(MADSEngine *vm) : _vm(vm) {
+SceneInfo::SceneInfo(RexNebularEngine *vm) : _vm(vm) {
_sceneId = 0;
_artFileNum = 0;
_depthStyle = 0;
@@ -113,7 +113,7 @@ SceneInfo::SceneInfo(MADSEngine *vm) : _vm(vm) {
_depthList[i] = 0;
}
-SceneInfo *SceneInfo::init(MADSEngine *vm) {
+SceneInfo *SceneInfo::init(RexNebularEngine *vm) {
switch (vm->getGameID()) {
case GType_RexNebular:
return new Nebular::SceneInfoNebular(vm);
@@ -521,7 +521,7 @@ void SceneInfo::loadMadsV2Background(int sceneId, const Common::String &resName,
/*------------------------------------------------------------------------*/
-SceneLogic::SceneLogic(MADSEngine *vm) : _vm(vm) {
+SceneLogic::SceneLogic(RexNebularEngine *vm) : _vm(vm) {
_scene = &_vm->_game->_scene;
}
diff --git a/engines/mads/scene_data.h b/engines/mads/core/scene_data.h
similarity index 91%
rename from engines/mads/scene_data.h
rename to engines/mads/core/scene_data.h
index f52f95b223d..6344d9e04be 100644
--- a/engines/mads/scene_data.h
+++ b/engines/mads/core/scene_data.h
@@ -28,14 +28,14 @@
#include "common/str.h"
#include "common/str-array.h"
#include "common/rect.h"
-#include "mads/action.h"
-#include "mads/assets.h"
-#include "mads/events.h"
-#include "mads/game_data.h"
-#include "mads/hotspots.h"
-#include "mads/messages.h"
-#include "mads/rails.h"
-#include "mads/user_interface.h"
+#include "mads/core/action.h"
+#include "mads/core/assets.h"
+#include "mads/core/events.h"
+#include "mads/core/game_data.h"
+#include "mads/core/hotspots.h"
+#include "mads/core/messages.h"
+#include "mads/core/rails.h"
+#include "mads/core/user_interface.h"
namespace MADS {
@@ -72,13 +72,13 @@ public:
class SceneLogic {
protected:
- MADSEngine *_vm;
+ RexNebularEngine *_vm;
Scene *_scene;
public:
/**
* Constructor
*/
- SceneLogic(MADSEngine *vm);
+ SceneLogic(RexNebularEngine *vm);
/**
* Destructor
@@ -150,12 +150,12 @@ class SceneInfo {
void load(Common::SeekableReadStream *f);
};
protected:
- MADSEngine *_vm;
+ RexNebularEngine *_vm;
/**
* Constructor
*/
- SceneInfo(MADSEngine *vm);
+ SceneInfo(RexNebularEngine *vm);
public:
int _sceneId;
int _artFileNum;
@@ -182,7 +182,7 @@ public:
/**
* Instantiates the class
*/
- static SceneInfo *init(MADSEngine *vm);
+ static SceneInfo *init(RexNebularEngine *vm);
/**
* loads the data
diff --git a/engines/mads/screen.cpp b/engines/mads/core/screen.cpp
similarity index 98%
rename from engines/mads/screen.cpp
rename to engines/mads/core/screen.cpp
index 862e84637fb..da5875437ee 100644
--- a/engines/mads/screen.cpp
+++ b/engines/mads/core/screen.cpp
@@ -20,15 +20,15 @@
*/
#include "common/scummsys.h"
-#include "mads/mads.h"
-#include "mads/game.h"
-#include "mads/screen.h"
-#include "mads/palette.h"
-#include "mads/user_interface.h"
+#include "mads/nebular/nebular.h"
+#include "mads/core/game.h"
+#include "mads/core/screen.h"
+#include "mads/core/palette.h"
+#include "mads/core/user_interface.h"
namespace MADS {
-MADSEngine *DirtyArea::_vm = nullptr;
+RexNebularEngine *DirtyArea::_vm = nullptr;
DirtyArea::DirtyArea() {
_active = false;
@@ -154,7 +154,7 @@ void DirtyArea::setUISlot(const UISlot *slot) {
/*------------------------------------------------------------------------*/
-DirtyAreas::DirtyAreas(MADSEngine *vm) /* : _vm(vm) */ {
+DirtyAreas::DirtyAreas(RexNebularEngine *vm) /* : _vm(vm) */ {
DirtyArea::_vm = vm;
for (int i = 0; i < DIRTY_AREAS_SIZE; ++i) {
@@ -250,7 +250,7 @@ ScreenObject::ScreenObject() {
/*------------------------------------------------------------------------*/
-ScreenObjects::ScreenObjects(MADSEngine *vm) : _vm(vm) {
+ScreenObjects::ScreenObjects(RexNebularEngine *vm) : _vm(vm) {
_objectY = -1;
_forceRescan = false;
_inputMode = kInputBuildingSentences;
diff --git a/engines/mads/screen.h b/engines/mads/core/screen.h
similarity index 96%
rename from engines/mads/screen.h
rename to engines/mads/core/screen.h
index 3a1e4e44ccd..cdf046c5e2c 100644
--- a/engines/mads/screen.h
+++ b/engines/mads/core/screen.h
@@ -24,8 +24,8 @@
#include "common/scummsys.h"
#include "common/array.h"
-#include "mads/msurface.h"
-#include "mads/action.h"
+#include "mads/core/msurface.h"
+#include "mads/core/action.h"
namespace MADS {
@@ -60,13 +60,14 @@ enum ThroughBlack {
THROUGH_BLACK2 = 2
};
+class RexNebularEngine;
class SpriteSlot;
class TextDisplay;
class UISlot;
class DirtyArea {
private:
- static MADSEngine *_vm;
+ static RexNebularEngine *_vm;
friend class DirtyAreas;
public:
Common::Rect _bounds;
@@ -96,9 +97,9 @@ public:
class DirtyAreas : public Common::Array<DirtyArea> {
//private:
-// MADSEngine *_vm;
+// RexNebularEngine *_vm;
public:
- DirtyAreas(MADSEngine *vm);
+ DirtyAreas(RexNebularEngine *vm);
/**
* Merge together any designated dirty areas that overlap
@@ -140,7 +141,7 @@ public:
class ScreenObjects : public Common::Array<ScreenObject> {
private:
- MADSEngine *_vm;
+ RexNebularEngine *_vm;
int _objectY;
int scanBackwards(const Common::Point &pt, int layer);
@@ -160,7 +161,7 @@ public:
/*
* Constructor
*/
- ScreenObjects(MADSEngine *vm);
+ ScreenObjects(RexNebularEngine *vm);
/**
* Add a new item to the list
diff --git a/engines/mads/sequence.cpp b/engines/mads/core/sequence.cpp
similarity index 98%
rename from engines/mads/sequence.cpp
rename to engines/mads/core/sequence.cpp
index 316006ae39d..7938be87bf4 100644
--- a/engines/mads/sequence.cpp
+++ b/engines/mads/core/sequence.cpp
@@ -20,10 +20,10 @@
*/
#include "common/scummsys.h"
-#include "mads/mads.h"
-#include "mads/assets.h"
-#include "mads/sequence.h"
-#include "mads/scene.h"
+#include "mads/nebular/nebular.h"
+#include "mads/core/assets.h"
+#include "mads/core/sequence.h"
+#include "mads/core/scene.h"
namespace MADS {
@@ -63,7 +63,7 @@ SequenceEntry::SequenceEntry() {
#define SEQUENCE_LIST_SIZE 30
-SequenceList::SequenceList(MADSEngine *vm) : _vm(vm) {
+SequenceList::SequenceList(RexNebularEngine *vm) : _vm(vm) {
// IMPORTANT: Preallocate timer slots. Note that sprite slots refer to entries
// in this list by index, so we can't just add or delete entries later
for (int i = 0; i < SEQUENCE_LIST_SIZE; ++i) {
diff --git a/engines/mads/sequence.h b/engines/mads/core/sequence.h
similarity index 97%
rename from engines/mads/sequence.h
rename to engines/mads/core/sequence.h
index 28f57c68023..3e784e7894c 100644
--- a/engines/mads/sequence.h
+++ b/engines/mads/core/sequence.h
@@ -25,7 +25,7 @@
#include "common/scummsys.h"
#include "common/array.h"
#include "common/rect.h"
-#include "mads/action.h"
+#include "mads/core/action.h"
namespace MADS {
@@ -84,14 +84,14 @@ struct SequenceEntry {
SequenceEntry();
};
-class MADSEngine;
+class RexNebularEngine;
class SequenceList {
private:
- MADSEngine *_vm;
+ RexNebularEngine *_vm;
Common::Array<SequenceEntry> _entries;
public:
- SequenceList(MADSEngine *vm);
+ SequenceList(RexNebularEngine *vm);
SequenceEntry &operator[](int index) { return _entries[index]; }
void clear();
diff --git a/engines/mads/sound.cpp b/engines/mads/core/sound.cpp
similarity index 96%
rename from engines/mads/sound.cpp
rename to engines/mads/core/sound.cpp
index f9ce5c78d59..96008f42962 100644
--- a/engines/mads/sound.cpp
+++ b/engines/mads/core/sound.cpp
@@ -21,8 +21,8 @@
#include "audio/fmopl.h"
#include "common/memstream.h"
-#include "mads/sound.h"
-#include "mads/mads.h"
+#include "mads/core/sound.h"
+#include "mads/nebular/nebular.h"
#include "mads/nebular/sound_nebular.h"
namespace Audio {
@@ -31,7 +31,7 @@ class Mixer;
namespace MADS {
-SoundManager::SoundManager(MADSEngine *vm, Audio::Mixer *mixer) {
+SoundManager::SoundManager(RexNebularEngine *vm, Audio::Mixer *mixer) {
_vm = vm;
_mixer = mixer;
_driver = nullptr;
diff --git a/engines/mads/sound.h b/engines/mads/core/sound.h
similarity index 95%
rename from engines/mads/sound.h
rename to engines/mads/core/sound.h
index 98ab2908e55..d7cf43fe316 100644
--- a/engines/mads/sound.h
+++ b/engines/mads/core/sound.h
@@ -39,11 +39,11 @@ namespace Nebular {
class ASound;
}
-class MADSEngine;
+class RexNebularEngine;
class SoundManager {
private:
- MADSEngine *_vm;
+ RexNebularEngine *_vm;
Audio::Mixer *_mixer;
OPL::OPL *_opl;
Nebular::ASound *_driver;
@@ -53,7 +53,7 @@ private:
Common::Queue<int> _queuedCommands;
int _masterVolume;
public:
- SoundManager(MADSEngine *vm, Audio::Mixer *mixer);
+ SoundManager(RexNebularEngine *vm, Audio::Mixer *mixer);
~SoundManager();
bool _preferRoland;
diff --git a/engines/mads/sprites.cpp b/engines/mads/core/sprites.cpp
similarity index 97%
rename from engines/mads/sprites.cpp
rename to engines/mads/core/sprites.cpp
index 2971bb6658b..6254968a968 100644
--- a/engines/mads/sprites.cpp
+++ b/engines/mads/core/sprites.cpp
@@ -21,10 +21,10 @@
#include "common/scummsys.h"
#include "engines/util.h"
-#include "mads/mads.h"
-#include "mads/screen.h"
-#include "mads/msurface.h"
-#include "mads/sprites.h"
+#include "mads/nebular/nebular.h"
+#include "mads/core/screen.h"
+#include "mads/core/msurface.h"
+#include "mads/core/sprites.h"
namespace MADS {
@@ -136,7 +136,7 @@ byte MSprite::getTransparencyIndex() const {
/*------------------------------------------------------------------------*/
-MADSEngine *SpriteSlot::_vm = nullptr;
+RexNebularEngine *SpriteSlot::_vm = nullptr;
SpriteSlot::SpriteSlot() {
_flags = IMG_STATIC;
@@ -172,7 +172,7 @@ void SpriteSlot::copy(const SpriteSlotSubset &other) {
/*------------------------------------------------------------------------*/
-SpriteSlots::SpriteSlots(MADSEngine *vm) : _vm(vm) {
+SpriteSlots::SpriteSlots(RexNebularEngine *vm) : _vm(vm) {
SpriteSlot::_vm = vm;
}
diff --git a/engines/mads/sprites.h b/engines/mads/core/sprites.h
similarity index 95%
rename from engines/mads/sprites.h
rename to engines/mads/core/sprites.h
index b38bf450435..8a988955241 100644
--- a/engines/mads/sprites.h
+++ b/engines/mads/core/sprites.h
@@ -24,8 +24,8 @@
#include "common/scummsys.h"
#include "common/array.h"
-#include "mads/assets.h"
-#include "mads/msurface.h"
+#include "mads/core/assets.h"
+#include "mads/core/msurface.h"
namespace MADS {
@@ -132,7 +132,7 @@ public:
class SpriteSlot : public SpriteSlotSubset {
private:
- static MADSEngine *_vm;
+ static RexNebularEngine *_vm;
friend class SpriteSlots;
public:
SpriteFlags _flags;
@@ -148,9 +148,9 @@ public:
class SpriteSlots : public Common::Array<SpriteSlot> {
private:
- MADSEngine *_vm;
+ RexNebularEngine *_vm;
public:
- SpriteSlots(MADSEngine *vm);
+ SpriteSlots(RexNebularEngine *vm);
/**
* Clears any pending slot data and schedules a full screen refresh.
@@ -199,14 +199,14 @@ public:
class SpriteSets : public Common::Array<SpriteAsset *> {
private:
- MADSEngine *_vm;
+ RexNebularEngine *_vm;
public:
SpriteAsset *_uiSprites;
public:
/**
* Constructor
*/
- SpriteSets(MADSEngine *vm) : _vm(vm), _uiSprites(nullptr) {}
+ SpriteSets(RexNebularEngine *vm) : _vm(vm), _uiSprites(nullptr) {}
/**
* Destructor
diff --git a/engines/mads/staticres.cpp b/engines/mads/core/staticres.cpp
similarity index 98%
rename from engines/mads/staticres.cpp
rename to engines/mads/core/staticres.cpp
index 80accd4b2c4..747fbf2ba4e 100644
--- a/engines/mads/staticres.cpp
+++ b/engines/mads/core/staticres.cpp
@@ -20,7 +20,7 @@
*/
#include "common/scummsys.h"
-#include "mads/staticres.h"
+#include "mads/core/staticres.h"
namespace MADS {
diff --git a/engines/mads/staticres.h b/engines/mads/core/staticres.h
similarity index 100%
rename from engines/mads/staticres.h
rename to engines/mads/core/staticres.h
diff --git a/engines/mads/user_interface.cpp b/engines/mads/core/user_interface.cpp
similarity index 99%
rename from engines/mads/user_interface.cpp
rename to engines/mads/core/user_interface.cpp
index 1395421dcac..35bc03ab0db 100644
--- a/engines/mads/user_interface.cpp
+++ b/engines/mads/core/user_interface.cpp
@@ -20,9 +20,9 @@
*/
#include "common/scummsys.h"
-#include "mads/mads.h"
-#include "mads/compression.h"
-#include "mads/user_interface.h"
+#include "mads/nebular/nebular.h"
+#include "mads/core/compression.h"
+#include "mads/core/user_interface.h"
#include "mads/nebular/game_nebular.h"
namespace MADS {
@@ -209,9 +209,9 @@ void UISlots::draw(bool updateFlag, bool delFlag) {
/*------------------------------------------------------------------------*/
-MADSEngine *Conversation::_vm;
+RexNebularEngine *Conversation::_vm;
-void Conversation::init(MADSEngine *vm) {
+void Conversation::init(RexNebularEngine *vm) {
_vm = vm;
}
@@ -309,7 +309,7 @@ void Conversation::start() {
/*------------------------------------------------------------------------*/
-UserInterface::UserInterface(MADSEngine *vm) : _vm(vm), _dirtyAreas(vm),
+UserInterface::UserInterface(RexNebularEngine *vm) : _vm(vm), _dirtyAreas(vm),
_uiSlots(vm) {
_invSpritesIndex = -1;
_invFrameNumber = 1;
diff --git a/engines/mads/user_interface.h b/engines/mads/core/user_interface.h
similarity index 95%
rename from engines/mads/user_interface.h
rename to engines/mads/core/user_interface.h
index c5e2d900a22..5ccd1b0a511 100644
--- a/engines/mads/user_interface.h
+++ b/engines/mads/core/user_interface.h
@@ -25,8 +25,8 @@
#include "common/scummsys.h"
#include "common/rect.h"
#include "common/str.h"
-#include "mads/msurface.h"
-#include "mads/screen.h"
+#include "mads/core/msurface.h"
+#include "mads/core/screen.h"
namespace MADS {
@@ -41,7 +41,7 @@ enum ScrollbarActive {
};
class AnimFrameEntry;
-class MADSEngine;
+class RexNebularEngine;
class UISlot {
public:
@@ -63,12 +63,12 @@ public:
*/
class UISlots : public Common::Array<UISlot> {
private:
- MADSEngine *_vm;
+ RexNebularEngine *_vm;
public:
/**
* Constructor
*/
- UISlots(MADSEngine *vm) : _vm(vm) {}
+ UISlots(RexNebularEngine *vm) : _vm(vm) {}
/**
* Add an overprint (text) entry to the list
@@ -95,9 +95,9 @@ public:
class Conversation {
private:
- static MADSEngine *_vm;
+ static RexNebularEngine *_vm;
public:
- static void init(MADSEngine *vm);
+ static void init(RexNebularEngine *vm);
public:
int _globalId;
Common::Array<int> _quotes;
@@ -132,7 +132,7 @@ public:
class UserInterface : public MSurface {
friend class UISlots;
private:
- MADSEngine *_vm;
+ RexNebularEngine *_vm;
int _invSpritesIndex;
int _invFrameNumber;
uint32 _scrollMilli;
@@ -215,7 +215,7 @@ public:
/**
* Constructor
*/
- UserInterface(MADSEngine *vm);
+ UserInterface(RexNebularEngine *vm);
/**
* Loads an interface from a specified resource
diff --git a/engines/mads/dragonsphere/dragonsphere_scenes.cpp b/engines/mads/dragonsphere/dragonsphere_scenes.cpp
index bcef5849246..fffbfc82e42 100644
--- a/engines/mads/dragonsphere/dragonsphere_scenes.cpp
+++ b/engines/mads/dragonsphere/dragonsphere_scenes.cpp
@@ -20,10 +20,10 @@
*/
#include "common/config-manager.h"
-#include "mads/mads.h"
-#include "mads/compression.h"
-#include "mads/resources.h"
-#include "mads/scene.h"
+#include "mads/nebular/nebular.h"
+#include "mads/core/compression.h"
+#include "mads/core/resources.h"
+#include "mads/core/scene.h"
#include "mads/dragonsphere/game_dragonsphere.h"
#include "mads/dragonsphere/dragonsphere_scenes.h"
#include "mads/dragonsphere/dragonsphere_scenes1.h"
@@ -31,7 +31,7 @@
namespace MADS {
namespace Dragonsphere {
-SceneLogic *SceneFactory::createScene(MADSEngine *vm) {
+SceneLogic *SceneFactory::createScene(RexNebularEngine *vm) {
Scene &scene = vm->_game->_scene;
// TODO
@@ -185,7 +185,7 @@ SceneLogic *SceneFactory::createScene(MADSEngine *vm) {
/*------------------------------------------------------------------------*/
-DragonsphereScene::DragonsphereScene(MADSEngine *vm) : SceneLogic(vm),
+DragonsphereScene::DragonsphereScene(RexNebularEngine *vm) : SceneLogic(vm),
_globals(static_cast<GameDragonsphere *>(vm->_game)->_globals),
_game(*static_cast<GameDragonsphere *>(vm->_game)),
_action(vm->_game->_scene._action) {
diff --git a/engines/mads/dragonsphere/dragonsphere_scenes.h b/engines/mads/dragonsphere/dragonsphere_scenes.h
index 6a66abdaff1..6b6027c27ec 100644
--- a/engines/mads/dragonsphere/dragonsphere_scenes.h
+++ b/engines/mads/dragonsphere/dragonsphere_scenes.h
@@ -22,7 +22,7 @@
#ifndef MADS_DRAGONSPHERE_SCENES_H
#define MADS_DRAGONSPHERE_SCENES_H
-#include "mads/scene.h"
+#include "mads/core/scene.h"
#include "mads/dragonsphere/game_dragonsphere.h"
//#include "mads/dragonsphere/globals_dragonsphere.h"
@@ -610,7 +610,7 @@ enum Noun {
class SceneFactory {
public:
- static SceneLogic *createScene(MADSEngine *vm);
+ static SceneLogic *createScene(RexNebularEngine *vm);
};
/**
@@ -635,7 +635,7 @@ public:
/**
* Constructor
*/
- DragonsphereScene(MADSEngine *vm);
+ DragonsphereScene(RexNebularEngine *vm);
void sub7178C();
};
@@ -650,13 +650,13 @@ protected:
/**
* Constructor
*/
- SceneInfoDragonsphere(MADSEngine *vm) : SceneInfo(vm) {}
+ SceneInfoDragonsphere(RexNebularEngine *vm) : SceneInfo(vm) {}
};
// TODO: Temporary, remove once implemented properly
class DummyScene : public DragonsphereScene {
public:
- DummyScene(MADSEngine *vm) : DragonsphereScene(vm) {
+ DummyScene(RexNebularEngine *vm) : DragonsphereScene(vm) {
warning("Unimplemented scene");
}
diff --git a/engines/mads/dragonsphere/dragonsphere_scenes1.cpp b/engines/mads/dragonsphere/dragonsphere_scenes1.cpp
index b719e92e7cc..66203b61360 100644
--- a/engines/mads/dragonsphere/dragonsphere_scenes1.cpp
+++ b/engines/mads/dragonsphere/dragonsphere_scenes1.cpp
@@ -19,9 +19,9 @@
*
*/
-#include "mads/mads.h"
-#include "mads/conversations.h"
-#include "mads/scene.h"
+#include "mads/nebular/nebular.h"
+#include "mads/core/conversations.h"
+#include "mads/core/scene.h"
#include "mads/dragonsphere/dragonsphere_scenes.h"
#include "mads/dragonsphere/dragonsphere_scenes1.h"
@@ -205,7 +205,7 @@ void Scene1xx::setPlayerSpritesPrefix() {
/*------------------------------------------------------------------------*/
-Scene101::Scene101(MADSEngine *vm) : Scene1xx(vm) {
+Scene101::Scene101(RexNebularEngine *vm) : Scene1xx(vm) {
}
void Scene101::synchronize(Common::Serializer &s) {
@@ -239,7 +239,7 @@ void Scene101::preActions() {
/*------------------------------------------------------------------------*/
-Scene102::Scene102(MADSEngine *vm) : Scene1xx(vm) {
+Scene102::Scene102(RexNebularEngine *vm) : Scene1xx(vm) {
_diaryHotspotIdx1 = -1;
_diaryHotspotIdx2 = -1;
_diaryFrame = -1;
@@ -645,7 +645,7 @@ void Scene102::preActions() {
/*------------------------------------------------------------------------*/
-Scene103::Scene103(MADSEngine *vm) : Scene1xx(vm) {
+Scene103::Scene103(RexNebularEngine *vm) : Scene1xx(vm) {
}
void Scene103::synchronize(Common::Serializer &s) {
@@ -1040,7 +1040,7 @@ void Scene103::preActions() {
/*------------------------------------------------------------------------*/
-Scene104::Scene104(MADSEngine *vm) : Scene1xx(vm) {
+Scene104::Scene104(RexNebularEngine *vm) : Scene1xx(vm) {
_anim0ActvFl = false;
_anim1ActvFl = false;
_anim2ActvFl = false;
@@ -3072,7 +3072,7 @@ void Scene104::handlePidAnimation() {
}
/*------------------------------------------------------------------------*/
-Scene105::Scene105(MADSEngine *vm) : Scene1xx(vm) {
+Scene105::Scene105(RexNebularEngine *vm) : Scene1xx(vm) {
_maidTalkingFl = false;
_sitUpFl = false;
_goodNumberFl = false;
diff --git a/engines/mads/dragonsphere/dragonsphere_scenes1.h b/engines/mads/dragonsphere/dragonsphere_scenes1.h
index 7d3ad22c23f..3be73b02295 100644
--- a/engines/mads/dragonsphere/dragonsphere_scenes1.h
+++ b/engines/mads/dragonsphere/dragonsphere_scenes1.h
@@ -45,12 +45,12 @@ protected:
*/
void setPlayerSpritesPrefix();
public:
- Scene1xx(MADSEngine *vm) : DragonsphereScene(vm) {}
+ Scene1xx(RexNebularEngine *vm) : DragonsphereScene(vm) {}
};
class Scene101 : public Scene1xx {
public:
- Scene101(MADSEngine *vm);
+ Scene101(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -68,7 +68,7 @@ private:
int _animRunning;
public:
- Scene102(MADSEngine *vm);
+ Scene102(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -80,7 +80,7 @@ public:
class Scene103 : public Scene1xx {
public:
- Scene103(MADSEngine *vm);
+ Scene103(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -137,7 +137,7 @@ private:
void handlePidAnimation();
public:
- Scene104(MADSEngine *vm);
+ Scene104(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -167,7 +167,7 @@ private:
void handleConversation();
public:
- Scene105(MADSEngine *vm);
+ Scene105(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
diff --git a/engines/mads/dragonsphere/game_dragonsphere.cpp b/engines/mads/dragonsphere/game_dragonsphere.cpp
index 6502d39dcb8..061aeb8fa32 100644
--- a/engines/mads/dragonsphere/game_dragonsphere.cpp
+++ b/engines/mads/dragonsphere/game_dragonsphere.cpp
@@ -20,10 +20,10 @@
*/
#include "common/config-manager.h"
-#include "mads/mads.h"
-#include "mads/game.h"
-#include "mads/screen.h"
-#include "mads/msurface.h"
+#include "mads/nebular/nebular.h"
+#include "mads/core/game.h"
+#include "mads/core/screen.h"
+#include "mads/core/msurface.h"
#include "mads/dragonsphere/game_dragonsphere.h"
//#include "mads/nebular/dialogs_nebular.h"
#include "mads/dragonsphere/globals_dragonsphere.h"
@@ -32,7 +32,7 @@
namespace MADS {
namespace Dragonsphere {
-GameDragonsphere::GameDragonsphere(MADSEngine *vm)
+GameDragonsphere::GameDragonsphere(RexNebularEngine *vm)
: Game(vm) {
_surface = new MSurface(MADS_SCREEN_WIDTH, MADS_SCENE_HEIGHT);
_storyMode = STORYMODE_NAUGHTY;
diff --git a/engines/mads/dragonsphere/game_dragonsphere.h b/engines/mads/dragonsphere/game_dragonsphere.h
index 81465ce04d5..341803746a0 100644
--- a/engines/mads/dragonsphere/game_dragonsphere.h
+++ b/engines/mads/dragonsphere/game_dragonsphere.h
@@ -22,8 +22,8 @@
#ifndef MADS_GAME_DRAGONSPHERE_H
#define MADS_GAME_DRAGONSPHERE_H
-#include "mads/game.h"
-#include "mads/globals.h"
+#include "mads/core/game.h"
+#include "mads/core/globals.h"
#include "mads/dragonsphere/globals_dragonsphere.h"
namespace MADS {
@@ -88,7 +88,7 @@ enum InventoryObject {
class GameDragonsphere : public Game {
friend class Game;
protected:
- GameDragonsphere(MADSEngine *vm);
+ GameDragonsphere(RexNebularEngine *vm);
void startGame() override;
@@ -115,7 +115,7 @@ public:
class Section1Handler : public SectionHandler {
public:
- Section1Handler(MADSEngine *vm) : SectionHandler(vm) {}
+ Section1Handler(RexNebularEngine *vm) : SectionHandler(vm) {}
// TODO: Properly implement handler methods
void preLoadSection() override {}
diff --git a/engines/mads/dragonsphere/globals_dragonsphere.h b/engines/mads/dragonsphere/globals_dragonsphere.h
index bce621f1d2f..d632a49c80e 100644
--- a/engines/mads/dragonsphere/globals_dragonsphere.h
+++ b/engines/mads/dragonsphere/globals_dragonsphere.h
@@ -22,8 +22,8 @@
#ifndef MADS_GLOBALS_DRAGONSPHERE_H
#define MADS_GLOBALS_DRAGONSPHERE_H
-#include "mads/game.h"
-#include "mads/resources.h"
+#include "mads/core/game.h"
+#include "mads/core/resources.h"
namespace MADS {
namespace Dragonsphere {
diff --git a/engines/mads/forest/forest_scenes.cpp b/engines/mads/forest/forest_scenes.cpp
index 8ad59961953..194fb382e35 100644
--- a/engines/mads/forest/forest_scenes.cpp
+++ b/engines/mads/forest/forest_scenes.cpp
@@ -20,17 +20,17 @@
*/
#include "common/config-manager.h"
-#include "mads/mads.h"
-#include "mads/compression.h"
-#include "mads/resources.h"
-#include "mads/scene.h"
+#include "mads/nebular/nebular.h"
+#include "mads/core/compression.h"
+#include "mads/core/resources.h"
+#include "mads/core/scene.h"
#include "mads/forest/game_forest.h"
#include "mads/forest/forest_scenes.h"
namespace MADS {
namespace Forest {
-SceneLogic *SceneFactory::createScene(MADSEngine *vm) {
+SceneLogic *SceneFactory::createScene(RexNebularEngine *vm) {
Scene &scene = vm->_game->_scene;
// TODO
@@ -124,7 +124,7 @@ SceneLogic *SceneFactory::createScene(MADSEngine *vm) {
/*------------------------------------------------------------------------*/
-ForestScene::ForestScene(MADSEngine *vm) : SceneLogic(vm),
+ForestScene::ForestScene(RexNebularEngine *vm) : SceneLogic(vm),
_globals(static_cast<GameForest *>(vm->_game)->_globals),
_game(*static_cast<GameForest *>(vm->_game)),
_action(vm->_game->_scene._action) {
diff --git a/engines/mads/forest/forest_scenes.h b/engines/mads/forest/forest_scenes.h
index abc13a972b2..01c50442fe6 100644
--- a/engines/mads/forest/forest_scenes.h
+++ b/engines/mads/forest/forest_scenes.h
@@ -22,7 +22,7 @@
#ifndef MADS_FOREST_SCENES_H
#define MADS_FOREST_SCENES_H
-#include "mads/scene.h"
+#include "mads/core/scene.h"
#include "mads/forest/game_forest.h"
#include "mads/forest/globals_forest.h"
@@ -176,7 +176,7 @@ enum Noun {
class SceneFactory {
public:
- static SceneLogic *createScene(MADSEngine *vm);
+ static SceneLogic *createScene(RexNebularEngine *vm);
};
/**
@@ -201,7 +201,7 @@ public:
/**
* Constructor
*/
- ForestScene(MADSEngine *vm);
+ ForestScene(RexNebularEngine *vm);
};
class SceneInfoForest : public SceneInfo {
@@ -214,13 +214,13 @@ protected:
/**
* Constructor
*/
- SceneInfoForest(MADSEngine *vm) : SceneInfo(vm) {}
+ SceneInfoForest(RexNebularEngine *vm) : SceneInfo(vm) {}
};
// TODO: Temporary, remove once implemented properly
class DummyScene : public ForestScene {
public:
- DummyScene(MADSEngine *vm) : ForestScene(vm) {
+ DummyScene(RexNebularEngine *vm) : ForestScene(vm) {
warning("Unimplemented scene");
}
diff --git a/engines/mads/forest/game_forest.cpp b/engines/mads/forest/game_forest.cpp
index f51ce2fd593..1263bbea214 100644
--- a/engines/mads/forest/game_forest.cpp
+++ b/engines/mads/forest/game_forest.cpp
@@ -20,10 +20,10 @@
*/
#include "common/config-manager.h"
-#include "mads/mads.h"
-#include "mads/game.h"
-#include "mads/screen.h"
-#include "mads/msurface.h"
+#include "mads/nebular/nebular.h"
+#include "mads/core/game.h"
+#include "mads/core/screen.h"
+#include "mads/core/msurface.h"
#include "mads/forest/game_forest.h"
//#include "mads/nebular/dialogs_nebular.h"
#include "mads/forest/globals_forest.h"
@@ -32,7 +32,7 @@
namespace MADS {
namespace Forest {
-GameForest::GameForest(MADSEngine *vm)
+GameForest::GameForest(RexNebularEngine *vm)
: Game(vm) {
_surface = new MSurface(MADS_SCREEN_WIDTH, MADS_SCENE_HEIGHT);
_storyMode = STORYMODE_NAUGHTY;
diff --git a/engines/mads/forest/game_forest.h b/engines/mads/forest/game_forest.h
index a97e7e76e52..42235aea830 100644
--- a/engines/mads/forest/game_forest.h
+++ b/engines/mads/forest/game_forest.h
@@ -22,8 +22,8 @@
#ifndef MADS_GAME_FOREST_H
#define MADS_GAME_FOREST_H
-#include "mads/game.h"
-#include "mads/globals.h"
+#include "mads/core/game.h"
+#include "mads/core/globals.h"
#include "mads/forest/globals_forest.h"
namespace MADS {
@@ -55,7 +55,7 @@ enum InventoryObject {
class GameForest : public Game {
friend class Game;
protected:
- GameForest(MADSEngine *vm);
+ GameForest(RexNebularEngine *vm);
void startGame() override;
@@ -82,7 +82,7 @@ public:
class Section1Handler : public SectionHandler {
public:
- Section1Handler(MADSEngine *vm) : SectionHandler(vm) {}
+ Section1Handler(RexNebularEngine *vm) : SectionHandler(vm) {}
// TODO: Properly implement handler methods
void preLoadSection() override {}
diff --git a/engines/mads/forest/globals_forest.h b/engines/mads/forest/globals_forest.h
index a67de5df2e5..e082ca6e006 100644
--- a/engines/mads/forest/globals_forest.h
+++ b/engines/mads/forest/globals_forest.h
@@ -22,8 +22,8 @@
#ifndef MADS_GLOBALS_FOREST_H
#define MADS_GLOBALS_FOREST_H
-#include "mads/game.h"
-#include "mads/resources.h"
+#include "mads/core/game.h"
+#include "mads/core/resources.h"
namespace MADS {
namespace Forest {
diff --git a/engines/mads/mads.cpp b/engines/mads/mads.cpp
index be5ece8e27b..80b21847d7a 100644
--- a/engines/mads/mads.cpp
+++ b/engines/mads/mads.cpp
@@ -19,160 +19,15 @@
*
*/
-#include "common/scummsys.h"
-#include "common/config-manager.h"
-#include "common/debug-channels.h"
-#include "common/events.h"
-#include "common/text-to-speech.h"
-#include "engines/util.h"
#include "mads/mads.h"
-#include "mads/game.h"
-#include "mads/screen.h"
-#include "mads/msurface.h"
-#include "mads/resources.h"
-#include "mads/sound.h"
-#include "mads/sprites.h"
-#include "mads/mps_installer.h"
namespace MADS {
MADSEngine::MADSEngine(OSystem *syst, const MADSGameDescription *gameDesc) :
- _gameDescription(gameDesc), Engine(syst), _randomSource("MADS") {
-
- // Initialize game/engine options
- _easyMouse = true;
- _invObjectsAnimated = true;
- _textWindowStill = false;
- _screenFade = SCREEN_FADE_SMOOTH;
- _musicFlag = true;
- _soundFlag = true;
- _dithering = false;
- _disableFastwalk = false;
-
- _dialogs = nullptr;
- _events = nullptr;
- _font = nullptr;
- _game = nullptr;
- _gameConv = nullptr;
- _palette = nullptr;
- _resources = nullptr;
- _sound = nullptr;
- _audio = nullptr;
- _screen = nullptr;
+ Engine(syst), _gameDescription(gameDesc), _randomSource("MADS") {
}
MADSEngine::~MADSEngine() {
- delete _dialogs;
- delete _events;
- delete _font;
- Font::deinit();
- delete _game;
- delete _gameConv;
- delete _palette;
- delete _resources;
- delete _sound;
- delete _audio;
- //_debugger Debugger is deleted by Engine
-
- _mixer->stopAll();
-}
-
-void MADSEngine::initialize() {
- if (_gameDescription->desc.flags & GF_INSTALLER) {
- // Right now used only by Rex Nebular
- Common::Archive* arch = MpsInstaller::open("MPSLABS");
- if (arch)
- SearchMan.add("mpslabs", arch);
- }
-
- // Initial sub-system engine references
- MSurface::setVm(this);
- MSprite::setVm(this);
-
- Resources::init(this);
- Conversation::init(this);
- _debugger = new Debugger(this);
- setDebugger(_debugger);
- _dialogs = Dialogs::init(this);
- _events = new EventsManager(this);
- _palette = new Palette(this);
- Font::init(this);
- _font = new Font();
- _screen = new Screen();
- _sound = new SoundManager(this, _mixer);
- _audio = new AudioPlayer(_mixer, getGameID());
- _game = Game::init(this);
- _gameConv = new GameConversations(this);
-
- loadOptions();
-
- _screen->clear();
-}
-
-void MADSEngine::loadOptions() {
- if (ConfMan.hasKey("EasyMouse"))
- _easyMouse = ConfMan.getBool("EasyMouse");
-
- if (ConfMan.hasKey("mute") && ConfMan.getBool("mute")) {
- _soundFlag = false;
- _musicFlag = false;
- } else {
- _soundFlag = !ConfMan.hasKey("sfx_mute") || !ConfMan.getBool("sfx_mute");
- _musicFlag = !ConfMan.hasGameDomain("music_mute") || !ConfMan.getBool("music_mute");
- }
-
- if (ConfMan.hasKey("ScreenFade"))
- _screenFade = (ScreenFade)ConfMan.getInt("ScreenFade");
- //if (ConfMan.hasKey("GraphicsDithering"))
- // _dithering = ConfMan.getBool("GraphicsDithering");
-
- if (getGameID() == GType_RexNebular) {
- if (ConfMan.hasKey("InvObjectsAnimated"))
- _invObjectsAnimated = ConfMan.getBool("InvObjectsAnimated");
- if (ConfMan.hasKey("TextWindowStill"))
- _textWindowStill = !ConfMan.getBool("TextWindowAnimated");
- if (ConfMan.hasKey("NaughtyMode"))
- _game->setNaughtyMode(ConfMan.getBool("NaughtyMode"));
- }
-
- // Note: MADS is weird in that sfx and music are handled by the same driver,
- // and the game scripts themselves check for music being enabled before playing
- // a "music" sound. Which means we can independently mute music in ScummVM, but
- // otherwise all sound, music and sfx, is controlled by the SFX volume slider.
- int soundVolume = MIN(255, ConfMan.getInt("sfx_volume"));
- _sound->setVolume(soundVolume);
-
- Common::TextToSpeechManager *ttsMan = g_system->getTextToSpeechManager();
- if (ttsMan != nullptr)
- ttsMan->enable(ConfMan.getBool("tts_narrator"));
-}
-
-void MADSEngine::saveOptions() {
- ConfMan.setBool("EasyMouse", _easyMouse);
- ConfMan.setInt("ScreenFade", (int)_screenFade);
- //ConfMan.setBool("GraphicsDithering", _dithering);
-
- ConfMan.setBool("mute", !_soundFlag && !_musicFlag);
- ConfMan.setBool("sfx_mute", !_soundFlag && _musicFlag);
- ConfMan.setBool("music_mute", _soundFlag && !_musicFlag);
-
- if (getGameID() == GType_RexNebular) {
- ConfMan.setBool("InvObjectsAnimated", _invObjectsAnimated);
- ConfMan.setBool("TextWindowAnimated", !_textWindowStill);
- ConfMan.setBool("NaughtyMode", _game->getNaughtyMode());
- }
-
- ConfMan.flushToDisk();
-}
-
-Common::Error MADSEngine::run() {
- initGraphics(MADS_SCREEN_WIDTH, MADS_SCREEN_HEIGHT);
- initialize();
-
- // Run the game
- _game->run();
-
- return Common::kNoError;
}
int MADSEngine::getRandomNumber(int maxNumber) {
@@ -185,35 +40,4 @@ int MADSEngine::getRandomNumber(int minNumber, int maxNumber) {
return minNumber + _randomSource.getRandomNumber(range);
}
-bool MADSEngine::canLoadGameStateCurrently(Common::U32String *msg) {
- return !_game->_winStatus && !_game->globals()[5]
- && _dialogs->_pendingDialog == DIALOG_NONE
- && _events->_cursorId != CURSOR_WAIT;
-}
-
-bool MADSEngine::canSaveGameStateCurrently(Common::U32String *msg) {
- return !_game->_winStatus && !_game->globals()[5]
- && _dialogs->_pendingDialog == DIALOG_NONE
- && _events->_cursorId != CURSOR_WAIT
- && _game->_scene._sceneLogic;
-}
-
-void MADSEngine::syncSoundSettings() {
- Engine::syncSoundSettings();
-
- loadOptions();
-}
-
-Common::Error MADSEngine::loadGameState(int slot) {
- _game->_loadGameSlot = slot;
- _game->_scene._currentSceneId = -1;
- _game->_currentSectionNumber = -1;
- return Common::kNoError;
-}
-
-Common::Error MADSEngine::saveGameState(int slot, const Common::String &desc, bool isAutosave) {
- _game->saveGame(slot, desc);
- return Common::kNoError;
-}
-
-} // End of namespace MADS
+} // namespace MADS
diff --git a/engines/mads/mads.h b/engines/mads/mads.h
index d11e45e2f77..2b8117edcc7 100644
--- a/engines/mads/mads.h
+++ b/engines/mads/mads.h
@@ -28,17 +28,6 @@
#include "common/random.h"
#include "common/util.h"
#include "engines/engine.h"
-#include "graphics/surface.h"
-#include "mads/conversations.h"
-#include "mads/debugger.h"
-#include "mads/dialogs.h"
-#include "mads/events.h"
-#include "mads/font.h"
-#include "mads/game.h"
-#include "mads/screen.h"
-#include "mads/msurface.h"
-#include "mads/resources.h"
-#include "mads/sound.h"
#include "mads/detection.h"
namespace MADS {
@@ -47,22 +36,6 @@ namespace MADS {
#define DEBUG_INTERMEDIATE 2
#define DEBUG_DETAILED 3
-enum MADSActions {
- kActionNone,
- kActionEscape,
- kActionGameMenu,
- kActionSave,
- kActionRestore,
- kActionScrollUp,
- kActionScrollDown,
- kActionStartGame,
- kActionResumeGame,
- kActionShowIntro,
- kActionCredits,
- kActionQuotes,
- kActionRestartAnimation
-};
-
enum MADSDebugChannels {
kDebugPath = 1,
kDebugScripts,
@@ -77,40 +50,12 @@ enum ScreenFade {
class MADSEngine : public Engine {
-private:
+protected:
const MADSGameDescription *_gameDescription;
Common::RandomSource _randomSource;
- /**
- * Handles basic initialisation
- */
- void initialize();
-
- void loadOptions();
-protected:
- // Engine APIs
- Common::Error run() override;
bool hasFeature(EngineFeature f) const override;
-public:
- Debugger *_debugger;
- Dialogs *_dialogs;
- EventsManager *_events;
- Font *_font;
- Game *_game;
- GameConversations * _gameConv;
- Palette *_palette;
- Resources *_resources;
- Screen *_screen;
- SoundManager *_sound;
- AudioPlayer *_audio;
- bool _easyMouse;
- bool _invObjectsAnimated;
- bool _textWindowStill;
- ScreenFade _screenFade;
- bool _musicFlag;
- bool _soundFlag;
- bool _dithering;
- bool _disableFastwalk;
+
public:
MADSEngine(OSystem *syst, const MADSGameDescription *gameDesc);
~MADSEngine() override;
@@ -125,35 +70,8 @@ public:
int getRandomNumber(int maxNumber);
int getRandomNumber(int minNumber, int maxNumber);
-
- /**
- * Returns true if it is currently okay to restore a game
- */
- bool canLoadGameStateCurrently(Common::U32String *msg = nullptr) override;
-
- /**
- * Returns true if it is currently okay to save the game
- */
- bool canSaveGameStateCurrently(Common::U32String *msg = nullptr) override;
-
- /**
- * Handles loading a game via the GMM
- */
- Common::Error loadGameState(int slot) override;
-
- /**
- * Handles saving the game via the GMM
- */
- Common::Error saveGameState(int slot, const Common::String &desc, bool isAutosave = false) override;
-
- /**
- * Handles updating sound settings after they're changed in the GMM dialog
- */
- void syncSoundSettings() override;
-
- void saveOptions();
};
-} // End of namespace MADS
+} // namespace MADS
-#endif /* MADS_MADS_H */
+#endif
diff --git a/engines/mads/madsv2/core/loader.cpp b/engines/mads/madsv2/core/loader.cpp
index 69a0dd482b7..0b9f715a6d8 100644
--- a/engines/mads/madsv2/core/loader.cpp
+++ b/engines/mads/madsv2/core/loader.cpp
@@ -208,11 +208,7 @@ long loader_read(void *target, long record_size, long record_count, LoadHandle h
if (!record_size)
return 0;
- if (record_count == 1) {
- total_size = record_size;
- } else {
- total_size = record_size * record_count;
- }
+ total_size = record_size * record_count;
total_left = total_size;
marker = handle->pack_list_marker++;
@@ -285,11 +281,13 @@ long loader_read(void *target, long record_size, long record_count, LoadHandle h
#endif
done:
- if (decompress_buffer != NULL) mem_free(decompress_buffer);
+ if (decompress_buffer != NULL)
+ mem_free(decompress_buffer);
+
if (result == record_size) {
- return (1);
+ return 1;
} else {
- return (result / record_size);
+ return result / record_size;
}
}
diff --git a/engines/mads/madsv2/engine.cpp b/engines/mads/madsv2/engine.cpp
index 90c88c3bdce..de1c9b30bda 100644
--- a/engines/mads/madsv2/engine.cpp
+++ b/engines/mads/madsv2/engine.cpp
@@ -30,13 +30,13 @@ namespace MADSV2 {
MADSV2Engine *g_engine;
MADSV2Engine::MADSV2Engine(OSystem *syst, const MADSGameDescription *gameDesc) :
- Engine(syst), _gameDescription(gameDesc) {
+ MADSEngine(syst, gameDesc) {
g_engine = this;
}
MADSV2Engine::~MADSV2Engine() {
- delete _screen;
g_engine = nullptr;
+ delete _screen;
}
Common::Error MADSV2Engine::run() {
diff --git a/engines/mads/madsv2/engine.h b/engines/mads/madsv2/engine.h
index a233908cf4b..cab4ce6549a 100644
--- a/engines/mads/madsv2/engine.h
+++ b/engines/mads/madsv2/engine.h
@@ -25,18 +25,15 @@
#include "common/events.h"
#include "common/list.h"
#include "common/random.h"
-#include "engines/engine.h"
#include "graphics/screen.h"
-#include "mads/detection.h"
+#include "mads/mads.h"
namespace MADS {
namespace MADSV2 {
-class MADSV2Engine : public Engine {
+class MADSV2Engine : public MADSEngine {
private:
- const MADSGameDescription *_gameDescription;
Graphics::Screen *_screen = nullptr;
- Common::RandomSource _random = Common::RandomSource("MADS");
Common::List<Common::Event> _events;
void pollEvents();
@@ -47,13 +44,6 @@ public:
Common::Error run() override;
- uint getRandomNumber(uint max) {
- return _random.getRandomNumber(max);
- }
- uint getRandomNumber(uint min, uint max) {
- return min + _random.getRandomNumber(max - min);
- }
-
Graphics::Screen *getScreen() const {
return _screen;
}
diff --git a/engines/mads/metaengine.cpp b/engines/mads/metaengine.cpp
index 8ea055d7741..e4d53c3b6e8 100644
--- a/engines/mads/metaengine.cpp
+++ b/engines/mads/metaengine.cpp
@@ -20,7 +20,7 @@
*
*/
-#include "mads/mads.h"
+#include "mads/nebular/nebular.h"
#include "base/plugins.h"
#include "engines/advancedDetector.h"
@@ -36,8 +36,8 @@
#include "common/translation.h"
#include "graphics/surface.h"
-#include "mads/events.h"
-#include "mads/game.h"
+#include "mads/core/events.h"
+#include "mads/core/game.h"
#include "mads/detection.h"
#ifdef ENABLE_MADSV2
#include "mads/madsv2/engine.h"
@@ -208,7 +208,7 @@ Common::Error MADSMetaEngine::createInstance(OSystem *syst, Engine **engine, con
else
#endif
- *engine = new MADS::MADSEngine(syst,desc);
+ *engine = new MADS::RexNebularEngine(syst,desc);
return Common::kNoError;
}
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index 047cd88f759..b88fe307ec9 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -1,6 +1,8 @@
MODULE := engines/mads
MODULE_OBJS := \
+ nebular/nebular.o \
+ nebular/debugger.o \
nebular/dialogs_nebular.o \
nebular/game_nebular.o \
nebular/globals_nebular.o \
@@ -15,40 +17,40 @@ MODULE_OBJS := \
nebular/nebular_scenes6.o \
nebular/nebular_scenes7.o \
nebular/nebular_scenes8.o \
- action.o \
- animation.o \
- assets.o \
- audio.o \
- camera.o \
- compression.o \
- conversations.o \
- debugger.o \
- dialogs.o \
- events.o \
- font.o \
- game.o \
- game_data.o \
- globals.o \
- hotspots.o \
- inventory.o \
- mads.o \
- menu_views.o \
- messages.o \
- msurface.o \
+ core/action.o \
+ core/animation.o \
+ core/assets.o \
+ core/audio.o \
+ core/camera.o \
+ core/compression.o \
+ core/conversations.o \
+ core/dialogs.o \
+ core/events.o \
+ core/font.o \
+ core/game.o \
+ core/game_data.o \
+ core/globals.o \
+ core/hotspots.o \
+ core/inventory.o \
+ core/mads.o \
+ core/menu_views.o \
+ core/messages.o \
+ core/msurface.o \
+ core/mps_installer.o \
+ core/palette.o \
+ core/player.o \
+ core/rails.o \
+ core/resources.o \
+ core/scene.o \
+ core/scene_data.o \
+ core/screen.o \
+ core/sequence.o \
+ core/sound.o \
+ core/sprites.o \
+ core/staticres.o \
+ core/user_interface.o \
metaengine.o \
- mps_installer.o \
- palette.o \
- player.o \
- rails.o \
- resources.o \
- scene.o \
- scene_data.o \
- screen.o \
- sequence.o \
- sound.o \
- sprites.o \
- staticres.o \
- user_interface.o
+ mads.o
ifdef ENABLE_MADSV2
MODULE_OBJS += \
diff --git a/engines/mads/debugger.cpp b/engines/mads/nebular/debugger.cpp
similarity index 98%
rename from engines/mads/debugger.cpp
rename to engines/mads/nebular/debugger.cpp
index a9c26a093af..8b0f502a34b 100644
--- a/engines/mads/debugger.cpp
+++ b/engines/mads/nebular/debugger.cpp
@@ -20,14 +20,14 @@
*/
#include "common/file.h"
-#include "mads/compression.h"
-#include "mads/mads.h"
-#include "mads/debugger.h"
+#include "mads/core/compression.h"
+#include "mads/nebular/nebular.h"
+#include "mads/nebular/debugger.h"
#include "mads/nebular/menu_nebular.h"
namespace MADS {
-Debugger::Debugger(MADSEngine *vm) : GUI::Debugger(), _vm(vm) {
+Debugger::Debugger(RexNebularEngine *vm) : GUI::Debugger(), _vm(vm) {
_showMousePos = false;
registerCmd("continue", WRAP_METHOD(Debugger, cmdExit));
diff --git a/engines/mads/debugger.h b/engines/mads/nebular/debugger.h
similarity index 96%
rename from engines/mads/debugger.h
rename to engines/mads/nebular/debugger.h
index f38ee711f9d..c2ea8300aa7 100644
--- a/engines/mads/debugger.h
+++ b/engines/mads/nebular/debugger.h
@@ -27,11 +27,12 @@
namespace MADS {
-class MADSEngine;
+class RexNebularEngine;
class Debugger : public GUI::Debugger {
private:
- MADSEngine *_vm;
+ RexNebularEngine *_vm;
+
protected:
bool Cmd_Mouse(int argc, const char **argv);
bool Cmd_LoadScene(int argc, const char **argv);
@@ -54,7 +55,7 @@ protected:
public:
bool _showMousePos;
public:
- Debugger(MADSEngine *vm);
+ Debugger(RexNebularEngine *vm);
~Debugger() override {}
};
diff --git a/engines/mads/nebular/dialogs_nebular.cpp b/engines/mads/nebular/dialogs_nebular.cpp
index d2989ce40e9..60ac9be0346 100644
--- a/engines/mads/nebular/dialogs_nebular.cpp
+++ b/engines/mads/nebular/dialogs_nebular.cpp
@@ -27,10 +27,10 @@
#include "gui/saveload.h"
-#include "mads/mads.h"
-#include "mads/screen.h"
-#include "mads/msurface.h"
-#include "mads/staticres.h"
+#include "mads/nebular/nebular.h"
+#include "mads/core/screen.h"
+#include "mads/core/msurface.h"
+#include "mads/core/staticres.h"
#include "mads/nebular/dialogs_nebular.h"
#include "mads/nebular/game_nebular.h"
#include "mads/nebular/menu_nebular.h"
@@ -399,7 +399,7 @@ void DialogsNebular::showScummVMRestoreDialog() {
/*------------------------------------------------------------------------*/
-CopyProtectionDialog::CopyProtectionDialog(MADSEngine *vm, bool priorAnswerWrong) :
+CopyProtectionDialog::CopyProtectionDialog(RexNebularEngine *vm, bool priorAnswerWrong) :
TextDialog(vm, FONT_INTERFACE, Common::Point(-1, -1), 32) {
getHogAnusEntry(_hogEntry);
@@ -521,7 +521,7 @@ bool CopyProtectionDialog::getHogAnusEntry(HOGANUS &entry) {
/*------------------------------------------------------------------------*/
-PictureDialog::PictureDialog(MADSEngine *vm, const Common::Point &pos,
+PictureDialog::PictureDialog(RexNebularEngine *vm, const Common::Point &pos,
int maxChars, int objectId) :
TextDialog(vm, FONT_INTERFACE, pos, maxChars), _objectId(objectId) {
// Turn off cycling if active
@@ -640,7 +640,7 @@ GameDialog::DialogLine::DialogLine(const Common::String &s) {
/*------------------------------------------------------------------------*/
-GameDialog::GameDialog(MADSEngine *vm) : FullScreenDialog(vm) {
+GameDialog::GameDialog(RexNebularEngine *vm) : FullScreenDialog(vm) {
Game &game = *_vm->_game;
Scene &scene = game._scene;
@@ -997,7 +997,7 @@ void GameDialog::refreshText() {
/*------------------------------------------------------------------------*/
-DifficultyDialog::DifficultyDialog(MADSEngine *vm) : GameDialog(vm) {
+DifficultyDialog::DifficultyDialog(RexNebularEngine *vm) : GameDialog(vm) {
setLines();
_vm->_palette->resetGamePalette(18, 10);
}
@@ -1041,7 +1041,7 @@ void DifficultyDialog::show() {
/*------------------------------------------------------------------------*/
-GameMenuDialog::GameMenuDialog(MADSEngine *vm) : GameDialog(vm) {
+GameMenuDialog::GameMenuDialog(RexNebularEngine *vm) : GameDialog(vm) {
setLines();
}
@@ -1092,7 +1092,7 @@ void GameMenuDialog::show() {
/*------------------------------------------------------------------------*/
-OptionsDialog::OptionsDialog(MADSEngine *vm) : GameDialog(vm) {
+OptionsDialog::OptionsDialog(RexNebularEngine *vm) : GameDialog(vm) {
setLines();
}
diff --git a/engines/mads/nebular/dialogs_nebular.h b/engines/mads/nebular/dialogs_nebular.h
index 7f76edf2f80..1518bd5d830 100644
--- a/engines/mads/nebular/dialogs_nebular.h
+++ b/engines/mads/nebular/dialogs_nebular.h
@@ -23,8 +23,8 @@
#define MADS_DIALOGS_NEBULAR_H
#include "common/scummsys.h"
-#include "mads/game.h"
-#include "mads/dialogs.h"
+#include "mads/core/game.h"
+#include "mads/core/dialogs.h"
namespace MADS {
@@ -38,7 +38,7 @@ private:
int _dialogWidth;
CapitalizationMode _capitalizationMode;
- DialogsNebular(MADSEngine *vm): Dialogs(vm), _capitalizationMode(kUppercase), _dialogWidth(0) {}
+ DialogsNebular(RexNebularEngine *vm): Dialogs(vm), _capitalizationMode(kUppercase), _dialogWidth(0) {}
Common::String getVocab(int vocabId) override;
@@ -78,7 +78,7 @@ public:
/**
* Constructor
*/
- CopyProtectionDialog(MADSEngine *vm, bool priorAnswerWrong);
+ CopyProtectionDialog(RexNebularEngine *vm, bool priorAnswerWrong);
/**
* Show the dialog
@@ -100,7 +100,7 @@ protected:
void restore() override;
public:
- PictureDialog(MADSEngine *vm, const Common::Point &pos, int maxChars, int objectId);
+ PictureDialog(RexNebularEngine *vm, const Common::Point &pos, int maxChars, int objectId);
~PictureDialog() override;
};
@@ -186,7 +186,7 @@ public:
/**
* Constructor
*/
- GameDialog(MADSEngine *vm);
+ GameDialog(RexNebularEngine *vm);
/**
* Destructor
@@ -206,7 +206,7 @@ private:
*/
void setLines();
public:
- DifficultyDialog(MADSEngine *vm);
+ DifficultyDialog(RexNebularEngine *vm);
/**
* Display the dialog
@@ -226,7 +226,7 @@ private:
*/
void setLines();
public:
- GameMenuDialog(MADSEngine *vm);
+ GameMenuDialog(RexNebularEngine *vm);
/**
* Display the dialog
@@ -251,7 +251,7 @@ private:
*/
int getOptionQuote(int option);
public:
- OptionsDialog(MADSEngine *vm);
+ OptionsDialog(RexNebularEngine *vm);
/**
* Display the dialog
diff --git a/engines/mads/nebular/game_nebular.cpp b/engines/mads/nebular/game_nebular.cpp
index c0dfe4d8191..18cc2f03456 100644
--- a/engines/mads/nebular/game_nebular.cpp
+++ b/engines/mads/nebular/game_nebular.cpp
@@ -22,11 +22,11 @@
#include "common/scummsys.h"
#include "common/config-manager.h"
#include "graphics/scaler.h"
-#include "mads/mads.h"
-#include "mads/game.h"
-#include "mads/screen.h"
-#include "mads/msurface.h"
-#include "mads/menu_views.h"
+#include "mads/nebular/nebular.h"
+#include "mads/core/game.h"
+#include "mads/core/screen.h"
+#include "mads/core/msurface.h"
+#include "mads/core/menu_views.h"
#include "mads/nebular/game_nebular.h"
#include "mads/nebular/dialogs_nebular.h"
#include "mads/nebular/globals_nebular.h"
@@ -36,7 +36,7 @@ namespace MADS {
namespace Nebular {
-GameNebular::GameNebular(MADSEngine *vm)
+GameNebular::GameNebular(RexNebularEngine *vm)
: Game(vm) {
_surface = new MSurface(MADS_SCREEN_WIDTH, MADS_SCENE_HEIGHT);
_storyMode = STORYMODE_NAUGHTY;
diff --git a/engines/mads/nebular/game_nebular.h b/engines/mads/nebular/game_nebular.h
index 798591d5359..da33de5b877 100644
--- a/engines/mads/nebular/game_nebular.h
+++ b/engines/mads/nebular/game_nebular.h
@@ -23,8 +23,8 @@
#define MADS_GAME_NEBULAR_H
#include "common/scummsys.h"
-#include "mads/game.h"
-#include "mads/globals.h"
+#include "mads/core/game.h"
+#include "mads/core/globals.h"
#include "mads/nebular/globals_nebular.h"
namespace MADS {
@@ -105,7 +105,7 @@ class GameNebular : public Game {
private:
ProtectionResult checkCopyProtection();
protected:
- GameNebular(MADSEngine *vm);
+ GameNebular(RexNebularEngine *vm);
void startGame() override;
@@ -138,7 +138,7 @@ public:
// Section handlers aren't needed in ScummVM implementation
class Section1Handler : public SectionHandler {
public:
- Section1Handler(MADSEngine *vm) : SectionHandler(vm) {}
+ Section1Handler(RexNebularEngine *vm) : SectionHandler(vm) {}
void preLoadSection() override {}
void sectionPtr2() override {}
diff --git a/engines/mads/nebular/globals_nebular.h b/engines/mads/nebular/globals_nebular.h
index 3f4bb921286..1fc86b3c64c 100644
--- a/engines/mads/nebular/globals_nebular.h
+++ b/engines/mads/nebular/globals_nebular.h
@@ -24,8 +24,8 @@
#include "common/scummsys.h"
#include "common/array.h"
-#include "mads/game.h"
-#include "mads/resources.h"
+#include "mads/core/game.h"
+#include "mads/core/resources.h"
namespace MADS {
diff --git a/engines/mads/nebular/menu_nebular.cpp b/engines/mads/nebular/menu_nebular.cpp
index a2f140898f4..418ba2e2576 100644
--- a/engines/mads/nebular/menu_nebular.cpp
+++ b/engines/mads/nebular/menu_nebular.cpp
@@ -21,12 +21,12 @@
#include "common/scummsys.h"
#include "common/config-manager.h"
-#include "mads/game.h"
-#include "mads/mads.h"
-#include "mads/menu_views.h"
-#include "mads/resources.h"
-#include "mads/scene.h"
-#include "mads/screen.h"
+#include "mads/core/game.h"
+#include "mads/nebular/nebular.h"
+#include "mads/core/menu_views.h"
+#include "mads/core/resources.h"
+#include "mads/core/scene.h"
+#include "mads/core/screen.h"
#include "mads/nebular/menu_nebular.h"
namespace MADS {
@@ -37,7 +37,7 @@ namespace Nebular {
#define MADS_MENU_Y ((MADS_SCREEN_HEIGHT - MADS_SCENE_HEIGHT) / 2)
#define MADS_MENU_ANIM_DELAY 70
-MainMenu::MainMenu(MADSEngine *vm): MenuView(vm) {
+MainMenu::MainMenu(RexNebularEngine *vm): MenuView(vm) {
Common::fill(&_menuItems[0], &_menuItems[7], (SpriteAsset *)nullptr);
Common::fill(&_menuItemIndexes[0], &_menuItemIndexes[7], -1);
_delayTimeout = 0;
@@ -371,7 +371,7 @@ void MainMenu::handleAction(MADSGameAction action) {
/*------------------------------------------------------------------------*/
-AdvertView::AdvertView(MADSEngine *vm): EventTarget(), _vm(vm) {
+AdvertView::AdvertView(RexNebularEngine *vm): EventTarget(), _vm(vm) {
_breakFlag = false;
}
diff --git a/engines/mads/nebular/menu_nebular.h b/engines/mads/nebular/menu_nebular.h
index 41c606844af..2f5466c027b 100644
--- a/engines/mads/nebular/menu_nebular.h
+++ b/engines/mads/nebular/menu_nebular.h
@@ -23,9 +23,9 @@
#define MADS_MENU_NEBULAR_H
#include "common/scummsys.h"
-#include "mads/game.h"
-#include "mads/menu_views.h"
-#include "mads/msurface.h"
+#include "mads/core/game.h"
+#include "mads/core/menu_views.h"
+#include "mads/core/msurface.h"
#include "mads/nebular/dialogs_nebular.h"
namespace MADS {
@@ -110,7 +110,7 @@ protected:
*/
bool onEvent(Common::Event &event) override;
public:
- MainMenu(MADSEngine *vm);
+ MainMenu(RexNebularEngine *vm);
~MainMenu() override;
};
@@ -120,7 +120,7 @@ private:
/**
* Engine reference
*/
- MADSEngine *_vm;
+ RexNebularEngine *_vm;
/**
* Signals when to close the dialog
@@ -132,7 +132,7 @@ protected:
*/
bool onEvent(Common::Event &event) override;
public:
- AdvertView(MADSEngine *vm);
+ AdvertView(RexNebularEngine *vm);
~AdvertView() override {}
@@ -146,12 +146,12 @@ class RexAnimationView : public AnimationView {
protected:
void scriptDone() override;
public:
- RexAnimationView(MADSEngine *vm) : AnimationView(vm) {}
+ RexAnimationView(RexNebularEngine *vm) : AnimationView(vm) {}
};
class RexTextView : public TextView {
public:
- RexTextView(MADSEngine *vm) : TextView(vm) {}
+ RexTextView(RexNebularEngine *vm) : TextView(vm) {}
};
} // End of namespace Nebular
diff --git a/engines/mads/nebular/nebular.cpp b/engines/mads/nebular/nebular.cpp
new file mode 100644
index 00000000000..82ded3fe8ac
--- /dev/null
+++ b/engines/mads/nebular/nebular.cpp
@@ -0,0 +1,210 @@
+/* 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/scummsys.h"
+#include "common/config-manager.h"
+#include "common/debug-channels.h"
+#include "common/events.h"
+#include "common/text-to-speech.h"
+#include "engines/util.h"
+#include "mads/nebular/nebular.h"
+#include "mads/core/game.h"
+#include "mads/core/screen.h"
+#include "mads/core/msurface.h"
+#include "mads/core/resources.h"
+#include "mads/core/sound.h"
+#include "mads/core/sprites.h"
+#include "mads/core/mps_installer.h"
+
+namespace MADS {
+
+RexNebularEngine *g_engine;
+
+RexNebularEngine::RexNebularEngine(OSystem *syst, const MADSGameDescription *gameDesc) :
+ MADSEngine(syst, gameDesc) {
+ // Initialize game/engine options
+ _easyMouse = true;
+ _invObjectsAnimated = true;
+ _textWindowStill = false;
+ _screenFade = SCREEN_FADE_SMOOTH;
+ _musicFlag = true;
+ _soundFlag = true;
+ _dithering = false;
+ _disableFastwalk = false;
+
+ _dialogs = nullptr;
+ _events = nullptr;
+ _font = nullptr;
+ _game = nullptr;
+ _gameConv = nullptr;
+ _palette = nullptr;
+ _resources = nullptr;
+ _sound = nullptr;
+ _audio = nullptr;
+ _screen = nullptr;
+}
+
+RexNebularEngine::~RexNebularEngine() {
+ delete _dialogs;
+ delete _events;
+ delete _font;
+ Font::deinit();
+ delete _game;
+ delete _gameConv;
+ delete _palette;
+ delete _resources;
+ delete _sound;
+ delete _audio;
+ //_debugger Debugger is deleted by Engine
+
+ _mixer->stopAll();
+}
+
+void RexNebularEngine::initialize() {
+ if (_gameDescription->desc.flags & GF_INSTALLER) {
+ // Right now used only by Rex Nebular
+ Common::Archive* arch = MpsInstaller::open("MPSLABS");
+ if (arch)
+ SearchMan.add("mpslabs", arch);
+ }
+
+ // Initial sub-system engine references
+ MSurface::setVm(this);
+ MSprite::setVm(this);
+
+ Resources::init(this);
+ Conversation::init(this);
+ _debugger = new Debugger(this);
+ setDebugger(_debugger);
+ _dialogs = Dialogs::init(this);
+ _events = new EventsManager(this);
+ _palette = new Palette(this);
+ Font::init(this);
+ _font = new Font();
+ _screen = new Screen();
+ _sound = new SoundManager(this, _mixer);
+ _audio = new AudioPlayer(_mixer, getGameID());
+ _game = Game::init(this);
+ _gameConv = new GameConversations(this);
+
+ loadOptions();
+
+ _screen->clear();
+}
+
+void RexNebularEngine::loadOptions() {
+ if (ConfMan.hasKey("EasyMouse"))
+ _easyMouse = ConfMan.getBool("EasyMouse");
+
+ if (ConfMan.hasKey("mute") && ConfMan.getBool("mute")) {
+ _soundFlag = false;
+ _musicFlag = false;
+ } else {
+ _soundFlag = !ConfMan.hasKey("sfx_mute") || !ConfMan.getBool("sfx_mute");
+ _musicFlag = !ConfMan.hasGameDomain("music_mute") || !ConfMan.getBool("music_mute");
+ }
+
+ if (ConfMan.hasKey("ScreenFade"))
+ _screenFade = (ScreenFade)ConfMan.getInt("ScreenFade");
+ //if (ConfMan.hasKey("GraphicsDithering"))
+ // _dithering = ConfMan.getBool("GraphicsDithering");
+
+ if (getGameID() == GType_RexNebular) {
+ if (ConfMan.hasKey("InvObjectsAnimated"))
+ _invObjectsAnimated = ConfMan.getBool("InvObjectsAnimated");
+ if (ConfMan.hasKey("TextWindowStill"))
+ _textWindowStill = !ConfMan.getBool("TextWindowAnimated");
+ if (ConfMan.hasKey("NaughtyMode"))
+ _game->setNaughtyMode(ConfMan.getBool("NaughtyMode"));
+ }
+
+ // Note: MADS is weird in that sfx and music are handled by the same driver,
+ // and the game scripts themselves check for music being enabled before playing
+ // a "music" sound. Which means we can independently mute music in ScummVM, but
+ // otherwise all sound, music and sfx, is controlled by the SFX volume slider.
+ int soundVolume = MIN(255, ConfMan.getInt("sfx_volume"));
+ _sound->setVolume(soundVolume);
+
+ Common::TextToSpeechManager *ttsMan = g_system->getTextToSpeechManager();
+ if (ttsMan != nullptr)
+ ttsMan->enable(ConfMan.getBool("tts_narrator"));
+}
+
+void RexNebularEngine::saveOptions() {
+ ConfMan.setBool("EasyMouse", _easyMouse);
+ ConfMan.setInt("ScreenFade", (int)_screenFade);
+ //ConfMan.setBool("GraphicsDithering", _dithering);
+
+ ConfMan.setBool("mute", !_soundFlag && !_musicFlag);
+ ConfMan.setBool("sfx_mute", !_soundFlag && _musicFlag);
+ ConfMan.setBool("music_mute", _soundFlag && !_musicFlag);
+
+ if (getGameID() == GType_RexNebular) {
+ ConfMan.setBool("InvObjectsAnimated", _invObjectsAnimated);
+ ConfMan.setBool("TextWindowAnimated", !_textWindowStill);
+ ConfMan.setBool("NaughtyMode", _game->getNaughtyMode());
+ }
+
+ ConfMan.flushToDisk();
+}
+
+Common::Error RexNebularEngine::run() {
+ initGraphics(MADS_SCREEN_WIDTH, MADS_SCREEN_HEIGHT);
+ initialize();
+
+ // Run the game
+ _game->run();
+
+ return Common::kNoError;
+}
+
+bool RexNebularEngine::canLoadGameStateCurrently(Common::U32String *msg) {
+ return !_game->_winStatus && !_game->globals()[5]
+ && _dialogs->_pendingDialog == DIALOG_NONE
+ && _events->_cursorId != CURSOR_WAIT;
+}
+
+bool RexNebularEngine::canSaveGameStateCurrently(Common::U32String *msg) {
+ return !_game->_winStatus && !_game->globals()[5]
+ && _dialogs->_pendingDialog == DIALOG_NONE
+ && _events->_cursorId != CURSOR_WAIT
+ && _game->_scene._sceneLogic;
+}
+
+void RexNebularEngine::syncSoundSettings() {
+ Engine::syncSoundSettings();
+
+ loadOptions();
+}
+
+Common::Error RexNebularEngine::loadGameState(int slot) {
+ _game->_loadGameSlot = slot;
+ _game->_scene._currentSceneId = -1;
+ _game->_currentSectionNumber = -1;
+ return Common::kNoError;
+}
+
+Common::Error RexNebularEngine::saveGameState(int slot, const Common::String &desc, bool isAutosave) {
+ _game->saveGame(slot, desc);
+ return Common::kNoError;
+}
+
+} // End of namespace MADS
diff --git a/engines/mads/nebular/nebular.h b/engines/mads/nebular/nebular.h
new file mode 100644
index 00000000000..287b5589d37
--- /dev/null
+++ b/engines/mads/nebular/nebular.h
@@ -0,0 +1,133 @@
+/* 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 MADS_NEBULAR_H
+#define MADS_NEBULAR_H
+
+#include "common/scummsys.h"
+#include "common/system.h"
+#include "common/error.h"
+#include "common/random.h"
+#include "common/util.h"
+#include "engines/engine.h"
+#include "graphics/surface.h"
+#include "mads/mads.h"
+#include "mads/nebular/debugger.h"
+#include "mads/core/conversations.h"
+#include "mads/core/dialogs.h"
+#include "mads/core/events.h"
+#include "mads/core/font.h"
+#include "mads/core/game.h"
+#include "mads/core/screen.h"
+#include "mads/core/msurface.h"
+#include "mads/core/resources.h"
+#include "mads/core/sound.h"
+
+namespace MADS {
+
+#define DEBUG_BASIC 1
+#define DEBUG_INTERMEDIATE 2
+#define DEBUG_DETAILED 3
+
+enum MADSActions {
+ kActionNone,
+ kActionEscape,
+ kActionGameMenu,
+ kActionSave,
+ kActionRestore,
+ kActionScrollUp,
+ kActionScrollDown,
+ kActionStartGame,
+ kActionResumeGame,
+ kActionShowIntro,
+ kActionCredits,
+ kActionQuotes,
+ kActionRestartAnimation
+};
+
+class RexNebularEngine : public MADSEngine {
+private:
+ /**
+ * Handles basic initialisation
+ */
+ void initialize();
+
+ void loadOptions();
+
+protected:
+ // Engine APIs
+ Common::Error run() override;
+
+public:
+ Debugger *_debugger;
+ Dialogs *_dialogs;
+ EventsManager *_events;
+ Font *_font;
+ Game *_game;
+ GameConversations * _gameConv;
+ Palette *_palette;
+ Resources *_resources;
+ Screen *_screen;
+ SoundManager *_sound;
+ AudioPlayer *_audio;
+ bool _easyMouse;
+ bool _invObjectsAnimated;
+ bool _textWindowStill;
+ ScreenFade _screenFade;
+ bool _musicFlag;
+ bool _soundFlag;
+ bool _dithering;
+ bool _disableFastwalk;
+public:
+ RexNebularEngine(OSystem *syst, const MADSGameDescription *gameDesc);
+ ~RexNebularEngine() override;
+
+ /**
+ * Returns true if it is currently okay to restore a game
+ */
+ bool canLoadGameStateCurrently(Common::U32String *msg = nullptr) override;
+
+ /**
+ * Returns true if it is currently okay to save the game
+ */
+ bool canSaveGameStateCurrently(Common::U32String *msg = nullptr) override;
+
+ /**
+ * Handles loading a game via the GMM
+ */
+ Common::Error loadGameState(int slot) override;
+
+ /**
+ * Handles saving the game via the GMM
+ */
+ Common::Error saveGameState(int slot, const Common::String &desc, bool isAutosave = false) override;
+
+ /**
+ * Handles updating sound settings after they're changed in the GMM dialog
+ */
+ void syncSoundSettings() override;
+
+ void saveOptions();
+};
+
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/nebular/nebular_scenes.cpp b/engines/mads/nebular/nebular_scenes.cpp
index 1728f9e760e..855536ca3a2 100644
--- a/engines/mads/nebular/nebular_scenes.cpp
+++ b/engines/mads/nebular/nebular_scenes.cpp
@@ -21,10 +21,10 @@
#include "common/scummsys.h"
#include "common/config-manager.h"
-#include "mads/mads.h"
-#include "mads/compression.h"
-#include "mads/resources.h"
-#include "mads/scene.h"
+#include "mads/nebular/nebular.h"
+#include "mads/core/compression.h"
+#include "mads/core/resources.h"
+#include "mads/core/scene.h"
#include "mads/nebular/game_nebular.h"
#include "mads/nebular/nebular_scenes.h"
#include "mads/nebular/nebular_scenes1.h"
@@ -40,7 +40,7 @@ namespace MADS {
namespace Nebular {
-SceneLogic *SceneFactory::createScene(MADSEngine *vm) {
+SceneLogic *SceneFactory::createScene(RexNebularEngine *vm) {
Scene &scene = vm->_game->_scene;
scene.addActiveVocab(NOUN_DROP);
@@ -297,7 +297,7 @@ SceneLogic *SceneFactory::createScene(MADSEngine *vm) {
/*------------------------------------------------------------------------*/
-NebularScene::NebularScene(MADSEngine *vm) : SceneLogic(vm),
+NebularScene::NebularScene(RexNebularEngine *vm) : SceneLogic(vm),
_globals(static_cast<GameNebular *>(vm->_game)->_globals),
_game(*static_cast<GameNebular *>(vm->_game)),
_action(vm->_game->_scene._action) {
@@ -343,7 +343,7 @@ void SceneInfoNebular::loadCodes(BaseSurface &depthSurface, Common::SeekableRead
/*------------------------------------------------------------------------*/
-SceneTeleporter::SceneTeleporter(MADSEngine *vm) : NebularScene(vm) {
+SceneTeleporter::SceneTeleporter(RexNebularEngine *vm) : NebularScene(vm) {
_buttonTyped = -1;
_curCode = -1;
_digitCount = -1;
diff --git a/engines/mads/nebular/nebular_scenes.h b/engines/mads/nebular/nebular_scenes.h
index f1a95b272ef..31c375d86d3 100644
--- a/engines/mads/nebular/nebular_scenes.h
+++ b/engines/mads/nebular/nebular_scenes.h
@@ -23,8 +23,8 @@
#define MADS_NEBULAR_SCENES_H
#include "common/scummsys.h"
-#include "mads/game.h"
-#include "mads/scene.h"
+#include "mads/core/game.h"
+#include "mads/core/scene.h"
#include "mads/nebular/game_nebular.h"
#include "mads/nebular/globals_nebular.h"
@@ -1339,7 +1339,7 @@ enum Noun {
class SceneFactory {
public:
- static SceneLogic *createScene(MADSEngine *vm);
+ static SceneLogic *createScene(RexNebularEngine *vm);
};
/**
@@ -1364,7 +1364,7 @@ public:
/**
* Constructor
*/
- NebularScene(MADSEngine *vm);
+ NebularScene(RexNebularEngine *vm);
void sub7178C();
};
@@ -1379,7 +1379,7 @@ protected:
/**
* Constructor
*/
- SceneInfoNebular(MADSEngine *vm) : SceneInfo(vm) {}
+ SceneInfoNebular(RexNebularEngine *vm) : SceneInfo(vm) {}
};
class SceneTeleporter : public NebularScene {
@@ -1408,7 +1408,7 @@ protected:
/**
* Constructor
*/
- SceneTeleporter(MADSEngine *vm);
+ SceneTeleporter(RexNebularEngine *vm);
};
} // End of namespace Nebular
diff --git a/engines/mads/nebular/nebular_scenes1.cpp b/engines/mads/nebular/nebular_scenes1.cpp
index eaba6928a34..e1dc8818206 100644
--- a/engines/mads/nebular/nebular_scenes1.cpp
+++ b/engines/mads/nebular/nebular_scenes1.cpp
@@ -21,8 +21,8 @@
#include "common/scummsys.h"
#include "math/utils.h"
-#include "mads/mads.h"
-#include "mads/scene.h"
+#include "mads/nebular/nebular.h"
+#include "mads/core/scene.h"
#include "mads/nebular/nebular_scenes.h"
#include "mads/nebular/nebular_scenes1.h"
@@ -99,7 +99,7 @@ void Scene1xx::setPlayerSpritesPrefix() {
/*------------------------------------------------------------------------*/
-Scene101::Scene101(MADSEngine *vm) : Scene1xx(vm) {
+Scene101::Scene101(RexNebularEngine *vm) : Scene1xx(vm) {
_sittingFl = false;
_panelOpened = false;
_messageNum = 0;
@@ -643,7 +643,7 @@ void Scene101::actions() {
/*------------------------------------------------------------------------*/
-Scene102::Scene102(MADSEngine *vm) : Scene1xx(vm) {
+Scene102::Scene102(RexNebularEngine *vm) : Scene1xx(vm) {
_fridgeOpenedFl = false;
_fridgeOpenedDescr = false;
_fridgeFirstOpenFl = false;
@@ -1278,7 +1278,7 @@ void Scene102::postActions() {
/*------------------------------------------------------------------------*/
-Scene103::Scene103(MADSEngine *vm) : Scene1xx(vm) {
+Scene103::Scene103(RexNebularEngine *vm) : Scene1xx(vm) {
_updateClock = 0;
}
@@ -1599,7 +1599,7 @@ void Scene103::postActions() {
/*------------------------------------------------------------------------*/
-Scene104::Scene104(MADSEngine *vm) : Scene1xx(vm) {
+Scene104::Scene104(RexNebularEngine *vm) : Scene1xx(vm) {
_kargShootingFl = false;
_loseFl = false;
}
@@ -1815,7 +1815,7 @@ void Scene104::actions() {
/*------------------------------------------------------------------------*/
-Scene105::Scene105(MADSEngine *vm) : Scene1xx(vm) {
+Scene105::Scene105(RexNebularEngine *vm) : Scene1xx(vm) {
_explosionFl = false;
}
@@ -1974,7 +1974,7 @@ void Scene105::actions() {
/*------------------------------------------------------------------------*/
-Scene106::Scene106(MADSEngine *vm) : Scene1xx(vm) {
+Scene106::Scene106(RexNebularEngine *vm) : Scene1xx(vm) {
_backToShipFl = false;
_shadowFl = false;
_firstEmergingFl = false;
@@ -2197,7 +2197,7 @@ void Scene106::actions() {
/*------------------------------------------------------------------------*/
-Scene107::Scene107(MADSEngine *vm) : Scene1xx(vm) {
+Scene107::Scene107(RexNebularEngine *vm) : Scene1xx(vm) {
_shootingFl = false;
}
@@ -2407,7 +2407,7 @@ void Scene108::actions() {
/*------------------------------------------------------------------------*/
-Scene109::Scene109(MADSEngine *vm) : Scene1xx(vm) {
+Scene109::Scene109(RexNebularEngine *vm) : Scene1xx(vm) {
_rexThrowingObject = false;
_hoovicDifficultFl = false;
_beforeEatingRex = false;
@@ -2832,7 +2832,7 @@ void Scene109::actions() {
/*------------------------------------------------------------------------*/
-Scene110::Scene110(MADSEngine *vm) : Scene1xx(vm) {
+Scene110::Scene110(RexNebularEngine *vm) : Scene1xx(vm) {
_crabsFl = false;
}
@@ -2966,7 +2966,7 @@ void Scene110::actions() {
/*------------------------------------------------------------------------*/
-Scene111::Scene111(MADSEngine *vm) : Scene1xx(vm) {
+Scene111::Scene111(RexNebularEngine *vm) : Scene1xx(vm) {
_stampedFl = false;
_launch1Fl = false;
_launched2Fl = false;
diff --git a/engines/mads/nebular/nebular_scenes1.h b/engines/mads/nebular/nebular_scenes1.h
index 652b789e205..683a561e40f 100644
--- a/engines/mads/nebular/nebular_scenes1.h
+++ b/engines/mads/nebular/nebular_scenes1.h
@@ -24,8 +24,8 @@
#include "common/scummsys.h"
#include "common/serializer.h"
-#include "mads/game.h"
-#include "mads/scene.h"
+#include "mads/core/game.h"
+#include "mads/core/scene.h"
#include "mads/nebular/nebular_scenes.h"
namespace MADS {
@@ -49,7 +49,7 @@ protected:
*/
void setPlayerSpritesPrefix();
public:
- Scene1xx(MADSEngine *vm) : NebularScene(vm) {}
+ Scene1xx(RexNebularEngine *vm) : NebularScene(vm) {}
};
class Scene101 : public Scene1xx {
@@ -66,7 +66,7 @@ private:
void sayDang();
public:
- Scene101(MADSEngine *vm);
+ Scene101(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -90,7 +90,7 @@ private:
void addRandomMessage();
public:
- Scene102(MADSEngine *vm);
+ Scene102(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -106,7 +106,7 @@ private:
uint32 _updateClock;
public:
- Scene103(MADSEngine *vm);
+ Scene103(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -122,7 +122,7 @@ private:
bool _loseFl;
public:
- Scene104(MADSEngine *vm);
+ Scene104(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -137,7 +137,7 @@ private:
bool _explosionFl;
public:
- Scene105(MADSEngine *vm);
+ Scene105(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -156,7 +156,7 @@ private:
int _positionY;
public:
- Scene106(MADSEngine *vm);
+ Scene106(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -171,7 +171,7 @@ private:
bool _shootingFl;
public:
- Scene107(MADSEngine *vm);
+ Scene107(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -183,7 +183,7 @@ public:
class Scene108 : public Scene1xx {
public:
- Scene108(MADSEngine *vm) : Scene1xx(vm) {}
+ Scene108(RexNebularEngine *vm) : Scene1xx(vm) {}
void setup() override;
void enter() override;
@@ -204,7 +204,7 @@ private:
int _hoovicTrigger;
public:
- Scene109(MADSEngine *vm);
+ Scene109(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -219,7 +219,7 @@ private:
bool _crabsFl;
public:
- Scene110(MADSEngine *vm);
+ Scene110(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -237,7 +237,7 @@ private:
bool _rexDivingFl;
public:
- Scene111(MADSEngine *vm);
+ Scene111(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -249,7 +249,7 @@ public:
class Scene112 : public Scene1xx {
public:
- Scene112(MADSEngine *vm) : Scene1xx(vm) {}
+ Scene112(RexNebularEngine *vm) : Scene1xx(vm) {}
void setup() override;
void enter() override;
diff --git a/engines/mads/nebular/nebular_scenes2.cpp b/engines/mads/nebular/nebular_scenes2.cpp
index 93716331c40..efa0a0e91a6 100644
--- a/engines/mads/nebular/nebular_scenes2.cpp
+++ b/engines/mads/nebular/nebular_scenes2.cpp
@@ -20,8 +20,8 @@
*/
#include "common/scummsys.h"
-#include "mads/mads.h"
-#include "mads/scene.h"
+#include "mads/nebular/nebular.h"
+#include "mads/core/scene.h"
#include "mads/nebular/nebular_scenes.h"
#include "mads/nebular/nebular_scenes2.h"
@@ -116,7 +116,7 @@ void Scene2xx::sceneEntrySound() {
/*------------------------------------------------------------------------*/
-Scene201::Scene201(MADSEngine *vm) : Scene2xx(vm) {
+Scene201::Scene201(RexNebularEngine *vm) : Scene2xx(vm) {
_pterodactylFlag = false;
}
@@ -337,7 +337,7 @@ void Scene201::actions() {
/*------------------------------------------------------------------------*/
-Scene202::Scene202(MADSEngine *vm) : Scene2xx(vm) {
+Scene202::Scene202(RexNebularEngine *vm) : Scene2xx(vm) {
_activeMsgFl = false;
_ladderTopFl = false;
_waitingMeteoFl = false;
@@ -1022,7 +1022,7 @@ void Scene202::actions() {
/*****************************************************************************/
-Scene203::Scene203(MADSEngine *vm) : Scene2xx(vm) {
+Scene203::Scene203(RexNebularEngine *vm) : Scene2xx(vm) {
_rhotundaEat2Fl = false;
_rhotundaEatFl = false;
}
@@ -1154,7 +1154,7 @@ void Scene205::setup() {
_scene->addActiveVocab(NOUN_PIRANHA);
}
-Scene205::Scene205(MADSEngine *vm) : Scene2xx(vm) {
+Scene205::Scene205(RexNebularEngine *vm) : Scene2xx(vm) {
_lastFishTime = _scene->_frameStartTime;
_chickenTime = _scene->_frameStartTime;
@@ -1443,7 +1443,7 @@ void Scene205::actions() {
/*****************************************************************************/
-Scene207::Scene207(MADSEngine *vm) : Scene2xx(vm) {
+Scene207::Scene207(RexNebularEngine *vm) : Scene2xx(vm) {
_vultureFl = false;
_spiderFl = false;
_eyeFl = false;
@@ -1655,7 +1655,7 @@ void Scene207::actions() {
/*****************************************************************************/
-Scene208::Scene208(MADSEngine *vm) : Scene2xx(vm) {
+Scene208::Scene208(RexNebularEngine *vm) : Scene2xx(vm) {
_rhotundaTurnFl = false;
_boundingFl = false;
_rhotundaTime = 0;
@@ -1962,7 +1962,7 @@ void Scene208::actions() {
/*****************************************************************************/
-Scene209::Scene209(MADSEngine *vm) : Scene2xx(vm) {
+Scene209::Scene209(RexNebularEngine *vm) : Scene2xx(vm) {
_dodgeFl = false;
_forceDodgeFl = false;
_pitchFl = false;
@@ -3678,7 +3678,7 @@ void Scene209::actions() {
/*****************************************************************************/
-Scene210::Scene210(MADSEngine *vm) : Scene2xx(vm) {
+Scene210::Scene210(RexNebularEngine *vm) : Scene2xx(vm) {
_curDialogNode = -1;
_nextHandsPlace = 0;
_twinkleAnimationType = 0;
@@ -4732,7 +4732,7 @@ void Scene210::actions() {
/*------------------------------------------------------------------------*/
-Scene211::Scene211(MADSEngine *vm) : Scene2xx(vm) {
+Scene211::Scene211(RexNebularEngine *vm) : Scene2xx(vm) {
_ambushFl = false;
_wakeFl = false;
_monkeyFrame = 0;
@@ -5151,7 +5151,7 @@ void Scene213::actions() {
/*------------------------------------------------------------------------*/
-Scene214::Scene214(MADSEngine *vm) : Scene2xx(vm) {
+Scene214::Scene214(RexNebularEngine *vm) : Scene2xx(vm) {
_devilTime = 0;
_devilRunningFl = false;
}
diff --git a/engines/mads/nebular/nebular_scenes2.h b/engines/mads/nebular/nebular_scenes2.h
index 0379a712678..8a05a58561f 100644
--- a/engines/mads/nebular/nebular_scenes2.h
+++ b/engines/mads/nebular/nebular_scenes2.h
@@ -23,8 +23,8 @@
#define MADS_NEBULAR_SCENES2_H
#include "common/scummsys.h"
-#include "mads/game.h"
-#include "mads/scene.h"
+#include "mads/core/game.h"
+#include "mads/core/scene.h"
#include "mads/nebular/nebular_scenes.h"
namespace MADS {
@@ -45,7 +45,7 @@ protected:
void sceneEntrySound();
public:
- Scene2xx(MADSEngine *vm) : NebularScene(vm) {}
+ Scene2xx(RexNebularEngine *vm) : NebularScene(vm) {}
};
class Scene201 : public Scene2xx {
@@ -53,7 +53,7 @@ private:
bool _pterodactylFlag;
public:
- Scene201(MADSEngine *vm);
+ Scene201(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -75,7 +75,7 @@ private:
int subStep4(int randVal);
public:
- Scene202(MADSEngine *vm);
+ Scene202(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -92,7 +92,7 @@ private:
bool _rhotundaEat2Fl, _rhotundaEatFl;
public:
- Scene203(MADSEngine *vm);
+ Scene203(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -112,7 +112,7 @@ private:
void handleWomanSpeech(int quoteId);
public:
- Scene205(MADSEngine *vm);
+ Scene205(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -131,7 +131,7 @@ private:
void moveSpider();
public:
- Scene207(MADSEngine *vm);
+ Scene207(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -150,7 +150,7 @@ private:
void subAction(int mode);
public:
- Scene208(MADSEngine *vm);
+ Scene208(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -196,7 +196,7 @@ private:
void handleMonkey2();
public:
- Scene209(MADSEngine *vm);
+ Scene209(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -235,7 +235,7 @@ private:
void restoreDialogNode(int node, int msgId, int posY);
public:
- Scene210(MADSEngine *vm);
+ Scene210(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -252,7 +252,7 @@ private:
uint32 _monkeyTime;
public:
- Scene211(MADSEngine *vm);
+ Scene211(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -264,7 +264,7 @@ public:
class Scene212 : public Scene2xx {
public:
- Scene212(MADSEngine *vm) : Scene2xx(vm) {}
+ Scene212(RexNebularEngine *vm) : Scene2xx(vm) {}
void setup() override;
void enter() override;
void step() override;
@@ -274,7 +274,7 @@ public:
class Scene213 : public SceneTeleporter {
public:
- Scene213(MADSEngine *vm) : SceneTeleporter(vm) {}
+ Scene213(RexNebularEngine *vm) : SceneTeleporter(vm) {}
void setup() override;
void enter() override;
@@ -288,7 +288,7 @@ private:
bool _devilRunningFl;
public:
- Scene214(MADSEngine *vm);
+ Scene214(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -299,7 +299,7 @@ public:
class Scene215 : public Scene2xx {
public:
- Scene215(MADSEngine *vm) : Scene2xx(vm) {}
+ Scene215(RexNebularEngine *vm) : Scene2xx(vm) {}
void setup() override;
void enter() override;
@@ -309,7 +309,7 @@ public:
class Scene216 : public Scene2xx {
public:
- Scene216(MADSEngine *vm) : Scene2xx(vm) {}
+ Scene216(RexNebularEngine *vm) : Scene2xx(vm) {}
void setup() override;
void enter() override;
diff --git a/engines/mads/nebular/nebular_scenes3.cpp b/engines/mads/nebular/nebular_scenes3.cpp
index 009d6568a6d..7435fa324f9 100644
--- a/engines/mads/nebular/nebular_scenes3.cpp
+++ b/engines/mads/nebular/nebular_scenes3.cpp
@@ -20,8 +20,8 @@
*/
#include "common/scummsys.h"
-#include "mads/mads.h"
-#include "mads/scene.h"
+#include "mads/nebular/nebular.h"
+#include "mads/core/scene.h"
#include "mads/nebular/nebular_scenes.h"
#include "mads/nebular/nebular_scenes3.h"
@@ -265,7 +265,7 @@ void Scene301::step() {
/*------------------------------------------------------------------------*/
-Scene302::Scene302(MADSEngine *vm) : Scene3xx(vm) {
+Scene302::Scene302(RexNebularEngine *vm) : Scene3xx(vm) {
_oldFrame = 0;
}
@@ -340,7 +340,7 @@ void Scene303::step() {
/*------------------------------------------------------------------------*/
-Scene304::Scene304(MADSEngine *vm) : Scene3xx(vm) {
+Scene304::Scene304(RexNebularEngine *vm) : Scene3xx(vm) {
_explosionSpriteId = -1;
}
@@ -476,7 +476,7 @@ void Scene304::step() {
/*------------------------------------------------------------------------*/
-Scene307::Scene307(MADSEngine *vm) : Scene3xx(vm) {
+Scene307::Scene307(RexNebularEngine *vm) : Scene3xx(vm) {
_afterPeeingFl = false;
_duringPeeingFl = false;
_grateOpenedFl = false;
@@ -1203,7 +1203,7 @@ void Scene307::actions() {
/*------------------------------------------------------------------------*/
-Scene308::Scene308(MADSEngine *vm) : Scene3xx(vm) {
+Scene308::Scene308(RexNebularEngine *vm) : Scene3xx(vm) {
_forceField.init();
}
@@ -1337,7 +1337,7 @@ void Scene308::step() {
/*------------------------------------------------------------------------*/
-Scene309::Scene309(MADSEngine *vm) : Scene3xx(vm) {
+Scene309::Scene309(RexNebularEngine *vm) : Scene3xx(vm) {
for (int i = 0; i < 3; i++) {
_characterSpriteIndexes[i] = -1;
_messagesIndexes[i] = -1;
@@ -1547,7 +1547,7 @@ void Scene309::step() {
/*------------------------------------------------------------------------*/
-Scene310::Scene310(MADSEngine *vm) : Scene3xx(vm) {
+Scene310::Scene310(RexNebularEngine *vm) : Scene3xx(vm) {
_forceField.init();
}
@@ -1590,7 +1590,7 @@ void Scene310::step() {
/*------------------------------------------------------------------------*/
-Scene311::Scene311(MADSEngine *vm) : Scene3xx(vm) {
+Scene311::Scene311(RexNebularEngine *vm) : Scene3xx(vm) {
_checkGuardFl = false;
}
@@ -2421,7 +2421,7 @@ void Scene316::actions() {
/*------------------------------------------------------------------------*/
-Scene318::Scene318(MADSEngine *vm) : Scene3xx(vm) {
+Scene318::Scene318(RexNebularEngine *vm) : Scene3xx(vm) {
_dropTimer = 0;
_lastFrame = -1;
@@ -3064,7 +3064,7 @@ void Scene318::actions() {
/*------------------------------------------------------------------------*/
-Scene319::Scene319(MADSEngine *vm) : Scene3xx(vm) {
+Scene319::Scene319(RexNebularEngine *vm) : Scene3xx(vm) {
_animMode = -1;
_animFrame = -1;
_nextAction1 = -1;
@@ -3566,7 +3566,7 @@ void Scene319::actions() {
/*------------------------------------------------------------------------*/
-Scene320::Scene320(MADSEngine *vm) : Scene300s(vm) {
+Scene320::Scene320(RexNebularEngine *vm) : Scene300s(vm) {
_blinkFl = false;
_flippedFl = false;
@@ -4160,7 +4160,7 @@ void Scene351::actions() {
/*------------------------------------------------------------------------*/
-Scene352::Scene352(MADSEngine *vm) : Scene3xx(vm) {
+Scene352::Scene352(RexNebularEngine *vm) : Scene3xx(vm) {
_vaultOpenFl = false;
_mustPutArmDownFl = false;
_leaveRoomFl = false;
@@ -4972,7 +4972,7 @@ void Scene358::actions() {
/*------------------------------------------------------------------------*/
-Scene359::Scene359(MADSEngine *vm) : Scene3xx(vm) {
+Scene359::Scene359(RexNebularEngine *vm) : Scene3xx(vm) {
_cardHotspotId = -1;
}
@@ -5681,7 +5681,7 @@ void Scene388::actions() {
/*------------------------------------------------------------------------*/
-Scene389::Scene389(MADSEngine *vm) : Scene300s(vm) {
+Scene389::Scene389(RexNebularEngine *vm) : Scene300s(vm) {
_monsterTime = 0;
_circularQuoteId = -1;
}
diff --git a/engines/mads/nebular/nebular_scenes3.h b/engines/mads/nebular/nebular_scenes3.h
index 257a7d99f8d..baf0d9880b6 100644
--- a/engines/mads/nebular/nebular_scenes3.h
+++ b/engines/mads/nebular/nebular_scenes3.h
@@ -23,8 +23,8 @@
#define MADS_NEBULAR_SCENES3_H
#include "common/scummsys.h"
-#include "mads/game.h"
-#include "mads/scene.h"
+#include "mads/core/game.h"
+#include "mads/core/scene.h"
#include "mads/nebular/nebular_scenes.h"
namespace MADS {
@@ -75,21 +75,21 @@ protected:
int computeScale(int low, int high, int id);
public:
- Scene3xx(MADSEngine *vm) : NebularScene(vm) {}
+ Scene3xx(RexNebularEngine *vm) : NebularScene(vm) {}
void actions() override {}
};
class Scene300s : public Scene3xx {
public:
- Scene300s(MADSEngine *vm) : Scene3xx(vm) {}
+ Scene300s(RexNebularEngine *vm) : Scene3xx(vm) {}
void preActions() override;
};
class Scene301 : public Scene3xx {
public:
- Scene301(MADSEngine *vm) : Scene3xx(vm) {}
+ Scene301(RexNebularEngine *vm) : Scene3xx(vm) {}
void setup() override;
void enter() override;
@@ -101,7 +101,7 @@ private:
int _oldFrame;
public:
- Scene302(MADSEngine *vm);
+ Scene302(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -111,7 +111,7 @@ public:
class Scene303 : public Scene3xx {
public:
- Scene303(MADSEngine *vm) : Scene3xx(vm) {}
+ Scene303(RexNebularEngine *vm) : Scene3xx(vm) {}
void setup() override;
void enter() override;
@@ -123,7 +123,7 @@ private:
int _explosionSpriteId;
public:
- Scene304(MADSEngine *vm);
+ Scene304(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -160,7 +160,7 @@ private:
void handlePrisonerSpeech(int firstQuoteId, int number, uint32 timeout);
public:
- Scene307(MADSEngine *vm);
+ Scene307(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -174,7 +174,7 @@ private:
ForceField _forceField;
public:
- Scene308(MADSEngine *vm);
+ Scene308(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -190,7 +190,7 @@ private:
int _lastFrame;
public:
- Scene309(MADSEngine *vm);
+ Scene309(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -203,7 +203,7 @@ private:
ForceField _forceField;
public:
- Scene310(MADSEngine *vm);
+ Scene310(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -216,7 +216,7 @@ private:
bool _checkGuardFl;
public:
- Scene311(MADSEngine *vm);
+ Scene311(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -227,7 +227,7 @@ public:
class Scene313 : public Scene3xx {
public:
- Scene313(MADSEngine *vm) : Scene3xx(vm) {}
+ Scene313(RexNebularEngine *vm) : Scene3xx(vm) {}
void setup() override;
void enter() override;
@@ -240,7 +240,7 @@ private:
void handleRoxInGrate();
public:
- Scene316(MADSEngine *vm) : Scene3xx(vm) {}
+ Scene316(RexNebularEngine *vm) : Scene3xx(vm) {}
void setup() override;
void enter() override;
@@ -275,7 +275,7 @@ private:
void handleInternDialog(int quoteId, int quoteNum, uint32 timeout);
public:
- Scene318(MADSEngine *vm);
+ Scene318(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -304,7 +304,7 @@ private:
void handleRexDialogues(int quote);
void handleSlacheDialogs(int quoteId, int counter, uint32 timer);
public:
- Scene319(MADSEngine *vm);
+ Scene319(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -329,7 +329,7 @@ private:
int _rightItemId;
public:
- Scene320(MADSEngine *vm);
+ Scene320(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -340,7 +340,7 @@ public:
class Scene321 : public Scene3xx {
public:
- Scene321(MADSEngine *vm) : Scene3xx(vm) {}
+ Scene321(RexNebularEngine *vm) : Scene3xx(vm) {}
void setup() override;
void enter() override;
@@ -349,7 +349,7 @@ public:
class Scene322 : public SceneTeleporter {
public:
- Scene322(MADSEngine *vm) : SceneTeleporter(vm) {}
+ Scene322(RexNebularEngine *vm) : SceneTeleporter(vm) {}
void setup() override;
void enter() override;
@@ -359,7 +359,7 @@ public:
class Scene351 : public Scene3xx {
public:
- Scene351(MADSEngine *vm) : Scene3xx(vm) {}
+ Scene351(RexNebularEngine *vm) : Scene3xx(vm) {}
void setup() override;
void enter() override;
@@ -383,7 +383,7 @@ private:
void putArmDown(bool corridorExit, bool doorwayExit);
public:
- Scene352(MADSEngine *vm);
+ Scene352(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -394,7 +394,7 @@ public:
class Scene353 : public Scene3xx {
public:
- Scene353(MADSEngine *vm) : Scene3xx(vm) {}
+ Scene353(RexNebularEngine *vm) : Scene3xx(vm) {}
void setup() override;
void enter() override;
@@ -403,7 +403,7 @@ public:
class Scene354 : public Scene3xx {
public:
- Scene354(MADSEngine *vm) : Scene3xx(vm) {}
+ Scene354(RexNebularEngine *vm) : Scene3xx(vm) {}
void setup() override;
void enter() override;
@@ -413,7 +413,7 @@ public:
class Scene357 : public Scene3xx {
public:
- Scene357(MADSEngine *vm) : Scene3xx(vm) {}
+ Scene357(RexNebularEngine *vm) : Scene3xx(vm) {}
void setup() override;
void enter() override;
@@ -423,7 +423,7 @@ public:
class Scene358 : public Scene3xx {
public:
- Scene358(MADSEngine *vm) : Scene3xx(vm) {}
+ Scene358(RexNebularEngine *vm) : Scene3xx(vm) {}
void setup() override;
void enter() override;
@@ -436,7 +436,7 @@ private:
int _cardHotspotId;
public:
- Scene359(MADSEngine *vm);
+ Scene359(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -447,7 +447,7 @@ public:
class Scene360 : public Scene3xx {
public:
- Scene360(MADSEngine *vm) : Scene3xx(vm) {}
+ Scene360(RexNebularEngine *vm) : Scene3xx(vm) {}
void setup() override;
void enter() override;
@@ -461,7 +461,7 @@ private:
void handleRoxAction();
public:
- Scene361(MADSEngine *vm) : Scene3xx(vm) {}
+ Scene361(RexNebularEngine *vm) : Scene3xx(vm) {}
void setup() override;
void enter() override;
@@ -472,7 +472,7 @@ public:
class Scene366 : public Scene300s {
public:
- Scene366(MADSEngine *vm) : Scene300s(vm) {}
+ Scene366(RexNebularEngine *vm) : Scene300s(vm) {}
void setup() override;
void enter() override;
@@ -481,7 +481,7 @@ public:
class Scene387 : public Scene300s {
public:
- Scene387(MADSEngine *vm) : Scene300s(vm) {}
+ Scene387(RexNebularEngine *vm) : Scene300s(vm) {}
void setup() override;
void enter() override;
@@ -490,7 +490,7 @@ public:
class Scene388 : public Scene300s {
public:
- Scene388(MADSEngine *vm) : Scene300s(vm) {}
+ Scene388(RexNebularEngine *vm) : Scene300s(vm) {}
void setup() override;
void enter() override;
@@ -504,7 +504,7 @@ private:
int _circularQuoteId;
public:
- Scene389(MADSEngine *vm);
+ Scene389(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -515,7 +515,7 @@ public:
class Scene390 : public Scene300s {
public:
- Scene390(MADSEngine *vm) : Scene300s(vm) {}
+ Scene390(RexNebularEngine *vm) : Scene300s(vm) {}
void setup() override;
void enter() override;
@@ -524,7 +524,7 @@ public:
class Scene391 : public Scene300s {
public:
- Scene391(MADSEngine *vm) : Scene300s(vm) {}
+ Scene391(RexNebularEngine *vm) : Scene300s(vm) {}
void setup() override;
void enter() override;
@@ -533,7 +533,7 @@ public:
class Scene399 : public Scene300s {
public:
- Scene399(MADSEngine *vm) : Scene300s(vm) {}
+ Scene399(RexNebularEngine *vm) : Scene300s(vm) {}
void setup() override;
void enter() override;
diff --git a/engines/mads/nebular/nebular_scenes4.cpp b/engines/mads/nebular/nebular_scenes4.cpp
index 16c2843ed23..c2237cf5e72 100644
--- a/engines/mads/nebular/nebular_scenes4.cpp
+++ b/engines/mads/nebular/nebular_scenes4.cpp
@@ -21,8 +21,8 @@
#include "common/scummsys.h"
#include "math/utils.h"
-#include "mads/mads.h"
-#include "mads/scene.h"
+#include "mads/nebular/nebular.h"
+#include "mads/core/scene.h"
#include "mads/nebular/nebular_scenes.h"
#include "mads/nebular/nebular_scenes4.h"
@@ -93,7 +93,7 @@ void Scene4xx::sceneEntrySound() {
/*------------------------------------------------------------------------*/
-Scene401::Scene401(MADSEngine *vm) : Scene4xx(vm), _destPos(0, 0) {
+Scene401::Scene401(RexNebularEngine *vm) : Scene4xx(vm), _destPos(0, 0) {
_northFl = false;
_timer = 0;
}
@@ -237,7 +237,7 @@ void Scene401::actions() {
/*------------------------------------------------------------------------*/
-Scene402::Scene402(MADSEngine *vm) : Scene4xx(vm) {
+Scene402::Scene402(RexNebularEngine *vm) : Scene4xx(vm) {
_lightOn = false;
_blowingSmoke = false;
_leftWomanMoving = false;
@@ -2576,7 +2576,7 @@ void Scene405::actions() {
/*------------------------------------------------------------------------*/
-Scene406::Scene406(MADSEngine *vm) : Scene4xx(vm) {
+Scene406::Scene406(RexNebularEngine *vm) : Scene4xx(vm) {
_hitStorageDoor = false;
}
@@ -2791,7 +2791,7 @@ void Scene406::actions() {
/*------------------------------------------------------------------------*/
-Scene407::Scene407(MADSEngine *vm) : Scene4xx(vm), _destPos(0, 0) {
+Scene407::Scene407(RexNebularEngine *vm) : Scene4xx(vm), _destPos(0, 0) {
_fromNorth = false;
}
@@ -3284,7 +3284,7 @@ void Scene410::actions() {
/*------------------------------------------------------------------------*/
-Scene411::Scene411(MADSEngine *vm) : Scene4xx(vm) {
+Scene411::Scene411(RexNebularEngine *vm) : Scene4xx(vm) {
_curAnimationFrame = -1;
_newIngredient = -1;
_newQuantity = -1;
@@ -4054,7 +4054,7 @@ void Scene411::actions() {
/*------------------------------------------------------------------------*/
-Scene413::Scene413(MADSEngine *vm) : Scene4xx(vm) {
+Scene413::Scene413(RexNebularEngine *vm) : Scene4xx(vm) {
_rexDeath = -1;
_canMove = -1;
}
diff --git a/engines/mads/nebular/nebular_scenes4.h b/engines/mads/nebular/nebular_scenes4.h
index cf3dd50d866..f7854df1ac4 100644
--- a/engines/mads/nebular/nebular_scenes4.h
+++ b/engines/mads/nebular/nebular_scenes4.h
@@ -23,8 +23,8 @@
#define MADS_NEBULAR_SCENES4_H
#include "common/scummsys.h"
-#include "mads/game.h"
-#include "mads/scene.h"
+#include "mads/core/game.h"
+#include "mads/core/scene.h"
#include "mads/nebular/nebular_scenes.h"
namespace MADS {
@@ -46,7 +46,7 @@ protected:
void sceneEntrySound();
public:
- Scene4xx(MADSEngine *vm) : NebularScene(vm) {}
+ Scene4xx(RexNebularEngine *vm) : NebularScene(vm) {}
};
class Scene401 : public Scene4xx {
@@ -56,7 +56,7 @@ private:
uint32 _timer;
public:
- Scene401(MADSEngine *vm);
+ Scene401(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -117,7 +117,7 @@ private:
void handleDialogs();
public:
- Scene402(MADSEngine *vm);
+ Scene402(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -129,7 +129,7 @@ public:
class Scene405 : public Scene4xx {
public:
- Scene405(MADSEngine *vm) : Scene4xx(vm) {}
+ Scene405(RexNebularEngine *vm) : Scene4xx(vm) {}
void setup() override;
void enter() override;
@@ -143,7 +143,7 @@ private:
bool _hitStorageDoor;
public:
- Scene406(MADSEngine *vm);
+ Scene406(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -159,7 +159,7 @@ private:
Common::Point _destPos;
public:
- Scene407(MADSEngine *vm);
+ Scene407(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -171,7 +171,7 @@ public:
class Scene408 : public Scene4xx {
public:
- Scene408(MADSEngine *vm) : Scene4xx(vm) {}
+ Scene408(RexNebularEngine *vm) : Scene4xx(vm) {}
void setup() override;
void enter() override;
@@ -181,7 +181,7 @@ public:
class Scene409 : public SceneTeleporter {
public:
- Scene409(MADSEngine *vm) : SceneTeleporter(vm) {}
+ Scene409(RexNebularEngine *vm) : SceneTeleporter(vm) {}
void setup() override;
void enter() override;
@@ -191,7 +191,7 @@ public:
class Scene410 : public Scene4xx {
public:
- Scene410(MADSEngine *vm) : Scene4xx(vm) {}
+ Scene410(RexNebularEngine *vm) : Scene4xx(vm) {}
void setup() override;
void enter() override;
@@ -226,7 +226,7 @@ private:
bool addIngredient();
public:
- Scene411(MADSEngine *vm);
+ Scene411(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -242,7 +242,7 @@ private:
int _canMove;
public:
- Scene413(MADSEngine *vm);
+ Scene413(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
diff --git a/engines/mads/nebular/nebular_scenes5.cpp b/engines/mads/nebular/nebular_scenes5.cpp
index 4fbc5e88363..790c41f1c07 100644
--- a/engines/mads/nebular/nebular_scenes5.cpp
+++ b/engines/mads/nebular/nebular_scenes5.cpp
@@ -20,8 +20,8 @@
*/
#include "common/scummsys.h"
-#include "mads/mads.h"
-#include "mads/scene.h"
+#include "mads/nebular/nebular.h"
+#include "mads/core/scene.h"
#include "mads/nebular/nebular_scenes.h"
#include "mads/nebular/nebular_scenes5.h"
@@ -91,7 +91,7 @@ void Scene5xx::sceneEntrySound() {
/*------------------------------------------------------------------------*/
-Scene501::Scene501(MADSEngine *vm) : Scene5xx(vm) {
+Scene501::Scene501(RexNebularEngine *vm) : Scene5xx(vm) {
_mainSequenceId = -1;
_mainSpriteId = -1;
_doorHotspotid = -1;
@@ -531,7 +531,7 @@ void Scene502::actions() {
/*------------------------------------------------------------------------*/
-Scene503::Scene503(MADSEngine *vm) : Scene5xx(vm) {
+Scene503::Scene503(RexNebularEngine *vm) : Scene5xx(vm) {
_detonatorHotspotId = -1;
}
@@ -663,7 +663,7 @@ void Scene503::actions() {
/*------------------------------------------------------------------------*/
-Scene504::Scene504(MADSEngine *vm) : Scene5xx(vm) {
+Scene504::Scene504(RexNebularEngine *vm) : Scene5xx(vm) {
_carAnimationMode = -1;
_carFrame = -1;
}
@@ -872,7 +872,7 @@ void Scene504::actions() {
/*------------------------------------------------------------------------*/
-Scene505::Scene505(MADSEngine *vm) : Scene5xx(vm) {
+Scene505::Scene505(RexNebularEngine *vm) : Scene5xx(vm) {
_frame = -1;
_nextButtonId = -1;
_homeSelectedId = -1;
@@ -1150,7 +1150,7 @@ void Scene505::actions() {
/*------------------------------------------------------------------------*/
-Scene506::Scene506(MADSEngine *vm) : Scene5xx(vm), _doorPos(0, 0) {
+Scene506::Scene506(RexNebularEngine *vm) : Scene5xx(vm), _doorPos(0, 0) {
_heroFacing = FACING_DUMMY;
_doorDepth = -1;
@@ -1443,7 +1443,7 @@ void Scene506::actions() {
/*------------------------------------------------------------------------*/
-Scene507::Scene507(MADSEngine *vm) : Scene5xx(vm) {
+Scene507::Scene507(RexNebularEngine *vm) : Scene5xx(vm) {
_penlightHotspotId = -1;
}
@@ -1566,7 +1566,7 @@ void Scene507::actions() {
/*------------------------------------------------------------------------*/
-Scene508::Scene508(MADSEngine *vm) : Scene5xx(vm) {
+Scene508::Scene508(RexNebularEngine *vm) : Scene5xx(vm) {
_chosenObject = -1;
}
@@ -1835,7 +1835,7 @@ void Scene508::actions() {
/*------------------------------------------------------------------------*/
-Scene511::Scene511(MADSEngine *vm) : Scene5xx(vm) {
+Scene511::Scene511(RexNebularEngine *vm) : Scene5xx(vm) {
_handingLine = false;
_lineMoving = false;
@@ -2181,7 +2181,7 @@ void Scene511::actions() {
/*------------------------------------------------------------------------*/
-Scene512::Scene512(MADSEngine *vm) : Scene5xx(vm) {
+Scene512::Scene512(RexNebularEngine *vm) : Scene5xx(vm) {
_fishingRodHotspotId = -1;
_keyHotspotId = -1;
}
diff --git a/engines/mads/nebular/nebular_scenes5.h b/engines/mads/nebular/nebular_scenes5.h
index afd5fcf4763..c34b1aac529 100644
--- a/engines/mads/nebular/nebular_scenes5.h
+++ b/engines/mads/nebular/nebular_scenes5.h
@@ -23,8 +23,8 @@
#define MADS_NEBULAR_SCENES5_H
#include "common/scummsys.h"
-#include "mads/game.h"
-#include "mads/scene.h"
+#include "mads/core/game.h"
+#include "mads/core/scene.h"
#include "mads/nebular/nebular_scenes.h"
namespace MADS {
@@ -46,7 +46,7 @@ protected:
void sceneEntrySound();
public:
- Scene5xx(MADSEngine *vm) : NebularScene(vm) {}
+ Scene5xx(RexNebularEngine *vm) : NebularScene(vm) {}
};
class Scene501 : public Scene5xx{
@@ -59,7 +59,7 @@ private:
void handleSlotActions();
public:
- Scene501(MADSEngine *vm);
+ Scene501(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -71,7 +71,7 @@ public:
class Scene502 : public SceneTeleporter {
public:
- Scene502(MADSEngine *vm) : SceneTeleporter(vm) {}
+ Scene502(RexNebularEngine *vm) : SceneTeleporter(vm) {}
void setup() override;
void enter() override;
@@ -84,7 +84,7 @@ private:
int _detonatorHotspotId;
public:
- Scene503(MADSEngine *vm);
+ Scene503(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -98,7 +98,7 @@ private:
int _carFrame;
public:
- Scene504(MADSEngine *vm);
+ Scene504(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -119,7 +119,7 @@ private:
int _carLocations[9];
public:
- Scene505(MADSEngine *vm);
+ Scene505(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -145,7 +145,7 @@ private:
void handleDoorSequences();
public:
- Scene506(MADSEngine *vm);
+ Scene506(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -159,7 +159,7 @@ private:
int _penlightHotspotId;
public:
- Scene507(MADSEngine *vm);
+ Scene507(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -174,7 +174,7 @@ private:
void handlePedestral();
public:
- Scene508(MADSEngine *vm);
+ Scene508(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -193,7 +193,7 @@ private:
int _lineAnimationPosition;
public:
- Scene511(MADSEngine *vm);
+ Scene511(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -209,7 +209,7 @@ private:
int _keyHotspotId;
public:
- Scene512(MADSEngine *vm);
+ Scene512(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -219,7 +219,7 @@ public:
class Scene513 : public Scene5xx{
public:
- Scene513(MADSEngine *vm) : Scene5xx(vm) {}
+ Scene513(RexNebularEngine *vm) : Scene5xx(vm) {}
void setup() override;
void enter() override;
@@ -229,7 +229,7 @@ public:
class Scene515 : public Scene5xx{
public:
- Scene515(MADSEngine *vm) : Scene5xx(vm) {}
+ Scene515(RexNebularEngine *vm) : Scene5xx(vm) {}
void setup() override;
void enter() override;
@@ -239,7 +239,7 @@ public:
class Scene551 : public Scene5xx{
public:
- Scene551(MADSEngine *vm) : Scene5xx(vm) {}
+ Scene551(RexNebularEngine *vm) : Scene5xx(vm) {}
void setup() override;
void enter() override;
diff --git a/engines/mads/nebular/nebular_scenes6.cpp b/engines/mads/nebular/nebular_scenes6.cpp
index c2bd6a59a26..10634084507 100644
--- a/engines/mads/nebular/nebular_scenes6.cpp
+++ b/engines/mads/nebular/nebular_scenes6.cpp
@@ -20,8 +20,8 @@
*/
#include "common/scummsys.h"
-#include "mads/mads.h"
-#include "mads/scene.h"
+#include "mads/nebular/nebular.h"
+#include "mads/core/scene.h"
#include "mads/nebular/nebular_scenes.h"
#include "mads/nebular/nebular_scenes6.h"
@@ -216,7 +216,7 @@ void Scene601::actions() {
/*------------------------------------------------------------------------*/
-Scene602::Scene602(MADSEngine *vm) : Scene6xx(vm) {
+Scene602::Scene602(RexNebularEngine *vm) : Scene6xx(vm) {
_lastSpriteIdx = -1;
_lastSequenceIdx = -1;
_cycleIndex = -1;
@@ -545,7 +545,7 @@ void Scene602::actions() {
/*------------------------------------------------------------------------*/
-Scene603::Scene603(MADSEngine *vm) : Scene6xx(vm) {
+Scene603::Scene603(RexNebularEngine *vm) : Scene6xx(vm) {
_compactCaseHotspotId = -1;
_noteHotspotId = -1;
}
@@ -698,7 +698,7 @@ void Scene603::actions() {
/*------------------------------------------------------------------------*/
-Scene604::Scene604(MADSEngine *vm) : Scene6xx(vm) {
+Scene604::Scene604(RexNebularEngine *vm) : Scene6xx(vm) {
_timebombHotspotId = -1;
_bombMode = -1;
_monsterFrame = -1;
@@ -1041,7 +1041,7 @@ void Scene605::actions() {
/*------------------------------------------------------------------------*/
-Scene607::Scene607(MADSEngine *vm) : Scene6xx(vm) {
+Scene607::Scene607(RexNebularEngine *vm) : Scene6xx(vm) {
_dogTimer = 0;
_lastFrameTime = 0;
@@ -1504,7 +1504,7 @@ void Scene607::actions() {
/*------------------------------------------------------------------------*/
-Scene608::Scene608(MADSEngine *vm) : Scene6xx(vm) {
+Scene608::Scene608(RexNebularEngine *vm) : Scene6xx(vm) {
_carMode = -1;
_carFrame = -1;
_carMoveMode = -1;
@@ -2502,7 +2502,7 @@ void Scene608::actions() {
/*------------------------------------------------------------------------*/
-Scene609::Scene609(MADSEngine *vm) : Scene6xx(vm) {
+Scene609::Scene609(RexNebularEngine *vm) : Scene6xx(vm) {
_videoDoorMode = -1;
}
@@ -2835,7 +2835,7 @@ void Scene609::actions() {
/*------------------------------------------------------------------------*/
-Scene610::Scene610(MADSEngine *vm) : Scene6xx(vm) {
+Scene610::Scene610(RexNebularEngine *vm) : Scene6xx(vm) {
_handsetHotspotId = -1;
_checkVal = -1;
@@ -3040,7 +3040,7 @@ void Scene610::actions() {
/*------------------------------------------------------------------------*/
-Scene611::Scene611(MADSEngine *vm) : Scene6xx(vm), _defaultDialogPos(0, 0) {
+Scene611::Scene611(RexNebularEngine *vm) : Scene6xx(vm), _defaultDialogPos(0, 0) {
_seenRatFl = false;
_eyesRunningFl = false;
_shouldRemoveEyes = false;
@@ -4474,7 +4474,7 @@ void Scene611::actions() {
/*------------------------------------------------------------------------*/
-Scene612::Scene612(MADSEngine *vm) : Scene6xx(vm) {
+Scene612::Scene612(RexNebularEngine *vm) : Scene6xx(vm) {
_actionMode = -1;
_cycleIndex = -1;
}
diff --git a/engines/mads/nebular/nebular_scenes6.h b/engines/mads/nebular/nebular_scenes6.h
index 79026ab3082..3bf715ae134 100644
--- a/engines/mads/nebular/nebular_scenes6.h
+++ b/engines/mads/nebular/nebular_scenes6.h
@@ -23,8 +23,8 @@
#define MADS_NEBULAR_SCENES6_H
#include "common/scummsys.h"
-#include "mads/game.h"
-#include "mads/scene.h"
+#include "mads/core/game.h"
+#include "mads/core/scene.h"
#include "mads/nebular/nebular_scenes.h"
namespace MADS {
@@ -46,12 +46,12 @@ protected:
void sceneEntrySound();
public:
- Scene6xx(MADSEngine *vm) : NebularScene(vm) {}
+ Scene6xx(RexNebularEngine *vm) : NebularScene(vm) {}
};
class Scene601 : public Scene6xx{
public:
- Scene601(MADSEngine *vm) : Scene6xx(vm) {}
+ Scene601(RexNebularEngine *vm) : Scene6xx(vm) {}
void setup() override;
void enter() override;
@@ -69,7 +69,7 @@ private:
void handleSafeActions();
public:
- Scene602(MADSEngine *vm);
+ Scene602(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -83,7 +83,7 @@ private:
int _noteHotspotId;
public:
- Scene603(MADSEngine *vm);
+ Scene603(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -105,7 +105,7 @@ private:
void handleBombActions();
public:
- Scene604(MADSEngine *vm);
+ Scene604(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -116,7 +116,7 @@ public:
class Scene605 : public Scene6xx{
public:
- Scene605(MADSEngine *vm) : Scene6xx(vm) {}
+ Scene605(RexNebularEngine *vm) : Scene6xx(vm) {}
void setup() override;
void enter() override;
@@ -141,7 +141,7 @@ private:
void handleThrowingBone();
public:
- Scene607(MADSEngine *vm);
+ Scene607(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -189,7 +189,7 @@ private:
void handleThrowingBone();
public:
- Scene608(MADSEngine *vm);
+ Scene608(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -206,7 +206,7 @@ private:
void enterStore();
public:
- Scene609(MADSEngine *vm);
+ Scene609(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -227,7 +227,7 @@ private:
uint32 _lastFrameTimer;
public:
- Scene610(MADSEngine *vm);
+ Scene610(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -279,7 +279,7 @@ private:
bool check4ChargedBatteries();
public:
- Scene611(MADSEngine *vm);
+ Scene611(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -297,7 +297,7 @@ private:
void handleWinchMovement();
public:
- Scene612(MADSEngine *vm);
+ Scene612(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -308,7 +308,7 @@ public:
class Scene620 : public Scene6xx{
public:
- Scene620(MADSEngine *vm) : Scene6xx(vm) {}
+ Scene620(RexNebularEngine *vm) : Scene6xx(vm) {}
void setup() override;
void enter() override;
diff --git a/engines/mads/nebular/nebular_scenes7.cpp b/engines/mads/nebular/nebular_scenes7.cpp
index 359415c9353..c64dfa85acb 100644
--- a/engines/mads/nebular/nebular_scenes7.cpp
+++ b/engines/mads/nebular/nebular_scenes7.cpp
@@ -20,8 +20,8 @@
*/
#include "common/scummsys.h"
-#include "mads/mads.h"
-#include "mads/scene.h"
+#include "mads/nebular/nebular.h"
+#include "mads/core/scene.h"
#include "mads/nebular/nebular_scenes.h"
#include "mads/nebular/nebular_scenes7.h"
@@ -88,7 +88,7 @@ void Scene7xx::sceneEntrySound() {
/*------------------------------------------------------------------------*/
-Scene701::Scene701(MADSEngine *vm) : Scene7xx(vm) {
+Scene701::Scene701(RexNebularEngine *vm) : Scene7xx(vm) {
_fishingLineId = -1;
}
@@ -551,7 +551,7 @@ void Scene702::actions() {
/*------------------------------------------------------------------------*/
-Scene703::Scene703(MADSEngine *vm) : Scene7xx(vm) {
+Scene703::Scene703(RexNebularEngine *vm) : Scene7xx(vm) {
_monsterMode = -1;
_boatFrame = -1;
_curSequence = -1;
@@ -1109,7 +1109,7 @@ void Scene703::actions() {
/*------------------------------------------------------------------------*/
-Scene704::Scene704(MADSEngine *vm) : Scene7xx(vm) {
+Scene704::Scene704(RexNebularEngine *vm) : Scene7xx(vm) {
_bottleHotspotId = -1;
_boatCurrentFrame = -1;
_animationMode = -1;
@@ -1736,7 +1736,7 @@ void Scene705::actions() {
/*------------------------------------------------------------------------*/
-Scene706::Scene706(MADSEngine *vm) : Scene7xx(vm) {
+Scene706::Scene706(RexNebularEngine *vm) : Scene7xx(vm) {
_vaseHotspotId = -1;
_vaseMode = -1;
_animationMode = -1;
@@ -2168,7 +2168,7 @@ void Scene711::actions() {
/*------------------------------------------------------------------------*/
-Scene751::Scene751(MADSEngine *vm) : Scene7xx(vm) {
+Scene751::Scene751(RexNebularEngine *vm) : Scene7xx(vm) {
_rexHandingLine = false;
}
@@ -2503,7 +2503,7 @@ void Scene751::actions() {
/*------------------------------------------------------------------------*/
-Scene752::Scene752(MADSEngine *vm) : Scene7xx(vm) {
+Scene752::Scene752(RexNebularEngine *vm) : Scene7xx(vm) {
_cardId = -1;
}
diff --git a/engines/mads/nebular/nebular_scenes7.h b/engines/mads/nebular/nebular_scenes7.h
index 25345568516..6070db7c0d8 100644
--- a/engines/mads/nebular/nebular_scenes7.h
+++ b/engines/mads/nebular/nebular_scenes7.h
@@ -23,8 +23,8 @@
#define MADS_NEBULAR_SCENES7_H
#include "common/scummsys.h"
-#include "mads/game.h"
-#include "mads/scene.h"
+#include "mads/core/game.h"
+#include "mads/core/scene.h"
#include "mads/nebular/nebular_scenes.h"
namespace MADS {
@@ -46,7 +46,7 @@ protected:
void sceneEntrySound();
public:
- Scene7xx(MADSEngine *vm) : NebularScene(vm) {}
+ Scene7xx(RexNebularEngine *vm) : NebularScene(vm) {}
};
class Scene701 : public Scene7xx {
@@ -54,7 +54,7 @@ private:
int _fishingLineId;
public:
- Scene701(MADSEngine *vm);
+ Scene701(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -66,7 +66,7 @@ public:
class Scene702 : public Scene7xx {
public:
- Scene702(MADSEngine *vm) : Scene7xx(vm) {}
+ Scene702(RexNebularEngine *vm) : Scene7xx(vm) {}
void setup() override;
void enter() override;
@@ -96,7 +96,7 @@ private:
void handleFillBottle(int quote);
public:
- Scene703(MADSEngine *vm);
+ Scene703(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -121,7 +121,7 @@ private:
void handleBottleInterface();
public:
- Scene704(MADSEngine *vm);
+ Scene704(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -139,7 +139,7 @@ private:
void handleBottleInterface();
public:
- Scene705(MADSEngine *vm) : Scene7xx(vm) {}
+ Scene705(RexNebularEngine *vm) : Scene7xx(vm) {}
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -161,7 +161,7 @@ private:
void handleRexDeath();
public:
- Scene706(MADSEngine *vm);
+ Scene706(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -173,7 +173,7 @@ public:
class Scene707 : public SceneTeleporter {
public:
- Scene707(MADSEngine *vm) : SceneTeleporter(vm) {}
+ Scene707(RexNebularEngine *vm) : SceneTeleporter(vm) {}
void setup() override;
void enter() override;
@@ -183,7 +183,7 @@ public:
class Scene710 : public Scene7xx {
public:
- Scene710(MADSEngine *vm) : Scene7xx(vm) {}
+ Scene710(RexNebularEngine *vm) : Scene7xx(vm) {}
void setup() override;
void enter() override;
@@ -193,7 +193,7 @@ public:
class Scene711 : public SceneTeleporter {
public:
- Scene711(MADSEngine *vm) : SceneTeleporter(vm) {}
+ Scene711(RexNebularEngine *vm) : SceneTeleporter(vm) {}
void setup() override;
void enter() override;
@@ -206,7 +206,7 @@ private:
bool _rexHandingLine;
public:
- Scene751(MADSEngine *vm);
+ Scene751(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -221,7 +221,7 @@ private:
int _cardId;
public:
- Scene752(MADSEngine *vm);
+ Scene752(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
diff --git a/engines/mads/nebular/nebular_scenes8.cpp b/engines/mads/nebular/nebular_scenes8.cpp
index 9b5884f4b44..8335339e51b 100644
--- a/engines/mads/nebular/nebular_scenes8.cpp
+++ b/engines/mads/nebular/nebular_scenes8.cpp
@@ -20,8 +20,8 @@
*/
#include "common/scummsys.h"
-#include "mads/mads.h"
-#include "mads/scene.h"
+#include "mads/nebular/nebular.h"
+#include "mads/core/scene.h"
#include "mads/nebular/nebular_scenes.h"
#include "mads/nebular/nebular_scenes8.h"
@@ -77,7 +77,7 @@ void Scene8xx::sceneEntrySound() {
/*------------------------------------------------------------------------*/
-Scene801::Scene801(MADSEngine *vm) : Scene8xx(vm) {
+Scene801::Scene801(RexNebularEngine *vm) : Scene8xx(vm) {
_walkThroughDoor = false;
}
@@ -832,7 +832,7 @@ void Scene803::actions() {
/*------------------------------------------------------------------------*/
-Scene804::Scene804(MADSEngine *vm) : Scene8xx(vm) {
+Scene804::Scene804(RexNebularEngine *vm) : Scene8xx(vm) {
_messWithThrottle = false;
_movingThrottle = false;
_throttleGone = false;
@@ -1368,7 +1368,7 @@ void Scene807::actions() {
/*------------------------------------------------------------------------*/
-Scene808::Scene808(MADSEngine *vm) : Scene8xx(vm) {
+Scene808::Scene808(RexNebularEngine *vm) : Scene8xx(vm) {
_goingTo803 = false;
}
@@ -1584,7 +1584,7 @@ void Scene808::actions() {
/*------------------------------------------------------------------------*/
-Scene810::Scene810(MADSEngine *vm) : Scene8xx(vm) {
+Scene810::Scene810(RexNebularEngine *vm) : Scene8xx(vm) {
_moveAllowed = false;
}
diff --git a/engines/mads/nebular/nebular_scenes8.h b/engines/mads/nebular/nebular_scenes8.h
index 58e134c2444..2b3aec7e564 100644
--- a/engines/mads/nebular/nebular_scenes8.h
+++ b/engines/mads/nebular/nebular_scenes8.h
@@ -23,8 +23,8 @@
#define MADS_NEBULAR_SCENES8_H
#include "common/scummsys.h"
-#include "mads/game.h"
-#include "mads/scene.h"
+#include "mads/core/game.h"
+#include "mads/core/scene.h"
#include "mads/nebular/nebular_scenes.h"
namespace MADS {
@@ -48,7 +48,7 @@ protected:
*/
void sceneEntrySound();
public:
- Scene8xx(MADSEngine *vm) : NebularScene(vm) {}
+ Scene8xx(RexNebularEngine *vm) : NebularScene(vm) {}
};
class Scene801 : public Scene8xx{
@@ -56,7 +56,7 @@ private:
bool _walkThroughDoor;
public:
- Scene801(MADSEngine *vm);
+ Scene801(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -68,7 +68,7 @@ public:
class Scene802 : public Scene8xx{
public:
- Scene802(MADSEngine *vm) : Scene8xx(vm) {}
+ Scene802(RexNebularEngine *vm) : Scene8xx(vm) {}
void setup() override;
void enter() override;
@@ -79,7 +79,7 @@ public:
class Scene803 : public Scene8xx{
public:
- Scene803(MADSEngine *vm) : Scene8xx(vm) {}
+ Scene803(RexNebularEngine *vm) : Scene8xx(vm) {}
void setup() override;
void enter() override;
@@ -101,7 +101,7 @@ private:
int _resetFrame;
public:
- Scene804(MADSEngine *vm);
+ Scene804(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -112,7 +112,7 @@ public:
class Scene805 : public Scene8xx{
public:
- Scene805(MADSEngine *vm) : Scene8xx(vm) {}
+ Scene805(RexNebularEngine *vm) : Scene8xx(vm) {}
void setup() override;
void enter() override;
@@ -123,7 +123,7 @@ public:
class Scene807 : public SceneTeleporter {
public:
- Scene807(MADSEngine *vm) : SceneTeleporter(vm) {}
+ Scene807(RexNebularEngine *vm) : SceneTeleporter(vm) {}
void setup() override;
void enter() override;
@@ -136,7 +136,7 @@ private:
bool _goingTo803;
public:
- Scene808(MADSEngine *vm);
+ Scene808(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
@@ -149,7 +149,7 @@ private:
bool _moveAllowed;
public:
- Scene810(MADSEngine *vm);
+ Scene810(RexNebularEngine *vm);
void synchronize(Common::Serializer &s) override;
void setup() override;
Commit: 24e2d5b6d9ec9bbae9689883ae49a5cd99771225
https://github.com/scummvm/scummvm/commit/24e2d5b6d9ec9bbae9689883ae49a5cd99771225
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:21:18+10:00
Commit Message:
MADS: Separate out HagArchive class
Changed paths:
A engines/mads/core/hag.cpp
A engines/mads/core/hag.h
engines/mads/core/resources.cpp
engines/mads/core/resources.h
engines/mads/module.mk
diff --git a/engines/mads/core/hag.cpp b/engines/mads/core/hag.cpp
new file mode 100644
index 00000000000..7b3b55da233
--- /dev/null
+++ b/engines/mads/core/hag.cpp
@@ -0,0 +1,247 @@
+/* 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/file.h"
+#include "mads/core/hag.h"
+#include "mads/detection.h"
+
+namespace MADS {
+
+const char *const MADSCONCAT_STRING = "MADSCONCAT";
+
+HagArchive::HagArchive(int gameID, bool isDemo) {
+ loadIndex(gameID, isDemo);
+}
+
+HagArchive::~HagArchive() {
+}
+
+// Archive implementation
+bool HagArchive::hasFile(const Common::Path &path) const {
+ HagIndex hagIndex;
+ HagEntry hagEntry;
+ return getHeaderEntry(path, hagIndex, hagEntry);
+}
+
+int HagArchive::listMembers(Common::ArchiveMemberList &list) const {
+ int members = 0;
+
+ for (uint hagCtr = 0; hagCtr < _index.size(); ++hagCtr) {
+ HagIndex hagIndex = _index[hagCtr];
+ Common::List<HagEntry>::iterator i;
+
+ for (i = hagIndex._entries.begin(); i != hagIndex._entries.end(); ++i) {
+ list.push_back(Common::ArchiveMemberList::value_type(
+ new Common::GenericArchiveMember((*i)._resourceName, *this)));
+ ++members;
+ }
+ }
+
+ return members;
+}
+
+const Common::ArchiveMemberPtr HagArchive::getMember(const Common::Path &path) const {
+ if (!hasFile(path))
+ return Common::ArchiveMemberPtr();
+
+ return Common::ArchiveMemberPtr(new Common::GenericArchiveMember(path, *this));
+}
+
+Common::SeekableReadStream *HagArchive::createReadStreamForMember(const Common::Path &path) const {
+ HagIndex hagIndex;
+ HagEntry hagEntry;
+
+ if (getHeaderEntry(path, hagIndex, hagEntry)) {
+ // Entry found. If the correct file is not already open, open it
+ Common::File f;
+ if (!f.open(hagIndex._filename))
+ error("Could not open HAG file");
+
+ // Return a new stream for the specific resource
+ f.seek(hagEntry._offset);
+ return f.readStream(hagEntry._size);
+ }
+
+ return nullptr;
+}
+
+void HagArchive::loadIndex(int gameID, bool isDemo) {
+ Common::File hagFile;
+
+ for (int sectionIndex = -1; sectionIndex < 11; ++sectionIndex) {
+ if (sectionIndex == 0 && !Common::File::exists("SECTION0.HAG"))
+ continue;
+
+ // Rex Nebular and Dragonsphere demos only have sections 1 and 9 - skip the rest
+ if ((gameID == GType_RexNebular || gameID == GType_Dragonsphere) && isDemo) {
+ if (sectionIndex != 1 && sectionIndex != 9)
+ continue;
+ }
+
+ // Phantom demo only has sections 1, 2 and 9 - skip the rest
+ if (gameID == GType_Phantom && isDemo) {
+ if (sectionIndex != 1 && sectionIndex != 2 && sectionIndex != 9)
+ continue;
+ }
+
+ // Dragonsphere does not have some sections - skip them
+ if (gameID == GType_Dragonsphere) {
+ if (sectionIndex == 7 || sectionIndex == 8)
+ continue;
+ }
+
+ // Phantom and Forest don't have some sections - skip them
+ if (gameID == GType_Phantom || gameID == GType_Forest) {
+ if (sectionIndex == 6 || sectionIndex == 7 || sectionIndex == 8)
+ continue;
+ }
+
+ Common::Path filename = (sectionIndex == -1) ? Common::Path("GLOBAL.HAG") :
+ Common::Path(Common::String::format("SECTION%d.HAG", sectionIndex));
+ if (sectionIndex == 10) {
+ // Speech
+ if (!Common::File::exists("SPEECH.HAG"))
+ break;
+ else
+ filename = "SPEECH.HAG";
+ }
+ if (!hagFile.open(filename))
+ error("Could not locate HAG file - %s", filename.toString().c_str());
+
+ // Check for header
+ char headerBuffer[16];
+ if ((hagFile.read(headerBuffer, 16) != 16) ||
+ (strncmp(headerBuffer, MADSCONCAT_STRING, 10) != 0))
+ error("Invalid HAG file opened");
+
+ // Scan through the HAG index
+ int numEntries = hagFile.readUint16LE();
+
+ HagIndex hagIndex;
+ hagIndex._filename = filename;
+
+ for (int idx = 0; idx < numEntries; ++idx) {
+ // Read in the details of the next resource
+ char resourceBuffer[14];
+ uint32 offset = hagFile.readUint32LE();
+ uint32 size = hagFile.readUint32LE();
+ hagFile.read(resourceBuffer, 14);
+
+ hagIndex._entries.push_back(HagEntry(resourceBuffer, offset, size));
+ }
+
+ hagFile.close();
+ _index.push_back(hagIndex);
+ }
+}
+
+bool HagArchive::getHeaderEntry(const Common::Path &resourceName,
+ HagIndex &hagIndex, HagEntry &hagEntry) const {
+ Common::Path resName = resourceName;
+ resName.toUppercase();
+ Common::String baseName(resName.baseName());
+ if (baseName[0] == '*') {
+ baseName.deleteChar(0);
+ resName = resName.getParent().appendComponent(baseName);
+ }
+
+ Common::Path hagFilename = getResourceFilename(resName);
+
+ // Find the index for the given file
+ for (uint hagCtr = 0; hagCtr < _index.size(); ++hagCtr) {
+ hagIndex = _index[hagCtr];
+
+ if (hagIndex._filename == hagFilename) {
+ Common::List<HagEntry>::iterator ei;
+ for (ei = hagIndex._entries.begin(); ei != hagIndex._entries.end(); ++ei) {
+ hagEntry = *ei;
+ if (hagEntry._resourceName.equalsIgnoreCase(resName))
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+Common::Path HagArchive::getResourceFilename(const Common::Path &resourceName) const {
+ Common::String baseName(resourceName.baseName());
+ ResourceType resType = getResourceType(baseName);
+ Common::Path outputFilename = "GLOBAL.HAG";
+
+ if ((resType == RESTYPE_ROOM) || (resType == RESTYPE_SC)) {
+ int value = atoi(baseName.c_str() + 2);
+ int hagFileNum = (resType == RESTYPE_ROOM) ? value / 100 : value;
+
+ if (hagFileNum >= 0)
+ outputFilename = Common::Path(Common::String::format("SECTION%d.HAG", hagFileNum));
+ }
+
+ if (resType == RESTYPE_SPEECH)
+ outputFilename = "SPEECH.HAG";
+
+ return outputFilename;
+}
+
+ResourceType HagArchive::getResourceType(const Common::String &resourceName) const {
+ if (resourceName.hasPrefix("RM")) {
+ // Room resource
+ return RESTYPE_ROOM;
+ } else if (resourceName.hasPrefix("SC")) {
+ // SC resource
+ return RESTYPE_SC;
+ } else if (resourceName.hasSuffix(".TXT")) {
+ // Text resource
+ return RESTYPE_TEXT;
+ } else if (resourceName.hasSuffix(".QUO")) {
+ // QUO resource
+ return RESTYPE_QUO;
+ } else if (resourceName.hasPrefix("I")) {
+ // I resource
+ return RESTYPE_I;
+ } else if (resourceName.hasPrefix("OB")) {
+ // OB resource
+ return RESTYPE_OB;
+ } else if (resourceName.hasPrefix("FONT")) {
+ // FONT resource
+ return RESTYPE_FONT;
+ } else if (resourceName.hasPrefix("SOUND")) {
+ // SOUND resource
+ return RESTYPE_SOUND;
+ } else if (resourceName.hasPrefix("SPCHC")) {
+ // SPEECH resource
+ return RESTYPE_SPEECH;
+ }
+
+ // Check for a known extension
+ const char *extPos = strchr(resourceName.c_str(), '.');
+ if (extPos) {
+ ++extPos;
+ if (!strcmp(extPos, "FL") || !strcmp(extPos, "LBM") || !strcmp(extPos, "ANM") ||
+ !strcmp(extPos, "AA") || !strcmp(extPos, "SS")) {
+ return RESTYPE_HAS_EXT;
+ }
+ }
+
+ return RESTYPE_NO_EXT;
+}
+
+} // End of namespace MADS
diff --git a/engines/mads/core/hag.h b/engines/mads/core/hag.h
new file mode 100644
index 00000000000..849af6eee23
--- /dev/null
+++ b/engines/mads/core/hag.h
@@ -0,0 +1,95 @@
+/* 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 MADS_HAG_H
+#define MADS_HAG_H
+
+#include "common/archive.h"
+
+namespace MADS {
+
+enum ResourceType {
+ RESTYPE_ROOM, RESTYPE_SC, RESTYPE_TEXT, RESTYPE_QUO, RESTYPE_I,
+ RESTYPE_OB, RESTYPE_FONT, RESTYPE_SOUND, RESTYPE_SPEECH, RESTYPE_HAS_EXT, RESTYPE_NO_EXT
+};
+
+/**
+ * HAG Archives implementation
+ */
+class HagArchive : public Common::Archive {
+private:
+ /**
+ * Details of a single entry in a HAG file index
+ */
+ struct HagEntry {
+ Common::Path _resourceName;
+ uint32 _offset;
+ uint32 _size;
+
+ HagEntry() : _offset(0), _size(0) {
+ }
+ HagEntry(const Common::Path &resourceName, uint32 offset, uint32 size)
+ : _resourceName(resourceName), _offset(offset), _size(size) {
+ }
+ };
+
+ class HagIndex {
+ public:
+ Common::List<HagEntry> _entries;
+ Common::Path _filename;
+ };
+
+ Common::Array<HagIndex> _index;
+
+ /**
+ * Load the index of all the game's HAG files
+ */
+ void loadIndex(int gameID, bool isDemo);
+
+ /**
+ * Given a resource name, opens up the correct HAG file and returns whether
+ * an entry with the given name exists.
+ */
+ bool getHeaderEntry(const Common::Path &resourceName, HagIndex &hagIndex, HagEntry &hagEntry) const;
+
+ /**
+ * Returns the HAG resource filename that will contain a given resource
+ */
+ Common::Path getResourceFilename(const Common::Path &resourceName) const;
+
+ /**
+ * Return a resource type given a resource name
+ */
+ ResourceType getResourceType(const Common::String &resourceName) const;
+public:
+ explicit HagArchive(int gameID, bool isDemo);
+ ~HagArchive() override;
+
+ // Archive implementation
+ bool hasFile(const Common::Path &path) const override;
+ int listMembers(Common::ArchiveMemberList &list) const override;
+ const Common::ArchiveMemberPtr getMember(const Common::Path &path) const override;
+ Common::SeekableReadStream *createReadStreamForMember(const Common::Path &path) const override;
+};
+
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/core/resources.cpp b/engines/mads/core/resources.cpp
index d210eb71c76..4552b69f4ce 100644
--- a/engines/mads/core/resources.cpp
+++ b/engines/mads/core/resources.cpp
@@ -22,295 +22,15 @@
#include "common/scummsys.h"
#include "common/archive.h"
#include "common/textconsole.h"
+#include "mads/mads.h"
#include "mads/nebular/nebular.h"
#include "mads/core/resources.h"
+#include "mads/core/hag.h"
namespace MADS {
-enum ResourceType {RESTYPE_ROOM, RESTYPE_SC, RESTYPE_TEXT, RESTYPE_QUO, RESTYPE_I,
- RESTYPE_OB, RESTYPE_FONT, RESTYPE_SOUND, RESTYPE_SPEECH, RESTYPE_HAS_EXT, RESTYPE_NO_EXT};
-
-/**
- * HAG Archives implementation
- */
-class HagArchive : public Common::Archive {
-private:
- /**
- * Details of a single entry in a HAG file index
- */
- struct HagEntry {
- Common::Path _resourceName;
- uint32 _offset;
- uint32 _size;
-
- HagEntry() : _offset(0), _size(0) {}
- HagEntry(const Common::Path &resourceName, uint32 offset, uint32 size)
- : _resourceName(resourceName), _offset(offset), _size(size) {
- }
- };
-
- class HagIndex {
- public:
- Common::List<HagEntry> _entries;
- Common::Path _filename;
- };
-
- Common::Array<HagIndex> _index;
-
- /**
- * Load the index of all the game's HAG files
- */
- void loadIndex(RexNebularEngine *vm);
-
- /**
- * Given a resource name, opens up the correct HAG file and returns whether
- * an entry with the given name exists.
- */
- bool getHeaderEntry(const Common::Path &resourceName, HagIndex &hagIndex, HagEntry &hagEntry) const;
-
- /**
- * Returns the HAG resource filename that will contain a given resource
- */
- Common::Path getResourceFilename(const Common::Path &resourceName) const;
-
- /**
- * Return a resource type given a resource name
- */
- ResourceType getResourceType(const Common::String &resourceName) const;
-public:
- explicit HagArchive(RexNebularEngine *vm);
- ~HagArchive() override;
-
- // Archive implementation
- bool hasFile(const Common::Path &path) const override;
- int listMembers(Common::ArchiveMemberList &list) const override;
- const Common::ArchiveMemberPtr getMember(const Common::Path &path) const override;
- Common::SeekableReadStream *createReadStreamForMember(const Common::Path &path) const override;
-};
-
-const char *const MADSCONCAT_STRING = "MADSCONCAT";
-
-HagArchive::HagArchive(RexNebularEngine *vm) {
- loadIndex(vm);
-}
-
-HagArchive::~HagArchive() {
-}
-
-// Archive implementation
-bool HagArchive::hasFile(const Common::Path &path) const {
- HagIndex hagIndex;
- HagEntry hagEntry;
- return getHeaderEntry(path, hagIndex, hagEntry);
-}
-
-int HagArchive::listMembers(Common::ArchiveMemberList &list) const {
- int members = 0;
-
- for (uint hagCtr = 0; hagCtr < _index.size(); ++hagCtr) {
- HagIndex hagIndex = _index[hagCtr];
- Common::List<HagEntry>::iterator i;
-
- for (i = hagIndex._entries.begin(); i != hagIndex._entries.end(); ++i) {
- list.push_back(Common::ArchiveMemberList::value_type(
- new Common::GenericArchiveMember((*i)._resourceName, *this)));
- ++members;
- }
- }
-
- return members;
-}
-
-const Common::ArchiveMemberPtr HagArchive::getMember(const Common::Path &path) const {
- if (!hasFile(path))
- return Common::ArchiveMemberPtr();
-
- return Common::ArchiveMemberPtr(new Common::GenericArchiveMember(path, *this));
-}
-
-Common::SeekableReadStream *HagArchive::createReadStreamForMember(const Common::Path &path) const {
- HagIndex hagIndex;
- HagEntry hagEntry;
-
- if (getHeaderEntry(path, hagIndex, hagEntry)) {
- // Entry found. If the correct file is not already open, open it
- Common::File f;
- if (!f.open(hagIndex._filename))
- error("Could not open HAG file");
-
- // Return a new stream for the specific resource
- f.seek(hagEntry._offset);
- return f.readStream(hagEntry._size);
- }
-
- return nullptr;
-}
-
-void HagArchive::loadIndex(RexNebularEngine *vm) {
- Common::File hagFile;
-
- for (int sectionIndex = -1; sectionIndex < 11; ++sectionIndex) {
- if (sectionIndex == 0 && !Common::File::exists("SECTION0.HAG"))
- continue;
-
- // Rex Nebular and Dragonsphere demos only have sections 1 and 9 - skip the rest
- if ((vm->getGameID() == GType_RexNebular || vm->getGameID() == GType_Dragonsphere) && vm->isDemo()) {
- if (sectionIndex != 1 && sectionIndex != 9)
- continue;
- }
-
- // Phantom demo only has sections 1, 2 and 9 - skip the rest
- if (vm->getGameID() == GType_Phantom && vm->isDemo()) {
- if (sectionIndex != 1 && sectionIndex != 2 && sectionIndex != 9)
- continue;
- }
-
- // Dragonsphere does not have some sections - skip them
- if (vm->getGameID() == GType_Dragonsphere) {
- if (sectionIndex == 7 || sectionIndex == 8)
- continue;
- }
-
- // Phantom and Forest don't have some sections - skip them
- if (vm->getGameID() == GType_Phantom || vm->getGameID() == GType_Forest) {
- if (sectionIndex == 6 || sectionIndex == 7 || sectionIndex == 8)
- continue;
- }
-
- Common::Path filename = (sectionIndex == -1) ? Common::Path("GLOBAL.HAG") :
- Common::Path(Common::String::format("SECTION%d.HAG", sectionIndex));
- if (sectionIndex == 10) {
- // Speech
- if (!Common::File::exists("SPEECH.HAG"))
- break;
- else
- filename = "SPEECH.HAG";
- }
- if (!hagFile.open(filename))
- error("Could not locate HAG file - %s", filename.toString().c_str());
-
- // Check for header
- char headerBuffer[16];
- if ((hagFile.read(headerBuffer, 16) != 16) ||
- (strncmp(headerBuffer, MADSCONCAT_STRING, 10) != 0))
- error("Invalid HAG file opened");
-
- // Scan through the HAG index
- int numEntries = hagFile.readUint16LE();
-
- HagIndex hagIndex;
- hagIndex._filename = filename;
-
- for (int idx = 0; idx < numEntries; ++idx) {
- // Read in the details of the next resource
- char resourceBuffer[14];
- uint32 offset = hagFile.readUint32LE();
- uint32 size = hagFile.readUint32LE();
- hagFile.read(resourceBuffer, 14);
-
- hagIndex._entries.push_back(HagEntry(resourceBuffer, offset, size));
- }
-
- hagFile.close();
- _index.push_back(hagIndex);
- }
-}
-
-bool HagArchive::getHeaderEntry(const Common::Path &resourceName,
- HagIndex &hagIndex, HagEntry &hagEntry) const {
- Common::Path resName = resourceName;
- resName.toUppercase();
- Common::String baseName(resName.baseName());
- if (baseName[0] == '*') {
- baseName.deleteChar(0);
- resName = resName.getParent().appendComponent(baseName);
- }
-
- Common::Path hagFilename = getResourceFilename(resName);
-
- // Find the index for the given file
- for (uint hagCtr = 0; hagCtr < _index.size(); ++hagCtr) {
- hagIndex = _index[hagCtr];
-
- if (hagIndex._filename == hagFilename) {
- Common::List<HagEntry>::iterator ei;
- for (ei = hagIndex._entries.begin(); ei != hagIndex._entries.end(); ++ei) {
- hagEntry = *ei;
- if (hagEntry._resourceName.equalsIgnoreCase(resName))
- return true;
- }
- }
- }
-
- return false;
-}
-
-Common::Path HagArchive::getResourceFilename(const Common::Path &resourceName) const {
- Common::String baseName(resourceName.baseName());
- ResourceType resType = getResourceType(baseName);
- Common::Path outputFilename = "GLOBAL.HAG";
-
- if ((resType == RESTYPE_ROOM) || (resType == RESTYPE_SC)) {
- int value = atoi(baseName.c_str() + 2);
- int hagFileNum = (resType == RESTYPE_ROOM) ? value / 100 : value;
-
- if (hagFileNum >= 0)
- outputFilename = Common::Path(Common::String::format("SECTION%d.HAG", hagFileNum));
- }
-
- if (resType == RESTYPE_SPEECH)
- outputFilename = "SPEECH.HAG";
-
- return outputFilename;
-}
-
-ResourceType HagArchive::getResourceType(const Common::String &resourceName) const {
- if (resourceName.hasPrefix("RM")) {
- // Room resource
- return RESTYPE_ROOM;
- } else if (resourceName.hasPrefix("SC")) {
- // SC resource
- return RESTYPE_SC;
- } else if (resourceName.hasSuffix(".TXT")) {
- // Text resource
- return RESTYPE_TEXT;
- } else if (resourceName.hasSuffix(".QUO")) {
- // QUO resource
- return RESTYPE_QUO;
- } else if (resourceName.hasPrefix("I")) {
- // I resource
- return RESTYPE_I;
- } else if (resourceName.hasPrefix("OB")) {
- // OB resource
- return RESTYPE_OB;
- } else if (resourceName.hasPrefix("FONT")) {
- // FONT resource
- return RESTYPE_FONT;
- } else if (resourceName.hasPrefix("SOUND")) {
- // SOUND resource
- return RESTYPE_SOUND;
- } else if (resourceName.hasPrefix("SPCHC")) {
- // SPEECH resource
- return RESTYPE_SPEECH;
- }
-
- // Check for a known extension
- const char *extPos = strchr(resourceName.c_str(), '.');
- if (extPos) {
- ++extPos;
- if (!strcmp(extPos, "FL") || !strcmp(extPos, "LBM") || !strcmp(extPos, "ANM") ||
- !strcmp(extPos, "AA") || !strcmp(extPos, "SS")) {
- return RESTYPE_HAS_EXT;
- }
- }
-
- return RESTYPE_NO_EXT;
-}
-
-/*------------------------------------------------------------------------*/
-
void Resources::init(RexNebularEngine *vm) {
- SearchMan.add("HAG", new HagArchive(vm));
+ SearchMan.add("HAG", new HagArchive(vm->getGameID(), vm->isDemo()));
}
Common::Path Resources::formatName(RESPREFIX resType, int id, const Common::String &ext) {
diff --git a/engines/mads/core/resources.h b/engines/mads/core/resources.h
index 0ab7a788415..ada1e25a4db 100644
--- a/engines/mads/core/resources.h
+++ b/engines/mads/core/resources.h
@@ -29,8 +29,6 @@
namespace MADS {
-class RexNebularEngine;
-
enum RESPREFIX {
RESPREFIX_GL = 1, RESPREFIX_SC = 2, RESPREFIX_RM = 3
};
@@ -40,6 +38,8 @@ enum EXTTYPE {
EXT_ART = 5, EXT_INT = 6
};
+class RexNebularEngine;
+
class Resources {
public:
/**
@@ -85,4 +85,4 @@ public:
} // End of namespace MADS
-#endif /* MADS_RESOURCES_H */
+#endif
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index b88fe307ec9..207add7b2e1 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -30,6 +30,7 @@ MODULE_OBJS := \
core/game.o \
core/game_data.o \
core/globals.o \
+ core/hag.o \
core/hotspots.o \
core/inventory.o \
core/mads.o \
Commit: ec9190612f64af037c4d0de82fac3ac2ae0048fa
https://github.com/scummvm/scummvm/commit/ec9190612f64af037c4d0de82fac3ac2ae0048fa
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:21:18+10:00
Commit Message:
MADS: PHANTOM: Kernel startup cleanups, added dummy timer stack
Changed paths:
engines/mads/madsv2/core/kernel.cpp
engines/mads/madsv2/core/timer.cpp
diff --git a/engines/mads/madsv2/core/kernel.cpp b/engines/mads/madsv2/core/kernel.cpp
index 454fa436b6d..fb6ab188729 100644
--- a/engines/mads/madsv2/core/kernel.cpp
+++ b/engines/mads/madsv2/core/kernel.cpp
@@ -301,7 +301,6 @@ int kernel_game_startup(int game_video_mode, int load_flag,
int error_flag = true;
int count, count2;
int ems_temp;
- int ems_error;
int pages;
int reserve[EMS_PAGING_CLASSES];
byte *interrupt_stack;
@@ -318,7 +317,7 @@ int kernel_game_startup(int game_video_mode, int load_flag,
// ScummVM doesn't need EMS/XMS
#if 0
- ems_error = true;
+ int ems_error = true;
if (ems_exists) {
work_screen_ems_handle = ems_get_page_handle(4);
@@ -423,8 +422,7 @@ int kernel_game_startup(int game_video_mode, int load_flag,
buffer_fill(scr_main, 0);
- /* Load the main interface fonts */
-
+ // Load the main interface fonts
if (load_flag & KERNEL_STARTUP_FONT) {
font_main = font_load("*FONTMAIN.FF");
font_inter = font_load("*FONTINTR.FF");
@@ -443,8 +441,7 @@ int kernel_game_startup(int game_video_mode, int load_flag,
}
- /* Install timer handler & low priority cycling interrupt */
-
+ // Install timer handler & low priority cycling interrupt
if (load_flag & KERNEL_STARTUP_INTERRUPT) {
timer_install();
@@ -486,10 +483,8 @@ int kernel_game_startup(int game_video_mode, int load_flag,
}
#endif
- /* Load the objects list */
-
+ // Load the objects list
if (load_flag & KERNEL_STARTUP_OBJECTS) {
- /* inter_allocate_objects(); */
if (object_load()) {
#ifndef disable_error_check
error_code = ERROR_KERNEL_NO_OBJECTS;
@@ -501,34 +496,28 @@ int kernel_game_startup(int game_video_mode, int load_flag,
}
}
- /* Allow packing routines to use lower interrupt stack */
-
+ // Allow packing routines to use lower interrupt stack
interrupt_stack = timer_get_interrupt_stack();
pack_set_special_buffer(interrupt_stack, NULL);
- /* Initialize player data structures */
-
- if (load_flag & KERNEL_STARTUP_PLAYER) player_init();
+ // Initialize player data structures
+ if (load_flag & KERNEL_STARTUP_PLAYER)
+ player_init();
popup_available = true;
- /* video_update (&scr_main, 0, 0, 0, 0, video_x, video_y); */
-
Common::strcpy_s(box_param.name, "*BOX.SS");
if (load_flag & KERNEL_STARTUP_CURSOR) {
-
- /* Wipe palette & prepare for cursor */
-
+ // Wipe palette & prepare for cursor
pal_init(KERNEL_RESERVED_LOW_COLORS, KERNEL_RESERVED_HIGH_COLORS);
pal_white(master_palette);
if (video_mode == mcga_mode) {
mcga_setpal_range(&master_palette, 0, 4);
}
- /* Load cursor sprite series */
-
- cursor = sprite_series_load("*CURSOR.SS", PAL_MAP_RESERVED | PAL_MAP_DEFINE_RESERVED);
+ // Load cursor sprite series
+ cursor = sprite_series_load("*CURSOR.SS", PAL_MAP_RESERVED /* | PAL_MAP_DEFINE_RESERVED*/);
if (cursor == NULL) {
#ifndef disable_error_check
error_code = ERROR_KERNEL_NO_CURSOR;
@@ -536,8 +525,7 @@ int kernel_game_startup(int game_video_mode, int load_flag,
goto done;
}
- /* Activate main cursor sprite as mouse cursor */
-
+ // Activate main cursor sprite as mouse cursor
cursor_last = cursor_id = (cursor->num_sprites > 1) ? 2 : 1;
mouse_cursor_sprite(cursor, cursor_id);
}
@@ -564,7 +552,9 @@ int kernel_game_startup(int game_video_mode, int load_flag,
error_flag = false;
done:
- if (load_flag & KERNEL_STARTUP_CURSOR_SHOW) mouse_show();
+ if (load_flag & KERNEL_STARTUP_CURSOR_SHOW)
+ mouse_show();
+
if (error_flag) {
#ifndef disable_error_check
error_check_memory();
diff --git a/engines/mads/madsv2/core/timer.cpp b/engines/mads/madsv2/core/timer.cpp
index b6eaa910af3..4b1684fc570 100644
--- a/engines/mads/madsv2/core/timer.cpp
+++ b/engines/mads/madsv2/core/timer.cpp
@@ -34,6 +34,9 @@ word timer_noise_on;
byte timer_copy_protect_in = 0;
byte timer_copy_protect_out = 0;
+constexpr int interrupt_stack_size = 12800;
+byte _interrupt_stack[interrupt_stack_size];
+
word timer_low_priority;
word timer_low_semaphore;
word timer_low_stacking;
@@ -127,7 +130,7 @@ void timer_activate_low_priority(void (*(routine))()) {
}
byte *timer_get_interrupt_stack(void) {
- error("TODO: timer_get_interrupt_stack");
+ return _interrupt_stack;
}
} // namespace MADSV2
Commit: 4aecd060fab9603cd85b4df026a0a8c4564f2e29
https://github.com/scummvm/scummvm/commit/4aecd060fab9603cd85b4df026a0a8c4564f2e29
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:21:18+10:00
Commit Message:
MADS: PHANTOM: Fixes to FAB decompression
Changed paths:
engines/mads/madsv2/core/pfab.cpp
diff --git a/engines/mads/madsv2/core/pfab.cpp b/engines/mads/madsv2/core/pfab.cpp
index 3b26f4b1205..85b10981ac3 100644
--- a/engines/mads/madsv2/core/pfab.cpp
+++ b/engines/mads/madsv2/core/pfab.cpp
@@ -82,8 +82,8 @@ namespace MADSV2 {
* I/O callback typedefs (match the original Pascal calling convention
* signatures translated to plain C function pointers)
* ====================================================================== */
-typedef word (*ReadFn) (char *buffer, word *size);
-typedef word (*WriteFn)(char *buffer, word *size);
+typedef word(*ReadFn) (char *buffer, word *size);
+typedef word(*WriteFn)(char *buffer, word *size);
/* =========================================================================
@@ -481,7 +481,7 @@ lz_exit:
* Public API: pFABcomp
* ---------------------------------------------------------------------- */
word pFABcomp(ReadFn read_buff, WriteFn write_buff, char *work_buff,
- word *type, word *dsize) {
+ word *type, word *dsize) {
/* If work_buff is NULL, return required buffer size */
if (!work_buff)
return comp_work_size();
@@ -626,33 +626,42 @@ static unsigned long fab_explode(ExpIO *io) {
if (exp_getbyte(io) != 'F') return 0;
if (exp_getbyte(io) != 'A') return 0;
if (exp_getbyte(io) != 'B') return 0;
- byte dict_bits = exp_getbyte(io); /* e.g. 12 */
-
- int lempel = 1 << dict_bits; /* 4096 */
- int zbits = 16 - dict_bits; /* 4 */
- int zmax_len = (1 << zbits) - 1; /* 15 (max short len-2) */
- //byte umask = (byte)(0xFF << (dict_bits - 8)); /* offset hi mask */
-
- unsigned ctrl = 0;
- int cbits = 0; /* bits left in ctrl word */
+ byte shiftVal = exp_getbyte(io); /* dict bits, e.g. 12 */
+
+ /*
+ * Derive the same masks FabDecompressor uses:
+ * copyOfsShift = 16 - shiftVal (e.g. 4)
+ * copyOfsMask = 0xFF << (shiftVal - 8) (e.g. 0xF0) -- sign-extends
+ * the high offset nibble
+ * copyLenMask = (1 << copyOfsShift) - 1 (e.g. 0x0F)
+ */
+ byte copyOfsShift = (byte)(16 - shiftVal);
+ byte copyOfsMask = (byte)(0xFF << (shiftVal - 8));
+ byte copyLenMask = (byte)((1 << copyOfsShift) - 1);
+ byte copyLen;
+ unsigned long copyOfs;
+
+ // Setup initial control bits word
+ uint ctrl = exp_getword(io);
+ int cbits = 16;
auto get_ctrl_bit = [&]() -> int {
- if (cbits == 0) {
- ctrl = exp_getword(io);
+ if (--cbits == 0) {
+ ctrl = (exp_getword(io) << 1) | (ctrl & 1);
cbits = 16;
}
+
int bit = (int)(ctrl & 1);
ctrl >>= 1;
- cbits--;
return bit;
- };
+ };
/* ---- Decode loop ------------------------------------------------- */
for (;;) {
int bit0 = get_ctrl_bit();
if (bit0 == 1) {
- /* LITERAL */
+ /* LITERAL: copy one byte straight through */
byte c = exp_getbyte(io);
exp_putbyte(io, c);
continue;
@@ -662,65 +671,41 @@ static unsigned long fab_explode(ExpIO *io) {
int bit1 = get_ctrl_bit();
if (bit1 == 0) {
- /* SHORT COPY: 2 more control bits = length 2-5, 1 byte dist 1-255 */
+ // Short copy
int lb = get_ctrl_bit();
int la = get_ctrl_bit();
- int enc_len = (lb << 1) | la; /* 0..3 = len - 2 */
- int cplen = enc_len + 2; /* 2..5 */
- byte off_byte = exp_getbyte(io);
- int dist = (int)(byte)(-((int)(byte)off_byte));
- if (dist == 0) dist = 256; /* 0 encodes as 256 */
-
- for (int i = 0; i < cplen; i++) {
- byte c = exp_readback(io, dist, io->out_count);
- exp_putbyte(io, c);
- }
- continue;
- }
-
- /* bit1 == 1 -> LONG COPY (or NORMALIZE / EXIT) */
- {
- byte lo_off = exp_getbyte(io);
- byte packed = exp_getbyte(io);
-
- /* High bits of offset: upper zbits of packed, shifted down */
- unsigned hi_off = (unsigned)(packed >> zbits);
- unsigned dist = ((unsigned)hi_off << 8) | lo_off;
-
- /* Length: lower (DICT-4) = zbits-1... actually lower zbits bits */
- int enc_len = packed & zmax_len;
-
- if (dist == 0) {
- if (enc_len == 0) {
- /* NORMALIZE marker - continue */
- continue;
- }
- if (enc_len == 1) {
- /* EXIT */
+ copyLen = ((lb << 1) | la) + 2;
+ copyOfs = exp_getbyte(io) | 0xFFFFFF00;
+ } else {
+ // Long copy
+ int lb = exp_getbyte(io);
+ int la = exp_getbyte(io);
+ copyOfs = (((la >> copyOfsShift) | copyOfsMask) << 8) | lb;
+ copyLen = la & copyLenMask;
+
+ if (copyLen == 0) {
+ copyLen = exp_getbyte(io);
+ if (copyLen == 0)
+ // End of decompression
break;
- }
- }
-
- int cplen;
- if (enc_len == zmax_len) {
- /* Extra length byte follows */
- byte ext = exp_getbyte(io);
- cplen = (int)ext + 1;
+ else if (copyLen == 1)
+ continue;
+ else
+ copyLen++;
} else {
- cplen = enc_len + 2;
+ copyLen += 2;
}
+ copyOfs |= 0xFFFF0000;
+ }
- /* dist is the back-reference distance (positive) */
- unsigned actual_dist = dist ? dist : lempel; /* 0 => lempel */
-
- for (int i = 0; i < cplen; i++) {
- byte c = exp_readback(io, (int)actual_dist, io->out_count);
- exp_putbyte(io, c);
- }
+ int dist = ABS((signed int)copyOfs);
+ while (copyLen-- > 0) {
+ byte c = exp_readback(io, dist, io->out_count);
+ exp_putbyte(io, c);
}
}
- /* Flush any remaining output */
+ // Flush any remaining output */
if (io->to_file)
exp_flush_wbuf(io, 1);
Commit: 68fe4b7ec523b00580159882fbbf320882afcbad
https://github.com/scummvm/scummvm/commit/68fe4b7ec523b00580159882fbbf320882afcbad
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:21:19+10:00
Commit Message:
MADS: PHANTOM: Implement endian safe sprite series loading
Changed paths:
engines/mads/madsv2/core/color.cpp
engines/mads/madsv2/core/color.h
engines/mads/madsv2/core/player.cpp
engines/mads/madsv2/core/sprite.cpp
engines/mads/madsv2/core/sprite.h
diff --git a/engines/mads/madsv2/core/color.cpp b/engines/mads/madsv2/core/color.cpp
index 348d90474c3..139174b161e 100644
--- a/engines/mads/madsv2/core/color.cpp
+++ b/engines/mads/madsv2/core/color.cpp
@@ -19,6 +19,7 @@
*
*/
+#include "common/memstream.h"
#include "mads/madsv2/core/color.h"
#include "mads/madsv2/core/screen.h"
#include "mads/madsv2/core/sort.h"
@@ -27,6 +28,28 @@
namespace MADS {
namespace MADSV2 {
+void Color::load(Common::SeekableReadStream *src) {
+ src->readMultipleLE(r, g, b, x16, cycle, group);
+}
+
+bool ColorList::load(Load &load_handle, int size) {
+ // Load in the needed data
+ byte *buffer = (byte *)malloc(size);
+ bool result = loader_read(buffer, size, 1, &load_handle);
+
+ if (result) {
+ Common::MemoryReadStream src(buffer, size);
+
+ num_colors = src.readUint16LE();
+ for (int i = 0; i < num_colors; ++i)
+ table[i].load(&src);
+ }
+
+ free(buffer);
+ return result;
+}
+
+
byte color_thatch(int color, int thatching) {
byte thatch;
diff --git a/engines/mads/madsv2/core/color.h b/engines/mads/madsv2/core/color.h
index c61f6ef26c7..9797cc08236 100644
--- a/engines/mads/madsv2/core/color.h
+++ b/engines/mads/madsv2/core/color.h
@@ -22,7 +22,8 @@
#ifndef MADS_CORE_COLOR_H
#define MADS_CORE_COLOR_H
-#include "mads/madsv2/core/general.h"
+#include "common/stream.h"
+#include "mads/madsv2/core/loader.h"
namespace MADS {
namespace MADSV2 {
@@ -59,22 +60,27 @@ namespace MADSV2 {
/* A fully parameterized color (in contrast to a plain RGBcolor as */
/* defined in general.mac) */
-typedef struct {
+struct Color {
byte r, g, b; /* RGB values */
byte x16; /* 16 color dither translation */
byte cycle; /* Color cycling handle */
byte group; /* Color grouping flags */
-} Color;
+
+ static constexpr int SIZE = 1 + 1 + 1 + 1 + 1 + 1;
+ void load(Common::SeekableReadStream *src);
+};
typedef Color *ColorPtr;
/* Palette-independent color list; ready to map into palette */
-typedef struct {
- int num_colors;
+struct ColorList {
+ uint16 num_colors;
Color table[COLOR_MAX_USER_COLORS];
-} ColorList;
+
+ bool load(Load &load_handle, int size);
+};
typedef ColorList *ColorListPtr;
diff --git a/engines/mads/madsv2/core/player.cpp b/engines/mads/madsv2/core/player.cpp
index 86a38a42f5a..07886fe6781 100644
--- a/engines/mads/madsv2/core/player.cpp
+++ b/engines/mads/madsv2/core/player.cpp
@@ -126,7 +126,7 @@ void player_select_series() {
id = player.series_base + player.series;
- player.velocity = MAX(series_list[id]->walker->velocity, 100);
+ player.velocity = MAX<int>(series_list[id]->walker->velocity, 100);
player_set_base_frame_rate();
diff --git a/engines/mads/madsv2/core/sprite.cpp b/engines/mads/madsv2/core/sprite.cpp
index 2ea5f82c106..6beed18d4ed 100644
--- a/engines/mads/madsv2/core/sprite.cpp
+++ b/engines/mads/madsv2/core/sprite.cpp
@@ -19,6 +19,7 @@
*
*/
+#include "common/memstream.h"
#include "mads/madsv2/core/general.h"
#include "mads/madsv2/core/sprite.h"
#include "mads/madsv2/core/mem.h"
@@ -291,6 +292,60 @@ void sprite_draw_3d_scaled_mono(SeriesPtr series, int id,
//====================================================================
+void WalkerInfo::load(Load &load_handle) {
+ // Load in the needed data
+ byte buffer[SIZE];
+ loader_read(buffer, SIZE, 1, &load_handle);
+
+ Common::MemoryReadStream src(buffer, SIZE);
+ load(&src);
+}
+
+void WalkerInfo::load(Common::SeekableReadStream *src) {
+ // Read in the fields
+ num_primary = src->readUint16LE();
+ num_secondary = src->readUint16LE();
+ src->readMultipleLE(sequence_start);
+ src->readMultipleLE(sequence_stop);
+ src->readMultipleLE(sequence_chance);
+
+ velocity = src->readSint16LE();
+ frame_rate = src->readByte();
+ center_of_gravity = src->readByte();
+}
+
+
+bool FileSeries::loadHeader(Load &load_handle) {
+ // Load in the needed data
+ byte buffer[HEADER_SIZE];
+ if (!loader_read(buffer, HEADER_SIZE, 1, &load_handle))
+ return false;
+
+ // Wrap it in a memory stream for reading convenience
+ Common::MemoryReadStream src(buffer, HEADER_SIZE);
+
+ // Read in the fields
+ pack_by_sprite = src.readByte();
+ compression = src.readByte();
+ delta_series = src.readUint16LE();
+ base_mode = src.readUint16LE();
+ src.readMultipleLE(misc);
+ num_sprites = src.readUint16LE();
+ walker.load(&src);
+
+ offset_x_view = src.readUint16LE();
+ offset_y_view = src.readUint16LE();
+ total_data_size = src.readUint32LE();
+
+ return true;
+}
+
+void FileSprite::load(Common::SeekableReadStream *src) {
+ src->readMultipleLE(file_offset, memory_needed, x, y, xs, ys);
+}
+
+//====================================================================
+
SeriesPtr sprite_series_load(const char *filename, int load_flags) {
register int count;
int len;
@@ -348,10 +403,11 @@ SeriesPtr sprite_series_load(const char *filename, int load_flags) {
/* Determine length of header, and read it */
len = sizeof(FileSeries) - sizeof(FileSprite);
+ if (!header.loadHeader(load_handle))
+ goto done;
- if (!loader_read(&header, len, 1, &load_handle)) goto done;
-
- if (header.misc_is_a_walker) load_flags |= SPRITE_LOAD_WALKER_INFO;
+ if (header.misc_is_a_walker)
+ load_flags |= SPRITE_LOAD_WALKER_INFO;
/* Determine length of index record array */
@@ -400,15 +456,23 @@ SeriesPtr sprite_series_load(const char *filename, int load_flags) {
target->page_table = NULL;
target->arena = NULL;
- /* Read the index record array */
+ // Read the sprites array
+ {
+ byte *buffer = (byte *)malloc(header.num_sprites * FileSprite::SIZE);
+ if (!loader_read(buffer, FileSprite::SIZE, header.num_sprites, &load_handle)) {
+ free(buffer);
+ sprite_error = SS_ERR_READFILE;
+ goto done;
+ }
+
+ Common::MemoryReadStream src(buffer, header.num_sprites * FileSprite::SIZE);
+ for (int i = 0; i < header.num_sprites; ++i)
+ sprite[i].load(&src);
- if (!loader_read(sprite, len2, 1, &load_handle)) {
- sprite_error = SS_ERR_READFILE;
- goto done;
+ free(buffer);
}
- /* Read the color list */
-
+ // Read the color list
total_color_size = load_handle.pack.strategy[load_handle.pack_list_marker].size;
color_list = (ColorListPtr)mem_get_name(total_color_size, "$color$");
@@ -417,7 +481,8 @@ SeriesPtr sprite_series_load(const char *filename, int load_flags) {
goto done;
}
- if (!loader_read(color_list, total_color_size, 1, &load_handle)) goto done;
+ if (!color_list->load(load_handle, total_color_size))
+ goto done;
/* Copy relevant header data to target header */
diff --git a/engines/mads/madsv2/core/sprite.h b/engines/mads/madsv2/core/sprite.h
index cdd32a0e725..00c90363dcf 100644
--- a/engines/mads/madsv2/core/sprite.h
+++ b/engines/mads/madsv2/core/sprite.h
@@ -24,6 +24,7 @@
#include "common/stream.h"
#include "mads/madsv2/core/color.h"
+#include "mads/madsv2/core/loader.h"
namespace MADS {
namespace MADSV2 {
@@ -92,17 +93,21 @@ namespace MADSV2 {
/* STRUCTURES FOR ALL SPRITE LEVELS */
-typedef struct {
- int num_primary; /* Number of primary sequence frames */
- int num_secondary; /* Number of secondary sequences */
- int sequence_start[MAX_SECONDARY]; /* Secondary sequence start frames */
- int sequence_stop[MAX_SECONDARY]; /* Secondary sequence stop frames */
- int sequence_chance[MAX_SECONDARY];/* Secondary sequence probability */
+struct WalkerInfo {
+ uint16 num_primary; /* Number of primary sequence frames */
+ uint16 num_secondary; /* Number of secondary sequences */
+ uint16 sequence_start[MAX_SECONDARY]; /* Secondary sequence start frames */
+ uint16 sequence_stop[MAX_SECONDARY]; /* Secondary sequence stop frames */
+ uint16 sequence_chance[MAX_SECONDARY];/* Secondary sequence probability */
+
+ int16 velocity; /* Pixel velocity for walker */
+ byte frame_rate; /* Frame rate for walker */
+ byte center_of_gravity; /* Center of gravity displacement */
- int velocity; /* Pixel velocity for walker */
- byte frame_rate; /* Frame rate for walker */
- byte center_of_gravity; /* Center of gravity displacement */
-} WalkerInfo;
+ static constexpr int SIZE = 2 + 2 + (2 + 2 + 2) * MAX_SECONDARY + 2 + 1 + 1;
+ void load(Load &load_handle);
+ void load(Common::SeekableReadStream *src);
+};
typedef WalkerInfo *WalkerInfoPtr;
@@ -164,38 +169,47 @@ typedef HagSeries *HagSeriesPtr;
/* LOADABLE FILE STRUCTURES (.SS files) */
-/* Loadable sprite record */
+/**
+ * Loadable sprite record
+ */
+struct FileSprite {
+ uint32 file_offset; /* Location of sprite data in file */
+ uint32 memory_needed; /* Memory needed to hold sprite data */
+ int16 x, y;
+ int16 xs, ys;
-typedef struct {
- long file_offset; /* Location of sprite data in file */
- long memory_needed; /* Memory needed to hold sprite data */
- int x, y;
- int xs, ys;
-} FileSprite;
+ static constexpr int SIZE = 4 + 4 + 2 + 2 + 2 + 2;
+ void load(Common::SeekableReadStream *src);
+};
typedef FileSprite *FileSpritePtr;
-/* Loadable sprite series record */
-
-typedef struct FileSeriesBuf {
+/**
+ * Loadable sprite series record
+ */
+struct FileSeries {
byte pack_by_sprite; /* Overall series packing strategy */
byte compression; /* Type of compression */
- int delta_series; /* Flag if series is a delta series */
- int base_mode; /* Base mode optimization type */
+ uint16 delta_series; /* Flag if series is a delta series */
+ uint16 base_mode; /* Base mode optimization type */
- int misc[16]; /* Miscellaneous data for updates */
+ uint16 misc[16]; /* Miscellaneous data for updates */
- int num_sprites; /* Number of sprites in series */
+ uint16 num_sprites; /* Number of sprites in series */
WalkerInfo walker; /* Walker information */
- int offset_x_view; /* View offsets for sprites intended */
- int offset_y_view; /* for extra-wide animations */
+ uint16 offset_x_view; /* View offsets for sprites intended */
+ uint16 offset_y_view; /* for extra-wide animations */
- long total_data_size; /* Total uncompressed data size */
+ uint32 total_data_size; /* Total uncompressed data size */
FileSprite index[1]; /* Sprite records begin here */
-} FileSeries;
+
+ static constexpr int HEADER_SIZE = 1 + 1 + 2 + 2 + 2 * 16 + 2 +
+ WalkerInfo::SIZE + 2 + 2 + 4;
+ bool loadHeader(Load &load_handle);
+};
typedef FileSeries *FileSeriesPtr;
Commit: 400266d2937b41ecd4dda1af9a852c7251128d91
https://github.com/scummvm/scummvm/commit/400266d2937b41ecd4dda1af9a852c7251128d91
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:21:19+10:00
Commit Message:
MADS: PHANTOM: Endian safe tile loading
Changed paths:
engines/mads/madsv2/core/color.cpp
engines/mads/madsv2/core/color.h
engines/mads/madsv2/core/room.cpp
engines/mads/madsv2/core/room.h
engines/mads/madsv2/core/tile.cpp
engines/mads/madsv2/core/tile.h
engines/mads/madsv2/phantom/main.cpp
diff --git a/engines/mads/madsv2/core/color.cpp b/engines/mads/madsv2/core/color.cpp
index 139174b161e..ce9d832ecec 100644
--- a/engines/mads/madsv2/core/color.cpp
+++ b/engines/mads/madsv2/core/color.cpp
@@ -49,6 +49,31 @@ bool ColorList::load(Load &load_handle, int size) {
return result;
}
+void ColorList::load(Common::SeekableReadStream *src) {
+ num_colors = src->readUint16LE();
+
+ for (int i = 0; i < COLOR_MAX_USER_COLORS; ++i)
+ table[i].load(src);
+}
+
+void Cycle::load(Common::SeekableReadStream *src) {
+ src->readMultipleLE(num_colors, first_list_color, first_palette_color, ticks);
+}
+
+void CycleList::load(Common::SeekableReadStream *src) {
+ num_cycles = src->readUint16LE();
+
+ for (int i = 0; i < COLOR_MAX_CYCLES; ++i)
+ table[i].load(src);
+}
+
+void ShadowList::load(Common::SeekableReadStream *src) {
+ src->readMultipleLE(num_shadow_colors);
+ for (int i = 0; i < COLOR_MAX_SHADOW_COLORS; ++i)
+ shadow_color[i] = src->readSint16LE();
+}
+
+//====================================================================
byte color_thatch(int color, int thatching) {
byte thatch;
diff --git a/engines/mads/madsv2/core/color.h b/engines/mads/madsv2/core/color.h
index 9797cc08236..2bc8c028867 100644
--- a/engines/mads/madsv2/core/color.h
+++ b/engines/mads/madsv2/core/color.h
@@ -79,7 +79,9 @@ struct ColorList {
uint16 num_colors;
Color table[COLOR_MAX_USER_COLORS];
+ static constexpr int SIZE = 2 + (Color::SIZE * COLOR_MAX_USER_COLORS);
bool load(Load &load_handle, int size);
+ void load(Common::SeekableReadStream *src);
};
typedef ColorList *ColorListPtr;
@@ -87,30 +89,39 @@ typedef ColorList *ColorListPtr;
/* Palette-independent color cycling range & timing information */
-typedef struct {
+struct Cycle {
byte num_colors; /* Number of colors in the cycle */
byte first_list_color; /* First color in color list */
byte first_palette_color; /* First color in final palette */
byte ticks; /* 60/s ticks between cycles */
-} Cycle;
+
+ static constexpr int SIZE = 1 + 1 + 1 + 1;
+ void load(Common::SeekableReadStream *src);
+};
typedef Cycle *CyclePtr;
/* List of color cycling ranges */
-typedef struct {
+struct CycleList {
int num_cycles;
Cycle table[COLOR_MAX_CYCLES];
-} CycleList;
+
+ static constexpr int SIZE = 2 + (Cycle::SIZE * COLOR_MAX_CYCLES);
+ void load(Common::SeekableReadStream *src);
+};
typedef CycleList *CycleListPtr;
-typedef struct {
- int num_shadow_colors;
- int shadow_color[COLOR_MAX_SHADOW_COLORS];
-} ShadowList;
+struct ShadowList {
+ uint16 num_shadow_colors;
+ int shadow_color[COLOR_MAX_SHADOW_COLORS];
+
+ static constexpr int SIZE = 2 + (2 * COLOR_MAX_SHADOW_COLORS);
+ void load(Common::SeekableReadStream *src);
+};
typedef ShadowList *ShadowListPtr;
diff --git a/engines/mads/madsv2/core/room.cpp b/engines/mads/madsv2/core/room.cpp
index 52767efb9e1..e7d160fc3c6 100644
--- a/engines/mads/madsv2/core/room.cpp
+++ b/engines/mads/madsv2/core/room.cpp
@@ -20,6 +20,7 @@
*/
#include "common/file.h"
+#include "common/memstream.h"
#include "mads/madsv2/core/room.h"
#include "mads/madsv2/core/attr.h"
#include "mads/madsv2/core/env.h"
@@ -53,6 +54,26 @@ RoomPict roompict;
static const char room_file_extension[5] = ".DAT";
+
+void Rail::load(Common::SeekableReadStream *src) {
+ src->readMultipleLE(x, y);
+ src->readMultipleLE(weight);
+}
+
+void RoomFile::load(Common::SeekableReadStream *src) {
+ src->read(picture_base, 80);
+ src->readMultipleLE(misc);
+ src->readMultipleLE(num_variants, num_hotspots, num_rails, front_y, back_y, front_scale, back_scale);
+ src->readMultipleLE(depth_table);
+
+ for (int i = 0; i < ROOM_MAX_RAILS; ++i)
+ rail[i].load(src);
+
+ shadow.load(src);
+}
+
+//====================================================================
+
int room_read_def(int room_code, char *room_file, char *picture_base, int mads_mode) {
int result = -1;
int count;
@@ -148,10 +169,15 @@ RoomPtr room_load(int id, int variant, const char *base_path, Buffer *picture,
}
/* Load room header block */
+ {
+ byte buffer[RoomFile::SIZE];
+ if (!loader_read(buffer, RoomFile::SIZE, 1, &load_handle)) {
+ room_load_error = 2;
+ goto done;
+ }
- if (!loader_read(&roomfile, sizeof(RoomFile), 1, &load_handle)) {
- room_load_error = 2;
- goto done;
+ Common::MemoryReadStream src(buffer, RoomFile::SIZE);
+ roomfile.load(&src);
}
Common::strcpy_s(block_name, "$ROOM");
diff --git a/engines/mads/madsv2/core/room.h b/engines/mads/madsv2/core/room.h
index 488b5209215..5ebe88c9330 100644
--- a/engines/mads/madsv2/core/room.h
+++ b/engines/mads/madsv2/core/room.h
@@ -22,6 +22,7 @@
#ifndef MADS_CORE_ROOM_H
#define MADS_CORE_ROOM_H
+#include "common/stream.h"
#include "mads/madsv2/core/general.h"
#include "mads/madsv2/core/vocab.h"
#include "mads/madsv2/core/color.h"
@@ -108,10 +109,13 @@ typedef HotSpot *HotPtr;
/* "Rail" nodes for smart walk */
-typedef struct Rail {
- int x, y; /* Screen location of node */
+struct Rail {
+ int16 x, y; /* Screen location of node */
word weight[ROOM_MAX_RAILS + 2]; /* Distance to other nodes in room */
-} Rail;
+
+ static constexpr int SIZE = 2 + 2 + 2 * (ROOM_MAX_RAILS + 2);
+ void load(Common::SeekableReadStream *src);
+};
typedef Rail *RailPtr;
@@ -156,7 +160,7 @@ typedef RoomPict RoomPictPtr;
/* Room definition structure (.DEF files) */
-typedef struct {
+struct RoomDef {
char picture_base[80]; /* Picture base */
@@ -174,36 +178,28 @@ typedef struct {
Rail rail[ROOM_MAX_RAILS + 2];/* Smart walk rails */
ShadowList shadow; /* Shadow list */
-
-} RoomDef;
+};
/* Loadable Room definition (.DAT files) */
-
-typedef struct {
- /* int id; Room number */
- /* int picture_id; Room whose ART file is needed */
- /* int format; Room format (panning/normal) */
- /* int xs, ys; X and Y size of room picture */
- char picture_base[80]; /* Picture base name */
- int misc[10]; /* Padding for future updates */
- int num_variants; /* Number of attribute variants */
- int num_hotspots; /* Number of hot spots */
- int num_rails; /* Number of rail nodes */
- int front_y, back_y; /* Player scaling baselines */
- int front_scale, back_scale; /* Player scaling factors */
- int depth_table[16]; /* Player depth table */
- Rail rail[ROOM_MAX_RAILS]; /* Rail nodes for room */
-
- /* int num_series; Number of background series */
- /* int num_images; Number of background images */
-
- /* char series_name[ROOM_MAX_SERIES][64]; Sprite series needed */
- /* Image image_list [ROOM_MAX_IMAGES]; Images to be drawn */
-
- ShadowList shadow; /* Shadow list */
-} RoomFile;
+struct RoomFile {
+ char picture_base[80]; /* Picture base name */
+ uint16 misc[10]; /* Padding for future updates */
+ uint16 num_variants; /* Number of attribute variants */
+ uint16 num_hotspots; /* Number of hot spots */
+ uint16 num_rails; /* Number of rail nodes */
+ uint16 front_y, back_y; /* Player scaling baselines */
+ uint16 front_scale, back_scale; /* Player scaling factors */
+ uint16 depth_table[16]; /* Player depth table */
+ Rail rail[ROOM_MAX_RAILS]; /* Rail nodes for room */
+
+ ShadowList shadow; /* Shadow list */
+
+ static constexpr int SIZE = 80 + (2 * 10) + 2 + 2 + 2 + (2 + 2) + (2 + 2) + 2 * 16 +
+ (Rail::SIZE * ROOM_MAX_RAILS) + ShadowList::SIZE;
+ void load(Common::SeekableReadStream *src);
+};
diff --git a/engines/mads/madsv2/core/tile.cpp b/engines/mads/madsv2/core/tile.cpp
index 0aef208ba6b..340fa3e5980 100644
--- a/engines/mads/madsv2/core/tile.cpp
+++ b/engines/mads/madsv2/core/tile.cpp
@@ -19,6 +19,7 @@
*
*/
+#include "common/memstream.h"
#include "mads/madsv2/core/general.h"
#include "mads/madsv2/core/anim.h"
#include "mads/madsv2/core/ems.h"
@@ -49,6 +50,24 @@ int tile_picture_handle = -1;
int tile_attribute_handle = -1;
+void TileMapHeader::load(Common::SeekableReadStream *src) {
+ src->readMultipleLE(tile_type, one_to_one, num_x_tiles, num_y_tiles,
+ tile_x_size, tile_y_size, viewport_x, viewport_y, orig_x_size, orig_y_size,
+ orig_x_tiles, orig_y_tiles, total_x_size, total_y_size);
+ src->readMultipleLE(pan_x, pan_y, pan_tile_x, pan_tile_y, pan_base_x, pan_base_y,
+ pan_offset_x, pan_offset_y);
+ src->skip(8); // skip resource and buffer pointers
+
+ resource = nullptr;
+ buffer = nullptr;
+ map = nullptr;
+}
+
+void TileResource::load(Common::SeekableReadStream *src) {
+ src->readMultipleLE(num_tiles, tile_x, tile_y, compression, ems_handle,
+ num_pages, tiles_per_page, chunk_size, color_handle);
+}
+
int tile_load(const char *base, int tile_type, TileResource *tile_resource,
TileMapHeader *map, Buffer *picture, ColorListPtr color_list,
@@ -118,27 +137,42 @@ int tile_load(const char *base, int tile_type, TileResource *tile_resource,
}
/* Read map header record */
+ {
+ byte buffer[TileMapHeader::SIZE];
+ if (!loader_read(buffer, TileMapHeader::SIZE, 1, &load_handle)) {
+ tile_load_error = 2;
+ map->map = NULL;
+ goto done;
+ }
- if (!loader_read(map, sizeof(TileMapHeader), 1, &load_handle)) {
- tile_load_error = 2;
- map->map = NULL;
- goto done;
+ Common::MemoryReadStream src(buffer, TileMapHeader::SIZE);
+ map->load(&src);
}
/* Compute map size and read map */
map->tile_type = tile_type;
- map_size = (map->num_x_tiles * map->num_y_tiles) * sizeof(int);
- map->map = (int *)mem_get_name(map_size, "$map$");
+ map_size = (map->num_x_tiles * map->num_y_tiles) * sizeof(int16);
+ map->map = (int16 *)mem_get_name(map_size, "$map$");
if (map->map == NULL) {
tile_load_error = 3;
goto done;
}
- if (!loader_read(map->map, map_size, 1, &load_handle)) {
- tile_load_error = 4;
- goto done;
+ {
+ byte *buffer = (byte *)malloc(map_size);
+
+ if (!loader_read(buffer, map_size, 1, &load_handle)) {
+ free(buffer);
+ tile_load_error = 4;
+ goto done;
+ }
+
+ const int16 *src = (const int16 *)buffer;
+ for (int i = 0; i < map_size / 2; ++i, ++src)
+ map->map[i] = READ_LE_INT16(src);
+ free(buffer);
}
loader_close(&load_handle);
@@ -158,10 +192,15 @@ int tile_load(const char *base, int tile_type, TileResource *tile_resource,
}
/* Read tile resource header record */
+ {
+ byte buffer[TileResource::SIZE];
+ if (!loader_read(buffer, TileResource::SIZE, 1, &load_handle)) {
+ tile_load_error = 6;
+ goto done;
+ }
- if (!loader_read(tile_resource, sizeof(TileResource), 1, &load_handle)) {
- tile_load_error = 6;
- goto done;
+ Common::MemoryReadStream src(buffer, TileResource::SIZE);
+ tile_resource->load(&src);
}
/* Initialize map structure parameters */
@@ -239,10 +278,17 @@ int tile_load(const char *base, int tile_type, TileResource *tile_resource,
}
if (tile_space) {
- if (!loader_read(tile, tile_space, 1, &load_handle)) {
+ byte *buffer = (byte *)malloc(tile_space);
+ if (!loader_read(buffer, tile_space, 1, &load_handle)) {
+ free(buffer);
tile_load_error = 10;
goto done;
}
+
+ Common::MemoryReadStream src(buffer, tile_space);
+ Tile *dest = tile;
+ for (int i = 0; i < tile_space / 4; ++i, ++dest)
+ dest->file_offset = src.readSint32LE();
}
/* For background pictures, load color lists and allocate palette space */
@@ -267,14 +313,26 @@ int tile_load(const char *base, int tile_type, TileResource *tile_resource,
}
}
- if (!loader_read(my_color_list, sizeof(ColorList), 1, &load_handle)) {
- tile_load_error = 13;
- goto done;
+ {
+ byte buffer[ColorList::SIZE];
+ if (!loader_read(buffer, ColorList::SIZE, 1, &load_handle)) {
+ tile_load_error = 13;
+ goto done;
+ }
+
+ Common::MemoryReadStream src(buffer, ColorList::SIZE);
+ my_color_list->load(&src);
}
- if (!loader_read(my_cycle_list, sizeof(CycleList), 1, &load_handle)) {
- tile_load_error = 14;
- goto done;
+ {
+ byte buffer[CycleList::SIZE];
+ if (!loader_read(buffer, CycleList::SIZE, 1, &load_handle)) {
+ tile_load_error = 14;
+ goto done;
+ }
+
+ Common::MemoryReadStream src(buffer, ColorList::SIZE);
+ my_cycle_list->load(&src);
}
if (load_flags & TILE_MAP_SHADOW) {
diff --git a/engines/mads/madsv2/core/tile.h b/engines/mads/madsv2/core/tile.h
index 7cf7c8f55d5..0ae53f1d5d3 100644
--- a/engines/mads/madsv2/core/tile.h
+++ b/engines/mads/madsv2/core/tile.h
@@ -45,52 +45,58 @@ namespace MADSV2 {
#define tile_ems_page 0
#define tile_ems_address ems_page[tile_ems_page]
-typedef struct {
- int num_tiles; /* Number of tiles in resource */
- int tile_x; /* Tile X size */
- int tile_y; /* Tile Y size */
- int compression; /* Compression in resource file */
- int ems_handle; /* EMS handle of resource */
- int num_pages; /* Number of pages needed */
- int tiles_per_page; /* Tiles stored per page */
- long chunk_size; /* Tile size in bytes (x*y) */
- int color_handle; /* Color handle for loaded resource */
-} TileResource;
+struct TileResource {
+ uint16 num_tiles; /* Number of tiles in resource */
+ int16 tile_x; /* Tile X size */
+ int16 tile_y; /* Tile Y size */
+ int16 compression; /* Compression in resource file */
+ int16 ems_handle; /* EMS handle of resource */
+ uint16 num_pages; /* Number of pages needed */
+ uint16 tiles_per_page; /* Tiles stored per page */
+ uint32 chunk_size; /* Tile size in bytes (x*y) */
+ int16 color_handle; /* Color handle for loaded resource */
+
+ static constexpr int SIZE = 2 + 2 + 2 + 2 + 2 + 2 + 2 + 4 + 2;
+ void load(Common::SeekableReadStream *src);
+};
typedef struct {
- long file_offset;
+ int32 file_offset;
} Tile;
-typedef struct {
- int tile_type; /* Type of tile */
- int one_to_one; /* One-to-one ratio with scr_orig */
- int num_x_tiles; /* Number of X tiles in map */
- int num_y_tiles; /* Number of Y tiles in map */
- int tile_x_size; /* Tile X size */
- int tile_y_size; /* Tile Y size */
- int viewport_x; /* Viewport X size */
- int viewport_y; /* Viewport Y size */
- int orig_x_size; /* Orig buffer X pixel size */
- int orig_y_size; /* Orig buffer Y pixel size */
- int orig_x_tiles; /* Orig buffer X tile size */
- int orig_y_tiles; /* Orig buffer Y tile size */
- int total_x_size; /* Total picture X size (pixels) */
- int total_y_size; /* Total picture Y size (pixels) */
-
- int pan_x; /* Panned to pixel X value */
- int pan_y; /* Panned to pixel Y value */
- int pan_tile_x; /* Panned to tile X value */
- int pan_tile_y; /* Panned to tile Y value */
- int pan_base_x; /* Base orig screen pixel X value */
- int pan_base_y; /* Base orig screen pixel Y value */
- int pan_offset_x; /* Panning orig offset to work X */
- int pan_offset_y; /* Panning orig offset to work Y */
+struct TileMapHeader {
+ uint16 tile_type; /* Type of tile */
+ uint16 one_to_one; /* One-to-one ratio with scr_orig */
+ uint16 num_x_tiles; /* Number of X tiles in map */
+ uint16 num_y_tiles; /* Number of Y tiles in map */
+ uint16 tile_x_size; /* Tile X size */
+ uint16 tile_y_size; /* Tile Y size */
+ uint16 viewport_x; /* Viewport X size */
+ uint16 viewport_y; /* Viewport Y size */
+ uint16 orig_x_size; /* Orig buffer X pixel size */
+ uint16 orig_y_size; /* Orig buffer Y pixel size */
+ uint16 orig_x_tiles; /* Orig buffer X tile size */
+ uint16 orig_y_tiles; /* Orig buffer Y tile size */
+ uint16 total_x_size; /* Total picture X size (pixels) */
+ uint16 total_y_size; /* Total picture Y size (pixels) */
+
+ int16 pan_x; /* Panned to pixel X value */
+ int16 pan_y; /* Panned to pixel Y value */
+ int16 pan_tile_x; /* Panned to tile X value */
+ int16 pan_tile_y; /* Panned to tile Y value */
+ int16 pan_base_x; /* Base orig screen pixel X value */
+ int16 pan_base_y; /* Base orig screen pixel Y value */
+ int16 pan_offset_x; /* Panning orig offset to work X */
+ int16 pan_offset_y; /* Panning orig offset to work Y */
TileResource *resource; /* Resource pointer */
Buffer *buffer; /* Buffer pointer */
- int *map; /* Picture tile map pointer */
-} TileMapHeader;
+ int16 *map; /* Picture tile map pointer (not in size) */
+
+ static constexpr int SIZE = (14 * 2) + (8 * 2) + 4 + 4;
+ void load(Common::SeekableReadStream *src);
+};
extern ShadowList tile_shadow;
extern int tile_load_error;
diff --git a/engines/mads/madsv2/phantom/main.cpp b/engines/mads/madsv2/phantom/main.cpp
index 4842e38d586..a4cd4929f09 100644
--- a/engines/mads/madsv2/phantom/main.cpp
+++ b/engines/mads/madsv2/phantom/main.cpp
@@ -44,7 +44,7 @@ static void main_menu_main() {
auto &screen = *g_engine->getScreen();
Palette palette;
- if (kernel_game_startup(19, KERNEL_STARTUP_CURSOR | KERNEL_STARTUP_INTERRUPT | KERNEL_STARTUP_FONT,
+ if (!kernel_game_startup(19, KERNEL_STARTUP_CURSOR | KERNEL_STARTUP_INTERRUPT | KERNEL_STARTUP_FONT,
nullptr, nullptr)) {
viewing_at_y = (200 - scr_work.y) >> 1;
Commit: 406d7d73006eabf90a2aad3c62b61050a8f66b46
https://github.com/scummvm/scummvm/commit/406d7d73006eabf90a2aad3c62b61050a8f66b46
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:21:19+10:00
Commit Message:
MADS: PHANTOM: Fix decompressing last tile in tile_load
Changed paths:
engines/mads/madsv2/core/pack.h
engines/mads/madsv2/core/tile.cpp
diff --git a/engines/mads/madsv2/core/pack.h b/engines/mads/madsv2/core/pack.h
index 66883108da4..e62ecb6816b 100644
--- a/engines/mads/madsv2/core/pack.h
+++ b/engines/mads/madsv2/core/pack.h
@@ -79,7 +79,7 @@ namespace MADSV2 {
#define PACK_PRIORITY_INTERFACES 10
#define PACK_PRIORITY_ROOM_ART 11
-#define PACK_OVERHEAD sizeof(PackList)
+#define PACK_OVERHEAD PackList::SIZE
struct PackStrategy {
byte type;
@@ -88,13 +88,12 @@ struct PackStrategy {
long compressed_size;
void load(Common::SeekableReadStream *src);
- static uint SIZE() {
- return 1 + 1 + 4 + 4;
- }
+ static constexpr int SIZE = 1 + 1 + 4 + 4;
};
typedef PackStrategy *PackStrategyPtr;
+#define PACK_HEADER (PACK_ID_LENGTH + 2)
struct PackList {
char id_string[PACK_ID_LENGTH];
@@ -102,13 +101,9 @@ struct PackList {
PackStrategy strategy[PACK_MAX_LIST_LENGTH];
bool load(Common::SeekableReadStream *src);
- static uint SIZE() {
- return PACK_ID_LENGTH + 2 + (PackStrategy::SIZE() * PACK_MAX_LIST_LENGTH);
- }
+ static constexpr int SIZE = PACK_HEADER + PackStrategy::SIZE * PACK_MAX_LIST_LENGTH;
};
-#define PACK_HEADER (PACK_ID_LENGTH + 2)
-
typedef PackList *PackListPtr;
diff --git a/engines/mads/madsv2/core/tile.cpp b/engines/mads/madsv2/core/tile.cpp
index 340fa3e5980..03cd162ba8c 100644
--- a/engines/mads/madsv2/core/tile.cpp
+++ b/engines/mads/madsv2/core/tile.cpp
@@ -481,7 +481,7 @@ int tile_load(const char *base, int tile_type, TileResource *tile_resource,
if (pack_data(packing_flag, tile_resource->chunk_size,
FROM_MEMORY, decompress_buffer,
- TO_MEMORY, tile_buffer.data) != tile_resource->chunk_size) {
+ TO_MEMORY, tile_buffer.data) != (long)tile_resource->chunk_size) {
tile_load_error = 51;
goto done;
}
@@ -496,7 +496,7 @@ int tile_load(const char *base, int tile_type, TileResource *tile_resource,
if (!already_unpacked) {
if (pack_data(packing_flag, tile_resource->chunk_size,
FROM_DISK, load_handle.handle,
- TO_MEMORY, tile_buffer.data) != tile_resource->chunk_size) {
+ TO_MEMORY, tile_buffer.data) != (long)tile_resource->chunk_size) {
tile_load_error = 19;
goto done;
}
Commit: 47079f0d2ee23f1a80daa2ef1b8cc468918c5c47
https://github.com/scummvm/scummvm/commit/47079f0d2ee23f1a80daa2ef1b8cc468918c5c47
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:21:19+10:00
Commit Message:
MADS: PHANTOM: Implementing timer read functions
Changed paths:
engines/mads/madsv2/core/timer.cpp
engines/mads/madsv2/core/timer.h
diff --git a/engines/mads/madsv2/core/timer.cpp b/engines/mads/madsv2/core/timer.cpp
index 4b1684fc570..a7db0ae8c47 100644
--- a/engines/mads/madsv2/core/timer.cpp
+++ b/engines/mads/madsv2/core/timer.cpp
@@ -19,6 +19,7 @@
*
*/
+#include "common/system.h"
#include "common/textconsole.h"
#include "mads/madsv2/core/general.h"
#include "mads/madsv2/core/timer.h"
@@ -43,71 +44,28 @@ word timer_low_stacking;
word timer_low_deferred;
void *timer_low_routine;
-long timer_600_low;
-long timer_60_low;
-long timer_dos_low;
-
-/*
-/* Reads system clock, returns number of ticks since midnight.
-*/
-long timer_read(void) {
- return (*timer_address);
-}
-
-
-long timer_read_dos(void) {
- return (*dos_timer_address);
-}
-
-
-long timer_read_600(void) {
- return (timer_600_low);
-}
-
-long timer_read_60(void) {
- return (timer_60_low);
+void timer_install() {
+ // No implementation in ScummVM
}
-/*
-/* This works around annoying MASM problem requiring us to make
-/* reference to code segment in order to get data segment stuff
-/* linked from an OBJ. This routine does not exist to be called
-/* but rather to make the required references in case the main
-/* program does not.
-*/
-void timer_hack(void) {
- timer_install();
- /* pl sound_manager(); */
- /* pl sound_driver_null(); */
- timer_remove();
+void timer_remove() {
+ // No implementation in ScummVM
}
-
-void timer_set_rate(word count_down) {
- warning("TODO: timer_set_rate");
-#ifdef TODO
- _asm {
- cli; Interrupts begone
-
- mov al, 00110110b; Timer chanel 0
- out 43h, al; Declare our intention to reprogram
- mov ax, count_down; Get new countdown value
- out 40h, al; Send low part
- mov al, ah
- out 40h, al; Send high part
-
- sti; Interrupts come hither
- }
-#endif
+long timer_read() {
+ unsigned long ms = g_system->getMillis();
+ return ms * 1193 / 65536;
}
-void timer_install() {
- // No implementation in ScummVM
+long timer_read_600() {
+ unsigned long ms = g_system->getMillis();
+ return ms * 600 / 1000;
}
-void timer_remove() {
- // No implementation in ScummVM
+long timer_read_60() {
+ unsigned long ms = g_system->getMillis();
+ return ms * 60 / 1000;
}
void timer_set_sound_flag(int sound_flag) {
@@ -129,7 +87,7 @@ void timer_activate_low_priority(void (*(routine))()) {
warning("TODO: timer_activate_low_priority");
}
-byte *timer_get_interrupt_stack(void) {
+byte *timer_get_interrupt_stack() {
return _interrupt_stack;
}
diff --git a/engines/mads/madsv2/core/timer.h b/engines/mads/madsv2/core/timer.h
index 92d2404046c..0c952a3a678 100644
--- a/engines/mads/madsv2/core/timer.h
+++ b/engines/mads/madsv2/core/timer.h
@@ -48,11 +48,16 @@ extern long timer_dos_low;
/* extern byte *interrupt_stack_pointer; */
/* extern word interrupt_stack_size; */
-/* timer_1.c */
-long timer_read(void);
-long timer_read_dos(void);
-long timer_read_600(void);
-long timer_read_60(void);
+/**
+ * Reads system clock, returns number of ticks since startup (1 tick = 54.9ms)
+ */
+long timer_read();
+inline long timer_read_dos() {
+ return timer_read();
+}
+
+long timer_read_600();
+long timer_read_60();
void timer_set_rate(word count_down);
/**
@@ -75,10 +80,10 @@ void timer_set_sound_flag(int sound_flag);
*/
void timer_activate_low_priority(void (*(routine))());
-byte *timer_get_interrupt_stack(void);
+byte *timer_get_interrupt_stack();
int timer_set_copy_protect(int protect);
-int timer_get_copy_protect(void);
+int timer_get_copy_protect();
} // namespace MADSV2
} // namespace MADS
Commit: 1f63de2eeb67860e50b222603a7f916aadb33ca2
https://github.com/scummvm/scummvm/commit/1f63de2eeb67860e50b222603a7f916aadb33ca2
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:21:19+10:00
Commit Message:
MADS: PHANTOM: Hotspots loading code
Changed paths:
engines/mads/madsv2/core/room.cpp
engines/mads/madsv2/core/room.h
diff --git a/engines/mads/madsv2/core/room.cpp b/engines/mads/madsv2/core/room.cpp
index e7d160fc3c6..0b5f4ed72a2 100644
--- a/engines/mads/madsv2/core/room.cpp
+++ b/engines/mads/madsv2/core/room.cpp
@@ -72,6 +72,11 @@ void RoomFile::load(Common::SeekableReadStream *src) {
shadow.load(src);
}
+void HotSpot::load(Common::SeekableReadStream *src) {
+ src->readMultipleLE(ul_x, ul_y, lr_x, lr_y, feet_x, feet_y,
+ facing, prep, active, cursor_number, syntax, vocab, verb);
+}
+
//====================================================================
int room_read_def(int room_code, char *room_file, char *picture_base, int mads_mode) {
@@ -371,21 +376,42 @@ HotPtr room_load_hotspots(int id, int *num_spots) {
spots = NULL;
- /* env_get_level_path (temp_buf, ROOM, ".HH", 0, id); */
Common::strcpy_s(temp_buf, "*RM");
env_catint(temp_buf, id, 3);
Common::strcat_s(temp_buf, ".HH");
- if (loader_open(&load_handle, temp_buf, "rb", true)) goto done;
+ if (loader_open(&load_handle, temp_buf, "rb", true))
+ goto done;
- if (!loader_read(num_spots, sizeof(int), 1, &load_handle)) goto done;
+ {
+ byte buffer[2];
+ if (!loader_read(buffer, sizeof(int), 1, &load_handle))
+ goto done;
+
+ *num_spots = READ_LE_UINT16(buffer);
+ }
num_to_read = MAX(*num_spots, 1);
memory_needed = (num_to_read * sizeof(HotSpot));
spots = (HotPtr)mem_get_name(memory_needed, "$hotspot");
- if (spots == NULL) goto done;
+ if (spots == NULL)
+ goto done;
- if (!loader_read(spots, memory_needed, 1, &load_handle)) goto done;
+ // Read in the hotspot list
+ {
+ size_t bytes_to_read = num_to_read * HotSpot::SIZE;
+ byte *buffer = (byte *)malloc(bytes_to_read);
+ if (!loader_read(spots, memory_needed, 1, &load_handle)) {
+ free(buffer);
+ goto done;
+ }
+
+ Common::MemoryReadStream src(buffer, bytes_to_read);
+ for (int i = 0; i < num_to_read; ++i)
+ spots[i].load(&src);
+
+ free(buffer);
+ }
result = spots;
diff --git a/engines/mads/madsv2/core/room.h b/engines/mads/madsv2/core/room.h
index 5ebe88c9330..10795b9a952 100644
--- a/engines/mads/madsv2/core/room.h
+++ b/engines/mads/madsv2/core/room.h
@@ -92,17 +92,20 @@ typedef HotSpotEdit *HotEditPtr;
/* Run-time structure for hotspots (.HH files) */
-typedef struct {
- int ul_x, ul_y, lr_x, lr_y; /* Hotspot screen coordinates */
- int feet_x, feet_y; /* Walk-to target for player */
+struct HotSpot {
+ int16 ul_x, ul_y, lr_x, lr_y; /* Hotspot screen coordinates */
+ int16 feet_x, feet_y; /* Walk-to target for player */
byte facing; /* Direction player should face */
byte prep; /* Preposition */
byte active; /* Flag if hotspot is active */
byte cursor_number; /* Mouse cursor number */
byte syntax; /* Syntax */
- int vocab; /* Vocabulary id of hotspot name */
- int verb; /* Vocabulary id of default verb */
-} HotSpot;
+ int16 vocab; /* Vocabulary id of hotspot name */
+ int16 verb; /* Vocabulary id of default verb */
+
+ static constexpr int SIZE = 6 * 2 + (5 * 1) + 2 + 2;
+ void load(Common::SeekableReadStream *src);
+};
typedef HotSpot *HotPtr;
Commit: 27a29711d36c1b9db950f83eddb54b113af9589e
https://github.com/scummvm/scummvm/commit/27a29711d36c1b9db950f83eddb54b113af9589e
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:21:19+10:00
Commit Message:
MADS: PHANTOM: Don't load hotspots for Phantom title screen
Phantom's mainmenu.exe has a variant of kernel_room_startup
that doesn't have the code for loading hotspots that the main
game has. And so trying to load the main menu's room 922 caused
a crash. Added a parameter to allow the calling code from the
main menu to tell to ignore loading the hotspots.
Changed paths:
engines/mads/madsv2/core/kernel.cpp
engines/mads/madsv2/core/kernel.h
engines/mads/madsv2/phantom/main.cpp
diff --git a/engines/mads/madsv2/core/kernel.cpp b/engines/mads/madsv2/core/kernel.cpp
index fb6ab188729..32546ea7fb5 100644
--- a/engines/mads/madsv2/core/kernel.cpp
+++ b/engines/mads/madsv2/core/kernel.cpp
@@ -608,7 +608,8 @@ void kernel_room_shutdown() {
}
}
-int kernel_room_startup(int newRoom, int initial_variant, char *interface, bool new_palette) {
+int kernel_room_startup(int newRoom, int initial_variant, const char *interface,
+ bool new_palette, bool barebones) {
int error_flag = true;
int load_flags;
#ifndef disable_error_check
@@ -689,16 +690,6 @@ int kernel_room_startup(int newRoom, int initial_variant, char *interface, bool
rail_connect_all_nodes();
- /* Load up the room's hotspot table */
-
- room_spots = room_load_hotspots(room_id, &room_num_spots);
- if (room_spots == NULL) {
-#ifndef disable_error_check
- error_code = ERROR_KERNEL_NO_HOTSPOTS;
-#endif
- goto done;
- }
-
inter_anim = NULL;
/* Make preliminary scaling computations */
@@ -721,15 +712,27 @@ int kernel_room_startup(int newRoom, int initial_variant, char *interface, bool
kernel_room_series_marker = series_list_marker;
- /* Set up interface background screen */
+ if (barebones) {
+ room_spots = nullptr;
- kernel_set_interface_mode(inter_input_mode);
+ } else {
+ // Load up the room's hotspot table
+ room_spots = room_load_hotspots(room_id, &room_num_spots);
+ if (room_spots == NULL) {
+#ifndef disable_error_check
+ error_code = ERROR_KERNEL_NO_HOTSPOTS;
+#endif
+ goto done;
+ }
- /* Mouse cursor on */
+ // Set up interface background screen
+ kernel_set_interface_mode(inter_input_mode);
- while ((char)mouse_showing > 0) mouse_show();
+ // Mouse cursor on
+ mouse_show();
- inter_allocate_objects();
+ inter_allocate_objects();
+ }
error_flag = false;
diff --git a/engines/mads/madsv2/core/kernel.h b/engines/mads/madsv2/core/kernel.h
index 7a1583250d9..86523d1d848 100644
--- a/engines/mads/madsv2/core/kernel.h
+++ b/engines/mads/madsv2/core/kernel.h
@@ -441,7 +441,7 @@ extern int kernel_section_startup(int new_section);
extern void kernel_room_shutdown();
extern int kernel_room_startup(int new_room, int initial_variant = 0,
- char *interface = nullptr, bool new_palette = true);
+ const char *interface = nullptr, bool new_palette = true, bool barebones = false);
/**
* Unloads all room series.
diff --git a/engines/mads/madsv2/phantom/main.cpp b/engines/mads/madsv2/phantom/main.cpp
index a4cd4929f09..a20aa55284f 100644
--- a/engines/mads/madsv2/phantom/main.cpp
+++ b/engines/mads/madsv2/phantom/main.cpp
@@ -69,7 +69,7 @@ static void main_menu_main() {
97, 98, 99, 0);
global_speech_load(9);
- bool valid = !kernel_room_startup(922);
+ bool valid = !kernel_room_startup(922, 0, nullptr, true, true);
master_palette[4].r = 63;
master_palette[4].g = 50;
Commit: 3f690b175737045e4cb900df787b85c3f2f5e690
https://github.com/scummvm/scummvm/commit/3f690b175737045e4cb900df787b85c3f2f5e690
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:21:20+10:00
Commit Message:
MADS: PHANTOM: Added ERROR_MESSAGES array
Changed paths:
engines/mads/madsv2/core/error.cpp
diff --git a/engines/mads/madsv2/core/error.cpp b/engines/mads/madsv2/core/error.cpp
index 0e411cc3546..6225d7b94ad 100644
--- a/engines/mads/madsv2/core/error.cpp
+++ b/engines/mads/madsv2/core/error.cpp
@@ -48,6 +48,78 @@ void (*error_service_routine_2)() = NULL;
int error_abort = WARNING;
char error_string[80] = "";
+static const char *ERROR_MESSAGES[] = {
+ nullptr,
+ "ERROR_SERIES_LIST_FULL",
+ "ERROR_MESSAGE_LIST_FULL",
+ "ERROR_IMAGE_LIST_FULL",
+ "ERROR_IMAGE_INTER_LIST_FULL",
+ "ERROR_NO_MORE_PALETTE_FLAGS",
+ "ERROR_NO_MORE_COLORS",
+ "ERROR_SERIES_LOAD_FAILED",
+ "ERROR_NO_MORE_MEMORY",
+ "ERROR_WRONG_SERIES_UNLOAD_ORDER",
+ "ERROR_PLAYER_INVENTORY_FULL ",
+
+ "ERROR_SEQUENCE_LIST_FULL",
+ "ERROR_VOCAB_ACTIVE_LIST_FULL",
+ "ERROR_NO_SUCH_OBJECT",
+ "ERROR_NO_SUCH_MESSAGE",
+ "ERROR_POPUP_TOO_MANY_LINES",
+ "ERROR_KERNEL_MESSAGE_LIST_FULL",
+ "ERROR_MESSAGE_TOO_LONG",
+ "ERROR_DEMO_PROTECTION",
+ "ERROR_BEEN_IN_TOO_MANY_ROOMS",
+ "ERROR_COPY_PROTECTION",
+
+ "ERROR_QUOTE_LOAD_FAILED",
+ "ERROR_TIME_LIMIT_EXPIRED",
+ "ERROR_QUOTE_DUPLICATE_LOAD",
+ "ERROR_DYNAMIC_HOTSPOT_OVERFLOW",
+ "ERROR_SPRITE_DATA_LOAD_FAILED",
+ "ERROR_CHAIN_FAILURE",
+ "ERROR_RESTORE_GAME_FAILURE",
+ "ERROR_EXPLODER_EXPLODED",
+ "ERROR_EXPLODER_NULL",
+ "ERROR_ANIMATION_LOAD_FAILURE",
+
+ "ERROR_BREAK_POINT",
+ "ERROR_KERNEL_NO_FONTS",
+ "ERROR_KERNEL_NO_CURSOR",
+ "ERROR_KERNEL_NO_OBJECTS",
+ "ERROR_KERNEL_NO_ROOM",
+ "ERROR_KERNEL_NO_HOTSPOTS",
+ "ERROR_KERNEL_NO_VOCAB",
+ "ERROR_KERNEL_NO_INTERFACE",
+ "ERROR_KERNEL_NO_ANIMATION",
+ "ERROR_KERNEL_NO_EMS",
+
+ "ERROR_KERNEL_NO_POPUP",
+ nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr,
+ "ERROR_CONV_BAD_PCODE",
+
+ "ERROR_CONV_BAD_OPERATOR",
+ "ERROR_CONV_VARIABLE_RANGE",
+ "ERROR_POPUP_OVERFLOW",
+ "ERROR_CONV_FLUSH",
+ "ERROR_CONV_GET",
+ "ERROR_CONV_RUN",
+ "ERROR_CONV_MENU",
+ "ERROR_CONV_NO_TEXT_LINE",
+ "ERROR_NO_MORE_EMS",
+ "ERROR_HEAP_REQUEST_FAILED",
+
+ "ERROR_NO_MORE_HEAP",
+ "ERROR_ORPHANED_TRIGGER",
+ "ERROR_PEELING_DISABLED",
+ "ERROR_POPUP_NO_ITEMS",
+ "ERROR_WRITE_SAVE_DIRECTORY",
+ "ERROR_MEMORY_CHAIN_CORRUPT",
+ "ERROR_POPUP_PRESERVE_FAILURE",
+ "ERROR_TOO_MANY_DAMN_HOTSPOTS",
+ "ERROR_VARIANT_LOAD_FAILURE"
+};
int error_scan(char *target, const char *name, int number) {
@@ -106,7 +178,8 @@ done:
delete handle;
}
-static void error_explode(char *error_buf, char *module_buf, char *data1_buf, char *data2_buf, long avail, int error) {
+static void error_explode(const char *error_buf, const char *module_buf,
+ const char *data1_buf, const char *data2_buf, long avail, int error) {
midi_uninstall();
digi_uninstall();
@@ -117,23 +190,12 @@ static void error_explode(char *error_buf, char *module_buf, char *data1_buf, ch
mouse_init(false, 3);
screen_dominant_mode(text_mode);
- ::error("Execution aborted");
+ ::error("Error %s", error_buf);
}
void error_report(int error, int severity, int module, long data1, long data2) {
- char error_buf[40], module_buf[40], data1_buf[12], data2_buf[12];
- int handled = false;
-
- if (severity >= error_abort) {
- mads_itoa(error, error_buf, 10);
- mads_itoa(module, module_buf, 10);
- ltoa(data1, data1_buf, 10);
- ltoa(data2, data2_buf, 10);
-
- if (!handled) {
- error_explode(error_buf, module_buf, data1_buf, data2_buf, mem_get_avail(), error);
- }
- }
+ const char *msg = error < -1 ? ERROR_MESSAGES[ABS(error)] : "General Error";
+ error_explode(msg, nullptr, nullptr, nullptr, mem_get_avail(), error);
}
void error_break_point(int data1, int data2) {
Commit: 6ee95257504fc0a78c03783df961b7a37593f003
https://github.com/scummvm/scummvm/commit/6ee95257504fc0a78c03783df961b7a37593f003
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:21:20+10:00
Commit Message:
MADS: PHANTOM: Fixes for anim_load
Changed paths:
A engines/mads/madsv2/core/image.cpp
engines/mads/madsv2/core/anim.cpp
engines/mads/madsv2/core/anim.h
engines/mads/madsv2/core/general.h
engines/mads/madsv2/core/image.h
engines/mads/madsv2/core/inter.cpp
engines/mads/module.mk
diff --git a/engines/mads/madsv2/core/anim.cpp b/engines/mads/madsv2/core/anim.cpp
index 57fcb6f88b6..3f27279c385 100644
--- a/engines/mads/madsv2/core/anim.cpp
+++ b/engines/mads/madsv2/core/anim.cpp
@@ -19,6 +19,8 @@
*
*/
+#include "common/algorithm.h"
+#include "common/memstream.h"
#include "mads/madsv2/core/anim.h"
#include "mads/madsv2/core/himem.h"
#include "mads/madsv2/core/env.h"
@@ -41,6 +43,51 @@ namespace MADSV2 {
ShadowList anim_shadow = { 0 };
int anim_error;
+void AnimFile::load(Common::SeekableReadStream *src) {
+ src->readMultipleLE(num_series, num_frames, num_images, num_speech,
+ load_flags, font_auto_spacing, background_type, background_room);
+ src->readMultipleLE(misc);
+ src->read(background_name, 13);
+
+ for (int i = 0; i < AA_MAX_SERIES; ++i)
+ src->read(&series_name[i][0], 13);
+
+ src->read(sound_file_name, 13);
+ src->read(background_depth, 13);
+ src->read(speech_file, 13);
+ src->read(font_file, 13);
+}
+
+void Speech::load(Common::SeekableReadStream *src) {
+ resource_id = src->readSint16LE();
+ src->read(text, 60);
+ src->read(misc, 3);
+ src->readMultipleLE(sound, x, y, display_condition);
+
+ for (int i = 0; i < 2; ++i)
+ color[i].load(src);
+
+ src->readMultipleLE(flags, speech_loops, non_speech_loops, segment_to_loop,
+ first_frame, last_frame, first_image);
+}
+
+void ImageInter::load(Common::SeekableReadStream *src) {
+ src->readMultipleLE(flags, segment_id, series_id, sprite_id, x, y);
+}
+
+void Frame::load(Common::SeekableReadStream *src) {
+ src->readMultipleLE(sound, speech, ticks, view_x, view_y, yank_x, yank_y);
+}
+
+void SegmentInter::load(Common::SeekableReadStream *src) {
+ src->readMultipleLE(probability, num_images, first_image, last_image, counter);
+ src->read(spawn, AA_MAX_SPAWNED);
+ src->readMultipleLE(spawn_frame);
+ src->readMultipleLE(sound, sound_frame);
+}
+
+
+//====================================================================
int anim_load_background(AnimFile *anim_in, Buffer *this_orig,
Buffer *this_depth, TileMapHeader *pictureMap, TileMapHeader *depthMap,
@@ -171,7 +218,7 @@ AnimPtr anim_load(const char *file_name, Buffer *orig, Buffer *depth,
word *color_slaves = (word *)temp_buf;
word num_color_slaves;
long image_size, frame_size, speech_size, anim_size;
- AnimPtr anim = NULL;
+ AnimPtr anim = NULL;
AnimInterPtr anim2 = NULL;
AnimFile anim_in;
Load load_handle;
@@ -188,10 +235,18 @@ AnimPtr anim_load(const char *file_name, Buffer *orig, Buffer *depth,
star_search = (temp_buf[0] == '*');
anim_error = 1;
- if (loader_open(&load_handle, temp_buf, "rb", true)) goto done;
+ if (loader_open(&load_handle, temp_buf, "rb", true))
+ goto done;
- anim_error = 2;
- if (!loader_read(&anim_in, sizeof(AnimFile), 1, &load_handle)) goto done;
+ {
+ anim_error = 2;
+ byte buffer[AnimFile::SIZE];
+ if (!loader_read(buffer, sizeof(AnimFile), 1, &load_handle))
+ goto done;
+
+ Common::MemoryReadStream src(buffer, AnimFile::SIZE);
+ anim_in.load(&src);
+ }
if (anim_in.background_type == AA_INTERFACE) {
load_flags |= PAL_MAP_RESERVED;
@@ -257,20 +312,33 @@ AnimPtr anim_load(const char *file_name, Buffer *orig, Buffer *depth,
}
// get ready for loading some series
- for (count = 0; count < AA_MAX_SERIES; count++) {
- anim->series[count] = NULL;
- }
+ Common::fill(anim->series, anim->series + AA_MAX_SERIES, (SeriesPtr)nullptr);
+ Common::fill(anim->series_id, anim->series_id + AA_MAX_SERIES, -1);
// we read the header before, now get it into our new structure
memcpy(anim, &anim_in, sizeof(AnimFile));
- for (count = 0; count < anim->num_series; count++) {
- anim->series_id[count] = -1;
- }
-
if (speech_size > 0) {
anim_error = 5;
- if (!loader_read(anim->speech, speech_size, 1, &load_handle)) goto done;
+
+ size_t size = Speech::SIZE * anim_in.num_speech;
+ byte *buffer = (byte *)malloc(size);
+ if (!loader_read(buffer, speech_size, 1, &load_handle)) {
+ free(buffer);
+ goto done;
+ }
+
+ Common::MemoryReadStream src(buffer, size);
+
+ if (anim_in.background_type == AA_INTERFACE) {
+ for (int i = 0; i < anim_in.num_speech; ++i)
+ anim2->speech[i].load(&src);
+ } else {
+ for (int i = 0; i < anim_in.num_speech; ++i)
+ anim->speech[i].load(&src);
+ }
+
+ free(buffer);
}
// x, y, depth, s, series and sprite id comprise an image
@@ -278,7 +346,25 @@ AnimPtr anim_load(const char *file_name, Buffer *orig, Buffer *depth,
if (image_size > 0) {
anim_error = 6;
- if (!loader_read(anim->image, image_size, 1, &load_handle)) goto done;
+
+ size_t size = (anim_in.background_type == AA_INTERFACE ? ImageInter::SIZE : Image::SIZE) * anim_in.num_images;
+ byte *buffer = (byte *)malloc(size);
+ if (!loader_read(buffer, size, 1, &load_handle)) {
+ free(buffer);
+ goto done;
+ }
+
+ Common::MemoryReadStream src(buffer, size);
+
+ if (anim_in.background_type == AA_INTERFACE) {
+ for (int i = 0; i < anim_in.num_images; ++i)
+ anim2->image[i].load(&src);
+ } else {
+ for (int i = 0; i < anim_in.num_images; ++i)
+ anim->image[i].load(&src);
+ }
+
+ free(buffer);
}
// a frame contains timing information and sound effect information
@@ -286,9 +372,26 @@ AnimPtr anim_load(const char *file_name, Buffer *orig, Buffer *depth,
if (frame_size > 0) {
anim_error = 7;
- if (!loader_read(anim->frame, frame_size, 1, &load_handle)) goto done;
- }
+ size_t size = (anim_in.background_type == AA_INTERFACE ? SegmentInter::SIZE : Frame::SIZE) * anim_in.num_frames;
+ byte *buffer = (byte *)malloc(size);
+ if (!loader_read(buffer, size, 1, &load_handle)) {
+ free(buffer);
+ goto done;
+ }
+
+ Common::MemoryReadStream src(buffer, size);
+
+ if (anim_in.background_type == AA_INTERFACE) {
+ for (int i = 0; i < anim_in.num_frames; ++i)
+ anim2->segment[i].load(&src);
+ } else {
+ for (int i = 0; i < anim_in.num_frames; ++i)
+ anim->frame[i].load(&src);
+ }
+
+ free(buffer);
+ }
loader_close(&load_handle);
diff --git a/engines/mads/madsv2/core/anim.h b/engines/mads/madsv2/core/anim.h
index 77d4efc2ba7..258f85967e3 100644
--- a/engines/mads/madsv2/core/anim.h
+++ b/engines/mads/madsv2/core/anim.h
@@ -22,6 +22,8 @@
#ifndef MADS_CORE_ANIM_H
#define MADS_CORE_ANIM_H
+#include "common/stream.h"
+#include "mads/madsv2/core/general.h"
#include "mads/madsv2/core/font.h"
#include "mads/madsv2/core/image.h"
#include "mads/madsv2/core/room.h"
@@ -228,15 +230,17 @@ struct ImageEditBuf {
typedef struct ImageEditBuf ImageEdit;
typedef ImageEdit *ImageEditPtr;
-struct ImageInterBuf {
- int flags;
+struct ImageInter {
+ int16 flags;
byte segment_id;
byte series_id;
byte sprite_id;
- int x;
+ int16 x;
byte y;
+
+ static constexpr int SIZE = 2 + 1 + 1 + 1 + 2 + 1;
+ void load(Common::SeekableReadStream *src);
};
-typedef struct ImageInterBuf ImageInter;
typedef ImageInter *ImageInterPtr;
@@ -270,53 +274,58 @@ typedef struct FrameEditBuf FrameEdit;
typedef FrameEdit *FrameEditPtr;
-struct FrameBuf {
+struct Frame {
byte sound; /* what sound cue to play */
byte speech; /* what speech record to activate */
word ticks; /* how many ticks for this frame (before? after?) */
word view_x; /* where the pan set currently */
word view_y;
- char yank_x; /* for backgrounds which wrap around, like starfields */
- char yank_y;
-};
+ int8 yank_x; /* for backgrounds which wrap around, like starfields */
+ int8 yank_y;
-typedef struct FrameBuf Frame;
+ static constexpr int SIZE = 1 + 1 + 2 + 2 + 2 + 1 + 1;
+ void load(Common::SeekableReadStream *src);
+};
typedef Frame *FramePtr;
-struct SegmentInterBuf {
- int probability;
- int num_images;
- int first_image;
- int last_image;
- int counter;
+struct SegmentInter {
+ int16 probability;
+ int16 num_images;
+ int16 first_image;
+ int16 last_image;
+ int16 counter;
byte spawn[AA_MAX_SPAWNED];
- int spawn_frame[AA_MAX_SPAWNED];
+ int16 spawn_frame[AA_MAX_SPAWNED];
byte sound;
- int sound_frame;
-};
+ int16 sound_frame;
-typedef struct SegmentInterBuf SegmentInter;
+ static constexpr int SIZE = 5 * 2 + AA_MAX_SPAWNED + AA_MAX_SPAWNED * 2 + 1 + 2;
+ void load(Common::SeekableReadStream *src);
+};
typedef SegmentInter *SegmentInterPtr;
-typedef struct {
- int resource_id; /* Speech segment id in resource file */
- char text[60]; /* Text to be displayed */
- byte misc[3]; /* 3 extra bonus bytes */
- byte sound; /* Sound to be used */
+struct Speech {
+ int16 resource_id; /* Speech segment id in resource file */
+ char text[60]; /* Text to be displayed */
+ byte misc[3]; /* 3 extra bonus bytes */
+ byte sound; /* Sound to be used */
/* pl SpeechDirPtr speech; */ /* Binary speech pointer */
- int x, y; /* Text coordinates */
- int display_condition; /* Condition for display */
- RGBcolor color[2]; /* Colors for text display */
- word flags; /* Segment flags */
- int speech_loops; /* Loops if speech active */
- int non_speech_loops; /* Loops if speech inactive */
- int segment_to_loop; /* Segment ID to be looped */
- int first_frame; /* First frame of segment */
- int last_frame; /* Last frame of segment */
- int first_image; /* First image number */
-} Speech;
+ int16 x, y; /* Text coordinates */
+ int16 display_condition; /* Condition for display */
+ RGBcolor color[2]; /* Colors for text display */
+ word flags; /* Segment flags */
+ int16 speech_loops; /* Loops if speech active */
+ int16 non_speech_loops; /* Loops if speech inactive */
+ int16 segment_to_loop; /* Segment ID to be looped */
+ int16 first_frame; /* First frame of segment */
+ int16 last_frame; /* Last frame of segment */
+ int16 first_image; /* First image number */
+
+ static constexpr int SIZE = 2 + 60 + 3 + 1 + 2 + 2 + 2 + 2 * RGBcolor::SIZE + 7 * 2;
+ void load(Common::SeekableReadStream *src);
+};
typedef Speech *SpeechPtr;
@@ -361,92 +370,55 @@ typedef AnimDef *AnimDefPtr;
/* aa file header */
-struct AnimFileBuf {
- int num_series;
- int num_frames;
- int num_images;
- int num_speech;
+struct AnimFile {
+ uint16 num_series;
+ uint16 num_frames;
+ uint16 num_images;
+ uint16 num_speech;
word load_flags;
- int font_auto_spacing;
- int background_type; /* black, or room, or whatever */
- int background_room; /* room number to load */
- int misc[10]; /* see MISC_ defines above */
+ uint16 font_auto_spacing;
+ uint16 background_type; /* black, or room, or whatever */
+ uint16 background_room; /* room number to load */
+ uint16 misc[10]; /* see MISC_ defines above */
char background_name[13]; /* if needed */
char series_name[AA_MAX_SERIES][13]; /* filenames for all your series */
char sound_file_name[13];
char background_depth[13];
char speech_file[13];
char font_file[13];
-};
-typedef struct AnimFileBuf AnimFile;
+ static constexpr int SIZE = (8 * 2) + (10 * 2) + 13 +
+ (AA_MAX_SERIES * 13) + 13 + 13 + 13 + 13 +
+ 1; // structure padding
+ void load(Common::SeekableReadStream *src);
+};
/* runtime memory image for an animation */
-struct AnimBuf {
- int num_series;
- int num_frames;
- int num_images;
- int num_speech;
- word load_flags;
- int font_auto_spacing;
- int background_type;
- int background_room;
- int misc[10];
-
- char background_name[13];
- char series_name[AA_MAX_SERIES][13];
-
- char sound_file_name[13];
- char background_depth[13];
- char speech_file[13];
- char font_file[13];
-
- FontPtr font;
+struct Anim : public AnimFile {
+ FontPtr font;
SpeechPtr speech;
- ImagePtr image; /* to the array of images */
- FramePtr frame; /* to the array of frames */
- SeriesPtr series[AA_MAX_SERIES]; /* pointers to series */
+ ImagePtr image; /* to the array of images */
+ FramePtr frame; /* to the array of frames */
+ SeriesPtr series[AA_MAX_SERIES]; /* pointers to series */
- int series_id[AA_MAX_SERIES];
+ int series_id[AA_MAX_SERIES];
};
-
-typedef struct AnimBuf Anim;
typedef Anim *AnimPtr;
/* the interface version of the above */
-struct AnimInterBuf {
- int num_series;
- int num_segments;
- int num_images;
- int num_speech;
- word load_flags;
- int font_auto_spacing;
- int background_type;
- int background_room;
- int misc[10];
-
- char background_name[13];
- char series_name[AA_MAX_SERIES][13];
-
- char sound_file_name[13];
- char background_depth[13];
- char speech_file[13];
- char font_file[13];
-
- FontPtr font;
+struct AnimInter : public AnimFile {
+ FontPtr font;
SpeechPtr speech;
- ImageInterPtr image;
+ ImageInterPtr image;
SegmentInterPtr segment;
- SeriesPtr series[AA_MAX_SERIES];
+ SeriesPtr series[AA_MAX_SERIES];
- int series_id[AA_MAX_SERIES];
+ int series_id[AA_MAX_SERIES];
};
-
-typedef struct AnimInterBuf AnimInter;
typedef AnimInter *AnimInterPtr;
diff --git a/engines/mads/madsv2/core/general.h b/engines/mads/madsv2/core/general.h
index 7c0a093a811..867d431a09f 100644
--- a/engines/mads/madsv2/core/general.h
+++ b/engines/mads/madsv2/core/general.h
@@ -22,7 +22,7 @@
#ifndef MADS_CORE_GENERAL_H
#define MADS_CORE_GENERAL_H
-#include "common/str.h"
+#include "common/stream.h"
namespace MADS {
namespace MADSV2 {
@@ -39,9 +39,17 @@ typedef uint16 word; /* generic 16 bit data */
/* vertical data types */
-typedef struct {
+/* A single palette color */
+struct RGBcolor {
byte r, g, b;
-} RGBcolor; /* A single palette color */
+
+ static constexpr int SIZE = 3;
+ inline void load(Common::SeekableReadStream *src) {
+ r = src->readByte();
+ g = src->readByte();
+ b = src->readByte();
+ }
+};
typedef RGBcolor Palette[256]; /* An entire Mcga palette */
typedef byte PaletteMap[256][3]; /* An entire Mcga palette #2 */
diff --git a/engines/mads/madsv2/core/image.cpp b/engines/mads/madsv2/core/image.cpp
new file mode 100644
index 00000000000..ca8022c7d04
--- /dev/null
+++ b/engines/mads/madsv2/core/image.cpp
@@ -0,0 +1,32 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "mads/madsv2/core/image.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+void Image::load(Common::SeekableReadStream *src) {
+ src->readMultipleLE(flags, segment_id, series_id, sprite_id, x, y, depth, scale);
+}
+
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/core/image.h b/engines/mads/madsv2/core/image.h
index ab14844b1f8..cce3c1dbcd8 100644
--- a/engines/mads/madsv2/core/image.h
+++ b/engines/mads/madsv2/core/image.h
@@ -22,26 +22,28 @@
#ifndef MADS_CORE_IMAGE_H
#define MADS_CORE_IMAGE_H
-#include "common/scummsys.h"
+#include "common/stream.h"
namespace MADS {
namespace MADSV2 {
-struct ImageBuf {
- int flags; /* refers to the index of the corresponding frame in the anim struct */
+struct Image {
+ int16 flags; /* refers to the index of the corresponding frame in the anim struct */
/* ^^ only true for images which have been anim_loaded... */
/* anim_view dumps these images into lists using flags to tell */
/* when they should be put; the flags then become actual flags */
/* like IMAGE_INCOMING, IMAGE_STATIC, or about to be erased, or ... */
byte segment_id; /* i'm a part of this segment */
byte series_id; /* this is my series */
- int sprite_id; /* sprite within the series */
- int x, y;
+ int16 sprite_id; /* sprite within the series */
+ int16 x, y;
byte depth;
byte scale;
+
+ static constexpr int SIZE = 2 + 1 + 1 + 2 + 2 + 2 + 1 + 1;
+ void load(Common::SeekableReadStream *src);
};
-typedef struct ImageBuf Image;
typedef Image *ImagePtr;
} // namespace MADSV2
diff --git a/engines/mads/madsv2/core/inter.cpp b/engines/mads/madsv2/core/inter.cpp
index 764c3e2d010..706851ab2da 100644
--- a/engines/mads/madsv2/core/inter.cpp
+++ b/engines/mads/madsv2/core/inter.cpp
@@ -1883,7 +1883,7 @@ static void inter_background_animation(void) {
inter_no_segments_active = !inter_some_segments_active;
inter_some_segments_active = false;
- for (count = 0; count < inter_anim->num_segments; count++) {
+ for (count = 0; count < inter_anim->num_series /* num_segments */; count++) {
if (inter_anim->segment[count].counter < 0) {
if (inter_anim->segment[count].counter == -1) {
prob_check = imath_random(1, 30000);
@@ -1925,7 +1925,7 @@ static void inter_background_animation(void) {
}
}
- for (count = 0; count < inter_anim->num_segments; count++) {
+ for (count = 0; count < inter_anim->num_series; count++) {
image_scan = inter_anim->segment[count].counter;
if (image_scan >= 0) {
if (image_inter_marker < IMAGE_INTER_LIST_SIZE) {
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index 207add7b2e1..bb2230dd878 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -85,6 +85,7 @@ MODULE_OBJS += \
madsv2/core/heap.o \
madsv2/core/himem.o \
madsv2/core/hspot.o \
+ madsv2/core/image.o \
madsv2/core/imath.o \
madsv2/core/implode.o \
madsv2/core/inter.o \
Commit: d353e1817f617ae294d958f3e3c79ea7fa961642
https://github.com/scummvm/scummvm/commit/d353e1817f617ae294d958f3e3c79ea7fa961642
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:21:20+10:00
Commit Message:
MADS: PHANTOM: Fix sprite drawing with depth buffer
Changed paths:
engines/mads/madsv2/core/sprite_0.cpp
diff --git a/engines/mads/madsv2/core/sprite_0.cpp b/engines/mads/madsv2/core/sprite_0.cpp
index f1b94ad6e20..ef21cb77688 100644
--- a/engines/mads/madsv2/core/sprite_0.cpp
+++ b/engines/mads/madsv2/core/sprite_0.cpp
@@ -1094,14 +1094,6 @@ pixel_IRLE_image_next:
/* row_next: advance to next row */
- /* row_finish: if this line wasn't completed (e.g. right-clipped early),
- consume the rest of the sprite row stream until SS_EOL. */
-row_finish:
- if (!line_finished) {
- while (*sprite_ptr++ != SS_EOL)
- ;
- }
-
/* Advance target row pointer by one scanline */
target_row += target_wrap;
@@ -1110,6 +1102,14 @@ row_finish:
attr_row += attr_wrap;
#endif
+ /* row_finish: if this line wasn't completed (e.g. right-clipped early),
+ consume the rest of the sprite row stream until SS_EOL. */
+row_finish:
+ if (!line_finished) {
+ while (*sprite_ptr++ != SS_EOL)
+ ;
+ }
+
} /* end while(1) row_loop */
}
Commit: d671f0d3998d3fd42a2d07312d70e53c3a6e20ef
https://github.com/scummvm/scummvm/commit/d671f0d3998d3fd42a2d07312d70e53c3a6e20ef
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:21:20+10:00
Commit Message:
MADS: PHANTOM: Screen updates
Changed paths:
engines/mads/madsv2/core/timer.cpp
engines/mads/madsv2/engine.cpp
engines/mads/madsv2/engine.h
engines/mads/madsv2/phantom/main_menu.cpp
diff --git a/engines/mads/madsv2/core/timer.cpp b/engines/mads/madsv2/core/timer.cpp
index a7db0ae8c47..68295d75728 100644
--- a/engines/mads/madsv2/core/timer.cpp
+++ b/engines/mads/madsv2/core/timer.cpp
@@ -19,10 +19,10 @@
*
*/
-#include "common/system.h"
#include "common/textconsole.h"
#include "mads/madsv2/core/general.h"
#include "mads/madsv2/core/timer.h"
+#include "mads/madsv2/engine.h"
namespace MADS {
namespace MADSV2 {
@@ -54,17 +54,17 @@ void timer_remove() {
}
long timer_read() {
- unsigned long ms = g_system->getMillis();
+ unsigned long ms = g_engine->getMillis();
return ms * 1193 / 65536;
}
long timer_read_600() {
- unsigned long ms = g_system->getMillis();
+ unsigned long ms = g_engine->getMillis();
return ms * 600 / 1000;
}
long timer_read_60() {
- unsigned long ms = g_system->getMillis();
+ unsigned long ms = g_engine->getMillis();
return ms * 60 / 1000;
}
diff --git a/engines/mads/madsv2/engine.cpp b/engines/mads/madsv2/engine.cpp
index de1c9b30bda..3be8967196a 100644
--- a/engines/mads/madsv2/engine.cpp
+++ b/engines/mads/madsv2/engine.cpp
@@ -27,6 +27,9 @@
namespace MADS {
namespace MADSV2 {
+constexpr int GAME_FRAME_RATE = 50;
+constexpr int GAME_FRAME_TIME = 1000 / GAME_FRAME_RATE;
+
MADSV2Engine *g_engine;
MADSV2Engine::MADSV2Engine(OSystem *syst, const MADSGameDescription *gameDesc) :
@@ -49,9 +52,22 @@ Common::Error MADSV2Engine::run() {
}
void MADSV2Engine::pollEvents() {
- Common::Event e;
- while (g_system->getEventManager()->pollEvent(e) && !shouldQuit())
- _events.push_back(e);
+ // Check for screen update time
+ uint32 time = g_system->getMillis();
+ if (time >= _nextFrameTime) {
+ _screen->update();
+ _nextFrameTime = time + GAME_FRAME_TIME;
+ }
+
+ // Poll for events
+ Common::Event e;
+ while (g_system->getEventManager()->pollEvent(e) && !shouldQuit()) {
+ if (e.type == Common::EVENT_MOUSEMOVE && (!_events.empty() && _events.back().type == Common::EVENT_MOUSEMOVE))
+ _events.back().mouse = e.mouse;
+ else
+ _events.push_back(e);
+ }
+
}
bool MADSV2Engine::hasPendingKey() {
@@ -92,5 +108,11 @@ void MADSV2Engine::flushKeys() {
}
}
+uint32 MADSV2Engine::getMillis() {
+ pollEvents();
+ return g_system->getMillis();
+}
+
+
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/engine.h b/engines/mads/madsv2/engine.h
index cab4ce6549a..8a96301ccf0 100644
--- a/engines/mads/madsv2/engine.h
+++ b/engines/mads/madsv2/engine.h
@@ -35,6 +35,7 @@ class MADSV2Engine : public MADSEngine {
private:
Graphics::Screen *_screen = nullptr;
Common::List<Common::Event> _events;
+ uint32 _nextFrameTime = 0;
void pollEvents();
@@ -52,6 +53,11 @@ public:
int getKey();
void flushKeys();
+ /**
+ * Get the elapsed time in milliseconds
+ */
+ uint32 getMillis();
+
/* Callback routines in game-specific MAIN module */
int main_cheating_key(int mykey) {
return 0;
diff --git a/engines/mads/madsv2/phantom/main_menu.cpp b/engines/mads/madsv2/phantom/main_menu.cpp
index 2f8944295ab..2616e08b8b2 100644
--- a/engines/mads/madsv2/phantom/main_menu.cpp
+++ b/engines/mads/madsv2/phantom/main_menu.cpp
@@ -19,6 +19,7 @@
*
*/
+#include "mads/madsv2/engine.h"
#include "mads/madsv2/core/general.h"
#include "mads/madsv2/core/config.h"
#include "mads/madsv2/core/font.h"
@@ -103,7 +104,7 @@ int command_line_size = 0;
int use_mouse_cursor_fix = false;
-int going;
+bool going;
int menu_mode;
int must_perform_matte;
@@ -454,7 +455,7 @@ void menu_control(void) {
mouse_init_cycle();
- while (going) {
+ while (going && !g_engine->shouldQuit()) {
if (keys_any()) {
mykey = keys_get();
switch (toupper(mykey)) {
Commit: 5d20c04353f215a1d9cb8720d4f1da1cb4a9318a
https://github.com/scummvm/scummvm/commit/5d20c04353f215a1d9cb8720d4f1da1cb4a9318a
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:21:20+10:00
Commit Message:
MADS: PHANTOM: Translate 6-bit palette RGBs to 8-bit
Changed paths:
engines/mads/madsv2/core/mcga.cpp
diff --git a/engines/mads/madsv2/core/mcga.cpp b/engines/mads/madsv2/core/mcga.cpp
index 4b1f8b557d9..f5f5b4e94f0 100644
--- a/engines/mads/madsv2/core/mcga.cpp
+++ b/engines/mads/madsv2/core/mcga.cpp
@@ -105,21 +105,29 @@ void mcga_close_window(byte *inp) {
mem_free(inp);
}
-void mcga_setpal(Palette *pal) {
- const byte *colors = (byte *)&(*pal)[0];
- g_system->getPaletteManager()->setPalette(colors, 0, Graphics::PALETTE_COUNT);
-}
-
void mcga_getpal(Palette *pal) {
- byte *colors = (byte *)&(*pal)[0];
- g_system->getPaletteManager()->grabPalette(colors, 0, Graphics::PALETTE_COUNT);
+ byte tmp[Graphics::PALETTE_COUNT * 3];
+ g_system->getPaletteManager()->grabPalette(tmp, 0, Graphics::PALETTE_COUNT);
+ for (int i = 0; i < Graphics::PALETTE_COUNT; i++) {
+ (*pal)[i].r = tmp[i * 3 + 0] * 63 / 255;
+ (*pal)[i].g = tmp[i * 3 + 1] * 63 / 255;
+ (*pal)[i].b = tmp[i * 3 + 2] * 63 / 255;
+ }
}
void mcga_setpal_range(Palette *pal, int first_color, int num_colors) {
- byte *colors = (byte *)&(*pal)[first_color];
- g_system->getPaletteManager()->setPalette(colors, first_color, num_colors);
+ byte tmp[Graphics::PALETTE_COUNT * 3];
+ for (int i = 0; i < num_colors; i++) {
+ tmp[i * 3 + 0] = (*pal)[first_color + i].r * 255 / 63;
+ tmp[i * 3 + 1] = (*pal)[first_color + i].g * 255 / 63;
+ tmp[i * 3 + 2] = (*pal)[first_color + i].b * 255 / 63;
+ }
+ g_system->getPaletteManager()->setPalette(tmp, first_color, num_colors);
}
+void mcga_setpal(Palette *pal) {
+ mcga_setpal_range(pal, 0, Graphics::PALETTE_COUNT);
+}
void mcga_cls(byte inp) {
g_engine->getScreen()->clear(inp);
Commit: bb07d87b9544175f5e71a730668dc215c370c73d
https://github.com/scummvm/scummvm/commit/bb07d87b9544175f5e71a730668dc215c370c73d
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:21:21+10:00
Commit Message:
MADS: PHANTOM: Hook up mouse events to update mouse fields
Changed paths:
engines/mads/madsv2/core/mouse.cpp
engines/mads/madsv2/core/mouse.h
engines/mads/madsv2/engine.cpp
engines/mads/madsv2/engine.h
diff --git a/engines/mads/madsv2/core/mouse.cpp b/engines/mads/madsv2/core/mouse.cpp
index 12a8f38a459..2f05d5a03c5 100644
--- a/engines/mads/madsv2/core/mouse.cpp
+++ b/engines/mads/madsv2/core/mouse.cpp
@@ -55,8 +55,8 @@ Buffer mouse_cursor_buffer;
int mouse_button = -1;
int mouse_status = 0;
-int mouse_x = 0;
-int mouse_y = 0;
+int mouse_x = 0, mouse_y = 0;
+int mouse_buttons = 0;
bool mouse_start_stroke = false;
bool mouse_stroke_going = false;
bool mouse_changed = false;
@@ -228,7 +228,10 @@ void mouse_double_freedom(int freedom_flag) {
}
int mouse_get_status(int *x, int *y) {
- return 0;
+ *x = mouse_x;
+ *y = mouse_y;
+
+ return mouse_buttons;
}
void mouse_timing() {
diff --git a/engines/mads/madsv2/core/mouse.h b/engines/mads/madsv2/core/mouse.h
index 238649b714f..dff67c71538 100644
--- a/engines/mads/madsv2/core/mouse.h
+++ b/engines/mads/madsv2/core/mouse.h
@@ -44,6 +44,7 @@ extern byte mouse_showing; /* Mouse cursor showing status (0 = show) */
extern int mouse_button; /* Last button pressed (0 = left, 1 = right) */
extern int mouse_status; /* Button status flags */
extern int mouse_x, mouse_y; /* Most recent cursor position */
+extern int mouse_buttons; /* Most recent button state */
extern bool mouse_start_stroke; /* True if new button press this round */
extern bool mouse_stroke_going; /* True if any button currently down */
extern bool mouse_changed; /* True if position or any button changed */
diff --git a/engines/mads/madsv2/engine.cpp b/engines/mads/madsv2/engine.cpp
index 3be8967196a..600c352188e 100644
--- a/engines/mads/madsv2/engine.cpp
+++ b/engines/mads/madsv2/engine.cpp
@@ -22,6 +22,7 @@
#include "common/system.h"
#include "engines/util.h"
#include "mads/madsv2/engine.h"
+#include "mads/madsv2/core/mouse.h"
#include "mads/madsv2/phantom/main.h"
namespace MADS {
@@ -52,44 +53,68 @@ Common::Error MADSV2Engine::run() {
}
void MADSV2Engine::pollEvents() {
- // Check for screen update time
- uint32 time = g_system->getMillis();
- if (time >= _nextFrameTime) {
- _screen->update();
- _nextFrameTime = time + GAME_FRAME_TIME;
- }
-
- // Poll for events
- Common::Event e;
- while (g_system->getEventManager()->pollEvent(e) && !shouldQuit()) {
- if (e.type == Common::EVENT_MOUSEMOVE && (!_events.empty() && _events.back().type == Common::EVENT_MOUSEMOVE))
- _events.back().mouse = e.mouse;
- else
- _events.push_back(e);
- }
+ // Check for screen update time
+ uint32 time = g_system->getMillis();
+ if (time >= _nextFrameTime) {
+ _screen->update();
+ _nextFrameTime = time + GAME_FRAME_TIME;
+ }
+
+ // Poll for events
+ Common::Event e;
+ while (g_system->getEventManager()->pollEvent(e) && !shouldQuit()) {
+ bool isMouse = false;
+ switch (e.type) {
+ case Common::EVENT_LBUTTONDOWN:
+ mouse_buttons |= 1;
+ isMouse = true;
+ break;
+ case Common::EVENT_LBUTTONUP:
+ mouse_buttons &= ~1;
+ isMouse = true;
+ break;
+ case Common::EVENT_RBUTTONDOWN:
+ mouse_buttons |= 2;
+ isMouse = true;
+ break;
+ case Common::EVENT_RBUTTONUP:
+ mouse_buttons &= ~2;
+ isMouse = true;
+ break;
+ case Common::EVENT_MBUTTONDOWN:
+ mouse_buttons |= 4;
+ isMouse = true;
+ break;
+ case Common::EVENT_MBUTTONUP:
+ mouse_buttons &= ~4;
+ isMouse = true;
+ break;
+ default:
+ break;
+ }
+ if (isMouse) {
+ mouse_x = e.mouse.x;
+ mouse_y = e.mouse.y;
+ }
+
+ if (e.type == Common::EVENT_KEYDOWN)
+ _keyEvents.push(e);
+ }
}
bool MADSV2Engine::hasPendingKey() {
pollEvents();
- for (auto it = _events.begin(); it != _events.end(); ++it) {
- if (it->type == Common::EVENT_KEYDOWN)
- return true;
- }
-
- return false;
+ return !_keyEvents.empty();
}
int MADSV2Engine::getKey() {
pollEvents();
- for (auto it = _events.begin(); it != _events.end(); ++it) {
- if (it->type == Common::EVENT_KEYDOWN) {
- Common::Event e = *it;
- _events.erase(it);
- return (e.kbd.keycode & 0xff) | 0x100;
- }
+ if (!_keyEvents.empty()) {
+ Common::Event e = _keyEvents.pop();
+ return (e.kbd.keycode & 0xff) | 0x100;
}
return 0;
@@ -98,14 +123,7 @@ int MADSV2Engine::getKey() {
void MADSV2Engine::flushKeys() {
pollEvents();
- for (auto it = _events.begin(); it != _events.end(); ) {
- if (it->type == Common::EVENT_KEYDOWN) {
- Common::Event e = *it;
- it = _events.erase(it);
- } else {
- ++it;
- }
- }
+ _keyEvents.clear();
}
uint32 MADSV2Engine::getMillis() {
diff --git a/engines/mads/madsv2/engine.h b/engines/mads/madsv2/engine.h
index 8a96301ccf0..6974aea2bb8 100644
--- a/engines/mads/madsv2/engine.h
+++ b/engines/mads/madsv2/engine.h
@@ -23,7 +23,7 @@
#define MADSV2_ENGINE_H
#include "common/events.h"
-#include "common/list.h"
+#include "common/stack.h"
#include "common/random.h"
#include "graphics/screen.h"
#include "mads/mads.h"
@@ -34,7 +34,7 @@ namespace MADSV2 {
class MADSV2Engine : public MADSEngine {
private:
Graphics::Screen *_screen = nullptr;
- Common::List<Common::Event> _events;
+ Common::Stack<Common::Event> _keyEvents;
uint32 _nextFrameTime = 0;
void pollEvents();
Commit: 94a5023aa9585bc48f1624d488cdd3e458ed1769
https://github.com/scummvm/scummvm/commit/94a5023aa9585bc48f1624d488cdd3e458ed1769
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:21:21+10:00
Commit Message:
MADS: PHANTOM: Implement mouse cursor display
Changed paths:
engines/mads/madsv2/core/mouse.cpp
engines/mads/madsv2/core/mouse.h
diff --git a/engines/mads/madsv2/core/mouse.cpp b/engines/mads/madsv2/core/mouse.cpp
index 2f05d5a03c5..779ca6a09e7 100644
--- a/engines/mads/madsv2/core/mouse.cpp
+++ b/engines/mads/madsv2/core/mouse.cpp
@@ -31,28 +31,6 @@
namespace MADS {
namespace MADSV2 {
-static const byte cursor_mask[16][16] = {
- /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 */
- {255, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
- { 0, 7, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
- { 0, 7, 7, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
- { 0, 7, 15, 7, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
- { 0, 7, 15, 15, 7, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
- { 0, 7, 15, 15, 15, 7, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255},
- { 0, 7, 15, 15, 15, 15, 7, 0, 255, 255, 255, 255, 255, 255, 255, 255},
- { 0, 7, 15, 15, 15, 15, 15, 7, 0, 255, 255, 255, 255, 255, 255, 255},
- { 0, 7, 15, 15, 15, 15, 7, 7, 7, 0, 255, 255, 255, 255, 255, 255},
- { 0, 7, 15, 7, 15, 15, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255},
- { 0, 7, 7, 0, 7, 15, 7, 0, 255, 255, 255, 255, 255, 255, 255, 255},
- {255, 0, 0, 255, 0, 7, 15, 0, 255, 255, 255, 255, 255, 255, 255, 255},
- {255, 255, 255, 255, 0, 7, 15, 0, 255, 255, 255, 255, 255, 255, 255, 255},
- {255, 255, 255, 255, 255, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255},
- {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
- {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
-};
-
-Buffer mouse_cursor_buffer;
-
int mouse_button = -1;
int mouse_status = 0;
int mouse_x = 0, mouse_y = 0;
@@ -67,9 +45,6 @@ int mouse_old_x = 0;
int mouse_old_y = 0;
long mouse_clock = 0;
byte mouse_showing = 0;
-
-int mouse_hot_x = 0;
-int mouse_hot_y = 0;
int mouse_video_mode = 0;
@@ -162,19 +137,12 @@ void mouse_cursor_sprite(SeriesPtr series, int id) {
if (work_area[16][count] != 255) hot_x = count;
}
- if ((hot_x != mouse_hot_x) || (hot_y != mouse_hot_y)) {
- mouse_hot_x = hot_x;
- mouse_hot_y = hot_y;
-
- mouse_hide();
- mouse_set_hotspot(hot_x, hot_y);
- buffer_rect_copy(load_buffer, mouse_cursor_buffer, 0, 0, 16, 16);
- mouse_show();
- } else {
- mouse_change_cursor_begin();
- buffer_rect_copy(load_buffer, mouse_cursor_buffer, 0, 0, 16, 16);
- mouse_change_cursor_end();
+ if (work_area[0][16] == 9 && work_area[16][0] == 9) {
+ work_area[0][16] = work_area[16][0] = 0xff;
}
+
+ CursorMan.replaceCursor(load_buffer.data, load_buffer.x, load_buffer.y, hot_x, hot_y, 0xff);
+ CursorMan.disableCursorPalette(true);
}
void mouse_video_init() {
diff --git a/engines/mads/madsv2/core/mouse.h b/engines/mads/madsv2/core/mouse.h
index dff67c71538..e44f01dfcde 100644
--- a/engines/mads/madsv2/core/mouse.h
+++ b/engines/mads/madsv2/core/mouse.h
@@ -34,8 +34,6 @@ namespace MADSV2 {
#define MOUSE_DOUBLE_TIMING 5 /* Double click threshold (ticks) */
#define MOUSE_BALLISTIC_TIMING 36 /* Ballistic threshold (ticks) */
-extern Buffer mouse_cursor_buffer; /* Points at cursor pixel map */
-
extern word mouse_driver; /* True if mouse driver is currently active */
extern word mouse_known_mode; /* True if mouse in a 320x200 graphics mode */
extern int mouse_video_mode; /* Rom BIOS video mode # of current cursor */
Commit: c9f03bec94376abed3662d6366db16974db1cd45
https://github.com/scummvm/scummvm/commit/c9f03bec94376abed3662d6366db16974db1cd45
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:21:21+10:00
Commit Message:
MADS: PHANTOM: Beginning of sound handling
Changed paths:
engines/mads/madsv2/core/matte.cpp
engines/mads/madsv2/core/sound.cpp
engines/mads/madsv2/core/sound.h
diff --git a/engines/mads/madsv2/core/matte.cpp b/engines/mads/madsv2/core/matte.cpp
index fecf8949e6a..ebadc5bf3c6 100644
--- a/engines/mads/madsv2/core/matte.cpp
+++ b/engines/mads/madsv2/core/matte.cpp
@@ -1067,7 +1067,7 @@ void matte_frame(int special_effect, int full_screen) {
#endif
} else {
matte_special_effect(special_effect, full_screen);
- /* pl sound_queue_flush(); */
+ sound_queue_flush();
}
}
diff --git a/engines/mads/madsv2/core/sound.cpp b/engines/mads/madsv2/core/sound.cpp
index de0113e0f11..c798d13f7ef 100644
--- a/engines/mads/madsv2/core/sound.cpp
+++ b/engines/mads/madsv2/core/sound.cpp
@@ -29,5 +29,9 @@ void sound_queue(int soundNum) {
error("TODO: sound_queue");
}
+void sound_queue_flush() {
+ error("TODO: sound_queue_flush");
+}
+
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/core/sound.h b/engines/mads/madsv2/core/sound.h
index c14278959d6..ccf149e2d8d 100644
--- a/engines/mads/madsv2/core/sound.h
+++ b/engines/mads/madsv2/core/sound.h
@@ -30,6 +30,7 @@ namespace MADSV2 {
constexpr int sound_board_roland = 1;
extern void sound_queue(int soundNum);
+extern void sound_queue_flush();
} // namespace MADSV2
} // namespace MADS
Commit: efce444c99bbdd577d57111fee275392d7390a6c
https://github.com/scummvm/scummvm/commit/efce444c99bbdd577d57111fee275392d7390a6c
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:21:21+10:00
Commit Message:
MADS: PHANTOM: Creating shared SoundManager and ASound classes
I think the base code is the same for both games, so I'm
extracting out the Rex Nebular specific code so that the
rest can be re-used
Changed paths:
engines/mads/core/sound.cpp
engines/mads/core/sound.h
engines/mads/madsv2/core/matte.cpp
engines/mads/nebular/nebular.cpp
engines/mads/nebular/sound_nebular.cpp
engines/mads/nebular/sound_nebular.h
diff --git a/engines/mads/core/sound.cpp b/engines/mads/core/sound.cpp
index 96008f42962..1d1d07d1610 100644
--- a/engines/mads/core/sound.cpp
+++ b/engines/mads/core/sound.cpp
@@ -31,28 +31,9 @@ class Mixer;
namespace MADS {
-SoundManager::SoundManager(RexNebularEngine *vm, Audio::Mixer *mixer) {
- _vm = vm;
- _mixer = mixer;
- _driver = nullptr;
- _pollSoundEnabled = false;
- _soundPollFlag = false;
- _newSoundsPaused = false;
- _masterVolume = 255;
-
- _preferRoland = false;
-
+SoundManager::SoundManager(Audio::Mixer *mixer, bool &soundFlag) : _mixer(mixer), _soundFlag(soundFlag) {
_opl = OPL::Config::create();
_opl->init();
-
- // Validate sound files
- switch (_vm->getGameID()) {
- case GType_RexNebular:
- Nebular::ASound::validate();
- break;
- default:
- break;
- }
}
SoundManager::~SoundManager() {
@@ -70,47 +51,8 @@ void SoundManager::init(int sectionNumber) {
if (_driver != nullptr)
delete _driver;
- switch (_vm->getGameID()) {
- case GType_RexNebular:
- switch (sectionNumber) {
- case 1:
- _driver = new Nebular::ASound1(_mixer, _opl);
- break;
- case 2:
- _driver = new Nebular::ASound2(_mixer, _opl);
- break;
- case 3:
- _driver = new Nebular::ASound3(_mixer, _opl);
- break;
- case 4:
- _driver = new Nebular::ASound4(_mixer, _opl);
- break;
- case 5:
- _driver = new Nebular::ASound5(_mixer, _opl);
- break;
- case 6:
- _driver = new Nebular::ASound6(_mixer, _opl);
- break;
- case 7:
- _driver = new Nebular::ASound7(_mixer, _opl);
- break;
- case 8:
- _driver = new Nebular::ASound8(_mixer, _opl);
- break;
- case 9:
- _driver = new Nebular::ASound9(_mixer, _opl);
- break;
- default:
- _driver = nullptr;
- return;
- }
- break;
-
- default:
- warning("SoundManager: Unknown game");
- _driver = nullptr;
- return;
- }
+ // Load the correct driver for the section
+ loadDriver(sectionNumber);
// Set volume for newly loaded driver
_driver->setVolume(_masterVolume);
@@ -163,7 +105,7 @@ void SoundManager::command(int commandId, int param) {
} else if (_driver) {
// Note: I don't know any way to identify music commands versus sfx
// commands, so if sfx is mute, then so is music
- if (_vm->_soundFlag)
+ if (_soundFlag)
_driver->command(commandId, param);
}
}
@@ -178,4 +120,889 @@ void SoundManager::noise() {
_driver->noise();
}
+/*-----------------------------------------------------------------------*/
+
+bool AdlibChannel::_channelsEnabled;
+
+AdlibChannel::AdlibChannel() {
+ _owner = nullptr;
+ _activeCount = 0;
+ _field1 = 0;
+ _field2 = 0;
+ _field3 = 0;
+ _field4 = 0;
+ _sampleIndex = 0;
+ _volume = 0;
+ _volumeOffset = 0;
+ _field7 = 0;
+ _field8 = 0;
+ _field9 = 0;
+ _fieldA = 0;
+ _fieldB = 0;
+ _fieldC = 0;
+ _fieldD = 0;
+ _fieldE = 0;
+ _ptr1 = nullptr;
+ _pSrc = nullptr;
+ _ptr3 = nullptr;
+ _ptr4 = nullptr;
+ _ptrEnd = nullptr;
+ _field17 = 0;
+ _field19 = 0;
+ _soundData = nullptr;
+ _field1D = 0;
+ _field1F = 0;
+
+ _field20 = 0;
+}
+
+void AdlibChannel::reset() {
+ _activeCount = 0;
+ _field1 = 0;
+ _field2 = 0;
+ _field3 = 0;
+}
+
+void AdlibChannel::enable(int flag) {
+ if (_activeCount) {
+ _fieldE = flag;
+
+ // WORKAROUND: Original set _soundData pointer to flag. Since this seems
+ // just intended to invalidate any prior pointer, I've replaced it with
+ // a simple null pointer
+ _soundData = nullptr;
+ }
+
+ _channelsEnabled = true;
+}
+
+void AdlibChannel::setPtr2(byte *pData) {
+ _pSrc = pData;
+ _field2 = 0xFF;
+ _fieldA = 1;
+ _field9 = 1;
+}
+
+void AdlibChannel::load(byte *pData) {
+ _ptr1 = _pSrc = _ptr3 = pData;
+ _ptr4 = _soundData = pData;
+ _volumeOffset = 0;
+ _fieldA = 0xFF;
+ _activeCount = 1;
+ _fieldD = 64;
+ _field1 = 0;
+ _field1F = 0;
+ _field2 = _field3 = 0;
+ _volume = _field7 = 0;
+ _field1D = 0;
+ _fieldE = 0;
+ _field9 = 0;
+ _fieldB = 0;
+ _field17 = 0;
+ _field19 = 0;
+
+ CachedDataEntry &cacheEntry = _owner->getCachedData(pData);
+ _ptrEnd = cacheEntry._dataEnd;
+}
+
+void AdlibChannel::check(byte *nullPtr) {
+ if (_activeCount && _fieldE) {
+ if (!_volumeOffset) {
+ _pSrc = nullPtr;
+ _fieldE = 0;
+ } else {
+ _field2 = 0xFF;
+ _fieldA = 4;
+ if (!_field9)
+ _field9 = 1;
+ }
+ }
+}
+
+/*-----------------------------------------------------------------------*/
+
+AdlibSample::AdlibSample(Common::SeekableReadStream &s) {
+ _attackRate = s.readByte();
+ _decayRate = s.readByte();
+ _sustainLevel = s.readByte();
+ _releaseRate = s.readByte();
+ _egTyp = s.readByte() != 0;
+ _ksr = s.readByte() != 0;
+ _totalLevel = s.readByte();
+ _scalingLevel = s.readByte();
+ _waveformSelect = s.readByte();
+ _freqMultiple = s.readByte();
+ _feedback = s.readByte();
+ _ampMod = s.readByte() != 0;
+ _vib = s.readByte();
+ _alg = s.readByte();
+ _fieldE = s.readByte();
+ s.skip(1);
+ _freqMask = s.readUint16LE();
+ _freqBase = s.readUint16LE();
+ _field14 = s.readUint16LE();
+}
+
+/*-----------------------------------------------------------------------*/
+
+ASound::ASound(Audio::Mixer *mixer, OPL::OPL *opl, const Common::Path &filename, int dataOffset) {
+ // Open up the appropriate sound file
+ if (!_soundFile.open(filename))
+ error("Could not open file - %s", filename.toString().c_str());
+
+ // Initialize fields
+ _commandParam = 0;
+ _activeChannelPtr = nullptr;
+ _samplePtr = nullptr;
+ _frameCounter = 0;
+ _isDisabled = false;
+ _masterVolume = 255;
+ _v1 = 0;
+ _v2 = 0;
+ _activeChannelNumber = 0;
+ _freqMask1 = _freqMask2 = 0;
+ _freqBase1 = _freqBase2 = 0;
+ _channelNum1 = _channelNum2 = 0;
+ _v7 = 0;
+ _v8 = 0;
+ _v9 = 0;
+ _v10 = 0;
+ _pollResult = 0;
+ _resultFlag = 0;
+ _nullData[0] = _nullData[1] = 0;
+ Common::fill(&_ports[0], &_ports[256], 0);
+ _stateFlag = false;
+ _activeChannelReg = 0;
+ _v11 = 0;
+ _randomSeed = 1234;
+ _amDep = _vibDep = _splitPoint = true;
+
+ for (int i = 0; i < 11; ++i) {
+ _channelData[i]._field0 = 0;
+ _channelData[i]._freqMask = 0;
+ _channelData[i]._freqBase = 0;
+ _channelData[i]._field6 = 0;
+ }
+
+ for (int i = 0; i < ADLIB_CHANNEL_COUNT; ++i)
+ _channels[i]._owner = this;
+
+ AdlibChannel::_channelsEnabled = false;
+
+ // Store passed parameters, and setup OPL
+ _dataOffset = dataOffset;
+ _mixer = mixer;
+ _opl = opl;
+
+ // Initialize the Adlib
+ adlibInit();
+
+ // Reset the adlib
+ command0();
+
+ _opl->start(new Common::Functor0Mem<void, ASound>(this, &ASound::onTimer), CALLBACKS_PER_SECOND);
+}
+
+ASound::~ASound() {
+ _opl->stop();
+
+ Common::List<CachedDataEntry>::iterator i;
+ for (i = _dataCache.begin(); i != _dataCache.end(); ++i)
+ delete[](*i)._data;
+}
+
+
+void ASound::adlibInit() {
+ write(4, 0x60);
+ write(4, 0x80);
+ write(2, 0xff);
+ write(4, 0x21);
+ write(4, 0x60);
+ write(4, 0x80);
+}
+
+int ASound::stop() {
+ command0();
+ int result = _pollResult;
+ _pollResult = 0;
+ return result;
+}
+
+int ASound::poll() {
+ // Update any playing sounds
+ update();
+
+ // Return result
+ int result = _pollResult;
+ _pollResult = 0;
+ return result;
+}
+
+void ASound::noise() {
+ int randomVal = getRandomNumber();
+
+ if (_v1) {
+ setFrequency(_channelNum1, ((randomVal ^ 0xFFFF) & _freqMask1) + _freqBase1);
+ }
+
+ if (_v2) {
+ setFrequency(_channelNum2, (randomVal & _freqMask2) + _freqBase2);
+ }
+}
+
+CachedDataEntry &ASound::getCachedData(byte *pData) {
+ Common::List<CachedDataEntry>::iterator i;
+ for (i = _dataCache.begin(); i != _dataCache.end(); ++i) {
+ CachedDataEntry &e = *i;
+ if (e._data == pData)
+ return e;
+ }
+
+ error("Could not find previously loaded data");
+}
+
+void ASound::write(int reg, int val) {
+ _queue.push(RegisterValue(reg, val));
+}
+
+int ASound::write2(int state, int reg, int val) {
+ // TODO: Original has a state parameter, not used when in Adlib mode?
+ _ports[reg] = val;
+ write(reg, val);
+ return state;
+}
+
+void ASound::flush() {
+ Common::StackLock slock(_driverMutex);
+
+ while (!_queue.empty()) {
+ RegisterValue v = _queue.pop();
+ _opl->writeReg(v._regNum, v._value);
+ }
+}
+
+void ASound::channelOn(int reg, int volume) {
+ write2(8, reg, (_ports[reg] & 0xC0) | (volume & 0x3F));
+}
+
+void ASound::channelOff(int reg) {
+ write2(8, reg, _ports[reg] | 0x3F);
+}
+
+void ASound::resultCheck() {
+ if (_resultFlag != 1) {
+ _resultFlag = 1;
+ _pollResult = 1;
+ }
+}
+
+byte *ASound::loadData(int offset, int size) {
+ // First scan for an existing copy
+ Common::List<CachedDataEntry>::iterator i;
+ for (i = _dataCache.begin(); i != _dataCache.end(); ++i) {
+ CachedDataEntry &e = *i;
+ if (e._offset == offset)
+ return e._data;
+ }
+
+ // No existing entry found, so load up data and store as a new entry
+ CachedDataEntry rec;
+ rec._offset = offset;
+ rec._data = new byte[size];
+ rec._dataEnd = rec._data + size - 1;
+ _soundFile.seek(_dataOffset + offset);
+ _soundFile.read(rec._data, size);
+ _dataCache.push_back(rec);
+
+ // Return the data
+ return rec._data;
+}
+
+void ASound::playSound(int offset, int size) {
+ // Load the specified data block
+ playSoundData(loadData(offset, size));
+}
+
+void ASound::playSoundData(byte *pData, int startingChannel) {
+ // Scan for a high level free channel
+ for (int i = startingChannel; i < ADLIB_CHANNEL_COUNT; ++i) {
+ if (!_channels[i]._activeCount) {
+ _channels[i].load(pData);
+ return;
+ }
+ }
+
+ // None found, do a secondary scan for an interruptable channel
+ for (int i = ADLIB_CHANNEL_COUNT - 1; i >= startingChannel; --i) {
+ if (_channels[i]._fieldE == 0xFF) {
+ _channels[i].load(pData);
+ return;
+ }
+ }
+}
+
+bool ASound::isSoundActive(byte *pData) {
+ for (int i = 0; i < ADLIB_CHANNEL_MIDWAY; ++i) {
+ if (_channels[i]._activeCount && _channels[i]._soundData == pData)
+ return true;
+ }
+
+ return false;
+}
+
+void ASound::setFrequency(int channel, int freq) {
+ write2(8, 0xA0 + channel, freq & 0xFF);
+ write2(8, 0xB0 + channel, (freq >> 8) | 0x20);
+}
+
+int ASound::getRandomNumber() {
+ int v = 0x9248 + (int)_randomSeed;
+ _randomSeed = ((v >> 3) | (v << 13)) & 0xFFFF;
+ return _randomSeed;
+}
+
+void ASound::update() {
+ getRandomNumber();
+ if (_isDisabled)
+ return;
+
+ ++_frameCounter;
+ pollChannels();
+ checkChannels();
+
+ if (_v1 == _v2) {
+ if (_resultFlag != -1) {
+ _resultFlag = -1;
+ _pollResult = -1;
+ }
+ } else {
+ if (_v1) {
+ _freqBase1 += _v7;
+ if (!--_v1) {
+ if (!_v2 || _channelNum1 != _channelNum2) {
+ write2(8, 0xA0 + _channelNum1, 0);
+ write2(8, 0xB0 + _channelNum1, 0);
+ }
+ }
+ }
+
+ if (_v2) {
+ _freqBase2 += _v8;
+ if (!--_v2) {
+ if (!_v1 || _channelNum2 != _channelNum1) {
+ write2(8, 0xA0 + _channelNum2, 0);
+ write2(8, 0xB0 + _channelNum2, 0);
+ }
+ }
+ }
+ }
+}
+
+void ASound::pollChannels() {
+ _activeChannelNumber = 0;
+ for (int i = 0; i < ADLIB_CHANNEL_COUNT; ++i) {
+ _activeChannelPtr = &_channels[i];
+ pollActiveChannel();
+ }
+}
+
+void ASound::checkChannels() {
+ if (AdlibChannel::_channelsEnabled) {
+ for (int i = 0; i < ADLIB_CHANNEL_COUNT; ++i)
+ _channels[i].check(_nullData);
+ }
+}
+
+void ASound::pollActiveChannel() {
+ AdlibChannel *chan = _activeChannelPtr;
+
+ if (chan->_activeCount) {
+ if (chan->_field8 > 0 && --chan->_field8 == 0)
+ updateOctave();
+
+ bool updateFlag = true;
+ if (--_activeChannelPtr->_activeCount <= 0) {
+ for (;;) {
+ byte *pSrc = chan->_pSrc;
+ if (!chan->_ptr1) {
+ warning("pollActiveChannel(): No data found for sound channel");
+ break;
+ }
+ if (pSrc > chan->_ptrEnd) {
+ warning("Read beyond end of loaded sound data");
+ return;
+ }
+
+ if (!(*pSrc & 0x80) || (*pSrc <= 0xF0)) {
+ if (updateFlag)
+ updateActiveChannel();
+
+ chan->_field4 = *pSrc++;
+ chan->_activeCount = *pSrc++;
+ chan->_pSrc += 2;
+
+ if (!chan->_field4 || !chan->_activeCount) {
+ updateOctave();
+ } else {
+ chan->_field8 = chan->_activeCount - chan->_field7;
+ updateChannelState();
+ }
+
+ // Break out of processing loop
+ break;
+ } else {
+ updateFlag = false;
+
+ switch ((~*pSrc) & 0xF) {
+ case 0:
+ if (!chan->_field17) {
+ if (*++pSrc == 0) {
+ chan->_pSrc += 2;
+ chan->_ptr3 = chan->_pSrc;
+ chan->_field17 = 0;
+ } else {
+ chan->_field17 = *pSrc;
+ chan->_pSrc = chan->_ptr3;
+ }
+ } else if (--chan->_field17) {
+ chan->_pSrc = chan->_ptr3;
+ } else {
+ chan->_pSrc += 2;
+ chan->_ptr3 = chan->_pSrc;
+ }
+ break;
+
+ case 1:
+ if (!chan->_field19) {
+ if (*++pSrc == 0) {
+ chan->_pSrc += 2;
+ chan->_ptr4 = chan->_pSrc;
+ chan->_ptr3 = chan->_pSrc;
+ chan->_field17 = 0;
+ chan->_field19 = 0;
+ } else {
+ chan->_field19 = *pSrc;
+ chan->_pSrc = chan->_ptr4;
+ chan->_ptr3 = chan->_ptr4;
+ }
+ } else if (--chan->_field19) {
+ chan->_ptr4 = chan->_pSrc;
+ chan->_ptr3 = chan->_pSrc;
+ } else {
+ chan->_pSrc += 2;
+ chan->_ptr4 = chan->_pSrc;
+ chan->_ptr3 = chan->_pSrc;
+ }
+ break;
+
+ case 2:
+ // Loop sound data
+ chan->_field1 = 0;
+ chan->_field2 = chan->_field3 = 0;
+ chan->_volume = chan->_field7 = 0;
+ chan->_field1D = chan->_volumeOffset = 0;
+ chan->_field8 = 0;
+ chan->_field9 = 0;
+ chan->_fieldB = 0;
+ chan->_field17 = 0;
+ chan->_field19 = 0;
+ chan->_fieldD = 0x40;
+ chan->_ptr1 = chan->_soundData;
+ chan->_pSrc = chan->_soundData;
+ chan->_ptr3 = chan->_soundData;
+ chan->_ptr4 = chan->_soundData;
+
+ chan->_pSrc += 2;
+ break;
+
+ case 3:
+ chan->_sampleIndex = *++pSrc;
+ chan->_pSrc += 2;
+ loadSample(chan->_sampleIndex);
+ break;
+
+ case 4:
+ chan->_field7 = *++pSrc;
+ chan->_pSrc += 2;
+ break;
+
+ case 5:
+ chan->_field1 = *++pSrc;
+ chan->_pSrc += 2;
+ break;
+
+ case 6:
+ ++pSrc;
+ if (chan->_fieldE) {
+ chan->_pSrc += 2;
+ } else {
+ chan->_volume = *pSrc >> 1;
+ updateFlag = true;
+ chan->_pSrc += 2;
+ }
+ break;
+
+ case 7:
+ ++pSrc;
+ if (!chan->_fieldE) {
+ chan->_fieldA = *pSrc;
+ chan->_field2 = *++pSrc;
+ chan->_field9 = 1;
+ }
+
+ chan->_pSrc += 3;
+ break;
+
+ case 8:
+ chan->_field1D = (int8) * ++pSrc;
+ chan->_pSrc += 2;
+ break;
+
+ case 9:
+ {
+ int v1 = *++pSrc;
+ ++pSrc;
+ int v2 = (v1 - 1) & getRandomNumber();
+ int v3 = pSrc[v2];
+ int v4 = pSrc[v1];
+
+ pSrc[v4 + v1 + 1] = v3;
+ chan->_pSrc += v1 + 3;
+ break;
+ }
+
+ case 10:
+ ++pSrc;
+ if (chan->_fieldE) {
+ chan->_pSrc += 2;
+ } else {
+ chan->_volumeOffset = *pSrc >> 1;
+ updateFlag = true;
+ chan->_pSrc += 2;
+ }
+ break;
+
+ case 11:
+ chan->_fieldD = *++pSrc;
+ updateFlag = true;
+ chan->_pSrc += 2;
+ break;
+
+ case 12:
+ chan->_fieldC = *++pSrc;
+ chan->_field3 = *++pSrc;
+ chan->_fieldB = 1;
+ chan->_pSrc += 2;
+ break;
+
+ case 13:
+ ++pSrc;
+ chan->_pSrc += 2;
+ break;
+
+ case 14:
+ chan->_field1F = *++pSrc;
+ chan->_pSrc += 2;
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ if (chan->_field1)
+ updateFNumber();
+
+ updateFlag = false;
+ if (chan->_field9 || chan->_fieldB) {
+ if (!--chan->_field9) {
+ chan->_field9 = chan->_fieldA;
+ if (chan->_field2) {
+ int8 newVal = (int8)chan->_field2 + (int8)chan->_volumeOffset;
+ if (newVal < 0) {
+ chan->_field9 = 0;
+ newVal = 0;
+ } else if (newVal > 63) {
+ chan->_field9 = 0;
+ newVal = 63;
+ }
+
+ chan->_volumeOffset = newVal;
+ updateFlag = true;
+ }
+ }
+
+ if (!--chan->_fieldB) {
+ chan->_fieldB = chan->_fieldC;
+ if (chan->_field3) {
+ chan->_fieldD = chan->_field3;
+ updateFlag = true;
+ }
+ }
+
+ if (updateFlag)
+ updateActiveChannel();
+ }
+ }
+
+ ++_activeChannelNumber;
+}
+
+void ASound::updateOctave() {
+ int reg = 0xB0 + _activeChannelNumber;
+ write2(8, reg, _ports[reg] & 0xDF);
+}
+
+static int _vList1[] = {
+ 0x200, 0x21E, 0x23F, 0x261, 0x285, 0x2AB,
+ 0x2D4, 0x2FF, 0x32D, 0x35D, 0x390, 0x3C7
+};
+
+void ASound::updateChannelState() {
+ updateActiveChannel();
+
+ if (_channelData[_activeChannelNumber]._field0) {
+ if (_channelNum1 == _activeChannelNumber)
+ _stateFlag = 0;
+ if (_channelNum2 == _activeChannelNumber)
+ _stateFlag = 1;
+
+ if (!_stateFlag) {
+ _stateFlag = 1;
+ if (_v1)
+ write2(8, 0xB0 + _channelNum1, _ports[0xB0 + _channelNum1] & 0xDF);
+
+ _channelNum1 = _activeChannelNumber;
+ _v1 = _channelData[_channelNum1]._field0;
+ _freqMask1 = _channelData[_channelNum1]._freqMask;
+ _freqBase1 = _channelData[_channelNum1]._freqBase;
+ _v7 = _channelData[_channelNum1]._field6;
+ } else {
+ _stateFlag = 0;
+ if (_v2)
+ write2(8, 0xB0 + _channelNum2, _ports[0xB0 + _channelNum2] & 0xDF);
+
+ _channelNum2 = _activeChannelNumber;
+ _v2 = _channelData[_channelNum2]._field0;
+ _freqMask2 = _channelData[_channelNum2]._freqMask;
+ _freqBase2 = _channelData[_channelNum2]._freqBase;
+ _v8 = _channelData[_channelNum2]._field6;
+ }
+
+ resultCheck();
+ } else {
+ int reg = 0xA0 + _activeChannelNumber;
+ int vTimes = (byte)(_activeChannelPtr->_field4 + _activeChannelPtr->_field1F) / 12;
+ int vOffset = (byte)(_activeChannelPtr->_field4 + _activeChannelPtr->_field1F) % 12;
+ int val = _vList1[vOffset] + _activeChannelPtr->_field1D;
+ write2(8, reg, val & 0xFF);
+
+ reg += 0x10;
+ write2(8, reg, (_ports[reg] & 0x20) | (vTimes << 2) | (val >> 8));
+
+ write2(8, reg, _ports[reg] | 0x20);
+ }
+}
+
+static const int outputIndexes[] = {
+ 0, 3, 1, 4, 2, 5, 6, 9, 7, 10, 8, 11, 12, 15, 13, 16, 14, 17
+};
+static const int outputChannels[] = {
+ 0, 1, 2, 3, 4, 5, 8, 9, 10, 11, 12, 13, 16, 17, 18, 19, 20, 21, 0
+};
+
+void ASound::updateActiveChannel() {
+ int reg = 0x40 + outputChannels[outputIndexes[_activeChannelNumber * 2 + 1]];
+ int portVal = _ports[reg] & 0xFFC0;
+ int newVolume = CLIP(_activeChannelPtr->_volume + _activeChannelPtr->_volumeOffset, 0, 63);
+ newVolume = newVolume * _masterVolume / 255;
+
+ // Note: Original had a whole block not seeming to be used, since the initialisation
+ // sets a variable to 5660h, and doesn't change it, so the branch is never taken
+ portVal |= 63 - newVolume;
+
+ write2(8, reg, portVal);
+}
+
+void ASound::loadSample(int sampleIndex) {
+ _activeChannelReg = 0xB0 + _activeChannelNumber;
+ write2(8, _activeChannelReg, _ports[_activeChannelReg] & 0xDF);
+
+ _activeChannelReg = _activeChannelNumber;
+ _samplePtr = &_samples[sampleIndex * 2];
+ _v11 = outputChannels[outputIndexes[_activeChannelReg * 2]];
+ processSample();
+
+ AdlibChannelData &cd = _channelData[_activeChannelNumber];
+ cd._field6 = _samplePtr->_field14;
+ cd._freqBase = _samplePtr->_freqBase;
+ cd._freqMask = _samplePtr->_freqMask;
+ cd._field0 = _samplePtr->_fieldE;
+
+ _samplePtr = &_samples[sampleIndex * 2 + 1];
+ _v11 = outputChannels[outputIndexes[_activeChannelReg * 2 + 1]];
+ processSample();
+}
+
+void ASound::processSample() {
+ // Write out vib flags and split point
+ write2(8, 0x40 + _v11, 0x3F);
+ int depthRhythm = (_ports[0xBD] & 0x3F) | (_amDep ? 0x80 : 0) |
+ (_vibDep ? 0x40 : 0);
+ write2(8, 0xBD, depthRhythm);
+ write2(8, 8, _splitPoint ? 0x40 : 0);
+
+ // Write out feedback & Alg
+ int val = (_samplePtr->_feedback << 1) | (1 - _samplePtr->_alg);
+ write2(8, 0xC0 + _activeChannelReg, val);
+
+ // Write out attack/decay rate
+ val = (_samplePtr->_attackRate << 4) | (_samplePtr->_decayRate & 0xF);
+ write2(8, 0x60 + _v11, val);
+
+ // Write out sustain level/release rate
+ val = (_samplePtr->_sustainLevel << 4) | (_samplePtr->_releaseRate & 0xF);
+ write2(8, 0x80 + _v11, val);
+
+ // Write out misc flags
+ val = (_samplePtr->_ampMod ? 0x80 : 0) | (_samplePtr->_vib ? 0x40 : 0)
+ | (_samplePtr->_egTyp ? 0x20 : 0) | (_samplePtr->_ksr ? 0x10 : 0)
+ | (_samplePtr->_freqMultiple & 0xF);
+ write2(8, 0x20 + _v11, val);
+
+ // Write out waveform select
+ write2(8, 0xE0 + _v11, _samplePtr->_waveformSelect & 3);
+
+ // Write out total level & scaling level
+ val = -((_samplePtr->_totalLevel & 0x3F) - 0x3F) | (_samplePtr->_scalingLevel << 6);
+ write2(8, 0x40 + _v11, val);
+}
+
+void ASound::updateFNumber() {
+ int loReg = 0xA0 + _activeChannelNumber;
+ int hiReg = 0xB0 + _activeChannelNumber;
+ int val1 = (_ports[hiReg] & 0x1F) << 8;
+ val1 += _ports[loReg] + _activeChannelPtr->_field1;
+ write2(8, loReg, val1);
+
+ int val2 = (_ports[hiReg] & 0x20) | (val1 >> 8);
+ write2(8, hiReg, val2);
+}
+
+void ASound::onTimer() {
+ Common::StackLock slock(_driverMutex);
+ poll();
+ flush();
+}
+
+void ASound::setVolume(int volume) {
+ _masterVolume = volume;
+ if (!volume)
+ command0();
+}
+
+int ASound::command0() {
+ bool isDisabled = _isDisabled;
+ _isDisabled = true;
+
+ for (int i = 0; i < ADLIB_CHANNEL_COUNT; ++i)
+ _channels[i].reset();
+
+ _v1 = 0;
+ _v2 = 0;
+ _freqMask1 = _freqMask2 = 0;
+ _freqBase1 = _freqBase2 = 0;
+ _v7 = 0;
+ _v8 = 0;
+
+ // Reset Adlib port registers
+ for (int reg = 0x4F; reg >= 0x40; --reg)
+ write2(8, reg, 0x3F);
+ for (int reg = 0xFF; reg >= 0x60; --reg)
+ write2(8, reg, 0);
+ for (int reg = 0x3F; reg > 0; --reg)
+ write2(8, reg, 0);
+ write2(8, 1, 0x20);
+
+ _isDisabled = isDisabled;
+ return 0;
+}
+
+int ASound::command1() {
+ for (int i = 0; i < ADLIB_CHANNEL_COUNT; ++i)
+ _channels[i].enable(0xFF);
+ return 0;
+}
+
+int ASound::command2() {
+ for (int i = 0; i < ADLIB_CHANNEL_MIDWAY; ++i)
+ _channels[i].setPtr2(_nullData);
+ return 0;
+}
+
+int ASound::command3() {
+ for (int i = 0; i < ADLIB_CHANNEL_MIDWAY; ++i)
+ _channels[i].enable(0xFF);
+ return 0;
+}
+
+int ASound::command4() {
+ for (int i = ADLIB_CHANNEL_MIDWAY; i < ADLIB_CHANNEL_COUNT; ++i)
+ _channels[i].setPtr2(_nullData);
+ return 0;
+}
+
+int ASound::command5() {
+ for (int i = 5; i < ADLIB_CHANNEL_COUNT; ++i)
+ _channels[i].enable(0xFF);
+ return 0;
+}
+
+int ASound::command6() {
+ _v9 = _v1;
+ _v1 = 0;
+ _v10 = _v2;
+ _v2 = 0;
+
+ channelOff(0x43);
+ channelOff(0x44);
+ channelOff(0x45);
+ channelOff(0x4B);
+ channelOff(0x4C);
+ channelOff(0x4D);
+ channelOff(0x53);
+ channelOff(0x54);
+ channelOff(0x55);
+
+ return 0;
+}
+
+int ASound::command7() {
+ channelOn(0x43, _channels[0]._volume);
+ channelOn(0x44, _channels[1]._volume);
+ channelOn(0x45, _channels[2]._volume);
+ channelOn(0x4B, _channels[3]._volume);
+ channelOn(0x4C, _channels[4]._volume);
+ channelOn(0x4D, _channels[5]._volume);
+
+ _v1 = _v9;
+ _v2 = _v10;
+
+ if (_v9 != _v10)
+ resultCheck();
+
+ _isDisabled = 0;
+ return _v10;
+}
+
+int ASound::command8() {
+ int result = 0;
+ for (int i = 0; i < ADLIB_CHANNEL_COUNT; ++i)
+ result |= _channels[i]._activeCount;
+
+ return result;
+}
+
} // End of namespace MADS
diff --git a/engines/mads/core/sound.h b/engines/mads/core/sound.h
index d7cf43fe316..4f8a28bcecd 100644
--- a/engines/mads/core/sound.h
+++ b/engines/mads/core/sound.h
@@ -22,7 +22,9 @@
#ifndef MADS_SOUND_H
#define MADS_SOUND_H
-#include "common/scummsys.h"
+#include "common/array.h"
+#include "common/file.h"
+#include "common/mutex.h"
#include "common/queue.h"
namespace Audio {
@@ -35,26 +37,32 @@ class OPL;
namespace MADS {
-namespace Nebular {
class ASound;
-}
-
-class RexNebularEngine;
class SoundManager {
-private:
- RexNebularEngine *_vm;
+protected:
Audio::Mixer *_mixer;
- OPL::OPL *_opl;
- Nebular::ASound *_driver;
- bool _pollSoundEnabled;
- bool _soundPollFlag;
- bool _newSoundsPaused;
+ bool &_soundFlag;
+ OPL::OPL *_opl = nullptr;
+ ASound *_driver = nullptr;
+ bool _pollSoundEnabled = false;
+ bool _soundPollFlag = false;
+ bool _newSoundsPaused = false;
Common::Queue<int> _queuedCommands;
- int _masterVolume;
+ int _masterVolume = 255;
+
+protected:
+ /**
+ * Load the particular section sound handler
+ * @param sectionNum Section number
+ */
+ virtual void loadDriver(int sectionNum) = 0;
+
public:
- SoundManager(RexNebularEngine *vm, Audio::Mixer *mixer);
- ~SoundManager();
+ SoundManager(Audio::Mixer *mixer, bool &soundFlag);
+ virtual ~SoundManager();
+
+ virtual void validate() = 0;
bool _preferRoland;
@@ -116,6 +124,342 @@ public:
//@}
};
-} // End of namespace MADS
-#endif /* MADS_SOUND_H */
+/**
+ * Represents the data for a channel on the Adlib
+ */
+class AdlibChannel {
+public:
+ ASound *_owner;
+
+ int _activeCount;
+ int _field1;
+ int _field2;
+ int _field3;
+ int _field4;
+ int _sampleIndex;
+ int _volume;
+ int _field7;
+ int _field8;
+ int _field9;
+ int _fieldA;
+ uint8 _fieldB;
+ int _fieldC;
+ int _fieldD;
+ int _fieldE;
+ byte *_ptr1;
+ byte *_pSrc;
+ byte *_ptr3;
+ byte *_ptr4;
+ byte *_ptrEnd;
+ int _field17;
+ int _field19;
+ byte *_soundData;
+ int _field1D;
+ int _volumeOffset;
+ int _field1F;
+
+ // TODO: Only used by asound.003. Figure out usage
+ byte _field20;
+public:
+ static bool _channelsEnabled;
+public:
+ AdlibChannel();
+
+ void reset();
+ void enable(int flag);
+ void setPtr2(byte *pData);
+ void load(byte *pData);
+ void check(byte *nullPtr);
+};
+
+class AdlibChannelData {
+public:
+ int _field0;
+ int _freqMask;
+ int _freqBase;
+ int _field6;
+};
+
+class AdlibSample {
+public:
+ int _attackRate;
+ int _decayRate;
+ int _sustainLevel;
+ int _releaseRate;
+ bool _egTyp;
+ bool _ksr;
+ int _totalLevel;
+ int _scalingLevel;
+ int _waveformSelect;
+ int _freqMultiple;
+ int _feedback;
+ bool _ampMod;
+ int _vib;
+ int _alg;
+ int _fieldE;
+ int _freqMask;
+ int _freqBase;
+ int _field14;
+
+ AdlibSample() {
+ }
+ AdlibSample(Common::SeekableReadStream &s);
+};
+
+struct RegisterValue {
+ uint8 _regNum;
+ uint8 _value;
+
+ RegisterValue(int regNum, int value) {
+ _regNum = regNum; _value = value;
+ }
+};
+
+#define ADLIB_CHANNEL_COUNT 9
+#define ADLIB_CHANNEL_MIDWAY 5
+#define CALLBACKS_PER_SECOND 60
+
+struct CachedDataEntry {
+ int _offset;
+ byte *_data;
+ byte *_dataEnd;
+};
+
+/**
+ * Base class for the sound player resource files
+ */
+class ASound {
+private:
+ Common::List<CachedDataEntry> _dataCache;
+ uint16 _randomSeed;
+ int _masterVolume;
+
+ /**
+ * Does the initial Adlib initialisation
+ */
+ void adlibInit();
+
+ /**
+ * Does on-going processing for the Adlib sounds being played
+ */
+ void update();
+
+ /**
+ * Polls each of the channels for updates
+ */
+ void pollChannels();
+
+ /**
+ * Checks the status of the channels
+ */
+ void checkChannels();
+
+ /**
+ * Polls the currently active channel
+ */
+ void pollActiveChannel();
+
+ /**
+ * Updates the octave of the currently active channel
+ */
+ void updateOctave();
+
+ void updateChannelState();
+ void updateActiveChannel();
+
+ /**
+ * Loads up the specified sample
+ */
+ void loadSample(int sampleIndex);
+
+ /**
+ * Writes out the data of the selected sample to the Adlib
+ */
+ void processSample();
+
+ void updateFNumber();
+
+ /**
+ * Timer function for OPL
+ */
+ void onTimer();
+protected:
+ int _commandParam;
+
+ /**
+ * Queue a byte for an Adlib register
+ */
+ void write(int reg, int val);
+
+ /**
+ * Queue a byte for an Adlib register, and store it in the _ports array
+ */
+ int write2(int state, int reg, int val);
+
+ /**
+ * Flush any pending Adlib register values to the OPL driver
+ */
+ void flush();
+
+ /**
+ * Turn a channel on
+ */
+ void channelOn(int reg, int volume);
+
+ /**
+ * Turn a channel off
+ */
+ void channelOff(int reg);
+
+ /**
+ * Checks for whether a poll result needs to be set
+ */
+ void resultCheck();
+
+ /**
+ * Loads a data block from the sound file, caching the result for any future
+ * calls for the same data
+ */
+ byte *loadData(int offset, int size);
+
+ /**
+ * Play the specified sound
+ * @param offset Offset of sound data within sound player data segment
+ * @param size Size of sound data block
+ */
+ void playSound(int offset, int size);
+
+ /**
+ * Play the specified raw sound data
+ * @param pData Pointer to data block containing sound data
+ * @param startingChannel Channel to start scan from
+ */
+ void playSoundData(byte *pData, int startingChannel = ADLIB_CHANNEL_MIDWAY);
+
+ /**
+ * Checks to see whether the given block of data is already loaded into a channel.
+ */
+ bool isSoundActive(byte *pData);
+
+ /**
+ * Sets the frequency for a given channel.
+ */
+ void setFrequency(int channel, int freq);
+
+ /**
+ * Returns a 16-bit random number
+ */
+ int getRandomNumber();
+
+ virtual int command0();
+ int command1();
+ int command2();
+ int command3();
+ int command4();
+ int command5();
+ int command6();
+ int command7();
+ int command8();
+
+ int nullCommand() {
+ return 0;
+ }
+public:
+ Audio::Mixer *_mixer;
+ OPL::OPL *_opl;
+ AdlibChannel _channels[ADLIB_CHANNEL_COUNT];
+ AdlibChannel *_activeChannelPtr;
+ AdlibChannelData _channelData[11];
+ Common::Array<AdlibSample> _samples;
+ AdlibSample *_samplePtr;
+ Common::File _soundFile;
+ Common::Queue<RegisterValue> _queue;
+ Common::Mutex _driverMutex;
+ int _dataOffset;
+ int _frameCounter;
+ bool _isDisabled;
+ int _v1;
+ int _v2;
+ int _activeChannelNumber;
+ int _freqMask1;
+ int _freqMask2;
+ int _freqBase1;
+ int _freqBase2;
+ int _channelNum1, _channelNum2;
+ int _v7;
+ int _v8;
+ int _v9;
+ int _v10;
+ int _pollResult;
+ int _resultFlag;
+ byte _nullData[2];
+ int _ports[256];
+ bool _stateFlag;
+ int _activeChannelReg;
+ int _v11;
+ bool _amDep, _vibDep, _splitPoint;
+public:
+ /**
+ * Constructor
+ * @param mixer Mixer
+ * @param opl OPL
+ * @param filename Specifies the adlib sound player file to use
+ * @param dataOffset Offset in the file of the data segment
+ */
+ ASound(Audio::Mixer *mixer, OPL::OPL *opl, const Common::Path &filename, int dataOffset);
+
+ /**
+ * Destructor
+ */
+ virtual ~ASound();
+
+ /**
+ * Validates the Adlib sound files
+ */
+ static void validate();
+
+ /**
+ * Execute a player command. Most commands represent sounds to play, but some
+ * low number commands also provide control operations.
+ * @param commandId Player ommand to execute.
+ * @param param Optional parameter used by a few commands
+ */
+ virtual int command(int commandId, int param) = 0;
+
+ /**
+ * Stop all currently playing sounds
+ */
+ int stop();
+
+ /**
+ * Main poll method to allow sounds to progress
+ */
+ int poll();
+
+ /**
+ * General noise/note output
+ */
+ void noise();
+
+ /**
+ * Return the current frame counter
+ */
+ int getFrameCounter() {
+ return _frameCounter;
+ }
+
+ /**
+ * Return the cached data block record for previously loaded sound data
+ */
+ CachedDataEntry &getCachedData(byte *pData);
+
+ /**
+ * Set the volume
+ */
+ void setVolume(int volume);
+};
+
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/matte.cpp b/engines/mads/madsv2/core/matte.cpp
index ebadc5bf3c6..5398e23bd31 100644
--- a/engines/mads/madsv2/core/matte.cpp
+++ b/engines/mads/madsv2/core/matte.cpp
@@ -34,6 +34,7 @@
#include "mads/madsv2/core/ems.h"
#include "mads/madsv2/core/keys.h"
#include "mads/madsv2/core/timer.h"
+#include "mads/madsv2/core/sound.h"
#define word_align_mattes
#ifndef disable_error_check
diff --git a/engines/mads/nebular/nebular.cpp b/engines/mads/nebular/nebular.cpp
index 82ded3fe8ac..cd8964fd1a6 100644
--- a/engines/mads/nebular/nebular.cpp
+++ b/engines/mads/nebular/nebular.cpp
@@ -26,6 +26,7 @@
#include "common/text-to-speech.h"
#include "engines/util.h"
#include "mads/nebular/nebular.h"
+#include "mads/nebular/sound_nebular.h"
#include "mads/core/game.h"
#include "mads/core/screen.h"
#include "mads/core/msurface.h"
@@ -46,7 +47,6 @@ RexNebularEngine::RexNebularEngine(OSystem *syst, const MADSGameDescription *gam
_textWindowStill = false;
_screenFade = SCREEN_FADE_SMOOTH;
_musicFlag = true;
- _soundFlag = true;
_dithering = false;
_disableFastwalk = false;
@@ -100,7 +100,7 @@ void RexNebularEngine::initialize() {
Font::init(this);
_font = new Font();
_screen = new Screen();
- _sound = new SoundManager(this, _mixer);
+ _sound = new Nebular::RexSoundManager(_mixer, _soundFlag);
_audio = new AudioPlayer(_mixer, getGameID());
_game = Game::init(this);
_gameConv = new GameConversations(this);
diff --git a/engines/mads/nebular/sound_nebular.cpp b/engines/mads/nebular/sound_nebular.cpp
index 0de1c34e076..5cd34715d68 100644
--- a/engines/mads/nebular/sound_nebular.cpp
+++ b/engines/mads/nebular/sound_nebular.cpp
@@ -32,196 +32,7 @@ namespace MADS {
namespace Nebular {
-bool AdlibChannel::_channelsEnabled;
-
-AdlibChannel::AdlibChannel() {
- _owner = nullptr;
- _activeCount = 0;
- _field1 = 0;
- _field2 = 0;
- _field3 = 0;
- _field4 = 0;
- _sampleIndex = 0;
- _volume = 0;
- _volumeOffset = 0;
- _field7 = 0;
- _field8 = 0;
- _field9 = 0;
- _fieldA = 0;
- _fieldB = 0;
- _fieldC = 0;
- _fieldD = 0;
- _fieldE = 0;
- _ptr1 = nullptr;
- _pSrc = nullptr;
- _ptr3 = nullptr;
- _ptr4 = nullptr;
- _ptrEnd = nullptr;
- _field17 = 0;
- _field19 = 0;
- _soundData = nullptr;
- _field1D = 0;
- _field1F = 0;
-
- _field20 = 0;
-}
-
-void AdlibChannel::reset() {
- _activeCount = 0;
- _field1 = 0;
- _field2 = 0;
- _field3 = 0;
-}
-
-void AdlibChannel::enable(int flag) {
- if (_activeCount) {
- _fieldE = flag;
-
- // WORKAROUND: Original set _soundData pointer to flag. Since this seems
- // just intended to invalidate any prior pointer, I've replaced it with
- // a simple null pointer
- _soundData = nullptr;
- }
-
- _channelsEnabled = true;
-}
-
-void AdlibChannel::setPtr2(byte *pData) {
- _pSrc = pData;
- _field2 = 0xFF;
- _fieldA = 1;
- _field9 = 1;
-}
-
-void AdlibChannel::load(byte *pData) {
- _ptr1 = _pSrc = _ptr3 = pData;
- _ptr4 = _soundData = pData;
- _volumeOffset = 0;
- _fieldA = 0xFF;
- _activeCount = 1;
- _fieldD = 64;
- _field1 = 0;
- _field1F = 0;
- _field2 = _field3 = 0;
- _volume = _field7 = 0;
- _field1D = 0;
- _fieldE = 0;
- _field9 = 0;
- _fieldB = 0;
- _field17 = 0;
- _field19 = 0;
-
- CachedDataEntry &cacheEntry = _owner->getCachedData(pData);
- _ptrEnd = cacheEntry._dataEnd;
-}
-
-void AdlibChannel::check(byte *nullPtr) {
- if (_activeCount && _fieldE) {
- if (!_volumeOffset) {
- _pSrc = nullPtr;
- _fieldE = 0;
- } else {
- _field2 = 0xFF;
- _fieldA = 4;
- if (!_field9)
- _field9 = 1;
- }
- }
-}
-
-/*-----------------------------------------------------------------------*/
-
-AdlibSample::AdlibSample(Common::SeekableReadStream &s) {
- _attackRate = s.readByte();
- _decayRate = s.readByte();
- _sustainLevel = s.readByte();
- _releaseRate = s.readByte();
- _egTyp = s.readByte() != 0;
- _ksr = s.readByte() != 0;
- _totalLevel = s.readByte();
- _scalingLevel = s.readByte();
- _waveformSelect = s.readByte();
- _freqMultiple = s.readByte();
- _feedback = s.readByte();
- _ampMod = s.readByte() != 0;
- _vib = s.readByte();
- _alg = s.readByte();
- _fieldE = s.readByte();
- s.skip(1);
- _freqMask = s.readUint16LE();
- _freqBase = s.readUint16LE();
- _field14 = s.readUint16LE();
-}
-
-/*-----------------------------------------------------------------------*/
-
-ASound::ASound(Audio::Mixer *mixer, OPL::OPL *opl, const Common::Path &filename, int dataOffset) {
- // Open up the appropriate sound file
- if (!_soundFile.open(filename))
- error("Could not open file - %s", filename.toString().c_str());
-
- // Initialize fields
- _commandParam = 0;
- _activeChannelPtr = nullptr;
- _samplePtr = nullptr;
- _frameCounter = 0;
- _isDisabled = false;
- _masterVolume = 255;
- _v1 = 0;
- _v2 = 0;
- _activeChannelNumber = 0;
- _freqMask1 = _freqMask2 = 0;
- _freqBase1 = _freqBase2 = 0;
- _channelNum1 = _channelNum2 = 0;
- _v7 = 0;
- _v8 = 0;
- _v9 = 0;
- _v10 = 0;
- _pollResult = 0;
- _resultFlag = 0;
- _nullData[0] = _nullData[1] = 0;
- Common::fill(&_ports[0], &_ports[256], 0);
- _stateFlag = false;
- _activeChannelReg = 0;
- _v11 = 0;
- _randomSeed = 1234;
- _amDep = _vibDep = _splitPoint = true;
-
- for (int i = 0; i < 11; ++i) {
- _channelData[i]._field0 = 0;
- _channelData[i]._freqMask = 0;
- _channelData[i]._freqBase = 0;
- _channelData[i]._field6 = 0;
- }
-
- for (int i = 0; i < ADLIB_CHANNEL_COUNT; ++i)
- _channels[i]._owner = this;
-
- AdlibChannel::_channelsEnabled = false;
-
- // Store passed parameters, and setup OPL
- _dataOffset = dataOffset;
- _mixer = mixer;
- _opl = opl;
-
- // Initialize the Adlib
- adlibInit();
-
- // Reset the adlib
- command0();
-
- _opl->start(new Common::Functor0Mem<void, ASound>(this, &ASound::onTimer), CALLBACKS_PER_SECOND);
-}
-
-ASound::~ASound() {
- _opl->stop();
-
- Common::List<CachedDataEntry>::iterator i;
- for (i = _dataCache.begin(); i != _dataCache.end(); ++i)
- delete[] (*i)._data;
-}
-
-void ASound::validate() {
+void RexSoundManager::validate() {
Common::File f;
static const char *const MD5[] = {
"205398468de2c8873b7d4d73d5be8ddc",
@@ -247,698 +58,41 @@ void ASound::validate() {
}
}
-void ASound::adlibInit() {
- write(4, 0x60);
- write(4, 0x80);
- write(2, 0xff);
- write(4, 0x21);
- write(4, 0x60);
- write(4, 0x80);
-}
-
-int ASound::stop() {
- command0();
- int result = _pollResult;
- _pollResult = 0;
- return result;
-}
-
-int ASound::poll() {
- // Update any playing sounds
- update();
-
- // Return result
- int result = _pollResult;
- _pollResult = 0;
- return result;
-}
-
-void ASound::noise() {
- int randomVal = getRandomNumber();
-
- if (_v1) {
- setFrequency(_channelNum1, ((randomVal ^ 0xFFFF) & _freqMask1) + _freqBase1);
- }
-
- if (_v2) {
- setFrequency(_channelNum2, (randomVal & _freqMask2) + _freqBase2);
- }
-}
-
-CachedDataEntry &ASound::getCachedData(byte *pData) {
- Common::List<CachedDataEntry>::iterator i;
- for (i = _dataCache.begin(); i != _dataCache.end(); ++i) {
- CachedDataEntry &e = *i;
- if (e._data == pData)
- return e;
- }
-
- error("Could not find previously loaded data");
-}
-
-void ASound::write(int reg, int val) {
- _queue.push(RegisterValue(reg, val));
-}
-
-int ASound::write2(int state, int reg, int val) {
- // TODO: Original has a state parameter, not used when in Adlib mode?
- _ports[reg] = val;
- write(reg, val);
- return state;
-}
-
-void ASound::flush() {
- Common::StackLock slock(_driverMutex);
-
- while (!_queue.empty()) {
- RegisterValue v = _queue.pop();
- _opl->writeReg(v._regNum, v._value);
- }
-}
-
-void ASound::channelOn(int reg, int volume) {
- write2(8, reg, (_ports[reg] & 0xC0) | (volume & 0x3F));
-}
-
-void ASound::channelOff(int reg) {
- write2(8, reg, _ports[reg] | 0x3F);
-}
-
-void ASound::resultCheck() {
- if (_resultFlag != 1) {
- _resultFlag = 1;
- _pollResult = 1;
- }
-}
-
-byte *ASound::loadData(int offset, int size) {
- // First scan for an existing copy
- Common::List<CachedDataEntry>::iterator i;
- for (i = _dataCache.begin(); i != _dataCache.end(); ++i) {
- CachedDataEntry &e = *i;
- if (e._offset == offset)
- return e._data;
- }
-
- // No existing entry found, so load up data and store as a new entry
- CachedDataEntry rec;
- rec._offset = offset;
- rec._data = new byte[size];
- rec._dataEnd = rec._data + size - 1;
- _soundFile.seek(_dataOffset + offset);
- _soundFile.read(rec._data, size);
- _dataCache.push_back(rec);
-
- // Return the data
- return rec._data;
-}
-
-void ASound::playSound(int offset, int size) {
- // Load the specified data block
- playSoundData(loadData(offset, size));
-}
-
-void ASound::playSoundData(byte *pData, int startingChannel) {
- // Scan for a high level free channel
- for (int i = startingChannel; i < ADLIB_CHANNEL_COUNT; ++i) {
- if (!_channels[i]._activeCount) {
- _channels[i].load(pData);
- return;
- }
- }
-
- // None found, do a secondary scan for an interruptable channel
- for (int i = ADLIB_CHANNEL_COUNT - 1; i >= startingChannel; --i) {
- if (_channels[i]._fieldE == 0xFF) {
- _channels[i].load(pData);
- return;
- }
- }
-}
-
-bool ASound::isSoundActive(byte *pData) {
- for (int i = 0; i < ADLIB_CHANNEL_MIDWAY; ++i) {
- if (_channels[i]._activeCount && _channels[i]._soundData == pData)
- return true;
- }
-
- return false;
-}
-
-void ASound::setFrequency(int channel, int freq) {
- write2(8, 0xA0 + channel, freq & 0xFF);
- write2(8, 0xB0 + channel, (freq >> 8) | 0x20);
-}
-
-int ASound::getRandomNumber() {
- int v = 0x9248 + (int)_randomSeed;
- _randomSeed = ((v >> 3) | (v << 13)) & 0xFFFF;
- return _randomSeed;
-}
-
-void ASound::update() {
- getRandomNumber();
- if (_isDisabled)
+void RexSoundManager::loadDriver(int sectionNumber) {
+ switch (sectionNumber) {
+ case 1:
+ _driver = new Nebular::ASound1(_mixer, _opl);
+ break;
+ case 2:
+ _driver = new Nebular::ASound2(_mixer, _opl);
+ break;
+ case 3:
+ _driver = new Nebular::ASound3(_mixer, _opl);
+ break;
+ case 4:
+ _driver = new Nebular::ASound4(_mixer, _opl);
+ break;
+ case 5:
+ _driver = new Nebular::ASound5(_mixer, _opl);
+ break;
+ case 6:
+ _driver = new Nebular::ASound6(_mixer, _opl);
+ break;
+ case 7:
+ _driver = new Nebular::ASound7(_mixer, _opl);
+ break;
+ case 8:
+ _driver = new Nebular::ASound8(_mixer, _opl);
+ break;
+ case 9:
+ _driver = new Nebular::ASound9(_mixer, _opl);
+ break;
+ default:
+ _driver = nullptr;
return;
-
- ++_frameCounter;
- pollChannels();
- checkChannels();
-
- if (_v1 == _v2) {
- if (_resultFlag != -1) {
- _resultFlag = -1;
- _pollResult = -1;
- }
- } else {
- if (_v1) {
- _freqBase1 += _v7;
- if (!--_v1) {
- if (!_v2 || _channelNum1 != _channelNum2) {
- write2(8, 0xA0 + _channelNum1, 0);
- write2(8, 0xB0 + _channelNum1, 0);
- }
- }
- }
-
- if (_v2) {
- _freqBase2 += _v8;
- if (!--_v2) {
- if (!_v1 || _channelNum2 != _channelNum1) {
- write2(8, 0xA0 + _channelNum2, 0);
- write2(8, 0xB0 + _channelNum2, 0);
- }
- }
- }
}
}
-void ASound::pollChannels() {
- _activeChannelNumber = 0;
- for (int i = 0; i < ADLIB_CHANNEL_COUNT; ++i) {
- _activeChannelPtr = &_channels[i];
- pollActiveChannel();
- }
-}
-
-void ASound::checkChannels() {
- if (AdlibChannel::_channelsEnabled) {
- for (int i = 0; i < ADLIB_CHANNEL_COUNT; ++i)
- _channels[i].check(_nullData);
- }
-}
-
-void ASound::pollActiveChannel() {
- AdlibChannel *chan = _activeChannelPtr;
-
- if (chan->_activeCount) {
- if (chan->_field8 > 0 && --chan->_field8 == 0)
- updateOctave();
-
- bool updateFlag = true;
- if (--_activeChannelPtr->_activeCount <= 0) {
- for (;;) {
- byte *pSrc = chan->_pSrc;
- if (!chan->_ptr1) {
- warning("pollActiveChannel(): No data found for sound channel");
- break;
- }
- if (pSrc > chan->_ptrEnd) {
- warning("Read beyond end of loaded sound data");
- return;
- }
-
- if (!(*pSrc & 0x80) || (*pSrc <= 0xF0)) {
- if (updateFlag)
- updateActiveChannel();
-
- chan->_field4 = *pSrc++;
- chan->_activeCount = *pSrc++;
- chan->_pSrc += 2;
-
- if (!chan->_field4 || !chan->_activeCount) {
- updateOctave();
- } else {
- chan->_field8 = chan->_activeCount - chan->_field7;
- updateChannelState();
- }
-
- // Break out of processing loop
- break;
- } else {
- updateFlag = false;
-
- switch ((~*pSrc) & 0xF) {
- case 0:
- if (!chan->_field17) {
- if (*++pSrc == 0) {
- chan->_pSrc += 2;
- chan->_ptr3 = chan->_pSrc;
- chan->_field17 = 0;
- } else {
- chan->_field17 = *pSrc;
- chan->_pSrc = chan->_ptr3;
- }
- } else if (--chan->_field17) {
- chan->_pSrc = chan->_ptr3;
- } else {
- chan->_pSrc += 2;
- chan->_ptr3 = chan->_pSrc;
- }
- break;
-
- case 1:
- if (!chan->_field19) {
- if (*++pSrc == 0) {
- chan->_pSrc += 2;
- chan->_ptr4 = chan->_pSrc;
- chan->_ptr3 = chan->_pSrc;
- chan->_field17 = 0;
- chan->_field19 = 0;
- } else {
- chan->_field19 = *pSrc;
- chan->_pSrc = chan->_ptr4;
- chan->_ptr3 = chan->_ptr4;
- }
- } else if (--chan->_field19) {
- chan->_ptr4 = chan->_pSrc;
- chan->_ptr3 = chan->_pSrc;
- } else {
- chan->_pSrc += 2;
- chan->_ptr4 = chan->_pSrc;
- chan->_ptr3 = chan->_pSrc;
- }
- break;
-
- case 2:
- // Loop sound data
- chan->_field1 = 0;
- chan->_field2 = chan->_field3 = 0;
- chan->_volume = chan->_field7 = 0;
- chan->_field1D = chan->_volumeOffset = 0;
- chan->_field8 = 0;
- chan->_field9 = 0;
- chan->_fieldB = 0;
- chan->_field17 = 0;
- chan->_field19 = 0;
- chan->_fieldD = 0x40;
- chan->_ptr1 = chan->_soundData;
- chan->_pSrc = chan->_soundData;
- chan->_ptr3 = chan->_soundData;
- chan->_ptr4 = chan->_soundData;
-
- chan->_pSrc += 2;
- break;
-
- case 3:
- chan->_sampleIndex = *++pSrc;
- chan->_pSrc += 2;
- loadSample(chan->_sampleIndex);
- break;
-
- case 4:
- chan->_field7 = *++pSrc;
- chan->_pSrc += 2;
- break;
-
- case 5:
- chan->_field1 = *++pSrc;
- chan->_pSrc += 2;
- break;
-
- case 6:
- ++pSrc;
- if (chan->_fieldE) {
- chan->_pSrc += 2;
- } else {
- chan->_volume = *pSrc >> 1;
- updateFlag = true;
- chan->_pSrc += 2;
- }
- break;
-
- case 7:
- ++pSrc;
- if (!chan->_fieldE) {
- chan->_fieldA = *pSrc;
- chan->_field2 = *++pSrc;
- chan->_field9 = 1;
- }
-
- chan->_pSrc += 3;
- break;
-
- case 8:
- chan->_field1D = (int8)*++pSrc;
- chan->_pSrc += 2;
- break;
-
- case 9: {
- int v1 = *++pSrc;
- ++pSrc;
- int v2 = (v1 - 1) & getRandomNumber();
- int v3 = pSrc[v2];
- int v4 = pSrc[v1];
-
- pSrc[v4 + v1 + 1] = v3;
- chan->_pSrc += v1 + 3;
- break;
- }
-
- case 10:
- ++pSrc;
- if (chan->_fieldE) {
- chan->_pSrc += 2;
- } else {
- chan->_volumeOffset = *pSrc >> 1;
- updateFlag = true;
- chan->_pSrc += 2;
- }
- break;
-
- case 11:
- chan->_fieldD = *++pSrc;
- updateFlag = true;
- chan->_pSrc += 2;
- break;
-
- case 12:
- chan->_fieldC = *++pSrc;
- chan->_field3 = *++pSrc;
- chan->_fieldB = 1;
- chan->_pSrc += 2;
- break;
-
- case 13:
- ++pSrc;
- chan->_pSrc += 2;
- break;
-
- case 14:
- chan->_field1F = *++pSrc;
- chan->_pSrc += 2;
- break;
-
- default:
- break;
- }
- }
- }
- }
-
- if (chan->_field1)
- updateFNumber();
-
- updateFlag = false;
- if (chan->_field9 || chan->_fieldB) {
- if (!--chan->_field9) {
- chan->_field9 = chan->_fieldA;
- if (chan->_field2) {
- int8 newVal = (int8)chan->_field2 + (int8)chan->_volumeOffset;
- if (newVal < 0) {
- chan->_field9 = 0;
- newVal = 0;
- } else if (newVal > 63) {
- chan->_field9 = 0;
- newVal = 63;
- }
-
- chan->_volumeOffset = newVal;
- updateFlag = true;
- }
- }
-
- if (!--chan->_fieldB) {
- chan->_fieldB = chan->_fieldC;
- if (chan->_field3) {
- chan->_fieldD = chan->_field3;
- updateFlag = true;
- }
- }
-
- if (updateFlag)
- updateActiveChannel();
- }
- }
-
- ++_activeChannelNumber;
-}
-
-void ASound::updateOctave() {
- int reg = 0xB0 + _activeChannelNumber;
- write2(8, reg, _ports[reg] & 0xDF);
-}
-
-static int _vList1[] = {
- 0x200, 0x21E, 0x23F, 0x261, 0x285, 0x2AB,
- 0x2D4, 0x2FF, 0x32D, 0x35D, 0x390, 0x3C7
-};
-
-void ASound::updateChannelState() {
- updateActiveChannel();
-
- if (_channelData[_activeChannelNumber]._field0) {
- if (_channelNum1 == _activeChannelNumber)
- _stateFlag = 0;
- if (_channelNum2 == _activeChannelNumber)
- _stateFlag = 1;
-
- if (!_stateFlag) {
- _stateFlag = 1;
- if (_v1)
- write2(8, 0xB0 + _channelNum1, _ports[0xB0 + _channelNum1] & 0xDF);
-
- _channelNum1 = _activeChannelNumber;
- _v1 = _channelData[_channelNum1]._field0;
- _freqMask1 = _channelData[_channelNum1]._freqMask;
- _freqBase1 = _channelData[_channelNum1]._freqBase;
- _v7 = _channelData[_channelNum1]._field6;
- } else {
- _stateFlag = 0;
- if (_v2)
- write2(8, 0xB0 + _channelNum2, _ports[0xB0 + _channelNum2] & 0xDF);
-
- _channelNum2 = _activeChannelNumber;
- _v2 = _channelData[_channelNum2]._field0;
- _freqMask2 = _channelData[_channelNum2]._freqMask;
- _freqBase2 = _channelData[_channelNum2]._freqBase;
- _v8 = _channelData[_channelNum2]._field6;
- }
-
- resultCheck();
- } else {
- int reg = 0xA0 + _activeChannelNumber;
- int vTimes = (byte)(_activeChannelPtr->_field4 + _activeChannelPtr->_field1F) / 12;
- int vOffset = (byte)(_activeChannelPtr->_field4 + _activeChannelPtr->_field1F) % 12;
- int val = _vList1[vOffset] + _activeChannelPtr->_field1D;
- write2(8, reg, val & 0xFF);
-
- reg += 0x10;
- write2(8, reg, (_ports[reg] & 0x20) | (vTimes << 2) | (val >> 8));
-
- write2(8, reg, _ports[reg] | 0x20);
- }
-}
-
-static const int outputIndexes[] = {
- 0, 3, 1, 4, 2, 5, 6, 9, 7, 10, 8, 11, 12, 15, 13, 16, 14, 17
-};
-static const int outputChannels[] = {
- 0, 1, 2, 3, 4, 5, 8, 9, 10, 11, 12, 13, 16, 17, 18, 19, 20, 21, 0
-};
-
-void ASound::updateActiveChannel() {
- int reg = 0x40 + outputChannels[outputIndexes[_activeChannelNumber * 2 + 1]];
- int portVal = _ports[reg] & 0xFFC0;
- int newVolume = CLIP(_activeChannelPtr->_volume + _activeChannelPtr->_volumeOffset, 0, 63);
- newVolume = newVolume * _masterVolume / 255;
-
- // Note: Original had a whole block not seeming to be used, since the initialisation
- // sets a variable to 5660h, and doesn't change it, so the branch is never taken
- portVal |= 63 - newVolume;
-
- write2(8, reg, portVal);
-}
-
-void ASound::loadSample(int sampleIndex) {
- _activeChannelReg = 0xB0 + _activeChannelNumber;
- write2(8, _activeChannelReg, _ports[_activeChannelReg] & 0xDF);
-
- _activeChannelReg = _activeChannelNumber;
- _samplePtr = &_samples[sampleIndex * 2];
- _v11 = outputChannels[outputIndexes[_activeChannelReg * 2]];
- processSample();
-
- AdlibChannelData &cd = _channelData[_activeChannelNumber];
- cd._field6 = _samplePtr->_field14;
- cd._freqBase = _samplePtr->_freqBase;
- cd._freqMask = _samplePtr->_freqMask;
- cd._field0 = _samplePtr->_fieldE;
-
- _samplePtr = &_samples[sampleIndex * 2 + 1];
- _v11 = outputChannels[outputIndexes[_activeChannelReg * 2 + 1]];
- processSample();
-}
-
-void ASound::processSample() {
- // Write out vib flags and split point
- write2(8, 0x40 + _v11, 0x3F);
- int depthRhythm = (_ports[0xBD] & 0x3F) | (_amDep ? 0x80 : 0) |
- (_vibDep ? 0x40 : 0);
- write2(8, 0xBD, depthRhythm);
- write2(8, 8, _splitPoint ? 0x40 : 0);
-
- // Write out feedback & Alg
- int val = (_samplePtr->_feedback << 1) | (1 - _samplePtr->_alg);
- write2(8, 0xC0 + _activeChannelReg, val);
-
- // Write out attack/decay rate
- val = (_samplePtr->_attackRate << 4) | (_samplePtr->_decayRate & 0xF);
- write2(8, 0x60 + _v11, val);
-
- // Write out sustain level/release rate
- val = (_samplePtr->_sustainLevel << 4) | (_samplePtr->_releaseRate & 0xF);
- write2(8, 0x80 + _v11, val);
-
- // Write out misc flags
- val = (_samplePtr->_ampMod ? 0x80 : 0) | (_samplePtr->_vib ? 0x40 : 0)
- | (_samplePtr->_egTyp ? 0x20 : 0) | (_samplePtr->_ksr ? 0x10 : 0)
- | (_samplePtr->_freqMultiple & 0xF);
- write2(8, 0x20 + _v11, val);
-
- // Write out waveform select
- write2(8, 0xE0 + _v11, _samplePtr->_waveformSelect & 3);
-
- // Write out total level & scaling level
- val = -((_samplePtr->_totalLevel & 0x3F) - 0x3F) | (_samplePtr->_scalingLevel << 6);
- write2(8, 0x40 + _v11, val);
-}
-
-void ASound::updateFNumber() {
- int loReg = 0xA0 + _activeChannelNumber;
- int hiReg = 0xB0 + _activeChannelNumber;
- int val1 = (_ports[hiReg] & 0x1F) << 8;
- val1 += _ports[loReg] + _activeChannelPtr->_field1;
- write2(8, loReg, val1);
-
- int val2 = (_ports[hiReg] & 0x20) | (val1 >> 8);
- write2(8, hiReg, val2);
-}
-
-void ASound::onTimer() {
- Common::StackLock slock(_driverMutex);
- poll();
- flush();
-}
-
-void ASound::setVolume(int volume) {
- _masterVolume = volume;
- if (!volume)
- command0();
-}
-
-int ASound::command0() {
- bool isDisabled = _isDisabled;
- _isDisabled = true;
-
- for (int i = 0; i < ADLIB_CHANNEL_COUNT; ++i)
- _channels[i].reset();
-
- _v1 = 0;
- _v2 = 0;
- _freqMask1 = _freqMask2 = 0;
- _freqBase1 = _freqBase2 = 0;
- _v7 = 0;
- _v8 = 0;
-
- // Reset Adlib port registers
- for (int reg = 0x4F; reg >= 0x40; --reg)
- write2(8, reg, 0x3F);
- for (int reg = 0xFF; reg >= 0x60; --reg)
- write2(8, reg, 0);
- for (int reg = 0x3F; reg > 0; --reg)
- write2(8, reg, 0);
- write2(8, 1, 0x20);
-
- _isDisabled = isDisabled;
- return 0;
-}
-
-int ASound::command1() {
- for (int i = 0; i < ADLIB_CHANNEL_COUNT; ++i)
- _channels[i].enable(0xFF);
- return 0;
-}
-
-int ASound::command2() {
- for (int i = 0; i < ADLIB_CHANNEL_MIDWAY; ++i)
- _channels[i].setPtr2(_nullData);
- return 0;
-}
-
-int ASound::command3() {
- for (int i = 0; i < ADLIB_CHANNEL_MIDWAY; ++i)
- _channels[i].enable(0xFF);
- return 0;
-}
-
-int ASound::command4() {
- for (int i = ADLIB_CHANNEL_MIDWAY; i < ADLIB_CHANNEL_COUNT; ++i)
- _channels[i].setPtr2(_nullData);
- return 0;
-}
-
-int ASound::command5() {
- for (int i = 5; i < ADLIB_CHANNEL_COUNT; ++i)
- _channels[i].enable(0xFF);
- return 0;
-}
-
-int ASound::command6() {
- _v9 = _v1;
- _v1 = 0;
- _v10 = _v2;
- _v2 = 0;
-
- channelOff(0x43);
- channelOff(0x44);
- channelOff(0x45);
- channelOff(0x4B);
- channelOff(0x4C);
- channelOff(0x4D);
- channelOff(0x53);
- channelOff(0x54);
- channelOff(0x55);
-
- return 0;
-}
-
-int ASound::command7() {
- channelOn(0x43, _channels[0]._volume);
- channelOn(0x44, _channels[1]._volume);
- channelOn(0x45, _channels[2]._volume);
- channelOn(0x4B, _channels[3]._volume);
- channelOn(0x4C, _channels[4]._volume);
- channelOn(0x4D, _channels[5]._volume);
-
- _v1 = _v9;
- _v2 = _v10;
-
- if (_v9 != _v10)
- resultCheck();
-
- _isDisabled = 0;
- return _v10;
-}
-
-int ASound::command8() {
- int result = 0;
- for (int i = 0; i < ADLIB_CHANNEL_COUNT; ++i)
- result |= _channels[i]._activeCount;
-
- return result;
-}
-
/*-----------------------------------------------------------------------*/
const ASound1::CommandPtr ASound1::_commandList[42] = {
diff --git a/engines/mads/nebular/sound_nebular.h b/engines/mads/nebular/sound_nebular.h
index bfc2ca87fcc..a6392ac1c89 100644
--- a/engines/mads/nebular/sound_nebular.h
+++ b/engines/mads/nebular/sound_nebular.h
@@ -22,357 +22,22 @@
#ifndef MADS_SOUND_NEBULAR_H
#define MADS_SOUND_NEBULAR_H
-#include "common/scummsys.h"
-#include "common/file.h"
-#include "common/mutex.h"
-#include "common/queue.h"
-
-namespace Audio {
-class Mixer;
-}
-
-namespace Common {
-class SeekableReadStream;
-}
-
-namespace OPL {
-class OPL;
-}
+#include "mads/core/sound.h"
namespace MADS {
-
namespace Nebular {
-class ASound;
-
-/**
- * Represents the data for a channel on the Adlib
- */
-class AdlibChannel {
-public:
- ASound *_owner;
-
- int _activeCount;
- int _field1;
- int _field2;
- int _field3;
- int _field4;
- int _sampleIndex;
- int _volume;
- int _field7;
- int _field8;
- int _field9;
- int _fieldA;
- uint8 _fieldB;
- int _fieldC;
- int _fieldD;
- int _fieldE;
- byte *_ptr1;
- byte *_pSrc;
- byte *_ptr3;
- byte *_ptr4;
- byte *_ptrEnd;
- int _field17;
- int _field19;
- byte *_soundData;
- int _field1D;
- int _volumeOffset;
- int _field1F;
-
- // TODO: Only used by asound.003. Figure out usage
- byte _field20;
-public:
- static bool _channelsEnabled;
-public:
- AdlibChannel();
-
- void reset();
- void enable(int flag);
- void setPtr2(byte *pData);
- void load(byte *pData);
- void check(byte *nullPtr);
-};
-
-class AdlibChannelData {
-public:
- int _field0;
- int _freqMask;
- int _freqBase;
- int _field6;
-};
+class RexSoundManager : public SoundManager {
+protected:
+ void loadDriver(int sectionNum) override;
-class AdlibSample {
public:
- int _attackRate;
- int _decayRate;
- int _sustainLevel;
- int _releaseRate;
- bool _egTyp;
- bool _ksr;
- int _totalLevel;
- int _scalingLevel;
- int _waveformSelect;
- int _freqMultiple;
- int _feedback;
- bool _ampMod;
- int _vib;
- int _alg;
- int _fieldE;
- int _freqMask;
- int _freqBase;
- int _field14;
-
- AdlibSample() {}
- AdlibSample(Common::SeekableReadStream &s);
-};
-
-struct RegisterValue {
- uint8 _regNum;
- uint8 _value;
-
- RegisterValue(int regNum, int value) {
- _regNum = regNum; _value = value;
+ RexSoundManager(Audio::Mixer *mixer, bool &soundFlag) : SoundManager(mixer, soundFlag) {
+ }
+ ~RexSoundManager() override {
}
-};
-
-#define ADLIB_CHANNEL_COUNT 9
-#define ADLIB_CHANNEL_MIDWAY 5
-#define CALLBACKS_PER_SECOND 60
-
-struct CachedDataEntry {
- int _offset;
- byte *_data;
- byte *_dataEnd;
-};
-/**
- * Base class for the sound player resource files
- */
-class ASound {
-private:
- Common::List<CachedDataEntry> _dataCache;
- uint16 _randomSeed;
- int _masterVolume;
-
- /**
- * Does the initial Adlib initialisation
- */
- void adlibInit();
-
- /**
- * Does on-going processing for the Adlib sounds being played
- */
- void update();
-
- /**
- * Polls each of the channels for updates
- */
- void pollChannels();
-
- /**
- * Checks the status of the channels
- */
- void checkChannels();
-
- /**
- * Polls the currently active channel
- */
- void pollActiveChannel();
-
- /**
- * Updates the octave of the currently active channel
- */
- void updateOctave();
-
- void updateChannelState();
- void updateActiveChannel();
-
- /**
- * Loads up the specified sample
- */
- void loadSample(int sampleIndex);
-
- /**
- * Writes out the data of the selected sample to the Adlib
- */
- void processSample();
-
- void updateFNumber();
-
- /**
- * Timer function for OPL
- */
- void onTimer();
-protected:
- int _commandParam;
-
- /**
- * Queue a byte for an Adlib register
- */
- void write(int reg, int val);
-
- /**
- * Queue a byte for an Adlib register, and store it in the _ports array
- */
- int write2(int state, int reg, int val);
-
- /**
- * Flush any pending Adlib register values to the OPL driver
- */
- void flush();
-
- /**
- * Turn a channel on
- */
- void channelOn(int reg, int volume);
-
- /**
- * Turn a channel off
- */
- void channelOff(int reg);
-
- /**
- * Checks for whether a poll result needs to be set
- */
- void resultCheck();
-
- /**
- * Loads a data block from the sound file, caching the result for any future
- * calls for the same data
- */
- byte *loadData(int offset, int size);
-
- /**
- * Play the specified sound
- * @param offset Offset of sound data within sound player data segment
- * @param size Size of sound data block
- */
- void playSound(int offset, int size);
-
- /**
- * Play the specified raw sound data
- * @param pData Pointer to data block containing sound data
- * @param startingChannel Channel to start scan from
- */
- void playSoundData(byte *pData, int startingChannel = ADLIB_CHANNEL_MIDWAY);
-
- /**
- * Checks to see whether the given block of data is already loaded into a channel.
- */
- bool isSoundActive(byte *pData);
-
- /**
- * Sets the frequency for a given channel.
- */
- void setFrequency(int channel, int freq);
-
- /**
- * Returns a 16-bit random number
- */
- int getRandomNumber();
-
- virtual int command0();
- int command1();
- int command2();
- int command3();
- int command4();
- int command5();
- int command6();
- int command7();
- int command8();
-
- int nullCommand() { return 0; }
-public:
- Audio::Mixer *_mixer;
- OPL::OPL *_opl;
- AdlibChannel _channels[ADLIB_CHANNEL_COUNT];
- AdlibChannel *_activeChannelPtr;
- AdlibChannelData _channelData[11];
- Common::Array<AdlibSample> _samples;
- AdlibSample *_samplePtr;
- Common::File _soundFile;
- Common::Queue<RegisterValue> _queue;
- Common::Mutex _driverMutex;
- int _dataOffset;
- int _frameCounter;
- bool _isDisabled;
- int _v1;
- int _v2;
- int _activeChannelNumber;
- int _freqMask1;
- int _freqMask2;
- int _freqBase1;
- int _freqBase2;
- int _channelNum1, _channelNum2;
- int _v7;
- int _v8;
- int _v9;
- int _v10;
- int _pollResult;
- int _resultFlag;
- byte _nullData[2];
- int _ports[256];
- bool _stateFlag;
- int _activeChannelReg;
- int _v11;
- bool _amDep, _vibDep, _splitPoint;
-public:
- /**
- * Constructor
- * @param mixer Mixer
- * @param opl OPL
- * @param filename Specifies the adlib sound player file to use
- * @param dataOffset Offset in the file of the data segment
- */
- ASound(Audio::Mixer *mixer, OPL::OPL *opl, const Common::Path &filename, int dataOffset);
-
- /**
- * Destructor
- */
- virtual ~ASound();
-
- /**
- * Validates the Adlib sound files
- */
- static void validate();
-
- /**
- * Execute a player command. Most commands represent sounds to play, but some
- * low number commands also provide control operations.
- * @param commandId Player ommand to execute.
- * @param param Optional parameter used by a few commands
- */
- virtual int command(int commandId, int param) = 0;
-
- /**
- * Stop all currently playing sounds
- */
- int stop();
-
- /**
- * Main poll method to allow sounds to progress
- */
- int poll();
-
- /**
- * General noise/note output
- */
- void noise();
-
- /**
- * Return the current frame counter
- */
- int getFrameCounter() { return _frameCounter; }
-
- /**
- * Return the cached data block record for previously loaded sound data
- */
- CachedDataEntry &getCachedData(byte *pData);
-
- /**
- * Set the volume
- */
- void setVolume(int volume);
+ void validate() override;
};
class ASound1 : public ASound {
Commit: fac67af9a99a137100c67b1d1654b63ea34f509f
https://github.com/scummvm/scummvm/commit/fac67af9a99a137100c67b1d1654b63ea34f509f
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:21:22+10:00
Commit Message:
MADS: PHANTOM: Skeleton sound manager implementation
Changed paths:
A engines/mads/madsv2/phantom/sound_phantom.cpp
A engines/mads/madsv2/phantom/sound_phantom.h
engines/mads/module.mk
diff --git a/engines/mads/madsv2/phantom/sound_phantom.cpp b/engines/mads/madsv2/phantom/sound_phantom.cpp
new file mode 100644
index 00000000000..d21d872d30b
--- /dev/null
+++ b/engines/mads/madsv2/phantom/sound_phantom.cpp
@@ -0,0 +1,145 @@
+/* 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/md5.h"
+#include "mads/madsv2/phantom/sound_phantom.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+
+void PhantomSoundManager::validate() {
+ Common::File f;
+ static const char *const MD5[] = {
+ "205398468de2c8873b7d4d73d5be8ddc",
+ "f9b2d944a2fb782b1af5c0ad592306d3",
+ "7431f8dad77d6ddfc24e6f3c0c4ac7df",
+ "eb1f3f5a4673d3e73d8ac1818c957cf4",
+ "f936dd853073fa44f3daac512e91c476",
+ nullptr,
+ nullptr,
+ nullptr,
+ "a31e4783e098f633cbb6689adb41dd4f"
+ };
+
+ for (int i = 1; i <= 9; ++i) {
+ if (i >= 6 && i <= 8)
+ continue;
+ Common::Path filename(Common::String::format("ASOUND.00%d", i));
+ if (!f.open(filename))
+ error("Could not process - %s", filename.toString().c_str());
+ Common::String md5str = Common::computeStreamMD5AsString(f, 8192);
+ f.close();
+
+ if (md5str != MD5[i - 1])
+ error("Invalid sound file - %s", filename.toString().c_str());
+ }
+}
+
+void PhantomSoundManager::loadDriver(int sectionNumber) {
+ switch (sectionNumber) {
+ case 1:
+ _driver = new ASound1(_mixer, _opl);
+ break;
+ case 2:
+ _driver = new ASound2(_mixer, _opl);
+ break;
+ case 3:
+ _driver = new ASound3(_mixer, _opl);
+ break;
+ case 4:
+ _driver = new ASound4(_mixer, _opl);
+ break;
+ case 5:
+ _driver = new ASound5(_mixer, _opl);
+ break;
+ case 9:
+ _driver = new ASound9(_mixer, _opl);
+ break;
+ default:
+ _driver = nullptr;
+ return;
+ }
+}
+
+/*-----------------------------------------------------------------------*/
+
+ASound1::ASound1(Audio::Mixer *mixer, OPL::OPL *opl) : ASound(mixer, opl, "asound.ph1", 0) {
+}
+
+int ASound1::command(int commandId, int param) {
+ // TODO
+ return 0;
+}
+
+/*-----------------------------------------------------------------------*/
+
+ASound2::ASound2(Audio::Mixer *mixer, OPL::OPL *opl) : ASound(mixer, opl, "asound.ph1", 0) {
+}
+
+int ASound2::command(int commandId, int param) {
+ // TODO
+ return 0;
+}
+
+/*-----------------------------------------------------------------------*/
+
+ASound3::ASound3(Audio::Mixer *mixer, OPL::OPL *opl) : ASound(mixer, opl, "asound.ph1", 0) {
+}
+
+int ASound3::command(int commandId, int param) {
+ // TODO
+ return 0;
+}
+
+/*-----------------------------------------------------------------------*/
+
+ASound4::ASound4(Audio::Mixer *mixer, OPL::OPL *opl) : ASound(mixer, opl, "asound.ph1", 0) {
+}
+
+int ASound4::command(int commandId, int param) {
+ // TODO
+ return 0;
+}
+
+/*-----------------------------------------------------------------------*/
+
+ASound5::ASound5(Audio::Mixer *mixer, OPL::OPL *opl) : ASound(mixer, opl, "asound.ph1", 0) {
+}
+
+int ASound5::command(int commandId, int param) {
+ // TODO
+ return 0;
+}
+
+/*-----------------------------------------------------------------------*/
+
+ASound9::ASound9(Audio::Mixer *mixer, OPL::OPL *opl) : ASound(mixer, opl, "asound.ph1", 0) {
+}
+
+int ASound9::command(int commandId, int param) {
+ // TODO
+ return 0;
+}
+
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/sound_phantom.h b/engines/mads/madsv2/phantom/sound_phantom.h
new file mode 100644
index 00000000000..966e0dd9f99
--- /dev/null
+++ b/engines/mads/madsv2/phantom/sound_phantom.h
@@ -0,0 +1,95 @@
+/* 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 MADS_PHANTOM_SOUND_H
+#define MADS_PHANTOM_SOUND_H
+
+#include "mads/core/sound.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+
+class PhantomSoundManager : public SoundManager {
+protected:
+ void loadDriver(int sectionNum) override;
+
+public:
+ PhantomSoundManager(Audio::Mixer *mixer, bool &soundFlag) : SoundManager(mixer, soundFlag) {
+ }
+ ~PhantomSoundManager() override {
+ }
+
+ void validate() override;
+};
+
+class ASound1 : public ASound {
+public:
+ ASound1(Audio::Mixer *mixer, OPL::OPL *opl);
+ ~ASound1() override {
+ }
+ int command(int commandId, int param) override;
+};
+
+class ASound2 : public ASound {
+public:
+ ASound2(Audio::Mixer *mixer, OPL::OPL *opl);
+ ~ASound2() override {}
+ int command(int commandId, int param) override;
+};
+
+class ASound3 : public ASound {
+public:
+ ASound3(Audio::Mixer *mixer, OPL::OPL *opl);
+ ~ASound3() override {
+ }
+ int command(int commandId, int param) override;
+};
+
+class ASound4 : public ASound {
+public:
+ ASound4(Audio::Mixer *mixer, OPL::OPL *opl);
+ ~ASound4() override {
+ }
+ int command(int commandId, int param) override;
+};
+
+class ASound5 : public ASound {
+public:
+ ASound5(Audio::Mixer *mixer, OPL::OPL *opl);
+ ~ASound5() override {
+ }
+ int command(int commandId, int param) override;
+};
+
+class ASound9 : public ASound {
+public:
+ ASound9(Audio::Mixer *mixer, OPL::OPL *opl);
+ ~ASound9() override {
+ }
+ int command(int commandId, int param) override;
+};
+
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index bb2230dd878..e42d5536124 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -122,7 +122,8 @@ MODULE_OBJS += \
madsv2/core/window.o \
madsv2/phantom/mads/mads.o \
madsv2/phantom/main_menu.o \
- madsv2/phantom/main.o
+ madsv2/phantom/main.o \
+ madsv2/phantom/sound_phantom.o
endif
# This module can be built as a plugin
Commit: db0f091b411f247d6ab59920a4b67ab4432fc675
https://github.com/scummvm/scummvm/commit/db0f091b411f247d6ab59920a4b67ab4432fc675
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:21:22+10:00
Commit Message:
MADS: PHANTOM: Create derived PhantomEngine class
Changed paths:
A engines/mads/madsv2/phantom/phantom.cpp
A engines/mads/madsv2/phantom/phantom.h
engines/mads/madsv2/core/general.h
engines/mads/madsv2/core/sound.cpp
engines/mads/madsv2/engine.cpp
engines/mads/madsv2/engine.h
engines/mads/metaengine.cpp
engines/mads/module.mk
diff --git a/engines/mads/madsv2/core/general.h b/engines/mads/madsv2/core/general.h
index 867d431a09f..2c28ea7e71d 100644
--- a/engines/mads/madsv2/core/general.h
+++ b/engines/mads/madsv2/core/general.h
@@ -122,8 +122,8 @@ typedef struct { /* Video buffer structure */
#define false 0
#endif
-#define none 0
-#define stop 99
+constexpr int none = 0;
+constexpr int stop = 99;
/* misc functional defines */
diff --git a/engines/mads/madsv2/core/sound.cpp b/engines/mads/madsv2/core/sound.cpp
index c798d13f7ef..cfcf05b4c52 100644
--- a/engines/mads/madsv2/core/sound.cpp
+++ b/engines/mads/madsv2/core/sound.cpp
@@ -26,11 +26,11 @@ namespace MADS {
namespace MADSV2 {
void sound_queue(int soundNum) {
- error("TODO: sound_queue");
+ // TODO: sound_queue
}
void sound_queue_flush() {
- error("TODO: sound_queue_flush");
+ // TODO: sound_queue_flush
}
} // namespace MADSV2
diff --git a/engines/mads/madsv2/engine.cpp b/engines/mads/madsv2/engine.cpp
index 600c352188e..cd6df8b204d 100644
--- a/engines/mads/madsv2/engine.cpp
+++ b/engines/mads/madsv2/engine.cpp
@@ -24,6 +24,7 @@
#include "mads/madsv2/engine.h"
#include "mads/madsv2/core/mouse.h"
#include "mads/madsv2/phantom/main.h"
+#include "mads/core/sound.h"
namespace MADS {
namespace MADSV2 {
@@ -41,15 +42,7 @@ MADSV2Engine::MADSV2Engine(OSystem *syst, const MADSGameDescription *gameDesc) :
MADSV2Engine::~MADSV2Engine() {
g_engine = nullptr;
delete _screen;
-}
-
-Common::Error MADSV2Engine::run() {
- initGraphics(320, 200);
- _screen = new Graphics::Screen();
-
- Phantom::phantom_main();
-
- return Common::kNoError;
+ delete _soundManager;
}
void MADSV2Engine::pollEvents() {
diff --git a/engines/mads/madsv2/engine.h b/engines/mads/madsv2/engine.h
index 6974aea2bb8..91ca2ee3bcd 100644
--- a/engines/mads/madsv2/engine.h
+++ b/engines/mads/madsv2/engine.h
@@ -27,13 +27,16 @@
#include "common/random.h"
#include "graphics/screen.h"
#include "mads/mads.h"
+#include "mads/core/sound.h"
namespace MADS {
+
namespace MADSV2 {
class MADSV2Engine : public MADSEngine {
-private:
+protected:
Graphics::Screen *_screen = nullptr;
+ MADS::SoundManager *_soundManager = nullptr;
Common::Stack<Common::Event> _keyEvents;
uint32 _nextFrameTime = 0;
@@ -43,8 +46,6 @@ public:
MADSV2Engine(OSystem *syst, const MADSGameDescription *gameDesc);
~MADSV2Engine() override;
- Common::Error run() override;
-
Graphics::Screen *getScreen() const {
return _screen;
}
diff --git a/engines/mads/madsv2/phantom/phantom.cpp b/engines/mads/madsv2/phantom/phantom.cpp
new file mode 100644
index 00000000000..d7d9a959d91
--- /dev/null
+++ b/engines/mads/madsv2/phantom/phantom.cpp
@@ -0,0 +1,43 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "engines/util.h"
+#include "mads/madsv2/phantom/phantom.h"
+#include "mads/madsv2/phantom/main.h"
+#include "mads/madsv2/phantom/sound_phantom.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+
+Common::Error PhantomEngine::run() {
+ initGraphics(320, 200);
+ _screen = new Graphics::Screen();
+ _soundManager = new PhantomSoundManager(_mixer, _soundFlag);
+
+ Phantom::phantom_main();
+
+ return Common::kNoError;
+}
+
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/phantom.h b/engines/mads/madsv2/phantom/phantom.h
new file mode 100644
index 00000000000..cc28853c4e1
--- /dev/null
+++ b/engines/mads/madsv2/phantom/phantom.h
@@ -0,0 +1,47 @@
+/* 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 MADS_PHANTOM_PHANTOM_H
+#define MADS_PHANTOM_PHANTOM_H
+
+#include "mads/madsv2/engine.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+
+class PhantomEngine : public MADSV2Engine {
+private:
+ bool _soundFlag = true;
+
+public:
+ PhantomEngine(OSystem *syst, const MADSGameDescription *gameDesc) :
+ MADSV2Engine(syst, gameDesc) {}
+ ~PhantomEngine() override {}
+
+ Common::Error run() override;
+};
+
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/metaengine.cpp b/engines/mads/metaengine.cpp
index e4d53c3b6e8..08f50828c88 100644
--- a/engines/mads/metaengine.cpp
+++ b/engines/mads/metaengine.cpp
@@ -40,7 +40,7 @@
#include "mads/core/game.h"
#include "mads/detection.h"
#ifdef ENABLE_MADSV2
-#include "mads/madsv2/engine.h"
+#include "mads/madsv2/phantom/phantom.h"
#endif
#define MAX_SAVES 99
@@ -204,7 +204,7 @@ bool MADS::MADSEngine::hasFeature(EngineFeature f) const {
Common::Error MADSMetaEngine::createInstance(OSystem *syst, Engine **engine, const MADS::MADSGameDescription *desc) const {
#ifdef ENABLE_MADSV2
if (desc->gameID == MADS::GType_Phantom)
- *engine = new MADS::MADSV2::MADSV2Engine(syst, desc);
+ *engine = new MADS::MADSV2::Phantom::PhantomEngine(syst, desc);
else
#endif
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index e42d5536124..e121f449030 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -121,6 +121,7 @@ MODULE_OBJS += \
madsv2/core/vocab.o \
madsv2/core/window.o \
madsv2/phantom/mads/mads.o \
+ madsv2/phantom/phantom.o \
madsv2/phantom/main_menu.o \
madsv2/phantom/main.o \
madsv2/phantom/sound_phantom.o
Commit: f6a1a4c0cf816c025d463264c50e0330fe4e6b31
https://github.com/scummvm/scummvm/commit/f6a1a4c0cf816c025d463264c50e0330fe4e6b31
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:21:22+10:00
Commit Message:
MADS: PHANTOM: Asound files md5 validation
Changed paths:
engines/mads/madsv2/phantom/phantom.cpp
engines/mads/madsv2/phantom/sound_phantom.cpp
engines/mads/nebular/nebular.cpp
diff --git a/engines/mads/madsv2/phantom/phantom.cpp b/engines/mads/madsv2/phantom/phantom.cpp
index d7d9a959d91..6eee4c8cd70 100644
--- a/engines/mads/madsv2/phantom/phantom.cpp
+++ b/engines/mads/madsv2/phantom/phantom.cpp
@@ -32,6 +32,7 @@ Common::Error PhantomEngine::run() {
initGraphics(320, 200);
_screen = new Graphics::Screen();
_soundManager = new PhantomSoundManager(_mixer, _soundFlag);
+ _soundManager->validate();
Phantom::phantom_main();
diff --git a/engines/mads/madsv2/phantom/sound_phantom.cpp b/engines/mads/madsv2/phantom/sound_phantom.cpp
index d21d872d30b..16c46926f31 100644
--- a/engines/mads/madsv2/phantom/sound_phantom.cpp
+++ b/engines/mads/madsv2/phantom/sound_phantom.cpp
@@ -20,6 +20,7 @@
*/
#include "common/md5.h"
+#include "common/textconsole.h"
#include "mads/madsv2/phantom/sound_phantom.h"
namespace MADS {
@@ -29,21 +30,21 @@ namespace Phantom {
void PhantomSoundManager::validate() {
Common::File f;
static const char *const MD5[] = {
- "205398468de2c8873b7d4d73d5be8ddc",
- "f9b2d944a2fb782b1af5c0ad592306d3",
- "7431f8dad77d6ddfc24e6f3c0c4ac7df",
- "eb1f3f5a4673d3e73d8ac1818c957cf4",
- "f936dd853073fa44f3daac512e91c476",
+ "8edcb79a8c3514eac0835496326a72ae",
+ "4b81a46440f8404d9eda1ce5ae2c5579",
+ "11d8d441e47ad1ccd8faafd6572a17d0",
+ "4cd5c4d45126e60ca701690489ab8afa",
+ "588357d711bbcdabdf7d7e5d96013ce5",
nullptr,
nullptr,
nullptr,
- "a31e4783e098f633cbb6689adb41dd4f"
+ "3d4843074c1dcbfd7919179c58aec9bc"
};
for (int i = 1; i <= 9; ++i) {
if (i >= 6 && i <= 8)
continue;
- Common::Path filename(Common::String::format("ASOUND.00%d", i));
+ Common::Path filename(Common::String::format("asound.ph%d", i));
if (!f.open(filename))
error("Could not process - %s", filename.toString().c_str());
Common::String md5str = Common::computeStreamMD5AsString(f, 8192);
@@ -92,7 +93,7 @@ int ASound1::command(int commandId, int param) {
/*-----------------------------------------------------------------------*/
-ASound2::ASound2(Audio::Mixer *mixer, OPL::OPL *opl) : ASound(mixer, opl, "asound.ph1", 0) {
+ASound2::ASound2(Audio::Mixer *mixer, OPL::OPL *opl) : ASound(mixer, opl, "asound.ph2", 0) {
}
int ASound2::command(int commandId, int param) {
@@ -102,7 +103,7 @@ int ASound2::command(int commandId, int param) {
/*-----------------------------------------------------------------------*/
-ASound3::ASound3(Audio::Mixer *mixer, OPL::OPL *opl) : ASound(mixer, opl, "asound.ph1", 0) {
+ASound3::ASound3(Audio::Mixer *mixer, OPL::OPL *opl) : ASound(mixer, opl, "asound.ph3", 0) {
}
int ASound3::command(int commandId, int param) {
@@ -112,7 +113,7 @@ int ASound3::command(int commandId, int param) {
/*-----------------------------------------------------------------------*/
-ASound4::ASound4(Audio::Mixer *mixer, OPL::OPL *opl) : ASound(mixer, opl, "asound.ph1", 0) {
+ASound4::ASound4(Audio::Mixer *mixer, OPL::OPL *opl) : ASound(mixer, opl, "asound.ph4", 0) {
}
int ASound4::command(int commandId, int param) {
@@ -122,7 +123,7 @@ int ASound4::command(int commandId, int param) {
/*-----------------------------------------------------------------------*/
-ASound5::ASound5(Audio::Mixer *mixer, OPL::OPL *opl) : ASound(mixer, opl, "asound.ph1", 0) {
+ASound5::ASound5(Audio::Mixer *mixer, OPL::OPL *opl) : ASound(mixer, opl, "asound.ph5", 0) {
}
int ASound5::command(int commandId, int param) {
@@ -132,7 +133,7 @@ int ASound5::command(int commandId, int param) {
/*-----------------------------------------------------------------------*/
-ASound9::ASound9(Audio::Mixer *mixer, OPL::OPL *opl) : ASound(mixer, opl, "asound.ph1", 0) {
+ASound9::ASound9(Audio::Mixer *mixer, OPL::OPL *opl) : ASound(mixer, opl, "asound.ph9", 0) {
}
int ASound9::command(int commandId, int param) {
diff --git a/engines/mads/nebular/nebular.cpp b/engines/mads/nebular/nebular.cpp
index cd8964fd1a6..7424e218df1 100644
--- a/engines/mads/nebular/nebular.cpp
+++ b/engines/mads/nebular/nebular.cpp
@@ -107,6 +107,7 @@ void RexNebularEngine::initialize() {
loadOptions();
+ _sound->validate();
_screen->clear();
}
Commit: f42abd58f57b1b568b04776dcdbb0cd79e0a0abf
https://github.com/scummvm/scummvm/commit/f42abd58f57b1b568b04776dcdbb0cd79e0a0abf
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:21:23+10:00
Commit Message:
MADS: PHANTOM: Skeleton command functions for ASound9 class
Changed paths:
engines/mads/madsv2/phantom/sound_phantom.cpp
engines/mads/madsv2/phantom/sound_phantom.h
diff --git a/engines/mads/madsv2/phantom/sound_phantom.cpp b/engines/mads/madsv2/phantom/sound_phantom.cpp
index 16c46926f31..629bf8b5072 100644
--- a/engines/mads/madsv2/phantom/sound_phantom.cpp
+++ b/engines/mads/madsv2/phantom/sound_phantom.cpp
@@ -133,11 +133,156 @@ int ASound5::command(int commandId, int param) {
/*-----------------------------------------------------------------------*/
+const ASound9::CommandPtr ASound9::_commandList[72] = {
+ &ASound9::command0, &ASound9::command1, &ASound9::command2, &ASound9::command3,
+ &ASound9::command4, &ASound9::command5, &ASound9::command6, &ASound9::command7,
+ &ASound9::command8, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr,
+ &ASound9::command16, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr,
+ &ASound9::command24, &ASound9::command25, &ASound9::command26, &ASound9::command27,
+ nullptr, nullptr, nullptr, nullptr,
+ &ASound9::command32, &ASound9::command33, &ASound9::command34, &ASound9::command35,
+ &ASound9::command36, &ASound9::command37, &ASound9::command38, &ASound9::command39,
+ nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr,
+ &ASound9::command64, &ASound9::command65, &ASound9::command66, &ASound9::command67,
+ &ASound9::command68, &ASound9::command69, &ASound9::command70, &ASound9::command71
+};
+
ASound9::ASound9(Audio::Mixer *mixer, OPL::OPL *opl) : ASound(mixer, opl, "asound.ph9", 0) {
}
int ASound9::command(int commandId, int param) {
- // TODO
+ if (commandId > 71 || !_commandList[commandId])
+ return 0;
+
+ _commandParam = param;
+ _frameCounter = 0;
+ return (this->*_commandList[commandId])();
+}
+
+int ASound9::command0() {
+ return 0;
+}
+
+int ASound9::command1() {
+ return 0;
+}
+
+int ASound9::command2() {
+ return 0;
+}
+
+int ASound9::command3() {
+ return 0;
+}
+
+int ASound9::command4() {
+ return 0;
+}
+
+int ASound9::command5() {
+ return 0;
+}
+
+int ASound9::command6() {
+ return 0;
+}
+
+int ASound9::command7() {
+ return 0;
+}
+
+int ASound9::command8() {
+ return 0;
+}
+
+int ASound9::command16() {
+ return 0;
+}
+
+int ASound9::command24() {
+ return 0;
+}
+
+int ASound9::command25() {
+ return 0;
+}
+
+int ASound9::command26() {
+ return 0;
+}
+
+int ASound9::command27() {
+ return 0;
+}
+
+int ASound9::command32() {
+ return 0;
+}
+
+int ASound9::command33() {
+ return 0;
+}
+
+int ASound9::command34() {
+ return 0;
+}
+
+int ASound9::command35() {
+ return 0;
+}
+
+int ASound9::command36() {
+ return 0;
+}
+
+int ASound9::command37() {
+ return 0;
+}
+
+int ASound9::command38() {
+ return 0;
+}
+
+int ASound9::command39() {
+ return 0;
+}
+
+int ASound9::command64() {
+ return 0;
+}
+
+int ASound9::command65() {
+ return 0;
+}
+
+int ASound9::command66() {
+ return 0;
+}
+
+int ASound9::command67() {
+ return 0;
+}
+
+int ASound9::command68() {
+ return 0;
+}
+
+int ASound9::command69() {
+ return 0;
+}
+
+int ASound9::command70() {
+ return 0;
+}
+
+int ASound9::command71() {
return 0;
}
diff --git a/engines/mads/madsv2/phantom/sound_phantom.h b/engines/mads/madsv2/phantom/sound_phantom.h
index 966e0dd9f99..e67ad88e08e 100644
--- a/engines/mads/madsv2/phantom/sound_phantom.h
+++ b/engines/mads/madsv2/phantom/sound_phantom.h
@@ -81,6 +81,47 @@ public:
};
class ASound9 : public ASound {
+private:
+ typedef int (ASound9:: *CommandPtr)();
+ int command0();
+ int command1();
+ int command2();
+ int command3();
+ int command4();
+ int command5();
+ int command6();
+ int command7();
+ int command8();
+
+ int command16() {
+ return command24();
+ }
+
+ int command24();
+ int command25();
+ int command26();
+ int command27();
+
+ int command32();
+ int command33();
+ int command34();
+ int command35();
+ int command36();
+ int command37();
+ int command38();
+ int command39();
+
+ int command64();
+ int command65();
+ int command66();
+ int command67();
+ int command68();
+ int command69();
+ int command70();
+ int command71();
+
+ static const CommandPtr _commandList[72];
+
public:
ASound9(Audio::Mixer *mixer, OPL::OPL *opl);
~ASound9() override {
Commit: 7e66f79f8c267b724612321e69b714cd122fe712
https://github.com/scummvm/scummvm/commit/7e66f79f8c267b724612321e69b714cd122fe712
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:21:23+10:00
Commit Message:
MADS: PHANTOM: Figure out data segment offsets for sound files
Changed paths:
engines/mads/madsv2/phantom/sound_phantom.cpp
diff --git a/engines/mads/madsv2/phantom/sound_phantom.cpp b/engines/mads/madsv2/phantom/sound_phantom.cpp
index 629bf8b5072..e74a9b9eb86 100644
--- a/engines/mads/madsv2/phantom/sound_phantom.cpp
+++ b/engines/mads/madsv2/phantom/sound_phantom.cpp
@@ -83,7 +83,7 @@ void PhantomSoundManager::loadDriver(int sectionNumber) {
/*-----------------------------------------------------------------------*/
-ASound1::ASound1(Audio::Mixer *mixer, OPL::OPL *opl) : ASound(mixer, opl, "asound.ph1", 0) {
+ASound1::ASound1(Audio::Mixer *mixer, OPL::OPL *opl) : ASound(mixer, opl, "asound.ph1", 0x21e0) {
}
int ASound1::command(int commandId, int param) {
@@ -93,7 +93,7 @@ int ASound1::command(int commandId, int param) {
/*-----------------------------------------------------------------------*/
-ASound2::ASound2(Audio::Mixer *mixer, OPL::OPL *opl) : ASound(mixer, opl, "asound.ph2", 0) {
+ASound2::ASound2(Audio::Mixer *mixer, OPL::OPL *opl) : ASound(mixer, opl, "asound.ph2", 0x2040) {
}
int ASound2::command(int commandId, int param) {
@@ -103,7 +103,7 @@ int ASound2::command(int commandId, int param) {
/*-----------------------------------------------------------------------*/
-ASound3::ASound3(Audio::Mixer *mixer, OPL::OPL *opl) : ASound(mixer, opl, "asound.ph3", 0) {
+ASound3::ASound3(Audio::Mixer *mixer, OPL::OPL *opl) : ASound(mixer, opl, "asound.ph3", 0x20c0) {
}
int ASound3::command(int commandId, int param) {
@@ -113,7 +113,7 @@ int ASound3::command(int commandId, int param) {
/*-----------------------------------------------------------------------*/
-ASound4::ASound4(Audio::Mixer *mixer, OPL::OPL *opl) : ASound(mixer, opl, "asound.ph4", 0) {
+ASound4::ASound4(Audio::Mixer *mixer, OPL::OPL *opl) : ASound(mixer, opl, "asound.ph4", 0x1f90) {
}
int ASound4::command(int commandId, int param) {
@@ -123,7 +123,7 @@ int ASound4::command(int commandId, int param) {
/*-----------------------------------------------------------------------*/
-ASound5::ASound5(Audio::Mixer *mixer, OPL::OPL *opl) : ASound(mixer, opl, "asound.ph5", 0) {
+ASound5::ASound5(Audio::Mixer *mixer, OPL::OPL *opl) : ASound(mixer, opl, "asound.ph5", 0x2140) {
}
int ASound5::command(int commandId, int param) {
@@ -154,7 +154,7 @@ const ASound9::CommandPtr ASound9::_commandList[72] = {
&ASound9::command68, &ASound9::command69, &ASound9::command70, &ASound9::command71
};
-ASound9::ASound9(Audio::Mixer *mixer, OPL::OPL *opl) : ASound(mixer, opl, "asound.ph9", 0) {
+ASound9::ASound9(Audio::Mixer *mixer, OPL::OPL *opl) : ASound(mixer, opl, "asound.ph9", 0x20c0) {
}
int ASound9::command(int commandId, int param) {
@@ -202,10 +202,6 @@ int ASound9::command8() {
return 0;
}
-int ASound9::command16() {
- return 0;
-}
-
int ASound9::command24() {
return 0;
}
Commit: c100027c44c7de16d4257a9a41b6616c806695fb
https://github.com/scummvm/scummvm/commit/c100027c44c7de16d4257a9a41b6616c806695fb
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:21:23+10:00
Commit Message:
MADS: PHANTOM: Claude implementation of ASound9
Changed paths:
engines/mads/madsv2/phantom/sound_phantom.cpp
diff --git a/engines/mads/madsv2/phantom/sound_phantom.cpp b/engines/mads/madsv2/phantom/sound_phantom.cpp
index e74a9b9eb86..43bd5fbf68f 100644
--- a/engines/mads/madsv2/phantom/sound_phantom.cpp
+++ b/engines/mads/madsv2/phantom/sound_phantom.cpp
@@ -166,119 +166,245 @@ int ASound9::command(int commandId, int param) {
return (this->*_commandList[commandId])();
}
+// commands 0-8 delegate to the base ASound implementations
int ASound9::command0() {
- return 0;
+ return ASound::command0();
}
-
int ASound9::command1() {
- return 0;
+ return ASound::command1();
}
-
int ASound9::command2() {
- return 0;
+ return ASound::command2();
}
-
int ASound9::command3() {
- return 0;
+ return ASound::command3();
}
-
int ASound9::command4() {
- return 0;
+ return ASound::command4();
}
-
int ASound9::command5() {
- return 0;
+ return ASound::command5();
}
-
int ASound9::command6() {
- return 0;
+ return ASound::command6();
}
-
int ASound9::command7() {
- return 0;
+ return ASound::command7();
}
-
int ASound9::command8() {
- return 0;
+ return ASound::command8();
}
+// ---------------------------------------------------------------------------
+// Commands 24-27 (asound_command offsets2, range 16-27)
+//
+// Each call to sub_1039C loads a sound into any available channel from the
+// upper three channels (6-8) first. cx holds a seg001-relative data offset;
+// the C++ loadData/playSound API takes the same value as the offset argument
+// (the base class adds _dataOffset when seeking the file).
+// ---------------------------------------------------------------------------
+
+// asound_command24: loads two percussion-style voices (chimes/bells) into
+// the upper channel pool.
int ASound9::command24() {
+ playSound(0x203E, 51); // cx = 0x203E
+ playSound(0x2071, 46); // cx = 0x2071
return 0;
}
+// asound_command25: two more upper-channel voices.
int ASound9::command25() {
+ playSound(0x209F, 44); // cx = 0x209F
+ playSound(0x20CB, 46); // cx = 0x20CB
return 0;
}
+// asound_command26: single upper-channel voice.
int ASound9::command26() {
+ playSound(0x20F9, 12); // cx = 0x20F9
return 0;
}
+// asound_command27: single upper-channel voice.
int ASound9::command27() {
+ playSound(0x2105, 81); // cx = 0x2105
return 0;
}
+// ---------------------------------------------------------------------------
+// Commands 32-39 (asound_command offsets3)
+//
+// Each command calls asound_command1 first (which calls both command3 and
+// command5, fading out channels 0-5 and 6-8 respectively), then loads new
+// sound data into specific channels via AdlibChannel_load0..8.
+//
+// asound_command32 and asound_command39 instead use AdlibChannel_loadAny
+// (sub_1039C / AdlibChannel_loadAny) which picks the first free channel.
+// ---------------------------------------------------------------------------
+
+// asound_command32: eight voices loaded into any available channels.
int ASound9::command32() {
+ playSound(0x2B16, 86);
+ playSound(0x2B6C, 74);
+ playSound(0x2BB6, 722);
+ playSound(0x2E88, 16);
+ playSound(0x2E98, 11);
+ playSound(0x2EA3, 11);
+ playSound(0x2EAE, 9);
+ playSound(0x2EB7, 15);
return 0;
}
+// asound_command33: no-op in the original (bare retn).
int ASound9::command33() {
return 0;
}
+// asound_command34: seven voices into channels 0-6, and a continuation
+// fragment into channel 7.
int ASound9::command34() {
+ _channels[0].load(loadData(0x31D0, 81));
+ _channels[1].load(loadData(0x3221, 97));
+ _channels[2].load(loadData(0x3282, 73));
+ _channels[3].load(loadData(0x32CB, 79));
+ _channels[4].load(loadData(0x331A, 79));
+ _channels[5].load(loadData(0x3369, 71));
+ _channels[6].load(loadData(0x33B0, 7));
+ _channels[7].load(loadData(0x33B7, 0)); // trailing fragment
return 0;
}
+// asound_command35: seven voices into channels 0-6.
int ASound9::command35() {
+ _channels[0].load(loadData(0x295E, 64));
+ _channels[1].load(loadData(0x299E, 37));
+ _channels[2].load(loadData(0x29C3, 37));
+ _channels[3].load(loadData(0x29E8, 94));
+ _channels[4].load(loadData(0x2A46, 95));
+ _channels[5].load(loadData(0x2AA5, 59));
+ _channels[6].load(loadData(0x2AE0, 0));
return 0;
}
+// asound_command36: six voices into channels 0-5.
int ASound9::command36() {
+ _channels[0].load(loadData(0x30AA, 51));
+ _channels[1].load(loadData(0x30DD, 44));
+ _channels[2].load(loadData(0x3109, 52));
+ _channels[3].load(loadData(0x313D, 56));
+ _channels[4].load(loadData(0x3175, 38));
+ _channels[5].load(loadData(0x319B, 0));
return 0;
}
+// asound_command37: seven voices into channels 0-6.
int ASound9::command37() {
+ _channels[0].load(loadData(0x2156, 80));
+ _channels[1].load(loadData(0x21A6, 232));
+ _channels[2].load(loadData(0x228E, 105));
+ _channels[3].load(loadData(0x22F7, 90));
+ _channels[4].load(loadData(0x2351, 599));
+ _channels[5].load(loadData(0x25A8, 791));
+ _channels[6].load(loadData(0x28BF, 0));
return 0;
}
+// asound_command38: eight voices into channels 0-7.
+// Preceded by asound_command1 (fade-out both banks).
int ASound9::command38() {
+ _channels[0].load(loadData(0x11BC, 699));
+ _channels[1].load(loadData(0x1477, 278));
+ _channels[2].load(loadData(0x158D, 490));
+ _channels[3].load(loadData(0x1777, 512));
+ _channels[4].load(loadData(0x1977, 590));
+ _channels[5].load(loadData(0x1BC5, 314));
+ _channels[6].load(loadData(0x1CFF, 432));
+ _channels[7].load(loadData(0x1EAF, 0));
return 0;
}
+// asound_command39: six voices loaded into channels 0-5 via AdlibChannel_load.
+// Preceded by asound_command0 (full reset), then specific channel loads.
int ASound9::command39() {
+ byte *pData = loadData(0x0C36, 0);
+ if (!isSoundActive(pData)) {
+ stop();
+ _channels[0].load(loadData(0x0C36, 311));
+ _channels[1].load(loadData(0x0D7D, 211));
+ _channels[2].load(loadData(0x0E50, 204));
+ _channels[3].load(loadData(0x0F1C, 178));
+ _channels[4].load(loadData(0x0FCE, 236));
+ _channels[5].load(loadData(0x10BA, 0));
+ }
return 0;
}
+// ---------------------------------------------------------------------------
+// Commands 64-71 (asound_command offsets4)
+//
+// Commands 64, 65, 68-71 use sub_1039C (loads into upper channels 6-8 first).
+// Commands 66 and 67 load explicitly named channels.
+// ---------------------------------------------------------------------------
+
+// asound_command64: single voice into upper channel pool.
int ASound9::command64() {
+ playSound(0x2EC6, 20); // cx = 0x2EC6
return 0;
}
+// asound_command65: single voice into upper channel pool.
int ASound9::command65() {
+ playSound(0x2EDA, 10); // cx = 0x2EDA
return 0;
}
+// asound_command66: eight voices into channels 0-7 in a repeating
+// four-voice pattern (0/1/2/3 mirrored onto 4/5/6, then 7 gets the 4th).
int ASound9::command66() {
+ _channels[0].load(loadData(0x2EE4, 42));
+ _channels[1].load(loadData(0x2F0E, 48));
+ _channels[2].load(loadData(0x2F3E, 48));
+ _channels[3].load(loadData(0x2F6E, 48));
+ _channels[4].load(loadData(0x2EE4, 42)); // mirrors channel 0
+ _channels[5].load(loadData(0x2F0E, 48)); // mirrors channel 1
+ _channels[6].load(loadData(0x2F3E, 48)); // mirrors channel 2
+ _channels[7].load(loadData(0x2F6E, 48)); // mirrors channel 3
return 0;
}
+// asound_command67: three voices into channels 6-8.
int ASound9::command67() {
+ _channels[6].load(loadData(0x2F9E, 31));
+ _channels[7].load(loadData(0x2FBD, 15));
+ _channels[8].load(loadData(0x2FCC, 31));
return 0;
}
+// asound_command68: single voice into upper channel pool.
int ASound9::command68() {
+ playSound(0x2FEB, 10); // cx = 0x2FEB
return 0;
}
+// asound_command69: three voices into upper channel pool.
int ASound9::command69() {
+ playSound(0x2FF5, 38); // cx = 0x2FF5
+ playSound(0x301B, 38); // cx = 0x301B
+ playSound(0x3041, 26); // cx = 0x3041
return 0;
}
+// asound_command70: two voices into upper channel pool.
int ASound9::command70() {
+ playSound(0x305B, 9); // cx = 0x305B
+ playSound(0x3064, 9); // cx = 0x3064
return 0;
}
+// asound_command71: two voices into upper channel pool.
int ASound9::command71() {
+ playSound(0x306D, 29); // cx = 0x306D
+ playSound(0x308A, 0); // cx = 0x308A
return 0;
}
Commit: 1a167ac273d881307fb8e908eed9cb7df5d42256
https://github.com/scummvm/scummvm/commit/1a167ac273d881307fb8e908eed9cb7df5d42256
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:21:24+10:00
Commit Message:
MADS: PHANTOM: Hooking up sound driver calls
Changed paths:
engines/mads/madsv2/core/kernel.cpp
engines/mads/madsv2/core/sound.cpp
engines/mads/madsv2/engine.h
diff --git a/engines/mads/madsv2/core/kernel.cpp b/engines/mads/madsv2/core/kernel.cpp
index 32546ea7fb5..3e28b260871 100644
--- a/engines/mads/madsv2/core/kernel.cpp
+++ b/engines/mads/madsv2/core/kernel.cpp
@@ -2582,6 +2582,13 @@ void kernel_unload_sound_driver() {
}
int kernel_load_sound_driver(const char *name, char sound_card_, int sound_board_address_, int sound_board_type_, int sound_board_irq_) {
+ // Get the section number from the end of the driver filename, and use it to initialize
+ // the sound system; we provide our own implementation of the drivers
+ int sectionNum = *(name + strlen(name) - 1) - '0';
+ assert((sectionNum >= 1 && sectionNum <= 5) || sectionNum == 9);
+
+ g_engine->_soundManager->init(sectionNum);
+
return 0;
}
diff --git a/engines/mads/madsv2/core/sound.cpp b/engines/mads/madsv2/core/sound.cpp
index cfcf05b4c52..a25e9087f38 100644
--- a/engines/mads/madsv2/core/sound.cpp
+++ b/engines/mads/madsv2/core/sound.cpp
@@ -21,16 +21,17 @@
#include "common/textconsole.h"
#include "mads/madsv2/core/sound.h"
+#include "mads/madsv2/engine.h"
namespace MADS {
namespace MADSV2 {
void sound_queue(int soundNum) {
- // TODO: sound_queue
+ g_engine->_soundManager->command(soundNum);
}
void sound_queue_flush() {
- // TODO: sound_queue_flush
+ g_engine->_soundManager->startQueuedCommands();
}
} // namespace MADSV2
diff --git a/engines/mads/madsv2/engine.h b/engines/mads/madsv2/engine.h
index 91ca2ee3bcd..a37acb371cb 100644
--- a/engines/mads/madsv2/engine.h
+++ b/engines/mads/madsv2/engine.h
@@ -36,12 +36,14 @@ namespace MADSV2 {
class MADSV2Engine : public MADSEngine {
protected:
Graphics::Screen *_screen = nullptr;
- MADS::SoundManager *_soundManager = nullptr;
Common::Stack<Common::Event> _keyEvents;
uint32 _nextFrameTime = 0;
void pollEvents();
+public:
+ MADS::SoundManager *_soundManager = nullptr;
+
public:
MADSV2Engine(OSystem *syst, const MADSGameDescription *gameDesc);
~MADSV2Engine() override;
Commit: 3d3a3e55688aacd72659d7832ea7323b3b5bd2b0
https://github.com/scummvm/scummvm/commit/3d3a3e55688aacd72659d7832ea7323b3b5bd2b0
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:36+10:00
Commit Message:
MADS: PHANTOM: Add Claude AI files to .gitignore
Changed paths:
.gitignore
diff --git a/.gitignore b/.gitignore
index 08c2b456fcf..001b99b495d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -308,3 +308,7 @@ __pycache__/
#Ignore vcpkg generated files
/vcpkg_installed/
+
+#Ignore Claude instruction files
+CLAUDE.md
+.claude
Commit: 837805ca4d061e67d663c7485ae6a95edfca4f50
https://github.com/scummvm/scummvm/commit/837805ca4d061e67d663c7485ae6a95edfca4f50
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:39+10:00
Commit Message:
MADS: PHANTOM: Added room 101
Changed paths:
A engines/mads/madsv2/phantom/conv.cpp
A engines/mads/madsv2/phantom/conv.h
A engines/mads/madsv2/phantom/global.h
A engines/mads/madsv2/phantom/mads/text.h
A engines/mads/madsv2/phantom/mads/words.h
A engines/mads/madsv2/phantom/rooms/room101.cpp
A engines/mads/madsv2/phantom/rooms/room101.h
A engines/mads/madsv2/phantom/rooms/section1.cpp
A engines/mads/madsv2/phantom/rooms/section1.h
engines/mads/madsv2/core/vocabh.h
engines/mads/module.mk
diff --git a/engines/mads/madsv2/core/vocabh.h b/engines/mads/madsv2/core/vocabh.h
index 2ebd96c4a8a..1e61eb60590 100644
--- a/engines/mads/madsv2/core/vocabh.h
+++ b/engines/mads/madsv2/core/vocabh.h
@@ -28,20 +28,21 @@ namespace MADS {
namespace MADSV2 {
/* Hardcoded vocabulary words */
-
-#define words_game 1
-#define words_qsave 2
-#define words_look 3
-#define words_take 4
-#define words_push 5
-#define words_open 6
-#define words_put 7
-#define words_talk_to 8
-#define words_give 9
-#define words_pull 10
-#define words_close 11
-#define words_throw 12
-#define words_walk_to 13
+enum {
+ words_game = 1,
+ words_qsave = 2,
+ words_look = 3,
+ words_take = 4,
+ words_push = 5,
+ words_open = 6,
+ words_put = 7,
+ words_talk_to = 8,
+ words_give = 9,
+ words_pull = 10,
+ words_close = 11,
+ words_throw = 12,
+ words_walk_to = 13
+};
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/conv.cpp b/engines/mads/madsv2/phantom/conv.cpp
new file mode 100644
index 00000000000..f6a396283f9
--- /dev/null
+++ b/engines/mads/madsv2/phantom/conv.cpp
@@ -0,0 +1,98 @@
+/* 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/algorithm.h"
+#include "common/str.h"
+#include "mads/madsv2/phantom/conv.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+
+int conv_restore_running;
+ConvControl conv_control;
+
+
+constexpr int CONV_MAX_SLOTS = 40;
+constexpr int CONV_MAX_DATA = 5;
+
+static int conv_slot_indexes[CONV_MAX_SLOTS];
+static int conv_slots[CONV_MAX_DATA];
+static int conv_data[CONV_MAX_DATA];
+static int conv_conditions[CONV_MAX_DATA];
+
+
+static const char *conv_get_filename(int convNum, int extType, char *name) {
+ *name = '\0';
+
+ if (extType != 2)
+ Common::strcat_s(name, 40, "*");
+ Common::strcat_s(name, 40, "conv");
+ Common::strcat_s(name, 40, Common::String::format("%d", convNum).c_str());
+ if (extType == 2)
+ Common::strcat_s(name, 40, ".dat");
+
+ return name;
+}
+
+static ConvData *conv_load_data(const char *fname) {
+ // TODO
+ return nullptr;
+}
+
+
+void conv_system_init() {
+ Common::fill(conv_slot_indexes, conv_slot_indexes + CONV_MAX_SLOTS, 0);
+ Common::fill(conv_slots, conv_slots + CONV_MAX_DATA, 0);
+ Common::fill(conv_data, conv_data + CONV_MAX_DATA, 0);
+ Common::fill(conv_conditions, conv_conditions + CONV_MAX_DATA, 0);
+ conv_system_cleanup();
+}
+
+void conv_system_cleanup() {
+ // Removes any files with the format 'conv%d.dat'
+}
+
+void conv_get(int convNum) {
+ int free_slot = -1;
+ char fname[40];
+
+ for (int i = 0; i < CONV_MAX_DATA && free_slot == -1; ++i) {
+ if (!conv_slots[i])
+ free_slot = i;
+ }
+
+ if (free_slot >= 0) {
+ conv_slots[free_slot] = -1;
+ (void)conv_load_data(conv_get_filename(convNum, 0, fname));
+ // TODO: More stuff
+ }
+}
+
+void conv_run(int convNum) {}
+void conv_export_pointer(int *ptr) {}
+void conv_abort() {}
+void conv_me_trigger(int trigger) {}
+void conv_you_trigger(int trigger) {}
+
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/conv.h b/engines/mads/madsv2/phantom/conv.h
new file mode 100644
index 00000000000..8770c437db6
--- /dev/null
+++ b/engines/mads/madsv2/phantom/conv.h
@@ -0,0 +1,75 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef MADS_PHANTOM_CONV_H
+#define MADS_PHANTOM_CONV_H
+
+#include "common/scummsys.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+
+struct ConvData {
+ int16 node_count;
+ int16 dialog_count;
+ int16 message_count;
+ int16 text_line_count;
+ int16 num_variables;
+
+ int16 max_imports;
+ int16 speaker_count;
+ char speaker_portraits[5][16];
+ int16 speaker_frame[5];
+ char speech_file[14];
+ uint32 text_length;
+
+ uint32 commands_length;
+ void *text_ptr;
+ void *scripts_ptr;
+ void *nodes_ptr;
+ void *dialogs_ptr;
+ void *messages_ptr;
+ void *text_lines_ptr;
+};
+
+struct ConvControl {
+ int running;
+};
+
+extern int conv_restore_running;
+extern ConvControl conv_control;
+
+extern void conv_system_init();
+extern void conv_system_cleanup();
+
+extern void conv_get(int convNum);
+extern void conv_run(int convNum);
+extern void conv_export_pointer(int *ptr);
+extern void conv_abort();
+extern void conv_me_trigger(int trigger);
+extern void conv_you_trigger(int trigger);
+
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/phantom/global.h b/engines/mads/madsv2/phantom/global.h
new file mode 100644
index 00000000000..594cedc0a99
--- /dev/null
+++ b/engines/mads/madsv2/phantom/global.h
@@ -0,0 +1,71 @@
+/* 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 MADS_PHANTOM_GLOBAL_H
+#define MADS_PHANTOM_GLOBAL_H
+
+#include "mads/madsv2/core/vocabh.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+
+enum {
+ conv001_speech_talk = 0,
+ conv001_continue_abc = 1,
+ conv001_what_one = 4,
+ conv001_yesno_yes = 8,
+ conv001_everything_byebye = 10,
+ conv001_everything_copycat = 12,
+ conv001_speak_byebye = 18,
+ conv001_saytwo_1 = 22,
+ conv001_instructions_three = 24,
+ conv001_point_two_abc = 27
+};
+
+
+// Global indices
+#define walker_converse 4
+#define current_year 10
+#define brie_talk_status 24
+#define jacques_status 31
+
+// brie_talk_status values
+#define BEFORE_BRIE_MOTIONS 0
+#define BEFORE_CHANDELIER_CONV 1
+#define AFTER_CONVS_0_AND_1 2
+
+// jacques_status values
+#define JACQUES_IS_DEAD 1
+#define JACQUES_IS_DEAD_RICH_GONE 2
+
+// walker_converse values
+#define CONVERSE_NONE 0
+#define CONVERSE_LEAN 1
+#define CONVERSE_HAND_WAVE 2
+#define CONVERSE_HAND_WAVE_2 3
+#define CONVERSE_HAND_CHIN 4
+
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/phantom/mads/text.h b/engines/mads/madsv2/phantom/mads/text.h
new file mode 100644
index 00000000000..b8083c48e89
--- /dev/null
+++ b/engines/mads/madsv2/phantom/mads/text.h
@@ -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/>.
+ *
+ */
+
+#ifndef MADS_PHANTOM_MADS_TEXT_H
+#define MADS_PHANTOM_MADS_TEXT_H
+
+#include "common/scummsys.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+
+enum {
+ text_101_10 = 10110,
+ text_101_11 = 10111,
+ text_101_12 = 10112,
+ text_101_13 = 10113,
+ text_101_14 = 10114,
+ text_101_15 = 10115,
+ text_101_16 = 10116,
+ text_101_17 = 10117,
+ text_101_18 = 10118,
+ text_101_19 = 10119,
+ text_101_20 = 10120,
+ text_101_21 = 10121,
+ text_101_22 = 10122
+};
+
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/phantom/mads/words.h b/engines/mads/madsv2/phantom/mads/words.h
new file mode 100644
index 00000000000..a378cf8ad7b
--- /dev/null
+++ b/engines/mads/madsv2/phantom/mads/words.h
@@ -0,0 +1,48 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef MADS_PHANTOM_MADS_SPEECHES_H
+#define MADS_PHANTOM_MADS_SPEECHES_H
+
+#include "common/scummsys.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+
+enum {
+ words_aisle = 18,
+ words_exit_to = 55,
+ words_look_at = 96,
+ words_orchestra_pit = 108,
+ words_seats = 129,
+ words_side_wall = 130,
+ words_grand_foyer = 180,
+ words_back_wall = 181,
+ words_chandelier = 201,
+ words_Monsieur_Brie = 258
+};
+
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/phantom/rooms/room101.cpp b/engines/mads/madsv2/phantom/rooms/room101.cpp
new file mode 100644
index 00000000000..c7947eb908b
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room101.cpp
@@ -0,0 +1,644 @@
+/* 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 "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/phantom/mads/words.h"
+#include "mads/madsv2/phantom/rooms/section1.h"
+#include "mads/madsv2/phantom/rooms/room101.h"
+#include "mads/madsv2/phantom/conv.h"
+#include "mads/madsv2/core/imath.h"
+#include "mads/madsv2/core/camera.h"
+#include "mads/madsv2/core/matte.h"
+#include "mads/madsv2/core/text.h"
+#include "mads/madsv2/core/inter.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+void room_101_init(void) {
+ kernel.disable_fastwalk = true;
+
+ if (previous_room != KERNEL_RESTORING_GAME) {
+ local->execute_chan = RESET;
+ local->execute_wipe = RESET;
+ local->start_walking = false;
+ local->start_walking_0 = false;
+ local->anim_0_running = false;
+ local->anim_0_running = true;
+
+ /* ======== When false, camera hasn't panned past 208 ======== */
+ local->start_sitting_down = false;
+ }
+
+
+ /* =================== Load conversations ==================== */
+
+ conv_get(CONV_BRIE_MOTIONS_TO_RAOUL);
+ conv_get(CONV_BRIE_BY_CHANDELIER);
+
+
+ /* =================== Load sprite series ==================== */
+ /* =========== If in 1993, put crashed chandelier ============ */
+
+ if (global[current_year] == 1993) {
+ ss[fx_chandelier] = kernel_load_series(kernel_name('z', -1), false);
+ seq[fx_chandelier] = kernel_seq_stamp(ss[fx_chandelier], false, 1);
+ kernel_seq_depth(seq[fx_chandelier], 14);
+ } else {
+ kernel_flip_hotspot(words_chandelier, false);
+ }
+
+
+ /* ================ Run anims & set up dynamic =============== */
+
+ if (global[brie_talk_status] == BEFORE_BRIE_MOTIONS) {
+ player_first_walk(OFF_SCREEN_X_FROM_202, OFF_SCREEN_Y_FROM_202, FACING_EAST,
+ PLAYER_X_FROM_202, PLAYER_Y_FROM_202, FACING_EAST, true);
+
+ local->brie_calling_position = CONV0_BRIE_ARMS_AT_SIDE;
+
+ local->brie_chandelier_position = CONV1_BRIE_SHOULD_FREEZE_STAND;
+
+ player_walk_trigger(ROOM_101_START_CONV_MOTIONS);
+
+ aa[1] = kernel_run_animation(kernel_name('b', 9), 1);
+ aa[0] = kernel_run_animation(kernel_name('b', 8), 1);
+
+ local->anim_0_running = true;
+ local->anim_1_running = true;
+
+ local->dynamic_brie = kernel_add_dynamic(words_Monsieur_Brie, words_walk_to, SYNTAX_SINGULAR_MASC, KERNEL_NONE,
+ 0, 0, 0, 0);
+ kernel_dynamic_hot[local->dynamic_brie].prep = PREP_ON;
+ kernel_dynamic_walk(local->dynamic_brie, DYNAMIC_BRIE_WALK_TO_X, DYNAMIC_BRIE_WALK_TO_Y, 5);
+ kernel_dynamic_anim(local->dynamic_brie, aa[0], 0);
+ kernel_dynamic_anim(local->dynamic_brie, aa[0], 1);
+ kernel_dynamic_anim(local->dynamic_brie, aa[0], 2);
+ kernel_dynamic_anim(local->dynamic_brie, aa[0], 3);
+ kernel_dynamic_anim(local->dynamic_brie, aa[0], 4);
+
+ local->dynamic_brie_2 = kernel_add_dynamic(words_Monsieur_Brie, words_walk_to, SYNTAX_SINGULAR_MASC, KERNEL_NONE,
+ 0, 0, 0, 0);
+ kernel_dynamic_hot[local->dynamic_brie_2].prep = PREP_ON;
+ kernel_dynamic_walk(local->dynamic_brie_2, DYN_BRIE_1_WALK_TO_X, DYN_BRIE_1_WALK_TO_Y, 5);
+ kernel_dynamic_anim(local->dynamic_brie_2, aa[1], 1);
+ kernel_dynamic_anim(local->dynamic_brie_2, aa[1], 2);
+
+ local->talk_count = 0;
+
+ } else if (global[brie_talk_status] == BEFORE_CHANDELIER_CONV) {
+ aa[1] = kernel_run_animation(kernel_name('b', 9), 1);
+ local->dynamic_brie = kernel_add_dynamic(words_Monsieur_Brie, words_walk_to, SYNTAX_SINGULAR_MASC, KERNEL_NONE,
+ 0, 0, 0, 0);
+ kernel_dynamic_hot[local->dynamic_brie].prep = PREP_ON;
+ kernel_dynamic_anim(local->dynamic_brie, aa[1], 1);
+ kernel_dynamic_anim(local->dynamic_brie, aa[1], 2);
+ local->anim_1_running = true;
+ local->talk_count = 0;
+ local->brie_chandelier_position = CONV1_BRIE_SHOULD_FREEZE_STAND;
+
+ /* ============= If restoring into conv, run it ============== */
+
+ if (conv_restore_running == CONV_BRIE_BY_CHANDELIER) {
+ conv_run(CONV_BRIE_BY_CHANDELIER);
+ conv_export_pointer(&global[player_score]);
+ local->brie_chandelier_position = CONV1_BRIE_SHOULD_FREEZE_SIT;
+ kernel_reset_animation(aa[1], 25); /* the sitting position */
+ }
+
+
+ } else {
+
+ /* ======================= Previous Rooms ==================== */
+
+ if (previous_room == 202) {
+ if (global[jacques_status] == JACQUES_IS_DEAD) {
+ global[jacques_status] = JACQUES_IS_DEAD_RICH_GONE;
+ }
+ player_first_walk(OFF_SCREEN_X_FROM_202, OFF_SCREEN_Y_FROM_202, FACING_EAST,
+ PLAYER_X_FROM_202, PLAYER_Y_FROM_202, FACING_EAST, true);
+
+ } else if ((previous_room == 102) || (previous_room != KERNEL_RESTORING_GAME)) {
+ player_first_walk(OFF_SCREEN_X_FROM_102, OFF_SCREEN_Y_FROM_102, FACING_WEST,
+ PLAYER_X_FROM_102, PLAYER_Y_FROM_102, FACING_WEST, true);
+ camera_jump_to(RIGHT_HALF, 0);
+ }
+ }
+
+ section_1_music();
+}
+
+
+static void handle_animation_000(void) {
+ int random;
+ int reset_frame;
+
+ if (kernel_anim[aa[0]].frame != local->brie_calling_frame) {
+ local->brie_calling_frame = kernel_anim[aa[0]].frame;
+ reset_frame = -1;
+ switch (local->brie_calling_frame) {
+
+ /* Choices while Brie has his hand up */
+
+ case 1: /* end of arms at side */
+ case 9: /* end of TALK_1 */
+ case 12: /* end of TALK_2 */
+
+ if (local->brie_calling_position == CONV0_BRIE_RAISING_ARMS) {
+ if (local->brie_calling_frame == 9) {
+ if (local->start_walking_0) {
+ reset_frame = 13; /* start CALLING_TURN_AND_WALK */
+ local->brie_calling_position = CONV0_BRIE_SHOULD_WALK;
+ } else {
+ local->brie_calling_position = CONV0_BRIE_SHOULD_TALK;
+ }
+ } else {
+ reset_frame = 1;
+ }
+ }
+
+ if (local->brie_calling_position == CONV0_BRIE_ARMS_AT_SIDE) {
+ if (local->start_walking_0) {
+ reset_frame = 60; /* start to turn around */
+ local->brie_calling_position = CONV0_BRIE_SHOULD_WALK;
+ } else {
+ reset_frame = 0;
+ }
+ }
+
+ if (local->brie_calling_position == CONV0_BRIE_SHOULD_TALK) {
+
+ if (local->start_walking_0) {
+ reset_frame = 13; /* start CALLING_TURN_AND_WALK */
+ local->brie_calling_position = CONV0_BRIE_SHOULD_WALK;
+
+ } else {
+ random = imath_random(1, 2); /* between TALK_1 and TALK_2 */
+ ++local->talk_count; /* run through so many talk cycles */
+ /* before putting arms down to side */
+ if (local->talk_count < 18) {
+ if (random == 1) {
+ reset_frame = 7; /* start TALK_1 */
+ } else {
+ reset_frame = 10; /* start TALK_2 */
+ }
+ } else {
+ reset_frame = 54; /* put arms down at side */
+ local->brie_calling_position = CONV0_BRIE_ARMS_AT_SIDE;
+ }
+ }
+ }
+ break;
+
+ case 53: /* end of CALLING_TURN_AND_WALK */
+ local->anim_0_running = false;
+ kernel_abort_animation(aa[0]);
+ break;
+
+ case 59:
+ if (local->start_walking_0) {
+ reset_frame = 60; /* start to turn */
+ local->brie_calling_position = CONV0_BRIE_SHOULD_WALK;
+ } else {
+ reset_frame = 0; /* keep Brie standing still */
+ local->brie_calling_position = CONV0_BRIE_ARMS_AT_SIDE;
+ }
+ break;
+
+ case 66:
+ reset_frame = 24; /* make Brie walk off of screen */
+ break;
+ }
+
+ if (reset_frame >= 0) {
+ kernel_reset_animation(aa[0], reset_frame);
+ local->brie_calling_frame = reset_frame;
+ }
+ }
+}
+
+
+
+static void handle_animation_001(void) {
+ int random;
+ int reset_frame;
+
+ if (kernel_anim[aa[1]].frame != local->brie_chandelier_frame) {
+ local->brie_chandelier_frame = kernel_anim[aa[1]].frame;
+ reset_frame = -1;
+ switch (local->brie_chandelier_frame) {
+
+ /* Choices while Brie is sitting on armrest */
+
+ case 1: /* end of freezing in standing position */
+ if (local->brie_chandelier_position == CONV1_BRIE_SHOULD_FREEZE_STAND) {
+ reset_frame = 0; /* stick BRIE in the standing still position */
+ }
+ break;
+
+ case 11: /* end of sitting down on armrest */
+ case 14: /* end of TALK_1 */
+ case 17: /* end of TALK_2 */
+ case 19: /* end of TALK_3 */
+ case 26: /* end of raising hands and sitting still frame */
+ case 44: /* end of motioning to chandelier */
+ case 333: /* end of wiping forehead */
+
+ if (local->talk_count == local->execute_chan) {
+ local->brie_chandelier_position = CONV1_BRIE_SHOULD_MOTION_CHAN;
+ ++local->talk_count;
+ local->execute_chan = RESET;
+ }
+
+ if (local->talk_count == local->execute_wipe) {
+ local->brie_chandelier_position = CONV1_BRIE_SHOULD_WIPE;
+ ++local->talk_count;
+ local->execute_wipe = RESET;
+ }
+
+ if (local->start_walking) {
+ if (conv_control.running == CONV_BRIE_BY_CHANDELIER) {
+ if (local->talk_count > 13) {
+ local->brie_chandelier_position = CONV1_BRIE_SHOULD_WALK;
+ }
+ } else {
+ local->brie_chandelier_position = CONV1_BRIE_SHOULD_WALK;
+ }
+ }
+
+ switch (local->brie_chandelier_position) {
+
+ case CONV1_BRIE_SHOULD_TALK:
+ random = imath_random(1, 3); /* between 4 talking movements */
+ ++local->talk_count; /* run through so many talk cycles */
+ /* before putting arms down to side */
+ if (local->talk_count < 15) {
+ if (random == 1) {
+ reset_frame = 12; /* start TALK_1 */
+ } else if (random == 2) {
+ reset_frame = 14; /* start TALK_2 */
+ } else if (random == 3) {
+ reset_frame = 17; /* start TALK_3 */
+ }
+ } else {
+ local->brie_chandelier_position = CONV1_BRIE_SHOULD_FREEZE_SIT;
+ reset_frame = 25;
+ }
+ break;
+
+ case CONV1_BRIE_SHOULD_WALK:
+ global[brie_talk_status] = AFTER_CONVS_0_AND_1;
+ reset_frame = 45; /* start walking away */
+ if (conv_control.running == CONV_BRIE_BY_CHANDELIER) {
+ conv_abort(); /* so the player.commands_allowed = false */
+ /* that is to follow doesn't screw up conversation */
+ }
+ kernel_delete_dynamic(local->dynamic_brie);
+ player.commands_allowed = false;
+ break;
+
+ case CONV1_BRIE_SHOULD_MOTION_CHAN:
+ reset_frame = 27; /* start to motion to chandelier */
+ local->brie_chandelier_position = CONV1_BRIE_SHOULD_TALK;
+ break;
+
+ case CONV1_BRIE_SHOULD_WIPE:
+ reset_frame = 316; /* start to motion to wipe forehead */
+ local->brie_chandelier_position = CONV1_BRIE_SHOULD_TALK;
+ break;
+
+ case CONV1_BRIE_SHOULD_RAISE_HANDS:
+ reset_frame = 21; /* raise hands like 'I dunno' or */
+ /* more like 'are you stupid?' */
+ local->brie_chandelier_position = CONV1_BRIE_SHOULD_TALK;
+ break;
+
+ case CONV1_BRIE_SHOULD_FREEZE_SIT:
+ reset_frame = 25; /* stick BRIE in the sitting still position */
+ break;
+ }
+ break;
+
+ case 315: /* end of CALLING_TURN_AND_WALK */
+ /* global[brie_talk_status] = AFTER_CONVS_0_AND_1; */
+ kernel_abort_animation(aa[1]);
+ break;
+ }
+
+ if (reset_frame >= 0) {
+ kernel_reset_animation(aa[1], reset_frame);
+ local->brie_chandelier_frame = reset_frame;
+ }
+ }
+}
+
+
+
+
+void room_101_daemon(void) {
+ /* =============== Goto conversation functions =============== */
+
+ if (local->anim_0_running) {
+ handle_animation_000();
+ }
+
+ if ((global[walker_converse] == CONVERSE_HAND_WAVE) ||
+ (global[walker_converse] == CONVERSE_HAND_WAVE_2)) {
+ ++local->converse_counter;
+ if (local->converse_counter > 200) {
+ global[walker_converse] = imath_random(CONVERSE_LEAN, CONVERSE_HAND_CHIN);
+ }
+ }
+
+ if (local->anim_1_running) {
+ handle_animation_001();
+ /* ====== Turn on commands if Brie has walked past Raoul ===== */
+
+ if (kernel_anim[aa[1]].frame == 80) {
+ player.commands_allowed = true;
+ player_walk_trigger(ROOM_101_START_CONV_CHAN);
+ }
+ }
+
+
+ /* ========== Check camera - to make Brie sit down =========== */
+
+ if ((picture_view_x > 200) && (local->start_sitting_down == false) &&
+ (global[brie_talk_status] != AFTER_CONVS_0_AND_1)) {
+ local->start_sitting_down = true;
+ player_walk(DYNAMIC_BRIE_WALK_TO_X, DYNAMIC_BRIE_WALK_TO_Y, FACING_NORTHEAST);
+ player.commands_allowed = false;
+ player_walk_trigger(ROOM_101_START_CONV_CHAN);
+ local->brie_chandelier_position = CONV1_BRIE_SHOULD_FREEZE_SIT;
+ }
+
+
+ /* ============ Once I get to Brie, start conv 1 ============= */
+
+ if (kernel.trigger == ROOM_101_START_CONV_CHAN) {
+ player.commands_allowed = true;
+ conv_run(CONV_BRIE_BY_CHANDELIER);
+ conv_export_pointer(&global[player_score]);
+ local->brie_chandelier_frame = RESET;
+ local->talk_count = 0;
+ }
+
+
+ /* ====== When Raoul walks from off-screen, start conv ======= */
+
+ if (kernel.trigger == ROOM_101_START_CONV_MOTIONS) {
+ conv_run(CONV_BRIE_MOTIONS_TO_RAOUL);
+ local->brie_calling_position = CONV0_BRIE_RAISING_ARMS;
+ }
+}
+
+static void process_conversation_0(void) {
+ conv_me_trigger(ROOM_101_CONV0_MAKE_BRIE_WALK);
+
+ if (kernel.trigger == ROOM_101_CONV0_MAKE_BRIE_WALK) {
+ global[brie_talk_status] = BEFORE_CHANDELIER_CONV;
+ local->start_walking_0 = true;
+ }
+}
+
+
+
+static void process_conversation_1(void) {
+ int you_trig_flag = false;
+
+ if ((player_verb >= conv001_speech_talk) &&
+ (player_verb <= conv001_point_two_abc)) {
+
+ if (kernel.trigger == ROOM_101_BRIE_START_TALKING) {
+ switch (player_verb) {
+ case conv001_speech_talk:
+ local->brie_chandelier_position = CONV1_BRIE_SHOULD_WIPE;
+ local->execute_wipe = 2;
+ break;
+
+ case conv001_continue_abc:
+ local->brie_chandelier_position = CONV1_BRIE_SHOULD_TALK;
+ local->execute_chan = 9; /* on talk_count #9, motion to chandelier */
+ break;
+
+ case conv001_what_one:
+ local->brie_chandelier_position = CONV1_BRIE_SHOULD_MOTION_CHAN;
+ local->execute_chan = RESET;
+ local->execute_wipe = RESET;
+ break;
+
+ case conv001_everything_copycat:
+ local->brie_chandelier_position = CONV1_BRIE_SHOULD_RAISE_HANDS;
+ local->execute_chan = RESET;
+ local->execute_wipe = RESET;
+ break;
+
+ case conv001_yesno_yes:
+ case conv001_everything_byebye:
+ case conv001_speak_byebye:
+ case conv001_saytwo_1:
+ case conv001_instructions_three:
+ local->start_walking = true;
+ local->execute_chan = RESET;
+ local->execute_wipe = RESET;
+ global[walker_converse] = CONVERSE_NONE;
+ conv_you_trigger(ROOM_101_STOP_CONVERSING);
+ you_trig_flag = true;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (!you_trig_flag) {
+ conv_you_trigger(ROOM_101_BRIE_START_TALKING);
+ }
+
+ conv_me_trigger(ROOM_101_BRIE_STOP_TALKING);
+
+ local->talk_count = 0;
+
+ if (kernel.trigger == ROOM_101_BRIE_START_TALKING) {
+ if (!local->start_walking) {
+ global[walker_converse] = imath_random(CONVERSE_LEAN, CONVERSE_HAND_CHIN);
+ }
+ local->brie_chandelier_position = CONV1_BRIE_SHOULD_TALK;
+ } else if (kernel.trigger == ROOM_101_BRIE_STOP_TALKING) {
+ if (local->start_walking == false) {
+ local->brie_chandelier_position = CONV1_BRIE_SHOULD_FREEZE_SIT;
+ local->execute_chan = RESET;
+ local->execute_wipe = RESET;
+ if (!local->start_walking) {
+ global[walker_converse] = imath_random(CONVERSE_HAND_WAVE, CONVERSE_HAND_WAVE_2);
+ }
+ local->converse_counter = 0;
+ }
+ }
+ }
+}
+
+
+
+void room_101_pre_parser(void) {
+ if (player_said_2(exit_to, orchestra_pit)) {
+ if ((global[brie_talk_status] == AFTER_CONVS_0_AND_1) || (local->start_walking)) {
+ player.walk_off_edge_to_room = 102;
+ global[brie_talk_status] = AFTER_CONVS_0_AND_1;
+ } else {
+ conv_run(CONV_BRIE_MOTIONS_TO_RAOUL);
+ player.need_to_walk = false;
+ }
+ }
+
+ if (player_said_2(exit_to, grand_foyer)) {
+ if ((global[brie_talk_status] == AFTER_CONVS_0_AND_1) || (local->start_walking)) {
+ player.walk_off_edge_to_room = 202;
+ } else {
+ conv_run(CONV_BRIE_MOTIONS_TO_RAOUL);
+ player.need_to_walk = false;
+ }
+ }
+
+ if (player_said_2(take, Monsieur_Brie)) {
+ text_show(text_101_21);
+ }
+
+ if (player_said_2(talk_to, Monsieur_Brie)) {
+ if (global[brie_talk_status] == AFTER_CONVS_0_AND_1) {
+ player.need_to_walk = false;
+ }
+ }
+}
+
+
+void room_101_parser(void) {
+ if (conv_control.running == CONV_BRIE_MOTIONS_TO_RAOUL) {
+ process_conversation_0();
+ goto handled;
+ }
+
+ if (conv_control.running == CONV_BRIE_BY_CHANDELIER) {
+ process_conversation_1();
+ goto handled;
+ }
+
+ if (player.look_around) {
+ if (global[current_year] == 1993) {
+ text_show(text_101_10);
+ } else {
+ text_show(text_101_11);
+ }
+ goto handled;
+ }
+
+ if (player_said_1(look) || player_said_1(look_at)) {
+
+ if (player_said_1(aisle)) {
+ text_show(text_101_12);
+ goto handled;
+ }
+
+ if (player_said_1(chandelier)) {
+ text_show(text_101_13);
+ goto handled;
+ }
+
+ if (player_said_1(back_wall)) {
+ text_show(text_101_14);
+ goto handled;
+ }
+
+ if (player_said_1(side_wall)) {
+ text_show(text_101_15);
+ goto handled;
+ }
+
+ if (player_said_1(seats)) {
+ if (global[current_year] == 1881) {
+ text_show(text_101_16);
+ } else {
+ if ((global[brie_talk_status] > BEFORE_CHANDELIER_CONV) ||
+ (local->start_walking)) {
+ text_show(text_101_19);
+ } else {
+ text_show(text_101_16);
+ }
+ }
+ goto handled;
+ }
+
+ if (player_said_1(grand_foyer)) {
+ text_show(text_101_17);
+ goto handled;
+ }
+
+ if (player_said_1(orchestra_pit)) {
+ text_show(text_101_18);
+ goto handled;
+ }
+
+ if (player_said_1(Monsieur_Brie)) {
+ text_show(text_101_20);
+ goto handled;
+ }
+ }
+
+
+ if (player_said_2(talk_to, Monsieur_Brie)) {
+ if (global[brie_talk_status] == AFTER_CONVS_0_AND_1) {
+ text_show(text_101_22);
+ }
+ goto handled;
+ }
+
+ if (player_said_2(take, Monsieur_Brie)) {
+ goto handled;
+ }
+
+ goto done;
+
+handled:
+ player.command_ready = false;
+
+done:
+ ;
+}
+
+void room_101_preload(void) {
+ room_init_code_pointer = room_101_init;
+ room_pre_parser_code_pointer = room_101_pre_parser;
+ room_parser_code_pointer = room_101_parser;
+ room_daemon_code_pointer = room_101_daemon;
+
+ section_1_walker();
+ section_1_interface();
+
+ vocab_make_active(words_Monsieur_Brie);
+}
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/rooms/room101.h b/engines/mads/madsv2/phantom/rooms/room101.h
new file mode 100644
index 00000000000..4c50e5a7399
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room101.h
@@ -0,0 +1,128 @@
+/* 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 MADS_PHANTOM_ROOMS_101_H
+#define MADS_PHANTOM_ROOMS_101_H
+
+#include "mads/madsv2/core/general.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+#define local ((Scratch *)(&game.scratch[0]))
+#define ss local->sprite
+#define seq local->sequence
+#define aa local->animation
+
+typedef struct { /* Room local variables */
+ int16 sprite[15]; /* Sprite series handles */
+ int16 sequence[15]; /* Sequence handles */
+ int16 animation[4]; /* Animation handles */
+ int16 brie_calling_position; /* Conv000 tells position of Brie */
+ int16 brie_chandelier_position; /* Conv000 tells position of Brie */
+ int16 brie_calling_frame; /* */
+ int16 brie_chandelier_frame; /* */
+ int16 talk_count; /* how many times Brie will talk in CONV000 */
+ int16 start_sitting_down; /* true if picture_view_x > 208 */
+ int16 dynamic_brie; /* for dynamic Brie */
+ int16 dynamic_brie_2; /* for dynamic Brie */
+ int16 execute_chan; /* if talk_count == this var, then motion to chandelier */
+ int16 execute_wipe; /* if talk_count == this var, then wipe forehead */
+ int16 start_walking; /* if true, start walking away (conv001) */
+ int16 start_walking_0; /* if true, start walking away (conv000) */
+
+ int16 anim_0_running; /* T if aa[0] is running */
+ int16 anim_1_running; /* T if aa[1] is running */
+
+ int converse_counter; /* counter for talking displacements */
+
+} Scratch;
+
+
+/* ========================= Sprite Series =================== */
+
+#define fx_chandelier 0 /* rm101z */
+
+
+/* ========================= Other Macros ==================== */
+
+#define PLAYER_X_FROM_102 625
+#define PLAYER_Y_FROM_102 127
+
+#define PLAYER_X_FROM_202 18
+#define PLAYER_Y_FROM_202 79
+
+#define RIGHT_HALF 320 /* for camera_jump_to */
+#define LEFT_HALF 0 /* for camera_jump_to */
+
+#define CONV0_BRIE_ARMS_AT_SIDE 0
+#define CONV0_BRIE_RAISING_ARMS 1
+#define CONV0_BRIE_SHOULD_TALK 2 /* For conv000, Brie can do 2 different */
+#define CONV0_BRIE_SHOULD_WALK 3 /* talk sequences, or turn an walk away */
+
+#define CONV1_BRIE_SHOULD_MOTION_CHAN 0
+#define CONV1_BRIE_SHOULD_WALK 1
+#define CONV1_BRIE_SHOULD_TALK 2
+#define CONV1_BRIE_SHOULD_FREEZE_STAND 3
+#define CONV1_BRIE_SHOULD_FREEZE_SIT 4
+#define CONV1_BRIE_SHOULD_RAISE_HANDS 5
+#define CONV1_BRIE_SHOULD_WIPE 6
+
+#define CONV_BRIE_MOTIONS_TO_RAOUL 0 /* CONV000 */
+#define CONV_BRIE_BY_CHANDELIER 1 /* CONV001 */
+
+#define OFF_SCREEN_X_FROM_202 -20
+#define OFF_SCREEN_Y_FROM_202 75
+
+#define OFF_SCREEN_X_FROM_102 655
+#define OFF_SCREEN_Y_FROM_102 130
+
+#define DYNAMIC_BRIE_X 509
+#define DYNAMIC_BRIE_Y 73
+#define DYNAMIC_BRIE_X_SIZE 16
+#define DYNAMIC_BRIE_Y_SIZE 39
+#define DYNAMIC_BRIE_WALK_TO_X 490
+#define DYNAMIC_BRIE_WALK_TO_Y 119
+#define RESET -1
+
+#define DYN_BRIE_1_WALK_TO_X 25
+#define DYN_BRIE_1_WALK_TO_Y 80
+
+ /* ======================== Triggers ========================= */
+
+#define ROOM_101_START_CONV_MOTIONS 50 /* When this happens, CONV000 will start */
+#define ROOM_101_START_CONV_CHAN 55 /* When this happens, CONV000 will start */
+#define ROOM_101_BRIE_START_TALKING 60
+#define ROOM_101_BRIE_STOP_TALKING 70
+#define ROOM_101_BRIE_START_WALKING 80
+#define ROOM_101_CONV0_MAKE_BRIE_WALK 90
+
+#define ROOM_101_NO_TALK_DISP 100
+#define ROOM_101_STOP_CONVERSING 105
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/phantom/rooms/section1.cpp b/engines/mads/madsv2/phantom/rooms/section1.cpp
new file mode 100644
index 00000000000..c771c3063dc
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/section1.cpp
@@ -0,0 +1,41 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "mads/madsv2/phantom/rooms/section1.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+void section_1_music() {
+}
+
+void section_1_walker() {
+}
+
+void section_1_interface() {
+}
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/rooms/section1.h b/engines/mads/madsv2/phantom/rooms/section1.h
new file mode 100644
index 00000000000..af7e44a7969
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/section1.h
@@ -0,0 +1,44 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 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 MADS_PHANTOM_SECTION1_H
+#define MADS_PHANTOM_SECTION1_H
+
+#include "mads/madsv2/phantom/global.h"
+#include "mads/madsv2/phantom/mads/text.h"
+#include "mads/madsv2/phantom/mads/words.h"
+#include "mads/madsv2/core/vocabh.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+extern void section_1_music();
+extern void section_1_walker();
+extern void section_1_interface();
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index e121f449030..348e233d6d0 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -121,7 +121,10 @@ MODULE_OBJS += \
madsv2/core/vocab.o \
madsv2/core/window.o \
madsv2/phantom/mads/mads.o \
+ madsv2/phantom/rooms/section1.o \
+ madsv2/phantom/rooms/room101.o \
madsv2/phantom/phantom.o \
+ madsv2/phantom/conv.o \
madsv2/phantom/main_menu.o \
madsv2/phantom/main.o \
madsv2/phantom/sound_phantom.o
Commit: cc86c12ea2f4a4582e245643995aa42671ca300b
https://github.com/scummvm/scummvm/commit/cc86c12ea2f4a4582e245643995aa42671ca300b
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:39+10:00
Commit Message:
MADS: PHANTOM: Added room 102
Changed paths:
A engines/mads/madsv2/phantom/rooms/room102.cpp
A engines/mads/madsv2/phantom/rooms/room102.h
engines/mads/madsv2/core/global.h
engines/mads/madsv2/core/sound.cpp
engines/mads/madsv2/core/sound.h
engines/mads/madsv2/phantom/global.h
engines/mads/madsv2/phantom/mads/sounds.h
engines/mads/madsv2/phantom/mads/text.h
engines/mads/madsv2/phantom/mads/words.h
engines/mads/madsv2/phantom/rooms/room101.cpp
engines/mads/module.mk
diff --git a/engines/mads/madsv2/core/global.h b/engines/mads/madsv2/core/global.h
index 066343cd456..5e4d1c17f2d 100644
--- a/engines/mads/madsv2/core/global.h
+++ b/engines/mads/madsv2/core/global.h
@@ -70,12 +70,14 @@ extern char global_release_copyright[];
/* ================= Global to all sections ================== */
+#if 0
#define player_score 10 /* player's score of the game */
#define player_score_flags 11 /* 16 flags for checking if player increased score */
#define dont_load_walker 12 /* if T, will not load walker in section code */
#define perform_displacements 13 /* if T, will do displacements */
#define intro 14 /* if T, Intro is in progress */
#define outro 15 /* if T, Outro is in progress */
+#endif
/* =================== Section 1 20 - 39 ==================== */
diff --git a/engines/mads/madsv2/core/sound.cpp b/engines/mads/madsv2/core/sound.cpp
index a25e9087f38..464c2177e83 100644
--- a/engines/mads/madsv2/core/sound.cpp
+++ b/engines/mads/madsv2/core/sound.cpp
@@ -26,6 +26,10 @@
namespace MADS {
namespace MADSV2 {
+void sound_play(int soundNum) {
+ sound_queue(soundNum);
+}
+
void sound_queue(int soundNum) {
g_engine->_soundManager->command(soundNum);
}
diff --git a/engines/mads/madsv2/core/sound.h b/engines/mads/madsv2/core/sound.h
index ccf149e2d8d..90a39e5dfdb 100644
--- a/engines/mads/madsv2/core/sound.h
+++ b/engines/mads/madsv2/core/sound.h
@@ -29,6 +29,7 @@ namespace MADSV2 {
constexpr int sound_board_roland = 1;
+extern void sound_play(int soundNum);
extern void sound_queue(int soundNum);
extern void sound_queue_flush();
diff --git a/engines/mads/madsv2/phantom/global.h b/engines/mads/madsv2/phantom/global.h
index 594cedc0a99..e62884d2aa2 100644
--- a/engines/mads/madsv2/phantom/global.h
+++ b/engines/mads/madsv2/phantom/global.h
@@ -41,12 +41,133 @@ enum {
conv001_point_two_abc = 27
};
+enum {
+ /* --- System / all-sections (0â19) --- */
+ kWalkerTiming = 0,
+ kWalkerTiming2 = 1,
+ stop_walker_disabled = 2,
+ temp_interface = 3,
+ walker_converse = 4,
+ walker_converse_state = 5,
+ walker_converse_now = 6,
+ _007 = 7,
+ _008 = 8,
+ _009 = 9,
+ current_year = 10,
+ music_selected = 11,
+ player_score = 12,
+ player_score_flags = 13,
+ done_brie_conv_203 = 14,
+ lantern_status = 15,
+ _016 = 16,
+ _017 = 17,
+ _018 = 18,
+ leave_angel_music_on = 19,
+
+ /* --- Section 1 (20â59) --- */
+ trap_door_status = 20,
+ christine_door_status = 21,
+ sandbag_status = 22,
+ chris_f_status = 23,
+ brie_talk_status = 24,
+ julies_door = 25,
+ prompter_stand_status = 26,
+ chris_d_status = 27,
+ julie_name_is_known = 28,
+ chris_kicked_raoul_out = 29,
+ jacques_name_is_known = 30,
+ jacques_status = 31,
+ florent_name_is_known = 32,
+ charles_name_is_known = 33,
+ room_103_104_transition = 34,
+ observed_phan_104 = 35,
+ death_location = 36,
+ make_brie_leave_203 = 37,
+ hint_that_daae_is_home_1 = 38,
+ hint_that_daae_is_home_2 = 39,
+
+ /* --- Section 2 (40â59) --- */
+ christine_told_envelope = 40,
+ read_book = 41,
+ scanned_bookcase = 42,
+ ran_conv_in_205 = 43,
+ doors_in_205 = 44,
+ panel_in_206 = 45,
+ madame_name_is_known = 46,
+ madame_giry_loc = 47,
+ looked_at_case = 48,
+ madame_giry_shows_up = 49,
+ done_rich_conv_203 = 50,
+ came_from_fade = 51,
+ ticket_people_here = 52,
+ degas_name_is_known = 53,
+ temp_var = 54,
+ flicked_1 = 55,
+ flicked_2 = 56,
+ flicked_3 = 57,
+ flicked_4 = 58,
+ _059 = 59,
+
+ /* --- Section 3 (60â79) --- */
+ top_floor_locked = 60,
+ field_7A = 61,
+ field_7C = 62,
+ field_7E = 63,
+ field_80 = 64,
+ field_82 = 65,
+ field_84 = 66,
+ field_86 = 67,
+ field_88 = 68,
+ field_8A = 69,
+ _070 = 70,
+ field_8E = 71,
+ field_90 = 72,
+ field_92 = 73,
+ field_94 = 74,
+ field_96 = 75,
+ field_98 = 76,
+ field_9A = 77,
+ field_9C = 78,
+ field_9E = 79,
+
+ /* --- Section 4 / Catacombs (80â99) --- */
+ catacombs_room = 80,
+ catacombs_misc = 81,
+ catacombs_flag = 82,
+ catacombs_from = 83,
+ catacombs_309 = 84,
+ catacombs_409a = 85,
+ catacombs_409b = 86,
+ catacombs_501 = 87,
+ catacombs_309_from = 88,
+ catacombs_409a_from = 89,
+ catacombs_409b_from = 90,
+ catacombs_501_from = 91,
+ catacombs_next_room = 92,
+ door_in_409_is_open = 93,
+ priest_piston_puke = 94,
+ cob_web_is_cut = 95,
+ field_C0 = 96,
+ field_C2 = 97,
+ field_C4 = 98,
+ _099 = 99,
+
+ /* --- Section 5 (100â112) --- */
+ christine_is_in_boat = 100,
+ chris_will_take_seat = 101,
+ right_door_is_open_504 = 102,
+ coffin_status = 103,
+ chris_left_505 = 104,
+ knocked_over_head = 105,
+ fight_status = 106,
+ he_listened = 107,
+ can_find_book_library = 108,
+ ring_is_on_finger = 109,
+ looked_at_skull_face = 110,
+ cable_hook_was_seperate = 111,
+ make_rich_leave_203 = 112
+};
-// Global indices
-#define walker_converse 4
-#define current_year 10
-#define brie_talk_status 24
-#define jacques_status 31
// brie_talk_status values
#define BEFORE_BRIE_MOTIONS 0
@@ -64,6 +185,11 @@ enum {
#define CONVERSE_HAND_WAVE_2 3
#define CONVERSE_HAND_CHIN 4
+// death_location values
+#define FAR_PIT 0
+#define MIDDLE_PIT 1
+#define NEAR_PIT 2
+
} // namespace Phantom
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/mads/sounds.h b/engines/mads/madsv2/phantom/mads/sounds.h
index fa061fa6775..13eb066bf5a 100644
--- a/engines/mads/madsv2/phantom/mads/sounds.h
+++ b/engines/mads/madsv2/phantom/mads/sounds.h
@@ -30,6 +30,7 @@ namespace Phantom {
enum {
N_AllFade = 1,
+ N_BackgroundMus = 16,
N_PlayerFalls = 67
};
diff --git a/engines/mads/madsv2/phantom/mads/text.h b/engines/mads/madsv2/phantom/mads/text.h
index b8083c48e89..70eb36689f6 100644
--- a/engines/mads/madsv2/phantom/mads/text.h
+++ b/engines/mads/madsv2/phantom/mads/text.h
@@ -28,7 +28,10 @@ namespace MADS {
namespace MADSV2 {
namespace Phantom {
+/* Formula: text_RRR_NN = RRR * 100 + NN */
+
enum {
+ /* Room 101 */
text_101_10 = 10110,
text_101_11 = 10111,
text_101_12 = 10112,
@@ -41,7 +44,31 @@ enum {
text_101_19 = 10119,
text_101_20 = 10120,
text_101_21 = 10121,
- text_101_22 = 10122
+ text_101_22 = 10122,
+
+ /* Room 102 */
+ text_102_10 = 10210,
+ text_102_11 = 10211,
+ text_102_12 = 10212,
+ text_102_13 = 10213,
+ text_102_14 = 10214,
+ text_102_15 = 10215,
+ text_102_17 = 10217,
+ text_102_18 = 10218,
+ text_102_19 = 10219,
+ text_102_20 = 10220,
+ text_102_21 = 10221,
+ text_102_22 = 10222,
+ text_102_23 = 10223,
+ text_102_24 = 10224,
+ text_102_25 = 10225,
+ text_102_26 = 10226,
+ text_102_27 = 10227,
+ text_102_28 = 10228,
+ text_102_29 = 10229,
+ text_102_30 = 10230,
+ text_102_31 = 10231,
+ text_102_32 = 10232
};
} // namespace Phantom
diff --git a/engines/mads/madsv2/phantom/mads/words.h b/engines/mads/madsv2/phantom/mads/words.h
index a378cf8ad7b..8efaf422c9b 100644
--- a/engines/mads/madsv2/phantom/mads/words.h
+++ b/engines/mads/madsv2/phantom/mads/words.h
@@ -29,12 +29,31 @@ namespace MADSV2 {
namespace Phantom {
enum {
+ words_look = 3,
+ words_push = 5,
+ words_open = 6,
+ words__in_one_ = 15,
+ words__in_two_ = 16,
+ words_act_curtain = 17,
words_aisle = 18,
+ words_apron = 19,
+ words_conductor_s_stand = 37,
words_exit_to = 55,
+ words_folding_chairs = 74,
+ words_leg = 90,
words_look_at = 96,
+ words_music_stand = 103,
+ words_music_stands = 104,
+ words_orchestra_door = 107,
words_orchestra_pit = 108,
+ words_pit = 113,
+ words_prompter_s_box = 116,
+ words_proscenium_arch = 119,
words_seats = 129,
words_side_wall = 130,
+ words_stage = 132,
+ words_walk_down = 154,
+ words_walk_through = 155,
words_grand_foyer = 180,
words_back_wall = 181,
words_chandelier = 201,
diff --git a/engines/mads/madsv2/phantom/rooms/room101.cpp b/engines/mads/madsv2/phantom/rooms/room101.cpp
index c7947eb908b..9f13ae75daa 100644
--- a/engines/mads/madsv2/phantom/rooms/room101.cpp
+++ b/engines/mads/madsv2/phantom/rooms/room101.cpp
@@ -29,6 +29,7 @@
#include "mads/madsv2/core/camera.h"
#include "mads/madsv2/core/matte.h"
#include "mads/madsv2/core/text.h"
+#include "mads/madsv2/phantom/mads/text.h"
#include "mads/madsv2/core/inter.h"
namespace MADS {
diff --git a/engines/mads/madsv2/phantom/rooms/room102.cpp b/engines/mads/madsv2/phantom/rooms/room102.cpp
new file mode 100644
index 00000000000..afb462c1d6c
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room102.cpp
@@ -0,0 +1,309 @@
+/* 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 "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/sound.h"
+#include "mads/madsv2/core/text.h"
+#include "mads/madsv2/phantom/mads/text.h"
+#include "mads/madsv2/core/inter.h"
+#include "mads/madsv2/phantom/mads/words.h"
+#include "mads/madsv2/phantom/mads/sounds.h"
+#include "mads/madsv2/phantom/rooms/section1.h"
+#include "mads/madsv2/phantom/rooms/room102.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+void room_102_init(void) {
+ int death_x = 0;
+ int death_y = 0;
+ int death_scale = 0;
+ int death_depth = 0;
+
+ local->anim_0_running = false;
+
+ /* =================== Load Sprite Series ==================== */
+
+ ss[fx_door] = kernel_load_series(kernel_name('x', 0), false);
+ ss[fx_death] = kernel_load_series("*RAL86", false);
+
+
+ /* =========== If in 1993, put chandelier here =============== */
+
+ if (global[current_year] == 1993) {
+ ss[fx_chandelier] = kernel_load_series(kernel_name('z', -1), false);
+ kernel_draw_to_background(ss[fx_chandelier], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ kernel_seq_depth(seq[fx_chandelier], 14);
+ } else {
+ kernel_flip_hotspot(words_chandelier, false);
+ }
+
+
+ /* ======================= Previous Rooms ==================== */
+
+ if (previous_room == 101) {
+ player.x = PLAYER_X_FROM_101;
+ player.y = PLAYER_Y_FROM_101;
+ player.facing = FACING_SOUTHEAST;
+ seq[fx_door] = kernel_seq_stamp(ss[fx_door], false, 4);
+ player_walk(PLAYER_X_FROM_101 - 14, PLAYER_Y_FROM_101 + 8, FACING_SOUTHEAST);
+ kernel_seq_depth(seq[fx_door], 14);
+
+ } else if (previous_room == 104) {
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ switch (global[death_location]) {
+ case FAR_PIT:
+ death_x = 221;
+ death_y = 57;
+ death_scale = 50;
+ death_depth = 14;
+ break;
+
+ case MIDDLE_PIT:
+ death_x = 219;
+ death_y = 85;
+ death_scale = 60;
+ death_depth = 6;
+ break;
+
+ case NEAR_PIT:
+ death_x = 257;
+ death_y = 138;
+ death_scale = 76;
+ death_depth = 1;
+ break;
+
+ default:
+ break;
+ }
+
+ kernel_init_dialog();
+ kernel_set_interface_mode(INTER_CONVERSATION);
+ seq[fx_death] = kernel_seq_stamp(ss[fx_death], false, 1);
+ kernel_seq_depth(seq[fx_death], death_depth);
+ kernel_seq_loc(seq[fx_death], death_x, death_y);
+ kernel_seq_scale(seq[fx_death], death_scale);
+ kernel_timing_trigger(TWO_SECONDS, ROOM_102_DEATH);
+ seq[fx_door] = kernel_seq_stamp(ss[fx_door], false, 4);
+ kernel_seq_depth(seq[fx_door], 14);
+
+ } else if ((previous_room == 103) || (previous_room != KERNEL_RESTORING_GAME)) {
+ player.x = PLAYER_X_FROM_103;
+ player.y = PLAYER_Y_FROM_103;
+ player.facing = FACING_WEST;
+ local->anim_0_running = true;
+ local->animation[0] = kernel_run_animation(kernel_name('d', 1), ROOM_102_DOOR_CLOSES);
+
+ } else if (previous_room == KERNEL_RESTORING_GAME) {
+ seq[fx_door] = kernel_seq_stamp(ss[fx_door], false, 4);
+ kernel_seq_depth(seq[fx_door], 14);
+ }
+
+ section_1_music();
+}
+
+
+void room_102_daemon(void) {
+ if (kernel.trigger == ROOM_102_DOOR_CLOSES) {
+ seq[fx_door] = kernel_seq_stamp(ss[fx_door], false, 4);
+ kernel_seq_depth(seq[fx_door], 14);
+ local->anim_0_running = false;
+ }
+
+ if (kernel.trigger == ROOM_102_DEATH) {
+ if (global[death_location] == FAR_PIT) {
+ text_show(text_102_32);
+ } else {
+ text_show(text_102_29);
+ }
+ sound_play(N_BackgroundMus);
+ new_room = 104;
+ }
+}
+
+
+void room_102_pre_parser(void) {
+ if ((player_said_2(open, orchestra_door)) ||
+ (player_said_2(push, orchestra_door))) {
+ player_walk(FRONT_OF_DOOR_X, FRONT_OF_DOOR_Y, FACING_EAST);
+ }
+}
+
+
+void room_102_parser(void) {
+ if (player_said_2(walk_down, aisle)) {
+ new_room = 101;
+ goto handled;
+ }
+
+ if ((player_said_2(walk_through, orchestra_door)) ||
+ (player_said_2(push, orchestra_door)) ||
+ (player_said_2(open, orchestra_door))) {
+ if (local->anim_0_running) {
+ kernel_timing_trigger(QUARTER_SECOND, ROOM_102_TRY_AGAIN);
+ player.commands_allowed = false;
+
+ } else {
+ switch (kernel.trigger) {
+ case ROOM_102_TRY_AGAIN:
+ case 0:
+ kernel_seq_delete(seq[fx_door]);
+ local->animation[0] = kernel_run_animation(kernel_name('d', 0), 1);
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ break;
+
+ case 1:
+ new_room = 103;
+ break;
+ }
+ }
+ goto handled;
+ }
+
+ if (player.look_around) {
+ text_show(text_102_10);
+ goto handled;
+ }
+
+ if (player_said_1(look) || player_said_1(look_at)) {
+ if (player_said_1(pit)) {
+ text_show(text_102_11);
+ goto handled;
+ }
+
+ if (player_said_1(seats)) {
+ if (global[current_year] == 1881) {
+ text_show(text_102_12);
+ } else {
+ text_show(text_102_30);
+ }
+ goto handled;
+ }
+
+ if (player_said_1(orchestra_door)) {
+ text_show(text_102_13);
+ goto handled;
+ }
+
+ if (player_said_1(conductor_s_stand)) {
+ text_show(text_102_14);
+ goto handled;
+ }
+
+ if (player_said_1(music_stand) || player_said_1(music_stands)) {
+ text_show(text_102_15);
+ goto handled;
+ }
+
+ if (player_said_1(prompter_s_box)) {
+ text_show(text_102_17);
+ goto handled;
+ }
+
+ if (player_said_1(stage)) {
+ text_show(text_102_18);
+ goto handled;
+ }
+
+ if (player_said_1(apron)) {
+ text_show(text_102_19);
+ goto handled;
+ }
+
+ if (player_said_1(side_wall)) {
+ text_show(text_102_20);
+ goto handled;
+ }
+
+ if (player_said_1(folding_chairs)) {
+ text_show(text_102_21);
+ goto handled;
+ }
+
+ if (player_said_1(aisle)) {
+ text_show(text_102_22);
+ goto handled;
+ }
+
+ if (player_said_1(proscenium_arch)) {
+ text_show(text_102_23);
+ goto handled;
+ }
+
+ if (player_said_1(act_curtain)) {
+ text_show(text_102_24);
+ goto handled;
+ }
+
+ if (player_said_1(_in_one_)) {
+ text_show(text_102_25);
+ goto handled;
+ }
+
+ if (player_said_1(_in_two_)) {
+ text_show(text_102_26);
+ goto handled;
+ }
+
+ if (player_said_1(leg)) {
+ text_show(text_102_27);
+ goto handled;
+ }
+
+ if (player_said_1(chandelier)) {
+ text_show(text_102_31);
+ goto handled;
+ }
+ }
+
+ if (player_said_2(close, orchestra_door)) {
+ text_show(text_102_28);
+ goto handled;
+ }
+
+ goto done;
+
+handled:
+ player.command_ready = false;
+
+done:
+ ;
+}
+
+void room_102_preload(void) {
+ room_init_code_pointer = room_102_init;
+ room_pre_parser_code_pointer = room_102_pre_parser;
+ room_parser_code_pointer = room_102_parser;
+ room_daemon_code_pointer = room_102_daemon;
+
+ section_1_walker();
+ section_1_interface();
+}
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/rooms/room102.h b/engines/mads/madsv2/phantom/rooms/room102.h
new file mode 100644
index 00000000000..607e9bd7902
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room102.h
@@ -0,0 +1,75 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef MADS_PHANTOM_ROOMS_102_H
+#define MADS_PHANTOM_ROOMS_102_H
+
+#include "mads/madsv2/core/general.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+#define local ((Scratch *)(&game.scratch[0]))
+#define ss local->sprite
+#define seq local->sequence
+#define aa local->animation
+
+typedef struct { /* Room local variables */
+ int sprite[15]; /* Sprite series handles */
+ int sequence[15]; /* Sequence handles */
+ int animation[4]; /* Animation handles */
+ int anim_0_running;
+} Scratch;
+
+
+/* ========================= Load Sprite Series =================== */
+
+#define fx_chandelier 0 /* rm102z */
+#define fx_door 2 /* rm102x0 */
+#define fx_death 3 /* RAL86 */
+
+
+/* ========================= Other Macros ========================= */
+
+#define PLAYER_X_FROM_103 282
+#define PLAYER_Y_FROM_103 145
+
+#define PLAYER_X_FROM_101 97
+#define PLAYER_Y_FROM_101 79
+
+#define FRONT_OF_DOOR_X 282
+#define FRONT_OF_DOOR_Y 145
+
+
+/* ========================= Triggers ============================= */
+
+#define ROOM_102_DOOR_CLOSES 60
+#define ROOM_102_DEATH 65
+#define ROOM_102_TRY_AGAIN 70
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index 348e233d6d0..78ca73d7502 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -123,6 +123,7 @@ MODULE_OBJS += \
madsv2/phantom/mads/mads.o \
madsv2/phantom/rooms/section1.o \
madsv2/phantom/rooms/room101.o \
+ madsv2/phantom/rooms/room102.o \
madsv2/phantom/phantom.o \
madsv2/phantom/conv.o \
madsv2/phantom/main_menu.o \
Commit: 385f660c230672a4116b57ba02ba0f94e0c4c77f
https://github.com/scummvm/scummvm/commit/385f660c230672a4116b57ba02ba0f94e0c4c77f
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:39+10:00
Commit Message:
MADS: PHANTOM: Added room 103
Changed paths:
A engines/mads/madsv2/phantom/rooms/room103.cpp
A engines/mads/madsv2/phantom/rooms/room103.h
engines/mads/core/sound.cpp
engines/mads/core/sound.h
engines/mads/madsv2/core/global.h
engines/mads/madsv2/core/sound.cpp
engines/mads/madsv2/core/sound.h
engines/mads/madsv2/phantom/conv.cpp
engines/mads/madsv2/phantom/conv.h
engines/mads/madsv2/phantom/global.h
engines/mads/madsv2/phantom/mads/sounds.h
engines/mads/madsv2/phantom/mads/text.h
engines/mads/madsv2/phantom/mads/words.h
engines/mads/module.mk
diff --git a/engines/mads/core/sound.cpp b/engines/mads/core/sound.cpp
index 1d1d07d1610..9610ac0022e 100644
--- a/engines/mads/core/sound.cpp
+++ b/engines/mads/core/sound.cpp
@@ -98,16 +98,19 @@ void SoundManager::setVolume(int volume) {
_driver->setVolume(volume);
}
-void SoundManager::command(int commandId, int param) {
+int SoundManager::command(int commandId, int param) {
if (_newSoundsPaused) {
if (_queuedCommands.size() < 8)
_queuedCommands.push(commandId);
+ return _queuedCommands.size() - 1;
} else if (_driver) {
// Note: I don't know any way to identify music commands versus sfx
// commands, so if sfx is mute, then so is music
if (_soundFlag)
_driver->command(commandId, param);
}
+
+ return 0;
}
void SoundManager::stop() {
diff --git a/engines/mads/core/sound.h b/engines/mads/core/sound.h
index 4f8a28bcecd..c3a01351c9a 100644
--- a/engines/mads/core/sound.h
+++ b/engines/mads/core/sound.h
@@ -108,7 +108,7 @@ public:
* @param commandid Command Id to execute
* @param param Optional paramater specific to a few commands
*/
- void command(int commandId, int param = 0);
+ int command(int commandId, int param = 0);
/**
* Stops any currently playing sound
diff --git a/engines/mads/madsv2/core/global.h b/engines/mads/madsv2/core/global.h
index 5e4d1c17f2d..3f33d03fa3b 100644
--- a/engines/mads/madsv2/core/global.h
+++ b/engines/mads/madsv2/core/global.h
@@ -40,6 +40,9 @@ extern char global_release_copyright[];
/* Global macros */
+#define YES 1
+#define NO 0
+
#define SCORE_LOOK_SPHERE_106 1
#define SCORE_READ_BOOK_101 2
#define SCORE_SHIFT_INTO_SEAL_113 4
diff --git a/engines/mads/madsv2/core/sound.cpp b/engines/mads/madsv2/core/sound.cpp
index 464c2177e83..6b9f5a2f4a0 100644
--- a/engines/mads/madsv2/core/sound.cpp
+++ b/engines/mads/madsv2/core/sound.cpp
@@ -26,12 +26,12 @@
namespace MADS {
namespace MADSV2 {
-void sound_play(int soundNum) {
- sound_queue(soundNum);
+int sound_play(int soundNum) {
+ return sound_queue(soundNum);
}
-void sound_queue(int soundNum) {
- g_engine->_soundManager->command(soundNum);
+int sound_queue(int soundNum) {
+ return g_engine->_soundManager->command(soundNum);
}
void sound_queue_flush() {
diff --git a/engines/mads/madsv2/core/sound.h b/engines/mads/madsv2/core/sound.h
index 90a39e5dfdb..705ae78f580 100644
--- a/engines/mads/madsv2/core/sound.h
+++ b/engines/mads/madsv2/core/sound.h
@@ -29,8 +29,8 @@ namespace MADSV2 {
constexpr int sound_board_roland = 1;
-extern void sound_play(int soundNum);
-extern void sound_queue(int soundNum);
+extern int sound_play(int soundNum);
+extern int sound_queue(int soundNum);
extern void sound_queue_flush();
} // namespace MADSV2
diff --git a/engines/mads/madsv2/phantom/conv.cpp b/engines/mads/madsv2/phantom/conv.cpp
index f6a396283f9..5f29ba9559c 100644
--- a/engines/mads/madsv2/phantom/conv.cpp
+++ b/engines/mads/madsv2/phantom/conv.cpp
@@ -93,6 +93,15 @@ void conv_abort() {}
void conv_me_trigger(int trigger) {}
void conv_you_trigger(int trigger) {}
+int *conv_get_variable(int varNum) {
+ // TODO
+ return nullptr;
+}
+
+void conv_export_value(int varNum) {
+ // TODO
+}
+
} // namespace Phantom
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/conv.h b/engines/mads/madsv2/phantom/conv.h
index 8770c437db6..baa82cba55f 100644
--- a/engines/mads/madsv2/phantom/conv.h
+++ b/engines/mads/madsv2/phantom/conv.h
@@ -28,6 +28,35 @@ namespace MADS {
namespace MADSV2 {
namespace Phantom {
+
+enum {
+ conv001_speech_talk = 0,
+ conv001_continue_abc = 1,
+ conv001_what_one = 4,
+ conv001_yesno_yes = 8,
+ conv001_everything_byebye = 10,
+ conv001_everything_copycat = 12,
+ conv001_speak_byebye = 18,
+ conv001_saytwo_1 = 22,
+ conv001_instructions_three = 24,
+ conv001_point_two_abc = 27,
+};
+
+enum {
+ conv012_hello_one = 1,
+ conv012_hello_four = 4,
+ conv012_byebye_first = 6,
+ conv012_questions_three = 7,
+ conv012_questions_one = 8,
+ conv012_seen_byebye = 10,
+ conv012_seen_mask = 12,
+ conv012_tell_byebye = 19,
+ conv012_tell_knewhim = 29,
+ conv012_nomore_first = 30,
+
+ conv012_var_questions_done = 26
+};
+
struct ConvData {
int16 node_count;
int16 dialog_count;
@@ -67,6 +96,8 @@ extern void conv_export_pointer(int *ptr);
extern void conv_abort();
extern void conv_me_trigger(int trigger);
extern void conv_you_trigger(int trigger);
+extern int *conv_get_variable(int varNum);
+extern void conv_export_value(int varNum);
} // namespace Phantom
} // namespace MADSV2
diff --git a/engines/mads/madsv2/phantom/global.h b/engines/mads/madsv2/phantom/global.h
index e62884d2aa2..5693aacfb3f 100644
--- a/engines/mads/madsv2/phantom/global.h
+++ b/engines/mads/madsv2/phantom/global.h
@@ -28,19 +28,6 @@ namespace MADS {
namespace MADSV2 {
namespace Phantom {
-enum {
- conv001_speech_talk = 0,
- conv001_continue_abc = 1,
- conv001_what_one = 4,
- conv001_yesno_yes = 8,
- conv001_everything_byebye = 10,
- conv001_everything_copycat = 12,
- conv001_speak_byebye = 18,
- conv001_saytwo_1 = 22,
- conv001_instructions_three = 24,
- conv001_point_two_abc = 27
-};
-
enum {
/* --- System / all-sections (0â19) --- */
kWalkerTiming = 0,
@@ -175,8 +162,10 @@ enum {
#define AFTER_CONVS_0_AND_1 2
// jacques_status values
-#define JACQUES_IS_DEAD 1
-#define JACQUES_IS_DEAD_RICH_GONE 2
+#define JACQUES_IS_ALIVE 0
+#define JACQUES_IS_DEAD 1
+#define JACQUES_IS_DEAD_RICH_GONE 2
+#define JAC_DEAD_RICH_GONE_SEEN_BODY 3
// walker_converse values
#define CONVERSE_NONE 0
@@ -190,6 +179,24 @@ enum {
#define MIDDLE_PIT 1
#define NEAR_PIT 2
+// jacques_name_is_known
+#define YES_AND_END_CONV 2
+
+// trap_door_status
+#define TRAP_DOOR_IS_OPEN 0
+#define TRAP_DOOR_IS_CLOSED 1
+
+// prompter_stand_status
+#define PROMPT_LEFT 0
+#define PROMPT_RIGHT 1
+
+// room_103_104_transition
+#define PEEK_THROUGH 0
+#define NEW_ROOM 1
+
+// player_score_flags
+#define SCORE_TRAP_DOOR 1
+
} // namespace Phantom
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/mads/sounds.h b/engines/mads/madsv2/phantom/mads/sounds.h
index 13eb066bf5a..ac96b2bb508 100644
--- a/engines/mads/madsv2/phantom/mads/sounds.h
+++ b/engines/mads/madsv2/phantom/mads/sounds.h
@@ -30,8 +30,16 @@ namespace Phantom {
enum {
N_AllFade = 1,
+ N_IsAnySoundOn = 8,
N_BackgroundMus = 16,
- N_PlayerFalls = 67
+ N_DoorOpens = 24,
+ N_DoorCloses = 25,
+ N_TakeObjectSnd = 26,
+ N_BackMus1stTime = 38,
+ N_TrapDoor001 = 64,
+ N_SqueakyDoor = 66,
+ N_PlayerFalls = 67,
+ N_DoorHandle = 73
};
} // namespace Phantom
diff --git a/engines/mads/madsv2/phantom/mads/text.h b/engines/mads/madsv2/phantom/mads/text.h
index 70eb36689f6..925ce0fe86d 100644
--- a/engines/mads/madsv2/phantom/mads/text.h
+++ b/engines/mads/madsv2/phantom/mads/text.h
@@ -68,7 +68,52 @@ enum {
text_102_29 = 10229,
text_102_30 = 10230,
text_102_31 = 10231,
- text_102_32 = 10232
+ text_102_32 = 10232,
+
+ /* Cross-room */
+ text_000_32 = 32,
+ text_008_00 = 800,
+
+ /* Room 103 */
+ text_103_10 = 10310,
+ text_103_11 = 10311,
+ text_103_12 = 10312,
+ text_103_13 = 10313,
+ text_103_14 = 10314,
+ text_103_15 = 10315,
+ text_103_16 = 10316,
+ text_103_17 = 10317,
+ text_103_18 = 10318,
+ text_103_19 = 10319,
+ text_103_20 = 10320,
+ text_103_21 = 10321,
+ text_103_22 = 10322,
+ text_103_23 = 10323,
+ text_103_24 = 10324,
+ text_103_25 = 10325,
+ text_103_26 = 10326,
+ text_103_27 = 10327,
+ text_103_28 = 10328,
+ text_103_29 = 10329,
+ text_103_31 = 10331,
+ text_103_33 = 10333,
+ text_103_35 = 10335,
+ text_103_36 = 10336,
+ text_103_37 = 10337,
+ text_103_38 = 10338,
+ text_103_39 = 10339,
+ text_103_40 = 10340,
+ text_103_41 = 10341,
+ text_103_42 = 10342,
+ text_103_43 = 10343,
+ text_103_44 = 10344,
+ text_103_45 = 10345,
+ text_103_46 = 10346,
+ text_103_47 = 10347,
+ text_103_48 = 10348,
+ text_103_49 = 10349,
+ text_103_50 = 10350,
+ text_103_51 = 10351
};
} // namespace Phantom
diff --git a/engines/mads/madsv2/phantom/mads/words.h b/engines/mads/madsv2/phantom/mads/words.h
index 8efaf422c9b..8be6c8a38fd 100644
--- a/engines/mads/madsv2/phantom/mads/words.h
+++ b/engines/mads/madsv2/phantom/mads/words.h
@@ -29,19 +29,27 @@ namespace MADSV2 {
namespace Phantom {
enum {
- words_look = 3,
- words_push = 5,
- words_open = 6,
words__in_one_ = 15,
words__in_two_ = 16,
words_act_curtain = 17,
words_aisle = 18,
words_apron = 19,
+ words_cable = 26,
+ words_carton = 28,
+ words_climb_through = 35,
words_conductor_s_stand = 37,
+ words_door = 46,
words_exit_to = 55,
+ words_exposed_brick = 67,
+ words_floor = 73,
words_folding_chairs = 74,
+ words_garbage_can = 75,
+ words_junk = 84,
+ words_key = 85,
words_leg = 90,
+ words_lock = 93,
words_look_at = 96,
+ words_look_through = 97,
words_music_stand = 103,
words_music_stands = 104,
words_orchestra_door = 107,
@@ -52,12 +60,26 @@ enum {
words_seats = 129,
words_side_wall = 130,
words_stage = 132,
+ words_stair_unit = 137,
+ words_trap_ceiling = 147,
+ words_trap_door = 148,
+ words_unlock = 151,
+ words_walk_across = 153,
words_walk_down = 154,
words_walk_through = 155,
+ words_wall = 157,
+ words_water_pipe = 160,
+ words_door_to_pit = 170,
words_grand_foyer = 180,
words_back_wall = 181,
words_chandelier = 201,
- words_Monsieur_Brie = 258
+ words_Monsieur_Brie = 258,
+ words_prompter_s_stand = 270,
+ words_Jacques = 280,
+ words_gentleman = 281,
+ words_climb = 288,
+ words_prompter_s_seat = 300,
+ words_lever = 301
};
} // namespace Phantom
diff --git a/engines/mads/madsv2/phantom/rooms/room103.cpp b/engines/mads/madsv2/phantom/rooms/room103.cpp
new file mode 100644
index 00000000000..d5ec6c7e749
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room103.cpp
@@ -0,0 +1,1766 @@
+/* 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 "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/imath.h"
+#include "mads/madsv2/core/text.h"
+#include "mads/madsv2/core/inter.h"
+#include "mads/madsv2/core/rail.h"
+#include "mads/madsv2/core/sound.h"
+#include "mads/madsv2/core/object.h"
+#include "mads/madsv2/phantom/global.h"
+#include "mads/madsv2/phantom/mads/words.h"
+#include "mads/madsv2/phantom/mads/sounds.h"
+#include "mads/madsv2/phantom/mads/text.h"
+#include "mads/madsv2/phantom/conv.h"
+#include "mads/madsv2/phantom/rooms/section1.h"
+#include "mads/madsv2/phantom/rooms/room103.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+constexpr int key = 0;
+
+void room_103_adjust_rails(int variant) {
+ switch (variant) {
+ case 0:
+ rail_disconnect_node(3);
+ rail_disconnect_node(4);
+ rail_disconnect_node(5);
+ rail_disconnect_node(6);
+ rail_disconnect_node(12);
+ rail_disconnect_node(13);
+ rail_disconnect_node(14);
+ break;
+
+ case 1:
+ rail_disconnect_node(1);
+ rail_disconnect_node(2);
+ rail_disconnect_node(3);
+ rail_disconnect_node(4);
+ rail_disconnect_node(5);
+ rail_disconnect_node(6);
+ rail_disconnect_node(7);
+ rail_disconnect_node(9);
+ rail_disconnect_node(10);
+ rail_disconnect_node(11);
+ break;
+
+ case 2:
+ rail_disconnect_node(1);
+ rail_disconnect_node(2);
+ rail_disconnect_node(5);
+ rail_disconnect_node(6);
+ rail_disconnect_node(7);
+ rail_disconnect_node(9);
+ rail_disconnect_node(10);
+ rail_disconnect_node(11);
+ break;
+
+ case 3:
+ rail_disconnect_node(1);
+ rail_disconnect_node(2);
+ rail_disconnect_node(3);
+ rail_disconnect_node(4);
+ rail_disconnect_node(10);
+ rail_disconnect_node(11);
+ break;
+ }
+}
+
+void room_103_init(void) {
+ int prompt_x;
+ int prompt_y;
+ int prompt_facing;
+ int dyn_floor_3;
+ int dyn_floor_4;
+ int dyn_floor_5;
+ int dyn_floor_6;
+ int dyn_floor_7;
+ int dyn_floor_8;
+ int dyn_jacques_body_1;
+
+ if (previous_room != KERNEL_RESTORING_GAME) {
+ local->anim_0_running = false;
+ local->anim_1_running = false;
+ local->anim_2_running = false;
+ local->anim_3_running = false;
+ local->anim_4_running = false;
+ local->anim_5_running = false;
+ local->anim_6_running = false;
+ local->climb_thru = false;
+ local->frame_guard = false;
+ local->sit_on_it = false;
+ local->jacques_action = CONV12_JAC_SHUT_UP;
+ local->just_did_option = 0;
+ local->top_of_stand = NO;
+ }
+
+
+ /* =================== Load Sprite Series ==================== */
+
+ if (global[jacques_status] >= JACQUES_IS_DEAD) {
+ if (object_is_here(key)) {
+ ss[fx_key] = kernel_load_series(kernel_name('x', 2), false);
+ ss[fx_bend_down_9] = kernel_load_series("*RRD_9", false);
+ }
+ ss[fx_steps] = kernel_load_series(kernel_name('f', 3), false);
+ ss[fx_jacques_body] = kernel_load_series(kernel_name('c', 1), false);
+ ss[fx_broken_promp] = kernel_load_series(kernel_name('f', 1), false);
+
+ } else {
+ ss[fx_steps] = kernel_load_series(kernel_name('f', 0), false);
+ ss[fx_on_seat] = kernel_load_series(kernel_name('a', 3), false);
+ }
+
+ ss[fx_lever] = kernel_load_series(kernel_name('x', 3), false);
+ ss[fx_up_trap_door] = kernel_load_series(kernel_name('a', 2), false);
+ ss[fx_rail_pieces] = kernel_load_series(kernel_name('f', 2), false);
+ ss[fx_trap_door] = kernel_load_series(kernel_name('x', 0), false);
+ ss[fx_door] = kernel_load_series(kernel_name('x', 1), false);
+ ss[fx_take_6] = kernel_load_series("*RDR_6", false);
+
+
+ /* ==================== Adjust rail nodes ==================== */
+
+ room_103_adjust_rails(kernel_initial_variant);
+
+
+ kernel_flip_hotspot(words_Jacques, false);
+ kernel_flip_hotspot(words_key, false);
+
+
+ /* ================== Load conversation ====================== */
+
+ conv_get(CONV_JACQUES);
+
+
+ /* ================= Stamp trap door & lever ================= */
+
+ if (global[trap_door_status] == TRAP_DOOR_IS_CLOSED) {
+ seq[fx_trap_door] = kernel_seq_stamp(ss[fx_trap_door], false, 1);
+ kernel_seq_depth(seq[fx_trap_door], 14);
+ seq[fx_lever] = kernel_seq_stamp(ss[fx_lever], false, 1);
+ kernel_seq_depth(seq[fx_lever], 3);
+ }
+
+ if (global[trap_door_status] == TRAP_DOOR_IS_OPEN) {
+ seq[fx_trap_door] = kernel_seq_stamp(ss[fx_trap_door], false, 5);
+ kernel_seq_depth(seq[fx_trap_door], 14);
+ seq[fx_lever] = kernel_seq_stamp(ss[fx_lever], false, 2);
+ kernel_seq_depth(seq[fx_lever], 3);
+ }
+
+
+ if (global[jacques_status] == JACQUES_IS_ALIVE) {
+ prompt_x = DYN_PROMPT_R_WALK_TO_X_JAC;
+ prompt_y = DYN_PROMPT_R_WALK_TO_Y_JAC;
+ prompt_facing = FACING_NORTHEAST;
+ } else {
+ prompt_x = DYN_PROMPT_R_WALK_TO_X;
+ prompt_y = DYN_PROMPT_R_WALK_TO_Y;
+ prompt_facing = FACING_NORTHWEST;
+ }
+
+
+ /* ========================= Stairs ========================== */
+
+ if ((global[prompter_stand_status] == PROMPT_RIGHT) || (global[current_year] == 1881)) {
+
+ if (global[jacques_status] >= JACQUES_IS_DEAD) {
+ seq[fx_broken_promp] = kernel_seq_stamp(ss[fx_broken_promp], false, 1);
+ kernel_seq_depth(seq[fx_broken_promp], 1);
+ seq[fx_steps] = kernel_seq_stamp(ss[fx_steps], false, 1);
+ kernel_seq_depth(seq[fx_steps], 4);
+ kernel_seq_loc(seq[fx_steps], PROMPT_RIGHT_X, PROMPT_RIGHT_Y);
+
+ } else {
+ seq[fx_steps] = kernel_seq_stamp(ss[fx_steps], false, 1);
+ kernel_seq_depth(seq[fx_steps], 4);
+ kernel_seq_loc(seq[fx_steps], PROMPT_RIGHT_X, PROMPT_RIGHT_Y);
+
+ seq[fx_rail_pieces] = kernel_seq_stamp(ss[fx_rail_pieces], false, 1);
+ kernel_seq_depth(seq[fx_rail_pieces], 1);
+ }
+
+ local->prompt_1 = kernel_add_dynamic(words_prompter_s_stand, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ DYN_PROMPT_RIGHT_1_X, DYN_PROMPT_RIGHT_1_Y,
+ DYN_PROMPT_X_SIZE_1, DYN_PROMPT_Y_SIZE_1);
+ kernel_dynamic_hot[local->prompt_1].prep = PREP_ON;
+ kernel_dynamic_walk(local->prompt_1, prompt_x, prompt_y, prompt_facing);
+ local->prompt_2 = kernel_add_dynamic(words_prompter_s_stand, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ DYN_PROMPT_RIGHT_2_X, DYN_PROMPT_RIGHT_2_Y,
+ DYN_PROMPT_X_SIZE_2, DYN_PROMPT_Y_SIZE_2);
+ kernel_dynamic_hot[local->prompt_2].prep = PREP_ON;
+ kernel_dynamic_walk(local->prompt_2, prompt_x, prompt_y, prompt_facing);
+ local->prompt_3 = kernel_add_dynamic(words_prompter_s_stand, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ DYN_PROMPT_RIGHT_3_X, DYN_PROMPT_RIGHT_3_Y,
+ DYN_PROMPT_X_SIZE_3, DYN_PROMPT_Y_SIZE_3);
+ kernel_dynamic_hot[local->prompt_3].prep = PREP_ON;
+ kernel_dynamic_walk(local->prompt_3, prompt_x, prompt_y, prompt_facing);
+ local->prompt_4 = kernel_add_dynamic(words_prompter_s_stand, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ DYN_PROMPT_RIGHT_4_X, DYN_PROMPT_RIGHT_4_Y,
+ DYN_PROMPT_X_SIZE_4, DYN_PROMPT_Y_SIZE_4);
+ kernel_dynamic_hot[local->prompt_4].prep = PREP_ON;
+ kernel_dynamic_walk(local->prompt_4, prompt_x, prompt_y, prompt_facing);
+ local->prompt_5 = kernel_add_dynamic(words_prompter_s_stand, words_climb, SYNTAX_SINGULAR, KERNEL_NONE,
+ DYN_PROMPT_RIGHT_5_X, DYN_PROMPT_LEFT_5_Y,
+ DYN_PROMPT_X_SIZE_5, DYN_PROMPT_Y_SIZE_5);
+ kernel_dynamic_hot[local->prompt_5].prep = PREP_ON;
+ kernel_dynamic_walk(local->prompt_5, PROMPT_UP_RIGHT_X, PROMPT_UP_RIGHT_Y, FACING_SOUTHWEST);
+ kernel_dynamic_cursor(local->prompt_5, CURSOR_UP);
+
+ local->floor_r_1 = kernel_add_dynamic(words_floor, words_walk_across, SYNTAX_SINGULAR, KERNEL_NONE,
+ DYN_FLOOR_R_1_X, DYN_FLOOR_R_1_Y,
+ DYN_FLOOR_R_1_X_SIZE, DYN_FLOOR_R_1_Y_SIZE);
+ kernel_dynamic_hot[local->floor_r_1].prep = PREP_ON;
+ kernel_dynamic_walk(local->floor_r_1, DYN_FLOOR_R_1_WALK_TO_X, DYN_FLOOR_R_1_WALK_TO_Y, 5);
+ local->floor_r_2 = kernel_add_dynamic(words_floor, words_walk_across, SYNTAX_SINGULAR, KERNEL_NONE,
+ DYN_FLOOR_R_2_X, DYN_FLOOR_R_2_Y,
+ DYN_FLOOR_R_2_X_SIZE, DYN_FLOOR_R_2_Y_SIZE);
+ kernel_dynamic_hot[local->floor_r_2].prep = PREP_ON;
+ kernel_dynamic_walk(local->floor_r_2, DYN_FLOOR_R_2_WALK_TO_X, DYN_FLOOR_R_2_WALK_TO_Y, 5);
+
+ if ((global[jacques_status] == JACQUES_IS_ALIVE) && (global[current_year] == 1881)) {
+ if (global[jacques_name_is_known] >= YES) {
+ local->man = kernel_add_dynamic(words_Jacques, words_walk_to, SYNTAX_SINGULAR_MASC, KERNEL_NONE,
+ DYN_JAC_X, DYN_JAC_Y,
+ DYN_JAC_X_SIZE, DYN_JAC_Y_SIZE);
+ kernel_dynamic_hot[local->man].prep = PREP_ON;
+ kernel_dynamic_walk(local->man, DYN_JAC_WALK_TO_X, DYN_JAC_WALK_TO_Y, FACING_NORTHWEST);
+ } else {
+ local->man = kernel_add_dynamic(words_gentleman, words_walk_to, SYNTAX_MASC_NOT_PROPER, KERNEL_NONE,
+ DYN_JAC_X, DYN_JAC_Y,
+ DYN_JAC_X_SIZE, DYN_JAC_Y_SIZE);
+ kernel_dynamic_hot[local->man].prep = PREP_ON;
+ kernel_dynamic_walk(local->man, DYN_JAC_WALK_TO_X, DYN_JAC_WALK_TO_Y, FACING_NORTHWEST);
+ }
+ dyn_floor_3 = kernel_add_dynamic(words_floor, words_walk_across, SYNTAX_SINGULAR, KERNEL_NONE,
+ DYN_FLOOR_R_3_X, DYN_FLOOR_R_3_Y,
+ DYN_FLOOR_R_3_X_SIZE, DYN_FLOOR_R_3_Y_SIZE);
+ kernel_dynamic_hot[dyn_floor_3].prep = PREP_ON;
+ kernel_dynamic_walk(dyn_floor_3, DYN_FLOOR_R_3_WALK_TO_X, DYN_FLOOR_R_3_WALK_TO_Y, 5);
+ dyn_floor_4 = kernel_add_dynamic(words_floor, words_walk_across, SYNTAX_SINGULAR, KERNEL_NONE,
+ DYN_FLOOR_R_4_X, DYN_FLOOR_R_4_Y,
+ DYN_FLOOR_R_4_X_SIZE, DYN_FLOOR_R_4_Y_SIZE);
+ kernel_dynamic_hot[dyn_floor_4].prep = PREP_ON;
+ kernel_dynamic_walk(dyn_floor_4, DYN_FLOOR_R_4_WALK_TO_X, DYN_FLOOR_R_4_WALK_TO_Y, 5);
+
+ } else if ((global[jacques_status] >= JACQUES_IS_DEAD) && (global[current_year] == 1881)) {
+ /* Jacques is dead - stamp him, key, & dynamics */
+ seq[fx_jacques_body] = kernel_seq_stamp(ss[fx_jacques_body], false, 1);
+ kernel_seq_depth(seq[fx_jacques_body], 3);
+ if (object_is_here(key)) {
+ seq[fx_key] = kernel_seq_stamp(ss[fx_key], false, 1);
+ kernel_seq_depth(seq[fx_key], 14);
+ kernel_flip_hotspot(words_key, true);
+ }
+ kernel_flip_hotspot(words_Jacques, true);
+ kernel_delete_dynamic(local->floor_r_2);
+ dyn_jacques_body_1 = kernel_add_dynamic(words_Jacques, words_walk_to, SYNTAX_SINGULAR_MASC, KERNEL_NONE,
+ DYN_JAC_BODY_X, DYN_JAC_BODY_Y,
+ DYN_JAC_BODY_X_SIZE, DYN_JAC_BODY_Y_SIZE);
+ kernel_dynamic_hot[dyn_jacques_body_1].prep = PREP_ON;
+ kernel_dynamic_walk(dyn_jacques_body_1, DYN_JAC_BODY_WALK_TO_X, DYN_JAC_BODY_WALK_TO_Y, FACING_NORTHEAST);
+ dyn_floor_5 = kernel_add_dynamic(words_floor, words_walk_across, SYNTAX_SINGULAR, KERNEL_NONE,
+ DYN_FLOOR_R_5_X, DYN_FLOOR_R_5_Y,
+ DYN_FLOOR_R_5_X_SIZE, DYN_FLOOR_R_5_Y_SIZE);
+ kernel_dynamic_hot[dyn_floor_5].prep = PREP_ON;
+ kernel_dynamic_walk(dyn_floor_5, DYN_FLOOR_R_5_WALK_TO_X, DYN_FLOOR_R_5_WALK_TO_Y, 5);
+ dyn_floor_6 = kernel_add_dynamic(words_floor, words_walk_across, SYNTAX_SINGULAR, KERNEL_NONE,
+ DYN_FLOOR_R_6_X, DYN_FLOOR_R_6_Y,
+ DYN_FLOOR_R_6_X_SIZE, DYN_FLOOR_R_6_Y_SIZE);
+ kernel_dynamic_hot[dyn_floor_6].prep = PREP_ON;
+ kernel_dynamic_walk(dyn_floor_6, DYN_FLOOR_R_6_WALK_TO_X, DYN_FLOOR_R_6_WALK_TO_Y, 5);
+ dyn_floor_7 = kernel_add_dynamic(words_floor, words_walk_across, SYNTAX_SINGULAR, KERNEL_NONE,
+ DYN_FLOOR_R_7_X, DYN_FLOOR_R_7_Y,
+ DYN_FLOOR_R_7_X_SIZE, DYN_FLOOR_R_7_Y_SIZE);
+ kernel_dynamic_hot[dyn_floor_7].prep = PREP_ON;
+ kernel_dynamic_walk(dyn_floor_7, DYN_FLOOR_R_7_WALK_TO_X, DYN_FLOOR_R_7_WALK_TO_Y, 5);
+ dyn_floor_8 = kernel_add_dynamic(words_floor, words_walk_across, SYNTAX_SINGULAR, KERNEL_NONE,
+ DYN_FLOOR_R_8_X, DYN_FLOOR_R_8_Y,
+ DYN_FLOOR_R_8_X_SIZE, DYN_FLOOR_R_8_Y_SIZE);
+ kernel_dynamic_hot[dyn_floor_8].prep = PREP_ON;
+ kernel_dynamic_walk(dyn_floor_8, DYN_FLOOR_R_8_WALK_TO_X, DYN_FLOOR_R_8_WALK_TO_Y, 5);
+ }
+
+ } else if (global[prompter_stand_status] == PROMPT_LEFT) {
+
+ seq[fx_steps] = kernel_seq_stamp(ss[fx_steps], false, 1);
+ kernel_seq_depth(seq[fx_steps], 4);
+ kernel_seq_loc(seq[fx_steps], PROMPT_LEFT_X, PROMPT_LEFT_Y);
+
+ local->prompt_1 = kernel_add_dynamic(words_prompter_s_stand, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ DYN_PROMPT_LEFT_1_X, DYN_PROMPT_LEFT_1_Y,
+ DYN_PROMPT_X_SIZE_1, DYN_PROMPT_Y_SIZE_1);
+ kernel_dynamic_hot[local->prompt_1].prep = PREP_ON;
+ kernel_dynamic_walk(local->prompt_1, DYN_PROMPT_L_WALK_TO_X, DYN_PROMPT_L_WALK_TO_Y, FACING_NORTHWEST);
+
+ local->prompt_2 = kernel_add_dynamic(words_prompter_s_stand, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ DYN_PROMPT_LEFT_2_X, DYN_PROMPT_LEFT_2_Y,
+ DYN_PROMPT_X_SIZE_2, DYN_PROMPT_Y_SIZE_2);
+ kernel_dynamic_hot[local->prompt_2].prep = PREP_ON;
+ kernel_dynamic_walk(local->prompt_2, DYN_PROMPT_L_WALK_TO_X, DYN_PROMPT_L_WALK_TO_Y, FACING_NORTHWEST);
+
+ local->prompt_3 = kernel_add_dynamic(words_prompter_s_stand, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ DYN_PROMPT_LEFT_3_X, DYN_PROMPT_LEFT_3_Y,
+ DYN_PROMPT_X_SIZE_3, DYN_PROMPT_Y_SIZE_3);
+ kernel_dynamic_hot[local->prompt_3].prep = PREP_ON;
+ kernel_dynamic_walk(local->prompt_3, DYN_PROMPT_L_WALK_TO_X, DYN_PROMPT_L_WALK_TO_Y, FACING_NORTHWEST);
+
+ local->prompt_5 = kernel_add_dynamic(words_prompter_s_stand, words_climb, SYNTAX_SINGULAR, KERNEL_NONE,
+ DYN_PROMPT_LEFT_5_X, DYN_PROMPT_LEFT_5_Y,
+ DYN_PROMPT_X_SIZE_5, DYN_PROMPT_Y_SIZE_5);
+ kernel_dynamic_hot[local->prompt_5].prep = PREP_ON;
+ kernel_dynamic_walk(local->prompt_5, PROMPT_UP_LEFT_X, PROMPT_UP_LEFT_Y, FACING_SOUTHWEST);
+ kernel_dynamic_cursor(local->prompt_5, CURSOR_UP);
+
+ local->floor_l_1 = kernel_add_dynamic(words_floor, words_walk_across, SYNTAX_SINGULAR, KERNEL_NONE,
+ DYN_FLOOR_L_1_X, DYN_FLOOR_L_1_Y,
+ DYN_FLOOR_L_1_X_SIZE, DYN_FLOOR_L_1_Y_SIZE);
+ kernel_dynamic_hot[local->floor_l_1].prep = PREP_ON;
+ kernel_dynamic_walk(local->floor_l_1, DYN_FLOOR_L_1_WALK_TO_X, DYN_FLOOR_L_1_WALK_TO_Y, 5);
+ local->floor_l_2 = kernel_add_dynamic(words_floor, words_walk_across, SYNTAX_SINGULAR, KERNEL_NONE,
+ DYN_FLOOR_L_2_X, DYN_FLOOR_L_2_Y,
+ DYN_FLOOR_L_2_X_SIZE, DYN_FLOOR_L_2_Y_SIZE);
+ kernel_dynamic_hot[local->floor_l_2].prep = PREP_ON;
+ kernel_dynamic_walk(local->floor_l_2, DYN_FLOOR_L_2_WALK_TO_X, DYN_FLOOR_L_2_WALK_TO_Y, 5);
+ }
+
+
+ /* ============= Put Jacques here if alive =================== */
+
+ if ((global[jacques_status] == JACQUES_IS_ALIVE) && (global[current_year] == 1881)) {
+ aa[0] = kernel_run_animation(kernel_name('j', 1), 1);
+ local->anim_0_running = true;
+ kernel_reset_animation(aa[0], 9); /* start Jacques at frame 9 */
+ }
+
+
+ /* ====================== Previous Rooms ===================== */
+
+ if (previous_room == 104) {
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ if (global[room_103_104_transition] == PEEK_THROUGH) {
+ global[room_103_104_transition] = NEW_ROOM;
+ seq[fx_on_seat] = kernel_seq_stamp(ss[fx_on_seat], false, KERNEL_LAST);
+ kernel_seq_depth(seq[fx_on_seat], 4);
+ local->top_of_stand = YES_LEFT;
+ player.x = PROMPT_UP_LEFT_X;
+ player.y = PROMPT_UP_LEFT_Y;
+ kernel_timing_trigger(1, ROOM_103_GET_OFF_SEAT);
+ /* stamp on seat, then let Daemon get him off */
+
+ } else {
+ local->top_of_stand = YES_RIGHT;
+ aa[3] = kernel_run_animation(kernel_name('w', 1), 0);
+ local->anim_3_running = true;
+ player.commands_allowed = true;
+ player.x = PROMPT_UP_RIGHT_X;
+ player.y = PROMPT_UP_RIGHT_Y;
+ kernel_reset_animation(aa[3], 36);
+ /* stamp him on right stairs on top */
+
+ kernel_seq_delete(seq[fx_steps]);
+ seq[fx_steps] = kernel_seq_stamp(ss[fx_steps], false, 1);
+ kernel_seq_depth(seq[fx_steps], 13);
+ kernel_seq_loc(seq[fx_steps], PROMPT_RIGHT_X, PROMPT_RIGHT_Y);
+ }
+
+ seq[fx_door] = kernel_seq_stamp(ss[fx_door], false, KERNEL_FIRST);
+ kernel_seq_depth(seq[fx_door], 14);
+
+ } else if (previous_room == 102) {
+ player_first_walk(OFF_SCREEN_X_FROM_102, OFF_SCREEN_Y_FROM_102, FACING_EAST,
+ PLAYER_X_FROM_102, PLAYER_Y_FROM_102, FACING_EAST, true);
+ seq[fx_door] = kernel_seq_stamp(ss[fx_door], false, 1);
+ kernel_seq_depth(seq[fx_door], 14);
+
+ } else if ((previous_room == 105) || (previous_room != KERNEL_RESTORING_GAME)) {
+ player.x = PLAYER_X_FROM_105;
+ player.y = PLAYER_Y_FROM_105;
+ player.facing = FACING_WEST;
+ player.commands_allowed = false;
+ player_walk(WALK_TO_X_FROM_105, WALK_TO_Y_FROM_105, FACING_WEST);
+ player_walk_trigger(ROOM_103_DOOR_CLOSES);
+ seq[fx_door] = kernel_seq_stamp(ss[fx_door], false, 6);
+ kernel_seq_depth(seq[fx_door], 14);
+
+ } else if (previous_room == KERNEL_RESTORING_GAME) {
+ if (local->top_of_stand == YES_LEFT) {
+ player.walker_visible = false;
+ aa[5] = kernel_run_animation(kernel_name('w', 3), 0);
+ local->anim_5_running = true;
+ kernel_reset_animation(aa[5], 33);
+
+ } else if (local->top_of_stand == YES_RIGHT) {
+ kernel_seq_delete(seq[fx_steps]);
+ seq[fx_steps] = kernel_seq_stamp(ss[fx_steps], false, 1);
+ kernel_seq_depth(seq[fx_steps], 13);
+ kernel_seq_loc(seq[fx_steps], PROMPT_RIGHT_X, PROMPT_RIGHT_Y);
+ player.walker_visible = false;
+ aa[3] = kernel_run_animation(kernel_name('w', 1), 0);
+ local->anim_3_running = true;
+ player.commands_allowed = true;
+ kernel_reset_animation(aa[3], 36);
+
+ } else {
+ if (conv_restore_running == CONV_JACQUES) {
+ conv_run(CONV_JACQUES);
+ conv_export_pointer(&global[player_score]);
+ conv_export_value(global[music_selected]);
+ global[walker_converse] = imath_random(CONVERSE_LEAN, CONVERSE_HAND_CHIN);
+ }
+ }
+ seq[fx_door] = kernel_seq_stamp(ss[fx_door], false, KERNEL_FIRST);
+ kernel_seq_depth(seq[fx_door], 14);
+ }
+
+ section_1_music();
+}
+
+static void climb_stairs_right(void) {
+ int stairs_reset_frame;
+
+ if (kernel_anim[aa[3]].frame != local->stairs_frame) {
+ local->stairs_frame = kernel_anim[aa[3]].frame;
+ stairs_reset_frame = -1;
+
+ if (local->stairs_frame == 37) {
+ stairs_reset_frame = 36;
+ local->top_of_stand = YES_RIGHT;
+ player.commands_allowed = true;
+ }
+
+ if (local->stairs_frame == 2) {
+ kernel_seq_delete(seq[fx_steps]);
+ seq[fx_steps] = kernel_seq_stamp(ss[fx_steps], false, 1);
+ kernel_seq_depth(seq[fx_steps], 13);
+ kernel_seq_loc(seq[fx_steps], PROMPT_RIGHT_X, PROMPT_RIGHT_Y);
+ }
+
+ if (stairs_reset_frame >= 0) {
+ kernel_reset_animation(aa[3], stairs_reset_frame);
+ local->stairs_frame = stairs_reset_frame;
+ }
+ }
+}
+
+static void decend_stairs_right(void) {
+ int stairs_reset_frame;
+
+ if (kernel_anim[aa[4]].frame != local->stairs_frame) {
+ local->stairs_frame = kernel_anim[aa[4]].frame;
+ stairs_reset_frame = -1;
+
+ if (local->stairs_frame == 2) {
+ kernel_seq_delete(seq[fx_steps]);
+ seq[fx_steps] = kernel_seq_stamp(ss[fx_steps], false, 1);
+ kernel_seq_depth(seq[fx_steps], 4);
+ kernel_seq_loc(seq[fx_steps], PROMPT_RIGHT_X, PROMPT_RIGHT_Y);
+ }
+
+ if (stairs_reset_frame >= 0) {
+ kernel_reset_animation(aa[4], stairs_reset_frame);
+ local->stairs_frame = stairs_reset_frame;
+ }
+ }
+}
+
+static void climb_stairs_left(void) {
+ int stairs_reset_frame;
+
+ if (kernel_anim[aa[5]].frame != local->stairs_frame) {
+ local->stairs_frame = kernel_anim[aa[5]].frame;
+ stairs_reset_frame = -1;
+
+ if (local->stairs_frame == 34) {
+ stairs_reset_frame = 33;
+ local->top_of_stand = YES_LEFT;
+ player.commands_allowed = true;
+ }
+
+ if (local->stairs_frame == 2) {
+ kernel_seq_delete(seq[fx_steps]);
+ seq[fx_steps] = kernel_seq_stamp(ss[fx_steps], false, 1);
+ kernel_seq_depth(seq[fx_steps], 13);
+ kernel_seq_loc(seq[fx_steps], PROMPT_LEFT_X, PROMPT_LEFT_Y);
+ }
+
+ if (stairs_reset_frame >= 0) {
+ kernel_reset_animation(aa[5], stairs_reset_frame);
+ local->stairs_frame = stairs_reset_frame;
+ }
+ }
+}
+
+static void decend_stairs_left(void) {
+ int stairs_reset_frame;
+
+ if (kernel_anim[aa[6]].frame != local->stairs_frame) {
+ local->stairs_frame = kernel_anim[aa[6]].frame;
+ stairs_reset_frame = -1;
+
+ if (local->stairs_frame == 2) {
+ kernel_seq_delete(seq[fx_steps]);
+ seq[fx_steps] = kernel_seq_stamp(ss[fx_steps], false, 1);
+ kernel_seq_depth(seq[fx_steps], 4);
+ kernel_seq_loc(seq[fx_steps], PROMPT_LEFT_X, PROMPT_LEFT_Y);
+ }
+
+ if (stairs_reset_frame >= 0) {
+ kernel_reset_animation(aa[6], stairs_reset_frame);
+ local->stairs_frame = stairs_reset_frame;
+ }
+ }
+}
+
+static void handle_animation_jacques(void) {
+ int random;
+ int jacques_reset_frame;
+
+ if (kernel_anim[aa[0]].frame != local->jacques_frame) {
+ local->jacques_frame = kernel_anim[aa[0]].frame;
+ jacques_reset_frame = -1;
+
+ switch (local->jacques_frame) {
+ case 1: /* end of talk 1 */
+ case 2: /* end of talk 2 */
+ case 3: /* end of talk 3 */
+ case 9: /* end of point up & freeze */
+ case 17: /* end of I dunno 1 */
+ case 33: /* end of brush arm */
+ case 23: /* end of touch head */
+ case 51: /* end of put arms on knees (from other node) */
+
+ switch (local->jacques_action) {
+ case CONV12_JAC_POINT:
+ random = 4; /* point up */
+ local->jacques_action = CONV12_JAC_TALK;
+ break;
+
+ case CONV12_JAC_I_DUNNO_1:
+ random = 5; /* i dunno 1 */
+ local->jacques_action = CONV12_JAC_TALK;
+ break;
+
+ case CONV12_JAC_I_DUNNO_2:
+ random = 6; /* i dunno 2 */
+ break;
+
+ case CONV12_JAC_TALK:
+ random = imath_random(1, 3);
+ ++local->jacques_talk_count;
+ if (local->jacques_talk_count > 22) {
+ local->jacques_action = CONV12_JAC_SHUT_UP;
+ random = 9;
+ }
+ break;
+
+ default:
+ random = imath_random(6, 50);
+ while (local->just_did_option == random) {
+ random = imath_random(6, 50);
+ } /* so we don't repeat the same option twice */
+ local->just_did_option = random;
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ jacques_reset_frame = 0;
+ break; /* do talk 1 */
+ case 2:
+ jacques_reset_frame = 1;
+ break; /* do talk 2 */
+ case 3:
+ jacques_reset_frame = 2;
+ break; /* do talk 3 */
+ case 4:
+ jacques_reset_frame = 4;
+ break; /* point up */
+ case 5:
+ jacques_reset_frame = 10;
+ break; /* i dunno 1 */
+ case 6:
+ jacques_reset_frame = 34;
+ break; /* fold arms (goto next node) */
+ case 7:
+ jacques_reset_frame = 24;
+ break; /* brush arm */
+ case 8:
+ jacques_reset_frame = 18;
+ break; /* turn head */
+ default:
+ jacques_reset_frame = 8;
+ break; /* arms frozen on knees */
+ }
+ break;
+
+ case 36: /* end of freeze */
+ case 40: /* end i dunno 2 */
+ case 48: /* end of fold hands (from other node) */
+
+ switch (local->jacques_action) {
+ case CONV12_JAC_POINT:
+ case CONV12_JAC_I_DUNNO_1:
+ case CONV12_JAC_TALK:
+ random = 2; /* goto arms on knees (other node) */
+ break;
+
+ case CONV12_JAC_I_DUNNO_2:
+ random = 1; /* i dunno 2 */
+ local->jacques_action = CONV12_JAC_TALK;
+ break;
+
+ default:
+ random = imath_random(2, 50);
+ while (local->just_did_option == random) {
+ random = imath_random(2, 50);
+ }
+ local->just_did_option = random;
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ jacques_reset_frame = 37;
+ break; /* i dunno 2 */
+ case 2:
+ jacques_reset_frame = 49;
+ break; /* put arms on knees (goto other node) */
+ case 3:
+ jacques_reset_frame = 41;
+ break; /* put hands on side */
+ default:
+ jacques_reset_frame = 35;
+ break; /* hands folded frozen */
+ }
+ break;
+
+ case 44: /* end of hands on side and frozen */
+
+ random = imath_random(1, 50);
+ while (local->just_did_option == random) {
+ random = imath_random(1, 50);
+ }
+ local->just_did_option = random;
+
+ switch (local->jacques_action) {
+ case CONV12_JAC_POINT:
+ case CONV12_JAC_I_DUNNO_1:
+ case CONV12_JAC_I_DUNNO_2:
+ case CONV12_JAC_TALK:
+ random = 1; /* fold hands (other node) */
+ break;
+
+ default:
+ random = imath_random(1, 50);
+ while (local->just_did_option == random) {
+ random = imath_random(1, 50);
+ }
+ local->just_did_option = random;
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ jacques_reset_frame = 45;
+ break; /* fold hands (goto other node) */
+ default:
+ jacques_reset_frame = 43;
+ break; /* freeze hands on side */
+ }
+ break;
+ }
+
+ if (jacques_reset_frame >= 0) {
+ kernel_reset_animation(aa[0], jacques_reset_frame);
+ local->jacques_frame = jacques_reset_frame;
+ }
+ }
+}
+
+void room_103_daemon(void) {
+ int temp; /* for synching purposes */
+
+ if (local->anim_0_running) {
+ handle_animation_jacques();
+ }
+
+ if (local->anim_3_running) {
+ climb_stairs_right();
+ }
+
+ if (local->anim_5_running) {
+ climb_stairs_left();
+ }
+
+ if (local->anim_4_running) {
+ decend_stairs_right();
+ }
+
+ if (local->anim_6_running) {
+ decend_stairs_left();
+ }
+
+
+ /* =========== Deal with talker offsets during conv ========== */
+
+ if ((global[walker_converse] == CONVERSE_HAND_WAVE) ||
+ (global[walker_converse] == CONVERSE_HAND_WAVE_2)) {
+ ++local->converse_counter;
+ if (local->converse_counter > 200) {
+ global[walker_converse] = imath_random(CONVERSE_LEAN, CONVERSE_HAND_CHIN);
+ }
+ }
+
+
+ /* ========= Close door when player enters from 105 ========== */
+
+ switch (kernel.trigger) {
+ case ROOM_103_DOOR_CLOSES:
+ kernel_seq_delete(seq[fx_door]);
+ seq[fx_door] = kernel_seq_backward(ss[fx_door], false, 8, 0, 0, 1);
+ kernel_seq_depth(seq[fx_door], 14);
+ kernel_seq_range(seq[fx_door], 1, 6);
+ kernel_seq_trigger(seq[fx_door], KERNEL_TRIGGER_EXPIRE, 0, ROOM_103_DOOR_CLOSES + 1);
+ sound_play(N_SqueakyDoor);
+ break;
+
+ case ROOM_103_DOOR_CLOSES + 1:
+ temp = seq[fx_door];
+ sound_play(N_DoorCloses);
+ seq[fx_door] = kernel_seq_stamp(ss[fx_door], false, 1);
+ kernel_synch(KERNEL_SERIES, seq[fx_door], KERNEL_SERIES, temp);
+ kernel_seq_depth(seq[fx_door], 14);
+ player.commands_allowed = true;
+ break;
+
+ case ROOM_103_DIED:
+ new_room = 104;
+ kernel.force_restart = true;
+ break;
+ }
+
+
+ /* ==================== Get off of seat ====================== */
+
+ switch (kernel.trigger) {
+ case ROOM_103_GET_OFF_SEAT:
+ kernel_seq_delete(seq[fx_on_seat]);
+ seq[fx_on_seat] = kernel_seq_backward(ss[fx_on_seat], false, 6, 0, 0, 1);
+ kernel_seq_trigger(seq[fx_on_seat], KERNEL_TRIGGER_EXPIRE, 0, ROOM_103_GET_OFF_SEAT + 1);
+ kernel_seq_range(seq[fx_on_seat], KERNEL_FIRST, KERNEL_LAST);
+ kernel_seq_depth(seq[fx_on_seat], 4);
+ break;
+
+ case ROOM_103_GET_OFF_SEAT + 1:
+ aa[5] = kernel_run_animation(kernel_name('w', 3), 0);
+ local->anim_5_running = true;
+ kernel_reset_animation(aa[5], 33);
+ player.commands_allowed = true;
+ kernel_synch(KERNEL_ANIM, aa[5], KERNEL_SERIES, seq[fx_on_seat]);
+ break;
+ }
+
+
+ /* ================= Open/close trap door ==================== */
+
+ switch (kernel.trigger) {
+ case 0:
+ if (local->anim_1_running) {
+ if ((kernel_anim[aa[1]].frame == 10) && (!local->frame_guard)) {
+ sound_play(N_TrapDoor001);
+ local->frame_guard = true;
+ kernel_seq_delete(seq[fx_trap_door]);
+ kernel_seq_delete(seq[fx_lever]);
+ seq[fx_trap_door] = kernel_seq_forward(ss[fx_trap_door], false, 6, 0, 0, 1);
+ kernel_seq_depth(seq[fx_trap_door], 14);
+ kernel_seq_range(seq[fx_trap_door], KERNEL_FIRST, KERNEL_LAST);
+ kernel_seq_trigger(seq[fx_trap_door], KERNEL_TRIGGER_EXPIRE, 0, ROOM_103_SWITCH_DOWN);
+ }
+
+ } else if (local->anim_2_running) {
+ if ((kernel_anim[aa[2]].frame == 7) && (!local->frame_guard)) {
+ sound_play(N_TrapDoor001);
+ local->frame_guard = true;
+ kernel_seq_delete(seq[fx_trap_door]);
+ kernel_seq_delete(seq[fx_lever]);
+ seq[fx_trap_door] = kernel_seq_backward(ss[fx_trap_door], false, 6, 0, 0, 1);
+ kernel_seq_depth(seq[fx_trap_door], 14);
+ kernel_seq_range(seq[fx_trap_door], KERNEL_FIRST, KERNEL_LAST);
+ kernel_seq_trigger(seq[fx_trap_door], KERNEL_TRIGGER_EXPIRE, 0, ROOM_103_SWITCH_UP);
+ }
+ }
+ break;
+
+ case ROOM_103_SWITCH_DOWN:
+ seq[fx_trap_door] = kernel_seq_stamp(ss[fx_trap_door], false, KERNEL_LAST);
+ kernel_seq_depth(seq[fx_trap_door], 14);
+ seq[fx_lever] = kernel_seq_stamp(ss[fx_lever], false, KERNEL_LAST);
+ kernel_seq_depth(seq[fx_lever], 2);
+ local->frame_guard = false;
+ break;
+
+ case ROOM_103_SWITCH_UP:
+ seq[fx_trap_door] = kernel_seq_stamp(ss[fx_trap_door], false, KERNEL_FIRST);
+ kernel_seq_depth(seq[fx_trap_door], 14);
+ seq[fx_lever] = kernel_seq_stamp(ss[fx_lever], false, KERNEL_FIRST);
+ kernel_seq_depth(seq[fx_lever], 2);
+ local->frame_guard = false;
+ break;
+ }
+
+ if ((global[jacques_status] == JAC_DEAD_RICH_GONE_SEEN_BODY) &&
+ (!sound_queue(N_IsAnySoundOn))) {
+ sound_play(N_BackMus1stTime);
+ }
+}
+
+static void process_conv_jacques(void) {
+ int quit_converse = false;
+ int *value_1;
+
+ switch (player_verb) {
+ case conv012_hello_four:
+ case conv012_byebye_first:
+ case conv012_questions_three:
+ case conv012_seen_byebye:
+ case conv012_tell_byebye:
+ case conv012_nomore_first:
+ global[walker_converse] = CONVERSE_NONE;
+ value_1 = conv_get_variable(conv012_var_questions_done);
+ if (*value_1) {
+ global[jacques_name_is_known] = YES_AND_END_CONV;
+ }
+ quit_converse = true;
+ break;
+
+ case conv012_questions_one:
+ conv_you_trigger(ROOM_103_JACQUES_POINT);
+ break;
+
+ case conv012_tell_knewhim:
+ conv_you_trigger(ROOM_103_JACQUES_I_DUNNO_2);
+ break;
+
+ case conv012_seen_mask:
+ conv_you_trigger(ROOM_103_JACQUES_I_DUNNO_1);
+ break;
+
+ case conv012_hello_one:
+ conv_you_trigger(ROOM_103_JACQUES_I_DUNNO_1);
+ if (global[jacques_name_is_known] == NO) {
+ global[jacques_name_is_known] = YES;
+ kernel_delete_dynamic(local->man);
+ local->man = kernel_add_dynamic(words_Jacques, words_walk_to, SYNTAX_SINGULAR_MASC, KERNEL_NONE,
+ DYN_JAC_X, DYN_JAC_Y,
+ DYN_JAC_X_SIZE, DYN_JAC_Y_SIZE);
+ kernel_dynamic_hot[local->man].prep = PREP_ON;
+ kernel_dynamic_walk(local->man, DYN_JAC_WALK_TO_X, DYN_JAC_WALK_TO_Y, FACING_NORTHWEST);
+ }
+ break;
+ }
+
+ if ((player_verb != conv012_questions_one) &&
+ (player_verb != conv012_tell_knewhim) &&
+ (player_verb != conv012_hello_one) &&
+ (player_verb != conv012_seen_mask)) {
+ conv_you_trigger(ROOM_103_JACQUES_TALK);
+ }
+
+ conv_me_trigger(ROOM_103_JACQUES_SHUT_UP);
+
+ switch (kernel.trigger) {
+ case ROOM_103_JACQUES_I_DUNNO_2:
+ if (!quit_converse) {
+ global[walker_converse] = imath_random(CONVERSE_LEAN, CONVERSE_HAND_CHIN);
+ }
+ local->jacques_action = CONV12_JAC_I_DUNNO_2;
+ break;
+
+ case ROOM_103_JACQUES_I_DUNNO_1:
+ if (!quit_converse) {
+ global[walker_converse] = imath_random(CONVERSE_LEAN, CONVERSE_HAND_CHIN);
+ }
+ local->jacques_action = CONV12_JAC_I_DUNNO_1;
+ break;
+
+ case ROOM_103_JACQUES_POINT:
+ if (!quit_converse) {
+ global[walker_converse] = imath_random(CONVERSE_LEAN, CONVERSE_HAND_CHIN);
+ }
+ local->jacques_action = CONV12_JAC_POINT;
+ break;
+
+ case ROOM_103_JACQUES_TALK:
+ if (!quit_converse) {
+ global[walker_converse] = imath_random(CONVERSE_LEAN, CONVERSE_HAND_CHIN);
+ }
+ local->jacques_action = CONV12_JAC_TALK;
+ break;
+
+ case ROOM_103_JACQUES_SHUT_UP:
+ if (!quit_converse) {
+ global[walker_converse] = imath_random(CONVERSE_HAND_WAVE, CONVERSE_HAND_WAVE_2);
+ }
+ local->converse_counter = 0;
+ local->jacques_action = CONV12_JAC_SHUT_UP;
+ break;
+ }
+
+ local->jacques_talk_count = 0;
+}
+
+void room_103_pre_parser(void) {
+ if (player_said_2(open, door)) {
+ player.need_to_walk = true;
+ }
+
+ if (player_said_2(open, door_to_pit)) {
+ player_walk(LEAVE_LEFT_X, LEAVE_LEFT_Y, FACING_WEST);
+ player.walk_off_edge_to_room = 102;
+ }
+
+ /* ================ Climb down prompter's stand ============== */
+
+ if ((local->top_of_stand != NO) && !player_said_2(climb_through, trap_door) &&
+ !player_said_2(open, trap_door) &&
+ !player_said_2(climb, prompter_s_stand) &&
+ !player_said_2(push, trap_door) &&
+ !player_said_2(look_through, prompter_s_box) &&
+ !player_said_2(pull, trap_door)) {
+
+ if (player_said_1(pull) || player_said_1(push)) {
+ if ((!player_said_1(lever)) && (!kernel.trigger)) {
+ player.need_to_walk = false;
+ /* so he does not walk down the staircase */
+ }
+ }
+
+ if ((player_said_2(push, prompter_s_stand)) || (player_said_2(pull, prompter_s_stand))) {
+ if (!kernel.trigger) {
+ player.need_to_walk = true;
+ /* so he will walk down the staircase */
+ }
+ }
+
+ if (player.need_to_walk) {
+ if (global[prompter_stand_status] == PROMPT_LEFT) {
+ switch (kernel.trigger) {
+ case 0:
+ kernel_abort_animation(aa[5]);
+ player.ready_to_walk = false;
+ player.walker_visible = false;
+ player.commands_allowed = false;
+ local->anim_5_running = false;
+ local->anim_6_running = true;
+ aa[6] = kernel_run_animation(kernel_name('w', 4), 1);
+ break;
+
+ case 1:
+ player.x = PROMPT_UP_LEFT_X;
+ player.y = PROMPT_UP_LEFT_Y;
+ player.commands_allowed = true;
+ player.walker_visible = true;
+ local->top_of_stand = NO;
+ player.ready_to_walk = true;
+ if (player_said_2(push, prompter_s_stand)) {
+ player.need_to_walk = false;
+ }
+ local->anim_6_running = false;
+ player_demand_facing(FACING_NORTHEAST);
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_ANIM, aa[6]);
+ break;
+ }
+
+ } else {
+ switch (kernel.trigger) {
+ case 0:
+ kernel_abort_animation(aa[3]);
+ player.ready_to_walk = false;
+ if (player_said_2(push, prompter_s_stand)) {
+ player.need_to_walk = true;
+ }
+ player.walker_visible = false;
+ player.commands_allowed = false;
+ local->anim_3_running = false;
+ local->anim_4_running = true;
+ aa[4] = kernel_run_animation(kernel_name('w', 2), 1);
+ break;
+
+ case 1:
+ player.x = PROMPT_UP_RIGHT_X;
+ player.y = PROMPT_UP_RIGHT_Y;
+ player.commands_allowed = true;
+ player.ready_to_walk = true;
+ if (player_said_2(push, prompter_s_stand)) {
+ player.need_to_walk = false;
+ }
+ player.walker_visible = true;
+ local->top_of_stand = NO;
+ local->anim_4_running = false;
+ player_demand_facing(FACING_NORTHEAST);
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_ANIM, aa[4]);
+ break;
+ }
+ }
+ }
+ }
+
+ if (local->top_of_stand == NO) {
+ if ((player_said_2(push, prompter_s_stand)) || (player_said_2(pull, prompter_s_stand))) {
+ if (global[current_year] == 1993) {
+ if (global[prompter_stand_status] == PROMPT_LEFT) {
+ player_walk(WALKER_LEFT_PROMPT_X, WALKER_LEFT_PROMPT_Y, FACING_WEST);
+ } else {
+ player_walk(WALKER_RIGHT_PROMPT_X, WALKER_RIGHT_PROMPT_Y, FACING_WEST);
+ }
+ }
+ }
+ }
+
+ if ((player_said_2(look_through, prompter_s_box)) && (local->top_of_stand == NO) &&
+ (global[prompter_stand_status] == PROMPT_LEFT) && (global[current_year] == 1993)) {
+ player_walk(PROMPT_UP_LEFT_X, PROMPT_UP_LEFT_Y, FACING_SOUTHWEST);
+ }
+
+ if ((player_said_2(climb_through, trap_door)) && (local->top_of_stand == NO) &&
+ (global[prompter_stand_status] == PROMPT_RIGHT) && (global[trap_door_status] == TRAP_DOOR_IS_OPEN)) {
+ player_walk(PROMPT_UP_RIGHT_X, PROMPT_UP_RIGHT_Y, FACING_SOUTHWEST);
+ }
+
+ if (player_said_2(walk_through, door_to_pit)) {
+ player.walk_off_edge_to_room = 102;
+ }
+
+ if ((player_said_2(open, door) || player_said_2(unlock, door) || player_said_2(lock, door)) && (local->top_of_stand == NO)) {
+ player_walk(WALK_TO_X_FROM_105, WALK_TO_Y_FROM_105, FACING_EAST);
+ }
+}
+
+void room_103_parser(void) {
+ int temp; /* for synching purposes */
+
+ if (player_said_2(open, door_to_pit)) {
+ new_room = 102;
+ goto handled;
+ }
+
+ if (conv_control.running == CONV_JACQUES) {
+ process_conv_jacques();
+ goto handled;
+ }
+
+ if (player_said_2(climb_through, trap_door)) {
+ if (global[trap_door_status] == TRAP_DOOR_IS_CLOSED) {
+ text_show(text_103_33);
+ goto handled;
+ /* trap door is closed */
+ } else if (global[prompter_stand_status] == PROMPT_LEFT) {
+ text_show(text_103_41);
+ goto handled;
+ /* you can't reach the trap door when the stand is under prompters box */
+ }
+ }
+
+ if ((player_said_2(look_through, prompter_s_box)) && (global[prompter_stand_status] == PROMPT_RIGHT)) {
+ text_show(text_103_42);
+ /* you can't reach the prompters box when the stand is under trap door */
+ goto handled;
+ }
+
+
+ /* ================ Climb prompter's stand =================== */
+
+ if ((player_said_2(climb, prompter_s_stand) && local->top_of_stand == NO) ||
+ ((player_said_2(look_through, prompter_s_box)) && (local->top_of_stand == NO)) ||
+ ((player_said_2(climb_through, trap_door)) && (local->top_of_stand == NO))) {
+ if (global[prompter_stand_status] == PROMPT_LEFT) {
+ switch (kernel.trigger) {
+ case 0:
+ if (player_said_2(look_through, prompter_s_box)) {
+ local->sit_on_it = true;
+ aa[5] = kernel_run_animation(kernel_name('w', 3), ROOM_103_LOOK_THRU_BOX);
+ } else {
+ aa[5] = kernel_run_animation(kernel_name('w', 3), 0);
+ }
+ player.walker_visible = false;
+ player.commands_allowed = false;
+ local->anim_5_running = true;
+ kernel_synch(KERNEL_ANIM, aa[5], KERNEL_PLAYER, 0);
+ goto handled;
+ break;
+ }
+
+ } else {
+ switch (kernel.trigger) {
+ case 0:
+ if (player_said_2(climb_through, trap_door)) {
+ local->climb_thru = true;
+ aa[3] = kernel_run_animation(kernel_name('w', 1), ROOM_103_CLIMB_OUT_TRAP);
+ } else {
+ aa[3] = kernel_run_animation(kernel_name('w', 1), 0);
+ }
+ player.walker_visible = false;
+ player.commands_allowed = false;
+ local->anim_3_running = true;
+ kernel_synch(KERNEL_ANIM, aa[3], KERNEL_PLAYER, 0);
+ goto handled;
+ break;
+ }
+ }
+ }
+
+ if (player_said_2(climb, prompter_s_stand)) {
+ if (local->top_of_stand != NO) {
+ goto handled;
+ /* so nothing is said */
+ }
+ }
+
+
+ /* ================ Push prompter's stand ==================== */
+
+ if ((player_said_2(push, prompter_s_stand)) || (player_said_2(pull, prompter_s_stand))) {
+ if (global[current_year] == 1993) {
+ if (global[prompter_stand_status] == PROMPT_LEFT) {
+ switch (kernel.trigger) {
+ case 0:
+ if (global[prompter_stand_status] == PROMPT_LEFT) {
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ aa[0] = kernel_run_animation(kernel_name('s', 1), ROOM_103_DONE_MOVING_PROMPT);
+ player.clock = kernel.clock;
+ kernel_synch(KERNEL_ANIM, aa[0], KERNEL_PLAYER, 0);
+ kernel_seq_delete(seq[fx_steps]);
+ }
+ break;
+
+ case ROOM_103_DONE_MOVING_PROMPT:
+ if (global[prompter_stand_status] == PROMPT_LEFT) {
+ seq[fx_rail_pieces] = kernel_seq_stamp(ss[fx_rail_pieces], false, 1);
+ kernel_seq_depth(seq[fx_rail_pieces], 1);
+ seq[fx_steps] = kernel_seq_stamp(ss[fx_steps], false, 1);
+ kernel_seq_depth(seq[fx_steps], 4);
+ kernel_seq_loc(seq[fx_steps], PROMPT_RIGHT_X, PROMPT_RIGHT_Y);
+ kernel_synch(KERNEL_SERIES, seq[fx_steps], KERNEL_ANIM, aa[0]);
+ global[prompter_stand_status] = PROMPT_RIGHT;
+ player.commands_allowed = true;
+ player.walker_visible = true;
+ player.x = AFTER_STEPS_FROM_LEFT_X;
+ player.y = AFTER_STEPS_FROM_LEFT_Y;
+ player_demand_facing(FACING_EAST);
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_ANIM, aa[0]);
+
+ kernel_delete_dynamic(local->prompt_1);
+ kernel_delete_dynamic(local->prompt_2);
+ kernel_delete_dynamic(local->prompt_3);
+ kernel_delete_dynamic(local->prompt_5);
+ kernel_delete_dynamic(local->floor_l_1);
+ kernel_delete_dynamic(local->floor_l_2);
+ local->prompt_1 = kernel_add_dynamic(words_prompter_s_stand, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ DYN_PROMPT_RIGHT_1_X, DYN_PROMPT_RIGHT_1_Y,
+ DYN_PROMPT_X_SIZE_1, DYN_PROMPT_Y_SIZE_1);
+ kernel_dynamic_hot[local->prompt_1].prep = PREP_ON;
+ kernel_dynamic_walk(local->prompt_1, DYN_PROMPT_R_WALK_TO_X, DYN_PROMPT_R_WALK_TO_Y, FACING_NORTHWEST);
+ local->prompt_2 = kernel_add_dynamic(words_prompter_s_stand, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ DYN_PROMPT_RIGHT_2_X, DYN_PROMPT_RIGHT_2_Y,
+ DYN_PROMPT_X_SIZE_2, DYN_PROMPT_Y_SIZE_2);
+ kernel_dynamic_hot[local->prompt_2].prep = PREP_ON;
+ kernel_dynamic_walk(local->prompt_2, DYN_PROMPT_R_WALK_TO_X, DYN_PROMPT_R_WALK_TO_Y, FACING_NORTHWEST);
+ local->prompt_3 = kernel_add_dynamic(words_prompter_s_stand, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ DYN_PROMPT_RIGHT_3_X, DYN_PROMPT_RIGHT_3_Y,
+ DYN_PROMPT_X_SIZE_3, DYN_PROMPT_Y_SIZE_3);
+ kernel_dynamic_hot[local->prompt_3].prep = PREP_ON;
+ kernel_dynamic_walk(local->prompt_3, DYN_PROMPT_R_WALK_TO_X, DYN_PROMPT_R_WALK_TO_Y, FACING_NORTHWEST);
+ local->prompt_4 = kernel_add_dynamic(words_prompter_s_stand, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ DYN_PROMPT_RIGHT_4_X, DYN_PROMPT_RIGHT_4_Y,
+ DYN_PROMPT_X_SIZE_4, DYN_PROMPT_Y_SIZE_4);
+ kernel_dynamic_hot[local->prompt_4].prep = PREP_ON;
+ kernel_dynamic_walk(local->prompt_4, DYN_PROMPT_R_WALK_TO_X, DYN_PROMPT_R_WALK_TO_Y, FACING_NORTHWEST);
+ local->prompt_5 = kernel_add_dynamic(words_prompter_s_stand, words_climb, SYNTAX_SINGULAR, KERNEL_NONE,
+ DYN_PROMPT_RIGHT_5_X, DYN_PROMPT_LEFT_5_Y,
+ DYN_PROMPT_X_SIZE_5, DYN_PROMPT_Y_SIZE_5);
+ kernel_dynamic_hot[local->prompt_5].prep = PREP_ON;
+ kernel_dynamic_walk(local->prompt_5, PROMPT_UP_RIGHT_X, PROMPT_UP_RIGHT_Y, FACING_SOUTHWEST);
+ kernel_dynamic_cursor(local->prompt_5, CURSOR_UP);
+
+ local->floor_r_1 = kernel_add_dynamic(words_floor, words_walk_across, SYNTAX_SINGULAR, KERNEL_NONE,
+ DYN_FLOOR_R_1_X, DYN_FLOOR_R_1_Y,
+ DYN_FLOOR_R_1_X_SIZE, DYN_FLOOR_R_1_Y_SIZE);
+ kernel_dynamic_hot[local->floor_r_1].prep = PREP_ON;
+ kernel_dynamic_walk(local->floor_r_1, DYN_FLOOR_R_1_WALK_TO_X, DYN_FLOOR_R_1_WALK_TO_Y, 5);
+ local->floor_r_2 = kernel_add_dynamic(words_floor, words_walk_across, SYNTAX_SINGULAR, KERNEL_NONE,
+ DYN_FLOOR_R_2_X, DYN_FLOOR_R_2_Y,
+ DYN_FLOOR_R_2_X_SIZE, DYN_FLOOR_R_2_Y_SIZE);
+ kernel_dynamic_hot[local->floor_r_2].prep = PREP_ON;
+ kernel_dynamic_walk(local->floor_r_2, DYN_FLOOR_R_2_WALK_TO_X, DYN_FLOOR_R_2_WALK_TO_Y, 5);
+ kernel_load_variant(1);
+ room_103_adjust_rails(1);
+ }
+ break;
+ }
+ } else {
+ switch (kernel.trigger) {
+ case 0:
+ if (global[prompter_stand_status] == PROMPT_RIGHT) {
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ aa[0] = kernel_run_animation(kernel_name('s', 2), ROOM_103_DONE_MOVING_PROMPT);
+ player.clock = kernel.clock;
+ kernel_synch(KERNEL_ANIM, aa[0], KERNEL_PLAYER, 0);
+ kernel_seq_delete(seq[fx_rail_pieces]);
+ kernel_seq_delete(seq[fx_steps]);
+ }
+ break;
+
+ case ROOM_103_DONE_MOVING_PROMPT:
+ if (global[prompter_stand_status] == PROMPT_RIGHT) {
+ seq[fx_steps] = kernel_seq_stamp(ss[fx_steps], false, 1);
+ kernel_seq_depth(seq[fx_steps], 4);
+ kernel_seq_loc(seq[fx_steps], PROMPT_LEFT_X, PROMPT_LEFT_Y);
+ kernel_synch(KERNEL_SERIES, seq[fx_steps], KERNEL_ANIM, aa[0]);
+ global[prompter_stand_status] = PROMPT_LEFT;
+ player.commands_allowed = true;
+ player.walker_visible = true;
+ player.x = AFTER_STEPS_FROM_RIGHT_X;
+ player.y = AFTER_STEPS_FROM_RIGHT_Y;
+ player_demand_facing(FACING_WEST);
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_ANIM, aa[0]);
+ kernel_delete_dynamic(local->prompt_1);
+ kernel_delete_dynamic(local->prompt_2);
+ kernel_delete_dynamic(local->prompt_3);
+ kernel_delete_dynamic(local->prompt_4);
+ kernel_delete_dynamic(local->prompt_5);
+ kernel_delete_dynamic(local->floor_r_1);
+ kernel_delete_dynamic(local->floor_r_2);
+ local->prompt_1 = kernel_add_dynamic(words_prompter_s_stand, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ DYN_PROMPT_LEFT_1_X, DYN_PROMPT_LEFT_1_Y,
+ DYN_PROMPT_X_SIZE_1, DYN_PROMPT_Y_SIZE_1);
+ kernel_dynamic_hot[local->prompt_1].prep = PREP_ON;
+ kernel_dynamic_walk(local->prompt_1, DYN_PROMPT_L_WALK_TO_X, DYN_PROMPT_L_WALK_TO_Y, FACING_NORTHWEST);
+ local->prompt_2 = kernel_add_dynamic(words_prompter_s_stand, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ DYN_PROMPT_LEFT_2_X, DYN_PROMPT_LEFT_2_Y,
+ DYN_PROMPT_X_SIZE_2, DYN_PROMPT_Y_SIZE_2);
+ kernel_dynamic_hot[local->prompt_2].prep = PREP_ON;
+ kernel_dynamic_walk(local->prompt_2, DYN_PROMPT_L_WALK_TO_X, DYN_PROMPT_L_WALK_TO_Y, FACING_NORTHWEST);
+ local->prompt_3 = kernel_add_dynamic(words_prompter_s_stand, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ DYN_PROMPT_LEFT_3_X, DYN_PROMPT_LEFT_3_Y,
+ DYN_PROMPT_X_SIZE_3, DYN_PROMPT_Y_SIZE_3);
+ kernel_dynamic_hot[local->prompt_3].prep = PREP_ON;
+ kernel_dynamic_walk(local->prompt_3, DYN_PROMPT_L_WALK_TO_X, DYN_PROMPT_L_WALK_TO_Y, FACING_NORTHWEST);
+ local->floor_l_1 = kernel_add_dynamic(words_floor, words_walk_across, SYNTAX_SINGULAR, KERNEL_NONE,
+ DYN_FLOOR_L_1_X, DYN_FLOOR_L_1_Y,
+ DYN_FLOOR_L_1_X_SIZE, DYN_FLOOR_L_1_Y_SIZE);
+ kernel_dynamic_hot[local->floor_l_1].prep = PREP_ON;
+ kernel_dynamic_walk(local->floor_l_1, DYN_FLOOR_L_1_WALK_TO_X, DYN_FLOOR_L_1_WALK_TO_Y, 5);
+ local->floor_l_2 = kernel_add_dynamic(words_floor, words_walk_across, SYNTAX_SINGULAR, KERNEL_NONE,
+ DYN_FLOOR_L_2_X, DYN_FLOOR_L_2_Y,
+ DYN_FLOOR_L_2_X_SIZE, DYN_FLOOR_L_2_Y_SIZE);
+ kernel_dynamic_hot[local->floor_l_2].prep = PREP_ON;
+ kernel_dynamic_walk(local->floor_l_2, DYN_FLOOR_L_2_WALK_TO_X, DYN_FLOOR_L_2_WALK_TO_Y, 5);
+ local->prompt_5 = kernel_add_dynamic(words_prompter_s_stand, words_climb, SYNTAX_SINGULAR, KERNEL_NONE,
+ DYN_PROMPT_LEFT_5_X, DYN_PROMPT_LEFT_5_Y,
+ DYN_PROMPT_X_SIZE_5, DYN_PROMPT_Y_SIZE_5);
+ kernel_dynamic_hot[local->prompt_5].prep = PREP_ON;
+ kernel_dynamic_walk(local->prompt_5, PROMPT_UP_LEFT_X, PROMPT_UP_LEFT_Y, FACING_SOUTHWEST);
+ kernel_dynamic_cursor(local->prompt_5, CURSOR_UP);
+ kernel_load_variant(0);
+ room_103_adjust_rails(0);
+ }
+ break;
+ }
+ }
+ } else {
+ if (global[jacques_name_is_known]) {
+ text_show(text_103_40);
+ } else {
+ text_show(text_103_50);
+ }
+ /* Jacques would fall over */
+ }
+ goto handled;
+ }
+
+
+ /* ================ Open door on right ======================= */
+
+ if (player_said_2(walk_through, door) || player_said_2(open, door) ||
+ player_said_2(unlock, door) || player_said_2(lock, door)) {
+ if ((global[current_year] == 1881) && !player_said_2(lock, door) && !player_said_2(unlock, door)) {
+ switch (kernel.trigger) {
+ case 0:
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_take_6] = kernel_seq_pingpong(ss[fx_take_6], false, 5, 0, 0, 2);
+ kernel_seq_range(seq[fx_take_6], KERNEL_FIRST, KERNEL_LAST);
+ kernel_seq_player(seq[fx_take_6], true);
+ kernel_seq_trigger(seq[fx_take_6], KERNEL_TRIGGER_EXPIRE, 0, 2);
+ kernel_seq_trigger(seq[fx_take_6], KERNEL_TRIGGER_SPRITE, 3, ROOM_103_DOOR_OPENS);
+ break;
+
+ case ROOM_103_DOOR_OPENS:
+ sound_play(N_DoorOpens);
+ kernel_seq_delete(seq[fx_door]);
+ seq[fx_door] = kernel_seq_forward(ss[fx_door], false, 8, 0, 0, 1);
+ kernel_seq_depth(seq[fx_door], 14);
+ kernel_seq_range(seq[fx_door], KERNEL_FIRST, KERNEL_LAST);
+ kernel_seq_trigger(seq[fx_door], KERNEL_TRIGGER_EXPIRE, 0, ROOM_103_DOOR_OPENS + 1);
+ sound_play(N_SqueakyDoor);
+ break;
+
+ case ROOM_103_DOOR_OPENS + 1:
+ temp = seq[fx_door];
+ seq[fx_door] = kernel_seq_stamp(ss[fx_door], false, KERNEL_LAST);
+ kernel_synch(KERNEL_SERIES, seq[fx_door], KERNEL_SERIES, temp);
+ kernel_seq_depth(seq[fx_door], 14);
+ break;
+
+ case 2:
+ player.walker_visible = true;
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_SERIES, seq[fx_take_6]);
+ player_walk(WALK_TO_X_OPEN_DOOR, WALK_TO_Y_OPEN_DOOR, FACING_WEST);
+ kernel_timing_trigger(THREE_SECONDS, 3);
+ break;
+
+ case 3:
+ new_room = 105;
+ break;
+ }
+ } else {
+ switch (kernel.trigger) {
+ case 0:
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_take_6] = kernel_seq_forward(ss[fx_take_6], false, 5, 0, 0, 1);
+ kernel_seq_range(seq[fx_take_6], 1, 4);
+ kernel_seq_player(seq[fx_take_6], true);
+ kernel_seq_trigger(seq[fx_take_6], KERNEL_TRIGGER_EXPIRE, 0, 1);
+ break;
+
+ case 1:
+ temp = seq[fx_take_6];
+ seq[fx_take_6] = kernel_seq_stamp(ss[fx_take_6], false, 4);
+ kernel_synch(KERNEL_SERIES, seq[fx_take_6], KERNEL_SERIES, temp);
+ kernel_seq_player(seq[fx_take_6], false);
+ kernel_timing_trigger(QUARTER_SECOND, 2);
+ sound_play(N_DoorHandle);
+ break;
+
+ case 2:
+ kernel_seq_delete(seq[fx_take_6]);
+ seq[fx_take_6] = kernel_seq_backward(ss[fx_take_6], false, 5, 0, 0, 1);
+ kernel_seq_range(seq[fx_take_6], 1, 4);
+ kernel_seq_player(seq[fx_take_6], false);
+ kernel_seq_trigger(seq[fx_take_6], KERNEL_TRIGGER_EXPIRE, 0, 3);
+ break;
+
+ case 3:
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_SERIES, seq[fx_take_6]);
+ player.walker_visible = true;
+ if (player_said_1(lock) || player_said_1(unlock)) {
+ text_show(text_000_32);
+ /* the key does not work here */
+ } else {
+ text_show(text_103_35);
+ /* the door is locked */
+ }
+ player.commands_allowed = true;
+ break;
+ }
+ }
+ goto handled;
+ }
+
+
+ /* ======================== Take key ========================= */
+
+ if (player_said_2(take, key) &&
+ (object_is_here(key) || kernel.trigger)) {
+ switch (kernel.trigger) {
+ case 0:
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_bend_down_9] = kernel_seq_pingpong(ss[fx_bend_down_9], false, 5, 0, 0, 2);
+ kernel_seq_range(seq[fx_bend_down_9], 1, 5);
+ kernel_seq_player(seq[fx_bend_down_9], true);
+ kernel_seq_trigger(seq[fx_bend_down_9], KERNEL_TRIGGER_SPRITE, 5, 1);
+ kernel_seq_trigger(seq[fx_bend_down_9], KERNEL_TRIGGER_EXPIRE, 0, 2);
+ goto handled;
+ break;
+
+ case 1:
+ kernel_seq_delete(seq[fx_key]);
+ kernel_flip_hotspot(words_key, false);
+ inter_give_to_player(key);
+ sound_play(N_TakeObjectSnd);
+ goto handled;
+ break;
+
+ case 2:
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_SERIES, seq[fx_bend_down_9]);
+ player.walker_visible = true;
+ kernel_timing_trigger(20, 3);
+ goto handled;
+ break;
+
+ case 3:
+ global[player_score] += 5;
+ object_examine(key, text_008_00, 0);
+ /* you pick up the key */
+ player.commands_allowed = true;
+ goto handled;
+ break;
+ }
+ }
+
+
+ /* ============= Run conv if talk to Jacques ================= */
+
+ if (player_said_2(talk_to, gentleman) ||
+ player_said_2(talk_to, Jacques)) {
+ if (global[jacques_status] == JACQUES_IS_ALIVE) {
+ conv_run(CONV_JACQUES);
+ conv_export_pointer(&global[player_score]);
+ conv_export_value(global[music_selected]);
+ } else {
+ text_show(text_103_43);
+ /* you are talking to a dead man */
+ }
+ goto handled;
+ }
+
+
+ /* ================= Climb thru trap door ==================== */
+
+ if (player_said_2(climb_through, trap_door) || local->climb_thru) {
+ if ((local->top_of_stand == YES_RIGHT) && (global[trap_door_status] == TRAP_DOOR_IS_OPEN)) {
+ switch (kernel.trigger) {
+ case 0:
+ case ROOM_103_CLIMB_OUT_TRAP:
+
+ if (!(global[player_score_flags] & SCORE_TRAP_DOOR)) {
+ global[player_score_flags] = global[player_score_flags] | SCORE_TRAP_DOOR;
+ global[player_score] += 3;
+ }
+
+ kernel_abort_animation(aa[3]);
+ local->anim_3_running = false;
+ local->climb_thru = false;
+ player.commands_allowed = false;
+ seq[fx_up_trap_door] = kernel_seq_forward(ss[fx_up_trap_door], false, 6, 0, 0, 1);
+ kernel_seq_depth(seq[fx_up_trap_door], 5);
+ kernel_seq_range(seq[fx_up_trap_door], KERNEL_FIRST, KERNEL_LAST);
+ kernel_seq_trigger(seq[fx_up_trap_door], KERNEL_TRIGGER_EXPIRE, 0, 1);
+ break;
+
+ case 1:
+ global[room_103_104_transition] = NEW_ROOM;
+ new_room = 104;
+ break;
+ }
+ }
+ goto handled;
+ }
+
+
+ /* ============= Looking thru prompter's box ================= */
+
+ if (player_said_2(look_through, prompter_s_box) || local->sit_on_it) {
+ if (local->top_of_stand == YES_LEFT) {
+ switch (kernel.trigger) {
+ case 0:
+ case ROOM_103_LOOK_THRU_BOX:
+ kernel_abort_animation(aa[5]);
+ local->anim_5_running = false;
+ player.commands_allowed = false;
+ seq[fx_on_seat] = kernel_seq_forward(ss[fx_on_seat], false, 6, 0, 0, 1);
+ kernel_seq_depth(seq[fx_on_seat], 4);
+ kernel_seq_range(seq[fx_on_seat], KERNEL_FIRST, KERNEL_LAST);
+ kernel_seq_trigger(seq[fx_on_seat], KERNEL_TRIGGER_EXPIRE, 0, 1);
+ if (!local->sit_on_it) {
+ kernel_synch(KERNEL_SERIES, seq[fx_on_seat], KERNEL_ANIM, aa[5]);
+ }
+ local->sit_on_it = false;
+ break;
+
+ case 1:
+ global[room_103_104_transition] = PEEK_THROUGH;
+ new_room = 104;
+ break;
+ }
+ }
+ goto handled;
+ }
+
+
+ /* =========== Pull lever to open/close trap door ============ */
+
+ if ((player_said_2(push, lever)) || (player_said_2(pull, lever))) {
+ if (global[trap_door_status] == TRAP_DOOR_IS_CLOSED) {
+ switch (kernel.trigger) {
+ case 0:
+ aa[1] = kernel_run_animation(kernel_name('l', 1), 1);
+ local->anim_1_running = true;
+ player.walker_visible = false;
+ player.commands_allowed = false;
+ kernel_synch(KERNEL_ANIM, aa[1], KERNEL_PLAYER, 0);
+ break;
+
+ case 1:
+ local->anim_1_running = false;
+ player.walker_visible = true;
+ global[trap_door_status] = TRAP_DOOR_IS_OPEN;
+ player.commands_allowed = true;
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_ANIM, aa[1]);
+ break;
+ }
+ } else {
+ switch (kernel.trigger) {
+ case 0:
+ aa[2] = kernel_run_animation(kernel_name('l', 2), 1);
+ local->anim_2_running = true;
+ player.walker_visible = false;
+ player.commands_allowed = false;
+ kernel_synch(KERNEL_ANIM, aa[2], KERNEL_PLAYER, 0);
+ break;
+
+ case 1:
+ local->anim_2_running = false;
+ player.walker_visible = true;
+ global[trap_door_status] = TRAP_DOOR_IS_CLOSED;
+ player.commands_allowed = true;
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_ANIM, aa[2]);
+ break;
+ }
+ }
+ goto handled;
+ }
+
+
+ /* ======================== Look around ====================== */
+
+ if (player.look_around) {
+ if ((global[current_year] == 1881) && (global[jacques_status] >= JACQUES_IS_DEAD)) {
+ text_show(text_103_11);
+ } else {
+ text_show(text_103_10);
+ }
+ goto handled;
+ }
+
+ if (player_said_1(look) || player_said_1(look_at)) {
+
+ if (player_said_1(prompter_s_stand)) {
+ if (global[jacques_status] >= JACQUES_IS_DEAD) {
+ text_show(text_103_49);
+ } else if (global[current_year] == 1993) {
+ text_show(text_103_12);
+ } else {
+ text_show(text_103_45);
+ }
+ goto handled;
+ }
+
+ if (player_said_1(floor)) {
+ text_show(text_103_13);
+ goto handled;
+ }
+
+ if (player_said_1(trap_ceiling)) {
+ text_show(text_103_14);
+ goto handled;
+ }
+
+ if (player_said_1(door)) {
+ text_show(text_103_15);
+ goto handled;
+ }
+
+ if (player_said_1(door_to_pit)) {
+ text_show(text_103_16);
+ goto handled;
+ }
+
+ if (player_said_1(wall)) {
+ text_show(text_103_17);
+ goto handled;
+ }
+
+ if (player_said_1(prompter_s_box)) {
+ text_show(text_103_18);
+ goto handled;
+ }
+
+ if (player_said_1(trap_door)) {
+ text_show(text_103_19);
+ goto handled;
+ }
+
+ if (player_said_1(junk)) {
+ if (global[current_year] == 1993) {
+ text_show(text_103_20);
+ } else {
+ text_show(text_103_46);
+ }
+ goto handled;
+ }
+
+ if (player_said_1(carton)) {
+ if (global[current_year] == 1993) {
+ text_show(text_103_21);
+ } else {
+ text_show(text_103_47);
+ }
+ goto handled;
+ }
+
+ if (player_said_1(garbage_can)) {
+ if (global[current_year] == 1993) {
+ text_show(text_103_22);
+ } else {
+ text_show(text_103_48);
+ }
+ goto handled;
+ }
+
+ if (player_said_1(cable)) {
+ text_show(text_103_23);
+ goto handled;
+ }
+
+ if (player_said_1(Jacques) || player_said_1(gentleman)) {
+ if (global[jacques_status] == JACQUES_IS_ALIVE) {
+ text_show(text_103_24);
+ } else {
+ text_show(text_103_25);
+ }
+ goto handled;
+ }
+
+ if (player_said_1(key)) {
+ if (object_is_here(key)) {
+ text_show(text_103_26);
+ goto handled;
+ }
+ }
+
+ if (player_said_1(stair_unit)) {
+ text_show(text_103_27);
+ goto handled;
+ }
+
+ if (player_said_1(exposed_brick)) {
+ text_show(text_103_28);
+ goto handled;
+ }
+
+ if (player_said_1(water_pipe)) {
+ text_show(text_103_29);
+ goto handled;
+ }
+
+ if (player_said_1(prompter_s_seat)) {
+ text_show(text_103_38);
+ goto handled;
+ }
+
+ if (player_said_1(lever)) {
+ text_show(text_103_39);
+ goto handled;
+ }
+ }
+
+ if (player_said_2(close, door_to_pit)) {
+ text_show(text_103_31);
+ goto handled;
+ }
+
+ if (player_said_2(close, door)) {
+ text_show(text_103_31);
+ goto handled;
+ }
+
+ if ((player_said_2(open, trap_door)) || (player_said_2(close, trap_door))) {
+ text_show(text_103_44);
+ goto handled;
+ }
+
+ if (player_said_2(take, Jacques) || player_said_2(take, gentleman)) {
+ if (global[jacques_status] == JACQUES_IS_ALIVE) {
+ if (global[jacques_name_is_known]) {
+ text_show(text_103_36);
+ } else {
+ text_show(text_103_51);
+ }
+ } else {
+ text_show(text_103_37);
+ }
+ goto handled;
+ }
+
+
+ goto done;
+
+handled:
+ player.command_ready = false;
+
+done:
+ ;
+}
+
+
+void room_103_preload(void) {
+ room_init_code_pointer = room_103_init;
+ room_pre_parser_code_pointer = room_103_pre_parser;
+ room_parser_code_pointer = room_103_parser;
+ room_daemon_code_pointer = room_103_daemon;
+
+ section_1_walker();
+ section_1_interface();
+
+ kernel_initial_variant = 0;
+
+ if ((global[prompter_stand_status] == PROMPT_RIGHT) || (global[current_year] == 1881)) {
+ kernel_initial_variant = 1;
+ if ((global[jacques_status] == JACQUES_IS_ALIVE) && (global[current_year] == 1881)) {
+ kernel_initial_variant = 2;
+ } else if ((global[jacques_status] >= JACQUES_IS_DEAD) && (global[current_year] == 1881)) {
+ kernel_initial_variant = 3;
+ }
+ }
+
+ vocab_make_active(words_prompter_s_stand);
+ vocab_make_active(words_Jacques);
+ vocab_make_active(words_gentleman);
+ vocab_make_active(words_climb);
+}
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/rooms/room103.h b/engines/mads/madsv2/phantom/rooms/room103.h
new file mode 100644
index 00000000000..c11aeedf14f
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room103.h
@@ -0,0 +1,311 @@
+/* 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 MADS_PHANTOM_ROOMS_103_H
+#define MADS_PHANTOM_ROOMS_103_H
+
+#include "mads/madsv2/core/general.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+#define local ((Scratch *)(&game.scratch[0]))
+#define ss local->sprite
+#define seq local->sequence
+#define aa local->animation
+
+typedef struct { /* Room local variables */
+ int sprite[20]; /* Sprite series handles */
+ int sequence[20]; /* Sequence handles */
+ int animation[7]; /* Animation handles */
+ int prompt_1; /* Dynamic var for prompter's stand */
+ int prompt_2; /* Dynamic var for prompter's stand */
+ int prompt_3; /* Dynamic var for prompter's stand */
+ int prompt_4; /* Dynamic var for prompter's stand */
+ int prompt_5; /* Dynamic var for prompter's stand */
+ int floor_r_1; /* Dynamic var for floor */
+ int floor_r_2; /* Dynamic var for floor */
+ int floor_l_1; /* Dynamic var for floor */
+ int floor_l_2; /* Dynamic var for floor */
+ int man; /* Dynamic var for man / Jacques */
+
+ int jacques_frame;
+ int jacques_action;
+ int jacques_talk_count;
+
+ int just_did_option;
+ int anim_0_running;
+ int anim_1_running;
+ int anim_2_running;
+ int anim_3_running;
+ int anim_4_running;
+ int anim_5_running;
+ int anim_6_running;
+
+ int top_of_stand; /* Either NO, YES_LEFT, or YES_RIGHT */
+
+ int converse_counter; /* counter for talking displacements */
+ int frame_guard; /* guards against running certain daemon code more than once */
+
+ int stairs_frame;
+ int climb_thru;
+ int sit_on_it;
+} Scratch;
+
+
+/* ========================= Sprite Series =================== */
+
+#define fx_trap_door 0 /* rm103x0 */
+#define fx_door 1 /* rm103x1 */
+#define fx_take_6 2 /* rdr_6 */
+#define fx_steps 3 /* rm103f0 */
+#define fx_take_9 4 /* rdr_9 */
+#define fx_key 5 /* rm103x2 */
+#define fx_jacques_body 6 /* rm103c1 */
+#define fx_broken_promp 7 /* rm103f1 */
+#define fx_bend_down_9 8 /* rrd_9 */
+#define fx_lever 9 /* rm103x3 */
+#define fx_on_seat 10 /* rm103a3 */
+#define fx_up_trap_door 11 /* rm103a2 */
+#define fx_rail_pieces 12 /* rm103f2 */
+
+
+/* ======================== Jacques actions ================== */
+
+#define CONV12_JAC_TALK 0
+#define CONV12_JAC_SHUT_UP 1
+#define CONV12_JAC_POINT 2
+#define CONV12_JAC_I_DUNNO_1 3
+#define CONV12_JAC_I_DUNNO_2 4
+
+
+/* ========================= Triggers ======================== */
+
+#define ROOM_103_TRAP_DOOR_OPENS 60
+#define ROOM_103_TRAP_DOOR_CLOSES 62
+#define ROOM_103_DOOR_CLOSES 65
+#define ROOM_103_DOOR_OPENS 70
+#define ROOM_103_DONE_MOVING_PROMPT 75
+#define ROOM_103_DIED 80
+#define ROOM_103_JACQUES_TALK 90
+#define ROOM_103_JACQUES_SHUT_UP 92
+#define ROOM_103_JACQUES_POINT 94
+#define ROOM_103_JACQUES_I_DUNNO_1 96
+#define ROOM_103_JACQUES_I_DUNNO_2 98
+
+#define ROOM_103_GET_OFF_SEAT 100
+
+#define ROOM_103_SWITCH_DOWN 105
+#define ROOM_103_SWITCH_UP 110
+#define ROOM_103_LOOK_THRU_BOX 115
+#define ROOM_103_CLIMB_OUT_TRAP 120
+
+
+/* ======================= Other Macros ====================== */
+
+#define CONV_JACQUES 12
+
+#define PLAYER_X_FROM_102 15
+#define PLAYER_Y_FROM_102 147
+
+#define PLAYER_X_FROM_105 287
+#define PLAYER_Y_FROM_105 135
+
+#define WALK_TO_X_FROM_105 252
+#define WALK_TO_Y_FROM_105 134
+
+#define WALK_TO_X_OPEN_DOOR 295
+#define WALK_TO_Y_OPEN_DOOR 132
+
+#define OFF_SCREEN_X_FROM_102 -20
+#define OFF_SCREEN_Y_FROM_102 140
+
+#define WALKER_LEFT_PROMPT_X 2
+#define WALKER_LEFT_PROMPT_Y 138
+
+#define WALKER_RIGHT_PROMPT_X 176
+#define WALKER_RIGHT_PROMPT_Y 142
+
+#define PROMPT_LEFT_X 37
+#define PROMPT_LEFT_Y 139
+
+#define PROMPT_RIGHT_X 154
+#define PROMPT_RIGHT_Y 139
+
+#define DYN_PROMPT_LEFT_1_X 2
+#define DYN_PROMPT_LEFT_1_Y 79
+#define DYN_PROMPT_X_SIZE_1 40
+#define DYN_PROMPT_Y_SIZE_1 63
+
+#define DYN_PROMPT_LEFT_2_X 42
+#define DYN_PROMPT_LEFT_2_Y 67
+#define DYN_PROMPT_X_SIZE_2 16
+#define DYN_PROMPT_Y_SIZE_2 75
+
+#define DYN_PROMPT_LEFT_3_X 58
+#define DYN_PROMPT_LEFT_3_Y 90
+#define DYN_PROMPT_X_SIZE_3 18
+#define DYN_PROMPT_Y_SIZE_3 52
+
+#define DYN_PROMPT_LEFT_5_X 2
+#define DYN_PROMPT_LEFT_5_Y 49
+#define DYN_PROMPT_X_SIZE_5 40
+#define DYN_PROMPT_Y_SIZE_5 30
+
+#define DYN_PROMPT_L_WALK_TO_X 59
+#define DYN_PROMPT_L_WALK_TO_Y 140
+
+#define DYN_PROMPT_RIGHT_1_X 121
+#define DYN_PROMPT_RIGHT_1_Y 79
+
+#define DYN_PROMPT_RIGHT_2_X 161
+#define DYN_PROMPT_RIGHT_2_Y 67
+
+#define DYN_PROMPT_RIGHT_3_X 177
+#define DYN_PROMPT_RIGHT_3_Y 90
+
+#define DYN_PROMPT_RIGHT_4_X 114
+#define DYN_PROMPT_RIGHT_4_Y 100
+#define DYN_PROMPT_X_SIZE_4 7
+#define DYN_PROMPT_Y_SIZE_4 38
+
+#define DYN_PROMPT_RIGHT_5_X 121
+
+#define DYN_PROMPT_R_WALK_TO_X 171
+#define DYN_PROMPT_R_WALK_TO_Y 142
+
+#define DYN_PROMPT_R_WALK_TO_X_JAC 115
+#define DYN_PROMPT_R_WALK_TO_Y_JAC 142
+
+#define AFTER_STEPS_FROM_LEFT_X 117
+#define AFTER_STEPS_FROM_LEFT_Y 139
+
+#define AFTER_STEPS_FROM_RIGHT_X 62
+#define AFTER_STEPS_FROM_RIGHT_Y 142
+
+#define DYN_FLOOR_R_1_X 154
+#define DYN_FLOOR_R_1_Y 136
+#define DYN_FLOOR_R_1_X_SIZE 41
+#define DYN_FLOOR_R_1_Y_SIZE 6
+#define DYN_FLOOR_R_1_WALK_TO_X 171
+#define DYN_FLOOR_R_1_WALK_TO_Y 142
+
+#define DYN_FLOOR_R_2_X 114
+#define DYN_FLOOR_R_2_Y 136
+#define DYN_FLOOR_R_2_X_SIZE 32
+#define DYN_FLOOR_R_2_Y_SIZE 6
+#define DYN_FLOOR_R_2_WALK_TO_X 127
+#define DYN_FLOOR_R_2_WALK_TO_Y 140
+
+#define DYN_FLOOR_R_3_X 149
+#define DYN_FLOOR_R_3_Y 140
+#define DYN_FLOOR_R_3_X_SIZE 13
+#define DYN_FLOOR_R_3_Y_SIZE 7
+#define DYN_FLOOR_R_3_WALK_TO_X 155
+#define DYN_FLOOR_R_3_WALK_TO_Y 144
+
+#define DYN_FLOOR_R_4_X 187
+#define DYN_FLOOR_R_4_Y 136
+#define DYN_FLOOR_R_4_X_SIZE 8
+#define DYN_FLOOR_R_4_Y_SIZE 7
+#define DYN_FLOOR_R_4_WALK_TO_X 195
+#define DYN_FLOOR_R_4_WALK_TO_Y 139
+
+#define DYN_FLOOR_R_5_X 94
+#define DYN_FLOOR_R_5_Y 129
+#define DYN_FLOOR_R_5_X_SIZE 18
+#define DYN_FLOOR_R_5_Y_SIZE 4
+#define DYN_FLOOR_R_5_WALK_TO_X 95
+#define DYN_FLOOR_R_5_WALK_TO_Y 133
+
+#define DYN_FLOOR_R_6_X 94
+#define DYN_FLOOR_R_6_Y 132
+#define DYN_FLOOR_R_6_X_SIZE 3
+#define DYN_FLOOR_R_6_Y_SIZE 9
+#define DYN_FLOOR_R_6_WALK_TO_X 93
+#define DYN_FLOOR_R_6_WALK_TO_Y 135
+
+#define DYN_FLOOR_R_7_X 112
+#define DYN_FLOOR_R_7_Y 150
+#define DYN_FLOOR_R_7_X_SIZE 21
+#define DYN_FLOOR_R_7_Y_SIZE 3
+#define DYN_FLOOR_R_7_WALK_TO_X 118
+#define DYN_FLOOR_R_7_WALK_TO_Y 154
+
+#define DYN_FLOOR_R_8_X 98
+#define DYN_FLOOR_R_8_Y 146
+#define DYN_FLOOR_R_8_X_SIZE 21
+#define DYN_FLOOR_R_8_Y_SIZE 4
+#define DYN_FLOOR_R_8_WALK_TO_X 104
+#define DYN_FLOOR_R_8_WALK_TO_Y 148
+
+#define DYN_FLOOR_L_1_X 35
+#define DYN_FLOOR_L_1_Y 137
+#define DYN_FLOOR_L_1_X_SIZE 40
+#define DYN_FLOOR_L_1_Y_SIZE 5
+#define DYN_FLOOR_L_1_WALK_TO_X 59
+#define DYN_FLOOR_L_1_WALK_TO_Y 140
+
+#define DYN_FLOOR_L_2_X 76
+#define DYN_FLOOR_L_2_Y 129
+#define DYN_FLOOR_L_2_X_SIZE 6
+#define DYN_FLOOR_L_2_Y_SIZE 6
+#define DYN_FLOOR_L_2_WALK_TO_X 80
+#define DYN_FLOOR_L_2_WALK_TO_Y 135
+
+#define DYN_JAC_X 156
+#define DYN_JAC_Y 116
+#define DYN_JAC_X_SIZE 33
+#define DYN_JAC_Y_SIZE 31
+#define DYN_JAC_WALK_TO_X 206
+#define DYN_JAC_WALK_TO_Y 148
+
+#define DYN_JAC_BODY_X 114
+#define DYN_JAC_BODY_Y 132
+#define DYN_JAC_BODY_X_SIZE 30
+#define DYN_JAC_BODY_Y_SIZE 10
+#define DYN_JAC_BODY_WALK_TO_X 95
+#define DYN_JAC_BODY_WALK_TO_Y 144
+
+#define PROMPT_UP_LEFT_X 79
+#define PROMPT_UP_LEFT_Y 132
+
+#define PROMPT_UP_RIGHT_X 196
+#define PROMPT_UP_RIGHT_Y 134
+
+#define DEATH_X 150
+#define DEATH_Y 147
+
+#define NO 0
+#define YES_LEFT 1
+#define YES_RIGHT 2
+
+#define LEAVE_LEFT_X 0
+#define LEAVE_LEFT_Y 150
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index 78ca73d7502..32517f742ae 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -124,6 +124,7 @@ MODULE_OBJS += \
madsv2/phantom/rooms/section1.o \
madsv2/phantom/rooms/room101.o \
madsv2/phantom/rooms/room102.o \
+ madsv2/phantom/rooms/room103.o \
madsv2/phantom/phantom.o \
madsv2/phantom/conv.o \
madsv2/phantom/main_menu.o \
Commit: 879ea943ba130ad4862f1b8b6e340a967bc3ecc2
https://github.com/scummvm/scummvm/commit/879ea943ba130ad4862f1b8b6e340a967bc3ecc2
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:39+10:00
Commit Message:
MADS: PHANTOM: Added Claude generated ASound implementations
Changed paths:
engines/mads/madsv2/phantom/sound_phantom.cpp
engines/mads/madsv2/phantom/sound_phantom.h
diff --git a/engines/mads/madsv2/phantom/sound_phantom.cpp b/engines/mads/madsv2/phantom/sound_phantom.cpp
index 43bd5fbf68f..c2a49ccc3b4 100644
--- a/engines/mads/madsv2/phantom/sound_phantom.cpp
+++ b/engines/mads/madsv2/phantom/sound_phantom.cpp
@@ -83,51 +83,1409 @@ void PhantomSoundManager::loadDriver(int sectionNumber) {
/*-----------------------------------------------------------------------*/
-ASound1::ASound1(Audio::Mixer *mixer, OPL::OPL *opl) : ASound(mixer, opl, "asound.ph1", 0x21e0) {
+/*-----------------------------------------------------------------------*/
+/* ASound1 (asound.ph1) *
+ * *
+ * Channel-load helpers in the original: *
+ * sub_103FF=ch0, sub_10404=ch1, sub_10409=ch2 *
+ * sub_1040E=ch3, sub_10413=ch4, sub_10418=ch5 *
+ * loc_1041D=ch6, loc_10422=ch7, loc_10427=ch8 *
+ * *
+ * sub_106DF = isSoundActive guard (non-zero BX â already playing) *
+ * sub_1039C = playSoundData(pData, ADLIB_CHANNEL_MIDWAY) (upper pool) *
+ * sub_10352 = playSoundData(pData, 0) (lower pool) *
+ *-----------------------------------------------------------------------*/
+
+const ASound1::CommandPtr ASound1::_commandList[40] = {
+ &ASound1::command0, &ASound1::command1, &ASound1::command2, &ASound1::command3,
+ &ASound1::command4, &ASound1::command5, &ASound1::command6, &ASound1::command7,
+ &ASound1::command8, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr,
+ &ASound1::command16, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr,
+ &ASound1::command24, &ASound1::command25, &ASound1::command26, &ASound1::command27,
+ nullptr, nullptr, nullptr, nullptr,
+ &ASound1::command32, &ASound1::command33, &ASound1::command34, &ASound1::command35,
+ &ASound1::command36, &ASound1::command37, &ASound1::command38, &ASound1::command39
+};
+
+ASound1::ASound1(Audio::Mixer *mixer, OPL::OPL *opl)
+ : ASound(mixer, opl, "asound.ph1", 0x21e0), _musicIndex(0) {
+}
+
+int ASound1::command(int commandId, int param) {
+ // The original dispatcher also handles commands 64â76 via a raw-data
+ // near-pointer table (unk_13C3E) that cannot be safely reconstructed.
+ if (commandId > 39 || !_commandList[commandId])
+ return 0;
+
+ _commandParam = param;
+ _frameCounter = 0;
+ return (this->*_commandList[commandId])();
+}
+
+// commands 0â8: delegate to base ASound
+int ASound1::command0() { return ASound::command0(); }
+int ASound1::command1() { return ASound::command1(); }
+int ASound1::command2() { return ASound::command2(); }
+int ASound1::command3() { return ASound::command3(); }
+int ASound1::command4() { return ASound::command4(); }
+int ASound1::command5() { return ASound::command5(); }
+int ASound1::command6() { return ASound::command6(); }
+int ASound1::command7() { return ASound::command7(); }
+int ASound1::command8() { return ASound::command8(); }
+
+// ---------------------------------------------------------------------------
+// Background-music loaders (sub_11D84, sub_11EE6, sub_11F0E, sub_11F36)
+// Each calls command1() then loads six channels.
+// The five cx values that command16 checks against _channels[0]._field17
+// are the starting offsets of each piece: 0x1ECA, 0x21C4, 0x3418, 0x3688,
+// 0x3D52. (0x21C4 is the start of dead code following commandMusic0 that
+// was never reached by any dispatch table entry.)
+// ---------------------------------------------------------------------------
+
+int ASound1::commandMusic0() {
+ ASound::command1();
+ _channels[0].load(loadData(0x1ECA, 245));
+ _channels[1].load(loadData(0x1FBF, 120));
+ _channels[2].load(loadData(0x2037, 183));
+ _channels[3].load(loadData(0x20EE, 173));
+ _channels[4].load(loadData(0x219B, 20));
+ _channels[5].load(loadData(0x21AF, 21));
+ return 0;
+}
+
+int ASound1::commandMusic1() {
+ ASound::command1();
+ _channels[0].load(loadData(0x3418, 211));
+ _channels[1].load(loadData(0x34EB, 176));
+ _channels[2].load(loadData(0x359B, 189));
+ _channels[3].load(loadData(0x3658, 15));
+ _channels[4].load(loadData(0x3667, 16));
+ _channels[5].load(loadData(0x3677, 17));
+ return 0;
+}
+
+int ASound1::commandMusic2() {
+ ASound::command1();
+ _channels[0].load(loadData(0x3688, 499));
+ _channels[1].load(loadData(0x387B, 390));
+ _channels[2].load(loadData(0x3A01, 453));
+ _channels[3].load(loadData(0x3BC6, 363));
+ _channels[4].load(loadData(0x3D31, 16));
+ _channels[5].load(loadData(0x3D41, 17));
+ return 0;
+}
+
+int ASound1::commandMusic3() {
+ ASound::command1();
+ _channels[0].load(loadData(0x3D52, 641));
+ _channels[1].load(loadData(0x3FD3, 556));
+ _channels[2].load(loadData(0x41FF, 13));
+ _channels[3].load(loadData(0x420C, 13));
+ _channels[4].load(loadData(0x4219, 16));
+ _channels[5].load(loadData(0x4229, 17));
+ return 0;
+}
+
+// ---------------------------------------------------------------------------
+// command16 (sub_11F70) â random background music
+//
+// If channel 0 is active and already playing one of the five known music
+// pieces (identified by their starting offset in field_17), leave it alone.
+// Otherwise pick a piece at random: the original uses getRandomNumber() & 7,
+// discarding 0 and indexing a four-entry table repeated twice (entries 1â3
+// â pieces 1â3, entries 4â7 â same pieces again with entry 4 wrapping to
+// piece 0). We reproduce this with a modulo-4 on a non-zero value.
+// ---------------------------------------------------------------------------
+int ASound1::command16() {
+ if (_channels[0]._activeCount) {
+ int f = _channels[0]._field17;
+ if (f == 0x1ECA || f == 0x21C4 ||
+ f == 0x3418 || f == 0x3688 || f == 0x3D52)
+ return 0;
+ }
+
+ int idx;
+ do {
+ idx = getRandomNumber() & 3;
+ } while (idx == 0);
+ _musicIndex = idx;
+
+ typedef int (ASound1::*MusicPtr)();
+ static const MusicPtr musicTable[4] = {
+ &ASound1::commandMusic0,
+ &ASound1::commandMusic1,
+ &ASound1::commandMusic2,
+ &ASound1::commandMusic3
+ };
+ return (this->*musicTable[idx])();
+}
+
+// ---------------------------------------------------------------------------
+// commands 24â27 (off_11C46) â upper channel pool (sub_1039C per entry)
+// ---------------------------------------------------------------------------
+
+int ASound1::command24() {
+ playSound(0x173A, 51);
+ playSound(0x176D, 46);
+ return 0;
+}
+
+int ASound1::command25() {
+ playSound(0x179B, 44);
+ playSound(0x17C7, 46);
+ return 0;
+}
+
+int ASound1::command26() {
+ playSound(0x17F5, 12);
+ return 0;
+}
+
+int ASound1::command27() {
+ playSound(0x1801, 81);
+ return 0;
+}
+
+// ---------------------------------------------------------------------------
+// commands 32â39 (off_11C4E, entries 0â7)
+// ---------------------------------------------------------------------------
+
+// command32 (sub_11DD4) â no guard, no fade, load ch0â5
+int ASound1::command32() {
+ _channels[0].load(loadData(0x2522, 59));
+ _channels[1].load(loadData(0x255D, 52));
+ _channels[2].load(loadData(0x2591, 42));
+ _channels[3].load(loadData(0x25BB, 44));
+ _channels[4].load(loadData(0x25E7, 44));
+ _channels[5].load(loadData(0x2613, 89));
+ return 0;
+}
+
+// command33 (sub_11E02) â isSoundActive guard, command1, load ch0â5
+int ASound1::command33() {
+ byte *pData = loadData(0x266C, 701);
+ if (!isSoundActive(pData)) {
+ ASound::command1();
+ _channels[0].load(pData);
+ _channels[1].load(loadData(0x2929, 500));
+ _channels[2].load(loadData(0x2B1D, 538));
+ _channels[3].load(loadData(0x2D37, 396));
+ _channels[4].load(loadData(0x2EC3, 368));
+ _channels[5].load(loadData(0x3033, 493));
+ }
+ return 0;
+}
+
+// command34 (sub_11D54) â isSoundActive guard, stop(), load ch0â5
+int ASound1::command34() {
+ byte *pData = loadData(0x1852, 599);
+ if (!isSoundActive(pData)) {
+ stop();
+ _channels[0].load(pData);
+ _channels[1].load(loadData(0x1AA9, 283));
+ _channels[2].load(loadData(0x1BC4, 301));
+ _channels[3].load(loadData(0x1CF1, 257));
+ _channels[4].load(loadData(0x1DF2, 204));
+ _channels[5].load(loadData(0x1EBE, 12));
+ }
+ return 0;
+}
+
+// command35 (sub_11CCC) â isSoundActive guard, command2 (lower-bank fade),
+// load ch0â5
+int ASound1::command35() {
+ byte *pData = loadData(0x0C36, 329);
+ if (!isSoundActive(pData)) {
+ ASound::command2();
+ _channels[0].load(pData);
+ _channels[1].load(loadData(0x0D7F, 201));
+ _channels[2].load(loadData(0x0E48, 200));
+ _channels[3].load(loadData(0x0F10, 162));
+ _channels[4].load(loadData(0x0FB2, 228));
+ _channels[5].load(loadData(0x1096, 250));
+ }
+ return 0;
+}
+
+// command36 (sub_11CFC) â isSoundActive guard, command2 (lower-bank fade),
+// load ch0â5
+int ASound1::command36() {
+ byte *pData = loadData(0x1190, 327);
+ if (!isSoundActive(pData)) {
+ ASound::command2();
+ _channels[0].load(pData);
+ _channels[1].load(loadData(0x12D7, 211));
+ _channels[2].load(loadData(0x13AA, 204));
+ _channels[3].load(loadData(0x1476, 178));
+ _channels[4].load(loadData(0x1528, 236));
+ _channels[5].load(loadData(0x1614, 294));
+ }
+ return 0;
+}
+
+// command37 (sub_11E32) â isSoundActive guard, command1, four loadAny
+// calls starting from channel 0 (sub_10352 = playSoundData(pData, 0))
+int ASound1::command37() {
+ byte *pData = loadData(0x3220, 74);
+ if (!isSoundActive(pData)) {
+ ASound::command1();
+ playSoundData(pData, 0);
+ playSoundData(loadData(0x326A, 41), 0);
+ playSoundData(loadData(0x3293, 25), 0);
+ playSoundData(loadData(0x32AC, 14), 0);
+ }
+ return 0;
+}
+
+// command38 (sub_11D84) â alias for commandMusic0; also the direct dispatch
+// target for command 38.
+int ASound1::command38() {
+ return commandMusic0();
+}
+
+// command39 (sub_11FAE) â isSoundActive guard, command1, load ch0â5
+int ASound1::command39() {
+ byte *pData = loadData(0x423A, 421);
+ if (!isSoundActive(pData)) {
+ ASound::command1();
+ _channels[0].load(pData);
+ _channels[1].load(loadData(0x43DF, 280));
+ _channels[2].load(loadData(0x44F7, 246));
+ _channels[3].load(loadData(0x45ED, 268));
+ _channels[4].load(loadData(0x46F9, 438));
+ _channels[5].load(loadData(0x48AF, 0));
+ }
+ return 0;
+}
+
+/*-----------------------------------------------------------------------*/
+
+/*-----------------------------------------------------------------------*/
+/* ASound2 (asound.ph2) *
+ * *
+ * Dispatch table layout: *
+ * asound_commands1: commands 0â 8 (max=8, base=0) *
+ * asound_commands2: command 16 (max=0x10, base=0x10, 1 entry) *
+ * asound_commands3: commands 24â27 (max=0x1B, base=0x18, 4 entries) *
+ * asound_commands4: commands 32â35 (max=0x23, base=0x20, 4 entries) *
+ * asound_commands5: commands 64â72 (max=0x48, base=0x40, 9 entries) *
+ * *
+ * Channel-load helpers: *
+ * sub_103FF=ch0 sub_10404=ch1 sub_10409=ch2 sub_1040E=ch3 *
+ * sub_10413=ch4 sub_10418=ch5 loc_1041D=ch6 loc_10422=ch7 *
+ * (ch8 not used in any sound command) *
+ * *
+ * sub_105F3 = command1 (fade both banks) *
+ * sub_10481 = command2 (lower setPtr2, cx=0x1A26) *
+ * sub_105FA = command3 (lower bank fade helper) *
+ * sub_104A9 = command4 (upper setPtr2, cx=0x1A26) *
+ * sub_104BF = command6 *
+ * loc_10548 = command7 *
+ * unk_106B2 = command8 (OR of all channel activeCount fields) *
+ * sub_106DF = isSoundActive guard *
+ * sub_1039C = playSoundData(pData, ADLIB_CHANNEL_MIDWAY) (upper pool) *
+ * sub_10352 = playSoundData(pData, 0) (lower pool) *
+ * *
+ * commands5 entry 4 (command 68) = nullsub_3 = no-op *
+ *-----------------------------------------------------------------------*/
+
+const ASound2::CommandPtr ASound2::_commandList[73] = {
+ // commands 0â8 (asound_commands1)
+ &ASound2::command0, &ASound2::command1, &ASound2::command2, &ASound2::command3,
+ &ASound2::command4, &ASound2::command5, &ASound2::command6, &ASound2::command7,
+ &ASound2::command8,
+ // 9â15 absent
+ nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr,
+ // command 16 (asound_commands2)
+ &ASound2::command16,
+ // 17â23 absent
+ nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr,
+ // commands 24â27 (asound_commands3)
+ &ASound2::command24, &ASound2::command25, &ASound2::command26, &ASound2::command27,
+ // 28â31 absent
+ nullptr, nullptr, nullptr, nullptr,
+ // commands 32â35 (asound_commands4)
+ &ASound2::command32, &ASound2::command33, &ASound2::command34, &ASound2::command35,
+ // 36â63 absent
+ nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr,
+ // commands 64â72 (asound_commands5)
+ &ASound2::command64, &ASound2::command65, &ASound2::command66, &ASound2::command67,
+ &ASound2::command68, &ASound2::command69, &ASound2::command70, &ASound2::command71,
+ &ASound2::command72
+};
+
+ASound2::ASound2(Audio::Mixer *mixer, OPL::OPL *opl)
+ : ASound(mixer, opl, "asound.ph2", 0x2040) {
+}
+
+int ASound2::command(int commandId, int param) {
+ if (commandId > 72 || !_commandList[commandId])
+ return 0;
+
+ _commandParam = param;
+ _frameCounter = 0;
+ return (this->*_commandList[commandId])();
+}
+
+// commands 0â8: delegate to base ASound
+int ASound2::command0() { return ASound::command0(); }
+int ASound2::command1() { return ASound::command1(); }
+int ASound2::command2() { return ASound::command2(); }
+int ASound2::command3() { return ASound::command3(); }
+int ASound2::command4() { return ASound::command4(); }
+int ASound2::command5() { return ASound::command5(); }
+int ASound2::command6() { return ASound::command6(); }
+int ASound2::command7() { return ASound::command7(); }
+int ASound2::command8() { return ASound::command8(); }
+
+// ---------------------------------------------------------------------------
+// command16 (sub_11CBC) â isSoundActive guard, command1, load ch0â5
+// ---------------------------------------------------------------------------
+int ASound2::command16() {
+ byte *pData = loadData(0x0C36, 88);
+ if (!isSoundActive(pData)) {
+ ASound::command1();
+ _channels[0].load(pData);
+ _channels[1].load(loadData(0x0C8E, 102));
+ _channels[2].load(loadData(0x0CF4, 90));
+ _channels[3].load(loadData(0x0D4E, 85));
+ _channels[4].load(loadData(0x0DA3, 14));
+ _channels[5].load(loadData(0x0DB1, 15));
+ }
+ return 0;
+}
+
+// ---------------------------------------------------------------------------
+// commands 24â27 (asound_commands3) â upper channel pool via sub_1039C
+// ---------------------------------------------------------------------------
+
+// sub_11D78
+int ASound2::command24() {
+ playSound(0x1A4A, 51);
+ playSound(0x1A7D, 46);
+ return 0;
+}
+
+// sub_11D85
+int ASound2::command25() {
+ playSound(0x1AAB, 44);
+ playSound(0x1AD7, 46);
+ return 0;
+}
+
+// sub_11D92
+int ASound2::command26() {
+ playSound(0x1B05, 12);
+ return 0;
+}
+
+// sub_11D99
+int ASound2::command27() {
+ playSound(0x1B11, 81);
+ return 0;
+}
+
+// ---------------------------------------------------------------------------
+// commands 32â35 (asound_commands4)
+// ---------------------------------------------------------------------------
+
+// command32 (sub_11DDC) â command1, six loadAny calls from channel 0
+// (sub_10352 = playSoundData(pData, 0))
+int ASound2::command32() {
+ ASound::command1();
+ playSoundData(loadData(0x1BE4, 211), 0);
+ playSoundData(loadData(0x1CB7, 359), 0);
+ playSoundData(loadData(0x1E1E, 170), 0);
+ playSoundData(loadData(0x1EC8, 16), 0);
+ playSoundData(loadData(0x1ED8, 23), 0);
+ playSoundData(loadData(0x1EEF, 19), 0);
+ return 0;
+}
+
+// command33 (sub_11DA0) â isSoundActive guard, command1, load ch0â7
+int ASound2::command33() {
+ byte *pData = loadData(0x1B62, 53);
+ if (!isSoundActive(pData)) {
+ ASound::command1();
+ _channels[0].load(pData);
+ _channels[1].load(loadData(0x1B97, 14));
+ _channels[2].load(loadData(0x1BA5, 14));
+ _channels[3].load(loadData(0x1BB3, 14));
+ _channels[4].load(loadData(0x1BC1, 4));
+ _channels[5].load(loadData(0x1BC5, 4));
+ _channels[6].load(loadData(0x1BC9, 12));
+ _channels[7].load(loadData(0x1BD5, 15));
+ }
+ return 0;
+}
+
+// command34 (sub_11CEC) â isSoundActive guard, command1, load ch0â6
+int ASound2::command34() {
+ byte *pData = loadData(0x0DC0, 495);
+ if (!isSoundActive(pData)) {
+ ASound::command1();
+ _channels[0].load(pData);
+ _channels[1].load(loadData(0x0FAF, 599));
+ _channels[2].load(loadData(0x1206, 404));
+ _channels[3].load(loadData(0x139A, 459));
+ _channels[4].load(loadData(0x1565, 718));
+ _channels[5].load(loadData(0x1833, 154));
+ _channels[6].load(loadData(0x18CD, 91));
+ }
+ return 0;
+}
+
+// command35 (sub_11E04) â isSoundActive guard, command1, load ch0â6
+int ASound2::command35() {
+ byte *pData = loadData(0x1F02, 100);
+ if (!isSoundActive(pData)) {
+ ASound::command1();
+ _channels[0].load(pData);
+ _channels[1].load(loadData(0x1F66, 10));
+ _channels[2].load(loadData(0x1F70, 29));
+ _channels[3].load(loadData(0x1F8D, 65));
+ _channels[4].load(loadData(0x1FCE, 41));
+ _channels[5].load(loadData(0x1FF7, 55));
+ _channels[6].load(loadData(0x202E, 34));
+ }
+ return 0;
+}
+
+// ---------------------------------------------------------------------------
+// commands 64â72 (asound_commands5) â upper channel pool via sub_1039C
+// ---------------------------------------------------------------------------
+
+// sub_11D22
+int ASound2::command64() {
+ playSound(0x1928, 20);
+ return 0;
+}
+
+// sub_11D29
+int ASound2::command65() {
+ playSound(0x193C, 10);
+ return 0;
+}
+
+// sub_11D30
+int ASound2::command66() {
+ playSound(0x1946, 22);
+ playSound(0x195C, 17);
+ return 0;
+}
+
+// sub_11D3D
+int ASound2::command67() {
+ playSound(0x196D, 18);
+ return 0;
+}
+
+// nullsub_3 â no-op
+int ASound2::command68() {
+ return 0;
+}
+
+// sub_11D45
+int ASound2::command69() {
+ playSound(0x197F, 38);
+ playSound(0x19A5, 38);
+ playSound(0x19CB, 26);
+ return 0;
+}
+
+// sub_11D58
+int ASound2::command70() {
+ playSound(0x19E5, 12);
+ playSound(0x19F1, 14);
+ return 0;
+}
+
+// sub_11D65
+int ASound2::command71() {
+ playSound(0x19FF, 14);
+ return 0;
+}
+
+// sub_11D6C
+int ASound2::command72() {
+ playSound(0x1A0D, 3);
+ playSound(0x1A10, 22);
+ return 0;
+}
+
+/*-----------------------------------------------------------------------*/
+
+/*-----------------------------------------------------------------------*/
+/* ASound3 (asound.ph3) *
+ * *
+ * Dispatch table layout: *
+ * asound_commands1: commands 0â8 (max=8, base=0) *
+ * asound_commands2: command 16 (max=0x10, base=0x10, 1 entry) *
+ * asound_commands3: commands 24â27 (max=0x1B, base=0x18, 4 entries) *
+ * asound_commands4: commands 32â37 (max=0x25, base=0x20, 6 entries) *
+ * asound_commands5: commands 64â76 (max=0x4B, base=0x40, 12 entries) *
+ * (entry 12, command 76 = nullsub_8, is a no-op) *
+ * *
+ * Channel-load helpers: *
+ * sub_103FF=ch0 sub_10404=ch1 sub_10409=ch2 sub_1040E=ch3 *
+ * sub_10413=ch4 sub_10418=ch5 sub_1041D=ch6 sub_10422=ch7 *
+ * loc_10427 =ch8 *
+ * *
+ * sub_106DF = isSoundActive guard *
+ * sub_1039C = playSoundData(pData, ADLIB_CHANNEL_MIDWAY) (upper pool) *
+ * *
+ * sub_11CC6 (helper) â isSoundActive guard on 0xC36, command1, *
+ * loads ch0â7; called by command34 which then adds ch8 at 0x298E. *
+ *-----------------------------------------------------------------------*/
+
+const ASound3::CommandPtr ASound3::_commandList[77] = {
+ // commands 0â8 (asound_commands1)
+ &ASound3::command0, &ASound3::command1, &ASound3::command2, &ASound3::command3,
+ &ASound3::command4, &ASound3::command5, &ASound3::command6, &ASound3::command7,
+ &ASound3::command8,
+ // 9â15 absent
+ nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr,
+ // command 16 (asound_commands2)
+ &ASound3::command16,
+ // 17â23 absent
+ nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr,
+ // commands 24â27 (asound_commands3)
+ &ASound3::command24, &ASound3::command25, &ASound3::command26, &ASound3::command27,
+ // 28â31 absent
+ nullptr, nullptr, nullptr, nullptr,
+ // commands 32â37 (asound_commands4)
+ &ASound3::command32, &ASound3::command33, &ASound3::command34, &ASound3::command35,
+ &ASound3::command36, &ASound3::command37,
+ // 38â63 absent
+ nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr,
+ // commands 64â75 (asound_commands5)
+ &ASound3::command64, &ASound3::command65, &ASound3::command66, &ASound3::command67,
+ &ASound3::command68, &ASound3::command69, &ASound3::command70, &ASound3::command71,
+ &ASound3::command72, &ASound3::command73, &ASound3::command74, &ASound3::command75,
+ // command 76 = nullsub_8
+ nullptr
+};
+
+ASound3::ASound3(Audio::Mixer *mixer, OPL::OPL *opl)
+ : ASound(mixer, opl, "asound.ph3", 0x20c0) {
+}
+
+int ASound3::command(int commandId, int param) {
+ if (commandId > 76 || !_commandList[commandId])
+ return 0;
+
+ _commandParam = param;
+ _frameCounter = 0;
+ return (this->*_commandList[commandId])();
+}
+
+// commands 0â8: delegate to base ASound
+int ASound3::command0() { return ASound::command0(); }
+int ASound3::command1() { return ASound::command1(); }
+int ASound3::command2() { return ASound::command2(); }
+int ASound3::command3() { return ASound::command3(); }
+int ASound3::command4() { return ASound::command4(); }
+int ASound3::command5() { return ASound::command5(); }
+int ASound3::command6() { return ASound::command6(); }
+int ASound3::command7() { return ASound::command7(); }
+int ASound3::command8() { return ASound::command8(); }
+
+// ---------------------------------------------------------------------------
+// sub_11CC6 â shared helper used by command34.
+// isSoundActive guard on 0xC36; if not active: command1, load ch0â7.
+// (The tiny ch6 and ch7 blocks â 4 bytes each â are very short sub-blocks
+// within the same composite sound.)
+// ---------------------------------------------------------------------------
+void ASound3::sub11CC6() {
+ byte *pData = loadData(0x0C36, 53);
+ if (!isSoundActive(pData)) {
+ ASound::command1();
+ _channels[0].load(pData);
+ _channels[1].load(loadData(0x0C6B, 14));
+ _channels[2].load(loadData(0x0C79, 14));
+ _channels[3].load(loadData(0x0C87, 14));
+ _channels[4].load(loadData(0x0C95, 4));
+ _channels[5].load(loadData(0x0C99, 4));
+ _channels[6].load(loadData(0x0C9D, 12));
+ _channels[7].load(loadData(0x0CA9, 15));
+ }
+}
+
+// ---------------------------------------------------------------------------
+// command16 (sub_11D98) â isSoundActive guard, command1, load ch0â5
+// ---------------------------------------------------------------------------
+int ASound3::command16() {
+ byte *pData = loadData(0x24F2, 172);
+ if (!isSoundActive(pData)) {
+ ASound::command1();
+ _channels[0].load(pData);
+ _channels[1].load(loadData(0x259E, 137));
+ _channels[2].load(loadData(0x2627, 135));
+ _channels[3].load(loadData(0x26AE, 179));
+ _channels[4].load(loadData(0x2761, 175));
+ _channels[5].load(loadData(0x2810, 186));
+ }
+ return 0;
+}
+
+// ---------------------------------------------------------------------------
+// commands 24â27 (asound_commands3) â upper channel pool (sub_1039C)
+// ---------------------------------------------------------------------------
+
+// sub_11E54
+int ASound3::command24() {
+ playSound(0x2A7C, 51);
+ playSound(0x2AAF, 46);
+ return 0;
+}
+
+// sub_11E61
+int ASound3::command25() {
+ playSound(0x2ADD, 44);
+ playSound(0x2B09, 46);
+ return 0;
+}
+
+// sub_11E6E
+int ASound3::command26() {
+ playSound(0x2B37, 12);
+ return 0;
+}
+
+// sub_11E75
+int ASound3::command27() {
+ playSound(0x2B43, 12);
+ return 0;
+}
+
+// ---------------------------------------------------------------------------
+// commands 32â37 (asound_commands4)
+// ---------------------------------------------------------------------------
+
+// command32 (sub_11E7C) â isSoundActive guard, command1, load ch0â7
+int ASound3::command32() {
+ byte *pData = loadData(0x2B94, 108);
+ if (!isSoundActive(pData)) {
+ ASound::command1();
+ _channels[0].load(pData);
+ _channels[1].load(loadData(0x2C00, 73));
+ _channels[2].load(loadData(0x2C49, 67));
+ _channels[3].load(loadData(0x2C8C, 151));
+ _channels[4].load(loadData(0x2D23, 171));
+ _channels[5].load(loadData(0x2DCE, 87));
+ _channels[6].load(loadData(0x2E25, 95));
+ _channels[7].load(loadData(0x2E84, 110));
+ }
+ return 0;
+}
+
+// command33 (sub_11D32) â isSoundActive guard, command1, load ch0â6
+int ASound3::command33() {
+ byte *pData = loadData(0x149E, 525);
+ if (!isSoundActive(pData)) {
+ ASound::command1();
+ _channels[0].load(pData);
+ _channels[1].load(loadData(0x16AB, 648));
+ _channels[2].load(loadData(0x1933, 252));
+ _channels[3].load(loadData(0x1A2F, 502));
+ _channels[4].load(loadData(0x1C25, 680));
+ _channels[5].load(loadData(0x1ECD, 418));
+ _channels[6].load(loadData(0x206F, 3));
+ }
+ return 0;
+}
+
+// command34 (sub_11E2F) â calls sub11CC6 (loads ch0â7 if not active),
+// then unconditionally loads ch8 at 0x298E
+int ASound3::command34() {
+ sub11CC6();
+ _channels[8].load(loadData(0x298E, 10));
+ return 0;
+}
+
+// command35 (sub_11D02) â isSoundActive guard, command1, load ch0â5
+int ASound3::command35() {
+ byte *pData = loadData(0x0CB8, 413);
+ if (!isSoundActive(pData)) {
+ ASound::command1();
+ _channels[0].load(pData);
+ _channels[1].load(loadData(0x0E55, 270));
+ _channels[2].load(loadData(0x0F63, 238));
+ _channels[3].load(loadData(0x1051, 264));
+ _channels[4].load(loadData(0x1159, 434));
+ _channels[5].load(loadData(0x130B, 403));
+ }
+ return 0;
+}
+
+// command36 (sub_11D68) â isSoundActive guard, command1, load ch0â5
+int ASound3::command36() {
+ byte *pData = loadData(0x2072, 196);
+ if (!isSoundActive(pData)) {
+ ASound::command1();
+ _channels[0].load(pData);
+ _channels[1].load(loadData(0x2136, 692));
+ _channels[2].load(loadData(0x23EA, 83));
+ _channels[3].load(loadData(0x243D, 24));
+ _channels[4].load(loadData(0x2455, 78));
+ _channels[5].load(loadData(0x24A3, 79));
+ }
+ return 0;
+}
+
+// command37 (sub_11DF8) â single upper-pool voice
+int ASound3::command37() {
+ playSound(0x298E, 10);
+ return 0;
}
-int ASound1::command(int commandId, int param) {
- // TODO
+// ---------------------------------------------------------------------------
+// commands 64â75 (asound_commands5)
+//
+// sub_11DC8/sub_11DD4: load ch6 and ch8 directly (skipping ch7).
+// sub_11DE0: loads ch6, ch7, ch8.
+// sub_11E22/sub_11E47: load ch7 and ch8 directly.
+// Remaining entries use the upper pool (sub_1039C).
+// ---------------------------------------------------------------------------
+
+// sub_11DC8 â ch6 + ch8
+int ASound3::command64() {
+ _channels[6].load(loadData(0x28CA, 50));
+ _channels[8].load(loadData(0x28FC, 29));
return 0;
}
-/*-----------------------------------------------------------------------*/
+// sub_11DD4 â ch6 + ch8
+int ASound3::command65() {
+ _channels[6].load(loadData(0x2919, 17));
+ _channels[8].load(loadData(0x292A, 13));
+ return 0;
+}
-ASound2::ASound2(Audio::Mixer *mixer, OPL::OPL *opl) : ASound(mixer, opl, "asound.ph2", 0x2040) {
+// sub_11DE0 â ch6 + ch7 + ch8
+int ASound3::command66() {
+ _channels[6].load(loadData(0x2937, 31));
+ _channels[7].load(loadData(0x2956, 15));
+ _channels[8].load(loadData(0x2965, 31));
+ return 0;
}
-int ASound2::command(int commandId, int param) {
- // TODO
+// sub_11DF2 â upper pool x1
+int ASound3::command67() {
+ playSound(0x2984, 10);
return 0;
}
-/*-----------------------------------------------------------------------*/
+// sub_11DFE â upper pool x3
+int ASound3::command68() {
+ playSound(0x2998, 22);
+ playSound(0x29AE, 20);
+ playSound(0x29C2, 22);
+ return 0;
+}
-ASound3::ASound3(Audio::Mixer *mixer, OPL::OPL *opl) : ASound(mixer, opl, "asound.ph3", 0x20c0) {
+// sub_11E10 â upper pool x1
+int ASound3::command69() {
+ playSound(0x29D8, 18);
+ return 0;
}
-int ASound3::command(int commandId, int param) {
- // TODO
+// sub_11E16 â upper pool x1
+int ASound3::command70() {
+ playSound(0x2B4F, 15);
+ return 0;
+}
+
+// sub_11E1C â upper pool x1
+int ASound3::command71() {
+ playSound(0x2B5E, 54);
+ return 0;
+}
+
+// sub_11E22 â ch7 + ch8
+int ASound3::command72() {
+ _channels[7].load(loadData(0x29EA, 17));
+ _channels[8].load(loadData(0x2A18, 17));
+ return 0;
+}
+
+// sub_11E39 â upper pool x1
+int ASound3::command73() {
+ playSound(0x2A44, 10);
return 0;
}
+// sub_11E40 â upper pool x1
+int ASound3::command74() {
+ playSound(0x2A4E, 46);
+ return 0;
+}
+
+// sub_11E47 â ch7 + ch8
+int ASound3::command75() {
+ _channels[7].load(loadData(0x29FB, 29));
+ _channels[8].load(loadData(0x2A29, 27));
+ return 0;
+}
+
+/*-----------------------------------------------------------------------*/
+
/*-----------------------------------------------------------------------*/
+/* ASound4 (asound.ph4) *
+ * *
+ * Dispatch table layout: *
+ * asound_commands1: commands 0â8 (max=8, base=0) *
+ * asound_commands2: command 16 (max=0x10, base=0x10, 1 entry) *
+ * asound_commands3: commands 24â27 (max=0x1B, base=0x18, 4 entries) *
+ * asound_commands4: commands 64â70 (max=0x46, base=0x40, 7 entries) *
+ * (The 0x20-range table also points at asound_commands4 but has *
+ * max=0, making commands 32â63 unreachable.) *
+ * *
+ * Channel-load helpers: *
+ * sub_103FF=ch0 sub_10404=ch1 sub_10409=ch2 sub_1040E=ch3 *
+ * sub_10413=ch4 sub_10418=ch5 sub_1041D=ch6 *
+ * *
+ * sub_106DF = isSoundActive guard *
+ * sub_1039C = playSoundData(pData, ADLIB_CHANNEL_MIDWAY) (upper pool) *
+ * *
+ * commands 24 and 25 share the same handler (sub_11D0A). *
+ * Two unreferenced subs (sub_11D5E, sub_11D6B) contain dead sound data *
+ * that is never played; they are omitted. *
+ * An unreferenced random-pitch stub exists between sub_11CAB and *
+ * sub_11CD3; it was never wired into any command. *
+ *-----------------------------------------------------------------------*/
-ASound4::ASound4(Audio::Mixer *mixer, OPL::OPL *opl) : ASound(mixer, opl, "asound.ph4", 0x1f90) {
+const ASound4::CommandPtr ASound4::_commandList[71] = {
+ // commands 0â8 (asound_commands1)
+ &ASound4::command0, &ASound4::command1, &ASound4::command2, &ASound4::command3,
+ &ASound4::command4, &ASound4::command5, &ASound4::command6, &ASound4::command7,
+ &ASound4::command8,
+ // 9â15 absent
+ nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr,
+ // command 16 (asound_commands2)
+ &ASound4::command16,
+ // 17â23 absent
+ nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr,
+ // commands 24â27 (asound_commands3)
+ &ASound4::command24, &ASound4::command25, &ASound4::command26, &ASound4::command27,
+ // 28â63 absent (the 0x20-range table has max=0, unreachable)
+ nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr,
+ // commands 64â70 (asound_commands4)
+ &ASound4::command64, &ASound4::command65, &ASound4::command66, &ASound4::command67,
+ &ASound4::command68, &ASound4::command69, &ASound4::command70
+};
+
+ASound4::ASound4(Audio::Mixer *mixer, OPL::OPL *opl)
+ : ASound(mixer, opl, "asound.ph4", 0x1f90) {
}
int ASound4::command(int commandId, int param) {
- // TODO
+ if (commandId > 70 || !_commandList[commandId])
+ return 0;
+
+ _commandParam = param;
+ _frameCounter = 0;
+ return (this->*_commandList[commandId])();
+}
+
+// commands 0â8: delegate to base ASound
+int ASound4::command0() { return ASound::command0(); }
+int ASound4::command1() { return ASound::command1(); }
+int ASound4::command2() { return ASound::command2(); }
+int ASound4::command3() { return ASound::command3(); }
+int ASound4::command4() { return ASound::command4(); }
+int ASound4::command5() { return ASound::command5(); }
+int ASound4::command6() { return ASound::command6(); }
+int ASound4::command7() { return ASound::command7(); }
+int ASound4::command8() { return ASound::command8(); }
+
+// ---------------------------------------------------------------------------
+// command16 (sub_11CD3) â isSoundActive guard, command1, load ch0â6
+// ---------------------------------------------------------------------------
+int ASound4::command16() {
+ byte *pData = loadData(0x0C36, 63);
+ if (!isSoundActive(pData)) {
+ ASound::command1();
+ _channels[0].load(pData);
+ _channels[1].load(loadData(0x0C75, 636));
+ _channels[2].load(loadData(0x0EF1, 40));
+ _channels[3].load(loadData(0x0F19, 40));
+ _channels[4].load(loadData(0x0F41, 38));
+ _channels[5].load(loadData(0x0F67, 41));
+ _channels[6].load(loadData(0x0F90, 106));
+ }
+ return 0;
+}
+
+// ---------------------------------------------------------------------------
+// commands 24â27 (asound_commands3) â upper pool (sub_1039C)
+//
+// commands 24 and 25 are both wired to the same handler (sub_11D0A),
+// which loads two upper-pool sounds.
+// ---------------------------------------------------------------------------
+
+// sub_11D0A (shared by both command24 and command25)
+int ASound4::command24() {
+ playSound(0x0FFA, 18);
+ playSound(0x100C, 11);
+ return 0;
+}
+
+int ASound4::command25() {
+ return command24();
+}
+
+// sub_11D78
+int ASound4::command26() {
+ playSound(0x119D, 12);
+ return 0;
+}
+
+// sub_11D7F
+int ASound4::command27() {
+ playSound(0x11A9, 121);
+ return 0;
+}
+
+// ---------------------------------------------------------------------------
+// commands 64â70 (asound_commands4, base 0x40)
+// All entries use the upper pool (sub_1039C).
+// ---------------------------------------------------------------------------
+
+// sub_11D16
+int ASound4::command64() {
+ playSound(0x1017, 26);
+ playSound(0x1031, 17);
+ return 0;
+}
+
+// sub_11D22
+int ASound4::command65() {
+ playSound(0x1042, 9);
+ playSound(0x104B, 20);
+ return 0;
+}
+
+// sub_11D2E
+int ASound4::command66() {
+ playSound(0x105F, 9);
+ playSound(0x1068, 16);
+ return 0;
+}
+
+// sub_11D3A
+int ASound4::command67() {
+ playSound(0x1078, 9);
+ playSound(0x1081, 14);
+ return 0;
+}
+
+// sub_11D46
+int ASound4::command68() {
+ playSound(0x108F, 12);
+ return 0;
+}
+
+// sub_11D4C
+int ASound4::command69() {
+ playSound(0x109B, 10);
+ return 0;
+}
+
+// sub_11D52
+int ASound4::command70() {
+ playSound(0x10A5, 3);
+ playSound(0x10A8, 58);
return 0;
}
/*-----------------------------------------------------------------------*/
-ASound5::ASound5(Audio::Mixer *mixer, OPL::OPL *opl) : ASound(mixer, opl, "asound.ph5", 0x2140) {
+/*-----------------------------------------------------------------------*/
+/* ASound5 (asound.ph5) *
+ * *
+ * Dispatch table layout: *
+ * asound_commands1: commands 0â8 (max=8, base=0) *
+ * asound_commands2: command 16 (max=0x10, base=0x10, 1 entry) *
+ * asound_commands3: commands 24â27 (max=0x1B, base=0x18, 4 entries) *
+ * asound_commands4: commands 32â39 (max=0x27, base=0x20, 8 entries) *
+ * asound_commands5: commands 64â78 (max=0x4E, base=0x40, 15 entries) *
+ * (entry 15, command 79 = nullsub_8, silently ignored) *
+ * *
+ * Channel-load helpers: *
+ * sub_103FF=ch0 sub_10404=ch1 sub_10409=ch2 sub_1040E=ch3 *
+ * sub_10413=ch4 sub_10418=ch5 loc_1041D=ch6 loc_10422=ch7 *
+ * loc_10427=ch8 *
+ * *
+ * In this driver IDA named the lower-pool loadAny as AdlibChannel_loadAny*
+ * (starts from ch0) and sub_1039C as the upper-pool loader (ch6-8). *
+ * AdlibChannel_loadAny â playSoundData(pData, 0) *
+ * sub_1039C â playSound() / playSoundData(pData, MIDWAY) *
+ * *
+ * loc_11D42 (cmd37) and loc_11D72 (cmd36) load channels in non- *
+ * sequential order â the sound data for each channel is not stored *
+ * contiguously. Block sizes are derived from the full sorted data map. *
+ * *
+ * commands 70/77/78 all reference the same data block at 0x40BA. *
+ * A dead sub (sub_11F09) and a dead random-pitch stub are ignored. *
+ *-----------------------------------------------------------------------*/
+
+const ASound5::CommandPtr ASound5::_commandList[79] = {
+ // commands 0â8 (asound_commands1)
+ &ASound5::command0, &ASound5::command1, &ASound5::command2, &ASound5::command3,
+ &ASound5::command4, &ASound5::command5, &ASound5::command6, &ASound5::command7,
+ &ASound5::command8,
+ // 9â15 absent
+ nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr,
+ // command 16 (asound_commands2)
+ &ASound5::command16,
+ // 17â23 absent
+ nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr,
+ // commands 24â27 (asound_commands3)
+ &ASound5::command24, &ASound5::command25, &ASound5::command26, &ASound5::command27,
+ // 28â31 absent
+ nullptr, nullptr, nullptr, nullptr,
+ // commands 32â39 (asound_commands4)
+ &ASound5::command32, &ASound5::command33, &ASound5::command34, &ASound5::command35,
+ &ASound5::command36, &ASound5::command37, &ASound5::command38, &ASound5::command39,
+ // 40â63 absent
+ nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr,
+ // commands 64â78 (asound_commands5)
+ &ASound5::command64, &ASound5::command65, &ASound5::command66, &ASound5::command67,
+ &ASound5::command68, &ASound5::command69, &ASound5::command70, &ASound5::command71,
+ &ASound5::command72, &ASound5::command73, &ASound5::command74, &ASound5::command75,
+ &ASound5::command76, &ASound5::command77, &ASound5::command78
+};
+
+ASound5::ASound5(Audio::Mixer *mixer, OPL::OPL *opl)
+ : ASound(mixer, opl, "asound.ph5", 0x2140) {
}
int ASound5::command(int commandId, int param) {
- // TODO
+ if (commandId > 78 || !_commandList[commandId])
+ return 0;
+
+ _commandParam = param;
+ _frameCounter = 0;
+ return (this->*_commandList[commandId])();
+}
+
+// commands 0â8: delegate to base ASound
+int ASound5::command0() { return ASound::command0(); }
+int ASound5::command1() { return ASound::command1(); }
+int ASound5::command2() { return ASound::command2(); }
+int ASound5::command3() { return ASound::command3(); }
+int ASound5::command4() { return ASound::command4(); }
+int ASound5::command5() { return ASound::command5(); }
+int ASound5::command6() { return ASound::command6(); }
+int ASound5::command7() { return ASound::command7(); }
+int ASound5::command8() { return ASound::command8(); }
+
+// ---------------------------------------------------------------------------
+// command16 (sub_11E84) â isSoundActive guard, command1, load ch0â5
+// ---------------------------------------------------------------------------
+int ASound5::command16() {
+ byte *pData = loadData(0x4142, 120);
+ if (!isSoundActive(pData)) {
+ ASound::command1();
+ _channels[0].load(pData);
+ _channels[1].load(loadData(0x41BA, 146));
+ _channels[2].load(loadData(0x424C, 133));
+ _channels[3].load(loadData(0x42D1, 69));
+ _channels[4].load(loadData(0x4316, 152));
+ _channels[5].load(loadData(0x43AE, 14));
+ }
+ return 0;
+}
+
+// ---------------------------------------------------------------------------
+// commands 24â27 (asound_commands3) â upper pool (sub_1039C)
+// ---------------------------------------------------------------------------
+
+// sub_11EE8
+int ASound5::command24() {
+ playSound(0x51FA, 51);
+ playSound(0x522D, 46);
+ return 0;
+}
+
+// sub_11EF5
+int ASound5::command25() {
+ playSound(0x525B, 44);
+ playSound(0x5287, 46);
+ return 0;
+}
+
+// sub_11F02
+int ASound5::command26() {
+ playSound(0x52B5, 12);
+ return 0;
+}
+
+// sub_11E71 â three upper-pool voices
+int ASound5::command27() {
+ playSound(0x4040, 10);
+ playSound(0x404A, 23);
+ playSound(0x4061, 25);
+ return 0;
+}
+
+// ---------------------------------------------------------------------------
+// commands 32â39 (asound_commands4)
+// ---------------------------------------------------------------------------
+
+// sub_11EB4 â command1, eight loadAny (lower pool, AdlibChannel_loadAny)
+int ASound5::command32() {
+ ASound::command1();
+ playSoundData(loadData(0x43BC, 689), 0);
+ playSoundData(loadData(0x466D, 262), 0);
+ playSoundData(loadData(0x4773, 480), 0);
+ playSoundData(loadData(0x4953, 504), 0);
+ playSoundData(loadData(0x4B4B, 584), 0);
+ playSoundData(loadData(0x4D93, 308), 0);
+ playSoundData(loadData(0x4EC7, 426), 0);
+ playSoundData(loadData(0x5071, 357), 0);
+ return 0;
+}
+
+// sub_11DA2 â isSoundActive guard, command1, load ch0â6
+int ASound5::command33() {
+ byte *pData = loadData(0x21C6, 609);
+ if (!isSoundActive(pData)) {
+ ASound::command1();
+ _channels[0].load(pData);
+ _channels[1].load(loadData(0x2427, 652));
+ _channels[2].load(loadData(0x26B3, 272));
+ _channels[3].load(loadData(0x27C3, 558));
+ _channels[4].load(loadData(0x29F1, 712));
+ _channels[5].load(loadData(0x2CB9, 464));
+ _channels[6].load(loadData(0x2E89, 21));
+ }
+ return 0;
+}
+
+// sub_11DD8 â isSoundActive guard, command1, load ch0â5 (non-sequential)
+// ch1 and ch3 use data from the 0x4000 region; ch0/ch2/ch4 from 0x2E9E region
+int ASound5::command34() {
+ byte *pData = loadData(0x2E9E, 1521);
+ if (!isSoundActive(pData)) {
+ ASound::command1();
+ _channels[0].load(pData);
+ _channels[1].load(loadData(0x4003, 7));
+ _channels[2].load(loadData(0x348F, 1424));
+ _channels[3].load(loadData(0x400A, 7));
+ _channels[4].load(loadData(0x3A1F, 1508));
+ _channels[5].load(loadData(0x4011, 9));
+ }
+ return 0;
+}
+
+// loc_11D72 â isSoundActive guard, command1, load ch0â5 (non-sequential)
+// ch1/ch3/ch5 use data from the 0x2196 region interleaved with ch0/ch2/ch4
+int ASound5::command35() {
+ byte *pData = loadData(0x1D0A, 320);
+ if (!isSoundActive(pData)) {
+ ASound::command1();
+ _channels[0].load(pData);
+ _channels[1].load(loadData(0x2196, 18));
+ _channels[2].load(loadData(0x1E4A, 304));
+ _channels[3].load(loadData(0x21A8, 18));
+ _channels[4].load(loadData(0x1F7A, 540));
+ _channels[5].load(loadData(0x21BA, 12));
+ }
+ return 0;
+}
+
+// loc_11D42 â isSoundActive guard, command1, load ch0â5 (non-sequential)
+// ch4 and ch5 reuse blocks at 0x15EC and 0x18D9 that precede ch0's data
+int ASound5::command36() {
+ byte *pData = loadData(0x15F5, 740);
+ if (!isSoundActive(pData)) {
+ ASound::command1();
+ _channels[0].load(pData);
+ _channels[1].load(loadData(0x18E2, 326));
+ _channels[2].load(loadData(0x1A28, 561));
+ _channels[3].load(loadData(0x1C59, 177));
+ _channels[4].load(loadData(0x15EC, 9));
+ _channels[5].load(loadData(0x18D9, 9));
+ }
+ return 0;
+}
+
+// loc_11D00 â isSoundActive guard, command1, load ch0â8
+int ASound5::command37() {
+ byte *pData = loadData(0x1190, 397);
+ if (!isSoundActive(pData)) {
+ ASound::command1();
+ _channels[0].load(pData);
+ _channels[1].load(loadData(0x131D, 378));
+ _channels[2].load(loadData(0x1497, 60));
+ _channels[3].load(loadData(0x14D3, 64));
+ _channels[4].load(loadData(0x1513, 44));
+ _channels[5].load(loadData(0x153F, 44));
+ _channels[6].load(loadData(0x156B, 50));
+ _channels[7].load(loadData(0x159D, 52));
+ _channels[8].load(loadData(0x15D1, 27));
+ }
+ return 0;
+}
+
+// loc_11CD0 â isSoundActive guard, command2 (lower-bank fade), load ch0â5
+int ASound5::command38() {
+ byte *pData = loadData(0x0C36, 329);
+ if (!isSoundActive(pData)) {
+ ASound::command2();
+ _channels[0].load(pData);
+ _channels[1].load(loadData(0x0D7F, 201));
+ _channels[2].load(loadData(0x0E48, 200));
+ _channels[3].load(loadData(0x0F10, 162));
+ _channels[4].load(loadData(0x0FB2, 228));
+ _channels[5].load(loadData(0x1096, 250));
+ }
+ return 0;
+}
+
+// sub_11F10 â isSoundActive guard, command3 (lower-bank fade only), load ch0â5
+int ASound5::command39() {
+ byte *pData = loadData(0x5312, 599);
+ if (!isSoundActive(pData)) {
+ ASound::command3();
+ _channels[0].load(pData);
+ _channels[1].load(loadData(0x5569, 275));
+ _channels[2].load(loadData(0x567C, 289));
+ _channels[3].load(loadData(0x579D, 243));
+ _channels[4].load(loadData(0x5890, 196));
+ _channels[5].load(loadData(0x5954, 206));
+ }
+ return 0;
+}
+
+// ---------------------------------------------------------------------------
+// commands 64â78 (asound_commands5) â upper pool (sub_1039C) unless noted
+// ---------------------------------------------------------------------------
+
+// sub_11E08
+int ASound5::command64() {
+ playSound(0x4101, 10);
+ return 0;
+}
+
+// sub_11E0E
+int ASound5::command65() {
+ playSound(0x401A, 18);
+ return 0;
+}
+
+// sub_11E14
+int ASound5::command66() {
+ playSound(0x402C, 10);
+ return 0;
+}
+
+// sub_11E1A
+int ASound5::command67() {
+ playSound(0x4036, 10);
+ return 0;
+}
+
+// sub_11E21
+int ASound5::command68() {
+ playSound(0x407A, 18);
+ return 0;
+}
+
+// sub_11E27
+int ASound5::command69() {
+ playSound(0x408C, 46);
+ return 0;
+}
+
+// sub_11E2D â also shared by command77 and command78
+int ASound5::command70() {
+ playSound(0x40BA, 14);
+ return 0;
+}
+
+// sub_11E33
+int ASound5::command71() {
+ playSound(0x40C8, 10);
+ return 0;
+}
+
+// sub_11E39
+int ASound5::command72() {
+ playSound(0x40D2, 10);
+ return 0;
+}
+
+// sub_11E3F
+int ASound5::command73() {
+ playSound(0x40DC, 11);
+ playSound(0x40E7, 26);
+ return 0;
+}
+
+// sub_11E4C
+int ASound5::command74() {
+ playSound(0x410B, 20);
+ return 0;
+}
+
+// sub_11E52
+int ASound5::command75() {
+ playSound(0x4129, 11);
+ playSound(0x4134, 14);
+ return 0;
+}
+
+// sub_11E5F â same block as command70
+int ASound5::command76() {
+ return command70();
+}
+
+// sub_11E65 â same block as command70
+int ASound5::command77() {
+ return command70();
+}
+
+// sub_11E6B
+int ASound5::command78() {
+ playSound(0x411F, 10);
return 0;
}
@@ -166,245 +1524,119 @@ int ASound9::command(int commandId, int param) {
return (this->*_commandList[commandId])();
}
-// commands 0-8 delegate to the base ASound implementations
int ASound9::command0() {
- return ASound::command0();
+ return 0;
}
+
int ASound9::command1() {
- return ASound::command1();
+ return 0;
}
+
int ASound9::command2() {
- return ASound::command2();
+ return 0;
}
+
int ASound9::command3() {
- return ASound::command3();
+ return 0;
}
+
int ASound9::command4() {
- return ASound::command4();
+ return 0;
}
+
int ASound9::command5() {
- return ASound::command5();
+ return 0;
}
+
int ASound9::command6() {
- return ASound::command6();
+ return 0;
}
+
int ASound9::command7() {
- return ASound::command7();
+ return 0;
}
+
int ASound9::command8() {
- return ASound::command8();
+ return 0;
}
-// ---------------------------------------------------------------------------
-// Commands 24-27 (asound_command offsets2, range 16-27)
-//
-// Each call to sub_1039C loads a sound into any available channel from the
-// upper three channels (6-8) first. cx holds a seg001-relative data offset;
-// the C++ loadData/playSound API takes the same value as the offset argument
-// (the base class adds _dataOffset when seeking the file).
-// ---------------------------------------------------------------------------
-
-// asound_command24: loads two percussion-style voices (chimes/bells) into
-// the upper channel pool.
int ASound9::command24() {
- playSound(0x203E, 51); // cx = 0x203E
- playSound(0x2071, 46); // cx = 0x2071
return 0;
}
-// asound_command25: two more upper-channel voices.
int ASound9::command25() {
- playSound(0x209F, 44); // cx = 0x209F
- playSound(0x20CB, 46); // cx = 0x20CB
return 0;
}
-// asound_command26: single upper-channel voice.
int ASound9::command26() {
- playSound(0x20F9, 12); // cx = 0x20F9
return 0;
}
-// asound_command27: single upper-channel voice.
int ASound9::command27() {
- playSound(0x2105, 81); // cx = 0x2105
return 0;
}
-// ---------------------------------------------------------------------------
-// Commands 32-39 (asound_command offsets3)
-//
-// Each command calls asound_command1 first (which calls both command3 and
-// command5, fading out channels 0-5 and 6-8 respectively), then loads new
-// sound data into specific channels via AdlibChannel_load0..8.
-//
-// asound_command32 and asound_command39 instead use AdlibChannel_loadAny
-// (sub_1039C / AdlibChannel_loadAny) which picks the first free channel.
-// ---------------------------------------------------------------------------
-
-// asound_command32: eight voices loaded into any available channels.
int ASound9::command32() {
- playSound(0x2B16, 86);
- playSound(0x2B6C, 74);
- playSound(0x2BB6, 722);
- playSound(0x2E88, 16);
- playSound(0x2E98, 11);
- playSound(0x2EA3, 11);
- playSound(0x2EAE, 9);
- playSound(0x2EB7, 15);
return 0;
}
-// asound_command33: no-op in the original (bare retn).
int ASound9::command33() {
return 0;
}
-// asound_command34: seven voices into channels 0-6, and a continuation
-// fragment into channel 7.
int ASound9::command34() {
- _channels[0].load(loadData(0x31D0, 81));
- _channels[1].load(loadData(0x3221, 97));
- _channels[2].load(loadData(0x3282, 73));
- _channels[3].load(loadData(0x32CB, 79));
- _channels[4].load(loadData(0x331A, 79));
- _channels[5].load(loadData(0x3369, 71));
- _channels[6].load(loadData(0x33B0, 7));
- _channels[7].load(loadData(0x33B7, 0)); // trailing fragment
return 0;
}
-// asound_command35: seven voices into channels 0-6.
int ASound9::command35() {
- _channels[0].load(loadData(0x295E, 64));
- _channels[1].load(loadData(0x299E, 37));
- _channels[2].load(loadData(0x29C3, 37));
- _channels[3].load(loadData(0x29E8, 94));
- _channels[4].load(loadData(0x2A46, 95));
- _channels[5].load(loadData(0x2AA5, 59));
- _channels[6].load(loadData(0x2AE0, 0));
return 0;
}
-// asound_command36: six voices into channels 0-5.
int ASound9::command36() {
- _channels[0].load(loadData(0x30AA, 51));
- _channels[1].load(loadData(0x30DD, 44));
- _channels[2].load(loadData(0x3109, 52));
- _channels[3].load(loadData(0x313D, 56));
- _channels[4].load(loadData(0x3175, 38));
- _channels[5].load(loadData(0x319B, 0));
return 0;
}
-// asound_command37: seven voices into channels 0-6.
int ASound9::command37() {
- _channels[0].load(loadData(0x2156, 80));
- _channels[1].load(loadData(0x21A6, 232));
- _channels[2].load(loadData(0x228E, 105));
- _channels[3].load(loadData(0x22F7, 90));
- _channels[4].load(loadData(0x2351, 599));
- _channels[5].load(loadData(0x25A8, 791));
- _channels[6].load(loadData(0x28BF, 0));
return 0;
}
-// asound_command38: eight voices into channels 0-7.
-// Preceded by asound_command1 (fade-out both banks).
int ASound9::command38() {
- _channels[0].load(loadData(0x11BC, 699));
- _channels[1].load(loadData(0x1477, 278));
- _channels[2].load(loadData(0x158D, 490));
- _channels[3].load(loadData(0x1777, 512));
- _channels[4].load(loadData(0x1977, 590));
- _channels[5].load(loadData(0x1BC5, 314));
- _channels[6].load(loadData(0x1CFF, 432));
- _channels[7].load(loadData(0x1EAF, 0));
return 0;
}
-// asound_command39: six voices loaded into channels 0-5 via AdlibChannel_load.
-// Preceded by asound_command0 (full reset), then specific channel loads.
int ASound9::command39() {
- byte *pData = loadData(0x0C36, 0);
- if (!isSoundActive(pData)) {
- stop();
- _channels[0].load(loadData(0x0C36, 311));
- _channels[1].load(loadData(0x0D7D, 211));
- _channels[2].load(loadData(0x0E50, 204));
- _channels[3].load(loadData(0x0F1C, 178));
- _channels[4].load(loadData(0x0FCE, 236));
- _channels[5].load(loadData(0x10BA, 0));
- }
return 0;
}
-// ---------------------------------------------------------------------------
-// Commands 64-71 (asound_command offsets4)
-//
-// Commands 64, 65, 68-71 use sub_1039C (loads into upper channels 6-8 first).
-// Commands 66 and 67 load explicitly named channels.
-// ---------------------------------------------------------------------------
-
-// asound_command64: single voice into upper channel pool.
int ASound9::command64() {
- playSound(0x2EC6, 20); // cx = 0x2EC6
return 0;
}
-// asound_command65: single voice into upper channel pool.
int ASound9::command65() {
- playSound(0x2EDA, 10); // cx = 0x2EDA
return 0;
}
-// asound_command66: eight voices into channels 0-7 in a repeating
-// four-voice pattern (0/1/2/3 mirrored onto 4/5/6, then 7 gets the 4th).
int ASound9::command66() {
- _channels[0].load(loadData(0x2EE4, 42));
- _channels[1].load(loadData(0x2F0E, 48));
- _channels[2].load(loadData(0x2F3E, 48));
- _channels[3].load(loadData(0x2F6E, 48));
- _channels[4].load(loadData(0x2EE4, 42)); // mirrors channel 0
- _channels[5].load(loadData(0x2F0E, 48)); // mirrors channel 1
- _channels[6].load(loadData(0x2F3E, 48)); // mirrors channel 2
- _channels[7].load(loadData(0x2F6E, 48)); // mirrors channel 3
return 0;
}
-// asound_command67: three voices into channels 6-8.
int ASound9::command67() {
- _channels[6].load(loadData(0x2F9E, 31));
- _channels[7].load(loadData(0x2FBD, 15));
- _channels[8].load(loadData(0x2FCC, 31));
return 0;
}
-// asound_command68: single voice into upper channel pool.
int ASound9::command68() {
- playSound(0x2FEB, 10); // cx = 0x2FEB
return 0;
}
-// asound_command69: three voices into upper channel pool.
int ASound9::command69() {
- playSound(0x2FF5, 38); // cx = 0x2FF5
- playSound(0x301B, 38); // cx = 0x301B
- playSound(0x3041, 26); // cx = 0x3041
return 0;
}
-// asound_command70: two voices into upper channel pool.
int ASound9::command70() {
- playSound(0x305B, 9); // cx = 0x305B
- playSound(0x3064, 9); // cx = 0x3064
return 0;
}
-// asound_command71: two voices into upper channel pool.
int ASound9::command71() {
- playSound(0x306D, 29); // cx = 0x306D
- playSound(0x308A, 0); // cx = 0x308A
return 0;
}
diff --git a/engines/mads/madsv2/phantom/sound_phantom.h b/engines/mads/madsv2/phantom/sound_phantom.h
index e67ad88e08e..21c0b1ceced 100644
--- a/engines/mads/madsv2/phantom/sound_phantom.h
+++ b/engines/mads/madsv2/phantom/sound_phantom.h
@@ -41,42 +41,298 @@ public:
void validate() override;
};
+/**
+ * ASound1 (asound.ph1, _dataOffset = 0x21e0)
+ *
+ * Dispatch table layout:
+ * off_11C32: commands 0â8 (max=8, base=0)
+ * off_11C44: command 16 (max=0x10, base=0x10, 1 entry)
+ * off_11C46: commands 24â27 (max=0x1B, base=0x18, 4 entries)
+ * off_11C4E: commands 32â39 (max=0x27, base=0x20, 8 entries)
+ *
+ * A fifth table (unk_13C3E, commands 64â76) exists but is encoded as raw
+ * sound data bytes used as near-pointers â not reconstructible without the
+ * binary. Those commands are silently ignored.
+ *
+ * command16 (sub_11F70): random background-music selector. Checks whether
+ * channel 0 is already playing one of the five known music pieces; if not,
+ * randomly picks from four music loaders and plays it, storing the choice
+ * in _musicIndex (mirrors word_11F5E in the original).
+ */
class ASound1 : public ASound {
+private:
+ typedef int (ASound1::*CommandPtr)();
+ static const CommandPtr _commandList[40];
+
+ // Mirrors word_11F5E: tracks which music piece was last selected.
+ int _musicIndex;
+
+ // Background-music loaders (targets of the CS:0x1F60 indirect table).
+ int commandMusic0(); // sub_11D84 â starts at 0x1ECA
+ int commandMusic1(); // sub_11EE6 â starts at 0x3418
+ int commandMusic2(); // sub_11F0E â starts at 0x3688
+ int commandMusic3(); // sub_11F36 â starts at 0x3D52
+
+ int command0();
+ int command1();
+ int command2();
+ int command3();
+ int command4();
+ int command5();
+ int command6();
+ int command7();
+ int command8();
+
+ int command16();
+
+ int command24();
+ int command25();
+ int command26();
+ int command27();
+
+ int command32();
+ int command33();
+ int command34();
+ int command35();
+ int command36();
+ int command37();
+ int command38();
+ int command39();
+
public:
ASound1(Audio::Mixer *mixer, OPL::OPL *opl);
- ~ASound1() override {
- }
+ ~ASound1() override {}
int command(int commandId, int param) override;
};
+/**
+ * ASound2 (asound.ph2, _dataOffset = 0x2040)
+ *
+ * Dispatch table layout:
+ * asound_commands1: commands 0â8 (max=8, base=0)
+ * asound_commands2: command 16 (max=0x10, base=0x10, 1 entry)
+ * asound_commands3: commands 24â27 (max=0x1B, base=0x18, 4 entries)
+ * asound_commands4: commands 32â35 (max=0x23, base=0x20, 4 entries)
+ * asound_commands5: commands 64â72 (max=0x48, base=0x40, 9 entries)
+ */
class ASound2 : public ASound {
+private:
+ typedef int (ASound2::*CommandPtr)();
+ static const CommandPtr _commandList[73];
+
+ int command0();
+ int command1();
+ int command2();
+ int command3();
+ int command4();
+ int command5();
+ int command6();
+ int command7();
+ int command8();
+
+ int command16();
+
+ int command24();
+ int command25();
+ int command26();
+ int command27();
+
+ int command32();
+ int command33();
+ int command34();
+ int command35();
+
+ int command64();
+ int command65();
+ int command66();
+ int command67();
+ int command68();
+ int command69();
+ int command70();
+ int command71();
+ int command72();
+
public:
ASound2(Audio::Mixer *mixer, OPL::OPL *opl);
~ASound2() override {}
int command(int commandId, int param) override;
};
+/**
+ * ASound3 (asound.ph3, _dataOffset = 0x20c0)
+ *
+ * Dispatch table layout:
+ * asound_commands1: commands 0â8 (max=8, base=0)
+ * asound_commands2: command 16 (max=0x10, base=0x10, 1 entry)
+ * asound_commands3: commands 24â27 (max=0x1B, base=0x18, 4 entries)
+ * asound_commands4: commands 32â37 (max=0x25, base=0x20, 6 entries)
+ * asound_commands5: commands 64â75 (max=0x4B, base=0x40, 12 entries)
+ * (command 76 = nullsub_8, silently ignored by bounds check)
+ */
class ASound3 : public ASound {
+private:
+ typedef int (ASound3::*CommandPtr)();
+ static const CommandPtr _commandList[77];
+
+ // Internal helper: isSoundActive guard on 0xC36, load ch0â7.
+ // Called by command34 which then adds ch8.
+ void sub11CC6();
+
+ int command0();
+ int command1();
+ int command2();
+ int command3();
+ int command4();
+ int command5();
+ int command6();
+ int command7();
+ int command8();
+
+ int command16();
+
+ int command24();
+ int command25();
+ int command26();
+ int command27();
+
+ int command32();
+ int command33();
+ int command34();
+ int command35();
+ int command36();
+ int command37();
+
+ int command64();
+ int command65();
+ int command66();
+ int command67();
+ int command68();
+ int command69();
+ int command70();
+ int command71();
+ int command72();
+ int command73();
+ int command74();
+ int command75();
+
public:
ASound3(Audio::Mixer *mixer, OPL::OPL *opl);
- ~ASound3() override {
- }
+ ~ASound3() override {}
int command(int commandId, int param) override;
};
+/**
+ * ASound4 (asound.ph4, _dataOffset = 0x1f90)
+ *
+ * Dispatch table layout:
+ * asound_commands1: commands 0â8 (max=8, base=0)
+ * asound_commands2: command 16 (max=0x10, base=0x10, 1 entry)
+ * asound_commands3: commands 24â27 (max=0x1B, base=0x18, 4 entries)
+ * asound_commands4: commands 64â70 (max=0x46, base=0x40, 7 entries)
+ * (Commands 32â63 are unreachable: the 0x20-range max constant = 0)
+ *
+ * commands 24 and 25 share the same handler (sub_11D0A).
+ */
class ASound4 : public ASound {
+private:
+ typedef int (ASound4::*CommandPtr)();
+ static const CommandPtr _commandList[71];
+
+ int command0();
+ int command1();
+ int command2();
+ int command3();
+ int command4();
+ int command5();
+ int command6();
+ int command7();
+ int command8();
+
+ int command16();
+
+ int command24();
+ int command25();
+ int command26();
+ int command27();
+
+ int command64();
+ int command65();
+ int command66();
+ int command67();
+ int command68();
+ int command69();
+ int command70();
+
public:
ASound4(Audio::Mixer *mixer, OPL::OPL *opl);
- ~ASound4() override {
- }
+ ~ASound4() override {}
int command(int commandId, int param) override;
};
+/**
+ * ASound5 (asound.ph5, _dataOffset = 0x2140)
+ *
+ * Dispatch table layout:
+ * asound_commands1: commands 0â8 (max=8, base=0)
+ * asound_commands2: command 16 (max=0x10, base=0x10, 1 entry)
+ * asound_commands3: commands 24â27 (max=0x1B, base=0x18, 4 entries)
+ * asound_commands4: commands 32â39 (max=0x27, base=0x20, 8 entries)
+ * asound_commands5: commands 64â78 (max=0x4E, base=0x40, 15 entries)
+ * (command 79 = nullsub_8, silently ignored by bounds check)
+ *
+ * commands 36/35/34 load channels in non-sequential data order.
+ * commands 70, 77, and 78 all play the same 0x40BA sound block.
+ */
class ASound5 : public ASound {
+private:
+ typedef int (ASound5::*CommandPtr)();
+ static const CommandPtr _commandList[79];
+
+ int command0();
+ int command1();
+ int command2();
+ int command3();
+ int command4();
+ int command5();
+ int command6();
+ int command7();
+ int command8();
+
+ int command16();
+
+ int command24();
+ int command25();
+ int command26();
+ int command27();
+
+ int command32();
+ int command33();
+ int command34();
+ int command35();
+ int command36();
+ int command37();
+ int command38();
+ int command39();
+
+ int command64();
+ int command65();
+ int command66();
+ int command67();
+ int command68();
+ int command69();
+ int command70();
+ int command71();
+ int command72();
+ int command73();
+ int command74();
+ int command75();
+ int command76();
+ int command77();
+ int command78();
+
public:
ASound5(Audio::Mixer *mixer, OPL::OPL *opl);
- ~ASound5() override {
- }
+ ~ASound5() override {}
int command(int commandId, int param) override;
};
Commit: d82257eb0555f659753493673ab116bbabeb7101
https://github.com/scummvm/scummvm/commit/d82257eb0555f659753493673ab116bbabeb7101
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:40+10:00
Commit Message:
MADS: PHANTOM: Added room 104
Changed paths:
A engines/mads/madsv2/phantom/mads/inventory.h
A engines/mads/madsv2/phantom/rooms/room104.cpp
A engines/mads/madsv2/phantom/rooms/room104.h
engines/mads/madsv2/phantom/conv.cpp
engines/mads/madsv2/phantom/conv.h
engines/mads/madsv2/phantom/global.h
engines/mads/madsv2/phantom/mads/sounds.h
engines/mads/madsv2/phantom/mads/text.h
engines/mads/madsv2/phantom/mads/words.h
engines/mads/madsv2/phantom/rooms/room103.cpp
engines/mads/module.mk
diff --git a/engines/mads/madsv2/phantom/conv.cpp b/engines/mads/madsv2/phantom/conv.cpp
index 5f29ba9559c..867c235f7bf 100644
--- a/engines/mads/madsv2/phantom/conv.cpp
+++ b/engines/mads/madsv2/phantom/conv.cpp
@@ -102,6 +102,14 @@ void conv_export_value(int varNum) {
// TODO
}
+void conv_hold() {
+ // TODO
+}
+
+void conv_release() {
+ // TODO
+}
+
} // namespace Phantom
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/conv.h b/engines/mads/madsv2/phantom/conv.h
index baa82cba55f..fca87662ae6 100644
--- a/engines/mads/madsv2/phantom/conv.h
+++ b/engines/mads/madsv2/phantom/conv.h
@@ -54,7 +54,26 @@ enum {
conv012_tell_knewhim = 29,
conv012_nomore_first = 30,
- conv012_var_questions_done = 26
+ conv012_var_questions_done = 26,
+
+ conv007_richard_intro_b = 2,
+ conv007_daaeb_intro_c = 3,
+ conv007_where_pushed = 8,
+ conv007_where_killed = 10,
+ conv007_badfall_abc = 11,
+ conv007_youraoul_abc = 12,
+ conv007_kiss_abc = 13,
+ conv007_afterkiss_abc = 14,
+ conv007_delirious_abc = 16,
+ conv007_long_abc = 20,
+ conv007_worry_abc = 21,
+ conv007_dashing_tuxedo = 22,
+ conv007_dashing_london = 23,
+ conv007_answers_abc = 24,
+ conv007_final_goaway = 25,
+ conv007_office_abc = 28,
+ conv007_solo_alone = 30,
+ conv007_pinch_wait_b_nothing_b = 32
};
struct ConvData {
@@ -98,6 +117,8 @@ extern void conv_me_trigger(int trigger);
extern void conv_you_trigger(int trigger);
extern int *conv_get_variable(int varNum);
extern void conv_export_value(int varNum);
+extern void conv_hold();
+extern void conv_release();
} // namespace Phantom
} // namespace MADSV2
diff --git a/engines/mads/madsv2/phantom/global.h b/engines/mads/madsv2/phantom/global.h
index 5693aacfb3f..7213e55dbec 100644
--- a/engines/mads/madsv2/phantom/global.h
+++ b/engines/mads/madsv2/phantom/global.h
@@ -197,6 +197,9 @@ enum {
// player_score_flags
#define SCORE_TRAP_DOOR 1
+// ticket_people_here
+#define SELLER 1
+
} // namespace Phantom
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/mads/inventory.h b/engines/mads/madsv2/phantom/mads/inventory.h
new file mode 100644
index 00000000000..b226bca814a
--- /dev/null
+++ b/engines/mads/madsv2/phantom/mads/inventory.h
@@ -0,0 +1,48 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef MADS_PHANTOM_MADS_INVENTORY_H
+#define MADS_PHANTOM_MADS_INVENTORY_H
+
+#include "common/scummsys.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+
+enum {
+ key = 0,
+ red_frame = 2,
+ sandbag = 3,
+ yellow_frame = 4,
+ small_note = 6,
+ parchment = 12,
+ book = 15,
+ blue_frame = 17,
+ large_note = 18,
+ green_frame = 19
+};
+
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/phantom/mads/sounds.h b/engines/mads/madsv2/phantom/mads/sounds.h
index ac96b2bb508..4325fcb4728 100644
--- a/engines/mads/madsv2/phantom/mads/sounds.h
+++ b/engines/mads/madsv2/phantom/mads/sounds.h
@@ -39,6 +39,7 @@ enum {
N_TrapDoor001 = 64,
N_SqueakyDoor = 66,
N_PlayerFalls = 67,
+ N_EchoSteps = 68,
N_DoorHandle = 73
};
diff --git a/engines/mads/madsv2/phantom/mads/text.h b/engines/mads/madsv2/phantom/mads/text.h
index 925ce0fe86d..91f6b4bde90 100644
--- a/engines/mads/madsv2/phantom/mads/text.h
+++ b/engines/mads/madsv2/phantom/mads/text.h
@@ -113,7 +113,34 @@ enum {
text_103_48 = 10348,
text_103_49 = 10349,
text_103_50 = 10350,
- text_103_51 = 10351
+ text_103_51 = 10351,
+
+ /* Room 104 */
+ text_104_10 = 10410,
+ text_104_11 = 10411,
+ text_104_12 = 10412,
+ text_104_13 = 10413,
+ text_104_14 = 10414,
+ text_104_15 = 10415,
+ text_104_16 = 10416,
+ text_104_17 = 10417,
+ text_104_18 = 10418,
+ text_104_19 = 10419,
+ text_104_20 = 10420,
+ text_104_21 = 10421,
+ text_104_22 = 10422,
+ text_104_23 = 10423,
+ text_104_24 = 10424,
+ text_104_25 = 10425,
+ text_104_26 = 10426,
+ text_104_27 = 10427,
+ text_104_28 = 10428,
+ text_104_29 = 10429,
+ text_104_30 = 10430,
+ text_104_32 = 10432,
+ text_104_33 = 10433,
+ text_104_34 = 10434,
+ text_104_35 = 10435
};
} // namespace Phantom
diff --git a/engines/mads/madsv2/phantom/mads/words.h b/engines/mads/madsv2/phantom/mads/words.h
index 8be6c8a38fd..6961c258810 100644
--- a/engines/mads/madsv2/phantom/mads/words.h
+++ b/engines/mads/madsv2/phantom/mads/words.h
@@ -39,11 +39,14 @@ enum {
words_climb_through = 35,
words_conductor_s_stand = 37,
words_door = 46,
+ words_exit = 52,
words_exit_to = 55,
words_exposed_brick = 67,
words_floor = 73,
words_folding_chairs = 74,
words_garbage_can = 75,
+ words_house = 80,
+ words_jump_into = 82,
words_junk = 84,
words_key = 85,
words_leg = 90,
@@ -60,6 +63,8 @@ enum {
words_seats = 129,
words_side_wall = 130,
words_stage = 132,
+ words_stage_left = 134,
+ words_stage_right = 135,
words_stair_unit = 137,
words_trap_ceiling = 147,
words_trap_door = 148,
@@ -79,7 +84,8 @@ enum {
words_gentleman = 281,
words_climb = 288,
words_prompter_s_seat = 300,
- words_lever = 301
+ words_lever = 301,
+ words_Monsieur_Richard = 302
};
} // namespace Phantom
diff --git a/engines/mads/madsv2/phantom/rooms/room103.cpp b/engines/mads/madsv2/phantom/rooms/room103.cpp
index d5ec6c7e749..121259401e3 100644
--- a/engines/mads/madsv2/phantom/rooms/room103.cpp
+++ b/engines/mads/madsv2/phantom/rooms/room103.cpp
@@ -31,6 +31,7 @@
#include "mads/madsv2/phantom/mads/words.h"
#include "mads/madsv2/phantom/mads/sounds.h"
#include "mads/madsv2/phantom/mads/text.h"
+#include "mads/madsv2/phantom/mads/inventory.h"
#include "mads/madsv2/phantom/conv.h"
#include "mads/madsv2/phantom/rooms/section1.h"
#include "mads/madsv2/phantom/rooms/room103.h"
@@ -40,8 +41,6 @@ namespace MADSV2 {
namespace Phantom {
namespace Rooms {
-constexpr int key = 0;
-
void room_103_adjust_rails(int variant) {
switch (variant) {
case 0:
diff --git a/engines/mads/madsv2/phantom/rooms/room104.cpp b/engines/mads/madsv2/phantom/rooms/room104.cpp
new file mode 100644
index 00000000000..de113c34049
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room104.cpp
@@ -0,0 +1,1140 @@
+/* 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 "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/imath.h"
+#include "mads/madsv2/core/text.h"
+#include "mads/madsv2/core/inter.h"
+#include "mads/madsv2/core/object.h"
+#include "mads/madsv2/core/sound.h"
+#include "mads/madsv2/core/camera.h"
+#include "mads/madsv2/phantom/global.h"
+#include "mads/madsv2/phantom/mads/words.h"
+#include "mads/madsv2/phantom/mads/sounds.h"
+#include "mads/madsv2/phantom/mads/text.h"
+#include "mads/madsv2/phantom/mads/inventory.h"
+#include "mads/madsv2/phantom/conv.h"
+#include "mads/madsv2/phantom/rooms/section1.h"
+#include "mads/madsv2/phantom/rooms/room104.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+static void get_rid_of_inventory() {
+ if (player_has(large_note)) {
+ inter_move_object(large_note, NOWHERE);
+ }
+
+ if (player_has(sandbag)) {
+ inter_move_object(sandbag, NOWHERE);
+ }
+
+ if (player_has(small_note)) {
+ inter_move_object(small_note, NOWHERE);
+ }
+
+ if (player_has(parchment)) {
+ inter_move_object(parchment, NOWHERE);
+ }
+
+ if (player_has(book)) {
+ inter_move_object(book, NOWHERE);
+ }
+
+ if (player_has(red_frame)) {
+ inter_move_object(red_frame, 105);
+ }
+
+ if (player_has(yellow_frame)) {
+ inter_move_object(yellow_frame, 107);
+ }
+
+ if (player_has(blue_frame)) {
+ inter_move_object(blue_frame, 302);
+ }
+
+ if (player_has(green_frame)) {
+ inter_move_object(green_frame, 307);
+ }
+}
+
+static void handle_animation_daae_walk() {
+ int daae_walk_reset_frame;
+
+ if (kernel_anim[aa[2]].frame != local->daae_walk_frame) {
+ local->daae_walk_frame = kernel_anim[aa[2]].frame;
+ daae_walk_reset_frame = -1;
+
+ switch (local->daae_walk_frame) {
+ case 1: /* end of invisible */
+ if (local->daae_walk_action == CONV7_DAAE_WALK_INVISIBLE) {
+ daae_walk_reset_frame = 0;
+ } else {
+ kernel_synch(KERNEL_ANIM, aa[2], KERNEL_ANIM, aa[1]);
+ daae_walk_reset_frame = 1;
+ }
+ break;
+
+ case 138: /* end of walking away */
+ local->daae_walk_action = CONV7_DAAE_WALK_INVISIBLE;
+ daae_walk_reset_frame = 0;
+ break;
+ }
+
+ if (daae_walk_reset_frame >= 0) {
+ kernel_reset_animation(aa[2], daae_walk_reset_frame);
+ local->daae_walk_frame = daae_walk_reset_frame;
+ }
+ }
+}
+
+static void handle_animation_rich() {
+ int random = 0;
+ int rich_reset_frame;
+
+ if (kernel_anim[aa[0]].frame != local->rich_frame) {
+ local->rich_frame = kernel_anim[aa[0]].frame;
+ rich_reset_frame = -1;
+
+ switch (local->rich_frame) {
+ case 117: /* somewhere into Richard walking away */
+ local->couple_action = CONV7_COUPLE_RAOUL_ALONE;
+ break;
+
+ case 1: /* end of freeze */
+ case 2: /* end of talk 1 */
+ case 3: /* end of talk 2 */
+ case 4: /* end of talk 3 */
+ case 8: /* end of head right */
+ case 14: /* end of head left */
+ case 44: /* end of head up */
+ case 48: /* end of head down */
+ case 22: /* end of hand on chin */
+ case 34: /* end of arms out */
+ case 40: /* end of point */
+
+ if (local->rich_action == CONV7_RICH_TALK) {
+ random = imath_random(1, 3);
+ ++local->rich_talk_count;
+ if (local->rich_talk_count > 15) {
+ local->rich_action = CONV7_RICH_SHUT_UP;
+ random = 40;
+ }
+ }
+
+ if (local->rich_action == CONV7_RICH_SHUT_UP) {
+ random = imath_random(7, 80);
+ }
+
+ if (local->rich_action == CONV7_RICH_ARMS_OUT) {
+ random = 4;
+ local->rich_action = CONV7_RICH_TALK;
+ local->rich_talk_count = 8;
+ }
+
+ if (local->rich_action == CONV7_RICH_POINT) {
+ random = 5;
+ local->rich_action = CONV7_RICH_TALK;
+ local->rich_talk_count = 8;
+ }
+
+ if (local->rich_action == CONV7_RICH_WALK) {
+ random = 6;
+ }
+
+ if (local->rich_action == CONV7_RICH_LOOK_UP) {
+ random = 7;
+ }
+
+ switch (random) {
+ case 1: rich_reset_frame = 1; break; /* do talk 1 */
+ case 2: rich_reset_frame = 2; break; /* do talk 2 */
+ case 3: rich_reset_frame = 3; break; /* do talk 3 */
+ case 4: rich_reset_frame = 23; break; /* put arms out */
+ case 5: rich_reset_frame = 35; break; /* point */
+ case 6: rich_reset_frame = 49; break; /* walk away */
+ case 7: rich_reset_frame = 41; break; /* look up */
+ case 8: rich_reset_frame = 45; break; /* look down */
+ case 9: rich_reset_frame = 9; break; /* look left */
+ case 10: rich_reset_frame = 5; break; /* look right */
+ case 11: rich_reset_frame = 15; break; /* hand on chin */
+ default: rich_reset_frame = 0; break; /* shut up */
+ }
+ break;
+
+ case 125:
+ rich_reset_frame = 124;
+ break; /* keep Richard invisible */
+ }
+
+ if (rich_reset_frame >= 0) {
+ kernel_reset_animation(aa[0], rich_reset_frame);
+ local->rich_frame = rich_reset_frame;
+ }
+ }
+}
+
+static void handle_animation_couple() {
+ int random = 0;
+ int couple_reset_frame;
+
+ if (kernel_anim[aa[1]].frame != local->couple_frame) {
+ local->couple_frame = kernel_anim[aa[1]].frame;
+ couple_reset_frame = -1;
+
+ switch (local->couple_frame) {
+ case 1: /* end of laying flat out on the stage */
+ case 103: /* end of her talking to him 1 while he is flat on stage */
+ case 104: /* end of her talking to him 2 while he is flat on stage */
+ case 105: /* end of her talking to him 3 while he is flat on stage */
+
+ if (local->couple_action == CONV7_COUPLE_STAY_DOWN) {
+ couple_reset_frame = 0;
+
+ } else {
+ couple_reset_frame = imath_random(102, 104);
+ ++local->couple_she_talk_count;
+ if (local->couple_she_talk_count > 15) {
+ if (local->wants_to_get_up) {
+ local->couple_action = CONV7_COUPLE_TOUCH_HEAD;
+ couple_reset_frame = 1;
+ } else {
+ local->couple_action = CONV7_COUPLE_STAY_DOWN;
+ couple_reset_frame = 0;
+ }
+ }
+ }
+ break;
+
+ case 9: /* end of waking up */
+ case 10: /* end of he talking to her 1 */
+ case 11: /* end of he talking to her 2 */
+ case 12: /* end of he talking to her 3 */
+ case 13: /* end of she talking to him 1 */
+ case 14: /* end of she talking to him 2 */
+ case 15: /* end of she talking to him 3 */
+ case 25: /* end of turn to face each other */
+ case 33: /* end of kiss */
+ case 41: /* end of touch head */
+ switch (local->couple_frame) {
+ case 9:
+ local->couple_action = CONV7_COUPLE_TOUCH_HEAD;
+ break;
+
+ case 33: /* end of kiss */
+ conv_release();
+ if (player_verb == conv007_kiss_abc) {
+ local->couple_action = CONV7_COUPLE_SHE_TALK;
+ }
+ break;
+
+ case 41: /* end of touch head */
+ conv_release();
+ local->sitting_up = true;
+ if (local->wants_to_talk) {
+ local->couple_action = CONV7_COUPLE_HE_TALK;
+ } else {
+ local->couple_action = CONV7_COUPLE_SHUT_UP;
+ }
+ break;
+ }
+
+ switch (local->couple_action) {
+ case CONV7_COUPLE_SHE_TALK:
+ if (local->get_ready_she_leave) {
+ random = 10;
+ /* get up and walk away */
+ } else {
+ random = imath_random(1, 3);
+ ++local->couple_she_talk_count;
+ if (local->couple_she_talk_count > 15) {
+ local->couple_action = CONV7_COUPLE_SHUT_UP;
+ random = 12;
+ }
+ }
+ break;
+
+ case CONV7_COUPLE_HE_TALK:
+ random = imath_random(4, 6);
+ ++local->couple_he_talk_count;
+ if (local->couple_he_talk_count > 15) {
+ local->couple_action = CONV7_COUPLE_SHUT_UP;
+ random = 12;
+ }
+ break;
+
+ case CONV7_COUPLE_TOUCH_HEAD:
+ local->couple_action = CONV7_COUPLE_SHUT_UP;
+ random = 7;
+ break;
+
+ case CONV7_COUPLE_KISS:
+ local->couple_action = CONV7_COUPLE_SHUT_UP;
+ random = 8;
+ break;
+
+ case CONV7_COUPLE_RAOUL_ALONE:
+ random = 9;
+ break;
+
+ case CONV7_COUPLE_SHE_WALK:
+ random = 10;
+ break;
+
+ case CONV7_COUPLE_SHUT_UP_R:
+ case CONV7_COUPLE_HE_TALK_R:
+ case CONV7_COUPLE_SHE_TALK_R:
+ random = 11;
+ break;
+
+ case CONV7_COUPLE_SHUT_UP:
+ random = 12;
+ break;
+ }
+
+ switch (random) {
+ case 1: couple_reset_frame = 12; break; /* do she talk 1 to Raoul */
+ case 2: couple_reset_frame = 13; break; /* do she talk 2 to Raoul */
+ case 3: couple_reset_frame = 14; break; /* do she talk 3 to Raoul */
+ case 4: couple_reset_frame = 9; break; /* do Raoul talk 1 to her */
+ case 5: couple_reset_frame = 10; break; /* do Raoul talk 2 to her */
+ case 6: couple_reset_frame = 11; break; /* do Raoul talk 3 to her */
+ case 7: couple_reset_frame = 33; break; /* touch head */
+ case 8: couple_reset_frame = 25; break; /* she kiss him */
+ case 9: couple_reset_frame = 54; break; /* he get up */
+ case 10: couple_reset_frame = 41; break; /* she get up and walk */
+ case 11: couple_reset_frame = 15; break; /* they turn to Richard */
+ case 12: couple_reset_frame = 14; break; /* freeze looking at each other */
+ }
+ break;
+
+ case 17: /* end of she & Raoul turn to Richard */
+ case 18: /* end of Raoul talk to Richard 1 */
+ case 19: /* end of Raoul talk to Richard 2 */
+ case 20: /* end of Raoul talk to Richard 3 */
+ case 21: /* end of she talk to Richard 1 */
+ case 22: /* end of she talk to Richard 2 */
+ case 23: /* end of she talk to Richard 3 */
+ switch (local->couple_action) {
+ case CONV7_COUPLE_LOOK_AT_R_SHORT:
+ random = 1; /* make the couple look at Richard (short period of time) */
+ ++local->couple_look_rich_count;
+ if (local->couple_look_rich_count > 6) {
+ local->couple_action = CONV7_COUPLE_SHUT_UP;
+ random = 7;
+ }
+ break;
+
+ case CONV7_COUPLE_LOOK_AT_R_LONG:
+ random = 1; /* make the couple look at Richard (long period of time) */
+ break;
+
+ case CONV7_COUPLE_SHE_TALK_R:
+ random = imath_random(1, 3);
+ ++local->couple_she_talk_count;
+ if (local->couple_she_talk_count > 15) {
+ local->couple_action = CONV7_COUPLE_SHUT_UP;
+ random = 7;
+ }
+ break;
+
+ case CONV7_COUPLE_HE_TALK_R:
+ random = imath_random(4, 6);
+ ++local->couple_he_talk_count;
+ if (local->couple_he_talk_count > 15) {
+ local->couple_action = CONV7_COUPLE_SHUT_UP_R;
+ random = 8;
+ }
+ break;
+
+ case CONV7_COUPLE_SHUT_UP:
+ case CONV7_COUPLE_HE_TALK:
+ case CONV7_COUPLE_SHE_TALK:
+ case CONV7_COUPLE_KISS:
+ case CONV7_COUPLE_HE_GET_UP:
+ case CONV7_COUPLE_SHE_WALK:
+ case CONV7_COUPLE_TOUCH_HEAD:
+ random = 7;
+ break;
+
+ case CONV7_COUPLE_SHUT_UP_R:
+ random = 8;
+ break;
+ }
+
+ switch (random) {
+ case 1: couple_reset_frame = 20; break; /* do she talk 1 to Rich */
+ case 2: couple_reset_frame = 21; break; /* do she talk 2 to Rich */
+ case 3: couple_reset_frame = 22; break; /* do she talk 3 to Rich */
+ case 4: couple_reset_frame = 17; break; /* do Raoul talk 1 to Rich */
+ case 5: couple_reset_frame = 18; break; /* do Raoul talk 2 to Rich */
+ case 6: couple_reset_frame = 19; break; /* do Raoul talk 3 to Rich */
+ case 7: couple_reset_frame = 23; break; /* they look at each other */
+ case 8: couple_reset_frame = 20; break; /* they freeze looking at Richard */
+ }
+ break;
+
+ case 52: /* end of she getting up - start anim d1 */
+ local->daae_walk_action = CONV7_DAAE_WALK_LEAVE;
+ couple_reset_frame = 54;
+ break;
+
+ case 55: /* end of Raoul sitting up alone */
+ if (local->couple_action != CONV7_COUPLE_RAOUL_ALONE) {
+ couple_reset_frame = 54;
+ }
+ break;
+
+ case 89: /* almost end of getting to start pinching */
+ conv_release();
+ break;
+
+ case 90: /* end of getting to start pinching */
+ if (local->couple_action != CONV7_COUPLE_PINCH) {
+ couple_reset_frame = 89;
+ } else {
+ couple_reset_frame = 90;
+ global[temp_var] = 200;
+ /* This is to help me debug this pinching thing. If the player
+ does pinch himself, then this variable will be set. */
+ }
+ break;
+
+ case 102: /* end of getting on feet */
+ conv_release();
+ player.x = AFTER_CONV_X;
+ player.y = AFTER_CONV_Y;
+ player_demand_facing(FACING_SOUTH);
+ couple_reset_frame = 105;
+ player.walker_visible = true;
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_ANIM, aa[1]);
+ break;
+
+ case 106: /* end of invisible */
+ local->couple_action = CONV7_COUPLE_INVISIBLE;
+ couple_reset_frame = 105;
+ break;
+ }
+
+ if (couple_reset_frame >= 0) {
+ kernel_reset_animation(aa[1], couple_reset_frame);
+ local->couple_frame = couple_reset_frame;
+ }
+ }
+}
+
+static void handle_player_walk() {
+ if (player.sprite != local->last_player_step) {
+ local->last_player_step = player.sprite;
+ switch (player.facing) {
+ case FACING_NORTH:
+ case FACING_SOUTH:
+ if ((player.sprite == 5) || (player.sprite == 11))
+ sound_play(N_EchoSteps);
+ break;
+
+ case FACING_NORTHEAST:
+ case FACING_NORTHWEST:
+ case FACING_SOUTHEAST:
+ case FACING_SOUTHWEST:
+ if ((player.sprite == 7) || (player.sprite == 14))
+ sound_play(N_EchoSteps);
+ break;
+
+ case FACING_EAST:
+ case FACING_WEST:
+ if ((player.sprite == 8) || (player.sprite == 16))
+ sound_play(N_EchoSteps);
+ break;
+ }
+ }
+}
+
+void room_104_init() {
+ kernel.disable_fastwalk = true;
+
+ if (previous_room != KERNEL_RESTORING_GAME) {
+ local->anim_0_running = false;
+ local->anim_1_running = false;
+ local->anim_2_running = false;
+ local->wants_to_talk = false;
+ local->wants_to_get_up = false;
+ local->sitting_up = false;
+ local->get_ready_she_leave = false;
+ local->wants_to_stand_up = false;
+ }
+
+ /* ==================== Load Sprite Series ====================== */
+
+ ss[fx_climb_thru] = kernel_load_series(kernel_name('a', 0), false);
+ ss[fx_fall] = kernel_load_series(kernel_name('a', 6), false);
+ ss[fx_trap_door] = kernel_load_series(kernel_name('x', 0), false);
+
+ if (global[current_year] == 1993) {
+ ss[fx_chandelier] = kernel_load_series(kernel_name('z', 0), false);
+ }
+
+
+ /* ==================== Load conversation ======================= */
+
+ conv_get(CONV_AFTER_FALL_FROM_301);
+
+
+ /* ==================== Do trap door stuff ====================== */
+
+ if (global[trap_door_status] == TRAP_DOOR_IS_CLOSED) {
+ seq[fx_trap_door] = kernel_seq_stamp(ss[fx_trap_door], false, 1);
+ kernel_seq_depth(seq[fx_trap_door], 15);
+ } else {
+ seq[fx_trap_door] = kernel_seq_stamp(ss[fx_trap_door], false, 2);
+ kernel_seq_depth(seq[fx_trap_door], 15);
+ }
+
+
+ /* ==================== Previous Rooms ========================== */
+
+ if (previous_room == KERNEL_RESTORING_GAME) {
+
+ if (conv_restore_running == CONV_AFTER_FALL_FROM_301) {
+
+ aa[1] = kernel_run_animation(kernel_name('r', 1), 1);
+ /* anim of couple on floor of stage (Raoul & Daae) */
+
+ aa[2] = kernel_run_animation(kernel_name('d', 1), 1);
+ local->daae_walk_action = CONV7_DAAE_WALK_INVISIBLE;
+ /* anim of Daae walking off stage */
+
+ aa[0] = kernel_run_animation(kernel_name('m', 1), 1);
+ /* anim of Monsieur Richard */
+
+ if (local->couple_action < CONV7_COUPLE_STAY_DOWN) {
+ local->couple_action = CONV7_COUPLE_SHUT_UP;
+ local->rich_action = CONV7_RICH_SHUT_UP;
+ kernel_reset_animation(aa[1], 14);
+ /* make the couple look at each other on the floor */
+ } else {
+ local->couple_action = CONV7_COUPLE_INVISIBLE;
+ local->rich_action = CONV7_RICH_WALK;
+ kernel_reset_animation(aa[1], 105);
+ /* make the couple invisible */
+ kernel_reset_animation(aa[0], 216);
+ /* make Richard invisible */
+ }
+
+ conv_run(CONV_AFTER_FALL_FROM_301);
+ conv_export_pointer(&global[player_score]);
+ player.walker_visible = false;
+ }
+
+ } else if (previous_room == 301) {
+
+ aa[1] = kernel_run_animation(kernel_name('r', 1), 1);
+ local->anim_1_running = true;
+ local->couple_action = CONV7_COUPLE_STAY_DOWN;
+ /* anim of couple on floor of stage (Raoul & Daae) */
+
+ aa[2] = kernel_run_animation(kernel_name('d', 1), 1);
+ local->anim_2_running = true;
+ local->daae_walk_action = CONV7_DAAE_WALK_INVISIBLE;
+ /* anim of Daae walking off stage */
+
+ aa[0] = kernel_run_animation(kernel_name('m', 1), 1);
+ local->anim_0_running = true;
+ local->rich_action = CONV7_RICH_SHUT_UP;
+ /* anim of Monsieur Richard */
+
+ get_rid_of_inventory();
+
+ player.walker_visible = false;
+ player.num_rooms_been_in = 0;
+ global[trap_door_status] = TRAP_DOOR_IS_CLOSED;
+ global[current_year] = 1881;
+ global[prompter_stand_status] = PROMPT_RIGHT;
+ global[ticket_people_here] = SELLER;
+ global[make_brie_leave_203] = false;
+ /* we are in 1881 now, so the stand should be on right */
+ player.x = 161; /* picked this number from my nose. don't want the camera to pan */
+
+ player_discover_room(301); /* so the shadow does not appear again */
+ player_discover_room(101); /* so the opening fugue does not repeat */
+
+ camera_jump_to(LEFT_STAGE + 60, 0);
+
+ kernel_timing_trigger(1, ROOM_104_INIT_TEXT);
+
+ } else if (previous_room == 103) {
+ if (global[room_103_104_transition] == PEEK_THROUGH) {
+ kernel_init_dialog(); /* clear interface */
+ kernel_set_interface_mode(INTER_CONVERSATION);
+
+ if (!global[observed_phan_104]) {
+ aa[4] = kernel_run_animation(kernel_name('p', 1), ROOM_104_END_PHANTOM);
+ player.x = 319; /* pulled this number from my ass (so camera won't scroll) */
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ camera_jump_to(MIDDLE_STAGE, 0);
+ /* player will peek through box, and see Phantom */
+
+ } else {
+ aa[5] = kernel_run_animation(kernel_name('p', 2), ROOM_104_END_PHANTOM + 1);
+ player.x = 319; /* pulled this number from my ass (so camera won't scroll) */
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ camera_jump_to(MIDDLE_STAGE, 0);
+ /* player will peek through box, and see nothing */
+ }
+
+ } else {
+ player.x = NEW_ROOM_FROM_103_X;
+ player.y = NEW_ROOM_FROM_103_Y;
+ player.facing = FACING_SOUTH;
+ camera_jump_to(MIDDLE_STAGE, 0);
+ }
+
+ } else if (previous_room == 102) { /* return from death */
+ switch (global[death_location]) {
+ case FAR_PIT:
+ player.x = RESTORE_X_FAR;
+ player.y = RESTORE_Y_FAR;
+ camera_jump_to(RIGHT_STAGE, 0);
+ break;
+
+ case MIDDLE_PIT:
+ player.x = RESTORE_X_MIDDLE;
+ player.y = RESTORE_Y_MIDDLE;
+ camera_jump_to(MIDDLE_STAGE, 0);
+ break;
+
+ case NEAR_PIT:
+ player.x = RESTORE_X_NEAR;
+ player.y = RESTORE_Y_NEAR;
+ break;
+ }
+
+ } else if (previous_room == 108) {
+ if (player.x > 213) {
+ player.y = PLAYER_Y_FROM_108_3;
+ } else if (player.x > 110) {
+ player.y = PLAYER_Y_FROM_108_2;
+ } else {
+ player.y = PLAYER_Y_FROM_108_1;
+ }
+
+ player_first_walk(OFF_SCREEN_X_FROM_108, player.y, FACING_EAST,
+ PLAYER_X_FROM_108, player.y, FACING_EAST, true);
+
+ } else if ((previous_room == 107) || (previous_room != KERNEL_RESTORING_GAME)) {
+ if (player.x > 191) {
+ player.y = PLAYER_Y_FROM_107_3;
+ } else if (player.x > 104) {
+ player.y = PLAYER_Y_FROM_107_2;
+ } else {
+ player.y = PLAYER_Y_FROM_107_1;
+ }
+
+ player_first_walk(OFF_SCREEN_X_FROM_107, player.y, FACING_WEST,
+ PLAYER_X_FROM_107, player.y, FACING_WEST, true);
+
+ camera_jump_to(RIGHT_STAGE, 0);
+ }
+
+
+ /* ==================== If in 1993, put chandelier here ========= */
+
+ if (global[current_year] == 1993) {
+ seq[fx_chandelier] = kernel_seq_stamp(ss[fx_chandelier], false, 1);
+ kernel_seq_depth(seq[fx_chandelier], 14);
+ } else {
+ kernel_flip_hotspot(words_chandelier, false);
+ }
+
+
+ /* ==================== Do trap door stuff ====================== */
+
+ if (global[trap_door_status] == TRAP_DOOR_IS_CLOSED) {
+ seq[fx_trap_door] = kernel_seq_stamp(ss[fx_trap_door], false, 1);
+ kernel_seq_depth(seq[fx_trap_door], 15);
+ } else {
+ seq[fx_trap_door] = kernel_seq_stamp(ss[fx_trap_door], false, 2);
+ kernel_seq_depth(seq[fx_trap_door], 15);
+ }
+
+ section_1_music();
+}
+
+void room_104_daemon() {
+ if (local->anim_0_running) {
+ handle_animation_rich();
+ }
+
+ if (local->anim_1_running) {
+ handle_animation_couple();
+ }
+
+ if (local->anim_2_running) {
+ handle_animation_daae_walk();
+ }
+
+ if (player.walking) {
+ handle_player_walk();
+ }
+
+ if (kernel.trigger == ROOM_104_INIT_TEXT) {
+ text_show(text_104_34);
+ conv_run(CONV_AFTER_FALL_FROM_301);
+ conv_export_pointer(&global[player_score]);
+ }
+
+ if (kernel.trigger == ROOM_104_END_PHANTOM) {
+ new_room = 103;
+ player.x = 400; /* in 103, because Player_x == 400, will stop phantom music
+ and start normal background music */
+ global[room_103_104_transition] = PEEK_THROUGH;
+ }
+
+ if (kernel.trigger == ROOM_104_END_PHANTOM + 1) {
+ new_room = 103;
+ global[room_103_104_transition] = PEEK_THROUGH;
+ }
+}
+
+static void process_conversation_fall() {
+ int you_trig_flag = false;
+ int me_trig_flag = false;
+
+ switch (player_verb) {
+ case conv007_where_pushed:
+ conv_you_trigger(ROOM_104_POINT);
+ you_trig_flag = true;
+ break;
+
+ case conv007_dashing_london:
+ conv_you_trigger(ROOM_104_ARMS_OUT);
+ you_trig_flag = true;
+ break;
+
+ case conv007_office_abc:
+ conv_you_trigger(ROOM_104_GET_TO_SHE_WALK);
+ you_trig_flag = true;
+ break;
+
+ case conv007_solo_alone:
+ if (!kernel.trigger) {
+ conv_hold();
+ local->rich_action = CONV7_RICH_WALK;
+ }
+ break;
+
+ case conv007_pinch_wait_b_nothing_b:
+ local->couple_action = CONV7_COUPLE_PINCH;
+ me_trig_flag = true;
+ you_trig_flag = true;
+ conv_hold();
+ break;
+
+ case conv007_dashing_tuxedo:
+ conv_you_trigger(ROOM_104_RICHARD_TALK);
+ conv_me_trigger(ROOM_104_HE_TALK_TO_RICH);
+ you_trig_flag = true;
+ me_trig_flag = true;
+ break;
+
+ case conv007_badfall_abc:
+ conv_you_trigger(ROOM_104_SHE_TALK_TO_RICH);
+ you_trig_flag = true;
+ break;
+
+ case conv007_daaeb_intro_c:
+ if (!local->wants_to_get_up) {
+ conv_you_trigger(ROOM_104_SIT_UP);
+ you_trig_flag = true;
+ local->wants_to_get_up = true;
+ }
+ break;
+
+ case conv007_afterkiss_abc:
+ case conv007_final_goaway:
+ if (!kernel.trigger) {
+ local->rich_action = CONV7_RICH_SHUT_UP;
+ local->couple_action = CONV7_COUPLE_KISS;
+ conv_hold();
+ }
+ break;
+
+ case conv007_richard_intro_b:
+ case conv007_where_killed:
+ case conv007_youraoul_abc:
+ case conv007_delirious_abc:
+ case conv007_long_abc:
+ case conv007_worry_abc:
+ case conv007_answers_abc:
+ conv_you_trigger(ROOM_104_RICHARD_TALK);
+ you_trig_flag = true;
+ break;
+ }
+
+ switch (kernel.trigger) {
+ case ROOM_104_COMMANDS_ALLOWED_NOT:
+ conv_release();
+ if (local->couple_action != CONV7_COUPLE_INVISIBLE) {
+ player.commands_allowed = false;
+ }
+ break;
+
+ case ROOM_104_POINT:
+ local->rich_action = CONV7_RICH_POINT;
+ break;
+
+ case ROOM_104_ARMS_OUT:
+ local->rich_action = CONV7_RICH_ARMS_OUT;
+ break;
+
+ case ROOM_104_GET_TO_SHE_WALK:
+ local->rich_action = CONV7_RICH_TALK;
+ local->get_ready_he_leave = true;
+ local->couple_action = CONV7_COUPLE_SHE_WALK;
+ break;
+
+ case ROOM_104_SIT_UP:
+ conv_hold();
+ local->couple_action = CONV7_COUPLE_SHE_TALK_LAY;
+ break;
+
+ case ROOM_104_SHE_TALK_TO_RICH:
+ local->rich_action = CONV7_RICH_SHUT_UP;
+ local->couple_action = CONV7_COUPLE_SHE_TALK_R;
+ break;
+
+ case ROOM_104_HE_TALK_TO_RICH:
+ local->rich_action = CONV7_RICH_SHUT_UP;
+ local->couple_action = CONV7_COUPLE_HE_TALK_R;
+ break;
+
+ case ROOM_104_RICHARD_TALK:
+ local->rich_action = CONV7_RICH_TALK;
+
+ if (local->sitting_up) {
+ if (player_verb == conv007_long_abc) {
+ local->couple_look_rich_count = 0;
+ local->couple_action = CONV7_COUPLE_LOOK_AT_R_SHORT;
+
+ } else if ((player_verb == conv007_worry_abc) ||
+ (player_verb == conv007_dashing_tuxedo)) {
+ local->couple_look_rich_count = 0;
+ local->couple_action = CONV7_COUPLE_LOOK_AT_R_LONG;
+
+ } else {
+ local->couple_action = CONV7_COUPLE_SHUT_UP;
+ }
+ } else {
+ local->couple_action = CONV7_COUPLE_STAY_DOWN;
+ }
+ break;
+
+ case ROOM_104_SHE_TALK:
+ if ((!local->get_ready_she_leave) && (!local->get_ready_he_leave) &&
+ (local->couple_action != CONV7_COUPLE_PINCH) && (!local->wants_to_stand_up)) {
+ local->rich_action = CONV7_RICH_SHUT_UP;
+ if (local->sitting_up) {
+ local->couple_action = CONV7_COUPLE_SHE_TALK;
+ } else {
+ local->couple_action = CONV7_COUPLE_SHE_TALK_LAY;
+ }
+ }
+ break;
+
+ case ROOM_104_ME_TALK:
+ if ((!local->get_ready_she_leave) && (!local->get_ready_he_leave) &&
+ (local->couple_action != CONV7_COUPLE_PINCH) && (!local->wants_to_stand_up)) {
+ local->rich_action = CONV7_RICH_SHUT_UP;
+ if ((local->sitting_up) && (!local->get_ready_she_leave)) {
+ local->couple_action = CONV7_COUPLE_HE_TALK;
+ local->rich_action = CONV7_RICH_SHUT_UP;
+ }
+ }
+ break;
+ }
+
+
+ /* ==================== Set up me and you triggers ============== */
+
+ if (!me_trig_flag) {
+ if (!local->get_ready_she_leave) {
+ conv_me_trigger(ROOM_104_ME_TALK);
+ }
+ } /* if me_trig_flag == true, then a me trigger is called from above, not here. */
+
+ if (!you_trig_flag) {
+ conv_you_trigger(ROOM_104_SHE_TALK);
+ } /* if you_trig_flag == true, then a you trigger is called from above, not here. */
+
+ local->rich_talk_count = 0;
+ local->couple_he_talk_count = 0;
+ local->couple_she_talk_count = 0;
+}
+
+void room_104_pre_parser() {
+ if (player_said_2(exit, stage_left)) {
+ player.walk_off_edge_to_room = 108;
+ }
+
+ if (player_said_2(exit, stage_right)) {
+ player.walk_off_edge_to_room = 107;
+ }
+
+ if (player_said_2(open, trap_door) || player_said_2(close, trap_door)) {
+ player_walk(320, 92, FACING_NORTH);
+ }
+}
+
+void room_104_parser() {
+ if (conv_control.running == CONV_AFTER_FALL_FROM_301) {
+ process_conversation_fall();
+ goto handled;
+ }
+
+ if (player_said_2(climb_through, trap_door)) {
+ if (global[trap_door_status] == TRAP_DOOR_IS_OPEN) {
+ switch (kernel.trigger) {
+ case 0:
+ player.walker_visible = false;
+ seq[fx_climb_thru] = kernel_seq_forward(ss[fx_climb_thru], false,
+ 8, 0, 0, 1);
+ kernel_seq_depth(seq[fx_climb_thru], 13);
+ kernel_seq_range(seq[fx_climb_thru], 1, 16);
+ kernel_seq_trigger(seq[fx_climb_thru],
+ KERNEL_TRIGGER_EXPIRE, 0, ROOM_104_CLIMB_THRU);
+ break;
+
+ case ROOM_104_CLIMB_THRU:
+ new_room = 103;
+ global[room_103_104_transition] = NEW_ROOM;
+ player.commands_allowed = true;
+ break;
+ }
+ } else {
+ text_show(text_104_29);
+ /* go through trap door when it's closed */
+ }
+ goto handled;
+ }
+
+ if (player_said_2(jump_into, orchestra_pit)) {
+ switch (kernel.trigger) {
+ case 0:
+ if (player.x > 400) {
+ global[death_location] = FAR_PIT;
+ } else if (player.x > 200) {
+ global[death_location] = MIDDLE_PIT;
+ } else {
+ global[death_location] = NEAR_PIT;
+ }
+
+ kernel_load_variant(2);
+
+ if (global[trap_door_status] == TRAP_DOOR_IS_CLOSED) {
+ kernel_draw_to_background(ss[fx_trap_door], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ } else {
+ kernel_draw_to_background(ss[fx_trap_door], 2, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ }
+
+ text_show(text_104_26);
+ player.walker_visible = false;
+ player.commands_allowed = false;
+ seq[fx_fall] = kernel_seq_forward(ss[fx_fall], false, 7, 0, 0, 1);
+ kernel_seq_depth(seq[fx_fall], 15);
+ kernel_seq_range(seq[fx_fall], KERNEL_FIRST, 4);
+ kernel_seq_loc(seq[fx_fall], player.x, player.y);
+ kernel_seq_player(seq[fx_fall], true);
+ kernel_seq_trigger(seq[fx_fall],
+ KERNEL_TRIGGER_EXPIRE, 0, 1);
+ break;
+
+ case 1:
+ seq[fx_fall] = kernel_seq_pingpong(ss[fx_fall], false, 1, 0, 0, 10);
+ kernel_timing_trigger(ONE_SECOND, 2);
+ kernel_seq_range(seq[fx_fall], 4, 4);
+ kernel_seq_depth(seq[fx_fall], 15);
+ kernel_seq_player(seq[fx_fall], true);
+ kernel_seq_motion(seq[fx_fall], 0, 0, 200);
+ break;
+
+ case 2:
+ sound_play(N_AllFade);
+ sound_play(N_PlayerFalls);
+ new_room = 102;
+ break;
+ }
+ goto handled;
+ }
+
+ if (player.look_around) {
+ if (global[current_year] == 1993) {
+ text_show(text_104_10);
+ } else {
+ text_show(text_104_11);
+ }
+ goto handled;
+ }
+
+ if (player_said_1(look) || player_said_1(look_at)) {
+
+ if (player_said_1(stage)) {
+ text_show(text_104_12);
+ goto handled;
+ }
+
+ if (player_said_1(apron)) {
+ text_show(text_104_13);
+ goto handled;
+ }
+
+ if (player_said_1(proscenium_arch)) {
+ text_show(text_104_14);
+ goto handled;
+ }
+
+ if (player_said_1(act_curtain)) {
+ text_show(text_104_15);
+ goto handled;
+ }
+
+ if (player_said_1(orchestra_pit)) {
+ text_show(text_104_16);
+ goto handled;
+ }
+
+ if (player_said_1(conductor_s_stand)) {
+ text_show(text_104_17);
+ goto handled;
+ }
+
+ if ((player_said_1(music_stand)) || (player_said_1(music_stands))) {
+ text_show(text_104_18);
+ goto handled;
+ }
+
+ if (player_said_1(prompter_s_box)) {
+ text_show(text_104_19);
+ goto handled;
+ }
+
+ if (player_said_1(trap_door)) {
+ text_show(text_104_20);
+ goto handled;
+ }
+
+ if (player_said_1(house)) {
+ if (global[current_year] == 1881) {
+ text_show(text_104_21);
+ } else {
+ text_show(text_104_27);
+ }
+ goto handled;
+ }
+
+ if (player_said_1(stage_left)) {
+ text_show(text_104_22);
+ goto handled;
+ }
+
+ if (player_said_1(stage_right)) {
+ text_show(text_104_23);
+ goto handled;
+ }
+
+ if (player_said_1(chandelier)) {
+ text_show(text_104_28);
+ goto handled;
+ }
+
+ if (player_said_1(Monsieur_Richard)) {
+ text_show(text_104_33);
+ goto handled;
+ }
+ }
+
+ if (player_said_2(jump_into, orchestra_pit)) {
+ text_show(text_104_26);
+ new_room = 102;
+ goto handled;
+ }
+
+ if (player_said_2(open, prompter_s_box) || player_said_2(close, prompter_s_box)) {
+ text_show(text_104_30);
+ goto handled;
+ }
+
+ if (player_said_2(open, trap_door)) {
+ if (global[trap_door_status] == TRAP_DOOR_IS_OPEN) {
+ text_show(text_104_24);
+ } else {
+ text_show(text_104_32);
+ }
+ goto handled;
+ }
+
+ if (player_said_2(close, trap_door)) {
+ if (global[trap_door_status] == TRAP_DOOR_IS_CLOSED) {
+ text_show(text_104_25);
+ } else {
+ text_show(text_104_33);
+ }
+ goto handled;
+ }
+
+ if (player_said_2(take, chandelier)) {
+ text_show(text_104_35);
+ goto handled;
+ }
+
+ goto done;
+
+handled:
+ player.command_ready = false;
+
+done:
+ ;
+}
+
+void room_104_preload() {
+ room_init_code_pointer = room_104_init;
+ room_pre_parser_code_pointer = room_104_pre_parser;
+ room_parser_code_pointer = room_104_parser;
+ room_daemon_code_pointer = room_104_daemon;
+
+ section_1_walker();
+ section_1_interface();
+
+ if (global[trap_door_status] == TRAP_DOOR_IS_CLOSED) {
+ kernel_initial_variant = 1;
+ }
+
+ vocab_make_active(words_Monsieur_Richard);
+}
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/rooms/room104.h b/engines/mads/madsv2/phantom/rooms/room104.h
new file mode 100644
index 00000000000..960c422c9d4
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room104.h
@@ -0,0 +1,209 @@
+/* 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/>.
+ *
+ */
+
+/* room104.mac by Paul Lahaise 8-Jan-93 */
+
+#ifndef MADS_PHANTOM_ROOM104_H
+#define MADS_PHANTOM_ROOM104_H
+
+#include "mads/madsv2/phantom/rooms/section1.h"
+#include "mads/madsv2/phantom/global.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+#define local ((Scratch *)(&game.scratch[0]))
+#define ss local->sprite
+#define seq local->sequence
+#define aa local->animation
+
+typedef struct { /* Room local variables */
+
+ int sprite[15]; /* Sprite series handles */
+ int sequence[15]; /* Sequence handles */
+ int animation[6]; /* Animation handles */
+ int anim_0_running;
+ int anim_1_running;
+ int anim_2_running;
+
+ int get_ready_she_leave; /* if T, Daae will, after talking, leave scene */
+ int get_ready_he_leave; /* if T, Daae will, after talking, leave scene */
+
+ int wants_to_talk; /* if T, Raoul will talk */
+ int wants_to_get_up; /* if T, Raoul will sit up */
+
+ int sitting_up; /* T if Raoul is sitting up from fall */
+
+ int rich_action; /* action Richard is going to perform */
+ int rich_frame;
+
+ int raoul_action; /* action Raoul is going to perform */
+ int raoul_frame;
+
+ int daae_walk_action; /* action Daae is going to perform */
+ int daae_walk_frame;
+
+ int couple_action; /* action couple is going to perform */
+ int couple_frame;
+
+ int rich_talk_count; /* counters for talking */
+ int couple_he_talk_count; /* counters for he talking */
+ int couple_she_talk_count; /* counters for she talking */
+ int couple_look_rich_count; /* counter for couple looking at Richard */
+
+ int wants_to_stand_up; /* if T, will not talk, etc. */
+
+ int last_player_step; /* Frame marker for player walk */
+
+} Scratch;
+
+
+/* ========================= Sprite Series ========================= */
+
+#define fx_trap_door 0 /* rm104x0 */
+#define fx_climb_thru 1 /* rm104a0 */
+#define fx_chandelier 2 /* rm104z0 */
+#define fx_fall 3 /* rm104a6 */
+
+
+/* ========================= Triggers ============================== */
+
+#define ROOM_104_CLIMB_THRU 60
+#define ROOM_104_TRAP_DOOR_MOVEMENT 65
+#define ROOM_104_SIT_UP 67
+#define ROOM_104_SHE_TALK 69
+#define ROOM_104_ME_TALK 71
+#define ROOM_104_KISS_HIM 73
+#define ROOM_104_RICHARD_TALK 75
+#define ROOM_104_SHE_TALK_TO_RICH 77
+#define ROOM_104_HE_TALK_TO_RICH 79
+#define ROOM_104_GET_TO_SHE_WALK 81
+#define ROOM_104_COMMANDS_ALLOWED_NOT 83
+#define ROOM_104_POINT 87
+#define ROOM_104_ARMS_OUT 89
+#define ROOM_104_INIT_TEXT 91
+#define ROOM_104_END_PHANTOM 93
+
+
+/* ========================= Camera positions ====================== */
+
+#define RIGHT_STAGE 320 /* for camera_jump_to */
+#define LEFT_STAGE 0 /* for camera_jump_to */
+#define MIDDLE_STAGE 158 /* for camera_jump_to */
+
+
+/* ========================= Player positions from room 107 ======== */
+
+#define PLAYER_X_FROM_107 627
+#define PLAYER_Y_FROM_107_1 95
+#define PLAYER_Y_FROM_107_2 120
+#define PLAYER_Y_FROM_107_3 142
+#define OFF_SCREEN_X_FROM_107 655
+
+
+/* ========================= Player positions from room 108 ======== */
+
+#define PLAYER_X_FROM_108 12
+#define PLAYER_Y_FROM_108_1 148
+#define PLAYER_Y_FROM_108_2 128
+#define PLAYER_Y_FROM_108_3 97
+#define OFF_SCREEN_X_FROM_108 -20
+
+
+/* ========================= Conversation ========================== */
+
+#define CONV_AFTER_FALL_FROM_301 7
+
+
+/* ========================= Richard (Conv 7) action states ======== */
+
+#define CONV7_RICH_SHUT_UP 0
+#define CONV7_RICH_TALK 1
+#define CONV7_RICH_ARMS_OUT 2
+#define CONV7_RICH_POINT 3
+#define CONV7_RICH_WALK 4
+#define CONV7_RICH_LOOK_UP 5
+
+
+/* ========================= Couple (Conv 7) action states ========= */
+/* the '_R' means Richard */
+
+#define CONV7_COUPLE_SHUT_UP 1
+#define CONV7_COUPLE_SHUT_UP_R 2
+#define CONV7_COUPLE_HE_TALK 3
+#define CONV7_COUPLE_SHE_TALK 4
+#define CONV7_COUPLE_KISS 5
+#define CONV7_COUPLE_TOUCH_HEAD 6
+#define CONV7_COUPLE_HE_TALK_R 7
+#define CONV7_COUPLE_SHE_TALK_R 8
+#define CONV7_COUPLE_LOOK_AT_R_SHORT 9
+#define CONV7_COUPLE_LOOK_AT_R_LONG 10
+#define CONV7_COUPLE_STAY_DOWN 11
+#define CONV7_COUPLE_SHE_TALK_LAY 12
+#define CONV7_COUPLE_RAOUL_ALONE 13
+#define CONV7_COUPLE_PINCH 14
+#define CONV7_COUPLE_SHE_WALK 15
+#define CONV7_COUPLE_HE_GET_UP 16
+#define CONV7_COUPLE_INVISIBLE 17
+
+
+/* ========================= Daae walk action states =============== */
+
+#define CONV7_DAAE_WALK_INVISIBLE 0
+#define CONV7_DAAE_WALK_LEAVE 1
+
+
+/* ========================= Post-conversation positions =========== */
+
+#define AFTER_CONV_X 166
+#define AFTER_CONV_Y 126
+
+
+/* ========================= Restore positions (from death) ======== */
+
+#define RESTORE_X_FAR 496
+#define RESTORE_Y_FAR 79
+#define RESTORE_X_MIDDLE 346
+#define RESTORE_Y_MIDDLE 71
+#define RESTORE_X_NEAR 172
+#define RESTORE_Y_NEAR 73
+
+
+/* ========================= Entry from room 103 =================== */
+
+#define NEW_ROOM_FROM_103_X 319
+#define NEW_ROOM_FROM_103_Y 96
+
+
+extern void room_104_init(void);
+extern void room_104_daemon(void);
+extern void room_104_pre_parser(void);
+extern void room_104_parser(void);
+extern void room_104_preload(void);
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index 32517f742ae..83a39d0ff4a 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -125,6 +125,7 @@ MODULE_OBJS += \
madsv2/phantom/rooms/room101.o \
madsv2/phantom/rooms/room102.o \
madsv2/phantom/rooms/room103.o \
+ madsv2/phantom/rooms/room104.o \
madsv2/phantom/phantom.o \
madsv2/phantom/conv.o \
madsv2/phantom/main_menu.o \
Commit: 5e6a12748f9af6c831404580f6b24608f85984da
https://github.com/scummvm/scummvm/commit/5e6a12748f9af6c831404580f6b24608f85984da
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:40+10:00
Commit Message:
MADS: PHANTOM: Added room 105
Changed paths:
A engines/mads/madsv2/phantom/rooms/room105.cpp
A engines/mads/madsv2/phantom/rooms/room105.h
engines/mads/madsv2/core/speech.cpp
engines/mads/madsv2/core/speech.h
engines/mads/madsv2/phantom/mads/inventory.h
engines/mads/madsv2/phantom/mads/mads.cpp
engines/mads/madsv2/phantom/mads/speeches.h
engines/mads/madsv2/phantom/mads/text.h
engines/mads/madsv2/phantom/mads/words.h
engines/mads/madsv2/phantom/main.cpp
engines/mads/madsv2/phantom/main_menu.cpp
engines/mads/madsv2/phantom/main_menu.h
engines/mads/module.mk
diff --git a/engines/mads/madsv2/core/speech.cpp b/engines/mads/madsv2/core/speech.cpp
index f01d62130c1..4417b3fb85a 100644
--- a/engines/mads/madsv2/core/speech.cpp
+++ b/engines/mads/madsv2/core/speech.cpp
@@ -29,6 +29,8 @@ bool speech_system_active = false;
bool speech_on = false;
int speech_ems_handle;
SpeechBuffer speech_main_buffer;
+char global_speech_resource[16] = "*PHAN009.DSR";
+int global_speech_ready = -1;
SpeechDirPtr speech_load(const char *resName, int id, bool) {
warning("TODO: speech_load");
@@ -51,5 +53,39 @@ void speech_ems_go(int handle, int size) {
warning("TODO: speech_ems_go");
}
+void global_speech(int id) {
+ if (speech_system_active && speech_on) {
+ speech_ems_play(global_speech_resource, id);
+ }
+}
+
+void global_speech_load(int id) {
+ SpeechDirPtr chunk;
+
+ if (speech_system_active && speech_on) {
+ speech_all_off();
+ chunk = speech_load(global_speech_resource, id, false);
+ if (chunk != NULL) {
+ global_speech_ready = id;
+ } else {
+ global_speech_ready = -1;
+ }
+ } else {
+ global_speech_ready = -1;
+ }
+}
+
+void global_speech_go(int id) {
+ if (speech_system_active && speech_on) {
+ if (global_speech_ready == id) {
+ speech_all_off();
+ speech_sample_rate(speech_main_buffer.sample_rate);
+ speech_ems_go(speech_ems_handle, speech_main_buffer.decompress_size);
+ } else {
+ global_speech(id);
+ }
+ }
+}
+
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/core/speech.h b/engines/mads/madsv2/core/speech.h
index d58c98f4fad..c79a369ed81 100644
--- a/engines/mads/madsv2/core/speech.h
+++ b/engines/mads/madsv2/core/speech.h
@@ -44,6 +44,8 @@ extern void speech_ems_play(const char *resName, int id);
extern void speech_all_off();
extern void speech_sample_rate(int rate);
extern void speech_ems_go(int handle, int size);
+extern void global_speech_load(int id);
+extern void global_speech_go(int id);
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/mads/inventory.h b/engines/mads/madsv2/phantom/mads/inventory.h
index b226bca814a..bdb35be2b36 100644
--- a/engines/mads/madsv2/phantom/mads/inventory.h
+++ b/engines/mads/madsv2/phantom/mads/inventory.h
@@ -30,15 +30,19 @@ namespace Phantom {
enum {
key = 0,
+ lantern = 1,
red_frame = 2,
sandbag = 3,
yellow_frame = 4,
small_note = 6,
+ rope = 7,
parchment = 12,
book = 15,
blue_frame = 17,
large_note = 18,
- green_frame = 19
+ green_frame = 19,
+ cable_hook = 22,
+ rope_with_hook = 23
};
} // namespace Phantom
diff --git a/engines/mads/madsv2/phantom/mads/mads.cpp b/engines/mads/madsv2/phantom/mads/mads.cpp
index ef477ef7b98..fd078a5114f 100644
--- a/engines/mads/madsv2/phantom/mads/mads.cpp
+++ b/engines/mads/madsv2/phantom/mads/mads.cpp
@@ -22,3 +22,5 @@
#include "mads/madsv2/phantom/mads/quotes.h"
#include "mads/madsv2/phantom/mads/sounds.h"
#include "mads/madsv2/phantom/mads/speeches.h"
+#include "mads/madsv2/phantom/mads/text.h"
+#include "mads/madsv2/phantom/mads/words.h"
diff --git a/engines/mads/madsv2/phantom/mads/speeches.h b/engines/mads/madsv2/phantom/mads/speeches.h
index ff88f99a9d1..e72f1cb59cf 100644
--- a/engines/mads/madsv2/phantom/mads/speeches.h
+++ b/engines/mads/madsv2/phantom/mads/speeches.h
@@ -29,6 +29,7 @@ namespace MADSV2 {
namespace Phantom {
enum {
+ speech_christine_scales = 8,
speech_phantom_cackle = 9
};
diff --git a/engines/mads/madsv2/phantom/mads/text.h b/engines/mads/madsv2/phantom/mads/text.h
index 91f6b4bde90..55fb6108556 100644
--- a/engines/mads/madsv2/phantom/mads/text.h
+++ b/engines/mads/madsv2/phantom/mads/text.h
@@ -73,6 +73,9 @@ enum {
/* Cross-room */
text_000_32 = 32,
text_008_00 = 800,
+ text_008_01 = 801,
+ text_008_02 = 802,
+ text_008_42 = 842,
/* Room 103 */
text_103_10 = 10310,
@@ -140,7 +143,40 @@ enum {
text_104_32 = 10432,
text_104_33 = 10433,
text_104_34 = 10434,
- text_104_35 = 10435
+ text_104_35 = 10435,
+
+ /* Room 105 */
+ text_105_10 = 10510,
+ text_105_11 = 10511,
+ text_105_12 = 10512,
+ text_105_13 = 10513,
+ text_105_14 = 10514,
+ text_105_15 = 10515,
+ text_105_16 = 10516,
+ text_105_17 = 10517,
+ text_105_18 = 10518,
+ text_105_19 = 10519,
+ text_105_20 = 10520,
+ text_105_21 = 10521,
+ text_105_22 = 10522,
+ text_105_23 = 10523,
+ text_105_24 = 10524,
+ text_105_25 = 10525,
+ text_105_26 = 10526,
+ text_105_27 = 10527,
+ text_105_28 = 10528,
+ text_105_29 = 10529,
+ text_105_30 = 10530,
+ text_105_31 = 10531,
+ text_105_32 = 10532,
+ text_105_33 = 10533,
+ text_105_34 = 10534,
+ text_105_35 = 10535,
+ text_105_36 = 10536,
+ text_105_37 = 10537,
+ text_105_38 = 10538,
+ text_105_39 = 10539,
+ text_105_40 = 10540
};
} // namespace Phantom
diff --git a/engines/mads/madsv2/phantom/mads/words.h b/engines/mads/madsv2/phantom/mads/words.h
index 6961c258810..b3df1a1a786 100644
--- a/engines/mads/madsv2/phantom/mads/words.h
+++ b/engines/mads/madsv2/phantom/mads/words.h
@@ -19,8 +19,8 @@
*
*/
-#ifndef MADS_PHANTOM_MADS_SPEECHES_H
-#define MADS_PHANTOM_MADS_SPEECHES_H
+#ifndef MADS_PHANTOM_MADS_WORDS_H
+#define MADS_PHANTOM_MADS_WORDS_H
#include "common/scummsys.h"
@@ -34,22 +34,33 @@ enum {
words_act_curtain = 17,
words_aisle = 18,
words_apron = 19,
+ words_bear_prop = 22,
words_cable = 26,
words_carton = 28,
+ words_circular_staircase = 32,
+ words_climb_down = 33,
words_climb_through = 35,
+ words_column_prop = 36,
words_conductor_s_stand = 37,
words_door = 46,
+ words_elephant_prop = 50,
words_exit = 52,
+ words_exit_sign = 54,
words_exit_to = 55,
words_exposed_brick = 67,
+ words_flats = 72,
words_floor = 73,
words_folding_chairs = 74,
words_garbage_can = 75,
+ words_graffiti = 76,
+ words_hemp = 78,
words_house = 80,
words_jump_into = 82,
words_junk = 84,
words_key = 85,
+ words_lantern = 87,
words_leg = 90,
+ words_light_fixture = 92,
words_lock = 93,
words_look_at = 96,
words_look_through = 97,
@@ -57,15 +68,20 @@ enum {
words_music_stands = 104,
words_orchestra_door = 107,
words_orchestra_pit = 108,
+ words_pipe = 112,
words_pit = 113,
words_prompter_s_box = 116,
+ words_prop_table = 117,
+ words_props = 118,
words_proscenium_arch = 119,
+ words_red_frame = 123,
words_seats = 129,
words_side_wall = 130,
words_stage = 132,
words_stage_left = 134,
words_stage_right = 135,
words_stair_unit = 137,
+ words_thunder_machine = 145,
words_trap_ceiling = 147,
words_trap_door = 148,
words_unlock = 151,
@@ -74,6 +90,8 @@ enum {
words_walk_through = 155,
words_wall = 157,
words_water_pipe = 160,
+ words_prop = 164,
+ words_climb_up = 165,
words_door_to_pit = 170,
words_grand_foyer = 180,
words_back_wall = 181,
diff --git a/engines/mads/madsv2/phantom/main.cpp b/engines/mads/madsv2/phantom/main.cpp
index a20aa55284f..5f466087b15 100644
--- a/engines/mads/madsv2/phantom/main.cpp
+++ b/engines/mads/madsv2/phantom/main.cpp
@@ -28,6 +28,7 @@
#include "mads/madsv2/core/mouse.h"
#include "mads/madsv2/core/pal.h"
#include "mads/madsv2/core/quote.h"
+#include "mads/madsv2/core/speech.h"
#include "mads/madsv2/phantom/main_menu.h"
#include "mads/madsv2/engine.h"
diff --git a/engines/mads/madsv2/phantom/main_menu.cpp b/engines/mads/madsv2/phantom/main_menu.cpp
index 2616e08b8b2..92a87969a3d 100644
--- a/engines/mads/madsv2/phantom/main_menu.cpp
+++ b/engines/mads/madsv2/phantom/main_menu.cpp
@@ -154,43 +154,6 @@ Palette special_pal; /* Palette for fadeout */
MenuItem menu_item[NUM_MENU_ITEMS+1]; /* Menu item array */
-char global_speech_resource[16] = "*PHAN009.DSR";
-int global_speech_ready = -1;
-
-void global_speech(int id) {
- if (speech_system_active && speech_on) {
- speech_ems_play(global_speech_resource, id);
- }
-}
-
-void global_speech_load(int id) {
- SpeechDirPtr chunk;
-
- if (speech_system_active && speech_on) {
- speech_all_off();
- chunk = speech_load(global_speech_resource, id, false);
- if (chunk != NULL) {
- global_speech_ready = id;
- } else {
- global_speech_ready = -1;
- }
- } else {
- global_speech_ready = -1;
- }
-}
-
-void global_speech_go(int id) {
- if (speech_system_active && speech_on) {
- if (global_speech_ready == id) {
- speech_all_off();
- speech_sample_rate(speech_main_buffer.sample_rate);
- speech_ems_go(speech_ems_handle, speech_main_buffer.decompress_size);
- } else {
- global_speech(id);
- }
- }
-}
-
void start_series() {
int error_flag = true;
int count;
diff --git a/engines/mads/madsv2/phantom/main_menu.h b/engines/mads/madsv2/phantom/main_menu.h
index e06c6fa8089..27d3bfd83b3 100644
--- a/engines/mads/madsv2/phantom/main_menu.h
+++ b/engines/mads/madsv2/phantom/main_menu.h
@@ -50,8 +50,6 @@ typedef struct {
extern bool new_background;
extern int selected_item;
-
-extern void global_speech_load(int id);
extern void menu_control();
} // namespace Phantom
diff --git a/engines/mads/madsv2/phantom/rooms/room105.cpp b/engines/mads/madsv2/phantom/rooms/room105.cpp
new file mode 100644
index 00000000000..2e4b6275223
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room105.cpp
@@ -0,0 +1,624 @@
+/* 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 "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/imath.h"
+#include "mads/madsv2/core/text.h"
+#include "mads/madsv2/core/inter.h"
+#include "mads/madsv2/core/object.h"
+#include "mads/madsv2/core/sound.h"
+#include "mads/madsv2/core/speech.h"
+#include "mads/madsv2/phantom/global.h"
+#include "mads/madsv2/phantom/mads/inventory.h"
+#include "mads/madsv2/phantom/mads/words.h"
+#include "mads/madsv2/phantom/mads/sounds.h"
+#include "mads/madsv2/phantom/mads/speeches.h"
+#include "mads/madsv2/phantom/mads/text.h"
+#include "mads/madsv2/phantom/conv.h"
+#include "mads/madsv2/phantom/rooms/section1.h"
+#include "mads/madsv2/phantom/rooms/room105.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+void room_105_init() {
+ global_speech_load(speech_christine_scales);
+
+ /* ==================== Load Sprite Series ====================== */
+
+ ss[fx_door] = kernel_load_series(kernel_name('x', 2), false);
+ ss[fx_thunder] = kernel_load_series(kernel_name('x', 3), false);
+ ss[fx_bend_down_9] = kernel_load_series("*RRD_9", false);
+ ss[fx_take_9] = kernel_load_series("*RDR_9", false);
+ ss[fx_climb_up] = kernel_load_series(kernel_name('a', 0), false);
+ ss[fx_climb_down] = kernel_load_series(kernel_name('a', 1), false);
+
+ if (global[current_year] == 1993) {
+ ss[fx_1993] = kernel_load_series(kernel_name('z', -1), false);
+ }
+
+ if ((global[current_year] == 1881) && (!global[hint_that_daae_is_home_2])) {
+ if ((global[jacques_name_is_known] == YES_AND_END_CONV) &&
+ (global[madame_name_is_known] == YES_AND_END_CONV) &&
+ (global[panel_in_206]) &&
+ (global[done_rich_conv_203]) &&
+ player_has(lantern) &&
+ ((player_has(cable_hook) && player_has(rope)) || player_has(rope_with_hook))) {
+ global[hint_that_daae_is_home_2] = true;
+ kernel_timing_trigger(FIVE_SECONDS, ROOM_105_INIT_TEXT);
+ }
+ }
+
+
+ /* ==================== If in 1881, put lantern & red_frame ==== */
+
+ if ((object_is_here(lantern)) && (global[current_year] == 1881)) {
+ ss[fx_lantern] = kernel_load_series(kernel_name('x', 0), false);
+ seq[fx_lantern] = kernel_seq_stamp(ss[fx_lantern], false, 1);
+ kernel_seq_depth(seq[fx_lantern], 14);
+ } else {
+ kernel_flip_hotspot(words_lantern, false);
+ }
+
+ if (object_is_here(red_frame)) {
+ ss[fx_red_frame] = kernel_load_series(kernel_name('x', 1), false);
+ seq[fx_red_frame] = kernel_seq_stamp(ss[fx_red_frame], false, 1);
+ kernel_seq_depth(seq[fx_red_frame], 14);
+ } else {
+ kernel_flip_hotspot(words_red_frame, false);
+ }
+
+
+ /* ==================== Change room if it is 1993 ============== */
+
+ if (global[current_year] == 1993) {
+ kernel_draw_to_background(ss[fx_1993], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ kernel_flip_hotspot(words_props, false);
+ kernel_flip_hotspot(words_bear_prop, false);
+ kernel_flip_hotspot(words_stair_unit, false);
+ kernel_flip_hotspot(words_prop, false);
+ kernel_flip_hotspot(words_elephant_prop, false);
+ kernel_flip_hotspot(words_column_prop, false);
+
+ /* 2 dynamics for column props in background */
+
+ local->column_prop = kernel_add_dynamic(words_column_prop, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ COLUMN_1_X, COLUMN_1_Y, COLUMN_1_X_SIZE, COLUMN_1_Y_SIZE);
+ kernel_dynamic_walk(local->column_prop, WALK_TO_COLUMN_1_X, WALK_TO_COLUMN_1_Y, FACING_NORTHWEST);
+ local->column_prop = kernel_add_dynamic(words_column_prop, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ COLUMN_2_X, COLUMN_2_Y, COLUMN_2_X_SIZE, COLUMN_2_Y_SIZE);
+ kernel_dynamic_walk(local->column_prop, WALK_TO_COLUMN_2_X, WALK_TO_COLUMN_2_Y, FACING_NORTHWEST);
+
+ /* 3 dynamics for misc. props in foreground */
+
+ kernel_add_dynamic(words_prop, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ PROP_1_X, PROP_1_Y, PROP_1_X_SIZE, PROP_1_Y_SIZE);
+ kernel_add_dynamic(words_prop, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ PROP_2_X, PROP_2_Y, PROP_2_X_SIZE, PROP_2_Y_SIZE);
+ kernel_add_dynamic(words_prop, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ PROP_3_X, PROP_3_Y, PROP_3_X_SIZE, PROP_3_Y_SIZE);
+
+ /* 3 dynamics for bear prop in foreground */
+
+ kernel_add_dynamic(words_bear_prop, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ BEAR_1_X, BEAR_1_Y, BEAR_1_X_SIZE, BEAR_1_Y_SIZE);
+ kernel_add_dynamic(words_bear_prop, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ BEAR_2_X, BEAR_2_Y, BEAR_2_X_SIZE, BEAR_2_Y_SIZE);
+ kernel_add_dynamic(words_bear_prop, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ BEAR_3_X, BEAR_3_Y, BEAR_3_X_SIZE, BEAR_3_Y_SIZE);
+
+ /* 1 dynamic for light on ceiling */
+
+ kernel_add_dynamic(words_light_fixture, words_look_at, SYNTAX_SINGULAR, KERNEL_NONE,
+ LIGHT_X, LIGHT_Y, LIGHT_X_SIZE, LIGHT_Y_SIZE);
+ }
+
+
+ /* ==================== Thunder Machine ========================= */
+
+ seq[fx_thunder] = kernel_seq_stamp(ss[fx_thunder], false, 2);
+ kernel_seq_depth(seq[fx_thunder], 14);
+
+
+ /* ==================== Previous Rooms ========================== */
+
+ if ((previous_room == 106) || (previous_room == 114)) {
+ player.x = PLAYER_X_FROM_STAIRCASE;
+ player.y = PLAYER_Y_FROM_STAIRCASE;
+ player.facing = FACING_WEST;
+ seq[fx_door] = kernel_seq_stamp(ss[fx_door], false, 1);
+ kernel_seq_depth(seq[fx_door], 10);
+
+ } else if ((previous_room == 103) || (previous_room != KERNEL_RESTORING_GAME)) {
+ player.x = PLAYER_X_FROM_103;
+ player.y = PLAYER_Y_FROM_103;
+ player.facing = FACING_SOUTHEAST;
+ player_walk(WALK_TO_X_FROM_103, WALK_TO_Y_FROM_103, FACING_SOUTHEAST);
+ player_walk_trigger(ROOM_105_DOOR_CLOSES);
+ player.commands_allowed = false;
+ seq[fx_door] = kernel_seq_stamp(ss[fx_door], false, 8);
+ kernel_seq_depth(seq[fx_door], 10);
+
+ } else if (previous_room == KERNEL_RESTORING_GAME) {
+ seq[fx_door] = kernel_seq_stamp(ss[fx_door], false, KERNEL_FIRST);
+ kernel_seq_depth(seq[fx_door], 10);
+ }
+
+ section_1_music();
+}
+
+void room_105_daemon() {
+ /* ==================== Close the door when player enters ======= */
+
+ switch (kernel.trigger) {
+ case ROOM_105_INIT_TEXT:
+ global_speech_go(speech_christine_scales);
+ kernel_timing_trigger(TWO_SECONDS, ROOM_105_INIT_TEXT + 1);
+ break;
+
+ case ROOM_105_INIT_TEXT + 1:
+ text_show(text_105_37);
+ break;
+
+ case ROOM_105_DOOR_CLOSES:
+ kernel_seq_delete(seq[fx_door]);
+ seq[fx_door] = kernel_seq_backward(ss[fx_door], false,
+ 8, 0, 0, 1);
+ kernel_seq_depth(seq[fx_door], 10);
+ kernel_seq_range(seq[fx_door], 1, 8);
+ kernel_seq_trigger(seq[fx_door],
+ KERNEL_TRIGGER_EXPIRE, 0, ROOM_105_DOOR_CLOSES + 1);
+ sound_play(N_SqueakyDoor);
+ break;
+
+ case ROOM_105_DOOR_CLOSES + 1:
+ sound_play(N_DoorCloses);
+ seq[fx_door] = kernel_seq_stamp(ss[fx_door], false, 1);
+ kernel_seq_depth(seq[fx_door], 10);
+ player.commands_allowed = true;
+ break;
+ }
+}
+
+void room_105_pre_parser() {
+ if (player_said_2(walk_through, door_to_pit)) {
+ player.walk_off_edge_to_room = 102;
+ }
+
+ if (player_said_2(open, door) || player_said_2(unlock, door) || player_said_2(lock, door)) {
+ player_walk(FRONT_OF_DOOR_X, FRONT_OF_DOOR_Y, FACING_NORTHWEST);
+ }
+}
+
+void room_105_parser() {
+ int temp; /* For synching purposes */
+ int count = 0;
+
+ if ((player_said_2(push, thunder_machine)) ||
+ (player_said_2(pull, thunder_machine))) {
+ switch (kernel.trigger) {
+ case 0:
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ aa[0] = kernel_run_animation(kernel_name('t', 1), ROOM_105_DUN_THUNDER);
+ kernel_seq_delete(seq[fx_thunder]);
+ kernel_synch(KERNEL_SERIES, seq[fx_thunder], KERNEL_ANIM, aa[0]);
+ kernel_seq_player(aa[0], false);
+ break;
+
+ case ROOM_105_DUN_THUNDER:
+ seq[fx_thunder] = kernel_seq_stamp(ss[fx_thunder], false, 2);
+ kernel_seq_depth(seq[fx_thunder], 14);
+ kernel_synch(KERNEL_SERIES, seq[fx_thunder], KERNEL_ANIM, aa[0]);
+ player.commands_allowed = true;
+ player.walker_visible = true;
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_ANIM, aa[0]);
+ break;
+ }
+ goto handled;
+ }
+
+ if (player_said_2(climb_up, circular_staircase)) {
+ switch (kernel.trigger) {
+ case 0:
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ aa[0] = kernel_run_animation(kernel_name('u', 1), 1);
+ kernel_synch(KERNEL_ANIM, aa[0], KERNEL_PLAYER, 0);
+ break;
+
+ case 1:
+ new_room = 106;
+ break;
+ }
+ goto handled;
+ }
+
+ if (player_said_2(climb_down, circular_staircase)) {
+ switch (kernel.trigger) {
+ case 0:
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ aa[0] = kernel_run_animation(kernel_name('d', 1), 1);
+ kernel_synch(KERNEL_ANIM, aa[0], KERNEL_PLAYER, 0);
+ break;
+
+ case 1:
+ new_room = 114;
+ break;
+ }
+ goto handled;
+ }
+
+ if (player_said_2(take, red_frame) &&
+ (object_is_here(red_frame) || kernel.trigger)) {
+ switch (kernel.trigger) {
+ case 0:
+ if (global[current_year] == 1881) {
+ if (player_has(yellow_frame)) ++count;
+ if (player_has(green_frame)) ++count;
+ if (player_has(blue_frame)) ++count;
+ if (count < 3) global[player_score] += 5;
+ }
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_bend_down_9] = kernel_seq_pingpong(ss[fx_bend_down_9], true,
+ 5, 0, 0, 2);
+ kernel_seq_range(seq[fx_bend_down_9], 1, 5);
+ kernel_seq_player(seq[fx_bend_down_9], true);
+ kernel_seq_trigger(seq[fx_bend_down_9],
+ KERNEL_TRIGGER_SPRITE, 5, 1);
+ kernel_seq_trigger(seq[fx_bend_down_9],
+ KERNEL_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ kernel_seq_delete(seq[fx_red_frame]);
+ kernel_flip_hotspot(words_red_frame, false);
+ inter_give_to_player(red_frame);
+ sound_play(N_TakeObjectSnd);
+ break;
+
+ case 2:
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_SERIES, seq[fx_bend_down_9]);
+ player.walker_visible = true;
+ kernel_timing_trigger(20, 3);
+ break;
+
+ case 3:
+ if (global[current_year] == 1881) {
+ object_examine(red_frame, text_008_42, 0);
+ } else {
+ object_examine(red_frame, text_008_02, 0);
+ }
+ /* You pick up the red color frame */
+ player.commands_allowed = true;
+ break;
+ }
+ goto handled;
+ }
+
+ if (player_said_2(take, lantern) &&
+ (object_is_here(lantern) || kernel.trigger)) {
+ switch (kernel.trigger) {
+ case 0:
+ global[player_score] += 5;
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_take_9] = kernel_seq_pingpong(ss[fx_take_9], true,
+ 5, 0, 0, 2);
+ kernel_seq_range(seq[fx_take_9], 1, 4);
+ kernel_seq_player(seq[fx_take_9], true);
+ kernel_seq_trigger(seq[fx_take_9],
+ KERNEL_TRIGGER_SPRITE, 4, 1);
+ kernel_seq_trigger(seq[fx_take_9],
+ KERNEL_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ kernel_seq_delete(seq[fx_lantern]);
+ kernel_flip_hotspot(words_lantern, false);
+ inter_give_to_player(lantern);
+ sound_play(N_TakeObjectSnd);
+ break;
+
+ case 2:
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_SERIES, seq[fx_take_9]);
+ player.walker_visible = true;
+ kernel_timing_trigger(20, 3);
+ break;
+
+ case 3:
+ object_examine(lantern, text_008_01, 0);
+ /* You pick up the lantern */
+ player.commands_allowed = true;
+ break;
+ }
+ goto handled;
+ }
+
+ if (player_said_2(walk_through, door) || player_said_2(open, door) || (kernel.trigger) ||
+ player_said_2(unlock, door) || player_said_2(lock, door)) {
+ if ((global[current_year] == 1881) && !player_said_1(unlock) && !player_said_1(lock)) {
+ switch (kernel.trigger) {
+ case 0:
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_take_9] = kernel_seq_pingpong(ss[fx_take_9], true,
+ 5, 0, 0, 2);
+ kernel_seq_range(seq[fx_take_9], 1, 4);
+ kernel_seq_player(seq[fx_take_9], true);
+ kernel_seq_trigger(seq[fx_take_9],
+ KERNEL_TRIGGER_SPRITE, 4, ROOM_105_DOOR_OPENS);
+ kernel_seq_trigger(seq[fx_take_9],
+ KERNEL_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case ROOM_105_DOOR_OPENS:
+ sound_play(N_DoorOpens);
+ kernel_seq_delete(seq[fx_door]);
+ seq[fx_door] = kernel_seq_forward(ss[fx_door], false,
+ 8, 0, 0, 1);
+ kernel_seq_depth(seq[fx_door], 14);
+ kernel_seq_range(seq[fx_door], 1, 8);
+ kernel_seq_trigger(seq[fx_door],
+ KERNEL_TRIGGER_EXPIRE, 0, ROOM_105_DOOR_OPENS + 1);
+ sound_play(N_SqueakyDoor);
+ break;
+
+ case ROOM_105_DOOR_OPENS + 1:
+ temp = seq[fx_door];
+ seq[fx_door] = kernel_seq_stamp(ss[fx_door], false, 8);
+ kernel_synch(KERNEL_SERIES, seq[fx_door], KERNEL_SERIES, temp);
+ kernel_seq_depth(seq[fx_door], 14);
+ player_walk(WALK_TO_X_OPEN_DOOR, WALK_TO_Y_OPEN_DOOR, FACING_NORTHWEST);
+ break;
+
+ case 2:
+ player.walker_visible = true;
+ kernel_timing_trigger(THREE_SECONDS, 3);
+ break;
+
+ case 3:
+ new_room = 103;
+ break;
+ }
+
+ } else {
+ switch (kernel.trigger) {
+ case 0:
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_take_9] = kernel_seq_forward(ss[fx_take_9], true, 5, 0, 0, 1);
+ kernel_seq_range(seq[fx_take_9], 1, 4);
+ kernel_seq_player(seq[fx_take_9], true);
+ kernel_seq_trigger(seq[fx_take_9], KERNEL_TRIGGER_EXPIRE, 0, 1);
+ break;
+
+ case 1:
+ temp = seq[fx_take_9];
+ seq[fx_take_9] = kernel_seq_stamp(ss[fx_take_9], true, 4);
+ kernel_synch(KERNEL_SERIES, seq[fx_take_9], KERNEL_SERIES, temp);
+ kernel_seq_player(seq[fx_take_9], false);
+ sound_play(N_DoorHandle);
+ kernel_timing_trigger(QUARTER_SECOND, 2);
+ break;
+
+ case 2:
+ kernel_seq_delete(seq[fx_take_9]);
+ seq[fx_take_9] = kernel_seq_backward(ss[fx_take_9], true, 5, 0, 0, 1);
+ kernel_seq_range(seq[fx_take_9], 1, 4);
+ kernel_seq_player(seq[fx_take_9], false);
+ kernel_seq_trigger(seq[fx_take_9], KERNEL_TRIGGER_EXPIRE, 0, 3);
+ break;
+
+ case 3:
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_SERIES, seq[fx_take_9]);
+ player.walker_visible = true;
+ if (player_said_1(lock) || player_said_1(unlock)) {
+ text_show(text_000_32);
+ /* the key does not work here */
+ } else {
+ text_show(text_105_36);
+ /* the door is locked */
+ }
+ player.commands_allowed = true;
+ break;
+ }
+ }
+ goto handled;
+ }
+
+ if (player.look_around) {
+ if (global[current_year] == 1993) {
+ text_show(text_105_10);
+ } else {
+ text_show(text_105_11);
+ }
+ goto handled;
+ }
+
+ if (player_said_1(look) || player_said_1(look_at)) {
+
+ if (player_said_1(floor)) {
+ text_show(text_105_12);
+ goto handled;
+ }
+
+ if (player_said_1(circular_staircase)) {
+ text_show(text_105_13);
+ goto handled;
+ }
+
+ if (player_said_1(lantern) && object_is_here(lantern)) {
+ text_show(text_105_14);
+ goto handled;
+ }
+
+ if (player_said_1(red_frame) && object_is_here(red_frame)) {
+ if (global[current_year] == 1881) {
+ text_show(text_105_30);
+ } else {
+ text_show(text_105_15);
+ }
+ goto handled;
+ }
+
+ if (player_said_1(door)) {
+ text_show(text_105_16);
+ goto handled;
+ }
+
+ if (player_said_1(wall)) {
+ text_show(text_105_17);
+ goto handled;
+ }
+
+ if (player_said_1(prop_table)) {
+ text_show(text_105_18);
+ goto handled;
+ }
+
+ if (player_said_1(bear_prop)) {
+ if (global[current_year] == 1993) {
+ text_show(text_105_19);
+ } else {
+ text_show(text_105_38);
+ }
+ goto handled;
+ }
+
+ if (player_said_1(elephant_prop)) {
+ text_show(text_105_20);
+ goto handled;
+ }
+
+ if (player_said_1(column_prop)) {
+ if (global[current_year] == 1993) {
+ text_show(text_105_21);
+ } else {
+ text_show(text_105_39);
+ }
+ goto handled;
+ }
+
+ if (player_said_1(thunder_machine)) {
+ if (global[current_year] == 1993) {
+ text_show(text_105_22);
+ } else {
+ text_show(text_105_40);
+ }
+ goto handled;
+ }
+
+ if (player_said_1(stair_unit)) {
+ text_show(text_105_23);
+ goto handled;
+ }
+
+ if (player_said_1(prop)) {
+ text_show(text_105_24);
+ goto handled;
+ }
+
+ if (player_said_1(props)) {
+ text_show(text_105_25);
+ goto handled;
+ }
+
+ if (player_said_1(exit_sign)) {
+ text_show(text_105_26);
+ goto handled;
+ }
+
+ if (player_said_1(flats)) {
+ text_show(text_105_27);
+ goto handled;
+ }
+
+ if (player_said_1(hemp)) {
+ text_show(text_105_28);
+ goto handled;
+ }
+
+ if (player_said_1(pipe)) {
+ text_show(text_105_29);
+ goto handled;
+ }
+
+ if (player_said_1(graffiti)) {
+ text_show(text_105_31);
+ goto handled;
+ }
+
+ if (player_said_1(light_fixture)) {
+ text_show(text_105_35);
+ goto handled;
+ }
+ }
+
+ if (player_said_2(talk_to, bear_prop)) {
+ text_show(text_105_32);
+ goto handled;
+ }
+
+ if (player_said_2(take, bear_prop)) {
+ text_show(text_105_33);
+ goto handled;
+ }
+
+ if (player_said_2(close, door)) {
+ text_show(text_105_34);
+ goto handled;
+ }
+
+ goto done;
+
+handled:
+ player.command_ready = false;
+
+done:
+ ;
+}
+
+void room_105_preload() {
+ room_init_code_pointer = room_105_init;
+ room_pre_parser_code_pointer = room_105_pre_parser;
+ room_parser_code_pointer = room_105_parser;
+ room_daemon_code_pointer = room_105_daemon;
+
+ if (global[current_year] == 1993) {
+ kernel_initial_variant = 1;
+ }
+
+ section_1_walker();
+ section_1_interface();
+
+ vocab_make_active(words_light_fixture);
+}
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/rooms/room105.h b/engines/mads/madsv2/phantom/rooms/room105.h
new file mode 100644
index 00000000000..be0d22e3cca
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room105.h
@@ -0,0 +1,163 @@
+/* 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/>.
+ *
+ */
+
+/* room105.mac by Paul Lahaise 8-Jan-93 */
+
+#ifndef MADS_PHANTOM_ROOM105_H
+#define MADS_PHANTOM_ROOM105_H
+
+#include "mads/madsv2/phantom/rooms/section1.h"
+#include "mads/madsv2/phantom/global.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+#define local ((Scratch *)(&game.scratch[0]))
+#define ss local->sprite
+#define seq local->sequence
+#define aa local->animation
+
+typedef struct { /* Room local variables */
+
+ int sprite[15]; /* Sprite series handles */
+ int sequence[15]; /* Sequence handles */
+ int animation[4]; /* Animation handles */
+ int column_prop; /* Dynamic HS for column_prop */
+
+} Scratch;
+
+
+/* ========================= Sprite Series ========================= */
+
+#define fx_lantern 0 /* rm105x0 */
+#define fx_red_frame 1 /* rm105x1 */
+#define fx_door 2 /* rm105x2 */
+#define fx_1993 3 /* rm105z */
+#define fx_thunder 4 /* rm105x3 */
+#define fx_bend_down_9 5 /* rrd_9 */
+#define fx_take_9 6 /* rdr_9 */
+#define fx_climb_up 7 /* rm105a0 */
+#define fx_climb_down 8 /* rm105a1 */
+
+
+/* ========================= Triggers ============================== */
+
+#define ROOM_105_DOOR_CLOSES 60
+#define ROOM_105_DOOR_OPENS 65
+#define ROOM_105_DUN_THUNDER 70
+#define ROOM_105_INIT_TEXT 75
+
+
+/* ========================= Player positions ====================== */
+
+#define PLAYER_X_FROM_103 3
+#define PLAYER_Y_FROM_103 112
+
+#define PLAYER_X_FROM_STAIRCASE 198
+#define PLAYER_Y_FROM_STAIRCASE 132
+
+#define WALK_TO_X_FROM_103 45
+#define WALK_TO_Y_FROM_103 131
+
+#define WALK_TO_X_OPEN_DOOR 0
+#define WALK_TO_Y_OPEN_DOOR 111
+
+#define FRONT_OF_DOOR_X 33
+#define FRONT_OF_DOOR_Y 128
+
+#define WALK_TO_STAIRS_X 207
+#define WALK_TO_STAIRS_Y 131
+
+
+/* ========================= Dynamic hotspot coords â props ======== */
+
+#define PROP_1_X 0
+#define PROP_1_Y 125
+#define PROP_2_X 29
+#define PROP_2_Y 136
+#define PROP_3_X 79
+#define PROP_3_Y 141
+
+#define PROP_1_X_SIZE 29
+#define PROP_1_Y_SIZE 31
+#define PROP_2_X_SIZE 50
+#define PROP_2_Y_SIZE 20
+#define PROP_3_X_SIZE 53
+#define PROP_3_Y_SIZE 15
+
+
+/* ========================= Dynamic hotspot coords â bear ========= */
+
+#define BEAR_1_X 278
+#define BEAR_1_Y 132
+#define BEAR_2_X 299
+#define BEAR_2_Y 146
+#define BEAR_3_X 269
+#define BEAR_3_Y 142
+
+#define BEAR_1_X_SIZE 21
+#define BEAR_1_Y_SIZE 24
+#define BEAR_2_X_SIZE 8
+#define BEAR_2_Y_SIZE 10
+#define BEAR_3_X_SIZE 8
+#define BEAR_3_Y_SIZE 8
+
+
+/* ========================= Dynamic hotspot coords â light ======== */
+
+#define LIGHT_X 102
+#define LIGHT_Y 14
+#define LIGHT_X_SIZE 24
+#define LIGHT_Y_SIZE 10
+
+
+/* ========================= Dynamic hotspot coords â columns ====== */
+
+#define COLUMN_1_X 132
+#define COLUMN_1_Y 24
+#define COLUMN_2_X 56
+#define COLUMN_2_Y 45
+
+#define COLUMN_1_X_SIZE 21
+#define COLUMN_1_Y_SIZE 105
+#define COLUMN_2_X_SIZE 11
+#define COLUMN_2_Y_SIZE 77
+
+#define WALK_TO_COLUMN_1_X 159
+#define WALK_TO_COLUMN_1_Y 133
+#define WALK_TO_COLUMN_2_X 72
+#define WALK_TO_COLUMN_2_Y 126
+
+
+extern void room_105_init(void);
+extern void room_105_daemon(void);
+extern void room_105_pre_parser(void);
+extern void room_105_parser(void);
+extern void room_105_preload(void);
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index 83a39d0ff4a..9dfd5f85b62 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -126,6 +126,7 @@ MODULE_OBJS += \
madsv2/phantom/rooms/room102.o \
madsv2/phantom/rooms/room103.o \
madsv2/phantom/rooms/room104.o \
+ madsv2/phantom/rooms/room105.o \
madsv2/phantom/phantom.o \
madsv2/phantom/conv.o \
madsv2/phantom/main_menu.o \
Commit: d2fdb01bbab2ca55d70ce1147503efb3255c06fc
https://github.com/scummvm/scummvm/commit/d2fdb01bbab2ca55d70ce1147503efb3255c06fc
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:40+10:00
Commit Message:
MADS: PHANTOM: Added room 106
Changed paths:
A engines/mads/madsv2/phantom/rooms/room106.cpp
A engines/mads/madsv2/phantom/rooms/room106.h
engines/mads/madsv2/phantom/global.h
engines/mads/madsv2/phantom/mads/sounds.h
engines/mads/madsv2/phantom/mads/text.h
engines/mads/madsv2/phantom/mads/words.h
engines/mads/module.mk
diff --git a/engines/mads/madsv2/phantom/global.h b/engines/mads/madsv2/phantom/global.h
index 7213e55dbec..9a476e3208b 100644
--- a/engines/mads/madsv2/phantom/global.h
+++ b/engines/mads/madsv2/phantom/global.h
@@ -200,6 +200,9 @@ enum {
// ticket_people_here
#define SELLER 1
+// sandbag_status
+#define SANDBAG_DROPPED 1
+
} // namespace Phantom
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/mads/sounds.h b/engines/mads/madsv2/phantom/mads/sounds.h
index 4325fcb4728..8af908f19ae 100644
--- a/engines/mads/madsv2/phantom/mads/sounds.h
+++ b/engines/mads/madsv2/phantom/mads/sounds.h
@@ -40,6 +40,7 @@ enum {
N_SqueakyDoor = 66,
N_PlayerFalls = 67,
N_EchoSteps = 68,
+ N_SandbagThud = 70,
N_DoorHandle = 73
};
diff --git a/engines/mads/madsv2/phantom/mads/text.h b/engines/mads/madsv2/phantom/mads/text.h
index 55fb6108556..a6c16a6eec4 100644
--- a/engines/mads/madsv2/phantom/mads/text.h
+++ b/engines/mads/madsv2/phantom/mads/text.h
@@ -75,6 +75,8 @@ enum {
text_008_00 = 800,
text_008_01 = 801,
text_008_02 = 802,
+ text_008_03 = 803,
+ text_008_22 = 822,
text_008_42 = 842,
/* Room 103 */
@@ -176,7 +178,38 @@ enum {
text_105_37 = 10537,
text_105_38 = 10538,
text_105_39 = 10539,
- text_105_40 = 10540
+ text_105_40 = 10540,
+
+ /* Room 106 */
+ text_106_10 = 10610,
+ text_106_11 = 10611,
+ text_106_12 = 10612,
+ text_106_13 = 10613,
+ text_106_14 = 10614,
+ text_106_15 = 10615,
+ text_106_16 = 10616,
+ text_106_17 = 10617,
+ text_106_18 = 10618,
+ text_106_19 = 10619,
+ text_106_20 = 10620,
+ text_106_21 = 10621,
+ text_106_22 = 10622,
+ text_106_23 = 10623,
+ text_106_24 = 10624,
+ text_106_25 = 10625,
+ text_106_26 = 10626,
+ text_106_27 = 10627,
+ text_106_28 = 10628,
+ text_106_29 = 10629,
+ text_106_30 = 10630,
+ text_106_32 = 10632,
+ text_106_33 = 10633,
+ text_106_34 = 10634,
+ text_106_35 = 10635,
+ text_106_36 = 10636,
+ text_106_37 = 10637,
+ text_106_38 = 10638,
+ text_106_39 = 10639
};
} // namespace Phantom
diff --git a/engines/mads/madsv2/phantom/mads/words.h b/engines/mads/madsv2/phantom/mads/words.h
index b3df1a1a786..4c04bb5ac76 100644
--- a/engines/mads/madsv2/phantom/mads/words.h
+++ b/engines/mads/madsv2/phantom/mads/words.h
@@ -42,6 +42,8 @@ enum {
words_climb_through = 35,
words_column_prop = 36,
words_conductor_s_stand = 37,
+ words_crate = 41,
+ words_cyclorama = 44,
words_door = 46,
words_elephant_prop = 50,
words_exit = 52,
@@ -75,6 +77,7 @@ enum {
words_props = 118,
words_proscenium_arch = 119,
words_red_frame = 123,
+ words_sandbag = 127,
words_seats = 129,
words_side_wall = 130,
words_stage = 132,
@@ -93,9 +96,20 @@ enum {
words_prop = 164,
words_climb_up = 165,
words_door_to_pit = 170,
+ words_boxes = 172,
+ words_box = 175,
words_grand_foyer = 180,
words_back_wall = 181,
+ words_stage_right_wing = 193,
+ words_stage_left_wing = 194,
+ words_pedestal = 195,
+ words_plant_prop = 196,
+ words_statue = 197,
+ words_batten = 198,
+ words_big_prop = 199,
+ words_ventilation_duct = 200,
words_chandelier = 201,
+ words_prop_case = 247,
words_Monsieur_Brie = 258,
words_prompter_s_stand = 270,
words_Jacques = 280,
@@ -103,7 +117,8 @@ enum {
words_climb = 288,
words_prompter_s_seat = 300,
words_lever = 301,
- words_Monsieur_Richard = 302
+ words_Monsieur_Richard = 302,
+ words_cable_hook = 304
};
} // namespace Phantom
diff --git a/engines/mads/madsv2/phantom/rooms/room106.cpp b/engines/mads/madsv2/phantom/rooms/room106.cpp
new file mode 100644
index 00000000000..0c41ba9d0e1
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room106.cpp
@@ -0,0 +1,634 @@
+/* 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/>.
+ *
+ */
+
+/* room106i.c / room106d.c / room106p.c
+ * room106i.c by Brian Reynolds, room106p.c by Paul Lahaise 7-Jan-93
+ *
+ * NOTE: the original source used 'case' as a vocabulary word identifier.
+ * Since 'case' is a C++ reserved keyword, it has been renamed 'prop_case'
+ * throughout this file (maps to words_prop_case).
+ */
+
+#include "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/imath.h"
+#include "mads/madsv2/core/text.h"
+#include "mads/madsv2/core/inter.h"
+#include "mads/madsv2/core/object.h"
+#include "mads/madsv2/core/sound.h"
+#include "mads/madsv2/core/speech.h"
+#include "mads/madsv2/phantom/global.h"
+#include "mads/madsv2/phantom/mads/inventory.h"
+#include "mads/madsv2/phantom/mads/words.h"
+#include "mads/madsv2/phantom/mads/sounds.h"
+#include "mads/madsv2/phantom/mads/speeches.h"
+#include "mads/madsv2/phantom/mads/text.h"
+#include "mads/madsv2/phantom/conv.h"
+#include "mads/madsv2/phantom/rooms/section1.h"
+#include "mads/madsv2/phantom/rooms/room106.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+void room_106_init() {
+ int dyn_floor;
+
+ global_speech_load(speech_christine_scales);
+
+ /* ==================== Load Sprite Series ====================== */
+
+ if (global[current_year] == 1993) {
+ if (!player_has(sandbag)) {
+ ss[fx_bend_down_9] = kernel_load_series("*RRD_9", false);
+ ss[fx_sandbag] = kernel_load_series(kernel_name('x', 0), false);
+ }
+ } else {
+ ss[fx_1881] = kernel_load_series(kernel_name('z', -1), false);
+ if (object_is_here(cable_hook) && !player_has(rope_with_hook)) {
+ ss[fx_bend_down_9] = kernel_load_series("*RRD_9", false);
+ ss[fx_cable_hook] = kernel_load_series(kernel_name('p', 0), false);
+ }
+ }
+
+ ss[fx_yikes] = kernel_load_series(kernel_name('a', 0), false);
+ ss[fx_door] = kernel_load_series(kernel_name('x', 1), false);
+ ss[fx_take_9] = kernel_load_series("*RDR_9", false);
+ ss[fx_climb_up] = kernel_load_series(kernel_name('a', 1), false);
+ ss[fx_climb_down] = kernel_load_series(kernel_name('a', 2), false);
+
+
+ if ((global[current_year] == 1881) && (!global[hint_that_daae_is_home_1])) {
+ if ((global[jacques_name_is_known] == YES_AND_END_CONV) &&
+ (global[madame_name_is_known] == YES_AND_END_CONV) &&
+ (global[panel_in_206]) &&
+ (global[done_rich_conv_203]) &&
+ (player_has(lantern)) &&
+ ((player_has(cable_hook) && player_has(rope)) || player_has(rope_with_hook))) {
+ global[hint_that_daae_is_home_1] = true;
+ kernel_timing_trigger(FIVE_SECONDS, ROOM_106_INIT_TEXT);
+ }
+ }
+
+
+ /* ==================== If sandbag has dropped, show it ======== */
+
+ if ((global[sandbag_status] == SANDBAG_DROPPED) && (global[current_year] == 1993) &&
+ (object_is_here(sandbag))) {
+ seq[fx_sandbag] = kernel_seq_stamp(ss[fx_sandbag], false, KERNEL_LAST);
+ local->dynamic_sandbag = kernel_add_dynamic(words_sandbag, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ SANDBAG_X, SANDBAG_Y, SANDBAG_XS, SANDBAG_YS);
+ kernel_dynamic_walk(local->dynamic_sandbag, SANDBAG_WALK_TO_X, SANDBAG_WALK_TO_Y, FACING_NORTHEAST);
+ kernel_seq_depth(seq[fx_sandbag], 2);
+ }
+
+ if (global[current_year] == 1881) {
+ kernel_draw_to_background(ss[fx_1881], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ kernel_flip_hotspot(words_big_prop, false);
+ kernel_flip_hotspot(words_statue, false);
+ kernel_flip_hotspot(words_plant_prop, false);
+ kernel_flip_hotspot(words_pedestal, false);
+ kernel_flip_hotspot(words_sandbag, false);
+ kernel_flip_hotspot(words_crate, false);
+ kernel_add_dynamic(words_sandbag, words_look_at, SYNTAX_SINGULAR, KERNEL_NONE,
+ DYN_SANDBAG_1_X, DYN_SANDBAG_1_Y, DYN_SANDBAG_1_X_SIZE, DYN_SANDBAG_1_Y_SIZE);
+ kernel_add_dynamic(words_sandbag, words_look_at, SYNTAX_SINGULAR, KERNEL_NONE,
+ DYN_SANDBAG_2_X, DYN_SANDBAG_2_Y, DYN_SANDBAG_2_X_SIZE, DYN_SANDBAG_2_Y_SIZE);
+ kernel_add_dynamic(words_sandbag, words_look_at, SYNTAX_SINGULAR, KERNEL_NONE,
+ DYN_SANDBAG_3_X, DYN_SANDBAG_3_Y, DYN_SANDBAG_3_X_SIZE, DYN_SANDBAG_3_Y_SIZE);
+ kernel_add_dynamic(words_sandbag, words_look_at, SYNTAX_SINGULAR, KERNEL_NONE,
+ DYN_SANDBAG_4_X, DYN_SANDBAG_4_Y, DYN_SANDBAG_4_X_SIZE, DYN_SANDBAG_4_Y_SIZE);
+ dyn_floor = kernel_add_dynamic(words_stage, words_walk_across, SYNTAX_SINGULAR, KERNEL_NONE,
+ DYN_FLOOR_1_X, DYN_FLOOR_1_Y, DYN_FLOOR_1_X_SIZE, DYN_FLOOR_1_Y_SIZE);
+ kernel_dynamic_walk(dyn_floor, DYN_FLOOR_1_WALK_TO_X, DYN_FLOOR_1_WALK_TO_Y, 5);
+ dyn_floor = kernel_add_dynamic(words_stage, words_walk_across, SYNTAX_SINGULAR, KERNEL_NONE,
+ DYN_FLOOR_2_X, DYN_FLOOR_2_Y, DYN_FLOOR_2_X_SIZE, DYN_FLOOR_2_Y_SIZE);
+ kernel_dynamic_walk(dyn_floor, DYN_FLOOR_2_WALK_TO_X, DYN_FLOOR_2_WALK_TO_Y, 5);
+
+ } else {
+ kernel_flip_hotspot(words_boxes, false);
+ kernel_flip_hotspot(words_prop_case, false); /* 'case' renamed: C++ keyword */
+ }
+
+
+ if ((object_is_here(cable_hook)) && (global[current_year] == 1881) && !player_has(rope_with_hook)) {
+ seq[fx_cable_hook] = kernel_seq_stamp(ss[fx_cable_hook], false, 1);
+ kernel_seq_depth(seq[fx_cable_hook], 3);
+ } else {
+ kernel_flip_hotspot(words_cable_hook, false);
+ }
+
+
+ /* ==================== Previous Rooms ========================== */
+
+ if (previous_room == 109) {
+ player.x = WALK_TO_X_BEHIND_DOOR;
+ player.y = WALK_TO_Y_BEHIND_DOOR - 2; /* -2 gives walking time during fade in */
+ player.facing = FACING_SOUTH;
+ player_walk(FRONT_OF_DOOR_X, FRONT_OF_DOOR_Y, FACING_SOUTH);
+ player_walk_trigger(ROOM_106_DOOR_CLOSES);
+ player.commands_allowed = false;
+ seq[fx_door] = kernel_seq_stamp(ss[fx_door], false, 5);
+ kernel_seq_depth(seq[fx_door], 14);
+
+ } else if ((previous_room == 105) || (previous_room == 301)) {
+ player.x = WALK_TO_AFTER_ANIM_X - 1; /* So daemon won't send us to 105 or 321 */
+ player.y = WALK_TO_AFTER_ANIM_Y;
+ player.facing = FACING_WEST;
+ player_walk(PLAYER_X_FROM_105, PLAYER_Y_FROM_105, FACING_WEST);
+ seq[fx_door] = kernel_seq_stamp(ss[fx_door], false, 1);
+ kernel_seq_depth(seq[fx_door], 14);
+
+ } else if (previous_room == 107) {
+ player.x = PLAYER_X_FROM_107;
+ player.y = PLAYER_Y_FROM_107;
+ player.facing = FACING_WEST;
+ player_walk(WALK_TO_X_FROM_107, WALK_TO_Y_FROM_107, FACING_SOUTHEAST);
+ seq[fx_door] = kernel_seq_stamp(ss[fx_door], false, 1);
+ kernel_seq_depth(seq[fx_door], 14);
+
+ } else if ((previous_room == 108) || (previous_room != KERNEL_RESTORING_GAME)) {
+ player_first_walk(OFF_SCREEN_X_FROM_108, OFF_SCREEN_Y_FROM_108, FACING_SOUTHEAST,
+ PLAYER_X_FROM_108, PLAYER_Y_FROM_108, FACING_NORTHEAST, true);
+ seq[fx_door] = kernel_seq_stamp(ss[fx_door], false, 1);
+ kernel_seq_depth(seq[fx_door], 14);
+
+ } else if (previous_room == KERNEL_RESTORING_GAME) {
+ seq[fx_door] = kernel_seq_stamp(ss[fx_door], false, KERNEL_FIRST);
+ kernel_seq_depth(seq[fx_door], 14);
+ }
+
+ section_1_music();
+}
+
+void room_106_daemon() {
+ switch (kernel.trigger) {
+ case ROOM_106_INIT_TEXT:
+ global_speech_go(speech_christine_scales);
+ kernel_timing_trigger(TWO_SECONDS, ROOM_106_INIT_TEXT + 1);
+ break;
+
+ case ROOM_106_INIT_TEXT + 1:
+ text_show(text_106_37);
+ break;
+
+ case ROOM_106_DOOR_CLOSES:
+ kernel_seq_delete(seq[fx_door]);
+ seq[fx_door] = kernel_seq_backward(ss[fx_door], false,
+ 8, 0, 0, 1);
+ kernel_seq_depth(seq[fx_door], 14);
+ kernel_seq_range(seq[fx_door], 1, 5);
+ kernel_seq_trigger(seq[fx_door],
+ KERNEL_TRIGGER_EXPIRE, 0, ROOM_106_DOOR_CLOSES + 1);
+ break;
+
+ case ROOM_106_DOOR_CLOSES + 1:
+ seq[fx_door] = kernel_seq_stamp(ss[fx_door], false, 1);
+ kernel_seq_depth(seq[fx_door], 14);
+ sound_play(N_DoorCloses);
+ player.commands_allowed = true;
+ break;
+ }
+}
+
+void room_106_pre_parser() {
+ if (player_said_2(exit_to, stage_left_wing)) {
+ player.walk_off_edge_to_room = 108;
+ }
+
+ if (player_said_2(open, door)) {
+ player_walk(FRONT_OF_DOOR_X, FRONT_OF_DOOR_Y, FACING_NORTHWEST);
+ }
+}
+
+void room_106_parser() {
+ int temp; /* For synching purposes */
+
+ if ((player_said_2(take, sandbag)) && (inter_point_y < 61)) {
+ text_show(text_106_35);
+ goto handled;
+ /* the sandbags are too high up! */
+
+ } else if (player_said_2(take, sandbag)) {
+ if (object_is_here(sandbag)) {
+ switch (kernel.trigger) {
+ case 0:
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_bend_down_9] = kernel_seq_pingpong(ss[fx_bend_down_9], false,
+ 5, 0, 0, 2);
+ kernel_seq_range(seq[fx_bend_down_9], 1, 5);
+ kernel_seq_player(seq[fx_bend_down_9], true);
+ kernel_seq_trigger(seq[fx_bend_down_9],
+ KERNEL_TRIGGER_SPRITE, 5, 1);
+ kernel_seq_trigger(seq[fx_bend_down_9],
+ KERNEL_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ kernel_seq_delete(seq[fx_sandbag]);
+ kernel_delete_dynamic(local->dynamic_sandbag);
+ sound_play(N_TakeObjectSnd);
+ break;
+
+ case 2:
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_SERIES, seq[fx_bend_down_9]);
+ player.walker_visible = true;
+ kernel_timing_trigger(20, 3);
+ break;
+
+ case 3:
+ inter_give_to_player(sandbag);
+ /* You pick up the sandbag. */
+ object_examine(sandbag, text_008_03, 0);
+ player.commands_allowed = true;
+ break;
+ }
+ goto handled;
+ }
+ }
+
+ if (player_said_2(take, cable_hook)) {
+ if (object_is_here(cable_hook)) {
+ switch (kernel.trigger) {
+ case 0:
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_bend_down_9] = kernel_seq_pingpong(ss[fx_bend_down_9], true,
+ 5, 0, 0, 2);
+ kernel_seq_range(seq[fx_bend_down_9], 1, 5);
+ kernel_seq_player(seq[fx_bend_down_9], true);
+ kernel_seq_trigger(seq[fx_bend_down_9],
+ KERNEL_TRIGGER_SPRITE, 5, 1);
+ kernel_seq_trigger(seq[fx_bend_down_9],
+ KERNEL_TRIGGER_EXPIRE, 0, 2);
+ global[player_score] += 5;
+ break;
+
+ case 1:
+ kernel_seq_delete(seq[fx_cable_hook]);
+ kernel_flip_hotspot(words_cable_hook, false);
+ sound_play(N_TakeObjectSnd);
+ break;
+
+ case 2:
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_SERIES, seq[fx_bend_down_9]);
+ player.walker_visible = true;
+ kernel_timing_trigger(20, 3);
+ break;
+
+ case 3:
+ inter_give_to_player(cable_hook);
+ /* You pick up the cable hook. */
+ object_examine(cable_hook, text_008_22, 0);
+ player.commands_allowed = true;
+ break;
+ }
+ goto handled;
+ }
+ }
+
+ switch (kernel.trigger) {
+ case ROOM_106_CLIMB_UP:
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ aa[0] = kernel_run_animation(kernel_name('u', 1), ROOM_106_CLIMB_UP + 1);
+ kernel_synch(KERNEL_ANIM, aa[0], KERNEL_PLAYER, 0);
+ goto handled;
+ break;
+
+ case ROOM_106_CLIMB_UP + 1:
+ kernel_timing_trigger(TWO_SECONDS, ROOM_106_CLIMB_UP + 2);
+ goto handled;
+ break;
+
+ case ROOM_106_CLIMB_UP + 2:
+ new_room = 301;
+ goto handled;
+ break;
+
+ case ROOM_106_CLIMB_DOWN:
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ aa[0] = kernel_run_animation(kernel_name('d', 1), ROOM_106_CLIMB_DOWN + 1);
+ kernel_synch(KERNEL_ANIM, aa[0], KERNEL_PLAYER, 0);
+ goto handled;
+ break;
+
+ case ROOM_106_CLIMB_DOWN + 1:
+ new_room = 105;
+ goto handled;
+ break;
+ }
+
+ if (player_said_2(exit_to, stage_right_wing)) {
+ new_room = 107;
+ goto handled;
+ }
+
+ if (player_said_1(climb_down) || player_said_1(climb_up)) {
+ if (global[sandbag_status] == SANDBAG_DROPPED) {
+ switch (kernel.trigger) {
+ case 0:
+ aa[0] = kernel_run_animation(kernel_name('s', -1), 1);
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ break;
+
+ case 1:
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_ANIM, aa[0]);
+ player.walker_visible = true;
+ player.x = AFTER_LOOK_ANIM_X;
+ player.y = AFTER_LOOK_ANIM_Y;
+ player_demand_facing(FACING_EAST);
+ player_walk(WALK_TO_AFTER_ANIM_X, WALK_TO_AFTER_ANIM_Y, FACING_EAST);
+
+ if (player_said_1(climb_down)) {
+ player_walk_trigger(ROOM_106_CLIMB_DOWN);
+ } else {
+ player_walk_trigger(ROOM_106_CLIMB_UP);
+ }
+ break;
+ }
+ } else {
+ switch (kernel.trigger) {
+ case 0:
+ seq[fx_sandbag] = kernel_seq_forward(ss[fx_sandbag], false,
+ 4, 0, 0, 1);
+ kernel_seq_depth(seq[fx_sandbag], 2);
+ kernel_seq_range(seq[fx_sandbag], 1, 9);
+ kernel_timing_trigger(TENTH_SECOND, 2);
+ kernel_seq_trigger(seq[fx_sandbag],
+ KERNEL_TRIGGER_EXPIRE, 0, 1);
+ break;
+
+ case 1:
+ sound_play(N_SandbagThud);
+ seq[fx_sandbag] = kernel_seq_stamp(ss[fx_sandbag], false, KERNEL_LAST);
+ kernel_seq_depth(seq[fx_sandbag], 2);
+ local->dynamic_sandbag = kernel_add_dynamic(words_sandbag, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ SANDBAG_X, SANDBAG_Y, SANDBAG_XS, SANDBAG_YS);
+ kernel_dynamic_walk(local->dynamic_sandbag, SANDBAG_WALK_TO_X, SANDBAG_WALK_TO_Y, FACING_NORTHEAST);
+ break;
+
+ case 2:
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ aa[0] = kernel_run_animation(kernel_name('s', 1), 3);
+ kernel_synch(KERNEL_ANIM, aa[0], KERNEL_PLAYER, 0);
+ break;
+
+ case 3:
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_ANIM, aa[0]);
+ player.walker_visible = true;
+ player.commands_allowed = true;
+ player.x = AFTER_LOOK_ANIM_X + 3;
+ player.y = AFTER_LOOK_ANIM_Y - 3;
+ player_demand_facing(FACING_SOUTHEAST);
+ global[sandbag_status] = SANDBAG_DROPPED;
+ text_show(text_106_32);
+ /* sandbag just fell */
+ break;
+ }
+ }
+ goto handled;
+ }
+
+ if (player_said_2(walk_through, door) || player_said_2(open, door)) {
+ switch (kernel.trigger) {
+ case 0:
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_take_9] = kernel_seq_pingpong(ss[fx_take_9], false,
+ 5, 0, 0, 2);
+ kernel_seq_range(seq[fx_take_9], 1, 4);
+ kernel_seq_player(seq[fx_take_9], true);
+ kernel_seq_trigger(seq[fx_take_9],
+ KERNEL_TRIGGER_SPRITE, 4, ROOM_106_DOOR_OPENS);
+ kernel_seq_trigger(seq[fx_take_9],
+ KERNEL_TRIGGER_EXPIRE, 0, ROOM_106_DOOR_OPENS + 2);
+ break;
+
+ case ROOM_106_DOOR_OPENS:
+ sound_play(N_DoorOpens);
+ kernel_seq_delete(seq[fx_door]);
+ seq[fx_door] = kernel_seq_forward(ss[fx_door], false,
+ 8, 0, 0, 1);
+ kernel_seq_depth(seq[fx_door], 14);
+ kernel_seq_range(seq[fx_door], 1, 5);
+ kernel_seq_trigger(seq[fx_door],
+ KERNEL_TRIGGER_EXPIRE, 0, ROOM_106_DOOR_OPENS + 1);
+ break;
+
+ case ROOM_106_DOOR_OPENS + 1:
+ temp = seq[fx_door];
+ seq[fx_door] = kernel_seq_stamp(ss[fx_door], false, 5);
+ kernel_synch(KERNEL_SERIES, seq[fx_door], KERNEL_SERIES, temp);
+ kernel_seq_depth(seq[fx_door], 14);
+ break;
+
+ case ROOM_106_DOOR_OPENS + 2:
+ player.walker_visible = true;
+ player_walk(WALK_TO_X_BEHIND_DOOR, WALK_TO_Y_BEHIND_DOOR, FACING_NORTH);
+ player_walk_trigger(ROOM_106_DOOR_OPENS + 3);
+ break;
+
+ case ROOM_106_DOOR_OPENS + 3:
+ kernel_seq_delete(seq[fx_door]);
+ seq[fx_door] = kernel_seq_backward(ss[fx_door], false,
+ 8, 0, 0, 1);
+ kernel_seq_depth(seq[fx_door], 1);
+ kernel_seq_range(seq[fx_door], KERNEL_FIRST, KERNEL_LAST);
+ kernel_seq_trigger(seq[fx_door],
+ KERNEL_TRIGGER_EXPIRE, 0, ROOM_106_DOOR_OPENS + 4);
+ break;
+
+ case ROOM_106_DOOR_OPENS + 4:
+ sound_play(N_DoorCloses);
+ seq[fx_door] = kernel_seq_stamp(ss[fx_door], false, KERNEL_FIRST);
+ kernel_seq_depth(seq[fx_door], 1);
+ new_room = 109;
+ break;
+ }
+ goto handled;
+ }
+
+ if (player.look_around) {
+ text_show(text_106_10);
+ goto handled;
+ }
+
+ if (player_said_1(look) || player_said_1(look_at)) {
+
+ if (player_said_1(stage_right_wing)) {
+ text_show(text_106_11);
+ goto handled;
+ }
+
+ if (player_said_1(stage_left_wing)) {
+ text_show(text_106_12);
+ goto handled;
+ }
+
+ if (player_said_1(_in_two_)) {
+ text_show(text_106_13);
+ goto handled;
+ }
+
+ if (player_said_1(cyclorama)) {
+ text_show(text_106_14);
+ goto handled;
+ }
+
+ if (player_said_1(stage)) {
+ text_show(text_106_15);
+ goto handled;
+ }
+
+ if (player_said_1(pedestal)) {
+ text_show(text_106_16);
+ goto handled;
+ }
+
+ if (player_said_1(plant_prop)) {
+ text_show(text_106_17);
+ goto handled;
+ }
+
+ if (player_said_1(sandbag)) {
+ if (inter_point_y < 60) {
+ text_show(text_106_18);
+ goto handled;
+ } else {
+ if (object_is_here(sandbag)) {
+ text_show(text_106_33);
+ goto handled;
+ }
+ }
+ }
+
+ if (player_said_1(statue)) {
+ text_show(text_106_19);
+ goto handled;
+ }
+
+ if (player_said_1(circular_staircase)) {
+ text_show(text_106_20);
+ goto handled;
+ }
+
+ if (player_said_1(batten)) {
+ text_show(text_106_21);
+ goto handled;
+ }
+
+ if (player_said_1(door)) {
+ text_show(text_106_22);
+ goto handled;
+ }
+
+ if (player_said_1(boxes) || player_said_1(box)) {
+ text_show(text_106_23);
+ goto handled;
+ }
+
+ if (player_said_1(big_prop)) {
+ text_show(text_106_24);
+ goto handled;
+ }
+
+ if (player_said_1(crate)) {
+ text_show(text_106_25);
+ goto handled;
+ }
+
+ if (player_said_1(prop_case)) { /* 'case' renamed: C++ keyword */
+ if (global[current_year] == 1881) {
+ text_show(text_106_38);
+ } else {
+ text_show(text_106_36);
+ }
+ goto handled;
+ }
+
+ if (player_said_1(ventilation_duct)) {
+ text_show(text_106_26);
+ goto handled;
+ }
+
+ if (player_said_1(junk)) {
+ text_show(text_106_27);
+ goto handled;
+ }
+
+ if (player_said_1(flats)) {
+ text_show(text_106_28);
+ goto handled;
+ }
+
+ if (player_said_1(wall)) {
+ text_show(text_106_29);
+ goto handled;
+ }
+
+ if (player_said_1(cable_hook) && object_is_here(cable_hook)) {
+ text_show(text_106_39);
+ goto handled;
+ }
+ }
+
+ if (player_said_2(talk_to, statue)) {
+ text_show(text_106_30);
+ goto handled;
+ }
+
+ if (player_said_2(close, door)) {
+ text_show(text_106_34);
+ goto handled;
+ }
+
+ goto done;
+
+handled:
+ player.command_ready = false;
+
+done:
+ ;
+}
+
+void room_106_preload() {
+ room_init_code_pointer = room_106_init;
+ room_pre_parser_code_pointer = room_106_pre_parser;
+ room_parser_code_pointer = room_106_parser;
+ room_daemon_code_pointer = room_106_daemon;
+
+ if (global[current_year] == 1881) {
+ kernel_initial_variant = 1;
+ }
+ section_1_walker();
+ section_1_interface();
+}
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/rooms/room106.h b/engines/mads/madsv2/phantom/rooms/room106.h
new file mode 100644
index 00000000000..d83e0ac4211
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room106.h
@@ -0,0 +1,167 @@
+/* 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/>.
+ *
+ */
+
+/* room106.mac by Paul Lahaise 7-Jan-93 */
+
+#ifndef MADS_PHANTOM_ROOM106_H
+#define MADS_PHANTOM_ROOM106_H
+
+#include "mads/madsv2/phantom/rooms/section1.h"
+#include "mads/madsv2/phantom/global.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+#define local ((Scratch *)(&game.scratch[0]))
+#define ss local->sprite
+#define seq local->sequence
+#define aa local->animation
+
+typedef struct { /* Room local variables */
+
+ int sprite[15]; /* Sprite series handles */
+ int sequence[15]; /* Sequence handles */
+ int animation[4]; /* Animation handles */
+ int dynamic_sandbag; /* Dynamic HS for fallen sandbag */
+
+} Scratch;
+
+
+/* ========================= Sprite Series ========================= */
+
+#define fx_sandbag 0 /* rm106x0 */
+#define fx_yikes 1 /* rm106a0 */
+#define fx_door 2 /* rm106x1 */
+#define fx_take_9 3 /* rdr_9 */
+#define fx_climb_up 4 /* rm106a1 */
+#define fx_bend_down_9 5 /* rrd_9 */
+#define fx_climb_down 6 /* rm106a2 */
+#define fx_1881 7 /* rm106z */
+#define fx_cable_hook 8 /* rm106p0 */
+
+
+/* ========================= Triggers ============================== */
+
+#define ROOM_106_DOOR_CLOSES 60
+#define ROOM_106_DOOR_OPENS 65
+#define ROOM_106_CLIMB_DOWN 75
+#define ROOM_106_CLIMB_UP 80
+#define ROOM_106_INIT_TEXT 85
+
+
+/* ========================= Player positions ====================== */
+
+#define PLAYER_X_FROM_105 227
+#define PLAYER_Y_FROM_105 143
+
+#define PLAYER_X_FROM_108 19
+#define PLAYER_Y_FROM_108 147
+
+#define PLAYER_X_FROM_107 143
+#define PLAYER_Y_FROM_107 68
+
+#define PLAYER_X_FROM_109 178
+#define PLAYER_Y_FROM_109 68
+
+#define WALK_TO_X_FROM_107 163
+#define WALK_TO_Y_FROM_107 68
+
+#define AFTER_LOOK_ANIM_X 225
+#define AFTER_LOOK_ANIM_Y 143
+
+#define WALK_TO_AFTER_ANIM_X 236
+#define WALK_TO_AFTER_ANIM_Y 142
+
+#define FRONT_OF_DOOR_X 179
+#define FRONT_OF_DOOR_Y 63
+
+#define WALK_TO_X_BEHIND_DOOR 180
+#define WALK_TO_Y_BEHIND_DOOR 60
+
+#define OFF_SCREEN_X_FROM_108 -20
+#define OFF_SCREEN_Y_FROM_108 130
+
+
+/* ========================= Fallen sandbag hotspot ================ */
+
+#define SANDBAG_X 227
+#define SANDBAG_Y 140
+#define SANDBAG_XS 18
+#define SANDBAG_YS 11
+
+#define SANDBAG_WALK_TO_X 224
+#define SANDBAG_WALK_TO_Y 152
+
+
+/* ========================= Sandbag dynamics (1881) =============== */
+
+#define DYN_SANDBAG_1_X 40
+#define DYN_SANDBAG_1_Y 47
+#define DYN_SANDBAG_1_X_SIZE 11
+#define DYN_SANDBAG_1_Y_SIZE 17
+
+#define DYN_SANDBAG_2_X 98
+#define DYN_SANDBAG_2_Y 14
+#define DYN_SANDBAG_2_X_SIZE 5
+#define DYN_SANDBAG_2_Y_SIZE 10
+
+#define DYN_SANDBAG_3_X 111
+#define DYN_SANDBAG_3_Y 23
+#define DYN_SANDBAG_3_X_SIZE 6
+#define DYN_SANDBAG_3_Y_SIZE 9
+
+#define DYN_SANDBAG_4_X 119
+#define DYN_SANDBAG_4_Y 12
+#define DYN_SANDBAG_4_X_SIZE 5
+#define DYN_SANDBAG_4_Y_SIZE 8
+
+
+/* ========================= Floor dynamics (1881) ================= */
+
+#define DYN_FLOOR_1_X 80
+#define DYN_FLOOR_1_Y 114
+#define DYN_FLOOR_1_X_SIZE 24
+#define DYN_FLOOR_1_Y_SIZE 4
+#define DYN_FLOOR_1_WALK_TO_X 93
+#define DYN_FLOOR_1_WALK_TO_Y 121
+
+#define DYN_FLOOR_2_X 106
+#define DYN_FLOOR_2_Y 102
+#define DYN_FLOOR_2_X_SIZE 5
+#define DYN_FLOOR_2_Y_SIZE 10
+#define DYN_FLOOR_2_WALK_TO_X 108
+#define DYN_FLOOR_2_WALK_TO_Y 109
+
+
+extern void room_106_init(void);
+extern void room_106_daemon(void);
+extern void room_106_pre_parser(void);
+extern void room_106_parser(void);
+extern void room_106_preload(void);
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index 9dfd5f85b62..11eec2823b2 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -127,6 +127,7 @@ MODULE_OBJS += \
madsv2/phantom/rooms/room103.o \
madsv2/phantom/rooms/room104.o \
madsv2/phantom/rooms/room105.o \
+ madsv2/phantom/rooms/room106.o \
madsv2/phantom/phantom.o \
madsv2/phantom/conv.o \
madsv2/phantom/main_menu.o \
Commit: 7815cb5a9ae1a92a058a3e4a38bc739344b6a123
https://github.com/scummvm/scummvm/commit/7815cb5a9ae1a92a058a3e4a38bc739344b6a123
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:40+10:00
Commit Message:
MADS: PHANTOM: Added room 107
Changed paths:
A engines/mads/madsv2/phantom/rooms/room107.cpp
A engines/mads/madsv2/phantom/rooms/room107.h
engines/mads/madsv2/phantom/mads/text.h
engines/mads/madsv2/phantom/mads/words.h
engines/mads/module.mk
diff --git a/engines/mads/madsv2/phantom/mads/text.h b/engines/mads/madsv2/phantom/mads/text.h
index a6c16a6eec4..a7183758517 100644
--- a/engines/mads/madsv2/phantom/mads/text.h
+++ b/engines/mads/madsv2/phantom/mads/text.h
@@ -76,8 +76,10 @@ enum {
text_008_01 = 801,
text_008_02 = 802,
text_008_03 = 803,
+ text_008_04 = 804,
text_008_22 = 822,
text_008_42 = 842,
+ text_008_43 = 843,
/* Room 103 */
text_103_10 = 10310,
@@ -209,7 +211,32 @@ enum {
text_106_36 = 10636,
text_106_37 = 10637,
text_106_38 = 10638,
- text_106_39 = 10639
+ text_106_39 = 10639,
+
+ /* Room 107 */
+ text_107_10 = 10710,
+ text_107_11 = 10711,
+ text_107_12 = 10712,
+ text_107_13 = 10713,
+ text_107_14 = 10714,
+ text_107_15 = 10715,
+ text_107_16 = 10716,
+ text_107_17 = 10717,
+ text_107_18 = 10718,
+ text_107_19 = 10719,
+ text_107_20 = 10720,
+ text_107_21 = 10721,
+ text_107_22 = 10722,
+ text_107_23 = 10723,
+ text_107_24 = 10724,
+ text_107_25 = 10725,
+ text_107_26 = 10726,
+ text_107_27 = 10727,
+ text_107_28 = 10728,
+ text_107_29 = 10729,
+ text_107_30 = 10730,
+ text_107_31 = 10731,
+ text_107_32 = 10732
};
} // namespace Phantom
diff --git a/engines/mads/madsv2/phantom/mads/words.h b/engines/mads/madsv2/phantom/mads/words.h
index 4c04bb5ac76..b1439196fce 100644
--- a/engines/mads/madsv2/phantom/mads/words.h
+++ b/engines/mads/madsv2/phantom/mads/words.h
@@ -34,6 +34,7 @@ enum {
words_act_curtain = 17,
words_aisle = 18,
words_apron = 19,
+ words_backstage = 21,
words_bear_prop = 22,
words_cable = 26,
words_carton = 28,
@@ -42,6 +43,7 @@ enum {
words_climb_through = 35,
words_column_prop = 36,
words_conductor_s_stand = 37,
+ words_counterweight_system = 40,
words_crate = 41,
words_cyclorama = 44,
words_door = 46,
@@ -64,6 +66,7 @@ enum {
words_leg = 90,
words_light_fixture = 92,
words_lock = 93,
+ words_lockrail = 95,
words_look_at = 96,
words_look_through = 97,
words_music_stand = 103,
@@ -76,6 +79,7 @@ enum {
words_prop_table = 117,
words_props = 118,
words_proscenium_arch = 119,
+ words_purchase_lines = 120,
words_red_frame = 123,
words_sandbag = 127,
words_seats = 129,
@@ -93,11 +97,15 @@ enum {
words_walk_through = 155,
words_wall = 157,
words_water_pipe = 160,
+ words_yellow_frame = 163,
words_prop = 164,
words_climb_up = 165,
+ words_walk_onto = 166,
+ words_walk = 167,
words_door_to_pit = 170,
words_boxes = 172,
words_box = 175,
+ words_headset = 179,
words_grand_foyer = 180,
words_back_wall = 181,
words_stage_right_wing = 193,
diff --git a/engines/mads/madsv2/phantom/rooms/room107.cpp b/engines/mads/madsv2/phantom/rooms/room107.cpp
new file mode 100644
index 00000000000..a92d47c7449
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room107.cpp
@@ -0,0 +1,303 @@
+/* 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 "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/imath.h"
+#include "mads/madsv2/core/text.h"
+#include "mads/madsv2/core/inter.h"
+#include "mads/madsv2/core/object.h"
+#include "mads/madsv2/core/sound.h"
+#include "mads/madsv2/phantom/global.h"
+#include "mads/madsv2/phantom/mads/inventory.h"
+#include "mads/madsv2/phantom/mads/words.h"
+#include "mads/madsv2/phantom/mads/sounds.h"
+#include "mads/madsv2/phantom/mads/text.h"
+#include "mads/madsv2/phantom/rooms/section1.h"
+#include "mads/madsv2/phantom/rooms/room107.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+void room_107_init() {
+ /* ==================== Load Sprite Series ====================== */
+
+ if (global[current_year] == 1993) {
+ ss[fx_1993] = kernel_load_series(kernel_name('z', -1), false);
+ }
+
+ if (object_is_here(yellow_frame)) {
+ ss[fx_yellow_frame] = kernel_load_series(kernel_name('f', 0), false);
+ ss[fx_bend_down_9] = kernel_load_series("*RRD_9", false);
+ }
+
+
+ /* ==================== If in 1881, put yellow_frame =========== */
+
+ if (object_is_here(yellow_frame)) {
+ seq[fx_yellow_frame] = kernel_seq_stamp(ss[fx_yellow_frame], false, 1);
+ kernel_seq_depth(seq[fx_yellow_frame], 14);
+ } else {
+ kernel_flip_hotspot(words_yellow_frame, false);
+ }
+
+
+ /* ==================== If in 1993, put 1993 here ============== */
+
+ if (global[current_year] == 1993) {
+ kernel_draw_to_background(ss[fx_1993], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ kernel_flip_hotspot(words_prop_table, false);
+ } else {
+ kernel_flip_hotspot(words_headset, false);
+ }
+
+
+ /* ==================== Previous Rooms ========================== */
+
+ if (previous_room == 106) {
+ player.x = PLAYER_X_FROM_106;
+ player.y = PLAYER_Y_FROM_106;
+ player.facing = FACING_SOUTHWEST;
+ player_walk(WALK_TO_X_FROM_106, WALK_TO_Y_FROM_106, FACING_SOUTHWEST);
+
+ } else if ((previous_room == 104) || (previous_room != KERNEL_RESTORING_GAME)) {
+
+ if (player.y > 128) {
+ player.x = PLAYER_X_FROM_104_3;
+ player.facing = FACING_NORTHWEST;
+
+ } else if (player.y > 99) {
+ player.x = PLAYER_X_FROM_104_2;
+ player.facing = FACING_NORTHWEST;
+
+ } else {
+ player.x = PLAYER_X_FROM_104_1;
+ player.facing = FACING_NORTHEAST;
+ }
+
+ player.y = PLAYER_Y_FROM_104;
+ }
+
+ section_1_music();
+}
+
+void room_107_parser() {
+ int count = 0;
+
+ if (player_said_2(walk_onto, stage)) {
+ new_room = 104;
+ goto handled;
+ }
+
+ if (player_said_2(walk, backstage)) {
+ new_room = 106;
+ goto handled;
+ }
+
+ if (player_said_2(take, yellow_frame) &&
+ (object_is_here(yellow_frame) || kernel.trigger)) {
+ switch (kernel.trigger) {
+ case 0:
+ if (global[current_year] == 1881) {
+ if (player_has(green_frame)) ++count;
+ if (player_has(red_frame)) ++count;
+ if (player_has(blue_frame)) ++count;
+ if (count < 3) global[player_score] += 5;
+ }
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_bend_down_9] = kernel_seq_pingpong(ss[fx_bend_down_9], false,
+ 5, 0, 0, 2);
+ kernel_seq_range(seq[fx_bend_down_9], 1, 5);
+ kernel_seq_player(seq[fx_bend_down_9], true);
+ kernel_seq_trigger(seq[fx_bend_down_9],
+ KERNEL_TRIGGER_SPRITE, 5, 1);
+ kernel_seq_trigger(seq[fx_bend_down_9],
+ KERNEL_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ kernel_seq_delete(seq[fx_yellow_frame]);
+ kernel_flip_hotspot(words_yellow_frame, false);
+ inter_give_to_player(yellow_frame);
+ sound_play(N_TakeObjectSnd);
+ break;
+
+ case 2:
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_SERIES, seq[fx_bend_down_9]);
+ player.walker_visible = true;
+ kernel_timing_trigger(20, 3);
+ break;
+
+ case 3:
+ if (global[current_year] == 1881) {
+ object_examine(yellow_frame, text_008_43, 0);
+ } else {
+ object_examine(yellow_frame, text_008_04, 0);
+ }
+ /* You pick up the yellow color frame */
+ player.commands_allowed = true;
+ break;
+ }
+ goto handled;
+ }
+
+ if (player.look_around) {
+ text_show(text_107_10);
+ goto handled;
+ }
+
+ if (player_said_1(look) || player_said_1(look_at)) {
+ if (player_said_1(stage)) {
+ text_show(text_107_11);
+ goto handled;
+ }
+
+ if (player_said_1(_in_two_)) {
+ text_show(text_107_12);
+ goto handled;
+ }
+
+ if (player_said_1(_in_one_)) {
+ text_show(text_107_13);
+ goto handled;
+ }
+
+ if (player_said_1(cyclorama)) {
+ text_show(text_107_14);
+ goto handled;
+ }
+
+ if (player_said_1(counterweight_system)) {
+ text_show(text_107_15);
+ goto handled;
+ }
+
+ if (player_said_1(purchase_lines)) {
+ text_show(text_107_16);
+ goto handled;
+ }
+
+ if (player_said_1(lockrail)) {
+ text_show(text_107_17);
+ goto handled;
+ }
+
+ if (player_said_1(stage)) { /* Note: second 'stage' check â unreachable in original */
+ text_show(text_107_18);
+ goto handled;
+ }
+
+ if (player_said_1(prop_table)) {
+ text_show(text_107_19);
+ goto handled;
+ }
+
+ if (player_said_1(act_curtain)) {
+ text_show(text_107_20);
+ goto handled;
+ }
+
+ if (player_said_1(leg)) {
+ text_show(text_107_21);
+ goto handled;
+ }
+
+ if (player_said_1(apron)) {
+ text_show(text_107_22);
+ goto handled;
+ }
+
+ if (player_said_1(proscenium_arch)) {
+ text_show(text_107_23);
+ goto handled;
+ }
+
+ if (player_said_1(stage)) { /* Note: third 'stage' check â unreachable in original */
+ text_show(text_107_24);
+ goto handled;
+ }
+
+ if (player_said_1(backstage)) {
+ text_show(text_107_25);
+ goto handled;
+ }
+
+ if (player_said_1(yellow_frame) && object_is_here(yellow_frame)) {
+ if (global[current_year] == 1881) {
+ text_show(text_107_27);
+ } else {
+ text_show(text_107_26);
+ }
+ goto handled;
+ }
+
+ if (player_said_1(headset)) {
+ text_show(text_107_28);
+ goto handled;
+ }
+
+ if (player_said_1(wall)) {
+ text_show(text_107_30);
+ goto handled;
+ }
+ }
+
+ if (player_said_2(take, headset)) {
+ text_show(text_107_29);
+ goto handled;
+ }
+
+ if (player_said_2(talk_to, headset)) {
+ text_show(text_107_32);
+ goto handled;
+ }
+
+ if (player_said_2(pull, purchase_lines)) {
+ text_show(text_107_31);
+ goto handled;
+ }
+
+ goto done;
+
+handled:
+ player.command_ready = false;
+
+done:
+ ;
+}
+
+void room_107_preload() {
+ room_init_code_pointer = room_107_init;
+ room_pre_parser_code_pointer = NULL;
+ room_parser_code_pointer = room_107_parser;
+ room_daemon_code_pointer = NULL;
+
+ section_1_walker();
+ section_1_interface();
+}
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/rooms/room107.h b/engines/mads/madsv2/phantom/rooms/room107.h
new file mode 100644
index 00000000000..cf8cb69919e
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room107.h
@@ -0,0 +1,79 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/* room107.mac by Paul Lahaise 8-Jan-93 */
+
+#ifndef MADS_PHANTOM_ROOM107_H
+#define MADS_PHANTOM_ROOM107_H
+
+#include "mads/madsv2/phantom/rooms/section1.h"
+#include "mads/madsv2/phantom/global.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+#define local ((Scratch *)(&game.scratch[0]))
+#define ss local->sprite
+#define seq local->sequence
+#define aa local->animation
+
+typedef struct { /* Room local variables */
+
+ int sprite[15]; /* Sprite series handles */
+ int sequence[15]; /* Sequence handles */
+ int animation[4]; /* Animation handles */
+
+} Scratch;
+
+
+/* ========================= Sprite Series ========================= */
+
+#define fx_1993 0 /* rm107z */
+#define fx_bend_down_9 1 /* rrd_9 */
+#define fx_yellow_frame 2 /* rm107f0 */
+
+
+/* ========================= Player positions ====================== */
+
+#define PLAYER_X_FROM_104_1 44
+#define PLAYER_X_FROM_104_2 127
+#define PLAYER_X_FROM_104_3 216
+#define PLAYER_Y_FROM_104 143
+
+#define PLAYER_X_FROM_106 276
+#define PLAYER_Y_FROM_106 73
+
+#define WALK_TO_X_FROM_106 248
+#define WALK_TO_Y_FROM_106 75
+
+
+extern void room_107_init(void);
+extern void room_107_parser(void);
+extern void room_107_preload(void);
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index 11eec2823b2..d63c91db600 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -128,6 +128,7 @@ MODULE_OBJS += \
madsv2/phantom/rooms/room104.o \
madsv2/phantom/rooms/room105.o \
madsv2/phantom/rooms/room106.o \
+ madsv2/phantom/rooms/room107.o \
madsv2/phantom/phantom.o \
madsv2/phantom/conv.o \
madsv2/phantom/main_menu.o \
Commit: 460ec4839ddc9a76aaf22be2c229760f717afa86
https://github.com/scummvm/scummvm/commit/460ec4839ddc9a76aaf22be2c229760f717afa86
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:41+10:00
Commit Message:
MADS: PHANTOM: Added room 108
Changed paths:
A engines/mads/madsv2/phantom/rooms/room108.cpp
A engines/mads/madsv2/phantom/rooms/room108.h
engines/mads/madsv2/phantom/conv.h
engines/mads/madsv2/phantom/mads/text.h
engines/mads/madsv2/phantom/mads/words.h
engines/mads/module.mk
diff --git a/engines/mads/madsv2/phantom/conv.h b/engines/mads/madsv2/phantom/conv.h
index fca87662ae6..565e472db54 100644
--- a/engines/mads/madsv2/phantom/conv.h
+++ b/engines/mads/madsv2/phantom/conv.h
@@ -32,6 +32,7 @@ namespace Phantom {
enum {
conv001_speech_talk = 0,
conv001_continue_abc = 1,
+ conv002_questions_one = 2,
conv001_what_one = 4,
conv001_yesno_yes = 8,
conv001_everything_byebye = 10,
@@ -43,18 +44,20 @@ enum {
};
enum {
- conv012_hello_one = 1,
- conv012_hello_four = 4,
- conv012_byebye_first = 6,
- conv012_questions_three = 7,
- conv012_questions_one = 8,
- conv012_seen_byebye = 10,
- conv012_seen_mask = 12,
- conv012_tell_byebye = 19,
- conv012_tell_knewhim = 29,
- conv012_nomore_first = 30,
-
- conv012_var_questions_done = 26,
+ conv002_sayone_abc = 1,
+ conv002_answers_job = 5,
+ conv002_answers_please = 6,
+ conv002_answers_house = 8,
+ conv002_answers_go_on = 9,
+ conv002_answers_prison = 10,
+ conv002_answers_building = 11,
+ conv002_answers_catacombs = 12,
+ conv002_interrogate_mishap = 15,
+ conv002_interrogate_chandelier = 16,
+ conv002_interrogate_phantom = 19,
+ conv002_interrogate_giry = 22,
+ conv002_nomore_first = 25,
+ conv002_saytwo_abc = 26,
conv007_richard_intro_b = 2,
conv007_daaeb_intro_c = 3,
@@ -73,7 +76,19 @@ enum {
conv007_final_goaway = 25,
conv007_office_abc = 28,
conv007_solo_alone = 30,
- conv007_pinch_wait_b_nothing_b = 32
+ conv007_pinch_wait_b_nothing_b = 32,
+
+ conv012_hello_one = 1,
+ conv012_hello_four = 4,
+ conv012_byebye_first = 6,
+ conv012_questions_three = 7,
+ conv012_questions_one = 8,
+ conv012_seen_byebye = 10,
+ conv012_seen_mask = 12,
+ conv012_tell_byebye = 19,
+ conv012_var_questions_done = 26,
+ conv012_tell_knewhim = 29,
+ conv012_nomore_first = 30
};
struct ConvData {
diff --git a/engines/mads/madsv2/phantom/mads/text.h b/engines/mads/madsv2/phantom/mads/text.h
index a7183758517..969be0d58ef 100644
--- a/engines/mads/madsv2/phantom/mads/text.h
+++ b/engines/mads/madsv2/phantom/mads/text.h
@@ -236,7 +236,47 @@ enum {
text_107_29 = 10729,
text_107_30 = 10730,
text_107_31 = 10731,
- text_107_32 = 10732
+ text_107_32 = 10732,
+
+ /* Room 108 */
+ text_108_10 = 10810,
+ text_108_11 = 10811,
+ text_108_12 = 10812,
+ text_108_13 = 10813,
+ text_108_14 = 10814,
+ text_108_15 = 10815,
+ text_108_16 = 10816,
+ text_108_17 = 10817,
+ text_108_18 = 10818,
+ text_108_19 = 10819,
+ text_108_20 = 10820,
+ text_108_21 = 10821,
+ text_108_22 = 10822,
+ text_108_23 = 10823,
+ text_108_24 = 10824,
+ text_108_25 = 10825,
+ text_108_26 = 10826,
+ text_108_27 = 10827,
+ text_108_28 = 10828,
+ text_108_29 = 10829,
+ text_108_30 = 10830,
+
+ /* Room 109 */
+ text_109_10 = 10910,
+ text_109_11 = 10911,
+ text_109_12 = 10912,
+ text_109_13 = 10913,
+ text_109_14 = 10914,
+ text_109_15 = 10915,
+ text_109_16 = 10916,
+ text_109_17 = 10917,
+ text_109_18 = 10918,
+ text_109_19 = 10919,
+ text_109_20 = 10920,
+ text_109_21 = 10921,
+ text_109_22 = 10922,
+ text_109_23 = 10923,
+ text_109_24 = 10924
};
} // namespace Phantom
diff --git a/engines/mads/madsv2/phantom/mads/words.h b/engines/mads/madsv2/phantom/mads/words.h
index b1439196fce..07a4bf15b16 100644
--- a/engines/mads/madsv2/phantom/mads/words.h
+++ b/engines/mads/madsv2/phantom/mads/words.h
@@ -87,7 +87,9 @@ enum {
words_stage = 132,
words_stage_left = 134,
words_stage_right = 135,
+ words_stagemanager_s_post = 136,
words_stair_unit = 137,
+ words_stool = 140,
words_thunder_machine = 145,
words_trap_ceiling = 147,
words_trap_door = 148,
@@ -123,6 +125,7 @@ enum {
words_Jacques = 280,
words_gentleman = 281,
words_climb = 288,
+ words_Charles = 298,
words_prompter_s_seat = 300,
words_lever = 301,
words_Monsieur_Richard = 302,
diff --git a/engines/mads/madsv2/phantom/rooms/room108.cpp b/engines/mads/madsv2/phantom/rooms/room108.cpp
new file mode 100644
index 00000000000..01fc0bfd40f
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room108.cpp
@@ -0,0 +1,581 @@
+/* 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 "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/imath.h"
+#include "mads/madsv2/core/text.h"
+#include "mads/madsv2/core/inter.h"
+#include "mads/madsv2/core/object.h"
+#include "mads/madsv2/core/sound.h"
+#include "mads/madsv2/phantom/global.h"
+#include "mads/madsv2/phantom/conv.h"
+#include "mads/madsv2/phantom/mads/words.h"
+#include "mads/madsv2/phantom/mads/sounds.h"
+#include "mads/madsv2/phantom/mads/text.h"
+#include "mads/madsv2/phantom/conv.h"
+#include "mads/madsv2/phantom/rooms/section1.h"
+#include "mads/madsv2/phantom/rooms/room108.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+static void handle_animation_char() {
+ int random = 0;
+ int char_reset_frame;
+ int delay;
+
+ if (kernel_anim[aa[0]].frame != local->char_frame) {
+ local->char_frame = kernel_anim[aa[0]].frame;
+ char_reset_frame = -1;
+
+ switch (local->char_frame) {
+ case 1: /* end of write 1 */
+ case 2: /* end of write 2 */
+ case 3: /* end of write 3 */
+ case 4: /* end of write 4 */
+ case 92: /* end of turning to write */
+ if (local->char_action == CONV2_CHAR_WRITE) {
+ random = imath_random(2, 15);
+ } /* random writing motions */
+
+ if (local->char_action == CONV2_CHAR_TURN_TO_RAOUL) {
+ local->char_talk_count = 0;
+ local->char_action = CONV2_CHAR_TALK;
+ random = 1;
+ } /* turn to face Raoul (new node) */
+
+ switch (random) {
+ case 1: char_reset_frame = 5; break; /* turn to face Raoul (new node) */
+ case 2: char_reset_frame = 0; break; /* do write 1 */
+ case 3: char_reset_frame = 1; break; /* do write 2 */
+ case 4: char_reset_frame = 2; break; /* do write 3 */
+ default: char_reset_frame = 3; break; /* do write 5 */
+ }
+ break;
+
+ case 18: /* end of turn to face Raoul */
+ case 19: /* end of talk 1 */
+ case 20: /* end of talk 2 */
+ case 21: /* end of talk 3 */
+ case 73: /* end of talk 4 (left hand up) */
+ case 27: /* end of point right */
+ case 33: /* end of point up */
+ case 52: /* end of shut up 1 */
+ case 53: /* end of shut up 2 */
+ case 54: /* end of shut up 3 */
+ case 55: /* end of shut up 4 */
+ case 56: /* end of shut up 5 */
+ case 57: /* end of shut up 6 */
+ case 62: /* end of shut up 7 */
+ case 51: /* end of oh my */
+ case 41: /* end of both hands up */
+
+ if (local->char_frame == 18) {
+ player.commands_allowed = true;
+ conv_run(CONV_CHARLES);
+ conv_export_pointer(&global[player_score]);
+ conv_export_value(global[julie_name_is_known]);
+ conv_export_value(global[observed_phan_104]);
+ }
+
+ if (local->char_action == CONV2_CHAR_TALK) {
+ if (local->did_raise_hand) {
+ random = imath_random(1, 3); /* so we don't raise hand again */
+ } else {
+ random = imath_random(1, 4);
+ if (random == 4) {
+ random = imath_random(1, 4); /* decrease raise hand probability */
+ }
+ }
+
+ if (random == 4) {
+ local->did_raise_hand = true;
+ }
+
+ ++local->char_talk_count;
+ if (local->char_talk_count > local->max_talk_count) {
+ local->char_action = CONV2_CHAR_SHUT_UP;
+ local->char_shut_up_count = 0;
+ local->prev_shut_up_frame = 10;
+ random = 12;
+ }
+
+ } else if (local->char_action == CONV2_CHAR_SHUT_UP) {
+ delay = imath_random(10, 15); /* delay for shut up motions */
+ ++local->char_shut_up_count;
+ if (local->char_shut_up_count > delay) {
+ random = imath_random(10, 16);
+ local->prev_shut_up_frame = random;
+ if (random == 15) {
+ local->char_shut_up_count = 16; /* make him turn right once */
+ } else {
+ local->char_shut_up_count = 0; /* make him freeze x times */
+ }
+ } else {
+ random = local->prev_shut_up_frame;
+ } /* random shut up motions */
+
+ } else if (local->char_action == CONV2_CHAR_POINT_RIGHT) {
+ local->char_action = CONV2_CHAR_TALK;
+ random = 5;
+ /* point right */
+
+ } else if (local->char_action == CONV2_CHAR_OH_MY) {
+ local->char_action = CONV2_CHAR_TALK;
+ random = 6;
+ /* do oh my! */
+
+ } else if (local->char_action == CONV2_CHAR_BOTH_HANDS_UP) {
+ local->char_action = CONV2_CHAR_TALK;
+ random = 7;
+ /* do both hands up */
+
+ } else if (local->char_action == CONV2_CHAR_POINT_UP) {
+ local->char_action = CONV2_CHAR_TALK;
+ random = 8;
+ /* point up */
+
+ } else if (local->char_action == CONV2_CHAR_WRITE) {
+ random = 9;
+ } /* turn back to write */
+
+ switch (random) {
+ case 1: char_reset_frame = 18; break; /* do talk 1 */
+ case 2: char_reset_frame = 19; break; /* do talk 2 */
+ case 3: char_reset_frame = 20; break; /* do talk 3 */
+ case 4:
+ char_reset_frame = 62;
+ local->char_talk_count += 5;
+ break; /* do talk 4 (put left hand up) */
+ case 5: char_reset_frame = 21; break; /* point right */
+ case 6: char_reset_frame = 41; break; /* do oh my! */
+ case 7: char_reset_frame = 33; break; /* do both hands up */
+ case 8: char_reset_frame = 27; break; /* do point up */
+ case 9: char_reset_frame = 74; break; /* turn back to write */
+ case 10: char_reset_frame = 51; break; /* do shut up 1 */
+ case 11: char_reset_frame = 53; break; /* do shut up 2 */
+ case 12: char_reset_frame = 54; break; /* do shut up 3 */
+ case 13: char_reset_frame = 55; break; /* do shut up 4 */
+ case 14: char_reset_frame = 56; break; /* do shut up 5 */
+ case 15: char_reset_frame = 57; break; /* do shut up 6 (look right) */
+ case 16: char_reset_frame = 52; break; /* do shut up 7 */
+ }
+ break;
+ }
+
+ if (char_reset_frame >= 0) {
+ kernel_reset_animation(aa[0], char_reset_frame);
+ local->char_frame = char_reset_frame;
+ }
+ }
+}
+
+void room_108_init() {
+ int dynamic; /* For adding dynamic hotspots */
+
+ if (previous_room != KERNEL_RESTORING_GAME) {
+ local->anim_0_running = false;
+ local->did_raise_hand = false;
+ local->char_talk_count = 0;
+ local->char_shut_up_count = 40; /* so daemon will pick a new shut up motion */
+ local->max_talk_count = 15;
+ }
+
+
+ /* ==================== Load conversation ======================= */
+
+ conv_get(CONV_CHARLES);
+
+
+ /* ==================== Load Sprite Series ====================== */
+ /* ==================== Put headset / change podium if in 1993 = */
+
+ if (global[current_year] == 1993) {
+ ss[fx_1993] = kernel_load_series(kernel_name('z', -1), false);
+ kernel_flip_hotspot(words_stool, false);
+ dynamic = kernel_add_dynamic(words_stool, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ STOOL_X, STOOL_Y, STOOL_X_SIZE, STOOL_Y_SIZE);
+ kernel_dynamic_hot[dynamic].prep = PREP_ON;
+ kernel_dynamic_walk(dynamic, STOOL_WALK_X, STOOL_WALK_Y, FACING_SOUTHEAST);
+ kernel_draw_to_background(ss[fx_1993], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ } else {
+ kernel_flip_hotspot(words_headset, false);
+ dynamic = kernel_add_dynamic(words_wall, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ WALL_X, WALL_Y, WALL_X_SIZE, WALL_Y_SIZE);
+ kernel_dynamic_hot[dynamic].prep = PREP_ON;
+ kernel_dynamic_walk(dynamic, WALL_WALK_X, WALL_WALK_Y, FACING_NORTHEAST);
+ }
+
+
+ /* ==================== Put Charles down ======================== */
+
+ if ((global[current_year] == 1993) && (global[done_brie_conv_203] == NO)) {
+ aa[0] = kernel_run_animation(kernel_name('c', 1), 1);
+ local->anim_0_running = true;
+
+ if (conv_restore_running == CONV_CHARLES) {
+ global[walker_converse] = imath_random(CONVERSE_LEAN, CONVERSE_HAND_CHIN);
+ local->char_action = CONV2_CHAR_SHUT_UP;
+ conv_run(CONV_CHARLES);
+ conv_export_pointer(&global[player_score]);
+ conv_export_value(global[julie_name_is_known]);
+ conv_export_value(global[observed_phan_104]);
+ kernel_reset_animation(aa[0], 55); /* put somewhere in the shut up mode */
+ local->char_shut_up_count = 40; /* so daemon will pick a new shut up motion */
+ } else {
+ local->char_action = CONV2_CHAR_WRITE;
+ }
+
+ if (global[charles_name_is_known]) {
+ local->dynamic_char = kernel_add_dynamic(words_Charles, words_walk_to, SYNTAX_SINGULAR_MASC, KERNEL_NONE,
+ DYN_CHAR_X, DYN_CHAR_Y, DYN_CHAR_XS, DYN_CHAR_YS);
+ kernel_dynamic_hot[local->dynamic_char].prep = PREP_ON;
+ } else {
+ local->dynamic_char = kernel_add_dynamic(words_gentleman, words_walk_to, SYNTAX_MASC_NOT_PROPER, KERNEL_NONE,
+ DYN_CHAR_X, DYN_CHAR_Y, DYN_CHAR_XS, DYN_CHAR_YS);
+ kernel_dynamic_hot[local->dynamic_char].prep = PREP_ON;
+ }
+ kernel_dynamic_walk(local->dynamic_char, DYN_CHAR_WALK_TO_X, DYN_CHAR_WALK_TO_Y, FACING_NORTHEAST);
+ }
+
+
+ /* ==================== Previous Rooms ========================== */
+
+ if (previous_room == 106) {
+ player.x = PLAYER_X_FROM_106;
+ player.y = PLAYER_Y_FROM_106;
+ player.facing = FACING_SOUTHEAST;
+ player_walk(WALK_TO_X_FROM_106, WALK_TO_Y_FROM_106, FACING_SOUTHEAST);
+
+ } else if ((previous_room == 104) || (previous_room != KERNEL_RESTORING_GAME)) {
+
+ if (player.y > 128) {
+ player.x = PLAYER_X_FROM_104_3;
+ player.facing = FACING_NORTHEAST;
+
+ } else if (player.y > 99) {
+ player.x = PLAYER_X_FROM_104_2;
+ player.facing = FACING_NORTHEAST;
+
+ } else {
+ player.x = PLAYER_X_FROM_104_1;
+ player.facing = FACING_NORTHWEST;
+ }
+
+ player.y = PLAYER_Y_FROM_104;
+ }
+
+ section_1_music();
+}
+
+void room_108_daemon() {
+ if (local->anim_0_running) {
+ handle_animation_char();
+ }
+
+ if ((global[walker_converse] == CONVERSE_HAND_WAVE) ||
+ (global[walker_converse] == CONVERSE_HAND_WAVE_2)) {
+ ++local->converse_counter;
+ if (local->converse_counter > 200) {
+ global[walker_converse] = imath_random(CONVERSE_LEAN, CONVERSE_HAND_CHIN);
+ }
+ }
+}
+
+static void process_conversation_charles() {
+ switch (player_verb) {
+ case conv002_sayone_abc:
+ case conv002_nomore_first:
+ case conv002_saytwo_abc:
+ global[walker_converse] = CONVERSE_NONE;
+ conv_me_trigger(ROOM_108_CHAR_WRITE);
+ if (player_verb == conv002_saytwo_abc) {
+ global[charles_name_is_known] = YES_AND_END_CONV;
+ }
+ break;
+
+ case conv002_answers_job:
+ conv_you_trigger(ROOM_108_CHAR_BOTH_HANDS_UP);
+ local->max_talk_count = 35;
+ break;
+
+ case conv002_interrogate_chandelier:
+ conv_you_trigger(ROOM_108_CHAR_POINT_UP);
+ local->max_talk_count = 35;
+ break;
+
+ case conv002_interrogate_giry:
+ conv_you_trigger(ROOM_108_CHAR_POINT_RIGHT);
+ break;
+
+ case conv002_interrogate_phantom:
+ conv_you_trigger(ROOM_108_CHAR_OH_MY);
+ break;
+
+ case conv002_answers_please:
+ case conv002_answers_house:
+ case conv002_answers_go_on:
+ case conv002_answers_prison:
+ case conv002_answers_building:
+ case conv002_answers_catacombs:
+ case conv002_interrogate_mishap:
+ local->max_talk_count = 35;
+ break;
+
+ case conv002_questions_one:
+ if (!global[charles_name_is_known]) {
+ kernel_delete_dynamic(local->dynamic_char);
+ local->dynamic_char = kernel_add_dynamic(words_Charles, words_walk_to, SYNTAX_SINGULAR_MASC, KERNEL_NONE,
+ DYN_CHAR_X, DYN_CHAR_Y, DYN_CHAR_XS, DYN_CHAR_YS);
+ kernel_dynamic_hot[local->dynamic_char].prep = PREP_ON;
+ kernel_dynamic_walk(local->dynamic_char, DYN_CHAR_WALK_TO_X, DYN_CHAR_WALK_TO_Y, FACING_NORTHEAST);
+ global[charles_name_is_known] = true;
+ }
+ break;
+
+ default:
+ local->max_talk_count = 15;
+ break;
+ }
+
+ switch (kernel.trigger) {
+ /* ==================== Process talking triggers ================ */
+ case ROOM_108_CHAR_BOTH_HANDS_UP:
+ local->char_action = CONV2_CHAR_BOTH_HANDS_UP;
+ break;
+
+ case ROOM_108_CHAR_POINT_UP:
+ local->char_action = CONV2_CHAR_POINT_UP;
+ break;
+
+ case ROOM_108_CHAR_POINT_RIGHT:
+ local->char_action = CONV2_CHAR_POINT_RIGHT;
+ break;
+
+ case ROOM_108_CHAR_OH_MY:
+ local->char_action = CONV2_CHAR_OH_MY;
+ break;
+
+ case ROOM_108_CHAR_WRITE:
+ local->char_action = CONV2_CHAR_WRITE;
+ break;
+
+ case ROOM_108_CHAR_TALK:
+ local->char_action = CONV2_CHAR_TALK;
+ global[walker_converse] = imath_random(CONVERSE_LEAN, CONVERSE_HAND_CHIN);
+ break;
+
+ case ROOM_108_CHAR_SHUT_UP:
+ global[walker_converse] = imath_random(CONVERSE_HAND_WAVE, CONVERSE_HAND_WAVE_2);
+ local->converse_counter = 0;
+ local->char_action = CONV2_CHAR_SHUT_UP;
+ break;
+ }
+
+ /* ==================== Set up me and you triggers ============== */
+
+ if ((player_verb != conv002_nomore_first) &&
+ (player_verb != conv002_saytwo_abc) &&
+ (player_verb != conv002_sayone_abc) &&
+ (player_verb != conv002_interrogate_chandelier) &&
+ (player_verb != conv002_interrogate_giry) &&
+ (player_verb != conv002_interrogate_phantom) &&
+ (player_verb != conv002_answers_job) &&
+ (local->char_action != CONV2_CHAR_WRITE) &&
+ (player_verb != conv002_sayone_abc)) {
+ conv_you_trigger(ROOM_108_CHAR_TALK);
+ conv_me_trigger(ROOM_108_CHAR_SHUT_UP);
+ }
+
+ local->char_talk_count = 0;
+ local->char_shut_up_count = 40; /* so in daemon it will pick a new shut up movement */
+ local->did_raise_hand = false;
+}
+
+void room_108_parser() {
+ if (conv_control.running == CONV_CHARLES) {
+ process_conversation_charles();
+ goto handled;
+ }
+
+ if ((player_said_2(talk_to, gentleman)) ||
+ (player_said_2(talk_to, Charles))) {
+ local->char_action = CONV2_CHAR_TURN_TO_RAOUL;
+ player.commands_allowed = false;
+ goto handled;
+ }
+
+ if (player_said_2(walk_onto, stage)) {
+ new_room = 104;
+ goto handled;
+ }
+
+ if (player_said_2(walk, backstage)) {
+ new_room = 106;
+ goto handled;
+ }
+
+ if (player.look_around) {
+ text_show(text_108_10);
+ goto handled;
+ }
+
+ if (player_said_1(look) || player_said_1(look_at)) {
+ if (player_said_1(wall)) {
+ text_show(text_107_30); /* shared look-at-wall response */
+ goto handled;
+ }
+
+ if (player_said_1(stage)) {
+ text_show(text_108_11);
+ goto handled;
+ }
+
+ if (player_said_1(_in_two_)) {
+ text_show(text_108_12);
+ goto handled;
+ }
+
+ if (player_said_1(_in_one_)) {
+ text_show(text_108_13);
+ goto handled;
+ }
+
+ if (player_said_1(proscenium_arch)) {
+ text_show(text_108_14);
+ goto handled;
+ }
+
+ if (player_said_1(act_curtain)) {
+ text_show(text_108_15);
+ goto handled;
+ }
+
+ if (player_said_1(leg)) {
+ text_show(text_108_16);
+ goto handled;
+ }
+
+ if (player_said_1(cyclorama)) {
+ text_show(text_108_17);
+ goto handled;
+ }
+
+ if (player_said_1(flats)) {
+ text_show(text_108_18);
+ goto handled;
+ }
+
+ if (player_said_1(stagemanager_s_post)) {
+ if (global[current_year] == 1993) {
+ text_show(text_108_19);
+ } else {
+ text_show(text_108_20);
+ }
+ goto handled;
+ }
+
+ if (player_said_1(stool)) {
+ text_show(text_108_21);
+ goto handled;
+ }
+
+ if (player_said_1(backstage)) {
+ text_show(text_108_22);
+ goto handled;
+ }
+
+ if (player_said_1(stage)) { /* Note: second 'stage' check â unreachable in original */
+ text_show(text_108_23);
+ goto handled;
+ }
+
+ if (player_said_1(headset)) {
+ text_show(text_108_24);
+ goto handled;
+ }
+
+ if (player_said_1(wall)) { /* Note: second 'wall' check â unreachable in original */
+ text_show(text_108_26);
+ goto handled;
+ }
+
+ if (player_said_1(Charles) || player_said_1(gentleman)) {
+ text_show(text_108_27);
+ goto handled;
+ }
+ }
+
+ if (player_said_2(take, Charles) || player_said_2(take, gentleman)) {
+ text_show(text_108_28);
+ goto handled;
+ }
+
+ if (player_said_2(take, headset)) {
+ text_show(text_108_25);
+ goto handled;
+ }
+
+ if (player_said_2(take, stool)) {
+ if (global[current_year] == 1993) {
+ text_show(text_108_29);
+ goto handled;
+ }
+ }
+
+ if (player_said_2(talk_to, headset)) {
+ text_show(text_108_30);
+ goto handled;
+ }
+
+ goto done;
+
+handled:
+ player.command_ready = false;
+
+done:
+ ;
+}
+
+void room_108_preload() {
+ room_init_code_pointer = room_108_init;
+ room_pre_parser_code_pointer = NULL;
+ room_parser_code_pointer = room_108_parser;
+ room_daemon_code_pointer = room_108_daemon;
+
+ section_1_walker();
+ section_1_interface();
+
+ if (global[current_year] == 1993) {
+ kernel_initial_variant = 1;
+ }
+
+ vocab_make_active(words_gentleman);
+ vocab_make_active(words_Charles);
+}
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/rooms/room108.h b/engines/mads/madsv2/phantom/rooms/room108.h
new file mode 100644
index 00000000000..b36e09c7904
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room108.h
@@ -0,0 +1,147 @@
+/* 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/>.
+ *
+ */
+
+/* room108.mac by Paul Lahaise 8-Jan-93 */
+
+#ifndef MADS_PHANTOM_ROOM108_H
+#define MADS_PHANTOM_ROOM108_H
+
+#include "mads/madsv2/phantom/rooms/section1.h"
+#include "mads/madsv2/phantom/global.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+#define local ((Scratch *)(&game.scratch[0]))
+#define ss local->sprite
+#define seq local->sequence
+#define aa local->animation
+
+typedef struct { /* Room local variables */
+
+ int sprite[15]; /* Sprite series handles */
+ int sequence[15]; /* Sequence handles */
+ int animation[4]; /* Animation handles */
+ int anim_0_running;
+
+ int char_action; /* action Charles is going to perform */
+ int char_frame;
+ int char_talk_count;
+ int char_shut_up_count;
+ int dynamic_char; /* Dynamic HS for Charles */
+ int prev_shut_up_frame;
+ int max_talk_count; /* max talking count for Charles */
+ int did_raise_hand; /* true, when if talking, did raise hand */
+ int converse_counter; /* counter for talking displacements */
+
+} Scratch;
+
+
+/* ========================= Sprite Series ========================= */
+
+#define fx_1993 0 /* rm108z */
+
+
+/* ========================= Conversation ========================== */
+
+#define CONV_CHARLES 2
+
+
+/* ========================= Charles (Conv 2) action states ======== */
+
+#define CONV2_CHAR_SHUT_UP 0
+#define CONV2_CHAR_TALK 1
+#define CONV2_CHAR_WRITE 2
+#define CONV2_CHAR_OH_MY 3
+#define CONV2_CHAR_POINT_UP 4
+#define CONV2_CHAR_BOTH_HANDS_UP 5
+#define CONV2_CHAR_TURN_TO_RAOUL 6
+#define CONV2_CHAR_POINT_RIGHT 7
+
+
+/* ========================= Triggers ============================== */
+
+#define ROOM_108_CHAR_TALK 60
+#define ROOM_108_CHAR_SHUT_UP 62
+#define ROOM_108_CHAR_WRITE 64
+#define ROOM_108_CHAR_BOTH_HANDS_UP 66
+#define ROOM_108_CHAR_POINT_UP 68
+#define ROOM_108_CHAR_POINT_RIGHT 70
+#define ROOM_108_CHAR_OH_MY 72
+
+
+/* ========================= Player positions ====================== */
+
+#define PLAYER_X_FROM_106 48
+#define PLAYER_Y_FROM_106 81
+
+#define WALK_TO_X_FROM_106 71
+#define WALK_TO_Y_FROM_106 76
+
+#define PLAYER_X_FROM_104_1 243
+#define PLAYER_X_FROM_104_2 185
+#define PLAYER_X_FROM_104_3 124
+#define PLAYER_Y_FROM_104 143
+
+
+/* ========================= Dynamic hotspot â stool (1993) ======== */
+
+#define STOOL_X 250
+#define STOOL_Y 68
+#define STOOL_X_SIZE 8
+#define STOOL_Y_SIZE 21
+#define STOOL_WALK_X 253
+#define STOOL_WALK_Y 75
+
+
+/* ========================= Dynamic hotspot â wall (1881) ========= */
+
+#define WALL_X 258
+#define WALL_Y 58
+#define WALL_X_SIZE 6
+#define WALL_Y_SIZE 10
+#define WALL_WALK_X 236
+#define WALL_WALK_Y 69
+
+
+/* ========================= Dynamic hotspot â Charles ============= */
+
+#define DYN_CHAR_X 253
+#define DYN_CHAR_Y 52
+#define DYN_CHAR_XS 15
+#define DYN_CHAR_YS 34
+#define DYN_CHAR_WALK_TO_X 235
+#define DYN_CHAR_WALK_TO_Y 102
+
+
+extern void room_108_init(void);
+extern void room_108_daemon(void);
+extern void room_108_parser(void);
+extern void room_108_preload(void);
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index d63c91db600..9194480c5e3 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -129,6 +129,7 @@ MODULE_OBJS += \
madsv2/phantom/rooms/room105.o \
madsv2/phantom/rooms/room106.o \
madsv2/phantom/rooms/room107.o \
+ madsv2/phantom/rooms/room108.o \
madsv2/phantom/phantom.o \
madsv2/phantom/conv.o \
madsv2/phantom/main_menu.o \
Commit: 75ecc6136e6b09c3de08b754694a6ba698e0fe7f
https://github.com/scummvm/scummvm/commit/75ecc6136e6b09c3de08b754694a6ba698e0fe7f
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:41+10:00
Commit Message:
MADS: PHANTOM: Added room 109
Changed paths:
A engines/mads/madsv2/phantom/rooms/room109.cpp
A engines/mads/madsv2/phantom/rooms/room109.h
engines/mads/madsv2/phantom/mads/words.h
engines/mads/module.mk
diff --git a/engines/mads/madsv2/phantom/mads/words.h b/engines/mads/madsv2/phantom/mads/words.h
index 07a4bf15b16..8f25db77104 100644
--- a/engines/mads/madsv2/phantom/mads/words.h
+++ b/engines/mads/madsv2/phantom/mads/words.h
@@ -38,6 +38,7 @@ enum {
words_bear_prop = 22,
words_cable = 26,
words_carton = 28,
+ words_ceiling = 30,
words_circular_staircase = 32,
words_climb_down = 33,
words_climb_through = 35,
@@ -58,10 +59,12 @@ enum {
words_garbage_can = 75,
words_graffiti = 76,
words_hemp = 78,
+ words_hole = 79,
words_house = 80,
words_jump_into = 82,
words_junk = 84,
words_key = 85,
+ words_lamp = 86,
words_lantern = 87,
words_leg = 90,
words_light_fixture = 92,
@@ -80,6 +83,7 @@ enum {
words_props = 118,
words_proscenium_arch = 119,
words_purchase_lines = 120,
+ words_railing = 121,
words_red_frame = 123,
words_sandbag = 127,
words_seats = 129,
@@ -89,6 +93,7 @@ enum {
words_stage_right = 135,
words_stagemanager_s_post = 136,
words_stair_unit = 137,
+ words_staircase = 138,
words_stool = 140,
words_thunder_machine = 145,
words_trap_ceiling = 147,
diff --git a/engines/mads/madsv2/phantom/rooms/room109.cpp b/engines/mads/madsv2/phantom/rooms/room109.cpp
new file mode 100644
index 00000000000..98ada88a7f7
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room109.cpp
@@ -0,0 +1,557 @@
+/* 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 "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/camera.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/imath.h"
+#include "mads/madsv2/core/text.h"
+#include "mads/madsv2/core/inter.h"
+#include "mads/madsv2/core/object.h"
+#include "mads/madsv2/core/sound.h"
+#include "mads/madsv2/phantom/global.h"
+#include "mads/madsv2/phantom/mads/inventory.h"
+#include "mads/madsv2/phantom/mads/words.h"
+#include "mads/madsv2/phantom/mads/sounds.h"
+#include "mads/madsv2/phantom/mads/text.h"
+#include "mads/madsv2/phantom/rooms/section1.h"
+#include "mads/madsv2/phantom/rooms/room109.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+void room_109_init() {
+ local->anim_0_running = false;
+ local->anim_1_running = false;
+ local->anim_2_running = false;
+ local->anim_3_running = false;
+
+ /* ==================== Load Sprite Series ====================== */
+
+ ss[fx_top_door] = kernel_load_series(kernel_name('x', 0), false);
+ ss[fx_middle_door] = kernel_load_series(kernel_name('x', 2), false);
+ ss[fx_take_6] = kernel_load_series("*RDR_6", false);
+
+
+ /* ================ Start Flame Sprites or Lightbulbs =========== */
+
+ if (global[current_year] == 1881) {
+
+ ss[fx_top_flame] = kernel_load_series(kernel_name('x', 1), false);
+ ss[fx_middle_flame] = kernel_load_series(kernel_name('x', 3), false);
+ ss[fx_bottom_flame] = kernel_load_series(kernel_name('x', 4), false);
+
+ kernel_flip_hotspot(words_light_fixture, false);
+ seq[fx_top_flame] = kernel_seq_stamp(ss[fx_top_flame], false, 1);
+ kernel_seq_depth(seq[fx_top_flame], 14);
+ seq[fx_middle_flame] = kernel_seq_stamp(ss[fx_middle_flame], false, 1);
+ kernel_seq_depth(seq[fx_middle_flame], 14);
+ seq[fx_bottom_flame] = kernel_seq_stamp(ss[fx_bottom_flame], false, 1);
+ kernel_seq_depth(seq[fx_bottom_flame], 14);
+ kernel_timing_trigger(1, ROOM_109_CHANGE_LANTERN_FLAME);
+
+ } else { /* current year is 1993 */
+
+ ss[fx_top_lester] = kernel_load_series(kernel_name('z', 0), false);
+ ss[fx_middle_lester] = kernel_load_series(kernel_name('z', 1), false);
+ ss[fx_bottom_lester] = kernel_load_series(kernel_name('z', 2), false);
+
+ kernel_flip_hotspot(words_lamp, false);
+ seq[fx_top_lester] = kernel_seq_stamp(ss[fx_top_lester], false, 1);
+ seq[fx_middle_lester] = kernel_seq_stamp(ss[fx_middle_lester], false, 1);
+ seq[fx_bottom_lester] = kernel_seq_stamp(ss[fx_bottom_lester], false, 1);
+ }
+
+
+ /* ====================== Previous Rooms ======================== */
+
+ if (previous_room == 106) {
+ player.x = PLAYER_X_FROM_106;
+ player.y = PLAYER_Y_FROM_106;
+ player.facing = FACING_NORTHEAST;
+ camera_jump_to(0, BOTTOM_FLOOR);
+ kernel_room_scale(467, 95, 442, 78);
+ local->on_floor = 1;
+
+ } else if (previous_room == 111) {
+ if (global[leave_angel_music_on]) {
+ global[leave_angel_music_on] = false;
+ section_1_music();
+ }
+ player.x = PLAYER_X_FROM_111;
+ player.y = PLAYER_Y_FROM_111;
+ player.facing = FACING_EAST;
+ player_walk(WALK_TO_X_FROM_111, WALK_TO_Y_FROM_111, FACING_EAST);
+ player_walk_trigger(ROOM_109_TOP_DOOR_CLOSES);
+ player.commands_allowed = false;
+ camera_jump_to(0, TOP_FLOOR);
+ kernel_room_scale(155, 95, 130, 78);
+ seq[fx_top_door] = kernel_seq_stamp(ss[fx_top_door], false, 3);
+ kernel_seq_depth(seq[fx_top_door], 14);
+ local->on_floor = 3;
+
+ } else if ((previous_room == 110) || (previous_room != KERNEL_RESTORING_GAME)) {
+ player.x = PLAYER_X_FROM_110;
+ player.y = PLAYER_Y_FROM_110;
+ player.facing = FACING_EAST;
+ player_walk(WALK_TO_X_FROM_110, WALK_TO_Y_FROM_110, FACING_EAST);
+ player_walk_trigger(ROOM_109_MIDDLE_DOOR_CLOSES);
+ player.commands_allowed = false;
+ camera_jump_to(0, MIDDLE_FLOOR);
+ kernel_room_scale(311, 95, 286, 78);
+ seq[fx_middle_door] = kernel_seq_stamp(ss[fx_middle_door], false, 3);
+ kernel_seq_depth(seq[fx_middle_door], 14);
+ local->on_floor = 2;
+
+ } else if (previous_room == KERNEL_RESTORING_GAME) {
+ if (local->on_floor == 2) {
+ camera_jump_to(0, MIDDLE_FLOOR);
+ kernel_room_scale(311, 95, 286, 78);
+ } else if (local->on_floor == 3) {
+ camera_jump_to(0, TOP_FLOOR);
+ kernel_room_scale(155, 95, 130, 78);
+ } else {
+ camera_jump_to(0, BOTTOM_FLOOR);
+ kernel_room_scale(467, 95, 442, 78);
+ }
+ }
+
+ section_1_music();
+}
+
+void room_109_daemon() {
+ int flame_frame; /* Random # for lamp frame will go here */
+ int flame_delay; /* Random # for flame delay will go here */
+
+ if (local->anim_0_running) {
+ if (kernel_anim[aa[0]].frame == 80) {
+ camera_pan_to(&camera_y, MIDDLE_FLOOR);
+ }
+ }
+
+ if (local->anim_1_running) {
+ if (kernel_anim[aa[1]].frame == 80) {
+ camera_pan_to(&camera_y, TOP_FLOOR);
+ }
+ }
+
+ if (local->anim_2_running) {
+ if (kernel_anim[aa[2]].frame == 7) {
+ camera_pan_to(&camera_y, BOTTOM_FLOOR);
+ }
+ }
+
+ if (local->anim_3_running) {
+ if (kernel_anim[aa[3]].frame == 14) {
+ camera_pan_to(&camera_y, MIDDLE_FLOOR);
+ }
+ }
+
+ /* ========= Close the top door when player enters top floor ===== */
+
+ switch (kernel.trigger) {
+ case ROOM_109_TOP_DOOR_CLOSES:
+ kernel_seq_delete(seq[fx_top_door]);
+ seq[fx_top_door] = kernel_seq_backward(ss[fx_top_door], false, 8, 0, 0, 1);
+ kernel_seq_depth(seq[fx_top_door], 14);
+ kernel_seq_range(seq[fx_top_door], 1, 3);
+ kernel_seq_trigger(seq[fx_top_door],
+ KERNEL_TRIGGER_EXPIRE, 0, ROOM_109_TOP_DOOR_CLOSES + 1);
+ break;
+
+ case ROOM_109_TOP_DOOR_CLOSES + 1:
+ sound_play(N_DoorCloses);
+ player.commands_allowed = true;
+ break;
+ }
+
+
+ /* ==== Close middle door when player enters middle floor ======= */
+
+ switch (kernel.trigger) {
+ case ROOM_109_MIDDLE_DOOR_CLOSES:
+ kernel_seq_delete(seq[fx_middle_door]);
+ seq[fx_middle_door] = kernel_seq_backward(ss[fx_middle_door], false, 8, 0, 0, 1);
+ kernel_seq_depth(seq[fx_middle_door], 14);
+ kernel_seq_range(seq[fx_middle_door], 1, 3);
+ kernel_seq_trigger(seq[fx_middle_door],
+ KERNEL_TRIGGER_EXPIRE, 0, ROOM_109_MIDDLE_DOOR_CLOSES + 1);
+ break;
+
+ case ROOM_109_MIDDLE_DOOR_CLOSES + 1:
+ sound_play(N_DoorCloses);
+ player.commands_allowed = true;
+ break;
+ }
+
+
+ /* ========= Randomly flicker the lamps on ALL walls ============ */
+
+ switch (kernel.trigger) {
+ case ROOM_109_CHANGE_LANTERN_FLAME:
+ flame_frame = imath_random(1, 3);
+ flame_delay = imath_random(4, 7);
+ kernel_seq_delete(seq[fx_top_flame]);
+ kernel_seq_delete(seq[fx_middle_flame]);
+ kernel_seq_delete(seq[fx_bottom_flame]);
+
+ seq[fx_top_flame] = kernel_seq_stamp(ss[fx_top_flame], false, flame_frame);
+ kernel_seq_depth(seq[fx_top_flame], 14);
+
+ seq[fx_middle_flame] = kernel_seq_stamp(ss[fx_middle_flame], false, flame_frame);
+ kernel_seq_depth(seq[fx_middle_flame], 14);
+
+ seq[fx_bottom_flame] = kernel_seq_stamp(ss[fx_bottom_flame], false, flame_frame);
+ kernel_seq_depth(seq[fx_bottom_flame], 14);
+
+ kernel_timing_trigger(flame_delay, ROOM_109_CHANGE_LANTERN_FLAME);
+ break;
+ }
+}
+
+void room_109_pre_parser() {
+ if (player_said_2(open, door)) {
+ if (local->on_floor == 3) {
+ player_walk(WALK_TO_X_FROM_111, WALK_TO_Y_FROM_111, FACING_WEST);
+ } else if (local->on_floor == 2) {
+ player_walk(WALK_TO_X_FROM_110, WALK_TO_Y_FROM_110, FACING_WEST);
+ }
+ }
+}
+
+void room_109_parser() {
+ int temp; /* For synching purposes */
+
+ if (player_said_2(walk, backstage)) {
+ new_room = 106;
+ goto handled;
+ }
+
+ if (player_said_2(climb_up, staircase)) {
+ if (local->on_floor == 2) {
+ switch (kernel.trigger) {
+ case 0:
+ player_walk(START_CLIMB_MIDDLE_X, START_CLIMB_MIDDLE_Y, FACING_EAST);
+ player_walk_trigger(1);
+ break;
+
+ case 1:
+ local->anim_1_running = true;
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ aa[1] = kernel_run_animation(kernel_name('w', 2), 2);
+ kernel_synch(KERNEL_ANIM, aa[1], KERNEL_PLAYER, 0);
+ break;
+
+ case 2:
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_ANIM, aa[1]);
+ kernel_room_scale(155, 95, 130, 78);
+ local->anim_1_running = false;
+ player.walker_visible = true;
+ player.x = END_CLIMB_MIDDLE_FLOOR_X;
+ player.y = END_CLIMB_MIDDLE_FLOOR_Y;
+ player_walk(END_CLIMB_MIDDLE_FLOOR_X + 20, END_CLIMB_MIDDLE_FLOOR_Y + 6, FACING_SOUTHWEST);
+ player_walk_trigger(3);
+ break;
+
+ case 3:
+ player.commands_allowed = true;
+ local->on_floor = 3;
+ break;
+ }
+
+ } else if (local->on_floor == 1) {
+ switch (kernel.trigger) {
+ case 0:
+ player_walk(START_CLIMB_BOTTOM_X, START_CLIMB_BOTTOM_Y, FACING_EAST);
+ player_walk_trigger(1);
+ break;
+
+ case 1:
+ local->anim_0_running = true;
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ aa[0] = kernel_run_animation(kernel_name('w', 1), 2);
+ kernel_synch(KERNEL_ANIM, aa[0], KERNEL_PLAYER, 0);
+ break;
+
+ case 2:
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_ANIM, aa[0]);
+ kernel_room_scale(311, 95, 286, 78);
+ local->anim_0_running = false;
+ player.walker_visible = true;
+ player.x = END_CLIMB_BOTTOM_FLOOR_X;
+ player.y = END_CLIMB_BOTTOM_FLOOR_Y;
+ player_walk(END_CLIMB_BOTTOM_FLOOR_X + 25, END_CLIMB_BOTTOM_FLOOR_Y + 4, FACING_SOUTHWEST);
+ player_walk_trigger(3);
+ break;
+
+ case 3:
+ player.commands_allowed = true;
+ local->on_floor = 2;
+ break;
+ }
+ }
+ goto handled;
+ }
+
+ if (player_said_2(climb_down, staircase)) {
+ if (local->on_floor == 2) {
+ switch (kernel.trigger) {
+ case 0:
+ player_walk(START_DOWN_MIDDLE_X + 18, START_DOWN_MIDDLE_Y - 1, FACING_WEST);
+ player_walk_trigger(1);
+ break;
+
+ case 1:
+ player_walk(START_DOWN_MIDDLE_X, START_DOWN_MIDDLE_Y, FACING_WEST);
+ player_walk_trigger(2);
+ break;
+
+ case 2:
+ local->anim_2_running = true;
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ aa[2] = kernel_run_animation(kernel_name('w', 3), 3);
+ kernel_synch(KERNEL_ANIM, aa[2], KERNEL_PLAYER, 0);
+ break;
+
+ case 3:
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_ANIM, aa[2]);
+ kernel_room_scale(467, 95, 442, 78);
+ local->anim_2_running = false;
+ player.walker_visible = true;
+ player.x = END_DOWN_MIDDLE_FLOOR_X;
+ player.y = END_DOWN_MIDDLE_FLOOR_Y;
+ player_walk(END_DOWN_MIDDLE_FLOOR_X - 25, END_DOWN_MIDDLE_FLOOR_Y, FACING_SOUTHEAST);
+ player_walk_trigger(4);
+ break;
+
+ case 4:
+ player.commands_allowed = true;
+ local->on_floor = 1;
+ break;
+ }
+
+ } else if (local->on_floor == 3) {
+ switch (kernel.trigger) {
+ case 0:
+ player_walk(START_DOWN_TOP_X + 18, START_DOWN_TOP_Y - 1, FACING_WEST);
+ player_walk_trigger(1);
+ break;
+
+ case 1:
+ player_walk(START_DOWN_TOP_X, START_DOWN_TOP_Y, FACING_WEST);
+ player_walk_trigger(2);
+ break;
+
+ case 2:
+ local->anim_3_running = true;
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ aa[3] = kernel_run_animation(kernel_name('w', 4), 3);
+ kernel_synch(KERNEL_ANIM, aa[3], KERNEL_PLAYER, 0);
+ break;
+
+ case 3:
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_ANIM, aa[3]);
+ kernel_room_scale(311, 95, 286, 78);
+ local->anim_3_running = false;
+ player.walker_visible = true;
+ player.x = END_DOWN_TOP_FLOOR_X;
+ player.y = END_DOWN_TOP_FLOOR_Y;
+ player_walk(END_DOWN_TOP_FLOOR_X - 19, END_DOWN_TOP_FLOOR_Y - 2, FACING_SOUTHEAST);
+ player_walk_trigger(4);
+ break;
+
+ case 4:
+ player.commands_allowed = true;
+ local->on_floor = 2;
+ break;
+ }
+ }
+ goto handled;
+ }
+
+ if (player_said_2(walk_through, door) || player_said_2(open, door) || kernel.trigger) {
+ switch (kernel.trigger) {
+ case 0:
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_take_6] = kernel_seq_pingpong(ss[fx_take_6], true, 5, 0, 0, 2);
+ kernel_seq_range(seq[fx_take_6], KERNEL_FIRST, KERNEL_LAST);
+ kernel_seq_player(seq[fx_take_6], true);
+ kernel_seq_trigger(seq[fx_take_6], KERNEL_TRIGGER_EXPIRE, 0, 2);
+ kernel_seq_trigger(seq[fx_take_6], KERNEL_TRIGGER_SPRITE, 4, ROOM_109_DOOR_OPENS);
+ break;
+
+ case ROOM_109_DOOR_OPENS:
+ sound_play(N_DoorOpens);
+ if (local->on_floor == 3) {
+ seq[fx_top_door] = kernel_seq_forward(ss[fx_top_door], false, 8, 0, 0, 1);
+ kernel_seq_depth(seq[fx_top_door], 14);
+ kernel_seq_range(seq[fx_top_door], 1, 3);
+ kernel_seq_trigger(seq[fx_top_door],
+ KERNEL_TRIGGER_EXPIRE, 0, ROOM_109_DOOR_OPENS + 1);
+ } else if (local->on_floor == 2) {
+ seq[fx_middle_door] = kernel_seq_forward(ss[fx_middle_door], false, 8, 0, 0, 1);
+ kernel_seq_depth(seq[fx_middle_door], 14);
+ kernel_seq_range(seq[fx_middle_door], 1, 3);
+ kernel_seq_trigger(seq[fx_middle_door],
+ KERNEL_TRIGGER_EXPIRE, 0, ROOM_109_DOOR_OPENS + 1);
+ }
+ break;
+
+ case ROOM_109_DOOR_OPENS + 1:
+ if (local->on_floor == 3) {
+ temp = seq[fx_top_door];
+ seq[fx_top_door] = kernel_seq_stamp(ss[fx_top_door], false, 3);
+ kernel_synch(KERNEL_SERIES, seq[fx_top_door], KERNEL_SERIES, temp);
+ kernel_seq_depth(seq[fx_top_door], 14);
+ } else if (local->on_floor == 2) {
+ temp = seq[fx_middle_door];
+ seq[fx_middle_door] = kernel_seq_stamp(ss[fx_middle_door], false, 3);
+ kernel_synch(KERNEL_SERIES, seq[fx_middle_door], KERNEL_SERIES, temp);
+ kernel_seq_depth(seq[fx_middle_door], 14);
+ }
+ break;
+
+ case 2:
+ player.walker_visible = true;
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_SERIES, seq[fx_take_6]);
+ if (local->on_floor == 3) {
+ player_walk(WALK_TO_X_OPEN_TOP_DOOR, WALK_TO_Y_OPEN_TOP_DOOR, FACING_WEST);
+ } else if (local->on_floor == 2) {
+ player_walk(WALK_TO_X_OPEN_MIDDLE_DOOR, WALK_TO_Y_OPEN_MIDDLE_DOOR, FACING_WEST);
+ }
+ kernel_timing_trigger(THREE_SECONDS, 3);
+ break;
+
+ case 3:
+ if (local->on_floor == 3) {
+ new_room = 111;
+ } else if (local->on_floor == 2) {
+ new_room = 110;
+ }
+ break;
+ }
+ goto handled;
+ }
+
+ if (player.look_around) {
+ text_show(text_109_10);
+ goto handled;
+ }
+
+ if (player_said_1(look) || player_said_1(look_at)) {
+
+ if (player_said_1(staircase)) {
+ if (local->on_floor == 1) {
+ text_show(text_109_11);
+ } else if (local->on_floor == 2) {
+ text_show(text_109_21);
+ } else if (local->on_floor == 3) {
+ text_show(text_109_22);
+ }
+ goto handled;
+ }
+
+ if (player_said_1(floor)) {
+ text_show(text_109_12);
+ goto handled;
+ }
+
+ if (player_said_1(backstage)) {
+ text_show(text_109_13);
+ goto handled;
+ }
+
+ if (player_said_1(door)) {
+ text_show(text_109_14);
+ goto handled;
+ }
+
+ if (player_said_1(railing)) {
+ text_show(text_109_15);
+ goto handled;
+ }
+
+ if (player_said_1(wall)) {
+ text_show(text_109_16);
+ goto handled;
+ }
+
+ if (player_said_1(light_fixture)) {
+ text_show(text_109_17);
+ goto handled;
+ }
+
+ if (player_said_1(lamp)) {
+ text_show(text_109_18);
+ goto handled;
+ }
+
+ if (player_said_1(hole)) {
+ text_show(text_109_19);
+ goto handled;
+ }
+
+ if (player_said_1(ceiling)) {
+ text_show(text_109_20);
+ goto handled;
+ }
+ }
+
+ if (player_said_2(take, lamp)) {
+ text_show(text_109_24);
+ goto handled;
+ }
+
+ if (player_said_2(close, door)) {
+ text_show(text_109_23);
+ goto handled;
+ }
+
+ goto done;
+
+handled:
+ player.command_ready = false;
+
+done:
+ ;
+}
+
+void room_109_preload() {
+ room_init_code_pointer = room_109_init;
+ room_pre_parser_code_pointer = room_109_pre_parser;
+ room_parser_code_pointer = room_109_parser;
+ room_daemon_code_pointer = room_109_daemon;
+
+ section_1_walker();
+ section_1_interface();
+}
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/rooms/room109.h b/engines/mads/madsv2/phantom/rooms/room109.h
new file mode 100644
index 00000000000..69d039b9577
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room109.h
@@ -0,0 +1,147 @@
+/* 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/>.
+ *
+ */
+
+/* room109.mac by Paul Lahaise 7-Jan-93 */
+
+#ifndef MADS_PHANTOM_ROOM109_H
+#define MADS_PHANTOM_ROOM109_H
+
+#include "mads/madsv2/phantom/rooms/section1.h"
+#include "mads/madsv2/phantom/global.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+#define local ((Scratch *)(&game.scratch[0]))
+#define ss local->sprite
+#define seq local->sequence
+#define aa local->animation
+
+typedef struct { /* Room local variables */
+
+ int sprite[15]; /* Sprite series handles */
+ int sequence[15]; /* Sequence handles */
+ int animation[4]; /* Animation handles */
+ int on_floor; /* Which floor are we on? 3=top, 1=bottom */
+ int anim_0_running;
+ int anim_1_running;
+ int anim_2_running;
+ int anim_3_running;
+
+} Scratch;
+
+
+/* ========================= Sprite Series ========================= */
+
+#define fx_top_door 0 /* rm109x0 */
+#define fx_middle_door 1 /* rm109x2 */
+#define fx_top_flame 2 /* rm109x1 */
+#define fx_middle_flame 3 /* rm109x3 */
+#define fx_bottom_flame 4 /* rm109x4 */
+#define fx_top_lester 5 /* rm109z0 */
+#define fx_middle_lester 6 /* rm109z1 */
+#define fx_bottom_lester 7 /* rm109z2 */
+#define fx_take_6 8 /* rdr_6 */
+
+
+/* ========================= Triggers ============================== */
+
+#define ROOM_109_TOP_DOOR_CLOSES 60
+#define ROOM_109_MIDDLE_DOOR_CLOSES 65
+#define ROOM_109_CHANGE_LANTERN_FLAME 70
+#define ROOM_109_DOOR_OPENS 75
+
+
+/* ========================= Player positions ====================== */
+
+#define PLAYER_X_FROM_106 31
+#define PLAYER_Y_FROM_106 459
+
+#define PLAYER_X_FROM_111 4
+#define PLAYER_Y_FROM_111 136
+
+#define PLAYER_X_FROM_110 3
+#define PLAYER_Y_FROM_110 292
+
+#define WALK_TO_X_FROM_111 32
+#define WALK_TO_Y_FROM_111 138
+
+#define WALK_TO_X_FROM_110 31
+#define WALK_TO_Y_FROM_110 295
+
+
+/* ========================= Camera floors ========================= */
+
+#define TOP_FLOOR 0 /* for camera_jump_to */
+#define MIDDLE_FLOOR 156 /* for camera_jump_to */
+#define BOTTOM_FLOOR 312 /* for camera_jump_to */
+
+
+/* ========================= Door approach positions =============== */
+
+#define WALK_TO_X_OPEN_TOP_DOOR 2
+#define WALK_TO_Y_OPEN_TOP_DOOR 131
+
+#define WALK_TO_X_OPEN_MIDDLE_DOOR 2
+#define WALK_TO_Y_OPEN_MIDDLE_DOOR 281
+
+
+/* ========================= Climb / descend positions ============= */
+
+#define END_CLIMB_BOTTOM_FLOOR_X 264
+#define END_CLIMB_BOTTOM_FLOOR_Y 295
+
+#define START_CLIMB_BOTTOM_X 58
+#define START_CLIMB_BOTTOM_Y 452
+
+#define END_CLIMB_MIDDLE_FLOOR_X 261
+#define END_CLIMB_MIDDLE_FLOOR_Y 137
+
+#define START_CLIMB_MIDDLE_X 58
+#define START_CLIMB_MIDDLE_Y 295
+
+#define START_DOWN_MIDDLE_X 269
+#define START_DOWN_MIDDLE_Y 292
+
+#define END_DOWN_MIDDLE_FLOOR_X 61
+#define END_DOWN_MIDDLE_FLOOR_Y 450
+
+#define START_DOWN_TOP_X 269
+#define START_DOWN_TOP_Y 138
+
+#define END_DOWN_TOP_FLOOR_X 59
+#define END_DOWN_TOP_FLOOR_Y 296
+
+
+extern void room_109_init();
+extern void room_109_daemon();
+extern void room_109_pre_parser();
+extern void room_109_parser();
+extern void room_109_preload();
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index 9194480c5e3..37ceaab3721 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -130,6 +130,7 @@ MODULE_OBJS += \
madsv2/phantom/rooms/room106.o \
madsv2/phantom/rooms/room107.o \
madsv2/phantom/rooms/room108.o \
+ madsv2/phantom/rooms/room109.o \
madsv2/phantom/phantom.o \
madsv2/phantom/conv.o \
madsv2/phantom/main_menu.o \
Commit: 3afcb36f588cbcf8e4d382a38b6887260f286a82
https://github.com/scummvm/scummvm/commit/3afcb36f588cbcf8e4d382a38b6887260f286a82
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:41+10:00
Commit Message:
MADS: PHANTOM: Minor header file cleanups
Changed paths:
engines/mads/madsv2/phantom/rooms/room104.h
engines/mads/madsv2/phantom/rooms/room105.h
engines/mads/madsv2/phantom/rooms/room106.h
engines/mads/madsv2/phantom/rooms/room107.h
engines/mads/madsv2/phantom/rooms/room108.h
engines/mads/madsv2/phantom/rooms/room109.h
diff --git a/engines/mads/madsv2/phantom/rooms/room104.h b/engines/mads/madsv2/phantom/rooms/room104.h
index 960c422c9d4..6fcfeefbce4 100644
--- a/engines/mads/madsv2/phantom/rooms/room104.h
+++ b/engines/mads/madsv2/phantom/rooms/room104.h
@@ -19,8 +19,6 @@
*
*/
-/* room104.mac by Paul Lahaise 8-Jan-93 */
-
#ifndef MADS_PHANTOM_ROOM104_H
#define MADS_PHANTOM_ROOM104_H
diff --git a/engines/mads/madsv2/phantom/rooms/room105.h b/engines/mads/madsv2/phantom/rooms/room105.h
index be0d22e3cca..13dbcae34e6 100644
--- a/engines/mads/madsv2/phantom/rooms/room105.h
+++ b/engines/mads/madsv2/phantom/rooms/room105.h
@@ -19,8 +19,6 @@
*
*/
-/* room105.mac by Paul Lahaise 8-Jan-93 */
-
#ifndef MADS_PHANTOM_ROOM105_H
#define MADS_PHANTOM_ROOM105_H
diff --git a/engines/mads/madsv2/phantom/rooms/room106.h b/engines/mads/madsv2/phantom/rooms/room106.h
index d83e0ac4211..db39cbeed0f 100644
--- a/engines/mads/madsv2/phantom/rooms/room106.h
+++ b/engines/mads/madsv2/phantom/rooms/room106.h
@@ -19,8 +19,6 @@
*
*/
-/* room106.mac by Paul Lahaise 7-Jan-93 */
-
#ifndef MADS_PHANTOM_ROOM106_H
#define MADS_PHANTOM_ROOM106_H
diff --git a/engines/mads/madsv2/phantom/rooms/room107.h b/engines/mads/madsv2/phantom/rooms/room107.h
index cf8cb69919e..ef569970fba 100644
--- a/engines/mads/madsv2/phantom/rooms/room107.h
+++ b/engines/mads/madsv2/phantom/rooms/room107.h
@@ -19,8 +19,6 @@
*
*/
-/* room107.mac by Paul Lahaise 8-Jan-93 */
-
#ifndef MADS_PHANTOM_ROOM107_H
#define MADS_PHANTOM_ROOM107_H
diff --git a/engines/mads/madsv2/phantom/rooms/room108.h b/engines/mads/madsv2/phantom/rooms/room108.h
index b36e09c7904..abd5d143959 100644
--- a/engines/mads/madsv2/phantom/rooms/room108.h
+++ b/engines/mads/madsv2/phantom/rooms/room108.h
@@ -19,8 +19,6 @@
*
*/
-/* room108.mac by Paul Lahaise 8-Jan-93 */
-
#ifndef MADS_PHANTOM_ROOM108_H
#define MADS_PHANTOM_ROOM108_H
diff --git a/engines/mads/madsv2/phantom/rooms/room109.h b/engines/mads/madsv2/phantom/rooms/room109.h
index 69d039b9577..9b9e160141d 100644
--- a/engines/mads/madsv2/phantom/rooms/room109.h
+++ b/engines/mads/madsv2/phantom/rooms/room109.h
@@ -19,8 +19,6 @@
*
*/
-/* room109.mac by Paul Lahaise 7-Jan-93 */
-
#ifndef MADS_PHANTOM_ROOM109_H
#define MADS_PHANTOM_ROOM109_H
Commit: 78341c751d6f0e9ecc4fcc9791d3b70b58193c61
https://github.com/scummvm/scummvm/commit/78341c751d6f0e9ecc4fcc9791d3b70b58193c61
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:41+10:00
Commit Message:
MADS: PHANTOM: Added room 110
Changed paths:
A engines/mads/madsv2/phantom/rooms/room110.cpp
A engines/mads/madsv2/phantom/rooms/room110.h
engines/mads/madsv2/phantom/global.h
engines/mads/madsv2/phantom/mads/text.h
engines/mads/madsv2/phantom/mads/words.h
engines/mads/module.mk
diff --git a/engines/mads/madsv2/phantom/global.h b/engines/mads/madsv2/phantom/global.h
index 9a476e3208b..643a7dbe9ce 100644
--- a/engines/mads/madsv2/phantom/global.h
+++ b/engines/mads/madsv2/phantom/global.h
@@ -203,6 +203,13 @@ enum {
// sandbag_status
#define SANDBAG_DROPPED 1
+// julies_door
+#define FULLY_OPEN 0
+#define CRACKED_OPEN 1
+
+// chris_f_status
+#define CHRIS_F_IS_ALIVE 1
+
} // namespace Phantom
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/mads/text.h b/engines/mads/madsv2/phantom/mads/text.h
index 969be0d58ef..8bcfc970a7c 100644
--- a/engines/mads/madsv2/phantom/mads/text.h
+++ b/engines/mads/madsv2/phantom/mads/text.h
@@ -276,7 +276,30 @@ enum {
text_109_21 = 10921,
text_109_22 = 10922,
text_109_23 = 10923,
- text_109_24 = 10924
+ text_109_24 = 10924,
+
+ /* Room 110 */
+ text_110_10 = 11010,
+ text_110_11 = 11011,
+ text_110_12 = 11012,
+ text_110_13 = 11013,
+ text_110_14 = 11014,
+ text_110_15 = 11015,
+ text_110_16 = 11016,
+ text_110_17 = 11017,
+ text_110_18 = 11018,
+ text_110_19 = 11019,
+ text_110_20 = 11020,
+ text_110_21 = 11021,
+ text_110_22 = 11022,
+ text_110_23 = 11023,
+ text_110_24 = 11024,
+ text_110_25 = 11025,
+ text_110_26 = 11026,
+ text_110_27 = 11027,
+ text_110_28 = 11028,
+ text_110_29 = 11029,
+ text_110_30 = 11030
};
} // namespace Phantom
diff --git a/engines/mads/madsv2/phantom/mads/words.h b/engines/mads/madsv2/phantom/mads/words.h
index 8f25db77104..bee0d4eae84 100644
--- a/engines/mads/madsv2/phantom/mads/words.h
+++ b/engines/mads/madsv2/phantom/mads/words.h
@@ -78,6 +78,7 @@ enum {
words_orchestra_pit = 108,
words_pipe = 112,
words_pit = 113,
+ words_poster = 115,
words_prompter_s_box = 116,
words_prop_table = 117,
words_props = 118,
@@ -94,6 +95,7 @@ enum {
words_stagemanager_s_post = 136,
words_stair_unit = 137,
words_staircase = 138,
+ words_stairwell = 139,
words_stool = 140,
words_thunder_machine = 145,
words_trap_ceiling = 147,
@@ -103,15 +105,19 @@ enum {
words_walk_down = 154,
words_walk_through = 155,
words_wall = 157,
+ words_waste_basket = 159,
words_water_pipe = 160,
words_yellow_frame = 163,
words_prop = 164,
words_climb_up = 165,
words_walk_onto = 166,
words_walk = 167,
+ words_left_door = 168,
+ words_right_door = 169,
words_door_to_pit = 170,
words_boxes = 172,
words_box = 175,
+ words_trash_bucket = 177,
words_headset = 179,
words_grand_foyer = 180,
words_back_wall = 181,
@@ -125,6 +131,7 @@ enum {
words_ventilation_duct = 200,
words_chandelier = 201,
words_prop_case = 247,
+ words_bulletin_board = 252,
words_Monsieur_Brie = 258,
words_prompter_s_stand = 270,
words_Jacques = 280,
@@ -134,7 +141,8 @@ enum {
words_prompter_s_seat = 300,
words_lever = 301,
words_Monsieur_Richard = 302,
- words_cable_hook = 304
+ words_cable_hook = 304,
+ words_paper = 399
};
} // namespace Phantom
diff --git a/engines/mads/madsv2/phantom/rooms/room110.cpp b/engines/mads/madsv2/phantom/rooms/room110.cpp
new file mode 100644
index 00000000000..b59ad83afa3
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room110.cpp
@@ -0,0 +1,399 @@
+/* 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 "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/text.h"
+#include "mads/madsv2/core/inter.h"
+#include "mads/madsv2/core/object.h"
+#include "mads/madsv2/core/sound.h"
+#include "mads/madsv2/phantom/global.h"
+#include "mads/madsv2/phantom/mads/inventory.h"
+#include "mads/madsv2/phantom/mads/speeches.h"
+#include "mads/madsv2/phantom/mads/words.h"
+#include "mads/madsv2/phantom/mads/sounds.h"
+#include "mads/madsv2/phantom/mads/text.h"
+#include "mads/madsv2/phantom/mads/words.h"
+#include "mads/madsv2/phantom/rooms/section1.h"
+#include "mads/madsv2/phantom/rooms/room110.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+void room_110_init() {
+ /* ==================== Load Sprite Series ====================== */
+
+ ss[fx_door] = kernel_load_series(kernel_name('x', 0), false);
+ ss[fx_door_closed] = kernel_load_series(kernel_name('x', 1), false);
+ ss[fx_take_9] = kernel_load_series("*RDR_9", false);
+
+
+ /* =========== Put light, cork board, julie's door ============== */
+
+ if (global[current_year] == 1993) {
+ ss[fx_1993] = kernel_load_series(kernel_name('z', -1), false);
+ kernel_draw_to_background(ss[fx_1993], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ kernel_flip_hotspot(words_poster, false);
+ kernel_flip_hotspot(words_waste_basket, false);
+
+ if (global[done_brie_conv_203] == NO) {
+ if (global[julies_door] == FULLY_OPEN) {
+ seq[fx_door] = kernel_seq_stamp(ss[fx_door], false, 3);
+ kernel_seq_depth(seq[fx_door], 8);
+ }
+
+ } else {
+ seq[fx_door_closed] = kernel_seq_stamp(ss[fx_door_closed], false, 1);
+ kernel_seq_depth(seq[fx_door_closed], 8);
+ }
+
+ } else {
+ kernel_flip_hotspot(words_bulletin_board, false);
+ kernel_flip_hotspot(words_paper, false);
+ kernel_flip_hotspot(words_trash_bucket, false);
+ }
+
+ /* ====================== Previous Rooms ======================== */
+
+ if (previous_room == 112) {
+ player.x = PLAYER_X_FROM_112;
+ player.y = PLAYER_Y_FROM_112;
+ player.facing = FACING_SOUTH;
+ player_walk(WALK_TO_X_FROM_112, WALK_TO_Y_FROM_112, FACING_SOUTH);
+
+ } else if ((previous_room == 109) || (previous_room != KERNEL_RESTORING_GAME)) {
+ player_first_walk(OFF_SCREEN_X_FROM_109, OFF_SCREEN_Y_FROM_109, FACING_WEST,
+ PLAYER_X_FROM_109, PLAYER_Y_FROM_109, FACING_WEST, true);
+ }
+
+ section_1_music();
+}
+
+void room_110_pre_parser() {
+ if (player_said_2(exit_to, stairwell)) {
+ player.walk_off_edge_to_room = 109;
+ }
+
+ if (player_said_2(open, left_door) || player_said_2(unlock, left_door) ||
+ player_said_2(lock, left_door)) {
+ player_walk(FRONT_LEFT_DOOR_X, FRONT_LEFT_DOOR_Y, FACING_NORTHEAST);
+ }
+
+ if (player_said_2(open, right_door) || player_said_2(walk_through, right_door) ||
+ player_said_2(unlock, right_door) || player_said_2(lock, right_door)) {
+
+ if ((global[current_year] == 1881) || (global[done_brie_conv_203] >= YES)) {
+ player_walk(FRONT_RIGHT_DOOR_X, FRONT_RIGHT_DOOR_Y, FACING_NORTHEAST);
+
+ } else if ((global[julies_door] == CRACKED_OPEN) || player_said_1(open)) {
+ player_walk(FRONT_RIGHT_DOOR_X + 2, FRONT_RIGHT_DOOR_Y - 3, FACING_NORTHEAST);
+ /* get closer to door because it is already open */
+
+ } else if (global[julies_door] == FULLY_OPEN) {
+ player_walk(INSIDE_RIGHT_DOOR_X, INSIDE_RIGHT_DOOR_Y, FACING_NORTHEAST);
+ /* door is fully open, walk into room */
+ }
+ }
+
+ if (player_said_2(look, paper)) {
+ player.need_to_walk = true;
+ }
+}
+
+void room_110_parser() {
+ int temp; /* For synching purposes */
+
+ if ((player_said_2(walk_through, right_door) || player_said_2(unlock, right_door) ||
+ player_said_2(lock, right_door)) && (global[done_brie_conv_203] == NO) &&
+ (global[current_year] == 1993) && (global[julies_door] == FULLY_OPEN)) {
+ new_room = 112;
+ goto handled;
+ }
+
+ if (player_said_2(walk_through, left_door) || player_said_2(open, left_door) ||
+ player_said_2(unlock, left_door) || player_said_2(lock, left_door)) {
+ switch (kernel.trigger) {
+ case 0:
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_take_9] = kernel_seq_forward(ss[fx_take_9], false, 5, 0, 0, 1);
+ kernel_seq_range(seq[fx_take_9], 1, 4);
+ kernel_seq_player(seq[fx_take_9], true);
+ kernel_seq_trigger(seq[fx_take_9], KERNEL_TRIGGER_EXPIRE, 0, 1);
+ break;
+
+ case 1:
+ temp = seq[fx_take_9];
+ seq[fx_take_9] = kernel_seq_stamp(ss[fx_take_9], false, 4);
+ kernel_synch(KERNEL_SERIES, seq[fx_take_9], KERNEL_SERIES, temp);
+ kernel_seq_player(seq[fx_take_9], false);
+ kernel_timing_trigger(HALF_SECOND, 2);
+ sound_play(N_DoorHandle);
+ break;
+
+ case 2:
+ kernel_seq_delete(seq[fx_take_9]);
+ seq[fx_take_9] = kernel_seq_backward(ss[fx_take_9], false, 5, 0, 0, 1);
+ kernel_seq_range(seq[fx_take_9], 1, 4);
+ kernel_seq_player(seq[fx_take_9], false);
+ kernel_seq_trigger(seq[fx_take_9], KERNEL_TRIGGER_EXPIRE, 0, 3);
+ break;
+
+ case 3:
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_SERIES, seq[fx_take_9]);
+ player.walker_visible = true;
+ player.commands_allowed = true;
+ if (player_said_1(lock) || player_said_1(unlock)) {
+ text_show(text_000_32);
+ /* the key does not work here */
+ } else {
+ text_show(text_110_22);
+ /* the door is locked */
+ }
+ break;
+ }
+ goto handled;
+ }
+
+ if (player_said_2(walk_through, right_door) || player_said_2(open, right_door) ||
+ player_said_2(unlock, right_door) || player_said_2(lock, right_door)) {
+ if ((global[current_year] == 1881) || (global[done_brie_conv_203] >= YES) &&
+ !player_said_2(unlock, right_door) && !player_said_2(lock, right_door)) {
+ switch (kernel.trigger) {
+ case 0:
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_take_9] = kernel_seq_forward(ss[fx_take_9], false, 5, 0, 0, 1);
+ kernel_seq_range(seq[fx_take_9], 1, 4);
+ kernel_seq_player(seq[fx_take_9], true);
+ kernel_seq_trigger(seq[fx_take_9], KERNEL_TRIGGER_EXPIRE, 0, 1);
+ break;
+
+ case 1:
+ temp = seq[fx_take_9];
+ seq[fx_take_9] = kernel_seq_stamp(ss[fx_take_9], false, 4);
+ kernel_synch(KERNEL_SERIES, seq[fx_take_9], KERNEL_SERIES, temp);
+ kernel_seq_player(seq[fx_take_9], false);
+ kernel_timing_trigger(HALF_SECOND, 2);
+ sound_play(N_DoorHandle);
+ break;
+
+ case 2:
+ kernel_seq_delete(seq[fx_take_9]);
+ seq[fx_take_9] = kernel_seq_backward(ss[fx_take_9], false, 5, 0, 0, 1);
+ kernel_seq_range(seq[fx_take_9], 1, 4);
+ kernel_seq_player(seq[fx_take_9], false);
+ kernel_seq_trigger(seq[fx_take_9], KERNEL_TRIGGER_EXPIRE, 0, 3);
+ break;
+
+ case 3:
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_SERIES, seq[fx_take_9]);
+ player.walker_visible = true;
+ player.commands_allowed = true;
+ if (player_said_1(lock) || player_said_1(unlock)) {
+ text_show(text_000_32);
+ /* the key does not work here */
+ } else {
+ text_show(text_110_23);
+ /* The door is locked */
+ }
+ break;
+ }
+ goto handled;
+
+ } else if (global[julies_door] == CRACKED_OPEN) {
+ switch (kernel.trigger) {
+ case 0:
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_take_9] = kernel_seq_pingpong(ss[fx_take_9], false, 7, 0, 0, 2);
+ kernel_seq_range(seq[fx_take_9], 1, 4);
+ kernel_seq_player(seq[fx_take_9], true);
+ kernel_seq_trigger(seq[fx_take_9], KERNEL_TRIGGER_SPRITE, 4, 1);
+ kernel_seq_trigger(seq[fx_take_9], KERNEL_TRIGGER_EXPIRE, 0, 3);
+ break;
+
+ case 1:
+ sound_play(N_DoorOpens);
+ seq[fx_door] = kernel_seq_forward(ss[fx_door], false, 10, 0, 0, 1);
+ kernel_seq_range(seq[fx_door], KERNEL_FIRST, KERNEL_LAST);
+ kernel_seq_depth(seq[fx_door], 10);
+ kernel_seq_trigger(seq[fx_door], KERNEL_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 2:
+ seq[fx_door] = kernel_seq_stamp(ss[fx_door], false, 3);
+ kernel_seq_depth(seq[fx_door], 10);
+ break;
+
+ case 3:
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_SERIES, seq[fx_take_9]);
+ player.walker_visible = true;
+ /* The door has been pushed open all of the way */
+ player_walk(PLAYER_X_FROM_112, PLAYER_Y_FROM_112, FACING_NORTHEAST);
+ player_walk_trigger(4);
+ break;
+
+ case 4:
+ new_room = 112;
+ global[julies_door] = FULLY_OPEN;
+ break;
+ }
+ goto handled;
+ }
+ }
+
+ if (player.look_around) {
+ text_show(text_110_10);
+ goto handled;
+ }
+
+ if (player_said_1(look) || player_said_1(look_at)) {
+
+ if (player_said_1(floor)) {
+ text_show(text_110_11);
+ goto handled;
+ }
+
+ if (player_said_1(wall)) {
+ text_show(text_110_12);
+ goto handled;
+ }
+
+ if (player_said_1(ceiling)) {
+ text_show(text_110_13);
+ goto handled;
+ }
+
+ if (player_said_1(stairwell)) {
+ text_show(text_110_14);
+ goto handled;
+ }
+
+ if (player_said_1(right_door)) {
+ if (global[done_brie_conv_203] >= YES) {
+ text_show(text_110_16);
+ } else if (global[chris_f_status] == CHRIS_F_IS_ALIVE) {
+ text_show(text_110_15);
+ } else {
+ text_show(text_110_16);
+ }
+ goto handled;
+ }
+
+ if (player_said_1(left_door)) {
+ text_show(text_110_16);
+ goto handled;
+ }
+
+ if ((player_said_1(waste_basket)) || (player_said_1(trash_bucket))) {
+ text_show(text_110_17);
+ goto handled;
+ }
+
+ if (player_said_1(poster)) {
+ text_show(text_110_18);
+ goto handled;
+ }
+
+ if (player_said_1(bulletin_board)) {
+ text_show(text_110_19);
+ goto handled;
+ }
+
+ if (player_said_1(paper)) {
+ text_show(text_110_29);
+ goto handled;
+ }
+
+ if (player_said_2(take, waste_basket) || player_said_2(take, trash_bucket)) {
+ text_show(text_110_20);
+ goto handled;
+ }
+
+ if (player_said_1(light_fixture)) {
+ if (global[current_year] == 1993) {
+ text_show(text_110_21);
+ } else {
+ text_show(text_110_28);
+ }
+ goto handled;
+ }
+ }
+
+ if (player_said_2(take, paper)) {
+ text_show(text_110_30);
+ goto handled;
+ }
+
+ if (player_said_2(close, right_door)) {
+ if (global[done_brie_conv_203] >= YES) {
+ text_show(text_110_26);
+ } else if (global[chris_f_status] == CHRIS_F_IS_ALIVE) {
+ text_show(text_110_24);
+ } else {
+ text_show(text_110_26);
+ }
+ goto handled;
+ }
+
+ if (player_said_2(close, left_door)) {
+ text_show(text_110_25);
+ goto handled;
+ }
+
+ if (player_said_2(open, right_door)) {
+ if ((global[chris_f_status] == CHRIS_F_IS_ALIVE) &&
+ (global[done_brie_conv_203] == NO)) {
+ text_show(text_110_27);
+ }
+ goto handled;
+ }
+
+ goto done;
+
+handled:
+ player.command_ready = false;
+
+done:
+ ;
+}
+
+void room_110_preload() {
+ room_init_code_pointer = room_110_init;
+ room_pre_parser_code_pointer = room_110_pre_parser;
+ room_parser_code_pointer = room_110_parser;
+ room_daemon_code_pointer = NULL;
+
+ if (global[current_year] == 1993) {
+ kernel_initial_variant = 1;
+ }
+
+ section_1_walker();
+ section_1_interface();
+}
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/rooms/room110.h b/engines/mads/madsv2/phantom/rooms/room110.h
new file mode 100644
index 00000000000..7eeafdedd26
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room110.h
@@ -0,0 +1,92 @@
+/* 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 MADS_PHANTOM_ROOM110_H
+#define MADS_PHANTOM_ROOM110_H
+
+#include "mads/madsv2/phantom/rooms/section1.h"
+#include "mads/madsv2/phantom/global.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+#define local ((Scratch *)(&game.scratch[0]))
+#define ss local->sprite
+#define seq local->sequence
+#define aa local->animation
+
+typedef struct { /* Room local variables */
+
+ int sprite[15]; /* Sprite series handles */
+ int sequence[15]; /* Sequence handles */
+ int animation[4]; /* Animation handles */
+
+} Scratch;
+
+
+/* ========================= Sprite Series ========================= */
+
+#define fx_1993 0 /* rm110z */
+#define fx_take_9 1 /* rdr_9 */
+#define fx_door 2 /* rm110x0 */
+#define fx_door_closed 3 /* rm110x1 */
+
+
+/* ========================= Player positions ====================== */
+
+#define PLAYER_X_FROM_109 310
+#define PLAYER_Y_FROM_109 150
+
+#define PLAYER_X_FROM_112 261
+#define PLAYER_Y_FROM_112 121
+
+#define WALK_TO_X_FROM_112 221
+#define WALK_TO_Y_FROM_112 131
+
+#define OFF_SCREEN_X_FROM_109 335
+#define OFF_SCREEN_Y_FROM_109 150
+
+
+/* ========================= Door approach positions =============== */
+
+#define FRONT_LEFT_DOOR_X 111
+#define FRONT_LEFT_DOOR_Y 126
+
+#define FRONT_RIGHT_DOOR_X 221
+#define FRONT_RIGHT_DOOR_Y 131
+
+#define INSIDE_RIGHT_DOOR_X 261
+#define INSIDE_RIGHT_DOOR_Y 120
+
+
+extern void room_110_init();
+extern void room_110_pre_parser();
+extern void room_110_parser();
+extern void room_110_preload();
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index 37ceaab3721..535a13e3eea 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -131,6 +131,7 @@ MODULE_OBJS += \
madsv2/phantom/rooms/room107.o \
madsv2/phantom/rooms/room108.o \
madsv2/phantom/rooms/room109.o \
+ madsv2/phantom/rooms/room110.o \
madsv2/phantom/phantom.o \
madsv2/phantom/conv.o \
madsv2/phantom/main_menu.o \
Commit: 153d136029fda2e202a2c98b3651018460c3242e
https://github.com/scummvm/scummvm/commit/153d136029fda2e202a2c98b3651018460c3242e
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:42+10:00
Commit Message:
MADS: PHANTOM: Added room 111
Changed paths:
A engines/mads/madsv2/phantom/rooms/room111.cpp
A engines/mads/madsv2/phantom/rooms/room111.h
engines/mads/madsv2/phantom/conv.h
engines/mads/madsv2/phantom/global.h
engines/mads/madsv2/phantom/mads/inventory.h
engines/mads/madsv2/phantom/mads/text.h
engines/mads/madsv2/phantom/mads/words.h
engines/mads/module.mk
diff --git a/engines/mads/madsv2/phantom/conv.h b/engines/mads/madsv2/phantom/conv.h
index 565e472db54..e701ca65af1 100644
--- a/engines/mads/madsv2/phantom/conv.h
+++ b/engines/mads/madsv2/phantom/conv.h
@@ -58,7 +58,9 @@ enum {
conv002_interrogate_giry = 22,
conv002_nomore_first = 25,
conv002_saytwo_abc = 26,
+};
+enum {
conv007_richard_intro_b = 2,
conv007_daaeb_intro_c = 3,
conv007_where_pushed = 8,
@@ -77,7 +79,9 @@ enum {
conv007_office_abc = 28,
conv007_solo_alone = 30,
conv007_pinch_wait_b_nothing_b = 32,
+};
+enum {
conv012_hello_one = 1,
conv012_hello_four = 4,
conv012_byebye_first = 6,
@@ -91,6 +95,11 @@ enum {
conv012_nomore_first = 30
};
+enum {
+ conv014_second_angel = 1,
+ conv014_eighth_inside = 7
+};
+
struct ConvData {
int16 node_count;
int16 dialog_count;
diff --git a/engines/mads/madsv2/phantom/global.h b/engines/mads/madsv2/phantom/global.h
index 643a7dbe9ce..4cac6ad593a 100644
--- a/engines/mads/madsv2/phantom/global.h
+++ b/engines/mads/madsv2/phantom/global.h
@@ -210,6 +210,11 @@ enum {
// chris_f_status
#define CHRIS_F_IS_ALIVE 1
+// christine_door_status
+#define CHRIS_IS_IN 0
+#define CHRIS_DOOR_CLOSED 1
+#define CHRIS_DOOR_CHOPPED 2
+
} // namespace Phantom
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/mads/inventory.h b/engines/mads/madsv2/phantom/mads/inventory.h
index bdb35be2b36..c26d09bea23 100644
--- a/engines/mads/madsv2/phantom/mads/inventory.h
+++ b/engines/mads/madsv2/phantom/mads/inventory.h
@@ -34,6 +34,7 @@ enum {
red_frame = 2,
sandbag = 3,
yellow_frame = 4,
+ fire_axe = 5,
small_note = 6,
rope = 7,
parchment = 12,
diff --git a/engines/mads/madsv2/phantom/mads/text.h b/engines/mads/madsv2/phantom/mads/text.h
index 8bcfc970a7c..c6db14a4cd8 100644
--- a/engines/mads/madsv2/phantom/mads/text.h
+++ b/engines/mads/madsv2/phantom/mads/text.h
@@ -299,7 +299,42 @@ enum {
text_110_27 = 11027,
text_110_28 = 11028,
text_110_29 = 11029,
- text_110_30 = 11030
+ text_110_30 = 11030,
+
+ /* Room 111 */
+ text_111_10 = 11110,
+ text_111_11 = 11111,
+ text_111_12 = 11112,
+ text_111_13 = 11113,
+ text_111_14 = 11114,
+ text_111_15 = 11115,
+ text_111_16 = 11116,
+ text_111_17 = 11117,
+ text_111_18 = 11118,
+ text_111_19 = 11119,
+ text_111_20 = 11120,
+ text_111_21 = 11121,
+ text_111_22 = 11122,
+ text_111_23 = 11123,
+ text_111_24 = 11124,
+ text_111_25 = 11125,
+ text_111_26 = 11126,
+ text_111_27 = 11127,
+ text_111_28 = 11128,
+ text_111_29 = 11129,
+ text_111_30 = 11130,
+ text_111_31 = 11131,
+ text_111_32 = 11132,
+ /* text_111_33 not used */
+ text_111_34 = 11134,
+ text_111_35 = 11135,
+ text_111_36 = 11136,
+ text_111_37 = 11137,
+ text_111_38 = 11138,
+ text_111_39 = 11139,
+ text_111_40 = 11140,
+ text_111_41 = 11141,
+ text_111_42 = 11142
};
} // namespace Phantom
diff --git a/engines/mads/madsv2/phantom/mads/words.h b/engines/mads/madsv2/phantom/mads/words.h
index bee0d4eae84..6fe19d61780 100644
--- a/engines/mads/madsv2/phantom/mads/words.h
+++ b/engines/mads/madsv2/phantom/mads/words.h
@@ -53,6 +53,7 @@ enum {
words_exit_sign = 54,
words_exit_to = 55,
words_exposed_brick = 67,
+ words_fire_axe = 69,
words_flats = 72,
words_floor = 73,
words_folding_chairs = 74,
@@ -78,6 +79,7 @@ enum {
words_orchestra_pit = 108,
words_pipe = 112,
words_pit = 113,
+ words_plant = 114,
words_poster = 115,
words_prompter_s_box = 116,
words_prop_table = 117,
@@ -97,6 +99,7 @@ enum {
words_staircase = 138,
words_stairwell = 139,
words_stool = 140,
+ words_table = 143,
words_thunder_machine = 145,
words_trap_ceiling = 147,
words_trap_door = 148,
@@ -130,7 +133,11 @@ enum {
words_big_prop = 199,
words_ventilation_duct = 200,
words_chandelier = 201,
+ words_light = 245,
words_prop_case = 247,
+ words_handle = 248,
+ words_axe = 249,
+ words_door_chunks = 250,
words_bulletin_board = 252,
words_Monsieur_Brie = 258,
words_prompter_s_stand = 270,
@@ -142,6 +149,7 @@ enum {
words_lever = 301,
words_Monsieur_Richard = 302,
words_cable_hook = 304,
+ words_hook = 390,
words_paper = 399
};
diff --git a/engines/mads/madsv2/phantom/rooms/room111.cpp b/engines/mads/madsv2/phantom/rooms/room111.cpp
new file mode 100644
index 00000000000..40e6576a5a0
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room111.cpp
@@ -0,0 +1,642 @@
+/* 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 "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/text.h"
+#include "mads/madsv2/core/inter.h"
+#include "mads/madsv2/core/object.h"
+#include "mads/madsv2/core/sound.h"
+#include "mads/madsv2/phantom/global.h"
+#include "mads/madsv2/phantom/conv.h"
+#include "mads/madsv2/phantom/mads/inventory.h"
+#include "mads/madsv2/phantom/mads/speeches.h"
+#include "mads/madsv2/phantom/mads/words.h"
+#include "mads/madsv2/phantom/mads/sounds.h"
+#include "mads/madsv2/phantom/mads/text.h"
+#include "mads/madsv2/phantom/rooms/section1.h"
+#include "mads/madsv2/phantom/rooms/room111.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+static void handle_animation_listen() {
+ int listen_reset_frame;
+
+ if (kernel_anim[aa[0]].frame != local->listen_frame) {
+ local->listen_frame = kernel_anim[aa[0]].frame;
+ listen_reset_frame = -1;
+
+ switch (local->listen_frame) {
+ case 6: /* end of freeze (ear to door) */
+
+ if (local->listen_action == CONV14_LISTEN) {
+ listen_reset_frame = 5;
+ break; /* keep ear to door */
+ }
+
+ if (local->listen_action == CONV14_UN_LISTEN) {
+ listen_reset_frame = 7;
+ break; /* back off from door */
+ }
+ break;
+ }
+
+ if (listen_reset_frame >= 0) {
+ kernel_reset_animation(aa[0], listen_reset_frame);
+ local->listen_frame = listen_reset_frame;
+ }
+ }
+}
+
+void room_111_init() {
+ int temp_dynamic; /* For dynamic hotspots */
+
+ kernel_flip_hotspot(words_hook, false);
+
+ local->delete_axe = false;
+ local->anim_0_running = false;
+ local->anim_1_running = false;
+ local->it_is_closed = true;
+
+ if (global[current_year] == 1881) {
+ if ((global[jacques_name_is_known] == YES_AND_END_CONV) &&
+ (global[madame_name_is_known] == YES_AND_END_CONV) &&
+ (global[panel_in_206]) &&
+ (global[done_rich_conv_203]) &&
+ (player_has(lantern)) &&
+ ((player_has(cable_hook) && player_has(rope)) || player_has(rope_with_hook))) {
+ local->it_is_closed = false;
+ } else {
+ local->it_is_closed = true;
+ }
+ } else {
+ local->it_is_closed = false;
+ }
+
+ if (global[jacques_status]) {
+ kernel_flip_hotspot(words_hook, true);
+ kernel_flip_hotspot(words_fire_axe, false);
+ }
+
+
+ /* =================== Load conversation ======================== */
+
+ conv_get(CONV_LISTEN);
+
+
+ /* ==================== Load Sprite Series ====================== */
+
+ ss[fx_take_9] = kernel_load_series("*RDR_9", false);
+ ss[fx_axe] = kernel_load_series(kernel_name('a', 1), false);
+ ss[fx_open_door] = kernel_load_series(kernel_name('a', 3), false);
+ ss[fx_door] = kernel_load_series(kernel_name('x', 0), false);
+
+ if (global[current_year] == 1881) {
+ ss[fx_broken_axe] = kernel_load_series(kernel_name('a', 2), false);
+ }
+
+
+ /* =================== Draw 1993 sprite ========================= */
+
+ if (global[current_year] == 1993) {
+ ss[fx_1993] = kernel_load_series(kernel_name('z', -1), false);
+ kernel_draw_to_background(ss[fx_1993], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ kernel_flip_hotspot(words_lamp, false);
+ temp_dynamic = kernel_add_dynamic(words_wall, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ WALL_X, WALL_Y, WALL_X_SIZE, WALL_Y_SIZE);
+ kernel_dynamic_walk(temp_dynamic, WALL_WALK_X, WALL_WALK_Y, FACING_NORTHEAST);
+
+ } else {
+ kernel_flip_hotspot(words_light, false);
+ if (global[christine_door_status] == CHRIS_DOOR_CHOPPED) {
+ seq[fx_broken_axe] = kernel_seq_stamp(ss[fx_broken_axe], false, 1);
+ kernel_seq_depth(seq[fx_broken_axe], 10);
+ kernel_draw_to_background(ss[fx_open_door], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ kernel_flip_hotspot(words_fire_axe, false);
+ kernel_flip_hotspot(words_door_chunks, true);
+ kernel_flip_hotspot(words_handle, true);
+ kernel_flip_hotspot(words_axe, true);
+ }
+ }
+
+ if ((global[christine_door_status] == CHRIS_IS_IN) &&
+ (previous_room != 113) && (!local->it_is_closed)) {
+ seq[fx_door] = kernel_seq_stamp(ss[fx_door], false, 3);
+ kernel_seq_depth(seq[fx_door], 14);
+ /* now it is set up so that CHRIS_IS_IN will apply to both times (for Daae & Florent) */
+ }
+
+ if ((global[current_year] == 1993) || (global[christine_door_status] <= CHRIS_DOOR_CLOSED)) {
+ if (!global[jacques_status]) {
+ seq[fx_axe] = kernel_seq_stamp(ss[fx_axe], false, 1);
+ kernel_seq_depth(seq[fx_axe], 5);
+ kernel_flip_hotspot(words_axe, false);
+ }
+ kernel_flip_hotspot(words_door_chunks, false);
+ kernel_flip_hotspot(words_handle, false);
+ }
+
+
+ /* ====================== Previous Rooms ======================== */
+
+ if (previous_room == 113) {
+ player.x = PLAYER_X_FROM_113_SAWDUST;
+ player.y = PLAYER_Y_FROM_113_SAWDUST;
+ player_walk(PLAYER_X_FROM_113, PLAYER_Y_FROM_113, FACING_SOUTH);
+
+ if (!global[leave_angel_music_on]) {
+ section_1_music();
+ }
+
+ if (global[christine_door_status] != CHRIS_DOOR_CHOPPED) {
+ seq[fx_door] = kernel_seq_stamp(ss[fx_door], false, 3);
+ kernel_seq_depth(seq[fx_door], 14);
+
+ if ((global[current_year] == 1881) && (global[leave_angel_music_on])) {
+ /* Daae kicked Raoul out â send to daemon to close door */
+ player_walk_trigger(ROOM_111_MADE_IT_OUT_DOOR);
+ player.commands_allowed = false;
+ player.commands_allowed = false;
+ global[christine_door_status] = CHRIS_DOOR_CLOSED;
+ global[chris_kicked_raoul_out] = true;
+ global[hint_that_daae_is_home_1] = true;
+ global[hint_that_daae_is_home_2] = true;
+ }
+ }
+
+ } else if ((previous_room == 109) || (previous_room != KERNEL_RESTORING_GAME)) {
+ player_first_walk(OFF_SCREEN_X_FROM_109, OFF_SCREEN_Y_FROM_109, FACING_WEST,
+ PLAYER_X_FROM_109, PLAYER_Y_FROM_109, FACING_WEST, true);
+ }
+
+ section_1_music();
+}
+
+void room_111_daemon() {
+ if (local->anim_0_running) {
+ handle_animation_listen();
+ }
+
+ if ((!local->delete_axe) && (local->anim_1_running) &&
+ (kernel_anim[local->animation[1]].frame == 5)) {
+ kernel_seq_delete(seq[fx_axe]);
+ inter_give_to_player(fire_axe);
+ local->delete_axe = true;
+ }
+
+ if ((player_has(fire_axe)) && (local->anim_1_running) &&
+ (kernel_anim[local->animation[1]].frame == 36)) {
+ inter_move_object(fire_axe, NOWHERE);
+ }
+
+ if ((player.x == WALK_TO_X_INSIDE_112) && (player.y == WALK_TO_Y_INSIDE_112)) {
+ new_room = 113;
+ }
+
+
+ switch (kernel.trigger) {
+
+ case ROOM_111_MADE_IT_OUT_DOOR:
+ kernel_seq_delete(seq[fx_door]);
+ seq[fx_door] = kernel_seq_backward(ss[fx_door], false, 7, 0, 0, 1);
+ kernel_seq_trigger(seq[fx_door], KERNEL_TRIGGER_EXPIRE, 0, ROOM_111_CLOSED_DOOR);
+ kernel_seq_depth(seq[fx_door], 14);
+ kernel_seq_range(seq[fx_door], KERNEL_FIRST, KERNEL_LAST);
+ break;
+
+ case ROOM_111_CLOSED_DOOR:
+ sound_play(N_DoorCloses);
+ player.commands_allowed = true;
+ conv_run(CONV_LISTEN);
+ if (game.difficulty == EASY_MODE) {
+ conv_export_value(1);
+ } else {
+ conv_export_value(0);
+ }
+ player_walk(LISTEN_X, LISTEN_Y, FACING_EAST);
+ player_walk_trigger(ROOM_111_AT_LISTEN_POINT);
+ break;
+
+ case ROOM_111_AT_LISTEN_POINT:
+ aa[0] = kernel_run_animation(kernel_name('l', 1), ROOM_111_DONE_LISTENING);
+ kernel_synch(KERNEL_ANIM, aa[0], KERNEL_PLAYER, 0);
+ local->anim_0_running = true;
+ local->listen_action = CONV14_LISTEN;
+ player.walker_visible = false;
+ break;
+
+ case ROOM_111_DONE_LISTENING:
+ player.walker_visible = true;
+ local->anim_0_running = false;
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_ANIM, aa[0]);
+ kernel_timing_trigger(HALF_SECOND, ROOM_111_DONE_LISTENING + 1);
+ break;
+
+ case ROOM_111_DONE_LISTENING + 1:
+ conv_release();
+ break;
+ }
+}
+
+static void process_conversation_listen() {
+ if (player_verb == conv014_second_angel) {
+ conv_you_trigger(ROOM_111_LISTEN);
+ }
+
+ if (player_verb == conv014_eighth_inside) {
+ conv_you_trigger(ROOM_111_UN_LISTEN);
+ }
+
+ if (kernel.trigger == ROOM_111_LISTEN) {
+ local->listen_action = CONV14_LISTEN;
+ }
+
+ if (kernel.trigger == ROOM_111_UN_LISTEN) {
+ local->listen_action = CONV14_UN_LISTEN;
+ conv_hold();
+ }
+
+ /* ================= Set up me and you triggers ================= */
+
+ if ((player_verb != conv014_second_angel) &&
+ (player_verb != conv014_eighth_inside)) {
+ conv_you_trigger(ROOM_111_NOTHING);
+ }
+}
+
+void room_111_pre_parser() {
+ if (player_said_2(exit_to, stairwell)) {
+ if (global[leave_angel_music_on]) {
+ text_show(text_111_39);
+ player.need_to_walk = false;
+ player_cancel_command();
+ /* You shouldn't leave now, Christine is behind door */
+ } else {
+ player.walk_off_edge_to_room = 109;
+ }
+ }
+
+ if (player_said_2(take, fire_axe) && object_is_here(fire_axe) && global[current_year] == 1881) {
+ if ((global[christine_door_status] == CHRIS_DOOR_CLOSED) &&
+ (global[chris_kicked_raoul_out]) && (global[jacques_status] == JACQUES_IS_ALIVE)) {
+ player_walk(LISTEN_X, LISTEN_Y, FACING_EAST); /* also for taking axe */
+ }
+ }
+
+ if (player_said_2(open, right_door) || player_said_2(unlock, right_door) ||
+ player_said_2(lock, right_door)) {
+ player_walk(FRONT_RIGHT_DOOR_X, FRONT_RIGHT_DOOR_Y, FACING_NORTHEAST);
+ }
+
+ if (player_said_2(open, left_door) || player_said_2(unlock, left_door) ||
+ player_said_2(lock, left_door)) {
+ player_walk(FRONT_LEFT_DOOR_X, FRONT_LEFT_DOOR_Y, FACING_NORTHEAST);
+ }
+
+ if ((player_said_2(walk_through, left_door) || player_said_2(unlock, left_door) ||
+ player_said_2(lock, left_door)) && (!local->it_is_closed)) {
+ if ((global[christine_door_status] == CHRIS_DOOR_CHOPPED) ||
+ (global[christine_door_status] == CHRIS_IS_IN)) {
+ player_walk(WALK_TO_X_INSIDE_112, WALK_TO_Y_INSIDE_112, FACING_NORTHEAST);
+ }
+ }
+}
+
+void room_111_parser() {
+ int temp; /* For synching purposes */
+
+ if (conv_control.running == CONV_LISTEN) {
+ process_conversation_listen();
+ goto handled;
+ }
+
+ if (player_said_2(walk_through, right_door) || player_said_2(open, right_door) ||
+ player_said_1(unlock) || player_said_1(lock)) {
+ switch (kernel.trigger) {
+ case 0:
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_take_9] = kernel_seq_forward(ss[fx_take_9], false, 5, 0, 0, 1);
+ kernel_seq_range(seq[fx_take_9], 1, 4);
+ kernel_seq_player(seq[fx_take_9], true);
+ kernel_seq_trigger(seq[fx_take_9], KERNEL_TRIGGER_EXPIRE, 0, 1);
+ goto handled;
+ break; // dead code; preserved from original
+
+ case 1:
+ temp = seq[fx_take_9];
+ seq[fx_take_9] = kernel_seq_stamp(ss[fx_take_9], false, 4);
+ kernel_synch(KERNEL_SERIES, seq[fx_take_9], KERNEL_SERIES, temp);
+ kernel_seq_player(seq[fx_take_9], false);
+ kernel_timing_trigger(HALF_SECOND, 2);
+ sound_play(N_DoorHandle);
+ goto handled;
+ break; // dead code; preserved from original
+
+ case 2:
+ kernel_seq_delete(seq[fx_take_9]);
+ seq[fx_take_9] = kernel_seq_backward(ss[fx_take_9], false, 5, 0, 0, 1);
+ kernel_seq_range(seq[fx_take_9], 1, 4);
+ kernel_seq_player(seq[fx_take_9], false);
+ kernel_seq_trigger(seq[fx_take_9], KERNEL_TRIGGER_EXPIRE, 0, 3);
+ goto handled;
+ break; // dead code; preserved from original
+
+ case 3:
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_SERIES, seq[fx_take_9]);
+ player.walker_visible = true;
+ if (player_said_1(lock) || player_said_1(unlock)) {
+ text_show(text_000_32);
+ /* the key won't work */
+ } else {
+ text_show(text_111_23);
+ /* the door is locked */
+ }
+ player.commands_allowed = true;
+ goto handled;
+ break; // dead code; preserved from original
+ }
+ }
+
+
+ if (player_said_2(walk_through, left_door) || player_said_2(open, left_door) ||
+ player_said_2(unlock, left_door) || player_said_2(lock, left_door)) {
+ if ((global[christine_door_status] == CHRIS_DOOR_CLOSED) || (local->it_is_closed) ||
+ player_said_2(unlock, left_door) || player_said_2(lock, left_door)) {
+ switch (kernel.trigger) {
+ case 0:
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_take_9] = kernel_seq_forward(ss[fx_take_9], false, 5, 0, 0, 1);
+ kernel_seq_range(seq[fx_take_9], 1, 4);
+ kernel_seq_player(seq[fx_take_9], true);
+ kernel_seq_trigger(seq[fx_take_9], KERNEL_TRIGGER_EXPIRE, 0, 1);
+ goto handled;
+ break; // dead code; preserved from original
+
+ case 1:
+ temp = seq[fx_take_9];
+ seq[fx_take_9] = kernel_seq_stamp(ss[fx_take_9], false, 4);
+ kernel_synch(KERNEL_SERIES, seq[fx_take_9], KERNEL_SERIES, temp);
+ kernel_seq_player(seq[fx_take_9], false);
+ kernel_timing_trigger(HALF_SECOND, 2);
+ sound_play(N_DoorHandle);
+ goto handled;
+ break; // dead code; preserved from original
+
+ case 2:
+ kernel_seq_delete(seq[fx_take_9]);
+ seq[fx_take_9] = kernel_seq_backward(ss[fx_take_9], false, 5, 0, 0, 1);
+ kernel_seq_range(seq[fx_take_9], 1, 4);
+ kernel_seq_player(seq[fx_take_9], false);
+ kernel_seq_trigger(seq[fx_take_9], KERNEL_TRIGGER_EXPIRE, 0, 3);
+ goto handled;
+ break; // dead code; preserved from original
+
+ case 3:
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_SERIES, seq[fx_take_9]);
+ player.walker_visible = true;
+
+ if (player_said_1(lock) || player_said_1(unlock)) {
+ text_show(text_000_32);
+ /* the key does not work here */
+ } else if ((global[chris_kicked_raoul_out]) /*&& (local->it_is_closed)*/ &&
+ (global[ticket_people_here] == SELLER) &&
+ (global[jacques_status] == JACQUES_IS_ALIVE)) {
+ text_show(text_111_35);
+ /* the door is locked! */
+ } else {
+ text_show(text_111_24);
+ /* the door is locked no one is inside */
+ }
+ player.commands_allowed = true;
+ goto handled;
+ break; // dead code; preserved from original
+ }
+
+ } else if (global[christine_door_status] == CHRIS_DOOR_CHOPPED) {
+ text_show(text_111_37);
+ goto handled;
+ /* the door is chopped up */
+ } else {
+ text_show(text_111_26);
+ goto handled; /* the door is already open, someone is inside */
+ }
+ }
+
+ if (player_said_2(take, fire_axe)) {
+ if ((global[current_year] == 1881) &&
+ (global[jacques_status] == JACQUES_IS_ALIVE) &&
+ (global[christine_door_status] == CHRIS_DOOR_CLOSED) &&
+ (global[chris_kicked_raoul_out])) {
+ switch (kernel.trigger) {
+ case 0:
+ aa[1] = kernel_run_animation(kernel_name('q', -1), 1);
+ kernel_flip_hotspot(words_fire_axe, false);
+ kernel_flip_hotspot(words_door_chunks, true);
+ kernel_flip_hotspot(words_handle, true);
+ kernel_flip_hotspot(words_axe, true);
+ local->anim_1_running = true;
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ break;
+
+ case 1:
+ global[christine_door_status] = CHRIS_DOOR_CHOPPED;
+ seq[fx_broken_axe] = kernel_seq_stamp(ss[fx_broken_axe], false, 1);
+ kernel_synch(KERNEL_SERIES, seq[fx_broken_axe], KERNEL_ANIM, local->animation[1]);
+ kernel_seq_depth(seq[fx_broken_axe], 10);
+ kernel_draw_to_background(ss[fx_open_door], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_ANIM, local->animation[1]);
+ player.walker_visible = true;
+ player.x = AFTER_AXE_ANIM_X;
+ player.y = AFTER_AXE_ANIM_Y;
+ local->anim_1_running = false;
+ player_walk(WALK_TO_X_INSIDE_112, WALK_TO_Y_INSIDE_112, FACING_NORTHEAST);
+ player_demand_facing(FACING_NORTHWEST);
+ break;
+ }
+ } else {
+ if (global[current_year] == 1993 && global[make_brie_leave_203]) {
+ text_show(text_111_42);
+ /* you would not want to hack up a murderer (right to life) */
+ } else {
+ text_show(text_111_34);
+ /* the axe is fine where it is */
+ }
+ }
+ goto handled;
+ }
+
+ if (player.look_around) {
+ if (global[current_year] == 1993) {
+ text_show(text_111_10);
+ } else {
+ text_show(text_111_11);
+ }
+ goto handled;
+ }
+
+ if (player_said_1(look) || player_said_1(look_at)) {
+
+ if (player_said_1(floor)) {
+ text_show(text_111_12);
+ goto handled;
+ }
+
+ if (player_said_1(wall)) {
+ text_show(text_111_13);
+ goto handled;
+ }
+
+ if (player_said_1(ceiling)) {
+ text_show(text_111_14);
+ goto handled;
+ }
+
+ if (player_said_1(stairwell)) {
+ text_show(text_111_15);
+ goto handled;
+ }
+
+ if (player_said_1(table)) {
+ text_show(text_111_18);
+ goto handled;
+ }
+
+ if (player_said_1(plant)) {
+ text_show(text_111_19);
+ goto handled;
+ }
+
+ if (player_said_1(fire_axe)) {
+ text_show(text_111_20);
+ goto handled;
+ }
+
+ if (player_said_1(handle)) {
+ text_show(text_111_21);
+ goto handled;
+ }
+
+ if (player_said_1(axe)) {
+ text_show(text_111_22);
+ goto handled;
+ }
+
+ if (player_said_1(door_chunks)) {
+ text_show(text_111_29);
+ goto handled;
+ }
+
+ if (player_said_1(light)) {
+ text_show(text_111_31);
+ goto handled;
+ }
+
+ if (player_said_1(lamp)) {
+ text_show(text_111_32);
+ goto handled;
+ }
+
+ if (player_said_1(hook)) {
+ text_show(text_111_41);
+ goto handled;
+ }
+
+ if (player_said_1(left_door)) {
+ if (global[jacques_status]) { /* true means he is dead in some way */
+ text_show(text_111_40);
+ } else if (global[christine_door_status] == CHRIS_DOOR_CHOPPED) {
+ text_show(text_111_30);
+ } else if ((global[chris_kicked_raoul_out]) && (global[ticket_people_here] == SELLER)) {
+ text_show(text_111_36);
+ } else if ((global[christine_door_status] == CHRIS_DOOR_CLOSED) || (local->it_is_closed)) {
+ text_show(text_111_17);
+ } else if (global[christine_door_status] == CHRIS_IS_IN) {
+ text_show(text_111_16);
+ }
+ goto handled;
+ }
+
+ if (player_said_1(right_door)) {
+ text_show(text_111_17);
+ goto handled;
+ }
+ }
+
+ if (player_said_2(close, right_door)) {
+ text_show(text_111_28);
+ goto handled;
+ }
+
+ if (player_said_2(close, left_door)) {
+ if (local->it_is_closed) {
+ text_show(text_111_28);
+ } else if ((global[christine_door_status] == CHRIS_DOOR_CHOPPED) &&
+ (!global[ticket_people_here])) {
+ text_show(text_111_38);
+ } else if (global[christine_door_status] == CHRIS_DOOR_CLOSED) {
+ text_show(text_111_27);
+ } else if (global[christine_door_status] == CHRIS_IS_IN) {
+ text_show(text_111_25);
+ }
+ goto handled;
+ }
+
+ if (player_said_2(open, left_door)) {
+ if (global[christine_door_status] == CHRIS_IS_IN) {
+ text_show(text_111_26);
+ }
+ goto handled;
+ }
+
+ goto done;
+
+handled:
+ player.command_ready = false;
+
+done:
+ ;
+}
+
+
+void room_111_preload() {
+ room_init_code_pointer = room_111_init;
+ room_pre_parser_code_pointer = room_111_pre_parser;
+ room_parser_code_pointer = room_111_parser;
+ room_daemon_code_pointer = room_111_daemon;
+
+ if (global[current_year] == 1993) {
+ kernel_initial_variant = 1;
+ }
+
+ section_1_walker();
+ section_1_interface();
+}
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/rooms/room111.h b/engines/mads/madsv2/phantom/rooms/room111.h
new file mode 100644
index 00000000000..4963f98b180
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room111.h
@@ -0,0 +1,138 @@
+/* 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/>.
+ *
+ */
+
+/* room111.mac by Paul Lahaise 8-Jan-93 */
+
+#ifndef MADS_PHANTOM_ROOM111_H
+#define MADS_PHANTOM_ROOM111_H
+
+#include "mads/madsv2/phantom/rooms/section1.h"
+#include "mads/madsv2/phantom/global.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+#define local ((Scratch *)(&game.scratch[0]))
+#define ss local->sprite
+#define seq local->sequence
+#define aa local->animation
+
+typedef struct { /* Room local variables */
+
+ int sprite[15]; /* Sprite series handles */
+ int sequence[15]; /* Sequence handles */
+ int animation[4]; /* Animation handles */
+ int delete_axe; /* true if axe was deleted */
+ int anim_0_running;
+ int anim_1_running;
+ int listen_frame;
+ int listen_action;
+ int it_is_closed;
+
+} Scratch;
+
+
+/* ========================= Sprite Series ========================= */
+
+#define fx_take_9 0 /* rdr_9 */
+#define fx_1993 1 /* rm111z */
+#define fx_axe 2 /* rm111a1 */
+#define fx_broken_axe 3 /* rm111a2 */
+#define fx_open_door 4 /* rm111a3 */
+#define fx_door 5 /* rm111x0 */
+
+
+/* ========================= Conversation ========================== */
+
+#define CONV_LISTEN 14
+#define CONV14_LISTEN 0
+#define CONV14_UN_LISTEN 1
+
+
+/* ========================= Triggers ============================== */
+
+#define ROOM_111_MADE_IT_OUT_DOOR 60
+#define ROOM_111_CLOSED_DOOR 62
+#define ROOM_111_AT_LISTEN_POINT 64
+#define ROOM_111_LISTEN 66
+#define ROOM_111_UN_LISTEN 68
+#define ROOM_111_DONE_LISTENING 70
+#define ROOM_111_NOTHING 72
+
+
+/* ========================= Player positions ====================== */
+
+#define PLAYER_X_FROM_113 112
+#define PLAYER_Y_FROM_113 126
+
+#define PLAYER_X_FROM_113_SAWDUST 146
+#define PLAYER_Y_FROM_113_SAWDUST 108
+
+#define PLAYER_X_FROM_109 311
+#define PLAYER_Y_FROM_109 150
+
+#define OFF_SCREEN_X_FROM_109 335
+#define OFF_SCREEN_Y_FROM_109 150
+
+#define LISTEN_X 119
+#define LISTEN_Y 124
+
+
+/* ========================= Door approach positions =============== */
+
+#define FRONT_RIGHT_DOOR_X 219
+#define FRONT_RIGHT_DOOR_Y 131
+
+#define FRONT_LEFT_DOOR_X 109
+#define FRONT_LEFT_DOOR_Y 124
+
+#define WALK_TO_X_INSIDE_112 145
+#define WALK_TO_Y_INSIDE_112 108
+
+#define AFTER_AXE_ANIM_X 126
+#define AFTER_AXE_ANIM_Y 126
+
+
+/* ========================= Wall dynamic hotspot ================== */
+
+#define WALL_X 35
+#define WALL_Y 82
+#define WALL_X_SIZE 13
+#define WALL_Y_SIZE 11
+
+#define WALL_WALK_X 78
+#define WALL_WALK_Y 122
+
+
+extern void room_111_init();
+extern void room_111_daemon();
+extern void room_111_pre_parser();
+extern void room_111_parser();
+extern void room_111_preload();
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index 535a13e3eea..9489e0b3884 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -132,6 +132,7 @@ MODULE_OBJS += \
madsv2/phantom/rooms/room108.o \
madsv2/phantom/rooms/room109.o \
madsv2/phantom/rooms/room110.o \
+ madsv2/phantom/rooms/room111.o \
madsv2/phantom/phantom.o \
madsv2/phantom/conv.o \
madsv2/phantom/main_menu.o \
Commit: 62c5545ce7261882ee91e3953037e73e681ab0e6
https://github.com/scummvm/scummvm/commit/62c5545ce7261882ee91e3953037e73e681ab0e6
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:42+10:00
Commit Message:
MADS: PHANTOM: Added room 112
Changed paths:
A engines/mads/madsv2/phantom/rooms/room112.cpp
A engines/mads/madsv2/phantom/rooms/room112.h
engines/mads/madsv2/phantom/conv.h
engines/mads/madsv2/phantom/global.h
engines/mads/madsv2/phantom/mads/text.h
engines/mads/madsv2/phantom/mads/words.h
engines/mads/module.mk
diff --git a/engines/mads/madsv2/phantom/conv.h b/engines/mads/madsv2/phantom/conv.h
index e701ca65af1..83b2ffdb6f8 100644
--- a/engines/mads/madsv2/phantom/conv.h
+++ b/engines/mads/madsv2/phantom/conv.h
@@ -60,6 +60,25 @@ enum {
conv002_saytwo_abc = 26,
};
+enum {
+ conv003_bon_jour_hello = 0,
+ conv003_first_howdy = 1,
+ conv003_second_aloha = 2,
+ conv003_name_i_am = 3,
+ conv003_name_form = 4,
+ conv003_name_oops = 5,
+ conv003_adios_byebye= 6,
+ conv003_nomore_byebye = 7,
+ conv003_questions_three = 10,
+ conv003_knowghost_see = 13,
+ conv003_knowghost_look = 14,
+ conv003_return_dreams = 15,
+ conv003_return_she = 16,
+ conv003_return_giry = 18,
+ conv003_return_byebye = 23,
+ conv003_yourself_byebye = 27
+};
+
enum {
conv007_richard_intro_b = 2,
conv007_daaeb_intro_c = 3,
diff --git a/engines/mads/madsv2/phantom/global.h b/engines/mads/madsv2/phantom/global.h
index 4cac6ad593a..0d69f51e18c 100644
--- a/engines/mads/madsv2/phantom/global.h
+++ b/engines/mads/madsv2/phantom/global.h
@@ -215,6 +215,11 @@ enum {
#define CHRIS_DOOR_CLOSED 1
#define CHRIS_DOOR_CHOPPED 2
+// julie_name_is_known
+#define JULIE_NO 0
+#define NO_AND_QUIT_CONV 1
+#define JULIE_YES 2
+
} // namespace Phantom
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/mads/text.h b/engines/mads/madsv2/phantom/mads/text.h
index c6db14a4cd8..91927dc78f8 100644
--- a/engines/mads/madsv2/phantom/mads/text.h
+++ b/engines/mads/madsv2/phantom/mads/text.h
@@ -334,7 +334,38 @@ enum {
text_111_39 = 11139,
text_111_40 = 11140,
text_111_41 = 11141,
- text_111_42 = 11142
+ text_111_42 = 11142,
+
+ /* Room 112 */
+ text_112_10 = 11210,
+ text_112_11 = 11211,
+ text_112_12 = 11212,
+ text_112_13 = 11213,
+ text_112_14 = 11214,
+ text_112_15 = 11215,
+ text_112_16 = 11216,
+ text_112_17 = 11217,
+ text_112_18 = 11218,
+ text_112_19 = 11219,
+ text_112_20 = 11220,
+ text_112_21 = 11221,
+ text_112_22 = 11222,
+ text_112_23 = 11223,
+ text_112_24 = 11224,
+ text_112_25 = 11225,
+ text_112_26 = 11226,
+ text_112_27 = 11227,
+ text_112_28 = 11228,
+ text_112_29 = 11229,
+ /* text_112_30 not used */
+ text_112_31 = 11231,
+ text_112_32 = 11232,
+ text_112_33 = 11233,
+ text_112_34 = 11234,
+ text_112_35 = 11235,
+ text_112_36 = 11236,
+ text_112_37 = 11237,
+ text_112_38 = 11238
};
} // namespace Phantom
diff --git a/engines/mads/madsv2/phantom/mads/words.h b/engines/mads/madsv2/phantom/mads/words.h
index 6fe19d61780..227c06d5ed8 100644
--- a/engines/mads/madsv2/phantom/mads/words.h
+++ b/engines/mads/madsv2/phantom/mads/words.h
@@ -39,15 +39,19 @@ enum {
words_cable = 26,
words_carton = 28,
words_ceiling = 30,
+ words_chair = 31,
words_circular_staircase = 32,
words_climb_down = 33,
words_climb_through = 35,
words_column_prop = 36,
words_conductor_s_stand = 37,
+ words_corridor = 38,
words_counterweight_system = 40,
words_crate = 41,
words_cyclorama = 44,
words_door = 46,
+ words_dressing_screen = 48,
+ words_dressing_table = 49,
words_elephant_prop = 50,
words_exit = 52,
words_exit_sign = 54,
@@ -73,6 +77,7 @@ enum {
words_lockrail = 95,
words_look_at = 96,
words_look_through = 97,
+ words_mirror = 99,
words_music_stand = 103,
words_music_stands = 104,
words_orchestra_door = 107,
@@ -108,6 +113,7 @@ enum {
words_walk_down = 154,
words_walk_through = 155,
words_wall = 157,
+ words_wardrobe = 158,
words_waste_basket = 159,
words_water_pipe = 160,
words_yellow_frame = 163,
@@ -124,6 +130,17 @@ enum {
words_headset = 179,
words_grand_foyer = 180,
words_back_wall = 181,
+ words_ballet_bar = 182,
+ words_throw_rugs = 183,
+ words_costume_rack = 184,
+ words_coat_rack = 185,
+ words_paintings = 186,
+ words_umbrella = 187,
+ words_shelf = 188,
+ words_container = 189,
+ words_torn_poster = 190,
+ words_review = 191,
+ words_reviews = 192,
words_stage_right_wing = 193,
words_stage_left_wing = 194,
words_pedestal = 195,
@@ -140,6 +157,7 @@ enum {
words_door_chunks = 250,
words_bulletin_board = 252,
words_Monsieur_Brie = 258,
+ words_woman = 269,
words_prompter_s_stand = 270,
words_Jacques = 280,
words_gentleman = 281,
@@ -148,6 +166,7 @@ enum {
words_prompter_s_seat = 300,
words_lever = 301,
words_Monsieur_Richard = 302,
+ words_Julie = 303,
words_cable_hook = 304,
words_hook = 390,
words_paper = 399
diff --git a/engines/mads/madsv2/phantom/rooms/room112.cpp b/engines/mads/madsv2/phantom/rooms/room112.cpp
new file mode 100644
index 00000000000..325644a1aed
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room112.cpp
@@ -0,0 +1,698 @@
+/* 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 "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/imath.h"
+#include "mads/madsv2/core/text.h"
+#include "mads/madsv2/core/inter.h"
+#include "mads/madsv2/core/object.h"
+#include "mads/madsv2/core/sound.h"
+#include "mads/madsv2/phantom/global.h"
+#include "mads/madsv2/phantom/conv.h"
+#include "mads/madsv2/phantom/mads/inventory.h"
+#include "mads/madsv2/phantom/mads/speeches.h"
+#include "mads/madsv2/phantom/mads/words.h"
+#include "mads/madsv2/phantom/mads/sounds.h"
+#include "mads/madsv2/phantom/mads/text.h"
+#include "mads/madsv2/phantom/rooms/section1.h"
+#include "mads/madsv2/phantom/rooms/room112.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+static void handle_animation_julie_practice() {
+ int random = 0;
+ int julie_reset_frame;
+
+ if (kernel_anim[aa[0]].frame != local->julie_frame) {
+ local->julie_frame = kernel_anim[aa[0]].frame;
+ julie_reset_frame = -1;
+
+ switch (local->julie_frame) {
+ case 56: /* end of putting right arm up */
+ case 77: /* end of a tilting head back */
+ case 83: /* end of putting right arm down - then up */
+ random = imath_random(1, 3);
+ while (local->just_did_option == random) {
+ random = imath_random(1, 3);
+ } /* so we don't repeat the same option twice */
+ local->just_did_option = random;
+
+ switch (local->julie_action) {
+ case CONV3_JULIE_TALK:
+ case CONV3_JULIE_I_DUNNO:
+ random = 3;
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ julie_reset_frame = 71;
+ break; /* do a head tilt */
+
+ case 2:
+ julie_reset_frame = 77;
+ break; /* put right arm down - then up */
+
+ case 3:
+ julie_reset_frame = 56;
+ break; /* put right arm down */
+ }
+ break;
+
+ case 1: /* end of talk 1 */
+ case 2: /* end of talk 2 */
+ case 3: /* end of talk 3 */
+ case 22: /* end of init movements (just entered room) */
+ case 39: /* end of dipping */
+ case 71: /* end of putting right arm down */
+ case 107: /* end of turning left (facing camera) */
+
+ switch (local->julie_action) {
+
+ case CONV3_JULIE_PRACTICE:
+ random = imath_random(1, 3);
+ while (local->just_did_option == random) {
+ random = imath_random(1, 3);
+ }
+ local->just_did_option = random;
+ break;
+
+ case CONV3_JULIE_I_DUNNO:
+ random = 3;
+ break;
+
+ case CONV3_JULIE_TALK:
+ random = imath_random(4, 6);
+ ++local->julie_talk_count;
+ /* between the 3 talk movements */
+ if (local->julie_talk_count > 25) {
+ local->julie_action = CONV3_JULIE_PRACTICE;
+ }
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ julie_reset_frame = 22;
+ break; /* do a dip */
+
+ case 2:
+ julie_reset_frame = 39;
+ break; /* put right arm up */
+
+ case 3:
+ julie_reset_frame = 83;
+ break; /* turn right */
+
+ case 4:
+ julie_reset_frame = 0;
+ break; /* talk 1 */
+
+ case 5:
+ julie_reset_frame = 1;
+ break; /* talk 2 */
+
+ case 6:
+ julie_reset_frame = 2;
+ break; /* talk 3 */
+ }
+ break;
+
+ case 95: /* end of turning right */
+
+ switch (local->julie_action) {
+ case CONV3_JULIE_I_DUNNO:
+ random = 2;
+ break;
+
+ default:
+ random = 1;
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ julie_reset_frame = 95;
+ break; /* turn left (to face camera) */
+
+ case 2:
+ julie_reset_frame = 107;
+ break; /* give an "I don't know" type of an action */
+ /* used during player_verb = knowghost_see */
+ }
+ break;
+
+ case 130: /* end of an "I don't know" */
+ julie_reset_frame = 95;
+ local->julie_action = CONV3_JULIE_PRACTICE;
+ break; /* turn left (to face camera) */
+ }
+
+ if (julie_reset_frame >= 0) {
+ kernel_reset_animation(aa[0], julie_reset_frame);
+ local->julie_frame = julie_reset_frame;
+ }
+ }
+}
+
+static void handle_animation_raoul_chair() {
+ int random;
+ int raoul_reset_frame;
+
+ if (kernel_anim[aa[1]].frame != local->raoul_frame) {
+ local->raoul_frame = kernel_anim[aa[1]].frame;
+ raoul_reset_frame = -1;
+
+ switch (local->raoul_frame) {
+ case 18: /* end of freeze & sit down */
+ case 30: /* end of left hand point */
+ case 41: /* end of left hand up */
+ case 49: /* end of both hands up */
+ case 56: /* end of right hand point */
+ case 65: /* end of touch hand */
+
+ switch (local->raoul_action) {
+ case CONV3_RAOUL_INVISIBLE:
+ random = 6; /* turn invisible */
+ break;
+
+ case CONV3_RAOUL_GET_UP:
+ random = 5; /* get up */
+ local->raoul_action = CONV3_RAOUL_INVISIBLE;
+ break;
+
+ case CONV3_RAOUL_TALK:
+ random = imath_random(1, 4);
+ local->raoul_action = CONV3_RAOUL_SHUT_UP;
+ break;
+
+ default:
+ random = imath_random(7, 50);
+ while (local->just_did_option == random) {
+ random = imath_random(7, 50);
+ } /* so we don't repeat the same option twice */
+ local->just_did_option = random;
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ raoul_reset_frame = 49;
+ break; /* do a right hand point (talk 1) */
+
+ case 2:
+ raoul_reset_frame = 41;
+ break; /* put both hands up (talk 2) */
+
+ case 3:
+ raoul_reset_frame = 18;
+ break; /* do a left hand point (talk 3) */
+
+ case 4:
+ raoul_reset_frame = 30;
+ break; /* put left hand up (talk 4) */
+
+ case 5:
+ raoul_reset_frame = 65;
+ break; /* get up */
+
+ case 6:
+ raoul_reset_frame = 82;
+ break; /* invisible */
+
+ case 7:
+ raoul_reset_frame = 56;
+ break; /* touch head (new node) */
+
+ default:
+ raoul_reset_frame = 17;
+ break; /* freeze */
+ }
+ break;
+
+ case 61: /* hand on chin */
+
+ switch (local->raoul_action) {
+ case CONV3_RAOUL_SHUT_UP:
+ random = 1;
+ break;
+
+ default:
+ random = 2;
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ raoul_reset_frame = 60;
+ break; /* keep hand on chin */
+
+ case 2:
+ raoul_reset_frame = 61;
+ break; /* put hand down */
+ }
+ break;
+
+ case 83: /* end of invisible */
+
+ switch (local->raoul_action) {
+ case CONV3_RAOUL_INVISIBLE:
+ random = 1;
+ break;
+
+ default:
+ random = 2;
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ raoul_reset_frame = 82;
+ break; /* keep him invisible */
+
+ case 2:
+ raoul_reset_frame = 0;
+ break; /* make him sit down */
+ }
+ break;
+
+ case 82: /* player now has walker back */
+ local->raoul_action = CONV3_RAOUL_INVISIBLE;
+ player.walker_visible = true;
+ conv_release();
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_ANIM, aa[1]);
+ break;
+ }
+
+ if (raoul_reset_frame >= 0) {
+ kernel_reset_animation(aa[1], raoul_reset_frame);
+ local->raoul_frame = raoul_reset_frame;
+ }
+ }
+}
+
+void room_112_init() {
+ if (previous_room != KERNEL_RESTORING_GAME) {
+ local->raoul_action = CONV3_RAOUL_INVISIBLE;
+ local->just_did_option = 0;
+ local->display_wait = false;
+ }
+
+ /* =================== Load conversation ======================== */
+
+ conv_get(CONV_JULIE_PRACTICE);
+
+
+ /* ============== Run animation of julie practicing ============= */
+
+ aa[0] = kernel_run_animation(kernel_name('j', 1), 1);
+ local->anim_0_running = true;
+ local->julie_action = CONV3_JULIE_PRACTICE;
+ kernel_reset_animation(aa[0], 3); /* start Julie at frame 3 */
+
+ if (global[julie_name_is_known] == JULIE_YES) {
+ local->dynamic_julie = kernel_add_dynamic(words_Julie, words_walk_to, SYNTAX_SINGULAR_FEM, KERNEL_NONE,
+ DYNAMIC_JULIE_X, DYNAMIC_JULIE_Y,
+ DYNAMIC_JULIE_X_SIZE, DYNAMIC_JULIE_Y_SIZE);
+ kernel_dynamic_hot[local->dynamic_julie].prep = PREP_ON;
+ kernel_dynamic_walk(local->dynamic_julie, DYNAMIC_JULIE_WALK_TO_X, DYNAMIC_JULIE_WALK_TO_Y, FACING_NORTHEAST);
+ kernel_flip_hotspot(words_woman, false);
+ }
+ aa[1] = kernel_run_animation(kernel_name('r', 1), 1);
+ local->anim_1_running = true;
+ kernel_reset_animation(aa[1], 82); /* start Raoul at frame 82 (invisible) */
+ local->raoul_action = CONV3_RAOUL_INVISIBLE;
+
+
+ /* ===== If restoring into conv, run it & sit raoul down ======== */
+ /* ====================== Previous Rooms ======================== */
+
+ if (conv_restore_running == CONV_JULIE_PRACTICE) {
+ conv_run(CONV_JULIE_PRACTICE);
+ conv_export_pointer(&global[player_score]);
+ kernel_reset_animation(aa[1], 17); /* start Raoul at just sitting there */
+ local->raoul_action = CONV3_RAOUL_SHUT_UP;
+ player.x = CHAIR_X;
+ player.y = CHAIR_Y;
+ player.facing = FACING_EAST;
+ player.walker_visible = false;
+
+ } else if ((previous_room == 110) || (previous_room != KERNEL_RESTORING_GAME)) {
+ player.x = PLAYER_X_FROM_110;
+ player.y = PLAYER_Y_FROM_110;
+ player.facing = FACING_NORTH;
+ }
+
+ section_1_music();
+}
+
+void room_112_daemon() {
+ if (local->anim_0_running) {
+ handle_animation_julie_practice();
+ }
+
+ if (local->anim_1_running) {
+ handle_animation_raoul_chair();
+ }
+}
+
+static void process_conv_julie_practice() {
+ switch (player_verb) {
+ case conv003_return_byebye:
+ case conv003_yourself_byebye:
+ case conv003_questions_three:
+ case conv003_nomore_byebye:
+ case conv003_adios_byebye:
+ conv_you_trigger(ROOM_112_GET_UP); /* you */
+ global[julie_name_is_known] = JULIE_YES;
+ break;
+
+ case conv003_name_oops:
+ conv_you_trigger(ROOM_112_GET_UP);
+ global[julie_name_is_known] = NO_AND_QUIT_CONV;
+ break;
+
+ case conv003_first_howdy:
+ if (!kernel.trigger) {
+ if (local->raoul_action == CONV3_RAOUL_INVISIBLE) {
+ conv_you_trigger(ROOM_112_BEFORE_CHAIR);
+ }
+ }
+ break;
+
+ case conv003_knowghost_look:
+ case conv003_return_dreams:
+ case conv003_return_she:
+ local->julie_action = CONV3_JULIE_TALK;
+ local->raoul_action = CONV3_RAOUL_SHUT_UP;
+ break;
+
+ case conv003_name_i_am:
+ case conv003_name_form:
+ if (global[julie_name_is_known] < JULIE_YES) {
+ global[julie_name_is_known] = JULIE_YES;
+ kernel_flip_hotspot(words_woman, false);
+ local->dynamic_julie = kernel_add_dynamic(words_Julie, words_walk_to, SYNTAX_SINGULAR_FEM, KERNEL_NONE,
+ DYNAMIC_JULIE_X, DYNAMIC_JULIE_Y,
+ DYNAMIC_JULIE_X_SIZE, DYNAMIC_JULIE_Y_SIZE);
+ kernel_dynamic_hot[local->dynamic_julie].prep = PREP_ON;
+ kernel_dynamic_walk(local->dynamic_julie, DYNAMIC_JULIE_WALK_TO_X, DYNAMIC_JULIE_WALK_TO_Y, FACING_NORTHEAST);
+ }
+ break;
+
+ case conv003_knowghost_see:
+ local->julie_action = CONV3_JULIE_I_DUNNO;
+ local->raoul_action = CONV3_RAOUL_SHUT_UP;
+ break;
+ }
+
+ switch (kernel.trigger) {
+ case ROOM_112_GET_UP:
+ local->raoul_action = CONV3_RAOUL_GET_UP;
+ conv_hold();
+ break;
+
+ case ROOM_112_BEFORE_CHAIR:
+ kernel_timing_trigger(TWO_SECONDS, ROOM_112_BETWEEN_CHAIR);
+ conv_hold(); /* hold so options don't appear in interface */
+ break;
+
+ case ROOM_112_BETWEEN_CHAIR:
+ player_walk(CHAIR_X, CHAIR_Y, FACING_EAST);
+ player_walk_trigger(ROOM_112_AT_CHAIR);
+ break; /* give a 3 sec. delay before walking to chair */
+
+ case ROOM_112_AT_CHAIR:
+ conv_release();
+ player.walker_visible = false;
+ kernel_synch(KERNEL_ANIM, aa[1], KERNEL_PLAYER, 0);
+ kernel_reset_animation(aa[1], 1);
+ local->raoul_action = CONV3_RAOUL_SHUT_UP;
+ /* when made it to chair, run frame 1 of sitting him down */
+ /* and make options appear in interface */
+ break;
+
+ case ROOM_112_RAOUL_TALK:
+ local->julie_action = CONV3_JULIE_PRACTICE;
+ if (local->raoul_action != CONV3_RAOUL_INVISIBLE) {
+ local->raoul_action = CONV3_RAOUL_TALK;
+ }
+ break;
+
+ case ROOM_112_JULIE_TALK:
+ local->julie_action = CONV3_JULIE_TALK;
+ local->raoul_action = CONV3_RAOUL_SHUT_UP;
+ break;
+ }
+
+ if ((player_verb != conv003_first_howdy) &&
+ (player_verb != conv003_bon_jour_hello) &&
+ (player_verb != conv003_name_oops) &&
+ (player_verb != conv003_return_byebye) &&
+ (player_verb != conv003_yourself_byebye) &&
+ (player_verb != conv003_questions_three) &&
+ (player_verb != conv003_nomore_byebye) &&
+ (player_verb != conv003_second_aloha) &&
+ (player_verb != conv003_adios_byebye)) {
+ conv_you_trigger(ROOM_112_JULIE_TALK);
+ conv_me_trigger(ROOM_112_RAOUL_TALK);
+ }
+
+ if (player_verb == conv003_return_giry) {
+ global[can_find_book_library] = true;
+ }
+
+ local->julie_talk_count = 0;
+ local->raoul_talk_count = 0;
+}
+
+void room_112_pre_parser() {
+ /* if we want to talk to Julie and she has already told us to sit down
+ in the past, then automatically make Raoul walk to chair */
+ if ((player_said_2(talk_to, Julie)) ||
+ (player_said_2(talk_to, woman))) {
+ if (global[julie_name_is_known] > JULIE_NO) {
+ player_walk(CHAIR_X, CHAIR_Y, FACING_EAST);
+ }
+ }
+}
+
+void room_112_parser() {
+ if (conv_control.running == CONV_JULIE_PRACTICE) {
+ process_conv_julie_practice();
+ goto handled;
+ }
+
+ if ((player_said_2(talk_to, Julie)) ||
+ (player_said_2(talk_to, woman))) {
+ if (global[julie_name_is_known] > JULIE_NO) {
+ /* if we want to talk to Julie and she has already told us to sit down
+ in the past, then automatically make Raoul sit down in chair */
+ player.walker_visible = false;
+ kernel_synch(KERNEL_ANIM, aa[1], KERNEL_PLAYER, 0);
+ kernel_reset_animation(aa[1], 1);
+ local->raoul_action = CONV3_RAOUL_SHUT_UP;
+ }
+ conv_run(CONV_JULIE_PRACTICE);
+ conv_export_pointer(&global[player_score]);
+ goto handled;
+ }
+
+ if (player_said_2(exit_to, corridor)) {
+ new_room = 110;
+ goto handled;
+ }
+
+ if (player.look_around) {
+ text_show(text_112_10);
+ goto handled;
+ }
+
+ if (player_said_1(look) || player_said_1(look_at)) {
+ if (player_said_1(wall)) {
+ text_show(text_112_11);
+ goto handled;
+ }
+
+ if (player_said_1(floor)) {
+ text_show(text_112_12);
+ goto handled;
+ }
+
+ if (player_said_1(mirror)) {
+ text_show(text_112_13);
+ goto handled;
+ }
+
+ if (player_said_1(ballet_bar)) {
+ text_show(text_112_14);
+ goto handled;
+ }
+
+ if (player_said_1(corridor)) {
+ text_show(text_112_15);
+ goto handled;
+ }
+
+ if (player_said_1(throw_rugs)) {
+ text_show(text_112_16);
+ goto handled;
+ }
+
+ if (player_said_1(dressing_screen)) {
+ text_show(text_112_17);
+ goto handled;
+ }
+
+ if (player_said_1(dressing_table)) {
+ text_show(text_112_18);
+ goto handled;
+ }
+
+ if (player_said_1(chair)) {
+ text_show(text_112_19);
+ goto handled;
+ }
+
+ if (player_said_1(plant)) {
+ text_show(text_112_20);
+ goto handled;
+ }
+
+ if (player_said_1(coat_rack)) {
+ text_show(text_112_21);
+ goto handled;
+ }
+
+ if (player_said_1(umbrella)) {
+ text_show(text_112_22);
+ goto handled;
+ }
+
+ if (player_said_1(paintings)) {
+ text_show(text_112_23);
+ goto handled;
+ }
+
+ if (player_said_1(trash_bucket)) {
+ text_show(text_112_24);
+ goto handled;
+ }
+
+ if (player_said_1(shelf)) {
+ text_show(text_112_25);
+ goto handled;
+ }
+
+ if (player_said_1(container)) {
+ text_show(text_112_26);
+ goto handled;
+ }
+
+ if (player_said_1(torn_poster)) {
+ text_show(text_112_27);
+ goto handled;
+ }
+
+ if (player_said_1(poster)) {
+ text_show(text_112_28);
+ goto handled;
+ }
+
+ if ((player_said_1(review)) || (player_said_1(reviews))) {
+ text_show(text_112_29);
+ goto handled;
+ }
+
+ if (player_said_1(Julie)) {
+ text_show(text_112_31);
+ goto handled;
+ }
+
+ if (player_said_1(costume_rack)) {
+ text_show(text_112_32);
+ goto handled;
+ }
+
+ if (player_said_1(light_fixture)) {
+ text_show(text_112_33);
+ goto handled;
+ }
+
+ if (player_said_1(wardrobe)) {
+ text_show(text_112_34);
+ goto handled;
+ }
+
+ if (player_said_1(woman)) {
+ text_show(text_112_37);
+ goto handled;
+ }
+ }
+
+ if (player_said_1(take)) {
+ if (player_said_1(woman) || player_said_1(Julie)) {
+ text_show(text_112_38);
+ goto handled;
+ }
+ }
+
+ if (player_said_2(open, wardrobe)) {
+ text_show(text_112_35);
+ goto handled;
+ }
+
+ if (player_said_2(open, container)) {
+ text_show(text_112_36);
+ goto handled;
+ }
+
+ goto done;
+
+handled:
+ player.command_ready = false;
+
+done:
+ ;
+}
+
+
+void room_112_preload() {
+ room_init_code_pointer = room_112_init;
+ room_pre_parser_code_pointer = room_112_pre_parser;
+ room_parser_code_pointer = room_112_parser;
+ room_daemon_code_pointer = room_112_daemon;
+
+ section_1_walker();
+ section_1_interface();
+
+ vocab_make_active(words_woman);
+ vocab_make_active(words_Julie);
+}
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/rooms/room112.h b/engines/mads/madsv2/phantom/rooms/room112.h
new file mode 100644
index 00000000000..6f2dca80ad2
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room112.h
@@ -0,0 +1,114 @@
+/* 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/>.
+ *
+ */
+
+/* room112.mac by Paul Lahaise 8-Jan-93 */
+
+#ifndef MADS_PHANTOM_ROOM112_H
+#define MADS_PHANTOM_ROOM112_H
+
+#include "mads/madsv2/phantom/rooms/section1.h"
+#include "mads/madsv2/phantom/global.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+#define local ((Scratch *)(&game.scratch[0]))
+#define ss local->sprite
+#define seq local->sequence
+#define aa local->animation
+
+typedef struct { /* Room local variables */
+
+ int sprite[15]; /* Sprite series handles */
+ int sequence[15]; /* Sequence handles */
+ int animation[4]; /* Animation handles */
+ int dynamic_julie; /* For dynamic HS of Julie */
+ int anim_0_running; /* T if Julie's practicing anim is running */
+ int anim_1_running; /* T if Raoul's chair movement anim is running */
+ int just_did_option;
+ int julie_frame;
+ int julie_action;
+ int julie_talk_count;
+ int raoul_frame;
+ int raoul_action;
+ int raoul_talk_count;
+ int display_wait; /* for getting up out of the chair */
+
+} Scratch;
+
+
+/* ========================= Conversation ========================== */
+
+#define CONV_JULIE_PRACTICE 3
+
+#define CONV3_JULIE_TALK 0
+#define CONV3_JULIE_I_DUNNO 1
+#define CONV3_JULIE_PRACTICE 2
+
+#define CONV3_RAOUL_TALK 0
+#define CONV3_RAOUL_SHUT_UP 1
+#define CONV3_RAOUL_INVISIBLE 2
+#define CONV3_RAOUL_GET_UP 3
+
+
+/* ========================= Triggers ============================== */
+
+#define ROOM_112_JULIE_TALK 60
+#define ROOM_112_RAOUL_TALK 62
+#define ROOM_112_BEFORE_CHAIR 68
+#define ROOM_112_BETWEEN_CHAIR 70
+#define ROOM_112_AT_CHAIR 72
+#define ROOM_112_GET_UP 74
+
+
+/* ========================= Player positions ====================== */
+
+#define PLAYER_X_FROM_110 128
+#define PLAYER_Y_FROM_110 145
+
+#define CHAIR_X 53
+#define CHAIR_Y 128
+
+
+/* ========================= Julie dynamic hotspot ================= */
+
+#define DYNAMIC_JULIE_X 255
+#define DYNAMIC_JULIE_Y 82
+#define DYNAMIC_JULIE_X_SIZE 30
+#define DYNAMIC_JULIE_Y_SIZE 44
+#define DYNAMIC_JULIE_WALK_TO_X 216
+#define DYNAMIC_JULIE_WALK_TO_Y 137
+
+
+extern void room_112_init();
+extern void room_112_daemon();
+extern void room_112_pre_parser();
+extern void room_112_parser();
+extern void room_112_preload();
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index 9489e0b3884..3568894ae81 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -133,6 +133,7 @@ MODULE_OBJS += \
madsv2/phantom/rooms/room109.o \
madsv2/phantom/rooms/room110.o \
madsv2/phantom/rooms/room111.o \
+ madsv2/phantom/rooms/room112.o \
madsv2/phantom/phantom.o \
madsv2/phantom/conv.o \
madsv2/phantom/main_menu.o \
Commit: 52496755a6c48caa17b9f8c397f48dd29eaabb99
https://github.com/scummvm/scummvm/commit/52496755a6c48caa17b9f8c397f48dd29eaabb99
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:42+10:00
Commit Message:
MADS: PHANTOM: Added room 113
Note that there were numerous changes to the constants used by the room.
I did the best I could to figure out the new values using a disassembly.
But the fact that there were changes could mean that this room had some
code changes as well that may need investigating.
Changed paths:
A engines/mads/madsv2/phantom/rooms/room113.cpp
A engines/mads/madsv2/phantom/rooms/room113.h
engines/mads/madsv2/core/speech.h
engines/mads/madsv2/phantom/conv.h
engines/mads/madsv2/phantom/global.h
engines/mads/madsv2/phantom/mads/sounds.h
engines/mads/madsv2/phantom/mads/text.h
engines/mads/madsv2/phantom/mads/words.h
engines/mads/module.mk
diff --git a/engines/mads/madsv2/core/speech.h b/engines/mads/madsv2/core/speech.h
index c79a369ed81..d3d2e198ef7 100644
--- a/engines/mads/madsv2/core/speech.h
+++ b/engines/mads/madsv2/core/speech.h
@@ -38,6 +38,7 @@ extern bool speech_system_active;
extern bool speech_on;
extern int speech_ems_handle;
extern SpeechBuffer speech_main_buffer;
+extern int global_speech_ready;
extern SpeechDirPtr speech_load(const char *resName, int id, bool);
extern void speech_ems_play(const char *resName, int id);
diff --git a/engines/mads/madsv2/phantom/conv.h b/engines/mads/madsv2/phantom/conv.h
index 83b2ffdb6f8..31f11b00911 100644
--- a/engines/mads/madsv2/phantom/conv.h
+++ b/engines/mads/madsv2/phantom/conv.h
@@ -79,6 +79,22 @@ enum {
conv003_yourself_byebye = 27
};
+enum {
+ conv004_bon_jour_hello = 0,
+ conv004_who_who_are = 1,
+ conv004_monsieur_again = 2,
+ conv004_name_raoul = 3,
+ conv004_name_dear = 4,
+ conv004_name_sorry = 5,
+ conv004_anything_take = 19,
+ conv004_imgone_bye = 25,
+ conv004_dontleave_help = 26,
+ conv004_promises_continue = 27,
+ conv004_promises_return = 28,
+ conv004_promises_cant = 29,
+ conv004_promises_safe = 30
+};
+
enum {
conv007_richard_intro_b = 2,
conv007_daaeb_intro_c = 3,
@@ -114,6 +130,16 @@ enum {
conv012_nomore_first = 30
};
+enum {
+ conv013_intro_hello = 0,
+ conv013_returned_abc = 1,
+ conv013_again_abc = 2,
+ conv013_dreams_romantic = 19,
+ conv013_lovescene_openline = 21,
+ conv013_practice_first = 27,
+ conv013_biteme_b_b = 31
+};
+
enum {
conv014_second_angel = 1,
conv014_eighth_inside = 7
diff --git a/engines/mads/madsv2/phantom/global.h b/engines/mads/madsv2/phantom/global.h
index 0d69f51e18c..2ed1a3b4d48 100644
--- a/engines/mads/madsv2/phantom/global.h
+++ b/engines/mads/madsv2/phantom/global.h
@@ -196,6 +196,7 @@ enum {
// player_score_flags
#define SCORE_TRAP_DOOR 1
+#define SCORE_DEAD_FLORENT 4
// ticket_people_here
#define SELLER 1
@@ -220,6 +221,13 @@ enum {
#define NO_AND_QUIT_CONV 1
#define JULIE_YES 2
+// done_brie_conv_203
+#define YES_AND_CHASE 3
+
+// chris_kicked_raoul_out
+#define CHRIS_KICKED_YES -1
+#define CAME_INTO_EMPTY_113 3
+
} // namespace Phantom
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/mads/sounds.h b/engines/mads/madsv2/phantom/mads/sounds.h
index 8af908f19ae..f311bb42509 100644
--- a/engines/mads/madsv2/phantom/mads/sounds.h
+++ b/engines/mads/madsv2/phantom/mads/sounds.h
@@ -35,6 +35,7 @@ enum {
N_DoorOpens = 24,
N_DoorCloses = 25,
N_TakeObjectSnd = 26,
+ N_AngelMus001 = 34,
N_BackMus1stTime = 38,
N_TrapDoor001 = 64,
N_SqueakyDoor = 66,
diff --git a/engines/mads/madsv2/phantom/mads/text.h b/engines/mads/madsv2/phantom/mads/text.h
index 91927dc78f8..d38980a1e83 100644
--- a/engines/mads/madsv2/phantom/mads/text.h
+++ b/engines/mads/madsv2/phantom/mads/text.h
@@ -31,6 +31,8 @@ namespace Phantom {
/* Formula: text_RRR_NN = RRR * 100 + NN */
enum {
+ text_008_06 = 806,
+
/* Room 101 */
text_101_10 = 10110,
text_101_11 = 10111,
@@ -365,7 +367,50 @@ enum {
text_112_35 = 11235,
text_112_36 = 11236,
text_112_37 = 11237,
- text_112_38 = 11238
+ text_112_38 = 11238,
+
+ /* Room 113 */
+ text_113_10 = 11310,
+ text_113_11 = 11311,
+ text_113_12 = 11312,
+ text_113_13 = 11313,
+ text_113_14 = 11314,
+ text_113_15 = 11315,
+ text_113_16 = 11316,
+ text_113_17 = 11317,
+ text_113_18 = 11318,
+ text_113_19 = 11319,
+ text_113_20 = 11320,
+ text_113_21 = 11321,
+ text_113_22 = 11322,
+ text_113_23 = 11323,
+ text_113_24 = 11324,
+ text_113_25 = 11325,
+ text_113_26 = 11326,
+ text_113_27 = 11327,
+ text_113_28 = 11328,
+ text_113_29 = 11329,
+ text_113_30 = 11330,
+ text_113_31 = 11331,
+ text_113_32 = 11332,
+ text_113_33 = 11333,
+ text_113_34 = 11334,
+ text_113_35 = 11335,
+ text_113_36 = 11336,
+ text_113_37 = 11337,
+ text_113_38 = 11338,
+ text_113_39 = 11339,
+ text_113_40 = 11340,
+ text_113_41 = 11341,
+ text_113_42 = 11342,
+ text_113_43 = 11343,
+ text_113_44 = 11344,
+ text_113_45 = 11345,
+ text_113_46 = 11346,
+ text_113_47 = 11347,
+ text_113_48 = 11348,
+ text_113_49 = 11349,
+ text_113_50 = 11350
};
} // namespace Phantom
diff --git a/engines/mads/madsv2/phantom/mads/words.h b/engines/mads/madsv2/phantom/mads/words.h
index 227c06d5ed8..e9628e79655 100644
--- a/engines/mads/madsv2/phantom/mads/words.h
+++ b/engines/mads/madsv2/phantom/mads/words.h
@@ -46,6 +46,7 @@ enum {
words_column_prop = 36,
words_conductor_s_stand = 37,
words_corridor = 38,
+ words_couch = 39,
words_counterweight_system = 40,
words_crate = 41,
words_cyclorama = 44,
@@ -57,6 +58,7 @@ enum {
words_exit_sign = 54,
words_exit_to = 55,
words_exposed_brick = 67,
+ words_fan = 68,
words_fire_axe = 69,
words_flats = 72,
words_floor = 73,
@@ -78,10 +80,13 @@ enum {
words_look_at = 96,
words_look_through = 97,
words_mirror = 99,
+ words_mural = 101,
words_music_stand = 103,
words_music_stands = 104,
+ words_notice = 106,
words_orchestra_door = 107,
words_orchestra_pit = 108,
+ words_painting = 109,
words_pipe = 112,
words_pit = 113,
words_plant = 114,
@@ -93,9 +98,11 @@ enum {
words_purchase_lines = 120,
words_railing = 121,
words_red_frame = 123,
+ words_rug = 126,
words_sandbag = 127,
words_seats = 129,
words_side_wall = 130,
+ words_small_note = 131,
words_stage = 132,
words_stage_left = 134,
words_stage_right = 135,
@@ -112,6 +119,7 @@ enum {
words_walk_across = 153,
words_walk_down = 154,
words_walk_through = 155,
+ words_walk_up = 156,
words_wall = 157,
words_wardrobe = 158,
words_waste_basket = 159,
@@ -156,7 +164,9 @@ enum {
words_axe = 249,
words_door_chunks = 250,
words_bulletin_board = 252,
+ words_dressing_gown = 257,
words_Monsieur_Brie = 258,
+ words_Christine = 268,
words_woman = 269,
words_prompter_s_stand = 270,
words_Jacques = 280,
@@ -168,6 +178,9 @@ enum {
words_Monsieur_Richard = 302,
words_Julie = 303,
words_cable_hook = 304,
+ words_hat_rack = 340,
+ words_vase = 341,
+ words_clothes_dummy = 342,
words_hook = 390,
words_paper = 399
};
diff --git a/engines/mads/madsv2/phantom/rooms/room113.cpp b/engines/mads/madsv2/phantom/rooms/room113.cpp
new file mode 100644
index 00000000000..4d6a2fef1eb
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room113.cpp
@@ -0,0 +1,1612 @@
+/* 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 "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/imath.h"
+#include "mads/madsv2/core/text.h"
+#include "mads/madsv2/core/inter.h"
+#include "mads/madsv2/core/object.h"
+#include "mads/madsv2/core/sound.h"
+#include "mads/madsv2/core/speech.h"
+#include "mads/madsv2/phantom/global.h"
+#include "mads/madsv2/phantom/conv.h"
+#include "mads/madsv2/phantom/mads/inventory.h"
+#include "mads/madsv2/phantom/mads/speeches.h"
+#include "mads/madsv2/phantom/mads/words.h"
+#include "mads/madsv2/phantom/mads/sounds.h"
+#include "mads/madsv2/phantom/mads/text.h"
+#include "mads/madsv2/phantom/rooms/section1.h"
+#include "mads/madsv2/phantom/rooms/room113.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+static void handle_animation_florent() {
+ int random;
+ int florent_reset_frame;
+
+ if (kernel_anim[aa[2]].frame != local->florent_frame) {
+ local->florent_frame = kernel_anim[aa[2]].frame;
+ florent_reset_frame = -1;
+
+ switch (local->florent_frame) {
+ case 1: /* end of freeze (at mirror) */
+ case 11: /* end of pointing (and back to mirror) */
+ case 23: /* end of brush hair (and back to mirror) */
+ case 38: /* end talking offsets (and back to mirror) */
+ case 45: /* end holding hand */
+
+ random = imath_random(4, 30);
+
+ if (local->florent_action == CONV4_FLORENT_POINT) {
+ random = 1;
+ }
+
+ if (local->florent_action == CONV4_FLORENT_TALK) {
+ random = 2;
+ }
+
+ if (local->florent_action == CONV4_FLORENT_HOLD_HAND) {
+ random = 3;
+ }
+
+ switch (random) {
+ case 1:
+ florent_reset_frame = 2;
+ local->florent_action = CONV4_FLORENT_SHUT_UP;
+ break; /* do point */
+
+ case 2:
+ florent_reset_frame = 28;
+ break; /* go to talking offsets */
+
+ case 3:
+ florent_reset_frame = 39;
+ break; /* go to hold hand */
+
+ case 4:
+ florent_reset_frame = 12;
+ break; /* do brush hair */
+
+ default:
+ florent_reset_frame = 0;
+ break; /* freeze looking at mirror */
+ }
+ break;
+
+ case 33: /* end of move to talking offsets */
+ case 24: /* end of talking 1 */
+ case 25: /* end of talking 2 */
+ case 26: /* end of talking 3 */
+ case 27: /* end of talking 4 */
+
+ random = imath_random(5, 20);
+
+ if (local->florent_action == CONV4_FLORENT_TALK) {
+ random = imath_random(1, 4);
+ ++local->florent_talk_count;
+ if (local->florent_talk_count > 5) {
+ local->florent_action = CONV4_FLORENT_SHUT_UP;
+ random = 5;
+ }
+ }
+
+ if ((local->florent_action == CONV4_FLORENT_POINT) ||
+ (local->florent_action == CONV4_FLORENT_HOLD_HAND)) {
+ random = 5;
+ }
+
+ switch (random) {
+ case 1:
+ florent_reset_frame = 23;
+ break; /* do talk 1 */
+
+ case 2:
+ florent_reset_frame = 24;
+ break; /* do talk 2 */
+
+ case 3:
+ florent_reset_frame = 25;
+ break; /* do talk 3 */
+
+ case 4:
+ florent_reset_frame = 26;
+ break; /* do talk 4 */
+
+ case 5:
+ florent_reset_frame = 34;
+ break; /* look at mirror */
+
+ default:
+ florent_reset_frame = 32;
+ break; /* freeze while pointing */
+ }
+ break;
+
+ case 42: /* end of holding hand */
+
+ if (local->florent_action == CONV4_FLORENT_HOLD_HAND) {
+ florent_reset_frame = 41; /* keep holding hand */
+ }
+ break;
+ }
+
+ if (florent_reset_frame >= 0) {
+ kernel_reset_animation(aa[2], florent_reset_frame);
+ local->florent_frame = florent_reset_frame;
+ }
+ }
+}
+
+static void handle_animation_13_day() {
+ int random;
+ int day_reset_frame;
+
+ if (kernel_anim[aa[0]].frame != local->day_frame) {
+ local->day_frame = kernel_anim[aa[0]].frame;
+ day_reset_frame = -1;
+
+ switch (local->day_frame) {
+ case 205: /* just finished walking away from him */
+ case 212: /* she has back to him, by mirror - freeze her there */
+ day_reset_frame = 211;
+ break;
+
+ case 182: /* player now has walker back; he can only try to talk to her & leave */
+ player.walker_visible = true;
+ conv_release();
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_ANIM, aa[1]);
+ player.x = PLAYER_X_AFTER_CONV13;
+ player.y = PLAYER_Y_AFTER_CONV13;
+ player.turn_to_facing = FACING_NORTHEAST;
+ player_demand_facing(FACING_SOUTHEAST);
+ player.turn_to_facing = FACING_NORTHEAST;
+ break;
+
+ case 1: /* end of looking at mirror */
+ case 4: /* end of first talk */
+ case 14: /* end of wave at Raoul */
+ case 17: /* end of second talk */
+ case 20: /* end of third talk */
+ case 26: /* end of looking toward Raoul */
+ case 166: /* end of both of them shutting up */
+ case 206: /* end of day talk while standing 1 */
+ case 207: /* end of day talk while standing 2 */
+ case 208: /* end of day talk while standing 3 */
+ case 209: /* end of raoul talk while standing 1 */
+ case 210: /* end of raoul talk while standing 2 */
+ case 211: /* end of raoul talk while standing 3 */
+ case 219: /* end of brush hair 1 */
+ case 231: /* end of brush hair 2 */
+ case 253: /* end of brush hair 3 */
+ switch (local->day_action) {
+ case CONV13_DAY_STAND_TALK:
+ day_reset_frame = imath_random(205, 207);
+ ++local->stand_talk_count;
+ if (local->stand_talk_count > 18) {
+ local->day_action = CONV13_BOTH_SHUT_UP;
+ day_reset_frame = 165;
+ }
+ if (local->music_is_playing) {
+ day_reset_frame = 167;
+ }
+ break; /* choose random if she is talking while standing */
+
+ case CONV13_DAY_STAND_SHUT_UP:
+ day_reset_frame = imath_random(208, 210);
+ while (local->just_did_option == day_reset_frame) {
+ day_reset_frame = imath_random(208, 210);
+ } /* so we don't repeat the same option twice */
+ local->just_did_option = day_reset_frame;
+
+ ++local->stand_talk_count;
+ if (local->stand_talk_count > 18) {
+ local->day_action = CONV13_BOTH_SHUT_UP;
+ day_reset_frame = 165;
+ }
+
+ if (local->music_is_playing) {
+ day_reset_frame = 167;
+ } /* if music is playing, make then separate */
+ break; /* choose random if he is talking while standing */
+
+ case CONV13_BOTH_SHUT_UP:
+ day_reset_frame = 165;
+ if (local->music_is_playing) {
+ day_reset_frame = 167;
+ } /* if music is playing, make then separate */
+ break; /* make them both shut up while standing */
+
+ case CONV13_DAY_WAVE:
+ day_reset_frame = 5; /* make Day wave at Raoul */
+ local->day_action = CONV13_DAY_TALK;
+ break;
+
+ case CONV13_DAY_MIRROR:
+ random = imath_random(1, 50);
+ switch (random) {
+ case 1:
+ day_reset_frame = 212;
+ break; /* do brush hair 1 */
+
+ case 2:
+ day_reset_frame = 219;
+ break; /* do brush hair 2 */
+
+ case 3:
+ day_reset_frame = 231;
+ break; /* do brush hair 3 */
+
+ default:
+ day_reset_frame = 0; /* make Day keep looking at mirror */
+ break;
+ }
+ break;
+
+ case CONV13_DAY_GET_READY_TALK:
+ if (local->day_wants_to_talk) {
+ local->day_action = CONV13_DAY_TALK;
+ local->day_wants_to_talk = false;
+ day_reset_frame = 1;
+ } else {
+ day_reset_frame = 25;
+ }
+ break;
+
+ case CONV13_DAY_TALK:
+ random = imath_random(1, 3); /* Between 3 talking movements. */
+ ++local->day_talk_count; /* Run through day_talk_count talking */
+ /* cycles before shutting up (looking */
+ /* toward Raoul) */
+ if (local->day_talk_count < 6) {
+ if (random == 1) {
+ day_reset_frame = 1; /* start first talk */
+ } else if (random == 2) {
+ day_reset_frame = 15; /* start second talk */
+ } else {
+ day_reset_frame = 18; /* start third talk */
+ }
+ } else {
+ local->day_action = CONV13_DAY_GET_READY_TALK;
+ day_reset_frame = 25;
+ local->day_wants_to_talk = false;
+ }
+ break;
+
+ case CONV13_DAY_GET_UP:
+ day_reset_frame = 31; /* start getting up & going toward Raoul */
+ break;
+ }
+ break;
+ }
+
+ if (day_reset_frame >= 0) {
+ kernel_reset_animation(aa[0], day_reset_frame);
+ local->day_frame = day_reset_frame;
+ }
+ }
+}
+
+static void handle_animation_4_raoul() {
+ int raoul_reset_frame;
+
+ if (global[florent_name_is_known] == YES_AND_END_CONV) {
+ local->raoul_action = CONV4_RAOUL_INVISIBLE;
+ }
+
+ if (kernel_anim[aa[3]].frame != local->raoul_frame) {
+ local->raoul_frame = kernel_anim[aa[3]].frame;
+ raoul_reset_frame = -1;
+
+ switch (local->raoul_frame) {
+
+ case 9: /* end of first open mouth and freeze */
+ case 10: /* end of second open mouth */
+ case 11: /* end of third open mouth */
+ case 34: /* end of invisible frame */
+ case 33: /* end of take_note */
+
+ if (local->raoul_frame == 33) {
+ conv_release();
+ }
+
+ switch (local->raoul_action) {
+
+ case CONV4_RAOUL_TAKE_NOTE:
+ raoul_reset_frame = 20;
+ local->raoul_action = CONV4_RAOUL_SHUT_UP;
+ break;
+
+ case CONV4_RAOUL_GET_UP:
+ raoul_reset_frame = 38; /* make Raoul get up */
+ local->raoul_is_up = true;
+ conv_hold();
+ break;
+
+ case CONV4_RAOUL_SHUT_UP:
+ raoul_reset_frame = 8; /* make Raoul frozen */
+ break;
+
+ case CONV4_RAOUL_TALK:
+ raoul_reset_frame = imath_random(7, 9); /* between 3 talking frames */
+ ++local->raoul_talk_count; /* run through so many talk cycles */
+
+ if (local->raoul_talk_count > 17) {
+ local->raoul_action = CONV4_RAOUL_SHUT_UP;
+ raoul_reset_frame = 8; /* make Raoul frozen */
+ }
+ break;
+
+ case CONV4_RAOUL_INVISIBLE:
+ raoul_reset_frame = 33; /* keep Raoul invisible */
+ break;
+
+ case CONV4_RAOUL_CHIN:
+ raoul_reset_frame = 11; /* put hand on chin */
+ break;
+ }
+ break;
+
+ case 42: /* end of getting up */
+
+ switch (local->raoul_action) {
+
+ case CONV4_RAOUL_GET_UP:
+ if (!local->prevent_2) {
+ conv_release();
+ }
+ raoul_reset_frame = 33; /* keep Raoul invisible */
+ local->raoul_action = CONV4_RAOUL_INVISIBLE;
+ player.walker_visible = true;
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_ANIM, aa[3]);
+ break;
+ }
+ break;
+
+ case 19: /* end of hand on chin */
+ if ((local->raoul_action == CONV4_RAOUL_TAKE_NOTE) && (!player_has(small_note))) {
+ raoul_reset_frame = 20; /* make Raoul talk */
+ local->raoul_action = CONV4_RAOUL_SHUT_UP;
+
+ } else if (local->raoul_action == CONV4_RAOUL_GET_UP) {
+ raoul_reset_frame = 38; /* make Raoul get up */
+ local->raoul_is_up = true;
+
+ } else if (local->raoul_action == CONV4_RAOUL_TALK) {
+ raoul_reset_frame = 9; /* make Raoul talk */
+
+ } else {
+ raoul_reset_frame = 8; /* make Raoul frozen */
+ local->raoul_action = CONV4_RAOUL_SHUT_UP;
+ }
+ break;
+ }
+
+ if (raoul_reset_frame >= 0) {
+ kernel_reset_animation(aa[3], raoul_reset_frame);
+ local->raoul_frame = raoul_reset_frame;
+ }
+ }
+}
+
+static void handle_animation_13_raoul() {
+ int raoul_reset_frame;
+
+ if (kernel_anim[aa[1]].frame != local->raoul_frame) {
+ local->raoul_frame = kernel_anim[aa[1]].frame;
+ raoul_reset_frame = -1;
+
+ switch (local->raoul_frame) {
+ case 9: /* end of first open mouth and freeze */
+ case 10: /* end of second open mouth */
+ case 11: /* end of third open mouth */
+ case 34: /* end of invisible frame */
+ switch (local->raoul_action) {
+ case CONV13_RAOUL_SHUT_UP:
+ raoul_reset_frame = 8; /* make Raoul frozen */
+ break;
+
+ case CONV13_RAOUL_TALK:
+ raoul_reset_frame = imath_random(7, 9); /* between 3 talking frames */
+ ++local->raoul_talk_count; /* run through so many talk cycles */
+
+ if (local->raoul_talk_count > 17) {
+ local->raoul_action = CONV13_RAOUL_SHUT_UP;
+ raoul_reset_frame = 8; /* make Raoul frozen */
+ }
+ break;
+
+ case CONV13_RAOUL_INVISIBLE:
+ raoul_reset_frame = 33; /* keep Raoul invisible */
+ break;
+
+ case CONV13_RAOUL_CHIN:
+ raoul_reset_frame = 11; /* put hand on chin */
+ break;
+ }
+ break;
+
+ case 19: /* end of hand on chin */
+ if (local->raoul_action == CONV13_RAOUL_TALK) {
+ raoul_reset_frame = 9; /* make Raoul talk */
+ } else {
+ raoul_reset_frame = 8; /* make Raoul frozen */
+ local->raoul_action = CONV13_RAOUL_SHUT_UP;
+ }
+ break;
+ }
+
+ if (raoul_reset_frame >= 0) {
+ kernel_reset_animation(aa[1], raoul_reset_frame);
+ local->raoul_frame = raoul_reset_frame;
+ }
+ }
+}
+
+static void handle_animation_6_julie() {
+ int julie_reset_frame;
+ int random = 0;
+
+ if (kernel_anim[aa[4]].frame != local->julie_frame) {
+ local->julie_frame = kernel_anim[aa[4]].frame;
+ julie_reset_frame = -1;
+
+ switch (local->julie_frame) {
+
+ case 1: /* end of talk 1 */
+ case 2: /* end of talk 2 */
+ case 3: /* end of talk 3 */
+ case 11: /* end of cry 1 */
+ case 16: /* end of cry 2 */
+ case 17: /* end of freeze */
+ switch (local->julie_action) {
+ case CONV6_JULIE_TALK:
+ random = imath_random(1, 3);
+ ++local->julie_talk_count;
+ if (local->julie_talk_count > 20) {
+ local->julie_action = CONV6_JULIE_CRY;
+ random = 6;
+ }
+ break;
+
+ case CONV6_JULIE_CRY:
+ random = imath_random(4, 20);
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ julie_reset_frame = 0;
+ break; /* start talk 1 */
+
+ case 2:
+ julie_reset_frame = 1;
+ break; /* start talk 2 */
+
+ case 3:
+ julie_reset_frame = 2;
+ break; /* start talk 3 */
+
+ case 4:
+ julie_reset_frame = 12;
+ break; /* start cry 1 */
+
+ case 5:
+ julie_reset_frame = 4;
+ break; /* start cry 2 */
+
+ default:
+ julie_reset_frame = 16;
+ break; /* start freeze */
+ break;
+ }
+ break;
+ }
+
+ if (julie_reset_frame >= 0) {
+ kernel_reset_animation(aa[4], julie_reset_frame);
+ local->julie_frame = julie_reset_frame;
+ }
+ }
+}
+
+void room_113_init() {
+ if (previous_room != KERNEL_RESTORING_GAME) {
+ local->standing_talking = false;
+ local->day_wants_to_talk = false;
+ local->music_is_playing = false;
+ local->right_after_kiss = false;
+ local->anim_0_running = false;
+ local->anim_1_running = false;
+ local->anim_2_running = false;
+ local->anim_3_running = false;
+ local->anim_4_running = false;
+ local->prevent_1 = false;
+ local->prevent_2 = false;
+ local->raoul_is_up = false;
+ local->arms_are_out = false;
+ }
+
+ kernel_flip_hotspot(words_small_note, false);
+ kernel_flip_hotspot(words_dressing_gown, false);
+ kernel_flip_hotspot(words_Christine, false);
+ kernel_flip_hotspot(words_Julie, false);
+ kernel_flip_hotspot(words_light_fixture, false);
+ /* these will be turned on if needed */
+
+
+ /* =================== Load Sprite Series ======================= */
+
+ if (global[current_year] == 1993) {
+ ss[fx_1993] = kernel_load_series(kernel_name('z', -1), false);
+ ss[fx_dress] = kernel_load_series(kernel_name('f', 0), false);
+
+ if (object_is_here(small_note)) {
+ ss[fx_small_note] = kernel_load_series(kernel_name('f', 1), false);
+ }
+
+ if ((global[done_brie_conv_203] == YES) ||
+ (global[done_brie_conv_203] == YES_AND_CHASE)) {
+ ss[fx_corpse] = kernel_load_series(kernel_name('c', 3), false);
+ }
+ }
+
+
+ /* =================== Load conversation ======================== */
+
+ if (global[current_year] == 1993) {
+ conv_get(CONV_FLORENT);
+ if ((global[done_brie_conv_203] == YES) || (global[done_brie_conv_203] == YES_AND_CHASE)) {
+ /* completed conv with brie in 203 - show dead Florent */
+ conv_get(CONV_FLORENT_DEAD);
+ }
+ } else {
+ ss[fx_face_1] = kernel_load_series("*faceral", false);
+ ss[fx_face_2] = kernel_load_series("*facecrsd", false);
+ conv_get(CONV_LOVE_SCENE);
+ }
+
+
+ /* ============== If 1993, put florent here ===================== */
+
+ if (global[current_year] == 1993) {
+ kernel_draw_to_background(ss[fx_1993], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ kernel_flip_hotspot(words_vase, false);
+ kernel_flip_hotspot(words_fan, false);
+ kernel_flip_hotspot_loc(words_light_fixture, true, LIGHT_1993_X, LIGHT_1993_Y);
+ } else {
+ kernel_flip_hotspot_loc(words_light_fixture, true, LIGHT_1881_X, LIGHT_1881_Y);
+ kernel_flip_hotspot(words_notice, false);
+ }
+
+ if (previous_room == KERNEL_RESTORING_GAME) {
+ if (global[current_year] == 1881) { /* start Daae anim */
+ if (local->day_action <= CONV13_DAY_WAVE) {
+ aa[1] = kernel_run_animation(kernel_name('r', 1), 1);
+ local->anim_1_running = true;
+ }
+
+ switch (local->raoul_action) {
+ case CONV13_RAOUL_INVISIBLE:
+ kernel_reset_animation(aa[1], 33); /* this will keep Raoul shutting up (on couch) */
+ break;
+
+ default:
+ local->raoul_action = CONV13_RAOUL_SHUT_UP;
+ player.walker_visible = false;
+ kernel_reset_animation(aa[1], 8); /* this will keep Raoul shutting up (on couch) */
+ break;
+ }
+
+ if (local->music_is_playing) {
+ aa[0] = kernel_run_animation(kernel_name('d', 2), 0);
+ local->anim_0_running = true;
+ local->chris_daae_dynamic = kernel_add_dynamic(words_Christine, words_walk_to, SYNTAX_SINGULAR_FEM, KERNEL_NONE,
+ 0, 0, 0, 0);
+ kernel_dynamic_hot[local->chris_daae_dynamic].prep = PREP_ON;
+ kernel_dynamic_anim(local->chris_daae_dynamic, aa[0], 13);
+ kernel_dynamic_anim(local->chris_daae_dynamic, aa[0], 14);
+ kernel_dynamic_anim(local->chris_daae_dynamic, aa[0], 16);
+
+ kernel_reset_animation(aa[0], 212); /* keep her standing by mirror */
+ player.walker_visible = true;
+ local->anim_1_running = false;
+
+ } else {
+
+ switch (local->day_action) {
+ case CONV13_DAY_TALK:
+ case CONV13_DAY_GET_READY_TALK:
+ case CONV13_DAY_MIRROR:
+ case CONV13_DAY_WAVE:
+ aa[0] = kernel_run_animation(kernel_name('d', 1), 0);
+ local->anim_0_running = true;
+ local->day_action = CONV13_DAY_MIRROR;
+ kernel_reset_animation(aa[0], 208); /* keep her looking into dresser mirror */
+ kernel_flip_hotspot(words_Christine, true);
+ kernel_flip_hotspot_loc(words_Christine, false, CHRIS_DEAD_X, CHRIS_DEAD_Y);
+ break;
+
+ /* case CONV13_DAY_STAND_TALK: */
+ /* case CONV13_DAY_STAND_SHUT_UP: */
+ /* case CONV13_BOTH_SHUT_UP: */
+
+ default:
+ aa[0] = kernel_run_animation(kernel_name('d', 2), 0);
+ local->anim_0_running = true;
+ local->day_action = CONV13_BOTH_SHUT_UP;
+ player.walker_visible = false;
+ kernel_reset_animation(aa[0], 165); /* keep both of them looking at each other while standing */
+ break;
+ }
+ local->chris_daae_dynamic = kernel_add_dynamic(words_Christine, words_walk_to, SYNTAX_SINGULAR_FEM, KERNEL_NONE,
+ 0, 0, 0, 0);
+ kernel_dynamic_hot[local->chris_daae_dynamic].prep = PREP_ON;
+ kernel_dynamic_anim(local->chris_daae_dynamic, aa[0], 13);
+ kernel_dynamic_anim(local->chris_daae_dynamic, aa[0], 14);
+ kernel_dynamic_anim(local->chris_daae_dynamic, aa[0], 16);
+ }
+
+ if (local->day_action == CONV13_DAY_MIRROR) {
+ kernel_flip_hotspot(words_Christine, true);
+ kernel_flip_hotspot_loc(words_Christine, false, CHRIS_DEAD_X, CHRIS_DEAD_Y);
+
+ } else {
+ player.x = PLAYER_X_AFTER_CONV13;
+ player.y = PLAYER_Y_AFTER_CONV13;
+ player.facing = FACING_NORTHEAST;
+ }
+
+ } else if ((global[done_brie_conv_203] == YES) || (global[done_brie_conv_203] == YES_AND_CHASE)) {
+ /* completed conv with brie in 203 - show dead Florent */
+
+ aa[4] = kernel_run_animation(kernel_name('x', 1), 1);
+ local->julie_action = CONV6_JULIE_CRY;
+ local->anim_4_running = true;
+ global[make_brie_leave_203] = true;
+ seq[fx_dress] = kernel_seq_stamp(ss[fx_dress], false, 1);
+ seq[fx_corpse] = kernel_seq_stamp(ss[fx_corpse], false, 1);
+ kernel_seq_depth(seq[fx_dress], 14);
+ kernel_seq_depth(seq[fx_corpse], 14);
+ kernel_flip_hotspot(words_dressing_gown, true);
+ kernel_flip_hotspot(words_Julie, true);
+ kernel_flip_hotspot_loc(words_Christine, true, CHRIS_DEAD_X, CHRIS_DEAD_Y);
+
+ } else if (global[current_year] == 1993) { /* start Florent anim */
+ seq[fx_dress] = kernel_seq_stamp(ss[fx_dress], false, 1);
+ kernel_seq_depth(seq[fx_dress], 14);
+ aa[2] = kernel_run_animation(kernel_name('f', 1), 1);
+ local->anim_2_running = true; /* anim of Florent by dresser */
+
+ if (local->florent_action != CONV4_FLORENT_HOLD_HAND) {
+ local->florent_action = CONV4_FLORENT_SHUT_UP;
+ }
+
+ aa[3] = kernel_run_animation(kernel_name('r', 1), 1);
+ local->anim_3_running = true; /* anim of Raoul on couch */
+
+ if (local->raoul_action == CONV4_RAOUL_INVISIBLE) {
+ kernel_reset_animation(aa[3], 33); /* this will keep Raoul invisible */
+
+ } else {
+ kernel_reset_animation(aa[3], 8); /* this will keep Raoul frozen on couch */
+ local->raoul_action = CONV4_RAOUL_SHUT_UP;
+ player.x = COUCH_X;
+ player.y = COUCH_Y;
+ player.facing = FACING_SOUTH;
+ player.walker_visible = false;
+ }
+
+ if (local->florent_action == CONV4_FLORENT_HOLD_HAND) {
+ kernel_reset_animation(aa[2], 41); /* this will make Florent hold Raoul's hand */
+ }
+
+ if (global[florent_name_is_known] >= YES) {
+ local->chris_flor_dynamic = kernel_add_dynamic(words_Christine, words_walk_to, SYNTAX_SINGULAR_FEM, KERNEL_NONE,
+ DYN_FLORENT_X, DYN_FLORENT_Y,
+ DYN_FLORENT_X_SIZE, DYN_FLORENT_Y_SIZE);
+ kernel_dynamic_hot[local->chris_flor_dynamic].prep = PREP_ON;
+ kernel_dynamic_walk(local->chris_flor_dynamic, SCREEN_X, SCREEN_Y, FACING_SOUTHWEST);
+
+ } else {
+ local->chris_flor_dynamic = kernel_add_dynamic(words_woman, words_walk_to, SYNTAX_FEM_NOT_PROPER, KERNEL_NONE,
+ DYN_FLORENT_X, DYN_FLORENT_Y,
+ DYN_FLORENT_X_SIZE, DYN_FLORENT_Y_SIZE);
+ kernel_dynamic_hot[local->chris_flor_dynamic].prep = PREP_ON;
+ kernel_dynamic_walk(local->chris_flor_dynamic, SCREEN_X, SCREEN_Y, FACING_SOUTHWEST);
+ }
+
+ kernel_flip_hotspot(words_dressing_gown, true);
+
+ if (object_is_here(small_note)) {
+ kernel_flip_hotspot(words_small_note, true);
+ seq[fx_small_note] = kernel_seq_stamp(ss[fx_small_note], false, 1);
+ kernel_seq_depth(seq[fx_small_note], 13);
+ }
+ }
+
+ } else if (global[current_year] == 1993) {
+ if ((global[done_brie_conv_203] == YES) || (global[done_brie_conv_203] == YES_AND_CHASE)) {
+ /* completed conv with brie in 203 - show dead Florent */
+
+ if (!(global[player_score_flags] & SCORE_DEAD_FLORENT)) {
+ global[player_score_flags] = global[player_score_flags] | SCORE_DEAD_FLORENT;
+ global[player_score] += 5;
+ }
+
+ aa[4] = kernel_run_animation(kernel_name('x', 1), 1);
+ local->julie_action = CONV6_JULIE_CRY;
+ local->anim_4_running = true;
+ global[make_brie_leave_203] = true;
+ player.x = PLAYER_X_FROM_111;
+ player.y = PLAYER_Y_FROM_111;
+ player.facing = FACING_NORTH;
+ player.commands_allowed = false;
+ seq[fx_dress] = kernel_seq_stamp(ss[fx_dress], false, 1);
+ seq[fx_corpse] = kernel_seq_stamp(ss[fx_corpse], false, 1);
+ kernel_seq_depth(seq[fx_dress], 14);
+ kernel_seq_depth(seq[fx_corpse], 14);
+ kernel_flip_hotspot(words_dressing_gown, true);
+ kernel_flip_hotspot(words_Julie, true);
+ kernel_flip_hotspot_loc(words_Christine, true, CHRIS_DEAD_X, CHRIS_DEAD_Y);
+ player_walk(CORPSE_X, CORPSE_Y, FACING_NORTHEAST);
+ player_walk_trigger(ROOM_113_AT_CORPSE);
+
+ } else { /* walk in & start conv with Florent */
+ seq[fx_dress] = kernel_seq_stamp(ss[fx_dress], false, 1);
+ kernel_seq_depth(seq[fx_dress], 14);
+ aa[2] = kernel_run_animation(kernel_name('f', 1), 1);
+ local->florent_action = CONV4_FLORENT_SHUT_UP;
+ local->anim_2_running = true;
+
+ aa[3] = kernel_run_animation(kernel_name('r', 1), 1);
+ local->raoul_action = CONV4_RAOUL_INVISIBLE;
+ local->anim_3_running = true;
+ kernel_reset_animation(aa[3], 33); /* this will keep Raoul invisible */
+
+ if (global[florent_name_is_known] >= YES) {
+ local->chris_flor_dynamic = kernel_add_dynamic(words_Christine, words_walk_to, SYNTAX_SINGULAR_FEM, KERNEL_NONE,
+ DYN_FLORENT_X, DYN_FLORENT_Y,
+ DYN_FLORENT_X_SIZE, DYN_FLORENT_Y_SIZE);
+ kernel_dynamic_hot[local->chris_flor_dynamic].prep = PREP_ON;
+ kernel_dynamic_walk(local->chris_flor_dynamic, SCREEN_X, SCREEN_Y, FACING_SOUTHWEST);
+
+ } else {
+ local->chris_flor_dynamic = kernel_add_dynamic(words_woman, words_walk_to, SYNTAX_FEM_NOT_PROPER, KERNEL_NONE,
+ DYN_FLORENT_X, DYN_FLORENT_Y,
+ DYN_FLORENT_X_SIZE, DYN_FLORENT_Y_SIZE);
+ kernel_dynamic_hot[local->chris_flor_dynamic].prep = PREP_ON;
+ kernel_dynamic_walk(local->chris_flor_dynamic, SCREEN_X, SCREEN_Y, FACING_SOUTHWEST);
+ }
+
+ player.x = PLAYER_X_FROM_111;
+ player.y = PLAYER_Y_FROM_111;
+ player.facing = FACING_NORTH;
+
+ kernel_flip_hotspot(words_dressing_gown, true);
+ if (object_is_here(small_note)) {
+ kernel_flip_hotspot(words_small_note, true);
+ seq[fx_small_note] = kernel_seq_stamp(ss[fx_small_note], false, 1);
+ kernel_seq_depth(seq[fx_small_note], 13);
+ }
+ }
+
+ } else if ((global[current_year] == 1881) && (!global[chris_kicked_raoul_out])) {
+
+ aa[1] = kernel_run_animation(kernel_name('r', 1), 1);
+ local->raoul_action = CONV13_RAOUL_INVISIBLE;
+ local->anim_1_running = true;
+ kernel_reset_animation(aa[1], 33); /* this will keep Raoul invisible */
+
+ aa[0] = kernel_run_animation(kernel_name('d', 1), 1);
+ local->day_action = CONV13_DAY_MIRROR;
+ local->anim_0_running = true;
+
+ kernel_flip_hotspot(words_Christine, true);
+ kernel_flip_hotspot_loc(words_Christine, false, CHRIS_DEAD_X, CHRIS_DEAD_Y);
+ kernel_timing_trigger(ONE_SECOND, ROOM_113_AT_DRESSER);
+ player.x = PLAYER_X_FROM_111;
+ player.y = PLAYER_Y_FROM_111;
+ player.facing = FACING_NORTH;
+ /* Raoul comes into room, Daae is sitting down by mirror */
+
+ } else if ((global[current_year] == 1881) && (global[chris_kicked_raoul_out] == CHRIS_KICKED_YES)) {
+ global[chris_kicked_raoul_out] = CAME_INTO_EMPTY_113; /* so we don't repeat these actions */
+ player.x = PLAYER_X_FROM_111;
+ player.y = PLAYER_Y_FROM_111;
+ player.facing = FACING_NORTH;
+ global[came_from_fade] = true;
+ player.commands_allowed = false;
+ global[player_score] += 8;
+ kernel_timing_trigger(ONE_SECOND, ROOM_113_WAIT_FOR_FADE_IN);
+ /* Raoul comes into room and she is gone */
+
+ } else if (previous_room == 111) {
+ player.x = PLAYER_X_FROM_111;
+ player.y = PLAYER_Y_FROM_111;
+ player.facing = FACING_NORTH;
+ }
+
+
+ /* ============= If restoring game into conv, run it ============ */
+
+ switch (conv_restore_running) {
+ case CONV_LOVE_SCENE:
+ conv_run(CONV_LOVE_SCENE);
+ conv_export_pointer(&global[player_score]);
+ break;
+
+ case CONV_FLORENT:
+ conv_run(CONV_FLORENT);
+ conv_export_pointer(&global[player_score]);
+ break;
+
+ case CONV_FLORENT_DEAD:
+ conv_run(CONV_FLORENT_DEAD);
+ break;
+ }
+
+ section_1_music();
+}
+
+void room_113_daemon() {
+ if (local->anim_1_running) {
+ handle_animation_13_raoul();
+ }
+
+ if (local->anim_4_running) {
+ handle_animation_6_julie();
+ }
+
+ if (local->anim_2_running) {
+ handle_animation_florent();
+ }
+
+ if (local->anim_3_running) {
+ handle_animation_4_raoul();
+
+ if ((!player_has(small_note)) && (kernel_anim[aa[3]].frame == 26)) {
+ kernel_flip_hotspot(words_small_note, false);
+ inter_give_to_player(small_note);
+ kernel_seq_delete(seq[fx_small_note]);
+ sound_play(N_TakeObjectSnd);
+ global_speech_ready = -1;
+ object_examine(small_note, text_008_06, 2);
+ }
+ }
+
+ if ((kernel_anim[aa[0]].frame == 86) && (!local->prevent_2)) {
+ kernel_abort_animation(aa[0]);
+ local->prevent_2 = true;
+ aa[0] = kernel_run_animation(kernel_name('d', 2), 0);
+ kernel_reset_animation(aa[0], 86);
+ kernel_synch(KERNEL_ANIM, aa[0], KERNEL_NOW, 0);
+ kernel_process_all_animations();
+ }
+
+ if (local->anim_0_running) {
+ handle_animation_13_day();
+
+ if ((kernel_anim[aa[0]].frame == 95) && (!local->arms_are_out)) {
+ /* her hands are outstretched */
+ local->standing_talking = true;
+ local->day_action = CONV13_BOTH_SHUT_UP;
+ local->raoul_action = CONV13_RAOUL_INVISIBLE;
+ local->arms_are_out = true;
+ kernel_synch(KERNEL_ANIM, aa[0], KERNEL_ANIM, aa[1]);
+ }
+
+ if ((kernel_anim[aa[0]].frame == 165) && (!local->right_after_kiss)) {
+ /* immediately after kiss */
+ local->right_after_kiss = true;
+ }
+ }
+
+
+ switch (kernel.trigger) {
+ case ROOM_113_WAIT_FOR_FADE_IN:
+ text_show(text_113_31);
+ player_walk(MIRROR_X, MIRROR_Y, FACING_EAST);
+ player_walk_trigger(ROOM_113_BY_MIRROR);
+ break;
+
+ case ROOM_113_BY_MIRROR:
+ text_show(text_113_32);
+ text_show(text_113_33);
+ new_room = 150;
+ global[leave_angel_music_on] = false;
+ break;
+
+ case ROOM_113_AT_CORPSE:
+ player.commands_allowed = true;
+ conv_run(CONV_FLORENT_DEAD);
+ /* once he gets to corpse of Florent, start conv 6 */
+ break;
+
+ case ROOM_113_AT_DRESSER:
+ if (!player.been_here_before) {
+ text_show(text_113_42);
+ }
+ break;
+ }
+}
+
+static void process_conversation_dead() {
+ switch (kernel.trigger) {
+
+ /* =================== Process talking triggers ================ */
+
+ case ROOM_113_JULIE_START_TALKING:
+ local->julie_action = CONV6_JULIE_TALK;
+ break;
+
+ case ROOM_113_JULIE_STOP_TALKING:
+ local->julie_action = CONV6_JULIE_CRY;
+ break;
+ }
+
+ /* ================= Set up me and you triggers ================ */
+
+ conv_you_trigger(ROOM_113_JULIE_START_TALKING);
+ conv_me_trigger(ROOM_113_JULIE_STOP_TALKING);
+
+ local->julie_talk_count = 0;
+}
+
+static void process_conversation_florent() {
+ int random;
+
+ switch (player_verb) {
+ case conv004_dontleave_help:
+ if (!local->prevent_2) {
+ kernel_timing_trigger(TWO_SECONDS, ROOM_113_DELAY_BEFORE_WALK);
+ conv_you_trigger(ROOM_113_PUT_ON_HOLD);
+ local->florent_action = CONV4_FLORENT_TALK;
+ local->prevent_2 = true;
+ }
+ break;
+
+ case conv004_promises_continue:
+ case conv004_promises_safe:
+ conv_you_trigger(ROOM_113_HOLD_HAND);
+ break;
+
+ case conv004_promises_return:
+ case conv004_promises_cant:
+ conv_you_trigger(ROOM_113_END_HOLD_HAND);
+ break;
+
+ case conv004_name_raoul:
+ case conv004_name_dear:
+ if (!local->prevent_1) {
+ global[florent_name_is_known] = YES;
+ conv_you_trigger(ROOM_113_BEFORE_COUCH);
+ kernel_delete_dynamic(local->chris_flor_dynamic);
+ local->chris_flor_dynamic = kernel_add_dynamic(words_Christine, words_walk_to, SYNTAX_SINGULAR_FEM, KERNEL_NONE,
+ DYN_FLORENT_X, DYN_FLORENT_Y,
+ DYN_FLORENT_X_SIZE, DYN_FLORENT_Y_SIZE);
+ kernel_dynamic_hot[local->chris_flor_dynamic].prep = PREP_ON;
+ kernel_dynamic_walk(local->chris_flor_dynamic, SCREEN_X, SCREEN_Y, FACING_SOUTHWEST);
+ local->prevent_1 = true;
+ }
+ break;
+
+ case conv004_anything_take:
+ local->florent_action = CONV4_FLORENT_POINT;
+ conv_you_trigger(86); // ROOM_113_TAKE_NOTE);
+ break;
+
+ case conv004_imgone_bye:
+ if (local->raoul_action != CONV4_RAOUL_INVISIBLE) {
+ local->raoul_action = CONV4_RAOUL_GET_UP;
+ }
+ break;
+ }
+
+ switch (kernel.trigger) {
+ case ROOM_113_PUT_ON_HOLD:
+ conv_hold();
+ break;
+
+ case ROOM_113_END_HOLD_HAND:
+ local->florent_action = CONV4_FLORENT_SHUT_UP;
+ global[stop_walker_disabled] = false;
+ break;
+
+#if 0
+ // TODO: This case was mapped to a second "case 80" in the release executable, and can
+ // never be reached. Need to see if the label "ROOM_113_HOLD_HAND", which is 98, is
+ // legitimate, and this case can be re-enabled
+ case ROOM_113_HOLD_HAND:
+ local->florent_action = CONV4_FLORENT_HOLD_HAND;
+ break;
+#endif
+
+ case ROOM_113_MADE_IT_TO_FLORENT:
+ global[stop_walker_disabled] = true;
+ global[florent_name_is_known] = YES_AND_END_CONV;
+ conv_release();
+ break;
+
+ case ROOM_113_DELAY_BEFORE_WALK:
+ player_walk(FLORENT_TOUCH_HAND_X, FLORENT_TOUCH_HAND_Y, FACING_SOUTHWEST);
+ player_walk_trigger(ROOM_113_MADE_IT_TO_FLORENT);
+ break;
+
+ case ROOM_113_TAKE_NOTE:
+ local->raoul_action = CONV4_RAOUL_TAKE_NOTE;
+ conv_hold();
+ break;
+
+ case ROOM_113_BEFORE_COUCH:
+ local->florent_action = CONV4_FLORENT_TALK;
+ kernel_timing_trigger(TWO_SECONDS, ROOM_113_BETWEEN_COUCH);
+ conv_hold(); // hold so options don't appear in interface
+ break;
+
+ case ROOM_113_BETWEEN_COUCH:
+ player_walk(COUCH_X, COUCH_Y, FACING_SOUTH);
+ player_walk_trigger(ROOM_113_AT_COUCH);
+ break;
+
+ case ROOM_113_AT_COUCH:
+ conv_release();
+ player.walker_visible = false;
+ local->raoul_action = CONV4_RAOUL_SHUT_UP;
+ kernel_synch(KERNEL_ANIM, aa[3], KERNEL_PLAYER, 0);
+ kernel_reset_animation(aa[3], 1);
+ /* when made it to couch, run frame 1 of sitting him down */
+ /* and make options appear in interface */
+ break;
+
+
+ /* =================== Process talking triggers ================ */
+
+ case ROOM_113_FLORENT_START_TALKING2:
+ if ((local->florent_action != CONV4_FLORENT_HOLD_HAND) &&
+ (local->florent_action != CONV4_FLORENT_POINT)) {
+ random = imath_random(1, 5);
+ if (random == 1) {
+ local->florent_action = CONV4_FLORENT_TALK;
+ }
+ }
+
+ if ((local->raoul_action != CONV4_RAOUL_INVISIBLE) &&
+ (local->raoul_action != CONV4_RAOUL_TAKE_NOTE) &&
+ (local->raoul_action != CONV4_RAOUL_GET_UP) &&
+ (!local->raoul_is_up)) {
+ local->raoul_action = CONV4_RAOUL_SHUT_UP;
+ random = imath_random(1, 2); // chance for hand on chin
+ if (random == 1) {
+ local->raoul_action = CONV4_RAOUL_CHIN;
+ } /* if Raoul is visible, stop talking and maybe put hand on chin */
+ }
+ break;
+
+ case ROOM_113_RAOUL_START_TALKING:
+ if ((player_verb != conv004_name_raoul) &&
+ (player_verb != conv004_name_dear) &&
+ (player_verb != conv004_name_sorry) &&
+ (player_verb != conv004_bon_jour_hello) &&
+ (player_verb != conv004_who_who_are) &&
+ (player_verb != conv004_monsieur_again)) {
+ /* I don't want her to stick arm up for these player_verbs */
+
+ if ((local->raoul_action != CONV4_RAOUL_TAKE_NOTE) &&
+ (local->raoul_action != CONV4_RAOUL_GET_UP) &&
+ (!local->raoul_is_up)) {
+ local->raoul_action = CONV4_RAOUL_TALK;
+ }
+
+ if ((local->florent_action != CONV4_FLORENT_HOLD_HAND) &&
+ (local->florent_action != CONV4_FLORENT_POINT)) {
+ local->florent_action = CONV4_FLORENT_SHUT_UP;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ /* ================= Set up me and you triggers ================ */
+
+ if ((player_verb != conv004_name_raoul) &&
+ (player_verb != conv004_name_dear) &&
+ (player_verb != conv004_anything_take) &&
+ (player_verb != conv004_promises_return) &&
+ (player_verb != conv004_promises_cant) &&
+ (player_verb != conv004_promises_continue) &&
+ (player_verb != conv004_promises_safe) &&
+ (player_verb != conv004_dontleave_help)) {
+ conv_you_trigger(ROOM_113_FLORENT_START_TALKING);
+ } /* there is a you trigger called above for the above player_verbs */
+
+ conv_me_trigger(ROOM_113_RAOUL_START_TALKING);
+
+ local->raoul_talk_count = 0;
+ local->florent_talk_count = 0;
+}
+
+static void process_conversation_love() {
+ int random;
+
+ switch (player_verb) {
+ case conv013_returned_abc:
+ case conv013_again_abc:
+ if (!local->prevent_1) {
+ conv_you_trigger(ROOM_113_BEFORE_COUCH);
+ local->prevent_1 = true;
+ }
+ break;
+
+ case conv013_lovescene_openline:
+ /* if the player verb == "come here my love" then hold conversation and
+ set up trigger to wait for frame 96 (arms are held out toward Raoul) */
+ if (!local->arms_are_out) {
+ local->day_action = CONV13_DAY_GET_UP; // time to get up
+ kernel_timing_trigger(SMALL_NUMBER_OF_TICKS, ROOM_113_CHECK_FOR_ARMS_OUT);
+ kernel_init_dialog(); /* clear interface */
+ kernel_set_interface_mode(INTER_CONVERSATION);
+ kernel_flip_hotspot(words_Christine, false);
+ conv_hold();
+ }
+ break;
+
+ case conv013_practice_first:
+ sound_play(N_AngelMus001);
+ global[leave_angel_music_on] = true;
+ break;
+
+ /* case conv013_finale_violin: */
+ /* case conv013_finale_adieu: */
+ case conv013_biteme_b_b:
+ if (!local->music_is_playing) {
+ conv_hold();
+ local->day_action = CONV13_BOTH_SHUT_UP;
+ local->music_is_playing = true;
+ local->chris_daae_dynamic = kernel_add_dynamic(words_Christine, words_walk_to, SYNTAX_SINGULAR_FEM, KERNEL_NONE,
+ 0, 0, 0, 0);
+ kernel_dynamic_hot[local->chris_daae_dynamic].prep = PREP_ON;
+ kernel_dynamic_anim(local->chris_daae_dynamic, aa[0], 14);
+ kernel_dynamic_anim(local->chris_daae_dynamic, aa[0], 16);
+ }
+ break;
+ }
+
+ /* if daemon code does not set local->arms_are_out to true, then run this code */
+ /* again. When it does reach frame 96 (and set to true), then resume conv to */
+ /* say "come here my love with arms outreached. */
+
+ switch (kernel.trigger) {
+ case ROOM_113_BEFORE_COUCH:
+ kernel_timing_trigger(TWO_SECONDS, ROOM_113_BETWEEN_COUCH);
+ conv_hold(); /* hold so options don't appear in interface */
+ local->day_action = CONV13_DAY_GET_READY_TALK;
+ local->day_wants_to_talk = true;
+ break;
+
+ case ROOM_113_BETWEEN_COUCH:
+ player_walk(COUCH_X, COUCH_Y, FACING_SOUTH);
+ player_walk_trigger(ROOM_113_AT_COUCH);
+ break; /* give a 3 sec. delay before walking to couch */
+
+ case ROOM_113_AT_COUCH:
+ conv_release();
+ player.walker_visible = false;
+ local->raoul_action = CONV13_RAOUL_SHUT_UP;
+ kernel_synch(KERNEL_ANIM, aa[1], KERNEL_PLAYER, 0);
+ kernel_reset_animation(aa[1], 1);
+ /* when made it to couch, run frame 1 of sitting him down */
+ /* and make options appear in interface */
+ break;
+
+ case ROOM_113_CHECK_FOR_ARMS_OUT:
+ case ROOM_113_WAIT_TO_SIT:
+ if (local->arms_are_out) {
+ conv_release(); // let her say "come here my love"
+ conv_you_trigger(ROOM_113_HOLD_OPTIONS); // so we can not display options
+ }
+ break;
+
+ case ROOM_113_HOLD_OPTIONS:
+ conv_hold();
+ kernel_timing_trigger(SMALL_NUMBER_OF_TICKS, ROOM_113_CHECK_FOR_AFTER_KISS);
+ break;
+
+ case ROOM_113_CHECK_FOR_AFTER_KISS:
+ if (local->right_after_kiss) { /* frame 165 */
+ conv_release();
+ } else {
+ kernel_timing_trigger(SMALL_NUMBER_OF_TICKS, ROOM_113_CHECK_FOR_AFTER_KISS);
+ }
+ break;
+
+
+ /* =================== Process talking triggers ================ */
+
+ case ROOM_113_DAY_START_TALKING:
+ if (local->standing_talking) {
+ local->day_action = CONV13_DAY_STAND_TALK;
+
+ } else {
+ if (player_verb == conv013_dreams_romantic) {
+ local->day_action = CONV13_DAY_WAVE;
+ } else {
+ local->day_action = CONV13_DAY_GET_READY_TALK;
+ local->day_wants_to_talk = true;
+ } /* if dreams_romantic, then have her wave hand, else just talk */
+
+ if (local->raoul_action != CONV13_RAOUL_INVISIBLE) {
+ local->raoul_action = CONV13_RAOUL_SHUT_UP;
+ random = imath_random(1, 2); /* chance for hand on chin */
+ if (random == 1) {
+ local->raoul_action = CONV13_RAOUL_CHIN;
+ } /* if Raoul is visible, stop talking and maybe put hand on chin */
+ }
+ }
+ break;
+
+ case ROOM_113_RAOUL_START_TALKING:
+ if (player_verb != conv013_intro_hello) {
+ if (local->standing_talking) {
+ local->day_action = CONV13_DAY_STAND_SHUT_UP;
+
+ } else if (local->day_action != CONV13_DAY_GET_UP) {
+ local->day_action = CONV13_DAY_GET_READY_TALK;
+ local->raoul_action = CONV13_RAOUL_TALK;
+ local->day_wants_to_talk = false;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+
+ /* ================= Set up me and you triggers ================ */
+
+ if ((player_verb != conv013_lovescene_openline) &&
+ (player_verb != conv013_returned_abc) &&
+ (player_verb != conv013_again_abc)) {
+ conv_you_trigger(ROOM_113_DAY_START_TALKING);
+ } /* there is a you trigger called above for 3 other player_verbs */
+
+ conv_me_trigger(ROOM_113_RAOUL_START_TALKING);
+
+ local->raoul_talk_count = 0;
+ local->day_talk_count = 0;
+ local->stand_talk_count = 0;
+}
+
+void room_113_pre_parser() {
+ if (player_said_2(walk_up, aisle)) {
+ player.walk_off_edge_to_room = 101;
+ }
+
+ if (player_said_2(look, mirror)) {
+ player_walk(MIRROR_X, MIRROR_Y, FACING_EAST);
+ }
+
+ if ((!player_said_2(exit_to, corridor)) &&
+ (!global[chris_kicked_raoul_out]) &&
+ (!player_said_2(look, Christine)) &&
+ (!player_said_2(take, Christine)) &&
+ (local->music_is_playing)) {
+ conv_run(CONV_LOVE_SCENE);
+ conv_export_pointer(&global[player_score]);
+ player_cancel_command();
+ /* if player said anything but leave room during conv */
+ /* with Daae, then re-enter conv */
+
+ } else if ((player_said_2(talk_to, woman)) ||
+ (player_said_2(talk_to, Christine))) {
+ player_walk(SCREEN_X, SCREEN_Y, FACING_SOUTHWEST);
+ }
+
+ if ((!player_said_2(exit_to, corridor)) &&
+ (!player_said_2(look, Julie)) &&
+ (!player_said_2(look, Christine)) &&
+ (!player.look_around) &&
+ (global[done_brie_conv_203] != NO) &&
+ (global[current_year] == 1993)) {
+
+ if (player_said_2(talk_to, Christine)) {
+ player.need_to_walk = false;
+
+ } else if (player_said_1(look)) {
+ player.need_to_walk = false;
+
+ } else if (player_said_2(talk_to, Julie)) {
+ player.need_to_walk = false;
+ conv_run(CONV_FLORENT_DEAD);
+ player_cancel_command();
+
+ } else {
+ text_show(text_113_50);
+ player.need_to_walk = false;
+ player_cancel_command();
+ }
+
+ } /* if player said anything but leave room during conv */
+ /* with Julie (dead Florent is here), then re-enter conv */
+}
+
+
+void room_113_parser() {
+ if (conv_control.running == CONV_LOVE_SCENE) {
+ process_conversation_love();
+ goto handled;
+ }
+
+ if (conv_control.running == CONV_FLORENT) {
+ process_conversation_florent();
+ goto handled;
+ }
+
+ if (conv_control.running == CONV_FLORENT_DEAD) {
+ process_conversation_dead();
+ goto handled;
+ }
+
+ if ((player_said_2(talk_to, woman)) ||
+ (player_said_2(talk_to, Christine))) {
+ if (global[current_year] == 1881) {
+ player.commands_allowed = true;
+ conv_run(CONV_LOVE_SCENE);
+ conv_export_pointer(&global[player_score]);
+ } else {
+ if (global[done_brie_conv_203]) {
+ text_show(text_113_48);
+ /* talk to dead Florent */
+ } else {
+ player.commands_allowed = true;
+ conv_run(CONV_FLORENT);
+ conv_export_pointer(&global[player_score]);
+ }
+ } /* once he gets to dresser, start conv 13 or 4 */
+ goto handled;
+ }
+
+ if (player_said_2(exit_to, corridor)) {
+ if (global[done_brie_conv_203] == YES) {
+ global[done_brie_conv_203] = YES_AND_CHASE;
+ }
+ new_room = 111;
+ goto handled;
+ }
+
+ if (player.look_around) {
+ if (global[current_year] == 1993) {
+ if (global[done_brie_conv_203]) {
+ text_show(text_113_40); /* when Christine's body is here */
+ } else {
+ text_show(text_113_10);
+ }
+ } else {
+ text_show(text_113_11);
+ }
+ goto handled;
+ }
+
+ if (player_said_1(look) || player_said_1(look_at)) {
+ if (player_said_1(floor)) {
+ text_show(text_113_12);
+ goto handled;
+ }
+
+ if (player_said_1(rug)) {
+ text_show(text_113_13);
+ goto handled;
+ }
+
+ if (player_said_1(wall)) {
+ text_show(text_113_14);
+ goto handled;
+ }
+
+ if (player_said_1(couch)) {
+ text_show(text_113_15);
+ goto handled;
+ }
+
+ if (player_said_1(mural)) {
+ text_show(text_113_16);
+ goto handled;
+ }
+
+ if (player_said_1(painting)) {
+ if (global[current_year] == 1881) {
+ text_show(text_113_17);
+ } else {
+ text_show(text_113_43);
+ }
+ goto handled;
+ }
+
+ // NOTE: duplicate player_said_1(painting) check â unreachable dead code from original
+ if (player_said_1(painting)) {
+ text_show(text_113_17);
+ goto handled;
+ }
+
+ if (player_said_1(dressing_table)) {
+ text_show(text_113_18);
+ goto handled;
+ }
+
+ if (player_said_1(chair)) {
+ text_show(text_113_19);
+ goto handled;
+ }
+
+ if (player_said_1(mirror)) {
+ if (global[current_year] == 1993) {
+ text_show(text_113_44);
+ } else {
+ text_show(text_113_20);
+ }
+ goto handled;
+ }
+
+ if (player_said_1(fan)) {
+ text_show(text_113_21);
+ goto handled;
+ }
+
+ if (player_said_1(vase)) {
+ text_show(text_113_22);
+ goto handled;
+ }
+
+ if (player_said_1(hat_rack)) {
+ text_show(text_113_23);
+ goto handled;
+ }
+
+ if (player_said_1(light_fixture)) {
+ text_show(text_113_24);
+ goto handled;
+ }
+
+ if (player_said_1(ceiling)) {
+ text_show(text_113_25);
+ goto handled;
+ }
+
+ if (player_said_1(wardrobe)) {
+ text_show(text_113_26);
+ goto handled;
+ }
+
+ if (player_said_1(dressing_screen)) {
+ text_show(text_113_27);
+ goto handled;
+ }
+
+ if (player_said_1(corridor)) {
+ text_show(text_113_28);
+ goto handled;
+ }
+
+ if (player_said_1(dressing_gown)) {
+ text_show(text_113_30);
+ goto handled;
+ }
+
+ if (player_said_1(small_note) && object_is_here(small_note)) {
+ text_show(text_113_49);
+ goto handled;
+ }
+
+ if (player_said_1(Christine)) {
+ if (global[done_brie_conv_203]) { /* completed conv with brie in 203 - Florent is dead */
+ text_show(text_113_38);
+ goto handled;
+ }
+ }
+
+ if (player_said_1(Julie)) {
+ text_show(text_113_39);
+ goto handled;
+ }
+
+ if (player_said_1(notice)) {
+ text_show(text_113_47);
+ goto handled;
+ }
+
+ if (player_said_1(clothes_dummy)) {
+ if (global[current_year] == 1993) {
+ text_show(text_113_45);
+ } else {
+ text_show(text_113_46);
+ }
+ goto handled;
+ }
+
+ if (player_said_1(woman) || player_said_1(Christine)) {
+ if (global[current_year] == 1993) {
+ text_show(text_113_41);
+ } else {
+ if (local->music_is_playing) { /* at end of love scene */
+ text_show(text_113_36);
+ } else {
+ text_show(text_113_42);
+ }
+ }
+ goto handled;
+ }
+ }
+
+ if (player_said_2(open, wardrobe)) {
+ text_show(text_113_29);
+ goto handled;
+ }
+
+ if (player_said_2(take, small_note)) {
+ if (object_is_here(small_note)) {
+ text_show(text_113_34);
+ goto handled;
+ }
+ }
+
+ if (player_said_2(take, dressing_gown)) {
+ text_show(text_113_35);
+ goto handled;
+ }
+
+ if (player_said_2(take, Christine) || player_said_2(take, woman)) {
+ text_show(text_113_37);
+ goto handled;
+ }
+
+ goto done;
+
+handled:
+ player.command_ready = false;
+
+done:
+ ;
+}
+
+void room_113_preload() {
+ room_init_code_pointer = room_113_init;
+ room_pre_parser_code_pointer = room_113_pre_parser;
+ room_parser_code_pointer = room_113_parser;
+ room_daemon_code_pointer = room_113_daemon;
+
+ section_1_walker();
+ section_1_interface();
+
+ vocab_make_active(words_Christine);
+ vocab_make_active(words_woman);
+ vocab_make_active(words_Julie);
+}
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/rooms/room113.h b/engines/mads/madsv2/phantom/rooms/room113.h
new file mode 100644
index 00000000000..db154f63ba6
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room113.h
@@ -0,0 +1,224 @@
+/* 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/>.
+ *
+ */
+
+/* room113.mac by Paul Lahaise 8-Jan-93 */
+
+#ifndef MADS_PHANTOM_ROOM113_H
+#define MADS_PHANTOM_ROOM113_H
+
+#include "mads/madsv2/phantom/rooms/section1.h"
+#include "mads/madsv2/phantom/global.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+#define local ((Scratch *)(&game.scratch[0]))
+#define ss local->sprite
+#define seq local->sequence
+#define aa local->animation
+
+typedef struct { /* Room local variables */
+
+ int sprite[15]; /* Sprite series handles */
+ int sequence[15]; /* Sequence handles */
+ int animation[5]; /* Animation handles [0=Daae, 1=Raoul13/Raoul4's */
+ /* proxy, 2=Florent, 3=Raoul4, 4=Julie] */
+
+ int chris_daae_dynamic; /* Dynamic HS for Christine (love scene) */
+ int chris_flor_dynamic; /* Dynamic HS for Christine/Florent (1993) */
+
+ int standing_talking; /* T once Daae & Raoul are standing face-to-face */
+ int day_wants_to_talk; /* T if Daae should start talking at next idle pt */
+ int music_is_playing; /* T once angel music has been triggered */
+ int right_after_kiss; /* T once kiss frame (165) has been reached */
+ int anim_0_running; /* T if Daae animation is active */
+ int anim_1_running; /* T if Raoul-13 animation is active */
+ int anim_2_running; /* T if Florent animation is active */
+ int anim_3_running; /* T if Raoul-4 animation is active */
+ int anim_4_running; /* T if Julie animation is active */
+ int prevent_1; /* Prevent first-time code from repeating */
+ int prevent_2; /* Prevent first-time code from repeating */
+ int raoul_is_up; /* T once Raoul has stood up from couch */
+ int arms_are_out; /* T once Daae has arms outstretched (frame 95) */
+
+ int day_frame;
+ int day_action;
+ int day_talk_count;
+ int stand_talk_count;
+ int florent_frame;
+ int florent_action;
+ int florent_talk_count;
+ int raoul_frame;
+ int raoul_action;
+ int raoul_talk_count;
+ int julie_frame;
+ int julie_action;
+ int julie_talk_count;
+ int just_did_option;
+
+} Scratch;
+
+
+/* ========================= Sprite Series ========================= */
+
+#define fx_1993 0 /* rm113z (1993 overlay backdrop) */
+#define fx_dress 1 /* rm113f0 (Florent/Christine dress) */
+#define fx_small_note 2 /* rm113f1 (note sprite) */
+#define fx_corpse 3 /* rm113c3 (dead Florent) */
+#define fx_face_1 4 /* *faceral (1881 only) */
+#define fx_face_2 5 /* *facecrsd (1881 only) */
+
+
+/* ========================= Conversations ========================= */
+
+#define CONV_LOVE_SCENE 13
+#define CONV_FLORENT 4
+#define CONV_FLORENT_DEAD 6
+
+/* Conv 4 (Florent) â Florent action states */
+#define CONV4_FLORENT_TALK 0
+#define CONV4_FLORENT_SHUT_UP 1
+#define CONV4_FLORENT_POINT 2
+#define CONV4_FLORENT_HOLD_HAND 3
+
+/* Conv 4 (Florent) â Raoul action states */
+#define CONV4_RAOUL_TALK 0
+#define CONV4_RAOUL_SHUT_UP 1
+#define CONV4_RAOUL_INVISIBLE 3
+#define CONV4_RAOUL_GET_UP 4
+#define CONV4_RAOUL_TAKE_NOTE 5
+#define CONV4_RAOUL_CHIN 2
+
+/* Conv 6 (Julie/dead Florent) â Julie action states */
+#define CONV6_JULIE_TALK 0
+#define CONV6_JULIE_CRY 1
+
+/* Conv 13 (love scene) â Daae action states */
+#define CONV13_DAY_MIRROR 2 //0
+#define CONV13_DAY_TALK 0 //1
+#define CONV13_DAY_GET_READY_TALK 1 //2
+#define CONV13_DAY_WAVE 3 //3
+#define CONV13_DAY_STAND_TALK 5 //4
+#define CONV13_DAY_STAND_SHUT_UP 6 //5
+#define CONV13_BOTH_SHUT_UP 7 //6
+#define CONV13_DAY_GET_UP 4 //7
+
+/* Conv 13 (love scene) â Raoul action states */
+#define CONV13_RAOUL_INVISIBLE 3 //0
+#define CONV13_RAOUL_SHUT_UP 1 //1
+#define CONV13_RAOUL_TALK 0 //2
+#define CONV13_RAOUL_CHIN 2 //3
+
+
+/* ========================= Triggers ============================== */
+
+/* Daemon triggers */
+#define ROOM_113_BY_MIRROR 57
+#define ROOM_113_AT_CORPSE 59
+#define ROOM_113_AT_DRESSER 61
+#define ROOM_113_WAIT_FOR_FADE_IN 110
+
+/* Process_conversation_dead triggers */
+#define ROOM_113_JULIE_START_TALKING 63
+#define ROOM_113_JULIE_STOP_TALKING 65
+
+/* Process_conversation_florent triggers */
+#define ROOM_113_RAOUL_START_TALKING 62
+#define ROOM_113_FLORENT_START_TALKING2 64
+#define ROOM_113_FLORENT_START_TALKING 66
+#define ROOM_113_TAKE_NOTE 74
+#define ROOM_113_MADE_IT_TO_FLORENT 78
+#define ROOM_113_AT_COUCH 80
+#define ROOM_113_BEFORE_COUCH 82
+#define ROOM_113_BETWEEN_COUCH 84
+#define ROOM_113_DELAY_BEFORE_WALK 92
+#define ROOM_113_PUT_ON_HOLD 96
+#define ROOM_113_HOLD_HAND 98
+#define ROOM_113_END_HOLD_HAND 100
+
+/* Process_conversation_love triggers */
+#define ROOM_113_CHECK_FOR_ARMS_OUT 70 //89
+#define ROOM_113_DAY_START_TALKING 66 //91
+#define ROOM_113_WAIT_TO_SIT 78 //93
+#define ROOM_113_CHECK_FOR_AFTER_KISS 72 //95
+#define ROOM_113_HOLD_OPTIONS 76 //97
+
+
+/* ========================= Player positions ====================== */
+
+#define PLAYER_X_FROM_111 190
+#define PLAYER_Y_FROM_111 148
+
+#define PLAYER_X_AFTER_CONV13 175
+#define PLAYER_Y_AFTER_CONV13 148
+
+#define COUCH_X 201
+#define COUCH_Y 120
+
+#define MIRROR_X 272
+#define MIRROR_Y 138
+
+#define SCREEN_X 106
+#define SCREEN_Y 127
+
+#define CORPSE_X 175
+#define CORPSE_Y 128
+
+#define FLORENT_TOUCH_HAND_X 142
+#define FLORENT_TOUCH_HAND_Y 68
+
+
+/* ========================= Florent dynamic hotspot =============== */
+
+#define DYN_FLORENT_X 43
+#define DYN_FLORENT_Y 118
+#define DYN_FLORENT_X_SIZE 15
+#define DYN_FLORENT_Y_SIZE 29
+
+
+/* ========================= Misc coordinates ====================== */
+
+#define CHRIS_DEAD_X 220
+#define CHRIS_DEAD_Y 130
+
+#define LIGHT_1993_X 155
+#define LIGHT_1993_Y 17
+
+#define LIGHT_1881_X 150
+#define LIGHT_1881_Y 46
+
+#define SMALL_NUMBER_OF_TICKS 1
+
+
+extern void room_113_init();
+extern void room_113_daemon();
+extern void room_113_pre_parser();
+extern void room_113_parser();
+extern void room_113_preload();
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index 3568894ae81..e9bc481717c 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -134,6 +134,7 @@ MODULE_OBJS += \
madsv2/phantom/rooms/room110.o \
madsv2/phantom/rooms/room111.o \
madsv2/phantom/rooms/room112.o \
+ madsv2/phantom/rooms/room113.o \
madsv2/phantom/phantom.o \
madsv2/phantom/conv.o \
madsv2/phantom/main_menu.o \
Commit: ba78a7454c6c7b588823f99661814c5d67727d7c
https://github.com/scummvm/scummvm/commit/ba78a7454c6c7b588823f99661814c5d67727d7c
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:43+10:00
Commit Message:
MADS: PHANTOM: Added room 114
Changed paths:
A engines/mads/madsv2/phantom/rooms/room114.cpp
A engines/mads/madsv2/phantom/rooms/room114.h
engines/mads/madsv2/phantom/mads/text.h
engines/mads/madsv2/phantom/mads/words.h
engines/mads/module.mk
diff --git a/engines/mads/madsv2/phantom/mads/text.h b/engines/mads/madsv2/phantom/mads/text.h
index d38980a1e83..9a43760f8d5 100644
--- a/engines/mads/madsv2/phantom/mads/text.h
+++ b/engines/mads/madsv2/phantom/mads/text.h
@@ -32,6 +32,7 @@ namespace Phantom {
enum {
text_008_06 = 806,
+ text_008_07 = 807,
/* Room 101 */
text_101_10 = 10110,
@@ -410,7 +411,39 @@ enum {
text_113_47 = 11347,
text_113_48 = 11348,
text_113_49 = 11349,
- text_113_50 = 11350
+ text_113_50 = 11350,
+
+ /* Room 114 */
+ text_114_10 = 11410,
+ text_114_11 = 11411,
+ text_114_12 = 11412,
+ text_114_13 = 11413,
+ text_114_14 = 11414,
+ text_114_15 = 11415,
+ text_114_16 = 11416,
+ text_114_17 = 11417,
+ text_114_18 = 11418,
+ text_114_19 = 11419,
+ text_114_20 = 11420,
+ text_114_21 = 11421,
+ text_114_22 = 11422,
+ text_114_23 = 11423,
+ text_114_24 = 11424,
+ text_114_25 = 11425,
+ text_114_26 = 11426,
+ text_114_27 = 11427,
+ text_114_28 = 11428,
+ text_114_29 = 11429,
+ text_114_30 = 11430,
+ text_114_31 = 11431,
+ text_114_32 = 11432,
+ text_114_33 = 11433,
+ text_114_34 = 11434,
+ text_114_35 = 11435,
+ text_114_36 = 11436,
+ text_114_37 = 11437,
+ /* text_114_38 not used */
+ text_114_39 = 11439
};
} // namespace Phantom
diff --git a/engines/mads/madsv2/phantom/mads/words.h b/engines/mads/madsv2/phantom/mads/words.h
index e9628e79655..a434910eef5 100644
--- a/engines/mads/madsv2/phantom/mads/words.h
+++ b/engines/mads/madsv2/phantom/mads/words.h
@@ -36,8 +36,10 @@ enum {
words_apron = 19,
words_backstage = 21,
words_bear_prop = 22,
+ words_bust = 25,
words_cable = 26,
words_carton = 28,
+ words_cartons = 29,
words_ceiling = 30,
words_chair = 31,
words_circular_staircase = 32,
@@ -49,7 +51,9 @@ enum {
words_couch = 39,
words_counterweight_system = 40,
words_crate = 41,
+ words_crates = 42,
words_cyclorama = 44,
+ words_cylinder = 45,
words_door = 46,
words_dressing_screen = 48,
words_dressing_table = 49,
@@ -60,6 +64,7 @@ enum {
words_exposed_brick = 67,
words_fan = 68,
words_fire_axe = 69,
+ words_flat = 71,
words_flats = 72,
words_floor = 73,
words_folding_chairs = 74,
@@ -79,7 +84,9 @@ enum {
words_lockrail = 95,
words_look_at = 96,
words_look_through = 97,
+ words_mannequins = 98,
words_mirror = 99,
+ words_mummy_prop = 100,
words_mural = 101,
words_music_stand = 103,
words_music_stands = 104,
@@ -98,8 +105,10 @@ enum {
words_purchase_lines = 120,
words_railing = 121,
words_red_frame = 123,
+ words_rope = 125,
words_rug = 126,
words_sandbag = 127,
+ words_scaffolding = 128,
words_seats = 129,
words_side_wall = 130,
words_small_note = 131,
@@ -133,7 +142,10 @@ enum {
words_right_door = 169,
words_door_to_pit = 170,
words_boxes = 172,
+ words_mug = 173,
+ words_dinette_set = 174,
words_box = 175,
+ words_cases = 176,
words_trash_bucket = 177,
words_headset = 179,
words_grand_foyer = 180,
@@ -160,6 +172,7 @@ enum {
words_chandelier = 201,
words_light = 245,
words_prop_case = 247,
+ words_case = 247,
words_handle = 248,
words_axe = 249,
words_door_chunks = 250,
diff --git a/engines/mads/madsv2/phantom/rooms/room114.cpp b/engines/mads/madsv2/phantom/rooms/room114.cpp
new file mode 100644
index 00000000000..a97cb9535f4
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room114.cpp
@@ -0,0 +1,381 @@
+/* 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 "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/imath.h"
+#include "mads/madsv2/core/text.h"
+#include "mads/madsv2/core/inter.h"
+#include "mads/madsv2/core/object.h"
+#include "mads/madsv2/core/sound.h"
+#include "mads/madsv2/phantom/global.h"
+#include "mads/madsv2/phantom/mads/inventory.h"
+#include "mads/madsv2/phantom/mads/speeches.h"
+#include "mads/madsv2/phantom/mads/words.h"
+#include "mads/madsv2/phantom/mads/sounds.h"
+#include "mads/madsv2/phantom/mads/text.h"
+#include "mads/madsv2/phantom/rooms/section1.h"
+#include "mads/madsv2/phantom/rooms/room114.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+void room_114_init() {
+ /* =================== Load Sprite Series ======================= */
+
+ if (global[current_year] == 1993) {
+ ss[fx_1993] = kernel_load_series(kernel_name('z', -1), false);
+ } else {
+ if (object_is_here(rope) && !player_has(rope_with_hook)) {
+ ss[fx_rope] = kernel_load_series(kernel_name('f', 0), false);
+ ss[fx_take_9] = kernel_load_series("*RDR_9", false);
+ }
+ }
+
+ ss[fx_climb] = kernel_load_series(kernel_name('a', 0), false);
+
+ /* ================ If in 1881, put rope ======================== */
+
+ if ((object_is_here(rope)) && (global[current_year] == 1881) && !player_has(rope_with_hook)) {
+ seq[fx_rope] = kernel_seq_stamp(ss[fx_rope], false, 1);
+ kernel_seq_depth(seq[fx_rope], 2);
+ } else {
+ kernel_flip_hotspot(words_rope, false);
+ }
+
+ /* ======= Load variant if in 1993 & change hotspots =========== */
+
+ if (global[current_year] == 1993) {
+ kernel_flip_hotspot(words_cylinder, false);
+ kernel_flip_hotspot(words_mannequins, false);
+ kernel_flip_hotspot(words_prop, false);
+ kernel_flip_hotspot(words_bust, false);
+ kernel_flip_hotspot(words_scaffolding, false);
+ kernel_draw_to_background(ss[fx_1993], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ } else {
+ kernel_flip_hotspot(words_boxes, false);
+ kernel_flip_hotspot(words_dinette_set, false);
+ kernel_flip_hotspot(words_crate, false);
+ kernel_flip_hotspot(words_cases, false);
+ }
+
+
+ /* ========================= Previous Rooms ===================== */
+
+ if ((previous_room == 105) || (previous_room != KERNEL_RESTORING_GAME)) {
+ player.x = PLAYER_X_FROM_105;
+ player.y = PLAYER_Y_FROM_105;
+ player.facing = FACING_WEST;
+ }
+
+ section_1_music();
+}
+
+void room_114_parser() {
+ if (player_said_2(climb_up, circular_staircase)) {
+ switch (kernel.trigger) {
+ case 0:
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ aa[0] = kernel_run_animation(kernel_name('u', 1), 1);
+ kernel_synch(KERNEL_ANIM, aa[0], KERNEL_PLAYER, 0);
+ break;
+
+ case 1:
+ new_room = 105;
+ break;
+ }
+ goto handled;
+ }
+
+ if (player_said_2(climb_up, circular_staircase)) {
+ new_room = 105;
+ goto handled;
+ }
+
+ if (player_said_2(take, rope) &&
+ (object_is_here(rope) || kernel.trigger)) {
+ switch (kernel.trigger) {
+ case 0:
+ global[player_score] += 5;
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_take_9] = kernel_seq_pingpong(ss[fx_take_9], false,
+ 6, 0, 0, 2);
+ kernel_seq_range(seq[fx_take_9], 1, 3);
+ kernel_seq_player(seq[fx_take_9], true);
+ kernel_seq_trigger(seq[fx_take_9],
+ KERNEL_TRIGGER_SPRITE, 3, 1);
+ kernel_seq_trigger(seq[fx_take_9],
+ KERNEL_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ kernel_seq_delete(seq[fx_rope]);
+ kernel_flip_hotspot(words_rope, false);
+ inter_give_to_player(rope);
+ sound_play(N_TakeObjectSnd);
+ break;
+
+ case 2:
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_SERIES, seq[fx_take_9]);
+ player.walker_visible = true;
+ kernel_timing_trigger(20, 3);
+ break;
+
+ case 3:
+ object_examine(rope, text_008_07, 0);
+ /* You pick up the rope */
+ player.commands_allowed = true;
+ break;
+ }
+ goto handled;
+ }
+
+ if (player.look_around) {
+ text_show(text_114_10);
+ goto handled;
+ }
+
+ if (player_said_1(look) || player_said_1(look_at)) {
+
+ if (player_said_1(floor)) {
+ text_show(text_114_11);
+ goto handled;
+ }
+
+ if (player_said_1(circular_staircase)) {
+ text_show(text_114_12);
+ goto handled;
+ }
+
+ if (player_said_1(rope) && object_is_here(rope)) {
+ text_show(text_114_13);
+ goto handled;
+ }
+
+ if (player_said_1(wall)) {
+ text_show(text_114_14);
+ goto handled;
+ }
+
+ if (player_said_1(mannequins)) {
+ text_show(text_114_15);
+ goto handled;
+ }
+
+ if (player_said_1(flat)) {
+ text_show(text_114_16);
+ goto handled;
+ }
+
+ if (player_said_1(scaffolding)) {
+ text_show(text_114_17);
+ goto handled;
+ }
+
+ if (player_said_1(mummy_prop)) {
+ if (global[current_year] == 1993) {
+ text_show(text_114_18);
+ } else {
+ text_show(text_114_33);
+ }
+ goto handled;
+ }
+
+ if (player_said_1(crates)) {
+ if (global[current_year] == 1993) {
+ text_show(text_114_19);
+ } else {
+ text_show(text_114_34);
+ }
+ goto handled;
+ }
+
+ if (player_said_1(crate)) {
+ if (global[current_year] == 1993) {
+ text_show(text_114_20);
+ } else {
+ text_show(text_114_35);
+ }
+ goto handled;
+ }
+
+ if (player_said_1(cartons)) {
+ if (global[current_year] == 1993) {
+ text_show(text_114_21);
+ } else {
+ text_show(text_114_36);
+ }
+ goto handled;
+ }
+
+ if (player_said_1(carton)) {
+ if (global[current_year] == 1993) {
+ text_show(text_114_22);
+ } else {
+ text_show(text_114_37);
+ }
+ goto handled;
+ }
+
+ if (player_said_1(prop)) {
+ text_show(text_114_23);
+ goto handled;
+ }
+
+ if (player_said_1(bust)) {
+ text_show(text_114_24);
+ goto handled;
+ }
+
+ if (player_said_1(mug)) {
+ text_show(text_114_25);
+ goto handled;
+ }
+
+ if ((player_said_1(cases)) || (player_said_1(case))) {
+ text_show(text_114_26);
+ goto handled;
+ }
+
+ if (player_said_1(boxes) || player_said_1(box)) {
+ if (global[current_year] == 1993) {
+ text_show(text_114_27);
+ } else {
+ text_show(text_114_39);
+ }
+ goto handled;
+ }
+
+ // NOTE: duplicate box check â unreachable dead code from original
+ if (player_said_1(box)) {
+ if (global[current_year] == 1881) {
+ text_show(text_114_39);
+ goto handled;
+ }
+ }
+
+ if (player_said_1(dinette_set)) {
+ text_show(text_114_28);
+ goto handled;
+ }
+
+ if (player_said_1(cylinder)) {
+ text_show(text_114_29);
+ goto handled;
+ }
+ }
+
+ if (player_said_2(open, cartons)) {
+ if (global[current_year] == 1993) {
+ text_show(text_114_21);
+ } else {
+ text_show(text_114_36);
+ }
+ goto handled;
+ }
+
+ if (player_said_2(open, carton)) {
+ if (global[current_year] == 1993) {
+ text_show(text_114_22);
+ } else {
+ text_show(text_114_37);
+ }
+ goto handled;
+ }
+
+ if (player_said_2(open, crates)) {
+ if (global[current_year] == 1993) {
+ text_show(text_114_19);
+ } else {
+ text_show(text_114_34);
+ }
+ goto handled;
+ }
+
+ if (player_said_2(open, crate)) {
+ if (global[current_year] == 1993) {
+ text_show(text_114_19);
+ } else {
+ text_show(text_114_35);
+ }
+ goto handled;
+ }
+
+ if (player_said_2(open, cases)) {
+ text_show(text_114_26);
+ goto handled;
+ }
+
+ if (player_said_2(open, boxes) || player_said_2(open, box)) {
+ if (global[current_year] == 1993) {
+ text_show(text_114_27);
+ } else {
+ text_show(text_114_39);
+ }
+ goto handled;
+ }
+
+ if (player_said_2(take, mug)) {
+ text_show(text_114_30);
+ goto handled;
+ }
+
+ if (player_said_2(open, mummy_prop)) {
+ text_show(text_114_31);
+ goto handled;
+ }
+
+ if (player_said_2(talk_to, mummy_prop)) {
+ text_show(text_114_32);
+ goto handled;
+ }
+
+ goto done;
+
+handled:
+ player.command_ready = false;
+
+done:
+ ;
+}
+
+void room_114_preload() {
+ room_init_code_pointer = room_114_init;
+ room_pre_parser_code_pointer = NULL;
+ room_parser_code_pointer = room_114_parser;
+ room_daemon_code_pointer = NULL;
+
+ if (global[current_year] == 1993) {
+ kernel_initial_variant = 1;
+ }
+
+ section_1_walker();
+ section_1_interface();
+}
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/rooms/room114.h b/engines/mads/madsv2/phantom/rooms/room114.h
new file mode 100644
index 00000000000..551984187bf
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room114.h
@@ -0,0 +1,72 @@
+/* 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/>.
+ *
+ */
+
+/* room114.mac by Paul Lahaise 8-Jan-93 */
+
+#ifndef MADS_PHANTOM_ROOM114_H
+#define MADS_PHANTOM_ROOM114_H
+
+#include "mads/madsv2/phantom/rooms/section1.h"
+#include "mads/madsv2/phantom/global.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+#define local ((Scratch *)(&game.scratch[0]))
+#define ss local->sprite
+#define seq local->sequence
+#define aa local->animation
+
+typedef struct { /* Room local variables */
+
+ int sprite[15]; /* Sprite series handles */
+ int sequence[15]; /* Sequence handles */
+ int animation[4]; /* Animation handles */
+
+} Scratch;
+
+
+/* ========================= Sprite Series ========================= */
+
+#define fx_1993 0 /* rm114z - 1993 overlay backdrop */
+#define fx_take_9 1 /* *RDR_9 - take-object animation */
+#define fx_rope 2 /* rm114f0 - rope prop sprite */
+#define fx_climb 3 /* rm114a0 - climb animation series */
+
+
+/* ========================= Player positions ====================== */
+
+#define PLAYER_X_FROM_105 218
+#define PLAYER_Y_FROM_105 123
+
+
+extern void room_114_init();
+extern void room_114_parser();
+extern void room_114_preload();
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index e9bc481717c..917a120e588 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -135,6 +135,7 @@ MODULE_OBJS += \
madsv2/phantom/rooms/room111.o \
madsv2/phantom/rooms/room112.o \
madsv2/phantom/rooms/room113.o \
+ madsv2/phantom/rooms/room114.o \
madsv2/phantom/phantom.o \
madsv2/phantom/conv.o \
madsv2/phantom/main_menu.o \
Commit: 211acca44e2fb206026d4a6723a522d2d77d3310
https://github.com/scummvm/scummvm/commit/211acca44e2fb206026d4a6723a522d2d77d3310
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:43+10:00
Commit Message:
MADS: PHANTOM: Change room Scratch fields from int to int16
Changed paths:
engines/mads/madsv2/phantom/rooms/room101.h
engines/mads/madsv2/phantom/rooms/room105.h
engines/mads/madsv2/phantom/rooms/room108.h
engines/mads/madsv2/phantom/rooms/room110.h
engines/mads/madsv2/phantom/rooms/room111.h
engines/mads/madsv2/phantom/rooms/room112.h
engines/mads/madsv2/phantom/rooms/room113.h
engines/mads/madsv2/phantom/rooms/room114.h
diff --git a/engines/mads/madsv2/phantom/rooms/room101.h b/engines/mads/madsv2/phantom/rooms/room101.h
index 4c50e5a7399..d7b59999bf2 100644
--- a/engines/mads/madsv2/phantom/rooms/room101.h
+++ b/engines/mads/madsv2/phantom/rooms/room101.h
@@ -54,7 +54,7 @@ typedef struct { /* Room local variables */
int16 anim_0_running; /* T if aa[0] is running */
int16 anim_1_running; /* T if aa[1] is running */
- int converse_counter; /* counter for talking displacements */
+ int16 converse_counter; /* counter for talking displacements */
} Scratch;
diff --git a/engines/mads/madsv2/phantom/rooms/room105.h b/engines/mads/madsv2/phantom/rooms/room105.h
index 13dbcae34e6..ea4f961ba94 100644
--- a/engines/mads/madsv2/phantom/rooms/room105.h
+++ b/engines/mads/madsv2/phantom/rooms/room105.h
@@ -37,10 +37,10 @@ namespace Rooms {
typedef struct { /* Room local variables */
- int sprite[15]; /* Sprite series handles */
- int sequence[15]; /* Sequence handles */
- int animation[4]; /* Animation handles */
- int column_prop; /* Dynamic HS for column_prop */
+ int16 sprite[15]; /* Sprite series handles */
+ int16 sequence[15]; /* Sequence handles */
+ int16 animation[4]; /* Animation handles */
+ int16 column_prop; /* Dynamic HS for column_prop */
} Scratch;
diff --git a/engines/mads/madsv2/phantom/rooms/room108.h b/engines/mads/madsv2/phantom/rooms/room108.h
index abd5d143959..679247aff64 100644
--- a/engines/mads/madsv2/phantom/rooms/room108.h
+++ b/engines/mads/madsv2/phantom/rooms/room108.h
@@ -37,20 +37,20 @@ namespace Rooms {
typedef struct { /* Room local variables */
- int sprite[15]; /* Sprite series handles */
- int sequence[15]; /* Sequence handles */
- int animation[4]; /* Animation handles */
- int anim_0_running;
-
- int char_action; /* action Charles is going to perform */
- int char_frame;
- int char_talk_count;
- int char_shut_up_count;
- int dynamic_char; /* Dynamic HS for Charles */
- int prev_shut_up_frame;
- int max_talk_count; /* max talking count for Charles */
- int did_raise_hand; /* true, when if talking, did raise hand */
- int converse_counter; /* counter for talking displacements */
+ int16 sprite[15]; /* Sprite series handles */
+ int16 sequence[15]; /* Sequence handles */
+ int16 animation[4]; /* Animation handles */
+ int16 anim_0_running;
+
+ int16 char_action; /* action Charles is going to perform */
+ int16 char_frame;
+ int16 char_talk_count;
+ int16 char_shut_up_count;
+ int16 dynamic_char; /* Dynamic HS for Charles */
+ int16 prev_shut_up_frame;
+ int16 max_talk_count; /* max talking count for Charles */
+ int16 did_raise_hand; /* true, when if talking, did raise hand */
+ int16 converse_counter; /* counter for talking displacements */
} Scratch;
diff --git a/engines/mads/madsv2/phantom/rooms/room110.h b/engines/mads/madsv2/phantom/rooms/room110.h
index 7eeafdedd26..d449c30209f 100644
--- a/engines/mads/madsv2/phantom/rooms/room110.h
+++ b/engines/mads/madsv2/phantom/rooms/room110.h
@@ -37,9 +37,9 @@ namespace Rooms {
typedef struct { /* Room local variables */
- int sprite[15]; /* Sprite series handles */
- int sequence[15]; /* Sequence handles */
- int animation[4]; /* Animation handles */
+ int16 sprite[15]; /* Sprite series handles */
+ int16 sequence[15]; /* Sequence handles */
+ int16 animation[4]; /* Animation handles */
} Scratch;
diff --git a/engines/mads/madsv2/phantom/rooms/room111.h b/engines/mads/madsv2/phantom/rooms/room111.h
index 4963f98b180..46ec7cc6040 100644
--- a/engines/mads/madsv2/phantom/rooms/room111.h
+++ b/engines/mads/madsv2/phantom/rooms/room111.h
@@ -19,8 +19,6 @@
*
*/
-/* room111.mac by Paul Lahaise 8-Jan-93 */
-
#ifndef MADS_PHANTOM_ROOM111_H
#define MADS_PHANTOM_ROOM111_H
@@ -39,15 +37,15 @@ namespace Rooms {
typedef struct { /* Room local variables */
- int sprite[15]; /* Sprite series handles */
- int sequence[15]; /* Sequence handles */
- int animation[4]; /* Animation handles */
- int delete_axe; /* true if axe was deleted */
- int anim_0_running;
- int anim_1_running;
- int listen_frame;
- int listen_action;
- int it_is_closed;
+ int16 sprite[15]; /* Sprite series handles */
+ int16 sequence[15]; /* Sequence handles */
+ int16 animation[4]; /* Animation handles */
+ int16 delete_axe; /* true if axe was deleted */
+ int16 anim_0_running;
+ int16 anim_1_running;
+ int16 listen_frame;
+ int16 listen_action;
+ int16 it_is_closed;
} Scratch;
diff --git a/engines/mads/madsv2/phantom/rooms/room112.h b/engines/mads/madsv2/phantom/rooms/room112.h
index 6f2dca80ad2..762f3fa1aac 100644
--- a/engines/mads/madsv2/phantom/rooms/room112.h
+++ b/engines/mads/madsv2/phantom/rooms/room112.h
@@ -19,8 +19,6 @@
*
*/
-/* room112.mac by Paul Lahaise 8-Jan-93 */
-
#ifndef MADS_PHANTOM_ROOM112_H
#define MADS_PHANTOM_ROOM112_H
@@ -39,20 +37,20 @@ namespace Rooms {
typedef struct { /* Room local variables */
- int sprite[15]; /* Sprite series handles */
- int sequence[15]; /* Sequence handles */
- int animation[4]; /* Animation handles */
- int dynamic_julie; /* For dynamic HS of Julie */
- int anim_0_running; /* T if Julie's practicing anim is running */
- int anim_1_running; /* T if Raoul's chair movement anim is running */
- int just_did_option;
- int julie_frame;
- int julie_action;
- int julie_talk_count;
- int raoul_frame;
- int raoul_action;
- int raoul_talk_count;
- int display_wait; /* for getting up out of the chair */
+ int16 sprite[15]; /* Sprite series handles */
+ int16 sequence[15]; /* Sequence handles */
+ int16 animation[4]; /* Animation handles */
+ int16 dynamic_julie; /* For dynamic HS of Julie */
+ int16 anim_0_running; /* T if Julie's practicing anim is running */
+ int16 anim_1_running; /* T if Raoul's chair movement anim is running */
+ int16 just_did_option;
+ int16 julie_frame;
+ int16 julie_action;
+ int16 julie_talk_count;
+ int16 raoul_frame;
+ int16 raoul_action;
+ int16 raoul_talk_count;
+ int16 display_wait; /* for getting up out of the chair */
} Scratch;
diff --git a/engines/mads/madsv2/phantom/rooms/room113.h b/engines/mads/madsv2/phantom/rooms/room113.h
index db154f63ba6..5efb084c1f9 100644
--- a/engines/mads/madsv2/phantom/rooms/room113.h
+++ b/engines/mads/madsv2/phantom/rooms/room113.h
@@ -19,8 +19,6 @@
*
*/
-/* room113.mac by Paul Lahaise 8-Jan-93 */
-
#ifndef MADS_PHANTOM_ROOM113_H
#define MADS_PHANTOM_ROOM113_H
@@ -39,42 +37,42 @@ namespace Rooms {
typedef struct { /* Room local variables */
- int sprite[15]; /* Sprite series handles */
- int sequence[15]; /* Sequence handles */
- int animation[5]; /* Animation handles [0=Daae, 1=Raoul13/Raoul4's */
- /* proxy, 2=Florent, 3=Raoul4, 4=Julie] */
-
- int chris_daae_dynamic; /* Dynamic HS for Christine (love scene) */
- int chris_flor_dynamic; /* Dynamic HS for Christine/Florent (1993) */
-
- int standing_talking; /* T once Daae & Raoul are standing face-to-face */
- int day_wants_to_talk; /* T if Daae should start talking at next idle pt */
- int music_is_playing; /* T once angel music has been triggered */
- int right_after_kiss; /* T once kiss frame (165) has been reached */
- int anim_0_running; /* T if Daae animation is active */
- int anim_1_running; /* T if Raoul-13 animation is active */
- int anim_2_running; /* T if Florent animation is active */
- int anim_3_running; /* T if Raoul-4 animation is active */
- int anim_4_running; /* T if Julie animation is active */
- int prevent_1; /* Prevent first-time code from repeating */
- int prevent_2; /* Prevent first-time code from repeating */
- int raoul_is_up; /* T once Raoul has stood up from couch */
- int arms_are_out; /* T once Daae has arms outstretched (frame 95) */
-
- int day_frame;
- int day_action;
- int day_talk_count;
- int stand_talk_count;
- int florent_frame;
- int florent_action;
- int florent_talk_count;
- int raoul_frame;
- int raoul_action;
- int raoul_talk_count;
- int julie_frame;
- int julie_action;
- int julie_talk_count;
- int just_did_option;
+ int16 sprite[15]; /* Sprite series handles */
+ int16 sequence[15]; /* Sequence handles */
+ int16 animation[5]; /* Animation handles [0=Daae, 1=Raoul13/Raoul4's */
+ /* proxy, 2=Florent, 3=Raoul4, 4=Julie] */
+
+ int16 chris_daae_dynamic; /* Dynamic HS for Christine (love scene) */
+ int16 chris_flor_dynamic; /* Dynamic HS for Christine/Florent (1993) */
+
+ int16 standing_talking; /* T once Daae & Raoul are standing face-to-face */
+ int16 day_wants_to_talk; /* T if Daae should start talking at next idle pt */
+ int16 music_is_playing; /* T once angel music has been triggered */
+ int16 right_after_kiss; /* T once kiss frame (165) has been reached */
+ int16 anim_0_running; /* T if Daae animation is active */
+ int16 anim_1_running; /* T if Raoul-13 animation is active */
+ int16 anim_2_running; /* T if Florent animation is active */
+ int16 anim_3_running; /* T if Raoul-4 animation is active */
+ int16 anim_4_running; /* T if Julie animation is active */
+ int16 prevent_1; /* Prevent first-time code from repeating */
+ int16 prevent_2; /* Prevent first-time code from repeating */
+ int16 raoul_is_up; /* T once Raoul has stood up from couch */
+ int16 arms_are_out; /* T once Daae has arms outstretched (frame 95) */
+
+ int16 day_frame;
+ int16 day_action;
+ int16 day_talk_count;
+ int16 stand_talk_count;
+ int16 florent_frame;
+ int16 florent_action;
+ int16 florent_talk_count;
+ int16 raoul_frame;
+ int16 raoul_action;
+ int16 raoul_talk_count;
+ int16 julie_frame;
+ int16 julie_action;
+ int16 julie_talk_count;
+ int16 just_did_option;
} Scratch;
diff --git a/engines/mads/madsv2/phantom/rooms/room114.h b/engines/mads/madsv2/phantom/rooms/room114.h
index 551984187bf..b8d916ed8b3 100644
--- a/engines/mads/madsv2/phantom/rooms/room114.h
+++ b/engines/mads/madsv2/phantom/rooms/room114.h
@@ -19,8 +19,6 @@
*
*/
-/* room114.mac by Paul Lahaise 8-Jan-93 */
-
#ifndef MADS_PHANTOM_ROOM114_H
#define MADS_PHANTOM_ROOM114_H
@@ -38,7 +36,6 @@ namespace Rooms {
#define aa local->animation
typedef struct { /* Room local variables */
-
int sprite[15]; /* Sprite series handles */
int sequence[15]; /* Sequence handles */
int animation[4]; /* Animation handles */
Commit: 8a64f7da4667d1400c963f818a0c5906bed141b0
https://github.com/scummvm/scummvm/commit/8a64f7da4667d1400c963f818a0c5906bed141b0
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:43+10:00
Commit Message:
MADS: PHANTOM: Added room 150
Changed paths:
A engines/mads/madsv2/phantom/rooms/room150.cpp
A engines/mads/madsv2/phantom/rooms/room150.h
engines/mads/module.mk
diff --git a/engines/mads/madsv2/phantom/rooms/room150.cpp b/engines/mads/madsv2/phantom/rooms/room150.cpp
new file mode 100644
index 00000000000..22a3ff92216
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room150.cpp
@@ -0,0 +1,102 @@
+/* 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 "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/matte.h"
+#include "mads/madsv2/core/mcga.h"
+#include "mads/madsv2/core/pal.h"
+#include "mads/madsv2/phantom/global.h"
+#include "mads/madsv2/phantom/rooms/section1.h"
+#include "mads/madsv2/phantom/rooms/room150.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+void room_150_init() {
+ viewing_at_y = ((video_y - display_y) >> 1);
+
+ player.commands_allowed = false;
+ player.walker_visible = false;
+
+ if (previous_room == 113) {
+ aa[0] = kernel_run_animation(kernel_name('l', 1), 1);
+
+ } else if (previous_room == 203) {
+ aa[0] = kernel_run_animation(kernel_name('f', 1), 2);
+ section_1_music();
+
+ } else if (previous_room == 306) {
+ aa[0] = kernel_run_animation(kernel_name('e', 1), 4);
+
+ } else if (previous_room == 208) {
+ aa[0] = kernel_run_animation(kernel_name('h', 1), 3);
+
+ } else {
+ aa[0] = kernel_run_animation(kernel_name('q', 1), 5);
+ }
+}
+
+void room_150_daemon() {
+ if (kernel.trigger == 1) {
+ new_room = 203;
+ }
+
+ if (kernel.trigger == 2) {
+ new_room = 111;
+ }
+
+ if (kernel.trigger == 4) {
+ new_room = 204;
+ }
+
+ if (kernel.trigger == 3) {
+ global[jacques_status] = JACQUES_IS_DEAD;
+ new_room = 205;
+ }
+
+ if (kernel.trigger == 5) {
+ game.going = false;
+ win_status = 1;
+ }
+
+ if (new_room != room_id) {
+ memset(&master_palette[4], 0, sizeof(RGBcolor) * 248);
+ mcga_setpal(&master_palette);
+ }
+}
+
+void room_150_preload() {
+ room_init_code_pointer = room_150_init;
+ room_pre_parser_code_pointer = NULL;
+ room_parser_code_pointer = NULL;
+ room_daemon_code_pointer = room_150_daemon;
+
+ section_1_walker();
+ section_1_interface();
+}
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/rooms/room150.h b/engines/mads/madsv2/phantom/rooms/room150.h
new file mode 100644
index 00000000000..ebb5862613c
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room150.h
@@ -0,0 +1,55 @@
+/* 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 MADS_PHANTOM_ROOM150_H
+#define MADS_PHANTOM_ROOM150_H
+
+#include "mads/madsv2/phantom/rooms/section1.h"
+#include "mads/madsv2/phantom/global.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+#define local ((Scratch *)(&game.scratch[0]))
+#define ss local->sprite
+#define seq local->sequence
+#define aa local->animation
+
+typedef struct { /* Room local variables */
+ int16 sprite[15]; /* Sprite series handles */
+ int16 sequence[15]; /* Sequence handles */
+ int16 animation[4]; /* Animation handles */
+
+} Scratch;
+
+
+extern void room_150_init();
+extern void room_150_daemon();
+extern void room_150_preload();
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index 917a120e588..98178eea5d4 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -136,6 +136,7 @@ MODULE_OBJS += \
madsv2/phantom/rooms/room112.o \
madsv2/phantom/rooms/room113.o \
madsv2/phantom/rooms/room114.o \
+ madsv2/phantom/rooms/room150.o \
madsv2/phantom/phantom.o \
madsv2/phantom/conv.o \
madsv2/phantom/main_menu.o \
Commit: b499cdfd37f855a419a1eb66c4212ebec2e2d2ae
https://github.com/scummvm/scummvm/commit/b499cdfd37f855a419a1eb66c4212ebec2e2d2ae
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:43+10:00
Commit Message:
MADS: PHANTOM: Added room 201
Changed paths:
A engines/mads/madsv2/phantom/rooms/room201.cpp
A engines/mads/madsv2/phantom/rooms/room201.h
A engines/mads/madsv2/phantom/rooms/section2.h
engines/mads/madsv2/phantom/conv.h
engines/mads/madsv2/phantom/mads/inventory.h
engines/mads/madsv2/phantom/mads/text.h
engines/mads/madsv2/phantom/mads/words.h
engines/mads/module.mk
diff --git a/engines/mads/madsv2/phantom/conv.h b/engines/mads/madsv2/phantom/conv.h
index 31f11b00911..09c66a5f704 100644
--- a/engines/mads/madsv2/phantom/conv.h
+++ b/engines/mads/madsv2/phantom/conv.h
@@ -145,6 +145,14 @@ enum {
conv014_eighth_inside = 7
};
+enum {
+ conv016_buy_four = 4,
+ conv016_take_b_b = 6,
+ conv016_kind_five = 12,
+ conv016_money_cash = 13,
+ conv016_money_lend = 14
+};
+
struct ConvData {
int16 node_count;
int16 dialog_count;
diff --git a/engines/mads/madsv2/phantom/mads/inventory.h b/engines/mads/madsv2/phantom/mads/inventory.h
index c26d09bea23..ce0b03b1212 100644
--- a/engines/mads/madsv2/phantom/mads/inventory.h
+++ b/engines/mads/madsv2/phantom/mads/inventory.h
@@ -37,6 +37,7 @@ enum {
fire_axe = 5,
small_note = 6,
rope = 7,
+ envelope = 9,
parchment = 12,
book = 15,
blue_frame = 17,
diff --git a/engines/mads/madsv2/phantom/mads/text.h b/engines/mads/madsv2/phantom/mads/text.h
index 9a43760f8d5..3b4d1521eaa 100644
--- a/engines/mads/madsv2/phantom/mads/text.h
+++ b/engines/mads/madsv2/phantom/mads/text.h
@@ -443,7 +443,27 @@ enum {
text_114_36 = 11436,
text_114_37 = 11437,
/* text_114_38 not used */
- text_114_39 = 11439
+ text_114_39 = 11439,
+
+ /* Cross-room text (room 008 range) */
+ text_008_34 = 834,
+
+ /* Room 201 */
+ text_201_10 = 20110,
+ text_201_11 = 20111,
+ text_201_12 = 20112,
+ text_201_13 = 20113,
+ text_201_14 = 20114,
+ text_201_15 = 20115,
+ text_201_16 = 20116,
+ text_201_17 = 20117,
+ text_201_18 = 20118,
+ text_201_19 = 20119,
+ text_201_20 = 20120,
+ text_201_21 = 20121,
+ text_201_22 = 20122,
+ text_201_23 = 20123,
+ text_201_24 = 20124
};
} // namespace Phantom
diff --git a/engines/mads/madsv2/phantom/mads/words.h b/engines/mads/madsv2/phantom/mads/words.h
index a434910eef5..4daa67a0e9a 100644
--- a/engines/mads/madsv2/phantom/mads/words.h
+++ b/engines/mads/madsv2/phantom/mads/words.h
@@ -170,6 +170,10 @@ enum {
words_big_prop = 199,
words_ventilation_duct = 200,
words_chandelier = 201,
+ words_barrier = 202,
+ words_placard = 203,
+ words_ticket_window = 204,
+ words_archway = 205,
words_light = 245,
words_prop_case = 247,
words_case = 247,
@@ -191,6 +195,7 @@ enum {
words_Monsieur_Richard = 302,
words_Julie = 303,
words_cable_hook = 304,
+ words_ticket_seller = 329,
words_hat_rack = 340,
words_vase = 341,
words_clothes_dummy = 342,
diff --git a/engines/mads/madsv2/phantom/rooms/room201.cpp b/engines/mads/madsv2/phantom/rooms/room201.cpp
new file mode 100644
index 00000000000..97cc65787fa
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room201.cpp
@@ -0,0 +1,527 @@
+/* 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 "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/imath.h"
+#include "mads/madsv2/core/text.h"
+#include "mads/madsv2/core/inter.h"
+#include "mads/madsv2/core/object.h"
+#include "mads/madsv2/core/sound.h"
+#include "mads/madsv2/phantom/global.h"
+#include "mads/madsv2/phantom/conv.h"
+#include "mads/madsv2/phantom/mads/inventory.h"
+#include "mads/madsv2/phantom/mads/speeches.h"
+#include "mads/madsv2/phantom/mads/words.h"
+#include "mads/madsv2/phantom/mads/sounds.h"
+#include "mads/madsv2/phantom/mads/text.h"
+#include "mads/madsv2/phantom/rooms/section2.h"
+#include "mads/madsv2/phantom/rooms/room201.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+static void handle_animation_raoul() {
+ int random;
+ int raoul_reset_frame;
+
+ if (kernel_anim[aa[0]].frame != local->raoul_frame) {
+ local->raoul_frame = kernel_anim[aa[0]].frame;
+ raoul_reset_frame = -1;
+
+ switch (local->raoul_frame) {
+ case 9: /* end of take envelope */
+ player.walker_visible = true;
+ local->anim_0_running = false;
+ player.commands_allowed = true;
+ raoul_reset_frame = 49;
+ break;
+
+ case 1: /* end of freeze standing upright */
+ case 19: /* end talk */
+ case 49: /* end of coming from lean */
+
+ random = imath_random(4, 50);
+
+ switch (local->raoul_action) {
+ case CONV16_RAOUL_TALK:
+ random = 1;
+ break;
+
+ case CONV16_RAOUL_TAKE_IT:
+ random = 2;
+ player.commands_allowed = false;
+ break;
+
+ case CONV16_RAOUL_QUIT:
+ random = 3;
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ raoul_reset_frame = 9;
+ local->raoul_action = CONV16_RAOUL_SHUT_UP;
+ break; /* do talk (standing upright) */
+
+ case 2:
+ raoul_reset_frame = 1;
+ break; /* take envelope */
+
+ case 3:
+ player.walker_visible = true;
+ local->seller_action = CONV16_SELLER_LOOK_DOWN;
+ local->anim_0_running = false;
+ raoul_reset_frame = 49;
+ player.commands_allowed = true;
+ local->want_to_hold = false;
+ break; /* quit */
+
+ case 4:
+ raoul_reset_frame = 19;
+ break; /* lean (new node) */
+
+ default:
+ raoul_reset_frame = 0;
+ break; /* freeze while standing upright */
+ }
+ break;
+
+ case 23: /* end of coming to lean and freeze */
+ case 35: /* end of talk */
+ case 45: /* end of hand on chin */
+ random = imath_random(3, 70);
+
+ switch (local->raoul_action) {
+ case CONV16_RAOUL_TAKE_IT:
+ case CONV16_RAOUL_QUIT:
+ random = 1;
+ break;
+
+ case CONV16_RAOUL_TALK:
+ random = 2;
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ raoul_reset_frame = 45;
+ break; /* go to stand upright (new node) */
+
+ case 2:
+ raoul_reset_frame = 23;
+ local->raoul_action = CONV16_RAOUL_SHUT_UP;
+ break; /* talk while leaning */
+
+ case 3:
+ raoul_reset_frame = 35;
+ break; /* hand on chin */
+
+ default:
+ raoul_reset_frame = 22;
+ break; /* freeze while slouch 1 */
+ }
+ break;
+
+ case 5:
+ kernel_seq_delete(seq[fx_envelope]);
+ inter_give_to_player(envelope);
+ sound_play(N_TakeObjectSnd);
+ object_examine(envelope, text_008_34, 0);
+ break;
+ }
+
+ if (raoul_reset_frame >= 0) {
+ kernel_reset_animation(aa[0], raoul_reset_frame);
+ local->raoul_frame = raoul_reset_frame;
+ }
+ }
+}
+
+static void handle_animation_seller() {
+ int random = 0;
+ int seller_reset_frame;
+
+ if (kernel_anim[aa[1]].frame != local->seller_frame) {
+ local->seller_frame = kernel_anim[aa[1]].frame;
+ seller_reset_frame = -1;
+
+ switch (local->seller_frame) {
+ case 1: /* end of talk 1 */
+ case 2: /* end of talk 2 */
+ case 3: /* end of talk 3 */
+ case 4: /* end of talk 4 */
+ case 5: /* end of talk 5 */
+ case 6: /* end of look down 1 */
+ case 7: /* end of look down 2 */
+ case 10: /* end of give envelope */
+
+ if (local->seller_frame == 10) {
+ local->raoul_action = CONV16_RAOUL_TAKE_IT;
+ }
+
+ switch (local->seller_action) {
+ case CONV16_SELLER_TALK:
+ random = imath_random(1, 5);
+ ++local->seller_talk_count;
+ if (local->seller_talk_count > 30) {
+ local->seller_action = CONV16_SELLER_SHUT_UP;
+ random = 6;
+ }
+ break;
+
+ case CONV16_SELLER_LOOK_DOWN:
+ if (local->seller_frame == 6) random = 6;
+ else if (local->seller_frame == 7) random = 7;
+ else random = imath_random(6, 7);
+
+ ++local->seller_talk_count;
+ if (local->seller_talk_count > 30) {
+ local->seller_talk_count = 0;
+ random = imath_random(6, 7);
+ }
+ break;
+
+ case CONV16_SELLER_SHUT_UP:
+ random = 1;
+ break;
+
+ case CONV16_SELLER_GIVE:
+ random = 8;
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ seller_reset_frame = 0;
+ break; /* do talk 1 and shut up */
+
+ case 2:
+ seller_reset_frame = 1;
+ break; /* do talk 2 */
+
+ case 3:
+ seller_reset_frame = 2;
+ break; /* do talk 3 */
+
+ case 4:
+ seller_reset_frame = 3;
+ break; /* do talk 4 */
+
+ case 5:
+ seller_reset_frame = 4;
+ break; /* do talk 5 */
+
+ case 6:
+ seller_reset_frame = 5;
+ break; /* do look down 1 */
+
+ case 7:
+ seller_reset_frame = 6;
+ break; /* do look down 2 */
+
+ case 8:
+ seller_reset_frame = 7;
+ break; /* give envelope */
+ }
+ break;
+
+ case 9:
+ seq[fx_envelope] = kernel_seq_stamp(ss[fx_envelope], false, 1);
+ kernel_seq_depth(seq[fx_envelope], 1);
+ local->seller_action = CONV16_SELLER_LOOK_DOWN;
+ break;
+ }
+
+ if (seller_reset_frame >= 0) {
+ kernel_reset_animation(aa[1], seller_reset_frame);
+ local->seller_frame = seller_reset_frame;
+ }
+ }
+}
+
+void room_201_init() {
+ if (previous_room != KERNEL_RESTORING_GAME) {
+ local->anim_0_running = false;
+ local->anim_1_running = false;
+ }
+
+ local->seller_talk_count = 0;
+ local->want_to_hold = false;
+
+ /* =================== Load conversation ======================== */
+
+ conv_get(CONV_TICKET_16);
+
+
+ /* =================== Load Sprite Series ======================= */
+
+ ss[fx_curtain] = kernel_load_series(kernel_name('x', 0), false);
+ ss[fx_envelope] = kernel_load_series(kernel_name('f', 0), false);
+
+
+ /* ================ Start anim of ticket seller ================= */
+
+ if (global[ticket_people_here]) {
+ aa[1] = kernel_run_animation(kernel_name('s', 1), 0);
+ local->anim_1_running = true;
+ local->seller_action = CONV16_SELLER_LOOK_DOWN;
+ kernel_reset_animation(aa[1], 5); /* make ticket seller look down */
+
+ } else {
+ kernel_flip_hotspot(words_ticket_seller, false);
+ seq[fx_curtain] = kernel_seq_stamp(ss[fx_curtain], false, 1);
+ kernel_seq_depth(seq[fx_curtain], 14);
+ }
+
+ if (conv_restore_running == CONV_TICKET_16) {
+ player.x = WINDOW_X;
+ player.y = WINDOW_Y;
+ player.facing = FACING_NORTHWEST;
+ aa[0] = kernel_run_animation(kernel_name('r', 1), 0);
+ local->anim_0_running = true;
+ local->raoul_action = CONV16_RAOUL_SHUT_UP;
+ player.walker_visible = false;
+
+ conv_run(CONV_TICKET_16);
+ conv_export_pointer(&global[player_score]);
+ conv_export_pointer(&global[christine_told_envelope]);
+ }
+
+
+ /* ========================= Previous Rooms ===================== */
+
+ if ((previous_room == 202) || (previous_room != KERNEL_RESTORING_GAME)) {
+ player.x = PLAYER_X_FROM_202;
+ player.y = PLAYER_Y_FROM_202;
+ player_walk(WALK_TO_X_FROM_202, WALK_TO_Y_FROM_202, FACING_SOUTHWEST);
+ }
+
+ section_2_music();
+}
+
+void room_201_daemon() {
+ if (local->anim_0_running) {
+ handle_animation_raoul();
+ }
+
+ if (local->anim_1_running) {
+ handle_animation_seller();
+ }
+
+ if ((local->want_to_hold) && (conv_control.running != CONV_TICKET_16)) {
+ player.commands_allowed = false;
+ local->want_to_hold = false;
+ }
+}
+
+static void process_conversation_16() {
+ int you_trig_flag = false;
+ int me_trig_flag = false;
+
+ switch (player_verb) {
+ case conv016_take_b_b:
+ local->seller_action = CONV16_SELLER_GIVE;
+ local->want_to_hold = true;
+ you_trig_flag = true;
+ me_trig_flag = true;
+ break;
+
+ case conv016_buy_four:
+ case conv016_kind_five:
+ case conv016_money_cash:
+ case conv016_money_lend:
+ conv_you_trigger(ROOM_201_END);
+ local->want_to_hold = true;
+ you_trig_flag = true;
+ break;
+ }
+
+ switch (kernel.trigger) {
+ case ROOM_201_END:
+ conv_me_trigger(ROOM_201_END + 1);
+ me_trig_flag = true;
+ break;
+
+ case ROOM_201_END + 1:
+ local->raoul_action = CONV16_RAOUL_QUIT;
+ me_trig_flag = true;
+ you_trig_flag = true;
+ break;
+
+ case ROOM_201_SELLER_TALK:
+ if (local->seller_action != CONV16_SELLER_GIVE) {
+ local->seller_action = CONV16_SELLER_TALK;
+ }
+ break;
+
+ case ROOM_201_ME_TALK:
+ if (local->seller_action != CONV16_SELLER_GIVE) {
+ local->seller_action = CONV16_SELLER_SHUT_UP;
+ local->raoul_action = CONV16_RAOUL_TALK;
+ }
+ break;
+ }
+
+
+ /* ================= Set up me and you triggers ================ */
+
+ if (!me_trig_flag) {
+ conv_me_trigger(ROOM_201_ME_TALK);
+ } /* if me_trig_flag == true, then a me trigger is called from above, not here. */
+
+ if (!you_trig_flag) {
+ conv_you_trigger(ROOM_201_SELLER_TALK);
+ } /* if you_trig_flag == true, then a you trigger is called from above, not here. */
+
+ local->seller_talk_count = 0;
+}
+
+void room_201_pre_parser() {
+ if (player_said_1(look) || player_said_1(look_at)) {
+ if (player_said_1(placard)) {
+ player_walk(SIGN_X, SIGN_Y, FACING_NORTHWEST);
+ }
+ }
+}
+
+void room_201_parser() {
+ if (conv_control.running == CONV_TICKET_16) {
+ process_conversation_16();
+ goto handled;
+ }
+
+ if (player_said_2(walk_through, archway)) {
+ new_room = 202;
+ goto handled;
+ }
+
+ if (player_said_2(talk_to, ticket_seller)) {
+ aa[0] = kernel_run_animation(kernel_name('r', 1), 0);
+ local->anim_0_running = true;
+ local->raoul_action = CONV16_RAOUL_SHUT_UP;
+ conv_run(CONV_TICKET_16);
+ conv_export_pointer(&global[player_score]);
+ conv_export_pointer(&global[christine_told_envelope]);
+ player.walker_visible = false;
+ goto handled;
+ }
+
+ if (player.look_around) {
+ if (global[current_year] == 1993) {
+ text_show(text_201_10);
+ } else {
+ text_show(text_201_11);
+ }
+ goto handled;
+ }
+
+ if (player_said_1(look) || player_said_1(look_at)) {
+
+ if (player_said_1(floor)) {
+ text_show(text_201_12);
+ goto handled;
+ }
+
+ if (player_said_1(wall)) {
+ text_show(text_201_13);
+ goto handled;
+ }
+
+ if (player_said_1(bust)) {
+ text_show(text_201_14);
+ goto handled;
+ }
+
+ if (player_said_1(pedestal)) {
+ text_show(text_201_15);
+ goto handled;
+ }
+
+ if (player_said_1(barrier)) {
+ text_show(text_201_16);
+ goto handled;
+ }
+
+ if (player_said_1(placard)) {
+ if (global[current_year] == 1993) {
+ text_show(text_201_17);
+ } else {
+ text_show(text_201_18);
+ }
+ goto handled;
+ }
+
+ if (player_said_1(ticket_window)) {
+ if (global[current_year] == 1993) {
+ text_show(text_201_19);
+ } else {
+ text_show(text_201_20);
+ }
+ goto handled;
+ }
+
+ if (player_said_1(archway)) {
+ text_show(text_201_21);
+ goto handled;
+ }
+
+ if (player_said_1(ticket_seller)) {
+ text_show(text_201_23);
+ goto handled;
+ }
+ }
+
+ if (player_said_2(take, ticket_seller)) {
+ text_show(text_201_24);
+ goto handled;
+ }
+
+ if (player_said_2(talk_to, bust)) {
+ text_show(text_201_22);
+ goto handled;
+ }
+
+ goto done;
+
+handled:
+ player.command_ready = false;
+
+done:
+ ;
+}
+
+void room_201_preload() {
+ room_init_code_pointer = room_201_init;
+ room_pre_parser_code_pointer = room_201_pre_parser;
+ room_parser_code_pointer = room_201_parser;
+ room_daemon_code_pointer = room_201_daemon;
+
+ section_2_walker();
+ section_2_interface();
+}
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/rooms/room201.h b/engines/mads/madsv2/phantom/rooms/room201.h
new file mode 100644
index 00000000000..0d026721b7b
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room201.h
@@ -0,0 +1,118 @@
+/* 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 MADS_PHANTOM_ROOM201_H
+#define MADS_PHANTOM_ROOM201_H
+
+#include "mads/madsv2/phantom/rooms/section2.h"
+#include "mads/madsv2/phantom/global.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+#define local ((Scratch *)(&game.scratch[0]))
+#define ss local->sprite
+#define seq local->sequence
+#define aa local->animation
+
+typedef struct { /* Room local variables */
+
+ int16 sprite[15]; /* Sprite series handles */
+ int16 sequence[15]; /* Sequence handles */
+ int16 animation[4]; /* Animation handles */
+
+ int16 raoul_frame;
+ int16 raoul_action;
+ int16 anim_0_running;
+
+ int16 seller_frame;
+ int16 seller_action;
+ int16 seller_talk_count;
+ int16 anim_1_running;
+ int16 want_to_hold;
+
+} Scratch;
+
+
+/* ========================= Sprite Series ========================= */
+
+#define fx_curtain 0 /* rm201x0 */
+#define fx_envelope 1 /* rm201f0 */
+
+
+/* ========================= Conversation ========================== */
+
+#define CONV_TICKET_16 16
+
+/* Conv 16 â Raoul action states */
+#define CONV16_RAOUL_TALK 0
+#define CONV16_RAOUL_SHUT_UP 1
+#define CONV16_RAOUL_TAKE_IT 2
+#define CONV16_RAOUL_QUIT 3
+
+/* Conv 16 â Seller action states */
+#define CONV16_SELLER_SHUT_UP 0
+#define CONV16_SELLER_TALK 1
+#define CONV16_SELLER_LOOK_DOWN 2
+#define CONV16_SELLER_GIVE 3
+
+
+/* ========================= Triggers ============================== */
+
+#define ROOM_201_DOOR_CLOSES 60
+#define ROOM_201_SELLER_TALK 65
+#define ROOM_201_ME_TALK 70
+#define ROOM_201_DONE_RAOUL_ANIM 80
+#define ROOM_201_END 90
+
+
+/* ========================= Player positions ====================== */
+
+#define PLAYER_X_FROM_202 314
+#define PLAYER_Y_FROM_202 86
+
+#define WALK_TO_X_FROM_202 266
+#define WALK_TO_Y_FROM_202 98
+
+
+/* ========================= Misc positions ======================== */
+
+#define WINDOW_X 72
+#define WINDOW_Y 101
+
+#define SIGN_X 147
+#define SIGN_Y 104
+
+
+extern void room_201_init();
+extern void room_201_daemon();
+extern void room_201_pre_parser();
+extern void room_201_parser();
+extern void room_201_preload();
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/phantom/rooms/section2.h b/engines/mads/madsv2/phantom/rooms/section2.h
new file mode 100644
index 00000000000..152ca751079
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/section2.h
@@ -0,0 +1,44 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 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 MADS_PHANTOM_SECTION2_H
+#define MADS_PHANTOM_SECTION2_H
+
+#include "mads/madsv2/phantom/global.h"
+#include "mads/madsv2/phantom/mads/text.h"
+#include "mads/madsv2/phantom/mads/words.h"
+#include "mads/madsv2/core/vocabh.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+extern void section_2_music();
+extern void section_2_walker();
+extern void section_2_interface();
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index 98178eea5d4..bcfa320d4d9 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -137,6 +137,8 @@ MODULE_OBJS += \
madsv2/phantom/rooms/room113.o \
madsv2/phantom/rooms/room114.o \
madsv2/phantom/rooms/room150.o \
+ madsv2/phantom/rooms/section2.o \
+ madsv2/phantom/rooms/room201.o \
madsv2/phantom/phantom.o \
madsv2/phantom/conv.o \
madsv2/phantom/main_menu.o \
Commit: 66e2e88e47448936c6373aded8331b5ac4361909
https://github.com/scummvm/scummvm/commit/66e2e88e47448936c6373aded8331b5ac4361909
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:44+10:00
Commit Message:
MADS: PHANTOM: Added room 202
Changed paths:
A engines/mads/madsv2/phantom/rooms/room202.cpp
A engines/mads/madsv2/phantom/rooms/room202.h
engines/mads/madsv2/phantom/conv.h
engines/mads/madsv2/phantom/global.h
engines/mads/madsv2/phantom/mads/inventory.h
engines/mads/madsv2/phantom/mads/text.h
engines/mads/madsv2/phantom/mads/words.h
engines/mads/module.mk
diff --git a/engines/mads/madsv2/phantom/conv.h b/engines/mads/madsv2/phantom/conv.h
index 09c66a5f704..f04c3e247b2 100644
--- a/engines/mads/madsv2/phantom/conv.h
+++ b/engines/mads/madsv2/phantom/conv.h
@@ -116,6 +116,14 @@ enum {
conv007_pinch_wait_b_nothing_b = 32,
};
+enum {
+ conv009_dialogue_one = 1,
+ conv009_dialogue_paint = 2,
+ conv009_dialogue_three = 10,
+ conv009_lips_abc = 11,
+ conv009_wink_abc = 12
+};
+
enum {
conv012_hello_one = 1,
conv012_hello_four = 4,
@@ -153,6 +161,12 @@ enum {
conv016_money_lend = 14
};
+enum {
+ conv017_ticket_block = 0,
+ conv017_hasit_first = 3,
+ conv017_hasnot_first = 4
+};
+
struct ConvData {
int16 node_count;
int16 dialog_count;
diff --git a/engines/mads/madsv2/phantom/global.h b/engines/mads/madsv2/phantom/global.h
index 2ed1a3b4d48..df5aea51ada 100644
--- a/engines/mads/madsv2/phantom/global.h
+++ b/engines/mads/madsv2/phantom/global.h
@@ -200,6 +200,7 @@ enum {
// ticket_people_here
#define SELLER 1
+#define USHER_AND_SELLER 2
// sandbag_status
#define SANDBAG_DROPPED 1
diff --git a/engines/mads/madsv2/phantom/mads/inventory.h b/engines/mads/madsv2/phantom/mads/inventory.h
index ce0b03b1212..b2fc786caaa 100644
--- a/engines/mads/madsv2/phantom/mads/inventory.h
+++ b/engines/mads/madsv2/phantom/mads/inventory.h
@@ -38,6 +38,7 @@ enum {
small_note = 6,
rope = 7,
envelope = 9,
+ ticket = 10,
parchment = 12,
book = 15,
blue_frame = 17,
diff --git a/engines/mads/madsv2/phantom/mads/text.h b/engines/mads/madsv2/phantom/mads/text.h
index 3b4d1521eaa..ec906e2b4d9 100644
--- a/engines/mads/madsv2/phantom/mads/text.h
+++ b/engines/mads/madsv2/phantom/mads/text.h
@@ -463,7 +463,27 @@ enum {
text_201_21 = 20121,
text_201_22 = 20122,
text_201_23 = 20123,
- text_201_24 = 20124
+ text_201_24 = 20124,
+
+ /* Room 202 */
+ text_202_10 = 20210,
+ text_202_11 = 20211,
+ text_202_12 = 20212,
+ text_202_13 = 20213,
+ text_202_14 = 20214,
+ text_202_15 = 20215,
+ text_202_16 = 20216,
+ text_202_17 = 20217,
+ text_202_18 = 20218,
+ text_202_19 = 20219,
+ text_202_20 = 20220,
+ text_202_21 = 20221,
+ text_202_22 = 20222,
+ text_202_23 = 20223,
+ text_202_24 = 20224,
+ text_202_25 = 20225,
+ text_202_26 = 20226,
+ text_202_27 = 20227
};
} // namespace Phantom
diff --git a/engines/mads/madsv2/phantom/mads/words.h b/engines/mads/madsv2/phantom/mads/words.h
index 4daa67a0e9a..ad585aa5889 100644
--- a/engines/mads/madsv2/phantom/mads/words.h
+++ b/engines/mads/madsv2/phantom/mads/words.h
@@ -122,6 +122,7 @@ enum {
words_stool = 140,
words_table = 143,
words_thunder_machine = 145,
+ words_ticket = 146,
words_trap_ceiling = 147,
words_trap_door = 148,
words_unlock = 151,
@@ -174,6 +175,10 @@ enum {
words_placard = 203,
words_ticket_window = 204,
words_archway = 205,
+ words_overdoor_medallion = 223,
+ words_decorative_molding = 225,
+ words_left_archway = 227,
+ words_right_archway = 229,
words_light = 245,
words_prop_case = 247,
words_case = 247,
@@ -181,6 +186,7 @@ enum {
words_axe = 249,
words_door_chunks = 250,
words_bulletin_board = 252,
+ words_middle_door = 256,
words_dressing_gown = 257,
words_Monsieur_Brie = 258,
words_Christine = 268,
@@ -196,9 +202,11 @@ enum {
words_Julie = 303,
words_cable_hook = 304,
words_ticket_seller = 329,
+ words_usher = 330,
words_hat_rack = 340,
words_vase = 341,
words_clothes_dummy = 342,
+ words_Edgar_Degas = 385,
words_hook = 390,
words_paper = 399
};
diff --git a/engines/mads/madsv2/phantom/rooms/room202.cpp b/engines/mads/madsv2/phantom/rooms/room202.cpp
new file mode 100644
index 00000000000..b1076133022
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room202.cpp
@@ -0,0 +1,998 @@
+/* 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 "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/camera.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/imath.h"
+#include "mads/madsv2/core/text.h"
+#include "mads/madsv2/core/inter.h"
+#include "mads/madsv2/core/matte.h"
+#include "mads/madsv2/core/object.h"
+#include "mads/madsv2/core/sound.h"
+#include "mads/madsv2/phantom/global.h"
+#include "mads/madsv2/phantom/conv.h"
+#include "mads/madsv2/phantom/mads/inventory.h"
+#include "mads/madsv2/phantom/mads/speeches.h"
+#include "mads/madsv2/phantom/mads/words.h"
+#include "mads/madsv2/phantom/mads/sounds.h"
+#include "mads/madsv2/phantom/mads/text.h"
+#include "mads/madsv2/phantom/rooms/section2.h"
+#include "mads/madsv2/phantom/rooms/room202.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+void set_chandelier_positions() {
+ int chandelier;
+ int center;
+ int difference;
+ int direction;
+ int distance;
+ int displace;
+ int x;
+ int y;
+ int xs;
+
+ center = picture_view_x + (video_x >> 1);
+
+ for (chandelier = 0; chandelier < NUM_CHANDELIERS; chandelier++) {
+
+ if (seq[chandelier + fx_chandelier_0] >= 0) {
+ kernel_seq_delete(seq[chandelier + fx_chandelier_0]);
+ }
+
+ difference = center - local->chandelier_base[chandelier];
+ direction = neg(sgn(difference));
+ distance = abs(difference);
+
+ displace = (int)(((long)distance * camera_ratio_1) / camera_ratio_2);
+ displace = sgn_in(displace, direction);
+
+ x = local->chandelier_base[chandelier] + displace - 1;
+ y = series_list[ss[fx_chandelier_0]]->index[0].ys - 1;
+ xs = series_list[ss[fx_chandelier_0]]->index[0].xs;
+
+ if (((x - ((xs >> 1) + 1)) >= (picture_view_x + video_x)) ||
+ ((x + ((xs >> 1) + 1)) < picture_view_x)) {
+ seq[chandelier + fx_chandelier_0] = -1;
+ } else {
+ if (local->dyn_chandeliers[chandelier] != -1) {
+ kernel_delete_dynamic(local->dyn_chandeliers[chandelier]);
+ }
+
+ local->dyn_chandeliers[chandelier] = kernel_add_dynamic(words_chandelier, words_look_at, SYNTAX_SINGULAR, KERNEL_NONE,
+ x - 8, y - 12, 16, 13);
+
+ seq[chandelier + fx_chandelier_0] =
+ kernel_seq_stamp(ss[fx_chandelier_0], false, 1);
+ kernel_seq_loc(seq[chandelier + fx_chandelier_0], x, y);
+ kernel_seq_depth(seq[chandelier + fx_chandelier_0], 1);
+ }
+ }
+}
+
+static void handle_animation_usher() {
+ int random = 0;
+ int usher_reset_frame;
+
+ if (kernel_anim[aa[0]].frame != local->usher_frame) {
+ local->usher_frame = kernel_anim[aa[0]].frame;
+ usher_reset_frame = -1;
+
+ switch (local->usher_frame) {
+ case 1: /* end of freeze */
+ case 35: /* end of point */
+ case 51: /* end of put left arm up */
+ case 52: /* end of talk 1 */
+ case 53: /* end of talk 2 */
+ case 54: /* end of talk 3 */
+ case 13: /* end of do you have ticket */
+
+ switch (local->usher_action) {
+ case CONV17_USHER_TALK:
+ random = imath_random(1, 3);
+ ++local->usher_talk_count;
+ if (local->usher_talk_count > 15) {
+ if (player_verb == conv017_ticket_block) {
+ local->usher_action = CONV17_USHER_HAVE_TICKET;
+ random = 5;
+ } else {
+ local->usher_action = CONV17_USHER_SHUT_UP;
+ random = 7;
+ }
+ }
+ break;
+
+ case CONV17_USHER_POINT:
+ random = 4;
+ break;
+
+ case CONV17_USHER_HAVE_TICKET:
+ random = 5;
+ break;
+
+ case CONV17_USHER_LEFT_UP:
+ random = 6;
+ break;
+
+ default:
+ random = 7;
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ usher_reset_frame = 51;
+ break; /* do talk 1 */
+
+ case 2:
+ usher_reset_frame = 52;
+ break; /* do talk 2 */
+
+ case 3:
+ usher_reset_frame = 53;
+ break; /* do talk 3 */
+
+ case 4:
+ usher_reset_frame = 21;
+ local->usher_action = CONV17_USHER_POINT;
+ break; /* point (new node) */
+
+ case 5:
+ usher_reset_frame = 1;
+ break; /* do you have ticket (new node) */
+
+ case 6:
+ usher_reset_frame = 35;
+ local->usher_action = CONV17_USHER_TALK;
+ break; /* put left arm up (to block the entrance) */
+
+ default:
+ usher_reset_frame = 0;
+ break; /* freeze sitting still */
+ }
+ break;
+
+ case 7: /* holding hand out */
+ switch (local->usher_action) {
+ case CONV17_USHER_HAVE_TICKET:
+ random = 1;
+ break;
+
+ default:
+ random = 2;
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ usher_reset_frame = 6;
+ break; /* keep hand out */
+
+ default:
+ usher_reset_frame = 7;
+ break; /* go to stand still (new node) */
+ }
+ break;
+
+ case 28: /* pointing */
+ switch (local->usher_action) {
+ case CONV17_USHER_POINT:
+ random = 1;
+ ++local->usher_talk_count;
+ if (local->usher_talk_count > 15) {
+ local->usher_action = CONV17_USHER_SHUT_UP;
+ random = 2;
+ }
+ break;
+
+ default:
+ random = 2;
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ usher_reset_frame = 27;
+ break; /* keep pointing */
+
+ default:
+ usher_reset_frame = 28;
+ break; /* go to stand still (new node) */
+ }
+ break;
+ }
+
+ if (usher_reset_frame >= 0) {
+ kernel_reset_animation(aa[0], usher_reset_frame);
+ local->usher_frame = usher_reset_frame;
+ }
+ }
+}
+
+static void handle_animation_degas() {
+ int random = 0;
+ int degas_reset_frame;
+
+ if (kernel_anim[aa[1]].frame != local->degas_frame) {
+ local->degas_frame = kernel_anim[aa[1]].frame;
+ degas_reset_frame = -1;
+
+ switch (local->degas_frame) {
+ case 110:
+ conv_release();
+ break;
+
+ case 1: /* end of freeze */
+ case 17: /* end of talk 1 */
+ case 58: /* end of put bag down */
+ switch (local->degas_action) {
+ case CONV9_DEGAS_TALK:
+ local->degas_action = CONV9_DEGAS_SHUT_UP;
+ random = 1;
+ break;
+
+ case CONV9_DEGAS_BOW:
+ case CONV9_DEGAS_GIRL:
+ case CONV9_DEGAS_LEAVE:
+ random = 2;
+ break; /* pull bag up under arm (new node) */
+
+ default:
+ random = imath_random(3, 50);
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ degas_reset_frame = 1;
+ break; /* do talk */
+
+ case 2:
+ degas_reset_frame = 58;
+ break; /* pull bag up under arm (new node) */
+
+ case 3:
+ degas_reset_frame = 58;
+ break; /* pull bag up under arm (new node) while shutting up */
+
+ default:
+ degas_reset_frame = 0;
+ break; /* freeze standing still */
+ }
+ break;
+
+ case 62: /* end of pulling bag up */
+ case 55: /* end of talking about girls */
+ case 40: /* end of generic talk and freeze */
+ case 33: /* end of bow */
+ switch (local->degas_action) {
+ case CONV9_DEGAS_TALK:
+ local->degas_action = CONV9_DEGAS_SHUT_UP;
+ random = 1;
+ break;
+
+ case CONV9_DEGAS_BOW:
+ local->degas_action = CONV9_DEGAS_SHUT_UP;
+ random = 2;
+ break;
+
+ case CONV9_DEGAS_GIRL:
+ local->degas_action = CONV9_DEGAS_SHUT_UP;
+ random = 3;
+ break;
+
+ case CONV9_DEGAS_LEAVE:
+ random = 4;
+ break;
+
+ default:
+ random = imath_random(5, 50);
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ degas_reset_frame = 33;
+ break; /* generic talk */
+
+ case 2:
+ degas_reset_frame = 17;
+ break; /* do a bow */
+
+ case 3:
+ degas_reset_frame = 42;
+ break; /* put hand to mouth (talk about girl) */
+
+ case 4:
+ degas_reset_frame = 62;
+ break; /* leave */
+
+ case 5:
+ degas_reset_frame = 41;
+ break; /* look left (new node) */
+
+ case 6:
+ degas_reset_frame = 55;
+ break; /* put bag by waist (new node) */
+
+ default:
+ degas_reset_frame = 39;
+ break; /* freeze while bag is up under arm */
+ }
+ break;
+
+ case 42: /* looking left */
+ switch (local->degas_action) {
+ case CONV9_DEGAS_BOW:
+ case CONV9_DEGAS_GIRL:
+ case CONV9_DEGAS_LEAVE:
+ case CONV9_DEGAS_TALK:
+ random = 1;
+ break;
+
+ default:
+ random = imath_random(1, 50);
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ degas_reset_frame = 39;
+ break; /* look straight ahead (new node) */
+
+ default:
+ degas_reset_frame = 41;
+ break; /* keep looking left */
+ }
+ break;
+ }
+
+ if (degas_reset_frame >= 0) {
+ kernel_reset_animation(aa[1], degas_reset_frame);
+ local->degas_frame = degas_reset_frame;
+ }
+ }
+}
+
+void room_202_init() {
+ int count;
+
+ kernel.disable_fastwalk = true;
+
+ local->gave = false;
+ local->chandelier_base[0] = 77;
+ local->chandelier_base[1] = 192;
+ local->chandelier_base[2] = 319;
+ local->chandelier_base[3] = 445;
+ local->chandelier_base[4] = 560;
+
+ if (global[ticket_people_here] == USHER_AND_SELLER) {
+ global[make_rich_leave_203] = true;
+ }
+
+ if ((global[degas_name_is_known]) || (global[current_year] == 1993)) {
+ kernel_flip_hotspot(words_gentleman, false);
+ }
+
+ for (count = 0; count < NUM_CHANDELIERS; count++) {
+ seq[fx_chandelier_0 + count] = -1;
+ local->dyn_chandeliers[count] = -1;
+ }
+
+ if (previous_room != KERNEL_RESTORING_GAME) {
+ local->anim_0_running = false;
+ local->anim_1_running = false;
+ local->prevent = false;
+ }
+
+ local->converse_counter = 0;
+
+
+ /* =================== Load conversations ======================== */
+
+ conv_get(CONV_USHER_17);
+ conv_get(CONV_DEGAS_9);
+
+
+ /* =================== Load Sprite Series ======================= */
+
+ ss[fx_take_9] = kernel_load_series("*RDR_9", false);
+ ss[fx_left_door] = kernel_load_series(kernel_name('x', 0), false);
+ ss[fx_chandelier_0] = kernel_load_series(kernel_name('f', 0), false);
+
+
+ if (global[ticket_people_here] == USHER_AND_SELLER) {
+ aa[0] = kernel_run_animation(kernel_name('b', 0), 0);
+ local->anim_0_running = true;
+ local->usher_action = CONV17_USHER_SHUT_UP;
+
+ } else {
+ kernel_flip_hotspot(words_usher, false);
+ }
+
+ if (global[degas_name_is_known]) {
+ local->anim_1_running = false;
+ }
+
+ if ((global[current_year] == 1881) && (!global[degas_name_is_known])) {
+ aa[1] = kernel_run_animation(kernel_name('d', 1), ROOM_202_DEGAS_DONE);
+ local->anim_1_running = true;
+ local->degas_action = CONV9_DEGAS_SHUT_UP;
+ }
+
+
+ if (conv_restore_running == CONV_USHER_17) {
+ conv_run(CONV_USHER_17);
+ conv_export_value(player_has(ticket));
+ conv_export_value(0);
+ player.x = USHER_X;
+ player.y = USHER_Y;
+ player.facing = FACING_NORTHEAST;
+ global[walker_converse] = imath_random(CONVERSE_LEAN, CONVERSE_HAND_CHIN);
+ }
+
+ if (conv_restore_running == CONV_DEGAS_9) {
+ conv_run(CONV_DEGAS_9);
+ conv_export_pointer(&global[player_score]);
+ player.x = DEGAS_X;
+ player.y = DEGAS_Y;
+ player.facing = FACING_NORTHWEST;
+ global[walker_converse] = imath_random(CONVERSE_LEAN, CONVERSE_HAND_CHIN);
+ }
+
+
+ /* ========================= Previous Rooms ===================== */
+
+ if (previous_room == 201) {
+ player.x = PLAYER_X_FROM_201;
+ player.y = PLAYER_Y_FROM_201;
+ player_walk(WALK_TO_X_FROM_201, WALK_TO_Y_FROM_201, FACING_EAST);
+ seq[fx_left_door] = kernel_seq_stamp(ss[fx_left_door], false, 1);
+ kernel_seq_depth(seq[fx_left_door], 14);
+
+ } else if (previous_room == 203) {
+ player.x = WALK_TO_X_BEHIND_LEFT_DOOR;
+ player.y = WALK_TO_Y_BEHIND_LEFT_DOOR;
+ player.facing = FACING_SOUTH;
+ player.commands_allowed = false;
+ player_walk(FRONT_OF_LEFT_DOOR_X, FRONT_OF_LEFT_DOOR_Y, FACING_SOUTH);
+ player_walk_trigger(ROOM_202_DOOR_CLOSES);
+ seq[fx_left_door] = kernel_seq_stamp(ss[fx_left_door], false, 5);
+ kernel_seq_depth(seq[fx_left_door], 14);
+
+ } else if (previous_room == 204) {
+ player.x = PLAYER_X_FROM_204;
+ player.y = PLAYER_Y_FROM_204;
+ player_walk(WALK_TO_X_FROM_204, WALK_TO_Y_FROM_204, FACING_SOUTH);
+ seq[fx_left_door] = kernel_seq_stamp(ss[fx_left_door], false, 1);
+ kernel_seq_depth(seq[fx_left_door], 14);
+ camera_jump_to(RIGHT_HALF - 250, 0);
+
+ } else if (previous_room == 205) {
+ player.x = PLAYER_X_FROM_205;
+ player.y = PLAYER_Y_FROM_205;
+ player_walk(WALK_TO_X_FROM_205, WALK_TO_Y_FROM_205, FACING_SOUTH);
+ camera_jump_to(RIGHT_HALF, 0);
+ seq[fx_left_door] = kernel_seq_stamp(ss[fx_left_door], false, 1);
+ kernel_seq_depth(seq[fx_left_door], 14);
+
+ } else if ((previous_room == 101) || (previous_room != KERNEL_RESTORING_GAME)) {
+ player.x = PLAYER_X_FROM_101;
+ player.y = PLAYER_Y_FROM_101;
+ player_walk(WALK_TO_X_FROM_101, WALK_TO_Y_FROM_101, FACING_WEST);
+ camera_jump_to(RIGHT_HALF, 0);
+ seq[fx_left_door] = kernel_seq_stamp(ss[fx_left_door], false, 1);
+ kernel_seq_depth(seq[fx_left_door], 14);
+
+ } else if (previous_room == KERNEL_RESTORING_GAME) {
+ seq[fx_left_door] = kernel_seq_stamp(ss[fx_left_door], false, KERNEL_FIRST);
+ kernel_seq_depth(seq[fx_left_door], 14);
+ }
+
+ set_chandelier_positions();
+ section_2_music();
+}
+
+void room_202_daemon() {
+ if (camera_x.pan_this_frame) {
+ set_chandelier_positions();
+ }
+
+ if (local->anim_0_running) {
+ handle_animation_usher();
+ }
+
+ if (kernel.trigger == ROOM_202_DEGAS_DONE) {
+ local->anim_1_running = false;
+ }
+
+ if (local->anim_1_running) {
+ handle_animation_degas();
+ }
+
+ if ((global[current_year] == 1881) && (!global[degas_name_is_known]) &&
+ (player.x < 405) && (!local->prevent)) {
+ player_walk(DEGAS_X, DEGAS_Y, FACING_NORTHWEST);
+ player_walk_trigger(ROOM_202_TALK_TO_DEGAS);
+ player.commands_allowed = false;
+ local->prevent = true;
+ }
+
+ if (kernel.trigger == ROOM_202_TALK_TO_DEGAS) {
+ player.commands_allowed = true;
+ conv_run(CONV_DEGAS_9);
+ conv_export_pointer(&global[player_score]);
+ global[walker_converse] = imath_random(CONVERSE_LEAN, CONVERSE_HAND_CHIN);
+ }
+
+ switch (kernel.trigger) {
+ case ROOM_202_DOOR_CLOSES:
+ kernel_seq_delete(seq[fx_left_door]);
+ seq[fx_left_door] = kernel_seq_backward(ss[fx_left_door], false, 8, 0, 0, 1);
+ kernel_seq_depth(seq[fx_left_door], 14);
+ kernel_seq_range(seq[fx_left_door], 1, 5);
+ kernel_seq_trigger(seq[fx_left_door], KERNEL_TRIGGER_EXPIRE, 0, ROOM_202_DOOR_CLOSES + 1);
+ break;
+
+ case ROOM_202_DOOR_CLOSES + 1:
+ sound_play(N_DoorCloses);
+ seq[fx_left_door] = kernel_seq_stamp(ss[fx_left_door], false, 1);
+ kernel_seq_depth(seq[fx_left_door], 14);
+ player.commands_allowed = true;
+ break;
+ }
+
+ if ((global[walker_converse] == CONVERSE_HAND_WAVE) ||
+ (global[walker_converse] == CONVERSE_HAND_WAVE_2)) {
+ ++local->converse_counter;
+ if (local->converse_counter > 200) {
+ global[walker_converse] = imath_random(CONVERSE_LEAN, CONVERSE_HAND_CHIN);
+ }
+ }
+}
+
+static void process_conversation_17() {
+ int you_trig_flag = false;
+ int me_trig_flag = false;
+
+ switch (player_verb) {
+ case conv017_ticket_block:
+ if (!local->gave) {
+ local->usher_action = CONV17_USHER_LEFT_UP;
+ }
+ global[walker_converse] = imath_random(CONVERSE_LEAN, CONVERSE_HAND_CHIN);
+ you_trig_flag = true;
+ me_trig_flag = true;
+ break;
+
+ case conv017_hasit_first:
+ conv_you_trigger(ROOM_202_USHER_POINT);
+ conv_me_trigger(ROOM_202_END);
+ you_trig_flag = true;
+ me_trig_flag = true;
+ break;
+
+ case conv017_hasnot_first:
+ conv_me_trigger(ROOM_202_END);
+ me_trig_flag = true;
+ you_trig_flag = true;
+ break;
+
+ default:
+ break;
+ }
+
+ switch (kernel.trigger) {
+ case ROOM_202_END:
+ global[walker_converse] = CONVERSE_NONE;
+ local->gave = false;
+ me_trig_flag = true;
+ you_trig_flag = true;
+ break;
+
+ case ROOM_202_USHER_TALK:
+ global[walker_converse] = imath_random(CONVERSE_LEAN, CONVERSE_HAND_CHIN);
+ local->usher_action = CONV17_USHER_TALK;
+ break;
+
+ case ROOM_202_USHER_POINT:
+ local->usher_action = CONV17_USHER_POINT;
+ break;
+
+ case ROOM_202_ME_TALK:
+ global[walker_converse] = imath_random(CONVERSE_HAND_WAVE, CONVERSE_HAND_WAVE_2);
+ local->usher_action = CONV17_USHER_SHUT_UP;
+ local->converse_counter = 0;
+ break;
+ }
+
+
+ /* ================= Set up me and you triggers ================ */
+
+ if (!me_trig_flag) {
+ conv_me_trigger(ROOM_202_ME_TALK);
+ } /* if me_trig_flag == true, then a me trigger is called from above, not here. */
+
+ if (!you_trig_flag) {
+ conv_you_trigger(ROOM_202_USHER_TALK);
+ } /* if you_trig_flag == true, then a you trigger is called from above, not here. */
+
+ local->usher_talk_count = 0;
+}
+
+static void process_conversation_9() {
+ int you_trig_flag = false;
+ int me_trig_flag = false;
+ int dyn_degas;
+
+ switch (player_verb) {
+ case conv009_dialogue_three:
+ global[walker_converse] = imath_random(CONVERSE_LEAN, CONVERSE_HAND_CHIN);
+ conv_me_trigger(ROOM_202_DEGAS_WALK);
+ you_trig_flag = true;
+ me_trig_flag = true;
+ break;
+
+ case conv009_dialogue_one:
+ global[degas_name_is_known] = YES;
+ break;
+ }
+
+ switch (kernel.trigger) {
+ case ROOM_202_DEGAS_TALK:
+ global[walker_converse] = imath_random(CONVERSE_LEAN, CONVERSE_HAND_CHIN);
+ switch (player_verb) {
+ case conv009_dialogue_one:
+ local->degas_action = CONV9_DEGAS_BOW;
+ break;
+
+ case conv009_dialogue_paint:
+ local->degas_action = CONV9_DEGAS_GIRL;
+ break;
+
+ default:
+ if ((player_verb != conv009_lips_abc) &&
+ (player_verb != conv009_wink_abc)) {
+ local->degas_action = CONV9_DEGAS_TALK;
+ }
+ break;
+ }
+ break;
+
+ case ROOM_202_DEGAS_WALK:
+ conv_you_trigger(ROOM_202_DEGAS_WALK + 1);
+ you_trig_flag = true;
+ me_trig_flag = true;
+ break;
+
+ case ROOM_202_DEGAS_WALK + 1:
+ conv_me_trigger(ROOM_202_DEGAS_WALK + 2);
+ local->degas_action = CONV9_DEGAS_TALK;
+ you_trig_flag = true;
+ me_trig_flag = true;
+ break;
+
+ case ROOM_202_DEGAS_WALK + 2:
+ global[walker_converse] = CONVERSE_NONE;
+ local->degas_action = CONV9_DEGAS_LEAVE;
+
+ if (global[degas_name_is_known] == YES) {
+ dyn_degas = kernel_add_dynamic(words_Edgar_Degas, words_walk_to, SYNTAX_SINGULAR_MASC, KERNEL_NONE,
+ 0, 0, 0, 0);
+ kernel_dynamic_hot[dyn_degas].prep = PREP_ON;
+ kernel_dynamic_walk(dyn_degas, DEGAS_AFTER_CONV_X, DEGAS_AFTER_CONV_Y, FACING_EAST);
+ kernel_dynamic_anim(dyn_degas, aa[1], 1);
+
+ } else {
+ dyn_degas = kernel_add_dynamic(words_gentleman, words_walk_to, SYNTAX_SINGULAR_MASC, KERNEL_NONE,
+ 0, 0, 0, 0);
+ kernel_dynamic_hot[dyn_degas].prep = PREP_ON;
+ kernel_dynamic_walk(dyn_degas, DEGAS_AFTER_CONV_X, DEGAS_AFTER_CONV_Y, FACING_EAST);
+ kernel_dynamic_anim(dyn_degas, aa[1], 1);
+ }
+
+ global[degas_name_is_known] = YES_AND_END_CONV;
+ you_trig_flag = true;
+ me_trig_flag = true;
+ kernel_flip_hotspot(words_gentleman, false);
+ player.commands_allowed = false;
+ conv_hold();
+ break;
+
+ case ROOM_202_ME_TALK:
+ global[walker_converse] = imath_random(CONVERSE_HAND_WAVE, CONVERSE_HAND_WAVE_2);
+ local->degas_action = CONV9_DEGAS_SHUT_UP;
+ local->converse_counter = 0;
+ break;
+ }
+
+
+ /* ================= Set up me and you triggers ================ */
+
+ if (!me_trig_flag) {
+ conv_me_trigger(ROOM_202_ME_TALK);
+ } /* if me_trig_flag == true, then a me trigger is called from above, not here. */
+
+ if (!you_trig_flag) {
+ conv_you_trigger(ROOM_202_DEGAS_TALK);
+ } /* if you_trig_flag == true, then a you trigger is called from above, not here. */
+}
+
+void room_202_pre_parser() {
+ if (player_said_2(open, left_door)) {
+ player_walk(FRONT_OF_LEFT_DOOR_X, FRONT_OF_LEFT_DOOR_Y, FACING_NORTHEAST);
+ }
+
+ if ((global[ticket_people_here] == USHER_AND_SELLER) && (player_said_2(walk_through, right_archway))) {
+ player_walk(USHER_X, USHER_Y, FACING_NORTHEAST);
+ }
+
+ if (player_said_2(take, gentleman) || player_said_2(take, Edgar_Degas)) {
+ player.need_to_walk = false;
+ }
+}
+
+void room_202_parser() {
+ int temp; /* for synching purposes */
+
+ if (conv_control.running == CONV_USHER_17) {
+ process_conversation_17();
+ goto handled;
+ }
+
+ if (conv_control.running == CONV_DEGAS_9) {
+ process_conversation_9();
+ goto handled;
+ }
+
+ if (global[ticket_people_here] == USHER_AND_SELLER) {
+ if (player_said_2(walk_through, right_archway) || player_said_2(talk_to, usher)) {
+ conv_run(CONV_USHER_17);
+ conv_export_value(player_has(ticket));
+ conv_export_value(0);
+ global[walker_converse] = imath_random(CONVERSE_LEAN, CONVERSE_HAND_CHIN);
+ goto handled;
+ }
+ }
+
+ if (player_said_3(give, ticket, usher)) {
+ local->gave = true;
+ conv_run(CONV_USHER_17);
+ conv_export_value(player_has(ticket));
+ conv_export_value(1);
+ global[walker_converse] = imath_random(CONVERSE_LEAN, CONVERSE_HAND_CHIN);
+ goto handled;
+ }
+
+ if ((player_said_2(talk_to, gentleman)) ||
+ (player_said_2(talk_to, Edgar_Degas))) {
+ if (!global[degas_name_is_known]) {
+ conv_run(CONV_DEGAS_9);
+ conv_export_pointer(&global[player_score]);
+ global[walker_converse] = imath_random(CONVERSE_LEAN, CONVERSE_HAND_CHIN);
+ goto handled;
+ } else {
+ text_show(text_202_24);
+ goto handled;
+ }
+ }
+
+ if (player_said_2(walk_through, left_door) || player_said_2(open, left_door)) {
+ switch (kernel.trigger) {
+ case 0:
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_take_9] = kernel_seq_pingpong(ss[fx_take_9], false, 5, 0, 0, 2);
+ kernel_seq_range(seq[fx_take_9], 1, 4);
+ kernel_seq_player(seq[fx_take_9], true);
+ kernel_seq_trigger(seq[fx_take_9], KERNEL_TRIGGER_SPRITE, 4, ROOM_202_DOOR_OPENS);
+ kernel_seq_trigger(seq[fx_take_9], KERNEL_TRIGGER_EXPIRE, 0, ROOM_202_DOOR_OPENS + 2);
+ break;
+
+ case ROOM_202_DOOR_OPENS:
+ kernel_seq_delete(seq[fx_left_door]);
+ seq[fx_left_door] = kernel_seq_forward(ss[fx_left_door], false, 8, 0, 0, 1);
+ kernel_seq_depth(seq[fx_left_door], 14);
+ kernel_seq_range(seq[fx_left_door], 1, 5);
+ kernel_seq_trigger(seq[fx_left_door], KERNEL_TRIGGER_EXPIRE, 0, ROOM_202_DOOR_OPENS + 1);
+ sound_play(N_DoorOpens);
+ break;
+
+ case ROOM_202_DOOR_OPENS + 1:
+ temp = seq[fx_left_door];
+ seq[fx_left_door] = kernel_seq_stamp(ss[fx_left_door], false, 5);
+ kernel_synch(KERNEL_SERIES, seq[fx_left_door], KERNEL_SERIES, temp);
+ kernel_seq_depth(seq[fx_left_door], 14);
+ player_walk(WALK_TO_X_BEHIND_LEFT_DOOR, WALK_TO_Y_BEHIND_LEFT_DOOR, FACING_NORTH);
+ player_walk_trigger(ROOM_202_DOOR_OPENS + 3);
+ break;
+
+ case ROOM_202_DOOR_OPENS + 2:
+ player.walker_visible = true;
+ break;
+
+ case ROOM_202_DOOR_OPENS + 3:
+ kernel_seq_delete(seq[fx_left_door]);
+ seq[fx_left_door] = kernel_seq_backward(ss[fx_left_door], false, 8, 0, 0, 1);
+ kernel_seq_depth(seq[fx_left_door], 1);
+ kernel_seq_range(seq[fx_left_door], 1, 5);
+ kernel_seq_trigger(seq[fx_left_door], KERNEL_TRIGGER_EXPIRE, 0, ROOM_202_DOOR_OPENS + 4);
+ sound_play(N_DoorCloses);
+ break;
+
+ case ROOM_202_DOOR_OPENS + 4:
+ seq[fx_left_door] = kernel_seq_stamp(ss[fx_left_door], false, 5);
+ kernel_seq_depth(seq[fx_left_door], 1);
+ new_room = 203;
+ break;
+ }
+ goto handled;
+ }
+
+ if (player_said_2(walk_through, left_archway)) {
+ new_room = 201;
+ goto handled;
+ }
+
+ if (player_said_2(walk_through, right_archway)) {
+ new_room = 101;
+ goto handled;
+ }
+
+ if (player_said_2(walk_through, middle_door)) {
+ new_room = 204;
+ goto handled;
+ }
+
+ if (player_said_2(walk_through, right_door)) {
+ new_room = 205;
+ goto handled;
+ }
+
+ if (player.look_around) {
+ text_show(text_202_10);
+ goto handled;
+ }
+
+ if (player_said_1(look) || player_said_1(look_at)) {
+
+ if (player_said_1(floor)) {
+ text_show(text_202_11);
+ goto handled;
+ }
+
+ if (player_said_1(wall)) {
+ text_show(text_202_12);
+ goto handled;
+ }
+
+ if (player_said_1(left_archway)) {
+ text_show(text_202_13);
+ goto handled;
+ }
+
+ if (player_said_1(right_archway)) {
+ text_show(text_202_14);
+ goto handled;
+ }
+
+ if (player_said_1(left_door)) {
+ text_show(text_202_15);
+ goto handled;
+ }
+
+ if (player_said_1(middle_door)) {
+ text_show(text_202_16);
+ goto handled;
+ }
+
+ if (player_said_1(right_door)) {
+ text_show(text_202_17);
+ goto handled;
+ }
+
+ if (player_said_1(light_fixture)) {
+ text_show(text_202_18);
+ goto handled;
+ }
+
+ if (player_said_1(overdoor_medallion)) {
+ text_show(text_202_19);
+ goto handled;
+ }
+
+ if (player_said_1(decorative_molding)) {
+ text_show(text_202_20);
+ goto handled;
+ }
+
+ if (player_said_1(painting)) {
+ text_show(text_202_21);
+ goto handled;
+ }
+
+ if (player_said_1(Edgar_Degas) || player_said_1(gentleman)) {
+ text_show(text_202_23);
+ goto handled;
+ }
+
+ if (player_said_1(usher)) {
+ text_show(text_202_25);
+ goto handled;
+ }
+
+ if (player_said_1(chandelier)) {
+ text_show(text_202_18);
+ goto handled;
+ }
+ }
+
+ if (player_said_1(take)) {
+ if (player_said_1(gentleman) || player_said_1(Edgar_Degas)) {
+ text_show(text_202_26);
+ goto handled;
+ }
+ }
+
+ if (player_said_2(take, usher)) {
+ text_show(text_202_27);
+ goto handled;
+ }
+
+ if (player_said_2(close, door)) {
+ text_show(text_202_22);
+ goto handled;
+ }
+
+ goto done;
+
+handled:
+ player.command_ready = false;
+
+done:
+ ;
+}
+
+void room_202_preload() {
+ room_init_code_pointer = room_202_init;
+ room_pre_parser_code_pointer = room_202_pre_parser;
+ room_parser_code_pointer = room_202_parser;
+ room_daemon_code_pointer = room_202_daemon;
+
+ section_2_walker();
+ section_2_interface();
+
+ if (global[ticket_people_here] == USHER_AND_SELLER) {
+ kernel_initial_variant = 1;
+ }
+
+ vocab_make_active(words_chandelier);
+ vocab_make_active(words_Edgar_Degas);
+}
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/rooms/room202.h b/engines/mads/madsv2/phantom/rooms/room202.h
new file mode 100644
index 00000000000..79aa2a7de14
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room202.h
@@ -0,0 +1,183 @@
+/* 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 MADS_PHANTOM_ROOM202_H
+#define MADS_PHANTOM_ROOM202_H
+
+#include "mads/madsv2/phantom/rooms/section2.h"
+#include "mads/madsv2/phantom/global.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+#define local ((Scratch *)(&game.scratch[0]))
+#define ss local->sprite
+#define seq local->sequence
+#define aa local->animation
+
+typedef struct { /* Room local variables */
+
+ int16 sprite[15]; /* Sprite series handles */
+ int16 sequence[15]; /* Sequence handles */
+ int16 animation[4]; /* Animation handles */
+
+ int16 usher_action;
+ int16 usher_frame;
+ int16 usher_talk_count;
+
+ int16 degas_action;
+ int16 degas_frame;
+
+ int16 rich_frame;
+ int16 rich_action;
+ int16 rich_talk_count;
+
+ int16 anim_0_running;
+ int16 anim_1_running;
+ int16 converse_counter;
+ int16 prevent;
+
+ int16 chandelier_base[5];
+ int16 dyn_chandeliers[5];
+
+ int16 gave;
+
+} Scratch;
+
+
+/* ========================= Sprite Series ========================= */
+
+#define fx_left_door 0 /* rm202x0 */
+#define fx_take_9 1 /* rdr_9 */
+#define fx_chandelier_0 2 /* rm202f0 */
+#define fx_chandelier_1 3
+#define fx_chandelier_2 4
+#define fx_chandelier_3 5
+#define fx_chandelier_4 6
+
+
+/* ========================= Conversations ========================= */
+
+#define CONV_USHER_17 17
+#define CONV_DEGAS_9 9
+
+/* Conv 17 â Usher action states */
+#define CONV17_USHER_TALK 0
+#define CONV17_USHER_POINT 1
+#define CONV17_USHER_SHUT_UP 2
+#define CONV17_USHER_HAVE_TICKET 3
+#define CONV17_USHER_LEFT_UP 4
+
+/* Conv 9 â Degas action states */
+#define CONV9_DEGAS_TALK 0
+#define CONV9_DEGAS_BOW 1
+#define CONV9_DEGAS_GIRL 2
+#define CONV9_DEGAS_LEAVE 3
+#define CONV9_DEGAS_SHUT_UP 4
+
+
+/* ========================= Triggers ============================== */
+
+#define ROOM_202_DOOR_CLOSES 60
+#define ROOM_202_USHER_TALK 70
+#define ROOM_202_USHER_POINT 72
+#define ROOM_202_ME_TALK 74
+#define ROOM_202_END 76
+#define ROOM_202_DOOR_OPENS 80
+#define ROOM_202_TALK_TO_DEGAS 90
+#define ROOM_202_DEGAS_TALK 93
+#define ROOM_202_DEGAS_WALK 96
+#define ROOM_202_DEGAS_DONE 100
+
+
+/* ========================= Player positions ====================== */
+
+#define PLAYER_X_FROM_201 3
+#define PLAYER_Y_FROM_201 141
+
+#define PLAYER_X_FROM_204 253
+#define PLAYER_Y_FROM_204 117
+
+#define PLAYER_X_FROM_205 510
+#define PLAYER_Y_FROM_205 117
+
+#define PLAYER_X_FROM_101 636
+#define PLAYER_Y_FROM_101 143
+
+#define WALK_TO_X_FROM_201 40
+#define WALK_TO_Y_FROM_201 141
+
+#define WALK_TO_X_FROM_203 132
+#define WALK_TO_Y_FROM_203 134
+
+#define WALK_TO_X_FROM_204 255
+#define WALK_TO_Y_FROM_204 133
+
+#define WALK_TO_X_FROM_205 512
+#define WALK_TO_Y_FROM_205 133
+
+#define WALK_TO_X_FROM_101 598
+#define WALK_TO_Y_FROM_101 143
+
+#define WALK_TO_X_BEHIND_LEFT_DOOR 134
+#define WALK_TO_Y_BEHIND_LEFT_DOOR 112
+
+
+/* ========================= Misc positions ======================== */
+
+#define FRONT_OF_LEFT_DOOR_X 126
+#define FRONT_OF_LEFT_DOOR_Y 123
+
+#define USHER_X 569
+#define USHER_Y 147
+
+#define DEGAS_X 400
+#define DEGAS_Y 141
+
+#define DEGAS_AFTER_CONV_X 596
+#define DEGAS_AFTER_CONV_Y 144
+
+#define RIGHT_HALF 320
+
+
+/* ========================= Chandelier ============================ */
+
+#define NUM_CHANDELIERS 5
+#define camera_ratio_1 1
+#define camera_ratio_2 5
+
+
+extern void set_chandelier_positions();
+
+extern void room_202_init();
+extern void room_202_daemon();
+extern void room_202_pre_parser();
+extern void room_202_parser();
+extern void room_202_preload();
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index bcfa320d4d9..d24c7c95c78 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -139,6 +139,7 @@ MODULE_OBJS += \
madsv2/phantom/rooms/room150.o \
madsv2/phantom/rooms/section2.o \
madsv2/phantom/rooms/room201.o \
+ madsv2/phantom/rooms/room202.o \
madsv2/phantom/phantom.o \
madsv2/phantom/conv.o \
madsv2/phantom/main_menu.o \
Commit: 56c05a5a0f761caf8a3da348763f47324ae5e486
https://github.com/scummvm/scummvm/commit/56c05a5a0f761caf8a3da348763f47324ae5e486
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:44+10:00
Commit Message:
MADS: PHANTOM: Added room 203
Changed paths:
A engines/mads/madsv2/phantom/rooms/room203.cpp
A engines/mads/madsv2/phantom/rooms/room203.h
engines/mads/madsv2/core/sound.h
engines/mads/madsv2/core/speech.h
engines/mads/madsv2/phantom/conv.h
engines/mads/madsv2/phantom/global.h
engines/mads/madsv2/phantom/mads/inventory.h
engines/mads/madsv2/phantom/mads/sounds.h
engines/mads/madsv2/phantom/mads/speeches.h
engines/mads/madsv2/phantom/mads/text.h
engines/mads/madsv2/phantom/mads/words.h
engines/mads/module.mk
diff --git a/engines/mads/madsv2/core/sound.h b/engines/mads/madsv2/core/sound.h
index 705ae78f580..96cf23adec0 100644
--- a/engines/mads/madsv2/core/sound.h
+++ b/engines/mads/madsv2/core/sound.h
@@ -28,6 +28,7 @@ namespace MADS {
namespace MADSV2 {
constexpr int sound_board_roland = 1;
+constexpr bool global_prefer_roland = false;
extern int sound_play(int soundNum);
extern int sound_queue(int soundNum);
diff --git a/engines/mads/madsv2/core/speech.h b/engines/mads/madsv2/core/speech.h
index d3d2e198ef7..66b98de624e 100644
--- a/engines/mads/madsv2/core/speech.h
+++ b/engines/mads/madsv2/core/speech.h
@@ -47,6 +47,7 @@ extern void speech_sample_rate(int rate);
extern void speech_ems_go(int handle, int size);
extern void global_speech_load(int id);
extern void global_speech_go(int id);
+extern void global_speech(int id);
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/conv.h b/engines/mads/madsv2/phantom/conv.h
index f04c3e247b2..65299775910 100644
--- a/engines/mads/madsv2/phantom/conv.h
+++ b/engines/mads/madsv2/phantom/conv.h
@@ -95,6 +95,21 @@ enum {
conv004_promises_safe = 30
};
+enum {
+ conv005_nowhere_nothing = 9,
+ conv005_report_adieu = 12,
+ conv005_lets_see_b_what_have_b = 14,
+ conv005_anyone_b_sign_it_b = 17,
+ conv005_crime_missing = 20,
+ conv005_rumors_sandbag = 24,
+ conv005_rumors_accident = 25,
+ conv005_goman_abc = 35,
+ conv005_murder_b_aa = 37,
+ conv005_scream_help = 41,
+ conv005_readbook_two_abc = 42,
+ conv005_point_one_b_abc = 44
+};
+
enum {
conv007_richard_intro_b = 2,
conv007_daaeb_intro_c = 3,
@@ -116,6 +131,21 @@ enum {
conv007_pinch_wait_b_nothing_b = 32,
};
+enum {
+ conv008_things_two = 4,
+ conv008_things_three = 5,
+ conv008_actions_b_b = 7,
+ conv008_actions_d_d = 13,
+ conv008_actions_byebye = 15,
+ conv008_tellabout_have = 17,
+ conv008_tellabout_rumor = 19,
+ conv008_later_final = 20,
+ conv008_nomore_first = 21,
+ conv008_var_actions_done = 24,
+ conv008_var_christine_done = 26,
+ conv008_christine_three = 27
+};
+
enum {
conv009_dialogue_one = 1,
conv009_dialogue_paint = 2,
@@ -153,6 +183,16 @@ enum {
conv014_eighth_inside = 7
};
+enum {
+ conv015_daae_b_b = 5,
+ conv015_next_second = 7,
+ conv015_professional_fourth = 9,
+ conv015_damned_b_b = 11,
+ conv015_exchange_ticket = 13,
+ conv015_exchange_relief = 14,
+ conv015_exchange_opera = 15
+};
+
enum {
conv016_buy_four = 4,
conv016_take_b_b = 6,
diff --git a/engines/mads/madsv2/phantom/global.h b/engines/mads/madsv2/phantom/global.h
index df5aea51ada..9343222ff17 100644
--- a/engines/mads/madsv2/phantom/global.h
+++ b/engines/mads/madsv2/phantom/global.h
@@ -210,6 +210,7 @@ enum {
#define CRACKED_OPEN 1
// chris_f_status
+#define CHRIS_F_IS_DEAD 0
#define CHRIS_F_IS_ALIVE 1
// christine_door_status
diff --git a/engines/mads/madsv2/phantom/mads/inventory.h b/engines/mads/madsv2/phantom/mads/inventory.h
index b2fc786caaa..74b3e865762 100644
--- a/engines/mads/madsv2/phantom/mads/inventory.h
+++ b/engines/mads/madsv2/phantom/mads/inventory.h
@@ -40,6 +40,8 @@ enum {
envelope = 9,
ticket = 10,
parchment = 12,
+ letter = 13,
+ notice = 14,
book = 15,
blue_frame = 17,
large_note = 18,
diff --git a/engines/mads/madsv2/phantom/mads/sounds.h b/engines/mads/madsv2/phantom/mads/sounds.h
index f311bb42509..28c43900bac 100644
--- a/engines/mads/madsv2/phantom/mads/sounds.h
+++ b/engines/mads/madsv2/phantom/mads/sounds.h
@@ -38,6 +38,7 @@ enum {
N_AngelMus001 = 34,
N_BackMus1stTime = 38,
N_TrapDoor001 = 64,
+ N_WomanScream002 = 65,
N_SqueakyDoor = 66,
N_PlayerFalls = 67,
N_EchoSteps = 68,
diff --git a/engines/mads/madsv2/phantom/mads/speeches.h b/engines/mads/madsv2/phantom/mads/speeches.h
index e72f1cb59cf..c1dd6c0a6b4 100644
--- a/engines/mads/madsv2/phantom/mads/speeches.h
+++ b/engines/mads/madsv2/phantom/mads/speeches.h
@@ -29,6 +29,7 @@ namespace MADSV2 {
namespace Phantom {
enum {
+ speech_woman_scream = 1,
speech_christine_scales = 8,
speech_phantom_cackle = 9
};
diff --git a/engines/mads/madsv2/phantom/mads/text.h b/engines/mads/madsv2/phantom/mads/text.h
index ec906e2b4d9..7e145150523 100644
--- a/engines/mads/madsv2/phantom/mads/text.h
+++ b/engines/mads/madsv2/phantom/mads/text.h
@@ -483,7 +483,42 @@ enum {
text_202_24 = 20224,
text_202_25 = 20225,
text_202_26 = 20226,
- text_202_27 = 20227
+ text_202_27 = 20227,
+
+ /* Room 203 */
+ text_203_10 = 20310,
+ text_203_11 = 20311,
+ text_203_12 = 20312,
+ text_203_13 = 20313,
+ text_203_14 = 20314,
+ text_203_15 = 20315,
+ text_203_16 = 20316,
+ text_203_17 = 20317,
+ text_203_18 = 20318,
+ text_203_19 = 20319,
+ text_203_20 = 20320,
+ text_203_21 = 20321,
+ text_203_22 = 20322,
+ text_203_23 = 20323,
+ text_203_24 = 20324,
+ text_203_25 = 20325,
+ text_203_26 = 20326,
+ text_203_27 = 20327,
+ text_203_28 = 20328,
+ text_203_29 = 20329,
+ text_203_30 = 20330,
+ text_203_31 = 20331,
+ text_203_32 = 20332,
+ text_203_33 = 20333,
+ text_203_34 = 20334,
+ text_203_35 = 20335,
+ text_203_36 = 20336,
+ text_203_37 = 20337,
+
+ /* Cross-room text (room 008 range, continued) */
+ text_008_12 = 812,
+ text_008_13 = 813,
+ text_008_14 = 814
};
} // namespace Phantom
diff --git a/engines/mads/madsv2/phantom/mads/words.h b/engines/mads/madsv2/phantom/mads/words.h
index ad585aa5889..622a4cb0928 100644
--- a/engines/mads/madsv2/phantom/mads/words.h
+++ b/engines/mads/madsv2/phantom/mads/words.h
@@ -79,6 +79,7 @@ enum {
words_lamp = 86,
words_lantern = 87,
words_leg = 90,
+ words_letter = 91,
words_light_fixture = 92,
words_lock = 93,
words_lockrail = 95,
@@ -94,6 +95,7 @@ enum {
words_orchestra_door = 107,
words_orchestra_pit = 108,
words_painting = 109,
+ words_parchment = 110,
words_pipe = 112,
words_pit = 113,
words_plant = 114,
@@ -175,11 +177,21 @@ enum {
words_placard = 203,
words_ticket_window = 204,
words_archway = 205,
+ words_bookcase = 214,
+ words_doorway = 215,
+ words_comfy_chair = 216,
+ words_desk = 217,
+ words_manager_s_chair = 218,
+ words_desk_lamp = 219,
+ words_window = 220,
+ words_sheers = 221,
+ words_tapestry = 222,
words_overdoor_medallion = 223,
words_decorative_molding = 225,
words_left_archway = 227,
words_right_archway = 229,
words_light = 245,
+ words_candle = 246,
words_prop_case = 247,
words_case = 247,
words_handle = 248,
diff --git a/engines/mads/madsv2/phantom/rooms/room203.cpp b/engines/mads/madsv2/phantom/rooms/room203.cpp
new file mode 100644
index 00000000000..8666ad0cd27
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room203.cpp
@@ -0,0 +1,1863 @@
+/* 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 "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/imath.h"
+#include "mads/madsv2/core/text.h"
+#include "mads/madsv2/core/inter.h"
+#include "mads/madsv2/core/object.h"
+#include "mads/madsv2/core/sound.h"
+#include "mads/madsv2/core/speech.h"
+#include "mads/madsv2/phantom/global.h"
+#include "mads/madsv2/phantom/conv.h"
+#include "mads/madsv2/phantom/mads/inventory.h"
+#include "mads/madsv2/phantom/mads/speeches.h"
+#include "mads/madsv2/phantom/mads/words.h"
+#include "mads/madsv2/phantom/mads/sounds.h"
+#include "mads/madsv2/phantom/mads/text.h"
+#include "mads/madsv2/phantom/rooms/section2.h"
+#include "mads/madsv2/phantom/rooms/room203.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+static void handle_animation_brie() {
+ int random = 0;
+ int brie_reset_frame;
+
+ if (kernel_anim[aa[0]].frame != local->brie_frame) {
+ local->brie_frame = kernel_anim[aa[0]].frame;
+ brie_reset_frame = -1;
+
+ switch (local->brie_frame) {
+ case 1: /* end of freeze sitting upright and end talk 1 */
+ case 2: /* end talk 2 (sitting upright) */
+ case 4: /* end of nod (sitting upright) */
+ case 11: /* end of putting right arm down */
+ case 22: /* end of putting both arms down */
+ case 31: /* end of un-slouch 1 */
+ case 35: /* end of un-slouch 2 */
+ case 29: /* end of point */
+
+ random = imath_random(6, 45);
+
+ switch (local->brie_action) {
+ case CONV5_BRIE_TALK:
+ random = imath_random(1, 2);
+ ++local->brie_talk_count;
+ if (local->brie_talk_count > 20) {
+ local->brie_action = CONV5_BRIE_SHUT_UP;
+ random = 45;
+ }
+ break;
+
+ case CONV5_BRIE_NOD:
+ random = 3;
+ local->brie_action = CONV5_BRIE_TALK;
+ break;
+
+ case CONV5_BRIE_POINT:
+ random = 4;
+ break;
+
+ case CONV5_BRIE_TALK_HANDS_UP:
+ random = 5;
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ brie_reset_frame = 0;
+ break; /* do talk 1 (sitting upright) */
+
+ case 2:
+ brie_reset_frame = 1;
+ break; /* do talk 2 (sitting upright) */
+
+ case 3:
+ brie_reset_frame = 2;
+ break; /* do a nod */
+
+ case 4:
+ brie_reset_frame = 22;
+ local->brie_action = CONV5_BRIE_TALK;
+ break; /* do a point */
+
+ case 5:
+ brie_reset_frame = 13;
+ break; /* talk with hands up (new node) */
+
+ case 6:
+ brie_reset_frame = 4;
+ break; /* put right arm up (new node) */
+
+ case 7:
+ brie_reset_frame = 29;
+ break; /* do slouch 1 (new node) */
+
+ case 8:
+ brie_reset_frame = 31;
+ break; /* do slouch 2 (new node) */
+
+ default:
+ brie_reset_frame = 0;
+ break; /* freeze while sitting upright */
+ }
+ break;
+
+ case 30: /* end of coming to slouch 1 and freeze slouch 1 */
+
+ random = imath_random(1, 45);
+
+ switch (local->brie_action) {
+ case CONV5_BRIE_TALK:
+ case CONV5_BRIE_TALK_HANDS_UP:
+ case CONV5_BRIE_POINT:
+ case CONV5_BRIE_NOD:
+ random = 1;
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ brie_reset_frame = 30;
+ break; /* go to sit upright (new node) */
+
+ default:
+ brie_reset_frame = 29;
+ break; /* freeze while slouch 1 */
+ }
+ break;
+
+ case 8: /* end of coming to right arm up and freeze */
+
+ random = imath_random(1, 45);
+
+ switch (local->brie_action) {
+ case CONV5_BRIE_TALK:
+ case CONV5_BRIE_TALK_HANDS_UP:
+ case CONV5_BRIE_POINT:
+ case CONV5_BRIE_NOD:
+ random = 3;
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ brie_reset_frame = 11;
+ break; /* go to look at fist (new node) */
+
+ case 2:
+ brie_reset_frame = 12;
+ break; /* go to right arm way back */
+
+ case 3:
+ brie_reset_frame = 8;
+ break; /* go to sit upright (new node) */
+
+ default:
+ brie_reset_frame = 7;
+ break; /* freeze right arm up */
+ }
+ break;
+
+ case 12: /* end of look at fist freeze */
+
+ random = imath_random(1, 45);
+
+ switch (local->brie_action) {
+ case CONV5_BRIE_TALK:
+ case CONV5_BRIE_TALK_HANDS_UP:
+ case CONV5_BRIE_POINT:
+ case CONV5_BRIE_NOD:
+ random = 1;
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ brie_reset_frame = 7;
+ break; /* go to freeze right arm up (new node) */
+
+ default:
+ brie_reset_frame = 11;
+ break; /* freeze look at fist */
+ }
+ break;
+
+ case 13: /* end of fist way back freeze */
+
+ random = imath_random(1, 45);
+
+ switch (local->brie_action) {
+ case CONV5_BRIE_TALK:
+ case CONV5_BRIE_TALK_HANDS_UP:
+ case CONV5_BRIE_POINT:
+ case CONV5_BRIE_NOD:
+ random = 1;
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ brie_reset_frame = 7;
+ break; /* go to freeze right arm up (new node) */
+
+ default:
+ brie_reset_frame = 12;
+ break; /* freeze fist way back */
+ }
+ break;
+
+ case 17: /* end of coming to both hands up, freeze, & talk hands up 1 */
+ case 18: /* end of talk hands up 2 */
+
+ switch (local->brie_action) {
+ case CONV5_BRIE_TALK_HANDS_UP:
+ random = imath_random(1, 2);
+ ++local->brie_talk_count;
+ if (local->brie_talk_count > 20) {
+ local->brie_action = CONV5_BRIE_SHUT_UP;
+ random = 3;
+ }
+ break;
+
+ case CONV5_BRIE_TALK:
+ case CONV5_BRIE_POINT:
+ case CONV5_BRIE_NOD:
+ random = 3;
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ brie_reset_frame = 16;
+ break; /* do talk 1 (hands up in air) */
+
+ case 2:
+ brie_reset_frame = 17;
+ break; /* do talk 2 (hands up in air) */
+
+ case 3:
+ brie_reset_frame = 18;
+ break; /* go to sit upright (new node) */
+ }
+ break;
+
+ case 33: /* end of coming to slouch 2, and freeze */
+ case 40: /* end of coming from look at fist while slouching */
+
+ random = imath_random(1, 45);
+
+ switch (local->brie_action) {
+ case CONV5_BRIE_TALK:
+ case CONV5_BRIE_TALK_HANDS_UP:
+ case CONV5_BRIE_POINT:
+ case CONV5_BRIE_NOD:
+ random = 1;
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ brie_reset_frame = 33;
+ break; /* go to sit upright (new node) */
+
+ case 2:
+ brie_reset_frame = 35;
+ break; /* go to look at fist while slouching (new node) */
+
+ default:
+ brie_reset_frame = 32;
+ break; /* freeze while slouch 2 */
+ }
+ break;
+
+ case 38: /* end of coming to look at fist while slouch 2, and freeze */
+
+ random = imath_random(1, 45);
+
+ switch (local->brie_action) {
+ case CONV5_BRIE_TALK:
+ case CONV5_BRIE_TALK_HANDS_UP:
+ case CONV5_BRIE_POINT:
+ case CONV5_BRIE_NOD:
+ random = 1;
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ brie_reset_frame = 38;
+ break; /* go to slouch 2 look at fists (new node) */
+
+ default:
+ brie_reset_frame = 37;
+ break; /* freeze while looking at fist slouch 2 */
+ }
+ break;
+ }
+
+ if (brie_reset_frame >= 0) {
+ kernel_reset_animation(aa[0], brie_reset_frame);
+ local->brie_frame = brie_reset_frame;
+ }
+ }
+}
+
+static void handle_animation_rich() {
+ int random = 0;
+ int rich_reset_frame;
+
+ if (kernel_anim[aa[2]].frame != local->rich_frame) {
+ local->rich_frame = kernel_anim[aa[2]].frame;
+ rich_reset_frame = -1;
+
+ switch (local->rich_frame) {
+ case 1: /* end of freeze sitting upright and end talk 1 */
+ case 2: /* end talk 2 (sitting upright) */
+ case 3: /* end talk 3 (sitting upright) */
+ case 25: /* end of touch head */
+ case 37: /* end of pushing his head way back */
+ case 53: /* end of putting both arms up */
+ case 59: /* end of point */
+ case 87: /* end of looking at knuckle (similar to look right hand) */
+ case 79: /* end of left up don't know */
+ case 69: /* end of up */
+ case 67: /* end of left */
+ case 63: /* end of right */
+ case 15: /* end of hand on chin */
+ case 7: /* end of look at right hand */
+ case 108: /* end of sitting down */
+
+ random = imath_random(8, 45);
+
+ switch (local->rich_action) {
+ case CONV8_RICH_TALK:
+ random = imath_random(1, 3);
+ ++local->rich_talk_count;
+ if (local->rich_talk_count > 20) {
+ local->rich_action = CONV8_RICH_SHUT_UP;
+ random = 45;
+ }
+ break;
+
+ case CONV8_RICH_LEFT_UP_DONT_KNOW:
+ random = 4;
+ local->rich_action = CONV8_RICH_TALK;
+ break;
+
+ case CONV8_RICH_POINT:
+ random = 5;
+ local->rich_action = CONV8_RICH_TALK;
+ break;
+
+ case CONV8_RICH_BOTH_UP:
+ random = 6;
+ local->rich_action = CONV8_RICH_TALK;
+ break;
+
+ case CONV15_RICH_STAND_TALK:
+ random = 7;
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ rich_reset_frame = 0;
+ break; /* do talk 1 (sitting upright) */
+
+ case 2:
+ rich_reset_frame = 1;
+ break; /* do talk 2 (sitting upright) */
+
+ case 3:
+ rich_reset_frame = 2;
+ break; /* do talk 3 (sitting upright) */
+
+ case 4:
+ rich_reset_frame = 69;
+ break; /* do a left arm up */
+
+ case 5:
+ rich_reset_frame = 53;
+ local->rich_action = CONV8_RICH_TALK;
+ break; /* do a point */
+
+ case 6:
+ rich_reset_frame = 42;
+ break; /* put both hands up */
+
+ case 7:
+ rich_reset_frame = 87;
+ break; /* stand up and talk (new node) */
+
+ case 8:
+ rich_reset_frame = 25;
+ break; /* push head way back (new node) */
+
+ case 9:
+ rich_reset_frame = 15;
+ break; /* touch head */
+
+ case 10:
+ rich_reset_frame = 3;
+ break; /* look at right hand (new node) */
+
+ case 11:
+ rich_reset_frame = 7;
+ break; /* put hand on chin (new node) */
+
+ case 12:
+ rich_reset_frame = 59;
+ break; /* look right (new node) */
+
+ case 13:
+ rich_reset_frame = 63;
+ break; /* look left (new node) */
+
+ case 14:
+ rich_reset_frame = 67;
+ break; /* look up (new node) */
+
+ case 15:
+ rich_reset_frame = 79;
+ break; /* look at knuckle (new node) */
+
+ default:
+ rich_reset_frame = 0;
+ break; /* freeze sitting */
+ }
+ break;
+
+ case 5: /* end of coming to look at right hand */
+
+ random = imath_random(1, 45);
+
+ switch (local->rich_action) {
+ case CONV8_RICH_TALK:
+ case CONV8_RICH_LEFT_UP_DONT_KNOW:
+ case CONV8_RICH_POINT:
+ case CONV8_RICH_BOTH_UP:
+ case CONV15_RICH_STAND_TALK:
+ random = 1;
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ rich_reset_frame = 5;
+ break; /* go to sit upright (new node) */
+
+ default:
+ rich_reset_frame = 4;
+ break; /* continue looking at right hand */
+ }
+ break;
+
+ case 11: /* end of coming to look chin */
+
+ random = imath_random(1, 45);
+
+ switch (local->rich_action) {
+ case CONV8_RICH_TALK:
+ case CONV8_RICH_LEFT_UP_DONT_KNOW:
+ case CONV8_RICH_POINT:
+ case CONV8_RICH_BOTH_UP:
+ case CONV15_RICH_STAND_TALK:
+ random = 1;
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ rich_reset_frame = 11;
+ break; /* go to sit upright (new node) */
+
+ default:
+ rich_reset_frame = 10;
+ break; /* continue looking at chin */
+ }
+ break;
+
+ case 61: /* end of coming to look right */
+
+ random = imath_random(1, 45);
+
+ switch (local->rich_action) {
+ case CONV8_RICH_TALK:
+ case CONV8_RICH_LEFT_UP_DONT_KNOW:
+ case CONV8_RICH_POINT:
+ case CONV8_RICH_BOTH_UP:
+ case CONV15_RICH_STAND_TALK:
+ random = 1;
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ rich_reset_frame = 61;
+ break; /* go to sit upright (new node) */
+
+ default:
+ rich_reset_frame = 60;
+ break; /* continue looking right */
+ }
+ break;
+
+ case 65: /* end of coming to look left */
+
+ random = imath_random(1, 45);
+
+ switch (local->rich_action) {
+ case CONV8_RICH_TALK:
+ case CONV8_RICH_LEFT_UP_DONT_KNOW:
+ case CONV8_RICH_POINT:
+ case CONV8_RICH_BOTH_UP:
+ case CONV15_RICH_STAND_TALK:
+ random = 1;
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ rich_reset_frame = 65;
+ break; /* go to sit up (new node) */
+
+ default:
+ rich_reset_frame = 64;
+ break; /* continue looking left */
+ }
+ break;
+
+ case 68: /* end of coming to look up */
+
+ random = imath_random(1, 45);
+
+ switch (local->rich_action) {
+ case CONV8_RICH_TALK:
+ case CONV8_RICH_LEFT_UP_DONT_KNOW:
+ case CONV8_RICH_POINT:
+ case CONV8_RICH_BOTH_UP:
+ case CONV15_RICH_STAND_TALK:
+ random = 1;
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ rich_reset_frame = 68;
+ break; /* go to sit up (new node) */
+
+ default:
+ rich_reset_frame = 67;
+ break; /* continue looking up */
+ }
+ break;
+
+ case 83: /* end of coming to look at knuckle */
+
+ random = imath_random(1, 45);
+
+ switch (local->rich_action) {
+ case CONV8_RICH_TALK:
+ case CONV8_RICH_LEFT_UP_DONT_KNOW:
+ case CONV8_RICH_POINT:
+ case CONV8_RICH_BOTH_UP:
+ case CONV15_RICH_STAND_TALK:
+ random = 1;
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ rich_reset_frame = 83;
+ break; /* go to sit upright (new node) */
+
+ default:
+ rich_reset_frame = 82;
+ break; /* continue looking at knuckle */
+ }
+ break;
+
+ case 92:
+ conv_release();
+ break;
+
+ case 93: /* end of coming to stand up and talk 1 */
+ case 94: /* end of talk 2 */
+ case 95: /* end of talk 3 */
+
+ switch (local->rich_action) {
+ case CONV15_RICH_STAND_TALK:
+ random = imath_random(1, 3);
+ ++local->rich_talk_count;
+ if (local->rich_talk_count > 20) {
+ local->rich_action = CONV15_RICH_STAND_SHUT_UP;
+ random = 4;
+ }
+ break;
+
+ default:
+ random = 4;
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ rich_reset_frame = 92;
+ break; /* do talk 1 (standing - arms out) */
+
+ case 2:
+ rich_reset_frame = 93;
+ break; /* do talk 2 (standing - arms out) */
+
+ case 3:
+ rich_reset_frame = 94;
+ break; /* do talk 3 (standing - arms out) */
+
+ case 4:
+ rich_reset_frame = 95;
+ break; /* put arms down, but continue standing (new node) */
+ }
+ break;
+
+ case 100: /* end of coming to stand with arms by side, talk 1, and stand shut up */
+ case 101: /* end of talk 2 */
+ case 102: /* end of talk 3 */
+
+ switch (local->rich_action) {
+ case CONV15_RICH_STAND_SHUT_UP:
+ random = 1;
+ break;
+
+ case CONV15_RICH_STAND_TALK:
+ random = imath_random(1, 3);
+ ++local->rich_talk_count;
+ if (local->rich_talk_count > 20) {
+ local->rich_action = CONV15_RICH_STAND_SHUT_UP;
+ random = 1;
+ }
+ break;
+
+ default:
+ random = 4;
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ rich_reset_frame = 99;
+ break; /* do talk 1, or freeze (standing - arms by side) */
+
+ case 2:
+ rich_reset_frame = 100;
+ break; /* do talk 2 (standing - arms by side) */
+
+ case 3:
+ rich_reset_frame = 101;
+ break; /* do talk 3 (standing - arms by side) */
+
+ case 4:
+ rich_reset_frame = 102;
+ break; /* sit down (new node) */
+ }
+ break;
+
+ case 31: /* end of putting head way back */
+
+ random = imath_random(1, 45);
+
+ switch (local->rich_action) {
+ case CONV8_RICH_TALK:
+ case CONV8_RICH_LEFT_UP_DONT_KNOW:
+ case CONV8_RICH_POINT:
+ case CONV8_RICH_BOTH_UP:
+ case CONV15_RICH_STAND_TALK:
+ random = 1;
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ rich_reset_frame = 31;
+ break; /* go to sit upright (new node) */
+
+ default:
+ rich_reset_frame = 30;
+ break; /* continue putting head way back */
+ }
+ break;
+ }
+
+ if (rich_reset_frame >= 0) {
+ kernel_reset_animation(aa[2], rich_reset_frame);
+ local->rich_frame = rich_reset_frame;
+ }
+ }
+}
+
+static void handle_animation_raoul() {
+ int random = 0;
+ int raoul_reset_frame;
+
+ if (kernel_anim[aa[1]].frame != local->raoul_frame) {
+ local->raoul_frame = kernel_anim[aa[1]].frame;
+ raoul_reset_frame = -1;
+
+ switch (local->raoul_frame) {
+ case 9:
+ case 21:
+ case 57:
+ conv_release();
+ break;
+
+ case 10: /* end of freeze */
+ case 22: /* end take */
+ case 30: /* end of talk */
+ case 34: /* end of touching head */
+ case 58: /* end of taking letter from tray */
+
+ if (local->raoul_frame == 22) {
+ local->raoul_action = CONV5_RAOUL_SHUT_UP;
+ }
+
+ random = imath_random(5, 45);
+
+ switch (local->raoul_action) {
+ case CONV5_RAOUL_TALK:
+ random = 1;
+ break;
+
+ case CONV5_RAOUL_GET_UP:
+ player.commands_allowed = false;
+ random = 2;
+ break;
+
+ case CONV5_RAOUL_TAKE:
+ case CONV5_RAOUL_SHOW:
+ random = 3;
+ break;
+
+ case CONV5_RAOUL_TAKE_TRAY:
+ random = 4;
+ break;
+
+ default:
+ random = imath_random(5, 100);
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ raoul_reset_frame = 22;
+ break; /* do talk (new node) */
+
+ case 2:
+ raoul_reset_frame = 34;
+ break; /* get up */
+
+ case 3:
+ raoul_reset_frame = 10;
+ break; /* take whatever */
+
+ case 4:
+ raoul_reset_frame = 45;
+ break; /* take letter from tray */
+
+ case 5:
+ raoul_reset_frame = 30;
+ break; /* touch head */
+
+ default:
+ raoul_reset_frame = 9;
+ break; /* freeze sitting still */
+ }
+ break;
+
+ case 16: /* middle of taking parchment */
+
+ switch (local->raoul_action) {
+ case CONV5_RAOUL_TAKE:
+ random = 1;
+ break;
+
+ case CONV5_RAOUL_SHUT_UP:
+ case CONV5_RAOUL_GET_UP:
+ random = 2;
+ break;
+
+ case CONV5_RAOUL_SHOW:
+ random = 3;
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ if (global[current_year] == 1881) {
+ raoul_reset_frame = 16;
+ kernel_seq_delete(seq[fx_parchment]);
+ kernel_flip_hotspot(words_notice, false);
+ inter_give_to_player(notice);
+ sound_play(N_TakeObjectSnd);
+ global_speech_ready = -1;
+ object_examine(notice, text_008_14, 5);
+ local->raoul_action = CONV5_RAOUL_SHUT_UP;
+ /* this is for conv 8 */
+ } else {
+ raoul_reset_frame = 16;
+ kernel_seq_delete(seq[fx_parchment]);
+ kernel_flip_hotspot(words_parchment, false);
+ inter_give_to_player(parchment);
+ sound_play(N_TakeObjectSnd);
+ global_speech_ready = -1;
+ object_examine(parchment, text_008_12, 3);
+ local->raoul_action = CONV5_RAOUL_SHUT_UP;
+ /* this is for conv 5 */
+ }
+ break; /* go to sit still (new node) */
+
+ case 2:
+ if (local->show_note) {
+ kernel_seq_delete(seq[fx_parchment_2]);
+ local->show_note = false;
+ /* take back note and sit still in chair */
+ }
+ break; /* go to sit still (new node) */
+
+ default:
+ if (!local->show_note) {
+ seq[fx_parchment_2] = kernel_seq_stamp(ss[fx_parchment], true, 1);
+ kernel_seq_depth(seq[fx_parchment_2], 3);
+ conv_release();
+ local->show_note = true;
+ /* stamp note on desk and hold it there */
+ /* the ss[parchment] is used for 2 pieces of paper */
+ }
+ raoul_reset_frame = 15;
+ break; /* keep hand out (with note on desk) */
+ }
+ break;
+
+ case 26: /* end of coming to slouch 1 and freeze slouch 1 */
+
+ random = imath_random(1, 45);
+
+ switch (local->raoul_action) {
+ case CONV5_RAOUL_TALK:
+ random = 2;
+ break;
+
+ case CONV5_RAOUL_TAKE:
+ case CONV5_RAOUL_TAKE_TRAY:
+ case CONV5_RAOUL_SHOW:
+ case CONV5_RAOUL_SHUT_UP:
+ case CONV5_RAOUL_GET_UP:
+ random = 1;
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ raoul_reset_frame = 26;
+ break; /* go to sit still (new node) */
+
+ default:
+ raoul_reset_frame = 25;
+ break; /* talk freeze (hand out) */
+ }
+ break;
+
+ case 45: /* end of getting up */
+
+ local->anim_1_running = false;
+ player.walker_visible = true;
+ player.commands_allowed = true;
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_ANIM, aa[1]);
+ raoul_reset_frame = 58;
+ if ((global[done_brie_conv_203]) && (global[current_year] == 1993)) {
+ global[prompter_stand_status] = PROMPT_RIGHT;
+ new_room = 150;
+ }
+ break;
+
+ case 52: /* middle of take note on tray */
+ kernel_seq_delete(seq[fx_letter]);
+ kernel_flip_hotspot(words_letter, false);
+ inter_give_to_player(letter);
+ sound_play(N_TakeObjectSnd);
+ global_speech_ready = -1;
+ object_examine(letter, text_008_13, 4);
+ local->raoul_action = CONV5_RAOUL_SHUT_UP;
+ break;
+ }
+
+ if (raoul_reset_frame >= 0) {
+ kernel_reset_animation(aa[1], raoul_reset_frame);
+ local->raoul_frame = raoul_reset_frame;
+ }
+ }
+}
+
+static void handle_animation_daae() {
+ int random = 0;
+ int daae_reset_frame;
+
+ if (kernel_anim[aa[3]].frame != local->daae_frame) {
+ local->daae_frame = kernel_anim[aa[3]].frame;
+ daae_reset_frame = -1;
+
+ switch (local->daae_frame) {
+ case 20: /* just entered room */
+ conv_release();
+ local->rich_action = CONV15_RICH_STAND_TALK;
+ break;
+
+ case 175: /* make Richard sit when she is almost out the door (after conv with her) */
+ local->rich_action = CONV8_RICH_SHUT_UP;
+ break;
+
+ case 198: /* almost out the door (after conv with her), release */
+ conv_release();
+ break;
+
+ case 201:
+ kernel_timing_trigger(1, ROOM_203_DOOR_CLOSES);
+ break;
+
+ case 76: /* end of walking into room and freeze */
+ case 92: /* end of talk to Richard 1 */
+ case 102: /* end of talk to Richard 2 */
+ case 123: /* end of talk to Raoul */
+
+ switch (local->daae_action) {
+ case CONV15_DAAE_TALK_RICH:
+ random = imath_random(1, 2);
+ local->daae_action = CONV15_DAAE_TALK_RAOUL;
+ break;
+
+ case CONV15_DAAE_TALK_RAOUL:
+ random = 3;
+ local->daae_action = CONV15_DAAE_SHUT_UP;
+ break;
+
+ case CONV15_DAAE_LEAVE:
+ random = 4;
+ break;
+
+ default:
+ random = 5;
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ daae_reset_frame = 79;
+ break; /* do talk to Richard 1 */
+
+ case 2:
+ daae_reset_frame = 92;
+ break; /* do talk to Richard 2 */
+
+ case 3:
+ daae_reset_frame = 102;
+ break; /* talk to Raoul */
+
+ case 4:
+ daae_reset_frame = 123;
+ break; /* leave */
+
+ case 5:
+ daae_reset_frame = 75;
+ break; /* freeze */
+ }
+ break;
+ }
+
+ if (daae_reset_frame >= 0) {
+ kernel_reset_animation(aa[3], daae_reset_frame);
+ local->daae_frame = daae_reset_frame;
+ }
+ }
+}
+
+void room_203_daemon() {
+ if (local->anim_0_running) {
+ handle_animation_brie();
+ }
+
+ if (local->anim_1_running) {
+ handle_animation_raoul();
+ }
+
+ if (local->anim_2_running) {
+ handle_animation_rich();
+ }
+
+ if (local->anim_3_running) {
+ handle_animation_daae();
+ }
+
+ if ((global[walker_converse] == CONVERSE_HAND_WAVE) ||
+ (global[walker_converse] == CONVERSE_HAND_WAVE_2)) {
+ ++local->converse_counter;
+ if (local->converse_counter > 200) {
+ global[walker_converse] = imath_random(CONVERSE_LEAN, CONVERSE_HAND_CHIN);
+ }
+ }
+
+ switch (kernel.trigger) {
+ case ROOM_203_DOOR_CLOSES:
+ kernel_seq_delete(seq[fx_door]);
+ seq[fx_door] = kernel_seq_backward(ss[fx_door], false, 8, 0, 0, 1);
+ kernel_seq_depth(seq[fx_door], 10);
+ kernel_seq_range(seq[fx_door], KERNEL_FIRST, KERNEL_LAST);
+ kernel_seq_trigger(seq[fx_door], KERNEL_TRIGGER_EXPIRE, 0, ROOM_203_DOOR_CLOSES + 1);
+ break;
+
+ case ROOM_203_DOOR_CLOSES + 1:
+ sound_play(N_DoorCloses);
+ seq[fx_door] = kernel_seq_stamp(ss[fx_door], false, KERNEL_FIRST);
+ kernel_seq_depth(seq[fx_door], 14);
+ if (conv_control.running != CONV_RD_15) {
+ player.commands_allowed = true;
+ }
+ break;
+ }
+}
+
+static void process_conversation_brie() {
+ int you_trig_flag = false;
+ int me_trig_flag = false;
+
+ switch (player_verb) {
+ case conv005_crime_missing:
+ case conv005_rumors_accident:
+ conv_you_trigger(ROOM_203_BRIE_TALK_HANDS_UP);
+ you_trig_flag = true;
+ break;
+
+ case conv005_murder_b_aa:
+ if (!kernel.trigger) {
+ conv_hold();
+ if (global_prefer_roland) {
+ sound_play(N_WomanScream002);
+ } else {
+ global_speech(speech_woman_scream);
+ }
+ kernel_timing_trigger(ONE_SECOND, ROOM_203_AFTER_SCREAM);
+ }
+ break;
+
+ case conv005_scream_help:
+ global[done_brie_conv_203] = YES;
+ global[chris_f_status] = CHRIS_F_IS_DEAD;
+ break; /* by setting this flag, Florent is dead */
+
+ case conv005_rumors_sandbag:
+ conv_you_trigger(ROOM_203_BRIE_POINT);
+ you_trig_flag = true;
+ break;
+
+ case conv005_anyone_b_sign_it_b:
+ local->raoul_action = CONV5_RAOUL_SHUT_UP;
+ conv_hold();
+ break;
+
+ case conv005_nowhere_nothing:
+ case conv005_report_adieu:
+ case conv005_goman_abc:
+ case conv005_readbook_two_abc:
+ conv_you_trigger(ROOM_203_GET_UP);
+ you_trig_flag = true;
+ me_trig_flag = true;
+ break;
+
+ case conv005_lets_see_b_what_have_b:
+ if (!kernel.trigger) {
+ conv_hold();
+ local->raoul_action = CONV5_RAOUL_SHOW;
+ }
+ break;
+
+ case conv005_point_one_b_abc:
+ if (!kernel.trigger) {
+ conv_hold();
+ local->raoul_action = CONV5_RAOUL_TAKE;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ switch (kernel.trigger) {
+ case ROOM_203_AFTER_SCREAM:
+ conv_release();
+ break;
+
+ case ROOM_203_GET_UP:
+ conv_me_trigger(ROOM_203_GET_UP + 1);
+ you_trig_flag = true;
+ me_trig_flag = true;
+ break;
+
+ case ROOM_203_GET_UP + 1:
+ local->raoul_action = CONV5_RAOUL_GET_UP;
+ break;
+
+ case ROOM_203_BRIE_TALK_HANDS_UP:
+ local->brie_action = CONV5_BRIE_TALK_HANDS_UP;
+ break;
+
+ case ROOM_203_BRIE_POINT:
+ local->brie_action = CONV5_BRIE_POINT;
+ break;
+
+ case ROOM_203_TAKE_NOTE:
+ conv_hold();
+ local->raoul_action = CONV5_RAOUL_TAKE;
+ break;
+
+ case ROOM_203_BRIE_START_TALKING:
+ local->brie_action = CONV5_BRIE_TALK;
+ break;
+
+ case ROOM_203_RAOUL_START_TALKING:
+ local->brie_action = CONV5_BRIE_SHUT_UP;
+ break;
+
+ default:
+ break;
+ }
+
+
+ /* ================= Set up me and you triggers ================ */
+
+ if (!me_trig_flag) {
+ if (local->raoul_action != CONV5_RAOUL_SHOW) {
+ conv_me_trigger(ROOM_203_RAOUL_START_TALKING);
+ }
+ }
+
+ if (!you_trig_flag) {
+ conv_you_trigger(ROOM_203_BRIE_START_TALKING);
+ }
+
+ local->brie_talk_count = 0;
+ local->raoul_talk_count = 0;
+}
+
+static void process_conversation_rich() {
+ int you_trig_flag = false;
+ int me_trig_flag = false;
+ int *value_1;
+ int *value_2;
+
+ switch (player_verb) {
+ case conv008_tellabout_have:
+ conv_you_trigger(ROOM_203_RICH_BOTH_UP);
+ you_trig_flag = true;
+ break;
+
+ case conv008_tellabout_rumor:
+ conv_you_trigger(ROOM_203_RICH_POINT);
+ you_trig_flag = true;
+ break;
+
+ case conv008_things_two:
+ conv_you_trigger(ROOM_203_RICH_LEFT_UP_DONT_KNOW);
+ you_trig_flag = true;
+ break;
+
+ case conv008_things_three:
+ case conv008_actions_byebye:
+ case conv008_later_final:
+ case conv008_nomore_first:
+ case conv008_christine_three:
+ conv_you_trigger(ROOM_203_GET_UP);
+ you_trig_flag = true;
+ me_trig_flag = true;
+ break;
+
+ case conv008_actions_b_b:
+ if (object_is_here(notice)) {
+ if (!kernel.trigger) {
+ conv_hold();
+ local->raoul_action = CONV5_RAOUL_TAKE;
+ }
+ break;
+ }
+ break;
+
+ case conv008_actions_d_d:
+ if (object_is_here(letter)) {
+ if (!kernel.trigger) {
+ conv_hold();
+ local->raoul_action = CONV5_RAOUL_TAKE_TRAY;
+ }
+ break;
+ }
+ break;
+ }
+
+ switch (kernel.trigger) {
+ case ROOM_203_GET_UP:
+ conv_me_trigger(ROOM_203_GET_UP + 1);
+ you_trig_flag = true;
+ me_trig_flag = true;
+ break;
+
+ case ROOM_203_GET_UP + 1:
+ local->raoul_action = CONV5_RAOUL_GET_UP;
+ value_1 = conv_get_variable(conv008_var_actions_done);
+ value_2 = conv_get_variable(conv008_var_christine_done);
+ if ((*value_1) && (*value_2)) {
+ global[done_rich_conv_203] = true;
+ global[madame_giry_shows_up] = true;
+ }
+ break;
+
+ case ROOM_203_RICH_BOTH_UP:
+ local->rich_action = CONV8_RICH_BOTH_UP;
+ break;
+
+ case ROOM_203_RICH_POINT:
+ local->rich_action = CONV8_RICH_POINT;
+ break;
+
+ case ROOM_203_RICH_LEFT_UP_DONT_KNOW:
+ local->rich_action = CONV8_RICH_LEFT_UP_DONT_KNOW;
+ break;
+
+ case ROOM_203_TAKE_NOTE:
+ conv_hold();
+ local->raoul_action = CONV5_RAOUL_TAKE;
+ break;
+
+ case ROOM_203_RICH_START_TALKING:
+ local->rich_action = CONV8_RICH_TALK;
+ break;
+
+ case ROOM_203_RAOUL_START_TALKING:
+ local->rich_action = CONV8_RICH_SHUT_UP;
+ break;
+
+ default:
+ break;
+ }
+
+
+ /* ================= Set up me and you triggers ================ */
+
+ if (!me_trig_flag) {
+ if (local->raoul_action != CONV5_RAOUL_SHOW) {
+ conv_me_trigger(ROOM_203_RAOUL_START_TALKING);
+ }
+ }
+
+ if (!you_trig_flag) {
+ conv_you_trigger(ROOM_203_RICH_START_TALKING);
+ }
+
+ local->brie_talk_count = 0;
+ local->raoul_talk_count = 0;
+}
+
+static void process_conversation_rd() {
+ int you_trig_flag = false;
+ int me_trig_flag = false;
+
+ switch (player_verb) {
+ case conv015_exchange_ticket:
+ case conv015_exchange_relief:
+ case conv015_exchange_opera:
+ global[christine_door_status] = CHRIS_DOOR_CLOSED;
+ global[ticket_people_here] = USHER_AND_SELLER;
+ me_trig_flag = true;
+ you_trig_flag = true;
+ conv_you_trigger(ROOM_203_END);
+ break;
+
+ case conv015_daae_b_b:
+ if (!kernel.trigger) {
+ conv_hold();
+ sound_play(N_DoorOpens);
+ kernel_seq_delete(seq[fx_door]);
+ seq[fx_door] = kernel_seq_forward(ss[fx_door], false, 8, 0, 0, 1);
+ kernel_seq_depth(seq[fx_door], 1);
+ kernel_seq_range(seq[fx_door], KERNEL_FIRST, KERNEL_LAST);
+ kernel_seq_trigger(seq[fx_door], KERNEL_TRIGGER_EXPIRE, 0, ROOM_203_DOOR_OPENS);
+ you_trig_flag = true;
+ me_trig_flag = true;
+ }
+ break;
+
+ case conv015_damned_b_b:
+ if (!kernel.trigger) {
+ conv_hold();
+ local->daae_action = CONV15_DAAE_LEAVE;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ switch (kernel.trigger) {
+ case ROOM_203_END:
+ global[walker_converse] = CONVERSE_NONE;
+ me_trig_flag = true;
+ you_trig_flag = true;
+ break;
+
+ case ROOM_203_DOOR_OPENS:
+ seq[fx_door] = kernel_seq_stamp(ss[fx_door], false, KERNEL_LAST);
+ kernel_seq_depth(seq[fx_door], 1);
+ aa[3] = kernel_run_animation(kernel_name('d', 1), 0);
+ local->anim_3_running = true;
+ local->daae_action = CONV15_DAAE_SHUT_UP;
+ break;
+
+ case ROOM_203_RICH_START_TALKING:
+ if (global[walker_converse] != CONVERSE_NONE) {
+ global[walker_converse] = imath_random(CONVERSE_LEAN, CONVERSE_HAND_CHIN);
+ }
+
+ if ((player_verb == conv015_next_second) ||
+ (player_verb == conv015_professional_fourth)) {
+ local->daae_action = CONV15_DAAE_TALK_RICH;
+ } else if (local->rich_action == CONV15_RICH_STAND_SHUT_UP) {
+ local->rich_action = CONV15_RICH_STAND_TALK;
+ } else if (local->rich_action != CONV15_RICH_STAND_TALK) {
+ local->rich_action = CONV8_RICH_TALK;
+ }
+ break;
+
+ case ROOM_203_RAOUL_START_TALKING:
+ if (global[walker_converse] != CONVERSE_NONE) {
+ global[walker_converse] = imath_random(CONVERSE_HAND_WAVE, CONVERSE_HAND_WAVE_2);
+ }
+
+ if ((local->rich_action != CONV15_RICH_STAND_TALK) &&
+ (local->rich_action != CONV15_RICH_STAND_SHUT_UP)) {
+ local->rich_action = CONV8_RICH_SHUT_UP;
+ }
+ local->converse_counter = 0;
+ break;
+
+ default:
+ break;
+ }
+
+
+ /* ================= Set up me and you triggers ================ */
+
+ if (!me_trig_flag) {
+ conv_me_trigger(ROOM_203_RAOUL_START_TALKING);
+ }
+
+ if (!you_trig_flag) {
+ conv_you_trigger(ROOM_203_RICH_START_TALKING);
+ }
+
+ local->brie_talk_count = 0;
+ local->raoul_talk_count = 0;
+}
+
+void room_203_pre_parser() {
+ if (player_said_2(talk_to, Monsieur_Richard)) {
+ if (global[came_from_fade]) {
+ player_walk(PLAYER_X_FROM_113, PLAYER_Y_FROM_113, FACING_NORTHEAST);
+ } else {
+ player_walk(FRONT_CHAIR_X, FRONT_CHAIR_Y, FACING_NORTHWEST);
+ }
+ }
+
+ if (player_said_2(talk_to, Monsieur_Brie)) {
+ player_walk(FRONT_CHAIR_X, FRONT_CHAIR_Y, FACING_NORTHWEST);
+ }
+
+ if (player_said_2(open, door)) {
+ player_walk(DOOR_X, DOOR_Y, FACING_EAST);
+ }
+}
+
+void room_203_parser() {
+ if (conv_control.running == CONV_BRIE_5) {
+ process_conversation_brie();
+ goto handled;
+ }
+
+ if (conv_control.running == CONV_RICH_8) {
+ process_conversation_rich();
+ goto handled;
+ }
+
+ if (conv_control.running == CONV_RD_15) {
+ process_conversation_rd();
+ goto handled;
+ }
+
+ if (player_said_2(walk_through, door) || player_said_2(open, door) || kernel.trigger) {
+ switch (kernel.trigger) {
+ case 0:
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_take_6] = kernel_seq_pingpong(ss[fx_take_6], false, 5, 0, 0, 2);
+ kernel_seq_range(seq[fx_take_6], 1, 4);
+ kernel_seq_player(seq[fx_take_6], true);
+ kernel_seq_trigger(seq[fx_take_6], KERNEL_TRIGGER_SPRITE, 4, ROOM_203_DOOR_OPENS);
+ kernel_seq_trigger(seq[fx_take_6], KERNEL_TRIGGER_EXPIRE, 0, ROOM_203_DOOR_OPENS + 2);
+ break;
+
+ case ROOM_203_DOOR_OPENS:
+ sound_play(N_DoorOpens);
+ kernel_seq_delete(seq[fx_door]);
+ seq[fx_door] = kernel_seq_forward(ss[fx_door], false, 8, 0, 0, 1);
+ kernel_seq_depth(seq[fx_door], 1);
+ kernel_seq_range(seq[fx_door], KERNEL_FIRST, KERNEL_LAST);
+ kernel_seq_trigger(seq[fx_door], KERNEL_TRIGGER_EXPIRE, 0, ROOM_203_DOOR_OPENS + 1);
+ break;
+
+ case ROOM_203_DOOR_OPENS + 1:
+ seq[fx_door] = kernel_seq_stamp(ss[fx_door], false, KERNEL_LAST);
+ kernel_seq_depth(seq[fx_door], 1);
+ break;
+
+ case ROOM_203_DOOR_OPENS + 2:
+ player.walker_visible = true;
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_SERIES, seq[fx_take_6]);
+ player_walk(WALK_TO_X_BEHIND_DOOR, WALK_TO_Y_BEHIND_DOOR, FACING_WEST);
+ player_walk_trigger(ROOM_203_DOOR_OPENS + 3);
+ break;
+
+ case ROOM_203_DOOR_OPENS + 3:
+ new_room = 204;
+ break;
+ }
+ goto handled;
+ }
+
+ if (player_said_2(talk_to, Monsieur_Brie)) {
+ aa[1] = kernel_run_animation(kernel_name('c', 1), 0);
+ local->anim_1_running = true;
+ player.walker_visible = false;
+ local->raoul_action = CONV5_RAOUL_SHUT_UP;
+ kernel_synch(KERNEL_ANIM, aa[1], KERNEL_PLAYER, 0);
+
+ conv_run(CONV_BRIE_5);
+ conv_hold();
+ conv_export_pointer(&global[player_score]);
+ conv_export_value(player_has(small_note));
+ conv_export_value(global[read_book]);
+ conv_export_value(player_has(large_note));
+ conv_export_value(global[looked_at_case]);
+ if (global[charles_name_is_known] == YES_AND_END_CONV) {
+ conv_export_value(1);
+ } else {
+ conv_export_value(0);
+ }
+ conv_export_value(global[can_find_book_library]);
+ conv_export_value(global[florent_name_is_known]);
+ conv_export_value(global[sandbag_status]);
+ conv_export_value(global[observed_phan_104]);
+ goto handled;
+ }
+
+ if (player_said_2(talk_to, Monsieur_Richard)) {
+ if (global[came_from_fade]) {
+ conv_run(CONV_RD_15); /* came from 113 */
+ conv_export_pointer(&global[player_score]);
+ conv_export_pointer(&global[christine_told_envelope]);
+
+ } else {
+ aa[1] = kernel_run_animation(kernel_name('c', 1), 0);
+ local->anim_1_running = true;
+ player.walker_visible = false;
+ player.commands_allowed = false;
+ local->raoul_action = CONV5_RAOUL_SHUT_UP;
+ kernel_synch(KERNEL_ANIM, aa[1], KERNEL_PLAYER, 0);
+
+ conv_run(CONV_RICH_8);
+ conv_export_pointer(&global[player_score]);
+ conv_hold();
+ }
+ goto handled;
+ }
+
+ if (player_said_2(exit_to, grand_foyer)) {
+ new_room = 202;
+ goto handled;
+ }
+
+ if (player.look_around) {
+ if (global[make_brie_leave_203]) {
+ text_show(text_203_37);
+ } else {
+ text_show(text_203_10);
+ }
+ goto handled;
+ }
+
+ if (player_said_1(look) || player_said_1(look_at)) {
+
+ if (player_said_1(wall)) {
+ text_show(text_203_11);
+ goto handled;
+ }
+
+ if (player_said_1(floor)) {
+ text_show(text_203_12);
+ goto handled;
+ }
+
+ if (player_said_1(bookcase)) {
+ text_show(text_203_13);
+ goto handled;
+ }
+
+ if (player_said_1(doorway)) {
+ text_show(text_203_14);
+ goto handled;
+ }
+
+ if (player_said_1(comfy_chair)) {
+ text_show(text_203_15);
+ goto handled;
+ }
+
+ if (player_said_1(desk)) {
+ text_show(text_203_16);
+ goto handled;
+ }
+
+ if (player_said_1(manager_s_chair)) {
+ text_show(text_203_17);
+ goto handled;
+ }
+
+ if (player_said_1(desk_lamp)) {
+ text_show(text_203_18);
+ goto handled;
+ }
+
+ if (player_said_1(lamp)) {
+ text_show(text_203_19);
+ goto handled;
+ }
+
+ if (player_said_1(light_fixture)) {
+ text_show(text_203_20);
+ goto handled;
+ }
+
+ if (player_said_1(window)) {
+ text_show(text_203_21);
+ goto handled;
+ }
+
+ if (player_said_1(sheers)) {
+ text_show(text_203_22);
+ goto handled;
+ }
+
+ if (player_said_1(tapestry)) {
+ text_show(text_203_23);
+ goto handled;
+ }
+
+ if (player_said_1(grand_foyer)) {
+ text_show(text_203_24);
+ goto handled;
+ }
+
+ if (player_said_1(table)) {
+ text_show(text_203_25);
+ goto handled;
+ }
+
+ if (player_said_1(candle)) {
+ text_show(text_203_26);
+ goto handled;
+ }
+
+ if (player_said_1(Monsieur_Brie)) {
+ text_show(text_203_27);
+ goto handled;
+ }
+
+ if (player_said_1(Monsieur_Richard)) {
+ text_show(text_203_28);
+ goto handled;
+ }
+
+ if (player_said_1(parchment) && object_is_here(parchment)) {
+ text_show(text_203_29);
+ goto handled;
+ }
+
+ if (player_said_1(letter) && object_is_here(letter)) {
+ text_show(text_203_31);
+ goto handled;
+ }
+
+ if (player_said_1(notice) && object_is_here(notice)) {
+ text_show(text_203_33);
+ goto handled;
+ }
+ }
+
+ if (player_said_2(take, parchment)) {
+ text_show(text_203_30);
+ goto handled;
+ }
+
+ if (player_said_2(take, letter)) {
+ text_show(text_203_32);
+ goto handled;
+ }
+
+ if (player_said_2(take, notice)) {
+ text_show(text_203_34);
+ goto handled;
+ }
+
+ if (player_said_2(take, Monsieur_Brie)) {
+ text_show(text_203_35);
+ goto handled;
+ }
+
+ if (player_said_2(take, Monsieur_Richard)) {
+ text_show(text_203_36);
+ goto handled;
+ }
+
+ goto done;
+
+handled:
+ player.command_ready = false;
+
+done:
+ ;
+}
+
+void room_203_init() {
+ if (previous_room != KERNEL_RESTORING_GAME) {
+ local->anim_0_running = false;
+ local->anim_1_running = false;
+ local->anim_2_running = false;
+ local->anim_3_running = false;
+ local->show_note = false;
+ }
+
+ local->converse_counter = 0;
+
+ kernel_flip_hotspot(words_letter, false);
+ kernel_flip_hotspot(words_parchment, false);
+ kernel_flip_hotspot(words_notice, false);
+
+
+ /* =================== Load Sprite Series ====================== */
+
+ ss[fx_parchment] = kernel_load_series(kernel_name('p', 1), false);
+ ss[fx_letter] = kernel_load_series(kernel_name('p', 0), false);
+ ss[fx_door] = kernel_load_series(kernel_name('x', 0), false);
+ ss[fx_take_6] = kernel_load_series("*RDR_6", false);
+
+
+ /* =================== Load conversations ====================== */
+
+ if (global[current_year] == 1993) {
+ ss[fx_1993] = kernel_load_series(kernel_name('z', -1), false);
+ conv_get(CONV_BRIE_5);
+ } else {
+ conv_get(CONV_RICH_8);
+ conv_get(CONV_RD_15); /* RD is Richard & Daae */
+ }
+
+
+ /* =================== Draw 1993 sprite ======================== */
+
+ if (global[current_year] == 1993) {
+ if (object_is_here(parchment)) {
+ seq[fx_parchment] = kernel_seq_stamp(ss[fx_parchment], false, 1);
+ kernel_seq_depth(seq[fx_parchment], 3);
+ kernel_flip_hotspot(words_parchment, true);
+ }
+
+ kernel_flip_hotspot(words_Monsieur_Richard, false);
+ kernel_flip_hotspot(words_manager_s_chair, false);
+
+ if (!global[make_brie_leave_203]) {
+ aa[0] = kernel_run_animation(kernel_name('b', 9), 1);
+ local->anim_0_running = true;
+ local->brie_action = CONV5_BRIE_SHUT_UP;
+ } else {
+ kernel_flip_hotspot(words_Monsieur_Brie, false);
+ kernel_flip_hotspot(words_manager_s_chair, true);
+ }
+
+ if (previous_room == KERNEL_RESTORING_GAME) {
+ if (conv_restore_running == CONV_BRIE_5) {
+ local->brie_action = CONV5_BRIE_SHUT_UP;
+ local->raoul_action = CONV5_RAOUL_SHUT_UP;
+ local->anim_1_running = true;
+ player.walker_visible = false;
+ player.commands_allowed = false;
+ aa[1] = kernel_run_animation(kernel_name('c', 1), 0);
+ kernel_reset_animation(aa[1], 9);
+ conv_run(CONV_BRIE_5);
+ conv_export_pointer(&global[player_score]);
+ conv_export_value(player_has(small_note));
+ conv_export_value(global[read_book]);
+ conv_export_value(player_has(large_note));
+ conv_export_value(global[looked_at_case]);
+ conv_export_value(global[charles_name_is_known]);
+ conv_export_value(global[can_find_book_library]);
+ conv_export_value(global[florent_name_is_known]);
+ conv_export_value(global[sandbag_status]);
+ conv_export_value(global[observed_phan_104]);
+ }
+ }
+
+ kernel_draw_to_background(ss[fx_1993], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ kernel_flip_hotspot(words_candle, false);
+
+ } else if (global[jacques_status] == JACQUES_IS_ALIVE) {
+
+ kernel_flip_hotspot(words_desk_lamp, false);
+ kernel_flip_hotspot(words_Monsieur_Brie, false);
+ kernel_flip_hotspot(words_manager_s_chair, false);
+
+ if (!global[make_rich_leave_203]) {
+ aa[2] = kernel_run_animation(kernel_name('r', 1), 1);
+ local->anim_2_running = true;
+ local->rich_action = CONV8_RICH_SHUT_UP;
+
+ } else {
+ kernel_flip_hotspot(words_Monsieur_Richard, false);
+ kernel_flip_hotspot(words_manager_s_chair, true);
+ }
+
+ if (previous_room == KERNEL_RESTORING_GAME) {
+ if (conv_restore_running == CONV_RICH_8) {
+ aa[1] = kernel_run_animation(kernel_name('c', 1), 0);
+ kernel_reset_animation(aa[1], 9); /* make Raoul frozen while sitting down */
+ local->anim_1_running = true;
+ player.walker_visible = false;
+ local->raoul_action = CONV5_RAOUL_SHUT_UP;
+ conv_run(CONV_RICH_8);
+ conv_export_pointer(&global[player_score]);
+ }
+ }
+
+ if (object_is_here(letter)) {
+ seq[fx_letter] = kernel_seq_stamp(ss[fx_letter], false, 1);
+ kernel_seq_depth(seq[fx_letter], 3);
+ kernel_flip_hotspot(words_letter, true);
+ }
+
+ if (object_is_here(notice)) {
+ seq[fx_parchment] = kernel_seq_stamp(ss[fx_parchment], false, 1);
+ kernel_seq_depth(seq[fx_parchment], 3);
+ kernel_flip_hotspot(words_notice, true);
+ }
+
+ } else {
+ kernel_flip_hotspot(words_Monsieur_Brie, false);
+ kernel_flip_hotspot(words_Monsieur_Richard, false);
+ kernel_flip_hotspot(words_desk_lamp, false);
+ }
+
+
+ if (conv_restore_running == CONV_RD_15) {
+ seq[fx_door] = kernel_seq_stamp(ss[fx_door], false, KERNEL_FIRST);
+ kernel_seq_depth(seq[fx_door], 14);
+ player.x = PLAYER_X_FROM_113;
+ player.y = PLAYER_Y_FROM_113;
+ player.facing = FACING_NORTHEAST;
+ conv_run(CONV_RD_15);
+ conv_export_pointer(&global[player_score]);
+ conv_export_pointer(&global[christine_told_envelope]);
+ global[walker_converse] = imath_random(CONVERSE_LEAN, CONVERSE_HAND_CHIN);
+ }
+
+
+ /* ========================= Previous Rooms ===================== */
+
+ if (previous_room == KERNEL_RESTORING_GAME) {
+ seq[fx_door] = kernel_seq_stamp(ss[fx_door], false, KERNEL_FIRST);
+ kernel_seq_depth(seq[fx_door], 14);
+
+ } else if (previous_room == 202) {
+ seq[fx_door] = kernel_seq_stamp(ss[fx_door], false, KERNEL_FIRST);
+ kernel_seq_depth(seq[fx_door], 14);
+ player.x = PLAYER_X_FROM_202;
+ player.y = PLAYER_Y_FROM_202;
+ player.facing = FACING_NORTH;
+
+ } else if (previous_room == 150) {
+ seq[fx_door] = kernel_seq_stamp(ss[fx_door], false, KERNEL_FIRST);
+ kernel_seq_depth(seq[fx_door], 14);
+ player.x = PLAYER_X_FROM_113;
+ player.y = PLAYER_Y_FROM_113;
+ player.facing = FACING_NORTHEAST;
+ conv_run(CONV_RD_15);
+ conv_export_pointer(&global[player_score]);
+ conv_export_pointer(&global[christine_told_envelope]);
+ global[walker_converse] = imath_random(CONVERSE_LEAN, CONVERSE_HAND_CHIN);
+
+ } else if ((previous_room == 204) || (previous_room != KERNEL_RESTORING_GAME)) {
+ seq[fx_door] = kernel_seq_stamp(ss[fx_door], false, KERNEL_LAST);
+ kernel_seq_depth(seq[fx_door], 1);
+ player.x = WALK_TO_X_BEHIND_DOOR;
+ player.y = WALK_TO_Y_BEHIND_DOOR;
+ player.facing = FACING_SOUTHWEST;
+ player_walk(WALK_TO_X_FROM_204, WALK_TO_Y_FROM_204, FACING_WEST);
+ player_walk_trigger(ROOM_203_DOOR_CLOSES);
+ player.commands_allowed = false;
+ }
+
+ section_2_music();
+}
+
+void room_203_preload() {
+ room_init_code_pointer = room_203_init;
+ room_pre_parser_code_pointer = room_203_pre_parser;
+ room_parser_code_pointer = room_203_parser;
+ room_daemon_code_pointer = room_203_daemon;
+
+ if (global[current_year] == 1993) {
+ kernel_initial_variant = 1;
+ }
+
+ section_2_walker();
+ section_2_interface();
+}
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/rooms/room203.h b/engines/mads/madsv2/phantom/rooms/room203.h
new file mode 100644
index 00000000000..dde62d99b4a
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room203.h
@@ -0,0 +1,175 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef MADS_PHANTOM_ROOM203_H
+#define MADS_PHANTOM_ROOM203_H
+
+#include "mads/madsv2/phantom/rooms/section2.h"
+#include "mads/madsv2/phantom/global.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+#define local ((Scratch *)(&game.scratch[0]))
+#define ss local->sprite
+#define seq local->sequence
+#define aa local->animation
+
+typedef struct { /* Room local variables */
+
+ int16 sprite[15]; /* Sprite series handles */
+ int16 sequence[15]; /* Sequence handles */
+ int16 animation[4]; /* Animation handles */
+
+ int16 brie_action;
+ int16 brie_frame;
+ int16 brie_talk_count;
+
+ int16 raoul_action;
+ int16 raoul_frame;
+ int16 raoul_talk_count;
+
+ int16 rich_action;
+ int16 rich_frame;
+ int16 rich_talk_count;
+
+ int16 daae_action;
+ int16 daae_frame;
+ int16 daae_talk_count;
+
+ int16 anim_0_running;
+ int16 anim_1_running;
+ int16 anim_2_running;
+ int16 anim_3_running;
+ int16 show_note;
+ int16 converse_counter;
+
+} Scratch;
+
+
+/* ========================= Sprite Series ========================= */
+
+#define fx_1993 0 /* rm203z */
+#define fx_parchment 1 /* rm203p1 */
+#define fx_parchment_2 2 /* rm203p1 (second stamp slot) */
+#define fx_letter 3 /* rm203p0 */
+#define fx_take_6 4 /* rdr_6 */
+#define fx_door 5 /* rm203x0 */
+
+
+/* ========================= Conversations ========================= */
+
+#define CONV_BRIE_5 5
+#define CONV_RICH_8 8
+#define CONV_RD_15 15
+
+/* Conv 5 â Brie action states */
+#define CONV5_BRIE_TALK 0
+#define CONV5_BRIE_TALK_HANDS_UP 1
+#define CONV5_BRIE_POINT 2
+#define CONV5_BRIE_NOD 3
+#define CONV5_BRIE_SHUT_UP 4
+
+/* Conv 8 â Rich action states (also shared by Conv 15) */
+#define CONV8_RICH_TALK 0
+#define CONV8_RICH_LEFT_UP_DONT_KNOW 1
+#define CONV8_RICH_POINT 2
+#define CONV8_RICH_BOTH_UP 3
+#define CONV8_RICH_SHUT_UP 4
+#define CONV15_RICH_STAND_TALK 5
+#define CONV15_RICH_SIT_DOWN 6
+#define CONV15_RICH_STAND_SHUT_UP 7
+
+/* Conv 5 â Raoul action states */
+#define CONV5_RAOUL_SHUT_UP 0
+#define CONV5_RAOUL_TALK 1
+#define CONV5_RAOUL_GET_UP 2
+#define CONV5_RAOUL_TAKE 3
+#define CONV5_RAOUL_TAKE_TRAY 4
+#define CONV5_RAOUL_SHOW 5
+
+/* Conv 15 â Daae action states */
+#define CONV15_DAAE_SHUT_UP 0
+#define CONV15_DAAE_TALK_RICH 1
+#define CONV15_DAAE_TALK_RAOUL 2
+#define CONV15_DAAE_LEAVE 3
+
+
+/* ========================= Triggers ============================== */
+
+#define ROOM_203_BRIE_START_TALKING 60
+#define ROOM_203_RAOUL_START_TALKING 65
+#define ROOM_203_GET_UP 70
+#define ROOM_203_TAKE_NOTE 74
+#define ROOM_203_BRIE_TALK_HANDS_UP 76
+#define ROOM_203_BRIE_POINT 78
+#define ROOM_203_RICH_POINT 81
+#define ROOM_203_RICH_LEFT_UP_DONT_KNOW 83
+#define ROOM_203_RICH_BOTH_UP 85
+#define ROOM_203_DOOR_OPENS 90
+#define ROOM_203_DOOR_CLOSES 95
+#define ROOM_203_RICH_START_TALKING 100
+#define ROOM_203_DAAE_START_TALKING 105
+#define ROOM_203_AFTER_SCREAM 110
+#define ROOM_203_END 115
+
+
+/* ========================= Player positions ====================== */
+
+#define PLAYER_X_FROM_202 195
+#define PLAYER_Y_FROM_202 147
+
+#define PLAYER_X_FROM_113 98
+#define PLAYER_Y_FROM_113 137
+
+#define PLAYER_X_FROM_204 292
+#define PLAYER_Y_FROM_204 119
+
+#define WALK_TO_X_FROM_204 276
+#define WALK_TO_Y_FROM_204 123
+
+#define WALK_TO_X_BEHIND_DOOR 319
+#define WALK_TO_Y_BEHIND_DOOR 123
+
+
+/* ========================= Misc positions ======================== */
+
+#define FRONT_CHAIR_X 154
+#define FRONT_CHAIR_Y 131
+
+#define DOOR_X 276
+#define DOOR_Y 123
+
+
+extern void room_203_init();
+extern void room_203_daemon();
+extern void room_203_pre_parser();
+extern void room_203_parser();
+extern void room_203_preload();
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index d24c7c95c78..1df5898671e 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -140,6 +140,7 @@ MODULE_OBJS += \
madsv2/phantom/rooms/section2.o \
madsv2/phantom/rooms/room201.o \
madsv2/phantom/rooms/room202.o \
+ madsv2/phantom/rooms/room203.o \
madsv2/phantom/phantom.o \
madsv2/phantom/conv.o \
madsv2/phantom/main_menu.o \
Commit: 2b366bdf7e2477c37645ccf40781e912664198ec
https://github.com/scummvm/scummvm/commit/2b366bdf7e2477c37645ccf40781e912664198ec
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:44+10:00
Commit Message:
MADS: PHANTOM: Added room 204
Changed paths:
A engines/mads/madsv2/phantom/rooms/room204.cpp
A engines/mads/madsv2/phantom/rooms/room204.h
engines/mads/madsv2/phantom/conv.h
engines/mads/madsv2/phantom/global.h
engines/mads/madsv2/phantom/mads/quotes.h
engines/mads/madsv2/phantom/mads/text.h
engines/mads/madsv2/phantom/mads/words.h
engines/mads/module.mk
diff --git a/engines/mads/madsv2/phantom/conv.h b/engines/mads/madsv2/phantom/conv.h
index 65299775910..8d1863d66d3 100644
--- a/engines/mads/madsv2/phantom/conv.h
+++ b/engines/mads/madsv2/phantom/conv.h
@@ -207,6 +207,25 @@ enum {
conv017_hasnot_first = 4
};
+enum {
+ conv022_second_next = 1,
+ conv022_resolution_florent = 6,
+ conv022_resolution_fall = 7,
+ conv022_resolution_alone = 8,
+ conv022_dead_strangled = 9,
+ conv022_object_abc = 13,
+ conv022_do_abc = 15,
+ conv022_kiss_b_b = 17,
+ conv022_kiss_abc = 18,
+ conv022_notes_hadany = 19,
+ conv022_notes_here = 20,
+ conv022_notes_chandelier = 21,
+ conv022_notes_audience = 22,
+ conv022_look_abc = 23,
+ conv022_notes_b_b = 25,
+ conv022_leave_b_b = 29
+};
+
struct ConvData {
int16 node_count;
int16 dialog_count;
diff --git a/engines/mads/madsv2/phantom/global.h b/engines/mads/madsv2/phantom/global.h
index 9343222ff17..933bd5fb711 100644
--- a/engines/mads/madsv2/phantom/global.h
+++ b/engines/mads/madsv2/phantom/global.h
@@ -203,6 +203,7 @@ enum {
#define USHER_AND_SELLER 2
// sandbag_status
+#define SANDBAG_SECURE 0
#define SANDBAG_DROPPED 1
// julies_door
diff --git a/engines/mads/madsv2/phantom/mads/quotes.h b/engines/mads/madsv2/phantom/mads/quotes.h
index 81554c951a1..de7d50cc7bd 100644
--- a/engines/mads/madsv2/phantom/mads/quotes.h
+++ b/engines/mads/madsv2/phantom/mads/quotes.h
@@ -29,8 +29,9 @@ namespace MADSV2 {
namespace Phantom {
enum {
- quote_mainmenu_phantom_1 = 66
+ quote_mainmenu_phantom_1 = 66,
+ quote_204a0 = 117
#if 0
quote_menu_done,
quote_menu_cancel,
diff --git a/engines/mads/madsv2/phantom/mads/text.h b/engines/mads/madsv2/phantom/mads/text.h
index 7e145150523..9fd72eba477 100644
--- a/engines/mads/madsv2/phantom/mads/text.h
+++ b/engines/mads/madsv2/phantom/mads/text.h
@@ -518,7 +518,38 @@ enum {
/* Cross-room text (room 008 range, continued) */
text_008_12 = 812,
text_008_13 = 813,
- text_008_14 = 814
+ text_008_14 = 814,
+ text_008_15 = 815,
+
+ /* Room 204 */
+ text_204_10 = 20410,
+ text_204_11 = 20411,
+ text_204_12 = 20412,
+ text_204_13 = 20413,
+ text_204_14 = 20414,
+ /* text_204_15 not used */
+ text_204_16 = 20416,
+ text_204_17 = 20417,
+ text_204_18 = 20418,
+ text_204_19 = 20419,
+ text_204_20 = 20420,
+ text_204_21 = 20421,
+ text_204_22 = 20422,
+ text_204_23 = 20423,
+ text_204_24 = 20424,
+ text_204_25 = 20425,
+ text_204_26 = 20426,
+ text_204_27 = 20427,
+ text_204_28 = 20428,
+ text_204_29 = 20429,
+ text_204_30 = 20430,
+ text_204_31 = 20431,
+ text_204_32 = 20432,
+ text_204_33 = 20433,
+ text_204_34 = 20434,
+ /* text_204_35 not used */
+ text_204_36 = 20436,
+ text_204_37 = 20437
};
} // namespace Phantom
diff --git a/engines/mads/madsv2/phantom/mads/words.h b/engines/mads/madsv2/phantom/mads/words.h
index 622a4cb0928..7cfb7ffa13e 100644
--- a/engines/mads/madsv2/phantom/mads/words.h
+++ b/engines/mads/madsv2/phantom/mads/words.h
@@ -36,6 +36,7 @@ enum {
words_apron = 19,
words_backstage = 21,
words_bear_prop = 22,
+ words_book = 24,
words_bust = 25,
words_cable = 26,
words_carton = 28,
@@ -190,6 +191,10 @@ enum {
words_decorative_molding = 225,
words_left_archway = 227,
words_right_archway = 229,
+ words_sofa = 230,
+ words_end_table = 231,
+ words_coffee_table = 232,
+ words_decorative_vase = 233,
words_light = 245,
words_candle = 246,
words_prop_case = 247,
@@ -198,6 +203,7 @@ enum {
words_axe = 249,
words_door_chunks = 250,
words_bulletin_board = 252,
+ words_glass_case = 254,
words_middle_door = 256,
words_dressing_gown = 257,
words_Monsieur_Brie = 258,
diff --git a/engines/mads/madsv2/phantom/rooms/room204.cpp b/engines/mads/madsv2/phantom/rooms/room204.cpp
new file mode 100644
index 00000000000..901d9484e30
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room204.cpp
@@ -0,0 +1,1028 @@
+/* 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 "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/imath.h"
+#include "mads/madsv2/core/text.h"
+#include "mads/madsv2/core/inter.h"
+#include "mads/madsv2/core/object.h"
+#include "mads/madsv2/core/sound.h"
+#include "mads/madsv2/core/speech.h"
+#include "mads/madsv2/core/quote.h"
+#include "mads/madsv2/core/matte.h"
+#include "mads/madsv2/core/buffer.h"
+#include "mads/madsv2/phantom/global.h"
+#include "mads/madsv2/phantom/conv.h"
+#include "mads/madsv2/phantom/mads/inventory.h"
+#include "mads/madsv2/phantom/mads/quotes.h"
+#include "mads/madsv2/phantom/mads/sounds.h"
+#include "mads/madsv2/phantom/mads/speeches.h"
+#include "mads/madsv2/phantom/mads/text.h"
+#include "mads/madsv2/phantom/mads/words.h"
+#include "mads/madsv2/phantom/rooms/section2.h"
+#include "mads/madsv2/phantom/rooms/room204.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+static void handle_animation_brie() {
+ int random = 0;
+ int brie_reset_frame;
+
+ if (kernel_anim[aa[0]].frame != local->brie_frame) {
+ local->brie_frame = kernel_anim[aa[0]].frame;
+ brie_reset_frame = -1;
+
+ switch (local->brie_frame) {
+ case 80: /* somewhere into Brie's leaving */
+ conv_release();
+ local->raoul_action = CONV22_RAOUL_SIT;
+ break;
+
+ case 173:
+ player.commands_allowed = true;
+ text_show(text_204_30);
+ player.commands_allowed = false;
+ break;
+
+ case 174: /* end of leave */
+ local->raoul_action = CONV22_RAOUL_GET_BOOK;
+ brie_reset_frame = 173;
+ break;
+
+ case 1: /* end of freeze */
+ case 22: /* end point */
+ case 49: /* end of put right arm up */
+ case 7: /* end of talk 1 */
+ case 13: /* end of talk 2 */
+ case 33: /* end of talk 3 */
+ case 61: /* end of talk 4 */
+
+ switch (local->brie_action) {
+ case CONV22_BRIE_TALK:
+ random = imath_random(1, 4);
+ local->brie_action = CONV22_BRIE_SHUT_UP;
+ break;
+
+ case CONV22_BRIE_POINT:
+ random = 5;
+ break;
+
+ case CONV22_BRIE_LEAVE:
+ random = 6;
+ break;
+
+ case CONV22_BRIE_RIGHT_UP:
+ random = 7;
+ break;
+
+ default:
+ random = 8;
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ brie_reset_frame = 1;
+ local->brie_action = CONV22_BRIE_SHUT_UP;
+ break; /* do talk 1 */
+
+ case 2:
+ brie_reset_frame = 7;
+ local->brie_action = CONV22_BRIE_SHUT_UP;
+ break; /* do talk 2 */
+
+ case 3:
+ brie_reset_frame = 22;
+ local->brie_action = CONV22_BRIE_SHUT_UP;
+ break; /* do talk 3 */
+
+ case 4:
+ brie_reset_frame = 49;
+ local->brie_action = CONV22_BRIE_SHUT_UP;
+ break; /* do talk 4 */
+
+ case 5:
+ brie_reset_frame = 13;
+ local->brie_action = CONV22_BRIE_SHUT_UP;
+ break; /* point */
+
+ case 6:
+ brie_reset_frame = 61;
+ break; /* leave */
+
+ default:
+ brie_reset_frame = 0;
+ break; /* freeze sitting still */
+ }
+ break;
+ }
+
+ if (brie_reset_frame >= 0) {
+ kernel_reset_animation(aa[0], brie_reset_frame);
+ local->brie_frame = brie_reset_frame;
+ }
+ }
+}
+
+static void handle_animation_flor() {
+ int random = 0;
+ int flor_reset_frame;
+
+ if (kernel_anim[aa[1]].frame != local->flor_frame) {
+ local->flor_frame = kernel_anim[aa[1]].frame;
+ flor_reset_frame = -1;
+
+ switch (local->flor_frame) {
+ case 80: /* just as Raoul turns invisible, make him visible with aa[2] */
+ kernel_reset_animation(aa[2], 1);
+ kernel_synch(KERNEL_ANIM, aa[2], KERNEL_ANIM, aa[1]);
+ local->raoul_action = CONV22_RAOUL_SHUT_UP;
+ break;
+
+ case 86: /* a few frames just after kiss (where Florent leaves) */
+ conv_release();
+ break;
+
+ case 173: /* end of leave */
+ flor_reset_frame = 172;
+ break;
+
+ case 1: /* end of Raoul laying down 1 */
+ case 2: /* end of Raoul laying down 2 */
+ case 3: /* end of Raoul laying down 3 */
+ if (local->keep_raoul_down) {
+ random = imath_random(1, 1000);
+ if (random < 300) {
+ flor_reset_frame = 0;
+ } else if (random < 600) {
+ flor_reset_frame = 1;
+ } else {
+ flor_reset_frame = 2;
+ }
+ }
+ break;
+
+ case 21: /* end of Raoul awaking */
+ case 180: /* end of Raoul glancing to case */
+ conv_release();
+ break;
+
+ case 22: /* end of freeze */
+ case 50: /* end of talk to Brie */
+ case 30: /* end of talk to Raoul */
+ case 174: /* end of Raoul talk to Flor 1 */
+ case 175: /* end of Raoul talk to Flor 2 */
+ case 176: /* end of Raoul talk to Flor 3 */
+ case 181: /* end of Raoul glancing to case */
+
+ switch (local->flor_action) {
+ case CONV22_FLOR_TALK_RAOUL:
+ random = 1;
+ local->flor_action = CONV22_FLOR_SHUT_UP;
+ break;
+
+ case CONV22_FLOR_TALK_BRIE:
+ random = 2;
+ local->flor_action = CONV22_FLOR_SHUT_UP;
+ break;
+
+ case CONV22_FLOR_LEAVE:
+ random = 3;
+ break;
+
+ case CONV22_RAOUL_GLANCE:
+ random = 4;
+ local->flor_action = CONV22_FLOR_SHUT_UP;
+ break;
+
+ case CONV22_FLOR_RAOUL_TALK:
+ random = imath_random(5, 7);
+ ++local->raoul_talk_count;
+ if (local->raoul_talk_count > 17) {
+ local->flor_action = CONV22_FLOR_SHUT_UP;
+ random = 8;
+ }
+ break;
+
+ default:
+ random = 7;
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ flor_reset_frame = 22;
+ break; /* do talk to Raoul */
+
+ case 2:
+ flor_reset_frame = 30;
+ break; /* do talk to Brie */
+
+ case 3:
+ flor_reset_frame = 53;
+ break; /* leave */
+
+ case 4:
+ flor_reset_frame = 176;
+ break; /* Raoul glance over to case */
+
+ case 5:
+ flor_reset_frame = 173;
+ break; /* Raoul talk to Flor 1 */
+
+ case 6:
+ flor_reset_frame = 174;
+ break; /* Raoul talk to Flor 2 */
+
+ case 7:
+ flor_reset_frame = 175;
+ break; /* Raoul talk to Flor 3 */
+
+ default:
+ flor_reset_frame = 21;
+ break; /* freeze Florent and Raoul */
+ }
+ break;
+ }
+
+ if (flor_reset_frame >= 0) {
+ kernel_reset_animation(aa[1], flor_reset_frame);
+ local->flor_frame = flor_reset_frame;
+ }
+ }
+}
+
+static void handle_animation_raoul() {
+ int random = 0;
+ int raoul_reset_frame;
+
+ if (kernel_anim[aa[2]].frame != local->raoul_frame) {
+ local->raoul_frame = kernel_anim[aa[2]].frame;
+ raoul_reset_frame = -1;
+
+ switch (local->raoul_frame) {
+ case 213:
+ player.commands_allowed = true;
+ object_examine(book, text_204_31, 0);
+ player.commands_allowed = false;
+ break;
+
+ case 229:
+ player.commands_allowed = true;
+ object_examine(book, text_204_32, 0);
+ player.commands_allowed = false;
+ break;
+
+ case 237:
+ kernel_abort_animation(aa[1]);
+ kernel_abort_animation(aa[0]);
+ local->anim_0_running = false;
+ local->anim_1_running = false;
+ local->anim_3_running = true;
+ aa[3] = kernel_run_animation(kernel_name('e', 1), 0);
+ global_speech_load(speech_phantom_cackle);
+ break;
+
+ case 253: /* end of getting book */
+ raoul_reset_frame = 244;
+ break;
+
+ case 114: /* just took book â delete book */
+ kernel_seq_delete(seq[fx_book]);
+ inter_give_to_player(book);
+ break;
+
+ case 1: /* end of invisible */
+ if (local->raoul_action == CONV22_RAOUL_INVISIBLE) {
+ raoul_reset_frame = 0;
+ }
+ break;
+
+ case 31:
+ if (local->raoul_action == CONV22_RAOUL_GET_BOOK) {
+ raoul_reset_frame = 33;
+ } else {
+ raoul_reset_frame = 30;
+ }
+ break;
+
+ case 33:
+ raoul_reset_frame = 32;
+ break;
+
+ case 257: /* almost at end of glance */
+ conv_release();
+ break;
+
+ case 10: /* end of freeze (visible) */
+ case 14: /* end of talk 1 */
+ case 20: /* end of talk 2 */
+ case 258: /* end of glance */
+
+ switch (local->raoul_action) {
+ case CONV22_RAOUL_TALK:
+ random = imath_random(1, 2);
+ local->raoul_action = CONV22_RAOUL_SHUT_UP;
+ break;
+
+ case CONV22_RAOUL_SIT:
+ random = 3;
+ break;
+
+ case CONV22_RAOUL_GLANCE:
+ random = 4;
+ break;
+
+ default:
+ random = 5;
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ raoul_reset_frame = 10;
+ local->raoul_action = CONV22_RAOUL_SHUT_UP;
+ break; /* do talk 1 */
+
+ case 2:
+ raoul_reset_frame = 14;
+ local->raoul_action = CONV22_RAOUL_SHUT_UP;
+ break; /* do talk 2 */
+
+ case 3:
+ raoul_reset_frame = 20;
+ break; /* sit (put both feet on floor) */
+
+ case 4:
+ raoul_reset_frame = 253;
+ local->raoul_action = CONV22_RAOUL_SHUT_UP;
+ break; /* glance over to case */
+
+ default:
+ raoul_reset_frame = 9;
+ break; /* freeze laying up */
+ }
+ break;
+ }
+
+ if (raoul_reset_frame >= 0) {
+ kernel_reset_animation(aa[2], raoul_reset_frame);
+ local->raoul_frame = raoul_reset_frame;
+ }
+ }
+}
+
+static void handle_animation_end() {
+ if ((kernel_anim[aa[3]].frame == 15) && (!local->prevent_3)) {
+ global_speech_go(speech_phantom_cackle);
+ local->prevent_3 = true;
+ }
+
+ if ((kernel_anim[aa[3]].frame == 26) && (!local->prevent_2)) {
+ kernel_timing_trigger(FIVE_SECONDS, ROOM_204_BYE);
+ kernel_message_add(quote_string(kernel.quotes, quote_204a0),
+ 123, 137, MESSAGE_COLOR, SIX_SECONDS, 0, 0);
+ local->prevent_2 = true;
+ }
+
+ if (kernel_anim[aa[3]].frame == 27) {
+ kernel_reset_animation(aa[3], 12);
+ }
+}
+
+void room_204_daemon() {
+ if (local->anim_0_running) {
+ handle_animation_brie();
+ }
+
+ if (local->anim_1_running) {
+ handle_animation_flor();
+ }
+
+ if (local->anim_2_running) {
+ handle_animation_raoul();
+ }
+
+ if (local->anim_3_running) {
+ handle_animation_end();
+ }
+
+ if (kernel.trigger == ROOM_204_BYE) {
+ new_room = 250;
+ }
+
+ if ((conv_control.running != CONV_END_22) && (!local->prevent) && (local->end_of_game)) {
+ player.commands_allowed = false;
+ local->prevent = true;
+ }
+
+ switch (kernel.trigger) {
+ case ROOM_204_DOOR_CLOSES:
+ seq[fx_door] = kernel_seq_backward(ss[fx_door], false, 8, 0, 0, 1);
+ kernel_seq_depth(seq[fx_door], 10);
+ kernel_seq_range(seq[fx_door], KERNEL_FIRST, KERNEL_LAST);
+ kernel_seq_trigger(seq[fx_door], KERNEL_TRIGGER_EXPIRE, 0, ROOM_204_DOOR_CLOSES + 1);
+ break;
+
+ case ROOM_204_DOOR_CLOSES + 1:
+ sound_play(N_DoorCloses);
+ seq[fx_door] = kernel_seq_stamp(ss[fx_door], false, 1);
+ kernel_seq_depth(seq[fx_door], 5);
+ player.commands_allowed = true;
+ break;
+ }
+}
+
+static void process_conversation_22() {
+ int you_trig_flag = false;
+ int me_trig_flag = false;
+
+ switch (player_verb) {
+ case conv022_resolution_florent:
+ case conv022_resolution_fall:
+ case conv022_resolution_alone:
+ if (local->keep_raoul_down) {
+ conv_hold();
+ local->keep_raoul_down = false;
+ }
+ break;
+
+ case conv022_kiss_b_b:
+ if (!kernel.trigger) {
+ local->flor_action = CONV22_FLOR_LEAVE;
+ local->florent_is_gone = true;
+ you_trig_flag = true;
+ me_trig_flag = true;
+ conv_hold();
+ }
+ break;
+
+ case conv022_leave_b_b:
+ you_trig_flag = true;
+ me_trig_flag = true;
+ if (!kernel.trigger) {
+ local->brie_action = CONV22_BRIE_LEAVE;
+ conv_hold();
+ }
+ break;
+
+ case conv022_notes_b_b:
+ if (!kernel.trigger) {
+ local->raoul_action = CONV22_RAOUL_GLANCE;
+ local->flor_action = CONV22_RAOUL_GLANCE;
+ you_trig_flag = true;
+ me_trig_flag = true;
+ conv_hold();
+ }
+ break;
+ }
+
+ switch (kernel.trigger) {
+ case ROOM_204_YOU_TALK:
+ if (local->florent_is_gone) {
+ if ((player_verb != conv022_kiss_abc) &&
+ (player_verb != conv022_look_abc)) {
+ local->brie_action = CONV22_BRIE_TALK;
+ }
+
+ } else {
+ switch (player_verb) {
+ case conv022_second_next:
+ case conv022_resolution_fall:
+ case conv022_resolution_alone:
+ case conv022_dead_strangled:
+ case conv022_object_abc:
+ case conv022_do_abc:
+ case conv022_notes_hadany:
+ case conv022_notes_here:
+ case conv022_notes_chandelier:
+ case conv022_notes_audience:
+ local->brie_action = CONV22_BRIE_TALK;
+ break;
+
+ default:
+ local->flor_action = CONV22_FLOR_TALK_RAOUL;
+ break;
+ }
+ }
+ break;
+
+ case ROOM_204_ME_TALK:
+ if (local->florent_is_gone) {
+ if (local->raoul_action != CONV22_RAOUL_SIT) {
+ local->raoul_action = CONV22_RAOUL_TALK;
+ }
+ } else {
+ local->flor_action = CONV22_FLOR_RAOUL_TALK;
+ }
+ break;
+ }
+
+
+ /* ================= Set up me and you triggers ================ */
+
+ if (!me_trig_flag) {
+ if (!local->keep_raoul_down) {
+ conv_me_trigger(ROOM_204_ME_TALK);
+ }
+ }
+
+ if (!you_trig_flag) {
+ conv_you_trigger(ROOM_204_YOU_TALK);
+ }
+
+ local->raoul_talk_count = 0;
+}
+
+void room_204_pre_parser() {
+ if (player_said_2(look, bookcase)) {
+ player.need_to_walk = true;
+ }
+
+ if (player_said_2(look, book) && object_is_here(book)) {
+ player.need_to_walk = true;
+ }
+
+ if (player_said_2(open, door)) {
+ player_walk(DOOR_X, DOOR_Y, FACING_WEST);
+ }
+}
+
+void room_204_parser() {
+ if (conv_control.running == CONV_END_22) {
+ process_conversation_22();
+ goto handled;
+ }
+
+ if (player_said_2(walk_through, door) || player_said_2(open, door)) {
+ switch (kernel.trigger) {
+ case 0:
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_take_6] = kernel_seq_pingpong(ss[fx_take_6], true, 5, 0, 0, 2);
+ kernel_seq_range(seq[fx_take_6], 1, 4);
+ kernel_seq_player(seq[fx_take_6], true);
+ kernel_seq_trigger(seq[fx_take_6], KERNEL_TRIGGER_SPRITE, 4, ROOM_204_DOOR_OPENS);
+ kernel_seq_trigger(seq[fx_take_6], KERNEL_TRIGGER_EXPIRE, 0, ROOM_204_DOOR_OPENS + 1);
+ break;
+
+ case ROOM_204_DOOR_OPENS:
+ sound_play(N_DoorOpens);
+ kernel_seq_delete(seq[fx_door]);
+ seq[fx_door] = kernel_seq_forward(ss[fx_door], false, 8, 0, 0, 1);
+ kernel_seq_depth(seq[fx_door], 14);
+ kernel_seq_range(seq[fx_door], KERNEL_FIRST, KERNEL_LAST);
+ break;
+
+ case ROOM_204_DOOR_OPENS + 1:
+ player.walker_visible = true;
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_SERIES, seq[fx_take_6]);
+ player_walk(WALK_TO_X_BEHIND_DOOR, WALK_TO_Y_BEHIND_DOOR, FACING_WEST);
+ player_walk_trigger(ROOM_204_DOOR_OPENS + 2);
+ break;
+
+ case ROOM_204_DOOR_OPENS + 2:
+ new_room = 203;
+ break;
+ }
+ goto handled;
+ }
+
+ if (player_said_2(take, book) &&
+ (object_is_here(book) || kernel.trigger)) {
+ switch (kernel.trigger) {
+ case 0:
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_reach_up_7] = kernel_seq_pingpong(ss[fx_reach_up_7], false, 5, 0, 0, 2);
+ kernel_seq_range(seq[fx_reach_up_7], KERNEL_FIRST, KERNEL_LAST);
+ kernel_seq_player(seq[fx_reach_up_7], true);
+ kernel_seq_trigger(seq[fx_reach_up_7], KERNEL_TRIGGER_SPRITE, 8, 1);
+ kernel_seq_trigger(seq[fx_reach_up_7], KERNEL_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ kernel_seq_delete(seq[fx_book]);
+ kernel_flip_hotspot(words_book, false);
+ inter_give_to_player(book);
+ sound_play(N_TakeObjectSnd);
+ break;
+
+ case 2:
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_SERIES, seq[fx_reach_up_7]);
+ player.walker_visible = true;
+ kernel_timing_trigger(20, 3);
+ break;
+
+ case 3:
+ object_examine(book, text_008_15, 0);
+ global[read_book] = true;
+ global[player_score] += 5;
+ player.commands_allowed = true;
+ break;
+ }
+ goto handled;
+ }
+
+ if (player_said_2(exit_to, grand_foyer)) {
+ new_room = 202;
+ goto handled;
+ }
+
+ if (player.look_around) {
+ text_show(text_204_10);
+ goto handled;
+ }
+
+ if (player_said_1(look) || player_said_1(look_at)) {
+
+ if (player_said_1(wall)) {
+ text_show(text_204_11);
+ goto handled;
+ }
+
+ if (player_said_1(floor)) {
+ text_show(text_204_12);
+ goto handled;
+ }
+
+ if (player_said_1(rug)) {
+ text_show(text_204_13);
+ goto handled;
+ }
+
+ if (player_said_1(glass_case)) {
+ text_show(text_204_14);
+ global[looked_at_case] = true;
+ goto handled;
+ }
+
+ if (player_said_1(ceiling)) {
+ if (global[sandbag_status] == SANDBAG_SECURE) {
+ text_show(text_204_29);
+ } else {
+ text_show(text_204_16);
+ }
+ goto handled;
+ }
+
+ if (player_said_1(bookcase)) {
+ if ((global[can_find_book_library]) && (global[current_year] == 1993)) {
+ if ((inter_point_x < 46) && (!player_has(book))) {
+ if (!global[scanned_bookcase]) {
+ text_show(text_204_33);
+ kernel_flip_hotspot(words_book, true);
+ global[scanned_bookcase] = true;
+ } else {
+ text_show(text_204_37);
+ }
+ } else {
+ text_show(text_204_17);
+ }
+ } else {
+ text_show(text_204_17);
+ }
+ goto handled;
+ }
+
+ if (player_said_1(sofa)) {
+ text_show(text_204_18);
+ goto handled;
+ }
+
+ if (player_said_1(end_table)) {
+ text_show(text_204_19);
+ goto handled;
+ }
+
+ if (player_said_1(lamp)) {
+ text_show(text_204_20);
+ goto handled;
+ }
+
+ if (player_said_1(bust)) {
+ text_show(text_204_21);
+ goto handled;
+ }
+
+ if (player_said_1(coffee_table)) {
+ text_show(text_204_22);
+ goto handled;
+ }
+
+ if (player_said_1(comfy_chair)) {
+ text_show(text_204_23);
+ goto handled;
+ }
+
+ if (player_said_1(decorative_vase)) {
+ text_show(text_204_24);
+ goto handled;
+ }
+
+ if (player_said_1(painting)) {
+ text_show(text_204_25);
+ goto handled;
+ }
+
+ if (player_said_1(grand_foyer)) {
+ text_show(text_204_26);
+ goto handled;
+ }
+
+ if (player_said_1(door)) {
+ text_show(text_204_27);
+ goto handled;
+ }
+
+ if (player_said_1(window)) {
+ text_show(text_204_28);
+ goto handled;
+ }
+
+ if (player_said_1(book) && object_is_here(book)) {
+ text_show(text_204_34);
+ goto handled;
+ }
+ }
+
+ if (player_said_2(talk_to, bust)) {
+ text_show(text_204_36);
+ goto handled;
+ }
+
+ goto done;
+
+handled:
+ player.command_ready = false;
+
+done:
+ ;
+}
+
+void room_204_init() {
+ int coffee_table; /* Dynamic for coffee table / object iterator */
+ int chair; /* Dynamic for chair */
+ int exit; /* Dynamic for exits */
+
+ local->prevent_3 = false;
+
+ if (previous_room != KERNEL_RESTORING_GAME) {
+ local->anim_0_running = false;
+ local->anim_1_running = false;
+ local->anim_2_running = false;
+ local->anim_3_running = false;
+ local->florent_is_gone = false;
+ local->prevent = false;
+ local->prevent_2 = false;
+ local->end_of_game = false;
+ local->keep_raoul_down = true;
+ }
+
+ if (global[ticket_people_here] == USHER_AND_SELLER) {
+ global[make_rich_leave_203] = true;
+ }
+
+ if (global[right_door_is_open_504]) {
+ local->end_of_game = true;
+ }
+
+ if (local->end_of_game) {
+ if (room_loaded_walk) {
+ buffer_free(&scr_walk);
+ }
+ }
+
+ kernel_flip_hotspot(words_book, false);
+
+
+ /* =================== Load conversations ====================== */
+
+ conv_get(CONV_END_22);
+
+
+ /* =================== Load Sprite Series ====================== */
+
+ ss[fx_book] = kernel_load_series(kernel_name('p', 0), false);
+ ss[fx_door] = kernel_load_series(kernel_name('x', 6), false);
+ ss[fx_reach_up_7] = kernel_load_series("*RALRH_9", false);
+ ss[fx_take_6] = kernel_load_series("*RDRR_6", false);
+
+
+ /* =================== If book is here, stamp it =============== */
+
+ if (object_is_here(book) || (global[current_year] == 1881) || (local->end_of_game)) {
+ seq[fx_book] = kernel_seq_stamp(ss[fx_book], false, 1);
+ kernel_seq_depth(seq[fx_book], 5);
+ if ((global[scanned_bookcase]) && (global[current_year] == 1993)) {
+ kernel_flip_hotspot(words_book, true);
+ }
+ }
+
+
+ /* =================== Draw 1993 sprite ======================== */
+
+ if ((global[current_year] == 1993) || local->end_of_game) {
+ ss[fx_1993] = kernel_load_series(kernel_name('z', -1), false);
+ kernel_draw_to_background(ss[fx_1993], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ matte_deallocate_series(ss[fx_1993], true);
+ kernel_flip_hotspot(words_candle, false);
+ kernel_flip_hotspot(words_bust, false);
+ kernel_flip_hotspot(words_coffee_table, false);
+
+ /* 1 dynamic for coffee_table */
+ coffee_table = kernel_add_dynamic(words_coffee_table, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ COFFEE_X, COFFEE_Y, COFFEE_X_SIZE, COFFEE_Y_SIZE);
+ kernel_dynamic_walk(coffee_table, WALK_TO_COFFEE_X, WALK_TO_COFFEE_Y, FACING_SOUTHEAST);
+
+ /* 2 dynamics for exits */
+ exit = kernel_add_dynamic(words_grand_foyer, words_exit_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ EXIT_1_X, EXIT_1_Y, EXIT_1_X_SIZE, EXIT_1_Y_SIZE);
+ kernel_dynamic_walk(exit, WALK_TO_EXIT_1_X, WALK_TO_EXIT_1_Y, FACING_SOUTH);
+ kernel_dynamic_cursor(exit, 3);
+
+ exit = kernel_add_dynamic(words_grand_foyer, words_exit_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ EXIT_2_X, EXIT_2_Y, EXIT_2_X_SIZE, EXIT_2_Y_SIZE);
+ kernel_dynamic_walk(exit, WALK_TO_EXIT_2_X, WALK_TO_EXIT_2_Y, FACING_SOUTH);
+ kernel_dynamic_cursor(exit, 3);
+
+ } else {
+ kernel_flip_hotspot(words_light, false);
+ kernel_flip_hotspot(words_glass_case, false);
+
+ /* 3 dynamics for chairs */
+ chair = kernel_add_dynamic(words_comfy_chair, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ CHAIR_1_X, CHAIR_1_Y, CHAIR_1_X_SIZE, CHAIR_1_Y_SIZE);
+ kernel_dynamic_walk(chair, WALK_TO_CHAIR_X, WALK_TO_CHAIR_Y, FACING_SOUTHEAST);
+
+ chair = kernel_add_dynamic(words_comfy_chair, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ CHAIR_2_X, CHAIR_2_Y, CHAIR_2_X_SIZE, CHAIR_2_Y_SIZE);
+ kernel_dynamic_walk(chair, WALK_TO_CHAIR_X, WALK_TO_CHAIR_Y, FACING_SOUTHEAST);
+
+ chair = kernel_add_dynamic(words_comfy_chair, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ CHAIR_3_X, CHAIR_3_Y, CHAIR_3_X_SIZE, CHAIR_3_Y_SIZE);
+ kernel_dynamic_walk(chair, WALK_TO_CHAIR_X, WALK_TO_CHAIR_Y, FACING_SOUTHEAST);
+
+ /* 2 dynamics for exits */
+ exit = kernel_add_dynamic(words_grand_foyer, words_exit_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ EXIT_3_X, EXIT_3_Y, EXIT_3_X_SIZE, EXIT_3_Y_SIZE);
+ kernel_dynamic_walk(exit, WALK_TO_EXIT_3_X, WALK_TO_EXIT_3_Y, FACING_SOUTH);
+ kernel_dynamic_cursor(exit, 3);
+
+ exit = kernel_add_dynamic(words_grand_foyer, words_exit_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ EXIT_4_X, EXIT_4_Y, EXIT_4_X_SIZE, EXIT_4_Y_SIZE);
+ kernel_dynamic_walk(exit, WALK_TO_EXIT_4_X, WALK_TO_EXIT_4_Y, FACING_SOUTH);
+ kernel_dynamic_cursor(exit, 3);
+ }
+
+
+ /* =================== Draw glass_case ========================= */
+
+ if ((previous_room == 306) || (local->end_of_game)) {
+ ss[fx_case] = kernel_load_series(kernel_name('f', 0), false);
+ kernel_draw_to_background(ss[fx_case], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+
+ } else {
+ if (global[current_year] == 1993) {
+ ss[fx_broken_case] = kernel_load_series(kernel_name('f', 1), false);
+ kernel_draw_to_background(ss[fx_broken_case], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ matte_deallocate_series(ss[fx_broken_case], true);
+ }
+ }
+
+
+ /* =================== Previous Rooms ========================== */
+
+ if (previous_room == KERNEL_RESTORING_GAME) {
+
+ if (local->end_of_game) {
+
+ kernel.quotes = quote_load(quote_204a0, 0);
+
+ aa[2] = kernel_run_animation(kernel_name('r', 1), 0);
+ local->anim_2_running = true;
+
+ if (local->florent_is_gone) {
+ kernel_reset_animation(aa[2], 9); /* put Raoul sitting up, talking to Brie */
+ local->raoul_action = CONV22_RAOUL_SHUT_UP;
+ } else {
+ kernel_reset_animation(aa[2], 32); /* this is the invisible frame */
+ local->raoul_action = CONV22_RAOUL_INVISIBLE;
+ }
+
+ aa[0] = kernel_run_animation(kernel_name('m', 1), 0);
+ local->anim_0_running = true;
+ local->brie_action = CONV22_BRIE_SHUT_UP;
+
+ aa[1] = kernel_run_animation(kernel_name('f', 1), 0);
+ local->anim_1_running = true;
+ local->flor_action = CONV22_FLOR_SHUT_UP;
+
+ if (local->florent_is_gone) {
+ kernel_reset_animation(aa[1], 172); /* make Florent invisible */
+ } else {
+ if (!local->keep_raoul_down) {
+ kernel_reset_animation(aa[1], 21); /* this will make Raoul sit up with Florent there */
+ }
+ }
+
+ player.walker_visible = false;
+
+ conv_run(CONV_END_22);
+ conv_export_pointer(&global[player_score]);
+
+ } else {
+ seq[fx_door] = kernel_seq_stamp(ss[fx_door], false, 1);
+ kernel_seq_depth(seq[fx_door], 5);
+ }
+
+ } else if (previous_room == 202) {
+ seq[fx_door] = kernel_seq_stamp(ss[fx_door], false, 1);
+ kernel_seq_depth(seq[fx_door], 5);
+ if (global[current_year] == 1993) {
+ player.x = PLAYER_X_FROM_202_1993;
+ player.y = PLAYER_Y_FROM_202_1993;
+ } else {
+ player.x = PLAYER_X_FROM_202_1881;
+ player.y = PLAYER_Y_FROM_202_1881;
+ }
+ player.facing = FACING_NORTHWEST;
+
+ } else if (previous_room == 150) {
+ /* Move all objects to inventory/room 1 for end-of-game */
+ for (coffee_table = 0; coffee_table < num_objects; coffee_table++) {
+ inter_move_object(coffee_table, 1);
+ }
+
+ kernel.quotes = quote_load(quote_204a0, 0);
+
+ aa[2] = kernel_run_animation(kernel_name('r', 1), 0);
+ local->anim_2_running = true;
+ local->raoul_action = CONV22_RAOUL_INVISIBLE;
+ kernel_reset_animation(aa[2], 32); /* this is the invisible frame */
+
+ aa[0] = kernel_run_animation(kernel_name('m', 1), 0);
+ local->anim_0_running = true;
+ local->brie_action = CONV22_BRIE_SHUT_UP;
+
+ aa[1] = kernel_run_animation(kernel_name('f', 1), 0);
+ local->anim_1_running = true;
+ local->keep_raoul_down = true;
+ local->flor_action = CONV22_FLOR_SHUT_UP;
+
+ player.walker_visible = false;
+ local->end_of_game = true;
+
+ conv_run(CONV_END_22);
+ conv_export_pointer(&global[player_score]);
+
+ } else if ((previous_room == 203) || (previous_room != KERNEL_RESTORING_GAME)) {
+ player_first_walk(WALK_TO_X_BEHIND_DOOR - 10, WALK_TO_Y_BEHIND_DOOR, FACING_EAST,
+ WALK_TO_X_FROM_203, WALK_TO_Y_FROM_203, FACING_EAST, true);
+ player_walk_trigger(ROOM_204_DOOR_CLOSES);
+ player.commands_allowed = false;
+ }
+
+ section_2_music();
+}
+
+void room_204_preload() {
+ room_init_code_pointer = room_204_init;
+ room_pre_parser_code_pointer = room_204_pre_parser;
+ room_parser_code_pointer = room_204_parser;
+ room_daemon_code_pointer = room_204_daemon;
+
+ if ((global[current_year] == 1993) || (global[right_door_is_open_504])) {
+ kernel_initial_variant = 1;
+ }
+
+ section_2_walker();
+ section_2_interface();
+}
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/rooms/room204.h b/engines/mads/madsv2/phantom/rooms/room204.h
new file mode 100644
index 00000000000..e0bf3613880
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room204.h
@@ -0,0 +1,208 @@
+/* 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 MADS_PHANTOM_ROOM204_H
+#define MADS_PHANTOM_ROOM204_H
+
+#include "mads/madsv2/phantom/rooms/section2.h"
+#include "mads/madsv2/phantom/global.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+#define local ((Scratch *)(&game.scratch[0]))
+#define ss local->sprite
+#define seq local->sequence
+#define aa local->animation
+
+typedef struct { /* Room local variables */
+
+ int16 sprite[15]; /* Sprite series handles */
+ int16 sequence[15]; /* Sequence handles */
+ int16 animation[4]; /* Animation handles */
+ int16 anim_0_running;
+ int16 anim_1_running;
+ int16 anim_2_running;
+ int16 anim_3_running;
+ int16 keep_raoul_down;
+ int16 florent_is_gone;
+
+ int16 prevent;
+ int16 prevent_2;
+ int16 prevent_3;
+ int16 end_of_game;
+
+ int16 brie_action;
+ int16 brie_frame;
+ int16 flor_action;
+ int16 flor_frame;
+ int16 raoul_action;
+ int16 raoul_frame;
+
+ int16 raoul_talk_count;
+
+} Scratch;
+
+
+/* ========================= Sprite Series ========================= */
+
+#define fx_1993 0 /* rm204z */
+#define fx_broken_case 1 /* rm204f1 */
+#define fx_book 2 /* rm204p0 */
+#define fx_door 3 /* rm204x6 */
+#define fx_reach_up_7 4 /* *RALRH_9 */
+#define fx_take_6 5 /* *RDRR_6 */
+#define fx_case 6 /* rm204f0 */
+
+
+/* ========================= Conversations ========================= */
+
+#define CONV_END_22 22
+
+/* Conv 22 â Brie action states */
+#define CONV22_BRIE_TALK 0
+#define CONV22_BRIE_POINT 1
+#define CONV22_BRIE_SHUT_UP 2
+#define CONV22_BRIE_LEAVE 3
+#define CONV22_BRIE_RIGHT_UP 4
+
+/* Conv 22 â Florent action states */
+#define CONV22_FLOR_TALK_RAOUL 0
+#define CONV22_FLOR_TALK_BRIE 1
+#define CONV22_FLOR_SHUT_UP 2
+#define CONV22_FLOR_LEAVE 3
+#define CONV22_FLOR_RAOUL_TALK 4
+
+/* Conv 22 â Raoul action states */
+#define CONV22_RAOUL_TALK 0
+#define CONV22_RAOUL_SHUT_UP 1
+#define CONV22_RAOUL_SIT 2
+#define CONV22_RAOUL_GET_BOOK 3
+#define CONV22_RAOUL_INVISIBLE 4
+#define CONV22_RAOUL_GLANCE 5
+
+
+/* ========================= Triggers ============================== */
+
+#define ROOM_204_DOOR_OPENS 60
+#define ROOM_204_DOOR_CLOSES 70
+#define ROOM_204_ME_TALK 75
+#define ROOM_204_YOU_TALK 80
+#define ROOM_204_BYE 85
+
+
+/* ========================= Player positions ====================== */
+
+#define PLAYER_X_FROM_202_1881 115
+#define PLAYER_Y_FROM_202_1881 147
+
+#define PLAYER_X_FROM_202_1993 175
+#define PLAYER_Y_FROM_202_1993 145
+
+#define PLAYER_X_FROM_203 2
+#define PLAYER_Y_FROM_203 140
+
+#define WALK_TO_X_FROM_203 30
+#define WALK_TO_Y_FROM_203 140
+
+#define WALK_TO_X_BEHIND_DOOR 0
+#define WALK_TO_Y_BEHIND_DOOR 136
+
+
+/* ========================= Dynamic hotspot bounds ================ */
+
+/* Coffee table (1993) */
+#define COFFEE_X 83
+#define COFFEE_Y 140
+#define COFFEE_X_SIZE 45
+#define COFFEE_Y_SIZE 12
+#define WALK_TO_COFFEE_X 84
+#define WALK_TO_COFFEE_Y 150
+
+/* Comfy chairs (1881) */
+#define CHAIR_1_X 220
+#define CHAIR_1_Y 147
+#define CHAIR_1_X_SIZE 6
+#define CHAIR_1_Y_SIZE 8
+#define WALK_TO_CHAIR_X 220
+#define WALK_TO_CHAIR_Y 150
+
+#define CHAIR_2_X 226
+#define CHAIR_2_Y 134
+#define CHAIR_2_X_SIZE 12
+#define CHAIR_2_Y_SIZE 21
+
+#define CHAIR_3_X 238
+#define CHAIR_3_Y 128
+#define CHAIR_3_X_SIZE 13
+#define CHAIR_3_Y_SIZE 27
+
+/* Grand foyer exits (1993) */
+#define EXIT_1_X 199
+#define EXIT_1_Y 147
+#define EXIT_1_X_SIZE 52
+#define EXIT_1_Y_SIZE 8
+#define WALK_TO_EXIT_1_X 224
+#define WALK_TO_EXIT_1_Y 152
+
+#define EXIT_2_X 145
+#define EXIT_2_Y 147
+#define EXIT_2_X_SIZE 54
+#define EXIT_2_Y_SIZE 8
+#define WALK_TO_EXIT_2_X 175
+#define WALK_TO_EXIT_2_Y 152
+
+/* Grand foyer exits (1881) */
+#define EXIT_3_X 199
+#define EXIT_3_Y 147
+#define EXIT_3_X_SIZE 19
+#define EXIT_3_Y_SIZE 8
+#define WALK_TO_EXIT_3_X 209
+#define WALK_TO_EXIT_3_Y 152
+
+#define EXIT_4_X 84
+#define EXIT_4_Y 147
+#define EXIT_4_X_SIZE 61
+#define EXIT_4_Y_SIZE 8
+#define WALK_TO_EXIT_4_X 115
+#define WALK_TO_EXIT_4_Y 152
+
+
+/* ========================= Misc ================================== */
+
+#define DOOR_X 27
+#define DOOR_Y 139
+
+
+extern void room_204_init();
+extern void room_204_daemon();
+extern void room_204_pre_parser();
+extern void room_204_parser();
+extern void room_204_preload();
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index 1df5898671e..7265eedaf1c 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -141,6 +141,7 @@ MODULE_OBJS += \
madsv2/phantom/rooms/room201.o \
madsv2/phantom/rooms/room202.o \
madsv2/phantom/rooms/room203.o \
+ madsv2/phantom/rooms/room204.o \
madsv2/phantom/phantom.o \
madsv2/phantom/conv.o \
madsv2/phantom/main_menu.o \
Commit: 702dd37cbd784986557b624ba8dea02ca06eea19
https://github.com/scummvm/scummvm/commit/702dd37cbd784986557b624ba8dea02ca06eea19
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:44+10:00
Commit Message:
MADS: PHANTOM: Added room 205
Changed paths:
A engines/mads/madsv2/phantom/rooms/room205.cpp
A engines/mads/madsv2/phantom/rooms/room205.h
engines/mads/madsv2/phantom/conv.h
engines/mads/madsv2/phantom/global.h
engines/mads/madsv2/phantom/mads/sounds.h
engines/mads/madsv2/phantom/mads/text.h
engines/mads/madsv2/phantom/mads/words.h
engines/mads/module.mk
diff --git a/engines/mads/madsv2/phantom/conv.h b/engines/mads/madsv2/phantom/conv.h
index 8d1863d66d3..0f2e55edef3 100644
--- a/engines/mads/madsv2/phantom/conv.h
+++ b/engines/mads/madsv2/phantom/conv.h
@@ -154,6 +154,38 @@ enum {
conv009_wink_abc = 12
};
+enum {
+ conv010_hasthem_abc = 4,
+ conv010_noyoudont_abc = 5,
+ conv010_unlock_b_box_5 = 7,
+ conv010_gethem_abc = 8,
+ conv010_beginning_who = 9,
+ conv010_beginning_you = 10,
+ conv010_beginning_pardon = 11,
+ conv010_nomore_abc = 13,
+ conv010_byebye_first = 14,
+ conv010_dialogue_three = 16,
+ conv010_dialogue_one = 17,
+ conv010_ghost_byebye = 19,
+ conv010_trance_b_box_5 = 21,
+ conv010_box_b_b = 23,
+ conv010_box_d_d = 25,
+ conv010_box_byebye = 40,
+ conv010_ghost_interest = 45,
+ conv010_bye_two_solong = 46
+};
+
+enum {
+ conv011_has_b_ticket = 5,
+ conv011_has_abc = 6,
+ conv011_enter_b_a = 8,
+ conv011_hasnot_abc = 9,
+ conv011_boxoffice_abc = 10,
+ conv011_enter_it_abc = 12,
+ conv011_enjoy_abc = 13,
+ conv011_five_nono = 14
+};
+
enum {
conv012_hello_one = 1,
conv012_hello_four = 4,
@@ -207,6 +239,12 @@ enum {
conv017_hasnot_first = 4
};
+enum {
+ conv018_begin_first = 0,
+ conv018_adieu_bye = 4,
+ conv018_nomore_huh = 5
+};
+
enum {
conv022_second_next = 1,
conv022_resolution_florent = 6,
diff --git a/engines/mads/madsv2/phantom/global.h b/engines/mads/madsv2/phantom/global.h
index 933bd5fb711..4eda02ac578 100644
--- a/engines/mads/madsv2/phantom/global.h
+++ b/engines/mads/madsv2/phantom/global.h
@@ -199,6 +199,7 @@ enum {
#define SCORE_DEAD_FLORENT 4
// ticket_people_here
+#define NEITHER 0
#define SELLER 1
#define USHER_AND_SELLER 2
@@ -231,6 +232,17 @@ enum {
#define CHRIS_KICKED_YES -1
#define CAME_INTO_EMPTY_113 3
+// madame_giry_loc
+#define LEFT 0
+#define MIDDLE 1
+#define RIGHT 2
+
+// doors_in_205
+#define BOTH_LOCKED 0
+#define LEFT_OPEN 1
+#define RIGHT_OPEN 2
+#define BOTH_OPEN 3
+
} // namespace Phantom
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/mads/sounds.h b/engines/mads/madsv2/phantom/mads/sounds.h
index 28c43900bac..5a2f8c58f1b 100644
--- a/engines/mads/madsv2/phantom/mads/sounds.h
+++ b/engines/mads/madsv2/phantom/mads/sounds.h
@@ -43,6 +43,7 @@ enum {
N_PlayerFalls = 67,
N_EchoSteps = 68,
N_SandbagThud = 70,
+ N_DoorHandle002 = 72,
N_DoorHandle = 73
};
diff --git a/engines/mads/madsv2/phantom/mads/text.h b/engines/mads/madsv2/phantom/mads/text.h
index 9fd72eba477..a77c998be37 100644
--- a/engines/mads/madsv2/phantom/mads/text.h
+++ b/engines/mads/madsv2/phantom/mads/text.h
@@ -549,7 +549,30 @@ enum {
text_204_34 = 20434,
/* text_204_35 not used */
text_204_36 = 20436,
- text_204_37 = 20437
+ text_204_37 = 20437,
+
+ /* Room 205 â Box corridor */
+ text_205_10 = 20510,
+ text_205_11 = 20511,
+ text_205_12 = 20512,
+ text_205_13 = 20513,
+ text_205_14 = 20514,
+ text_205_15 = 20515,
+ text_205_16 = 20516,
+ text_205_17 = 20517,
+ text_205_18 = 20518,
+ text_205_19 = 20519,
+ text_205_20 = 20520,
+ text_205_21 = 20521,
+ text_205_22 = 20522,
+ text_205_23 = 20523,
+ text_205_24 = 20524,
+ text_205_25 = 20525,
+ text_205_26 = 20526,
+ text_205_27 = 20527,
+ text_205_28 = 20528,
+ text_205_29 = 20529,
+ text_205_30 = 20530
};
} // namespace Phantom
diff --git a/engines/mads/madsv2/phantom/mads/words.h b/engines/mads/madsv2/phantom/mads/words.h
index 7cfb7ffa13e..e3eb9984a5d 100644
--- a/engines/mads/madsv2/phantom/mads/words.h
+++ b/engines/mads/madsv2/phantom/mads/words.h
@@ -39,6 +39,7 @@ enum {
words_book = 24,
words_bust = 25,
words_cable = 26,
+ words_carpet = 27,
words_carton = 28,
words_cartons = 29,
words_ceiling = 30,
@@ -195,6 +196,13 @@ enum {
words_end_table = 231,
words_coffee_table = 232,
words_decorative_vase = 233,
+ words_marble_column = 234,
+ words_box_five = 235,
+ words_enter = 236,
+ words_box_six = 237,
+ words_box_seven = 238,
+ words_box_eight = 239,
+ words_box_nine = 240,
words_light = 245,
words_candle = 246,
words_prop_case = 247,
@@ -219,8 +227,11 @@ enum {
words_Monsieur_Richard = 302,
words_Julie = 303,
words_cable_hook = 304,
+ words_Madame_Giry = 323,
words_ticket_seller = 329,
words_usher = 330,
+ words_box_ten = 336,
+ words_walk_down_stairs_to = 339,
words_hat_rack = 340,
words_vase = 341,
words_clothes_dummy = 342,
diff --git a/engines/mads/madsv2/phantom/rooms/room205.cpp b/engines/mads/madsv2/phantom/rooms/room205.cpp
new file mode 100644
index 00000000000..5cce1d2e55b
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room205.cpp
@@ -0,0 +1,1799 @@
+/* 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 "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/imath.h"
+#include "mads/madsv2/core/text.h"
+#include "mads/madsv2/core/inter.h"
+#include "mads/madsv2/core/object.h"
+#include "mads/madsv2/core/rail.h"
+#include "mads/madsv2/core/sound.h"
+#include "mads/madsv2/core/speech.h"
+#include "mads/madsv2/core/quote.h"
+#include "mads/madsv2/core/matte.h"
+#include "mads/madsv2/core/buffer.h"
+#include "mads/madsv2/phantom/global.h"
+#include "mads/madsv2/phantom/conv.h"
+#include "mads/madsv2/phantom/mads/inventory.h"
+#include "mads/madsv2/phantom/mads/quotes.h"
+#include "mads/madsv2/phantom/mads/sounds.h"
+#include "mads/madsv2/phantom/mads/speeches.h"
+#include "mads/madsv2/phantom/mads/text.h"
+#include "mads/madsv2/phantom/mads/words.h"
+#include "mads/madsv2/phantom/rooms/section2.h"
+#include "mads/madsv2/phantom/rooms/room205.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+static void handle_animation_rich() {
+ int random;
+ int rich_reset_frame;
+
+ if (kernel_anim[aa[0]].frame != local->rich_frame) {
+ local->rich_frame = kernel_anim[aa[0]].frame;
+ rich_reset_frame = -1;
+
+ switch (local->rich_frame) {
+ case 1: /* end of talk 1 & freeze & left & right & up */
+ case 2: /* end of talk 2 */
+ case 3: /* end of talk 3 */
+ case 19: /* end of point */
+ case 11: /* end of both arms up */
+ case 69: /* end of return from both go */
+ case 57: /* end of return from collar */
+ case 47: /* end of return from chin */
+ case 35: /* end of return from hips */
+
+ switch (local->rich_action) {
+ case CONV18_RICH_POINT:
+ random = 4; /* point */
+ local->rich_action = CONV18_RICH_TALK;
+ break;
+
+ case CONV18_RICH_BOTH_ARMS_UP:
+ random = 5; /* both arms up like 'what the hell' */
+ local->rich_action = CONV18_RICH_TALK;
+ break;
+
+ case CONV18_RICH_BOTH_GO:
+ random = 6; /* put both arms up like 'get going, man' */
+ break;
+
+ case CONV18_RICH_TALK:
+ random = imath_random(1, 3);
+ ++local->rich_talk_count;
+ if (local->rich_talk_count > 30) {
+ local->rich_action = CONV18_RICH_SHUT_UP;
+ random = 9;
+ }
+ break;
+
+ default: /* CONV18_RICH_SHUT_UP */
+ random = imath_random(7, 50);
+ while (local->just_did_option == random) {
+ random = imath_random(7, 50);
+ } /* so we don't repeat the same option twice */
+ local->just_did_option = random;
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ rich_reset_frame = 0;
+ break; /* do talk 1 */
+
+ case 2:
+ rich_reset_frame = 1;
+ break; /* do talk 2 */
+
+ case 3:
+ rich_reset_frame = 2;
+ break; /* do talk 3 */
+
+ case 4:
+ rich_reset_frame = 11;
+ break; /* point */
+
+ case 5:
+ rich_reset_frame = 3;
+ break; /* both arms up 'what the hell' */
+
+ case 6:
+ rich_reset_frame = 57;
+ break; /* both arms up 'get going' */
+
+ case 7:
+ rich_reset_frame = 23;
+ break; /* look up (new node) */
+
+ case 8:
+ rich_reset_frame = 19;
+ break; /* look left (new node) */
+
+ case 9:
+ rich_reset_frame = 21;
+ break; /* look right (new node) */
+
+ case 10:
+ rich_reset_frame = 25;
+ break; /* put hands on hips (new node) */
+
+ case 11:
+ rich_reset_frame = 35;
+ break; /* put hands on chin (new node) */
+
+ case 12:
+ rich_reset_frame = 47;
+ break; /* put hands on collar (new node) */
+
+ default:
+ rich_reset_frame = 0;
+ break; /* freeze standing still */
+ }
+ break;
+
+ case 30: /* put hands on hips */
+
+ switch (local->rich_action) {
+ case CONV18_RICH_POINT:
+ case CONV18_RICH_BOTH_GO:
+ case CONV18_RICH_BOTH_ARMS_UP:
+ case CONV18_RICH_TALK:
+ random = 1; /* go to freeze standing still (new node) */
+ break;
+
+ default:
+ random = imath_random(1, 50);
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ rich_reset_frame = 30;
+ break; /* goto hands by side (new node) */
+
+ default:
+ rich_reset_frame = 29;
+ break; /* hands on hips */
+ }
+ break;
+
+ case 24: /* look up */
+
+ switch (local->rich_action) {
+ case CONV18_RICH_POINT:
+ case CONV18_RICH_BOTH_GO:
+ case CONV18_RICH_BOTH_ARMS_UP:
+ case CONV18_RICH_TALK:
+ random = 1; /* go to freeze standing still (new node) */
+ break;
+
+ default:
+ random = imath_random(1, 30);
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ rich_reset_frame = 0;
+ break; /* goto hands by side (new node) */
+
+ default:
+ rich_reset_frame = 23;
+ break; /* look up */
+ }
+ break;
+
+ case 20: /* look left */
+
+ switch (local->rich_action) {
+ case CONV18_RICH_POINT:
+ case CONV18_RICH_BOTH_GO:
+ case CONV18_RICH_BOTH_ARMS_UP:
+ case CONV18_RICH_TALK:
+ random = 1; /* go to freeze standing still (new node) */
+ break;
+
+ default:
+ random = imath_random(1, 50);
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ rich_reset_frame = 0;
+ break; /* goto hands by side (new node) */
+
+ default:
+ rich_reset_frame = 19;
+ break; /* look left */
+ }
+ break;
+
+ case 22: /* look right */
+
+ switch (local->rich_action) {
+ case CONV18_RICH_POINT:
+ case CONV18_RICH_BOTH_GO:
+ case CONV18_RICH_BOTH_ARMS_UP:
+ case CONV18_RICH_TALK:
+ random = 1; /* go to freeze standing still (new node) */
+ break;
+
+ default:
+ random = imath_random(1, 50);
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ rich_reset_frame = 0;
+ break; /* goto hands by side (new node) */
+
+ default:
+ rich_reset_frame = 21;
+ break; /* look right */
+ }
+ break;
+
+ case 41: /* put hands on chin */
+
+ switch (local->rich_action) {
+ case CONV18_RICH_POINT:
+ case CONV18_RICH_BOTH_GO:
+ case CONV18_RICH_BOTH_ARMS_UP:
+ case CONV18_RICH_TALK:
+ random = 1; /* go to freeze standing still (new node) */
+ break;
+
+ default:
+ random = imath_random(1, 50);
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ rich_reset_frame = 41;
+ break; /* goto hands by side (new node) */
+
+ default:
+ rich_reset_frame = 40;
+ break; /* hands on chin */
+ }
+ break;
+
+ case 52: /* put hands on collar */
+
+ switch (local->rich_action) {
+ case CONV18_RICH_POINT:
+ case CONV18_RICH_BOTH_GO:
+ case CONV18_RICH_BOTH_ARMS_UP:
+ case CONV18_RICH_TALK:
+ random = 1; /* go to freeze standing still (new node) */
+ break;
+
+ default:
+ random = imath_random(1, 50);
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ rich_reset_frame = 52;
+ break; /* goto hands by side (new node) */
+
+ default:
+ rich_reset_frame = 51;
+ break; /* hands on collar */
+ }
+ break;
+
+ case 65: /* both hands up in air (get going, man) */
+
+ switch (local->rich_action) {
+ case CONV18_RICH_POINT:
+ case CONV18_RICH_BOTH_GO:
+ case CONV18_RICH_BOTH_ARMS_UP:
+ case CONV18_RICH_TALK:
+ random = 1; /* go to freeze standing still (new node) */
+ break;
+
+ default:
+ random = imath_random(1, 50);
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ rich_reset_frame = 65;
+ break; /* goto hands by side (new node) */
+
+ default:
+ rich_reset_frame = 64;
+ break; /* keep hands up in air */
+ }
+ break;
+ }
+
+ if (rich_reset_frame >= 0) {
+ kernel_reset_animation(aa[0], rich_reset_frame);
+ local->rich_frame = rich_reset_frame;
+ }
+ }
+}
+
+static void handle_animation_giry() {
+ int random;
+ int giry_reset_frame;
+
+ if (kernel_anim[aa[1]].frame != local->giry_frame) {
+ local->giry_frame = kernel_anim[aa[1]].frame;
+ giry_reset_frame = -1;
+
+ switch (local->giry_frame) {
+ case 77: /* almost end of trance */
+ conv_release();
+ break;
+
+ case 1: /* end of talk 1 & freeze */
+ case 2: /* end of talk 2 */
+ case 3: /* end of talk 3 */
+ case 44: /* end of touch head */
+ case 14: /* end of both arms up */
+ case 21: /* end of nod */
+ case 35: /* end of point and talk */
+ case 56: /* end of welcome */
+ case 78: /* end of trance */
+ case 284: /* end of take */
+
+ switch (local->giry_action) {
+ case CONV10_GIRY_TALK:
+ random = imath_random(1, 3);
+ ++local->giry_talk_count;
+ if (local->giry_talk_count > 30) {
+ local->giry_action = CONV10_GIRY_SHUT_UP;
+ random = 100;
+ }
+ break;
+
+ case CONV10_GIRY_HANDS_UP:
+ random = 4; /* hands up */
+ local->giry_action = CONV10_GIRY_TALK;
+ break;
+
+ case CONV10_GIRY_NOD:
+ random = 5; /* nod */
+ local->giry_action = CONV10_GIRY_TALK;
+ break;
+
+ case CONV10_GIRY_POINT_TALK:
+ random = 6; /* point and talk */
+ break;
+
+ case CONV10_GIRY_WELCOME:
+ local->giry_action = CONV10_GIRY_TALK;
+ random = 7; /* give a welcome */
+ break;
+
+ case CONV10_GIRY_TRANCE:
+ random = 8; /* go into a trance state */
+ break;
+
+ case CONV10_GIRY_LEFT_DOOR:
+ random = 9; /* open left door (new node) */
+ local->giry_action = CONV10_GIRY_SHUT_UP;
+ break;
+
+ case CONV10_GIRY_RIGHT_DOOR:
+ random = 10; /* open right door (new node) */
+ local->giry_action = CONV10_GIRY_SHUT_UP;
+ break;
+
+ case CONV11_GIRY_TAKE:
+ random = 11; /* take ticket */
+ break;
+
+ default: /* CONV10_GIRY_SHUT_UP */
+ random = imath_random(12, 100);
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ giry_reset_frame = 0;
+ break; /* do talk 1 */
+
+ case 2:
+ giry_reset_frame = 1;
+ break; /* do talk 2 */
+
+ case 3:
+ giry_reset_frame = 2;
+ break; /* do talk 3 */
+
+ case 4:
+ giry_reset_frame = 3;
+ break; /* put both hands up (new node) */
+
+ case 5:
+ giry_reset_frame = 16;
+ break; /* nod */
+
+ case 6:
+ giry_reset_frame = 21;
+ break; /* point and talk (new node) */
+
+ case 7:
+ giry_reset_frame = 44;
+ break; /* give a welcome */
+
+ case 8:
+ giry_reset_frame = 56;
+ break; /* go into a trance (new node) */
+
+ case 9:
+ giry_reset_frame = 78;
+ conv_hold();
+ break; /* open left door (new node) */
+
+ case 10:
+ giry_reset_frame = 140;
+ break; /* open right door (new node) */
+
+ case 11:
+ giry_reset_frame = 276;
+ break; /* take ticket (new node) */
+
+ case 12:
+ giry_reset_frame = 35;
+ break; /* touch head */
+
+ default:
+ giry_reset_frame = 0;
+ break; /* freeze standing still */
+ }
+ break;
+
+ case 27: /* end of point and talk 1 and freeze */
+ case 28: /* end of point and talk 2 */
+ case 29: /* end of point and talk 3 */
+
+ switch (local->giry_action) {
+ case CONV10_GIRY_TALK:
+ case CONV11_GIRY_TAKE:
+ case CONV10_GIRY_SHUT_UP:
+ case CONV10_GIRY_NOD:
+ case CONV10_GIRY_TRANCE:
+ case CONV10_GIRY_WELCOME:
+ case CONV10_GIRY_LEFT_DOOR:
+ case CONV10_GIRY_RIGHT_DOOR:
+ case CONV10_GIRY_HANDS_UP:
+ random = 4; /* go to freeze standing still (new node) */
+ break;
+
+ default:
+ random = imath_random(1, 3);
+ ++local->giry_talk_count;
+ if (local->giry_talk_count > 30) {
+ local->giry_action = CONV10_GIRY_SHUT_UP;
+ random = 100;
+ }
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ giry_reset_frame = 26;
+ break; /* point and talk 1 */
+
+ case 2:
+ giry_reset_frame = 27;
+ break; /* point and talk 2 */
+
+ case 3:
+ giry_reset_frame = 28;
+ break; /* point and talk 3 */
+
+ default:
+ giry_reset_frame = 29;
+ break; /* hands by side */
+ }
+ break;
+
+ case 265: /* almost end of unlock box 9 */
+ kernel_flip_hotspot_loc(words_Madame_Giry, true, HS_MADAME_X_R_1, HS_MADAME_Y_R_1);
+ kernel_flip_hotspot_loc(words_Madame_Giry, true, HS_MADAME_X_R_2, HS_MADAME_Y_R_2);
+ conv_release();
+ break;
+
+ case 274: /* end of talk 1 by box 9 and freeze */
+ case 275: /* end of talk 2 by box 9 */
+ case 276: /* end of talk 3 by box 9 */
+
+ switch (local->giry_action) {
+ case CONV10_GIRY_TALK:
+ random = imath_random(1, 3);
+ ++local->giry_talk_count;
+ if (local->giry_talk_count > 30) {
+ local->giry_action = CONV10_GIRY_SHUT_UP;
+ random = 100;
+ }
+ break;
+
+ default:
+ random = 100; /* go to freeze standing by right door */
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ giry_reset_frame = 273;
+ break; /* talk by right door 1 */
+
+ case 2:
+ giry_reset_frame = 274;
+ break; /* talk by right door 2 */
+
+ case 3:
+ giry_reset_frame = 275;
+ break; /* talk by right door 3 */
+
+ default:
+ giry_reset_frame = 273;
+ break; /* freeze standing by right door */
+ }
+ break;
+
+ case 85: /* just starting to walk to left door */
+ conv_release();
+ break;
+
+ case 110: /* almost end of unlock box 5 */
+ kernel_flip_hotspot_loc(words_Madame_Giry, true, HS_MADAME_X_L_1, HS_MADAME_Y_L_1);
+ kernel_flip_hotspot_loc(words_Madame_Giry, true, HS_MADAME_X_L_2, HS_MADAME_Y_L_2);
+ break;
+
+ case 138: /* end of talk 1 by box 5 and freeze */
+ case 139: /* end of talk 2 by box 5 */
+ case 140: /* end of talk 3 by box 5 */
+
+ switch (local->giry_action) {
+ case CONV10_GIRY_TALK:
+ case CONV10_GIRY_POINT_TALK:
+ random = imath_random(1, 3);
+ ++local->giry_talk_count;
+ if (local->giry_talk_count > 30) {
+ local->giry_action = CONV10_GIRY_SHUT_UP;
+ random = 100;
+ }
+ break;
+
+ default:
+ random = 100; /* go to freeze standing by left door */
+ break;
+ }
+
+ switch (random) {
+ case 1:
+ giry_reset_frame = 137;
+ break; /* talk by left door 1 */
+
+ case 2:
+ giry_reset_frame = 138;
+ break; /* talk by left door 2 */
+
+ case 3:
+ giry_reset_frame = 139;
+ break; /* talk by left door 3 */
+
+ default:
+ giry_reset_frame = 137;
+ break; /* freeze standing by left door */
+ }
+ break;
+
+ case 66: /* almost at end of getting to trance */
+ conv_release();
+ break;
+
+ case 67: /* end of trance and freeze */
+
+ switch (local->giry_action) {
+ case CONV10_GIRY_TALK:
+ case CONV11_GIRY_TAKE:
+ case CONV10_GIRY_SHUT_UP:
+ case CONV10_GIRY_NOD:
+ case CONV10_GIRY_WELCOME:
+ case CONV10_GIRY_LEFT_DOOR:
+ case CONV10_GIRY_RIGHT_DOOR:
+ case CONV10_GIRY_HANDS_UP:
+ random = 1; /* go to freeze standing still (new node) */
+ break;
+
+ default:
+ random = 100;
+ break; /* stay in trance */
+ }
+
+ switch (random) {
+ case 1:
+ giry_reset_frame = 67;
+ break; /* goto hands by side (new node) */
+
+ default:
+ giry_reset_frame = 66;
+ break; /* stay in trance */
+ }
+ break;
+
+ case 8: /* end of both hands up */
+ case 9: /* end of freeze */
+
+ switch (local->giry_action) {
+ case CONV10_GIRY_TALK:
+ case CONV11_GIRY_TAKE:
+ case CONV10_GIRY_SHUT_UP:
+ case CONV10_GIRY_NOD:
+ case CONV10_GIRY_TRANCE:
+ case CONV10_GIRY_WELCOME:
+ case CONV10_GIRY_LEFT_DOOR:
+ case CONV10_GIRY_RIGHT_DOOR:
+ case CONV10_GIRY_HANDS_UP:
+ random = 1; /* go to freeze standing still (new node) */
+ break;
+
+ default:
+ random = 100;
+ break; /* keep both hands up */
+ }
+
+ switch (random) {
+ case 1:
+ giry_reset_frame = 9;
+ break; /* goto hands by side (new node) */
+
+ default:
+ giry_reset_frame = 8;
+ break; /* keep both hands up */
+ }
+ break;
+
+ case 280: /* hand almost fully extended for taking ticket */
+ local->give_ticket = true;
+ break;
+
+ case 281: /* hand extended for taking ticket */
+
+ switch (local->giry_action) {
+ case CONV10_GIRY_TALK:
+ case CONV10_GIRY_SHUT_UP:
+ case CONV10_GIRY_NOD:
+ case CONV10_GIRY_TRANCE:
+ case CONV10_GIRY_WELCOME:
+ case CONV10_GIRY_LEFT_DOOR:
+ case CONV10_GIRY_RIGHT_DOOR:
+ case CONV10_GIRY_HANDS_UP:
+ random = 1; /* go to freeze standing still (new node) */
+ break;
+
+ default:
+ random = 100;
+ break; /* keep hand up */
+ }
+
+ switch (random) {
+ case 1:
+ giry_reset_frame = 281;
+ break; /* goto hands by side (new node) */
+
+ default:
+ giry_reset_frame = 280;
+ break; /* keep hand up */
+ }
+ break;
+ }
+
+ if (giry_reset_frame >= 0) {
+ kernel_reset_animation(aa[1], giry_reset_frame);
+ local->giry_frame = giry_reset_frame;
+ }
+ }
+}
+
+void room_205_daemon() {
+ if (local->anim_0_running) {
+ handle_animation_rich();
+ }
+
+ if (local->anim_1_running) {
+ handle_animation_giry();
+ }
+
+ if ((global[walker_converse] == CONVERSE_HAND_WAVE) ||
+ (global[walker_converse] == CONVERSE_HAND_WAVE_2)) {
+ ++local->converse_counter;
+ if (local->converse_counter > 200) {
+ global[walker_converse] = imath_random(CONVERSE_LEAN, CONVERSE_HAND_CHIN);
+ }
+ }
+
+ if (local->give_ticket && !player_said_1(give)) {
+ global[walker_converse] = CONVERSE_NONE;
+ player_walk(player.x + 5, player.y - 10, FACING_NORTHWEST);
+ player_walk_trigger(ROOM_205_TAKE_TICKET);
+ local->give_ticket = false;
+ }
+
+ switch (kernel.trigger) {
+ case ROOM_205_TAKE_TICKET:
+ player.walker_visible = false;
+ seq[fx_take_9] = kernel_seq_pingpong(ss[fx_take_9], true, 5, 0, 0, 2);
+ kernel_seq_range(seq[fx_take_9], KERNEL_FIRST, KERNEL_LAST);
+ kernel_seq_player(seq[fx_take_9], true);
+ kernel_seq_trigger(seq[fx_take_9], KERNEL_TRIGGER_EXPIRE, 0, ROOM_205_TAKE_TICKET + 2);
+ kernel_seq_trigger(seq[fx_take_9], KERNEL_TRIGGER_SPRITE, 4, ROOM_205_TAKE_TICKET + 1);
+ break;
+
+ case ROOM_205_TAKE_TICKET + 1:
+ inter_move_object(ticket, NOWHERE);
+ local->giry_action = CONV10_GIRY_SHUT_UP;
+ break;
+
+ case ROOM_205_TAKE_TICKET + 2:
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_SERIES, seq[fx_take_9]);
+ player.walker_visible = true;
+ player.commands_allowed = true;
+ conv_release();
+ break;
+ }
+
+
+ /* Complete left door closing */
+
+ switch (kernel.trigger) {
+ case ROOM_205_LEFT_DOOR_CLOSES:
+ kernel_seq_delete(seq[fx_left_door]);
+ seq[fx_left_door] = kernel_seq_backward(ss[fx_left_door], false, 8, 0, 0, 1);
+ kernel_seq_depth(seq[fx_left_door], 14);
+ kernel_seq_range(seq[fx_left_door], KERNEL_FIRST, KERNEL_LAST);
+ kernel_seq_trigger(seq[fx_left_door],
+ KERNEL_TRIGGER_EXPIRE, 0, ROOM_205_LEFT_DOOR_CLOSES + 1);
+ break;
+
+ case ROOM_205_LEFT_DOOR_CLOSES + 1:
+ seq[fx_left_door] = kernel_seq_stamp(ss[fx_left_door], false, KERNEL_FIRST);
+ kernel_seq_depth(seq[fx_left_door], 14);
+ sound_play(N_DoorCloses);
+ player.commands_allowed = true;
+ break;
+
+ case ROOM_205_RIGHT_DOOR_CLOSES:
+ kernel_seq_delete(seq[fx_right_door]);
+ seq[fx_right_door] = kernel_seq_backward(ss[fx_right_door], false, 8, 0, 0, 1);
+ kernel_seq_depth(seq[fx_right_door], 14);
+ kernel_seq_range(seq[fx_right_door], KERNEL_FIRST, KERNEL_LAST);
+ kernel_seq_trigger(seq[fx_right_door],
+ KERNEL_TRIGGER_EXPIRE, 0, ROOM_205_RIGHT_DOOR_CLOSES + 1);
+ break;
+
+ case ROOM_205_RIGHT_DOOR_CLOSES + 1:
+ seq[fx_right_door] = kernel_seq_stamp(ss[fx_right_door], false, KERNEL_FIRST);
+ kernel_seq_depth(seq[fx_right_door], 14);
+ sound_play(N_DoorCloses);
+ player.commands_allowed = true;
+ break;
+ }
+}
+
+static void process_conversation_18() {
+ int you_trig_flag = false;
+ int me_trig_flag = false;
+
+ switch (player_verb) {
+ case conv018_begin_first:
+ global[walker_converse] = imath_random(CONVERSE_LEAN, CONVERSE_HAND_CHIN);
+ local->rich_action = CONV18_RICH_TALK;
+ break;
+
+ case conv018_adieu_bye:
+ case conv018_nomore_huh:
+ conv_me_trigger(ROOM_205_END);
+ global[ran_conv_in_205] = true;
+ me_trig_flag = true;
+ you_trig_flag = true;
+ break;
+
+ default:
+ break;
+ }
+
+ switch (kernel.trigger) {
+ case ROOM_205_END:
+ global[walker_converse] = CONVERSE_NONE;
+ me_trig_flag = true;
+ you_trig_flag = true;
+ break;
+
+ case ROOM_205_RICHARD_TALK:
+ global[walker_converse] = imath_random(CONVERSE_LEAN, CONVERSE_HAND_CHIN);
+ local->rich_action = CONV18_RICH_TALK;
+ break;
+
+ case ROOM_205_ME_TALK:
+ global[walker_converse] = imath_random(CONVERSE_HAND_WAVE, CONVERSE_HAND_WAVE_2);
+ local->rich_action = CONV18_RICH_SHUT_UP;
+ local->converse_counter = 0;
+ break;
+
+ default:
+ break;
+ }
+
+
+ /* Set up me and you triggers */
+
+ if (!me_trig_flag) {
+ conv_me_trigger(ROOM_205_ME_TALK);
+ } /* if me_trig_flag == true, then a me trigger is called from above, not here. */
+
+ if (!you_trig_flag) {
+ conv_you_trigger(ROOM_205_RICHARD_TALK);
+ } /* if you_trig_flag == true, then a you trigger is called from above, not here. */
+
+ local->rich_talk_count = 0;
+}
+
+static void process_conversation_10() {
+ int you_trig_flag = false;
+ int me_trig_flag = false;
+
+ switch (player_verb) {
+ case conv010_beginning_who:
+ conv_you_trigger(ROOM_205_WELCOME);
+ you_trig_flag = true;
+ global[madame_name_is_known] = YES;
+ kernel_flip_hotspot(words_woman, false);
+ kernel_flip_hotspot_loc(words_Madame_Giry, true, HS_MADAME_X_M_1, HS_MADAME_Y_M_1);
+ kernel_flip_hotspot_loc(words_Madame_Giry, true, HS_MADAME_X_M_2, HS_MADAME_Y_M_2);
+ break;
+
+ case conv010_beginning_you:
+ global[madame_name_is_known] = YES;
+ kernel_flip_hotspot(words_woman, false);
+ kernel_flip_hotspot_loc(words_Madame_Giry, true, HS_MADAME_X_M_1, HS_MADAME_Y_M_1);
+ kernel_flip_hotspot_loc(words_Madame_Giry, true, HS_MADAME_X_M_2, HS_MADAME_Y_M_2);
+ break;
+
+ case conv010_unlock_b_box_5:
+ if (!kernel.trigger) {
+ local->giry_action = CONV10_GIRY_LEFT_DOOR;
+ global[madame_name_is_known] = YES_AND_END_CONV;
+ global[madame_giry_loc] = LEFT;
+ kernel_load_variant(2);
+ rail_disconnect_node(6);
+ rail_disconnect_node(7);
+ rail_disconnect_node(8);
+ rail_disconnect_node(9);
+ /* these rail nodes are only needed if Richard is in this room (after kidnapping) */
+ kernel_flip_hotspot_loc(words_Madame_Giry, false, HS_MADAME_X_M_1, HS_MADAME_Y_M_1);
+ kernel_flip_hotspot_loc(words_Madame_Giry, false, HS_MADAME_X_M_2, HS_MADAME_Y_M_2);
+ you_trig_flag = true;
+ me_trig_flag = true;
+ if (global[doors_in_205] == BOTH_LOCKED) {
+ global[doors_in_205] = LEFT_OPEN;
+ } else if (global[doors_in_205] == RIGHT_OPEN) {
+ global[doors_in_205] = BOTH_OPEN;
+ }
+ }
+ break;
+
+ case conv010_nomore_abc:
+ case conv010_ghost_interest:
+ conv_you_trigger(ROOM_205_POINT_TALK);
+ you_trig_flag = true;
+ break;
+
+ case conv010_trance_b_box_5:
+ if ((!kernel.trigger) && (!local->no_hold)) {
+ conv_hold();
+ local->giry_action = CONV10_GIRY_TRANCE;
+ } else {
+ local->no_hold = false;
+ }
+ break;
+
+ case conv010_dialogue_one:
+ conv_you_trigger(ROOM_205_NOD);
+ you_trig_flag = true;
+ break;
+
+ case conv010_beginning_pardon:
+ if (!kernel.trigger) {
+ conv_you_trigger(ROOM_205_BOTH_HANDS_UP);
+ }
+ me_trig_flag = true;
+ you_trig_flag = true;
+ break;
+
+ case conv010_box_b_b:
+ case conv010_box_d_d:
+ if ((!kernel.trigger) && (local->giry_action == CONV10_GIRY_TRANCE)) {
+ conv_hold();
+ local->giry_action = CONV10_GIRY_TALK;
+ }
+ break;
+
+ case conv010_hasthem_abc:
+ case conv010_noyoudont_abc:
+ case conv010_gethem_abc:
+ case conv010_byebye_first:
+ case conv010_dialogue_three:
+ case conv010_ghost_byebye:
+ case conv010_box_byebye:
+ case conv010_bye_two_solong:
+ conv_you_trigger(ROOM_205_END);
+ you_trig_flag = true;
+ break;
+
+ default:
+ break;
+ }
+
+ switch (kernel.trigger) {
+ case ROOM_205_END:
+ switch (player_verb) {
+ case conv010_hasthem_abc:
+ case conv010_dialogue_three:
+ case conv010_box_byebye:
+ case conv010_ghost_byebye:
+ case conv010_byebye_first:
+ case conv010_bye_two_solong:
+ local->giry_action = CONV10_GIRY_TALK;
+ break;
+ }
+ global[walker_converse] = CONVERSE_NONE;
+ me_trig_flag = true;
+ you_trig_flag = true;
+ break;
+
+ case ROOM_205_WELCOME:
+ local->giry_action = CONV10_GIRY_WELCOME;
+ break;
+
+ case ROOM_205_BOTH_HANDS_UP:
+ local->giry_action = CONV10_GIRY_HANDS_UP;
+ global[walker_converse] = CONVERSE_NONE;
+ me_trig_flag = true;
+ you_trig_flag = true;
+ break;
+
+ case ROOM_205_NOD:
+ local->giry_action = CONV10_GIRY_NOD;
+ break;
+
+ case ROOM_205_POINT_TALK:
+ if (player_verb == conv010_nomore_abc) {
+ global[walker_converse] = CONVERSE_NONE;
+ me_trig_flag = true;
+ you_trig_flag = true;
+ }
+ local->giry_action = CONV10_GIRY_POINT_TALK;
+ break;
+
+ case ROOM_205_GIRY_TALK:
+ if (global[walker_converse] != CONVERSE_NONE) {
+ global[walker_converse] = imath_random(CONVERSE_LEAN, CONVERSE_HAND_CHIN);
+ }
+ if (local->giry_action != CONV10_GIRY_TRANCE &&
+ local->giry_action != CONV10_GIRY_LEFT_DOOR &&
+ local->giry_action != CONV10_GIRY_RIGHT_DOOR) {
+ local->giry_action = CONV10_GIRY_TALK;
+ }
+ break;
+
+ case ROOM_205_ME_TALK:
+ if (global[walker_converse] != CONVERSE_NONE) {
+ global[walker_converse] = imath_random(CONVERSE_HAND_WAVE, CONVERSE_HAND_WAVE_2);
+ }
+ if (local->giry_action != CONV10_GIRY_TRANCE &&
+ local->giry_action != CONV10_GIRY_LEFT_DOOR &&
+ local->giry_action != CONV10_GIRY_RIGHT_DOOR) {
+ local->giry_action = CONV10_GIRY_SHUT_UP;
+ }
+ local->converse_counter = 0;
+ break;
+ }
+
+
+ /* Set up me and you triggers */
+
+ if (!me_trig_flag) {
+ conv_me_trigger(ROOM_205_ME_TALK);
+ } /* if me_trig_flag == true, then a me trigger is called from above, not here. */
+
+ if (!you_trig_flag) {
+ conv_you_trigger(ROOM_205_GIRY_TALK);
+ } /* if you_trig_flag == true, then a you trigger is called from above, not here. */
+
+ local->giry_talk_count = 0;
+}
+
+static void process_conversation_11() {
+ int you_trig_flag = false;
+ int me_trig_flag = false;
+
+ switch (player_verb) {
+ case conv011_has_b_ticket:
+ if (!kernel.trigger) {
+ conv_hold();
+ local->giry_action = CONV11_GIRY_TAKE;
+ }
+ break;
+
+ case conv011_enter_b_a:
+ if (!kernel.trigger) {
+ conv_hold();
+ local->giry_action = CONV10_GIRY_RIGHT_DOOR;
+ conv_you_trigger(ROOM_205_END);
+ player_walk(225, 79, FACING_NORTHEAST);
+ you_trig_flag = true;
+ global[madame_giry_loc] = RIGHT;
+ kernel_load_variant(4);
+ rail_disconnect_node(6);
+ rail_disconnect_node(7);
+ rail_disconnect_node(8);
+ rail_disconnect_node(9);
+ /* these rail nodes are only needed if Richard is in this room (after kidnapping) */
+ kernel_flip_hotspot_loc(words_Madame_Giry, false, HS_MADAME_X_M_1, HS_MADAME_Y_M_1);
+ kernel_flip_hotspot_loc(words_Madame_Giry, false, HS_MADAME_X_M_2, HS_MADAME_Y_M_2);
+ if (global[doors_in_205] == BOTH_LOCKED) {
+ global[doors_in_205] = RIGHT_OPEN;
+ } else if (global[doors_in_205] == LEFT_OPEN) {
+ global[doors_in_205] = BOTH_OPEN;
+ }
+ }
+ break;
+
+ case conv011_hasnot_abc:
+ case conv011_boxoffice_abc:
+ case conv011_enter_it_abc:
+ case conv011_enjoy_abc:
+ case conv011_five_nono:
+ conv_you_trigger(ROOM_205_END);
+ you_trig_flag = true;
+ break;
+
+ default:
+ break;
+ }
+
+ switch (kernel.trigger) {
+ case ROOM_205_END:
+ switch (player_verb) {
+ case conv011_has_abc:
+ case conv011_hasnot_abc:
+ case conv011_enjoy_abc:
+ case conv011_boxoffice_abc:
+ case conv011_five_nono:
+ local->giry_action = CONV10_GIRY_TALK;
+ break;
+ }
+ global[walker_converse] = CONVERSE_NONE;
+ me_trig_flag = true;
+ you_trig_flag = true;
+ break;
+
+ case ROOM_205_WALK:
+ conv_hold();
+ local->giry_action = CONV10_GIRY_RIGHT_DOOR;
+ break;
+
+ case ROOM_205_GIRY_TALK:
+ if (global[walker_converse] != CONVERSE_NONE) {
+ global[walker_converse] = imath_random(CONVERSE_LEAN, CONVERSE_HAND_CHIN);
+ }
+ if (local->giry_action != CONV11_GIRY_TAKE) {
+ local->giry_action = CONV10_GIRY_TALK;
+ }
+ break;
+
+ case ROOM_205_ME_TALK:
+ if (global[walker_converse] != CONVERSE_NONE) {
+ global[walker_converse] = imath_random(CONVERSE_HAND_WAVE, CONVERSE_HAND_WAVE_2);
+ }
+ if (local->giry_action != CONV11_GIRY_TAKE) {
+ local->giry_action = CONV10_GIRY_SHUT_UP;
+ }
+ local->converse_counter = 0;
+ break;
+ }
+
+
+ /* Set up me and you triggers */
+
+ if (!me_trig_flag) {
+ conv_me_trigger(ROOM_205_ME_TALK);
+ } /* if me_trig_flag == true, then a me trigger is called from above, not here. */
+
+ if (!you_trig_flag) {
+ conv_you_trigger(ROOM_205_GIRY_TALK);
+ } /* if you_trig_flag == true, then a you trigger is called from above, not here. */
+
+ local->giry_talk_count = 0;
+}
+
+void room_205_pre_parser() {
+ if ((player_said_1(box_five)) && (player_said_1(lock) || player_said_1(unlock) || player_said_1(open))) {
+ player_walk(FRONT_5_X, FRONT_5_Y, FACING_NORTHEAST);
+ }
+
+ if ((player_said_1(box_six)) && (player_said_1(lock) || player_said_1(unlock) || player_said_1(open))) {
+ player_walk(FRONT_6_X, FRONT_6_Y, FACING_NORTHEAST);
+ }
+
+ if ((player_said_1(box_seven)) && (player_said_1(lock) || player_said_1(unlock) || player_said_1(open))) {
+ player_walk(FRONT_7_X, FRONT_7_Y, FACING_NORTHEAST);
+ }
+
+ if ((player_said_1(box_eight)) && (player_said_1(lock) || player_said_1(unlock) || player_said_1(open))) {
+ player_walk(FRONT_8_X, FRONT_8_Y, FACING_NORTHEAST);
+ }
+
+ if ((player_said_1(box_nine)) && (player_said_1(lock) || player_said_1(unlock) || player_said_1(open))) {
+ player_walk(FRONT_9_X, FRONT_9_Y, FACING_NORTHEAST);
+ }
+
+ if (player_said_2(walk_down_stairs_to, grand_foyer)) {
+ if ((global[doors_in_205] != RIGHT_OPEN) && (global[doors_in_205] != BOTH_OPEN)) {
+ player.walk_off_edge_to_room = 202;
+ global[madame_giry_loc] = MIDDLE;
+ }
+ }
+}
+
+void room_205_parser() {
+ int temp;
+ int frame_counter = 0;
+
+ if (conv_control.running == CONV_RICHARD_18) {
+ process_conversation_18();
+ goto handled;
+ }
+
+ if (conv_control.running == CONV_GIRY_10) {
+ process_conversation_10();
+ goto handled;
+ }
+
+ if (conv_control.running == CONV_GIRY_11) {
+ process_conversation_11();
+ goto handled;
+ }
+
+ if ((player_said_2(open, box_five)) || (player_said_2(enter, box_five))) {
+ if (global[ticket_people_here] == USHER_AND_SELLER) {
+ if (global[madame_giry_loc] == RIGHT) {
+ conv_run(CONV_GIRY_11);
+ conv_export_value(player_has(ticket));
+ conv_export_value(3);
+ conv_export_value(0);
+ /* it is reserved, put box on left */
+ goto handled;
+ } else {
+ conv_run(CONV_GIRY_11);
+ conv_export_value(player_has(ticket));
+ conv_export_value(4);
+ conv_export_value(0);
+ /* it is reserved, put box on right */
+ goto handled;
+ }
+ }
+ }
+
+ if (player_said_2(walk_down_stairs_to, grand_foyer)) {
+ if (global[ticket_people_here] == USHER_AND_SELLER) {
+ if (global[madame_giry_loc] == RIGHT) {
+ conv_run(CONV_GIRY_11);
+ conv_export_value(player_has(ticket));
+ conv_export_value(1);
+ conv_export_value(0);
+ /* performance is about to begin, put box on left */
+ } else {
+ conv_run(CONV_GIRY_11);
+ conv_export_value(player_has(ticket));
+ conv_export_value(2);
+ conv_export_value(0);
+ /* performance is about to begin, put box on right */
+ }
+ goto handled;
+ }
+ }
+
+ if ((player_said_1(enter)) || (player_said_1(open)) || player_said_1(unlock) || player_said_1(lock)) {
+ if (((player_said_1(box_five)) && ((global[doors_in_205] == BOTH_LOCKED) || (global[doors_in_205] == RIGHT_OPEN))
+ || player_said_1(unlock) || player_said_1(lock))
+ ||
+ ((player_said_1(box_nine)) && ((global[doors_in_205] == BOTH_LOCKED) || (global[doors_in_205] == LEFT_OPEN)))
+ ||
+ (player_said_1(box_six)) || (player_said_1(box_seven)) || (player_said_1(box_eight))) {
+ switch (kernel.trigger) {
+ case 0:
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_take_9] = kernel_seq_forward(ss[fx_take_9], false, 5, 0, 0, 1);
+ kernel_seq_range(seq[fx_take_9], 1, 4);
+ kernel_seq_player(seq[fx_take_9], true);
+ kernel_seq_trigger(seq[fx_take_9], KERNEL_TRIGGER_EXPIRE, 0, 1);
+ goto handled;
+ break;
+
+ case 1:
+ temp = seq[fx_take_9];
+ seq[fx_take_9] = kernel_seq_stamp(ss[fx_take_9], false, 4);
+ kernel_synch(KERNEL_SERIES, seq[fx_take_9], KERNEL_SERIES, temp);
+ kernel_seq_player(seq[fx_take_9], false);
+ sound_play(N_DoorHandle002);
+ kernel_timing_trigger(QUARTER_SECOND, 2);
+ goto handled;
+ break;
+
+ case 2:
+ kernel_seq_delete(seq[fx_take_9]);
+ seq[fx_take_9] = kernel_seq_backward(ss[fx_take_9], false, 5, 0, 0, 1);
+ kernel_seq_range(seq[fx_take_9], 1, 4);
+ kernel_seq_player(seq[fx_take_9], false);
+ kernel_seq_trigger(seq[fx_take_9], KERNEL_TRIGGER_EXPIRE, 0, 3);
+ goto handled;
+ break;
+
+ case 3:
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_SERIES, seq[fx_take_9]);
+ player.walker_visible = true;
+ player.commands_allowed = true;
+ if (player_said_1(unlock) || player_said_1(lock)) {
+ text_show(text_205_28);
+ /* the key does not work on this door */
+ } else {
+ text_show(text_205_27);
+ /* the door is locked */
+ }
+ goto handled;
+ break;
+ }
+
+ } else if (((player_said_1(box_five)) && ((global[doors_in_205] == BOTH_OPEN) || (global[doors_in_205] == LEFT_OPEN)))
+ ||
+ ((player_said_1(box_nine)) && ((global[doors_in_205] == BOTH_OPEN) || (global[doors_in_205] == RIGHT_OPEN)))) {
+ switch (kernel.trigger) {
+ case 0:
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_take_9] = kernel_seq_pingpong(ss[fx_take_9], false, 5, 0, 0, 2);
+ kernel_seq_range(seq[fx_take_9], KERNEL_FIRST, KERNEL_LAST);
+ kernel_seq_player(seq[fx_take_9], true);
+ kernel_seq_trigger(seq[fx_take_9],
+ KERNEL_TRIGGER_EXPIRE, 0, 2);
+ kernel_seq_trigger(seq[fx_take_9],
+ KERNEL_TRIGGER_SPRITE, 4, ROOM_205_DOOR_OPENS);
+ goto handled;
+ break;
+
+ case ROOM_205_DOOR_OPENS:
+ sound_play(N_DoorOpens);
+ if (player_said_1(box_five)) {
+ kernel_seq_delete(seq[fx_left_door]);
+ seq[fx_left_door] = kernel_seq_forward(ss[fx_left_door], false, 8, 0, 0, 1);
+ kernel_seq_depth(seq[fx_left_door], 14);
+ kernel_seq_range(seq[fx_left_door], KERNEL_FIRST, KERNEL_LAST);
+ kernel_seq_trigger(seq[fx_left_door],
+ KERNEL_TRIGGER_EXPIRE, 0, ROOM_205_DOOR_OPENS + 1);
+
+ } else if (player_said_1(box_nine)) {
+ kernel_seq_delete(seq[fx_right_door]);
+ seq[fx_right_door] = kernel_seq_forward(ss[fx_right_door], false, 8, 0, 0, 1);
+ kernel_seq_depth(seq[fx_right_door], 14);
+ kernel_seq_range(seq[fx_right_door], KERNEL_FIRST, KERNEL_LAST);
+ kernel_seq_trigger(seq[fx_right_door],
+ KERNEL_TRIGGER_EXPIRE, 0, ROOM_205_DOOR_OPENS + 1);
+ }
+ goto handled;
+ break;
+
+ case ROOM_205_DOOR_OPENS + 1:
+ if (player_said_1(box_five)) {
+ temp = seq[fx_left_door];
+ seq[fx_left_door] = kernel_seq_stamp(ss[fx_left_door], false, KERNEL_LAST);
+ kernel_synch(KERNEL_SERIES, seq[fx_left_door], KERNEL_SERIES, temp);
+ kernel_seq_depth(seq[fx_left_door], 14);
+
+ } else if (player_said_1(box_nine)) {
+ temp = seq[fx_right_door];
+ seq[fx_right_door] = kernel_seq_stamp(ss[fx_right_door], false, KERNEL_LAST);
+ kernel_synch(KERNEL_SERIES, seq[fx_right_door], KERNEL_SERIES, temp);
+ kernel_seq_depth(seq[fx_right_door], 14);
+ }
+ goto handled;
+ break;
+
+ case 2:
+ player.walker_visible = true;
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_SERIES, seq[fx_take_9]);
+ if (player_said_1(box_five)) {
+ player_walk(BEHIND_LEFT_X, BEHIND_LEFT_Y, FACING_NORTH);
+ player_walk_trigger(3);
+
+ } else if (player_said_1(box_nine)) {
+ player_walk(BEHIND_RIGHT_X, BEHIND_RIGHT_Y, FACING_NORTH);
+ player_walk_trigger(3);
+ }
+ goto handled;
+ break;
+
+ case 3:
+ if (player_said_1(box_five)) {
+ new_room = 206;
+ global[madame_giry_loc] = MIDDLE;
+
+ } else if (player_said_1(box_nine)) {
+ new_room = 207;
+ global[madame_giry_loc] = MIDDLE;
+ }
+ goto handled;
+ break;
+ }
+ }
+ }
+
+ if (player_said_2(talk_to, Monsieur_Richard)) {
+ conv_run(CONV_RICHARD_18);
+ goto handled;
+ }
+
+ if ((player_said_2(talk_to, Madame_Giry)) ||
+ (player_said_2(talk_to, woman)) ||
+ (player_said_3(give, ticket, Madame_Giry))) {
+ if (global[ticket_people_here] == USHER_AND_SELLER) {
+ if ((global[doors_in_205] == RIGHT_OPEN) || (global[doors_in_205] == BOTH_OPEN)) {
+ if (global[madame_giry_loc] == RIGHT) {
+ conv_run(CONV_GIRY_11);
+ conv_export_value(player_has(ticket));
+ conv_export_value(1);
+
+ if (player_said_1(give)) {
+ conv_export_value(1);
+ } else {
+ conv_export_value(0);
+ }
+
+ /* performance is about to begin, put box on left */
+ } else {
+ conv_run(CONV_GIRY_11);
+ conv_export_value(player_has(ticket));
+ conv_export_value(2);
+
+ if (player_said_1(give)) {
+ conv_export_value(1);
+ } else {
+ conv_export_value(0);
+ }
+
+ /* performance is about to begin, put box on right */
+ }
+ } else {
+ conv_run(CONV_GIRY_11);
+ conv_export_value(player_has(ticket));
+ conv_export_value(0);
+
+ if (player_said_1(give)) {
+ conv_export_value(1);
+ } else {
+ conv_export_value(0);
+ }
+ }
+ goto handled;
+
+ } else {
+
+ if (player_has(red_frame)) ++frame_counter;
+ if (player_has(green_frame)) ++frame_counter;
+ if (player_has(yellow_frame)) ++frame_counter;
+ if (player_has(blue_frame)) ++frame_counter;
+
+ conv_run(CONV_GIRY_10);
+ conv_export_pointer(&global[player_score]);
+ conv_export_value(game.difficulty);
+
+ if (frame_counter > 2) {
+ conv_export_value(1);
+ } else {
+ conv_export_value(0);
+ }
+
+ global[walker_converse] = imath_random(CONVERSE_LEAN, CONVERSE_HAND_CHIN);
+ goto handled;
+ }
+ }
+
+ if (player.look_around) {
+ text_show(text_205_10);
+ goto handled;
+ }
+
+ if (player_said_1(look) || player_said_1(look_at)) {
+
+ if (player_said_1(box_six)) {
+ text_show(text_205_11);
+ goto handled;
+ }
+
+ if (player_said_1(box_seven)) {
+ text_show(text_205_12);
+ goto handled;
+ }
+
+ if (player_said_1(box_eight)) {
+ text_show(text_205_13);
+ goto handled;
+ }
+
+ if (player_said_1(box_nine)) {
+ if ((global[doors_in_205] == BOTH_LOCKED) ||
+ (global[doors_in_205] == LEFT_OPEN)) {
+ text_show(text_205_16);
+ } else {
+ text_show(text_205_17);
+ }
+ goto handled;
+ }
+
+ if (player_said_1(box_five)) {
+ if ((global[doors_in_205] == BOTH_LOCKED) ||
+ (global[doors_in_205] == RIGHT_OPEN)) {
+ text_show(text_205_14);
+ } else {
+ text_show(text_205_15);
+ }
+ goto handled;
+ }
+
+ if (player_said_1(floor)) {
+ text_show(text_205_18);
+ goto handled;
+ }
+
+ if (player_said_1(marble_column)) {
+ text_show(text_205_19);
+ goto handled;
+ }
+
+ if (player_said_1(ceiling)) {
+ text_show(text_205_20);
+ goto handled;
+ }
+
+ if (player_said_1(wall)) {
+ text_show(text_205_21);
+ goto handled;
+ }
+
+ if (player_said_1(bust)) {
+ text_show(text_205_22);
+ goto handled;
+ }
+
+ if (player_said_1(carpet)) {
+ text_show(text_205_23);
+ goto handled;
+ }
+
+ if (player_said_1(grand_foyer)) {
+ text_show(text_205_24);
+ goto handled;
+ }
+
+ if ((player_said_1(woman)) ||
+ (player_said_1(Madame_Giry))) {
+ text_show(text_205_25);
+ goto handled;
+ }
+
+ if (player_said_1(Monsieur_Richard)) {
+ text_show(text_205_26);
+ goto handled;
+ }
+ }
+
+ if (player_said_2(talk_to, bust)) {
+ text_show(text_205_29);
+ goto handled;
+ }
+
+ if ((player_said_2(open, box_ten)) || (player_said_2(enter, box_ten)) ||
+ (player_said_2(look, box_ten))) {
+ text_show(text_205_13);
+ goto handled;
+ }
+
+ if (player_said_1(take)) {
+ if (player_said_1(woman) | player_said_1(Madame_Giry)) {
+ text_show(text_205_30);
+ goto handled;
+ }
+ }
+
+ goto done;
+
+handled:
+ player.command_ready = false;
+
+done:
+ ;
+}
+
+void room_205_init() {
+ int dynamic_giry; /* for dynamic HS's of Giry */
+ int frame_counter = 0;
+
+ kernel.disable_fastwalk = true;
+
+ if (global[jacques_status] != JACQUES_IS_DEAD) {
+ rail_disconnect_node(6);
+ rail_disconnect_node(7);
+ rail_disconnect_node(8);
+ rail_disconnect_node(9);
+ /* these rail nodes are only needed if Richard is in this room (after kidnapping) */
+ }
+
+ if (previous_room != KERNEL_RESTORING_GAME) {
+ local->just_did_option = false;
+ local->anim_0_running = false;
+ local->anim_1_running = false;
+ }
+
+ local->converse_counter = 0;
+ local->no_hold = false;
+ local->give_ticket = false;
+
+ /* Load sprite series */
+
+ ss[fx_left_door] = kernel_load_series(kernel_name('f', 0), false);
+ ss[fx_right_door] = kernel_load_series(kernel_name('f', 1), false);
+ ss[fx_take_9] = kernel_load_series("*RDR_9", false);
+
+
+ kernel_flip_hotspot(words_Monsieur_Richard, false);
+ kernel_flip_hotspot(words_Madame_Giry, false);
+ kernel_flip_hotspot(words_woman, false);
+
+ /* Load conversations */
+
+ conv_get(CONV_RICHARD_18);
+ conv_get(CONV_GIRY_10);
+ conv_get(CONV_GIRY_11);
+
+
+ if (global[current_year] == 1881) {
+ if ((global[madame_giry_shows_up]) && (global[jacques_status] == JACQUES_IS_ALIVE)) {
+ aa[1] = kernel_run_animation(kernel_name('g', 1), 1);
+ local->anim_1_running = true;
+ local->giry_action = CONV10_GIRY_SHUT_UP;
+
+ dynamic_giry = kernel_add_dynamic(words_Madame_Giry, words_walk_to, SYNTAX_SINGULAR_FEM, KERNEL_NONE,
+ 0, 0, 0, 0);
+ kernel_dynamic_hot[dynamic_giry].prep = PREP_ON;
+ kernel_dynamic_walk(dynamic_giry, DYN_GIRY_X_L, DYN_GIRY_Y_L, FACING_NORTHWEST);
+ kernel_dynamic_anim(dynamic_giry, aa[1], 1);
+ kernel_dynamic_anim(dynamic_giry, aa[1], 2);
+
+ switch (global[madame_giry_loc]) {
+ case LEFT:
+ kernel_reset_animation(aa[1], 138); /* freeze Giry by left door */
+ kernel_flip_hotspot_loc(words_Madame_Giry, true, HS_MADAME_X_L_1, HS_MADAME_Y_L_1);
+ kernel_flip_hotspot_loc(words_Madame_Giry, true, HS_MADAME_X_L_2, HS_MADAME_Y_L_2);
+ break;
+
+ case MIDDLE:
+ if (global[madame_name_is_known] >= YES) {
+ kernel_flip_hotspot_loc(words_Madame_Giry, true, HS_MADAME_X_M_1, HS_MADAME_Y_M_1);
+ kernel_flip_hotspot_loc(words_Madame_Giry, true, HS_MADAME_X_M_2, HS_MADAME_Y_M_2);
+
+ } else {
+ kernel_flip_hotspot(words_woman, true);
+ }
+ break;
+
+ case RIGHT:
+ kernel_reset_animation(aa[1], 273); /* freeze Giry by right door */
+ kernel_flip_hotspot_loc(words_Madame_Giry, true, HS_MADAME_X_R_1, HS_MADAME_Y_R_1);
+ kernel_flip_hotspot_loc(words_Madame_Giry, true, HS_MADAME_X_R_2, HS_MADAME_Y_R_2);
+ break;
+ }
+ }
+
+ if (previous_room == KERNEL_RESTORING_GAME) {
+ if (conv_restore_running == CONV_GIRY_10) {
+
+ if (player_has(red_frame)) ++frame_counter;
+ if (player_has(green_frame)) ++frame_counter;
+ if (player_has(yellow_frame)) ++frame_counter;
+ if (player_has(blue_frame)) ++frame_counter;
+
+ conv_run(CONV_GIRY_10);
+ conv_export_pointer(&global[player_score]);
+ conv_export_value(game.difficulty);
+
+ if (frame_counter > 2) {
+ conv_export_value(1);
+ } else {
+ conv_export_value(0);
+ }
+
+ global[walker_converse] = imath_random(CONVERSE_LEAN, CONVERSE_HAND_CHIN);
+ local->no_hold = true;
+
+ if (local->giry_action == CONV10_GIRY_TRANCE) {
+ kernel_reset_animation(aa[1], 66);
+ } else {
+ local->giry_action = CONV10_GIRY_SHUT_UP;
+ }
+
+ } else if (conv_restore_running == CONV_GIRY_11) {
+
+ conv_run(CONV_GIRY_11);
+ conv_export_value(player_has(ticket));
+ conv_export_value(0);
+ conv_export_value(0);
+
+ global[walker_converse] = imath_random(CONVERSE_LEAN, CONVERSE_HAND_CHIN);
+ }
+ }
+ }
+
+
+ if (previous_room == KERNEL_RESTORING_GAME) {
+
+ seq[fx_left_door] = kernel_seq_stamp(ss[fx_left_door], false, 1);
+ kernel_seq_depth(seq[fx_left_door], 14);
+
+ seq[fx_right_door] = kernel_seq_stamp(ss[fx_right_door], false, 1);
+ kernel_seq_depth(seq[fx_right_door], 14);
+
+ if (global[jacques_status] == JACQUES_IS_DEAD) {
+ aa[0] = kernel_run_animation(kernel_name('b', 9), 1);
+ local->anim_0_running = true;
+ local->rich_action = CONV18_RICH_SHUT_UP;
+ kernel_flip_hotspot(words_Monsieur_Richard, true);
+
+ if (conv_restore_running == CONV_RICHARD_18) {
+ global[walker_converse] = imath_random(CONVERSE_LEAN, CONVERSE_HAND_CHIN);
+ local->rich_action = CONV18_RICH_SHUT_UP;
+ conv_run(CONV_RICHARD_18);
+ kernel_reset_animation(aa[0], 1); /* shut Richard up */
+ }
+ }
+
+
+ /* Previous Rooms */
+
+ } else if (previous_room == 206) {
+ player.x = BEHIND_LEFT_X;
+ player.y = BEHIND_LEFT_Y;
+ player.facing = FACING_SOUTH;
+ player_walk(FRONT_5_X + 4, FRONT_5_Y, FACING_SOUTH);
+ player_walk_trigger(ROOM_205_LEFT_DOOR_CLOSES);
+ player.commands_allowed = false;
+ seq[fx_right_door] = kernel_seq_stamp(ss[fx_right_door], false, KERNEL_FIRST);
+ kernel_seq_depth(seq[fx_right_door], 14);
+ seq[fx_left_door] = kernel_seq_stamp(ss[fx_left_door], false, KERNEL_LAST);
+ kernel_seq_depth(seq[fx_left_door], 14);
+ if (global[jacques_status] == JACQUES_IS_DEAD) {
+ aa[0] = kernel_run_animation(kernel_name('b', 9), 1);
+ local->anim_0_running = true;
+ local->rich_action = CONV18_RICH_SHUT_UP;
+ kernel_flip_hotspot(words_Monsieur_Richard, true);
+ }
+
+ } else if (previous_room == 207) {
+ player.x = BEHIND_RIGHT_X;
+ player.y = BEHIND_RIGHT_Y;
+ player.facing = FACING_SOUTH;
+ player_walk(FRONT_9_X + 4, FRONT_9_Y, FACING_SOUTH);
+ player_walk_trigger(ROOM_205_RIGHT_DOOR_CLOSES);
+ player.commands_allowed = false;
+ seq[fx_right_door] = kernel_seq_stamp(ss[fx_right_door], false, KERNEL_LAST);
+ kernel_seq_depth(seq[fx_right_door], 14);
+ seq[fx_left_door] = kernel_seq_stamp(ss[fx_left_door], false, KERNEL_FIRST);
+ kernel_seq_depth(seq[fx_left_door], 14);
+
+ } else if (previous_room == 150) {
+ aa[0] = kernel_run_animation(kernel_name('b', 9), 1);
+ local->anim_0_running = true;
+ local->rich_action = CONV18_RICH_SHUT_UP;
+ player.x = BRIE_X;
+ player.y = BRIE_Y;
+ player.facing = FACING_NORTHWEST;
+ global[doors_in_205] = LEFT_OPEN;
+ global[ticket_people_here] = NEITHER;
+ global[walker_converse] = imath_random(CONVERSE_LEAN, CONVERSE_HAND_CHIN);
+ seq[fx_right_door] = kernel_seq_stamp(ss[fx_right_door], false, KERNEL_FIRST);
+ seq[fx_left_door] = kernel_seq_stamp(ss[fx_left_door], false, KERNEL_FIRST);
+ kernel_seq_depth(seq[fx_right_door], 14);
+ kernel_seq_depth(seq[fx_left_door], 14);
+ kernel_flip_hotspot(words_Monsieur_Richard, true);
+ conv_run(CONV_RICHARD_18);
+
+ } else if ((previous_room == 202) || (previous_room != KERNEL_RESTORING_GAME)) {
+
+ if (global[jacques_status] == JACQUES_IS_DEAD) {
+ aa[0] = kernel_run_animation(kernel_name('b', 9), 1);
+ local->anim_0_running = true;
+ local->rich_action = CONV18_RICH_SHUT_UP;
+ kernel_flip_hotspot(words_Monsieur_Richard, true);
+ }
+
+ seq[fx_left_door] = kernel_seq_stamp(ss[fx_left_door], false, 1);
+ kernel_seq_depth(seq[fx_left_door], 14);
+
+ seq[fx_right_door] = kernel_seq_stamp(ss[fx_right_door], false, 1);
+ kernel_seq_depth(seq[fx_right_door], 14);
+
+ player_first_walk(OFF_SCREEN_X_FROM_202, OFF_SCREEN_Y_FROM_202, FACING_EAST,
+ WALK_TO_X_FROM_202, WALK_TO_Y_FROM_202, FACING_NORTHEAST, true);
+ }
+
+ section_2_music();
+}
+
+void room_205_preload() {
+ room_init_code_pointer = room_205_init;
+ room_pre_parser_code_pointer = room_205_pre_parser;
+ room_parser_code_pointer = room_205_parser;
+ room_daemon_code_pointer = room_205_daemon;
+
+ section_2_walker();
+ section_2_interface();
+
+ if (global[current_year] == 1881) {
+ if (global[jacques_status] == JACQUES_IS_DEAD) {
+ kernel_initial_variant = 3;
+
+ } else if (global[jacques_status] == JACQUES_IS_ALIVE) {
+ switch (global[madame_giry_loc]) {
+ case LEFT:
+ kernel_initial_variant = 2;
+ break;
+
+ case MIDDLE:
+ kernel_initial_variant = 1;
+ break;
+ }
+ }
+ }
+}
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/rooms/room205.h b/engines/mads/madsv2/phantom/rooms/room205.h
new file mode 100644
index 00000000000..4ca89edf2d3
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room205.h
@@ -0,0 +1,193 @@
+/* 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 MADS_PHANTOM_ROOM205_H
+#define MADS_PHANTOM_ROOM205_H
+
+#include "mads/madsv2/phantom/rooms/section2.h"
+#include "mads/madsv2/phantom/global.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+#define local ((Scratch *)(&game.scratch[0]))
+#define ss local->sprite
+#define seq local->sequence
+#define aa local->animation
+
+typedef struct { /* Room local variables */
+
+ int16 sprite[15]; /* Sprite series handles */
+ int16 sequence[15]; /* Sequence handles */
+ int16 animation[4]; /* Animation handles */
+
+ int16 rich_frame;
+ int16 rich_action;
+ int16 rich_talk_count;
+
+ int16 giry_frame;
+ int16 giry_action;
+ int16 giry_talk_count;
+
+ int16 just_did_option;
+ int16 anim_0_running;
+ int16 anim_1_running;
+ int16 converse_counter;
+ int16 no_hold; /* if true, will not conv_hold in Parser */
+ int16 give_ticket; /* if true, will give ticket */
+
+} Scratch;
+
+
+/* ========================= Sprite Series ========================= */
+
+#define fx_left_door 0 /* rm203f0 */
+#define fx_right_door 1 /* rm203f1 */
+#define fx_take_9 2 /* *RDR_9 */
+
+
+/* ========================= Conversations ========================= */
+
+#define CONV_RICHARD_18 18
+#define CONV_GIRY_10 10
+#define CONV_GIRY_11 11
+
+/* Conv 18 â Richard action states */
+#define CONV18_RICH_TALK 0
+#define CONV18_RICH_POINT 1
+#define CONV18_RICH_BOTH_GO 2
+#define CONV18_RICH_SHUT_UP 3
+#define CONV18_RICH_BOTH_ARMS_UP 4
+
+/* Conv 10/11 â Giry action states */
+#define CONV10_GIRY_TALK 0
+#define CONV10_GIRY_POINT_TALK 1
+#define CONV10_GIRY_SHUT_UP 2
+#define CONV10_GIRY_NOD 3
+#define CONV10_GIRY_TRANCE 4
+#define CONV10_GIRY_WELCOME 5
+#define CONV10_GIRY_LEFT_DOOR 6
+#define CONV10_GIRY_RIGHT_DOOR 7
+#define CONV10_GIRY_HANDS_UP 8
+#define CONV11_GIRY_TAKE 9
+
+
+/* ========================= Triggers ============================== */
+
+#define ROOM_205_ME_TALK 60
+#define ROOM_205_RICHARD_TALK 62
+#define ROOM_205_END 64
+#define ROOM_205_GIRY_TALK 66
+#define ROOM_205_WELCOME 68
+#define ROOM_205_POINT_TALK 70
+#define ROOM_205_NOD 72
+#define ROOM_205_BOTH_HANDS_UP 74
+#define ROOM_205_DOOR_OPENS 80
+#define ROOM_205_LEFT_DOOR_CLOSES 90
+#define ROOM_205_RIGHT_DOOR_CLOSES 95
+#define ROOM_205_TAKE_TICKET 100
+#define ROOM_205_WALK 110
+
+
+/* ========================= Player positions ====================== */
+
+#define WALK_TO_X_FROM_202 19
+#define WALK_TO_Y_FROM_202 144
+#define OFF_SCREEN_X_FROM_202 -20
+#define OFF_SCREEN_Y_FROM_202 144
+
+#define PLAYER_X_FROM_206 36
+#define PLAYER_Y_FROM_206 68
+
+#define PLAYER_X_FROM_207 263
+#define PLAYER_Y_FROM_207 65
+
+#define BRIE_X 132
+#define BRIE_Y 112
+
+
+/* ========================= Box door walk positions =============== */
+
+#define FRONT_5_X 37
+#define FRONT_5_Y 67
+
+#define FRONT_6_X 80
+#define FRONT_6_Y 68
+
+#define FRONT_7_X 167
+#define FRONT_7_Y 65
+
+#define FRONT_8_X 212
+#define FRONT_8_Y 64
+
+#define FRONT_9_X 258
+#define FRONT_9_Y 63
+
+#define BEHIND_LEFT_X 37
+#define BEHIND_LEFT_Y 64
+
+#define BEHIND_RIGHT_X 263
+#define BEHIND_RIGHT_Y 59
+
+
+/* ========================= Dynamic Giry positions ================ */
+
+#define DYN_GIRY_X_R 257
+#define DYN_GIRY_Y_R 79
+#define DYN_GIRY_X_L 75
+#define DYN_GIRY_Y_L 84
+
+
+/* ========================= Madame Giry hotspot locations ========= */
+
+/* Left position (by box 5) */
+#define HS_MADAME_X_L_1 62
+#define HS_MADAME_Y_L_1 54
+#define HS_MADAME_X_L_2 62
+#define HS_MADAME_Y_L_2 66
+
+/* Middle position */
+#define HS_MADAME_X_M_1 113
+#define HS_MADAME_Y_M_1 44
+#define HS_MADAME_X_M_2 107
+#define HS_MADAME_Y_M_2 66
+
+/* Right position (by box 9) */
+#define HS_MADAME_X_R_1 283
+#define HS_MADAME_Y_R_1 51
+#define HS_MADAME_X_R_2 289
+#define HS_MADAME_Y_R_2 62
+
+
+extern void room_205_init();
+extern void room_205_daemon();
+extern void room_205_pre_parser();
+extern void room_205_parser();
+extern void room_205_preload();
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index 7265eedaf1c..47ef2f2a97a 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -142,6 +142,7 @@ MODULE_OBJS += \
madsv2/phantom/rooms/room202.o \
madsv2/phantom/rooms/room203.o \
madsv2/phantom/rooms/room204.o \
+ madsv2/phantom/rooms/room205.o \
madsv2/phantom/phantom.o \
madsv2/phantom/conv.o \
madsv2/phantom/main_menu.o \
Commit: 430e3c3382a103c6a10f17e161277f1e3793c50b
https://github.com/scummvm/scummvm/commit/430e3c3382a103c6a10f17e161277f1e3793c50b
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:45+10:00
Commit Message:
MADS: PHANTOM: Added room 206
Changed paths:
A engines/mads/madsv2/phantom/rooms/room206.cpp
A engines/mads/madsv2/phantom/rooms/room206.h
engines/mads/madsv2/phantom/global.h
engines/mads/madsv2/phantom/mads/inventory.h
engines/mads/madsv2/phantom/mads/sounds.h
engines/mads/madsv2/phantom/mads/text.h
engines/mads/madsv2/phantom/mads/words.h
engines/mads/module.mk
diff --git a/engines/mads/madsv2/phantom/global.h b/engines/mads/madsv2/phantom/global.h
index 4eda02ac578..c12f3059855 100644
--- a/engines/mads/madsv2/phantom/global.h
+++ b/engines/mads/madsv2/phantom/global.h
@@ -197,6 +197,7 @@ enum {
// player_score_flags
#define SCORE_TRAP_DOOR 1
#define SCORE_DEAD_FLORENT 4
+#define SCORE_HOLLOW_COLUMN 8
// ticket_people_here
#define NEITHER 0
@@ -243,6 +244,12 @@ enum {
#define RIGHT_OPEN 2
#define BOTH_OPEN 3
+// panel_in_206
+#define PANEL_UNDISCOVERED 0
+#define PANEL_DISCOVERED 1
+#define PANEL_LOCKED 2
+#define PANEL_UNLOCKED 3
+
} // namespace Phantom
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/mads/inventory.h b/engines/mads/madsv2/phantom/mads/inventory.h
index 74b3e865762..c0bfdb88f7c 100644
--- a/engines/mads/madsv2/phantom/mads/inventory.h
+++ b/engines/mads/madsv2/phantom/mads/inventory.h
@@ -43,6 +43,7 @@ enum {
letter = 13,
notice = 14,
book = 15,
+ crumpled_note = 16,
blue_frame = 17,
large_note = 18,
green_frame = 19,
diff --git a/engines/mads/madsv2/phantom/mads/sounds.h b/engines/mads/madsv2/phantom/mads/sounds.h
index 5a2f8c58f1b..6eb7c241fdb 100644
--- a/engines/mads/madsv2/phantom/mads/sounds.h
+++ b/engines/mads/madsv2/phantom/mads/sounds.h
@@ -43,6 +43,7 @@ enum {
N_PlayerFalls = 67,
N_EchoSteps = 68,
N_SandbagThud = 70,
+ N_KeyTurnSnd = 71,
N_DoorHandle002 = 72,
N_DoorHandle = 73
};
diff --git a/engines/mads/madsv2/phantom/mads/text.h b/engines/mads/madsv2/phantom/mads/text.h
index a77c998be37..0fe7aaf54f6 100644
--- a/engines/mads/madsv2/phantom/mads/text.h
+++ b/engines/mads/madsv2/phantom/mads/text.h
@@ -33,6 +33,7 @@ namespace Phantom {
enum {
text_008_06 = 806,
text_008_07 = 807,
+ text_008_16 = 816,
/* Room 101 */
text_101_10 = 10110,
@@ -572,7 +573,30 @@ enum {
text_205_27 = 20527,
text_205_28 = 20528,
text_205_29 = 20529,
- text_205_30 = 20530
+ text_205_30 = 20530,
+
+ /* Room 206 â Box 5 (left box) */
+ text_206_10 = 20610,
+ text_206_11 = 20611,
+ text_206_12 = 20612,
+ text_206_13 = 20613,
+ text_206_14 = 20614,
+ text_206_15 = 20615,
+ text_206_16 = 20616,
+ text_206_17 = 20617,
+ text_206_18 = 20618,
+ text_206_19 = 20619,
+ text_206_20 = 20620,
+ text_206_21 = 20621,
+ text_206_22 = 20622,
+ text_206_23 = 20623,
+ text_206_24 = 20624,
+ text_206_25 = 20625,
+ text_206_26 = 20626,
+ text_206_27 = 20627,
+ text_206_28 = 20628,
+ text_206_29 = 20629,
+ text_206_30 = 20630
};
} // namespace Phantom
diff --git a/engines/mads/madsv2/phantom/mads/words.h b/engines/mads/madsv2/phantom/mads/words.h
index e3eb9984a5d..29655cef49d 100644
--- a/engines/mads/madsv2/phantom/mads/words.h
+++ b/engines/mads/madsv2/phantom/mads/words.h
@@ -54,6 +54,7 @@ enum {
words_counterweight_system = 40,
words_crate = 41,
words_crates = 42,
+ words_crumpled_note = 43,
words_cyclorama = 44,
words_cylinder = 45,
words_door = 46,
@@ -179,6 +180,12 @@ enum {
words_placard = 203,
words_ticket_window = 204,
words_archway = 205,
+ words_rail = 207,
+ words_seat = 208,
+ words_loge_corridor = 209,
+ words_house_light = 210,
+ words_left_column = 212,
+ words_right_column = 213,
words_bookcase = 214,
words_doorway = 215,
words_comfy_chair = 216,
@@ -203,6 +210,8 @@ enum {
words_box_seven = 238,
words_box_eight = 239,
words_box_nine = 240,
+ words_panel = 242,
+ words_walk_behind = 243,
words_light = 245,
words_candle = 246,
words_prop_case = 247,
@@ -212,6 +221,7 @@ enum {
words_door_chunks = 250,
words_bulletin_board = 252,
words_glass_case = 254,
+ words_keyhole = 255,
words_middle_door = 256,
words_dressing_gown = 257,
words_Monsieur_Brie = 258,
diff --git a/engines/mads/madsv2/phantom/rooms/room206.cpp b/engines/mads/madsv2/phantom/rooms/room206.cpp
new file mode 100644
index 00000000000..045358c16dc
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room206.cpp
@@ -0,0 +1,560 @@
+/* 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 "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/imath.h"
+#include "mads/madsv2/core/text.h"
+#include "mads/madsv2/core/inter.h"
+#include "mads/madsv2/core/object.h"
+#include "mads/madsv2/core/rail.h"
+#include "mads/madsv2/core/sound.h"
+#include "mads/madsv2/core/speech.h"
+#include "mads/madsv2/core/quote.h"
+#include "mads/madsv2/core/matte.h"
+#include "mads/madsv2/core/buffer.h"
+#include "mads/madsv2/phantom/global.h"
+#include "mads/madsv2/phantom/conv.h"
+#include "mads/madsv2/phantom/mads/inventory.h"
+#include "mads/madsv2/phantom/mads/quotes.h"
+#include "mads/madsv2/phantom/mads/sounds.h"
+#include "mads/madsv2/phantom/mads/speeches.h"
+#include "mads/madsv2/phantom/mads/text.h"
+#include "mads/madsv2/phantom/mads/words.h"
+#include "mads/madsv2/phantom/rooms/section2.h"
+#include "mads/madsv2/phantom/rooms/room206.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+void room_206_daemon() {
+ switch (kernel.trigger) {
+ case ROOM_206_FROM_308:
+ sound_play(N_DoorOpens);
+ seq[fx_panel_closes] = kernel_seq_stamp(ss[fx_panel_closes], false, 1);
+ kernel_seq_depth(seq[fx_panel_closes], 14);
+ seq[fx_panel_opens] = kernel_seq_backward(ss[fx_panel_opens], false, 8, 0, 0, 1);
+ kernel_seq_depth(seq[fx_panel_opens], 13);
+ kernel_seq_range(seq[fx_panel_opens], KERNEL_FIRST, KERNEL_LAST);
+ kernel_seq_trigger(seq[fx_panel_opens],
+ KERNEL_TRIGGER_EXPIRE, 0, ROOM_206_FROM_308 + 1);
+ break;
+
+ case ROOM_206_FROM_308 + 1:
+ seq[fx_panel_appears] = kernel_seq_stamp(ss[fx_panel_appears], false, 3);
+ kernel_seq_depth(seq[fx_panel_appears], 13);
+ player.commands_allowed = true;
+ break;
+
+ case ROOM_206_HIT_ON_HEAD:
+ player.x = HIT_HEAD_X;
+ player.y = HIT_HEAD_Y;
+ player.walker_visible = true;
+ player.commands_allowed = true;
+ local->anim_0_running = false;
+ player_demand_facing(FACING_WEST);
+ break;
+ }
+
+ if (local->anim_0_running && !local->prevent) {
+ if (kernel_anim[aa[0]].frame == 118) {
+ global[knocked_over_head] = true;
+ local->prevent = true;
+ kernel_timing_trigger(1, ROOM_206_FROM_308 + 2);
+ }
+ }
+
+ if (local->anim_0_running && !local->prevent_2) {
+ if (kernel_anim[aa[0]].frame == 61) {
+ if (global_prefer_roland) {
+ sound_play(N_WomanScream002);
+ } else {
+ global_speech_go(speech_woman_scream);
+ }
+ local->prevent_2 = true;
+ }
+ }
+
+ switch (kernel.trigger) {
+ case ROOM_206_FROM_308 + 2:
+ sound_play(N_DoorOpens);
+ seq[fx_panel_closes] = kernel_seq_stamp(ss[fx_panel_closes], false, 1);
+ kernel_seq_depth(seq[fx_panel_closes], 14);
+ seq[fx_panel_opens] = kernel_seq_backward(ss[fx_panel_opens], false, 8, 0, 0, 1);
+ kernel_seq_depth(seq[fx_panel_opens], 13);
+ kernel_seq_range(seq[fx_panel_opens], KERNEL_FIRST, KERNEL_LAST);
+ kernel_seq_trigger(seq[fx_panel_opens],
+ KERNEL_TRIGGER_EXPIRE, 0, ROOM_206_FROM_308 + 3);
+ break;
+
+ case ROOM_206_FROM_308 + 3:
+ seq[fx_panel_appears] = kernel_seq_stamp(ss[fx_panel_appears], false, 3);
+ kernel_seq_depth(seq[fx_panel_appears], 13);
+ break;
+ }
+}
+
+void room_206_pre_parser() {
+ if (player_said_2(look, left_column)) {
+ player.need_to_walk = true;
+ }
+
+ if (player_said_2(unlock, panel) || player_said_2(walk_behind, panel) ||
+ player_said_2(lock, panel) || player_said_2(open, panel)) {
+ player_walk(PANEL_X, PANEL_Y, FACING_NORTHWEST);
+ }
+
+ if (player_said_1(left_column)) {
+ if (global[panel_in_206] == PANEL_UNDISCOVERED) {
+ player_walk(PANEL_X - 5, PANEL_Y, FACING_NORTHWEST);
+ }
+ }
+}
+
+void room_206_parser() {
+ int temp;
+
+ if (player_said_2(exit_to, loge_corridor)) {
+ if (global[right_door_is_open_504]) {
+ if (global_prefer_roland) {
+ sound_play(N_WomanScream002);
+ } else {
+ global_speech_go(speech_woman_scream);
+ }
+ conv_run(CONV_MISC);
+ conv_export_value(4);
+ } else {
+ new_room = 205;
+ }
+ goto handled;
+ }
+
+ if (player_said_2(take, crumpled_note) &&
+ (object_is_here(crumpled_note) || kernel.trigger)) {
+ switch (kernel.trigger) {
+ case 0:
+ global[player_score] += 5;
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_take_9] = kernel_seq_pingpong(ss[fx_take_9], false, 5, 0, 0, 2);
+ kernel_seq_range(seq[fx_take_9], KERNEL_FIRST, KERNEL_LAST);
+ kernel_seq_player(seq[fx_take_9], true);
+ kernel_seq_trigger(seq[fx_take_9],
+ KERNEL_TRIGGER_SPRITE, 4, ROOM_206_TAKE_NOTE);
+ kernel_seq_trigger(seq[fx_take_9],
+ KERNEL_TRIGGER_EXPIRE, 0, ROOM_206_TAKE_NOTE + 1);
+ goto handled;
+ break;
+
+ case ROOM_206_TAKE_NOTE:
+ kernel_seq_delete(seq[fx_note]);
+ kernel_flip_hotspot(words_crumpled_note, false);
+ inter_give_to_player(crumpled_note);
+ sound_play(N_TakeObjectSnd);
+ goto handled;
+ break;
+
+ case ROOM_206_TAKE_NOTE + 1:
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_SERIES, seq[fx_take_9]);
+ player.walker_visible = true;
+ kernel_timing_trigger(20, ROOM_206_TAKE_NOTE + 2);
+ goto handled;
+ break;
+
+ case ROOM_206_TAKE_NOTE + 2:
+ object_examine(crumpled_note, text_008_16, 6);
+ /* You pick up the crumpled note */
+ player.commands_allowed = true;
+ goto handled;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (player_said_2(walk_behind, panel) || player_said_2(open, panel) ||
+ ((kernel.trigger >= ROOM_206_ENTER_PANEL) && (kernel.trigger < ROOM_206_TAKE_NOTE))) {
+ if (global[panel_in_206] == PANEL_UNLOCKED) {
+ switch (kernel.trigger) {
+ case 0:
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_take_9] = kernel_seq_pingpong(ss[fx_take_9], true, 7, 0, 0, 2);
+ kernel_seq_range(seq[fx_take_9], 1, 3);
+ kernel_seq_player(seq[fx_take_9], true);
+ kernel_seq_trigger(seq[fx_take_9],
+ KERNEL_TRIGGER_SPRITE, 3, ROOM_206_ENTER_PANEL);
+ kernel_seq_trigger(seq[fx_take_9],
+ KERNEL_TRIGGER_EXPIRE, 0, ROOM_206_ENTER_PANEL + 1);
+ break;
+
+ case ROOM_206_ENTER_PANEL:
+ sound_play(N_DoorOpens);
+ kernel_seq_delete(seq[fx_panel_appears]);
+ seq[fx_panel_opens] = kernel_seq_forward(ss[fx_panel_opens], false, 8, 0, 0, 1);
+ kernel_seq_depth(seq[fx_panel_opens], 13);
+ kernel_seq_range(seq[fx_panel_opens], KERNEL_FIRST, KERNEL_LAST);
+ break;
+
+ case ROOM_206_ENTER_PANEL + 1:
+ seq[fx_panel_opens] = kernel_seq_stamp(ss[fx_panel_opens], false, KERNEL_LAST);
+ kernel_seq_depth(seq[fx_panel_opens], 14);
+ player.commands_allowed = true;
+ player.walker_visible = true;
+ player_walk(BEHIND_PANEL_X, BEHIND_PANEL_Y, FACING_NORTHWEST);
+ player_walk_trigger(ROOM_206_ENTER_PANEL + 2);
+ break;
+
+ case ROOM_206_ENTER_PANEL + 2:
+ sound_play(N_DoorOpens);
+ kernel_seq_delete(seq[fx_panel_opens]);
+ seq[fx_panel_opens] = kernel_seq_backward(ss[fx_panel_opens], false, 8, 0, 0, 1);
+ kernel_seq_depth(seq[fx_panel_opens], 13);
+ kernel_seq_range(seq[fx_panel_opens], KERNEL_FIRST, KERNEL_LAST);
+ kernel_seq_trigger(seq[fx_panel_opens],
+ KERNEL_TRIGGER_EXPIRE, 0, ROOM_206_ENTER_PANEL + 3);
+ break;
+
+ case ROOM_206_ENTER_PANEL + 3:
+ seq[fx_panel_appears] = kernel_seq_stamp(ss[fx_panel_appears], false, KERNEL_LAST);
+ kernel_seq_depth(seq[fx_panel_appears], 14);
+ new_room = 308;
+ break;
+ }
+
+ } else {
+ switch (kernel.trigger) {
+ case 0:
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_take_9] = kernel_seq_pingpong(ss[fx_take_9], true, 7, 0, 0, 2);
+ kernel_seq_range(seq[fx_take_9], 1, 3);
+ kernel_seq_player(seq[fx_take_9], true);
+ kernel_seq_trigger(seq[fx_take_9],
+ KERNEL_TRIGGER_EXPIRE, 0, ROOM_206_ENTER_PANEL + 4);
+ kernel_seq_trigger(seq[fx_take_9],
+ KERNEL_TRIGGER_SPRITE, 3, ROOM_206_ENTER_PANEL + 5);
+ break;
+
+ case ROOM_206_ENTER_PANEL + 5:
+ sound_play(N_DoorHandle002);
+ break;
+
+ case ROOM_206_ENTER_PANEL + 4:
+ player.commands_allowed = true;
+ player.walker_visible = true;
+ text_show(text_206_25);
+ /* the panel is locked */
+ break;
+ }
+ }
+ goto handled;
+ }
+
+ if (player_said_2(unlock, panel) || player_said_2(lock, panel) || player_said_3(put, key, keyhole) ||
+ player_said_2(unlock, keyhole) || player_said_2(lock, keyhole) ||
+ (kernel.trigger >= ROOM_206_SCREW_WITH_PANEL)) {
+ if (global[panel_in_206] >= PANEL_DISCOVERED) {
+ switch (kernel.trigger) {
+ case 0:
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_take_9] = kernel_seq_forward(ss[fx_take_9], true, 7, 0, 0, 1);
+ kernel_seq_range(seq[fx_take_9], 1, 3);
+ kernel_seq_player(seq[fx_take_9], true);
+ kernel_seq_trigger(seq[fx_take_9],
+ KERNEL_TRIGGER_EXPIRE, 0, ROOM_206_SCREW_WITH_PANEL);
+ break;
+
+ case ROOM_206_SCREW_WITH_PANEL:
+ sound_play(N_KeyTurnSnd);
+ temp = seq[fx_take_9];
+ seq[fx_take_9] = kernel_seq_stamp(ss[fx_take_9], true, KERNEL_LAST);
+ kernel_synch(KERNEL_SERIES, seq[fx_take_9], KERNEL_SERIES, temp);
+ kernel_seq_player(seq[fx_take_9], false);
+ kernel_timing_trigger(HALF_SECOND, ROOM_206_SCREW_WITH_PANEL + 1);
+ break;
+
+ case ROOM_206_SCREW_WITH_PANEL + 1:
+ kernel_seq_delete(seq[fx_take_9]);
+ seq[fx_take_9] = kernel_seq_backward(ss[fx_take_9], true, 7, 0, 0, 1);
+ kernel_seq_range(seq[fx_take_9], 1, 3);
+ kernel_seq_player(seq[fx_take_9], false);
+ kernel_seq_trigger(seq[fx_take_9],
+ KERNEL_TRIGGER_EXPIRE, 0, ROOM_206_SCREW_WITH_PANEL + 2);
+ break;
+
+ case ROOM_206_SCREW_WITH_PANEL + 2:
+ if (player_said_1(lock)) {
+ global[panel_in_206] = PANEL_LOCKED;
+ text_show(text_206_29);
+ } else if (player_said_1(unlock)) {
+ global[panel_in_206] = PANEL_UNLOCKED;
+ text_show(text_206_28);
+ }
+
+ if (player_said_1(put)) {
+ if (global[panel_in_206] <= PANEL_LOCKED) {
+ global[panel_in_206] = PANEL_UNLOCKED;
+ text_show(text_206_28);
+ } else {
+ global[panel_in_206] = PANEL_LOCKED;
+ text_show(text_206_29);
+ }
+ }
+
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_SERIES, seq[fx_take_9]);
+ player.commands_allowed = true;
+ player.walker_visible = true;
+ break;
+ }
+ goto handled;
+ }
+ }
+
+ if (player.look_around) {
+ text_show(text_206_10);
+ goto handled;
+ }
+
+ if (player_said_1(look) || player_said_1(look_at)) {
+
+ if (player_said_1(wall)) {
+ text_show(text_206_11);
+ goto handled;
+ }
+
+ if (player_said_1(floor)) {
+ text_show(text_206_12);
+ goto handled;
+ }
+
+ if (player_said_1(right_column)) {
+ text_show(text_206_14);
+ goto handled;
+ }
+
+ if (player_said_1(keyhole)) {
+ text_show(text_206_15);
+ goto handled;
+ }
+
+ if (player_said_1(rail)) {
+ text_show(text_206_16);
+ goto handled;
+ }
+
+ if (player_said_1(seat)) {
+ text_show(text_206_17);
+ goto handled;
+ }
+
+ if (player_said_1(loge_corridor)) {
+ text_show(text_206_18);
+ goto handled;
+ }
+
+ if (player_said_1(stage)) {
+ if (global[jacques_status]) {
+ text_show(text_206_30);
+ } else {
+ text_show(text_206_19);
+ }
+ goto handled;
+ }
+
+ if (player_said_1(house)) {
+ text_show(text_206_20);
+ goto handled;
+ }
+
+ if (player_said_1(ceiling)) {
+ text_show(text_206_21);
+ goto handled;
+ }
+
+ if (player_said_1(house_light)) {
+ text_show(text_206_22);
+ goto handled;
+ }
+
+ if (player_said_1(panel)) {
+ if (global[panel_in_206] == PANEL_UNLOCKED) {
+ text_show(text_206_24);
+ } else {
+ text_show(text_206_26);
+ }
+ goto handled;
+ }
+
+ if ((player_said_1(left_column)) && (!kernel.trigger)) {
+ if (global[panel_in_206] == PANEL_UNDISCOVERED) {
+ text_show(text_206_13);
+ aa[0] = kernel_run_animation(kernel_name('k', 1), ROOM_206_KNOCK);
+ player.commands_allowed = false;
+ player.walker_visible = false;
+
+ } else {
+ text_show(text_206_23);
+ }
+ goto handled;
+ }
+
+ if (player_said_1(crumpled_note) && object_is_here(crumpled_note)) {
+ text_show(text_206_27);
+ goto handled;
+ }
+ }
+
+ switch (kernel.trigger) {
+ case ROOM_206_KNOCK:
+ player.walker_visible = true;
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_ANIM, aa[0]);
+ kernel_flip_hotspot(words_panel, true);
+ kernel_flip_hotspot(words_keyhole, true);
+ seq[fx_panel_appears] = kernel_seq_stamp(ss[fx_panel_appears], false, 3);
+ kernel_seq_depth(seq[fx_panel_appears], 13);
+ if (!(global[player_score_flags] & SCORE_HOLLOW_COLUMN)) {
+ global[player_score_flags] = global[player_score_flags] | SCORE_HOLLOW_COLUMN;
+ global[player_score] += 5;
+ }
+ kernel_timing_trigger(QUARTER_SECOND, ROOM_206_KNOCK + 1); /* a slight delay so anim totally ends */
+ goto handled;
+ break;
+
+ case ROOM_206_KNOCK + 1:
+ player.commands_allowed = true;
+ global[panel_in_206] = PANEL_DISCOVERED;
+ text_show(text_206_23);
+ goto handled;
+ break;
+ }
+
+ goto done;
+
+handled:
+ player.command_ready = false;
+
+done:
+ ;
+}
+
+void room_206_init() {
+ local->anim_0_running = false;
+ local->prevent = false;
+ local->prevent_2 = false;
+
+ global_speech_load(speech_woman_scream);
+
+ conv_get(CONV_MISC);
+
+ /* Load sprites */
+
+ ss[fx_trap_door] = kernel_load_series(kernel_name('x', 0), false);
+ ss[fx_panel_closes] = kernel_load_series(kernel_name('x', 1), false);
+ ss[fx_panel_appears] = kernel_load_series(kernel_name('x', 2), false);
+ ss[fx_panel_opens] = kernel_load_series(kernel_name('x', 3), false);
+ ss[fx_take_9] = kernel_load_series("*RDR_9", false);
+
+
+ /* Do knocked on panel stuff */
+
+ if (previous_room != 308) {
+ switch (global[panel_in_206]) {
+ case PANEL_UNDISCOVERED:
+ seq[fx_panel_closes] = kernel_seq_stamp(ss[fx_panel_closes], false, 1);
+ kernel_seq_depth(seq[fx_panel_closes], 14);
+ break;
+
+ default:
+ seq[fx_panel_closes] = kernel_seq_stamp(ss[fx_panel_closes], false, 1);
+ kernel_seq_depth(seq[fx_panel_closes], 14);
+ seq[fx_panel_appears] = kernel_seq_stamp(ss[fx_panel_appears], false, 3);
+ kernel_seq_depth(seq[fx_panel_appears], 13);
+ break;
+ }
+ }
+
+ if (global[panel_in_206] == PANEL_UNDISCOVERED) {
+ kernel_flip_hotspot(words_panel, false);
+ kernel_flip_hotspot(words_keyhole, false);
+ }
+
+
+ if (object_is_here(crumpled_note)) {
+ ss[fx_note] = kernel_load_series(kernel_name('p', 0), false);
+ seq[fx_note] = kernel_seq_stamp(ss[fx_note], false, 1);
+ kernel_seq_depth(seq[fx_note], 10);
+
+ } else {
+ kernel_flip_hotspot(words_crumpled_note, false);
+ }
+
+
+ /* If trap door is open, stamp it */
+
+ if (global[trap_door_status] == TRAP_DOOR_IS_OPEN) {
+ seq[fx_trap_door] = kernel_seq_stamp(ss[fx_trap_door], false, 1);
+ kernel_seq_depth(seq[fx_trap_door], 14);
+ }
+
+
+ /* Previous Rooms */
+
+ if (global[right_door_is_open_504] && !global[knocked_over_head]) {
+ aa[0] = kernel_run_animation(kernel_name('h', 1), ROOM_206_HIT_ON_HEAD);
+ player.walker_visible = false;
+ player.commands_allowed = false;
+ local->anim_0_running = true;
+
+ } else if (previous_room == 308) {
+ player.x = BEHIND_PANEL_X;
+ player.y = BEHIND_PANEL_Y;
+ player.commands_allowed = false;
+ player_walk(PANEL_X, PANEL_Y, FACING_EAST);
+ player_walk_trigger(ROOM_206_FROM_308);
+
+ } else if ((previous_room == 205) || (previous_room != KERNEL_RESTORING_GAME)) {
+ player.x = PLAYER_X_FROM_205;
+ player.y = PLAYER_Y_FROM_205;
+ player.facing = FACING_NORTH;
+ }
+
+ section_2_music();
+}
+
+void room_206_preload() {
+ room_init_code_pointer = room_206_init;
+ room_pre_parser_code_pointer = room_206_pre_parser;
+ room_parser_code_pointer = room_206_parser;
+ room_daemon_code_pointer = room_206_daemon;
+
+ section_2_walker();
+ section_2_interface();
+}
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/rooms/room206.h b/engines/mads/madsv2/phantom/rooms/room206.h
new file mode 100644
index 00000000000..b953eb56bf0
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room206.h
@@ -0,0 +1,98 @@
+/* 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 MADS_PHANTOM_ROOM206_H
+#define MADS_PHANTOM_ROOM206_H
+
+#include "mads/madsv2/phantom/phantom.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+/* ---- Scratch (room-local variables) ---- */
+
+struct Room206Scratch {
+ int16 sprite[15]; // Sprite series handles
+ int16 sequence[15]; // Sequence handles
+ int16 animation[4]; // Animation handles
+ int16 anim_0_running;
+ int16 prevent;
+ int16 prevent_2;
+};
+
+#define local ((Room206Scratch *)(&game.scratch[0]))
+#define ss local->sprite
+#define seq local->sequence
+#define aa local->animation
+
+/* ---- Sprite series indices ---- */
+
+#define fx_trap_door 0 /* rm206x0 */
+#define fx_panel_closes 1 /* rm206x1 */
+#define fx_panel_appears 2 /* rm206x2 */
+#define fx_panel_opens 3 /* rm206x3 */
+#define fx_note 4 /* rm206p0 */
+#define fx_take_9 5 /* *RDR_9 */
+
+/* ---- Conversation ---- */
+
+#define CONV_MISC 26
+
+/* ---- Trigger constants ---- */
+
+#define ROOM_206_DOOR_CLOSES 60
+#define ROOM_206_SCREW_WITH_PANEL 64
+#define ROOM_206_ENTER_PANEL 70
+#define ROOM_206_TAKE_NOTE 77
+#define ROOM_206_FROM_308 82
+#define ROOM_206_HIT_ON_HEAD 88
+#define ROOM_206_KNOCK 95
+
+/* ---- Player / world positions ---- */
+
+#define PLAYER_X_FROM_205 153
+#define PLAYER_Y_FROM_205 148
+
+#define PANEL_X 108
+#define PANEL_Y 137
+
+#define BEHIND_PANEL_X 67
+#define BEHIND_PANEL_Y 127
+
+#define HIT_HEAD_X 168
+#define HIT_HEAD_Y 138
+
+/* ---- Entry points ---- */
+
+void room_206_preload();
+void room_206_init();
+void room_206_daemon();
+void room_206_pre_parser();
+void room_206_parser();
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif // MADS_PHANTOM_ROOM206_H
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index 47ef2f2a97a..f9e2bccf9d4 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -143,6 +143,7 @@ MODULE_OBJS += \
madsv2/phantom/rooms/room203.o \
madsv2/phantom/rooms/room204.o \
madsv2/phantom/rooms/room205.o \
+ madsv2/phantom/rooms/room206.o \
madsv2/phantom/phantom.o \
madsv2/phantom/conv.o \
madsv2/phantom/main_menu.o \
Commit: 4d57e590097a354c6fb0d9952e97e65f4303bdd8
https://github.com/scummvm/scummvm/commit/4d57e590097a354c6fb0d9952e97e65f4303bdd8
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:45+10:00
Commit Message:
MADS: PHANTOM: Added room 207
Changed paths:
A engines/mads/madsv2/phantom/rooms/room207.cpp
A engines/mads/madsv2/phantom/rooms/room207.h
engines/mads/madsv2/phantom/mads/sounds.h
engines/mads/madsv2/phantom/mads/speeches.h
engines/mads/madsv2/phantom/mads/text.h
engines/mads/module.mk
diff --git a/engines/mads/madsv2/phantom/mads/sounds.h b/engines/mads/madsv2/phantom/mads/sounds.h
index 6eb7c241fdb..9c6883764a1 100644
--- a/engines/mads/madsv2/phantom/mads/sounds.h
+++ b/engines/mads/madsv2/phantom/mads/sounds.h
@@ -30,6 +30,7 @@ namespace Phantom {
enum {
N_AllFade = 1,
+ N_MusicFade = 3,
N_IsAnySoundOn = 8,
N_BackgroundMus = 16,
N_DoorOpens = 24,
@@ -42,6 +43,7 @@ enum {
N_SqueakyDoor = 66,
N_PlayerFalls = 67,
N_EchoSteps = 68,
+ N_Applause002 = 69,
N_SandbagThud = 70,
N_KeyTurnSnd = 71,
N_DoorHandle002 = 72,
diff --git a/engines/mads/madsv2/phantom/mads/speeches.h b/engines/mads/madsv2/phantom/mads/speeches.h
index c1dd6c0a6b4..5aa76131115 100644
--- a/engines/mads/madsv2/phantom/mads/speeches.h
+++ b/engines/mads/madsv2/phantom/mads/speeches.h
@@ -30,6 +30,7 @@ namespace Phantom {
enum {
speech_woman_scream = 1,
+ speech_applause = 2,
speech_christine_scales = 8,
speech_phantom_cackle = 9
};
diff --git a/engines/mads/madsv2/phantom/mads/text.h b/engines/mads/madsv2/phantom/mads/text.h
index 0fe7aaf54f6..589a7116d88 100644
--- a/engines/mads/madsv2/phantom/mads/text.h
+++ b/engines/mads/madsv2/phantom/mads/text.h
@@ -596,7 +596,21 @@ enum {
text_206_27 = 20627,
text_206_28 = 20628,
text_206_29 = 20629,
- text_206_30 = 20630
+ text_206_30 = 20630,
+
+ /* Room 207 â Box 9 (right box) */
+ text_207_10 = 20710,
+ text_207_11 = 20711,
+ text_207_12 = 20712,
+ text_207_13 = 20713,
+ text_207_14 = 20714,
+ text_207_15 = 20715,
+ text_207_16 = 20716,
+ text_207_17 = 20717,
+ text_207_18 = 20718,
+ text_207_19 = 20719,
+ text_207_20 = 20720,
+ text_207_21 = 20721
};
} // namespace Phantom
diff --git a/engines/mads/madsv2/phantom/rooms/room207.cpp b/engines/mads/madsv2/phantom/rooms/room207.cpp
new file mode 100644
index 00000000000..e286deab459
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room207.cpp
@@ -0,0 +1,234 @@
+/* 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 "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/imath.h"
+#include "mads/madsv2/core/text.h"
+#include "mads/madsv2/core/inter.h"
+#include "mads/madsv2/core/object.h"
+#include "mads/madsv2/core/rail.h"
+#include "mads/madsv2/core/sound.h"
+#include "mads/madsv2/core/speech.h"
+#include "mads/madsv2/core/quote.h"
+#include "mads/madsv2/core/matte.h"
+#include "mads/madsv2/core/buffer.h"
+#include "mads/madsv2/phantom/global.h"
+#include "mads/madsv2/phantom/conv.h"
+#include "mads/madsv2/phantom/mads/inventory.h"
+#include "mads/madsv2/phantom/mads/quotes.h"
+#include "mads/madsv2/phantom/mads/sounds.h"
+#include "mads/madsv2/phantom/mads/speeches.h"
+#include "mads/madsv2/phantom/mads/text.h"
+#include "mads/madsv2/phantom/mads/words.h"
+#include "mads/madsv2/phantom/rooms/section2.h"
+#include "mads/madsv2/phantom/rooms/room207.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+void room_207_daemon() {
+ if (local->anim_0_running && !local->prevent) {
+ if (kernel_anim[aa[0]].frame == 6) {
+ if (global_prefer_roland) {
+ sound_play(N_Applause002);
+ } else {
+ global_speech_go(speech_applause);
+ }
+ local->prevent = true;
+ }
+ }
+}
+
+void room_207_pre_parser() {
+ if (player_said_2(take, seat)) {
+ player_walk(SEAT_X, SEAT_Y, FACING_NORTH);
+ }
+}
+
+void room_207_parser() {
+ if (player_said_2(take, seat)) {
+ switch (kernel.trigger) {
+ case 0:
+ global[player_score] += 5;
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ sound_play(N_MusicFade);
+ seq[fx_sit] = kernel_seq_forward(ss[fx_sit], false, 7, 0, 0, 1);
+ kernel_seq_depth(seq[fx_sit], 10);
+ kernel_seq_range(seq[fx_sit], KERNEL_FIRST, KERNEL_LAST);
+ kernel_seq_trigger(seq[fx_sit], KERNEL_TRIGGER_EXPIRE, 0, 1);
+ break;
+
+ case 1:
+ seq[fx_sit] = kernel_seq_stamp(ss[fx_sit], false, KERNEL_LAST);
+ kernel_seq_depth(seq[fx_sit], 10);
+ kernel_timing_trigger(TWO_SECONDS, 2);
+ kernel_timing_trigger(FOUR_SECONDS, 3);
+ break;
+
+ case 2:
+ seq[fx_lights] = kernel_seq_forward(ss[fx_lights], false, 6, 0, 0, 1);
+ kernel_seq_depth(seq[fx_lights], 1);
+ kernel_seq_range(seq[fx_lights], KERNEL_FIRST, KERNEL_LAST);
+ kernel_seq_trigger(seq[fx_lights], KERNEL_TRIGGER_EXPIRE, 0, 4);
+ break;
+
+ case 3:
+ aa[0] = kernel_run_animation(kernel_name('s', 1), 5);
+ local->anim_0_running = true;
+ kernel_seq_delete(seq[fx_curtain]);
+ /* run anim of Christine singing */
+ break;
+
+ case 4:
+ seq[fx_lights] = kernel_seq_stamp(ss[fx_lights], false, KERNEL_LAST);
+ kernel_seq_depth(seq[fx_lights], 1);
+ break;
+
+ case 5:
+ new_room = 208;
+ break;
+ }
+ goto handled;
+ }
+
+
+ if (player_said_2(exit_to, loge_corridor)) {
+ new_room = 205;
+ goto handled;
+ }
+
+ if (player.look_around) {
+ text_show(text_207_10);
+ goto handled;
+ }
+
+ if (player_said_1(look) || player_said_1(look_at)) {
+
+ if (player_said_1(wall)) {
+ text_show(text_207_11);
+ goto handled;
+ }
+
+ if (player_said_1(floor)) {
+ text_show(text_207_12);
+ goto handled;
+ }
+
+ if (player_said_1(left_column)) {
+ text_show(text_207_13);
+ goto handled;
+ }
+
+ if (player_said_1(right_column)) {
+ text_show(text_207_14);
+ goto handled;
+ }
+
+ if (player_said_1(rail)) {
+ text_show(text_207_15);
+ goto handled;
+ }
+
+ if (player_said_1(seat)) {
+ text_show(text_207_16);
+ goto handled;
+ }
+
+ if (player_said_1(loge_corridor)) {
+ text_show(text_207_17);
+ goto handled;
+ }
+
+ if (player_said_1(stage)) {
+ text_show(text_207_18);
+ goto handled;
+ }
+
+ if (player_said_1(house)) {
+ text_show(text_207_19);
+ goto handled;
+ }
+
+ if (player_said_1(ceiling)) {
+ text_show(text_207_20);
+ goto handled;
+ }
+
+ if (player_said_1(house_light)) {
+ text_show(text_207_21);
+ goto handled;
+ }
+ }
+
+ goto done;
+
+handled:
+ player.command_ready = false;
+
+done:
+ ;
+}
+
+void room_207_init() {
+ global_speech_load(speech_applause);
+
+ local->prevent = false;
+ local->anim_0_running = false;
+
+ /* Load sprite series */
+
+ ss[fx_sit] = kernel_load_series(kernel_name('a', 0), false);
+ ss[fx_curtain] = kernel_load_series(kernel_name('c', 0), false);
+ ss[fx_lights] = kernel_load_series(kernel_name('x', 0), false);
+
+ seq[fx_curtain] = kernel_seq_stamp(ss[fx_curtain], false, 1);
+ kernel_seq_depth(seq[fx_curtain], 10);
+
+
+ /* Previous Rooms */
+
+ if ((previous_room == 205) || (previous_room != KERNEL_RESTORING_GAME)) {
+ player.x = PLAYER_X_FROM_205;
+ player.y = PLAYER_Y_FROM_205;
+ player.facing = FACING_NORTH;
+ }
+
+ section_2_music();
+}
+
+void room_207_preload() {
+ room_init_code_pointer = room_207_init;
+ room_pre_parser_code_pointer = room_207_pre_parser;
+ room_parser_code_pointer = room_207_parser;
+ room_daemon_code_pointer = room_207_daemon;
+
+ section_2_walker();
+ section_2_interface();
+}
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/rooms/room207.h b/engines/mads/madsv2/phantom/rooms/room207.h
new file mode 100644
index 00000000000..b45a58cef60
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room207.h
@@ -0,0 +1,78 @@
+/* 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 MADS_PHANTOM_ROOM207_H
+#define MADS_PHANTOM_ROOM207_H
+
+#include "mads/madsv2/phantom/phantom.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+/* ---- Scratch (room-local variables) ---- */
+
+struct Room207Scratch {
+ int16 sprite[15]; // Sprite series handles
+ int16 sequence[15]; // Sequence handles
+ int16 animation[4]; // Animation handles
+ int16 prevent;
+ int16 anim_0_running;
+};
+
+#define local ((Room207Scratch *)(&game.scratch[0]))
+#define ss local->sprite
+#define seq local->sequence
+#define aa local->animation
+
+/* ---- Sprite series indices ---- */
+
+#define fx_sit 0 /* rm207a0 */
+#define fx_curtain 1 /* rm207c0 */
+#define fx_lights 2 /* rm207x0 */
+
+/* ---- Trigger constants ---- */
+
+#define ROOM_207_DOOR_CLOSES 60 /* defined but not used */
+
+/* ---- Player / world positions ---- */
+
+#define PLAYER_X_FROM_205 159
+#define PLAYER_Y_FROM_205 147
+
+#define SEAT_X 139
+#define SEAT_Y 124
+
+/* ---- Entry points ---- */
+
+void room_207_preload();
+void room_207_init();
+void room_207_daemon();
+void room_207_pre_parser();
+void room_207_parser();
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif // MADS_PHANTOM_ROOM207_H
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index f9e2bccf9d4..8c32d8e5372 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -144,6 +144,7 @@ MODULE_OBJS += \
madsv2/phantom/rooms/room204.o \
madsv2/phantom/rooms/room205.o \
madsv2/phantom/rooms/room206.o \
+ madsv2/phantom/rooms/room207.o \
madsv2/phantom/phantom.o \
madsv2/phantom/conv.o \
madsv2/phantom/main_menu.o \
Commit: 117ce246494e42a9c91adadcb8f4d0c1c3bb1eea
https://github.com/scummvm/scummvm/commit/117ce246494e42a9c91adadcb8f4d0c1c3bb1eea
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:45+10:00
Commit Message:
MADS: PHANTOM: Added room 208
Changed paths:
A engines/mads/madsv2/phantom/rooms/room208.cpp
A engines/mads/madsv2/phantom/rooms/room208.h
engines/mads/module.mk
diff --git a/engines/mads/madsv2/phantom/rooms/room208.cpp b/engines/mads/madsv2/phantom/rooms/room208.cpp
new file mode 100644
index 00000000000..ce691b828c3
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room208.cpp
@@ -0,0 +1,469 @@
+/* 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 "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/imath.h"
+#include "mads/madsv2/core/text.h"
+#include "mads/madsv2/core/inter.h"
+#include "mads/madsv2/core/object.h"
+#include "mads/madsv2/core/rail.h"
+#include "mads/madsv2/core/sound.h"
+#include "mads/madsv2/core/speech.h"
+#include "mads/madsv2/core/quote.h"
+#include "mads/madsv2/core/matte.h"
+#include "mads/madsv2/core/buffer.h"
+#include "mads/madsv2/phantom/global.h"
+#include "mads/madsv2/phantom/conv.h"
+#include "mads/madsv2/phantom/mads/inventory.h"
+#include "mads/madsv2/phantom/mads/quotes.h"
+#include "mads/madsv2/phantom/mads/sounds.h"
+#include "mads/madsv2/phantom/mads/speeches.h"
+#include "mads/madsv2/phantom/mads/text.h"
+#include "mads/madsv2/phantom/mads/words.h"
+#include "mads/madsv2/phantom/rooms/section2.h"
+#include "mads/madsv2/phantom/rooms/room208.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+static void animate_top_left() {
+ int delay;
+ int random;
+ int random_2;
+ int chance;
+
+ if (kernel.trigger == ROOM_208_MOVE_TOP_LEFT) {
+ kernel_seq_delete(seq[fx_top_left]);
+
+ random_2 = imath_random(1, 2);
+ if (local->top_left_frame == 3) {
+ chance = 1;
+ } else {
+ chance = random_2;
+ } /* this will keep the person looking at the stage more often */
+
+ if (random_2 == chance) {
+ random = imath_random(-1, 1);
+ local->top_left_frame += random;
+ if (local->top_left_frame == 0) {
+ local->top_left_frame = 1;
+ } else if (local->top_left_frame == 4) {
+ local->top_left_frame = 3;
+ }
+ }
+
+ seq[fx_top_left] = kernel_seq_stamp(ss[fx_top_left], false, local->top_left_frame);
+ kernel_seq_depth(seq[fx_top_left], 1);
+ delay = imath_random(QUARTER_SECOND, ONE_SECOND);
+ kernel_timing_trigger(delay, ROOM_208_MOVE_TOP_LEFT);
+ }
+}
+
+static void animate_top_right() {
+ int delay;
+ int random;
+ int random_2;
+ int chance;
+
+ if (kernel.trigger == ROOM_208_MOVE_TOP_RIGHT) {
+ kernel_seq_delete(seq[fx_top_right]);
+
+ random_2 = imath_random(1, 2);
+ if (local->top_right_frame == 4) {
+ chance = 1;
+ } else {
+ chance = random_2;
+ } /* this will keep the person looking at the stage more often */
+
+ if (random_2 == chance) {
+ random = imath_random(-1, 1);
+ local->top_right_frame += random;
+ if (local->top_right_frame == 0) {
+ local->top_right_frame = 1;
+ } else if (local->top_right_frame == 5) {
+ local->top_right_frame = 4;
+ }
+ }
+
+ seq[fx_top_right] = kernel_seq_stamp(ss[fx_top_right], false, local->top_right_frame);
+ kernel_seq_depth(seq[fx_top_right], 1);
+ delay = imath_random(QUARTER_SECOND, ONE_SECOND);
+ kernel_timing_trigger(delay, ROOM_208_MOVE_TOP_RIGHT);
+ }
+}
+
+static void animate_middle_left() {
+ int delay;
+ int random;
+ int random_2;
+ int chance;
+
+ if (kernel.trigger == ROOM_208_MOVE_MIDDLE_LEFT) {
+ kernel_seq_delete(seq[fx_middle_left]);
+ delay = imath_random(ONE_SECOND, TWO_SECONDS);
+
+ random_2 = imath_random(1, 2);
+ if (local->middle_left_frame == 2) {
+ chance = 1;
+ } else {
+ chance = random_2;
+ } /* this will keep the person looking at the stage more often */
+
+ if (random_2 == chance) {
+ random = imath_random(-1, 1);
+ local->middle_left_frame += random;
+ if (local->middle_left_frame == 0) {
+ local->middle_left_frame = 1;
+ } else if (local->middle_left_frame == 5) {
+ local->middle_left_frame = 4;
+ }
+ }
+
+ if (local->middle_middle_frame == 3) { /* if man is hunched over, whispering */
+ if (local->middle_left_frame < 4) {
+ ++local->middle_left_frame;
+ delay = QUICKLY;
+ }
+ } /* if man is whispering, move left woman's head to the couple (she's annoyed) */
+
+ seq[fx_middle_left] = kernel_seq_stamp(ss[fx_middle_left], false, local->middle_left_frame);
+ kernel_seq_depth(seq[fx_middle_left], 1);
+ kernel_timing_trigger(delay, ROOM_208_MOVE_MIDDLE_LEFT);
+ }
+}
+
+static void animate_middle_middle() {
+ int delay;
+
+ if (kernel.trigger == ROOM_208_MOVE_MIDDLE_MIDDLE) {
+ kernel_seq_delete(seq[fx_middle_middle]);
+
+ if (local->middle_direction) { /* if going to whisper */
+ ++local->middle_middle_frame;
+ delay = QUARTER_SECOND;
+ if (local->middle_middle_frame == 4) { /* whispering */
+ delay = imath_random(FIVE_SECONDS, SEVEN_SECONDS);
+ --local->middle_middle_frame;
+ local->middle_direction = 0;
+ }
+ } else { /* if returning to watch play */
+ --local->middle_middle_frame;
+ delay = QUARTER_SECOND;
+ if (local->middle_middle_frame == 0) { /* standing up */
+ delay = imath_random(TEN_SECONDS, FIFTEEN_SECONDS);
+ ++local->middle_middle_frame;
+ local->middle_direction = 1;
+ }
+ }
+
+ seq[fx_middle_middle] = kernel_seq_stamp(ss[fx_middle_middle], false, local->middle_middle_frame);
+ kernel_seq_depth(seq[fx_middle_middle], 14);
+ kernel_timing_trigger(delay, ROOM_208_MOVE_MIDDLE_MIDDLE);
+ }
+}
+
+static void animate_middle_right() {
+ int delay;
+ int random;
+ int random_2;
+ int chance;
+
+ if (kernel.trigger == ROOM_208_MOVE_MIDDLE_RIGHT) {
+ kernel_seq_delete(seq[fx_middle_right]);
+
+ random_2 = imath_random(1, 2);
+ if (local->middle_right_frame == 1) {
+ chance = 1;
+ } else {
+ chance = random_2;
+ } /* this will keep the person looking at the stage more often */
+
+ if (random_2 == chance) {
+ random = imath_random(-1, 1);
+ local->middle_right_frame += random;
+ if (local->middle_right_frame == 0) {
+ local->middle_right_frame = 1;
+ } else if (local->middle_right_frame == 4) {
+ local->middle_right_frame = 3;
+ }
+
+ if (local->middle_middle_frame == 3) {
+ local->middle_right_frame = 3;
+ } /* if man is whispering to woman, then freeze woman at frame 3 (listening to man) */
+ }
+
+ seq[fx_middle_right] = kernel_seq_stamp(ss[fx_middle_right], false, local->middle_right_frame);
+ kernel_seq_depth(seq[fx_middle_right], 1);
+ delay = imath_random(QUARTER_SECOND, ONE_SECOND);
+ kernel_timing_trigger(delay, ROOM_208_MOVE_MIDDLE_RIGHT);
+ }
+}
+
+static void animate_bottom_left() {
+ int delay;
+ int random;
+ int random_2;
+ int chance;
+
+ if (kernel.trigger == ROOM_208_MOVE_BOTTOM_LEFT) {
+ kernel_seq_delete(seq[fx_bottom_left]);
+
+ random_2 = imath_random(1, 2);
+ if (local->bottom_left_frame == 4) {
+ chance = 1;
+ } else {
+ chance = random_2;
+ } /* this will keep the person looking at the stage more often */
+
+ if (random_2 == chance) {
+ random = imath_random(-1, 1);
+ local->bottom_left_frame += random;
+ if (local->bottom_left_frame == 0) {
+ local->bottom_left_frame = 1;
+ } else if (local->bottom_left_frame == 5) {
+ local->bottom_left_frame = 4;
+ }
+ }
+
+ seq[fx_bottom_left] = kernel_seq_stamp(ss[fx_bottom_left], false, local->bottom_left_frame);
+ kernel_seq_depth(seq[fx_bottom_left], 1);
+ delay = imath_random(QUARTER_SECOND, ONE_SECOND);
+ kernel_timing_trigger(delay, ROOM_208_MOVE_BOTTOM_LEFT);
+ }
+}
+
+static void animate_bottom_middle() {
+ int delay;
+ int random;
+ int random_2;
+ int chance;
+
+ if (kernel.trigger == ROOM_208_MOVE_BOTTOM_MIDDLE) {
+ kernel_seq_delete(seq[fx_bottom_middle]);
+
+ random_2 = imath_random(1, 2);
+ if (local->bottom_middle_frame == 4) {
+ chance = 1;
+ } else {
+ chance = random_2;
+ } /* this will keep the person looking at the stage more often */
+
+ if (random_2 == chance) {
+ random = imath_random(-1, 1);
+ local->bottom_middle_frame += random;
+ if (local->bottom_middle_frame == 0) {
+ local->bottom_middle_frame = 1;
+ } else if (local->bottom_middle_frame == 5) {
+ local->bottom_middle_frame = 4;
+ }
+ }
+
+ seq[fx_bottom_middle] = kernel_seq_stamp(ss[fx_bottom_middle], false, local->bottom_middle_frame);
+ kernel_seq_depth(seq[fx_bottom_middle], 14);
+ delay = imath_random(QUARTER_SECOND, ONE_SECOND);
+ kernel_timing_trigger(delay, ROOM_208_MOVE_BOTTOM_MIDDLE);
+ }
+}
+
+static void animate_bottom_right() {
+ int delay;
+ int random;
+ int random_2;
+ int chance;
+
+ if (kernel.trigger == ROOM_208_MOVE_BOTTOM_RIGHT) {
+ kernel_seq_delete(seq[fx_bottom_right]);
+
+ random_2 = imath_random(1, 2);
+ if ((local->bottom_right_frame == 3) || (local->bottom_right_frame == 1)) {
+ chance = 1;
+ } else {
+ chance = random_2;
+ } /* this will keep the person looking at the stage more often */
+
+ if (random_2 == chance) {
+ random = imath_random(-1, 1);
+ local->bottom_right_frame += random;
+ if (local->bottom_right_frame == 0) {
+ local->bottom_right_frame = 1;
+ } else if (local->bottom_right_frame == 4) {
+ local->bottom_right_frame = 3;
+ }
+ }
+
+ seq[fx_bottom_right] = kernel_seq_stamp(ss[fx_bottom_right], false, local->bottom_right_frame);
+ kernel_seq_depth(seq[fx_bottom_right], 1);
+ delay = imath_random(QUARTER_SECOND, ONE_SECOND);
+ kernel_timing_trigger(delay, ROOM_208_MOVE_BOTTOM_RIGHT);
+ }
+}
+
+void room_208_daemon() {
+ animate_top_left();
+ animate_top_right();
+ animate_middle_left();
+ animate_middle_middle();
+ animate_middle_right();
+ animate_bottom_left();
+ animate_bottom_middle();
+ animate_bottom_right();
+
+ if (!local->prevent) {
+ if (kernel_anim[aa[0]].frame == 49) {
+ if (global_prefer_roland) {
+ sound_play(N_WomanScream002);
+ } else {
+ global_speech_go(speech_woman_scream);
+ }
+ local->prevent = true;
+ }
+ }
+
+ if (!local->prevent_2) {
+ if (kernel_anim[aa[0]].frame == 68) {
+ if (global_prefer_roland) {
+ sound_play(N_WomanScream002);
+ } else {
+ global_speech_go(speech_woman_scream);
+ }
+ local->prevent_2 = true;
+ }
+ }
+
+ if (kernel.trigger == ROOM_208_DONE_PHANTOM) {
+ new_room = 150;
+ }
+}
+
+void room_208_init() {
+ global_speech_load(speech_woman_scream);
+
+ local->prevent = false;
+ local->prevent_2 = false;
+
+ /* Load Sprite Series */
+
+ ss[fx_top_left] = kernel_load_series(kernel_name('x', 0), false);
+ ss[fx_top_right] = kernel_load_series(kernel_name('x', 1), false);
+ ss[fx_middle_left] = kernel_load_series(kernel_name('x', 2), false);
+ ss[fx_middle_middle] = kernel_load_series(kernel_name('x', 3), false);
+ ss[fx_middle_right] = kernel_load_series(kernel_name('x', 4), false);
+ ss[fx_bottom_left] = kernel_load_series(kernel_name('x', 5), false);
+ ss[fx_bottom_middle] = kernel_load_series(kernel_name('x', 6), false);
+ ss[fx_bottom_right] = kernel_load_series(kernel_name('x', 7), false);
+
+ kernel_init_dialog();
+ kernel_set_interface_mode(INTER_CONVERSATION);
+
+ global_speech_load(speech_woman_scream); /* called twice in original source */
+
+ player.commands_allowed = false;
+ player.walker_visible = false;
+
+
+ /* Deal with top left person */
+
+ local->top_left_frame = 2;
+ seq[fx_top_left] = kernel_seq_stamp(ss[fx_top_left], false, local->top_left_frame);
+ kernel_seq_depth(seq[fx_top_left], 1);
+ kernel_timing_trigger(TWO_SECONDS, ROOM_208_MOVE_TOP_LEFT);
+
+
+ /* Deal with top right person */
+
+ local->top_right_frame = 2;
+ seq[fx_top_right] = kernel_seq_stamp(ss[fx_top_right], false, local->top_right_frame);
+ kernel_seq_depth(seq[fx_top_right], 1);
+ kernel_timing_trigger(HALF_SECOND, ROOM_208_MOVE_TOP_RIGHT);
+
+
+ /* Deal with middle left person */
+
+ local->middle_left_frame = 2;
+ seq[fx_middle_left] = kernel_seq_stamp(ss[fx_middle_left], false, local->middle_left_frame);
+ kernel_seq_depth(seq[fx_middle_left], 1);
+ kernel_timing_trigger(HALF_SECOND, ROOM_208_MOVE_MIDDLE_LEFT);
+
+
+ /* Deal with middle middle person */
+
+ local->middle_middle_frame = 1;
+ local->middle_direction = 1;
+ seq[fx_middle_middle] = kernel_seq_stamp(ss[fx_middle_middle], false, local->middle_middle_frame);
+ kernel_seq_depth(seq[fx_middle_middle], 14);
+ kernel_timing_trigger(FIVE_SECONDS, ROOM_208_MOVE_MIDDLE_MIDDLE);
+
+
+ /* Deal with middle right person */
+
+ local->middle_right_frame = 3;
+ seq[fx_middle_right] = kernel_seq_stamp(ss[fx_middle_right], false, local->middle_right_frame);
+ kernel_seq_depth(seq[fx_middle_right], 1);
+ kernel_timing_trigger(ONE_SECOND, ROOM_208_MOVE_MIDDLE_RIGHT);
+
+
+ /* Deal with bottom left person */
+
+ local->bottom_left_frame = 4;
+ seq[fx_bottom_left] = kernel_seq_stamp(ss[fx_bottom_left], false, local->bottom_left_frame);
+ kernel_seq_depth(seq[fx_bottom_left], 1);
+ kernel_timing_trigger(ONE_SECOND, ROOM_208_MOVE_BOTTOM_LEFT);
+
+
+ /* Deal with bottom middle person */
+
+ local->bottom_middle_frame = 4;
+ seq[fx_bottom_middle] = kernel_seq_stamp(ss[fx_bottom_middle], false, local->bottom_middle_frame);
+ kernel_seq_depth(seq[fx_bottom_middle], 14);
+ kernel_timing_trigger(HALF_SECOND, ROOM_208_MOVE_BOTTOM_MIDDLE);
+
+
+ /* Deal with bottom right person */
+
+ local->bottom_right_frame = 3;
+ seq[fx_bottom_right] = kernel_seq_stamp(ss[fx_bottom_right], false, local->bottom_right_frame);
+ kernel_seq_depth(seq[fx_bottom_right], 1);
+ kernel_timing_trigger(QUARTER_SECOND, ROOM_208_MOVE_BOTTOM_RIGHT);
+
+
+ aa[0] = kernel_run_animation(kernel_name('p', 1), ROOM_208_DONE_PHANTOM);
+ /* run anim of Phantom swinging down and taking Christine */
+
+ section_2_music();
+}
+
+void room_208_preload() {
+ room_init_code_pointer = room_208_init;
+ room_pre_parser_code_pointer = NULL;
+ room_parser_code_pointer = NULL;
+ room_daemon_code_pointer = room_208_daemon;
+
+ section_2_walker();
+ section_2_interface();
+}
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/rooms/room208.h b/engines/mads/madsv2/phantom/rooms/room208.h
new file mode 100644
index 00000000000..0823cfd1acf
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room208.h
@@ -0,0 +1,96 @@
+/* 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 MADS_PHANTOM_ROOM208_H
+#define MADS_PHANTOM_ROOM208_H
+
+#include "mads/madsv2/phantom/phantom.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+/* ---- Scratch (room-local variables) ---- */
+
+struct Room208Scratch {
+ int16 sprite[15]; // Sprite series handles
+ int16 sequence[15]; // Sequence handles
+ int16 animation[4]; // Animation handles
+ int16 middle_direction; // 1 = increasing (toward whisper), 0 = decreasing (returning)
+ int16 top_left_frame; // Current frame for top left person
+ int16 top_right_frame; // Current frame for top right person
+ int16 middle_left_frame; // Current frame for middle left person
+ int16 middle_middle_frame; // Current frame for middle middle person
+ int16 middle_right_frame; // Current frame for middle right person
+ int16 bottom_left_frame; // Current frame for bottom left person
+ int16 bottom_middle_frame; // Current frame for bottom middle person
+ int16 bottom_right_frame; // Current frame for bottom right person
+ int16 prevent;
+ int16 prevent_2;
+};
+
+#define local ((Room208Scratch *)(&game.scratch[0]))
+#define ss local->sprite
+#define seq local->sequence
+#define aa local->animation
+
+/* ---- Sprite series indices ---- */
+
+#define fx_top_left 0 /* rm208x0 */
+#define fx_top_right 1 /* rm208x1 */
+#define fx_middle_left 2 /* rm208x2 */
+#define fx_middle_middle 3 /* rm208x3 */
+#define fx_middle_right 4 /* rm208x4 */
+#define fx_bottom_left 5 /* rm208x5 */
+#define fx_bottom_middle 6 /* rm208x6 */
+#define fx_bottom_right 7 /* rm208x7 */
+
+/* ---- Trigger constants ---- */
+
+#define ROOM_208_MOVE_TOP_LEFT 60
+#define ROOM_208_MOVE_TOP_RIGHT 62
+#define ROOM_208_MOVE_MIDDLE_LEFT 64
+#define ROOM_208_MOVE_MIDDLE_MIDDLE 66
+#define ROOM_208_MOVE_MIDDLE_RIGHT 68
+#define ROOM_208_MOVE_BOTTOM_LEFT 70
+#define ROOM_208_MOVE_BOTTOM_MIDDLE 72
+#define ROOM_208_MOVE_BOTTOM_RIGHT 74
+
+#define ROOM_208_DONE_PHANTOM 80
+
+/* ---- Delay constant ---- */
+
+#define QUICKLY 10 /* very short delay in game ticks */
+
+/* ---- Entry points ---- */
+
+void room_208_preload();
+void room_208_init();
+void room_208_daemon();
+/* no pre_parser or parser â both NULL in preload */
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif // MADS_PHANTOM_ROOM208_H
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index 8c32d8e5372..df2f94465a3 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -145,6 +145,7 @@ MODULE_OBJS += \
madsv2/phantom/rooms/room205.o \
madsv2/phantom/rooms/room206.o \
madsv2/phantom/rooms/room207.o \
+ madsv2/phantom/rooms/room208.o \
madsv2/phantom/phantom.o \
madsv2/phantom/conv.o \
madsv2/phantom/main_menu.o \
Commit: cbdb0f6bc8ab3a9a2b6daf13cf87d83b40955191
https://github.com/scummvm/scummvm/commit/cbdb0f6bc8ab3a9a2b6daf13cf87d83b40955191
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:45+10:00
Commit Message:
MADS: PHANTOM: Added room 250
Changed paths:
A engines/mads/madsv2/phantom/rooms/room250.cpp
A engines/mads/madsv2/phantom/rooms/room250.h
engines/mads/madsv2/phantom/mads/quotes.h
engines/mads/module.mk
diff --git a/engines/mads/madsv2/phantom/mads/quotes.h b/engines/mads/madsv2/phantom/mads/quotes.h
index de7d50cc7bd..a6266629bc1 100644
--- a/engines/mads/madsv2/phantom/mads/quotes.h
+++ b/engines/mads/madsv2/phantom/mads/quotes.h
@@ -29,6 +29,18 @@ namespace MADSV2 {
namespace Phantom {
enum {
+ quote_score_1 = 54,
+ quote_score_2 = 55,
+ quote_score_3 = 56,
+ quote_score_4 = 57,
+ quote_score_rank_1 = 58,
+ quote_score_rank_2 = 59,
+ quote_score_rank_3 = 60,
+ quote_score_rank_4 = 61,
+ quote_score_rank_5 = 62,
+ quote_score_rank_6 = 63,
+ quote_score_rank_7 = 64,
+ quote_score_rank_8 = 65,
quote_mainmenu_phantom_1 = 66,
quote_204a0 = 117
diff --git a/engines/mads/madsv2/phantom/rooms/room250.cpp b/engines/mads/madsv2/phantom/rooms/room250.cpp
new file mode 100644
index 00000000000..091c08dae0f
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room250.cpp
@@ -0,0 +1,143 @@
+/* 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 "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/global.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/matte.h"
+#include "mads/madsv2/core/quote.h"
+#include "mads/madsv2/phantom/mads/quotes.h"
+#include "mads/madsv2/phantom/rooms/section2.h"
+#include "mads/madsv2/phantom/rooms/room250.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+void room_250_init(void) {
+ viewing_at_y = ((video_y - display_y) >> 1);
+
+ player.commands_allowed = false;
+ player.walker_visible = false;
+
+ kernel.quotes = quote_load(quote_score_1, quote_score_2,
+ quote_score_3, quote_score_4,
+ quote_score_rank_1,
+ quote_score_rank_2,
+ quote_score_rank_3,
+ quote_score_rank_4,
+ quote_score_rank_5,
+ quote_score_rank_6,
+ quote_score_rank_7,
+ quote_score_rank_8, 0);
+
+ aa[0] = kernel_run_animation("*RM150Q1", 1);
+}
+
+
+void room_250_daemon(void) {
+ int score;
+ int id;
+ int y;
+ static char message[40];
+
+ if (kernel.trigger == 1) {
+ kernel_timing_trigger(12, 2);
+ }
+
+ if (kernel.trigger == 2) {
+ y = 68;
+
+ kernel_message_add(quote_string(kernel.quotes, quote_score_1),
+ video_x >> 1, y, MESSAGE_COLOR,
+ FIFTEEN_SECONDS, 0,
+ KERNEL_MESSAGE_CENTER);
+ y += 16;
+
+ if (global[player_score] > 250) global[player_score] = 250;
+
+ mads_itoa(global[player_score], message, 10);
+ Common::strcat_s(message, " ");
+ Common::strcat_s(message, quote_string(kernel.quotes, quote_score_2));
+ Common::strcat_s(message, " 250 ");
+ Common::strcat_s(message, quote_string(kernel.quotes, quote_score_3));
+
+ kernel_message_add(message,
+ video_x >> 1, y, MESSAGE_COLOR,
+ FIFTEEN_SECONDS, 3,
+ KERNEL_MESSAGE_CENTER);
+ y += 16;
+
+ kernel_message_add(quote_string(kernel.quotes, quote_score_4),
+ video_x >> 1, y, MESSAGE_COLOR,
+ FIFTEEN_SECONDS, 0,
+ KERNEL_MESSAGE_CENTER);
+ y += 16;
+
+ score = global[player_score];
+
+ if (score <= 25) {
+ id = quote_score_rank_1; /* Stage sweeper */
+ } else if (score <= 50) {
+ id = quote_score_rank_2; /* Dresser */
+ } else if (score <= 75) {
+ id = quote_score_rank_3; /* Usher */
+ } else if (score <= 100) {
+ id = quote_score_rank_4; /* Stagehand */
+ } else if (score <= 150) {
+ id = quote_score_rank_5; /* Chorus Member */
+ } else if (score <= 200) {
+ id = quote_score_rank_6; /* Supporting Player */
+ } else if (score <= 249) {
+ id = quote_score_rank_7; /* Star Player */
+ } else {
+ id = quote_score_rank_8; /* Director */
+ }
+
+ kernel_message_add(quote_string(kernel.quotes, id),
+ video_x >> 1, y, MESSAGE_COLOR,
+ FIFTEEN_SECONDS, 0,
+ KERNEL_MESSAGE_CENTER);
+
+ kernel_timing_trigger(FIFTEEN_SECONDS + HALF_SECOND, 3);
+ }
+
+ if (kernel.trigger == 3) {
+ game.going = false;
+ win_status = 1;
+ }
+}
+
+void room_250_preload(void) {
+ room_init_code_pointer = room_250_init;
+ room_pre_parser_code_pointer = NULL;
+ room_parser_code_pointer = NULL;
+ room_daemon_code_pointer = room_250_daemon;
+
+ section_2_walker();
+ section_2_interface();
+}
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/rooms/room250.h b/engines/mads/madsv2/phantom/rooms/room250.h
new file mode 100644
index 00000000000..f6b78a72155
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room250.h
@@ -0,0 +1,50 @@
+/* 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 MADS_PHANTOM_ROOM250_H
+#define MADS_PHANTOM_ROOM250_H
+
+#include "mads/madsv2/phantom/phantom.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+#define local ((Scratch *)(&game.scratch[0]))
+#define ss local->sprite
+#define seq local->sequence
+#define aa local->animation
+
+typedef struct { /* Room local variables */
+
+ int16 sprite[15]; /* Sprite series handles */
+ int16 sequence[15]; /* Sequence handles */
+ int16 animation[4]; /* Animation handles */
+
+} Scratch;
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif // MADS_PHANTOM_ROOM250_H
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index df2f94465a3..f610840fe2c 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -146,6 +146,7 @@ MODULE_OBJS += \
madsv2/phantom/rooms/room206.o \
madsv2/phantom/rooms/room207.o \
madsv2/phantom/rooms/room208.o \
+ madsv2/phantom/rooms/room250.o \
madsv2/phantom/phantom.o \
madsv2/phantom/conv.o \
madsv2/phantom/main_menu.o \
Commit: ae4217a7cc8ee200d128d6e794b62910437912df
https://github.com/scummvm/scummvm/commit/ae4217a7cc8ee200d128d6e794b62910437912df
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:46+10:00
Commit Message:
MADS: PHANTOM: Added room 301
Changed paths:
A engines/mads/madsv2/phantom/rooms/room301.cpp
A engines/mads/madsv2/phantom/rooms/room301.h
A engines/mads/madsv2/phantom/rooms/section3.h
engines/mads/madsv2/phantom/mads/speeches.h
engines/mads/madsv2/phantom/mads/text.h
engines/mads/madsv2/phantom/mads/words.h
engines/mads/module.mk
diff --git a/engines/mads/madsv2/phantom/mads/speeches.h b/engines/mads/madsv2/phantom/mads/speeches.h
index 5aa76131115..b5c8ea53be2 100644
--- a/engines/mads/madsv2/phantom/mads/speeches.h
+++ b/engines/mads/madsv2/phantom/mads/speeches.h
@@ -31,6 +31,7 @@ namespace Phantom {
enum {
speech_woman_scream = 1,
speech_applause = 2,
+ speech_raoul_catwalk = 6,
speech_christine_scales = 8,
speech_phantom_cackle = 9
};
diff --git a/engines/mads/madsv2/phantom/mads/text.h b/engines/mads/madsv2/phantom/mads/text.h
index 589a7116d88..1c9649b837b 100644
--- a/engines/mads/madsv2/phantom/mads/text.h
+++ b/engines/mads/madsv2/phantom/mads/text.h
@@ -610,7 +610,42 @@ enum {
text_207_18 = 20718,
text_207_19 = 20719,
text_207_20 = 20720,
- text_207_21 = 20721
+ text_207_21 = 20721,
+
+ /* Room 301 */
+ text_301_10 = 30110,
+ text_301_11 = 30111,
+ text_301_12 = 30112,
+ text_301_13 = 30113,
+ text_301_14 = 30114,
+ text_301_15 = 30115,
+ text_301_16 = 30116,
+ text_301_17 = 30117,
+ text_301_18 = 30118,
+ text_301_19 = 30119,
+ text_301_20 = 30120,
+ text_301_21 = 30121,
+ text_301_22 = 30122,
+ text_301_23 = 30123,
+ text_301_24 = 30124,
+ text_301_25 = 30125,
+ text_301_26 = 30126,
+ text_301_27 = 30127,
+ text_301_28 = 30128,
+ text_301_29 = 30129,
+ text_301_30 = 30130,
+ text_301_31 = 30131,
+ text_301_32 = 30132,
+ text_301_33 = 30133,
+ text_301_34 = 30134,
+ text_301_35 = 30135,
+ text_301_36 = 30136,
+ text_301_37 = 30137,
+ text_301_38 = 30138,
+ text_301_39 = 30139,
+ text_301_40 = 30140,
+ text_301_41 = 30141,
+ text_301_42 = 30142,
};
} // namespace Phantom
diff --git a/engines/mads/madsv2/phantom/mads/words.h b/engines/mads/madsv2/phantom/mads/words.h
index 29655cef49d..2ddc03d3293 100644
--- a/engines/mads/madsv2/phantom/mads/words.h
+++ b/engines/mads/madsv2/phantom/mads/words.h
@@ -225,9 +225,19 @@ enum {
words_middle_door = 256,
words_dressing_gown = 257,
words_Monsieur_Brie = 258,
+ words_catwalk = 259,
+ words_grid = 260,
+ words_gridwork = 262,
words_Christine = 268,
words_woman = 269,
words_prompter_s_stand = 270,
+ words_support = 271,
+ words_other_catwalk = 272,
+ words_beam_position = 274,
+ words_lighting_instrument = 275,
+ words_tarp = 276,
+ words_catwalk_over_house = 278,
+ words_staircase_post = 279,
words_Jacques = 280,
words_gentleman = 281,
words_climb = 288,
diff --git a/engines/mads/madsv2/phantom/rooms/room301.cpp b/engines/mads/madsv2/phantom/rooms/room301.cpp
new file mode 100644
index 00000000000..ec81afed595
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room301.cpp
@@ -0,0 +1,402 @@
+/* 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 "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/camera.h"
+#include "mads/madsv2/core/global.h"
+#include "mads/madsv2/core/inter.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/matte.h"
+#include "mads/madsv2/core/quote.h"
+#include "mads/madsv2/core/sound.h"
+#include "mads/madsv2/core/speech.h"
+#include "mads/madsv2/core/text.h"
+#include "mads/madsv2/phantom/mads/quotes.h"
+#include "mads/madsv2/phantom/mads/sounds.h"
+#include "mads/madsv2/phantom/mads/speeches.h"
+#include "mads/madsv2/phantom/rooms/section3.h"
+#include "mads/madsv2/phantom/rooms/room301.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+void room_301_init() {
+ kernel.disable_fastwalk = true;
+
+ local->anim_0_running = false;
+ local->guard = false;
+ local->prevent = false;
+
+ global_speech_load(speech_raoul_catwalk);
+
+ kernel_flip_hotspot(words_cable, false);
+ kernel_flip_hotspot(words_stool, false);
+
+ /* ==================== Load Sprite Series =================== */
+
+ ss[fx_down_stairs] = kernel_load_series(kernel_name('a', 0), false);
+
+
+ /* =============== If in 1993, stamp down z's ================ */
+
+ if (global[current_year] == 1993) {
+
+ ss[fx_push] = kernel_load_series(kernel_name('a', 1), false);
+
+ ss[fx_1993_0] = kernel_load_series(kernel_name('z', 0), false);
+ ss[fx_1993_1] = kernel_load_series(kernel_name('z', 1), false);
+ ss[fx_1993_2] = kernel_load_series(kernel_name('z', 2), false);
+ ss[fx_1993_3] = kernel_load_series(kernel_name('z', 3), false);
+ ss[fx_1993_4] = kernel_load_series(kernel_name('z', 4), false);
+ ss[fx_1993_5] = kernel_load_series(kernel_name('z', 5), false);
+ ss[fx_1993_6] = kernel_load_series(kernel_name('z', 6), false);
+
+ /* two dynamic lights */
+ local->dynamic_light = kernel_add_dynamic(words_lighting_instrument, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ DYN_LIGHT_1_X, DYN_LIGHT_1_Y, DYN_LIGHT_1_XS, DYN_LIGHT_1_YS);
+ kernel_dynamic_walk(local->dynamic_light, DYN_LIGHT_1_WALK_TO_X, DYN_LIGHT_1_WALK_TO_Y, FACING_NORTHWEST);
+ local->dynamic_light = kernel_add_dynamic(words_lighting_instrument, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ DYN_LIGHT_2_X, DYN_LIGHT_2_Y, DYN_LIGHT_2_XS, DYN_LIGHT_2_YS);
+ kernel_dynamic_walk(local->dynamic_light, DYN_LIGHT_2_WALK_TO_X, DYN_LIGHT_2_WALK_TO_Y, FACING_NORTHWEST);
+
+ seq[fx_1993_0] = kernel_seq_stamp(ss[fx_1993_0], false, 1);
+ kernel_seq_depth(seq[fx_1993_0], 14);
+
+ seq[fx_1993_1] = kernel_seq_stamp(ss[fx_1993_1], false, 1);
+ kernel_seq_depth(seq[fx_1993_1], 14);
+
+ seq[fx_1993_2] = kernel_seq_stamp(ss[fx_1993_2], false, 1);
+ kernel_seq_depth(seq[fx_1993_2], 14);
+
+ seq[fx_1993_3] = kernel_seq_stamp(ss[fx_1993_3], false, 1);
+ kernel_seq_depth(seq[fx_1993_3], 14);
+
+ seq[fx_1993_4] = kernel_seq_stamp(ss[fx_1993_4], false, 1);
+ kernel_seq_depth(seq[fx_1993_4], 14);
+
+ seq[fx_1993_5] = kernel_seq_stamp(ss[fx_1993_5], false, 1);
+ kernel_seq_depth(seq[fx_1993_5], 14);
+
+ seq[fx_1993_6] = kernel_seq_stamp(ss[fx_1993_6], false, 1);
+ kernel_seq_depth(seq[fx_1993_6], 14);
+
+ kernel_flip_hotspot(words_cable, true);
+
+ } else {
+ /* two dynamic sandbags */
+ local->dynamic_sand = kernel_add_dynamic(words_sandbag, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ DYN_SAND_1_X, DYN_SAND_1_Y, DYN_SAND_1_XS, DYN_SAND_1_YS);
+ kernel_dynamic_walk(local->dynamic_sand, DYN_SAND_1_WALK_TO_X, DYN_SAND_1_WALK_TO_Y, FACING_NORTHWEST);
+ kernel_add_dynamic(words_sandbag, words_look_at, SYNTAX_SINGULAR, KERNEL_NONE,
+ DYN_SAND_2_X, DYN_SAND_2_Y, DYN_SAND_2_XS, DYN_SAND_2_YS);
+ kernel_flip_hotspot(words_stool, true);
+ kernel_flip_hotspot(words_big_prop, false);
+ }
+
+
+ /* ========================= Previous Rooms ================== */
+
+ if (previous_room == 302) {
+ player_first_walk(OFF_SCREEN_X_FROM_302, OFF_SCREEN_Y_FROM_302, FACING_WEST,
+ PLAYER_X_FROM_302, PLAYER_Y_FROM_302, FACING_EAST, true);
+ camera_jump_to(LEFT_STAGE, 0);
+
+ } else if ((previous_room == 106) || (previous_room != KERNEL_RESTORING_GAME)) {
+ player.x = PLAYER_X_FROM_106;
+ player.y = PLAYER_Y_FROM_106;
+ player.facing = FACING_WEST;
+ camera_jump_to(RIGHT_STAGE, 0);
+ }
+
+ if (!player.been_here_before) {
+ ss[fx_shadow] = kernel_load_series(kernel_name('x', 0), false);
+ seq[fx_shadow] = kernel_seq_forward(ss[fx_shadow], false, 7, 0, 0, 1);
+ kernel_seq_depth(seq[fx_shadow], 5);
+ kernel_seq_range(seq[fx_shadow], KERNEL_FIRST, KERNEL_LAST);
+ kernel_seq_trigger(seq[fx_shadow], KERNEL_TRIGGER_EXPIRE, 0, ROOM_301_SHOW_TEXT);
+ }
+ section_3_music();
+}
+
+void room_301_pre_parser(void) {
+ if (player_said_2(exit_to, catwalk_over_house)) {
+ player.walk_off_edge_to_room = 302;
+ }
+}
+
+void room_301_parser(void) {
+ if (player_said_2(climb_down, circular_staircase)) {
+ switch (kernel.trigger) {
+ case 0:
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ aa[0] = kernel_run_animation(kernel_name('d', 1), 1);
+ kernel_synch(KERNEL_ANIM, aa[0], KERNEL_PLAYER, 0);
+ break;
+
+ case 1:
+ new_room = 106;
+ break;
+ }
+ goto handled;
+ }
+
+ if (player.look_around) {
+ text_show(text_301_10);
+ goto handled;
+ }
+
+ if (player_said_1(look) || player_said_1(look_at)) {
+ if (player_said_1(grid)) {
+ text_show(text_301_11);
+ goto handled;
+ }
+
+ if (player_said_1(catwalk)) {
+ text_show(text_301_12);
+ goto handled;
+ }
+
+ if (player_said_1(side_wall)) {
+ text_show(text_301_13);
+ goto handled;
+ }
+
+ if (player_said_1(back_wall)) {
+ text_show(text_301_14);
+ goto handled;
+ }
+
+ if (player_said_1(support)) {
+ text_show(text_301_15);
+ goto handled;
+ }
+
+ if (player_said_1(act_curtain)) {
+ text_show(text_301_16);
+ goto handled;
+ }
+
+ if (player_said_1(house)) {
+ text_show(text_301_17);
+ goto handled;
+ }
+
+ if (player_said_1(other_catwalk)) {
+ text_show(text_301_18);
+ goto handled;
+ }
+
+ if (player_said_1(gridwork)) {
+ text_show(text_301_19);
+ goto handled;
+ }
+
+ if (player_said_1(beam_position)) {
+ text_show(text_301_20);
+ goto handled;
+ }
+
+ if (player_said_1(lighting_instrument)) {
+ if (global[current_year] == 1993) {
+ text_show(text_301_21);
+ } else {
+ text_show(text_301_22);
+ }
+ goto handled;
+ }
+
+ if (player_said_1(tarp)) {
+ if (global[current_year] == 1993) {
+ text_show(text_301_23);
+ } else {
+ text_show(text_301_40);
+ }
+ goto handled;
+ }
+
+ if (player_said_1(counterweight_system)) {
+ text_show(text_301_24);
+ goto handled;
+ }
+
+ if (player_said_1(sandbag)) {
+ if (player.main_object_source == STROKE_INTERFACE) {
+ text_show(text_301_25);
+ goto handled;
+ }
+ }
+
+ if (player_said_1(batten)) {
+ text_show(text_301_26);
+ goto handled;
+ }
+
+ if (player_said_1(stool)) {
+ text_show(text_301_27);
+ goto handled;
+ }
+
+ if (player_said_1(hemp)) {
+ text_show(text_301_28);
+ goto handled;
+ }
+
+ if (player_said_1(circular_staircase)) {
+ text_show(text_301_29);
+ goto handled;
+ }
+
+ if (player_said_1(catwalk_over_house)) {
+ text_show(text_301_30);
+ goto handled;
+ }
+
+ if (player_said_1(staircase_post)) {
+ text_show(text_301_31);
+ goto handled;
+ }
+
+ if (player_said_1(railing)) {
+ text_show(text_301_32);
+ goto handled;
+ }
+
+ if (player_said_1(cyclorama)) {
+ text_show(text_301_33);
+ goto handled;
+ }
+
+ if (player_said_1(big_prop)) {
+ text_show(text_301_34);
+ goto handled;
+ }
+
+ if (player_said_1(proscenium_arch)) {
+ text_show(text_301_35);
+ goto handled;
+ }
+
+ if (player_said_1(cable)) {
+ text_show(text_301_36);
+ goto handled;
+ }
+ }
+
+ if (player_said_2(take, hemp)) {
+ text_show(text_301_38);
+ goto handled;
+ }
+
+ if (player_said_2(pull, hemp)) {
+ text_show(text_301_41);
+ goto handled;
+ }
+
+ if (player_said_2(take, sandbag)) {
+ if (player.main_object_source == STROKE_INTERFACE) {
+ text_show(text_301_39);
+ goto handled;
+ }
+ }
+
+ if (player_said_2(take, tarp)) {
+ text_show(text_301_42);
+ goto handled;
+ }
+
+ goto done;
+
+handled:
+ player.command_ready = false;
+
+done:
+ ;
+}
+
+void room_301_daemon(void) {
+ if (global[done_brie_conv_203] == YES_AND_CHASE) {
+ if ((picture_view_x < 320) && (player.x < 350)) {
+ player_cancel_command();
+ player_walk(PUSH_X, PUSH_Y, FACING_NORTHWEST);
+ player_walk_trigger(ROOM_301_WALK_TO_PUSH_LOC);
+ global[done_brie_conv_203] = NO;
+ player.commands_allowed = false;
+ }
+ }
+
+ if (kernel.trigger == ROOM_301_WALK_TO_PUSH_LOC) {
+ aa[0] = kernel_run_animation(kernel_name('p', 1), 0);
+ local->anim_0_running = true;
+ player.walker_visible = false;
+ global[player_score] += 10;
+ kernel_synch(KERNEL_ANIM, aa[0], KERNEL_PLAYER, 0);
+ }
+
+ if (local->anim_0_running && !local->prevent) {
+ if (kernel_anim[aa[0]].frame == 50) {
+ global_speech_go(speech_raoul_catwalk);
+ local->prevent = true;
+ }
+ }
+
+ if (local->anim_0_running) {
+ if (kernel_anim[aa[0]].frame == 61) {
+ kernel_reset_animation(aa[0], 60);
+ if (!local->guard) {
+ sound_play(N_AllFade);
+ kernel_timing_trigger(SEVEN_SECONDS, ROOM_301_DONE_PUSHING);
+ local->guard = true;
+ }
+ }
+ }
+
+ if (kernel.trigger == ROOM_301_DONE_PUSHING) {
+ inter_turn_off_object();
+ inter_screen_update();
+ new_room = 104;
+ }
+
+ if (kernel.trigger == ROOM_301_SHOW_TEXT) {
+ kernel_timing_trigger(ONE_SECOND, ROOM_301_SHOW_TEXT + 1);
+ }
+
+ if (kernel.trigger == ROOM_301_SHOW_TEXT + 1) {
+ text_show(text_301_37);
+ }
+}
+
+void room_301_preload(void) {
+ room_init_code_pointer = room_301_init;
+ room_pre_parser_code_pointer = room_301_pre_parser;
+ room_parser_code_pointer = room_301_parser;
+ room_daemon_code_pointer = room_301_daemon;
+
+ section_3_walker();
+ section_3_interface();
+}
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/rooms/room301.h b/engines/mads/madsv2/phantom/rooms/room301.h
new file mode 100644
index 00000000000..21f34230b04
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room301.h
@@ -0,0 +1,124 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef MADS_PHANTOM_ROOM301_H
+#define MADS_PHANTOM_ROOM301_H
+
+#include "mads/madsv2/phantom/phantom.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+#define local ((Scratch *)(&game.scratch[0]))
+#define ss local->sprite
+#define seq local->sequence
+#define aa local->animation
+
+typedef struct { /* Room local variables */
+
+ int16 sprite[15]; /* Sprite series handles */
+ int16 sequence[15]; /* Sequence handles */
+ int16 animation[4]; /* Animation handles */
+ int16 dynamic_light; /* Dynamic HS for lights */
+ int16 dynamic_sand; /* Dynamic HS for sandbags */
+ int16 anim_0_running;
+ int16 guard;
+ int16 prevent;
+
+} Scratch;
+
+
+/* ========================= Sprite Series =================== */
+
+#define fx_1993_0 0 /* rm301z0 */
+#define fx_1993_1 1 /* rm301z1 */
+#define fx_1993_2 2 /* rm301z2 */
+#define fx_1993_3 3 /* rm301z3 */
+#define fx_1993_4 4 /* rm301z4 */
+#define fx_1993_5 5 /* rm301z5 */
+#define fx_1993_6 6 /* rm301z6 */
+#define fx_down_stairs 7 /* rm301a0 */
+#define fx_push 8 /* rm301a1 */
+#define fx_shadow 9 /* rm301x0 */
+
+
+/* ========================= Triggers ======================== */
+
+#define ROOM_301_WALK_TO_PUSH_LOC 60
+#define ROOM_301_SHOW_TEXT 64
+#define ROOM_301_DONE_PUSHING 70
+
+/* ========================= Other Macros ==================== */
+
+#define LEFT_STAGE 0
+#define RIGHT_STAGE 320
+
+#define OFF_SCREEN_X_FROM_302 -20
+#define OFF_SCREEN_Y_FROM_302 132
+#define PLAYER_X_FROM_302 19
+#define PLAYER_Y_FROM_302 132
+
+
+#define PLAYER_X_FROM_106 568
+#define PLAYER_Y_FROM_106 133
+
+#define WALK_TO_X_FROM_106 568
+#define WALK_TO_Y_FROM_106 133
+
+#define DYN_LIGHT_1_X 50
+#define DYN_LIGHT_1_Y 116
+#define DYN_LIGHT_1_XS 19
+#define DYN_LIGHT_1_YS 10
+#define DYN_LIGHT_1_WALK_TO_X 67
+#define DYN_LIGHT_1_WALK_TO_Y 129
+
+#define DYN_LIGHT_2_X 126
+#define DYN_LIGHT_2_Y 118
+#define DYN_LIGHT_2_XS 29
+#define DYN_LIGHT_2_YS 8
+#define DYN_LIGHT_2_WALK_TO_X 152
+#define DYN_LIGHT_2_WALK_TO_Y 129
+
+#define DYN_SAND_1_X 464
+#define DYN_SAND_1_Y 114
+#define DYN_SAND_1_XS 11
+#define DYN_SAND_1_YS 9
+#define DYN_SAND_1_WALK_TO_X 475
+#define DYN_SAND_1_WALK_TO_Y 125
+
+#define DYN_SAND_2_X 468
+#define DYN_SAND_2_Y 42
+#define DYN_SAND_2_XS 6
+#define DYN_SAND_2_YS 13
+#define DYN_SAND_2_WALK_TO_X 466
+#define DYN_SAND_2_WALK_TO_Y 58
+
+
+#define PUSH_X 256
+#define PUSH_Y 130
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif // MADS_PHANTOM_ROOM250_H
diff --git a/engines/mads/madsv2/phantom/rooms/section3.h b/engines/mads/madsv2/phantom/rooms/section3.h
new file mode 100644
index 00000000000..8b04af43a38
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/section3.h
@@ -0,0 +1,44 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 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 MADS_PHANTOM_SECTION3_H
+#define MADS_PHANTOM_SECTION3_H
+
+#include "mads/madsv2/phantom/global.h"
+#include "mads/madsv2/phantom/mads/text.h"
+#include "mads/madsv2/phantom/mads/words.h"
+#include "mads/madsv2/core/vocabh.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+extern void section_3_music();
+extern void section_3_walker();
+extern void section_3_interface();
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index f610840fe2c..81f43ab6215 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -147,6 +147,7 @@ MODULE_OBJS += \
madsv2/phantom/rooms/room207.o \
madsv2/phantom/rooms/room208.o \
madsv2/phantom/rooms/room250.o \
+ madsv2/phantom/rooms/room301.o \
madsv2/phantom/phantom.o \
madsv2/phantom/conv.o \
madsv2/phantom/main_menu.o \
Commit: 253c061160645f8eb4961a5ba482697e1f560731
https://github.com/scummvm/scummvm/commit/253c061160645f8eb4961a5ba482697e1f560731
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:46+10:00
Commit Message:
MADS: PHANTOM: Added room 302
Changed paths:
A engines/mads/madsv2/phantom/rooms/room302.cpp
A engines/mads/madsv2/phantom/rooms/room302.h
engines/mads/madsv2/phantom/mads/text.h
engines/mads/madsv2/phantom/mads/words.h
engines/mads/module.mk
diff --git a/engines/mads/madsv2/phantom/mads/text.h b/engines/mads/madsv2/phantom/mads/text.h
index 1c9649b837b..dfe95fffd1b 100644
--- a/engines/mads/madsv2/phantom/mads/text.h
+++ b/engines/mads/madsv2/phantom/mads/text.h
@@ -34,6 +34,8 @@ enum {
text_008_06 = 806,
text_008_07 = 807,
text_008_16 = 816,
+ text_008_17 = 817,
+ text_008_44 = 844,
/* Room 101 */
text_101_10 = 10110,
@@ -646,6 +648,23 @@ enum {
text_301_40 = 30140,
text_301_41 = 30141,
text_301_42 = 30142,
+
+ /* Room 302 */
+ text_302_10 = 30210,
+ text_302_11 = 30211,
+ text_302_12 = 30212,
+ text_302_13 = 30213,
+ text_302_14 = 30214,
+ text_302_15 = 30215,
+ text_302_16 = 30216,
+ text_302_17 = 30217,
+ text_302_18 = 30218,
+ text_302_19 = 30219,
+ text_302_20 = 30220,
+ text_302_21 = 30221,
+ text_302_22 = 30222,
+ text_302_23 = 30223,
+ text_302_24 = 30224
};
} // namespace Phantom
diff --git a/engines/mads/madsv2/phantom/mads/words.h b/engines/mads/madsv2/phantom/mads/words.h
index 2ddc03d3293..a66075be795 100644
--- a/engines/mads/madsv2/phantom/mads/words.h
+++ b/engines/mads/madsv2/phantom/mads/words.h
@@ -36,6 +36,7 @@ enum {
words_apron = 19,
words_backstage = 21,
words_bear_prop = 22,
+ words_blue_frame = 23,
words_book = 24,
words_bust = 25,
words_cable = 26,
diff --git a/engines/mads/madsv2/phantom/rooms/room302.cpp b/engines/mads/madsv2/phantom/rooms/room302.cpp
new file mode 100644
index 00000000000..782ab3e7ec6
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room302.cpp
@@ -0,0 +1,246 @@
+/* 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 "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/camera.h"
+#include "mads/madsv2/core/global.h"
+#include "mads/madsv2/core/inter.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/matte.h"
+#include "mads/madsv2/core/object.h"
+#include "mads/madsv2/core/quote.h"
+#include "mads/madsv2/core/sound.h"
+#include "mads/madsv2/core/speech.h"
+#include "mads/madsv2/core/text.h"
+#include "mads/madsv2/phantom/mads/inventory.h"
+#include "mads/madsv2/phantom/mads/quotes.h"
+#include "mads/madsv2/phantom/mads/sounds.h"
+#include "mads/madsv2/phantom/mads/speeches.h"
+#include "mads/madsv2/phantom/rooms/section3.h"
+#include "mads/madsv2/phantom/rooms/room302.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+void room_302_init(void) {
+ /* =================== Load sprite series ==================== */
+
+ ss[fx_blue_frame] = kernel_load_series(kernel_name('p', 0), false);
+ ss[fx_bend_down_9] = kernel_load_series("*RRD_9", false);
+
+
+ /* ================ If in 1881, put blue_frame ============= */
+
+ if (object_is_here(blue_frame)) {
+ seq[fx_blue_frame] = kernel_seq_stamp(ss[fx_blue_frame], false, 1);
+ kernel_seq_depth(seq[fx_blue_frame], 14);
+ } else {
+ kernel_flip_hotspot(words_blue_frame, false);
+ }
+
+
+ /* =============== If in 1993, stamp down z's ================ */
+
+ if (global[current_year] == 1993) {
+ ss[fx_1993] = kernel_load_series(kernel_name('z', -1), false);
+ kernel_draw_to_background(ss[fx_1993], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ }
+
+ /* ========================= Previous Rooms ================== */
+
+ if (previous_room == 303) {
+ player_first_walk(OFF_SCREEN_X_FROM_303, OFF_SCREEN_Y_FROM_303, FACING_WEST,
+ PLAYER_X_FROM_303, PLAYER_Y_FROM_303, FACING_EAST, true);
+ } else if ((previous_room == 301) || (previous_room != KERNEL_RESTORING_GAME)) {
+ player_first_walk(OFF_SCREEN_X_FROM_301, OFF_SCREEN_Y_FROM_301, FACING_WEST,
+ PLAYER_X_FROM_301, PLAYER_Y_FROM_301, FACING_WEST, true);
+ }
+ section_3_music();
+}
+
+void room_302_pre_parser(void) {
+ if (player_said_2(exit_to, catwalk)) {
+ if (inter_point_x > 160) {
+ player.walk_off_edge_to_room = 301;
+ } else {
+ player.walk_off_edge_to_room = 303;
+ }
+ }
+}
+
+void room_302_parser(void) {
+ int count = 0;
+
+ if (player_said_2(take, blue_frame) &&
+ (object_is_here(blue_frame) || kernel.trigger)) {
+ switch (kernel.trigger) {
+ case 0:
+ if (global[current_year] == 1881) {
+ if (player_has(yellow_frame)) ++count;
+ if (player_has(red_frame)) ++count;
+ if (player_has(green_frame)) ++count;
+ if (count < 3) global[player_score] += 5;
+ }
+
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_bend_down_9] = kernel_seq_pingpong(ss[fx_bend_down_9], true,
+ 5, 0, 0, 2);
+ kernel_seq_range(seq[fx_bend_down_9], 1, 5);
+ kernel_seq_player(seq[fx_bend_down_9], true);
+ kernel_seq_trigger(seq[fx_bend_down_9],
+ KERNEL_TRIGGER_SPRITE, 5, 1);
+ kernel_seq_trigger(seq[fx_bend_down_9],
+ KERNEL_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ kernel_seq_delete(seq[fx_blue_frame]);
+ kernel_flip_hotspot(words_blue_frame, false);
+ inter_give_to_player(blue_frame);
+ sound_play(N_TakeObjectSnd);
+ break;
+
+ case 2:
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_SERIES, seq[fx_bend_down_9]);
+ player.walker_visible = true;
+ kernel_timing_trigger(20, 3);
+ break;
+
+ case 3:
+ if (global[current_year] == 1881) {
+ object_examine(blue_frame, text_008_44, 0);
+ } else {
+ object_examine(blue_frame, text_008_17, 0);
+ }
+ /* You pick up the blue color frame */
+ player.commands_allowed = true;
+ break;
+ }
+ goto handled;
+ }
+
+ if (player.look_around) {
+ text_show(text_302_10);
+ goto handled;
+ }
+
+ if (player_said_1(look) || player_said_1(look_at)) {
+
+ if (player_said_1(catwalk)) {
+ text_show(text_302_11);
+ goto handled;
+ }
+
+ if (player_said_1(grid)) {
+ text_show(text_302_12);
+ goto handled;
+ }
+
+ if (player_said_1(hemp)) {
+ text_show(text_302_13);
+ goto handled;
+ }
+
+ if (player_said_1(side_wall)) {
+ text_show(text_302_14);
+ goto handled;
+ }
+
+ if (player_said_1(catwalk)) {
+ text_show(text_302_15);
+ goto handled;
+ }
+
+ if (player_said_1(railing)) {
+ text_show(text_302_16);
+ goto handled;
+ }
+
+ if (player_said_1(beam_position)) {
+ text_show(text_302_17);
+ goto handled;
+ }
+
+ if (player_said_1(lighting_instrument)) {
+ if (global[current_year] == 1993) {
+ text_show(text_302_18);
+ } else {
+ text_show(text_302_19);
+ }
+ goto handled;
+ }
+
+ if (player_said_1(blue_frame) && object_is_here(blue_frame)) {
+ if (global[current_year] == 1993) {
+ text_show(text_302_20);
+ } else {
+ text_show(text_302_21);
+ }
+ goto handled;
+ }
+
+ if (player_said_1(support)) {
+ text_show(text_302_22);
+ goto handled;
+ }
+
+ if (player_said_1(other_catwalk)) {
+ text_show(text_302_23);
+ goto handled;
+ }
+ }
+
+ if (player_said_2(take, hemp)) {
+ text_show(text_302_24);
+ goto handled;
+ }
+
+ if (player_said_2(pull, hemp)) {
+ text_show(text_301_41);
+ goto handled;
+ }
+
+ goto done;
+
+handled:
+ player.command_ready = false;
+
+done:
+ ;
+}
+
+void room_302_preload(void) {
+ room_init_code_pointer = room_302_init;
+ room_pre_parser_code_pointer = room_302_pre_parser;
+ room_parser_code_pointer = room_302_parser;
+ room_daemon_code_pointer = NULL;
+
+ section_3_walker();
+ section_3_interface();
+}
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/rooms/room302.h b/engines/mads/madsv2/phantom/rooms/room302.h
new file mode 100644
index 00000000000..7ba5410b9e8
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room302.h
@@ -0,0 +1,75 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef MADS_PHANTOM_ROOM302_H
+#define MADS_PHANTOM_ROOM302_H
+
+#include "mads/madsv2/phantom/phantom.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+#define local ((Scratch *)(&game.scratch[0]))
+#define ss local->sprite
+#define seq local->sequence
+#define aa local->animation
+
+typedef struct { /* Room local variables */
+
+ int16 sprite[15]; /* Sprite series handles */
+ int16 sequence[15]; /* Sequence handles */
+ int16 animation[4]; /* Animation handles */
+
+} Scratch;
+
+
+/* ========================= Sprite Series =================== */
+
+#define fx_1993 0 /* rm302z */
+#define fx_bend_down_9 1 /* rrd_9 */
+#define fx_blue_frame 2 /* rm302p0 */
+
+
+
+/* ========================= Triggers ======================== */
+
+
+
+/* ========================= Other Macros ==================== */
+
+#define OFF_SCREEN_X_FROM_303 -20
+#define OFF_SCREEN_Y_FROM_303 134
+#define PLAYER_X_FROM_303 15
+#define PLAYER_Y_FROM_303 134
+
+#define OFF_SCREEN_X_FROM_301 340
+#define OFF_SCREEN_Y_FROM_301 134
+#define PLAYER_X_FROM_301 297
+#define PLAYER_Y_FROM_301 134
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif // MADS_PHANTOM_ROOM250_H
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index 81f43ab6215..d930647c171 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -148,6 +148,7 @@ MODULE_OBJS += \
madsv2/phantom/rooms/room208.o \
madsv2/phantom/rooms/room250.o \
madsv2/phantom/rooms/room301.o \
+ madsv2/phantom/rooms/room302.o \
madsv2/phantom/phantom.o \
madsv2/phantom/conv.o \
madsv2/phantom/main_menu.o \
Commit: 9c1547975ea1fd3a271d19d6f19533d6da130d57
https://github.com/scummvm/scummvm/commit/9c1547975ea1fd3a271d19d6f19533d6da130d57
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:46+10:00
Commit Message:
MADS: PHANTOM: Added room 303
Changed paths:
A engines/mads/madsv2/phantom/rooms/room303.cpp
A engines/mads/madsv2/phantom/rooms/room303.h
engines/mads/madsv2/phantom/mads/inventory.h
engines/mads/madsv2/phantom/mads/sounds.h
engines/mads/madsv2/phantom/mads/text.h
engines/mads/madsv2/phantom/mads/words.h
engines/mads/module.mk
diff --git a/engines/mads/madsv2/phantom/mads/inventory.h b/engines/mads/madsv2/phantom/mads/inventory.h
index c0bfdb88f7c..0481da7e120 100644
--- a/engines/mads/madsv2/phantom/mads/inventory.h
+++ b/engines/mads/madsv2/phantom/mads/inventory.h
@@ -37,6 +37,7 @@ enum {
fire_axe = 5,
small_note = 6,
rope = 7,
+ sword = 8,
envelope = 9,
ticket = 10,
parchment = 12,
diff --git a/engines/mads/madsv2/phantom/mads/sounds.h b/engines/mads/madsv2/phantom/mads/sounds.h
index 9c6883764a1..6341e58b8d0 100644
--- a/engines/mads/madsv2/phantom/mads/sounds.h
+++ b/engines/mads/madsv2/phantom/mads/sounds.h
@@ -47,7 +47,8 @@ enum {
N_SandbagThud = 70,
N_KeyTurnSnd = 71,
N_DoorHandle002 = 72,
- N_DoorHandle = 73
+ N_DoorHandle = 73,
+ N_WomanScream003 = 74
};
} // namespace Phantom
diff --git a/engines/mads/madsv2/phantom/mads/text.h b/engines/mads/madsv2/phantom/mads/text.h
index dfe95fffd1b..59e7e137b43 100644
--- a/engines/mads/madsv2/phantom/mads/text.h
+++ b/engines/mads/madsv2/phantom/mads/text.h
@@ -35,6 +35,7 @@ enum {
text_008_07 = 807,
text_008_16 = 816,
text_008_17 = 817,
+ text_008_18 = 818,
text_008_44 = 844,
/* Room 101 */
@@ -664,7 +665,31 @@ enum {
text_302_21 = 30221,
text_302_22 = 30222,
text_302_23 = 30223,
- text_302_24 = 30224
+ text_302_24 = 30224,
+
+ /* Room 303 */
+ text_303_10 = 30310,
+ text_303_11 = 30311,
+ text_303_12 = 30312,
+ text_303_13 = 30313,
+ text_303_14 = 30314,
+ text_303_15 = 30315,
+ text_303_16 = 30316,
+ text_303_17 = 30317,
+ text_303_18 = 30318,
+ text_303_19 = 30319,
+ text_303_20 = 30320,
+ text_303_21 = 30321,
+ text_303_22 = 30322,
+ text_303_23 = 30323,
+ text_303_24 = 30324,
+ text_303_25 = 30325,
+ text_303_26 = 30326,
+ text_303_27 = 30327,
+ text_303_29 = 30329,
+ text_303_30 = 30330,
+ text_303_31 = 30331,
+
};
} // namespace Phantom
diff --git a/engines/mads/madsv2/phantom/mads/words.h b/engines/mads/madsv2/phantom/mads/words.h
index a66075be795..1f9fab1a2fb 100644
--- a/engines/mads/madsv2/phantom/mads/words.h
+++ b/engines/mads/madsv2/phantom/mads/words.h
@@ -47,6 +47,7 @@ enum {
words_chair = 31,
words_circular_staircase = 32,
words_climb_down = 33,
+ words_climb_into = 34,
words_climb_through = 35,
words_column_prop = 36,
words_conductor_s_stand = 37,
@@ -82,6 +83,7 @@ enum {
words_key = 85,
words_lamp = 86,
words_lantern = 87,
+ words_large_note = 88,
words_leg = 90,
words_letter = 91,
words_light_fixture = 92,
@@ -229,6 +231,7 @@ enum {
words_catwalk = 259,
words_grid = 260,
words_gridwork = 262,
+ words_ductwork = 263,
words_Christine = 268,
words_woman = 269,
words_prompter_s_stand = 270,
@@ -242,6 +245,8 @@ enum {
words_Jacques = 280,
words_gentleman = 281,
words_climb = 288,
+ words_chandelier_trap = 289,
+ words_piece_of_wood = 290,
words_Charles = 298,
words_prompter_s_seat = 300,
words_lever = 301,
@@ -257,6 +262,7 @@ enum {
words_vase = 341,
words_clothes_dummy = 342,
words_Edgar_Degas = 385,
+ words_chandelier_cable = 386,
words_hook = 390,
words_paper = 399
};
diff --git a/engines/mads/madsv2/phantom/rooms/room303.cpp b/engines/mads/madsv2/phantom/rooms/room303.cpp
new file mode 100644
index 00000000000..cbf078384e2
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room303.cpp
@@ -0,0 +1,353 @@
+/* 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 "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/camera.h"
+#include "mads/madsv2/core/global.h"
+#include "mads/madsv2/core/inter.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/matte.h"
+#include "mads/madsv2/core/object.h"
+#include "mads/madsv2/core/quote.h"
+#include "mads/madsv2/core/rail.h"
+#include "mads/madsv2/core/sound.h"
+#include "mads/madsv2/core/speech.h"
+#include "mads/madsv2/core/text.h"
+#include "mads/madsv2/phantom/mads/inventory.h"
+#include "mads/madsv2/phantom/mads/quotes.h"
+#include "mads/madsv2/phantom/mads/sounds.h"
+#include "mads/madsv2/phantom/mads/speeches.h"
+#include "mads/madsv2/phantom/rooms/section3.h"
+#include "mads/madsv2/phantom/rooms/room303.h"
+#include "mads/madsv2/phantom/conv.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+void room_303_init(void) {
+ local->anim_0_running = false;
+ local->frame_guard = false;
+
+ if (global[right_door_is_open_504]) {
+ conv_get(CONV_MISC);
+ }
+
+ /* ==================== Load Sprite Series =================== */
+
+ if (global[current_year] == 1993) {
+ ss[fx_1993] = kernel_load_series(kernel_name('z', -1), false);
+ ss[fx_large_note] = kernel_load_series(kernel_name('p', 0), false);
+ }
+
+ if ((object_is_here(large_note)) && (global[current_year] == 1993)) {
+ seq[fx_large_note] = kernel_seq_stamp(ss[fx_large_note], false, 1);
+ kernel_seq_depth(seq[fx_large_note], 4);
+ } else {
+ kernel_flip_hotspot(words_large_note, false);
+ }
+
+ /* =============== If in 1993, stamp down z's ================ */
+
+ if (global[current_year] == 1993) {
+ kernel_draw_to_background(ss[fx_1993], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+
+ } else {
+ local->dynamic_hemp = kernel_add_dynamic(words_chandelier_cable, words_climb_down, SYNTAX_SINGULAR, KERNEL_NONE,
+ DYN_HEMP_X, DYN_HEMP_Y, DYN_HEMP_XS, DYN_HEMP_YS);
+ kernel_dynamic_walk(local->dynamic_hemp, DYN_HEMP_WALK_TO_X, DYN_HEMP_WALK_TO_Y, FACING_NORTHWEST);
+ kernel_dynamic_hot[local->dynamic_hemp].prep = PREP_ON;
+ kernel_dynamic_cursor(local->dynamic_hemp, 3);
+ }
+
+ /* ========================= Previous Rooms ================== */
+
+ if (previous_room == 307) {
+ player_first_walk(OFF_SCREEN_X_FROM_307, OFF_SCREEN_Y_FROM_307, FACING_EAST,
+ PLAYER_X_FROM_307, PLAYER_Y_FROM_307, FACING_EAST, true);
+
+ } else if (previous_room == 304) {
+ aa[0] = kernel_run_animation(kernel_name('u', 1), ROOM_303_DONE_CLIMBING_UP);
+ player.commands_allowed = false;
+ player.walker_visible = false;
+
+ } else if (previous_room == 305) {
+ inter_give_to_player(sword);
+ player.x = PLAYER_X_FROM_305;
+ player.y = PLAYER_Y_FROM_305;
+ player.facing = FACING_SOUTHWEST;
+
+ } else if ((previous_room == 302) || (previous_room != KERNEL_RESTORING_GAME)) {
+ player_first_walk(OFF_SCREEN_X_FROM_302, OFF_SCREEN_Y_FROM_302, FACING_WEST,
+ PLAYER_X_FROM_302, PLAYER_Y_FROM_302, FACING_WEST, true);
+ }
+
+ rail_disconnect_line(5, 9);
+ rail_disconnect_line(5, 12);
+ rail_disconnect_line(5, 8);
+ rail_disconnect_line(6, 3);
+ rail_disconnect_line(6, 2);
+ rail_disconnect_line(11, 3);
+ rail_disconnect_line(11, 4);
+ rail_disconnect_line(10, 2);
+ rail_disconnect_line(4, 9);
+ rail_disconnect_line(8, 0);
+
+ section_3_music();
+}
+
+void room_303_pre_parser(void) {
+ if (player_said_2(exit_to, catwalk)) {
+ if (!global[right_door_is_open_504]) {
+ if (inter_point_x > 160) {
+ player.walk_off_edge_to_room = 302;
+ } else {
+ player.walk_off_edge_to_room = 307;
+ }
+ }
+ }
+
+ if (player_said_2(climb_into, hole) || player_said_2(climb_down, chandelier_cable)) {
+ player_walk(CLIMB_X, CLIMB_Y, FACING_SOUTHWEST);
+ }
+}
+
+void room_303_parser(void) {
+ if (((player_said_2(take, large_note)) && (object_is_here(large_note))) || ((kernel.trigger > 0) && kernel.trigger < 3)) {
+ switch (kernel.trigger) {
+ case (0):
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ aa[0] = kernel_run_animation(kernel_name('n', 1), 1);
+ local->anim_0_running = true;
+ kernel_synch(KERNEL_ANIM, aa[0], KERNEL_PLAYER, 0);
+ global[player_score] += 5;
+ break;
+
+ case 1:
+ local->anim_0_running = false;
+ player.walker_visible = true;
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_ANIM, aa[0]);
+ kernel_timing_trigger(20, 2);
+ break;
+
+ case 2:
+ object_examine(large_note, text_008_18, 7);
+ /* You pick up the large note */
+ player.commands_allowed = true;
+ break;
+ }
+ goto handled;
+ }
+
+ if (player_said_2(climb_into, hole) || player_said_2(climb_down, chandelier_cable)) {
+ if (global[current_year] == 1881) {
+ switch (kernel.trigger) {
+ case 0:
+ if (global[right_door_is_open_504]) {
+ text_show(text_303_31);
+ }
+ aa[0] = kernel_run_animation(kernel_name('d', 1), 3);
+ /* chose 3 because other triggers above use 3 */
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ kernel_synch(KERNEL_ANIM, aa[0], KERNEL_PLAYER, 0);
+ break;
+
+ case 3:
+ new_room = 304;
+ break;
+ }
+ } else {
+ text_show(text_303_25);
+ /* the rope is cut, you would fall to your death */
+ }
+ goto handled;
+ }
+
+
+ if (player_said_2(exit_to, catwalk)) {
+ if (global[right_door_is_open_504]) {
+ if (global_prefer_roland) {
+ sound_play(N_WomanScream003);
+ } else {
+ global_speech_go(speech_woman_scream);
+ }
+ conv_run(CONV_MISC);
+ conv_export_value(4);
+ goto handled;
+ }
+ }
+
+
+ if (player.look_around) {
+ text_show(text_303_10);
+ goto handled;
+ }
+
+ if (player_said_1(look) || player_said_1(look_at)) {
+
+ if (player_said_2(exit_to, catwalk)) {
+ text_show(text_303_16);
+ goto handled;
+ }
+
+ if (player_said_1(catwalk)) {
+ text_show(text_303_11);
+ goto handled;
+ }
+
+ if (player_said_1(grid)) {
+ text_show(text_303_12);
+ goto handled;
+ }
+
+ if (player_said_1(chandelier_cable)) {
+ if (global[current_year] == 1993) {
+ text_show(text_303_17);
+ } else {
+ if (global[right_door_is_open_504]) {
+ text_show(text_303_30);
+ } else {
+ text_show(text_303_29);
+ }
+ }
+ goto handled;
+ }
+
+ if (player_said_1(hemp)) {
+ text_show(text_303_13);
+ goto handled;
+ }
+
+ if (player_said_1(back_wall)) {
+ text_show(text_303_14);
+ goto handled;
+ }
+
+ if (player_said_1(ductwork)) {
+ text_show(text_303_15);
+ goto handled;
+ }
+
+ if (player_said_1(crate)) {
+ text_show(text_303_18);
+ goto handled;
+ }
+
+ if (player_said_1(support)) {
+ text_show(text_303_19);
+ goto handled;
+ }
+
+ if (player_said_1(piece_of_wood)) {
+ text_show(text_303_20);
+ goto handled;
+ }
+
+ if (player_said_1(railing)) {
+ text_show(text_303_21);
+ goto handled;
+ }
+
+ if (player_said_1(chandelier_trap)) {
+ text_show(text_303_22);
+ goto handled;
+ }
+
+ if (player_said_1(hole)) {
+ if (global[current_year] == 1993) {
+ text_show(text_303_26);
+ } else {
+ text_show(text_303_23);
+ }
+ goto handled;
+ }
+
+ if (player_said_1(large_note) && object_is_here(large_note)) {
+ text_show(text_303_24);
+ goto handled;
+ }
+ }
+
+ if (player_said_2(walk_to, hole)) {
+ text_show(text_303_25);
+ goto handled;
+ }
+
+ if (player_said_2(take, hemp)) {
+ text_show(text_303_27);
+ goto handled;
+ }
+
+ if (player_said_2(pull, hemp)) {
+ text_show(text_301_41);
+ goto handled;
+ }
+
+ goto done;
+
+handled:
+ player.command_ready = false;
+
+done:
+ ;
+}
+
+void room_303_daemon(void) {
+ if (kernel.trigger == ROOM_303_DONE_CLIMBING_UP) {
+ player.x = CLIMB_X;
+ player.y = CLIMB_Y;
+ player.commands_allowed = true;
+ player.walker_visible = true;
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_ANIM, aa[0]);
+ player_demand_facing(FACING_SOUTHWEST);
+ }
+
+ if (local->anim_0_running) {
+ if ((kernel_anim[aa[0]].frame >= 6) && (!local->frame_guard)) {
+ local->frame_guard = true;
+ kernel_seq_delete(seq[fx_large_note]);
+ kernel_flip_hotspot(words_large_note, false);
+ inter_give_to_player(large_note);
+ sound_play(N_TakeObjectSnd);
+ }
+ }
+}
+
+void room_303_preload(void) {
+ room_init_code_pointer = room_303_init;
+ room_pre_parser_code_pointer = room_303_pre_parser;
+ room_parser_code_pointer = room_303_parser;
+ room_daemon_code_pointer = room_303_daemon;
+
+ section_3_walker();
+ section_3_interface();
+
+ vocab_make_active(words_chandelier_cable);
+ vocab_make_active(words_climb_down);
+}
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/rooms/room303.h b/engines/mads/madsv2/phantom/rooms/room303.h
new file mode 100644
index 00000000000..4200517d434
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room303.h
@@ -0,0 +1,92 @@
+/* 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 MADS_PHANTOM_ROOM303_H
+#define MADS_PHANTOM_ROOM303_H
+
+#include "mads/madsv2/phantom/phantom.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+#define local ((Scratch *)(&game.scratch[0]))
+#define ss local->sprite
+#define seq local->sequence
+#define aa local->animation
+
+typedef struct { /* Room local variables */
+
+ int16 sprite[15]; /* Sprite series handles */
+ int16 sequence[15]; /* Sequence handles */
+ int16 animation[4]; /* Animation handles */
+ int16 dynamic_hemp; /* Dynamic HS for hemp */
+ int16 anim_0_running;
+ int16 frame_guard;
+
+} Scratch;
+
+
+/* ========================= Sprite Series =================== */
+
+#define fx_1993 0 /* rm303z */
+#define fx_large_note 2 /* rm303p0 */
+
+
+/* ========================= Triggers ======================== */
+
+#define ROOM_303_DONE_CLIMBING_UP 60
+
+
+/* ========================= Other Macros ==================== */
+
+#define OFF_SCREEN_X_FROM_307 -20
+#define OFF_SCREEN_Y_FROM_307 135
+#define PLAYER_X_FROM_307 16
+#define PLAYER_Y_FROM_307 135
+
+#define OFF_SCREEN_X_FROM_302 340
+#define OFF_SCREEN_Y_FROM_302 136
+#define PLAYER_X_FROM_302 303
+#define PLAYER_Y_FROM_302 136
+
+#define PLAYER_X_FROM_305 117
+#define PLAYER_Y_FROM_305 92
+
+#define DYN_HEMP_X 74
+#define DYN_HEMP_Y 92
+#define DYN_HEMP_XS 7
+#define DYN_HEMP_YS 12
+#define DYN_HEMP_WALK_TO_X 95
+#define DYN_HEMP_WALK_TO_Y 107
+
+#define CLIMB_X 110
+#define CLIMB_Y 95
+
+#define CONV_MISC 26
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif // MADS_PHANTOM_ROOM250_H
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index d930647c171..9b5ca69a83e 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -149,6 +149,7 @@ MODULE_OBJS += \
madsv2/phantom/rooms/room250.o \
madsv2/phantom/rooms/room301.o \
madsv2/phantom/rooms/room302.o \
+ madsv2/phantom/rooms/room303.o \
madsv2/phantom/phantom.o \
madsv2/phantom/conv.o \
madsv2/phantom/main_menu.o \
Commit: 5e6eade9758cbc17d1c570f08cf06f5fb400e3c2
https://github.com/scummvm/scummvm/commit/5e6eade9758cbc17d1c570f08cf06f5fb400e3c2
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:47+10:00
Commit Message:
MADS: PHANTOM: Added room 304
Changed paths:
A engines/mads/madsv2/phantom/rooms/room304.cpp
A engines/mads/madsv2/phantom/rooms/room304.h
engines/mads/madsv2/phantom/conv.h
engines/mads/madsv2/phantom/mads/text.h
engines/mads/madsv2/phantom/mads/words.h
engines/mads/module.mk
diff --git a/engines/mads/madsv2/phantom/conv.h b/engines/mads/madsv2/phantom/conv.h
index 0f2e55edef3..1a5d9d83fbc 100644
--- a/engines/mads/madsv2/phantom/conv.h
+++ b/engines/mads/madsv2/phantom/conv.h
@@ -264,6 +264,13 @@ enum {
conv022_leave_b_b = 29
};
+enum {
+ conv023_unhand_b_b = 3,
+ conv023_okay_b_b = 6,
+ conv023_okay_abc = 7,
+ conv023_die_b_b = 12
+};
+
struct ConvData {
int16 node_count;
int16 dialog_count;
diff --git a/engines/mads/madsv2/phantom/mads/text.h b/engines/mads/madsv2/phantom/mads/text.h
index 59e7e137b43..acdbf94484e 100644
--- a/engines/mads/madsv2/phantom/mads/text.h
+++ b/engines/mads/madsv2/phantom/mads/text.h
@@ -688,8 +688,17 @@ enum {
text_303_27 = 30327,
text_303_29 = 30329,
text_303_30 = 30330,
- text_303_31 = 30331,
+ text_303_31 = 30331
+};
+enum {
+ text_304_10 = 30410,
+ text_304_11 = 30411,
+ text_304_12 = 30412,
+ text_304_13 = 30413,
+ text_304_14 = 30414,
+ text_304_15 = 30415,
+ text_304_16 = 30416
};
} // namespace Phantom
diff --git a/engines/mads/madsv2/phantom/mads/words.h b/engines/mads/madsv2/phantom/mads/words.h
index 1f9fab1a2fb..b579f9a4894 100644
--- a/engines/mads/madsv2/phantom/mads/words.h
+++ b/engines/mads/madsv2/phantom/mads/words.h
@@ -199,6 +199,7 @@ enum {
words_sheers = 221,
words_tapestry = 222,
words_overdoor_medallion = 223,
+ words_latticework = 224,
words_decorative_molding = 225,
words_left_archway = 227,
words_right_archway = 229,
@@ -232,6 +233,8 @@ enum {
words_grid = 260,
words_gridwork = 262,
words_ductwork = 263,
+ words_opening = 264,
+ words_dome = 265,
words_Christine = 268,
words_woman = 269,
words_prompter_s_stand = 270,
diff --git a/engines/mads/madsv2/phantom/rooms/room304.cpp b/engines/mads/madsv2/phantom/rooms/room304.cpp
new file mode 100644
index 00000000000..399e5e33759
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room304.cpp
@@ -0,0 +1,488 @@
+/* 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 "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/camera.h"
+#include "mads/madsv2/core/global.h"
+#include "mads/madsv2/core/imath.h"
+#include "mads/madsv2/core/inter.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/matte.h"
+#include "mads/madsv2/core/object.h"
+#include "mads/madsv2/core/quote.h"
+#include "mads/madsv2/core/rail.h"
+#include "mads/madsv2/core/sound.h"
+#include "mads/madsv2/core/speech.h"
+#include "mads/madsv2/core/text.h"
+#include "mads/madsv2/phantom/mads/inventory.h"
+#include "mads/madsv2/phantom/mads/quotes.h"
+#include "mads/madsv2/phantom/mads/sounds.h"
+#include "mads/madsv2/phantom/mads/speeches.h"
+#include "mads/madsv2/phantom/rooms/section3.h"
+#include "mads/madsv2/phantom/rooms/room304.h"
+#include "mads/madsv2/phantom/conv.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+void room_304_init() {
+ local->raoul_look_count = 0;
+ player.x = 0;
+
+ if (previous_room != KERNEL_RESTORING_GAME) {
+ local->anim_0_running = false;
+ local->anim_1_running = false;
+ local->anim_2_running = false;
+ }
+
+ /* =================== Load conversations ==================== */
+
+ if (global[right_door_is_open_504]) {
+ conv_get(CONV_FIGHT_23);
+ }
+
+
+ /* ===================== Stamp down chan ===================== */
+
+ if (!global[right_door_is_open_504]) {
+ ss[fx_chan] = kernel_load_series(kernel_name('f', 1), false);
+ seq[fx_chan] = kernel_seq_stamp(ss[fx_chan], false, KERNEL_FIRST);
+ kernel_seq_depth(seq[fx_chan], 1);
+
+ aa[0] = kernel_run_animation(kernel_name('n', 1), 0);
+ local->anim_0_running = true;
+ local->raoul_action = RAOUL_OTHER;
+ player.commands_allowed = false;
+
+ } else {
+
+ kernel_set_interface_mode(INTER_LIMITED_SENTENCES);
+
+ /* viewing_at_y = ((video_y - display_y) >> 1); */
+
+ if (previous_room == 305) {
+ ss[fx_chan_tilt] = kernel_load_series(kernel_name('f', 0), false);
+ kernel_draw_to_background(ss[fx_chan_tilt], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+
+ player.commands_allowed = false;
+ aa[1] = kernel_run_animation(kernel_name('f', 1), 0);
+ local->anim_1_running = true;
+ kernel_reset_animation(aa[1], 138);
+
+ } else {
+
+ ss[fx_chan_tilt] = kernel_load_series(kernel_name('f', 0), false);
+ kernel_draw_to_background(ss[fx_chan_tilt], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+
+ aa[1] = kernel_run_animation(kernel_name('f', 1), 0);
+ local->anim_1_running = true;
+ local->phantom_action = CONV23_PHANTOM_DAAE;
+
+ aa[2] = kernel_run_animation(kernel_name('r', 1), 0);
+ local->anim_2_running = true;
+ local->raoul_fight_action = CONV23_RAOUL_OTHER;
+
+ player.commands_allowed = false;
+ local->raoul_fight_talk_count = 0;
+
+ global[player_score] += 10;
+
+ conv_run(CONV_FIGHT_23);
+ conv_hold();
+ }
+ }
+
+
+ if (previous_room == KERNEL_RESTORING_GAME) {
+ if (!global[right_door_is_open_504]) {
+ kernel_reset_animation(aa[0], 53);
+ player.commands_allowed = true;
+ }
+ }
+
+ player.walker_visible = false;
+
+ section_3_music();
+}
+
+static void process_conversation_23() {
+ switch (player_verb) {
+ case conv023_unhand_b_b:
+ if (local->phantom_action != CONV23_PHANTOM_LET_GO) {
+ local->raoul_fight_action = CONV23_RAOUL_TALK;
+ }
+ break;
+
+ case conv023_okay_b_b:
+ if (local->phantom_action != CONV23_PHANTOM_LET_GO) {
+ local->raoul_fight_action = CONV23_RAOUL_OTHER;
+ }
+ conv_hold();
+ break;
+
+ case conv023_die_b_b:
+ local->phantom_action = CONV23_PHANTOM_FIGHT;
+ /* conv_hold (); */
+ break;
+
+ case conv023_okay_abc:
+ local->phantom_action = CONV23_PHANTOM_LET_GO;
+ conv_hold();
+ break;
+
+ default:
+ break;
+ }
+
+ local->raoul_fight_talk_count = 0;
+}
+
+void room_304_parser() {
+ if (conv_control.running == CONV_FIGHT_23) {
+ process_conversation_23();
+ goto handled;
+ }
+
+ if (player_said_2(climb_through, opening) || player_said_2(climb, chandelier_cable)) {
+ local->raoul_action = RAOUL_CLIMB_UP;
+ goto handled;
+ }
+
+ if (player.look_around) {
+ text_show(text_304_10);
+ goto handled;
+ }
+
+ if (player_said_1(look) || player_said_1(look_at)) {
+ if (player_said_1(ceiling)) {
+ text_show(text_304_11);
+ goto handled;
+ }
+
+ if (player_said_1(dome)) {
+ text_show(text_304_12);
+ goto handled;
+ }
+
+ if (player_said_1(latticework)) {
+ text_show(text_304_13);
+ goto handled;
+ }
+
+ if (player_said_1(opening)) {
+ text_show(text_304_14);
+ goto handled;
+ }
+
+ if (player_said_1(chandelier)) {
+ text_show(text_304_15);
+ goto handled;
+ }
+
+ if (player_said_1(chandelier_cable)) {
+ text_show(text_304_16);
+ goto handled;
+ }
+ }
+
+ goto done;
+
+handled:
+ player.command_ready = false;
+
+done:
+ ;
+}
+
+static void handle_animation_raoul() {
+ int random;
+ int raoul_reset_frame;
+
+ if (kernel_anim[aa[0]].frame != local->raoul_frame) {
+ local->raoul_frame = kernel_anim[aa[0]].frame;
+ raoul_reset_frame = -1;
+
+ switch (local->raoul_frame) {
+ case 53: /* end of climbing up rope */
+ new_room = 303;
+ break;
+
+ case 20: /* end of climbing down */
+ player.commands_allowed = true;
+ raoul_reset_frame = 53;
+ break;
+
+ case 54: /* end of look straight */
+ case 55: /* end of look left */
+ case 56: /* end of look right */
+
+ switch (local->raoul_action) {
+ case RAOUL_CLIMB_UP:
+ raoul_reset_frame = 20; /* climb up rope */
+ player.commands_allowed = false;
+ break;
+
+ default: /* look around */
+ random = imath_random(1, 50);
+ switch (local->raoul_frame) {
+ case 54: /* looking straight */
+ if (random == 1) raoul_reset_frame = 54; /* look left */
+ else if (random == 2) raoul_reset_frame = 55; /* look right */
+ else raoul_reset_frame = local->raoul_frame - 1;
+ break;
+
+ case 55: /* looking left */
+ if (random == 1) raoul_reset_frame = 54; /* look left */
+ else if (random == 2) raoul_reset_frame = 53; /* look straight */
+ else raoul_reset_frame = local->raoul_frame - 1;
+ break;
+
+ case 56: /* looking right */
+ if (random == 1) raoul_reset_frame = 55; /* look right */
+ else if (random == 2) raoul_reset_frame = 53; /* look straight */
+ else raoul_reset_frame = local->raoul_frame - 1;
+ break;
+ }
+ break;
+ }
+ break;
+ }
+
+ if (raoul_reset_frame >= 0) {
+ kernel_reset_animation(aa[0], raoul_reset_frame);
+ local->raoul_frame = raoul_reset_frame;
+ }
+ }
+}
+
+static void handle_animation_phantom() {
+ int random;
+ int phantom_reset_frame;
+
+ if (kernel_anim[aa[1]].frame != local->phantom_frame) {
+ local->phantom_frame = kernel_anim[aa[1]].frame;
+ phantom_reset_frame = -1;
+
+ switch (local->phantom_frame) {
+
+ case 25:
+ conv_release();
+ break;
+
+ case 47:
+ local->raoul_fight_action = CONV23_RAOUL_OTHER;
+ break;
+
+ case 137:
+ player.x = 100;
+ new_room = 305;
+ /* Phantom is on top of Raoul */
+ break;
+
+ case 176:
+ player.x = 200;
+ new_room = 305;
+ /* Raoul is on top of Phantom */
+ break;
+
+ case 7: /* end of struggle point */
+ case 11: /* end of struggle point */
+ phantom_reset_frame = imath_random(6, 7);
+
+ if (local->phantom_action == CONV23_PHANTOM_LET_GO) {
+ phantom_reset_frame = 7;
+ }
+ break;
+
+ case 9: /* end of struggle point */
+ case 15: /* end of struggle point */
+ random = imath_random(1, 3);
+ switch (random) {
+ case 1:
+ phantom_reset_frame = 8;
+ break;
+
+ case 2:
+ phantom_reset_frame = 9;
+ break;
+
+ case 3:
+ phantom_reset_frame = 11;
+ break;
+ }
+
+ if (local->phantom_action == CONV23_PHANTOM_LET_GO) {
+ phantom_reset_frame = 11;
+ }
+ break;
+
+ case 13: /* end of struggle point */
+ case 24: /* end of struggle point */
+ random = imath_random(1, 3);
+ switch (random) {
+ case 1:
+ phantom_reset_frame = 12;
+ break;
+
+ case 2:
+ phantom_reset_frame = 13;
+ break;
+
+ case 3:
+ phantom_reset_frame = 16;
+ break;
+ }
+
+ if (local->phantom_action == CONV23_PHANTOM_LET_GO) {
+ phantom_reset_frame = 16;
+ }
+ break;
+
+ case 20: /* end of struggle point */
+ random = imath_random(1, 2);
+ switch (random) {
+ case 1:
+ phantom_reset_frame = 19;
+ break;
+
+ case 2:
+ phantom_reset_frame = 20;
+ break;
+ }
+
+ if (local->phantom_action == CONV23_PHANTOM_LET_GO) {
+ phantom_reset_frame = 24;
+ }
+ break;
+
+ case 59:
+ if (local->phantom_action == CONV23_PHANTOM_FIGHT) {
+ phantom_reset_frame = 59;
+ } else {
+ phantom_reset_frame = 58;
+ }
+ break;
+
+ case 60:
+ player.commands_allowed = false;
+ break;
+
+ case 80:
+ inter_move_object(sword, NOWHERE);
+ break;
+
+ }
+
+ if (phantom_reset_frame >= 0) {
+ kernel_reset_animation(aa[1], phantom_reset_frame);
+ local->phantom_frame = phantom_reset_frame;
+ }
+ }
+}
+
+static void handle_animation_raoul_fight() {
+ int raoul_fight_reset_frame;
+
+ if (kernel_anim[aa[2]].frame != local->raoul_fight_frame) {
+ local->raoul_fight_frame = kernel_anim[aa[2]].frame;
+ raoul_fight_reset_frame = -1;
+
+ switch (local->raoul_fight_frame) {
+ case 22: /* almost end of climbing down rope */
+ conv_release();
+ break;
+
+ case 23: /* almost end of climbing down rope */
+ if (local->raoul_fight_action != CONV23_RAOUL_TALK) {
+ raoul_fight_reset_frame = 22;
+ }
+ break;
+
+ case 25: /* end of climbing down rope & talk 1*/
+ case 26: /* end of talk 2 */
+ case 27: /* end of talk 3 */
+ if (local->raoul_fight_action == CONV23_RAOUL_TALK) {
+ raoul_fight_reset_frame = imath_random(24, 26);
+ ++local->raoul_fight_talk_count;
+ if (local->raoul_fight_talk_count > 17) {
+ raoul_fight_reset_frame = 24;
+ }
+ }
+ break;
+
+ case 28:
+ local->raoul_fight_action = CONV23_RAOUL_TALK;
+ break;
+
+ case 45:
+ conv_release();
+ break;
+
+ case 46: /* end of jumping down to second level and talk 1 */
+ case 47: /* end of talk 2 */
+ case 48: /* end of talk 3 */
+ if (local->raoul_fight_action == CONV23_RAOUL_TALK) {
+ raoul_fight_reset_frame = imath_random(45, 47);
+ ++local->raoul_fight_talk_count;
+ if (local->raoul_fight_talk_count > 17) {
+ raoul_fight_reset_frame = 45;
+ }
+ }
+ break;
+ }
+
+ if (raoul_fight_reset_frame >= 0) {
+ kernel_reset_animation(aa[2], raoul_fight_reset_frame);
+ local->raoul_fight_frame = raoul_fight_reset_frame;
+ }
+ }
+}
+
+void room_304_daemon() {
+ if (local->anim_0_running) {
+ handle_animation_raoul();
+ }
+
+ if (local->anim_1_running) {
+ handle_animation_phantom();
+ }
+
+ if (local->anim_2_running) {
+ handle_animation_raoul_fight();
+ }
+}
+
+void room_304_preload() {
+ room_init_code_pointer = room_304_init;
+ room_pre_parser_code_pointer = NULL;
+ room_parser_code_pointer = room_304_parser;
+ room_daemon_code_pointer = room_304_daemon;
+
+ section_3_walker();
+ section_3_interface();
+}
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/rooms/room304.h b/engines/mads/madsv2/phantom/rooms/room304.h
new file mode 100644
index 00000000000..1614438da4d
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room304.h
@@ -0,0 +1,92 @@
+/* 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 MADS_PHANTOM_ROOM304_H
+#define MADS_PHANTOM_ROOM304_H
+
+#include "mads/madsv2/phantom/phantom.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+#define local ((Scratch *)(&game.scratch[0]))
+#define ss local->sprite
+#define seq local->sequence
+#define aa local->animation
+
+typedef struct { /* Room local variables */
+
+ int16 sprite[15]; /* Sprite series handles */
+ int16 sequence[15]; /* Sequence handles */
+ int16 animation[4]; /* Animation handles */
+
+ int16 anim_0_running;
+ int16 anim_1_running;
+ int16 anim_2_running;
+
+ int16 raoul_frame;
+ int16 raoul_action;
+ int16 raoul_look_count;
+
+ int16 raoul_fight_frame;
+ int16 raoul_fight_action;
+ int16 raoul_fight_talk_count;
+
+ int16 phantom_frame;
+ int16 phantom_action;
+
+} Scratch;
+
+
+/* ========================= Sprite Series =================== */
+
+#define fx_chan_tilt 0 /* rm304f0 */
+#define fx_chan 1 /* rm304f1 */
+
+/* ========================= Triggers ======================== */
+
+#define ROOM_304_CLIMB_DOWN 60
+#define ROOM_304_CLIMB_UP 65
+
+/* ========================= Other Macros ==================== */
+
+
+#define RAOUL_CLIMB_UP 0
+#define RAOUL_OTHER 1
+
+#define CONV23_RAOUL_OTHER 0
+#define CONV23_RAOUL_SHUT_UP 1
+#define CONV23_RAOUL_TALK 2
+
+#define CONV_FIGHT_23 23
+
+#define CONV23_PHANTOM_DAAE 0
+#define CONV23_PHANTOM_LET_GO 1
+#define CONV23_PHANTOM_FIGHT 2
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif // MADS_PHANTOM_ROOM250_H
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index 9b5ca69a83e..9e725dd26d7 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -150,6 +150,7 @@ MODULE_OBJS += \
madsv2/phantom/rooms/room301.o \
madsv2/phantom/rooms/room302.o \
madsv2/phantom/rooms/room303.o \
+ madsv2/phantom/rooms/room304.o \
madsv2/phantom/phantom.o \
madsv2/phantom/conv.o \
madsv2/phantom/main_menu.o \
Commit: b764cf8a5d376b8ff092f8756d2213475f4b87ff
https://github.com/scummvm/scummvm/commit/b764cf8a5d376b8ff092f8756d2213475f4b87ff
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:47+10:00
Commit Message:
MADS: PHANTOM: Added room 305
Changed paths:
A engines/mads/madsv2/phantom/rooms/room305.cpp
A engines/mads/madsv2/phantom/rooms/room305.h
engines/mads/madsv2/phantom/mads/quotes.h
engines/mads/madsv2/phantom/mads/speeches.h
engines/mads/madsv2/phantom/mads/words.h
engines/mads/module.mk
diff --git a/engines/mads/madsv2/phantom/mads/quotes.h b/engines/mads/madsv2/phantom/mads/quotes.h
index a6266629bc1..f61a77b7ced 100644
--- a/engines/mads/madsv2/phantom/mads/quotes.h
+++ b/engines/mads/madsv2/phantom/mads/quotes.h
@@ -42,7 +42,8 @@ enum {
quote_score_rank_7 = 64,
quote_score_rank_8 = 65,
quote_mainmenu_phantom_1 = 66,
-
+ quote_305a0 = 100,
+ quote_305a1 = 101,
quote_204a0 = 117
#if 0
quote_menu_done,
diff --git a/engines/mads/madsv2/phantom/mads/speeches.h b/engines/mads/madsv2/phantom/mads/speeches.h
index b5c8ea53be2..b8d3a6c99d4 100644
--- a/engines/mads/madsv2/phantom/mads/speeches.h
+++ b/engines/mads/madsv2/phantom/mads/speeches.h
@@ -31,6 +31,7 @@ namespace Phantom {
enum {
speech_woman_scream = 1,
speech_applause = 2,
+ speech_raoul_strangle = 5,
speech_raoul_catwalk = 6,
speech_christine_scales = 8,
speech_phantom_cackle = 9
diff --git a/engines/mads/madsv2/phantom/mads/words.h b/engines/mads/madsv2/phantom/mads/words.h
index b579f9a4894..c4a92e3ca67 100644
--- a/engines/mads/madsv2/phantom/mads/words.h
+++ b/engines/mads/madsv2/phantom/mads/words.h
@@ -267,6 +267,8 @@ enum {
words_Edgar_Degas = 385,
words_chandelier_cable = 386,
words_hook = 390,
+ words_cane = 392,
+ words_mask = 393,
words_paper = 399
};
diff --git a/engines/mads/madsv2/phantom/rooms/room305.cpp b/engines/mads/madsv2/phantom/rooms/room305.cpp
new file mode 100644
index 00000000000..61572705457
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room305.cpp
@@ -0,0 +1,170 @@
+/* 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 "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/camera.h"
+#include "mads/madsv2/core/global.h"
+#include "mads/madsv2/core/imath.h"
+#include "mads/madsv2/core/inter.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/matte.h"
+#include "mads/madsv2/core/object.h"
+#include "mads/madsv2/core/quote.h"
+#include "mads/madsv2/core/rail.h"
+#include "mads/madsv2/core/sound.h"
+#include "mads/madsv2/core/speech.h"
+#include "mads/madsv2/core/text.h"
+#include "mads/madsv2/phantom/mads/inventory.h"
+#include "mads/madsv2/phantom/mads/quotes.h"
+#include "mads/madsv2/phantom/mads/sounds.h"
+#include "mads/madsv2/phantom/mads/speeches.h"
+#include "mads/madsv2/phantom/rooms/section3.h"
+#include "mads/madsv2/phantom/rooms/room305.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+void room_305_init() {
+ local->unmask = false;
+ local->prevent = false;
+ player.walker_visible = false;
+ local->anim_0_running = false;
+ local->anim_1_running = false;
+
+ kernel_set_interface_mode(INTER_LIMITED_SENTENCES);
+
+ global_speech_load(speech_raoul_strangle);
+
+ /* viewing_at_y = ((video_y - display_y) >> 1); */
+
+ kernel.quotes = quote_load(quote_305a0, quote_305a1, 0);
+
+ if (player.x == 100) {
+ aa[0] = kernel_run_animation(kernel_name('r', 1), ROOM_305_DEAD);
+ kernel_flip_hotspot(words_mask, false);
+ local->anim_1_running = true;
+
+ } else if (player.x == 200) {
+ aa[0] = kernel_run_animation(kernel_name('u', 1), 0);
+ local->anim_0_running = true;
+ kernel_flip_hotspot(words_cane, false);
+ }
+
+ section_3_music();
+}
+
+void room_305_parser() {
+ if (player_said_2(push, cane)) {
+ new_room = 304;
+ goto handled;
+ }
+
+ if (player_said_2(take, mask)) {
+ local->unmask = true;
+ player.commands_allowed = false;
+ goto handled;
+ }
+
+ goto done;
+
+handled:
+ player.command_ready = false;
+
+done:
+ ;
+}
+
+static void handle_animation_unmask() {
+ int unmask_reset_frame;
+ /* int id; */
+
+ if (kernel_anim[aa[0]].frame != local->unmask_frame) {
+ local->unmask_frame = kernel_anim[aa[0]].frame;
+ unmask_reset_frame = -1;
+
+ switch (local->unmask_frame) {
+ case 25: /* end of struggle with phantom masked */
+ if (!local->unmask) {
+ unmask_reset_frame = 0;
+ }
+ break;
+
+ case 60: /* somewhere when we can see phantom's face */
+ global_speech(10);
+
+ kernel_message_add(quote_string(kernel.quotes, quote_305a0),
+ 176, 53, MESSAGE_COLOR, SIX_SECONDS, 0, 0);
+ kernel_message_add(quote_string(kernel.quotes, quote_305a1),
+ 176, 68, MESSAGE_COLOR, SIX_SECONDS, 0, 0);
+ break;
+
+ case 95: /* end of unmasking */
+ new_room = 306;
+ break;
+ }
+
+ if (unmask_reset_frame >= 0) {
+ kernel_reset_animation(aa[0], unmask_reset_frame);
+ local->unmask_frame = unmask_reset_frame;
+ }
+ }
+}
+
+void room_305_daemon() {
+ if (local->anim_0_running) {
+ handle_animation_unmask();
+ }
+
+ if (local->anim_1_running) {
+ if (kernel_anim[aa[0]].frame == 53) {
+ player.commands_allowed = false;
+ }
+
+ if (kernel_anim[aa[0]].frame == 54 && !local->prevent) {
+ global_speech_go(speech_raoul_strangle);
+ local->prevent = true;
+ }
+ }
+
+ if (kernel.trigger == ROOM_305_DEAD) {
+ global[player_score] -= 10;
+ inter_turn_off_object();
+ inter_screen_update();
+ new_room = 303;
+ }
+}
+
+void room_305_preload() {
+ room_init_code_pointer = room_305_init;
+ room_pre_parser_code_pointer = NULL;
+ room_parser_code_pointer = room_305_parser;
+ room_daemon_code_pointer = room_305_daemon;
+
+ section_3_walker();
+ section_3_interface();
+}
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/rooms/room305.h b/engines/mads/madsv2/phantom/rooms/room305.h
new file mode 100644
index 00000000000..0be511d7c25
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room305.h
@@ -0,0 +1,73 @@
+/* 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 MADS_PHANTOM_ROOM305_H
+#define MADS_PHANTOM_ROOM305_H
+
+#include "mads/madsv2/phantom/phantom.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+#define local ((Scratch *)(&game.scratch[0]))
+#define ss local->sprite
+#define seq local->sequence
+#define aa local->animation
+
+typedef struct { /* Room local variables */
+
+ int16 sprite[15]; /* Sprite series handles */
+ int16 sequence[15]; /* Sequence handles */
+ int16 animation[4]; /* Animation handles */
+
+ int16 anim_0_running;
+ int16 anim_1_running;
+ int16 unmask_frame;
+ int16 unmask_action;
+ int16 unmask;
+
+ int16 prevent;
+
+} Scratch;
+
+
+/* ========================= Sprite Series =================== */
+
+#define fx_test 0 /* rm305x0 */
+#define fx_test_2 1 /* @rdr_9 */
+
+
+/* ========================= Triggers ======================== */
+
+#define ROOM_305_DEAD 60
+#define ROOM_305_END 65
+
+
+/* ========================= Other Macros ==================== */
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif // MADS_PHANTOM_ROOM250_H
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index 9e725dd26d7..1195dbe1c42 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -151,6 +151,7 @@ MODULE_OBJS += \
madsv2/phantom/rooms/room302.o \
madsv2/phantom/rooms/room303.o \
madsv2/phantom/rooms/room304.o \
+ madsv2/phantom/rooms/room305.o \
madsv2/phantom/phantom.o \
madsv2/phantom/conv.o \
madsv2/phantom/main_menu.o \
Commit: dade73d3c792a81b17b47acd5a2e5427e463deb9
https://github.com/scummvm/scummvm/commit/dade73d3c792a81b17b47acd5a2e5427e463deb9
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:47+10:00
Commit Message:
MADS: PHANTOM: Added room 306
Changed paths:
A engines/mads/madsv2/phantom/rooms/room306.cpp
A engines/mads/madsv2/phantom/rooms/room306.h
engines/mads/madsv2/phantom/mads/sounds.h
engines/mads/madsv2/phantom/rooms/room301.h
engines/mads/module.mk
diff --git a/engines/mads/madsv2/phantom/mads/sounds.h b/engines/mads/madsv2/phantom/mads/sounds.h
index 6341e58b8d0..3bb583b83a5 100644
--- a/engines/mads/madsv2/phantom/mads/sounds.h
+++ b/engines/mads/madsv2/phantom/mads/sounds.h
@@ -48,7 +48,9 @@ enum {
N_KeyTurnSnd = 71,
N_DoorHandle002 = 72,
N_DoorHandle = 73,
- N_WomanScream003 = 74
+ N_WomanScream003 = 74,
+
+ N_Crash003 = 66
};
} // namespace Phantom
diff --git a/engines/mads/madsv2/phantom/rooms/room301.h b/engines/mads/madsv2/phantom/rooms/room301.h
index 21f34230b04..2029b73762e 100644
--- a/engines/mads/madsv2/phantom/rooms/room301.h
+++ b/engines/mads/madsv2/phantom/rooms/room301.h
@@ -116,6 +116,7 @@ typedef struct { /* Room local variables */
#define PUSH_X 256
#define PUSH_Y 130
+
} // namespace Rooms
} // namespace Phantom
} // namespace MADSV2
diff --git a/engines/mads/madsv2/phantom/rooms/room306.cpp b/engines/mads/madsv2/phantom/rooms/room306.cpp
new file mode 100644
index 00000000000..3a43e21bf4f
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room306.cpp
@@ -0,0 +1,94 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/matte.h"
+#include "mads/madsv2/core/sound.h"
+#include "mads/madsv2/core/speech.h"
+#include "mads/madsv2/phantom/mads/sounds.h"
+#include "mads/madsv2/phantom/mads/speeches.h"
+#include "mads/madsv2/phantom/rooms/section3.h"
+#include "mads/madsv2/phantom/rooms/room306.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+void room_306_init() {
+ /* ===================== Load Sprite Series ================== */
+
+ global_speech_load(speech_raoul_catwalk);
+
+ local->prevent = false;
+
+ viewing_at_y = ((video_y - display_y) >> 1);
+
+ player.walker_visible = false;
+ player.commands_allowed = false;
+
+ aa[0] = kernel_run_animation(kernel_name('a', 1), ROOM_306_END);
+
+ section_3_music();
+}
+
+void room_306_daemon() {
+ if (kernel.trigger == ROOM_306_END) {
+ if (global_prefer_roland) {
+ kernel_timing_trigger(TWO_SECONDS, ROOM_306_END + 1);
+ } else {
+ kernel_timing_trigger(FIVE_SECONDS, ROOM_306_END + 1);
+ }
+ }
+
+ if (!local->prevent) {
+ if (kernel_anim[aa[0]].frame == 3) {
+ global_speech_go(speech_raoul_catwalk);
+ local->prevent = true;
+ }
+ }
+
+ if (kernel.trigger == ROOM_306_END + 1) {
+ sound_play(N_AllFade);
+ sound_play(N_Crash003);
+ kernel_timing_trigger(TWO_SECONDS, ROOM_306_END + 2);
+ }
+
+ if (kernel.trigger == ROOM_306_END + 2) {
+ new_room = 150;
+ }
+}
+
+void room_306_preload() {
+ room_init_code_pointer = room_306_init;
+ room_pre_parser_code_pointer = NULL;
+ room_parser_code_pointer = NULL;
+ room_daemon_code_pointer = room_306_daemon;
+
+ section_3_walker();
+ section_3_interface();
+}
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/rooms/room306.h b/engines/mads/madsv2/phantom/rooms/room306.h
new file mode 100644
index 00000000000..97671a4edec
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room306.h
@@ -0,0 +1,62 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef MADS_PHANTOM_ROOM306_H
+#define MADS_PHANTOM_ROOM306_H
+
+#include "mads/madsv2/phantom/phantom.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+#define local ((Scratch *)(&game.scratch[0]))
+#define ss local->sprite
+#define seq local->sequence
+#define aa local->animation
+
+typedef struct { /* Room local variables */
+
+ int16 sprite[15]; /* Sprite series handles */
+ int16 sequence[15]; /* Sequence handles */
+ int16 animation[4]; /* Animation handles */
+ int16 prevent;
+
+} Scratch;
+
+
+/* ========================= Sprite Series =================== */
+
+#define fx_fall 0 /* rm306a0 */
+
+
+/* ========================= Triggers ======================== */
+
+#define ROOM_306_END 60
+#define ROOM_306_BREAK_LOOSE 70
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif // MADS_PHANTOM_ROOM250_H
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index 1195dbe1c42..04dcc3a1789 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -152,6 +152,7 @@ MODULE_OBJS += \
madsv2/phantom/rooms/room303.o \
madsv2/phantom/rooms/room304.o \
madsv2/phantom/rooms/room305.o \
+ madsv2/phantom/rooms/room306.o \
madsv2/phantom/phantom.o \
madsv2/phantom/conv.o \
madsv2/phantom/main_menu.o \
Commit: dff5b3da8cff4369fef5e004fae17a8b31873f83
https://github.com/scummvm/scummvm/commit/dff5b3da8cff4369fef5e004fae17a8b31873f83
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:47+10:00
Commit Message:
MADS: PHANTOM: Added room 307
Changed paths:
A engines/mads/madsv2/phantom/rooms/room307.cpp
A engines/mads/madsv2/phantom/rooms/room307.h
engines/mads/madsv2/phantom/global.h
engines/mads/madsv2/phantom/mads/text.h
engines/mads/madsv2/phantom/mads/words.h
engines/mads/module.mk
diff --git a/engines/mads/madsv2/phantom/global.h b/engines/mads/madsv2/phantom/global.h
index c12f3059855..5b3bb8ec7ac 100644
--- a/engines/mads/madsv2/phantom/global.h
+++ b/engines/mads/madsv2/phantom/global.h
@@ -195,9 +195,10 @@ enum {
#define NEW_ROOM 1
// player_score_flags
-#define SCORE_TRAP_DOOR 1
-#define SCORE_DEAD_FLORENT 4
-#define SCORE_HOLLOW_COLUMN 8
+#define SCORE_TRAP_DOOR 0x01
+#define SCORE_DEAD_FLORENT 0x04
+#define SCORE_HOLLOW_COLUMN 0x08
+#define SCORE_CHASE_CATWALK 0x10
// ticket_people_here
#define NEITHER 0
diff --git a/engines/mads/madsv2/phantom/mads/text.h b/engines/mads/madsv2/phantom/mads/text.h
index acdbf94484e..5510234d4e9 100644
--- a/engines/mads/madsv2/phantom/mads/text.h
+++ b/engines/mads/madsv2/phantom/mads/text.h
@@ -36,7 +36,9 @@ enum {
text_008_16 = 816,
text_008_17 = 817,
text_008_18 = 818,
+ text_008_19 = 819,
text_008_44 = 844,
+ text_008_45 = 845,
/* Room 101 */
text_101_10 = 10110,
@@ -688,17 +690,35 @@ enum {
text_303_27 = 30327,
text_303_29 = 30329,
text_303_30 = 30330,
- text_303_31 = 30331
-};
+ text_303_31 = 30331,
-enum {
+ /* Room 304 */
text_304_10 = 30410,
text_304_11 = 30411,
text_304_12 = 30412,
text_304_13 = 30413,
text_304_14 = 30414,
text_304_15 = 30415,
- text_304_16 = 30416
+ text_304_16 = 30416,
+
+ /* Room 307 */
+ text_307_10 = 30710,
+ text_307_11 = 30711,
+ text_307_12 = 30712,
+ text_307_13 = 30713,
+ text_307_14 = 30714,
+ text_307_15 = 30715,
+ text_307_16 = 30716,
+ text_307_17 = 30717,
+ text_307_18 = 30718,
+ text_307_19 = 30719,
+ text_307_20 = 30720,
+ text_307_21 = 30721,
+ text_307_22 = 30722,
+ text_307_23 = 30723,
+ text_307_25 = 30725,
+ text_307_26 = 30726,
+
};
} // namespace Phantom
diff --git a/engines/mads/madsv2/phantom/mads/words.h b/engines/mads/madsv2/phantom/mads/words.h
index c4a92e3ca67..b557a352d09 100644
--- a/engines/mads/madsv2/phantom/mads/words.h
+++ b/engines/mads/madsv2/phantom/mads/words.h
@@ -75,6 +75,7 @@ enum {
words_folding_chairs = 74,
words_garbage_can = 75,
words_graffiti = 76,
+ words_green_frame = 77,
words_hemp = 78,
words_hole = 79,
words_house = 80,
@@ -183,6 +184,7 @@ enum {
words_placard = 203,
words_ticket_window = 204,
words_archway = 205,
+ words_column = 206,
words_rail = 207,
words_seat = 208,
words_loge_corridor = 209,
@@ -231,10 +233,12 @@ enum {
words_Monsieur_Brie = 258,
words_catwalk = 259,
words_grid = 260,
+ words_girder = 261,
words_gridwork = 262,
words_ductwork = 263,
words_opening = 264,
words_dome = 265,
+ words_alcove = 266,
words_Christine = 268,
words_woman = 269,
words_prompter_s_stand = 270,
diff --git a/engines/mads/madsv2/phantom/rooms/room307.cpp b/engines/mads/madsv2/phantom/rooms/room307.cpp
new file mode 100644
index 00000000000..f9a4efcb835
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room307.cpp
@@ -0,0 +1,320 @@
+/* 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 "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/matte.h"
+#include "mads/madsv2/core/object.h"
+#include "mads/madsv2/core/sound.h"
+#include "mads/madsv2/core/speech.h"
+#include "mads/madsv2/core/text.h"
+#include "mads/madsv2/phantom/mads/inventory.h"
+#include "mads/madsv2/phantom/mads/sounds.h"
+#include "mads/madsv2/phantom/mads/speeches.h"
+#include "mads/madsv2/phantom/rooms/section3.h"
+#include "mads/madsv2/phantom/rooms/room307.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+void room_307_init() {
+ ss[fx_green_frame] = kernel_load_series(kernel_name('p', 0), false);
+ ss[fx_door] = kernel_load_series(kernel_name('x', 0), false);
+ ss[fx_bend_down_9] = kernel_load_series("*RRD_9", false);
+ ss[fx_take_9] = kernel_load_series("*RDR_9", false);
+
+ if (global[right_door_is_open_504]) {
+ kernel_flip_hotspot(words_door, true);
+ } else {
+ kernel_flip_hotspot(words_door, false);
+ }
+
+ /* ================ If in 1881, put green_frame ============= */
+
+ if ((object_is_here(green_frame)) && (game.difficulty == EASY_MODE)) {
+ seq[fx_green_frame] = kernel_seq_stamp(ss[fx_green_frame], false, 1);
+ kernel_seq_depth(seq[fx_green_frame], 14);
+ } else {
+ kernel_flip_hotspot(words_green_frame, false);
+ }
+
+ /* ========================= Previous Rooms ================== */
+
+ if (previous_room == 308) {
+ player.x = START_X_FROM_308;
+ player.y = START_Y_FROM_308;
+ player.facing = FACING_SOUTHEAST;
+ player.commands_allowed = false;
+ seq[fx_door] = kernel_seq_stamp(ss[fx_door], false, KERNEL_LAST);
+ if (!(global[player_score_flags] & SCORE_CHASE_CATWALK)) {
+ global[player_score_flags] = global[player_score_flags] | SCORE_CHASE_CATWALK;
+ global[player_score] += 5;
+ }
+ kernel_seq_depth(seq[fx_door], 4);
+ player_walk(END_X_FROM_308, END_Y_FROM_308, FACING_EAST);
+ player_walk_trigger(ROOM_307_DOOR_CLOSES);
+
+ } else if ((previous_room == 303) || (previous_room != KERNEL_RESTORING_GAME)) {
+ player_first_walk(OFF_SCREEN_X_FROM_303, OFF_SCREEN_Y_FROM_303, FACING_WEST,
+ PLAYER_X_FROM_303, PLAYER_Y_FROM_303, FACING_WEST, true);
+ }
+
+ section_3_music();
+}
+
+void room_307_pre_parser() {
+ if (player_said_2(exit_to, alcove)) {
+ player.walk_off_edge_to_room = 303;
+ }
+
+ if (player_said_2(open, door)) {
+ player_walk(OPEN_DOOR_X, OPEN_DOOR_Y, FACING_NORTHWEST);
+ }
+}
+
+void room_307_parser() {
+ int temp; /* for synching purposes */
+ int count = 0;
+
+ if (player_said_2(take, green_frame) &&
+ (object_is_here(green_frame) || kernel.trigger)) {
+ switch (kernel.trigger) {
+ case (0):
+
+ if (global[current_year] == 1881) {
+ if (player_has(yellow_frame)) ++count;
+ if (player_has(red_frame)) ++count;
+ if (player_has(blue_frame)) ++count;
+ if (count < 3) global[player_score] += 5;
+ }
+
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_bend_down_9] = kernel_seq_pingpong(ss[fx_bend_down_9], false,
+ 5, 0, 0, 2);
+ kernel_seq_range(seq[fx_bend_down_9], 1, 5);
+ kernel_seq_player(seq[fx_bend_down_9], true);
+ kernel_seq_trigger(seq[fx_bend_down_9],
+ KERNEL_TRIGGER_SPRITE, 5, 1);
+ kernel_seq_trigger(seq[fx_bend_down_9],
+ KERNEL_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ kernel_seq_delete(seq[fx_green_frame]);
+ kernel_flip_hotspot(words_green_frame, false);
+ inter_give_to_player(green_frame);
+ sound_play(N_TakeObjectSnd);
+ break;
+
+ case 2:
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_SERIES, seq[fx_bend_down_9]);
+ player.walker_visible = true;
+ kernel_timing_trigger(20, 3);
+ break;
+
+ case 3:
+ if (global[current_year] == 1881) {
+ object_examine(green_frame, text_008_45, 0);
+ } else {
+ object_examine(green_frame, text_008_19, 0);
+ }
+ /* You pick up the green color frame */
+ player.commands_allowed = true;
+ break;
+ }
+ goto handled;
+ }
+
+ if (player_said_2(walk_through, door) || player_said_2(open, door)) {
+ switch (kernel.trigger) {
+ case (0):
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_take_9] = kernel_seq_pingpong(ss[fx_take_9], true,
+ 5, 0, 0, 2);
+ kernel_seq_range(seq[fx_take_9], 1, 4);
+ kernel_seq_player(seq[fx_take_9], true);
+ kernel_seq_trigger(seq[fx_take_9],
+ KERNEL_TRIGGER_SPRITE, 4, ROOM_307_DOOR_OPENS);
+ kernel_seq_trigger(seq[fx_take_9],
+ KERNEL_TRIGGER_EXPIRE, 0, ROOM_307_DOOR_OPENS + 2);
+ break;
+
+ case ROOM_307_DOOR_OPENS:
+ sound_play(N_DoorOpens);
+ seq[fx_door] = kernel_seq_forward(ss[fx_door], false,
+ 8, 0, 0, 1);
+ kernel_seq_depth(seq[fx_door], 14);
+ kernel_seq_range(seq[fx_door], KERNEL_FIRST, KERNEL_LAST);
+ kernel_seq_trigger(seq[fx_door],
+ KERNEL_TRIGGER_EXPIRE, 0, ROOM_307_DOOR_OPENS + 1);
+ break;
+
+ case ROOM_307_DOOR_OPENS + 1:
+ temp = seq[fx_door];
+ seq[fx_door] = kernel_seq_stamp(ss[fx_door], false, KERNEL_LAST);
+ kernel_synch(KERNEL_SERIES, seq[fx_door], KERNEL_SERIES, temp);
+ kernel_seq_depth(seq[fx_door], 14);
+ kernel_timing_trigger(10, ROOM_307_DOOR_OPENS + 3);
+ break;
+
+ case ROOM_307_DOOR_OPENS + 2:
+ player.walker_visible = true;
+ break;
+
+ case ROOM_307_DOOR_OPENS + 3:
+ new_room = 308;
+ break;
+ }
+ goto handled;
+ }
+
+ if (player.look_around) {
+ text_show(text_307_10);
+ goto handled;
+ }
+
+ if (player_said_1(look) || player_said_1(look_at)) {
+ if (player_said_1(column)) {
+ if (global[right_door_is_open_504]) {
+ text_show(text_307_25);
+ } else {
+ text_show(text_307_11);
+ }
+ goto handled;
+ }
+
+ if (player_said_1(catwalk)) {
+ text_show(text_307_12);
+ goto handled;
+ }
+
+ if (player_said_1(grid)) {
+ text_show(text_307_13);
+ goto handled;
+ }
+
+ if (player_said_1(girder)) {
+ text_show(text_307_14);
+ goto handled;
+ }
+
+ if (player_said_1(gridwork)) {
+ text_show(text_307_15);
+ goto handled;
+ }
+
+ if (player_said_1(hemp)) {
+ text_show(text_307_16);
+ goto handled;
+ }
+
+ if (player_said_1(back_wall)) {
+ text_show(text_307_17);
+ goto handled;
+ }
+
+ if (player_said_1(ductwork)) {
+ text_show(text_307_18);
+ goto handled;
+ }
+
+ if ((player_said_1(green_frame)) && (object_is_here(green_frame))) {
+ if (global[current_year] == 1993) {
+ text_show(text_307_19);
+ goto handled;
+ } else {
+ text_show(text_307_20);
+ goto handled;
+ }
+ }
+
+ if (player_said_1(alcove)) {
+ text_show(text_307_21);
+ goto handled;
+ }
+
+ if (player_said_1(railing)) {
+ text_show(text_307_22);
+ goto handled;
+ }
+
+ if (player_said_1(door)) {
+ text_show(text_307_26);
+ goto handled;
+ }
+ }
+
+ if (player_said_2(take, hemp)) {
+ text_show(text_307_23);
+ goto handled;
+ }
+
+ if (player_said_2(pull, hemp)) {
+ text_show(text_301_41);
+ goto handled;
+ }
+
+ goto done;
+
+handled:
+ player.command_ready = false;
+
+done:
+ ;
+}
+
+void room_307_daemon() {
+ switch (kernel.trigger) {
+ case ROOM_307_DOOR_CLOSES:
+ kernel_seq_delete(seq[fx_door]);
+ seq[fx_door] = kernel_seq_backward(ss[fx_door], false,
+ 8, 0, 0, 1);
+ kernel_seq_depth(seq[fx_door], 10);
+ kernel_seq_range(seq[fx_door], KERNEL_FIRST, KERNEL_LAST);
+ kernel_seq_trigger(seq[fx_door],
+ KERNEL_TRIGGER_EXPIRE, 0, ROOM_307_DOOR_CLOSES + 1);
+ break;
+
+ case ROOM_307_DOOR_CLOSES + 1:
+ sound_play(N_DoorCloses);
+ player.commands_allowed = true;
+ break;
+ }
+}
+
+void room_307_preload() {
+ room_init_code_pointer = room_307_init;
+ room_pre_parser_code_pointer = room_307_pre_parser;
+ room_parser_code_pointer = room_307_parser;
+ room_daemon_code_pointer = room_307_daemon;
+
+ section_3_walker();
+ section_3_interface();
+}
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/rooms/room307.h b/engines/mads/madsv2/phantom/rooms/room307.h
new file mode 100644
index 00000000000..c38d6bcfd0b
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room307.h
@@ -0,0 +1,82 @@
+/* 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 MADS_PHANTOM_ROOM307_H
+#define MADS_PHANTOM_ROOM307_H
+
+#include "mads/madsv2/phantom/phantom.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+#define local ((Scratch *)(&game.scratch[0]))
+#define ss local->sprite
+#define seq local->sequence
+#define aa local->animation
+
+typedef struct { /* Room local variables */
+
+ int sprite[15]; /* Sprite series handles */
+ int sequence[15]; /* Sequence handles */
+ int animation[4]; /* Animation handles */
+
+} Scratch;
+
+
+/* ========================= Sprite Series =================== */
+
+#define fx_test 0 /* rm301x0 */
+#define fx_bend_down_9 1 /* rrd_9 */
+#define fx_green_frame 2 /* rm307p0 */
+#define fx_door 3 /* rm307x0 */
+#define fx_take_9 4 /* rdr_9 */
+
+
+
+/* ========================= Triggers ======================== */
+
+#define ROOM_307_DOOR_CLOSES 60
+#define ROOM_307_DOOR_OPENS 70
+
+
+/* ========================= Other Macros ==================== */
+
+#define OFF_SCREEN_X_FROM_303 340
+#define OFF_SCREEN_Y_FROM_303 137
+#define PLAYER_X_FROM_303 304
+#define PLAYER_Y_FROM_303 137
+
+#define START_X_FROM_308 18
+#define START_Y_FROM_308 134
+#define END_X_FROM_308 41
+#define END_Y_FROM_308 137
+
+#define OPEN_DOOR_X 28
+#define OPEN_DOOR_Y 137
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif // MADS_PHANTOM_ROOM250_H
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index 04dcc3a1789..ae872a73fc1 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -153,6 +153,7 @@ MODULE_OBJS += \
madsv2/phantom/rooms/room304.o \
madsv2/phantom/rooms/room305.o \
madsv2/phantom/rooms/room306.o \
+ madsv2/phantom/rooms/room307.o \
madsv2/phantom/phantom.o \
madsv2/phantom/conv.o \
madsv2/phantom/main_menu.o \
Commit: a9fcf43af100539d34a50f4a38fa8ff54a5eff75
https://github.com/scummvm/scummvm/commit/a9fcf43af100539d34a50f4a38fa8ff54a5eff75
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:48+10:00
Commit Message:
MADS: PHANTOM: Added room 308
Changed paths:
A engines/mads/madsv2/phantom/rooms/room308.cpp
A engines/mads/madsv2/phantom/rooms/room308.h
engines/mads/madsv2/phantom/mads/speeches.h
engines/mads/madsv2/phantom/mads/text.h
engines/mads/madsv2/phantom/mads/words.h
engines/mads/module.mk
diff --git a/engines/mads/madsv2/phantom/mads/speeches.h b/engines/mads/madsv2/phantom/mads/speeches.h
index b8d3a6c99d4..b7a2e50a1dd 100644
--- a/engines/mads/madsv2/phantom/mads/speeches.h
+++ b/engines/mads/madsv2/phantom/mads/speeches.h
@@ -31,6 +31,7 @@ namespace Phantom {
enum {
speech_woman_scream = 1,
speech_applause = 2,
+ speech_christine_scream = 4,
speech_raoul_strangle = 5,
speech_raoul_catwalk = 6,
speech_christine_scales = 8,
diff --git a/engines/mads/madsv2/phantom/mads/text.h b/engines/mads/madsv2/phantom/mads/text.h
index 5510234d4e9..c77042ff748 100644
--- a/engines/mads/madsv2/phantom/mads/text.h
+++ b/engines/mads/madsv2/phantom/mads/text.h
@@ -719,6 +719,9 @@ enum {
text_307_25 = 30725,
text_307_26 = 30726,
+ /* Room 308 */
+ text_308_10 = 30810,
+ text_308_11 = 30811
};
} // namespace Phantom
diff --git a/engines/mads/madsv2/phantom/mads/words.h b/engines/mads/madsv2/phantom/mads/words.h
index b557a352d09..5451555c53e 100644
--- a/engines/mads/madsv2/phantom/mads/words.h
+++ b/engines/mads/madsv2/phantom/mads/words.h
@@ -251,6 +251,9 @@ enum {
words_staircase_post = 279,
words_Jacques = 280,
words_gentleman = 281,
+ words_upper_level = 284,
+ words_middle_level = 285,
+ words_lower_level = 286,
words_climb = 288,
words_chandelier_trap = 289,
words_piece_of_wood = 290,
diff --git a/engines/mads/madsv2/phantom/rooms/room308.cpp b/engines/mads/madsv2/phantom/rooms/room308.cpp
new file mode 100644
index 00000000000..57626fcf889
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room308.cpp
@@ -0,0 +1,390 @@
+/* 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 "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/matte.h"
+#include "mads/madsv2/core/object.h"
+#include "mads/madsv2/core/sound.h"
+#include "mads/madsv2/core/speech.h"
+#include "mads/madsv2/core/text.h"
+#include "mads/madsv2/phantom/mads/inventory.h"
+#include "mads/madsv2/phantom/mads/sounds.h"
+#include "mads/madsv2/phantom/mads/speeches.h"
+#include "mads/madsv2/phantom/rooms/section3.h"
+#include "mads/madsv2/phantom/rooms/room308.h"
+#include "mads/madsv2/phantom/conv.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+void room_308_init() {
+ global_speech_load(speech_christine_scream);
+
+ if (previous_room != KERNEL_RESTORING_GAME) {
+ local->anim_0_running = false;
+ local->anim_1_running = false;
+ local->anim_2_running = false;
+ local->anim_3_running = false;
+ }
+
+ local->prevent = false;
+ local->prevent_2 = false;
+
+ conv_get(CONV_MISC);
+
+ /* =================== Load sprites series =================== */
+
+ ss[fx_raoul] = kernel_load_series(kernel_name('a', 0), false);
+ ss[fx_her] = kernel_load_series(kernel_name('b', 0), false);
+
+ kernel_set_interface_mode(INTER_LIMITED_SENTENCES);
+
+ player.walker_visible = false;
+
+
+ /* ========================= Previous Rooms ================== */
+
+
+ if (previous_room == KERNEL_RESTORING_GAME) {
+ switch (local->on_floor) {
+ case 1:
+ if (global[right_door_is_open_504]) {
+ seq[fx_raoul] = kernel_seq_stamp(ss[fx_raoul], false, 1);
+ kernel_seq_depth(seq[fx_raoul], 10);
+ kernel_seq_loc(seq[fx_raoul], HIM_BOTH_BOTTOM_X, HIM_BOTH_BOTTOM_Y);
+ seq[fx_her] = kernel_seq_stamp(ss[fx_her], false, 1);
+ kernel_seq_depth(seq[fx_her], 10);
+ kernel_seq_loc(seq[fx_her], HER_BOTH_BOTTOM_X, HER_BOTH_BOTTOM_Y);
+
+ } else {
+ seq[fx_raoul] = kernel_seq_stamp
+ (ss[fx_raoul], false, 1);
+ kernel_seq_depth(seq[fx_raoul], 10);
+ kernel_seq_loc(seq[fx_raoul], RAOUL_BOTTOM_X, RAOUL_BOTTOM_Y);
+ }
+ break;
+
+ case 2:
+ seq[fx_raoul] = kernel_seq_stamp
+ (ss[fx_raoul], false, 1);
+ kernel_seq_depth(seq[fx_raoul], 10);
+ kernel_seq_loc(seq[fx_raoul], RAOUL_MIDDLE_X, RAOUL_MIDDLE_Y);
+ break;
+
+ case 3:
+ if (global[right_door_is_open_504] && !global[knocked_over_head]) {
+ local->anim_0_running = true;
+ local->prevent = true;
+ aa[0] = kernel_run_animation(kernel_name('b', 2), 2);
+ kernel_reset_animation(aa[0], 76);
+
+ } else {
+ local->anim_0_running = true;
+ local->prevent = true;
+ aa[0] = kernel_run_animation(kernel_name('u', 2), 2);
+ kernel_reset_animation(aa[0], 96);
+ }
+ break;
+ }
+
+ } else if (previous_room == 309) {
+ local->on_floor = 1;
+ if (global[right_door_is_open_504]) {
+ seq[fx_raoul] = kernel_seq_stamp(ss[fx_raoul], false, 1);
+ kernel_seq_depth(seq[fx_raoul], 10);
+ kernel_seq_loc(seq[fx_raoul], HIM_BOTH_BOTTOM_X, HIM_BOTH_BOTTOM_Y);
+ seq[fx_her] = kernel_seq_stamp(ss[fx_her], false, 1);
+ kernel_seq_depth(seq[fx_her], 10);
+ kernel_seq_loc(seq[fx_her], HER_BOTH_BOTTOM_X, HER_BOTH_BOTTOM_Y);
+
+ } else {
+ seq[fx_raoul] = kernel_seq_stamp(ss[fx_raoul], false, 1);
+ kernel_seq_depth(seq[fx_raoul], 10);
+ kernel_seq_loc(seq[fx_raoul], RAOUL_BOTTOM_X, RAOUL_BOTTOM_Y);
+ }
+
+ } else if (previous_room == 206) {
+ local->on_floor = 2;
+ seq[fx_raoul] = kernel_seq_stamp
+ (ss[fx_raoul], false, 1);
+ kernel_seq_depth(seq[fx_raoul], 10);
+ kernel_seq_loc(seq[fx_raoul], RAOUL_MIDDLE_X, RAOUL_MIDDLE_Y);
+
+ } else if (previous_room == 307) {
+ local->on_floor = 3;
+ local->anim_0_running = true;
+ local->prevent = true;
+ aa[0] = kernel_run_animation(kernel_name('u', 2), 2);
+ kernel_reset_animation(aa[0], 96);
+ }
+
+ if (!player.been_here_before) {
+ global[player_score] += 5;
+ kernel_timing_trigger(1, ROOM_308_SHOW_TEXT);
+ }
+
+ section_3_music();
+}
+
+void room_308_parser() {
+ switch (kernel.trigger) {
+ case 1:
+ new_room = 206;
+ goto handled;
+ break;
+
+ case 2:
+ new_room = 307;
+ goto handled;
+ break;
+
+ case 3:
+ new_room = 309;
+ goto handled;
+ break;
+ }
+
+ if (player_said_2(exit_to, middle_level)) {
+ switch (local->on_floor) {
+ case 1: /* on bottom floor */
+ if (global[right_door_is_open_504]) {
+ aa[0] = kernel_run_animation(kernel_name('b', 1), 1);
+ kernel_seq_delete(seq[fx_raoul]);
+ kernel_seq_delete(seq[fx_her]);
+ player.commands_allowed = false;
+
+ } else {
+ aa[0] = kernel_run_animation(kernel_name('u', 1), 1);
+ kernel_seq_delete(seq[fx_raoul]);
+ player.commands_allowed = false;
+ }
+ goto handled;
+ break;
+
+ case 2: /* on middle floor */
+ aa[0] = kernel_run_animation(kernel_name('m', 1), 1);
+ kernel_seq_delete(seq[fx_raoul]);
+ player.commands_allowed = false;
+ goto handled;
+ break;
+
+ case 3: /* on top floor (it was blocked) */
+ if (global[right_door_is_open_504] && !global[knocked_over_head]) {
+ kernel_abort_animation(aa[0]);
+ aa[0] = kernel_run_animation(kernel_name('b', 4), 1);
+ player.commands_allowed = false;
+ local->anim_2_running = false;
+
+ } else {
+ kernel_abort_animation(aa[0]);
+ aa[0] = kernel_run_animation(kernel_name('x', 1), 1);
+ player.commands_allowed = false;
+ local->anim_0_running = false;
+ local->anim_1_running = false;
+ }
+ goto handled;
+ break;
+ }
+ }
+
+ if (player_said_2(exit_to, upper_level)) {
+ switch (local->on_floor) {
+ case 1: /* on bottom floor */
+ if (global[right_door_is_open_504]) {
+ aa[0] = kernel_run_animation(kernel_name('b', 2), 1);
+ kernel_seq_delete(seq[fx_raoul]);
+ kernel_seq_delete(seq[fx_her]);
+ player.commands_allowed = false;
+ local->anim_2_running = true;
+ local->on_floor = 3;
+
+ } else {
+ aa[0] = kernel_run_animation(kernel_name('u', 2), 2);
+ kernel_seq_delete(seq[fx_raoul]);
+ player.commands_allowed = false;
+ local->anim_0_running = true;
+ local->on_floor = 3;
+ }
+ goto handled;
+ break;
+
+ case 2: /* on middle floor */
+ if (global[right_door_is_open_504]) {
+ aa[0] = kernel_run_animation(kernel_name('u', 3), 2);
+ kernel_seq_delete(seq[fx_raoul]);
+ player.commands_allowed = false;
+ goto handled;
+
+ } else {
+ aa[0] = kernel_run_animation(kernel_name('u', 3), 2);
+ kernel_seq_delete(seq[fx_raoul]);
+ player.commands_allowed = false;
+ local->anim_1_running = true;
+ local->on_floor = 3;
+ goto handled;
+ }
+ break;
+
+ case 3: /* on top floor (door is locked */
+ if (global[right_door_is_open_504]) {
+ global[top_floor_locked] = false;
+
+ } else {
+ local->prevent_2 = false;
+ local->prevent = false;
+ }
+ goto handled;
+ break;
+ }
+ }
+
+ if (player_said_2(exit_to, lower_level)) {
+ switch (local->on_floor) {
+ case 1: /* on bottom floor */
+ if (global[right_door_is_open_504]) {
+ conv_run(CONV_MISC);
+ conv_export_value(1);
+
+ } else {
+ aa[0] = kernel_run_animation(kernel_name('l', 1), 3);
+ kernel_seq_delete(seq[fx_raoul]);
+ player.commands_allowed = false;
+ }
+ goto handled;
+ break;
+
+ case 2: /* on middle floor */
+ if (global[right_door_is_open_504]) {
+ if (global_prefer_roland) {
+ sound_play(N_WomanScream003);
+ } else {
+ global_speech(speech_woman_scream);
+ }
+ conv_run(CONV_MISC);
+ conv_export_value(6);
+
+ } else {
+ aa[0] = kernel_run_animation(kernel_name('d', 1), 3);
+ kernel_seq_delete(seq[fx_raoul]);
+ player.commands_allowed = false;
+ }
+ goto handled;
+ break;
+
+ case 3: /* on top floor (it was blocked) */
+
+ if (global[right_door_is_open_504] && !global[knocked_over_head]) {
+ conv_run(CONV_MISC);
+ conv_export_value(5);
+
+ } else if (global[right_door_is_open_504] && global[knocked_over_head]) {
+ if (global_prefer_roland) {
+ sound_play(N_WomanScream003);
+ } else {
+ global_speech(speech_woman_scream);
+ }
+ conv_run(CONV_MISC);
+ conv_export_value(6);
+
+ } else {
+ kernel_abort_animation(aa[0]);
+ aa[0] = kernel_run_animation(kernel_name('x', 2), 3);
+ player.commands_allowed = false;
+ local->anim_0_running = false;
+ local->anim_1_running = false;
+ }
+ goto handled;
+ break;
+ }
+ }
+
+ goto done;
+
+handled:
+ player.command_ready = false;
+
+done:
+ ;
+}
+
+void room_308_daemon() {
+ if (kernel.trigger == ROOM_308_SHOW_TEXT) {
+ text_show(text_308_10);
+ }
+
+ if (local->anim_2_running) {
+ if (kernel_anim[aa[0]].frame == 77) {
+ kernel_reset_animation(aa[0], 76);
+ if (!local->prevent) {
+ player.commands_allowed = true;
+ text_show(text_308_11);
+ local->prevent = true;
+ }
+ }
+ }
+
+ if (local->anim_0_running) {
+ if (kernel_anim[aa[0]].frame == 97) {
+ if (global[top_floor_locked]) {
+ kernel_reset_animation(aa[0], 96);
+ if (!local->prevent) {
+ player.commands_allowed = true;
+ text_show(text_308_11);
+ local->prevent = true;
+ }
+ }
+ } else if (kernel_anim[aa[0]].frame == 116) {
+ global[top_floor_locked] = true;
+ new_room = 307;
+ }
+ }
+
+ if (local->anim_1_running) {
+ if (kernel_anim[aa[0]].frame == 51) {
+ if (global[top_floor_locked]) {
+ kernel_reset_animation(aa[0], 50);
+ if (!local->prevent) {
+ player.commands_allowed = true;
+ text_show(text_308_11);
+ local->prevent = true;
+ }
+ }
+ }
+ }
+}
+
+void room_308_preload() {
+ room_init_code_pointer = room_308_init;
+ room_pre_parser_code_pointer = NULL;
+ room_parser_code_pointer = room_308_parser;
+ room_daemon_code_pointer = room_308_daemon;
+
+ section_3_walker();
+ section_3_interface();
+}
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/rooms/room308.h b/engines/mads/madsv2/phantom/rooms/room308.h
new file mode 100644
index 00000000000..8aadbcc8466
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room308.h
@@ -0,0 +1,91 @@
+/* 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 MADS_PHANTOM_ROOM308_H
+#define MADS_PHANTOM_ROOM308_H
+
+#include "mads/madsv2/phantom/phantom.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+#define local ((Scratch *)(&game.scratch[0]))
+#define ss local->sprite
+#define seq local->sequence
+#define aa local->animation
+
+typedef struct { /* Room local variables */
+
+ int16 sprite[15]; /* Sprite series handles */
+ int16 sequence[15]; /* Sequence handles */
+ int16 animation[4]; /* Animation handles */
+ int16 anim_0_running;
+ int16 anim_1_running;
+ int16 anim_2_running;
+ int16 anim_3_running;
+ int16 on_floor;
+ int16 prevent;
+ int16 prevent_2;
+
+} Scratch;
+
+
+/* ========================= Sprite Series =================== */
+
+#define fx_raoul 0 /* rm308a0 */
+#define fx_her 1 /* rm308b0 */
+
+/* ========================= Triggers ======================== */
+
+#define ROOM_308_SHOW_TEXT 60
+
+
+/* ========================= Other Macros ==================== */
+
+
+#define RAOUL_BOTTOM_X 160
+#define RAOUL_BOTTOM_Y 127
+
+#define RAOUL_MIDDLE_X 160
+#define RAOUL_MIDDLE_Y 76
+
+#define HIM_BOTH_BOTTOM_X 160
+#define HIM_BOTH_BOTTOM_Y 104
+
+#define HER_BOTH_BOTTOM_X 161
+#define HER_BOTH_BOTTOM_Y 124
+
+#define CONV_MISC 26
+
+#define HIM_BOTH_TOP_X 160
+#define HIM_BOTH_TOP_Y 27
+
+#define HER_BOTH_TOP_X 161
+#define HER_BOTH_TOP_Y 48
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif // MADS_PHANTOM_ROOM250_H
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index ae872a73fc1..be06992b58d 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -154,6 +154,7 @@ MODULE_OBJS += \
madsv2/phantom/rooms/room305.o \
madsv2/phantom/rooms/room306.o \
madsv2/phantom/rooms/room307.o \
+ madsv2/phantom/rooms/room308.o \
madsv2/phantom/phantom.o \
madsv2/phantom/conv.o \
madsv2/phantom/main_menu.o \
Commit: bc0ac3867cf1d72cb6be5fcb3de6a1af468fee3b
https://github.com/scummvm/scummvm/commit/bc0ac3867cf1d72cb6be5fcb3de6a1af468fee3b
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:48+10:00
Commit Message:
MADS: PHANTOM: Added room 309
Changed paths:
A engines/mads/madsv2/phantom/rooms/room309.cpp
A engines/mads/madsv2/phantom/rooms/room309.h
engines/mads/madsv2/phantom/global.h
engines/mads/madsv2/phantom/mads/text.h
engines/mads/madsv2/phantom/mads/words.h
engines/mads/module.mk
diff --git a/engines/mads/madsv2/phantom/global.h b/engines/mads/madsv2/phantom/global.h
index 5b3bb8ec7ac..61cceb0a500 100644
--- a/engines/mads/madsv2/phantom/global.h
+++ b/engines/mads/madsv2/phantom/global.h
@@ -251,6 +251,13 @@ enum {
#define PANEL_LOCKED 2
#define PANEL_UNLOCKED 3
+// lantern_status
+#define LANTERN_IS_OFF 0
+#define LANTERN_IS_ON 1
+
+
+extern void global_enter_catacombs(int special);
+
} // namespace Phantom
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/mads/text.h b/engines/mads/madsv2/phantom/mads/text.h
index c77042ff748..fac0a4938ef 100644
--- a/engines/mads/madsv2/phantom/mads/text.h
+++ b/engines/mads/madsv2/phantom/mads/text.h
@@ -721,7 +721,21 @@ enum {
/* Room 308 */
text_308_10 = 30810,
- text_308_11 = 30811
+ text_308_11 = 30811,
+
+ /* Room 309 */
+ text_309_10 = 30910,
+ text_309_11 = 30911,
+ text_309_12 = 30912,
+ text_309_13 = 30913,
+ text_309_14 = 30914,
+ text_309_15 = 30915,
+ text_309_16 = 30916,
+ text_309_17 = 30917,
+ text_309_18 = 30918,
+ text_309_19 = 30919,
+ text_309_20 = 30920,
+ text_309_21 = 30921
};
} // namespace Phantom
diff --git a/engines/mads/madsv2/phantom/mads/words.h b/engines/mads/madsv2/phantom/mads/words.h
index 5451555c53e..615ad75c705 100644
--- a/engines/mads/madsv2/phantom/mads/words.h
+++ b/engines/mads/madsv2/phantom/mads/words.h
@@ -257,6 +257,11 @@ enum {
words_climb = 288,
words_chandelier_trap = 289,
words_piece_of_wood = 290,
+ words_stone_wall = 292,
+ words_lake = 293,
+ words_stone_column = 294,
+ words_stone_floor = 296,
+ words_stone_archway = 297,
words_Charles = 298,
words_prompter_s_seat = 300,
words_lever = 301,
@@ -264,6 +269,7 @@ enum {
words_Julie = 303,
words_cable_hook = 304,
words_Madame_Giry = 323,
+ words_catacombs = 328,
words_ticket_seller = 329,
words_usher = 330,
words_box_ten = 336,
@@ -273,6 +279,7 @@ enum {
words_clothes_dummy = 342,
words_Edgar_Degas = 385,
words_chandelier_cable = 386,
+ words_boat = 389,
words_hook = 390,
words_cane = 392,
words_mask = 393,
diff --git a/engines/mads/madsv2/phantom/rooms/room309.cpp b/engines/mads/madsv2/phantom/rooms/room309.cpp
new file mode 100644
index 00000000000..0572b592e19
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room309.cpp
@@ -0,0 +1,408 @@
+/* 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 "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/imath.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/matte.h"
+#include "mads/madsv2/core/object.h"
+#include "mads/madsv2/core/sound.h"
+#include "mads/madsv2/core/speech.h"
+#include "mads/madsv2/core/text.h"
+#include "mads/madsv2/phantom/mads/inventory.h"
+#include "mads/madsv2/phantom/mads/sounds.h"
+#include "mads/madsv2/phantom/mads/speeches.h"
+#include "mads/madsv2/phantom/rooms/section3.h"
+#include "mads/madsv2/phantom/rooms/room309.h"
+#include "mads/madsv2/phantom/conv.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+void room_309_init() {
+ int id;
+
+ kernel_flip_hotspot(words_Christine, false);
+ kernel_flip_hotspot(words_boat, false);
+
+ local->anim_0_running = false;
+ local->boat_action = ACTION_OTHER;
+
+ conv_get(CONV_MISC);
+
+ /* ====================== Load sprites ======================= */
+
+ ss[fx_door] = kernel_load_series(kernel_name('x', 0), false);
+ ss[fx_boat] = kernel_load_series(kernel_name('x', 1), false);
+ ss[fx_take_9] = kernel_load_series("*RDR_9", false);
+
+ if (previous_room == KERNEL_RESTORING_GAME) {
+
+ seq[fx_door] = kernel_seq_stamp(ss[fx_door], false, KERNEL_FIRST);
+ kernel_seq_depth(seq[fx_door], 10);
+
+ if (player_has_been_in_room(310)) {
+ local->anim_0_running = true;
+
+ aa[0] = kernel_run_animation(kernel_name('b', 1), ROOM_309_OUT_OF_BOAT);
+ kernel_reset_animation(aa[0], 184); /* put Chris by door */
+ id = kernel_add_dynamic(words_Christine, words_walk_to, SYNTAX_SINGULAR_FEM, KERNEL_NONE,
+ 0, 0, 0, 0);
+ kernel_dynamic_walk(id, DYNAMIC_CHR_WALK_TO_X, DYNAMIC_CHR_WALK_TO_Y, FACING_NORTHWEST);
+ kernel_dynamic_hot[id].prep = PREP_ON;
+
+ kernel_dynamic_anim(id, aa[0], 10);
+ kernel_dynamic_anim(id, aa[0], 11);
+ kernel_dynamic_anim(id, aa[0], 12);
+ kernel_dynamic_anim(id, aa[0], 13);
+ kernel_dynamic_anim(id, aa[0], 14);
+ kernel_dynamic_anim(id, aa[0], 15);
+ kernel_dynamic_anim(id, aa[0], 16);
+ kernel_dynamic_anim(id, aa[0], 17);
+ kernel_dynamic_anim(id, aa[0], 18);
+ kernel_flip_hotspot(words_Christine, true);
+ kernel_flip_hotspot(words_boat, true);
+ }
+ }
+
+
+ /* ===================== Previous rooms ====================== */
+
+ if (previous_room == 404) {
+ player.x = PLAYER_X_FROM_404;
+ player.y = PLAYER_Y_FROM_404;
+ player.facing = FACING_SOUTHWEST;
+ player_walk(WALK_TO_X_FROM_404, WALK_TO_Y_FROM_404, FACING_SOUTHWEST);
+ seq[fx_door] = kernel_seq_stamp
+ (ss[fx_door], false, KERNEL_FIRST);
+ kernel_seq_depth(seq[fx_door], 10);
+
+ } else if (previous_room == 310) {
+ player.x = PLAYER_X_FROM_310;
+ player.y = PLAYER_Y_FROM_310;
+ player.facing = FACING_SOUTH;
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ local->anim_0_running = true;
+
+ aa[0] = kernel_run_animation(kernel_name('b', 1), ROOM_309_OUT_OF_BOAT);
+ id = kernel_add_dynamic(words_Christine, words_walk_to, SYNTAX_SINGULAR_FEM, KERNEL_NONE,
+ 0, 0, 0, 0);
+ kernel_dynamic_walk(id, DYNAMIC_CHR_WALK_TO_X, DYNAMIC_CHR_WALK_TO_Y, FACING_NORTHWEST);
+ kernel_dynamic_hot[id].prep = PREP_ON;
+
+ kernel_dynamic_anim(id, aa[0], 10);
+ kernel_dynamic_anim(id, aa[0], 11);
+ kernel_dynamic_anim(id, aa[0], 12);
+ kernel_dynamic_anim(id, aa[0], 13);
+ kernel_dynamic_anim(id, aa[0], 14);
+ kernel_dynamic_anim(id, aa[0], 15);
+ kernel_dynamic_anim(id, aa[0], 16);
+ kernel_dynamic_anim(id, aa[0], 17);
+ kernel_dynamic_anim(id, aa[0], 18);
+ kernel_flip_hotspot(words_Christine, true);
+ kernel_flip_hotspot(words_boat, true);
+ seq[fx_door] = kernel_seq_stamp(ss[fx_door], false, KERNEL_FIRST);
+ kernel_seq_depth(seq[fx_door], 10);
+
+ } else if ((previous_room == 308) || (previous_room != KERNEL_RESTORING_GAME)) {
+ player.x = PLAYER_X_FROM_308;
+ player.y = PLAYER_Y_FROM_308;
+ player.facing = FACING_SOUTHEAST;
+ player_walk(WALK_TO_X_FROM_308, WALK_TO_Y_FROM_308, FACING_SOUTHEAST);
+ player_walk_trigger(ROOM_309_DOOR_CLOSES);
+ player.commands_allowed = false;
+ seq[fx_door] = kernel_seq_stamp
+ (ss[fx_door], false, KERNEL_LAST);
+ kernel_seq_depth(seq[fx_door], 10);
+ }
+ section_3_music();
+}
+
+void room_309_pre_parser() {
+ if (player_said_2(walk_through, stone_archway)) {
+ if (global[lantern_status] == LANTERN_IS_OFF) {
+ player.need_to_walk = false;
+ text_show(text_309_18);
+ }
+ }
+
+ if (player_said_2(walk_through, stone_archway)) {
+ if (global[right_door_is_open_504]) {
+ player_walk(WALK_TO_CAT_NO_X, WALK_TO_CAT_NO_Y, FACING_NORTHEAST);
+ }
+ }
+
+ if (player_said_2(open, door)) {
+ player_walk(DOOR_X, DOOR_Y, FACING_NORTHEAST);
+ }
+}
+
+void room_309_parser() {
+ int temp; /* for synching purposes */
+
+ if (player_said_2(walk_through, stone_archway)) {
+ if (global[right_door_is_open_504]) {
+ conv_run(CONV_MISC);
+ conv_export_value(1);
+ local->boat_action = ACTION_TALK;
+ local->chris_talk_count = 0;
+ } else if (global[lantern_status] == LANTERN_IS_ON) {
+ global_enter_catacombs(0);
+ }
+ goto handled;
+ }
+
+ if (player_said_2(talk_to, Christine)) {
+ conv_run(CONV_MISC);
+ conv_export_value(1);
+ local->boat_action = ACTION_TALK;
+ local->chris_talk_count = 0;
+ goto handled;
+ }
+
+ if (player_said_2(walk_through, door) || player_said_2(open, door)) {
+ switch (kernel.trigger) {
+ case (0):
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_take_9] = kernel_seq_pingpong(ss[fx_take_9], false,
+ 5, 0, 0, 2);
+ kernel_seq_range(seq[fx_take_9], 1, 4);
+ kernel_seq_player(seq[fx_take_9], true);
+ kernel_seq_trigger(seq[fx_take_9],
+ KERNEL_TRIGGER_SPRITE, 4, ROOM_309_DOOR_OPENS);
+ kernel_seq_trigger(seq[fx_take_9],
+ KERNEL_TRIGGER_EXPIRE, 0, ROOM_309_DOOR_OPENS + 2);
+ break;
+
+ case ROOM_309_DOOR_OPENS:
+ kernel_seq_delete(seq[fx_door]);
+ seq[fx_door] = kernel_seq_forward(ss[fx_door], false,
+ 8, 0, 0, 1);
+ kernel_seq_depth(seq[fx_door], 14);
+ kernel_seq_range(seq[fx_door], KERNEL_FIRST, KERNEL_LAST);
+ kernel_seq_trigger(seq[fx_door],
+ KERNEL_TRIGGER_EXPIRE, 0, ROOM_309_DOOR_OPENS + 1);
+ sound_play(N_DoorOpens);
+ break;
+
+ case ROOM_309_DOOR_OPENS + 1:
+ temp = seq[fx_door];
+ seq[fx_door] = kernel_seq_stamp(ss[fx_door], false, 5);
+ kernel_synch(KERNEL_SERIES, seq[fx_door], KERNEL_SERIES, temp);
+ kernel_seq_depth(seq[fx_door], 14);
+ player_walk(PLAYER_X_FROM_308, PLAYER_Y_FROM_308, FACING_NORTHWEST);
+ player_walk_trigger(ROOM_309_DOOR_OPENS + 3);
+ break;
+
+ case ROOM_309_DOOR_OPENS + 2:
+ player.walker_visible = true;
+ break;
+
+ case ROOM_309_DOOR_OPENS + 3:
+ if (!global[right_door_is_open_504]) {
+ kernel_seq_delete(seq[fx_door]);
+ seq[fx_door] = kernel_seq_backward(ss[fx_door], false,
+ 8, 0, 0, 1);
+ kernel_seq_depth(seq[fx_door], 1);
+ kernel_seq_range(seq[fx_door], KERNEL_FIRST, KERNEL_LAST);
+ kernel_seq_trigger(seq[fx_door],
+ KERNEL_TRIGGER_EXPIRE, 0, ROOM_309_DOOR_OPENS + 4);
+ sound_play(N_DoorCloses);
+
+ } else {
+ kernel_reset_animation(aa[0], 186);
+ }
+
+ break;
+
+ case ROOM_309_DOOR_OPENS + 4:
+ seq[fx_door] = kernel_seq_stamp(ss[fx_door], false, 5);
+ kernel_seq_depth(seq[fx_door], 1);
+ new_room = 308;
+ break;
+ }
+ goto handled;
+ }
+
+ if (player.look_around) {
+ text_show(text_309_10);
+ goto handled;
+ }
+
+ if (player_said_1(look) || player_said_1(look_at)) {
+
+ if (player_said_1(stone_wall)) {
+ text_show(text_309_11);
+ goto handled;
+ }
+
+ if (player_said_1(lake)) {
+ text_show(text_309_12);
+ goto handled;
+ }
+
+ if (player_said_1(stone_column)) {
+ text_show(text_309_13);
+ goto handled;
+ }
+
+ if (player_said_1(doorway)) {
+ text_show(text_309_14);
+ goto handled;
+ }
+
+ if (player_said_1(stone_archway)) {
+ text_show(text_309_15);
+ goto handled;
+ }
+
+ if (player_said_1(stone_floor)) {
+ text_show(text_309_16);
+ goto handled;
+ }
+
+ if (player_said_1(catacombs)) {
+ text_show(text_309_17);
+ goto handled;
+ }
+
+ if (player_said_1(Christine)) {
+ text_show(text_309_19);
+ goto handled;
+ }
+
+ if (player_said_1(boat)) {
+ text_show(text_309_21);
+ goto handled;
+ }
+ }
+
+ if (player_said_2(climb_into, boat)) {
+ text_show(text_309_20);
+ goto handled;
+ }
+
+ goto done;
+
+handled:
+ player.command_ready = false;
+
+done:
+ ;
+}
+
+static void handle_animation_boat() {
+ int boat_reset_frame;
+
+ if (kernel_anim[aa[0]].frame != local->boat_frame) {
+ local->boat_frame = kernel_anim[aa[0]].frame;
+ boat_reset_frame = -1;
+
+ switch (local->boat_frame) {
+ case 72: /* Turn on Raoul's walker */
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_ANIM, aa[0]);
+ player.walker_visible = true;
+ break;
+
+ case 130:
+ player.commands_allowed = true;
+ break;
+
+ case 185: /* keep Chris by door */
+ if (local->boat_action == ACTION_TALK) {
+ boat_reset_frame = 244;
+ } else {
+ boat_reset_frame = 184;
+ }
+
+ break;
+
+ case 244:
+ new_room = 308;
+ break;
+
+ case 245: /* end of talk 1 */
+ case 246: /* end of talk 2 */
+ case 247: /* end of talk 3 */
+ boat_reset_frame = imath_random(244, 246);
+ ++local->chris_talk_count;
+ if (local->chris_talk_count > 10) {
+ boat_reset_frame = 184;
+ local->boat_action = ACTION_OTHER;
+ }
+ break;
+ }
+
+ if (boat_reset_frame >= 0) {
+ kernel_reset_animation(aa[0], boat_reset_frame);
+ local->boat_frame = boat_reset_frame;
+ }
+ }
+}
+
+
+void room_309_daemon() {
+ if (local->anim_0_running) {
+ handle_animation_boat();
+ }
+
+ switch (kernel.trigger) {
+ case ROOM_309_DOOR_CLOSES:
+ kernel_seq_delete(seq[fx_door]);
+ seq[fx_door] = kernel_seq_backward(ss[fx_door], false,
+ 8, 0, 0, 1);
+ kernel_seq_depth(seq[fx_door], 10);
+ kernel_seq_range(seq[fx_door], KERNEL_FIRST, KERNEL_LAST);
+ kernel_seq_trigger(seq[fx_door],
+ KERNEL_TRIGGER_EXPIRE, 0, ROOM_309_DOOR_CLOSES + 1);
+ break;
+
+ case ROOM_309_DOOR_CLOSES + 1:
+ sound_play(N_DoorCloses);
+ seq[fx_door] = kernel_seq_stamp(ss[fx_door], false, KERNEL_FIRST);
+ kernel_seq_depth(seq[fx_door], 10);
+ player.commands_allowed = true;
+ break;
+ }
+}
+
+void room_309_preload() {
+ room_init_code_pointer = room_309_init;
+ room_pre_parser_code_pointer = room_309_pre_parser;
+ room_parser_code_pointer = room_309_parser;
+ room_daemon_code_pointer = room_309_daemon;
+
+ section_3_walker();
+ section_3_interface();
+
+ if (global[right_door_is_open_504]) {
+ kernel_initial_variant = 1;
+ }
+}
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/rooms/room309.h b/engines/mads/madsv2/phantom/rooms/room309.h
new file mode 100644
index 00000000000..0f0af163a86
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room309.h
@@ -0,0 +1,100 @@
+/* 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 MADS_PHANTOM_ROOM309_H
+#define MADS_PHANTOM_ROOM309_H
+
+#include "mads/madsv2/phantom/phantom.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+#define local ((Scratch *)(&game.scratch[0]))
+#define ss local->sprite
+#define seq local->sequence
+#define aa local->animation
+
+typedef struct { /* Room local variables */
+
+ int16 sprite[15]; /* Sprite series handles */
+ int16 sequence[15]; /* Sequence handles */
+ int16 animation[4]; /* Animation handles */
+
+ int16 boat_action; /* pulling up in boat */
+ int16 boat_frame;
+ int16 anim_0_running;
+
+ int chris_talk_count;
+
+} Scratch;
+
+
+/* ========================= Sprite Series =================== */
+
+#define fx_door 0 /* rm309x0 */
+#define fx_take_9 1 /* rdr_9 */
+#define fx_boat 2 /* rm309x1 */
+
+/* ========================= Triggers ======================== */
+
+#define ROOM_309_DOOR_OPENS 60
+#define ROOM_309_DOOR_CLOSES 65
+#define ROOM_309_OUT_OF_BOAT 70
+
+/* ========================= Other Macros ==================== */
+
+#define PLAYER_X_FROM_404 319
+#define PLAYER_Y_FROM_404 136
+
+#define WALK_TO_X_FROM_404 281
+#define WALK_TO_Y_FROM_404 148
+
+#define PLAYER_X_FROM_308 0
+#define PLAYER_Y_FROM_308 121
+
+#define WALK_TO_X_FROM_308 28
+#define WALK_TO_Y_FROM_308 142
+
+#define PLAYER_X_FROM_310 209
+#define PLAYER_Y_FROM_310 144
+
+#define DYNAMIC_CHR_WALK_TO_X 62
+#define DYNAMIC_CHR_WALK_TO_Y 146
+
+#define CONV_MISC 26
+
+#define ACTION_TALK 0
+#define ACTION_OTHER 1
+
+#define WALK_TO_CAT_NO_X 285
+#define WALK_TO_CAT_NO_Y 147
+
+#define DOOR_X 16
+#define DOOR_Y 139
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif // MADS_PHANTOM_ROOM250_H
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index be06992b58d..92201cc2bf7 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -155,6 +155,7 @@ MODULE_OBJS += \
madsv2/phantom/rooms/room306.o \
madsv2/phantom/rooms/room307.o \
madsv2/phantom/rooms/room308.o \
+ madsv2/phantom/rooms/room309.o \
madsv2/phantom/phantom.o \
madsv2/phantom/conv.o \
madsv2/phantom/main_menu.o \
Commit: f98c7081ad3627452f1be9e86850c22c1f10c9cf
https://github.com/scummvm/scummvm/commit/f98c7081ad3627452f1be9e86850c22c1f10c9cf
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:48+10:00
Commit Message:
MADS: PHANTOM: Added room 310
Changed paths:
A engines/mads/madsv2/phantom/rooms/room310.cpp
A engines/mads/madsv2/phantom/rooms/room310.h
engines/mads/madsv2/phantom/mads/quotes.h
engines/mads/module.mk
diff --git a/engines/mads/madsv2/phantom/mads/quotes.h b/engines/mads/madsv2/phantom/mads/quotes.h
index f61a77b7ced..5dc180c66e8 100644
--- a/engines/mads/madsv2/phantom/mads/quotes.h
+++ b/engines/mads/madsv2/phantom/mads/quotes.h
@@ -44,7 +44,24 @@ enum {
quote_mainmenu_phantom_1 = 66,
quote_305a0 = 100,
quote_305a1 = 101,
+
+ quote_310a0 = 102,
+ quote_310a1 = 103,
+ quote_310a2 = 104,
+ quote_310b0 = 105,
+ quote_310b1 = 106,
+ quote_310b2 = 107,
+ quote_310c0 = 108,
+ quote_310c1 = 109,
+ quote_310d0 = 110,
+ quote_310d1 = 111,
+ quote_310d2 = 112,
+ quote_310e0 = 113,
+ quote_310e1 = 114,
+ quote_310e2 = 115,
+ quote_310f0 = 116,
quote_204a0 = 117
+
#if 0
quote_menu_done,
quote_menu_cancel,
diff --git a/engines/mads/madsv2/phantom/rooms/room310.cpp b/engines/mads/madsv2/phantom/rooms/room310.cpp
new file mode 100644
index 00000000000..93d49288470
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room310.cpp
@@ -0,0 +1,274 @@
+/* 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 "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/camera.h"
+#include "mads/madsv2/core/inter.h"
+#include "mads/madsv2/core/matte.h"
+#include "mads/madsv2/core/quote.h"
+#include "mads/madsv2/phantom/mads/quotes.h"
+#include "mads/madsv2/phantom/rooms/section3.h"
+#include "mads/madsv2/phantom/rooms/room310.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+void room_310_init() {
+ viewing_at_y = ((video_y - display_y) >> 1);
+
+ for (int count = 0; count < NUM_MULTIPLANES; count++) {
+ ss[fx_multiplane_0 + count] = kernel_load_series(kernel_name('f', count), false);
+ seq[fx_multiplane_0 + count] = -1;
+ }
+
+
+ local->multiplane_base[0] = 100;
+ local->multiplane_base[1] = 210;
+ local->multiplane_base[2] = 320;
+ local->multiplane_base[3] = 472;
+
+
+ kernel.quotes = quote_load(quote_310a0, quote_310a1, quote_310b0,
+ quote_310b1, quote_310c0, quote_310c1,
+ quote_310d0, quote_310d1, quote_310e0,
+ quote_310e1, quote_310f0, quote_310d2,
+ quote_310a2, quote_310e2, quote_310b2, 0);
+
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ aa[0] = kernel_run_animation(kernel_name('l', 1), ROOM_310_DONE);
+ kernel_anim[aa[0]].view_changes = true;
+ camera_x.pan_mode = CAMERA_MANUAL;
+
+ local->message_1 = (1 << 8) + 2;
+ local->message_2 = MESSAGE_COLOR;
+
+ kernel_init_dialog(); /* clear interface */
+ kernel_set_interface_mode(INTER_CONVERSATION);
+
+ section_3_music();
+}
+
+void set_multiplane_positions_310(int x_new) {
+ int multiplane;
+ int center;
+ int difference;
+ int direction;
+ int distance;
+ int displace;
+ int x;
+ int y;
+ int xs;
+
+ center = x_new + (video_x >> 1);
+
+ for (multiplane = 0; multiplane < NUM_MULTIPLANES; multiplane++) {
+
+ if (seq[multiplane + fx_multiplane_0] >= 0) {
+ kernel_seq_delete(seq[multiplane + fx_multiplane_0]);
+ }
+
+ difference = center - local->multiplane_base[multiplane];
+ direction = neg(sgn(difference));
+ distance = abs(difference);
+
+ displace = (int)(((long)distance * camera_ratio_1) / camera_ratio_2);
+ displace = sgn_in(displace, direction);
+
+ x = local->multiplane_base[multiplane] + displace - 1;
+ y = series_list[ss[fx_multiplane_0 + multiplane]]->index[0].ys - 1 + 30;
+ xs = series_list[ss[fx_multiplane_0 + multiplane]]->index[0].xs;
+
+ if (((x - ((xs >> 1) + 1)) >= (x_new + video_x)) ||
+ ((x + ((xs >> 1) + 1)) < x_new)) {
+ seq[multiplane + fx_multiplane_0] = -1;
+ } else {
+ /*
+ if (local->dyn_multiplanes[multiplane] != -1) {
+ kernel_delete_dynamic (local->dyn_multiplanes[multiplane]);
+ }
+
+ local->dyn_multiplanes[multiplane] = kernel_add_dynamic (words_multiplane, words_look_at, SYNTAX_SINGULAR, KERNEL_NONE,
+ x - 8, y - 12, 16, 13);
+ */
+
+ seq[multiplane + fx_multiplane_0] =
+ kernel_seq_stamp(ss[fx_multiplane_0 + multiplane], false, 1);
+ kernel_seq_loc(seq[multiplane + fx_multiplane_0], x, y);
+ kernel_seq_depth(seq[multiplane + fx_multiplane_0], 1);
+ }
+ }
+}
+
+static void handle_animation_lake() {
+ int lake_reset_frame;
+ int id;
+
+ if (kernel_anim[aa[0]].frame != local->lake_frame) {
+ local->lake_frame = kernel_anim[aa[0]].frame;
+ lake_reset_frame = -1;
+
+ switch (local->lake_frame) {
+ case 60:
+ id = kernel_message_add(quote_string(kernel.quotes, quote_310a0),
+ -142, 0, local->message_2, TEN_SECONDS, ROOM_310_CONV + 1, 0);
+ kernel_message_anim(id, aa[0], 0);
+ id = kernel_message_add(quote_string(kernel.quotes, quote_310a1),
+ -142, 15, local->message_2, TEN_SECONDS, 0, 0);
+ kernel_message_anim(id, aa[0], 0);
+ id = kernel_message_add(quote_string(kernel.quotes, quote_310a2),
+ -142, 30, local->message_2, TEN_SECONDS, 0, 0);
+ kernel_message_anim(id, aa[0], 0);
+ break;
+
+ case 120:
+ kernel_message_purge();
+ break;
+
+ case 140:
+ id = kernel_message_add(quote_string(kernel.quotes, quote_310b0),
+ -120, 0, local->message_2, SIX_SECONDS, ROOM_310_CONV + 3, 0);
+ kernel_message_anim(id, aa[0], 0);
+ id = kernel_message_add(quote_string(kernel.quotes, quote_310b1),
+ -120, 15, local->message_2, SIX_SECONDS, 0, 0);
+ kernel_message_anim(id, aa[0], 0);
+ id = kernel_message_add(quote_string(kernel.quotes, quote_310b2),
+ -120, 30, local->message_2, SIX_SECONDS, 0, 0);
+ kernel_message_anim(id, aa[0], 0);
+ break;
+
+ case 200:
+ kernel_message_purge();
+ break;
+
+ case 220:
+ id = kernel_message_add(quote_string(kernel.quotes, quote_310c0),
+ -32, 30, local->message_2, FOUR_SECONDS, ROOM_310_CONV + 5, 0);
+ kernel_message_anim(id, aa[0], 0);
+ id = kernel_message_add(quote_string(kernel.quotes, quote_310c1),
+ -32, 45, local->message_2, FOUR_SECONDS, 0, 0);
+ kernel_message_anim(id, aa[0], 0);
+ break;
+
+ case 280:
+ kernel_message_purge();
+ break;
+
+ case 300:
+ id = kernel_message_add(quote_string(kernel.quotes, quote_310d0),
+ 101, 0, local->message_1, SIX_SECONDS, ROOM_310_CONV + 7, 0);
+ kernel_message_anim(id, aa[0], 0);
+ id = kernel_message_add(quote_string(kernel.quotes, quote_310d1),
+ 101, 15, local->message_1, SIX_SECONDS, 0, 0);
+ kernel_message_anim(id, aa[0], 0);
+ id = kernel_message_add(quote_string(kernel.quotes, quote_310d2),
+ 101, 30, local->message_1, SIX_SECONDS, 0, 0);
+ kernel_message_anim(id, aa[0], 0);
+ break;
+
+ case 360:
+ kernel_message_purge();
+ break;
+
+ case 380:
+ id = kernel_message_add(quote_string(kernel.quotes, quote_310e0),
+ 107, 0, local->message_2, SIX_SECONDS, ROOM_310_CONV + 9, 0);
+ kernel_message_anim(id, aa[0], 0);
+ id = kernel_message_add(quote_string(kernel.quotes, quote_310e1),
+ 107, 15, local->message_2, SIX_SECONDS, 0, 0);
+ kernel_message_anim(id, aa[0], 0);
+ id = kernel_message_add(quote_string(kernel.quotes, quote_310e2),
+ 107, 30, local->message_2, SIX_SECONDS, 0, 0);
+ kernel_message_anim(id, aa[0], 0);
+ break;
+
+ case 440:
+ kernel_message_purge();
+ break;
+
+ case 460:
+ id = kernel_message_add(quote_string(kernel.quotes, quote_310f0),
+ 107, 7, local->message_2, THREE_SECONDS, 0, 0);
+ kernel_message_anim(id, aa[0], 0);
+ break;
+
+ case 510:
+ kernel_message_purge();
+ break;
+ }
+
+ if (lake_reset_frame >= 0) {
+ kernel_reset_animation(aa[0], lake_reset_frame);
+ local->lake_frame = lake_reset_frame;
+ }
+ }
+}
+
+void room_310_daemon() {
+ int frame;
+ int x;
+ int positions_set;
+ long clock;
+
+ handle_animation_lake();
+
+ if (kernel.trigger == ROOM_310_DONE) {
+ new_room = 309;
+ }
+
+ positions_set = false;
+
+ if (aa[0] >= 0) {
+ frame = kernel_anim[aa[0]].frame;
+ clock = kernel_anim[aa[0]].next_clock;
+ if (frame > 0) {
+ if (kernel.clock >= clock) {
+ x = kernel_anim[aa[0]].anim->frame[frame].view_x;
+ if (x != picture_view_x) {
+ set_multiplane_positions_310(x);
+ positions_set = true;
+ }
+ }
+ }
+ }
+
+ if (!positions_set && kernel.fx) {
+ set_multiplane_positions_310(video_x);
+ }
+}
+
+void room_310_preload() {
+ room_init_code_pointer = room_310_init;
+ room_pre_parser_code_pointer = NULL;
+ room_parser_code_pointer = NULL;
+ room_daemon_code_pointer = room_310_daemon;
+
+ section_3_walker();
+ section_3_interface();
+}
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/rooms/room310.h b/engines/mads/madsv2/phantom/rooms/room310.h
new file mode 100644
index 00000000000..93eaf0d058a
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room310.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 MADS_PHANTOM_ROOM310_H
+#define MADS_PHANTOM_ROOM310_H
+
+#include "mads/madsv2/core/general.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+#define local ((Scratch *)(&game.scratch[0]))
+#define ss local->sprite
+#define seq local->sequence
+#define aa local->animation
+
+typedef struct { /* Room local variables */
+
+ int16 sprite[15]; /* Sprite series handles */
+ int16 sequence[15]; /* Sequence handles */
+ int16 animation[4]; /* Animation handles */
+
+ word message_1; /* Raoul's message color */
+ word message_2; /* Christine's color */
+
+ int multiplane_base[4]; /* Multiplanar scrolling bases */
+
+ int lake_frame;
+
+} Scratch;
+
+
+#define fx_multiplane_0 0
+#define fx_multiplane_1 0
+#define fx_multiplane_2 0
+#define fx_multiplane_3 0
+
+
+/* ========================= Triggers ======================== */
+
+#define ROOM_310_CONV 60
+#define ROOM_310_DONE 80
+
+
+/* ========================= Other Macros ==================== */
+
+#define NUM_MULTIPLANES 4
+
+#define camera_ratio_1 1
+#define camera_ratio_2 1 /* 5 */
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif // MADS_PHANTOM_ROOM250_H
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index 92201cc2bf7..e069d423bd3 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -156,6 +156,7 @@ MODULE_OBJS += \
madsv2/phantom/rooms/room307.o \
madsv2/phantom/rooms/room308.o \
madsv2/phantom/rooms/room309.o \
+ madsv2/phantom/rooms/room310.o \
madsv2/phantom/phantom.o \
madsv2/phantom/conv.o \
madsv2/phantom/main_menu.o \
Commit: 963967034f52026fca79e7d7e5928df75d4ca111
https://github.com/scummvm/scummvm/commit/963967034f52026fca79e7d7e5928df75d4ca111
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:48+10:00
Commit Message:
MADS: PHANTOM: Added room 401
Changed paths:
A engines/mads/madsv2/phantom/global.cpp
A engines/mads/madsv2/phantom/rooms/room401.cpp
A engines/mads/madsv2/phantom/rooms/room401.h
A engines/mads/madsv2/phantom/rooms/section4.h
engines/mads/madsv2/phantom/global.h
engines/mads/madsv2/phantom/mads/text.h
engines/mads/madsv2/phantom/mads/words.h
engines/mads/module.mk
diff --git a/engines/mads/madsv2/phantom/global.cpp b/engines/mads/madsv2/phantom/global.cpp
new file mode 100644
index 00000000000..ea7617f6038
--- /dev/null
+++ b/engines/mads/madsv2/phantom/global.cpp
@@ -0,0 +1,226 @@
+/* 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 "mads/madsv2/phantom/global.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+
+/* Fun stuff for the catacombs */
+
+#define NORTH 0
+#define EAST 1
+#define SOUTH 2
+#define WEST 3
+
+#define DIRECTION_MASK 0x0003
+#define FLAGS_MASK 0x00fc
+
+#define CATACOMBS_TO_309 -2
+#define CATACOMBS_TO_409a -3
+#define CATACOMBS_TO_409b -4
+#define CATACOMBS_TO_501 -5
+
+
+struct Catacombs {
+ int16 room_id; /* Room ID of catacomb part. */
+ int8 exit[4]; /* Catacomb room # if exit in direction */
+ int8 from[4]; /* When exit, will enter from this direction */
+ int16 misc; /* Miscellaneous bit data */
+};
+
+Catacombs *catacombs = NULL;
+
+Catacombs easy_catacombs[32] = {
+ { 401, { -1, 1, 2, 6 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BRICK },
+ { 404, { 10, 11, 3, 0 }, { SOUTH, WEST, NORTH, EAST }, MAZE_PUDDLE },
+ { 404, { 0, 3, 4, CATACOMBS_TO_309 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BLOCK },
+ { 401, { 1, 14, 5, 2 }, { SOUTH, WEST, NORTH, EAST }, MAZE_POT },
+ { 453, { 2, 4, -1, 4 }, { SOUTH, WEST, NORTH, EAST }, MAZE_DRAIN },
+ { 403, { 3, 6, -1, -1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BRICK | MAZE_PLANK },
+ { 406, { -1, 0, -1, 5 }, { SOUTH, WEST, NORTH, EAST }, 0 },
+ { 453, { -1, 8, -1, -1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BRICK },
+ /* 8 */
+ { 406, { -1, 9, -1, 7 }, { SOUTH, WEST, NORTH, EAST }, 0 },
+ { 401, { 1, -1, 10, 8 }, { SOUTH, WEST, NORTH, EAST }, MAZE_RAT_NEST | MAZE_SKULL },
+ { 408, { 9, -1, 1, -1 }, { SOUTH, WEST, NORTH, EAST }, 0 },
+ { 453, { 12, -1, -1, 1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BRICK | MAZE_STONE },
+ /* 12 */
+ { 408, { 13, -1, 11, -1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BRICK },
+ { 401, { 13, 20, 12, 13 }, { WEST, WEST, NORTH, NORTH }, MAZE_BRICK },
+ { 453, { 16, 15, -1, 3 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BRICK | MAZE_RAT_NEST },
+ { 456, { -1, -1, -1, 14 }, { SOUTH, WEST, NORTH, EAST }, 0 },
+ /* 16 */
+ { 404, { -1, 17, 14, -1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_WEB | MAZE_POT },
+ { 401, { 18, -1, 19, 16 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BRICK },
+ { 408, { -1, -1, 17, -1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BRICK },
+ { 403, { 17, -1, -1, -1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_HOLE | MAZE_WEB },
+ /* 20 */
+ { 403, { 21, 22, -1, 13 }, { SOUTH, WEST, NORTH, EAST }, MAZE_WEB | MAZE_SKULL },
+ { 404, { -1, -1, 20, -1 }, { SOUTH, WEST, NORTH, EAST }, 0 },
+ { 406, { -1, 23, -1, 20 }, { SOUTH, WEST, NORTH, EAST }, 0 },
+ { 404, { 24, 23, 23, 22 }, { SOUTH, SOUTH, EAST, EAST }, MAZE_RAT_NEST | MAZE_BRICK },
+ /* 24 */
+ { 401, { -1, 1, 23, 25 }, { SOUTH, EAST, NORTH, EAST }, MAZE_PUDDLE | MAZE_POT | MAZE_BRICK },
+ { 407, { 29, 24, 28, 26 }, { WEST, WEST, EAST, EAST }, 0 },
+ { 401, { 27, 25, 23, -1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_SKULL },
+ { 404, { -1, 28, 26, -1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_WEB | MAZE_FALLEN_BLOCK },
+ /* 28 */
+ { 456, { -1, 25, -1, 27 }, { SOUTH, SOUTH, NORTH, EAST }, 0 },
+ { 406, { -1, 30, -1, 25 }, { SOUTH, WEST, NORTH, NORTH }, 0 },
+ { 453, { CATACOMBS_TO_409a, 30, -1, 29 }, { SOUTH, WEST, NORTH, EAST },
+ MAZE_STONE | MAZE_RAT_NEST | MAZE_WEB },
+ { 408, { CATACOMBS_TO_501, -1, CATACOMBS_TO_409b, -1 }, { SOUTH, WEST, NORTH, EAST },
+ MAZE_WEB | MAZE_BRICK }
+};
+
+Catacombs hard_catacombs[62] = {
+ { 401, { -1, 1, 2, 6 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BRICK },
+ { 404, { 10, 11, 3, 0 }, { SOUTH, WEST, NORTH, EAST }, MAZE_PUDDLE },
+ { 404, { 0, 3, 4, CATACOMBS_TO_309 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BLOCK },
+ { 401, { 1, 20, 5, 2 }, { SOUTH, NORTH, NORTH, EAST }, MAZE_POT },
+ { 453, { 2, 4, -1, 4 }, { SOUTH, WEST, NORTH, EAST }, MAZE_DRAIN },
+ { 403, { 3, 6, -1, 4 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BRICK | MAZE_PLANK },
+ { 406, { -1, 0, -1, 5 }, { SOUTH, WEST, NORTH, EAST }, 0 },
+ { 453, { -1, 8, -1, -1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BRICK },
+ /* 8 */
+ { 406, { -1, 9, -1, 7 }, { SOUTH, WEST, NORTH, EAST }, 0 },
+ { 401, { 1, -1, 10, 8 }, { NORTH, WEST, NORTH, EAST }, MAZE_RAT_NEST | MAZE_SKULL },
+ { 408, { 9, -1, 1, -1 }, { SOUTH, WEST, NORTH, EAST }, 0 },
+ { 453, { 12, -1, -1, 1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BRICK | MAZE_STONE },
+ /* 12 */
+ { 408, { 13, -1, 11, -1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BRICK },
+ { 401, { 13, 21, 12, 13 }, { WEST, WEST, NORTH, NORTH }, MAZE_BRICK },
+ { 453, { 16, 15, -1, 20 }, { SOUTH, WEST, NORTH, SOUTH }, MAZE_RAT_NEST | MAZE_BRICK },
+ { 456, { -1, -1, -1, 14 }, { SOUTH, WEST, NORTH, EAST }, 0 },
+ /* 16 */
+ { 404, { -1, 17, 14, -1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_WEB | MAZE_POT },
+ { 401, { 18, -1, 19, 16 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BRICK },
+ { 408, { -1, -1, 17, -1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BRICK },
+ { 403, { 17, -1, -1, -1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_HOLE | MAZE_WEB },
+ /* 20 */
+ { 408, { 3, -1, 14, -1 }, { EAST, WEST, WEST, EAST }, 0 },
+ { 404, { 9, 30, 22, 13 }, { NORTH, WEST, NORTH, EAST }, MAZE_RAT_NEST },
+ { 403, { 21, 23, -1, -1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_HOLE | MAZE_WEB },
+ { 401, { -1, -1, 24, 22 }, { SOUTH, WEST, WEST, EAST }, MAZE_BRICK },
+ /* 24 */
+ { 406, { -1, 26, -1, 23 }, { SOUTH, NORTH, NORTH, SOUTH }, 0 },
+ { 407, { 36, 33, 35, 34 }, { WEST, WEST, EAST, EAST }, 0 },
+ { 453, { 24, 27, -1, -1 }, { EAST, NORTH, NORTH, EAST }, MAZE_BRICK },
+ { 403, { 26, -1, -1, 28 }, { EAST, WEST, NORTH, NORTH }, MAZE_BRICK | MAZE_SKULL },
+ /* 28 */
+ { 404, { 27, 28, 28, 29 }, { WEST, SOUTH, EAST, SOUTH }, 0 },
+ { 408, { -1, -1, 28, -1 }, { SOUTH, WEST, WEST, EAST }, MAZE_BRICK },
+ { 406, { -1, 31, -1, 21 }, { SOUTH, NORTH, NORTH, EAST }, 0 },
+ { 401, { 30, 33, 1, -1 }, { EAST, SOUTH, EAST, EAST }, MAZE_PUDDLE | MAZE_POT },
+ /* 32 */
+ { 456, { -1, 31, -1, 33 }, { SOUTH, EAST, NORTH, NORTH }, 0 },
+ { 404, { 32, -1, 31, 25 }, { WEST, WEST, EAST, EAST }, 0 },
+ { 401, { 46, 25, 31, -1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_SKULL },
+ { 401, { -1, 25, 41, -1 }, { SOUTH, SOUTH, EAST, EAST }, MAZE_BRICK | MAZE_POT },
+ /* 36 */
+ { 406, { -1, 37, -1, 25 }, { SOUTH, WEST, NORTH, NORTH }, 0 },
+ { 453, { CATACOMBS_TO_409a, 37, -1, 36 }, { SOUTH, WEST, NORTH, EAST }, MAZE_STONE | MAZE_RAT_NEST | MAZE_WEB },
+ { 408, { 57, -1, 54, -1 }, { SOUTH, WEST, NORTH, EAST }, 0 },
+ { 408, { 40, -1, CATACOMBS_TO_409b, -1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BRICK | MAZE_WEB },
+ /* 40 */
+ { 404, { 40, 40, 39, 53 }, { EAST, NORTH, NORTH, EAST }, MAZE_BLOCK | MAZE_FALLEN_BLOCK },
+ { 456, { -1, 35, -1, 42 }, { SOUTH, SOUTH, NORTH, SOUTH }, 0 },
+ { 408, { 43, -1, 41, -1 }, { EAST, WEST, WEST, EAST }, MAZE_BRICK },
+ { 406, { -1, 42, -1, 61 }, { SOUTH, NORTH, NORTH, EAST }, 0 },
+ /* 44 */
+ { 403, { 58, 45, -1, -1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BRICK | MAZE_RAT_NEST },
+ { 401, { 34, -1, 46, 44 }, { NORTH, WEST, NORTH, EAST }, MAZE_RAT_NEST | MAZE_BRICK },
+ { 404, { 45, -1, 34, 47 }, { SOUTH, WEST, NORTH, EAST }, MAZE_WEB | MAZE_FALLEN_BLOCK },
+ { 406, { -1, 46, -1, 48 }, { SOUTH, WEST, NORTH, EAST }, 0 },
+ /* 48 */
+ { 403, { 49, 47, -1, -1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BRICK | MAZE_SKULL | MAZE_WEB },
+ { 408, { 50, -1, 48, -1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BRICK },
+ { 408, { 51, -1, 49, -1 }, { SOUTH, WEST, NORTH, EAST }, 0 },
+ { 408, { 52, -1, 50, -1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BRICK },
+ /* 52 */
+ { 408, { -1, -1, 51, -1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BRICK },
+ { 406, { -1, 40, -1, 54 }, { SOUTH, WEST, NORTH, EAST }, 0 },
+ { 403, { 38, 53, -1, 55 }, { SOUTH, WEST, NORTH, EAST }, MAZE_SKULL },
+ { 453, { 56, 54, -1, -1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BRICK | MAZE_WEB },
+ /* 56 */
+ { 401, { 56, CATACOMBS_TO_501, 55, 56 }, { WEST, WEST, NORTH, NORTH }, MAZE_BRICK | MAZE_SKULL },
+ { 404, { -1, 57, 38, 57 }, { SOUTH, WEST, NORTH, EAST }, MAZE_POT | MAZE_BLOCK },
+ { 404, { 59, 59, 44, 60 }, { SOUTH, WEST, NORTH, EAST }, 0 },
+ { 404, { 59, 60, 59, 58 }, { SOUTH, WEST, NORTH, EAST }, 0 },
+ /* 60 */
+ { 404, { 61, 58, 59, 59 }, { SOUTH, WEST, NORTH, EAST }, 0 },
+ { 404, { 34, 43, 60, 44 }, { NORTH, WEST, NORTH, EAST }, 0 }
+};
+
+void global_catacombs_init() {
+}
+
+void global_enter_catacombs(int special) {
+}
+
+int global_catacombs_exit(int exit) {
+ return catacombs[global[catacombs_room]].exit[exit];
+}
+
+static void global_catacombs_new_room(int catacomb_node, int from) {
+ int newRoom;
+
+ global[catacombs_next_room] = catacomb_node;
+ global[catacombs_from] = from & DIRECTION_MASK;
+ global[catacombs_flag] = from & FLAGS_MASK;
+
+ if (catacomb_node >= 0) {
+ newRoom = catacombs[catacomb_node].room_id;
+ global[catacombs_misc] = catacombs[catacomb_node].misc;
+ } else {
+ switch (catacomb_node) {
+ case CATACOMBS_TO_409a:
+ case CATACOMBS_TO_409b:
+ newRoom = 409;
+ break;
+
+ case CATACOMBS_TO_501:
+ newRoom = 501;
+ break;
+
+ case CATACOMBS_TO_309:
+ newRoom = 309;
+ break;
+
+ default:
+ error_report(ERROR_KERNEL_NO_ROOM, ERROR, MODULE_UNKNOWN, new_room, 0);
+ break;
+ }
+ }
+
+ if (kernel.trigger_setup_mode == KERNEL_TRIGGER_PREPARSE) {
+ player.walk_off_edge_to_room = newRoom;
+ } else {
+ new_room = newRoom;
+ kernel.force_restart = true;
+ }
+}
+
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/global.h b/engines/mads/madsv2/phantom/global.h
index 61cceb0a500..35d67a3944b 100644
--- a/engines/mads/madsv2/phantom/global.h
+++ b/engines/mads/madsv2/phantom/global.h
@@ -255,8 +255,29 @@ enum {
#define LANTERN_IS_OFF 0
#define LANTERN_IS_ON 1
-
+// Catacomb defines
+constexpr int NORTH = 0;
+constexpr int EAST = 1;
+constexpr int SOUTH = 2;
+constexpr int WEST = 3;
+
+constexpr int MAZE_PUDDLE = 0x0001; /* 401,404 */
+constexpr int MAZE_RAT_NEST = 0x0002; /* 401,403,453,404 */
+constexpr int MAZE_SKULL = 0x0004; /* 401,403 */
+constexpr int MAZE_POT = 0x0008; /* 401,404 */
+constexpr int MAZE_BRICK = 0x0010; /* 401,403,453,408 */
+constexpr int MAZE_HOLE = 0x0020; /* 403 */
+constexpr int MAZE_WEB = 0x0040; /* 403,453,404,408 */
+constexpr int MAZE_PLANK = 0x0080; /* 403 */
+constexpr int MAZE_DRAIN = 0x0100; /* 453 */
+constexpr int MAZE_STONE = 0x0200; /* 453 */
+constexpr int MAZE_BLOCK = 0x0400; /* 404 */
+constexpr int MAZE_FALLEN_BLOCK = 0x0800; /* 404 */
+
+extern void global_catacombs_init();
extern void global_enter_catacombs(int special);
+extern int global_catacombs_exit(int exit);
+extern void global_catacombs_move(int exit);
} // namespace Phantom
} // namespace MADSV2
diff --git a/engines/mads/madsv2/phantom/mads/text.h b/engines/mads/madsv2/phantom/mads/text.h
index fac0a4938ef..12e88a382b8 100644
--- a/engines/mads/madsv2/phantom/mads/text.h
+++ b/engines/mads/madsv2/phantom/mads/text.h
@@ -31,6 +31,8 @@ namespace Phantom {
/* Formula: text_RRR_NN = RRR * 100 + NN */
enum {
+ text_000_29 = 29,
+
text_008_06 = 806,
text_008_07 = 807,
text_008_16 = 816,
@@ -735,7 +737,23 @@ enum {
text_309_18 = 30918,
text_309_19 = 30919,
text_309_20 = 30920,
- text_309_21 = 30921
+ text_309_21 = 30921,
+
+ /* Room 401 */
+ text_401_10 = 40110,
+ text_401_11 = 40111,
+ text_401_12 = 40112,
+ text_401_13 = 40113,
+ text_401_14 = 40114,
+ text_401_15 = 40115,
+ text_401_16 = 40116,
+ text_401_17 = 40117,
+ text_401_18 = 40118,
+ text_401_19 = 40119,
+ text_401_20 = 40120,
+ text_401_21 = 40121,
+ text_401_22 = 40122,
+ text_401_23 = 40123,
};
} // namespace Phantom
diff --git a/engines/mads/madsv2/phantom/mads/words.h b/engines/mads/madsv2/phantom/mads/words.h
index 615ad75c705..9efeebbc49d 100644
--- a/engines/mads/madsv2/phantom/mads/words.h
+++ b/engines/mads/madsv2/phantom/mads/words.h
@@ -268,7 +268,10 @@ enum {
words_Monsieur_Richard = 302,
words_Julie = 303,
words_cable_hook = 304,
+ words_skull = 316,
words_Madame_Giry = 323,
+ words_more_catacombs = 325,
+ words_blocked_archway = 326,
words_catacombs = 328,
words_ticket_seller = 329,
words_usher = 330,
@@ -277,6 +280,13 @@ enum {
words_hat_rack = 340,
words_vase = 341,
words_clothes_dummy = 342,
+ words_archway_to_north = 344,
+ words_archway_to_west = 345,
+ words_archway_to_east = 346,
+ words_pot = 349,
+ words_puddle = 350,
+ words_rat_s_nest = 354,
+ words_broken_pot = 355,
words_Edgar_Degas = 385,
words_chandelier_cable = 386,
words_boat = 389,
diff --git a/engines/mads/madsv2/phantom/rooms/room401.cpp b/engines/mads/madsv2/phantom/rooms/room401.cpp
new file mode 100644
index 00000000000..70d26f77a5c
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room401.cpp
@@ -0,0 +1,549 @@
+/* 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 "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/camera.h"
+#include "mads/madsv2/core/inter.h"
+#include "mads/madsv2/core/matte.h"
+#include "mads/madsv2/core/object.h"
+#include "mads/madsv2/core/quote.h"
+#include "mads/madsv2/core/sound.h"
+#include "mads/madsv2/core/text.h"
+#include "mads/madsv2/phantom/mads/inventory.h"
+#include "mads/madsv2/phantom/mads/sounds.h"
+#include "mads/madsv2/phantom/rooms/section4.h"
+#include "mads/madsv2/phantom/rooms/room401.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+void room_401_init() {
+ global_catacombs_init();
+
+ local->anim_0_running = false;
+
+ kernel_flip_hotspot(words_puddle, false);
+ kernel_flip_hotspot(words_rat_s_nest, false);
+ kernel_flip_hotspot(words_skull, false);
+ kernel_flip_hotspot(words_pot, false);
+
+
+ /* =================== Load sprites series =================== */
+
+ ss[fx_bend_down_9] = kernel_load_series("*RRD_9", false);
+ ss[fx_red_frame] = kernel_load_series(kernel_name('f', 0), false);
+ ss[fx_green_frame] = kernel_load_series(kernel_name('f', 1), false);
+ ss[fx_blue_frame] = kernel_load_series(kernel_name('f', 2), false);
+ ss[fx_yellow_frame] = kernel_load_series(kernel_name('f', 3), false);
+
+
+
+ if (global_catacombs_exit(NORTH) == -1) {
+ ss[fx_north] = kernel_load_series(kernel_name('c', 1), false);
+ kernel_draw_to_background(ss[fx_north], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ kernel_flip_hotspot(words_archway_to_north, false);
+ }
+
+ if (global_catacombs_exit(WEST) == -1) {
+ ss[fx_west] = kernel_load_series(kernel_name('c', 0), false);
+ kernel_draw_to_background(ss[fx_west], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ kernel_flip_hotspot(words_archway_to_west, false);
+ }
+
+ if (global_catacombs_exit(EAST) == -1) {
+ ss[fx_east] = kernel_load_series(kernel_name('c', 2), false);
+ kernel_draw_to_background(ss[fx_east], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ kernel_flip_hotspot(words_archway_to_east, false);
+ }
+
+ if (global_catacombs_exit(SOUTH) == -1) {
+ kernel_flip_hotspot(words_more_catacombs, false);
+ }
+
+ if (global[catacombs_misc] & MAZE_RAT_NEST) {
+ ss[fx_rat_nest] = kernel_load_series(kernel_name('c', 4), false);
+ kernel_draw_to_background(ss[fx_rat_nest], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ kernel_flip_hotspot(words_rat_s_nest, true);
+ }
+
+ if (global[catacombs_misc] & MAZE_SKULL) {
+ ss[fx_skull] = kernel_load_series(kernel_name('c', 5), false);
+ kernel_draw_to_background(ss[fx_skull], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ kernel_flip_hotspot(words_skull, true);
+ }
+
+ if (global[catacombs_misc] & MAZE_POT) {
+ ss[fx_pot] = kernel_load_series(kernel_name('c', 6), false);
+ kernel_draw_to_background(ss[fx_pot], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ kernel_flip_hotspot(words_pot, true);
+ }
+
+ if (global[catacombs_misc] & MAZE_BRICK) {
+ ss[fx_brick] = kernel_load_series(kernel_name('c', 7), false);
+ kernel_draw_to_background(ss[fx_brick], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ }
+
+ if (global[catacombs_misc] & MAZE_PUDDLE) {
+ kernel_flip_hotspot(words_puddle, true);
+ aa[0] = kernel_run_animation(kernel_name('d', 1), 0);
+ local->anim_0_running = true;
+ }
+
+ if (previous_room != KERNEL_RESTORING_GAME) {
+
+ switch (global[catacombs_from]) {
+
+ case NORTH:
+ player.x = NORTH_X;
+ player.y = NORTH_Y;
+ player.facing = FACING_SOUTH;
+ player_walk(WALK_TO_NORTH_X, WALK_TO_NORTH_Y, FACING_SOUTH);
+ break;
+
+ case SOUTH:
+ player.x = SOUTH_X;
+ player.y = SOUTH_Y;
+ player.facing = FACING_NORTH;
+ break;
+
+ case EAST:
+ player.x = EAST_X;
+ player.y = EAST_Y;
+ player.facing = FACING_WEST;
+ player_walk(WALK_TO_EAST_X, WALK_TO_EAST_Y, FACING_WEST);
+ break;
+
+ case WEST:
+ player.x = WEST_X;
+ player.y = WEST_Y;
+ player.facing = FACING_SOUTH;
+ player_walk(WALK_TO_WEST_X, WALK_TO_WEST_Y, FACING_EAST);
+ break;
+ }
+ }
+
+ if (object[red_frame].location == (global[catacombs_room] + 600)) {
+ seq[fx_red_frame] = kernel_seq_stamp(ss[fx_red_frame], false, 1);
+ kernel_seq_depth(seq[fx_red_frame], 14);
+ local->dyn_red = kernel_add_dynamic(words_red_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5,
+ series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_red, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+
+ if (object[green_frame].location == (global[catacombs_room] + 600)) {
+ seq[fx_green_frame] = kernel_seq_stamp(ss[fx_green_frame], false, 1);
+ kernel_seq_depth(seq[fx_green_frame], 14);
+ local->dyn_green = kernel_add_dynamic(words_green_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5,
+ series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_green, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+
+ if (object[blue_frame].location == (global[catacombs_room] + 600)) {
+ seq[fx_blue_frame] = kernel_seq_stamp(ss[fx_blue_frame], false, 1);
+ kernel_seq_depth(seq[fx_blue_frame], 14);
+ local->dyn_blue = kernel_add_dynamic(words_blue_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5,
+ series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_blue, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+
+ if (object[yellow_frame].location == (global[catacombs_room] + 600)) {
+ seq[fx_yellow_frame] = kernel_seq_stamp(ss[fx_yellow_frame], false, 1);
+ kernel_seq_depth(seq[fx_yellow_frame], 14);
+ local->dyn_yellow = kernel_add_dynamic(words_yellow_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5,
+ series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_yellow, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+ section_4_music();
+}
+
+void room_401_pre_parser() {
+ local->frame_is_here = false;
+ local->frame_here_for_taking = false;
+
+ if (object[red_frame].location == (global[catacombs_room] + 600)) {
+ local->frame_is_here = true;
+ if (player_said_2(take, red_frame)) {
+ local->frame_here_for_taking = true;
+ }
+ }
+
+ if (object[yellow_frame].location == (global[catacombs_room] + 600)) {
+ local->frame_is_here = true;
+ if (player_said_2(take, yellow_frame)) {
+ local->frame_here_for_taking = true;
+ }
+ }
+
+ if (object[blue_frame].location == (global[catacombs_room] + 600)) {
+ local->frame_is_here = true;
+ if (player_said_2(take, blue_frame)) {
+ local->frame_here_for_taking = true;
+ }
+ }
+
+ if (object[green_frame].location == (global[catacombs_room] + 600)) {
+ local->frame_is_here = true;
+ if (player_said_2(take, green_frame)) {
+ local->frame_here_for_taking = true;
+ }
+ }
+
+ if (player_said_1(put) && player_said_1(floor)) {
+ if (player_said_1(red_frame) ||
+ player_said_1(blue_frame) ||
+ player_said_1(yellow_frame) ||
+ player_said_1(green_frame)) {
+ if (local->frame_is_here) {
+ player.need_to_walk = false;
+
+ } else {
+ player_walk(series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+ }
+ }
+}
+
+void room_401_parser() {
+ if (player_said_1(put) && player_said_1(floor)) {
+ if (player_said_1(red_frame) ||
+ player_said_1(blue_frame) ||
+ player_said_1(yellow_frame) ||
+ player_said_1(green_frame)) {
+ if (local->frame_is_here) {
+ text_show(text_000_29);
+ goto handled;
+
+ } else {
+
+ switch (kernel.trigger) {
+ case (0):
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_bend_down_9] = kernel_seq_pingpong(ss[fx_bend_down_9], true,
+ 5, 0, 0, 2);
+ kernel_seq_range(seq[fx_bend_down_9], 1, 5);
+ kernel_seq_player(seq[fx_bend_down_9], true);
+ kernel_seq_trigger(seq[fx_bend_down_9],
+ KERNEL_TRIGGER_SPRITE, 5, 1);
+ kernel_seq_trigger(seq[fx_bend_down_9],
+ KERNEL_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ if (player_said_1(red_frame)) {
+ inter_move_object(red_frame, NOWHERE);
+ object[red_frame].location = global[catacombs_room] + 600;
+ seq[fx_red_frame] = kernel_seq_stamp(ss[fx_red_frame], false, 1);
+ kernel_seq_depth(seq[fx_red_frame], 14);
+ local->dyn_red = kernel_add_dynamic(words_red_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5, series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_red, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+
+ if (player_said_1(green_frame)) {
+ inter_move_object(green_frame, NOWHERE);
+ object[green_frame].location = global[catacombs_room] + 600;
+ seq[fx_green_frame] = kernel_seq_stamp(ss[fx_green_frame], false, 1);
+ kernel_seq_depth(seq[fx_green_frame], 14);
+ local->dyn_green = kernel_add_dynamic(words_green_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5, series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_green, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+
+ if (player_said_1(blue_frame)) {
+ inter_move_object(blue_frame, NOWHERE);
+ object[blue_frame].location = global[catacombs_room] + 600;
+ seq[fx_blue_frame] = kernel_seq_stamp(ss[fx_blue_frame], false, 1);
+ kernel_seq_depth(seq[fx_blue_frame], 14);
+ local->dyn_blue = kernel_add_dynamic(words_blue_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5, series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_blue, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+
+ if (player_said_1(yellow_frame)) {
+ inter_move_object(yellow_frame, NOWHERE);
+ object[yellow_frame].location = global[catacombs_room] + 600;
+ seq[fx_yellow_frame] = kernel_seq_stamp(ss[fx_yellow_frame], false, 1);
+ kernel_seq_depth(seq[fx_yellow_frame], 14);
+ local->dyn_yellow = kernel_add_dynamic(words_yellow_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5, series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_yellow, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+ break;
+
+ case 2:
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_SERIES, seq[fx_bend_down_9]);
+ player.walker_visible = true;
+ player.commands_allowed = true;
+ break;
+ }
+ goto handled;
+ }
+ }
+ }
+
+
+ if (player_said_1(take)) {
+ if (player_said_1(red_frame) || player_said_1(green_frame) ||
+ player_said_1(blue_frame) || player_said_1(yellow_frame)) {
+
+ if ((local->frame_here_for_taking || kernel.trigger)) {
+ switch (kernel.trigger) {
+ case (0):
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_bend_down_9] = kernel_seq_pingpong(ss[fx_bend_down_9], true,
+ 5, 0, 0, 2);
+ kernel_seq_range(seq[fx_bend_down_9], 1, 5);
+ kernel_seq_player(seq[fx_bend_down_9], true);
+ kernel_seq_trigger(seq[fx_bend_down_9],
+ KERNEL_TRIGGER_SPRITE, 5, 1);
+ kernel_seq_trigger(seq[fx_bend_down_9],
+ KERNEL_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ if (player_said_1(red_frame)) {
+ kernel_seq_delete(seq[fx_red_frame]);
+ kernel_delete_dynamic(local->dyn_red);
+ inter_give_to_player(red_frame);
+ }
+
+ if (player_said_1(green_frame)) {
+ kernel_seq_delete(seq[fx_green_frame]);
+ kernel_delete_dynamic(local->dyn_green);
+ inter_give_to_player(green_frame);
+ }
+
+ if (player_said_1(blue_frame)) {
+ kernel_seq_delete(seq[fx_blue_frame]);
+ kernel_delete_dynamic(local->dyn_blue);
+ inter_give_to_player(blue_frame);
+ }
+
+ if (player_said_1(yellow_frame)) {
+ kernel_seq_delete(seq[fx_yellow_frame]);
+ kernel_delete_dynamic(local->dyn_yellow);
+ inter_give_to_player(yellow_frame);
+ }
+
+ sound_play(N_TakeObjectSnd);
+ break;
+
+ case 2:
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_SERIES, seq[fx_bend_down_9]);
+ player.walker_visible = true;
+ player.commands_allowed = true;
+ break;
+ }
+ goto handled;
+ }
+ }
+ }
+
+ if (player_said_2(walk_through, archway_to_north)) {
+ global_catacombs_move(NORTH);
+ goto handled;
+ }
+
+ if (player_said_2(walk_through, archway_to_west)) {
+ global_catacombs_move(WEST);
+ goto handled;
+ }
+
+ if (player_said_2(exit_to, more_catacombs)) {
+ global_catacombs_move(SOUTH);
+ if (game.difficulty == HARD_MODE) {
+ if (global[catacombs_room] == 31) {
+ global[priest_piston_puke] = true;
+ }
+ }
+ goto handled;
+ }
+
+ if (player_said_2(walk_through, archway_to_east)) {
+ global_catacombs_move(EAST);
+ if (game.difficulty == EASY_MODE) {
+ if (global[catacombs_room] == 24) {
+ global[priest_piston_puke] = true;
+ }
+ }
+ goto handled;
+ }
+
+ if (player.look_around) {
+ text_show(text_401_10);
+ goto handled;
+ }
+
+ if (player_said_1(look) || player_said_1(look_at)) {
+
+ if (player_said_1(wall)) {
+ text_show(text_401_11);
+ goto handled;
+ }
+
+ if (player_said_1(floor)) {
+ text_show(text_401_12);
+ goto handled;
+ }
+
+ if (player_said_1(archway)) {
+ text_show(text_401_13);
+ goto handled;
+ }
+
+ if (player_said_1(exposed_brick)) {
+ text_show(text_401_14);
+ goto handled;
+ }
+
+ if (player_said_1(more_catacombs)) {
+ text_show(text_401_15);
+ goto handled;
+ }
+
+ if (player_said_1(blocked_archway)) {
+ text_show(text_401_16);
+ goto handled;
+ }
+
+ if (player_said_1(puddle)) {
+ text_show(text_401_17);
+ goto handled;
+ }
+
+ if (player_said_1(rat_s_nest)) {
+ text_show(text_401_18);
+ goto handled;
+ }
+
+ if (player_said_1(skull)) {
+ text_show(text_401_20);
+ goto handled;
+ }
+
+ if (player_said_1(red_frame)) {
+ if (!player_has(red_frame)) {
+ object_examine(red_frame, text_008_02, 0);
+ goto handled;
+ }
+ }
+
+ if (player_said_1(green_frame)) {
+ if (!player_has(green_frame)) {
+ object_examine(green_frame, text_008_19, 0);
+ goto handled;
+ }
+ }
+
+ if (player_said_1(blue_frame)) {
+ if (!player_has(blue_frame)) {
+ object_examine(blue_frame, text_008_17, 0);
+ goto handled;
+ }
+ }
+
+ if (player_said_1(yellow_frame)) {
+ if (!player_has(yellow_frame)) {
+ object_examine(yellow_frame, text_008_04, 0);
+ goto handled;
+ }
+ }
+
+
+ if (player_said_1(broken_pot)) {
+ text_show(text_401_22);
+ goto handled;
+ }
+ }
+
+ if (player_said_2(take, rat_s_nest)) {
+ text_show(text_401_19);
+ goto handled;
+ }
+
+ if (player_said_2(take, skull)) {
+ text_show(text_401_21);
+ goto handled;
+ }
+
+ if (player_said_2(take, broken_pot)) {
+ text_show(text_401_23);
+ goto handled;
+ }
+
+ goto done;
+
+handled:
+ player.command_ready = false;
+
+done:
+ ;
+}
+
+void room_401_daemon() {
+ if (local->anim_0_running) {
+ if (kernel_anim[aa[0]].frame == 20) {
+ kernel_reset_animation(aa[0], 0);
+ }
+ }
+}
+
+void room_401_preload() {
+ room_init_code_pointer = room_401_init;
+ room_pre_parser_code_pointer = room_401_pre_parser;
+ room_parser_code_pointer = room_401_parser;
+ room_daemon_code_pointer = room_401_daemon;
+
+ section_4_walker();
+ section_4_interface();
+
+ if (global[catacombs_misc] & MAZE_PUDDLE) {
+ kernel_initial_variant = 1;
+ }
+
+ vocab_make_active(words_red_frame);
+ vocab_make_active(words_yellow_frame);
+ vocab_make_active(words_blue_frame);
+ vocab_make_active(words_green_frame);
+}
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/rooms/room401.h b/engines/mads/madsv2/phantom/rooms/room401.h
new file mode 100644
index 00000000000..88c846c7719
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room401.h
@@ -0,0 +1,100 @@
+/* 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 MADS_PHANTOM_ROOM401_H
+#define MADS_PHANTOM_ROOM401_H
+
+#include "mads/madsv2/core/general.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+#define local ((Scratch *)(&game.scratch[0]))
+#define ss local->sprite
+#define seq local->sequence
+#define aa local->animation
+
+typedef struct { /* Room local variables */
+
+ int16 sprite[15]; /* Sprite series handles */
+ int16 sequence[15]; /* Sequence handles */
+ int16 animation[4]; /* Animation handles */
+ int16 anim_0_running;
+ int16 frame_is_here; /* T if any frame is here */
+ int16 dyn_red;
+ int16 dyn_green;
+ int16 dyn_blue;
+ int16 dyn_yellow;
+ int16 frame_here_for_taking; /* T if a specific frame is here */
+
+} Scratch;
+
+
+/* ========================= Sprite Series =================== */
+
+#define fx_west 0 /* rm403c0 */
+#define fx_north 1 /* rm403c1 */
+#define fx_east 2 /* rm403c2 */
+
+#define fx_puddle 3
+#define fx_rat_nest 4
+#define fx_skull 5
+#define fx_pot 6
+#define fx_brick 7
+
+#define fx_bend_down_9 8 /* rrd_9 */
+#define fx_red_frame 9 /* rm401f0 */
+#define fx_green_frame 10 /* rm401f1 */
+#define fx_blue_frame 11 /* rm401f2 */
+#define fx_yellow_frame 12 /* rm401f3 */
+
+/* ========================= Other Macros ==================== */
+
+#define NORTH_X 128
+#define NORTH_Y 79
+
+#define WALK_TO_NORTH_X 128
+#define WALK_TO_NORTH_Y 91
+
+#define WEST_X 4
+#define WEST_Y 113
+
+#define WALK_TO_WEST_X 48
+#define WALK_TO_WEST_Y 113
+
+#define EAST_X 311
+#define EAST_Y 115
+
+#define WALK_TO_EAST_X 271
+#define WALK_TO_EAST_Y 123
+
+#define SOUTH_X 142
+#define SOUTH_Y 146
+
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif // MADS_PHANTOM_ROOM250_H
diff --git a/engines/mads/madsv2/phantom/rooms/section4.h b/engines/mads/madsv2/phantom/rooms/section4.h
new file mode 100644
index 00000000000..47f0c789d56
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/section4.h
@@ -0,0 +1,44 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 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 MADS_PHANTOM_SECTION4_H
+#define MADS_PHANTOM_SECTION4_H
+
+#include "mads/madsv2/phantom/global.h"
+#include "mads/madsv2/phantom/mads/text.h"
+#include "mads/madsv2/phantom/mads/words.h"
+#include "mads/madsv2/core/vocabh.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+extern void section_4_music();
+extern void section_4_walker();
+extern void section_4_interface();
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index e069d423bd3..54df3b064ec 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -157,8 +157,10 @@ MODULE_OBJS += \
madsv2/phantom/rooms/room308.o \
madsv2/phantom/rooms/room309.o \
madsv2/phantom/rooms/room310.o \
+ madsv2/phantom/rooms/room401.o \
madsv2/phantom/phantom.o \
madsv2/phantom/conv.o \
+ madsv2/phantom/global.o \
madsv2/phantom/main_menu.o \
madsv2/phantom/main.o \
madsv2/phantom/sound_phantom.o
Commit: 1eca97ab613606c3dc42f0ea5dbc61d31ada86ee
https://github.com/scummvm/scummvm/commit/1eca97ab613606c3dc42f0ea5dbc61d31ada86ee
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:49+10:00
Commit Message:
MADS: PHANTOM: Added room 403
Changed paths:
A engines/mads/madsv2/phantom/rooms/room403.cpp
A engines/mads/madsv2/phantom/rooms/room403.h
engines/mads/madsv2/phantom/global.cpp
engines/mads/madsv2/phantom/mads/text.h
engines/mads/madsv2/phantom/mads/words.h
engines/mads/module.mk
diff --git a/engines/mads/madsv2/phantom/global.cpp b/engines/mads/madsv2/phantom/global.cpp
index ea7617f6038..968b90d84c1 100644
--- a/engines/mads/madsv2/phantom/global.cpp
+++ b/engines/mads/madsv2/phantom/global.cpp
@@ -20,6 +20,9 @@
*/
#include "mads/madsv2/phantom/global.h"
+#include "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/error.h"
namespace MADS {
namespace MADSV2 {
@@ -172,14 +175,28 @@ Catacombs hard_catacombs[62] = {
{ 404, { 34, 43, 60, 44 }, { NORTH, WEST, NORTH, EAST }, 0 }
};
-void global_catacombs_init() {
-}
-
-void global_enter_catacombs(int special) {
-}
-
-int global_catacombs_exit(int exit) {
- return catacombs[global[catacombs_room]].exit[exit];
+static void global_catacombs_setup() {
+ if (game.difficulty == HARD_MODE) {
+ catacombs = hard_catacombs;
+ global[catacombs_309_from] = 3;
+ global[catacombs_409a] = 37;
+ global[catacombs_409a_from] = 0;
+ global[catacombs_409b] = 39;
+ global[catacombs_309] = 2;
+ global[catacombs_409b_from] = 2;
+ global[catacombs_501] = 56;
+ global[catacombs_501_from] = 1;
+ } else {
+ catacombs = easy_catacombs;
+ global[catacombs_309_from] = 3;
+ global[catacombs_409a] = 30;
+ global[catacombs_309] = 2;
+ global[catacombs_409b_from] = 2;
+ global[catacombs_409b] = 31;
+ global[catacombs_501] = 31;
+ global[catacombs_409a_from] = 0;
+ global[catacombs_501_from] = 0;
+ }
}
static void global_catacombs_new_room(int catacomb_node, int from) {
@@ -221,6 +238,18 @@ static void global_catacombs_new_room(int catacomb_node, int from) {
}
}
+void global_catacombs_init() {
+ global_catacombs_setup();
+ global[catacombs_next_room] = global[catacombs_room];
+}
+
+void global_enter_catacombs(int special) {
+}
+
+int global_catacombs_exit(int exit) {
+ return catacombs[global[catacombs_room]].exit[exit];
+}
+
} // namespace Phantom
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/mads/text.h b/engines/mads/madsv2/phantom/mads/text.h
index 12e88a382b8..86829193894 100644
--- a/engines/mads/madsv2/phantom/mads/text.h
+++ b/engines/mads/madsv2/phantom/mads/text.h
@@ -32,6 +32,7 @@ namespace Phantom {
enum {
text_000_29 = 29,
+ text_000_31 = 31,
text_008_06 = 806,
text_008_07 = 807,
@@ -754,6 +755,26 @@ enum {
text_401_21 = 40121,
text_401_22 = 40122,
text_401_23 = 40123,
+
+ /* Room 403 */
+ text_403_10 = 40310,
+ text_403_11 = 40311,
+ text_403_12 = 40312,
+ text_403_13 = 40313,
+ text_403_14 = 40314,
+ text_403_15 = 40315,
+ text_403_16 = 40316,
+ text_403_17 = 40317,
+ text_403_18 = 40318,
+ text_403_19 = 40319,
+ text_403_20 = 40320,
+ text_403_21 = 40321,
+ text_403_23 = 40323,
+ text_403_24 = 40324,
+ text_403_25 = 40325,
+ text_403_26 = 40326,
+ text_453_30 = 45330,
+ text_453_31 = 45331
};
} // namespace Phantom
diff --git a/engines/mads/madsv2/phantom/mads/words.h b/engines/mads/madsv2/phantom/mads/words.h
index 9efeebbc49d..2ba6437e407 100644
--- a/engines/mads/madsv2/phantom/mads/words.h
+++ b/engines/mads/madsv2/phantom/mads/words.h
@@ -283,8 +283,11 @@ enum {
words_archway_to_north = 344,
words_archway_to_west = 345,
words_archway_to_east = 346,
+ words_gate = 347,
words_pot = 349,
words_puddle = 350,
+ words_web = 351,
+ words_plank = 352,
words_rat_s_nest = 354,
words_broken_pot = 355,
words_Edgar_Degas = 385,
diff --git a/engines/mads/madsv2/phantom/rooms/room403.cpp b/engines/mads/madsv2/phantom/rooms/room403.cpp
new file mode 100644
index 00000000000..b04148bce15
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room403.cpp
@@ -0,0 +1,551 @@
+/* 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 "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/camera.h"
+#include "mads/madsv2/core/inter.h"
+#include "mads/madsv2/core/matte.h"
+#include "mads/madsv2/core/object.h"
+#include "mads/madsv2/core/quote.h"
+#include "mads/madsv2/core/sound.h"
+#include "mads/madsv2/core/text.h"
+#include "mads/madsv2/phantom/mads/inventory.h"
+#include "mads/madsv2/phantom/mads/sounds.h"
+#include "mads/madsv2/phantom/rooms/section4.h"
+#include "mads/madsv2/phantom/rooms/room403.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+void room_403_init() {
+ global_catacombs_init();
+
+ kernel_flip_hotspot(words_hole, false);
+ kernel_flip_hotspot(words_web, false);
+ kernel_flip_hotspot(words_rat_s_nest, false);
+ kernel_flip_hotspot(words_skull, false);
+ kernel_flip_hotspot(words_plank, false);
+ kernel_flip_hotspot(words_gate, false);
+
+ /* =================== Load sprites series =================== */
+
+ ss[fx_bend_down_9] = kernel_load_series("*RRD_9", false);
+ ss[fx_red_frame] = kernel_load_series(kernel_name('f', 0), false);
+ ss[fx_green_frame] = kernel_load_series(kernel_name('f', 1), false);
+ ss[fx_blue_frame] = kernel_load_series(kernel_name('f', 2), false);
+ ss[fx_yellow_frame] = kernel_load_series(kernel_name('f', 3), false);
+
+ if (global_catacombs_exit(NORTH) == -1) {
+ ss[fx_north] = kernel_load_series(kernel_name('c', 1), false);
+ kernel_draw_to_background(ss[fx_north], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ kernel_flip_hotspot(words_archway_to_north, false);
+ }
+
+ if (global_catacombs_exit(WEST) == -1) {
+ ss[fx_west] = kernel_load_series(kernel_name('c', 0), false);
+ kernel_draw_to_background(ss[fx_west], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ kernel_flip_hotspot(words_archway_to_west, false);
+ }
+
+ if (global_catacombs_exit(EAST) == -1) {
+ kernel_flip_hotspot(words_more_catacombs, false);
+ kernel_flip_hotspot(words_gate, true);
+ ss[fx_gate] = kernel_load_series(kernel_name('c', 9), false);
+ kernel_draw_to_background(ss[fx_gate], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ }
+
+
+
+ if (global[catacombs_misc] & MAZE_HOLE) {
+ ss[fx_hole] = kernel_load_series(kernel_name('c', 3), false);
+ kernel_draw_to_background(ss[fx_hole], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ kernel_flip_hotspot(words_hole, true);
+ }
+
+ if (global[catacombs_misc] & MAZE_WEB) {
+ ss[fx_web] = kernel_load_series(kernel_name('c', 4), false);
+ kernel_draw_to_background(ss[fx_web], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ kernel_flip_hotspot(words_web, true);
+ }
+
+ if (global[catacombs_misc] & MAZE_BRICK) {
+ ss[fx_brick] = kernel_load_series(kernel_name('c', 5), false);
+ kernel_draw_to_background(ss[fx_brick], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ kernel_flip_hotspot_loc(words_exposed_brick, false, BRICK_X, BRICK_Y);
+ }
+
+ if (global[catacombs_misc] & MAZE_RAT_NEST) {
+ ss[fx_rat_nest] = kernel_load_series(kernel_name('c', 6), false);
+ kernel_draw_to_background(ss[fx_rat_nest], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ kernel_flip_hotspot(words_rat_s_nest, true);
+ }
+
+ if (global[catacombs_misc] & MAZE_SKULL) {
+ ss[fx_skull] = kernel_load_series(kernel_name('c', 7), false);
+ kernel_draw_to_background(ss[fx_skull], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ kernel_flip_hotspot(words_skull, true);
+ }
+
+ if (global[catacombs_misc] & MAZE_PLANK) {
+ ss[fx_plank] = kernel_load_series(kernel_name('c', 8), false);
+ kernel_draw_to_background(ss[fx_plank], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ kernel_flip_hotspot(words_plank, true);
+ }
+
+ if (previous_room != KERNEL_RESTORING_GAME) {
+
+ switch (global[catacombs_from]) {
+
+ case NORTH:
+ player.x = NORTH_X;
+ player.y = NORTH_Y;
+ player.facing = FACING_SOUTH;
+ player_walk(WALK_TO_NORTH_X, WALK_TO_NORTH_Y, FACING_SOUTH);
+ break;
+
+ case EAST:
+ player_first_walk(EAST_X, EAST_Y, FACING_EAST,
+ WALK_TO_EAST_X, WALK_TO_EAST_Y, FACING_WEST, true);
+ break;
+
+ case WEST:
+ player.x = WEST_X;
+ player.y = WEST_Y;
+ player.facing = FACING_SOUTH;
+ player_walk(WALK_TO_WEST_X, WALK_TO_WEST_Y, FACING_EAST);
+ break;
+ }
+ }
+
+ if (object[red_frame].location == global[catacombs_room] + 600) {
+ seq[fx_red_frame] = kernel_seq_stamp(ss[fx_red_frame], false, 1);
+ kernel_seq_depth(seq[fx_red_frame], 14);
+ local->dyn_red = kernel_add_dynamic(words_red_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5,
+ series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_red, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+
+ if (object[green_frame].location == global[catacombs_room] + 600) {
+ seq[fx_green_frame] = kernel_seq_stamp(ss[fx_green_frame], false, 1);
+ kernel_seq_depth(seq[fx_green_frame], 14);
+ local->dyn_green = kernel_add_dynamic(words_green_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5,
+ series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_green, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+
+ if (object[blue_frame].location == global[catacombs_room] + 600) {
+ seq[fx_blue_frame] = kernel_seq_stamp(ss[fx_blue_frame], false, 1);
+ kernel_seq_depth(seq[fx_blue_frame], 14);
+ local->dyn_blue = kernel_add_dynamic(words_blue_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5,
+ series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_blue, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+
+ if (object[yellow_frame].location == global[catacombs_room] + 600) {
+ seq[fx_yellow_frame] = kernel_seq_stamp(ss[fx_yellow_frame], false, 1);
+ kernel_seq_depth(seq[fx_yellow_frame], 14);
+ local->dyn_yellow = kernel_add_dynamic(words_yellow_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5,
+ series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_yellow, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+
+ if (game.difficulty == EASY_MODE) {
+ if (global[catacombs_room] == 19) {
+ kernel_timing_trigger(TWO_SECONDS, ROOM_403_SHOW_TEXT);
+ }
+ }
+
+ section_4_music();
+}
+
+void room_403_pre_parser() {
+ if (player_said_2(exit_to, more_catacombs)) {
+ global_catacombs_move(EAST);
+ }
+
+ local->frame_is_here = false;
+ local->frame_here_for_taking = false;
+
+ if (object[red_frame].location == global[catacombs_room] + 600) {
+ local->frame_is_here = true;
+ if (player_said_2(take, red_frame)) {
+ local->frame_here_for_taking = true;
+ }
+ }
+
+ if (object[yellow_frame].location == global[catacombs_room] + 600) {
+ local->frame_is_here = true;
+ if (player_said_2(take, yellow_frame)) {
+ local->frame_here_for_taking = true;
+ }
+ }
+
+ if (object[blue_frame].location == global[catacombs_room] + 600) {
+ local->frame_is_here = true;
+ if (player_said_2(take, blue_frame)) {
+ local->frame_here_for_taking = true;
+ }
+ }
+
+ if (object[green_frame].location == global[catacombs_room] + 600) {
+ local->frame_is_here = true;
+ if (player_said_2(take, green_frame)) {
+ local->frame_here_for_taking = true;
+ }
+ }
+
+ if (player_said_1(put) && player_said_1(floor)) {
+ if (player_said_1(red_frame) ||
+ player_said_1(blue_frame) ||
+ player_said_1(yellow_frame) ||
+ player_said_1(green_frame)) {
+ if (local->frame_is_here) {
+ player.need_to_walk = false;
+
+ } else {
+ player_walk(series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+ }
+ }
+}
+
+void room_403_parser() {
+ if (player_said_1(put) && player_said_1(floor)) {
+ if (player_said_1(red_frame) ||
+ player_said_1(blue_frame) ||
+ player_said_1(yellow_frame) ||
+ player_said_1(green_frame)) {
+ if (local->frame_is_here) {
+ text_show(text_000_29);
+ goto handled;
+
+ } else {
+
+ switch (kernel.trigger) {
+ case (0):
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_bend_down_9] = kernel_seq_pingpong(ss[fx_bend_down_9], true,
+ 5, 0, 0, 2);
+ kernel_seq_range(seq[fx_bend_down_9], 1, 5);
+ kernel_seq_player(seq[fx_bend_down_9], true);
+ kernel_seq_trigger(seq[fx_bend_down_9],
+ KERNEL_TRIGGER_SPRITE, 5, 1);
+ kernel_seq_trigger(seq[fx_bend_down_9],
+ KERNEL_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ if (player_said_1(red_frame)) {
+ inter_move_object(red_frame, NOWHERE);
+ object[red_frame].location = global[catacombs_room] + 600;
+ seq[fx_red_frame] = kernel_seq_stamp(ss[fx_red_frame], false, 1);
+ kernel_seq_depth(seq[fx_red_frame], 14);
+ local->dyn_red = kernel_add_dynamic(words_red_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5, series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_red, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+
+ if (player_said_1(green_frame)) {
+ inter_move_object(green_frame, NOWHERE);
+ object[green_frame].location = global[catacombs_room] + 600;
+ seq[fx_green_frame] = kernel_seq_stamp(ss[fx_green_frame], false, 1);
+ kernel_seq_depth(seq[fx_green_frame], 14);
+ local->dyn_green = kernel_add_dynamic(words_green_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5, series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_green, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+
+ if (player_said_1(blue_frame)) {
+ inter_move_object(blue_frame, NOWHERE);
+ object[blue_frame].location = global[catacombs_room] + 600;
+ seq[fx_blue_frame] = kernel_seq_stamp(ss[fx_blue_frame], false, 1);
+ kernel_seq_depth(seq[fx_blue_frame], 14);
+ local->dyn_blue = kernel_add_dynamic(words_blue_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5, series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_blue, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+
+ if (player_said_1(yellow_frame)) {
+ inter_move_object(yellow_frame, NOWHERE);
+ object[yellow_frame].location = global[catacombs_room] + 600;
+ seq[fx_yellow_frame] = kernel_seq_stamp(ss[fx_yellow_frame], false, 1);
+ kernel_seq_depth(seq[fx_yellow_frame], 14);
+ local->dyn_yellow = kernel_add_dynamic(words_yellow_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5, series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_yellow, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+ break;
+
+ case 2:
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_SERIES, seq[fx_bend_down_9]);
+ player.walker_visible = true;
+ player.commands_allowed = true;
+ break;
+ }
+ goto handled;
+ }
+ }
+ }
+
+
+ if (player_said_1(take)) {
+ if (player_said_1(red_frame) || player_said_1(green_frame) ||
+ player_said_1(blue_frame) || player_said_1(yellow_frame)) {
+
+ if ((local->frame_here_for_taking || kernel.trigger)) {
+ switch (kernel.trigger) {
+ case (0):
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_bend_down_9] = kernel_seq_pingpong(ss[fx_bend_down_9], true,
+ 5, 0, 0, 2);
+ kernel_seq_range(seq[fx_bend_down_9], 1, 5);
+ kernel_seq_player(seq[fx_bend_down_9], true);
+ kernel_seq_trigger(seq[fx_bend_down_9],
+ KERNEL_TRIGGER_SPRITE, 5, 1);
+ kernel_seq_trigger(seq[fx_bend_down_9],
+ KERNEL_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ if (player_said_1(red_frame)) {
+ kernel_seq_delete(seq[fx_red_frame]);
+ kernel_delete_dynamic(local->dyn_red);
+ inter_give_to_player(red_frame);
+ }
+
+ if (player_said_1(green_frame)) {
+ kernel_seq_delete(seq[fx_green_frame]);
+ kernel_delete_dynamic(local->dyn_green);
+ inter_give_to_player(green_frame);
+ }
+
+ if (player_said_1(blue_frame)) {
+ kernel_seq_delete(seq[fx_blue_frame]);
+ kernel_delete_dynamic(local->dyn_blue);
+ inter_give_to_player(blue_frame);
+ }
+
+ if (player_said_1(yellow_frame)) {
+ kernel_seq_delete(seq[fx_yellow_frame]);
+ kernel_delete_dynamic(local->dyn_yellow);
+ inter_give_to_player(yellow_frame);
+ }
+
+ sound_play(N_TakeObjectSnd);
+ break;
+
+ case 2:
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_SERIES, seq[fx_bend_down_9]);
+ player.walker_visible = true;
+ player.commands_allowed = true;
+ break;
+ }
+ goto handled;
+ }
+ }
+ }
+
+ if (player_said_2(walk_through, archway_to_north)) {
+ global_catacombs_move(NORTH);
+ goto handled;
+ }
+
+ if (player_said_2(walk_through, archway_to_west)) {
+ global_catacombs_move(WEST);
+ goto handled;
+ }
+
+ if (player.look_around) {
+ text_show(text_403_10);
+ goto handled;
+ }
+
+ if (player_said_1(look) || player_said_1(look_at)) {
+
+ if (player_said_1(wall)) {
+ text_show(text_403_11);
+ goto handled;
+ }
+
+ if (player_said_1(floor)) {
+ text_show(text_403_12);
+ goto handled;
+ }
+
+ if (player_said_1(archway)) {
+ text_show(text_403_13);
+ goto handled;
+ }
+
+ if (player_said_1(exposed_brick)) {
+ text_show(text_403_14);
+ goto handled;
+ }
+
+ if (player_said_1(more_catacombs)) {
+ text_show(text_403_15);
+ goto handled;
+ }
+
+ if (player_said_1(blocked_archway)) {
+ text_show(text_403_16);
+ goto handled;
+ }
+
+ if (player_said_1(rat_s_nest)) {
+ text_show(text_403_18);
+ goto handled;
+ }
+
+ if (player_said_1(skull)) {
+ text_show(text_403_20);
+ goto handled;
+ }
+
+ if (player_said_1(hole)) {
+ text_show(text_403_23);
+ goto handled;
+ }
+
+ if (player_said_1(web)) {
+ text_show(text_403_24);
+ goto handled;
+ }
+
+ if (player_said_1(red_frame)) {
+ if (!player_has(red_frame)) {
+ object_examine(red_frame, text_008_02, 0);
+ goto handled;
+ }
+ }
+
+ if (player_said_1(green_frame)) {
+ if (!player_has(green_frame)) {
+ object_examine(green_frame, text_008_19, 0);
+ goto handled;
+ }
+ }
+
+ if (player_said_1(blue_frame)) {
+ if (!player_has(blue_frame)) {
+ object_examine(blue_frame, text_008_17, 0);
+ goto handled;
+ }
+ }
+
+ if (player_said_1(yellow_frame)) {
+ if (!player_has(yellow_frame)) {
+ object_examine(yellow_frame, text_008_04, 0);
+ goto handled;
+ }
+ }
+
+ if (player_said_1(gate)) {
+ text_show(text_453_30);
+ goto handled;
+ }
+
+ if (player_said_1(plank)) {
+ text_show(text_403_25);
+ goto handled;
+ }
+ }
+
+ if (player_said_2(open, gate)) {
+ text_show(text_453_31);
+ goto handled;
+ }
+
+ if (player_said_2(take, rat_s_nest)) {
+ text_show(text_403_19);
+ goto handled;
+ }
+
+ if (player_said_2(take, skull)) {
+ text_show(text_403_21);
+ goto handled;
+ }
+
+ if (player_said_2(take, plank)) {
+ text_show(text_403_26);
+ goto handled;
+ }
+
+ goto done;
+
+handled:
+ player.command_ready = false;
+
+done:
+ ;
+}
+
+void room_403_daemon() {
+ if (kernel.trigger == ROOM_403_SHOW_TEXT) {
+ text_show(text_000_31);
+ }
+}
+
+void room_403_preload() {
+ room_init_code_pointer = room_403_init;
+ room_pre_parser_code_pointer = room_403_pre_parser;
+ room_parser_code_pointer = room_403_parser;
+ room_daemon_code_pointer = room_403_daemon;
+
+ section_4_walker();
+ section_4_interface();
+
+ if (global[catacombs_misc] & MAZE_HOLE) {
+ kernel_initial_variant = 1;
+ }
+
+ if (global[catacombs_misc] & MAZE_PLANK) {
+ kernel_initial_variant = 2;
+ }
+
+ vocab_make_active(words_red_frame);
+ vocab_make_active(words_yellow_frame);
+ vocab_make_active(words_blue_frame);
+ vocab_make_active(words_green_frame);
+}
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/rooms/room403.h b/engines/mads/madsv2/phantom/rooms/room403.h
new file mode 100644
index 00000000000..8518ae67ddc
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room403.h
@@ -0,0 +1,109 @@
+/* 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 MADS_PHANTOM_ROOM403_H
+#define MADS_PHANTOM_ROOM403_H
+
+#include "mads/madsv2/core/general.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+#define local ((Scratch *)(&game.scratch[0]))
+#define ss local->sprite
+#define seq local->sequence
+#define aa local->animation
+
+typedef struct { /* Room local variables */
+
+ int16 sprite[15]; /* Sprite series handles */
+ int16 sequence[15]; /* Sequence handles */
+ int16 animation[4]; /* Animation handles */
+ int16 frame_is_here; /* T if any frame is here */
+ int16 dyn_red;
+ int16 dyn_green;
+ int16 dyn_blue;
+ int16 dyn_yellow;
+ int16 frame_here_for_taking; /* T if a specific frame is here */
+
+
+} Scratch;
+
+
+/* ========================= Sprite Series =================== */
+
+#define fx_west 0 /* rm403c0 */
+#define fx_north 1 /* rm403c1 */
+
+#define fx_hole 2
+#define fx_web 3
+#define fx_brick 4
+#define fx_rat_nest 5
+#define fx_skull 6
+#define fx_plank 7
+
+#define fx_bend_down_9 8 /* rrd_9 */
+#define fx_red_frame 9 /* rm403f0 */
+#define fx_green_frame 10 /* rm403f1 */
+#define fx_blue_frame 11 /* rm403f2 */
+#define fx_yellow_frame 12 /* rm403f3 */
+
+#define fx_gate 13 /* rm403c9 */
+
+
+/* ========================= Triggers ======================== */
+
+#define ROOM_403_SHOW_TEXT 60
+
+/* ========================= Other Macros ==================== */
+
+#define NORTH_X 212
+#define NORTH_Y 86
+
+#define WALK_TO_NORTH_X 212
+#define WALK_TO_NORTH_Y 100
+
+#define WEST_X 3
+#define WEST_Y 128
+
+#define WALK_TO_WEST_X 40
+#define WALK_TO_WEST_Y 128
+
+#define EAST_X 330
+#define EAST_Y 126
+
+#define WALK_TO_EAST_X 305
+#define WALK_TO_EAST_Y 126
+
+#define SOUTH_X 175
+#define SOUTH_Y 147
+
+#define BRICK_X 178
+#define BRICK_Y 35
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif // MADS_PHANTOM_ROOM250_H
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index 54df3b064ec..9109705ae79 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -158,6 +158,7 @@ MODULE_OBJS += \
madsv2/phantom/rooms/room309.o \
madsv2/phantom/rooms/room310.o \
madsv2/phantom/rooms/room401.o \
+ madsv2/phantom/rooms/room403.o \
madsv2/phantom/phantom.o \
madsv2/phantom/conv.o \
madsv2/phantom/global.o \
Commit: 1308e97d07e9165bcc9d0f4e214853410aac61e1
https://github.com/scummvm/scummvm/commit/1308e97d07e9165bcc9d0f4e214853410aac61e1
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:49+10:00
Commit Message:
MADS: PHANTOM: Added room 404
Changed paths:
A engines/mads/madsv2/phantom/rooms/room404.cpp
A engines/mads/madsv2/phantom/rooms/room404.h
engines/mads/madsv2/phantom/mads/text.h
engines/mads/madsv2/phantom/mads/words.h
engines/mads/module.mk
diff --git a/engines/mads/madsv2/phantom/mads/text.h b/engines/mads/madsv2/phantom/mads/text.h
index 86829193894..0d02fd65f71 100644
--- a/engines/mads/madsv2/phantom/mads/text.h
+++ b/engines/mads/madsv2/phantom/mads/text.h
@@ -32,6 +32,7 @@ namespace Phantom {
enum {
text_000_29 = 29,
+ text_000_30 = 30,
text_000_31 = 31,
text_008_06 = 806,
@@ -774,7 +775,23 @@ enum {
text_403_25 = 40325,
text_403_26 = 40326,
text_453_30 = 45330,
- text_453_31 = 45331
+ text_453_31 = 45331,
+
+ /* Room 404 */
+ text_404_10 = 40410,
+ text_404_11 = 40411,
+ text_404_12 = 40412,
+ text_404_13 = 40413,
+ text_404_14 = 40414,
+ text_404_15 = 40415,
+ text_404_17 = 40417,
+ text_404_18 = 40418,
+ text_404_19 = 40419,
+ text_404_21 = 40421,
+ text_404_22 = 40422,
+ text_404_24 = 40424,
+ text_404_30 = 40430,
+ text_404_31 = 40431
};
} // namespace Phantom
diff --git a/engines/mads/madsv2/phantom/mads/words.h b/engines/mads/madsv2/phantom/mads/words.h
index 2ba6437e407..6a3be3b0815 100644
--- a/engines/mads/madsv2/phantom/mads/words.h
+++ b/engines/mads/madsv2/phantom/mads/words.h
@@ -288,6 +288,7 @@ enum {
words_puddle = 350,
words_web = 351,
words_plank = 352,
+ words_block = 353,
words_rat_s_nest = 354,
words_broken_pot = 355,
words_Edgar_Degas = 385,
diff --git a/engines/mads/madsv2/phantom/rooms/room404.cpp b/engines/mads/madsv2/phantom/rooms/room404.cpp
new file mode 100644
index 00000000000..a5d5b6ecb03
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room404.cpp
@@ -0,0 +1,553 @@
+/* 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 "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/camera.h"
+#include "mads/madsv2/core/inter.h"
+#include "mads/madsv2/core/matte.h"
+#include "mads/madsv2/core/object.h"
+#include "mads/madsv2/core/quote.h"
+#include "mads/madsv2/core/sound.h"
+#include "mads/madsv2/core/text.h"
+#include "mads/madsv2/phantom/mads/inventory.h"
+#include "mads/madsv2/phantom/mads/sounds.h"
+#include "mads/madsv2/phantom/rooms/section4.h"
+#include "mads/madsv2/phantom/rooms/room404.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+void room_404_init() {
+ global_catacombs_init();
+
+ kernel_flip_hotspot(words_rat_s_nest, false);
+ kernel_flip_hotspot(words_web, false);
+ kernel_flip_hotspot(words_broken_pot, false);
+ kernel_flip_hotspot(words_block, false);
+ kernel_flip_hotspot(words_puddle, false);
+
+ local->anim_0_running = false;
+
+ /* =================== Load sprites series =================== */
+
+ ss[fx_bend_down_9] = kernel_load_series("*RRD_9", false);
+ ss[fx_red_frame] = kernel_load_series(kernel_name('f', 0), false);
+ ss[fx_green_frame] = kernel_load_series(kernel_name('f', 1), false);
+ ss[fx_blue_frame] = kernel_load_series(kernel_name('f', 2), false);
+ ss[fx_yellow_frame] = kernel_load_series(kernel_name('f', 3), false);
+
+
+ if (global_catacombs_exit(NORTH) == -1) {
+ ss[fx_north] = kernel_load_series(kernel_name('c', 1), false);
+ kernel_draw_to_background(ss[fx_north], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ kernel_flip_hotspot(words_archway_to_north, false);
+ }
+
+ if (global_catacombs_exit(WEST) == -1) {
+ ss[fx_west] = kernel_load_series(kernel_name('c', 0), false);
+ kernel_draw_to_background(ss[fx_west], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ kernel_flip_hotspot(words_archway_to_west, false);
+ }
+
+ if (global_catacombs_exit(EAST) == -1) {
+ ss[fx_east] = kernel_load_series(kernel_name('c', 2), false);
+ kernel_draw_to_background(ss[fx_east], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ kernel_flip_hotspot(words_archway_to_east, false);
+ }
+
+ if (global_catacombs_exit(SOUTH) == -1) {
+ kernel_flip_hotspot(words_more_catacombs, false);
+ }
+
+
+ if (global[catacombs_misc] & MAZE_RAT_NEST) {
+ ss[fx_rat_nest] = kernel_load_series(kernel_name('c', 3), false);
+ kernel_draw_to_background(ss[fx_rat_nest], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ kernel_flip_hotspot(words_rat_s_nest, true);
+ }
+
+ if (global[catacombs_misc] & MAZE_WEB) {
+ ss[fx_web] = kernel_load_series(kernel_name('c', 4), false);
+ kernel_draw_to_background(ss[fx_web], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ kernel_flip_hotspot(words_web, true);
+ }
+
+ if (global[catacombs_misc] & MAZE_POT) {
+ ss[fx_pot] = kernel_load_series(kernel_name('c', 5), false);
+ kernel_draw_to_background(ss[fx_pot], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ kernel_flip_hotspot(words_broken_pot, true);
+ }
+
+ if (global[catacombs_misc] & MAZE_BLOCK) {
+ ss[fx_block] = kernel_load_series(kernel_name('c', 7), false);
+ kernel_draw_to_background(ss[fx_block], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ }
+
+ if (global[catacombs_misc] & MAZE_FALLEN_BLOCK) {
+ ss[fx_fallen_block] = kernel_load_series(kernel_name('c', 8), false);
+ kernel_draw_to_background(ss[fx_fallen_block], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ kernel_flip_hotspot(words_block, true);
+ }
+
+ if (global[catacombs_misc] & MAZE_PUDDLE) {
+ kernel_flip_hotspot(words_puddle, true);
+ aa[0] = kernel_run_animation(kernel_name('d', 1), 0);
+ local->anim_0_running = true;
+ }
+
+ if (previous_room != KERNEL_RESTORING_GAME) {
+
+ switch (global[catacombs_from]) {
+
+ case NORTH:
+ player.x = NORTH_X;
+ player.y = NORTH_Y;
+ player.facing = FACING_SOUTH;
+ player_walk(WALK_TO_NORTH_X, WALK_TO_NORTH_Y, FACING_SOUTH);
+ break;
+
+ case SOUTH:
+ player.x = SOUTH_X;
+ player.y = SOUTH_Y;
+ player.facing = FACING_NORTH;
+ break;
+
+ case EAST:
+ player.x = EAST_X;
+ player.y = EAST_Y;
+ player.facing = FACING_WEST;
+ player_walk(WALK_TO_EAST_X, WALK_TO_EAST_Y, FACING_WEST);
+ break;
+
+ case WEST:
+ player.x = WEST_X;
+ player.y = WEST_Y;
+ player.facing = FACING_SOUTH;
+ player_walk(WALK_TO_WEST_X, WALK_TO_WEST_Y, FACING_EAST);
+ break;
+ }
+ }
+
+ if (object[red_frame].location == global[catacombs_room] + 600) {
+ seq[fx_red_frame] = kernel_seq_stamp(ss[fx_red_frame], false, 1);
+ kernel_seq_depth(seq[fx_red_frame], 14);
+ local->dyn_red = kernel_add_dynamic(words_red_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5,
+ series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_red, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+
+ if (object[green_frame].location == global[catacombs_room] + 600) {
+ seq[fx_green_frame] = kernel_seq_stamp(ss[fx_green_frame], false, 1);
+ kernel_seq_depth(seq[fx_green_frame], 14);
+ local->dyn_green = kernel_add_dynamic(words_green_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5,
+ series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_green, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+
+ if (object[blue_frame].location == global[catacombs_room] + 600) {
+ seq[fx_blue_frame] = kernel_seq_stamp(ss[fx_blue_frame], false, 1);
+ kernel_seq_depth(seq[fx_blue_frame], 14);
+ local->dyn_blue = kernel_add_dynamic(words_blue_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5,
+ series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_blue, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+
+ if (object[yellow_frame].location == global[catacombs_room] + 600) {
+ seq[fx_yellow_frame] = kernel_seq_stamp(ss[fx_yellow_frame], false, 1);
+ kernel_seq_depth(seq[fx_yellow_frame], 14);
+ local->dyn_yellow = kernel_add_dynamic(words_yellow_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5,
+ series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_yellow, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+
+ if (global[priest_piston_puke]) {
+ kernel_timing_trigger(TWO_SECONDS, ROOM_404_SHOW_TEXT);
+ }
+
+ section_4_music();
+}
+
+void room_404_pre_parser() {
+ local->frame_is_here = false;
+ local->frame_here_for_taking = false;
+
+ if (object[red_frame].location == global[catacombs_room] + 600) {
+ local->frame_is_here = true;
+ if (player_said_2(take, red_frame)) {
+ local->frame_here_for_taking = true;
+ }
+ }
+
+ if (object[yellow_frame].location == global[catacombs_room] + 600) {
+ local->frame_is_here = true;
+ if (player_said_2(take, yellow_frame)) {
+ local->frame_here_for_taking = true;
+ }
+ }
+
+ if (object[blue_frame].location == global[catacombs_room] + 600) {
+ local->frame_is_here = true;
+ if (player_said_2(take, blue_frame)) {
+ local->frame_here_for_taking = true;
+ }
+ }
+
+ if (object[green_frame].location == global[catacombs_room] + 600) {
+ local->frame_is_here = true;
+ if (player_said_2(take, green_frame)) {
+ local->frame_here_for_taking = true;
+ }
+ }
+
+ if (player_said_1(put) && player_said_1(floor)) {
+ if (player_said_1(red_frame) ||
+ player_said_1(blue_frame) ||
+ player_said_1(yellow_frame) ||
+ player_said_1(green_frame)) {
+ if (local->frame_is_here) {
+ player.need_to_walk = false;
+
+ } else {
+ player_walk(series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+ }
+ }
+}
+
+void room_404_parser() {
+ if (player_said_1(put) && player_said_1(floor)) {
+ if (player_said_1(red_frame) ||
+ player_said_1(blue_frame) ||
+ player_said_1(yellow_frame) ||
+ player_said_1(green_frame)) {
+ if (local->frame_is_here) {
+ text_show(text_000_29);
+ goto handled;
+
+ } else {
+
+ switch (kernel.trigger) {
+ case (0):
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_bend_down_9] = kernel_seq_pingpong(ss[fx_bend_down_9], true,
+ 5, 0, 0, 2);
+ kernel_seq_range(seq[fx_bend_down_9], 1, 5);
+ kernel_seq_player(seq[fx_bend_down_9], true);
+ kernel_seq_trigger(seq[fx_bend_down_9],
+ KERNEL_TRIGGER_SPRITE, 5, 1);
+ kernel_seq_trigger(seq[fx_bend_down_9],
+ KERNEL_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ if (player_said_1(red_frame)) {
+ inter_move_object(red_frame, NOWHERE);
+ object[red_frame].location = global[catacombs_room] + 600;
+ seq[fx_red_frame] = kernel_seq_stamp(ss[fx_red_frame], false, 1);
+ kernel_seq_depth(seq[fx_red_frame], 14);
+ local->dyn_red = kernel_add_dynamic(words_red_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5, series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_red, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+
+ if (player_said_1(green_frame)) {
+ inter_move_object(green_frame, NOWHERE);
+ object[green_frame].location = global[catacombs_room] + 600;
+ seq[fx_green_frame] = kernel_seq_stamp(ss[fx_green_frame], false, 1);
+ kernel_seq_depth(seq[fx_green_frame], 14);
+ local->dyn_green = kernel_add_dynamic(words_green_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5, series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_green, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+
+ if (player_said_1(blue_frame)) {
+ inter_move_object(blue_frame, NOWHERE);
+ object[blue_frame].location = global[catacombs_room] + 600;
+ seq[fx_blue_frame] = kernel_seq_stamp(ss[fx_blue_frame], false, 1);
+ kernel_seq_depth(seq[fx_blue_frame], 14);
+ local->dyn_blue = kernel_add_dynamic(words_blue_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5, series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_blue, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+
+ if (player_said_1(yellow_frame)) {
+ inter_move_object(yellow_frame, NOWHERE);
+ object[yellow_frame].location = global[catacombs_room] + 600;
+ seq[fx_yellow_frame] = kernel_seq_stamp(ss[fx_yellow_frame], false, 1);
+ kernel_seq_depth(seq[fx_yellow_frame], 14);
+ local->dyn_yellow = kernel_add_dynamic(words_yellow_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5, series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_yellow, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+ break;
+
+ case 2:
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_SERIES, seq[fx_bend_down_9]);
+ player.walker_visible = true;
+ player.commands_allowed = true;
+ break;
+ }
+ goto handled;
+ }
+ }
+ }
+
+ if (player_said_1(take)) {
+ if (player_said_1(red_frame) || player_said_1(green_frame) ||
+ player_said_1(blue_frame) || player_said_1(yellow_frame)) {
+
+ if ((local->frame_here_for_taking || kernel.trigger)) {
+ switch (kernel.trigger) {
+ case (0):
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_bend_down_9] = kernel_seq_pingpong(ss[fx_bend_down_9], true,
+ 5, 0, 0, 2);
+ kernel_seq_range(seq[fx_bend_down_9], 1, 5);
+ kernel_seq_player(seq[fx_bend_down_9], true);
+ kernel_seq_trigger(seq[fx_bend_down_9],
+ KERNEL_TRIGGER_SPRITE, 5, 1);
+ kernel_seq_trigger(seq[fx_bend_down_9],
+ KERNEL_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ if (player_said_1(red_frame)) {
+ kernel_seq_delete(seq[fx_red_frame]);
+ kernel_delete_dynamic(local->dyn_red);
+ inter_give_to_player(red_frame);
+ }
+
+ if (player_said_1(green_frame)) {
+ kernel_seq_delete(seq[fx_green_frame]);
+ kernel_delete_dynamic(local->dyn_green);
+ inter_give_to_player(green_frame);
+ }
+
+ if (player_said_1(blue_frame)) {
+ kernel_seq_delete(seq[fx_blue_frame]);
+ kernel_delete_dynamic(local->dyn_blue);
+ inter_give_to_player(blue_frame);
+ }
+
+ if (player_said_1(yellow_frame)) {
+ kernel_seq_delete(seq[fx_yellow_frame]);
+ kernel_delete_dynamic(local->dyn_yellow);
+ inter_give_to_player(yellow_frame);
+ }
+
+ sound_play(N_TakeObjectSnd);
+ break;
+
+ case 2:
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_SERIES, seq[fx_bend_down_9]);
+ player.walker_visible = true;
+ player.commands_allowed = true;
+ break;
+ }
+ goto handled;
+ }
+ }
+ }
+
+ if (player_said_2(walk_through, archway_to_north)) {
+ global_catacombs_move(NORTH);
+ goto handled;
+ }
+
+ if (player_said_2(walk_through, archway_to_west)) {
+ global_catacombs_move(WEST);
+ goto handled;
+ }
+
+ if (player_said_2(exit_to, more_catacombs)) {
+ global_catacombs_move(SOUTH);
+ goto handled;
+ }
+
+ if (player_said_2(walk_through, archway_to_east)) {
+ global_catacombs_move(EAST);
+ goto handled;
+ }
+
+ if (player.look_around) {
+ text_show(text_404_10);
+ goto handled;
+ }
+
+ if (player_said_1(look) || player_said_1(look_at)) {
+
+ if (player_said_1(wall)) {
+ text_show(text_404_11);
+ goto handled;
+ }
+
+ if (player_said_1(floor)) {
+ text_show(text_404_12);
+ goto handled;
+ }
+
+ if (player_said_1(archway)) {
+ text_show(text_404_13);
+ goto handled;
+ }
+
+ if (player_said_1(exposed_brick)) {
+ text_show(text_404_14);
+ goto handled;
+ }
+
+ if (player_said_1(more_catacombs)) {
+ text_show(text_404_15);
+ goto handled;
+ }
+
+ if (player_said_1(puddle)) {
+ text_show(text_404_17);
+ goto handled;
+ }
+
+ if (player_said_1(rat_s_nest)) {
+ text_show(text_404_18);
+ goto handled;
+ }
+
+ if (player_said_1(broken_pot)) {
+ text_show(text_404_21);
+ goto handled;
+ }
+
+ if (player_said_1(web)) {
+ text_show(text_404_24);
+ goto handled;
+ }
+
+ if (player_said_1(red_frame)) {
+ if (!player_has(red_frame)) {
+ object_examine(red_frame, text_008_02, 0);
+ goto handled;
+ }
+ }
+
+ if (player_said_1(green_frame)) {
+ if (!player_has(green_frame)) {
+ object_examine(green_frame, text_008_19, 0);
+ goto handled;
+ }
+ }
+
+ if (player_said_1(blue_frame)) {
+ if (!player_has(blue_frame)) {
+ object_examine(blue_frame, text_008_17, 0);
+ goto handled;
+ }
+ }
+
+ if (player_said_1(yellow_frame)) {
+ if (!player_has(yellow_frame)) {
+ object_examine(yellow_frame, text_008_04, 0);
+ goto handled;
+ }
+ }
+
+ if (player_said_1(block)) {
+ text_show(text_404_30);
+ goto handled;
+ }
+ }
+
+ if (player_said_2(take, rat_s_nest)) {
+ text_show(text_404_19);
+ goto handled;
+ }
+
+ if (player_said_2(take, broken_pot)) {
+ text_show(text_404_22);
+ goto handled;
+ }
+
+ if (player_said_2(take, block)) {
+ text_show(text_404_31);
+ goto handled;
+ }
+
+ goto done;
+
+handled:
+ player.command_ready = false;
+
+done:
+ ;
+}
+
+void room_404_daemon() {
+ if (local->anim_0_running) {
+ if (kernel_anim[aa[0]].frame == 20) {
+ kernel_reset_animation(aa[0], 0);
+ }
+ }
+
+ if (kernel.trigger == ROOM_404_SHOW_TEXT) {
+ text_show(text_000_30);
+ global[priest_piston_puke] = false;
+ }
+}
+
+void room_404_preload() {
+ room_init_code_pointer = room_404_init;
+ room_pre_parser_code_pointer = room_404_pre_parser;
+ room_parser_code_pointer = room_404_parser;
+ room_daemon_code_pointer = room_404_daemon;
+
+ section_4_walker();
+ section_4_interface();
+
+ if (global[catacombs_misc] & MAZE_BLOCK) {
+ kernel_initial_variant = 1;
+ }
+
+ vocab_make_active(words_red_frame);
+ vocab_make_active(words_yellow_frame);
+ vocab_make_active(words_blue_frame);
+ vocab_make_active(words_green_frame);
+}
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/rooms/room404.h b/engines/mads/madsv2/phantom/rooms/room404.h
new file mode 100644
index 00000000000..a6cb5abb0c5
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room404.h
@@ -0,0 +1,106 @@
+/* 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 MADS_PHANTOM_ROOM404_H
+#define MADS_PHANTOM_ROOM404_H
+
+#include "mads/madsv2/core/general.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+#define local ((Scratch *)(&game.scratch[0]))
+#define ss local->sprite
+#define seq local->sequence
+#define aa local->animation
+
+typedef struct { /* Room local variables */
+
+ int16 sprite[15]; /* Sprite series handles */
+ int16 sequence[15]; /* Sequence handles */
+ int16 animation[4]; /* Animation handles */
+ int16 frame_is_here; /* T if any frame is here */
+ int16 dyn_red;
+ int16 dyn_green;
+ int16 dyn_blue;
+ int16 dyn_yellow;
+ int16 frame_here_for_taking; /* T if a specific frame is here */
+ int16 anim_0_running;
+
+
+} Scratch;
+
+
+/* ========================= Sprite Series =================== */
+
+#define fx_west 0 /* rm404c0 */
+#define fx_north 1 /* rm404c1 */
+#define fx_east 2 /* rm404c2 */
+
+#define fx_rat_nest 3
+#define fx_web 4
+#define fx_pot 5
+#define fx_puddle 6
+#define fx_block 7
+#define fx_fallen_block 8
+
+#define fx_bend_down_9 9 /* rrd_9 */
+#define fx_red_frame 10 /* rm401f0 */
+#define fx_green_frame 11 /* rm401f1 */
+#define fx_blue_frame 12 /* rm401f2 */
+#define fx_yellow_frame 13 /* rm401f3 */
+
+
+/* ========================= Triggers ======================== */
+
+#define ROOM_404_SHOW_TEXT 60
+
+/* ========================= Other Macros ==================== */
+
+#define NORTH_X 156
+#define NORTH_Y 98
+
+#define WALK_TO_NORTH_X 156
+#define WALK_TO_NORTH_Y 117
+
+#define WEST_X 17
+#define WEST_Y 131
+
+#define WALK_TO_WEST_X 60
+#define WALK_TO_WEST_Y 131
+
+#define EAST_X 319
+#define EAST_Y 135
+
+#define WALK_TO_EAST_X 279
+#define WALK_TO_EAST_Y 135
+
+#define SOUTH_X 175
+#define SOUTH_Y 147
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif // MADS_PHANTOM_ROOM250_H
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index 9109705ae79..2d91161aa72 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -159,6 +159,7 @@ MODULE_OBJS += \
madsv2/phantom/rooms/room310.o \
madsv2/phantom/rooms/room401.o \
madsv2/phantom/rooms/room403.o \
+ madsv2/phantom/rooms/room404.o \
madsv2/phantom/phantom.o \
madsv2/phantom/conv.o \
madsv2/phantom/global.o \
Commit: ff5904ecf8e06b98972c40e52806c0331a3618a6
https://github.com/scummvm/scummvm/commit/ff5904ecf8e06b98972c40e52806c0331a3618a6
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:49+10:00
Commit Message:
MADS: PHANTOM: Added room 406
Changed paths:
A engines/mads/madsv2/phantom/rooms/room406.cpp
A engines/mads/madsv2/phantom/rooms/room406.h
engines/mads/madsv2/phantom/mads/text.h
engines/mads/madsv2/phantom/mads/words.h
engines/mads/module.mk
diff --git a/engines/mads/madsv2/phantom/mads/text.h b/engines/mads/madsv2/phantom/mads/text.h
index 0d02fd65f71..c3a9f7df824 100644
--- a/engines/mads/madsv2/phantom/mads/text.h
+++ b/engines/mads/madsv2/phantom/mads/text.h
@@ -791,7 +791,18 @@ enum {
text_404_22 = 40422,
text_404_24 = 40424,
text_404_30 = 40430,
- text_404_31 = 40431
+ text_404_31 = 40431,
+
+ /* Room 406 */
+ text_406_10 = 40610,
+ text_406_11 = 40611,
+ text_406_12 = 40612,
+ text_406_13 = 40613,
+ text_406_14 = 40614,
+ text_406_15 = 40615,
+ text_406_16 = 40616,
+ text_406_17 = 40617,
+ text_406_18 = 40618
};
} // namespace Phantom
diff --git a/engines/mads/madsv2/phantom/mads/words.h b/engines/mads/madsv2/phantom/mads/words.h
index 6a3be3b0815..652d6c33aaa 100644
--- a/engines/mads/madsv2/phantom/mads/words.h
+++ b/engines/mads/madsv2/phantom/mads/words.h
@@ -272,6 +272,7 @@ enum {
words_Madame_Giry = 323,
words_more_catacombs = 325,
words_blocked_archway = 326,
+ words_grate = 327,
words_catacombs = 328,
words_ticket_seller = 329,
words_usher = 330,
diff --git a/engines/mads/madsv2/phantom/rooms/room406.cpp b/engines/mads/madsv2/phantom/rooms/room406.cpp
new file mode 100644
index 00000000000..09bfb5ff780
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room406.cpp
@@ -0,0 +1,461 @@
+/* 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 "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/camera.h"
+#include "mads/madsv2/core/inter.h"
+#include "mads/madsv2/core/matte.h"
+#include "mads/madsv2/core/object.h"
+#include "mads/madsv2/core/quote.h"
+#include "mads/madsv2/core/sound.h"
+#include "mads/madsv2/core/text.h"
+#include "mads/madsv2/phantom/mads/inventory.h"
+#include "mads/madsv2/phantom/mads/sounds.h"
+#include "mads/madsv2/phantom/rooms/section4.h"
+#include "mads/madsv2/phantom/rooms/room404.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+void room_406_init() {
+ global_catacombs_init();
+
+ /* =================== Load sprites series =================== */
+
+ ss[fx_bend_down_9] = kernel_load_series("*RRD_9", false);
+ ss[fx_red_frame] = kernel_load_series(kernel_name('f', 0), false);
+ ss[fx_green_frame] = kernel_load_series(kernel_name('f', 1), false);
+ ss[fx_blue_frame] = kernel_load_series(kernel_name('f', 2), false);
+ ss[fx_yellow_frame] = kernel_load_series(kernel_name('f', 3), false);
+
+ if (previous_room != KERNEL_RESTORING_GAME) {
+
+ switch (global[catacombs_from]) {
+
+ case EAST:
+ player.x = EAST_X;
+ player.y = EAST_Y;
+ player.facing = FACING_WEST;
+ player_walk(WALK_TO_EAST_X, WALK_TO_EAST_Y, FACING_WEST);
+ break;
+
+ case WEST:
+ player.x = WEST_X;
+ player.y = WEST_Y;
+ player.facing = FACING_SOUTH;
+ player_walk(WALK_TO_WEST_X, WALK_TO_WEST_Y, FACING_EAST);
+ break;
+ }
+ }
+
+ if (object[red_frame].location == global[catacombs_room] + 600) {
+ seq[fx_red_frame] = kernel_seq_stamp(ss[fx_red_frame], false, 1);
+ kernel_seq_depth(seq[fx_red_frame], 14);
+ local->dyn_red = kernel_add_dynamic(words_red_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5,
+ series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_red, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+
+ if (object[green_frame].location == global[catacombs_room] + 600) {
+ seq[fx_green_frame] = kernel_seq_stamp(ss[fx_green_frame], false, 1);
+ kernel_seq_depth(seq[fx_green_frame], 14);
+ local->dyn_green = kernel_add_dynamic(words_green_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5,
+ series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_green, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+
+ if (object[blue_frame].location == global[catacombs_room] + 600) {
+ seq[fx_blue_frame] = kernel_seq_stamp(ss[fx_blue_frame], false, 1);
+ kernel_seq_depth(seq[fx_blue_frame], 14);
+ local->dyn_blue = kernel_add_dynamic(words_blue_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5,
+ series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_blue, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+
+ if (object[yellow_frame].location == global[catacombs_room] + 600) {
+ seq[fx_yellow_frame] = kernel_seq_stamp(ss[fx_yellow_frame], false, 1);
+ kernel_seq_depth(seq[fx_yellow_frame], 14);
+ local->dyn_yellow = kernel_add_dynamic(words_yellow_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5,
+ series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_yellow, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+ section_4_music();
+}
+
+void room_406_pre_parser() {
+ local->frame_is_here = false;
+ local->frame_here_for_taking = false;
+
+ if (object[red_frame].location == global[catacombs_room] + 600) {
+ local->frame_is_here = true;
+ if (player_said_2(take, red_frame)) {
+ local->frame_here_for_taking = true;
+ }
+ }
+
+ if (object[yellow_frame].location == global[catacombs_room] + 600) {
+ local->frame_is_here = true;
+ if (player_said_2(take, yellow_frame)) {
+ local->frame_here_for_taking = true;
+ }
+ }
+
+ if (object[blue_frame].location == global[catacombs_room] + 600) {
+ local->frame_is_here = true;
+ if (player_said_2(take, blue_frame)) {
+ local->frame_here_for_taking = true;
+ }
+ }
+
+ if (object[green_frame].location == global[catacombs_room] + 600) {
+ local->frame_is_here = true;
+ if (player_said_2(take, green_frame)) {
+ local->frame_here_for_taking = true;
+ }
+ }
+
+ if (player_said_1(put) && player_said_1(floor)) {
+ if (player_said_1(red_frame) ||
+ player_said_1(blue_frame) ||
+ player_said_1(yellow_frame) ||
+ player_said_1(green_frame)) {
+ if (local->frame_is_here) {
+ player.need_to_walk = false;
+
+ } else {
+ player_walk(series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+ }
+ }
+}
+
+void room_406_parser() {
+ if (player_said_1(put) && player_said_1(floor)) {
+ if (player_said_1(red_frame) ||
+ player_said_1(blue_frame) ||
+ player_said_1(yellow_frame) ||
+ player_said_1(green_frame)) {
+ if (local->frame_is_here) {
+ text_show(text_000_29);
+ goto handled;
+
+ } else {
+
+ switch (kernel.trigger) {
+ case (0):
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_bend_down_9] = kernel_seq_pingpong(ss[fx_bend_down_9], true,
+ 5, 0, 0, 2);
+ kernel_seq_range(seq[fx_bend_down_9], 1, 5);
+ kernel_seq_player(seq[fx_bend_down_9], true);
+ kernel_seq_trigger(seq[fx_bend_down_9],
+ KERNEL_TRIGGER_SPRITE, 5, 1);
+ kernel_seq_trigger(seq[fx_bend_down_9],
+ KERNEL_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ if (player_said_1(red_frame)) {
+ inter_move_object(red_frame, NOWHERE);
+ object[red_frame].location = global[catacombs_room] + 600;
+ seq[fx_red_frame] = kernel_seq_stamp(ss[fx_red_frame], false, 1);
+ kernel_seq_depth(seq[fx_red_frame], 14);
+ local->dyn_red = kernel_add_dynamic(words_red_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5, series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_red, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+
+ if (player_said_1(green_frame)) {
+ inter_move_object(green_frame, NOWHERE);
+ object[green_frame].location = global[catacombs_room] + 600;
+ seq[fx_green_frame] = kernel_seq_stamp(ss[fx_green_frame], false, 1);
+ kernel_seq_depth(seq[fx_green_frame], 14);
+ local->dyn_green = kernel_add_dynamic(words_green_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5, series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_green, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+
+ if (player_said_1(blue_frame)) {
+ inter_move_object(blue_frame, NOWHERE);
+ object[blue_frame].location = global[catacombs_room] + 600;
+ seq[fx_blue_frame] = kernel_seq_stamp(ss[fx_blue_frame], false, 1);
+ kernel_seq_depth(seq[fx_blue_frame], 14);
+ local->dyn_blue = kernel_add_dynamic(words_blue_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5, series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_blue, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+
+ if (player_said_1(yellow_frame)) {
+ inter_move_object(yellow_frame, NOWHERE);
+ object[yellow_frame].location = global[catacombs_room] + 600;
+ seq[fx_yellow_frame] = kernel_seq_stamp(ss[fx_yellow_frame], false, 1);
+ kernel_seq_depth(seq[fx_yellow_frame], 14);
+ local->dyn_yellow = kernel_add_dynamic(words_yellow_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5, series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_yellow, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+ break;
+
+ case 2:
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_SERIES, seq[fx_bend_down_9]);
+ player.walker_visible = true;
+ player.commands_allowed = true;
+ break;
+ }
+ goto handled;
+ }
+ }
+ }
+
+
+ if (player_said_1(take)) {
+ if (player_said_1(red_frame) || player_said_1(green_frame) ||
+ player_said_1(blue_frame) || player_said_1(yellow_frame)) {
+
+ if ((local->frame_here_for_taking || kernel.trigger)) {
+ switch (kernel.trigger) {
+ case (0):
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_bend_down_9] = kernel_seq_pingpong(ss[fx_bend_down_9], true,
+ 5, 0, 0, 2);
+ kernel_seq_range(seq[fx_bend_down_9], 1, 5);
+ kernel_seq_player(seq[fx_bend_down_9], true);
+ kernel_seq_trigger(seq[fx_bend_down_9],
+ KERNEL_TRIGGER_SPRITE, 5, 1);
+ kernel_seq_trigger(seq[fx_bend_down_9],
+ KERNEL_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ if (player_said_1(red_frame)) {
+ kernel_seq_delete(seq[fx_red_frame]);
+ kernel_delete_dynamic(local->dyn_red);
+ inter_give_to_player(red_frame);
+ }
+
+ if (player_said_1(green_frame)) {
+ kernel_seq_delete(seq[fx_green_frame]);
+ kernel_delete_dynamic(local->dyn_green);
+ inter_give_to_player(green_frame);
+ }
+
+ if (player_said_1(blue_frame)) {
+ kernel_seq_delete(seq[fx_blue_frame]);
+ kernel_delete_dynamic(local->dyn_blue);
+ inter_give_to_player(blue_frame);
+ }
+
+ if (player_said_1(yellow_frame)) {
+ kernel_seq_delete(seq[fx_yellow_frame]);
+ kernel_delete_dynamic(local->dyn_yellow);
+ inter_give_to_player(yellow_frame);
+ }
+
+ sound_play(N_TakeObjectSnd);
+ break;
+
+ case 2:
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_SERIES, seq[fx_bend_down_9]);
+ player.walker_visible = true;
+ player.commands_allowed = true;
+ break;
+ }
+ goto handled;
+ }
+ }
+ }
+
+ if (player_said_2(walk_through, archway_to_west)) {
+ global_catacombs_move(WEST);
+ goto handled;
+ }
+
+ if (player_said_2(walk_through, archway_to_east)) {
+ global_catacombs_move(EAST);
+ goto handled;
+ }
+
+ if (player.look_around) {
+ text_show(text_406_10);
+ goto handled;
+ }
+
+ if (player_said_1(look) || player_said_1(look_at)) {
+
+ if (player_said_1(wall)) {
+ text_show(text_406_11);
+ goto handled;
+ }
+
+ if (player_said_1(floor)) {
+ text_show(text_406_12);
+ goto handled;
+ }
+
+ if (player_said_1(archway)) {
+ text_show(text_406_13);
+ goto handled;
+ }
+
+ if (player_said_1(exposed_brick)) {
+ text_show(text_406_14);
+ goto handled;
+ }
+
+ if (player_said_1(more_catacombs)) {
+ text_show(text_406_15);
+ goto handled;
+ }
+
+ if (player_said_1(blocked_archway)) {
+ text_show(text_406_16);
+ goto handled;
+ }
+
+ if (player_said_1(red_frame)) {
+ if (!player_has(red_frame)) {
+ object_examine(red_frame, text_008_02, 0);
+ goto handled;
+ }
+ }
+
+ if (player_said_1(green_frame)) {
+ if (!player_has(green_frame)) {
+ object_examine(green_frame, text_008_19, 0);
+ goto handled;
+ }
+ }
+
+ if (player_said_1(blue_frame)) {
+ if (!player_has(blue_frame)) {
+ object_examine(blue_frame, text_008_17, 0);
+ goto handled;
+ }
+ }
+
+ if (player_said_1(yellow_frame)) {
+ if (!player_has(yellow_frame)) {
+ object_examine(yellow_frame, text_008_04, 0);
+ goto handled;
+ }
+ }
+
+ if (player_said_1(grate)) {
+ text_show(text_406_17);
+ goto handled;
+ }
+ }
+
+ if ((player_said_2(open, grate)) ||
+ (player_said_2(push, grate)) ||
+ (player_said_2(pull, grate))) {
+ switch (kernel.trigger) {
+ case (0):
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_bend_down_9] = kernel_seq_forward(ss[fx_bend_down_9], true,
+ 5, 0, 0, 1);
+ kernel_seq_range(seq[fx_bend_down_9], KERNEL_FIRST, KERNEL_LAST);
+ kernel_seq_player(seq[fx_bend_down_9], true);
+ kernel_seq_trigger(seq[fx_bend_down_9],
+ KERNEL_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 2:
+ seq[fx_bend_down_9] = kernel_seq_stamp
+ (ss[fx_bend_down_9], true, KERNEL_LAST);
+ kernel_seq_player(seq[fx_bend_down_9], true);
+ /* kernel_seq_depth (seq[fx_bend_down_9], 1); */
+ kernel_timing_trigger(HALF_SECOND, 3);
+ break;
+
+ case 3:
+ /* temp = seq[fx_bend_down_9]; */
+ kernel_seq_delete(seq[fx_bend_down_9]);
+ seq[fx_bend_down_9] = kernel_seq_backward(ss[fx_bend_down_9], true,
+ 5, 0, 0, 1);
+ /* kernel_synch (KERNEL_SERIES, seq[fx_bend_down_9], KERNEL_SERIES, temp); */
+ kernel_seq_range(seq[fx_bend_down_9], KERNEL_FIRST, KERNEL_LAST);
+ kernel_seq_player(seq[fx_bend_down_9], false);
+ kernel_seq_trigger(seq[fx_bend_down_9],
+ KERNEL_TRIGGER_EXPIRE, 0, 4);
+ break;
+
+ case 4:
+ player.walker_visible = true;
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_SERIES, seq[fx_bend_down_9]);
+ kernel_timing_trigger(TENTH_SECOND, 5);
+ break;
+
+ case 5:
+ player.commands_allowed = true;
+ text_show(text_406_18);
+ break;
+ }
+ goto handled;
+ }
+
+ goto done;
+
+handled:
+ player.command_ready = false;
+
+done:
+ ;
+}
+
+void room_406_preload() {
+ room_init_code_pointer = room_406_init;
+ room_pre_parser_code_pointer = room_406_pre_parser;
+ room_parser_code_pointer = room_406_parser;
+ room_daemon_code_pointer = NULL;
+
+ section_4_walker();
+ section_4_interface();
+
+ vocab_make_active(words_red_frame);
+ vocab_make_active(words_yellow_frame);
+ vocab_make_active(words_blue_frame);
+ vocab_make_active(words_green_frame);
+}
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/rooms/room406.h b/engines/mads/madsv2/phantom/rooms/room406.h
new file mode 100644
index 00000000000..6c2851c4d30
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room406.h
@@ -0,0 +1,81 @@
+/* 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 MADS_PHANTOM_ROOM406_H
+#define MADS_PHANTOM_ROOM406_H
+
+#include "mads/madsv2/core/general.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+#define local ((Scratch *)(&game.scratch[0]))
+#define ss local->sprite
+#define seq local->sequence
+#define aa local->animation
+
+typedef struct { /* Room local variables */
+
+ int16 sprite[15]; /* Sprite series handles */
+ int16 sequence[15]; /* Sequence handles */
+ int16 animation[4]; /* Animation handles */
+ int16 frame_is_here; /* T if any frame is here */
+ int16 dyn_red;
+ int16 dyn_green;
+ int16 dyn_blue;
+ int16 dyn_yellow;
+ int16 frame_here_for_taking; /* T if a specific frame is here */
+
+
+} Scratch;
+
+/* ========================= Sprite Series =================== */
+
+#define fx_bend_down_9 0 /* rrd_9 */
+#define fx_red_frame 1 /* rm401f0 */
+#define fx_green_frame 2 /* rm401f1 */
+#define fx_blue_frame 3 /* rm401f2 */
+#define fx_yellow_frame 4 /* rm401f3 */
+
+/* ========================= Triggers ======================== */
+
+/* ========================= Other Macros ==================== */
+
+#define WEST_X 20
+#define WEST_Y 122
+
+#define WALK_TO_WEST_X 66
+#define WALK_TO_WEST_Y 122
+
+#define EAST_X 310
+#define EAST_Y 118
+
+#define WALK_TO_EAST_X 271
+#define WALK_TO_EAST_Y 118
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif // MADS_PHANTOM_ROOM250_H
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index 2d91161aa72..df1174e3d19 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -160,6 +160,7 @@ MODULE_OBJS += \
madsv2/phantom/rooms/room401.o \
madsv2/phantom/rooms/room403.o \
madsv2/phantom/rooms/room404.o \
+ madsv2/phantom/rooms/room406.o \
madsv2/phantom/phantom.o \
madsv2/phantom/conv.o \
madsv2/phantom/global.o \
Commit: 747aca50e872660fe21bef62b653b64256577c8f
https://github.com/scummvm/scummvm/commit/747aca50e872660fe21bef62b653b64256577c8f
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:50+10:00
Commit Message:
MADS: PHANTOM: Added room 407
Changed paths:
A engines/mads/madsv2/phantom/rooms/room407.cpp
A engines/mads/madsv2/phantom/rooms/room407.h
engines/mads/madsv2/phantom/mads/text.h
engines/mads/madsv2/phantom/rooms/room406.cpp
engines/mads/module.mk
diff --git a/engines/mads/madsv2/phantom/mads/text.h b/engines/mads/madsv2/phantom/mads/text.h
index c3a9f7df824..f51cc781b08 100644
--- a/engines/mads/madsv2/phantom/mads/text.h
+++ b/engines/mads/madsv2/phantom/mads/text.h
@@ -802,7 +802,18 @@ enum {
text_406_15 = 40615,
text_406_16 = 40616,
text_406_17 = 40617,
- text_406_18 = 40618
+ text_406_18 = 40618,
+
+ /* Room 407 */
+ text_407_10 = 40710,
+ text_407_11 = 40711,
+ text_407_12 = 40712,
+ text_407_13 = 40713,
+ text_407_14 = 40714,
+ text_407_15 = 40715,
+ text_407_16 = 40716,
+ text_407_17 = 40717,
+ text_407_18 = 40718
};
} // namespace Phantom
diff --git a/engines/mads/madsv2/phantom/rooms/room406.cpp b/engines/mads/madsv2/phantom/rooms/room406.cpp
index 09bfb5ff780..ddae636d3cc 100644
--- a/engines/mads/madsv2/phantom/rooms/room406.cpp
+++ b/engines/mads/madsv2/phantom/rooms/room406.cpp
@@ -31,7 +31,7 @@
#include "mads/madsv2/phantom/mads/inventory.h"
#include "mads/madsv2/phantom/mads/sounds.h"
#include "mads/madsv2/phantom/rooms/section4.h"
-#include "mads/madsv2/phantom/rooms/room404.h"
+#include "mads/madsv2/phantom/rooms/room406.h"
namespace MADS {
namespace MADSV2 {
diff --git a/engines/mads/madsv2/phantom/rooms/room407.cpp b/engines/mads/madsv2/phantom/rooms/room407.cpp
new file mode 100644
index 00000000000..34aba3c4cb1
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room407.cpp
@@ -0,0 +1,543 @@
+/* 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 "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/camera.h"
+#include "mads/madsv2/core/inter.h"
+#include "mads/madsv2/core/matte.h"
+#include "mads/madsv2/core/object.h"
+#include "mads/madsv2/core/quote.h"
+#include "mads/madsv2/core/sound.h"
+#include "mads/madsv2/core/text.h"
+#include "mads/madsv2/phantom/mads/inventory.h"
+#include "mads/madsv2/phantom/mads/sounds.h"
+#include "mads/madsv2/phantom/rooms/section4.h"
+#include "mads/madsv2/phantom/rooms/room407.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+void room_407_init() {
+ global_catacombs_init();
+
+ /* =================== Load sprites series =================== */
+
+ ss[fx_bend_down_9] = kernel_load_series("*RRD_9", false);
+ ss[fx_red_frame] = kernel_load_series(kernel_name('f', 0), false);
+ ss[fx_green_frame] = kernel_load_series(kernel_name('f', 1), false);
+ ss[fx_blue_frame] = kernel_load_series(kernel_name('f', 2), false);
+ ss[fx_yellow_frame] = kernel_load_series(kernel_name('f', 3), false);
+
+ if (global_catacombs_exit(WEST) == -1) {
+ kernel_flip_hotspot_loc(words_more_catacombs, false, CAT_LEFT_1_X, CAT_LEFT_1_Y);
+ kernel_flip_hotspot_loc(words_more_catacombs, false, CAT_LEFT_2_X, CAT_LEFT_2_Y);
+ kernel_flip_hotspot_loc(words_more_catacombs, false, CAT_LEFT_3_X, CAT_LEFT_3_Y);
+ kernel_flip_hotspot_loc(words_more_catacombs, false, CAT_LEFT_4_X, CAT_LEFT_4_Y);
+ }
+
+ if (global_catacombs_exit(EAST) == -1) {
+ kernel_flip_hotspot_loc(words_more_catacombs, false, CAT_RIGHT_1_X, CAT_RIGHT_1_Y);
+ kernel_flip_hotspot_loc(words_more_catacombs, false, CAT_RIGHT_2_X, CAT_RIGHT_2_Y);
+ kernel_flip_hotspot_loc(words_more_catacombs, false, CAT_RIGHT_3_X, CAT_RIGHT_3_Y);
+ kernel_flip_hotspot_loc(words_more_catacombs, false, CAT_RIGHT_4_X, CAT_RIGHT_4_Y);
+ }
+
+ if (previous_room != KERNEL_RESTORING_GAME) {
+
+ switch (global[catacombs_from]) {
+
+ case NORTH:
+ player.x = NORTH_X;
+ player.y = NORTH_Y;
+ player.facing = FACING_WEST;
+ player_walk(WALK_TO_NORTH_X, WALK_TO_NORTH_Y, FACING_WEST);
+ break;
+
+ case SOUTH:
+ player.x = SOUTH_X;
+ player.y = SOUTH_Y;
+ player.facing = FACING_EAST;
+ player_walk(WALK_TO_SOUTH_X, WALK_TO_SOUTH_Y, FACING_EAST);
+ break;
+
+ case EAST:
+ player_first_walk(EAST_X, EAST_Y, FACING_WEST, WALK_TO_EAST_X, WALK_TO_EAST_Y, FACING_WEST, true);
+ break;
+
+ case WEST:
+ player_first_walk(WEST_X, WEST_Y, FACING_WEST, WALK_TO_WEST_X, WALK_TO_WEST_Y, FACING_WEST, true);
+ break;
+ }
+ }
+
+ if (object[red_frame].location == global[catacombs_room] + 600) {
+ seq[fx_red_frame] = kernel_seq_stamp(ss[fx_red_frame], false, 1);
+ kernel_seq_depth(seq[fx_red_frame], 14);
+ local->dyn_red = kernel_add_dynamic(words_red_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5,
+ series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_red, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+
+ if (object[green_frame].location == global[catacombs_room] + 600) {
+ seq[fx_green_frame] = kernel_seq_stamp(ss[fx_green_frame], false, 1);
+ kernel_seq_depth(seq[fx_green_frame], 14);
+ local->dyn_green = kernel_add_dynamic(words_green_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5,
+ series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_green, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+
+ if (object[blue_frame].location == global[catacombs_room] + 600) {
+ seq[fx_blue_frame] = kernel_seq_stamp(ss[fx_blue_frame], false, 1);
+ kernel_seq_depth(seq[fx_blue_frame], 14);
+ local->dyn_blue = kernel_add_dynamic(words_blue_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5,
+ series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_blue, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+
+ if (object[yellow_frame].location == global[catacombs_room] + 600) {
+ seq[fx_yellow_frame] = kernel_seq_stamp(ss[fx_yellow_frame], false, 1);
+ kernel_seq_depth(seq[fx_yellow_frame], 14);
+ local->dyn_yellow = kernel_add_dynamic(words_yellow_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5,
+ series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_yellow, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+ section_4_music();
+}
+
+void room_407_pre_parser() {
+ if (player_said_2(exit_to, more_catacombs)) {
+ if (player.y > 30) {
+ if (inter_point_x < 100) {
+ global_catacombs_move(WEST);
+ } else {
+ global_catacombs_move(EAST);
+ }
+ } else {
+ player.need_to_walk = false;
+ }
+ }
+
+ if (player_said_1(walk_through)) {
+ if (player.y > 30) {
+ player.need_to_walk = false;
+ }
+ }
+
+ local->frame_is_here = false;
+ local->frame_here_for_taking = false;
+
+ if (object[red_frame].location == global[catacombs_room] + 600) {
+ local->frame_is_here = true;
+ if (player_said_2(take, red_frame)) {
+ local->frame_here_for_taking = true;
+ }
+ }
+
+ if (object[yellow_frame].location == global[catacombs_room] + 600) {
+ local->frame_is_here = true;
+ if (player_said_2(take, yellow_frame)) {
+ local->frame_here_for_taking = true;
+ }
+ }
+
+ if (object[blue_frame].location == global[catacombs_room] + 600) {
+ local->frame_is_here = true;
+ if (player_said_2(take, blue_frame)) {
+ local->frame_here_for_taking = true;
+ }
+ }
+
+ if (object[green_frame].location == global[catacombs_room] + 600) {
+ local->frame_is_here = true;
+ if (player_said_2(take, green_frame)) {
+ local->frame_here_for_taking = true;
+ }
+ }
+
+ if (player_said_1(put) && player_said_1(floor)) {
+ if (player_said_1(red_frame) ||
+ player_said_1(blue_frame) ||
+ player_said_1(yellow_frame) ||
+ player_said_1(green_frame)) {
+ if ((local->frame_is_here) || (player.y < 30) || (inter_point_y < 30)) {
+ player.need_to_walk = false;
+
+ } else {
+ player_walk(series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+ }
+ }
+
+ if (player_said_1(take)) {
+ if (player_said_1(red_frame) || player_said_1(green_frame) ||
+ player_said_1(blue_frame) || player_said_1(yellow_frame)) {
+
+ if (local->frame_here_for_taking) {
+ if (player.y < 30) {
+ player.need_to_walk = false;
+ }
+ }
+ }
+ }
+
+ if (player_said_2(walk_across, floor)) {
+ if ((player.y < 30) && (inter_point_y > 29)) {
+ player.need_to_walk = false;
+ }
+ }
+
+ if (player_said_2(walk_to, lake) && (player.y < 30)) {
+ player_walk(LAKE_X, LAKE_Y, FACING_SOUTH);
+ }
+
+ if (player_said_1(walk_to) && (inter_point_x < 130) && (player.y < 30)) {
+ player.need_to_walk = false;
+ }
+
+ if (player_said_1(walk_to) && (inter_point_x > 203) && (player.y < 30)) {
+ player.need_to_walk = false;
+ }
+
+ if (player_said_2(walk_to, wall) && (player.y > 30)) {
+ if ((inter_point_x > 160) && (inter_point_x < 190)) {
+ player.need_to_walk = false;
+ }
+ }
+}
+
+void room_407_parser() {
+ if (player_said_2(walk_to, wall) && (player.y > 30)) {
+ if ((inter_point_x > 160) && (inter_point_x < 190)) {
+ text_show(text_407_18);
+ goto handled;
+ }
+ }
+
+ if (player_said_1(walk_to) && (inter_point_x < 130) && (player.y < 30)) {
+ text_show(text_407_18);
+ goto handled;
+ }
+
+ if (player_said_1(walk_to) && (inter_point_x > 203) && (player.y < 30)) {
+ text_show(text_407_18);
+ goto handled;
+ }
+
+ if (player_said_2(walk_across, floor)) {
+ if ((player.y < 30) && (inter_point_y > 29)) {
+ text_show(text_407_18);
+ goto handled;
+
+ } else if ((player.y > 29) && (inter_point_y < 30)) {
+ text_show(text_407_18);
+ goto handled;
+ /* you can't cross the lake */
+ }
+ }
+
+ if (player_said_1(put) && player_said_1(floor)) {
+ if (player_said_1(red_frame) ||
+ player_said_1(blue_frame) ||
+ player_said_1(yellow_frame) ||
+ player_said_1(green_frame)) {
+
+ if ((player.y < 30) && (inter_point_y < 30)) {
+ text_show(text_407_17);
+ goto handled;
+ /* you are on far side and want to put frame down on far side */
+
+ } else if ((player.y < 30) && (inter_point_y > 29)) {
+ text_show(text_407_18);
+ goto handled;
+ /* you are on far side and want to put frame down on near side */
+
+ } else if (local->frame_is_here) {
+ text_show(text_000_29);
+ /* a frame is already here */
+ goto handled;
+
+ } else {
+
+ switch (kernel.trigger) {
+ case (0):
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_bend_down_9] = kernel_seq_pingpong(ss[fx_bend_down_9], true,
+ 5, 0, 0, 2);
+ kernel_seq_range(seq[fx_bend_down_9], 1, 5);
+ kernel_seq_player(seq[fx_bend_down_9], true);
+ kernel_seq_trigger(seq[fx_bend_down_9],
+ KERNEL_TRIGGER_SPRITE, 5, 1);
+ kernel_seq_trigger(seq[fx_bend_down_9],
+ KERNEL_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ if (player_said_1(red_frame)) {
+ inter_move_object(red_frame, NOWHERE);
+ object[red_frame].location = global[catacombs_room] + 600;
+ seq[fx_red_frame] = kernel_seq_stamp(ss[fx_red_frame], false, 1);
+ kernel_seq_depth(seq[fx_red_frame], 14);
+ local->dyn_red = kernel_add_dynamic(words_red_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5, series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_red, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+
+ if (player_said_1(green_frame)) {
+ inter_move_object(green_frame, NOWHERE);
+ object[green_frame].location = global[catacombs_room] + 600;
+ seq[fx_green_frame] = kernel_seq_stamp(ss[fx_green_frame], false, 1);
+ kernel_seq_depth(seq[fx_green_frame], 14);
+ local->dyn_green = kernel_add_dynamic(words_green_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5, series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_green, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+
+ if (player_said_1(blue_frame)) {
+ inter_move_object(blue_frame, NOWHERE);
+ object[blue_frame].location = global[catacombs_room] + 600;
+ seq[fx_blue_frame] = kernel_seq_stamp(ss[fx_blue_frame], false, 1);
+ kernel_seq_depth(seq[fx_blue_frame], 14);
+ local->dyn_blue = kernel_add_dynamic(words_blue_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5, series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_blue, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+
+ if (player_said_1(yellow_frame)) {
+ inter_move_object(yellow_frame, NOWHERE);
+ object[yellow_frame].location = global[catacombs_room] + 600;
+ seq[fx_yellow_frame] = kernel_seq_stamp(ss[fx_yellow_frame], false, 1);
+ kernel_seq_depth(seq[fx_yellow_frame], 14);
+ local->dyn_yellow = kernel_add_dynamic(words_yellow_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5, series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_yellow, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+ break;
+
+ case 2:
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_SERIES, seq[fx_bend_down_9]);
+ player.walker_visible = true;
+ player.commands_allowed = true;
+ break;
+ }
+ goto handled;
+ }
+ }
+ }
+
+ if (player_said_1(take)) {
+ if (player_said_1(red_frame) || player_said_1(green_frame) ||
+ player_said_1(blue_frame) || player_said_1(yellow_frame)) {
+
+ if ((local->frame_here_for_taking || kernel.trigger)) {
+ if (player.y < 30) {
+ text_show(text_407_18);
+ goto handled;
+ } else {
+ switch (kernel.trigger) {
+ case (0):
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_bend_down_9] = kernel_seq_pingpong(ss[fx_bend_down_9], true,
+ 5, 0, 0, 2);
+ kernel_seq_range(seq[fx_bend_down_9], 1, 5);
+ kernel_seq_player(seq[fx_bend_down_9], true);
+ kernel_seq_trigger(seq[fx_bend_down_9],
+ KERNEL_TRIGGER_SPRITE, 5, 1);
+ kernel_seq_trigger(seq[fx_bend_down_9],
+ KERNEL_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ if (player_said_1(red_frame)) {
+ kernel_seq_delete(seq[fx_red_frame]);
+ kernel_delete_dynamic(local->dyn_red);
+ inter_give_to_player(red_frame);
+ }
+
+ if (player_said_1(green_frame)) {
+ kernel_seq_delete(seq[fx_green_frame]);
+ kernel_delete_dynamic(local->dyn_green);
+ inter_give_to_player(green_frame);
+ }
+
+ if (player_said_1(blue_frame)) {
+ kernel_seq_delete(seq[fx_blue_frame]);
+ kernel_delete_dynamic(local->dyn_blue);
+ inter_give_to_player(blue_frame);
+ }
+
+ if (player_said_1(yellow_frame)) {
+ kernel_seq_delete(seq[fx_yellow_frame]);
+ kernel_delete_dynamic(local->dyn_yellow);
+ inter_give_to_player(yellow_frame);
+ }
+
+ sound_play(N_TakeObjectSnd);
+ break;
+
+ case 2:
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_SERIES, seq[fx_bend_down_9]);
+ player.walker_visible = true;
+ player.commands_allowed = true;
+ break;
+ }
+ goto handled;
+ }
+ }
+ }
+ }
+
+ if (player_said_2(walk_through, archway_to_west)) {
+ if (player.y < 30) {
+ global_catacombs_move(SOUTH);
+ } else {
+ text_show(text_407_18);
+ }
+ goto handled;
+ }
+
+ if (player_said_2(walk_through, archway_to_east)) {
+ if (player.y < 30) {
+ global_catacombs_move(NORTH);
+ } else {
+ text_show(text_407_18);
+ }
+ goto handled;
+ }
+
+ if (player_said_2(exit_to, more_catacombs)) {
+ if (player.y < 30) {
+ text_show(text_407_18);
+ goto handled;
+ }
+ }
+
+ if (player.look_around) {
+ text_show(text_407_10);
+ goto handled;
+ }
+
+ if (player_said_1(look) || player_said_1(look_at)) {
+
+ if (player_said_1(wall)) {
+ text_show(text_407_11);
+ goto handled;
+ }
+
+ if (player_said_1(floor)) {
+ text_show(text_407_12);
+ goto handled;
+ }
+
+ if (player_said_1(archway)) {
+ text_show(text_407_13);
+ goto handled;
+ }
+
+ if (player_said_1(more_catacombs)) {
+ text_show(text_407_14);
+ goto handled;
+ }
+
+ if (player_said_1(column)) {
+ text_show(text_407_15);
+ goto handled;
+ }
+
+ if (player_said_1(red_frame)) {
+ if (!player_has(red_frame)) {
+ object_examine(red_frame, text_008_02, 0);
+ goto handled;
+ }
+ }
+
+ if (player_said_1(green_frame)) {
+ if (!player_has(green_frame)) {
+ object_examine(green_frame, text_008_18, 0);
+ goto handled;
+ }
+ }
+
+ if (player_said_1(blue_frame)) {
+ if (!player_has(blue_frame)) {
+ object_examine(blue_frame, text_008_17, 0);
+ goto handled;
+ }
+ }
+
+ if (player_said_1(yellow_frame)) {
+ if (!player_has(yellow_frame)) {
+ object_examine(yellow_frame, text_008_04, 0);
+ goto handled;
+ }
+ }
+
+ if (player_said_1(lake)) {
+ text_show(text_407_16);
+ goto handled;
+ }
+ }
+
+ goto done;
+
+handled:
+ player.command_ready = false;
+
+done:
+ ;
+}
+
+void room_407_preload() {
+ room_init_code_pointer = room_407_init;
+ room_pre_parser_code_pointer = room_407_pre_parser;
+ room_parser_code_pointer = room_407_parser;
+ room_daemon_code_pointer = NULL;
+
+ section_4_walker();
+ section_4_interface();
+
+ vocab_make_active(words_red_frame);
+ vocab_make_active(words_yellow_frame);
+ vocab_make_active(words_blue_frame);
+ vocab_make_active(words_green_frame);
+}
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/rooms/room407.h b/engines/mads/madsv2/phantom/rooms/room407.h
new file mode 100644
index 00000000000..dbc60b2374c
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room407.h
@@ -0,0 +1,124 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef MADS_PHANTOM_ROOM407_H
+#define MADS_PHANTOM_ROOM407_H
+
+#include "mads/madsv2/core/general.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+#define local ((Scratch *)(&game.scratch[0]))
+#define ss local->sprite
+#define seq local->sequence
+#define aa local->animation
+
+typedef struct { /* Room local variables */
+
+ int16 sprite[15]; /* Sprite series handles */
+ int16 sequence[15]; /* Sequence handles */
+ int16 animation[4]; /* Animation handles */
+ int16 frame_is_here; /* T if any frame is here */
+ int16 dyn_red;
+ int16 dyn_green;
+ int16 dyn_blue;
+ int16 dyn_yellow;
+ int16 frame_here_for_taking; /* T if a specific frame is here */
+
+} Scratch;
+
+
+/* ===================== Sprite seriers ====================== */
+
+#define fx_bend_down_9 0 /* rrd_9 */
+#define fx_red_frame 1 /* rm401f0 */
+#define fx_green_frame 2 /* rm401f1 */
+#define fx_blue_frame 3 /* rm401f2 */
+#define fx_yellow_frame 4 /* rm401f3 */
+
+/* ========================= Triggers ======================== */
+
+
+
+/* ========================= Other Macros ==================== */
+
+#define NORTH_X 197
+#define NORTH_Y 14
+
+#define WALK_TO_NORTH_X 181
+#define WALK_TO_NORTH_Y 14
+
+#define WEST_X -20
+#define WEST_Y 143
+
+#define WALK_TO_WEST_X 20
+#define WALK_TO_WEST_Y 143
+
+#define EAST_X 330
+#define EAST_Y 146
+
+#define WALK_TO_EAST_X 298
+#define WALK_TO_EAST_Y 146
+
+#define SOUTH_X 147
+#define SOUTH_Y 14
+
+#define WALK_TO_SOUTH_X 165
+#define WALK_TO_SOUTH_Y 14
+
+
+
+#define CAT_RIGHT_1_X 310
+#define CAT_RIGHT_1_Y 107
+
+#define CAT_RIGHT_2_X 308
+#define CAT_RIGHT_2_Y 175
+
+#define CAT_RIGHT_3_X 308
+#define CAT_RIGHT_3_Y 146
+
+#define CAT_RIGHT_4_X 309
+#define CAT_RIGHT_4_Y 152
+
+#define CAT_LEFT_1_X 9
+#define CAT_LEFT_1_Y 46
+
+#define CAT_LEFT_2_X 8
+#define CAT_LEFT_2_Y 138
+
+#define CAT_LEFT_3_X 12
+#define CAT_LEFT_3_Y 149
+
+#define CAT_LEFT_4_X 0
+#define CAT_LEFT_4_Y 151
+
+#define LAKE_X 172
+#define LAKE_Y 18
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif // MADS_PHANTOM_ROOM250_H
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index df1174e3d19..1ff03bcb5ab 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -161,6 +161,7 @@ MODULE_OBJS += \
madsv2/phantom/rooms/room403.o \
madsv2/phantom/rooms/room404.o \
madsv2/phantom/rooms/room406.o \
+ madsv2/phantom/rooms/room407.o \
madsv2/phantom/phantom.o \
madsv2/phantom/conv.o \
madsv2/phantom/global.o \
Commit: 685b1440e8eb031c9d0dee8fb6a66f6a85c55d18
https://github.com/scummvm/scummvm/commit/685b1440e8eb031c9d0dee8fb6a66f6a85c55d18
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:50+10:00
Commit Message:
MADS: PHANTOM: Added room 408
Changed paths:
A engines/mads/madsv2/phantom/rooms/room408.cpp
A engines/mads/madsv2/phantom/rooms/room408.h
engines/mads/madsv2/phantom/mads/text.h
engines/mads/madsv2/phantom/mads/words.h
engines/mads/module.mk
diff --git a/engines/mads/madsv2/phantom/mads/text.h b/engines/mads/madsv2/phantom/mads/text.h
index f51cc781b08..cefa7753110 100644
--- a/engines/mads/madsv2/phantom/mads/text.h
+++ b/engines/mads/madsv2/phantom/mads/text.h
@@ -813,7 +813,20 @@ enum {
text_407_15 = 40715,
text_407_16 = 40716,
text_407_17 = 40717,
- text_407_18 = 40718
+ text_407_18 = 40718,
+
+ /* Room 408 */
+ text_408_10 = 40810,
+ text_408_11 = 40811,
+ text_408_12 = 40812,
+ text_408_13 = 40813,
+ text_408_14 = 40814,
+ text_408_15 = 40815,
+ text_408_16 = 40816,
+ text_408_17 = 40817,
+ text_408_18 = 40818,
+ text_408_19 = 40819,
+ text_408_20 = 40820
};
} // namespace Phantom
diff --git a/engines/mads/madsv2/phantom/mads/words.h b/engines/mads/madsv2/phantom/mads/words.h
index 652d6c33aaa..1f9042b21a0 100644
--- a/engines/mads/madsv2/phantom/mads/words.h
+++ b/engines/mads/madsv2/phantom/mads/words.h
@@ -34,6 +34,7 @@ enum {
words_act_curtain = 17,
words_aisle = 18,
words_apron = 19,
+ words_attack = 20,
words_backstage = 21,
words_bear_prop = 22,
words_blue_frame = 23,
@@ -298,6 +299,7 @@ enum {
words_hook = 390,
words_cane = 392,
words_mask = 393,
+ words_cobweb = 397,
words_paper = 399
};
diff --git a/engines/mads/madsv2/phantom/rooms/room408.cpp b/engines/mads/madsv2/phantom/rooms/room408.cpp
new file mode 100644
index 00000000000..2480f2bff5a
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room408.cpp
@@ -0,0 +1,546 @@
+/* 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 "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/camera.h"
+#include "mads/madsv2/core/inter.h"
+#include "mads/madsv2/core/matte.h"
+#include "mads/madsv2/core/object.h"
+#include "mads/madsv2/core/quote.h"
+#include "mads/madsv2/core/sound.h"
+#include "mads/madsv2/core/text.h"
+#include "mads/madsv2/phantom/mads/inventory.h"
+#include "mads/madsv2/phantom/mads/sounds.h"
+#include "mads/madsv2/phantom/rooms/section4.h"
+#include "mads/madsv2/phantom/rooms/room408.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+void room_408_init(void) {
+ int web;
+
+ global_catacombs_init();
+
+ kernel_flip_hotspot(words_cobweb, false);
+
+ /* =================== Load sprites series =================== */
+
+ ss[fx_north] = kernel_load_series(kernel_name('c', 0), false);
+ ss[fx_bend_down_9] = kernel_load_series("*RRD_9", false);
+ ss[fx_red_frame] = kernel_load_series(kernel_name('f', 0), false);
+ ss[fx_green_frame] = kernel_load_series(kernel_name('f', 1), false);
+ ss[fx_blue_frame] = kernel_load_series(kernel_name('f', 2), false);
+ ss[fx_yellow_frame] = kernel_load_series(kernel_name('f', 3), false);
+ ss[fx_web] = kernel_load_series(kernel_name('c', 1), false);
+ ss[fx_brick] = kernel_load_series(kernel_name('c', 2), false);
+
+ if (global_catacombs_exit(NORTH) == -1) {
+ kernel_draw_to_background(ss[fx_north], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ kernel_flip_hotspot(words_archway_to_north, false);
+ kernel_flip_hotspot_loc(words_floor, false, FLOOR_1_X, FLOOR_1_Y);
+ kernel_flip_hotspot_loc(words_floor, false, FLOOR_2_X, FLOOR_2_Y);
+ kernel_flip_hotspot_loc(words_floor, false, FLOOR_3_X, FLOOR_3_Y);
+ kernel_flip_hotspot_loc(words_floor, false, FLOOR_4_X, FLOOR_4_Y);
+ kernel_flip_hotspot_loc(words_floor, false, FLOOR_5_X, FLOOR_5_Y);
+ kernel_flip_hotspot_loc(words_floor, false, FLOOR_6_X, FLOOR_6_Y);
+ kernel_flip_hotspot_loc(words_floor, false, FLOOR_7_X, FLOOR_7_Y);
+ kernel_flip_hotspot_loc(words_floor, false, FLOOR_8_X, FLOOR_8_Y);
+ kernel_flip_hotspot_loc(words_wall, false, WALL_1_X, WALL_1_Y);
+ kernel_flip_hotspot_loc(words_wall, false, WALL_2_X, WALL_2_Y);
+ kernel_flip_hotspot_loc(words_wall, false, WALL_3_X, WALL_3_Y);
+ kernel_flip_hotspot_loc(words_wall, false, WALL_4_X, WALL_4_Y);
+ kernel_load_variant(1);
+
+ } else {
+ kernel_flip_hotspot(words_gate, false);
+ }
+
+ if (previous_room != KERNEL_RESTORING_GAME) {
+
+ switch (global[catacombs_from]) {
+
+ case NORTH:
+ player.x = NORTH_X;
+ player.y = NORTH_Y;
+ player.facing = FACING_SOUTH;
+ player_walk(WALK_TO_NORTH_X, WALK_TO_NORTH_Y, FACING_SOUTH);
+ break;
+
+ case SOUTH:
+ player.x = SOUTH_X;
+ player.y = SOUTH_Y;
+ player.facing = FACING_NORTH;
+ break;
+ }
+ }
+
+ if (global[catacombs_misc] & MAZE_WEB) {
+ ss[fx_un_web] = kernel_load_series(kernel_name('x', -1), false);
+ if (!global[cob_web_is_cut]) {
+ ss[fx_web] = kernel_load_series(kernel_name('c', 1), false);
+ seq[fx_web] = kernel_seq_stamp
+ (ss[fx_web], false, 1);
+ kernel_seq_depth(seq[fx_web], 10);
+ kernel_flip_hotspot(words_cobweb, true);
+
+ } else {
+ seq[fx_un_web] = kernel_seq_stamp
+ (ss[fx_un_web], false, KERNEL_LAST);
+ kernel_seq_depth(seq[fx_un_web], 10);
+ web = kernel_add_dynamic(words_cobweb, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ DYN_WEB_RIGHT_X, DYN_WEB_RIGHT_Y,
+ DYN_WEB_RIGHT_XS, DYN_WEB_RIGHT_YS);
+ kernel_dynamic_walk(web, WEB_WALK_TO_RIGHT_X, WEB_WALK_TO_RIGHT_Y, FACING_NORTHEAST);
+ web = kernel_add_dynamic(words_cobweb, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ DYN_WEB_RIGHT_X_2, DYN_WEB_RIGHT_Y_2,
+ DYN_WEB_RIGHT_XS_2, DYN_WEB_RIGHT_YS_2);
+ kernel_dynamic_walk(web, WEB_WALK_TO_RIGHT_X_2, WEB_WALK_TO_RIGHT_Y_2, FACING_NORTHEAST);
+
+ web = kernel_add_dynamic(words_cobweb, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ DYN_WEB_LEFT_X, DYN_WEB_LEFT_Y,
+ DYN_WEB_LEFT_XS, DYN_WEB_LEFT_YS);
+ kernel_dynamic_walk(web, WEB_WALK_TO_LEFT_X, WEB_WALK_TO_LEFT_Y, FACING_NORTHWEST);
+ web = kernel_add_dynamic(words_cobweb, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ DYN_WEB_LEFT_X_2, DYN_WEB_LEFT_Y_2,
+ DYN_WEB_LEFT_XS_2, DYN_WEB_LEFT_YS_2);
+ kernel_dynamic_walk(web, WEB_WALK_TO_LEFT_X_2, WEB_WALK_TO_LEFT_Y_2, FACING_NORTHWEST);
+ }
+ }
+
+ if (global[catacombs_misc] & MAZE_BRICK) {
+ ss[fx_brick] = kernel_load_series(kernel_name('c', 2), false);
+ kernel_draw_to_background(ss[fx_brick], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ kernel_flip_hotspot(words_exposed_brick, false);
+ }
+
+ if (object[red_frame].location == global[catacombs_room] + 600) {
+ seq[fx_red_frame] = kernel_seq_stamp(ss[fx_red_frame], false, 1);
+ kernel_seq_depth(seq[fx_red_frame], 14);
+ local->dyn_red = kernel_add_dynamic(words_red_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5,
+ series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_red, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+
+ if (object[green_frame].location == global[catacombs_room] + 600) {
+ seq[fx_green_frame] = kernel_seq_stamp(ss[fx_green_frame], false, 1);
+ kernel_seq_depth(seq[fx_green_frame], 14);
+ local->dyn_green = kernel_add_dynamic(words_green_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5,
+ series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_green, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+
+ if (object[blue_frame].location == global[catacombs_room] + 600) {
+ seq[fx_blue_frame] = kernel_seq_stamp(ss[fx_blue_frame], false, 1);
+ kernel_seq_depth(seq[fx_blue_frame], 14);
+ local->dyn_blue = kernel_add_dynamic(words_blue_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5,
+ series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_blue, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+
+ if (object[yellow_frame].location == global[catacombs_room] + 600) {
+ seq[fx_yellow_frame] = kernel_seq_stamp(ss[fx_yellow_frame], false, 1);
+ kernel_seq_depth(seq[fx_yellow_frame], 14);
+ local->dyn_yellow = kernel_add_dynamic(words_yellow_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5,
+ series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_yellow, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+
+ if (game.difficulty == HARD_MODE) {
+ if (global[catacombs_room] == 52) {
+ kernel_timing_trigger(TWO_SECONDS, ROOM_408_SHOW_TEXT);
+ }
+ }
+
+ section_4_music();
+}
+
+void room_408_pre_parser(void) {
+ local->frame_is_here = false;
+ local->frame_here_for_taking = false;
+
+ if (object[red_frame].location == global[catacombs_room] + 600) {
+ local->frame_is_here = true;
+ if (player_said_2(take, red_frame)) {
+ local->frame_here_for_taking = true;
+ }
+ }
+
+ if (object[yellow_frame].location == global[catacombs_room] + 600) {
+ local->frame_is_here = true;
+ if (player_said_2(take, yellow_frame)) {
+ local->frame_here_for_taking = true;
+ }
+ }
+
+ if (object[blue_frame].location == global[catacombs_room] + 600) {
+ local->frame_is_here = true;
+ if (player_said_2(take, blue_frame)) {
+ local->frame_here_for_taking = true;
+ }
+ }
+
+ if (object[green_frame].location == global[catacombs_room] + 600) {
+ local->frame_is_here = true;
+ if (player_said_2(take, green_frame)) {
+ local->frame_here_for_taking = true;
+ }
+ }
+
+ if (player_said_1(put) && player_said_1(floor)) {
+ if (player_said_1(red_frame) ||
+ player_said_1(blue_frame) ||
+ player_said_1(yellow_frame) ||
+ player_said_1(green_frame)) {
+ if (local->frame_is_here) {
+ player.need_to_walk = false;
+ } else {
+ player_walk(series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+ }
+ }
+}
+
+void room_408_parser(void) {
+ int web;
+
+ if (player_said_1(put) && player_said_1(floor)) {
+ if (player_said_1(red_frame) ||
+ player_said_1(blue_frame) ||
+ player_said_1(yellow_frame) ||
+ player_said_1(green_frame)) {
+ if (local->frame_is_here) {
+ text_show(text_000_29);
+ goto handled;
+
+ } else {
+
+ switch (kernel.trigger) {
+ case (0):
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_bend_down_9] = kernel_seq_pingpong(ss[fx_bend_down_9], true,
+ 5, 0, 0, 2);
+ kernel_seq_range(seq[fx_bend_down_9], 1, 5);
+ kernel_seq_player(seq[fx_bend_down_9], true);
+ kernel_seq_trigger(seq[fx_bend_down_9],
+ KERNEL_TRIGGER_SPRITE, 5, 1);
+ kernel_seq_trigger(seq[fx_bend_down_9],
+ KERNEL_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ if (player_said_1(red_frame)) {
+ inter_move_object(red_frame, NOWHERE);
+ object[red_frame].location = global[catacombs_room] + 600;
+ seq[fx_red_frame] = kernel_seq_stamp(ss[fx_red_frame], false, 1);
+ kernel_seq_depth(seq[fx_red_frame], 14);
+ local->dyn_red = kernel_add_dynamic(words_red_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5, series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_red, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+
+ if (player_said_1(green_frame)) {
+ inter_move_object(green_frame, NOWHERE);
+ object[green_frame].location = global[catacombs_room] + 600;
+ seq[fx_green_frame] = kernel_seq_stamp(ss[fx_green_frame], false, 1);
+ kernel_seq_depth(seq[fx_green_frame], 14);
+ local->dyn_green = kernel_add_dynamic(words_green_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5, series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_green, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+
+ if (player_said_1(blue_frame)) {
+ inter_move_object(blue_frame, NOWHERE);
+ object[blue_frame].location = global[catacombs_room] + 600;
+ seq[fx_blue_frame] = kernel_seq_stamp(ss[fx_blue_frame], false, 1);
+ kernel_seq_depth(seq[fx_blue_frame], 14);
+ local->dyn_blue = kernel_add_dynamic(words_blue_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5, series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_blue, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+
+ if (player_said_1(yellow_frame)) {
+ inter_move_object(yellow_frame, NOWHERE);
+ object[yellow_frame].location = global[catacombs_room] + 600;
+ seq[fx_yellow_frame] = kernel_seq_stamp(ss[fx_yellow_frame], false, 1);
+ kernel_seq_depth(seq[fx_yellow_frame], 14);
+ local->dyn_yellow = kernel_add_dynamic(words_yellow_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5, series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_yellow, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+ break;
+
+ case 2:
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_SERIES, seq[fx_bend_down_9]);
+ player.walker_visible = true;
+ player.commands_allowed = true;
+ break;
+ }
+ goto handled;
+ }
+ }
+ }
+
+ if (player_said_1(take)) {
+ if (player_said_1(red_frame) || player_said_1(green_frame) ||
+ player_said_1(blue_frame) || player_said_1(yellow_frame)) {
+
+ if ((local->frame_here_for_taking || kernel.trigger)) {
+ switch (kernel.trigger) {
+ case (0):
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_bend_down_9] = kernel_seq_pingpong(ss[fx_bend_down_9], true,
+ 5, 0, 0, 2);
+ kernel_seq_range(seq[fx_bend_down_9], 1, 5);
+ kernel_seq_player(seq[fx_bend_down_9], true);
+ kernel_seq_trigger(seq[fx_bend_down_9],
+ KERNEL_TRIGGER_SPRITE, 5, 1);
+ kernel_seq_trigger(seq[fx_bend_down_9],
+ KERNEL_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ if (player_said_1(red_frame)) {
+ kernel_seq_delete(seq[fx_red_frame]);
+ kernel_delete_dynamic(local->dyn_red);
+ inter_give_to_player(red_frame);
+ }
+
+ if (player_said_1(green_frame)) {
+ kernel_seq_delete(seq[fx_green_frame]);
+ kernel_delete_dynamic(local->dyn_green);
+ inter_give_to_player(green_frame);
+ }
+
+ if (player_said_1(blue_frame)) {
+ kernel_seq_delete(seq[fx_blue_frame]);
+ kernel_delete_dynamic(local->dyn_blue);
+ inter_give_to_player(blue_frame);
+ }
+
+ if (player_said_1(yellow_frame)) {
+ kernel_seq_delete(seq[fx_yellow_frame]);
+ kernel_delete_dynamic(local->dyn_yellow);
+ inter_give_to_player(yellow_frame);
+ }
+
+ sound_play(N_TakeObjectSnd);
+ break;
+
+ case 2:
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_SERIES, seq[fx_bend_down_9]);
+ player.walker_visible = true;
+ player.commands_allowed = true;
+ break;
+ }
+ goto handled;
+ }
+ }
+ }
+
+ if (player_said_2(walk_through, archway_to_north)) {
+ global_catacombs_move(NORTH);
+ goto handled;
+ }
+
+ if (player_said_2(exit_to, more_catacombs)) {
+ global_catacombs_move(SOUTH);
+ goto handled;
+ }
+
+ if (player.look_around) {
+ text_show(text_408_10);
+ goto handled;
+ }
+
+ if (player_said_1(look) || player_said_1(look_at)) {
+
+ if (player_said_1(wall)) {
+ text_show(text_408_11);
+ goto handled;
+ }
+
+ if (player_said_1(floor)) {
+ text_show(text_408_12);
+ goto handled;
+ }
+
+ if (player_said_1(archway)) {
+ text_show(text_408_13);
+ goto handled;
+ }
+
+ if (player_said_1(exposed_brick)) {
+ text_show(text_408_14);
+ goto handled;
+ }
+
+ if (player_said_1(more_catacombs)) {
+ text_show(text_408_15);
+ goto handled;
+ }
+
+ if (player_said_1(ceiling)) {
+ text_show(text_408_16);
+ goto handled;
+ }
+
+ if (player_said_1(red_frame)) {
+ if (!player_has(red_frame)) {
+ object_examine(red_frame, text_008_02, 0);
+ goto handled;
+ }
+ }
+
+ if (player_said_1(green_frame)) {
+ if (!player_has(green_frame)) {
+ object_examine(green_frame, text_008_19, 0);
+ goto handled;
+ }
+ }
+
+ if (player_said_1(blue_frame)) {
+ if (!player_has(blue_frame)) {
+ object_examine(blue_frame, text_008_17, 0);
+ goto handled;
+ }
+ }
+
+ if (player_said_1(yellow_frame)) {
+ if (!player_has(yellow_frame)) {
+ object_examine(yellow_frame, text_008_04, 0);
+ goto handled;
+ }
+ }
+
+ if (player_said_1(gate)) {
+ text_show(text_408_17);
+ goto handled;
+ }
+
+ if (player_said_1(cobweb)) {
+ if (global[cob_web_is_cut]) {
+ text_show(text_408_20);
+ } else {
+ text_show(text_408_19);
+ }
+ goto handled;
+ }
+ }
+
+ if ((player_said_2(attack, cobweb) && !global[cob_web_is_cut])) {
+ aa[0] = kernel_run_animation(kernel_name('W', 1), ROOM_408_DONE);
+ player.walker_visible = false;
+ player.commands_allowed = false;
+ global[cob_web_is_cut] = true;
+ kernel_seq_delete(seq[fx_web]);
+ goto handled;
+ }
+
+ if (kernel.trigger == ROOM_408_DONE) {
+ seq[fx_un_web] = kernel_seq_stamp
+ (ss[fx_un_web], false, KERNEL_LAST);
+ kernel_seq_depth(seq[fx_un_web], 14);
+ kernel_load_variant(0);
+ kernel_flip_hotspot(words_cobweb, false);
+ player.walker_visible = true;
+ player.commands_allowed = true;
+ web = kernel_add_dynamic(words_cobweb, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ DYN_WEB_RIGHT_X, DYN_WEB_RIGHT_Y,
+ DYN_WEB_RIGHT_XS, DYN_WEB_RIGHT_YS);
+ kernel_dynamic_walk(web, WEB_WALK_TO_RIGHT_X, WEB_WALK_TO_RIGHT_Y, FACING_NORTHEAST);
+ web = kernel_add_dynamic(words_cobweb, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ DYN_WEB_RIGHT_X_2, DYN_WEB_RIGHT_Y_2,
+ DYN_WEB_RIGHT_XS_2, DYN_WEB_RIGHT_YS_2);
+ kernel_dynamic_walk(web, WEB_WALK_TO_RIGHT_X_2, WEB_WALK_TO_RIGHT_Y_2, FACING_NORTHEAST);
+
+ web = kernel_add_dynamic(words_cobweb, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ DYN_WEB_LEFT_X, DYN_WEB_LEFT_Y,
+ DYN_WEB_LEFT_XS, DYN_WEB_LEFT_YS);
+ kernel_dynamic_walk(web, WEB_WALK_TO_LEFT_X, WEB_WALK_TO_LEFT_Y, FACING_NORTHWEST);
+ web = kernel_add_dynamic(words_cobweb, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ DYN_WEB_LEFT_X_2, DYN_WEB_LEFT_Y_2,
+ DYN_WEB_LEFT_XS_2, DYN_WEB_LEFT_YS_2);
+ kernel_dynamic_walk(web, WEB_WALK_TO_LEFT_X_2, WEB_WALK_TO_LEFT_Y_2, FACING_NORTHWEST);
+ goto handled;
+ }
+
+ if (player_said_2(open, gate)) {
+ text_show(text_408_18);
+ goto handled;
+ }
+
+ goto done;
+
+handled:
+ player.command_ready = false;
+
+done:
+ ;
+}
+
+void room_408_daemon(void) {
+ if (kernel.trigger == ROOM_408_SHOW_TEXT) {
+ text_show(text_000_31);
+ }
+}
+
+void room_408_preload(void) {
+ room_init_code_pointer = room_408_init;
+ room_pre_parser_code_pointer = room_408_pre_parser;
+ room_parser_code_pointer = room_408_parser;
+ room_daemon_code_pointer = room_408_daemon;
+
+ section_4_walker();
+ section_4_interface();
+
+ if ((global[catacombs_misc] & MAZE_WEB) && (!global[cob_web_is_cut])) {
+ kernel_initial_variant = 1;
+ }
+
+ vocab_make_active(words_red_frame);
+ vocab_make_active(words_yellow_frame);
+ vocab_make_active(words_blue_frame);
+ vocab_make_active(words_green_frame);
+}
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/rooms/room408.h b/engines/mads/madsv2/phantom/rooms/room408.h
new file mode 100644
index 00000000000..39742546829
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room408.h
@@ -0,0 +1,151 @@
+/* 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 MADS_PHANTOM_ROOM408_H
+#define MADS_PHANTOM_ROOM408_H
+
+#include "mads/madsv2/core/general.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+#define local ((Scratch *)(&game.scratch[0]))
+#define ss local->sprite
+#define seq local->sequence
+#define aa local->animation
+
+typedef struct { /* Room local variables */
+
+ int16 sprite[15]; /* Sprite series handles */
+ int16 sequence[15]; /* Sequence handles */
+ int16 animation[4]; /* Animation handles */
+ int16 frame_is_here; /* T if any frame is here */
+ int16 dyn_red;
+ int16 dyn_green;
+ int16 dyn_blue;
+ int16 dyn_yellow;
+ int16 frame_here_for_taking; /* T if a specific frame is here */
+
+
+} Scratch;
+
+/* ========================= Sprite Series =================== */
+
+#define fx_north 0 /* rm408c0 */
+#define fx_bend_down_9 1 /* rrd_9 */
+#define fx_red_frame 2 /* rm408f0 */
+#define fx_green_frame 3 /* rm408f1 */
+#define fx_blue_frame 4 /* rm408f2 */
+#define fx_yellow_frame 5 /* rm408f3 */
+#define fx_web 6 /* rm408c1 */
+#define fx_brick 7 /* rm408c2 */
+#define fx_un_web 8 /* rm408x */
+
+
+/* ======================== Triggers ========================= */
+
+#define ROOM_408_SHOW_TEXT 60
+#define ROOM_408_DONE 70
+
+
+/* ========================= Other Macros ==================== */
+
+#define NORTH_X 174
+#define NORTH_Y 100
+
+#define WALK_TO_NORTH_X 174
+#define WALK_TO_NORTH_Y 106
+
+#define SOUTH_X 175
+#define SOUTH_Y 145
+
+#define FLOOR_1_X 147
+#define FLOOR_1_Y 121
+
+#define FLOOR_2_X 153
+#define FLOOR_2_Y 121
+
+#define FLOOR_3_X 154
+#define FLOOR_3_Y 115
+
+#define FLOOR_4_X 161
+#define FLOOR_4_Y 101
+
+#define FLOOR_5_X 162
+#define FLOOR_5_Y 106
+
+#define FLOOR_6_X 187
+#define FLOOR_6_Y 107
+
+#define FLOOR_7_X 185
+#define FLOOR_7_Y 101
+
+#define FLOOR_8_X 192
+#define FLOOR_8_Y 119
+
+#define WALL_1_X 147
+#define WALL_1_Y 76
+
+#define WALL_2_X 159
+#define WALL_2_Y 108
+
+#define WALL_3_X 185
+#define WALL_3_Y 93
+
+#define WALL_4_X 199
+#define WALL_4_Y 91
+
+#define DYN_WEB_RIGHT_X 199
+#define DYN_WEB_RIGHT_Y 112
+#define DYN_WEB_RIGHT_XS 6
+#define DYN_WEB_RIGHT_YS 12
+#define WEB_WALK_TO_RIGHT_X 194
+#define WEB_WALK_TO_RIGHT_Y 125
+
+#define DYN_WEB_RIGHT_X_2 202
+#define DYN_WEB_RIGHT_Y_2 81
+#define DYN_WEB_RIGHT_XS_2 5
+#define DYN_WEB_RIGHT_YS_2 31
+#define WEB_WALK_TO_RIGHT_X_2 194
+#define WEB_WALK_TO_RIGHT_Y_2 125
+
+#define DYN_WEB_LEFT_X 138
+#define DYN_WEB_LEFT_Y 74
+#define DYN_WEB_LEFT_XS 7
+#define DYN_WEB_LEFT_YS 33
+#define WEB_WALK_TO_LEFT_X 154
+#define WEB_WALK_TO_LEFT_Y 124
+
+#define DYN_WEB_LEFT_X_2 143
+#define DYN_WEB_LEFT_Y_2 107
+#define DYN_WEB_LEFT_XS_2 6
+#define DYN_WEB_LEFT_YS_2 15
+#define WEB_WALK_TO_LEFT_X_2 154
+#define WEB_WALK_TO_LEFT_Y_2 124
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif // MADS_PHANTOM_ROOM250_H
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index 1ff03bcb5ab..8e82bd9f11c 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -162,6 +162,7 @@ MODULE_OBJS += \
madsv2/phantom/rooms/room404.o \
madsv2/phantom/rooms/room406.o \
madsv2/phantom/rooms/room407.o \
+ madsv2/phantom/rooms/room408.o \
madsv2/phantom/phantom.o \
madsv2/phantom/conv.o \
madsv2/phantom/global.o \
Commit: e2de73f229630e392c0ee83bf1c7bf41ac308e44
https://github.com/scummvm/scummvm/commit/e2de73f229630e392c0ee83bf1c7bf41ac308e44
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:50+10:00
Commit Message:
MADS: PHANTOM: Added room 409
Changed paths:
A engines/mads/madsv2/phantom/rooms/room409.cpp
A engines/mads/madsv2/phantom/rooms/room409.h
engines/mads/madsv2/phantom/mads/sounds.h
engines/mads/madsv2/phantom/mads/speeches.h
engines/mads/madsv2/phantom/mads/text.h
engines/mads/madsv2/phantom/mads/words.h
engines/mads/module.mk
diff --git a/engines/mads/madsv2/phantom/mads/sounds.h b/engines/mads/madsv2/phantom/mads/sounds.h
index 3bb583b83a5..cc0a0f55806 100644
--- a/engines/mads/madsv2/phantom/mads/sounds.h
+++ b/engines/mads/madsv2/phantom/mads/sounds.h
@@ -36,8 +36,10 @@ enum {
N_DoorOpens = 24,
N_DoorCloses = 25,
N_TakeObjectSnd = 26,
+ N_PlayerDies = 27,
N_AngelMus001 = 34,
N_BackMus1stTime = 38,
+ N_PoisonGas = 61,
N_TrapDoor001 = 64,
N_WomanScream002 = 65,
N_SqueakyDoor = 66,
@@ -50,7 +52,8 @@ enum {
N_DoorHandle = 73,
N_WomanScream003 = 74,
- N_Crash003 = 66
+ N_Crash003 = 66,
+ N_DoorHandle004 = 70
};
} // namespace Phantom
diff --git a/engines/mads/madsv2/phantom/mads/speeches.h b/engines/mads/madsv2/phantom/mads/speeches.h
index b7a2e50a1dd..f320b1e266e 100644
--- a/engines/mads/madsv2/phantom/mads/speeches.h
+++ b/engines/mads/madsv2/phantom/mads/speeches.h
@@ -31,6 +31,7 @@ namespace Phantom {
enum {
speech_woman_scream = 1,
speech_applause = 2,
+ speech_raoul_gas = 3,
speech_christine_scream = 4,
speech_raoul_strangle = 5,
speech_raoul_catwalk = 6,
diff --git a/engines/mads/madsv2/phantom/mads/text.h b/engines/mads/madsv2/phantom/mads/text.h
index cefa7753110..e2decd19b59 100644
--- a/engines/mads/madsv2/phantom/mads/text.h
+++ b/engines/mads/madsv2/phantom/mads/text.h
@@ -37,6 +37,7 @@ enum {
text_008_06 = 806,
text_008_07 = 807,
+ text_008_08 = 808,
text_008_16 = 816,
text_008_17 = 817,
text_008_18 = 818,
@@ -826,7 +827,23 @@ enum {
text_408_17 = 40817,
text_408_18 = 40818,
text_408_19 = 40819,
- text_408_20 = 40820
+ text_408_20 = 40820,
+
+ /* Room 409 */
+ text_409_10 = 40910,
+ text_409_11 = 40911,
+ text_409_12 = 40912,
+ text_409_13 = 40913,
+ text_409_14 = 40914,
+ text_409_15 = 40915,
+ text_409_16 = 40916,
+ text_409_17 = 40917,
+ text_409_18 = 40918,
+ text_409_19 = 40919,
+ text_409_20 = 40920,
+ text_409_21 = 40921,
+ text_409_23 = 40923,
+ text_409_24 = 40924
};
} // namespace Phantom
diff --git a/engines/mads/madsv2/phantom/mads/words.h b/engines/mads/madsv2/phantom/mads/words.h
index 1f9042b21a0..4e38b4482c0 100644
--- a/engines/mads/madsv2/phantom/mads/words.h
+++ b/engines/mads/madsv2/phantom/mads/words.h
@@ -130,6 +130,7 @@ enum {
words_staircase = 138,
words_stairwell = 139,
words_stool = 140,
+ words_sword = 142,
words_table = 143,
words_thunder_machine = 145,
words_ticket = 146,
@@ -277,6 +278,8 @@ enum {
words_catacombs = 328,
words_ticket_seller = 329,
words_usher = 330,
+ words_unlucky_adventurer = 331,
+ words_switch_panel = 332,
words_box_ten = 336,
words_walk_down_stairs_to = 339,
words_hat_rack = 340,
diff --git a/engines/mads/madsv2/phantom/rooms/room409.cpp b/engines/mads/madsv2/phantom/rooms/room409.cpp
new file mode 100644
index 00000000000..4eaecf4e55c
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room409.cpp
@@ -0,0 +1,690 @@
+/* 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 "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/camera.h"
+#include "mads/madsv2/core/inter.h"
+#include "mads/madsv2/core/matte.h"
+#include "mads/madsv2/core/object.h"
+#include "mads/madsv2/core/quote.h"
+#include "mads/madsv2/core/sound.h"
+#include "mads/madsv2/core/speech.h"
+#include "mads/madsv2/core/text.h"
+#include "mads/madsv2/phantom/mads/inventory.h"
+#include "mads/madsv2/phantom/mads/sounds.h"
+#include "mads/madsv2/phantom/mads/speeches.h"
+#include "mads/madsv2/phantom/rooms/section4.h"
+#include "mads/madsv2/phantom/rooms/room409.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+void room_409_init() {
+ global_catacombs_init();
+
+ global_speech_load(speech_raoul_gas);
+
+ kernel_flip_hotspot(words_sword, false);
+
+ /* =================== Load sprites series =================== */
+
+ ss[fx_take_9] = kernel_load_series("*RDR_9", false);
+ ss[fx_bend_down_9] = kernel_load_series("*RRD_9", false);
+ ss[fx_red_frame] = kernel_load_series(kernel_name('f', 0), false);
+ ss[fx_green_frame] = kernel_load_series(kernel_name('f', 1), false);
+ ss[fx_blue_frame] = kernel_load_series(kernel_name('f', 2), false);
+ ss[fx_yellow_frame] = kernel_load_series(kernel_name('f', 3), false);
+ ss[fx_door] = kernel_load_series(kernel_name('x', 0), false);
+ ss[fx_gas] = kernel_load_series(kernel_name('a', 0), false);
+
+ if (object_is_here(sword)) {
+ ss[fx_sword] = kernel_load_series(kernel_name('p', 0), false);
+ ss[fx_bend_down_9] = kernel_load_series("*RRD_9", false);
+ seq[fx_sword] = kernel_seq_stamp(ss[fx_sword], false, 1);
+ kernel_seq_depth(seq[fx_sword], 14);
+ kernel_flip_hotspot(words_sword, true);
+ }
+
+
+ if (!global[door_in_409_is_open]) {
+ seq[fx_door] = kernel_seq_stamp
+ (ss[fx_door], false, 1);
+ kernel_seq_depth(seq[fx_door], 14);
+ kernel_flip_hotspot(words_archway_to_north, false);
+ } else {
+ kernel_flip_hotspot(words_door, false);
+ }
+
+
+ /* ===================== Previous rooms ====================== */
+
+ if (previous_room == 410) {
+ player.facing = FACING_NORTH;
+ player.x = PANEL_X;
+ player.y = PANEL_Y;
+
+ if (global[flicked_1] && global[flicked_2] && global[flicked_3] && global[flicked_4]) {
+ if ((global[flicked_1] == 5) && (global[flicked_2] == 18) &&
+ (global[flicked_3] == 9) && (global[flicked_4] == 11)) {
+ if (!global[door_in_409_is_open]) {
+ global[player_score] += 5;
+ sound_play(N_DoorOpens);
+ kernel_seq_delete(seq[fx_door]);
+ player.commands_allowed = false;
+ seq[fx_door] = kernel_seq_forward(ss[fx_door], false, 7, 0, 0, 1);
+ kernel_seq_depth(seq[fx_door], 14);
+ kernel_seq_range(seq[fx_door], KERNEL_FIRST, KERNEL_LAST);
+ kernel_seq_trigger(seq[fx_door],
+ KERNEL_TRIGGER_EXPIRE, 0, ROOM_409_DOOR_OPENS);
+ }
+
+ } else {
+ global[flicked_1] = 0;
+ global[flicked_2] = 0;
+ global[flicked_3] = 0;
+ global[flicked_4] = 0;
+ player.commands_allowed = false;
+ seq[fx_gas] = kernel_seq_forward(ss[fx_gas], false, 9, 0, 0, 1);
+ kernel_seq_depth(seq[fx_gas], 1);
+ kernel_seq_range(seq[fx_gas], KERNEL_FIRST, KERNEL_LAST);
+ kernel_seq_trigger(seq[fx_gas],
+ KERNEL_TRIGGER_SPRITE, 15, ROOM_409_DIE);
+ kernel_seq_trigger(seq[fx_gas],
+ KERNEL_TRIGGER_EXPIRE, 0, ROOM_409_DIE + 1);
+ sound_play(N_PoisonGas);
+ }
+
+ } else {
+ global[flicked_1] = 0;
+ global[flicked_2] = 0;
+ global[flicked_3] = 0;
+ global[flicked_4] = 0;
+ }
+
+ } else if (previous_room != KERNEL_RESTORING_GAME) {
+
+ switch (global[catacombs_from]) {
+
+ case NORTH:
+ player.x = NORTH_X;
+ player.y = NORTH_Y;
+ player.facing = FACING_SOUTH;
+ player_walk(WALK_TO_NORTH_X, WALK_TO_NORTH_Y, FACING_SOUTH);
+ break;
+
+ case SOUTH:
+ player.x = SOUTH_X;
+ player.y = SOUTH_Y;
+ player.facing = FACING_NORTH;
+ break;
+ }
+ }
+
+
+ /* ================= Stamp frame if in room ================== */
+
+ if (object[red_frame].location == global[catacombs_room] + 600) {
+ seq[fx_red_frame] = kernel_seq_stamp(ss[fx_red_frame], false, 1);
+ kernel_seq_depth(seq[fx_red_frame], 14);
+ local->dyn_red = kernel_add_dynamic(words_red_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5,
+ series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_red, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+
+ if (object[green_frame].location == global[catacombs_room] + 600) {
+ seq[fx_green_frame] = kernel_seq_stamp(ss[fx_green_frame], false, 1);
+ kernel_seq_depth(seq[fx_green_frame], 14);
+ local->dyn_green = kernel_add_dynamic(words_green_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5,
+ series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_green, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+
+ if (object[blue_frame].location == global[catacombs_room] + 600) {
+ seq[fx_blue_frame] = kernel_seq_stamp(ss[fx_blue_frame], false, 1);
+ kernel_seq_depth(seq[fx_blue_frame], 14);
+ local->dyn_blue = kernel_add_dynamic(words_blue_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5,
+ series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_blue, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+
+ if (object[yellow_frame].location == global[catacombs_room] + 600) {
+ seq[fx_yellow_frame] = kernel_seq_stamp(ss[fx_yellow_frame], false, 1);
+ kernel_seq_depth(seq[fx_yellow_frame], 14);
+ local->dyn_yellow = kernel_add_dynamic(words_yellow_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5,
+ series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_yellow, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+
+ section_4_music();
+}
+
+void room_409_pre_parser() {
+ local->frame_is_here = false;
+ local->frame_here_for_taking = false;
+
+ if (object[red_frame].location == global[catacombs_room] + 600) {
+ local->frame_is_here = true;
+ if (player_said_2(take, red_frame)) {
+ local->frame_here_for_taking = true;
+ }
+ }
+
+ if (object[yellow_frame].location == global[catacombs_room] + 600) {
+ local->frame_is_here = true;
+ if (player_said_2(take, yellow_frame)) {
+ local->frame_here_for_taking = true;
+ }
+ }
+
+ if (object[blue_frame].location == global[catacombs_room] + 600) {
+ local->frame_is_here = true;
+ if (player_said_2(take, blue_frame)) {
+ local->frame_here_for_taking = true;
+ }
+ }
+
+ if (object[green_frame].location == global[catacombs_room] + 600) {
+ local->frame_is_here = true;
+ if (player_said_2(take, green_frame)) {
+ local->frame_here_for_taking = true;
+ }
+ }
+
+ if (player_said_1(put) && player_said_1(floor)) {
+ if (player_said_1(red_frame) ||
+ player_said_1(blue_frame) ||
+ player_said_1(yellow_frame) ||
+ player_said_1(green_frame)) {
+ if (local->frame_is_here) {
+ player.need_to_walk = false;
+
+ } else {
+ player_walk(series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+ }
+ }
+
+ if (player_said_2(look, switch_panel)) {
+ player_walk(PANEL_X, PANEL_Y, FACING_NORTH);
+ }
+
+ if (player_said_2(open, door)) {
+ player_walk(DOOR_X, DOOR_Y, FACING_NORTHEAST);
+ }
+
+ if (player_said_2(open, grate)) {
+ player.need_to_walk = true;
+ }
+}
+
+void room_409_parser() {
+ int temp; /* for synching purposes */
+
+ if (player_said_2(walk_through, door) || player_said_2(open, door)) {
+ switch (kernel.trigger) {
+ case (0):
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_take_9] = kernel_seq_forward(ss[fx_take_9], false, 5, 0, 0, 1);
+ kernel_seq_range(seq[fx_take_9], 1, 4);
+ kernel_seq_player(seq[fx_take_9], true);
+ kernel_seq_trigger(seq[fx_take_9], KERNEL_TRIGGER_EXPIRE, 0, 1);
+ kernel_seq_trigger(seq[fx_take_9], KERNEL_TRIGGER_SPRITE, 4, 4);
+ goto handled;
+ break;
+
+ case 1:
+ temp = seq[fx_take_9];
+ seq[fx_take_9] = kernel_seq_stamp(ss[fx_take_9], false, 4);
+ kernel_synch(KERNEL_SERIES, seq[fx_take_9], KERNEL_SERIES, temp);
+ kernel_seq_player(seq[fx_take_9], false);
+ kernel_timing_trigger(HALF_SECOND, 2);
+ goto handled;
+ break;
+
+ case 2:
+ kernel_seq_delete(seq[fx_take_9]);
+ seq[fx_take_9] = kernel_seq_backward(ss[fx_take_9], false, 5, 0, 0, 1);
+ kernel_seq_range(seq[fx_take_9], 1, 4);
+ kernel_seq_player(seq[fx_take_9], false);
+ kernel_seq_trigger(seq[fx_take_9], KERNEL_TRIGGER_EXPIRE, 0, 3);
+ goto handled;
+ break;
+
+ case 3:
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_SERIES, seq[fx_take_9]);
+ player.walker_visible = true;
+ text_show(text_409_23);
+ /* the door is locked */
+ player.commands_allowed = true;
+ goto handled;
+ break;
+
+ case 4:
+ sound_play(N_DoorHandle004);
+ goto handled;
+ break;
+ }
+ }
+
+ if (player_said_1(put) && player_said_1(floor)) {
+ if (player_said_1(red_frame) ||
+ player_said_1(blue_frame) ||
+ player_said_1(yellow_frame) ||
+ player_said_1(green_frame)) {
+ if (local->frame_is_here) {
+ text_show(text_000_29);
+ goto handled;
+
+ } else {
+
+ switch (kernel.trigger) {
+ case (0):
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_bend_down_9] = kernel_seq_pingpong(ss[fx_bend_down_9], true,
+ 5, 0, 0, 2);
+ kernel_seq_range(seq[fx_bend_down_9], 1, 5);
+ kernel_seq_player(seq[fx_bend_down_9], true);
+ kernel_seq_trigger(seq[fx_bend_down_9],
+ KERNEL_TRIGGER_SPRITE, 5, 1);
+ kernel_seq_trigger(seq[fx_bend_down_9],
+ KERNEL_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ if (player_said_1(red_frame)) {
+ inter_move_object(red_frame, NOWHERE);
+ object[red_frame].location = global[catacombs_room] + 600;
+ seq[fx_red_frame] = kernel_seq_stamp(ss[fx_red_frame], false, 1);
+ kernel_seq_depth(seq[fx_red_frame], 14);
+ local->dyn_red = kernel_add_dynamic(words_red_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5, series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_red, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+
+ if (player_said_1(green_frame)) {
+ inter_move_object(green_frame, NOWHERE);
+ object[green_frame].location = global[catacombs_room] + 600;
+ seq[fx_green_frame] = kernel_seq_stamp(ss[fx_green_frame], false, 1);
+ kernel_seq_depth(seq[fx_green_frame], 14);
+ local->dyn_green = kernel_add_dynamic(words_green_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5, series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_green, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+
+ if (player_said_1(blue_frame)) {
+ inter_move_object(blue_frame, NOWHERE);
+ object[blue_frame].location = global[catacombs_room] + 600;
+ seq[fx_blue_frame] = kernel_seq_stamp(ss[fx_blue_frame], false, 1);
+ kernel_seq_depth(seq[fx_blue_frame], 14);
+ local->dyn_blue = kernel_add_dynamic(words_blue_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5, series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_blue, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+
+ if (player_said_1(yellow_frame)) {
+ inter_move_object(yellow_frame, NOWHERE);
+ object[yellow_frame].location = global[catacombs_room] + 600;
+ seq[fx_yellow_frame] = kernel_seq_stamp(ss[fx_yellow_frame], false, 1);
+ kernel_seq_depth(seq[fx_yellow_frame], 14);
+ local->dyn_yellow = kernel_add_dynamic(words_yellow_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5, series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_yellow, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+ break;
+
+ case 2:
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_SERIES, seq[fx_bend_down_9]);
+ player.walker_visible = true;
+ player.commands_allowed = true;
+ break;
+ }
+ goto handled;
+ }
+ }
+ }
+
+
+ if (player_said_1(take)) {
+ if (player_said_1(red_frame) || player_said_1(green_frame) ||
+ player_said_1(blue_frame) || player_said_1(yellow_frame)) {
+
+ if ((local->frame_here_for_taking || kernel.trigger)) {
+ switch (kernel.trigger) {
+ case (0):
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_bend_down_9] = kernel_seq_pingpong(ss[fx_bend_down_9], true,
+ 5, 0, 0, 2);
+ kernel_seq_range(seq[fx_bend_down_9], 1, 5);
+ kernel_seq_player(seq[fx_bend_down_9], true);
+ kernel_seq_trigger(seq[fx_bend_down_9],
+ KERNEL_TRIGGER_SPRITE, 5, 1);
+ kernel_seq_trigger(seq[fx_bend_down_9],
+ KERNEL_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ if (player_said_1(red_frame)) {
+ kernel_seq_delete(seq[fx_red_frame]);
+ kernel_delete_dynamic(local->dyn_red);
+ inter_give_to_player(red_frame);
+ }
+
+ if (player_said_1(green_frame)) {
+ kernel_seq_delete(seq[fx_green_frame]);
+ kernel_delete_dynamic(local->dyn_green);
+ inter_give_to_player(green_frame);
+ }
+
+ if (player_said_1(blue_frame)) {
+ kernel_seq_delete(seq[fx_blue_frame]);
+ kernel_delete_dynamic(local->dyn_blue);
+ inter_give_to_player(blue_frame);
+ }
+
+ if (player_said_1(yellow_frame)) {
+ kernel_seq_delete(seq[fx_yellow_frame]);
+ kernel_delete_dynamic(local->dyn_yellow);
+ inter_give_to_player(yellow_frame);
+ }
+
+ sound_play(N_TakeObjectSnd);
+ break;
+
+ case 2:
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_SERIES, seq[fx_bend_down_9]);
+ player.walker_visible = true;
+ player.commands_allowed = true;
+ break;
+ }
+ goto handled;
+ }
+ }
+ }
+
+ if (player_said_2(walk_through, archway_to_north)) {
+ global_enter_catacombs(true);
+ goto handled;
+ }
+
+ if (player_said_2(exit_to, more_catacombs)) {
+ global_enter_catacombs(false);
+ goto handled;
+ }
+
+ if (player.look_around) {
+ text_show(text_409_10);
+ goto handled;
+ }
+
+ if (player_said_2(take, sword) &&
+ (object_is_here(sword) || kernel.trigger)) {
+ switch (kernel.trigger) {
+ case (0):
+ global[player_score] += 5;
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_bend_down_9] = kernel_seq_pingpong(ss[fx_bend_down_9], true,
+ 5, 0, 0, 2);
+ kernel_seq_range(seq[fx_bend_down_9], 1, 5);
+ kernel_seq_player(seq[fx_bend_down_9], true);
+ kernel_seq_trigger(seq[fx_bend_down_9],
+ KERNEL_TRIGGER_SPRITE, 5, 1);
+ kernel_seq_trigger(seq[fx_bend_down_9],
+ KERNEL_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ kernel_seq_delete(seq[fx_sword]);
+ kernel_flip_hotspot(words_sword, false);
+ inter_give_to_player(sword);
+ sound_play(N_TakeObjectSnd);
+ break;
+
+ case 2:
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_SERIES, seq[fx_bend_down_9]);
+ player.walker_visible = true;
+ kernel_timing_trigger(20, 3);
+ break;
+
+ case 3:
+ object_examine(sword, text_008_08, 0);
+ /* You pick up the sword frame */
+ player.commands_allowed = true;
+ break;
+ }
+ goto handled;
+ }
+
+ if (player_said_1(look) || player_said_1(look_at)) {
+
+ if (player_said_1(wall)) {
+ text_show(text_409_11);
+ goto handled;
+ }
+
+ if (player_said_1(floor)) {
+ text_show(text_409_12);
+ goto handled;
+ }
+
+ if (player_said_1(archway)) {
+ text_show(text_409_13);
+ goto handled;
+ }
+
+ if (player_said_1(exposed_brick)) {
+ text_show(text_409_14);
+ goto handled;
+ }
+
+ if (player_said_1(more_catacombs)) {
+ text_show(text_409_15);
+ goto handled;
+ }
+
+ if (player_said_1(blocked_archway)) {
+ text_show(text_409_16);
+ goto handled;
+ }
+
+ if (player_said_1(grate)) {
+ text_show(text_409_17);
+ goto handled;
+ }
+
+ if (player_said_1(unlucky_adventurer)) {
+ text_show(text_409_20);
+ goto handled;
+ }
+
+ if (player_said_1(red_frame)) {
+ if (!player_has(red_frame)) {
+ object_examine(red_frame, text_008_02, 0);
+ goto handled;
+ }
+ }
+
+ if (player_said_1(green_frame)) {
+ if (!player_has(green_frame)) {
+ object_examine(green_frame, text_008_19, 0);
+ goto handled;
+ }
+ }
+
+ if (player_said_1(blue_frame)) {
+ if (!player_has(blue_frame)) {
+ object_examine(blue_frame, text_008_17, 0);
+ goto handled;
+ }
+ }
+
+ if (player_said_1(yellow_frame)) {
+ if (!player_has(yellow_frame)) {
+ object_examine(yellow_frame, text_008_04, 0);
+ goto handled;
+ }
+ }
+
+ if (player_said_1(sword) && object_is_here(sword)) {
+ text_show(text_409_21);
+ goto handled;
+ }
+ }
+
+ if (player_said_2(look, switch_panel)) {
+ text_show(text_409_19);
+ new_room = 410;
+ goto handled;
+ }
+
+ if (player_said_2(walk_to, switch_panel)) {
+ new_room = 410;
+ goto handled;
+ }
+
+ if ((player_said_2(open, grate)) ||
+ (player_said_2(push, grate)) ||
+ (player_said_2(pull, grate))) {
+ switch (kernel.trigger) {
+ case (0):
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_bend_down_9] = kernel_seq_forward(ss[fx_bend_down_9], false,
+ 5, 0, 0, 1);
+ kernel_seq_range(seq[fx_bend_down_9], KERNEL_FIRST, KERNEL_LAST);
+ kernel_seq_player(seq[fx_bend_down_9], true);
+ kernel_seq_trigger(seq[fx_bend_down_9],
+ KERNEL_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 2:
+ seq[fx_bend_down_9] = kernel_seq_stamp
+ (ss[fx_bend_down_9], false, KERNEL_LAST);
+ kernel_seq_player(seq[fx_bend_down_9], true);
+ /* kernel_seq_depth (seq[fx_bend_down_9], 1); */
+ kernel_timing_trigger(HALF_SECOND, 3);
+ break;
+
+ case 3:
+ /* temp = seq[fx_bend_down_9]; */
+ kernel_seq_delete(seq[fx_bend_down_9]);
+ seq[fx_bend_down_9] = kernel_seq_backward(ss[fx_bend_down_9], false,
+ 5, 0, 0, 1);
+ /* kernel_synch (KERNEL_SERIES, seq[fx_bend_down_9], KERNEL_SERIES, temp); */
+ kernel_seq_range(seq[fx_bend_down_9], KERNEL_FIRST, KERNEL_LAST);
+ kernel_seq_player(seq[fx_bend_down_9], false);
+ kernel_seq_trigger(seq[fx_bend_down_9],
+ KERNEL_TRIGGER_EXPIRE, 0, 4);
+ break;
+
+ case 4:
+ player.walker_visible = true;
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_SERIES, seq[fx_bend_down_9]);
+ kernel_timing_trigger(TENTH_SECOND, 5);
+ break;
+
+ case 5:
+ player.commands_allowed = true;
+ text_show(text_409_18);
+ break;
+ }
+ goto handled;
+ }
+
+ if (player_said_2(talk_to, unlucky_adventurer)) {
+ text_show(text_409_24);
+ goto handled;
+ }
+
+ goto done;
+
+handled:
+ player.command_ready = false;
+
+done:
+ ;
+}
+
+void room_409_daemon() {
+ if (kernel.trigger == ROOM_409_DIE) {
+ player.walker_visible = false;
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_SERIES, seq[fx_gas]);
+ global_speech_go(speech_raoul_gas);
+ }
+
+ if (kernel.trigger == ROOM_409_DIE + 1) {
+ seq[fx_gas] = kernel_seq_stamp
+ (ss[fx_gas], false, KERNEL_LAST);
+ kernel_seq_depth(seq[fx_gas], 1);
+ kernel_timing_trigger(ONE_SECOND, ROOM_409_DIE + 2);
+ sound_play(N_PlayerDies);
+ }
+
+ if (kernel.trigger == ROOM_409_DIE + 2) {
+ kernel.force_restart = true;
+ }
+
+ if (kernel.trigger == ROOM_409_DOOR_OPENS) {
+ player.commands_allowed = true;
+ global[door_in_409_is_open] = true;
+ kernel_flip_hotspot(words_door, false);
+ kernel_flip_hotspot(words_archway_to_north, true);
+ }
+}
+
+void room_409_preload() {
+ room_init_code_pointer = room_409_init;
+ room_pre_parser_code_pointer = room_409_pre_parser;
+ room_parser_code_pointer = room_409_parser;
+ room_daemon_code_pointer = room_409_daemon;
+
+ section_4_walker();
+ section_4_interface();
+
+ vocab_make_active(words_red_frame);
+ vocab_make_active(words_yellow_frame);
+ vocab_make_active(words_blue_frame);
+ vocab_make_active(words_green_frame);
+}
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/rooms/room409.h b/engines/mads/madsv2/phantom/rooms/room409.h
new file mode 100644
index 00000000000..20f1b3a1db1
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room409.h
@@ -0,0 +1,96 @@
+/* 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 MADS_PHANTOM_ROOM409_H
+#define MADS_PHANTOM_ROOM409_H
+
+#include "mads/madsv2/core/general.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+#define local ((Scratch *)(&game.scratch[0]))
+#define ss local->sprite
+#define seq local->sequence
+#define aa local->animation
+
+typedef struct { /* Room local variables */
+
+ int16 sprite[15]; /* Sprite series handles */
+ int16 sequence[15]; /* Sequence handles */
+ int16 animation[4]; /* Animation handles */
+ int16 frame_is_here; /* T if any frame is here */
+ int16 dyn_red;
+ int16 dyn_green;
+ int16 dyn_blue;
+ int16 dyn_yellow;
+ int16 frame_here_for_taking; /* T if a specific frame is here */
+
+
+} Scratch;
+
+
+/* ========================= Sprite Series =================== */
+
+#define fx_bend_down_9 0 /* rrd_9 */
+#define fx_sword 1 /* rm409p0 */
+#define fx_red_frame 2 /* rm409f0 */
+#define fx_green_frame 3 /* rm409f1 */
+#define fx_blue_frame 4 /* rm409f2 */
+#define fx_yellow_frame 5 /* rm409f3 */
+#define fx_door 6 /* rm409x0 */
+#define fx_gas 7 /* rm409a0 */
+#define fx_take_9 8 /* rdr_9 */
+
+
+
+
+/* ======================== Triggers ========================= */
+
+#define ROOM_409_DIE 60
+#define ROOM_409_DOOR_OPENS 65
+
+
+/* ========================= Other Macros ==================== */
+
+#define NORTH_X 195
+#define NORTH_Y 92
+
+#define WALK_TO_NORTH_X 195
+#define WALK_TO_NORTH_Y 107
+
+#define SOUTH_X 184
+#define SOUTH_Y 145
+
+#define PANEL_X 229
+#define PANEL_Y 106
+
+#define DOOR_X 191
+#define DOOR_Y 104
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif // MADS_PHANTOM_ROOM250_H
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index 8e82bd9f11c..3c7914d7d10 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -163,6 +163,7 @@ MODULE_OBJS += \
madsv2/phantom/rooms/room406.o \
madsv2/phantom/rooms/room407.o \
madsv2/phantom/rooms/room408.o \
+ madsv2/phantom/rooms/room409.o \
madsv2/phantom/phantom.o \
madsv2/phantom/conv.o \
madsv2/phantom/global.o \
Commit: c5cd112150f94922dadb4c744010fcbca12abc83
https://github.com/scummvm/scummvm/commit/c5cd112150f94922dadb4c744010fcbca12abc83
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:51+10:00
Commit Message:
MADS: PHANTOM: Added room 410
Changed paths:
A engines/mads/madsv2/phantom/rooms/room410.cpp
A engines/mads/madsv2/phantom/rooms/room410.h
engines/mads/madsv2/phantom/mads/sounds.h
engines/mads/madsv2/phantom/mads/text.h
engines/mads/madsv2/phantom/mads/words.h
engines/mads/module.mk
diff --git a/engines/mads/madsv2/phantom/mads/sounds.h b/engines/mads/madsv2/phantom/mads/sounds.h
index cc0a0f55806..10447e6b0c8 100644
--- a/engines/mads/madsv2/phantom/mads/sounds.h
+++ b/engines/mads/madsv2/phantom/mads/sounds.h
@@ -53,7 +53,11 @@ enum {
N_WomanScream003 = 74,
N_Crash003 = 66,
- N_DoorHandle004 = 70
+ N_DoorHandle004 = 70,
+
+ N_LeverSnap = 65,
+ N_LeverBing = 66,
+ N_DoorGong = 67
};
} // namespace Phantom
diff --git a/engines/mads/madsv2/phantom/mads/text.h b/engines/mads/madsv2/phantom/mads/text.h
index e2decd19b59..dcb9a98ea49 100644
--- a/engines/mads/madsv2/phantom/mads/text.h
+++ b/engines/mads/madsv2/phantom/mads/text.h
@@ -843,7 +843,14 @@ enum {
text_409_20 = 40920,
text_409_21 = 40921,
text_409_23 = 40923,
- text_409_24 = 40924
+ text_409_24 = 40924,
+
+ /* Room 410 */
+ text_410_11 = 41011,
+ text_410_12 = 41012,
+ text_410_13 = 41013,
+ text_410_14 = 41014,
+ text_410_15 = 41015
};
} // namespace Phantom
diff --git a/engines/mads/madsv2/phantom/mads/words.h b/engines/mads/madsv2/phantom/mads/words.h
index 4e38b4482c0..476f72616ac 100644
--- a/engines/mads/madsv2/phantom/mads/words.h
+++ b/engines/mads/madsv2/phantom/mads/words.h
@@ -280,6 +280,7 @@ enum {
words_usher = 330,
words_unlucky_adventurer = 331,
words_switch_panel = 332,
+ words_catacomb_room = 335,
words_box_ten = 336,
words_walk_down_stairs_to = 339,
words_hat_rack = 340,
@@ -296,6 +297,32 @@ enum {
words_block = 353,
words_rat_s_nest = 354,
words_broken_pot = 355,
+ words_skull_switch_1 = 359,
+ words_skull_switch_2 = 360,
+ words_skull_switch_3 = 361,
+ words_skull_switch_4 = 362,
+ words_skull_switch_5 = 363,
+ words_skull_switch_6 = 364,
+ words_skull_switch_7 = 365,
+ words_skull_switch_8 = 366,
+ words_skull_switch_9 = 367,
+ words_skull_switch_10 = 368,
+ words_skull_switch_11 = 369,
+ words_skull_switch_12 = 370,
+ words_skull_switch_13 = 371,
+ words_skull_switch_14 = 372,
+ words_skull_switch_15 = 373,
+ words_skull_switch_16 = 374,
+ words_skull_switch_17 = 375,
+ words_skull_switch_18 = 376,
+ words_skull_switch_19 = 377,
+ words_skull_switch_20 = 378,
+ words_skull_switch_21 = 379,
+ words_skull_switch_22 = 380,
+ words_skull_switch_23 = 381,
+ words_skull_switch_24 = 382,
+ words_skull_switch_25 = 383,
+ words_skull_switch_26 = 384,
words_Edgar_Degas = 385,
words_chandelier_cable = 386,
words_boat = 389,
diff --git a/engines/mads/madsv2/phantom/rooms/room410.cpp b/engines/mads/madsv2/phantom/rooms/room410.cpp
new file mode 100644
index 00000000000..2714d084cf1
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room410.cpp
@@ -0,0 +1,439 @@
+/* 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 "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/camera.h"
+#include "mads/madsv2/core/inter.h"
+#include "mads/madsv2/core/matte.h"
+#include "mads/madsv2/core/object.h"
+#include "mads/madsv2/core/quote.h"
+#include "mads/madsv2/core/sound.h"
+#include "mads/madsv2/core/speech.h"
+#include "mads/madsv2/core/text.h"
+#include "mads/madsv2/phantom/mads/inventory.h"
+#include "mads/madsv2/phantom/mads/sounds.h"
+#include "mads/madsv2/phantom/mads/speeches.h"
+#include "mads/madsv2/phantom/rooms/section4.h"
+#include "mads/madsv2/phantom/rooms/room410.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+static void get_lever_coordinate_and_type(int *x, int *y, int *type, int lever_number, int *noun) {
+ /* x will return the x location for the stamping of skull */
+ /* y will return the y location for the stamping of skull */
+ /* type will return which type the skull is (1-3) */
+ /* lever_number (if known - only in init code) will help us find the x,y,type */
+ /* if lever_number is not known, noun will be passed a true value. When this happens
+ we will find out which lever was pushed, and that value will be passed back
+ thru noun */
+
+ if (noun != NULL) {
+ switch (player_main_noun) {
+ case words_skull_switch_1: lever_number = 1; break;
+ case words_skull_switch_2: lever_number = 2; break;
+ case words_skull_switch_3: lever_number = 3; break;
+ case words_skull_switch_4: lever_number = 4; break;
+ case words_skull_switch_5: lever_number = 5; break;
+ case words_skull_switch_6: lever_number = 6; break;
+ case words_skull_switch_7: lever_number = 7; break;
+ case words_skull_switch_8: lever_number = 8; break;
+ case words_skull_switch_9: lever_number = 9; break;
+ case words_skull_switch_10: lever_number = 10; break;
+ case words_skull_switch_11: lever_number = 11; break;
+ case words_skull_switch_12: lever_number = 12; break;
+ case words_skull_switch_13: lever_number = 13; break;
+ case words_skull_switch_14: lever_number = 14; break;
+ case words_skull_switch_15: lever_number = 15; break;
+ case words_skull_switch_16: lever_number = 16; break;
+ case words_skull_switch_17: lever_number = 17; break;
+ case words_skull_switch_18: lever_number = 18; break;
+ case words_skull_switch_19: lever_number = 19; break;
+ case words_skull_switch_20: lever_number = 20; break;
+ case words_skull_switch_21: lever_number = 21; break;
+ case words_skull_switch_22: lever_number = 22; break;
+ case words_skull_switch_23: lever_number = 23; break;
+ case words_skull_switch_24: lever_number = 24; break;
+ case words_skull_switch_25: lever_number = 25; break;
+ case words_skull_switch_26: lever_number = 26; break;
+ }
+ *noun = lever_number;
+ }
+
+ switch (lever_number) { /* 1 - 26 */
+ case 1: *x = 124; *y = 46; *type = 3; break;
+ case 2: *x = 143; *y = 46; *type = 2; break;
+ case 3: *x = 162; *y = 46; *type = 1; break;
+ case 4: *x = 181; *y = 46; *type = 3; break;
+ case 5: *x = 200; *y = 46; *type = 1; break;
+ case 6: *x = 219; *y = 46; *type = 2; break;
+ case 7: *x = 238; *y = 46; *type = 1; break;
+ case 8: *x = 133; *y = 71; *type = 3; break;
+ case 9: *x = 152; *y = 71; *type = 2; break;
+ case 10: *x = 171; *y = 71; *type = 1; break;
+ case 11: *x = 190; *y = 71; *type = 3; break;
+ case 12: *x = 209; *y = 71; *type = 2; break;
+ case 13: *x = 228; *y = 71; *type = 1; break;
+ case 14: *x = 124; *y = 98; *type = 1; break;
+ case 15: *x = 143; *y = 98; *type = 3; break;
+ case 16: *x = 162; *y = 98; *type = 2; break;
+ case 17: *x = 181; *y = 98; *type = 1; break;
+ case 18: *x = 200; *y = 98; *type = 1; break;
+ case 19: *x = 219; *y = 98; *type = 2; break;
+ case 20: *x = 238; *y = 98; *type = 1; break;
+ case 21: *x = 133; *y = 125; *type = 3; break;
+ case 22: *x = 152; *y = 125; *type = 1; break;
+ case 23: *x = 171; *y = 125; *type = 3; break;
+ case 24: *x = 190; *y = 125; *type = 2; break;
+ case 25: *x = 209; *y = 125; *type = 1; break;
+ case 26: *x = 228; *y = 125; *type = 2; break;
+ }
+}
+
+void room_410_init() {
+ int x;
+ int y;
+ int type;
+ int count;
+ int ss_type = 0; /* which skull are we going to stamp */
+
+ player.walker_visible = false;
+
+ /* ===================== Load Sprite Series ================== */
+
+ ss[fx_skull_0] = kernel_load_series(kernel_name('l', 0), false);
+ ss[fx_skull_1] = kernel_load_series(kernel_name('l', 1), false);
+ ss[fx_skull_2] = kernel_load_series(kernel_name('l', 2), false);
+ ss[fx_hand] = kernel_load_series(kernel_name('a', 0), false);
+ ss[fx_alphabet] = kernel_load_series(kernel_name('f', 0), false);
+
+
+ /* ========================= Previous Rooms ================== */
+
+
+ for (count = 1; count < 27; count++) {
+ get_lever_coordinate_and_type(&x, &y, &type, count, NULL);
+
+ switch (type) {
+ case 1: ss_type = ss[fx_skull_0]; break;
+ case 2: ss_type = ss[fx_skull_1]; break;
+ case 3: ss_type = ss[fx_skull_2]; break;
+ }
+
+ seq[fx_skull_0] = kernel_seq_stamp(ss_type, false, 1);
+ kernel_seq_loc(seq[fx_skull_0], x, y);
+ kernel_seq_depth(seq[fx_skull_0], 2);
+ skull_seq.num[count - 1] = seq[fx_skull_0];
+ /* save the handle for later deletion */
+ }
+
+ /* if (previous_room == KERNEL_RESTORING_GAME) { */
+ if (global[flicked_1]) {
+ get_lever_coordinate_and_type(&x, &y, &type, global[flicked_1], NULL);
+ switch (type) {
+ case 1: ss_type = ss[fx_skull_0]; break;
+ case 2: ss_type = ss[fx_skull_1]; break;
+ case 3: ss_type = ss[fx_skull_2]; break;
+ }
+ kernel_seq_delete(skull_seq.num[global[flicked_1] - 1]);
+ seq[fx_skull_0] = kernel_seq_stamp
+ (ss_type, false, KERNEL_LAST);
+ kernel_seq_loc(seq[fx_skull_0], x, y);
+ kernel_seq_depth(seq[fx_skull_0], 2);
+ }
+
+ if (global[flicked_2]) {
+ get_lever_coordinate_and_type(&x, &y, &type, global[flicked_2], NULL);
+ switch (type) {
+ case 1: ss_type = ss[fx_skull_0]; break;
+ case 2: ss_type = ss[fx_skull_1]; break;
+ case 3: ss_type = ss[fx_skull_2]; break;
+ }
+ kernel_seq_delete(skull_seq.num[global[flicked_2] - 1]);
+ seq[fx_skull_0] = kernel_seq_stamp
+ (ss_type, false, KERNEL_LAST);
+ kernel_seq_loc(seq[fx_skull_0], x, y);
+ kernel_seq_depth(seq[fx_skull_0], 2);
+ }
+
+ if (global[flicked_3]) {
+ get_lever_coordinate_and_type(&x, &y, &type, global[flicked_3], NULL);
+ switch (type) {
+ case 1: ss_type = ss[fx_skull_0]; break;
+ case 2: ss_type = ss[fx_skull_1]; break;
+ case 3: ss_type = ss[fx_skull_2]; break;
+ }
+ kernel_seq_delete(skull_seq.num[global[flicked_3] - 1]);
+ seq[fx_skull_0] = kernel_seq_stamp
+ (ss_type, false, KERNEL_LAST);
+ kernel_seq_loc(seq[fx_skull_0], x, y);
+ kernel_seq_depth(seq[fx_skull_0], 2);
+ }
+
+ if (global[flicked_4]) {
+ get_lever_coordinate_and_type(&x, &y, &type, global[flicked_4], NULL);
+ switch (type) {
+ case 1: ss_type = ss[fx_skull_0]; break;
+ case 2: ss_type = ss[fx_skull_1]; break;
+ case 3: ss_type = ss[fx_skull_2]; break;
+ }
+ kernel_seq_delete(skull_seq.num[global[flicked_4] - 1]);
+ seq[fx_skull_0] = kernel_seq_stamp
+ (ss_type, false, KERNEL_LAST);
+ kernel_seq_loc(seq[fx_skull_0], x, y);
+ kernel_seq_depth(seq[fx_skull_0], 2);
+ }
+
+ section_4_music();
+}
+
+void room_410_parser() {
+ int x;
+ int y;
+ int type;
+ int number;
+
+ if (player.look_around) {
+ text_show(text_410_13);
+ goto handled;
+ }
+
+ if (player_said_1(push) || player_said_1(pull)) {
+ if (global[door_in_409_is_open]) {
+ text_show(text_410_14);
+ goto handled;
+
+ } else {
+ switch (kernel.trigger) {
+ case 0:
+ player.commands_allowed = false;
+ get_lever_coordinate_and_type(&x, &y, &type, 0, &number);
+ seq[fx_hand] = kernel_seq_pingpong(ss[fx_hand], false, 4, 0, 0, 2);
+ kernel_seq_depth(seq[fx_hand], 1);
+ kernel_seq_range(seq[fx_hand], KERNEL_FIRST, KERNEL_LAST);
+ if (y == 46) {
+ y = 48; /* If y == 46 (push a top row button), then you will see thru
+ the hand just above the interface (the sprite is not tall enough) */
+ }
+ kernel_seq_loc(seq[fx_hand], x + 4, y + 107);
+ if (!global[door_in_409_is_open]) {
+ kernel_seq_trigger(seq[fx_hand],
+ KERNEL_TRIGGER_SPRITE, 16, 1);
+ }
+ kernel_seq_trigger(seq[fx_hand],
+ KERNEL_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ get_lever_coordinate_and_type(&x, &y, &type, 0, &number);
+
+ if ((global[flicked_1] != number) && (global[flicked_2] != number) &&
+ (global[flicked_3] != number) && (global[flicked_4] != number)) {
+
+ sound_play(N_LeverSnap);
+
+ if (!global[flicked_1]) {
+ global[flicked_1] = number;
+ if (global[flicked_1] == 5) {
+ sound_play(N_LeverBing);
+ }
+
+ } else if (!global[flicked_2]) {
+ global[flicked_2] = number;
+ if ((global[flicked_1] == 5) && (global[flicked_2] == 18)) {
+ sound_play(N_LeverBing);
+ }
+
+ } else if (!global[flicked_3]) {
+ global[flicked_3] = number;
+ if ((global[flicked_1] == 5) && (global[flicked_2] == 18) &&
+ (global[flicked_3] == 9)) {
+ sound_play(N_LeverBing);
+ }
+
+ } else if (!global[flicked_4]) {
+ global[flicked_4] = number;
+ if ((global[flicked_1] == 5) && (global[flicked_2] == 18) &&
+ (global[flicked_3] == 9) && (global[flicked_4] == 11)) {
+ sound_play(N_LeverBing);
+ }
+ }
+
+ if (game.difficulty == EASY_MODE) {
+ kernel_draw_to_background(ss[fx_alphabet], number, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ }
+
+ switch (type) {
+ case 1:
+ kernel_seq_delete(skull_seq.num[number - 1]);
+ seq[fx_skull_0] = kernel_seq_forward(ss[fx_skull_0], false, 4, 0, 0, 1);
+ kernel_seq_depth(seq[fx_skull_0], 2);
+ kernel_seq_range(seq[fx_skull_0], KERNEL_FIRST, KERNEL_LAST);
+ kernel_seq_trigger(seq[fx_skull_0], KERNEL_TRIGGER_EXPIRE, 0, 4);
+ kernel_seq_loc(seq[fx_skull_0], x, y);
+ break;
+
+ case 2:
+ kernel_seq_delete(skull_seq.num[number - 1]);
+ seq[fx_skull_1] = kernel_seq_forward(ss[fx_skull_1], false, 4, 0, 0, 1);
+ kernel_seq_depth(seq[fx_skull_1], 2);
+ kernel_seq_range(seq[fx_skull_1], KERNEL_FIRST, KERNEL_LAST);
+ kernel_seq_trigger(seq[fx_skull_1], KERNEL_TRIGGER_EXPIRE, 0, 4);
+ kernel_seq_loc(seq[fx_skull_1], x, y);
+ break;
+
+ case 3:
+ kernel_seq_delete(skull_seq.num[number - 1]);
+ seq[fx_skull_2] = kernel_seq_forward(ss[fx_skull_2], false, 4, 0, 0, 1);
+ kernel_seq_depth(seq[fx_skull_2], 2);
+ kernel_seq_range(seq[fx_skull_2], KERNEL_FIRST, KERNEL_LAST);
+ kernel_seq_trigger(seq[fx_skull_2], KERNEL_TRIGGER_EXPIRE, 0, 4);
+ kernel_seq_loc(seq[fx_skull_2], x, y);
+ break;
+ }
+ }
+ break;
+
+ case 2:
+ player.commands_allowed = true;
+
+ if ((global[flicked_1] == 5) && (global[flicked_2] == 18) &&
+ (global[flicked_3] == 9) && (global[flicked_4] == 11)) {
+ if (!global[door_in_409_is_open]) {
+ sound_play(N_DoorGong);
+ }
+ } /* a 'gong' sound if player was successfull */
+
+ if (global[flicked_1] && global[flicked_2] &&
+ global[flicked_3] && global[flicked_4]) {
+ new_room = 409;
+ } /* no matter which 4 levers are pulled, goto 409 */
+ break;
+
+ case 4:
+ get_lever_coordinate_and_type(&x, &y, &type, 0, &number);
+ seq[fx_skull_0] = kernel_seq_stamp
+ (ss[fx_skull_0], false, KERNEL_LAST);
+ kernel_seq_depth(seq[fx_skull_0], 2);
+ kernel_seq_loc(seq[fx_skull_0], x, y);
+ break;
+
+ case 5:
+ get_lever_coordinate_and_type(&x, &y, &type, 0, &number);
+ seq[fx_skull_1] = kernel_seq_stamp
+ (ss[fx_skull_1], false, KERNEL_LAST);
+ kernel_seq_depth(seq[fx_skull_1], 2);
+ kernel_seq_loc(seq[fx_skull_1], x, y);
+ break;
+
+ case 6:
+ get_lever_coordinate_and_type(&x, &y, &type, 0, &number);
+ seq[fx_skull_2] = kernel_seq_stamp
+ (ss[fx_skull_2], false, KERNEL_LAST);
+ kernel_seq_depth(seq[fx_skull_2], 2);
+ kernel_seq_loc(seq[fx_skull_2], x, y);
+ break;
+ }
+ }
+ goto handled;
+ }
+
+ if (player_said_1(look) || player_said_1(look_at)) {
+
+ if (player_said_1(wall)) {
+ text_show(text_410_11);
+ goto handled;
+ }
+
+ if (player_said_1(switch_panel)) {
+ text_show(text_410_11);
+ goto handled;
+ }
+
+ if (player_said_1(catacomb_room)) {
+ text_show(text_410_15);
+ goto handled;
+ }
+
+ switch (player_main_noun) {
+ case words_skull_switch_1:
+ case words_skull_switch_2:
+ case words_skull_switch_3:
+ case words_skull_switch_4:
+ case words_skull_switch_5:
+ case words_skull_switch_6:
+ case words_skull_switch_7:
+ case words_skull_switch_8:
+ case words_skull_switch_9:
+ case words_skull_switch_10:
+ case words_skull_switch_11:
+ case words_skull_switch_12:
+ case words_skull_switch_13:
+ case words_skull_switch_14:
+ case words_skull_switch_15:
+ case words_skull_switch_16:
+ case words_skull_switch_17:
+ case words_skull_switch_18:
+ case words_skull_switch_19:
+ case words_skull_switch_20:
+ case words_skull_switch_21:
+ case words_skull_switch_22:
+ case words_skull_switch_23:
+ case words_skull_switch_24:
+ case words_skull_switch_25:
+ case words_skull_switch_26:
+ text_show(text_410_12);
+ goto handled;
+ break;
+ }
+ }
+
+ if (player_said_2(exit_to, catacomb_room)) {
+ new_room = 409;
+ goto handled;
+ }
+
+ goto done;
+
+handled:
+ player.command_ready = false;
+
+done:
+ ;
+}
+
+void room_410_preload() {
+ room_init_code_pointer = room_410_init;
+ room_pre_parser_code_pointer = NULL;
+ room_parser_code_pointer = room_410_parser;
+ room_daemon_code_pointer = NULL;
+
+ section_4_walker();
+ section_4_interface();
+}
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/rooms/room410.h b/engines/mads/madsv2/phantom/rooms/room410.h
new file mode 100644
index 00000000000..588c998bd39
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room410.h
@@ -0,0 +1,67 @@
+/* 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 MADS_PHANTOM_ROOM410_H
+#define MADS_PHANTOM_ROOM410_H
+
+#include "mads/madsv2/core/general.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+#define local ((Scratch *)(&game.scratch[0]))
+#define ss local->sprite
+#define seq local->sequence
+#define aa local->animation
+
+struct {
+ int16 num[26];
+} skull_seq;
+
+/* this contains the handles returned from stamping
+ skull down in Init code for later deletion in Parser
+ (when the lever is flipped) */
+
+
+typedef struct { /* Room local variables */
+
+ int16 sprite[15]; /* Sprite series handles */
+ int16 sequence[15]; /* Sequence handles */
+ int16 animation[4]; /* Animation handles */
+
+} Scratch;
+
+/* ========================= Sprite Series =================== */
+
+#define fx_skull_0 0 /* rm410l0 */
+#define fx_skull_1 1 /* rm410l1 */
+#define fx_skull_2 2 /* rm410l2 */
+#define fx_hand 3 /* rm410a0 */
+#define fx_alphabet 4 /* rm410f0 */
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif // MADS_PHANTOM_ROOM250_H
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index 3c7914d7d10..f1fb3ed9762 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -164,6 +164,7 @@ MODULE_OBJS += \
madsv2/phantom/rooms/room407.o \
madsv2/phantom/rooms/room408.o \
madsv2/phantom/rooms/room409.o \
+ madsv2/phantom/rooms/room410.o \
madsv2/phantom/phantom.o \
madsv2/phantom/conv.o \
madsv2/phantom/global.o \
Commit: 93e5b9875b39aedbe1fce6f4d0f4ae82aac4fe34
https://github.com/scummvm/scummvm/commit/93e5b9875b39aedbe1fce6f4d0f4ae82aac4fe34
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:51+10:00
Commit Message:
MADS: PHANTOM: Added room 453
Changed paths:
A engines/mads/madsv2/phantom/rooms/room453.cpp
A engines/mads/madsv2/phantom/rooms/room453.h
engines/mads/madsv2/phantom/mads/text.h
engines/mads/madsv2/phantom/mads/words.h
engines/mads/module.mk
diff --git a/engines/mads/madsv2/phantom/mads/text.h b/engines/mads/madsv2/phantom/mads/text.h
index dcb9a98ea49..384d746705b 100644
--- a/engines/mads/madsv2/phantom/mads/text.h
+++ b/engines/mads/madsv2/phantom/mads/text.h
@@ -850,7 +850,24 @@ enum {
text_410_12 = 41012,
text_410_13 = 41013,
text_410_14 = 41014,
- text_410_15 = 41015
+ text_410_15 = 41015,
+
+ /* Room 453 */
+ text_453_10 = 45310,
+ text_453_11 = 45311,
+ text_453_12 = 45312,
+ text_453_13 = 45313,
+ text_453_14 = 45314,
+ text_453_15 = 45315,
+ text_453_17 = 45317,
+ text_453_18 = 45318,
+ text_453_19 = 45319,
+ text_453_24 = 45324,
+ text_453_25 = 45325,
+ text_453_26 = 45326,
+ text_453_27 = 45327,
+ text_453_28 = 45328,
+ text_453_29 = 45329
};
} // namespace Phantom
diff --git a/engines/mads/madsv2/phantom/mads/words.h b/engines/mads/madsv2/phantom/mads/words.h
index 476f72616ac..2891eb40f69 100644
--- a/engines/mads/madsv2/phantom/mads/words.h
+++ b/engines/mads/madsv2/phantom/mads/words.h
@@ -271,6 +271,7 @@ enum {
words_Julie = 303,
words_cable_hook = 304,
words_skull = 316,
+ words_drain = 317,
words_Madame_Giry = 323,
words_more_catacombs = 325,
words_blocked_archway = 326,
@@ -297,6 +298,7 @@ enum {
words_block = 353,
words_rat_s_nest = 354,
words_broken_pot = 355,
+ words_stone = 356,
words_skull_switch_1 = 359,
words_skull_switch_2 = 360,
words_skull_switch_3 = 361,
diff --git a/engines/mads/madsv2/phantom/rooms/room453.cpp b/engines/mads/madsv2/phantom/rooms/room453.cpp
new file mode 100644
index 00000000000..6cb5a6af4ca
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room453.cpp
@@ -0,0 +1,532 @@
+/* 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 "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/camera.h"
+#include "mads/madsv2/core/inter.h"
+#include "mads/madsv2/core/matte.h"
+#include "mads/madsv2/core/object.h"
+#include "mads/madsv2/core/sound.h"
+#include "mads/madsv2/core/text.h"
+#include "mads/madsv2/phantom/mads/inventory.h"
+#include "mads/madsv2/phantom/mads/quotes.h"
+#include "mads/madsv2/phantom/mads/sounds.h"
+#include "mads/madsv2/phantom/rooms/section4.h"
+#include "mads/madsv2/phantom/rooms/room453.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+void room_453_init() {
+ global_catacombs_init();
+
+ kernel_flip_hotspot(words_skull, false);
+ kernel_flip_hotspot(words_drain, false);
+ kernel_flip_hotspot(words_rat_s_nest, false);
+ kernel_flip_hotspot(words_web, false);
+ kernel_flip_hotspot(words_stone, false);
+ kernel_flip_hotspot(words_hole, false);
+ kernel_flip_hotspot(words_gate, false);
+
+ /* =================== Load sprites series =================== */
+
+ ss[fx_bend_down_9] = kernel_load_series("*RRD_9", false);
+ ss[fx_red_frame] = kernel_load_series(kernel_name('f', 0), false);
+ ss[fx_green_frame] = kernel_load_series(kernel_name('f', 1), false);
+ ss[fx_blue_frame] = kernel_load_series(kernel_name('f', 2), false);
+ ss[fx_yellow_frame] = kernel_load_series(kernel_name('f', 3), false);
+
+
+ if (global_catacombs_exit(NORTH) == -1) {
+ ss[fx_north] = kernel_load_series(kernel_name('c', 1), false);
+ kernel_draw_to_background(ss[fx_north], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ kernel_flip_hotspot(words_archway_to_north, false);
+ }
+
+ if (global_catacombs_exit(WEST) == -1) {
+ ss[fx_gate] = kernel_load_series(kernel_name('c', 8), false);
+ kernel_draw_to_background(ss[fx_gate], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ kernel_flip_hotspot(words_more_catacombs, false);
+ kernel_flip_hotspot(words_gate, true);
+ }
+
+ if (global_catacombs_exit(EAST) == -1) {
+ ss[fx_east] = kernel_load_series(kernel_name('c', 2), false);
+ kernel_draw_to_background(ss[fx_east], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ kernel_flip_hotspot(words_archway_to_east, false);
+ }
+
+
+ if (global[catacombs_misc] & MAZE_DRAIN) {
+ ss[fx_drain] = kernel_load_series(kernel_name('c', 3), false);
+ kernel_draw_to_background(ss[fx_drain], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ kernel_flip_hotspot(words_drain, true);
+ }
+
+ if (global[catacombs_misc] & MAZE_RAT_NEST) {
+ ss[fx_rat_nest] = kernel_load_series(kernel_name('c', 4), false);
+ kernel_draw_to_background(ss[fx_rat_nest], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ kernel_flip_hotspot(words_skull, true);
+ kernel_flip_hotspot(words_rat_s_nest, true);
+ }
+
+ if (global[catacombs_misc] & MAZE_WEB) {
+ ss[fx_web] = kernel_load_series(kernel_name('c', 5), false);
+ kernel_draw_to_background(ss[fx_web], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ kernel_flip_hotspot(words_web, true);
+ }
+
+ if (global[catacombs_misc] & MAZE_BRICK) {
+ ss[fx_brick] = kernel_load_series(kernel_name('c', 6), false);
+ kernel_draw_to_background(ss[fx_brick], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ kernel_flip_hotspot_loc(words_exposed_brick, false, BRICK_1_X, BRICK_1_Y);
+ kernel_flip_hotspot_loc(words_exposed_brick, false, BRICK_2_X, BRICK_2_Y);
+ }
+
+ if (global[catacombs_misc] & MAZE_STONE) {
+ ss[fx_stone] = kernel_load_series(kernel_name('c', 7), false);
+ kernel_draw_to_background(ss[fx_stone], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ kernel_flip_hotspot(words_hole, true);
+ kernel_flip_hotspot(words_stone, true);
+ }
+
+
+ if (previous_room != KERNEL_RESTORING_GAME) {
+
+ switch (global[catacombs_from]) {
+
+ case NORTH:
+ player.x = NORTH_X;
+ player.y = NORTH_Y;
+ player.facing = FACING_SOUTH;
+ player_walk(WALK_TO_NORTH_X, WALK_TO_NORTH_Y, FACING_SOUTH);
+ break;
+
+ case EAST:
+ player.x = EAST_X;
+ player.y = EAST_Y;
+ player.facing = FACING_WEST;
+ player_walk(WALK_TO_EAST_X, WALK_TO_EAST_Y, FACING_WEST);
+ break;
+
+ case WEST:
+ player_first_walk(WEST_X, WEST_Y, FACING_EAST, WALK_TO_WEST_X, WALK_TO_WEST_Y, FACING_EAST, true);
+ break;
+ }
+ }
+
+ if (object[red_frame].location == global[catacombs_room] + 600) {
+ seq[fx_red_frame] = kernel_seq_stamp(ss[fx_red_frame], false, 1);
+ kernel_seq_depth(seq[fx_red_frame], 14);
+ local->dyn_red = kernel_add_dynamic(words_red_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5,
+ series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_red, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+
+ if (object[green_frame].location == global[catacombs_room] + 600) {
+ seq[fx_green_frame] = kernel_seq_stamp(ss[fx_green_frame], false, 1);
+ kernel_seq_depth(seq[fx_green_frame], 14);
+ local->dyn_green = kernel_add_dynamic(words_green_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5,
+ series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_green, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+
+ if (object[blue_frame].location == global[catacombs_room] + 600) {
+ seq[fx_blue_frame] = kernel_seq_stamp(ss[fx_blue_frame], false, 1);
+ kernel_seq_depth(seq[fx_blue_frame], 14);
+ local->dyn_blue = kernel_add_dynamic(words_blue_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5,
+ series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_blue, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+
+ if (object[yellow_frame].location == global[catacombs_room] + 600) {
+ seq[fx_yellow_frame] = kernel_seq_stamp(ss[fx_yellow_frame], false, 1);
+ kernel_seq_depth(seq[fx_yellow_frame], 14);
+ local->dyn_yellow = kernel_add_dynamic(words_yellow_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5,
+ series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_yellow, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+ section_4_music();
+}
+
+
+void room_453_pre_parser() {
+ if (player_said_2(exit_to, more_catacombs)) {
+ global_catacombs_move(WEST);
+ }
+
+ local->frame_is_here = false;
+ local->frame_here_for_taking = false;
+
+ if (object[red_frame].location == global[catacombs_room] + 600) {
+ local->frame_is_here = true;
+ if (player_said_2(take, red_frame)) {
+ local->frame_here_for_taking = true;
+ }
+ }
+
+ if (object[yellow_frame].location == global[catacombs_room] + 600) {
+ local->frame_is_here = true;
+ if (player_said_2(take, yellow_frame)) {
+ local->frame_here_for_taking = true;
+ }
+ }
+
+ if (object[blue_frame].location == global[catacombs_room] + 600) {
+ local->frame_is_here = true;
+ if (player_said_2(take, blue_frame)) {
+ local->frame_here_for_taking = true;
+ }
+ }
+
+ if (object[green_frame].location == global[catacombs_room] + 600) {
+ local->frame_is_here = true;
+ if (player_said_2(take, green_frame)) {
+ local->frame_here_for_taking = true;
+ }
+ }
+
+ if (player_said_1(put) && player_said_1(floor)) {
+ if (player_said_1(red_frame) ||
+ player_said_1(blue_frame) ||
+ player_said_1(yellow_frame) ||
+ player_said_1(green_frame)) {
+ if (local->frame_is_here) {
+ player.need_to_walk = false;
+
+ } else {
+ player_walk(series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+ }
+ }
+}
+
+void room_453_parser() {
+ if (player_said_1(put) && player_said_1(floor)) {
+ if (player_said_1(red_frame) ||
+ player_said_1(blue_frame) ||
+ player_said_1(yellow_frame) ||
+ player_said_1(green_frame)) {
+ if (local->frame_is_here) {
+ text_show(text_000_29);
+ goto handled;
+
+ } else {
+
+ switch (kernel.trigger) {
+ case (0):
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_bend_down_9] = kernel_seq_pingpong(ss[fx_bend_down_9], true,
+ 5, 0, 0, 2);
+ kernel_seq_range(seq[fx_bend_down_9], 1, 5);
+ kernel_seq_player(seq[fx_bend_down_9], true);
+ kernel_seq_trigger(seq[fx_bend_down_9],
+ KERNEL_TRIGGER_SPRITE, 5, 1);
+ kernel_seq_trigger(seq[fx_bend_down_9],
+ KERNEL_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ if (player_said_1(red_frame)) {
+ inter_move_object(red_frame, NOWHERE);
+ object[red_frame].location = global[catacombs_room] + 600;
+ seq[fx_red_frame] = kernel_seq_stamp(ss[fx_red_frame], false, 1);
+ kernel_seq_depth(seq[fx_red_frame], 14);
+ local->dyn_red = kernel_add_dynamic(words_red_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5, series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_red, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+
+ if (player_said_1(green_frame)) {
+ inter_move_object(green_frame, NOWHERE);
+ object[green_frame].location = global[catacombs_room] + 600;
+ seq[fx_green_frame] = kernel_seq_stamp(ss[fx_green_frame], false, 1);
+ kernel_seq_depth(seq[fx_green_frame], 14);
+ local->dyn_green = kernel_add_dynamic(words_green_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5, series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_green, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+
+ if (player_said_1(blue_frame)) {
+ inter_move_object(blue_frame, NOWHERE);
+ object[blue_frame].location = global[catacombs_room] + 600;
+ seq[fx_blue_frame] = kernel_seq_stamp(ss[fx_blue_frame], false, 1);
+ kernel_seq_depth(seq[fx_blue_frame], 14);
+ local->dyn_blue = kernel_add_dynamic(words_blue_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5, series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_blue, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+
+ if (player_said_1(yellow_frame)) {
+ inter_move_object(yellow_frame, NOWHERE);
+ object[yellow_frame].location = global[catacombs_room] + 600;
+ seq[fx_yellow_frame] = kernel_seq_stamp(ss[fx_yellow_frame], false, 1);
+ kernel_seq_depth(seq[fx_yellow_frame], 14);
+ local->dyn_yellow = kernel_add_dynamic(words_yellow_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5, series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_yellow, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+ break;
+
+ case 2:
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_SERIES, seq[fx_bend_down_9]);
+ player.walker_visible = true;
+ player.commands_allowed = true;
+ break;
+ }
+ goto handled;
+ }
+ }
+ }
+
+ if (player_said_1(take)) {
+ if (player_said_1(red_frame) || player_said_1(green_frame) ||
+ player_said_1(blue_frame) || player_said_1(yellow_frame)) {
+
+ if ((local->frame_here_for_taking || kernel.trigger)) {
+ switch (kernel.trigger) {
+ case (0):
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_bend_down_9] = kernel_seq_pingpong(ss[fx_bend_down_9], true,
+ 5, 0, 0, 2);
+ kernel_seq_range(seq[fx_bend_down_9], 1, 5);
+ kernel_seq_player(seq[fx_bend_down_9], true);
+ kernel_seq_trigger(seq[fx_bend_down_9],
+ KERNEL_TRIGGER_SPRITE, 5, 1);
+ kernel_seq_trigger(seq[fx_bend_down_9],
+ KERNEL_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ if (player_said_1(red_frame)) {
+ kernel_seq_delete(seq[fx_red_frame]);
+ kernel_delete_dynamic(local->dyn_red);
+ inter_give_to_player(red_frame);
+ }
+
+ if (player_said_1(green_frame)) {
+ kernel_seq_delete(seq[fx_green_frame]);
+ kernel_delete_dynamic(local->dyn_green);
+ inter_give_to_player(green_frame);
+ }
+
+ if (player_said_1(blue_frame)) {
+ kernel_seq_delete(seq[fx_blue_frame]);
+ kernel_delete_dynamic(local->dyn_blue);
+ inter_give_to_player(blue_frame);
+ }
+
+ if (player_said_1(yellow_frame)) {
+ kernel_seq_delete(seq[fx_yellow_frame]);
+ kernel_delete_dynamic(local->dyn_yellow);
+ inter_give_to_player(yellow_frame);
+ }
+
+ sound_play(N_TakeObjectSnd);
+ break;
+
+ case 2:
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_SERIES, seq[fx_bend_down_9]);
+ player.walker_visible = true;
+ player.commands_allowed = true;
+ break;
+ }
+ goto handled;
+ }
+ }
+ }
+
+ if (player_said_2(walk_through, archway_to_north)) {
+ global_catacombs_move(NORTH);
+ goto handled;
+ }
+
+ if (player_said_2(walk_through, archway_to_east)) {
+ global_catacombs_move(EAST);
+ goto handled;
+ }
+
+ if (player.look_around) {
+ text_show(text_453_10);
+ goto handled;
+ }
+
+ if (player_said_1(look) || player_said_1(look_at)) {
+
+ if (player_said_1(wall)) {
+ text_show(text_453_11);
+ goto handled;
+ }
+
+ if (player_said_1(floor)) {
+ text_show(text_453_12);
+ goto handled;
+ }
+
+ if (player_said_1(archway)) {
+ text_show(text_453_13);
+ goto handled;
+ }
+
+ if (player_said_1(exposed_brick)) {
+ text_show(text_453_14);
+ goto handled;
+ }
+
+ if (player_said_1(hole)) {
+ text_show(text_453_17);
+ goto handled;
+ }
+
+ if (player_said_1(skull)) {
+ text_show(text_453_18);
+ goto handled;
+ }
+
+ if (player_said_1(web)) {
+ text_show(text_453_24);
+ goto handled;
+ }
+
+ if (player_said_1(rat_s_nest)) {
+ text_show(text_453_25);
+ goto handled;
+ }
+
+ if (player_said_1(drain)) {
+ text_show(text_453_27);
+ goto handled;
+ }
+
+ if (player_said_1(stone)) {
+ text_show(text_453_28);
+ goto handled;
+ }
+
+ if (player_said_1(red_frame)) {
+ if (!player_has(red_frame)) {
+ object_examine(red_frame, text_008_02, 0);
+ goto handled;
+ }
+ }
+
+ if (player_said_1(green_frame)) {
+ if (!player_has(green_frame)) {
+ object_examine(green_frame, text_008_19, 0);
+ goto handled;
+ }
+ }
+
+ if (player_said_1(blue_frame)) {
+ if (!player_has(blue_frame)) {
+ object_examine(blue_frame, text_008_17, 0);
+ goto handled;
+ }
+ }
+
+ if (player_said_1(yellow_frame)) {
+ if (!player_has(yellow_frame)) {
+ object_examine(yellow_frame, text_008_04, 0);
+ goto handled;
+ }
+ }
+
+ if (player_said_1(more_catacombs)) {
+ text_show(text_453_15);
+ goto handled;
+ }
+
+ if (player_said_1(gate)) {
+ text_show(text_453_30);
+ goto handled;
+ }
+ }
+
+ if (player_said_2(take, skull)) {
+ text_show(text_453_19);
+ goto handled;
+ }
+
+ if (player_said_2(open, gate)) {
+ text_show(text_453_31);
+ goto handled;
+ }
+
+ if (player_said_2(take, rat_s_nest)) {
+ text_show(text_453_26);
+ goto handled;
+ }
+
+ if (player_said_2(take, stone)) {
+ text_show(text_453_29);
+ goto handled;
+ }
+
+ goto done;
+
+handled:
+ player.command_ready = false;
+
+done:
+ ;
+}
+
+void room_453_preload() {
+ room_init_code_pointer = room_453_init;
+ room_pre_parser_code_pointer = room_453_pre_parser;
+ room_parser_code_pointer = room_453_parser;
+ room_daemon_code_pointer = NULL;
+
+ section_4_walker();
+ section_4_interface();
+
+ if (global[catacombs_misc] & MAZE_STONE) {
+ kernel_initial_variant = 1;
+ }
+
+ vocab_make_active(words_red_frame);
+ vocab_make_active(words_yellow_frame);
+ vocab_make_active(words_blue_frame);
+ vocab_make_active(words_green_frame);
+}
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/rooms/room453.h b/engines/mads/madsv2/phantom/rooms/room453.h
new file mode 100644
index 00000000000..bec249144d0
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room453.h
@@ -0,0 +1,110 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef MADS_PHANTOM_ROOM453_H
+#define MADS_PHANTOM_ROOM453_H
+
+#include "mads/madsv2/core/general.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+#define local ((Scratch *)(&game.scratch[0]))
+#define ss local->sprite
+#define seq local->sequence
+#define aa local->animation
+
+typedef struct { /* Room local variables */
+
+ int16 sprite[15]; /* Sprite series handles */
+ int16 sequence[15]; /* Sequence handles */
+ int16 animation[4]; /* Animation handles */
+ int16 frame_is_here; /* T if any frame is here */
+ int16 dyn_red;
+ int16 dyn_green;
+ int16 dyn_blue;
+ int16 dyn_yellow;
+ int16 frame_here_for_taking; /* T if a specific frame is here */
+
+
+} Scratch;
+
+
+/* ========================= Sprite Series =================== */
+
+#define fx_west 0 /* rm453c0 */
+#define fx_north 1 /* rm453c1 */
+#define fx_east 2 /* rm453c2 */
+
+#define fx_drain 3
+#define fx_rat_nest 4
+#define fx_web 5
+#define fx_brick 6
+#define fx_stone 7
+
+#define fx_bend_down_9 8 /* rrd_9 */
+#define fx_red_frame 9 /* rm453f0 */
+#define fx_green_frame 10 /* rm453f1 */
+#define fx_blue_frame 11 /* rm453f2 */
+#define fx_yellow_frame 12 /* rm453f3 */
+
+#define fx_gate 13 /* rm405c8 */
+
+
+
+/* ========================= Triggers ======================== */
+
+
+
+/* ========================= Other Macros ==================== */
+
+#define NORTH_X 107
+#define NORTH_Y 87
+
+#define WALK_TO_NORTH_X 107
+#define WALK_TO_NORTH_Y 98
+
+#define WEST_X -20
+#define WEST_Y 128
+
+#define WALK_TO_WEST_X 19
+#define WALK_TO_WEST_Y 128
+
+#define EAST_X 316
+#define EAST_Y 129
+
+#define WALK_TO_EAST_X 277
+#define WALK_TO_EAST_Y 129
+
+#define BRICK_1_X 138
+#define BRICK_1_Y 35
+
+#define BRICK_2_X 84
+#define BRICK_2_Y 27
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif // MADS_PHANTOM_ROOM250_H
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index f1fb3ed9762..c0e5c049f36 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -165,6 +165,7 @@ MODULE_OBJS += \
madsv2/phantom/rooms/room408.o \
madsv2/phantom/rooms/room409.o \
madsv2/phantom/rooms/room410.o \
+ madsv2/phantom/rooms/room453.o \
madsv2/phantom/phantom.o \
madsv2/phantom/conv.o \
madsv2/phantom/global.o \
Commit: 421d5671c7a3d9f066e3990639ca10c76ef6b6cd
https://github.com/scummvm/scummvm/commit/421d5671c7a3d9f066e3990639ca10c76ef6b6cd
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:51+10:00
Commit Message:
MADS: PHANTOM: Added room 456
Changed paths:
A engines/mads/madsv2/phantom/rooms/room456.cpp
A engines/mads/madsv2/phantom/rooms/room456.h
engines/mads/madsv2/phantom/mads/text.h
engines/mads/module.mk
diff --git a/engines/mads/madsv2/phantom/mads/text.h b/engines/mads/madsv2/phantom/mads/text.h
index 384d746705b..d6ba86eabb8 100644
--- a/engines/mads/madsv2/phantom/mads/text.h
+++ b/engines/mads/madsv2/phantom/mads/text.h
@@ -867,7 +867,15 @@ enum {
text_453_26 = 45326,
text_453_27 = 45327,
text_453_28 = 45328,
- text_453_29 = 45329
+ text_453_29 = 45329,
+
+ /* Room 456 */
+ text_456_10 = 45610,
+ text_456_11 = 45611,
+ text_456_12 = 45612,
+ text_456_13 = 45613,
+ text_456_14 = 45614,
+ text_456_15 = 45615
};
} // namespace Phantom
diff --git a/engines/mads/madsv2/phantom/rooms/room456.cpp b/engines/mads/madsv2/phantom/rooms/room456.cpp
new file mode 100644
index 00000000000..092a978f6e8
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room456.cpp
@@ -0,0 +1,405 @@
+/* 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 "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/camera.h"
+#include "mads/madsv2/core/inter.h"
+#include "mads/madsv2/core/matte.h"
+#include "mads/madsv2/core/object.h"
+#include "mads/madsv2/core/sound.h"
+#include "mads/madsv2/core/text.h"
+#include "mads/madsv2/phantom/mads/inventory.h"
+#include "mads/madsv2/phantom/mads/quotes.h"
+#include "mads/madsv2/phantom/mads/sounds.h"
+#include "mads/madsv2/phantom/rooms/section4.h"
+#include "mads/madsv2/phantom/rooms/room456.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+void room_456_init() {
+ global_catacombs_init();
+
+ /* =================== Load sprites series =================== */
+
+ ss[fx_east] = kernel_load_series(kernel_name('c', 1), false);
+ ss[fx_bend_down_9] = kernel_load_series("*RRD_9", false);
+ ss[fx_red_frame] = kernel_load_series(kernel_name('f', 0), false);
+ ss[fx_green_frame] = kernel_load_series(kernel_name('f', 1), false);
+ ss[fx_blue_frame] = kernel_load_series(kernel_name('f', 2), false);
+ ss[fx_yellow_frame] = kernel_load_series(kernel_name('f', 3), false);
+
+ if (global_catacombs_exit(EAST) == -1) {
+ kernel_draw_to_background(ss[fx_east], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ kernel_flip_hotspot(words_archway_to_east, false);
+ }
+
+ if (previous_room != KERNEL_RESTORING_GAME) {
+ switch (global[catacombs_from]) {
+ case EAST:
+ player.x = EAST_X;
+ player.y = EAST_Y;
+ player.facing = FACING_WEST;
+ player_walk(WALK_TO_EAST_X, WALK_TO_EAST_Y, FACING_WEST);
+ break;
+
+ case WEST:
+ player.x = WEST_X;
+ player.y = WEST_Y;
+ player.facing = FACING_SOUTH;
+ player_walk(WALK_TO_WEST_X, WALK_TO_WEST_Y, FACING_EAST);
+ break;
+ }
+ }
+
+ if (object[red_frame].location == global[catacombs_room] + 600) {
+ seq[fx_red_frame] = kernel_seq_stamp(ss[fx_red_frame], false, 1);
+ kernel_seq_depth(seq[fx_red_frame], 14);
+ local->dyn_red = kernel_add_dynamic(words_red_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5,
+ series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_red, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+
+ if (object[green_frame].location == global[catacombs_room] + 600) {
+ seq[fx_green_frame] = kernel_seq_stamp(ss[fx_green_frame], false, 1);
+ kernel_seq_depth(seq[fx_green_frame], 14);
+ local->dyn_green = kernel_add_dynamic(words_green_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5,
+ series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_green, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+
+ if (object[blue_frame].location == global[catacombs_room] + 600) {
+ seq[fx_blue_frame] = kernel_seq_stamp(ss[fx_blue_frame], false, 1);
+ kernel_seq_depth(seq[fx_blue_frame], 14);
+ local->dyn_blue = kernel_add_dynamic(words_blue_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5,
+ series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_blue, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+
+ if (object[yellow_frame].location == global[catacombs_room] + 600) {
+ seq[fx_yellow_frame] = kernel_seq_stamp(ss[fx_yellow_frame], false, 1);
+ kernel_seq_depth(seq[fx_yellow_frame], 14);
+ local->dyn_yellow = kernel_add_dynamic(words_yellow_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5,
+ series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_yellow, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+ section_4_music();
+}
+
+void room_456_pre_parser() {
+ local->frame_is_here = false;
+ local->frame_here_for_taking = false;
+
+ if (object[red_frame].location == global[catacombs_room] + 600) {
+ local->frame_is_here = true;
+ if (player_said_2(take, red_frame)) {
+ local->frame_here_for_taking = true;
+ }
+ }
+
+ if (object[yellow_frame].location == global[catacombs_room] + 600) {
+ local->frame_is_here = true;
+ if (player_said_2(take, yellow_frame)) {
+ local->frame_here_for_taking = true;
+ }
+ }
+
+ if (object[blue_frame].location == global[catacombs_room] + 600) {
+ local->frame_is_here = true;
+ if (player_said_2(take, blue_frame)) {
+ local->frame_here_for_taking = true;
+ }
+ }
+
+ if (object[green_frame].location == global[catacombs_room] + 600) {
+ local->frame_is_here = true;
+ if (player_said_2(take, green_frame)) {
+ local->frame_here_for_taking = true;
+ }
+ }
+
+ if (player_said_1(put) && player_said_1(floor)) {
+ if (player_said_1(red_frame) ||
+ player_said_1(blue_frame) ||
+ player_said_1(yellow_frame) ||
+ player_said_1(green_frame)) {
+ if (local->frame_is_here) {
+ player.need_to_walk = false;
+
+ } else {
+ player_walk(series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+ }
+ }
+}
+
+void room_456_parser() {
+ if (player_said_1(put) && player_said_1(floor)) {
+ if (player_said_1(red_frame) ||
+ player_said_1(blue_frame) ||
+ player_said_1(yellow_frame) ||
+ player_said_1(green_frame)) {
+ if (local->frame_is_here) {
+ text_show(text_000_29);
+ goto handled;
+
+ } else {
+
+ switch (kernel.trigger) {
+ case 0:
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_bend_down_9] = kernel_seq_pingpong(ss[fx_bend_down_9], true,
+ 5, 0, 0, 2);
+ kernel_seq_range(seq[fx_bend_down_9], 1, 5);
+ kernel_seq_player(seq[fx_bend_down_9], true);
+ kernel_seq_trigger(seq[fx_bend_down_9],
+ KERNEL_TRIGGER_SPRITE, 5, 1);
+ kernel_seq_trigger(seq[fx_bend_down_9],
+ KERNEL_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ if (player_said_1(red_frame)) {
+ inter_move_object(red_frame, NOWHERE);
+ object[red_frame].location = global[catacombs_room] + 600;
+ seq[fx_red_frame] = kernel_seq_stamp(ss[fx_red_frame], false, 1);
+ kernel_seq_depth(seq[fx_red_frame], 14);
+ local->dyn_red = kernel_add_dynamic(words_red_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5, series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_red, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+
+ if (player_said_1(green_frame)) {
+ inter_move_object(green_frame, NOWHERE);
+ object[green_frame].location = global[catacombs_room] + 600;
+ seq[fx_green_frame] = kernel_seq_stamp(ss[fx_green_frame], false, 1);
+ kernel_seq_depth(seq[fx_green_frame], 14);
+ local->dyn_green = kernel_add_dynamic(words_green_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5, series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_green, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+
+ if (player_said_1(blue_frame)) {
+ inter_move_object(blue_frame, NOWHERE);
+ object[blue_frame].location = global[catacombs_room] + 600;
+ seq[fx_blue_frame] = kernel_seq_stamp(ss[fx_blue_frame], false, 1);
+ kernel_seq_depth(seq[fx_blue_frame], 14);
+ local->dyn_blue = kernel_add_dynamic(words_blue_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5, series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_blue, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+
+ if (player_said_1(yellow_frame)) {
+ inter_move_object(yellow_frame, NOWHERE);
+ object[yellow_frame].location = global[catacombs_room] + 600;
+ seq[fx_yellow_frame] = kernel_seq_stamp(ss[fx_yellow_frame], false, 1);
+ kernel_seq_depth(seq[fx_yellow_frame], 14);
+ local->dyn_yellow = kernel_add_dynamic(words_yellow_frame, words_walk_to, SYNTAX_SINGULAR, KERNEL_NONE,
+ series_list[ss[fx_red_frame]]->index[0].x - 5, series_list[ss[fx_red_frame]]->index[0].y - 5, 10, 6);
+ kernel_dynamic_walk(local->dyn_yellow, series_list[ss[fx_red_frame]]->index[0].x + 12,
+ series_list[ss[fx_red_frame]]->index[0].y, FACING_NORTHWEST);
+ }
+ break;
+
+ case 2:
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_SERIES, seq[fx_bend_down_9]);
+ player.walker_visible = true;
+ player.commands_allowed = true;
+ break;
+ }
+ goto handled;
+ }
+ }
+ }
+
+ if (player_said_1(take)) {
+ if (player_said_1(red_frame) || player_said_1(green_frame) ||
+ player_said_1(blue_frame) || player_said_1(yellow_frame)) {
+
+ if ((local->frame_here_for_taking || kernel.trigger)) {
+ switch (kernel.trigger) {
+ case (0):
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_bend_down_9] = kernel_seq_pingpong(ss[fx_bend_down_9], true,
+ 5, 0, 0, 2);
+ kernel_seq_range(seq[fx_bend_down_9], 1, 5);
+ kernel_seq_player(seq[fx_bend_down_9], true);
+ kernel_seq_trigger(seq[fx_bend_down_9],
+ KERNEL_TRIGGER_SPRITE, 5, 1);
+ kernel_seq_trigger(seq[fx_bend_down_9],
+ KERNEL_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ if (player_said_1(red_frame)) {
+ kernel_seq_delete(seq[fx_red_frame]);
+ kernel_delete_dynamic(local->dyn_red);
+ inter_give_to_player(red_frame);
+ }
+
+ if (player_said_1(green_frame)) {
+ kernel_seq_delete(seq[fx_green_frame]);
+ kernel_delete_dynamic(local->dyn_green);
+ inter_give_to_player(green_frame);
+ }
+
+ if (player_said_1(blue_frame)) {
+ kernel_seq_delete(seq[fx_blue_frame]);
+ kernel_delete_dynamic(local->dyn_blue);
+ inter_give_to_player(blue_frame);
+ }
+
+ if (player_said_1(yellow_frame)) {
+ kernel_seq_delete(seq[fx_yellow_frame]);
+ kernel_delete_dynamic(local->dyn_yellow);
+ inter_give_to_player(yellow_frame);
+ }
+
+ sound_play(N_TakeObjectSnd);
+ break;
+
+ case 2:
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_SERIES, seq[fx_bend_down_9]);
+ player.walker_visible = true;
+ player.commands_allowed = true;
+ break;
+ }
+ goto handled;
+ }
+ }
+ }
+
+ if (player_said_2(walk_through, archway_to_west)) {
+ global_catacombs_move(WEST);
+ goto handled;
+ }
+
+ if (player_said_2(walk_through, archway_to_east)) {
+ global_catacombs_move(EAST);
+ goto handled;
+ }
+
+ if (player.look_around) {
+ text_show(text_456_10);
+ goto handled;
+ }
+
+ if (player_said_1(look) || player_said_1(look_at)) {
+
+ if (player_said_1(wall)) {
+ text_show(text_456_11);
+ goto handled;
+ }
+
+ if (player_said_1(floor)) {
+ text_show(text_456_12);
+ goto handled;
+ }
+
+ if (player_said_1(archway)) {
+ text_show(text_456_13);
+ goto handled;
+ }
+
+ if (player_said_1(exposed_brick)) {
+ text_show(text_456_14);
+ goto handled;
+ }
+
+ if (player_said_1(red_frame)) {
+ if (!player_has(red_frame)) {
+ object_examine(red_frame, text_008_02, 0);
+ goto handled;
+ }
+ }
+
+ if (player_said_1(green_frame)) {
+ if (!player_has(green_frame)) {
+ object_examine(green_frame, text_008_19, 0);
+ goto handled;
+ }
+ }
+
+ if (player_said_1(blue_frame)) {
+ if (!player_has(blue_frame)) {
+ object_examine(blue_frame, text_008_17, 0);
+ goto handled;
+ }
+ }
+
+ if (player_said_1(yellow_frame)) {
+ if (!player_has(yellow_frame)) {
+ object_examine(yellow_frame, text_008_04, 0);
+ goto handled;
+ }
+ }
+
+ if (player_said_1(more_catacombs)) {
+ text_show(text_456_15);
+ goto handled;
+ }
+ }
+
+ goto done;
+
+handled:
+ player.command_ready = false;
+
+done:
+ ;
+}
+
+void room_456_preload() {
+ room_init_code_pointer = room_456_init;
+ room_pre_parser_code_pointer = room_456_pre_parser;
+ room_parser_code_pointer = room_456_parser;
+ room_daemon_code_pointer = NULL;
+
+ section_4_walker();
+ section_4_interface();
+
+ vocab_make_active(words_red_frame);
+ vocab_make_active(words_yellow_frame);
+ vocab_make_active(words_blue_frame);
+ vocab_make_active(words_green_frame);
+}
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/rooms/room456.h b/engines/mads/madsv2/phantom/rooms/room456.h
new file mode 100644
index 00000000000..7b33d50a696
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room456.h
@@ -0,0 +1,88 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef MADS_PHANTOM_ROOM456_H
+#define MADS_PHANTOM_ROOM456_H
+
+#include "mads/madsv2/core/general.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+#define local ((Scratch *)(&game.scratch[0]))
+#define ss local->sprite
+#define seq local->sequence
+#define aa local->animation
+
+typedef struct { /* Room local variables */
+
+ int16 sprite[15]; /* Sprite series handles */
+ int16 sequence[15]; /* Sequence handles */
+ int16 animation[4]; /* Animation handles */
+ int16 frame_is_here; /* T if any frame is here */
+ int16 dyn_red;
+ int16 dyn_green;
+ int16 dyn_blue;
+ int16 dyn_yellow;
+ int16 frame_here_for_taking; /* T if a specific frame is here */
+
+
+} Scratch;
+
+
+/* ========================= Sprite Series =================== */
+
+#define fx_east 0 /* rm456c1 */
+
+#define fx_bend_down_9 1 /* rrd_9 */
+#define fx_red_frame 2 /* rm401f0 */
+#define fx_green_frame 3 /* rm401f1 */
+#define fx_blue_frame 4 /* rm401f2 */
+#define fx_yellow_frame 5 /* rm401f3 */
+
+
+
+/* ========================= Triggers ======================== */
+
+
+
+/* ========================= Other Macros ==================== */
+
+#define WEST_X 14
+#define WEST_Y 117
+
+#define WALK_TO_WEST_X 46
+#define WALK_TO_WEST_Y 117
+
+#define EAST_X 298
+#define EAST_Y 123
+
+#define WALK_TO_EAST_X 254
+#define WALK_TO_EAST_Y 123
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif // MADS_PHANTOM_ROOM250_H
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index c0e5c049f36..5415cf02dbd 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -166,6 +166,7 @@ MODULE_OBJS += \
madsv2/phantom/rooms/room409.o \
madsv2/phantom/rooms/room410.o \
madsv2/phantom/rooms/room453.o \
+ madsv2/phantom/rooms/room456.o \
madsv2/phantom/phantom.o \
madsv2/phantom/conv.o \
madsv2/phantom/global.o \
Commit: a1d41ae887f3d8231035fee264341b629fdae03c
https://github.com/scummvm/scummvm/commit/a1d41ae887f3d8231035fee264341b629fdae03c
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:52+10:00
Commit Message:
MADS: PHANTOM: Added section 5 rooms
Changed paths:
A engines/mads/madsv2/phantom/rooms/room501.cpp
A engines/mads/madsv2/phantom/rooms/room501.h
A engines/mads/madsv2/phantom/rooms/room502.cpp
A engines/mads/madsv2/phantom/rooms/room502.h
A engines/mads/madsv2/phantom/rooms/room504.cpp
A engines/mads/madsv2/phantom/rooms/room504.h
A engines/mads/madsv2/phantom/rooms/room505.cpp
A engines/mads/madsv2/phantom/rooms/room505.h
A engines/mads/madsv2/phantom/rooms/room506.cpp
A engines/mads/madsv2/phantom/rooms/room506.h
A engines/mads/madsv2/phantom/rooms/section2.cpp
A engines/mads/madsv2/phantom/rooms/section3.cpp
A engines/mads/madsv2/phantom/rooms/section4.cpp
A engines/mads/madsv2/phantom/rooms/section5.cpp
A engines/mads/madsv2/phantom/rooms/section5.h
engines/mads/madsv2/phantom/conv.cpp
engines/mads/madsv2/phantom/conv.h
engines/mads/madsv2/phantom/global.h
engines/mads/madsv2/phantom/mads/inventory.h
engines/mads/madsv2/phantom/mads/sounds.h
engines/mads/madsv2/phantom/mads/speeches.h
engines/mads/madsv2/phantom/mads/text.h
engines/mads/madsv2/phantom/mads/words.h
engines/mads/madsv2/phantom/rooms/room250.h
engines/mads/madsv2/phantom/rooms/room301.h
engines/mads/madsv2/phantom/rooms/room302.h
engines/mads/madsv2/phantom/rooms/room303.h
engines/mads/madsv2/phantom/rooms/room304.h
engines/mads/madsv2/phantom/rooms/room305.h
engines/mads/madsv2/phantom/rooms/room306.h
engines/mads/madsv2/phantom/rooms/room307.h
engines/mads/madsv2/phantom/rooms/room308.h
engines/mads/madsv2/phantom/rooms/room309.h
engines/mads/madsv2/phantom/rooms/room310.h
engines/mads/madsv2/phantom/rooms/room401.h
engines/mads/madsv2/phantom/rooms/room403.h
engines/mads/madsv2/phantom/rooms/room404.h
engines/mads/madsv2/phantom/rooms/room406.h
engines/mads/madsv2/phantom/rooms/room407.h
engines/mads/madsv2/phantom/rooms/room408.h
engines/mads/madsv2/phantom/rooms/room409.h
engines/mads/madsv2/phantom/rooms/room410.h
engines/mads/madsv2/phantom/rooms/room453.h
engines/mads/madsv2/phantom/rooms/room456.h
engines/mads/module.mk
diff --git a/engines/mads/madsv2/phantom/conv.cpp b/engines/mads/madsv2/phantom/conv.cpp
index 867c235f7bf..14cad1e58c2 100644
--- a/engines/mads/madsv2/phantom/conv.cpp
+++ b/engines/mads/madsv2/phantom/conv.cpp
@@ -29,7 +29,7 @@ namespace Phantom {
int conv_restore_running;
ConvControl conv_control;
-
+int *conv_my_next_start;
constexpr int CONV_MAX_SLOTS = 40;
constexpr int CONV_MAX_DATA = 5;
diff --git a/engines/mads/madsv2/phantom/conv.h b/engines/mads/madsv2/phantom/conv.h
index 1a5d9d83fbc..b8e01baa0b7 100644
--- a/engines/mads/madsv2/phantom/conv.h
+++ b/engines/mads/madsv2/phantom/conv.h
@@ -245,6 +245,30 @@ enum {
conv018_nomore_huh = 5
};
+enum {
+ conv019_talk_b_b = 2,
+ conv019_exit_b_b = 12
+};
+
+enum {
+ conv020_where_a = 2,
+ conv020_exit_b_b = 5,
+ conv020_dialogue_b_b = 8,
+ conv020_bye_b_b = 14,
+ conv020_story_b_b = 22
+};
+
+enum {
+ conv021_fight_b_b = 3,
+ conv021_ending_b_b = 8,
+ conv021_outtahere_first = 10,
+ conv021_outtahere_second = 11,
+ conv021_outtahere_third = 12,
+ conv021_hasit_b_b = 14,
+ conv021_score_abc = 15,
+ conv021_score_b_b = 17,
+};
+
enum {
conv022_second_next = 1,
conv022_resolution_florent = 6,
@@ -271,6 +295,15 @@ enum {
conv023_die_b_b = 12
};
+enum {
+ conv027_choices_one = 2,
+ conv027_choices_two = 3,
+ conv027_choices_three = 4,
+ conv027_choices_four = 5,
+ conv027_choices_five = 6,
+ conv027_exit_a_a = 7
+};
+
struct ConvData {
int16 node_count;
int16 dialog_count;
@@ -300,6 +333,7 @@ struct ConvControl {
extern int conv_restore_running;
extern ConvControl conv_control;
+extern int *conv_my_next_start;
extern void conv_system_init();
extern void conv_system_cleanup();
diff --git a/engines/mads/madsv2/phantom/global.h b/engines/mads/madsv2/phantom/global.h
index 35d67a3944b..eefa3cb4d91 100644
--- a/engines/mads/madsv2/phantom/global.h
+++ b/engines/mads/madsv2/phantom/global.h
@@ -255,6 +255,16 @@ enum {
#define LANTERN_IS_OFF 0
#define LANTERN_IS_ON 1
+// fight_status
+#define FIGHT_NOT_HAPPENED 0
+#define FIGHT_TALKING 1
+#define FIGHT_PARTED 2
+
+// coffin_status
+#define COFFIN_CLOSED 0
+#define COFFIN_UNLOCKED 1
+#define COFFIN_OPEN 2
+
// Catacomb defines
constexpr int NORTH = 0;
constexpr int EAST = 1;
diff --git a/engines/mads/madsv2/phantom/mads/inventory.h b/engines/mads/madsv2/phantom/mads/inventory.h
index 0481da7e120..cacb10a1988 100644
--- a/engines/mads/madsv2/phantom/mads/inventory.h
+++ b/engines/mads/madsv2/phantom/mads/inventory.h
@@ -48,8 +48,11 @@ enum {
blue_frame = 17,
large_note = 18,
green_frame = 19,
+ music_score = 20,
+ wedding_ring = 21,
cable_hook = 22,
- rope_with_hook = 23
+ rope_with_hook = 23,
+ oar = 24
};
} // namespace Phantom
diff --git a/engines/mads/madsv2/phantom/mads/sounds.h b/engines/mads/madsv2/phantom/mads/sounds.h
index 10447e6b0c8..22a7dea19dd 100644
--- a/engines/mads/madsv2/phantom/mads/sounds.h
+++ b/engines/mads/madsv2/phantom/mads/sounds.h
@@ -30,6 +30,7 @@ namespace Phantom {
enum {
N_AllFade = 1,
+ N_MusicOff = 2,
N_MusicFade = 3,
N_IsAnySoundOn = 8,
N_BackgroundMus = 16,
@@ -57,7 +58,20 @@ enum {
N_LeverSnap = 65,
N_LeverBing = 66,
- N_DoorGong = 67
+ N_DoorGong = 67,
+
+ N_Bach_dm = 34,
+ N_Gigue = 35,
+ N_Canon = 36,
+ N_Bach_gm = 37,
+ N_AngelMus505 = 39,
+ N_PanelClank = 65,
+ N_HeatHiss = 67,
+ N_LassoThrow = 69,
+ N_SecretDoor = 73,
+ N_DoorHandle005 = 74,
+ N_CoffinUnlocks = 76,
+ N_PushSkull = 77
};
} // namespace Phantom
diff --git a/engines/mads/madsv2/phantom/mads/speeches.h b/engines/mads/madsv2/phantom/mads/speeches.h
index f320b1e266e..1664b21699c 100644
--- a/engines/mads/madsv2/phantom/mads/speeches.h
+++ b/engines/mads/madsv2/phantom/mads/speeches.h
@@ -35,6 +35,7 @@ enum {
speech_christine_scream = 4,
speech_raoul_strangle = 5,
speech_raoul_catwalk = 6,
+ speech_raoul_fire = 7,
speech_christine_scales = 8,
speech_phantom_cackle = 9
};
diff --git a/engines/mads/madsv2/phantom/mads/text.h b/engines/mads/madsv2/phantom/mads/text.h
index d6ba86eabb8..3326da4e366 100644
--- a/engines/mads/madsv2/phantom/mads/text.h
+++ b/engines/mads/madsv2/phantom/mads/text.h
@@ -42,6 +42,7 @@ enum {
text_008_17 = 817,
text_008_18 = 818,
text_008_19 = 819,
+ text_008_20 = 820,
text_008_44 = 844,
text_008_45 = 845,
@@ -91,7 +92,9 @@ enum {
text_008_02 = 802,
text_008_03 = 803,
text_008_04 = 804,
+ text_008_21 = 821,
text_008_22 = 822,
+ text_008_24 = 824,
text_008_42 = 842,
text_008_43 = 843,
@@ -875,7 +878,125 @@ enum {
text_456_12 = 45612,
text_456_13 = 45613,
text_456_14 = 45614,
- text_456_15 = 45615
+ text_456_15 = 45615,
+
+ /* Room 501 */
+ text_501_10 = 50110,
+ text_501_11 = 50111,
+ text_501_12 = 50112,
+ text_501_13 = 50113,
+ text_501_14 = 50114,
+ text_501_17 = 50117,
+ text_501_18 = 50118,
+ text_501_19 = 50119,
+ text_501_20 = 50120,
+ text_501_21 = 50121,
+ text_501_22 = 50122,
+ text_501_23 = 50123,
+ text_501_24 = 50124,
+ text_501_25 = 50125,
+ text_501_26 = 50126,
+ text_501_27 = 50127,
+ text_501_28 = 50128,
+ text_501_29 = 50129,
+
+ /* Room 502 */
+ text_502_10 = 50210,
+ text_502_11 = 50211,
+ text_502_12 = 50212,
+ text_502_13 = 50213,
+ text_502_14 = 50214,
+ text_502_15 = 50215,
+ text_502_16 = 50216,
+ text_502_17 = 50217,
+ text_502_19 = 50219,
+ text_502_20 = 50220,
+ text_502_21 = 50221,
+ text_502_22 = 50222,
+ text_502_23 = 50223,
+ text_502_24 = 50224,
+ text_502_25 = 50225,
+ text_502_26 = 50226,
+ text_502_27 = 50227,
+ text_502_28 = 50228,
+ text_502_29 = 50229,
+ text_502_30 = 50230,
+ text_502_31 = 50231,
+ text_502_32 = 50232,
+ text_502_33 = 50233,
+ text_502_34 = 50234,
+
+ /* Room 504 */
+ text_504_10 = 50410,
+ text_504_11 = 50411,
+ text_504_12 = 50412,
+ text_504_13 = 50413,
+ text_504_14 = 50414,
+ text_504_15 = 50415,
+ text_504_16 = 50416,
+ text_504_17 = 50417,
+ text_504_18 = 50418,
+ text_504_19 = 50419,
+ text_504_20 = 50420,
+ text_504_21 = 50421,
+ text_504_22 = 50422,
+ text_504_24 = 50424,
+ text_504_25 = 50425,
+ text_504_26 = 50426,
+ text_504_27 = 50427,
+ text_504_28 = 50428,
+ text_504_29 = 50429,
+ text_504_30 = 50430,
+ text_504_31 = 50431,
+ text_504_32 = 50432,
+ text_504_33 = 50433,
+ text_504_34 = 50434,
+ text_504_35 = 50435,
+ text_504_36 = 50436,
+
+ /* Room 505 */
+ text_505_10 = 50510,
+ text_505_11 = 50511,
+ text_505_12 = 50512,
+ text_505_13 = 50513,
+ text_505_14 = 50514,
+ text_505_15 = 50515,
+ text_505_18 = 50518,
+ text_505_19 = 50519,
+ text_505_20 = 50520,
+ text_505_21 = 50521,
+ text_505_22 = 50522,
+ text_505_23 = 50523,
+ text_505_24 = 50524,
+ text_505_25 = 50525,
+ text_505_28 = 50528,
+ text_505_29 = 50529,
+ text_505_30 = 50530,
+ text_505_31 = 50531,
+ text_505_32 = 50532,
+ text_505_33 = 50533,
+ text_505_34 = 50534,
+ text_505_35 = 50535,
+ text_505_36 = 50536,
+ text_505_37 = 50537,
+ text_505_38 = 50538,
+ text_505_39 = 50539,
+ text_505_40 = 50540,
+
+ /* Room 506 */
+ text_506_10 = 50610,
+ text_506_11 = 50611,
+ text_506_12 = 50612,
+ text_506_13 = 50613,
+ text_506_14 = 50614,
+ text_506_15 = 50615,
+ text_506_16 = 50616,
+ text_506_17 = 50617,
+ text_506_18 = 50618,
+ text_506_19 = 50619,
+ text_506_20 = 50620,
+ text_506_21 = 50621,
+ text_506_22 = 50622
};
} // namespace Phantom
diff --git a/engines/mads/madsv2/phantom/mads/words.h b/engines/mads/madsv2/phantom/mads/words.h
index 2891eb40f69..fabeee4eb5c 100644
--- a/engines/mads/madsv2/phantom/mads/words.h
+++ b/engines/mads/madsv2/phantom/mads/words.h
@@ -86,6 +86,7 @@ enum {
words_lamp = 86,
words_lantern = 87,
words_large_note = 88,
+ words_lasso = 89,
words_leg = 90,
words_letter = 91,
words_light_fixture = 92,
@@ -97,6 +98,7 @@ enum {
words_mirror = 99,
words_mummy_prop = 100,
words_mural = 101,
+ words_music_score = 102,
words_music_stand = 103,
words_music_stands = 104,
words_notice = 106,
@@ -270,9 +272,24 @@ enum {
words_Monsieur_Richard = 302,
words_Julie = 303,
words_cable_hook = 304,
+ words_rope_with_hook = 306,
+ words_grapple = 307,
+ words_oar = 308,
+ words_organ = 309,
+ words_organ_bench = 311,
+ words_sit_on = 312,
+ words_large_chair = 313,
+ words_sit_in = 314,
+ words_sarcophagus = 315,
words_skull = 316,
- words_drain = 317,
+ words_skulls = 317,
+ words_totem = 318,
+ words_pole = 319,
+ words_curtain = 320,
+ words_torch = 321,
+ words_ramp = 322,
words_Madame_Giry = 323,
+ words_panels = 324,
words_more_catacombs = 325,
words_blocked_archway = 326,
words_grate = 327,
@@ -299,6 +316,7 @@ enum {
words_rat_s_nest = 354,
words_broken_pot = 355,
words_stone = 356,
+ words_drain = 357,
words_skull_switch_1 = 359,
words_skull_switch_2 = 360,
words_skull_switch_3 = 361,
@@ -327,11 +345,14 @@ enum {
words_skull_switch_26 = 384,
words_Edgar_Degas = 385,
words_chandelier_cable = 386,
+ words_skull_face = 388,
words_boat = 389,
words_hook = 390,
words_cane = 392,
words_mask = 393,
+ words_lid = 396,
words_cobweb = 397,
+ words_Phantom = 398,
words_paper = 399
};
diff --git a/engines/mads/madsv2/phantom/rooms/room250.h b/engines/mads/madsv2/phantom/rooms/room250.h
index f6b78a72155..7196bc6bf89 100644
--- a/engines/mads/madsv2/phantom/rooms/room250.h
+++ b/engines/mads/madsv2/phantom/rooms/room250.h
@@ -47,4 +47,4 @@ typedef struct { /* Room local variables */
} // namespace MADSV2
} // namespace MADS
-#endif // MADS_PHANTOM_ROOM250_H
+#endif
diff --git a/engines/mads/madsv2/phantom/rooms/room301.h b/engines/mads/madsv2/phantom/rooms/room301.h
index 2029b73762e..2a52c7110ce 100644
--- a/engines/mads/madsv2/phantom/rooms/room301.h
+++ b/engines/mads/madsv2/phantom/rooms/room301.h
@@ -122,4 +122,4 @@ typedef struct { /* Room local variables */
} // namespace MADSV2
} // namespace MADS
-#endif // MADS_PHANTOM_ROOM250_H
+#endif
diff --git a/engines/mads/madsv2/phantom/rooms/room302.h b/engines/mads/madsv2/phantom/rooms/room302.h
index 7ba5410b9e8..e80532d1295 100644
--- a/engines/mads/madsv2/phantom/rooms/room302.h
+++ b/engines/mads/madsv2/phantom/rooms/room302.h
@@ -72,4 +72,4 @@ typedef struct { /* Room local variables */
} // namespace MADSV2
} // namespace MADS
-#endif // MADS_PHANTOM_ROOM250_H
+#endif
diff --git a/engines/mads/madsv2/phantom/rooms/room303.h b/engines/mads/madsv2/phantom/rooms/room303.h
index 4200517d434..4162c04d7df 100644
--- a/engines/mads/madsv2/phantom/rooms/room303.h
+++ b/engines/mads/madsv2/phantom/rooms/room303.h
@@ -89,4 +89,4 @@ typedef struct { /* Room local variables */
} // namespace MADSV2
} // namespace MADS
-#endif // MADS_PHANTOM_ROOM250_H
+#endif
diff --git a/engines/mads/madsv2/phantom/rooms/room304.h b/engines/mads/madsv2/phantom/rooms/room304.h
index 1614438da4d..8987e14a218 100644
--- a/engines/mads/madsv2/phantom/rooms/room304.h
+++ b/engines/mads/madsv2/phantom/rooms/room304.h
@@ -89,4 +89,4 @@ typedef struct { /* Room local variables */
} // namespace MADSV2
} // namespace MADS
-#endif // MADS_PHANTOM_ROOM250_H
+#endif
diff --git a/engines/mads/madsv2/phantom/rooms/room305.h b/engines/mads/madsv2/phantom/rooms/room305.h
index 0be511d7c25..d33d2e1699e 100644
--- a/engines/mads/madsv2/phantom/rooms/room305.h
+++ b/engines/mads/madsv2/phantom/rooms/room305.h
@@ -70,4 +70,4 @@ typedef struct { /* Room local variables */
} // namespace MADSV2
} // namespace MADS
-#endif // MADS_PHANTOM_ROOM250_H
+#endif
diff --git a/engines/mads/madsv2/phantom/rooms/room306.h b/engines/mads/madsv2/phantom/rooms/room306.h
index 97671a4edec..0449f646f9c 100644
--- a/engines/mads/madsv2/phantom/rooms/room306.h
+++ b/engines/mads/madsv2/phantom/rooms/room306.h
@@ -59,4 +59,4 @@ typedef struct { /* Room local variables */
} // namespace MADSV2
} // namespace MADS
-#endif // MADS_PHANTOM_ROOM250_H
+#endif
diff --git a/engines/mads/madsv2/phantom/rooms/room307.h b/engines/mads/madsv2/phantom/rooms/room307.h
index c38d6bcfd0b..853cb3dd222 100644
--- a/engines/mads/madsv2/phantom/rooms/room307.h
+++ b/engines/mads/madsv2/phantom/rooms/room307.h
@@ -79,4 +79,4 @@ typedef struct { /* Room local variables */
} // namespace MADSV2
} // namespace MADS
-#endif // MADS_PHANTOM_ROOM250_H
+#endif
diff --git a/engines/mads/madsv2/phantom/rooms/room308.h b/engines/mads/madsv2/phantom/rooms/room308.h
index 8aadbcc8466..e963886eacd 100644
--- a/engines/mads/madsv2/phantom/rooms/room308.h
+++ b/engines/mads/madsv2/phantom/rooms/room308.h
@@ -88,4 +88,4 @@ typedef struct { /* Room local variables */
} // namespace MADSV2
} // namespace MADS
-#endif // MADS_PHANTOM_ROOM250_H
+#endif
diff --git a/engines/mads/madsv2/phantom/rooms/room309.h b/engines/mads/madsv2/phantom/rooms/room309.h
index 0f0af163a86..08f46b5ff8b 100644
--- a/engines/mads/madsv2/phantom/rooms/room309.h
+++ b/engines/mads/madsv2/phantom/rooms/room309.h
@@ -97,4 +97,4 @@ typedef struct { /* Room local variables */
} // namespace MADSV2
} // namespace MADS
-#endif // MADS_PHANTOM_ROOM250_H
+#endif
diff --git a/engines/mads/madsv2/phantom/rooms/room310.h b/engines/mads/madsv2/phantom/rooms/room310.h
index 93eaf0d058a..d177a1ff694 100644
--- a/engines/mads/madsv2/phantom/rooms/room310.h
+++ b/engines/mads/madsv2/phantom/rooms/room310.h
@@ -74,4 +74,4 @@ typedef struct { /* Room local variables */
} // namespace MADSV2
} // namespace MADS
-#endif // MADS_PHANTOM_ROOM250_H
+#endif
diff --git a/engines/mads/madsv2/phantom/rooms/room401.h b/engines/mads/madsv2/phantom/rooms/room401.h
index 88c846c7719..233f8cd9232 100644
--- a/engines/mads/madsv2/phantom/rooms/room401.h
+++ b/engines/mads/madsv2/phantom/rooms/room401.h
@@ -97,4 +97,4 @@ typedef struct { /* Room local variables */
} // namespace MADSV2
} // namespace MADS
-#endif // MADS_PHANTOM_ROOM250_H
+#endif
diff --git a/engines/mads/madsv2/phantom/rooms/room403.h b/engines/mads/madsv2/phantom/rooms/room403.h
index 8518ae67ddc..b7d0926ff4a 100644
--- a/engines/mads/madsv2/phantom/rooms/room403.h
+++ b/engines/mads/madsv2/phantom/rooms/room403.h
@@ -106,4 +106,4 @@ typedef struct { /* Room local variables */
} // namespace MADSV2
} // namespace MADS
-#endif // MADS_PHANTOM_ROOM250_H
+#endif
diff --git a/engines/mads/madsv2/phantom/rooms/room404.h b/engines/mads/madsv2/phantom/rooms/room404.h
index a6cb5abb0c5..7007752f31a 100644
--- a/engines/mads/madsv2/phantom/rooms/room404.h
+++ b/engines/mads/madsv2/phantom/rooms/room404.h
@@ -103,4 +103,4 @@ typedef struct { /* Room local variables */
} // namespace MADSV2
} // namespace MADS
-#endif // MADS_PHANTOM_ROOM250_H
+#endif
diff --git a/engines/mads/madsv2/phantom/rooms/room406.h b/engines/mads/madsv2/phantom/rooms/room406.h
index 6c2851c4d30..1a7af8744cc 100644
--- a/engines/mads/madsv2/phantom/rooms/room406.h
+++ b/engines/mads/madsv2/phantom/rooms/room406.h
@@ -78,4 +78,4 @@ typedef struct { /* Room local variables */
} // namespace MADSV2
} // namespace MADS
-#endif // MADS_PHANTOM_ROOM250_H
+#endif
diff --git a/engines/mads/madsv2/phantom/rooms/room407.h b/engines/mads/madsv2/phantom/rooms/room407.h
index dbc60b2374c..b9f8a93e8fb 100644
--- a/engines/mads/madsv2/phantom/rooms/room407.h
+++ b/engines/mads/madsv2/phantom/rooms/room407.h
@@ -121,4 +121,4 @@ typedef struct { /* Room local variables */
} // namespace MADSV2
} // namespace MADS
-#endif // MADS_PHANTOM_ROOM250_H
+#endif
diff --git a/engines/mads/madsv2/phantom/rooms/room408.h b/engines/mads/madsv2/phantom/rooms/room408.h
index 39742546829..ede4a75efcb 100644
--- a/engines/mads/madsv2/phantom/rooms/room408.h
+++ b/engines/mads/madsv2/phantom/rooms/room408.h
@@ -148,4 +148,4 @@ typedef struct { /* Room local variables */
} // namespace MADSV2
} // namespace MADS
-#endif // MADS_PHANTOM_ROOM250_H
+#endif
diff --git a/engines/mads/madsv2/phantom/rooms/room409.h b/engines/mads/madsv2/phantom/rooms/room409.h
index 20f1b3a1db1..86ec8b286f9 100644
--- a/engines/mads/madsv2/phantom/rooms/room409.h
+++ b/engines/mads/madsv2/phantom/rooms/room409.h
@@ -93,4 +93,4 @@ typedef struct { /* Room local variables */
} // namespace MADSV2
} // namespace MADS
-#endif // MADS_PHANTOM_ROOM250_H
+#endif
diff --git a/engines/mads/madsv2/phantom/rooms/room410.h b/engines/mads/madsv2/phantom/rooms/room410.h
index 588c998bd39..e748875fd6a 100644
--- a/engines/mads/madsv2/phantom/rooms/room410.h
+++ b/engines/mads/madsv2/phantom/rooms/room410.h
@@ -64,4 +64,4 @@ typedef struct { /* Room local variables */
} // namespace MADSV2
} // namespace MADS
-#endif // MADS_PHANTOM_ROOM250_H
+#endif
diff --git a/engines/mads/madsv2/phantom/rooms/room453.h b/engines/mads/madsv2/phantom/rooms/room453.h
index bec249144d0..15fe3262dc7 100644
--- a/engines/mads/madsv2/phantom/rooms/room453.h
+++ b/engines/mads/madsv2/phantom/rooms/room453.h
@@ -107,4 +107,4 @@ typedef struct { /* Room local variables */
} // namespace MADSV2
} // namespace MADS
-#endif // MADS_PHANTOM_ROOM250_H
+#endif
diff --git a/engines/mads/madsv2/phantom/rooms/room456.h b/engines/mads/madsv2/phantom/rooms/room456.h
index 7b33d50a696..1f117b0074e 100644
--- a/engines/mads/madsv2/phantom/rooms/room456.h
+++ b/engines/mads/madsv2/phantom/rooms/room456.h
@@ -85,4 +85,4 @@ typedef struct { /* Room local variables */
} // namespace MADSV2
} // namespace MADS
-#endif // MADS_PHANTOM_ROOM250_H
+#endif
diff --git a/engines/mads/madsv2/phantom/rooms/room501.cpp b/engines/mads/madsv2/phantom/rooms/room501.cpp
new file mode 100644
index 00000000000..e0b58f5d2bb
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room501.cpp
@@ -0,0 +1,656 @@
+/* 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 "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/camera.h"
+#include "mads/madsv2/core/inter.h"
+#include "mads/madsv2/core/matte.h"
+#include "mads/madsv2/core/object.h"
+#include "mads/madsv2/core/pal.h"
+#include "mads/madsv2/core/sound.h"
+#include "mads/madsv2/core/text.h"
+#include "mads/madsv2/phantom/conv.h"
+#include "mads/madsv2/phantom/rooms/section5.h"
+#include "mads/madsv2/phantom/rooms/room501.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+void room_501_init() {
+ kernel_flip_hotspot(words_Christine, false);
+ kernel_flip_hotspot(words_boat, false);
+
+ if (previous_room != KERNEL_RESTORING_GAME) {
+ local->anim_0_running = false;
+ local->prevent_2 = false;
+ }
+
+ conv_get(CONV_MISC);
+
+ /* ===================== Load Sprite Series ================== */
+
+ ss[fx_flame] = kernel_load_series(kernel_name('x', 0), false);
+ ss[fx_door] = kernel_load_series(kernel_name('x', 1), false);
+ ss[fx_left_door] = kernel_load_series(kernel_name('x', 2), false);
+ ss[fx_shove_off] = kernel_load_series(kernel_name('a', 1), false);
+ ss[fx_christine] = kernel_load_series(kernel_name('a', 0), false);
+ ss[fx_christine] = kernel_load_series("*CHR_6", PAL_MAP_ALL_TO_CLOSEST |
+ PAL_MAP_ANY_TO_CLOSEST);
+ ss[fx_christine] = kernel_load_series("*CHR_9", PAL_MAP_ALL_TO_CLOSEST |
+ PAL_MAP_ANY_TO_CLOSEST);
+ ss[fx_christine] = kernel_load_series("*CHR_8", PAL_MAP_ALL_TO_CLOSEST |
+ PAL_MAP_ANY_TO_CLOSEST);
+ ss[fx_take_6] = kernel_load_series("*RDRR_6", false);
+
+
+
+ /* ======================= Stamp flame ======================= */
+
+
+ seq[fx_flame] = kernel_seq_forward(ss[fx_flame], false, 6, 0, 0, 0);
+ kernel_seq_depth(seq[fx_flame], 14);
+ kernel_seq_range(seq[fx_flame], KERNEL_FIRST, KERNEL_LAST);
+
+ if (previous_room == KERNEL_RESTORING_GAME) {
+
+ if (global[christine_is_in_boat]) {
+ local->anim_0_running = true;
+ aa[0] = kernel_run_animation(kernel_name('b', 1), ROOM_501_START_ROWING);
+ kernel_reset_animation(aa[0], 124);
+ kernel_flip_hotspot_loc(words_Christine, true, CHRIS_X_LEFT, CHRIS_Y_LEFT);
+ kernel_flip_hotspot(words_boat, true);
+ }
+
+ seq[fx_door] = kernel_seq_stamp
+ (ss[fx_door], false, 1);
+ kernel_seq_depth(seq[fx_door], 4);
+ seq[fx_left_door] = kernel_seq_stamp
+ (ss[fx_left_door], false, KERNEL_FIRST);
+ kernel_seq_depth(seq[fx_left_door], 4);
+ }
+
+ /* ========================= Previous Rooms ================== */
+
+
+ if (previous_room == 506) {
+ player.x = PLAYER_X_FROM_506;
+ player.y = PLAYER_Y_FROM_506;
+ player.facing = FACING_WEST;
+ player.commands_allowed = false;
+
+ if (global[christine_is_in_boat]) {
+ local->anim_0_running = true;
+ aa[0] = kernel_run_animation(kernel_name('b', 1), ROOM_501_START_ROWING);
+ kernel_reset_animation(aa[0], 124);
+ kernel_flip_hotspot_loc(words_Christine, true, CHRIS_X_LEFT, CHRIS_Y_LEFT);
+ kernel_flip_hotspot(words_boat, true);
+ player_walk(WALK_TO_X_FROM_506, WALK_TO_Y_FROM_506, FACING_SOUTHWEST);
+ player_walk_trigger(ROOM_501_FROM_506);
+ player_walk_trigger(ROOM_501_LEFT_DOOR_CLOSES);
+
+ } else {
+ local->anim_0_running = true;
+ aa[0] = kernel_run_animation(kernel_name('b', 1), ROOM_501_START_ROWING);
+ global[christine_is_in_boat] = true;
+ kernel_flip_hotspot(words_boat, true);
+ player_walk(WALK_TO_X_FROM_506, WALK_TO_Y_FROM_506, FACING_SOUTHWEST);
+ player_walk_trigger(ROOM_501_FROM_506);
+
+ }
+
+ seq[fx_door] = kernel_seq_stamp
+ (ss[fx_door], false, 1);
+ kernel_seq_depth(seq[fx_door], 4);
+
+ seq[fx_left_door] = kernel_seq_stamp
+ (ss[fx_left_door], false, KERNEL_LAST);
+ kernel_seq_depth(seq[fx_left_door], 1);
+
+ } else if ((previous_room == 401) || (previous_room == 408) || (previous_room != KERNEL_RESTORING_GAME)) {
+ player_first_walk(WEST_X, WEST_Y, FACING_EAST, WALK_TO_WEST_X, WALK_TO_WEST_Y, FACING_EAST, true);
+ seq[fx_door] = kernel_seq_stamp
+ (ss[fx_door], false, 1);
+ kernel_seq_depth(seq[fx_door], 4);
+ seq[fx_left_door] = kernel_seq_stamp
+ (ss[fx_left_door], false, KERNEL_FIRST);
+ kernel_seq_depth(seq[fx_left_door], 4);
+ }
+
+ section_5_music();
+}
+
+void room_501_pre_parser() {
+ if (player_said_2(walk_through, archway_to_west)) {
+ if (global[lantern_status] == LANTERN_IS_OFF) {
+ player.need_to_walk = false;
+ text_show(text_309_18);
+ player_cancel_command();
+
+ } else if (!global[christine_is_in_boat]) {
+ global_enter_catacombs(0);
+ }
+ }
+
+ if ((player_said_1(door)) && (player_said_1(lock) || player_said_1(unlock) || player_said_1(open))) {
+ if (inter_point_x < 287) {
+ player_walk(DOOR_LEFT_X, DOOR_LEFT_Y, FACING_EAST);
+ } else {
+ player_walk(DOOR_RIGHT_X, DOOR_RIGHT_Y, FACING_EAST);
+ }
+ }
+
+ if ((player_said_2(walk_through, door) || player_said_2(open, door)) &&
+ player_has_been_in_room(506) && inter_point_x < 287) {
+ switch (kernel.trigger) {
+ case 0:
+ player.ready_to_walk = false;
+ player.need_to_walk = false;
+ player.commands_allowed = false;
+ conv_run(CONV_MISC);
+ conv_export_value(2);
+ kernel_timing_trigger(6, 1);
+ break;
+
+ case 1:
+ if (conv_control.running >= 0) {
+ kernel_timing_trigger(6, 1);
+ } else {
+ player.commands_allowed = true;
+ player.command_ready = true;
+ player.need_to_walk = true;
+ player.ready_to_walk = true;
+ }
+ break;
+ }
+ }
+
+ if (player_said_2(walk_through, archway_to_west) && global[lantern_status]) {
+ if (global[right_door_is_open_504]) {
+ player_walk(WALK_TO_CAT_NO_X, WALK_TO_CAT_NO_Y, FACING_WEST);
+ }
+ }
+}
+
+void room_501_parser() {
+ int temp;
+
+ if (conv_control.running == CONV_MISC) {
+ goto handled;
+ }
+
+ if (player_said_2(walk_through, archway_to_west) && (global[christine_is_in_boat])) {
+ conv_run(CONV_MISC);
+ conv_export_value(3);
+ goto handled;
+ }
+
+ if (player_said_2(talk_to, Christine)) {
+ conv_run(CONV_MISC);
+ conv_export_value(1);
+ goto handled;
+ }
+
+ if (player_said_2(climb_into, boat)) {
+ if (player_has(oar)) {
+ local->anim_0_running = false;
+ } else {
+ text_show(text_501_23);
+ }
+ goto handled;
+ }
+
+ if (player_said_2(unlock, door) || player_said_2(lock, door)) {
+ switch (kernel.trigger) {
+ case 0:
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_take_6] = kernel_seq_forward(ss[fx_take_6], false, 5, 0, 0, 1);
+ kernel_seq_range(seq[fx_take_6], 1, 4);
+ kernel_seq_player(seq[fx_take_6], true);
+ kernel_seq_trigger(seq[fx_take_6], KERNEL_TRIGGER_EXPIRE, 0, 1);
+ break;
+
+ case 1:
+ temp = seq[fx_take_6];
+ seq[fx_take_6] = kernel_seq_stamp(ss[fx_take_6], false, 4);
+ kernel_synch(KERNEL_SERIES, seq[fx_take_6], KERNEL_SERIES, temp);
+ kernel_seq_player(seq[fx_take_6], false);
+ kernel_timing_trigger(QUARTER_SECOND, 2);
+ sound_play(N_DoorHandle005);
+ break;
+
+ case 2:
+ kernel_seq_delete(seq[fx_take_6]);
+ seq[fx_take_6] = kernel_seq_backward(ss[fx_take_6], false, 5, 0, 0, 1);
+ kernel_seq_range(seq[fx_take_6], 1, 4);
+ kernel_seq_player(seq[fx_take_6], false);
+ kernel_seq_trigger(seq[fx_take_6], KERNEL_TRIGGER_EXPIRE, 0, 3);
+ break;
+
+ case 3:
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_SERIES, seq[fx_take_6]);
+ player.walker_visible = true;
+ text_show(text_501_22);
+ /* the key won't work */
+ player.commands_allowed = true;
+ break;
+ }
+ goto handled;
+ }
+
+ if (player_said_2(walk_through, door) || player_said_2(open, door)) {
+ if (inter_point_x < 287) { /* the left door */
+ if (!global[christine_is_in_boat]) { /* lock the left door */
+ switch (kernel.trigger) {
+ case 0:
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_take_6] = kernel_seq_forward(ss[fx_take_6], false, 5, 0, 0, 1);
+ kernel_seq_range(seq[fx_take_6], 1, 4);
+ kernel_seq_player(seq[fx_take_6], true);
+ kernel_seq_trigger(seq[fx_take_6], KERNEL_TRIGGER_EXPIRE, 0, 1);
+ break;
+
+ case 1:
+ temp = seq[fx_take_6];
+ seq[fx_take_6] = kernel_seq_stamp(ss[fx_take_6], false, 4);
+ kernel_synch(KERNEL_SERIES, seq[fx_take_6], KERNEL_SERIES, temp);
+ kernel_seq_player(seq[fx_take_6], false);
+ kernel_timing_trigger(QUARTER_SECOND, 2);
+ sound_play(N_DoorHandle005);
+ break;
+
+ case 2:
+ kernel_seq_delete(seq[fx_take_6]);
+ seq[fx_take_6] = kernel_seq_backward(ss[fx_take_6], false, 5, 0, 0, 1);
+ kernel_seq_range(seq[fx_take_6], 1, 4);
+ kernel_seq_player(seq[fx_take_6], false);
+ kernel_seq_trigger(seq[fx_take_6], KERNEL_TRIGGER_EXPIRE, 0, 3);
+ break;
+
+ case 3:
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_SERIES, seq[fx_take_6]);
+ player.walker_visible = true;
+ text_show(text_501_20);
+ /* the door is locked */
+ player.commands_allowed = true;
+ break;
+ }
+ goto handled;
+
+ } else { /* Christine is in boat, unlock left door (to get oar) */
+
+ switch (kernel.trigger) {
+ case (0):
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_take_6] = kernel_seq_pingpong(ss[fx_take_6], false,
+ 5, 0, 0, 2);
+ kernel_seq_range(seq[fx_take_6], 1, 4);
+ kernel_seq_player(seq[fx_take_6], true);
+ kernel_seq_trigger(seq[fx_take_6],
+ KERNEL_TRIGGER_SPRITE, 4, ROOM_501_DOOR_OPENS);
+ kernel_seq_trigger(seq[fx_take_6],
+ KERNEL_TRIGGER_EXPIRE, 0, ROOM_501_DOOR_OPENS + 2);
+ break;
+
+ case ROOM_501_DOOR_OPENS:
+ kernel_seq_delete(seq[fx_left_door]);
+ seq[fx_left_door] = kernel_seq_forward(ss[fx_left_door], false,
+ 8, 0, 0, 1);
+ kernel_seq_depth(seq[fx_left_door], 4);
+ kernel_seq_range(seq[fx_left_door], KERNEL_FIRST, KERNEL_LAST);
+ kernel_seq_trigger(seq[fx_left_door],
+ KERNEL_TRIGGER_EXPIRE, 0, ROOM_501_DOOR_OPENS + 1);
+ sound_play(N_DoorOpens);
+ break;
+
+ case ROOM_501_DOOR_OPENS + 1:
+ seq[fx_left_door] = kernel_seq_stamp
+ (ss[fx_left_door], false, KERNEL_LAST);
+ kernel_seq_depth(seq[fx_left_door], 1);
+ player_walk(PLAYER_X_FROM_506, PLAYER_Y_FROM_506, FACING_EAST);
+ player_walk_trigger(ROOM_501_DOOR_OPENS + 3);
+ break;
+
+ case ROOM_501_DOOR_OPENS + 2:
+ player.walker_visible = true;
+ break;
+
+ case ROOM_501_DOOR_OPENS + 3:
+ conv_abort();
+ new_room = 506;
+ break;
+ }
+ goto handled;
+ }
+
+ } else { /* the right door */
+
+ if (!global[christine_is_in_boat]) {
+ switch (kernel.trigger) {
+ case (0):
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_take_6] = kernel_seq_pingpong(ss[fx_take_6], false,
+ 5, 0, 0, 2);
+ kernel_seq_range(seq[fx_take_6], 1, 4);
+ kernel_seq_player(seq[fx_take_6], true);
+ kernel_seq_trigger(seq[fx_take_6],
+ KERNEL_TRIGGER_SPRITE, 4, ROOM_501_DOOR_OPENS);
+ kernel_seq_trigger(seq[fx_take_6],
+ KERNEL_TRIGGER_EXPIRE, 0, ROOM_501_DOOR_OPENS + 2);
+ break;
+
+ case ROOM_501_DOOR_OPENS:
+ temp = seq[fx_door];
+ kernel_seq_delete(seq[fx_door]);
+ seq[fx_door] = kernel_seq_forward(ss[fx_door], false,
+ 8, 0, 0, 1);
+ kernel_synch(KERNEL_SERIES, seq[fx_door], KERNEL_SERIES, temp);
+ kernel_seq_depth(seq[fx_door], 4);
+ kernel_seq_range(seq[fx_door], KERNEL_FIRST, KERNEL_LAST);
+ kernel_seq_trigger(seq[fx_door],
+ KERNEL_TRIGGER_EXPIRE, 0, ROOM_501_DOOR_OPENS + 1);
+ sound_play(N_DoorOpens);
+ break;
+
+ case ROOM_501_DOOR_OPENS + 1:
+ player_walk(PLAYER_X_FROM_502, PLAYER_Y_FROM_502, FACING_NORTHWEST);
+ player_walk_trigger(ROOM_501_DOOR_OPENS + 3);
+ break;
+
+ case ROOM_501_DOOR_OPENS + 2:
+ player.walker_visible = true;
+ break;
+
+ case ROOM_501_DOOR_OPENS + 3:
+ seq[fx_door] = kernel_seq_backward(ss[fx_door], false,
+ 8, 0, 0, 1);
+ kernel_seq_depth(seq[fx_door], 1);
+ kernel_seq_range(seq[fx_door], KERNEL_FIRST, KERNEL_LAST);
+ kernel_seq_trigger(seq[fx_door],
+ KERNEL_TRIGGER_EXPIRE, 0, ROOM_501_DOOR_OPENS + 4);
+ sound_play(N_DoorCloses);
+ break;
+
+ case ROOM_501_DOOR_OPENS + 4:
+ seq[fx_door] = kernel_seq_stamp(ss[fx_door], false, 5);
+ kernel_seq_depth(seq[fx_door], 1);
+ new_room = 502;
+ break;
+ }
+ goto handled;
+
+ } else { /* she is in the boat - lock the right door */
+
+ switch (kernel.trigger) {
+ case (0):
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_take_6] = kernel_seq_forward(ss[fx_take_6], false, 5, 0, 0, 1);
+ kernel_seq_range(seq[fx_take_6], 1, 4);
+ kernel_seq_player(seq[fx_take_6], true);
+ kernel_seq_trigger(seq[fx_take_6], KERNEL_TRIGGER_EXPIRE, 0, 1);
+ break;
+
+ case 1:
+ temp = seq[fx_take_6];
+ seq[fx_take_6] = kernel_seq_stamp(ss[fx_take_6], false, 4);
+ kernel_synch(KERNEL_SERIES, seq[fx_take_6], KERNEL_SERIES, temp);
+ kernel_seq_player(seq[fx_take_6], false);
+ kernel_timing_trigger(QUARTER_SECOND, 2);
+ sound_play(N_DoorHandle);
+ break;
+
+ case 2:
+ kernel_seq_delete(seq[fx_take_6]);
+ seq[fx_take_6] = kernel_seq_backward(ss[fx_take_6], false, 5, 0, 0, 1);
+ kernel_seq_range(seq[fx_take_6], 1, 4);
+ kernel_seq_player(seq[fx_take_6], false);
+ kernel_seq_trigger(seq[fx_take_6], KERNEL_TRIGGER_EXPIRE, 0, 3);
+ break;
+
+ case 3:
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_SERIES, seq[fx_take_6]);
+ player.walker_visible = true;
+ text_show(text_501_20);
+ /* the door is locked */
+ player.commands_allowed = true;
+ break;
+ }
+ goto handled;
+ }
+ }
+ }
+
+ if (player.look_around) {
+ text_show(text_501_10);
+ goto handled;
+ }
+
+ if (player_said_1(look) || player_said_1(look_at)) {
+
+ if (player_said_1(floor)) {
+ text_show(text_501_11);
+ goto handled;
+ }
+
+ if (player_said_1(wall)) {
+ text_show(text_501_12);
+ goto handled;
+ }
+
+ if (player_said_1(ceiling)) {
+ text_show(text_501_13);
+ goto handled;
+ }
+
+ if (player_said_1(lake)) {
+ text_show(text_501_14);
+ goto handled;
+ }
+
+ if (player_said_1(boat)) {
+ text_show(text_501_26);
+ goto handled;
+ }
+
+ if (player_said_1(torch)) {
+ text_show(text_501_17);
+ goto handled;
+ }
+
+ if (player_said_1(archway_to_west)) {
+ text_show(text_501_18);
+ goto handled;
+ }
+
+ if (player_said_1(door)) {
+ if (inter_point_x < 287) { /* the left door */
+ if (player_has_been_in_room(506)) {
+ text_show(text_501_27);
+ } else {
+ text_show(text_501_19);
+ }
+ } else {
+ if (player_has_been_in_room(506)) {
+ text_show(text_501_28);
+ } else {
+ text_show(text_501_19);
+ }
+ }
+ goto handled;
+ }
+
+ if (player_said_1(column)) {
+ text_show(text_501_21);
+ goto handled;
+ }
+
+ if (player_said_1(Christine)) {
+ text_show(text_501_24);
+ goto handled;
+ }
+ }
+
+ if (player_said_2(take, torch)) {
+ text_show(text_501_25);
+ goto handled;
+ }
+
+ if (player_said_2(take, Christine)) {
+ text_show(text_501_29);
+ goto handled;
+ }
+
+ goto done;
+
+handled:
+ player.command_ready = false;
+
+done:
+ ;
+}
+
+void room_501_daemon() {
+ int id;
+
+ /* ==================== Close right door ===================== */
+
+ switch (kernel.trigger) {
+ case ROOM_501_LEFT_DOOR_CLOSES:
+ kernel_seq_delete(seq[fx_left_door]);
+ seq[fx_left_door] = kernel_seq_backward(ss[fx_left_door], false,
+ 8, 0, 0, 1);
+ kernel_seq_depth(seq[fx_left_door], 10);
+ kernel_seq_range(seq[fx_left_door], KERNEL_FIRST, KERNEL_LAST);
+ kernel_seq_trigger(seq[fx_left_door],
+ KERNEL_TRIGGER_EXPIRE, 0, ROOM_501_LEFT_DOOR_CLOSES + 1);
+ break;
+
+ case ROOM_501_LEFT_DOOR_CLOSES + 1:
+ sound_play(N_DoorCloses);
+ seq[fx_left_door] = kernel_seq_stamp(ss[fx_left_door], false, 1);
+ kernel_seq_depth(seq[fx_left_door], 10);
+ if (!global[chris_will_take_seat]) {
+ player.commands_allowed = true;
+ }
+ global[chris_will_take_seat] = false;
+ break;
+ }
+
+ switch (kernel.trigger) {
+ case ROOM_501_DOOR_CLOSES:
+ seq[fx_door] = kernel_seq_backward(ss[fx_door], false,
+ 8, 0, 0, 1);
+ kernel_seq_depth(seq[fx_door], 4);
+ kernel_seq_range(seq[fx_door], KERNEL_FIRST, KERNEL_LAST);
+ kernel_seq_trigger(seq[fx_door],
+ KERNEL_TRIGGER_EXPIRE, 0, ROOM_501_DOOR_CLOSES + 1);
+ break;
+
+ case ROOM_501_DOOR_CLOSES + 1:
+ sound_play(N_DoorCloses);
+ seq[fx_door] = kernel_seq_stamp(ss[fx_door], false, KERNEL_FIRST);
+ kernel_seq_depth(seq[fx_door], 4);
+ player.commands_allowed = true;
+ break;
+
+ case ROOM_501_FROM_506:
+ player_walk(WALK_TO_X_FROM_506 - 5, WALK_TO_Y_FROM_506 + 6, FACING_NORTHWEST);
+ kernel_reset_animation(aa[0], 2);
+ id = kernel_add_dynamic(words_Christine, words_walk_to, SYNTAX_SINGULAR_FEM, KERNEL_NONE,
+ 0, 0, 0, 0);
+ kernel_dynamic_anim(id, aa[0], 0);
+ kernel_dynamic_anim(id, aa[0], 1);
+ kernel_dynamic_anim(id, aa[0], 2);
+ kernel_dynamic_anim(id, aa[0], 3);
+ break;
+
+ case ROOM_501_START_ROWING:
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_shove_off] = kernel_seq_forward(ss[fx_shove_off], false,
+ 9, 0, 0, 1);
+ kernel_seq_range(seq[fx_shove_off], KERNEL_FIRST, KERNEL_LAST);
+ kernel_seq_trigger(seq[fx_shove_off],
+ KERNEL_TRIGGER_EXPIRE, 0, ROOM_501_SHOVE_OFF);
+ break;
+
+ case ROOM_501_SHOVE_OFF:
+ global[player_score] += 5;
+ new_room = 310;
+ break;
+ }
+
+ if (local->anim_0_running) {
+ if (kernel_anim[aa[0]].frame == 103) {
+ kernel_flip_hotspot_loc(words_Christine, true, CHRIS_X_RIGHT, CHRIS_Y_RIGHT);
+ }
+
+ if ((kernel_anim[aa[0]].frame == 28) && (!local->prevent_2)) {
+ local->prevent_2 = true;
+ kernel_timing_trigger(1, ROOM_501_LEFT_DOOR_CLOSES);
+ }
+
+ if (kernel_anim[aa[0]].frame == 124) {
+ kernel_flip_hotspot_loc(words_Christine, false, CHRIS_X_RIGHT, CHRIS_Y_RIGHT);
+ kernel_flip_hotspot_loc(words_Christine, true, CHRIS_X_LEFT, CHRIS_Y_LEFT);
+ }
+
+ if (kernel_anim[aa[0]].frame == 125) {
+ kernel_reset_animation(aa[0], 124);
+ /* repeat Christine waiting in boat */
+ }
+
+ if (kernel_anim[aa[0]].frame == 1) {
+ kernel_reset_animation(aa[0], 0);
+ /* have boat sitting at dock while Chris is getting into it */
+ }
+
+ if (kernel_anim[aa[0]].frame == 84) {
+ player.commands_allowed = true;
+ }
+ }
+}
+
+void room_501_preload() {
+ room_init_code_pointer = room_501_init;
+ room_pre_parser_code_pointer = room_501_pre_parser;
+ room_parser_code_pointer = room_501_parser;
+ room_daemon_code_pointer = room_501_daemon;
+
+ section_5_walker();
+ section_5_interface();
+
+ vocab_make_active(words_Christine);
+ vocab_make_active(words_look_at);
+ vocab_make_active(words_walk_to);
+}
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/rooms/room501.h b/engines/mads/madsv2/phantom/rooms/room501.h
new file mode 100644
index 00000000000..f82250c7a2e
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room501.h
@@ -0,0 +1,113 @@
+/* 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 MADS_PHANTOM_ROOM501_H
+#define MADS_PHANTOM_ROOM501_H
+
+#include "mads/madsv2/core/general.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+#define local ((Scratch *)(&game.scratch[0]))
+#define ss local->sprite
+#define seq local->sequence
+#define aa local->animation
+
+typedef struct { /* Room local variables */
+
+ int16 sprite[15]; /* Sprite series handles */
+ int16 sequence[15]; /* Sequence handles */
+ int16 animation[4]; /* Animation handles */
+ int16 anim_0_running;
+ int16 prevent_2;
+
+} Scratch;
+
+
+/* ========================= Sprite Series =================== */
+
+#define fx_flame 0 /* rm501x0 */
+#define fx_door 1 /* rm501x1 */
+#define fx_left_door 2 /* rm501x2 */
+#define fx_take_6 3 /* rdrr_6 */
+#define fx_boat 4 /* rm501x3 */
+#define fx_shove_off 5 /* rm501a1 */
+#define fx_christine 6 /* *chr_6 */
+ /* *chr_9 */
+ /* *chr_8 */
+
+
+
+/* ========================= Triggers ======================== */
+
+#define ROOM_501_LEFT_DOOR_CLOSES 55
+#define ROOM_501_DOOR_CLOSES 60
+#define ROOM_501_DOOR_OPENS 65
+#define ROOM_501_FROM_506 80
+#define ROOM_501_SHOVE_OFF 90
+#define ROOM_501_START_ROWING 100
+
+/* ========================= Other Macros ==================== */
+
+#define PLAYER_X_FROM_506 305
+#define PLAYER_Y_FROM_506 112
+
+#define WALK_TO_X_FROM_506 260
+#define WALK_TO_Y_FROM_506 112
+
+#define PLAYER_X_FROM_502 319
+#define PLAYER_Y_FROM_502 116
+
+#define WALK_TO_X_FROM_502 286
+#define WALK_TO_Y_FROM_502 119
+
+#define WEST_X -20
+#define WEST_Y 109
+
+#define WALK_TO_WEST_X 24
+#define WALK_TO_WEST_Y 109
+
+#define DOOR_LEFT_X 266
+#define DOOR_LEFT_Y 112
+
+#define DOOR_RIGHT_X 287
+#define DOOR_RIGHT_Y 118
+
+#define CHRIS_X_LEFT 113
+#define CHRIS_Y_LEFT 93
+
+#define CHRIS_X_RIGHT 125
+#define CHRIS_Y_RIGHT 94
+
+#define CONV_MISC 26
+
+#define WALK_TO_CAT_NO_X 24
+#define WALK_TO_CAT_NO_Y 110
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/phantom/rooms/room502.cpp b/engines/mads/madsv2/phantom/rooms/room502.cpp
new file mode 100644
index 00000000000..56c513ef716
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room502.cpp
@@ -0,0 +1,1281 @@
+/* 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 "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/camera.h"
+#include "mads/madsv2/core/cycle.h"
+#include "mads/madsv2/core/env.h"
+#include "mads/madsv2/core/error.h"
+#include "mads/madsv2/core/fileio.h"
+#include "mads/madsv2/core/imath.h"
+#include "mads/madsv2/core/inter.h"
+#include "mads/madsv2/core/matte.h"
+#include "mads/madsv2/core/mem.h"
+#include "mads/madsv2/core/object.h"
+#include "mads/madsv2/core/sound.h"
+#include "mads/madsv2/core/speech.h"
+#include "mads/madsv2/core/text.h"
+#include "mads/madsv2/phantom/mads/speeches.h"
+#include "mads/madsv2/phantom/rooms/section5.h"
+#include "mads/madsv2/phantom/rooms/room502.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+static void room_502_initialize_panels() {
+ int count;
+ int count_2 = 1;
+ int figure = 2;
+ int ss_type;
+
+ for (count = 0; count < 16; count++) {
+
+ if (previous_room != KERNEL_RESTORING_GAME) {
+ local->puzzle_picture[count] = (byte)imath_random(1, 4);
+ }
+
+ figure += (local->puzzle_picture[count] * 3) - 3;
+ local->puzzle_sprite[count] = (byte)figure;
+
+ switch (count) {
+ case 0:
+ case 1:
+ case 2:
+ case 3: ss_type = ss[fx_row_1]; break;
+
+ case 4:
+ case 5:
+ case 6:
+ case 7: ss_type = ss[fx_row_2]; break;
+
+ case 8:
+ case 9:
+ case 10:
+ case 11: ss_type = ss[fx_row_3]; break;
+
+ default: ss_type = ss[fx_row_4]; break;
+ }
+
+ seq[fx_panel] = kernel_seq_stamp(ss_type, false, figure);
+ kernel_seq_depth(seq[fx_panel], 14);
+ local->puzzle_sequence[count] = seq[fx_panel];
+ /* save the handle for later deletion */
+
+ ++count_2;
+ if (count_2 >= 5) {
+ count_2 = 1;
+ }
+
+ switch (count_2) {
+ case 1: figure = 2; break;
+ case 2: figure = 14; break;
+ case 3: figure = 26; break;
+ case 4: figure = 38; break;
+ }
+ }
+}
+
+static void room_502_load_cycling_info() {
+ int error_code = 0;
+ int count;
+ int cycle;
+ int num_colors;
+ int total_colors = 0;
+ byte *chunk = NULL;
+ Common::SeekableReadStream *handle = NULL;
+ RGBcolor *color_marker;
+
+ mem_save_free();
+
+ local->cycle_pointer = NULL;
+
+ chunk = (byte *)mem_get(mem_get_avail() - 256);
+ if (chunk == NULL) goto done;
+
+ color_marker = (RGBcolor *)chunk;
+
+ handle = env_open("*RM502.CYC", "rb");
+ if (handle == NULL) {
+ error_code = 100;
+ goto done;
+ }
+
+ for (count = 0; count < num_cycle_stages; count++) {
+
+ if (!fileio_fread_f(&local->cycle_list[count], sizeof(CycleList), 1, handle)) {
+ error_code = 200 + count;
+ goto done;
+ }
+
+ num_colors = 0;
+ for (cycle = 0; cycle < local->cycle_list[count].num_cycles; cycle++) {
+ local->cycle_list[count].table[cycle].first_list_color = (byte)num_colors;
+ num_colors += local->cycle_list[count].table[cycle].num_colors;
+ }
+
+ local->cycle_color[count] = color_marker;
+
+ if (!fileio_fread_f(color_marker, sizeof(RGBcolor) * num_colors, 1, handle)) {
+ error_code = 300 + count;
+ goto done;
+ }
+
+ color_marker += num_colors;
+ total_colors += num_colors;
+ }
+
+ mem_adjust(chunk, (total_colors * sizeof(RGBcolor)));
+
+ local->cycle_pointer = chunk;
+ local->cycle_bookkeep = 0;
+
+done:
+ delete handle;
+ if (local->cycle_pointer == NULL) {
+ error_report(ERROR_BREAK_POINT, ERROR, MODULE_UNKNOWN, 502, error_code);
+ }
+ mem_restore_free();
+}
+
+static void get_panel_info(int *walk_to_x, int *walk_to_y, int *panel, int mouse_x, int mouse_y, int *interim_x, int *interim_y) {
+ /* walk_to_x will return the x coordinate for walking to that panel */
+ /* walk_to_y will return the y coordinate for walking to that panel */
+ /* panel will return the number of the panel (top row is 1-4, bottom row is 13-16) */
+ /* pass in mouse_x and mouse_y to figure all this shit out */
+
+ *walk_to_y = COLUMN_Y;
+
+ if ((mouse_x >= 120) && (mouse_x <= 139)) {
+ *interim_x = 129;
+ if ((mouse_y >= 75) && (mouse_y <= 90)) {
+ *panel = 0; *interim_y = 90; *walk_to_x = COLUMN_1_X;
+ }
+ if ((mouse_y >= 91) && (mouse_y <= 106)) {
+ *panel = 4; *interim_y = 106; *walk_to_x = COLUMN_1_X;
+ }
+ if ((mouse_y >= 107) && (mouse_y <= 122)) {
+ *panel = 8; *interim_y = 122; *walk_to_x = COLUMN_1_X;
+ }
+ if ((mouse_y >= 123) && (mouse_y <= 137)) {
+ *panel = 12; *interim_y = 138; *walk_to_x = COLUMN_1_X;
+ }
+ }
+
+ if ((mouse_x >= 140) && (mouse_x <= 159)) {
+ *interim_x = 149;
+ if ((mouse_y >= 75) && (mouse_y <= 90)) {
+ *panel = 1; *interim_y = 90; *walk_to_x = COLUMN_2_X;
+ }
+ if ((mouse_y >= 91) && (mouse_y <= 106)) {
+ *panel = 5; *interim_y = 106; *walk_to_x = COLUMN_2_X;
+ }
+ if ((mouse_y >= 107) && (mouse_y <= 122)) {
+ *panel = 9; *interim_y = 122; *walk_to_x = COLUMN_2_X;
+ }
+ if ((mouse_y >= 123) && (mouse_y <= 137)) {
+ *panel = 13; *interim_y = 138; *walk_to_x = COLUMN_2_X;
+ }
+ }
+
+ if ((mouse_x >= 160) && (mouse_x <= 179)) {
+ *interim_x = 169;
+ if ((mouse_y >= 75) && (mouse_y <= 90)) {
+ *panel = 2; *interim_y = 90; *walk_to_x = COLUMN_3_X;
+ }
+ if ((mouse_y >= 91) && (mouse_y <= 106)) {
+ *panel = 6; *interim_y = 106; *walk_to_x = COLUMN_3_X;
+ }
+ if ((mouse_y >= 107) && (mouse_y <= 122)) {
+ *panel = 10; *interim_y = 122; *walk_to_x = COLUMN_3_X;
+ }
+ if ((mouse_y >= 123) && (mouse_y <= 137)) {
+ *panel = 14; *interim_y = 138; *walk_to_x = COLUMN_3_X;
+ }
+ }
+
+ if ((mouse_x >= 180) && (mouse_x <= 199)) {
+ *interim_x = 189;
+ if ((mouse_y >= 75) && (mouse_y <= 90)) {
+ *panel = 3; *interim_y = 90; *walk_to_x = COLUMN_4_X;
+ }
+ if ((mouse_y >= 91) && (mouse_y <= 106)) {
+ *panel = 7; *interim_y = 106; *walk_to_x = COLUMN_4_X;
+ }
+ if ((mouse_y >= 107) && (mouse_y <= 122)) {
+ *panel = 11; *interim_y = 122; *walk_to_x = COLUMN_4_X;
+ }
+ if ((mouse_y >= 123) && (mouse_y <= 137)) {
+ *panel = 15; *interim_y = 138; *walk_to_x = COLUMN_4_X;
+ }
+ }
+}
+
+static void animate_panels() {
+ int temp; /* for synching purposes */
+ int new_sprite;
+ int count;
+ int yippie = true;
+
+ switch (kernel.trigger) {
+ case ROOM_502_ANIMATE_PANELS:
+ sound_play(N_PanelClank);
+ kernel_seq_delete(local->puzzle_sequence[local->panel_pushed]);
+ switch (local->panel_pushed) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ seq[fx_row_1] = kernel_seq_stamp(ss[fx_row_1], false, local->puzzle_sprite[local->panel_pushed] - 1);
+ kernel_seq_depth(seq[fx_row_1], 14);
+ kernel_timing_trigger(5, ROOM_502_ANIMATE_PANELS + 1);
+ break;
+
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ seq[fx_row_2] = kernel_seq_stamp(ss[fx_row_2], false, local->puzzle_sprite[local->panel_pushed] - 1);
+ kernel_seq_depth(seq[fx_row_2], 14);
+ kernel_timing_trigger(5, ROOM_502_ANIMATE_PANELS + 1);
+ break;
+
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ seq[fx_row_3] = kernel_seq_stamp(ss[fx_row_3], false, local->puzzle_sprite[local->panel_pushed] - 1);
+ kernel_seq_depth(seq[fx_row_3], 14);
+ kernel_timing_trigger(5, ROOM_502_ANIMATE_PANELS + 1);
+ break;
+
+ default:
+ seq[fx_row_4] = kernel_seq_stamp(ss[fx_row_4], false, local->puzzle_sprite[local->panel_pushed] - 1);
+ kernel_seq_depth(seq[fx_row_4], 14);
+ kernel_timing_trigger(5, ROOM_502_ANIMATE_PANELS + 1);
+ break;
+ }
+ break;
+
+ case ROOM_502_ANIMATE_PANELS + 1:
+ switch (local->panel_pushed) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ kernel_seq_delete(seq[fx_row_1]);
+ break;
+
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ kernel_seq_delete(seq[fx_row_2]);
+ break;
+
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ kernel_seq_delete(seq[fx_row_3]);
+ break;
+
+ default:
+ kernel_seq_delete(seq[fx_row_4]);
+ break;
+ }
+
+ seq[fx_interim] = kernel_seq_forward(ss[fx_interim], false, 5, 0, 0, 1);
+ kernel_seq_depth(seq[fx_interim], 14);
+ kernel_seq_loc(seq[fx_interim], local->interim_x, local->interim_y);
+ kernel_seq_range(seq[fx_interim], KERNEL_FIRST, KERNEL_LAST);
+ kernel_seq_trigger(seq[fx_interim], KERNEL_TRIGGER_EXPIRE, 0, ROOM_502_ANIMATE_PANELS + 2);
+ break;
+
+ case ROOM_502_ANIMATE_PANELS + 2:
+ temp = seq[fx_interim];
+
+ switch (local->panel_pushed) {
+ case 0:
+ case 4:
+ case 8:
+ case 12:
+ new_sprite = local->puzzle_sprite[local->panel_pushed] + 4;
+ if (new_sprite > 12) {
+ new_sprite = 3;
+ }
+ break;
+
+ case 1:
+ case 5:
+ case 9:
+ case 13:
+ new_sprite = local->puzzle_sprite[local->panel_pushed] + 4;
+ if (new_sprite > 24) {
+ new_sprite = 15;
+ }
+ break;
+
+ case 2:
+ case 6:
+ case 10:
+ case 14:
+ new_sprite = local->puzzle_sprite[local->panel_pushed] + 4;
+ if (new_sprite > 36) {
+ new_sprite = 27;
+ }
+ break;
+
+ default:
+ new_sprite = local->puzzle_sprite[local->panel_pushed] + 4;
+ if (new_sprite > 48) {
+ new_sprite = 39;
+ }
+ break;
+ }
+
+ switch (local->panel_pushed) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ seq[fx_row_1] = kernel_seq_stamp(ss[fx_row_1], false, new_sprite);
+ kernel_seq_depth(seq[fx_row_1], 14);
+ kernel_synch(KERNEL_SERIES, seq[fx_row_1], KERNEL_SERIES, temp);
+ kernel_timing_trigger(5, ROOM_502_ANIMATE_PANELS + 3);
+ break;
+
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ seq[fx_row_2] = kernel_seq_stamp(ss[fx_row_2], false, new_sprite);
+ kernel_seq_depth(seq[fx_row_2], 14);
+ kernel_synch(KERNEL_SERIES, seq[fx_row_2], KERNEL_SERIES, temp);
+ kernel_timing_trigger(5, ROOM_502_ANIMATE_PANELS + 3);
+ break;
+
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ seq[fx_row_3] = kernel_seq_stamp(ss[fx_row_3], false, new_sprite);
+ kernel_seq_depth(seq[fx_row_3], 14);
+ kernel_synch(KERNEL_SERIES, seq[fx_row_3], KERNEL_SERIES, temp);
+ kernel_timing_trigger(5, ROOM_502_ANIMATE_PANELS + 3);
+ break;
+
+ default:
+ seq[fx_row_4] = kernel_seq_stamp(ss[fx_row_4], false, new_sprite);
+ kernel_seq_depth(seq[fx_row_4], 14);
+ kernel_synch(KERNEL_SERIES, seq[fx_row_4], KERNEL_SERIES, temp);
+ kernel_timing_trigger(5, ROOM_502_ANIMATE_PANELS + 3);
+ break;
+ }
+ break;
+
+ case ROOM_502_ANIMATE_PANELS + 3:
+
+
+ switch (local->panel_pushed) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ kernel_seq_delete(seq[fx_row_1]);
+ break;
+
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ kernel_seq_delete(seq[fx_row_2]);
+ break;
+
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ kernel_seq_delete(seq[fx_row_3]);
+ break;
+
+ default:
+ kernel_seq_delete(seq[fx_row_4]);
+ break;
+ }
+
+ new_sprite = local->puzzle_sprite[local->panel_pushed] + 3;
+
+ switch (local->panel_pushed) {
+ case 0:
+ case 4:
+ case 8:
+ case 12:
+ if (new_sprite > 12) {
+ new_sprite = 2;
+ }
+ break;
+
+ case 1:
+ case 5:
+ case 9:
+ case 13:
+ if (new_sprite > 24) {
+ new_sprite = 14;
+ }
+ break;
+
+ case 2:
+ case 6:
+ case 10:
+ case 14:
+ if (new_sprite > 36) {
+ new_sprite = 26;
+ }
+ break;
+
+ default:
+ if (new_sprite > 48) {
+ new_sprite = 38;
+ }
+ break;
+ }
+ local->puzzle_sprite[local->panel_pushed] = (byte)new_sprite;
+ ++local->puzzle_picture[local->panel_pushed];
+ if (local->puzzle_picture[local->panel_pushed] >= 5) {
+ local->puzzle_picture[local->panel_pushed] = 1;
+ }
+
+ switch (local->panel_pushed) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ seq[fx_row_1] = kernel_seq_stamp(ss[fx_row_1], false, new_sprite);
+ kernel_seq_depth(seq[fx_row_1], 14);
+ local->puzzle_sequence[local->panel_pushed] = seq[fx_row_1];
+ break;
+
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ seq[fx_row_2] = kernel_seq_stamp(ss[fx_row_2], false, new_sprite);
+ kernel_seq_depth(seq[fx_row_2], 14);
+ local->puzzle_sequence[local->panel_pushed] = seq[fx_row_2];
+ break;
+
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ seq[fx_row_3] = kernel_seq_stamp(ss[fx_row_3], false, new_sprite);
+ kernel_seq_depth(seq[fx_row_3], 14);
+ local->puzzle_sequence[local->panel_pushed] = seq[fx_row_3];
+ break;
+
+ default:
+ seq[fx_row_4] = kernel_seq_stamp(ss[fx_row_4], false, new_sprite);
+ kernel_seq_depth(seq[fx_row_4], 14);
+ local->puzzle_sequence[local->panel_pushed] = seq[fx_row_4];
+ break;
+ }
+
+ for (count = 0; count < 16; count++) {
+ if (local->puzzle_picture[count] != 1) {
+ yippie = false;
+ }
+ }
+
+ if (yippie) {
+ if (!local->yippie) {
+ local->yippie = true;
+ kernel_seq_delete(seq[fx_trap_door]);
+ aa[0] = kernel_run_animation(kernel_name('t', 1), ROOM_502_TRAP_DOOR_OPEN);
+ }
+ }
+ break;
+ }
+}
+
+
+void room_502_init() {
+ room_502_load_cycling_info(); /* Top of init code */
+
+ global_speech_load(speech_raoul_fire);
+
+ local->panel_pushed = -1;
+ local->turning_panel = false;
+ local->fire_1_on = false;
+ local->fire_2_on = false;
+ local->fire_3_on = false;
+ local->fire_4_on = false;
+
+ if (previous_room != KERNEL_RESTORING_GAME) {
+ local->hot_clock = kernel.clock;
+ local->cycle_stage = 0;
+ local->hot_timer = 0;
+ local->death_timer = 0;
+ local->message_stage = 1;
+ local->room_getting_hotter = true;
+ local->yippie = false;
+ }
+
+ kernel_flip_hotspot(words_rope, false);
+ kernel_flip_hotspot_loc(words_trap_door, false, TRAP_DOOR_HS_X, TRAP_DOOR_HS_Y);
+
+ /* ===================== Load Sprite Series ================== */
+
+ ss[fx_fire_1] = kernel_load_series(kernel_name('x', 2), false);
+ ss[fx_fire_2] = kernel_load_series(kernel_name('x', 3), false);
+ ss[fx_fire_3] = kernel_load_series(kernel_name('x', 4), false);
+ ss[fx_fire_4] = kernel_load_series(kernel_name('x', 5), false);
+ ss[fx_death] = kernel_load_series(kernel_name('a', 2), false);
+ ss[fx_door] = kernel_load_series(kernel_name('x', 0), false);
+ ss[fx_trap_door] = kernel_load_series(kernel_name('x', 1), false);
+ ss[fx_rope_thrower] = kernel_load_series(kernel_name('a', 1), false);
+ ss[fx_rope_climber] = kernel_load_series(kernel_name('a', 3), false);
+ ss[fx_rope] = kernel_load_series(kernel_name('x', 6), false);
+ ss[fx_pusher] = kernel_load_series(kernel_name('a', 0), false);
+ ss[fx_row_1] = kernel_load_series(kernel_name('j', 0), false);
+ ss[fx_row_2] = kernel_load_series(kernel_name('k', 0), false);
+ ss[fx_row_3] = kernel_load_series(kernel_name('l', 0), false);
+ ss[fx_row_4] = kernel_load_series(kernel_name('m', 0), false);
+ ss[fx_interim] = kernel_load_series(kernel_name('h', 0), false);
+
+
+ /* =================== Stamp morphing door =================== */
+
+ if (previous_room != KERNEL_RESTORING_GAME) {
+ seq[fx_door] = kernel_seq_stamp(ss[fx_door], false, 1);
+ kernel_seq_depth(seq[fx_door], 14);
+
+ } else {
+ kernel_draw_to_background(ss[fx_door], KERNEL_LAST, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ }
+
+ /* ========================= Previous Rooms ================== */
+
+ if ((previous_room == 501) || (previous_room != KERNEL_RESTORING_GAME)) {
+
+ if (!player.been_here_before) {
+
+ if (player_has(rope)) {
+ global[cable_hook_was_seperate] = true;
+ } else {
+ global[cable_hook_was_seperate] = false;
+ }
+
+ } else {
+
+ if (global[cable_hook_was_seperate]) {
+ inter_give_to_player(rope);
+ inter_give_to_player(cable_hook);
+ inter_move_object(rope_with_hook, NOWHERE);
+ } else {
+ inter_move_object(rope, NOWHERE);
+ inter_move_object(cable_hook, NOWHERE);
+ inter_give_to_player(rope_with_hook);
+ }
+ }
+
+ player.x = PLAYER_X_FROM_501;
+ player.y = PLAYER_Y_FROM_501;
+ player.facing = FACING_EAST;
+ player.commands_allowed = false;
+ player_walk(WALK_TO_X_FROM_501, WALK_TO_Y_FROM_501, FACING_EAST);
+ player_walk_trigger(ROOM_502_ENTER);
+ }
+
+ room_502_initialize_panels();
+
+ /* ===================== Stamp trap door ===================== */
+
+ if (local->yippie) {
+ seq[fx_trap_door] = kernel_seq_stamp(ss[fx_trap_door], false, 6);
+ kernel_seq_depth(seq[fx_trap_door], 1);
+ kernel_flip_hotspot(words_trap_door, false);
+ kernel_flip_hotspot_loc(words_trap_door, true, TRAP_DOOR_HS_X, TRAP_DOOR_HS_Y);
+ if (!player_has(rope_with_hook) && !player_has(cable_hook)) {
+ seq[fx_rope] = kernel_seq_stamp(ss[fx_rope], false, KERNEL_LAST);
+ kernel_seq_depth(seq[fx_rope], 12);
+ kernel_flip_hotspot(words_rope, true);
+ }
+
+ } else {
+ seq[fx_trap_door] = kernel_seq_stamp(ss[fx_trap_door], false, 1);
+ kernel_seq_depth(seq[fx_trap_door], 14);
+ }
+
+ section_5_music();
+}
+
+void room_502_shutdown() {
+ if (local->cycle_pointer != NULL) {
+ mem_free(local->cycle_pointer);
+ }
+}
+
+void room_502_pre_parser() {
+ int walk_to_x;
+ int walk_to_y;
+ int panel;
+ int interim_x;
+ int interim_y;
+
+ if (player_said_2(push, panel)) {
+ get_panel_info(&walk_to_x, &walk_to_y, &panel, inter_point_x, inter_point_y, &interim_x, &interim_y);
+ player_walk(walk_to_x, walk_to_y, FACING_NORTH);
+ }
+
+ if (player_said_2(climb, rope) ||
+ player_said_2(climb_through, trap_door)) {
+ if (local->yippie) {
+ player_walk(TRAP_DOOR_X, TRAP_DOOR_Y, FACING_NORTH);
+ }
+ }
+
+ if (player_said_3(throw, rope_with_hook, trap_door) ||
+ player_said_2(grapple, trap_door)) {
+ if (local->yippie) {
+ player_walk(THROW_UP_X, THROW_UP_Y, FACING_NORTH);
+ }
+ }
+}
+
+void room_502_parser() {
+ int temp; /* for synching purposes */
+ int walk_to_x;
+ int walk_to_y;
+ int panel;
+ int interim_x;
+ int interim_y;
+
+ if (kernel.trigger >= ROOM_502_ANIMATE_PANELS) {
+ animate_panels();
+ goto handled;
+ }
+
+ switch (kernel.trigger) {
+ case ROOM_502_ROW_1:
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_pusher] = kernel_seq_pingpong(ss[fx_pusher], false, 7, 0, 0, 2);
+ kernel_seq_player(seq[fx_pusher], true);
+ kernel_seq_depth(seq[fx_pusher], 1);
+ kernel_seq_range(seq[fx_pusher], 14, 18);
+ kernel_seq_trigger(seq[fx_pusher], KERNEL_TRIGGER_EXPIRE, 0, ROOM_502_ROW_1 + 1);
+ kernel_seq_trigger(seq[fx_pusher], KERNEL_TRIGGER_SPRITE, 18, ROOM_502_ANIMATE_PANELS);
+ goto handled;
+ break;
+
+ case ROOM_502_ROW_1 + 1:
+ temp = seq[fx_pusher];
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_SERIES, temp);
+ player.walker_visible = true;
+ player.commands_allowed = true;
+ kernel_timing_trigger(5, ROOM_502_ROW_3 + 2);
+ goto handled;
+ break;
+
+ case ROOM_502_ROW_2:
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_pusher] = kernel_seq_pingpong(ss[fx_pusher], false, 7, 0, 0, 2);
+ kernel_seq_player(seq[fx_pusher], true);
+ kernel_seq_depth(seq[fx_pusher], 1);
+ kernel_seq_range(seq[fx_pusher], 8, 13);
+ kernel_seq_trigger(seq[fx_pusher], KERNEL_TRIGGER_EXPIRE, 0, ROOM_502_ROW_2 + 1);
+ kernel_seq_trigger(seq[fx_pusher], KERNEL_TRIGGER_SPRITE, 13, ROOM_502_ANIMATE_PANELS);
+ goto handled;
+ break;
+
+ case ROOM_502_ROW_2 + 1:
+ temp = seq[fx_pusher];
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_SERIES, temp);
+ player.walker_visible = true;
+ player.commands_allowed = true;
+ kernel_timing_trigger(5, ROOM_502_ROW_3 + 2);
+ goto handled;
+ break;
+
+ case ROOM_502_ROW_3:
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_pusher] = kernel_seq_pingpong(ss[fx_pusher], false, 9, 0, 0, 2);
+ kernel_seq_player(seq[fx_pusher], true);
+ kernel_seq_depth(seq[fx_pusher], 1);
+ kernel_seq_range(seq[fx_pusher], 5, 7);
+ kernel_seq_trigger(seq[fx_pusher], KERNEL_TRIGGER_EXPIRE, 0, ROOM_502_ROW_3 + 1);
+ kernel_seq_trigger(seq[fx_pusher], KERNEL_TRIGGER_SPRITE, 7, ROOM_502_ANIMATE_PANELS);
+ goto handled;
+ break;
+
+ case ROOM_502_ROW_3 + 1:
+ temp = seq[fx_pusher];
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_SERIES, temp);
+ player.walker_visible = true;
+ kernel_timing_trigger(5, ROOM_502_ROW_3 + 2);
+ goto handled;
+ break;
+
+ case ROOM_502_ROW_3 + 2:
+ local->turning_panel = false;
+ player.commands_allowed = true;
+ goto handled;
+ break;
+
+ case ROOM_502_ROW_4:
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_pusher] = kernel_seq_pingpong(ss[fx_pusher], false, 8, 0, 0, 2);
+ kernel_seq_player(seq[fx_pusher], true);
+ kernel_seq_depth(seq[fx_pusher], 1);
+ kernel_seq_range(seq[fx_pusher], 1, 4);
+ kernel_seq_trigger(seq[fx_pusher], KERNEL_TRIGGER_EXPIRE, 0, ROOM_502_ROW_4 + 1);
+ kernel_seq_trigger(seq[fx_pusher], KERNEL_TRIGGER_SPRITE, 4, ROOM_502_ANIMATE_PANELS);
+ goto handled;
+ break;
+
+ case ROOM_502_ROW_4 + 1:
+ temp = seq[fx_pusher];
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_SERIES, temp);
+ player.walker_visible = true;
+ kernel_timing_trigger(5, ROOM_502_ROW_3 + 2);
+ goto handled;
+ break;
+
+ case ROOM_502_TRAP_DOOR_OPEN:
+ seq[fx_trap_door] = kernel_seq_stamp(ss[fx_trap_door], false, 6);
+ kernel_flip_hotspot_loc(words_rope, true, TRAP_DOOR_HS_X, TRAP_DOOR_HS_Y);
+ kernel_seq_depth(seq[fx_trap_door], 1);
+ kernel_flip_hotspot(words_trap_door, false);
+ kernel_flip_hotspot_loc(words_trap_door, true, TRAP_DOOR_HS_X, TRAP_DOOR_HS_Y);
+ if (!local->turning_panel) {
+ text_show(text_502_16);
+ }
+ goto handled;
+ break;
+ }
+
+ if (player_said_2(push, panel)) {
+ if (local->turning_panel) {
+ goto handled;
+ }
+
+ get_panel_info(&walk_to_x, &walk_to_y, &panel, inter_point_x, inter_point_y, &interim_x, &interim_y);
+
+ local->panel_pushed = (byte)panel;
+ local->interim_x = interim_x;
+ local->interim_y = (byte)interim_y;
+ local->turning_panel = true;
+
+ switch (panel) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ kernel_timing_trigger(1, ROOM_502_ROW_1);
+ break;
+
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ kernel_timing_trigger(1, ROOM_502_ROW_2);
+ break;
+
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ kernel_timing_trigger(1, ROOM_502_ROW_3);
+ break;
+
+ default:
+ kernel_timing_trigger(1, ROOM_502_ROW_4);
+ break;
+ }
+ goto handled;
+ }
+
+ if (player_said_3(throw, rope_with_hook, trap_door) ||
+ player_said_2(grapple, trap_door)) {
+ if (local->yippie) {
+ switch (kernel.trigger) {
+ case 0:
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ local->turning_panel = true;
+ seq[fx_rope_thrower] = kernel_seq_forward(ss[fx_rope_thrower], false, 6, 0, 0, 1);
+ kernel_seq_depth(seq[fx_rope_thrower], 13);
+ kernel_seq_range(seq[fx_rope_thrower], KERNEL_FIRST, KERNEL_LAST);
+ kernel_seq_trigger(seq[fx_rope_thrower], KERNEL_TRIGGER_EXPIRE, 0, ROOM_502_THROW_UP);
+ kernel_seq_trigger(seq[fx_rope_thrower], KERNEL_TRIGGER_SPRITE, 10, ROOM_502_THROW_UP + 1);
+ inter_move_object(rope_with_hook, NOWHERE);
+ break;
+
+ case ROOM_502_THROW_UP + 1:
+ sound_play(N_LassoThrow);
+ break;
+
+ case ROOM_502_THROW_UP:
+ temp = seq[fx_rope_thrower];
+ player.commands_allowed = true;
+ player.walker_visible = true;
+ local->turning_panel = false;
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_SERIES, temp);
+ seq[fx_rope] = kernel_seq_stamp(ss[fx_rope], false, KERNEL_LAST);
+ kernel_seq_depth(seq[fx_rope], 13);
+ kernel_flip_hotspot(words_rope, true);
+ break;
+ }
+
+ } else {
+ text_show(text_502_29);
+ /* throw rope with hook at trap door when it is closed */
+ }
+ goto handled;
+ }
+
+ if (player_said_2(climb_through, trap_door)) {
+ if (player_has(rope_with_hook) || player_has(cable_hook)) {
+ text_show(text_502_28);
+ /* climb through trap door when rope is not installed */
+ goto handled;
+ }
+ }
+
+ if (player_said_3(throw, rope, trap_door)) {
+ text_show(text_502_26);
+ /* throw just the rope at trap door */
+ goto handled;
+ }
+
+ if (player_said_3(throw, cable_hook, trap_door)) {
+ text_show(text_502_27);
+ /* throw just the cable hook at trap door */
+ goto handled;
+ }
+
+ if (player_said_2(climb, rope) || player_said_2(climb_through, trap_door)) {
+ switch (kernel.trigger) {
+ case 0:
+ global[player_score] += 5;
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ local->turning_panel = true;
+ seq[fx_rope_climber] = kernel_seq_forward(ss[fx_rope_climber], false, 6, 0, 0, 1);
+ kernel_seq_depth(seq[fx_rope_climber], 10);
+ kernel_seq_range(seq[fx_rope_climber], KERNEL_FIRST, KERNEL_LAST);
+ kernel_seq_trigger(seq[fx_rope_climber], KERNEL_TRIGGER_EXPIRE, 0, ROOM_502_THROW_UP);
+ break;
+
+ case ROOM_502_THROW_UP:
+ new_room = 504;
+ break;
+ }
+ goto handled;
+ }
+
+ if (player.look_around) {
+ text_show(text_502_10);
+ goto handled;
+ }
+
+ if (player_said_1(look) || player_said_1(look_at)) {
+
+ if (player_said_1(floor)) {
+ text_show(text_502_17);
+ goto handled;
+ }
+
+ if (player_said_1(trap_door)) {
+ if (local->yippie) {
+ text_show(text_502_20);
+ } else {
+ text_show(text_502_25);
+ }
+ goto handled;
+ }
+
+ if (player_said_1(wall)) {
+ text_show(text_502_19);
+ goto handled;
+ }
+
+ if (player_said_1(door)) {
+ text_show(text_502_21);
+ goto handled;
+ }
+
+ if (player_said_1(panels)) {
+ text_show(text_502_22);
+ goto handled;
+ }
+
+ if (player_said_1(panel)) {
+ text_show(text_502_23);
+ goto handled;
+ }
+
+ if (player_said_1(ceiling)) {
+ text_show(text_502_24);
+ goto handled;
+ }
+
+ if (player_said_1(rope)) {
+ if (!player_has(rope) && !player_has(cable_hook) && !player_has(rope_with_hook)) {
+ text_show(text_502_33);
+ goto handled;
+ }
+ }
+ }
+
+ if (player_said_2(open, trap_door)) {
+ if (local->yippie) {
+ text_show(text_502_30);
+ } else {
+ text_show(text_502_28);
+ }
+ goto handled;
+ }
+
+ if (player_said_2(close, trap_door)) {
+ if (local->yippie) {
+ text_show(text_502_28);
+ } else {
+ text_show(text_502_31);
+ }
+ goto handled;
+ }
+
+ if (player_said_2(take, rope)) {
+ if (!player_has(rope) && !player_has(cable_hook) && !player_has(rope_with_hook)) {
+ text_show(text_502_34);
+ goto handled;
+ }
+ }
+
+ if (player_said_2(lasso, trap_door)) {
+ text_show(text_502_32);
+ goto handled;
+ }
+
+ goto done;
+
+handled:
+ player.command_ready = false;
+
+done:
+ ;
+}
+
+static void animate_fire_bursts() {
+ int trig;
+
+ if (local->room_getting_hotter) {
+ trig = imath_random(1, 50);
+ } else {
+ trig = imath_random(1, 400);
+ }
+
+ if (trig == 1) {
+
+ trig = imath_random(1, 4);
+
+ switch (trig) {
+ case 1:
+ if (!local->fire_1_on) {
+ kernel_timing_trigger(imath_random(FIVE_SECONDS, TEN_SECONDS), ROOM_502_FIRE_BURST_1);
+ local->fire_1_on = true;
+ }
+ break;
+
+ case 2:
+ if (!local->fire_2_on) {
+ kernel_timing_trigger(imath_random(FIVE_SECONDS, TEN_SECONDS), ROOM_502_FIRE_BURST_2);
+ local->fire_2_on = true;
+ }
+ break;
+
+ case 3:
+ if (!local->fire_3_on) {
+ kernel_timing_trigger(imath_random(FIVE_SECONDS, TEN_SECONDS), ROOM_502_FIRE_BURST_3);
+ local->fire_3_on = true;
+ }
+ break;
+
+ case 4:
+ if (!local->fire_4_on) {
+ kernel_timing_trigger(imath_random(FIVE_SECONDS, TEN_SECONDS), ROOM_502_FIRE_BURST_4);
+ local->fire_4_on = true;
+ }
+ break;
+ }
+ }
+
+ switch (kernel.trigger) {
+ case ROOM_502_FIRE_BURST_1:
+ if ((player.x < 198) || (player.y > 150)) {
+ seq[fx_fire_1] = kernel_seq_forward(ss[fx_fire_1], false, 5, 0, 0, 1);
+ kernel_seq_depth(seq[fx_fire_1], 14);
+ kernel_seq_range(seq[fx_fire_1], 1, 10);
+ kernel_seq_trigger(seq[fx_fire_1],
+ KERNEL_TRIGGER_EXPIRE, 0, ROOM_502_FIRE_BURST_1 + 1);
+ /* local->fire_1_on = true; */
+ }
+ break;
+
+ case ROOM_502_FIRE_BURST_1 + 1:
+ local->fire_1_on = false;
+ break;
+
+ case ROOM_502_FIRE_BURST_2:
+ if ((player.x > 127) || (player.y < 150)) {
+ seq[fx_fire_2] = kernel_seq_forward(ss[fx_fire_2], false, 5, 0, 0, 1);
+ kernel_seq_depth(seq[fx_fire_2], 1);
+ kernel_seq_range(seq[fx_fire_2], 1, 10);
+ kernel_seq_trigger(seq[fx_fire_2],
+ KERNEL_TRIGGER_EXPIRE, 0, ROOM_502_FIRE_BURST_2 + 1);
+ /* local->fire_2_on = true; */
+ }
+ break;
+
+ case ROOM_502_FIRE_BURST_2 + 1:
+ local->fire_2_on = false;
+ break;
+
+ case ROOM_502_FIRE_BURST_3:
+ if (player.x < 198) {
+ seq[fx_fire_3] = kernel_seq_forward(ss[fx_fire_3], false, 5, 0, 0, 1);
+ kernel_seq_depth(seq[fx_fire_3], 1);
+ kernel_seq_range(seq[fx_fire_3], 1, 10);
+ kernel_seq_trigger(seq[fx_fire_3],
+ KERNEL_TRIGGER_EXPIRE, 0, ROOM_502_FIRE_BURST_3 + 1);
+ /* local->fire_3_on = true; */
+ }
+ break;
+
+ case ROOM_502_FIRE_BURST_3 + 1:
+ local->fire_3_on = false;
+ break;
+
+ case ROOM_502_FIRE_BURST_4:
+ if ((player.x > 110) || (player.y > 150)) {
+ seq[fx_fire_4] = kernel_seq_forward(ss[fx_fire_4], false, 5, 0, 0, 1);
+ kernel_seq_depth(seq[fx_fire_4], 14);
+ kernel_seq_range(seq[fx_fire_4], 1, 10);
+ kernel_seq_trigger(seq[fx_fire_4],
+ KERNEL_TRIGGER_EXPIRE, 0, ROOM_502_FIRE_BURST_4 + 1);
+ /* local->fire_4_on = true; */
+ }
+ break;
+
+ case ROOM_502_FIRE_BURST_4 + 1:
+ local->fire_4_on = false;
+ break;
+ }
+}
+
+static void fastcall room_502_set_cycle() {
+ int save_cycling;
+ int cycle;
+ int color_offset;
+ int num_colors;
+ int num_first_colors;
+ int num_second_colors;
+ CycleListPtr my_cycle;
+ RGBcolor *color_base;
+ RGBcolor *color_marker;
+ RGBcolor *palette_base;
+ RGBcolor *palette_marker;
+
+ if (local->cycle_stage != local->cycle_bookkeep) {
+ save_cycling = cycling_active;
+ cycling_active = false;
+
+ my_cycle = &local->cycle_list[local->cycle_stage];
+ color_base = local->cycle_color[local->cycle_stage];
+
+ for (cycle = 0; cycle < my_cycle->num_cycles; cycle++) {
+ color_marker = color_base + my_cycle->table[cycle].first_list_color;
+
+ palette_base = &cycling_palette[0];
+ palette_base += cycle_list.table[cycle].first_palette_color;
+
+ color_offset = cycle_list.table[cycle].first_list_color;
+
+ num_colors = my_cycle->table[cycle].num_colors;
+ num_first_colors = num_colors - color_offset;
+ num_second_colors = num_colors - num_first_colors;
+
+ palette_marker = palette_base + color_offset;
+
+ memcpy(palette_marker, color_marker, sizeof(RGBcolor) * num_first_colors);
+
+ color_marker += num_first_colors;
+
+ if (num_second_colors) {
+ memcpy(palette_base, color_marker, sizeof(RGBcolor) * num_second_colors);
+ }
+
+ cycle_list.table[cycle].ticks = my_cycle->table[cycle].ticks;
+ }
+
+ local->cycle_bookkeep = local->cycle_stage;
+
+ cycling_active = save_cycling;
+ }
+}
+
+void room_502_daemon() {
+ long dif;
+
+ if (local->room_getting_hotter) {
+ dif = kernel.clock - local->hot_clock;
+ if ((dif >= 0) && (dif <= 4)) {
+ local->hot_timer += dif;
+ local->death_timer += dif;
+ } else {
+ local->hot_timer += 1;
+ local->death_timer += 1;
+ }
+ local->hot_clock = kernel.clock;
+
+ if (local->hot_timer >= CYCLE_SWITCH_TICKS) {
+ local->hot_timer = 0;
+ if (local->cycle_stage < (num_cycle_stages - 1)) {
+ local->cycle_stage++;
+ }
+ }
+ }
+
+
+ if (local->death_timer >= LENGTH_OF_LIFE) {
+ if (!local->turning_panel) {
+ text_show(text_502_15);
+ player_walk(DEATH_X, DEATH_Y, FACING_NORTH);
+ player_walk_trigger(ROOM_502_DEATH);
+ player.commands_allowed = false;
+ local->turning_panel = true;
+ local->death_timer = 0;
+ }
+ }
+
+ if ((local->death_timer > FIFTEEN_SECONDS) && (local->message_stage == 1)) {
+ if (!local->turning_panel) {
+ local->message_stage = 2;
+ text_show(text_502_12);
+ }
+ }
+
+ if ((local->death_timer > SIXTY_SECONDS) && (local->message_stage == 2)) {
+ if (!local->turning_panel) {
+ local->message_stage = 3;
+ text_show(text_502_13);
+ }
+ }
+
+ if ((local->death_timer > NINETY_SECONDS) && (local->message_stage == 3)) {
+ if (!local->turning_panel) {
+ local->message_stage = 4;
+ text_show(text_502_14);
+ }
+ }
+
+ switch (kernel.trigger) {
+ case ROOM_502_DEATH:
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_death] = kernel_seq_forward(ss[fx_death], false, 7, 0, 0, 1);
+ kernel_seq_depth(seq[fx_death], 1);
+ kernel_seq_range(seq[fx_death], KERNEL_FIRST, KERNEL_LAST);
+ kernel_seq_trigger(seq[fx_death], KERNEL_TRIGGER_EXPIRE, 0, ROOM_502_DEATH + 1);
+ kernel_seq_trigger(seq[fx_death], KERNEL_TRIGGER_SPRITE, 44, ROOM_502_DEATH + 2);
+ kernel_seq_trigger(seq[fx_death], KERNEL_TRIGGER_SPRITE, 51, ROOM_502_DEATH + 3);
+ kernel_seq_trigger(seq[fx_death], KERNEL_TRIGGER_SPRITE, 32, ROOM_502_DEATH + 4);
+ break;
+
+ case ROOM_502_DEATH + 1:
+ seq[fx_death] = kernel_seq_stamp(ss[fx_death], false, KERNEL_LAST);
+ kernel_seq_depth(seq[fx_death], 1);
+ inter_turn_off_object();
+ inter_screen_update();
+ kernel_timing_trigger(TWO_SECONDS, ROOM_502_DEATH + 5);
+ break;
+
+ case ROOM_502_DEATH + 5:
+ kernel.force_restart = true;
+ break;
+
+ case ROOM_502_DEATH + 4:
+ global_speech_go(speech_raoul_fire);
+ break;
+
+ case ROOM_502_DEATH + 2:
+ sound_play(N_AllFade);
+ sound_play(N_HeatHiss);
+ break;
+
+ case ROOM_502_DEATH + 3:
+ sound_play(N_PlayerDies);
+ break;
+
+ case ROOM_502_ENTER:
+ kernel_seq_delete(seq[fx_door]);
+ seq[fx_door] = kernel_seq_forward(ss[fx_door], false, 7, 0, 0, 1);
+ kernel_seq_depth(seq[fx_door], 1);
+ kernel_seq_range(seq[fx_door], KERNEL_FIRST, KERNEL_LAST);
+ kernel_seq_trigger(seq[fx_door], KERNEL_TRIGGER_EXPIRE, 0, ROOM_502_ENTER + 1);
+ break;
+
+ case ROOM_502_ENTER + 1:
+ text_show(text_502_11);
+ kernel_draw_to_background(ss[fx_door], KERNEL_LAST, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ player.commands_allowed = true;
+ break;
+ }
+
+ if (!local->yippie) {
+ animate_fire_bursts();
+ }
+
+ room_502_set_cycle();
+}
+
+void room_502_preload() {
+ room_init_code_pointer = room_502_init;
+ room_pre_parser_code_pointer = room_502_pre_parser;
+ room_parser_code_pointer = room_502_parser;
+ room_daemon_code_pointer = room_502_daemon;
+ room_shutdown_code_pointer = room_502_shutdown;
+
+ section_5_walker();
+ section_5_interface();
+}
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/rooms/room502.h b/engines/mads/madsv2/phantom/rooms/room502.h
new file mode 100644
index 00000000000..99ebc651073
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room502.h
@@ -0,0 +1,155 @@
+/* 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 MADS_PHANTOM_ROOM502_H
+#define MADS_PHANTOM_ROOM502_H
+
+#include "mads/madsv2/core/general.h"
+#include "mads/madsv2/core/anim.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+#define local ((Scratch *)(&game.scratch[0]))
+#define ss local->sprite
+#define seq local->sequence
+#define aa local->animation
+
+#define num_cycle_stages 9 /* 9 stages of color cycling */
+
+typedef struct { /* Room local variables */
+
+ byte puzzle_picture[16]; /* one of 4 */
+ byte puzzle_sprite[16]; /* which sprite in ss */
+
+ byte fire_1_on; /* T if fire 1 is shooting from floor */
+ byte fire_2_on;
+ byte fire_3_on;
+ byte fire_4_on;
+ int8 panel_pushed; /* will hold panel #0-15 where mouse clicked */
+ byte turning_panel; /* T if Raoul is moving (jumping, etc) */
+ byte yippie; /* T if puzzle is solved */
+ byte message_stage; /* # is next message to display (1 to 3) */
+ byte room_getting_hotter; /* Set if room getting hot */
+ byte interim_y;
+
+ int16 interim_x; /* will hold interim coordinates for panel_pushed */
+
+ int16 sprite[17]; /* Sprite series handles */
+ int16 sequence[17]; /* Sequence handles */
+ int16 animation[1]; /* Animation handles */
+
+ int16 puzzle_sequence[16]; /* sequence handles for stamps */
+
+ CycleList cycle_list[num_cycle_stages]; /* Cycling lists */
+ RGBcolor *cycle_color[num_cycle_stages]; /* Cycling colors */
+
+ byte *cycle_pointer; /* Master cycle pointer */
+ int16 cycle_bookkeep; /* Cycling bookkeeping */
+ int16 cycle_stage; /* Set desired value (0-6) */
+
+ uint32 hot_clock; /* Last kernel clock */
+ uint32 hot_timer; /* Timer count */
+ uint32 death_timer; /* when this reaches LENGTH_OF_LIFE, die */
+
+} Scratch;
+
+
+/* ========================= Sprite Series =================== */
+
+#define fx_fire_1 0 /* rm502x2 */
+#define fx_fire_2 1 /* rm502x3 */
+#define fx_fire_3 2 /* rm502x4 */
+#define fx_fire_4 3 /* rm502x5 */
+#define fx_death 4 /* rm502a2 */
+#define fx_door 5 /* rm502x0 */
+#define fx_trap_door 6 /* rm502x1 */
+#define fx_rope_thrower 7 /* rm502a1 */
+#define fx_rope_climber 8 /* rm502a3 */
+#define fx_rope 9 /* rm502x6 */
+#define fx_pusher 10 /* rm502a0 */
+
+#define fx_row_1 11 /* rm502j0 */
+#define fx_row_2 12 /* rm502k0 */
+#define fx_row_3 13 /* rm502l0 */
+#define fx_row_4 14 /* rm502m0 */
+#define fx_panel 15
+#define fx_interim 16 /* rm502h0 */
+
+/* ========================= Triggers ======================== */
+
+#define ROOM_502_FIRE_BURST_1 60
+#define ROOM_502_FIRE_BURST_2 63
+#define ROOM_502_FIRE_BURST_3 66
+#define ROOM_502_FIRE_BURST_4 69
+#define ROOM_502_DEATH 71
+#define ROOM_502_ENTER 77
+#define ROOM_502_TRAP_DOOR_OPEN 80
+#define ROOM_502_THROW_UP 82
+
+#define ROOM_502_ROW_1 90
+#define ROOM_502_ROW_2 95
+#define ROOM_502_ROW_3 100
+#define ROOM_502_ROW_4 105
+#define ROOM_502_ANIMATE_PANELS 110
+
+
+/* ========================= Other Macros ==================== */
+
+#define PLAYER_X_FROM_501 43
+#define PLAYER_Y_FROM_501 154
+
+#define WALK_TO_X_FROM_501 87
+#define WALK_TO_Y_FROM_501 153
+
+#define CYCLE_SWITCH_TICKS 300 /* How fast room gets hot */
+#define LENGTH_OF_LIFE 7200 /* (2 minutes ) */
+
+#define DEATH_X 160
+#define DEATH_Y 148
+
+#define COLUMN_1_X 107
+#define COLUMN_2_X 127
+#define COLUMN_3_X 147
+#define COLUMN_4_X 167
+#define COLUMN_Y 148
+
+#define TRAP_DOOR_X 211
+#define TRAP_DOOR_Y 149
+
+#define TRAP_DOOR_HS_X 225
+#define TRAP_DOOR_HS_Y 28
+
+#define THROW_UP_X 200
+#define THROW_UP_Y 149
+
+#define FIFTEEN_SECONDS 900
+#define SIXTY_SECONDS 3600
+#define NINETY_SECONDS 5400
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/phantom/rooms/room504.cpp b/engines/mads/madsv2/phantom/rooms/room504.cpp
new file mode 100644
index 00000000000..475b8324c74
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room504.cpp
@@ -0,0 +1,1523 @@
+/* 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 "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/camera.h"
+#include "mads/madsv2/core/imath.h"
+#include "mads/madsv2/core/inter.h"
+#include "mads/madsv2/core/matte.h"
+#include "mads/madsv2/core/object.h"
+#include "mads/madsv2/core/pal.h"
+#include "mads/madsv2/core/sound.h"
+#include "mads/madsv2/core/speech.h"
+#include "mads/madsv2/core/text.h"
+#include "mads/madsv2/phantom/conv.h"
+#include "mads/madsv2/phantom/mads/speeches.h"
+#include "mads/madsv2/phantom/rooms/section5.h"
+#include "mads/madsv2/phantom/rooms/room504.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+int conv027_second = 0;
+
+void room_504_init() {
+ int id;
+
+ kernel.disable_fastwalk = true;
+
+ local->input_count = 0;
+ local->death_count = 0;
+ local->anim_2_running = false;
+
+ if (previous_room != KERNEL_RESTORING_GAME) {
+ local->play_count = 0;
+ local->anim_0_running = false;
+ local->anim_1_running = false;
+ local->anim_3_running = false;
+ local->anim_4_running = false;
+ local->anim_5_running = false;
+ local->music_is_playing = false;
+ local->fire_breath = false;
+ local->prevent = false;
+ local->music_choice = 0;
+ local->phan_action = 0;
+ }
+
+
+ kernel_flip_hotspot(words_Christine, false);
+
+ /* ==================== Load conversation ==================== */
+
+ if (!global[right_door_is_open_504]) {
+ conv_get(CONV_LISTEN);
+ conv_get(CONV_MUSIC);
+ } else {
+ conv_get(CONV_FIGHT);
+ }
+
+ conv_get(CONV_MISC);
+
+ /* ===================== Load Sprite Series ================== */
+
+ ss[fx_take_9] = kernel_load_series("*RDR_9", false);
+ ss[fx_music] = kernel_load_series(kernel_name('x', 8), false);
+
+ if (!object_is_here(music_score)) {
+ seq[fx_music] = kernel_seq_stamp(ss[fx_music], false, 1);
+ kernel_seq_depth(seq[fx_music], 14);
+ kernel_flip_hotspot(words_music_score, false);
+ }
+
+ ss[fx_trap_door] = kernel_load_series(kernel_name('x', 2), false);
+ ss[fx_burn] = kernel_load_series(kernel_name('x', 7), PAL_MAP_ALL_TO_CLOSEST |
+ PAL_MAP_ANY_TO_CLOSEST);
+
+ if (global[fight_status] == FIGHT_NOT_HAPPENED) {
+ ss[fx_left_door] = kernel_load_series(kernel_name('x', 1), false);
+ }
+
+ ss[fx_ramhead] = kernel_load_series(kernel_name('x', 3), false);
+
+ if ((previous_room == 505) || ((previous_room == 504) && global[right_door_is_open_504])) {
+
+ if ((global[fight_status] == FIGHT_NOT_HAPPENED) && (global[coffin_status] == COFFIN_OPEN)) {
+ /* start the fight sequence */
+
+ kernel_flip_hotspot(words_Christine, true);
+
+ kernel_draw_to_background(ss[fx_trap_door], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+
+ ss[fx_burn] = kernel_load_series(kernel_name('x', 7), PAL_MAP_ALL_TO_CLOSEST |
+ PAL_MAP_ANY_TO_CLOSEST);
+
+ /* These are loaded, but not dumped from memory. An anim loads these, */
+ /* so I don't care what handle is returned. I just load em to re-map */
+
+ ss[fx_test] = kernel_load_series(kernel_name('b', 0), false);
+
+ ss[fx_test] = kernel_load_series("*CHR_6", PAL_MAP_ALL_TO_CLOSEST |
+ PAL_MAP_ANY_TO_CLOSEST);
+ ss[fx_test] = kernel_load_series("*FACERAL", PAL_MAP_ALL_TO_CLOSEST |
+ PAL_MAP_ANY_TO_CLOSEST);
+ ss[fx_test] = kernel_load_series("*FACEXDFR", PAL_MAP_ALL_TO_CLOSEST |
+ PAL_MAP_ANY_TO_CLOSEST);
+ ss[fx_test] = kernel_load_series("*FACEPHN", PAL_MAP_ALL_TO_CLOSEST |
+ PAL_MAP_ANY_TO_CLOSEST);
+
+ /* These are loaded and will be dumped from memory in Daemon */
+
+ ss[fx_a_5] = kernel_load_series(kernel_name('a', 5), false);
+ ss[fx_a_3] = kernel_load_series(kernel_name('a', 3), PAL_MAP_ALL_TO_CLOSEST |
+ PAL_MAP_ANY_TO_CLOSEST);
+ ss[fx_a_6] = kernel_load_series(kernel_name('a', 6), PAL_MAP_ALL_TO_CLOSEST |
+ PAL_MAP_ANY_TO_CLOSEST);
+ ss[fx_a_7] = kernel_load_series(kernel_name('a', 7), PAL_MAP_ALL_TO_CLOSEST |
+ PAL_MAP_ANY_TO_CLOSEST);
+ ss[fx_a_0] = kernel_load_series(kernel_name('a', 0), PAL_MAP_ALL_TO_CLOSEST |
+ PAL_MAP_ANY_TO_CLOSEST);
+
+ aa[3] = kernel_run_animation(kernel_name('p', 1), 0);
+ id = kernel_add_dynamic(words_Phantom, words_look_at, SYNTAX_MASC_NOT_PROPER, KERNEL_NONE,
+ 0, 0, 0, 0);
+ kernel_dynamic_hot[id].prep = PREP_ON;
+ kernel_dynamic_walk(id, WALK_NONE, WALK_NONE, 5);
+
+ kernel_dynamic_anim(id, aa[3], 4);
+ kernel_dynamic_anim(id, aa[3], 8);
+ kernel_dynamic_anim(id, aa[3], 13);
+
+ local->phan_action = FIGHT_ENTER_ROOM;
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ local->anim_3_running = true;
+
+ } else {
+
+ if (global[fight_status]) {
+ kernel_draw_to_background(ss[fx_burn], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ }
+
+ if (global[coffin_status] != COFFIN_OPEN) {
+ seq[fx_left_door] = kernel_seq_stamp(ss[fx_left_door], false, 1);
+ kernel_seq_depth(seq[fx_left_door], 14);
+ }
+
+ player.x = PLAYER_X_FROM_505;
+ player.y = PLAYER_Y_FROM_505;
+ player.facing = FACING_SOUTHWEST;
+ player_walk(WALK_TO_X_FROM_505, WALK_TO_Y_FROM_505, FACING_SOUTHWEST);
+
+ kernel_draw_to_background(ss[fx_trap_door], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+
+ if (!player_has_been_in_room(506) && (global[coffin_status] == COFFIN_OPEN)) { /* Chris is waiting by door in 504 */
+
+ kernel_load_variant(1);
+
+ kernel_draw_to_background(ss[fx_burn], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+
+ local->anim_5_running = true;
+
+ /* I never unload these because at end of anim, new room = 506 */
+
+ ss[fx_test] = kernel_load_series("*CHR_2", false);
+ ss[fx_test] = kernel_load_series("*FACERAL", PAL_MAP_ALL_TO_CLOSEST |
+ PAL_MAP_ANY_TO_CLOSEST);
+ ss[fx_test] = kernel_load_series("*FACEXDFR", PAL_MAP_ALL_TO_CLOSEST |
+ PAL_MAP_ANY_TO_CLOSEST);
+ ss[fx_test] = kernel_load_series("*FACEPHN", PAL_MAP_ALL_TO_CLOSEST |
+ PAL_MAP_ANY_TO_CLOSEST);
+
+ aa[3] = kernel_run_animation(kernel_name('p', 3), 0);
+ id = kernel_add_dynamic(words_Christine, words_walk_to, SYNTAX_SINGULAR_FEM, KERNEL_NONE,
+ 0, 0, 0, 0);
+ local->phan_action = FIGHT_CHRIS_TO_DOOR;
+ kernel_dynamic_hot[id].prep = PREP_ON;
+ kernel_reset_animation(aa[3], 79);
+ kernel_dynamic_walk(id, DYNAMIC_CHR_WALK_TO_X, DYNAMIC_CHR_WALK_TO_Y, FACING_NORTHWEST);
+ kernel_dynamic_anim(id, aa[3], 0);
+ kernel_dynamic_anim(id, aa[3], 1);
+ kernel_dynamic_anim(id, aa[3], 2);
+ kernel_dynamic_anim(id, aa[3], 3);
+ kernel_dynamic_anim(id, aa[3], 4);
+ }
+ }
+
+ } else if (previous_room == 506) {
+
+ player.x = PLAYER_X_FROM_506;
+ player.y = PLAYER_Y_FROM_506;
+ player.facing = FACING_SOUTHEAST;
+ player_walk(WALK_TO_X_FROM_506, WALK_TO_Y_FROM_506, FACING_SOUTHEAST);
+ kernel_draw_to_background(ss[fx_trap_door], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ kernel_draw_to_background(ss[fx_burn], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+
+ } else if (previous_room == 504) { /* just returned from burning at the organ */
+ seq[fx_left_door] = kernel_seq_stamp(ss[fx_left_door], false, 1);
+ kernel_seq_depth(seq[fx_left_door], 14);
+
+ ss[fx_right_door] = kernel_load_series(kernel_name('x', 0), false);
+ seq[fx_right_door] = kernel_seq_stamp(ss[fx_right_door], false, 1);
+ kernel_seq_depth(seq[fx_right_door], 14);
+ kernel_draw_to_background(ss[fx_trap_door], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+
+ player.x = PLAYER_X_FROM_502;
+ player.y = PLAYER_Y_FROM_502;
+ player.facing = FACING_EAST;
+
+ } else if ((previous_room == 502) || (previous_room != KERNEL_RESTORING_GAME)) {
+
+ seq[fx_left_door] = kernel_seq_stamp(ss[fx_left_door], false, 1);
+ kernel_seq_depth(seq[fx_left_door], 14);
+
+ ss[fx_right_door] = kernel_load_series(kernel_name('x', 0), false);
+ seq[fx_right_door] = kernel_seq_stamp(ss[fx_right_door], false, 1);
+ kernel_seq_depth(seq[fx_right_door], 14);
+
+ aa[0] = kernel_run_animation(kernel_name('t', 1), ROOM_504_FROM_502);
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ player.x = PLAYER_X_FROM_502;
+ player.y = PLAYER_Y_FROM_502;
+ player.facing = FACING_EAST;
+
+ }
+
+ if (previous_room == KERNEL_RESTORING_GAME) {
+ if (!global[right_door_is_open_504]) {
+ ss[fx_right_door] = kernel_load_series(kernel_name('x', 0), false);
+ seq[fx_right_door] = kernel_seq_stamp(ss[fx_right_door], false, 1);
+ kernel_seq_depth(seq[fx_right_door], 14);
+ }
+
+ if (conv_restore_running == CONV_LISTEN) {
+ kernel_draw_to_background(ss[fx_trap_door], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ seq[fx_left_door] = kernel_seq_stamp(ss[fx_left_door], false, 1);
+ kernel_seq_depth(seq[fx_left_door], 14);
+
+ aa[0] = kernel_run_animation(kernel_name('l', 1), ROOM_504_END_LISTEN);
+ local->anim_0_running = true;
+ player.walker_visible = false;
+ player.commands_allowed = false;
+ player.x = RIGHT_DOOR_X;
+ player.y = RIGHT_DOOR_Y;
+ player.facing = FACING_EAST;
+ local->listen_action = CONV19_LISTEN;
+ kernel_reset_animation(aa[0], 8);
+ conv_run(CONV_LISTEN);
+ conv_export_value(game.difficulty);
+
+ } else if (conv_restore_running == CONV_MUSIC) {
+ kernel_draw_to_background(ss[fx_trap_door], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ seq[fx_left_door] = kernel_seq_stamp(ss[fx_left_door], false, 1);
+ kernel_seq_depth(seq[fx_left_door], 14);
+
+ ss[fx_fire_left] = kernel_load_series(kernel_name('x', 4), PAL_MAP_ALL_TO_CLOSEST |
+ PAL_MAP_ANY_TO_CLOSEST);
+ ss[fx_fire_right] = kernel_load_series(kernel_name('x', 5), PAL_MAP_ALL_TO_CLOSEST |
+ PAL_MAP_ANY_TO_CLOSEST);
+ aa[1] = kernel_run_animation(kernel_name('o', 1), ROOM_504_DONE_PLAYING);
+ kernel_reset_animation(aa[1], 22);
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ local->music_is_playing = false;
+ local->anim_1_running = true;
+ local->play_action = CONV27_SELECT;
+ conv_run(CONV_MUSIC);
+
+ } else if ((global[fight_status] <= FIGHT_TALKING) && (global[coffin_status] == COFFIN_OPEN)) {
+ /* Christine and Raoul are in fight sequence with Phan */
+
+ if ((local->phan_action == FIGHT_BEFORE_DODGE) || (local->phan_action == FIGHT_CHOICE)) {
+
+ kernel_flip_hotspot(words_Christine, true);
+
+ kernel_draw_to_background(ss[fx_trap_door], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+
+ /* These are loaded, but not dumped from memory. An anim loads these, */
+ /* so I don't care what handle is returned. I just load em to re-map */
+
+ ss[fx_test] = kernel_load_series(kernel_name('b', 0), false);
+
+ ss[fx_test] = kernel_load_series("*CHR_6", PAL_MAP_ALL_TO_CLOSEST |
+ PAL_MAP_ANY_TO_CLOSEST);
+ ss[fx_test] = kernel_load_series("*FACERAL", PAL_MAP_ALL_TO_CLOSEST |
+ PAL_MAP_ANY_TO_CLOSEST);
+ ss[fx_test] = kernel_load_series("*FACEXDFR", PAL_MAP_ALL_TO_CLOSEST |
+ PAL_MAP_ANY_TO_CLOSEST);
+ ss[fx_test] = kernel_load_series("*FACEPHN", PAL_MAP_ALL_TO_CLOSEST |
+ PAL_MAP_ANY_TO_CLOSEST);
+
+ /* These are loaded and will be dumped from memory in Daemon */
+
+ ss[fx_a_5] = kernel_load_series(kernel_name('a', 5), false);
+ ss[fx_a_3] = kernel_load_series(kernel_name('a', 3), PAL_MAP_ALL_TO_CLOSEST |
+ PAL_MAP_ANY_TO_CLOSEST);
+ ss[fx_a_6] = kernel_load_series(kernel_name('a', 6), PAL_MAP_ALL_TO_CLOSEST |
+ PAL_MAP_ANY_TO_CLOSEST);
+ ss[fx_a_7] = kernel_load_series(kernel_name('a', 7), PAL_MAP_ALL_TO_CLOSEST |
+ PAL_MAP_ANY_TO_CLOSEST);
+ ss[fx_a_0] = kernel_load_series(kernel_name('a', 0), PAL_MAP_ALL_TO_CLOSEST |
+ PAL_MAP_ANY_TO_CLOSEST);
+
+ aa[3] = kernel_run_animation(kernel_name('p', 1), 0);
+ id = kernel_add_dynamic(words_Phantom, words_look_at, SYNTAX_MASC_NOT_PROPER, KERNEL_NONE,
+ 0, 0, 0, 0);
+ kernel_dynamic_hot[id].prep = PREP_ON;
+ kernel_dynamic_walk(id, WALK_NONE, WALK_NONE, 5);
+
+ if (local->phan_action == FIGHT_BEFORE_DODGE) {
+ kernel_reset_animation(aa[3], imath_random(109, 112));
+ } else if (local->phan_action == FIGHT_CHOICE) {
+ kernel_reset_animation(aa[3], imath_random(148, 150));
+ kernel_draw_to_background(ss[fx_burn], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ }
+
+ kernel_dynamic_anim(id, aa[3], 4);
+ kernel_dynamic_anim(id, aa[3], 8);
+ kernel_dynamic_anim(id, aa[3], 13);
+
+ player.walker_visible = false;
+ local->anim_3_running = true;
+
+ if (conv_restore_running == CONV_FIGHT) {
+ player.commands_allowed = false;
+ conv_run(CONV_FIGHT);
+ conv_export_value(player_has(music_score));
+ }
+
+ } else if (local->phan_action == FIGHT_SWORD) { /* Chris is asking 'what happened' */
+ kernel_draw_to_background(ss[fx_trap_door], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ kernel_draw_to_background(ss[fx_burn], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+
+ ss[fx_test] = kernel_load_series("*CHR_3", false);
+ /* ss[fx_test] = kernel_load_series(kernel_name('b', 0), false); */
+ ss[fx_test] = kernel_load_series("*FACERAL", PAL_MAP_ALL_TO_CLOSEST |
+ PAL_MAP_ANY_TO_CLOSEST);
+ ss[fx_test] = kernel_load_series("*FACEXDFR", PAL_MAP_ALL_TO_CLOSEST |
+ PAL_MAP_ANY_TO_CLOSEST);
+ ss[fx_test] = kernel_load_series("*FACEPHN", PAL_MAP_ALL_TO_CLOSEST |
+ PAL_MAP_ANY_TO_CLOSEST);
+
+ ss[fx_a_8] = kernel_load_series(kernel_name('a', 8), PAL_MAP_ALL_TO_CLOSEST |
+ PAL_MAP_ANY_TO_CLOSEST);
+
+ aa[3] = kernel_run_animation(kernel_name('p', 2), ROOM_504_RUN_PART_3);
+ kernel_reset_animation(aa[3], 159);
+
+ player.x = WALK_TO_AFTER_FIGHT_X;
+ player.y = WALK_TO_AFTER_FIGHT_Y;
+ player.facing = FACING_NORTHEAST;
+ player.walker_visible = true;
+ local->anim_4_running = true;
+
+ player.commands_allowed = false;
+ conv_run(CONV_FIGHT);
+ conv_export_value(player_has(music_score));
+ }
+
+ } else if (global[fight_status] == FIGHT_PARTED) {
+ if (!player_has_been_in_room(506)) { /* Chris is waiting by door in 504 */
+ kernel_load_variant(1);
+
+ kernel_draw_to_background(ss[fx_trap_door], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ kernel_draw_to_background(ss[fx_burn], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ local->anim_5_running = true;
+
+ /* I never unload this because at end of anim, new room = 506 */
+
+ ss[fx_test] = kernel_load_series("*CHR_3", false);
+ ss[fx_test] = kernel_load_series("*FACERAL", PAL_MAP_ALL_TO_CLOSEST |
+ PAL_MAP_ANY_TO_CLOSEST);
+ ss[fx_test] = kernel_load_series("*FACEXDFR", PAL_MAP_ALL_TO_CLOSEST |
+ PAL_MAP_ANY_TO_CLOSEST);
+ ss[fx_test] = kernel_load_series("*FACEPHN", PAL_MAP_ALL_TO_CLOSEST |
+ PAL_MAP_ANY_TO_CLOSEST);
+
+ aa[3] = kernel_run_animation(kernel_name('p', 3), 0);
+ id = kernel_add_dynamic(words_Christine, words_walk_to, SYNTAX_SINGULAR_FEM, KERNEL_NONE,
+ 0, 0, 0, 0);
+ local->phan_action = FIGHT_CHRIS_TO_DOOR;
+ kernel_dynamic_hot[id].prep = PREP_ON;
+ kernel_reset_animation(aa[3], 79);
+ kernel_dynamic_walk(id, DYNAMIC_CHR_WALK_TO_X, DYNAMIC_CHR_WALK_TO_Y, FACING_NORTHWEST);
+ kernel_dynamic_anim(id, aa[3], 0);
+ kernel_dynamic_anim(id, aa[3], 1);
+ kernel_dynamic_anim(id, aa[3], 2);
+ kernel_dynamic_anim(id, aa[3], 3);
+ kernel_dynamic_anim(id, aa[3], 4);
+
+ } else {
+ kernel_draw_to_background(ss[fx_trap_door], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ kernel_draw_to_background(ss[fx_burn], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ }
+
+ } else {
+ kernel_draw_to_background(ss[fx_trap_door], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ seq[fx_left_door] = kernel_seq_stamp(ss[fx_left_door], false, 1);
+ kernel_seq_depth(seq[fx_left_door], 14);
+ seq[fx_left_door] = kernel_seq_stamp(ss[fx_left_door], false, 1);
+ kernel_seq_depth(seq[fx_left_door], 14);
+ if (!global[he_listened]) {
+ kernel_timing_trigger(HALF_SECOND, ROOM_504_FROM_502 + 2);
+ /* start listen conversation */
+ }
+ }
+ }
+
+ section_5_music();
+}
+
+static void process_conversation_listen() {
+ if (player_verb == conv019_talk_b_b) {
+ if (!kernel.trigger) {
+ player_walk(RIGHT_DOOR_X, RIGHT_DOOR_Y, FACING_EAST);
+ player_walk_trigger(ROOM_504_LISTEN);
+ }
+ }
+
+ if (player_verb == conv019_exit_b_b) {
+ local->listen_action = CONV19_OTHER;
+ }
+}
+
+static void process_conversation_play() {
+ switch (player_verb) {
+ case conv027_choices_one:
+ *conv_my_next_start = conv027_second;
+ conv_abort();
+ local->play_action = CONV27_PLAY;
+ local->music_choice = 1;
+ break;
+
+ case conv027_choices_two:
+ *conv_my_next_start = conv027_second;
+ conv_abort();
+ local->play_action = CONV27_PLAY;
+ local->music_choice = 2;
+ break;
+
+ case conv027_choices_three:
+ *conv_my_next_start = conv027_second;
+ conv_abort();
+ local->play_action = CONV27_PLAY;
+ local->music_choice = 3;
+ break;
+
+ case conv027_choices_four:
+ *conv_my_next_start = conv027_second;
+ conv_abort();
+ local->play_action = CONV27_PLAY;
+ local->music_choice = 4;
+ break;
+
+ case conv027_choices_five:
+ *conv_my_next_start = conv027_second;
+ conv_abort();
+ local->play_action = CONV27_PLAY;
+ local->music_choice = 5;
+ break;
+
+ case conv027_exit_a_a:
+ *conv_my_next_start = conv027_second;
+ conv_abort();
+ local->play_action = CONV27_PLAY;
+ break;
+ }
+}
+
+static void process_conversation_fight() {
+ switch (player_verb) {
+ case conv021_fight_b_b:
+ conv_hold();
+ local->phan_action = FIGHT_BEFORE_DODGE;
+ break;
+
+ case conv021_ending_b_b:
+ local->phan_action = FIGHT_CHOICE;
+ break;
+
+ case conv021_hasit_b_b:
+ case conv021_score_b_b:
+ local->phan_action = FIGHT_CHRIS_TO_DOOR;
+ global[fight_status] = FIGHT_PARTED;
+ break;
+
+ case conv021_outtahere_first:
+ case conv021_outtahere_second:
+ case conv021_outtahere_third:
+ case conv021_score_abc:
+ conv_you_trigger(ROOM_504_CHRIS_TALK);
+ break;
+ }
+
+ if (kernel.trigger == ROOM_504_CHRIS_TALK) {
+ if (local->phan_action != FIGHT_CHRIS_TO_DOOR) {
+ local->phan_action = FIGHT_CHRIS_TALK;
+ local->chris_talk_count = 0;
+ }
+ }
+}
+
+void room_504_pre_parser() {
+ if (player_said_2(walk_through, right_door) ||
+ player_said_2(open, right_door)) {
+
+ if (global[right_door_is_open_504]) {
+ if ((global[fight_status] == FIGHT_PARTED) && !player_has_been_in_room(506)) {
+ switch (kernel.trigger) {
+ case 0:
+ player_walk(BEHIND_RIGHT_DOOR_X, BEHIND_RIGHT_DOOR_Y, FACING_NORTHEAST);
+ player.ready_to_walk = false;
+ player.need_to_walk = false;
+ player.commands_allowed = false;
+ conv_run(CONV_MISC);
+ conv_export_value(2);
+ kernel_timing_trigger(6, 1);
+ break;
+
+ case 1:
+ if (conv_control.running >= 0) {
+ kernel_timing_trigger(6, 1);
+ } else {
+ player.commands_allowed = true;
+ player.command_ready = true;
+ player.need_to_walk = true;
+ player.ready_to_walk = true;
+ }
+ break;
+ }
+
+ } else {
+ player_walk(BEHIND_RIGHT_DOOR_X, BEHIND_RIGHT_DOOR_Y, FACING_NORTHEAST);
+ }
+
+ } else if (global[he_listened] || (global[fight_status] == FIGHT_NOT_HAPPENED)) {
+ player_walk(RIGHT_DOOR_X, RIGHT_DOOR_Y, FACING_NORTHEAST);
+ }
+ }
+
+ if (local->anim_2_running && !player_said_1(sit_in)) {
+ if (player.need_to_walk) {
+ local->chair_action = CHAIR_GET_UP;
+ player.commands_allowed = false;
+ player.ready_to_walk = false;
+ }
+ }
+
+ if (player_said_2(walk_through, left_door) ||
+ player_said_2(open, left_door)) {
+
+ if ((global[fight_status] == FIGHT_NOT_HAPPENED) && (global[coffin_status] == COFFIN_OPEN) &&
+ !player_has_been_in_room(506)) {
+ text_show(text_504_32);
+ player_cancel_command();
+ goto over;
+
+ } else if (player_has_been_in_room(506)) { /* Chris is waiting in 506 */
+ player_walk(EXIT_LEFT_DOOR_X, EXIT_LEFT_DOOR_Y, FACING_NORTHWEST);
+
+ } else if (!player_has(music_score) || (global[fight_status] == FIGHT_NOT_HAPPENED)) {
+ player_walk(LEFT_DOOR_X, LEFT_DOOR_Y, FACING_NORTHWEST);
+ }
+ }
+
+ if ((global[fight_status] == FIGHT_NOT_HAPPENED) && (global[coffin_status] == COFFIN_OPEN) &&
+ !player_has_been_in_room(506)) {
+ if (!player_said_1(look) && !player_said_1(look_at) && !player_said_1(attack) &&
+ !player_said_2(take, sword) && !player_said_2(talk_to, Phantom)) {
+ text_show(text_504_30);
+ player_cancel_command();
+ }
+ }
+
+over:
+ ;
+}
+
+void room_504_parser() {
+ if (conv_control.running == CONV_MISC) {
+ goto handled;
+ }
+
+ if (player_said_2(sit_in, large_chair)) {
+ if (!local->anim_2_running) {
+ local->chair_action = CHAIR_SIT;
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ local->anim_2_running = true;
+ aa[2] = kernel_run_animation(kernel_name('c', 1), 0);
+ kernel_synch(KERNEL_ANIM, aa[0], KERNEL_PLAYER, 0);
+ goto handled;
+ } else {
+ text_show(text_504_36);
+ goto handled;
+ }
+ }
+
+ if (kernel.trigger == ROOM_504_LISTEN) {
+ aa[0] = kernel_run_animation(kernel_name('l', 1), ROOM_504_END_LISTEN);
+ local->listen_action = CONV19_LISTEN;
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ local->anim_0_running = true;
+ global[he_listened] = true;
+ conv_run(CONV_LISTEN);
+ conv_export_value(game.difficulty);
+ goto handled;
+ }
+
+ if (kernel.trigger == ROOM_504_END_LISTEN) {
+ player.commands_allowed = true;
+ player.walker_visible = true;
+ local->anim_0_running = false;
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_ANIM, aa[0]);
+ goto handled;
+ }
+
+ if (conv_control.running == CONV_LISTEN) {
+ process_conversation_listen();
+ goto handled;
+ }
+
+ if (conv_control.running == CONV_MUSIC) {
+ process_conversation_play();
+ goto handled;
+ }
+
+ if (conv_control.running == CONV_FIGHT) {
+ process_conversation_fight();
+ goto handled;
+ }
+
+ if (kernel.trigger == ROOM_504_DONE_PLAYING) {
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_ANIM, aa[1]);
+ player.x = AFTER_PLAY_X;
+ player.y = AFTER_PLAY_Y;
+ player.walker_visible = true;
+ local->anim_1_running = false;
+ player_demand_facing(FACING_EAST);
+ kernel_timing_trigger(10, ROOM_504_DONE_PLAYING + 1);
+ goto handled;
+ }
+
+ if (kernel.trigger == ROOM_504_DONE_PLAYING + 1) {
+ player.commands_allowed = true;
+ matte_deallocate_series(ss[fx_fire_right], true);
+ matte_deallocate_series(ss[fx_fire_left], true);
+ goto handled;
+ }
+
+ if (player_said_2(sit_on, organ_bench)) {
+ if (global[right_door_is_open_504]) {
+ text_show(text_504_27);
+ } else {
+ ss[fx_fire_left] = kernel_load_series(kernel_name('x', 4), PAL_MAP_ALL_TO_CLOSEST |
+ PAL_MAP_ANY_TO_CLOSEST);
+ ss[fx_fire_right] = kernel_load_series(kernel_name('x', 5), PAL_MAP_ALL_TO_CLOSEST |
+ PAL_MAP_ANY_TO_CLOSEST);
+ aa[1] = kernel_run_animation(kernel_name('o', 1), ROOM_504_DONE_PLAYING);
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ local->music_is_playing = false;
+ local->anim_1_running = true;
+ local->play_action = CONV27_SELECT;
+ }
+ goto handled;
+ }
+
+ if (player_said_2(walk_through, right_door) ||
+ player_said_2(open, right_door)) {
+
+ if (global[right_door_is_open_504]) {
+
+ if (conv_control.running == CONV_MISC) {
+ conv_abort();
+ }
+
+ new_room = 505;
+ goto handled;
+
+ } else {
+ text_show(text_504_18);
+ goto handled;
+ }
+ }
+
+ if (player_said_2(walk_through, left_door) ||
+ player_said_2(open, left_door)) {
+
+ if (global[fight_status]) {
+ if (player_has_been_in_room(506)) { /* Chris is waiting in 506 */
+ new_room = 506;
+
+ } else if (!player_has(music_score)) {
+ text_show(text_504_25);
+ /* Hey, why don't you get the music score? */
+
+ } else {
+ local->phan_action = FIGHT_CHRIS_LEAVE;
+ player.commands_allowed = false;
+ /* you have music score, ladies first into 506 */
+ }
+
+ } else {
+ text_show(text_504_18);
+ /* the door is locked tight */
+ }
+ goto handled;
+ }
+
+ if (player_said_2(take, music_score)) {
+ switch (kernel.trigger) {
+ case (0):
+ if (object_is_here(music_score)) {
+ global[player_score] += 5;
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_take_9] = kernel_seq_pingpong(ss[fx_take_9], false,
+ 5, 0, 0, 2);
+ kernel_seq_range(seq[fx_take_9], 1, 4);
+ kernel_seq_player(seq[fx_take_9], true);
+ kernel_seq_trigger(seq[fx_take_9],
+ KERNEL_TRIGGER_SPRITE, 4, 1);
+ kernel_seq_trigger(seq[fx_take_9],
+ KERNEL_TRIGGER_EXPIRE, 0, 2);
+ goto handled;
+ }
+ break;
+
+ case 1:
+ seq[fx_music] = kernel_seq_stamp(ss[fx_music], false, 1);
+ kernel_seq_depth(seq[fx_music], 14);
+ kernel_flip_hotspot(words_music_score, false);
+ inter_give_to_player(music_score);
+ sound_play(N_TakeObjectSnd);
+ goto handled;
+ break;
+
+ case 2:
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_SERIES, seq[fx_take_9]);
+ player.walker_visible = true;
+ kernel_timing_trigger(20, 3);
+ goto handled;
+ break;
+
+ case 3:
+ object_examine(music_score, text_008_20, 0);
+ /* You pick up the music score */
+ player.commands_allowed = true;
+ goto handled;
+ break;
+ }
+ }
+
+ if (player.look_around) {
+ text_show(text_504_10);
+ goto handled;
+ }
+
+ if (player_said_1(look) || player_said_1(look_at)) {
+ if (player_said_1(floor)) {
+ text_show(text_504_11);
+ goto handled;
+ }
+
+ if (player_said_1(wall)) {
+ text_show(text_504_12);
+ goto handled;
+ }
+
+ if (player_said_1(organ)) {
+ text_show(text_504_13);
+ goto handled;
+ }
+
+ if (player_said_1(organ_bench)) {
+ text_show(text_504_14);
+ goto handled;
+ }
+
+ if (player_said_1(music_score) && object_is_here(music_score)) {
+ text_show(text_504_15);
+ goto handled;
+ }
+
+ if (player_said_1(left_door)) {
+ text_show(text_504_16);
+ goto handled;
+ }
+
+ if (player_said_1(right_door)) {
+ if (global[right_door_is_open_504]) {
+ text_show(text_504_34);
+ } else {
+ text_show(text_504_17);
+ }
+ goto handled;
+ }
+
+ if (player_said_1(table)) {
+ text_show(text_504_19);
+ goto handled;
+ }
+
+ if (player_said_1(trap_door)) {
+ text_show(text_504_20);
+ goto handled;
+ }
+
+ if (player_said_1(large_chair)) {
+ text_show(text_504_22);
+ goto handled;
+ }
+
+ if (player_said_1(Christine)) {
+ if (global[fight_status]) {
+ text_show(text_504_26);
+ } else {
+ text_show(text_504_29);
+ }
+ goto handled;
+ }
+
+ if (player_said_1(Phantom)) {
+ text_show(text_504_28);
+ goto handled;
+ }
+
+ }
+
+ if (player_said_2(open, trap_door)) {
+ text_show(text_504_21);
+ goto handled;
+ }
+
+ if (player_said_1(close)) {
+ if (player_said_1(right_door)) {
+ if (!global[right_door_is_open_504]) {
+ text_show(text_504_33);
+ goto handled;
+ }
+ }
+ }
+
+ if (player_said_1(close)) {
+ if (player_said_1(left_door)) {
+ if (!global[fight_status] && !player_has_been_in_room(506)) { /* Chris is waiting in 506 */
+ text_show(text_504_33);
+ goto handled;
+ }
+ }
+ }
+
+ if (local->anim_3_running) {
+ if (player_said_2(take, sword) || player_said_2(attack, Phantom)) {
+ player.commands_allowed = false;
+ local->input_count = 0;
+ local->phan_action = FIGHT_SWORD;
+ goto handled;
+ }
+ }
+
+ if (player_said_2(talk_to, Christine)) {
+ conv_run(CONV_FIGHT);
+ conv_export_value(player_has(music_score));
+ conv_export_value(0);
+ local->phan_action = FIGHT_CHRIS_TALK;
+ local->chris_talk_count = 0;
+ goto handled;
+ }
+
+ if (player_said_2(talk_to, Phantom)) {
+ text_show(text_504_31);
+ goto handled;
+ }
+
+ if (player_said_2(take, Christine)) {
+ text_show(text_504_35);
+ goto handled;
+ }
+
+ goto done;
+
+handled:
+ player.command_ready = false;
+
+done:
+ ;
+}
+static void handle_animation_listen() {
+ int listen_reset_frame;
+
+ if (kernel_anim[aa[0]].frame != local->listen_frame) {
+ local->listen_frame = kernel_anim[aa[0]].frame;
+ listen_reset_frame = -1;
+
+ switch (local->listen_frame) {
+ case 8: /* listening */
+ conv_release();
+ break;
+
+ case 9: /* listening */
+ if (local->listen_action == CONV19_LISTEN) {
+ listen_reset_frame = 8;
+ /* keep listening */
+ } else {
+ listen_reset_frame = 9;
+ /* move away from door */
+ }
+ break;
+ }
+
+ if (listen_reset_frame >= 0) {
+ kernel_reset_animation(aa[0], listen_reset_frame);
+ local->listen_frame = listen_reset_frame;
+ }
+ }
+}
+
+static void handle_animation_play_organ() {
+ int play_reset_frame;
+
+ if (kernel_anim[aa[1]].frame != local->play_frame) {
+ local->play_frame = kernel_anim[aa[1]].frame;
+ play_reset_frame = -1;
+
+ switch (local->play_frame) {
+ case 22: /* prompt for music */
+ player.commands_allowed = true;
+ conv_run(CONV_MUSIC);
+ break;
+
+ case 23:
+ if (local->play_action == CONV27_SELECT) {
+ play_reset_frame = 22;
+ /* freeze while choosing piece */
+
+ } else {
+ player.commands_allowed = false;
+ /* play organ */
+ if (local->music_choice == 5) {
+ local->music_is_playing = false;
+ local->fire_breath = false;
+ play_reset_frame = 104;
+ /* get up */
+ }
+ }
+ break;
+
+ case 28:
+ if (!local->music_is_playing) {
+ local->music_is_playing = true;
+ local->fire_breath = true;
+ player.commands_allowed = false;
+
+ switch (local->music_choice) {
+ case 1:
+ sound_play(N_Bach_dm);
+ break;
+
+ case 3:
+ sound_play(N_Gigue);
+ break;
+
+ case 4:
+ sound_play(N_Canon);
+ break;
+
+ case 2:
+ sound_play(N_Bach_gm);
+ break;
+ }
+ }
+ break;
+
+ case 69: /* restart playing - maybe */
+ if ((global[right_door_is_open_504]) && (local->play_count >= 2)) {
+ local->play_count = 0;
+ play_reset_frame = 102;
+ sound_play(N_MusicOff);
+ sound_play(N_BackgroundMus);
+ /* get up */
+
+ } else if (local->music_choice != global[music_selected]) {
+ sound_play(N_MusicOff);
+ local->fire_breath = true;
+ play_reset_frame = 75;
+ /* die */
+
+ } else {
+ play_reset_frame = 25;
+ ++local->play_count;
+ if (!global[right_door_is_open_504]) {
+ kernel_timing_trigger(1, ROOM_504_OPEN_RIGHT_DOOR);
+ global[player_score] += 5;
+ } /* keep playing (player will live) */
+ }
+ break;
+
+ case 76:
+ global_speech(speech_raoul_fire);
+ break;
+
+ case 90:
+ sound_play(N_PlayerDies);
+ break;
+
+ case 102: /* restart room - player died */
+ ++local->death_count;
+ if (local->death_count >= 17) {
+ kernel.force_restart = true;
+ } else {
+ play_reset_frame = 101;
+ }
+ break;
+ }
+
+ if (play_reset_frame >= 0) {
+ kernel_reset_animation(aa[1], play_reset_frame);
+ local->play_frame = play_reset_frame;
+ }
+ }
+}
+
+
+static void handle_animation_phantom_1() {
+ int phan_reset_frame;
+ /* int id; */
+
+
+
+ if (kernel_anim[aa[3]].frame != local->phan_frame) {
+ local->phan_frame = kernel_anim[aa[3]].frame;
+ phan_reset_frame = -1;
+
+ switch (local->phan_frame) {
+
+ case 52: /* end of just as phantom comes into room (same for next 3) */
+ case 53: /* Here, we'll wait for a few lines to be exchanged */
+ case 54:
+ case 55:
+ if (local->phan_action == FIGHT_ENTER_ROOM) {
+ phan_reset_frame = imath_random(51, 54);
+ } else {
+ phan_reset_frame = 55;
+ }
+ break;
+
+ case 41: /* They first come into room (Phan enters from other side) */
+ conv_run(CONV_FIGHT);
+ conv_export_value(player_has(music_score));
+ conv_export_value(0);
+ break; /* Chris says 'It's him' */
+
+ case 78:
+ conv_release();
+ break; /* phantom is now jumping onto table and Raoul is walking to center of room */
+
+ case 169:
+ sound_play(N_AllFade);
+ global_speech(speech_raoul_fire);
+ break;
+
+ case 180:
+ sound_play(N_PlayerDies);
+ break;
+
+ case 187:
+ local->death_count = 0;
+ break;
+
+ case 189:
+ ++local->death_count;
+ if (local->death_count >= 29) {
+ kernel.force_restart = true;
+ } else {
+ phan_reset_frame = 188;
+ }
+ break;
+
+ case 110: /* Raoul stepped closer to phan - fireball coming */
+ case 111: /* Raoul stepped closer to phan - fireball coming */
+ case 112: /* Raoul stepped closer to phan - fireball coming */
+ case 113: /* Raoul stepped closer to phan - fireball coming */
+ if (local->phan_action == FIGHT_BEFORE_DODGE) {
+ phan_reset_frame = imath_random(109, 112);
+ } else {
+ phan_reset_frame = 113;
+ }
+ break;
+
+ case 142:
+ kernel_draw_to_background(ss[fx_burn], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ break;
+
+ case 143:
+ player.commands_allowed = true;
+ break;
+
+ case 149: /* end of wait for player input 3 */
+ case 150: /* end of wait for player input 3 */
+ case 151: /* end of wait for player input 3 */
+
+ ++local->input_count;
+
+ if (local->phan_action == FIGHT_SWORD) {
+ player.commands_allowed = false;
+ phan_reset_frame = 200;
+
+ } else if (local->input_count >= 9) {
+ player.commands_allowed = false;
+ phan_reset_frame = 151;
+
+ } else if (local->phan_action == FIGHT_CHOICE) {
+ phan_reset_frame = imath_random(148, 150);
+ }
+ break;
+
+ case 227:
+
+ kernel_abort_animation(aa[3]);
+ matte_deallocate_series(ss[fx_a_0], true);
+ matte_deallocate_series(ss[fx_a_7], true);
+ matte_deallocate_series(ss[fx_a_6], true);
+ matte_deallocate_series(ss[fx_a_3], true);
+ matte_deallocate_series(ss[fx_a_5], true);
+
+ ss[fx_test] = kernel_load_series("*CHR_3", PAL_MAP_ALL_TO_CLOSEST |
+ PAL_MAP_ANY_TO_CLOSEST);
+ ss[fx_a_8] = kernel_load_series(kernel_name('a', 8), PAL_MAP_ALL_TO_CLOSEST |
+ PAL_MAP_ANY_TO_CLOSEST);
+
+ /* What a fucking nightmare! */
+
+ aa[3] = kernel_run_animation(kernel_name('p', 2), ROOM_504_RUN_PART_3);
+
+ kernel_reset_animation(aa[3], 27);
+ phan_reset_frame = -1;
+ local->anim_3_running = false;
+ local->anim_4_running = true; /* still keep aa[3], though */
+ break;
+
+ }
+
+ if (phan_reset_frame >= 0) {
+ kernel_reset_animation(aa[3], phan_reset_frame);
+ local->phan_frame = phan_reset_frame;
+ }
+ }
+}
+
+
+
+static void handle_animation_phantom_2() {
+ int phan_reset_frame;
+
+ if (kernel_anim[aa[3]].frame != local->phan_frame) {
+ local->phan_frame = kernel_anim[aa[3]].frame;
+ phan_reset_frame = -1;
+
+ switch (local->phan_frame) {
+
+ case 78:
+ global_speech(speech_phantom_cackle);
+ break;
+
+ case 119:
+ player.x = AFTER_FIGHT_X;
+ player.y = AFTER_FIGHT_Y;
+ player.facing = FACING_WEST;
+ player.walker_visible = true;
+ global[player_score] += 5;
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_ANIM, aa[3]);
+ player_walk(WALK_TO_AFTER_FIGHT_X, WALK_TO_AFTER_FIGHT_Y, FACING_NORTHEAST);
+ kernel_flip_hotspot(words_Christine, false);
+ player_walk_trigger(ROOM_504_COMPLETE_CONV);
+ sound_play(N_AllFade);
+ break;
+
+ case 150:
+ sound_play(N_BackgroundMus);
+ break;
+
+ case 160:
+ if (local->phan_action == FIGHT_CHRIS_TALK) {
+ phan_reset_frame = 160;
+ } else if (local->phan_action != FIGHT_CHRIS_TO_DOOR) {
+ phan_reset_frame = 159;
+ } else {
+ phan_reset_frame = 164;
+ }
+ break;
+
+ case 161:
+ case 162:
+ case 163:
+ case 164:
+ if (local->phan_action == FIGHT_CHRIS_TO_DOOR) {
+ phan_reset_frame = 159;
+ } else {
+ phan_reset_frame = imath_random(160, 162);
+ }
+ ++local->chris_talk_count;
+ if (local->chris_talk_count > 10) {
+ phan_reset_frame = 159;
+ if (local->phan_action != FIGHT_CHRIS_TO_DOOR) {
+ local->phan_action = FIGHT_SWORD;
+ }
+ }
+ break;
+
+ }
+
+ if (phan_reset_frame >= 0) {
+ kernel_reset_animation(aa[3], phan_reset_frame);
+ local->phan_frame = phan_reset_frame;
+ }
+ }
+}
+
+static void handle_animation_phantom_3() {
+ int phan_reset_frame;
+
+ if (kernel_anim[aa[3]].frame != local->phan_frame) {
+ local->phan_frame = kernel_anim[aa[3]].frame;
+ phan_reset_frame = -1;
+
+ switch (local->phan_frame) {
+
+ case 58:
+ player.commands_allowed = true;
+ break;
+
+ case 80:
+ if (local->phan_action == FIGHT_CHRIS_TALK) {
+ phan_reset_frame = 116;
+ } else if (local->phan_action != FIGHT_CHRIS_LEAVE) {
+ phan_reset_frame = 79;
+ }
+ break;
+
+ case 115:
+ player_walk(EXIT_LEFT_DOOR_X, EXIT_LEFT_DOOR_Y, FACING_NORTHWEST);
+ player_walk_trigger(ROOM_504_EXIT_INTO_506);
+ break;
+
+ case 116:
+ phan_reset_frame = 115;
+ break;
+
+ case 117:
+ case 118:
+ case 119:
+ phan_reset_frame = imath_random(116, 118);
+ ++local->chris_talk_count;
+ if (local->chris_talk_count > 10) {
+ phan_reset_frame = 79;
+ if (local->phan_action != FIGHT_CHRIS_LEAVE) {
+ local->phan_action = FIGHT_CHRIS_TO_DOOR;
+ }
+ }
+ break;
+ }
+
+ if (phan_reset_frame >= 0) {
+ kernel_reset_animation(aa[3], phan_reset_frame);
+ local->phan_frame = phan_reset_frame;
+ }
+ }
+}
+
+
+static void handle_animation_chair() {
+ int chair_reset_frame;
+
+ if (kernel_anim[aa[2]].frame != local->chair_frame) {
+ local->chair_frame = kernel_anim[aa[2]].frame;
+ chair_reset_frame = -1;
+
+ switch (local->chair_frame) {
+
+ case 24:
+ player.commands_allowed = true;
+ break;
+
+ case 25:
+ case 26:
+ case 30:
+ case 31:
+
+ if (!local->prevent) {
+ local->prevent = true;
+ text_show(text_504_24);
+ /* someone is watching you */
+ }
+
+ if (local->chair_action == CHAIR_SIT) {
+ if (imath_random(1, 5) == 1) {
+ chair_reset_frame = imath_random(24, 30);
+
+ } else {
+ chair_reset_frame = local->chair_frame - 1;
+ }
+
+ } else {
+ chair_reset_frame = 31; /* get up */
+ }
+ break;
+
+ case 47:
+ chair_reset_frame = -1;
+ player.commands_allowed = true;
+ player.walker_visible = true;
+ player.ready_to_walk = true;
+ local->anim_2_running = false;
+ local->prevent = false;
+ kernel_abort_animation(aa[2]);
+ break;
+ }
+
+ if (chair_reset_frame >= 0) {
+ kernel_reset_animation(aa[2], chair_reset_frame);
+ local->chair_frame = chair_reset_frame;
+ }
+ }
+}
+
+
+void room_504_daemon() {
+ int id;
+
+ if (local->anim_0_running) {
+ handle_animation_listen();
+ }
+
+ if (local->anim_1_running) {
+ handle_animation_play_organ();
+ }
+
+ if (local->anim_2_running) {
+ handle_animation_chair();
+ }
+
+ if (local->anim_3_running) {
+ handle_animation_phantom_1();
+ }
+
+ if (local->anim_4_running) {
+ handle_animation_phantom_2();
+ }
+
+ if (local->anim_5_running) {
+ handle_animation_phantom_3();
+ }
+
+ if (kernel.trigger == ROOM_504_COMPLETE_CONV) {
+ player.commands_allowed = false;
+ conv_run(CONV_FIGHT);
+ conv_export_value(player_has(music_score));
+ conv_export_value(1);
+ global[fight_status] = FIGHT_TALKING;
+ /* after phantom dissapears into chair, chris & raoul say a few lines */
+ }
+
+ if (kernel.trigger == ROOM_504_FROM_502) {
+ player.walker_visible = true;
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_ANIM, aa[0]);
+ kernel_draw_to_background(ss[fx_trap_door], 1, KERNEL_HOME, KERNEL_HOME, 0, 100);
+ kernel_timing_trigger(HALF_SECOND, ROOM_504_FROM_502 + 1);
+ }
+
+ if (kernel.trigger == ROOM_504_FROM_502 + 1) {
+ player.commands_allowed = true;
+ kernel_timing_trigger(ONE_SECOND, ROOM_504_FROM_502 + 2);
+ }
+
+ if (kernel.trigger == ROOM_504_FROM_502 + 2) {
+ global[he_listened] = true;
+ player.commands_allowed = false;
+ conv_run(CONV_LISTEN);
+ conv_export_value(game.difficulty);
+ }
+
+ if (kernel.trigger == ROOM_504_OPEN_RIGHT_DOOR) {
+ sound_play(N_SecretDoor);
+ global[right_door_is_open_504] = true;
+ kernel_seq_delete(seq[fx_right_door]);
+ seq[fx_right_door] = kernel_seq_forward(ss[fx_right_door], false, 6, 0, 0, 1);
+ kernel_seq_depth(seq[fx_right_door], 1);
+ kernel_seq_range(seq[fx_right_door], KERNEL_FIRST, KERNEL_LAST);
+
+ seq[fx_ramhead] = kernel_seq_forward(ss[fx_ramhead], false, 6, 0, 0, 1);
+ kernel_seq_depth(seq[fx_ramhead], 1);
+ kernel_seq_range(seq[fx_ramhead], KERNEL_FIRST, KERNEL_LAST);
+ kernel_seq_trigger(seq[fx_ramhead], KERNEL_TRIGGER_EXPIRE, 0, ROOM_504_NEXT_FIRE);
+ }
+
+ if (kernel.trigger == ROOM_504_NEXT_FIRE) {
+ seq[fx_fire_left] = kernel_seq_forward(ss[fx_fire_left], false, 6, 0, 0, 1);
+ kernel_seq_depth(seq[fx_fire_left], 1);
+ kernel_seq_range(seq[fx_fire_left], KERNEL_FIRST, KERNEL_LAST);
+ kernel_seq_trigger(seq[fx_fire_left], KERNEL_TRIGGER_EXPIRE, 0, ROOM_504_NEXT_FIRE + 1);
+ }
+
+ if (kernel.trigger == ROOM_504_NEXT_FIRE + 1) {
+ seq[fx_fire_right] = kernel_seq_forward(ss[fx_fire_right], false, 6, 0, 0, 1);
+ kernel_seq_depth(seq[fx_fire_right], 1);
+ kernel_seq_range(seq[fx_fire_right], KERNEL_FIRST, KERNEL_LAST);
+ kernel_seq_trigger(seq[fx_fire_right], KERNEL_TRIGGER_EXPIRE, 0, ROOM_504_NEXT_FIRE + 2);
+ }
+
+ if (kernel.trigger == ROOM_504_NEXT_FIRE + 2) {
+ local->fire_breath = true;
+ }
+
+ if (local->fire_breath) {
+ seq[fx_ramhead] = kernel_seq_forward(ss[fx_ramhead], false, 6, 0, 0, 1);
+ kernel_seq_depth(seq[fx_ramhead], 1);
+ kernel_seq_range(seq[fx_ramhead], KERNEL_FIRST, KERNEL_LAST);
+ seq[fx_fire_left] = kernel_seq_forward(ss[fx_fire_left], false, 6, 0, 0, 1);
+ kernel_seq_depth(seq[fx_fire_left], 1);
+ kernel_seq_range(seq[fx_fire_left], KERNEL_FIRST, KERNEL_LAST);
+ seq[fx_fire_right] = kernel_seq_forward(ss[fx_fire_right], false, 6, 0, 0, 1);
+ kernel_seq_depth(seq[fx_fire_right], 1);
+ kernel_seq_range(seq[fx_fire_right], KERNEL_FIRST, KERNEL_LAST);
+ local->fire_breath = false;
+ }
+
+ if (kernel.trigger == ROOM_504_RUN_PART_3) {
+
+ kernel_abort_animation(aa[3]);
+ matte_deallocate_series(ss[fx_a_8], true);
+
+ local->anim_4_running = false;
+ local->anim_5_running = true;
+
+ /* I never unload these because at end of anim, new room = 506 */
+
+ ss[fx_test] = kernel_load_series("*CHR_2", PAL_MAP_ALL_TO_CLOSEST |
+ PAL_MAP_ANY_TO_CLOSEST);
+ ss[fx_test] = kernel_load_series("*CHR_3", PAL_MAP_ALL_TO_CLOSEST |
+ PAL_MAP_ANY_TO_CLOSEST);
+
+ kernel_load_variant(1);
+
+ aa[3] = kernel_run_animation(kernel_name('p', 3), 0);
+ id = kernel_add_dynamic(words_Christine, words_walk_to, SYNTAX_SINGULAR_FEM, KERNEL_NONE,
+ 0, 0, 0, 0);
+ kernel_dynamic_hot[id].prep = PREP_ON;
+ kernel_dynamic_walk(id, DYNAMIC_CHR_WALK_TO_X, DYNAMIC_CHR_WALK_TO_Y, FACING_NORTHWEST);
+ kernel_dynamic_anim(id, aa[3], 0);
+ kernel_dynamic_anim(id, aa[3], 1);
+ kernel_dynamic_anim(id, aa[3], 2);
+ kernel_dynamic_anim(id, aa[3], 3);
+ kernel_dynamic_anim(id, aa[3], 4);
+ }
+
+ if (kernel.trigger == ROOM_504_END_LISTEN) {
+ player.commands_allowed = true;
+ player.walker_visible = true;
+ local->anim_0_running = false;
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_ANIM, aa[0]);
+ }
+
+ if (kernel.trigger == ROOM_504_EXIT_INTO_506) {
+ new_room = 506;
+ }
+
+ if (kernel.trigger == ROOM_504_DONE_PLAYING) {
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_ANIM, aa[1]);
+ player.x = AFTER_PLAY_X;
+ player.y = AFTER_PLAY_Y;
+ player.walker_visible = true;
+ local->anim_1_running = false;
+ player_demand_facing(FACING_EAST);
+ kernel_timing_trigger(10, ROOM_504_DONE_PLAYING + 1);
+ }
+
+ if (kernel.trigger == ROOM_504_DONE_PLAYING + 1) {
+ player.commands_allowed = true;
+ matte_deallocate_series(ss[fx_fire_right], true);
+ matte_deallocate_series(ss[fx_fire_left], true);
+ }
+}
+
+void room_504_preload() {
+ room_init_code_pointer = room_504_init;
+ room_pre_parser_code_pointer = room_504_pre_parser;
+ room_parser_code_pointer = room_504_parser;
+ room_daemon_code_pointer = room_504_daemon;
+
+ section_5_walker();
+ section_5_interface();
+
+ vocab_make_active(words_Phantom);
+ vocab_make_active(words_Christine);
+}
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/rooms/room504.h b/engines/mads/madsv2/phantom/rooms/room504.h
new file mode 100644
index 00000000000..22bb49b5b1a
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room504.h
@@ -0,0 +1,189 @@
+/* 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 MADS_PHANTOM_ROOM504_H
+#define MADS_PHANTOM_ROOM504_H
+
+#include "mads/madsv2/core/general.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+#define local ((Scratch *)(&game.scratch[0]))
+#define ss local->sprite
+#define seq local->sequence
+#define aa local->animation
+
+typedef struct { /* Room local variables */
+
+ int16 sprite[17]; /* Sprite series handles */
+ int16 sequence[17]; /* Sequence handles */
+ int16 animation[4]; /* Animation handles */
+
+ int16 music_choice;
+ int16 input_count; /* counter for raoul taking sword */
+
+ int16 anim_0_running;
+ int16 anim_1_running;
+ int16 anim_2_running;
+ int16 anim_3_running;
+ int16 anim_4_running;
+ int16 anim_5_running;
+ int16 music_is_playing;
+ int16 play_count;
+ int16 fire_breath;
+
+ int16 listen_action; /* action Raoul is going to perform */
+ int16 listen_frame;
+
+ int16 chair_action; /* action Raoul is going to perform while in chair */
+ int16 chair_frame;
+
+ int16 play_action; /* action Raoul is going to perform at organ */
+ int16 play_frame;
+ int16 prevent;
+
+ int16 phan_action; /* action fight scene is going to perform at organ */
+ int16 phan_frame;
+
+ int16 chris_talk_count;
+
+ int16 death_count;
+
+} Scratch;
+
+
+/* ========================= Sprite Series =================== */
+
+#define fx_trap_door 0 /* rm504x2 */
+#define fx_left_door 1 /* rm504x1 */
+#define fx_right_door 2 /* rm504x0 */
+#define fx_ramhead 3 /* rm504x3 */
+#define fx_fire_left 4 /* rm504x4 */
+#define fx_fire_right 5 /* rm504x5 */
+#define fx_test 6 /* rm504x5 */
+#define fx_a_6 7
+#define fx_a_7 8
+#define fx_a_0 9
+#define fx_a_3 10
+#define fx_a_5 11
+#define fx_a_8 12
+#define fx_burn 13 /* rm504x7 */
+#define fx_take_9 14 /* *rdr_9 */
+#define fx_music 15 /* rm504x8 */
+#define fx_phan 15 /* facephn */
+
+
+/* 'test' is used many times to load a series so that I can
+ remap it. 'test' series are used in anims. */
+ /* fx'letters' are loaded in and dumped from memory later */
+
+
+ /* ========================= Triggers ======================== */
+
+#define ROOM_504_FROM_502 60
+#define ROOM_504_SIT 64
+#define ROOM_504_END_LISTEN 67
+#define ROOM_504_END_CONV 70
+#define ROOM_504_OPEN_RIGHT_DOOR 80
+#define ROOM_504_NEXT_FIRE 90
+#define ROOM_504_LISTEN 95
+#define ROOM_504_DONE_PLAYING 100
+#define ROOM_504_LOAD_NEW_PART 110
+#define ROOM_504_COMPLETE_CONV 120 /* (after sword battle) */
+#define ROOM_504_RUN_PART_3 130
+#define ROOM_504_EXIT_INTO_506 136
+#define ROOM_504_CHRIS_TALK 145
+
+
+/* ========================= Other Macros ==================== */
+
+#define CONV_LISTEN 19
+#define CONV_MUSIC 27
+#define CONV_FIGHT 21
+
+#define CONV19_LISTEN 0
+#define CONV19_OTHER 1
+
+#define PLAYER_X_FROM_502 147
+#define PLAYER_Y_FROM_502 131
+
+#define PLAYER_X_FROM_506 0
+#define PLAYER_Y_FROM_506 109
+
+#define WALK_TO_X_FROM_506 39
+#define WALK_TO_Y_FROM_506 118
+
+#define PLAYER_X_FROM_505 317
+#define PLAYER_Y_FROM_505 115
+
+#define WALK_TO_X_FROM_505 279
+#define WALK_TO_Y_FROM_505 121
+
+#define RIGHT_DOOR_X 286
+#define RIGHT_DOOR_Y 120
+
+#define BEHIND_RIGHT_DOOR_X 317
+#define BEHIND_RIGHT_DOOR_Y 115
+
+#define LEFT_DOOR_X 33
+#define LEFT_DOOR_Y 116
+
+#define CONV27_SELECT 0
+#define CONV27_PLAY 1
+
+#define AFTER_PLAY_X 156
+#define AFTER_PLAY_Y 114
+
+#define FIGHT_ENTER_ROOM 0
+#define FIGHT_BEFORE_DODGE 1
+#define FIGHT_CHOICE 2
+#define FIGHT_DIE 3
+#define FIGHT_SWORD 4
+#define FIGHT_CHRIS_TO_DOOR 5
+#define FIGHT_CHRIS_LEAVE 6
+#define FIGHT_CHRIS_TALK 7
+
+#define AFTER_FIGHT_X 114
+#define AFTER_FIGHT_Y 137
+
+#define WALK_TO_AFTER_FIGHT_X 130
+#define WALK_TO_AFTER_FIGHT_Y 135
+
+#define DYNAMIC_CHR_WALK_TO_X 66
+#define DYNAMIC_CHR_WALK_TO_Y 119
+
+#define EXIT_LEFT_DOOR_X 0
+#define EXIT_LEFT_DOOR_Y 109
+
+#define CONV_MISC 26
+
+#define CHAIR_SIT 0
+#define CHAIR_GET_UP 1
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/phantom/rooms/room505.cpp b/engines/mads/madsv2/phantom/rooms/room505.cpp
new file mode 100644
index 00000000000..e3330792567
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room505.cpp
@@ -0,0 +1,860 @@
+/* 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 "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/camera.h"
+#include "mads/madsv2/core/imath.h"
+#include "mads/madsv2/core/inter.h"
+#include "mads/madsv2/core/matte.h"
+#include "mads/madsv2/core/object.h"
+#include "mads/madsv2/core/sound.h"
+#include "mads/madsv2/core/text.h"
+#include "mads/madsv2/phantom/conv.h"
+#include "mads/madsv2/phantom/rooms/section5.h"
+#include "mads/madsv2/phantom/rooms/room505.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+void room_505_init() {
+ int id;
+
+ kernel.disable_fastwalk = true;
+
+ if (previous_room != KERNEL_RESTORING_GAME) {
+ local->they_parted = false;
+ local->leave_room = false;
+ local->anim_0_running = false;
+ local->anim_1_running = false;
+ local->anim_2_running = false;
+ local->made_it_past_106 = false;
+ }
+
+ /* ==================== Load conversation ==================== */
+
+ conv_get(CONV_COFFIN);
+
+ kernel_flip_hotspot_loc(words_lid, false, COVER_AIR_X, COVER_AIR_Y);
+ kernel_flip_hotspot(words_Christine, false);
+
+
+ /* ===================== Load Sprite Series ================== */
+
+ ss[fx_lid] = kernel_load_series(kernel_name('x', 6), false);
+ ss[fx_pusher] = kernel_load_series(kernel_name('a', 1), false);
+ ss[fx_skull_0] = kernel_load_series(kernel_name('x', 0), false);
+ ss[fx_skull_1] = kernel_load_series(kernel_name('x', 1), false);
+ ss[fx_skull_2] = kernel_load_series(kernel_name('x', 2), false);
+ ss[fx_skull_3] = kernel_load_series(kernel_name('x', 3), false);
+ ss[fx_skull_4] = kernel_load_series(kernel_name('x', 4), false);
+ ss[fx_skull_5] = kernel_load_series(kernel_name('x', 5), false);
+ ss[fx_take_9] = kernel_load_series(kernel_name('a', 4), false);
+
+ /* ========================= Previous Rooms ================== */
+
+
+ if (previous_room == KERNEL_RESTORING_GAME) {
+
+ if (conv_restore_running == CONV_COFFIN) {
+
+ kernel_flip_hotspot(words_lid, false);
+ kernel_flip_hotspot_loc(words_lid, true, COVER_AIR_X, COVER_AIR_Y);
+ seq[fx_lid] = kernel_seq_stamp(ss[fx_lid], false, 12);
+ kernel_seq_depth(seq[fx_lid], 1);
+
+ aa[1] = kernel_run_animation(kernel_name('c', 1), ROOM_505_AFTER_RESCUE);
+ kernel_reset_animation(aa[1], 109);
+ local->anim_1_running = true;
+ player.walker_visible = false;
+ player.commands_allowed = false;
+ local->both_action = BOTH_SHUT_UP;
+
+ conv_run(CONV_COFFIN);
+ conv_export_pointer(&global[player_score]);
+
+ } else if (local->they_parted && (global[fight_status] == FIGHT_NOT_HAPPENED)) {
+ kernel_flip_hotspot(words_lid, false);
+ kernel_flip_hotspot_loc(words_lid, true, COVER_AIR_X, COVER_AIR_Y);
+ seq[fx_lid] = kernel_seq_stamp(ss[fx_lid], false, 12);
+ kernel_seq_depth(seq[fx_lid], 1);
+
+ local->anim_2_running = true;
+ local->both_action = BOTH_SHUT_UP;
+ aa[2] = kernel_run_animation(kernel_name('b', 1), 0);
+ id = kernel_add_dynamic(words_Christine, words_walk_to, SYNTAX_SINGULAR_FEM, KERNEL_NONE,
+ 0, 0, 0, 0);
+ kernel_dynamic_hot[id].prep = PREP_ON;
+ kernel_dynamic_walk(id, DYNAMIC_CHR_WALK_TO_X, DYNAMIC_CHR_WALK_TO_Y, FACING_NORTHWEST);
+ kernel_reset_animation(aa[2], 89);
+ kernel_dynamic_anim(id, aa[2], 3);
+ kernel_dynamic_anim(id, aa[2], 4);
+ kernel_dynamic_anim(id, aa[2], 5);
+ kernel_dynamic_anim(id, aa[2], 6);
+ kernel_dynamic_anim(id, aa[2], 7);
+
+ } else if (global[fight_status]) {
+ kernel_flip_hotspot(words_lid, false);
+ kernel_flip_hotspot_loc(words_lid, true, COVER_AIR_X, COVER_AIR_Y);
+ seq[fx_lid] = kernel_seq_stamp(ss[fx_lid], false, 12);
+ kernel_seq_depth(seq[fx_lid], 1);
+
+ } else {
+ aa[1] = kernel_run_animation(kernel_name('c', 1), ROOM_505_AFTER_RESCUE);
+ local->anim_1_running = true;
+ local->both_action = HIT_GLASS;
+ kernel_flip_hotspot(words_Christine, true);
+ }
+ }
+
+ if ((previous_room == 504) || (previous_room != KERNEL_RESTORING_GAME)) {
+ player.x = PLAYER_X_FROM_504;
+ player.y = PLAYER_Y_FROM_504;
+ player.facing = FACING_EAST;
+ player.commands_allowed = false;
+ player_walk(WALK_TO_X_FROM_504, WALK_TO_Y_FROM_504, FACING_SOUTHEAST);
+ if (global[coffin_status] != COFFIN_OPEN) {
+ player_walk_trigger(ROOM_505_START_CONV);
+ local->anim_1_running = true;
+ local->both_action = HIT_GLASS;
+ kernel_flip_hotspot(words_Christine, true);
+ aa[1] = kernel_run_animation(kernel_name('c', 1), ROOM_505_AFTER_RESCUE);
+
+ } else {
+ kernel_flip_hotspot(words_lid, false);
+ kernel_flip_hotspot_loc(words_lid, true, COVER_AIR_X, COVER_AIR_Y);
+ seq[fx_lid] = kernel_seq_stamp(ss[fx_lid], false, 12);
+ kernel_seq_depth(seq[fx_lid], 1);
+ player.commands_allowed = true;
+ }
+ }
+
+ section_5_music();
+}
+
+static void process_conversation_coffin() {
+ int you_trig_flag = false;
+ int me_trig_flag = false;
+
+ switch (player_verb) {
+ case conv020_where_a:
+ me_trig_flag = true;
+ you_trig_flag = true;
+ if (!kernel.trigger) {
+ conv_hold();
+ player_walk(COFFIN_X, COFFIN_Y, FACING_SOUTHWEST);
+ player_walk_trigger(ROOM_505_START_CONV + 1);
+ }
+ break;
+
+ case conv020_exit_b_b:
+ me_trig_flag = true;
+ you_trig_flag = true;
+ if (!kernel.trigger) {
+ conv_hold();
+ local->raoul_action = CONV20_RAOUL_END;
+ }
+ break;
+
+ case conv020_bye_b_b:
+ me_trig_flag = true;
+ you_trig_flag = true;
+ local->both_action = PART;
+ break;
+
+ case conv020_dialogue_b_b:
+ me_trig_flag = true;
+ you_trig_flag = true;
+ if (!local->made_it_past_106) {
+ conv_hold();
+ }
+ break;
+
+ case conv020_story_b_b:
+ me_trig_flag = true;
+ you_trig_flag = true;
+ if (!kernel.trigger) {
+ conv_hold();
+ local->both_action = GIVE_RING;
+ }
+ break;
+ }
+
+ switch (kernel.trigger) {
+ case ROOM_505_START_CONV + 1:
+ aa[0] = kernel_run_animation(kernel_name('r', 1), ROOM_505_END_CONV);
+ local->anim_0_running = true;
+ local->raoul_action = CONV20_RAOUL_TALK;
+ local->raoul_talk_count = 0;
+ player.walker_visible = false;
+ break;
+
+ case ROOM_505_END_CONV:
+ player.walker_visible = true;
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_ANIM, aa[0]);
+ kernel_timing_trigger(10, ROOM_505_END_CONV + 1);
+ break;
+
+ case ROOM_505_END_CONV + 1:
+ conv_release();
+ break;
+
+ case ROOM_505_START_CONV:
+ conv_release();
+ break;
+
+ case ROOM_505_ME_TALK:
+ if ((local->both_action != PART) &&
+ (local->both_action != HIT_GLASS)) {
+ local->both_action = HE_TALK;
+ }
+ break;
+
+ case ROOM_505_YOU_TALK:
+ if ((local->both_action != PART) &&
+ (local->both_action != HIT_GLASS)) {
+ local->both_action = SHE_TALK;
+ }
+ break;
+
+ }
+
+ if (!me_trig_flag) {
+ conv_me_trigger(ROOM_505_ME_TALK);
+ } /* if me_trig_flag == true, then a me trigger is called from above, not here. */
+
+ if (!you_trig_flag) {
+ conv_you_trigger(ROOM_505_YOU_TALK);
+ } /* if you_trig_flag == true, then a you trigger is called from above, not here. */
+
+ local->both_talk_count = 0;
+}
+
+void room_505_pre_parser() {
+ if (player_said_2(unlock, skull_face) ||
+ player_said_2(unlock, sarcophagus) ||
+ player_said_3(put, key, skull_face) ||
+ player_said_2(unlock, lid)) {
+ if (global[coffin_status] == COFFIN_CLOSED) {
+ if (player_said_1(skull_face)) {
+ player_walk(LOCK_X, LOCK_Y, FACING_SOUTHWEST);
+ } else if (global[looked_at_skull_face]) {
+ player_walk(LOCK_X, LOCK_Y, FACING_SOUTHWEST);
+ }
+ }
+ }
+
+ if (player_said_1(skull_face)) {
+ if (player_said_1(look) || player_said_1(look_at)) {
+ player_walk(LOCK_X, LOCK_Y, FACING_SOUTHWEST);
+ }
+ }
+
+ if (player_said_1(look) || player_said_1(look_at)) {
+ if (player_said_1(curtain)) {
+ player.need_to_walk = true;
+ }
+ }
+
+ if (player_said_1(look) || player_said_1(look_at)) {
+ if (player_said_1(skull)) {
+ player.need_to_walk = true;
+ }
+ }
+}
+
+void room_505_parser() {
+ int id;
+ int skull_seq;
+
+ if (kernel.trigger == ROOM_505_HOLD_HANDS) {
+ local->both_action = GET_OUT_B;
+ goto handled;
+ }
+
+ if (conv_control.running == CONV_COFFIN) {
+ process_conversation_coffin();
+ goto handled;
+ }
+
+ if (player_said_2(talk_to, Christine)) {
+ if (global[coffin_status] != COFFIN_OPEN) {
+ text_show(text_505_36);
+ } else {
+ conv_run(CONV_COFFIN);
+ conv_export_pointer(&global[player_score]);
+ local->part_action = SHE_WAIT_TALK;
+ local->part_talk_count = 0;
+ }
+ goto handled;
+ }
+
+ if ((player_said_2(unlock, sarcophagus) || player_said_2(unlock, lid)) && !global[looked_at_skull_face]) {
+ text_show(text_505_39);
+ goto handled;
+ }
+
+ if ((player_said_2(unlock, skull_face) || player_said_3(put, key, skull_face)) ||
+ ((player_said_2(unlock, sarcophagus) || player_said_2(unlock, lid)) && global[looked_at_skull_face])) {
+ if (global[coffin_status] == COFFIN_CLOSED) {
+ switch (kernel.trigger) {
+ case (0):
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_take_9] = kernel_seq_pingpong(ss[fx_take_9], false,
+ 5, 0, 0, 2);
+ kernel_seq_range(seq[fx_take_9], KERNEL_FIRST, KERNEL_LAST);
+ kernel_seq_player(seq[fx_take_9], true);
+ kernel_seq_trigger(seq[fx_take_9],
+ KERNEL_TRIGGER_SPRITE, 9, ROOM_505_UNLOCK);
+ kernel_seq_trigger(seq[fx_take_9],
+ KERNEL_TRIGGER_EXPIRE, 0, ROOM_505_UNLOCK + 1);
+ goto handled;
+ break;
+
+ case ROOM_505_UNLOCK:
+ sound_play(N_CoffinUnlocks);
+ text_show(text_505_28);
+ goto handled;
+ break;
+
+ case ROOM_505_UNLOCK + 1:
+ player.walker_visible = true;
+ player.commands_allowed = true;
+ global[coffin_status] = COFFIN_UNLOCKED;
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_SERIES, seq[fx_take_9]);
+ goto handled;
+ break;
+ }
+
+ } else {
+ text_show(text_505_34);
+ goto handled;
+ }
+ }
+
+ if (player_said_2(push, skull) && (inter_point_x >= 19)) {
+ switch (kernel.trigger) {
+ case 0:
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_pusher] = kernel_seq_pingpong(ss[fx_pusher], false,
+ 5, 0, 0, 2);
+ kernel_seq_range(seq[fx_pusher], KERNEL_FIRST, KERNEL_LAST);
+ kernel_seq_player(seq[fx_pusher], true);
+ kernel_seq_trigger(seq[fx_pusher],
+ KERNEL_TRIGGER_SPRITE, 6, 1);
+ kernel_seq_trigger(seq[fx_pusher],
+ KERNEL_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ sound_play(N_PushSkull);
+ if (inter_point_x <= 44) {
+ id = ss[fx_skull_3];
+ } else if (inter_point_x <= 58) {
+ id = ss[fx_skull_2];
+ } else if (inter_point_x <= 71) {
+ id = ss[fx_skull_1];
+ } else if (inter_point_x <= 84) {
+ id = ss[fx_skull_0];
+ if (global[coffin_status] == COFFIN_UNLOCKED) {
+ local->both_action = GET_OUT_A;
+ kernel_flip_hotspot(words_lid, false);
+ kernel_flip_hotspot(words_Christine, false);
+ kernel_flip_hotspot_loc(words_lid, true, COVER_AIR_X, COVER_AIR_Y);
+ kernel_load_variant(1);
+ }
+ } else if (inter_point_x <= 100) {
+ id = ss[fx_skull_4];
+ } else {
+ id = ss[fx_skull_5];
+ }
+
+ skull_seq = kernel_seq_pingpong(id, false, 5, 0, 0, 2);
+ kernel_seq_range(skull_seq, KERNEL_FIRST, KERNEL_LAST);
+ kernel_seq_depth(skull_seq, 1);
+ break;
+
+ case 2:
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_SERIES, seq[fx_pusher]);
+ player.walker_visible = true;
+ player.commands_allowed = true;
+ if (local->both_action == GET_OUT_A) {
+ player_walk(HOLD_HANDS_X, HOLD_HANDS_Y, FACING_EAST);
+ player_walk_trigger(ROOM_505_HOLD_HANDS);
+ player.commands_allowed = false;
+ }
+ break;
+ }
+ goto handled;
+ }
+
+ if (player_said_2(walk_through, door)) {
+ if (local->anim_2_running) {
+ local->leave_room = true;
+ player.commands_allowed = false;
+ } else {
+ global[chris_left_505] = true;
+ new_room = 504;
+ }
+ goto handled;
+ }
+
+ if (player.look_around) {
+ text_show(text_505_10);
+ goto handled;
+ }
+
+ if (player_said_1(look) || player_said_1(look_at)) {
+
+ if (player_said_1(floor)) {
+ text_show(text_505_11);
+ goto handled;
+ }
+
+ if (player_said_1(wall)) {
+ text_show(text_505_12);
+ goto handled;
+ }
+
+ if (player_said_1(sarcophagus)) {
+ if (global[coffin_status] <= COFFIN_UNLOCKED) {
+ text_show(text_505_13);
+ } else {
+ text_show(text_505_14);
+ }
+ goto handled;
+ }
+
+ if (player_said_1(skull_face)) {
+ global[looked_at_skull_face] = true;
+ text_show(text_505_29);
+ goto handled;
+ }
+
+ if (player_said_1(door)) {
+ text_show(text_505_19);
+ goto handled;
+ }
+
+ if (player_said_1(skull)) {
+ if (inter_point_x < 19) {
+ text_show(text_505_21);
+ } else {
+ text_show(text_505_20);
+ }
+ goto handled;
+ }
+
+ if (player_said_1(skulls)) {
+ text_show(text_505_21);
+ goto handled;
+ }
+
+ if (player_said_1(totem)) {
+ text_show(text_505_22);
+ goto handled;
+ }
+
+ if (player_said_1(desk)) {
+ text_show(text_505_23);
+ goto handled;
+ }
+
+ if (player_said_1(pole)) {
+ text_show(text_505_24);
+ goto handled;
+ }
+
+ if (player_said_1(curtain)) {
+ text_show(text_505_25);
+ goto handled;
+ }
+
+ if (player_said_1(Christine)) {
+ if (global[coffin_status] == COFFIN_OPEN) {
+ text_show(text_505_30);
+ } else {
+ text_show(text_505_37);
+ }
+ goto handled;
+ }
+
+ if (player_said_1(lid)) {
+ if (global[coffin_status] == COFFIN_OPEN) {
+ text_show(text_505_31);
+ } else {
+ text_show(text_505_32);
+ }
+ goto handled;
+ }
+ }
+
+ if (player_said_2(lock, sarcophagus) ||
+ player_said_2(lock, lid) ||
+ player_said_2(lock, skull_face)) {
+ text_show(text_505_35);
+ goto handled;
+ }
+
+ if (player_said_2(open, sarcophagus) ||
+ player_said_2(open, lid)) {
+ if (global[coffin_status] == COFFIN_OPEN) {
+ text_show(text_505_33);
+ } else if (global[coffin_status] == COFFIN_UNLOCKED) {
+ text_show(text_505_18);
+ } else {
+ text_show(text_505_15);
+ }
+ goto handled;
+ }
+
+ if (player_said_2(take, Christine)) {
+ if (global[coffin_status] != COFFIN_OPEN) {
+ text_show(text_505_38);
+ goto handled;
+ }
+ }
+
+ if (player_said_2(take, Christine)) {
+ if (global[coffin_status] <= COFFIN_UNLOCKED) {
+ text_show(text_505_38);
+ } else {
+ text_show(text_505_40);
+ }
+ goto handled;
+ }
+
+ goto done;
+
+handled:
+ player.command_ready = false;
+
+done:
+ ;
+}
+
+static void handle_animation_raoul() {
+ int raoul_reset_frame;
+
+ if (kernel_anim[aa[0]].frame != local->raoul_frame) {
+ local->raoul_frame = kernel_anim[aa[0]].frame;
+ raoul_reset_frame = -1;
+
+ switch (local->raoul_frame) {
+ case 3:
+ conv_release();
+ break;
+
+ case 4: /* end of freeze and talk 1 */
+ case 5: /* end of talk 2 */
+ case 6: /* end of talk 2 */
+ if (local->raoul_action == CONV20_RAOUL_TALK) {
+ raoul_reset_frame = imath_random(3, 5);
+ ++local->raoul_talk_count;
+ if (local->raoul_talk_count > 20) {
+ local->raoul_action = CONV20_RAOUL_SHUT_UP;
+ raoul_reset_frame = 3;
+ }
+ break;
+ }
+
+ if (local->raoul_action == CONV20_RAOUL_SHUT_UP) {
+ raoul_reset_frame = 3;
+ }
+
+ if (local->raoul_action == CONV20_RAOUL_END) {
+ raoul_reset_frame = 6;
+ }
+ break;
+ }
+
+ if (raoul_reset_frame >= 0) {
+ kernel_reset_animation(aa[0], raoul_reset_frame);
+ local->raoul_frame = raoul_reset_frame;
+ }
+ }
+}
+
+static void handle_animation_both() {
+ int both_reset_frame;
+
+ if (kernel_anim[aa[1]].frame != local->both_frame) {
+ local->both_frame = kernel_anim[aa[1]].frame;
+ both_reset_frame = -1;
+
+ switch (local->both_frame) {
+ case 41:
+ sound_play(N_AngelMus505);
+ break;
+
+ case 51: /* lid is up in air */
+ seq[fx_lid] = kernel_seq_stamp(ss[fx_lid], false, 12);
+ kernel_seq_depth(seq[fx_lid], 1);
+ global[coffin_status] = COFFIN_OPEN;
+ break;
+
+ case 66:
+ player.commands_allowed = false;
+ conv_run(CONV_COFFIN);
+ conv_export_pointer(&global[player_score]);
+ break;
+
+ case 67:
+ if (local->both_action == GET_OUT_A) {
+ both_reset_frame = 66;
+ }
+ break;
+
+ case 68: /* make walker vanish */
+ player.walker_visible = false;
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_ANIM, aa[1]);
+ break;
+
+ case 32: /* almost end of hit glass once */
+ if (imath_random(1, 2) == 1) {
+ both_reset_frame = 28;
+ }
+ break;
+
+ case 14: /* almost end of hit glass twice */
+ if (imath_random(1, 3) == 1) {
+ both_reset_frame = 8;
+ }
+ break;
+
+ case 1: /* end of freeze */
+ case 20: /* end of hit glass 1 */
+ case 39: /* end of hot glass 2 */
+
+ if (local->both_action == HIT_GLASS) {
+ if (imath_random(1, 35) == 1) {
+ if (imath_random(1, 2) == 1) {
+ both_reset_frame = 1; /* bang on glass 1 */
+ } else {
+ both_reset_frame = 20; /* bang on glass 2 */
+ }
+
+ } else {
+ both_reset_frame = 0;
+ }
+
+ } else if (local->both_action == GET_OUT_A) {
+ both_reset_frame = 39;
+
+ } else {
+ both_reset_frame = 0;
+ }
+
+
+ break;
+
+ case 106:
+ local->made_it_past_106 = true;
+ conv_release();
+ break;
+
+ case 109:
+ case 130:
+ conv_release();
+ break;
+
+ case 127:
+ sound_play(N_TakeObjectSnd);
+ inter_give_to_player(wedding_ring);
+ object_examine(wedding_ring, text_008_21, 0);
+ /* show player the ring */
+ break;
+
+ case 110: /* end of he talk 1 */
+ case 111: /* end of he talk 2 */
+ case 112: /* end of he talk 3 */
+ case 113: /* end of she talk 1 */
+ case 114: /* end of she talk 2 */
+ case 115: /* end of she talk 3 */
+ case 131: /* end of give ring */
+
+ switch (local->both_action) {
+ case HE_TALK:
+ both_reset_frame = imath_random(109, 111);
+ ++local->both_talk_count;
+ if (local->both_talk_count > 20) {
+ local->both_action = BOTH_SHUT_UP;
+ both_reset_frame = 109;
+ } /* He will talk */
+ break;
+
+ case SHE_TALK:
+ both_reset_frame = imath_random(112, 114);
+ ++local->both_talk_count;
+ if (local->both_talk_count > 20) {
+ local->both_action = BOTH_SHUT_UP;
+ both_reset_frame = 109;
+ } /* She will talk */
+ break;
+
+ case GIVE_RING:
+ both_reset_frame = 115; /* She will give ring to Him */
+ local->both_action = BOTH_SHUT_UP;
+ break;
+
+ case PART:
+ both_reset_frame = 131;
+ local->both_action = SHE_WAIT;
+ player.commands_allowed = false;
+ break; /* She will go over to door, he will walk a couple of feet */
+
+ default:
+ both_reset_frame = 109;
+ break; /* freeze them holding hands */
+ }
+ break;
+ }
+
+ if (both_reset_frame >= 0) {
+ kernel_reset_animation(aa[1], both_reset_frame);
+ local->both_frame = both_reset_frame;
+ }
+ }
+}
+
+static void handle_animation_part() {
+ int part_reset_frame;
+
+ if (kernel_anim[aa[2]].frame != local->part_frame) {
+ local->part_frame = kernel_anim[aa[2]].frame;
+ part_reset_frame = -1;
+
+ switch (local->part_frame) {
+ case 20:
+ sound_play(N_BackgroundMus);
+ break;
+
+ case 90:
+ if (local->part_action == SHE_WAIT_TALK) {
+ part_reset_frame = 146;
+ } else if (!local->leave_room) {
+ part_reset_frame = 89;
+ }
+ break;
+
+ case 25:
+ player.x = RAOUL_END_X;
+ player.y = RAOUL_END_Y;
+ player_demand_facing(FACING_WEST);
+ player.walker_visible = true;
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_ANIM, aa[2]);
+ break;
+
+ case 70:
+ player.commands_allowed = true;
+ break;
+
+ case 145:
+ new_room = 504;
+ break;
+
+ case 147:
+ case 148:
+ case 149:
+ part_reset_frame = imath_random(146, 148);
+ ++local->part_talk_count;
+ if (local->part_talk_count > 10) {
+ part_reset_frame = 89;
+ local->part_action = SHE_WAIT;
+ }
+ break;
+ }
+
+ if (part_reset_frame >= 0) {
+ kernel_reset_animation(aa[2], part_reset_frame);
+ local->part_frame = part_reset_frame;
+ }
+ }
+}
+
+void room_505_daemon() {
+ int id;
+
+ if (local->anim_0_running) {
+ handle_animation_raoul();
+ }
+
+ if (local->anim_1_running) {
+ handle_animation_both();
+ }
+
+ if (local->anim_2_running) {
+ handle_animation_part();
+ }
+
+ if (kernel.trigger == ROOM_505_AFTER_RESCUE) {
+ kernel_abort_animation(aa[1]);
+ sound_play(N_AllFade);
+ local->they_parted = true;
+ local->anim_2_running = true;
+ local->anim_1_running = false;
+ /* player.commands_allowed = false; */
+ aa[2] = kernel_run_animation(kernel_name('b', 1), 0);
+ id = kernel_add_dynamic(words_Christine, words_walk_to, SYNTAX_SINGULAR_FEM, KERNEL_NONE,
+ 0, 0, 0, 0);
+ kernel_dynamic_walk(id, DYNAMIC_CHR_WALK_TO_X, DYNAMIC_CHR_WALK_TO_Y, FACING_NORTHWEST);
+ kernel_dynamic_hot[id].prep = PREP_ON;
+
+ kernel_dynamic_anim(id, aa[2], 3);
+ kernel_dynamic_anim(id, aa[2], 4);
+ kernel_dynamic_anim(id, aa[2], 5);
+ kernel_dynamic_anim(id, aa[2], 6);
+ kernel_dynamic_anim(id, aa[2], 7);
+ }
+
+ if (kernel.trigger == ROOM_505_START_CONV) {
+ player.commands_allowed = true;
+ if (!player.been_here_before) {
+ conv_run(CONV_COFFIN);
+ conv_export_pointer(&global[player_score]);
+ }
+ }
+}
+
+void room_505_preload() {
+ room_init_code_pointer = room_505_init;
+ room_pre_parser_code_pointer = room_505_pre_parser;
+ room_parser_code_pointer = room_505_parser;
+ room_daemon_code_pointer = room_505_daemon;
+
+ section_5_walker();
+ section_5_interface();
+
+ if ((global[coffin_status] == COFFIN_OPEN) && (!global[chris_left_505])) {
+ kernel_initial_variant = 1;
+ }
+
+ vocab_make_active(words_Christine);
+}
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/rooms/room505.h b/engines/mads/madsv2/phantom/rooms/room505.h
new file mode 100644
index 00000000000..33e2bdc66e8
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room505.h
@@ -0,0 +1,140 @@
+/* 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 MADS_PHANTOM_ROOM505_H
+#define MADS_PHANTOM_ROOM505_H
+
+#include "mads/madsv2/core/general.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+#define local ((Scratch *)(&game.scratch[0]))
+#define ss local->sprite
+#define seq local->sequence
+#define aa local->animation
+
+typedef struct { /* Room local variables */
+
+ int16 sprite[15]; /* Sprite series handles */
+ int16 sequence[15]; /* Sequence handles */
+ int16 animation[4]; /* Animation handles */
+
+ int16 raoul_action; /* action Raoul is going to perform */
+ int16 raoul_frame;
+ int16 raoul_talk_count;
+
+ int16 both_action; /* action They are going to perform */
+ int16 both_frame;
+ int16 both_talk_count;
+
+ int16 part_action; /* action They are going to perform (when parted) */
+ int16 part_frame;
+ int16 part_talk_count;
+
+ int16 anim_0_running;
+ int16 anim_1_running;
+ int16 anim_2_running;
+
+ int16 made_it_past_106; /* If T, will not put on conv_hold (during embrace) */
+ int16 leave_room; /* if T, She will follow him out door */
+ int16 they_parted;
+
+} Scratch;
+
+
+/* ========================= Sprite Series =================== */
+
+#define fx_pusher 0 /* rm505a1 */
+#define fx_skull_0 1 /* rm505x0 */
+#define fx_skull_1 2 /* rm505x1 */
+#define fx_skull_2 3 /* rm505x2 */
+#define fx_skull_3 4 /* rm505x3 */
+#define fx_skull_4 5 /* rm505x4 */
+#define fx_skull_5 6 /* rm505x5 */
+#define fx_lid 7 /* rm505x6 */
+#define fx_take_9 8 /* rm505a4 */
+
+
+/* ========================= Triggers ======================== */
+
+#define ROOM_505_OPEN_IT 60
+#define ROOM_505_AFTER_RESCUE 65
+#define ROOM_505_START_CONV 70
+#define ROOM_505_END_CONV 75
+#define ROOM_505_HOLD_HANDS 80
+#define ROOM_505_ME_TALK 85
+#define ROOM_505_YOU_TALK 90
+#define ROOM_505_UNLOCK 95
+
+
+/* ========================= Other Macros ==================== */
+
+#define CONV_COFFIN 20
+
+#define CONV20_RAOUL_TALK 0
+#define CONV20_RAOUL_SHUT_UP 1
+#define CONV20_RAOUL_END 2
+
+#define PLAYER_X_FROM_504 5
+#define PLAYER_Y_FROM_504 87
+
+#define WALK_TO_X_FROM_504 58
+#define WALK_TO_Y_FROM_504 104
+
+#define HIT_GLASS 0
+#define GET_OUT_A 1
+#define GET_OUT_B 2
+#define BOTH_SHUT_UP 3
+#define SHE_TALK 4
+#define HE_TALK 5
+#define PART 6
+#define GIVE_RING 7
+#define SHE_WAIT 8
+#define C_YA 9
+#define SHE_WAIT_TALK 10
+
+#define COFFIN_X 244
+#define COFFIN_Y 130
+
+#define HOLD_HANDS_X 136
+#define HOLD_HANDS_Y 126
+
+#define RAOUL_END_X 93
+#define RAOUL_END_Y 133
+
+#define DYNAMIC_CHR_WALK_TO_X 91
+#define DYNAMIC_CHR_WALK_TO_Y 108
+
+#define COVER_AIR_X 216
+#define COVER_AIR_Y 44
+
+#define LOCK_X 279
+#define LOCK_Y 150
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/phantom/rooms/room506.cpp b/engines/mads/madsv2/phantom/rooms/room506.cpp
new file mode 100644
index 00000000000..8026fe82ea1
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room506.cpp
@@ -0,0 +1,471 @@
+/* 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 "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/camera.h"
+#include "mads/madsv2/core/inter.h"
+#include "mads/madsv2/core/matte.h"
+#include "mads/madsv2/core/object.h"
+#include "mads/madsv2/core/pal.h"
+#include "mads/madsv2/core/sound.h"
+#include "mads/madsv2/core/text.h"
+#include "mads/madsv2/phantom/conv.h"
+#include "mads/madsv2/phantom/rooms/section5.h"
+#include "mads/madsv2/phantom/rooms/room506.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+void room_506_init() {
+ int id;
+
+ kernel.disable_fastwalk = true;
+
+ if (previous_room != KERNEL_RESTORING_GAME) {
+ local->anim_0_running = false;
+ local->prevent = false;
+ local->ascending = false;
+ }
+
+ conv_get(CONV_MISC);
+
+ /* ===================== Load Sprite Series ================== */
+
+ ss[fx_left_flame] = kernel_load_series(kernel_name('x', 0), false);
+ ss[fx_middle_flame] = kernel_load_series(kernel_name('x', 1), false);
+ ss[fx_right_flame] = kernel_load_series(kernel_name('x', 2), false);
+ ss[fx_door] = kernel_load_series(kernel_name('x', 3), false);
+ ss[fx_oar] = kernel_load_series(kernel_name('p', 0), false);
+ ss[fx_raoul_ascend] = kernel_load_series(kernel_name('a', 1), false);
+ ss[fx_raoul_decend] = kernel_load_series(kernel_name('a', 0), false);
+
+ ss[fx_christine] = kernel_load_series(kernel_name('b', 0), PAL_MAP_ALL_TO_CLOSEST |
+ PAL_MAP_ANY_TO_CLOSEST);
+
+ ss[fx_take_6] = kernel_load_series("*RDR_9", false);
+
+ ss[fx_christine] = kernel_load_series("*CHR_6", PAL_MAP_ALL_TO_CLOSEST |
+ PAL_MAP_ANY_TO_CLOSEST);
+ ss[fx_christine] = kernel_load_series("*CHR_3", PAL_MAP_ALL_TO_CLOSEST |
+ PAL_MAP_ANY_TO_CLOSEST);
+ ss[fx_christine] = kernel_load_series("*CHR_2", PAL_MAP_ALL_TO_CLOSEST |
+ PAL_MAP_ANY_TO_CLOSEST);
+
+ /* ======================== Stamp oar ======================== */
+
+ if (object_is_here(oar)) {
+ seq[fx_oar] = kernel_seq_stamp
+ (ss[fx_oar], false, 1);
+ kernel_seq_depth(seq[fx_oar], 14);
+
+ } else {
+ kernel_flip_hotspot(words_oar, false);
+ }
+
+ /* ======================= Stamp flames ====================== */
+
+ seq[fx_left_flame] = kernel_seq_forward(ss[fx_left_flame], false, 6, 0, 0, 0);
+ kernel_seq_depth(seq[fx_left_flame], 14);
+ kernel_seq_range(seq[fx_left_flame], KERNEL_FIRST, KERNEL_LAST);
+
+ seq[fx_middle_flame] = kernel_seq_forward(ss[fx_middle_flame], false, 6, 0, 0, 0);
+ kernel_seq_depth(seq[fx_middle_flame], 14);
+ kernel_seq_range(seq[fx_middle_flame], KERNEL_FIRST, KERNEL_LAST);
+
+ seq[fx_right_flame] = kernel_seq_forward(ss[fx_right_flame], false, 6, 0, 0, 0);
+ kernel_seq_depth(seq[fx_right_flame], 14);
+ kernel_seq_range(seq[fx_right_flame], KERNEL_FIRST, KERNEL_LAST);
+
+ /* ========================= Previous Rooms ================== */
+
+ if (previous_room == KERNEL_RESTORING_GAME) {
+ seq[fx_door] = kernel_seq_stamp
+ (ss[fx_door], false, 1);
+ kernel_seq_depth(seq[fx_door], 14);
+ if (!global[christine_is_in_boat]) {
+ local->anim_0_running = true;
+ aa[0] = kernel_run_animation(kernel_name('r', 1), 0);
+ kernel_reset_animation(aa[0], 239);
+ id = kernel_add_dynamic(words_Christine, words_walk_to, SYNTAX_SINGULAR_FEM, KERNEL_NONE,
+ 0, 0, 0, 0);
+ kernel_dynamic_hot[id].prep = PREP_ON;
+ kernel_dynamic_walk(id, DYNAMIC_CHR_WALK_TO_X, DYNAMIC_CHR_WALK_TO_Y, FACING_SOUTHWEST);
+ kernel_dynamic_anim(id, aa[0], 6);
+ }
+
+ } else if (previous_room == 504) {
+
+ seq[fx_door] = kernel_seq_stamp
+ (ss[fx_door], false, 1);
+ kernel_seq_depth(seq[fx_door], 14);
+
+ if (player.been_here_before) {
+ player.x = END_OF_DECEND_X;
+ player.y = END_OF_DECEND_Y;
+ player.facing = FACING_SOUTHWEST;
+ player.commands_allowed = false;
+ player.walker_visible = false;
+
+ if (!global[christine_is_in_boat]) {
+ local->anim_0_running = true;
+ aa[0] = kernel_run_animation(kernel_name('r', 1), 0);
+ kernel_reset_animation(aa[0], 239);
+ id = kernel_add_dynamic(words_Christine, words_walk_to, SYNTAX_SINGULAR_FEM, KERNEL_NONE,
+ 0, 0, 0, 0);
+ kernel_dynamic_hot[id].prep = PREP_ON;
+ kernel_dynamic_walk(id, DYNAMIC_CHR_WALK_TO_X, DYNAMIC_CHR_WALK_TO_Y, FACING_SOUTHWEST);
+ kernel_dynamic_anim(id, aa[0], 6);
+ }
+
+ aa[1] = kernel_run_animation(kernel_name('r', 2), ROOM_506_DONE_GOING_DOWN);
+
+ } else {
+ player.x = PLAYER_X_FROM_504;
+ player.y = PLAYER_Y_FROM_504;
+ player.facing = FACING_SOUTHWEST;
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ local->anim_0_running = true;
+ aa[0] = kernel_run_animation(kernel_name('r', 1), 0);
+ id = kernel_add_dynamic(words_Christine, words_walk_to, SYNTAX_SINGULAR_FEM, KERNEL_NONE,
+ 0, 0, 0, 0);
+ kernel_dynamic_hot[id].prep = PREP_ON;
+ kernel_dynamic_walk(id, DYNAMIC_CHR_WALK_TO_X, DYNAMIC_CHR_WALK_TO_Y, FACING_SOUTHWEST);
+ kernel_dynamic_anim(id, aa[0], 2);
+ kernel_dynamic_anim(id, aa[0], 3);
+ kernel_dynamic_anim(id, aa[0], 4);
+ kernel_dynamic_anim(id, aa[0], 5);
+ kernel_dynamic_anim(id, aa[0], 6);
+ }
+
+ } else if ((previous_room == 501) || (previous_room != KERNEL_RESTORING_GAME)) {
+ player.x = PLAYER_X_FROM_501;
+ player.y = PLAYER_Y_FROM_501;
+ player.facing = FACING_EAST;
+ player.commands_allowed = false;
+ player_walk(WALK_TO_X_FROM_501, WALK_TO_Y_FROM_501, FACING_EAST);
+ player_walk_trigger(ROOM_506_DOOR_CLOSES);
+ }
+ section_5_music();
+}
+
+void room_506_pre_parser() {
+ if (player_said_2(unlock, door) || player_said_2(lock, door)) {
+ player_walk(FRONT_OF_DOOR_X, FRONT_OF_DOOR_Y, FACING_NORTHWEST);
+ }
+
+ if (player_said_2(open, door)) {
+ if (inter_point_x < 150) {
+ player_walk(FRONT_OF_DOOR_X, FRONT_OF_DOOR_Y, FACING_NORTHWEST);
+ } else {
+ player_walk(START_OF_ASCEND_X, START_OF_ASCEND_Y, FACING_EAST);
+ }
+ }
+}
+
+void room_506_parser() {
+ if (player_said_2(talk_to, Christine)) {
+ conv_run(CONV_MISC);
+ conv_export_value(1);
+ kernel_reset_animation(aa[0], 290);
+ goto handled;
+ }
+
+ if (player_said_2(take, oar)) {
+ switch (kernel.trigger) {
+ case (0):
+ if (object_is_here(oar)) {
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_take_6] = kernel_seq_pingpong(ss[fx_take_6], true,
+ 5, 0, 0, 2);
+ kernel_seq_range(seq[fx_take_6], 1, 4);
+ kernel_seq_player(seq[fx_take_6], true);
+ kernel_seq_trigger(seq[fx_take_6],
+ KERNEL_TRIGGER_SPRITE, 4, 1);
+ kernel_seq_trigger(seq[fx_take_6],
+ KERNEL_TRIGGER_EXPIRE, 0, 2);
+ }
+ break;
+
+ case 1:
+ kernel_seq_delete(seq[fx_oar]);
+ kernel_flip_hotspot(words_oar, false);
+ inter_give_to_player(oar);
+ sound_play(N_TakeObjectSnd);
+ break;
+
+ case 2:
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_SERIES, seq[fx_take_6]);
+ player.walker_visible = true;
+ kernel_timing_trigger(20, 3);
+ break;
+
+ case 3:
+ object_examine(oar, text_008_24, 0);
+ /* You pick up the oar */
+ player.commands_allowed = true;
+ break;
+ }
+ goto handled;
+ }
+
+ if (player_said_2(walk_through, door) || player_said_2(open, door)) {
+ if (inter_point_x < 150) {
+ switch (kernel.trigger) {
+ case (0):
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_take_6] = kernel_seq_pingpong(ss[fx_take_6], true,
+ 5, 0, 0, 2);
+ kernel_seq_range(seq[fx_take_6], 1, 4);
+ kernel_seq_player(seq[fx_take_6], true);
+ kernel_seq_trigger(seq[fx_take_6],
+ KERNEL_TRIGGER_SPRITE, 4, ROOM_506_DOOR_OPENS);
+ kernel_seq_trigger(seq[fx_take_6],
+ KERNEL_TRIGGER_EXPIRE, 0, ROOM_506_DOOR_OPENS + 2);
+ break;
+
+ case ROOM_506_DOOR_OPENS:
+ kernel_seq_delete(seq[fx_door]);
+ seq[fx_door] = kernel_seq_forward(ss[fx_door], false,
+ 8, 0, 0, 1);
+ kernel_seq_depth(seq[fx_door], 14);
+ kernel_seq_range(seq[fx_door], KERNEL_FIRST, KERNEL_LAST);
+ kernel_seq_trigger(seq[fx_door],
+ KERNEL_TRIGGER_EXPIRE, 0, ROOM_506_DOOR_OPENS + 1);
+ sound_play(N_DoorOpens);
+ break;
+
+ case ROOM_506_DOOR_OPENS + 1:
+ player_walk(PLAYER_X_FROM_501, PLAYER_Y_FROM_501, FACING_WEST);
+ player_walk_trigger(ROOM_506_DOOR_OPENS + 3);
+ break;
+
+ case ROOM_506_DOOR_OPENS + 2:
+ player.walker_visible = true;
+ break;
+
+ case ROOM_506_DOOR_OPENS + 3:
+ if (global[christine_is_in_boat]) {
+ new_room = 501;
+ } else {
+ kernel_reset_animation(aa[0], 241);
+ }
+ break;
+ }
+
+ } else {
+ switch (kernel.trigger) {
+ case (0):
+ if (!global[christine_is_in_boat]) {
+ conv_run(CONV_MISC);
+ conv_export_value(2);
+ if (kernel_anim[aa[0]].frame == 240 ||
+ kernel_anim[aa[0]].frame == 239) {
+ kernel_reset_animation(aa[0], 290);
+ }
+ local->ascending = true;
+ }
+ player.commands_allowed = false;
+ player.walker_visible = false;
+ seq[fx_raoul_ascend] = kernel_seq_forward(ss[fx_raoul_ascend], false,
+ 5, 0, 0, 1);
+ kernel_seq_range(seq[fx_raoul_ascend], KERNEL_FIRST, KERNEL_LAST);
+ kernel_synch(KERNEL_SERIES, seq[fx_raoul_ascend], KERNEL_PLAYER, 0);
+ kernel_seq_trigger(seq[fx_raoul_ascend],
+ KERNEL_TRIGGER_EXPIRE, 0, ROOM_506_DONE_GOING_UP);
+ break;
+
+ case ROOM_506_DONE_GOING_UP:
+ conv_abort();
+ new_room = 504;
+ break;
+ }
+ }
+ goto handled;
+ }
+
+ if (conv_control.running == CONV_MISC) {
+ goto handled;
+ }
+
+ if (player.look_around) {
+ text_show(text_506_10);
+ goto handled;
+ }
+
+ if (player_said_1(look) || player_said_1(look_at)) {
+
+ if (player_said_1(floor)) {
+ text_show(text_506_11);
+ goto handled;
+ }
+
+ if (player_said_1(wall)) {
+ text_show(text_506_12);
+ goto handled;
+ }
+
+ if (player_said_1(torch)) {
+ text_show(text_506_13);
+ goto handled;
+ }
+
+ if (player_said_1(column)) {
+ text_show(text_506_14);
+ goto handled;
+ }
+
+ if (player_said_1(ceiling)) {
+ text_show(text_506_15);
+ goto handled;
+ }
+
+ if (player_said_1(ramp)) {
+ text_show(text_506_16);
+ goto handled;
+ }
+
+ if (player_said_1(door)) {
+ if (inter_point_x < 150) {
+ text_show(text_506_17);
+ } else {
+ text_show(text_506_18);
+ }
+ goto handled;
+ }
+
+ if (player_said_1(oar) && object_is_here(oar)) {
+ text_show(text_506_19);
+ goto handled;
+ }
+
+ if (player_said_1(Christine)) {
+ if (kernel_anim[aa[0]].frame < 235) {
+ text_show(text_506_21);
+ } else {
+ text_show(text_506_20);
+ }
+ goto handled;
+ }
+ }
+
+ if (player_said_2(take, torch)) {
+ text_show(text_506_13);
+ goto handled;
+ }
+
+ if (player_said_2(take, Christine)) {
+ text_show(text_506_22);
+ goto handled;
+ }
+
+
+ goto done;
+
+handled:
+ player.command_ready = false;
+
+done:
+ ;
+}
+
+void room_506_daemon() {
+ switch (kernel.trigger) {
+
+ case ROOM_506_DONE_GOING_DOWN:
+ player.walker_visible = true;
+ player.commands_allowed = true;
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_ANIM, aa[1]);
+ break;
+
+ case ROOM_506_DOOR_CLOSES:
+ seq[fx_door] = kernel_seq_backward(ss[fx_door], false, 6, 0, 0, 1);
+ kernel_seq_depth(seq[fx_door], 14);
+ kernel_seq_range(seq[fx_door], KERNEL_FIRST, KERNEL_LAST);
+ kernel_seq_trigger(seq[fx_door], KERNEL_TRIGGER_EXPIRE, 0, ROOM_506_DOOR_CLOSES + 1);
+ break;
+
+ case ROOM_506_DOOR_CLOSES + 1:
+ seq[fx_door] = kernel_seq_stamp
+ (ss[fx_door], false, 1);
+ kernel_seq_depth(seq[fx_door], 14);
+ player.commands_allowed = true;
+ break;
+ }
+
+ if (local->anim_0_running) {
+ if ((kernel_anim[aa[0]].frame == 141) && (!local->prevent)) {
+ player.walker_visible = true;
+ local->prevent = true;
+ kernel_synch(KERNEL_PLAYER, 0, KERNEL_ANIM, aa[0]);
+ }
+
+ if (kernel_anim[aa[0]].frame == 240) {
+ kernel_reset_animation(aa[0], 239);
+ }
+
+ if (kernel_anim[aa[0]].frame == 300) {
+ kernel_reset_animation(aa[0], 239);
+ }
+
+ if (kernel_anim[aa[0]].frame == 168) {
+ player.commands_allowed = true;
+ }
+
+ if (kernel_anim[aa[0]].frame == 289) {
+ new_room = 501;
+ }
+ }
+
+ if (local->ascending) {
+ if (conv_control.running != CONV_MISC) {
+ local->ascending = false;
+ player.commands_allowed = false;
+ }
+ }
+}
+
+void room_506_preload() {
+ room_init_code_pointer = room_506_init;
+ room_pre_parser_code_pointer = room_506_pre_parser;
+ room_parser_code_pointer = room_506_parser;
+ room_daemon_code_pointer = room_506_daemon;
+
+ section_5_walker();
+ section_5_interface();
+
+ vocab_make_active(words_Christine);
+ vocab_make_active(words_look_at);
+
+ if (!global[christine_is_in_boat]) {
+ kernel_initial_variant = 1;
+ }
+}
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/rooms/room506.h b/engines/mads/madsv2/phantom/rooms/room506.h
new file mode 100644
index 00000000000..d5e96b22418
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/room506.h
@@ -0,0 +1,104 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 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 MADS_PHANTOM_ROOM506_H
+#define MADS_PHANTOM_ROOM506_H
+
+#include "mads/madsv2/core/general.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+#define local ((Scratch *)(&game.scratch[0]))
+#define ss local->sprite
+#define seq local->sequence
+#define aa local->animation
+
+typedef struct { /* Room local variables */
+
+ int16 sprite[15]; /* Sprite series handles */
+ int16 sequence[15]; /* Sequence handles */
+ int16 animation[4]; /* Animation handles */
+ int16 anim_0_running;
+ int16 prevent;
+ int16 ascending;
+
+} Scratch;
+
+
+/* ========================= Sprite Series =================== */
+
+#define fx_left_flame 0 /* rm506x0 */
+#define fx_middle_flame 1 /* rm506x1 */
+#define fx_right_flame 2 /* rm506x2 */
+#define fx_door 3 /* rm506x3 */
+#define fx_take_6 4 /* rdrr_6 */
+#define fx_oar 5 /* rm506p0 */
+#define fx_christine 6 /* *chr_6 */
+ /* *chr_3 */
+ /* *chr_2 */
+#define fx_raoul_ascend 7 /* rm506a1 */
+#define fx_raoul_decend 8 /* rm506a0 */
+
+
+/* ========================= Triggers ======================== */
+
+#define ROOM_506_DOOR_CLOSES 60
+#define ROOM_506_DOOR_OPENS 65
+#define ROOM_506_DONE_GOING_UP 90
+#define ROOM_506_DONE_GOING_DOWN 95
+
+/* ========================= Other Macros ==================== */
+
+#define PLAYER_X_FROM_501 0
+#define PLAYER_Y_FROM_501 142
+
+#define WALK_TO_X_FROM_501 23
+#define WALK_TO_Y_FROM_501 145
+
+#define PLAYER_X_FROM_504 186
+#define PLAYER_Y_FROM_504 122
+
+#define WALK_TO_X_FROM_504 301
+#define WALK_TO_Y_FROM_504 98
+
+#define DYNAMIC_CHR_WALK_TO_X 79
+#define DYNAMIC_CHR_WALK_TO_Y 133
+
+#define END_OF_DECEND_X 189
+#define END_OF_DECEND_Y 123
+
+#define START_OF_ASCEND_X 191
+#define START_OF_ASCEND_Y 118
+
+#define FRONT_OF_DOOR_X 33
+#define FRONT_OF_DOOR_Y 142
+
+#define CONV_MISC 26
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/phantom/rooms/section2.cpp b/engines/mads/madsv2/phantom/rooms/section2.cpp
new file mode 100644
index 00000000000..87f99d74b5a
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/section2.cpp
@@ -0,0 +1,41 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "mads/madsv2/phantom/rooms/section1.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+void section_2_music() {
+}
+
+void section_2_walker() {
+}
+
+void section_2_interface() {
+}
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/rooms/section3.cpp b/engines/mads/madsv2/phantom/rooms/section3.cpp
new file mode 100644
index 00000000000..30a4d725f3a
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/section3.cpp
@@ -0,0 +1,41 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "mads/madsv2/phantom/rooms/section1.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+void section_3_music() {
+}
+
+void section_3_walker() {
+}
+
+void section_3_interface() {
+}
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/rooms/section4.cpp b/engines/mads/madsv2/phantom/rooms/section4.cpp
new file mode 100644
index 00000000000..5d4816addba
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/section4.cpp
@@ -0,0 +1,41 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "mads/madsv2/phantom/rooms/section1.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+void section_4_music() {
+}
+
+void section_4_walker() {
+}
+
+void section_4_interface() {
+}
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/rooms/section5.cpp b/engines/mads/madsv2/phantom/rooms/section5.cpp
new file mode 100644
index 00000000000..7808f66f926
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/section5.cpp
@@ -0,0 +1,41 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "mads/madsv2/phantom/rooms/section1.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+void section_5_music() {
+}
+
+void section_5_walker() {
+}
+
+void section_5_interface() {
+}
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/rooms/section5.h b/engines/mads/madsv2/phantom/rooms/section5.h
new file mode 100644
index 00000000000..f4b7c4255bd
--- /dev/null
+++ b/engines/mads/madsv2/phantom/rooms/section5.h
@@ -0,0 +1,46 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef MADS_PHANTOM_SECTION5_H
+#define MADS_PHANTOM_SECTION5_H
+
+#include "mads/madsv2/phantom/mads/inventory.h"
+#include "mads/madsv2/phantom/mads/quotes.h"
+#include "mads/madsv2/phantom/mads/sounds.h"
+#include "mads/madsv2/phantom/mads/words.h"
+#include "mads/madsv2/phantom/mads/text.h"
+#include "mads/madsv2/phantom/global.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+namespace Rooms {
+
+extern void section_5_music();
+extern void section_5_walker();
+extern void section_5_interface();
+
+} // namespace Rooms
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index 5415cf02dbd..3515b421197 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -147,6 +147,7 @@ MODULE_OBJS += \
madsv2/phantom/rooms/room207.o \
madsv2/phantom/rooms/room208.o \
madsv2/phantom/rooms/room250.o \
+ madsv2/phantom/rooms/section3.o \
madsv2/phantom/rooms/room301.o \
madsv2/phantom/rooms/room302.o \
madsv2/phantom/rooms/room303.o \
@@ -157,6 +158,7 @@ MODULE_OBJS += \
madsv2/phantom/rooms/room308.o \
madsv2/phantom/rooms/room309.o \
madsv2/phantom/rooms/room310.o \
+ madsv2/phantom/rooms/section4.o \
madsv2/phantom/rooms/room401.o \
madsv2/phantom/rooms/room403.o \
madsv2/phantom/rooms/room404.o \
@@ -167,6 +169,12 @@ MODULE_OBJS += \
madsv2/phantom/rooms/room410.o \
madsv2/phantom/rooms/room453.o \
madsv2/phantom/rooms/room456.o \
+ madsv2/phantom/rooms/section5.o \
+ madsv2/phantom/rooms/room501.o \
+ madsv2/phantom/rooms/room502.o \
+ madsv2/phantom/rooms/room504.o \
+ madsv2/phantom/rooms/room505.o \
+ madsv2/phantom/rooms/room506.o \
madsv2/phantom/phantom.o \
madsv2/phantom/conv.o \
madsv2/phantom/global.o \
Commit: 7445927a07fc525559666b4636bb18cf5501e594
https://github.com/scummvm/scummvm/commit/7445927a07fc525559666b4636bb18cf5501e594
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:52+10:00
Commit Message:
MADS: PHANTOM: Implement section handlers
Changed paths:
engines/mads/madsv2/core/player.h
engines/mads/madsv2/phantom/mads/sounds.h
engines/mads/madsv2/phantom/rooms/room501.cpp
engines/mads/madsv2/phantom/rooms/section1.cpp
engines/mads/madsv2/phantom/rooms/section2.cpp
engines/mads/madsv2/phantom/rooms/section3.cpp
engines/mads/madsv2/phantom/rooms/section4.cpp
engines/mads/madsv2/phantom/rooms/section5.cpp
diff --git a/engines/mads/madsv2/core/player.h b/engines/mads/madsv2/core/player.h
index b2742f8ee59..d3cdbfcf906 100644
--- a/engines/mads/madsv2/core/player.h
+++ b/engines/mads/madsv2/core/player.h
@@ -41,8 +41,7 @@ namespace MADSV2 {
#define PLAYER_MAX_STOP 12 /* Max items in stop-walker stack */
-
-typedef struct {
+struct Player {
int walking; /* Player is "on the move" */
int x, y; /* Player's current screen location */
int target_x, target_y; /* Player's screen destination */
@@ -140,8 +139,7 @@ typedef struct {
int walk_trigger_words[3]; /* Vocabulary words for reactivating parser*/
int enable_at_target; /* Enable commands at walk target */
-
-} Player;
+};
typedef struct {
diff --git a/engines/mads/madsv2/phantom/mads/sounds.h b/engines/mads/madsv2/phantom/mads/sounds.h
index 22a7dea19dd..dbd91b517ef 100644
--- a/engines/mads/madsv2/phantom/mads/sounds.h
+++ b/engines/mads/madsv2/phantom/mads/sounds.h
@@ -29,37 +29,57 @@ namespace MADSV2 {
namespace Phantom {
enum {
+ /* Shared */
N_AllFade = 1,
N_MusicOff = 2,
N_MusicFade = 3,
+ N_NoiseFade = 5,
N_IsAnySoundOn = 8,
N_BackgroundMus = 16,
N_DoorOpens = 24,
N_DoorCloses = 25,
N_TakeObjectSnd = 26,
N_PlayerDies = 27,
+
+ /* Section 1 */
+ N_JacquesDeadMus = 32,
+ N_1881Music = 33,
N_AngelMus001 = 34,
+ N_Christine1881_001 = 35,
+ N_Christine1993 = 36,
+ N_PhantomAppears001 = 37,
N_BackMus1stTime = 38,
- N_PoisonGas = 61,
+ N_ChaseMusic001 = 39,
N_TrapDoor001 = 64,
- N_WomanScream002 = 65,
N_SqueakyDoor = 66,
N_PlayerFalls = 67,
N_EchoSteps = 68,
- N_Applause002 = 69,
N_SandbagThud = 70,
+ N_DoorHandle = 73,
+
+ /* Section 2 */
+ N_IsabelWedding = 34,
+ N_WomanScream002 = 65,
+ N_Applause002 = 69,
N_KeyTurnSnd = 71,
N_DoorHandle002 = 72,
- N_DoorHandle = 73,
- N_WomanScream003 = 74,
+ /* Section 3 */
+ N_FightMusic304 = 33,
+ N_LakeMusic = 36,
N_Crash003 = 66,
- N_DoorHandle004 = 70,
+ N_WomanScream003 = 74,
+ /* Section 4 */
+ N_PoisonGas = 61,
N_LeverSnap = 65,
N_LeverBing = 66,
N_DoorGong = 67,
+ N_DoorHandle004 = 70,
+ N_DoorHandle501 = 74,
+ /* Section 5 */
+ N_FightMusic504 = 33,
N_Bach_dm = 34,
N_Gigue = 35,
N_Canon = 36,
diff --git a/engines/mads/madsv2/phantom/rooms/room501.cpp b/engines/mads/madsv2/phantom/rooms/room501.cpp
index e0b58f5d2bb..3d5ade65f4d 100644
--- a/engines/mads/madsv2/phantom/rooms/room501.cpp
+++ b/engines/mads/madsv2/phantom/rooms/room501.cpp
@@ -421,7 +421,7 @@ void room_501_parser() {
kernel_synch(KERNEL_SERIES, seq[fx_take_6], KERNEL_SERIES, temp);
kernel_seq_player(seq[fx_take_6], false);
kernel_timing_trigger(QUARTER_SECOND, 2);
- sound_play(N_DoorHandle);
+ sound_play(N_DoorHandle501);
break;
case 2:
diff --git a/engines/mads/madsv2/phantom/rooms/section1.cpp b/engines/mads/madsv2/phantom/rooms/section1.cpp
index c771c3063dc..36f980d91f4 100644
--- a/engines/mads/madsv2/phantom/rooms/section1.cpp
+++ b/engines/mads/madsv2/phantom/rooms/section1.cpp
@@ -19,6 +19,16 @@
*
*/
+#include "mads/madsv2/core/config.h"
+#include "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/inter.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/pal.h"
+#include "mads/madsv2/core/player.h"
+#include "mads/madsv2/core/sound.h"
+#include "mads/madsv2/phantom/conv.h"
+#include "mads/madsv2/phantom/global.h"
+#include "mads/madsv2/phantom/mads/sounds.h"
#include "mads/madsv2/phantom/rooms/section1.h"
namespace MADS {
@@ -26,13 +36,210 @@ namespace MADSV2 {
namespace Phantom {
namespace Rooms {
-void section_1_music() {
-}
+extern void room_101_preload();
+extern void room_102_preload();
+extern void room_103_preload();
+extern void room_104_preload();
+extern void room_105_preload();
+extern void room_106_preload();
+extern void room_107_preload();
+extern void room_108_preload();
+extern void room_109_preload();
+extern void room_110_preload();
+extern void room_111_preload();
+extern void room_112_preload();
+extern void room_113_preload();
+extern void room_114_preload();
+extern void room_150_preload();
+
void section_1_walker() {
+ char temp_buf[80];
+
+ sound_queue(N_NoiseFade);
+
+ Common::strcpy_s(temp_buf, player.series_name);
+
+ if (!player.force_series)
+ Common::strcpy_s(player.series_name, "RAL");
+
+ if (strcmp(temp_buf, player.series_name) != 0)
+ player.walker_must_reload = true;
+
+ player.scaling_velocity = true;
}
void section_1_interface() {
+ Common::strcpy_s(kernel.interface, kernel_interface_name(global[temp_interface]));
+
+ pal_change_color(INTER_MESSAGE_COLOR, 43, 47, 51);
+}
+
+void section_1_music() {
+ if (sound_off) {
+ sound_play(N_NoiseFade);
+ }
+
+ if (music_off) {
+ sound_play(N_MusicFade);
+ goto done;
+ }
+
+ if (global[done_brie_conv_203] == YES_AND_CHASE) {
+ sound_play(N_ChaseMusic001);
+
+ } else {
+ switch (new_room) {
+ case 101:
+ if (!player.been_here_before) {
+ sound_play(N_BackMus1stTime);
+
+ } else {
+ sound_play(N_BackgroundMus);
+ }
+ break;
+
+ case 111:
+ if (previous_room == 150) {
+ sound_play(N_BackMus1stTime);
+
+ } else if (global[leave_angel_music_on]) {
+ sound_play(N_AngelMus001);
+
+ } else {
+ sound_play(N_BackgroundMus);
+ }
+ break;
+
+ case 113:
+ if (global[leave_angel_music_on]) {
+ sound_play(N_AngelMus001);
+
+ } else {
+ if (global[current_year] == 1993) {
+ sound_play(N_Christine1993);
+
+ } else {
+ sound_play(N_Christine1881_001);
+ }
+ }
+ break;
+
+ case 103:
+ if ((global[jacques_status] == JACQUES_IS_DEAD_RICH_GONE)) {
+ sound_play(N_JacquesDeadMus);
+ global[jacques_status] = JAC_DEAD_RICH_GONE_SEEN_BODY;
+
+ } else {
+ sound_play(N_BackgroundMus);
+ }
+ break;
+
+ case 102:
+ if (previous_room == 104) {
+ sound_play(N_PlayerDies);
+
+ } else {
+ sound_play(N_BackgroundMus);
+ }
+ break;
+
+ case 104:
+ if ((conv_restore_running == 7) || (previous_room == 301)) {
+ sound_play(N_1881Music);
+
+ } else if ((global[room_103_104_transition] == PEEK_THROUGH) &&
+ (!global[observed_phan_104])) {
+ sound_play(N_PhantomAppears001);
+ global[observed_phan_104] = true;
+
+ } else {
+ sound_play(N_BackgroundMus);
+ }
+ break;
+
+ default:
+ if ((previous_room != 204) && (new_room != 150)) {
+ sound_play(N_BackgroundMus);
+ }
+ break;
+ }
+ }
+
+done:
+ ;
+}
+
+void section_1_init() {
+ player.scaling_velocity = true;
+}
+
+void section_1_constructor() {
+ room_preload_code_pointer = NULL;
+ room_init_code_pointer = NULL;
+ room_daemon_code_pointer = NULL;
+ room_pre_parser_code_pointer = NULL;
+ room_parser_code_pointer = NULL;
+ room_error_code_pointer = NULL;
+ room_shutdown_code_pointer = NULL;
+
+ switch (new_room) {
+ case 101:
+ room_preload_code_pointer = room_101_preload;
+ break;
+ case 102:
+ room_preload_code_pointer = room_102_preload;
+ break;
+ case 103:
+ room_preload_code_pointer = room_103_preload;
+ break;
+ case 104:
+ room_preload_code_pointer = room_104_preload;
+ break;
+ case 105:
+ room_preload_code_pointer = room_105_preload;
+ break;
+ case 106:
+ room_preload_code_pointer = room_106_preload;
+ break;
+ case 107:
+ room_preload_code_pointer = room_107_preload;
+ break;
+ case 108:
+ room_preload_code_pointer = room_108_preload;
+ break;
+ case 109:
+ room_preload_code_pointer = room_109_preload;
+ break;
+ case 110:
+ room_preload_code_pointer = room_110_preload;
+ break;
+ case 111:
+ room_preload_code_pointer = room_111_preload;
+ break;
+ case 112:
+ room_preload_code_pointer = room_112_preload;
+ break;
+ case 113:
+ room_preload_code_pointer = room_113_preload;
+ break;
+ case 114:
+ room_preload_code_pointer = room_114_preload;
+ break;
+ case 150:
+ room_preload_code_pointer = room_150_preload;
+ break;
+ }
+
+ room_himem_preload(new_room, SECTION);
+}
+
+void section_1_preload() {
+ section_init_code_pointer = section_1_init;
+ section_room_constructor = section_1_constructor;
+ section_music_reset_pointer = section_1_music;
+ section_daemon_code_pointer = NULL;
+ section_parser_code_pointer = NULL;
}
} // namespace Rooms
diff --git a/engines/mads/madsv2/phantom/rooms/section2.cpp b/engines/mads/madsv2/phantom/rooms/section2.cpp
index 87f99d74b5a..e58d7adb649 100644
--- a/engines/mads/madsv2/phantom/rooms/section2.cpp
+++ b/engines/mads/madsv2/phantom/rooms/section2.cpp
@@ -19,20 +19,145 @@
*
*/
-#include "mads/madsv2/phantom/rooms/section1.h"
+#include "mads/madsv2/core/config.h"
+#include "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/inter.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/pal.h"
+#include "mads/madsv2/core/player.h"
+#include "mads/madsv2/core/sound.h"
+#include "mads/madsv2/phantom/conv.h"
+#include "mads/madsv2/phantom/global.h"
+#include "mads/madsv2/phantom/mads/sounds.h"
+#include "mads/madsv2/phantom/rooms/section2.h"
namespace MADS {
namespace MADSV2 {
namespace Phantom {
namespace Rooms {
-void section_2_music() {
-}
+extern void room_201_preload();
+extern void room_202_preload();
+extern void room_203_preload();
+extern void room_204_preload();
+extern void room_205_preload();
+extern void room_206_preload();
+extern void room_207_preload();
+extern void room_208_preload();
+extern void room_250_preload();
+
void section_2_walker() {
+ char temp_buf[80];
+
+ sound_queue(N_NoiseFade);
+
+ if (new_room == 208) {
+ player.series_name[0] = 0;
+
+ } else {
+ Common::strcpy_s(temp_buf, player.series_name);
+ if (!player.force_series)
+ Common::strcpy_s(player.series_name, "RAL");
+ if (strcmp(temp_buf, player.series_name) != 0)
+ player.walker_must_reload = true;
+ }
+
+ player.scaling_velocity = true;
}
+
+
void section_2_interface() {
+ Common::strcpy_s(kernel.interface, kernel_interface_name(global[temp_interface]));
+
+ pal_change_color(INTER_MESSAGE_COLOR, 43, 47, 51);
+}
+
+void section_2_music() {
+ if (sound_off) {
+ sound_play(N_NoiseFade);
+ }
+
+ if (music_off) {
+ sound_play(N_MusicFade);
+ goto done;
+ }
+
+ switch (new_room) {
+ case 208:
+ sound_play(N_IsabelWedding);
+ break;
+
+ case 206:
+ if (!global[knocked_over_head]) {
+ sound_play(N_BackgroundMus);
+ }
+ break;
+
+ default:
+ if (new_room != 250) {
+ sound_play(N_BackgroundMus);
+ }
+ break;
+ }
+
+done:
+ ;
+}
+
+void section_2_init() {
+ player.scaling_velocity = true;
+}
+
+void section_2_constructor() {
+ room_preload_code_pointer = NULL;
+ room_init_code_pointer = NULL;
+ room_daemon_code_pointer = NULL;
+ room_pre_parser_code_pointer = NULL;
+ room_parser_code_pointer = NULL;
+ room_error_code_pointer = NULL;
+ room_shutdown_code_pointer = NULL;
+
+ switch (new_room) {
+ case 201:
+ room_preload_code_pointer = room_201_preload;
+ break;
+ case 202:
+ room_preload_code_pointer = room_202_preload;
+ break;
+ case 203:
+ room_preload_code_pointer = room_203_preload;
+ break;
+ case 204:
+ room_preload_code_pointer = room_204_preload;
+ break;
+ case 205:
+ room_preload_code_pointer = room_205_preload;
+ break;
+ case 206:
+ room_preload_code_pointer = room_206_preload;
+ break;
+ case 207:
+ room_preload_code_pointer = room_207_preload;
+ break;
+ case 208:
+ room_preload_code_pointer = room_208_preload;
+ break;
+ case 250:
+ room_preload_code_pointer = room_250_preload;
+ break;
+ }
+
+ room_himem_preload(new_room, SECTION);
+}
+
+void section_2_preload() {
+ section_init_code_pointer = section_2_init;
+ section_room_constructor = section_2_constructor;
+ section_music_reset_pointer = section_2_music;
+ section_parser_code_pointer = NULL;
+ section_daemon_code_pointer = NULL;
}
} // namespace Rooms
diff --git a/engines/mads/madsv2/phantom/rooms/section3.cpp b/engines/mads/madsv2/phantom/rooms/section3.cpp
index 30a4d725f3a..d5e7fa8de2e 100644
--- a/engines/mads/madsv2/phantom/rooms/section3.cpp
+++ b/engines/mads/madsv2/phantom/rooms/section3.cpp
@@ -19,6 +19,16 @@
*
*/
+#include "mads/madsv2/core/config.h"
+#include "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/inter.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/pal.h"
+#include "mads/madsv2/core/player.h"
+#include "mads/madsv2/core/sound.h"
+#include "mads/madsv2/phantom/conv.h"
+#include "mads/madsv2/phantom/global.h"
+#include "mads/madsv2/phantom/mads/sounds.h"
#include "mads/madsv2/phantom/rooms/section1.h"
namespace MADS {
@@ -26,13 +36,148 @@ namespace MADSV2 {
namespace Phantom {
namespace Rooms {
-void section_3_music() {
-}
+extern void room_301_preload();
+extern void room_302_preload();
+extern void room_303_preload();
+extern void room_304_preload();
+extern void room_305_preload();
+extern void room_306_preload();
+extern void room_307_preload();
+extern void room_308_preload();
+extern void room_309_preload();
+extern void room_310_preload();
+
void section_3_walker() {
+ char temp_buf[80];
+
+ sound_play(N_NoiseFade);
+
+ if ((new_room == 304) || (new_room == 305) || (new_room == 306) || (new_room == 310)) {
+ player.series_name[0] = 0;
+
+ } else {
+ Common::strcpy_s(temp_buf, player.series_name);
+ if (!player.force_series)
+ Common::strcpy_s(player.series_name, "RAL");
+ if (strcmp(temp_buf, player.series_name) != 0)
+ player.walker_must_reload = true;
+ }
+
+ player.scaling_velocity = true;
}
void section_3_interface() {
+ Common::strcpy_s(kernel.interface, kernel_interface_name(global[temp_interface]));
+
+ pal_change_color(INTER_MESSAGE_COLOR, 43, 47, 51);
+}
+
+void section_3_music() {
+ if (sound_off) {
+ sound_play(N_NoiseFade);
+ }
+
+ if (music_off) {
+ sound_play(N_MusicFade);
+ goto done;
+ }
+
+ switch (new_room) {
+ case 303:
+ case 304:
+ case 305:
+ case 307:
+ case 308:
+ if (global[knocked_over_head]) {
+ sound_play(N_FightMusic304);
+ } else {
+ sound_play(N_BackgroundMus);
+ }
+ break;
+
+ case 310:
+ case 320:
+ case 330:
+ case 340:
+ sound_play(N_LakeMusic);
+ break;
+
+ default:
+ if (new_room != 306) {
+ sound_play(N_BackgroundMus);
+ }
+ break;
+ }
+
+done:
+ ;
+}
+
+void section_3_init() {
+ player.scaling_velocity = true;
+}
+
+void section_3_constructor() {
+ room_preload_code_pointer = NULL;
+ room_init_code_pointer = NULL;
+ room_daemon_code_pointer = NULL;
+ room_pre_parser_code_pointer = NULL;
+ room_parser_code_pointer = NULL;
+ room_error_code_pointer = NULL;
+ room_shutdown_code_pointer = NULL;
+
+ switch (new_room) {
+ case 301:
+ room_preload_code_pointer = room_301_preload;
+ break;
+
+ case 302:
+ room_preload_code_pointer = room_302_preload;
+ break;
+
+ case 303:
+ room_preload_code_pointer = room_303_preload;
+ break;
+
+ case 304:
+ room_preload_code_pointer = room_304_preload;
+ break;
+
+ case 305:
+ room_preload_code_pointer = room_305_preload;
+ break;
+
+ case 306:
+ room_preload_code_pointer = room_306_preload;
+ break;
+
+ case 307:
+ room_preload_code_pointer = room_307_preload;
+ break;
+
+ case 308:
+ room_preload_code_pointer = room_308_preload;
+ break;
+
+ case 309:
+ room_preload_code_pointer = room_309_preload;
+ break;
+
+ case 310:
+ room_preload_code_pointer = room_310_preload;
+ break;
+ }
+
+ room_himem_preload(new_room, SECTION);
+}
+
+void section_3_preload() {
+ section_init_code_pointer = section_3_init;
+ section_room_constructor = section_3_constructor;
+ section_music_reset_pointer = section_3_music;
+ section_parser_code_pointer = NULL;
+ section_daemon_code_pointer = NULL;
}
} // namespace Rooms
diff --git a/engines/mads/madsv2/phantom/rooms/section4.cpp b/engines/mads/madsv2/phantom/rooms/section4.cpp
index 5d4816addba..75ba96133f0 100644
--- a/engines/mads/madsv2/phantom/rooms/section4.cpp
+++ b/engines/mads/madsv2/phantom/rooms/section4.cpp
@@ -19,20 +19,137 @@
*
*/
-#include "mads/madsv2/phantom/rooms/section1.h"
+#include "mads/madsv2/core/config.h"
+#include "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/inter.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/pal.h"
+#include "mads/madsv2/core/player.h"
+#include "mads/madsv2/core/sound.h"
+#include "mads/madsv2/phantom/conv.h"
+#include "mads/madsv2/phantom/global.h"
+#include "mads/madsv2/phantom/mads/sounds.h"
+#include "mads/madsv2/phantom/rooms/section4.h"
namespace MADS {
namespace MADSV2 {
namespace Phantom {
namespace Rooms {
-void section_4_music() {
-}
+extern void room_401_preload();
+extern void room_403_preload();
+extern void room_404_preload();
+extern void room_406_preload();
+extern void room_407_preload();
+extern void room_408_preload();
+extern void room_409_preload();
+extern void room_410_preload();
+extern void room_453_preload();
+extern void room_456_preload();
+
void section_4_walker() {
+ char temp_buf[80];
+
+ sound_queue(N_NoiseFade);
+
+ Common::strcpy_s(temp_buf, player.series_name);
+
+ if (!player.force_series)
+ Common::strcpy_s(player.series_name, "RAL");
+
+ if (strcmp(temp_buf, player.series_name) != 0)
+ player.walker_must_reload = true;
+
+ player.scaling_velocity = true;
}
void section_4_interface() {
+ Common::strcpy_s(kernel.interface, kernel_interface_name(1));
+
+ pal_change_color(INTER_MESSAGE_COLOR, 43, 47, 51);
+}
+
+void section_4_music() {
+ if (sound_off) {
+ sound_play(N_NoiseFade);
+ }
+
+ if (music_off) {
+ sound_play(N_MusicFade);
+ goto done;
+ }
+
+ sound_play(N_BackgroundMus);
+
+done:
+ ;
+}
+
+void section_4_init() {
+ player.scaling_velocity = true;
+}
+
+void section_4_constructor() {
+ room_preload_code_pointer = NULL;
+ room_init_code_pointer = NULL;
+ room_daemon_code_pointer = NULL;
+ room_pre_parser_code_pointer = NULL;
+ room_parser_code_pointer = NULL;
+ room_error_code_pointer = NULL;
+ room_shutdown_code_pointer = NULL;
+
+ switch (new_room) {
+ case 401:
+ room_preload_code_pointer = room_401_preload;
+ break;
+
+ case 403:
+ room_preload_code_pointer = room_403_preload;
+ break;
+
+ case 404:
+ room_preload_code_pointer = room_404_preload;
+ break;
+
+ case 406:
+ room_preload_code_pointer = room_406_preload;
+ break;
+
+ case 407:
+ room_preload_code_pointer = room_407_preload;
+ break;
+
+ case 408:
+ room_preload_code_pointer = room_408_preload;
+ break;
+
+ case 409:
+ room_preload_code_pointer = room_409_preload;
+ break;
+
+ case 410:
+ room_preload_code_pointer = room_410_preload;
+ break;
+
+ case 453:
+ room_preload_code_pointer = room_453_preload;
+ break;
+
+ case 456:
+ room_preload_code_pointer = room_456_preload;
+ break;
+ }
+
+ room_himem_preload(new_room, SECTION);
+}
+
+void section_4_preload() {
+ section_init_code_pointer = section_4_init;
+ section_room_constructor = section_4_constructor;
+ section_music_reset_pointer = section_4_music;
+ section_daemon_code_pointer = NULL;
+ section_parser_code_pointer = NULL;
}
} // namespace Rooms
diff --git a/engines/mads/madsv2/phantom/rooms/section5.cpp b/engines/mads/madsv2/phantom/rooms/section5.cpp
index 7808f66f926..3d0f282bef5 100644
--- a/engines/mads/madsv2/phantom/rooms/section5.cpp
+++ b/engines/mads/madsv2/phantom/rooms/section5.cpp
@@ -19,20 +19,127 @@
*
*/
-#include "mads/madsv2/phantom/rooms/section1.h"
+#include "mads/madsv2/core/config.h"
+#include "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/inter.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/pal.h"
+#include "mads/madsv2/core/player.h"
+#include "mads/madsv2/core/sound.h"
+#include "mads/madsv2/phantom/conv.h"
+#include "mads/madsv2/phantom/global.h"
+#include "mads/madsv2/phantom/mads/sounds.h"
+#include "mads/madsv2/phantom/rooms/section5.h"
namespace MADS {
namespace MADSV2 {
namespace Phantom {
namespace Rooms {
-void section_5_music() {
-}
+extern void room_501_preload();
+extern void room_502_preload();
+extern void room_504_preload();
+extern void room_505_preload();
+extern void room_506_preload();
+
void section_5_walker() {
+ char temp_buf[80];
+
+ sound_queue(N_NoiseFade);
+
+ Common::strcpy_s(temp_buf, player.series_name);
+
+ if (!player.force_series)
+ Common::strcpy_s(player.series_name, "RAL");
+
+ if (strcmp(temp_buf, player.series_name) != 0)
+ player.walker_must_reload = true;
+
+ player.scaling_velocity = true;
}
void section_5_interface() {
+ Common::strcpy_s(kernel.interface, kernel_interface_name(1));
+
+ pal_change_color(INTER_MESSAGE_COLOR, 43, 47, 51);
+}
+
+void section_5_music() {
+ if (sound_off) {
+ sound_play(N_NoiseFade);
+ }
+
+ if (music_off) {
+ sound_play(N_MusicFade);
+ goto done;
+ }
+
+ if (global[coffin_status] == COFFIN_OPEN && !player_has_been_in_room(506) &&
+ global[fight_status] == FIGHT_NOT_HAPPENED && room_id == 504) {
+ sound_play(N_FightMusic504);
+ /* we are in the fight at some stage */
+
+ } else if (room_id == 505) {
+ if (conv_restore_running == 20) { /* running coffin conv */
+ sound_play(N_AngelMus505);
+
+ } else {
+ sound_play(N_BackgroundMus);
+ }
+
+ } else {
+ sound_play(N_BackgroundMus);
+ }
+
+done:
+ ;
+}
+
+void section_5_init() {
+ player.scaling_velocity = true;
+}
+
+void section_5_constructor() {
+ room_preload_code_pointer = NULL;
+ room_init_code_pointer = NULL;
+ room_daemon_code_pointer = NULL;
+ room_pre_parser_code_pointer = NULL;
+ room_parser_code_pointer = NULL;
+ room_error_code_pointer = NULL;
+ room_shutdown_code_pointer = NULL;
+
+ switch (new_room) {
+ case 501:
+ room_preload_code_pointer = room_501_preload;
+ break;
+
+ case 502:
+ room_preload_code_pointer = room_502_preload;
+ break;
+
+ case 504:
+ room_preload_code_pointer = room_504_preload;
+ break;
+
+ case 505:
+ room_preload_code_pointer = room_505_preload;
+ break;
+
+ case 506:
+ room_preload_code_pointer = room_506_preload;
+ break;
+ }
+
+ room_himem_preload(new_room, SECTION);
+}
+
+void section_5_preload() {
+ section_init_code_pointer = section_5_init;
+ section_room_constructor = section_5_constructor;
+ section_music_reset_pointer = section_5_music;
+ section_daemon_code_pointer = NULL;
+ section_parser_code_pointer = NULL;
}
} // namespace Rooms
Commit: 787fd241a58c0a6c92b1d9b71d88d031776f157e
https://github.com/scummvm/scummvm/commit/787fd241a58c0a6c92b1d9b71d88d031776f157e
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:53+10:00
Commit Message:
MADS: PHANTOM: Seperating out and completing catacombs code
Changed paths:
A engines/mads/madsv2/phantom/catacombs.cpp
A engines/mads/madsv2/phantom/catacombs.h
engines/mads/madsv2/phantom/global.cpp
engines/mads/madsv2/phantom/global.h
engines/mads/madsv2/phantom/rooms/room309.cpp
engines/mads/madsv2/phantom/rooms/room401.cpp
engines/mads/madsv2/phantom/rooms/room403.cpp
engines/mads/madsv2/phantom/rooms/room404.cpp
engines/mads/madsv2/phantom/rooms/room406.cpp
engines/mads/madsv2/phantom/rooms/room407.cpp
engines/mads/madsv2/phantom/rooms/room408.cpp
engines/mads/madsv2/phantom/rooms/room409.cpp
engines/mads/madsv2/phantom/rooms/room453.cpp
engines/mads/madsv2/phantom/rooms/room456.cpp
engines/mads/madsv2/phantom/rooms/room501.cpp
engines/mads/module.mk
diff --git a/engines/mads/madsv2/phantom/catacombs.cpp b/engines/mads/madsv2/phantom/catacombs.cpp
new file mode 100644
index 00000000000..f9b53568c14
--- /dev/null
+++ b/engines/mads/madsv2/phantom/catacombs.cpp
@@ -0,0 +1,280 @@
+/* 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 "mads/madsv2/phantom/catacombs.h"
+#include "mads/madsv2/phantom/global.h"
+#include "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/error.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+
+/* Fun stuff for the catacombs */
+
+#define NORTH 0
+#define EAST 1
+#define SOUTH 2
+#define WEST 3
+
+#define DIRECTION_MASK 0x0003
+#define FLAGS_MASK 0x00fc
+
+#define CATACOMBS_TO_309 -2
+#define CATACOMBS_TO_409a -3
+#define CATACOMBS_TO_409b -4
+#define CATACOMBS_TO_501 -5
+
+
+struct Catacombs {
+ int16 room_id; /* Room ID of catacomb part. */
+ int8 exit[4]; /* Catacomb room # if exit in direction */
+ int8 from[4]; /* When exit, will enter from this direction */
+ int16 misc; /* Miscellaneous bit data */
+};
+
+Catacombs *catacombs = NULL;
+
+Catacombs easy_catacombs[32] = {
+ { 401, { -1, 1, 2, 6 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BRICK },
+ { 404, { 10, 11, 3, 0 }, { SOUTH, WEST, NORTH, EAST }, MAZE_PUDDLE },
+ { 404, { 0, 3, 4, CATACOMBS_TO_309 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BLOCK },
+ { 401, { 1, 14, 5, 2 }, { SOUTH, WEST, NORTH, EAST }, MAZE_POT },
+ { 453, { 2, 4, -1, 4 }, { SOUTH, WEST, NORTH, EAST }, MAZE_DRAIN },
+ { 403, { 3, 6, -1, -1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BRICK | MAZE_PLANK },
+ { 406, { -1, 0, -1, 5 }, { SOUTH, WEST, NORTH, EAST }, 0 },
+ { 453, { -1, 8, -1, -1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BRICK },
+ /* 8 */
+ { 406, { -1, 9, -1, 7 }, { SOUTH, WEST, NORTH, EAST }, 0 },
+ { 401, { 1, -1, 10, 8 }, { SOUTH, WEST, NORTH, EAST }, MAZE_RAT_NEST | MAZE_SKULL },
+ { 408, { 9, -1, 1, -1 }, { SOUTH, WEST, NORTH, EAST }, 0 },
+ { 453, { 12, -1, -1, 1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BRICK | MAZE_STONE },
+ /* 12 */
+ { 408, { 13, -1, 11, -1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BRICK },
+ { 401, { 13, 20, 12, 13 }, { WEST, WEST, NORTH, NORTH }, MAZE_BRICK },
+ { 453, { 16, 15, -1, 3 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BRICK | MAZE_RAT_NEST },
+ { 456, { -1, -1, -1, 14 }, { SOUTH, WEST, NORTH, EAST }, 0 },
+ /* 16 */
+ { 404, { -1, 17, 14, -1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_WEB | MAZE_POT },
+ { 401, { 18, -1, 19, 16 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BRICK },
+ { 408, { -1, -1, 17, -1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BRICK },
+ { 403, { 17, -1, -1, -1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_HOLE | MAZE_WEB },
+ /* 20 */
+ { 403, { 21, 22, -1, 13 }, { SOUTH, WEST, NORTH, EAST }, MAZE_WEB | MAZE_SKULL },
+ { 404, { -1, -1, 20, -1 }, { SOUTH, WEST, NORTH, EAST }, 0 },
+ { 406, { -1, 23, -1, 20 }, { SOUTH, WEST, NORTH, EAST }, 0 },
+ { 404, { 24, 23, 23, 22 }, { SOUTH, SOUTH, EAST, EAST }, MAZE_RAT_NEST | MAZE_BRICK },
+ /* 24 */
+ { 401, { -1, 1, 23, 25 }, { SOUTH, EAST, NORTH, EAST }, MAZE_PUDDLE | MAZE_POT | MAZE_BRICK },
+ { 407, { 29, 24, 28, 26 }, { WEST, WEST, EAST, EAST }, 0 },
+ { 401, { 27, 25, 23, -1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_SKULL },
+ { 404, { -1, 28, 26, -1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_WEB | MAZE_FALLEN_BLOCK },
+ /* 28 */
+ { 456, { -1, 25, -1, 27 }, { SOUTH, SOUTH, NORTH, EAST }, 0 },
+ { 406, { -1, 30, -1, 25 }, { SOUTH, WEST, NORTH, NORTH }, 0 },
+ { 453, { CATACOMBS_TO_409a, 30, -1, 29 }, { SOUTH, WEST, NORTH, EAST },
+ MAZE_STONE | MAZE_RAT_NEST | MAZE_WEB },
+ { 408, { CATACOMBS_TO_501, -1, CATACOMBS_TO_409b, -1 }, { SOUTH, WEST, NORTH, EAST },
+ MAZE_WEB | MAZE_BRICK }
+};
+
+Catacombs hard_catacombs[62] = {
+ { 401, { -1, 1, 2, 6 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BRICK },
+ { 404, { 10, 11, 3, 0 }, { SOUTH, WEST, NORTH, EAST }, MAZE_PUDDLE },
+ { 404, { 0, 3, 4, CATACOMBS_TO_309 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BLOCK },
+ { 401, { 1, 20, 5, 2 }, { SOUTH, NORTH, NORTH, EAST }, MAZE_POT },
+ { 453, { 2, 4, -1, 4 }, { SOUTH, WEST, NORTH, EAST }, MAZE_DRAIN },
+ { 403, { 3, 6, -1, 4 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BRICK | MAZE_PLANK },
+ { 406, { -1, 0, -1, 5 }, { SOUTH, WEST, NORTH, EAST }, 0 },
+ { 453, { -1, 8, -1, -1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BRICK },
+ /* 8 */
+ { 406, { -1, 9, -1, 7 }, { SOUTH, WEST, NORTH, EAST }, 0 },
+ { 401, { 1, -1, 10, 8 }, { NORTH, WEST, NORTH, EAST }, MAZE_RAT_NEST | MAZE_SKULL },
+ { 408, { 9, -1, 1, -1 }, { SOUTH, WEST, NORTH, EAST }, 0 },
+ { 453, { 12, -1, -1, 1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BRICK | MAZE_STONE },
+ /* 12 */
+ { 408, { 13, -1, 11, -1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BRICK },
+ { 401, { 13, 21, 12, 13 }, { WEST, WEST, NORTH, NORTH }, MAZE_BRICK },
+ { 453, { 16, 15, -1, 20 }, { SOUTH, WEST, NORTH, SOUTH }, MAZE_RAT_NEST | MAZE_BRICK },
+ { 456, { -1, -1, -1, 14 }, { SOUTH, WEST, NORTH, EAST }, 0 },
+ /* 16 */
+ { 404, { -1, 17, 14, -1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_WEB | MAZE_POT },
+ { 401, { 18, -1, 19, 16 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BRICK },
+ { 408, { -1, -1, 17, -1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BRICK },
+ { 403, { 17, -1, -1, -1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_HOLE | MAZE_WEB },
+ /* 20 */
+ { 408, { 3, -1, 14, -1 }, { EAST, WEST, WEST, EAST }, 0 },
+ { 404, { 9, 30, 22, 13 }, { NORTH, WEST, NORTH, EAST }, MAZE_RAT_NEST },
+ { 403, { 21, 23, -1, -1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_HOLE | MAZE_WEB },
+ { 401, { -1, -1, 24, 22 }, { SOUTH, WEST, WEST, EAST }, MAZE_BRICK },
+ /* 24 */
+ { 406, { -1, 26, -1, 23 }, { SOUTH, NORTH, NORTH, SOUTH }, 0 },
+ { 407, { 36, 33, 35, 34 }, { WEST, WEST, EAST, EAST }, 0 },
+ { 453, { 24, 27, -1, -1 }, { EAST, NORTH, NORTH, EAST }, MAZE_BRICK },
+ { 403, { 26, -1, -1, 28 }, { EAST, WEST, NORTH, NORTH }, MAZE_BRICK | MAZE_SKULL },
+ /* 28 */
+ { 404, { 27, 28, 28, 29 }, { WEST, SOUTH, EAST, SOUTH }, 0 },
+ { 408, { -1, -1, 28, -1 }, { SOUTH, WEST, WEST, EAST }, MAZE_BRICK },
+ { 406, { -1, 31, -1, 21 }, { SOUTH, NORTH, NORTH, EAST }, 0 },
+ { 401, { 30, 33, 1, -1 }, { EAST, SOUTH, EAST, EAST }, MAZE_PUDDLE | MAZE_POT },
+ /* 32 */
+ { 456, { -1, 31, -1, 33 }, { SOUTH, EAST, NORTH, NORTH }, 0 },
+ { 404, { 32, -1, 31, 25 }, { WEST, WEST, EAST, EAST }, 0 },
+ { 401, { 46, 25, 31, -1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_SKULL },
+ { 401, { -1, 25, 41, -1 }, { SOUTH, SOUTH, EAST, EAST }, MAZE_BRICK | MAZE_POT },
+ /* 36 */
+ { 406, { -1, 37, -1, 25 }, { SOUTH, WEST, NORTH, NORTH }, 0 },
+ { 453, { CATACOMBS_TO_409a, 37, -1, 36 }, { SOUTH, WEST, NORTH, EAST }, MAZE_STONE | MAZE_RAT_NEST | MAZE_WEB },
+ { 408, { 57, -1, 54, -1 }, { SOUTH, WEST, NORTH, EAST }, 0 },
+ { 408, { 40, -1, CATACOMBS_TO_409b, -1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BRICK | MAZE_WEB },
+ /* 40 */
+ { 404, { 40, 40, 39, 53 }, { EAST, NORTH, NORTH, EAST }, MAZE_BLOCK | MAZE_FALLEN_BLOCK },
+ { 456, { -1, 35, -1, 42 }, { SOUTH, SOUTH, NORTH, SOUTH }, 0 },
+ { 408, { 43, -1, 41, -1 }, { EAST, WEST, WEST, EAST }, MAZE_BRICK },
+ { 406, { -1, 42, -1, 61 }, { SOUTH, NORTH, NORTH, EAST }, 0 },
+ /* 44 */
+ { 403, { 58, 45, -1, -1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BRICK | MAZE_RAT_NEST },
+ { 401, { 34, -1, 46, 44 }, { NORTH, WEST, NORTH, EAST }, MAZE_RAT_NEST | MAZE_BRICK },
+ { 404, { 45, -1, 34, 47 }, { SOUTH, WEST, NORTH, EAST }, MAZE_WEB | MAZE_FALLEN_BLOCK },
+ { 406, { -1, 46, -1, 48 }, { SOUTH, WEST, NORTH, EAST }, 0 },
+ /* 48 */
+ { 403, { 49, 47, -1, -1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BRICK | MAZE_SKULL | MAZE_WEB },
+ { 408, { 50, -1, 48, -1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BRICK },
+ { 408, { 51, -1, 49, -1 }, { SOUTH, WEST, NORTH, EAST }, 0 },
+ { 408, { 52, -1, 50, -1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BRICK },
+ /* 52 */
+ { 408, { -1, -1, 51, -1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BRICK },
+ { 406, { -1, 40, -1, 54 }, { SOUTH, WEST, NORTH, EAST }, 0 },
+ { 403, { 38, 53, -1, 55 }, { SOUTH, WEST, NORTH, EAST }, MAZE_SKULL },
+ { 453, { 56, 54, -1, -1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BRICK | MAZE_WEB },
+ /* 56 */
+ { 401, { 56, CATACOMBS_TO_501, 55, 56 }, { WEST, WEST, NORTH, NORTH }, MAZE_BRICK | MAZE_SKULL },
+ { 404, { -1, 57, 38, 57 }, { SOUTH, WEST, NORTH, EAST }, MAZE_POT | MAZE_BLOCK },
+ { 404, { 59, 59, 44, 60 }, { SOUTH, WEST, NORTH, EAST }, 0 },
+ { 404, { 59, 60, 59, 58 }, { SOUTH, WEST, NORTH, EAST }, 0 },
+ /* 60 */
+ { 404, { 61, 58, 59, 59 }, { SOUTH, WEST, NORTH, EAST }, 0 },
+ { 404, { 34, 43, 60, 44 }, { NORTH, WEST, NORTH, EAST }, 0 }
+};
+
+static void global_catacombs_setup() {
+ if (game.difficulty == HARD_MODE) {
+ catacombs = hard_catacombs;
+ global[catacombs_309_from] = 3;
+ global[catacombs_409a] = 37;
+ global[catacombs_409a_from] = 0;
+ global[catacombs_409b] = 39;
+ global[catacombs_309] = 2;
+ global[catacombs_409b_from] = 2;
+ global[catacombs_501] = 56;
+ global[catacombs_501_from] = 1;
+ } else {
+ catacombs = easy_catacombs;
+ global[catacombs_309_from] = 3;
+ global[catacombs_409a] = 30;
+ global[catacombs_309] = 2;
+ global[catacombs_409b_from] = 2;
+ global[catacombs_409b] = 31;
+ global[catacombs_501] = 31;
+ global[catacombs_409a_from] = 0;
+ global[catacombs_501_from] = 0;
+ }
+}
+
+static void global_catacombs_new_room(int catacomb_node, int from) {
+ int newRoom = 0;
+
+ global[catacombs_next_room] = catacomb_node;
+ global[catacombs_from] = from & DIRECTION_MASK;
+ global[catacombs_flag] = from & FLAGS_MASK;
+
+ if (catacomb_node >= 0) {
+ newRoom = catacombs[catacomb_node].room_id;
+ global[catacombs_misc] = catacombs[catacomb_node].misc;
+ } else {
+ switch (catacomb_node) {
+ case CATACOMBS_TO_409a:
+ case CATACOMBS_TO_409b:
+ newRoom = 409;
+ break;
+
+ case CATACOMBS_TO_501:
+ newRoom = 501;
+ break;
+
+ case CATACOMBS_TO_309:
+ newRoom = 309;
+ break;
+
+ default:
+ error_report(ERROR_KERNEL_NO_ROOM, ERROR, MODULE_UNKNOWN, new_room, 0);
+ break;
+ }
+ }
+
+ if (kernel.trigger_setup_mode == KERNEL_TRIGGER_PREPARSE) {
+ player.walk_off_edge_to_room = newRoom;
+ } else {
+ new_room = newRoom;
+ kernel.force_restart = true;
+ }
+}
+
+void global_catacombs_init() {
+ global_catacombs_setup();
+ global[catacombs_next_room] = global[catacombs_room];
+}
+
+void global_enter_catacombs(int special) {
+ global_catacombs_setup();
+
+ switch (room_id) {
+ case 409:
+ if (special)
+ global_catacombs_new_room(global[catacombs_409b], global[catacombs_409b_from]);
+ else
+ global_catacombs_new_room(global[catacombs_409a], global[catacombs_409a_from]);
+ break;
+
+ case 501:
+ global_catacombs_new_room(global[catacombs_501], global[catacombs_501_from]);
+ break;
+
+ default:
+ global_catacombs_new_room(global[catacombs_309], global[catacombs_309_from]);
+ break;
+ }
+}
+
+int global_catacombs_exit(int exit) {
+ return catacombs[global[catacombs_room]].exit[exit];
+}
+
+void global_catacombs_move(int exit) {
+ int from = catacombs[global[catacombs_room]].from[exit];
+ int node = catacombs[global[catacombs_room]].exit[exit];
+ global_catacombs_new_room(node, from);
+}
+
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/catacombs.h b/engines/mads/madsv2/phantom/catacombs.h
new file mode 100644
index 00000000000..7a37ab470c9
--- /dev/null
+++ b/engines/mads/madsv2/phantom/catacombs.h
@@ -0,0 +1,58 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef MADS_PHANTOM_CATACOMBS_H
+#define MADS_PHANTOM_CATACOMBS_H
+
+#include "mads/madsv2/core/vocabh.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+
+constexpr int NORTH = 0;
+constexpr int EAST = 1;
+constexpr int SOUTH = 2;
+constexpr int WEST = 3;
+
+constexpr int MAZE_PUDDLE = 0x0001; /* 401,404 */
+constexpr int MAZE_RAT_NEST = 0x0002; /* 401,403,453,404 */
+constexpr int MAZE_SKULL = 0x0004; /* 401,403 */
+constexpr int MAZE_POT = 0x0008; /* 401,404 */
+constexpr int MAZE_BRICK = 0x0010; /* 401,403,453,408 */
+constexpr int MAZE_HOLE = 0x0020; /* 403 */
+constexpr int MAZE_WEB = 0x0040; /* 403,453,404,408 */
+constexpr int MAZE_PLANK = 0x0080; /* 403 */
+constexpr int MAZE_DRAIN = 0x0100; /* 453 */
+constexpr int MAZE_STONE = 0x0200; /* 453 */
+constexpr int MAZE_BLOCK = 0x0400; /* 404 */
+constexpr int MAZE_FALLEN_BLOCK = 0x0800; /* 404 */
+
+extern void global_catacombs_init();
+extern void global_enter_catacombs(int special);
+extern int global_catacombs_exit(int exit);
+extern void global_catacombs_move(int exit);
+
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/phantom/global.cpp b/engines/mads/madsv2/phantom/global.cpp
index 968b90d84c1..72bb62d9771 100644
--- a/engines/mads/madsv2/phantom/global.cpp
+++ b/engines/mads/madsv2/phantom/global.cpp
@@ -28,228 +28,50 @@ namespace MADS {
namespace MADSV2 {
namespace Phantom {
-/* Fun stuff for the catacombs */
-
-#define NORTH 0
-#define EAST 1
-#define SOUTH 2
-#define WEST 3
-
-#define DIRECTION_MASK 0x0003
-#define FLAGS_MASK 0x00fc
-
-#define CATACOMBS_TO_309 -2
-#define CATACOMBS_TO_409a -3
-#define CATACOMBS_TO_409b -4
-#define CATACOMBS_TO_501 -5
-
-
-struct Catacombs {
- int16 room_id; /* Room ID of catacomb part. */
- int8 exit[4]; /* Catacomb room # if exit in direction */
- int8 from[4]; /* When exit, will enter from this direction */
- int16 misc; /* Miscellaneous bit data */
-};
-
-Catacombs *catacombs = NULL;
-
-Catacombs easy_catacombs[32] = {
- { 401, { -1, 1, 2, 6 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BRICK },
- { 404, { 10, 11, 3, 0 }, { SOUTH, WEST, NORTH, EAST }, MAZE_PUDDLE },
- { 404, { 0, 3, 4, CATACOMBS_TO_309 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BLOCK },
- { 401, { 1, 14, 5, 2 }, { SOUTH, WEST, NORTH, EAST }, MAZE_POT },
- { 453, { 2, 4, -1, 4 }, { SOUTH, WEST, NORTH, EAST }, MAZE_DRAIN },
- { 403, { 3, 6, -1, -1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BRICK | MAZE_PLANK },
- { 406, { -1, 0, -1, 5 }, { SOUTH, WEST, NORTH, EAST }, 0 },
- { 453, { -1, 8, -1, -1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BRICK },
- /* 8 */
- { 406, { -1, 9, -1, 7 }, { SOUTH, WEST, NORTH, EAST }, 0 },
- { 401, { 1, -1, 10, 8 }, { SOUTH, WEST, NORTH, EAST }, MAZE_RAT_NEST | MAZE_SKULL },
- { 408, { 9, -1, 1, -1 }, { SOUTH, WEST, NORTH, EAST }, 0 },
- { 453, { 12, -1, -1, 1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BRICK | MAZE_STONE },
- /* 12 */
- { 408, { 13, -1, 11, -1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BRICK },
- { 401, { 13, 20, 12, 13 }, { WEST, WEST, NORTH, NORTH }, MAZE_BRICK },
- { 453, { 16, 15, -1, 3 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BRICK | MAZE_RAT_NEST },
- { 456, { -1, -1, -1, 14 }, { SOUTH, WEST, NORTH, EAST }, 0 },
- /* 16 */
- { 404, { -1, 17, 14, -1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_WEB | MAZE_POT },
- { 401, { 18, -1, 19, 16 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BRICK },
- { 408, { -1, -1, 17, -1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BRICK },
- { 403, { 17, -1, -1, -1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_HOLE | MAZE_WEB },
- /* 20 */
- { 403, { 21, 22, -1, 13 }, { SOUTH, WEST, NORTH, EAST }, MAZE_WEB | MAZE_SKULL },
- { 404, { -1, -1, 20, -1 }, { SOUTH, WEST, NORTH, EAST }, 0 },
- { 406, { -1, 23, -1, 20 }, { SOUTH, WEST, NORTH, EAST }, 0 },
- { 404, { 24, 23, 23, 22 }, { SOUTH, SOUTH, EAST, EAST }, MAZE_RAT_NEST | MAZE_BRICK },
- /* 24 */
- { 401, { -1, 1, 23, 25 }, { SOUTH, EAST, NORTH, EAST }, MAZE_PUDDLE | MAZE_POT | MAZE_BRICK },
- { 407, { 29, 24, 28, 26 }, { WEST, WEST, EAST, EAST }, 0 },
- { 401, { 27, 25, 23, -1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_SKULL },
- { 404, { -1, 28, 26, -1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_WEB | MAZE_FALLEN_BLOCK },
- /* 28 */
- { 456, { -1, 25, -1, 27 }, { SOUTH, SOUTH, NORTH, EAST }, 0 },
- { 406, { -1, 30, -1, 25 }, { SOUTH, WEST, NORTH, NORTH }, 0 },
- { 453, { CATACOMBS_TO_409a, 30, -1, 29 }, { SOUTH, WEST, NORTH, EAST },
- MAZE_STONE | MAZE_RAT_NEST | MAZE_WEB },
- { 408, { CATACOMBS_TO_501, -1, CATACOMBS_TO_409b, -1 }, { SOUTH, WEST, NORTH, EAST },
- MAZE_WEB | MAZE_BRICK }
-};
-
-Catacombs hard_catacombs[62] = {
- { 401, { -1, 1, 2, 6 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BRICK },
- { 404, { 10, 11, 3, 0 }, { SOUTH, WEST, NORTH, EAST }, MAZE_PUDDLE },
- { 404, { 0, 3, 4, CATACOMBS_TO_309 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BLOCK },
- { 401, { 1, 20, 5, 2 }, { SOUTH, NORTH, NORTH, EAST }, MAZE_POT },
- { 453, { 2, 4, -1, 4 }, { SOUTH, WEST, NORTH, EAST }, MAZE_DRAIN },
- { 403, { 3, 6, -1, 4 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BRICK | MAZE_PLANK },
- { 406, { -1, 0, -1, 5 }, { SOUTH, WEST, NORTH, EAST }, 0 },
- { 453, { -1, 8, -1, -1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BRICK },
- /* 8 */
- { 406, { -1, 9, -1, 7 }, { SOUTH, WEST, NORTH, EAST }, 0 },
- { 401, { 1, -1, 10, 8 }, { NORTH, WEST, NORTH, EAST }, MAZE_RAT_NEST | MAZE_SKULL },
- { 408, { 9, -1, 1, -1 }, { SOUTH, WEST, NORTH, EAST }, 0 },
- { 453, { 12, -1, -1, 1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BRICK | MAZE_STONE },
- /* 12 */
- { 408, { 13, -1, 11, -1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BRICK },
- { 401, { 13, 21, 12, 13 }, { WEST, WEST, NORTH, NORTH }, MAZE_BRICK },
- { 453, { 16, 15, -1, 20 }, { SOUTH, WEST, NORTH, SOUTH }, MAZE_RAT_NEST | MAZE_BRICK },
- { 456, { -1, -1, -1, 14 }, { SOUTH, WEST, NORTH, EAST }, 0 },
- /* 16 */
- { 404, { -1, 17, 14, -1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_WEB | MAZE_POT },
- { 401, { 18, -1, 19, 16 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BRICK },
- { 408, { -1, -1, 17, -1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BRICK },
- { 403, { 17, -1, -1, -1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_HOLE | MAZE_WEB },
- /* 20 */
- { 408, { 3, -1, 14, -1 }, { EAST, WEST, WEST, EAST }, 0 },
- { 404, { 9, 30, 22, 13 }, { NORTH, WEST, NORTH, EAST }, MAZE_RAT_NEST },
- { 403, { 21, 23, -1, -1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_HOLE | MAZE_WEB },
- { 401, { -1, -1, 24, 22 }, { SOUTH, WEST, WEST, EAST }, MAZE_BRICK },
- /* 24 */
- { 406, { -1, 26, -1, 23 }, { SOUTH, NORTH, NORTH, SOUTH }, 0 },
- { 407, { 36, 33, 35, 34 }, { WEST, WEST, EAST, EAST }, 0 },
- { 453, { 24, 27, -1, -1 }, { EAST, NORTH, NORTH, EAST }, MAZE_BRICK },
- { 403, { 26, -1, -1, 28 }, { EAST, WEST, NORTH, NORTH }, MAZE_BRICK | MAZE_SKULL },
- /* 28 */
- { 404, { 27, 28, 28, 29 }, { WEST, SOUTH, EAST, SOUTH }, 0 },
- { 408, { -1, -1, 28, -1 }, { SOUTH, WEST, WEST, EAST }, MAZE_BRICK },
- { 406, { -1, 31, -1, 21 }, { SOUTH, NORTH, NORTH, EAST }, 0 },
- { 401, { 30, 33, 1, -1 }, { EAST, SOUTH, EAST, EAST }, MAZE_PUDDLE | MAZE_POT },
- /* 32 */
- { 456, { -1, 31, -1, 33 }, { SOUTH, EAST, NORTH, NORTH }, 0 },
- { 404, { 32, -1, 31, 25 }, { WEST, WEST, EAST, EAST }, 0 },
- { 401, { 46, 25, 31, -1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_SKULL },
- { 401, { -1, 25, 41, -1 }, { SOUTH, SOUTH, EAST, EAST }, MAZE_BRICK | MAZE_POT },
- /* 36 */
- { 406, { -1, 37, -1, 25 }, { SOUTH, WEST, NORTH, NORTH }, 0 },
- { 453, { CATACOMBS_TO_409a, 37, -1, 36 }, { SOUTH, WEST, NORTH, EAST }, MAZE_STONE | MAZE_RAT_NEST | MAZE_WEB },
- { 408, { 57, -1, 54, -1 }, { SOUTH, WEST, NORTH, EAST }, 0 },
- { 408, { 40, -1, CATACOMBS_TO_409b, -1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BRICK | MAZE_WEB },
- /* 40 */
- { 404, { 40, 40, 39, 53 }, { EAST, NORTH, NORTH, EAST }, MAZE_BLOCK | MAZE_FALLEN_BLOCK },
- { 456, { -1, 35, -1, 42 }, { SOUTH, SOUTH, NORTH, SOUTH }, 0 },
- { 408, { 43, -1, 41, -1 }, { EAST, WEST, WEST, EAST }, MAZE_BRICK },
- { 406, { -1, 42, -1, 61 }, { SOUTH, NORTH, NORTH, EAST }, 0 },
- /* 44 */
- { 403, { 58, 45, -1, -1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BRICK | MAZE_RAT_NEST },
- { 401, { 34, -1, 46, 44 }, { NORTH, WEST, NORTH, EAST }, MAZE_RAT_NEST | MAZE_BRICK },
- { 404, { 45, -1, 34, 47 }, { SOUTH, WEST, NORTH, EAST }, MAZE_WEB | MAZE_FALLEN_BLOCK },
- { 406, { -1, 46, -1, 48 }, { SOUTH, WEST, NORTH, EAST }, 0 },
- /* 48 */
- { 403, { 49, 47, -1, -1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BRICK | MAZE_SKULL | MAZE_WEB },
- { 408, { 50, -1, 48, -1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BRICK },
- { 408, { 51, -1, 49, -1 }, { SOUTH, WEST, NORTH, EAST }, 0 },
- { 408, { 52, -1, 50, -1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BRICK },
- /* 52 */
- { 408, { -1, -1, 51, -1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BRICK },
- { 406, { -1, 40, -1, 54 }, { SOUTH, WEST, NORTH, EAST }, 0 },
- { 403, { 38, 53, -1, 55 }, { SOUTH, WEST, NORTH, EAST }, MAZE_SKULL },
- { 453, { 56, 54, -1, -1 }, { SOUTH, WEST, NORTH, EAST }, MAZE_BRICK | MAZE_WEB },
- /* 56 */
- { 401, { 56, CATACOMBS_TO_501, 55, 56 }, { WEST, WEST, NORTH, NORTH }, MAZE_BRICK | MAZE_SKULL },
- { 404, { -1, 57, 38, 57 }, { SOUTH, WEST, NORTH, EAST }, MAZE_POT | MAZE_BLOCK },
- { 404, { 59, 59, 44, 60 }, { SOUTH, WEST, NORTH, EAST }, 0 },
- { 404, { 59, 60, 59, 58 }, { SOUTH, WEST, NORTH, EAST }, 0 },
- /* 60 */
- { 404, { 61, 58, 59, 59 }, { SOUTH, WEST, NORTH, EAST }, 0 },
- { 404, { 34, 43, 60, 44 }, { NORTH, WEST, NORTH, EAST }, 0 }
-};
-
-static void global_catacombs_setup() {
- if (game.difficulty == HARD_MODE) {
- catacombs = hard_catacombs;
- global[catacombs_309_from] = 3;
- global[catacombs_409a] = 37;
- global[catacombs_409a_from] = 0;
- global[catacombs_409b] = 39;
- global[catacombs_309] = 2;
- global[catacombs_409b_from] = 2;
- global[catacombs_501] = 56;
- global[catacombs_501_from] = 1;
- } else {
- catacombs = easy_catacombs;
- global[catacombs_309_from] = 3;
- global[catacombs_409a] = 30;
- global[catacombs_309] = 2;
- global[catacombs_409b_from] = 2;
- global[catacombs_409b] = 31;
- global[catacombs_501] = 31;
- global[catacombs_409a_from] = 0;
- global[catacombs_501_from] = 0;
+extern void section_1_preload();
+extern void section_2_preload();
+extern void section_3_preload();
+extern void section_4_preload();
+extern void section_5_preload();
+extern void section_6_preload();
+extern void section_7_preload();
+extern void section_8_preload();
+
+
+void global_section_constructor() {
+ section_preload_code_pointer = NULL;
+ section_room_constructor = NULL;
+ section_init_code_pointer = NULL;
+ section_parser_code_pointer = NULL;
+ section_daemon_code_pointer = NULL;
+
+ room_preload_code_pointer = NULL;
+ room_init_code_pointer = NULL;
+ room_daemon_code_pointer = NULL;
+ room_pre_parser_code_pointer = NULL;
+ room_parser_code_pointer = NULL;
+ room_error_code_pointer = NULL;
+ room_shutdown_code_pointer = NULL;
+
+ switch (new_section) {
+ case 1:
+ section_preload_code_pointer = section_1_preload;
+ break;
+ case 2:
+ section_preload_code_pointer = section_2_preload;
+ break;
+ case 3:
+ section_preload_code_pointer = section_3_preload;
+ break;
+ case 4:
+ section_preload_code_pointer = section_4_preload;
+ break;
+ case 5:
+ section_preload_code_pointer = section_5_preload;
+ break;
}
}
-static void global_catacombs_new_room(int catacomb_node, int from) {
- int newRoom;
-
- global[catacombs_next_room] = catacomb_node;
- global[catacombs_from] = from & DIRECTION_MASK;
- global[catacombs_flag] = from & FLAGS_MASK;
-
- if (catacomb_node >= 0) {
- newRoom = catacombs[catacomb_node].room_id;
- global[catacombs_misc] = catacombs[catacomb_node].misc;
- } else {
- switch (catacomb_node) {
- case CATACOMBS_TO_409a:
- case CATACOMBS_TO_409b:
- newRoom = 409;
- break;
-
- case CATACOMBS_TO_501:
- newRoom = 501;
- break;
-
- case CATACOMBS_TO_309:
- newRoom = 309;
- break;
-
- default:
- error_report(ERROR_KERNEL_NO_ROOM, ERROR, MODULE_UNKNOWN, new_room, 0);
- break;
- }
- }
-
- if (kernel.trigger_setup_mode == KERNEL_TRIGGER_PREPARSE) {
- player.walk_off_edge_to_room = newRoom;
- } else {
- new_room = newRoom;
- kernel.force_restart = true;
- }
-}
-
-void global_catacombs_init() {
- global_catacombs_setup();
- global[catacombs_next_room] = global[catacombs_room];
-}
-
-void global_enter_catacombs(int special) {
-}
-
-int global_catacombs_exit(int exit) {
- return catacombs[global[catacombs_room]].exit[exit];
-}
-
} // namespace Phantom
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/global.h b/engines/mads/madsv2/phantom/global.h
index eefa3cb4d91..6463cce9f17 100644
--- a/engines/mads/madsv2/phantom/global.h
+++ b/engines/mads/madsv2/phantom/global.h
@@ -265,30 +265,6 @@ enum {
#define COFFIN_UNLOCKED 1
#define COFFIN_OPEN 2
-// Catacomb defines
-constexpr int NORTH = 0;
-constexpr int EAST = 1;
-constexpr int SOUTH = 2;
-constexpr int WEST = 3;
-
-constexpr int MAZE_PUDDLE = 0x0001; /* 401,404 */
-constexpr int MAZE_RAT_NEST = 0x0002; /* 401,403,453,404 */
-constexpr int MAZE_SKULL = 0x0004; /* 401,403 */
-constexpr int MAZE_POT = 0x0008; /* 401,404 */
-constexpr int MAZE_BRICK = 0x0010; /* 401,403,453,408 */
-constexpr int MAZE_HOLE = 0x0020; /* 403 */
-constexpr int MAZE_WEB = 0x0040; /* 403,453,404,408 */
-constexpr int MAZE_PLANK = 0x0080; /* 403 */
-constexpr int MAZE_DRAIN = 0x0100; /* 453 */
-constexpr int MAZE_STONE = 0x0200; /* 453 */
-constexpr int MAZE_BLOCK = 0x0400; /* 404 */
-constexpr int MAZE_FALLEN_BLOCK = 0x0800; /* 404 */
-
-extern void global_catacombs_init();
-extern void global_enter_catacombs(int special);
-extern int global_catacombs_exit(int exit);
-extern void global_catacombs_move(int exit);
-
} // namespace Phantom
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/rooms/room309.cpp b/engines/mads/madsv2/phantom/rooms/room309.cpp
index 0572b592e19..34db03f56e8 100644
--- a/engines/mads/madsv2/phantom/rooms/room309.cpp
+++ b/engines/mads/madsv2/phantom/rooms/room309.cpp
@@ -33,6 +33,7 @@
#include "mads/madsv2/phantom/rooms/section3.h"
#include "mads/madsv2/phantom/rooms/room309.h"
#include "mads/madsv2/phantom/conv.h"
+#include "mads/madsv2/phantom/catacombs.h"
namespace MADS {
namespace MADSV2 {
diff --git a/engines/mads/madsv2/phantom/rooms/room401.cpp b/engines/mads/madsv2/phantom/rooms/room401.cpp
index 70d26f77a5c..f9beef2f81d 100644
--- a/engines/mads/madsv2/phantom/rooms/room401.cpp
+++ b/engines/mads/madsv2/phantom/rooms/room401.cpp
@@ -32,6 +32,7 @@
#include "mads/madsv2/phantom/mads/sounds.h"
#include "mads/madsv2/phantom/rooms/section4.h"
#include "mads/madsv2/phantom/rooms/room401.h"
+#include "mads/madsv2/phantom/catacombs.h"
namespace MADS {
namespace MADSV2 {
diff --git a/engines/mads/madsv2/phantom/rooms/room403.cpp b/engines/mads/madsv2/phantom/rooms/room403.cpp
index b04148bce15..ee6ed0af08f 100644
--- a/engines/mads/madsv2/phantom/rooms/room403.cpp
+++ b/engines/mads/madsv2/phantom/rooms/room403.cpp
@@ -32,6 +32,7 @@
#include "mads/madsv2/phantom/mads/sounds.h"
#include "mads/madsv2/phantom/rooms/section4.h"
#include "mads/madsv2/phantom/rooms/room403.h"
+#include "mads/madsv2/phantom/catacombs.h"
namespace MADS {
namespace MADSV2 {
diff --git a/engines/mads/madsv2/phantom/rooms/room404.cpp b/engines/mads/madsv2/phantom/rooms/room404.cpp
index a5d5b6ecb03..770f686dbcd 100644
--- a/engines/mads/madsv2/phantom/rooms/room404.cpp
+++ b/engines/mads/madsv2/phantom/rooms/room404.cpp
@@ -32,6 +32,7 @@
#include "mads/madsv2/phantom/mads/sounds.h"
#include "mads/madsv2/phantom/rooms/section4.h"
#include "mads/madsv2/phantom/rooms/room404.h"
+#include "mads/madsv2/phantom/catacombs.h"
namespace MADS {
namespace MADSV2 {
diff --git a/engines/mads/madsv2/phantom/rooms/room406.cpp b/engines/mads/madsv2/phantom/rooms/room406.cpp
index ddae636d3cc..508240c88d7 100644
--- a/engines/mads/madsv2/phantom/rooms/room406.cpp
+++ b/engines/mads/madsv2/phantom/rooms/room406.cpp
@@ -32,6 +32,7 @@
#include "mads/madsv2/phantom/mads/sounds.h"
#include "mads/madsv2/phantom/rooms/section4.h"
#include "mads/madsv2/phantom/rooms/room406.h"
+#include "mads/madsv2/phantom/catacombs.h"
namespace MADS {
namespace MADSV2 {
diff --git a/engines/mads/madsv2/phantom/rooms/room407.cpp b/engines/mads/madsv2/phantom/rooms/room407.cpp
index 34aba3c4cb1..972a59bf98c 100644
--- a/engines/mads/madsv2/phantom/rooms/room407.cpp
+++ b/engines/mads/madsv2/phantom/rooms/room407.cpp
@@ -32,6 +32,7 @@
#include "mads/madsv2/phantom/mads/sounds.h"
#include "mads/madsv2/phantom/rooms/section4.h"
#include "mads/madsv2/phantom/rooms/room407.h"
+#include "mads/madsv2/phantom/catacombs.h"
namespace MADS {
namespace MADSV2 {
diff --git a/engines/mads/madsv2/phantom/rooms/room408.cpp b/engines/mads/madsv2/phantom/rooms/room408.cpp
index 2480f2bff5a..95d618306e2 100644
--- a/engines/mads/madsv2/phantom/rooms/room408.cpp
+++ b/engines/mads/madsv2/phantom/rooms/room408.cpp
@@ -32,6 +32,7 @@
#include "mads/madsv2/phantom/mads/sounds.h"
#include "mads/madsv2/phantom/rooms/section4.h"
#include "mads/madsv2/phantom/rooms/room408.h"
+#include "mads/madsv2/phantom/catacombs.h"
namespace MADS {
namespace MADSV2 {
diff --git a/engines/mads/madsv2/phantom/rooms/room409.cpp b/engines/mads/madsv2/phantom/rooms/room409.cpp
index 4eaecf4e55c..4dbbbf345d1 100644
--- a/engines/mads/madsv2/phantom/rooms/room409.cpp
+++ b/engines/mads/madsv2/phantom/rooms/room409.cpp
@@ -34,6 +34,7 @@
#include "mads/madsv2/phantom/mads/speeches.h"
#include "mads/madsv2/phantom/rooms/section4.h"
#include "mads/madsv2/phantom/rooms/room409.h"
+#include "mads/madsv2/phantom/catacombs.h"
namespace MADS {
namespace MADSV2 {
diff --git a/engines/mads/madsv2/phantom/rooms/room453.cpp b/engines/mads/madsv2/phantom/rooms/room453.cpp
index 6cb5a6af4ca..7733f3cdf37 100644
--- a/engines/mads/madsv2/phantom/rooms/room453.cpp
+++ b/engines/mads/madsv2/phantom/rooms/room453.cpp
@@ -32,6 +32,7 @@
#include "mads/madsv2/phantom/mads/sounds.h"
#include "mads/madsv2/phantom/rooms/section4.h"
#include "mads/madsv2/phantom/rooms/room453.h"
+#include "mads/madsv2/phantom/catacombs.h"
namespace MADS {
namespace MADSV2 {
diff --git a/engines/mads/madsv2/phantom/rooms/room456.cpp b/engines/mads/madsv2/phantom/rooms/room456.cpp
index 092a978f6e8..94273ee52ac 100644
--- a/engines/mads/madsv2/phantom/rooms/room456.cpp
+++ b/engines/mads/madsv2/phantom/rooms/room456.cpp
@@ -32,6 +32,7 @@
#include "mads/madsv2/phantom/mads/sounds.h"
#include "mads/madsv2/phantom/rooms/section4.h"
#include "mads/madsv2/phantom/rooms/room456.h"
+#include "mads/madsv2/phantom/catacombs.h"
namespace MADS {
namespace MADSV2 {
diff --git a/engines/mads/madsv2/phantom/rooms/room501.cpp b/engines/mads/madsv2/phantom/rooms/room501.cpp
index 3d5ade65f4d..96c1e301be4 100644
--- a/engines/mads/madsv2/phantom/rooms/room501.cpp
+++ b/engines/mads/madsv2/phantom/rooms/room501.cpp
@@ -31,6 +31,7 @@
#include "mads/madsv2/phantom/conv.h"
#include "mads/madsv2/phantom/rooms/section5.h"
#include "mads/madsv2/phantom/rooms/room501.h"
+#include "mads/madsv2/phantom/catacombs.h"
namespace MADS {
namespace MADSV2 {
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index 3515b421197..4c61def9d00 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -176,6 +176,7 @@ MODULE_OBJS += \
madsv2/phantom/rooms/room505.o \
madsv2/phantom/rooms/room506.o \
madsv2/phantom/phantom.o \
+ madsv2/phantom/catacombs.o \
madsv2/phantom/conv.o \
madsv2/phantom/global.o \
madsv2/phantom/main_menu.o \
Commit: 0c78f02d0826963aec1fa49c2c4497b8a89d522a
https://github.com/scummvm/scummvm/commit/0c78f02d0826963aec1fa49c2c4497b8a89d522a
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:53+10:00
Commit Message:
MADS: PHANTOM: Hooking up global_section_constructor
Changed paths:
engines/mads/madsv2/core/global.cpp
engines/mads/madsv2/engine.h
engines/mads/madsv2/phantom/global.cpp
engines/mads/madsv2/phantom/global.h
engines/mads/madsv2/phantom/phantom.cpp
engines/mads/madsv2/phantom/phantom.h
diff --git a/engines/mads/madsv2/core/global.cpp b/engines/mads/madsv2/core/global.cpp
index 971c6c114f3..286d2898bc6 100644
--- a/engines/mads/madsv2/core/global.cpp
+++ b/engines/mads/madsv2/core/global.cpp
@@ -21,6 +21,7 @@
#include "common/textconsole.h"
#include "mads/madsv2/core/global.h"
+#include "mads/madsv2/engine.h"
namespace MADS {
namespace MADSV2 {
@@ -67,7 +68,7 @@ void global_sound_driver() {
}
void global_section_constructor() {
- error("TODO: void global_section_constructor(void);");
+ g_engine->global_section_constructor();
}
void global_game_menu() {
diff --git a/engines/mads/madsv2/engine.h b/engines/mads/madsv2/engine.h
index a37acb371cb..d724ee7fed7 100644
--- a/engines/mads/madsv2/engine.h
+++ b/engines/mads/madsv2/engine.h
@@ -76,6 +76,8 @@ public:
void main_global_init_code(void) {}
void section_music(int section_num) {}
void game_control_loop() {}
+
+ virtual void global_section_constructor() = 0;
};
extern MADSV2Engine *g_engine;
diff --git a/engines/mads/madsv2/phantom/global.cpp b/engines/mads/madsv2/phantom/global.cpp
index 72bb62d9771..c151551facd 100644
--- a/engines/mads/madsv2/phantom/global.cpp
+++ b/engines/mads/madsv2/phantom/global.cpp
@@ -28,6 +28,7 @@ namespace MADS {
namespace MADSV2 {
namespace Phantom {
+namespace Rooms {
extern void section_1_preload();
extern void section_2_preload();
extern void section_3_preload();
@@ -36,7 +37,7 @@ extern void section_5_preload();
extern void section_6_preload();
extern void section_7_preload();
extern void section_8_preload();
-
+} // namespace Rooms
void global_section_constructor() {
section_preload_code_pointer = NULL;
@@ -55,19 +56,19 @@ void global_section_constructor() {
switch (new_section) {
case 1:
- section_preload_code_pointer = section_1_preload;
+ section_preload_code_pointer = Rooms::section_1_preload;
break;
case 2:
- section_preload_code_pointer = section_2_preload;
+ section_preload_code_pointer = Rooms::section_2_preload;
break;
case 3:
- section_preload_code_pointer = section_3_preload;
+ section_preload_code_pointer = Rooms::section_3_preload;
break;
case 4:
- section_preload_code_pointer = section_4_preload;
+ section_preload_code_pointer = Rooms::section_4_preload;
break;
case 5:
- section_preload_code_pointer = section_5_preload;
+ section_preload_code_pointer = Rooms::section_5_preload;
break;
}
}
diff --git a/engines/mads/madsv2/phantom/global.h b/engines/mads/madsv2/phantom/global.h
index 6463cce9f17..09654a0911d 100644
--- a/engines/mads/madsv2/phantom/global.h
+++ b/engines/mads/madsv2/phantom/global.h
@@ -265,6 +265,9 @@ enum {
#define COFFIN_UNLOCKED 1
#define COFFIN_OPEN 2
+
+extern void global_section_constructor();
+
} // namespace Phantom
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/phantom.cpp b/engines/mads/madsv2/phantom/phantom.cpp
index 6eee4c8cd70..8ac8a345433 100644
--- a/engines/mads/madsv2/phantom/phantom.cpp
+++ b/engines/mads/madsv2/phantom/phantom.cpp
@@ -23,6 +23,7 @@
#include "mads/madsv2/phantom/phantom.h"
#include "mads/madsv2/phantom/main.h"
#include "mads/madsv2/phantom/sound_phantom.h"
+#include "mads/madsv2/phantom/global.h"
namespace MADS {
namespace MADSV2 {
@@ -39,6 +40,10 @@ Common::Error PhantomEngine::run() {
return Common::kNoError;
}
+void PhantomEngine::global_section_constructor() {
+ Phantom::global_section_constructor();
+}
+
} // namespace Phantom
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/phantom.h b/engines/mads/madsv2/phantom/phantom.h
index cc28853c4e1..3e1ceba62ab 100644
--- a/engines/mads/madsv2/phantom/phantom.h
+++ b/engines/mads/madsv2/phantom/phantom.h
@@ -38,6 +38,8 @@ public:
~PhantomEngine() override {}
Common::Error run() override;
+
+ void global_section_constructor() override;
};
} // namespace Phantom
Commit: 2c34c280c5f7eb6964457091626a68c199df36c1
https://github.com/scummvm/scummvm/commit/2c34c280c5f7eb6964457091626a68c199df36c1
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:53+10:00
Commit Message:
MADS: PHANTOM: Implementing main_cold_data_init
Changed paths:
engines/mads/madsv2/engine.h
engines/mads/madsv2/phantom/phantom.cpp
engines/mads/madsv2/phantom/phantom.h
diff --git a/engines/mads/madsv2/engine.h b/engines/mads/madsv2/engine.h
index d724ee7fed7..99f06b79c8e 100644
--- a/engines/mads/madsv2/engine.h
+++ b/engines/mads/madsv2/engine.h
@@ -68,12 +68,13 @@ public:
int main_normal_key(int mykey) {
return 0;
}
- int main_copy_verify(void) {
+ int main_copy_verify() {
return 0;
}
- void main_cold_data_init(void) {}
- void main_false_start(void) {}
- void main_global_init_code(void) {}
+
+ virtual void main_cold_data_init() = 0;
+ void main_false_start() {}
+ void main_global_init_code() {}
void section_music(int section_num) {}
void game_control_loop() {}
diff --git a/engines/mads/madsv2/phantom/phantom.cpp b/engines/mads/madsv2/phantom/phantom.cpp
index 8ac8a345433..6fc814d5215 100644
--- a/engines/mads/madsv2/phantom/phantom.cpp
+++ b/engines/mads/madsv2/phantom/phantom.cpp
@@ -20,6 +20,8 @@
*/
#include "engines/util.h"
+#include "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/kernel.h"
#include "mads/madsv2/phantom/phantom.h"
#include "mads/madsv2/phantom/main.h"
#include "mads/madsv2/phantom/sound_phantom.h"
@@ -40,6 +42,33 @@ Common::Error PhantomEngine::run() {
return Common::kNoError;
}
+
+void PhantomEngine::main_cold_data_init() {
+#if 0
+ debugger_reset = game_debugger_reset;
+ debugger_update = game_debugger;
+
+ game_menu_routine = global_game_menu;
+ game_menu_init = global_menu_system_init;
+ game_menu_exit = global_menu_system_shutdown;
+ game_emergency_save = global_emergency_save;
+#endif
+ Common::strcpy_s(config_file_name, "config.pha");
+ Common::strcpy_s(save_game_key, "phan");
+ Common::strcpy_s(restart_game_key, "phantom");
+
+ Common::strcpy_s(player.series_name, "RAL");
+ player.walker_must_reload = true;
+ player.walker_loads_first = false;
+ player.walker_visible = true;
+ player.scaling_velocity = true;
+
+ Common::strcpy_s(kernel_cheating_password, "WIDECHEW");
+ kernel_cheating_allowed = strlen(kernel_cheating_password);
+
+ kernel.cheating = (byte)kernel_cheating_allowed;
+}
+
void PhantomEngine::global_section_constructor() {
Phantom::global_section_constructor();
}
diff --git a/engines/mads/madsv2/phantom/phantom.h b/engines/mads/madsv2/phantom/phantom.h
index 3e1ceba62ab..a83ea2d5b32 100644
--- a/engines/mads/madsv2/phantom/phantom.h
+++ b/engines/mads/madsv2/phantom/phantom.h
@@ -39,6 +39,7 @@ public:
Common::Error run() override;
+ void main_cold_data_init() override;
void global_section_constructor() override;
};
Commit: 7c5f5cc0bb27128ef0cc4192514e07091c3ec313
https://github.com/scummvm/scummvm/commit/7c5f5cc0bb27128ef0cc4192514e07091c3ec313
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:54+10:00
Commit Message:
MADS: PHANTOM: Janitorial
Changed paths:
engines/mads/core/action.cpp
engines/mads/core/action.h
engines/mads/core/animation.cpp
engines/mads/core/animation.h
engines/mads/core/assets.cpp
engines/mads/core/assets.h
engines/mads/core/audio.cpp
engines/mads/core/audio.h
engines/mads/core/camera.cpp
engines/mads/core/camera.h
engines/mads/core/compression.cpp
engines/mads/core/compression.h
engines/mads/core/conversations.cpp
engines/mads/core/conversations.h
engines/mads/core/dialogs.cpp
engines/mads/core/dialogs.h
engines/mads/core/events.cpp
engines/mads/core/events.h
engines/mads/core/font.cpp
engines/mads/core/font.h
engines/mads/core/game.cpp
engines/mads/core/game.h
engines/mads/core/game_data.cpp
engines/mads/core/game_data.h
engines/mads/core/globals.cpp
engines/mads/core/globals.h
engines/mads/core/hag.cpp
engines/mads/core/hotspots.cpp
engines/mads/core/hotspots.h
engines/mads/core/inventory.cpp
engines/mads/core/inventory.h
engines/mads/core/menu_views.cpp
engines/mads/core/menu_views.h
engines/mads/core/messages.cpp
engines/mads/core/messages.h
engines/mads/core/msurface.cpp
engines/mads/core/msurface.h
engines/mads/core/palette.cpp
engines/mads/core/palette.h
engines/mads/core/player.cpp
engines/mads/core/player.h
engines/mads/core/rails.cpp
engines/mads/core/rails.h
engines/mads/core/resources.cpp
engines/mads/core/resources.h
engines/mads/core/scene.cpp
engines/mads/core/scene.h
engines/mads/core/scene_data.cpp
engines/mads/core/scene_data.h
engines/mads/core/screen.cpp
engines/mads/core/screen.h
engines/mads/core/sequence.h
engines/mads/core/sound.cpp
engines/mads/core/sprites.cpp
engines/mads/core/sprites.h
engines/mads/core/staticres.cpp
engines/mads/core/staticres.h
engines/mads/core/user_interface.cpp
engines/mads/core/user_interface.h
engines/mads/detection.h
engines/mads/detection_tables.h
engines/mads/dragonsphere/dragonsphere_scenes.cpp
engines/mads/dragonsphere/dragonsphere_scenes.h
engines/mads/dragonsphere/dragonsphere_scenes1.cpp
engines/mads/dragonsphere/dragonsphere_scenes1.h
engines/mads/dragonsphere/game_dragonsphere.cpp
engines/mads/dragonsphere/game_dragonsphere.h
engines/mads/dragonsphere/globals_dragonsphere.cpp
engines/mads/dragonsphere/globals_dragonsphere.h
engines/mads/forest/forest_scenes.cpp
engines/mads/forest/forest_scenes.h
engines/mads/forest/game_forest.cpp
engines/mads/forest/game_forest.h
engines/mads/forest/globals_forest.cpp
engines/mads/forest/globals_forest.h
engines/mads/madsv2/phantom/rooms/room206.h
engines/mads/madsv2/phantom/rooms/room207.h
engines/mads/madsv2/phantom/rooms/room208.h
engines/mads/metaengine.cpp
engines/mads/nebular/debugger.cpp
engines/mads/nebular/debugger.h
engines/mads/nebular/dialogs_nebular.cpp
engines/mads/nebular/dialogs_nebular.h
engines/mads/nebular/game_nebular.cpp
engines/mads/nebular/game_nebular.h
engines/mads/nebular/globals_nebular.cpp
engines/mads/nebular/globals_nebular.h
engines/mads/nebular/menu_nebular.cpp
engines/mads/nebular/menu_nebular.h
engines/mads/nebular/nebular.cpp
engines/mads/nebular/nebular_scenes.cpp
engines/mads/nebular/nebular_scenes.h
engines/mads/nebular/nebular_scenes1.cpp
engines/mads/nebular/nebular_scenes1.h
engines/mads/nebular/nebular_scenes2.cpp
engines/mads/nebular/nebular_scenes2.h
engines/mads/nebular/nebular_scenes3.cpp
engines/mads/nebular/nebular_scenes3.h
engines/mads/nebular/nebular_scenes4.cpp
engines/mads/nebular/nebular_scenes4.h
engines/mads/nebular/nebular_scenes5.cpp
engines/mads/nebular/nebular_scenes5.h
engines/mads/nebular/nebular_scenes6.cpp
engines/mads/nebular/nebular_scenes6.h
engines/mads/nebular/nebular_scenes7.cpp
engines/mads/nebular/nebular_scenes7.h
engines/mads/nebular/nebular_scenes8.cpp
engines/mads/nebular/nebular_scenes8.h
engines/mads/nebular/sound_nebular.cpp
engines/mads/nebular/sound_nebular.h
diff --git a/engines/mads/core/action.cpp b/engines/mads/core/action.cpp
index 0dda3d20ab3..2fefb25c5e2 100644
--- a/engines/mads/core/action.cpp
+++ b/engines/mads/core/action.cpp
@@ -702,4 +702,4 @@ void MADSAction::synchronize(Common::Serializer &s) {
s.syncAsByte(_inProgress);
}
-} // End of namespace MADS
+} // namespace MADS
diff --git a/engines/mads/core/action.h b/engines/mads/core/action.h
index 1eeaf402c59..2aea5595160 100644
--- a/engines/mads/core/action.h
+++ b/engines/mads/core/action.h
@@ -170,6 +170,6 @@ public:
void synchronize(Common::Serializer &s);
};
-} // End of namespace MADS
+} // namespace MADS
#endif /* MADS_ACTION_H */
diff --git a/engines/mads/core/animation.cpp b/engines/mads/core/animation.cpp
index 26d2ae05599..316c427b29f 100644
--- a/engines/mads/core/animation.cpp
+++ b/engines/mads/core/animation.cpp
@@ -628,4 +628,4 @@ Common::Point Animation::getFramePosAdjust(int idx) {
return Common::Point(0, 0);
}
-} // End of namespace MADS
+} // namespace MADS
diff --git a/engines/mads/core/animation.h b/engines/mads/core/animation.h
index e41190426f1..4cfc883ce9f 100644
--- a/engines/mads/core/animation.h
+++ b/engines/mads/core/animation.h
@@ -240,6 +240,6 @@ public:
Common::Point getFramePosAdjust(int idx);
};
-} // End of namespace MADS
+} // namespace MADS
#endif /* MADS_ANIMATION_H */
diff --git a/engines/mads/core/assets.cpp b/engines/mads/core/assets.cpp
index 8a1da96bad0..4553e876657 100644
--- a/engines/mads/core/assets.cpp
+++ b/engines/mads/core/assets.cpp
@@ -224,4 +224,4 @@ SpriteSetCharInfo::SpriteSetCharInfo(Common::SeekableReadStream *s) {
_centerOfGravity = s->readByte();
}
-} // End of namespace MADS
+} // namespace MADS
diff --git a/engines/mads/core/assets.h b/engines/mads/core/assets.h
index 07f125e4abc..59d2c13a6b5 100644
--- a/engines/mads/core/assets.h
+++ b/engines/mads/core/assets.h
@@ -111,6 +111,6 @@ public:
bool isBackground() const { return _isBackground; }
};
-} // End of namespace MADS
+} // namespace MADS
#endif /* MADS_ASSETS_H */
diff --git a/engines/mads/core/audio.cpp b/engines/mads/core/audio.cpp
index a75939a6174..0266d4e3e69 100644
--- a/engines/mads/core/audio.cpp
+++ b/engines/mads/core/audio.cpp
@@ -136,4 +136,4 @@ void AudioPlayer::stop() {
_mixer->stopHandle(_handle);
}
-} // End of namespace M4
+} // namespace M4
diff --git a/engines/mads/core/audio.h b/engines/mads/core/audio.h
index 6978cb0e6a2..cef2a8ad081 100644
--- a/engines/mads/core/audio.h
+++ b/engines/mads/core/audio.h
@@ -59,6 +59,6 @@ public:
Common::Array<DSREntry> _dsrEntries;
};
-} // End of namespace MADS
+} // namespace MADS
#endif
diff --git a/engines/mads/core/camera.cpp b/engines/mads/core/camera.cpp
index f95087bb925..48d20face99 100644
--- a/engines/mads/core/camera.cpp
+++ b/engines/mads/core/camera.cpp
@@ -188,4 +188,4 @@ bool Camera::camPan(int16 *picture_view, int16 *player_loc, int display_size, in
return (panningFl);
}
-} // End of namespace MADS
+} // namespace MADS
diff --git a/engines/mads/core/camera.h b/engines/mads/core/camera.h
index 770fe448ea8..56939245fbc 100644
--- a/engines/mads/core/camera.h
+++ b/engines/mads/core/camera.h
@@ -57,6 +57,6 @@ public:
void setDefaultPanY();
};
-} // End of namespace MADS
+} // namespace MADS
#endif /* MADS_CAMERA_H */
diff --git a/engines/mads/core/compression.cpp b/engines/mads/core/compression.cpp
index c30b7c3a61d..775d74bc425 100644
--- a/engines/mads/core/compression.cpp
+++ b/engines/mads/core/compression.cpp
@@ -191,4 +191,4 @@ int FabDecompressor::getBit() {
return bit;
}
-} // End of namespace MADS
+} // namespace MADS
diff --git a/engines/mads/core/compression.h b/engines/mads/core/compression.h
index ca30debe3e8..1cc8891dece 100644
--- a/engines/mads/core/compression.h
+++ b/engines/mads/core/compression.h
@@ -82,6 +82,6 @@ public:
void decompress(const byte *srcData, int srcSize, byte *destData, int destSize);
};
-} // End of namespace MADS
+} // namespace MADS
#endif
diff --git a/engines/mads/core/conversations.cpp b/engines/mads/core/conversations.cpp
index b900e0b3bf9..abc509b5550 100644
--- a/engines/mads/core/conversations.cpp
+++ b/engines/mads/core/conversations.cpp
@@ -1019,4 +1019,4 @@ int ScriptEntry::Conditional::get(int paramNum) const {
/*------------------------------------------------------------------------*/
-} // End of namespace MADS
+} // namespace MADS
diff --git a/engines/mads/core/conversations.h b/engines/mads/core/conversations.h
index e1811213adc..ec48f4660c6 100644
--- a/engines/mads/core/conversations.h
+++ b/engines/mads/core/conversations.h
@@ -500,6 +500,6 @@ public:
ConversationMode currentMode() const { return _currentMode; }
};
-} // End of namespace MADS
+} // namespace MADS
#endif /* MADS_CONVERSATIONS_H */
diff --git a/engines/mads/core/dialogs.cpp b/engines/mads/core/dialogs.cpp
index 191e99de003..9ad550e7bfd 100644
--- a/engines/mads/core/dialogs.cpp
+++ b/engines/mads/core/dialogs.cpp
@@ -547,4 +547,4 @@ void FullScreenDialog::display() {
scene._spriteSlots.fullRefresh();
}
-} // End of namespace MADS
+} // namespace MADS
diff --git a/engines/mads/core/dialogs.h b/engines/mads/core/dialogs.h
index 581007009a6..f8f5662d87b 100644
--- a/engines/mads/core/dialogs.h
+++ b/engines/mads/core/dialogs.h
@@ -290,6 +290,6 @@ public:
~FullScreenDialog() override;
};
-} // End of namespace MADS
+} // namespace MADS
#endif /* MADS_DIALOGS_H */
diff --git a/engines/mads/core/events.cpp b/engines/mads/core/events.cpp
index a456acaa548..a26ea2e948c 100644
--- a/engines/mads/core/events.cpp
+++ b/engines/mads/core/events.cpp
@@ -271,4 +271,4 @@ void EventsManager::clearEvents() {
}
-} // End of namespace MADS
+} // namespace MADS
diff --git a/engines/mads/core/events.h b/engines/mads/core/events.h
index 60d22b85ab5..75d1d4bb32b 100644
--- a/engines/mads/core/events.h
+++ b/engines/mads/core/events.h
@@ -190,6 +190,6 @@ public:
Common::CustomEventType getAction() { return _pendingActions.pop(); }
};
-} // End of namespace MADS
+} // namespace MADS
#endif /* MADS_EVENTS_H */
diff --git a/engines/mads/core/font.cpp b/engines/mads/core/font.cpp
index 5dc28e4b65c..d0f4703f242 100644
--- a/engines/mads/core/font.cpp
+++ b/engines/mads/core/font.cpp
@@ -243,4 +243,4 @@ int Font::getBpp(int charWidth) {
return 1;
}
-} // End of namespace MADS
+} // namespace MADS
diff --git a/engines/mads/core/font.h b/engines/mads/core/font.h
index cd405892200..37573cde2c4 100644
--- a/engines/mads/core/font.h
+++ b/engines/mads/core/font.h
@@ -89,6 +89,6 @@ public:
int spaceWidth = 0, int width = 0);
};
-} // End of namespace MADS
+} // namespace MADS
#endif /* MADS_FONT_H */
diff --git a/engines/mads/core/game.cpp b/engines/mads/core/game.cpp
index 6c3f91dafb0..bd9af32443c 100644
--- a/engines/mads/core/game.cpp
+++ b/engines/mads/core/game.cpp
@@ -697,4 +697,4 @@ void Game::camUpdate() {
}
}
-} // End of namespace MADS
+} // namespace MADS
diff --git a/engines/mads/core/game.h b/engines/mads/core/game.h
index a205be9f551..2afcdd51d30 100644
--- a/engines/mads/core/game.h
+++ b/engines/mads/core/game.h
@@ -255,6 +255,6 @@ public:
void camUpdate();
};
-} // End of namespace MADS
+} // namespace MADS
#endif /* MADS_GAME_H */
diff --git a/engines/mads/core/game_data.cpp b/engines/mads/core/game_data.cpp
index 9c6e736c9a5..4a4b708b34f 100644
--- a/engines/mads/core/game_data.cpp
+++ b/engines/mads/core/game_data.cpp
@@ -62,4 +62,4 @@ void VisitedScenes::synchronize(Common::Serializer &s, int sceneId) {
}
}
-} // End of namespace MADS
+} // namespace MADS
diff --git a/engines/mads/core/game_data.h b/engines/mads/core/game_data.h
index ed4e3cff523..bc63e0bc65b 100644
--- a/engines/mads/core/game_data.h
+++ b/engines/mads/core/game_data.h
@@ -67,6 +67,6 @@ public:
virtual void step() {}
};
-} // End of namespace MADS
+} // namespace MADS
#endif /* MADS_GAME_DATA_H */
diff --git a/engines/mads/core/globals.cpp b/engines/mads/core/globals.cpp
index a23826abb1a..2cf62984077 100644
--- a/engines/mads/core/globals.cpp
+++ b/engines/mads/core/globals.cpp
@@ -29,4 +29,4 @@ void Globals::reset() {
(*this)[i] = 0;
}
-} // End of namespace MADS
+} // namespace MADS
diff --git a/engines/mads/core/globals.h b/engines/mads/core/globals.h
index 9a06d4d5e84..d2c6cd44654 100644
--- a/engines/mads/core/globals.h
+++ b/engines/mads/core/globals.h
@@ -41,6 +41,6 @@ public:
void reset();
};
-} // End of namespace MADS
+} // namespace MADS
#endif /* MADS_GLOBALS_H */
diff --git a/engines/mads/core/hag.cpp b/engines/mads/core/hag.cpp
index 7b3b55da233..26c3dfa9f0e 100644
--- a/engines/mads/core/hag.cpp
+++ b/engines/mads/core/hag.cpp
@@ -244,4 +244,4 @@ ResourceType HagArchive::getResourceType(const Common::String &resourceName) con
return RESTYPE_NO_EXT;
}
-} // End of namespace MADS
+} // namespace MADS
diff --git a/engines/mads/core/hotspots.cpp b/engines/mads/core/hotspots.cpp
index d127e6ad345..7dfff09a5d7 100644
--- a/engines/mads/core/hotspots.cpp
+++ b/engines/mads/core/hotspots.cpp
@@ -263,4 +263,4 @@ void Hotspots::activateAtPos(int vocabId, bool active, Common::Point pos) {
}
}
-} // End of namespace MADS
+} // namespace MADS
diff --git a/engines/mads/core/hotspots.h b/engines/mads/core/hotspots.h
index d08aa651cf5..2370b28b1e5 100644
--- a/engines/mads/core/hotspots.h
+++ b/engines/mads/core/hotspots.h
@@ -135,6 +135,6 @@ public:
};
-} // End of namespace MADS
+} // namespace MADS
#endif /* MADS_HOTSPOTS_H */
diff --git a/engines/mads/core/inventory.cpp b/engines/mads/core/inventory.cpp
index 18216959034..f094d88c47e 100644
--- a/engines/mads/core/inventory.cpp
+++ b/engines/mads/core/inventory.cpp
@@ -221,4 +221,4 @@ int InventoryObjects::getIdFromDesc(int descId) {
return -1;
}
-} // End of namespace MADS
+} // namespace MADS
diff --git a/engines/mads/core/inventory.h b/engines/mads/core/inventory.h
index cf703dbc7d4..381f30f5364 100644
--- a/engines/mads/core/inventory.h
+++ b/engines/mads/core/inventory.h
@@ -136,6 +136,6 @@ public:
int getIdFromDesc(int objectId);
};
-} // End of namespace MADS
+} // namespace MADS
#endif /* MADS_INVENTORY_H */
diff --git a/engines/mads/core/menu_views.cpp b/engines/mads/core/menu_views.cpp
index 473e3522e2a..d01205b7478 100644
--- a/engines/mads/core/menu_views.cpp
+++ b/engines/mads/core/menu_views.cpp
@@ -834,4 +834,4 @@ int AnimationView::scanResourceIndex(const Common::String &resourceName) {
return -1;
}
-} // End of namespace MADS
+} // namespace MADS
diff --git a/engines/mads/core/menu_views.h b/engines/mads/core/menu_views.h
index 77378e31063..76557a51803 100644
--- a/engines/mads/core/menu_views.h
+++ b/engines/mads/core/menu_views.h
@@ -227,6 +227,6 @@ public:
~AnimationView() override;
};
-} // End of namespace MADS
+} // namespace MADS
#endif /* MADS_MENU_VIEWS_H */
diff --git a/engines/mads/core/messages.cpp b/engines/mads/core/messages.cpp
index 09f8bcb50e9..7f594c83914 100644
--- a/engines/mads/core/messages.cpp
+++ b/engines/mads/core/messages.cpp
@@ -581,4 +581,4 @@ void TextDisplayList::expire(int idx) {
(*this)[idx]._expire = -1;
}
-} // End of namespace MADS
+} // namespace MADS
diff --git a/engines/mads/core/messages.h b/engines/mads/core/messages.h
index 9129bb77382..d88c3a15ce0 100644
--- a/engines/mads/core/messages.h
+++ b/engines/mads/core/messages.h
@@ -187,6 +187,6 @@ public:
void cleanUp();
};
-} // End of namespace MADS
+} // namespace MADS
#endif /* MADS_MESSAGES_H */
diff --git a/engines/mads/core/msurface.cpp b/engines/mads/core/msurface.cpp
index 173025db288..8ebb76098e1 100644
--- a/engines/mads/core/msurface.cpp
+++ b/engines/mads/core/msurface.cpp
@@ -497,4 +497,4 @@ int DepthSurface::getDepthHighBit(const Common::Point &pt) {
}
}
-} // End of namespace MADS
+} // namespace MADS
diff --git a/engines/mads/core/msurface.h b/engines/mads/core/msurface.h
index b9e1802ed3e..3862aa88696 100644
--- a/engines/mads/core/msurface.h
+++ b/engines/mads/core/msurface.h
@@ -203,6 +203,6 @@ public:
int getDepthHighBit(const Common::Point &pt);
};
-} // End of namespace MADS
+} // namespace MADS
#endif /* MADS_MSURFACE_H */
diff --git a/engines/mads/core/palette.cpp b/engines/mads/core/palette.cpp
index 0b3a7370b9f..ce571b7d29b 100644
--- a/engines/mads/core/palette.cpp
+++ b/engines/mads/core/palette.cpp
@@ -917,4 +917,4 @@ int Palette::closestColor(const byte *matchColor, const byte *refPalette,
}
-} // End of namespace MADS
+} // namespace MADS
diff --git a/engines/mads/core/palette.h b/engines/mads/core/palette.h
index 8f4f03d6bfa..cecb0c23eea 100644
--- a/engines/mads/core/palette.h
+++ b/engines/mads/core/palette.h
@@ -319,6 +319,6 @@ public:
int paletteInc, int count);
};
-} // End of namespace MADS
+} // namespace MADS
#endif /* MADS_PALETTE_H */
diff --git a/engines/mads/core/player.cpp b/engines/mads/core/player.cpp
index 694a61f199d..a0c256403c1 100644
--- a/engines/mads/core/player.cpp
+++ b/engines/mads/core/player.cpp
@@ -867,4 +867,4 @@ void Player::resetFacing(Facing facing) {
selectSeries();
}
-} // End of namespace MADS
+} // namespace MADS
diff --git a/engines/mads/core/player.h b/engines/mads/core/player.h
index 8d7b14cb80c..658913826dc 100644
--- a/engines/mads/core/player.h
+++ b/engines/mads/core/player.h
@@ -256,6 +256,6 @@ public:
};
-} // End of namespace MADS
+} // namespace MADS
#endif /* MADS_PLAYER_H */
diff --git a/engines/mads/core/rails.cpp b/engines/mads/core/rails.cpp
index 83e0b6da9d7..f2fd09bcb40 100644
--- a/engines/mads/core/rails.cpp
+++ b/engines/mads/core/rails.cpp
@@ -287,4 +287,4 @@ void Rails::disableLine(int from, int to) {
_nodes[to]._distances[from] = 0x3FFF;
}
-} // End of namespace MADS
+} // namespace MADS
diff --git a/engines/mads/core/rails.h b/engines/mads/core/rails.h
index 0e017602d1a..516c729013f 100644
--- a/engines/mads/core/rails.h
+++ b/engines/mads/core/rails.h
@@ -132,6 +132,6 @@ public:
};
-} // End of namespace MADS
+} // namespace MADS
#endif /* MADS_RAILS_H */
diff --git a/engines/mads/core/resources.cpp b/engines/mads/core/resources.cpp
index 4552b69f4ce..ae7631b448b 100644
--- a/engines/mads/core/resources.cpp
+++ b/engines/mads/core/resources.cpp
@@ -149,4 +149,4 @@ void SynchronizedList::synchronize(Common::Serializer &s) {
}
}
-} // End of namespace MADS
+} // namespace MADS
diff --git a/engines/mads/core/resources.h b/engines/mads/core/resources.h
index ada1e25a4db..b6f9cf6ad61 100644
--- a/engines/mads/core/resources.h
+++ b/engines/mads/core/resources.h
@@ -83,6 +83,6 @@ public:
void synchronize(Common::Serializer &s);
};
-} // End of namespace MADS
+} // namespace MADS
#endif
diff --git a/engines/mads/core/scene.cpp b/engines/mads/core/scene.cpp
index 8d150337c4e..3e256eaf6a6 100644
--- a/engines/mads/core/scene.cpp
+++ b/engines/mads/core/scene.cpp
@@ -893,4 +893,4 @@ void Scene::animations_tick() {
}
}
-} // End of namespace MADS
+} // namespace MADS
diff --git a/engines/mads/core/scene.h b/engines/mads/core/scene.h
index a34ab66a4a6..fad7902ba0d 100644
--- a/engines/mads/core/scene.h
+++ b/engines/mads/core/scene.h
@@ -267,6 +267,6 @@ public:
int _speechReady;
};
-} // End of namespace MADS
+} // namespace MADS
#endif /* MADS_SCENE_H */
diff --git a/engines/mads/core/scene_data.cpp b/engines/mads/core/scene_data.cpp
index 9e511df22db..99123f739a4 100644
--- a/engines/mads/core/scene_data.cpp
+++ b/engines/mads/core/scene_data.cpp
@@ -525,4 +525,4 @@ SceneLogic::SceneLogic(RexNebularEngine *vm) : _vm(vm) {
_scene = &_vm->_game->_scene;
}
-} // End of namespace MADS
+} // namespace MADS
diff --git a/engines/mads/core/scene_data.h b/engines/mads/core/scene_data.h
index 6344d9e04be..ce8fc85debc 100644
--- a/engines/mads/core/scene_data.h
+++ b/engines/mads/core/scene_data.h
@@ -220,6 +220,6 @@ public:
virtual void loadCodes(BaseSurface &depthSurface, Common::SeekableReadStream *stream) = 0;
};
-} // End of namespace MADS
+} // namespace MADS
#endif /* MADS_SCENE_DATA_H */
diff --git a/engines/mads/core/screen.cpp b/engines/mads/core/screen.cpp
index da5875437ee..85efca2174d 100644
--- a/engines/mads/core/screen.cpp
+++ b/engines/mads/core/screen.cpp
@@ -813,4 +813,4 @@ void Screen::resetClipBounds() {
setClipBounds(Common::Rect(0, 0, MADS_SCREEN_WIDTH, MADS_SCREEN_HEIGHT));
}
-} // End of namespace MADS
+} // namespace MADS
diff --git a/engines/mads/core/screen.h b/engines/mads/core/screen.h
index cdf046c5e2c..0e395a6cf11 100644
--- a/engines/mads/core/screen.h
+++ b/engines/mads/core/screen.h
@@ -260,6 +260,6 @@ public:
}
};
-} // End of namespace MADS
+} // namespace MADS
#endif /* MADS_SCREEN_H */
diff --git a/engines/mads/core/sequence.h b/engines/mads/core/sequence.h
index 3e784e7894c..043db3aea93 100644
--- a/engines/mads/core/sequence.h
+++ b/engines/mads/core/sequence.h
@@ -129,6 +129,6 @@ public:
void setSeqPlayer(int idx, bool flag);
};
-} // End of namespace MADS
+} // namespace MADS
#endif /* MADS_SEQUENCE_H */
diff --git a/engines/mads/core/sound.cpp b/engines/mads/core/sound.cpp
index 9610ac0022e..a838dadad1f 100644
--- a/engines/mads/core/sound.cpp
+++ b/engines/mads/core/sound.cpp
@@ -1008,4 +1008,4 @@ int ASound::command8() {
return result;
}
-} // End of namespace MADS
+} // namespace MADS
diff --git a/engines/mads/core/sprites.cpp b/engines/mads/core/sprites.cpp
index 6254968a968..7cdbd75fb15 100644
--- a/engines/mads/core/sprites.cpp
+++ b/engines/mads/core/sprites.cpp
@@ -420,4 +420,4 @@ SpriteAsset *&SpriteSets::operator[](int idx) {
Common::Array<SpriteAsset *>::operator[](idx);
}
-} // End of namespace MADS
+} // namespace MADS
diff --git a/engines/mads/core/sprites.h b/engines/mads/core/sprites.h
index 8a988955241..c4253e48820 100644
--- a/engines/mads/core/sprites.h
+++ b/engines/mads/core/sprites.h
@@ -236,6 +236,6 @@ public:
SpriteAsset *&operator[](int idx);
};
-} // End of namespace MADS
+} // namespace MADS
#endif /* MADS_SPRITES_H */
diff --git a/engines/mads/core/staticres.cpp b/engines/mads/core/staticres.cpp
index 747fbf2ba4e..0391bb292df 100644
--- a/engines/mads/core/staticres.cpp
+++ b/engines/mads/core/staticres.cpp
@@ -54,4 +54,4 @@ const uint32 DEFAULT_VGA_HIGH_PALETTE[16] = {
0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000
};
-} // End of namespace MADS
+} // namespace MADS
diff --git a/engines/mads/core/staticres.h b/engines/mads/core/staticres.h
index 97d360ad25b..f17123af2c6 100644
--- a/engines/mads/core/staticres.h
+++ b/engines/mads/core/staticres.h
@@ -41,6 +41,6 @@ extern const char *const kGameReleaseTitleStr;
extern const uint32 DEFAULT_VGA_LOW_PALETTE[16];
extern const uint32 DEFAULT_VGA_HIGH_PALETTE[16];
-} // End of namespace MADS
+} // namespace MADS
#endif /* MADS_STATICRES_H */
diff --git a/engines/mads/core/user_interface.cpp b/engines/mads/core/user_interface.cpp
index 35bc03ab0db..7062a4825e3 100644
--- a/engines/mads/core/user_interface.cpp
+++ b/engines/mads/core/user_interface.cpp
@@ -1113,4 +1113,4 @@ void UserInterface::synchronize(Common::Serializer &s) {
s.syncAsSint16LE(_categoryIndexes[i]);
}
-} // End of namespace MADS
+} // namespace MADS
diff --git a/engines/mads/core/user_interface.h b/engines/mads/core/user_interface.h
index 5ccd1b0a511..0d28b4cae96 100644
--- a/engines/mads/core/user_interface.h
+++ b/engines/mads/core/user_interface.h
@@ -303,6 +303,6 @@ public:
void refresh();
};
-} // End of namespace MADS
+} // namespace MADS
#endif /* MADS_USER_INTERFACE_H */
diff --git a/engines/mads/detection.h b/engines/mads/detection.h
index 04f0a28bd72..f910b1ef727 100644
--- a/engines/mads/detection.h
+++ b/engines/mads/detection.h
@@ -60,6 +60,6 @@ struct MADSGameDescription {
//#define GAMEOPTION_GRAPHICS_DITHERING GUIO_GAMEOPTIONS7
-} // End of namespace MADS
+} // namespace MADS
-#endif // MADS_DETECTION_H
+#endif
diff --git a/engines/mads/detection_tables.h b/engines/mads/detection_tables.h
index f6998304ee9..980cbd64ea8 100644
--- a/engines/mads/detection_tables.h
+++ b/engines/mads/detection_tables.h
@@ -240,4 +240,4 @@ static const MADSGameDescription gameDescriptions[] = {
{ AD_TABLE_END_MARKER, 0, 0 }
};
-} // End of namespace MADS
+} // namespace MADS
diff --git a/engines/mads/dragonsphere/dragonsphere_scenes.cpp b/engines/mads/dragonsphere/dragonsphere_scenes.cpp
index fffbfc82e42..5b76cd28bd6 100644
--- a/engines/mads/dragonsphere/dragonsphere_scenes.cpp
+++ b/engines/mads/dragonsphere/dragonsphere_scenes.cpp
@@ -232,5 +232,5 @@ void SceneInfoDragonsphere::loadCodes(BaseSurface &depthSurface, Common::Seekabl
delete[] walkMap;
}
-} // End of namespace Dragonsphere
-} // End of namespace MADS
+} // namespace Dragonsphere
+} // namespace MADS
diff --git a/engines/mads/dragonsphere/dragonsphere_scenes.h b/engines/mads/dragonsphere/dragonsphere_scenes.h
index 6b6027c27ec..4bc5a6ef276 100644
--- a/engines/mads/dragonsphere/dragonsphere_scenes.h
+++ b/engines/mads/dragonsphere/dragonsphere_scenes.h
@@ -665,7 +665,7 @@ public:
void actions() override {}
};
-} // End of namespace Dragonsphere
-} // End of namespace MADS
+} // namespace Dragonsphere
+} // namespace MADS
#endif
diff --git a/engines/mads/dragonsphere/dragonsphere_scenes1.cpp b/engines/mads/dragonsphere/dragonsphere_scenes1.cpp
index 66203b61360..ac43e50ea5b 100644
--- a/engines/mads/dragonsphere/dragonsphere_scenes1.cpp
+++ b/engines/mads/dragonsphere/dragonsphere_scenes1.cpp
@@ -3686,5 +3686,5 @@ void Scene105::handleConversation() {
/*------------------------------------------------------------------------*/
-} // End of namespace Dragonsphere
-} // End of namespace MADS
+} // namespace Dragonsphere
+} // namespace MADS
diff --git a/engines/mads/dragonsphere/dragonsphere_scenes1.h b/engines/mads/dragonsphere/dragonsphere_scenes1.h
index 3be73b02295..f31e0df28c5 100644
--- a/engines/mads/dragonsphere/dragonsphere_scenes1.h
+++ b/engines/mads/dragonsphere/dragonsphere_scenes1.h
@@ -177,7 +177,7 @@ public:
void actions() override;
};
-} // End of namespace Dragonsphere
-} // End of namespace MADS
+} // namespace Dragonsphere
+} // namespace MADS
#endif
diff --git a/engines/mads/dragonsphere/game_dragonsphere.cpp b/engines/mads/dragonsphere/game_dragonsphere.cpp
index 061aeb8fa32..e41d122b46a 100644
--- a/engines/mads/dragonsphere/game_dragonsphere.cpp
+++ b/engines/mads/dragonsphere/game_dragonsphere.cpp
@@ -155,5 +155,5 @@ void GameDragonsphere::synchronize(Common::Serializer &s, bool phase1) {
}
}
-} // End of namespace Dragonsphere
-} // End of namespace MADS
+} // namespace Dragonsphere
+} // namespace MADS
diff --git a/engines/mads/dragonsphere/game_dragonsphere.h b/engines/mads/dragonsphere/game_dragonsphere.h
index 341803746a0..83cc23b33c8 100644
--- a/engines/mads/dragonsphere/game_dragonsphere.h
+++ b/engines/mads/dragonsphere/game_dragonsphere.h
@@ -132,7 +132,7 @@ typedef Section1Handler Section6Handler;
typedef Section1Handler Section7Handler;
typedef Section1Handler Section8Handler;
-} // End of namespace Dragonsphere
-} // End of namespace MADS
+} // namespace Dragonsphere
+} // namespace MADS
#endif
diff --git a/engines/mads/dragonsphere/globals_dragonsphere.cpp b/engines/mads/dragonsphere/globals_dragonsphere.cpp
index 750d75c9199..69523247d75 100644
--- a/engines/mads/dragonsphere/globals_dragonsphere.cpp
+++ b/engines/mads/dragonsphere/globals_dragonsphere.cpp
@@ -41,5 +41,5 @@ void DragonsphereGlobals::synchronize(Common::Serializer &s) {
_animationIndexes.synchronize(s);
}
-} // End of namespace Dragonsphere
-} // End of namespace MADS
+} // namespace Dragonsphere
+} // namespace MADS
diff --git a/engines/mads/dragonsphere/globals_dragonsphere.h b/engines/mads/dragonsphere/globals_dragonsphere.h
index d632a49c80e..4d99cc25363 100644
--- a/engines/mads/dragonsphere/globals_dragonsphere.h
+++ b/engines/mads/dragonsphere/globals_dragonsphere.h
@@ -173,7 +173,7 @@ public:
virtual void synchronize(Common::Serializer &s);
};
-} // End of namespace Dragonsphere
-} // End of namespace MADS
+} // namespace Dragonsphere
+} // namespace MADS
#endif
diff --git a/engines/mads/forest/forest_scenes.cpp b/engines/mads/forest/forest_scenes.cpp
index 194fb382e35..c2d104a016c 100644
--- a/engines/mads/forest/forest_scenes.cpp
+++ b/engines/mads/forest/forest_scenes.cpp
@@ -171,5 +171,5 @@ void SceneInfoForest::loadCodes(BaseSurface &depthSurface, Common::SeekableReadS
delete[] walkMap;
}
-} // End of namespace Forest
-} // End of namespace MADS
+} // namespace Forest
+} // namespace MADS
diff --git a/engines/mads/forest/forest_scenes.h b/engines/mads/forest/forest_scenes.h
index 01c50442fe6..2ea438790a8 100644
--- a/engines/mads/forest/forest_scenes.h
+++ b/engines/mads/forest/forest_scenes.h
@@ -229,7 +229,7 @@ public:
void actions() override {}
};
-} // End of namespace Forest
-} // End of namespace MADS
+} // namespace Forest
+} // namespace MADS
#endif
diff --git a/engines/mads/forest/game_forest.cpp b/engines/mads/forest/game_forest.cpp
index 1263bbea214..4260c8358f5 100644
--- a/engines/mads/forest/game_forest.cpp
+++ b/engines/mads/forest/game_forest.cpp
@@ -155,5 +155,5 @@ void GameForest::synchronize(Common::Serializer &s, bool phase1) {
}
}
-} // End of namespace Forest
-} // End of namespace MADS
+} // namespace Forest
+} // namespace MADS
diff --git a/engines/mads/forest/game_forest.h b/engines/mads/forest/game_forest.h
index 42235aea830..bca5f938d9d 100644
--- a/engines/mads/forest/game_forest.h
+++ b/engines/mads/forest/game_forest.h
@@ -99,7 +99,7 @@ typedef Section1Handler Section6Handler;
typedef Section1Handler Section7Handler;
typedef Section1Handler Section8Handler;
-} // End of namespace Forest
-} // End of namespace MADS
+} // namespace Forest
+} // namespace MADS
#endif
diff --git a/engines/mads/forest/globals_forest.cpp b/engines/mads/forest/globals_forest.cpp
index 5bb92c104a4..9e6e6565351 100644
--- a/engines/mads/forest/globals_forest.cpp
+++ b/engines/mads/forest/globals_forest.cpp
@@ -41,5 +41,5 @@ void ForestGlobals::synchronize(Common::Serializer &s) {
_animationIndexes.synchronize(s);
}
-} // End of namespace Forest
-} // End of namespace MADS
+} // namespace Forest
+} // namespace MADS
diff --git a/engines/mads/forest/globals_forest.h b/engines/mads/forest/globals_forest.h
index e082ca6e006..f0571ea179a 100644
--- a/engines/mads/forest/globals_forest.h
+++ b/engines/mads/forest/globals_forest.h
@@ -52,7 +52,7 @@ public:
virtual void synchronize(Common::Serializer &s);
};
-} // End of namespace Forest
-} // End of namespace MADS
+} // namespace Forest
+} // namespace MADS
#endif
diff --git a/engines/mads/madsv2/phantom/rooms/room206.h b/engines/mads/madsv2/phantom/rooms/room206.h
index b953eb56bf0..c0744ef4403 100644
--- a/engines/mads/madsv2/phantom/rooms/room206.h
+++ b/engines/mads/madsv2/phantom/rooms/room206.h
@@ -95,4 +95,4 @@ void room_206_parser();
} // namespace MADSV2
} // namespace MADS
-#endif // MADS_PHANTOM_ROOM206_H
+#endif
diff --git a/engines/mads/madsv2/phantom/rooms/room207.h b/engines/mads/madsv2/phantom/rooms/room207.h
index b45a58cef60..37fac901a87 100644
--- a/engines/mads/madsv2/phantom/rooms/room207.h
+++ b/engines/mads/madsv2/phantom/rooms/room207.h
@@ -75,4 +75,4 @@ void room_207_parser();
} // namespace MADSV2
} // namespace MADS
-#endif // MADS_PHANTOM_ROOM207_H
+#endif
diff --git a/engines/mads/madsv2/phantom/rooms/room208.h b/engines/mads/madsv2/phantom/rooms/room208.h
index 0823cfd1acf..d48ead00f80 100644
--- a/engines/mads/madsv2/phantom/rooms/room208.h
+++ b/engines/mads/madsv2/phantom/rooms/room208.h
@@ -93,4 +93,4 @@ void room_208_daemon();
} // namespace MADSV2
} // namespace MADS
-#endif // MADS_PHANTOM_ROOM208_H
+#endif
diff --git a/engines/mads/metaengine.cpp b/engines/mads/metaengine.cpp
index 08f50828c88..1cad0e5bdee 100644
--- a/engines/mads/metaengine.cpp
+++ b/engines/mads/metaengine.cpp
@@ -161,7 +161,7 @@ Common::Platform MADSEngine::getPlatform() const {
return _gameDescription->desc.platform;
}
-} // End of namespace MADS
+} // namespace MADS
class MADSMetaEngine : public AdvancedMetaEngine<MADS::MADSGameDescription> {
public:
diff --git a/engines/mads/nebular/debugger.cpp b/engines/mads/nebular/debugger.cpp
index 8b0f502a34b..ea561dbc16e 100644
--- a/engines/mads/nebular/debugger.cpp
+++ b/engines/mads/nebular/debugger.cpp
@@ -404,4 +404,4 @@ bool Debugger::Cmd_SetCamera(int argc, const char **argv) {
return false;
}
}
-} // End of namespace MADS
+} // namespace MADS
diff --git a/engines/mads/nebular/debugger.h b/engines/mads/nebular/debugger.h
index c2ea8300aa7..27e8d79e145 100644
--- a/engines/mads/nebular/debugger.h
+++ b/engines/mads/nebular/debugger.h
@@ -59,6 +59,6 @@ public:
~Debugger() override {}
};
-} // End of namespace MADS
+} // namespace MADS
#endif /* MADS_DEBUGGER_H */
diff --git a/engines/mads/nebular/dialogs_nebular.cpp b/engines/mads/nebular/dialogs_nebular.cpp
index 60ac9be0346..d8a759832d6 100644
--- a/engines/mads/nebular/dialogs_nebular.cpp
+++ b/engines/mads/nebular/dialogs_nebular.cpp
@@ -1210,6 +1210,6 @@ void OptionsDialog::show() {
}
}
-} // End of namespace Nebular
+} // namespace Nebular
-} // End of namespace MADS
+} // namespace MADS
diff --git a/engines/mads/nebular/dialogs_nebular.h b/engines/mads/nebular/dialogs_nebular.h
index 1518bd5d830..007329db4ba 100644
--- a/engines/mads/nebular/dialogs_nebular.h
+++ b/engines/mads/nebular/dialogs_nebular.h
@@ -264,8 +264,8 @@ public:
void show() override;
};
-} // End of namespace Nebular
+} // namespace Nebular
-} // End of namespace MADS
+} // namespace MADS
#endif /* MADS_DIALOGS_NEBULAR_H */
diff --git a/engines/mads/nebular/game_nebular.cpp b/engines/mads/nebular/game_nebular.cpp
index 18cc2f03456..562492100e5 100644
--- a/engines/mads/nebular/game_nebular.cpp
+++ b/engines/mads/nebular/game_nebular.cpp
@@ -904,6 +904,6 @@ void GameNebular::synchronize(Common::Serializer &s, bool phase1) {
}
}
-} // End of namespace Nebular
+} // namespace Nebular
-} // End of namespace MADS
+} // namespace MADS
diff --git a/engines/mads/nebular/game_nebular.h b/engines/mads/nebular/game_nebular.h
index da33de5b877..9e538102723 100644
--- a/engines/mads/nebular/game_nebular.h
+++ b/engines/mads/nebular/game_nebular.h
@@ -153,8 +153,8 @@ typedef Section1Handler Section6Handler;
typedef Section1Handler Section7Handler;
typedef Section1Handler Section8Handler;
-} // End of namespace Nebular
+} // namespace Nebular
-} // End of namespace MADS
+} // namespace MADS
#endif /* MADS_GAME_NEBULAR_H */
diff --git a/engines/mads/nebular/globals_nebular.cpp b/engines/mads/nebular/globals_nebular.cpp
index 66601a3bf5f..92a2870c4c3 100644
--- a/engines/mads/nebular/globals_nebular.cpp
+++ b/engines/mads/nebular/globals_nebular.cpp
@@ -49,6 +49,6 @@ void NebularGlobals::synchronize(Common::Serializer &s) {
}
-} // End of namespace Nebular
+} // namespace Nebular
-} // End of namespace MADS
+} // namespace MADS
diff --git a/engines/mads/nebular/globals_nebular.h b/engines/mads/nebular/globals_nebular.h
index 1fc86b3c64c..eae8a6597af 100644
--- a/engines/mads/nebular/globals_nebular.h
+++ b/engines/mads/nebular/globals_nebular.h
@@ -307,8 +307,8 @@ public:
virtual void synchronize(Common::Serializer &s);
};
-} // End of namespace Nebular
+} // namespace Nebular
-} // End of namespace MADS
+} // namespace MADS
#endif /* MADS_GLOBALS_NEBULAR_H */
diff --git a/engines/mads/nebular/menu_nebular.cpp b/engines/mads/nebular/menu_nebular.cpp
index 418ba2e2576..772b05ac870 100644
--- a/engines/mads/nebular/menu_nebular.cpp
+++ b/engines/mads/nebular/menu_nebular.cpp
@@ -432,6 +432,6 @@ void RexAnimationView::scriptDone() {
}
}
-} // End of namespace Nebular
+} // namespace Nebular
-} // End of namespace MADS
+} // namespace MADS
diff --git a/engines/mads/nebular/menu_nebular.h b/engines/mads/nebular/menu_nebular.h
index 2f5466c027b..339ef084aa9 100644
--- a/engines/mads/nebular/menu_nebular.h
+++ b/engines/mads/nebular/menu_nebular.h
@@ -154,8 +154,8 @@ public:
RexTextView(RexNebularEngine *vm) : TextView(vm) {}
};
-} // End of namespace Nebular
+} // namespace Nebular
-} // End of namespace MADS
+} // namespace MADS
#endif /* MADS_MENU_NEBULAR_H */
diff --git a/engines/mads/nebular/nebular.cpp b/engines/mads/nebular/nebular.cpp
index 7424e218df1..5ce97f81b49 100644
--- a/engines/mads/nebular/nebular.cpp
+++ b/engines/mads/nebular/nebular.cpp
@@ -208,4 +208,4 @@ Common::Error RexNebularEngine::saveGameState(int slot, const Common::String &de
return Common::kNoError;
}
-} // End of namespace MADS
+} // namespace MADS
diff --git a/engines/mads/nebular/nebular_scenes.cpp b/engines/mads/nebular/nebular_scenes.cpp
index 855536ca3a2..484a0314cc3 100644
--- a/engines/mads/nebular/nebular_scenes.cpp
+++ b/engines/mads/nebular/nebular_scenes.cpp
@@ -625,6 +625,6 @@ void SceneTeleporter::teleporterStep() {
}
}
-} // End of namespace Nebular
+} // namespace Nebular
-} // End of namespace MADS
+} // namespace MADS
diff --git a/engines/mads/nebular/nebular_scenes.h b/engines/mads/nebular/nebular_scenes.h
index 31c375d86d3..58980ed8076 100644
--- a/engines/mads/nebular/nebular_scenes.h
+++ b/engines/mads/nebular/nebular_scenes.h
@@ -1411,7 +1411,7 @@ protected:
SceneTeleporter(RexNebularEngine *vm);
};
-} // End of namespace Nebular
-} // End of namespace MADS
+} // namespace Nebular
+} // namespace MADS
#endif /* MADS_NEBULAR_SCENES_H */
diff --git a/engines/mads/nebular/nebular_scenes1.cpp b/engines/mads/nebular/nebular_scenes1.cpp
index e1dc8818206..17679268945 100644
--- a/engines/mads/nebular/nebular_scenes1.cpp
+++ b/engines/mads/nebular/nebular_scenes1.cpp
@@ -3176,5 +3176,5 @@ void Scene112::step() {
/*------------------------------------------------------------------------*/
-} // End of namespace Nebular
-} // End of namespace MADS
+} // namespace Nebular
+} // namespace MADS
diff --git a/engines/mads/nebular/nebular_scenes1.h b/engines/mads/nebular/nebular_scenes1.h
index 683a561e40f..1e43c3a568e 100644
--- a/engines/mads/nebular/nebular_scenes1.h
+++ b/engines/mads/nebular/nebular_scenes1.h
@@ -257,7 +257,7 @@ public:
void actions() override {};
};
-} // End of namespace Nebular
-} // End of namespace MADS
+} // namespace Nebular
+} // namespace MADS
#endif /* MADS_NEBULAR_SCENES1_H */
diff --git a/engines/mads/nebular/nebular_scenes2.cpp b/engines/mads/nebular/nebular_scenes2.cpp
index efa0a0e91a6..8f72e3e7ab1 100644
--- a/engines/mads/nebular/nebular_scenes2.cpp
+++ b/engines/mads/nebular/nebular_scenes2.cpp
@@ -5522,5 +5522,5 @@ void Scene216::step() {
/*------------------------------------------------------------------------*/
-} // End of namespace Nebular
-} // End of namespace MADS
+} // namespace Nebular
+} // namespace MADS
diff --git a/engines/mads/nebular/nebular_scenes2.h b/engines/mads/nebular/nebular_scenes2.h
index 8a05a58561f..ed498f018b7 100644
--- a/engines/mads/nebular/nebular_scenes2.h
+++ b/engines/mads/nebular/nebular_scenes2.h
@@ -317,8 +317,8 @@ public:
void actions() override {};
};
-} // End of namespace Nebular
+} // namespace Nebular
-} // End of namespace MADS
+} // namespace MADS
#endif /* MADS_NEBULAR_SCENES2_H */
diff --git a/engines/mads/nebular/nebular_scenes3.cpp b/engines/mads/nebular/nebular_scenes3.cpp
index 7435fa324f9..67ebbf25678 100644
--- a/engines/mads/nebular/nebular_scenes3.cpp
+++ b/engines/mads/nebular/nebular_scenes3.cpp
@@ -5873,5 +5873,5 @@ void Scene399::actions() {
/*------------------------------------------------------------------------*/
-} // End of namespace Nebular
-} // End of namespace MADS
+} // namespace Nebular
+} // namespace MADS
diff --git a/engines/mads/nebular/nebular_scenes3.h b/engines/mads/nebular/nebular_scenes3.h
index baf0d9880b6..85e9b5b023c 100644
--- a/engines/mads/nebular/nebular_scenes3.h
+++ b/engines/mads/nebular/nebular_scenes3.h
@@ -540,8 +540,8 @@ public:
void actions() override;
};
-} // End of namespace Nebular
+} // namespace Nebular
-} // End of namespace MADS
+} // namespace MADS
#endif /* MADS_NEBULAR_SCENES3_H */
diff --git a/engines/mads/nebular/nebular_scenes4.cpp b/engines/mads/nebular/nebular_scenes4.cpp
index c2237cf5e72..95b035e393d 100644
--- a/engines/mads/nebular/nebular_scenes4.cpp
+++ b/engines/mads/nebular/nebular_scenes4.cpp
@@ -4211,5 +4211,5 @@ void Scene413::actions() {
/*------------------------------------------------------------------------*/
-} // End of namespace Nebular
-} // End of namespace MADS
+} // namespace Nebular
+} // namespace MADS
diff --git a/engines/mads/nebular/nebular_scenes4.h b/engines/mads/nebular/nebular_scenes4.h
index f7854df1ac4..0db1618330a 100644
--- a/engines/mads/nebular/nebular_scenes4.h
+++ b/engines/mads/nebular/nebular_scenes4.h
@@ -251,7 +251,7 @@ public:
void preActions() override;
void actions() override;
};
-} // End of namespace Nebular
-} // End of namespace MADS
+} // namespace Nebular
+} // namespace MADS
#endif /* MADS_NEBULAR_SCENES4_H */
diff --git a/engines/mads/nebular/nebular_scenes5.cpp b/engines/mads/nebular/nebular_scenes5.cpp
index 790c41f1c07..ad6aa542784 100644
--- a/engines/mads/nebular/nebular_scenes5.cpp
+++ b/engines/mads/nebular/nebular_scenes5.cpp
@@ -2875,5 +2875,5 @@ void Scene551::actions() {
/*------------------------------------------------------------------------*/
-} // End of namespace Nebular
-} // End of namespace MADS
+} // namespace Nebular
+} // namespace MADS
diff --git a/engines/mads/nebular/nebular_scenes5.h b/engines/mads/nebular/nebular_scenes5.h
index c34b1aac529..189fe0d341d 100644
--- a/engines/mads/nebular/nebular_scenes5.h
+++ b/engines/mads/nebular/nebular_scenes5.h
@@ -247,7 +247,7 @@ public:
void preActions() override;
void actions() override;
};
-} // End of namespace Nebular
-} // End of namespace MADS
+} // namespace Nebular
+} // namespace MADS
#endif /* MADS_NEBULAR_SCENES5_H */
diff --git a/engines/mads/nebular/nebular_scenes6.cpp b/engines/mads/nebular/nebular_scenes6.cpp
index 10634084507..48ac8e9ff27 100644
--- a/engines/mads/nebular/nebular_scenes6.cpp
+++ b/engines/mads/nebular/nebular_scenes6.cpp
@@ -4747,5 +4747,5 @@ void Scene620::step() {
/*------------------------------------------------------------------------*/
-} // End of namespace Nebular
-} // End of namespace MADS
+} // namespace Nebular
+} // namespace MADS
diff --git a/engines/mads/nebular/nebular_scenes6.h b/engines/mads/nebular/nebular_scenes6.h
index 3bf715ae134..a74f009ed1d 100644
--- a/engines/mads/nebular/nebular_scenes6.h
+++ b/engines/mads/nebular/nebular_scenes6.h
@@ -315,7 +315,7 @@ public:
void step() override;
void actions() override {};
};
-} // End of namespace Nebular
-} // End of namespace MADS
+} // namespace Nebular
+} // namespace MADS
#endif /* MADS_NEBULAR_SCENES6_H */
diff --git a/engines/mads/nebular/nebular_scenes7.cpp b/engines/mads/nebular/nebular_scenes7.cpp
index c64dfa85acb..2d639248eeb 100644
--- a/engines/mads/nebular/nebular_scenes7.cpp
+++ b/engines/mads/nebular/nebular_scenes7.cpp
@@ -2678,5 +2678,5 @@ void Scene752::actions() {
/*------------------------------------------------------------------------*/
-} // End of namespace Nebular
-} // End of namespace MADS
+} // namespace Nebular
+} // namespace MADS
diff --git a/engines/mads/nebular/nebular_scenes7.h b/engines/mads/nebular/nebular_scenes7.h
index 6070db7c0d8..8db5c958d3f 100644
--- a/engines/mads/nebular/nebular_scenes7.h
+++ b/engines/mads/nebular/nebular_scenes7.h
@@ -231,7 +231,7 @@ public:
void actions() override;
};
-} // End of namespace Nebular
-} // End of namespace MADS
+} // namespace Nebular
+} // namespace MADS
#endif /* MADS_NEBULAR_SCENES7_H */
diff --git a/engines/mads/nebular/nebular_scenes8.cpp b/engines/mads/nebular/nebular_scenes8.cpp
index 8335339e51b..ea67b7855e5 100644
--- a/engines/mads/nebular/nebular_scenes8.cpp
+++ b/engines/mads/nebular/nebular_scenes8.cpp
@@ -1622,5 +1622,5 @@ void Scene810::step() {
/*------------------------------------------------------------------------*/
-} // End of namespace Nebular
-} // End of namespace MADS
+} // namespace Nebular
+} // namespace MADS
diff --git a/engines/mads/nebular/nebular_scenes8.h b/engines/mads/nebular/nebular_scenes8.h
index 2b3aec7e564..19beb48584d 100644
--- a/engines/mads/nebular/nebular_scenes8.h
+++ b/engines/mads/nebular/nebular_scenes8.h
@@ -158,7 +158,7 @@ public:
void actions() override {};
};
-} // End of namespace Nebular
-} // End of namespace MADS
+} // namespace Nebular
+} // namespace MADS
#endif /* MADS_NEBULAR_SCENES8_H */
diff --git a/engines/mads/nebular/sound_nebular.cpp b/engines/mads/nebular/sound_nebular.cpp
index 5cd34715d68..5949f0e44ca 100644
--- a/engines/mads/nebular/sound_nebular.cpp
+++ b/engines/mads/nebular/sound_nebular.cpp
@@ -2589,6 +2589,6 @@ int ASound9::command51() {
}
-} // End of namespace Nebular
+} // namespace Nebular
-} // End of namespace MADS
+} // namespace MADS
diff --git a/engines/mads/nebular/sound_nebular.h b/engines/mads/nebular/sound_nebular.h
index a6392ac1c89..5b9b5670dc9 100644
--- a/engines/mads/nebular/sound_nebular.h
+++ b/engines/mads/nebular/sound_nebular.h
@@ -447,8 +447,8 @@ public:
int command(int commandId, int param) override;
};
-} // End of namespace Nebular
+} // namespace Nebular
-} // End of namespace MADS
+} // namespace MADS
#endif /* MADS_SOUND_NEBULAR_H */
Commit: f6be220385a4617a51520e1c3f25b7220d12bfa8
https://github.com/scummvm/scummvm/commit/f6be220385a4617a51520e1c3f25b7220d12bfa8
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:54+10:00
Commit Message:
MADS: PHANTOM: Added global_init_code
Changed paths:
engines/mads/madsv2/core/game.cpp
engines/mads/madsv2/core/game.h
engines/mads/madsv2/core/global.cpp
engines/mads/madsv2/core/himem.cpp
engines/mads/madsv2/core/himem.h
engines/mads/madsv2/core/inter.cpp
engines/mads/madsv2/core/player.cpp
engines/mads/madsv2/engine.h
engines/mads/madsv2/phantom/catacombs.cpp
engines/mads/madsv2/phantom/catacombs.h
engines/mads/madsv2/phantom/global.h
engines/mads/madsv2/phantom/phantom.cpp
engines/mads/madsv2/phantom/phantom.h
diff --git a/engines/mads/madsv2/core/game.cpp b/engines/mads/madsv2/core/game.cpp
index e78014c1dad..d2bb4c7ff1e 100644
--- a/engines/mads/madsv2/core/game.cpp
+++ b/engines/mads/madsv2/core/game.cpp
@@ -1341,7 +1341,6 @@ void game_control() {
if ((result != COPY_FAIL) && (result != COPY_ESCAPE)) {
ems_paging_mode(EMS_PAGING_GLOBAL);
global_init_code();
- main_global_init_code();
}
if (game_restore_flag && (result != COPY_FAIL) && (result != COPY_ESCAPE)) {
@@ -1612,9 +1611,7 @@ void game_control() {
player_stationary_update();
if (active_inven >= 0) {
- /* keep inventory turned off until selected */
- inter_turn_off_object(); /* delete this and uncomment below to return system to original */
- /* inter_spin_object (inven[active_inven]); */
+ inter_spin_object(inven[active_inven]);
} else {
inter_turn_off_object();
}
@@ -3338,13 +3335,5 @@ void main_cold_data_init() {
g_engine->main_cold_data_init();
}
-void main_false_start() {
- g_engine->main_cold_data_init();
-}
-
-void main_global_init_code() {
- g_engine->main_global_init_code();
-}
-
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/core/game.h b/engines/mads/madsv2/core/game.h
index 34b8a988b9b..51fa5430511 100644
--- a/engines/mads/madsv2/core/game.h
+++ b/engines/mads/madsv2/core/game.h
@@ -255,8 +255,6 @@ int main_cheating_key(int mykey);
int main_normal_key(int mykey);
int main_copy_verify(void);
void main_cold_data_init(void);
-void main_false_start(void);
-void main_global_init_code(void);
} // namespace MADSV2
diff --git a/engines/mads/madsv2/core/global.cpp b/engines/mads/madsv2/core/global.cpp
index 286d2898bc6..c556fce5946 100644
--- a/engines/mads/madsv2/core/global.cpp
+++ b/engines/mads/madsv2/core/global.cpp
@@ -36,7 +36,7 @@ char global_release_copyright[] = { "ScummVM" };
void global_init_code() {
- error("TODO: void global_init_code(void);");
+ g_engine->global_init_code();
}
void global_daemon_code() {
diff --git a/engines/mads/madsv2/core/himem.cpp b/engines/mads/madsv2/core/himem.cpp
index 1591d71e77a..2981380db11 100644
--- a/engines/mads/madsv2/core/himem.cpp
+++ b/engines/mads/madsv2/core/himem.cpp
@@ -360,7 +360,7 @@ done:
return preload_handle;
}
-int himem_preload_series(char *filename, int level) {
+int himem_preload_series(const char *fname, int level) {
int preload_handle = -1;
int new_handle = -1;
int page_marker = -1;
@@ -395,8 +395,8 @@ int himem_preload_series(char *filename, int level) {
handle.open = false;
- Common::strcpy_s(file_buf, filename);
- filename = file_buf;
+ Common::strcpy_s(file_buf, fname);
+ char *filename = file_buf;
fileio_add_ext(filename, "SS"); /* Default to Sprite Series */
diff --git a/engines/mads/madsv2/core/himem.h b/engines/mads/madsv2/core/himem.h
index 2785339793f..c28d4648dc8 100644
--- a/engines/mads/madsv2/core/himem.h
+++ b/engines/mads/madsv2/core/himem.h
@@ -69,7 +69,7 @@ extern int himem_directory_setup();
extern void himem_shutdown();
extern void himem_startup();
extern int himem_preload(char *filename, int level);
-extern int himem_preload_series(char *filename, int level);
+extern int himem_preload_series(const char *filename, int level);
extern void himem_flush(int level);
} // namespace MADSV2
diff --git a/engines/mads/madsv2/core/inter.cpp b/engines/mads/madsv2/core/inter.cpp
index 706851ab2da..95237aed6de 100644
--- a/engines/mads/madsv2/core/inter.cpp
+++ b/engines/mads/madsv2/core/inter.cpp
@@ -46,6 +46,7 @@
#include "mads/madsv2/core/env.h"
#include "mads/madsv2/core/error.h"
#include "mads/madsv2/core/extra.h"
+#include "mads/madsv2/engine.h"
namespace MADS {
namespace MADSV2 {
@@ -2096,9 +2097,14 @@ void inter_spin_object(int object_id) {
inter_object_series = matte_load_series(temp_buf,
SPRITE_LOAD_SPINNING_OBJECT,
SERIES_BONUS_OBJECT);
- stamp_sprite_to_interface(OUAF_OBJECT_X, OUAF_OBJECT_Y, 1, inter_object_series);
- paul_object_showing = object_id;
- if (inter_object_series < 0) goto done;
+
+ if (g_engine->getGameID() == GType_Forest) {
+ stamp_sprite_to_interface(OUAF_OBJECT_X, OUAF_OBJECT_Y, 1, inter_object_series);
+ paul_object_showing = object_id;
+ }
+
+ if (inter_object_series < 0)
+ goto done;
mcga_setpal_range(&master_palette, 7, 1);
mcga_setpal_range(&master_palette, 246, 6);
diff --git a/engines/mads/madsv2/core/player.cpp b/engines/mads/madsv2/core/player.cpp
index 07886fe6781..34dbb91379a 100644
--- a/engines/mads/madsv2/core/player.cpp
+++ b/engines/mads/madsv2/core/player.cpp
@@ -643,7 +643,7 @@ void player_preserve_palette() {
}
}
-void player_himem_preload(char *name, int level) {
+void player_himem_preload(const char *name, int level) {
char temp_buf[80];
int count;
diff --git a/engines/mads/madsv2/engine.h b/engines/mads/madsv2/engine.h
index 99f06b79c8e..a971a1f6a41 100644
--- a/engines/mads/madsv2/engine.h
+++ b/engines/mads/madsv2/engine.h
@@ -73,8 +73,7 @@ public:
}
virtual void main_cold_data_init() = 0;
- void main_false_start() {}
- void main_global_init_code() {}
+ virtual void global_init_code() = 0;
void section_music(int section_num) {}
void game_control_loop() {}
diff --git a/engines/mads/madsv2/phantom/catacombs.cpp b/engines/mads/madsv2/phantom/catacombs.cpp
index f9b53568c14..920b850c9e4 100644
--- a/engines/mads/madsv2/phantom/catacombs.cpp
+++ b/engines/mads/madsv2/phantom/catacombs.cpp
@@ -176,7 +176,7 @@ Catacombs hard_catacombs[62] = {
{ 404, { 34, 43, 60, 44 }, { NORTH, WEST, NORTH, EAST }, 0 }
};
-static void global_catacombs_setup() {
+void global_catacombs_setup() {
if (game.difficulty == HARD_MODE) {
catacombs = hard_catacombs;
global[catacombs_309_from] = 3;
diff --git a/engines/mads/madsv2/phantom/catacombs.h b/engines/mads/madsv2/phantom/catacombs.h
index 7a37ab470c9..06333f790f4 100644
--- a/engines/mads/madsv2/phantom/catacombs.h
+++ b/engines/mads/madsv2/phantom/catacombs.h
@@ -46,6 +46,7 @@ constexpr int MAZE_STONE = 0x0200; /* 453 */
constexpr int MAZE_BLOCK = 0x0400; /* 404 */
constexpr int MAZE_FALLEN_BLOCK = 0x0800; /* 404 */
+extern void global_catacombs_setup();
extern void global_catacombs_init();
extern void global_enter_catacombs(int special);
extern int global_catacombs_exit(int exit);
diff --git a/engines/mads/madsv2/phantom/global.h b/engines/mads/madsv2/phantom/global.h
index 09654a0911d..bfbd8424427 100644
--- a/engines/mads/madsv2/phantom/global.h
+++ b/engines/mads/madsv2/phantom/global.h
@@ -265,6 +265,15 @@ enum {
#define COFFIN_UNLOCKED 1
#define COFFIN_OPEN 2
+// chris_d_status
+#define BEFORE_LOVE 0
+
+/* Random music generated at start of each game */
+#define TOCCATA_FUGUE_D_MINOR 1
+#define LITTLE_FUGUE_G_MINOR 2
+#define FUGUE_B_MINOR 3
+#define FUGUE_C_MINOR 4
+
extern void global_section_constructor();
diff --git a/engines/mads/madsv2/phantom/phantom.cpp b/engines/mads/madsv2/phantom/phantom.cpp
index 6fc814d5215..5af95c5c74b 100644
--- a/engines/mads/madsv2/phantom/phantom.cpp
+++ b/engines/mads/madsv2/phantom/phantom.cpp
@@ -20,11 +20,16 @@
*/
#include "engines/util.h"
+#include "mads/madsv2/core/env.h"
#include "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/himem.h"
+#include "mads/madsv2/core/imath.h"
+#include "mads/madsv2/core/inter.h"
#include "mads/madsv2/core/kernel.h"
#include "mads/madsv2/phantom/phantom.h"
#include "mads/madsv2/phantom/main.h"
#include "mads/madsv2/phantom/sound_phantom.h"
+#include "mads/madsv2/phantom/catacombs.h"
#include "mads/madsv2/phantom/global.h"
namespace MADS {
@@ -42,7 +47,6 @@ Common::Error PhantomEngine::run() {
return Common::kNoError;
}
-
void PhantomEngine::main_cold_data_init() {
#if 0
debugger_reset = game_debugger_reset;
@@ -69,6 +73,107 @@ void PhantomEngine::main_cold_data_init() {
kernel.cheating = (byte)kernel_cheating_allowed;
}
+void PhantomEngine::global_init_code() {
+ Common::fill(global, global + GLOBAL_LIST_SIZE, 0);
+
+ global_catacombs_setup();
+
+ /* Section 1 Initialization */
+
+ player.facing = FACING_NORTH;
+ player.turn_to_facing = FACING_NORTH;
+
+ global[temp_var] = false;
+ global[room_103_104_transition] = NEW_ROOM;
+ global[current_year] = 1993;
+ global[trap_door_status] = TRAP_DOOR_IS_CLOSED;
+ global[christine_door_status] = CHRIS_IS_IN;
+ global[sandbag_status] = SANDBAG_SECURE;
+ global[jacques_status] = JACQUES_IS_ALIVE;
+ global[chris_f_status] = CHRIS_F_IS_ALIVE;
+ global[brie_talk_status] = BEFORE_BRIE_MOTIONS;
+ global[panel_in_206] = PANEL_UNDISCOVERED;
+ global[fight_status] = FIGHT_NOT_HAPPENED;
+ global[julies_door] = CRACKED_OPEN;
+ global[prompter_stand_status] = PROMPT_LEFT;
+ global[chris_d_status] = BEFORE_LOVE;
+ global[julie_name_is_known] = JULIE_NO;
+ global[doors_in_205] = BOTH_LOCKED;
+ global[madame_giry_loc] = MIDDLE;
+ global[ticket_people_here] = NEITHER;
+ global[coffin_status] = COFFIN_CLOSED;
+ global[done_brie_conv_203] = NO;
+ global[florent_name_is_known] = NO;
+ global[degas_name_is_known] = NO;
+ global[madame_giry_shows_up] = false;
+ global[jacques_name_is_known] = NO;
+ global[charles_name_is_known] = false;
+ global[top_floor_locked] = true;
+ global[madame_name_is_known] = NO;
+ global[chris_kicked_raoul_out] = false;
+ global[looked_at_case] = false;
+ global[ring_is_on_finger] = false;
+ global[he_listened] = false;
+ global[knocked_over_head] = false;
+ global[observed_phan_104] = false;
+ global[read_book] = false;
+ global[can_find_book_library] = false;
+ global[looked_at_skull_face] = false;
+ global[scanned_bookcase] = false;
+ global[ran_conv_in_205] = false;
+ global[done_rich_conv_203] = false;
+ global[hint_that_daae_is_home_1] = false;
+ global[hint_that_daae_is_home_2] = false;
+ global[make_brie_leave_203] = false;
+ global[make_rich_leave_203] = false;
+ global[came_from_fade] = false;
+ global[christine_told_envelope] = false;
+ global[leave_angel_music_on] = false;
+ global[door_in_409_is_open] = false;
+ global[priest_piston_puke] = false;
+ global[cob_web_is_cut] = false;
+ global[christine_is_in_boat] = false;
+ global[right_door_is_open_504] = false;
+ global[chris_left_505] = false;
+ global[chris_will_take_seat] = true;
+ global[flicked_1] = 0;
+ global[flicked_2] = 0;
+ global[flicked_3] = 0;
+ global[flicked_4] = 0;
+ global[player_score] = 0;
+ global[player_score_flags] = 0;
+
+ global[music_selected] = imath_random(TOCCATA_FUGUE_D_MINOR, FUGUE_C_MINOR);
+
+ inter_object_routine = global_object_sprite;
+
+
+ /* Global preload items */
+
+ player_himem_preload("RAL", GLOBAL);
+ himem_preload_series("*BOX", GLOBAL);
+ himem_preload_series("*LOGO", GLOBAL);
+ himem_preload_series("*MENU", GLOBAL);
+ himem_preload_series("*CURSOR", GLOBAL);
+ himem_preload_series("*FACERAL", GLOBAL);
+ himem_preload_series("*RRD_8", GLOBAL);
+ himem_preload_series("*RRD_9", GLOBAL);
+ himem_preload_series("*RDR_6", GLOBAL);
+ himem_preload_series("*RDR_9", GLOBAL);
+ himem_preload_series("*RTK_6", GLOBAL);
+ himem_preload_series("*RTK_9", GLOBAL);
+ himem_preload_series("*RALRH_9", GLOBAL);
+}
+
+void PhantomEngine::global_object_sprite() {
+ if (inter_object_id == 1 && global[lantern_status] == LANTERN_IS_ON)
+ inter_object_id = 31;
+
+ Common::strcpy_s(inter_object_buf, "*OB");
+ env_catint(inter_object_buf, inter_object_id, 3);
+ Common::strcat_s(inter_object_buf, "I");
+}
+
void PhantomEngine::global_section_constructor() {
Phantom::global_section_constructor();
}
diff --git a/engines/mads/madsv2/phantom/phantom.h b/engines/mads/madsv2/phantom/phantom.h
index a83ea2d5b32..dd8ecdbac60 100644
--- a/engines/mads/madsv2/phantom/phantom.h
+++ b/engines/mads/madsv2/phantom/phantom.h
@@ -32,6 +32,8 @@ class PhantomEngine : public MADSV2Engine {
private:
bool _soundFlag = true;
+ static void global_object_sprite();
+
public:
PhantomEngine(OSystem *syst, const MADSGameDescription *gameDesc) :
MADSV2Engine(syst, gameDesc) {}
@@ -40,6 +42,7 @@ public:
Common::Error run() override;
void main_cold_data_init() override;
+ void global_init_code() override;
void global_section_constructor() override;
};
Commit: 26ff0267bdd801bb8e34e81b96ee44842ec1f798
https://github.com/scummvm/scummvm/commit/26ff0267bdd801bb8e34e81b96ee44842ec1f798
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:55+10:00
Commit Message:
MADS: PHANTOM: Hooked up section_music
Changed paths:
engines/mads/madsv2/engine.h
engines/mads/madsv2/phantom/phantom.cpp
engines/mads/madsv2/phantom/phantom.h
diff --git a/engines/mads/madsv2/engine.h b/engines/mads/madsv2/engine.h
index a971a1f6a41..90d27215bb7 100644
--- a/engines/mads/madsv2/engine.h
+++ b/engines/mads/madsv2/engine.h
@@ -74,7 +74,7 @@ public:
virtual void main_cold_data_init() = 0;
virtual void global_init_code() = 0;
- void section_music(int section_num) {}
+ virtual void section_music(int section_num) = 0;
void game_control_loop() {}
virtual void global_section_constructor() = 0;
diff --git a/engines/mads/madsv2/phantom/phantom.cpp b/engines/mads/madsv2/phantom/phantom.cpp
index 5af95c5c74b..0b552e3c784 100644
--- a/engines/mads/madsv2/phantom/phantom.cpp
+++ b/engines/mads/madsv2/phantom/phantom.cpp
@@ -31,6 +31,11 @@
#include "mads/madsv2/phantom/sound_phantom.h"
#include "mads/madsv2/phantom/catacombs.h"
#include "mads/madsv2/phantom/global.h"
+#include "mads/madsv2/phantom/rooms/section1.h"
+#include "mads/madsv2/phantom/rooms/section2.h"
+#include "mads/madsv2/phantom/rooms/section3.h"
+#include "mads/madsv2/phantom/rooms/section4.h"
+#include "mads/madsv2/phantom/rooms/section5.h"
namespace MADS {
namespace MADSV2 {
@@ -165,6 +170,16 @@ void PhantomEngine::global_init_code() {
himem_preload_series("*RALRH_9", GLOBAL);
}
+void PhantomEngine::section_music(int section_num) {
+ switch (section_num) {
+ case 1: Rooms::section_1_music(); break;
+ case 2: Rooms::section_2_music(); break;
+ case 3: Rooms::section_3_music(); break;
+ case 4: Rooms::section_4_music(); break;
+ case 5: Rooms::section_5_music(); break;
+ }
+}
+
void PhantomEngine::global_object_sprite() {
if (inter_object_id == 1 && global[lantern_status] == LANTERN_IS_ON)
inter_object_id = 31;
diff --git a/engines/mads/madsv2/phantom/phantom.h b/engines/mads/madsv2/phantom/phantom.h
index dd8ecdbac60..798df973b1c 100644
--- a/engines/mads/madsv2/phantom/phantom.h
+++ b/engines/mads/madsv2/phantom/phantom.h
@@ -43,6 +43,7 @@ public:
void main_cold_data_init() override;
void global_init_code() override;
+ void section_music(int section_num) override;
void global_section_constructor() override;
};
Commit: a4bf87a78744b4e7c5ecb64a85da83d8ee3fbf76
https://github.com/scummvm/scummvm/commit/a4bf87a78744b4e7c5ecb64a85da83d8ee3fbf76
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:55+10:00
Commit Message:
MADS: PHANTOM: game_control_loop is not game-specific
Changed paths:
engines/mads/madsv2/core/game.cpp
engines/mads/madsv2/engine.h
diff --git a/engines/mads/madsv2/core/game.cpp b/engines/mads/madsv2/core/game.cpp
index d2bb4c7ff1e..537166b041f 100644
--- a/engines/mads/madsv2/core/game.cpp
+++ b/engines/mads/madsv2/core/game.cpp
@@ -171,6 +171,8 @@ int debugger_previous = DEBUGGER_NONE;
int debugger_watch = 0;
int debugger_watch_index[DEBUGGER_MAX_WATCH];
+static void game_control_loop();
+
static void game_cold_data_init() {
game.going = true;
@@ -1636,7 +1638,7 @@ void game_control() {
game_any_emergency = false;
}
- g_engine->game_control_loop();
+ game_control_loop();
/* ********************************************************************************************** */
@@ -2541,7 +2543,7 @@ skip_frame:
}
-void game_control_loop() {
+static void game_control_loop() {
game_any_keystroke = false;
digi_trigger_dialog = true;
diff --git a/engines/mads/madsv2/engine.h b/engines/mads/madsv2/engine.h
index 90d27215bb7..db17213ea12 100644
--- a/engines/mads/madsv2/engine.h
+++ b/engines/mads/madsv2/engine.h
@@ -75,7 +75,6 @@ public:
virtual void main_cold_data_init() = 0;
virtual void global_init_code() = 0;
virtual void section_music(int section_num) = 0;
- void game_control_loop() {}
virtual void global_section_constructor() = 0;
};
Commit: 05bd6c9b17c1cb62bf83c03dabcf9d657d81ce1a
https://github.com/scummvm/scummvm/commit/05bd6c9b17c1cb62bf83c03dabcf9d657d81ce1a
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:55+10:00
Commit Message:
MADS: PHANTOM: Clean up key callback functions
Changed paths:
engines/mads/madsv2/engine.h
diff --git a/engines/mads/madsv2/engine.h b/engines/mads/madsv2/engine.h
index db17213ea12..5fd85f6d19e 100644
--- a/engines/mads/madsv2/engine.h
+++ b/engines/mads/madsv2/engine.h
@@ -62,11 +62,11 @@ public:
uint32 getMillis();
/* Callback routines in game-specific MAIN module */
- int main_cheating_key(int mykey) {
- return 0;
+ int main_cheating_key(int mykey) const {
+ return mykey;
}
- int main_normal_key(int mykey) {
- return 0;
+ int main_normal_key(int mykey) const {
+ return mykey;
}
int main_copy_verify() {
return 0;
Commit: 0bb1d70975ae59b303d5122911cb27dba7060806
https://github.com/scummvm/scummvm/commit/0bb1d70975ae59b303d5122911cb27dba7060806
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:56+10:00
Commit Message:
MADS: PHANTOM: Hooking up game_main
Changed paths:
engines/mads/madsv2/core/game.cpp
engines/mads/madsv2/core/game.h
engines/mads/madsv2/core/xms.cpp
engines/mads/madsv2/core/xms.h
engines/mads/madsv2/engine.h
engines/mads/madsv2/phantom/main.cpp
engines/mads/madsv2/phantom/phantom.cpp
engines/mads/madsv2/phantom/phantom.h
engines/mads/module.mk
diff --git a/engines/mads/madsv2/core/game.cpp b/engines/mads/madsv2/core/game.cpp
index 537166b041f..a0a72d1f8ac 100644
--- a/engines/mads/madsv2/core/game.cpp
+++ b/engines/mads/madsv2/core/game.cpp
@@ -174,7 +174,7 @@ int debugger_watch_index[DEBUGGER_MAX_WATCH];
static void game_control_loop();
-static void game_cold_data_init() {
+void game_cold_data_init() {
game.going = true;
kernel.fx = 0;
@@ -211,7 +211,7 @@ static void game_cold_data_init() {
}
-static int scan_past(char **myscan, char scan) {
+static int scan_past(const char **myscan, char scan) {
int found = false;
while (**myscan && (**myscan != scan)) (*myscan)++;
@@ -226,14 +226,7 @@ static int scan_past(char **myscan, char scan) {
return found;
}
-
-
-/*
-/* flag_parse()
-/*
-/* Routine to parse command line flags.
-*/
-static void flag_parse(char **myscan) {
+void flag_parse(const char **myscan) {
long mem_max;
/* long mem_avail; */
@@ -434,9 +427,7 @@ done:
;
}
-
-
-static void show_version() {
+void show_version() {
echo(" ", true);
echo(global_release_name, true);
echo(" Release Version ", false);
@@ -456,7 +447,7 @@ static void show_version() {
}
-static void show_logo() {
+void show_logo() {
show_version();
}
@@ -3333,9 +3324,5 @@ int main_copy_verify() {
return g_engine->main_copy_verify();
}
-void main_cold_data_init() {
- g_engine->main_cold_data_init();
-}
-
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/core/game.h b/engines/mads/madsv2/core/game.h
index 51fa5430511..45da5bfa9d2 100644
--- a/engines/mads/madsv2/core/game.h
+++ b/engines/mads/madsv2/core/game.h
@@ -217,25 +217,6 @@ extern void (*room_parser_code_pointer)();
extern void (*room_error_code_pointer)();
extern void (*room_shutdown_code_pointer)();
-/* game_1.c */
-void game_main(int argc, char **argv);
-
-/* game_2.c */
-void game_save_name(int id);
-
-/* game_3.c */
-void game_set_camera_speed(void);
-
-/* game_4.c */
-void game_exec_function(void (*(target))());
-
-
-/* game_6.c */
-void game_debugger_reset(void);
-void game_debugger(void);
-
-
-/* game_5.c */
extern char game_save_file[13]; /* Save directory file */
extern char *game_save_directory; /* Save directory pointer */
@@ -243,19 +224,31 @@ extern int game_preserve_handle; /* scr_depth preserve */
extern Heap game_menu_heap; /* Custom heap for menu */
extern Popup *game_menu_popup; /* Popup structure for menu */
-
-
-/* game_5.c */
-void game_write_save_directory(void);
-void game_menu_setup(void);
-void game_menu_shutdown(void);
-
-/* Callback routines in game-specific MAIN module */
-int main_cheating_key(int mykey);
-int main_normal_key(int mykey);
-int main_copy_verify(void);
-void main_cold_data_init(void);
-
+extern int report_version;
+extern int art_hags_are_on_hd;
+
+extern void game_save_name(int id);
+extern void game_set_camera_speed(void);
+extern void game_exec_function(void (*(target))());
+extern void game_debugger_reset(void);
+extern void game_debugger(void);
+extern void game_write_save_directory(void);
+extern void game_menu_setup(void);
+extern void game_menu_shutdown(void);
+extern int main_cheating_key(int mykey);
+extern int main_normal_key(int mykey);
+extern int main_copy_verify(void);
+extern void game_cold_data_init();
+extern void game_control();
+
+/*
+/* flag_parse()
+/*
+/* Routine to parse command line flags.
+*/
+extern void flag_parse(const char **myscan);
+extern void show_logo();
+extern void show_version();
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/core/xms.cpp b/engines/mads/madsv2/core/xms.cpp
index 1e1647432bb..f81bd7efea2 100644
--- a/engines/mads/madsv2/core/xms.cpp
+++ b/engines/mads/madsv2/core/xms.cpp
@@ -24,6 +24,8 @@
namespace MADS {
namespace MADSV2 {
+bool xms_exists = false;
+bool xms_disabled = false;
word xms_version = 0;
dword xms_controller = 0;
word xms_chain_seg = 0;
diff --git a/engines/mads/madsv2/core/xms.h b/engines/mads/madsv2/core/xms.h
index ed773f97fea..c0039e3f784 100644
--- a/engines/mads/madsv2/core/xms.h
+++ b/engines/mads/madsv2/core/xms.h
@@ -22,7 +22,7 @@
#ifndef MADS_CORE_XMS_H
#define MADS_CORE_XMS_H
-#include "common/scummsys.h"
+#include "mads/madsv2/core/general.h"
namespace MADS {
namespace MADSV2 {
@@ -31,8 +31,8 @@ namespace MADSV2 {
#define XMS byte * /* XMS fake pointer type */
-extern int xms_exists; /* Flag if we've got some XMS memory */
-extern int xms_disabled; /* Flag to disable XMS altogether */
+extern bool xms_exists; /* Flag if we've got some XMS memory */
+extern bool xms_disabled; /* Flag to disable XMS altogether */
extern word xms_version; /* XMS driver version # */
extern dword xms_controller; /* XMS controller address */
extern word xms_chain_seg; /* First UMB MCB segment for us */
diff --git a/engines/mads/madsv2/engine.h b/engines/mads/madsv2/engine.h
index 5fd85f6d19e..558ee9b4b3a 100644
--- a/engines/mads/madsv2/engine.h
+++ b/engines/mads/madsv2/engine.h
@@ -72,7 +72,6 @@ public:
return 0;
}
- virtual void main_cold_data_init() = 0;
virtual void global_init_code() = 0;
virtual void section_music(int section_num) = 0;
diff --git a/engines/mads/madsv2/phantom/main.cpp b/engines/mads/madsv2/phantom/main.cpp
index 5f466087b15..ad9292aa372 100644
--- a/engines/mads/madsv2/phantom/main.cpp
+++ b/engines/mads/madsv2/phantom/main.cpp
@@ -21,12 +21,17 @@
#include "mads/madsv2/phantom/main.h"
#include "mads/madsv2/core/env.h"
+#include "mads/madsv2/core/error.h"
+#include "mads/madsv2/core/fileio.h"
+#include "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/himem.h"
#include "mads/madsv2/core/kernel.h"
#include "mads/madsv2/core/magic.h"
#include "mads/madsv2/core/matte.h"
#include "mads/madsv2/core/mcga.h"
#include "mads/madsv2/core/mouse.h"
#include "mads/madsv2/core/pal.h"
+#include "mads/madsv2/core/player.h"
#include "mads/madsv2/core/quote.h"
#include "mads/madsv2/core/speech.h"
#include "mads/madsv2/phantom/main_menu.h"
@@ -120,6 +125,152 @@ static void main_menu_main() {
warning("Selected item = %d", selected_item);
}
+static void main_cold_data_init() {
+#if 0
+ debugger_reset = game_debugger_reset;
+ debugger_update = game_debugger;
+
+ game_menu_routine = global_game_menu;
+ game_menu_init = global_menu_system_init;
+ game_menu_exit = global_menu_system_shutdown;
+ game_emergency_save = global_emergency_save;
+#endif
+ Common::strcpy_s(config_file_name, "config.pha");
+ Common::strcpy_s(save_game_key, "phan");
+ Common::strcpy_s(restart_game_key, "phantom");
+
+ Common::strcpy_s(player.series_name, "RAL");
+ player.walker_must_reload = true;
+ player.walker_loads_first = false;
+ player.walker_visible = true;
+ player.scaling_velocity = true;
+
+ Common::strcpy_s(kernel_cheating_password, "WIDECHEW");
+ kernel_cheating_allowed = strlen(kernel_cheating_password);
+
+ kernel.cheating = (byte)kernel_cheating_allowed;
+}
+
+static void game_main(int argc, const char **argv) {
+ int count;
+ int mads_mode;
+ const char *scan;
+ long mem_you_got;
+ long mem_required;
+
+ pack_enable_pfab_explode();
+
+ mads_mode = env_verify();
+
+ new_section = 9;
+ new_room = 901;
+
+ player.x = 160;
+ player.y = 78;
+
+ player.target_facing = FACING_NORTH;
+
+ game_cold_data_init();
+ main_cold_data_init();
+ global_read_config_file();
+ global_load_config_parameters();
+
+ if (argc >= 2) {
+ for (count = 1; count < argc; count++) {
+ if (strchr("-/", argv[count][0]) != NULL) {
+ for (scan = argv[count] + 1; *scan != 0; scan++) {
+ flag_parse(&scan);
+ }
+ } else if (argv[count][0] == '?') {
+ show_logo();
+
+ if (!mads_mode) env_search_mode = ENV_SEARCH_CONCAT_FILES;
+ error_dump_file("*warn2.dat");
+ goto done;
+ }
+ }
+ }
+
+ if (report_version) {
+ show_version();
+ goto done;
+ }
+
+ if (fileio_exist("global.hag")) {
+ art_hags_are_on_hd = true;
+ } else {
+ art_hags_are_on_hd = false;
+ }
+
+#if 0
+ if (config_file.cd_version_installed) {
+ strcpy(temp_buf_2, "x:\\forest.exe");
+ temp_buf_2[0] = env_cd_drive;
+ if (!fileio_exist(temp_buf_2)) {
+ problem();
+ printf("Please throw the Once Upon A Forest CD into drive %c:\n", (char)env_cd_drive);
+ printf("and type 'OUAF'. If your CD-ROM drive letter has changed, run\n");
+ printf("INSTALL to reconfigure this option.\n\n");
+ goto done;
+ }
+ }
+
+ if (!fileio_exist("config.for")) {
+ problem();
+ printf("Before you can run Once Upon A Forest, you need to run 'INSTALL' to configure\n");
+ printf("the game for you your hardware. Type 'INSTALL' and hit 'ENTER' when you have\n");
+ printf("finished reading this.\n\n");
+ goto done;
+ }
+
+ mem_you_got = mem_used + mem_avail_at_start;
+
+ if (mem_you_got < 569000) {
+ need_to_free = 569000 - mem_you_got;
+ problem();
+ printf("You need at least 588,000 bytes of conventional memory to play\n");
+ printf("Once Upon A Forest. You'll need to free up another %6ld bytes.\n\n", need_to_free);
+ /* printf("to play this game.\n\n"); */
+ goto done;
+ }
+#endif
+ himem_startup();
+
+ mem_required = 30L * 16384L;
+ mem_you_got = mem_required * 2;
+
+ himem_shutdown();
+
+ if (!mads_mode && (env_search_mode == ENV_SEARCH_MADS_PATH))
+ error("false start");
+
+ game_control();
+
+ if (!win_status) {
+ if (!chain_flag || !(win_status || force_chain) || !(key_abort_level < 2)) {
+ error_dump_file("*warn4.dat");
+ }
+
+ if (game_autosaved) {
+ error_dump_file("*warn5.dat");
+ }
+ }
+
+done:
+ global_unload_config_parameters();
+
+ if (fileio_exist("config.for")) {
+ global_write_config_file();
+ }
+ if (chain_flag && (win_status || force_chain) && (key_abort_level < 2)) {
+ warning("TODO: chain_execute");
+ } else {
+ if (win_status) {
+ debug("(Ending: %d)", win_status);
+ }
+ }
+}
+
void phantom_main() {
pack_enable_pfab_explode();
if (!env_verify())
diff --git a/engines/mads/madsv2/phantom/phantom.cpp b/engines/mads/madsv2/phantom/phantom.cpp
index 0b552e3c784..801e38f3f3e 100644
--- a/engines/mads/madsv2/phantom/phantom.cpp
+++ b/engines/mads/madsv2/phantom/phantom.cpp
@@ -52,32 +52,6 @@ Common::Error PhantomEngine::run() {
return Common::kNoError;
}
-void PhantomEngine::main_cold_data_init() {
-#if 0
- debugger_reset = game_debugger_reset;
- debugger_update = game_debugger;
-
- game_menu_routine = global_game_menu;
- game_menu_init = global_menu_system_init;
- game_menu_exit = global_menu_system_shutdown;
- game_emergency_save = global_emergency_save;
-#endif
- Common::strcpy_s(config_file_name, "config.pha");
- Common::strcpy_s(save_game_key, "phan");
- Common::strcpy_s(restart_game_key, "phantom");
-
- Common::strcpy_s(player.series_name, "RAL");
- player.walker_must_reload = true;
- player.walker_loads_first = false;
- player.walker_visible = true;
- player.scaling_velocity = true;
-
- Common::strcpy_s(kernel_cheating_password, "WIDECHEW");
- kernel_cheating_allowed = strlen(kernel_cheating_password);
-
- kernel.cheating = (byte)kernel_cheating_allowed;
-}
-
void PhantomEngine::global_init_code() {
Common::fill(global, global + GLOBAL_LIST_SIZE, 0);
diff --git a/engines/mads/madsv2/phantom/phantom.h b/engines/mads/madsv2/phantom/phantom.h
index 798df973b1c..2b3e2693b2f 100644
--- a/engines/mads/madsv2/phantom/phantom.h
+++ b/engines/mads/madsv2/phantom/phantom.h
@@ -41,7 +41,6 @@ public:
Common::Error run() override;
- void main_cold_data_init() override;
void global_init_code() override;
void section_music(int section_num) override;
void global_section_constructor() override;
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index 4c61def9d00..d61d2712f7f 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -120,6 +120,7 @@ MODULE_OBJS += \
madsv2/core/video.o \
madsv2/core/vocab.o \
madsv2/core/window.o \
+ madsv2/core/xms.o \
madsv2/phantom/mads/mads.o \
madsv2/phantom/rooms/section1.o \
madsv2/phantom/rooms/room101.o \
Commit: 8f39c1f651dd1a180411e5178bfa1fb8b4bcaa79
https://github.com/scummvm/scummvm/commit/8f39c1f651dd1a180411e5178bfa1fb8b4bcaa79
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:56+10:00
Commit Message:
MADS: PHANTOM: Tentative hookup of game_main
Changed paths:
engines/mads/madsv2/phantom/main.cpp
diff --git a/engines/mads/madsv2/phantom/main.cpp b/engines/mads/madsv2/phantom/main.cpp
index ad9292aa372..92c1c309e7f 100644
--- a/engines/mads/madsv2/phantom/main.cpp
+++ b/engines/mads/madsv2/phantom/main.cpp
@@ -120,9 +120,6 @@ static void main_menu_main() {
}
mcga_reset();
-
- // Handle menu item selection
- warning("Selected item = %d", selected_item);
}
static void main_cold_data_init() {
@@ -272,11 +269,26 @@ done:
}
void phantom_main() {
+ static const char *CMD_LINE[] = { nullptr, "-p" };
+
pack_enable_pfab_explode();
if (!env_verify())
env_search_mode = ENV_SEARCH_CONCAT_FILES;
- main_menu_main();
+ while (!g_engine->shouldQuit()) {
+ main_menu_main();
+
+ if (!g_engine->shouldQuit()) {
+ switch (selected_item) {
+ case 0:
+ game_main(2, CMD_LINE);
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
}
} // namespace Phantom
Commit: 0823b401c3ae2e251449692dae90d7f5e490b42d
https://github.com/scummvm/scummvm/commit/0823b401c3ae2e251449692dae90d7f5e490b42d
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:56+10:00
Commit Message:
MADS: PHANTOM: Shifting conv.cpp from phantom/ to core/
Changed paths:
A engines/mads/madsv2/core/conv.cpp
A engines/mads/madsv2/core/conv.h
A engines/mads/madsv2/phantom/mads/conv.h
R engines/mads/madsv2/phantom/conv.cpp
engines/mads/madsv2/core/game.cpp
engines/mads/madsv2/phantom/conv.h
engines/mads/madsv2/phantom/rooms/room101.cpp
engines/mads/madsv2/phantom/rooms/room103.cpp
engines/mads/madsv2/phantom/rooms/room104.cpp
engines/mads/madsv2/phantom/rooms/room105.cpp
engines/mads/madsv2/phantom/rooms/room106.cpp
engines/mads/madsv2/phantom/rooms/room108.cpp
engines/mads/madsv2/phantom/rooms/room111.cpp
engines/mads/madsv2/phantom/rooms/room112.cpp
engines/mads/madsv2/phantom/rooms/room113.cpp
engines/mads/madsv2/phantom/rooms/room201.cpp
engines/mads/madsv2/phantom/rooms/room202.cpp
engines/mads/madsv2/phantom/rooms/room203.cpp
engines/mads/madsv2/phantom/rooms/room204.cpp
engines/mads/madsv2/phantom/rooms/room205.cpp
engines/mads/madsv2/phantom/rooms/room206.cpp
engines/mads/madsv2/phantom/rooms/room207.cpp
engines/mads/madsv2/phantom/rooms/room208.cpp
engines/mads/madsv2/phantom/rooms/room303.cpp
engines/mads/madsv2/phantom/rooms/room304.cpp
engines/mads/madsv2/phantom/rooms/room308.cpp
engines/mads/madsv2/phantom/rooms/room309.cpp
engines/mads/madsv2/phantom/rooms/room501.cpp
engines/mads/madsv2/phantom/rooms/room504.cpp
engines/mads/madsv2/phantom/rooms/room505.cpp
engines/mads/madsv2/phantom/rooms/room506.cpp
engines/mads/madsv2/phantom/rooms/section1.cpp
engines/mads/madsv2/phantom/rooms/section1.h
engines/mads/madsv2/phantom/rooms/section2.cpp
engines/mads/madsv2/phantom/rooms/section2.h
engines/mads/madsv2/phantom/rooms/section3.cpp
engines/mads/madsv2/phantom/rooms/section3.h
engines/mads/madsv2/phantom/rooms/section4.cpp
engines/mads/madsv2/phantom/rooms/section4.h
engines/mads/madsv2/phantom/rooms/section5.cpp
engines/mads/madsv2/phantom/rooms/section5.h
engines/mads/module.mk
diff --git a/engines/mads/madsv2/phantom/conv.cpp b/engines/mads/madsv2/core/conv.cpp
similarity index 94%
rename from engines/mads/madsv2/phantom/conv.cpp
rename to engines/mads/madsv2/core/conv.cpp
index 14cad1e58c2..330e61d9e1a 100644
--- a/engines/mads/madsv2/phantom/conv.cpp
+++ b/engines/mads/madsv2/core/conv.cpp
@@ -21,11 +21,10 @@
#include "common/algorithm.h"
#include "common/str.h"
-#include "mads/madsv2/phantom/conv.h"
+#include "mads/madsv2/core/conv.h"
namespace MADS {
namespace MADSV2 {
-namespace Phantom {
int conv_restore_running;
ConvControl conv_control;
@@ -39,7 +38,6 @@ static int conv_slots[CONV_MAX_DATA];
static int conv_data[CONV_MAX_DATA];
static int conv_conditions[CONV_MAX_DATA];
-
static const char *conv_get_filename(int convNum, int extType, char *name) {
*name = '\0';
@@ -60,6 +58,10 @@ static ConvData *conv_load_data(const char *fname) {
void conv_system_init() {
+ conv_control.running = -1;
+ conv_control.slot = 0;
+ conv_control.status = CONV_NONE;
+
Common::fill(conv_slot_indexes, conv_slot_indexes + CONV_MAX_SLOTS, 0);
Common::fill(conv_slots, conv_slots + CONV_MAX_DATA, 0);
Common::fill(conv_data, conv_data + CONV_MAX_DATA, 0);
@@ -88,9 +90,15 @@ void conv_get(int convNum) {
}
void conv_run(int convNum) {}
+
+void conv_update(bool) {}
+
void conv_export_pointer(int *ptr) {}
+
void conv_abort() {}
+
void conv_me_trigger(int trigger) {}
+
void conv_you_trigger(int trigger) {}
int *conv_get_variable(int varNum) {
@@ -110,6 +118,5 @@ void conv_release() {
// TODO
}
-} // namespace Phantom
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/core/conv.h b/engines/mads/madsv2/core/conv.h
new file mode 100644
index 00000000000..acb98f2c8d0
--- /dev/null
+++ b/engines/mads/madsv2/core/conv.h
@@ -0,0 +1,87 @@
+/* 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 MADS_CORE_CONV_H
+#define MADS_CORE_CONV_H
+
+#include "common/scummsys.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+struct ConvData {
+ int16 node_count;
+ int16 dialog_count;
+ int16 message_count;
+ int16 text_line_count;
+ int16 num_variables;
+
+ int16 max_imports;
+ int16 speaker_count;
+ char speaker_portraits[5][16];
+ int16 speaker_frame[5];
+ char speech_file[14];
+ uint32 text_length;
+
+ uint32 commands_length;
+ void *text_ptr;
+ void *scripts_ptr;
+ void *nodes_ptr;
+ void *dialogs_ptr;
+ void *messages_ptr;
+ void *text_lines_ptr;
+};
+
+enum ConvStatus {
+ CONV_NONE,
+ CONV_STATUS_WAIT_AUTO,
+ CONV_STATUS_WAIT_ENTRY
+};
+
+struct ConvControl {
+ int running;
+ int slot;
+ ConvStatus status;
+};
+
+extern int conv_restore_running;
+extern ConvControl conv_control;
+extern int *conv_my_next_start;
+
+extern void conv_system_init();
+extern void conv_system_cleanup();
+
+extern void conv_get(int convNum);
+extern void conv_run(int convNum);
+extern void conv_update(bool);
+extern void conv_export_pointer(int *ptr);
+extern void conv_abort();
+extern void conv_me_trigger(int trigger);
+extern void conv_you_trigger(int trigger);
+extern int *conv_get_variable(int varNum);
+extern void conv_export_value(int varNum);
+extern void conv_hold();
+extern void conv_release();
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/core/game.cpp b/engines/mads/madsv2/core/game.cpp
index a0a72d1f8ac..0952d5d85d9 100644
--- a/engines/mads/madsv2/core/game.cpp
+++ b/engines/mads/madsv2/core/game.cpp
@@ -24,6 +24,7 @@
#include "mads/madsv2/core/game.h"
#include "mads/madsv2/core/mads.h"
#include "mads/madsv2/core/attr.h"
+#include "mads/madsv2/core/conv.h"
#include "mads/madsv2/core/lib.h"
#include "mads/madsv2/core/kernel.h"
#include "mads/madsv2/core/keys.h"
@@ -1906,160 +1907,78 @@ static void game_handle_command() {
kernel_trigger_in = kernel.trigger;
-#ifdef debug_enable_logfiles
-#define LOGFILE_NONE 0
-#define LOGFILE_ROOM_PARSER 1
-#define LOGFILE_SECTION_PARSER 2
-#define LOGFILE_GLOBAL_PARSER 3
-#define LOGFILE_ROOM_ERROR 4
-#define LOGFILE_SECTION_ERROR 5
-#define LOGFILE_GLOBAL_ERROR 6
- int logfile_handled_level = LOGFILE_NONE;
- char temp1[20];
- char temp2[80];
-#endif
-
- /* pl if (conv_control.running >= 0) {
+ if (conv_control.running >= 0) {
player.look_around = false;
if ((conv_control.status == CONV_STATUS_WAIT_AUTO) ||
(conv_control.status == CONV_STATUS_WAIT_ENTRY)) {
player.commands_allowed = false;
}
}
- */
handled_this_one = false;
- if (kernel.trigger) player.command_ready = true;
+ if (kernel.trigger)
+ player.command_ready = true;
kernel.trigger_setup_mode = KERNEL_TRIGGER_PARSER;
- if (kernel.trigger && (kernel.trigger_mode == KERNEL_TRIGGER_PARSER) && player.command_error) {
+ if (kernel.trigger && (kernel.trigger_mode == KERNEL_TRIGGER_PARSER) &&
+ player.command_error) {
error_report(ERROR_ORPHANED_TRIGGER, WARNING, MODULE_KERNEL, kernel.trigger, 0);
}
- if ((player.command_ready || kernel.trigger /*|| ((global[4] >= 0) && player.command_ready)*/) &&
- (!player.command_error)) {
-
+ if (!player.command_error &&
+ (player.command_ready || kernel.trigger)) {
game_exec_function(room_parser_code_pointer);
handled_this_one = !player.command_ready;
-#ifdef debug_enable_logfiles
- if (!player.command_ready) logfile_handled_level = LOGFILE_ROOM_PARSER;
-#endif
}
- /* pl if (conv_control.running >= 0) {
+ if (conv_control.running >= 0) {
player.command_ready = false;
goto done;
- }
- */
+ }
- if (player.command_ready || kernel.trigger /*|| ((global[4] >= 0) && player.command_ready)*/) {
+ if (player.command_ready || kernel.trigger) {
game_exec_function(section_parser_code_pointer);
handled_this_one = !player.command_ready;
-#ifdef debug_enable_logfiles
- if (!player.command_ready) logfile_handled_level = LOGFILE_SECTION_PARSER;
-#endif
}
- if ((player.command_ready || kernel.trigger /*|| ((global[4] >= 0) && player.command_ready)*/) &&
+ if ((player.command_ready || kernel.trigger) &&
(!handled_this_one) && (!player.command_error)) {
global_parser_code();
-#ifdef debug_enable_logfiles
- if (!player.command_ready) logfile_handled_level = LOGFILE_GLOBAL_PARSER;
-#endif
}
-
- /* if (global[4] >= 0) */
- /* player.command_ready = false; */
-
if (player.look_around) goto done;
if (player.command_ready) {
player.command_error = true;
game_exec_function(room_error_code_pointer);
-#ifdef debug_enable_logfiles
- if (!player.command_ready) logfile_handled_level = LOGFILE_ROOM_ERROR;
-#endif
}
if (player.command_ready) {
player.command_error = true;
game_exec_function(section_error_code_pointer);
-#ifdef debug_enable_logfiles
- if (!player.command_ready) logfile_handled_level = LOGFILE_SECTION_ERROR;
-#endif
}
if (player.command_ready) {
global_error_code();
-#ifdef debug_enable_logfiles
- logfile_handled_level = LOGFILE_GLOBAL_ERROR;
-#endif
}
-
done:
player.command_ready = false;
-#ifdef debug_enable_logfiles
- if ((!kernel.trigger) && (inter_input_mode == INTER_BUILDING_SENTENCES) && logfile_enabled) {
- Common::strcpy_s(temp2, "ROOM");
- temp1[0] = 0;
- env_catint(temp1, room_id, 3);
- Common::strcat_s(temp2, temp1);
- Common::strcat_s(temp2, ".LOG");
- logfile_handle = fopen(temp2, "at");
- if (logfile_handle != NULL) {
- if (player.command_error) {
- Common::strcpy_s(temp1, "ERROR ");
- } else {
- Common::strcpy_s(temp1, "Valid ");
- }
- switch (logfile_handled_level) {
- case LOGFILE_ROOM_PARSER:
- Common::strcpy_s(temp2, "room parser) ");
- break;
- case LOGFILE_SECTION_PARSER:
- Common::strcpy_s(temp2, "sect. parser) ");
- break;
- case LOGFILE_GLOBAL_PARSER:
- Common::strcpy_s(temp2, "global parser)");
- break;
- case LOGFILE_ROOM_ERROR:
- Common::strcpy_s(temp2, "room error) ");
- break;
- case LOGFILE_SECTION_ERROR:
- Common::strcpy_s(temp2, "sect. error) ");
- break;
- case LOGFILE_GLOBAL_ERROR:
- Common::strcpy_s(temp2, "global error) ");
- break;
- case LOGFILE_NONE:
- default:
- Common::strcpy_s(temp2, "NOTHING) ");
- break;
- }
- fprintf(logfile_handle, "%s (by: %s \"%s\"\n", temp1, temp2, player.sentence);
- fclose(logfile_handle);
- }
- }
-#endif
-
if (kernel.trigger_mode == KERNEL_TRIGGER_PARSER) {
if (kernel.trigger == kernel_trigger_in) {
kernel.trigger = 0;
}
}
- /* pl if (conv_control.running >= 0) {
+ if (conv_control.running >= 0) {
if ((conv_control.status == CONV_STATUS_WAIT_AUTO) ||
- (conv_control.status == CONV_STATUS_WAIT_ENTRY)) {
- conv_update(true);
+ (conv_control.status == CONV_STATUS_WAIT_ENTRY)) {
+ conv_update(true);
}
- }
- */
+ }
}
diff --git a/engines/mads/madsv2/phantom/conv.h b/engines/mads/madsv2/phantom/conv.h
index b8e01baa0b7..b7d4b5cf0fb 100644
--- a/engines/mads/madsv2/phantom/conv.h
+++ b/engines/mads/madsv2/phantom/conv.h
@@ -304,51 +304,6 @@ enum {
conv027_exit_a_a = 7
};
-struct ConvData {
- int16 node_count;
- int16 dialog_count;
- int16 message_count;
- int16 text_line_count;
- int16 num_variables;
-
- int16 max_imports;
- int16 speaker_count;
- char speaker_portraits[5][16];
- int16 speaker_frame[5];
- char speech_file[14];
- uint32 text_length;
-
- uint32 commands_length;
- void *text_ptr;
- void *scripts_ptr;
- void *nodes_ptr;
- void *dialogs_ptr;
- void *messages_ptr;
- void *text_lines_ptr;
-};
-
-struct ConvControl {
- int running;
-};
-
-extern int conv_restore_running;
-extern ConvControl conv_control;
-extern int *conv_my_next_start;
-
-extern void conv_system_init();
-extern void conv_system_cleanup();
-
-extern void conv_get(int convNum);
-extern void conv_run(int convNum);
-extern void conv_export_pointer(int *ptr);
-extern void conv_abort();
-extern void conv_me_trigger(int trigger);
-extern void conv_you_trigger(int trigger);
-extern int *conv_get_variable(int varNum);
-extern void conv_export_value(int varNum);
-extern void conv_hold();
-extern void conv_release();
-
} // namespace Phantom
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/mads/conv.h b/engines/mads/madsv2/phantom/mads/conv.h
new file mode 100644
index 00000000000..71cf1f2f931
--- /dev/null
+++ b/engines/mads/madsv2/phantom/mads/conv.h
@@ -0,0 +1,310 @@
+/* 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 MADS_PHANTOM_MADS_CONV_H
+#define MADS_PHANTOM_MADS_CONV_H
+
+#include "common/scummsys.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+
+enum {
+ conv001_speech_talk = 0,
+ conv001_continue_abc = 1,
+ conv002_questions_one = 2,
+ conv001_what_one = 4,
+ conv001_yesno_yes = 8,
+ conv001_everything_byebye = 10,
+ conv001_everything_copycat = 12,
+ conv001_speak_byebye = 18,
+ conv001_saytwo_1 = 22,
+ conv001_instructions_three = 24,
+ conv001_point_two_abc = 27,
+};
+
+enum {
+ conv002_sayone_abc = 1,
+ conv002_answers_job = 5,
+ conv002_answers_please = 6,
+ conv002_answers_house = 8,
+ conv002_answers_go_on = 9,
+ conv002_answers_prison = 10,
+ conv002_answers_building = 11,
+ conv002_answers_catacombs = 12,
+ conv002_interrogate_mishap = 15,
+ conv002_interrogate_chandelier = 16,
+ conv002_interrogate_phantom = 19,
+ conv002_interrogate_giry = 22,
+ conv002_nomore_first = 25,
+ conv002_saytwo_abc = 26,
+};
+
+enum {
+ conv003_bon_jour_hello = 0,
+ conv003_first_howdy = 1,
+ conv003_second_aloha = 2,
+ conv003_name_i_am = 3,
+ conv003_name_form = 4,
+ conv003_name_oops = 5,
+ conv003_adios_byebye = 6,
+ conv003_nomore_byebye = 7,
+ conv003_questions_three = 10,
+ conv003_knowghost_see = 13,
+ conv003_knowghost_look = 14,
+ conv003_return_dreams = 15,
+ conv003_return_she = 16,
+ conv003_return_giry = 18,
+ conv003_return_byebye = 23,
+ conv003_yourself_byebye = 27
+};
+
+enum {
+ conv004_bon_jour_hello = 0,
+ conv004_who_who_are = 1,
+ conv004_monsieur_again = 2,
+ conv004_name_raoul = 3,
+ conv004_name_dear = 4,
+ conv004_name_sorry = 5,
+ conv004_anything_take = 19,
+ conv004_imgone_bye = 25,
+ conv004_dontleave_help = 26,
+ conv004_promises_continue = 27,
+ conv004_promises_return = 28,
+ conv004_promises_cant = 29,
+ conv004_promises_safe = 30
+};
+
+enum {
+ conv005_nowhere_nothing = 9,
+ conv005_report_adieu = 12,
+ conv005_lets_see_b_what_have_b = 14,
+ conv005_anyone_b_sign_it_b = 17,
+ conv005_crime_missing = 20,
+ conv005_rumors_sandbag = 24,
+ conv005_rumors_accident = 25,
+ conv005_goman_abc = 35,
+ conv005_murder_b_aa = 37,
+ conv005_scream_help = 41,
+ conv005_readbook_two_abc = 42,
+ conv005_point_one_b_abc = 44
+};
+
+enum {
+ conv007_richard_intro_b = 2,
+ conv007_daaeb_intro_c = 3,
+ conv007_where_pushed = 8,
+ conv007_where_killed = 10,
+ conv007_badfall_abc = 11,
+ conv007_youraoul_abc = 12,
+ conv007_kiss_abc = 13,
+ conv007_afterkiss_abc = 14,
+ conv007_delirious_abc = 16,
+ conv007_long_abc = 20,
+ conv007_worry_abc = 21,
+ conv007_dashing_tuxedo = 22,
+ conv007_dashing_london = 23,
+ conv007_answers_abc = 24,
+ conv007_final_goaway = 25,
+ conv007_office_abc = 28,
+ conv007_solo_alone = 30,
+ conv007_pinch_wait_b_nothing_b = 32,
+};
+
+enum {
+ conv008_things_two = 4,
+ conv008_things_three = 5,
+ conv008_actions_b_b = 7,
+ conv008_actions_d_d = 13,
+ conv008_actions_byebye = 15,
+ conv008_tellabout_have = 17,
+ conv008_tellabout_rumor = 19,
+ conv008_later_final = 20,
+ conv008_nomore_first = 21,
+ conv008_var_actions_done = 24,
+ conv008_var_christine_done = 26,
+ conv008_christine_three = 27
+};
+
+enum {
+ conv009_dialogue_one = 1,
+ conv009_dialogue_paint = 2,
+ conv009_dialogue_three = 10,
+ conv009_lips_abc = 11,
+ conv009_wink_abc = 12
+};
+
+enum {
+ conv010_hasthem_abc = 4,
+ conv010_noyoudont_abc = 5,
+ conv010_unlock_b_box_5 = 7,
+ conv010_gethem_abc = 8,
+ conv010_beginning_who = 9,
+ conv010_beginning_you = 10,
+ conv010_beginning_pardon = 11,
+ conv010_nomore_abc = 13,
+ conv010_byebye_first = 14,
+ conv010_dialogue_three = 16,
+ conv010_dialogue_one = 17,
+ conv010_ghost_byebye = 19,
+ conv010_trance_b_box_5 = 21,
+ conv010_box_b_b = 23,
+ conv010_box_d_d = 25,
+ conv010_box_byebye = 40,
+ conv010_ghost_interest = 45,
+ conv010_bye_two_solong = 46
+};
+
+enum {
+ conv011_has_b_ticket = 5,
+ conv011_has_abc = 6,
+ conv011_enter_b_a = 8,
+ conv011_hasnot_abc = 9,
+ conv011_boxoffice_abc = 10,
+ conv011_enter_it_abc = 12,
+ conv011_enjoy_abc = 13,
+ conv011_five_nono = 14
+};
+
+enum {
+ conv012_hello_one = 1,
+ conv012_hello_four = 4,
+ conv012_byebye_first = 6,
+ conv012_questions_three = 7,
+ conv012_questions_one = 8,
+ conv012_seen_byebye = 10,
+ conv012_seen_mask = 12,
+ conv012_tell_byebye = 19,
+ conv012_var_questions_done = 26,
+ conv012_tell_knewhim = 29,
+ conv012_nomore_first = 30
+};
+
+enum {
+ conv013_intro_hello = 0,
+ conv013_returned_abc = 1,
+ conv013_again_abc = 2,
+ conv013_dreams_romantic = 19,
+ conv013_lovescene_openline = 21,
+ conv013_practice_first = 27,
+ conv013_biteme_b_b = 31
+};
+
+enum {
+ conv014_second_angel = 1,
+ conv014_eighth_inside = 7
+};
+
+enum {
+ conv015_daae_b_b = 5,
+ conv015_next_second = 7,
+ conv015_professional_fourth = 9,
+ conv015_damned_b_b = 11,
+ conv015_exchange_ticket = 13,
+ conv015_exchange_relief = 14,
+ conv015_exchange_opera = 15
+};
+
+enum {
+ conv016_buy_four = 4,
+ conv016_take_b_b = 6,
+ conv016_kind_five = 12,
+ conv016_money_cash = 13,
+ conv016_money_lend = 14
+};
+
+enum {
+ conv017_ticket_block = 0,
+ conv017_hasit_first = 3,
+ conv017_hasnot_first = 4
+};
+
+enum {
+ conv018_begin_first = 0,
+ conv018_adieu_bye = 4,
+ conv018_nomore_huh = 5
+};
+
+enum {
+ conv019_talk_b_b = 2,
+ conv019_exit_b_b = 12
+};
+
+enum {
+ conv020_where_a = 2,
+ conv020_exit_b_b = 5,
+ conv020_dialogue_b_b = 8,
+ conv020_bye_b_b = 14,
+ conv020_story_b_b = 22
+};
+
+enum {
+ conv021_fight_b_b = 3,
+ conv021_ending_b_b = 8,
+ conv021_outtahere_first = 10,
+ conv021_outtahere_second = 11,
+ conv021_outtahere_third = 12,
+ conv021_hasit_b_b = 14,
+ conv021_score_abc = 15,
+ conv021_score_b_b = 17,
+};
+
+enum {
+ conv022_second_next = 1,
+ conv022_resolution_florent = 6,
+ conv022_resolution_fall = 7,
+ conv022_resolution_alone = 8,
+ conv022_dead_strangled = 9,
+ conv022_object_abc = 13,
+ conv022_do_abc = 15,
+ conv022_kiss_b_b = 17,
+ conv022_kiss_abc = 18,
+ conv022_notes_hadany = 19,
+ conv022_notes_here = 20,
+ conv022_notes_chandelier = 21,
+ conv022_notes_audience = 22,
+ conv022_look_abc = 23,
+ conv022_notes_b_b = 25,
+ conv022_leave_b_b = 29
+};
+
+enum {
+ conv023_unhand_b_b = 3,
+ conv023_okay_b_b = 6,
+ conv023_okay_abc = 7,
+ conv023_die_b_b = 12
+};
+
+enum {
+ conv027_choices_one = 2,
+ conv027_choices_two = 3,
+ conv027_choices_three = 4,
+ conv027_choices_four = 5,
+ conv027_choices_five = 6,
+ conv027_exit_a_a = 7
+};
+
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/phantom/rooms/room101.cpp b/engines/mads/madsv2/phantom/rooms/room101.cpp
index 9f13ae75daa..3717eec79fd 100644
--- a/engines/mads/madsv2/phantom/rooms/room101.cpp
+++ b/engines/mads/madsv2/phantom/rooms/room101.cpp
@@ -24,7 +24,7 @@
#include "mads/madsv2/phantom/mads/words.h"
#include "mads/madsv2/phantom/rooms/section1.h"
#include "mads/madsv2/phantom/rooms/room101.h"
-#include "mads/madsv2/phantom/conv.h"
+#include "mads/madsv2/core/conv.h"
#include "mads/madsv2/core/imath.h"
#include "mads/madsv2/core/camera.h"
#include "mads/madsv2/core/matte.h"
diff --git a/engines/mads/madsv2/phantom/rooms/room103.cpp b/engines/mads/madsv2/phantom/rooms/room103.cpp
index 121259401e3..a7670feb8ea 100644
--- a/engines/mads/madsv2/phantom/rooms/room103.cpp
+++ b/engines/mads/madsv2/phantom/rooms/room103.cpp
@@ -32,7 +32,7 @@
#include "mads/madsv2/phantom/mads/sounds.h"
#include "mads/madsv2/phantom/mads/text.h"
#include "mads/madsv2/phantom/mads/inventory.h"
-#include "mads/madsv2/phantom/conv.h"
+#include "mads/madsv2/core/conv.h"
#include "mads/madsv2/phantom/rooms/section1.h"
#include "mads/madsv2/phantom/rooms/room103.h"
diff --git a/engines/mads/madsv2/phantom/rooms/room104.cpp b/engines/mads/madsv2/phantom/rooms/room104.cpp
index de113c34049..431f34cc11c 100644
--- a/engines/mads/madsv2/phantom/rooms/room104.cpp
+++ b/engines/mads/madsv2/phantom/rooms/room104.cpp
@@ -27,12 +27,13 @@
#include "mads/madsv2/core/object.h"
#include "mads/madsv2/core/sound.h"
#include "mads/madsv2/core/camera.h"
+#include "mads/madsv2/core/conv.h"
#include "mads/madsv2/phantom/global.h"
#include "mads/madsv2/phantom/mads/words.h"
#include "mads/madsv2/phantom/mads/sounds.h"
#include "mads/madsv2/phantom/mads/text.h"
#include "mads/madsv2/phantom/mads/inventory.h"
-#include "mads/madsv2/phantom/conv.h"
+#include "mads/madsv2/core/conv.h"
#include "mads/madsv2/phantom/rooms/section1.h"
#include "mads/madsv2/phantom/rooms/room104.h"
diff --git a/engines/mads/madsv2/phantom/rooms/room105.cpp b/engines/mads/madsv2/phantom/rooms/room105.cpp
index 2e4b6275223..08e5117cc48 100644
--- a/engines/mads/madsv2/phantom/rooms/room105.cpp
+++ b/engines/mads/madsv2/phantom/rooms/room105.cpp
@@ -33,7 +33,7 @@
#include "mads/madsv2/phantom/mads/sounds.h"
#include "mads/madsv2/phantom/mads/speeches.h"
#include "mads/madsv2/phantom/mads/text.h"
-#include "mads/madsv2/phantom/conv.h"
+#include "mads/madsv2/core/conv.h"
#include "mads/madsv2/phantom/rooms/section1.h"
#include "mads/madsv2/phantom/rooms/room105.h"
diff --git a/engines/mads/madsv2/phantom/rooms/room106.cpp b/engines/mads/madsv2/phantom/rooms/room106.cpp
index 0c41ba9d0e1..2ebaed6da53 100644
--- a/engines/mads/madsv2/phantom/rooms/room106.cpp
+++ b/engines/mads/madsv2/phantom/rooms/room106.cpp
@@ -41,7 +41,7 @@
#include "mads/madsv2/phantom/mads/sounds.h"
#include "mads/madsv2/phantom/mads/speeches.h"
#include "mads/madsv2/phantom/mads/text.h"
-#include "mads/madsv2/phantom/conv.h"
+#include "mads/madsv2/core/conv.h"
#include "mads/madsv2/phantom/rooms/section1.h"
#include "mads/madsv2/phantom/rooms/room106.h"
diff --git a/engines/mads/madsv2/phantom/rooms/room108.cpp b/engines/mads/madsv2/phantom/rooms/room108.cpp
index 01fc0bfd40f..4728223eef4 100644
--- a/engines/mads/madsv2/phantom/rooms/room108.cpp
+++ b/engines/mads/madsv2/phantom/rooms/room108.cpp
@@ -27,11 +27,11 @@
#include "mads/madsv2/core/object.h"
#include "mads/madsv2/core/sound.h"
#include "mads/madsv2/phantom/global.h"
-#include "mads/madsv2/phantom/conv.h"
+#include "mads/madsv2/core/conv.h"
#include "mads/madsv2/phantom/mads/words.h"
#include "mads/madsv2/phantom/mads/sounds.h"
#include "mads/madsv2/phantom/mads/text.h"
-#include "mads/madsv2/phantom/conv.h"
+#include "mads/madsv2/core/conv.h"
#include "mads/madsv2/phantom/rooms/section1.h"
#include "mads/madsv2/phantom/rooms/room108.h"
diff --git a/engines/mads/madsv2/phantom/rooms/room111.cpp b/engines/mads/madsv2/phantom/rooms/room111.cpp
index 40e6576a5a0..09b44082526 100644
--- a/engines/mads/madsv2/phantom/rooms/room111.cpp
+++ b/engines/mads/madsv2/phantom/rooms/room111.cpp
@@ -26,7 +26,7 @@
#include "mads/madsv2/core/object.h"
#include "mads/madsv2/core/sound.h"
#include "mads/madsv2/phantom/global.h"
-#include "mads/madsv2/phantom/conv.h"
+#include "mads/madsv2/core/conv.h"
#include "mads/madsv2/phantom/mads/inventory.h"
#include "mads/madsv2/phantom/mads/speeches.h"
#include "mads/madsv2/phantom/mads/words.h"
diff --git a/engines/mads/madsv2/phantom/rooms/room112.cpp b/engines/mads/madsv2/phantom/rooms/room112.cpp
index 325644a1aed..a20edf372fe 100644
--- a/engines/mads/madsv2/phantom/rooms/room112.cpp
+++ b/engines/mads/madsv2/phantom/rooms/room112.cpp
@@ -27,7 +27,7 @@
#include "mads/madsv2/core/object.h"
#include "mads/madsv2/core/sound.h"
#include "mads/madsv2/phantom/global.h"
-#include "mads/madsv2/phantom/conv.h"
+#include "mads/madsv2/core/conv.h"
#include "mads/madsv2/phantom/mads/inventory.h"
#include "mads/madsv2/phantom/mads/speeches.h"
#include "mads/madsv2/phantom/mads/words.h"
diff --git a/engines/mads/madsv2/phantom/rooms/room113.cpp b/engines/mads/madsv2/phantom/rooms/room113.cpp
index 4d6a2fef1eb..a1055166a57 100644
--- a/engines/mads/madsv2/phantom/rooms/room113.cpp
+++ b/engines/mads/madsv2/phantom/rooms/room113.cpp
@@ -28,7 +28,7 @@
#include "mads/madsv2/core/sound.h"
#include "mads/madsv2/core/speech.h"
#include "mads/madsv2/phantom/global.h"
-#include "mads/madsv2/phantom/conv.h"
+#include "mads/madsv2/core/conv.h"
#include "mads/madsv2/phantom/mads/inventory.h"
#include "mads/madsv2/phantom/mads/speeches.h"
#include "mads/madsv2/phantom/mads/words.h"
diff --git a/engines/mads/madsv2/phantom/rooms/room201.cpp b/engines/mads/madsv2/phantom/rooms/room201.cpp
index 97cc65787fa..f36ffa4e1fe 100644
--- a/engines/mads/madsv2/phantom/rooms/room201.cpp
+++ b/engines/mads/madsv2/phantom/rooms/room201.cpp
@@ -27,7 +27,7 @@
#include "mads/madsv2/core/object.h"
#include "mads/madsv2/core/sound.h"
#include "mads/madsv2/phantom/global.h"
-#include "mads/madsv2/phantom/conv.h"
+#include "mads/madsv2/core/conv.h"
#include "mads/madsv2/phantom/mads/inventory.h"
#include "mads/madsv2/phantom/mads/speeches.h"
#include "mads/madsv2/phantom/mads/words.h"
diff --git a/engines/mads/madsv2/phantom/rooms/room202.cpp b/engines/mads/madsv2/phantom/rooms/room202.cpp
index b1076133022..3ce15c8a4bd 100644
--- a/engines/mads/madsv2/phantom/rooms/room202.cpp
+++ b/engines/mads/madsv2/phantom/rooms/room202.cpp
@@ -29,7 +29,7 @@
#include "mads/madsv2/core/object.h"
#include "mads/madsv2/core/sound.h"
#include "mads/madsv2/phantom/global.h"
-#include "mads/madsv2/phantom/conv.h"
+#include "mads/madsv2/core/conv.h"
#include "mads/madsv2/phantom/mads/inventory.h"
#include "mads/madsv2/phantom/mads/speeches.h"
#include "mads/madsv2/phantom/mads/words.h"
diff --git a/engines/mads/madsv2/phantom/rooms/room203.cpp b/engines/mads/madsv2/phantom/rooms/room203.cpp
index 8666ad0cd27..bda4b4826ce 100644
--- a/engines/mads/madsv2/phantom/rooms/room203.cpp
+++ b/engines/mads/madsv2/phantom/rooms/room203.cpp
@@ -28,7 +28,7 @@
#include "mads/madsv2/core/sound.h"
#include "mads/madsv2/core/speech.h"
#include "mads/madsv2/phantom/global.h"
-#include "mads/madsv2/phantom/conv.h"
+#include "mads/madsv2/core/conv.h"
#include "mads/madsv2/phantom/mads/inventory.h"
#include "mads/madsv2/phantom/mads/speeches.h"
#include "mads/madsv2/phantom/mads/words.h"
diff --git a/engines/mads/madsv2/phantom/rooms/room204.cpp b/engines/mads/madsv2/phantom/rooms/room204.cpp
index 901d9484e30..2da6c7a6102 100644
--- a/engines/mads/madsv2/phantom/rooms/room204.cpp
+++ b/engines/mads/madsv2/phantom/rooms/room204.cpp
@@ -31,7 +31,7 @@
#include "mads/madsv2/core/matte.h"
#include "mads/madsv2/core/buffer.h"
#include "mads/madsv2/phantom/global.h"
-#include "mads/madsv2/phantom/conv.h"
+#include "mads/madsv2/core/conv.h"
#include "mads/madsv2/phantom/mads/inventory.h"
#include "mads/madsv2/phantom/mads/quotes.h"
#include "mads/madsv2/phantom/mads/sounds.h"
diff --git a/engines/mads/madsv2/phantom/rooms/room205.cpp b/engines/mads/madsv2/phantom/rooms/room205.cpp
index 5cce1d2e55b..01c2f6df04c 100644
--- a/engines/mads/madsv2/phantom/rooms/room205.cpp
+++ b/engines/mads/madsv2/phantom/rooms/room205.cpp
@@ -32,7 +32,7 @@
#include "mads/madsv2/core/matte.h"
#include "mads/madsv2/core/buffer.h"
#include "mads/madsv2/phantom/global.h"
-#include "mads/madsv2/phantom/conv.h"
+#include "mads/madsv2/core/conv.h"
#include "mads/madsv2/phantom/mads/inventory.h"
#include "mads/madsv2/phantom/mads/quotes.h"
#include "mads/madsv2/phantom/mads/sounds.h"
diff --git a/engines/mads/madsv2/phantom/rooms/room206.cpp b/engines/mads/madsv2/phantom/rooms/room206.cpp
index 045358c16dc..316ae5fc19c 100644
--- a/engines/mads/madsv2/phantom/rooms/room206.cpp
+++ b/engines/mads/madsv2/phantom/rooms/room206.cpp
@@ -32,7 +32,7 @@
#include "mads/madsv2/core/matte.h"
#include "mads/madsv2/core/buffer.h"
#include "mads/madsv2/phantom/global.h"
-#include "mads/madsv2/phantom/conv.h"
+#include "mads/madsv2/core/conv.h"
#include "mads/madsv2/phantom/mads/inventory.h"
#include "mads/madsv2/phantom/mads/quotes.h"
#include "mads/madsv2/phantom/mads/sounds.h"
diff --git a/engines/mads/madsv2/phantom/rooms/room207.cpp b/engines/mads/madsv2/phantom/rooms/room207.cpp
index e286deab459..980d39fbca3 100644
--- a/engines/mads/madsv2/phantom/rooms/room207.cpp
+++ b/engines/mads/madsv2/phantom/rooms/room207.cpp
@@ -32,7 +32,7 @@
#include "mads/madsv2/core/matte.h"
#include "mads/madsv2/core/buffer.h"
#include "mads/madsv2/phantom/global.h"
-#include "mads/madsv2/phantom/conv.h"
+#include "mads/madsv2/core/conv.h"
#include "mads/madsv2/phantom/mads/inventory.h"
#include "mads/madsv2/phantom/mads/quotes.h"
#include "mads/madsv2/phantom/mads/sounds.h"
diff --git a/engines/mads/madsv2/phantom/rooms/room208.cpp b/engines/mads/madsv2/phantom/rooms/room208.cpp
index ce691b828c3..a3915bf7667 100644
--- a/engines/mads/madsv2/phantom/rooms/room208.cpp
+++ b/engines/mads/madsv2/phantom/rooms/room208.cpp
@@ -32,7 +32,7 @@
#include "mads/madsv2/core/matte.h"
#include "mads/madsv2/core/buffer.h"
#include "mads/madsv2/phantom/global.h"
-#include "mads/madsv2/phantom/conv.h"
+#include "mads/madsv2/core/conv.h"
#include "mads/madsv2/phantom/mads/inventory.h"
#include "mads/madsv2/phantom/mads/quotes.h"
#include "mads/madsv2/phantom/mads/sounds.h"
diff --git a/engines/mads/madsv2/phantom/rooms/room303.cpp b/engines/mads/madsv2/phantom/rooms/room303.cpp
index cbf078384e2..a4edad448ce 100644
--- a/engines/mads/madsv2/phantom/rooms/room303.cpp
+++ b/engines/mads/madsv2/phantom/rooms/room303.cpp
@@ -37,7 +37,7 @@
#include "mads/madsv2/phantom/mads/speeches.h"
#include "mads/madsv2/phantom/rooms/section3.h"
#include "mads/madsv2/phantom/rooms/room303.h"
-#include "mads/madsv2/phantom/conv.h"
+#include "mads/madsv2/core/conv.h"
namespace MADS {
namespace MADSV2 {
diff --git a/engines/mads/madsv2/phantom/rooms/room304.cpp b/engines/mads/madsv2/phantom/rooms/room304.cpp
index 399e5e33759..ddfc84ec84d 100644
--- a/engines/mads/madsv2/phantom/rooms/room304.cpp
+++ b/engines/mads/madsv2/phantom/rooms/room304.cpp
@@ -38,7 +38,7 @@
#include "mads/madsv2/phantom/mads/speeches.h"
#include "mads/madsv2/phantom/rooms/section3.h"
#include "mads/madsv2/phantom/rooms/room304.h"
-#include "mads/madsv2/phantom/conv.h"
+#include "mads/madsv2/core/conv.h"
namespace MADS {
namespace MADSV2 {
diff --git a/engines/mads/madsv2/phantom/rooms/room308.cpp b/engines/mads/madsv2/phantom/rooms/room308.cpp
index 57626fcf889..2e4779c9d65 100644
--- a/engines/mads/madsv2/phantom/rooms/room308.cpp
+++ b/engines/mads/madsv2/phantom/rooms/room308.cpp
@@ -31,7 +31,7 @@
#include "mads/madsv2/phantom/mads/speeches.h"
#include "mads/madsv2/phantom/rooms/section3.h"
#include "mads/madsv2/phantom/rooms/room308.h"
-#include "mads/madsv2/phantom/conv.h"
+#include "mads/madsv2/core/conv.h"
namespace MADS {
namespace MADSV2 {
diff --git a/engines/mads/madsv2/phantom/rooms/room309.cpp b/engines/mads/madsv2/phantom/rooms/room309.cpp
index 34db03f56e8..349516b6b8a 100644
--- a/engines/mads/madsv2/phantom/rooms/room309.cpp
+++ b/engines/mads/madsv2/phantom/rooms/room309.cpp
@@ -32,7 +32,7 @@
#include "mads/madsv2/phantom/mads/speeches.h"
#include "mads/madsv2/phantom/rooms/section3.h"
#include "mads/madsv2/phantom/rooms/room309.h"
-#include "mads/madsv2/phantom/conv.h"
+#include "mads/madsv2/core/conv.h"
#include "mads/madsv2/phantom/catacombs.h"
namespace MADS {
diff --git a/engines/mads/madsv2/phantom/rooms/room501.cpp b/engines/mads/madsv2/phantom/rooms/room501.cpp
index 96c1e301be4..276aac21313 100644
--- a/engines/mads/madsv2/phantom/rooms/room501.cpp
+++ b/engines/mads/madsv2/phantom/rooms/room501.cpp
@@ -28,7 +28,7 @@
#include "mads/madsv2/core/pal.h"
#include "mads/madsv2/core/sound.h"
#include "mads/madsv2/core/text.h"
-#include "mads/madsv2/phantom/conv.h"
+#include "mads/madsv2/core/conv.h"
#include "mads/madsv2/phantom/rooms/section5.h"
#include "mads/madsv2/phantom/rooms/room501.h"
#include "mads/madsv2/phantom/catacombs.h"
diff --git a/engines/mads/madsv2/phantom/rooms/room504.cpp b/engines/mads/madsv2/phantom/rooms/room504.cpp
index 475b8324c74..7eb90f33467 100644
--- a/engines/mads/madsv2/phantom/rooms/room504.cpp
+++ b/engines/mads/madsv2/phantom/rooms/room504.cpp
@@ -30,7 +30,7 @@
#include "mads/madsv2/core/sound.h"
#include "mads/madsv2/core/speech.h"
#include "mads/madsv2/core/text.h"
-#include "mads/madsv2/phantom/conv.h"
+#include "mads/madsv2/core/conv.h"
#include "mads/madsv2/phantom/mads/speeches.h"
#include "mads/madsv2/phantom/rooms/section5.h"
#include "mads/madsv2/phantom/rooms/room504.h"
diff --git a/engines/mads/madsv2/phantom/rooms/room505.cpp b/engines/mads/madsv2/phantom/rooms/room505.cpp
index e3330792567..187ccfd3e2a 100644
--- a/engines/mads/madsv2/phantom/rooms/room505.cpp
+++ b/engines/mads/madsv2/phantom/rooms/room505.cpp
@@ -28,7 +28,7 @@
#include "mads/madsv2/core/object.h"
#include "mads/madsv2/core/sound.h"
#include "mads/madsv2/core/text.h"
-#include "mads/madsv2/phantom/conv.h"
+#include "mads/madsv2/core/conv.h"
#include "mads/madsv2/phantom/rooms/section5.h"
#include "mads/madsv2/phantom/rooms/room505.h"
diff --git a/engines/mads/madsv2/phantom/rooms/room506.cpp b/engines/mads/madsv2/phantom/rooms/room506.cpp
index 8026fe82ea1..0ea0650bbbd 100644
--- a/engines/mads/madsv2/phantom/rooms/room506.cpp
+++ b/engines/mads/madsv2/phantom/rooms/room506.cpp
@@ -28,7 +28,7 @@
#include "mads/madsv2/core/pal.h"
#include "mads/madsv2/core/sound.h"
#include "mads/madsv2/core/text.h"
-#include "mads/madsv2/phantom/conv.h"
+#include "mads/madsv2/core/conv.h"
#include "mads/madsv2/phantom/rooms/section5.h"
#include "mads/madsv2/phantom/rooms/room506.h"
diff --git a/engines/mads/madsv2/phantom/rooms/section1.cpp b/engines/mads/madsv2/phantom/rooms/section1.cpp
index 36f980d91f4..6af0363659d 100644
--- a/engines/mads/madsv2/phantom/rooms/section1.cpp
+++ b/engines/mads/madsv2/phantom/rooms/section1.cpp
@@ -26,7 +26,7 @@
#include "mads/madsv2/core/pal.h"
#include "mads/madsv2/core/player.h"
#include "mads/madsv2/core/sound.h"
-#include "mads/madsv2/phantom/conv.h"
+#include "mads/madsv2/core/conv.h"
#include "mads/madsv2/phantom/global.h"
#include "mads/madsv2/phantom/mads/sounds.h"
#include "mads/madsv2/phantom/rooms/section1.h"
diff --git a/engines/mads/madsv2/phantom/rooms/section1.h b/engines/mads/madsv2/phantom/rooms/section1.h
index af7e44a7969..000cfe3a713 100644
--- a/engines/mads/madsv2/phantom/rooms/section1.h
+++ b/engines/mads/madsv2/phantom/rooms/section1.h
@@ -22,6 +22,7 @@
#ifndef MADS_PHANTOM_SECTION1_H
#define MADS_PHANTOM_SECTION1_H
+#include "mads/madsv2/phantom/mads/conv.h"
#include "mads/madsv2/phantom/global.h"
#include "mads/madsv2/phantom/mads/text.h"
#include "mads/madsv2/phantom/mads/words.h"
diff --git a/engines/mads/madsv2/phantom/rooms/section2.cpp b/engines/mads/madsv2/phantom/rooms/section2.cpp
index e58d7adb649..3d60f15c58d 100644
--- a/engines/mads/madsv2/phantom/rooms/section2.cpp
+++ b/engines/mads/madsv2/phantom/rooms/section2.cpp
@@ -26,7 +26,7 @@
#include "mads/madsv2/core/pal.h"
#include "mads/madsv2/core/player.h"
#include "mads/madsv2/core/sound.h"
-#include "mads/madsv2/phantom/conv.h"
+#include "mads/madsv2/core/conv.h"
#include "mads/madsv2/phantom/global.h"
#include "mads/madsv2/phantom/mads/sounds.h"
#include "mads/madsv2/phantom/rooms/section2.h"
diff --git a/engines/mads/madsv2/phantom/rooms/section2.h b/engines/mads/madsv2/phantom/rooms/section2.h
index 152ca751079..8f12db9520f 100644
--- a/engines/mads/madsv2/phantom/rooms/section2.h
+++ b/engines/mads/madsv2/phantom/rooms/section2.h
@@ -22,6 +22,7 @@
#ifndef MADS_PHANTOM_SECTION2_H
#define MADS_PHANTOM_SECTION2_H
+#include "mads/madsv2/phantom/mads/conv.h"
#include "mads/madsv2/phantom/global.h"
#include "mads/madsv2/phantom/mads/text.h"
#include "mads/madsv2/phantom/mads/words.h"
diff --git a/engines/mads/madsv2/phantom/rooms/section3.cpp b/engines/mads/madsv2/phantom/rooms/section3.cpp
index d5e7fa8de2e..467858608db 100644
--- a/engines/mads/madsv2/phantom/rooms/section3.cpp
+++ b/engines/mads/madsv2/phantom/rooms/section3.cpp
@@ -26,7 +26,7 @@
#include "mads/madsv2/core/pal.h"
#include "mads/madsv2/core/player.h"
#include "mads/madsv2/core/sound.h"
-#include "mads/madsv2/phantom/conv.h"
+#include "mads/madsv2/core/conv.h"
#include "mads/madsv2/phantom/global.h"
#include "mads/madsv2/phantom/mads/sounds.h"
#include "mads/madsv2/phantom/rooms/section1.h"
diff --git a/engines/mads/madsv2/phantom/rooms/section3.h b/engines/mads/madsv2/phantom/rooms/section3.h
index 8b04af43a38..17bdacc8604 100644
--- a/engines/mads/madsv2/phantom/rooms/section3.h
+++ b/engines/mads/madsv2/phantom/rooms/section3.h
@@ -22,6 +22,7 @@
#ifndef MADS_PHANTOM_SECTION3_H
#define MADS_PHANTOM_SECTION3_H
+#include "mads/madsv2/phantom/mads/conv.h"
#include "mads/madsv2/phantom/global.h"
#include "mads/madsv2/phantom/mads/text.h"
#include "mads/madsv2/phantom/mads/words.h"
diff --git a/engines/mads/madsv2/phantom/rooms/section4.cpp b/engines/mads/madsv2/phantom/rooms/section4.cpp
index 75ba96133f0..747a1a6f962 100644
--- a/engines/mads/madsv2/phantom/rooms/section4.cpp
+++ b/engines/mads/madsv2/phantom/rooms/section4.cpp
@@ -26,7 +26,7 @@
#include "mads/madsv2/core/pal.h"
#include "mads/madsv2/core/player.h"
#include "mads/madsv2/core/sound.h"
-#include "mads/madsv2/phantom/conv.h"
+#include "mads/madsv2/core/conv.h"
#include "mads/madsv2/phantom/global.h"
#include "mads/madsv2/phantom/mads/sounds.h"
#include "mads/madsv2/phantom/rooms/section4.h"
diff --git a/engines/mads/madsv2/phantom/rooms/section4.h b/engines/mads/madsv2/phantom/rooms/section4.h
index 47f0c789d56..1ce468d7a76 100644
--- a/engines/mads/madsv2/phantom/rooms/section4.h
+++ b/engines/mads/madsv2/phantom/rooms/section4.h
@@ -22,6 +22,7 @@
#ifndef MADS_PHANTOM_SECTION4_H
#define MADS_PHANTOM_SECTION4_H
+#include "mads/madsv2/phantom/mads/conv.h"
#include "mads/madsv2/phantom/global.h"
#include "mads/madsv2/phantom/mads/text.h"
#include "mads/madsv2/phantom/mads/words.h"
diff --git a/engines/mads/madsv2/phantom/rooms/section5.cpp b/engines/mads/madsv2/phantom/rooms/section5.cpp
index 3d0f282bef5..1d3770525ab 100644
--- a/engines/mads/madsv2/phantom/rooms/section5.cpp
+++ b/engines/mads/madsv2/phantom/rooms/section5.cpp
@@ -26,7 +26,7 @@
#include "mads/madsv2/core/pal.h"
#include "mads/madsv2/core/player.h"
#include "mads/madsv2/core/sound.h"
-#include "mads/madsv2/phantom/conv.h"
+#include "mads/madsv2/core/conv.h"
#include "mads/madsv2/phantom/global.h"
#include "mads/madsv2/phantom/mads/sounds.h"
#include "mads/madsv2/phantom/rooms/section5.h"
diff --git a/engines/mads/madsv2/phantom/rooms/section5.h b/engines/mads/madsv2/phantom/rooms/section5.h
index f4b7c4255bd..6533aea7b4e 100644
--- a/engines/mads/madsv2/phantom/rooms/section5.h
+++ b/engines/mads/madsv2/phantom/rooms/section5.h
@@ -22,6 +22,7 @@
#ifndef MADS_PHANTOM_SECTION5_H
#define MADS_PHANTOM_SECTION5_H
+#include "mads/madsv2/phantom/mads/conv.h"
#include "mads/madsv2/phantom/mads/inventory.h"
#include "mads/madsv2/phantom/mads/quotes.h"
#include "mads/madsv2/phantom/mads/sounds.h"
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index d61d2712f7f..5c040c18149 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -69,6 +69,7 @@ MODULE_OBJS += \
madsv2/core/camera.o \
madsv2/core/color.o \
madsv2/core/config.o \
+ madsv2/core/conv.o \
madsv2/core/copy.o \
madsv2/core/cursor.o \
madsv2/core/cycle.o \
@@ -178,7 +179,6 @@ MODULE_OBJS += \
madsv2/phantom/rooms/room506.o \
madsv2/phantom/phantom.o \
madsv2/phantom/catacombs.o \
- madsv2/phantom/conv.o \
madsv2/phantom/global.o \
madsv2/phantom/main_menu.o \
madsv2/phantom/main.o \
Commit: 3aa5ab8bd16e057a600d35ff88b9d446d93f4c3f
https://github.com/scummvm/scummvm/commit/3aa5ab8bd16e057a600d35ff88b9d446d93f4c3f
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:57+10:00
Commit Message:
MADS: PHANTOM: Added global daemon code
Changed paths:
engines/mads/madsv2/core/conv.cpp
engines/mads/madsv2/core/conv.h
engines/mads/madsv2/core/game.cpp
engines/mads/madsv2/engine.h
engines/mads/madsv2/phantom/phantom.cpp
engines/mads/madsv2/phantom/phantom.h
diff --git a/engines/mads/madsv2/core/conv.cpp b/engines/mads/madsv2/core/conv.cpp
index 330e61d9e1a..4aad63fdc0a 100644
--- a/engines/mads/madsv2/core/conv.cpp
+++ b/engines/mads/madsv2/core/conv.cpp
@@ -56,11 +56,9 @@ static ConvData *conv_load_data(const char *fname) {
return nullptr;
}
-
void conv_system_init() {
+ Common::fill((byte *)&conv_control, (byte *)&conv_control + sizeof(ConvControl), 0);
conv_control.running = -1;
- conv_control.slot = 0;
- conv_control.status = CONV_NONE;
Common::fill(conv_slot_indexes, conv_slot_indexes + CONV_MAX_SLOTS, 0);
Common::fill(conv_slots, conv_slots + CONV_MAX_DATA, 0);
diff --git a/engines/mads/madsv2/core/conv.h b/engines/mads/madsv2/core/conv.h
index acb98f2c8d0..eb159c073a3 100644
--- a/engines/mads/madsv2/core/conv.h
+++ b/engines/mads/madsv2/core/conv.h
@@ -60,6 +60,9 @@ struct ConvControl {
int running;
int slot;
ConvStatus status;
+ ConvStatus prior_status;
+
+ uint32 popup_clock;
};
extern int conv_restore_running;
diff --git a/engines/mads/madsv2/core/game.cpp b/engines/mads/madsv2/core/game.cpp
index 0952d5d85d9..19b466a0d57 100644
--- a/engines/mads/madsv2/core/game.cpp
+++ b/engines/mads/madsv2/core/game.cpp
@@ -1785,7 +1785,7 @@ static void game_system_maintenance() {
}
if (unparsed_key || inter_auxiliary_click) {
- /* pl conv_control.popup_clock = kernel.clock; */
+ conv_control.popup_clock = kernel.clock;
inter_auxiliary_click = false;
}
}
diff --git a/engines/mads/madsv2/engine.h b/engines/mads/madsv2/engine.h
index 558ee9b4b3a..51b5d619ba5 100644
--- a/engines/mads/madsv2/engine.h
+++ b/engines/mads/madsv2/engine.h
@@ -74,8 +74,8 @@ public:
virtual void global_init_code() = 0;
virtual void section_music(int section_num) = 0;
-
virtual void global_section_constructor() = 0;
+ virtual void global_daemon_code() = 0;
};
extern MADSV2Engine *g_engine;
diff --git a/engines/mads/madsv2/phantom/phantom.cpp b/engines/mads/madsv2/phantom/phantom.cpp
index 801e38f3f3e..46fa8376383 100644
--- a/engines/mads/madsv2/phantom/phantom.cpp
+++ b/engines/mads/madsv2/phantom/phantom.cpp
@@ -20,6 +20,7 @@
*/
#include "engines/util.h"
+#include "mads/madsv2/core/conv.h"
#include "mads/madsv2/core/env.h"
#include "mads/madsv2/core/game.h"
#include "mads/madsv2/core/himem.h"
@@ -163,10 +164,224 @@ void PhantomEngine::global_object_sprite() {
Common::strcat_s(inter_object_buf, "I");
}
+
+void PhantomEngine::stop_walker_basic() {
+ int random;
+ int count;
+ int how_many;
+
+ random = imath_random(1, 30000);
+
+ switch (player.facing) {
+ case FACING_SOUTH:
+ if (random < 500) {
+ how_many = imath_random(4, 10);
+ for (count = 0; count < how_many; count++) {
+ player_add_stop_walker((random < 250) ? 1 : 2, 0);
+ }
+ } else if (random < 750) {
+ for (count = 0; count < 4; count++) {
+ player_add_stop_walker(1, 0);
+ }
+
+ player_add_stop_walker(0, 0);
+
+ for (count = 0; count < 4; count++) {
+ player_add_stop_walker(2, 0);
+ }
+
+ player_add_stop_walker(0, 0);
+ }
+ break;
+
+ case FACING_SOUTHEAST:
+ case FACING_SOUTHWEST:
+ case FACING_NORTHEAST:
+ case FACING_NORTHWEST:
+ if (random < 150) {
+ player_add_stop_walker(-1, 0);
+ player_add_stop_walker(1, 0);
+ for (count = 0; count < 6; count++) {
+ player_add_stop_walker(0, 0);
+ }
+ }
+ break;
+
+ case FACING_EAST:
+ case FACING_WEST:
+ if (random < 250) {
+ player_add_stop_walker(-1, 0);
+ how_many = imath_random(2, 6);
+ for (count = 0; count < how_many; count++) {
+ player_add_stop_walker(2, 0);
+ }
+ player_add_stop_walker(1, 0);
+ player_add_stop_walker(0, 0);
+ player_add_stop_walker(0, 0);
+ } else if (random < 500) {
+ WRITE_LE_UINT32(&global[walker_timing], kernel.clock);
+ }
+ break;
+
+ case FACING_NORTH:
+ if (random < 250) {
+ player_add_stop_walker(-1, 0);
+ how_many = imath_random(3, 7);
+ for (count = 0; count < how_many; count++) {
+ player_add_stop_walker(2, 0);
+ }
+ player_add_stop_walker(1, 0);
+ player_add_stop_walker(0, 0);
+ }
+ break;
+
+ }
+}
+
+void PhantomEngine::stop_walker_tricks() {
+ int state;
+ int cmd;
+ int random;
+
+ state = global[walker_converse_state];
+ cmd = global[walker_converse];
+
+ global[walker_converse_now] = state;
+
+ if ((player.facing != FACING_NORTHEAST) &&
+ (player.facing != FACING_NORTHWEST)) {
+ state = CONVERSE_NONE;
+ cmd = CONVERSE_NONE;
+ }
+
+ switch (state) {
+ case CONVERSE_LEAN:
+ switch (cmd) {
+ case CONVERSE_LEAN:
+ player_add_stop_walker(3, 0);
+ break;
+
+ case CONVERSE_HAND_WAVE:
+ case CONVERSE_HAND_WAVE_2:
+ player_add_stop_walker(6, 0);
+ player_add_stop_walker(5, 0);
+ player_add_stop_walker(4, 0);
+ state = CONVERSE_HAND_WAVE;
+ break;
+
+ case CONVERSE_HAND_CHIN:
+ player_add_stop_walker(8, 0);
+ player_add_stop_walker(4, 0);
+ state = CONVERSE_HAND_CHIN;
+ break;
+
+ case CONVERSE_NONE:
+ default:
+ player_add_stop_walker(-2, 0);
+ state = CONVERSE_NONE;
+ break;
+ }
+ break;
+
+ case CONVERSE_HAND_WAVE:
+ case CONVERSE_HAND_WAVE_2:
+ switch (cmd) {
+ case CONVERSE_HAND_WAVE:
+ case CONVERSE_HAND_WAVE_2:
+ random = imath_random(1, 30000);
+
+ if (state == CONVERSE_HAND_WAVE) {
+ if (random < 2000) {
+ player_add_stop_walker(10, 0);
+ player_add_stop_walker(7, 0);
+ state = CONVERSE_HAND_WAVE_2;
+ } else {
+ player_add_stop_walker(6, 0);
+ }
+ } else {
+ if (random < 1000) {
+ player_add_stop_walker(6, 0);
+ player_add_stop_walker(7, 0);
+ state = CONVERSE_HAND_WAVE;
+ } else {
+ player_add_stop_walker(10, 0);
+ }
+ }
+ break;
+
+ case CONVERSE_LEAN:
+ case CONVERSE_HAND_CHIN:
+ case CONVERSE_NONE:
+ default:
+ player_add_stop_walker(-4, 0);
+ player_add_stop_walker(-5, 0);
+ if (state == CONVERSE_HAND_WAVE_2) {
+ player_add_stop_walker(6, 0);
+ player_add_stop_walker(7, 0);
+ }
+ state = CONVERSE_LEAN;
+ break;
+ }
+ break;
+
+ case CONVERSE_HAND_CHIN:
+ switch (cmd) {
+ case CONVERSE_HAND_CHIN:
+ player_add_stop_walker(9, 0);
+ break;
+
+ case CONVERSE_LEAN:
+ case CONVERSE_HAND_WAVE:
+ case CONVERSE_HAND_WAVE_2:
+ case CONVERSE_NONE:
+ default:
+ player_add_stop_walker(-4, 0);
+ player_add_stop_walker(-8, 0);
+ state = CONVERSE_LEAN;
+ break;
+ }
+ break;
+
+ case CONVERSE_NONE:
+ default:
+ switch (cmd) {
+ case CONVERSE_LEAN:
+ case CONVERSE_HAND_WAVE:
+ case CONVERSE_HAND_WAVE_2:
+ case CONVERSE_HAND_CHIN:
+ player_add_stop_walker(2, 0);
+ state = CONVERSE_LEAN;
+ break;
+
+ case CONVERSE_NONE:
+ default:
+ stop_walker_basic();
+ break;
+ }
+ break;
+ }
+
+ global[walker_converse] = cmd;
+ global[walker_converse_state] = state;
+}
+
void PhantomEngine::global_section_constructor() {
Phantom::global_section_constructor();
}
+void PhantomEngine::global_daemon_code() {
+ if (player.walker_visible && !global[stop_walker_disabled] && (player.commands_allowed || (conv_control.running >= 0)) && !player.walking &&
+ (player.facing == player.turn_to_facing)) {
+ if (kernel.clock >= READ_LE_INT32(&global[walker_timing])) {
+ if (!player.stop_walker_pointer) {
+ stop_walker_tricks();
+ }
+
+ WRITE_LE_INT32(&global[walker_timing], READ_LE_INT32(&global[walker_timing]) + 6);
+ }
+ }
+}
+
} // namespace Phantom
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/phantom.h b/engines/mads/madsv2/phantom/phantom.h
index 2b3e2693b2f..74ee5ea5eca 100644
--- a/engines/mads/madsv2/phantom/phantom.h
+++ b/engines/mads/madsv2/phantom/phantom.h
@@ -33,6 +33,8 @@ private:
bool _soundFlag = true;
static void global_object_sprite();
+ static void stop_walker_basic();
+ static void stop_walker_tricks();
public:
PhantomEngine(OSystem *syst, const MADSGameDescription *gameDesc) :
@@ -44,6 +46,7 @@ public:
void global_init_code() override;
void section_music(int section_num) override;
void global_section_constructor() override;
+ void global_daemon_code() override;
};
} // namespace Phantom
Commit: f17a8b0a72a83d9e8303a66a953657ebc57ddfe8
https://github.com/scummvm/scummvm/commit/f17a8b0a72a83d9e8303a66a953657ebc57ddfe8
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:57+10:00
Commit Message:
MADS: PHANTOM: Added global parser code
Changed paths:
engines/mads/madsv2/core/global.cpp
engines/mads/madsv2/engine.h
engines/mads/madsv2/phantom/mads/inventory.h
engines/mads/madsv2/phantom/mads/text.h
engines/mads/madsv2/phantom/mads/words.h
engines/mads/madsv2/phantom/phantom.cpp
engines/mads/madsv2/phantom/phantom.h
diff --git a/engines/mads/madsv2/core/global.cpp b/engines/mads/madsv2/core/global.cpp
index c556fce5946..3431879190b 100644
--- a/engines/mads/madsv2/core/global.cpp
+++ b/engines/mads/madsv2/core/global.cpp
@@ -40,15 +40,15 @@ void global_init_code() {
}
void global_daemon_code() {
- error("TODO: void global_daemon_code(void);");
+ g_engine->global_daemon_code();
}
void global_pre_parser_code() {
- error("TODO: void global_pre_parser_code(void);");
+ g_engine->global_pre_parser_code();
}
void global_parser_code() {
- error("TODO: void global_parser_code(void);");
+ g_engine->global_parser_code();
}
void global_error_code() {
diff --git a/engines/mads/madsv2/engine.h b/engines/mads/madsv2/engine.h
index 51b5d619ba5..5fb499d573c 100644
--- a/engines/mads/madsv2/engine.h
+++ b/engines/mads/madsv2/engine.h
@@ -76,6 +76,8 @@ public:
virtual void section_music(int section_num) = 0;
virtual void global_section_constructor() = 0;
virtual void global_daemon_code() = 0;
+ virtual void global_pre_parser_code() = 0;
+ virtual void global_parser_code() = 0;
};
extern MADSV2Engine *g_engine;
diff --git a/engines/mads/madsv2/phantom/mads/inventory.h b/engines/mads/madsv2/phantom/mads/inventory.h
index cacb10a1988..012d44e494e 100644
--- a/engines/mads/madsv2/phantom/mads/inventory.h
+++ b/engines/mads/madsv2/phantom/mads/inventory.h
@@ -40,6 +40,7 @@ enum {
sword = 8,
envelope = 9,
ticket = 10,
+ piece_of_paper = 11,
parchment = 12,
letter = 13,
notice = 14,
diff --git a/engines/mads/madsv2/phantom/mads/text.h b/engines/mads/madsv2/phantom/mads/text.h
index 3326da4e366..9540b96eab7 100644
--- a/engines/mads/madsv2/phantom/mads/text.h
+++ b/engines/mads/madsv2/phantom/mads/text.h
@@ -28,23 +28,46 @@ namespace MADS {
namespace MADSV2 {
namespace Phantom {
-/* Formula: text_RRR_NN = RRR * 100 + NN */
-
enum {
+ /* Globals */
text_000_29 = 29,
text_000_30 = 30,
text_000_31 = 31,
+ text_000_33 = 33,
+ text_000_34 = 34,
+ text_000_35 = 35,
+ text_000_36 = 36,
+ text_000_37 = 37,
+ text_000_38 = 38,
text_008_06 = 806,
text_008_07 = 807,
text_008_08 = 808,
+ text_008_09 = 809,
+ text_008_10 = 810,
+ text_008_11 = 811,
text_008_16 = 816,
text_008_17 = 817,
text_008_18 = 818,
text_008_19 = 819,
text_008_20 = 820,
+ text_008_23 = 823,
+ text_008_25 = 825,
+ text_008_26 = 826,
+ text_008_27 = 827,
+ text_008_28 = 828,
+ text_008_29 = 829,
+ text_008_33 = 833,
+ text_008_35 = 835,
+ text_008_36 = 836,
text_008_44 = 844,
text_008_45 = 845,
+ text_008_48 = 848,
+ text_008_49 = 849,
+
+ text_114_38 = 11438,
+ text_401_24 = 40124,
+ text_401_25 = 40125,
/* Room 101 */
text_101_10 = 10110,
diff --git a/engines/mads/madsv2/phantom/mads/words.h b/engines/mads/madsv2/phantom/mads/words.h
index fabeee4eb5c..05967b3f58c 100644
--- a/engines/mads/madsv2/phantom/mads/words.h
+++ b/engines/mads/madsv2/phantom/mads/words.h
@@ -64,6 +64,7 @@ enum {
words_dressing_screen = 48,
words_dressing_table = 49,
words_elephant_prop = 50,
+ words_envelope = 51,
words_exit = 52,
words_exit_sign = 54,
words_exit_to = 55,
@@ -106,6 +107,7 @@ enum {
words_orchestra_pit = 108,
words_painting = 109,
words_parchment = 110,
+ words_piece_of_paper = 111,
words_pipe = 112,
words_pit = 113,
words_plant = 114,
@@ -116,7 +118,9 @@ enum {
words_proscenium_arch = 119,
words_purchase_lines = 120,
words_railing = 121,
+ words_read = 122,
words_red_frame = 123,
+ words_remove = 124,
words_rope = 125,
words_rug = 126,
words_sandbag = 127,
@@ -138,6 +142,8 @@ enum {
words_ticket = 146,
words_trap_ceiling = 147,
words_trap_door = 148,
+ words_turn_off = 149,
+ words_turn_on = 150,
words_unlock = 151,
words_walk_across = 153,
words_walk_down = 154,
@@ -147,6 +153,8 @@ enum {
words_wardrobe = 158,
words_waste_basket = 159,
words_water_pipe = 160,
+ words_wear = 161,
+ words_wedding_ring = 162,
words_yellow_frame = 163,
words_prop = 164,
words_climb_up = 165,
@@ -272,6 +280,7 @@ enum {
words_Monsieur_Richard = 302,
words_Julie = 303,
words_cable_hook = 304,
+ words_attach = 305,
words_rope_with_hook = 306,
words_grapple = 307,
words_oar = 308,
diff --git a/engines/mads/madsv2/phantom/phantom.cpp b/engines/mads/madsv2/phantom/phantom.cpp
index 46fa8376383..0f80569a80a 100644
--- a/engines/mads/madsv2/phantom/phantom.cpp
+++ b/engines/mads/madsv2/phantom/phantom.cpp
@@ -27,6 +27,8 @@
#include "mads/madsv2/core/imath.h"
#include "mads/madsv2/core/inter.h"
#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/object.h"
+#include "mads/madsv2/core/text.h"
#include "mads/madsv2/phantom/phantom.h"
#include "mads/madsv2/phantom/main.h"
#include "mads/madsv2/phantom/sound_phantom.h"
@@ -382,6 +384,265 @@ void PhantomEngine::global_daemon_code() {
}
}
+void PhantomEngine::global_pre_parser_code() {
+ if (player_said_1(look) || player_said_1(throw)) {
+ player.need_to_walk = false;
+ }
+}
+
+void PhantomEngine::global_parser_code() {
+ if (room_id >= 401 && room_id <= 456) {
+ if (player_said_1(red_frame) ||
+ player_said_1(yellow_frame) ||
+ player_said_1(green_frame) ||
+ player_said_1(blue_frame)) {
+
+ if (player_said_1(put)) {
+
+ if (player_said_1(unlucky_adventurer)) {
+ text_show(text_000_35);
+ goto handled;
+
+ } else if (player_said_1(hole)) {
+ text_show(text_000_36);
+ goto handled;
+
+ } else if (player_said_1(grate)) {
+ text_show(text_000_37);
+ goto handled;
+
+ } else if (player_said_1(wall)) {
+ text_show(text_000_38);
+ goto handled;
+ }
+ }
+ }
+ }
+
+ if (player.look_around) {
+ text_show(text_008_10);
+ goto handled;
+ }
+
+ if (player_said_2(put, red_frame) ||
+ player_said_2(put, blue_frame) ||
+ player_said_2(put, yellow_frame) ||
+ player_said_2(put, green_frame)) {
+ if (player_said_1(puddle)) {
+ text_show(text_401_24);
+ } else {
+ text_show(text_401_25);
+ }
+ goto handled;
+ }
+
+ if (player_said_2(wear, wedding_ring)) {
+ if (global[ring_is_on_finger]) {
+ text_show(text_008_49);
+ } else {
+ text_show(text_008_35);
+ global[ring_is_on_finger] = true;
+ }
+ goto handled;
+ }
+
+ if (player_said_2(remove, wedding_ring)) {
+ if (!global[ring_is_on_finger]) {
+ text_show(text_008_48);
+ } else {
+ text_show(text_008_36);
+ global[ring_is_on_finger] = false;
+ }
+ goto handled;
+ }
+
+ if (player_said_2(look, archway_to_west) || player_said_2(look, archway_to_east) ||
+ player_said_2(look, archway_to_north)) {
+ text_show(text_000_34);
+ goto handled;
+ }
+
+ if (player_said_2(attack, Christine)) {
+ text_show(text_000_33);
+ goto handled;
+ }
+
+ if (player_said_2(look, key)) {
+ object_examine(key, text_008_00, 0);
+ goto handled;
+ }
+
+ if (player_said_2(look, sandbag)) {
+ object_examine(sandbag, text_008_03, 0);
+ goto handled;
+ }
+
+ if (player_said_2(look, small_note) || player_said_2(read, small_note)) {
+ object_examine(small_note, text_008_06, 2);
+ goto handled;
+ }
+
+ if (player_said_2(look, rope)) {
+ object_examine(rope, text_008_07, 0);
+ goto handled;
+ }
+
+ if (player_said_2(look, sword)) {
+ object_examine(sword, text_008_08, 0);
+ goto handled;
+ }
+
+ if (player_said_2(look, envelope) || player_said_2(read, envelope)) {
+ object_examine(envelope, text_008_09, 0);
+ goto handled;
+ }
+
+ if (player_said_2(look, ticket) || player_said_2(read, ticket)) {
+ object_examine(ticket, text_008_10, 0);
+ goto handled;
+ }
+
+ if (player_said_2(look, piece_of_paper) || player_said_2(read, piece_of_paper)) {
+ object_examine(piece_of_paper, text_008_11, 1);
+ goto handled;
+ }
+
+ if (player_said_2(look, parchment) || player_said_2(read, parchment)) {
+ object_examine(parchment, text_008_12, 3);
+ goto handled;
+ }
+
+ if (player_said_2(look, letter) || player_said_2(read, letter)) {
+ object_examine(letter, text_008_13, 4);
+ goto handled;
+ }
+
+ if (player_said_2(look, notice) || player_said_2(read, notice)) {
+ object_examine(notice, text_008_14, 5);
+ goto handled;
+ }
+
+ if (player_said_2(look, book) || player_said_2(read, book)) {
+ object_examine(book, text_008_15, 0);
+ goto handled;
+ }
+
+ if (player_said_2(look, crumpled_note) || player_said_2(read, crumpled_note)) {
+ object_examine(crumpled_note, text_008_16, 6);
+ goto handled;
+ }
+
+ if (player_said_2(look, large_note) || player_said_2(read, large_note)) {
+ object_examine(large_note, text_008_18, 7);
+ goto handled;
+ }
+
+ if (player_said_2(look, music_score) || player_said_2(read, music_score)) {
+ object_examine(music_score, text_008_20, 0);
+ goto handled;
+ }
+
+ if (player_said_2(look, wedding_ring)) {
+ object_examine(wedding_ring, text_008_21, 0);
+ goto handled;
+ }
+
+ if (player_said_2(look, cable_hook)) {
+ object_examine(cable_hook, text_008_22, 0);
+ goto handled;
+ }
+
+ if (player_said_2(look, rope_with_hook)) {
+ object_examine(rope_with_hook, text_008_23, 0);
+ goto handled;
+ }
+
+ if (player_said_2(look, oar)) {
+ object_examine(oar, text_008_24, 0);
+ goto handled;
+ }
+
+
+ if (player_said_1(look) && player_has(object_named(player_main_noun))) {
+ object_examine(oar, text_008_24, 0);
+ goto handled;
+ }
+
+ if (player_said_2(turn_on, lantern)) {
+ if ((global[lantern_status] == LANTERN_IS_ON) && !kernel.trigger) {
+ text_show(text_008_28);
+ /* lantern is already on */
+ } else {
+ switch (kernel.trigger) {
+ case 0:
+ kernel_timing_trigger(4, 1);
+ global[lantern_status] = LANTERN_IS_ON;
+ inter_spin_object(lantern);
+ break;
+
+ case 1:
+ text_show(text_008_25);
+ break;
+ }
+ }
+ goto handled;
+ }
+
+ if (player_said_2(turn_off, lantern)) {
+ if ((global[lantern_status] == LANTERN_IS_OFF) && !kernel.trigger) {
+ text_show(text_008_29);
+ /* lantern is already off */
+ } else {
+ if (section_id == 4) {
+ text_show(text_008_26);
+ /* you are in catacombs, not a good idea */
+ } else {
+ switch (kernel.trigger) {
+ case 0:
+ kernel_timing_trigger(4, 1);
+ global[lantern_status] = LANTERN_IS_OFF;
+ inter_spin_object(lantern);
+ break;
+
+ case 1:
+ text_show(text_008_27);
+ break;
+ }
+ }
+ }
+ goto handled;
+ }
+
+ if (player_said_2(open, envelope)) {
+ inter_move_object(envelope, NOWHERE);
+ inter_give_to_player(ticket);
+ inter_give_to_player(piece_of_paper);
+ text_show(text_008_33);
+ goto handled;
+ }
+
+ if (player_said_3(attach, cable_hook, rope)) {
+ if (!player_has(rope)) {
+ text_show(text_114_38);
+ } else {
+ inter_move_object(cable_hook, NOWHERE);
+ inter_move_object(rope, NOWHERE);
+ inter_give_to_player(rope_with_hook);
+ object_examine(rope_with_hook, text_008_23, 0);
+ /* text_show (text_008_23); */
+ }
+ goto handled;
+ }
+
+ goto done;
+
+handled:
+ player.command_ready = false;
+
+done:
+ ;
+}
+
} // namespace Phantom
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/phantom.h b/engines/mads/madsv2/phantom/phantom.h
index 74ee5ea5eca..f7050394c2c 100644
--- a/engines/mads/madsv2/phantom/phantom.h
+++ b/engines/mads/madsv2/phantom/phantom.h
@@ -47,6 +47,8 @@ public:
void section_music(int section_num) override;
void global_section_constructor() override;
void global_daemon_code() override;
+ void global_pre_parser_code() override;
+ void global_parser_code() override;
};
} // namespace Phantom
Commit: 7023b3c7558b927edc310d21ebcb3644c6af5682
https://github.com/scummvm/scummvm/commit/7023b3c7558b927edc310d21ebcb3644c6af5682
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:57+10:00
Commit Message:
MADS: PHANTOM: Added global_error_code
Changed paths:
engines/mads/madsv2/core/global.cpp
engines/mads/madsv2/engine.h
engines/mads/madsv2/phantom/mads/text.h
engines/mads/madsv2/phantom/phantom.cpp
engines/mads/madsv2/phantom/phantom.h
diff --git a/engines/mads/madsv2/core/global.cpp b/engines/mads/madsv2/core/global.cpp
index 3431879190b..8bcc09f0102 100644
--- a/engines/mads/madsv2/core/global.cpp
+++ b/engines/mads/madsv2/core/global.cpp
@@ -52,7 +52,7 @@ void global_parser_code() {
}
void global_error_code() {
- error("TODO: void global_error_code(void);");
+ g_engine->global_error_code();
}
void global_room_init() {
diff --git a/engines/mads/madsv2/engine.h b/engines/mads/madsv2/engine.h
index 5fb499d573c..01e0a8cb469 100644
--- a/engines/mads/madsv2/engine.h
+++ b/engines/mads/madsv2/engine.h
@@ -78,6 +78,7 @@ public:
virtual void global_daemon_code() = 0;
virtual void global_pre_parser_code() = 0;
virtual void global_parser_code() = 0;
+ virtual void global_error_code() = 0;
};
extern MADSV2Engine *g_engine;
diff --git a/engines/mads/madsv2/phantom/mads/text.h b/engines/mads/madsv2/phantom/mads/text.h
index 9540b96eab7..8bba826f270 100644
--- a/engines/mads/madsv2/phantom/mads/text.h
+++ b/engines/mads/madsv2/phantom/mads/text.h
@@ -30,6 +30,34 @@ namespace Phantom {
enum {
/* Globals */
+ text_000_01 = 1,
+ text_000_02 = 2,
+ text_000_03 = 3,
+ text_000_04 = 4,
+ text_000_05 = 5,
+ text_000_06 = 6,
+ text_000_07 = 7,
+ text_000_08 = 8,
+ text_000_09 = 9,
+ text_000_10 = 10,
+ text_000_11 = 11,
+ text_000_12 = 12,
+ text_000_13 = 13,
+ text_000_14 = 14,
+ text_000_15 = 15,
+ text_000_16 = 16,
+ text_000_17 = 17,
+ text_000_18 = 18,
+ text_000_19 = 19,
+ text_000_20 = 20,
+ text_000_21 = 21,
+ text_000_22 = 22,
+ text_000_23 = 23,
+ text_000_24 = 24,
+ text_000_25 = 25,
+ text_000_26 = 26,
+ text_000_27 = 27,
+ text_000_28 = 28,
text_000_29 = 29,
text_000_30 = 30,
text_000_31 = 31,
@@ -65,6 +93,7 @@ enum {
text_008_48 = 848,
text_008_49 = 849,
+ text_101_23 = 10123,
text_114_38 = 11438,
text_401_24 = 40124,
text_401_25 = 40125,
diff --git a/engines/mads/madsv2/phantom/phantom.cpp b/engines/mads/madsv2/phantom/phantom.cpp
index 0f80569a80a..25a3a1d67d8 100644
--- a/engines/mads/madsv2/phantom/phantom.cpp
+++ b/engines/mads/madsv2/phantom/phantom.cpp
@@ -643,6 +643,153 @@ done:
;
}
+void PhantomEngine::global_error_code() {
+ int show_me = 0;
+ int item;
+ int random;
+
+ random = imath_random(1, 1000);
+
+ if (player_said_3(put, chandelier, seats)) {
+ text_show(text_101_23);
+ goto done;
+ }
+
+ if (player_said_1(take)) {
+ item = object_named(player_main_noun);
+ if (player_has(item)) {
+ show_me = text_000_25;
+ /* player already has it */
+
+ } else {
+ if (random <= 333) {
+ show_me = text_000_01;
+ } else if (random <= 666) {
+ show_me = text_000_02;
+ } else {
+ show_me = text_000_03;
+ }
+ }
+ goto done;
+ }
+
+ if (player_said_1(push)) {
+ if (random < 750) {
+ show_me = text_000_04;
+ } else {
+ show_me = text_000_05;
+ }
+ goto done;
+ }
+
+ if (player_said_1(pull)) {
+ if (random < 750) {
+ show_me = text_000_06;
+ } else {
+ show_me = text_000_07;
+ }
+ goto done;
+ }
+
+ if (player_said_1(open)) {
+ if (random <= 500) {
+ show_me = text_000_08;
+ } else if (random <= 750) {
+ show_me = text_000_09;
+ } else {
+ show_me = text_000_10;
+ }
+ goto done;
+ }
+
+ if (player_said_1(close)) {
+ if (random <= 500) {
+ show_me = text_000_11;
+ } else if (random <= 750) {
+ show_me = text_000_12;
+ } else {
+ show_me = text_000_13;
+ }
+ goto done;
+ }
+
+ if (player_said_1(put)) {
+ item = object_named(player_main_noun);
+ if (player_has(item)) {
+ show_me = text_000_26;
+ } else if (random < 500) {
+ show_me = text_000_14;
+ } else {
+ show_me = text_000_15;
+ }
+ goto done;
+ }
+
+ if (player_said_1(talk_to)) {
+ if (random <= 500) {
+ show_me = text_000_16;
+ } else {
+ show_me = text_000_17;
+ }
+ goto done;
+ }
+
+ if (player_said_1(give)) {
+ item = object_named(player_main_noun);
+ if (player_has(item)) {
+ show_me = text_000_27;
+ } else {
+ show_me = text_000_18;
+ }
+ goto done;
+ }
+
+ if (player_said_1(throw)) {
+ item = object_named(player_main_noun);
+ if (player_has(item)) {
+ show_me = text_000_19;
+ } else {
+ show_me = text_000_28;
+ }
+ goto done;
+ }
+
+ if (player_said_1(look)) {
+ item = object_named(player_main_noun);
+ if (random <= 333) {
+ show_me = text_000_20;
+ } else if (random <= 666) {
+ show_me = text_000_21;
+ } else {
+ show_me = text_000_22;
+ }
+ goto done;
+ }
+
+ if (player_said_1(unlock) || player_said_1(lock)) {
+ if (player_said_1(door) || player_said_1(left_door) ||
+ player_said_1(middle_door) || player_said_1(right_door) ||
+ player_said_1(trap_door)) {
+ show_me = text_000_32;
+ goto done;
+ }
+ }
+
+ if (!player_said_1(walk_to) && !player_said_1(walk_across) &&
+ !player_said_1(walk_down) && !player_said_1(walk_up)) {
+ if (random < 500) {
+ show_me = text_000_23;
+ } else {
+ show_me = text_000_24;
+ }
+ goto done;
+ }
+
+
+done:
+ if (show_me) text_show(show_me);
+}
+
} // namespace Phantom
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/phantom.h b/engines/mads/madsv2/phantom/phantom.h
index f7050394c2c..3c22d78043a 100644
--- a/engines/mads/madsv2/phantom/phantom.h
+++ b/engines/mads/madsv2/phantom/phantom.h
@@ -49,6 +49,7 @@ public:
void global_daemon_code() override;
void global_pre_parser_code() override;
void global_parser_code() override;
+ void global_error_code() override;
};
} // namespace Phantom
Commit: 2d388747ed4cf51a2d88fec5c1b22a8202c13834
https://github.com/scummvm/scummvm/commit/2d388747ed4cf51a2d88fec5c1b22a8202c13834
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:58+10:00
Commit Message:
MADS: PHANTOM: Added global_room_init
Changed paths:
engines/mads/madsv2/core/game.cpp
engines/mads/madsv2/core/global.cpp
engines/mads/madsv2/engine.h
engines/mads/madsv2/phantom/phantom.cpp
engines/mads/madsv2/phantom/phantom.h
diff --git a/engines/mads/madsv2/core/game.cpp b/engines/mads/madsv2/core/game.cpp
index 19b466a0d57..3b56e0e8ba5 100644
--- a/engines/mads/madsv2/core/game.cpp
+++ b/engines/mads/madsv2/core/game.cpp
@@ -1567,7 +1567,7 @@ void game_control() {
kernel_set_interface_mode(INTER_LIMITED_SENTENCES);
game_exec_function(room_init_code_pointer);
-
+#if 0
/* paul - oh no! magic numbers! */
stamp_sprite_to_interface(BP_X, BP_Y, 1, int_sprite[fx_int_backpack]);
if (global[5]) { /* candle_is_on */
@@ -1580,7 +1580,7 @@ void game_control() {
if (room_id != 199) { /* Taranjeet, if this is not journal room */
stamp_sprite_to_interface(JOURNAL_X, JOURNAL_Y, 1, int_sprite[fx_int_journal]);
}
-
+#endif
scr_work.data = buffer_pointer(&scr_main, 0, viewing_at_y);
if (viewing_at_y) {
buffer_rect_fill(scr_main, 0, 0, video_x, viewing_at_y, 0);
diff --git a/engines/mads/madsv2/core/global.cpp b/engines/mads/madsv2/core/global.cpp
index 8bcc09f0102..3673f65f40c 100644
--- a/engines/mads/madsv2/core/global.cpp
+++ b/engines/mads/madsv2/core/global.cpp
@@ -56,7 +56,7 @@ void global_error_code() {
}
void global_room_init() {
- error("TODO: void global_room_init(void);");
+ g_engine->global_room_init();
}
void global_verb_filter() {
diff --git a/engines/mads/madsv2/engine.h b/engines/mads/madsv2/engine.h
index 01e0a8cb469..db21c543f17 100644
--- a/engines/mads/madsv2/engine.h
+++ b/engines/mads/madsv2/engine.h
@@ -79,6 +79,7 @@ public:
virtual void global_pre_parser_code() = 0;
virtual void global_parser_code() = 0;
virtual void global_error_code() = 0;
+ virtual void global_room_init() = 0;
};
extern MADSV2Engine *g_engine;
diff --git a/engines/mads/madsv2/phantom/phantom.cpp b/engines/mads/madsv2/phantom/phantom.cpp
index 25a3a1d67d8..e2c6afb21cb 100644
--- a/engines/mads/madsv2/phantom/phantom.cpp
+++ b/engines/mads/madsv2/phantom/phantom.cpp
@@ -28,6 +28,7 @@
#include "mads/madsv2/core/inter.h"
#include "mads/madsv2/core/kernel.h"
#include "mads/madsv2/core/object.h"
+#include "mads/madsv2/core/pal.h"
#include "mads/madsv2/core/text.h"
#include "mads/madsv2/phantom/phantom.h"
#include "mads/madsv2/phantom/main.h"
@@ -790,6 +791,13 @@ done:
if (show_me) text_show(show_me);
}
+void PhantomEngine::global_room_init() {
+ pal_change_color(16, 45, 45, 55);
+ pal_change_color(17, 30, 30, 45);
+ global[walker_converse] = 0;
+ global[walker_converse_state] = 0;
+}
+
} // namespace Phantom
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/phantom.h b/engines/mads/madsv2/phantom/phantom.h
index 3c22d78043a..d3994c95b42 100644
--- a/engines/mads/madsv2/phantom/phantom.h
+++ b/engines/mads/madsv2/phantom/phantom.h
@@ -50,6 +50,7 @@ public:
void global_pre_parser_code() override;
void global_parser_code() override;
void global_error_code() override;
+ void global_room_init() override;
};
} // namespace Phantom
Commit: 8d2aad7c70060f6d556430ecdd9fa830f30cf42f
https://github.com/scummvm/scummvm/commit/8d2aad7c70060f6d556430ecdd9fa830f30cf42f
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:58+10:00
Commit Message:
MADS: PHANTOM: Added global_verb_filter
Changed paths:
engines/mads/madsv2/core/global.cpp
engines/mads/madsv2/engine.h
diff --git a/engines/mads/madsv2/core/global.cpp b/engines/mads/madsv2/core/global.cpp
index 3673f65f40c..e806f83a3d9 100644
--- a/engines/mads/madsv2/core/global.cpp
+++ b/engines/mads/madsv2/core/global.cpp
@@ -60,7 +60,7 @@ void global_room_init() {
}
void global_verb_filter() {
- error("TODO: void global_verb_filter(void);");
+ g_engine->global_verb_filter();
}
void global_sound_driver() {
diff --git a/engines/mads/madsv2/engine.h b/engines/mads/madsv2/engine.h
index db21c543f17..4670b4ceed0 100644
--- a/engines/mads/madsv2/engine.h
+++ b/engines/mads/madsv2/engine.h
@@ -80,6 +80,7 @@ public:
virtual void global_parser_code() = 0;
virtual void global_error_code() = 0;
virtual void global_room_init() = 0;
+ virtual void global_verb_filter() {}
};
extern MADSV2Engine *g_engine;
Commit: 73fd108173257511a0a9ed85babe12940660c19e
https://github.com/scummvm/scummvm/commit/73fd108173257511a0a9ed85babe12940660c19e
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:58+10:00
Commit Message:
MADS: PHANTOM: Adding config code
Changed paths:
engines/mads/madsv2/core/config.cpp
engines/mads/madsv2/core/config.h
engines/mads/madsv2/core/global.cpp
engines/mads/madsv2/engine.cpp
diff --git a/engines/mads/madsv2/core/config.cpp b/engines/mads/madsv2/core/config.cpp
index cad76ad3f94..cc5eedcda6a 100644
--- a/engines/mads/madsv2/core/config.cpp
+++ b/engines/mads/madsv2/core/config.cpp
@@ -19,12 +19,115 @@
*
*/
+#include "common/config-manager.h"
#include "mads/madsv2/core/config.h"
+#include "mads/madsv2/core/env.h"
+#include "mads/madsv2/core/inter.h"
+#include "mads/madsv2/core/kernel.h"
namespace MADS {
namespace MADSV2 {
-ConfigFile config_file;
+ConfigFile config_file = { 0, 0x220,
+ 0, 0x220, 7, 1,
+ true, true, 1,
+ 0, 0,
+ 0, 0,
+ 0, true,
+ 0, 0,
+ false, 'D',
+ false };
+
+void read_config_file() {
+ ConfMan.registerDefault("music_mute", false);
+ ConfMan.registerDefault("sfx_mute", false);
+ ConfMan.registerDefault("speech_mute", false);
+
+ ConfMan.registerDefault("interface_hotspots", INTERFACE_BRAINDEAD);
+ ConfMan.registerDefault("inventory_mode", INVENTORY_SQUAT);
+ ConfMan.registerDefault("animated_interface", true);
+ ConfMan.registerDefault("show_speech_boxes", true);
+
+ config_file.music_flag = !ConfMan.getBool("music_mute");
+ config_file.sound_flag = !ConfMan.getBool("sfx_mute");
+ config_file.speech_flag = !ConfMan.getBool("speech_mute");
+
+ config_file.interface_hotspots = ConfMan.getInt("interface_hotspots");
+ config_file.inventory_mode = ConfMan.getInt("inventory_spinning");
+ config_file.animated_interface = ConfMan.getBool("animated_interface");
+
+ config_file.quotes_enabled = ConfMan.getBool("quotes_enabled");
+ config_file.screen_fade = ConfMan.getBool("screen_fade");
+ config_file.panning_speed = ConfMan.getBool("panning_speed");
+
+ config_file.show_speech_boxes = ConfMan.getBool("show_speech_boxes");
+}
+
+void write_config_file() {
+ ConfMan.setBool("music_mute", !config_file.music_flag);
+ ConfMan.setBool("sfx_mute", !config_file.sound_flag);
+ ConfMan.setBool("speech_mute", !config_file.speech_flag);
+
+ ConfMan.setInt("interface_hotspots", config_file.interface_hotspots);
+ ConfMan.setInt("inventory_spinning", config_file.inventory_mode);
+ ConfMan.setBool("animated_interface", config_file.animated_interface);
+
+ ConfMan.setBool("quotes_enabled", config_file.quotes_enabled);
+ ConfMan.setBool("screen_fade", config_file.screen_fade);
+ ConfMan.setBool("panning_speed", config_file.panning_speed);
+
+ ConfMan.setBool("show_speech_boxes", config_file.show_speech_boxes);
+ ConfMan.flushToDisk();
+}
+
+void global_load_config_parameters() {
+ inter_report_hotspots = (config_file.interface_hotspots == INTERFACE_BRAINDEAD);
+ inter_spinning_objects = true;
+ inter_animation_running = true;
+
+ kernel_panning_speed = config_file.panning_speed;
+ kernel_screen_fade = config_file.screen_fade;
+#if 0
+ kernel.sound_card = sound_get_letter(config_file.sound_card_type);
+
+ music_on = config_file.music_flag;
+ sound_on = config_file.sound_flag;
+ speech_on = config_file.speech_flag;
+
+ int mem = config_file.high_memory_mode;
+
+ if ((mem == MEMORY_NO_EMS) || (mem == MEMORY_CONVENTIONAL)) {
+ himem_preload_ems_disabled = true;
+ }
+
+ if ((mem == MEMORY_NO_XMS) || (mem == MEMORY_CONVENTIONAL)) {
+ himem_preload_xms_disabled = true;
+ }
+
+ if (config_file.speech_version_installed) {
+ speech_system_requested = true;
+ }
+#endif
+ if (config_file.cd_version_installed) {
+ env_search_cd = true;
+ env_cd_drive = (char)config_file.cd_drive;
+ }
+}
+
+void global_unload_config_parameters(void) {
+ config_file.interface_hotspots = inter_report_hotspots ? INTERFACE_BRAINDEAD : INTERFACE_MACINTOSH;
+
+ config_file.panning_speed = kernel_panning_speed;
+ config_file.screen_fade = kernel_screen_fade;
+#if 0
+ config_file.music_flag = music_on;
+ config_file.sound_flag = sound_on;
+ config_file.speech_flag = speech_on;
+
+ config_file.sound_card_address = sound_board_address;
+ config_file.sound_card_type = sound_board_type;
+#endif
+}
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/core/config.h b/engines/mads/madsv2/core/config.h
index 7e2947b01dd..9eaf604c513 100644
--- a/engines/mads/madsv2/core/config.h
+++ b/engines/mads/madsv2/core/config.h
@@ -27,20 +27,26 @@
namespace MADS {
namespace MADSV2 {
-/* #define CONFIG_FILE_NAME "CONFIG.REX" */
-
-#define INTERFACE_MACINTOSH 0 /* Macintosh interface */
-#define INTERFACE_BRAINDEAD 1 /* The "other" interface */
+enum {
+ INTERFACE_MACINTOSH = 0, /* Macintosh interface */
+ INTERFACE_BRAINDEAD = 1 /* The "other" interface */
+};
-#define INVENTORY_SPINNING 0 /* Inventory objects spin */
-#define INVENTORY_SQUAT 1 /* Inventory objects squat */
+enum {
+ INVENTORY_SPINNING = 0, /* Inventory objects spin */
+ INVENTORY_SQUAT = 1 /* Inventory objects squat */
+};
-#define INTERFACE_ANIMATED 0 /* Interface animations on */
-#define INTERFACE_STILL 1 /* Interface still */
+enum {
+ INTERFACE_ANIMATED = 0, /* Interface animations on */
+ INTERFACE_STILL = 1 /* Interface still */
+};
-#define SCREEN_FADE_SMOOTH 0 /* Smooth fade (thru black) */
-#define SCREEN_FADE_MEDIUM 1 /* Medium fade (Detmar-o-matic) */
-#define SCREEN_FADE_FAST 2 /* Fast fade (thru black) */
+enum {
+ SCREEN_FADE_SMOOTH = 0, /* Smooth fade (thru black) */
+ SCREEN_FADE_MEDIUM = 1, /* Medium fade (Detmar-o-matic) */
+ SCREEN_FADE_FAST = 2 /* Fast fade (thru black) */
+};
#define MEMORY_ALL 0 /* Use all available memory */
#define MEMORY_NO_EMS 1 /* Do not use EMS memory */
@@ -66,6 +72,7 @@ struct ConfigFile {
int music_flag; /* Music on/off */
int sound_flag; /* Sound on/off */
int interface_hotspots; /* Easy / Standard */
+
int inventory_mode; /* Spinning / Still */
int animated_interface; /* On / Off */
@@ -100,6 +107,11 @@ extern ConfigFile config_file;
#define music_off (!config_file.music_flag)
#define sound_off (!config_file.sound_flag)
+extern void read_config_file();
+extern void write_config_file();
+extern void global_load_config_parameters();
+extern void global_unload_config_parameters();
+
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/core/global.cpp b/engines/mads/madsv2/core/global.cpp
index e806f83a3d9..78734f1abb2 100644
--- a/engines/mads/madsv2/core/global.cpp
+++ b/engines/mads/madsv2/core/global.cpp
@@ -20,6 +20,7 @@
*/
#include "common/textconsole.h"
+#include "mads/madsv2/core/config.h"
#include "mads/madsv2/core/global.h"
#include "mads/madsv2/engine.h"
@@ -88,19 +89,11 @@ void global_emergency_save() {
}
void global_read_config_file() {
- error("TODO: void global_read_config_file(void);");
+ read_config_file();
}
void global_write_config_file() {
- error("TODO: void global_write_config_file(void);");
-}
-
-void global_load_config_parameters() {
- error("TODO: void global_load_config_parameters(void);");
-}
-
-void global_unload_config_parameters() {
- error("TODO: void global_unload_config_parameters(void);");
+ write_config_file();
}
int global_copy_verify() {
diff --git a/engines/mads/madsv2/engine.cpp b/engines/mads/madsv2/engine.cpp
index cd6df8b204d..5e8368b5acd 100644
--- a/engines/mads/madsv2/engine.cpp
+++ b/engines/mads/madsv2/engine.cpp
@@ -124,6 +124,5 @@ uint32 MADSV2Engine::getMillis() {
return g_system->getMillis();
}
-
} // namespace MADSV2
} // namespace MADS
Commit: c71754606f043e28da5c63a9fd019912180bebe4
https://github.com/scummvm/scummvm/commit/c71754606f043e28da5c63a9fd019912180bebe4
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:59+10:00
Commit Message:
MADS: PHANTOM: Implemented Phantom version of global_copy_verify
Changed paths:
engines/mads/madsv2/core/copy.cpp
engines/mads/madsv2/core/copy.h
engines/mads/madsv2/core/global.cpp
engines/mads/madsv2/core/global.h
engines/mads/madsv2/phantom/phantom.cpp
diff --git a/engines/mads/madsv2/core/copy.cpp b/engines/mads/madsv2/core/copy.cpp
index 23f5078b73f..9999f08ca41 100644
--- a/engines/mads/madsv2/core/copy.cpp
+++ b/engines/mads/madsv2/core/copy.cpp
@@ -19,6 +19,7 @@
*
*/
+#include "common/config-manager.h"
#include "common/file.h"
#include "mads/madsv2/core/copy.h"
#include "mads/madsv2/core/imath.h"
@@ -35,20 +36,17 @@
namespace MADS {
namespace MADSV2 {
-extern char global_release_version[10];
+#define NUM_TEXT_LINES 10
-char happy_file_name[12] = "XSOUND.000";
-bool popup_vomitation_flag = false;
+extern char global_release_version[10];
void CopyProt::load(Common::SeekableReadStream *src) {
- manual = src->readByte();
- page = src->readUint16LE();
- line = src->readUint16LE();
- word_number = src->readUint16LE();
+ src->readMultipleLE(manual, page, line, word_number);
src->read(say, 20);
}
-void copy_mangle(CopyProt *copy_prot) {
+
+static void copy_mangle(CopyProt *copy_prot) {
int count;
byte *dog;
@@ -60,28 +58,25 @@ void copy_mangle(CopyProt *copy_prot) {
}
}
-int copy_load(CopyProt *copy_prot) {
+
+static int copy_load(CopyProt *copy_prot) {
int error_flag = true;
int num_items;
int item;
int seek_dog;
- Common::SeekableReadStream *handle = NULL;
+ Common::SeekableReadStream *handle;
handle = env_open("*HOGANUS.DAT", "rb");
if (handle == NULL) goto done;
num_items = handle->readUint16LE();
item = imath_random(1, num_items);
- if (item < 1) item = 1;
- if (item > num_items) item = num_items;
- seek_dog = (item - 1) * sizeof(CopyProt);
- if (seek_dog) {
+ seek_dog = (item - 1) * CopyProt::SIZE;
+ if (seek_dog)
handle->seek(seek_dog, SEEK_CUR);
- }
copy_prot->load(handle);
-
copy_mangle(copy_prot);
error_flag = false;
@@ -91,83 +86,84 @@ done:
return error_flag;
}
-int copy_pop_and_ask(void) {
+static int copy_pop_and_ask() {
int error_flag = COPY_FAIL;
int result;
int count;
+ long mem_to_get;
char work_buf[80];
char page_buf[10];
char line_buf[10];
char word_buf[10];
char entry_buf[80];
+ char *read_buf[NUM_TEXT_LINES];
+ char *load_buffer = NULL;
CopyProt copy_prot;
+ Common::SeekableReadStream *handle = NULL;
- popup_vomitation_flag = false; /* Allow keep of first letter */
+ box_param.erase_on_first = false; /* Allow keep of first letter */
if (copy_load(©_prot)) goto finish;
+ mem_to_get = 80 * NUM_TEXT_LINES;
+ load_buffer = (char *)mem_get(mem_to_get);
+ if (load_buffer == NULL) goto finish;
+
+ handle = env_open("*LANGUAGE.DAT", "rb");
+ if (handle == NULL) goto finish;
+
+ for (count = 0; count < NUM_TEXT_LINES; count++) {
+ read_buf[count] = load_buffer + (count * 80);
+ if (!fileio_fread_f(read_buf[count], 80, 1, handle)) goto finish;
+ }
+
+ delete handle;
+ handle = NULL;
+
mads_itoa(copy_prot.page, page_buf, 10);
mads_itoa(copy_prot.line, line_buf, 10);
mads_itoa(copy_prot.word_number, word_buf, 10);
for (count = 0; (count < COPY_TRIES_ALLOWED); count++) {
- if (popup_create(font_inter, 32, POPUP_CENTER, POPUP_CENTER))
- goto finish;
+
+ if (popup_create(popup_estimate_pieces(26), POPUP_CENTER, POPUP_CENTER)) goto finish;
if (!count) {
- Common::strcpy_s(work_buf, "REX NEBULAR version ");
+ popup_center_string(read_buf[0], false);
+ Common::strcpy_s(work_buf, read_buf[1]);
+ Common::strcat_s(work_buf, " ");
Common::strcat_s(work_buf, global_release_version);
- popup_center_string(work_buf, true);
- popup_write_string("\n");
- popup_center_string("(Copy Protection, for your convenience)", false);
+ popup_center_string(work_buf, false);
+ popup_next_line();
} else {
- popup_center_string("ANSWER INCORRECT!", true);
- popup_write_string("\n");
- popup_center_string("(But we'll give you another chance!)", false);
+ popup_center_string(read_buf[8], false);
+ popup_next_line();
+ popup_center_string(read_buf[9], false);
}
- popup_write_string("\n");
+ popup_next_line();
- Common::strcpy_s(work_buf, "Now comes the part that everybody hates. But if we don't");
- popup_write_string(work_buf);
- Common::strcpy_s(work_buf, "do this, nasty rodent-like people will pirate this game,");
- popup_write_string(work_buf);
- Common::strcpy_s(work_buf, "and a whole generation of talented designers, programmers,");
- popup_write_string(work_buf);
- Common::strcpy_s(work_buf, "artists, and playtesters will go hungry, and will wander");
- popup_write_string(work_buf);
- Common::strcpy_s(work_buf, "aimlessly through the land at night searching for peace.");
- popup_write_string(work_buf);
- Common::strcpy_s(work_buf, "So let's grit our teeth and get it over with. Just get");
- popup_write_string(work_buf);
+ popup_write_string(read_buf[2]);
+ popup_write_string(read_buf[3]);
- Common::strcpy_s(work_buf, "out your copy of ");
- if (copy_prot.manual == 'g') {
- Common::strcat_s(work_buf, "the GAME MANUAL");
- } else {
- Common::strcat_s(work_buf, "REX'S LOGBOOK");
- }
- Common::strcat_s(work_buf, ". See! That was easy. ");
+ Common::strcpy_s(work_buf, page_buf);
+ Common::strcat_s(work_buf, read_buf[4]);
popup_write_string(work_buf);
- Common::strcpy_s(work_buf, "Next, just turn to page ");
- Common::strcat_s(work_buf, page_buf);
- Common::strcat_s(work_buf, ". On line ");
- Common::strcat_s(work_buf, line_buf);
- Common::strcat_s(work_buf, ", find word number ");
- Common::strcat_s(work_buf, word_buf);
- Common::strcat_s(work_buf, ", ");
+ Common::strcpy_s(work_buf, line_buf);
+ Common::strcat_s(work_buf, read_buf[5]);
popup_write_string(work_buf);
- Common::strcpy_s(work_buf, "and type it on the line below (we've even given you");
+ Common::strcpy_s(work_buf, word_buf);
popup_write_string(work_buf);
- Common::strcpy_s(work_buf, "first letter as a hint). As soon as you do that, we can get");
- popup_write_string(work_buf);
- popup_write_string("right into this really COOL adventure game!\n");
- popup_write_string("\n");
- popup_write_string(" ");
+ popup_write_string(read_buf[6]);
+ popup_write_string(read_buf[7]);
+
+ popup_next_line();
+ popup_next_line();
+ popup_write_string(" ");
popup_set_ask();
- popup_write_string("\n");
+ popup_next_line();
entry_buf[0] = copy_prot.say[0];
entry_buf[1] = 0;
@@ -180,7 +176,8 @@ int copy_pop_and_ask(void) {
}
mads_strlwr(entry_buf);
- if (strcmp(entry_buf, copy_prot.say) == 0) goto finish;
+ if (strcmp(entry_buf, copy_prot.say) == 0)
+ goto finish;
}
goto done;
@@ -189,74 +186,38 @@ finish:
error_flag = COPY_SUCCEED;
done:
- popup_vomitation_flag = true; /* Reset */
-
- return (error_flag);
-}
-
-static int copy_read_boot_sector(byte *buffer) {
- error("TODO: copy_read_boot_sector");
-}
-
-static int copy_read_happy_file(byte *buffer) {
- int error_flag = true;
- Common::File handle;
+ box_param.erase_on_first = true; /* Reset */
- if (handle.open(happy_file_name)) {
- if (!fileio_fread_f(buffer, COPY_LENGTH, 1, &handle)) goto done;
- }
-
- error_flag = false;
+ delete handle;
+ if (load_buffer != NULL)
+ mem_free(load_buffer);
-done:
- handle.close();
return error_flag;
}
-static int copy_write_happy_file(byte *buffer) {
- error("TODO: copy_write_happy_file");
-}
-
-int copy_verify(void) {
+int global_copy_verify() {
int error_flag = COPY_FAIL;
- int dog_master;
- byte *work1 = NULL;
- byte *work2 = NULL;
-
- work1 = (byte *)mem_get(COPY_LENGTH);
- work2 = (byte *)mem_get(COPY_LENGTH);
-
- if ((work1 != NULL) && (work2 != NULL)) {
- //srand((word)timer_read_dos());
- dog_master = imath_random(1, 1000);
+ int loaded = false;
- if (dog_master <= 50) {
- memset(work1, 0, COPY_LENGTH);
- copy_write_happy_file(work1);
- }
+ if (!ConfMan.getBool("copy_protection"))
+ return COPY_SUCCEED;
- if (!copy_read_boot_sector(work1)) {
- if (!copy_read_happy_file(work2)) {
- if (memcmp(work1, work2, COPY_LENGTH) == 0) {
- goto finish;
- }
- }
- }
+ if (box_param.series == NULL) {
+ Common::strcpy_s(box_param.name, "*BOX");
+ if (popup_box_load())
+ goto done;
+ loaded = true;
}
error_flag = copy_pop_and_ask();
- if (error_flag != COPY_SUCCEED) goto done;
- if ((work1 != NULL) && (work2 != NULL)) {
- copy_write_happy_file(work1);
+ if (loaded) {
+ sprite_free(&box_param.menu, true);
+ sprite_free(&box_param.logo, true);
+ sprite_free(&box_param.series, true);
}
-finish:
- error_flag = COPY_SUCCEED;
-
done:
- if (work2 != NULL) mem_free(work2);
- if (work1 != NULL) mem_free(work1);
return error_flag;
}
diff --git a/engines/mads/madsv2/core/copy.h b/engines/mads/madsv2/core/copy.h
index 331c564b19a..d28dc9b50fa 100644
--- a/engines/mads/madsv2/core/copy.h
+++ b/engines/mads/madsv2/core/copy.h
@@ -39,19 +39,17 @@ namespace MADSV2 {
struct CopyProt {
- char manual;
- int page;
- int line;
- int word_number;
+ byte manual;
+ int16 page;
+ int16 line;
+ int16 word_number;
char say[20];
+ static constexpr int SIZE = 1 + 2 + 2 + 2 + 20;
void load(Common::SeekableReadStream *src);
};
-extern void copy_mangle(CopyProt *copy_prot);
-extern int copy_load(CopyProt *copy_prot);
-extern int copy_pop_and_ask();
-extern int copy_verify();
+extern int global_copy_verify();
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/core/global.cpp b/engines/mads/madsv2/core/global.cpp
index 78734f1abb2..c94c3dba2b6 100644
--- a/engines/mads/madsv2/core/global.cpp
+++ b/engines/mads/madsv2/core/global.cpp
@@ -96,9 +96,5 @@ void global_write_config_file() {
write_config_file();
}
-int global_copy_verify() {
- error("TODO: int global_copy_verify(void);");
-}
-
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/core/global.h b/engines/mads/madsv2/core/global.h
index 3f33d03fa3b..670d0ffa98c 100644
--- a/engines/mads/madsv2/core/global.h
+++ b/engines/mads/madsv2/core/global.h
@@ -126,7 +126,6 @@ void global_read_config_file(void);
void global_write_config_file(void);
void global_load_config_parameters(void);
void global_unload_config_parameters(void);
-int global_copy_verify(void);
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/phantom.cpp b/engines/mads/madsv2/phantom/phantom.cpp
index e2c6afb21cb..29828f4606e 100644
--- a/engines/mads/madsv2/phantom/phantom.cpp
+++ b/engines/mads/madsv2/phantom/phantom.cpp
@@ -21,6 +21,7 @@
#include "engines/util.h"
#include "mads/madsv2/core/conv.h"
+#include "mads/madsv2/core/copy.h"
#include "mads/madsv2/core/env.h"
#include "mads/madsv2/core/game.h"
#include "mads/madsv2/core/himem.h"
Commit: f3f61f16591b54d26af3cb3943ac09d6c6843fce
https://github.com/scummvm/scummvm/commit/f3f61f16591b54d26af3cb3943ac09d6c6843fce
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:59+10:00
Commit Message:
MADS: PHANTOM: Added Phantom game menus
Changed paths:
A engines/mads/madsv2/phantom/menus.cpp
A engines/mads/madsv2/phantom/menus.h
engines/mads/madsv2/core/global.cpp
engines/mads/madsv2/core/global.h
engines/mads/madsv2/core/popup.cpp
engines/mads/madsv2/core/popup.h
engines/mads/madsv2/phantom/mads/quotes.h
engines/mads/madsv2/phantom/main.cpp
engines/mads/module.mk
diff --git a/engines/mads/madsv2/core/global.cpp b/engines/mads/madsv2/core/global.cpp
index c94c3dba2b6..6f578be1d4e 100644
--- a/engines/mads/madsv2/core/global.cpp
+++ b/engines/mads/madsv2/core/global.cpp
@@ -72,22 +72,6 @@ void global_section_constructor() {
g_engine->global_section_constructor();
}
-void global_game_menu() {
- error("TODO: void global_game_menu(void);");
-}
-
-void global_menu_system_init() {
- error("TODO: void global_menu_system_init(void);");
-}
-
-void global_menu_system_shutdown() {
- error("TODO: void global_menu_system_shutdown(void);");
-}
-
-void global_emergency_save() {
- error("TODO: void global_emergency_save(void);");
-}
-
void global_read_config_file() {
read_config_file();
}
diff --git a/engines/mads/madsv2/core/global.h b/engines/mads/madsv2/core/global.h
index 670d0ffa98c..619ef54538f 100644
--- a/engines/mads/madsv2/core/global.h
+++ b/engines/mads/madsv2/core/global.h
@@ -118,10 +118,6 @@ void global_room_init(void);
void global_verb_filter(void);
void global_sound_driver(void);
void global_section_constructor(void);
-void global_game_menu(void);
-void global_menu_system_init(void);
-void global_menu_system_shutdown(void);
-void global_emergency_save(void);
void global_read_config_file(void);
void global_write_config_file(void);
void global_load_config_parameters(void);
diff --git a/engines/mads/madsv2/core/popup.cpp b/engines/mads/madsv2/core/popup.cpp
index 9305b2aea7a..a5aa4af8565 100644
--- a/engines/mads/madsv2/core/popup.cpp
+++ b/engines/mads/madsv2/core/popup.cpp
@@ -1330,7 +1330,7 @@ static void popup_item_init(PopupItem *item) {
/* Sets up popup dialog structure, allocating memory dynamically
/* if necessary.
*/
-Popup *popup_dialog_create(byte *memory, long heap_size, int max_items) {
+Popup *popup_dialog_create(void *memory, long heap_size, int max_items) {
int count;
byte *block = NULL;
word status;
@@ -1514,7 +1514,7 @@ static int popup_font_size(const char *string) {
static void popup_y_placement(PopupItem *item, int y) {
- int bottom;
+ int16 bottom;
if (y == POPUP_FILL) {
item->y = popup->y_position;
@@ -1529,7 +1529,7 @@ static void popup_y_placement(PopupItem *item, int y) {
static void popup_x_width_check(PopupItem *item) {
- int new_width;
+ int16 new_width;
if (item->x & POPUP_CENTER) {
new_width = item->xs;
@@ -1545,7 +1545,7 @@ static void popup_x_width_check(PopupItem *item) {
void popup_width_force(int width) {
- popup->width = MAX(popup->width, width);
+ popup->width = MAX<int16>(popup->width, width);
}
@@ -3030,7 +3030,7 @@ static void item_constructor(PopupItem *item, int type) {
PopupItem *popup_button(const char *prompt, int x) {
int first_button;
- int new_width;
+ int16 new_width;
PopupItem *item;
first_button = (popup->status & POPUP_STATUS_BUTTON) == 0;
@@ -3152,7 +3152,7 @@ PopupItem *popup_menu(const char *prompt,
-PopupItem *popup_message(char *prompt, int x, int y) {
+PopupItem *popup_message(const char *prompt, int x, int y) {
PopupItem *item;
item = item_allocate(false);
@@ -3171,7 +3171,7 @@ PopupItem *popup_message(char *prompt, int x, int y) {
popup_x_width_check(item);
- return (item);
+ return item;
}
@@ -3214,8 +3214,8 @@ PopupItem *popup_sprite(SeriesPtr series, int sprite, int x, int y) {
-PopupItem *popup_savelist(byte *data,
- byte *empty_string,
+PopupItem *popup_savelist(const char *data,
+ const char *empty_string,
int elements,
int element_offset,
int element_max_length,
diff --git a/engines/mads/madsv2/core/popup.h b/engines/mads/madsv2/core/popup.h
index abbfae1f753..fae58d924be 100644
--- a/engines/mads/madsv2/core/popup.h
+++ b/engines/mads/madsv2/core/popup.h
@@ -354,22 +354,22 @@ typedef struct {
word status; /* Popup status flags */
- int x, y; /* X location */
- int width; /* X minimum width */
- int y_position; /* Y current usage */
- int y_spacing; /* Y spacing */
- int xs, ys; /* Window size information */
-
- int button_y; /* Button Y location */
- int button_spacing; /* Button spacing */
- int button_left_fill; /* Button row left fill */
- int button_right_fill; /* Button row right fill */
- int button_bar_color; /* Button bar color */
-
- int key; /* Last keyboard input */
- int key_handled; /* Flag if key handled */
-
- int mouse_status; /* Mouse status word */
+ uint16 x, y; /* X location */
+ int16 width; /* X minimum width */
+ int16 y_position; /* Y current usage */
+ int16 y_spacing; /* Y spacing */
+ int16 xs, ys; /* Window size information */
+
+ int16 button_y; /* Button Y location */
+ int16 button_spacing; /* Button spacing */
+ int16 button_left_fill; /* Button row left fill */
+ int16 button_right_fill; /* Button row right fill */
+ int16 button_bar_color; /* Button bar color */
+
+ int16 key; /* Last keyboard input */
+ int16 key_handled; /* Flag if key handled */
+
+ int16 mouse_status; /* Mouse status word */
long mouse_clock; /* Mouse action clock */
PopupItem *enter_item; /* ENTER key button */
@@ -383,8 +383,8 @@ typedef struct {
PopupItem *list_item; /* List item */
PopupItem *clear_item; /* Clear list item */
- int max_items; /* Maximum # of items */
- int num_items; /* Number of items in popup */
+ int16 max_items; /* Maximum # of items */
+ int16 num_items; /* Number of items in popup */
PopupItem *item; /* Item list */
} Popup;
@@ -449,9 +449,7 @@ int popup_alert(int width, const char *message_line, ...);
int popup_box_load(void);
/* popup_5.c */
-Popup *popup_dialog_create(void *memory,
- long heap_size,
- int max_items);
+Popup *popup_dialog_create(void *memory, long heap_size, int max_items);
Popup *popup_dialog_destroy(void);
/* popup_5.c */
@@ -461,8 +459,8 @@ PopupItem *popup_message(const char *prompt, int x, int y);
PopupItem *popup_execute(void);
/* popup_5.c */
-PopupItem *popup_savelist(byte *data,
- byte *empty_string,
+PopupItem *popup_savelist(const char *data,
+ const char *empty_string,
int elements,
int element_offset,
int element_max_length,
@@ -479,7 +477,7 @@ void popup_width_force(int width);
/* popup_5.c */
void popup_menu_option(PopupItem *item, char *option);
-PopupItem *popup_menu(char *prompt,
+PopupItem *popup_menu(const char *prompt,
int x, int y, int pixel_width,
int off_center_x,
int elements, int element_max_length,
diff --git a/engines/mads/madsv2/phantom/mads/quotes.h b/engines/mads/madsv2/phantom/mads/quotes.h
index 5dc180c66e8..638769ee8ed 100644
--- a/engines/mads/madsv2/phantom/mads/quotes.h
+++ b/engines/mads/madsv2/phantom/mads/quotes.h
@@ -29,94 +29,90 @@ namespace MADSV2 {
namespace Phantom {
enum {
- quote_score_1 = 54,
- quote_score_2 = 55,
- quote_score_3 = 56,
- quote_score_4 = 57,
- quote_score_rank_1 = 58,
- quote_score_rank_2 = 59,
- quote_score_rank_3 = 60,
- quote_score_rank_4 = 61,
- quote_score_rank_5 = 62,
- quote_score_rank_6 = 63,
- quote_score_rank_7 = 64,
- quote_score_rank_8 = 65,
- quote_mainmenu_phantom_1 = 66,
- quote_305a0 = 100,
- quote_305a1 = 101,
-
- quote_310a0 = 102,
- quote_310a1 = 103,
- quote_310a2 = 104,
- quote_310b0 = 105,
- quote_310b1 = 106,
- quote_310b2 = 107,
- quote_310c0 = 108,
- quote_310c1 = 109,
- quote_310d0 = 110,
- quote_310d1 = 111,
- quote_310d2 = 112,
- quote_310e0 = 113,
- quote_310e1 = 114,
- quote_310e2 = 115,
- quote_310f0 = 116,
- quote_204a0 = 117
-
-#if 0
- quote_menu_done,
- quote_menu_cancel,
- quote_menu_save,
- quote_menu_restore,
- quote_menu_clear,
- quote_menu_yes,
- quote_menu_no,
- quote_menu_ok,
- quote_menu_empty,
- quote_menu_unnamed,
- quote_main_title,
- quote_main_item1,
- quote_main_item2,
- quote_main_item3,
- quote_main_item4,
- quote_main_item5,
- quote_main_item6,
- quote_options_title,
- quote_options_item1,
- quote_options_item2,
- quote_options_item3,
- quote_options_item4,
- quote_options_item5,
- quote_options_item6,
- quote_options_item1a,
- quote_options_item1b,
- quote_options_item2a,
- quote_options_item2b,
- quote_options_item3a,
- quote_options_item3b,
- quote_options_item4a,
- quote_options_item4b,
- quote_options_item4c,
- quote_options_item5a,
- quote_options_item5b,
- quote_options_item5c,
- quote_options_item6a,
- quote_options_item6b,
- quote_save_title,
- quote_restore_title,
- quote_difficulty_title,
- quote_difficulty_item1,
- quote_difficulty_item2,
- quote_save_successful,
- quote_restore_successful,
- quote_save_failed,
- quote_restore_failed,
- quote_emergency_save_1a,
- quote_emergency_save_1b,
- quote_emergency_save_success,
- quote_emergency_save_failure,
- quote_emergency_save_attempt,
- quote_emergency_save_resume
-#endif
+ quote_menu_done = 1,
+ quote_menu_cancel = 2,
+ quote_menu_save = 3,
+ quote_menu_restore = 4,
+ quote_menu_clear = 5,
+ quote_menu_yes = 6,
+ quote_menu_no = 7,
+ quote_menu_ok = 8,
+ quote_menu_empty = 9,
+ quote_menu_unnamed = 10,
+ quote_main_title = 11,
+ quote_main_item1 = 12,
+ quote_main_item2 = 13,
+ quote_main_item3 = 15,
+ quote_main_item4 = 16,
+ quote_main_item5 = 17,
+ quote_main_item6 = 14,
+ quote_options_title = 18,
+ quote_options_item1 = 19,
+ quote_options_item2 = 20,
+ quote_options_item3 = 21,
+ quote_options_item4 = 22,
+ quote_options_item5 = 23,
+ quote_options_item6 = 24,
+ quote_options_item1a = 25,
+ quote_options_item1b = 26,
+ quote_options_item2a = 27,
+ quote_options_item2b = 28,
+ quote_options_item3a = 29,
+ quote_options_item3b = 30,
+ quote_options_item4a = 31,
+ quote_options_item4b = 32,
+ quote_options_item4c = 33,
+ quote_options_item5a = 34,
+ quote_options_item5b = 35,
+ quote_options_item5c = 36,
+ quote_options_item6a = 37,
+ quote_options_item6b = 38,
+ quote_save_title = 39,
+ quote_restore_title = 40,
+ quote_difficulty_title = 41,
+ quote_difficulty_item1 = 42,
+ quote_difficulty_item2 = 43,
+ quote_save_successful = 44,
+ quote_restore_successful = 45,
+ quote_save_failed = 46,
+ quote_restore_failed = 47,
+ quote_emergency_save_1a = 48,
+ quote_emergency_save_1b = 49,
+ quote_emergency_save_success = 50,
+ quote_emergency_save_failure = 51,
+ quote_emergency_save_attempt = 52,
+ quote_emergency_save_resume = 53,
+ quote_score_1 = 54,
+ quote_score_2 = 55,
+ quote_score_3 = 56,
+ quote_score_4 = 57,
+ quote_score_rank_1 = 58,
+ quote_score_rank_2 = 59,
+ quote_score_rank_3 = 60,
+ quote_score_rank_4 = 61,
+ quote_score_rank_5 = 62,
+ quote_score_rank_6 = 63,
+ quote_score_rank_7 = 64,
+ quote_score_rank_8 = 65,
+ quote_mainmenu_phantom_1 = 66,
+ quote_305a0 = 100,
+ quote_305a1 = 101,
+ quote_310a0 = 102,
+ quote_310a1 = 103,
+ quote_310a2 = 104,
+ quote_310b0 = 105,
+ quote_310b1 = 106,
+ quote_310b2 = 107,
+ quote_310c0 = 108,
+ quote_310c1 = 109,
+ quote_310d0 = 110,
+ quote_310d1 = 111,
+ quote_310d2 = 112,
+ quote_310e0 = 113,
+ quote_310e1 = 114,
+ quote_310e2 = 115,
+ quote_310f0 = 116,
+ quote_204a0 = 117
};
} // namespace Phantom
diff --git a/engines/mads/madsv2/phantom/main.cpp b/engines/mads/madsv2/phantom/main.cpp
index 92c1c309e7f..b70043d6b38 100644
--- a/engines/mads/madsv2/phantom/main.cpp
+++ b/engines/mads/madsv2/phantom/main.cpp
@@ -35,6 +35,7 @@
#include "mads/madsv2/core/quote.h"
#include "mads/madsv2/core/speech.h"
#include "mads/madsv2/phantom/main_menu.h"
+#include "mads/madsv2/phantom/menus.h"
#include "mads/madsv2/engine.h"
namespace MADS {
@@ -123,15 +124,13 @@ static void main_menu_main() {
}
static void main_cold_data_init() {
-#if 0
debugger_reset = game_debugger_reset;
debugger_update = game_debugger;
-
game_menu_routine = global_game_menu;
game_menu_init = global_menu_system_init;
game_menu_exit = global_menu_system_shutdown;
game_emergency_save = global_emergency_save;
-#endif
+
Common::strcpy_s(config_file_name, "config.pha");
Common::strcpy_s(save_game_key, "phan");
Common::strcpy_s(restart_game_key, "phantom");
diff --git a/engines/mads/madsv2/phantom/menus.cpp b/engines/mads/madsv2/phantom/menus.cpp
new file mode 100644
index 00000000000..24371ffd265
--- /dev/null
+++ b/engines/mads/madsv2/phantom/menus.cpp
@@ -0,0 +1,719 @@
+/* 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 "mads/madsv2/core/config.h"
+#include "mads/madsv2/core/echo.h"
+#include "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/global.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/keys.h"
+#include "mads/madsv2/core/matte.h"
+#include "mads/madsv2/core/mem.h"
+#include "mads/madsv2/core/speech.h"
+#include "mads/madsv2/core/quote.h"
+#include "mads/madsv2/core/text.h"
+#include "mads/madsv2/phantom/menus.h"
+#include "mads/madsv2/phantom/global.h"
+#include "mads/madsv2/phantom/mads/quotes.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+
+#define SAVE_MENU_PIXEL_WIDTH 200
+#define MAX_SAVES_ON_SCREEN 10
+
+#define SPACE_BETWEEN -1
+
+#define MAIN_MENU_ITEM_WIDTH 140
+#define MAIN_MENU_FORCE_WIDTH 160
+
+#define DIFFICULTY_MENU_FORCE_WIDTH 140
+
+#define OPTIONS_MENU_ITEM_WIDTH 160
+#define OPTIONS_MENU_FORCE_WIDTH 170
+#define OPTIONS_MENU_OFF_CENTER 10
+
+
+#define SAVE_SUCCESSFUL 1
+#define RESTORE_SUCCESSFUL 2
+#define SAVE_FAILED 3
+#define RESTORE_FAILED 4
+
+
+int global_menu_direct_jump;
+int global_menu_force_restart;
+
+char *menu_quotes = NULL;
+
+
+static int global_save(int id) {
+ int status;
+
+ game_save_name(id + 1);
+
+ if (!kernel_save_game(save_game_buf)) {
+ status = SAVE_SUCCESSFUL;
+ } else {
+ status = SAVE_FAILED;
+ }
+
+ return status;
+}
+
+static int global_restore(int id) {
+ int status;
+
+ game_save_name(id + 1);
+
+ if (!kernel_load_game(save_game_buf)) {
+ status = RESTORE_SUCCESSFUL;
+ } else {
+ status = RESTORE_FAILED;
+ save_game_buf[0] = 0;
+ }
+
+ WRITE_LE_UINT32(&global[walker_timing], 0);
+
+ return status;
+}
+
+void global_menu_system_init() {
+ menu_quotes = quote_load(quote_menu_done, quote_menu_cancel,
+ quote_menu_save, quote_menu_restore,
+ quote_menu_clear, quote_menu_yes,
+ quote_menu_no, quote_menu_ok,
+ quote_menu_empty,
+ quote_menu_unnamed,
+ quote_main_title,
+ quote_main_item1, quote_main_item2,
+ quote_main_item3, quote_main_item4,
+ quote_main_item5, quote_main_item6,
+ quote_options_title,
+ quote_options_item1,
+ quote_options_item2,
+ quote_options_item3,
+ quote_options_item4,
+ quote_options_item5,
+ quote_options_item6,
+ quote_options_item1a,
+ quote_options_item1b,
+ quote_options_item2a,
+ quote_options_item2b,
+ quote_options_item3a,
+ quote_options_item3b,
+ quote_options_item4a,
+ quote_options_item4b,
+ quote_options_item4c,
+ quote_options_item5a,
+ quote_options_item5b,
+ quote_options_item5c,
+ quote_options_item6a,
+ quote_options_item6b,
+ quote_save_title, quote_restore_title,
+ quote_difficulty_title,
+ quote_difficulty_item1, quote_difficulty_item2,
+ quote_save_successful,
+ quote_restore_successful,
+ quote_save_failed,
+ quote_restore_failed,
+ quote_emergency_save_1a,
+ quote_emergency_save_1b,
+ quote_emergency_save_success,
+ quote_emergency_save_failure,
+ quote_emergency_save_attempt,
+ quote_emergency_save_resume,
+ 0);
+}
+
+void global_menu_system_shutdown() {
+ if (menu_quotes != NULL)
+ mem_free(menu_quotes);
+}
+
+static char *menu_quote(int id) {
+ return quote_string(menu_quotes, id);
+}
+
+void global_emergency_save() {
+ game_save_name(0);
+
+ echo(" ", true);
+ echo(menu_quote(quote_emergency_save_1a), false);
+ echo(save_game_buf, false);
+ echo(menu_quote(quote_emergency_save_1b), false);
+
+ if (scr_orig.data != NULL) mem_free(scr_orig.data);
+
+ if (!kernel_save_game(save_game_buf)) {
+ echo(menu_quote(quote_emergency_save_success), true);
+ echo(menu_quote(quote_emergency_save_attempt), false);
+ echo(restart_game_key, true);
+ echo(menu_quote(quote_emergency_save_resume), true);
+ } else {
+ echo(menu_quote(quote_emergency_save_failure), true);
+ }
+}
+
+static void global_alert(int status) {
+ int id = 0;
+
+ switch (status) {
+ case SAVE_SUCCESSFUL:
+ id = quote_save_successful;
+ break;
+
+ case SAVE_FAILED:
+ id = quote_save_failed;
+ break;
+
+ case RESTORE_SUCCESSFUL:
+ id = quote_restore_successful;
+ break;
+
+ case RESTORE_FAILED:
+ id = quote_restore_failed;
+ break;
+ }
+
+ popup_dialog_create(game_menu_popup, GAME_DIALOG_HEAP, 20);
+
+ popup_message(menu_quote(id), POPUP_CENTER, POPUP_FILL);
+
+ if (status == SAVE_SUCCESSFUL) {
+ mads_strlwr(&save_game_buf[1]);
+ popup_message(save_game_buf, POPUP_CENTER, POPUP_FILL);
+ }
+
+ popup_button(menu_quote(quote_menu_ok), POPUP_CENTER);
+
+ popup_execute();
+ popup_dialog_destroy();
+}
+
+static void global_menu_score() {
+ int score;
+
+ score = global[player_score];
+ if (score > 250) score = 250;
+
+ text_index[0] = score;
+ text_index[1] = 250;
+
+ if (score <= 25) {
+ text_index[2] = 1; /* Stage sweeper */
+ } else if (score <= 50) {
+ text_index[2] = 2; /* Dresser */
+ } else if (score <= 75) {
+ text_index[2] = 3; /* Usher */
+ } else if (score <= 100) {
+ text_index[2] = 4; /* Stagehand */
+ } else if (score <= 150) {
+ text_index[2] = 5; /* Chorus Member */
+ } else if (score <= 200) {
+ text_index[2] = 6; /* Supporting Player */
+ } else if (score <= 249) {
+ text_index[2] = 7; /* Star Player */
+ } else if (score <= 250) {
+ text_index[2] = 8; /* Director */
+ } else {
+ text_index[2] = 9; /* Bug Finder! */
+ }
+
+ text_show(99);
+
+ kernel.activate_menu = 0;
+}
+
+static void global_menu_save_restore(int save) {
+ int status = -1;
+ int selection;
+ char *save_game_name;
+ PopupItem *save_list;
+ PopupItem *go_button;
+ PopupItem *clear_button;
+ PopupItem *cancel_button;
+ PopupItem *result;
+
+ popup_dialog_create(game_menu_popup, GAME_DIALOG_HEAP, 20);
+
+ if (save) {
+ popup_message(menu_quote(quote_save_title), POPUP_CENTER, POPUP_FILL);
+ } else {
+ popup_message(menu_quote(quote_restore_title), POPUP_CENTER, POPUP_FILL);
+ }
+ popup_blank(4);
+
+ save_list = popup_savelist(nullptr, menu_quote(quote_menu_empty),
+ GAME_MAX_SAVE_SLOTS,
+ GAME_MAX_SAVE_LENGTH + 1,
+ GAME_MAX_SAVE_LENGTH,
+ SAVE_MENU_PIXEL_WIDTH,
+ MAX_SAVES_ON_SCREEN,
+ save, game.last_save);
+
+ if (save) {
+ go_button = popup_button(menu_quote(quote_menu_save), POPUP_BUTTON_LEFT);
+ clear_button = popup_button(menu_quote(quote_menu_clear), POPUP_CENTER);
+ game_menu_popup->clear_item = clear_button;
+ } else {
+ go_button = popup_button(menu_quote(quote_menu_restore), POPUP_BUTTON_LEFT);
+ }
+ cancel_button = popup_cancel_button(menu_quote(quote_menu_cancel));
+
+ result = popup_execute();
+
+ if (result == cancel_button) {
+ switch (game_menu_popup->key) {
+ case alt_x_key:
+ case ctrl_x_key:
+ case alt_q_key:
+ case ctrl_q_key:
+ game.going = false;
+ kernel.activate_menu = 0;
+ break;
+
+ case f1_key:
+ kernel.activate_menu = GAME_MAIN_MENU;
+ break;
+
+ case f2_key:
+ if (save) {
+ kernel.activate_menu = GAME_MAIN_MENU;
+ } else {
+ kernel.activate_menu = GAME_SAVE_MENU;
+ }
+ break;
+
+ case f3_key:
+ if (!save) {
+ kernel.activate_menu = GAME_MAIN_MENU;
+ } else {
+ kernel.activate_menu = GAME_RESTORE_MENU;
+ }
+ break;
+
+ case f4_key:
+ kernel.activate_menu = GAME_SCORE_MENU;
+
+ case f5_key:
+ kernel.activate_menu = GAME_OPTIONS_MENU;
+ break;
+
+ default:
+ kernel.activate_menu = GAME_MAIN_MENU;
+ break;
+ }
+ } else {
+ kernel.activate_menu = 0;
+ }
+
+ popup_dialog_destroy();
+
+ if (result == go_button) {
+ selection = save_list->list->picked_element;
+ game.last_save = selection;
+ if (save) {
+ save_game_name = game_save_directory + ((GAME_MAX_SAVE_LENGTH + 1) * selection);
+ if (!strlen(save_game_name)) {
+ Common::strcpy_s(save_game_name, GAME_MAX_SAVE_LENGTH, menu_quote(quote_menu_unnamed));
+ }
+ status = global_save(selection);
+ game_write_save_directory();
+ } else {
+ status = global_restore(selection);
+ }
+ }
+
+ if (save) {
+ game_write_save_directory();
+ }
+
+ if (status >= 0) {
+ global_alert(status);
+ }
+}
+
+static void global_menu_options() {
+ int initial_1, initial_2, initial_3;
+ int initial_4, initial_5, initial_6;
+ int former_music;
+ int former_sound;
+ PopupItem *music_item;
+ PopupItem *sound_item;
+ PopupItem *interface_item;
+ PopupItem *fade_item;
+ PopupItem *panning_item;
+ PopupItem *speech_item;
+ PopupItem *done_button;
+ PopupItem *cancel_button;
+ PopupItem *result;
+
+ global_unload_config_parameters();
+
+ popup_dialog_create(game_menu_popup, GAME_DIALOG_HEAP, 20);
+
+ popup_sprite(box_param.logo, 1, POPUP_CENTER, POPUP_FILL);
+ popup_blank(2);
+
+ former_music = config_file.music_flag;
+ former_sound = config_file.sound_flag;
+
+ initial_1 = config_file.music_flag ? 0 : 1;
+ initial_2 = config_file.sound_flag ? 0 : 1;
+ initial_6 = config_file.speech_flag ? 0 : 1;
+ initial_3 = config_file.interface_hotspots;
+ initial_4 = config_file.screen_fade;
+ initial_5 = config_file.panning_speed;
+
+ music_item = popup_menu(menu_quote(quote_options_item1),
+ POPUP_CENTER, POPUP_FILL, OPTIONS_MENU_ITEM_WIDTH,
+ OPTIONS_MENU_OFF_CENTER,
+ 2, 40, initial_1);
+ popup_menu_option(music_item, menu_quote(quote_options_item1a));
+ popup_menu_option(music_item, menu_quote(quote_options_item1b));
+
+ popup_blank(SPACE_BETWEEN);
+
+
+ sound_item = popup_menu(menu_quote(quote_options_item2),
+ POPUP_CENTER, POPUP_FILL, OPTIONS_MENU_ITEM_WIDTH,
+ OPTIONS_MENU_OFF_CENTER,
+ 2, 40, initial_2);
+ popup_menu_option(sound_item, menu_quote(quote_options_item2a));
+ popup_menu_option(sound_item, menu_quote(quote_options_item2b));
+
+ popup_blank(SPACE_BETWEEN);
+
+
+ speech_item = popup_menu(menu_quote(quote_options_item6),
+ POPUP_CENTER, POPUP_FILL, OPTIONS_MENU_ITEM_WIDTH,
+ OPTIONS_MENU_OFF_CENTER,
+ 2, 40, initial_6);
+ popup_menu_option(speech_item, menu_quote(quote_options_item6a));
+ popup_menu_option(speech_item, menu_quote(quote_options_item6b));
+
+ popup_blank(SPACE_BETWEEN);
+
+
+ interface_item = popup_menu(menu_quote(quote_options_item3),
+ POPUP_CENTER, POPUP_FILL, OPTIONS_MENU_ITEM_WIDTH,
+ OPTIONS_MENU_OFF_CENTER,
+ 2, 40, initial_3);
+ popup_menu_option(interface_item, menu_quote(quote_options_item3a));
+ popup_menu_option(interface_item, menu_quote(quote_options_item3b));
+
+ popup_blank(SPACE_BETWEEN);
+
+
+ fade_item = popup_menu(menu_quote(quote_options_item4),
+ POPUP_CENTER, POPUP_FILL, OPTIONS_MENU_ITEM_WIDTH,
+ OPTIONS_MENU_OFF_CENTER,
+ 3, 40, initial_4);
+ popup_menu_option(fade_item, menu_quote(quote_options_item4a));
+ popup_menu_option(fade_item, menu_quote(quote_options_item4b));
+ popup_menu_option(fade_item, menu_quote(quote_options_item4c));
+
+ popup_blank(SPACE_BETWEEN);
+
+
+ panning_item = popup_menu(menu_quote(quote_options_item5),
+ POPUP_CENTER, POPUP_FILL, OPTIONS_MENU_ITEM_WIDTH,
+ OPTIONS_MENU_OFF_CENTER,
+ 3, 40, initial_5);
+ popup_menu_option(panning_item, menu_quote(quote_options_item5a));
+ popup_menu_option(panning_item, menu_quote(quote_options_item5b));
+ popup_menu_option(panning_item, menu_quote(quote_options_item5c));
+
+
+
+ done_button = popup_button(menu_quote(quote_menu_done), POPUP_LEFT);
+ cancel_button = popup_cancel_button(menu_quote(quote_menu_cancel));
+
+ popup_width_force(OPTIONS_MENU_FORCE_WIDTH);
+
+ result = popup_execute();
+
+ kernel.activate_menu = GAME_MAIN_MENU;
+
+ if (result == cancel_button) {
+ switch (game_menu_popup->key) {
+ case alt_x_key:
+ case ctrl_x_key:
+ case alt_q_key:
+ case ctrl_q_key:
+ game.going = false;
+ kernel.activate_menu = 0;
+ break;
+
+ case f1_key:
+ kernel.activate_menu = GAME_MAIN_MENU;
+ break;
+
+ case f2_key:
+ kernel.activate_menu = GAME_SAVE_MENU;
+ break;
+
+ case f3_key:
+ kernel.activate_menu = GAME_RESTORE_MENU;
+ break;
+
+ case f4_key:
+ kernel.activate_menu = GAME_SCORE_MENU;
+ break;
+
+ case f5_key:
+ kernel.activate_menu = GAME_MAIN_MENU;
+ break;
+
+ default:
+ kernel.activate_menu = GAME_MAIN_MENU;
+ break;
+ }
+ }
+
+ if (result == done_button) {
+ config_file.music_flag = !music_item->list->picked_element;
+ config_file.sound_flag = !sound_item->list->picked_element;
+ config_file.speech_flag = !speech_item->list->picked_element;
+ config_file.interface_hotspots = interface_item->list->picked_element;
+ config_file.screen_fade = fade_item->list->picked_element;
+ config_file.panning_speed = panning_item->list->picked_element;
+
+ global_write_config_file();
+ global_load_config_parameters();
+
+ kernel.activate_menu = 0;
+ }
+
+ if ((former_music != config_file.music_flag) ||
+ (former_sound != config_file.sound_flag)) {
+ game_exec_function(section_music_reset_pointer);
+ }
+
+ if (!config_file.speech_flag) {
+ if (speech_system_active)
+ speech_all_off();
+ }
+
+ popup_dialog_destroy();
+}
+
+static void global_menu_difficulty() {
+ PopupItem *easy_item;
+ PopupItem *hard_item;
+ PopupItem *result;
+
+ popup_dialog_create(game_menu_popup, GAME_DIALOG_HEAP, 20);
+
+ popup_message(menu_quote(quote_difficulty_title), POPUP_CENTER, POPUP_FILL);
+ popup_blank(6);
+
+ easy_item = popup_menu(menu_quote(quote_difficulty_item1),
+ POPUP_CENTER, POPUP_FILL, MAIN_MENU_ITEM_WIDTH, 0,
+ 0, 0, 0);
+
+ popup_blank(SPACE_BETWEEN);
+
+ hard_item = popup_menu(menu_quote(quote_difficulty_item2),
+ POPUP_CENTER, POPUP_FILL, MAIN_MENU_ITEM_WIDTH, 0,
+ 0, 0, 0);
+
+
+ popup_width_force(DIFFICULTY_MENU_FORCE_WIDTH);
+
+ game_menu_popup->cancel_item = NULL;
+
+ result = popup_execute();
+
+ kernel.activate_menu = 0;
+
+ if (result == easy_item) {
+ game.difficulty = EASY_MODE;
+ } else {
+ game.difficulty = HARD_MODE;
+ }
+
+ if (result == NULL) {
+ game.going = false;
+ }
+
+ switch (game_menu_popup->key) {
+ case alt_x_key:
+ case ctrl_x_key:
+ case alt_q_key:
+ case ctrl_q_key:
+ case esc_key:
+ game.going = false;
+ break;
+ }
+
+ popup_dialog_destroy();
+}
+
+static void global_menu_main() {
+ PopupItem *save_item;
+ PopupItem *restore_item;
+ PopupItem *score_item;
+ PopupItem *options_item;
+ PopupItem *resume_item;
+ PopupItem *quit_item;
+ PopupItem *result;
+
+ popup_dialog_create(game_menu_popup, GAME_DIALOG_HEAP, 20);
+
+ popup_sprite(box_param.logo, 1, POPUP_CENTER, POPUP_FILL);
+ popup_blank(6);
+
+ save_item = popup_menu(menu_quote(quote_main_item1),
+ POPUP_CENTER, POPUP_FILL, MAIN_MENU_ITEM_WIDTH, 0,
+ 0, 0, 0);
+
+ popup_blank(SPACE_BETWEEN);
+
+ restore_item = popup_menu(menu_quote(quote_main_item2),
+ POPUP_CENTER, POPUP_FILL, MAIN_MENU_ITEM_WIDTH, 0,
+ 0, 0, 0);
+
+ popup_blank(SPACE_BETWEEN);
+
+ score_item = popup_menu(menu_quote(quote_main_item6),
+ POPUP_CENTER, POPUP_FILL, MAIN_MENU_ITEM_WIDTH, 0,
+ 0, 0, 0);
+
+ popup_blank(SPACE_BETWEEN);
+
+ options_item = popup_menu(menu_quote(quote_main_item3),
+ POPUP_CENTER, POPUP_FILL, MAIN_MENU_ITEM_WIDTH, 0,
+ 0, 0, 0);
+
+ popup_blank(SPACE_BETWEEN);
+
+ resume_item = popup_menu(menu_quote(quote_main_item4),
+ POPUP_CENTER, POPUP_FILL, MAIN_MENU_ITEM_WIDTH, 0,
+ 0, 0, 0);
+
+ popup_blank(SPACE_BETWEEN);
+
+ quit_item = popup_menu(menu_quote(quote_main_item5),
+ POPUP_CENTER, POPUP_FILL, MAIN_MENU_ITEM_WIDTH, 0,
+ 0, 0, 0);
+
+ popup_width_force(MAIN_MENU_FORCE_WIDTH);
+ game_menu_popup->cancel_item = resume_item;
+
+ result = popup_execute();
+
+ if (result == save_item) {
+ kernel.activate_menu = 2;
+ } else if (result == restore_item) {
+ kernel.activate_menu = 3;
+ } else if (result == options_item) {
+ kernel.activate_menu = 4;
+ } else if (result == score_item) {
+ kernel.activate_menu = 7;
+ } else {
+ kernel.activate_menu = 0;
+ }
+
+ if (result == quit_item)
+ game.going = false;
+
+ switch (game_menu_popup->key) {
+ case alt_q_key:
+ case alt_x_key:
+ case ctrl_q_key:
+ game.going = false;
+ kernel.activate_menu = 0;
+ break;
+
+ case f5_key:
+ kernel.activate_menu = 2;
+ break;
+
+ case f7_key:
+ kernel.activate_menu = 3;
+ break;
+
+ case f8_key:
+ kernel.activate_menu = 7;
+ break;
+
+ case f10_key:
+ kernel.activate_menu = 4;
+ break;
+
+ default:
+ break;
+ }
+}
+
+void global_game_menu() {
+ bool loaded = false;
+
+ if (box_param.series == NULL) {
+ Common::strcpy_s(box_param.name, "*BOX");
+ if (popup_box_load())
+ goto done;
+ loaded = true;
+ }
+
+ g_engine->flushKeys();
+
+ do {
+ switch (kernel.activate_menu) {
+ case 1:
+ global_menu_main();
+ break;
+ case 2:
+ global_menu_save_restore(true);
+ break;
+ case 3:
+ global_menu_save_restore(false);
+ break;
+ case 4:
+ global_menu_options();
+ break;
+ case 5:
+ global_menu_difficulty();
+ break;
+ case 7:
+ global_menu_score();
+ break;
+ default:
+ kernel.activate_menu = 0;
+ break;
+ }
+ } while (!g_engine->shouldQuit() && game.going && kernel.activate_menu != 0);
+
+ if (loaded) {
+ sprite_free(&box_param.menu, true);
+ sprite_free(&box_param.logo, true);
+ sprite_free(&box_param.series, true);
+ }
+
+done:
+ ;
+}
+
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/menus.h b/engines/mads/madsv2/phantom/menus.h
new file mode 100644
index 00000000000..f2c7a1a5c5a
--- /dev/null
+++ b/engines/mads/madsv2/phantom/menus.h
@@ -0,0 +1,40 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef MADS_PHANTOM_MENUS_H
+#define MADS_PHANTOM_MENUS_H
+
+#include "common/scummsys.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Phantom {
+
+extern void global_menu_system_init();
+extern void global_menu_system_shutdown();
+extern void global_emergency_save();
+extern void global_game_menu();
+
+} // namespace Phantom
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index 5c040c18149..b4c64784a21 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -181,6 +181,7 @@ MODULE_OBJS += \
madsv2/phantom/catacombs.o \
madsv2/phantom/global.o \
madsv2/phantom/main_menu.o \
+ madsv2/phantom/menus.o \
madsv2/phantom/main.o \
madsv2/phantom/sound_phantom.o
endif
Commit: 8c07739708921cb763a60be27d860c408c81b334
https://github.com/scummvm/scummvm/commit/8c07739708921cb763a60be27d860c408c81b334
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:22:59+10:00
Commit Message:
MADS: PHANTOM: Fix cursor loading and object_load
Changed paths:
engines/mads/madsv2/core/game.cpp
engines/mads/madsv2/core/inter.cpp
engines/mads/madsv2/core/inter.h
engines/mads/madsv2/core/kernel.h
engines/mads/madsv2/core/object.cpp
engines/mads/madsv2/core/object.h
engines/mads/madsv2/phantom/main.cpp
diff --git a/engines/mads/madsv2/core/game.cpp b/engines/mads/madsv2/core/game.cpp
index 3b56e0e8ba5..6a425d2a1d6 100644
--- a/engines/mads/madsv2/core/game.cpp
+++ b/engines/mads/madsv2/core/game.cpp
@@ -1285,9 +1285,8 @@ void game_control() {
mouse_disable_scale();
}
- game.going = (byte)!kernel_game_startup(mcga_mode, true,
- global_release_version,
- global_release_date);
+ game.going = (byte)!kernel_game_startup(mcga_mode, KERNEL_STARTUP_ALL_FLAGS,
+ global_release_version, global_release_date);
game_exec_function(game_menu_init);
diff --git a/engines/mads/madsv2/core/inter.cpp b/engines/mads/madsv2/core/inter.cpp
index 95237aed6de..f3bccfd241b 100644
--- a/engines/mads/madsv2/core/inter.cpp
+++ b/engines/mads/madsv2/core/inter.cpp
@@ -213,6 +213,11 @@ void inter_spin_object(int object_id);
void inter_turn_off_object(void);
+void VerbBuf::load(Common::SeekableReadStream *src) {
+ src->readMultipleLE(id, verb_type, prep_type);
+}
+
+
/*
/* inter_set_colors()
/*
diff --git a/engines/mads/madsv2/core/inter.h b/engines/mads/madsv2/core/inter.h
index 225528ad178..4cd8b3c87bf 100644
--- a/engines/mads/madsv2/core/inter.h
+++ b/engines/mads/madsv2/core/inter.h
@@ -160,6 +160,8 @@ struct VerbBuf {
word id;
byte verb_type;
byte prep_type;
+
+ void load(Common::SeekableReadStream *src);
};
typedef struct VerbBuf Verb;
diff --git a/engines/mads/madsv2/core/kernel.h b/engines/mads/madsv2/core/kernel.h
index 86523d1d848..59da91d2983 100644
--- a/engines/mads/madsv2/core/kernel.h
+++ b/engines/mads/madsv2/core/kernel.h
@@ -141,7 +141,7 @@ namespace MADSV2 {
#define KERNEL_STARTUP_CURSOR_SHOW 0x0100
#define KERNEL_STARTUP_VOCAB 0x0080
#define KERNEL_STARTUP_INTERFACE 0x0040
-
+#define KERNEL_STARTUP_ALL_FLAGS 0xffc0
typedef struct {
byte active_flag; /* Sequence is active */
diff --git a/engines/mads/madsv2/core/object.cpp b/engines/mads/madsv2/core/object.cpp
index 0925ff7b005..12a075c7278 100644
--- a/engines/mads/madsv2/core/object.cpp
+++ b/engines/mads/madsv2/core/object.cpp
@@ -56,6 +56,15 @@ int object_ems_handle = BUFFER_PRESERVE;
char object_speech_resource[20] = "*SPCHNOTE.DSR";
+void ObjectBuf::load(Common::SeekableReadStream *src) {
+ src->readMultipleLE(vocab_id, location, prep, num_verbs, num_qualities, syntax);
+ for (int i = 0; i < OBJECT_MAX_VERBS; ++i)
+ verb[i].load(src);
+ src->readMultipleLE(quality_id);
+ src->readMultipleLE(quality_value);
+}
+
+
void object_unload(void) {
if (object != NULL) {
mem_free(object);
@@ -72,15 +81,14 @@ int object_load(void) {
handle = env_open("*OBJECTS.DAT", "rb");
if (handle == NULL) goto done;
- if (!fileio_fread_f(&num_objects, sizeof(int), 1, handle)) goto done;
+ num_objects = handle->readUint16LE();
mem_to_get = sizeof(Object) * num_objects;
object = (ObjectPtr)mem_get_name(mem_to_get, "$objects");
if (object == NULL) goto done;
- for (count = 0; (count < num_objects); count++) {
- if (!fileio_fread_f(&object[count], sizeof(Object), 1, handle)) goto done;
- }
+ for (count = 0; (count < num_objects); count++)
+ object[count].load(handle);
inven_num_objects = 0;
for (count = 0; count < num_objects; count++) {
diff --git a/engines/mads/madsv2/core/object.h b/engines/mads/madsv2/core/object.h
index a7a7906ac5f..a9d49f571b3 100644
--- a/engines/mads/madsv2/core/object.h
+++ b/engines/mads/madsv2/core/object.h
@@ -22,6 +22,7 @@
#ifndef MADS_CORE_OBJECT_H
#define MADS_CORE_OBJECT_H
+#include "common/stream.h"
#include "mads/madsv2/core/general.h"
#include "mads/madsv2/core/vocab.h"
#include "mads/madsv2/core/qual.h"
@@ -55,18 +56,18 @@ typedef struct {
/* Format for storing objects on disk */
struct FileObjectBuf {
- int number; /* Official object number */
+ int16 number; /* Official object number */
char vocab_name[VC_MAXWORDLEN + 1];
char variable_name[VC_MAXWORDLEN + 1];
char desc[80];
- int location;
+ int16 location;
byte prep;
byte num_verbs;
byte num_qualities;
byte syntax;
HagVerb verb[OBJECT_MAX_VERBS];
char quality_name[OBJECT_MAX_QUALITIES][QU_MAXWORDLEN + 1];
- long quality_value[OBJECT_MAX_QUALITIES];
+ int32 quality_value[OBJECT_MAX_QUALITIES];
/* char short_name[OBJECT_SHORT_NAME_LEN + 1]; */
};
@@ -75,14 +76,16 @@ typedef FileObject *FileObjectPtr;
struct ObjectBuf {
word vocab_id; /* Vocab word for name */
- int location; /* Current location */
+ int16 location; /* Current location */
byte prep; /* "Put" preposition */
byte num_verbs; /* Number of special verbs */
byte num_qualities; /* Number of qualities */
byte syntax; /* Syntax */
Verb verb[OBJECT_MAX_VERBS]; /* Verb list for objects */
byte quality_id[OBJECT_MAX_QUALITIES]; /* Quality list */
- long quality_value[OBJECT_MAX_QUALITIES]; /* Quality values */
+ int32 quality_value[OBJECT_MAX_QUALITIES]; /* Quality values */
+
+ void load(Common::SeekableReadStream *src);
};
typedef struct ObjectBuf Object;
diff --git a/engines/mads/madsv2/phantom/main.cpp b/engines/mads/madsv2/phantom/main.cpp
index b70043d6b38..617e23d6d40 100644
--- a/engines/mads/madsv2/phantom/main.cpp
+++ b/engines/mads/madsv2/phantom/main.cpp
@@ -19,6 +19,7 @@
*
*/
+#include "common/config-manager.h"
#include "mads/madsv2/phantom/main.h"
#include "mads/madsv2/core/env.h"
#include "mads/madsv2/core/error.h"
@@ -274,8 +275,14 @@ void phantom_main() {
if (!env_verify())
env_search_mode = ENV_SEARCH_CONCAT_FILES;
+ bool firstTime = !ConfMan.getBool("start_game");
+ selected_item = 0;
+
while (!g_engine->shouldQuit()) {
- main_menu_main();
+ if (firstTime) {
+ main_menu_main();
+ firstTime = false;
+ }
if (!g_engine->shouldQuit()) {
switch (selected_item) {
Commit: 3fbadd3daa00f73e69d9b695e9f338971f1fb992
https://github.com/scummvm/scummvm/commit/3fbadd3daa00f73e69d9b695e9f338971f1fb992
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:00+10:00
Commit Message:
MADS: PHANTOM: Re-enable needed game_control conv code
Changed paths:
engines/mads/madsv2/core/conv.cpp
engines/mads/madsv2/core/conv.h
engines/mads/madsv2/core/game.cpp
diff --git a/engines/mads/madsv2/core/conv.cpp b/engines/mads/madsv2/core/conv.cpp
index 4aad63fdc0a..835a33ca006 100644
--- a/engines/mads/madsv2/core/conv.cpp
+++ b/engines/mads/madsv2/core/conv.cpp
@@ -116,5 +116,9 @@ void conv_release() {
// TODO
}
+void conv_flush() {
+ // TODO
+}
+
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/core/conv.h b/engines/mads/madsv2/core/conv.h
index eb159c073a3..7324f2caef8 100644
--- a/engines/mads/madsv2/core/conv.h
+++ b/engines/mads/madsv2/core/conv.h
@@ -83,6 +83,7 @@ extern int *conv_get_variable(int varNum);
extern void conv_export_value(int varNum);
extern void conv_hold();
extern void conv_release();
+extern void conv_flush();
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/core/game.cpp b/engines/mads/madsv2/core/game.cpp
index 6a425d2a1d6..e134e480b32 100644
--- a/engines/mads/madsv2/core/game.cpp
+++ b/engines/mads/madsv2/core/game.cpp
@@ -31,6 +31,7 @@
#include "mads/madsv2/core/inter.h"
#include "mads/madsv2/core/matte.h"
#include "mads/madsv2/core/mouse.h"
+#include "mads/madsv2/core/speech.h"
#include "mads/madsv2/core/timer.h"
#include "mads/madsv2/core/video.h"
#include "mads/madsv2/core/buffer.h"
@@ -1271,16 +1272,12 @@ void game_copy_speech_files(int room_) {
void game_control() {
int count, color;
int result;
+ bool aborted_conv = true;
/* Start up game level functions */
error_service_routine_2 = game_error_service;
- /*
- if (config_file.mouse_cursor_fix == MOUSE_NOT_MICROSOFT) {
- mouse_disable_scale();
- }
- */
if (game_mouse_cursor_fix) {
mouse_disable_scale();
}
@@ -1441,7 +1438,7 @@ void game_control() {
if (player.walker_is_loaded) {
player_dump_walker();
}
-
+#if 0
if (int_sprite[fx_int_journal] != -1 && room_id != KERNEL_RESTORING_GAME) {
matte_deallocate_series(int_sprite[fx_int_candle_on], true);
matte_deallocate_series(int_sprite[fx_int_dooropen], true);
@@ -1453,11 +1450,11 @@ void game_control() {
}
g_engine->section_music(section_id);
-
+#endif
pal_init(KERNEL_RESERVED_LOW_COLORS, KERNEL_RESERVED_HIGH_COLORS);
matte_init(true);
-
+#if 0
if (!player.walker_is_loaded) {
int_sprite[fx_int_journal] = kernel_load_series("*journal", false);
int_sprite[fx_int_backpack] = kernel_load_series("*backpack", false);
@@ -1466,7 +1463,7 @@ void game_control() {
int_sprite[fx_int_dooropen] = kernel_load_series("*dooropen", false);
int_sprite[fx_int_candle_on] = kernel_load_series("*candleon", false);
}
-
+#endif
} else {
/* paul - call my special preserve palette routine in extra_1 */
/* player_preserve_palette(); */
@@ -1637,28 +1634,22 @@ void game_control() {
/* ********************************************************************************************** */
- global[16] = false; /* dont_load_walker */
-
- /* pl if (speech_system_active && speech_on) {
+ if (speech_system_active && speech_on)
speech_all_off();
- }
- */
emergency:
game_wait_cursor();
kernel_mode = KERNEL_ROOM_PRELOAD;
- /* pl if (!game.going) {
- aborted_conv = conv_control.running;
- }
-
+ if (!game.going)
+ aborted_conv = conv_control.running;
conv_abort();
- */
/* Shutdown the current room structures */
- if (kernel.quotes != NULL) mem_free(kernel.quotes);
+ if (kernel.quotes != NULL)
+ mem_free(kernel.quotes);
kernel_abort_all_animations();
@@ -1676,7 +1667,7 @@ emergency:
kernel_room_shutdown();
- /* pl conv_flush(); */
+ conv_flush();
new_section = new_room / 100;
@@ -1684,15 +1675,14 @@ emergency:
himem_flush(ROOM);
- if (!game.going && !win_status && section_id != 9 /* && !global[copy_protect_failed] */) {
- /* pl conv_control.running = aborted_conv; */
+ if (!game.going && !win_status) {
+ conv_control.running = aborted_conv;
game_save_name(0);
kernel_save_game(save_game_buf);
game_autosaved = true;
} else {
game_autosaved = false;
}
-
}
/* remove .RAC and .RAW files */
Commit: 682efb4f68710e1b1ef0fa6c5aaf2cc59318590c
https://github.com/scummvm/scummvm/commit/682efb4f68710e1b1ef0fa6c5aaf2cc59318590c
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:00+10:00
Commit Message:
MADS: PHANTOM: Fix incorrect starting room
Changed paths:
engines/mads/madsv2/phantom/main.cpp
diff --git a/engines/mads/madsv2/phantom/main.cpp b/engines/mads/madsv2/phantom/main.cpp
index 617e23d6d40..a7ed5ab2d9f 100644
--- a/engines/mads/madsv2/phantom/main.cpp
+++ b/engines/mads/madsv2/phantom/main.cpp
@@ -159,9 +159,8 @@ static void game_main(int argc, const char **argv) {
mads_mode = env_verify();
- new_section = 9;
- new_room = 901;
-
+ new_section = 1;
+ new_room = 101;
player.x = 160;
player.y = 78;
Commit: 9ef4647d67663c376a9474602b5538f783453e3a
https://github.com/scummvm/scummvm/commit/9ef4647d67663c376a9474602b5538f783453e3a
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:00+10:00
Commit Message:
MADS: PHANTOM: Dummy EMS implementation
The ems_page array is used by the tile_load code, so it needed
to have allocated memory.
Changed paths:
engines/mads/madsv2/core/ems.cpp
engines/mads/madsv2/core/ems.h
engines/mads/madsv2/core/kernel.cpp
diff --git a/engines/mads/madsv2/core/ems.cpp b/engines/mads/madsv2/core/ems.cpp
index 07b06737c5b..029e39d7708 100644
--- a/engines/mads/madsv2/core/ems.cpp
+++ b/engines/mads/madsv2/core/ems.cpp
@@ -41,5 +41,40 @@ int ems_mapping_changed = 0;
int ems_page_mapped[4] = {};
int ems_page_stack[4] = {};
+static byte *ems_physical_pool = nullptr;
+
+bool ems_driver = false;
+bool ems_exists = false;
+
+bool ems_detect() {
+ if (ems_disabled)
+ return false;
+
+ ems_physical_pool = new byte[4 * EMS_PAGE_SIZE](); // zero-initialised
+ if (!ems_physical_pool)
+ return false;
+
+ for (int i = 0; i < 4; i++) {
+ ems_page[i] = ems_physical_pool + i * EMS_PAGE_SIZE;
+ ems_page_mapped[i] = i;
+ }
+
+ ems_high_version = 4;
+ ems_low_version = 0;
+ ems_driver = true;
+ ems_exists = true;
+ return true;
+}
+
+void ems_shutdown() {
+ delete[] ems_physical_pool;
+ ems_physical_pool = nullptr;
+
+ for (int i = 0; i < 4; i++)
+ ems_page[i] = nullptr;
+
+ ems_exists = false;
+}
+
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/core/ems.h b/engines/mads/madsv2/core/ems.h
index 92a022c54b3..664bca73cb7 100644
--- a/engines/mads/madsv2/core/ems.h
+++ b/engines/mads/madsv2/core/ems.h
@@ -61,8 +61,8 @@ typedef struct {
} EmsPtr;
-constexpr bool ems_driver = false; /* Flag if EMS driver is installed */
-constexpr bool ems_exists = false; /* Flag if we've got some EMS available */
+extern bool ems_driver; /* Flag if EMS driver is installed */
+extern bool ems_exists; /* Flag if we've got some EMS available */
extern word ems_page_frame; /* Segment address of EMS page frame */
extern word ems_handle; /* EMS handle of our allocated pages */
extern word ems_pages; /* # of pages EMS allocated for us */
@@ -93,15 +93,12 @@ extern int ems_page_stack[4];
* Returns "false" if EMS did not exist, if no pages were available,
* or if an error occurred.
*/
-inline bool ems_detect() {
- return false;
-}
+extern bool ems_detect();
/**
* Frees up any EMS memory that might have been allocated by ems_detect().
*/
-inline void ems_shutdown() {
-}
+extern void ems_shutdown();
/**
* Maps a logical page (0 - (ems_pages-1)) to a physical page (0-3).
diff --git a/engines/mads/madsv2/core/kernel.cpp b/engines/mads/madsv2/core/kernel.cpp
index 3e28b260871..d1477cd3f32 100644
--- a/engines/mads/madsv2/core/kernel.cpp
+++ b/engines/mads/madsv2/core/kernel.cpp
@@ -355,7 +355,7 @@ int kernel_game_startup(int game_video_mode, int load_flag,
if (ems_exists) {
pages = ems_pages_free;
for (count = 0; count < EMS_PAGING_CLASSES; count++) {
- reserve[EMS_PAGING_CLASSES] = 0;
+ reserve[count] = 0;
}
if (pages >= 4) {
reserve[EMS_PAGING_SYSTEM] = 4;
Commit: 82a7e0ad78430cf544999e3ee071224ee547dda4
https://github.com/scummvm/scummvm/commit/82a7e0ad78430cf544999e3ee071224ee547dda4
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:01+10:00
Commit Message:
MADS: PHANTOM: Fix loading hotspots
Changed paths:
engines/mads/madsv2/core/room.cpp
engines/mads/madsv2/core/room.h
diff --git a/engines/mads/madsv2/core/room.cpp b/engines/mads/madsv2/core/room.cpp
index 0b5f4ed72a2..fcfa0b728e8 100644
--- a/engines/mads/madsv2/core/room.cpp
+++ b/engines/mads/madsv2/core/room.cpp
@@ -384,7 +384,7 @@ HotPtr room_load_hotspots(int id, int *num_spots) {
{
byte buffer[2];
- if (!loader_read(buffer, sizeof(int), 1, &load_handle))
+ if (!loader_read(buffer, 2, 1, &load_handle))
goto done;
*num_spots = READ_LE_UINT16(buffer);
@@ -401,7 +401,7 @@ HotPtr room_load_hotspots(int id, int *num_spots) {
{
size_t bytes_to_read = num_to_read * HotSpot::SIZE;
byte *buffer = (byte *)malloc(bytes_to_read);
- if (!loader_read(spots, memory_needed, 1, &load_handle)) {
+ if (!loader_read(buffer, memory_needed, 1, &load_handle)) {
free(buffer);
goto done;
}
diff --git a/engines/mads/madsv2/core/room.h b/engines/mads/madsv2/core/room.h
index 10795b9a952..661618cd225 100644
--- a/engines/mads/madsv2/core/room.h
+++ b/engines/mads/madsv2/core/room.h
@@ -100,10 +100,11 @@ struct HotSpot {
byte active; /* Flag if hotspot is active */
byte cursor_number; /* Mouse cursor number */
byte syntax; /* Syntax */
+ //-- padding byte--
int16 vocab; /* Vocabulary id of hotspot name */
int16 verb; /* Vocabulary id of default verb */
- static constexpr int SIZE = 6 * 2 + (5 * 1) + 2 + 2;
+ static constexpr int SIZE = 6 * 2 + (5 * 1) + 1 + 2 + 2;
void load(Common::SeekableReadStream *src);
};
Commit: dabef2b2314ac45ed817dfc0887065fd3077b7c6
https://github.com/scummvm/scummvm/commit/dabef2b2314ac45ed817dfc0887065fd3077b7c6
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:02+10:00
Commit Message:
MADS: PHANTOM: Match max hotspots to original
Changed paths:
engines/mads/madsv2/core/hspot.h
diff --git a/engines/mads/madsv2/core/hspot.h b/engines/mads/madsv2/core/hspot.h
index 90b41065939..86341d22016 100644
--- a/engines/mads/madsv2/core/hspot.h
+++ b/engines/mads/madsv2/core/hspot.h
@@ -27,7 +27,7 @@
namespace MADS {
namespace MADSV2 {
-#define max_hot_spots 80 /* Size of hotspot list */
+#define max_hot_spots 120 /* Size of hotspot list */
#define max_hot_lists 2 /* Maximum # of lists */
#define HS_ALL -1 /* Pass in ERASE to wipe entire class */
Commit: b195f24cef4491f3588767a81bb56393e4778572
https://github.com/scummvm/scummvm/commit/b195f24cef4491f3588767a81bb56393e4778572
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:02+10:00
Commit Message:
MADS: PHANTOM: Fix font loading
Changed paths:
engines/mads/madsv2/core/font.cpp
engines/mads/madsv2/core/inter.cpp
diff --git a/engines/mads/madsv2/core/font.cpp b/engines/mads/madsv2/core/font.cpp
index 801d993f991..5092483c775 100644
--- a/engines/mads/madsv2/core/font.cpp
+++ b/engines/mads/madsv2/core/font.cpp
@@ -19,6 +19,7 @@
*
*/
+#include "common/algorithm.h"
#include "mads/madsv2/core/general.h"
#include "mads/madsv2/core/mem.h"
#include "mads/madsv2/core/error.h"
@@ -30,6 +31,9 @@
namespace MADS {
namespace MADSV2 {
+constexpr int OFFSETS_OFFSET = 2 + FONT_SIZE;
+constexpr int HEADER_SIZE = 2 + FONT_SIZE + (FONT_SIZE * 2);
+
FontPtr font_inter = NULL;
FontPtr font_main = NULL; /* Interface & main font handles */
FontPtr font_conv = NULL;
@@ -43,10 +47,12 @@ FontPtr font_load(const char *name) {
char temp_buf_2[80];
char *mark;
char block_name[20];
- long size;
+ long size, dataSize;
FontPtr new_font = NULL;
FontPtr result = NULL;
Load load_handle;
+ byte *buffer;
+ int i;
mem_last_alloc_loader = MODULE_FONT_LOADER;
@@ -66,11 +72,33 @@ FontPtr font_load(const char *name) {
if (loader_open(&load_handle, temp_buf_2, "rb", true)) goto done;
size = load_handle.pack.strategy[0].size;
+ dataSize = size - HEADER_SIZE; // Size for just the pixel data section
+
+ new_font = (FontPtr)mem_get_name(sizeof(FontBuf) + dataSize, block_name);
+ if (new_font == NULL)
+ goto done;
+
+ // Get the font resource into a temporary buffer
+ buffer = (byte *)malloc(size);
+ if (!buffer || !loader_read(buffer, size, 1, &load_handle)) {
+ free(buffer);
+ goto done;
+ }
+
+ // Copy data from the temporary buffer into the font
+ new_font->max_y_size = buffer[0];
+ new_font->max_x_size = buffer[1];
+ Common::copy(buffer + 2, buffer + OFFSETS_OFFSET, &new_font->width[0]);
+ Common::copy(buffer + HEADER_SIZE, buffer + size, (byte *)new_font + sizeof(FontBuf));
- new_font = (FontPtr)mem_get_name(size, block_name);
- if (new_font == NULL) goto done;
+ // Set up the individual pointers to the start of each character's data
+ for (i = 0; i < FONT_SIZE; ++i) {
+ int offset = READ_LE_UINT16(buffer + OFFSETS_OFFSET + i * 2);
+ new_font->data[i] = (byte *)new_font + sizeof(FontBuf) + (offset - HEADER_SIZE);
+ }
- if (!loader_read(new_font, size, 1, &load_handle)) goto done;
+ // Free the buffer
+ free(buffer);
result = new_font;
diff --git a/engines/mads/madsv2/core/inter.cpp b/engines/mads/madsv2/core/inter.cpp
index f3bccfd241b..dc8de558380 100644
--- a/engines/mads/madsv2/core/inter.cpp
+++ b/engines/mads/madsv2/core/inter.cpp
@@ -466,7 +466,8 @@ write:
}
}
- if (write_it) font_write(font_inter, &scr_inter, temp_buf, x, y, 0);
+ if (write_it)
+ font_write(font_inter, &scr_inter, temp_buf, x, y, 0);
done:
;
Commit: d02bf3e3c703bd6451427a8d53816f529184a153
https://github.com/scummvm/scummvm/commit/d02bf3e3c703bd6451427a8d53816f529184a153
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:03+10:00
Commit Message:
MADS: PHANTOM: Room startup sound fixes
Changed paths:
engines/mads/madsv2/core/game.cpp
engines/mads/madsv2/core/sound.cpp
engines/mads/madsv2/core/sound.h
diff --git a/engines/mads/madsv2/core/game.cpp b/engines/mads/madsv2/core/game.cpp
index e134e480b32..f245cbdb9ba 100644
--- a/engines/mads/madsv2/core/game.cpp
+++ b/engines/mads/madsv2/core/game.cpp
@@ -31,6 +31,7 @@
#include "mads/madsv2/core/inter.h"
#include "mads/madsv2/core/matte.h"
#include "mads/madsv2/core/mouse.h"
+#include "mads/madsv2/core/sound.h"
#include "mads/madsv2/core/speech.h"
#include "mads/madsv2/core/timer.h"
#include "mads/madsv2/core/video.h"
@@ -1257,10 +1258,6 @@ void start_the_copy_process(char orig_path[80]) {
error("TODO: start_the_copy_process");
}
-void game_copy_speech_files(int room_) {
- error("TODO: game_copy_speech_files");
-}
-
/*
/* game_control()
/*
@@ -1496,13 +1493,11 @@ void game_control() {
game.going = (byte)!kernel_room_startup(new_room, kernel_initial_variant, kernel.interface, false);
- game_copy_speech_files(new_room);
-
camera_init_default();
game_set_camera_speed();
- /* pl sound_queue_hold(); */
+ sound_queue_hold();
/* Load current player walker set */
diff --git a/engines/mads/madsv2/core/sound.cpp b/engines/mads/madsv2/core/sound.cpp
index 6b9f5a2f4a0..446352096ed 100644
--- a/engines/mads/madsv2/core/sound.cpp
+++ b/engines/mads/madsv2/core/sound.cpp
@@ -34,6 +34,10 @@ int sound_queue(int soundNum) {
return g_engine->_soundManager->command(soundNum);
}
+void sound_queue_hold() {
+ g_engine->_soundManager->pauseNewCommands();
+}
+
void sound_queue_flush() {
g_engine->_soundManager->startQueuedCommands();
}
diff --git a/engines/mads/madsv2/core/sound.h b/engines/mads/madsv2/core/sound.h
index 96cf23adec0..231a6cacf04 100644
--- a/engines/mads/madsv2/core/sound.h
+++ b/engines/mads/madsv2/core/sound.h
@@ -32,6 +32,7 @@ constexpr bool global_prefer_roland = false;
extern int sound_play(int soundNum);
extern int sound_queue(int soundNum);
+extern void sound_queue_hold();
extern void sound_queue_flush();
} // namespace MADSV2
Commit: 90736ad938ff80096593b7f5a1c6f1f11c31cd0a
https://github.com/scummvm/scummvm/commit/90736ad938ff80096593b7f5a1c6f1f11c31cd0a
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:03+10:00
Commit Message:
MADS: PHANTOM: Fix buffer overrun in tile_buffer from tile_pan
Confirmed that in the original the same buffer overun occurs,
so I've added a workaround to limit the X loop to the
allowed width
Changed paths:
engines/mads/madsv2/core/tile.cpp
diff --git a/engines/mads/madsv2/core/tile.cpp b/engines/mads/madsv2/core/tile.cpp
index 03cd162ba8c..294d9bf1ffa 100644
--- a/engines/mads/madsv2/core/tile.cpp
+++ b/engines/mads/madsv2/core/tile.cpp
@@ -603,6 +603,7 @@ int tile_buffer(Buffer *target,
int tile_page_number;
int last_page = -1;
Buffer tile_buffer;
+ int max_x;
default_value = (map->tile_type == TILE_PICTURE) ? 0 : 0xff;
@@ -615,12 +616,15 @@ int tile_buffer(Buffer *target,
tile_buffer.x = size_x;
tile_buffer.y = map->tile_y_size;
+ // WORKAROUND: For tile panning reading beyond end of buffer
+ max_x = MIN<int>(map->orig_x_tiles, map->num_x_tiles - tile_x);
+
for (y = 0; y < map->orig_y_tiles; y++) {
picture_y = y * map->tile_y_size;
map_y_offset = (y + tile_y) * map->num_x_tiles;
- for (x = 0; x < map->orig_x_tiles; x++) {
+ for (x = 0; x < max_x; x++) {
picture_x = x * size_x;
map_value = *(map->map + map_y_offset + tile_x + x);
Commit: 3185ffc838575bb76bc776456bd9b4f7b535a22c
https://github.com/scummvm/scummvm/commit/3185ffc838575bb76bc776456bd9b4f7b535a22c
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:04+10:00
Commit Message:
MADS: PHANTOM: Ifdef out unused code
I think it may be from Once Upon a Forest, so I'm not
removing it entirely yet
Changed paths:
engines/mads/madsv2/core/game.cpp
diff --git a/engines/mads/madsv2/core/game.cpp b/engines/mads/madsv2/core/game.cpp
index f245cbdb9ba..294f438a6bf 100644
--- a/engines/mads/madsv2/core/game.cpp
+++ b/engines/mads/madsv2/core/game.cpp
@@ -2049,6 +2049,7 @@ static void game_main_loop() {
/* these 3 are for the background efx */
long dif;
+#if 0
if (global[10]) { /* please play the damn targets */
/* this is for the background sound efx */
@@ -2109,7 +2110,6 @@ static void game_main_loop() {
}
}
-
if (player.walker_visible && player.commands_allowed && section_id != 9 && lets_get_a_move_on_anim &&
!player.walking && !player.need_to_walk && move_your_butt_anim_handle == -1) {
move_your_butt_enabled = 1;
@@ -2205,6 +2205,7 @@ static void game_main_loop() {
/* Clear any remaining player command message from screen */
+#endif
if (inter_sentence_ready || !player.commands_allowed) {
inter_init_sentence();
Commit: d4a7497671684c86e1d7beaf340a0481d5a379f2
https://github.com/scummvm/scummvm/commit/d4a7497671684c86e1d7beaf340a0481d5a379f2
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:04+10:00
Commit Message:
MADS: PHANTOM: Fix duplication of rails globals
Changed paths:
engines/mads/madsv2/core/kernel.cpp
engines/mads/madsv2/core/rail.cpp
engines/mads/madsv2/core/rail.h
diff --git a/engines/mads/madsv2/core/kernel.cpp b/engines/mads/madsv2/core/kernel.cpp
index d1477cd3f32..672e393fc58 100644
--- a/engines/mads/madsv2/core/kernel.cpp
+++ b/engines/mads/madsv2/core/kernel.cpp
@@ -686,7 +686,7 @@ int kernel_room_startup(int newRoom, int initial_variant, const char *interface,
/* Initialize rail-system parameters for this room */
rail_num_nodes = room->num_rails + 2;
- rail_base = (byte *) & room->rail[0];
+ rail_base = &room->rail[0];
rail_connect_all_nodes();
diff --git a/engines/mads/madsv2/core/rail.cpp b/engines/mads/madsv2/core/rail.cpp
index 998328baed2..6d1c8411021 100644
--- a/engines/mads/madsv2/core/rail.cpp
+++ b/engines/mads/madsv2/core/rail.cpp
@@ -61,24 +61,12 @@ namespace MADSV2 {
* then RAIL_MAX_NODES (12) weight words = 24 bytes,
* padding to reach 48 bytes total.
* ---------------------------------------------------------------------- */
-typedef struct {
- unsigned char header[RAIL_STRUCTURE_WEIGHT_OFFSET]; /* 4 bytes */
- uint16 weight[RAIL_MAX_NODES]; /* 24 bytes (12 words) */
- unsigned char padding[48 - 4 - 24]; /* 20 bytes padding */
-} RailNode;
+struct RailNode {
+ unsigned char header[RAIL_STRUCTURE_WEIGHT_OFFSET]; /* 4 bytes */
+ uint16 weight[RAIL_MAX_NODES]; /* 24 bytes (12 words) */
+ byte padding[48 - 4 - 24]; /* 20 bytes padding */
+};
-/* -------------------------------------------------------------------------
- * Global variables (COMM in the original -- shared across modules)
- * ---------------------------------------------------------------------- */
-uint16 _rail_solution_stack_pointer;
-uint16 _rail_solution_stack_weight;
-
-unsigned char _rail_visited[RAIL_MAX_NODES];
-unsigned char _rail_working_stack[RAIL_MAX_NODES];
-unsigned char _rail_solution_stack[RAIL_MAX_NODES];
-
-uint16 _rail_num_nodes;
-RailNode *_rail_base; /* far ptr in original; flat ptr here */
word rail_solution_stack_pointer;
word rail_solution_stack_weight;
@@ -86,7 +74,7 @@ byte rail_visited[RAIL_MAX_NODES];
byte rail_working_stack[RAIL_MAX_NODES];
byte rail_solution_stack[RAIL_MAX_NODES];
word rail_num_nodes;
-byte *rail_base;
+Rail *rail_base;
byte rail_active[ROOM_MAX_RAILS + 2];
@@ -184,18 +172,18 @@ static void recursive_check_path(int node_id,
uint16 allow_mode,
int working_sp) {
/* visited[node_id] = true */
- _rail_visited[node_id] = 1;
+ rail_visited[node_id] = 1;
/* push(node_id) onto working stack */
- _rail_working_stack[working_sp] = (unsigned char)node_id;
+ rail_working_stack[working_sp] = (unsigned char)node_id;
working_sp++;
/* Point at rail[node_id] */
- RailNode *node = &_rail_base[node_id];
+ Rail *node = &rail_base[node_id];
/* The source node is second-to-last: index = num_nodes - 2.
We look up the weight from node_id to the source (from_node). */
- int from_node = _rail_num_nodes - 2;
+ int from_node = rail_num_nodes - 2;
uint16 raw_weight = node->weight[from_node];
/* Check whether there is a direct legal path to the destination */
@@ -203,12 +191,12 @@ static void recursive_check_path(int node_id,
uint16 leg_weight = raw_weight & RAIL_WEIGHT_MASK;
uint16 total = weight + leg_weight;
- if (total < _rail_solution_stack_weight) {
+ if (total < rail_solution_stack_weight) {
/* This is a better solution -- save it */
int stack_len = working_sp; /* number of bytes currently on stack */
- memcpy(_rail_solution_stack, _rail_working_stack, stack_len);
- _rail_solution_stack_pointer = (uint16)stack_len;
- _rail_solution_stack_weight = total;
+ memcpy(rail_solution_stack, rail_working_stack, stack_len);
+ rail_solution_stack_pointer = (uint16)stack_len;
+ rail_solution_stack_weight = total;
}
} else {
/*
@@ -216,12 +204,12 @@ static void recursive_check_path(int node_id,
* Intermediate nodes are indices 0 .. (num_nodes - 3); the last two
* entries in the array are the destination and source nodes.
*/
- int num_intermediate = _rail_num_nodes - 2;
+ int num_intermediate = rail_num_nodes - 2;
for (int i = 0; i < num_intermediate; i++) {
int test_node = i; /* loop counter - 1 in the ASM */
- if (_rail_visited[test_node])
+ if (rail_visited[test_node])
continue;
/* Check edge weight from current node to test_node */
@@ -243,22 +231,22 @@ static void recursive_check_path(int node_id,
}
/* visited[node_id] = false (unwind) */
- _rail_visited[node_id] = 0;
+ rail_visited[node_id] = 0;
/* pop() -- working_sp is a local copy so this just falls off the frame */
}
void rail_check_path(int allow_one_illegal) {
/* Clear the visited array */
- memset(_rail_visited, 0, _rail_num_nodes);
+ memset(rail_visited, 0, rail_num_nodes);
/* Initialise solution state to "no solution yet" */
- _rail_solution_stack_weight = RAIL_WEIGHT_MASK;
- _rail_solution_stack_pointer = 0;
+ rail_solution_stack_weight = RAIL_WEIGHT_MASK;
+ rail_solution_stack_pointer = 0;
/* The last node in the array (index num_nodes - 1) is the starting
node for the search (the destination, in path terms) */
- int start_node = _rail_num_nodes - 1;
+ int start_node = rail_num_nodes - 1;
uint16 allow_mode = allow_one_illegal ? RAIL_ALLOW_ILLEGAL
: RAIL_ALLOW_LEGAL_ONLY;
diff --git a/engines/mads/madsv2/core/rail.h b/engines/mads/madsv2/core/rail.h
index 180bad8bc29..da00857e492 100644
--- a/engines/mads/madsv2/core/rail.h
+++ b/engines/mads/madsv2/core/rail.h
@@ -35,7 +35,7 @@ extern byte rail_working_stack[RAIL_MAX_NODES];
extern byte rail_solution_stack[RAIL_MAX_NODES];
extern word rail_num_nodes;
-extern byte *rail_base;
+extern struct Rail *rail_base;
extern void rail_add_node(int id, int x, int y);
extern void rail_connect_node(int id);
Commit: 9d6a6cba819dcc16e1860f1ba6d908706d85d84f
https://github.com/scummvm/scummvm/commit/9d6a6cba819dcc16e1860f1ba6d908706d85d84f
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:04+10:00
Commit Message:
MAP: PHANTOM: Properly map a000:0 pointers to use _screen surface
Changed paths:
engines/mads/madsv2/core/game.cpp
engines/mads/madsv2/core/general.h
engines/mads/madsv2/core/magic.cpp
engines/mads/madsv2/core/matte.cpp
engines/mads/madsv2/core/mcga.cpp
engines/mads/madsv2/core/screen.cpp
engines/mads/madsv2/core/window.cpp
engines/mads/madsv2/engine.cpp
engines/mads/madsv2/phantom/main_menu.cpp
engines/mads/madsv2/phantom/phantom.cpp
diff --git a/engines/mads/madsv2/core/game.cpp b/engines/mads/madsv2/core/game.cpp
index 294f438a6bf..03dabe2e37a 100644
--- a/engines/mads/madsv2/core/game.cpp
+++ b/engines/mads/madsv2/core/game.cpp
@@ -80,7 +80,7 @@ extern int room_state[40];
#define MOVE_YOUR_BUTT_TIMEOUT 3600
#define MAX_SPEECH_FILES_PER_ROOM 100
-Buffer scr_live = { video_y, video_x, mcga_video };
+Buffer scr_live = { video_y, video_x, nullptr };
char config_file_name[20];
int win_status = WIN_NOTHING;
@@ -2040,16 +2040,16 @@ static void game_main_loop() {
int temp_message_2 = 0;
int temp_message_3 = 0;
int temp_message_4 = 0;
- int yy;
long one_clock, two_clock;
static char temp_buf[20];
static char temp_buf_2[20];
static char temp_buf_3[20];
static char temp_buf_4[20];
- /* these 3 are for the background efx */
- long dif;
#if 0
+ /* these 3 are for the background efx */
+ int yy;
+ long dif;
if (global[10]) { /* please play the damn targets */
/* this is for the background sound efx */
@@ -2637,7 +2637,7 @@ done:
void game_debugger_reset() {
- screen = mono_text_video;
+ //screen = mono_text_video;
screen_normal_color = colorbyte(hi_white, black);
screen_hilite_color = screen_normal_color + 128;
diff --git a/engines/mads/madsv2/core/general.h b/engines/mads/madsv2/core/general.h
index 2c28ea7e71d..e3879d59cc1 100644
--- a/engines/mads/madsv2/core/general.h
+++ b/engines/mads/madsv2/core/general.h
@@ -93,12 +93,7 @@ typedef struct { /* Video buffer structure */
#define display_y 156 /* Picture area max Y size */
-#define color_text_video (byte *)0xb8000000 /* text mode address */
-#define mono_text_video (byte *)0xb0000000 /* herc/mono address */
-#define mcga_video (byte *)0xa0000000 /* 256 color address */
-#define tandy_video (byte *)0xb8000000 /* Tandy clr address */
-#define ega_video (byte *)0xa0000000 /* EGA color address */
-#define iaca (byte *)0x004000f0 /* The bad place */
+#define mcga_video (byte *)g_engine->getScreen()->getPixels()
#define text_mode 0x03
#define mono_text_mode 0x07
diff --git a/engines/mads/madsv2/core/magic.cpp b/engines/mads/madsv2/core/magic.cpp
index 8a0bed8d599..f8416336f6a 100644
--- a/engines/mads/madsv2/core/magic.cpp
+++ b/engines/mads/madsv2/core/magic.cpp
@@ -31,6 +31,7 @@
#include "mads/madsv2/core/sort.h"
#include "mads/madsv2/core/timer.h"
#include "mads/madsv2/core/video.h"
+#include "mads/madsv2/engine.h"
namespace MADS {
namespace MADSV2 {
diff --git a/engines/mads/madsv2/core/matte.cpp b/engines/mads/madsv2/core/matte.cpp
index 5398e23bd31..28d7a9826a9 100644
--- a/engines/mads/madsv2/core/matte.cpp
+++ b/engines/mads/madsv2/core/matte.cpp
@@ -35,6 +35,7 @@
#include "mads/madsv2/core/keys.h"
#include "mads/madsv2/core/timer.h"
#include "mads/madsv2/core/sound.h"
+#include "mads/madsv2/engine.h"
#define word_align_mattes
#ifndef disable_error_check
diff --git a/engines/mads/madsv2/core/mcga.cpp b/engines/mads/madsv2/core/mcga.cpp
index f5f5b4e94f0..6fdf9592a0c 100644
--- a/engines/mads/madsv2/core/mcga.cpp
+++ b/engines/mads/madsv2/core/mcga.cpp
@@ -70,7 +70,7 @@ byte *mcga_open_window(word x, word y, word xsize, word ysize) {
*run++ = xsize;
*run++ = ysize;
- live = (mcga_video + x + y * 320);
+ live = (byte *)g_engine->getScreen()->getBasePtr(x, y);
for (yy = 1; yy <= ysize; yy++) {
memcpy(work, live, xsize);
@@ -94,7 +94,7 @@ void mcga_close_window(byte *inp) {
xsize = *run++;
ysize = *run++;
- live = (mcga_video + x + y * 320);
+ live = (byte *)g_engine->getScreen()->getBasePtr(x, y);
for (yy = 1; yy <= ysize; yy++) {
memcpy(live, work, xsize);
diff --git a/engines/mads/madsv2/core/screen.cpp b/engines/mads/madsv2/core/screen.cpp
index d5db60c6186..6967cf79a48 100644
--- a/engines/mads/madsv2/core/screen.cpp
+++ b/engines/mads/madsv2/core/screen.cpp
@@ -38,7 +38,7 @@ int screen_center_y = 0;
Window screen_active = { 0,0,79,24,NULL }; /* The currently active window */
-byte *screen = color_text_video;
+byte *screen = nullptr; // color_text_video;
int *screen_bound_x = &screen_max_x;
diff --git a/engines/mads/madsv2/core/window.cpp b/engines/mads/madsv2/core/window.cpp
index 132f222faa1..3cd13b33d12 100644
--- a/engines/mads/madsv2/core/window.cpp
+++ b/engines/mads/madsv2/core/window.cpp
@@ -99,7 +99,7 @@ void window_shadow(WindowPtr window) {
short x_count, y_count, max_x, max_y;
short my_color;
- if (screen == mono_text_video) {
+ if (screen == nullptr /*mono_text_video*/) {
my_color = colorbyte(black, black);
} else {
my_color = window_shadow_color;
diff --git a/engines/mads/madsv2/engine.cpp b/engines/mads/madsv2/engine.cpp
index 5e8368b5acd..b5d299ed55a 100644
--- a/engines/mads/madsv2/engine.cpp
+++ b/engines/mads/madsv2/engine.cpp
@@ -49,6 +49,9 @@ void MADSV2Engine::pollEvents() {
// Check for screen update time
uint32 time = g_system->getMillis();
if (time >= _nextFrameTime) {
+ // Because the screen is accessed directly via Buffer objects,
+ // we need to do a full screen update each frame
+ _screen->markAllDirty();
_screen->update();
_nextFrameTime = time + GAME_FRAME_TIME;
}
diff --git a/engines/mads/madsv2/phantom/main_menu.cpp b/engines/mads/madsv2/phantom/main_menu.cpp
index 92a87969a3d..f1fa3f3d918 100644
--- a/engines/mads/madsv2/phantom/main_menu.cpp
+++ b/engines/mads/madsv2/phantom/main_menu.cpp
@@ -83,8 +83,6 @@ ConfigFile config_file;
int mads_mode = false;
-Buffer scr_live = { video_y, video_x, mcga_video };
-
FontPtr font = NULL;
int font_auto_spacing = -1;
diff --git a/engines/mads/madsv2/phantom/phantom.cpp b/engines/mads/madsv2/phantom/phantom.cpp
index 29828f4606e..3db8596f429 100644
--- a/engines/mads/madsv2/phantom/phantom.cpp
+++ b/engines/mads/madsv2/phantom/phantom.cpp
@@ -30,6 +30,7 @@
#include "mads/madsv2/core/kernel.h"
#include "mads/madsv2/core/object.h"
#include "mads/madsv2/core/pal.h"
+#include "mads/madsv2/core/screen.h"
#include "mads/madsv2/core/text.h"
#include "mads/madsv2/phantom/phantom.h"
#include "mads/madsv2/phantom/main.h"
@@ -49,6 +50,8 @@ namespace Phantom {
Common::Error PhantomEngine::run() {
initGraphics(320, 200);
_screen = new Graphics::Screen();
+ scr_live.data = (byte *)_screen->getPixels();
+
_soundManager = new PhantomSoundManager(_mixer, _soundFlag);
_soundManager->validate();
Commit: 06708e46a079e63765c32c8cb32c566a170603ab
https://github.com/scummvm/scummvm/commit/06708e46a079e63765c32c8cb32c566a170603ab
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:05+10:00
Commit Message:
MADS: PHANTOM: Stop the game in response to quit events
Changed paths:
engines/mads/madsv2/engine.cpp
diff --git a/engines/mads/madsv2/engine.cpp b/engines/mads/madsv2/engine.cpp
index b5d299ed55a..f0a75214860 100644
--- a/engines/mads/madsv2/engine.cpp
+++ b/engines/mads/madsv2/engine.cpp
@@ -22,6 +22,7 @@
#include "common/system.h"
#include "engines/util.h"
#include "mads/madsv2/engine.h"
+#include "mads/madsv2/core/kernel.h"
#include "mads/madsv2/core/mouse.h"
#include "mads/madsv2/phantom/main.h"
#include "mads/core/sound.h"
@@ -58,7 +59,7 @@ void MADSV2Engine::pollEvents() {
// Poll for events
Common::Event e;
- while (g_system->getEventManager()->pollEvent(e) && !shouldQuit()) {
+ while (g_system->getEventManager()->pollEvent(e) && game.going) {
bool isMouse = false;
switch (e.type) {
case Common::EVENT_LBUTTONDOWN:
@@ -85,6 +86,10 @@ void MADSV2Engine::pollEvents() {
mouse_buttons &= ~4;
isMouse = true;
break;
+ case Common::EVENT_RETURN_TO_LAUNCHER:
+ case Common::EVENT_QUIT:
+ game.going = false;
+ break;
default:
break;
}
Commit: 16c4fd6ecbd6b247ce3cd085992415563c642f49
https://github.com/scummvm/scummvm/commit/16c4fd6ecbd6b247ce3cd085992415563c642f49
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:05+10:00
Commit Message:
MADS: PHANTOM: Change tiles to using direct memory blocks
Changed paths:
engines/mads/madsv2/core/anim.cpp
engines/mads/madsv2/core/kernel.cpp
engines/mads/madsv2/core/object.cpp
engines/mads/madsv2/core/tile.cpp
engines/mads/madsv2/core/tile.h
diff --git a/engines/mads/madsv2/core/anim.cpp b/engines/mads/madsv2/core/anim.cpp
index 3f27279c385..4653ee676d1 100644
--- a/engines/mads/madsv2/core/anim.cpp
+++ b/engines/mads/madsv2/core/anim.cpp
@@ -109,8 +109,8 @@ int anim_load_background(AnimFile *anim_in, Buffer *this_orig,
depthMap,
pictureResource,
depthResource,
- tile_picture_handle,
- tile_attribute_handle,
+ -1,
+ -1,
load_flags);
if (my_room == NULL) {
diff --git a/engines/mads/madsv2/core/kernel.cpp b/engines/mads/madsv2/core/kernel.cpp
index 672e393fc58..f3fa8d27984 100644
--- a/engines/mads/madsv2/core/kernel.cpp
+++ b/engines/mads/madsv2/core/kernel.cpp
@@ -326,8 +326,6 @@ int kernel_game_startup(int game_video_mode, int load_flag,
}
}
- if (tile_setup()) ems_error = true;
-
if (ems_error) {
if (ems_exists) {
error_report(ERROR_NO_MORE_EMS, SEVERE, MODULE_KERNEL, ems_pages, work_screen_ems_handle);
@@ -665,8 +663,8 @@ int kernel_room_startup(int newRoom, int initial_variant, const char *interface,
&depth_map,
&picture_resource,
&depth_resource,
- tile_picture_handle,
- tile_attribute_handle,
+ -1,
+ -1,
load_flags);
if (room == NULL) {
#ifndef disable_error_check
@@ -2601,7 +2599,7 @@ void kernel_load_variant(int variant) {
&scr_special,
&depth_map,
&depth_resource,
- tile_attribute_handle)) {
+ -1)) {
error_report(ERROR_VARIANT_LOAD_FAILURE, WARNING, MODULE_KERNEL, room_load_error, (room_id * 10) + room_variant);
}
@@ -3048,8 +3046,8 @@ int kernel_background_startup(int newRoom, int initial_variant) {
&depth_map,
&picture_resource,
&depth_resource,
- tile_picture_handle,
- tile_attribute_handle,
+ -1,
+ -1,
load_flags);
if (room == NULL) {
error_data = room_load_error;
diff --git a/engines/mads/madsv2/core/object.cpp b/engines/mads/madsv2/core/object.cpp
index 12a075c7278..b679e95a003 100644
--- a/engines/mads/madsv2/core/object.cpp
+++ b/engines/mads/madsv2/core/object.cpp
@@ -472,7 +472,7 @@ int object_examine(int number, long message, int speech) {
if (room_load_variant(room_id, room_variant, NULL, room,
&scr_depth, &scr_walk, &scr_special,
- &depth_map, &depth_resource, tile_attribute_handle)) {
+ &depth_map, &depth_resource, -1)) {
error_report(ERROR_VARIANT_LOAD_FAILURE, WARNING, MODULE_OBJECT, room_load_error, (room_id * 10) + room_variant);
}
tile_pan(&depth_map, picture_view_x, picture_view_y);
diff --git a/engines/mads/madsv2/core/tile.cpp b/engines/mads/madsv2/core/tile.cpp
index 294d9bf1ffa..66775ca01de 100644
--- a/engines/mads/madsv2/core/tile.cpp
+++ b/engines/mads/madsv2/core/tile.cpp
@@ -22,7 +22,6 @@
#include "common/memstream.h"
#include "mads/madsv2/core/general.h"
#include "mads/madsv2/core/anim.h"
-#include "mads/madsv2/core/ems.h"
#include "mads/madsv2/core/buffer.h"
#include "mads/madsv2/core/loader.h"
#include "mads/madsv2/core/fileio.h"
@@ -45,10 +44,6 @@ namespace MADSV2 {
int tile_load_error;
ShadowList tile_shadow;
-int tile_ems_available = false;
-int tile_picture_handle = -1;
-int tile_attribute_handle = -1;
-
void TileMapHeader::load(Common::SeekableReadStream *src) {
src->readMultipleLE(tile_type, one_to_one, num_x_tiles, num_y_tiles,
@@ -75,19 +70,13 @@ int tile_load(const char *base, int tile_type, TileResource *tile_resource,
int error_flag = true;
int map_x_size;
int map_y_size;
- int tile_page;
- int tile_offset;
- int count, count2;
+ int count;
int packing_flag;
int x, y;
int map_value;
int color_handle = -1;
- int tile_page_number;
- int last_page = -1;
int x_size;
int pan;
- int ems_page_marker;
- int ems_page_offset;
int memory_mode;
int already_unpacked = false;
char resource_name[80];
@@ -97,8 +86,6 @@ int tile_load(const char *base, int tile_type, TileResource *tile_resource,
long top_of_file = 0;
long base_position;
long my_offset;
- long my_ems_marker;
- long my_ems_offset;
long compressed_size;
byte *decompress_buffer = NULL;
Tile *tile = NULL;
@@ -386,24 +373,17 @@ int tile_load(const char *base, int tile_type, TileResource *tile_resource,
tile_resource->chunk_size = ((((long)tile_resource->tile_x - 1) >> 1) + 1) * (long)tile_resource->tile_y;
}
- /* Load up EMS paging information */
-
- tile_resource->ems_handle = emsHandle;
- tile_resource->tiles_per_page = (int)(16384L / tile_resource->chunk_size);
+ /* Allocate flat tile store for panning maps */
- if (tile_resource->tiles_per_page <= 0) {
- if (!map->one_to_one) {
+ if (!map->one_to_one) {
+ delete[] tile_resource->tile_data;
+ tile_resource->tile_data = new byte[(long)tile_resource->num_tiles * tile_resource->chunk_size]();
+ if (!tile_resource->tile_data) {
tile_load_error = 16;
goto done;
}
- tile_resource->tiles_per_page = 1;
}
- tile_resource->num_pages = ((tile_resource->num_tiles - 1) / tile_resource->tiles_per_page) + 1;
-
- tile_page = 0;
- tile_offset = 0;
-
/* Get current (base) position in file */
if (memory_mode == LOADER_DISK) {
base_position = load_handle.handle->pos();
@@ -418,32 +398,6 @@ int tile_load(const char *base, int tile_type, TileResource *tile_resource,
for (count = 0; count < tile_resource->num_tiles; count++) {
switch (memory_mode) {
- case LOADER_EMS:
- my_offset = base_position + (tile_resource->chunk_size * count);
- my_ems_marker = my_offset / EMS_PAGE_SIZE;
- my_ems_offset = my_offset - (my_ems_marker * EMS_PAGE_SIZE);
-
- ems_page_marker = -1;
- for (count2 = 0; count2 < (int)my_ems_marker; count2++) {
- ems_page_marker = ems_next_handle_page(load_handle.ems_handle, ems_page_marker);
- }
- ems_page_offset = (int)my_ems_offset;
- if (ems_page_offset >= EMS_PAGE_SIZE) {
- ems_page_offset -= EMS_PAGE_SIZE;
- ems_page_marker = ems_next_handle_page(load_handle.ems_handle, ems_page_marker);
- }
-
- if (!ems_copy_it_down(load_handle.ems_handle,
- &ems_page_marker,
- &ems_page_offset,
- tile_buffer.data,
- tile_resource->chunk_size)) {
- tile_load_error = 17;
- goto done;
- }
-
- break;
-
case LOADER_XMS:
my_offset = base_position + (tile_resource->chunk_size * count);
if (!xms_copy(tile_resource->chunk_size,
@@ -533,24 +487,8 @@ int tile_load(const char *base, int tile_type, TileResource *tile_resource,
}
}
} else {
- tile_page = count / tile_resource->tiles_per_page;
-
- if (tile_page != last_page) {
- tile_page_number = ems_search_page(emsHandle, tile_page);
- if (tile_page_number < 0) {
- tile_load_error = 20;
- goto done;
- }
- if (ems_map_page(tile_ems_page, tile_page_number)) {
- tile_load_error = 21;
- goto done;
- }
-
- last_page = tile_page;
- }
-
- tile_offset = (int)((count % tile_resource->tiles_per_page) * tile_resource->chunk_size);
- memcpy(tile_ems_address + tile_offset, tile_buffer.data, (word)tile_resource->chunk_size);
+ memcpy(tile_resource->tile_data + (long)count * tile_resource->chunk_size,
+ tile_buffer.data, (word)tile_resource->chunk_size);
}
}
@@ -598,10 +536,6 @@ int tile_buffer(Buffer *target,
int picture_x, picture_y;
int map_y_offset;
int map_value;
- int tile_page;
- int tile_offset;
- int tile_page_number;
- int last_page = -1;
Buffer tile_buffer;
int max_x;
@@ -634,19 +568,8 @@ int tile_buffer(Buffer *target,
map->tile_y_size, (byte)default_value);
} else {
- tile_page = map_value / tile_resource->tiles_per_page;
- tile_offset = (word)((map_value % tile_resource->tiles_per_page) *
- tile_resource->chunk_size);
-
- if (tile_page != last_page) {
- tile_page_number = ems_search_page(tile_resource->ems_handle, tile_page);
- if (tile_page_number < 0) goto done;
- if (ems_map_page(tile_ems_page, tile_page_number)) goto done;
-
- last_page = tile_page;
- }
-
- tile_buffer.data = tile_ems_address + tile_offset;
+ tile_buffer.data = tile_resource->tile_data +
+ (long)map_value * tile_resource->chunk_size;
buffer_rect_copy_2(tile_buffer, *target,
0, 0,
picture_x, picture_y,
@@ -662,31 +585,13 @@ done:
return error_flag;
}
-int tile_setup(void) {
- int error_flag = true;
-
- picture_map.map = NULL;
- depth_map.map = NULL;
-
- tile_picture_handle = ems_get_page_handle(TILE_MAX_PAGES);
- if (tile_picture_handle < 0) goto done;
-
- tile_attribute_handle = ems_get_page_handle(TILE_MAX_PAGES >> 1);
- if (tile_attribute_handle < 0) goto done;
-
- tile_ems_available = true;
- error_flag = false;
-
-done:
- if (error_flag) {
- if (tile_picture_handle >= 0) ems_free_page_handle(tile_picture_handle);
- }
-
- return error_flag;
-}
void tile_map_free(TileMapHeader *map) {
if (map != NULL) {
+ if (map->resource != NULL) {
+ delete[] map->resource->tile_data;
+ map->resource->tile_data = nullptr;
+ }
if (map->map != NULL) {
mem_free(map->map);
map->map = NULL;
diff --git a/engines/mads/madsv2/core/tile.h b/engines/mads/madsv2/core/tile.h
index 0ae53f1d5d3..e3c6b7f54d4 100644
--- a/engines/mads/madsv2/core/tile.h
+++ b/engines/mads/madsv2/core/tile.h
@@ -32,8 +32,6 @@ namespace MADSV2 {
#define DEFAULT_TILE_X 20
#define DEFAULT_TILE_Y 12
-#define TILE_MAX_PAGES 14 /* Max EMS pages for a picture */
-/* (14 is enough for 4 screens) */
#define EMPTY_TILE -1
#define REPEAT_TILE 0x8000
@@ -42,20 +40,19 @@ namespace MADSV2 {
#define TILE_MAP_SHADOW 0x0020 /* Load shadow for tile */
-#define tile_ems_page 0
-#define tile_ems_address ems_page[tile_ems_page]
-
struct TileResource {
uint16 num_tiles; /* Number of tiles in resource */
int16 tile_x; /* Tile X size */
int16 tile_y; /* Tile Y size */
int16 compression; /* Compression in resource file */
- int16 ems_handle; /* EMS handle of resource */
+ int16 ems_handle; /* EMS handle of resource (on-disk field; unused at runtime) */
uint16 num_pages; /* Number of pages needed */
uint16 tiles_per_page; /* Tiles stored per page */
uint32 chunk_size; /* Tile size in bytes (x*y) */
int16 color_handle; /* Color handle for loaded resource */
+ byte *tile_data = nullptr; /* Flat tile store allocated by tile_load (not serialised) */
+
static constexpr int SIZE = 2 + 2 + 2 + 2 + 2 + 2 + 2 + 4 + 2;
void load(Common::SeekableReadStream *src);
};
@@ -100,9 +97,6 @@ struct TileMapHeader {
extern ShadowList tile_shadow;
extern int tile_load_error;
-extern int tile_ems_available;
-extern int tile_picture_handle;
-extern int tile_attribute_handle;
extern int tile_load(const char *base, int tile_type, TileResource *tile_resource,
@@ -110,7 +104,6 @@ extern int tile_load(const char *base, int tile_type, TileResource *tile_resourc
CycleListPtr cycle_list, int ems_handle, int load_flags);
extern int tile_buffer(Buffer *target, TileResource *tile_resource,
TileMapHeader *map, int tile_x, int tile_y);
-extern int tile_setup(void);
extern void tile_map_free(TileMapHeader *map);
extern void tile_pan(TileMapHeader *tile_map, int x, int y);
extern int tile_fake_map(int tile_type, TileMapHeader *tile_map,
Commit: 83ee9fe5588b120ffae1192c39ec371a5315011e
https://github.com/scummvm/scummvm/commit/83ee9fe5588b120ffae1192c39ec371a5315011e
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:05+10:00
Commit Message:
MADS: PHANTOM: Fix rendering backgrounds
Changed paths:
engines/mads/madsv2/core/tile.cpp
engines/mads/madsv2/core/tile.h
diff --git a/engines/mads/madsv2/core/tile.cpp b/engines/mads/madsv2/core/tile.cpp
index 66775ca01de..e75624593d8 100644
--- a/engines/mads/madsv2/core/tile.cpp
+++ b/engines/mads/madsv2/core/tile.cpp
@@ -557,7 +557,6 @@ int tile_buffer(Buffer *target,
picture_y = y * map->tile_y_size;
map_y_offset = (y + tile_y) * map->num_x_tiles;
-
for (x = 0; x < max_x; x++) {
picture_x = x * size_x;
map_value = *(map->map + map_y_offset + tile_x + x);
diff --git a/engines/mads/madsv2/core/tile.h b/engines/mads/madsv2/core/tile.h
index e3c6b7f54d4..ecf315ceeda 100644
--- a/engines/mads/madsv2/core/tile.h
+++ b/engines/mads/madsv2/core/tile.h
@@ -62,7 +62,7 @@ typedef struct {
} Tile;
struct TileMapHeader {
- uint16 tile_type; /* Type of tile */
+ int16 tile_type; /* Type of tile */
uint16 one_to_one; /* One-to-one ratio with scr_orig */
uint16 num_x_tiles; /* Number of X tiles in map */
uint16 num_y_tiles; /* Number of Y tiles in map */
Commit: c4d4fc5b1db8d733994af341fe4100fb60067a4a
https://github.com/scummvm/scummvm/commit/c4d4fc5b1db8d733994af341fe4100fb60067a4a
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:06+10:00
Commit Message:
MADS: PHANTOM: Fix playback speed
Changed paths:
engines/mads/madsv2/core/general.h
engines/mads/madsv2/core/timer.cpp
diff --git a/engines/mads/madsv2/core/general.h b/engines/mads/madsv2/core/general.h
index e3879d59cc1..c7a2b86b6d2 100644
--- a/engines/mads/madsv2/core/general.h
+++ b/engines/mads/madsv2/core/general.h
@@ -66,8 +66,11 @@ typedef struct { /* Video buffer structure */
/* Timer and clock stuff */
-#define clock_address 0x0040006c /* BIOS clock address */
-#define dos_timer_address (long *)clock_address
+// ScummVM: replace the DOS hardware address with a safe writable dummy so
+// that game code which writes *timer_address doesn't touch unmapped memory.
+extern long _timer_clock;
+#define clock_address (&_timer_clock)
+#define dos_timer_address (&_timer_clock)
#define interrupt_controller 0x20 /* Interrupt controller */
#define end_of_interrupt 0x20 /* End of interrupt ack */
diff --git a/engines/mads/madsv2/core/timer.cpp b/engines/mads/madsv2/core/timer.cpp
index 68295d75728..a2cf90fa967 100644
--- a/engines/mads/madsv2/core/timer.cpp
+++ b/engines/mads/madsv2/core/timer.cpp
@@ -27,6 +27,8 @@
namespace MADS {
namespace MADSV2 {
+long _timer_clock = 0; /* Backing store for *timer_address writes */
+
long *timer_address = dos_timer_address;
word timer_rate = 20;
int timer_service_active = false;
@@ -54,8 +56,12 @@ void timer_remove() {
}
long timer_read() {
+ // kernel.clock is compared against timing constants where ONE_SECOND = 60,
+ // so this counter must run at 60 Hz. The original DOS code achieved this
+ // by pointing timer_address at the interrupt handler's timer_60_low counter;
+ // here we derive the same rate directly from wall-clock milliseconds.
unsigned long ms = g_engine->getMillis();
- return ms * 1193 / 65536;
+ return (long)(ms * 60 / 1000);
}
long timer_read_600() {
Commit: 519732a3ee9e69408d3aabe78c498e3be9b7c0da
https://github.com/scummvm/scummvm/commit/519732a3ee9e69408d3aabe78c498e3be9b7c0da
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:06+10:00
Commit Message:
MADS: PHANTOM: Fixes for showing the difficulty menu on startup
Changed paths:
engines/mads/madsv2/core/game.cpp
engines/mads/madsv2/core/game.h
engines/mads/madsv2/core/mem.cpp
engines/mads/madsv2/core/popup.cpp
engines/mads/madsv2/core/quote.cpp
engines/mads/madsv2/phantom/menus.cpp
diff --git a/engines/mads/madsv2/core/game.cpp b/engines/mads/madsv2/core/game.cpp
index 03dabe2e37a..2295659e77b 100644
--- a/engines/mads/madsv2/core/game.cpp
+++ b/engines/mads/madsv2/core/game.cpp
@@ -1067,7 +1067,7 @@ int game_parse_keystroke(int mykey) {
case f1_key:
if (room_id != 199 && section_id != 9) {
if (kernel.activate_menu) {
- kernel.activate_menu = 0;
+ kernel.activate_menu = GAME_NO_MENU;
} else {
kernel.activate_menu = GAME_MAIN_MENU;
kernel.paused = false;
@@ -1310,7 +1310,8 @@ void game_control() {
/* Get difficulty level if new game */
if (!kernel.teleported_in && (game.difficulty == -1)) {
/* Difficulty menu */
- /* kernel.activate_menu = GAME_DIFFICULTY_MENU; */
+ if (g_engine->getGameID() == GType_Phantom)
+ kernel.activate_menu = GAME_DIFFICULTY_MENU;
game_exec_function(game_menu_routine);
game_wait_cursor();
@@ -2457,7 +2458,7 @@ static void game_control_loop() {
if (game_menu_routine == NULL) game.going = false;
- kernel.activate_menu = 0;
+ kernel.activate_menu = GAME_NO_MENU;
}
}
diff --git a/engines/mads/madsv2/core/game.h b/engines/mads/madsv2/core/game.h
index 45da5bfa9d2..bcad035349f 100644
--- a/engines/mads/madsv2/core/game.h
+++ b/engines/mads/madsv2/core/game.h
@@ -116,14 +116,20 @@ extern int selected_intro;
extern Player journal_player;
extern int journal_room;
-#define GAME_MAIN_MENU 1 /* Game menus */
-#define GAME_SAVE_MENU 2
-#define GAME_RESTORE_MENU 3
-#define GAME_OPTIONS_MENU 4
-#define GAME_DIFFICULTY_MENU 5
-#define GAME_ALERT_MENU 6
-#define GAME_SCORE_MENU 7
-#define GAME_CD_MENU 8
+/**
+ * Game menus
+ */
+enum {
+ GAME_NO_MENU = 0,
+ GAME_MAIN_MENU = 1,
+ GAME_SAVE_MENU = 2,
+ GAME_RESTORE_MENU = 3,
+ GAME_OPTIONS_MENU = 4,
+ GAME_DIFFICULTY_MENU = 5,
+ GAME_ALERT_MENU = 6,
+ GAME_SCORE_MENU = 7,
+ GAME_CD_MENU = 8
+};
#define GAME_MENU_MAX_ITEMS 20 /* Max number of menu items */
#define GAME_MAX_SAVE_SLOTS 99 /* Max number of save slots */
diff --git a/engines/mads/madsv2/core/mem.cpp b/engines/mads/madsv2/core/mem.cpp
index e06fca2c525..73374e60477 100644
--- a/engines/mads/madsv2/core/mem.cpp
+++ b/engines/mads/madsv2/core/mem.cpp
@@ -19,6 +19,7 @@
*
*/
+#include "common/algorithm.h"
#include "common/textconsole.h"
#include "mads/madsv2/core/general.h"
#include "mads/madsv2/core/error.h"
@@ -49,9 +50,11 @@ int mem_manager_active = false;
void *mem_get_name(long size, const char *) {
- void *memory_block = nullptr;
- if (size > 0)
- memory_block = malloc(size);
+ byte *memory_block = nullptr;
+ if (size > 0) {
+ memory_block = (byte *)malloc(size);
+ Common::fill(memory_block, memory_block + size, 0);
+ }
return memory_block;
}
diff --git a/engines/mads/madsv2/core/popup.cpp b/engines/mads/madsv2/core/popup.cpp
index a5aa4af8565..a64ea54d378 100644
--- a/engines/mads/madsv2/core/popup.cpp
+++ b/engines/mads/madsv2/core/popup.cpp
@@ -1641,10 +1641,12 @@ static void popup_redraw_item(PopupItem *item) {
static void popup_update_item(PopupItem *item) {
- if (item->vector[VECTOR_UPDATE] != NULL) {
- popup_exec_function(item, VECTOR_UPDATE);
- } else {
- popup_redraw_item(item);
+ if (item) {
+ if (item->vector[VECTOR_UPDATE] != NULL) {
+ popup_exec_function(item, VECTOR_UPDATE);
+ } else {
+ popup_redraw_item(item);
+ }
}
}
diff --git a/engines/mads/madsv2/core/quote.cpp b/engines/mads/madsv2/core/quote.cpp
index 852df82d483..3b99541372f 100644
--- a/engines/mads/madsv2/core/quote.cpp
+++ b/engines/mads/madsv2/core/quote.cpp
@@ -32,17 +32,6 @@ namespace MADSV2 {
int quote_emergency = false;
-static int word_get(char *target, Common::SeekableReadStream *handle) {
- do {
- *target = (char)handle->readByte();
- } while (!handle->eos() && !*target++);
-
- if (handle->err())
- quote_emergency = true;
-
- return false;
-}
-
char *quote_load(int quote_id, ...) {
va_list marker;
int quote_error = 0;
@@ -80,7 +69,7 @@ char *quote_load(int quote_id, ...) {
sort_insertion_16(mark, (byte *)work, list);
- total_mem_avail = mem_get_avail();
+ total_mem_avail = 65536;
buffer = pointer = (char *)mem_get_name(total_mem_avail - 64, "$quotes$");
if (buffer == NULL) {
quote_error = 2;
@@ -89,27 +78,26 @@ char *quote_load(int quote_id, ...) {
now_reading = 1;
while (now_finding < mark) {
- if (word_get(work, handle)) {
- quote_error = 3;
- goto done;
- }
+ Common::String quoteStr = handle->readString();
if (now_reading == list[now_finding]) {
- mem_needed = strlen(work) + 3;
+ mem_needed = quoteStr.size() + 3;
total_mem_needed += mem_needed;
if (total_mem_needed > total_mem_avail) {
quote_error = 4;
goto done;
}
- Common::strcpy_s(pointer, QUOTE_MAX_LIST_LENGTH, work);
+
+ Common::strcpy_s(pointer, QUOTE_MAX_LIST_LENGTH, quoteStr.c_str());
pointer += (mem_needed - 2);
- WRITE_LE_UINT16(pointer, list[now_finding]);
+ *(uint16 *)(pointer) = list[now_finding];
pointer += 2;
- pointer = (char *)mem_normalize(pointer);
now_finding++;
+
} else if (now_reading > list[now_finding]) {
error_report(ERROR_QUOTE_DUPLICATE_LOAD, WARNING, MODULE_QUOTE, quote_error, list[now_finding]);
}
+
now_reading++;
}
@@ -145,7 +133,7 @@ char *quote_string(char *quote_list, int quote_id) {
for (marker = quote_list; *marker && (result == NULL); marker = search + 2) {
for (search = marker; *search; search++);
search++;
- id = *((int *)search);
+ id = *((uint16 *)search);
if (id == quote_id) result = marker;
}
diff --git a/engines/mads/madsv2/phantom/menus.cpp b/engines/mads/madsv2/phantom/menus.cpp
index 24371ffd265..a8e192d8691 100644
--- a/engines/mads/madsv2/phantom/menus.cpp
+++ b/engines/mads/madsv2/phantom/menus.cpp
@@ -240,7 +240,7 @@ static void global_menu_score() {
text_show(99);
- kernel.activate_menu = 0;
+ kernel.activate_menu = GAME_NO_MENU;
}
static void global_menu_save_restore(int save) {
@@ -288,7 +288,7 @@ static void global_menu_save_restore(int save) {
case alt_q_key:
case ctrl_q_key:
game.going = false;
- kernel.activate_menu = 0;
+ kernel.activate_menu = GAME_NO_MENU;
break;
case f1_key:
@@ -323,7 +323,7 @@ static void global_menu_save_restore(int save) {
break;
}
} else {
- kernel.activate_menu = 0;
+ kernel.activate_menu = GAME_NO_MENU;
}
popup_dialog_destroy();
@@ -461,7 +461,7 @@ static void global_menu_options() {
case alt_q_key:
case ctrl_q_key:
game.going = false;
- kernel.activate_menu = 0;
+ kernel.activate_menu = GAME_NO_MENU;
break;
case f1_key:
@@ -501,7 +501,7 @@ static void global_menu_options() {
global_write_config_file();
global_load_config_parameters();
- kernel.activate_menu = 0;
+ kernel.activate_menu = GAME_NO_MENU;
}
if ((former_music != config_file.music_flag) ||
@@ -544,7 +544,7 @@ static void global_menu_difficulty() {
result = popup_execute();
- kernel.activate_menu = 0;
+ kernel.activate_menu = GAME_NO_MENU;
if (result == easy_item) {
game.difficulty = EASY_MODE;
@@ -623,15 +623,15 @@ static void global_menu_main() {
result = popup_execute();
if (result == save_item) {
- kernel.activate_menu = 2;
+ kernel.activate_menu = GAME_SAVE_MENU;
} else if (result == restore_item) {
- kernel.activate_menu = 3;
+ kernel.activate_menu = GAME_RESTORE_MENU;
} else if (result == options_item) {
- kernel.activate_menu = 4;
+ kernel.activate_menu = GAME_OPTIONS_MENU;
} else if (result == score_item) {
- kernel.activate_menu = 7;
+ kernel.activate_menu = GAME_SCORE_MENU;
} else {
- kernel.activate_menu = 0;
+ kernel.activate_menu = GAME_NO_MENU;
}
if (result == quit_item)
@@ -642,23 +642,23 @@ static void global_menu_main() {
case alt_x_key:
case ctrl_q_key:
game.going = false;
- kernel.activate_menu = 0;
+ kernel.activate_menu = GAME_NO_MENU;
break;
case f5_key:
- kernel.activate_menu = 2;
+ kernel.activate_menu = GAME_SAVE_MENU;
break;
case f7_key:
- kernel.activate_menu = 3;
+ kernel.activate_menu = GAME_RESTORE_MENU;
break;
case f8_key:
- kernel.activate_menu = 7;
+ kernel.activate_menu = GAME_SCORE_MENU;
break;
case f10_key:
- kernel.activate_menu = 4;
+ kernel.activate_menu = GAME_OPTIONS_MENU;
break;
default:
@@ -676,33 +676,36 @@ void global_game_menu() {
loaded = true;
}
+ game_menu_setup();
g_engine->flushKeys();
do {
switch (kernel.activate_menu) {
- case 1:
+ case GAME_MAIN_MENU:
global_menu_main();
break;
- case 2:
+ case GAME_SAVE_MENU:
global_menu_save_restore(true);
break;
- case 3:
+ case GAME_RESTORE_MENU:
global_menu_save_restore(false);
break;
- case 4:
+ case GAME_OPTIONS_MENU:
global_menu_options();
break;
- case 5:
+ case GAME_DIFFICULTY_MENU:
global_menu_difficulty();
break;
- case 7:
+ case GAME_SCORE_MENU:
global_menu_score();
break;
default:
- kernel.activate_menu = 0;
+ kernel.activate_menu = GAME_NO_MENU;
break;
}
- } while (!g_engine->shouldQuit() && game.going && kernel.activate_menu != 0);
+ } while (!g_engine->shouldQuit() && game.going && kernel.activate_menu != GAME_NO_MENU);
+
+ game_menu_shutdown();
if (loaded) {
sprite_free(&box_param.menu, true);
Commit: 607b346b02cbde85d865896fce0c204f0bd38d22
https://github.com/scummvm/scummvm/commit/607b346b02cbde85d865896fce0c204f0bd38d22
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:06+10:00
Commit Message:
MADS: PHANTOM: Fix quitting directly from Difficulty dialog
Changed paths:
engines/mads/madsv2/core/game.cpp
engines/mads/madsv2/core/pal.cpp
engines/mads/madsv2/core/popup.cpp
engines/mads/madsv2/phantom/main.cpp
diff --git a/engines/mads/madsv2/core/game.cpp b/engines/mads/madsv2/core/game.cpp
index 2295659e77b..34080a216b9 100644
--- a/engines/mads/madsv2/core/game.cpp
+++ b/engines/mads/madsv2/core/game.cpp
@@ -1313,6 +1313,8 @@ void game_control() {
if (g_engine->getGameID() == GType_Phantom)
kernel.activate_menu = GAME_DIFFICULTY_MENU;
game_exec_function(game_menu_routine);
+ if (!game.going)
+ return;
game_wait_cursor();
diff --git a/engines/mads/madsv2/core/pal.cpp b/engines/mads/madsv2/core/pal.cpp
index 9bcec1e0e0f..fd0815bcd81 100644
--- a/engines/mads/madsv2/core/pal.cpp
+++ b/engines/mads/madsv2/core/pal.cpp
@@ -73,6 +73,8 @@ void pal_init(int reserve_bottom, int reserve_top) {
color_status[count] = 0;
}
+ pal_interface(master_palette);
+
if (!palette_ever_initialized) {
pal_interface(master_palette);
palette_ever_initialized = true;
diff --git a/engines/mads/madsv2/core/popup.cpp b/engines/mads/madsv2/core/popup.cpp
index a64ea54d378..40519e31ff6 100644
--- a/engines/mads/madsv2/core/popup.cpp
+++ b/engines/mads/madsv2/core/popup.cpp
@@ -3463,6 +3463,11 @@ PopupItem *popup_execute(void) {
mouse_end_cycle(false, (popup->status & POPUP_STATUS_EXIT) == 0);
+ if (!game.going) {
+ result_item = nullptr;
+ goto done;
+ }
+
} while (!(popup->status & POPUP_STATUS_EXIT));
result_item = popup->active_item;
@@ -3470,7 +3475,7 @@ PopupItem *popup_execute(void) {
done:
popup_destroy();
box = keep_box;
- return (result_item);
+ return result_item;
}
} // namespace MADSV2
diff --git a/engines/mads/madsv2/phantom/main.cpp b/engines/mads/madsv2/phantom/main.cpp
index a7ed5ab2d9f..bbf4b024356 100644
--- a/engines/mads/madsv2/phantom/main.cpp
+++ b/engines/mads/madsv2/phantom/main.cpp
@@ -242,16 +242,6 @@ static void game_main(int argc, const char **argv) {
game_control();
- if (!win_status) {
- if (!chain_flag || !(win_status || force_chain) || !(key_abort_level < 2)) {
- error_dump_file("*warn4.dat");
- }
-
- if (game_autosaved) {
- error_dump_file("*warn5.dat");
- }
- }
-
done:
global_unload_config_parameters();
Commit: 75df90fb2a60de8942a8967c0424ecf50d090a26
https://github.com/scummvm/scummvm/commit/75df90fb2a60de8942a8967c0424ecf50d090a26
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:07+10:00
Commit Message:
MADS: PHANTOM: Fix palette for initial Difficulty dialog
Strangely enough, it seems like the dialog relied on
default VGA palette entries. Which seems strange,
considering other games could have changed them.
To resolve this, we have a hardcoded initial palette.
Changed paths:
engines/mads/madsv2/core/mcga.cpp
diff --git a/engines/mads/madsv2/core/mcga.cpp b/engines/mads/madsv2/core/mcga.cpp
index 6fdf9592a0c..77b067753f8 100644
--- a/engines/mads/madsv2/core/mcga.cpp
+++ b/engines/mads/madsv2/core/mcga.cpp
@@ -31,6 +31,57 @@ namespace MADSV2 {
#define mcga_retrace_magic 14 /* Dave McKibbin's magic heuristic # */
+/* --------------------------------------------------------------------------
+ * Default VGA DAC palette for mode 13h (256 colours, 6-bit 0-63 range).
+ *
+ * In DOS, the BIOS loaded this table into the DAC when the video mode was
+ * set. mcga_compute_retrace_parameters() read it back and stored a copy in
+ * master_palette. ScummVM has no hardware DAC to read, so we supply the
+ * table explicitly.
+ *
+ * Source: captured via DOSBox debugger immediately after kernel_game_startup
+ * sets the video mode, before any game palette calls run.
+ * Entries 0â15 : standard EGA/VGA 16-colour compatibility palette
+ * Entries 16â31 : near-black utility + skin/cloth tones (room 922) + grey ramp
+ * Entries 32â55 : full-saturation hue wheel (blueâmagentaâredâyellowâgreenâcyan)
+ * Entries 56â255: not yet captured; zeroed until confirmed
+ *
+ * NOTE: entries 0â3 were recorded after pal_white() ran (grayscale ramp).
+ * The true BIOS defaults for those four slots are the first four EGA colours
+ * ((0,0,0) (0,0,42) (0,42,0) (0,42,42)), but pal_interface() overwrites them
+ * immediately after this function returns, so the distinction is moot.
+ * -------------------------------------------------------------------------- */
+static const RGBcolor vga_default_pal[256] = {
+ /* 0-15: EGA compatibility (entries 0-3 show post-pal_white grayscale) */
+ {0x00,0x00,0x00}, {0x15,0x15,0x15}, {0x2A,0x2A,0x2A}, {0x3F,0x3F,0x3F}, /* 0-3 */
+ {0x2A,0x00,0x00}, {0x2A,0x00,0x2A}, {0x2A,0x15,0x00}, {0x2A,0x2A,0x2A}, /* 4-7 */
+ {0x15,0x15,0x15}, {0x15,0x15,0x3F}, {0x15,0x3F,0x15}, {0x15,0x3F,0x3F}, /* 8-11 */
+ {0x3F,0x15,0x15}, {0x3F,0x15,0x3F}, {0x3F,0x3F,0x15}, {0x3F,0x3F,0x3F}, /* 12-15*/
+
+ /* 16-31: near-black + game skin/cloth tones + grey ramp */
+ {0x00,0x00,0x00}, {0x05,0x05,0x05}, /* 16-17*/
+ {0x31,0x27,0x1A}, {0x25,0x18,0x12}, {0x11,0x10,0x21}, {0x05,0x0F,0x18}, /* 18-21*/
+ {0x18,0x1C,0x1E}, {0x0F,0x14,0x16}, {0x16,0x14,0x14}, {0x00,0x2A,0x2A}, /* 22-25*/
+ {0x24,0x24,0x24}, {0x28,0x28,0x28}, {0x2D,0x2D,0x2D}, {0x32,0x32,0x32}, /* 26-29*/
+ {0x38,0x38,0x38}, {0x3F,0x3F,0x3F}, /* 30-31*/
+
+ /* 32-55: full-saturation hue wheel (matches standard VGA BIOS defaults) */
+ /* blue â magenta */
+ {0x00,0x00,0x3F}, {0x10,0x00,0x3F}, {0x1F,0x00,0x3F}, {0x2F,0x00,0x3F}, /* 32-35*/
+ /* magenta â red */
+ {0x3F,0x00,0x3F}, {0x3F,0x00,0x2F}, {0x3F,0x00,0x1F}, {0x3F,0x00,0x10}, /* 36-39*/
+ /* red â yellow */
+ {0x3F,0x00,0x00}, {0x3F,0x10,0x00}, {0x3F,0x1F,0x00}, {0x3F,0x2F,0x00}, /* 40-43*/
+ /* yellow â green */
+ {0x3F,0x3F,0x00}, {0x2F,0x3F,0x00}, {0x1F,0x3F,0x00}, {0x10,0x3F,0x00}, /* 44-47*/
+ /* green â cyan */
+ {0x00,0x3F,0x00}, {0x00,0x3F,0x10}, {0x00,0x3F,0x1F}, {0x00,0x3F,0x2F}, /* 48-51*/
+ /* cyan â blue */
+ {0x00,0x3F,0x3F}, {0x00,0x2F,0x3F}, {0x00,0x1F,0x3F}, {0x00,0x10,0x3F}, /* 52-55*/
+
+ /* 56-255: not yet captured; zeroed */
+};
+
word mcga_shakes = false;
int mcga_retrace_computed = false;
word mcga_retrace_ticks = 0;
@@ -143,17 +194,18 @@ static word mcga_time_palette_swap(Palette *pal, int first_color, int num_colors
}
void mcga_compute_retrace_parameters(void) {
- Palette temp_pal;
-
- mcga_getpal(&temp_pal);
- memcpy(&master_palette, &temp_pal, sizeof(Palette));
- mcga_setpal(&temp_pal);
-
- /* On original hardware this function computed how many palette entries
- could be written within one vertical retrace interval, and stored the
- result in mcga_retrace_max_colors / mcga_retrace_max_bytes. Under a
- modern graphics API there is no retrace constraint, so we set the
- maximums to the full 256-entry palette and mark the computation done. */
+ /* In DOS, the BIOS initialised the VGA DAC with a default 256-colour
+ palette when the video mode was set; this function read that palette
+ back and stored it in master_palette so the engine had a populated
+ baseline before any room-specific colours were allocated.
+ In ScummVM there is no hardware DAC to read, so we copy the known
+ default table directly instead of calling mcga_getpal(). */
+ memcpy(&master_palette, &vga_default_pal, sizeof(Palette));
+ mcga_setpal(&master_palette);
+
+ /* On original hardware this function also measured how many palette
+ entries could be written inside one vertical retrace interval.
+ Under a modern graphics API there is no such constraint. */
mcga_palette_fast = true;
mcga_retrace_max_colors = Graphics::PALETTE_COUNT;
mcga_retrace_max_bytes = Graphics::PALETTE_SIZE;
Commit: 2b205a4ee361a71af74cb1fa848cc4ff603bc7d6
https://github.com/scummvm/scummvm/commit/2b205a4ee361a71af74cb1fa848cc4ff603bc7d6
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:07+10:00
Commit Message:
MADS: PHANTOM: ConfMan option to directly specify difficulty
Changed paths:
engines/mads/madsv2/core/config.cpp
diff --git a/engines/mads/madsv2/core/config.cpp b/engines/mads/madsv2/core/config.cpp
index cc5eedcda6a..a8a5af4c5df 100644
--- a/engines/mads/madsv2/core/config.cpp
+++ b/engines/mads/madsv2/core/config.cpp
@@ -47,6 +47,7 @@ void read_config_file() {
ConfMan.registerDefault("inventory_mode", INVENTORY_SQUAT);
ConfMan.registerDefault("animated_interface", true);
ConfMan.registerDefault("show_speech_boxes", true);
+ ConfMan.registerDefault("difficulty", -1);
config_file.music_flag = !ConfMan.getBool("music_mute");
config_file.sound_flag = !ConfMan.getBool("sfx_mute");
@@ -61,6 +62,7 @@ void read_config_file() {
config_file.panning_speed = ConfMan.getBool("panning_speed");
config_file.show_speech_boxes = ConfMan.getBool("show_speech_boxes");
+ game.difficulty = ConfMan.getInt("difficulty");
}
void write_config_file() {
Commit: c3b3ec7350768114bb8f72cfa93f9d29ef26d0a1
https://github.com/scummvm/scummvm/commit/c3b3ec7350768114bb8f72cfa93f9d29ef26d0a1
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:07+10:00
Commit Message:
MADS: PHANTOM: Re-enable missing conv system calls
Changed paths:
engines/mads/madsv2/core/conv.cpp
engines/mads/madsv2/core/conv.h
engines/mads/madsv2/core/game.cpp
engines/mads/madsv2/core/kernel.cpp
engines/mads/madsv2/core/kernel.h
diff --git a/engines/mads/madsv2/core/conv.cpp b/engines/mads/madsv2/core/conv.cpp
index 835a33ca006..c4199d496ab 100644
--- a/engines/mads/madsv2/core/conv.cpp
+++ b/engines/mads/madsv2/core/conv.cpp
@@ -21,22 +21,22 @@
#include "common/algorithm.h"
#include "common/str.h"
+#include "common/textconsole.h"
#include "mads/madsv2/core/conv.h"
namespace MADS {
namespace MADSV2 {
+Conv *conv[CONV_MAX_DATA];
+ConvData *conv_data[CONV_MAX_DATA];
+Conv *active_conv;
+ConvData *active_conv_data;
int conv_restore_running;
ConvControl conv_control;
int *conv_my_next_start;
-constexpr int CONV_MAX_SLOTS = 40;
-constexpr int CONV_MAX_DATA = 5;
-
static int conv_slot_indexes[CONV_MAX_SLOTS];
static int conv_slots[CONV_MAX_DATA];
-static int conv_data[CONV_MAX_DATA];
-static int conv_conditions[CONV_MAX_DATA];
static const char *conv_get_filename(int convNum, int extType, char *name) {
*name = '\0';
@@ -62,8 +62,8 @@ void conv_system_init() {
Common::fill(conv_slot_indexes, conv_slot_indexes + CONV_MAX_SLOTS, 0);
Common::fill(conv_slots, conv_slots + CONV_MAX_DATA, 0);
- Common::fill(conv_data, conv_data + CONV_MAX_DATA, 0);
- Common::fill(conv_conditions, conv_conditions + CONV_MAX_DATA, 0);
+ Common::fill(conv, conv + CONV_MAX_DATA, (Conv *)nullptr);
+ Common::fill(conv_data, conv_data + CONV_MAX_DATA, (ConvData *)nullptr);
conv_system_cleanup();
}
@@ -87,9 +87,14 @@ void conv_get(int convNum) {
}
}
-void conv_run(int convNum) {}
+void conv_run(int convNum) {
+}
+
+void conv_update(bool) {
+}
-void conv_update(bool) {}
+void conv_regenerate_last_message() {
+}
void conv_export_pointer(int *ptr) {}
@@ -100,6 +105,8 @@ void conv_me_trigger(int trigger) {}
void conv_you_trigger(int trigger) {}
int *conv_get_variable(int varNum) {
+ assert(varNum >= 0 && varNum < active_conv_data->variablesCount);
+
// TODO
return nullptr;
}
@@ -120,5 +127,16 @@ void conv_flush() {
// TODO
}
+int conv_append(Common::WriteStream *handle) {
+ error("TODO: conv_append");
+ return 0;
+}
+
+int conv_expand(Common::SeekableReadStream *handle) {
+ error("TODO: conv_expand");
+ return 0;
+}
+
+
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/core/conv.h b/engines/mads/madsv2/core/conv.h
index 7324f2caef8..34d3c623190 100644
--- a/engines/mads/madsv2/core/conv.h
+++ b/engines/mads/madsv2/core/conv.h
@@ -22,12 +22,24 @@
#ifndef MADS_CORE_CONV_H
#define MADS_CORE_CONV_H
-#include "common/scummsys.h"
+#include "common/stream.h"
namespace MADS {
namespace MADSV2 {
-struct ConvData {
+constexpr int CONV_MAX_SLOTS = 40;
+constexpr int CONV_MAX_DATA = 5;
+
+enum ConvStatus {
+ CONV_STATUS_HOLDING = -1,
+ CONV_STATUS_NEXT_NODE = 0,
+ CONV_STATUS_WAIT_AUTO = 1,
+ CONV_STATUS_WAIT_ENTRY = 2,
+ CONV_STATUS_EXECUTE = 3,
+ CONV_STATUS_REPLY = 4
+};
+
+struct Conv {
int16 node_count;
int16 dialog_count;
int16 message_count;
@@ -50,21 +62,57 @@ struct ConvData {
void *text_lines_ptr;
};
-enum ConvStatus {
- CONV_NONE,
- CONV_STATUS_WAIT_AUTO,
- CONV_STATUS_WAIT_ENTRY
+struct ConvData {
+ int16 currentNode;
+ int16 entryFlagsCount;
+ int16 variablesCount;
+ int16 importsCount;
+ int16 numImports;
+ int16 array1_size;
+ int16 messageList1_size;
+ int16 messageList2_size;
+ int16 messageList3_size;
+ int16 messageList4_size;
+ int16 array1[10];
+ int16 messageList1[10];
+ int16 messageList2[10];
+ int16 messageList3[10];
+ int16 messageList4[10];
+ int16 importsOffset;
+ int16 entryFlagsOffset;
+ int16 variablesOffset;
};
struct ConvControl {
- int running;
- int slot;
+ int16 running;
+ int16 index;
ConvStatus status;
- ConvStatus prior_status;
-
+ ConvStatus hold_status;
+ int16 has_text;
+ int16 popup_is_up;
+ int16 mask;
uint32 popup_clock;
+ int16 speaker_active[CONV_MAX_DATA];
+ int16 speaker_series[CONV_MAX_DATA];
+ int16 speaker_frame[CONV_MAX_DATA];
+ int16 x[CONV_MAX_DATA];
+ int16 y[CONV_MAX_DATA];
+ int16 width[CONV_MAX_DATA];
+ int16 speaker_val;
+ int16 person_speaking;
+ int16 node;
+ int16 entry;
+ int16 me_trigger;
+ int16 me_trigger_mode;
+ int16 you_trigger;
+ int16 you_trigger_mode;
+ int16 commands_allowed;
+ int16 input_mode;
};
+extern Conv *conv[CONV_MAX_DATA];
+extern ConvData *conv_data[CONV_MAX_DATA];
+
extern int conv_restore_running;
extern ConvControl conv_control;
extern int *conv_my_next_start;
@@ -75,6 +123,7 @@ extern void conv_system_cleanup();
extern void conv_get(int convNum);
extern void conv_run(int convNum);
extern void conv_update(bool);
+extern void conv_regenerate_last_message();
extern void conv_export_pointer(int *ptr);
extern void conv_abort();
extern void conv_me_trigger(int trigger);
@@ -84,6 +133,8 @@ extern void conv_export_value(int varNum);
extern void conv_hold();
extern void conv_release();
extern void conv_flush();
+extern int conv_append(Common::WriteStream *handle);
+extern int conv_expand(Common::SeekableReadStream *handle);
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/core/game.cpp b/engines/mads/madsv2/core/game.cpp
index 34080a216b9..98cdd0ad211 100644
--- a/engines/mads/madsv2/core/game.cpp
+++ b/engines/mads/madsv2/core/game.cpp
@@ -173,6 +173,7 @@ Popup *game_menu_popup; /* Popup structure for menu */
int debugger_previous = DEBUGGER_NONE;
int debugger_watch = 0;
int debugger_watch_index[DEBUGGER_MAX_WATCH];
+static int previous_running = -1000;
static void game_control_loop();
@@ -545,6 +546,7 @@ static void game_player_status() {
int game_parse_keystroke(int mykey) {
int count;
int temp;
+ long big_temp;
int move_object;
int move_target;
int change_flag;
@@ -601,23 +603,22 @@ int game_parse_keystroke(int mykey) {
break;
case ctrl_l_key:
- /* move_object = 0; */
- /* if (!popup_get_number(&move_object, "Examine Object", "Object #:", 3)) { */
- /* big_temp = move_object + 800; */
- /* if (!popup_get_long(&big_temp, "Object Message", "Message #:", 5)) { */
- /* object_examine (move_object, big_temp, 0); */
- /* } */
- /* } */
+ move_object = 0;
+ if (!popup_get_number(&move_object, "Examine Object", "Object #:", 3)) {
+ big_temp = move_object + 800;
+ if (!popup_get_long(&big_temp, "Object Message", "Message #:", 5)) {
+ object_examine(move_object, big_temp, 0);
+ }
+ }
break;
case ctrl_n_key:
- /* temp = 0; */
- /* if (!popup_get_number(&temp, "Activate Conversation", "Conv #:", 3)) { */
- /* pl conv_flush();
- conv_get(temp);
- conv_run(temp);
- */
- /* } */
+ temp = 0;
+ if (!popup_get_number(&temp, "Activate Conversation", "Conv #:", 3)) {
+ conv_flush();
+ conv_get(temp);
+ conv_run(temp);
+ }
break;
case ctrl_o_key:
@@ -971,53 +972,53 @@ int game_parse_keystroke(int mykey) {
case 'I':
case 'i':
num = (mykey == 'i') ? 1 : 5;
- /* pl y = conv_control.y[conv_control.person_speaking]; */
+ y = conv_control.y[conv_control.person_speaking];
if (y & POPUP_CENTER) y = 0;
y = MAX(y - num, 0);
- /* pl conv_control.y[conv_control.person_speaking] = y; */
- /* pl conv_regenerate_last_message(); */
+ conv_control.y[conv_control.person_speaking] = y;
+ conv_regenerate_last_message();
break;
case 'M':
case 'm':
num = (mykey == 'm') ? 1 : 5;
- /* pl conv_control.y[conv_control.person_speaking] += num; */
- /* pl conv_regenerate_last_message(); */
+ conv_control.y[conv_control.person_speaking] += num;
+ conv_regenerate_last_message();
break;
case 'J':
case 'j':
num = (mykey == 'j') ? 1 : 5;
- /* pl x = conv_control.x[conv_control.person_speaking]; */
+ x = conv_control.x[conv_control.person_speaking];
if (x & POPUP_CENTER) x = 0;
x = MAX(x - num, 0);
- /* pl conv_control.x[conv_control.person_speaking] = x; */
- /* pl conv_regenerate_last_message(); */
+ conv_control.x[conv_control.person_speaking] = x;
+ conv_regenerate_last_message();
break;
case 'K':
case 'k':
num = (mykey == 'k') ? 1 : 5;
- /* pl conv_control.x[conv_control.person_speaking] += num; */
- /* pl conv_regenerate_last_message(); */
+ conv_control.x[conv_control.person_speaking] += num;
+ conv_regenerate_last_message();
break;
case ',':
case '<':
num = (mykey == ',') ? 1 : 5;
- /* pl x = conv_control.width[conv_control.person_speaking]; */
+ x = conv_control.width[conv_control.person_speaking];
x = MAX(x - num, 10);
- /* pl conv_control.width[conv_control.person_speaking] = x; */
- /* pl conv_regenerate_last_message(); */
+ conv_control.width[conv_control.person_speaking] = x;
+ conv_regenerate_last_message();
break;
case '.':
case '>':
num = (mykey == '.') ? 1 : 5;
- /* pl x = conv_control.width[conv_control.person_speaking]; */
+ x = conv_control.width[conv_control.person_speaking];
x = MIN(x + num, 35);
- /* pl conv_control.width[conv_control.person_speaking] = x; */
- /* pl conv_regenerate_last_message(); */
+ conv_control.width[conv_control.person_speaking] = x;
+ conv_regenerate_last_message();
break;
case 0:
@@ -1284,7 +1285,7 @@ void game_control() {
game_exec_function(game_menu_init);
- /* pl conv_system_init(); */
+ conv_system_init();
result = main_copy_verify();
if (result == COPY_FAIL) {
@@ -1897,10 +1898,10 @@ static void game_handle_command() {
if (conv_control.running >= 0) {
player.look_around = false;
if ((conv_control.status == CONV_STATUS_WAIT_AUTO) ||
- (conv_control.status == CONV_STATUS_WAIT_ENTRY)) {
- player.commands_allowed = false;
+ (conv_control.status == CONV_STATUS_WAIT_ENTRY)) {
+ player.commands_allowed = false;
}
- }
+ }
handled_this_one = false;
if (kernel.trigger)
@@ -2265,7 +2266,7 @@ static void game_main_loop() {
}
if (new_room != room_id) {
- /* pl conv_abort(); */
+ conv_abort();
kernel_doom_all_animations();
goto skip_frame;
}
@@ -2279,21 +2280,19 @@ static void game_main_loop() {
game_system_maintenance();
if (new_room != room_id) {
- /* pl conv_abort(); */
+ conv_abort();
kernel_doom_all_animations();
goto skip_frame;
}
/* Update all active conversations */
-
- /* pl if (!kernel.trigger) {
- if (conv_control.running >= 0) {
- if (!camera_x.panning && !camera_y.panning) {
- conv_update (false);
+ if (!kernel.trigger) {
+ if (conv_control.running >= 0) {
+ if (!camera_x.panning && !camera_y.panning) {
+ conv_update(false);
+ }
}
- }
}
- */
/* Update the player image, if it is time to do so */
@@ -2325,8 +2324,10 @@ static void game_main_loop() {
if (!cursor_id) cursor_id = 1;
}
}
- if (!player.commands_allowed /*&& ((conv_control.running < 0) || conv_control.status == CONV_STATUS_HOLDING)*/) cursor_id = 2;
- /* if ((conv_control.running >= 0) && (cursor_id > 2)) cursor_id = 1; */
+ if (!player.commands_allowed && ((conv_control.running < 0) || conv_control.status == CONV_STATUS_HOLDING))
+ cursor_id = 2;
+ if ((conv_control.running >= 0) && (cursor_id > 2))
+ cursor_id = 1;
if (section_id != 9 || room_id == 904) {
cursor_id = MIN(cursor_id, cursor->num_sprites);
@@ -2911,99 +2912,97 @@ static void game_help_update() {
static void game_conversation() {
- /* pl
- static int previous_running = -1000;
- int x, y;
- int count, count2;
- int temp;
- int my_status;
- char temp_buf[80];
- Conv *my_conv;
- ConvData *my_data;
-
- if (conv_control.running != previous_running) {
+ int x, y;
+ int count, count2;
+ int temp;
+ int my_status;
+ char temp_buf[80];
+ Conv *my_conv;
+ ConvData *my_data;
+
+ if (conv_control.running != previous_running) {
game_debugger_reset();
- }
+ }
- previous_running = conv_control.running;
+ previous_running = conv_control.running;
- debugger_name ("6", 23);
+ debugger_name("6", 23);
- if (conv_control.running < 0) {
- screen_printf (0, 2, "(Conversation system inactive).");
+ if (conv_control.running < 0) {
+ screen_printf(0, 2, "(Conversation system inactive).");
goto done;
- } else {
- screen_printf (0, 2, "Conversation: %d", conv_control.running);
- }
+ } else {
+ screen_printf(0, 2, "Conversation: %d", conv_control.running);
+ }
- my_conv = conv[conv_control.index];
- my_data = conv_data[conv_control.index];
+ my_conv = conv[conv_control.index];
+ my_data = conv_data[conv_control.index];
- temp_buf[0] = 0;
- if (conv_control.status == CONV_STATUS_HOLDING) {
+ temp_buf[0] = 0;
+ if (conv_control.status == CONV_STATUS_HOLDING) {
my_status = conv_control.hold_status;
- } else {
+ } else {
my_status = conv_control.status;
- }
+ }
- switch (my_status) {
- case CONV_STATUS_NEXT_NODE:
- Common::strcpy_s (temp_buf, "Next");
- break;
+ switch (my_status) {
+ case CONV_STATUS_NEXT_NODE:
+ Common::strcpy_s(temp_buf, "Next");
+ break;
- case CONV_STATUS_WAIT_AUTO:
- Common::strcpy_s (temp_buf, "W-auto");
- break;
+ case CONV_STATUS_WAIT_AUTO:
+ Common::strcpy_s(temp_buf, "W-auto");
+ break;
- case CONV_STATUS_WAIT_ENTRY:
- Common::strcpy_s (temp_buf, "W-entry");
- break;
+ case CONV_STATUS_WAIT_ENTRY:
+ Common::strcpy_s(temp_buf, "W-entry");
+ break;
- case CONV_STATUS_EXECUTE:
- Common::strcpy_s (temp_buf, "Execute");
- break;
+ case CONV_STATUS_EXECUTE:
+ Common::strcpy_s(temp_buf, "Execute");
+ break;
- case CONV_STATUS_REPLY:
- default:
- Common::strcpy_s (temp_buf, "Reply");
- break;
- }
+ case CONV_STATUS_REPLY:
+ default:
+ Common::strcpy_s(temp_buf, "Reply");
+ break;
+ }
- if (conv_control.status == CONV_STATUS_HOLDING) {
- Common::strcat_s (temp_buf, " HOLD");
- }
+ if (conv_control.status == CONV_STATUS_HOLDING) {
+ Common::strcat_s(temp_buf, " HOLD");
+ }
- if (conv_control.popup_is_up) {
- Common::strcat_s (temp_buf, " Popup");
- }
+ if (conv_control.popup_is_up) {
+ Common::strcat_s(temp_buf, " Popup");
+ }
- screen_printf (0, 4, "Status: %-70s", temp_buf);
+ screen_printf(0, 4, "Status: %-70s", temp_buf);
- screen_printf (0, 6, "Node: %-3d Entry: %-3d", conv_control.node, conv_control.entry);
+ screen_printf(0, 6, "Node: %-3d Entry: %-3d", conv_control.node, conv_control.entry);
- screen_printf (0, 8, "Speaker: %-3d (Me: %-3d You: %-3d)", conv_control.person_speaking, conv_control.me_trigger, conv_control.you_trigger);
- temp = conv_control.person_speaking;
+ screen_printf(0, 8, "Speaker: %-3d (Me: %-3d You: %-3d)",
+ conv_control.person_speaking, conv_control.me_trigger, conv_control.you_trigger);
+ temp = conv_control.person_speaking;
- screen_printf (0, 9, " X: %-6d <=J K=>", conv_control.x[temp]);
- screen_printf (0, 10, " Y: %-6d <=I M=>", conv_control.y[temp]);
- screen_printf (0, 11, " W: %-6d <=, .=>", conv_control.width[temp]);
+ screen_printf(0, 9, " X: %-6d <=J K=>", conv_control.x[temp]);
+ screen_printf(0, 10, " Y: %-6d <=I M=>", conv_control.y[temp]);
+ screen_printf(0, 11, " W: %-6d <=, .=>", conv_control.width[temp]);
- for (count = 23; count < 143; count += 10) {
+ for (count = 23; count < 143; count += 10) {
y = ((count - 23) / 10) + 13;
x = 0;
if (count < my_conv->num_variables) {
- x = screen_printf (x, y, "%4d => ", count);
+ x = screen_printf(x, y, "%4d => ", count);
}
for (count2 = count; count2 < count + 10; count2++) {
- if (count2 < my_conv->num_variables) {
- x = screen_printf (x, y, "%04x ", *conv_get_variable(count2));
- }
+ if (count2 < my_conv->num_variables) {
+ x = screen_printf(x, y, "%04x ", *conv_get_variable(count2));
+ }
}
- }
+ }
- done:
- ;
- */
+done:
+ ;
}
@@ -3200,7 +3199,7 @@ void game_debugger() {
break;
case DEBUGGER_CONVERSATION:
- /* pl game_conversation(); */
+ game_conversation();
break;
case DEBUGGER_MATTE:
diff --git a/engines/mads/madsv2/core/kernel.cpp b/engines/mads/madsv2/core/kernel.cpp
index f3fa8d27984..272da1baed0 100644
--- a/engines/mads/madsv2/core/kernel.cpp
+++ b/engines/mads/madsv2/core/kernel.cpp
@@ -23,6 +23,7 @@
#include "mads/madsv2/core/kernel.h"
#include "mads/madsv2/core/mem.h"
#include "mads/madsv2/core/buffer.h"
+#include "mads/madsv2/core/conv.h"
#include "mads/madsv2/core/font.h"
#include "mads/madsv2/core/video.h"
#include "mads/madsv2/core/matte.h"
@@ -2656,12 +2657,13 @@ void kernel_dump_walker_only() {
player.walker_visible = false;
}
-int kernel_save_game(char *filename) {
+int kernel_save_game(const char *filename) {
int error_flag = true;
Load load_handle;
load_handle.open = false;
+ // TODO: Proper endian/saving
if (loader_open(&load_handle, filename, "wb", PACK_NONE)) goto done;
if (!loader_write(&game, sizeof(KernelGame), 1, &load_handle)) goto done;
@@ -2675,15 +2677,16 @@ int kernel_save_game(char *filename) {
if (!loader_write(global, sizeof(int) * global_list_size, 1, &load_handle)) goto done;
if (!loader_write(object, sizeof(Object) * num_objects, 1, &load_handle)) goto done;
if (!loader_write(0, sizeof(int), 1, &load_handle)) goto done;
- /* pl (see above line) if (!loader_write(&conv_control.running, sizeof(int), 1, &load_handle)) goto done; */
+ if (!loader_write(&conv_control.running, sizeof(int16), 1, &load_handle)) goto done;
if (!loader_write(&picture_view_x, sizeof(int), 1, &load_handle)) goto done;
if (!loader_write(&picture_view_y, sizeof(int), 1, &load_handle)) goto done;
+
if (!loader_write(room_state, sizeof(int) * OMR, 1, &load_handle)) goto done;
if (!loader_write(&previous_room, sizeof(int), 1, &load_handle)) goto done;
-
- /* pl if (conv_append(load_handle.handle)) goto done; */
-
+#ifdef TODO
+ if (conv_append(load_handle.handle)) goto done;
+#endif
error_flag = false;
done:
@@ -2691,7 +2694,7 @@ done:
return error_flag;
}
-int kernel_load_game(char *filename) {
+int kernel_load_game(const char *filename) {
int error_flag = true;
Load load_handle;
int save;
@@ -2719,7 +2722,7 @@ int kernel_load_game(char *filename) {
if (!loader_read(global, sizeof(int) * global_list_size, 1, &load_handle)) goto done;
if (!loader_read(object, sizeof(Object) * num_objects, 1, &load_handle)) goto done;
if (!loader_read(0, sizeof(int), 1, &load_handle)) goto done;
- /* pl (see above line) if (!loader_read(&conv_restore_running, sizeof(int), 1, &load_handle)) goto done; */
+ if (!loader_read(&conv_restore_running, sizeof(int), 1, &load_handle)) goto done;
/* Temporary support for old save file format */
if (load_handle.pack_list_marker >= (int)load_handle.pack.num_records) goto expand;
@@ -2730,7 +2733,7 @@ int kernel_load_game(char *filename) {
if (!loader_read(&previous_room, sizeof(int), 1, &load_handle)) goto done;
expand:
- /* pl if (conv_expand(load_handle.handle)) goto done; */
+ if (conv_expand(load_handle.handle)) goto done;
if (inven_num_objects > 0) {
active_inven = 0;
diff --git a/engines/mads/madsv2/core/kernel.h b/engines/mads/madsv2/core/kernel.h
index 59da91d2983..26dffed2604 100644
--- a/engines/mads/madsv2/core/kernel.h
+++ b/engines/mads/madsv2/core/kernel.h
@@ -563,8 +563,8 @@ extern void kernel_new_palette();
extern void kernel_dump_quotes();
extern void kernel_dump_all();
extern void kernel_dump_walker_only();
-extern int kernel_save_game(char *filename);
-extern int kernel_load_game(char *filename);
+extern int kernel_save_game(const char *filename);
+extern int kernel_load_game(const char *filename);
/**
* Initializes a random chatter sequence. (Parameters end with
Commit: c172f6ac0be8a33733171f9b1fe7088312565ab0
https://github.com/scummvm/scummvm/commit/c172f6ac0be8a33733171f9b1fe7088312565ab0
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:08+10:00
Commit Message:
MADS: PHANTOM: Fixes to interface display
Changed paths:
engines/mads/madsv2/core/anim.h
engines/mads/madsv2/core/game.cpp
engines/mads/madsv2/core/kernel.cpp
engines/mads/madsv2/core/kernel.h
diff --git a/engines/mads/madsv2/core/anim.h b/engines/mads/madsv2/core/anim.h
index 258f85967e3..04f086527bd 100644
--- a/engines/mads/madsv2/core/anim.h
+++ b/engines/mads/madsv2/core/anim.h
@@ -42,6 +42,7 @@ namespace MADSV2 {
#define ANIM_LOAD_TRANSLATE 0x0001 /* Translate to 16 colors */
#define ANIM_LOAD_BACKGROUND 0x0100 /* Load background picture */
#define ANIM_LOAD_BACK_ONLY 0x0200 /* Load background only */
+#define ANIM_INTERFACE 0x4000
/* these are mapped to misc[] in the AnimFile structure below */
diff --git a/engines/mads/madsv2/core/game.cpp b/engines/mads/madsv2/core/game.cpp
index 98cdd0ad211..a7ae00d94ef 100644
--- a/engines/mads/madsv2/core/game.cpp
+++ b/engines/mads/madsv2/core/game.cpp
@@ -1559,8 +1559,6 @@ void game_control() {
global_room_init();
- kernel_set_interface_mode(INTER_LIMITED_SENTENCES);
-
game_exec_function(room_init_code_pointer);
#if 0
/* paul - oh no! magic numbers! */
diff --git a/engines/mads/madsv2/core/kernel.cpp b/engines/mads/madsv2/core/kernel.cpp
index 272da1baed0..95f2751cc49 100644
--- a/engines/mads/madsv2/core/kernel.cpp
+++ b/engines/mads/madsv2/core/kernel.cpp
@@ -223,8 +223,6 @@ void kernel_game_shutdown() {
sprite_free(&box_param.logo, true);
sprite_free(&box_param.series, true);
- buffer_free(&scr_inter_orig);
-
vocab_unload_active();
/* Drop cursor */
@@ -533,14 +531,6 @@ int kernel_game_startup(int game_video_mode, int load_flag,
vocab_load_active();
}
- if (load_flag & KERNEL_STARTUP_INTERFACE) {
- buffer_init_name(&scr_inter_orig, video_x, inter_size_y, "$scrintr");
- if (scr_inter_orig.data == NULL) {
- error_code = ERROR_NO_MORE_MEMORY;
- goto done;
- }
- }
-
if (load_flag & KERNEL_STARTUP_POPUP) {
if (popup_box_load()) {
error_code = ERROR_KERNEL_NO_POPUP;
@@ -584,6 +574,15 @@ int kernel_section_startup(int newSection) {
void kernel_room_shutdown() {
inter_deallocate_objects();
+ if (inter_anim) {
+ anim_unload((AnimPtr)inter_anim);
+ buffer_free(&scr_inter_orig);
+ mem_free(inter_anim);
+ inter_anim = nullptr;
+ } else if (scr_inter_orig.data) {
+ buffer_free(&scr_inter_orig);
+ }
+
/* Dump the room hot spots */
if (room_spots != NULL) {
mem_free(room_spots);
@@ -622,6 +621,8 @@ int kernel_room_startup(int newRoom, int initial_variant, const char *interface,
room_id = newRoom;
room_variant = initial_variant;
+ scr_inter_orig.data = nullptr;
+
/* Start a brand new palette, reserving the proper # of colors */
if (new_palette)
pal_init(KERNEL_RESERVED_LOW_COLORS, KERNEL_RESERVED_HIGH_COLORS);
@@ -689,8 +690,6 @@ int kernel_room_startup(int newRoom, int initial_variant, const char *interface,
rail_connect_all_nodes();
- inter_anim = NULL;
-
/* Make preliminary scaling computations */
kernel_room_bound_dif = room->front_y - room->back_y;
@@ -713,26 +712,42 @@ int kernel_room_startup(int newRoom, int initial_variant, const char *interface,
if (barebones) {
room_spots = nullptr;
+ goto finish;
+ }
- } else {
- // Load up the room's hotspot table
- room_spots = room_load_hotspots(room_id, &room_num_spots);
- if (room_spots == NULL) {
+ // Load up the room's hotspot table
+ room_spots = room_load_hotspots(room_id, &room_num_spots);
+ if (room_spots == NULL) {
#ifndef disable_error_check
- error_code = ERROR_KERNEL_NO_HOTSPOTS;
+ error_code = ERROR_KERNEL_NO_HOTSPOTS;
#endif
- goto done;
- }
+ goto done;
+ }
- // Set up interface background screen
- kernel_set_interface_mode(inter_input_mode);
+ kernel_load_vocab();
- // Mouse cursor on
- mouse_show();
+ pal_activate_shadow(&kernel_shadow_inter);
+ load_flags = ANIM_LOAD_BACKGROUND | ANIM_INTERFACE;
+ if (kernel.translating)
+ load_flags |= ANIM_LOAD_TRANSLATE;
+ inter_anim = (AnimInterPtr)anim_load(interface, &scr_inter_orig, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr, nullptr, load_flags);
+ if (!inter_anim) goto done;
- inter_allocate_objects();
+ if (!inter_anim->font) {
+ mem_free(inter_anim);
+ inter_anim = nullptr;
}
+ // Set up interface background screen
+ kernel_set_interface_mode(inter_input_mode);
+
+ // Mouse cursor on
+ mouse_show();
+
+ inter_allocate_objects();
+
+finish:
error_flag = false;
done:
@@ -2916,34 +2931,24 @@ done:
return generated_one;
}
-void kernel_load_interface() {
- char temp_buf[80];
- char *mark;
+void kernel_set_interface_mode(int mode) {
+ if (mode != inter_input_mode) {
+ char fname[80];
+ Common::strcpy_s(fname, kernel.interface + 1);
+ char *dot = strchr(fname, '.');
- Common::strcpy_s(temp_buf, kernel.interface);
- mark = strchr(temp_buf, '.');
- if (mark != NULL) {
- *mark = 0;
- }
- if (inter_input_mode != INTER_BUILDING_SENTENCES) {
- Common::strcat_s(temp_buf, "A");
- }
- Common::strcat_s(temp_buf, ".INT");
+ if (dot) {
+ *dot = '\0';
+ if (mode != INTER_BUILDING_SENTENCES)
+ Common::strcat_s(fname, "A");
+ Common::strcat_s(fname, ".INT");
- if (strcmp(kernel_interface_loaded, temp_buf)) {
- buffer_free(&scr_inter_orig);
- pal_activate_shadow(&kernel_shadow_inter);
- if (inter_load_background(temp_buf, &scr_inter_orig)) {
- error_report(ERROR_KERNEL_NO_INTERFACE, SEVERE, MODULE_KERNEL, inter_input_mode, 0);
+ buffer_free(&scr_inter_orig);
+ inter_load_background(fname, &scr_inter_orig);
}
- Common::strcpy_s(kernel_interface_loaded, temp_buf);
- pal_activate_shadow(&kernel_shadow_main);
}
-}
-void kernel_set_interface_mode(int mode) {
inter_input_mode = mode;
- kernel_load_interface();
image_inter_marker = 1;
image_inter_list[0].flags = IMAGE_REFRESH;
@@ -2970,7 +2975,8 @@ void kernel_set_interface_mode(int mode) {
inter_init_sentence();
inter_setup_hotspots();
- if (!viewing_at_y) inter_prepare_background();
+ if (!viewing_at_y)
+ inter_prepare_background();
kernel_refresh_dynamic();
}
diff --git a/engines/mads/madsv2/core/kernel.h b/engines/mads/madsv2/core/kernel.h
index 26dffed2604..26e046702e7 100644
--- a/engines/mads/madsv2/core/kernel.h
+++ b/engines/mads/madsv2/core/kernel.h
@@ -140,7 +140,7 @@ namespace MADSV2 {
#define KERNEL_STARTUP_CURSOR 0x0200
#define KERNEL_STARTUP_CURSOR_SHOW 0x0100
#define KERNEL_STARTUP_VOCAB 0x0080
-#define KERNEL_STARTUP_INTERFACE 0x0040
+//#define KERNEL_STARTUP_INTERFACE 0x0040
#define KERNEL_STARTUP_ALL_FLAGS 0xffc0
typedef struct {
@@ -596,7 +596,6 @@ extern void kernel_random_message_server();
extern int kernel_generate_random_message(int chance_major, int chance_minor);
extern void kernel_random_purge();
-extern void kernel_load_interface();
/**
* Switches interface modes (INTER_BUILDING_SENTENCES is the normal mode;
Commit: ed1a06e39fdd4d14e1454641e39b14f60cf06859
https://github.com/scummvm/scummvm/commit/ed1a06e39fdd4d14e1454641e39b14f60cf06859
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:08+10:00
Commit Message:
MADS: PHANTOM: Implementing conv code
Changed paths:
engines/mads/madsv2/core/conv.cpp
engines/mads/madsv2/core/conv.h
engines/mads/madsv2/core/inter.cpp
engines/mads/madsv2/core/tile.cpp
diff --git a/engines/mads/madsv2/core/conv.cpp b/engines/mads/madsv2/core/conv.cpp
index c4199d496ab..d96c2c5e8c4 100644
--- a/engines/mads/madsv2/core/conv.cpp
+++ b/engines/mads/madsv2/core/conv.cpp
@@ -20,9 +20,17 @@
*/
#include "common/algorithm.h"
-#include "common/str.h"
+#include "common/memstream.h"
#include "common/textconsole.h"
#include "mads/madsv2/core/conv.h"
+#include "mads/madsv2/core/general.h"
+#include "mads/madsv2/core/fileio.h"
+#include "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/inter.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/matte.h"
+#include "mads/madsv2/core/mem.h"
+#include "mads/madsv2/core/popup.h"
namespace MADS {
namespace MADSV2 {
@@ -33,11 +41,57 @@ Conv *active_conv;
ConvData *active_conv_data;
int conv_restore_running;
ConvControl conv_control;
+Box conv_box;
int *conv_my_next_start;
+int conv_error_code;
static int conv_slot_indexes[CONV_MAX_SLOTS];
static int conv_slots[CONV_MAX_DATA];
+
+
+void Conv::load(Common::SeekableReadStream *src) {
+ src->readMultipleLE(node_count, dialog_count, message_count, text_line_count,
+ num_variables, max_imports, speaker_count);
+ for (int i = 0; i < 5; ++i)
+ src->read(speaker_portraits[i], 16);
+ for (int i = 0; i < 5; ++i)
+ speaker_frame[i] = src->readSint16LE();
+ src->read(speech_file, 14);
+ src->readMultipleLE(text_length, commands_length);
+
+ // In the original these are far pointers patched after load; read as
+ // raw offsets and store temporarily - conv_load_data resolves them.
+ uint32 text_off, scripts_off, nodes_off, dialogs_off, messages_off, text_lines_off;
+ src->readMultipleLE(text_off, scripts_off, nodes_off, dialogs_off, messages_off, text_lines_off);
+ text_ptr = (void *)(uintptr_t)text_off;
+ scripts_ptr = (void *)(uintptr_t)scripts_off;
+ nodes_ptr = (void *)(uintptr_t)nodes_off;
+ dialogs_ptr = (void *)(uintptr_t)dialogs_off;
+ messages_ptr = (void *)(uintptr_t)messages_off;
+ text_lines_ptr = (void *)(uintptr_t)text_lines_off;
+}
+
+void ConvNode::load(Common::SeekableReadStream *src) {
+ src->readMultipleLE(index, dialog_count, active, field_6, field_8);
+}
+
+void ConvDialog::load(Common::SeekableReadStream *src) {
+ src->readMultipleLE(text_line_index, speech_index, script_offset, script_size);
+}
+
+void ConvScriptParams::load(Common::SeekableReadStream *src) {
+ operation = src->readSint16LE();
+ param1IsVar = src->readByte();
+ param2IsVar = src->readByte();
+ src->readMultipleLE(param1, param2);
+}
+
+void ConvVariable::load(Common::SeekableReadStream *src) {
+ src->readMultipleLE(isPtr, val, unused);
+}
+
+
static const char *conv_get_filename(int convNum, int extType, char *name) {
*name = '\0';
@@ -51,9 +105,118 @@ static const char *conv_get_filename(int convNum, int extType, char *name) {
return name;
}
-static ConvData *conv_load_data(const char *fname) {
- // TODO
- return nullptr;
+static Conv *conv_load_data(const char *fname) {
+ Load file;
+ Conv convHeader;
+ Conv *dataPtr = nullptr;
+ Conv *result = nullptr;
+ char filename[80];
+ char name_buf[9];
+
+ file.open = false;
+
+ Common::strcpy_s(filename, fname);
+ fileio_add_ext(filename, "cnv");
+
+ // Strip leading '*' (wildcard prefix used for himem search) to get bare name
+ const char *fn = (filename[0] == '*') ? filename + 1 : filename;
+ Common::strlcpy(name_buf, fn, sizeof(name_buf));
+
+ if (loader_open(&file, filename, "rb", true)) {
+ conv_error_code = 1;
+ goto done;
+ }
+
+ {
+ // Read the fixed-size Conv header through a MemoryReadStream so that
+ // the load() function handles field sizes and endianness correctly.
+ byte hdrBuf[Conv::SIZE];
+ if (!loader_read(hdrBuf, Conv::SIZE, 1, &file)) {
+ conv_error_code = 2;
+ goto done;
+ }
+ Common::MemoryReadStream hdrStream(hdrBuf, Conv::SIZE);
+ convHeader.load(&hdrStream);
+ }
+
+ {
+ // Calculate total allocation size. The +15 on node_count matches the
+ // original: the DOS allocator rounded up to paragraph (16-byte) boundaries
+ // for the nodes sub-array so that far-pointer normalisation never overflows.
+ long nodeBytes = (long)(convHeader.node_count + 15) * ConvNode::SIZE;
+ long dialogBytes = (long)convHeader.dialog_count * ConvDialog::SIZE;
+ long messageBytes = (long)convHeader.message_count * 4; // 2 x int16 per entry
+ long textLineBytes = (long)convHeader.text_line_count * 2; // 1 x int16 per entry
+ long total = Conv::SIZE + nodeBytes + dialogBytes + messageBytes
+ + textLineBytes + (long)convHeader.text_length
+ + (long)convHeader.commands_length;
+
+ dataPtr = (Conv *)mem_get_name(total, name_buf);
+ if (!dataPtr) {
+ conv_error_code = 3;
+ goto done;
+ }
+
+ // Copy the loaded header to the front of the block, then fix up all
+ // sub-array pointers to point into the memory immediately following.
+ *dataPtr = convHeader;
+ byte *p = (byte *)dataPtr + Conv::SIZE;
+
+ dataPtr->nodes_ptr = p; p += nodeBytes;
+ dataPtr->dialogs_ptr = p; p += dialogBytes;
+ dataPtr->messages_ptr = p; p += messageBytes;
+ dataPtr->text_lines_ptr = p; p += textLineBytes;
+ dataPtr->text_ptr = p; p += convHeader.text_length;
+ dataPtr->scripts_ptr = p;
+
+ // Read each section from the file. Error codes deliberately match the
+ // originals (note: 6 is skipped, matching the disassembly).
+ if (!loader_read(dataPtr->nodes_ptr,
+ (long)convHeader.node_count * ConvNode::SIZE, 1, &file)) {
+ conv_error_code = 4;
+ goto done;
+ }
+
+ if (!loader_read(dataPtr->dialogs_ptr,
+ (long)convHeader.dialog_count * ConvDialog::SIZE, 1, &file)) {
+ conv_error_code = 5;
+ goto done;
+ }
+
+ if (!loader_read(dataPtr->messages_ptr,
+ (long)convHeader.message_count * 4, 1, &file)) {
+ conv_error_code = 7;
+ goto done;
+ }
+
+ if (!loader_read(dataPtr->text_lines_ptr,
+ (long)convHeader.text_line_count * 2, 1, &file)) {
+ conv_error_code = 8;
+ goto done;
+ }
+
+ if (!loader_read(dataPtr->text_ptr, convHeader.text_length, 1, &file)) {
+ conv_error_code = 9;
+ goto done;
+ }
+
+ if (!loader_read(dataPtr->scripts_ptr, convHeader.commands_length, 1, &file)) {
+ conv_error_code = 10;
+ goto done;
+ }
+
+ result = dataPtr;
+ }
+
+done:
+ if (file.open)
+ loader_close(&file);
+
+ // Free the block if we bailed out before completing the load
+ if (dataPtr && dataPtr != result)
+ mem_free(dataPtr);
+
+ return result;
}
void conv_system_init() {
@@ -71,6 +234,22 @@ void conv_system_cleanup() {
// Removes any files with the format 'conv%d.dat'
}
+static void conv_purge_any_popup() {
+ if (conv_control.popup_is_up) {
+ Box *my_box = box;
+ box = &conv_box;
+ popup_destroy();
+ matte_frame(0, 0);
+
+ if ((box->y + box->ys) >= 156)
+ matte_inter_frame(-1, -1);
+
+ box = my_box;
+ conv_control.popup_is_up = 0;
+ conv_control.popup_clock = kernel.clock;
+ }
+}
+
void conv_get(int convNum) {
int free_slot = -1;
char fname[40];
@@ -98,7 +277,25 @@ void conv_regenerate_last_message() {
void conv_export_pointer(int *ptr) {}
-void conv_abort() {}
+void conv_abort() {
+ if (conv_control.running >= 0) {
+ if (kernel_mode == KERNEL_ACTIVE_CODE)
+ player.commands_allowed = conv_control.commands_allowed;
+
+ conv_control.running = -1;
+ conv_purge_any_popup();
+
+ for (int i = conv[conv_control.index]->speaker_count - 1; i >= 0; --i) {
+ if (conv_control.speaker_active[i])
+ matte_deallocate_series(conv_control.speaker_series[i], -1);
+ }
+
+ if (conv_control.input_mode == INTER_CONVERSATION)
+ kernel_init_dialog();
+
+ kernel_set_interface_mode(conv_control.input_mode);
+ }
+}
void conv_me_trigger(int trigger) {}
diff --git a/engines/mads/madsv2/core/conv.h b/engines/mads/madsv2/core/conv.h
index 34d3c623190..237716597e2 100644
--- a/engines/mads/madsv2/core/conv.h
+++ b/engines/mads/madsv2/core/conv.h
@@ -60,6 +60,50 @@ struct Conv {
void *dialogs_ptr;
void *messages_ptr;
void *text_lines_ptr;
+
+ static constexpr int SIZE = 2 * 7 + 16 * 5 + 2 * 5 + 14 + 4 + 4 + 4 * 6;
+ void load(Common::SeekableReadStream *src);
+};
+
+struct ConvNode {
+ int16 index;
+ int16 dialog_count;
+ int16 active;
+ int16 field_6;
+ int16 field_8;
+
+ static constexpr int SIZE = 2 * 5;
+ void load(Common::SeekableReadStream *src);
+};
+
+struct ConvDialog {
+ int16 text_line_index;
+ int16 speech_index;
+ int16 script_offset;
+ int16 script_size;
+
+ static constexpr int SIZE = 2 * 4;
+ void load(Common::SeekableReadStream *src);
+};
+
+struct ConvScriptParams {
+ int16 operation;
+ byte param1IsVar;
+ byte param2IsVar;
+ int16 param1;
+ int16 param2;
+
+ static constexpr int SIZE = 2 + 1 + 1 + 2 + 2;
+ void load(Common::SeekableReadStream *src);
+};
+
+struct ConvVariable {
+ int16 isPtr;
+ int16 val;
+ int16 unused;
+
+ static constexpr int SIZE = 2 * 3;
+ void load(Common::SeekableReadStream *src);
};
struct ConvData {
diff --git a/engines/mads/madsv2/core/inter.cpp b/engines/mads/madsv2/core/inter.cpp
index dc8de558380..ff7f02b30e2 100644
--- a/engines/mads/madsv2/core/inter.cpp
+++ b/engines/mads/madsv2/core/inter.cpp
@@ -2315,5 +2315,6 @@ done:
if (load_handle.open) loader_close(&load_handle);
return error_flag;
}
+
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/core/tile.cpp b/engines/mads/madsv2/core/tile.cpp
index e75624593d8..30484bea0fa 100644
--- a/engines/mads/madsv2/core/tile.cpp
+++ b/engines/mads/madsv2/core/tile.cpp
@@ -524,12 +524,8 @@ done:
}
-int tile_buffer(Buffer *target,
- TileResource *tile_resource,
- TileMapHeader *map,
- int tile_x,
- int tile_y) {
- int error_flag = true;
+int tile_buffer(Buffer *target, TileResource *tile_resource,
+ TileMapHeader *map, int tile_x, int tile_y) {
int default_value;
int x, y;
int size_x;
@@ -578,10 +574,7 @@ int tile_buffer(Buffer *target,
}
}
- error_flag = false;
-
-done:
- return error_flag;
+ return false;
}
Commit: d00f73cca86eb1400a14dff4c5d399d636d099c0
https://github.com/scummvm/scummvm/commit/d00f73cca86eb1400a14dff4c5d399d636d099c0
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:08+10:00
Commit Message:
MADS: PHANTOM: More conv init code
Changed paths:
engines/mads/madsv2/core/conv.cpp
engines/mads/madsv2/core/conv.h
engines/mads/madsv2/core/env.h
diff --git a/engines/mads/madsv2/core/conv.cpp b/engines/mads/madsv2/core/conv.cpp
index d96c2c5e8c4..e258b7cce44 100644
--- a/engines/mads/madsv2/core/conv.cpp
+++ b/engines/mads/madsv2/core/conv.cpp
@@ -24,6 +24,7 @@
#include "common/textconsole.h"
#include "mads/madsv2/core/conv.h"
#include "mads/madsv2/core/general.h"
+#include "mads/madsv2/core/env.h"
#include "mads/madsv2/core/fileio.h"
#include "mads/madsv2/core/game.h"
#include "mads/madsv2/core/inter.h"
@@ -39,13 +40,17 @@ Conv *conv[CONV_MAX_DATA];
ConvData *conv_data[CONV_MAX_DATA];
Conv *active_conv;
ConvData *active_conv_data;
+int16 *conv_imports;
+int16 *conv_entry_flags;
+ConvVariable *conv_varsDataPtr;
+int16 *conv_vars0ValPtr;
int conv_restore_running;
ConvControl conv_control;
Box conv_box;
int *conv_my_next_start;
int conv_error_code;
-static int conv_slot_indexes[CONV_MAX_SLOTS];
+static int conv_indexes[CONV_MAX_SLOTS];
static int conv_slots[CONV_MAX_DATA];
@@ -61,7 +66,7 @@ void Conv::load(Common::SeekableReadStream *src) {
src->readMultipleLE(text_length, commands_length);
// In the original these are far pointers patched after load; read as
- // raw offsets and store temporarily - conv_load_data resolves them.
+ // raw offsets and store temporarily - load_conv resolves them.
uint32 text_off, scripts_off, nodes_off, dialogs_off, messages_off, text_lines_off;
src->readMultipleLE(text_off, scripts_off, nodes_off, dialogs_off, messages_off, text_lines_off);
text_ptr = (void *)(uintptr_t)text_off;
@@ -91,6 +96,19 @@ void ConvVariable::load(Common::SeekableReadStream *src) {
src->readMultipleLE(isPtr, val, unused);
}
+void ConvData::load(Common::SeekableReadStream *src) {
+ src->readMultipleLE(currentNode, entryFlagsCount, variablesCount,
+ importsCount, numImports, array1_size,
+ messageList1_size, messageList2_size, messageList3_size, messageList4_size);
+ src->readMultipleLE(array1);
+ src->readMultipleLE(messageList1);
+ src->readMultipleLE(messageList2);
+ src->readMultipleLE(messageList3);
+ src->readMultipleLE(messageList4);
+ src->readMultipleLE(importsOffset, entryFlagsOffset, variablesOffset);
+}
+
+//====================================================================
static const char *conv_get_filename(int convNum, int extType, char *name) {
*name = '\0';
@@ -105,7 +123,12 @@ static const char *conv_get_filename(int convNum, int extType, char *name) {
return name;
}
-static Conv *conv_load_data(const char *fname) {
+static Common::SeekableReadStream *conv_open(int convNum) {
+ char name[40];
+ return env_open(conv_get_filename(convNum, 2, name));
+}
+
+static Conv *load_conv(const char *fname) {
Load file;
Conv convHeader;
Conv *dataPtr = nullptr;
@@ -219,19 +242,133 @@ done:
return result;
}
-void conv_system_init() {
- Common::fill((byte *)&conv_control, (byte *)&conv_control + sizeof(ConvControl), 0);
- conv_control.running = -1;
+static ConvData *load_conv_data(const char *fname) {
+ Load file;
+ ConvData cndHeader;
+ ConvData *dataPtr = nullptr;
+ ConvData *result = nullptr;
+ char filename[80];
+ char name_buf[9];
- Common::fill(conv_slot_indexes, conv_slot_indexes + CONV_MAX_SLOTS, 0);
- Common::fill(conv_slots, conv_slots + CONV_MAX_DATA, 0);
- Common::fill(conv, conv + CONV_MAX_DATA, (Conv *)nullptr);
- Common::fill(conv_data, conv_data + CONV_MAX_DATA, (ConvData *)nullptr);
- conv_system_cleanup();
+ file.open = false;
+
+ Common::strcpy_s(filename, fname);
+ fileio_add_ext(filename, "cnv");
+
+ const char *fn = (filename[0] == '*') ? filename + 1 : filename;
+ Common::strlcpy(name_buf, fn, sizeof(name_buf));
+
+ if (loader_open(&file, filename, "rb", true))
+ goto done;
+
+ {
+ byte hdrBuf[ConvData::SIZE];
+ if (!loader_read(hdrBuf, ConvData::SIZE, 1, &file))
+ goto done;
+
+ Common::MemoryReadStream hdrStream(hdrBuf, ConvData::SIZE);
+ cndHeader.load(&hdrStream);
+ }
+
+ {
+ // Total allocation = ConvData header + imports array + entry flags array
+ // + variables array. The +21 on variablesCount is paragraph-alignment
+ // padding; 21 * 3 * 2 = 126 = ConvData::SIZE, so the header cost is
+ // already baked into the formula without a separate +ConvData::SIZE term.
+ long total = ((long)(cndHeader.variablesCount + 21) * 3
+ + cndHeader.importsCount + cndHeader.entryFlagsCount) * 2;
+
+ dataPtr = (ConvData *)mem_get_name(total, name_buf);
+ if (!dataPtr)
+ goto done;
+
+ *dataPtr = cndHeader;
+
+ // Sub-array byte offsets from the start of the block.
+ // 63 = ConvData::SIZE / 2; using it as a word-count base yields the
+ // correct byte offset arithmetic when multiplied by 2.
+ dataPtr->importsOffset = ConvData::SIZE;
+ dataPtr->entryFlagsOffset = (int16)((cndHeader.importsCount + 63) * 2);
+ dataPtr->variablesOffset = (int16)((cndHeader.entryFlagsCount
+ + cndHeader.importsCount + 63) * 2);
+
+ byte *block = (byte *)dataPtr;
+
+ // Imports: conditional â the original skips the loader_read when count <= 0
+ if (cndHeader.importsCount > 0) {
+ if (!loader_read(block + dataPtr->importsOffset,
+ (long)cndHeader.importsCount * 2, 1, &file))
+ goto done;
+ }
+
+ // Entry flags: always read (no count guard in the original)
+ if (!loader_read(block + dataPtr->entryFlagsOffset,
+ (long)cndHeader.entryFlagsCount * 2, 1, &file))
+ goto done;
+
+ // Variables
+ if (!loader_read(block + dataPtr->variablesOffset,
+ (long)cndHeader.variablesCount * ConvVariable::SIZE, 1, &file))
+ goto done;
+
+ // Zero the runtime isPtr flag for every variable; it is not meaningful
+ // as stored on disk
+ if (cndHeader.variablesCount > 0) {
+ ConvVariable *vars = (ConvVariable *)(block + dataPtr->variablesOffset);
+ for (int i = 0; i < cndHeader.variablesCount; ++i)
+ vars[i].isPtr = 0;
+ }
+
+ result = dataPtr;
+ }
+
+done:
+ if (file.open)
+ loader_close(&file);
+
+ if (dataPtr && dataPtr != result)
+ mem_free(dataPtr);
+
+ return result;
}
-void conv_system_cleanup() {
- // Removes any files with the format 'conv%d.dat'
+static ConvData *conv_read_data(Common::SeekableReadStream *src) {
+ byte buffer[ConvData::SIZE];
+ if (src->read(buffer, ConvData::SIZE) != ConvData::SIZE)
+ error("Reading ConvData header");
+
+ // TODO
+ error("TODO: conv_read_data");
+}
+
+static void conv_init(ConvData *convData, int val) {
+ conv_start(convData, nullptr);
+
+ for (int i = 0; i < convData->entryFlagsCount; ++i) {
+ uint16 *flag = (uint16 *)((byte *)convData + convData->entryFlagsOffset);
+ *flag &= 0x3fff;
+
+ if ((*flag & 1) || ((*flag & 4) && val))
+ *flag |= 0x8000;
+ }
+}
+
+static ConvData *conv_get_data(int convNum) {
+ ConvData *convData = nullptr;
+ char name[80];
+
+ if (conv_indexes[convNum]) {
+ Common::SeekableReadStream *handle = conv_open(convNum);
+ if (handle) {
+ convData = conv_read_data(handle);
+ delete handle;
+ }
+ } else {
+ convData = load_conv_data(conv_get_filename(convNum, 1, name));
+ conv_init(convData, 0);
+ }
+
+ return convData;
}
static void conv_purge_any_popup() {
@@ -250,6 +387,47 @@ static void conv_purge_any_popup() {
}
}
+void conv_system_init() {
+ Common::fill((byte *)&conv_control, (byte *)&conv_control + sizeof(ConvControl), 0);
+ conv_control.running = -1;
+
+ Common::fill(conv_indexes, conv_indexes + CONV_MAX_SLOTS, 0);
+ Common::fill(conv_slots, conv_slots + CONV_MAX_DATA, 0);
+ Common::fill(conv, conv + CONV_MAX_DATA, (Conv *)nullptr);
+ Common::fill(conv_data, conv_data + CONV_MAX_DATA, (ConvData *)nullptr);
+ conv_system_cleanup();
+}
+
+void conv_system_cleanup() {
+ // Removes any files with the format 'conv%d.dat'
+}
+
+
+void conv_start(ConvData *convData, Conv *convIn) {
+ active_conv = convIn;
+ active_conv_data = convData;
+
+ byte *block = (byte *)convData;
+
+ // Resolve the byte-offset sub-array pointers stored in the ConvData block
+ conv_imports = (int16 *)(block + convData->importsOffset);
+ conv_entry_flags = (int16 *)(block + convData->entryFlagsOffset);
+ conv_varsDataPtr = (ConvVariable *)(block + convData->variablesOffset);
+
+ // conv_vars0ValPtr -> variables[0].val (skips the isPtr field)
+ conv_vars0ValPtr = &conv_varsDataPtr[0].val;
+
+ // conv_my_next_start -> variables[1].val
+ // (offset = offsetof(ConvVariable, val) + sizeof(ConvVariable) from base)
+ conv_my_next_start = (int *)&conv_varsDataPtr[1].val;
+
+ convData->currentNode = -1;
+ convData->numImports = 0;
+
+ // Initialise variables[0].val from variables[1].val
+ *conv_vars0ValPtr = (int16)*conv_my_next_start;
+}
+
void conv_get(int convNum) {
int free_slot = -1;
char fname[40];
@@ -261,7 +439,7 @@ void conv_get(int convNum) {
if (free_slot >= 0) {
conv_slots[free_slot] = -1;
- (void)conv_load_data(conv_get_filename(convNum, 0, fname));
+ (void)load_conv(conv_get_filename(convNum, 0, fname));
// TODO: More stuff
}
}
diff --git a/engines/mads/madsv2/core/conv.h b/engines/mads/madsv2/core/conv.h
index 237716597e2..383aa8b97f6 100644
--- a/engines/mads/madsv2/core/conv.h
+++ b/engines/mads/madsv2/core/conv.h
@@ -125,6 +125,13 @@ struct ConvData {
int16 importsOffset;
int16 entryFlagsOffset;
int16 variablesOffset;
+
+ // On-disk size: 10 header words + 5 arrays of 10 words + 3 offset words
+ // = 20 + 100 + 6 = 126 = 0x7E. The +21 padding in load_conv_data
+ // exploits the fact that 21 * 6 = 126, so the formula automatically
+ // includes the header in the total allocation.
+ static constexpr int SIZE = 2 * 10 + 2 * 10 * 5 + 2 * 3;
+ void load(Common::SeekableReadStream *src);
};
struct ConvControl {
@@ -156,6 +163,13 @@ struct ConvControl {
extern Conv *conv[CONV_MAX_DATA];
extern ConvData *conv_data[CONV_MAX_DATA];
+extern Conv *active_conv;
+extern ConvData *active_conv_data;
+
+extern int16 *conv_imports;
+extern int16 *conv_entry_flags;
+extern ConvVariable *conv_varsDataPtr;
+extern int16 *conv_vars0ValPtr;
extern int conv_restore_running;
extern ConvControl conv_control;
@@ -164,6 +178,7 @@ extern int *conv_my_next_start;
extern void conv_system_init();
extern void conv_system_cleanup();
+extern void conv_start(ConvData *convData, Conv *convIn);
extern void conv_get(int convNum);
extern void conv_run(int convNum);
extern void conv_update(bool);
diff --git a/engines/mads/madsv2/core/env.h b/engines/mads/madsv2/core/env.h
index a7a0d0dbd42..a3ca7293120 100644
--- a/engines/mads/madsv2/core/env.h
+++ b/engines/mads/madsv2/core/env.h
@@ -75,7 +75,7 @@ extern char env_null[7];
extern int env_verify(void);
-extern Common::SeekableReadStream *env_open(const char *file_path, const char *options);
+extern Common::SeekableReadStream *env_open(const char *file_path, const char *options = "rb");
extern int env_exist(const char *file_name);
extern long env_get_file_size(Common::SeekableReadStream *handle);
extern char *env_get_path(char *madspath, const char *infile);
Commit: 32ddacaabaf1fcc0c6f8723ce844a88a06159ac9
https://github.com/scummvm/scummvm/commit/32ddacaabaf1fcc0c6f8723ce844a88a06159ac9
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:09+10:00
Commit Message:
MADS: PHANTOM: Changing conv/conv data to use Common::Array
Changed paths:
engines/mads/madsv2/core/conv.cpp
engines/mads/madsv2/core/conv.h
diff --git a/engines/mads/madsv2/core/conv.cpp b/engines/mads/madsv2/core/conv.cpp
index e258b7cce44..d11f29260c3 100644
--- a/engines/mads/madsv2/core/conv.cpp
+++ b/engines/mads/madsv2/core/conv.cpp
@@ -41,7 +41,7 @@ ConvData *conv_data[CONV_MAX_DATA];
Conv *active_conv;
ConvData *active_conv_data;
int16 *conv_imports;
-int16 *conv_entry_flags;
+uint16 *conv_entry_flags;
ConvVariable *conv_varsDataPtr;
int16 *conv_vars0ValPtr;
int conv_restore_running;
@@ -54,8 +54,7 @@ static int conv_indexes[CONV_MAX_SLOTS];
static int conv_slots[CONV_MAX_DATA];
-
-void Conv::load(Common::SeekableReadStream *src) {
+void ConvHeader::load(Common::SeekableReadStream *src) {
src->readMultipleLE(node_count, dialog_count, message_count, text_line_count,
num_variables, max_imports, speaker_count);
for (int i = 0; i < 5; ++i)
@@ -67,14 +66,8 @@ void Conv::load(Common::SeekableReadStream *src) {
// In the original these are far pointers patched after load; read as
// raw offsets and store temporarily - load_conv resolves them.
- uint32 text_off, scripts_off, nodes_off, dialogs_off, messages_off, text_lines_off;
- src->readMultipleLE(text_off, scripts_off, nodes_off, dialogs_off, messages_off, text_lines_off);
- text_ptr = (void *)(uintptr_t)text_off;
- scripts_ptr = (void *)(uintptr_t)scripts_off;
- nodes_ptr = (void *)(uintptr_t)nodes_off;
- dialogs_ptr = (void *)(uintptr_t)dialogs_off;
- messages_ptr = (void *)(uintptr_t)messages_off;
- text_lines_ptr = (void *)(uintptr_t)text_lines_off;
+ src->readMultipleLE(textOffset, scriptsOffset, nodesOffset,
+ dialogsOffset, messagesOffset, textLinesOffset);
}
void ConvNode::load(Common::SeekableReadStream *src) {
@@ -96,7 +89,7 @@ void ConvVariable::load(Common::SeekableReadStream *src) {
src->readMultipleLE(isPtr, val, unused);
}
-void ConvData::load(Common::SeekableReadStream *src) {
+void ConvDataHeader::load(Common::SeekableReadStream *src) {
src->readMultipleLE(currentNode, entryFlagsCount, variablesCount,
importsCount, numImports, array1_size,
messageList1_size, messageList2_size, messageList3_size, messageList4_size);
@@ -130,7 +123,7 @@ static Common::SeekableReadStream *conv_open(int convNum) {
static Conv *load_conv(const char *fname) {
Load file;
- Conv convHeader;
+ ConvHeader convHeader;
Conv *dataPtr = nullptr;
Conv *result = nullptr;
char filename[80];
@@ -153,98 +146,129 @@ static Conv *load_conv(const char *fname) {
{
// Read the fixed-size Conv header through a MemoryReadStream so that
// the load() function handles field sizes and endianness correctly.
- byte hdrBuf[Conv::SIZE];
- if (!loader_read(hdrBuf, Conv::SIZE, 1, &file)) {
+ byte hdrBuf[ConvHeader::SIZE];
+ if (!loader_read(hdrBuf, ConvHeader::SIZE, 1, &file)) {
conv_error_code = 2;
goto done;
}
- Common::MemoryReadStream hdrStream(hdrBuf, Conv::SIZE);
+ Common::MemoryReadStream hdrStream(hdrBuf, ConvHeader::SIZE);
convHeader.load(&hdrStream);
}
- {
- // Calculate total allocation size. The +15 on node_count matches the
- // original: the DOS allocator rounded up to paragraph (16-byte) boundaries
- // for the nodes sub-array so that far-pointer normalisation never overflows.
- long nodeBytes = (long)(convHeader.node_count + 15) * ConvNode::SIZE;
- long dialogBytes = (long)convHeader.dialog_count * ConvDialog::SIZE;
- long messageBytes = (long)convHeader.message_count * 4; // 2 x int16 per entry
- long textLineBytes = (long)convHeader.text_line_count * 2; // 1 x int16 per entry
- long total = Conv::SIZE + nodeBytes + dialogBytes + messageBytes
- + textLineBytes + (long)convHeader.text_length
- + (long)convHeader.commands_length;
-
- dataPtr = (Conv *)mem_get_name(total, name_buf);
- if (!dataPtr) {
- conv_error_code = 3;
- goto done;
- }
- // Copy the loaded header to the front of the block, then fix up all
- // sub-array pointers to point into the memory immediately following.
- *dataPtr = convHeader;
- byte *p = (byte *)dataPtr + Conv::SIZE;
-
- dataPtr->nodes_ptr = p; p += nodeBytes;
- dataPtr->dialogs_ptr = p; p += dialogBytes;
- dataPtr->messages_ptr = p; p += messageBytes;
- dataPtr->text_lines_ptr = p; p += textLineBytes;
- dataPtr->text_ptr = p; p += convHeader.text_length;
- dataPtr->scripts_ptr = p;
-
- // Read each section from the file. Error codes deliberately match the
- // originals (note: 6 is skipped, matching the disassembly).
- if (!loader_read(dataPtr->nodes_ptr,
- (long)convHeader.node_count * ConvNode::SIZE, 1, &file)) {
+ dataPtr = new Conv();
+ if (!dataPtr) {
+ conv_error_code = 3;
+ goto done;
+ }
+
+ // Copy the loaded header to the front of the block
+ *dataPtr = convHeader;
+
+ // Read each section from the file. Error codes deliberately match the
+ // originals (note: 6 is skipped, matching the disassembly).
+
+ // Nodes
+ {
+ byte *buffer = (byte *)malloc(dataPtr->node_count * ConvNode::SIZE);
+ if (!loader_read(buffer, convHeader.node_count * ConvNode::SIZE, 1, &file)) {
conv_error_code = 4;
+ free(buffer);
goto done;
}
- if (!loader_read(dataPtr->dialogs_ptr,
- (long)convHeader.dialog_count * ConvDialog::SIZE, 1, &file)) {
+ Common::MemoryReadStream src(buffer, convHeader.node_count * ConvNode::SIZE);
+ dataPtr->nodes.resize(convHeader.node_count);
+ for (int i = 0; i < convHeader.node_count; ++i)
+ dataPtr->nodes[i].load(&src);
+
+ free(buffer);
+ }
+
+ // Dialogs
+ {
+ byte *buffer = (byte *)malloc(dataPtr->dialog_count * ConvDialog::SIZE);
+ if (!loader_read(buffer, convHeader.dialog_count * ConvDialog::SIZE, 1, &file)) {
conv_error_code = 5;
+ free(buffer);
goto done;
}
- if (!loader_read(dataPtr->messages_ptr,
- (long)convHeader.message_count * 4, 1, &file)) {
+ Common::MemoryReadStream src(buffer, convHeader.dialog_count * ConvNode::SIZE);
+ dataPtr->dialogs.resize(convHeader.dialog_count);
+ for (int i = 0; i < convHeader.dialog_count; ++i)
+ dataPtr->dialogs[i].load(&src);
+
+ free(buffer);
+ }
+
+ // Messages
+ {
+ byte *buffer = (byte *)malloc(dataPtr->message_count * 4);
+ if (!loader_read(buffer, convHeader.message_count * 4, 1, &file)) {
conv_error_code = 7;
+ free(buffer);
goto done;
}
- if (!loader_read(dataPtr->text_lines_ptr,
- (long)convHeader.text_line_count * 2, 1, &file)) {
+ Common::MemoryReadStream src(buffer, convHeader.message_count * 4);
+ dataPtr->dialogs.resize(convHeader.message_count);
+ for (int i = 0; i < convHeader.message_count; ++i)
+ dataPtr->messages[i] = src.readSint32LE();
+
+ free(buffer);
+ }
+
+ // Text lines
+ {
+ byte *buffer = (byte *)malloc(dataPtr->text_line_count * 2);
+ if (!loader_read(buffer, convHeader.text_line_count * 2, 1, &file)) {
conv_error_code = 8;
+ free(buffer);
goto done;
}
- if (!loader_read(dataPtr->text_ptr, convHeader.text_length, 1, &file)) {
+ Common::MemoryReadStream src(buffer, convHeader.text_line_count * 2);
+ dataPtr->dialogs.resize(convHeader.text_line_count * 2);
+ for (int i = 0; i < convHeader.message_count; ++i)
+ dataPtr->messages[i] = src.readSint16LE();
+
+ free(buffer);
+ }
+
+ // Text block
+ {
+ dataPtr->text.resize(convHeader.text_length);
+ if (!loader_read(&dataPtr->text[0], convHeader.text_length, 1, &file)) {
conv_error_code = 9;
goto done;
}
+ }
- if (!loader_read(dataPtr->scripts_ptr, convHeader.commands_length, 1, &file)) {
+ // Scripts
+ {
+ if (!loader_read(&dataPtr->scripts[0], convHeader.commands_length, 1, &file)) {
conv_error_code = 10;
goto done;
}
-
- result = dataPtr;
}
+ result = dataPtr;
+
done:
if (file.open)
loader_close(&file);
// Free the block if we bailed out before completing the load
if (dataPtr && dataPtr != result)
- mem_free(dataPtr);
+ delete dataPtr;
return result;
}
static ConvData *load_conv_data(const char *fname) {
Load file;
- ConvData cndHeader;
+ ConvDataHeader header;
ConvData *dataPtr = nullptr;
ConvData *result = nullptr;
char filename[80];
@@ -262,79 +286,83 @@ static ConvData *load_conv_data(const char *fname) {
goto done;
{
- byte hdrBuf[ConvData::SIZE];
- if (!loader_read(hdrBuf, ConvData::SIZE, 1, &file))
+ byte hdrBuf[ConvDataHeader::SIZE];
+ if (!loader_read(hdrBuf, ConvDataHeader::SIZE, 1, &file))
goto done;
- Common::MemoryReadStream hdrStream(hdrBuf, ConvData::SIZE);
- cndHeader.load(&hdrStream);
+ Common::MemoryReadStream hdrStream(hdrBuf, ConvDataHeader::SIZE);
+ header.load(&hdrStream);
}
- {
- // Total allocation = ConvData header + imports array + entry flags array
- // + variables array. The +21 on variablesCount is paragraph-alignment
- // padding; 21 * 3 * 2 = 126 = ConvData::SIZE, so the header cost is
- // already baked into the formula without a separate +ConvData::SIZE term.
- long total = ((long)(cndHeader.variablesCount + 21) * 3
- + cndHeader.importsCount + cndHeader.entryFlagsCount) * 2;
-
- dataPtr = (ConvData *)mem_get_name(total, name_buf);
- if (!dataPtr)
- goto done;
+ dataPtr = new ConvData();
+ if (!dataPtr)
+ goto done;
- *dataPtr = cndHeader;
+ *dataPtr = header;
- // Sub-array byte offsets from the start of the block.
- // 63 = ConvData::SIZE / 2; using it as a word-count base yields the
- // correct byte offset arithmetic when multiplied by 2.
- dataPtr->importsOffset = ConvData::SIZE;
- dataPtr->entryFlagsOffset = (int16)((cndHeader.importsCount + 63) * 2);
- dataPtr->variablesOffset = (int16)((cndHeader.entryFlagsCount
- + cndHeader.importsCount + 63) * 2);
+ // Imports: conditional â the original skips the loader_read when count <= 0
+ if (header.importsCount > 0) {
+ int16 *buffer = (int16 *)malloc(header.importsCount * 2);
+ if (!loader_read(buffer, (long)header.importsCount * 2, 1, &file)) {
+ free(buffer);
+ goto done;
+ }
- byte *block = (byte *)dataPtr;
+ dataPtr->imports.resize(header.importsCount);
+ for (int i = 0; i < header.importsCount; ++i)
+ dataPtr->imports[i] = FROM_LE_16(buffer[i]);
+ free(buffer);
+ }
- // Imports: conditional â the original skips the loader_read when count <= 0
- if (cndHeader.importsCount > 0) {
- if (!loader_read(block + dataPtr->importsOffset,
- (long)cndHeader.importsCount * 2, 1, &file))
- goto done;
+ // Entry flags: always read (no count guard in the original)
+ {
+ int16 *buffer = (int16 *)malloc(header.entryFlagsCount * 2);
+ if (!loader_read(buffer, (long)header.entryFlagsCount * 2, 1, &file)) {
+ free(buffer);
+ goto done;
}
- // Entry flags: always read (no count guard in the original)
- if (!loader_read(block + dataPtr->entryFlagsOffset,
- (long)cndHeader.entryFlagsCount * 2, 1, &file))
- goto done;
+ dataPtr->entryFlags.resize(header.entryFlagsCount);
+ for (int i = 0; i < header.entryFlagsCount; ++i)
+ dataPtr->entryFlags[i] = FROM_LE_16(buffer[i]);
+ free(buffer);
+ }
- // Variables
- if (!loader_read(block + dataPtr->variablesOffset,
- (long)cndHeader.variablesCount * ConvVariable::SIZE, 1, &file))
+ // Variables
+ {
+ byte *buffer = (byte *)malloc(header.variablesCount * ConvVariable::SIZE);
+ if (!loader_read(buffer, (long)header.variablesCount * ConvVariable::SIZE, 1, &file)) {
+ free(buffer);
goto done;
-
- // Zero the runtime isPtr flag for every variable; it is not meaningful
- // as stored on disk
- if (cndHeader.variablesCount > 0) {
- ConvVariable *vars = (ConvVariable *)(block + dataPtr->variablesOffset);
- for (int i = 0; i < cndHeader.variablesCount; ++i)
- vars[i].isPtr = 0;
}
- result = dataPtr;
+ Common::MemoryReadStream src(buffer, header.variablesCount * ConvVariable::SIZE);
+ dataPtr->variables.resize(header.entryFlagsCount);
+ for (int i = 0; i < header.entryFlagsCount; ++i) {
+ dataPtr->variables[i].load(&src);
+
+ // Zero the runtime isPtr flag for every variable; it is not meaningful
+ // as stored on disk
+ dataPtr->variables[i].isPtr = false;
+ }
+ free(buffer);
}
+ result = dataPtr;
+
done:
if (file.open)
loader_close(&file);
if (dataPtr && dataPtr != result)
- mem_free(dataPtr);
+ delete dataPtr;
return result;
}
static ConvData *conv_read_data(Common::SeekableReadStream *src) {
- byte buffer[ConvData::SIZE];
- if (src->read(buffer, ConvData::SIZE) != ConvData::SIZE)
+ byte buffer[ConvDataHeader::SIZE];
+ if (src->read(buffer, ConvDataHeader::SIZE) != ConvDataHeader::SIZE)
error("Reading ConvData header");
// TODO
@@ -344,12 +372,12 @@ static ConvData *conv_read_data(Common::SeekableReadStream *src) {
static void conv_init(ConvData *convData, int val) {
conv_start(convData, nullptr);
- for (int i = 0; i < convData->entryFlagsCount; ++i) {
- uint16 *flag = (uint16 *)((byte *)convData + convData->entryFlagsOffset);
- *flag &= 0x3fff;
+ for (uint i = 0; i < convData->entryFlags.size(); ++i) {
+ uint16 &flag = convData->entryFlags[i];
+ flag &= 0x3fff;
- if ((*flag & 1) || ((*flag & 4) && val))
- *flag |= 0x8000;
+ if ((flag & 1) || ((flag & 4) && val))
+ flag |= 0x8000;
}
}
@@ -410,9 +438,9 @@ void conv_start(ConvData *convData, Conv *convIn) {
byte *block = (byte *)convData;
// Resolve the byte-offset sub-array pointers stored in the ConvData block
- conv_imports = (int16 *)(block + convData->importsOffset);
- conv_entry_flags = (int16 *)(block + convData->entryFlagsOffset);
- conv_varsDataPtr = (ConvVariable *)(block + convData->variablesOffset);
+ conv_imports = &convData->imports[0];
+ conv_entry_flags = &convData->entryFlags[0];
+ conv_varsDataPtr = &convData->variables[0];
// conv_vars0ValPtr -> variables[0].val (skips the isPtr field)
conv_vars0ValPtr = &conv_varsDataPtr[0].val;
diff --git a/engines/mads/madsv2/core/conv.h b/engines/mads/madsv2/core/conv.h
index 383aa8b97f6..5421d7f1e84 100644
--- a/engines/mads/madsv2/core/conv.h
+++ b/engines/mads/madsv2/core/conv.h
@@ -22,6 +22,7 @@
#ifndef MADS_CORE_CONV_H
#define MADS_CORE_CONV_H
+#include "common/array.h"
#include "common/stream.h"
namespace MADS {
@@ -39,31 +40,6 @@ enum ConvStatus {
CONV_STATUS_REPLY = 4
};
-struct Conv {
- int16 node_count;
- int16 dialog_count;
- int16 message_count;
- int16 text_line_count;
- int16 num_variables;
-
- int16 max_imports;
- int16 speaker_count;
- char speaker_portraits[5][16];
- int16 speaker_frame[5];
- char speech_file[14];
- uint32 text_length;
-
- uint32 commands_length;
- void *text_ptr;
- void *scripts_ptr;
- void *nodes_ptr;
- void *dialogs_ptr;
- void *messages_ptr;
- void *text_lines_ptr;
-
- static constexpr int SIZE = 2 * 7 + 16 * 5 + 2 * 5 + 14 + 4 + 4 + 4 * 6;
- void load(Common::SeekableReadStream *src);
-};
struct ConvNode {
int16 index;
@@ -106,7 +82,57 @@ struct ConvVariable {
void load(Common::SeekableReadStream *src);
};
-struct ConvData {
+struct ConvBase {
+ int16 node_count;
+ int16 dialog_count;
+ int16 message_count;
+ int16 text_line_count;
+ int16 num_variables;
+
+ int16 max_imports;
+ int16 speaker_count;
+ char speaker_portraits[5][16];
+ int16 speaker_frame[5];
+ char speech_file[14];
+ uint32 text_length;
+
+ uint32 commands_length;
+
+ static constexpr int SIZE = 2 * 7 + 16 * 5 + 2 * 5 + 14 + 4 + 4 + 4 * 6;
+};
+
+struct ConvHeader : public ConvBase {
+ int textOffset;
+ int scriptsOffset;
+ int nodesOffset;
+ int dialogsOffset;
+ int messagesOffset;
+ int textLinesOffset;
+
+ void load(Common::SeekableReadStream *src);
+};
+
+struct Conv : public ConvBase {
+ Conv &operator=(const ConvBase &src) {
+ *((ConvBase *)this) = src;
+ text.clear();
+ scripts.clear();
+ nodes.clear();
+ dialogs.clear();
+ messages.clear();
+ textLines.clear();
+ return *this;
+ }
+
+ Common::Array<ConvNode> nodes;
+ Common::Array<ConvDialog> dialogs;
+ Common::Array<int32> messages;
+ Common::Array<uint16> text;
+ Common::Array<uint16> scripts;
+ Common::Array<uint16> textLines;
+};
+
+struct ConvDataBase {
int16 currentNode;
int16 entryFlagsCount;
int16 variablesCount;
@@ -122,6 +148,9 @@ struct ConvData {
int16 messageList2[10];
int16 messageList3[10];
int16 messageList4[10];
+};
+
+struct ConvDataHeader : public ConvDataBase {
int16 importsOffset;
int16 entryFlagsOffset;
int16 variablesOffset;
@@ -134,6 +163,20 @@ struct ConvData {
void load(Common::SeekableReadStream *src);
};
+struct ConvData : public ConvDataBase {
+ ConvData &operator=(const ConvDataBase &src) {
+ *((ConvDataBase *)this) = src;
+ imports.clear();
+ entryFlags.clear();
+ variables.clear();
+ return *this;
+ }
+
+ Common::Array<int16> imports;
+ Common::Array<uint16> entryFlags;
+ Common::Array<ConvVariable> variables;
+};
+
struct ConvControl {
int16 running;
int16 index;
@@ -167,7 +210,7 @@ extern Conv *active_conv;
extern ConvData *active_conv_data;
extern int16 *conv_imports;
-extern int16 *conv_entry_flags;
+extern uint16 *conv_entry_flags;
extern ConvVariable *conv_varsDataPtr;
extern int16 *conv_vars0ValPtr;
Commit: 93381d50d94857ebd7b527d1f0417540aba959fc
https://github.com/scummvm/scummvm/commit/93381d50d94857ebd7b527d1f0417540aba959fc
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:09+10:00
Commit Message:
MADS: PHANTOM: Adding more conv functions
Changed paths:
engines/mads/madsv2/core/conv.cpp
engines/mads/madsv2/core/conv.h
diff --git a/engines/mads/madsv2/core/conv.cpp b/engines/mads/madsv2/core/conv.cpp
index d11f29260c3..801e3b484a0 100644
--- a/engines/mads/madsv2/core/conv.cpp
+++ b/engines/mads/madsv2/core/conv.cpp
@@ -25,6 +25,7 @@
#include "mads/madsv2/core/conv.h"
#include "mads/madsv2/core/general.h"
#include "mads/madsv2/core/env.h"
+#include "mads/madsv2/core/error.h"
#include "mads/madsv2/core/fileio.h"
#include "mads/madsv2/core/game.h"
#include "mads/madsv2/core/inter.h"
@@ -32,6 +33,7 @@
#include "mads/madsv2/core/matte.h"
#include "mads/madsv2/core/mem.h"
#include "mads/madsv2/core/popup.h"
+#include "mads/madsv2/core/speech.h"
namespace MADS {
namespace MADSV2 {
@@ -47,7 +49,7 @@ int16 *conv_vars0ValPtr;
int conv_restore_running;
ConvControl conv_control;
Box conv_box;
-int *conv_my_next_start;
+int16 *conv_my_next_start;
int conv_error_code;
static int conv_indexes[CONV_MAX_SLOTS];
@@ -64,8 +66,7 @@ void ConvHeader::load(Common::SeekableReadStream *src) {
src->read(speech_file, 14);
src->readMultipleLE(text_length, commands_length);
- // In the original these are far pointers patched after load; read as
- // raw offsets and store temporarily - load_conv resolves them.
+ // Read in the offsets
src->readMultipleLE(textOffset, scriptsOffset, nodesOffset,
dialogsOffset, messagesOffset, textLinesOffset);
}
@@ -92,11 +93,11 @@ void ConvVariable::load(Common::SeekableReadStream *src) {
void ConvDataHeader::load(Common::SeekableReadStream *src) {
src->readMultipleLE(currentNode, entryFlagsCount, variablesCount,
importsCount, numImports, array1_size,
- messageList1_size, messageList2_size, messageList3_size, messageList4_size);
+ messageList1_size, messageList2_size, speechListSize, messageList4_size);
src->readMultipleLE(array1);
src->readMultipleLE(messageList1);
src->readMultipleLE(messageList2);
- src->readMultipleLE(messageList3);
+ src->readMultipleLE(speechList);
src->readMultipleLE(messageList4);
src->readMultipleLE(importsOffset, entryFlagsOffset, variablesOffset);
}
@@ -194,7 +195,7 @@ static Conv *load_conv(const char *fname) {
goto done;
}
- Common::MemoryReadStream src(buffer, convHeader.dialog_count * ConvNode::SIZE);
+ Common::MemoryReadStream src(buffer, convHeader.dialog_count * ConvDialog::SIZE);
dataPtr->dialogs.resize(convHeader.dialog_count);
for (int i = 0; i < convHeader.dialog_count; ++i)
dataPtr->dialogs[i].load(&src);
@@ -212,7 +213,7 @@ static Conv *load_conv(const char *fname) {
}
Common::MemoryReadStream src(buffer, convHeader.message_count * 4);
- dataPtr->dialogs.resize(convHeader.message_count);
+ dataPtr->messages.resize(convHeader.message_count);
for (int i = 0; i < convHeader.message_count; ++i)
dataPtr->messages[i] = src.readSint32LE();
@@ -229,9 +230,9 @@ static Conv *load_conv(const char *fname) {
}
Common::MemoryReadStream src(buffer, convHeader.text_line_count * 2);
- dataPtr->dialogs.resize(convHeader.text_line_count * 2);
- for (int i = 0; i < convHeader.message_count; ++i)
- dataPtr->messages[i] = src.readSint16LE();
+ dataPtr->textLines.resize(convHeader.text_line_count);
+ for (int i = 0; i < convHeader.text_line_count; ++i)
+ dataPtr->textLines[i] = src.readUint16LE();
free(buffer);
}
@@ -247,6 +248,7 @@ static Conv *load_conv(const char *fname) {
// Scripts
{
+ dataPtr->scripts.resize(convHeader.commands_length);
if (!loader_read(&dataPtr->scripts[0], convHeader.commands_length, 1, &file)) {
conv_error_code = 10;
goto done;
@@ -360,13 +362,47 @@ done:
return result;
}
-static ConvData *conv_read_data(Common::SeekableReadStream *src) {
- byte buffer[ConvDataHeader::SIZE];
- if (src->read(buffer, ConvDataHeader::SIZE) != ConvDataHeader::SIZE)
- error("Reading ConvData header");
+static ConvData *read_conv_data(Common::SeekableReadStream *src) {
+ ConvDataHeader header;
+ ConvData *dataPtr = nullptr;
+ ConvData *result = nullptr;
- // TODO
- error("TODO: conv_read_data");
+ // Load the header
+ header.load(src);
+
+ dataPtr = new ConvData();
+ if (!dataPtr)
+ goto done;
+
+ *dataPtr = header;
+
+ // Imports: conditional â the original skips the loader_read when count <= 0
+ if (header.importsCount > 0) {
+ dataPtr->imports.resize(header.importsCount);
+ for (int i = 0; i < header.importsCount; ++i)
+ dataPtr->imports[i] = src->readSint16LE();
+ }
+
+ if (header.entryFlagsCount > 0) {
+ dataPtr->entryFlags.resize(header.entryFlagsCount);
+ for (int i = 0; i < header.entryFlagsCount; ++i)
+ dataPtr->entryFlags[i] = src->readUint16LE();
+ }
+
+ if (header.variablesCount > 0) {
+ dataPtr->variables.resize(header.entryFlagsCount);
+ for (int i = 0; i < header.entryFlagsCount; ++i) {
+ dataPtr->variables[i].load(src);
+ }
+ }
+
+ result = dataPtr;
+
+done:
+ if (dataPtr && dataPtr != result)
+ delete dataPtr;
+
+ return result;
}
static void conv_init(ConvData *convData, int val) {
@@ -388,7 +424,7 @@ static ConvData *conv_get_data(int convNum) {
if (conv_indexes[convNum]) {
Common::SeekableReadStream *handle = conv_open(convNum);
if (handle) {
- convData = conv_read_data(handle);
+ convData = read_conv_data(handle);
delete handle;
}
} else {
@@ -415,6 +451,15 @@ static void conv_purge_any_popup() {
}
}
+static void conv_set_variable(int idx, int16 v1, int16 *valPtr) {
+ // TODO
+}
+
+static int conv_next_node() {
+ active_conv_data->currentNode = *conv_vars0ValPtr;
+ return active_conv->nodes[active_conv_data->currentNode].active;
+}
+
void conv_system_init() {
Common::fill((byte *)&conv_control, (byte *)&conv_control + sizeof(ConvControl), 0);
conv_control.running = -1;
@@ -435,8 +480,6 @@ void conv_start(ConvData *convData, Conv *convIn) {
active_conv = convIn;
active_conv_data = convData;
- byte *block = (byte *)convData;
-
// Resolve the byte-offset sub-array pointers stored in the ConvData block
conv_imports = &convData->imports[0];
conv_entry_flags = &convData->entryFlags[0];
@@ -447,7 +490,7 @@ void conv_start(ConvData *convData, Conv *convIn) {
// conv_my_next_start -> variables[1].val
// (offset = offsetof(ConvVariable, val) + sizeof(ConvVariable) from base)
- conv_my_next_start = (int *)&conv_varsDataPtr[1].val;
+ conv_my_next_start = (int16 *)&conv_varsDataPtr[1].val;
convData->currentNode = -1;
convData->numImports = 0;
@@ -457,22 +500,199 @@ void conv_start(ConvData *convData, Conv *convIn) {
}
void conv_get(int convNum) {
- int free_slot = -1;
char fname[40];
+ int free_slot = -1;
+ int error_occurred = -1; // matches original si: -1 = error, 0 = success
+ int stage_error = 0; // which stage failed (1/2/3); used as data2 in error_report
- for (int i = 0; i < CONV_MAX_DATA && free_slot == -1; ++i) {
- if (!conv_slots[i])
+ // Find first free slot (stops as soon as one is found, matching original loop)
+ for (int i = 0; i < CONV_MAX_DATA; ++i) {
+ if (!conv_slots[i]) {
free_slot = i;
+ break;
+ }
+ }
+
+ if (free_slot < 0) {
+ stage_error = 1;
+ goto report;
+ }
+
+ conv_slots[free_slot] = 0xFF;
+
+ conv[free_slot] = load_conv(conv_get_filename(convNum, 0, fname));
+ if (!conv[free_slot]) {
+ stage_error = 2;
+ goto report;
+ }
+
+ conv_data[free_slot] = conv_get_data(convNum);
+ if (!conv_data[free_slot]) {
+ stage_error = 3;
+ goto report;
+ }
+
+ // Encode slot as (free_slot + 2) so that 0 means "not loaded"
+ conv_indexes[convNum] = free_slot + 2;
+ error_occurred = 0;
+
+report:
+ if (error_occurred)
+ error_report(ERROR_CONV_GET, ERROR, MODULE_CONV, convNum, stage_error);
+}
+
+void conv_run(int convId) {
+ char name[80];
+ int idx;
+
+ // Validate convId is loaded (non-fatal: report error but continue, matching original)
+ if (conv_indexes[convId] < 2)
+ error_report(ERROR_CONV_RUN, ERROR, MODULE_CONV, convId, 0);
+
+ // Stop any conversation already in progress
+ if (conv_control.running >= 0)
+ conv_abort();
+
+ conv_control.running = convId;
+ conv_control.index = conv_indexes[convId] - 2;
+ conv_control.status = CONV_STATUS_NEXT_NODE;
+ conv_control.mask = 0x7FFF;
+ conv_control.popup_clock = kernel.clock;
+ conv_control.entry = -1;
+ conv_control.commands_allowed = player.commands_allowed;
+ conv_control.input_mode = inter_input_mode;
+ conv_control.popup_is_up = 0;
+ conv_control.me_trigger = 0;
+ conv_control.you_trigger = 0;
+
+ // Initialise per-speaker slots.
+ // speaker_val and person_speaking are written inside the loop in the original
+ // (compiler artefact from an unrolled version); preserved here for fidelity.
+ for (idx = 0; idx < CONV_MAX_DATA; ++idx) {
+ conv_control.speaker_active[idx] = 0;
+ conv_control.speaker_series[idx] = -1;
+ conv_control.speaker_frame[idx] = 1;
+ conv_control.x[idx] = (int16)0x8000;
+ conv_control.y[idx] = (int16)0x8000;
+ conv_control.width[idx] = 30;
+ conv_control.speaker_val = 1;
+ conv_control.person_speaking = 1;
}
- if (free_slot >= 0) {
- conv_slots[free_slot] = -1;
- (void)load_conv(conv_get_filename(convNum, 0, fname));
- // TODO: More stuff
+ int slot = conv_control.index;
+ conv_start(conv_data[slot], conv[slot]);
+
+ // Bind conv variables 2â22 to live ConvControl fields.
+ // Variable 2 maps to speaker_val (not contiguous with the arrays below).
+ // Variables 3â22 map to speaker_frame[5], x[5], y[5], width[5] â 20
+ // consecutive int16s â so a single pointer walk replaces 20 separate calls.
+ conv_set_variable(2, -1, &conv_control.speaker_val);
+ int16 *p = conv_control.speaker_frame;
+ for (int i = 3; i <= 22; ++i, ++p)
+ conv_set_variable(i, -1, p);
+
+ // Load speaker portrait series for each declared speaker
+ for (idx = 0; idx < conv[slot]->speaker_count; ++idx) {
+ Common::strcpy_s(name, conv[slot]->speaker_portraits[idx]);
+ int series = kernel_load_series(name, 0x4000);
+ conv_control.speaker_series[idx] = series;
+ if (series > 0) {
+ conv_control.speaker_active[idx] = -1;
+ conv_control.speaker_frame[idx] = conv[slot]->speaker_frame[idx];
+ }
}
+
+ if (kernel_mode == KERNEL_ACTIVE_CODE)
+ kernel_new_palette();
+
+ player.commands_allowed = 0;
+}
+
+// ---------------------------------------------------------------------------
+// conv_string
+//
+// Returns a pointer to the null-terminated text string whose index within the
+// flat text buffer is stored in conv->textLines[textIdx]. The text blob is
+// held in conv->text (stored as uint16 units but treated as a byte stream);
+// textLines values are byte offsets into that blob.
+// ---------------------------------------------------------------------------
+static const char *conv_string(int textIdx, Conv *convIn) {
+ uint16 byteOffset = convIn->textLines[textIdx];
+ return reinterpret_cast<const char *>(convIn->text.begin()) + byteOffset;
}
-void conv_run(int convNum) {
+// ---------------------------------------------------------------------------
+// string_trim
+//
+// Strips trailing whitespace (any byte value <= ' ') from a mutable C string
+// in-place. Mirrors the original DOS helper of the same name.
+// ---------------------------------------------------------------------------
+static void string_trim(char *str) {
+ if (!str) return;
+ size_t len = strlen(str);
+ while (len > 0 && (unsigned char)str[len - 1] <= ' ')
+ str[--len] = '\0';
+}
+
+// ---------------------------------------------------------------------------
+// conv_generate_text
+//
+// Builds and displays a conversation-line popup for the current speaker, then
+// triggers the associated speech audio (if the speech system is active and at
+// least one speech index was supplied).
+//
+// Parameters
+// speechList â array of speech-audio indices; speechList[0] is played
+// convData â active ConvData (unused here; callers already route through
+// conv_control)
+// convIn â active Conv (provides the text pool and speech filename)
+// textIdx â index into convIn->textLines that selects the dialog string
+// speechCount â number of valid entries in speechList (0 = no speech)
+// ---------------------------------------------------------------------------
+static void conv_generate_text(int16 *speechList, ConvData * /*convData*/,
+ Conv *convIn, int textIdx, int speechCount) {
+ int person = conv_control.person_speaking;
+ char textBuf[512];
+ Box *savedBox;
+
+ // Redirect popup operations to the conversation-private box so that the
+ // bounds recorded by popup_draw can be used later by conv_purge_any_popup.
+ savedBox = box;
+ box = &conv_box;
+
+ // Size and position the popup from the current speaker's slot data.
+ int horiz_pieces = popup_estimate_pieces(conv_control.width[person]);
+ popup_create(horiz_pieces,
+ conv_control.x[person],
+ conv_control.y[person]);
+
+ // Attach the speaker portrait icon if a series was loaded for this slot.
+ // The icon_id is the 1-based frame stored in speaker_frame.
+ // center=0: left-aligned within the popup box.
+ if (conv_control.speaker_series[person] >= 0) {
+ popup_add_icon(series_list[conv_control.speaker_series[person]],
+ conv_control.speaker_frame[person],
+ 0);
+ }
+
+ // Copy the dialog string to a local mutable buffer, strip trailing
+ // whitespace (the raw text pool can have padding bytes), then write it.
+ Common::strlcpy(textBuf, conv_string(textIdx, convIn), sizeof(textBuf));
+ string_trim(textBuf);
+ popup_write_string(textBuf);
+
+ // Render the popup, saving the underlying screen region.
+ popup_draw(true, false);
+
+ // Restore the caller's box and record that a conversation popup is live.
+ box = savedBox;
+ conv_control.popup_is_up = -1;
+ conv_control.popup_clock = kernel.clock;
+
+ // Play the associated speech audio when the speech system is on.
+ if (speech_system_active && speech_on && speechCount > 0) {
+ speech_ems_play(convIn->speech_file, speechList[0]);
+ }
}
void conv_update(bool) {
diff --git a/engines/mads/madsv2/core/conv.h b/engines/mads/madsv2/core/conv.h
index 5421d7f1e84..909c651d5a1 100644
--- a/engines/mads/madsv2/core/conv.h
+++ b/engines/mads/madsv2/core/conv.h
@@ -141,12 +141,12 @@ struct ConvDataBase {
int16 array1_size;
int16 messageList1_size;
int16 messageList2_size;
- int16 messageList3_size;
+ int16 speechListSize;
int16 messageList4_size;
int16 array1[10];
int16 messageList1[10];
int16 messageList2[10];
- int16 messageList3[10];
+ int16 speechList[10];
int16 messageList4[10];
};
@@ -222,6 +222,7 @@ extern void conv_system_init();
extern void conv_system_cleanup();
extern void conv_start(ConvData *convData, Conv *convIn);
+extern void conv_stop();
extern void conv_get(int convNum);
extern void conv_run(int convNum);
extern void conv_update(bool);
Commit: ef604c7179b00766f4f06a282cadc8bb1e60a7bc
https://github.com/scummvm/scummvm/commit/ef604c7179b00766f4f06a282cadc8bb1e60a7bc
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:09+10:00
Commit Message:
MADS: PHANTOM: In progress conv script processing
Changed paths:
engines/mads/madsv2/core/conv.cpp
engines/mads/madsv2/core/conv.h
engines/mads/madsv2/phantom/rooms/room103.cpp
engines/mads/madsv2/phantom/rooms/room203.cpp
diff --git a/engines/mads/madsv2/core/conv.cpp b/engines/mads/madsv2/core/conv.cpp
index 801e3b484a0..d1971455742 100644
--- a/engines/mads/madsv2/core/conv.cpp
+++ b/engines/mads/madsv2/core/conv.cpp
@@ -33,6 +33,7 @@
#include "mads/madsv2/core/matte.h"
#include "mads/madsv2/core/mem.h"
#include "mads/madsv2/core/popup.h"
+#include "mads/madsv2/core/imath.h"
#include "mads/madsv2/core/speech.h"
namespace MADS {
@@ -51,11 +52,16 @@ ConvControl conv_control;
Box conv_box;
int16 *conv_my_next_start;
int conv_error_code;
+int conv_dlg_script_ptr, conv_dlg_script_end;
static int conv_indexes[CONV_MAX_SLOTS];
static int conv_slots[CONV_MAX_DATA];
+// ====================================================================
+// Struct serialization methods
+// ====================================================================
+
void ConvHeader::load(Common::SeekableReadStream *src) {
src->readMultipleLE(node_count, dialog_count, message_count, text_line_count,
num_variables, max_imports, speaker_count);
@@ -80,21 +86,24 @@ void ConvDialog::load(Common::SeekableReadStream *src) {
}
void ConvScriptParams::load(Common::SeekableReadStream *src) {
- operation = src->readSint16LE();
+ operation = (ConvOp)src->readSint16LE();
param1IsVar = src->readByte();
param2IsVar = src->readByte();
src->readMultipleLE(param1, param2);
}
void ConvVariable::load(Common::SeekableReadStream *src) {
- src->readMultipleLE(isPtr, val, unused);
+ (void)src->readUint16LE(); // isPtr
+ isPtr = false;
+ val = src->readSint16LE();
+ (void)src->readUint16LE(); // skip space for pointer segments
}
void ConvDataHeader::load(Common::SeekableReadStream *src) {
src->readMultipleLE(currentNode, entryFlagsCount, variablesCount,
- importsCount, numImports, array1_size,
+ importsCount, numImports, optionListSize,
messageList1_size, messageList2_size, speechListSize, messageList4_size);
- src->readMultipleLE(array1);
+ src->readMultipleLE(optionList);
src->readMultipleLE(messageList1);
src->readMultipleLE(messageList2);
src->readMultipleLE(speechList);
@@ -102,7 +111,10 @@ void ConvDataHeader::load(Common::SeekableReadStream *src) {
src->readMultipleLE(importsOffset, entryFlagsOffset, variablesOffset);
}
-//====================================================================
+
+// ====================================================================
+// Static helpers (ordered so no forward declarations are needed)
+// ====================================================================
static const char *conv_get_filename(int convNum, int extType, char *name) {
*name = '\0';
@@ -122,6 +134,48 @@ static Common::SeekableReadStream *conv_open(int convNum) {
return env_open(conv_get_filename(convNum, 2, name));
}
+// ---------------------------------------------------------------------------
+// string_trim â strips trailing whitespace from a mutable C string in-place.
+// ---------------------------------------------------------------------------
+static void string_trim(char *str) {
+ if (!str) return;
+ size_t len = strlen(str);
+ while (len > 0 && (unsigned char)str[len - 1] <= ' ')
+ str[--len] = '\0';
+}
+
+// ---------------------------------------------------------------------------
+// conv_string â returns a pointer to the null-terminated dialog string
+// identified by textIdx. textLines[textIdx] is a byte offset into the flat
+// text character pool stored in conv->text.
+// ---------------------------------------------------------------------------
+static const char *conv_string(int textIdx, Conv *convIn) {
+ uint16 byteOffset = convIn->textLines[textIdx];
+ return reinterpret_cast<const char *>(convIn->text.begin()) + byteOffset;
+}
+
+// Version to use if the isPtr parameter is true (-1)
+static void conv_set_variable(int idx, int16 *ptr) {
+ if (conv_control.running >= 0) {
+ ConvData &cd = *conv_data[conv_control.index];
+ ConvVariable &var = cd.variables[idx];
+
+ var.isPtr = true;
+ var.ptr = ptr;
+ }
+}
+
+// Version to use if the isPtr parameter is false (0)
+static void conv_set_variable(int idx, int16 val) {
+ if (conv_control.running >= 0) {
+ ConvData &cd = *conv_data[conv_control.index];
+ ConvVariable &var = cd.variables[idx];
+
+ var.isPtr = false;
+ var.val = val;
+ }
+}
+
static Conv *load_conv(const char *fname) {
Load file;
ConvHeader convHeader;
@@ -156,7 +210,6 @@ static Conv *load_conv(const char *fname) {
convHeader.load(&hdrStream);
}
-
dataPtr = new Conv();
if (!dataPtr) {
conv_error_code = 3;
@@ -246,7 +299,7 @@ static Conv *load_conv(const char *fname) {
}
}
- // Scripts
+ // Scripts
{
dataPtr->scripts.resize(convHeader.commands_length);
if (!loader_read(&dataPtr->scripts[0], convHeader.commands_length, 1, &file)) {
@@ -451,8 +504,65 @@ static void conv_purge_any_popup() {
}
}
-static void conv_set_variable(int idx, int16 v1, int16 *valPtr) {
- // TODO
+// ---------------------------------------------------------------------------
+// conv_generate_text
+//
+// Builds and displays a conversation-line popup for the current speaker, then
+// triggers the associated speech audio (if the speech system is active and at
+// least one speech index was supplied).
+//
+// Parameters
+// speechList â array of speech-audio indices; speechList[0] is played
+// convData â active ConvData (unused; callers already route through
+// conv_control)
+// convIn â active Conv (provides the text pool and speech filename)
+// textIdx â index into convIn->textLines that selects the dialog string
+// speechCount â number of valid entries in speechList (0 = no speech)
+// ---------------------------------------------------------------------------
+static void conv_generate_text(int16 *speechList, ConvData * /*convData*/,
+ Conv *convIn, int textIdx, int speechCount) {
+ int person = conv_control.person_speaking;
+ char textBuf[512];
+ Box *savedBox;
+
+ // Redirect popup operations to the conversation-private box so that the
+ // bounds recorded by popup_draw can be used later by conv_purge_any_popup.
+ savedBox = box;
+ box = &conv_box;
+
+ // Size and position the popup from the current speaker's slot data.
+ int horiz_pieces = popup_estimate_pieces(conv_control.width[person]);
+ popup_create(horiz_pieces,
+ conv_control.x[person],
+ conv_control.y[person]);
+
+ // Attach the speaker portrait icon if a series was loaded for this slot.
+ // The icon_id is the 1-based frame stored in speaker_frame.
+ // center=0: left-aligned within the popup box.
+ if (conv_control.speaker_series[person] >= 0) {
+ popup_add_icon(series_list[conv_control.speaker_series[person]],
+ conv_control.speaker_frame[person],
+ 0);
+ }
+
+ // Copy the dialog string to a local mutable buffer, strip trailing
+ // whitespace (the raw text pool can have padding bytes), then write it.
+ Common::strlcpy(textBuf, conv_string(textIdx, convIn), sizeof(textBuf));
+ string_trim(textBuf);
+ popup_write_string(textBuf);
+
+ // Render the popup, saving the underlying screen region.
+ popup_draw(true, false);
+
+ // Restore the caller's box and record that a conversation popup is live.
+ box = savedBox;
+ conv_control.popup_is_up = -1;
+ conv_control.popup_clock = kernel.clock;
+
+ // Play the associated speech audio when the speech system is on.
+ if (speech_system_active && speech_on && speechCount > 0) {
+ speech_ems_play(convIn->speech_file, speechList[0]);
+ }
}
static int conv_next_node() {
@@ -460,6 +570,510 @@ static int conv_next_node() {
return active_conv->nodes[active_conv_data->currentNode].active;
}
+// ---------------------------------------------------------------------------
+// conv_list_options
+//
+// Scans the dialogs belonging to the current conversation node and builds the
+// list of active (visible) options in active_conv_data->optionList[].
+//
+// A dialog entry is "active" when bit 15 of its entryFlags word is set. Up
+// to 10 active entries are recorded; when hasMore is zero the list is capped
+// at 5 (normal single-page display), otherwise the full 10 are collected
+// (extended/scrolled display). The final count of ALL active entries (not
+// just the ones stored) is written to active_conv_data->optionListSize.
+//
+// Parameters
+// hasMore â non-zero when more than one page of options should be collected
+// ---------------------------------------------------------------------------
+static int16 conv_list_options(int16 hasMore) {
+ int16 nodeIndex = *conv_vars0ValPtr;
+ int count = 0;
+ int dialogIter = 0;
+
+ int dialogBase = active_conv->nodes[nodeIndex].index;
+ int dialogCount = active_conv->nodes[nodeIndex].dialog_count;
+
+ while (dialogIter < dialogCount) {
+ int16 dialogIdx = (int16)(dialogBase + dialogIter);
+
+ if (active_conv_data->entryFlags[dialogIdx] & 0x8000) {
+ // Include in optionList only if within the allowed window size
+ if ((count < 5 || hasMore) && count < 10)
+ active_conv_data->optionList[count] = dialogIdx;
+ ++count;
+ }
+ ++dialogIter;
+ }
+
+ active_conv_data->optionListSize = (int16)count;
+ return (int16)count;
+}
+
+static void conv_flag_entry(int action, int index) {
+ uint16 &entry = active_conv_data->entryFlags[index];
+
+ switch (action) {
+ case 1:
+ entry |= 0x4000;
+ entry &= 0x7fff;
+ break;
+
+ case 2:
+ entry &= 0x7fff;
+ break;
+
+ case 3:
+ if (!(entry & 0x4000))
+ entry |= 0x8000;
+
+ default:
+ break;
+ }
+}
+
+static byte conv_get_script_byte() {
+ byte val = active_conv->scripts[conv_dlg_script_ptr];
+ if (conv_dlg_script_ptr <= conv_dlg_script_end)
+ ++conv_dlg_script_ptr;
+
+ return val;
+}
+
+static void conv_get_script_bytes(byte *dest, int count) {
+ while (count-- > 0)
+ *dest++ = conv_get_script_byte();
+}
+
+static int16 conv_get_script_word() {
+ byte buffer[2];
+ conv_get_script_bytes(buffer, 2);
+ return READ_LE_INT16(buffer);
+}
+
+static void conv_param_load(ConvScriptParams *params) {
+ params->operation = (ConvOp)conv_get_script_word();
+
+ if (params->operation == CONV_OP_NONE) {
+ params->param1IsVar = false;
+ params->param1 = 0;
+ } else {
+ params->param1IsVar = conv_get_script_byte();
+ params->param1 = conv_get_script_word();
+ }
+
+ if (params->operation == CONV_OP_VALUE || params->operation == CONV_OP_NONE) {
+ params->param2IsVar = false;
+ params->param2 = 0;
+ } else {
+ params->param2IsVar = conv_get_script_byte();
+ params->param2 = conv_get_script_word();
+ }
+}
+
+// ---------------------------------------------------------------------------
+// conv_scr_get_param
+//
+// Resolves one operand of a script expression. If the corresponding IsVar
+// flag is set the stored value is treated as a variable index and the live
+// value is fetched from conv_varsDataPtr; otherwise the value is used
+// directly.
+//
+// paramNum: 0 = param1, 1 = param2
+// ---------------------------------------------------------------------------
+static int16 conv_scr_get_param(ConvScriptParams *params, int paramNum) {
+ if (paramNum) {
+ return params->param2IsVar == 1 ? *conv_get_variable(params->param2) : params->param2;
+ } else {
+ return params->param1IsVar == 1 ? *conv_get_variable(params->param1) : params->param1;
+ }
+}
+
+// ---------------------------------------------------------------------------
+// conv_param_evaluate
+//
+// Evaluates a script expression encoded in *params and returns the result as
+// an int16.
+//
+// Special operation codes:
+// CONV_OP_NONE (255) â no expression; returns -1 without reading params.
+// CONV_OP_VALUE ( 0) â identity; returns param1 (resolved variable or
+// literal) without a second operand.
+//
+// Operations 1â13 take two resolved operands (param1, param2) and compute
+// arithmetic or logical results. An out-of-range operation code is a
+// non-fatal error (WARNING); the initialised result of -1 is returned.
+// ---------------------------------------------------------------------------
+static int16 conv_param_evaluate(ConvScriptParams *params) {
+ int16 result = -1;
+
+ if (params->operation == CONV_OP_NONE)
+ return result;
+
+ int16 param1 = conv_scr_get_param(params, 0);
+
+ if (params->operation == CONV_OP_VALUE)
+ return param1;
+
+ int16 param2 = conv_scr_get_param(params, 1);
+
+ switch (params->operation) {
+ case CONV_OP_ADD:
+ result = param1 + param2;
+ break;
+ case CONV_OP_SUB:
+ result = param1 - param2;
+ break;
+ case CONV_OP_MUL:
+ result = param1 * param2;
+ break;
+ case CONV_OP_DIV:
+ result = param1 / param2;
+ break;
+ case CONV_OP_MOD:
+ result = param1 % param2;
+ break;
+ case CONV_OP_GE:
+ result = (param1 >= param2) ? 1 : 0;
+ break;
+ case CONV_OP_LE:
+ result = (param1 <= param2) ? 1 : 0;
+ break;
+ case CONV_OP_GT:
+ result = (param1 > param2) ? 1 : 0;
+ break;
+ case CONV_OP_LT:
+ result = (param1 < param2) ? 1 : 0;
+ break;
+ case CONV_OP_NE:
+ result = (param1 != param2) ? 1 : 0;
+ break;
+ case CONV_OP_EQ:
+ result = (param1 == param2) ? 1 : 0;
+ break;
+ case CONV_OP_AND:
+ result = (param1 != 0 && param2 != 0) ? 1 : 0;
+ break;
+ case CONV_OP_OR:
+ result = (param1 != 0 || param2 != 0) ? 1 : 0;
+ break;
+ default:
+ // Unknown operator â non-fatal; report and return the initialised -1.
+ error_report(ERROR_CONV_BAD_OPERATOR, WARNING, MODULE_CONV,
+ conv_dlg_script_ptr, (int)params->operation);
+ break;
+ }
+
+ return result;
+}
+
+// ---------------------------------------------------------------------------
+// conv_generate_menu
+//
+// Prepares the player-choice menu for the current conversation node.
+//
+// Calls conv_list_options(0) to populate convData->optionList[] with the global
+// dialog indices of all active entries for the current node and to obtain the
+// total active count.
+//
+// If the node's field_8 value is >= count it acts as a redirect: variables
+// are updated to the target node stored in field_6 and the function returns 0
+// so the caller (conv_update) can loop and re-evaluate.
+//
+// Otherwise the function initialises the dialog interface, registers each
+// active entry's display text with inter_add_dialog(), enables command input,
+// and returns 2.
+//
+// Parameters
+// convData â ConvData for the active conversation (provides optionList)
+// convIn â Conv for the active conversation (provides nodes and dialogs)
+//
+// Returns
+// 0 â node redirected to another node (caller should re-run)
+// 2 â menu built and ready for player input
+// ---------------------------------------------------------------------------
+static int conv_generate_menu(ConvData *convData, Conv *convIn) {
+ int16 count = conv_list_options(0);
+ int16 nodeIndex = *conv_vars0ValPtr;
+ ConvNode *node = &convIn->nodes[nodeIndex];
+
+ // If field_8 >= count the node is a redirect: jump to the node index
+ // stored in field_6 and tell the caller to re-evaluate.
+ if (node->field_8 >= count) {
+ *conv_vars0ValPtr = node->field_6;
+ *conv_my_next_start = *conv_vars0ValPtr;
+ return 0;
+ }
+
+ // Sanity-check: there should be at least one active dialog entry.
+ if (count < 1)
+ error_report(ERROR_CONV_MENU, ERROR, MODULE_CONV, nodeIndex, count);
+
+ conv_control.popup_clock = kernel.clock;
+ kernel_init_dialog();
+
+ for (int i = 0; i < count; ++i) {
+ int16 dialogIdx = convData->optionList[i];
+ int16 textLineIdx = convIn->dialogs[dialogIdx].text_line_index;
+
+ if (textLineIdx < 0) {
+ // Dialog entry has no associated text â report and skip.
+ error_report(ERROR_CONV_NO_TEXT_LINE, ERROR, MODULE_CONV, dialogIdx, textLineIdx);
+ continue;
+ }
+
+ inter_add_dialog(const_cast<char *>(conv_string(textLineIdx, convIn)), dialogIdx);
+ }
+
+ kernel_set_interface_mode(INTER_CONVERSATION);
+ player.commands_allowed = -1;
+ return 2;
+}
+
+static void conv_handle_cmd123(int cmd) {
+ ConvScriptParams params;
+ conv_param_load(¶ms);
+ int value = conv_param_evaluate(¶ms);
+ int numFlags = conv_get_script_byte();
+
+ for (int i = 0; i < numFlags; ++i) {
+ int entryIndex = conv_get_script_word();
+ if (value)
+ conv_flag_entry(cmd, entryIndex);
+ }
+}
+
+static void conv_message(int cmd) {
+ ConvScriptParams params;
+ conv_param_load(¶ms);
+ int value = conv_param_evaluate(¶ms);
+ int count1 = conv_get_script_byte();
+ int count2 = conv_get_script_byte();
+ int total = 0;
+ int val1 = 0;
+ int array1[10], array2[10], array3[10];
+
+ for (int i = 0; i < count1; ++i) {
+ val1 = conv_get_script_byte();
+ if (i < 10) {
+ array1[i] = val1;
+ total += val1;
+ }
+ }
+
+ for (int i = 0; i < count1; ++i) {
+ val1 = conv_get_script_word();
+ if (i < 10)
+ array2[i] = val1;
+ }
+
+ for (int i = 0; i < count2; ++i) {
+ val1 = conv_get_script_word();
+ if (i < 10)
+ array3[i] = val1;
+ }
+
+ if (!value)
+ return;
+
+ // Weighted random selection: pick one of the count1 choices using the
+ // byte weights in array1. randomIndex starts at -1 and is incremented
+ // before each subtraction so that the first iteration checks array1[0].
+ // The loop exits (jg / jump-if-greater) when randomVal drops to <= 0,
+ // leaving randomIndex pointing at the selected entry.
+ int randomVal = imath_random(1, total);
+ int randomIndex = -1;
+ do {
+ ++randomIndex;
+ randomVal -= array1[randomIndex];
+ } while (randomVal > 0);
+
+ int entryVal = array2[randomIndex];
+
+ if (cmd == 4) {
+ // Player/"you" line
+ if (active_conv_data->messageList2_size < 10)
+ active_conv_data->messageList2[active_conv_data->messageList2_size++] = (int16)entryVal;
+
+ if (count1 > 1) {
+ // Multiple weighted choices: append only the matching data entry
+ if (randomIndex < count2 && active_conv_data->messageList4_size < 10)
+ active_conv_data->messageList4[active_conv_data->messageList4_size++] = (int16)array3[randomIndex];
+ } else {
+ // Single choice: append every data entry from array3
+ for (int i = 0; i < count2; ++i) {
+ if (active_conv_data->messageList4_size < 10)
+ active_conv_data->messageList4[active_conv_data->messageList4_size++] = (int16)array3[i];
+ }
+ }
+ } else {
+ // NPC/"me" line
+ if (active_conv_data->messageList1_size < 10)
+ active_conv_data->messageList1[active_conv_data->messageList1_size++] = (int16)entryVal;
+
+ if (count1 > 1) {
+ // Multiple weighted choices: append only the matching speech entry
+ if (randomIndex < count2 && active_conv_data->speechListSize < 10)
+ active_conv_data->speechList[active_conv_data->speechListSize++] = (int16)array3[randomIndex];
+ } else {
+ // Single choice: append every speech entry from array3
+ for (int i = 0; i < count2; ++i) {
+ if (active_conv_data->speechListSize < 10)
+ active_conv_data->speechList[active_conv_data->speechListSize++] = (int16)array3[i];
+ }
+ }
+ }
+}
+
+static int conv_cmd_node() {
+ ConvScriptParams params1, params2, params3;
+ int result = 0;
+ conv_param_load(¶ms1);
+ conv_param_load(¶ms2);
+ conv_param_load(¶ms3);
+
+ if (conv_param_evaluate(¶ms1)) {
+ int val2 = conv_param_evaluate(¶ms2);
+ int val3 = conv_param_evaluate(¶ms3);
+
+ *conv_vars0ValPtr = val2;
+ if (val2 >= 0)
+ *conv_my_next_start = val2;
+ else if (val3 >= 0)
+ *conv_my_next_start = val3;
+
+ result = -1;
+ }
+
+ return result;
+}
+
+static void conv_cmd_assign() {
+ ConvScriptParams params1, params2;
+ conv_param_load(¶ms1);
+ conv_param_load(¶ms2);
+ int varIndex = conv_get_script_word();
+
+ if (conv_param_evaluate(¶ms1)) {
+ int val = conv_param_evaluate(¶ms2);
+ int16 *varPtr = conv_get_variable(varIndex);
+ *varPtr = val;
+ }
+}
+
+static void conv_cmd_goto() {
+ ConvScriptParams params1;
+ conv_param_load(¶ms1);
+ int newOffset = conv_get_script_word();
+
+ if (conv_param_evaluate(¶ms1))
+ conv_dlg_script_ptr = newOffset;
+}
+
+// ---------------------------------------------------------------------------
+// conv_execute_entry
+//
+// Executes the byte-code script attached to dialog entry 'index' within the
+// active conversation. The script is consumed as a stream of command bytes,
+// each optionally followed by parameters read via the conv_get_script_*
+// helpers. Command byte values:
+//
+// 0 â no-op (continue to next command)
+// 1, 2, 3 â flag/show/hide entry â conv_handle_cmd123(cmd)
+// 4, 5 â NPC/player message â conv_message(cmd)
+// 6 â invalid command (error)
+// 7 â conditional node jump â conv_cmd_node()
+// 8 â conditional script goto â conv_cmd_goto()
+// 9 â conditional variable assign â conv_cmd_assign()
+// >9 â invalid (same error path as 6)
+//
+// Execution continues until the script pointer advances past the end of the
+// script block, or until conv_cmd_node() signals "done" by returning
+// non-zero (which sets flag â 0 â loop exit).
+//
+// Returns *conv_vars0ValPtr: set to -1 when the script ran to natural
+// completion; left at whatever conv_cmd_node() wrote there when a node
+// jump caused an early exit.
+// ---------------------------------------------------------------------------
+static int16 conv_execute_entry(int index) {
+ // Point the script stream at this dialog entry's byte-code block.
+ ConvDialog &dlg = active_conv->dialogs[index];
+ conv_dlg_script_ptr = dlg.script_offset;
+ conv_dlg_script_end = dlg.script_offset + dlg.script_size;
+
+ // Reset per-execution message lists.
+ active_conv_data->messageList1_size = 0;
+ active_conv_data->messageList2_size = 0;
+ active_conv_data->speechListSize = 0;
+ active_conv_data->messageList4_size = 0;
+
+ // Restore the current node pointer from the saved "next start" slot.
+ *conv_vars0ValPtr = *conv_my_next_start;
+
+ // flag: -1 = keep looping; 0 = early exit requested by cmd7.
+ int16 flag = -1;
+
+ for (;;) {
+ // Exit when the script pointer has advanced past the end of the block
+ // (matches: cmp conv_dlg_script_end, ax; jnb; else jmp exit).
+ if (conv_dlg_script_ptr > conv_dlg_script_end)
+ break;
+
+ int commandId = (uint8)conv_get_script_byte();
+
+ if (commandId > 9) {
+ // Unknown command â non-fatal error; loop will naturally exhaust
+ // the script or hit a real end.
+ error_report(-50, ERROR, MODULE_CONV, conv_dlg_script_ptr, commandId);
+ } else {
+ switch (commandId) {
+ case 0:
+ // No-op: read next command.
+ break;
+ case 1:
+ case 2:
+ case 3:
+ conv_handle_cmd123(commandId);
+ break;
+ case 4:
+ case 5:
+ conv_message(commandId);
+ break;
+ case 6:
+ error_report(-50, ERROR, MODULE_CONV, conv_dlg_script_ptr, commandId);
+ break;
+ case 7:
+ // conv_cmd_node returns non-zero when a node jump was taken
+ // (signal done â flag=0 â exit loop); 0 means no jump taken
+ // (flag=1 â continue).
+ // Matches: cmp ax,1; sbb ax,ax; neg ax
+ flag = conv_cmd_node() ? 0 : 1;
+ break;
+ case 8:
+ conv_cmd_goto();
+ break;
+ case 9:
+ conv_cmd_assign();
+ break;
+ }
+ }
+
+ // Exit early if a command set flag to 0.
+ if (flag == 0)
+ break;
+ }
+
+ // Natural completion (flag still non-zero): mark node as finished.
+ // Early exit (flag == 0): conv_cmd_node already wrote the new target node.
+ if (flag != 0)
+ *conv_vars0ValPtr = -1;
+
+ return *conv_vars0ValPtr;
+}
+
+// ====================================================================
+// Public API
+// ====================================================================
+
void conv_system_init() {
Common::fill((byte *)&conv_control, (byte *)&conv_control + sizeof(ConvControl), 0);
conv_control.running = -1;
@@ -586,10 +1200,10 @@ void conv_run(int convId) {
// Variable 2 maps to speaker_val (not contiguous with the arrays below).
// Variables 3â22 map to speaker_frame[5], x[5], y[5], width[5] â 20
// consecutive int16s â so a single pointer walk replaces 20 separate calls.
- conv_set_variable(2, -1, &conv_control.speaker_val);
+ conv_set_variable(2, &conv_control.speaker_val);
int16 *p = conv_control.speaker_frame;
for (int i = 3; i <= 22; ++i, ++p)
- conv_set_variable(i, -1, p);
+ conv_set_variable(i, p);
// Load speaker portrait series for each declared speaker
for (idx = 0; idx < conv[slot]->speaker_count; ++idx) {
@@ -609,93 +1223,222 @@ void conv_run(int convId) {
}
// ---------------------------------------------------------------------------
-// conv_string
+// conv_generate_message
//
-// Returns a pointer to the null-terminated text string whose index within the
-// flat text buffer is stored in conv->textLines[textIdx]. The text blob is
-// held in conv->text (stored as uint16 units but treated as a byte stream);
-// textLines values are byte offsets into that blob.
-// ---------------------------------------------------------------------------
-static const char *conv_string(int textIdx, Conv *convIn) {
- uint16 byteOffset = convIn->textLines[textIdx];
- return reinterpret_cast<const char *>(convIn->text.begin()) + byteOffset;
-}
-
-// ---------------------------------------------------------------------------
-// string_trim
+// Generates and displays a conversation message popup for either the NPC
+// ("me") or player ("you") side, drawing from message and voice/data index
+// lists that conv_execute_entry populated.
//
-// Strips trailing whitespace (any byte value <= ' ') from a mutable C string
-// in-place. Mirrors the original DOS helper of the same name.
+// Parameters (DOS push order â rightmost pushed first):
+// voiceList â array of speech/data indices (speechList or messageList4)
+// msgList â array of dialog text indices (messageList1 or messageList2)
+// convData â active ConvData
+// convIn â active Conv
+// msgListSize â number of valid entries in msgList (in ax)
+// voiceListSize â number of valid entries in voiceList (in dx)
// ---------------------------------------------------------------------------
-static void string_trim(char *str) {
- if (!str) return;
- size_t len = strlen(str);
- while (len > 0 && (unsigned char)str[len - 1] <= ' ')
- str[--len] = '\0';
+static void conv_generate_message(int16 *voiceList, int16 *msgList,
+ ConvData *convData, Conv *convIn,
+ int msgListSize, int voiceListSize) {
+ // TODO
}
// ---------------------------------------------------------------------------
-// conv_generate_text
+// conv_update
//
-// Builds and displays a conversation-line popup for the current speaker, then
-// triggers the associated speech audio (if the speech system is active and at
-// least one speech index was supplied).
+// Main per-tick conversation state machine. Called once per game tick while
+// a conversation is running. The 'flag' parameter indicates whether the
+// engine has a pending player command ready (mirrors player.command_ready in
+// the callers for modes 1 and 2).
//
-// Parameters
-// speechList â array of speech-audio indices; speechList[0] is played
-// convData â active ConvData (unused here; callers already route through
-// conv_control)
-// convIn â active Conv (provides the text pool and speech filename)
-// textIdx â index into convIn->textLines that selects the dialog string
-// speechCount â number of valid entries in speechList (0 = no speech)
+// Status dispatch table (off_2D438):
+// 0 (NEXT_NODE) â advance to next node or build player menu
+// 1 (WAIT_AUTO) â wait for auto-trigger then advance to EXECUTE
+// 2 (WAIT_ENTRY) â player chose an option; execute it + show NPC portrait
+// 3 (EXECUTE) â (clock-gated) execute entry script + show NPC message
+// 4 (REPLY) â (clock-gated) show player reply message
+// 5â9 â no-op (exit)
+// 10 (DONE) â call conv_abort
+// >10 â no-op (exit)
// ---------------------------------------------------------------------------
-static void conv_generate_text(int16 *speechList, ConvData * /*convData*/,
- Conv *convIn, int textIdx, int speechCount) {
- int person = conv_control.person_speaking;
- char textBuf[512];
- Box *savedBox;
+void conv_update(bool flag) {
+ if (conv_control.running < 0)
+ return;
- // Redirect popup operations to the conversation-private box so that the
- // bounds recorded by popup_draw can be used later by conv_purge_any_popup.
- savedBox = box;
- box = &conv_box;
+ int slot = conv_control.index;
+ Conv *my_conv = conv[slot];
+ ConvData *my_conv_data = conv_data[slot];
+
+ switch (conv_control.status) {
+
+ // ------------------------------------------------------------------
+ // Mode 0 â NEXT_NODE
+ // ------------------------------------------------------------------
+ case CONV_STATUS_NEXT_NODE: {
+ if (*conv_vars0ValPtr < 0) {
+ // Node is exhausted â wait for the popup clock then clean up.
+ if (kernel.clock < conv_control.popup_clock)
+ return;
+
+ conv_purge_any_popup();
+
+ if (conv_control.me_trigger) {
+ player_verb = conv_control.entry;
+ kernel.trigger = conv_control.me_trigger;
+ kernel.trigger_mode = conv_control.me_trigger_mode;
+ conv_control.me_trigger = 0;
+ return;
+ }
+
+ conv_control.status = CONV_STATUS_DONE;
+ return;
+ }
- // Size and position the popup from the current speaker's slot data.
- int horiz_pieces = popup_estimate_pieces(conv_control.width[person]);
- popup_create(horiz_pieces,
- conv_control.x[person],
- conv_control.y[person]);
+ // Advance to the next node in the script.
+ int var_4 = conv_next_node();
+ conv_control.node = *conv_vars0ValPtr;
- // Attach the speaker portrait icon if a series was loaded for this slot.
- // The icon_id is the 1-based frame stored in speaker_frame.
- // center=0: left-aligned within the popup box.
- if (conv_control.speaker_series[person] >= 0) {
- popup_add_icon(series_list[conv_control.speaker_series[person]],
- conv_control.speaker_frame[person],
- 0);
+ if (!var_4) {
+ // Node is a player-choice menu node.
+ conv_control.status = (ConvStatus)conv_generate_menu(my_conv_data, my_conv);
+ return;
+ }
+
+ // Node is an auto-play NPC node: pick the first dialog entry and
+ // fire a synthetic player command so mode 1 can advance to EXECUTE.
+ int16 nodeIndex = *conv_vars0ValPtr;
+ conv_control.entry = my_conv->nodes[nodeIndex].index;
+ conv_control.status = CONV_STATUS_WAIT_AUTO;
+ player_verb = conv_control.entry;
+ player.command_ready = -1;
+ player.command_error = 0;
+ return;
}
- // Copy the dialog string to a local mutable buffer, strip trailing
- // whitespace (the raw text pool can have padding bytes), then write it.
- Common::strlcpy(textBuf, conv_string(textIdx, convIn), sizeof(textBuf));
- string_trim(textBuf);
- popup_write_string(textBuf);
+ // ------------------------------------------------------------------
+ // Mode 10 â DONE: conversation finished, tear everything down.
+ // ------------------------------------------------------------------
+ case CONV_STATUS_DONE:
+ conv_abort();
+ return;
+
+ // ------------------------------------------------------------------
+ // Mode 1 â WAIT_AUTO: waiting for the synthetic command to fire.
+ // ------------------------------------------------------------------
+ case CONV_STATUS_WAIT_AUTO:
+ if (!flag)
+ return;
+ conv_control.status = CONV_STATUS_EXECUTE;
+ return;
+
+ // ------------------------------------------------------------------
+ // Mode 2 â WAIT_ENTRY: player has chosen a dialog option.
+ // ------------------------------------------------------------------
+ case CONV_STATUS_WAIT_ENTRY: {
+ if (!flag)
+ return;
+
+ player.commands_allowed = 0;
+ conv_control.entry = player_verb;
+
+ // Auto-hide the entry unless it is flagged as always-visible (bit 1).
+ if (!(active_conv_data->entryFlags[conv_control.entry] & 2))
+ conv_flag_entry(2, conv_control.entry);
- // Render the popup, saving the underlying screen region.
- popup_draw(true, false);
+ conv_purge_any_popup();
+ kernel_init_dialog();
+ kernel_set_interface_mode(INTER_CONVERSATION);
+ conv_control.person_speaking = 0;
+
+ conv_execute_entry(conv_control.entry);
+
+ // If the dialog has a dedicated speech index, override the speech list
+ // with that single index (takes priority over anything conv_execute_entry
+ // populated via conv_message).
+ int16 speech_idx = my_conv->dialogs[conv_control.entry].speech_index;
+ if (speech_idx) {
+ my_conv_data->speechList[0] = speech_idx;
+ my_conv_data->speechListSize = 1;
+ }
- // Restore the caller's box and record that a conversation popup is live.
- box = savedBox;
- conv_control.popup_is_up = -1;
- conv_control.popup_clock = kernel.clock;
+ conv_generate_text(my_conv_data->speechList, my_conv_data, my_conv,
+ my_conv->dialogs[conv_control.entry].text_line_index,
+ my_conv_data->speechListSize);
- // Play the associated speech audio when the speech system is on.
- if (speech_system_active && speech_on && speechCount > 0) {
- speech_ems_play(convIn->speech_file, speechList[0]);
+ conv_control.status = CONV_STATUS_REPLY;
+
+ if (conv_control.me_trigger) {
+ player_verb = conv_control.entry;
+ kernel.trigger = conv_control.me_trigger;
+ kernel.trigger_mode = conv_control.me_trigger_mode;
+ conv_control.me_trigger = 0;
+ return;
+ }
+ return;
}
-}
-void conv_update(bool) {
+ // ------------------------------------------------------------------
+ // Mode 3 â EXECUTE: execute the NPC entry's script and show message.
+ // ------------------------------------------------------------------
+ case CONV_STATUS_EXECUTE: {
+ if (kernel.clock < conv_control.popup_clock)
+ return;
+
+ conv_purge_any_popup();
+ conv_control.person_speaking = 0;
+
+ conv_execute_entry(conv_control.entry);
+
+ conv_generate_message(my_conv_data->speechList,
+ my_conv_data->messageList1,
+ my_conv_data, my_conv,
+ my_conv_data->messageList1_size,
+ my_conv_data->speechListSize);
+
+ // Fire me_trigger if one is pending and a popup is visible.
+ if (conv_control.me_trigger && conv_control.popup_is_up) {
+ player_verb = conv_control.entry;
+ kernel.trigger = conv_control.me_trigger;
+ kernel.trigger_mode = conv_control.me_trigger_mode;
+ conv_control.me_trigger = 0;
+ }
+
+ conv_control.status = CONV_STATUS_REPLY;
+ return;
+ }
+
+ // ------------------------------------------------------------------
+ // Mode 4 â REPLY: show the player's reply message.
+ // ------------------------------------------------------------------
+ case CONV_STATUS_REPLY: {
+ if (kernel.clock < conv_control.popup_clock)
+ return;
+
+ conv_purge_any_popup();
+ conv_control.person_speaking = conv_control.speaker_val;
+
+ conv_generate_message(my_conv_data->messageList4,
+ my_conv_data->messageList2,
+ my_conv_data, my_conv,
+ my_conv_data->messageList2_size,
+ my_conv_data->messageList4_size);
+
+ conv_control.status = CONV_STATUS_NEXT_NODE;
+
+ if (conv_control.you_trigger && conv_control.popup_is_up) {
+ player_verb = conv_control.entry;
+ kernel.trigger = conv_control.you_trigger;
+ kernel.trigger_mode = conv_control.you_trigger_mode;
+ conv_control.you_trigger = 0;
+ return;
+ }
+ return;
+ }
+
+ default:
+ // Statuses 5â9 and anything above 10: no-op.
+ return;
+ }
}
void conv_regenerate_last_message() {
@@ -727,15 +1470,23 @@ void conv_me_trigger(int trigger) {}
void conv_you_trigger(int trigger) {}
-int *conv_get_variable(int varNum) {
+int16 *conv_get_variable(int varNum) {
assert(varNum >= 0 && varNum < active_conv_data->variablesCount);
+ ConvVariable &var = active_conv_data->variables[varNum];
- // TODO
- return nullptr;
+ return var.isPtr ? var.ptr : &var.val;
}
-void conv_export_value(int varNum) {
- // TODO
+void conv_export_value(int16 value) {
+ if (conv_control.running >= 0) {
+ Conv &c = *conv[conv_control.index];
+ ConvData &cd = *conv_data[conv_control.index];
+
+ if (cd.numImports < c.max_imports) {
+ int idx = conv_imports[cd.numImports++];
+ conv_set_variable(idx, value);
+ }
+ }
}
void conv_hold() {
diff --git a/engines/mads/madsv2/core/conv.h b/engines/mads/madsv2/core/conv.h
index 909c651d5a1..d0907026d78 100644
--- a/engines/mads/madsv2/core/conv.h
+++ b/engines/mads/madsv2/core/conv.h
@@ -32,14 +32,34 @@ constexpr int CONV_MAX_SLOTS = 40;
constexpr int CONV_MAX_DATA = 5;
enum ConvStatus {
- CONV_STATUS_HOLDING = -1,
+ CONV_STATUS_HOLDING = -1,
CONV_STATUS_NEXT_NODE = 0,
CONV_STATUS_WAIT_AUTO = 1,
CONV_STATUS_WAIT_ENTRY = 2,
- CONV_STATUS_EXECUTE = 3,
- CONV_STATUS_REPLY = 4
+ CONV_STATUS_EXECUTE = 3,
+ CONV_STATUS_REPLY = 4,
+ CONV_STATUS_DONE = 10 // conversation finished; next update calls conv_abort
};
+// Operator codes used inside conversation script expressions.
+// Stored as int16 on disk; 0 = identity (return param1), 255 = no expression.
+enum ConvOp : int16 {
+ CONV_OP_VALUE = 0, // No operator â return param1 directly
+ CONV_OP_ADD = 1, // param1 + param2
+ CONV_OP_SUB = 2, // param1 - param2
+ CONV_OP_MUL = 3, // param1 * param2
+ CONV_OP_DIV = 4, // param1 / param2 (signed integer)
+ CONV_OP_MOD = 5, // param1 % param2 (signed remainder)
+ CONV_OP_GE = 6, // param1 >= param2
+ CONV_OP_LE = 7, // param1 <= param2
+ CONV_OP_GT = 8, // param1 > param2
+ CONV_OP_LT = 9, // param1 < param2
+ CONV_OP_NE = 10, // param1 != param2
+ CONV_OP_EQ = 11, // param1 == param2
+ CONV_OP_AND = 12, // param1 && param2 (logical)
+ CONV_OP_OR = 13, // param1 || param2 (logical)
+ CONV_OP_NONE = 255 // No expression â evaluates to -1
+};
struct ConvNode {
int16 index;
@@ -63,8 +83,8 @@ struct ConvDialog {
};
struct ConvScriptParams {
- int16 operation;
- byte param1IsVar;
+ ConvOp operation;
+ byte param1IsVar;
byte param2IsVar;
int16 param1;
int16 param2;
@@ -74,9 +94,11 @@ struct ConvScriptParams {
};
struct ConvVariable {
- int16 isPtr;
- int16 val;
- int16 unused;
+ bool isPtr = false;
+ union {
+ int16 val;
+ int16 *ptr;
+ };
static constexpr int SIZE = 2 * 3;
void load(Common::SeekableReadStream *src);
@@ -138,12 +160,12 @@ struct ConvDataBase {
int16 variablesCount;
int16 importsCount;
int16 numImports;
- int16 array1_size;
+ int16 optionListSize;
int16 messageList1_size;
int16 messageList2_size;
int16 speechListSize;
int16 messageList4_size;
- int16 array1[10];
+ int16 optionList[10];
int16 messageList1[10];
int16 messageList2[10];
int16 speechList[10];
@@ -185,7 +207,7 @@ struct ConvControl {
int16 has_text;
int16 popup_is_up;
int16 mask;
- uint32 popup_clock;
+ long popup_clock;
int16 speaker_active[CONV_MAX_DATA];
int16 speaker_series[CONV_MAX_DATA];
int16 speaker_frame[CONV_MAX_DATA];
@@ -216,7 +238,7 @@ extern int16 *conv_vars0ValPtr;
extern int conv_restore_running;
extern ConvControl conv_control;
-extern int *conv_my_next_start;
+extern int16 *conv_my_next_start;
extern void conv_system_init();
extern void conv_system_cleanup();
@@ -231,8 +253,8 @@ extern void conv_export_pointer(int *ptr);
extern void conv_abort();
extern void conv_me_trigger(int trigger);
extern void conv_you_trigger(int trigger);
-extern int *conv_get_variable(int varNum);
-extern void conv_export_value(int varNum);
+extern int16 *conv_get_variable(int varNum);
+extern void conv_export_value(int16 value);
extern void conv_hold();
extern void conv_release();
extern void conv_flush();
diff --git a/engines/mads/madsv2/phantom/rooms/room103.cpp b/engines/mads/madsv2/phantom/rooms/room103.cpp
index a7670feb8ea..4b6bfb43b27 100644
--- a/engines/mads/madsv2/phantom/rooms/room103.cpp
+++ b/engines/mads/madsv2/phantom/rooms/room103.cpp
@@ -841,7 +841,7 @@ void room_103_daemon(void) {
static void process_conv_jacques(void) {
int quit_converse = false;
- int *value_1;
+ int16 *value_1;
switch (player_verb) {
case conv012_hello_four:
diff --git a/engines/mads/madsv2/phantom/rooms/room203.cpp b/engines/mads/madsv2/phantom/rooms/room203.cpp
index bda4b4826ce..cbd99a16bc6 100644
--- a/engines/mads/madsv2/phantom/rooms/room203.cpp
+++ b/engines/mads/madsv2/phantom/rooms/room203.cpp
@@ -1172,8 +1172,8 @@ static void process_conversation_brie() {
static void process_conversation_rich() {
int you_trig_flag = false;
int me_trig_flag = false;
- int *value_1;
- int *value_2;
+ int16 *value_1;
+ int16 *value_2;
switch (player_verb) {
case conv008_tellabout_have:
Commit: e94aa52b171081ee9b0ebdd695ed59e43fc2551d
https://github.com/scummvm/scummvm/commit/e94aa52b171081ee9b0ebdd695ed59e43fc2551d
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:10+10:00
Commit Message:
MADS: PHANTOM: Conv message functions
Changed paths:
engines/mads/madsv2/core/conv.cpp
engines/mads/madsv2/core/conv.h
engines/mads/madsv2/core/global.h
diff --git a/engines/mads/madsv2/core/conv.cpp b/engines/mads/madsv2/core/conv.cpp
index d1971455742..9cd8bdaa1f5 100644
--- a/engines/mads/madsv2/core/conv.cpp
+++ b/engines/mads/madsv2/core/conv.cpp
@@ -20,6 +20,8 @@
*/
#include "common/algorithm.h"
+#include "common/hashmap.h"
+#include "common/hash-str.h"
#include "common/memstream.h"
#include "common/textconsole.h"
#include "mads/madsv2/core/conv.h"
@@ -28,12 +30,12 @@
#include "mads/madsv2/core/error.h"
#include "mads/madsv2/core/fileio.h"
#include "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/imath.h"
#include "mads/madsv2/core/inter.h"
#include "mads/madsv2/core/kernel.h"
#include "mads/madsv2/core/matte.h"
#include "mads/madsv2/core/mem.h"
#include "mads/madsv2/core/popup.h"
-#include "mads/madsv2/core/imath.h"
#include "mads/madsv2/core/speech.h"
namespace MADS {
@@ -54,6 +56,13 @@ int16 *conv_my_next_start;
int conv_error_code;
int conv_dlg_script_ptr, conv_dlg_script_end;
+struct MemoryWriteStreamDynamic : public Common::MemoryWriteStreamDynamic {
+public:
+ MemoryWriteStreamDynamic() : Common::MemoryWriteStreamDynamic(DisposeAfterUse::YES) {}
+};
+Common::HashMap<Common::String, MemoryWriteStreamDynamic,
+ Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> *savedConv;
+
static int conv_indexes[CONV_MAX_SLOTS];
static int conv_slots[CONV_MAX_DATA];
@@ -129,11 +138,32 @@ static const char *conv_get_filename(int convNum, int extType, char *name) {
return name;
}
+// conv_open version for when mode is "rb"
static Common::SeekableReadStream *conv_open(int convNum) {
char name[40];
- return env_open(conv_get_filename(convNum, 2, name));
+ conv_get_filename(convNum, 2, name);
+ Common::String fname = name;
+
+ // If there's a pretend temporary file for it, use that instead
+ if (savedConv->contains(fname))
+ return new Common::MemoryReadStream((*savedConv)[fname].getData(),
+ (*savedConv)[fname].size());
+
+ // Fall back on normal resource open
+ return env_open(name);
+}
+
+// conv_open version for when mode is "wb"
+static Common::WriteStream *conv_open_write(int convNum) {
+ char name[40];
+ conv_get_filename(convNum, 2, name);
+ Common::String fname = name;
+
+ (*savedConv)[fname] = MemoryWriteStreamDynamic();
+ return &(*savedConv)[fname];
}
+
// ---------------------------------------------------------------------------
// string_trim â strips trailing whitespace from a mutable C string in-place.
// ---------------------------------------------------------------------------
@@ -149,9 +179,9 @@ static void string_trim(char *str) {
// identified by textIdx. textLines[textIdx] is a byte offset into the flat
// text character pool stored in conv->text.
// ---------------------------------------------------------------------------
-static const char *conv_string(int textIdx, Conv *convIn) {
- uint16 byteOffset = convIn->textLines[textIdx];
- return reinterpret_cast<const char *>(convIn->text.begin()) + byteOffset;
+static const char *conv_string(Conv *convIn, int textIdx) {
+ uint16 strOffset = convIn->textLines[textIdx];
+ return &convIn->text[0] + strOffset;
}
// Version to use if the isPtr parameter is true (-1)
@@ -267,8 +297,10 @@ static Conv *load_conv(const char *fname) {
Common::MemoryReadStream src(buffer, convHeader.message_count * 4);
dataPtr->messages.resize(convHeader.message_count);
- for (int i = 0; i < convHeader.message_count; ++i)
- dataPtr->messages[i] = src.readSint32LE();
+ for (int i = 0; i < convHeader.message_count; ++i) {
+ dataPtr->messages[i].lineStart = src.readSint16LE();
+ dataPtr->messages[i].lineCount = src.readSint16LE();
+ }
free(buffer);
}
@@ -547,7 +579,7 @@ static void conv_generate_text(int16 *speechList, ConvData * /*convData*/,
// Copy the dialog string to a local mutable buffer, strip trailing
// whitespace (the raw text pool can have padding bytes), then write it.
- Common::strlcpy(textBuf, conv_string(textIdx, convIn), sizeof(textBuf));
+ Common::strlcpy(textBuf, conv_string(convIn, textIdx), sizeof(textBuf));
string_trim(textBuf);
popup_write_string(textBuf);
@@ -821,7 +853,7 @@ static int conv_generate_menu(ConvData *convData, Conv *convIn) {
continue;
}
- inter_add_dialog(const_cast<char *>(conv_string(textLineIdx, convIn)), dialogIdx);
+ inter_add_dialog(const_cast<char *>(conv_string(convIn, textLineIdx)), dialogIdx);
}
kernel_set_interface_mode(INTER_CONVERSATION);
@@ -1082,11 +1114,13 @@ void conv_system_init() {
Common::fill(conv_slots, conv_slots + CONV_MAX_DATA, 0);
Common::fill(conv, conv + CONV_MAX_DATA, (Conv *)nullptr);
Common::fill(conv_data, conv_data + CONV_MAX_DATA, (ConvData *)nullptr);
- conv_system_cleanup();
+
+ savedConv = new Common::HashMap<Common::String, MemoryWriteStreamDynamic,
+ Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo>();
}
void conv_system_cleanup() {
- // Removes any files with the format 'conv%d.dat'
+ delete savedConv;
}
@@ -1240,7 +1274,50 @@ void conv_run(int convId) {
static void conv_generate_message(int16 *voiceList, int16 *msgList,
ConvData *convData, Conv *convIn,
int msgListSize, int voiceListSize) {
- // TODO
+ Box *priorBox = box;
+ box = &conv_box;
+ conv_control.has_text = 0;
+ int personSpeaking;
+ int messageId;
+ int lineStart, lineCount;
+ char tempString[256];
+
+ if (msgListSize != 0) {
+ personSpeaking = conv_control.person_speaking;
+ if (!popup_create(popup_estimate_pieces(conv_control.width[personSpeaking]),
+ conv_control.x[personSpeaking], conv_control.y[personSpeaking])) {
+ if (conv_control.speaker_series[personSpeaking] >= 0) {
+ popup_add_icon(series_list[conv_control.speaker_series[personSpeaking]],
+ conv_control.speaker_frame[personSpeaking], 0);
+ }
+
+ for (int msgIndex = 0; msgIndex < msgListSize; ++msgIndex) {
+ messageId = msgList[msgIndex];
+ lineStart = convIn->messages[messageId].lineStart;
+ lineCount = convIn->messages[messageId].lineCount;
+
+ for (int lineCtr = 0; lineCtr < lineCount; ++lineCtr) {
+ Common::strcpy_s(tempString, conv_string(convIn, lineStart + lineCtr));
+ string_trim(tempString);
+ popup_write_string(tempString);
+ }
+ }
+
+ popup_next_line();
+ if (!popup_draw(-1, -1)) {
+ conv_control.popup_is_up = -1;
+ conv_control.popup_clock = kernel.clock + conv_control.mask;
+
+ if (speech_system_active && speech_on) {
+ if (voiceListSize != 0) {
+ speech_ems_play(convIn->speech_file, *voiceList);
+ }
+ }
+ }
+ }
+ }
+
+ box = priorBox;
}
// ---------------------------------------------------------------------------
@@ -1490,15 +1567,30 @@ void conv_export_value(int16 value) {
}
void conv_hold() {
- // TODO
+ if (conv_control.status != CONV_STATUS_HOLDING) {
+ conv_control.hold_status = conv_control.status;
+ conv_control.status = CONV_STATUS_HOLDING;
+ }
}
void conv_release() {
- // TODO
+ if (conv_control.status == CONV_STATUS_HOLDING) {
+ conv_control.status = conv_control.hold_status;
+
+ if (conv_control.status == CONV_STATUS_WAIT_AUTO ||
+ conv_control.status == CONV_STATUS_WAIT_ENTRY)
+ conv_update(true);
+ }
}
void conv_flush() {
- // TODO
+/*
+ bool errorFlag = true;
+ int errCode = 0;
+
+ for (int i = 0; i < CONV_MAX_SLOTS; ++i) {
+ // TODO
+ }*/
}
int conv_append(Common::WriteStream *handle) {
diff --git a/engines/mads/madsv2/core/conv.h b/engines/mads/madsv2/core/conv.h
index d0907026d78..3e0e3dad4c9 100644
--- a/engines/mads/madsv2/core/conv.h
+++ b/engines/mads/madsv2/core/conv.h
@@ -146,10 +146,15 @@ struct Conv : public ConvBase {
return *this;
}
+ struct LineSet {
+ int lineStart = 0;
+ int lineCount = 0;
+ };
+
Common::Array<ConvNode> nodes;
Common::Array<ConvDialog> dialogs;
- Common::Array<int32> messages;
- Common::Array<uint16> text;
+ Common::Array<LineSet> messages;
+ Common::Array<char> text;
Common::Array<uint16> scripts;
Common::Array<uint16> textLines;
};
diff --git a/engines/mads/madsv2/core/global.h b/engines/mads/madsv2/core/global.h
index 619ef54538f..6f58a47c5c7 100644
--- a/engines/mads/madsv2/core/global.h
+++ b/engines/mads/madsv2/core/global.h
@@ -40,8 +40,8 @@ extern char global_release_copyright[];
/* Global macros */
-#define YES 1
-#define NO 0
+constexpr int YES = 1;
+constexpr int NO = 0;
#define SCORE_LOOK_SPHERE_106 1
#define SCORE_READ_BOOK_101 2
Commit: 49b7586aac8407b44e4e45fe9c1b7860d8d639f7
https://github.com/scummvm/scummvm/commit/49b7586aac8407b44e4e45fe9c1b7860d8d639f7
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:10+10:00
Commit Message:
MADS: PHANTOM: Further conv functions
Changed paths:
engines/mads/madsv2/core/conv.cpp
engines/mads/madsv2/core/conv.h
engines/mads/madsv2/core/game.cpp
engines/mads/madsv2/core/global.cpp
engines/mads/madsv2/core/global.h
engines/mads/madsv2/core/kernel.cpp
engines/mads/madsv2/core/kernel.h
engines/mads/madsv2/core/popup.cpp
engines/mads/madsv2/core/popup.h
engines/mads/madsv2/core/text.cpp
diff --git a/engines/mads/madsv2/core/conv.cpp b/engines/mads/madsv2/core/conv.cpp
index 9cd8bdaa1f5..b02026207a1 100644
--- a/engines/mads/madsv2/core/conv.cpp
+++ b/engines/mads/madsv2/core/conv.cpp
@@ -111,12 +111,12 @@ void ConvVariable::load(Common::SeekableReadStream *src) {
void ConvDataHeader::load(Common::SeekableReadStream *src) {
src->readMultipleLE(currentNode, entryFlagsCount, variablesCount,
importsCount, numImports, optionListSize,
- messageList1_size, messageList2_size, speechListSize, messageList4_size);
+ messageList1Size, messageList2Size, speechList1Size, speechList2Size);
src->readMultipleLE(optionList);
src->readMultipleLE(messageList1);
src->readMultipleLE(messageList2);
- src->readMultipleLE(speechList);
- src->readMultipleLE(messageList4);
+ src->readMultipleLE(speechList1);
+ src->readMultipleLE(speechList2);
src->readMultipleLE(importsOffset, entryFlagsOffset, variablesOffset);
}
@@ -544,15 +544,15 @@ static void conv_purge_any_popup() {
// least one speech index was supplied).
//
// Parameters
-// speechList â array of speech-audio indices; speechList[0] is played
+// convIn â active Conv (provides the text pool and speech filename)
// convData â active ConvData (unused; callers already route through
// conv_control)
-// convIn â active Conv (provides the text pool and speech filename)
// textIdx â index into convIn->textLines that selects the dialog string
+// speechList â array of speech-audio indices; speechList[0] is played
// speechCount â number of valid entries in speechList (0 = no speech)
// ---------------------------------------------------------------------------
-static void conv_generate_text(int16 *speechList, ConvData * /*convData*/,
- Conv *convIn, int textIdx, int speechCount) {
+static void conv_generate_text(Conv *convIn, ConvData * /*convData*/,
+ int textIdx, int16 *speechList, int speechCount) {
int person = conv_control.person_speaking;
char textBuf[512];
Box *savedBox;
@@ -923,34 +923,34 @@ static void conv_message(int cmd) {
if (cmd == 4) {
// Player/"you" line
- if (active_conv_data->messageList2_size < 10)
- active_conv_data->messageList2[active_conv_data->messageList2_size++] = (int16)entryVal;
+ if (active_conv_data->messageList2Size < 10)
+ active_conv_data->messageList2[active_conv_data->messageList2Size++] = (int16)entryVal;
if (count1 > 1) {
// Multiple weighted choices: append only the matching data entry
- if (randomIndex < count2 && active_conv_data->messageList4_size < 10)
- active_conv_data->messageList4[active_conv_data->messageList4_size++] = (int16)array3[randomIndex];
+ if (randomIndex < count2 && active_conv_data->speechList2Size < 10)
+ active_conv_data->speechList2[active_conv_data->speechList2Size++] = (int16)array3[randomIndex];
} else {
// Single choice: append every data entry from array3
for (int i = 0; i < count2; ++i) {
- if (active_conv_data->messageList4_size < 10)
- active_conv_data->messageList4[active_conv_data->messageList4_size++] = (int16)array3[i];
+ if (active_conv_data->speechList2Size < 10)
+ active_conv_data->speechList2[active_conv_data->speechList2Size++] = (int16)array3[i];
}
}
} else {
// NPC/"me" line
- if (active_conv_data->messageList1_size < 10)
- active_conv_data->messageList1[active_conv_data->messageList1_size++] = (int16)entryVal;
+ if (active_conv_data->messageList1Size < 10)
+ active_conv_data->messageList1[active_conv_data->messageList1Size++] = (int16)entryVal;
if (count1 > 1) {
// Multiple weighted choices: append only the matching speech entry
- if (randomIndex < count2 && active_conv_data->speechListSize < 10)
- active_conv_data->speechList[active_conv_data->speechListSize++] = (int16)array3[randomIndex];
+ if (randomIndex < count2 && active_conv_data->speechList1Size < 10)
+ active_conv_data->speechList1[active_conv_data->speechList1Size++] = (int16)array3[randomIndex];
} else {
// Single choice: append every speech entry from array3
for (int i = 0; i < count2; ++i) {
- if (active_conv_data->speechListSize < 10)
- active_conv_data->speechList[active_conv_data->speechListSize++] = (int16)array3[i];
+ if (active_conv_data->speechList1Size < 10)
+ active_conv_data->speechList1[active_conv_data->speechList1Size++] = (int16)array3[i];
}
}
}
@@ -1033,10 +1033,10 @@ static int16 conv_execute_entry(int index) {
conv_dlg_script_end = dlg.script_offset + dlg.script_size;
// Reset per-execution message lists.
- active_conv_data->messageList1_size = 0;
- active_conv_data->messageList2_size = 0;
- active_conv_data->speechListSize = 0;
- active_conv_data->messageList4_size = 0;
+ active_conv_data->messageList1Size = 0;
+ active_conv_data->messageList2Size = 0;
+ active_conv_data->speechList1Size = 0;
+ active_conv_data->speechList2Size = 0;
// Restore the current node pointer from the saved "next start" slot.
*conv_vars0ValPtr = *conv_my_next_start;
@@ -1264,16 +1264,15 @@ void conv_run(int convId) {
// lists that conv_execute_entry populated.
//
// Parameters (DOS push order â rightmost pushed first):
-// voiceList â array of speech/data indices (speechList or messageList4)
-// msgList â array of dialog text indices (messageList1 or messageList2)
-// convData â active ConvData
// convIn â active Conv
+// convData â active ConvData
+// msgList â array of dialog text indices (messageList1 or messageList2)
// msgListSize â number of valid entries in msgList (in ax)
+// voiceList â array of speech/data indices (speechList1 or speechList2)
// voiceListSize â number of valid entries in voiceList (in dx)
// ---------------------------------------------------------------------------
-static void conv_generate_message(int16 *voiceList, int16 *msgList,
- ConvData *convData, Conv *convIn,
- int msgListSize, int voiceListSize) {
+static void conv_generate_message(Conv *convIn, ConvData *convData,
+ int16 *msgList, int msgListSize, int16 *voiceList, int voiceListSize) {
Box *priorBox = box;
box = &conv_box;
conv_control.has_text = 0;
@@ -1434,13 +1433,13 @@ void conv_update(bool flag) {
// populated via conv_message).
int16 speech_idx = my_conv->dialogs[conv_control.entry].speech_index;
if (speech_idx) {
- my_conv_data->speechList[0] = speech_idx;
- my_conv_data->speechListSize = 1;
+ my_conv_data->speechList1[0] = speech_idx;
+ my_conv_data->speechList1Size = 1;
}
- conv_generate_text(my_conv_data->speechList, my_conv_data, my_conv,
- my_conv->dialogs[conv_control.entry].text_line_index,
- my_conv_data->speechListSize);
+ conv_generate_text(my_conv, my_conv_data,
+ my_conv->dialogs[conv_control.entry].text_line_index,
+ my_conv_data->speechList1, my_conv_data->speechList1Size);
conv_control.status = CONV_STATUS_REPLY;
@@ -1466,11 +1465,9 @@ void conv_update(bool flag) {
conv_execute_entry(conv_control.entry);
- conv_generate_message(my_conv_data->speechList,
- my_conv_data->messageList1,
- my_conv_data, my_conv,
- my_conv_data->messageList1_size,
- my_conv_data->speechListSize);
+ conv_generate_message(my_conv, my_conv_data,
+ my_conv_data->messageList1, my_conv_data->messageList1Size,
+ my_conv_data->speechList1, my_conv_data->speechList1Size);
// Fire me_trigger if one is pending and a popup is visible.
if (conv_control.me_trigger && conv_control.popup_is_up) {
@@ -1494,11 +1491,9 @@ void conv_update(bool flag) {
conv_purge_any_popup();
conv_control.person_speaking = conv_control.speaker_val;
- conv_generate_message(my_conv_data->messageList4,
- my_conv_data->messageList2,
- my_conv_data, my_conv,
- my_conv_data->messageList2_size,
- my_conv_data->messageList4_size);
+ conv_generate_message(my_conv, my_conv_data,
+ my_conv_data->messageList2, my_conv_data->messageList2Size,
+ my_conv_data->speechList2, my_conv_data->speechList2Size);
conv_control.status = CONV_STATUS_NEXT_NODE;
@@ -1519,9 +1514,35 @@ void conv_update(bool flag) {
}
void conv_regenerate_last_message() {
+ if (conv_control.running && conv_control.popup_is_up) {
+ Conv &c = *conv[conv_control.index];
+ ConvData &cd = *conv_data[conv_control.index];
+
+ conv_purge_any_popup();
+
+ if (conv_control.has_text) {
+ conv_generate_text(&c, &cd, c.dialogs[conv_control.entry].text_line_index,
+ cd.speechList1, cd.speechList1Size);
+ } else if (conv_control.person_speaking) {
+ conv_generate_message(&c, &cd, cd.messageList2, cd.messageList2Size,
+ cd.speechList2, cd.speechList2Size);
+ } else {
+
+ }
+ }
}
-void conv_export_pointer(int *ptr) {}
+void conv_export_pointer(int16 *ptr) {
+ if (conv_control.running) {
+ Conv &c = *conv[conv_control.index];
+ ConvData &cd = *conv_data[conv_control.index];
+
+ if (cd.numImports < c.max_imports) {
+ int idx = conv_imports[cd.numImports++];
+ conv_set_variable(idx, ptr);
+ }
+ }
+}
void conv_abort() {
if (conv_control.running >= 0) {
@@ -1543,9 +1564,15 @@ void conv_abort() {
}
}
-void conv_me_trigger(int trigger) {}
+void conv_me_trigger(int trigger) {
+ conv_control.me_trigger = trigger;
+ conv_control.me_trigger_mode = kernel.trigger_setup_mode;
+}
-void conv_you_trigger(int trigger) {}
+void conv_you_trigger(int trigger) {
+ conv_control.you_trigger = trigger;
+ conv_control.you_trigger_mode = kernel.trigger_setup_mode;
+}
int16 *conv_get_variable(int varNum) {
assert(varNum >= 0 && varNum < active_conv_data->variablesCount);
@@ -1603,6 +1630,5 @@ int conv_expand(Common::SeekableReadStream *handle) {
return 0;
}
-
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/core/conv.h b/engines/mads/madsv2/core/conv.h
index 3e0e3dad4c9..ffd121cdd49 100644
--- a/engines/mads/madsv2/core/conv.h
+++ b/engines/mads/madsv2/core/conv.h
@@ -166,15 +166,15 @@ struct ConvDataBase {
int16 importsCount;
int16 numImports;
int16 optionListSize;
- int16 messageList1_size;
- int16 messageList2_size;
- int16 speechListSize;
- int16 messageList4_size;
+ int16 messageList1Size;
+ int16 messageList2Size;
+ int16 speechList1Size;
+ int16 speechList2Size;
int16 optionList[10];
int16 messageList1[10];
int16 messageList2[10];
- int16 speechList[10];
- int16 messageList4[10];
+ int16 speechList1[10];
+ int16 speechList2[10];
};
struct ConvDataHeader : public ConvDataBase {
@@ -254,7 +254,7 @@ extern void conv_get(int convNum);
extern void conv_run(int convNum);
extern void conv_update(bool);
extern void conv_regenerate_last_message();
-extern void conv_export_pointer(int *ptr);
+extern void conv_export_pointer(int16 *ptr);
extern void conv_abort();
extern void conv_me_trigger(int trigger);
extern void conv_you_trigger(int trigger);
diff --git a/engines/mads/madsv2/core/game.cpp b/engines/mads/madsv2/core/game.cpp
index a7ae00d94ef..8eead8a020f 100644
--- a/engines/mads/madsv2/core/game.cpp
+++ b/engines/mads/madsv2/core/game.cpp
@@ -545,11 +545,11 @@ static void game_player_status() {
int game_parse_keystroke(int mykey) {
int count;
- int temp;
+ int16 temp;
long big_temp;
- int move_object;
- int move_target;
- int change_flag;
+ int16 move_object;
+ int16 move_target;
+ int16 change_flag;
int current_mode;
int num;
int unpause = 0;
diff --git a/engines/mads/madsv2/core/global.cpp b/engines/mads/madsv2/core/global.cpp
index 6f578be1d4e..9d62c53d971 100644
--- a/engines/mads/madsv2/core/global.cpp
+++ b/engines/mads/madsv2/core/global.cpp
@@ -27,7 +27,7 @@
namespace MADS {
namespace MADSV2 {
-int global[GLOBAL_LIST_SIZE];
+int16 global[GLOBAL_LIST_SIZE];
int global_list_size = GLOBAL_LIST_SIZE;
char global_release_name[] = { "ScummVM" };
diff --git a/engines/mads/madsv2/core/global.h b/engines/mads/madsv2/core/global.h
index 6f58a47c5c7..31ab2e15859 100644
--- a/engines/mads/madsv2/core/global.h
+++ b/engines/mads/madsv2/core/global.h
@@ -106,7 +106,7 @@ extern char global_release_version[];
extern char global_release_date[];
extern char global_release_copyright[];
-extern int global[];
+extern int16 global[];
extern int global_list_size;
void global_init_code(void);
diff --git a/engines/mads/madsv2/core/kernel.cpp b/engines/mads/madsv2/core/kernel.cpp
index 95f2751cc49..7dce9c9e8c8 100644
--- a/engines/mads/madsv2/core/kernel.cpp
+++ b/engines/mads/madsv2/core/kernel.cpp
@@ -78,11 +78,11 @@ int room_id = KERNEL_STARTING_GAME;
int section_id = KERNEL_STARTING_GAME;
int room_variant = 0;
-int new_room = 101;
-int new_section = 1;
+int16 new_room = 101;
+int16 new_section = 1;
-int previous_room = 0;
-int previous_section = 0;
+int16 previous_room = 0;
+int16 previous_section = 0;
int kernel_initial_variant = 0;
diff --git a/engines/mads/madsv2/core/kernel.h b/engines/mads/madsv2/core/kernel.h
index 26e046702e7..7506aeaca85 100644
--- a/engines/mads/madsv2/core/kernel.h
+++ b/engines/mads/madsv2/core/kernel.h
@@ -339,11 +339,11 @@ extern int room_id; /* Current room # */
extern int section_id; /* Current section # */
extern int room_variant; /* Current room attribute variant */
-extern int new_room; /* New room # to enter */
-extern int new_section; /* New section # to enter */
+extern int16 new_room; /* New room # to enter */
+extern int16 new_section; /* New section # to enter */
-extern int previous_room; /* Last room # */
-extern int previous_section; /* Last section # */
+extern int16 previous_room; /* Last room # */
+extern int16 previous_section; /* Last section # */
extern int kernel_initial_variant; /* Initial variant to load */
diff --git a/engines/mads/madsv2/core/popup.cpp b/engines/mads/madsv2/core/popup.cpp
index 40519e31ff6..4659095ac1d 100644
--- a/engines/mads/madsv2/core/popup.cpp
+++ b/engines/mads/madsv2/core/popup.cpp
@@ -1098,7 +1098,7 @@ int popup_get_long(long *value, const char *top, const char *left, int maxlen) {
}
-int popup_get_number(int *value, const char *top, const char *left, int maxlen) {
+int popup_get_number(int16 *value, const char *top, const char *left, int maxlen) {
int result;
long temp;
diff --git a/engines/mads/madsv2/core/popup.h b/engines/mads/madsv2/core/popup.h
index fae58d924be..acc4ecfcdbc 100644
--- a/engines/mads/madsv2/core/popup.h
+++ b/engines/mads/madsv2/core/popup.h
@@ -440,7 +440,7 @@ int popup_ask_number(long *value, int maxlen, int save_screen);
int popup_estimate_pieces(int maxlen);
int popup_get_string(char *target, const char *top, const char *left, int maxlen);
int popup_get_long(long *value, const char *top, const char *left, int maxlen);
-int popup_get_number(int *value, const char *top, const char *left, int maxlen);
+int popup_get_number(int16 *value, const char *top, const char *left, int maxlen);
/* popup_3.c */
int popup_alert(int width, const char *message_line, ...);
diff --git a/engines/mads/madsv2/core/text.cpp b/engines/mads/madsv2/core/text.cpp
index 49356925341..9125b99400c 100644
--- a/engines/mads/madsv2/core/text.cpp
+++ b/engines/mads/madsv2/core/text.cpp
@@ -91,7 +91,7 @@ char text_command_subject[8] = TEXT_COMMAND_SUBJECT;
char text_command_custom[7] = TEXT_COMMAND_CUSTOM;
char text_command_demonstrative[14] = TEXT_COMMAND_DEMONSTRATIVE;
-extern int global[GLOBAL_LIST_SIZE];
+extern int16 global[GLOBAL_LIST_SIZE];
TextPtr text_load(long id, int mode) {
Commit: 3e63834f601b0aef9819192c3821e9ceac183912
https://github.com/scummvm/scummvm/commit/3e63834f601b0aef9819192c3821e9ceac183912
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:11+10:00
Commit Message:
MADS: PHANTOM: Conv reading/writing
Changed paths:
engines/mads/madsv2/core/conv.cpp
engines/mads/madsv2/core/conv.h
diff --git a/engines/mads/madsv2/core/conv.cpp b/engines/mads/madsv2/core/conv.cpp
index b02026207a1..5151ec8a625 100644
--- a/engines/mads/madsv2/core/conv.cpp
+++ b/engines/mads/madsv2/core/conv.cpp
@@ -108,6 +108,13 @@ void ConvVariable::load(Common::SeekableReadStream *src) {
(void)src->readUint16LE(); // skip space for pointer segments
}
+void ConvVariable::save(Common::WriteStream *dest) const {
+ assert(!isPtr);
+ dest->writeSint16LE(0);
+ dest->writeSint16LE(val);
+ dest->writeSint16LE(0);
+}
+
void ConvDataHeader::load(Common::SeekableReadStream *src) {
src->readMultipleLE(currentNode, entryFlagsCount, variablesCount,
importsCount, numImports, optionListSize,
@@ -120,6 +127,72 @@ void ConvDataHeader::load(Common::SeekableReadStream *src) {
src->readMultipleLE(importsOffset, entryFlagsOffset, variablesOffset);
}
+void ConvDataHeader::save(Common::WriteStream *dest) const {
+ dest->writeMultipleLE(currentNode, entryFlagsCount, variablesCount,
+ importsCount, numImports, optionListSize,
+ messageList1Size, messageList2Size, speechList1Size, speechList2Size);
+ dest->writeMultipleLE(optionList);
+ dest->writeMultipleLE(messageList1);
+ dest->writeMultipleLE(messageList2);
+ dest->writeMultipleLE(speechList1);
+ dest->writeMultipleLE(speechList2);
+ dest->writeMultipleLE(importsOffset, entryFlagsOffset, variablesOffset);
+}
+
+void ConvData::load(Common::SeekableReadStream *src) {
+ size_t startPos = src->pos();
+
+ // Load the header
+ ConvDataHeader header;
+ header.load(src);
+
+ // Copy header fields in
+ *this = header;
+
+ // Imports: conditional â the original skips the loader_read when count <= 0
+ if (header.importsCount > 0) {
+ assert((src->pos() - startPos) == header.importsOffset);
+ imports.resize(header.importsCount);
+ for (int i = 0; i < header.importsCount; ++i)
+ imports[i] = src->readSint16LE();
+ }
+
+ if (header.entryFlagsCount > 0) {
+ assert((src->pos() - startPos) == header.entryFlagsOffset);
+ entryFlags.resize(header.entryFlagsCount);
+ for (int i = 0; i < header.entryFlagsCount; ++i)
+ entryFlags[i] = src->readUint16LE();
+ }
+
+ if (header.variablesCount > 0) {
+ assert((src->pos() - startPos) == header.entryFlagsOffset);
+ variables.resize(header.entryFlagsCount);
+ for (int i = 0; i < header.entryFlagsCount; ++i) {
+ variables[i].load(src);
+ }
+ }
+}
+
+void ConvData::save(Common::WriteStream *dest) const {
+ // Save the header
+ ConvDataHeader header;
+ header = *this;
+ header.importsOffset = ConvDataHeader::SIZE;
+ header.entryFlagsOffset = header.importsOffset + (importsCount * 2);
+ header.variablesOffset = header.entryFlagsOffset + (entryFlagsCount * 2);
+
+ header.save(dest);
+
+ for (int i = 0; i < header.importsCount; ++i)
+ dest->writeSint16LE(imports[i]);
+
+ for (int i = 0; i < header.entryFlagsCount; ++i)
+ dest->writeSint16LE(entryFlags[i]);
+
+ for (int i = 0; i < header.entryFlagsCount; ++i)
+ variables[i].save(dest);
+}
+
// ====================================================================
// Static helpers (ordered so no forward declarations are needed)
@@ -447,47 +520,15 @@ done:
return result;
}
-static ConvData *read_conv_data(Common::SeekableReadStream *src) {
- ConvDataHeader header;
- ConvData *dataPtr = nullptr;
- ConvData *result = nullptr;
-
- // Load the header
- header.load(src);
-
- dataPtr = new ConvData();
- if (!dataPtr)
- goto done;
-
- *dataPtr = header;
-
- // Imports: conditional â the original skips the loader_read when count <= 0
- if (header.importsCount > 0) {
- dataPtr->imports.resize(header.importsCount);
- for (int i = 0; i < header.importsCount; ++i)
- dataPtr->imports[i] = src->readSint16LE();
- }
-
- if (header.entryFlagsCount > 0) {
- dataPtr->entryFlags.resize(header.entryFlagsCount);
- for (int i = 0; i < header.entryFlagsCount; ++i)
- dataPtr->entryFlags[i] = src->readUint16LE();
- }
-
- if (header.variablesCount > 0) {
- dataPtr->variables.resize(header.entryFlagsCount);
- for (int i = 0; i < header.entryFlagsCount; ++i) {
- dataPtr->variables[i].load(src);
- }
- }
-
- result = dataPtr;
-
-done:
- if (dataPtr && dataPtr != result)
- delete dataPtr;
+static ConvData *conv_read(Common::SeekableReadStream *src) {
+ ConvData *cd = new ConvData();
+ cd->load(src);
+ return cd;
+}
- return result;
+static int conv_write(Common::WriteStream *dest, const ConvData *convData) {
+ convData->save(dest);
+ return 0;
}
static void conv_init(ConvData *convData, int val) {
@@ -509,7 +550,7 @@ static ConvData *conv_get_data(int convNum) {
if (conv_indexes[convNum]) {
Common::SeekableReadStream *handle = conv_open(convNum);
if (handle) {
- convData = read_conv_data(handle);
+ convData = conv_read(handle);
delete handle;
}
} else {
@@ -1611,22 +1652,117 @@ void conv_release() {
}
void conv_flush() {
-/*
bool errorFlag = true;
int errCode = 0;
+ Common::WriteStream *dest;
+ int i;
+
+ for (i = 0; i < CONV_MAX_SLOTS; ++i) {
+ if (conv_indexes[i] >= 2) {
+ dest = conv_open_write(i);
+ if (!dest)
+ goto done;
+
+ ConvData *convData = conv_data[conv_indexes[i] - 2];
+ errCode = conv_write(dest, convData);
+ if (errCode) {
+ delete dest;
+ goto done;
+ }
+ }
+ }
+
+ for (i = CONV_MAX_DATA - 1; i >= 0; --i) {
+ if (conv_slots[i]) {
+ delete conv_data[i];
+ delete conv[i];
+ conv_data[i] = nullptr;
+ conv[i] = nullptr;
+ conv_slots[i] = 0;
+ }
+ }
- for (int i = 0; i < CONV_MAX_SLOTS; ++i) {
- // TODO
- }*/
+ errorFlag = false;
+done:
+ if (errorFlag)
+ error("Error flushing conversation data");
}
int conv_append(Common::WriteStream *handle) {
- error("TODO: conv_append");
+ int count = 0;
+ int16 list[CONV_MAX_SLOTS];
+ ConvData *convData;
+ int convNum, convIndex;
+ int i, errCode;
+
+ // Generate a list of conv_indexes that are present
+ for (i = 0; i < CONV_MAX_SLOTS; ++i) {
+ if (conv_indexes[i])
+ list[count++] = i;
+ }
+
+ // Write out count and list
+ handle->writeUint16LE(count);
+ for (i = 0; i < count; ++i)
+ handle->writeSint16LE(list[i]);
+
+ for (i = 0; i < count; ++i) {
+ convNum = list[i];
+ convIndex = conv_indexes[convNum];
+
+ if (convIndex == 1) {
+ convData = conv_get_data(convNum);
+ if (!convData)
+ break;
+
+ errCode = conv_write(handle, convData);
+ delete convData;
+ } else {
+ convData = conv_data[convIndex - 2];
+ errCode = conv_write(handle, convData);
+ }
+
+ if (errCode)
+ break;
+ }
+
return 0;
}
int conv_expand(Common::SeekableReadStream *handle) {
- error("TODO: conv_expand");
+ int count;
+ int16 list[CONV_MAX_SLOTS];
+ ConvData *convData;
+
+ Common::fill(conv_indexes, conv_indexes + CONV_MAX_SLOTS, 0);
+
+ // Read count and list
+ count = handle->readUint16LE();
+ handle->readMultipleLE(list);
+
+ for (int i = 0; i < count; ++i) {
+ int index = list[i];
+ conv_indexes[index] = 1;
+
+ // Open a temporary file for the conversation
+ Common::WriteStream *dest = conv_open_write(index);
+ if (!dest)
+ break;
+
+ // Read it's data from the savegame
+ convData = conv_read(handle);
+
+ // Write it out to the temporary file
+ bool success = false;
+ if (convData)
+ success = !conv_write(dest, convData);
+
+ if (!success) {
+ delete convData;
+ break;
+ }
+ }
+
return 0;
}
diff --git a/engines/mads/madsv2/core/conv.h b/engines/mads/madsv2/core/conv.h
index ffd121cdd49..4a33b1f556d 100644
--- a/engines/mads/madsv2/core/conv.h
+++ b/engines/mads/madsv2/core/conv.h
@@ -102,6 +102,7 @@ struct ConvVariable {
static constexpr int SIZE = 2 * 3;
void load(Common::SeekableReadStream *src);
+ void save(Common::WriteStream *dest) const;
};
struct ConvBase {
@@ -182,12 +183,19 @@ struct ConvDataHeader : public ConvDataBase {
int16 entryFlagsOffset;
int16 variablesOffset;
+ ConvDataHeader &operator=(const ConvDataBase &src) {
+ *((ConvDataBase *)this) = src;
+ importsOffset = entryFlagsOffset = variablesOffset = 0;
+ return *this;
+ }
+
// On-disk size: 10 header words + 5 arrays of 10 words + 3 offset words
// = 20 + 100 + 6 = 126 = 0x7E. The +21 padding in load_conv_data
// exploits the fact that 21 * 6 = 126, so the formula automatically
// includes the header in the total allocation.
static constexpr int SIZE = 2 * 10 + 2 * 10 * 5 + 2 * 3;
void load(Common::SeekableReadStream *src);
+ void save(Common::WriteStream *dest) const;
};
struct ConvData : public ConvDataBase {
@@ -202,6 +210,9 @@ struct ConvData : public ConvDataBase {
Common::Array<int16> imports;
Common::Array<uint16> entryFlags;
Common::Array<ConvVariable> variables;
+
+ void load(Common::SeekableReadStream *src);
+ void save(Common::WriteStream *dest) const;
};
struct ConvControl {
Commit: 569407b1a24e78daf3a6e732e32a72e9eb30a2b9
https://github.com/scummvm/scummvm/commit/569407b1a24e78daf3a6e732e32a72e9eb30a2b9
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:11+10:00
Commit Message:
MADS: PHANTOM: Conv opening fixes
Changed paths:
engines/mads/madsv2/core/conv.cpp
engines/mads/madsv2/core/conv.h
diff --git a/engines/mads/madsv2/core/conv.cpp b/engines/mads/madsv2/core/conv.cpp
index 5151ec8a625..8571f64d3d3 100644
--- a/engines/mads/madsv2/core/conv.cpp
+++ b/engines/mads/madsv2/core/conv.cpp
@@ -64,7 +64,7 @@ Common::HashMap<Common::String, MemoryWriteStreamDynamic,
Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> *savedConv;
static int conv_indexes[CONV_MAX_SLOTS];
-static int conv_slots[CONV_MAX_DATA];
+static bool conv_slots[CONV_MAX_DATA];
// ====================================================================
@@ -84,6 +84,8 @@ void ConvHeader::load(Common::SeekableReadStream *src) {
// Read in the offsets
src->readMultipleLE(textOffset, scriptsOffset, nodesOffset,
dialogsOffset, messagesOffset, textLinesOffset);
+ warning("pos = %d", src->pos());
+ assert(src->pos() == SIZE);
}
void ConvNode::load(Common::SeekableReadStream *src) {
@@ -204,7 +206,7 @@ static const char *conv_get_filename(int convNum, int extType, char *name) {
if (extType != 2)
Common::strcat_s(name, 40, "*");
Common::strcat_s(name, 40, "conv");
- Common::strcat_s(name, 40, Common::String::format("%d", convNum).c_str());
+ Common::strcat_s(name, 40, Common::String::format("%.3d", convNum).c_str());
if (extType == 2)
Common::strcat_s(name, 40, ".dat");
@@ -285,17 +287,12 @@ static Conv *load_conv(const char *fname) {
Conv *dataPtr = nullptr;
Conv *result = nullptr;
char filename[80];
- char name_buf[9];
file.open = false;
Common::strcpy_s(filename, fname);
fileio_add_ext(filename, "cnv");
- // Strip leading '*' (wildcard prefix used for himem search) to get bare name
- const char *fn = (filename[0] == '*') ? filename + 1 : filename;
- Common::strlcpy(name_buf, fn, sizeof(name_buf));
-
if (loader_open(&file, filename, "rb", true)) {
conv_error_code = 1;
goto done;
@@ -1152,7 +1149,7 @@ void conv_system_init() {
conv_control.running = -1;
Common::fill(conv_indexes, conv_indexes + CONV_MAX_SLOTS, 0);
- Common::fill(conv_slots, conv_slots + CONV_MAX_DATA, 0);
+ Common::fill(conv_slots, conv_slots + CONV_MAX_DATA, false);
Common::fill(conv, conv + CONV_MAX_DATA, (Conv *)nullptr);
Common::fill(conv_data, conv_data + CONV_MAX_DATA, (ConvData *)nullptr);
@@ -1207,7 +1204,7 @@ void conv_get(int convNum) {
goto report;
}
- conv_slots[free_slot] = 0xFF;
+ conv_slots[free_slot] = true;
conv[free_slot] = load_conv(conv_get_filename(convNum, 0, fname));
if (!conv[free_slot]) {
@@ -1678,7 +1675,7 @@ void conv_flush() {
delete conv[i];
conv_data[i] = nullptr;
conv[i] = nullptr;
- conv_slots[i] = 0;
+ conv_slots[i] = false;
}
}
diff --git a/engines/mads/madsv2/core/conv.h b/engines/mads/madsv2/core/conv.h
index 4a33b1f556d..b7535515ae4 100644
--- a/engines/mads/madsv2/core/conv.h
+++ b/engines/mads/madsv2/core/conv.h
@@ -118,20 +118,18 @@ struct ConvBase {
int16 speaker_frame[5];
char speech_file[14];
uint32 text_length;
-
uint32 commands_length;
-
- static constexpr int SIZE = 2 * 7 + 16 * 5 + 2 * 5 + 14 + 4 + 4 + 4 * 6;
};
struct ConvHeader : public ConvBase {
- int textOffset;
- int scriptsOffset;
- int nodesOffset;
- int dialogsOffset;
- int messagesOffset;
- int textLinesOffset;
-
+ uint32 textOffset;
+ uint32 scriptsOffset;
+ uint32 nodesOffset;
+ uint32 dialogsOffset;
+ uint32 messagesOffset;
+ uint32 textLinesOffset;
+
+ static constexpr int SIZE = (2 * 7 + 16 * 5 + 2 * 5 + 14 + 4 + 4) + 4 * 6;
void load(Common::SeekableReadStream *src);
};
Commit: f8c27b550a6461f95931ad9ad212ea8d254afbcb
https://github.com/scummvm/scummvm/commit/f8c27b550a6461f95931ad9ad212ea8d254afbcb
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:11+10:00
Commit Message:
MADS: PHANTOM: Conv data structure loading fixes
Changed paths:
engines/mads/madsv2/core/conv.cpp
engines/mads/madsv2/core/conv.h
diff --git a/engines/mads/madsv2/core/conv.cpp b/engines/mads/madsv2/core/conv.cpp
index 8571f64d3d3..10f3e32b5ce 100644
--- a/engines/mads/madsv2/core/conv.cpp
+++ b/engines/mads/madsv2/core/conv.cpp
@@ -71,7 +71,7 @@ static bool conv_slots[CONV_MAX_DATA];
// Struct serialization methods
// ====================================================================
-void ConvHeader::load(Common::SeekableReadStream *src) {
+void Conv::load(Common::SeekableReadStream *src) {
src->readMultipleLE(node_count, dialog_count, message_count, text_line_count,
num_variables, max_imports, speaker_count);
for (int i = 0; i < 5; ++i)
@@ -81,11 +81,15 @@ void ConvHeader::load(Common::SeekableReadStream *src) {
src->read(speech_file, 14);
src->readMultipleLE(text_length, commands_length);
- // Read in the offsets
- src->readMultipleLE(textOffset, scriptsOffset, nodesOffset,
- dialogsOffset, messagesOffset, textLinesOffset);
- warning("pos = %d", src->pos());
- assert(src->pos() == SIZE);
+ // Skip over original padding for pointer fields
+ src->skip(6 * sizeof(uint32));
+
+ nodes.clear();
+ dialogs.clear();
+ messages.clear();
+ text.clear();
+ scripts.clear();
+ textLines.clear();
}
void ConvNode::load(Common::SeekableReadStream *src) {
@@ -283,7 +287,6 @@ static void conv_set_variable(int idx, int16 val) {
static Conv *load_conv(const char *fname) {
Load file;
- ConvHeader convHeader;
Conv *dataPtr = nullptr;
Conv *result = nullptr;
char filename[80];
@@ -298,42 +301,35 @@ static Conv *load_conv(const char *fname) {
goto done;
}
+ dataPtr = new Conv();
+
{
// Read the fixed-size Conv header through a MemoryReadStream so that
// the load() function handles field sizes and endianness correctly.
- byte hdrBuf[ConvHeader::SIZE];
- if (!loader_read(hdrBuf, ConvHeader::SIZE, 1, &file)) {
+ byte hdrBuf[Conv::SIZE];
+ if (!loader_read(hdrBuf, Conv::SIZE, 1, &file)) {
conv_error_code = 2;
goto done;
}
- Common::MemoryReadStream hdrStream(hdrBuf, ConvHeader::SIZE);
- convHeader.load(&hdrStream);
- }
-
- dataPtr = new Conv();
- if (!dataPtr) {
- conv_error_code = 3;
- goto done;
+ Common::MemoryReadStream hdrStream(hdrBuf, Conv::SIZE);
+ dataPtr->load(&hdrStream);
}
- // Copy the loaded header to the front of the block
- *dataPtr = convHeader;
-
// Read each section from the file. Error codes deliberately match the
// originals (note: 6 is skipped, matching the disassembly).
// Nodes
{
byte *buffer = (byte *)malloc(dataPtr->node_count * ConvNode::SIZE);
- if (!loader_read(buffer, convHeader.node_count * ConvNode::SIZE, 1, &file)) {
+ if (!loader_read(buffer, dataPtr->node_count * ConvNode::SIZE, 1, &file)) {
conv_error_code = 4;
free(buffer);
goto done;
}
- Common::MemoryReadStream src(buffer, convHeader.node_count * ConvNode::SIZE);
- dataPtr->nodes.resize(convHeader.node_count);
- for (int i = 0; i < convHeader.node_count; ++i)
+ Common::MemoryReadStream src(buffer, dataPtr->node_count * ConvNode::SIZE);
+ dataPtr->nodes.resize(dataPtr->node_count);
+ for (int i = 0; i < dataPtr->node_count; ++i)
dataPtr->nodes[i].load(&src);
free(buffer);
@@ -342,15 +338,15 @@ static Conv *load_conv(const char *fname) {
// Dialogs
{
byte *buffer = (byte *)malloc(dataPtr->dialog_count * ConvDialog::SIZE);
- if (!loader_read(buffer, convHeader.dialog_count * ConvDialog::SIZE, 1, &file)) {
+ if (!loader_read(buffer, dataPtr->dialog_count * ConvDialog::SIZE, 1, &file)) {
conv_error_code = 5;
free(buffer);
goto done;
}
- Common::MemoryReadStream src(buffer, convHeader.dialog_count * ConvDialog::SIZE);
- dataPtr->dialogs.resize(convHeader.dialog_count);
- for (int i = 0; i < convHeader.dialog_count; ++i)
+ Common::MemoryReadStream src(buffer, dataPtr->dialog_count * ConvDialog::SIZE);
+ dataPtr->dialogs.resize(dataPtr->dialog_count);
+ for (int i = 0; i < dataPtr->dialog_count; ++i)
dataPtr->dialogs[i].load(&src);
free(buffer);
@@ -359,15 +355,15 @@ static Conv *load_conv(const char *fname) {
// Messages
{
byte *buffer = (byte *)malloc(dataPtr->message_count * 4);
- if (!loader_read(buffer, convHeader.message_count * 4, 1, &file)) {
+ if (!loader_read(buffer, dataPtr->message_count * 4, 1, &file)) {
conv_error_code = 7;
free(buffer);
goto done;
}
- Common::MemoryReadStream src(buffer, convHeader.message_count * 4);
- dataPtr->messages.resize(convHeader.message_count);
- for (int i = 0; i < convHeader.message_count; ++i) {
+ Common::MemoryReadStream src(buffer, dataPtr->message_count * 4);
+ dataPtr->messages.resize(dataPtr->message_count);
+ for (int i = 0; i < dataPtr->message_count; ++i) {
dataPtr->messages[i].lineStart = src.readSint16LE();
dataPtr->messages[i].lineCount = src.readSint16LE();
}
@@ -378,15 +374,15 @@ static Conv *load_conv(const char *fname) {
// Text lines
{
byte *buffer = (byte *)malloc(dataPtr->text_line_count * 2);
- if (!loader_read(buffer, convHeader.text_line_count * 2, 1, &file)) {
+ if (!loader_read(buffer, dataPtr->text_line_count * 2, 1, &file)) {
conv_error_code = 8;
free(buffer);
goto done;
}
- Common::MemoryReadStream src(buffer, convHeader.text_line_count * 2);
- dataPtr->textLines.resize(convHeader.text_line_count);
- for (int i = 0; i < convHeader.text_line_count; ++i)
+ Common::MemoryReadStream src(buffer, dataPtr->text_line_count * 2);
+ dataPtr->textLines.resize(dataPtr->text_line_count);
+ for (int i = 0; i < dataPtr->text_line_count; ++i)
dataPtr->textLines[i] = src.readUint16LE();
free(buffer);
@@ -394,8 +390,8 @@ static Conv *load_conv(const char *fname) {
// Text block
{
- dataPtr->text.resize(convHeader.text_length);
- if (!loader_read(&dataPtr->text[0], convHeader.text_length, 1, &file)) {
+ dataPtr->text.resize(dataPtr->text_length);
+ if (!loader_read(&dataPtr->text[0], dataPtr->text_length, 1, &file)) {
conv_error_code = 9;
goto done;
}
@@ -403,8 +399,8 @@ static Conv *load_conv(const char *fname) {
// Scripts
{
- dataPtr->scripts.resize(convHeader.commands_length);
- if (!loader_read(&dataPtr->scripts[0], convHeader.commands_length, 1, &file)) {
+ dataPtr->scripts.resize(dataPtr->commands_length);
+ if (!loader_read(&dataPtr->scripts[0], dataPtr->commands_length, 1, &file)) {
conv_error_code = 10;
goto done;
}
diff --git a/engines/mads/madsv2/core/conv.h b/engines/mads/madsv2/core/conv.h
index b7535515ae4..f0327a4be38 100644
--- a/engines/mads/madsv2/core/conv.h
+++ b/engines/mads/madsv2/core/conv.h
@@ -105,7 +105,7 @@ struct ConvVariable {
void save(Common::WriteStream *dest) const;
};
-struct ConvBase {
+struct Conv {
int16 node_count;
int16 dialog_count;
int16 message_count;
@@ -119,31 +119,6 @@ struct ConvBase {
char speech_file[14];
uint32 text_length;
uint32 commands_length;
-};
-
-struct ConvHeader : public ConvBase {
- uint32 textOffset;
- uint32 scriptsOffset;
- uint32 nodesOffset;
- uint32 dialogsOffset;
- uint32 messagesOffset;
- uint32 textLinesOffset;
-
- static constexpr int SIZE = (2 * 7 + 16 * 5 + 2 * 5 + 14 + 4 + 4) + 4 * 6;
- void load(Common::SeekableReadStream *src);
-};
-
-struct Conv : public ConvBase {
- Conv &operator=(const ConvBase &src) {
- *((ConvBase *)this) = src;
- text.clear();
- scripts.clear();
- nodes.clear();
- dialogs.clear();
- messages.clear();
- textLines.clear();
- return *this;
- }
struct LineSet {
int lineStart = 0;
@@ -156,6 +131,11 @@ struct Conv : public ConvBase {
Common::Array<char> text;
Common::Array<uint16> scripts;
Common::Array<uint16> textLines;
+
+ static constexpr int SIZE = (2 * 7 + 16 * 5 + 2 * 5 + 14 + 4 + 4) +
+ // Padding for pointers in original structure
+ 4 * 6;
+ void load(Common::SeekableReadStream *src);
};
struct ConvDataBase {
Commit: 86bd5391a0d177171c36b81519564da536464c46
https://github.com/scummvm/scummvm/commit/86bd5391a0d177171c36b81519564da536464c46
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:12+10:00
Commit Message:
MADS: PHANTOM: Fix loading conv data
Changed paths:
engines/mads/madsv2/core/conv.cpp
engines/mads/madsv2/core/conv.h
engines/mads/madsv2/core/loader.cpp
engines/mads/madsv2/core/loader.h
diff --git a/engines/mads/madsv2/core/conv.cpp b/engines/mads/madsv2/core/conv.cpp
index 10f3e32b5ce..7ed670b28d1 100644
--- a/engines/mads/madsv2/core/conv.cpp
+++ b/engines/mads/madsv2/core/conv.cpp
@@ -121,81 +121,87 @@ void ConvVariable::save(Common::WriteStream *dest) const {
dest->writeSint16LE(0);
}
-void ConvDataHeader::load(Common::SeekableReadStream *src) {
- src->readMultipleLE(currentNode, entryFlagsCount, variablesCount,
- importsCount, numImports, optionListSize,
- messageList1Size, messageList2Size, speechList1Size, speechList2Size);
- src->readMultipleLE(optionList);
- src->readMultipleLE(messageList1);
- src->readMultipleLE(messageList2);
- src->readMultipleLE(speechList1);
- src->readMultipleLE(speechList2);
- src->readMultipleLE(importsOffset, entryFlagsOffset, variablesOffset);
-}
-
-void ConvDataHeader::save(Common::WriteStream *dest) const {
- dest->writeMultipleLE(currentNode, entryFlagsCount, variablesCount,
- importsCount, numImports, optionListSize,
- messageList1Size, messageList2Size, speechList1Size, speechList2Size);
- dest->writeMultipleLE(optionList);
- dest->writeMultipleLE(messageList1);
- dest->writeMultipleLE(messageList2);
- dest->writeMultipleLE(speechList1);
- dest->writeMultipleLE(speechList2);
- dest->writeMultipleLE(importsOffset, entryFlagsOffset, variablesOffset);
-}
-
void ConvData::load(Common::SeekableReadStream *src) {
- size_t startPos = src->pos();
-
- // Load the header
- ConvDataHeader header;
- header.load(src);
+ {
+ byte buffer[SIZE];
+ if (!src->read(buffer, SIZE))
+ return;
- // Copy header fields in
- *this = header;
+ Common::MemoryReadStream mrs(buffer, SIZE);
+ mrs.readMultipleLE(currentNode, entryFlagsCount, variablesCount,
+ importsCount, numImports, optionListSize,
+ messageList1Size, messageList2Size, speechList1Size, speechList2Size);
+ mrs.readMultipleLE(optionList);
+ mrs.readMultipleLE(messageList1);
+ mrs.readMultipleLE(messageList2);
+ mrs.readMultipleLE(speechList1);
+ mrs.readMultipleLE(speechList2);
+ mrs.readMultipleLE(importsOffset, entryFlagsOffset, variablesOffset);
+ }
// Imports: conditional â the original skips the loader_read when count <= 0
- if (header.importsCount > 0) {
- assert((src->pos() - startPos) == header.importsOffset);
- imports.resize(header.importsCount);
- for (int i = 0; i < header.importsCount; ++i)
- imports[i] = src->readSint16LE();
+ imports.clear();
+ if (importsCount > 0) {
+ int16 *buffer = (int16 *)malloc(importsCount * 2);
+ src->read(buffer, importsCount * 2);
+
+ imports.resize(importsCount);
+ for (int i = 0; i < importsCount; ++i)
+ imports[i] = FROM_LE_16(buffer[i]);
+ free(buffer);
}
- if (header.entryFlagsCount > 0) {
- assert((src->pos() - startPos) == header.entryFlagsOffset);
- entryFlags.resize(header.entryFlagsCount);
- for (int i = 0; i < header.entryFlagsCount; ++i)
- entryFlags[i] = src->readUint16LE();
+ // Entry flags: always read (no count guard in the original)
+ {
+ int16 *buffer = (int16 *)malloc(entryFlagsCount * 2);
+ src->read(buffer, entryFlagsCount * 2);
+
+ entryFlags.resize(entryFlagsCount);
+ for (int i = 0; i < entryFlagsCount; ++i)
+ entryFlags[i] = FROM_LE_16(buffer[i]);
+ free(buffer);
}
- if (header.variablesCount > 0) {
- assert((src->pos() - startPos) == header.entryFlagsOffset);
- variables.resize(header.entryFlagsCount);
- for (int i = 0; i < header.entryFlagsCount; ++i) {
- variables[i].load(src);
+ // Variables
+ {
+ byte *buffer = (byte *)malloc(variablesCount * ConvVariable::SIZE);
+ src->read(buffer, (long)variablesCount * ConvVariable::SIZE);
+
+ Common::MemoryReadStream mrs(buffer, variablesCount * ConvVariable::SIZE);
+ variables.resize(variablesCount);
+ for (int i = 0; i < variablesCount; ++i) {
+ variables[i].load(&mrs);
+
+ // Zero the runtime isPtr flag for every variable; it is not meaningful as stored on disk
+ variables[i].isPtr = false;
}
+ free(buffer);
}
}
void ConvData::save(Common::WriteStream *dest) const {
- // Save the header
- ConvDataHeader header;
- header = *this;
- header.importsOffset = ConvDataHeader::SIZE;
- header.entryFlagsOffset = header.importsOffset + (importsCount * 2);
- header.variablesOffset = header.entryFlagsOffset + (entryFlagsCount * 2);
+ dest->writeMultipleLE(currentNode, entryFlagsCount, variablesCount,
+ importsCount, numImports, optionListSize,
+ messageList1Size, messageList2Size, speechList1Size, speechList2Size);
+ dest->writeMultipleLE(optionList);
+ dest->writeMultipleLE(messageList1);
+ dest->writeMultipleLE(messageList2);
+ dest->writeMultipleLE(speechList1);
+ dest->writeMultipleLE(speechList2);
- header.save(dest);
+ // Figure out offset fields
+ uint16 importsOffset1 = SIZE;
+ uint16 entryFlagsOffset1 = importsOffset1 + (importsCount * 2);
+ uint16 variablesOffset1 = entryFlagsOffset1 + (entryFlagsCount * 2);
+ dest->writeMultipleLE(importsOffset1, entryFlagsOffset1, variablesOffset1);
- for (int i = 0; i < header.importsCount; ++i)
+ for (int i = 0; i < importsCount; ++i)
dest->writeSint16LE(imports[i]);
- for (int i = 0; i < header.entryFlagsCount; ++i)
+ for (int i = 0; i < entryFlagsCount; ++i)
dest->writeSint16LE(entryFlags[i]);
- for (int i = 0; i < header.entryFlagsCount; ++i)
+ for (int i = 0; i < entryFlagsCount; ++i)
variables[i].save(dest);
}
@@ -306,12 +312,12 @@ static Conv *load_conv(const char *fname) {
{
// Read the fixed-size Conv header through a MemoryReadStream so that
// the load() function handles field sizes and endianness correctly.
- byte hdrBuf[Conv::SIZE];
- if (!loader_read(hdrBuf, Conv::SIZE, 1, &file)) {
+ byte buffer[Conv::SIZE];
+ if (!loader_read(buffer, Conv::SIZE, 1, &file)) {
conv_error_code = 2;
goto done;
}
- Common::MemoryReadStream hdrStream(hdrBuf, Conv::SIZE);
+ Common::MemoryReadStream hdrStream(buffer, Conv::SIZE);
dataPtr->load(&hdrStream);
}
@@ -421,96 +427,23 @@ done:
static ConvData *load_conv_data(const char *fname) {
Load file;
- ConvDataHeader header;
- ConvData *dataPtr = nullptr;
- ConvData *result = nullptr;
+ ConvData *convData = nullptr;
char filename[80];
- char name_buf[9];
file.open = false;
Common::strcpy_s(filename, fname);
- fileio_add_ext(filename, "cnv");
-
- const char *fn = (filename[0] == '*') ? filename + 1 : filename;
- Common::strlcpy(name_buf, fn, sizeof(name_buf));
+ fileio_add_ext(filename, "cnd");
if (loader_open(&file, filename, "rb", true))
- goto done;
-
- {
- byte hdrBuf[ConvDataHeader::SIZE];
- if (!loader_read(hdrBuf, ConvDataHeader::SIZE, 1, &file))
- goto done;
+ return nullptr;
- Common::MemoryReadStream hdrStream(hdrBuf, ConvDataHeader::SIZE);
- header.load(&hdrStream);
- }
-
- dataPtr = new ConvData();
- if (!dataPtr)
- goto done;
-
- *dataPtr = header;
-
- // Imports: conditional â the original skips the loader_read when count <= 0
- if (header.importsCount > 0) {
- int16 *buffer = (int16 *)malloc(header.importsCount * 2);
- if (!loader_read(buffer, (long)header.importsCount * 2, 1, &file)) {
- free(buffer);
- goto done;
- }
-
- dataPtr->imports.resize(header.importsCount);
- for (int i = 0; i < header.importsCount; ++i)
- dataPtr->imports[i] = FROM_LE_16(buffer[i]);
- free(buffer);
- }
+ convData = new ConvData();
+ LoaderReadStream src(&file);
+ convData->load(&src);
- // Entry flags: always read (no count guard in the original)
- {
- int16 *buffer = (int16 *)malloc(header.entryFlagsCount * 2);
- if (!loader_read(buffer, (long)header.entryFlagsCount * 2, 1, &file)) {
- free(buffer);
- goto done;
- }
-
- dataPtr->entryFlags.resize(header.entryFlagsCount);
- for (int i = 0; i < header.entryFlagsCount; ++i)
- dataPtr->entryFlags[i] = FROM_LE_16(buffer[i]);
- free(buffer);
- }
-
- // Variables
- {
- byte *buffer = (byte *)malloc(header.variablesCount * ConvVariable::SIZE);
- if (!loader_read(buffer, (long)header.variablesCount * ConvVariable::SIZE, 1, &file)) {
- free(buffer);
- goto done;
- }
-
- Common::MemoryReadStream src(buffer, header.variablesCount * ConvVariable::SIZE);
- dataPtr->variables.resize(header.entryFlagsCount);
- for (int i = 0; i < header.entryFlagsCount; ++i) {
- dataPtr->variables[i].load(&src);
-
- // Zero the runtime isPtr flag for every variable; it is not meaningful
- // as stored on disk
- dataPtr->variables[i].isPtr = false;
- }
- free(buffer);
- }
-
- result = dataPtr;
-
-done:
- if (file.open)
- loader_close(&file);
-
- if (dataPtr && dataPtr != result)
- delete dataPtr;
-
- return result;
+ loader_close(&file);
+ return convData;
}
static ConvData *conv_read(Common::SeekableReadStream *src) {
@@ -1163,16 +1096,16 @@ void conv_start(ConvData *convData, Conv *convIn) {
active_conv_data = convData;
// Resolve the byte-offset sub-array pointers stored in the ConvData block
- conv_imports = &convData->imports[0];
- conv_entry_flags = &convData->entryFlags[0];
- conv_varsDataPtr = &convData->variables[0];
+ conv_imports = convData->imports.empty() ? nullptr : &convData->imports[0];
+ conv_entry_flags = convData->entryFlags.empty() ? nullptr : & convData->entryFlags[0];
+ conv_varsDataPtr = convData->variables.empty() ? nullptr : & convData->variables[0];
// conv_vars0ValPtr -> variables[0].val (skips the isPtr field)
conv_vars0ValPtr = &conv_varsDataPtr[0].val;
// conv_my_next_start -> variables[1].val
// (offset = offsetof(ConvVariable, val) + sizeof(ConvVariable) from base)
- conv_my_next_start = (int16 *)&conv_varsDataPtr[1].val;
+ conv_my_next_start = &conv_varsDataPtr[1].val;
convData->currentNode = -1;
convData->numImports = 0;
diff --git a/engines/mads/madsv2/core/conv.h b/engines/mads/madsv2/core/conv.h
index f0327a4be38..b52e8733a72 100644
--- a/engines/mads/madsv2/core/conv.h
+++ b/engines/mads/madsv2/core/conv.h
@@ -138,7 +138,7 @@ struct Conv {
void load(Common::SeekableReadStream *src);
};
-struct ConvDataBase {
+struct ConvData {
int16 currentNode;
int16 entryFlagsCount;
int16 variablesCount;
@@ -154,41 +154,15 @@ struct ConvDataBase {
int16 messageList2[10];
int16 speechList1[10];
int16 speechList2[10];
-};
-
-struct ConvDataHeader : public ConvDataBase {
- int16 importsOffset;
- int16 entryFlagsOffset;
- int16 variablesOffset;
-
- ConvDataHeader &operator=(const ConvDataBase &src) {
- *((ConvDataBase *)this) = src;
- importsOffset = entryFlagsOffset = variablesOffset = 0;
- return *this;
- }
-
- // On-disk size: 10 header words + 5 arrays of 10 words + 3 offset words
- // = 20 + 100 + 6 = 126 = 0x7E. The +21 padding in load_conv_data
- // exploits the fact that 21 * 6 = 126, so the formula automatically
- // includes the header in the total allocation.
- static constexpr int SIZE = 2 * 10 + 2 * 10 * 5 + 2 * 3;
- void load(Common::SeekableReadStream *src);
- void save(Common::WriteStream *dest) const;
-};
-
-struct ConvData : public ConvDataBase {
- ConvData &operator=(const ConvDataBase &src) {
- *((ConvDataBase *)this) = src;
- imports.clear();
- entryFlags.clear();
- variables.clear();
- return *this;
- }
+ uint16 importsOffset;
+ uint16 entryFlagsOffset;
+ uint16 variablesOffset;
Common::Array<int16> imports;
Common::Array<uint16> entryFlags;
Common::Array<ConvVariable> variables;
+ static constexpr int SIZE = 2 * 10 + 2 * 10 * 5 + 2 * 3;
void load(Common::SeekableReadStream *src);
void save(Common::WriteStream *dest) const;
};
diff --git a/engines/mads/madsv2/core/loader.cpp b/engines/mads/madsv2/core/loader.cpp
index 0b9f715a6d8..0a99227e5ae 100644
--- a/engines/mads/madsv2/core/loader.cpp
+++ b/engines/mads/madsv2/core/loader.cpp
@@ -55,6 +55,12 @@ int loader_ems_search_disabled = false;
char loader_last[14] = "";
+uint32 LoaderReadStream::read(void *dataPtr, uint32 dataSize) {
+ loader_read(dataPtr, dataSize, 1, _load);
+ return dataSize;
+}
+
+
int loader_open(LoadHandle handle, const char *filename, const char *options, int flags) {
int error_flag = true;
int found_himem = -1;
diff --git a/engines/mads/madsv2/core/loader.h b/engines/mads/madsv2/core/loader.h
index 8f72bfe220a..372115fdfd9 100644
--- a/engines/mads/madsv2/core/loader.h
+++ b/engines/mads/madsv2/core/loader.h
@@ -51,6 +51,25 @@ typedef struct {
typedef Load *LoadHandle;
+/**
+ * Simple encapsulation for using loaders in Conv::load
+ */
+class LoaderReadStream : public Common::SeekableReadStream {
+private:
+ LoadHandle _load;
+public:
+ LoaderReadStream(LoadHandle load) : _load(load) {}
+ ~LoaderReadStream() override {
+ }
+
+ int64 pos() const override { return 0; }
+ int64 size() const { return 0; }
+ bool seek(int64 offset, int whence = SEEK_SET) override { return false; }
+ bool eos() const override { return false; }
+ uint32 read(void *dataPtr, uint32 dataSize) override;
+};
+
+
/* Debug tracking variables */
#ifndef disable_statistics
extern long loader_found_in_ems;
Commit: f6910e5d079383475aa4cda8432187d3d5a9cce0
https://github.com/scummvm/scummvm/commit/f6910e5d079383475aa4cda8432187d3d5a9cce0
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:12+10:00
Commit Message:
MADS: PHANTOM: Fix conv scripts declaration
Changed paths:
engines/mads/madsv2/core/conv.h
diff --git a/engines/mads/madsv2/core/conv.h b/engines/mads/madsv2/core/conv.h
index b52e8733a72..a89115514b0 100644
--- a/engines/mads/madsv2/core/conv.h
+++ b/engines/mads/madsv2/core/conv.h
@@ -129,7 +129,7 @@ struct Conv {
Common::Array<ConvDialog> dialogs;
Common::Array<LineSet> messages;
Common::Array<char> text;
- Common::Array<uint16> scripts;
+ Common::Array<byte> scripts;
Common::Array<uint16> textLines;
static constexpr int SIZE = (2 * 7 + 16 * 5 + 2 * 5 + 14 + 4 + 4) +
Commit: bff3e2b120194d29812a3d0ffe7c0688043ba77c
https://github.com/scummvm/scummvm/commit/bff3e2b120194d29812a3d0ffe7c0688043ba77c
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:12+10:00
Commit Message:
MADS: PHANTOM: Properly flag conv as done
Changed paths:
engines/mads/madsv2/core/conv.cpp
diff --git a/engines/mads/madsv2/core/conv.cpp b/engines/mads/madsv2/core/conv.cpp
index 7ed670b28d1..db7b25ab67e 100644
--- a/engines/mads/madsv2/core/conv.cpp
+++ b/engines/mads/madsv2/core/conv.cpp
@@ -1330,7 +1330,6 @@ void conv_update(bool flag) {
kernel.trigger = conv_control.me_trigger;
kernel.trigger_mode = conv_control.me_trigger_mode;
conv_control.me_trigger = 0;
- return;
}
conv_control.status = CONV_STATUS_DONE;
Commit: 65c54c9d8fd3466b377ae41f5dcc2c70fbabc722
https://github.com/scummvm/scummvm/commit/65c54c9d8fd3466b377ae41f5dcc2c70fbabc722
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:13+10:00
Commit Message:
MADS: PHANTOM: Fix loading room hotspot list
Changed paths:
engines/mads/madsv2/core/player.cpp
engines/mads/madsv2/core/room.cpp
diff --git a/engines/mads/madsv2/core/player.cpp b/engines/mads/madsv2/core/player.cpp
index 34dbb91379a..7e82ac8c351 100644
--- a/engines/mads/madsv2/core/player.cpp
+++ b/engines/mads/madsv2/core/player.cpp
@@ -180,6 +180,7 @@ static void player_keep_turning() {
temp_facing = player_clockwise[temp_facing]) {
clockwise_count++;
clockwise_sum += temp_facing;
+ assert(clockwise_count < 100);
}
for (temp_facing = player.facing;
diff --git a/engines/mads/madsv2/core/room.cpp b/engines/mads/madsv2/core/room.cpp
index fcfa0b728e8..dbae7df77a4 100644
--- a/engines/mads/madsv2/core/room.cpp
+++ b/engines/mads/madsv2/core/room.cpp
@@ -74,7 +74,9 @@ void RoomFile::load(Common::SeekableReadStream *src) {
void HotSpot::load(Common::SeekableReadStream *src) {
src->readMultipleLE(ul_x, ul_y, lr_x, lr_y, feet_x, feet_y,
- facing, prep, active, cursor_number, syntax, vocab, verb);
+ facing, prep, active, cursor_number, syntax);
+ src->skip(1);
+ src->readMultipleLE(vocab, verb);
}
//====================================================================
@@ -391,7 +393,7 @@ HotPtr room_load_hotspots(int id, int *num_spots) {
}
num_to_read = MAX(*num_spots, 1);
- memory_needed = (num_to_read * sizeof(HotSpot));
+ memory_needed = num_to_read * sizeof(HotSpot);
spots = (HotPtr)mem_get_name(memory_needed, "$hotspot");
if (spots == NULL)
Commit: d26d9ee9f229896570ef49a2c0ffd252c5bec426
https://github.com/scummvm/scummvm/commit/d26d9ee9f229896570ef49a2c0ffd252c5bec426
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:13+10:00
Commit Message:
MADS: PHANTOM: Remove deprecated popup_create stub
Changed paths:
engines/mads/madsv2/core/popup.cpp
engines/mads/madsv2/core/popup.h
diff --git a/engines/mads/madsv2/core/popup.cpp b/engines/mads/madsv2/core/popup.cpp
index 4659095ac1d..bbecccf3ffb 100644
--- a/engines/mads/madsv2/core/popup.cpp
+++ b/engines/mads/madsv2/core/popup.cpp
@@ -144,10 +144,6 @@ done:
return error_flag;
}
-int popup_create(FontPtr font, int horiz_pieces, int x, int y) {
- error("TODO: popup_create");
-}
-
void popup_add_icon(SeriesPtr series, int id, int center) {
box->icon = series;
box->icon_id = id;
diff --git a/engines/mads/madsv2/core/popup.h b/engines/mads/madsv2/core/popup.h
index acc4ecfcdbc..2616af6d9e4 100644
--- a/engines/mads/madsv2/core/popup.h
+++ b/engines/mads/madsv2/core/popup.h
@@ -410,7 +410,6 @@ extern BoxParam box_param;
/* popup_1.c */
int popup_create(int horiz_pieces, int x, int y);
-int popup_create(FontPtr font, int horiz_pieces, int x, int y);
void popup_add_icon(SeriesPtr series, int id, int center);
int popup_draw(int save_screen, int depth_code);
void popup_destroy(void);
Commit: a89d91a57da8ec69db7e5e111d072ccbce01f819
https://github.com/scummvm/scummvm/commit/a89d91a57da8ec69db7e5e111d072ccbce01f819
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:13+10:00
Commit Message:
MADS: PHANTOM: Don't save/restore popup screen areas using EMS
Changed paths:
engines/mads/madsv2/core/popup.cpp
engines/mads/madsv2/core/popup.h
diff --git a/engines/mads/madsv2/core/popup.cpp b/engines/mads/madsv2/core/popup.cpp
index bbecccf3ffb..e16650e08aa 100644
--- a/engines/mads/madsv2/core/popup.cpp
+++ b/engines/mads/madsv2/core/popup.cpp
@@ -115,6 +115,9 @@ int popup_create(int horiz_pieces, int x, int y) {
box->text_width = (box->text_xs / box_param.font->max_x_size) << 1;
+ box->screen_buffer.data = NULL;
+ box->depth_buffer.data = NULL;
+
box->screen_saved = false;
box->depth_saved = false;
@@ -503,23 +506,20 @@ int popup_draw(int save_screen, int depth_code) {
matte_map_work_screen();
if (depth_code) {
- box->preserve_handle = buffer_preserve(&scr_orig, popup_preserve_initiator[2],
- -1,
- box->x + picture_map.pan_offset_x,
- box->y + picture_map.pan_offset_y,
- box->xs, box->ys);
+ buffer_init(&box->screen_buffer, box->xs, box->ys);
+ if (box->screen_buffer.data != NULL)
+ buffer_rect_copy_2(scr_orig, box->screen_buffer,
+ box->x + picture_map.pan_offset_x,
+ box->y + picture_map.pan_offset_y,
+ 0, 0, box->xs, box->ys);
} else {
- box->preserve_handle = buffer_preserve(&scr_main, popup_preserve_initiator[0],
- work_screen_ems_handle,
- box->x, box->y,
- box->xs, box->ys);
+ buffer_init(&box->screen_buffer, box->xs, box->ys);
+ if (box->screen_buffer.data != NULL)
+ buffer_rect_copy_2(scr_main, box->screen_buffer,
+ box->x, box->y, 0, 0, box->xs, box->ys);
}
- box->screen_saved = true;
-
- if (box->preserve_handle == BUFFER_NOT_PRESERVED) {
- error_report(ERROR_POPUP_PRESERVE_FAILURE, WARNING, MODULE_POPUP, box->preserve_handle, 0);
- }
+ box->screen_saved = (box->screen_buffer.data != NULL);
if (depth_code) {
box->depth_x = box->x + picture_map.pan_offset_x;
@@ -535,18 +535,14 @@ int popup_draw(int save_screen, int depth_code) {
box->depth_x = box->depth_x >> 1;
box->depth_xs = box->depth_xs >> 1;
- box->depth_preserve_handle = buffer_preserve(&scr_depth,
- popup_preserve_initiator[1],
- -1,
- box->depth_x,
- box->y + picture_map.pan_offset_y,
- box->depth_xs, box->ys);
-
- if (box->depth_preserve_handle == BUFFER_NOT_PRESERVED) {
- error_report(ERROR_POPUP_PRESERVE_FAILURE, WARNING, MODULE_POPUP, box->depth_preserve_handle, 1);
- }
+ buffer_init(&box->depth_buffer, box->depth_xs, box->ys);
+ if (box->depth_buffer.data != NULL)
+ buffer_rect_copy_2(scr_depth, box->depth_buffer,
+ box->depth_x,
+ box->y + picture_map.pan_offset_y,
+ 0, 0, box->depth_xs, box->ys);
- box->depth_saved = true;
+ box->depth_saved = (box->depth_buffer.data != NULL);
}
}
@@ -749,13 +745,21 @@ void popup_destroy(void) {
if (box->active && box->screen_saved) {
if (box->depth_saved) {
- buffer_restore(&scr_orig, box->preserve_handle, -1,
- box->x + picture_map.pan_offset_x,
- box->y + picture_map.pan_offset_y,
- box->xs, box->ys);
- buffer_restore(&scr_depth, box->depth_preserve_handle, -1,
- box->depth_x, box->y + picture_map.pan_offset_y,
- box->depth_xs, box->ys);
+ if (box->screen_buffer.data != NULL) {
+ buffer_rect_copy_2(box->screen_buffer, scr_orig,
+ 0, 0,
+ box->x + picture_map.pan_offset_x,
+ box->y + picture_map.pan_offset_y,
+ box->xs, box->ys);
+ buffer_free(&box->screen_buffer);
+ }
+ if (box->depth_buffer.data != NULL) {
+ buffer_rect_copy_2(box->depth_buffer, scr_depth,
+ 0, 0,
+ box->depth_x, box->y + picture_map.pan_offset_y,
+ box->depth_xs, box->ys);
+ buffer_free(&box->depth_buffer);
+ }
matte_guard_depth_0 = false;
@@ -780,8 +784,11 @@ void popup_destroy(void) {
} else {
matte_map_work_screen();
- buffer_restore(&scr_main, box->preserve_handle, work_screen_ems_handle,
- box->x, box->y, box->xs, box->ys);
+ if (box->screen_buffer.data != NULL) {
+ buffer_rect_copy_2(box->screen_buffer, scr_main,
+ 0, 0, box->x, box->y, box->xs, box->ys);
+ buffer_free(&box->screen_buffer);
+ }
matte_map_work_screen();
diff --git a/engines/mads/madsv2/core/popup.h b/engines/mads/madsv2/core/popup.h
index 2616af6d9e4..25997987f93 100644
--- a/engines/mads/madsv2/core/popup.h
+++ b/engines/mads/madsv2/core/popup.h
@@ -177,6 +177,9 @@ typedef struct {
int preserve_handle;
int depth_preserve_handle;
+ Buffer screen_buffer; /* Direct copy of screen area under popup */
+ Buffer depth_buffer; /* Direct copy of depth area under popup */
+
int screen_saved;
int depth_saved;
Commit: ffb08436faff322c3621953362267010b12b50fb
https://github.com/scummvm/scummvm/commit/ffb08436faff322c3621953362267010b12b50fb
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:14+10:00
Commit Message:
MADS: PHANTOM: Fix mouse movement tracking
Changed paths:
engines/mads/madsv2/core/mouse.cpp
engines/mads/madsv2/engine.cpp
engines/mads/madsv2/engine.h
diff --git a/engines/mads/madsv2/core/mouse.cpp b/engines/mads/madsv2/core/mouse.cpp
index 779ca6a09e7..7bd5c7ed66e 100644
--- a/engines/mads/madsv2/core/mouse.cpp
+++ b/engines/mads/madsv2/core/mouse.cpp
@@ -27,6 +27,7 @@
#include "mads/madsv2/core/mouse.h"
#include "mads/madsv2/core/timer.h"
#include "mads/madsv2/core/video.h"
+#include "mads/madsv2/engine.h"
namespace MADS {
namespace MADSV2 {
@@ -34,7 +35,6 @@ namespace MADSV2 {
int mouse_button = -1;
int mouse_status = 0;
int mouse_x = 0, mouse_y = 0;
-int mouse_buttons = 0;
bool mouse_start_stroke = false;
bool mouse_stroke_going = false;
bool mouse_changed = false;
@@ -196,10 +196,7 @@ void mouse_double_freedom(int freedom_flag) {
}
int mouse_get_status(int *x, int *y) {
- *x = mouse_x;
- *y = mouse_y;
-
- return mouse_buttons;
+ return g_engine->getMouseState(*x, *y);
}
void mouse_timing() {
diff --git a/engines/mads/madsv2/engine.cpp b/engines/mads/madsv2/engine.cpp
index f0a75214860..71d8fb9497d 100644
--- a/engines/mads/madsv2/engine.cpp
+++ b/engines/mads/madsv2/engine.cpp
@@ -23,7 +23,6 @@
#include "engines/util.h"
#include "mads/madsv2/engine.h"
#include "mads/madsv2/core/kernel.h"
-#include "mads/madsv2/core/mouse.h"
#include "mads/madsv2/phantom/main.h"
#include "mads/core/sound.h"
@@ -63,27 +62,30 @@ void MADSV2Engine::pollEvents() {
bool isMouse = false;
switch (e.type) {
case Common::EVENT_LBUTTONDOWN:
- mouse_buttons |= 1;
+ _mouseButtons |= 1;
isMouse = true;
break;
case Common::EVENT_LBUTTONUP:
- mouse_buttons &= ~1;
+ _mouseButtons &= ~1;
isMouse = true;
break;
case Common::EVENT_RBUTTONDOWN:
- mouse_buttons |= 2;
+ _mouseButtons |= 2;
isMouse = true;
break;
case Common::EVENT_RBUTTONUP:
- mouse_buttons &= ~2;
+ _mouseButtons &= ~2;
isMouse = true;
break;
case Common::EVENT_MBUTTONDOWN:
- mouse_buttons |= 4;
+ _mouseButtons |= 4;
isMouse = true;
break;
case Common::EVENT_MBUTTONUP:
- mouse_buttons &= ~4;
+ _mouseButtons &= ~4;
+ isMouse = true;
+ break;
+ case Common::EVENT_MOUSEMOVE:
isMouse = true;
break;
case Common::EVENT_RETURN_TO_LAUNCHER:
@@ -94,10 +96,8 @@ void MADSV2Engine::pollEvents() {
break;
}
- if (isMouse) {
- mouse_x = e.mouse.x;
- mouse_y = e.mouse.y;
- }
+ if (isMouse)
+ _mousePos = e.mouse;
if (e.type == Common::EVENT_KEYDOWN)
_keyEvents.push(e);
@@ -127,6 +127,14 @@ void MADSV2Engine::flushKeys() {
_keyEvents.clear();
}
+int MADSV2Engine::getMouseState(int &x, int &y) {
+ pollEvents();
+
+ x = _mousePos.x;
+ y = _mousePos.y;
+ return _mouseButtons;
+}
+
uint32 MADSV2Engine::getMillis() {
pollEvents();
return g_system->getMillis();
diff --git a/engines/mads/madsv2/engine.h b/engines/mads/madsv2/engine.h
index 4670b4ceed0..d2784871eb9 100644
--- a/engines/mads/madsv2/engine.h
+++ b/engines/mads/madsv2/engine.h
@@ -38,6 +38,8 @@ protected:
Graphics::Screen *_screen = nullptr;
Common::Stack<Common::Event> _keyEvents;
uint32 _nextFrameTime = 0;
+ Common::Point _mousePos;
+ int _mouseButtons = 0;
void pollEvents();
@@ -56,6 +58,8 @@ public:
int getKey();
void flushKeys();
+ int getMouseState(int &x, int &y);
+
/**
* Get the elapsed time in milliseconds
*/
Commit: 27ed3ad83019fdc721b601f9379f0b3f79378d78
https://github.com/scummvm/scummvm/commit/27ed3ad83019fdc721b601f9379f0b3f79378d78
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:14+10:00
Commit Message:
MADS: PHANTOM: Fix display of interface tooltips
Changed paths:
engines/mads/madsv2/core/inter.cpp
diff --git a/engines/mads/madsv2/core/inter.cpp b/engines/mads/madsv2/core/inter.cpp
index ff7f02b30e2..855f58c7b90 100644
--- a/engines/mads/madsv2/core/inter.cpp
+++ b/engines/mads/madsv2/core/inter.cpp
@@ -2258,7 +2258,7 @@ void inter_main_loop(int allow_input) {
}
x = (video_x >> 1) - (width >> 1);
y = (viewing_at_y + scr_work.y - 1) - 12;
- /* inter_sentence_handle = matte_add_message (use_font, inter_sentence, x, y, INTER_MESSAGE_COLOR, use_spacing); */
+ inter_sentence_handle = matte_add_message (use_font, inter_sentence, x, y, INTER_MESSAGE_COLOR, use_spacing);
}
inter_sentence_changed = false;
}
Commit: 512f29b97690c1034825d533e7c98971eab4e29f
https://github.com/scummvm/scummvm/commit/512f29b97690c1034825d533e7c98971eab4e29f
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:14+10:00
Commit Message:
MADS: PHANTOM: Simplify text_load to match the original
It's possible that later games may need the extra complexity,
but if that turns out to be the case, we can always
re-introduce the code again.
Changed paths:
engines/mads/madsv2/core/text.cpp
engines/mads/madsv2/core/text.h
diff --git a/engines/mads/madsv2/core/text.cpp b/engines/mads/madsv2/core/text.cpp
index 9125b99400c..7448daaaa9b 100644
--- a/engines/mads/madsv2/core/text.cpp
+++ b/engines/mads/madsv2/core/text.cpp
@@ -20,6 +20,7 @@
*/
#include "common/debug.h"
+#include "common/memstream.h"
#include "mads/madsv2/core/general.h"
#include "mads/madsv2/core/general.h"
#include "mads/madsv2/core/popup.h"
@@ -94,23 +95,16 @@ char text_command_demonstrative[14] = TEXT_COMMAND_DEMONSTRATIVE;
extern int16 global[GLOBAL_LIST_SIZE];
-TextPtr text_load(long id, int mode) {
+TextPtr text_load(long id) {
TextPtr result = NULL;
- TextDirectory dir;
- TextDirectory *table = NULL;
char temp_buf[80];
word num_entries;
long file_offset;
- long index_offset;
long target_offset;
- long full_mem_size;
- long mem_avail;
- /* long high, low; */
- int count;
- int short_id;
- int number = 0;
- int found = false;
+ int count;
+ bool found = false;
Common::SeekableReadStream *handle = NULL;
+ TextDirectory dir;
dir.id = dir.file_offset = dir.length = 0;
mem_last_alloc_loader = MODULE_TEXT_LOADER;
@@ -119,98 +113,18 @@ TextPtr text_load(long id, int mode) {
Common::strcat_s(temp_buf, TEXT_COMPILED);
handle = env_open(temp_buf, "rb");
-
-
if (handle == NULL) goto done;
file_offset = handle->pos();
- if (!fileio_fread_f(&num_entries, sizeof(word), 1, handle))
- goto done;
-
- switch (mode) {
- case TEXT_LOAD_BY_ORDER:
- number = short_id = (int)id;
- if (short_id >= (int)num_entries) goto done;
-
- index_offset = file_offset + sizeof(word) + (sizeof(TextDirectory) * short_id);
- fileio_setpos(handle, index_offset);
-
- if (!fileio_fread_f(&dir, sizeof(TextDirectory), 1, handle)) goto done;
-
- found = true;
- break;
-
- case TEXT_LOAD_BY_ID:
- case TEXT_LOAD_NEXT:
- case TEXT_LOAD_PREVIOUS:
- default:
- full_mem_size = sizeof(TextDirectory) * num_entries;
- mem_avail = mem_get_avail();
-
- if (mem_avail - 128 >= full_mem_size) {
- table = (TextDirectory *)mem_get_name(full_mem_size, "$table$");
- }
+ num_entries = handle->readUint16LE();
- if (table != NULL) {
- if (!fileio_fread_f(table, full_mem_size, 1, handle)) goto done;
- for (count = 0; (!found) && (count < (int)num_entries); count++) {
- found = (table[count].id == id);
- if (found) {
- number = count;
- memcpy(&dir, &table[count], sizeof(TextDirectory));
- }
- }
- mem_free(table);
- table = NULL;
- } else {
- for (count = 0; (!found) && (count < (int)num_entries); count++) {
- if (!fileio_fread_f(&dir, sizeof(TextDirectory), 1, handle)) goto done;
- found = (dir.id == id);
- number = count;
- }
- }
-
- if ((mode == TEXT_LOAD_NEXT) || (mode == TEXT_LOAD_PREVIOUS)) {
- if (!found) goto done;
- if (mode == TEXT_LOAD_NEXT) {
- number++;
- } else {
- number--;
- }
- if (number >= (int)num_entries) goto done;
- if (number < 0) goto done;
-
- index_offset = file_offset + sizeof(word) + (sizeof(TextDirectory) * number);
- fileio_setpos(handle, index_offset);
-
- if (!fileio_fread_f(&dir, sizeof(TextDirectory), 1, handle)) goto done;
- }
- break;
+ for (count = 0; count < num_entries && !found; ++count) {
+ // Iterate over reading table elements
+ dir.load(handle);
+ found = dir.id == id;
}
- /*
- for (count = 0; (!found) && (count < (int)num_entries); count++) {
- if (!fileio_fread_f(&dir, sizeof(TextDirectory), 1, handle)) goto done;
- found = (dir.id == id);
- }
- */
-
- if (!found) {
- /*
- #ifndef disable_error_check
- high = id / 100;
- low = id - high;
- error_report (ERROR_NO_SUCH_MESSAGE, WARNING, MODULE_TEXT, (word)high, (word)low);
- #endif
- */
- goto done;
- }
-
- text_last_id = dir.id;
- text_last_number = number;
- text_last_num_entries = num_entries;
-
target_offset = file_offset + dir.file_offset;
result = (TextPtr)mem_get_name(dir.length + sizeof(word), "$text$");
@@ -229,9 +143,7 @@ TextPtr text_load(long id, int mode) {
}
done:
- if (table != NULL) mem_free(table);
- if (handle != NULL)
- delete handle;
+ delete handle;
return result;
}
@@ -505,7 +417,7 @@ done:
;
}
-int text_show_full(long id, int mode, int key_wait, int report_errors) {
+int text_show(long id) {
int error_flag = true;
int center = false;
int cr;
@@ -529,8 +441,6 @@ int text_show_full(long id, int mode, int key_wait, int report_errors) {
int icon_id = 0;
int icon_center = false;
- if (!key_wait) popup_destroy();
-
x = text_default_x;
y = text_default_y;
@@ -538,15 +448,8 @@ int text_show_full(long id, int mode, int key_wait, int report_errors) {
text_width = (text_force_width > 0) ? text_force_width : text_default_width;
- text = text_load(id, mode);
- if (text == NULL) {
- if (report_errors) {
-#ifndef disable_error_check
- error_report(ERROR_NO_SUCH_MESSAGE, WARNING, MODULE_TEXT, id, mode);
-#endif
- }
- goto done;
- }
+ text = text_load(id);
+ if (text == NULL) goto done;
scan = text->text;
@@ -686,11 +589,7 @@ int text_show_full(long id, int mode, int key_wait, int report_errors) {
if (!center) popup_next_line();
- if (key_wait) {
- if (popup_and_wait(text_saves_screen)) goto done;
- } else {
- if (popup_and_dont_wait(text_saves_screen)) goto done;
- }
+ if (popup_and_wait(text_saves_screen)) goto done;
error_flag = false;
@@ -704,10 +603,5 @@ done:
return error_flag;
}
-
-int text_show(long id) {
- return text_show_full(id, TEXT_LOAD_BY_ID, true, true);
-}
-
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/core/text.h b/engines/mads/madsv2/core/text.h
index eaae2ed8a0e..2fd12a31f28 100644
--- a/engines/mads/madsv2/core/text.h
+++ b/engines/mads/madsv2/core/text.h
@@ -76,22 +76,22 @@ namespace MADSV2 {
#define TEXT_UPPER_AND_LOWER 2
#define TEXT_AS_IS 3
-#define TEXT_LOAD_BY_ID 0 /* Load by id # */
-#define TEXT_LOAD_BY_ORDER 1 /* Load by order in file */
-#define TEXT_LOAD_NEXT 2 /* Load next in file */
-#define TEXT_LOAD_PREVIOUS 3 /* Load previous in file */
-
typedef struct {
word length;
char text[1];
} Text;
-typedef struct {
- long id;
- long file_offset;
+struct TextDirectory {
+ int32 id;
+ uint32 file_offset;
word length;
-} TextDirectory;
+
+ static constexpr int SIZE = 4 + 4 + 2;
+ void load(Common::SeekableReadStream *src) {
+ src->readMultipleLE(id, file_offset, length);
+ }
+};
typedef Text *TextPtr;
@@ -116,12 +116,10 @@ extern int text_last_number; /* Last text number used */
extern int text_last_num_entries; /* Number of entries */
-extern TextPtr text_load(long id, int mode);
+extern TextPtr text_load(long id);
extern int text_build(int build_header);
-
extern void text_copy_vocab(char **mark, int vocab_id);
-extern int text_show_full(long id, int mode, int key_wait, int report_errors);
extern int text_show(long id);
} // namespace MADSV2
Commit: 7ed2003266e0d3051692ebfa1dc7cd2a86912968
https://github.com/scummvm/scummvm/commit/7ed2003266e0d3051692ebfa1dc7cd2a86912968
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:15+10:00
Commit Message:
MADS: PHANTOM: Fix quitting when a dialog is on-screen
Changed paths:
engines/mads/madsv2/core/popup.cpp
diff --git a/engines/mads/madsv2/core/popup.cpp b/engines/mads/madsv2/core/popup.cpp
index e16650e08aa..6b30cf509a4 100644
--- a/engines/mads/madsv2/core/popup.cpp
+++ b/engines/mads/madsv2/core/popup.cpp
@@ -40,6 +40,7 @@
#include "mads/madsv2/core/game.h"
#include "mads/madsv2/core/pal.h"
#include "mads/madsv2/core/mcga.h"
+#include "mads/madsv2/engine.h"
namespace MADS {
namespace MADSV2 {
@@ -820,8 +821,8 @@ void popup_destroy(void) {
int popup_and_wait(int save_screen) {
- int error_flag = true;
- int waiting;
+ bool error_flag = true;
+ bool waiting;
if (cursor != NULL) {
cursor_last = 1;
@@ -836,7 +837,6 @@ int popup_and_wait(int save_screen) {
mouse_init_cycle();
while (waiting) {
-
mouse_begin_cycle(false);
if (keys_any()) {
@@ -847,6 +847,9 @@ int popup_and_wait(int save_screen) {
if (mouse_stop_stroke) waiting = false;
mouse_end_cycle(false, waiting);
+
+ if (g_engine->shouldQuit())
+ waiting = false;
}
popup_destroy();
Commit: 9b023c137f6cbb7aa1b7e82710717ece54ae5903
https://github.com/scummvm/scummvm/commit/9b023c137f6cbb7aa1b7e82710717ece54ae5903
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:15+10:00
Commit Message:
MADS: PHANTOM: Remove un-used digi.cpp/.h
Changed paths:
R engines/mads/madsv2/core/digi.cpp
R engines/mads/madsv2/core/digi.h
engines/mads/madsv2/core/error.cpp
engines/mads/madsv2/core/game.cpp
engines/mads/madsv2/core/kernel.cpp
engines/mads/madsv2/core/popup.cpp
engines/mads/module.mk
diff --git a/engines/mads/madsv2/core/digi.cpp b/engines/mads/madsv2/core/digi.cpp
deleted file mode 100644
index e51b7777de6..00000000000
--- a/engines/mads/madsv2/core/digi.cpp
+++ /dev/null
@@ -1,70 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include "common/textconsole.h"
-#include "mads/madsv2/core/digi.h"
-
-namespace MADS {
-namespace MADSV2 {
-
-bool digi_trigger_dialog;
-bool digi_trigger_ambiance;
-bool digi_trigger_effect;
-
-
-void digi_install() {
- // No implementation in ScummVM
-}
-
-void digi_uninstall() {
- // No implementation in ScummVM
-}
-
-void digi_play(char name[30], int slot) {
- warning("TODO: digi_play");
-}
-
-void digi_play_build(int room, char thing, int num, int slot) {
- warning("TODO: digi_play_build");
-}
-
-void digi_play_build_ii(char thing, int num, int slot) {
- warning("TODO: digi_play_build_ii");
-}
-
-void digi_stop(int which_one) {
- warning("TODO: digi_stop");
-}
-
-void digi_read_another_chunk() {
- warning("TODO: digi_read_another_chunk");
-}
-
-void digi_initial_volume(int vol) {
- warning("TODO: digi_initial_volume");
-}
-
-void digi_set_volume(int vol, int slot) {
- warning("TODO: digi_set_volume");
-}
-
-} // namespace MADSV2
-} // namespace MADS
diff --git a/engines/mads/madsv2/core/digi.h b/engines/mads/madsv2/core/digi.h
deleted file mode 100644
index 6368b78c7c0..00000000000
--- a/engines/mads/madsv2/core/digi.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#ifndef MADS_CORE_DIGI_H
-#define MADS_CORE_DIGI_H
-
-#include "mads/madsv2/core/general.h"
-
-namespace MADS {
-namespace MADSV2 {
-
-extern bool digi_trigger_dialog;
-extern bool digi_trigger_ambiance;
-extern bool digi_trigger_effect;
-
-
-void digi_install();
-void digi_play(char name[30], int slot);
-void digi_play_build(int room, char thing, int num, int slot);
-void digi_play_build_ii(char thing, int num, int slot);
-void digi_stop(int which_one);
-void digi_uninstall();
-void digi_read_another_chunk();
-void digi_initial_volume(int vol);
-void digi_set_volume(int vol, int slot);
-
-} // namespace MADSV2
-} // namespace MADS
-
-#endif
diff --git a/engines/mads/madsv2/core/error.cpp b/engines/mads/madsv2/core/error.cpp
index 6225d7b94ad..90149f37d0d 100644
--- a/engines/mads/madsv2/core/error.cpp
+++ b/engines/mads/madsv2/core/error.cpp
@@ -35,7 +35,6 @@
#include "mads/madsv2/core/keys.h"
#include "mads/madsv2/core/mem.h"
#include "mads/madsv2/core/midi.h"
-#include "mads/madsv2/core/digi.h"
namespace MADS {
namespace MADSV2 {
@@ -180,8 +179,6 @@ done:
static void error_explode(const char *error_buf, const char *module_buf,
const char *data1_buf, const char *data2_buf, long avail, int error) {
- midi_uninstall();
- digi_uninstall();
timer_remove();
keys_remove();
diff --git a/engines/mads/madsv2/core/game.cpp b/engines/mads/madsv2/core/game.cpp
index 8eead8a020f..b370b8f200d 100644
--- a/engines/mads/madsv2/core/game.cpp
+++ b/engines/mads/madsv2/core/game.cpp
@@ -59,7 +59,6 @@
#include "mads/madsv2/core/kernel.h"
#include "mads/madsv2/core/config.h"
#include "mads/madsv2/core/fileio.h"
-#include "mads/madsv2/core/digi.h"
#include "mads/madsv2/core/midi.h"
#include "mads/madsv2/core/copy.h"
#include "mads/madsv2/core/camera.h"
@@ -896,7 +895,7 @@ int game_parse_keystroke(int mykey) {
case ctrl_c_key:
kernel.mouse_cursor_point = (byte)(!kernel.mouse_cursor_point);
break;
-
+#if 0
case ctrl_s_key:
Common::strcpy_s(temp_buf, "d322u001");
@@ -926,7 +925,7 @@ int game_parse_keystroke(int mykey) {
}
}
break;
-
+#endif
case alt_f1_key:
if (room->front_y > room->back_y) room->front_y--;
kernel_room_bound_dif = room->front_y - room->back_y;
@@ -1817,6 +1816,7 @@ void do_interface_for_ouaf() {
/* Calls, in proper order, all daemon code for this framing round.
*/
static void game_daemon_code() {
+#if 0
global[4] = -1; /* turn off global[player_selected_object] */
digi_read_another_chunk();
@@ -1826,7 +1826,7 @@ static void game_daemon_code() {
if (section_id != 9) {
do_interface_for_ouaf();
}
-
+#endif
kernel.trigger_setup_mode = KERNEL_TRIGGER_DAEMON;
game_exec_function(room_daemon_code_pointer);
@@ -2443,10 +2443,6 @@ skip_frame:
static void game_control_loop() {
game_any_keystroke = false;
- digi_trigger_dialog = true;
- digi_trigger_ambiance = true;
- digi_trigger_effect = true;
-
if (debugger) game_exec_function(debugger_reset);
while ((new_room == room_id) && game.going && !kernel.force_restart) {
@@ -2468,13 +2464,12 @@ static void game_control_loop() {
error_report(ERROR_TIME_LIMIT_EXPIRED, SEVERE, MODULE_GAME, abort_value, 0);
}
}
-
}
-
+#if 0
digi_stop(1);
digi_stop(2);
digi_stop(3);
-
+#endif
if (debugger) game_exec_function(debugger_reset);
}
diff --git a/engines/mads/madsv2/core/kernel.cpp b/engines/mads/madsv2/core/kernel.cpp
index 7dce9c9e8c8..cc6c987bda4 100644
--- a/engines/mads/madsv2/core/kernel.cpp
+++ b/engines/mads/madsv2/core/kernel.cpp
@@ -52,7 +52,6 @@
#include "mads/madsv2/core/fileio.h"
#include "mads/madsv2/core/vocab.h"
#include "mads/madsv2/core/midi.h"
-#include "mads/madsv2/core/digi.h"
#include "mads/madsv2/core/rail.h"
#include "mads/madsv2/core/hspot.h"
#include "mads/madsv2/core/attr.h"
@@ -274,9 +273,6 @@ void kernel_game_shutdown() {
/* Remove timer interrupt stuff */
- midi_uninstall();
- digi_uninstall();
-
timer_activate_low_priority(NULL);
timer_remove();
@@ -442,17 +438,6 @@ int kernel_game_startup(int game_video_mode, int load_flag,
if (load_flag & KERNEL_STARTUP_INTERRUPT) {
timer_install();
- midi_install();
- digi_install();
-
- /*
- if (!lock_verification()) {
- error_report (ERROR_COPY_PROTECTION, SEVERE, MODULE_LOCK, 0, 0);
- }
- timer_remove();
- timer_install();
- */
-
cycling_active = false;
timer_activate_low_priority(cycle_colors);
keys_install();
@@ -1497,12 +1482,13 @@ int kernel_run_animation(const char *name, int trigger_code) {
int id;
long largest_block;
-
+#if 0
if (stop_speech_on_run_anim) {
digi_stop(1);
digi_stop(2);
digi_stop(3);
}
+#endif
anim_error = -2;
diff --git a/engines/mads/madsv2/core/popup.cpp b/engines/mads/madsv2/core/popup.cpp
index 6b30cf509a4..c9387e8600a 100644
--- a/engines/mads/madsv2/core/popup.cpp
+++ b/engines/mads/madsv2/core/popup.cpp
@@ -34,7 +34,6 @@
#include "mads/madsv2/core/keys.h"
#include "mads/madsv2/core/timer.h"
#include "mads/madsv2/core/sprite.h"
-#include "mads/madsv2/core/digi.h"
#include "mads/madsv2/core/midi.h"
#include "mads/madsv2/core/screen.h"
#include "mads/madsv2/core/game.h"
@@ -3385,7 +3384,6 @@ PopupItem *popup_execute(void) {
mouse_init_cycle();
do {
- digi_read_another_chunk();
midi_loop();
mouse_begin_cycle(false);
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index b4c64784a21..7797d0b18cb 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -74,7 +74,6 @@ MODULE_OBJS += \
madsv2/core/cursor.o \
madsv2/core/cycle.o \
madsv2/core/dialog.o \
- madsv2/core/digi.o \
madsv2/core/ems.o \
madsv2/core/env.o \
madsv2/core/error.o \
Commit: 5f049aea485d1fadde05e0af3e3a5266304ff36a
https://github.com/scummvm/scummvm/commit/5f049aea485d1fadde05e0af3e3a5266304ff36a
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:15+10:00
Commit Message:
MADS: PHANTOM: Properly initialize sound driver
Changed paths:
engines/mads/madsv2/core/game.cpp
engines/mads/madsv2/core/global.cpp
engines/mads/madsv2/core/kernel.h
engines/mads/madsv2/engine.h
engines/mads/madsv2/phantom/phantom.cpp
engines/mads/madsv2/phantom/phantom.h
diff --git a/engines/mads/madsv2/core/game.cpp b/engines/mads/madsv2/core/game.cpp
index b370b8f200d..9670383452d 100644
--- a/engines/mads/madsv2/core/game.cpp
+++ b/engines/mads/madsv2/core/game.cpp
@@ -172,6 +172,11 @@ Popup *game_menu_popup; /* Popup structure for menu */
int debugger_previous = DEBUGGER_NONE;
int debugger_watch = 0;
int debugger_watch_index[DEBUGGER_MAX_WATCH];
+
+int sound_board_address = 0;
+int sound_board_type = 0;
+int sound_board_irq = 0;
+
static int previous_running = -1000;
static void game_control_loop();
@@ -1358,7 +1363,7 @@ void game_control() {
kernel_mode = KERNEL_SECTION_PRELOAD;
- /* pl global_sound_driver (); */
+ global_sound_driver();
ems_paging_mode(EMS_PAGING_SECTION);
@@ -1368,8 +1373,7 @@ void game_control() {
game.going = (byte)!kernel_section_startup(new_section);
/* Load sound driver */
-
- /* pl kernel_load_sound_driver (kernel.sound_driver, kernel.sound_card, sound_board_address, sound_board_type, sound_board_irq); */
+ kernel_load_sound_driver(kernel.sound_driver, kernel.sound_card, sound_board_address, sound_board_type, sound_board_irq);
kernel_mode = KERNEL_SECTION_INIT;
diff --git a/engines/mads/madsv2/core/global.cpp b/engines/mads/madsv2/core/global.cpp
index 9d62c53d971..ece4b13c9cc 100644
--- a/engines/mads/madsv2/core/global.cpp
+++ b/engines/mads/madsv2/core/global.cpp
@@ -65,7 +65,7 @@ void global_verb_filter() {
}
void global_sound_driver() {
- error("TODO: void global_sound_driver(void);");
+ g_engine->global_sound_driver();
}
void global_section_constructor() {
diff --git a/engines/mads/madsv2/core/kernel.h b/engines/mads/madsv2/core/kernel.h
index 7506aeaca85..a4fedba7a5c 100644
--- a/engines/mads/madsv2/core/kernel.h
+++ b/engines/mads/madsv2/core/kernel.h
@@ -290,7 +290,7 @@ typedef struct {
byte teleported_in; /* Flag if player teleported to room */
char interface[20]; /* Name of current interface animation */
- /* char sound_driver[20]; */ /* Name of current sound driver */
+ char sound_driver[20]; /* Name of current sound driver */
char *quotes; /* Quote list */
diff --git a/engines/mads/madsv2/engine.h b/engines/mads/madsv2/engine.h
index d2784871eb9..98531c12dd7 100644
--- a/engines/mads/madsv2/engine.h
+++ b/engines/mads/madsv2/engine.h
@@ -84,6 +84,7 @@ public:
virtual void global_parser_code() = 0;
virtual void global_error_code() = 0;
virtual void global_room_init() = 0;
+ virtual void global_sound_driver() = 0;
virtual void global_verb_filter() {}
};
diff --git a/engines/mads/madsv2/phantom/phantom.cpp b/engines/mads/madsv2/phantom/phantom.cpp
index 3db8596f429..420198a1d3c 100644
--- a/engines/mads/madsv2/phantom/phantom.cpp
+++ b/engines/mads/madsv2/phantom/phantom.cpp
@@ -802,6 +802,11 @@ void PhantomEngine::global_room_init() {
global[walker_converse_state] = 0;
}
+void PhantomEngine::global_sound_driver() {
+ Common::strcpy_s(kernel.sound_driver, "*#SOUND.PH");
+ env_catint(kernel.sound_driver, new_section, 1);
+}
+
} // namespace Phantom
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/phantom/phantom.h b/engines/mads/madsv2/phantom/phantom.h
index d3994c95b42..693e5fdeec2 100644
--- a/engines/mads/madsv2/phantom/phantom.h
+++ b/engines/mads/madsv2/phantom/phantom.h
@@ -51,6 +51,7 @@ public:
void global_parser_code() override;
void global_error_code() override;
void global_room_init() override;
+ void global_sound_driver() override;
};
} // namespace Phantom
Commit: 2c5404b90dc7e2e6e21be0fd4eeb27a54893ae29
https://github.com/scummvm/scummvm/commit/2c5404b90dc7e2e6e21be0fd4eeb27a54893ae29
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:16+10:00
Commit Message:
MADS: PHANTOM: Refactoring channel commands to be game specific
In the original sound driver from Rex Nebular, source bytes from
0xf1 to 0xff can denote special channel actions. However, in
Return of the Phantom, this is increased to 66 different actions.
This commit shifts the now known to be Rex Nebular specific
channel command switch to it's own intermediate subclass
between ASound and ASound(1-9).
Changed paths:
engines/mads/core/sound.cpp
engines/mads/core/sound.h
engines/mads/madsv2/phantom/sound_phantom.cpp
engines/mads/madsv2/phantom/sound_phantom.h
engines/mads/nebular/sound_nebular.cpp
engines/mads/nebular/sound_nebular.h
diff --git a/engines/mads/core/sound.cpp b/engines/mads/core/sound.cpp
index a838dadad1f..589e775e751 100644
--- a/engines/mads/core/sound.cpp
+++ b/engines/mads/core/sound.cpp
@@ -536,7 +536,7 @@ void ASound::pollActiveChannel() {
return;
}
- if (!(*pSrc & 0x80) || (*pSrc <= 0xF0)) {
+ if (!(*pSrc & 0x80) || (*pSrc <= (0xff - _chanCommandCount))) {
if (updateFlag)
updateActiveChannel();
@@ -555,162 +555,7 @@ void ASound::pollActiveChannel() {
break;
} else {
updateFlag = false;
-
- switch ((~*pSrc) & 0xF) {
- case 0:
- if (!chan->_field17) {
- if (*++pSrc == 0) {
- chan->_pSrc += 2;
- chan->_ptr3 = chan->_pSrc;
- chan->_field17 = 0;
- } else {
- chan->_field17 = *pSrc;
- chan->_pSrc = chan->_ptr3;
- }
- } else if (--chan->_field17) {
- chan->_pSrc = chan->_ptr3;
- } else {
- chan->_pSrc += 2;
- chan->_ptr3 = chan->_pSrc;
- }
- break;
-
- case 1:
- if (!chan->_field19) {
- if (*++pSrc == 0) {
- chan->_pSrc += 2;
- chan->_ptr4 = chan->_pSrc;
- chan->_ptr3 = chan->_pSrc;
- chan->_field17 = 0;
- chan->_field19 = 0;
- } else {
- chan->_field19 = *pSrc;
- chan->_pSrc = chan->_ptr4;
- chan->_ptr3 = chan->_ptr4;
- }
- } else if (--chan->_field19) {
- chan->_ptr4 = chan->_pSrc;
- chan->_ptr3 = chan->_pSrc;
- } else {
- chan->_pSrc += 2;
- chan->_ptr4 = chan->_pSrc;
- chan->_ptr3 = chan->_pSrc;
- }
- break;
-
- case 2:
- // Loop sound data
- chan->_field1 = 0;
- chan->_field2 = chan->_field3 = 0;
- chan->_volume = chan->_field7 = 0;
- chan->_field1D = chan->_volumeOffset = 0;
- chan->_field8 = 0;
- chan->_field9 = 0;
- chan->_fieldB = 0;
- chan->_field17 = 0;
- chan->_field19 = 0;
- chan->_fieldD = 0x40;
- chan->_ptr1 = chan->_soundData;
- chan->_pSrc = chan->_soundData;
- chan->_ptr3 = chan->_soundData;
- chan->_ptr4 = chan->_soundData;
-
- chan->_pSrc += 2;
- break;
-
- case 3:
- chan->_sampleIndex = *++pSrc;
- chan->_pSrc += 2;
- loadSample(chan->_sampleIndex);
- break;
-
- case 4:
- chan->_field7 = *++pSrc;
- chan->_pSrc += 2;
- break;
-
- case 5:
- chan->_field1 = *++pSrc;
- chan->_pSrc += 2;
- break;
-
- case 6:
- ++pSrc;
- if (chan->_fieldE) {
- chan->_pSrc += 2;
- } else {
- chan->_volume = *pSrc >> 1;
- updateFlag = true;
- chan->_pSrc += 2;
- }
- break;
-
- case 7:
- ++pSrc;
- if (!chan->_fieldE) {
- chan->_fieldA = *pSrc;
- chan->_field2 = *++pSrc;
- chan->_field9 = 1;
- }
-
- chan->_pSrc += 3;
- break;
-
- case 8:
- chan->_field1D = (int8) * ++pSrc;
- chan->_pSrc += 2;
- break;
-
- case 9:
- {
- int v1 = *++pSrc;
- ++pSrc;
- int v2 = (v1 - 1) & getRandomNumber();
- int v3 = pSrc[v2];
- int v4 = pSrc[v1];
-
- pSrc[v4 + v1 + 1] = v3;
- chan->_pSrc += v1 + 3;
- break;
- }
-
- case 10:
- ++pSrc;
- if (chan->_fieldE) {
- chan->_pSrc += 2;
- } else {
- chan->_volumeOffset = *pSrc >> 1;
- updateFlag = true;
- chan->_pSrc += 2;
- }
- break;
-
- case 11:
- chan->_fieldD = *++pSrc;
- updateFlag = true;
- chan->_pSrc += 2;
- break;
-
- case 12:
- chan->_fieldC = *++pSrc;
- chan->_field3 = *++pSrc;
- chan->_fieldB = 1;
- chan->_pSrc += 2;
- break;
-
- case 13:
- ++pSrc;
- chan->_pSrc += 2;
- break;
-
- case 14:
- chan->_field1F = *++pSrc;
- chan->_pSrc += 2;
- break;
-
- default:
- break;
- }
+ channelCommand(255 - *pSrc, pSrc, updateFlag);
}
}
}
diff --git a/engines/mads/core/sound.h b/engines/mads/core/sound.h
index c3a01351c9a..2657255d6a3 100644
--- a/engines/mads/core/sound.h
+++ b/engines/mads/core/sound.h
@@ -268,11 +268,6 @@ private:
void updateChannelState();
void updateActiveChannel();
- /**
- * Loads up the specified sample
- */
- void loadSample(int sampleIndex);
-
/**
* Writes out the data of the selected sample to the Adlib
*/
@@ -284,9 +279,18 @@ private:
* Timer function for OPL
*/
void onTimer();
+
protected:
+ int _chanCommandCount;
int _commandParam;
+ virtual void channelCommand(int cmdNum, byte *&pSrc, bool &updateFlag) = 0;
+
+ /**
+ * Loads up the specified sample
+ */
+ void loadSample(int sampleIndex);
+
/**
* Queue a byte for an Adlib register
*/
diff --git a/engines/mads/madsv2/phantom/sound_phantom.cpp b/engines/mads/madsv2/phantom/sound_phantom.cpp
index c2a49ccc3b4..afe2e7d0635 100644
--- a/engines/mads/madsv2/phantom/sound_phantom.cpp
+++ b/engines/mads/madsv2/phantom/sound_phantom.cpp
@@ -83,6 +83,15 @@ void PhantomSoundManager::loadDriver(int sectionNumber) {
/*-----------------------------------------------------------------------*/
+PhantomASound::PhantomASound(Audio::Mixer *mixer, OPL::OPL *opl, const Common::Path &filename, int dataOffset) :
+ ASound(mixer, opl, filename, dataOffset) {
+ _chanCommandCount = 66;
+}
+
+void PhantomASound::channelCommand(int cmdNum, byte *&pSrc, bool &updateFlag) {
+ // TODO
+}
+
/*-----------------------------------------------------------------------*/
/* ASound1 (asound.ph1) *
* *
@@ -110,7 +119,7 @@ const ASound1::CommandPtr ASound1::_commandList[40] = {
};
ASound1::ASound1(Audio::Mixer *mixer, OPL::OPL *opl)
- : ASound(mixer, opl, "asound.ph1", 0x21e0), _musicIndex(0) {
+ : PhantomASound(mixer, opl, "asound.ph1", 0x21e0) {
}
int ASound1::command(int commandId, int param) {
@@ -425,7 +434,7 @@ const ASound2::CommandPtr ASound2::_commandList[73] = {
};
ASound2::ASound2(Audio::Mixer *mixer, OPL::OPL *opl)
- : ASound(mixer, opl, "asound.ph2", 0x2040) {
+ : PhantomASound(mixer, opl, "asound.ph2", 0x2040) {
}
int ASound2::command(int commandId, int param) {
@@ -685,7 +694,7 @@ const ASound3::CommandPtr ASound3::_commandList[77] = {
};
ASound3::ASound3(Audio::Mixer *mixer, OPL::OPL *opl)
- : ASound(mixer, opl, "asound.ph3", 0x20c0) {
+ : PhantomASound(mixer, opl, "asound.ph3", 0x20c0) {
}
int ASound3::command(int commandId, int param) {
@@ -1004,7 +1013,7 @@ const ASound4::CommandPtr ASound4::_commandList[71] = {
};
ASound4::ASound4(Audio::Mixer *mixer, OPL::OPL *opl)
- : ASound(mixer, opl, "asound.ph4", 0x1f90) {
+ : PhantomASound(mixer, opl, "asound.ph4", 0x1f90) {
}
int ASound4::command(int commandId, int param) {
@@ -1193,7 +1202,7 @@ const ASound5::CommandPtr ASound5::_commandList[79] = {
};
ASound5::ASound5(Audio::Mixer *mixer, OPL::OPL *opl)
- : ASound(mixer, opl, "asound.ph5", 0x2140) {
+ : PhantomASound(mixer, opl, "asound.ph5", 0x2140) {
}
int ASound5::command(int commandId, int param) {
@@ -1512,7 +1521,7 @@ const ASound9::CommandPtr ASound9::_commandList[72] = {
&ASound9::command68, &ASound9::command69, &ASound9::command70, &ASound9::command71
};
-ASound9::ASound9(Audio::Mixer *mixer, OPL::OPL *opl) : ASound(mixer, opl, "asound.ph9", 0x20c0) {
+ASound9::ASound9(Audio::Mixer *mixer, OPL::OPL *opl) : PhantomASound(mixer, opl, "asound.ph9", 0x20c0) {
}
int ASound9::command(int commandId, int param) {
diff --git a/engines/mads/madsv2/phantom/sound_phantom.h b/engines/mads/madsv2/phantom/sound_phantom.h
index 21c0b1ceced..7b6a2805a3e 100644
--- a/engines/mads/madsv2/phantom/sound_phantom.h
+++ b/engines/mads/madsv2/phantom/sound_phantom.h
@@ -41,6 +41,21 @@ public:
void validate() override;
};
+class PhantomASound : public ASound {
+protected:
+ void channelCommand(int cmdNum, byte *&pSrc, bool &updateFlag) override;
+
+public:
+ /**
+ * Constructor
+ * @param mixer Mixer
+ * @param opl OPL
+ * @param filename Specifies the adlib sound player file to use
+ * @param dataOffset Offset in the file of the data segment
+ */
+ PhantomASound(Audio::Mixer *mixer, OPL::OPL *opl, const Common::Path &filename, int dataOffset);
+};
+
/**
* ASound1 (asound.ph1, _dataOffset = 0x21e0)
*
@@ -59,13 +74,13 @@ public:
* randomly picks from four music loaders and plays it, storing the choice
* in _musicIndex (mirrors word_11F5E in the original).
*/
-class ASound1 : public ASound {
+class ASound1 : public PhantomASound {
private:
typedef int (ASound1::*CommandPtr)();
static const CommandPtr _commandList[40];
// Mirrors word_11F5E: tracks which music piece was last selected.
- int _musicIndex;
+ int _musicIndex = 0;
// Background-music loaders (targets of the CS:0x1F60 indirect table).
int commandMusic0(); // sub_11D84 â starts at 0x1ECA
@@ -115,7 +130,7 @@ public:
* asound_commands4: commands 32â35 (max=0x23, base=0x20, 4 entries)
* asound_commands5: commands 64â72 (max=0x48, base=0x40, 9 entries)
*/
-class ASound2 : public ASound {
+class ASound2 : public PhantomASound {
private:
typedef int (ASound2::*CommandPtr)();
static const CommandPtr _commandList[73];
@@ -169,7 +184,7 @@ public:
* asound_commands5: commands 64â75 (max=0x4B, base=0x40, 12 entries)
* (command 76 = nullsub_8, silently ignored by bounds check)
*/
-class ASound3 : public ASound {
+class ASound3 : public PhantomASound {
private:
typedef int (ASound3::*CommandPtr)();
static const CommandPtr _commandList[77];
@@ -233,7 +248,7 @@ public:
*
* commands 24 and 25 share the same handler (sub_11D0A).
*/
-class ASound4 : public ASound {
+class ASound4 : public PhantomASound {
private:
typedef int (ASound4::*CommandPtr)();
static const CommandPtr _commandList[71];
@@ -283,7 +298,7 @@ public:
* commands 36/35/34 load channels in non-sequential data order.
* commands 70, 77, and 78 all play the same 0x40BA sound block.
*/
-class ASound5 : public ASound {
+class ASound5 : public PhantomASound {
private:
typedef int (ASound5::*CommandPtr)();
static const CommandPtr _commandList[79];
@@ -336,7 +351,7 @@ public:
int command(int commandId, int param) override;
};
-class ASound9 : public ASound {
+class ASound9 : public PhantomASound {
private:
typedef int (ASound9:: *CommandPtr)();
int command0();
diff --git a/engines/mads/nebular/sound_nebular.cpp b/engines/mads/nebular/sound_nebular.cpp
index 5949f0e44ca..09893f3fab6 100644
--- a/engines/mads/nebular/sound_nebular.cpp
+++ b/engines/mads/nebular/sound_nebular.cpp
@@ -95,6 +95,174 @@ void RexSoundManager::loadDriver(int sectionNumber) {
/*-----------------------------------------------------------------------*/
+RexASound::RexASound(Audio::Mixer *mixer, OPL::OPL *opl,
+ const Common::Path &filename, int dataOffset) :
+ ASound(mixer, opl, filename, dataOffset) {
+ _chanCommandCount = 15;
+}
+
+void RexASound::channelCommand(int cmdNum, byte *&pSrc, bool &updateFlag) {
+ AdlibChannel *chan = _activeChannelPtr;
+
+ switch (cmdNum) {
+ case 0:
+ if (!chan->_field17) {
+ if (*++pSrc == 0) {
+ chan->_pSrc += 2;
+ chan->_ptr3 = chan->_pSrc;
+ chan->_field17 = 0;
+ } else {
+ chan->_field17 = *pSrc;
+ chan->_pSrc = chan->_ptr3;
+ }
+ } else if (--chan->_field17) {
+ chan->_pSrc = chan->_ptr3;
+ } else {
+ chan->_pSrc += 2;
+ chan->_ptr3 = chan->_pSrc;
+ }
+ break;
+
+ case 1:
+ if (!chan->_field19) {
+ if (*++pSrc == 0) {
+ chan->_pSrc += 2;
+ chan->_ptr4 = chan->_pSrc;
+ chan->_ptr3 = chan->_pSrc;
+ chan->_field17 = 0;
+ chan->_field19 = 0;
+ } else {
+ chan->_field19 = *pSrc;
+ chan->_pSrc = chan->_ptr4;
+ chan->_ptr3 = chan->_ptr4;
+ }
+ } else if (--chan->_field19) {
+ chan->_ptr4 = chan->_pSrc;
+ chan->_ptr3 = chan->_pSrc;
+ } else {
+ chan->_pSrc += 2;
+ chan->_ptr4 = chan->_pSrc;
+ chan->_ptr3 = chan->_pSrc;
+ }
+ break;
+
+ case 2:
+ // Loop sound data
+ chan->_field1 = 0;
+ chan->_field2 = chan->_field3 = 0;
+ chan->_volume = chan->_field7 = 0;
+ chan->_field1D = chan->_volumeOffset = 0;
+ chan->_field8 = 0;
+ chan->_field9 = 0;
+ chan->_fieldB = 0;
+ chan->_field17 = 0;
+ chan->_field19 = 0;
+ chan->_fieldD = 0x40;
+ chan->_ptr1 = chan->_soundData;
+ chan->_pSrc = chan->_soundData;
+ chan->_ptr3 = chan->_soundData;
+ chan->_ptr4 = chan->_soundData;
+
+ chan->_pSrc += 2;
+ break;
+
+ case 3:
+ chan->_sampleIndex = *++pSrc;
+ chan->_pSrc += 2;
+ loadSample(chan->_sampleIndex);
+ break;
+
+ case 4:
+ chan->_field7 = *++pSrc;
+ chan->_pSrc += 2;
+ break;
+
+ case 5:
+ chan->_field1 = *++pSrc;
+ chan->_pSrc += 2;
+ break;
+
+ case 6:
+ ++pSrc;
+ if (chan->_fieldE) {
+ chan->_pSrc += 2;
+ } else {
+ chan->_volume = *pSrc >> 1;
+ updateFlag = true;
+ chan->_pSrc += 2;
+ }
+ break;
+
+ case 7:
+ ++pSrc;
+ if (!chan->_fieldE) {
+ chan->_fieldA = *pSrc;
+ chan->_field2 = *++pSrc;
+ chan->_field9 = 1;
+ }
+
+ chan->_pSrc += 3;
+ break;
+
+ case 8:
+ chan->_field1D = (int8) * ++pSrc;
+ chan->_pSrc += 2;
+ break;
+
+ case 9:
+ {
+ int v1 = *++pSrc;
+ ++pSrc;
+ int v2 = (v1 - 1) & getRandomNumber();
+ int v3 = pSrc[v2];
+ int v4 = pSrc[v1];
+
+ pSrc[v4 + v1 + 1] = v3;
+ chan->_pSrc += v1 + 3;
+ break;
+ }
+
+ case 10:
+ ++pSrc;
+ if (chan->_fieldE) {
+ chan->_pSrc += 2;
+ } else {
+ chan->_volumeOffset = *pSrc >> 1;
+ updateFlag = true;
+ chan->_pSrc += 2;
+ }
+ break;
+
+ case 11:
+ chan->_fieldD = *++pSrc;
+ updateFlag = true;
+ chan->_pSrc += 2;
+ break;
+
+ case 12:
+ chan->_fieldC = *++pSrc;
+ chan->_field3 = *++pSrc;
+ chan->_fieldB = 1;
+ chan->_pSrc += 2;
+ break;
+
+ case 13:
+ ++pSrc;
+ chan->_pSrc += 2;
+ break;
+
+ case 14:
+ chan->_field1F = *++pSrc;
+ chan->_pSrc += 2;
+ break;
+
+ default:
+ break;
+ }
+}
+
+/*-----------------------------------------------------------------------*/
+
const ASound1::CommandPtr ASound1::_commandList[42] = {
&ASound1::command0, &ASound1::command1, &ASound1::command2, &ASound1::command3,
&ASound1::command4, &ASound1::command5, &ASound1::command6, &ASound1::command7,
@@ -110,7 +278,7 @@ const ASound1::CommandPtr ASound1::_commandList[42] = {
};
ASound1::ASound1(Audio::Mixer *mixer, OPL::OPL *opl)
- : ASound(mixer, opl, "asound.001", 0x1520) {
+ : RexASound(mixer, opl, "asound.001", 0x1520) {
_cmd23Toggle = false;
// Load sound samples
@@ -410,7 +578,7 @@ const ASound2::CommandPtr ASound2::_commandList[44] = {
&ASound2::command40, &ASound2::command41, &ASound2::command42, &ASound2::command43
};
-ASound2::ASound2(Audio::Mixer *mixer, OPL::OPL *opl) : ASound(mixer, opl, "asound.002", 0x15E0) {
+ASound2::ASound2(Audio::Mixer *mixer, OPL::OPL *opl) : RexASound(mixer, opl, "asound.002", 0x15E0) {
_command12Param = 0xFD;
// Load sound samples
@@ -781,7 +949,7 @@ const ASound3::CommandPtr ASound3::_commandList[61] = {
&ASound3::command60
};
-ASound3::ASound3(Audio::Mixer *mixer, OPL::OPL *opl) : ASound(mixer, opl, "asound.003", 0x15B0) {
+ASound3::ASound3(Audio::Mixer *mixer, OPL::OPL *opl) : RexASound(mixer, opl, "asound.003", 0x15B0) {
_command39Flag = false;
// Load sound samples
@@ -1185,7 +1353,7 @@ const ASound4::CommandPtr ASound4::_commandList[61] = {
&ASound4::command60
};
-ASound4::ASound4(Audio::Mixer *mixer, OPL::OPL *opl) : ASound(mixer, opl, "asound.004", 0x14F0) {
+ASound4::ASound4(Audio::Mixer *mixer, OPL::OPL *opl) : RexASound(mixer, opl, "asound.004", 0x14F0) {
// Load sound samples
_soundFile.seek(_dataOffset + 0x122);
for (int i = 0; i < 210; ++i)
@@ -1441,7 +1609,7 @@ const ASound5::CommandPtr ASound5::_commandList[42] = {
&ASound5::command40, &ASound5::command41
};
-ASound5::ASound5(Audio::Mixer *mixer, OPL::OPL *opl) : ASound(mixer, opl, "asound.002", 0x15E0) {
+ASound5::ASound5(Audio::Mixer *mixer, OPL::OPL *opl) : RexASound(mixer, opl, "asound.002", 0x15E0) {
// Load sound samples
_soundFile.seek(_dataOffset + 0x144);
for (int i = 0; i < 164; ++i)
@@ -1682,7 +1850,7 @@ const ASound6::CommandPtr ASound6::_commandList[30] = {
&ASound6::nullCommand, &ASound6::command29
};
-ASound6::ASound6(Audio::Mixer *mixer, OPL::OPL *opl) : ASound(mixer, opl, "asound.006", 0x1390) {
+ASound6::ASound6(Audio::Mixer *mixer, OPL::OPL *opl) : RexASound(mixer, opl, "asound.006", 0x1390) {
// Load sound samples
_soundFile.seek(_dataOffset + 0x122);
for (int i = 0; i < 200; ++i)
@@ -1838,7 +2006,7 @@ const ASound7::CommandPtr ASound7::_commandList[38] = {
&ASound7::command36, &ASound7::command37
};
-ASound7::ASound7(Audio::Mixer *mixer, OPL::OPL *opl) : ASound(mixer, opl, "asound.007", 0x1460) {
+ASound7::ASound7(Audio::Mixer *mixer, OPL::OPL *opl) : RexASound(mixer, opl, "asound.007", 0x1460) {
// Load sound samples
_soundFile.seek(_dataOffset + 0x122);
for (int i = 0; i < 214; ++i)
@@ -2044,7 +2212,7 @@ const ASound8::CommandPtr ASound8::_commandList[38] = {
&ASound8::command36, &ASound8::command37
};
-ASound8::ASound8(Audio::Mixer *mixer, OPL::OPL *opl) : ASound(mixer, opl, "asound.008", 0x1490) {
+ASound8::ASound8(Audio::Mixer *mixer, OPL::OPL *opl) : RexASound(mixer, opl, "asound.008", 0x1490) {
// Load sound samples
_soundFile.seek(_dataOffset + 0x122);
for (int i = 0; i < 174; ++i)
@@ -2300,7 +2468,7 @@ const ASound9::CommandPtr ASound9::_commandList[52] = {
&ASound9::command48, &ASound9::command49, &ASound9::command50, &ASound9::command51
};
-ASound9::ASound9(Audio::Mixer *mixer, OPL::OPL *opl) : ASound(mixer, opl, "asound.009", 0x16F0) {
+ASound9::ASound9(Audio::Mixer *mixer, OPL::OPL *opl) : RexASound(mixer, opl, "asound.009", 0x16F0) {
_v1 = _v2 = 0;
_soundPtr = nullptr;
diff --git a/engines/mads/nebular/sound_nebular.h b/engines/mads/nebular/sound_nebular.h
index 5b9b5670dc9..29ffd927bcb 100644
--- a/engines/mads/nebular/sound_nebular.h
+++ b/engines/mads/nebular/sound_nebular.h
@@ -40,7 +40,16 @@ public:
void validate() override;
};
-class ASound1 : public ASound {
+class RexASound : public ASound {
+protected:
+ void channelCommand(int cmdNum, byte *&pSrc, bool &updateFlag) override;
+
+public:
+ RexASound(Audio::Mixer *mixer, OPL::OPL *opl,
+ const Common::Path &filename, int dataOffset);
+};
+
+class ASound1 : public RexASound {
private:
typedef int (ASound1::*CommandPtr)();
static const CommandPtr _commandList[42];
@@ -88,7 +97,7 @@ public:
int command(int commandId, int param) override;
};
-class ASound2 : public ASound {
+class ASound2 : public RexASound {
private:
byte _command12Param;
private:
@@ -140,7 +149,7 @@ public:
int command(int commandId, int param) override;
};
-class ASound3 : public ASound {
+class ASound3 : public RexASound {
private:
bool _command39Flag;
@@ -200,7 +209,7 @@ public:
int command(int commandId, int param) override;
};
-class ASound4 : public ASound {
+class ASound4 : public RexASound {
private:
typedef int (ASound4::*CommandPtr)();
static const CommandPtr _commandList[61];
@@ -238,7 +247,7 @@ public:
int command(int commandId, int param) override;
};
-class ASound5 : public ASound {
+class ASound5 : public RexASound {
private:
typedef int (ASound5::*CommandPtr)();
static const CommandPtr _commandList[42];
@@ -284,7 +293,7 @@ public:
int command(int commandId, int param) override;
};
-class ASound6 : public ASound {
+class ASound6 : public RexASound {
private:
typedef int (ASound6::*CommandPtr)();
static const CommandPtr _commandList[30];
@@ -313,7 +322,7 @@ public:
int command(int commandId, int param) override;
};
-class ASound7 : public ASound {
+class ASound7 : public RexASound {
private:
typedef int (ASound7::*CommandPtr)();
static const CommandPtr _commandList[38];
@@ -345,7 +354,7 @@ public:
int command(int commandId, int param) override;
};
-class ASound8 : public ASound {
+class ASound8 : public RexASound {
private:
typedef int (ASound8::*CommandPtr)();
static const CommandPtr _commandList[38];
@@ -388,7 +397,7 @@ public:
int command(int commandId, int param) override;
};
-class ASound9 : public ASound {
+class ASound9 : public RexASound {
private:
int _v1, _v2;
byte *_soundPtr;
Commit: 2fe9311066708de40cf44b1dc75acd729555a3b8
https://github.com/scummvm/scummvm/commit/2fe9311066708de40cf44b1dc75acd729555a3b8
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:16+10:00
Commit Message:
MADS: PHANTOM: Claude generated Phantom channel commands
Changed paths:
engines/mads/core/sound.cpp
engines/mads/core/sound.h
engines/mads/madsv2/phantom/sound_phantom.cpp
engines/mads/madsv2/phantom/sound_phantom.h
engines/mads/nebular/sound_nebular.cpp
engines/mads/nebular/sound_nebular.h
diff --git a/engines/mads/core/sound.cpp b/engines/mads/core/sound.cpp
index 589e775e751..3cae76883f8 100644
--- a/engines/mads/core/sound.cpp
+++ b/engines/mads/core/sound.cpp
@@ -157,6 +157,11 @@ AdlibChannel::AdlibChannel() {
_field1F = 0;
_field20 = 0;
+ _field26 = 0;
+ _field28 = 0;
+ _field2A = 0;
+ _field2B = 0;
+ _field2C = 0;
}
void AdlibChannel::reset() {
@@ -353,6 +358,16 @@ void ASound::noise() {
}
}
+byte *ASound::getDataPtr(int nearPtr) {
+ for (auto i = _dataCache.begin(); i != _dataCache.end(); ++i) {
+ CachedDataEntry &e = *i;
+ int entrySize = (int)(e._dataEnd - e._data) + 1;
+ if (nearPtr >= e._offset && nearPtr < e._offset + entrySize)
+ return e._data + (nearPtr - e._offset);
+ }
+ return nullptr;
+}
+
CachedDataEntry &ASound::getCachedData(byte *pData) {
Common::List<CachedDataEntry>::iterator i;
for (i = _dataCache.begin(); i != _dataCache.end(); ++i) {
@@ -555,7 +570,7 @@ void ASound::pollActiveChannel() {
break;
} else {
updateFlag = false;
- channelCommand(255 - *pSrc, pSrc, updateFlag);
+ channelCommand(pSrc, updateFlag);
}
}
}
diff --git a/engines/mads/core/sound.h b/engines/mads/core/sound.h
index 2657255d6a3..5f0d8896193 100644
--- a/engines/mads/core/sound.h
+++ b/engines/mads/core/sound.h
@@ -161,6 +161,13 @@ public:
// TODO: Only used by asound.003. Figure out usage
byte _field20;
+
+ // Phantom-specific fields
+ int _field26; // pitch delta (set in case -14, zeroed in case -3)
+ int _field28; // zeroed in case -3
+ int _field2A; // set in case -18
+ int _field2B; // volume-cap flag (suppresses upward volume changes)
+ int _field2C; // frequency counter (used with _field7 in cases -9/-10)
public:
static bool _channelsEnabled;
public:
@@ -284,7 +291,7 @@ protected:
int _chanCommandCount;
int _commandParam;
- virtual void channelCommand(int cmdNum, byte *&pSrc, bool &updateFlag) = 0;
+ virtual void channelCommand(byte *&pSrc, bool &updateFlag) = 0;
/**
* Loads up the specified sample
@@ -356,6 +363,12 @@ protected:
*/
int getRandomNumber();
+ /**
+ * Converts a 16-bit near pointer (data-segment offset) to a C++ byte pointer
+ * by searching the data cache for the matching block.
+ */
+ byte *getDataPtr(int nearPtr);
+
virtual int command0();
int command1();
int command2();
diff --git a/engines/mads/madsv2/phantom/sound_phantom.cpp b/engines/mads/madsv2/phantom/sound_phantom.cpp
index afe2e7d0635..419917985c1 100644
--- a/engines/mads/madsv2/phantom/sound_phantom.cpp
+++ b/engines/mads/madsv2/phantom/sound_phantom.cpp
@@ -19,6 +19,7 @@
*
*/
+#include "common/endian.h"
#include "common/md5.h"
#include "common/textconsole.h"
#include "mads/madsv2/phantom/sound_phantom.h"
@@ -86,10 +87,546 @@ void PhantomSoundManager::loadDriver(int sectionNumber) {
PhantomASound::PhantomASound(Audio::Mixer *mixer, OPL::OPL *opl, const Common::Path &filename, int dataOffset) :
ASound(mixer, opl, filename, dataOffset) {
_chanCommandCount = 66;
-}
+ memset(_scratchArr, 0, sizeof(_scratchArr));
+}
+
+void PhantomASound::channelCommand(byte *&pSrc, bool &updateFlag) {
+ AdlibChannel *chan = _activeChannelPtr;
+ int cmdNum = (int8)*pSrc; // -1 .. -66
+
+ switch (cmdNum) {
+
+ case -1:
+ // Single-level repeat loop (uses _field17 / _ptr3)
+ if (!chan->_field17) {
+ if (pSrc[1] == 0) {
+ chan->_pSrc += 2;
+ chan->_ptr3 = chan->_pSrc;
+ chan->_field17 = 0;
+ } else {
+ chan->_field17 = (int8)pSrc[1];
+ chan->_pSrc = chan->_ptr3;
+ }
+ } else {
+ --chan->_field17;
+ if (!chan->_field17) {
+ chan->_pSrc += 2;
+ chan->_ptr3 = chan->_pSrc;
+ } else {
+ chan->_pSrc = chan->_ptr3;
+ }
+ }
+ break;
+
+ case -2:
+ // Double-level repeat loop (uses _field19/_ptr4 outer, _field17/_ptr3 inner)
+ if (!chan->_field19) {
+ if (pSrc[1] == 0) {
+ chan->_pSrc += 2;
+ chan->_ptr4 = chan->_pSrc;
+ chan->_ptr3 = chan->_pSrc;
+ chan->_field17 = 0;
+ chan->_field19 = 0;
+ } else {
+ chan->_field19 = (int8)pSrc[1];
+ chan->_pSrc = chan->_ptr4;
+ chan->_ptr3 = chan->_ptr4;
+ }
+ } else {
+ --chan->_field19;
+ if (!chan->_field19) {
+ chan->_pSrc += 2;
+ chan->_ptr4 = chan->_pSrc;
+ chan->_ptr3 = chan->_pSrc;
+ } else {
+ chan->_pSrc = chan->_ptr4;
+ chan->_ptr3 = chan->_ptr4;
+ }
+ }
+ break;
+
+ case -3:
+ // Reset channel to soundData start
+ chan->_fieldE = 0; // original stored soundData near ptr here
+ chan->_pSrc = chan->_soundData;
+ chan->_ptr3 = chan->_soundData;
+ chan->_ptr4 = chan->_soundData;
+ chan->_field1 = 0;
+ chan->_field2 = 0;
+ chan->_field3 = 0;
+ chan->_field26 = 0;
+ chan->_volumeOffset = 0;
+ chan->_field28 = 0;
+ chan->_volume = 0;
+ chan->_field9 = 0;
+ chan->_fieldB = 0;
+ chan->_field17 = 0;
+ chan->_field19 = 0;
+ chan->_field7 = 0;
+ break;
+
+ case -4: {
+ // Jump: set all four data pointers from a near-pointer word argument
+ ++pSrc;
+ int nearPtr = (int16)READ_LE_UINT16(pSrc);
+ byte *p = getDataPtr(nearPtr);
+ chan->_fieldE = nearPtr;
+ chan->_pSrc = p;
+ chan->_ptr3 = p;
+ chan->_ptr4 = p;
+ chan->_soundData = p;
+ break;
+ }
+
+ case -5: {
+ // Unconditional jump to near-pointer target (no return address saved)
+ ++pSrc;
+ int nearPtr = (int16)READ_LE_UINT16(pSrc);
+ chan->_pSrc = getDataPtr(nearPtr);
+ break;
+ }
+
+ case -6: {
+ // Unconditional call to near-pointer target (saves return address in _ptrEnd)
+ ++pSrc;
+ int nearPtr = (int16)READ_LE_UINT16(pSrc);
+ chan->_ptrEnd = chan->_pSrc + 3;
+ chan->_pSrc = getDataPtr(nearPtr);
+ break;
+ }
+
+ case -7:
+ // Return from call (restores _pSrc from _ptrEnd)
+ if (chan->_ptrEnd) {
+ chan->_pSrc = chan->_ptrEnd;
+ chan->_ptrEnd = nullptr;
+ } else {
+ chan->_pSrc += 1;
+ }
+ break;
+
+ case -8:
+ // Load sample: byte argument is sample index
+ chan->_sampleIndex = pSrc[1];
+ chan->_pSrc += 2;
+ loadSample(chan->_sampleIndex);
+ break;
+
+ case -9:
+ // Set _field7 (pitch source), clear _field2C (frequency counter)
+ chan->_field7 = pSrc[1];
+ chan->_field2C = 0;
+ chan->_pSrc += 2;
+ break;
+
+ case -10:
+ // Set _field2C (frequency counter), clear _field7
+ chan->_field2C = pSrc[1];
+ chan->_field7 = 0;
+ chan->_pSrc += 2;
+ break;
+
+ case -11:
+ // Set _field1 (envelope / modulation)
+ chan->_field1 = pSrc[1];
+ chan->_pSrc += 2;
+ break;
+
+ case -12:
+ // Set volume, capped downward if _field2B (mute flag) is active
+ {
+ int val = (int8)pSrc[1];
+ if (chan->_field2B) {
+ if (chan->_volume > val)
+ chan->_volume = val;
+ } else {
+ chan->_volume = val;
+ }
+ updateFlag = true;
+ chan->_pSrc += 2;
+ }
+ break;
+
+ case -13:
+ // Set _fieldA and _field2 (vibrato params), or skip if muted
+ if (chan->_field2B) {
+ chan->_pSrc += 3;
+ } else {
+ chan->_fieldA = pSrc[1];
+ chan->_field2 = pSrc[2];
+ chan->_field9 = 1;
+ chan->_pSrc += 3;
+ }
+ break;
+
+ case -14:
+ // Set _field26 (pitch delta)
+ chan->_field26 = pSrc[1];
+ chan->_pSrc += 2;
+ break;
+
+ case -15:
+ // Set _volumeOffset, capped downward if _field2B (mute flag) is active
+ {
+ int val = (int8)pSrc[1];
+ if (chan->_field2B) {
+ if ((int8)chan->_volumeOffset > val)
+ chan->_volumeOffset = val;
+ } else {
+ chan->_volumeOffset = val;
+ }
+ updateFlag = true;
+ chan->_pSrc += 2;
+ }
+ break;
+
+ case -16:
+ // Set _fieldD (volume increment step)
+ chan->_fieldD = pSrc[1];
+ updateFlag = true;
+ chan->_pSrc += 2;
+ break;
+
+ case -17:
+ // Set _fieldC (period) and _field3 (volume slide), enable slide (_fieldB=1)
+ chan->_fieldC = pSrc[1];
+ chan->_field3 = pSrc[2];
+ chan->_fieldB = 1;
+ chan->_pSrc += 3;
+ break;
+
+ case -18:
+ // Set _field2A
+ chan->_field2A = pSrc[1];
+ chan->_pSrc += 2;
+ break;
+
+ case -19:
+ // Relative skip: advance by (signed byte arg) + 3
+ chan->_pSrc += (int8)pSrc[1] + 3;
+ break;
+
+ case -20: {
+ // Pick random element from array[0..N-1], write chosen value to a
+ // self-modifying offset within the sound data
+ int n = (byte)pSrc[1];
+ byte *base = pSrc + 2;
+ int rnd = getRandomNumber() & 0x7FFF;
+ int idx = rnd % n;
+ byte chosen = base[idx];
+ int destIdx = (int8)base[n];
+ base[destIdx + n + 1] = chosen;
+ chan->_pSrc += n + 3;
+ break;
+ }
+
+ case -21: {
+ // Pick random value in [lower..upper], write to a self-modifying offset
+ int lower = (int8)pSrc[1];
+ int upper = (int8)pSrc[2];
+ int range = upper - lower + 1;
+ int rnd = getRandomNumber() & 0x7FFF;
+ byte *base = pSrc + 3;
+ int destIdx = (int8)base[0];
+ base[destIdx + 1] = (byte)(rnd % range + lower);
+ chan->_pSrc += 4;
+ break;
+ }
+
+ case -22: {
+ // Like -20 but array index is read from _scratchArr[regIdx]
+ int regIdx = (byte)pSrc[1];
+ int n = (byte)pSrc[2];
+ byte *base = pSrc + 3;
+ int arrVal = _scratchArr[regIdx];
+ byte chosen = base[arrVal];
+ int destOffset = (int8)base[n];
+ base[destOffset + n + 1] = chosen;
+ chan->_pSrc += n + 4;
+ break;
+ }
+
+ case -23:
+ // arr[dest] = literal
+ _scratchArr[(byte)pSrc[1]] = (byte)pSrc[2];
+ chan->_pSrc += 3;
+ break;
+
+ case -24:
+ // arr[dest] = arr[src]
+ _scratchArr[(byte)pSrc[1]] = _scratchArr[(byte)pSrc[2]];
+ chan->_pSrc += 3;
+ break;
+
+ case -25:
+ // Write arr[regIdx] into sound data at pSrc[offset+3]
+ pSrc[(int8)pSrc[2] + 3] = _scratchArr[(byte)pSrc[1]];
+ chan->_pSrc += 3;
+ break;
+
+ case -26:
+ // arr[idx]++
+ ++_scratchArr[(byte)pSrc[1]];
+ chan->_pSrc += 2;
+ break;
+
+ case -27:
+ // arr[idx]--
+ --_scratchArr[(byte)pSrc[1]];
+ chan->_pSrc += 2;
+ break;
+
+ case -28:
+ // arr[dest] += literal
+ _scratchArr[(byte)pSrc[1]] += (byte)pSrc[2];
+ chan->_pSrc += 3;
+ break;
+
+ case -29:
+ // arr[dest] += arr[src]
+ _scratchArr[(byte)pSrc[1]] += _scratchArr[(byte)pSrc[2]];
+ chan->_pSrc += 3;
+ break;
+
+ case -30:
+ // arr[dest] -= literal
+ _scratchArr[(byte)pSrc[1]] -= (byte)pSrc[2];
+ chan->_pSrc += 3;
+ break;
+
+ case -31:
+ // arr[dest] -= arr[src]
+ _scratchArr[(byte)pSrc[1]] -= _scratchArr[(byte)pSrc[2]];
+ chan->_pSrc += 3;
+ break;
+
+ case -32:
+ // arr[dest] = literal * arr[dest] (byte multiply, low byte)
+ _scratchArr[(byte)pSrc[1]] = (byte)((byte)pSrc[2] * _scratchArr[(byte)pSrc[1]]);
+ chan->_pSrc += 3;
+ break;
+
+ case -33:
+ // arr[dest] = arr[src] * arr[dest] (byte multiply, low byte)
+ _scratchArr[(byte)pSrc[1]] = (byte)(_scratchArr[(byte)pSrc[2]] * _scratchArr[(byte)pSrc[1]]);
+ chan->_pSrc += 3;
+ break;
-void PhantomASound::channelCommand(int cmdNum, byte *&pSrc, bool &updateFlag) {
- // TODO
+ case -34:
+ // arr[dest] /= literal (quotient)
+ _scratchArr[(byte)pSrc[1]] = (byte)(_scratchArr[(byte)pSrc[1]] / (int8)pSrc[2]);
+ chan->_pSrc += 3;
+ break;
+
+ case -35:
+ // arr[dest] /= arr[src] (quotient, unsigned)
+ _scratchArr[(byte)pSrc[1]] = (byte)(_scratchArr[(byte)pSrc[1]] / _scratchArr[(byte)pSrc[2]]);
+ chan->_pSrc += 3;
+ break;
+
+ case -36:
+ // arr[dest] %= literal (remainder)
+ _scratchArr[(byte)pSrc[1]] = (byte)(_scratchArr[(byte)pSrc[1]] % (int8)pSrc[2]);
+ chan->_pSrc += 3;
+ break;
+
+ case -37:
+ // arr[dest] %= arr[src] (remainder, unsigned)
+ _scratchArr[(byte)pSrc[1]] = (byte)(_scratchArr[(byte)pSrc[1]] % _scratchArr[(byte)pSrc[2]]);
+ chan->_pSrc += 3;
+ break;
+
+ case -38:
+ // arr[dest] &= literal
+ _scratchArr[(byte)pSrc[1]] &= (byte)pSrc[2];
+ chan->_pSrc += 3;
+ break;
+
+ case -39:
+ // arr[dest] &= arr[src]
+ _scratchArr[(byte)pSrc[1]] &= _scratchArr[(byte)pSrc[2]];
+ chan->_pSrc += 3;
+ break;
+
+ case -40:
+ // arr[dest] |= literal
+ _scratchArr[(byte)pSrc[1]] |= (byte)pSrc[2];
+ chan->_pSrc += 3;
+ break;
+
+ case -41:
+ // arr[dest] |= arr[src]
+ _scratchArr[(byte)pSrc[1]] |= _scratchArr[(byte)pSrc[2]];
+ chan->_pSrc += 3;
+ break;
+
+ case -42:
+ // arr[dest] ^= literal
+ _scratchArr[(byte)pSrc[1]] ^= (byte)pSrc[2];
+ chan->_pSrc += 3;
+ break;
+
+ case -43:
+ // arr[dest] ^= arr[src]
+ _scratchArr[(byte)pSrc[1]] ^= _scratchArr[(byte)pSrc[2]];
+ chan->_pSrc += 3;
+ break;
+
+ // Cases -44 to -51: conditional jumps (5-byte: cmd, idx, literal/idx2, ptr_lo, ptr_hi)
+ // Branch taken â jump to near-pointer target (bytes 3-4)
+ // Branch not taken â skip 5 bytes
+
+#define PHANTOM_COND_JUMP(cond) \
+ do { \
+ if (cond) { \
+ int nearPtr = (int16)READ_LE_UINT16(pSrc + 3); \
+ chan->_pSrc = getDataPtr(nearPtr); \
+ } else { \
+ chan->_pSrc += 5; \
+ } \
+ } while (0)
+
+ case -44:
+ PHANTOM_COND_JUMP(_scratchArr[(byte)pSrc[1]] == (byte)pSrc[2]);
+ break;
+
+ case -45:
+ PHANTOM_COND_JUMP(_scratchArr[(byte)pSrc[1]] != (byte)pSrc[2]);
+ break;
+
+ case -46:
+ // arr[idx] < literal (jmp if below the cap)
+ PHANTOM_COND_JUMP(_scratchArr[(byte)pSrc[1]] < (byte)pSrc[2]);
+ break;
+
+ case -47:
+ // arr[idx] > literal
+ PHANTOM_COND_JUMP(_scratchArr[(byte)pSrc[1]] > (byte)pSrc[2]);
+ break;
+
+ case -48:
+ PHANTOM_COND_JUMP(_scratchArr[(byte)pSrc[2]] == _scratchArr[(byte)pSrc[1]]);
+ break;
+
+ case -49:
+ PHANTOM_COND_JUMP(_scratchArr[(byte)pSrc[2]] != _scratchArr[(byte)pSrc[1]]);
+ break;
+
+ case -50:
+ // arr[idx2] > arr[idx1] (unsigned)
+ PHANTOM_COND_JUMP(_scratchArr[(byte)pSrc[2]] > _scratchArr[(byte)pSrc[1]]);
+ break;
+
+ case -51:
+ // arr[idx2] < arr[idx1] (unsigned)
+ PHANTOM_COND_JUMP(_scratchArr[(byte)pSrc[2]] < _scratchArr[(byte)pSrc[1]]);
+ break;
+
+#undef PHANTOM_COND_JUMP
+
+ // Cases -52 to -59: conditional calls â same as -44..-51 but save return address
+ // Branch taken â save (chan->_pSrc + 5) in _ptrEnd, then jump to target
+ // Branch not taken â skip 5 bytes
+
+#define PHANTOM_COND_CALL(cond) \
+ do { \
+ if (cond) { \
+ int nearPtr = (int16)READ_LE_UINT16(pSrc + 3); \
+ chan->_ptrEnd = chan->_pSrc + 5; \
+ chan->_pSrc = getDataPtr(nearPtr); \
+ } else { \
+ chan->_pSrc += 5; \
+ } \
+ } while (0)
+
+ case -52:
+ PHANTOM_COND_CALL(_scratchArr[(byte)pSrc[1]] == (byte)pSrc[2]);
+ break;
+
+ case -53:
+ PHANTOM_COND_CALL(_scratchArr[(byte)pSrc[1]] != (byte)pSrc[2]);
+ break;
+
+ case -54:
+ // arr[idx] < literal
+ PHANTOM_COND_CALL(_scratchArr[(byte)pSrc[1]] < (byte)pSrc[2]);
+ break;
+
+ case -55:
+ // arr[idx] > literal
+ PHANTOM_COND_CALL(_scratchArr[(byte)pSrc[1]] > (byte)pSrc[2]);
+ break;
+
+ case -56:
+ PHANTOM_COND_CALL(_scratchArr[(byte)pSrc[2]] == _scratchArr[(byte)pSrc[1]]);
+ break;
+
+ case -57:
+ PHANTOM_COND_CALL(_scratchArr[(byte)pSrc[2]] != _scratchArr[(byte)pSrc[1]]);
+ break;
+
+ case -58:
+ // arr[idx2] > arr[idx1] (unsigned)
+ PHANTOM_COND_CALL(_scratchArr[(byte)pSrc[2]] > _scratchArr[(byte)pSrc[1]]);
+ break;
+
+ case -59:
+ // arr[idx2] < arr[idx1] (unsigned)
+ PHANTOM_COND_CALL(_scratchArr[(byte)pSrc[2]] < _scratchArr[(byte)pSrc[1]]);
+ break;
+
+#undef PHANTOM_COND_CALL
+
+ case -60:
+ // Call near function pointer â not translatable to C++; skip 3-byte command
+ chan->_pSrc += 3;
+ break;
+
+ case -61:
+ // No-op with 2-byte command (original called a null stub)
+ chan->_pSrc += 2;
+ break;
+
+ case -62:
+ // Skip 4 bytes (advance past this 4-byte command)
+ chan->_pSrc += 4;
+ break;
+
+ case -63:
+ // Store signed byte into _w11F50 music state variable
+ _w11F50 = (int8)pSrc[1];
+ chan->_pSrc += 2;
+ break;
+
+ case -64:
+ // Store signed byte into _w11F46; if _w11F44 == 0, also copy to _w11F4E
+ _w11F46 = (int8)pSrc[1];
+ chan->_pSrc += 2;
+ if (!_w11F44)
+ _w11F4E = _w11F46;
+ break;
+
+ case -65: {
+ // Store 16-bit word into _w11F48; signal music sync (_w11F32/_w11F42 = 1)
+ ++pSrc;
+ _w11F48 = (int16)READ_LE_UINT16(pSrc);
+ chan->_pSrc = pSrc + 2; // advance 3 bytes total from command
+ if (!_w11F44)
+ _w11F4C = _w11F48;
+ _w11F32 = 1;
+ _w11F42 = 1;
+ break;
+ }
+
+ case -66:
+ // Store signed byte into _w11F4A music state variable
+ _w11F4A = (int8)pSrc[1];
+ chan->_pSrc += 2;
+ break;
+
+ default:
+ break;
+ }
}
/*-----------------------------------------------------------------------*/
diff --git a/engines/mads/madsv2/phantom/sound_phantom.h b/engines/mads/madsv2/phantom/sound_phantom.h
index 7b6a2805a3e..19e2936e75c 100644
--- a/engines/mads/madsv2/phantom/sound_phantom.h
+++ b/engines/mads/madsv2/phantom/sound_phantom.h
@@ -43,7 +43,15 @@ public:
class PhantomASound : public ASound {
protected:
- void channelCommand(int cmdNum, byte *&pSrc, bool &updateFlag) override;
+ // Per-driver scripting register file (256 byte-sized registers)
+ byte _scratchArr[256];
+
+ // Music synchronisation state variables (mirrors word_11F32 etc.)
+ int _w11F32 = 0, _w11F42 = 0, _w11F44 = 0;
+ int _w11F46 = 0, _w11F48 = 0, _w11F4A = 0;
+ int _w11F4C = 0, _w11F4E = 0, _w11F50 = 0;
+
+ void channelCommand(byte *&pSrc, bool &updateFlag) override;
public:
/**
diff --git a/engines/mads/nebular/sound_nebular.cpp b/engines/mads/nebular/sound_nebular.cpp
index 09893f3fab6..3d6d7c54b44 100644
--- a/engines/mads/nebular/sound_nebular.cpp
+++ b/engines/mads/nebular/sound_nebular.cpp
@@ -101,8 +101,9 @@ RexASound::RexASound(Audio::Mixer *mixer, OPL::OPL *opl,
_chanCommandCount = 15;
}
-void RexASound::channelCommand(int cmdNum, byte *&pSrc, bool &updateFlag) {
+void RexASound::channelCommand(byte *&pSrc, bool &updateFlag) {
AdlibChannel *chan = _activeChannelPtr;
+ int cmdNum = 255 - *pSrc;
switch (cmdNum) {
case 0:
diff --git a/engines/mads/nebular/sound_nebular.h b/engines/mads/nebular/sound_nebular.h
index 29ffd927bcb..fe5b232bc4e 100644
--- a/engines/mads/nebular/sound_nebular.h
+++ b/engines/mads/nebular/sound_nebular.h
@@ -42,7 +42,7 @@ public:
class RexASound : public ASound {
protected:
- void channelCommand(int cmdNum, byte *&pSrc, bool &updateFlag) override;
+ void channelCommand(byte *&pSrc, bool &updateFlag) override;
public:
RexASound(Audio::Mixer *mixer, OPL::OPL *opl,
Commit: efd3d0b47690c370f7ff853d0fd662bbf295bad4
https://github.com/scummvm/scummvm/commit/efd3d0b47690c370f7ff853d0fd662bbf295bad4
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:16+10:00
Commit Message:
MADS: PHANTOM: Load sound driver sample list
Changed paths:
engines/mads/madsv2/phantom/sound_phantom.cpp
diff --git a/engines/mads/madsv2/phantom/sound_phantom.cpp b/engines/mads/madsv2/phantom/sound_phantom.cpp
index 419917985c1..c3f744154e1 100644
--- a/engines/mads/madsv2/phantom/sound_phantom.cpp
+++ b/engines/mads/madsv2/phantom/sound_phantom.cpp
@@ -88,6 +88,12 @@ PhantomASound::PhantomASound(Audio::Mixer *mixer, OPL::OPL *opl, const Common::P
ASound(mixer, opl, filename, dataOffset) {
_chanCommandCount = 66;
memset(_scratchArr, 0, sizeof(_scratchArr));
+
+ // Load sound samples - all the asound drivers have an identical set of 120
+ // samples starting at offset 1d4h in their data segment
+ _soundFile.seek(_dataOffset + 0x1d4);
+ for (int i = 0; i < 120; ++i)
+ _samples.push_back(AdlibSample(_soundFile));
}
void PhantomASound::channelCommand(byte *&pSrc, bool &updateFlag) {
Commit: 81a2aaa0305fb4cb86a1b0da719fdadb7aa2d839
https://github.com/scummvm/scummvm/commit/81a2aaa0305fb4cb86a1b0da719fdadb7aa2d839
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:17+10:00
Commit Message:
MADS: PHANTOM: Cleanup of config file reading
Changed paths:
engines/mads/detection_tables.h
engines/mads/madsv2/core/config.cpp
engines/mads/madsv2/core/global.cpp
engines/mads/madsv2/core/global.h
engines/mads/madsv2/engine.cpp
engines/mads/madsv2/engine.h
engines/mads/madsv2/phantom/main.cpp
engines/mads/madsv2/phantom/phantom.h
diff --git a/engines/mads/detection_tables.h b/engines/mads/detection_tables.h
index 980cbd64ea8..518d574a525 100644
--- a/engines/mads/detection_tables.h
+++ b/engines/mads/detection_tables.h
@@ -156,7 +156,7 @@ static const MADSGameDescription gameDescriptions[] = {
Common::EN_ANY,
Common::kPlatformDOS,
ADGF_UNSTABLE,
- GUIO1(GAMEOPTION_EASY_MOUSE)
+ GUIO2(GUIO_NOMUSIC, GAMEOPTION_EASY_MOUSE)
},
GType_Phantom,
0
diff --git a/engines/mads/madsv2/core/config.cpp b/engines/mads/madsv2/core/config.cpp
index a8a5af4c5df..36f7c371d30 100644
--- a/engines/mads/madsv2/core/config.cpp
+++ b/engines/mads/madsv2/core/config.cpp
@@ -49,9 +49,9 @@ void read_config_file() {
ConfMan.registerDefault("show_speech_boxes", true);
ConfMan.registerDefault("difficulty", -1);
- config_file.music_flag = !ConfMan.getBool("music_mute");
- config_file.sound_flag = !ConfMan.getBool("sfx_mute");
- config_file.speech_flag = !ConfMan.getBool("speech_mute");
+ config_file.music_flag = !ConfMan.getBool("music_mute") && !ConfMan.getBool("mute");
+ config_file.sound_flag = !ConfMan.getBool("sfx_mute") && !ConfMan.getBool("mute");
+ config_file.speech_flag = !ConfMan.getBool("speech_mute") && !ConfMan.getBool("mute");
config_file.interface_hotspots = ConfMan.getInt("interface_hotspots");
config_file.inventory_mode = ConfMan.getInt("inventory_spinning");
diff --git a/engines/mads/madsv2/core/global.cpp b/engines/mads/madsv2/core/global.cpp
index ece4b13c9cc..54d17ae20a6 100644
--- a/engines/mads/madsv2/core/global.cpp
+++ b/engines/mads/madsv2/core/global.cpp
@@ -72,10 +72,6 @@ void global_section_constructor() {
g_engine->global_section_constructor();
}
-void global_read_config_file() {
- read_config_file();
-}
-
void global_write_config_file() {
write_config_file();
}
diff --git a/engines/mads/madsv2/core/global.h b/engines/mads/madsv2/core/global.h
index 31ab2e15859..cb436efa363 100644
--- a/engines/mads/madsv2/core/global.h
+++ b/engines/mads/madsv2/core/global.h
@@ -118,7 +118,6 @@ void global_room_init(void);
void global_verb_filter(void);
void global_sound_driver(void);
void global_section_constructor(void);
-void global_read_config_file(void);
void global_write_config_file(void);
void global_load_config_parameters(void);
void global_unload_config_parameters(void);
diff --git a/engines/mads/madsv2/engine.cpp b/engines/mads/madsv2/engine.cpp
index 71d8fb9497d..562563f8c10 100644
--- a/engines/mads/madsv2/engine.cpp
+++ b/engines/mads/madsv2/engine.cpp
@@ -22,6 +22,7 @@
#include "common/system.h"
#include "engines/util.h"
#include "mads/madsv2/engine.h"
+#include "mads/madsv2/core/config.h"
#include "mads/madsv2/core/kernel.h"
#include "mads/madsv2/phantom/main.h"
#include "mads/core/sound.h"
@@ -35,7 +36,7 @@ constexpr int GAME_FRAME_TIME = 1000 / GAME_FRAME_RATE;
MADSV2Engine *g_engine;
MADSV2Engine::MADSV2Engine(OSystem *syst, const MADSGameDescription *gameDesc) :
- MADSEngine(syst, gameDesc) {
+ MADSEngine(syst, gameDesc) {
g_engine = this;
}
@@ -45,6 +46,13 @@ MADSV2Engine::~MADSV2Engine() {
delete _soundManager;
}
+void MADSV2Engine::readConfigFile() {
+ read_config_file();
+ _musicFlag = config_file.music_flag;
+ _soundFlag = config_file.sound_flag;
+ _speechFlag = config_file.speech_flag;
+}
+
void MADSV2Engine::pollEvents() {
// Check for screen update time
uint32 time = g_system->getMillis();
diff --git a/engines/mads/madsv2/engine.h b/engines/mads/madsv2/engine.h
index 98531c12dd7..df429649934 100644
--- a/engines/mads/madsv2/engine.h
+++ b/engines/mads/madsv2/engine.h
@@ -45,10 +45,14 @@ protected:
public:
MADS::SoundManager *_soundManager = nullptr;
+ bool _musicFlag = true;
+ bool _soundFlag = true;
+ bool _speechFlag = true;
public:
MADSV2Engine(OSystem *syst, const MADSGameDescription *gameDesc);
~MADSV2Engine() override;
+ void readConfigFile();
Graphics::Screen *getScreen() const {
return _screen;
diff --git a/engines/mads/madsv2/phantom/main.cpp b/engines/mads/madsv2/phantom/main.cpp
index bbf4b024356..0b5274c7c26 100644
--- a/engines/mads/madsv2/phantom/main.cpp
+++ b/engines/mads/madsv2/phantom/main.cpp
@@ -168,7 +168,7 @@ static void game_main(int argc, const char **argv) {
game_cold_data_init();
main_cold_data_init();
- global_read_config_file();
+ g_engine->readConfigFile();
global_load_config_parameters();
if (argc >= 2) {
diff --git a/engines/mads/madsv2/phantom/phantom.h b/engines/mads/madsv2/phantom/phantom.h
index 693e5fdeec2..ac9bd2a2b34 100644
--- a/engines/mads/madsv2/phantom/phantom.h
+++ b/engines/mads/madsv2/phantom/phantom.h
@@ -30,8 +30,6 @@ namespace Phantom {
class PhantomEngine : public MADSV2Engine {
private:
- bool _soundFlag = true;
-
static void global_object_sprite();
static void stop_walker_basic();
static void stop_walker_tricks();
Commit: d109e396a81a78307939fb017c8635c489d83123
https://github.com/scummvm/scummvm/commit/d109e396a81a78307939fb017c8635c489d83123
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:17+10:00
Commit Message:
MADS: PHANTOM: Fix main menu event handling
Changed paths:
engines/mads/madsv2/engine.cpp
diff --git a/engines/mads/madsv2/engine.cpp b/engines/mads/madsv2/engine.cpp
index 562563f8c10..8c4e39caace 100644
--- a/engines/mads/madsv2/engine.cpp
+++ b/engines/mads/madsv2/engine.cpp
@@ -66,7 +66,7 @@ void MADSV2Engine::pollEvents() {
// Poll for events
Common::Event e;
- while (g_system->getEventManager()->pollEvent(e) && game.going) {
+ while (g_system->getEventManager()->pollEvent(e)) {
bool isMouse = false;
switch (e.type) {
case Common::EVENT_LBUTTONDOWN:
Commit: 4b10f801c4406fc7e6907a7b94a2ee4ed2af3f52
https://github.com/scummvm/scummvm/commit/4b10f801c4406fc7e6907a7b94a2ee4ed2af3f52
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:17+10:00
Commit Message:
MADS: PHANTOM: Remove unused midi.cpp/.h
Changed paths:
R engines/mads/madsv2/core/midi.cpp
R engines/mads/madsv2/core/midi.h
engines/mads/madsv2/core/error.cpp
engines/mads/madsv2/core/game.cpp
engines/mads/madsv2/core/kernel.cpp
engines/mads/madsv2/core/popup.cpp
engines/mads/module.mk
diff --git a/engines/mads/madsv2/core/error.cpp b/engines/mads/madsv2/core/error.cpp
index 90149f37d0d..ffd9a82c258 100644
--- a/engines/mads/madsv2/core/error.cpp
+++ b/engines/mads/madsv2/core/error.cpp
@@ -34,7 +34,6 @@
#include "mads/madsv2/core/popup.h"
#include "mads/madsv2/core/keys.h"
#include "mads/madsv2/core/mem.h"
-#include "mads/madsv2/core/midi.h"
namespace MADS {
namespace MADSV2 {
diff --git a/engines/mads/madsv2/core/game.cpp b/engines/mads/madsv2/core/game.cpp
index 9670383452d..2bb4c5c0f0d 100644
--- a/engines/mads/madsv2/core/game.cpp
+++ b/engines/mads/madsv2/core/game.cpp
@@ -59,7 +59,6 @@
#include "mads/madsv2/core/kernel.h"
#include "mads/madsv2/core/config.h"
#include "mads/madsv2/core/fileio.h"
-#include "mads/madsv2/core/midi.h"
#include "mads/madsv2/core/copy.h"
#include "mads/madsv2/core/camera.h"
#include "mads/madsv2/core/quote.h"
diff --git a/engines/mads/madsv2/core/kernel.cpp b/engines/mads/madsv2/core/kernel.cpp
index cc6c987bda4..4a4cf81e7ec 100644
--- a/engines/mads/madsv2/core/kernel.cpp
+++ b/engines/mads/madsv2/core/kernel.cpp
@@ -51,7 +51,6 @@
#include "mads/madsv2/core/env.h"
#include "mads/madsv2/core/fileio.h"
#include "mads/madsv2/core/vocab.h"
-#include "mads/madsv2/core/midi.h"
#include "mads/madsv2/core/rail.h"
#include "mads/madsv2/core/hspot.h"
#include "mads/madsv2/core/attr.h"
diff --git a/engines/mads/madsv2/core/midi.cpp b/engines/mads/madsv2/core/midi.cpp
deleted file mode 100644
index e7cb7ebd7b2..00000000000
--- a/engines/mads/madsv2/core/midi.cpp
+++ /dev/null
@@ -1,57 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include "common/textconsole.h"
-#include "mads/madsv2/core/midi.h"
-
-namespace MADS {
-namespace MADSV2 {
-
-void midi_install() {
- // No implementation in ScummVM
-}
-
-void midi_uninstall() {
- // No implementation in ScummVM
-}
-
-void midi_play(char name[30]) {
- warning("TODO: midi_play");
-}
-
-void midi_stop() {
- warning("TODO: midi_stop");
-}
-
-void midi_pause() {
- warning("TODO: midi_pause");
-}
-
-void midi_resume() {
- warning("TODO: midi_resume");
-}
-
-void midi_loop() {
- warning("TODO: midi_loop");
-}
-
-} // namespace MADSV2
-} // namespace MADS
diff --git a/engines/mads/madsv2/core/midi.h b/engines/mads/madsv2/core/midi.h
deleted file mode 100644
index 577535db268..00000000000
--- a/engines/mads/madsv2/core/midi.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#ifndef MADS_CORE_MIDI_H
-#define MADS_CORE_MIDI_H
-
-#include "mads/madsv2/core/general.h"
-#include "mads/madsv2/core/room.h"
-#include "mads/madsv2/core/color.h"
-
-namespace MADS {
-namespace MADSV2 {
-
-void midi_install(void);
-void midi_play(char name[30]);
-void midi_stop(void);
-void midi_pause(void);
-void midi_resume(void);
-void midi_loop(void);
-void midi_uninstall(void);
-
-} // namespace MADSV2
-} // namespace MADS
-
-#endif
diff --git a/engines/mads/madsv2/core/popup.cpp b/engines/mads/madsv2/core/popup.cpp
index c9387e8600a..155f66909d6 100644
--- a/engines/mads/madsv2/core/popup.cpp
+++ b/engines/mads/madsv2/core/popup.cpp
@@ -34,7 +34,6 @@
#include "mads/madsv2/core/keys.h"
#include "mads/madsv2/core/timer.h"
#include "mads/madsv2/core/sprite.h"
-#include "mads/madsv2/core/midi.h"
#include "mads/madsv2/core/screen.h"
#include "mads/madsv2/core/game.h"
#include "mads/madsv2/core/pal.h"
@@ -3384,8 +3383,6 @@ PopupItem *popup_execute(void) {
mouse_init_cycle();
do {
- midi_loop();
-
mouse_begin_cycle(false);
if (keys_any()) {
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index 7797d0b18cb..c96c18f8ef4 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -98,7 +98,6 @@ MODULE_OBJS += \
madsv2/core/matte.o \
madsv2/core/mcga.o \
madsv2/core/mem.o \
- madsv2/core/midi.o \
madsv2/core/mouse.o \
madsv2/core/object.o \
madsv2/core/pack.o \
Commit: 0ba693202e25a5c91c33a1634491f9d996e7fcec
https://github.com/scummvm/scummvm/commit/0ba693202e25a5c91c33a1634491f9d996e7fcec
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:17+10:00
Commit Message:
MADS: PHANTOM: Fix loading interface backgrounds
Changed paths:
engines/mads/madsv2/core/inter.cpp
engines/mads/madsv2/core/inter.h
engines/mads/madsv2/core/kernel.cpp
diff --git a/engines/mads/madsv2/core/inter.cpp b/engines/mads/madsv2/core/inter.cpp
index 855f58c7b90..1662a5c954a 100644
--- a/engines/mads/madsv2/core/inter.cpp
+++ b/engines/mads/madsv2/core/inter.cpp
@@ -2280,7 +2280,7 @@ void inter_main_loop(int allow_input) {
}
-int inter_load_background(char *name, Buffer *target) {
+int inter_load_background(const char *name, Buffer *target) {
Color color[16];
int count;
int error_flag = true;
diff --git a/engines/mads/madsv2/core/inter.h b/engines/mads/madsv2/core/inter.h
index 4cd8b3c87bf..59be261a2f6 100644
--- a/engines/mads/madsv2/core/inter.h
+++ b/engines/mads/madsv2/core/inter.h
@@ -290,7 +290,7 @@ extern void inter_reset_dialog(void);
extern int inter_add_dialog(char *string, int result);
/* inter_2.c */
-extern int inter_load_background(char *name, Buffer *target);
+extern int inter_load_background(const char *name, Buffer *target);
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/core/kernel.cpp b/engines/mads/madsv2/core/kernel.cpp
index 4a4cf81e7ec..465f462e4ae 100644
--- a/engines/mads/madsv2/core/kernel.cpp
+++ b/engines/mads/madsv2/core/kernel.cpp
@@ -2919,7 +2919,7 @@ done:
void kernel_set_interface_mode(int mode) {
if (mode != inter_input_mode) {
char fname[80];
- Common::strcpy_s(fname, kernel.interface + 1);
+ Common::strcpy_s(fname, kernel.interface);
char *dot = strchr(fname, '.');
if (dot) {
Commit: c2132a850505e1118b554f35668c6f7f7dd47a2e
https://github.com/scummvm/scummvm/commit/c2132a850505e1118b554f35668c6f7f7dd47a2e
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:18+10:00
Commit Message:
MADS: PHANTOM: Fixes for conversation variable loading
Conversation variables can be either variables or pointers.
When a pointer, a 16-bit mode value is set with 0xffff.
However, loading data for conversation 2, the default
variable #2 has a mode of '7011', which I'm presuming is
invalid data. So for now I'm making loading more strict
to only accept 0xffff as a valid indication of a pointer.
And only if found it'll still throw an error, since we
don't support loading pointers yet (there's no translation).
This will similarly be a problem for saving as well. If it
ends up trying to save any pointer variables, we'll have to
have some code that handles it properly. Maybe some kind of
enum instead of the actual pointer to a set of known
pointer destinations.
Changed paths:
engines/mads/detection.cpp
engines/mads/mads.h
engines/mads/madsv2/core/conv.cpp
diff --git a/engines/mads/detection.cpp b/engines/mads/detection.cpp
index 485826f68f3..a16ba8a9566 100644
--- a/engines/mads/detection.cpp
+++ b/engines/mads/detection.cpp
@@ -40,6 +40,7 @@ static const DebugChannelDef debugFlagList[] = {
{MADS::kDebugPath, "Path", "Pathfinding debug level"},
{MADS::kDebugScripts, "scripts", "Game scripts"},
{MADS::kDebugGraphics, "graphics", "Graphics handling"},
+ {MADS::kDebugConversations, "conv", "Game conversations"},
DEBUG_CHANNEL_END
};
diff --git a/engines/mads/mads.h b/engines/mads/mads.h
index 2b8117edcc7..723ef63ead7 100644
--- a/engines/mads/mads.h
+++ b/engines/mads/mads.h
@@ -40,6 +40,7 @@ enum MADSDebugChannels {
kDebugPath = 1,
kDebugScripts,
kDebugGraphics,
+ kDebugConversations
};
enum ScreenFade {
diff --git a/engines/mads/madsv2/core/conv.cpp b/engines/mads/madsv2/core/conv.cpp
index db7b25ab67e..fc5ec169d7a 100644
--- a/engines/mads/madsv2/core/conv.cpp
+++ b/engines/mads/madsv2/core/conv.cpp
@@ -20,6 +20,7 @@
*/
#include "common/algorithm.h"
+#include "common/debug.h"
#include "common/hashmap.h"
#include "common/hash-str.h"
#include "common/memstream.h"
@@ -37,6 +38,7 @@
#include "mads/madsv2/core/mem.h"
#include "mads/madsv2/core/popup.h"
#include "mads/madsv2/core/speech.h"
+#include "mads/mads.h"
namespace MADS {
namespace MADSV2 {
@@ -108,10 +110,14 @@ void ConvScriptParams::load(Common::SeekableReadStream *src) {
}
void ConvVariable::load(Common::SeekableReadStream *src) {
- (void)src->readUint16LE(); // isPtr
- isPtr = false;
+ uint16 flag = src->readUint16LE();
+ isPtr = flag == 0xffff;
val = src->readSint16LE();
- (void)src->readUint16LE(); // skip space for pointer segments
+ int16 seg = src->readUint16LE();
+
+ if (isPtr && flag != 0xffff)
+ debugC(1, kDebugConversations, "Invalid conv pointer: %.4x:%.4x", seg, val);
+ assert(!isPtr);
}
void ConvVariable::save(Common::WriteStream *dest) const {
Commit: f927e5c5a20781b846150b972a54fb37f60b7b2c
https://github.com/scummvm/scummvm/commit/f927e5c5a20781b846150b972a54fb37f60b7b2c
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:18+10:00
Commit Message:
MADS: PHANTOM: Handle seralizing ConvVariable pointers
Changed paths:
engines/mads/madsv2/core/conv.cpp
engines/mads/madsv2/core/conv.h
diff --git a/engines/mads/madsv2/core/conv.cpp b/engines/mads/madsv2/core/conv.cpp
index fc5ec169d7a..20c279ef603 100644
--- a/engines/mads/madsv2/core/conv.cpp
+++ b/engines/mads/madsv2/core/conv.cpp
@@ -111,20 +111,45 @@ void ConvScriptParams::load(Common::SeekableReadStream *src) {
void ConvVariable::load(Common::SeekableReadStream *src) {
uint16 flag = src->readUint16LE();
- isPtr = flag == 0xffff;
+ assert(flag != 0xffff); // TODO: See if original game has pointers for any conv
+ isPtr = flag == MKTAG16('V', 'M');
+
val = src->readSint16LE();
- int16 seg = src->readUint16LE();
+ uint16 type = src->readUint16LE();
- if (isPtr && flag != 0xffff)
- debugC(1, kDebugConversations, "Invalid conv pointer: %.4x:%.4x", seg, val);
- assert(!isPtr);
+ if (isPtr) {
+ switch (type) {
+ case PTRTYPE_GLOBAL:
+ ptr = global + val;
+ break;
+ case PTRTYPE_CONV_CONTROL:
+ if (val >= 0 && val < 20) {
+ // Index into one of the sequential 5 element arrays:
+ // speaker_frame[5], x[5], y[5], width[5]
+ ptr = conv_control.speaker_frame + val;
+ } else if (val == 20) {
+ ptr = &conv_control.speaker_val;
+ } else {
+ error("Unknown ConvVariable conv_control pointer");
+ }
+ break;
+ default:
+ error("Unknown ConvVariable pointer type");
+ break;
+ }
+ }
}
void ConvVariable::save(Common::WriteStream *dest) const {
- assert(!isPtr);
- dest->writeSint16LE(0);
- dest->writeSint16LE(val);
- dest->writeSint16LE(0);
+ if (isPtr) {
+ dest->writeUint16LE(MKTAG16('V', 'M'));
+ dest->writeSint16LE(val);
+ dest->writeSint16LE(type);
+ } else {
+ dest->writeUint16LE(0);
+ dest->writeSint16LE(val);
+ dest->writeSint16LE(0);
+ }
}
void ConvData::load(Common::SeekableReadStream *src) {
@@ -283,6 +308,22 @@ static void conv_set_variable(int idx, int16 *ptr) {
var.isPtr = true;
var.ptr = ptr;
+
+ // We need to know what kind of pointer it is so it can be properly serialized
+ if (ptr >= global && ptr < (global + GLOBAL_LIST_SIZE)) {
+ var.type = ConvVariable::PTRTYPE_GLOBAL;
+ var.val = ptr - global;
+ } else if (ptr >= conv_control.speaker_frame && ptr < conv_control.speaker_frame + 20) {
+ // Index into one of the sequential 5 element arrays:
+ // speaker_frame[5], x[5], y[5], width[5]
+ var.type = ConvVariable::PTRTYPE_CONV_CONTROL;
+ var.val = ptr - conv_control.speaker_frame;
+ } else if (ptr == &conv_control.speaker_val) {
+ var.type = ConvVariable::PTRTYPE_CONV_CONTROL;
+ var.val = 20;
+ } else {
+ error("Unhandled ConvVariable pointer type");
+ }
}
}
@@ -294,6 +335,7 @@ static void conv_set_variable(int idx, int16 val) {
var.isPtr = false;
var.val = val;
+ var.type = 0;
}
}
diff --git a/engines/mads/madsv2/core/conv.h b/engines/mads/madsv2/core/conv.h
index a89115514b0..a41002fb69d 100644
--- a/engines/mads/madsv2/core/conv.h
+++ b/engines/mads/madsv2/core/conv.h
@@ -94,11 +94,11 @@ struct ConvScriptParams {
};
struct ConvVariable {
+ enum PtrType { PTRTYPE_GLOBAL = 1, PTRTYPE_CONV_CONTROL = 2 };
+
bool isPtr = false;
- union {
- int16 val;
- int16 *ptr;
- };
+ int16 val = 0, type = 0;
+ int16 *ptr;
static constexpr int SIZE = 2 * 3;
void load(Common::SeekableReadStream *src);
Commit: 9326926020b158d325e420694c5ddfc4965cd880
https://github.com/scummvm/scummvm/commit/9326926020b158d325e420694c5ddfc4965cd880
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:18+10:00
Commit Message:
MADS: PHANTOM: Preliminary can save/load currently checks
Changed paths:
engines/mads/madsv2/engine.cpp
engines/mads/madsv2/engine.h
diff --git a/engines/mads/madsv2/engine.cpp b/engines/mads/madsv2/engine.cpp
index 8c4e39caace..473d8c8035c 100644
--- a/engines/mads/madsv2/engine.cpp
+++ b/engines/mads/madsv2/engine.cpp
@@ -23,6 +23,9 @@
#include "engines/util.h"
#include "mads/madsv2/engine.h"
#include "mads/madsv2/core/config.h"
+#include "mads/madsv2/core/conv.h"
+#include "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/inter.h"
#include "mads/madsv2/core/kernel.h"
#include "mads/madsv2/phantom/main.h"
#include "mads/core/sound.h"
@@ -53,6 +56,12 @@ void MADSV2Engine::readConfigFile() {
_speechFlag = config_file.speech_flag;
}
+bool MADSV2Engine::canLoadGameStateCurrently(Common::U32String *msg) {
+ return game.going && !win_status && !kernel.activate_menu &&
+ inter_input_mode == INTER_BUILDING_SENTENCES &&
+ conv_control.running == -1;
+}
+
void MADSV2Engine::pollEvents() {
// Check for screen update time
uint32 time = g_system->getMillis();
diff --git a/engines/mads/madsv2/engine.h b/engines/mads/madsv2/engine.h
index df429649934..ed503171c00 100644
--- a/engines/mads/madsv2/engine.h
+++ b/engines/mads/madsv2/engine.h
@@ -80,6 +80,11 @@ public:
return 0;
}
+ bool canLoadGameStateCurrently(Common::U32String *msg) override;
+ bool canSaveGameStateCurrently(Common::U32String *msg) override {
+ return canLoadGameStateCurrently(msg);
+ }
+
virtual void global_init_code() = 0;
virtual void section_music(int section_num) = 0;
virtual void global_section_constructor() = 0;
Commit: 5ba0a96969d67aa78cfb1d42d4f3fa12860ffc25
https://github.com/scummvm/scummvm/commit/5ba0a96969d67aa78cfb1d42d4f3fa12860ffc25
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:19+10:00
Commit Message:
MADS: PHANTOM: Hooking up engine saving/loading
Changed paths:
engines/mads/madsv2/core/game.cpp
engines/mads/madsv2/core/inter.cpp
engines/mads/madsv2/core/inter.h
engines/mads/madsv2/core/kernel.cpp
engines/mads/madsv2/core/kernel.h
engines/mads/madsv2/core/object.cpp
engines/mads/madsv2/core/object.h
engines/mads/madsv2/core/player.cpp
engines/mads/madsv2/core/player.h
engines/mads/madsv2/engine.cpp
engines/mads/madsv2/engine.h
engines/mads/madsv2/phantom/menus.cpp
engines/mads/metaengine.cpp
diff --git a/engines/mads/madsv2/core/game.cpp b/engines/mads/madsv2/core/game.cpp
index 2bb4c5c0f0d..b0fb1fce8d6 100644
--- a/engines/mads/madsv2/core/game.cpp
+++ b/engines/mads/madsv2/core/game.cpp
@@ -72,7 +72,7 @@ namespace MADSV2 {
extern long mem_used;
extern long mem_avail_at_start;
-extern int room_state[40];
+extern int16 room_state[40];
#define MOVE_YOUR_BUTT_TIMEOUT 3600
@@ -1347,8 +1347,10 @@ void game_control() {
force_chain = true;
}
} else {
+#if 0
game.going = (byte)!kernel_load_game(save_game_buf);
if (!game.going) force_chain = true;
+#endif
}
}
@@ -1676,8 +1678,12 @@ emergency:
if (!game.going && !win_status) {
conv_control.running = aborted_conv;
+#if 0
game_save_name(0);
kernel_save_game(save_game_buf);
+#else
+ warning("TODO: Original save dialog saves");
+#endif
game_autosaved = true;
} else {
game_autosaved = false;
diff --git a/engines/mads/madsv2/core/inter.cpp b/engines/mads/madsv2/core/inter.cpp
index 1662a5c954a..2c78626351d 100644
--- a/engines/mads/madsv2/core/inter.cpp
+++ b/engines/mads/madsv2/core/inter.cpp
@@ -213,8 +213,10 @@ void inter_spin_object(int object_id);
void inter_turn_off_object(void);
-void VerbBuf::load(Common::SeekableReadStream *src) {
- src->readMultipleLE(id, verb_type, prep_type);
+void VerbBuf::synchronize(Common::Serializer &s) {
+ s.syncAsUint16LE(id);
+ s.syncAsByte(verb_type);
+ s.syncAsByte(prep_type);
}
diff --git a/engines/mads/madsv2/core/inter.h b/engines/mads/madsv2/core/inter.h
index 59be261a2f6..c33d077c938 100644
--- a/engines/mads/madsv2/core/inter.h
+++ b/engines/mads/madsv2/core/inter.h
@@ -22,6 +22,7 @@
#ifndef MADS_CORE_INTER_H
#define MADS_CORE_INTER_H
+#include "common/serializer.h"
#include "mads/madsv2/core/general.h"
#include "mads/madsv2/core/anim.h"
@@ -161,7 +162,7 @@ struct VerbBuf {
byte verb_type;
byte prep_type;
- void load(Common::SeekableReadStream *src);
+ void synchronize(Common::Serializer &s);
};
typedef struct VerbBuf Verb;
@@ -195,6 +196,7 @@ extern int inven[INVEN_MAX_OBJECTS]; /* Inventory index */
extern int inven_num_objects; /* Inventory size */
extern int active_inven; /* The selected inventory item */
+extern int first_inven;
extern int right_command; /* Right mouse main verb */
extern int left_command; /* Left mouse main verb */
diff --git a/engines/mads/madsv2/core/kernel.cpp b/engines/mads/madsv2/core/kernel.cpp
index 465f462e4ae..f0d8fd6bf54 100644
--- a/engines/mads/madsv2/core/kernel.cpp
+++ b/engines/mads/madsv2/core/kernel.cpp
@@ -67,8 +67,7 @@ namespace MADSV2 {
extern int first_inven;
-#define OMR 40 /* OUAF_MAX_ROOMS in global.mac */
-int room_state[OMR];
+int16 room_state[OMR];
byte video_mode;
RoomPtr room = NULL;
@@ -160,6 +159,16 @@ static void kernel_seq_image(SequencePtr sequence, ImagePtr image, int sequence_
static void kernel_reconstruct_screen(int anim_handle);
static void kernel_animation_get_sprite(int handle, int id);
+void KernelGame::synchronize(Common::Serializer &s) {
+ s.syncAsByte(going);
+ s.skip(1);
+ for (int i = 0; i < KERNEL_SCRATCH_SIZE; ++i)
+ s.syncAsSint16LE(scratch[i]);
+ s.syncAsByte(difficulty);
+ s.skip(1);
+ s.syncAsSint16LE(last_save);
+}
+
int kernel_load_vocab() {
int error_flag;
@@ -2657,119 +2666,6 @@ void kernel_dump_walker_only() {
player.walker_visible = false;
}
-int kernel_save_game(const char *filename) {
- int error_flag = true;
- Load load_handle;
-
- load_handle.open = false;
-
- // TODO: Proper endian/saving
- if (loader_open(&load_handle, filename, "wb", PACK_NONE)) goto done;
-
- if (!loader_write(&game, sizeof(KernelGame), 1, &load_handle)) goto done;
- if (!loader_write(&room_id, sizeof(int), 1, &load_handle)) goto done;
- if (!loader_write(&player2, sizeof(Player2), 1, &load_handle)) goto done;
- if (!loader_write(&inven_num_objects, sizeof(int), 1, &load_handle)) goto done;
- if (inven_num_objects) {
- if (!loader_write(inven, sizeof(int) * inven_num_objects, 1, &load_handle)) goto done;
- }
- if (!loader_write(&player, sizeof(Player), 1, &load_handle)) goto done;
- if (!loader_write(global, sizeof(int) * global_list_size, 1, &load_handle)) goto done;
- if (!loader_write(object, sizeof(Object) * num_objects, 1, &load_handle)) goto done;
- if (!loader_write(0, sizeof(int), 1, &load_handle)) goto done;
- if (!loader_write(&conv_control.running, sizeof(int16), 1, &load_handle)) goto done;
-
- if (!loader_write(&picture_view_x, sizeof(int), 1, &load_handle)) goto done;
- if (!loader_write(&picture_view_y, sizeof(int), 1, &load_handle)) goto done;
-
- if (!loader_write(room_state, sizeof(int) * OMR, 1, &load_handle)) goto done;
- if (!loader_write(&previous_room, sizeof(int), 1, &load_handle)) goto done;
-#ifdef TODO
- if (conv_append(load_handle.handle)) goto done;
-#endif
- error_flag = false;
-
-done:
- if (load_handle.open) loader_close(&load_handle);
- return error_flag;
-}
-
-int kernel_load_game(const char *filename) {
- int error_flag = true;
- Load load_handle;
- int save;
-
- save = player.walker_is_loaded;
-
- /*
- keep_video_mode = kernel.video_mode;
- keep_sound_card = kernel.sound_card;
- keep_quotes = kernel.quotes;
- */
-
- load_handle.open = false;
-
- if (loader_open(&load_handle, filename, "rb", false)) goto done;
-
- if (!loader_read(&game, sizeof(KernelGame), 1, &load_handle)) goto done;
- if (!loader_read(&new_room, sizeof(int), 1, &load_handle)) goto done;
- if (!loader_read(&player2, sizeof(Player2), 1, &load_handle)) goto done;
- if (!loader_read(&inven_num_objects, sizeof(int), 1, &load_handle)) goto done;
- if (inven_num_objects) {
- if (!loader_read(inven, sizeof(int) * inven_num_objects, 1, &load_handle)) goto done;
- }
- if (!loader_read(&player, sizeof(Player), 1, &load_handle)) goto done;
- if (!loader_read(global, sizeof(int) * global_list_size, 1, &load_handle)) goto done;
- if (!loader_read(object, sizeof(Object) * num_objects, 1, &load_handle)) goto done;
- if (!loader_read(0, sizeof(int), 1, &load_handle)) goto done;
- if (!loader_read(&conv_restore_running, sizeof(int), 1, &load_handle)) goto done;
-
- /* Temporary support for old save file format */
- if (load_handle.pack_list_marker >= (int)load_handle.pack.num_records) goto expand;
-
- if (!loader_read(&camera_old_x_target, sizeof(int), 1, &load_handle)) goto done;
- if (!loader_read(&camera_old_y_target, sizeof(int), 1, &load_handle)) goto done;
- if (!loader_read(room_state, sizeof(int) * OMR, 1, &load_handle)) goto done;
- if (!loader_read(&previous_room, sizeof(int), 1, &load_handle)) goto done;
-
-expand:
- if (conv_expand(load_handle.handle)) goto done;
-
- if (inven_num_objects > 0) {
- active_inven = 0;
- } else {
- active_inven = -1;
- }
-
- first_inven = 0;
-
- section_id = KERNEL_RESTORING_GAME;
- room_id = KERNEL_RESTORING_GAME;
-
- new_section = new_room / 100;
-
- kernel.clock = timer_read();
- game.going = true;
-
- error_flag = false;
-
-done:
- if (load_handle.open) loader_close(&load_handle);
-
- /*
- kernel.video_mode = keep_video_mode;
- kernel.sound_card = keep_sound_card;
- kernel.quotes = keep_quotes;
- */
-
-
- player.walker_is_loaded = save;
- /* player.walker_is_loaded = false; */
- /* player.walker_must_reload = true; */
-
- return error_flag;
-}
-
void kernel_random_purge() {
int count;
diff --git a/engines/mads/madsv2/core/kernel.h b/engines/mads/madsv2/core/kernel.h
index a4fedba7a5c..8e8bf9e96e4 100644
--- a/engines/mads/madsv2/core/kernel.h
+++ b/engines/mads/madsv2/core/kernel.h
@@ -22,6 +22,7 @@
#ifndef MADS_CORE_KERNEL_H
#define MADS_CORE_KERNEL_H
+#include "common/serializer.h"
#include "mads/madsv2/core/general.h"
#include "mads/madsv2/core/anim.h"
#include "mads/madsv2/core/color.h"
@@ -304,12 +305,14 @@ typedef struct {
} Kernel;
-typedef struct {
- byte going; /* Game is running OK */
- int scratch[KERNEL_SCRATCH_SIZE]; /* Scratch variables for room */
- char difficulty; /* Difficulty level */
- int last_save; /* Most recent save slot # */
-} KernelGame;
+struct KernelGame {
+ byte going; /* Game is running OK */
+ int16 scratch[KERNEL_SCRATCH_SIZE]; /* Scratch variables for room */
+ int8 difficulty; /* Difficulty level */
+ int16 last_save; /* Most recent save slot # */
+
+ void synchronize(Common::Serializer &s);
+};
#ifdef old_animation
@@ -409,6 +412,9 @@ extern KernelMessage kernel_message[KERNEL_MAX_MESSAGES];
extern FontPtr kernel_message_font;
extern int kernel_message_spacing;
+#define OMR 40 /* OUAF_MAX_ROOMS in global.mac */
+extern int16 room_state[OMR];
+
extern int kernel_load_vocab();
@@ -563,8 +569,6 @@ extern void kernel_new_palette();
extern void kernel_dump_quotes();
extern void kernel_dump_all();
extern void kernel_dump_walker_only();
-extern int kernel_save_game(const char *filename);
-extern int kernel_load_game(const char *filename);
/**
* Initializes a random chatter sequence. (Parameters end with
diff --git a/engines/mads/madsv2/core/object.cpp b/engines/mads/madsv2/core/object.cpp
index b679e95a003..6c56118d251 100644
--- a/engines/mads/madsv2/core/object.cpp
+++ b/engines/mads/madsv2/core/object.cpp
@@ -57,11 +57,23 @@ char object_speech_resource[20] = "*SPCHNOTE.DSR";
void ObjectBuf::load(Common::SeekableReadStream *src) {
- src->readMultipleLE(vocab_id, location, prep, num_verbs, num_qualities, syntax);
+ Common::Serializer s(src, nullptr);
+ synchronize(s);
+}
+
+void ObjectBuf::synchronize(Common::Serializer &s) {
+ s.syncAsUint16LE(vocab_id);
+ s.syncAsSint16LE(location);
+ s.syncAsByte(prep);
+ s.syncAsByte(num_verbs);
+ s.syncAsByte(num_qualities);
+ s.syncAsByte(syntax);
+
for (int i = 0; i < OBJECT_MAX_VERBS; ++i)
- verb[i].load(src);
- src->readMultipleLE(quality_id);
- src->readMultipleLE(quality_value);
+ verb[i].synchronize(s);
+ s.syncBytes(quality_id, OBJECT_MAX_QUALITIES);
+ for (int i = 0; i < OBJECT_MAX_QUALITIES; ++i)
+ s.syncAsSint32LE(quality_value[i]);
}
diff --git a/engines/mads/madsv2/core/object.h b/engines/mads/madsv2/core/object.h
index a9d49f571b3..ce22a8c34ba 100644
--- a/engines/mads/madsv2/core/object.h
+++ b/engines/mads/madsv2/core/object.h
@@ -22,6 +22,7 @@
#ifndef MADS_CORE_OBJECT_H
#define MADS_CORE_OBJECT_H
+#include "common/serializer.h"
#include "common/stream.h"
#include "mads/madsv2/core/general.h"
#include "mads/madsv2/core/vocab.h"
@@ -86,6 +87,7 @@ struct ObjectBuf {
int32 quality_value[OBJECT_MAX_QUALITIES]; /* Quality values */
void load(Common::SeekableReadStream *src);
+ void synchronize(Common::Serializer &s);
};
typedef struct ObjectBuf Object;
diff --git a/engines/mads/madsv2/core/player.cpp b/engines/mads/madsv2/core/player.cpp
index 7e82ac8c351..3b1fe5d406e 100644
--- a/engines/mads/madsv2/core/player.cpp
+++ b/engines/mads/madsv2/core/player.cpp
@@ -44,6 +44,105 @@ byte player_facing_to_series[10] = { 0, 7, 4, 3, 6, 0, 2, 5, 0, 1 };
byte player_clockwise[10] = { 9, 4, 1, 2, 7, 9, 3, 8, 9, 6 };
byte player_counter_clockwise[10] = { 7, 2, 3, 6, 1, 7, 9, 4, 7, 8 };
+void Player::synchronize(Common::Serializer &s) {
+ s.syncAsSint16LE(walking);
+ s.syncAsSint16LE(x);
+ s.syncAsSint16LE(y);
+ s.syncAsSint16LE(target_x);
+ s.syncAsSint16LE(target_y);
+ s.syncAsSint16LE(sign_x);
+ s.syncAsSint16LE(sign_y);
+ s.syncAsSint16LE(x_count);
+ s.syncAsSint16LE(y_count);
+ s.syncAsSint16LE(x_counter);
+ s.syncAsSint16LE(y_counter);
+ s.syncAsSint16LE(target_facing);
+ s.syncAsSint16LE(special_code);
+ s.syncAsSint16LE(sprite_changed);
+ s.syncAsSint16LE(frame_delay);
+ s.syncAsSint16LE(center_of_gravity);
+ s.syncAsSint16LE(walk_freedom);
+ s.syncAsSint16LE(walk_anywhere);
+ s.syncAsSint16LE(walk_off_edge_to_room);
+ s.syncAsSint16LE(walk_off_edge);
+ s.syncAsSint16LE(need_to_walk);
+ s.syncAsSint16LE(ready_to_walk);
+ s.syncAsSint16LE(prepare_walk_facing);
+ s.syncAsSint16LE(prepare_walk_x);
+ s.syncAsSint16LE(prepare_walk_y);
+ s.syncAsSint16LE(commands_allowed);
+ s.syncAsSint16LE(walker_visible);
+ s.syncAsSint16LE(walker_previously_visible);
+ s.syncAsSint16LE(series_base);
+ s.syncAsSint16LE(available[8]);
+ s.syncAsSint16LE(facing);
+ s.syncAsSint16LE(turn_to_facing);
+ s.syncAsSint16LE(series);
+ s.syncAsSint16LE(mirror);
+ s.syncAsSint16LE(sprite);
+ s.syncAsByte(depth);
+ s.syncAsByte(scale);
+ s.syncAsSint16LE(stop_walker_sequence);
+ for (int i = 0; i < PLAYER_MAX_STOP; ++i)
+ s.syncAsSint16LE(stop_walker_stack[i]);
+ for (int i = 0; i < PLAYER_MAX_STOP; ++i)
+ s.syncAsSint16LE(stop_walker_trigger[i]);
+ s.syncAsSint16LE(stop_walker_pointer);
+ s.syncAsSint16LE(upcoming_trigger);
+ s.syncAsSint16LE(trigger);
+ s.syncAsSint16LE(next_special_code);
+ s.syncAsSint16LE(scaling_velocity);
+ s.syncAsSint16LE(pixel_accum);
+ s.syncAsSint16LE(dist_accum);
+ s.syncAsUint16LE(delta_distance);
+ s.syncAsUint16LE(total_distance);
+ s.syncAsSint16LE(velocity);
+ s.syncAsSint16LE(high_sprite);
+ s.syncAsSint16LE(command_ready);
+ s.syncAsSint16LE(command_error);
+ s.syncAsSint16LE(command_source);
+ s.syncAsSint16LE(command);
+ s.syncAsSint16LE(main_object);
+ s.syncAsSint16LE(second_object);
+ s.syncAsSint16LE(main_object_source);
+ s.syncAsSint16LE(second_object_source);
+ s.syncAsSint16LE(prep);
+ s.syncAsSint16LE(look_around);
+ s.syncAsSint16LE(main_syntax);
+ s.syncAsSint16LE(second_syntax);
+ s.syncBytes((byte *)series_name, 20);
+ s.syncBytes((byte *)sentence, 64);
+ s.syncAsSint32LE(clock);
+ s.syncAsByte(been_here_before);
+ s.skip(1);
+
+ s.syncAsSint16LE( num_rooms_been_in);
+ for (int i = 0; i < PLAYER_MAX_ROOMS; ++i)
+ s.syncAsSint16LE(rooms_been_in[i]);
+
+ s.syncAsSint16LE(num_series);
+ s.syncAsByte(walker_loads_first);
+ s.syncAsByte(walker_loaded_first);
+ s.syncAsByte(walker_is_loaded);
+ s.syncAsByte(walker_must_reload);
+ s.syncAsSint16LE(walker_been_visible);
+ s.syncAsByte(force_series);
+ s.skip(1);
+ s.syncAsSint16LE(walk_trigger);
+ s.syncAsByte(walk_trigger_dest);
+ s.skip(1);
+
+ for (int i = 0; i < 3; ++i)
+ s.syncAsSint16LE(walk_trigger_words[i]);
+
+ s.syncAsSint16LE(enable_at_target);
+}
+
+void Player2::synchronize(Common::Serializer &s) {
+ for (int i = 0; i < 3; ++i)
+ s.syncAsSint16LE(words[i]);
+}
+
/**
* Returns the scaling factor for the player walker, based on the
* player's current position
diff --git a/engines/mads/madsv2/core/player.h b/engines/mads/madsv2/core/player.h
index d3cdbfcf906..3abe30f2292 100644
--- a/engines/mads/madsv2/core/player.h
+++ b/engines/mads/madsv2/core/player.h
@@ -22,6 +22,7 @@
#ifndef MADS_CORE_PLAYER_H
#define MADS_CORE_PLAYER_H
+#include "common/serializer.h"
#include "mads/madsv2/core/general.h"
namespace MADS {
@@ -139,12 +140,16 @@ struct Player {
int walk_trigger_words[3]; /* Vocabulary words for reactivating parser*/
int enable_at_target; /* Enable commands at walk target */
+
+ void synchronize(Common::Serializer &s);
};
-typedef struct {
+struct Player2 {
int words[3]; /* Vocab word array of player's sentence */
-} Player2;
+
+ void synchronize(Common::Serializer &s);
+};
extern Player player;
diff --git a/engines/mads/madsv2/engine.cpp b/engines/mads/madsv2/engine.cpp
index 473d8c8035c..0baddf1e834 100644
--- a/engines/mads/madsv2/engine.cpp
+++ b/engines/mads/madsv2/engine.cpp
@@ -22,11 +22,14 @@
#include "common/system.h"
#include "engines/util.h"
#include "mads/madsv2/engine.h"
+#include "mads/madsv2/core/camera.h"
#include "mads/madsv2/core/config.h"
#include "mads/madsv2/core/conv.h"
#include "mads/madsv2/core/game.h"
#include "mads/madsv2/core/inter.h"
#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/object.h"
+#include "mads/madsv2/core/timer.h"
#include "mads/madsv2/phantom/main.h"
#include "mads/core/sound.h"
@@ -62,6 +65,74 @@ bool MADSV2Engine::canLoadGameStateCurrently(Common::U32String *msg) {
conv_control.running == -1;
}
+Common::Error MADSV2Engine::saveGameStream(Common::WriteStream *stream, bool isAutosave) {
+ // Sync main game data
+ Common::Serializer s(nullptr, stream);
+ syncGame(s);
+
+ // Save conversation data
+ conv_append(stream);
+
+ return Common::kNoError;
+}
+
+Common::Error MADSV2Engine::loadGameStream(Common::SeekableReadStream *stream) {
+int save = player.walker_is_loaded;
+
+ // Sync main game data
+ Common::Serializer s(stream, nullptr);
+ syncGame(s);
+
+ // Load conversation data
+ if (conv_expand(stream))
+ goto done;
+
+ if (inven_num_objects > 0) {
+ active_inven = 0;
+ } else {
+ active_inven = -1;
+ }
+
+ first_inven = 0;
+
+ section_id = KERNEL_RESTORING_GAME;
+ room_id = KERNEL_RESTORING_GAME;
+
+ new_section = new_room / 100;
+
+ kernel.clock = timer_read();
+ game.going = true;
+
+done:
+ player.walker_is_loaded = save;
+ return Common::kNoError;
+}
+
+void MADSV2Engine::syncGame(Common::Serializer &s) {
+ game.synchronize(s);
+ s.syncAsSint16LE(new_room);
+ player2.synchronize(s);
+
+ s.syncAsSint16LE(inven_num_objects);
+ for (int i = 0; i < inven_num_objects; ++i)
+ s.syncAsSint16LE(inven[i]);
+
+ player.synchronize(s);
+ for (int i = 0; i < global_list_size; ++i)
+ s.syncAsSint16LE(global[i]);
+
+ for (int i = 0; i < num_objects; ++i)
+ object[i].synchronize(s);
+
+ s.syncAsSint16LE(conv_restore_running);
+ s.syncAsSint16LE(camera_old_x_target);
+ s.syncAsSint16LE(camera_old_y_target);
+
+ for (int i = 0; i < OMR; ++i)
+ s.syncAsSint16LE(room_state[i]);
+ s.syncAsSint16LE(previous_room);
+}
+
void MADSV2Engine::pollEvents() {
// Check for screen update time
uint32 time = g_system->getMillis();
diff --git a/engines/mads/madsv2/engine.h b/engines/mads/madsv2/engine.h
index ed503171c00..0675c75e53d 100644
--- a/engines/mads/madsv2/engine.h
+++ b/engines/mads/madsv2/engine.h
@@ -23,6 +23,7 @@
#define MADSV2_ENGINE_H
#include "common/events.h"
+#include "common/serializer.h"
#include "common/stack.h"
#include "common/random.h"
#include "graphics/screen.h"
@@ -34,6 +35,9 @@ namespace MADS {
namespace MADSV2 {
class MADSV2Engine : public MADSEngine {
+private:
+ void syncGame(Common::Serializer &s);
+
protected:
Graphics::Screen *_screen = nullptr;
Common::Stack<Common::Event> _keyEvents;
@@ -84,6 +88,8 @@ public:
bool canSaveGameStateCurrently(Common::U32String *msg) override {
return canLoadGameStateCurrently(msg);
}
+ Common::Error saveGameStream(Common::WriteStream *stream, bool isAutosave) override;
+ Common::Error loadGameStream(Common::SeekableReadStream *stream) override;
virtual void global_init_code() = 0;
virtual void section_music(int section_num) = 0;
diff --git a/engines/mads/madsv2/phantom/menus.cpp b/engines/mads/madsv2/phantom/menus.cpp
index a8e192d8691..6dfaefe8082 100644
--- a/engines/mads/madsv2/phantom/menus.cpp
+++ b/engines/mads/madsv2/phantom/menus.cpp
@@ -70,11 +70,10 @@ static int global_save(int id) {
game_save_name(id + 1);
- if (!kernel_save_game(save_game_buf)) {
+ if (g_engine->saveGameState(id, save_game_buf).getCode() == Common::kNoError)
status = SAVE_SUCCESSFUL;
- } else {
+ else
status = SAVE_FAILED;
- }
return status;
}
@@ -82,14 +81,10 @@ static int global_save(int id) {
static int global_restore(int id) {
int status;
- game_save_name(id + 1);
-
- if (!kernel_load_game(save_game_buf)) {
+ if (g_engine->loadGameState(id).getCode() == Common::kNoError)
status = RESTORE_SUCCESSFUL;
- } else {
+ else
status = RESTORE_FAILED;
- save_game_buf[0] = 0;
- }
WRITE_LE_UINT32(&global[walker_timing], 0);
@@ -163,14 +158,7 @@ void global_emergency_save() {
if (scr_orig.data != NULL) mem_free(scr_orig.data);
- if (!kernel_save_game(save_game_buf)) {
- echo(menu_quote(quote_emergency_save_success), true);
- echo(menu_quote(quote_emergency_save_attempt), false);
- echo(restart_game_key, true);
- echo(menu_quote(quote_emergency_save_resume), true);
- } else {
- echo(menu_quote(quote_emergency_save_failure), true);
- }
+ g_engine->saveAutosaveIfEnabled();
}
static void global_alert(int status) {
diff --git a/engines/mads/metaengine.cpp b/engines/mads/metaengine.cpp
index 1cad0e5bdee..521a7dd37fb 100644
--- a/engines/mads/metaengine.cpp
+++ b/engines/mads/metaengine.cpp
@@ -186,12 +186,13 @@ public:
bool MADSMetaEngine::hasFeature(MetaEngineFeature f) const {
return
- (f == kSupportsListSaves) ||
+ (f == kSupportsListSaves) ||
(f == kSupportsLoadingDuringStartup) ||
(f == kSupportsDeleteSave) ||
(f == kSavesSupportMetaInfo) ||
(f == kSavesSupportThumbnail) ||
- (f == kSimpleSavesNames);
+ (f == kSimpleSavesNames) ||
+ checkExtendedSaves(f);
}
bool MADS::MADSEngine::hasFeature(EngineFeature f) const {
Commit: 3713880be1ddaf532e67cafe8065e5d9ae61f2ce
https://github.com/scummvm/scummvm/commit/3713880be1ddaf532e67cafe8065e5d9ae61f2ce
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:19+10:00
Commit Message:
ENGINES: Added getGameId for getting gameId from a target
Changed paths:
engines/advancedDetector.cpp
engines/advancedDetector.h
diff --git a/engines/advancedDetector.cpp b/engines/advancedDetector.cpp
index 555309eb2c9..b2fb99fdd3d 100644
--- a/engines/advancedDetector.cpp
+++ b/engines/advancedDetector.cpp
@@ -343,6 +343,20 @@ const ExtraGuiOptions AdvancedMetaEngineBase::getExtraGuiOptions(const Common::S
return options;
}
+Common::String AdvancedMetaEngineBase::getGameId(const char *target) const {
+ // Store a copy of the active domain
+ Common::String currDomain = ConfMan.getActiveDomainName();
+
+ // Switch to the given target domain and get it's game Id
+ ConfMan.setActiveDomain(target);
+ Common::String gameId = ConfMan.get("gameid");
+
+ // Switch back to the original domain and return the game Id
+ ConfMan.setActiveDomain(currDomain);
+
+ return gameId;
+}
+
Common::Error AdvancedMetaEngineDetectionBase::identifyGame(DetectedGame &game, const void **descriptor) {
Common::Language language = Common::UNK_LANG;
Common::Platform platform = Common::kPlatformUnknown;
diff --git a/engines/advancedDetector.h b/engines/advancedDetector.h
index 535f50a13c6..289c64207f1 100644
--- a/engines/advancedDetector.h
+++ b/engines/advancedDetector.h
@@ -656,6 +656,13 @@ public:
*/
const char *getName() const override = 0;
+ /**
+ * Gets the game Id based on the provided target.
+ * @param target Game target string
+ * @return Game Id string
+ */
+ Common::String getGameId(const char *target) const;
+
public:
/**
* A hashmap of file paths and their file system nodes.
Commit: 65903463e32d50b1d6190ead54048e707ea9eb2c
https://github.com/scummvm/scummvm/commit/65903463e32d50b1d6190ead54048e707ea9eb2c
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:19+10:00
Commit Message:
MADS: PHANTOM: Fix savegame loading
Changed paths:
engines/mads/madsv2/core/conv.cpp
engines/mads/madsv2/core/game.cpp
engines/mads/madsv2/engine.cpp
engines/mads/metaengine.cpp
diff --git a/engines/mads/madsv2/core/conv.cpp b/engines/mads/madsv2/core/conv.cpp
index 20c279ef603..1944da5edf4 100644
--- a/engines/mads/madsv2/core/conv.cpp
+++ b/engines/mads/madsv2/core/conv.cpp
@@ -232,7 +232,7 @@ void ConvData::save(Common::WriteStream *dest) const {
for (int i = 0; i < entryFlagsCount; ++i)
dest->writeSint16LE(entryFlags[i]);
- for (int i = 0; i < entryFlagsCount; ++i)
+ for (int i = 0; i < variablesCount; ++i)
variables[i].save(dest);
}
@@ -1711,7 +1711,8 @@ int conv_expand(Common::SeekableReadStream *handle) {
// Read count and list
count = handle->readUint16LE();
- handle->readMultipleLE(list);
+ for (int i = 0; i < count; ++i)
+ list[i] = handle->readSint16LE();
for (int i = 0; i < count; ++i) {
int index = list[i];
diff --git a/engines/mads/madsv2/core/game.cpp b/engines/mads/madsv2/core/game.cpp
index b0fb1fce8d6..3b46acf5e34 100644
--- a/engines/mads/madsv2/core/game.cpp
+++ b/engines/mads/madsv2/core/game.cpp
@@ -1254,14 +1254,6 @@ void game_set_camera_speed() {
}
}
-void nuke_all_speech_files(void) {
- error("TODO: nuke_all_speech_files");
-}
-
-void start_the_copy_process(char orig_path[80]) {
- error("TODO: start_the_copy_process");
-}
-
/*
/* game_control()
/*
@@ -1690,9 +1682,6 @@ emergency:
}
}
- /* remove .RAC and .RAW files */
- nuke_all_speech_files();
-
player_dump_walker();
if (room_id == KERNEL_RESTORING_GAME) {
diff --git a/engines/mads/madsv2/engine.cpp b/engines/mads/madsv2/engine.cpp
index 0baddf1e834..f2f7744eab6 100644
--- a/engines/mads/madsv2/engine.cpp
+++ b/engines/mads/madsv2/engine.cpp
@@ -77,7 +77,7 @@ Common::Error MADSV2Engine::saveGameStream(Common::WriteStream *stream, bool isA
}
Common::Error MADSV2Engine::loadGameStream(Common::SeekableReadStream *stream) {
-int save = player.walker_is_loaded;
+ int save = player.walker_is_loaded;
// Sync main game data
Common::Serializer s(stream, nullptr);
diff --git a/engines/mads/metaengine.cpp b/engines/mads/metaengine.cpp
index 521a7dd37fb..92a6e9a520c 100644
--- a/engines/mads/metaengine.cpp
+++ b/engines/mads/metaengine.cpp
@@ -214,6 +214,9 @@ Common::Error MADSMetaEngine::createInstance(OSystem *syst, Engine **engine, con
}
SaveStateList MADSMetaEngine::listSaves(const char *target) const {
+ if (getGameId(target) != "nebular")
+ return AdvancedMetaEngine<MADS::MADSGameDescription>::listSaves(target);
+
Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
Common::StringArray filenames;
Common::String saveDesc;
@@ -248,11 +251,18 @@ int MADSMetaEngine::getMaximumSaveSlot() const {
}
bool MADSMetaEngine::removeSaveState(const char *target, int slot) const {
- Common::String filename = Common::String::format("%s.%03d", target, slot);
- return g_system->getSavefileManager()->removeSavefile(filename);
+ if (getGameId(target) == "nebular") {
+ Common::String filename = Common::String::format("%s.%03d", target, slot);
+ return g_system->getSavefileManager()->removeSavefile(filename);
+ } else {
+ return AdvancedMetaEngine<MADS::MADSGameDescription>::removeSaveState(target, slot);
+ }
}
SaveStateDescriptor MADSMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
+ if (getGameId(target) != "nebular")
+ return AdvancedMetaEngine<MADS::MADSGameDescription>::querySaveMetaInfos(target, slot);
+
Common::String filename = Common::String::format("%s.%03d", target, slot);
Common::InSaveFile *f = g_system->getSavefileManager()->openForLoading(filename);
Commit: babf34cb6b793d99c11d822247fd1499f4ed8ab5
https://github.com/scummvm/scummvm/commit/babf34cb6b793d99c11d822247fd1499f4ed8ab5
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:20+10:00
Commit Message:
MADS: PHANTOM: Fix crash changing rooms
Changed paths:
engines/mads/madsv2/core/extra.cpp
engines/mads/madsv2/core/game.cpp
diff --git a/engines/mads/madsv2/core/extra.cpp b/engines/mads/madsv2/core/extra.cpp
index 3aa1735c701..3824ba72158 100644
--- a/engines/mads/madsv2/core/extra.cpp
+++ b/engines/mads/madsv2/core/extra.cpp
@@ -58,10 +58,6 @@ void extra_spinning_object(void) {
error("TODO: extra_spinning_object");
}
-void extra_inven_preserve_palette(void) {
- error("TODO: extra_inven_preserve_palette");
-}
-
void stamp_sprite_to_interface(int x, int y, int sprite, int series) {
error("TODO: stamp_sprite_to_interface");
}
diff --git a/engines/mads/madsv2/core/game.cpp b/engines/mads/madsv2/core/game.cpp
index 3b46acf5e34..f3fdb3c1090 100644
--- a/engines/mads/madsv2/core/game.cpp
+++ b/engines/mads/madsv2/core/game.cpp
@@ -1462,9 +1462,10 @@ void game_control() {
}
#endif
} else {
- /* paul - call my special preserve palette routine in extra_1 */
- /* player_preserve_palette(); */
+ player_preserve_palette();
+#if 0
extra_inven_preserve_palette();
+#endif
}
pal_activate_shadow(&kernel_shadow_main);
Commit: b4c6e27517c93de9963aceda354f7c9a63850324
https://github.com/scummvm/scummvm/commit/b4c6e27517c93de9963aceda354f7c9a63850324
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:20+10:00
Commit Message:
MADS: PHANTOM: Fix caching conversation data for savegames
Changed paths:
engines/mads/madsv2/core/conv.cpp
diff --git a/engines/mads/madsv2/core/conv.cpp b/engines/mads/madsv2/core/conv.cpp
index 1944da5edf4..50b5274fc0d 100644
--- a/engines/mads/madsv2/core/conv.cpp
+++ b/engines/mads/madsv2/core/conv.cpp
@@ -115,7 +115,7 @@ void ConvVariable::load(Common::SeekableReadStream *src) {
isPtr = flag == MKTAG16('V', 'M');
val = src->readSint16LE();
- uint16 type = src->readUint16LE();
+ type = src->readUint16LE();
if (isPtr) {
switch (type) {
@@ -1638,10 +1638,9 @@ void conv_flush() {
ConvData *convData = conv_data[conv_indexes[i] - 2];
errCode = conv_write(dest, convData);
- if (errCode) {
- delete dest;
- goto done;
- }
+ if (errCode) goto done;
+
+ conv_indexes[i] = 1;
}
}
Commit: 30289ce04b8a17ccc535f09227aec220bc609822
https://github.com/scummvm/scummvm/commit/30289ce04b8a17ccc535f09227aec220bc609822
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:20+10:00
Commit Message:
MADS: PHANTOM: Replace original autosave on exit
Changed paths:
engines/mads/madsv2/core/game.cpp
diff --git a/engines/mads/madsv2/core/game.cpp b/engines/mads/madsv2/core/game.cpp
index f3fdb3c1090..22ee8fcb402 100644
--- a/engines/mads/madsv2/core/game.cpp
+++ b/engines/mads/madsv2/core/game.cpp
@@ -1671,12 +1671,8 @@ emergency:
if (!game.going && !win_status) {
conv_control.running = aborted_conv;
-#if 0
- game_save_name(0);
- kernel_save_game(save_game_buf);
-#else
- warning("TODO: Original save dialog saves");
-#endif
+
+ g_engine->saveAutosaveIfEnabled();
game_autosaved = true;
} else {
game_autosaved = false;
Commit: 9c764d56c0e4b8658594ccb1cc35f7a2e56d5e60
https://github.com/scummvm/scummvm/commit/9c764d56c0e4b8658594ccb1cc35f7a2e56d5e60
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:21+10:00
Commit Message:
MADS: PHANTOM: Implement loading savegames from launcher
Changed paths:
engines/mads/madsv2/core/game.cpp
engines/mads/madsv2/engine.cpp
engines/mads/madsv2/phantom/main.cpp
diff --git a/engines/mads/madsv2/core/game.cpp b/engines/mads/madsv2/core/game.cpp
index 22ee8fcb402..3aac34cc5c6 100644
--- a/engines/mads/madsv2/core/game.cpp
+++ b/engines/mads/madsv2/core/game.cpp
@@ -19,6 +19,7 @@
*
*/
+#include "common/config-manager.h"
#include "common/debug.h"
#include "mads/madsv2/engine.h"
#include "mads/madsv2/core/game.h"
@@ -1264,7 +1265,7 @@ void game_set_camera_speed() {
void game_control() {
int count, color;
- int result;
+ int result = COPY_SUCCEED;
bool aborted_conv = true;
/* Start up game level functions */
@@ -1282,18 +1283,24 @@ void game_control() {
conv_system_init();
- result = main_copy_verify();
- if (result == COPY_FAIL) {
- game.going = false;
- force_chain = true;
- game_restore_flag = false;
- /* new_room = 804; */
- /* global_init_code(); */
- /* global[copy_protect_failed] = true; */
- error_report(ERROR_COPY_PROTECTION, SEVERE, MODULE_LOCK, 0, 0);
- } else if (result == COPY_ESCAPE) {
- game.going = false;
- force_chain = true;
+ if (ConfMan.hasKey("save_slot")) {
+ // Flag to do a savegame load
+ game_restore_flag = 1;
+
+ } else {
+ result = main_copy_verify();
+ if (result == COPY_FAIL) {
+ game.going = false;
+ force_chain = true;
+ game_restore_flag = false;
+ /* new_room = 804; */
+ /* global_init_code(); */
+ /* global[copy_protect_failed] = true; */
+ error_report(ERROR_COPY_PROTECTION, SEVERE, MODULE_LOCK, 0, 0);
+ } else if (result == COPY_ESCAPE) {
+ game.going = false;
+ force_chain = true;
+ }
}
kernel.clock = timer_read();
@@ -1339,10 +1346,8 @@ void game_control() {
force_chain = true;
}
} else {
-#if 0
- game.going = (byte)!kernel_load_game(save_game_buf);
- if (!game.going) force_chain = true;
-#endif
+ // Savegame load from GMM
+ g_engine->loadGameState(ConfMan.getInt("save_slot"));
}
}
diff --git a/engines/mads/madsv2/engine.cpp b/engines/mads/madsv2/engine.cpp
index f2f7744eab6..f93776ca303 100644
--- a/engines/mads/madsv2/engine.cpp
+++ b/engines/mads/madsv2/engine.cpp
@@ -28,6 +28,7 @@
#include "mads/madsv2/core/game.h"
#include "mads/madsv2/core/inter.h"
#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/matte.h"
#include "mads/madsv2/core/object.h"
#include "mads/madsv2/core/timer.h"
#include "mads/madsv2/phantom/main.h"
@@ -125,8 +126,14 @@ void MADSV2Engine::syncGame(Common::Serializer &s) {
object[i].synchronize(s);
s.syncAsSint16LE(conv_restore_running);
- s.syncAsSint16LE(camera_old_x_target);
- s.syncAsSint16LE(camera_old_y_target);
+
+ if (s.isSaving()) {
+ s.syncAsSint16LE(picture_view_x);
+ s.syncAsSint16LE(picture_view_y);
+ } else {
+ s.syncAsSint16LE(camera_old_x_target);
+ s.syncAsSint16LE(camera_old_y_target);
+ }
for (int i = 0; i < OMR; ++i)
s.syncAsSint16LE(room_state[i]);
diff --git a/engines/mads/madsv2/phantom/main.cpp b/engines/mads/madsv2/phantom/main.cpp
index 0b5274c7c26..4ee0689511e 100644
--- a/engines/mads/madsv2/phantom/main.cpp
+++ b/engines/mads/madsv2/phantom/main.cpp
@@ -264,7 +264,7 @@ void phantom_main() {
if (!env_verify())
env_search_mode = ENV_SEARCH_CONCAT_FILES;
- bool firstTime = !ConfMan.getBool("start_game");
+ bool firstTime = !ConfMan.getBool("start_game") && !ConfMan.hasKey("save_slot");
selected_item = 0;
while (!g_engine->shouldQuit()) {
Commit: d2564fb84e0ea04771f54825057e006bfd708988
https://github.com/scummvm/scummvm/commit/d2564fb84e0ea04771f54825057e006bfd708988
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:21+10:00
Commit Message:
MADS: PHANTOM: Remove duplicated conv.h file
Changed paths:
R engines/mads/madsv2/phantom/conv.h
diff --git a/engines/mads/madsv2/phantom/conv.h b/engines/mads/madsv2/phantom/conv.h
deleted file mode 100644
index b7d4b5cf0fb..00000000000
--- a/engines/mads/madsv2/phantom/conv.h
+++ /dev/null
@@ -1,311 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#ifndef MADS_PHANTOM_CONV_H
-#define MADS_PHANTOM_CONV_H
-
-#include "common/scummsys.h"
-
-namespace MADS {
-namespace MADSV2 {
-namespace Phantom {
-
-
-enum {
- conv001_speech_talk = 0,
- conv001_continue_abc = 1,
- conv002_questions_one = 2,
- conv001_what_one = 4,
- conv001_yesno_yes = 8,
- conv001_everything_byebye = 10,
- conv001_everything_copycat = 12,
- conv001_speak_byebye = 18,
- conv001_saytwo_1 = 22,
- conv001_instructions_three = 24,
- conv001_point_two_abc = 27,
-};
-
-enum {
- conv002_sayone_abc = 1,
- conv002_answers_job = 5,
- conv002_answers_please = 6,
- conv002_answers_house = 8,
- conv002_answers_go_on = 9,
- conv002_answers_prison = 10,
- conv002_answers_building = 11,
- conv002_answers_catacombs = 12,
- conv002_interrogate_mishap = 15,
- conv002_interrogate_chandelier = 16,
- conv002_interrogate_phantom = 19,
- conv002_interrogate_giry = 22,
- conv002_nomore_first = 25,
- conv002_saytwo_abc = 26,
-};
-
-enum {
- conv003_bon_jour_hello = 0,
- conv003_first_howdy = 1,
- conv003_second_aloha = 2,
- conv003_name_i_am = 3,
- conv003_name_form = 4,
- conv003_name_oops = 5,
- conv003_adios_byebye= 6,
- conv003_nomore_byebye = 7,
- conv003_questions_three = 10,
- conv003_knowghost_see = 13,
- conv003_knowghost_look = 14,
- conv003_return_dreams = 15,
- conv003_return_she = 16,
- conv003_return_giry = 18,
- conv003_return_byebye = 23,
- conv003_yourself_byebye = 27
-};
-
-enum {
- conv004_bon_jour_hello = 0,
- conv004_who_who_are = 1,
- conv004_monsieur_again = 2,
- conv004_name_raoul = 3,
- conv004_name_dear = 4,
- conv004_name_sorry = 5,
- conv004_anything_take = 19,
- conv004_imgone_bye = 25,
- conv004_dontleave_help = 26,
- conv004_promises_continue = 27,
- conv004_promises_return = 28,
- conv004_promises_cant = 29,
- conv004_promises_safe = 30
-};
-
-enum {
- conv005_nowhere_nothing = 9,
- conv005_report_adieu = 12,
- conv005_lets_see_b_what_have_b = 14,
- conv005_anyone_b_sign_it_b = 17,
- conv005_crime_missing = 20,
- conv005_rumors_sandbag = 24,
- conv005_rumors_accident = 25,
- conv005_goman_abc = 35,
- conv005_murder_b_aa = 37,
- conv005_scream_help = 41,
- conv005_readbook_two_abc = 42,
- conv005_point_one_b_abc = 44
-};
-
-enum {
- conv007_richard_intro_b = 2,
- conv007_daaeb_intro_c = 3,
- conv007_where_pushed = 8,
- conv007_where_killed = 10,
- conv007_badfall_abc = 11,
- conv007_youraoul_abc = 12,
- conv007_kiss_abc = 13,
- conv007_afterkiss_abc = 14,
- conv007_delirious_abc = 16,
- conv007_long_abc = 20,
- conv007_worry_abc = 21,
- conv007_dashing_tuxedo = 22,
- conv007_dashing_london = 23,
- conv007_answers_abc = 24,
- conv007_final_goaway = 25,
- conv007_office_abc = 28,
- conv007_solo_alone = 30,
- conv007_pinch_wait_b_nothing_b = 32,
-};
-
-enum {
- conv008_things_two = 4,
- conv008_things_three = 5,
- conv008_actions_b_b = 7,
- conv008_actions_d_d = 13,
- conv008_actions_byebye = 15,
- conv008_tellabout_have = 17,
- conv008_tellabout_rumor = 19,
- conv008_later_final = 20,
- conv008_nomore_first = 21,
- conv008_var_actions_done = 24,
- conv008_var_christine_done = 26,
- conv008_christine_three = 27
-};
-
-enum {
- conv009_dialogue_one = 1,
- conv009_dialogue_paint = 2,
- conv009_dialogue_three = 10,
- conv009_lips_abc = 11,
- conv009_wink_abc = 12
-};
-
-enum {
- conv010_hasthem_abc = 4,
- conv010_noyoudont_abc = 5,
- conv010_unlock_b_box_5 = 7,
- conv010_gethem_abc = 8,
- conv010_beginning_who = 9,
- conv010_beginning_you = 10,
- conv010_beginning_pardon = 11,
- conv010_nomore_abc = 13,
- conv010_byebye_first = 14,
- conv010_dialogue_three = 16,
- conv010_dialogue_one = 17,
- conv010_ghost_byebye = 19,
- conv010_trance_b_box_5 = 21,
- conv010_box_b_b = 23,
- conv010_box_d_d = 25,
- conv010_box_byebye = 40,
- conv010_ghost_interest = 45,
- conv010_bye_two_solong = 46
-};
-
-enum {
- conv011_has_b_ticket = 5,
- conv011_has_abc = 6,
- conv011_enter_b_a = 8,
- conv011_hasnot_abc = 9,
- conv011_boxoffice_abc = 10,
- conv011_enter_it_abc = 12,
- conv011_enjoy_abc = 13,
- conv011_five_nono = 14
-};
-
-enum {
- conv012_hello_one = 1,
- conv012_hello_four = 4,
- conv012_byebye_first = 6,
- conv012_questions_three = 7,
- conv012_questions_one = 8,
- conv012_seen_byebye = 10,
- conv012_seen_mask = 12,
- conv012_tell_byebye = 19,
- conv012_var_questions_done = 26,
- conv012_tell_knewhim = 29,
- conv012_nomore_first = 30
-};
-
-enum {
- conv013_intro_hello = 0,
- conv013_returned_abc = 1,
- conv013_again_abc = 2,
- conv013_dreams_romantic = 19,
- conv013_lovescene_openline = 21,
- conv013_practice_first = 27,
- conv013_biteme_b_b = 31
-};
-
-enum {
- conv014_second_angel = 1,
- conv014_eighth_inside = 7
-};
-
-enum {
- conv015_daae_b_b = 5,
- conv015_next_second = 7,
- conv015_professional_fourth = 9,
- conv015_damned_b_b = 11,
- conv015_exchange_ticket = 13,
- conv015_exchange_relief = 14,
- conv015_exchange_opera = 15
-};
-
-enum {
- conv016_buy_four = 4,
- conv016_take_b_b = 6,
- conv016_kind_five = 12,
- conv016_money_cash = 13,
- conv016_money_lend = 14
-};
-
-enum {
- conv017_ticket_block = 0,
- conv017_hasit_first = 3,
- conv017_hasnot_first = 4
-};
-
-enum {
- conv018_begin_first = 0,
- conv018_adieu_bye = 4,
- conv018_nomore_huh = 5
-};
-
-enum {
- conv019_talk_b_b = 2,
- conv019_exit_b_b = 12
-};
-
-enum {
- conv020_where_a = 2,
- conv020_exit_b_b = 5,
- conv020_dialogue_b_b = 8,
- conv020_bye_b_b = 14,
- conv020_story_b_b = 22
-};
-
-enum {
- conv021_fight_b_b = 3,
- conv021_ending_b_b = 8,
- conv021_outtahere_first = 10,
- conv021_outtahere_second = 11,
- conv021_outtahere_third = 12,
- conv021_hasit_b_b = 14,
- conv021_score_abc = 15,
- conv021_score_b_b = 17,
-};
-
-enum {
- conv022_second_next = 1,
- conv022_resolution_florent = 6,
- conv022_resolution_fall = 7,
- conv022_resolution_alone = 8,
- conv022_dead_strangled = 9,
- conv022_object_abc = 13,
- conv022_do_abc = 15,
- conv022_kiss_b_b = 17,
- conv022_kiss_abc = 18,
- conv022_notes_hadany = 19,
- conv022_notes_here = 20,
- conv022_notes_chandelier = 21,
- conv022_notes_audience = 22,
- conv022_look_abc = 23,
- conv022_notes_b_b = 25,
- conv022_leave_b_b = 29
-};
-
-enum {
- conv023_unhand_b_b = 3,
- conv023_okay_b_b = 6,
- conv023_okay_abc = 7,
- conv023_die_b_b = 12
-};
-
-enum {
- conv027_choices_one = 2,
- conv027_choices_two = 3,
- conv027_choices_three = 4,
- conv027_choices_four = 5,
- conv027_choices_five = 6,
- conv027_exit_a_a = 7
-};
-
-} // namespace Phantom
-} // namespace MADSV2
-} // namespace MADS
-
-#endif
Commit: aa51e0b1ccaee5be2e5a52fd14e3cad282f971bb
https://github.com/scummvm/scummvm/commit/aa51e0b1ccaee5be2e5a52fd14e3cad282f971bb
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:21+10:00
Commit Message:
MADS: PHANTOM: Fix duration of conversation response dialogs
Changed paths:
engines/mads/madsv2/core/conv.cpp
engines/mads/madsv2/core/conv.h
diff --git a/engines/mads/madsv2/core/conv.cpp b/engines/mads/madsv2/core/conv.cpp
index 50b5274fc0d..0a8888d630f 100644
--- a/engines/mads/madsv2/core/conv.cpp
+++ b/engines/mads/madsv2/core/conv.cpp
@@ -604,7 +604,7 @@ static void conv_generate_text(Conv *convIn, ConvData * /*convData*/,
// Restore the caller's box and record that a conversation popup is live.
box = savedBox;
conv_control.popup_is_up = -1;
- conv_control.popup_clock = kernel.clock;
+ conv_control.popup_clock = kernel.clock + conv_control.popup_duration;
// Play the associated speech audio when the speech system is on.
if (speech_system_active && speech_on && speechCount > 0) {
@@ -1219,7 +1219,7 @@ void conv_run(int convId) {
conv_control.running = convId;
conv_control.index = conv_indexes[convId] - 2;
conv_control.status = CONV_STATUS_NEXT_NODE;
- conv_control.mask = 0x7FFF;
+ conv_control.popup_duration = 0x7FFF; // Display for a long time
conv_control.popup_clock = kernel.clock;
conv_control.entry = -1;
conv_control.commands_allowed = player.commands_allowed;
@@ -1320,7 +1320,7 @@ static void conv_generate_message(Conv *convIn, ConvData *convData,
popup_next_line();
if (!popup_draw(-1, -1)) {
conv_control.popup_is_up = -1;
- conv_control.popup_clock = kernel.clock + conv_control.mask;
+ conv_control.popup_clock = kernel.clock + conv_control.popup_duration;
if (speech_system_active && speech_on) {
if (voiceListSize != 0) {
diff --git a/engines/mads/madsv2/core/conv.h b/engines/mads/madsv2/core/conv.h
index a41002fb69d..9e1554fd2ed 100644
--- a/engines/mads/madsv2/core/conv.h
+++ b/engines/mads/madsv2/core/conv.h
@@ -174,7 +174,7 @@ struct ConvControl {
ConvStatus hold_status;
int16 has_text;
int16 popup_is_up;
- int16 mask;
+ int16 popup_duration;
long popup_clock;
int16 speaker_active[CONV_MAX_DATA];
int16 speaker_series[CONV_MAX_DATA];
Commit: 4056f6a09113017a8fdec81f08498366f3e7ab62
https://github.com/scummvm/scummvm/commit/4056f6a09113017a8fdec81f08498366f3e7ab62
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:21+10:00
Commit Message:
MADS: PHANTOM: Adding speech data loading
Changed paths:
engines/mads/madsv2/core/conv.cpp
engines/mads/madsv2/core/object.cpp
engines/mads/madsv2/core/speech.cpp
engines/mads/madsv2/core/speech.h
diff --git a/engines/mads/madsv2/core/conv.cpp b/engines/mads/madsv2/core/conv.cpp
index 0a8888d630f..c6f16a13a1a 100644
--- a/engines/mads/madsv2/core/conv.cpp
+++ b/engines/mads/madsv2/core/conv.cpp
@@ -608,7 +608,7 @@ static void conv_generate_text(Conv *convIn, ConvData * /*convData*/,
// Play the associated speech audio when the speech system is on.
if (speech_system_active && speech_on && speechCount > 0) {
- speech_ems_play(convIn->speech_file, speechList[0]);
+ speech_play(convIn->speech_file, speechList[0]);
}
}
@@ -1324,7 +1324,7 @@ static void conv_generate_message(Conv *convIn, ConvData *convData,
if (speech_system_active && speech_on) {
if (voiceListSize != 0) {
- speech_ems_play(convIn->speech_file, *voiceList);
+ speech_play(convIn->speech_file, *voiceList);
}
}
}
diff --git a/engines/mads/madsv2/core/object.cpp b/engines/mads/madsv2/core/object.cpp
index 6c56118d251..2a97d855c93 100644
--- a/engines/mads/madsv2/core/object.cpp
+++ b/engines/mads/madsv2/core/object.cpp
@@ -365,7 +365,7 @@ int object_examine(int number, long message, int speech) {
/* pl if (speech) {
if (speech_system_active && speech_on) {
- speech_ems_play (object_speech_resource, speech);
+ speech_play (object_speech_resource, speech);
}
}
*/
diff --git a/engines/mads/madsv2/core/speech.cpp b/engines/mads/madsv2/core/speech.cpp
index 4417b3fb85a..134704f3d73 100644
--- a/engines/mads/madsv2/core/speech.cpp
+++ b/engines/mads/madsv2/core/speech.cpp
@@ -21,6 +21,9 @@
#include "common/textconsole.h"
#include "mads/madsv2/core/speech.h"
+#include "mads/madsv2/core/env.h"
+#include "mads/madsv2/core/mem.h"
+#include "mads/madsv2/core/pack.h"
namespace MADS {
namespace MADSV2 {
@@ -32,12 +35,76 @@ SpeechBuffer speech_main_buffer;
char global_speech_resource[16] = "*PHAN009.DSR";
int global_speech_ready = -1;
-SpeechDirPtr speech_load(const char *resName, int id, bool) {
- warning("TODO: speech_load");
- return nullptr;
+
+void SpeechDir::load(Common::SeekableReadStream *src) {
+ src->readMultipleLE(field0, compression, field4, field6, field8, size, offset);
+}
+
+
+SpeechDirPtr speech_load(const char *resName, int id, bool useMainMemory) {
+ SpeechDirPtr result = nullptr;
+ SpeechDirPtr speechPtr = nullptr;
+ uint filePos;
+ int count;
+ SpeechDir speechDir;
+ int headerSize, totalSize;
+ byte *load_buf;
+ int packing_flag;
+
+ // Always use main memory in ScummVM
+ useMainMemory = true;
+
+ // Open the sound resource for access
+ Common::SeekableReadStream *handle = env_open(resName);
+ if (!handle) goto done;
+ filePos = handle->pos();
+
+ // Get the number of voice samples in the file
+ count = handle->readUint16LE();
+
+ // Validate the speech Id specified is within range
+ --id;
+ if (id < 0 || id >= count) goto done;
+
+ // Seek to the correct offset and read the index entry
+ if (id > 0)
+ handle->seek(id * SpeechDir::SIZE, SEEK_CUR);
+ speechDir.load(handle);
+
+ // Seek to the start of the voice content
+ filePos += speechDir.offset;
+ handle->seek(filePos);
+
+ // Get the buffer space
+ headerSize = ((sizeof(SpeechDir) + 15) / 16) * 16;
+ totalSize = headerSize + speechDir.size;
+ speechPtr = (SpeechDirPtr)mem_get_name(totalSize, "$SPEECH");
+
+ // Copy the the index entry into memory block
+ *speechPtr = speechDir;
+ load_buf = (byte *)speechPtr + headerSize;
+
+ // Decompress the data
+ pack_strategy = speechDir.compression;
+ packing_flag = (speechDir.compression != PACK_NONE) ? PACK_EXPLODE : PACK_RAW_COPY;
+
+ if (pack_data(packing_flag, speechDir.size, FROM_DISK, handle, TO_MEMORY, load_buf) != speechDir.size) goto done;
+
+ // At this point we have valid data
+ result = speechPtr;
+
+done:
+ if (useMainMemory && !result && speechPtr)
+ mem_free(speechPtr);
+ delete handle;
+
+ return result;
}
-void speech_ems_play(const char *resName, int id) {
+void speech_play(const char *resName, int id) {
+ SpeechDirPtr speech = speech_load(resName, id);
+ assert(speech);
+
warning("TODO: global_speech_resource");
}
@@ -55,7 +122,7 @@ void speech_ems_go(int handle, int size) {
void global_speech(int id) {
if (speech_system_active && speech_on) {
- speech_ems_play(global_speech_resource, id);
+ speech_play(global_speech_resource, id);
}
}
diff --git a/engines/mads/madsv2/core/speech.h b/engines/mads/madsv2/core/speech.h
index 66b98de624e..31dc2ca291d 100644
--- a/engines/mads/madsv2/core/speech.h
+++ b/engines/mads/madsv2/core/speech.h
@@ -22,6 +22,7 @@
#ifndef MADS_CORE_SPEECH_H
#define MADS_CORE_SPEECH_H
+#include "common/stream.h"
#include "mads/madsv2/core/general.h"
namespace MADS {
@@ -32,7 +33,17 @@ struct SpeechBuffer {
int decompress_size;
};
-typedef void *SpeechDirPtr;
+struct SpeechDir {
+ int16 field0 = 0;
+ int16 compression = 0;
+ int16 field4 = 0, field6 = 0, field8 = 0;
+ int32 size = 0;
+ int32 offset = 0;
+
+ static constexpr int SIZE = 2 + 2 + 2 + 2 + 2 + 4 + 4;
+ void load(Common::SeekableReadStream *src);
+};
+typedef SpeechDir *SpeechDirPtr;
extern bool speech_system_active;
extern bool speech_on;
@@ -40,8 +51,8 @@ extern int speech_ems_handle;
extern SpeechBuffer speech_main_buffer;
extern int global_speech_ready;
-extern SpeechDirPtr speech_load(const char *resName, int id, bool);
-extern void speech_ems_play(const char *resName, int id);
+extern SpeechDirPtr speech_load(const char *resName, int id, bool useMainMemory = true);
+extern void speech_play(const char *resName, int id);
extern void speech_all_off();
extern void speech_sample_rate(int rate);
extern void speech_ems_go(int handle, int size);
Commit: a38facbef0d6f57f829eff5a887685d2a59c7312
https://github.com/scummvm/scummvm/commit/a38facbef0d6f57f829eff5a887685d2a59c7312
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:22+10:00
Commit Message:
MADS: PHANTOM: Fixes for startup speech init
Changed paths:
engines/mads/madsv2/core/kernel.cpp
engines/mads/madsv2/core/speech.cpp
engines/mads/madsv2/core/speech.h
engines/mads/madsv2/engine.cpp
engines/mads/madsv2/engine.h
diff --git a/engines/mads/madsv2/core/kernel.cpp b/engines/mads/madsv2/core/kernel.cpp
index f0d8fd6bf54..880871d5b57 100644
--- a/engines/mads/madsv2/core/kernel.cpp
+++ b/engines/mads/madsv2/core/kernel.cpp
@@ -32,6 +32,7 @@
#include "mads/madsv2/core/object.h"
#include "mads/madsv2/core/error.h"
#include "mads/madsv2/core/screen.h"
+#include "mads/madsv2/core/speech.h"
#include "mads/madsv2/core/ems.h"
#include "mads/madsv2/core/himem.h"
#include "mads/madsv2/core/echo.h"
@@ -262,11 +263,13 @@ void kernel_game_shutdown() {
/* Deallocate main screen buffer */
- if (work_screen_ems_handle < 0) buffer_free(&scr_main);
+ if (work_screen_ems_handle < 0)
+ buffer_free(&scr_main);
/* Turn of speech system */
- /* pl if (speech_system_active) speech_shutdown(); */
+ if (speech_system_active)
+ speech_shutdown();
/* Return video to text mode */
@@ -318,6 +321,8 @@ int kernel_game_startup(int game_video_mode, int load_flag,
himem_startup();
+ speech_init();
+
// ScummVM doesn't need EMS/XMS
#if 0
int ems_error = true;
diff --git a/engines/mads/madsv2/core/speech.cpp b/engines/mads/madsv2/core/speech.cpp
index 134704f3d73..3cade6a5b67 100644
--- a/engines/mads/madsv2/core/speech.cpp
+++ b/engines/mads/madsv2/core/speech.cpp
@@ -19,11 +19,13 @@
*
*/
+#include "audio/mixer.h"
#include "common/textconsole.h"
#include "mads/madsv2/core/speech.h"
#include "mads/madsv2/core/env.h"
#include "mads/madsv2/core/mem.h"
#include "mads/madsv2/core/pack.h"
+#include "mads/madsv2/engine.h"
namespace MADS {
namespace MADSV2 {
@@ -41,6 +43,14 @@ void SpeechDir::load(Common::SeekableReadStream *src) {
}
+void speech_init() {
+ speech_system_active = true;
+}
+
+void speech_shutdown() {
+ speech_system_active = false;
+}
+
SpeechDirPtr speech_load(const char *resName, int id, bool useMainMemory) {
SpeechDirPtr result = nullptr;
SpeechDirPtr speechPtr = nullptr;
diff --git a/engines/mads/madsv2/core/speech.h b/engines/mads/madsv2/core/speech.h
index 31dc2ca291d..6f069a0ee37 100644
--- a/engines/mads/madsv2/core/speech.h
+++ b/engines/mads/madsv2/core/speech.h
@@ -51,6 +51,8 @@ extern int speech_ems_handle;
extern SpeechBuffer speech_main_buffer;
extern int global_speech_ready;
+extern void speech_init();
+extern void speech_shutdown();
extern SpeechDirPtr speech_load(const char *resName, int id, bool useMainMemory = true);
extern void speech_play(const char *resName, int id);
extern void speech_all_off();
diff --git a/engines/mads/madsv2/engine.cpp b/engines/mads/madsv2/engine.cpp
index f93776ca303..6b41ca339c7 100644
--- a/engines/mads/madsv2/engine.cpp
+++ b/engines/mads/madsv2/engine.cpp
@@ -45,6 +45,7 @@ MADSV2Engine *g_engine;
MADSV2Engine::MADSV2Engine(OSystem *syst, const MADSGameDescription *gameDesc) :
MADSEngine(syst, gameDesc) {
g_engine = this;
+ _speechFlag = true;
}
MADSV2Engine::~MADSV2Engine() {
diff --git a/engines/mads/madsv2/engine.h b/engines/mads/madsv2/engine.h
index 0675c75e53d..9ff9f0ca816 100644
--- a/engines/mads/madsv2/engine.h
+++ b/engines/mads/madsv2/engine.h
@@ -29,6 +29,7 @@
#include "graphics/screen.h"
#include "mads/mads.h"
#include "mads/core/sound.h"
+#include "mads/madsv2/core/speech.h"
namespace MADS {
@@ -51,7 +52,7 @@ public:
MADS::SoundManager *_soundManager = nullptr;
bool _musicFlag = true;
bool _soundFlag = true;
- bool _speechFlag = true;
+ bool &_speechFlag = speech_on;
public:
MADSV2Engine(OSystem *syst, const MADSGameDescription *gameDesc);
Commit: 7b5353a578b23f19e8306798a827664fcbbd214d
https://github.com/scummvm/scummvm/commit/7b5353a578b23f19e8306798a827664fcbbd214d
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:22+10:00
Commit Message:
MADS: PHANTOM: Got speech code working using Audio::makeRawStream
Changed paths:
engines/mads/madsv2/core/speech.cpp
engines/mads/madsv2/core/speech.h
engines/mads/madsv2/engine.cpp
engines/mads/madsv2/engine.h
diff --git a/engines/mads/madsv2/core/speech.cpp b/engines/mads/madsv2/core/speech.cpp
index 3cade6a5b67..ad38696b5b6 100644
--- a/engines/mads/madsv2/core/speech.cpp
+++ b/engines/mads/madsv2/core/speech.cpp
@@ -20,7 +20,8 @@
*/
#include "audio/mixer.h"
-#include "common/textconsole.h"
+#include "audio/decoders/raw.h"
+#include "common/memstream.h"
#include "mads/madsv2/core/speech.h"
#include "mads/madsv2/core/env.h"
#include "mads/madsv2/core/mem.h"
@@ -32,10 +33,21 @@ namespace MADSV2 {
bool speech_system_active = false;
bool speech_on = false;
-int speech_ems_handle;
-SpeechBuffer speech_main_buffer;
char global_speech_resource[16] = "*PHAN009.DSR";
int global_speech_ready = -1;
+Audio::AudioStream *speech_stream;
+
+
+struct SpeechDir {
+ int16 field0 = 0;
+ int16 compression = 0;
+ int16 field4 = 0, field6 = 0, field8 = 0;
+ int32 size = 0;
+ int32 offset = 0;
+
+ static constexpr int SIZE = 2 + 2 + 2 + 2 + 2 + 4 + 4;
+ void load(Common::SeekableReadStream *src);
+};
void SpeechDir::load(Common::SeekableReadStream *src) {
@@ -48,17 +60,21 @@ void speech_init() {
}
void speech_shutdown() {
+ if (speech_stream) {
+ delete speech_stream;
+ speech_stream = nullptr;
+ }
+
speech_system_active = false;
}
-SpeechDirPtr speech_load(const char *resName, int id, bool useMainMemory) {
- SpeechDirPtr result = nullptr;
- SpeechDirPtr speechPtr = nullptr;
+Audio::AudioStream *speech_load(const char *resName, int id, bool useMainMemory) {
+ Common::MemoryReadStream *memStream;
+ Audio::AudioStream *audioStream = nullptr;
uint filePos;
int count;
SpeechDir speechDir;
- int headerSize, totalSize;
- byte *load_buf;
+ byte *load_buf = nullptr;
int packing_flag;
// Always use main memory in ScummVM
@@ -86,13 +102,7 @@ SpeechDirPtr speech_load(const char *resName, int id, bool useMainMemory) {
handle->seek(filePos);
// Get the buffer space
- headerSize = ((sizeof(SpeechDir) + 15) / 16) * 16;
- totalSize = headerSize + speechDir.size;
- speechPtr = (SpeechDirPtr)mem_get_name(totalSize, "$SPEECH");
-
- // Copy the the index entry into memory block
- *speechPtr = speechDir;
- load_buf = (byte *)speechPtr + headerSize;
+ load_buf = (byte *)malloc(speechDir.size);
// Decompress the data
pack_strategy = speechDir.compression;
@@ -101,33 +111,40 @@ SpeechDirPtr speech_load(const char *resName, int id, bool useMainMemory) {
if (pack_data(packing_flag, speechDir.size, FROM_DISK, handle, TO_MEMORY, load_buf) != speechDir.size) goto done;
// At this point we have valid data
- result = speechPtr;
+ memStream = new Common::MemoryReadStream(load_buf, speechDir.size, DisposeAfterUse::YES);
+ audioStream = Audio::makeRawStream(memStream, 11025, Audio::FLAG_UNSIGNED, DisposeAfterUse::YES);
done:
- if (useMainMemory && !result && speechPtr)
- mem_free(speechPtr);
delete handle;
- return result;
+ delete speech_stream;
+ speech_stream = audioStream;
+
+ return audioStream;
}
void speech_play(const char *resName, int id) {
- SpeechDirPtr speech = speech_load(resName, id);
- assert(speech);
+ Audio::AudioStream *speech = speech_load(resName, id);
- warning("TODO: global_speech_resource");
+ if (speech)
+ g_engine->playSpeech(speech);
+
+ speech_stream = nullptr;
}
void speech_all_off() {
- warning("TODO: speech_all_off");
+ g_engine->stopSpeech();
}
void speech_sample_rate(int rate) {
- warning("TODO: speech_sample_rate");
+ // TODO: implement speech_sample_rate
}
-void speech_ems_go(int handle, int size) {
- warning("TODO: speech_ems_go");
+void speech_go() {
+ if (speech_stream) {
+ g_engine->playSpeech(speech_stream);
+ speech_stream = nullptr;
+ }
}
void global_speech(int id) {
@@ -137,7 +154,7 @@ void global_speech(int id) {
}
void global_speech_load(int id) {
- SpeechDirPtr chunk;
+ Audio::AudioStream *chunk;
if (speech_system_active && speech_on) {
speech_all_off();
@@ -156,8 +173,8 @@ void global_speech_go(int id) {
if (speech_system_active && speech_on) {
if (global_speech_ready == id) {
speech_all_off();
- speech_sample_rate(speech_main_buffer.sample_rate);
- speech_ems_go(speech_ems_handle, speech_main_buffer.decompress_size);
+ //speech_sample_rate(speech_main_buffer.sample_rate);
+ speech_go();
} else {
global_speech(id);
}
diff --git a/engines/mads/madsv2/core/speech.h b/engines/mads/madsv2/core/speech.h
index 6f069a0ee37..4767081080e 100644
--- a/engines/mads/madsv2/core/speech.h
+++ b/engines/mads/madsv2/core/speech.h
@@ -22,42 +22,24 @@
#ifndef MADS_CORE_SPEECH_H
#define MADS_CORE_SPEECH_H
+#include "audio/audiostream.h"
#include "common/stream.h"
#include "mads/madsv2/core/general.h"
namespace MADS {
namespace MADSV2 {
-struct SpeechBuffer {
- int sample_rate;
- int decompress_size;
-};
-
-struct SpeechDir {
- int16 field0 = 0;
- int16 compression = 0;
- int16 field4 = 0, field6 = 0, field8 = 0;
- int32 size = 0;
- int32 offset = 0;
-
- static constexpr int SIZE = 2 + 2 + 2 + 2 + 2 + 4 + 4;
- void load(Common::SeekableReadStream *src);
-};
-typedef SpeechDir *SpeechDirPtr;
-
extern bool speech_system_active;
extern bool speech_on;
-extern int speech_ems_handle;
-extern SpeechBuffer speech_main_buffer;
extern int global_speech_ready;
extern void speech_init();
extern void speech_shutdown();
-extern SpeechDirPtr speech_load(const char *resName, int id, bool useMainMemory = true);
+extern Audio::AudioStream *speech_load(const char *resName, int id, bool useMainMemory = true);
extern void speech_play(const char *resName, int id);
extern void speech_all_off();
extern void speech_sample_rate(int rate);
-extern void speech_ems_go(int handle, int size);
+extern void speech_go();
extern void global_speech_load(int id);
extern void global_speech_go(int id);
extern void global_speech(int id);
diff --git a/engines/mads/madsv2/engine.cpp b/engines/mads/madsv2/engine.cpp
index 6b41ca339c7..44fc040fc7a 100644
--- a/engines/mads/madsv2/engine.cpp
+++ b/engines/mads/madsv2/engine.cpp
@@ -236,5 +236,13 @@ uint32 MADSV2Engine::getMillis() {
return g_system->getMillis();
}
+void MADSV2Engine::playSpeech(Audio::AudioStream *stream) {
+ _mixer->playStream(Audio::Mixer::kSpeechSoundType, &_speechHandle, stream);
+}
+
+void MADSV2Engine::stopSpeech() {
+ _mixer->stopHandle(_speechHandle);
+}
+
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/engine.h b/engines/mads/madsv2/engine.h
index 9ff9f0ca816..a91cc09e983 100644
--- a/engines/mads/madsv2/engine.h
+++ b/engines/mads/madsv2/engine.h
@@ -22,6 +22,7 @@
#ifndef MADSV2_ENGINE_H
#define MADSV2_ENGINE_H
+#include "audio/mixer.h"
#include "common/events.h"
#include "common/serializer.h"
#include "common/stack.h"
@@ -45,6 +46,7 @@ protected:
uint32 _nextFrameTime = 0;
Common::Point _mousePos;
int _mouseButtons = 0;
+ Audio::SoundHandle _speechHandle;
void pollEvents();
@@ -102,6 +104,9 @@ public:
virtual void global_room_init() = 0;
virtual void global_sound_driver() = 0;
virtual void global_verb_filter() {}
+
+ void playSpeech(Audio::AudioStream *stream);
+ void stopSpeech();
};
extern MADSV2Engine *g_engine;
Commit: 56ba643484a0a6509d3b57b0063636eebf54cd35
https://github.com/scummvm/scummvm/commit/56ba643484a0a6509d3b57b0063636eebf54cd35
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:22+10:00
Commit Message:
MADS: PHANTOM: Implement Exit button on main menu
Changed paths:
engines/mads/madsv2/phantom/main.cpp
diff --git a/engines/mads/madsv2/phantom/main.cpp b/engines/mads/madsv2/phantom/main.cpp
index 4ee0689511e..bba73110b1c 100644
--- a/engines/mads/madsv2/phantom/main.cpp
+++ b/engines/mads/madsv2/phantom/main.cpp
@@ -279,6 +279,10 @@ void phantom_main() {
game_main(2, CMD_LINE);
break;
+ case 4:
+ // Exit
+ return;
+
default:
break;
}
Commit: 434ca5a7f2f0547c71e024a70fc409a61f2456da
https://github.com/scummvm/scummvm/commit/434ca5a7f2f0547c71e024a70fc409a61f2456da
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:22+10:00
Commit Message:
MADS: PHANTOM: Fix interface command list display
Changed paths:
engines/mads/madsv2/core/inter.cpp
diff --git a/engines/mads/madsv2/core/inter.cpp b/engines/mads/madsv2/core/inter.cpp
index 2c78626351d..74a99613816 100644
--- a/engines/mads/madsv2/core/inter.cpp
+++ b/engines/mads/madsv2/core/inter.cpp
@@ -82,14 +82,15 @@ int inter_dialog_results[inter_columns];
Verb command[INTER_COMMANDS] = { /* Main Verb List */
{ words_look, VERB_THAT, PREP_NONE },
- { words_give, VERB_THIS, PREP_TO },
{ words_take, VERB_THAT, PREP_NONE },
- { words_talk_to, VERB_THAT, PREP_NONE },
{ words_push, VERB_THAT, PREP_NONE },
- { words_pull, VERB_THAT, PREP_NONE },
- { words_put, VERB_THIS, PREP_RELATIONAL },
{ words_open, VERB_THAT, PREP_NONE },
- { words_close, VERB_THAT, PREP_NONE }
+ { words_put, VERB_THIS, PREP_RELATIONAL },
+ { words_talk_to, VERB_THAT, PREP_NONE },
+ { words_give, VERB_THIS, PREP_TO },
+ { words_pull, VERB_THAT, PREP_NONE },
+ { words_close, VERB_THAT, PREP_NONE },
+ { words_throw, VERB_THIS, PREP_AT }
};
@@ -353,7 +354,6 @@ static void inter_show_word(int class_, int id) {
int x, y, junk;
int word_id = 0;
char temp_buf[80];
- int paul_id;
int write_it = true;
if (!inter_get_spot(class_, id, &x, &y, &junk, &junk)) {
@@ -425,14 +425,6 @@ static void inter_show_word(int class_, int id) {
case STROKE_ACTION:
default:
-
- paul_id = object[inven[active_inven]].vocab_id;
- paul_id = object_named(paul_id);
-
- if (paul_id == 8 && !global[86]) { /* pid doll / global [heal_verbs_visible] */
- if (id > 0) write_it = false; /* id == second verb, or == third verb */
- }
-
word_id = object[inven[active_inven]].verb[id].id;
if (id == left_action) {
inter_set_colors(LEFT_SELECT);
@@ -449,25 +441,6 @@ static void inter_show_word(int class_, int id) {
temp_buf[0] = (char)toupper((int)temp_buf[0]);
write:
-
- /* if (class_ == STROKE_INVEN) */
-
- if (class_ == STROKE_COMMAND) {
- switch (word_id) {
- case 3: x += 10; break; /* look */
- case 9: x += 12; break; /* give */
- case 4: x += 10; break; /* take */
-
- case 8: x += 4; break; /* talk to */
- case 5: x += 10; break; /* push */
- case 10: x += 13; break; /* pull */
-
- case 7: x += 12; break; /* put */
- case 6: x += 10; break; /* open */
- case 11: x += 9; break; /* close */
- }
- }
-
if (write_it)
font_write(font_inter, &scr_inter, temp_buf, x, y, 0);
Commit: 181ea1767e28914d6799e7fb1488a508faf6332a
https://github.com/scummvm/scummvm/commit/181ea1767e28914d6799e7fb1488a508faf6332a
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:23+10:00
Commit Message:
MADS: PHANTOM: Minor fixes to pal_allocate
Changed paths:
engines/mads/madsv2/core/pal.cpp
diff --git a/engines/mads/madsv2/core/pal.cpp b/engines/mads/madsv2/core/pal.cpp
index fd0815bcd81..501cf9719c1 100644
--- a/engines/mads/madsv2/core/pal.cpp
+++ b/engines/mads/madsv2/core/pal.cpp
@@ -301,7 +301,6 @@ int pal_allocate(ColorListPtr new_list, ShadowListPtr shadow_list, int pal_flags
int shadowing_enabled;
int shadowing_special;
int defining_background;
- int primary_load;
int conduct_search, conduct_insert;
int free_colors;
int hash, best_hash;
@@ -343,7 +342,6 @@ int pal_allocate(ColorListPtr new_list, ShadowListPtr shadow_list, int pal_flags
/* Check if we are defining a new background picture */
defining_background = pal_flags & PAL_MAP_BACKGROUND;
- primary_load = pal_flags & (PAL_MAP_BACKGROUND | PAL_MAP_DEFINE_RESERVED);
/* If a shadowing description was passed, enable shadow checking */
@@ -378,12 +376,6 @@ int pal_allocate(ColorListPtr new_list, ShadowListPtr shadow_list, int pal_flags
/* require an exact RGB mapping are given the first chance to allocate */
/* free color space. */
- /*
- reordering_index = mem_get_name(256, "$palidx");
- reordering_hash = mem_get_name(256, "$palhash");
- if ((reordering_index == NULL) || (reordering_hash == NULL)) goto done;
- */
-
for (count = 0; count < new_list->num_colors; count++) {
reordering_index[count] = (byte)count;
reordering_hash[count] = 0;
@@ -458,10 +450,9 @@ int pal_allocate(ColorListPtr new_list, ShadowListPtr shadow_list, int pal_flags
/* found a (shadowing) match; and B) if we are defining an initial */
/* background and therefore should not have any matches. */
- conduct_search = (!found) && (!defining_background);
+ conduct_search = !found && !defining_background && cycle_mask != 0;
if (conduct_search) {
-
/* Now, decide whether we need an exact match or are willing to just */
/* take the closest. */
@@ -550,14 +541,10 @@ int pal_allocate(ColorListPtr new_list, ShadowListPtr shadow_list, int pal_flags
pal_exec(pal_manager_update, 2);
done:
- /*
- if (reordering_hash != NULL) mem_free(reordering_hash);
- if (reordering_index != NULL) mem_free(reordering_index);
- */
#ifdef palette_dumps
pal_dump();
#endif
- return (return_code);
+ return return_code;
}
int pal_get_flags()
Commit: 7684e51bffb3cb0591e53bc6c3b52275d8746552
https://github.com/scummvm/scummvm/commit/7684e51bffb3cb0591e53bc6c3b52275d8746552
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:23+10:00
Commit Message:
MADS: PHANTOM: Fix incorrect type sizes in insertion_sort
This was causing the issues with the character shadows,
as well as running out of palette space on room change
Changed paths:
engines/mads/madsv2/core/sort.cpp
diff --git a/engines/mads/madsv2/core/sort.cpp b/engines/mads/madsv2/core/sort.cpp
index a745959c7b6..97653619e1d 100644
--- a/engines/mads/madsv2/core/sort.cpp
+++ b/engines/mads/madsv2/core/sort.cpp
@@ -24,7 +24,6 @@
namespace MADS {
namespace MADSV2 {
-
void sort_insertion(int elements, int *id, long *value) {
int going, count, count2, my_id;
int insertion, deletion;
@@ -36,21 +35,29 @@ void sort_insertion(int elements, int *id, long *value) {
going = false;
for (count = 0; (count < (elements - 1)) && !going; count++) {
if (value[count] > value[count + 1]) {
- deletion = (elements - (count + 1)) << 1;
+ deletion = elements - (count + 1);
my_value = value[count];
my_id = id[count];
if (deletion > 0) {
- memmove(&value[count], &value[count + 1], (deletion << 1));
- memmove(&id[count], &id[count + 1], deletion);
+ memmove(&value[count], &value[count + 1], deletion * sizeof(long));
+ memmove(&id[count], &id[count + 1], deletion * sizeof(int));
}
for (count2 = 0; (count2 < elements - 1) && !going; count2++) {
going = (my_value < value[count2]);
}
+ /* After the loop, count2 has been post-incremented one step past
+ * the found insertion position. If going was set to true inside
+ * the loop (i.e. we found a value[count2-1] > my_value), the for
+ * loop's count2++ still fired, so the real target index is
+ * count2-1. Decrement to correct for this. */
+ if (going) {
+ count2--;
+ }
going = true;
- insertion = ((elements - 1) - count2) << 1;
+ insertion = (elements - 1) - count2;
if (insertion > 0) {
- memmove(&value[count2 + 1], &value[count2], (insertion << 1));
- memmove(&id[count2 + 1], &id[count2], insertion);
+ memmove(&value[count2 + 1], &value[count2], insertion * sizeof(long));
+ memmove(&id[count2 + 1], &id[count2], insertion * sizeof(int));
}
value[count2] = my_value;
id[count2] = my_id;
Commit: 8edeee181fda9bf5f919eb07fc4d89543c002fbc
https://github.com/scummvm/scummvm/commit/8edeee181fda9bf5f919eb07fc4d89543c002fbc
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:23+10:00
Commit Message:
MADS: PHANTOM: Added sizeof(byte) to sort functions for better clarity
Changed paths:
engines/mads/madsv2/core/sort.cpp
diff --git a/engines/mads/madsv2/core/sort.cpp b/engines/mads/madsv2/core/sort.cpp
index 97653619e1d..cdf19ed9a2d 100644
--- a/engines/mads/madsv2/core/sort.cpp
+++ b/engines/mads/madsv2/core/sort.cpp
@@ -96,7 +96,7 @@ void sort_insertion_16(int elements, byte *id, word *value) {
int deletion = limit - si - 1;
if (deletion > 0) {
memmove(&value[si + 1], &value[si + 2], deletion * sizeof(word));
- memmove(&id[si + 1], &id[si + 2], deletion);
+ memmove(&id[si + 1], &id[si + 2], deletion * sizeof(byte));
}
/* quest_loop: find correct insertion point for my_value in [0..limit-1] */
@@ -111,7 +111,7 @@ void sort_insertion_16(int elements, byte *id, word *value) {
int insertion = limit - count2;
if (insertion > 0) {
memmove(&value[count2 + 1], &value[count2], insertion * sizeof(word));
- memmove(&id[count2 + 1], &id[count2], insertion);
+ memmove(&id[count2 + 1], &id[count2], insertion * sizeof(byte));
}
/* Insert saved element at its correct position */
@@ -148,8 +148,8 @@ void sort_insertion_8(int elements, byte *id, byte *value) {
/* Delete element at si+1 by shifting everything above it down one */
int deletion = limit - si - 1;
if (deletion > 0) {
- memmove(&value[si + 1], &value[si + 2], deletion);
- memmove(&id[si + 1], &id[si + 2], deletion);
+ memmove(&value[si + 1], &value[si + 2], deletion * sizeof(byte));
+ memmove(&id[si + 1], &id[si + 2], deletion * sizeof(byte));
}
/* quest_loop: find correct insertion point for my_value in [0..limit-1] */
@@ -164,8 +164,8 @@ void sort_insertion_8(int elements, byte *id, byte *value) {
int insertion = limit - count2;
if (insertion > 0) {
/* shift backwards (std / rep movsb in original) */
- memmove(&value[count2 + 1], &value[count2], insertion);
- memmove(&id[count2 + 1], &id[count2], insertion);
+ memmove(&value[count2 + 1], &value[count2], insertion * sizeof(byte));
+ memmove(&id[count2 + 1], &id[count2], insertion * sizeof(byte));
}
/* Insert saved element at its correct position */
Commit: e376e303e90848467fb5526399b0da3ae1abb5ae
https://github.com/scummvm/scummvm/commit/e376e303e90848467fb5526399b0da3ae1abb5ae
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:24+10:00
Commit Message:
MADS: PHANTOM: Fix drawing of horizontally flipped sprites
Changed paths:
engines/mads/madsv2/core/sprite_0.cpp
diff --git a/engines/mads/madsv2/core/sprite_0.cpp b/engines/mads/madsv2/core/sprite_0.cpp
index ef21cb77688..b66690fea56 100644
--- a/engines/mads/madsv2/core/sprite_0.cpp
+++ b/engines/mads/madsv2/core/sprite_0.cpp
@@ -274,11 +274,9 @@ ys = sprite->ys;
ax--;
target_x = ax;
- di -= cx; /* subtract original stop_x from size */
- di = -di; /* negate for pointer calculations */
- skip_x = di;
+ di -= stop_x; /* subtract original stop_x from size */
+ skip_x = -di;
- di = -di; /* make positive again */
di += draw_x;
stop_x = di;
}
Commit: 6eaf1e4af5462d5bd9586e0ea78d1447ca3cdc00
https://github.com/scummvm/scummvm/commit/6eaf1e4af5462d5bd9586e0ea78d1447ca3cdc00
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:24+10:00
Commit Message:
MADS: PHANTOM: Disable original cheat keys for now
Changed paths:
engines/mads/madsv2/phantom/main.cpp
diff --git a/engines/mads/madsv2/phantom/main.cpp b/engines/mads/madsv2/phantom/main.cpp
index bba73110b1c..4f42fe0af22 100644
--- a/engines/mads/madsv2/phantom/main.cpp
+++ b/engines/mads/madsv2/phantom/main.cpp
@@ -145,7 +145,7 @@ static void main_cold_data_init() {
Common::strcpy_s(kernel_cheating_password, "WIDECHEW");
kernel_cheating_allowed = strlen(kernel_cheating_password);
- kernel.cheating = (byte)kernel_cheating_allowed;
+ kernel.cheating = gDebugLevel == 9 ? kernel_cheating_allowed : 0;
}
static void game_main(int argc, const char **argv) {
Commit: 881a3d15788e789922f5b5ea2b3b29d39739eb6b
https://github.com/scummvm/scummvm/commit/881a3d15788e789922f5b5ea2b3b29d39739eb6b
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:24+10:00
Commit Message:
MADS: PHANTOM: Fix key constants, mapping keybinding to keys
Changed paths:
engines/mads/mads.h
engines/mads/madsv2/core/game.cpp
engines/mads/madsv2/core/keys.h
engines/mads/madsv2/engine.cpp
engines/mads/madsv2/engine.h
engines/mads/nebular/nebular.h
diff --git a/engines/mads/mads.h b/engines/mads/mads.h
index 723ef63ead7..17f5733c734 100644
--- a/engines/mads/mads.h
+++ b/engines/mads/mads.h
@@ -49,6 +49,21 @@ enum ScreenFade {
SCREEN_FADE_FAST = 2
};
+enum MADSActions {
+ kActionNone,
+ kActionEscape,
+ kActionGameMenu,
+ kActionSave,
+ kActionRestore,
+ kActionScrollUp,
+ kActionScrollDown,
+ kActionStartGame,
+ kActionResumeGame,
+ kActionShowIntro,
+ kActionCredits,
+ kActionQuotes,
+ kActionRestartAnimation
+};
class MADSEngine : public Engine {
protected:
diff --git a/engines/mads/madsv2/core/game.cpp b/engines/mads/madsv2/core/game.cpp
index 3aac34cc5c6..c0147b424df 100644
--- a/engines/mads/madsv2/core/game.cpp
+++ b/engines/mads/madsv2/core/game.cpp
@@ -1034,7 +1034,6 @@ int game_parse_keystroke(int mykey) {
}
}
-
if (kernel.cheating < (byte)kernel_cheating_allowed) {
if (mykey == (kernel_cheating_password[kernel.cheating] - '@')) {
kernel.cheating++;
diff --git a/engines/mads/madsv2/core/keys.h b/engines/mads/madsv2/core/keys.h
index 89b6a37e9b6..f50a0bd50f8 100644
--- a/engines/mads/madsv2/core/keys.h
+++ b/engines/mads/madsv2/core/keys.h
@@ -22,13 +22,14 @@
#ifndef MADS_CORE_KEYS_H
#define MADS_CORE_KEYS_H
+#include "common/keyboard.h"
#include "mads/madsv2/core/general.h"
namespace MADS {
namespace MADSV2 {
/* keystroke defines */
-
+#if 0
#define key_status_1 (byte *) 0x00400017 /* key status 1 */
#define key_status_2 (byte *) 0x00400018 /* key status 2 */
@@ -40,163 +41,164 @@ namespace MADSV2 {
#define KS1_CTRL 0x04 /* Ctrl key state */
#define KS1_LEFTSHIFT 0x02 /* Left shift state */
#define KS1_RIGHTSHIFT 0x01 /* Right shift state */
+#endif
-#define left_key 0x14b
-#define right_key 0x14d
-#define up_key 0x148
-#define down_key 0x150
-
-#define ins_key 0x152
-#define del_key 0x153
-#define delete_key 0x153
-
-#define home_key 0x147
-#define end_key 0x14f
-
-#define pgup_key 0x149
-#define pgdn_key 0x151
-
-#define enter_key 0x0d
-#define esc_key 0x1b
-#define bksp_key 0x08
-#define ctrl_del_key 0x193
-#define tab_key 0x09
-#define backtab_key 0x10f
-
-#define space_key 0x20
-
-#define A_key 0x41
-#define B_key 0x42
-#define C_key 0x43
-#define D_key 0x44
-#define E_key 0x45
-#define F_key 0x46
-#define G_key 0x47
-#define H_key 0x48
-#define I_key 0x49
-#define J_key 0x4a
-#define K_key 0x4b
-#define L_key 0x4c
-#define M_key 0x4d
-#define N_key 0x4e
-#define O_key 0x4f
-#define P_key 0x50
-#define Q_key 0x51
-#define R_key 0x52
-#define S_key 0x53
-#define T_key 0x54
-#define U_key 0x55
-#define V_key 0x56
-#define W_key 0x57
-#define X_key 0x58
-#define Y_key 0x59
-#define Z_key 0x5a
-
-#define a_key 0x61
-#define b_key 0x62
-#define g_key 0x67
-#define i_key 0x69
-#define j_key 0x6a
-#define m_key 0x6d
-#define z_key 0x7a
-
-#define alt_a_key 0x11e
-#define alt_b_key 0x130
-#define alt_c_key 0x12e
-#define alt_d_key 0x120
-#define alt_e_key 0x112
-#define alt_f_key 0x121
-#define alt_g_key 0x122
-#define alt_h_key 0x123
-#define alt_i_key 0x117
-#define alt_j_key 0x124
-#define alt_k_key 0x125
-#define alt_l_key 0x126
-#define alt_m_key 0x132
-#define alt_n_key 0x131
-#define alt_o_key 0x118
-#define alt_p_key 0x119
-#define alt_q_key 0x110
-#define alt_r_key 0x113
-#define alt_s_key 0x11f
-#define alt_t_key 0x114
-#define alt_u_key 0x116
-#define alt_v_key 0x12f
-#define alt_w_key 0x111
-#define alt_x_key 0x12d
-#define alt_y_key 0x115
-#define alt_z_key 0x12c
-
-#define f1_key 0x13b
-#define f2_key 0x13c
-#define f3_key 0x13d
-#define f4_key 0x13e
-#define f5_key 0x13f
-#define f6_key 0x140
-#define f7_key 0x141
-#define f8_key 0x142
-#define f9_key 0x143
-#define f10_key 0x144
-
-#define shift_f1_key 0x154
-#define shift_f2_key 0x155
-#define shift_f3_key 0x156
-#define shift_f4_key 0x157
-#define shift_f5_key 0x158
-#define shift_f6_key 0x159
-#define shift_f7_key 0x15a
-#define shift_f8_key 0x15b
-#define shift_f9_key 0x15c
-#define shift_f10_key 0x15d
-
-#define ctrl_f1_key 0x15e
-#define ctrl_f2_key 0x15f
-#define ctrl_f3_key 0x160
-#define ctrl_f4_key 0x161
-#define ctrl_f5_key 0x162
-#define ctrl_f6_key 0x163
-#define ctrl_f7_key 0x164
-#define ctrl_f8_key 0x165
-#define ctrl_f9_key 0x166
-#define ctrl_f10_key 0x167
-
-#define alt_f1_key 0x168
-#define alt_f2_key 0x169
-#define alt_f3_key 0x16a
-#define alt_f4_key 0x16b
-#define alt_f5_key 0x16c
-#define alt_f6_key 0x16d
-#define alt_f7_key 0x16e
-#define alt_f8_key 0x16f
-#define alt_f9_key 0x170
-#define alt_f10_key 0x171
-
-#define ctrl_a_key 0x01
-#define ctrl_b_key 0x02
-#define ctrl_c_key 0x03
-#define ctrl_d_key 0x04
-#define ctrl_e_key 0x05
-#define ctrl_f_key 0x06
-#define ctrl_g_key 0x07
-#define ctrl_h_key 0x08
-#define ctrl_i_key 0x09
-#define ctrl_j_key 0x0a
-#define ctrl_k_key 0x0b
-#define ctrl_l_key 0x0c
-#define ctrl_m_key 0x0d
-#define ctrl_n_key 0x0e
-#define ctrl_o_key 0x0f
-#define ctrl_p_key 0x10
-#define ctrl_q_key 0x11
-#define ctrl_r_key 0x12
-#define ctrl_s_key 0x13
-#define ctrl_t_key 0x14
-#define ctrl_u_key 0x15
-#define ctrl_v_key 0x16
-#define ctrl_w_key 0x17
-#define ctrl_x_key 0x18
-#define ctrl_y_key 0x19
-#define ctrl_z_key 0x1a
+#define left_key Common::KEYCODE_LEFT
+#define right_key Common::KEYCODE_RIGHT
+#define up_key Common::KEYCODE_UP
+#define down_key Common::KEYCODE_DOWN
+
+#define ins_key Common::KEYCODE_INSERT
+#define del_key Common::KEYCODE_DELETE
+#define delete_key Common::KEYCODE_DELETE
+
+#define home_key Common::KEYCODE_HOME
+#define end_key Common::KEYCODE_END
+
+#define pgup_key Common::KEYCODE_PAGEUP
+#define pgdn_key Common::KEYCODE_PAGEDOWN
+
+#define enter_key Common::KEYCODE_RETURN
+#define esc_key Common::KEYCODE_ESCAPE
+#define bksp_key Common::KEYCODE_BACKSPACE
+#define ctrl_del_key ((Common::KBD_CTRL << 16) | Common::KEYCODE_DELETE)
+#define tab_key Common::KEYCODE_TAB
+#define backtab_key ((Common::KBD_SHIFT << 16) | Common::KEYCODE_TAB)
+
+#define space_key Common::KEYCODE_SPACE
+
+#define A_key 'A'
+#define B_key 'B'
+#define C_key 'C'
+#define D_key 'D'
+#define E_key 'E'
+#define F_key 'F'
+#define G_key 'G'
+#define H_key 'H'
+#define I_key 'I'
+#define J_key 'J'
+#define K_key 'K'
+#define L_key 'L'
+#define M_key 'M'
+#define N_key 'N'
+#define O_key 'O'
+#define P_key 'P'
+#define Q_key 'Q'
+#define R_key 'R'
+#define S_key 'S'
+#define T_key 'T'
+#define U_key 'U'
+#define V_key 'V'
+#define W_key 'W'
+#define X_key 'X'
+#define Y_key 'Y'
+#define Z_key 'Z'
+
+#define a_key 'a'
+#define b_key 'b'
+#define g_key 'g'
+#define i_key 'i'
+#define j_key 'j'
+#define m_key 'm'
+#define z_key 'z'
+
+#define alt_a_key ((Common::KBD_ALT << 16) | Common::KEYCODE_a)
+#define alt_b_key ((Common::KBD_ALT << 16) | Common::KEYCODE_b)
+#define alt_c_key ((Common::KBD_ALT << 16) | Common::KEYCODE_c)
+#define alt_d_key ((Common::KBD_ALT << 16) | Common::KEYCODE_d)
+#define alt_e_key ((Common::KBD_ALT << 16) | Common::KEYCODE_e)
+#define alt_f_key ((Common::KBD_ALT << 16) | Common::KEYCODE_f)
+#define alt_g_key ((Common::KBD_ALT << 16) | Common::KEYCODE_g)
+#define alt_h_key ((Common::KBD_ALT << 16) | Common::KEYCODE_h)
+#define alt_i_key ((Common::KBD_ALT << 16) | Common::KEYCODE_i)
+#define alt_j_key ((Common::KBD_ALT << 16) | Common::KEYCODE_j)
+#define alt_k_key ((Common::KBD_ALT << 16) | Common::KEYCODE_k)
+#define alt_l_key ((Common::KBD_ALT << 16) | Common::KEYCODE_l)
+#define alt_m_key ((Common::KBD_ALT << 16) | Common::KEYCODE_m)
+#define alt_n_key ((Common::KBD_ALT << 16) | Common::KEYCODE_n)
+#define alt_o_key ((Common::KBD_ALT << 16) | Common::KEYCODE_o)
+#define alt_p_key ((Common::KBD_ALT << 16) | Common::KEYCODE_p)
+#define alt_q_key ((Common::KBD_ALT << 16) | Common::KEYCODE_q)
+#define alt_r_key ((Common::KBD_ALT << 16) | Common::KEYCODE_r)
+#define alt_s_key ((Common::KBD_ALT << 16) | Common::KEYCODE_s)
+#define alt_t_key ((Common::KBD_ALT << 16) | Common::KEYCODE_t)
+#define alt_u_key ((Common::KBD_ALT << 16) | Common::KEYCODE_u)
+#define alt_v_key ((Common::KBD_ALT << 16) | Common::KEYCODE_v)
+#define alt_w_key ((Common::KBD_ALT << 16) | Common::KEYCODE_w)
+#define alt_x_key ((Common::KBD_ALT << 16) | Common::KEYCODE_x)
+#define alt_y_key ((Common::KBD_ALT << 16) | Common::KEYCODE_y)
+#define alt_z_key ((Common::KBD_ALT << 16) | Common::KEYCODE_z)
+
+#define f1_key Common::KEYCODE_F1
+#define f2_key Common::KEYCODE_F2
+#define f3_key Common::KEYCODE_F3
+#define f4_key Common::KEYCODE_F4
+#define f5_key Common::KEYCODE_F5
+#define f6_key Common::KEYCODE_F6
+#define f7_key Common::KEYCODE_F7
+#define f8_key Common::KEYCODE_F8
+#define f9_key Common::KEYCODE_F9
+#define f10_key Common::KEYCODE_F10
+
+#define shift_f1_key ((Common::KBD_SHIFT << 16) | Common::KEYCODE_F1)
+#define shift_f2_key ((Common::KBD_SHIFT << 16) | Common::KEYCODE_F2)
+#define shift_f3_key ((Common::KBD_SHIFT << 16) | Common::KEYCODE_F3)
+#define shift_f4_key ((Common::KBD_SHIFT << 16) | Common::KEYCODE_F4)
+#define shift_f5_key ((Common::KBD_SHIFT << 16) | Common::KEYCODE_F5)
+#define shift_f6_key ((Common::KBD_SHIFT << 16) | Common::KEYCODE_F6)
+#define shift_f7_key ((Common::KBD_SHIFT << 16) | Common::KEYCODE_F7)
+#define shift_f8_key ((Common::KBD_SHIFT << 16) | Common::KEYCODE_F8)
+#define shift_f9_key ((Common::KBD_SHIFT << 16) | Common::KEYCODE_F9)
+#define shift_f10_key ((Common::KBD_SHIFT << 16) | Common::KEYCODE_F10)
+
+#define ctrl_f1_key ((Common::KBD_CTRL << 16) | Common::KEYCODE_F1)
+#define ctrl_f2_key ((Common::KBD_CTRL << 16) | Common::KEYCODE_F2)
+#define ctrl_f3_key ((Common::KBD_CTRL << 16) | Common::KEYCODE_F3)
+#define ctrl_f4_key ((Common::KBD_CTRL << 16) | Common::KEYCODE_F4)
+#define ctrl_f5_key ((Common::KBD_CTRL << 16) | Common::KEYCODE_F5)
+#define ctrl_f6_key ((Common::KBD_CTRL << 16) | Common::KEYCODE_F6)
+#define ctrl_f7_key ((Common::KBD_CTRL << 16) | Common::KEYCODE_F7)
+#define ctrl_f8_key ((Common::KBD_CTRL << 16) | Common::KEYCODE_F8)
+#define ctrl_f9_key ((Common::KBD_CTRL << 16) | Common::KEYCODE_F9)
+#define ctrl_f10_key ((Common::KBD_CTRL << 16) | Common::KEYCODE_F10)
+
+#define alt_f1_key ((Common::KBD_ALT << 16) | Common::KEYCODE_F1)
+#define alt_f2_key ((Common::KBD_ALT << 16) | Common::KEYCODE_F2)
+#define alt_f3_key ((Common::KBD_ALT << 16) | Common::KEYCODE_F3)
+#define alt_f4_key ((Common::KBD_ALT << 16) | Common::KEYCODE_F4)
+#define alt_f5_key ((Common::KBD_ALT << 16) | Common::KEYCODE_F5)
+#define alt_f6_key ((Common::KBD_ALT << 16) | Common::KEYCODE_F6)
+#define alt_f7_key ((Common::KBD_ALT << 16) | Common::KEYCODE_F7)
+#define alt_f8_key ((Common::KBD_ALT << 16) | Common::KEYCODE_F8)
+#define alt_f9_key ((Common::KBD_ALT << 16) | Common::KEYCODE_F9)
+#define alt_f10_key ((Common::KBD_ALT << 16) | Common::KEYCODE_F10)
+
+#define ctrl_a_key ((Common::KBD_CTRL << 16) | Common::KEYCODE_a)
+#define ctrl_b_key ((Common::KBD_CTRL << 16) | Common::KEYCODE_b)
+#define ctrl_c_key ((Common::KBD_CTRL << 16) | Common::KEYCODE_c)
+#define ctrl_d_key ((Common::KBD_CTRL << 16) | Common::KEYCODE_d)
+#define ctrl_e_key ((Common::KBD_CTRL << 16) | Common::KEYCODE_e)
+#define ctrl_f_key ((Common::KBD_CTRL << 16) | Common::KEYCODE_f)
+#define ctrl_g_key ((Common::KBD_CTRL << 16) | Common::KEYCODE_g)
+#define ctrl_h_key ((Common::KBD_CTRL << 16) | Common::KEYCODE_h)
+#define ctrl_i_key ((Common::KBD_CTRL << 16) | Common::KEYCODE_i)
+#define ctrl_j_key ((Common::KBD_CTRL << 16) | Common::KEYCODE_j)
+#define ctrl_k_key ((Common::KBD_CTRL << 16) | Common::KEYCODE_k)
+#define ctrl_l_key ((Common::KBD_CTRL << 16) | Common::KEYCODE_l)
+#define ctrl_m_key ((Common::KBD_CTRL << 16) | Common::KEYCODE_m)
+#define ctrl_n_key ((Common::KBD_CTRL << 16) | Common::KEYCODE_n)
+#define ctrl_o_key ((Common::KBD_CTRL << 16) | Common::KEYCODE_o)
+#define ctrl_p_key ((Common::KBD_CTRL << 16) | Common::KEYCODE_p)
+#define ctrl_q_key ((Common::KBD_CTRL << 16) | Common::KEYCODE_q)
+#define ctrl_r_key ((Common::KBD_CTRL << 16) | Common::KEYCODE_r)
+#define ctrl_s_key ((Common::KBD_CTRL << 16) | Common::KEYCODE_s)
+#define ctrl_t_key ((Common::KBD_CTRL << 16) | Common::KEYCODE_t)
+#define ctrl_u_key ((Common::KBD_CTRL << 16) | Common::KEYCODE_u)
+#define ctrl_v_key ((Common::KBD_CTRL << 16) | Common::KEYCODE_v)
+#define ctrl_w_key ((Common::KBD_CTRL << 16) | Common::KEYCODE_w)
+#define ctrl_x_key ((Common::KBD_CTRL << 16) | Common::KEYCODE_x)
+#define ctrl_y_key ((Common::KBD_CTRL << 16) | Common::KEYCODE_y)
+#define ctrl_z_key ((Common::KBD_CTRL << 16) | Common::KEYCODE_z)
#define KEYS_MAX_BUF_CHARS 32
diff --git a/engines/mads/madsv2/engine.cpp b/engines/mads/madsv2/engine.cpp
index 44fc040fc7a..1a22d92d356 100644
--- a/engines/mads/madsv2/engine.cpp
+++ b/engines/mads/madsv2/engine.cpp
@@ -21,6 +21,7 @@
#include "common/system.h"
#include "engines/util.h"
+#include "mads/mads.h"
#include "mads/madsv2/engine.h"
#include "mads/madsv2/core/camera.h"
#include "mads/madsv2/core/config.h"
@@ -42,6 +43,15 @@ constexpr int GAME_FRAME_TIME = 1000 / GAME_FRAME_RATE;
MADSV2Engine *g_engine;
+static const Common::KeyCode KEYBINDING_ACTIONS[kActionRestartAnimation + 1] = {
+ Common::KEYCODE_INVALID, Common::KEYCODE_ESCAPE, Common::KEYCODE_F1,
+ Common::KEYCODE_F5, Common::KEYCODE_7, Common::KEYCODE_PAGEUP,
+ Common::KEYCODE_PAGEDOWN, Common::KEYCODE_F1, Common::KEYCODE_F2,
+ Common::KEYCODE_F3, Common::KEYCODE_F4, Common::KEYCODE_F5,
+ Common::KEYCODE_INVALID
+};
+
+
MADSV2Engine::MADSV2Engine(OSystem *syst, const MADSGameDescription *gameDesc) :
MADSEngine(syst, gameDesc) {
g_engine = this;
@@ -196,7 +206,10 @@ void MADSV2Engine::pollEvents() {
_mousePos = e.mouse;
if (e.type == Common::EVENT_KEYDOWN)
- _keyEvents.push(e);
+ _keyEvents.push(e.kbd);
+ if (e.type == Common::EVENT_CUSTOM_ENGINE_ACTION_START &&
+ KEYBINDING_ACTIONS[e.customType] != Common::KEYCODE_INVALID)
+ _keyEvents.push(Common::KeyState(KEYBINDING_ACTIONS[e.customType]));
}
}
@@ -210,8 +223,8 @@ int MADSV2Engine::getKey() {
pollEvents();
if (!_keyEvents.empty()) {
- Common::Event e = _keyEvents.pop();
- return (e.kbd.keycode & 0xff) | 0x100;
+ Common::KeyState ks = _keyEvents.pop();
+ return (ks.ascii && !ks.flags) ? ks.ascii : (ks.flags << 16) | ks.keycode;
}
return 0;
diff --git a/engines/mads/madsv2/engine.h b/engines/mads/madsv2/engine.h
index a91cc09e983..b6cabc66f6a 100644
--- a/engines/mads/madsv2/engine.h
+++ b/engines/mads/madsv2/engine.h
@@ -42,7 +42,7 @@ private:
protected:
Graphics::Screen *_screen = nullptr;
- Common::Stack<Common::Event> _keyEvents;
+ Common::Stack<Common::KeyState> _keyEvents;
uint32 _nextFrameTime = 0;
Common::Point _mousePos;
int _mouseButtons = 0;
diff --git a/engines/mads/nebular/nebular.h b/engines/mads/nebular/nebular.h
index 287b5589d37..34ea200eecc 100644
--- a/engines/mads/nebular/nebular.h
+++ b/engines/mads/nebular/nebular.h
@@ -47,22 +47,6 @@ namespace MADS {
#define DEBUG_INTERMEDIATE 2
#define DEBUG_DETAILED 3
-enum MADSActions {
- kActionNone,
- kActionEscape,
- kActionGameMenu,
- kActionSave,
- kActionRestore,
- kActionScrollUp,
- kActionScrollDown,
- kActionStartGame,
- kActionResumeGame,
- kActionShowIntro,
- kActionCredits,
- kActionQuotes,
- kActionRestartAnimation
-};
-
class RexNebularEngine : public MADSEngine {
private:
/**
Commit: db02f972f06b898a6f5db2928c2813d965879d43
https://github.com/scummvm/scummvm/commit/db02f972f06b898a6f5db2928c2813d965879d43
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:25+10:00
Commit Message:
MADS: PHANTOM: Fix Game Menu quit button
Changed paths:
engines/mads/madsv2/phantom/main.cpp
diff --git a/engines/mads/madsv2/phantom/main.cpp b/engines/mads/madsv2/phantom/main.cpp
index 4f42fe0af22..5bd23a199b1 100644
--- a/engines/mads/madsv2/phantom/main.cpp
+++ b/engines/mads/madsv2/phantom/main.cpp
@@ -277,7 +277,7 @@ void phantom_main() {
switch (selected_item) {
case 0:
game_main(2, CMD_LINE);
- break;
+ return;
case 4:
// Exit
Commit: 637bae78f13dbdca693bc483c99bb557f52967e1
https://github.com/scummvm/scummvm/commit/637bae78f13dbdca693bc483c99bb557f52967e1
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:25+10:00
Commit Message:
MADS: PHANTOM: Fix cursors showing stray pixels
Changed paths:
engines/mads/madsv2/core/mouse.cpp
diff --git a/engines/mads/madsv2/core/mouse.cpp b/engines/mads/madsv2/core/mouse.cpp
index 7bd5c7ed66e..890771e33b4 100644
--- a/engines/mads/madsv2/core/mouse.cpp
+++ b/engines/mads/madsv2/core/mouse.cpp
@@ -137,11 +137,17 @@ void mouse_cursor_sprite(SeriesPtr series, int id) {
if (work_area[16][count] != 255) hot_x = count;
}
- if (work_area[0][16] == 9 && work_area[16][0] == 9) {
- work_area[0][16] = work_area[16][0] = 0xff;
- }
-
- CursorMan.replaceCursor(load_buffer.data, load_buffer.x, load_buffer.y, hot_x, hot_y, 0xff);
+ // Form a 16x16 surface around the data, ignoring the last column/row,
+ // which are only used for designating the hotspot position
+ Graphics::Surface s;
+ s.format = Graphics::PixelFormat::createFormatCLUT8();
+ s.setPixels(work_area);
+ s.w = 16;
+ s.pitch = 17;
+ s.h = 16;
+
+ // Set the cursor
+ CursorMan.replaceCursor(s, hot_x, hot_y, 0xff);
CursorMan.disableCursorPalette(true);
}
Commit: 9b8d50ec511f276a540466ac95617de8d1997f38
https://github.com/scummvm/scummvm/commit/9b8d50ec511f276a540466ac95617de8d1997f38
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:25+10:00
Commit Message:
MADS: PHANTOM: Implement delete_sprite_in_interface
Changed paths:
engines/mads/madsv2/core/extra.cpp
diff --git a/engines/mads/madsv2/core/extra.cpp b/engines/mads/madsv2/core/extra.cpp
index 3824ba72158..912d6299eba 100644
--- a/engines/mads/madsv2/core/extra.cpp
+++ b/engines/mads/madsv2/core/extra.cpp
@@ -20,6 +20,7 @@
*/
#include "common/textconsole.h"
+#include "mads/madsv2/core/matte.h"
#include "mads/madsv2/core/extra.h"
namespace MADS {
@@ -63,7 +64,7 @@ void stamp_sprite_to_interface(int x, int y, int sprite, int series) {
}
void delete_sprite_in_interface(int series) {
- error("TODO: delete_sprite_in_interface");
+ matte_deallocate_series(series, false);
}
void extra_change_animation(int handle, int x, int y, byte scale, byte depth) {
Commit: fe59a46927a437b055caf0793743151e0652790c
https://github.com/scummvm/scummvm/commit/fe59a46927a437b055caf0793743151e0652790c
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:26+10:00
Commit Message:
MADS: PHANTOM: Fix loading room depth table
Changed paths:
engines/mads/madsv2/core/room.cpp
engines/mads/madsv2/core/room.h
diff --git a/engines/mads/madsv2/core/room.cpp b/engines/mads/madsv2/core/room.cpp
index dbae7df77a4..a3092bed29b 100644
--- a/engines/mads/madsv2/core/room.cpp
+++ b/engines/mads/madsv2/core/room.cpp
@@ -199,7 +199,7 @@ RoomPtr room_load(int id, int variant, const char *base_path, Buffer *picture,
goto done;
}
- memcpy(&roomPtr->misc[0], &roomfile.misc[0], sizeof(int) * 10);
+ Common::copy(roomfile.misc, roomfile.misc + 10, roomPtr->misc);
roomPtr->num_variants = roomfile.num_variants;
roomPtr->num_hotspots = roomfile.num_hotspots;
roomPtr->num_rails = roomfile.num_rails;
@@ -207,10 +207,10 @@ RoomPtr room_load(int id, int variant, const char *base_path, Buffer *picture,
roomPtr->back_y = roomfile.back_y;
roomPtr->front_scale = roomfile.front_scale;
roomPtr->back_scale = roomfile.back_scale;
- memcpy(&roomPtr->depth_table[0], &roomfile.depth_table[0], sizeof(int) << 4);
+ Common::copy(roomfile.depth_table, roomfile.depth_table + 16, roomPtr->depth_table);
for (count = 0; count < roomfile.num_rails; count++) {
- memcpy(&roomPtr->rail[count], &roomfile.rail[count], sizeof(Rail));
+ roomPtr->rail[count] = roomfile.rail[count];
}
if (master_shadow != NULL) {
@@ -302,8 +302,8 @@ int room_load_variant(int id, int variant, const char *base_path, RoomPtr roomPt
room_load_error = 5100 + tile_load_error;
goto done;
} else if (tile_load_error == 1) {
- xx = MIN(video_x, roomPtr->xs);
- yy = MIN(display_y, roomPtr->ys);
+ xx = MIN<int16>(video_x, roomPtr->xs);
+ yy = MIN<int16>(display_y, roomPtr->ys);
buffer_init_name(depth, xx >> 1, yy, "$scrdpth");
if (depth->data == NULL) {
diff --git a/engines/mads/madsv2/core/room.h b/engines/mads/madsv2/core/room.h
index 661618cd225..31b67a8e558 100644
--- a/engines/mads/madsv2/core/room.h
+++ b/engines/mads/madsv2/core/room.h
@@ -209,27 +209,27 @@ struct RoomFile {
/* Run-time room definition structure (in memory) */
-typedef struct {
+struct Room {
/* int id; Room number */
/* int picture_id; Room whose ART file is needed */
/* int format; Room format (panning/normal) */
- int xs, ys; /* X and Y size of room picture */
+ int16 xs, ys; /* X and Y size of room picture */
- int misc[10]; /* Padding for future updates */
- int num_variants; /* Number of attribute variants */
- int num_hotspots; /* Number of hotspots */
- int num_rails; /* Number of rail nodes */
- int front_y, back_y; /* Player scaling baselines */
- int front_scale, back_scale; /* Player scaling factors */
- int depth_table[16]; /* Player depth table */
+ uint16 misc[10]; /* Padding for future updates */
+ uint16 num_variants; /* Number of attribute variants */
+ uint16 num_hotspots; /* Number of hotspots */
+ uint16 num_rails; /* Number of rail nodes */
+ int16 front_y, back_y; /* Player scaling baselines */
+ int16 front_scale, back_scale; /* Player scaling factors */
+ uint16 depth_table[16]; /* Player depth table */
- int color_handle; /* Background color handle */
- int variant_loaded; /* Current attribute variant */
+ int16 color_handle; /* Background color handle */
+ int16 variant_loaded; /* Current attribute variant */
- CycleList cycle_list; /* Active color cycling ranges */
+ CycleList cycle_list; /* Active color cycling ranges */
- Rail rail[1]; /* Rail nodes begin here... */
-} Room;
+ Rail rail[1]; /* Rail nodes begin here... */
+};
typedef Room *RoomPtr;
extern RoomDef roomdef;
Commit: 4f6b9975222ec27d9a5c033c6d84824f00fdf562
https://github.com/scummvm/scummvm/commit/4f6b9975222ec27d9a5c033c6d84824f00fdf562
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:26+10:00
Commit Message:
MADS: PHANTOM: Fix getting small note in room 113
Changed paths:
engines/mads/madsv2/phantom/rooms/room113.cpp
engines/mads/madsv2/phantom/rooms/room113.h
diff --git a/engines/mads/madsv2/phantom/rooms/room113.cpp b/engines/mads/madsv2/phantom/rooms/room113.cpp
index a1055166a57..c169228a726 100644
--- a/engines/mads/madsv2/phantom/rooms/room113.cpp
+++ b/engines/mads/madsv2/phantom/rooms/room113.cpp
@@ -1014,7 +1014,7 @@ static void process_conversation_florent() {
case conv004_anything_take:
local->florent_action = CONV4_FLORENT_POINT;
- conv_you_trigger(86); // ROOM_113_TAKE_NOTE);
+ conv_you_trigger(ROOM_113_TAKE_NOTE);
break;
case conv004_imgone_bye:
diff --git a/engines/mads/madsv2/phantom/rooms/room113.h b/engines/mads/madsv2/phantom/rooms/room113.h
index 5efb084c1f9..3e9e9a92dd7 100644
--- a/engines/mads/madsv2/phantom/rooms/room113.h
+++ b/engines/mads/madsv2/phantom/rooms/room113.h
@@ -144,11 +144,11 @@ typedef struct { /* Room local variables */
#define ROOM_113_RAOUL_START_TALKING 62
#define ROOM_113_FLORENT_START_TALKING2 64
#define ROOM_113_FLORENT_START_TALKING 66
-#define ROOM_113_TAKE_NOTE 74
#define ROOM_113_MADE_IT_TO_FLORENT 78
#define ROOM_113_AT_COUCH 80
#define ROOM_113_BEFORE_COUCH 82
#define ROOM_113_BETWEEN_COUCH 84
+#define ROOM_113_TAKE_NOTE 86
#define ROOM_113_DELAY_BEFORE_WALK 92
#define ROOM_113_PUT_ON_HOLD 96
#define ROOM_113_HOLD_HAND 98
Commit: feab44b02d48a618d8e4d1a1411e00c4d21b4838
https://github.com/scummvm/scummvm/commit/feab44b02d48a618d8e4d1a1411e00c4d21b4838
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:26+10:00
Commit Message:
MADS: PHANTOM: Ignore dummy ptr variables when entering manager's office
Changed paths:
engines/mads/madsv2/core/conv.cpp
diff --git a/engines/mads/madsv2/core/conv.cpp b/engines/mads/madsv2/core/conv.cpp
index c6f16a13a1a..1a3073f9ff7 100644
--- a/engines/mads/madsv2/core/conv.cpp
+++ b/engines/mads/madsv2/core/conv.cpp
@@ -111,13 +111,19 @@ void ConvScriptParams::load(Common::SeekableReadStream *src) {
void ConvVariable::load(Common::SeekableReadStream *src) {
uint16 flag = src->readUint16LE();
- assert(flag != 0xffff); // TODO: See if original game has pointers for any conv
isPtr = flag == MKTAG16('V', 'M');
val = src->readSint16LE();
- type = src->readUint16LE();
+ type = src->readSint16LE();
- if (isPtr) {
+ if (flag == 0xffff) {
+ // Original shouldn't have pointer variables by default, except for
+ // some placeholder entries in the Manager's Office, which have
+ // matching segment & offset values. So are obviously not used
+ assert(val == type);
+ val = type = 0;
+
+ } else if (isPtr) {
switch (type) {
case PTRTYPE_GLOBAL:
ptr = global + val;
Commit: e4abb70e55a817ecddc04f8ae9b9ad5db5e22407
https://github.com/scummvm/scummvm/commit/e4abb70e55a817ecddc04f8ae9b9ad5db5e22407
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:27+10:00
Commit Message:
MADS: PHANTOM: Added debugger console class
Changed paths:
A engines/mads/madsv2/console.cpp
A engines/mads/madsv2/console.h
engines/mads/madsv2/engine.h
engines/mads/madsv2/phantom/phantom.cpp
engines/mads/module.mk
diff --git a/engines/mads/madsv2/console.cpp b/engines/mads/madsv2/console.cpp
new file mode 100644
index 00000000000..b61cd96e857
--- /dev/null
+++ b/engines/mads/madsv2/console.cpp
@@ -0,0 +1,60 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "mads/madsv2/console.h"
+#include "mads/madsv2/core/kernel.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+Console::Console() : GUI::Debugger() {
+ registerCmd("teleport", WRAP_METHOD(Console, cmdTeleport));
+}
+
+static int strToInt(const char *s) {
+ if (!*s)
+ // No string at all
+ return 0;
+ else if (toupper(s[strlen(s) - 1]) != 'H')
+ // Standard decimal string
+ return atoi(s);
+
+ // Hexadecimal string
+ uint tmp = 0;
+ int read = sscanf(s, "%xh", &tmp);
+ if (read < 1)
+ error("strToInt failed on string \"%s\"", s);
+ return (int)tmp;
+}
+
+bool Console::cmdTeleport(int argc, const char **argv) {
+ if (argc != 2) {
+ debugPrintf("Current room is: %d\n", new_room);
+ debugPrintf("Usage: %s <room number>\n", argv[0]);
+ return true;
+ } else {
+ new_room = strToInt(argv[1]);
+ return false;
+ }
+}
+
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/console.h b/engines/mads/madsv2/console.h
new file mode 100644
index 00000000000..95e09a1a4aa
--- /dev/null
+++ b/engines/mads/madsv2/console.h
@@ -0,0 +1,42 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 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 MADSV2_CONSOLE_H
+#define MADSV2_CONSOLE_H
+
+#include "gui/debugger.h"
+
+namespace MADS {
+namespace MADSV2 {
+
+class Console : public GUI::Debugger {
+private:
+ bool cmdTeleport(int argc, const char **argv);
+
+public:
+ Console();
+ ~Console() override {}
+};
+
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/engine.h b/engines/mads/madsv2/engine.h
index b6cabc66f6a..6b91acc1e85 100644
--- a/engines/mads/madsv2/engine.h
+++ b/engines/mads/madsv2/engine.h
@@ -33,7 +33,6 @@
#include "mads/madsv2/core/speech.h"
namespace MADS {
-
namespace MADSV2 {
class MADSV2Engine : public MADSEngine {
diff --git a/engines/mads/madsv2/phantom/phantom.cpp b/engines/mads/madsv2/phantom/phantom.cpp
index 420198a1d3c..c383d285b16 100644
--- a/engines/mads/madsv2/phantom/phantom.cpp
+++ b/engines/mads/madsv2/phantom/phantom.cpp
@@ -20,6 +20,7 @@
*/
#include "engines/util.h"
+#include "mads/madsv2/console.h"
#include "mads/madsv2/core/conv.h"
#include "mads/madsv2/core/copy.h"
#include "mads/madsv2/core/env.h"
@@ -52,9 +53,14 @@ Common::Error PhantomEngine::run() {
_screen = new Graphics::Screen();
scr_live.data = (byte *)_screen->getPixels();
+ // Create a debugger console
+ setDebugger(new Console());
+
+ // Set up sound manager
_soundManager = new PhantomSoundManager(_mixer, _soundFlag);
_soundManager->validate();
+ // Run the game
Phantom::phantom_main();
return Common::kNoError;
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index c96c18f8ef4..89158e76e62 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -62,6 +62,7 @@ MODULE_OBJS += \
forest/game_forest.o \
forest/forest_scenes.o \
forest/globals_forest.o \
+ madsv2/console.o \
madsv2/engine.o \
madsv2/core/anim.o \
madsv2/core/attr.o \
Commit: 52e97492b88e1e32661927767562208a7649f2a3
https://github.com/scummvm/scummvm/commit/52e97492b88e1e32661927767562208a7649f2a3
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-04-20T15:23:27+10:00
Commit Message:
MADS: PHANTOM: Fix walker appearing all black after '5 minutes later' cutscene
Changed paths:
engines/mads/madsv2/core/game.cpp
diff --git a/engines/mads/madsv2/core/game.cpp b/engines/mads/madsv2/core/game.cpp
index c0147b424df..9acf825863e 100644
--- a/engines/mads/madsv2/core/game.cpp
+++ b/engines/mads/madsv2/core/game.cpp
@@ -1387,7 +1387,10 @@ void game_control() {
kernel_mode = KERNEL_ROOM_PRELOAD;
- player.walker_must_reload = (byte)(!player.walker_is_loaded);
+ // Return of the Phantom has this hardcoded true, due to text cutscenes like
+ // "5 Minutes Later" zeroing out the palette
+ player.walker_must_reload = (byte)(g_engine->getGameID() == GType_Phantom ||
+ !player.walker_is_loaded);
quote_emergency = false;
/* vocab_emergency = false; */
@@ -1690,9 +1693,7 @@ emergency:
kernel_unload_all_series();
}
- /* player_dump_walker(); */
-
- if (room_id != KERNEL_RESTORING_GAME) {
+ if (room_id != KERNEL_RESTORING_GAME && g_engine->getGameID() == GType_Forest) {
if (int_sprite[fx_int_journal] != -1) {
matte_deallocate_series(int_sprite[fx_int_candle_on], true);
matte_deallocate_series(int_sprite[fx_int_dooropen], true);
More information about the Scummvm-git-logs
mailing list