diff options
290 files changed, 29495 insertions, 13859 deletions
@@ -62,6 +62,10 @@ ScummVM Team Oliver Kiehl - (retired) Ludvig Strigeus - (retired) + AVALANCHE: + Peter Bozso + Arnaud Boutonne + CGE: Arnaud Boutonne Paul Gilbert @@ -513,6 +517,7 @@ Other contributions Janne Huttunen - V3 actor mask support, Dig/FT SMUSH audio Kovacs Endre Janos - Several fixes for Simon1 Jeroen Janssen - Numerous readability and bugfix patches + Keith Kaisershot - Several Pegasus Prime patches Andreas Karlsson - Initial port for SymbianOS Claudio Matsuoka - Daily Linux builds Thomas Mayer - PSP port contributions diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp index ad80ea7f8c..5e3d1d0db6 100644 --- a/backends/platform/android/android.cpp +++ b/backends/platform/android/android.cpp @@ -146,7 +146,8 @@ OSystem_Android::OSystem_Android(int audio_sample_rate, int audio_buffer_size) : _touchpad_scale(66), _dpad_scale(4), _fingersDown(0), - _trackball_scale(2) { + _trackball_scale(2), + _joystick_scale(10) { _fsFactory = new POSIXFilesystemFactory(); diff --git a/backends/platform/android/android.h b/backends/platform/android/android.h index b4813b3bdf..704ce12f60 100644 --- a/backends/platform/android/android.h +++ b/backends/platform/android/android.h @@ -231,6 +231,7 @@ private: int _touchpad_scale; int _trackball_scale; int _dpad_scale; + int _joystick_scale; int _fingersDown; void clipMouse(Common::Point &p); diff --git a/backends/platform/android/android.mk b/backends/platform/android/android.mk index f498c671de..915bf8ac60 100644 --- a/backends/platform/android/android.mk +++ b/backends/platform/android/android.mk @@ -25,13 +25,19 @@ PATH_RESOURCES = $(PATH_DIST)/res PORT_DISTFILES = $(PATH_DIST)/README.Android +# FIXME: OUYA specific. +# "values-television" not present in vanilla Android. +# $(PATH_RESOURCES)/../res-ouya/values-television/margins.xml \ + RESOURCES = \ $(PATH_RESOURCES)/values/strings.xml \ + $(PATH_RESOURCES)/values/margins.xml \ $(PATH_RESOURCES)/layout/main.xml \ $(PATH_RESOURCES)/layout/splash.xml \ $(PATH_RESOURCES)/drawable/gradient.xml \ $(PATH_RESOURCES)/drawable/scummvm.png \ - $(PATH_RESOURCES)/drawable/scummvm_big.png + $(PATH_RESOURCES)/drawable/scummvm_big.png \ + $(PATH_RESOURCES)/drawable-xhdpi/ouya_icon.png PLUGIN_RESOURCES = \ $(PATH_RESOURCES)/values/strings.xml \ diff --git a/backends/platform/android/events.cpp b/backends/platform/android/events.cpp index db1261e432..5c42db9347 100644 --- a/backends/platform/android/events.cpp +++ b/backends/platform/android/events.cpp @@ -64,6 +64,10 @@ enum { JE_RMB_DOWN = 11, JE_RMB_UP = 12, JE_MOUSE_MOVE = 13, + JE_GAMEPAD = 14, + JE_JOYSTICK = 15, + JE_MMB_DOWN = 16, + JE_MMB_UP = 17, JE_QUIT = 0x1000 }; @@ -109,6 +113,25 @@ enum { JKEYCODE_DPAD_CENTER = 23 }; +// gamepad +enum { + JKEYCODE_BUTTON_A = 96, + JKEYCODE_BUTTON_B = 97, + JKEYCODE_BUTTON_C = 98, + JKEYCODE_BUTTON_X = 99, + JKEYCODE_BUTTON_Y = 100, + JKEYCODE_BUTTON_Z = 101, + JKEYCODE_BUTTON_L1 = 102, + JKEYCODE_BUTTON_R1 = 103, + JKEYCODE_BUTTON_L2 = 104, + JKEYCODE_BUTTON_R2 = 105, + JKEYCODE_BUTTON_THUMBL = 106, + JKEYCODE_BUTTON_THUMBR = 107, + JKEYCODE_BUTTON_START = 108, + JKEYCODE_BUTTON_SELECT = 109, + JKEYCODE_BUTTON_MODE = 110, +}; + // meta modifier enum { JMETA_SHIFT = 0x01, @@ -827,6 +850,94 @@ void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3, return; + case JE_GAMEPAD: + switch (arg1) { + case JACTION_DOWN: + e.type = Common::EVENT_KEYDOWN; + break; + case JACTION_UP: + e.type = Common::EVENT_KEYUP; + break; + default: + LOGE("unhandled jaction on gamepad key: %d", arg1); + return; + } + + switch (arg2) { + case JKEYCODE_BUTTON_A: + case JKEYCODE_BUTTON_B: + switch (arg1) { + case JACTION_DOWN: + e.type = (arg2 == JKEYCODE_BUTTON_A? + Common::EVENT_LBUTTONDOWN : + Common::EVENT_RBUTTONDOWN); + break; + case JACTION_UP: + e.type = (arg2 == JKEYCODE_BUTTON_A? + Common::EVENT_LBUTTONUP : + Common::EVENT_RBUTTONUP); + break; + } + + e.mouse = getEventManager()->getMousePos(); + + break; + + case JKEYCODE_BUTTON_X: + e.kbd.keycode = Common::KEYCODE_ESCAPE; + e.kbd.ascii = Common::ASCII_ESCAPE; + break; + + default: + LOGW("unmapped gamepad key: %d", arg2); + return; + } + + lockMutex(_event_queue_lock); + _event_queue.push(e); + unlockMutex(_event_queue_lock); + + break; + + case JE_JOYSTICK: + e.mouse = getEventManager()->getMousePos(); + + switch (arg1) { + case JACTION_MULTIPLE: + e.type = Common::EVENT_MOUSEMOVE; + + // already multiplied by 100 + e.mouse.x += arg2 * _joystick_scale / _eventScaleX; + e.mouse.y += arg3 * _joystick_scale / _eventScaleY; + + clipMouse(e.mouse); + + break; + default: + LOGE("unhandled jaction on joystick: %d", arg1); + return; + } + + lockMutex(_event_queue_lock); + _event_queue.push(e); + unlockMutex(_event_queue_lock); + + return; + + case JE_MMB_DOWN: + e.type = Common::EVENT_MAINMENU; + + lockMutex(_event_queue_lock); + _event_queue.push(e); + unlockMutex(_event_queue_lock); + + return; + + case JE_MMB_UP: + // No action + + return; + case JE_QUIT: e.type = Common::EVENT_QUIT; diff --git a/backends/platform/android/org/scummvm/scummvm/MouseHelper.java b/backends/platform/android/org/scummvm/scummvm/MouseHelper.java index 999815593f..8990515b84 100644 --- a/backends/platform/android/org/scummvm/scummvm/MouseHelper.java +++ b/backends/platform/android/org/scummvm/scummvm/MouseHelper.java @@ -14,6 +14,7 @@ public class MouseHelper { private long _rmbGuardTime; private boolean _rmbPressed; private boolean _lmbPressed; + private boolean _mmbPressed; /** * Class initialization fails when this throws an exception. @@ -114,6 +115,23 @@ public class MouseHelper { _rmbPressed = false; } + boolean mmbDown = (buttonState & MotionEvent.BUTTON_TERTIARY) == MotionEvent.BUTTON_TERTIARY; + if (mmbDown) { + if (!_mmbPressed) { + // middle mouse button was pressed just now + _scummvm.pushEvent(ScummVMEvents.JE_MMB_DOWN, (int)e.getX(), (int)e.getY(), e.getButtonState(), 0, 0); + } + + _mmbPressed = true; + } else { + if (_mmbPressed) { + // middle mouse button was released just now + _scummvm.pushEvent(ScummVMEvents.JE_MMB_UP, (int)e.getX(), (int)e.getY(), e.getButtonState(), 0, 0); + } + + _mmbPressed = false; + } + return true; } diff --git a/backends/platform/android/org/scummvm/scummvm/ScummVMActivity.java b/backends/platform/android/org/scummvm/scummvm/ScummVMActivity.java index 829a948435..5d041dafd2 100644 --- a/backends/platform/android/org/scummvm/scummvm/ScummVMActivity.java +++ b/backends/platform/android/org/scummvm/scummvm/ScummVMActivity.java @@ -240,6 +240,14 @@ public class ScummVMActivity extends Activity { return false; } + @Override + public boolean onGenericMotionEvent(final MotionEvent e) { + if (_events != null) + return _events.onGenericMotionEvent(e); + + return false; + } + private void showKeyboard(boolean show) { SurfaceView main_surface = (SurfaceView)findViewById(R.id.main_surface); InputMethodManager imm = (InputMethodManager) diff --git a/backends/platform/android/org/scummvm/scummvm/ScummVMEvents.java b/backends/platform/android/org/scummvm/scummvm/ScummVMEvents.java index 5f51ffac6c..702215341b 100644 --- a/backends/platform/android/org/scummvm/scummvm/ScummVMEvents.java +++ b/backends/platform/android/org/scummvm/scummvm/ScummVMEvents.java @@ -9,6 +9,7 @@ import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; import android.view.GestureDetector; +import android.view.InputDevice; import android.view.inputmethod.InputMethodManager; public class ScummVMEvents implements @@ -31,6 +32,10 @@ public class ScummVMEvents implements public static final int JE_RMB_DOWN = 11; public static final int JE_RMB_UP = 12; public static final int JE_MOUSE_MOVE = 13; + public static final int JE_GAMEPAD = 14; + public static final int JE_JOYSTICK = 15; + public static final int JE_MMB_DOWN = 16; + public static final int JE_MMB_UP = 17; public static final int JE_QUIT = 0x1000; final protected Context _context; @@ -63,6 +68,18 @@ public class ScummVMEvents implements return true; } + public boolean onGenericMotionEvent(final MotionEvent e) { + if((e.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) { + _scummvm.pushEvent(JE_JOYSTICK, e.getAction(), + (int)(e.getAxisValue(MotionEvent.AXIS_X)*100), + (int)(e.getAxisValue(MotionEvent.AXIS_Y)*100), + 0, 0); + return true; + } + + return false; + } + final static int MSG_MENU_LONG_PRESS = 1; final private Handler keyHandler = new Handler() { @@ -177,6 +194,25 @@ public class ScummVMEvents implements (int)(e.getEventTime() - e.getDownTime()), e.getRepeatCount(), 0); return true; + case KeyEvent.KEYCODE_BUTTON_A: + case KeyEvent.KEYCODE_BUTTON_B: + case KeyEvent.KEYCODE_BUTTON_C: + case KeyEvent.KEYCODE_BUTTON_X: + case KeyEvent.KEYCODE_BUTTON_Y: + case KeyEvent.KEYCODE_BUTTON_Z: + case KeyEvent.KEYCODE_BUTTON_L1: + case KeyEvent.KEYCODE_BUTTON_R1: + case KeyEvent.KEYCODE_BUTTON_L2: + case KeyEvent.KEYCODE_BUTTON_R2: + case KeyEvent.KEYCODE_BUTTON_THUMBL: + case KeyEvent.KEYCODE_BUTTON_THUMBR: + case KeyEvent.KEYCODE_BUTTON_START: + case KeyEvent.KEYCODE_BUTTON_SELECT: + case KeyEvent.KEYCODE_BUTTON_MODE: + _scummvm.pushEvent(JE_GAMEPAD, action, keyCode, + (int)(e.getEventTime() - e.getDownTime()), + e.getRepeatCount(), 0); + return true; } _scummvm.pushEvent(JE_KEY, action, keyCode, diff --git a/base/plugins.h b/base/plugins.h index 4409c9eaea..e0673ce636 100644 --- a/base/plugins.h +++ b/base/plugins.h @@ -169,7 +169,7 @@ protected: PluginType _type; public: - Plugin() : _pluginObject(0) {} + Plugin() : _pluginObject(0), _type(PLUGIN_TYPE_MAX) {} virtual ~Plugin() { //if (isLoaded()) //unloadPlugin(); diff --git a/common/unarj.cpp b/common/unarj.cpp index fe3c17a2ac..e8aed7cbd1 100644 --- a/common/unarj.cpp +++ b/common/unarj.cpp @@ -95,6 +95,12 @@ class ArjDecoder { public: ArjDecoder(const ArjHeader *hdr) { _compsize = hdr->compSize; + _compressed = 0; + _outstream = 0; + _bitbuf = 0; + _bytebuf = 0; + _bitcount = 0; + _blocksize = 0; } ~ArjDecoder() { @@ -112,7 +118,6 @@ public: uint16 _bitbuf; uint16 _bytebuf; int32 _compsize; - byte _subbitbuf; int _bitcount; void init_getbits(); @@ -132,9 +137,6 @@ public: private: byte _ntext[ARJ_FDICSIZ]; - int16 _getlen; - int16 _getbuf; - uint16 _left[2 * ARJ_NC - 1]; uint16 _right[2 * ARJ_NC - 1]; byte _c_len[ARJ_NC]; @@ -656,7 +658,6 @@ void ArjDecoder::decode_f(int32 origsize) { init_getbits(); ncount = 0; - _getlen = _getbuf = 0; r = 0; while (ncount < (uint32)origsize) { @@ -864,6 +864,7 @@ Special configuration feature: motomagx for MotoMAGX n64 for Nintendo 64 openpandora for OpenPandora + ouya for OUYA ps2 for PlayStation 2 ps3 for PlayStation 3 psp for PlayStation Portable @@ -1268,7 +1269,7 @@ get_system_exe_extension $guessed_host NATIVEEXEEXT=$_exeext case $_host in -android | android-v7a) +android | android-v7a | ouya) _host_os=android _host_cpu=arm _host_alias=arm-linux-androideabi @@ -2050,6 +2051,12 @@ case $_host_os in CXXFLAGS="$CXXFLAGS -mfpu=vfp" LDFLAGS="$LDFLAGS -Wl,--fix-cortex-a8" ;; + ouya) + CXXFLAGS="$CXXFLAGS -march=armv7-a" + CXXFLAGS="$CXXFLAGS -mtune=cortex-a9" + CXXFLAGS="$CXXFLAGS -mfloat-abi=softfp" + CXXFLAGS="$CXXFLAGS -mfpu=neon" + ;; esac CXXFLAGS="$CXXFLAGS --sysroot=$ANDROID_NDK/platforms/android-4/arch-arm" CXXFLAGS="$CXXFLAGS -fpic" @@ -2338,7 +2345,7 @@ if test -n "$_host"; then # Cross-compiling mode - add your target here if needed echo "Cross-compiling to $_host" case "$_host" in - android | android-v7a) + android | android-v7a | ouya) # we link a .so as default LDFLAGS="$LDFLAGS -shared" LDFLAGS="$LDFLAGS -Wl,-Bsymbolic,--no-undefined" diff --git a/devtools/credits.pl b/devtools/credits.pl index e7828d8b18..fda6f4782e 100755 --- a/devtools/credits.pl +++ b/devtools/credits.pl @@ -541,6 +541,11 @@ begin_credits("Credits"); add_person("Oliver Kiehl", "olki", "(retired)"); add_person("Ludvig Strigeus", "ludde", "(retired)"); end_section(); + + begin_section("AVALANCHE"); + add_person("Peter Bozsó", "uruk", ""); + add_person("Arnaud Boutonné", "Strangerke", ""); + end_section(); begin_section("CGE"); add_person("Arnaud Boutonné", "Strangerke", ""); @@ -1067,6 +1072,7 @@ begin_credits("Credits"); add_person("Janne Huttunen", "", "V3 actor mask support, Dig/FT SMUSH audio"); add_person("Kovács Endre János", "", "Several fixes for Simon1"); add_person("Jeroen Janssen", "japj", "Numerous readability and bugfix patches"); + add_person("Keith Kaisershot", "blitter", "Several Pegasus Prime patches"); add_person("Andreas Karlsson", "Sprawl", "Initial port for SymbianOS"); add_person("Claudio Matsuoka", "", "Daily Linux builds"); add_person("Thomas Mayer", "", "PSP port contributions"); diff --git a/dists/android/AndroidManifest.xml b/dists/android/AndroidManifest.xml index 320ed16a6e..16d1ee578b 100644 --- a/dists/android/AndroidManifest.xml +++ b/dists/android/AndroidManifest.xml @@ -36,6 +36,7 @@ <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> + <category android:name="tv.ouya.intent.category.GAME"/> </intent-filter> </activity> </application> diff --git a/dists/android/AndroidManifest.xml.in b/dists/android/AndroidManifest.xml.in index 8f7887eaf5..bf45ffcc0e 100644 --- a/dists/android/AndroidManifest.xml.in +++ b/dists/android/AndroidManifest.xml.in @@ -36,6 +36,7 @@ <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> + <category android:name="tv.ouya.intent.category.GAME"/> </intent-filter> </activity> </application> diff --git a/dists/android/res-ouya/values-television/margins.xml b/dists/android/res-ouya/values-television/margins.xml new file mode 100644 index 0000000000..df586eea34 --- /dev/null +++ b/dists/android/res-ouya/values-television/margins.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <dimen name="verticalMargin">45px</dimen> + <dimen name="horizontalMargin">80px</dimen> +</resources> diff --git a/dists/android/res/drawable-xhdpi/ouya_icon.png b/dists/android/res/drawable-xhdpi/ouya_icon.png Binary files differnew file mode 100644 index 0000000000..42f9a2a8ce --- /dev/null +++ b/dists/android/res/drawable-xhdpi/ouya_icon.png diff --git a/dists/android/res/layout/main.xml b/dists/android/res/layout/main.xml index 8b0d515d62..31aa345cc7 100644 --- a/dists/android/res/layout/main.xml +++ b/dists/android/res/layout/main.xml @@ -9,4 +9,8 @@ android:keepScreenOn="true" android:focusable="true" android:focusableInTouchMode="true" + android:layout_marginTop="@dimen/verticalMargin" + android:layout_marginLeft="@dimen/horizontalMargin" + android:layout_marginBottom="@dimen/verticalMargin" + android:layout_marginRight="@dimen/horizontalMargin" /> diff --git a/dists/android/res/values/margins.xml b/dists/android/res/values/margins.xml new file mode 100644 index 0000000000..a865687b3a --- /dev/null +++ b/dists/android/res/values/margins.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <dimen name="verticalMargin">0px</dimen> + <dimen name="horizontalMargin">0px</dimen> +</resources> diff --git a/engines/agi/loader_v1.cpp b/engines/agi/loader_v1.cpp index 33e956af41..3b862ed91f 100644 --- a/engines/agi/loader_v1.cpp +++ b/engines/agi/loader_v1.cpp @@ -202,7 +202,7 @@ int AgiLoader_v1::loadResource(int t, int n) { uint8 *data = NULL; debugC(3, kDebugLevelResources, "(t = %d, n = %d)", t, n); - if (n > MAX_DIRS) + if (n >= MAX_DIRS) return errBadResource; switch (t) { diff --git a/engines/agi/loader_v2.cpp b/engines/agi/loader_v2.cpp index ee69bb5b27..458927a3bc 100644 --- a/engines/agi/loader_v2.cpp +++ b/engines/agi/loader_v2.cpp @@ -178,7 +178,7 @@ int AgiLoader_v2::loadResource(int t, int n) { uint8 *data = NULL; debugC(3, kDebugLevelResources, "(t = %d, n = %d)", t, n); - if (n > MAX_DIRS) + if (n >= MAX_DIRS) return errBadResource; switch (t) { diff --git a/engines/agi/loader_v3.cpp b/engines/agi/loader_v3.cpp index 250d8e7615..1dd00dc18e 100644 --- a/engines/agi/loader_v3.cpp +++ b/engines/agi/loader_v3.cpp @@ -257,7 +257,7 @@ int AgiLoader_v3::loadResource(int t, int n) { int ec = errOK; uint8 *data = NULL; - if (n > MAX_DIRS) + if (n >= MAX_DIRS) return errBadResource; switch (t) { diff --git a/engines/agi/opcodes.cpp b/engines/agi/opcodes.cpp index 807ab2dc2c..d893e44c12 100644 --- a/engines/agi/opcodes.cpp +++ b/engines/agi/opcodes.cpp @@ -367,6 +367,18 @@ void AgiEngine::setupOpcodes() { logicNamesTest = insV2Test; logicNamesCmd = insV2; + + // Alter opcode parameters for specific games + // TODO: This could be either turned into a game feature, or a version + // specific check, instead of a game version check + + // The Apple IIGS versions of MH1 and Goldrush both have a parameter for + // show.mouse and hide.mouse. Fixes bugs #3577754 and #3426946. + if ((getGameID() == GID_MH1 || getGameID() == GID_GOLDRUSH) && + getPlatform() == Common::kPlatformApple2GS) { + logicNamesCmd[176].args = "n"; // hide.mouse + logicNamesCmd[178].args = "n"; // show.mouse + } } else { for (int i = 0; i < ARRAYSIZE(insV1Test); ++i) _agiCondCommands[i] = insV1Test[i].func; @@ -376,18 +388,6 @@ void AgiEngine::setupOpcodes() { logicNamesTest = insV1Test; logicNamesCmd = insV1; } - - // Alter opcode parameters for specific games - // TODO: This could be either turned into a game feature, or a version - // specific check, instead of a game version check - - // The Apple IIGS versions of MH1 and Goldrush both have a parameter for - // show.mouse and hide.mouse. Fixes bugs #3577754 and #3426946. - if ((getGameID() == GID_MH1 || getGameID() == GID_GOLDRUSH) && - getPlatform() == Common::kPlatformApple2GS) { - logicNamesCmd[176].args = "n"; // hide.mouse - logicNamesCmd[178].args = "n"; // show.mouse - } } } diff --git a/engines/agi/preagi_mickey.cpp b/engines/agi/preagi_mickey.cpp index ed4882fcab..d0f6540651 100644 --- a/engines/agi/preagi_mickey.cpp +++ b/engines/agi/preagi_mickey.cpp @@ -850,7 +850,7 @@ void MickeyEngine::drawRoomAnimation() { } void MickeyEngine::drawRoom() { - uint8 buffer[256]; + uint8 buffer[512]; int pBuf = 0; int nObjs; diff --git a/engines/agi/words.cpp b/engines/agi/words.cpp index 9c5b3d349a..f423995de8 100644 --- a/engines/agi/words.cpp +++ b/engines/agi/words.cpp @@ -93,14 +93,25 @@ int AgiEngine::loadWords(const char *fname) { } while (!(c & 0x80) && k < (int)sizeof(str) - 1); str[k] = 0; - // And store it in our internal dictionary - AgiWord *w = new AgiWord; - w->word = myStrndup(str, k); - w->id = fp.readUint16BE(); - _game.words[i].push_back(w); + // WORKAROUND: + // The SQ0 fan game stores words starting with numbers (like '7up') + // in its dictionary under the 'a' entry. We skip these. + // See bug #3615061 + if (str[0] == 'a' + i) { + // And store it in our internal dictionary + AgiWord *w = new AgiWord; + w->word = myStrndup(str, k); + w->id = fp.readUint16BE(); + _game.words[i].push_back(w); + } + + k = fp.readByte(); // Are there more words with an already known prefix? - if (!(k = fp.readByte())) + // WORKAROUND: We only break after already seeing words with the + // right prefix, for the SQ0 words starting with digits filed under + // 'a'. See above comment and bug #3615061. + if (k == 0 && str[0] >= 'a' + i) break; } } diff --git a/engines/avalanche/animation.cpp b/engines/avalanche/animation.cpp new file mode 100644 index 0000000000..ef30faa87c --- /dev/null +++ b/engines/avalanche/animation.cpp @@ -0,0 +1,1459 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on the original source code of Lord Avalot d'Argent version 1.3. + * Copyright (c) 1994-1995 Mike, Mark and Thomas Thurman. + */ + +/* TRIP5 Trippancy V - the sprite animation subsystem */ + +#include "avalanche/avalanche.h" +#include "avalanche/animation.h" + +namespace Avalanche { + +// Art gallery at 2,1; notice about this at 2,2. +const int32 Animation::kCatacombMap[8][8] = { + // Geida's room + // 1 2 3 4 5 6 7 8 + {0x204, 0x200, 0xd0f0, 0xf0ff, 0xff, 0xd20f, 0xd200, 0x200}, + {0x50f1, 0x20ff, 0x2ff, 0xff, 0xe0ff, 0x20ff, 0x200f, 0x7210}, + {0xe3f0, 0xe10f, 0x72f0, 0xff, 0xe0ff, 0xff, 0xff, 0x800f}, + {0x2201, 0x2030, 0x800f, 0x220, 0x20f, 0x30, 0xff, 0x23f}, // >> Oubliette + {0x5024, 0xf3, 0xff, 0x200f, 0x22f0, 0x20f, 0x200, 0x7260}, + {0xf0, 0x2ff, 0xe2ff, 0xff, 0x200f, 0x50f0, 0x72ff, 0x201f}, + {0xf6, 0x220f, 0x22f0, 0x30f, 0xf0, 0x20f, 0x8200, 0x2f0}, // <<< In here + {0x34, 0x200f, 0x51f0, 0x201f, 0xf1, 0x50ff, 0x902f, 0x2062} +}; + +AnimationType::AnimationType(Animation *anim) { + _anim = anim; +} + +/** + * Loads & sets up the sprite. + */ +void AnimationType::init(byte spritenum, bool doCheck) { + const int32 idshould = -1317732048; + + if (spritenum == 177) + return; // Already running! + + Common::File inf; + Common::String filename = Common::String::format("sprite%d.avd", spritenum); + if (!inf.open(filename)) + error("AVALANCHE: Trip: File not found: %s", filename.c_str()); + + inf.seek(177); + + int32 id = inf.readSint32LE(); + if (id != idshould) { + inf.close(); + return; + } + + // Replace variable named 'soa' in the original code. + inf.skip(2); + // Skip real name Size (1 byte) then fixed sized zone containing name (12 bytes) + inf.skip(1 + 12); + // Skip real comment size (1 byte) then fixed sized zone containing comment (16 bytes) + inf.skip(1 + 16); + + _frameNum = inf.readByte(); + _xLength = inf.readByte(); + _yLength = inf.readByte(); + _seq = inf.readByte(); + uint16 size = inf.readUint16LE(); + assert (size > 6); + _fgBubbleCol = (Color)inf.readByte(); + _bgBubbleCol = (Color)inf.readByte(); + _characterId = inf.readByte(); + + byte xWidth = _xLength / 8; + if ((_xLength % 8) > 0) + xWidth++; + for (int i = 0; i < _frameNum; i++) { + _sil[i] = new SilType[11 * (_yLength + 1)]; + _mani[i] = new ManiType[size - 6]; + for (int j = 0; j <= _yLength; j++) + inf.read((*_sil[i])[j], xWidth); + inf.read(*_mani[i], size - 6); + } + + _x = 0; + _y = 0; + _quick = true; + _visible = false; + _speedX = kWalk; + _speedY = 1; + _homing = false; + _moveX = 0; + _moveY = 0; + _stepNum = 0; + _doCheck = doCheck; + _count = 0; + _id = spritenum; + _vanishIfStill = false; + _callEachStepFl = false; + + inf.close(); +} + +/** + * Just sets 'quick' to false. + * @remarks Originally called 'original' + */ +void AnimationType::reset() { + _quick = false; + _id = 177; +} + +/** + * Drops sprite onto screen. + * @remarks Originally called 'andexor' + */ +void AnimationType::draw() { + if (_vanishIfStill && (_moveX == 0) && (_moveY == 0)) + return; + + byte picnum = _facingDir * _seq + _stepNum; + + _anim->_vm->_graphics->drawSprite(this, picnum, _x, _y); +} + +/** + * Turns character round. + */ +void AnimationType::turn(Direction whichway) { + if (whichway == 8) + _facingDir = kDirUp; + else + _facingDir = whichway; +} + +/** + * Switches it on. + */ +void AnimationType::appear(int16 wx, int16 wy, Direction wf) { + _x = (wx / 8) * 8; + _y = wy; + _oldX[_anim->_vm->_cp] = wx; + _oldY[_anim->_vm->_cp] = wy; + turn(wf); + _visible = true; + _moveX = 0; + _moveY = 0; +} + +/** + * Check collision + * @remarks Originally called 'collision_check' + */ +bool AnimationType::checkCollision() { + for (int i = 0; i < _anim->kSpriteNumbMax; i++) { + AnimationType *spr = _anim->_sprites[i]; + if (spr->_quick && (spr->_id != _id) && (_x + _xLength > spr->_x) && (_x < spr->_x + spr->_xLength) && (spr->_y == _y)) + return true; + } + + return false; +} + +/** + * Prepares for draw(), etc. + */ +void AnimationType::walk() { + if (!_anim->_vm->_doingSpriteRun) { + _oldX[_anim->_vm->_cp] = _x; + _oldY[_anim->_vm->_cp] = _y; + if (_homing) + homeStep(); + _x += _moveX; + _y += _moveY; + } + + if (_doCheck) { + if (checkCollision()) { + bounce(); + return; + } + + byte magicColor = _anim->checkFeet(_x, _x + _xLength, _oldY[_anim->_vm->_cp], _y, _yLength) - 1; + // -1 is because the modified array indexes of magics[] compared to Pascal . + + if ((magicColor != 255) & !_anim->_vm->_doingSpriteRun) { + MagicType *magic = &_anim->_vm->_magics[magicColor]; + switch (magic->_operation) { + case kMagicExclaim: + bounce(); + _anim->_mustExclaim = true; + _anim->_sayWhat = magic->_data; + break; + case kMagicBounce: + bounce(); + break; + case kMagicTransport: + _anim->_vm->flipRoom((Room)(magic->_data >> 8), magic->_data & 0xff); + break; + case kMagicUnfinished: { + bounce(); + Common::String tmpStr = Common::String::format("%c%cSorry.%cThis place is not available yet!", + kControlBell, kControlCenter, kControlRoman); + _anim->_vm->_dialogs->displayText(tmpStr); + } + break; + case kMagicSpecial: + _anim->callSpecial(magic->_data); + break; + case kMagicOpenDoor: + _anim->_vm->openDoor((Room)(magic->_data >> 8), magic->_data & 0xff, magicColor); + break; + } + } + } + + if (!_anim->_vm->_doingSpriteRun) { + _count++; + if (((_moveX != 0) || (_moveY != 0)) && (_count > 1)) { + _stepNum++; + if (_stepNum == _seq) + _stepNum = 0; + _count = 0; + } + } +} + +/** + * Bounces off walls + */ +void AnimationType::bounce() { + _x = _oldX[_anim->_vm->_cp]; + _y = _oldY[_anim->_vm->_cp]; + if (_doCheck) + _anim->stopWalking(); + else + stopWalk(); + _anim->_vm->drawDirection(); +} + +int8 AnimationType::getSign(int16 val) { + if (val > 0) + return 1; + else if (val < 0) + return -1; + else + return 0; +} + +/** + * Home in on a point. + */ +void AnimationType::walkTo(byte pedNum) { + PedType *curPed = &_anim->_vm->_peds[pedNum]; + + setSpeed(getSign(curPed->_x - _x) * 4, getSign(curPed->_y - _y)); + _homingX = curPed->_x - _xLength / 2; + _homingY = curPed->_y - _yLength; + _homing = true; +} + +void AnimationType::stopHoming() { + _homing = false; +} + +/** + * Calculates ix & iy for one homing step. + */ +void AnimationType::homeStep() { + int16 temp; + + if ((_homingX == _x) && (_homingY == _y)) { + // touching the target + stopWalk(); + return; + } + _moveX = 0; + _moveY = 0; + if (_homingY != _y) { + temp = _homingY - _y; + if (temp > 4) + _moveY = 4; + else if (temp < -4) + _moveY = -4; + else + _moveY = temp; + } + if (_homingX != _x) { + temp = _homingX - _x; + if (temp > 4) + _moveX = 4; + else if (temp < -4) + _moveX = -4; + else + _moveX = temp; + } +} + +/** + * Sets ix & iy, non-homing, etc. + */ +void AnimationType::setSpeed(int8 xx, int8 yy) { + _moveX = xx; + _moveY = yy; + if ((_moveX == 0) && (_moveY == 0)) + return; // no movement + if (_moveX == 0) { + // No horz movement + if (_moveY < 0) + turn(kDirUp); + else + turn(kDirDown); + } else { + if (_moveX < 0) + turn(kDirLeft); + else + turn(kDirRight); + } +} + +/** + * Stops the sprite from moving. + */ +void AnimationType::stopWalk() { + _moveX = 0; + _moveY = 0; + _homing = false; +} + +/** + * Sets up talk vars. + */ +void AnimationType::chatter() { + _anim->_vm->_dialogs->setTalkPos(_x + _xLength / 2, _y); + _anim->_vm->_graphics->setDialogColor(_bgBubbleCol, _fgBubbleCol); +} + +void AnimationType::remove() { + for (int i = 0; i < _frameNum; i++) { + delete[] _mani[i]; + delete[] _sil[i]; + } + + _quick = false; + _id = 177; +} + +Animation::Animation(AvalancheEngine *vm) { + _vm = vm; + _mustExclaim = false; + + for (int16 i = 0; i < kSpriteNumbMax; i++) { + _sprites[i] = new AnimationType(this); + } +} + +Animation::~Animation() { + for (int16 i = 0; i < kSpriteNumbMax; i++) { + AnimationType *curSpr = _sprites[i]; + + if (curSpr->_quick) + curSpr->remove(); + delete(curSpr); + } +} + +/** + * Resets Animation variables. + * @remarks Originally called 'loadtrip' + */ +void Animation::resetAnims() { + setDirection(kDirStopped); + for (int16 i = 0; i < kSpriteNumbMax; i++) + _sprites[i]->reset(); +} + +byte Animation::checkFeet(int16 x1, int16 x2, int16 oy, int16 y, byte yl) { + if (!_vm->_alive) + return 0; + + if (x1 < 0) + x1 = 0; + if (x2 > 639) + x2 = 639; + + int16 minY = MIN(oy, y) + yl; + int16 maxY = MAX(oy, y) + yl; + + return _vm->_graphics->getAlsoColor(x1, minY, x2, maxY); +} + +byte Animation::geidaPed(byte ped) { + switch (ped) { + case 1: + return 6; + case 2: + case 6: + return 7; + case 3: + case 5: + return 8; + case 4: + return 9; + default: + error("geidaPed(): Unhandled ped value %d", ped); + } +} + +/** + * When you enter a new position in the catacombs, this procedure should be + * called. It changes the 'also' codes so that they may match the picture + * on the screen. + */ +void Animation::catacombMove(byte ped) { + // XY_uint16 is _catacombX+_catacombY*256. Thus, every room in the + // catacombs has a different number for it. + uint16 xy = _vm->_catacombX + _vm->_catacombY * 256; + _geidaSpin = 0; + + switch (xy) { + case 1801: // Exit catacombs + _vm->flipRoom(kRoomLustiesRoom, 4); + _vm->_dialogs->displayText("Phew! Nice to be out of there!"); + return; + case 1033:{ // Oubliette + _vm->flipRoom(kRoomOubliette, 1); + Common::String tmpStr = Common::String::format("Oh, NO!%c1%c", kControlRegister, kControlSpeechBubble); + _vm->_dialogs->displayText(tmpStr); + } + return; + case 4: + _vm->flipRoom(kRoomGeidas, 1); + return; + case 2307: + _vm->flipRoom(kRoomLusties, 5); + _vm->_dialogs->displayText("Oh no... here we go again..."); + _vm->_userMovesAvvy = false; + _sprites[0]->_moveY = 1; + _sprites[0]->_moveX = 0; + return; + } + + if (!_vm->_enterCatacombsFromLustiesRoom) + _vm->loadRoom(29); + int32 here = kCatacombMap[_vm->_catacombY - 1][_vm->_catacombX - 1]; + + switch (here & 0xf) { // West. + case 0: // no connection (wall) + _vm->_magics[1]._operation = kMagicBounce; // Sloping wall. + _vm->_magics[2]._operation = kMagicNothing; // Straight wall. + _vm->_portals[4]._operation = kMagicNothing; // Door. + _vm->_background->draw(-1, -1, 27); + break; + case 0x1: // no connection (wall + shield), + _vm->_magics[1]._operation = kMagicBounce; // Sloping wall. + _vm->_magics[2]._operation = kMagicNothing; // Straight wall. + _vm->_portals[4]._operation = kMagicNothing; // Door. + _vm->_background->draw(-1, -1, 27); // Wall, plus... + _vm->_background->draw(-1, -1, 28); // ...shield. + break; + case 0x2: // wall with door + _vm->_magics[1]._operation = kMagicBounce; // Sloping wall. + _vm->_magics[2]._operation = kMagicNothing; // Straight wall. + _vm->_portals[4]._operation = kMagicSpecial; // Door. + _vm->_background->draw(-1, -1, 27); // Wall, plus... + _vm->_background->draw(-1, -1, 29); // ...door. + break; + case 0x3: // wall with door and shield + _vm->_magics[1]._operation = kMagicBounce; // Sloping wall. + _vm->_magics[2]._operation = kMagicNothing; // Straight wall. + _vm->_portals[4]._operation = kMagicSpecial; // Door. + _vm->_background->draw(-1, -1, 27); // Wall, plus... + _vm->_background->draw(-1, -1, 29); // ...door, and... + _vm->_background->draw(-1, -1, 28); // ...shield. + break; + case 0x4: // no connection (wall + window), + _vm->_magics[1]._operation = kMagicBounce; // Sloping wall. + _vm->_magics[2]._operation = kMagicNothing; // Straight wall. + _vm->_portals[4]._operation = kMagicNothing; // Door. + _vm->_background->draw(-1, -1, 27); // Wall, plus... + _vm->_background->draw(-1, -1, 4); // ...window. + break; + case 0x5: // wall with door and window + _vm->_magics[1]._operation = kMagicBounce; // Sloping wall. + _vm->_magics[2]._operation = kMagicNothing; // Straight wall. + _vm->_portals[4]._operation = kMagicSpecial; // Door. + _vm->_background->draw(-1, -1, 27); // Wall, plus... + _vm->_background->draw(-1, -1, 29); // ...door, and... + _vm->_background->draw(-1, -1, 4); // ...window. + break; + case 0x6: // no connection (wall + torches), + _vm->_magics[1]._operation = kMagicBounce; // Sloping wall. + _vm->_magics[2]._operation = kMagicNothing; // Straight wall. + _vm->_portals[4]._operation = kMagicNothing; // No door. + _vm->_background->draw(-1, -1, 27); // Wall, plus... + _vm->_background->draw(-1, -1, 6); // ...torches. + break; + case 0x7: // wall with door and torches + _vm->_magics[1]._operation = kMagicBounce; // Sloping wall. + _vm->_magics[2]._operation = kMagicNothing; // Straight wall. + _vm->_portals[4]._operation = kMagicSpecial; // Door. + _vm->_background->draw(-1, -1, 27); // Wall, plus... + _vm->_background->draw(-1, -1, 29); // ...door, and... + _vm->_background->draw(-1, -1, 6); // ...torches. + break; + case 0xf: // straight-through corridor. + _vm->_magics[1]._operation = kMagicNothing; // Sloping wall. + _vm->_magics[2]._operation = kMagicSpecial; // Straight wall. + break; + } + + /* ---- */ + + switch ((here & 0xf0) >> 4) { // East + case 0: // no connection (wall) + _vm->_magics[4]._operation = kMagicBounce; // Sloping wall. + _vm->_magics[5]._operation = kMagicNothing; // Straight wall. + _vm->_portals[6]._operation = kMagicNothing; // Door. + _vm->_background->draw(-1, -1, 18); + break; + case 0x1: // no connection (wall + window), + _vm->_magics[4]._operation = kMagicBounce; // Sloping wall. + _vm->_magics[5]._operation = kMagicNothing; // Straight wall. + _vm->_portals[6]._operation = kMagicNothing; // Door. + _vm->_background->draw(-1, -1, 18); // Wall, plus... + _vm->_background->draw(-1, -1, 19); // ...window. + break; + case 0x2: // wall with door + _vm->_magics[4]._operation = kMagicBounce; // Sloping wall. + _vm->_magics[5]._operation = kMagicNothing; // Straight wall. + _vm->_portals[6]._operation = kMagicSpecial; // Door. + _vm->_background->draw(-1, -1, 18); // Wall, plus... + _vm->_background->draw(-1, -1, 20); // ...door. + break; + case 0x3: // wall with door and window + _vm->_magics[4]._operation = kMagicBounce; // Sloping wall. + _vm->_magics[5]._operation = kMagicNothing; // Straight wall. + _vm->_portals[6]._operation = kMagicSpecial; // Door. + _vm->_background->draw(-1, -1, 18); // Wall, plus... + _vm->_background->draw(-1, -1, 19); // ...door, and... + _vm->_background->draw(-1, -1, 20); // ...window. + break; + case 0x6: // no connection (wall + torches), + _vm->_magics[4]._operation = kMagicBounce; // Sloping wall. + _vm->_magics[5]._operation = kMagicNothing; // Straight wall. + _vm->_portals[6]._operation = kMagicNothing; // No door. + _vm->_background->draw(-1, -1, 18); // Wall, plus... + _vm->_background->draw(-1, -1, 17); // ...torches. + break; + case 0x7: // wall with door and torches + _vm->_magics[4]._operation = kMagicBounce; // Sloping wall. + _vm->_magics[5]._operation = kMagicNothing; // Straight wall. + _vm->_portals[6]._operation = kMagicSpecial; // Door. + _vm->_background->draw(-1, -1, 18); // Wall, plus... + _vm->_background->draw(-1, -1, 20); // ...door, and... + _vm->_background->draw(-1, -1, 17); // ...torches. + break; + case 0xf: // straight-through corridor. + _vm->_magics[4]._operation = kMagicNothing; // Sloping wall. + _vm->_magics[5]._operation = kMagicSpecial; // Straight wall. + _vm->_portals[6]._operation = kMagicNothing; // Door. + break; + } + + switch ((here & 0xf00) >> 8) { // South + case 0: // No connection. + _vm->_magics[6]._operation = kMagicBounce; + _vm->_magics[11]._operation = kMagicBounce; + _vm->_magics[12]._operation = kMagicBounce; + break; + case 0x1: + _vm->_background->draw(-1, -1, 21); + + if ((xy == 2051) && _vm->_geidaFollows) + _vm->_magics[12]._operation = kMagicExclaim; + else + _vm->_magics[12]._operation = kMagicSpecial; // Right exit south. + + _vm->_magics[6]._operation = kMagicBounce; + _vm->_magics[11]._operation = kMagicBounce; + break; + case 0x2: + _vm->_background->draw(-1, -1, 22); + _vm->_magics[6]._operation = kMagicSpecial; // Middle exit south. + _vm->_magics[11]._operation = kMagicBounce; + _vm->_magics[12]._operation = kMagicBounce; + break; + case 0x3: + _vm->_background->draw(-1, -1, 23); + _vm->_magics[11]._operation = kMagicSpecial; // Left exit south. + _vm->_magics[6]._operation = kMagicBounce; + _vm->_magics[12]._operation = kMagicBounce; + break; + } + + switch ((here & 0xf000) >> 12) { // North + case 0: // No connection + _vm->_magics[0]._operation = kMagicBounce; + _vm->_portals[3]._operation = kMagicNothing; // Door. + break; + // LEFT handles: +#if 0 + case 0x1: + _vm->_celer->show_one(-1, -1, 4); + _vm->magics[1].op = _vm->bounces; // { Left exit north. } { Change magic number! } + _vm->portals[12].op = _vm->special; // { Door. } + break; +#endif + case 0x2: + _vm->_background->draw(-1, -1, 3); + _vm->_magics[0]._operation = kMagicBounce; // Middle exit north. + _vm->_portals[3]._operation = kMagicSpecial; // Door. + break; +#if 0 + case 0x3: + _vm->_celer->show_one(-1, -1, 4); + _vm->magics[1].op = _vm->bounces; // { Right exit north. } { Change magic number! } + _vm->portals[12].op = _vm->special; // { Door. } + break; + // RIGHT handles: + case 0x4: + _vm->_celer->show_one(-1, -1, 3); + _vm->magics[1].op = _vm->bounces; // { Left exit north. } { Change magic number! } + _vm->portals[12].op = _vm->special; // { Door. } + break; +#endif + case 0x5: + _vm->_background->draw(-1, -1, 2); + _vm->_magics[0]._operation = kMagicBounce; // Middle exit north. + _vm->_portals[3]._operation = kMagicSpecial; // Door. + break; +#if 0 + case 0x6: + _vm->_celer->show_one(-1, -1, 3); + _vm->magics[1].op = _vm->bounces; // { Right exit north. } + _vm->portals[12].op = _vm->special; // { Door. } + break; +#endif + // ARCHWAYS: + case 0x7: + case 0x8: + case 0x9: + _vm->_background->draw(-1, -1, 5); + + if (((here & 0xf000) >> 12) > 0x7) + _vm->_background->draw(-1, -1, 30); + if (((here & 0xf000) >> 12) == 0x9) + _vm->_background->draw(-1, -1, 31); + + _vm->_magics[0]._operation = kMagicSpecial; // Middle arch north. + _vm->_portals[3]._operation = kMagicNothing; // Door. + break; + // DECORATIONS: + case 0xd: // No connection + WINDOW + _vm->_magics[0]._operation = kMagicBounce; + _vm->_portals[3]._operation = kMagicNothing; // Door. + _vm->_background->draw(-1, -1, 13); + break; + case 0xe: // No connection + TORCH + _vm->_magics[0]._operation = kMagicBounce; + _vm->_portals[3]._operation = kMagicNothing; // Door. + _vm->_background->draw(-1, -1, 7); + break; + // Recessed door: + case 0xf: + _vm->_magics[0]._operation = kMagicNothing; // Door to Geida's room. + _vm->_background->draw(-1, -1, 0); + _vm->_portals[3]._operation = kMagicSpecial; // Door. + break; + } + + switch (xy) { + case 514: + _vm->_background->draw(-1, -1, 16); + break; // [2,2] : "Art Gallery" sign over door. + case 264: + _vm->_background->draw(-1, -1, 8); + break; // [8,1] : "The Wrong Way!" sign. + case 1797: + _vm->_background->draw(-1, -1, 1); + break; // [5,7] : "Ite Mingite" sign. + case 258: + for (int i = 0; i <= 2; i++) { // [2,1] : Art gallery - pictures + _vm->_background->draw(130 + i * 120, 70, 14); + _vm->_background->draw(184 + i * 120, 78, 15); + } + break; + case 1287: + for (int i = 10; i <= 13; i++) + _vm->_background->draw(-1, -1, i - 1); + break; // [7,5] : 4 candles. + case 776: + _vm->_background->draw(-1, -1, 9); + break; // [8,3] : 1 candle. + case 2049: + _vm->_background->draw(-1, -1, 10); + break; // [1,8] : another candle. + case 257: + _vm->_background->draw(-1, -1, 11); + _vm->_background->draw(-1, -1, 12); + break; // [1,1] : the other two. + } + + if (_vm->_geidaFollows && (ped > 0)) { + AnimationType *spr1 = _sprites[1]; + + if (!spr1->_quick) // If we don't already have her... + spr1->init(5, true); // ...Load Geida. + appearPed(1, geidaPed(ped)); + spr1->_callEachStepFl = true; + spr1->_eachStepProc = kProcGeida; + } +} + +/** + * This proc gets called whenever you touch a line defined as _vm->special. + */ +void Animation::dawnDelay() { + _vm->_timer->addTimer(2, Timer::kProcDawnDelay, Timer::kReasonDawndelay); +} + +void Animation::callSpecial(uint16 which) { + switch (which) { + case 1: // _vm->special 1: Room 22: top of stairs. + _vm->_background->draw(-1, -1, 0); + _vm->_brummieStairs = 1; + _vm->_magics[9]._operation = kMagicNothing; + _vm->_timer->addTimer(10, Timer::kProcStairs, Timer::kReasonBrummieStairs); + stopWalking(); + _vm->_userMovesAvvy = false; + break; + case 2: // _vm->special 2: Room 22: bottom of stairs. + _vm->_brummieStairs = 3; + _vm->_magics[10]._operation = kMagicNothing; + _vm->_magics[11]._operation = kMagicExclaim; + _vm->_magics[11]._data = 5; + _vm->_magics[3]._operation = kMagicBounce; // Now works as planned! + stopWalking(); + _vm->_dialogs->displayScrollChain('q', 26); + _vm->_userMovesAvvy = true; + break; + case 3: // _vm->special 3: Room 71: triggers dart. + _sprites[0]->bounce(); // Must include that. + + if (!_arrowTriggered) { + _arrowTriggered = true; + + AnimationType *spr1 = _sprites[1]; + appearPed(1, 3); // The dart starts at ped 4, and... + spr1->walkTo(4); // flies to ped 5 (- 1 for pascal to C conversion). + spr1->_facingDir = kDirUp; // Only face. + // Should call some kind of Eachstep procedure which will deallocate + // the sprite when it hits the wall, and replace it with the chunk + // graphic of the arrow buried in the plaster. */ + + // OK! + spr1->_callEachStepFl = true; + spr1->_eachStepProc = kProcArrow; + } + break; + case 4: // This is the ghost room link. + _vm->fadeOut(); + _sprites[0]->turn(kDirRight); // you'll see this after we get back from bootstrap + _vm->_timer->addTimer(1, Timer::kProcGhostRoomPhew, Timer::kReasonGhostRoomPhew); + //_vm->_enid->backToBootstrap(3); TODO: Replace it with proper ScummVM-friendly function(s)! Do not remove until then! + break; + case 5: + if (_vm->_friarWillTieYouUp) { + // _vm->special 5: Room 42: touched tree, and get tied up. + _vm->_magics[4]._operation = kMagicBounce; // Boundary effect is now working again. + _vm->_dialogs->displayScrollChain('q', 35); + _sprites[0]->remove(); + //tr[1].vanishifstill:=true; + + AnimationType *spr1 = _sprites[1]; + _vm->_background->draw(-1, -1, 1); + _vm->_dialogs->displayScrollChain('q', 36); + _vm->_tiedUp = true; + _vm->_friarWillTieYouUp = false; + spr1->walkTo(2); + spr1->_vanishIfStill = true; + spr1->_doCheck = true; // One of them must have Check_Me switched on. + _vm->setRoom(kPeopleFriarTuck, kRoomDummy); // Not here, then. + _vm->_timer->addTimer(364, Timer::kProcHangAround, Timer::kReasonHangingAround); + } + break; + case 6: { + // _vm->special 6: fall down oubliette. + AnimationType *avvy = _sprites[0]; + _vm->_userMovesAvvy = false; + avvy->_moveX = 3; + avvy->_moveY = 0; + avvy->_facingDir = kDirRight; + _vm->_timer->addTimer(1, Timer::kProcFallDownOubliette, Timer::kReasonFallingDownOubliette); + } + break; + case 7: // _vm->special 7: stop falling down oubliette. + _sprites[0]->_visible = false; + _vm->_magics[9]._operation = kMagicNothing; + stopWalking(); + _vm->_timer->loseTimer(Timer::kReasonFallingDownOubliette); + //_vm->mblit(12, 80, 38, 160, 3, 0); + //_vm->mblit(12, 80, 38, 160, 3, 1); + _vm->_dialogs->displayText("Oh dear, you seem to be down the bottom of an oubliette."); + _vm->_timer->addTimer(200, Timer::kProcMeetAvaroid, Timer::kReasonMeetingAvaroid); + break; + case 8: // _vm->special 8: leave du Lustie's room. + if (_vm->_geidaFollows && !_vm->_lustieIsAsleep) { + AnimationType *spr1 = _sprites[1]; + _vm->_dialogs->displayScrollChain('q', 63); + spr1->turn(kDirDown); + spr1->stopWalk(); + spr1->_callEachStepFl = false; // Geida + _vm->gameOver(); + } + break; + case 9: { + // _vm->special 9: lose Geida to Robin Hood... + if (!_vm->_geidaFollows) + return; // DOESN'T COUNT: no Geida. + AnimationType *spr1 = _sprites[1]; + spr1->_callEachStepFl = false; // She no longer follows Avvy around. + spr1->walkTo(3); // She walks to somewhere... + _sprites[0]->remove(); // Lose Avvy. + _vm->_userMovesAvvy = false; + _vm->_timer->addTimer(40, Timer::kProcRobinHoodAndGeida, Timer::kReasonRobinHoodAndGeida); + } + break; + case 10: // _vm->special 10: transfer north in catacombs. + if ((_vm->_catacombX == 4) && (_vm->_catacombY == 1)) { + // Into Geida's room. + if (_vm->_objects[kObjectKey - 1]) + _vm->_dialogs->displayScrollChain('q', 62); + else { + _vm->_dialogs->displayScrollChain('q', 61); + return; + } + } + _vm->fadeOut(); + _vm->_catacombY--; + catacombMove(4); + if (_vm->_room != kRoomCatacombs) + return; + switch ((kCatacombMap[_vm->_catacombY - 1][_vm->_catacombX - 1] & 0xf00) >> 8) { + case 0x1: + appearPed(0, 11); + break; + case 0x3: + appearPed(0, 10); + break; + default: + appearPed(0, 3); + } + dawnDelay(); + break; + case 11: // _vm->special 11: transfer east in catacombs. + _vm->fadeOut(); + _vm->_catacombX++; + catacombMove(1); + if (_vm->_room != kRoomCatacombs) + return; + appearPed(0, 0); + dawnDelay(); + break; + case 12: // _vm->special 12: transfer south in catacombs. + _vm->fadeOut(); + _vm->_catacombY++; + catacombMove(2); + if (_vm->_room != kRoomCatacombs) + return; + appearPed(0, 1); + dawnDelay(); + break; + case 13: // _vm->special 13: transfer west in catacombs. + _vm->fadeOut(); + _vm->_catacombX--; + catacombMove(3); + if (_vm->_room != kRoomCatacombs) + return; + appearPed(0, 2); + dawnDelay(); + break; + } +} + +void Animation::updateSpeed() { + AnimationType *avvy = _sprites[0]; + // Given that you've just changed the speed in _speedX, this adjusts _moveX. + avvy->_moveX = (avvy->_moveX / 3) * avvy->_speedX; + _vm->_graphics->drawSpeedBar(avvy->_speedX); +} + +void Animation::setMoveSpeed(byte t, Direction dir) { + AnimationType *spr = _sprites[t]; + switch (dir) { + case kDirUp: + spr->setSpeed(0, -spr->_speedY); + break; + case kDirDown: + spr->setSpeed(0, spr->_speedY); + break; + case kDirLeft: + spr->setSpeed(-spr->_speedX, 0); + break; + case kDirRight: + spr->setSpeed(spr->_speedX, 0); + break; + case kDirUpLeft: + spr->setSpeed(-spr->_speedX, -spr->_speedY); + break; + case kDirUpRight: + spr->setSpeed(spr->_speedX, -spr->_speedY); + break; + case kDirDownLeft: + spr->setSpeed(-spr->_speedX, spr->_speedY); + break; + case kDirDownRight: + spr->setSpeed(spr->_speedX, spr->_speedY); + break; + default: + break; + } +} + +void Animation::appearPed(byte sprNum, byte pedNum) { + AnimationType *curSpr = _sprites[sprNum]; + PedType *curPed = &_vm->_peds[pedNum]; + curSpr->appear(curPed->_x - curSpr->_xLength / 2, curPed->_y - curSpr->_yLength, curPed->_direction); + setMoveSpeed(sprNum, curPed->_direction); +} + +/** + * @remarks Originally called 'follow_avvy_y' + */ +void Animation::followAvalotY(byte tripnum) { + if (_sprites[0]->_facingDir == kDirLeft) + return; + + AnimationType *tripSpr = _sprites[tripnum]; + AnimationType *spr1 = _sprites[1]; + + if (tripSpr->_homing) + tripSpr->_homingY = spr1->_y; + else { + if (tripSpr->_y < spr1->_y) + tripSpr->_y++; + else if (tripSpr->_y > spr1->_y) + tripSpr->_y--; + else + return; + + if (tripSpr->_moveX == 0) { + tripSpr->_stepNum++; + if (tripSpr->_stepNum == tripSpr->_seq) + tripSpr->_stepNum = 0; + tripSpr->_count = 0; + } + } +} + +void Animation::backAndForth(byte tripnum) { + AnimationType *tripSpr = _sprites[tripnum]; + + if (!tripSpr->_homing) { + if (tripSpr->_facingDir == kDirRight) + tripSpr->walkTo(3); + else + tripSpr->walkTo(4); + } +} + +void Animation::faceAvvy(byte tripnum) { + AnimationType *tripSpr = _sprites[tripnum]; + + if (!tripSpr->_homing) { + if (_sprites[0]->_x >= tripSpr->_x) + tripSpr->_facingDir = kDirRight; + else + tripSpr->_facingDir = kDirLeft; + } +} + +void Animation::arrowProcs(byte tripnum) { + AnimationType *tripSpr = _sprites[tripnum]; + AnimationType *avvy = _sprites[tripnum]; + + if (tripSpr->_homing) { + // Arrow is still in flight. + // We must check whether or not the arrow has collided tr[tripnum] Avvy's head. + // This is so if: a) the bottom of the arrow is below Avvy's head, + // b) the left of the arrow is left of the right of Avvy's head, and + // c) the right of the arrow is right of the left of Avvy's head. + if ((tripSpr->_y + tripSpr->_yLength >= avvy->_y) // A + && (tripSpr->_x <= avvy->_x + avvy->_xLength) // B + && (tripSpr->_x + tripSpr->_xLength >= avvy->_x)) { // C + // OK, it's hit him... what now? + + _sprites[1]->_callEachStepFl = false; // prevent recursion. + _vm->_dialogs->displayScrollChain('Q', 47); // Complaint! + tripSpr->remove(); // Deallocate the arrow. + + _vm->gameOver(); + + _vm->_userMovesAvvy = false; // Stop the user from moving him. + _vm->_timer->addTimer(55, Timer::kProcNaughtyDuke, Timer::kReasonNaughtyDuke); + } + } else { // Arrow has hit the wall! + tripSpr->remove(); // Deallocate the arrow. + _vm->_background->draw(-1, -1, 2); // Show pic of arrow stuck into the door. + _vm->_arrowInTheDoor = true; // So that we can pick it up. + } +} + +void Animation::grabAvvy(byte tripnum) { // For Friar Tuck, in Nottingham. + AnimationType *tripSpr = _sprites[tripnum]; + AnimationType *avvy = _sprites[tripnum]; + + int16 tox = avvy->_x + 17; + int16 toy = avvy->_y - 1; + if ((tripSpr->_x == tox) && (tripSpr->_y == toy)) { + tripSpr->_callEachStepFl = false; + tripSpr->_facingDir = kDirLeft; + tripSpr->stopWalk(); + // ... whatever ... + } else { + // Still some way to go. + if (tripSpr->_x < tox) { + tripSpr->_x += 5; + if (tripSpr->_x > tox) + tripSpr->_x = tox; + } + if (tripSpr->_y < toy) + tripSpr->_y++; + tripSpr->_stepNum++; + if (tripSpr->_stepNum == tripSpr->_seq) + tripSpr->_stepNum = 0; + } +} + +void Animation::takeAStep(byte &tripnum) { + AnimationType *tripSpr = _sprites[tripnum]; + + if (tripSpr->_moveX == 0) { + tripSpr->_stepNum++; + if (tripSpr->_stepNum == tripSpr->_seq) + tripSpr->_stepNum = 0; + tripSpr->_count = 0; + } +} + +void Animation::spin(Direction dir, byte &tripnum) { + AnimationType *tripSpr = _sprites[tripnum]; + + if (tripSpr->_facingDir == dir) + return; + + tripSpr->_facingDir = dir; + if (tripSpr->_id == 2) + return; // Not for Spludwick + + _geidaSpin++; + _geidaTime = 20; + if (_geidaSpin == 5) { + _vm->_dialogs->displayText("Steady on, Avvy, you'll make the poor girl dizzy!"); + _geidaSpin = 0; + _geidaTime = 0; // knock out records + } +} + +void Animation::geidaProcs(byte tripnum) { + AnimationType *tripSpr = _sprites[tripnum]; + AnimationType *avvy = _sprites[0]; + + if (_geidaTime > 0) { + _geidaTime--; + if (_geidaTime == 0) + _geidaSpin = 0; + } + + if (tripSpr->_y < (avvy->_y - 2)) { + // Geida is further from the screen than Avvy. + spin(kDirDown, tripnum); + tripSpr->_moveY = 1; + tripSpr->_moveX = 0; + takeAStep(tripnum); + return; + } else if (tripSpr->_y > (avvy->_y + 2)) { + // Avvy is further from the screen than Geida. + spin(kDirUp, tripnum); + tripSpr->_moveY = -1; + tripSpr->_moveX = 0; + takeAStep(tripnum); + return; + } + + tripSpr->_moveY = 0; + // These 12-s are not in the original, I added them to make the following method more "smooth". + // Now the NPC which is following Avvy won't block his way and will walk next to him properly. + if (tripSpr->_x < avvy->_x - avvy->_speedX * 8 - 12) { + tripSpr->_moveX = avvy->_speedX; + spin(kDirRight, tripnum); + takeAStep(tripnum); + } else if (tripSpr->_x > avvy->_x + avvy->_speedX * 8 + 12) { + tripSpr->_moveX = -avvy->_speedX; + spin(kDirLeft, tripnum); + takeAStep(tripnum); + } else + tripSpr->_moveX = 0; +} + +/** + * @remarks Originally called 'call_andexors' + */ +void Animation::drawSprites() { + int8 order[5]; + byte temp; + bool ok; + + for (int i = 0; i < 5; i++) + order[i] = -1; + + for (int16 i = 0; i < kSpriteNumbMax; i++) { + AnimationType *curSpr = _sprites[i]; + if (curSpr->_quick && curSpr->_visible) + order[i] = i; + } + + do { + ok = true; + for (int i = 0; i < 4; i++) { + if ((order[i] != -1) && (order[i + 1] != -1) && (_sprites[order[i]]->_y > _sprites[order[i + 1]]->_y)) { + // Swap them! + temp = order[i]; + order[i] = order[i + 1]; + order[i + 1] = temp; + ok = false; + } + } + } while (!ok); + + _vm->_graphics->refreshBackground(); + + for (int i = 0; i < 5; i++) { + if (order[i] > -1) + _sprites[order[i]]->draw(); + } +} + +/** + * Animation links + * @remarks Originally called 'trippancy_link' + */ +void Animation::animLink() { + if (_vm->_menu->isActive() || _vm->_seeScroll) + return; + for (int16 i = 0; i < kSpriteNumbMax; i++) { + AnimationType *curSpr = _sprites[i]; + if (curSpr->_quick && curSpr->_visible) + curSpr->walk(); + } + + drawSprites(); + + for (int16 i = 0; i < kSpriteNumbMax; i++) { + AnimationType *curSpr = _sprites[i]; + if (curSpr->_quick && curSpr->_callEachStepFl) { + switch (curSpr->_eachStepProc) { + case kProcFollowAvvyY : + followAvalotY(i); + break; + case kProcBackAndForth : + backAndForth(i); + break; + case kProcFaceAvvy : + faceAvvy(i); + break; + case kProcArrow : + arrowProcs(i); + break; + // PROCSpludwick_procs : spludwick_procs(fv); + case kProcGrabAvvy : + grabAvvy(i); + break; + case kProcGeida : + geidaProcs(i); + break; + } + } + } + + if (_mustExclaim) { + _mustExclaim = false; + _vm->_dialogs->displayScrollChain('x', _sayWhat); + } +} + +void Animation::stopWalking() { + AnimationType *avvy = _sprites[0]; + + avvy->stopWalk(); + _direction = kDirStopped; + if (_vm->_alive) + avvy->_stepNum = 1; +} + +/** + * Hide in the cupboard + * @remarks Originally called 'hide_in_the_cupboard' + */ +void Animation::hideInCupboard() { + if (_vm->_avvysInTheCupboard) { + if (_vm->_parser->_wearing == kObjectDummy) { + Common::String tmpStr = Common::String::format("%cAVVY!%cGet dressed first!", kControlItalic, kControlRoman); + _vm->_dialogs->displayText(tmpStr); + } else { + _sprites[0]->_visible = true; + _vm->_userMovesAvvy = true; + appearPed(0, 2); // Walk out of the cupboard. + _vm->_dialogs->displayText("You leave the cupboard. Nice to be out of there!"); + _vm->_avvysInTheCupboard = false; + _vm->_sequence->startCupboardSeq(); + } + } else { + // Not hiding in the cupboard + _sprites[0]->_visible = false; + _vm->_userMovesAvvy = false; + Common::String tmpStr = Common::String::format("You walk into the room...%cIt seems to be an empty, " \ + "but dusty, cupboard. Hmmmm... you leave the door slightly open to avoid suffocation.", kControlParagraph); + _vm->_dialogs->displayText(tmpStr); + _vm->_avvysInTheCupboard = true; + _vm->_background->draw(-1, -1, 7); + } +} + +/** + * Returns true if you're within field "which". + */ +bool Animation::inField(byte which) { + AnimationType *avvy = _sprites[0]; + + FieldType *curField = &_vm->_fields[which]; + int16 yy = avvy->_y + avvy->_yLength; + + return (avvy->_x >= curField->_x1) && (avvy->_x <= curField->_x2) && (yy >= curField->_y1) && (yy <= curField->_y2); +} + +/** + * Returns True if you're near a door. + */ +bool Animation::nearDoor() { + if (_vm->_fieldNum < 8) + // there ARE no doors here! + return false; + + AnimationType *avvy = _sprites[0]; + + int16 ux = avvy->_x; + int16 uy = avvy->_y + avvy->_yLength; + + for (int i = 8; i < _vm->_fieldNum; i++) { + FieldType *curField = &_vm->_fields[i]; + if ((ux >= curField->_x1) && (ux <= curField->_x2) && (uy >= curField->_y1) && (uy <= curField->_y2)) + return true; + } + + return false; +} + +/** + * @remarks Originally called 'tripkey' + */ +void Animation::handleMoveKey(const Common::Event &event) { + if (!_vm->_userMovesAvvy) + return; + + if (_vm->_menu->_activeMenuItem._activeNow) + _vm->_parser->tryDropdown(); + else { + switch (event.kbd.keycode) { + case Common::KEYCODE_UP: + if (_direction != kDirUp) { + _direction = kDirUp; + setMoveSpeed(0, _direction); + } else + stopWalking(); + break; + case Common::KEYCODE_DOWN: + if (_direction != kDirDown) { + _direction = kDirDown; + setMoveSpeed(0, _direction); + } else + stopWalking(); + break; + case Common::KEYCODE_LEFT: + if (_direction != kDirLeft) { + _direction = kDirLeft; + setMoveSpeed(0, _direction); + } else + stopWalking(); + break; + case Common::KEYCODE_RIGHT: + if (_direction != kDirRight) { + _direction = kDirRight; + setMoveSpeed(0, _direction); + } else + stopWalking(); + break; + case Common::KEYCODE_PAGEUP: + if (_direction != kDirUpRight) { + _direction = kDirUpRight; + setMoveSpeed(0, _direction); + } else + stopWalking(); + break; + case Common::KEYCODE_PAGEDOWN: + if (_direction != kDirDownRight) { + _direction = kDirDownRight; + setMoveSpeed(0, _direction); + } else + stopWalking(); + break; + case Common::KEYCODE_END: + if (_direction != kDirDownLeft) { + _direction = kDirDownLeft; + setMoveSpeed(0, _direction); + } else + stopWalking(); + break; + case Common::KEYCODE_HOME: + if (_direction != kDirUpLeft) { + _direction = kDirUpLeft; + setMoveSpeed(0, _direction); + } else + stopWalking(); + break; + case Common::KEYCODE_KP5: + stopWalking(); + break; + default: + break; + } + } +} + +void Animation::setDirection(Direction dir) { + _direction = dir; +} + +void Animation::setOldDirection(Direction dir) { + _oldDirection = dir; +} + +Direction Animation::getDirection() { + return _direction; +} + +Direction Animation::getOldDirection() { + return _oldDirection; +} + +void Animation::setAvvyClothes(int id) { + AnimationType *spr = _sprites[0]; + if (spr->_id == id) + return; + + int16 x = spr->_x; + int16 y = spr->_y; + spr->remove(); + spr->init(id, true); + spr->appear(x, y, kDirLeft); + spr->_visible = false; +} + +int Animation::getAvvyClothes() { + return _sprites[0]->_id; +} + +void Animation::resetVariables() { + _geidaSpin = 0; + _geidaTime = 0; + _arrowTriggered = false; +} + +void Animation::synchronize(Common::Serializer &sz) { + sz.syncAsByte(_direction); + sz.syncAsByte(_geidaSpin); + sz.syncAsByte(_geidaTime); + + byte spriteNum = 0; + if (sz.isSaving()) { + for (int i = 0; i < kSpriteNumbMax; i++) { + if (_sprites[i]->_quick) + spriteNum++; + } + } + sz.syncAsByte(spriteNum); + + if (sz.isLoading()) { + for (int i = 0; i < kSpriteNumbMax; i++) { // Deallocate sprites. + AnimationType *spr = _sprites[i]; + if (spr->_quick) + spr->remove(); + } + } + + for (int i = 0; i < spriteNum; i++) { + AnimationType *spr = _sprites[i]; + sz.syncAsByte(spr->_id); + sz.syncAsByte(spr->_doCheck); + + if (sz.isLoading()) { + spr->_quick = true; + spr->init(spr->_id, spr->_doCheck); + } + + sz.syncAsByte(spr->_moveX); + sz.syncAsByte(spr->_moveY); + sz.syncAsByte(spr->_facingDir); + sz.syncAsByte(spr->_stepNum); + sz.syncAsByte(spr->_visible); + sz.syncAsByte(spr->_homing); + sz.syncAsByte(spr->_count); + sz.syncAsByte(spr->_speedX); + sz.syncAsByte(spr->_speedY); + sz.syncAsByte(spr->_frameNum); + sz.syncAsSint16LE(spr->_homingX); + sz.syncAsSint16LE(spr->_homingY); + sz.syncAsByte(spr->_callEachStepFl); + sz.syncAsByte(spr->_eachStepProc); + sz.syncAsByte(spr->_vanishIfStill); + sz.syncAsSint16LE(spr->_x); + sz.syncAsSint16LE(spr->_y); + + if (sz.isLoading() && spr->_visible) + spr->appear(spr->_x, spr->_y, spr->_facingDir); + } + + sz.syncAsByte(_arrowTriggered); +} + +} // End of namespace Avalanche. diff --git a/engines/avalanche/animation.h b/engines/avalanche/animation.h new file mode 100644 index 0000000000..33f6ab02a6 --- /dev/null +++ b/engines/avalanche/animation.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 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on the original source code of Lord Avalot d'Argent version 1.3. + * Copyright (c) 1994-1995 Mike, Mark and Thomas Thurman. + */ + +/* Original name: TRIP5 / Trippancy V - the sprite animation subsystem */ + +#ifndef AVALANCHE_ANIMATION_H +#define AVALANCHE_ANIMATION_H + +namespace Avalanche { +class AvalancheEngine; +class Animation; + +enum Direction { + kDirUp = 0, kDirRight, kDirDown, kDirLeft, + kDirUpRight, kDirDownRight, kDirDownLeft, kDirUpLeft, + kDirStopped, kDirNone = 177 +}; + +class AnimationType { +public: + byte _id; + + byte _xLength, _yLength; + ManiType *_mani[24]; + SilType *_sil[24]; + byte _frameNum; // Number of pictures. + byte _seq; // How many in one stride. + byte _characterId; // The number according to Acci. (1=Avvy, etc.) + byte _count; // Counts before changing step. + + Direction _facingDir; + byte _stepNum; + int16 _x, _y; // Current xy coords. + int8 _moveX, _moveY; // Amount to move sprite by, each step. + bool _quick, _visible, _homing, _doCheck; + int16 _homingX, _homingY; // Homing x & y coords. + byte _speedX, _speedY; + bool _vanishIfStill; + bool _callEachStepFl; + byte _eachStepProc; + + AnimationType(Animation *anim); + + void init(byte spritenum, bool doCheck); + void reset(); + void draw(); + void turn(Direction whichway); + void appear(int16 wx, int16 wy, Direction wf); + void bounce(); + void walk(); + void walkTo(byte pednum); + void stopHoming(); + void setSpeed(int8 xx, int8 yy); + void stopWalk(); + void chatter(); + void remove(); + +private: + Animation *_anim; + + int16 _oldX[2], _oldY[2]; // Last xy coords. + Color _fgBubbleCol, _bgBubbleCol; // Foreground & background bubble colors. + + bool checkCollision(); + int8 getSign(int16 val); + void homeStep(); +}; + +class Animation { +public: + friend class AnimationType; + + static const byte kSpriteNumbMax = 5; // current max no. of sprites + + enum Proc { + kProcFollowAvvyY = 1, + kProcBackAndForth, + kProcFaceAvvy, + kProcArrow, + kProcSpludwick, // Unused + kProcGrabAvvy, + kProcGeida // Spludwick uses it as well for homing! TODO: Unify it with kProcSpludwick. + }; + + AnimationType *_sprites[kSpriteNumbMax]; + + Animation(AvalancheEngine *vm); + ~Animation(); + + void animLink(); + void resetAnims(); + void callSpecial(uint16 which); + void catacombMove(byte ped); + void stopWalking(); + void setMoveSpeed(byte t, Direction dir); + void appearPed(byte sprNum, byte pedNum); + bool inField(byte which); + bool nearDoor(); + void updateSpeed(); + void handleMoveKey(const Common::Event &event); + void hideInCupboard(); + + void setDirection(Direction dir); + void setOldDirection(Direction dir); + Direction getDirection(); + Direction getOldDirection(); + + void setAvvyClothes(int id); + int getAvvyClothes(); + + void resetVariables(); + void synchronize(Common::Serializer &sz); +private: + Direction _direction; // The direction Avvy is currently facing. + Direction _oldDirection; + static const int32 kCatacombMap[8][8]; + bool _arrowTriggered; // And has the arrow been triggered? + bool _mustExclaim; + byte _geidaSpin, _geidaTime; // For the making "Geida dizzy" joke. + uint16 _sayWhat; + + AvalancheEngine *_vm; + + byte checkFeet(int16 x1, int16 x2, int16 oy, int16 y, byte yl); + byte geidaPed(byte ped); + void dawnDelay(); + + void grabAvvy(byte tripnum); + void arrowProcs(byte tripnum); + + // Different movements for NPCs: + void followAvalotY(byte tripnum); + void backAndForth(byte tripnum); + void faceAvvy(byte tripnum); + + // Movements for Homing NPCs: Spludwick and Geida. + void spin(Direction dir, byte &tripnum); + void takeAStep(byte &tripnum); + void geidaProcs(byte tripnum); + + void drawSprites(); +}; + +} // End of namespace Avalanche. + +#endif // AVALANCHE_ANIMATION_H diff --git a/engines/avalanche/avalanche.cpp b/engines/avalanche/avalanche.cpp new file mode 100644 index 0000000000..4f3868768a --- /dev/null +++ b/engines/avalanche/avalanche.cpp @@ -0,0 +1,530 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on the original source code of Lord Avalot d'Argent version 1.3. + * Copyright (c) 1994-1995 Mike, Mark and Thomas Thurman. + */ + +#include "avalanche/avalanche.h" + +#include "common/random.h" +#include "common/savefile.h" +#include "graphics/thumbnail.h" + +namespace Avalanche { + +AvalancheEngine::AvalancheEngine(OSystem *syst, const AvalancheGameDescription *gd) : Engine(syst), _gameDescription(gd), _fxHidden(false), _interrogation(0) { + _system = syst; + _console = new AvalancheConsole(this); + + _rnd = new Common::RandomSource("avalanche"); + TimeDate time; + _system->getTimeAndDate(time); + _rnd->setSeed(time.tm_sec + time.tm_min + time.tm_hour); + + // Needed because of Lucerna::load_also() + for (int i = 0; i < 31; i++) { + for (int j = 0; j < 2; j++) + _also[i][j] = nullptr; + } + + _totalTime = 0; + _showDebugLines = false; + + memset(_fxPal, 0, 16 * 16 * 3); +} + +AvalancheEngine::~AvalancheEngine() { + delete _console; + delete _rnd; + + delete _graphics; + delete _parser; + + delete _clock; + delete _pingo; + delete _dialogs; + delete _background; + delete _sequence; + delete _timer; + delete _animation; + delete _menu; + delete _closing; + delete _sound; + + for (int i = 0; i < 31; i++) { + for (int j = 0; j < 2; j++) { + if (_also[i][j] != nullptr) { + delete _also[i][j]; + _also[i][j] = nullptr; + } + } + } +} + +Common::ErrorCode AvalancheEngine::initialize() { + _graphics = new GraphicManager(this); + _parser = new Parser(this); + + _clock = new Clock(this); + _pingo = new Pingo(this); + _dialogs = new Dialogs(this); + _background = new Background(this); + _sequence = new Sequence(this); + _timer = new Timer(this); + _animation = new Animation(this); + _menu = new Menu(this); + _closing = new Closing(this); + _sound = new SoundHandler(this); + + _graphics->init(); + _dialogs->init(); + init(); + _parser->init(); + + return Common::kNoError; +} + +GUI::Debugger *AvalancheEngine::getDebugger() { + return _console; +} + +Common::Platform AvalancheEngine::getPlatform() const { + return _platform; +} + +bool AvalancheEngine::hasFeature(EngineFeature f) const { + return (f == kSupportsSavingDuringRuntime) || (f == kSupportsLoadingDuringRuntime); +} + +const char *AvalancheEngine::getCopyrightString() const { + return "Copyright (c) 1994-1995 Mike, Mark and Thomas Thurman."; +} + +void AvalancheEngine::synchronize(Common::Serializer &sz) { + _animation->synchronize(sz); + _parser->synchronize(sz); + _sequence->synchronize(sz); + _background->synchronize(sz); + + sz.syncAsByte(_carryNum); + for (int i = 0; i < kObjectNum; i++) + sz.syncAsByte(_objects[i]); + sz.syncAsSint16LE(_dnascore); + sz.syncAsSint32LE(_money); + sz.syncAsByte(_room); + if (sz.isSaving()) + _saveNum++; + sz.syncAsByte(_saveNum); + sz.syncBytes(_roomCount, 100); + sz.syncAsByte(_wonNim); + sz.syncAsByte(_wineState); + sz.syncAsByte(_cwytalotGone); + sz.syncAsByte(_passwordNum); + sz.syncAsByte(_aylesIsAwake); + sz.syncAsByte(_drawbridgeOpen); + sz.syncAsByte(_avariciusTalk); + sz.syncAsByte(_rottenOnion); + sz.syncAsByte(_onionInVinegar); + sz.syncAsByte(_givenToSpludwick); + sz.syncAsByte(_brummieStairs); + sz.syncAsByte(_cardiffQuestionNum); + sz.syncAsByte(_passedCwytalotInHerts); + sz.syncAsByte(_avvyIsAwake); + sz.syncAsByte(_avvyInBed); + sz.syncAsByte(_userMovesAvvy); + sz.syncAsByte(_npcFacing); + sz.syncAsByte(_givenBadgeToIby); + sz.syncAsByte(_friarWillTieYouUp); + sz.syncAsByte(_tiedUp); + sz.syncAsByte(_boxContent); + sz.syncAsByte(_talkedToCrapulus); + sz.syncAsByte(_jacquesState); + sz.syncAsByte(_bellsAreRinging); + sz.syncAsByte(_standingOnDais); + sz.syncAsByte(_takenPen); + sz.syncAsByte(_arrowInTheDoor); + + if (sz.isSaving()) { + uint16 like2drinkSize = _favouriteDrink.size(); + sz.syncAsUint16LE(like2drinkSize); + for (uint16 i = 0; i < like2drinkSize; i++) { + char actChr = _favouriteDrink[i]; + sz.syncAsByte(actChr); + } + + uint16 favourite_songSize = _favouriteSong.size(); + sz.syncAsUint16LE(favourite_songSize); + for (uint16 i = 0; i < favourite_songSize; i++) { + char actChr = _favouriteSong[i]; + sz.syncAsByte(actChr); + } + + uint16 worst_place_on_earthSize = _worstPlaceOnEarth.size(); + sz.syncAsUint16LE(worst_place_on_earthSize); + for (uint16 i = 0; i < worst_place_on_earthSize; i++) { + char actChr = _worstPlaceOnEarth[i]; + sz.syncAsByte(actChr); + } + + uint16 spare_eveningSize = _spareEvening.size(); + sz.syncAsUint16LE(spare_eveningSize); + for (uint16 i = 0; i < spare_eveningSize; i++) { + char actChr = _spareEvening[i]; + sz.syncAsByte(actChr); + } + } else { + if (!_favouriteDrink.empty()) + _favouriteDrink.clear(); + uint16 like2drinkSize = 0; + char actChr = ' '; + sz.syncAsUint16LE(like2drinkSize); + for (uint16 i = 0; i < like2drinkSize; i++) { + sz.syncAsByte(actChr); + _favouriteDrink += actChr; + } + + if (!_favouriteSong.empty()) + _favouriteSong.clear(); + uint16 favourite_songSize = 0; + sz.syncAsUint16LE(favourite_songSize); + for (uint16 i = 0; i < favourite_songSize; i++) { + sz.syncAsByte(actChr); + _favouriteSong += actChr; + } + + if (!_worstPlaceOnEarth.empty()) + _worstPlaceOnEarth.clear(); + uint16 worst_place_on_earthSize = 0; + sz.syncAsUint16LE(worst_place_on_earthSize); + for (uint16 i = 0; i < worst_place_on_earthSize; i++) { + sz.syncAsByte(actChr); + _worstPlaceOnEarth += actChr; + } + + if (!_spareEvening.empty()) + _spareEvening.clear(); + uint16 spare_eveningSize = 0; + sz.syncAsUint16LE(spare_eveningSize); + for (uint16 i = 0; i < spare_eveningSize; i++) { + sz.syncAsByte(actChr); + _spareEvening += actChr; + } + } + + sz.syncAsSint32LE(_totalTime); + sz.syncAsByte(_jumpStatus); + sz.syncAsByte(_mushroomGrowing); + sz.syncAsByte(_spludwickAtHome); + sz.syncAsByte(_lastRoom); + sz.syncAsByte(_lastRoomNotMap); + sz.syncAsByte(_crapulusWillTell); + sz.syncAsByte(_enterCatacombsFromLustiesRoom); + sz.syncAsByte(_teetotal); + sz.syncAsByte(_malagauche); + sz.syncAsByte(_drinking); + sz.syncAsByte(_enteredLustiesRoomAsMonk); + sz.syncAsByte(_catacombX); + sz.syncAsByte(_catacombY); + sz.syncAsByte(_avvysInTheCupboard); + sz.syncAsByte(_geidaFollows); + sz.syncAsByte(_givenPotionToGeida); + sz.syncAsByte(_lustieIsAsleep); + sz.syncAsByte(_beenTiedUp); + sz.syncAsByte(_sittingInPub); + sz.syncAsByte(_spurgeTalkCount); + sz.syncAsByte(_metAvaroid); + sz.syncAsByte(_takenMushroom); + sz.syncAsByte(_givenPenToAyles); + sz.syncAsByte(_askedDogfoodAboutNim); + + for (int i = 0; i < 7; i++) { + sz.syncAsSint32LE(_timer->_times[i]._timeLeft); + sz.syncAsByte(_timer->_times[i]._action); + sz.syncAsByte(_timer->_times[i]._reason); + } + +} + +bool AvalancheEngine::canSaveGameStateCurrently() { // TODO: Refine these!!! + return (!_seeScroll && _alive); +} + +Common::Error AvalancheEngine::saveGameState(int slot, const Common::String &desc) { + return (saveGame(slot, desc) ? Common::kNoError : Common::kWritingFailed); +} + +bool AvalancheEngine::saveGame(const int16 slot, const Common::String &desc) { + Common::String fileName = getSaveFileName(slot); + Common::OutSaveFile *f = g_system->getSavefileManager()->openForSaving(fileName); + if (!f) { + warning("Can't create file '%s', game not saved.", fileName.c_str()); + return false; + } + + f->writeUint32LE(MKTAG('A', 'V', 'A', 'L')); + + // Write version. We can't restore from obsolete versions. + f->writeByte(kSavegameVersion); + + f->writeUint32LE(desc.size()); + f->write(desc.c_str(), desc.size()); + Graphics::saveThumbnail(*f); + + TimeDate t; + _system->getTimeAndDate(t); + f->writeSint16LE(t.tm_mday); + f->writeSint16LE(t.tm_mon); + f->writeSint16LE(t.tm_year); + + Common::Serializer sz(NULL, f); + synchronize(sz); + f->finalize(); + delete f; + + return true; +} + +Common::String AvalancheEngine::getSaveFileName(const int slot) { + return Common::String::format("%s.%03d", _targetName.c_str(), slot); +} + +bool AvalancheEngine::canLoadGameStateCurrently() { // TODO: Refine these!!! + return (!_seeScroll); +} + +Common::Error AvalancheEngine::loadGameState(int slot) { + return (loadGame(slot) ? Common::kNoError : Common::kReadingFailed); +} + +bool AvalancheEngine::loadGame(const int16 slot) { + Common::String fileName = getSaveFileName(slot); + Common::InSaveFile *f = g_system->getSavefileManager()->openForLoading(fileName); + if (!f) + return false; + + uint32 signature = f->readUint32LE(); + if (signature != MKTAG('A', 'V', 'A', 'L')) + return false; + + // Check version. We can't restore from obsolete versions. + byte saveVersion = f->readByte(); + if (saveVersion != kSavegameVersion) { + warning("Savegame of incompatible version!"); + delete f; + return false; + } + + // Read the description. + uint32 descSize = f->readUint32LE(); + Common::String description; + for (uint32 i = 0; i < descSize; i++) { + char actChar = f->readByte(); + description += actChar; + } + + description.toUppercase(); + Graphics::skipThumbnail(*f); + + // Read the time the game was saved. + TimeDate t; + t.tm_mday = f->readSint16LE(); + t.tm_mon = f->readSint16LE(); + t.tm_year = f->readSint16LE(); + + resetVariables(); + + Common::Serializer sz(f, NULL); + synchronize(sz); + delete f; + + _isLoaded = true; + _seeScroll = true; // This prevents display of the new sprites before the new picture is loaded. + + if (_holdTheDawn) { + _holdTheDawn = false; + fadeIn(); + } + + _background->release(); + minorRedraw(); + _menu->setup(); + setRoom(kPeopleAvalot, _room); + _alive = true; + refreshObjectList(); + _animation->updateSpeed(); + drawDirection(); + _animation->animLink(); + _background->update(); + + Common::String tmpStr = Common::String::format("%cLoaded: %c%s.ASG%c%c%c%s%c%csaved on %s.", + kControlItalic, kControlRoman, description.c_str(), kControlCenter, kControlNewLine, + kControlNewLine, _roomnName.c_str(), kControlNewLine, kControlNewLine, + expandDate(t.tm_mday, t.tm_mon, t.tm_year).c_str()); + _dialogs->displayText(tmpStr); + + AnimationType *avvy = _animation->_sprites[0]; + if (avvy->_quick && avvy->_visible) + _animation->setMoveSpeed(0, _animation->getDirection()); // We push Avvy in the right direction is he was moving. + + return true; +} + +Common::String AvalancheEngine::expandDate(int d, int m, int y) { + static const char months[12][10] = { + "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" + }; + + Common::String month = Common::String(months[m]); + Common::String day = intToStr(d); + + if (((1 <= d) && (d <= 9)) || ((21 <= d) && (d <= 31))) + switch (d % 10) { + case 1: + day += "st"; + break; + case 2: + day += "nd"; + break; + case 3: + day += "rd"; + break; + default: + day += "th"; + } + + return day + ' ' + month + ' ' + intToStr(y + 1900); +} + +void AvalancheEngine::updateEvents() { + Common::Event event; + + while (_eventMan->pollEvent(event)) { + switch (event.type) { + case Common::EVENT_LBUTTONDOWN: + _holdLeftMouse = true; // Used in checkclick() and Menu::menu_link(). + break; + case Common::EVENT_LBUTTONUP: + _holdLeftMouse = false; // Same as above. + break; + case Common::EVENT_KEYDOWN: + if ((event.kbd.keycode == Common::KEYCODE_d) && (event.kbd.flags & Common::KBD_CTRL)) { + // Attach to the debugger + _console->attach(); + _console->onFrame(); + } else + handleKeyDown(event); + break; + default: + break; + } + } +} + +bool AvalancheEngine::getEvent(Common::Event &event) { + return _eventMan->pollEvent(event); +} + +Common::Point AvalancheEngine::getMousePos() { + return _eventMan->getMousePos(); +} + +Common::Error AvalancheEngine::run() { + Common::ErrorCode err = initialize(); + if (err != Common::kNoError) + return err; + + do { + runAvalot(); + +#if 0 + switch (_storage._operation) { + case kRunShootemup: + run("seu.avx", kJsb, kBflight, kNormal); + break; + case kRunDosshell: + dosShell(); + break; + case kRunGhostroom: + run("g-room.avx", kJsb, kNoBflight, kNormal); + break; + case kRunGolden: + run("golden.avx", kJsb, kBflight, kMusical); + break; + } +#endif + + } while (!_letMeOut && !shouldQuit()); + + return Common::kNoError; +} + +#if 0 +void AvalancheEngine::run(Common::String what, bool withJsb, bool withBflight, Elm how) { + // Probably there'll be no need of this function, as all *.AVX-es will become classes. + warning("STUB: run(%s)", what.c_str()); +} + +Common::String AvalancheEngine::elmToStr(Elm how) { + switch (how) { + case kNormal: + case kMusical: + return Common::String("jsb"); + case kRegi: + return Common::String("REGI"); + case kElmpoyten: + return Common::String("ELMPOYTEN"); + // Useless, but silent a warning + default: + return Common::String(""); + } +} + +// Same as keypressed1(). +void AvalancheEngine::flushBuffer() { + warning("STUB: flushBuffer()"); +} + +void AvalancheEngine::dosShell() { + warning("STUB: dosShell()"); +} + +// Needed in dos_shell(). TODO: Remove later. +Common::String AvalancheEngine::commandCom() { + warning("STUB: commandCom()"); + return ("STUB: commandCom()"); +} + +// Needed for run_avalot()'s errors. TODO: Remove later. +void AvalancheEngine::explain(byte error) { + warning("STUB: explain()"); +} + +// Needed later. +void AvalancheEngine::quit() { + cursorOn(); +} + +#endif + +} // End of namespace Avalanche diff --git a/engines/avalanche/avalanche.h b/engines/avalanche/avalanche.h new file mode 100644 index 0000000000..cc9a34d82b --- /dev/null +++ b/engines/avalanche/avalanche.h @@ -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 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on the original source code of Lord Avalot d'Argent version 1.3. + * Copyright (c) 1994-1995 Mike, Mark and Thomas Thurman. + */ + +#ifndef AVALANCHE_AVALANCHE_H +#define AVALANCHE_AVALANCHE_H + +#include "avalanche/console.h" +#include "avalanche/graphics.h" +#include "avalanche/parser.h" +#include "avalanche/avalot.h" +#include "avalanche/pingo.h" +#include "avalanche/dialogs.h" +#include "avalanche/background.h" +#include "avalanche/sequence.h" +#include "avalanche/timer.h" +#include "avalanche/animation.h" +#include "avalanche/menu.h" +#include "avalanche/closing.h" +#include "avalanche/sound.h" + +#include "common/serializer.h" + +#include "engines/engine.h" +#include "engines/advancedDetector.h" + +#include "graphics/cursorman.h" + +namespace Common { +class RandomSource; +} + +namespace Avalanche { + +struct AvalancheGameDescription; + +static const int kSavegameVersion = 1; + +enum Pitch { + kPitchInvalid, + kPitchLower, + kPitchSame, + kPitchHigher +}; + +class AvalancheEngine : public Engine { +public: + byte _saveNum; // number of times this game has been saved + + Clock *_clock; + GraphicManager *_graphics; + Parser *_parser; + Pingo *_pingo; + Dialogs *_dialogs; + Background *_background; + Sequence *_sequence; + Timer *_timer; + Animation *_animation; + Menu *_menu; + Closing *_closing; + SoundHandler *_sound; + + OSystem *_system; + + AvalancheEngine(OSystem *syst, const AvalancheGameDescription *gd); + ~AvalancheEngine(); + + Common::ErrorCode initialize(); + GUI::Debugger *getDebugger(); + + Common::RandomSource *_rnd; + + const AvalancheGameDescription *_gameDescription; + uint32 getFeatures() const; + const char *getGameId() const; + Common::Platform getPlatform() const; + bool hasFeature(EngineFeature f) const; + const char *getCopyrightString() const; + + void synchronize(Common::Serializer &sz); + virtual bool canSaveGameStateCurrently(); + Common::Error saveGameState(int slot, const Common::String &desc); + bool saveGame(const int16 slot, const Common::String &desc); + Common::String getSaveFileName(const int slot); + virtual bool canLoadGameStateCurrently(); + Common::Error loadGameState(int slot); + bool loadGame(const int16 slot); + Common::String expandDate(int d, int m, int y); + + void updateEvents(); + bool getEvent(Common::Event &event); // A wrapper around _eventMan->pollEvent(), so we can use it in Scrolls::normscroll() for example. + Common::Point getMousePos(); + +protected: + // Engine APIs + Common::Error run(); + +private: + AvalancheConsole *_console; + Common::Platform _platform; + +#if 0 + struct { + byte _operation; + uint16 _skellern; + byte _contents[1000]; + } _storage; + + static const int16 kRunShootemup = 1, kRunDosshell = 2, kRunGhostroom = 3, kRunGolden = 4; + static const int16 kReset = 0; + + static const bool kJsb = true, kNoJsb = false, kBflight = true, kNoBflight = false; + + // From bootstrp: + enum Elm {kNormal, kMusical, kElmpoyten, kRegi}; + + Common::String _argsWithNoFilename; + byte _originalMode; + byte *_old1c; + Common::String _segofs; + int32 _soundcard, _speed, _baseaddr, _irq, _dma; + bool _zoomy; + + void run(Common::String what, bool withJsb, bool withBflight, Elm how); + void bFlightOn(); + void bFlightOff(); + Common::String elmToStr(Elm how); + bool keyPressed(); + void flushBuffer(); + void dosShell(); + void bFlight(); + Common::String commandCom(); + void explain(byte error); + void cursorOff(); + void cursorOn(); + void quit(); +#endif + +public: + // For Thinkabout: + static const bool kThing = true; + static const bool kPerson = false; + + static const char kSpludwicksOrder[3]; + + static const uint16 kNotes[12]; + static const TuneType kTune; + + bool _holdLeftMouse; + + // If this is greater than zero, the next line you type is stored in the DNA in a position dictated by the value. + // If a scroll comes up, or you leave the room, it's automatically set to zero. + byte _interrogation; + + // Former DNA structure + byte _carryNum; // How many objects you're carrying... + bool _objects[kObjectNum]; // ...and which ones they are. + int16 _dnascore; // your score, of course + int32 _money; // your current amount of dosh + Room _room; // your current room + bool _wonNim; // Have you *won* Nim? (That's harder.) + byte _wineState; // 0=good (Notts), 1=passable(Argent) ... 3=vinegar. + bool _cwytalotGone; // Has Cwytalot rushed off to Jerusalem yet? + byte _passwordNum; // Number of the passw for this game. + bool _aylesIsAwake; // pretty obvious! + byte _drawbridgeOpen; // Between 0 (shut) and 4 (open). + byte _avariciusTalk; // How much Avaricius has said to you. + bool _rottenOnion; // And has it rotted? + bool _onionInVinegar; // Is the onion in the vinegar? + byte _givenToSpludwick; // 0 = nothing given, 1 = onion... + byte _brummieStairs; // Progression through the stairs trick. + byte _cardiffQuestionNum; // Things you get asked in Cardiff. + bool _avvyIsAwake; // Well? Is Avvy awake? (Screen 1 only.) + bool _avvyInBed; // True if Avvy's in bed, but awake. + bool _userMovesAvvy; // If this is false, the user has no control over Avvy's movements. + byte _npcFacing; // If there's an NPC in the current room which turns it's head according to Avvy's movement (keep looking at him), this variable tells which way it's facing at the moment. + bool _givenBadgeToIby; // Have you given the badge to Iby yet? + bool _friarWillTieYouUp; // If you're going to get tied up. + bool _tiedUp; // You ARE tied up! + byte _boxContent; // 0 = money (sixpence), 254 = empty, any other number implies the contents of the box. + bool _talkedToCrapulus; // Pretty self-explanatory. + byte _jacquesState; // 0=asleep, 1=awake, 2=gets up, 3=gone. + bool _bellsAreRinging; // Is Jacques ringing the bells? + bool _standingOnDais; // In room 71, inside Cardiff Castle. + bool _takenPen; // Have you taken the pen (in Cardiff?) + bool _arrowInTheDoor; // Did the arrow hit the wall? + Common::String _favouriteDrink, _favouriteSong, _worstPlaceOnEarth, _spareEvening; // Personalisation str's + uint32 _totalTime; // Your total time playing this game, in ticks. + byte _jumpStatus; // Fixes how high you're jumping. + bool _mushroomGrowing; // Is the mushroom growing in 42? + bool _crapulusWillTell; // Will Crapulus tell you about Spludwick being away? + bool _enterCatacombsFromLustiesRoom; + bool _teetotal; // Are we touching any more drinks? + byte _malagauche; // Position of Malagauche. See Celer for more info. + char _drinking; // What's he getting you? + bool _enteredLustiesRoomAsMonk; + byte _catacombX, _catacombY; // XY coords in the catacombs. + bool _avvysInTheCupboard; // On screen 22. + bool _geidaFollows; // Is Geida following you? + bool _givenPotionToGeida; // Does Geida have the potion? + bool _lustieIsAsleep; // Is BDL asleep? + bool _beenTiedUp; // In r__Robins. + bool _sittingInPub; // Are you sitting down in the pub? + byte _spurgeTalkCount; // Count for talking to Spurge. + bool _metAvaroid; + bool _takenMushroom, _givenPenToAyles, _askedDogfoodAboutNim; + // End of former DNA Structure + + bool _showDebugLines; + byte _lineNum; // Number of lines. + LineType _lines[50]; // For Also. + bool _dropsOk; + bool _cheat; // CHECKME: Currently unused + bool _letMeOut; + byte _thinks; + bool _thinkThing; + bool _seeScroll; // TODO: maybe this means we're interacting with the toolbar / a scroll? + char _objectList[10]; + // Called .free() for them in ~Gyro(). + + byte _currentMouse; // current mouse-void + Common::String *_also[31][2]; + PedType _peds[15]; + MagicType _magics[15]; + MagicType _portals[7]; + FieldType _fields[30]; + byte _fieldNum; + Common::String _listen; + byte _cp, _ledStatus; + FontType _font; + bool _alive; + byte _subjectNum; // The same thing. + People _him, _her; + byte _it; + uint32 _roomTime; // Set to 0 when you enter a room, added to in every loop. + + bool _doingSpriteRun; // Only set to True if we're doing a sprite_run at this moment. This stops the trippancy system from moving any of the sprites. + bool _isLoaded; // Is it a loaded gamestate? + bool _soundFx; + + void callVerb(VerbCode id); + void loadRoom(byte num); + void thinkAbout(byte object, bool type); // Hey!!! Get it and put it!!! + void incScore(byte num); // Add on no. of points + void fxToggle(); + void refreshObjectList(); + void errorLed(); + void fadeOut(); + void fadeIn(); + void drawDirection(); // Draws the little icon at the left end of the text input field. + void gameOver(); + uint16 bearing(byte whichPed); // Returns the bearing from ped 'whichped' to Avvy, in degrees. + + // There are two kinds of redraw: Major and Minor. Minor is what happens when you load a game, etc. Major redraws EVERYTHING. + void minorRedraw(); + void majorRedraw(); + + void spriteRun(); + + Common::String intToStr(int32 num); + void newGame(); // This sets up the DNA for a completely new game. + bool getFlag(char x); + bool decreaseMoney(uint16 amount); // Called pennycheck in the original. + + Common::String getName(People whose); + Common::String getItem(byte which); // Called get_better in the original. + Common::String f5Does(); // This procedure determines what f5 does. + + void openDoor(Room whither, byte ped, byte magicnum); // Handles slidey-open doors. + void flipRoom(Room room, byte ped); + + void setRoom(People persId, Room roomId); + Room getRoom(People persId); +private: + static const int16 kMaxSprites = 2; // Current max no. of sprites. + static Room _whereIs[29]; + + // Will be used in dusk() and dawn(). + bool _fxHidden; + byte _fxPal[16][16][3]; + + bool _spludwickAtHome; // Is Spludwick at home? + bool _passedCwytalotInHerts; // Have you passed Cwytalot in Herts? + bool _holdTheDawn; // If this is true, calling Dawn will do nothing. It's used, for example, at the start, to stop Load from dawning. + byte _lastRoom; + byte _lastRoomNotMap; + byte _roomCount[100]; // Add one to each every time you enter a room + Common::String _mouseText; + Common::String _flags; + Common::String _roomnName; // Name of actual room + int8 _scoreToDisplay[3]; + + Common::String readAlsoStringFromFile(Common::File &file); + void runAvalot(); + void init(); + void setup(); + void scram(Common::String &str); + void unScramble(); + void handleKeyDown(Common::Event &event); // To replace Basher::keyboard_link() and Basher::typein(). + void enterNewTown(); + void findPeople(byte room); + void putGeidaAt(byte whichPed, byte ped); + void guideAvvy(Common::Point cursorPos); + void enterRoom(Room room, byte ped); + void exitRoom(byte x); + void drawToolbar(); + void drawScore(); + void useCompass(const Common::Point &cursorPos); // Click on the compass on the toolbar to control Avvy's movement. + void checkClick(); + void fixFlashers(); + void loadAlso(byte num); + void resetVariables(); +}; + +} // End of namespace Avalanche + +#endif // AVALANCHE_AVALANCHE_H diff --git a/engines/avalanche/avalot.cpp b/engines/avalanche/avalot.cpp new file mode 100644 index 0000000000..8ef41a2c93 --- /dev/null +++ b/engines/avalanche/avalot.cpp @@ -0,0 +1,1744 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on the original source code of Lord Avalot d'Argent version 1.3. + * Copyright (c) 1994-1995 Mike: Mark and Thomas Thurman. + */ + +/* AVALOT The kernel of the program. */ + +#include "avalanche/avalanche.h" + +#include "common/random.h" +#include "common/system.h" +#include "common/config-manager.h" +#include "graphics/palette.h" + +namespace Avalanche { + +// vv Stairs trap. + +/* Explanation: $NSEW. + Nibble N: North. + 0 = no connection, + 2 = (left,) middle(, right) door with left-hand handle, + 5 = (left,) middle(, right) door with right-hand handle, + 7 = arch, + 8 = arch and 1 north of it, + 9 = arch and 2 north of it, + D = no connection + WINDOW, + E = no connection + TORCH, + F = recessed door (to Geida's room.) + + Nibble S: South. + 0 = no connection, + 1,2,3 = left, middle, right door. + + Nibble E: East. + 0 = no connection (wall), + 1 = no connection (wall + window), + 2 = wall with door, + 3 = wall with door and window, + 6 = wall with candles, + 7 = wall with door and candles, + F = straight-through corridor. + + Nibble W: West. + 0 = no connection (wall), + 1 = no connection (wall + shield), + 2 = wall with door, + 3 = wall with door and shield, + 4 = no connection (window), + 5 = wall with door and window, + 6 = wall with candles, + 7 = wall with door and candles, + F = straight-through corridor. */ + +const char AvalancheEngine::kSpludwicksOrder[3] = {kObjectOnion, kObjectInk, kObjectMushroom}; +const uint16 AvalancheEngine::kNotes[12] = {196, 220, 247, 262, 294, 330, 350, 392, 440, 494, 523, 587}; +const TuneType AvalancheEngine::kTune = { + kPitchHigher, kPitchHigher, kPitchLower, kPitchSame, kPitchHigher, kPitchHigher, kPitchLower, kPitchHigher, kPitchHigher, kPitchHigher, + kPitchLower, kPitchHigher, kPitchHigher, kPitchSame, kPitchHigher, kPitchLower, kPitchLower, kPitchLower, kPitchLower, kPitchHigher, + kPitchHigher, kPitchLower, kPitchLower, kPitchLower, kPitchLower, kPitchSame, kPitchLower, kPitchHigher, kPitchSame, kPitchLower, kPitchHigher +}; + +Room AvalancheEngine::_whereIs[29] = { + // The Lads + kRoomYours, // Avvy + kRoomSpludwicks, // Spludwick + kRoomOutsideYours, // Crapulus + kRoomDucks, // Duck - r__DucksRoom's not defined yet. + kRoomArgentPub, // Malagauche + kRoomRobins, // Friar Tuck. + kRoomDummy, // Robin Hood - can't meet him at the start. + kRoomBrummieRoad, // Cwytalot + kRoomLustiesRoom, // Baron du Lustie. + kRoomOutsideCardiffCastle, // The Duke of Cardiff. + kRoomArgentPub, // Dogfood + kRoomOutsideDucks, // Trader + kRoomArgentPub, // Ibythneth + kRoomAylesOffice, // Ayles + kRoomNottsPub, // Port + kRoomNottsPub, // Spurge + kRoomMusicRoom, // Jacques + kRoomNowhere, + kRoomNowhere, + kRoomNowhere, + kRoomNowhere, + kRoomNowhere, + kRoomNowhere, + kRoomNowhere, + kRoomNowhere, + // The Lasses + kRoomYours, // Arkata + kRoomGeidas, // Geida + kRoomDummy, // nobody allocated here! + kRoomWiseWomans // The Wise Woman. +}; + +Clock::Clock(AvalancheEngine *vm) { + _vm = vm; + _oldHour = _oldHourAngle = _oldMinute = 17717; +} + +void Clock::update() { // TODO: Move variables from Gyro to here (or at least somewhere nearby), rename them. + TimeDate t; + _vm->_system->getTimeAndDate(t); + _hour = t.tm_hour; + _minute = t.tm_min; + _second = t.tm_sec; + + _hourAngle = (_hour % 12) * 30 + _minute / 2; + + if (_oldHour != _hour) { + plotHands(); + chime(); + } + + if (_oldMinute != _minute) + plotHands(); + + if ((_hour == 0) && (_oldHour != 0) && (_oldHour != 17717)) { + Common::String tmpStr = Common::String::format("Good morning!%c%cYes, it's just past " \ + "midnight. Are you having an all-night Avvy session? Glad you like the game that much!", + kControlNewLine, kControlNewLine); + _vm->_dialogs->displayText(tmpStr); + } + _oldHour = _hour; + _oldHourAngle = _hourAngle; + _oldMinute = _minute; +} + +Common::Point Clock::calcHand(uint16 angle, uint16 length, Color color) { + if (angle > 900) { + return(Common::Point(177, 177)); + } + + return(_vm->_graphics->drawScreenArc(kCenterX, kCenterY, 449 - angle, 450 - angle, length, color)); +} + +void Clock::drawHand(const Common::Point &endPoint, Color color) { + if (endPoint.x == 177) + return; + + _vm->_graphics->drawScreenLine(kCenterX, kCenterY, endPoint.x, endPoint.y, color); +} + +void Clock::plotHands() { + _clockHandHour = calcHand(_oldHourAngle, 14, kColorYellow); + _clockHandMinute = calcHand(_oldMinute * 6, 17, kColorYellow); + drawHand(_clockHandHour, kColorBrown); + drawHand(_clockHandMinute, kColorBrown); + + _clockHandHour = calcHand(_hourAngle, 14, kColorBrown); + _clockHandMinute = calcHand(_minute * 6, 17, kColorBrown); + drawHand(_clockHandHour, kColorYellow); + drawHand(_clockHandMinute, kColorYellow); +} + +void Clock::chime() { + if ((_oldHour == 17717) || (!_vm->_soundFx)) // Too high - must be first time around + return; + + byte hour = _hour % 12; + if (hour == 0) + hour = 12; + + _vm->_graphics->loadMouse(kCurWait); + + for (int i = 1; i <= hour; i++) { + for (int j = 1; j <= 3; j++) + _vm->_sound->playNote((i % 3) * 64 + 140 - j * 30, 50 - j * 12); + if (i != hour) + _vm->_system->delayMillis(100); + } +} + + +void AvalancheEngine::handleKeyDown(Common::Event &event) { + _sound->click(); + + if ((Common::KEYCODE_F1 <= event.kbd.keycode) && (event.kbd.keycode <= Common::KEYCODE_F15)) + _parser->handleFunctionKey(event); + else if ((32 <= event.kbd.ascii) && (event.kbd.ascii <= 128) && (event.kbd.ascii != 47)) + _parser->handleInputText(event); + else + switch (event.kbd.keycode) { // We can control Avvy with the numpad as well. + case Common::KEYCODE_KP8: + event.kbd.keycode = Common::KEYCODE_UP; + break; + case Common::KEYCODE_KP2: + event.kbd.keycode = Common::KEYCODE_DOWN; + break; + case Common::KEYCODE_KP6: + event.kbd.keycode = Common::KEYCODE_RIGHT; + break; + case Common::KEYCODE_KP4: + event.kbd.keycode = Common::KEYCODE_LEFT; + break; + case Common::KEYCODE_KP9: + event.kbd.keycode = Common::KEYCODE_PAGEUP; + break; + case Common::KEYCODE_KP3: + event.kbd.keycode = Common::KEYCODE_PAGEDOWN; + break; + case Common::KEYCODE_KP7: + event.kbd.keycode = Common::KEYCODE_HOME; + break; + case Common::KEYCODE_KP1: + event.kbd.keycode = Common::KEYCODE_END; + break; + default: + break; + } + + switch (event.kbd.keycode) { + case Common::KEYCODE_UP: + case Common::KEYCODE_DOWN: + case Common::KEYCODE_RIGHT: + case Common::KEYCODE_LEFT: + case Common::KEYCODE_PAGEUP: + case Common::KEYCODE_PAGEDOWN: + case Common::KEYCODE_HOME: + case Common::KEYCODE_END: + case Common::KEYCODE_KP5: + if (_alive && _avvyIsAwake) { + _animation->handleMoveKey(event); // Fallthroughs are intended. + drawDirection(); + return; + } + case Common::KEYCODE_BACKSPACE: + _parser->handleBackspace(); + break; + case Common::KEYCODE_RETURN: + _parser->handleReturn(); + break; + default: + break; + } + + drawDirection(); +} + +void AvalancheEngine::setup() { + init(); + + _dialogs->reset(); + fadeOut(); + _graphics->loadDigits(); + + _parser->_inputTextPos = 0; + _parser->_quote = true; + + _animation->resetAnims(); + + drawToolbar(); + _dialogs->setReadyLight(2); + + fadeIn(); + _parser->_cursorState = false; + _parser->cursorOn(); + _animation->_sprites[0]->_speedX = kWalk; + _animation->updateSpeed(); + + _menu->init(); + + int16 loadSlot = ConfMan.instance().getInt("save_slot"); + if (loadSlot >= 0) { + _thinks = 2; // You always have money. + thinkAbout(kObjectMoney, kThing); + + loadGame(loadSlot); + } else { + _isLoaded = false; // Set to true in _vm->loadGame(). + newGame(); + + _soundFx = !_soundFx; + fxToggle(); + thinkAbout(kObjectMoney, kThing); + + _dialogs->displayScrollChain('q', 83); // Info on the game, etc. + } +} + +void AvalancheEngine::runAvalot() { + setup(); + + do { + uint32 beginLoop = _system->getMillis(); + + updateEvents(); // The event handler. + + _clock->update(); + _menu->update(); + _background->update(); + _animation->animLink(); + checkClick(); + _timer->updateTimer(); + + _graphics->drawDebugLines(); + _graphics->refreshScreen(); + + uint32 delay = _system->getMillis() - beginLoop; + if (delay <= 55) + _system->delayMillis(55 - delay); // Replaces slowdown(); 55 comes from 18.2 Hz (B Flight). + } while (!_letMeOut && !shouldQuit()); + + warning("STUB: run()"); + + _closing->exitGame(); +} + +void AvalancheEngine::init() { + for (int i = 0; i < 31; i++) { + for (int j = 0; j < 2; j++) + _also[i][j] = nullptr; + } + +#if 0 + if (_vm->_enhanced->atbios) + atkey = "f1"; + else + atkey = "alt-"; +#endif + + _letMeOut = false; + _currentMouse = 177; + _dropsOk = true; + _mouseText = ""; + _cheat = false; + _cp = 0; + _ledStatus = 177; + for (int i = 0; i < 3; i++) + _scoreToDisplay[i] = -1; // Impossible digits. + _holdTheDawn = false; + + _graphics->loadMouse(kCurWait); + CursorMan.showMouse(true); +} + +/** + * Call a given Verb + * @remarks Originally called 'callverb' + */ +void AvalancheEngine::callVerb(VerbCode id) { + if (id == _parser->kPardon) { + Common::String tmpStr = Common::String::format("The f5 key lets you do a particular action in certain " \ + "situations. However, at the moment there is nothing assigned to it. You may press alt-A to see " \ + "what the current setting of this key is."); + _dialogs->displayText(tmpStr); + } else + _parser->doVerb(id); +} + +/** + * Check is it's possible to give something to Spludwick + * @remarks Originally called 'nextstring' + */ +Common::String AvalancheEngine::readAlsoStringFromFile(Common::File &file) { + Common::String str; + byte length = file.readByte(); + for (int i = 0; i < length; i++) + str += file.readByte(); + return str; +} + +void AvalancheEngine::scram(Common::String &str) { + for (uint i = 0; i < str.size(); i++) + str.setChar(str[i] ^ 177, i); +} + +void AvalancheEngine::unScramble() { + for (int i = 0; i < 31; i++) { + for (int j = 0; j < 2; j++) { + if (_also[i][j] != nullptr) + scram(*_also[i][j]); + } + } + scram(_listen); + scram(_flags); +} + +void AvalancheEngine::loadAlso(byte num) { + for (int i = 0; i < 31; i++) { + for (int j = 0; j < 2; j++) { + if (_also[i][j] != nullptr) { + delete _also[i][j]; + _also[i][j] = nullptr; + } + } + } + Common::String filename; + filename = Common::String::format("also%d.avd", num); + Common::File file; + if (!file.open(filename)) + error("AVALANCHE: File not found: %s", filename.c_str()); + + file.seek(128); + + byte alsoNum = file.readByte(); + Common::String tmpStr; + for (int i = 0; i <= alsoNum; i++) { + for (int j = 0; j < 2; j++) { + _also[i][j] = new Common::String; + *_also[i][j] = readAlsoStringFromFile(file); + } + tmpStr = Common::String::format("\x9D%s\x9D", _also[i][0]->c_str()); + *_also[i][0] = tmpStr; + } + + memset(_lines, 0xFF, sizeof(_lines)); + + _lineNum = file.readByte(); + for (int i = 0; i < _lineNum; i++) { + LineType *curLine = &_lines[i]; + curLine->_x1 = file.readSint16LE(); + curLine->_y1 = file.readSint16LE(); + curLine->_x2 = file.readSint16LE(); + curLine->_y2 = file.readSint16LE(); + curLine->_color = (Color)file.readByte(); + } + + memset(_peds, 177, sizeof(_peds)); + byte pedNum = file.readByte(); + for (int i = 0; i < pedNum; i++) { + PedType *curPed = &_peds[i]; + curPed->_x = file.readSint16LE(); + curPed->_y = file.readSint16LE(); + curPed->_direction = (Direction)file.readByte(); + } + + _fieldNum = file.readByte(); + for (int i = 0; i < _fieldNum; i++) { + FieldType *curField = &_fields[i]; + curField->_x1 = file.readSint16LE(); + curField->_y1 = file.readSint16LE(); + curField->_x2 = file.readSint16LE(); + curField->_y2 = file.readSint16LE(); + } + + for (int i = 0; i < 15; i++) { + MagicType *magic = &_magics[i]; + magic->_operation = file.readByte(); + magic->_data = file.readUint16LE(); + } + + for (int i = 0; i < 7; i++) { + MagicType *portal = &_portals[i]; + portal->_operation = file.readByte(); + portal->_data = file.readUint16LE(); + } + + _flags.clear(); + for (int i = 0; i < 26; i++) + _flags += file.readByte(); + + int16 size = file.readByte(); + _listen.clear(); + for (int i = 0; i < size; i++) + _listen += file.readByte(); + + _graphics->clearAlso(); + + CursorMan.showMouse(false); + for (int i = 0; i < _lineNum; i++) { + // We had to check if the lines are within the borders of the screen. + if ((_lines[i]._x1 >= 0) && (_lines[i]._x1 < kScreenWidth) && (_lines[i]._y1 >= 0) && (_lines[i]._y1 < kScreenHeight) + && (_lines[i]._x2 >= 0) && (_lines[i]._x2 < kScreenWidth) && (_lines[i]._y2 >= 0) && (_lines[i]._y2 < kScreenHeight)) + _graphics->setAlsoLine(_lines[i]._x1, _lines[i]._y1, _lines[i]._x2, _lines[i]._y2, _lines[i]._color); + } + CursorMan.showMouse(true); + + file.close(); + + unScramble(); + for (int i = 0; i <= alsoNum; i++) { + tmpStr = Common::String::format(",%s,", _also[i][0]->c_str()); + *_also[i][0] = tmpStr; + } +} + +void AvalancheEngine::loadRoom(byte num) { + CursorMan.showMouse(false); + + Common::String filename = Common::String::format("place%d.avd", num); + Common::File file; + if (!file.open(filename)) + error("AVALANCHE: File not found: %s", filename.c_str()); + + file.seek(146); + if (!_roomnName.empty()) + _roomnName.clear(); + for (int i = 0; i < 30; i++) { + char actChar = file.readByte(); + if ((32 <= actChar) && (actChar <= 126)) + _roomnName += actChar; + } + // Compression method byte follows this... + + file.seek(177); + + _graphics->loadBackground(file); + _graphics->refreshBackground(); + + file.close(); + + loadAlso(num); + _background->load(num); + CursorMan.showMouse(true); +} + +void AvalancheEngine::findPeople(byte room) { + for (int i = 1; i < 29; i++) { + if (_whereIs[i] == room) { + if (i < 25) + _him = (People)(150 + i); + else + _her = (People)(150 + i); + } + } +} + +void AvalancheEngine::exitRoom(byte x) { + _sound->stopSound(); + _background->release(); + _seeScroll = true; // This stops the trippancy system working over the length of this procedure. + + switch (x) { + case kRoomSpludwicks: + _timer->loseTimer(Timer::kReasonAvariciusTalks); + _avariciusTalk = 0; + // He doesn't HAVE to be talking for this to work. It just deletes it IF it exists. + break; + case kRoomBridge: + if (_drawbridgeOpen > 0) { + _drawbridgeOpen = 4; // Fully open. + _timer->loseTimer(Timer::kReasonDrawbridgeFalls); + } + break; + case kRoomOutsideCardiffCastle: + _timer->loseTimer(Timer::kReasonCardiffsurvey); + break; + case kRoomRobins: + _timer->loseTimer(Timer::kReasonGettingTiedUp); + break; + } + + _interrogation = 0; // Leaving the room cancels all the questions automatically. + _seeScroll = false; // Now it can work again! + + _lastRoom = _room; + if (_room != kRoomMap) + _lastRoomNotMap = _room; +} + + +/** + * Only when entering a NEW town! Not returning to the last one, + * but choosing another from the map. + * @remarks Originally called 'new_town' + */ +void AvalancheEngine::enterNewTown() { + _menu->setup(); + + switch (_room) { + case kRoomOutsideNottsPub: // Entry into Nottingham. + if ((_roomCount[kRoomRobins] > 0) && (_beenTiedUp) && (!_takenMushroom)) + _mushroomGrowing = true; + break; + case kRoomWiseWomans: // Entry into Argent. + if (_talkedToCrapulus && (!_lustieIsAsleep)) { + _spludwickAtHome = !((_roomCount[kRoomWiseWomans] % 3) == 1); + _crapulusWillTell = !_spludwickAtHome; + } else { + _spludwickAtHome = true; + _crapulusWillTell = false; + } + if (_boxContent == kObjectWine) + _wineState = 3; // Vinegar + break; + default: + break; + } + + if ((_room != kRoomOutsideDucks) && (_objects[kObjectOnion - 1]) && !(_onionInVinegar)) + _rottenOnion = true; // You're holding the onion +} + +void AvalancheEngine::putGeidaAt(byte whichPed, byte ped) { + if (ped == 0) + return; + AnimationType *spr1 = _animation->_sprites[1]; + + spr1->init(5, false); // load Geida + _animation->appearPed(1, whichPed); + spr1->_callEachStepFl = true; + spr1->_eachStepProc = Animation::kProcGeida; +} + +void AvalancheEngine::enterRoom(Room roomId, byte ped) { + _seeScroll = true; // This stops the trippancy system working over the length of this procedure. + + findPeople(roomId); + _room = roomId; + if (ped != 0) + _roomCount[roomId]++; + + loadRoom(roomId); + + if ((_roomCount[roomId] == 0) && (!getFlag('S'))) + incScore(1); + + _whereIs[kPeopleAvalot - 150] = _room; + + if (_geidaFollows) + _whereIs[kPeopleGeida - 150] = roomId; + + _roomTime = 0; + + + if ((_lastRoom == kRoomMap) && (_lastRoomNotMap != _room)) + enterNewTown(); + + switch (roomId) { + case kRoomYours: + if (_avvyInBed) { + _background->draw(-1, -1, 2); + _graphics->refreshBackground(); + _timer->addTimer(100, Timer::kProcArkataShouts, Timer::kReasonArkataShouts); + } + break; + + case kRoomOutsideYours: + if (ped > 0) { + AnimationType *spr1 = _animation->_sprites[1]; + if (!_talkedToCrapulus) { + _whereIs[kPeopleCrapulus - 150] = kRoomOutsideYours; + spr1->init(8, false); // load Crapulus + + if (_roomCount[kRoomOutsideYours] == 1) { + _animation->appearPed(1, 3); // Start on the right-hand side of the screen. + spr1->walkTo(4); // Walks up to greet you. + } else { + _animation->appearPed(1, 4); // Starts where he was before. + spr1->_facingDir = kDirLeft; + } + + spr1->_callEachStepFl = true; + spr1->_eachStepProc = Animation::kProcFaceAvvy; // He always faces Avvy. + + } else + _whereIs[kPeopleCrapulus - 150] = kRoomNowhere; + + if (_crapulusWillTell) { + spr1->init(8, false); + _animation->appearPed(1, 1); + spr1->walkTo(3); + _timer->addTimer(20, Timer::kProcCrapulusSpludOut, Timer::kReasonCrapulusSaysSpludwickOut); + _crapulusWillTell = false; + } + } + break; + + case kRoomOutsideSpludwicks: + if ((_roomCount[kRoomOutsideSpludwicks] == 1) && (ped == 1)) { + _timer->addTimer(20, Timer::kProcBang, Timer::kReasonExplosion); + _spludwickAtHome = true; + } + break; + + case kRoomSpludwicks: + if (_spludwickAtHome) { + AnimationType *spr1 = _animation->_sprites[1]; + if (ped > 0) { + spr1->init(2, false); // load Spludwick + _animation->appearPed(1, 1); + _whereIs[kPeopleSpludwick - 150] = kRoomSpludwicks; + } + + spr1->_callEachStepFl = true; + spr1->_eachStepProc = Animation::kProcGeida; + } else + _whereIs[kPeopleSpludwick - 150] = kRoomNowhere; + break; + + case kRoomBrummieRoad: + if (_geidaFollows) + putGeidaAt(4, ped); + if (_cwytalotGone) { + _magics[kColorLightred - 1]._operation = kMagicNothing; + _whereIs[kPeopleCwytalot - 150] = kRoomNowhere; + } else if (ped > 0) { + AnimationType *spr1 = _animation->_sprites[1]; + spr1->init(4, false); // 4 = Cwytalot + spr1->_callEachStepFl = true; + spr1->_eachStepProc = Animation::kProcFollowAvvyY; + _whereIs[kPeopleCwytalot - 150] = kRoomBrummieRoad; + + if (_roomCount[kRoomBrummieRoad] == 1) { // First time here... + _animation->appearPed(1, 1); // He appears on the right of the screen... + spr1->walkTo(3); // ...and he walks up... + } else { + // You've been here before. + _animation->appearPed(1, 3); // He's standing in your way straight away... + spr1->_facingDir = kDirLeft; + } + } + break; + + case kRoomArgentRoad: + if ((_cwytalotGone) && (!_passedCwytalotInHerts) && (ped == 2) && (_roomCount[kRoomArgentRoad] > 3)) { + AnimationType *spr1 = _animation->_sprites[1]; + spr1->init(4, false); // 4 = Cwytalot again + _animation->appearPed(1, 0); + spr1->walkTo(1); + spr1->_vanishIfStill = true; + _passedCwytalotInHerts = true; + // whereis[#157] = r__Nowhere; // can we fit this in? + _timer->addTimer(20, Timer::kProcCwytalotInHerts, Timer::kReasonCwytalotInHerts); + } + break; + + case kRoomBridge: + if (_drawbridgeOpen == 4) { // open + _background->draw(-1, -1, 2); // Position of drawbridge + _graphics->refreshBackground(); + _magics[kColorGreen - 1]._operation = kMagicNothing; // You may enter the drawbridge. + } + if (_geidaFollows) + putGeidaAt(ped + 2, ped); // load Geida + break; + + case kRoomRobins: + if ((ped > 0) && (!_beenTiedUp)) { + // A welcome party... or maybe not... + AnimationType *spr1 = _animation->_sprites[1]; + spr1->init(6, false); + _animation->appearPed(1, 1); + spr1->walkTo(2); + _timer->addTimer(36, Timer::kProcGetTiedUp, Timer::kReasonGettingTiedUp); + } + + if (_beenTiedUp) { + _whereIs[kPeopleRobinHood - 150] = kRoomNowhere; + _whereIs[kPeopleFriarTuck - 150] = kRoomNowhere; + } + + if (_tiedUp) + _background->draw(-1, -1, 1); + + if (!_mushroomGrowing) + _background->draw(-1, -1, 2); + _graphics->refreshBackground(); + break; + + case kRoomOutsideCardiffCastle: + if (ped > 0) { + AnimationType *spr1 = _animation->_sprites[1]; + switch (_cardiffQuestionNum) { + case 0 : // You've answered NONE of his questions. + spr1->init(9, false); + _animation->appearPed(1, 1); + spr1->walkTo(2); + _timer->addTimer(47, Timer::kProcCardiffSurvey, Timer::kReasonCardiffsurvey); + break; + case 5 : + _magics[1]._operation = kMagicNothing; + break; // You've answered ALL his questions. => nothing happens. + default: // You've answered SOME of his questions. + spr1->init(9, false); + _animation->appearPed(1, 2); + spr1->_facingDir = kDirRight; + _timer->addTimer(3, Timer::kProcCardiffReturn, Timer::kReasonCardiffsurvey); + } + } + + if (_cardiffQuestionNum < 5) + _interrogation = _cardiffQuestionNum; + else + _interrogation = 0; + break; + + case kRoomMap: + // You're entering the map. + fadeIn(); + if (ped > 0) + _graphics->zoomOut(_peds[ped - 1]._x, _peds[ped - 1]._y); + + if ((_objects[kObjectWine - 1]) && (_wineState != 3)) { + _dialogs->displayScrollChain('q', 9); // Don't want to waste the wine! + _objects[kObjectWine - 1] = false; + refreshObjectList(); + } + + _dialogs->displayScrollChain('q', 69); + break; + + case kRoomCatacombs: + if ((ped == 0) || (ped == 3) || (ped == 5) || (ped == 6)) { + + switch (ped) { + case 3: // Enter from oubliette + _catacombX = 8; + _catacombY = 4; + break; + case 5: // Enter from du Lustie's + _catacombX = 8; + _catacombY = 7; + break; + case 6: // Enter from Geida's + _catacombX = 4; + _catacombY = 1; + break; + } + + _enterCatacombsFromLustiesRoom = true; + _animation->catacombMove(ped); + _enterCatacombsFromLustiesRoom = false; + } + break; + + case kRoomArgentPub: + if (_wonNim) + _background->draw(-1, -1, 0); // No lute by the settle. + _malagauche = 0; // Ready to boot Malagauche + if (_givenBadgeToIby) { + _background->draw(-1, -1, 7); + _background->draw(-1, -1, 8); + } + _graphics->refreshBackground(); + break; + + case kRoomLustiesRoom: + _npcFacing = 1; // du Lustie. + if (_animation->getAvvyClothes() == 0) // Avvy in his normal clothes + _timer->addTimer(3, Timer::kProcCallsGuards, Timer::kReasonDuLustieTalks); + else if (!_enteredLustiesRoomAsMonk) // already + // Presumably, Avvy dressed as a monk. + _timer->addTimer(3, Timer::kProcGreetsMonk, Timer::kReasonDuLustieTalks); + + if (_geidaFollows) { + putGeidaAt(4, ped); + if (_lustieIsAsleep) { + _background->draw(-1, -1, 4); + _graphics->refreshBackground(); + } + } + break; + + case kRoomMusicRoom: + if (_jacquesState > 0) { + _jacquesState = 5; + _background->draw(-1, -1, 1); + _graphics->refreshBackground(); + _background->draw(-1, -1, 3); + _magics[kColorBrown - 1]._operation = kMagicNothing; + _whereIs[kPeopleJacques - 150] = kRoomNowhere; + } + if (ped != 0) { + _background->draw(-1, -1, 5); + _graphics->refreshBackground(); + _sequence->startMusicRoomSeq(); + } + break; + + case kRoomOutsideNottsPub: + if (ped == 2) { + _background->draw(-1, -1, 2); + _graphics->refreshBackground(); + _sequence->startDuckSeq(); + } + break; + + case kRoomOutsideArgentPub: + if (ped == 2) { + _background->draw(-1, -1, 5); + _graphics->refreshBackground(); + _sequence->startMusicRoomSeq(); + } + break; + + case kRoomWiseWomans: { + AnimationType *spr1 = _animation->_sprites[1]; + spr1->init(11, false); + if ((_roomCount[kRoomWiseWomans] == 1) && (ped > 0)) { + _animation->appearPed(1, 1); // Start on the right-hand side of the screen. + spr1->walkTo(3); // Walks up to greet you. + } else { + _animation->appearPed(1, 3); // Starts where she was before. + spr1->_facingDir = kDirLeft; + } + + spr1->_callEachStepFl = true; + spr1->_eachStepProc = Animation::kProcFaceAvvy; // She always faces Avvy. + } + break; + + case kRoomInsideCardiffCastle: + if (ped > 0) { + _animation->_sprites[1]->init(10, false); // Define the dart. + _background->draw(-1, -1, 0); + _graphics->refreshBackground(); + _sequence->startCardiffSeq2(); + } else { + _background->draw(-1, -1, 0); + if (_arrowInTheDoor) + _background->draw(-1, -1, 2); + else + _background->draw(-1, -1, 1); + _graphics->refreshBackground(); + } + break; + + case kRoomAvvysGarden: + if (ped == 1) { + _background->draw(-1, -1, 1); + _graphics->refreshBackground(); + _sequence->startGardenSeq(); + } + break; + + case kRoomEntranceHall: + case kRoomInsideAbbey: + case kRoomYourHall: + if (ped == 2) { +#if 0 + // It was the original: + _celer->show_one(-1, -1, 2); + _sequence->first_show(1); + _sequence->then_show(3); + _sequence->start_to_close(); +#endif + + _background->draw(-1, -1, 1); + _graphics->refreshBackground(); + _sequence->startGardenSeq(); + } + break; + + case kRoomAylesOffice: + if (_aylesIsAwake) + _background->draw(-1, -1, 1); + _graphics->refreshBackground(); + break; // Ayles awake. + + case kRoomGeidas: + putGeidaAt(1, ped); + break; // load Geida + + case kRoomEastHall: + case kRoomWestHall: + if (_geidaFollows) + putGeidaAt(ped + 1, ped); + break; + + case kRoomLusties: + if (_geidaFollows) + putGeidaAt(ped + 5, ped); + break; + + case kRoomNottsPub: + if (_sittingInPub) + _background->draw(-1, -1, 2); + _npcFacing = 1; // Port. + break; + + case kRoomOutsideDucks: + if (ped == 2) { + // Shut the door + _background->draw(-1, -1, 2); + _graphics->refreshBackground(); + _sequence->startDuckSeq(); + } + break; + + case kRoomDucks: + _npcFacing = 1; // Duck. + break; + + default: + break; + } + + _seeScroll = false; // Now it can work again! + _isLoaded = false; +} + +void AvalancheEngine::thinkAbout(byte object, bool type) { + _thinks = object; + object--; + + Common::String filename; + if (type == kThing) { + filename = "thinks.avd"; + } else { // kPerson + filename = "folk.avd"; + + object -= 149; + if (object >= 25) + object -= 8; + if (object == 20) + object--; // Last time... + } + + _graphics->loadMouse(kCurWait); + CursorMan.showMouse(false); + _graphics->drawThinkPic(filename, object); + CursorMan.showMouse(true); + + _thinkThing = type; +} + +void AvalancheEngine::drawToolbar() { + _graphics->drawToolbar(); + _animation->setOldDirection(kDirNone); + drawDirection(); +} + +void AvalancheEngine::drawScore() { + uint16 score = _dnascore; + int8 numbers[3] = {0, 0, 0}; + for (int i = 0; i < 2; i++) { + byte divisor = 1; + for (int j = 0; j < (2 - i); j++) + divisor *= 10; + numbers[i] = score / divisor; + score -= numbers[i] * divisor; + } + numbers[2] = score; + + CursorMan.showMouse(false); + + for (int i = 0; i < 3; i++) { + if (_scoreToDisplay[i] != numbers[i]) + _graphics->drawDigit(numbers[i], 250 + (i + 1) * 15, 177); + } + + CursorMan.showMouse(true); + + for (int i = 0; i < 3; i++) + _scoreToDisplay[i] = numbers[i]; +} + +void AvalancheEngine::incScore(byte num) { + for (int i = 1; i <= num; i++) { + _dnascore++; + + if (_soundFx) { + for (int j = 1; j <= 97; j++) + // Length os 2 is a guess, the original doesn't have a delay specified + _sound->playNote(177 + _dnascore * 3, 2); + } + } + warning("STUB: points()"); + + drawScore(); +} + +void AvalancheEngine::useCompass(const Common::Point &cursorPos) { + byte color = _graphics->getScreenColor(cursorPos); + + switch (color) { + case kColorGreen: + _animation->setDirection(kDirUp); + _animation->setMoveSpeed(0, kDirUp); + drawDirection(); + break; + case kColorBrown: + _animation->setDirection(kDirDown); + _animation->setMoveSpeed(0, kDirDown); + drawDirection(); + break; + case kColorCyan: + _animation->setDirection(kDirLeft); + _animation->setMoveSpeed(0, kDirLeft); + drawDirection(); + break; + case kColorLightmagenta: + _animation->setDirection(kDirRight); + _animation->setMoveSpeed(0, kDirRight); + drawDirection(); + break; + case kColorRed: + case kColorWhite: + case kColorLightcyan: + case kColorYellow: // Fall-throughs are intended. + _animation->stopWalking(); + drawDirection(); + break; + } +} + +void AvalancheEngine::fxToggle() { + warning("STUB: fxtoggle()"); +} + +void AvalancheEngine::refreshObjectList() { + _carryNum = 0; + if (_thinkThing && !_objects[_thinks - 1]) + thinkAbout(kObjectMoney, kThing); // you always have money + + for (int i = 0; i < kObjectNum; i++) { + if (_objects[i]) { + _objectList[_carryNum] = i + 1; + _carryNum++; + } + } +} + +/** + * @remarks Originally called 'verte' + */ +void AvalancheEngine::guideAvvy(Common::Point cursorPos) { + if (!_userMovesAvvy) + return; + + cursorPos.y /= 2; + byte what; + + // _animation->tr[0] is Avalot.) + AnimationType *avvy = _animation->_sprites[0]; + if (cursorPos.x < avvy->_x) + what = 1; + else if (cursorPos.x > (avvy->_x + avvy->_xLength)) + what = 2; + else + what = 0; // On top + + if (cursorPos.y < avvy->_y) + what += 3; + else if (cursorPos.y > (avvy->_y + avvy->_yLength)) + what += 6; + + switch (what) { + case 0: + _animation->stopWalking(); + break; // Clicked on Avvy: no movement. + case 1: + _animation->setMoveSpeed(0, kDirLeft); + break; + case 2: + _animation->setMoveSpeed(0, kDirRight); + break; + case 3: + _animation->setMoveSpeed(0, kDirUp); + break; + case 4: + _animation->setMoveSpeed(0, kDirUpLeft); + break; + case 5: + _animation->setMoveSpeed(0, kDirUpRight); + break; + case 6: + _animation->setMoveSpeed(0, kDirDown); + break; + case 7: + _animation->setMoveSpeed(0, kDirDownLeft); + break; + case 8: + _animation->setMoveSpeed(0, kDirDownRight); + break; + } // No other values are possible. + + drawDirection(); +} + +void AvalancheEngine::checkClick() { + Common::Point cursorPos = getMousePos(); + + /*if (mrelease > 0) + after_the_scroll = false;*/ + + if ((0 <= cursorPos.y) && (cursorPos.y <= 21)) + _graphics->loadMouse(kCurUpArrow); // up arrow + else if ((317 <= cursorPos.y) && (cursorPos.y <= 339)) + _graphics->loadMouse(kCurIBeam); //I-beam + else if ((340 <= cursorPos.y) && (cursorPos.y <= 399)) + _graphics->loadMouse(kCurScrewDriver); // screwdriver + else if (!_menu->isActive()) { // Dropdown can handle its own pointers. + if (_holdLeftMouse) { + _graphics->loadMouse(kCurCrosshair); // Mark's crosshairs + guideAvvy(cursorPos); // Normally, if you click on the picture, you're guiding Avvy around. + } else + _graphics->loadMouse(kCurFletch); // fletch + } + + if (_holdLeftMouse) { + if ((0 <= cursorPos.y) && (cursorPos.y <= 21)) { // Click on the dropdown menu. + if (_dropsOk) + _menu->update(); + } else if ((317 <= cursorPos.y) && (cursorPos.y <= 339)) { // Click on the command line. + _parser->_inputTextPos = (cursorPos.x - 23) / 8; + if (_parser->_inputTextPos > _parser->_inputText.size() + 1) + _parser->_inputTextPos = _parser->_inputText.size() + 1; + if (_parser->_inputTextPos < 1) + _parser->_inputTextPos = 1; + _parser->_inputTextPos--; + _parser->plotText(); + } else if ((340 <= cursorPos.y) && (cursorPos.y <= 399)) { // Check the toolbar. + if ((137 <= cursorPos.x) && (cursorPos.x <= 207)) { // Control Avvy with the compass. + if (_alive && _avvyIsAwake) + useCompass(cursorPos); + } else if ((208 <= cursorPos.x) && (cursorPos.x <= 260)) { // Examine the _thing. + do { + updateEvents(); + } while (_holdLeftMouse); + + if (_thinkThing) { + _parser->_thing = _thinks; + _parser->_thing += 49; + _parser->_person = kPeoplePardon; + } else { + _parser->_person = (People) _thinks; + _parser->_thing = _parser->kPardon; + } + callVerb(kVerbCodeExam); + } else if ((261 <= cursorPos.x) && (cursorPos.x <= 319)) { // Display the score. + do { + updateEvents(); + } while (_holdLeftMouse); + + callVerb(kVerbCodeScore); + } else if ((320 <= cursorPos.x) && (cursorPos.x <= 357)) { // Change speed. + _animation->_sprites[0]->_speedX = kWalk; + _animation->updateSpeed(); + } else if ((358 <= cursorPos.x) && (cursorPos.x <= 395)) { // Change speed. + _animation->_sprites[0]->_speedX = kRun; + _animation->updateSpeed(); + } else if ((396 <= cursorPos.x) && (cursorPos.x <= 483)) + fxToggle(); + else if ((535 <= cursorPos.x) && (cursorPos.x <= 640)) + _mouseText.insertChar(kControlNewLine, 0); + } else if (!_dropsOk) + _mouseText = Common::String(13) + _mouseText; + } +} + +void AvalancheEngine::errorLed() { + warning("STUB: errorled()"); +} + +/** + * Displays a fade out, full screen. + * This version is different to the one in the original, which was fading in 3 steps. + * @remarks Originally called 'dusk' + */ +void AvalancheEngine::fadeOut() { + byte pal[3], tmpPal[3]; + + _graphics->setBackgroundColor(kColorBlack); + if (_fxHidden) + return; + _fxHidden = true; + + for (int i = 0; i < 16; i++) { + for (int j = 0; j < 16; j++) { + g_system->getPaletteManager()->grabPalette((byte *)tmpPal, j, 1); + _fxPal[i][j][0] = tmpPal[0]; + _fxPal[i][j][1] = tmpPal[1]; + _fxPal[i][j][2] = tmpPal[2]; + if (tmpPal[0] >= 16) + pal[0] = tmpPal[0] - 16; + else + pal[0] = 0; + + if (tmpPal[1] >= 16) + pal[1] = tmpPal[1] - 16; + else + pal[1] = 0; + + if (tmpPal[2] >= 16) + pal[2] = tmpPal[2] - 16; + else + pal[2] = 0; + + g_system->getPaletteManager()->setPalette(pal, j, 1); + } + _system->delayMillis(10); + _graphics->refreshScreen(); + } +} + +/** + * Displays a fade in, full screen. + * This version is different to the one in the original, which was fading in 3 steps. + * @remarks Originally called 'dawn' + */ +void AvalancheEngine::fadeIn() { + if (_holdTheDawn || !_fxHidden) + return; + + _fxHidden = false; + + byte pal[3]; + for (int i = 15; i >= 0; i--) { + for (int j = 0; j < 16; j++) { + pal[0] = _fxPal[i][j][0]; + pal[1] = _fxPal[i][j][1]; + pal[2] = _fxPal[i][j][2]; + g_system->getPaletteManager()->setPalette(pal, j, 1); + } + _system->delayMillis(10); + _graphics->refreshScreen(); + } + + if ((_room == kRoomYours) && _avvyInBed && _teetotal) + _graphics->setBackgroundColor(kColorYellow); +} + +void AvalancheEngine::drawDirection() { // It's data is loaded in load_digits(). + if (_animation->getOldDirection() == _animation->getDirection()) + return; + + _animation->setOldDirection(_animation->getDirection()); + + CursorMan.showMouse(false); + _graphics->drawDirection(_animation->getDirection(), 0, 161); + CursorMan.showMouse(true); +} + + +void AvalancheEngine::gameOver() { + _userMovesAvvy = false; + + AnimationType *avvy = _animation->_sprites[0]; + int16 sx = avvy->_x; + int16 sy = avvy->_y; + + avvy->remove(); + avvy->init(12, true); // 12 = Avalot falls + avvy->_stepNum = 0; + avvy->appear(sx, sy, kDirUp); + + _timer->addTimer(3, Timer::kProcAvalotFalls, Timer::kReasonFallingOver); + _alive = false; +} + +void AvalancheEngine::minorRedraw() { + fadeOut(); + + enterRoom(_room, 0); // Ped unknown or non-existant. + + for (int i = 0; i < 3; i++) + _scoreToDisplay[i] = -1; // impossible digits + drawScore(); + + fadeIn(); +} + +void AvalancheEngine::majorRedraw() { + warning("STUB: major_redraw()"); +} + +uint16 AvalancheEngine::bearing(byte whichPed) { + AnimationType *avvy = _animation->_sprites[0]; + PedType *curPed = &_peds[whichPed]; + + if (avvy->_x == curPed->_x) + return 0; + + int16 deltaX = avvy->_x - curPed->_x; + int16 deltaY = avvy->_y - curPed->_y; + uint16 result = (uint16)(atan((float)(deltaY / deltaX)) * 180 / M_PI); + if (avvy->_x < curPed->_x) { + return result + 90; + } else { + return result + 270; + } +} + +/** + * @remarks Originally called 'sprite_run' + */ +void AvalancheEngine::spriteRun() { + _doingSpriteRun = true; + _animation->animLink(); + _doingSpriteRun = false; +} + +// CHECKME: Unused function +void AvalancheEngine::fixFlashers() { + _ledStatus = 177; + _animation->setOldDirection(kDirNone); + _dialogs->setReadyLight(2); + drawDirection(); +} + +Common::String AvalancheEngine::intToStr(int32 num) { + return Common::String::format("%d", num); +} + +void AvalancheEngine::resetVariables() { + _animation->setDirection(kDirUp); + _carryNum = 0; + for (int i = 0; i < kObjectNum; i++) + _objects[i] = false; + + _dnascore = 0; + _money = 0; + _room = kRoomNowhere; + _saveNum = 0; + for (int i = 0; i < 100; i++) + _roomCount[i] = 0; + + _wonNim = false; + _wineState = 0; + _cwytalotGone = false; + _passwordNum = 0; + _aylesIsAwake = false; + _drawbridgeOpen = 0; + _avariciusTalk = 0; + _rottenOnion = false; + _onionInVinegar = false; + _givenToSpludwick = 0; + _brummieStairs = 0; + _cardiffQuestionNum = 0; + _passedCwytalotInHerts = false; + _avvyIsAwake = false; + _avvyInBed = false; + _userMovesAvvy = false; + _npcFacing = 0; + _givenBadgeToIby = false; + _friarWillTieYouUp = false; + _tiedUp = false; + _boxContent = 0; + _talkedToCrapulus = false; + _jacquesState = 0; + _bellsAreRinging = false; + _standingOnDais = false; + _takenPen = false; + _arrowInTheDoor = false; + _favouriteDrink = ""; + _favouriteSong = ""; + _worstPlaceOnEarth = ""; + _spareEvening = ""; + _totalTime = 0; + _jumpStatus = 0; + _mushroomGrowing = false; + _spludwickAtHome = false; + _lastRoom = 0; + _lastRoomNotMap = 0; + _crapulusWillTell = false; + _enterCatacombsFromLustiesRoom = false; + _teetotal = false; + _malagauche = 0; + _drinking = 0; + _enteredLustiesRoomAsMonk = false; + _catacombX = 0; + _catacombY = 0; + _avvysInTheCupboard = false; + _geidaFollows = false; + _givenPotionToGeida = false; + _lustieIsAsleep = false; + _beenTiedUp = false; + _sittingInPub = false; + _spurgeTalkCount = 0; + _metAvaroid = false; + _takenMushroom = false; + _givenPenToAyles = false; + _askedDogfoodAboutNim = false; + + _parser->resetVariables(); + _animation->resetVariables(); + _sequence->resetVariables(); + _background->resetVariables(); + _menu->resetVariables(); +} + +void AvalancheEngine::newGame() { + for (int i = 0; i < kMaxSprites; i++) { + AnimationType *spr = _animation->_sprites[i]; + if (spr->_quick) + spr->remove(); + } + // Deallocate sprite. Sorry, beta testers! + + AnimationType *avvy = _animation->_sprites[0]; + avvy->init(0, true); + + _alive = true; + resetVariables(); + + _dialogs->setBubbleStateNatural(); + + _spareEvening = "answer a questionnaire"; + _favouriteDrink = "beer"; + _money = 30; // 2/6 + _animation->setDirection(kDirStopped); + _parser->_wearing = kObjectClothes; + _objects[kObjectMoney - 1] = true; + _objects[kObjectBodkin - 1] = true; + _objects[kObjectBell - 1] = true; + _objects[kObjectClothes - 1] = true; + + _thinkThing = true; + _thinks = 2; + refreshObjectList(); + _seeScroll = false; + + avvy->appear(300, 117, kDirRight); // Needed to initialize Avalot. + //for (gd = 0; gd <= 30; gd++) for (gm = 0; gm <= 1; gm++) also[gd][gm] = nil; + // fillchar(previous^,sizeof(previous^),#0); { blank out array } + _him = kPeoplePardon; + _her = kPeoplePardon; + _it = Parser::kPardon; + _passwordNum = _rnd->getRandomNumber(29) + 1; //Random(30) + 1; + _userMovesAvvy = false; + _doingSpriteRun = false; + _avvyInBed = true; + + enterRoom(kRoomYours, 1); + avvy->_visible = false; + drawScore(); + _menu->setup(); + _clock->update(); + spriteRun(); +} + +bool AvalancheEngine::getFlag(char x) { + for (uint16 i = 0; i < _flags.size(); i++) { + if (_flags[i] == x) + return true; + } + + return false; +} + +bool AvalancheEngine::decreaseMoney(uint16 amount) { + _money -= amount; + if (_money < 0) { + _dialogs->displayScrollChain('Q', 2); // "You are now denariusless!" + gameOver(); + return false; + } else + return true; +} + +Common::String AvalancheEngine::getName(People whose) { + static const char lads[17][20] = { + "Avalot", "Spludwick", "Crapulus", "Dr. Duck", "Malagauche", + "Friar Tuck", "Robin Hood", "Cwytalot", "du Lustie", "the Duke of Cardiff", + "Dogfood", "A trader", "Ibythneth", "Ayles", "Port", + "Spurge", "Jacques" + }; + + static const char lasses[4][15] = {"Arkata", "Geida", "\0xB1", "the Wise Woman"}; + + if (whose < kPeopleArkata) + return Common::String(lads[whose - kPeopleAvalot]); + else + return Common::String(lasses[whose - kPeopleArkata]); +} + +Common::String AvalancheEngine::getItem(byte which) { + static const char items[kObjectNum][18] = { + "some wine", "your money-bag", "your bodkin", "a potion", "a chastity belt", + "a crossbow bolt", "a crossbow", "a lute", "a pilgrim's badge", "a mushroom", + "a key", "a bell", "a scroll", "a pen", "some ink", + "your clothes", "a habit", "an onion" + }; + + Common::String result; + if (which > 150) + which -= 149; + + switch (which) { + case kObjectWine: + switch (_wineState) { + case 0: + case 1: + case 4: + result = Common::String(items[which - 1]); + break; + case 3: + result = "some vinegar"; + break; + } + break; + case kObjectOnion: + if (_rottenOnion) + result = "a rotten onion"; + else if (_onionInVinegar) + result = "a pickled onion (in the vinegar)"; + else + result = Common::String(items[which - 1]); + break; + default: + if ((which < kObjectNum) && (which > 0)) + result = Common::String(items[which - 1]); + else + result = ""; + } + return result; +} + +Common::String AvalancheEngine::f5Does() { + switch (_room) { + case kRoomYours: + if (!_avvyIsAwake) + return Common::String::format("%cWWake up", kVerbCodeWake); + else if (_avvyInBed) + return Common::String::format("%cGGet up", kVerbCodeStand); + break; + case kRoomInsideCardiffCastle: + if (_standingOnDais) + return Common::String::format("%cCClimb down", kVerbCodeClimb); + else + return Common::String::format("%cCClimb up", kVerbCodeClimb); + break; + case kRoomNottsPub: + if (_sittingInPub) + return Common::String::format("%cSStand up", kVerbCodeStand); + else + return Common::String::format("%cSSit down", kVerbCodeSit); + break; + case kRoomMusicRoom: + if (_animation->inField(5)) + return Common::String::format("%cPPlay the harp", kVerbCodePlay); + break; + default: + break; + } + + return Common::String::format("%c", kVerbCodePardon); // If all else fails... +} + +void AvalancheEngine::flipRoom(Room room, byte ped) { + assert((ped > 0) && (ped < 15)); + if (!_alive) { + // You can't leave the room if you're dead. + _animation->_sprites[0]->_moveX = 0; + _animation->_sprites[0]->_moveY = 0; // Stop him from moving. + return; + } + + if ((room == kRoomDummy) && (_room == kRoomLusties)) { + _animation->hideInCupboard(); + return; + } + + if ((_jumpStatus > 0) && (_room == kRoomInsideCardiffCastle)) { + // You can't *jump* out of Cardiff Castle! + _animation->_sprites[0]->_moveX = 0; + return; + } + + exitRoom(_room); + fadeOut(); + + for (int16 i = 1; i < _animation->kSpriteNumbMax; i++) { + if (_animation->_sprites[i]->_quick) + _animation->_sprites[i]->remove(); + } // Deallocate sprite + + if (_room == kRoomLustiesRoom) + _enterCatacombsFromLustiesRoom = true; + + enterRoom(room, ped); + _animation->appearPed(0, ped - 1); + _enterCatacombsFromLustiesRoom = false; + _animation->setOldDirection(_animation->getDirection()); + _animation->setDirection(_animation->_sprites[0]->_facingDir); + drawDirection(); + + fadeIn(); +} + +/** + * Open the Door. + * This slides the door open. The data really ought to be saved in + * the Also file, and will be next time. However, for now, they're + * here. + * @remarks Originally called 'open_the_door' + */ +void AvalancheEngine::openDoor(Room whither, byte ped, byte magicnum) { + switch (_room) { + case kRoomOutsideYours: + case kRoomOutsideNottsPub: + case kRoomOutsideDucks: + _sequence->startOutsideSeq(whither, ped); + break; + case kRoomInsideCardiffCastle: + _sequence->startCardiffSeq(whither, ped); + break; + case kRoomAvvysGarden: + case kRoomEntranceHall: + case kRoomInsideAbbey: + case kRoomYourHall: + _sequence->startHallSeq(whither, ped); + break; + case kRoomMusicRoom: + case kRoomOutsideArgentPub: + _sequence->startMusicRoomSeq2(whither, ped); + break; + case kRoomLusties: + switch (magicnum) { + case 14: + if (_avvysInTheCupboard) { + _animation->hideInCupboard(); + _sequence->startCupboardSeq(); + return; + } else { + _animation->appearPed(0, 5); + _animation->_sprites[0]->_facingDir = kDirRight; + _sequence->startLustiesSeq2(whither, ped); + } + break; + case 12: + _sequence->startLustiesSeq3(whither, ped); + break; + } + break; + default: + _sequence->startDummySeq(whither, ped); + } +} + +void AvalancheEngine::setRoom(People persId, Room roomId) { + _whereIs[persId - kPeopleAvalot] = roomId; +} + +Room AvalancheEngine::getRoom(People persId) { + return _whereIs[persId - kPeopleAvalot]; +} +} // End of namespace Avalanche diff --git a/engines/avalanche/avalot.h b/engines/avalanche/avalot.h new file mode 100644 index 0000000000..ab78f5c385 --- /dev/null +++ b/engines/avalanche/avalot.h @@ -0,0 +1,104 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on the original source code of Lord Avalot d'Argent version 1.3. + * Copyright (c) 1994-1995 Mike, Mark and Thomas Thurman. + */ + +/* AVALOT The kernel of the program. */ + +#ifndef AVALANCHE_AVALOT_H +#define AVALANCHE_AVALOT_H + +#include "avalanche/animation.h" + +namespace Avalanche { +class AvalancheEngine; + +class Clock { +public: + Clock(AvalancheEngine *vm); + + void update(); + +private: + static const int kCenterX = 510; + static const int kCenterY = 183; + + AvalancheEngine *_vm; + + uint16 _hour, _minute, _second, _hourAngle, _oldHour, _oldMinute, _oldHourAngle; + Common::Point _clockHandHour, _clockHandMinute; + + Common::Point calcHand(uint16 angle, uint16 length, Color color); + void drawHand(const Common::Point &endPoint, Color color); + void plotHands(); + void chime(); +}; + +static const byte kObjectNum = 18; // always preface with a # +static const int16 kCarryLimit = 12; // carry limit + +static const int16 kNumlockCode = 32; // Code for Num Lock +static const int16 kMouseSize = 134; + +struct PedType { + int16 _x, _y; + Direction _direction; +}; + +struct MagicType { + byte _operation; // one of the operations + uint16 _data; // data for them +}; + +struct FieldType { + int16 _x1, _y1, _x2, _y2; +}; + +struct LineType : public FieldType { + Color _color; +}; + +typedef int8 TuneType[31]; + +struct QuasipedType { + byte _whichPed; + Color _textColor; + Room _room; + Color _backgroundColor; + People _who; +}; + +#if 0 +struct Sundry { // Things which must be saved over a backtobootstrap, outside DNA. + Common::String _qEnidFilename; + bool _qSoundFx; + byte _qThinks; + bool _qThinkThing; +}; +#endif + +} // End of namespace Avalanche + +#endif // AVALANCHE_AVALOT_H diff --git a/engines/avalanche/background.cpp b/engines/avalanche/background.cpp new file mode 100644 index 0000000000..c84c049c8f --- /dev/null +++ b/engines/avalanche/background.cpp @@ -0,0 +1,369 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on the original source code of Lord Avalot d'Argent version 1.3. + * Copyright (c) 1994-1995 Mike, Mark and Thomas Thurman. + */ + +/* Original name: CELER The unit for updating the screen pics. */ + +#include "avalanche/avalanche.h" +#include "avalanche/background.h" + +namespace Avalanche { + +const int16 Background::kOnDisk = -1; + +Background::Background(AvalancheEngine *vm) { + _vm = vm; + _spriteNum = 0; +} + +Background::~Background() { + release(); +} + +/** + * @remarks Originally called 'pics_link' + */ +void Background::update() { + if (_vm->_menu->isActive()) + return; // No animation when the menus are up. + + switch (_vm->_room) { + case kRoomOutsideArgentPub: + if ((_vm->_roomTime % 12) == 0) + draw(-1, -1, (_vm->_roomTime / 12) % 4); + break; + case kRoomBrummieRoad: + if ((_vm->_roomTime % 2) == 0) + draw(-1, -1, (_vm->_roomTime / 2) % 4); + break; + case kRoomBridge: + if ((_vm->_roomTime % 2) == 0) + draw(-1, -1, 3 + (_vm->_roomTime / 2) % 4); + break; + case kRoomYours: + if ((!_vm->_avvyIsAwake) && ((_vm->_roomTime % 4) == 0)) + draw(-1, -1, (_vm->_roomTime / 12) % 2); + break; + case kRoomArgentPub: + if (((_vm->_roomTime % 7) == 1) && (_vm->_malagauche != 177)) { + // Malagauche cycle. + _vm->_malagauche++; + switch (_vm->_malagauche) { + case 1: + case 11: + case 21: + draw(-1, -1, 11); // Looks forwards. + break; + case 8: + case 18: + case 28: + case 32: + draw(-1, -1, 10); // Looks at you. + break; + case 30: + draw(-1, -1, 12); // Winks. + break; + case 33: + _vm->_malagauche = 0; + break; + } + } + + switch (_vm->_roomTime % 200) { + case 179: + case 197: + draw(-1, -1, 4); // Dogfood's drinking cycle. + break; + case 182: + case 194: + draw(-1, -1, 5); + break; + case 185: + draw(-1, -1, 6); + break; + case 199: + _vm->_npcFacing = 177; // Impossible value for this. + break; + default: + if (_vm->_roomTime % 200 <= 178) { // Normally. + byte direction = 1; + uint16 angle = _vm->bearing(1); + if (((angle >= 1) && (angle <= 90)) || ((angle >= 358) && (angle <= 360))) + direction = 3; + else if ((angle >= 293) && (angle <= 357)) + direction = 2; + else if ((angle >= 270) && (angle <= 292)) + direction = 4; + + if (direction != _vm->_npcFacing) { // Dogfood. + draw(-1, -1, direction - 1); + _vm->_npcFacing = direction; + } + } + } + break; + case kRoomWestHall: + if ((_vm->_roomTime % 3) == 0) { + switch ((_vm->_roomTime / 3) % 6) { + case 4: + draw(-1, -1, 0); + break; + case 1: + case 3: + case 5: + draw(-1, -1, 1); + break; + case 0: + case 2: + draw(-1, -1, 2); + break; + } + } + break; + case kRoomLustiesRoom: + if (!(_vm->_lustieIsAsleep)) { + byte direction = 0; + uint16 angle = _vm->bearing(1); + if ((_vm->_roomTime % 45) > 42) + direction = 4; // du Lustie blinks. + // Bearing of Avvy from du Lustie. + else if ((angle <= 45) || ((angle >= 315) && (angle <= 360))) + direction = 1; // Middle. + else if ((angle >= 45) && (angle <= 180)) + direction = 2; // Left. + else if ((angle >= 181) && (angle <= 314)) + direction = 3; // Right. + + if (direction != _vm->_npcFacing) { // du Lustie. + draw(-1, -1, direction - 1); + _vm->_npcFacing = direction; + } + } + break; + case kRoomAylesOffice: + if ((!_vm->_aylesIsAwake) && (_vm->_roomTime % 14 == 0)) { + switch ((_vm->_roomTime / 14) % 2) { + case 0: + draw(-1, -1, 0); // Frame 2: EGA. + break; + case 1: + draw(-1, -1, 2); // Frame 1: Natural. + break; + } + } + break; + case kRoomRobins: + if (_vm->_tiedUp) { + switch (_vm->_roomTime % 54) { + case 20: + draw(-1, -1, 3); // Frame 4: Avalot blinks. + break; + case 23: + draw(-1, -1, 1); // Frame 1: Back to normal. + break; + } + } + break; + case kRoomNottsPub: { + // Bearing of Avvy from Port. + byte direction = 0; + uint16 angle = _vm->bearing(4); + if ((angle <= 45) || ((angle >= 315) && (angle <= 360))) + direction = 2; // Middle. + else if ((angle >= 45) && (angle <= 180)) + direction = 6; // Left. + else if ((angle >= 181) && (angle <= 314)) + direction = 8; // Right. + + if ((_vm->_roomTime % 60) > 57) + direction--; // Blinks. + + if (direction != _vm->_npcFacing) { // Port. + draw(-1, -1, direction - 1); + _vm->_npcFacing = direction; + } + + switch (_vm->_roomTime % 50) { + case 45 : + draw(-1, -1, 8); // Spurge blinks. + break; + case 49 : + draw(-1, -1, 9); + break; + } + break; + } + case kRoomDucks: { + if ((_vm->_roomTime % 3) == 0) // The fire flickers. + draw(-1, -1, (_vm->_roomTime / 3) % 3); + + // Bearing of Avvy from Duck. + byte direction = 0; + uint16 angle = _vm->bearing(1); + if ((angle <= 45) || ((angle >= 315) && (angle <= 360))) + direction = 4; // Middle. + else if ((angle >= 45) && (angle <= 180)) + direction = 6; // Left. + else if ((angle >= 181) && (angle <= 314)) + direction = 8; // Right. + + if ((_vm->_roomTime % 45) > 42) + direction++; // Duck blinks. + + if (direction != _vm->_npcFacing) { // Duck. + draw(-1, -1, direction - 1); + _vm->_npcFacing = direction; + } + break; + } + default: + break; + } + + if ((_vm->_bellsAreRinging) && (_vm->getFlag('B'))) { + // They're ringing the bells. + switch (_vm->_roomTime % 4) { + case 1: + if (_nextBell < 5) + _nextBell = 12; + _nextBell--; + // CHECKME: 2 is a guess. No length in the original? + _vm->_sound->playNote(_vm->kNotes[_nextBell], 2); + break; + case 2: + _vm->_sound->stopSound(); + break; + } + } +} + +void Background::load(byte number) { + Common::File f; + _filename = _filename.format("chunk%d.avd", number); + if (!f.open(_filename)) + return; // We skip because some rooms don't have sprites in the background. + + f.seek(44); + _spriteNum = f.readByte(); + for (int i = 0; i < _spriteNum; i++) + _offsets[i] = f.readSint32LE(); + + for (int i = 0; i < _spriteNum; i++) { + f.seek(_offsets[i]); + + SpriteType sprite; + sprite._type = (PictureType)(f.readByte()); + sprite._x = f.readSint16LE(); + sprite._y = f.readSint16LE(); + sprite._xl = f.readSint16LE(); + sprite._yl = f.readSint16LE(); + sprite._size = f.readSint32LE(); + bool natural = f.readByte(); + bool memorize = f.readByte(); + + if (memorize) { + _sprites[i]._x = sprite._x; + _sprites[i]._xl = sprite._xl; + _sprites[i]._y = sprite._y; + _sprites[i]._yl = sprite._yl; + _sprites[i]._type = sprite._type; + + if (natural) + _vm->_graphics->getNaturalPicture(_sprites[i]); + else { + _sprites[i]._size = sprite._size; + _sprites[i]._picture = _vm->_graphics->loadPictureRaw(f, _sprites[i]._xl * 8, _sprites[i]._yl + 1); + } + } else + _sprites[i]._x = kOnDisk; + } + f.close(); +} + +void Background::release() { + for (int i = 0; i < _spriteNum; i++) { + if (_sprites[i]._x > kOnDisk) + _sprites[i]._picture.free(); + } +} + +/** + * Draw background animation + * @remarks Originally called 'show_one' + */ +void Background::draw(int16 destX, int16 destY, byte sprId) { + assert(sprId < 40); + + if (_sprites[sprId]._x > kOnDisk) { + if (destX < 0) { + destX = _sprites[sprId]._x * 8; + destY = _sprites[sprId]._y; + } + drawSprite(destX, destY, _sprites[sprId]); + } else { + Common::File f; + if (!f.open(_filename)) // Filename was set in loadBackgroundSprites(). + return; // We skip because some rooms don't have sprites in the background. + + f.seek(_offsets[sprId]); + + SpriteType sprite; + sprite._type = (PictureType)(f.readByte()); + sprite._x = f.readSint16LE(); + sprite._y = f.readSint16LE(); + sprite._xl = f.readSint16LE(); + sprite._yl = f.readSint16LE(); + sprite._size = f.readSint32LE(); + f.skip(2); // Natural and Memorize are used in Load() + sprite._picture = _vm->_graphics->loadPictureRaw(f, sprite._xl * 8, sprite._yl + 1); + + if (destX < 0) { + destX = sprite._x * 8; + destY = sprite._y; + } + drawSprite(destX, destY, sprite); + + sprite._picture.free(); + f.close(); + } +} + +/** + * @remarks Originally called 'display_it' + */ +void Background::drawSprite(int16 x, int16 y, SpriteType &sprite) { + // These pictures are practically parts of the background. -10 is for the drop-down menu. + _vm->_graphics->drawBackgroundSprite(x, y - 10, sprite); +} + +void Background::resetVariables() { + _nextBell = 0; +} + +void Background::synchronize(Common::Serializer &sz) { + sz.syncAsByte(_nextBell); +} +} // End of namespace Avalanche. diff --git a/engines/avalanche/background.h b/engines/avalanche/background.h new file mode 100644 index 0000000000..34d7a9a2cc --- /dev/null +++ b/engines/avalanche/background.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 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on the original source code of Lord Avalot d'Argent version 1.3. + * Copyright (c) 1994-1995 Mike, Mark and Thomas Thurman. + */ + +/* Original name: CELER The unit for updating the screen pics. */ + +#ifndef AVALANCHE_BACKGROUND_H +#define AVALANCHE_BACKGROUND_H + +#include "common/str.h" + +namespace Avalanche { +class AvalancheEngine; + +enum PictureType {kEga, kBgi, kNaturalImage}; + +struct SpriteType { + PictureType _type; + int16 _x, _y; + int16 _xl, _yl; + int32 _size; + Graphics::Surface _picture; +}; + +class Background { +public: + Background(AvalancheEngine *vm); + ~Background(); + + void update(); + void load(byte number); + void release(); + + // Setting the destination to negative coordinates means the picture should be drawn to it's original position. + // If you give it positive values, the picture will be plotted to the desired coordinates on the screen. + // By that we get rid of show_one_at(), which would be almost identical and cause a lot of code duplication. + void draw(int16 destX, int16 destY, byte sprId); + void resetVariables(); + void synchronize(Common::Serializer &sz); + +private: + AvalancheEngine *_vm; + + byte _nextBell; // For the ringing. + int32 _offsets[40]; + byte _spriteNum; + SpriteType _sprites[40]; + Common::String _filename; + static const int16 kOnDisk; // Value of _sprites[fv]._x when it's not in memory. + + void drawSprite(int16 x, int16 y, SpriteType &sprite); +}; + +} // End of namespace Avalanche. + +#endif // AVALANCHE_BACKGROUND_H diff --git a/engines/avalanche/closing.cpp b/engines/avalanche/closing.cpp new file mode 100644 index 0000000000..1cb2e84218 --- /dev/null +++ b/engines/avalanche/closing.cpp @@ -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 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on the original source code of Lord Avalot d'Argent version 1.3. + * Copyright (c) 1994-1995 Mike, Mark and Thomas Thurman. + */ + +/* CLOSING The closing screen and error handler. */ + +#include "avalanche/avalanche.h" +#include "avalanche/closing.h" + +#include "common/random.h" + +namespace Avalanche { + +Closing::Closing(AvalancheEngine *vm) { + _vm = vm; + warning("STUB: Closing::Closing()"); +} + +void Closing::getScreen(ScreenType which) { + warning("STUB: Closing::getScreen()"); +} + +void Closing::showScreen() { + warning("STUB: Closing::showScreen()"); +} + +void Closing::putIn(Common::String str, uint16 where) { + warning("STUB: Closing::putIn()"); +} + +void Closing::exitGame() { + static const char nouns[12][14] = { + "sackbut", "harpsichord", "camel", "conscience", "ice-cream", "serf", + "abacus", "castle", "carrots", "megaphone", "manticore", "drawbridge" + }; + + static const char verbs[12][12] = { + "haunt", "daunt", "tickle", "gobble", "erase", "provoke", + "surprise", "ignore", "stare at", "shriek at", "frighten", "quieten" + }; + + _vm->_sound->stopSound(); + + getScreen(kScreenNagScreen); + byte nounId = _vm->_rnd->getRandomNumber(11); + byte verbId = _vm->_rnd->getRandomNumber(11); + Common::String result = Common::String::format("%s will %s you", nouns[nounId], verbs[verbId]); + putIn(result, 1628); + showScreen(); // No halt- it's already set up. +} + +} // End of namespace Avalanche. diff --git a/engines/avalanche/closing.h b/engines/avalanche/closing.h new file mode 100644 index 0000000000..25217e347e --- /dev/null +++ b/engines/avalanche/closing.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 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on the original source code of Lord Avalot d'Argent version 1.3. + * Copyright (c) 1994-1995 Mike, Mark and Thomas Thurman. + */ + +/* CLOSING The closing screen and error handler. */ + +#ifndef AVALANCHE_CLOSING_H +#define AVALANCHE_CLOSING_H + +#include "common/str.h" + +namespace Avalanche { +class AvalancheEngine; + +class Closing { +public: + Closing(AvalancheEngine *vm); + void exitGame(); + +private: + // Will be needed during implementation of Closing. + enum ScreenType { + kScreenBugAlert = 1, + kScreenRamCram = 2, + kScreenNagScreen = 3, + kScreenTwoCopies = 5 + }; + + AvalancheEngine *_vm; + + void getScreen(ScreenType which); + void showScreen(); + void putIn(Common::String str, uint16 where); + +}; + +} // End of namespace Avalanche. + +#endif // AVALANCHE_CLOSING_H diff --git a/engines/avalanche/console.cpp b/engines/avalanche/console.cpp new file mode 100644 index 0000000000..656cc1907c --- /dev/null +++ b/engines/avalanche/console.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 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on the original source code of Lord Avalot d'Argent version 1.3. + * Copyright (c) 1994-1995 Mike, Mark and Thomas Thurman. + */ + +#include "avalanche/console.h" +#include "avalanche/avalanche.h" + +namespace Avalanche { + +AvalancheConsole::AvalancheConsole(AvalancheEngine *vm) : GUI::Debugger(), _vm(vm) { + DCmd_Register("magic_lines", WRAP_METHOD(AvalancheConsole, Cmd_MagicLines)); +} + +AvalancheConsole::~AvalancheConsole() { +} + +/** + * This command loads up the specified new scene number + */ +bool AvalancheConsole::Cmd_MagicLines(int argc, const char **argv) { + if (argc != 1) { + DebugPrintf("Usage: %s\n", argv[0]); + return true; + } + + _vm->_showDebugLines = !_vm->_showDebugLines; + return false; +} + + +} // End of namespace Avalanche diff --git a/engines/avalanche/console.h b/engines/avalanche/console.h new file mode 100644 index 0000000000..166515d913 --- /dev/null +++ b/engines/avalanche/console.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 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on the original source code of Lord Avalot d'Argent version 1.3. + * Copyright (c) 1994-1995 Mike, Mark and Thomas Thurman. + */ + +#ifndef AVALANCHE_CONSOLE_H +#define AVALANCHE_CONSOLE_H + +#include "gui/debugger.h" + +namespace Avalanche { + +class AvalancheEngine; + +class AvalancheConsole : public GUI::Debugger { +public: + AvalancheConsole(AvalancheEngine *vm); + virtual ~AvalancheConsole(void); + +protected: + bool Cmd_MagicLines(int argc, const char **argv); + +private: + AvalancheEngine *_vm; +}; + +} // End of namespace Avalanche + +#endif // AVALANCHE_CONSOLE_H diff --git a/engines/avalanche/detection.cpp b/engines/avalanche/detection.cpp new file mode 100644 index 0000000000..428e71f35a --- /dev/null +++ b/engines/avalanche/detection.cpp @@ -0,0 +1,213 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on the original source code of Lord Avalot d'Argent version 1.3. + * Copyright (c) 1994-1995 Mike, Mark and Thomas Thurman. + */ + +#include "avalanche/avalanche.h" + +#include "common/system.h" +#include "common/savefile.h" + +#include "engines/advancedDetector.h" +#include "graphics/thumbnail.h" + +namespace Avalanche { + +struct AvalancheGameDescription { + ADGameDescription desc; +}; + +uint32 AvalancheEngine::getFeatures() const { + return _gameDescription->desc.flags; +} + +const char *AvalancheEngine::getGameId() const { + return _gameDescription->desc.gameid; +} + +static const PlainGameDescriptor avalancheGames[] = { + {"avalanche", "Lord Avalot d'Argent"}, + {0, 0} +}; + +static const ADGameDescription gameDescriptions[] = { + { + "avalanche", 0, + { + {"avalot.sez", 0, "de10eb353228013da3d3297784f81ff9", 48763}, + {"mainmenu.avd", 0, "89f31211af579a872045b175cc264298", 18880}, + AD_LISTEND + }, + Common::EN_ANY, + Common::kPlatformDOS, + ADGF_NO_FLAGS, + GUIO0() + }, + + AD_TABLE_END_MARKER +}; + +class AvalancheMetaEngine : public AdvancedMetaEngine { +public: + AvalancheMetaEngine() : AdvancedMetaEngine(gameDescriptions, sizeof(AvalancheGameDescription), avalancheGames) { + } + + const char *getName() const { + return "Avalanche"; + } + + const char *getOriginalCopyright() const { + return "Avalanche Engine Copyright (c) 1994-1995 Mike, Mark and Thomas Thurman."; + } + + bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *gd) const; + bool hasFeature(MetaEngineFeature f) const; + + int getMaximumSaveSlot() const { return 99; } + SaveStateList listSaves(const char *target) const; + void removeSaveState(const char *target, int slot) const; + SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const; +}; + +bool AvalancheMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *gd) const { + if (gd) + *engine = new AvalancheEngine(syst, (const AvalancheGameDescription *)gd); + return gd != 0; +} + +bool AvalancheMetaEngine::hasFeature(MetaEngineFeature f) const { + return + (f == kSupportsListSaves) || + (f == kSupportsDeleteSave) || + (f == kSupportsLoadingDuringStartup) || + (f == kSavesSupportMetaInfo) || + (f == kSavesSupportThumbnail); +} + +SaveStateList AvalancheMetaEngine::listSaves(const char *target) const { + Common::SaveFileManager *saveFileMan = g_system->getSavefileManager(); + Common::StringArray filenames; + Common::String pattern = target; + pattern.toUppercase(); + pattern += ".???"; + + filenames = saveFileMan->listSavefiles(pattern); + sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..) + + SaveStateList saveList; + for (Common::StringArray::const_iterator filename = filenames.begin(); filename != filenames.end(); ++filename) { + const Common::String &fname = *filename; + int slotNum = atoi(fname.c_str() + fname.size() - 3); + if (slotNum >= 0 && slotNum <= getMaximumSaveSlot()) { + Common::InSaveFile *file = saveFileMan->openForLoading(fname); + if (file) { + // Check for our signature. + uint32 signature = file->readUint32LE(); + if (signature != MKTAG('A', 'V', 'A', 'L')) { + warning("Savegame of incompatible type!"); + delete file; + continue; + } + + // Check version. + byte saveVersion = file->readByte(); + if (saveVersion != kSavegameVersion) { + warning("Savegame of incompatible version!"); + delete file; + continue; + } + + // Read name. + uint32 nameSize = file->readUint32LE(); + if (nameSize >= 255) { + delete file; + continue; + } + char *name = new char[nameSize + 1]; + file->read(name, nameSize); + name[nameSize] = 0; + + saveList.push_back(SaveStateDescriptor(slotNum, name)); + delete[] name; + delete file; + } + } + } + + return saveList; +} + +void AvalancheMetaEngine::removeSaveState(const char *target, int slot) const { + Common::String fileName = Common::String::format("%s.%03d", target, slot); + g_system->getSavefileManager()->removeSavefile(fileName); +} + +SaveStateDescriptor AvalancheMetaEngine::querySaveMetaInfos(const char *target, int slot) const { + Common::String fileName = Common::String::format("%s.%03d", target, slot); + Common::InSaveFile *f = g_system->getSavefileManager()->openForLoading(fileName); + + if (f) { + // Check for our signature. + uint32 signature = f->readUint32LE(); + if (signature != MKTAG('A', 'V', 'A', 'L')) { + warning("Savegame of incompatible type!"); + delete f; + return SaveStateDescriptor(); + } + + // Check version. + byte saveVersion = f->readByte(); + if (saveVersion > kSavegameVersion) { + warning("Savegame of a too recent version!"); + delete f; + return SaveStateDescriptor(); + } + + // Read the description. + uint32 descSize = f->readUint32LE(); + Common::String description; + for (uint32 i = 0; i < descSize; i++) { + char actChar = f->readByte(); + description += actChar; + } + + SaveStateDescriptor desc(slot, description); + + Graphics::Surface *const thumbnail = Graphics::loadThumbnail(*f); + desc.setThumbnail(thumbnail); + + delete f; + return desc; + } + return SaveStateDescriptor(); +} + +} // End of namespace Avalanche + +#if PLUGIN_ENABLED_DYNAMIC(AVALANCHE) + REGISTER_PLUGIN_DYNAMIC(AVALANCHE, PLUGIN_TYPE_ENGINE, Avalanche::AvalancheMetaEngine); +#else + REGISTER_PLUGIN_STATIC(AVALANCHE, PLUGIN_TYPE_ENGINE, Avalanche::AvalancheMetaEngine); +#endif diff --git a/engines/avalanche/dialogs.cpp b/engines/avalanche/dialogs.cpp new file mode 100644 index 0000000000..e5acd9cae2 --- /dev/null +++ b/engines/avalanche/dialogs.cpp @@ -0,0 +1,1196 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on the original source code of Lord Avalot d'Argent version 1.3. + * Copyright (c) 1994-1995 Mike, Mark and Thomas Thurman. + */ + + /* SCROLLS The scroll driver. */ + +#include "avalanche/avalanche.h" +#include "avalanche/dialogs.h" + +#include "common/random.h" + +namespace Avalanche { + +// A quasiped defines how people who aren't sprites talk. For example, quasiped +// "A" is Dogfood. The rooms aren't stored because I'm leaving that to context. +const QuasipedType Dialogs::kQuasipeds[16] = { + //_whichPed, _foregroundColor, _room, _backgroundColor, _who + {1, kColorLightgray, kRoomArgentPub, kColorBrown, kPeopleDogfood}, // A: Dogfood (screen 19). + {2, kColorGreen, kRoomArgentPub, kColorWhite, kPeopleIbythneth}, // B: Ibythneth (screen 19). + {2, kColorWhite, kRoomYours, kColorMagenta, kPeopleArkata}, // C: Arkata (screen 1). + {2, kColorBlack, kRoomLustiesRoom, kColorRed, kPeopleInvisible}, // D: Hawk (screen 23). + {2, kColorLightgreen, kRoomOutsideDucks, kColorBrown, kPeopleTrader}, // E: Trader (screen 50). + {5, kColorYellow, kRoomRobins, kColorRed, kPeopleAvalot}, // F: Avvy, tied up (scr.42) + {1, kColorBlue, kRoomAylesOffice, kColorWhite, kPeopleAyles}, // G: Ayles (screen 16). + {1, kColorBrown, kRoomMusicRoom, kColorWhite, kPeopleJacques}, // H: Jacques (screen 7). + {1, kColorLightgreen, kRoomNottsPub, kColorGreen, kPeopleSpurge}, // I: Spurge (screen 47). + {2, kColorYellow, kRoomNottsPub, kColorRed, kPeopleAvalot}, // J: Avalot (screen 47). + {1, kColorLightgray, kRoomLustiesRoom, kColorBlack, kPeopleDuLustie}, // K: du Lustie (screen 23). + {1, kColorYellow, kRoomOubliette, kColorRed, kPeopleAvalot}, // L: Avalot (screen 27). + {2, kColorWhite, kRoomOubliette, kColorRed, kPeopleInvisible}, // M: Avaroid (screen 27). + {3, kColorLightgray, kRoomArgentPub, kColorDarkgray, kPeopleMalagauche},// N: Malagauche (screen 19). + {4, kColorLightmagenta, kRoomNottsPub, kColorRed, kPeoplePort}, // O: Port (screen 47). + {1, kColorLightgreen, kRoomDucks, kColorDarkgray, kPeopleDrDuck} // P: Duck (screen 51). +}; + +Dialogs::Dialogs(AvalancheEngine *vm) { + _vm = vm; + _noError = true; +} + +void Dialogs::init() { + loadFont(); + resetScrollDriver(); +} + +/** + * Determine the color of the ready light and draw it + * @remarks Originally called 'state' + */ +void Dialogs::setReadyLight(byte state) { + if (_vm->_ledStatus == state) + return; // Already like that! + + Color color = kColorBlack; + switch (state) { + case 0: + color = kColorBlack; + break; // Off + case 1: + case 2: + case 3: + color = kColorGreen; + break; // Hit a key + } + warning("STUB: Dialogs::setReadyLight()"); + + CursorMan.showMouse(false); + _vm->_graphics->drawReadyLight(color); + CursorMan.showMouse(true); + _vm->_ledStatus = state; +} + +void Dialogs::easterEgg() { + warning("STUB: Scrolls::easterEgg()"); +} + +void Dialogs::say(int16 x, int16 y, Common::String z) { + FontType itw; + byte lz = z.size(); + + bool offset = x % 8 == 4; + x /= 8; + y++; + int16 i = 0; + for (int xx = 0; xx < lz; xx++) { + switch (z[xx]) { + case kControlRoman: + _currentFont = kFontStyleRoman; + break; + case kControlItalic: + _currentFont = kFontStyleItalic; + break; + default: { + for (int yy = 0; yy < 12; yy++) + itw[(byte)z[xx]][yy] = _fonts[_currentFont][(byte)z[xx]][yy + 2]; + + // We have to draw the characters one-by-one because of the accidental font changes. + i++; + Common::String chr(z[xx]); + _vm->_graphics->drawScrollText(chr, itw, 12, (x - 1) * 8 + offset * 4 + i * 8, y, kColorBlack); + } + } + } +} + +/** + * One of the 3 "Mode" functions passed as ScrollsFunctionType parameters. + * @remarks Originally called 'normscroll' + */ +void Dialogs::scrollModeNormal() { + // Original code is: + // egg : array[1..8] of char = ^P^L^U^G^H+'***'; + // this is not using kControl characters: it's the secret code to be entered to trigger the easter egg + // TODO: To be fixed when the Easter egg code is implemented + Common::String egg = Common::String::format("%c%c%c%c%c***", kControlParagraph, kControlLeftJustified, kControlNegative, kControlBell, kControlBackspace); + Common::String e = "(c) 1994"; + + setReadyLight(3); + _vm->_seeScroll = true; + _vm->_graphics->loadMouse(kCurFletch); + + _vm->_graphics->saveScreen(); + _vm->_graphics->showScroll(); + + Common::Event event; + bool escape = false; + while (!_vm->shouldQuit() && !escape) { + _vm->_graphics->refreshScreen(); + while (_vm->getEvent(event)) { + if ((event.type == Common::EVENT_LBUTTONUP) || + ((event.type == Common::EVENT_KEYDOWN) && ((event.kbd.keycode == Common::KEYCODE_ESCAPE) || + (event.kbd.keycode == Common::KEYCODE_RETURN) || (event.kbd.keycode == Common::KEYCODE_HASH) || + (event.kbd.keycode == Common::KEYCODE_PLUS)))) { + escape = true; + break; + } + } + } + + _vm->_graphics->restoreScreen(); + _vm->_graphics->removeBackup(); + + warning("STUB: scrollModeNormal() - Check Easter Egg trigger"); +#if 0 + char r; + bool oktoexit; + do { + do { + _vm->check(); // was "checkclick;" + +//#ifdef RECORD slowdown(); basher::count++; #endif + + if (_vm->_enhanced->keypressede()) + break; + } while (!((mrelease > 0) || (buttona1()) || (buttonb1()))); + + + if (mrelease == 0) { + inkey(); + if (aboutscroll) { + move(e[2 - 1], e[1 - 1], 7); + e[8 - 1] = inchar; + if (egg == e) + easteregg(); + } + oktoexit = set::of('\15', '\33', '+', '#', eos).has(inchar); + if (!oktoexit) errorled(); + } + + } while (!((oktoexit) || (mrelease > 0))); + +//#ifdef RECORD record_one(); #endif + + _vm->screturn = r == '#'; // "back door" +#endif + + setReadyLight(0); + _vm->_seeScroll = false; + _vm->_holdLeftMouse = false; // Used in Lucerna::checkclick(). + + warning("STUB: Scrolls::scrollModeNormal()"); +} + +/** + * One of the 3 "Mode" functions passed as ScrollsFunctionType parameters. + * The "asking" scroll. Used indirectly in diplayQuestion(). + * @remarks Originally called 'dialogue' + */ +void Dialogs::scrollModeDialogue() { + _vm->_graphics->loadMouse(kCurHand); + + _vm->_graphics->saveScreen(); + _vm->_graphics->showScroll(); + + Common::Event event; + while (!_vm->shouldQuit()) { + _vm->_graphics->refreshScreen(); + + _vm->getEvent(event); + + Common::Point cursorPos = _vm->getMousePos(); + cursorPos.y /= 2; + + char inChar = 0; + if ((event.type == Common::EVENT_KEYDOWN) && (event.kbd.ascii <= 122) && (event.kbd.ascii >= 97)) { + inChar = (char)event.kbd.ascii; + Common::String temp(inChar); + temp.toUppercase(); + inChar = temp[0]; + } + + if (_vm->shouldQuit() || (event.type == Common::EVENT_LBUTTONUP) || (event.type == Common::EVENT_KEYDOWN)) { + if (((cursorPos.x >= _shadowBoxX - 65) && (cursorPos.y >= _shadowBoxY - 24) && (cursorPos.x <= _shadowBoxX - 5) && (cursorPos.y <= _shadowBoxY - 10)) + || (inChar == 'Y') || (inChar == 'J') || (inChar == 'O')) { // Yes, Ja, Oui + _scReturn = true; + break; + } else if (((cursorPos.x >= _shadowBoxX + 5) && (cursorPos.y >= _shadowBoxY - 24) && (cursorPos.x <= _shadowBoxX + 65) && (cursorPos.y <= _shadowBoxY - 10)) + || (inChar == 'N')){ // No, Non, Nein + _scReturn = false; + break; + } + } + } + + _vm->_graphics->restoreScreen(); + _vm->_graphics->removeBackup(); +} + +void Dialogs::store(byte what, TuneType &played) { + memcpy(played, played + 1, sizeof(played) - 1); + played[30] = what; +} + +bool Dialogs::theyMatch(TuneType &played) { + byte mistakes = 0; + + for (unsigned int i = 0; i < sizeof(played); i++) { + if (played[i] != _vm->kTune[i]) + mistakes++; + } + + return mistakes < 5; +} + +/** + * One of the 3 "Mode" functions passed as ScrollsFunctionType parameters. + * Part of the harp mini-game. + * @remarks Originally called 'music_Scroll' + */ +void Dialogs::scrollModeMusic() { + setReadyLight(3); + _vm->_seeScroll = true; + CursorMan.showMouse(false); + _vm->_graphics->loadMouse(kCurFletch); + + TuneType played; + for (unsigned int i = 0; i < sizeof(played); i++) + played[i] = kPitchInvalid; + int8 lastOne = -1, thisOne = -1; // Invalid values. + + _vm->_seeScroll = true; + + _vm->_graphics->saveScreen(); + _vm->_graphics->showScroll(); + + Common::Event event; + while (!_vm->shouldQuit()) { + _vm->_graphics->refreshScreen(); + + _vm->getEvent(event); + + // When we stop playing? + if ((event.type == Common::EVENT_LBUTTONDOWN) || + ((event.type == Common::EVENT_KEYDOWN) && ((event.kbd.keycode == Common::KEYCODE_RETURN) || (event.kbd.keycode == Common::KEYCODE_ESCAPE)))) { + break; + } + + // When we DO play: + if ((event.type == Common::EVENT_KEYDOWN) + && ((event.kbd.keycode == Common::KEYCODE_q) || (event.kbd.keycode == Common::KEYCODE_w) + || (event.kbd.keycode == Common::KEYCODE_e) || (event.kbd.keycode == Common::KEYCODE_r) + || (event.kbd.keycode == Common::KEYCODE_t) || (event.kbd.keycode == Common::KEYCODE_y) + || (event.kbd.keycode == Common::KEYCODE_u) || (event.kbd.keycode == Common::KEYCODE_i) + || (event.kbd.keycode == Common::KEYCODE_o) || (event.kbd.keycode == Common::KEYCODE_p) + || (event.kbd.keycode == Common::KEYCODE_LEFTBRACKET) || (event.kbd.keycode == Common::KEYCODE_RIGHTBRACKET))) { + byte value; + switch (event.kbd.keycode) { + case Common::KEYCODE_q: + value = 0; + break; + case Common::KEYCODE_w: + value = 1; + break; + case Common::KEYCODE_e: + value = 2; + break; + case Common::KEYCODE_r: + value = 3; + break; + case Common::KEYCODE_t: + value = 4; + break; + case Common::KEYCODE_y: + value = 5; + break; + case Common::KEYCODE_u: + value = 6; + break; + case Common::KEYCODE_i: + value = 7; + break; + case Common::KEYCODE_o: + value = 8; + break; + case Common::KEYCODE_p: + value = 9; + break; + case Common::KEYCODE_LEFTBRACKET: + value = 10; + break; + case Common::KEYCODE_RIGHTBRACKET: + value = 11; + break; + default: + break; + } + + lastOne = thisOne; + thisOne = value; + + _vm->_sound->playNote(_vm->kNotes[thisOne], 100); + _vm->_system->delayMillis(200); + + if (!_vm->_bellsAreRinging) { // These handle playing the right tune. + if (thisOne < lastOne) + store(kPitchLower, played); + else if (thisOne == lastOne) + store(kPitchSame, played); + else + store(kPitchHigher, played); + } + + if (theyMatch(played)) { + setReadyLight(0); + _vm->_timer->addTimer(8, Timer::kProcJacquesWakesUp, Timer::kReasonJacquesWakingUp); + break; + } + } + } + + _vm->_graphics->restoreScreen(); + _vm->_graphics->removeBackup(); + + _vm->_seeScroll = false; + CursorMan.showMouse(true); +} + +void Dialogs::resetScrollDriver() { + _scrollBells = 0; + _currentFont = kFontStyleRoman; + _useIcon = 0; + _vm->_interrogation = 0; // Always reset after a scroll comes up. +} + +/** + * Rings the bell x times + * @remarks Originally called 'dingdongbell' + */ +void Dialogs::ringBell() { + for (int i = 0; i < _scrollBells; i++) + _vm->errorLed(); // Ring the bell "_scrollBells" times. +} + +/** + * This moves the mouse pointer off the scroll so that you can read it. + * @remarks Originally called 'dodgem' + */ +void Dialogs::dodgem() { + _dodgeCoord = _vm->getMousePos(); + g_system->warpMouse(_dodgeCoord.x, _underScroll); // Move the pointer off the scroll. +} + +/** + * This is the opposite of Dodgem. + * It moves the mouse pointer back, IF you haven't moved it in the meantime. + * @remarks Originally called 'undodgem' + */ +void Dialogs::unDodgem() { + Common::Point actCoord = _vm->getMousePos(); + if ((actCoord.x == _dodgeCoord.x) && (actCoord.y == _underScroll)) + g_system->warpMouse(_dodgeCoord.x, _dodgeCoord.y); // No change, so restore the pointer's original position. +} + +void Dialogs::drawScroll(DialogFunctionType modeFunc) { + int16 lx = 0; + int16 ly = (_maxLineNum + 1) * 6; + int16 ex; + for (int i = 0; i <= _maxLineNum; i++) { + ex = _scroll[i].size() * 8; + if (lx < ex) + lx = ex; + } + int16 mx = 320; + int16 my = 100; // Getmaxx & getmaxy div 2, both. + lx /= 2; + ly -= 2; + + if ((1 <= _useIcon) && (_useIcon <= 34)) + lx += kHalfIconWidth; + + CursorMan.showMouse(false); + _vm->_graphics->drawScroll(mx, lx, my, ly); + + mx -= lx; + my -= ly + 2; + + bool centre = false; + + byte iconIndent = 0; + switch (_useIcon) { + case 0: + iconIndent = 0; + break; // No icon. + case 34: + _vm->_graphics->drawSign("about", 28, 76, 15); + iconIndent = 0; + break; + case 35: + _vm->_graphics->drawSign("gameover", 52, 59, 71); + iconIndent = 0; + break; + } + + if ((1 <= _useIcon) && (_useIcon <= 33)) { // Standard icon. + _vm->_graphics->drawIcon(mx, my + ly / 2, _useIcon); + iconIndent = 53; + } + + for (int i = 0; i <= _maxLineNum; i++) { + if (!_scroll[i].empty()) + switch (_scroll[i][_scroll[i].size() - 1]) { + case kControlCenter: + centre = true; + _scroll[i].deleteLastChar(); + break; + case kControlLeftJustified: + centre = false; + _scroll[i].deleteLastChar(); + break; + case kControlQuestion: + _shadowBoxX = mx + lx; + _shadowBoxY = my + ly; + _scroll[i].setChar(' ', 0); + _vm->_graphics->drawShadowBox(_shadowBoxX - 65, _shadowBoxY - 24, _shadowBoxX - 5, _shadowBoxY - 10, "Yes."); + _vm->_graphics->drawShadowBox(_shadowBoxX + 5, _shadowBoxY - 24, _shadowBoxX + 65, _shadowBoxY - 10, "No."); + break; + } + + if (centre) + say(320 - _scroll[i].size() * 4 + iconIndent, my, _scroll[i]); + else + say(mx + iconIndent, my, _scroll[i]); + + my += 12; + } + + _underScroll = (my + 3) * 2; // Multiplying because of the doubled screen height. + ringBell(); + + _vm->_dropsOk = false; + dodgem(); + + (this->*modeFunc)(); + + unDodgem(); + _vm->_dropsOk = true; + + resetScrollDriver(); +} + +void Dialogs::drawBubble(DialogFunctionType modeFunc) { + Common::Point points[3]; + + CursorMan.showMouse(false); + int16 xl = 0; + int16 yl = (_maxLineNum + 1) * 5; + for (int i = 0; i <= _maxLineNum; i++) { + uint16 textWidth = _scroll[i].size() * 8; + if (textWidth > xl) + xl = textWidth; + } + xl /= 2; + + int16 xw = xl + 18; + int16 yw = yl + 7; + int16 my = yw * 2 - 2; + int16 xc = 0; + + if (_talkX - xw < 0) + xc = -(_talkX - xw); + if (_talkX + xw > 639) + xc = 639 - (_talkX + xw); + + // Compute triangle coords for the tail of the bubble + points[0].x = _talkX - 10; + points[0].y = yw; + points[1].x = _talkX + 10; + points[1].y = yw; + points[2].x = _talkX; + points[2].y = _talkY; + + _vm->_graphics->prepareBubble(xc, xw, my, points); + + // Draw the text of the bubble. The centering of the text was improved here compared to Pascal's settextjustify(). + // The font is not the same that outtextxy() uses in Pascal. I don't have that, so I used characters instead. + // It's almost the same, only notable differences are '?', '!', etc. + for (int i = 0; i <= _maxLineNum; i++) { + int16 x = xc + _talkX - _scroll[i].size() / 2 * 8; + bool offset = _scroll[i].size() % 2; + _vm->_graphics->drawScrollText(_scroll[i], _vm->_font, 8, x - offset * 4, (i * 10) + 12, _vm->_graphics->_talkFontColor); + } + + ringBell(); + CursorMan.showMouse(false); + _vm->_dropsOk = false; + + // This does the actual drawing to the screen. + (this->*modeFunc)(); + + _vm->_dropsOk = true; + CursorMan.showMouse(true); // sink; + resetScrollDriver(); +} + +void Dialogs::reset() { + _maxLineNum = 0; + for (int i = 0; i < 15; i++) { + if (!_scroll[i].empty()) + _scroll[i].clear(); + } +} + +/** + * Natural state of bubbles + * @remarks Originally called 'natural' + */ +void Dialogs::setBubbleStateNatural() { + _talkX = 320; + _talkY = 200; + _vm->_graphics->setDialogColor(kColorDarkgray, kColorWhite); +} + +Common::String Dialogs::displayMoney() { + Common::String result; + + if (_vm->_money < 12) { // just pence + result = Common::String::format("%dd", _vm->_money); + } else if (_vm->_money < 240) { // shillings & pence + if ((_vm->_money % 12) == 0) + result = Common::String::format("%d/-", _vm->_money / 12); + else + result = Common::String::format("%d/%d", _vm->_money / 12, _vm->_money % 12); + } else { // L, s & d + result = Common::String::format("\x9C%d.%d.%d", _vm->_money / 240, (_vm->_money / 12) % 20, + _vm->_money % 12); + } + if (_vm->_money > 12) { + Common::String extraStr = Common::String::format(" (that's %dd)", _vm->_money); + result += extraStr; + } + + return result; +} + +/** + * Strip trailing character in a string + * @remarks Originally called 'strip' + */ +void Dialogs::stripTrailingSpaces(Common::String &str) { + while (str.lastChar() == ' ') + str.deleteLastChar(); + // We don't use String::trim() here because we need the leading whitespaces. +} + +/** + * Does the word wrapping. + */ +void Dialogs::solidify(byte n) { + if (!_scroll[n].contains(' ')) + return; // No spaces. + + // So there MUST be a space there, somewhere... + do { + _scroll[n + 1] = _scroll[n][_scroll[n].size() - 1] + _scroll[n + 1]; + _scroll[n].deleteLastChar(); + } while (_scroll[n][_scroll[n].size() - 1] != ' '); + + stripTrailingSpaces(_scroll[n]); +} + +/** + * @remarks Originally called 'calldriver' + * Display text by calling the dialog driver. It unifies the function of the original + * 'calldriver' and 'display' by using Common::String instead of a private buffer. + */ +void Dialogs::displayText(Common::String text) { +// bool was_virtual; // Was the mouse cursor virtual on entry to this proc? + warning("STUB: Scrolls::calldrivers()"); + + _vm->_sound->stopSound(); + + setReadyLight(0); + _scReturn = false; + bool mouthnext = false; + bool callSpriteRun = true; // Only call sprite_run the FIRST time. + + switch (text.lastChar()) { + case kControlToBuffer: + text.deleteLastChar(); + break; // ^D = (D)on't include pagebreak + case kControlSpeechBubble: + case kControlQuestion: + break; // ^B = speech (B)ubble, ^Q = (Q)uestion in dialogue box + default: + text.insertChar(kControlParagraph, text.size()); + } + + for (uint16 i = 0; i < text.size(); i++) { + if (mouthnext) { + if (text[i] == kControlRegister) + _param = 0; + else if (('0' <= text[i]) && (text[i] <= '9')) + _param = text[i] - 48; + else if (('A' <= text[i]) && (text[i] <= 'Z')) + _param = text[i] - 55; + + mouthnext = false; + } else { + switch (text[i]) { + case kControlParagraph: + if ((_maxLineNum == 0) && (_scroll[0].empty())) + break; + + if (callSpriteRun) + _vm->spriteRun(); + callSpriteRun = false; + + drawScroll(&Avalanche::Dialogs::scrollModeNormal); + + reset(); + + if (_scReturn) + return; + break; + case kControlBell: + _scrollBells++; + break; + case kControlSpeechBubble: + if ((_maxLineNum == 0) && (_scroll[0].empty())) + break; + + if (callSpriteRun) + _vm->spriteRun(); + callSpriteRun = false; + + if (_param == 0) + setBubbleStateNatural(); + else if ((1 <= _param) && (_param <= 9)) { + AnimationType *spr = _vm->_animation->_sprites[_param - 1]; + if ((_param > _vm->_animation->kSpriteNumbMax) || (!spr->_quick)) { // Not valid. + _vm->errorLed(); + setBubbleStateNatural(); + } else + spr->chatter(); // Normal sprite talking routine. + } else if ((10 <= _param) && (_param <= 36)) { + // Quasi-peds. (This routine performs the same + // thing with QPs as triptype.chatter does with the + // sprites.) + PedType *quasiPed = &_vm->_peds[kQuasipeds[_param - 10]._whichPed]; + _talkX = quasiPed->_x; + _talkY = quasiPed->_y; // Position. + + _vm->_graphics->setDialogColor(kQuasipeds[_param - 10]._backgroundColor, kQuasipeds[_param - 10]._textColor); + } else { + _vm->errorLed(); // Not valid. + setBubbleStateNatural(); + } + + drawBubble(&Avalanche::Dialogs::scrollModeNormal); + + reset(); + + if (_scReturn) + return; + break; + + // CHECME: The whole kControlNegative block seems completely unused, as the only use (the easter egg check) is a false positive + case kControlNegative: + switch (_param) { + case 1: + displayText(displayMoney() + kControlToBuffer); // Insert cash balance. (Recursion) + break; + case 2: { + int pwdId = _vm->_parser->kFirstPassword + _vm->_passwordNum; + displayText(_vm->_parser->_vocabulary[pwdId]._word + kControlToBuffer); + } + break; + case 3: + displayText(_vm->_favouriteDrink + kControlToBuffer); + break; + case 4: + displayText(_vm->_favouriteSong + kControlToBuffer); + break; + case 5: + displayText(_vm->_worstPlaceOnEarth + kControlToBuffer); + break; + case 6: + displayText(_vm->_spareEvening + kControlToBuffer); + break; + case 9: { + Common::String tmpStr = Common::String::format("%d,%d%c",_vm->_catacombX, _vm->_catacombY, kControlToBuffer); + displayText(tmpStr); + } + break; + case 10: + switch (_vm->_boxContent) { + case 0: // Sixpence. + displayScrollChain('q', 37); // You find the sixpence. + _vm->_money += 6; + _vm->_boxContent = _vm->_parser->kNothing; + _vm->incScore(2); + return; + case Parser::kNothing: + displayText("nothing at all. It's completely empty."); + break; + default: + displayText(_vm->getItem(_vm->_boxContent) + '.'); + } + break; + case 11: + for (int j = 0; j < kObjectNum; j++) { + if (_vm->_objects[j]) + displayText(_vm->getItem(j) + ", " + kControlToBuffer); + } + break; + } + break; + case kControlIcon: + _useIcon = _param; + break; + case kControlNewLine: + _maxLineNum++; + break; + case kControlQuestion: + if (callSpriteRun) + _vm->spriteRun(); + callSpriteRun = false; + + _maxLineNum++; + _scroll[_maxLineNum] = kControlQuestion; + + drawScroll(&Avalanche::Dialogs::scrollModeDialogue); + reset(); + break; + case kControlRegister: + mouthnext = true; + break; + case kControlInsertSpaces: + for (int j = 0; j < 9; j++) + _scroll[_maxLineNum] += ' '; + break; + default: // Add new char. + if (_scroll[_maxLineNum].size() == 50) { + solidify(_maxLineNum); + _maxLineNum++; + } + _scroll[_maxLineNum] += text[i]; + break; + } + } + } +} + +void Dialogs::setTalkPos(int16 x, int16 y) { + _talkX = x; + _talkY = y; +} + +int16 Dialogs::getTalkPosX() { + return _talkX; +} + +bool Dialogs::displayQuestion(Common::String question) { + displayText(question + kControlNewLine + kControlQuestion); + + if (_scReturn && (_vm->_rnd->getRandomNumber(1) == 0)) { // Half-and-half chance. + Common::String tmpStr = Common::String::format("...Positive about that?%cI%c%c%c", kControlRegister, kControlIcon, kControlNewLine, kControlQuestion); + displayText(tmpStr); // Be annoying! + if (_scReturn && (_vm->_rnd->getRandomNumber(3) == 3)) { // Another 25% chance + // \? are used to avoid that ??! is parsed as a trigraph + tmpStr = Common::String::format("%c100%% certain\?\?!%c%c%c%c", kControlInsertSpaces, kControlInsertSpaces, kControlIcon, kControlNewLine, kControlQuestion); + displayText(tmpStr); // Be very annoying! + } + } + + return _scReturn; +} + +void Dialogs::loadFont() { + Common::File file; + + if (!file.open("avalot.fnt")) + error("AVALANCHE: Scrolls: File not found: avalot.fnt"); + + for (int16 i = 0; i < 256; i++) + file.read(_fonts[0][i], 16); + file.close(); + + if (!file.open("avitalic.fnt")) + error("AVALANCHE: Scrolls: File not found: avitalic.fnt"); + + for (int16 i = 0; i < 256; i++) + file.read(_fonts[1][i], 16); + file.close(); + + if (!file.open("ttsmall.fnt")) + error("AVALANCHE: Scrolls: File not found: ttsmall.fnt"); + + for (int16 i = 0; i < 256; i++) + file.read(_vm->_font[i],16); + file.close(); +} + +/** + * Practically this one is a mini-game which called when you play the harp in the monastery. + * @remarks Originally called 'musical_scroll' + */ +void Dialogs::displayMusicalScroll() { + Common::String tmpStr = Common::String::format("To play the harp...%c%cUse these keys:%c%cQ W E R T Y U I O P [ ]%c%cOr press Enter to stop playing.%c", + kControlNewLine, kControlNewLine, kControlNewLine, kControlInsertSpaces, kControlNewLine, kControlNewLine, kControlToBuffer); + displayText(tmpStr); + + _vm->spriteRun(); + CursorMan.showMouse(false); + drawScroll(&Avalanche::Dialogs::scrollModeMusic); + CursorMan.showMouse(true); + reset(); +} + +void Dialogs::unSkrimble(Common::String &text) { + for (uint16 i = 0; i < text.size(); i++) + text.setChar((~(text[i] - (i + 1))) % 256, i); +} + +void Dialogs::doTheBubble(Common::String &text) { + text.insertChar(kControlSpeechBubble, text.size()); + assert(text.size() < 2000); +} + +/** + * Display a string in a scroll + * @remarks Originally called 'dixi' + */ +void Dialogs::displayScrollChain(char block, byte point, bool report, bool bubbling) { + Common::File indexfile; + if (!indexfile.open("avalot.idx")) + error("AVALANCHE: Visa: File not found: avalot.idx"); + + bool error = false; + + indexfile.seek((toupper(block) - 65) * 2); + uint16 idx_offset = indexfile.readUint16LE(); + if (idx_offset == 0) + error = true; + + indexfile.seek(idx_offset + point * 2); + uint16 sez_offset = indexfile.readUint16LE(); + if (sez_offset == 0) + error = true; + + indexfile.close(); + + _noError = !error; + + if (error) { + if (report) { + Common::String todisplay = Common::String::format("%cError accessing scroll %c%d", kControlBell, block, point); + displayText(todisplay); + } + return; + } + + Common::File sezfile; + if (!sezfile.open("avalot.sez")) + ::error("AVALANCHE: Visa: File not found: avalot.sez"); + + sezfile.seek(sez_offset); + uint16 _bufSize = sezfile.readUint16LE(); + assert(_bufSize < 2000); + char *_buffer = new char[_bufSize]; + sezfile.read(_buffer, _bufSize); + sezfile.close(); + Common::String text(_buffer, _bufSize); + delete[] _buffer; + + unSkrimble(text); + if (bubbling) + doTheBubble(text); + displayText(text); +} + +/** + * Start speech + * @remarks Originally called 'speech' + */ +void Dialogs::speak(byte who, byte subject) { + if (subject == 0) { // No subject. + displayScrollChain('s', who, false, true); + return; + } + + // Subject given. + _noError = false; // Assume that until we know otherwise. + + Common::File indexfile; + if (!indexfile.open("converse.avd")) + error("AVALANCHE: Visa: File not found: converse.avd"); + + indexfile.seek(who * 2 - 2); + uint16 idx_offset = indexfile.readUint16LE(); + uint16 next_idx_offset = indexfile.readUint16LE(); + + if ((idx_offset == 0) || ((((next_idx_offset - idx_offset) / 2) - 1) < subject)) + return; + + indexfile.seek(idx_offset + subject * 2); + uint16 sezOffset = indexfile.readUint16LE(); + if ((sezOffset == 0) || (indexfile.err())) + return; + indexfile.close(); + + Common::File sezfile; + if (!sezfile.open("avalot.sez")) + error("AVALANCHE: Visa: File not found: avalot.sez"); + + sezfile.seek(sezOffset); + uint16 _bufSize = sezfile.readUint16LE(); + assert(_bufSize < 2000); + char *_buffer = new char[_bufSize]; + sezfile.read(_buffer, _bufSize); + sezfile.close(); + Common::String text(_buffer, _bufSize); + delete[] _buffer; + + unSkrimble(text); + doTheBubble(text); + displayText(text); + + _noError = true; +} + +void Dialogs::talkTo(byte whom) { + if (_vm->_parser->_person == kPeoplePardon) { + _vm->_parser->_person = (People)_vm->_subjectNum; + _vm->_subjectNum = 0; + } + + if (_vm->_subjectNum == 0) { + switch (whom) { + case kPeopleSpludwick: + if ((_vm->_lustieIsAsleep) & (!_vm->_objects[kObjectPotion - 1])) { + displayScrollChain('q', 68); + _vm->_objects[kObjectPotion - 1] = true; + _vm->refreshObjectList(); + _vm->incScore(3); + return; + } else if (_vm->_talkedToCrapulus) { + // Spludwick - what does he need? + // 0 - let it through to use normal routine. + switch (_vm->_givenToSpludwick) { + case 1: // Fallthrough is intended. + case 2: { + Common::String objStr = _vm->getItem(AvalancheEngine::kSpludwicksOrder[_vm->_givenToSpludwick]); + Common::String tmpStr = Common::String::format("Can you get me %s, please?%c2%c", + objStr.c_str(), kControlRegister, kControlSpeechBubble); + displayText(tmpStr); + } + return; + case 3: + displayScrollChain('q', 30); // Need any help with the game? + return; + } + } else { + displayScrollChain('q', 42); // Haven't talked to Crapulus. Go and talk to him. + return; + } + break; + case kPeopleIbythneth: + if (_vm->_givenBadgeToIby) { + displayScrollChain('q', 33); // Thanks a lot! + return; // And leave the proc. + } + break; // Or... just continue, 'cos he hasn't got it. + case kPeopleDogfood: + if (_vm->_wonNim) { // We've won the game. + displayScrollChain('q', 6); // "I'm Not Playing!" + return; // Zap back. + } else + _vm->_askedDogfoodAboutNim = true; + break; + case kPeopleAyles: + if (!_vm->_aylesIsAwake) { + displayScrollChain('q', 43); // He's fast asleep! + return; + } else if (!_vm->_givenPenToAyles) { + displayScrollChain('q', 44); // Can you get me a pen, Avvy? + return; + } + break; + + case kPeopleJacques: + displayScrollChain('q', 43); + return; + + case kPeopleGeida: + if (_vm->_givenPotionToGeida) + _vm->_geidaFollows = true; + else { + displayScrollChain('u', 17); + return; + } + break; + case kPeopleSpurge: + if (!_vm->_sittingInPub) { + displayScrollChain('q', 71); // Try going over and sitting down. + return; + } else { + if (_vm->_spurgeTalkCount < 5) + _vm->_spurgeTalkCount++; + if (_vm->_spurgeTalkCount > 1) { // no. 1 falls through + displayScrollChain('q', 70 + _vm->_spurgeTalkCount); + return; + } + } + break; + } + // On a subject. Is there any reason to block it? + } else if ((whom == kPeopleAyles) && (!_vm->_aylesIsAwake)) { + displayScrollChain('q', 43); // He's fast asleep! + return; + } + + if (whom > 149) + whom -= 149; + + bool noMatches = true; + for (int i = 0; i < _vm->_animation->kSpriteNumbMax; i++) { + if (_vm->_animation->_sprites[i]->_characterId == whom) { + Common::String tmpStr = Common::String::format("%c%c%c", kControlRegister, i + 49, kControlToBuffer); + displayText(tmpStr); + noMatches = false; + break; + } + } + + if (noMatches) { + Common::String tmpStr = Common::String::format("%c%c%c", kControlRegister, kControlRegister, kControlToBuffer); + displayText(tmpStr); + } + + speak(whom, _vm->_subjectNum); + + if (!_noError) + displayScrollChain('n', whom); // File not found! + + if ((_vm->_subjectNum == 0) && ((whom + 149) == kPeopleCrapulus)) { // Crapulus: get the badge - first time only + _vm->_objects[kObjectBadge - 1] = true; + _vm->refreshObjectList(); + displayScrollChain('q', 1); // Circular from Cardiff. + _vm->_talkedToCrapulus = true; + _vm->setRoom(kPeopleCrapulus, kRoomDummy); // Crapulus walks off. + + AnimationType *spr = _vm->_animation->_sprites[1]; + spr->_vanishIfStill = true; + spr->walkTo(2); // Walks away. + + _vm->incScore(2); + } +} + +/** + * This makes Avalot say the response. + * @remarks Originally called 'sayit' + */ +void Dialogs::sayIt(Common::String str) { + Common::String x = str; + x.setChar(toupper(x[0]), 0); + Common::String tmpStr = Common::String::format("%c1%s.%c%c2", kControlRegister, x.c_str(), kControlSpeechBubble, kControlRegister); + displayText(tmpStr); +} + +Common::String Dialogs::personSpeaks() { + if ((_vm->_parser->_person == kPeoplePardon) || (_vm->_parser->_person == kPeopleNone)) { + if ((_vm->_him == kPeoplePardon) || (_vm->getRoom(_vm->_him) != _vm->_room)) + _vm->_parser->_person = _vm->_her; + else + _vm->_parser->_person = _vm->_him; + } + + if (_vm->getRoom(_vm->_parser->_person) != _vm->_room) { + return Common::String::format("%c1", kControlRegister); // Avvy himself! + } + + bool found = false; // The _person we're looking for's code is in _person. + Common::String tmpStr; + + for (int i = 0; i < _vm->_animation->kSpriteNumbMax; i++) { + AnimationType *curSpr = _vm->_animation->_sprites[i]; + if (curSpr->_quick && (curSpr->_characterId + 149 == _vm->_parser->_person)) { + tmpStr += Common::String::format("%c%c", kControlRegister, '1' + i); + found = true; + } + } + + if (found) + return tmpStr; + + for (int i = 0; i < 16; i++) { + if ((kQuasipeds[i]._who == _vm->_parser->_person) && (kQuasipeds[i]._room == _vm->_room)) + tmpStr += Common::String::format("%c%c", kControlRegister, 'A' + i); + } + + return tmpStr; +} + +/** + * Display a message when (uselessly) giving an object away + * @remarks Originally called 'heythanks' + */ +void Dialogs::sayThanks(byte thing) { + Common::String tmpStr = personSpeaks(); + tmpStr += Common::String::format("Hey, thanks!%c(But now, you've lost it!)", kControlSpeechBubble); + displayText(tmpStr); + _vm->_objects[thing] = false; +} + +/** + * Display a 'Hello' message + */ +void Dialogs::sayHello() { + Common::String tmpStr = personSpeaks(); + tmpStr += Common::String::format("Hello.%c", kControlSpeechBubble); + displayText(tmpStr); +} + +/** + * Display a 'OK' message + */ +void Dialogs::sayOK() { + Common::String tmpStr = personSpeaks(); + tmpStr += Common::String::format("That's OK.%c", kControlSpeechBubble); + displayText(tmpStr); +} + +/** + * Display a 'Silly' message + * @remarks Originally called 'silly' + */ +void Dialogs::saySilly() { + displayText("Don't be silly!"); +} + +} // End of namespace Avalanche diff --git a/engines/avalanche/dialogs.h b/engines/avalanche/dialogs.h new file mode 100644 index 0000000000..43e6a4fec6 --- /dev/null +++ b/engines/avalanche/dialogs.h @@ -0,0 +1,116 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on the original source code of Lord Avalot d'Argent version 1.3. + * Copyright (c) 1994-1995 Mike, Mark and Thomas Thurman. + */ + + /* SCROLLS The scroll driver. */ + +#ifndef AVALANCHE_DIALOGS_H +#define AVALANCHE_DIALOGS_H + +namespace Avalanche { +class AvalancheEngine; + +class Dialogs; + +typedef void (Dialogs::*DialogFunctionType)(); + +class Dialogs { +public: + bool _aboutBox; // Is this the about box? - Used in scrollModeNormal(), not yet fully implemented + FontType _fonts[2]; + + Dialogs(AvalancheEngine *vm); + + void init(); + void reset(); + void setReadyLight(byte state); + void displayText(Common::String text); + bool displayQuestion(Common::String question); + void setTalkPos(int16 x, int16 y); + int16 getTalkPosX(); + void setBubbleStateNatural(); + void displayMusicalScroll(); + void displayScrollChain(char block, byte point, bool report = true, bool bubbling = false); + void talkTo(byte whom); + void sayIt(Common::String str); + Common::String personSpeaks(); + void sayThanks(byte thing); + void sayHello(); + void sayOK(); + void saySilly(); +private: + AvalancheEngine *_vm; + int16 _talkX, _talkY; + + enum FontStyle { + kFontStyleRoman, + kFontStyleItalic + }; + + static const int16 kHalfIconWidth = 19; + static const QuasipedType kQuasipeds[16]; + + Common::String _scroll[15]; + Common::Point _dodgeCoord; + byte _maxLineNum; + bool _scReturn; + bool _noError; + byte _currentFont; + byte _param; // For using arguments code + byte _useIcon; + byte _scrollBells; // no. of times to ring the bell + int16 _underScroll; // Y-coord of just under the scroll text. + int16 _shadowBoxX, _shadowBoxY; + + void drawBubble(DialogFunctionType modeFunc); + void drawScroll(DialogFunctionType modeFunc); + void scrollModeNormal(); + void scrollModeDialogue(); + void scrollModeMusic(); + + // These 2 are used only in musicalScroll(). + void store(byte what, TuneType &played); + bool theyMatch(TuneType &played); + void stripTrailingSpaces(Common::String &str); + void solidify(byte n); + void dodgem(); + void unDodgem(); + + Common::String displayMoney(); + void easterEgg(); + void say(int16 x, int16 y, Common::String text); + void resetScrollDriver(); + void ringBell(); + void loadFont(); + + void unSkrimble(Common::String &text); + void doTheBubble(Common::String &text); + void speak(byte who, byte subject); +}; + +} // End of namespace Avalanche + +#endif // AVALANCHE_DIALOGS_H diff --git a/engines/avalanche/enums.h b/engines/avalanche/enums.h new file mode 100644 index 0000000000..604c62de84 --- /dev/null +++ b/engines/avalanche/enums.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 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on the original source code of Lord Avalot d'Argent version 1.3. + * Copyright (c) 1994-1995 Mike, Mark and Thomas Thurman. + */ + +#ifndef AVALANCHE_ENUMS_H +#define AVALANCHE_ENUMS_H + +namespace Avalanche { +enum Color { + kColorBlack = 0, kColorBlue, kColorGreen, kColorCyan, kColorRed, + kColorMagenta = 5, kColorBrown, kColorLightgray, kColorDarkgray, kColorLightblue, + kColorLightgreen = 10, kColorLightcyan, kColorLightred, kColorLightmagenta, kColorYellow, + kColorWhite = 15 +}; + +// CHECKME: kRoomBossKey is a guess +enum Room { + kRoomNowhere = 0, kRoomYours = 1, kRoomOutsideYours = 2, kRoomOutsideSpludwicks = 3, + kRoomYourHall = 5, kRoomMusicRoom = 7, kRoomOutsideArgentPub = 9, kRoomArgentRoad = 10, + kRoomWiseWomans = 11, kRoomSpludwicks = 12, kRoomInsideAbbey = 13, kRoomOutsideAbbey = 14, + kRoomAvvysGarden = 15, kRoomAylesOffice = 16, kRoomArgentPub = 19, kRoomBrummieRoad = 20, + kRoomBridge = 21, kRoomLusties = 22, kRoomLustiesRoom = 23, kRoomWestHall = 25, + kRoomEastHall = 26, kRoomOubliette = 27, kRoomGeidas = 28, kRoomCatacombs = 29, + kRoomEntranceHall = 40, kRoomRobins = 42, kRoomOutsideNottsPub = 46, kRoomNottsPub = 47, + kRoomOutsideDucks = 50, kRoomDucks = 51, kRoomOutsideCardiffCastle = 70, kRoomInsideCardiffCastle = 71, + kRoomBossKey = 98, kRoomMap = 99, kRoomDummy = 177 // Dummy room +}; + +// Objects you can hold: +enum Object { + kObjectWine = 1, kObjectMoney, kObjectBodkin, kObjectPotion, kObjectChastity, + kObjectBolt, kObjectCrossbow, kObjectLute, kObjectBadge, kObjectMushroom, + kObjectKey, kObjectBell, kObjectPrescription, kObjectPen, kObjectInk, + kObjectClothes, kObjectHabit, kObjectOnion, kObjectDummy = 177 +}; + +// People who hang around this game. +enum People { + // Boys: + kPeopleAvalot = 150, kPeopleSpludwick = 151, kPeopleCrapulus = 152, kPeopleDrDuck = 153, + kPeopleMalagauche = 154, kPeopleFriarTuck = 155, kPeopleRobinHood = 156, kPeopleCwytalot = 157, + kPeopleDuLustie = 158, kPeopleDuke = 159, kPeopleDogfood = 160, kPeopleTrader = 161, + kPeopleIbythneth = 162, kPeopleAyles = 163, kPeoplePort = 164, kPeopleSpurge = 165, + kPeopleJacques = 166, + // Girls: + kPeopleArkata = 175, kPeopleGeida = 176, kPeopleInvisible = 177, kPeopleWisewoman = 178, + // + kPeoplePardon = 254, kPeopleNone = 0 +}; + +enum VerbCode { + kVerbCodeExam = 1, kVerbCodeOpen = 2, kVerbCodePause = 3, kVerbCodeGet = 4, kVerbCodeDrop = 5, + kVerbCodeInv = 6, kVerbCodeTalk = 7, kVerbCodeGive = 8, kVerbCodeDrink = 9, kVerbCodeLoad = 10, + kVerbCodeSave = 11, kVerbCodePay = 12, kVerbCodeLook = 13, kVerbCodeBreak = 14, kVerbCodeQuit = 15, + kVerbCodeSit = 16, kVerbCodeStand = 17, kVerbCodeGo = 18, kVerbCodeInfo = 19, kVerbCodeUndress = 20, + kVerbCodeWear = 21, kVerbCodePlay = 22, kVerbCodeRing = 23, kVerbCodeHelp = 24, kVerbCodeLarrypass = 25, + kVerbCodePhaon = 26, kVerbCodeBoss = 27, kVerbCodePee = 28, kVerbCodeCheat = 29, kVerbCodeMagic = 30, + kVerbCodeRestart = 31, kVerbCodeEat = 32, kVerbCodeListen = 33, kVerbCodeBuy = 34, kVerbCodeAttack = 35, + kVerbCodePasswd = 36, kVerbCodeDir = 37, kVerbCodeDie = 38, kVerbCodeScore = 39, kVerbCodePut = 40, + kVerbCodeKiss = 41, kVerbCodeClimb = 42, kVerbCodeJump = 43, kVerbCodeHiscores = 44, kVerbCodeWake = 45, + kVerbCodeHello = 46, kVerbCodeThanks = 47, + kVerbCodeSmartAlec = 249, kVerbCodeExpletive = 253, kVerbCodePardon = 254 +}; + +enum MouseCursor { + kCurUpArrow = 0, kCurScrewDriver = 1, kCurRightArrow = 2, kCurFletch = 3, kCurWait = 4, kCurHand = 5, + kCurCrosshair = 6, kCurIBeam = 7 +}; + +// Magic/portal constants: +enum Magics { + kMagicNothing, // Ignore it if this line is touched. + kMagicBounce, // Bounce off this line. Not valid for portals. + kMagicExclaim, // Put up a chain of scrolls. + kMagicTransport, // Enter new room. + kMagicUnfinished, // Unfinished connection. + kMagicSpecial, // Special function. + kMagicOpenDoor // Opening door. +}; + +// Constants to replace the command characters from Pascal. +// For more information, see: https://github.com/urukgit/avalot/wiki/Scrolldrivers +enum ControlCharacter { + kControlSpeechBubble = 2, // ^B + kControlCenter = 3, // ^C + kControlToBuffer = 4, // ^D + kControlItalic = 6, // ^F + kControlBell = 7, // ^G + kControlBackspace = 8, // ^H + kControlInsertSpaces = 9, // ^I + kControlLeftJustified = 12, // ^L + kControlNewLine = 13, // ^M + kControlParagraph = 16, // ^P + kControlQuestion = 17, // ^Q + kControlRoman = 18, // ^R + kControlRegister = 19, // ^S + kControlNegative = 21, // ^U + kControlIcon = 22 // ^V +}; + +static const int16 kScreenWidth = 640; +static const int16 kScreenHeight = 200; + +static const int16 kWalk = 3; +static const int16 kRun = 5; + + +} // End of namespace Avalanche + +#endif // AVALANCHE_ENUMS_H diff --git a/engines/avalanche/graphics.cpp b/engines/avalanche/graphics.cpp new file mode 100644 index 0000000000..25b01d65f3 --- /dev/null +++ b/engines/avalanche/graphics.cpp @@ -0,0 +1,767 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on the original source code of Lord Avalot d'Argent version 1.3. + * Copyright (c) 1994-1995 Mike, Mark and Thomas Thurman. + */ + +#include "avalanche/avalanche.h" +#include "avalanche/graphics.h" + +#include "engines/util.h" +#include "graphics/palette.h" + +namespace Avalanche { + +const byte GraphicManager::kEgaPaletteIndex[16] = {0, 1, 2, 3, 4, 5, 20, 7, 56, 57, 58, 59, 60, 61, 62, 63}; + +const MouseHotspotType GraphicManager::kMouseHotSpots[9] = { + {8,0}, // 0 - up-arrow + {0,0}, // 1 - screwdriver + {15,6}, // 2 - right-arrow + {0,0}, // 3 - fletch + {8,7}, // 4 - hourglass + {4,0}, // 5 - TTHand + {8,5}, // 6 - Mark's crosshairs + {8,7}, // 7 - I-beam + {0,0} // 8 - question mark +}; + +GraphicManager::GraphicManager(AvalancheEngine *vm) { + _vm = vm; +} + +GraphicManager::~GraphicManager() { + _surface.free(); + _magics.free(); + _background.free(); + _screen.free(); + _scrolls.free(); + _backup.free(); + + for (int i = 0; i < 10; i++) + _digits[i].free(); + for (int i = 0; i < 9; i++) + _directions[i].free(); +} + +void GraphicManager::init() { + initGraphics(kScreenWidth, kScreenHeight * 2, true); // Doubling the height. + + for (int i = 0; i < 64; ++i) { + _egaPalette[i][0] = (i >> 2 & 1) * 0xaa + (i >> 5 & 1) * 0x55; + _egaPalette[i][1] = (i >> 1 & 1) * 0xaa + (i >> 4 & 1) * 0x55; + _egaPalette[i][2] = (i & 1) * 0xaa + (i >> 3 & 1) * 0x55; + } + + for (int i = 0; i < 16; i++) + g_system->getPaletteManager()->setPalette(_egaPalette[kEgaPaletteIndex[i]], i, 1); + + // Set the "flesh colors": + g_system->getPaletteManager()->setPalette(_egaPalette[39], 13, 1); + g_system->getPaletteManager()->setPalette(_egaPalette[28], 5, 1); + + _surface.create(kScreenWidth, kScreenHeight, Graphics::PixelFormat::createFormatCLUT8()); + _magics.create(kScreenWidth, kScreenHeight, Graphics::PixelFormat::createFormatCLUT8()); + _screen.create(kScreenWidth, kScreenHeight * 2, Graphics::PixelFormat::createFormatCLUT8()); + _scrolls.create(kScreenWidth, kScreenHeight, Graphics::PixelFormat::createFormatCLUT8()); +} + +/** + * Load the scoring digits & rwlites + * @remarks Originally called 'load_digits' + */ +void GraphicManager::loadDigits() { + const byte digitsize = 134; + const byte rwlitesize = 126; + + Common::File file; + if (!file.open("digit.avd")) + error("AVALANCHE: File not found: digit.avd"); + + for (int i = 0; i < 10; i++) { + file.seek(i * digitsize); + _digits[i] = loadPictureGraphic(file); + } + + for (int i = 0; i < 9; i++) { + file.seek(10 * digitsize + i * rwlitesize); + _directions[i] = loadPictureGraphic(file); + } + + file.close(); +} + +void GraphicManager::loadMouse(byte which) { + if (which == _vm->_currentMouse) + return; + + _vm->_currentMouse = which; + + Common::File f; + if (!f.open("mice.avd")) + error("AVALANCHE: Gyro: File not found: mice.avd"); + + Graphics::Surface cursor; + cursor.create(16, 32, Graphics::PixelFormat::createFormatCLUT8()); + cursor.fillRect(Common::Rect(0, 0, 16, 32), 255); + + + // The AND mask. + f.seek(kMouseSize * 2 * which + 134); + + Graphics::Surface mask = loadPictureGraphic(f); + + for (int j = 0; j < mask.h; j++) { + for (int i = 0; i < mask.w; i++) { + byte pixel = *(byte *)mask.getBasePtr(i, j); + if (pixel == 0) { + *(byte *)cursor.getBasePtr(i, j * 2 ) = 0; + *(byte *)cursor.getBasePtr(i, j * 2 + 1) = 0; + } + } + } + + mask.free(); + + // The OR mask. + f.seek(kMouseSize * 2 * which + 134 * 2); + + mask = loadPictureGraphic(f); + + for (int j = 0; j < mask.h; j++) { + for (int i = 0; i < mask.w; i++) { + byte pixel = *(byte *)mask.getBasePtr(i, j); + if (pixel != 0) { + *(byte *)cursor.getBasePtr(i, j * 2 ) = pixel; + *(byte *)cursor.getBasePtr(i, j * 2 + 1) = pixel; + } + } + } + + mask.free(); + f.close(); + + CursorMan.replaceCursor(cursor.getPixels(), 16, 32, kMouseHotSpots[which]._horizontal, kMouseHotSpots[which]._vertical * 2, 255, false); + cursor.free(); +} + +void GraphicManager::drawThinkPic(Common::String filename, int id) { + static const int16 picSize = 966; + Common::File file; + if (!file.open(filename)) + error("drawThinkPic(): File not found: %s", filename.c_str()); + + file.seek(id * picSize + 65); + Graphics::Surface picture = loadPictureGraphic(file); + drawPicture(_surface, picture, 205, 170); + + picture.free(); + file.close(); +} + +void GraphicManager::drawToolbar() { + Common::File file; + if (!file.open("useful.avd")) + error("drawToolbar(): File not found: useful.avd"); + + file.seek(40); + + CursorMan.showMouse(false); + Graphics::Surface picture = loadPictureGraphic(file); + drawPicture(_surface, picture, 5, 169); + CursorMan.showMouse(true); + + picture.free(); + file.close(); +} + +Common::Point GraphicManager::drawArc(Graphics::Surface &surface, int16 x, int16 y, int16 stAngle, int16 endAngle, uint16 radius, Color color) { + Common::Point endPoint; + const float convfac = M_PI / 180.0; + + int32 xRadius = radius; + int32 yRadius = radius * kScreenWidth / (8 * kScreenHeight); // Just don't ask why... + + if (xRadius == 0) + xRadius++; + if (yRadius == 0) + yRadius++; + + // Check for an ellipse with negligable x and y radius. + if ((xRadius <= 1) && (yRadius <= 1)) { + *(byte *)_scrolls.getBasePtr(x, y) = color; + endPoint.x = x; + endPoint.y = y; + return endPoint; + } + + // Check if valid angles. + stAngle = stAngle % 361; + endAngle = endAngle % 361; + + // If impossible angles, then swap them! + if (endAngle < stAngle) { + uint16 tmpAngle=endAngle; + endAngle=stAngle; + stAngle=tmpAngle; + } + + // Approximate the number of pixels required by using the circumference equation of an ellipse. + uint16 numOfPixels = (uint16)floor(sqrt(3.0) * sqrt(pow(double(xRadius), 2) + pow(double(yRadius), 2)) + 0.5); + + // Calculate the angle precision required. + float delta = 90.0 / numOfPixels; + + // Always just go over the first 90 degrees. Could be optimized a + // bit if startAngle and endAngle lie in the same quadrant, left as an + // exercise for the reader. :) + float j = 0; + + // Calculate stop position, go 1 further than 90 because otherwise 1 pixel is sometimes not drawn. + uint16 deltaEnd = 91; + + // Set the end point. + float tempTerm = endAngle * convfac; + endPoint.x = (int16)floor(xRadius * cos(tempTerm) + 0.5) + x; + endPoint.y = (int16)floor(yRadius * sin(tempTerm + M_PI) + 0.5) + y; + + // Calculate points. + int16 xNext = xRadius; + int16 yNext = 0; + do { + int16 xTemp = xNext; + int16 yTemp = yNext; + // This is used by both sin and cos. + tempTerm = (j + delta) * convfac; + + xNext = (int16)floor(xRadius * cos(tempTerm) + 0.5); + yNext = (int16)floor(yRadius * sin(tempTerm + M_PI) + 0.5); + + int16 xp = x + xTemp; + int16 xm = x - xTemp; + int16 yp = y + yTemp; + int16 ym = y - yTemp; + + if ((j >= stAngle) && (j <= endAngle)) + *(byte *)_scrolls.getBasePtr(xp, yp) = color; + + if (((180 - j) >= stAngle) && ((180 - j) <= endAngle)) + *(byte *)_scrolls.getBasePtr(xm, yp) = color; + + if (((j + 180) >= stAngle) && ((j + 180) <= endAngle)) + *(byte *)_scrolls.getBasePtr(xm, ym) = color; + + if (((360 - j) >= stAngle) && ((360 - j) <= endAngle)) + *(byte *)_scrolls.getBasePtr(xp, ym) = color; + + j += delta; + } while (j <= deltaEnd); + + return endPoint; +} + +Common::Point GraphicManager::drawScreenArc(int16 x, int16 y, int16 stAngle, int16 endAngle, uint16 radius, Color color) { + return drawArc(_surface, x, y, stAngle, endAngle, radius, color); +} + +void GraphicManager::drawPieSlice(int16 x, int16 y, int16 stAngle, int16 endAngle, uint16 radius, Color color) { + while (radius > 0) + drawArc(_scrolls, x, y, stAngle, endAngle, radius--, color); +} + +void GraphicManager::drawTriangle(Common::Point *p, Color color) { + // Draw the borders with a marking color. + _scrolls.drawLine(p[0].x, p[0].y, p[1].x, p[1].y, 255); + _scrolls.drawLine(p[1].x, p[1].y, p[2].x, p[2].y, 255); + _scrolls.drawLine(p[2].x, p[2].y, p[0].x, p[0].y, 255); + + // Get the top and the bottom of the triangle. + uint16 maxY = p[0].y, minY = p[0].y; + for (int i = 1; i < 3; i++) { + if (p[i].y < minY) + minY = p[i].y; + if (p[i].y > maxY) + maxY = p[i].y; + } + + // Fill the triangle. + for (uint16 y = minY; y <= maxY; y++) { + uint16 x = 0; + while (*(byte *)_scrolls.getBasePtr(x, y) != 255) + x++; + uint16 minX = x; + uint16 maxX = x; + x++; + while ((*(byte *)_scrolls.getBasePtr(x, y) != 255) && (x != 639)) + x++; + if (x != 639) + maxX = x; + if (minX != maxX) + _scrolls.drawLine(minX, y, maxX, y, color); + } + + // Redraw the borders with the actual color. + _scrolls.drawLine(p[0].x, p[0].y, p[1].x, p[1].y, color); + _scrolls.drawLine(p[1].x, p[1].y, p[2].x, p[2].y, color); + _scrolls.drawLine(p[2].x, p[2].y, p[0].x, p[0].y, color); +} + +void GraphicManager::drawText(Graphics::Surface &surface, const Common::String text, FontType font, byte fontHeight, int16 x, int16 y, Color color) { + for (uint i = 0; i < text.size(); i++) { + for (int j = 0; j < fontHeight; j++) { + byte pixel = font[(byte)text[i]][j]; + for (int bit = 0; bit < 8; bit++) { + byte pixelBit = (pixel >> bit) & 1; + if (pixelBit) + *(byte *)surface.getBasePtr(x + i * 8 + 7 - bit, y + j) = color; + } + } + } +} + +void GraphicManager::drawNormalText(const Common::String text, FontType font, byte fontHeight, int16 x, int16 y, Color color) { + drawText(_surface, text, font, fontHeight, x, y, color); +} + +void GraphicManager::drawScrollText(const Common::String text, FontType font, byte fontHeight, int16 x, int16 y, Color color) { + drawText(_scrolls, text, font, fontHeight, x, y, color); +} + +void GraphicManager::drawDigit(int index, int x, int y) { + drawPicture(_surface, _digits[index], x, y); +} + +void GraphicManager::drawDirection(int index, int x, int y) { + drawPicture(_surface, _directions[index], x, y); +} + +void GraphicManager::drawScrollShadow(int16 x1, int16 y1, int16 x2, int16 y2) { + for (byte i = 0; i < 2; i ++) { + _scrolls.fillRect(Common::Rect(x1 + i, y1 + i, x1 + i + 1, y2 - i), kColorWhite); + _scrolls.fillRect(Common::Rect(x1 + i, y1 + i, x2 - i, y1 + i + 1), kColorWhite); + + _scrolls.fillRect(Common::Rect(x2 - i, y1 + i, x2 - i + 1, y2 - i + 1), kColorDarkgray); + _scrolls.fillRect(Common::Rect(x1 + i, y2 - i, x2 - i, y2 - i + 1), kColorDarkgray); + } +} + +void GraphicManager::drawShadowBox(int16 x1, int16 y1, int16 x2, int16 y2, Common::String text) { + CursorMan.showMouse(false); + + drawScrollShadow(x1, y1, x2, y2); + + bool offset = text.size() % 2; + x1 = (x2 - x1) / 2 + x1 - text.size() / 2 * 8 - offset * 3; + y1 = (y2 - y1) / 2 + y1 - 4; + drawScrollText(text, _vm->_font, 8, x1, y1, kColorBlue); + drawScrollText(Common::String('_'), _vm->_font, 8, x1, y1, kColorBlue); + + CursorMan.showMouse(true); +} + +void GraphicManager::drawMenuBar(Color color) { + _surface.fillRect(Common::Rect(0, 0, 640, 10), color); +} + +void GraphicManager::drawMenuBlock(int x1, int y1, int x2, int y2, Color color) { + _surface.fillRect(Common::Rect(x1, y1, x2, y2), color); +} + +void GraphicManager::drawMenuItem(int x1, int y1, int x2, int y2) { + _surface.fillRect(Common::Rect(x1, y1, x2, y2), kMenuBackgroundColor); + _surface.frameRect(Common::Rect(x1 - 1, y1 - 1, x2 + 1, y2 + 1), kMenuBorderColor); +} + +void GraphicManager::drawSpeedBar(int speed) { + if (speed == kRun) { + _surface.drawLine(336, 199, 338, 199, kColorLightblue); + _surface.drawLine(371, 199, 373, 199, kColorYellow); + } else { + _surface.drawLine(371, 199, 373, 199, kColorLightblue); + _surface.drawLine(336, 199, 338, 199, kColorYellow); + } +} +void GraphicManager::drawScroll(int mx, int lx, int my, int ly) { + _scrolls.copyFrom(_surface); + + // The right corners of the scroll. + drawPieSlice(mx + lx, my - ly, 0, 90, 15, kColorLightgray); + drawPieSlice(mx + lx, my + ly, 270, 360, 15, kColorLightgray); + drawArc(_scrolls, mx + lx, my - ly, 0, 90, 15, kColorRed); + drawArc(_scrolls, mx + lx, my + ly, 270, 360, 15, kColorRed); + + // The body of the scroll. + _scrolls.fillRect(Common::Rect(mx - lx - 30, my + ly, mx + lx, my + ly + 6), kColorLightgray); + _scrolls.fillRect(Common::Rect(mx - lx - 30, my - ly - 6, mx + lx, my - ly + 1), kColorLightgray); + _scrolls.fillRect(Common::Rect(mx - lx - 15, my - ly, mx + lx + 15, my + ly + 1), kColorLightgray); + + // The left corners of the scroll. + drawPieSlice(mx - lx - 31, my - ly, 0, 180, 15, kColorDarkgray); + drawArc(_scrolls, mx - lx - 31, my - ly, 0, 180, 15, kColorRed); + _scrolls.drawLine(mx - lx - 31 - 15, my - ly, mx - lx - 31 + 15, my - ly, kColorRed); + drawPieSlice(mx - lx - 31, my + ly, 180, 360, 15, kColorDarkgray); + drawArc(_scrolls, mx - lx - 31, my + ly, 180, 360, 15, kColorRed); + _scrolls.drawLine(mx - lx - 31 - 15, my + ly, mx - lx - 31 + 15, my + ly, kColorRed); + + // The rear borders of the scroll. + _scrolls.fillRect(Common::Rect(mx - lx - 30, my - ly - 6, mx + lx, my - ly - 5), kColorRed); + _scrolls.fillRect(Common::Rect(mx - lx - 30, my + ly + 6, mx + lx, my + ly + 7), kColorRed); + _scrolls.fillRect(Common::Rect(mx - lx - 15, my - ly, mx - lx - 14, my + ly), kColorRed); + _scrolls.fillRect(Common::Rect(mx + lx + 15, my - ly, mx + lx + 16, my + ly), kColorRed); +} + +void GraphicManager::drawBackgroundSprite(int16 x, int16 y, SpriteType &sprite) { + drawPicture(_background, sprite._picture, x, y); +} + +void GraphicManager::drawDebugLines() { + if (!_vm->_showDebugLines) + return; + + for (int i = 0; i < _vm->_lineNum; i++) { + LineType *curLine = &_vm->_lines[i]; + _surface.drawLine(curLine->_x1, curLine->_y1, curLine->_x2, curLine->_y2, curLine->_color); + } + + for (int i = 0; i < _vm->_fieldNum; i++) { + FieldType *curField = &_vm->_fields[i]; + if (curField->_x1 < 640) + _surface.frameRect(Common::Rect(curField->_x1, curField->_y1, curField->_x2, curField->_y2), kColorLightmagenta); + } +} + +/** + * This function mimics Pascal's getimage(). + */ +Graphics::Surface GraphicManager::loadPictureGraphic(Common::File &file) { + // The height and the width are stored in 2-2 bytes. We have to add 1 to each because Pascal stores the value of them -1. + uint16 width = file.readUint16LE() + 1; + uint16 height = file.readUint16LE() + 1; + + Graphics::Surface picture; // We make a Surface object for the picture itself. + picture.create(width, height, Graphics::PixelFormat::createFormatCLUT8()); + + // Produce the picture. We read it in row-by-row, and every row has 4 planes. + for (int y = 0; y < height; y++) { + for (int8 plane = 3; plane >= 0; plane--) { // The planes are in the opposite way. + for (uint16 x = 0; x < width; x += 8) { + byte pixel = file.readByte(); + for (int bit = 0; bit < 8; bit++) { + byte pixelBit = (pixel >> bit) & 1; + if (pixelBit != 0) + *(byte *)picture.getBasePtr(x + 7 - bit, y) += (pixelBit << plane); + } + } + } + } + return picture; +} + +/** + * Reads Row-planar EGA data. + * This function is our own creation, very much like the one above. The main differences are that + * we don't read the width and the height from the file, the planes are in a different order + * and we read the picture plane-by-plane. + */ +Graphics::Surface GraphicManager::loadPictureRaw(Common::File &file, uint16 width, uint16 height) { + Graphics::Surface picture; + picture.create(width, height, Graphics::PixelFormat::createFormatCLUT8()); + + for (int plane = 0; plane < 4; plane++) { + for (uint16 y = 0; y < height; y++) { + for (uint16 x = 0; x < width; x += 8) { + byte pixel = file.readByte(); + for (int i = 0; i < 8; i++) { + byte pixelBit = (pixel >> i) & 1; + *(byte *)picture.getBasePtr(x + 7 - i, y) += (pixelBit << plane); + } + } + } + } + + return picture; +} + +void GraphicManager::clearAlso() { + _magics.fillRect(Common::Rect(0, 0, 640, 200), 0); + _magics.frameRect(Common::Rect(0, 45, 640, 161), 15); +} + +void GraphicManager::clearTextBar() { + _surface.fillRect(Common::Rect(24, 161, 640, 169), kColorBlack); // Black out the line of the text. +} + +void GraphicManager::setAlsoLine(int x1, int y1, int x2, int y2, Color color) { + _magics.drawLine(x1, y1, x2, y2, color); +} + +void GraphicManager::drawScreenLine(int16 x, int16 y, int16 x2, int16 y2, Color color) { + _surface.drawLine(x, y, x2, y2, color); +} + +byte GraphicManager::getAlsoColor(int x1, int y1, int x2, int y2) { + byte returnColor = 0; + for (int16 i = x1; i <= x2; i++) { + for (int16 j = y1; j <= y2; j++) { + byte actColor = *(byte *)_magics.getBasePtr(i, j); + returnColor = MAX(returnColor, actColor); + } + } + + return returnColor; +} + +byte GraphicManager::getScreenColor(Common::Point pos) { + return *(byte *)_surface.getBasePtr(pos.x, pos.y / 2); +} + +void GraphicManager::drawSprite(AnimationType *sprite, byte picnum, int16 x, int16 y) { + // First we make the pixels of the sprite blank. + for (int j = 0; j < sprite->_yLength; j++) { + for (int i = 0; i < sprite->_xLength; i++) { + if ((x + i < _surface.w) && (y + j < _surface.h)) { + if (((*sprite->_sil[picnum])[j][i / 8] >> ((7 - i % 8)) & 1) == 0) + *(byte *)_surface.getBasePtr(x + i, y + j) = 0; + } + } + } + + // Then we draw the picture to the blank places. + uint16 maniPos = 0; // Because the original manitype starts at 5!!! See Graphics.h for definition. + + for (int j = 0; j < sprite->_yLength; j++) { + for (int8 plane = 3; plane >= 0; plane--) { // The planes are in the opposite way. + for (uint16 i = 0; i < sprite->_xLength; i += 8) { + byte pixel = (*sprite->_mani[picnum])[maniPos++]; + for (int bit = 0; bit < 8; bit++) { + if ((x + i + 7 < _surface.w) && (y + j < _surface.h)) { + byte pixelBit = (pixel >> bit) & 1; + *(byte *)_surface.getBasePtr(x + i + 7 - bit, y + j) += (pixelBit << plane); + } + } + } + } + } +} + +void GraphicManager::drawPicture(Graphics::Surface &target, const Graphics::Surface picture, uint16 destX, uint16 destY) { + // Copy the picture to the given place on the screen. + uint16 maxX = picture.w; + uint16 maxY = picture.h; + + if (destX + maxX > target.w) + maxX = target.w - destX; + + if (destY + maxY > target.h) + maxY = target.h - destY; + + for (uint16 y = 0; y < maxY; y++) { + for (uint16 x = 0; x < maxX; x++) + *(byte *)target.getBasePtr(x + destX, y + destY) = *(const byte *)picture.getBasePtr(x, y); + } +} + +void GraphicManager::drawCursor(byte pos) { + int pixPos = 24 + (pos * 8); + // Draw the '_' character. + for (int i = 0; i < 8; i++) + *(byte *)_surface.getBasePtr(pixPos + i, 168) = kColorWhite; +} + +void GraphicManager::drawReadyLight(Color color) { + _surface.fillRect(Common::Rect(419, 195, 438, 197), color); +} + +/** + * This is for drawing a big "about" or "gameover" picture loaded from a file into an empty scroll. + */ +void GraphicManager::drawSign(Common::String fn, int16 xl, int16 yl, int16 y) { + Common::File file; + Common::String filename = Common::String::format("%s.avd", fn.c_str()); + + if (!file.open(filename)) + error("AVALANCHE: Scrolls: File not found: %s", filename.c_str()); + + // I know it looks very similar to the loadPicture methods, but in truth it's the combination of the two. + uint16 width = xl * 8; + uint16 height = yl; + + Graphics::Surface sign; // We make a Surface object for the picture itself. + sign.create(width, height, Graphics::PixelFormat::createFormatCLUT8()); + + // Produce the picture. We read it in row-by-row, and every row has 4 planes. + for (int yy = 0; yy < height; yy++) { + for (int8 plane = 0; plane < 4; plane++) { // The planes are in the "right" order. + for (uint16 xx = 0; xx < width; xx += 8) { + byte pixel = file.readByte(); + for (int bit = 0; bit < 8; bit++) { + byte pixelBit = (pixel >> bit) & 1; + if (pixelBit != 0) + *(byte *)sign.getBasePtr(xx + 7 - bit, yy) += (pixelBit << plane); + } + } + } + } + + drawPicture(_scrolls, sign, kScreenWidth / 2 - width / 2, y); + + file.close(); +} + +/** + * Draws an icon to the current scroll. + * @remarks Originally called 'geticon' + */ +void GraphicManager::drawIcon(int16 x, int16 y, byte which) { + Common::File file; + + if (!file.open("icons.avd")) + error("AVALANCHE: Scrolls: File not found: icons.avd"); + + which--; + file.seek(which * 426); + + Graphics::Surface icon = loadPictureGraphic(file); + drawPicture(_scrolls, icon, x, y); + + icon.free(); + file.close(); +} + +void GraphicManager::prepareBubble(int xc, int xw, int my, Common::Point points[3]) { + // Backup the screen before drawing the bubble. + _scrolls.copyFrom(_surface); + + int16 talkX = _vm->_dialogs->getTalkPosX(); + // The body of the bubble. + _scrolls.fillRect(Common::Rect(xc + talkX - xw + 9, 7, talkX + xw - 8 + xc, my + 1), _talkBackgroundColor); + _scrolls.fillRect(Common::Rect(xc + talkX - xw - 1, 12, talkX + xw + xc + 2, my - 4), _talkBackgroundColor); + + // Top the 4 rounded corners of the bubble. + drawPieSlice(xc + talkX + xw - 10, 11, 0, 90, 9, _talkBackgroundColor); + drawPieSlice(xc + talkX + xw - 10, my - 4, 270, 360, 9, _talkBackgroundColor); + drawPieSlice(xc + talkX - xw + 10, 11, 90, 180, 9, _talkBackgroundColor); + drawPieSlice(xc + talkX - xw + 10, my - 4, 180, 270, 9, _talkBackgroundColor); + + // "Tail" of the speech bubble. + drawTriangle(points, _talkBackgroundColor); +} + +/** + * Set the background of the text to the desired color. + */ +void GraphicManager::wipeChar(int x, int y, Color color) { + for (int k = 0; k < 8; k++) + *(byte *)_surface.getBasePtr(x + k, y) = color; +} + +void GraphicManager::drawChar(byte ander, int x, int y, Color color) { + byte pixel = ander; + for (int bit = 0; bit < 8; bit++) { + byte pixelBit = (pixel >> bit) & 1; + if (pixelBit) + *(byte *)_surface.getBasePtr(x + 7 - bit, y) = color; + } +} +void GraphicManager::refreshScreen() { + // These cycles are for doubling the screen height. + for (uint16 y = 0; y < _screen.h / 2; y++) { + memcpy(_screen.getBasePtr(0, y * 2), _surface.getBasePtr(0, y), _screen.w); + memcpy(_screen.getBasePtr(0, y * 2 + 1), _surface.getBasePtr(0, y), _screen.w); + } + // Now we copy the stretched picture to the screen. + g_system->copyRectToScreen(_screen.getPixels(), _screen.pitch, 0, 0, kScreenWidth, kScreenHeight * 2); + g_system->updateScreen(); +} + +void GraphicManager::loadBackground(Common::File &file) { + _background.free(); + _background = loadPictureRaw(file, kBackgroundWidth, kBackgroundHeight); +} + +void GraphicManager::refreshBackground() { + drawPicture(_surface, _background, 0, 10); +} + +/** + * Only used when entering the map. + * @remarks Originally called 'zoomout' + */ +void GraphicManager::zoomOut(int16 x, int16 y) { + //setlinestyle(dottedln, 0, 1); TODO: Implement it with a dotted line style!!! + + saveScreen(); + for (byte i = 1; i <= 20; i ++) { + int16 x1 = x - (x / 20) * i; + int16 y1 = y - ((y - 10) / 20) * i; + int16 x2 = x + (((639 - x) / 20) * i); + int16 y2 = y + (((161 - y) / 20) * i); + + _surface.frameRect(Common::Rect(x1, y1, x2, y2), kColorWhite); + refreshScreen(); + _vm->_system->delayMillis(17); + + restoreScreen(); + } + removeBackup(); +} + +void GraphicManager::showScroll() { + _surface.copyFrom(_scrolls); // TODO: Rework it using getSubArea !!!!!!! +} + +void GraphicManager::getNaturalPicture(SpriteType &sprite) { + sprite._type = kNaturalImage; // We simply read from the screen and later, in drawSprite() we draw it right back. + sprite._size = sprite._xl * 8 * sprite._yl + 1; + sprite._picture.create(sprite._xl * 8, sprite._yl + 1, Graphics::PixelFormat::createFormatCLUT8()); + for (uint16 y = 0; y < sprite._yl + 1; y++) { + for (uint16 x = 0; x < sprite._xl * 8; x++) + *(byte *)sprite._picture.getBasePtr(x, y) = *(byte *)_vm->_graphics->_surface.getBasePtr(sprite._x * 8 + x, sprite._y + y); + } +} + +void GraphicManager::saveScreen() { + _backup.copyFrom(_surface); +} + +void GraphicManager::removeBackup() { + _backup.free(); +} + +void GraphicManager::restoreScreen() { + _surface.copyFrom(_backup); + refreshScreen(); +} + +void GraphicManager::setDialogColor(Color bg, Color text) { + _talkBackgroundColor = bg; + _talkFontColor = text; +} + +// Original name background() +void GraphicManager::setBackgroundColor(Color x) { + warning("STUB: setBackgroundColor()"); +} + +} // End of namespace Avalanche diff --git a/engines/avalanche/graphics.h b/engines/avalanche/graphics.h new file mode 100644 index 0000000000..4af6d4e8db --- /dev/null +++ b/engines/avalanche/graphics.h @@ -0,0 +1,142 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on the original source code of Lord Avalot d'Argent version 1.3. + * Copyright (c) 1994-1995 Mike, Mark and Thomas Thurman. + */ + +#ifndef AVALANCHE_GRAPHICS_H +#define AVALANCHE_GRAPHICS_H + +#include "avalanche/enums.h" + +#include "common/file.h" +#include "common/rect.h" +#include "graphics/surface.h" + +namespace Avalanche { +class AvalancheEngine; +class AnimationType; +struct SpriteType; + +typedef byte FontType[256][16]; +typedef byte ManiType[2049]; +typedef byte SilType[51][11]; // 35, 4 + +struct MouseHotspotType { + int16 _horizontal, _vertical; +}; + +class GraphicManager { +public: + static const MouseHotspotType kMouseHotSpots[9]; + Color _talkBackgroundColor, _talkFontColor; + + GraphicManager(AvalancheEngine *vm); + ~GraphicManager(); + void init(); + void loadDigits(); + void loadMouse(byte which); + + Common::Point drawScreenArc(int16 x, int16 y, int16 stAngle, int16 endAngle, uint16 radius, Color color); + void drawPieSlice(int16 x, int16 y, int16 stAngle, int16 endAngle, uint16 radius, Color color); + void drawTriangle(Common::Point *p, Color color); + void drawNormalText(const Common::String text, FontType font, byte fontHeight, int16 x, int16 y, Color color); + void drawScrollText(const Common::String text, FontType font, byte fontHeight, int16 x, int16 y, Color color); + void drawDigit(int index, int x, int y); + void drawDirection(int index, int x, int y); + void drawScrollShadow(int16 x1, int16 y1, int16 x2, int16 y2); + void drawShadowBox(int16 x1, int16 y1, int16 x2, int16 y2, Common::String text); + void drawScroll(int mx, int lx, int my, int ly); + void drawMenuBar(Color color); + void drawSpeedBar(int speed); + void drawBackgroundSprite(int16 x, int16 y, SpriteType &sprite); + void drawMenuBlock(int x1, int y1, int x2, int y2, Color color); + void drawMenuItem(int x1, int y1, int x2, int y2); + void wipeChar(int x, int y, Color color); + void drawChar(byte ander, int x, int y, Color color); + void drawDebugLines(); + + void clearAlso(); + void clearTextBar(); + void setAlsoLine(int x1, int y1, int x2, int y2, Color color); + byte getAlsoColor(int x1, int y1, int x2, int y2); + byte getScreenColor(Common::Point pos); + + // The caller has to .free() the returned Surfaces!!! + // Further information about these two: http://www.shikadi.net/moddingwiki/Raw_EGA_data + Graphics::Surface loadPictureRaw(Common::File &file, uint16 width, uint16 height); + + void drawSprite(AnimationType *sprite, byte picnum, int16 x, int16 y); + void drawPicture(Graphics::Surface &target, const Graphics::Surface picture, uint16 destX, uint16 destY); + void drawThinkPic(Common::String filename, int id); + void drawToolbar(); + void drawCursor(byte pos); + void drawReadyLight(Color color); + void drawSign(Common::String name, int16 xl, int16 yl, int16 y); + void drawIcon(int16 x, int16 y, byte which); + void drawScreenLine(int16 x, int16 y, int16 x2, int16 y2, Color color); + void prepareBubble(int xc, int xw, int my, Common::Point points[3]); + void refreshScreen(); + void loadBackground(Common::File &file); + void refreshBackground(); + void setBackgroundColor(Color x); + void setDialogColor(Color bg, Color text); + + void zoomOut(int16 x, int16 y); + void showScroll(); + void getNaturalPicture(SpriteType &sprite); + + void saveScreen(); + void removeBackup(); + void restoreScreen(); + +private: + static const uint16 kBackgroundWidth = kScreenWidth; + static const byte kEgaPaletteIndex[16]; + static const byte kBackgroundHeight = 8 * 12080 / kScreenWidth; // With 640 width it's 151. + // The 8 = number of bits in a byte, and 12080 comes from Lucerna::load(). + + Graphics::Surface _background; + Graphics::Surface _backup; + Graphics::Surface _digits[10]; // digitsize and rwlitesize are defined in loadDigits() !!! + Graphics::Surface _directions[9]; // Maybe it will be needed to move them to the class itself instead. + Graphics::Surface _magics; // Lucerna::draw_also_lines() draws the "magical" lines here. Further information: https://github.com/urukgit/avalot/wiki/Also + Graphics::Surface _screen; // Only used in refreshScreen() to make it more optimized. (No recreation of it at every call of the function.) + Graphics::Surface _scrolls; + Graphics::Surface _surface; + byte _egaPalette[64][3]; + + AvalancheEngine *_vm; + + Graphics::Surface loadPictureGraphic(Common::File &file); // Reads Graphic-planar EGA data. + void drawText(Graphics::Surface &surface, const Common::String text, FontType font, byte fontHeight, int16 x, int16 y, Color color); + // Taken from Free Pascal's Procedure InternalEllipseDefault. Used to replace Pascal's procedure arc. + // Returns the end point of the arc. (Needed in Clock.) + // TODO: Make it more accurate later. + Common::Point drawArc(Graphics::Surface &surface, int16 x, int16 y, int16 stAngle, int16 endAngle, uint16 radius, Color color); +}; + +} // End of namespace Avalanche + +#endif // AVALANCHE_GRAPHICS_H diff --git a/engines/avalanche/menu.cpp b/engines/avalanche/menu.cpp new file mode 100644 index 0000000000..bba8e862a9 --- /dev/null +++ b/engines/avalanche/menu.cpp @@ -0,0 +1,834 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on the original source code of Lord Avalot d'Argent version 1.3. + * Copyright (c) 1994-1995 Mike, Mark and Thomas Thurman. + */ + +/* Original name: DROPDOWN A customized version of Oopmenu (qv). */ + +#include "avalanche/avalanche.h" +#include "avalanche/menu.h" + +namespace Avalanche { + +void HeadType::init(char trig, char altTrig, Common::String title, byte pos, MenuFunc setupFunc, MenuFunc chooseFunc, Menu *menu) { + _trigger = trig; + _altTrigger = altTrig; + _title = title; + _position = pos; + _xpos = _position * _menu->kSpacing + _menu->kIndent; + _xright = (_position + 1) * _menu->kSpacing + _menu->kIndent; + _setupFunc = setupFunc; + _chooseFunc = chooseFunc; + + _menu = menu; +} + +void HeadType::draw() { + CursorMan.showMouse(false); + _menu->drawMenuText(_xpos, 1, _trigger, _title, true, false); + CursorMan.showMouse(true); +} + +void HeadType::highlight() { + CursorMan.showMouse(false); + + _menu->_vm->_sound->stopSound(); + _menu->drawMenuText(_xpos, 1, _trigger, _title, true, true); + + _menu->_activeMenuItem._left = _xpos; + _menu->_activeMenuItem._activeNow = true; + _menu->_activeMenuItem._activeNum = _position; + _menu->_menuActive = true; + + // Force reload and redraw of cursor. + _menu->_vm->_currentMouse = 177; + +} + +bool HeadType::parseAltTrigger(char key) { + if (key != _altTrigger) + return true; + return false; +} + +void MenuItem::init(Menu *menu) { + _menu = menu; + + _activeNow = false; + _activeNum = 1; + _menu->_menuActive = false; +} + +void MenuItem::reset() { + _optionNum = 0; + _width = 0; + _firstlix = false; + _oldY = 0; + _highlightNum = 0; +} + +void MenuItem::setupOption(Common::String title, char trigger, Common::String shortcut, bool valid) { + uint16 width = (title + shortcut).size() + 3; + if (_width < width) + _width = width; + + _options[_optionNum]._title = title; + _options[_optionNum]._trigger = trigger; + _options[_optionNum]._shortcut = shortcut; + _options[_optionNum]._valid = valid; + _optionNum++; +} + +void MenuItem::displayOption(byte y, bool highlit) { + Common::String text = _options[y]._title; + while (text.size() + _options[y]._shortcut.size() < _width) + text += ' '; // Pad _options[y] with spaces. + text += _options[y]._shortcut; + + Color backgroundColor; + if (highlit) + backgroundColor = kColorBlack; + else + backgroundColor = kColorLightgray; + + _menu->_vm->_graphics->drawMenuBlock((_flx1 + 1) * 8, 3 + (y + 1) * 10, (_flx2 + 1) * 8, 13 + (y + 1) * 10, backgroundColor); + _menu->drawMenuText(_left, 4 + (y + 1) * 10, _options[y]._trigger, text, _options[y]._valid, highlit); +} + +void MenuItem::display() { + CursorMan.showMouse(false); + + _firstlix = true; + _flx1 = _left - 2; + _flx2 = _left + _width; + _fly = 15 + _optionNum * 10; + _activeNow = true; + _menu->_menuActive = true; + + _menu->_vm->_graphics->drawMenuItem((_flx1 + 1) * 8, 12, (_flx2 + 1) * 8, _fly); + + displayOption(0, true); + for (int y = 1; y < _optionNum; y++) + displayOption(y, false); + + _menu->_vm->_currentMouse = 177; + + CursorMan.showMouse(true); // 4 = fletch +} + +void MenuItem::wipe() { + CursorMan.showMouse(false); + + _menu->drawMenuText(_menu->_menuBar._menuItems[_menu->_activeMenuItem._activeNum]._xpos, 1, + _menu->_menuBar._menuItems[_menu->_activeMenuItem._activeNum]._trigger, + _menu->_menuBar._menuItems[_menu->_activeMenuItem._activeNum]._title, true, false); + + _activeNow = false; + _menu->_menuActive = false; + _firstlix = false; + + CursorMan.showMouse(true); +} + +void MenuItem::moveHighlight(int8 inc) { + if (inc != 0) { + int8 highlightNum = _highlightNum + inc; + if ((highlightNum < 0) || (highlightNum >= _optionNum)) + return; + _highlightNum = highlightNum; + } + CursorMan.showMouse(false); + displayOption(_oldY, false); + displayOption(_highlightNum, true); + _oldY = _highlightNum; + CursorMan.showMouse(true); +} + +/** + * This makes the menu highlight follow the mouse. + * @remarks Originally called 'lightup' + */ +void MenuItem::lightUp(Common::Point cursorPos) { + if ((cursorPos.x < _flx1 * 8) || (cursorPos.x > _flx2 * 8) || (cursorPos.y <= 25) || (cursorPos.y > ((_fly - 3) * 2 + 1))) + return; + _highlightNum = (cursorPos.y - 26) / 20; + if (_highlightNum == _oldY) + return; + moveHighlight(0); +} + +void MenuItem::select(byte which) { + if (!_options[which]._valid) + return; + + _choiceNum = which; + wipe(); + + if (_choiceNum == _optionNum) + _choiceNum--; // Off the bottom. + if (_choiceNum > _optionNum) + _choiceNum = 0; // Off the top, I suppose. + + (_menu->*_menu->_menuBar._menuItems[_activeNum]._chooseFunc)(); +} + +void MenuItem::parseKey(char c) { + c = toupper(c); + bool found = false; + for (int i = 0; i < _optionNum; i++) { + if ((toupper(_options[i]._trigger) == c) && _options[i]._valid) { + select(i); + found = true; + } + } + if (!found) + _menu->_vm->_sound->blip(); +} + +void MenuBar::init(Menu *menu) { + _menu = menu; + _menuNum = 0; +} + +void MenuBar::createMenuItem(char trig, Common::String title, char altTrig, MenuFunc setupFunc, MenuFunc chooseFunc) { + _menuItems[_menuNum].init(trig, altTrig, title, _menuNum, setupFunc, chooseFunc, _menu); + _menuNum++; +} + +void MenuBar::draw() { + _menu->_vm->_graphics->drawMenuBar(kMenuBackgroundColor); + + byte savecp = _menu->_vm->_cp; + _menu->_vm->_cp = 3; + + for (int i = 0; i < _menuNum; i++) + _menuItems[i].draw(); + + _menu->_vm->_cp = savecp; +} + +void MenuBar::parseAltTrigger(char c) { + byte i = 0; + while ((i < _menuNum) && (_menuItems[i].parseAltTrigger(c))) + i++; + if (i == _menuNum) + return; + setupMenuItem(i); +} + +void MenuBar::setupMenuItem(byte which) { + if (_menu->_activeMenuItem._activeNow) { + _menu->_activeMenuItem.wipe(); // Get rid of menu. + if (_menu->_activeMenuItem._activeNum == _menuItems[which]._position) + return; // Clicked on own highlight. + } + _menuItems[which].highlight(); + (_menu->*_menuItems[which]._setupFunc)(); +} + +void MenuBar::chooseMenuItem(int16 x) { + for (int i = 0; i < _menuNum; i++) { + if ((x > _menuItems[i]._xpos * 8) && (x < _menuItems[i]._xright * 8)) { + setupMenuItem(i); + break; + } + } +} + +Menu::Menu(AvalancheEngine *vm) { + _vm = vm; + _activeMenuItem.init(this); + _menuBar.init(this); +} + +void Menu::findWhatYouCanDoWithIt() { + switch (_vm->_thinks) { + case kObjectWine: + case kObjectPotion: + case kObjectInk: + _verbStr = Common::String(kVerbCodeExam) + kVerbCodeDrink; + break; + case kObjectBell: + _verbStr = Common::String(kVerbCodeExam) + kVerbCodeRing; + break; + case kObjectChastity: + _verbStr = Common::String(kVerbCodeExam) + kVerbCodeWear; + break; + case kObjectLute: + _verbStr = Common::String(kVerbCodeExam) + kVerbCodePlay; + break; + case kObjectMushroom: + case kObjectOnion: + _verbStr = Common::String(kVerbCodeExam) + kVerbCodeEat; + break; + case kObjectClothes: + _verbStr = Common::String(kVerbCodeExam) + kVerbCodeWear; + break; + default: + _verbStr = kVerbCodeExam; // Anything else. + } +} + +void Menu::drawMenuText(int16 x, int16 y, char trigger, Common::String text, bool valid, bool highlighted) { + Color fontColor; + Color backgroundColor; + if (highlighted) { + fontColor = kColorWhite; + backgroundColor = kColorBlack; + } else { + fontColor = kColorBlack; + backgroundColor = kColorLightgray; + } + + byte ander; + if (valid) + ander = 255; + else + ander = 170; + + FontType font; + for (uint i = 0; i < text.size(); i++) { + for (int j = 0; j < 8; j++) { + byte idx = text[i]; + font[idx][j] = _vm->_font[idx][j] & ander; // Set the font. + // And set the background of the text to the desired color. + _vm->_graphics->wipeChar(x * 8 + i * 8, y + j, backgroundColor); + } + } + + _vm->_graphics->drawNormalText(text, font, 8, x * 8, y, fontColor); + + // Underline the selected character. + if ((trigger == 0) || !text.contains(trigger) ) + return; + else { + byte i; + for (i = 0; text[i] != trigger; i++) + ; // Search for the character in the string. + + _vm->_graphics->drawChar(ander, x * 8 + i * 8, y + 8, fontColor); + } + + _vm->_graphics->refreshScreen(); +} + +void Menu::bleep() { + _vm->_sound->playNote(177, 7); +} + +void Menu::parseKey(char r, char re) { +#if 0 + switch (r) { + case 0: + case 224: { + switch (re) { + case 'K': + if (_activeMenuItem._activeNum > 1) { + _activeMenuItem.wipe(); + _menuBar.setupMenuItem(_activeMenuItem._activeNum - 1); + } else { + // Get menu on the left-hand side. + _activeMenuItem.wipe(); + _menuBar.chooseMenuItem((_menuBar._menuNum - 1) * kSpacing + kIndent); + } + break; + case 'M': + if (_activeMenuItem._activeNum < _menuBar._menuNum) { + _activeMenuItem.wipe(); + _menuBar.setupMenuItem(_activeMenuItem._activeNum + 1); + } else { + // Get menu on the far right-hand side. + _activeMenuItem.wipe(); + _menuBar.chooseMenuItem(kIndent); + } + break; + case 'H': + _activeMenuItem.moveHighlight(-1); + break; + case 'P': + _activeMenuItem.moveHighlight(1); + break; + default: + _menuBar.parseAltTrigger(re); + } + } + break; + case 13: + _activeMenuItem.select(_activeMenuItem._highlightNum); + break; + default: + if (_activeMenuItem._activeNow) + _activeMenuItem.parseKey(r); + } +#endif + + warning("STUB: Dropdown::parseKey()"); // To be implemented properly later! Don't remove the comment above! +} + +Common::String Menu::selectGender(byte x) { + if (x < 175) + return "im"; + else + return "er"; +} + +void Menu::setupMenuGame() { + _activeMenuItem.reset(); + _activeMenuItem.setupOption("Help...", 'H', "f1", true); + _activeMenuItem.setupOption("Boss Key", 'B', "alt-B", false); + _activeMenuItem.setupOption("Untrash screen", 'U', "ctrl-f7", true); + _activeMenuItem.setupOption("Score and rank", 'S', "f9", true); + _activeMenuItem.setupOption("About Avvy...", 'A', "shift-f10", true); + _activeMenuItem.display(); +} + +void Menu::setupMenuFile() { + _activeMenuItem.reset(); + _activeMenuItem.setupOption("New game", 'N', "f4", true); + _activeMenuItem.setupOption("Load...", 'L', "^f3", true); + _activeMenuItem.setupOption("Save", 'S', "^f2", _vm->_alive); + _activeMenuItem.setupOption("Save As...", 'v', "", _vm->_alive); + _activeMenuItem.setupOption("DOS Shell", 'D', "alt-1", false); + _activeMenuItem.setupOption("Quit", 'Q', "alt-X", true); + _activeMenuItem.display(); +} + +void Menu::setupMenuAction() { + _activeMenuItem.reset(); + + Common::String f5Does = _vm->f5Does(); + for (int i = 0; i < 2; i++) + if (!f5Does.empty()) + f5Does.deleteChar(0); + if (f5Does.empty()) + _activeMenuItem.setupOption("Do something", 'D', "f5", false); + else + _activeMenuItem.setupOption(f5Does, f5Does[0], "f5", true); + _activeMenuItem.setupOption("Pause game", 'P', "f6", true); + if (_vm->_room == kRoomMap) + _activeMenuItem.setupOption("Journey thither", 'J', "f7", _vm->_animation->nearDoor()); + else + _activeMenuItem.setupOption("Open the door", 'O', "f7", _vm->_animation->nearDoor()); + _activeMenuItem.setupOption("Look around", 'L', "f8", true); + _activeMenuItem.setupOption("Inventory", 'I', "Tab", true); + if (_vm->_animation->_sprites[0]->_speedX == kWalk) + _activeMenuItem.setupOption("Run fast", 'R', "^R", true); + else + _activeMenuItem.setupOption("Walk slowly", 'W', "^W", true); + + _activeMenuItem.display(); +} + +void Menu::setupMenuPeople() { + if (!people.empty()) + people.clear(); + + _activeMenuItem.reset(); + + for (int i = kPeopleAvalot; i <= kPeopleWisewoman; i++) { + if (_vm->getRoom((People)i) == _vm->_room) { + _activeMenuItem.setupOption(_vm->getName((People)i), getNameChar((People)i), "", true); + people += i; + } + } + + _activeMenuItem.display(); +} + +void Menu::setupMenuObjects() { + _activeMenuItem.reset(); + for (int i = 0; i < kObjectNum; i++) { + if (_vm->_objects[i]) + _activeMenuItem.setupOption(getThing(i + 1), getThingChar(i + 1), "", true); + } + _activeMenuItem.display(); +} + +void Menu::setupMenuWith() { + _activeMenuItem.reset(); + + if (_vm->_thinkThing) { + findWhatYouCanDoWithIt(); + + for (uint i = 0; i < _verbStr.size(); i++) { + char vbchar; + Common::String verb; + + _vm->_parser->verbOpt(_verbStr[i], verb, vbchar); + _activeMenuItem.setupOption(verb, vbchar, "", true); + } + + // We disable the "give" option if: (a), you haven't selected anybody, (b), the _person you've selected isn't in the room, + // or (c), the _person you've selected is YOU! + + if ((_lastPerson == kPeopleAvalot) || (_lastPerson == _vm->_parser->kNothing) + || (_vm->getRoom(_lastPerson) != _vm->_room)) + _activeMenuItem.setupOption("Give to...", 'G', "", false); // Not here. + else { + _activeMenuItem.setupOption(Common::String("Give to ") + _vm->getName(_lastPerson), 'G', "", true); + _verbStr = _verbStr + kVerbCodeGive; + } + } else { + _activeMenuItem.setupOption("Examine", 'x', "", true); + _activeMenuItem.setupOption(Common::String("Talk to h") + selectGender(_vm->_thinks), 'T', "", true); + _verbStr = Common::String(kVerbCodeExam) + kVerbCodeTalk; + switch (_vm->_thinks) { + case kPeopleGeida: + case kPeopleArkata: + _activeMenuItem.setupOption("Kiss her", 'K', "", true); + _verbStr = _verbStr + kVerbCodeKiss; + break; + case kPeopleDogfood: + _activeMenuItem.setupOption("Play his game", 'P', "", !_vm->_wonNim); // True if you HAVEN'T won. + _verbStr = _verbStr + kVerbCodePlay; + break; + case kPeopleMalagauche: { + bool isSober = !_vm->_teetotal; + _activeMenuItem.setupOption("Buy some wine", 'w', "", !_vm->_objects[kObjectWine - 1]); + _activeMenuItem.setupOption("Buy some beer", 'b', "", isSober); + _activeMenuItem.setupOption("Buy some whisky", 'h', "", isSober); + _activeMenuItem.setupOption("Buy some cider", 'c', "", isSober); + _activeMenuItem.setupOption("Buy some mead", 'm', "", isSober); + _verbStr = _verbStr + 101 + 100 + 102 + 103 + 104; + } + break; + case kPeopleTrader: + _activeMenuItem.setupOption("Buy an onion", 'o', "", !_vm->_objects[kObjectOnion - 1]); + _verbStr = _verbStr + 105; + break; + } + } + _activeMenuItem.display(); +} + +void Menu::runMenuGame() { + // Help, boss, untrash screen. + switch (_activeMenuItem._choiceNum) { + case 0: + _vm->callVerb(kVerbCodeHelp); + break; + case 1: + _vm->callVerb(kVerbCodeBoss); + break; + case 2: + _vm->majorRedraw(); + break; + case 3: + _vm->callVerb(kVerbCodeScore); + break; + case 4: + _vm->callVerb(kVerbCodeInfo); + break; + } +} + +void Menu::runMenuFile() { + // New game, load, save, save as, DOS shell, about, quit. + switch (_activeMenuItem._choiceNum) { + case 0: + _vm->callVerb(kVerbCodeRestart); + break; + case 1: + if (!_vm->_parser->_realWords[1].empty()) + _vm->_parser->_realWords[1].clear(); + _vm->callVerb(kVerbCodeLoad); + break; + // Case 2 is 'Save', Case 3 is 'Save As'. Both triggers ScummVM save screen. + case 2: + case 3: + if (!_vm->_parser->_realWords[1].empty()) + _vm->_parser->_realWords[1].clear(); + _vm->callVerb(kVerbCodeSave); + break; + case 4: + // Command Prompt, disabled + break; + case 5: + _vm->callVerb(kVerbCodeQuit); + break; + } +} + +void Menu::runMenuAction() { + // Get up, pause game, open door, look, inventory, walk/run. + switch (_activeMenuItem._choiceNum) { + case 0: { + _vm->_parser->_person = kPeoplePardon; + _vm->_parser->_thing = _vm->_parser->kPardon; + Common::String f5Does = _vm->f5Does(); + VerbCode verb = (VerbCode)(byte)f5Does[0]; + _vm->callVerb(verb); + } + break; + case 1: + _vm->_parser->_thing = _vm->_parser->kPardon; + _vm->callVerb(kVerbCodePause); + break; + case 2: + _vm->callVerb(kVerbCodeOpen); + break; + case 3: + _vm->_parser->_thing = _vm->_parser->kPardon; + _vm->callVerb(kVerbCodeLook); + break; + case 4: + _vm->callVerb(kVerbCodeInv); + break; + case 5: { + AnimationType *avvy = _vm->_animation->_sprites[0]; + if (avvy->_speedX == kWalk) + avvy->_speedX = kRun; + else + avvy->_speedX = kWalk; + _vm->_animation->updateSpeed(); + } + break; + } +} + +void Menu::runMenuObjects() { + _vm->thinkAbout(_vm->_objectList[_activeMenuItem._choiceNum], AvalancheEngine::kThing); +} + +void Menu::runMenuPeople() { + _vm->thinkAbout(people[_activeMenuItem._choiceNum], AvalancheEngine::kPerson); + _lastPerson = (People)people[_activeMenuItem._choiceNum]; +} + +void Menu::runMenuWith() { + _vm->_parser->_thing = _vm->_thinks; + + if (_vm->_thinkThing) { + _vm->_parser->_thing += 49; + + if (_verbStr[_activeMenuItem._choiceNum] == kVerbCodeGive) + _vm->_parser->_person = _lastPerson; + else + _vm->_parser->_person = kPeoplePardon; + } else { + switch (_verbStr[_activeMenuItem._choiceNum]) { + case 100: // Beer + case 102: // Whisky + case 103: // Cider + _vm->_parser->_thing = _verbStr[_activeMenuItem._choiceNum]; + _vm->callVerb(kVerbCodeBuy); + return; + case 101: // Wine + _vm->_parser->_thing = 50; + _vm->callVerb(kVerbCodeBuy); + return; + case 104: // Mead + _vm->_parser->_thing = 107; + _vm->callVerb(kVerbCodeBuy); + return; + case 105: // Onion (trader) + _vm->_parser->_thing = 67; + _vm->callVerb(kVerbCodeBuy); + return; + default: + _vm->_parser->_person = (People)_vm->_parser->_thing; + _vm->_parser->_thing = Parser::kPardon; + _vm->_subjectNum = 0; + } + } + _vm->callVerb((VerbCode)(byte)_verbStr[_activeMenuItem._choiceNum]); +} + +void Menu::setup() { + _menuBar.init(this); + _activeMenuItem.init(this); + + _menuBar.createMenuItem('F', "File", '!', &Avalanche::Menu::setupMenuFile, &Avalanche::Menu::runMenuFile); + _menuBar.createMenuItem('G', "Game", 34, &Avalanche::Menu::setupMenuGame, &Avalanche::Menu::runMenuGame); + _menuBar.createMenuItem('A', "Action", 30, &Avalanche::Menu::setupMenuAction, &Avalanche::Menu::runMenuAction); + _menuBar.createMenuItem('O', "Objects", 24, &Avalanche::Menu::setupMenuObjects, &Avalanche::Menu::runMenuObjects); + _menuBar.createMenuItem('P', "People", 25, &Avalanche::Menu::setupMenuPeople, &Avalanche::Menu::runMenuPeople); + _menuBar.createMenuItem('W', "With", 17, &Avalanche::Menu::setupMenuWith, &Avalanche::Menu::runMenuWith); + + _menuBar.draw(); +} + +void Menu::update() { // TODO: Optimize it ASAP!!! It really needs it... + _vm->_graphics->saveScreen(); + + Common::Point cursorPos = _vm->getMousePos(); + while (!_activeMenuItem._activeNow && (cursorPos.y <= 21) && _vm->_holdLeftMouse) { + _menuBar.chooseMenuItem(cursorPos.x); + do + _vm->updateEvents(); + while (_vm->_holdLeftMouse && !_vm->shouldQuit()); + + while (!_vm->shouldQuit()) { + do { + _vm->updateEvents(); + + // We update the cursor's picture. + cursorPos = _vm->getMousePos(); + // Change arrow... + if ((0 <= cursorPos.y) && (cursorPos.y <= 21)) + _vm->_graphics->loadMouse(kCurUpArrow); // Up arrow + else if ((22 <= cursorPos.y) && (cursorPos.y <= 339)) { + if ((cursorPos.x >= _activeMenuItem._flx1 * 8) && (cursorPos.x <= _activeMenuItem._flx2 * 8) && (cursorPos.y > 21) && (cursorPos.y <= _activeMenuItem._fly * 2 + 1)) + _vm->_graphics->loadMouse(kCurRightArrow); // Right-arrow + else + _vm->_graphics->loadMouse(kCurFletch); // Fletch + } else if ((340 <= cursorPos.y) && (cursorPos.y <= 399)) + _vm->_graphics->loadMouse(kCurScrewDriver); // Screwdriver + + _activeMenuItem.lightUp(cursorPos); + + _vm->_graphics->refreshScreen(); + } while (!_vm->_holdLeftMouse && !_vm->shouldQuit()); + + if (_vm->_holdLeftMouse) { + if (cursorPos.y > 21) { + if (!((_activeMenuItem._firstlix) && ((cursorPos.x >= _activeMenuItem._flx1 * 8) && (cursorPos.x <= _activeMenuItem._flx2 * 8) + && (cursorPos.y >= 24) && (cursorPos.y <= (_activeMenuItem._fly * 2 + 1))))) { + // Clicked OUTSIDE the menu. + if (_activeMenuItem._activeNow) { + _activeMenuItem.wipe(); + _vm->_holdLeftMouse = false; + _vm->_graphics->removeBackup(); + return; + } // No "else"- clicking on menu has no effect (only releasing). + } + } else { + // Clicked on menu bar. + if (_activeMenuItem._activeNow) { + _activeMenuItem.wipe(); + _vm->_graphics->restoreScreen(); + + if (((_activeMenuItem._left * 8) <= cursorPos.x) && (cursorPos.x <= (_activeMenuItem._left * 8 + 80))) { // 80: the width of one menu item on the bar in pixels. + // If we clicked on the same menu item (the one that is already active) on the bar... + _vm->_holdLeftMouse = false; + _vm->_graphics->removeBackup(); + return; + } else { + _vm->_holdLeftMouse = true; + break; + } + } + } + + // NOT clicked button... + if ((_activeMenuItem._firstlix) && ((cursorPos.x >= _activeMenuItem._flx1 * 8) && (cursorPos.x <= _activeMenuItem._flx2 * 8) + && (cursorPos.y >= 12) && (cursorPos.y <= (_activeMenuItem._fly * 2 + 1)))) { + + // We act only if the button is released over a menu item. + while (!_vm->shouldQuit()) { + cursorPos = _vm->getMousePos(); + _activeMenuItem.lightUp(cursorPos); + _vm->_graphics->refreshScreen(); + + _vm->updateEvents(); + if (!_vm->_holdLeftMouse) + break; + } + + uint16 which = (cursorPos.y - 26) / 20; + _activeMenuItem.select(which); + if (_activeMenuItem._options[which]._valid) { // If the menu item wasn't active, we do nothing. + _vm->_graphics->removeBackup(); + return; + } + } + } + } + } + + _vm->_graphics->removeBackup(); +} + +char Menu::getThingChar(byte which) { + static const char thingsChar[] = "WMBParCLguKeSnIohn"; // V=Vinegar + + char result; + switch (which) { + case kObjectWine: + if (_vm->_wineState == 3) + result = 'V'; // Vinegar + else + result = thingsChar[which - 1]; + break; + default: + result = thingsChar[which - 1]; + } + return result; +} + +byte Menu::getNameChar(People whose) { + static const char ladChar[] = "ASCDMTRwLfgeIyPu"; + static const char lassChar[] = "kG\0xB1o"; + + if (whose < kPeopleArkata) + return ladChar[whose - kPeopleAvalot]; + else + return lassChar[whose - kPeopleArkata]; +} + +Common::String Menu::getThing(byte which) { + static const char things[kObjectNum][20] = { + "Wine", "Money-bag", "Bodkin", "Potion", "Chastity belt", + "Crossbow bolt", "Crossbow", "Lute", "Pilgrim's badge", "Mushroom", "Key", + "Bell", "Scroll", "Pen", "Ink", "Clothes", "Habit", "Onion" + }; + + Common::String result; + switch (which) { + case kObjectWine: + switch (_vm->_wineState) { + case 1: + case 4: + result = Common::String(things[which - 1]); + break; + case 3: + result = "Vinegar"; + break; + } + break; + case kObjectOnion: + if (_vm->_rottenOnion) + result = Common::String("rotten onion"); + else + result = Common::String(things[which - 1]); + break; + default: + result = Common::String(things[which - 1]); + } + return result; +} + +bool Menu::isActive() { + return _menuActive; +} + +void Menu::init() { + _menuActive = false; +} + +void Menu::resetVariables() { + _lastPerson = kPeoplePardon; +} +} // End of namespace Avalanche. diff --git a/engines/avalanche/menu.h b/engines/avalanche/menu.h new file mode 100644 index 0000000000..a7ec8bf2db --- /dev/null +++ b/engines/avalanche/menu.h @@ -0,0 +1,181 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on the original source code of Lord Avalot d'Argent version 1.3. + * Copyright (c) 1994-1995 Mike, Mark and Thomas Thurman. + */ + +/* Original name: DROPDOWN A customized version of Oopmenu (qv). */ + +#ifndef AVALANCHE_MENU_H +#define AVALANCHE_MENU_H + +#include "common/str.h" + +namespace Avalanche { +class AvalancheEngine; + +class Menu; + +typedef void (Menu::*MenuFunc)(); +static const Color kMenuBackgroundColor = kColorLightgray; +static const Color kMenuBorderColor = kColorBlack; + +class HeadType { +public: + Common::String _title; + char _trigger, _altTrigger; + byte _position; + int16 _xpos, _xright; + MenuFunc _setupFunc, _chooseFunc; + + void init(char trig, char alTtrig, Common::String title, byte pos, MenuFunc setupFunc, MenuFunc chooseFunc, Menu *menu); + void draw(); + void highlight(); + bool parseAltTrigger(char key); + +private: + Menu *_menu; +}; + +struct OptionType { + Common::String _title; + byte _trigger; + Common::String _shortcut; + bool _valid; +}; + +class MenuItem { +public: + OptionType _options[12]; + uint16 _width, _left; + bool _firstlix; + int16 _flx1, _flx2, _fly; + bool _activeNow; // Is there an active option now? + byte _activeNum; // And if so, which is it? + byte _choiceNum; // Your choice? + + void init(Menu *menu); + void reset(); + void setupOption(Common::String title, char trigger, Common::String shortcut, bool valid); + void display(); + void wipe(); + void lightUp(Common::Point cursorPos); + void select(byte which); + +private: + byte _oldY; // used by lightUp + byte _optionNum; + byte _highlightNum; + + Menu *_menu; + + void displayOption(byte y, bool highlit); + void moveHighlight(int8 inc); + + // CHECKME: Useless function? + void parseKey(char c); +}; + +class MenuBar { +public: + HeadType _menuItems[8]; + byte _menuNum; + + void init(Menu *menu); + void createMenuItem(char trig, Common::String title, char altTrig, MenuFunc setupFunc, MenuFunc chooseFunc); + void draw(); + void chooseMenuItem(int16 x); + +private: + Menu *_menu; + + void setupMenuItem(byte which); + // CHECKME: Useless function + void parseAltTrigger(char c); +}; + +class Menu { +public: + friend class HeadType; + friend class MenuItem; + friend class MenuBar; + + MenuItem _activeMenuItem; + MenuBar _menuBar; + + Menu(AvalancheEngine *vm); + + void update(); + void setup(); // Standard menu bar. + bool isActive(); + void init(); + void resetVariables(); + +private: + static const byte kIndent = 5; + static const byte kSpacing = 10; + +// Checkme: Useless constants? +// static const Color kMenuFontColor = kColorBlack; +// static const Color kHighlightBackgroundColor = kColorBlack; +// static const Color kHighlightFontColor = kColorWhite; +// static const Color kDisabledColor = kColorDarkgray; + + Common::String people; + Common::String _verbStr; // what you can do with your object. :-) + bool _menuActive; // Kludge so we don't have to keep referring to the menu. + People _lastPerson; // Last person to have been selected using the People menu. + + AvalancheEngine *_vm; + + Common::String selectGender(byte x); // Returns "im" for boys, and "er" for girls. + void findWhatYouCanDoWithIt(); + void drawMenuText(int16 x, int16 y, char trigger, Common::String text, bool valid, bool highlighted); + void bleep(); + + char getThingChar(byte which); + byte getNameChar(People whose); + Common::String getThing(byte which); + + void setupMenuGame(); + void setupMenuFile(); + void setupMenuAction(); + void setupMenuPeople(); + void setupMenuObjects(); + void setupMenuWith(); + + void runMenuGame(); + void runMenuFile(); + void runMenuAction(); + void runMenuObjects(); + void runMenuPeople(); + void runMenuWith(); + + // CHECKME: Useless function? + void parseKey(char r, char re); +}; + +} // End of namespace Avalanche. + +#endif // AVALANCHE_MENU_H diff --git a/engines/avalanche/module.mk b/engines/avalanche/module.mk new file mode 100644 index 0000000000..9c1205df02 --- /dev/null +++ b/engines/avalanche/module.mk @@ -0,0 +1,26 @@ +MODULE := engines/avalanche + +MODULE_OBJS = \ + animation.o \ + avalanche.o \ + avalot.o \ + background.o \ + closing.o \ + console.o \ + detection.o \ + graphics.o \ + menu.o \ + parser.o \ + pingo.o \ + dialogs.o \ + sequence.o \ + sound.o \ + timer.o + +# This module can be built as a plugin +ifeq ($(ENABLE_AVALANCHE), DYNAMIC_PLUGIN) +PLUGIN := 1 +endif + +# Include common rules +include $(srcdir)/rules.mk diff --git a/engines/avalanche/parser.cpp b/engines/avalanche/parser.cpp new file mode 100644 index 0000000000..fc176c78b0 --- /dev/null +++ b/engines/avalanche/parser.cpp @@ -0,0 +1,2470 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on the original source code of Lord Avalot d'Argent version 1.3. + * Copyright (c) 1994-1995 Mike, Mark and Thomas Thurman. + */ + +#include "avalanche/avalanche.h" +#include "avalanche/parser.h" + +#include "gui/saveload.h" + +namespace Avalanche { + +const char *Parser::kCopyright = "1995"; +const char *Parser::kVersionNum = "1.30"; + +Parser::Parser(AvalancheEngine *vm) { + _vm = vm; +} + +void Parser::init() { + if (!_inputText.empty()) + _inputText.clear(); + _inputTextPos = 0; + + _weirdWord = false; + + // Initailaze the vocabulary. + // Verbs: 1-49 + _vocabulary[0].init(1, "EXAMINE"); + _vocabulary[1].init(1, "READ"); + _vocabulary[2].init(1, "XAM"); + _vocabulary[3].init(2, "OPEN"); + _vocabulary[4].init(2, "LEAVE"); + _vocabulary[5].init(2, "UNLOCK"); + _vocabulary[6].init(3, "PAUSE"); + _vocabulary[7].init(47, "TA"); // Early to avoid Take and Talk. + _vocabulary[8].init(4, "TAKE"); + _vocabulary[9].init(4, "GET"); + _vocabulary[10].init(4, "PICK"); + _vocabulary[11].init(5, "DROP"); + _vocabulary[12].init(6, "INVENTORY"); + _vocabulary[13].init(7, "TALK"); + _vocabulary[14].init(7, "SAY"); + _vocabulary[15].init(7, "ASK"); + _vocabulary[16].init(8, "GIVE"); + _vocabulary[17].init(9, "DRINK"); + _vocabulary[18].init(9, "IMBIBE"); + _vocabulary[19].init(9, "DRAIN"); + _vocabulary[20].init(10, "LOAD"); + _vocabulary[21].init(10, "RESTORE"); + _vocabulary[22].init(11, "SAVE"); + _vocabulary[23].init(12, "BRIBE"); + _vocabulary[24].init(12, "PAY"); + _vocabulary[25].init(13, "LOOK"); + _vocabulary[26].init(14, "BREAK"); + _vocabulary[27].init(15, "QUIT"); + _vocabulary[28].init(15, "EXIT"); + _vocabulary[29].init(16, "SIT"); + _vocabulary[30].init(16, "SLEEP"); + _vocabulary[31].init(17, "STAND"); + + _vocabulary[32].init(18, "GO"); + _vocabulary[33].init(19, "INFO"); + _vocabulary[34].init(20, "UNDRESS"); + _vocabulary[35].init(20, "DOFF"); + _vocabulary[36].init(21, "DRESS"); + _vocabulary[37].init(21, "WEAR"); + _vocabulary[38].init(21, "DON"); + _vocabulary[39].init(22, "PLAY"); + _vocabulary[40].init(22, "STRUM"); + _vocabulary[41].init(23, "RING"); + _vocabulary[42].init(24, "HELP"); + _vocabulary[43].init(25, "KENDAL"); + _vocabulary[44].init(26, "CAPYBARA"); + _vocabulary[45].init(27, "BOSS"); + _vocabulary[46].init(255, "NINET"); // block for NINETY + _vocabulary[47].init(28, "URINATE"); + _vocabulary[48].init(28, "MINGITE"); + _vocabulary[49].init(29, "NINETY"); + _vocabulary[50].init(30, "ABRACADABRA"); + _vocabulary[51].init(30, "PLUGH"); + _vocabulary[52].init(30, "XYZZY"); + _vocabulary[53].init(30, "HOCUS"); + _vocabulary[54].init(30, "POCUS"); + _vocabulary[55].init(30, "IZZY"); + _vocabulary[56].init(30, "WIZZY"); + _vocabulary[57].init(30, "PLOVER"); + _vocabulary[58].init(30, "MELENKURION"); + _vocabulary[59].init(30, "ZORTON"); + _vocabulary[60].init(30, "BLERBI"); + _vocabulary[61].init(30, "THURB"); + _vocabulary[62].init(30, "SNOEZE"); + _vocabulary[63].init(30, "SAMOHT"); + _vocabulary[64].init(30, "NOSIDE"); + _vocabulary[65].init(30, "PHUGGG"); + _vocabulary[66].init(30, "KNERL"); + _vocabulary[67].init(30, "MAGIC"); + _vocabulary[68].init(30, "KLAETU"); + _vocabulary[69].init(30, "VODEL"); + _vocabulary[70].init(30, "BONESCROLLS"); + _vocabulary[71].init(30, "RADOF"); + + _vocabulary[72].init(31, "RESTART"); + _vocabulary[73].init(32, "SWALLOW"); + _vocabulary[74].init(32, "EAT"); + _vocabulary[75].init(33, "LISTEN"); + _vocabulary[76].init(33, "HEAR"); + _vocabulary[77].init(34, "BUY"); + _vocabulary[78].init(34, "PURCHASE"); + _vocabulary[79].init(34, "ORDER"); + _vocabulary[80].init(34, "DEMAND"); + _vocabulary[81].init(35, "ATTACK"); + _vocabulary[82].init(35, "HIT"); + _vocabulary[83].init(35, "KILL"); + _vocabulary[84].init(35, "PUNCH"); + _vocabulary[85].init(35, "KICK"); + _vocabulary[86].init(35, "SHOOT"); + _vocabulary[87].init(35, "FIRE"); + + // Passwords: 36 + _vocabulary[88].init(36, "TIROS"); + _vocabulary[89].init(36, "WORDY"); + _vocabulary[90].init(36, "STACK"); + _vocabulary[91].init(36, "SHADOW"); + _vocabulary[92].init(36, "OWL"); + _vocabulary[93].init(36, "ACORN"); + _vocabulary[94].init(36, "DOMESDAY"); + _vocabulary[95].init(36, "FLOPPY"); + _vocabulary[96].init(36, "DIODE"); + _vocabulary[97].init(36, "FIELD"); + _vocabulary[98].init(36, "COWSLIP"); + _vocabulary[99].init(36, "OSBYTE"); + _vocabulary[100].init(36, "OSCLI"); + _vocabulary[101].init(36, "TIMBER"); + _vocabulary[102].init(36, "ADVAL"); + _vocabulary[103].init(36, "NEUTRON"); + _vocabulary[104].init(36, "POSITRON"); + _vocabulary[105].init(36, "ELECTRON"); + _vocabulary[106].init(36, "CIRCUIT"); + _vocabulary[107].init(36, "AURUM"); + _vocabulary[108].init(36, "PETRIFY"); + _vocabulary[109].init(36, "EBBY"); + _vocabulary[110].init(36, "CATAPULT"); + _vocabulary[111].init(36, "GAMERS"); + _vocabulary[112].init(36, "FUDGE"); + _vocabulary[113].init(36, "CANDLE"); + _vocabulary[114].init(36, "BEEB"); + _vocabulary[115].init(36, "MICRO"); + _vocabulary[116].init(36, "SESAME"); + _vocabulary[117].init(36, "LORDSHIP"); + + _vocabulary[118].init(37, "DIR"); + _vocabulary[119].init(37, "LS"); + _vocabulary[120].init(38, "DIE"); + _vocabulary[121].init(39, "SCORE"); + _vocabulary[122].init(40, "PUT"); + _vocabulary[123].init(40, "INSERT"); + _vocabulary[124].init(41, "KISS"); + _vocabulary[125].init(41, "SNOG"); + _vocabulary[126].init(41, "CUDDLE"); + _vocabulary[127].init(42, "CLIMB"); + _vocabulary[128].init(42, "CLAMBER"); + _vocabulary[129].init(43, "JUMP"); + _vocabulary[130].init(44, "HIGHSCORES"); + _vocabulary[131].init(44, "HISCORES"); + _vocabulary[132].init(45, "WAKEN"); + _vocabulary[133].init(45, "AWAKEN"); + _vocabulary[134].init(46, "HELLO"); + _vocabulary[135].init(46, "HI"); + _vocabulary[136].init(46, "YO"); + _vocabulary[137].init(47, "THANKS"); // = 47, "ta", which was defined earlier. + + // Nouns - Objects: 50-100 + _vocabulary[138].init(50, "WINE"); + _vocabulary[139].init(50, "BOOZE"); + _vocabulary[140].init(50, "NASTY"); + _vocabulary[141].init(50, "VINEGAR"); + _vocabulary[142].init(51, "MONEYBAG"); + _vocabulary[143].init(51, "BAG"); + _vocabulary[144].init(51, "CASH"); + _vocabulary[145].init(51, "DOSH"); + _vocabulary[146].init(51, "WALLET"); + _vocabulary[147].init(52, "BODKIN"); + _vocabulary[148].init(52, "DAGGER"); + _vocabulary[149].init(53, "POTION"); + _vocabulary[150].init(54, "CHASTITY"); + _vocabulary[151].init(54, "BELT"); + _vocabulary[152].init(55, "BOLT"); + _vocabulary[153].init(55, "ARROW"); + _vocabulary[154].init(55, "DART"); + _vocabulary[155].init(56, "CROSSBOW"); + _vocabulary[156].init(56, "BOW"); + _vocabulary[157].init(57, "LUTE"); + _vocabulary[158].init(58, "PILGRIM"); + _vocabulary[159].init(58, "BADGE"); + _vocabulary[160].init(59, "MUSHROOMS"); + _vocabulary[161].init(59, "TOADSTOOLS"); + _vocabulary[162].init(60, "KEY"); + _vocabulary[163].init(61, "BELL"); + _vocabulary[164].init(62, "PRESCRIPT"); + _vocabulary[165].init(62, "SCROLL"); + _vocabulary[166].init(62, "MESSAGE"); + _vocabulary[167].init(63, "PEN"); + _vocabulary[168].init(63, "QUILL"); + _vocabulary[169].init(64, "INK"); + _vocabulary[170].init(64, "INKPOT"); + _vocabulary[171].init(65, "CLOTHES"); + _vocabulary[172].init(66, "HABIT"); + _vocabulary[173].init(66, "DISGUISE"); + _vocabulary[174].init(67, "ONION"); + + _vocabulary[175].init(99, "PASSWORD"); + + // Objects from Also are placed between 101 and 131. + // Nouns - People - Male: 150-174 + _vocabulary[176].init(150, "AVVY"); + _vocabulary[177].init(150, "AVALOT"); + _vocabulary[178].init(150, "YOURSELF"); + _vocabulary[179].init(150, "ME"); + _vocabulary[180].init(150, "MYSELF"); + _vocabulary[181].init(151, "SPLUDWICK"); + _vocabulary[182].init(151, "THOMAS"); + _vocabulary[183].init(151, "ALCHEMIST"); + _vocabulary[184].init(151, "CHEMIST"); + _vocabulary[185].init(152, "CRAPULUS"); + _vocabulary[186].init(152, "SERF"); + _vocabulary[187].init(152, "SLAVE"); + _vocabulary[188].init(158, "DU"); // Put in early for Baron DU Lustie to save confusion with Duck & Duke. + _vocabulary[189].init(152, "CRAPPY"); + _vocabulary[190].init(153, "DUCK"); + _vocabulary[191].init(153, "DOCTOR"); + _vocabulary[192].init(154, "MALAGAUCHE"); + _vocabulary[193].init(155, "FRIAR"); + _vocabulary[194].init(155, "TUCK"); + _vocabulary[195].init(156, "ROBIN"); + _vocabulary[196].init(156, "HOOD"); + _vocabulary[197].init(157, "CWYTALOT"); + _vocabulary[198].init(157, "GUARD"); + _vocabulary[199].init(157, "BRIDGEKEEP"); + _vocabulary[200].init(158, "BARON"); + _vocabulary[201].init(158, "LUSTIE"); + _vocabulary[202].init(159, "DUKE"); + _vocabulary[203].init(159, "GRACE"); + _vocabulary[204].init(160, "DOGFOOD"); + _vocabulary[205].init(160, "MINSTREL"); + _vocabulary[206].init(161, "TRADER"); + _vocabulary[207].init(161, "SHOPKEEPER"); + _vocabulary[208].init(161, "STALLHOLDER"); + _vocabulary[209].init(162, "PILGRIM"); + _vocabulary[210].init(162, "IBYTHNETH"); + _vocabulary[211].init(163, "ABBOT"); + _vocabulary[212].init(163, "AYLES"); + _vocabulary[213].init(164, "PORT"); + _vocabulary[214].init(165, "SPURGE"); + _vocabulary[215].init(166, "JACQUES"); + _vocabulary[216].init(166, "SLEEPER"); + _vocabulary[217].init(166, "RINGER"); + + // Nouns - People - Female: 175-199 + _vocabulary[218].init(175, "WIFE"); + _vocabulary[219].init(175, "ARKATA"); + _vocabulary[220].init(176, "GEDALODAVA"); + _vocabulary[221].init(176, "GEIDA"); + _vocabulary[222].init(176, "PRINCESS"); + _vocabulary[223].init(178, "WISE"); + _vocabulary[224].init(178, "WITCH"); + + // Pronouns: 200-224 + _vocabulary[225].init(200, "HIM"); + _vocabulary[226].init(200, "MAN"); + _vocabulary[227].init(200, "GUY"); + _vocabulary[228].init(200, "DUDE"); + _vocabulary[229].init(200, "CHAP"); + _vocabulary[230].init(200, "FELLOW"); + _vocabulary[231].init(201, "HER"); + _vocabulary[232].init(201, "GIRL"); + _vocabulary[233].init(201, "WOMAN"); + _vocabulary[234].init(202, "IT"); + _vocabulary[235].init(202, "THING"); + _vocabulary[236].init(203, "MONK"); + _vocabulary[237].init(204, "BARMAN"); + _vocabulary[238].init(204, "BARTENDER"); + + // Prepositions: 225-249 + _vocabulary[239].init(225, "TO"); + _vocabulary[240].init(226, "AT"); + _vocabulary[241].init(227, "UP"); + _vocabulary[242].init(228, "INTO"); + _vocabulary[243].init(228, "INSIDE"); + _vocabulary[244].init(229, "OFF"); + _vocabulary[245].init(230, "UP"); + _vocabulary[246].init(231, "DOWN"); + _vocabulary[247].init(232, "ON"); + + // Please: 251 + _vocabulary[248].init(251, "PLEASE"); + + // About: 252 + _vocabulary[249].init(252, "ABOUT"); + _vocabulary[250].init(252, "CONCERNING"); + + // Swear words: 253 + /* I M P O R T A N T M E S S A G E + + DO *NOT* READ THE LINES BELOW IF YOU ARE OF A SENSITIVE + DISPOSITION. THOMAS IS *NOT* RESPONSIBLE FOR THEM. + GOODNESS KNOWS WHO WROTE THEM. + READ THEM AT YOUR OWN RISK. BETTER STILL, DON'T READ THEM. + WHY ARE YOU SNOOPING AROUND IN MY PROGRAM, ANYWAY? */ + _vocabulary[251].init(253, "SHIT"); + _vocabulary[252].init(28 , "PISS"); + _vocabulary[253].init(28 , "PEE"); + _vocabulary[254].init(253, "FART"); + _vocabulary[255].init(253, "FUCK"); + _vocabulary[256].init(253, "BALLS"); + _vocabulary[257].init(253, "BLAST"); + _vocabulary[258].init(253, "BUGGER"); + _vocabulary[259].init(253, "KNICKERS"); + _vocabulary[260].init(253, "BLOODY"); + _vocabulary[261].init(253, "HELL"); + _vocabulary[262].init(253, "DAMN"); + _vocabulary[263].init(253, "SMEG"); + // ...and other even ruder words. You didn't read them, did you? Good. + + // Answer-back smart-alec words: 249 + _vocabulary[264].init(249, "YES"); + _vocabulary[265].init(249, "NO"); + _vocabulary[266].init(249, "BECAUSE"); + + // Noise words: 255 + _vocabulary[267].init(255, "THE"); + _vocabulary[268].init(255, "A"); + _vocabulary[269].init(255, "NOW"); + _vocabulary[270].init(255, "SOME"); + _vocabulary[271].init(255, "AND"); + _vocabulary[272].init(255, "THAT"); + _vocabulary[273].init(255, "POCUS"); + _vocabulary[274].init(255, "HIS"); + _vocabulary[275].init(255, "THIS"); + _vocabulary[276].init(255, "SENTINEL"); // for "Ken SENT Me" +} + +void Parser::handleInputText(const Common::Event &event) { + byte inChar = event.kbd.ascii; + warning("STUB: Parser::handleInputText()"); +// if (_vm->_menu->_activeMenuItem._activeNow) { +// _vm->_menu->parseKey(inChar, _vm->_enhanced->extd); +// } else { + if (_inputText.size() < 76) { + if ((inChar == '"') || (inChar == '`')) { + if (_quote) + inChar = '`'; + else + inChar = '"'; + _quote = !_quote; // quote - unquote + } + + _inputText.insertChar(inChar, _inputTextPos); + _inputTextPos++; + plotText(); + } else + _vm->_sound->blip(); +// } +} + +void Parser::handleBackspace() { + if (_vm->_menu->_activeMenuItem._activeNow) + return; + + if (_inputTextPos > 0) { + _inputTextPos--; + if ((_inputText[_inputTextPos] == '"') || (_inputText[_inputTextPos] == '`')) + _quote = !_quote; + _inputText.deleteChar(_inputTextPos); + plotText(); + } else + _vm->_sound->blip(); +} + +void Parser::handleReturn() { + if (_vm->_menu->_activeMenuItem._activeNow) + tryDropdown(); + else if (!_inputText.empty()) { + _inputTextBackup = _inputText; + parse(); + doThat(); + _inputText.clear(); + wipeText(); + } +} + +void Parser::handleFunctionKey(const Common::Event &event) { + switch (event.kbd.keycode) { + case Common::KEYCODE_F1: + _vm->callVerb(kVerbCodeHelp); + break; + case Common::KEYCODE_F2: + if (event.kbd.flags & Common::KBD_CTRL) { + clearWords(); + _vm->callVerb(kVerbCodeSave); + } else + _vm->_sound->toggleSound(); + break; + case Common::KEYCODE_F3: + if (event.kbd.flags & Common::KBD_CTRL) { + clearWords(); + _vm->callVerb(kVerbCodeLoad); + } else if (_inputText.size() < _inputTextBackup.size()) { + _inputText = _inputText + &(_inputTextBackup.c_str()[_inputText.size()]); + _inputTextPos = _inputText.size(); + plotText(); + } + break; + case Common::KEYCODE_F4: + if (event.kbd.flags & Common::KBD_ALT) + _vm->callVerb(kVerbCodeQuit); + else + _vm->callVerb(kVerbCodeRestart); + break; + case Common::KEYCODE_F5: { + _person = kPeoplePardon; + _thing = kPardon; + Common::String f5does = _vm->f5Does(); + VerbCode verb = (VerbCode)(byte)f5does[0]; + _vm->callVerb(verb); + } + break; + case Common::KEYCODE_F6: + _vm->callVerb(kVerbCodePause); + break; + case Common::KEYCODE_F7: + if (event.kbd.flags & Common::KBD_CTRL) + _vm->majorRedraw(); + else + _vm->callVerb(kVerbCodeOpen); + break; + case Common::KEYCODE_F8: + _vm->callVerb(kVerbCodeLook); + break; + case Common::KEYCODE_F9: + _vm->callVerb(kVerbCodeScore); + break; + case Common::KEYCODE_F10: + if (event.kbd.flags & Common::KBD_SHIFT) + _vm->callVerb(kVerbCodeInfo); + else + _vm->callVerb(kVerbCodeQuit); + break; + case Common::KEYCODE_F11: + clearWords(); + _vm->callVerb(kVerbCodeSave); + break; + case Common::KEYCODE_F12: + clearWords(); + _vm->callVerb(kVerbCodeLoad); + break; + default: + break; + } +} + +void Parser::plotText() { + CursorMan.showMouse(false); + cursorOff(); + + _vm->_graphics->clearTextBar(); + _vm->_graphics->drawNormalText(_inputText, _vm->_font, 8, 24, 161, kColorWhite); + + cursorOn(); + CursorMan.showMouse(true); +} + +void Parser::cursorOn() { + if (_cursorState == true) + return; + _vm->_graphics->drawCursor(_inputTextPos); + _cursorState = true; +} + +void Parser::cursorOff() { + if (_cursorState == false) + return; + _vm->_graphics->drawCursor(_inputTextPos); + _cursorState = false; +} + +void Parser::tryDropdown() { + warning("STUB: Parser::tryDropdown()"); // TODO: Implement at the same time with Dropdown's keyboard handling. +} + +int16 Parser::getPos(const Common::String &crit, const Common::String &src) { + if (src.contains(crit)) + return strstr(src.c_str(),crit.c_str()) - src.c_str(); + else + return -1; +} + +void Parser::wipeText() { + CursorMan.showMouse(false); + cursorOff(); + + _vm->_graphics->clearTextBar(); + + _quote = true; + _inputTextPos = 0; + + cursorOn(); + CursorMan.showMouse(true); +} + +void Parser::clearWords() { + for (int i = 0; i < 11; i++) { + if (!_realWords[i].empty()) + _realWords[i].clear(); + } +} + +byte Parser::wordNum(Common::String word) { + if (word.empty()) + return 0; + + for (int32 i = kParserWordsNum - 1; i >= 0; i--) { + if (_vocabulary[i]._word == word) + return _vocabulary[i]._number; + } + + // If not found as a whole, we look for it as a substring. + for (int32 i = kParserWordsNum - 1; i >= 0; i--) { + if (Common::String(_vocabulary[i]._word.c_str(), word.size()) == word) + return _vocabulary[i]._number; + } + + return kPardon; +} + +void Parser::replace(Common::String oldChars, byte newChar) { + int16 pos = getPos(oldChars, _thats); + while (pos != -1) { + if (newChar == 0) + _thats.deleteChar(pos); + else { + for (uint i = pos; i < pos + oldChars.size(); i++) + _thats.deleteChar(pos); + _thats.insertChar(newChar, pos); + } + pos = getPos(oldChars, _thats); + } +} + +Common::String Parser::rank() { + static const RankType ranks[9] = { + {0, "Beginner"}, {10, "Novice"}, + {20, "Improving"}, {35, "Not bad"}, + {50, "Passable"}, {65, "Good"}, + {80, "Experienced"}, {108, "The BEST!"}, + {32767, "copyright'93"} + }; + + for (int i = 0; i < 8; i++) { + if ((_vm->_dnascore >= ranks[i]._score) && (_vm->_dnascore < ranks[i + 1]._score)) + return Common::String(ranks[i]._title); + } + return ""; +} + +Common::String Parser::totalTime() { + uint16 h, m, s; + + h = (uint16)(_vm->_totalTime / 65535); + s = (uint16)(_vm->_totalTime % 65535); + m = s / 60; + s = s % 60; + + Common::String result = "You've been playing for "; + if (h > 0) + result += Common::String::format("%d hours, ", h); + if ((m > 0) || (h != 0)) + result += Common::String::format("%d minutes and ", m); + return result + Common::String::format("%d seconds", s); +} + +void Parser::cheatParse(Common::String codes) { + warning("STUB: Parser::cheatParse()"); +} + +void Parser::stripPunctuation(Common::String &word) { + const char punct[] = "~`!@#$%^&*()_+-={}[]:\"|;'\\,./<>?"; + + for (int i = 0; i < 32; i++) { + for (;;) { + int16 pos = getPos(Common::String(punct[i]), word); + if (pos == -1) + break; + word.deleteChar(pos); + } + } +} + +void Parser::displayWhat(byte target, bool animate, bool &ambiguous) { + if (target == kPardon) { + ambiguous = true; + if (animate) + _vm->_dialogs->displayText("Whom?"); + else + _vm->_dialogs->displayText("What?"); + } else { + if (animate) { + Common::String tmpStr = Common::String::format("{ %s }", _vm->getName((People)target).c_str()); + _vm->_dialogs->displayText(tmpStr); + } else { + Common::String z = _vm->getItem(target); + if (z != "") { + Common::String tmpStr = Common::String::format("{ %s }", z.c_str()); + _vm->_dialogs->displayText(tmpStr); + } + } + } +} + +bool Parser::doPronouns() { + bool ambiguous = false; + + for (uint i = 0; i < _thats.size(); i++) { + byte wordCode = _thats[i]; + switch (wordCode) { + case 200: + displayWhat(_vm->_him, true, ambiguous); + _thats.setChar(_vm->_him, i); + break; + case 201: + displayWhat(_vm->_her, true, ambiguous); + _thats.setChar(_vm->_her, i); + break; + case 202: + displayWhat(_vm->_it, false, ambiguous); + _thats.setChar(_vm->_it, i); + break; + } + } + + return ambiguous; +} + +void Parser::properNouns() { + _inputText.toLowercase(); + + // We set every word's first character to uppercase. + for (uint i = 1; i < (_inputText.size() - 1); i++) { + if (_inputText[i] == ' ') + _inputText.setChar(toupper(_inputText[i + 1]), i + 1); + } + + // And the first character as well. + _inputText.setChar(toupper(_inputText[0]), 0); +} + +void Parser::storeInterrogation(byte interrogation) { + if (_inputText.empty()) + return; + + // Strip _inputText: + while ((_inputText[0] == ' ') && (!_inputText.empty())) + _inputText.deleteChar(0); + while ((_inputText.lastChar() == ' ') && (!_inputText.empty())) + _inputText.deleteLastChar(); + + _vm->_timer->loseTimer(Timer::kReasonCardiffsurvey); // If you want to use any other timer, put this into the case statement. + + switch (interrogation) { + case 1: + _inputText.toLowercase(); + _vm->_dialogs->sayIt(_inputText); + _vm->_favouriteDrink = _inputText; + _vm->_cardiffQuestionNum = 2; + break; + case 2: + properNouns(); + _vm->_dialogs->sayIt(_inputText); + _vm->_favouriteSong = _inputText; + _vm->_cardiffQuestionNum = 3; + break; + case 3: + properNouns(); + _vm->_dialogs->sayIt(_inputText); + _vm->_worstPlaceOnEarth = _inputText; + _vm->_cardiffQuestionNum = 4; + break; + case 4: + _inputText.toLowercase(); + _vm->_dialogs->sayIt(_inputText); + if (!_vm->_spareEvening.empty()) + _vm->_spareEvening.clear(); + _vm->_spareEvening = _inputText; + _vm->_dialogs->displayScrollChain('z', 5); // His closing statement... + _vm->_animation->_sprites[1]->walkTo(3); // The end of the drawbridge + _vm->_animation->_sprites[1]->_vanishIfStill = true; // Then go away! + _vm->_magics[1]._operation = kMagicNothing; + _vm->_cardiffQuestionNum = 5; + break; + case 99: + //store_high(_inputText); + warning("STUB: Parser::store_interrogation()"); + break; + } + + if (interrogation < 4) + _vm->_timer->cardiffSurvey(); +} + + + +void Parser::parse() { + // First parsing - word identification + if (!_thats.empty()) + _thats.clear(); + + _polite = false; + _verb = kVerbCodePardon; + _thing = kPardon; + _thing2 = kPardon; + _person = kPeoplePardon; + clearWords(); + + + // A cheat mode attempt. + if (_inputText[0] == '.') { + cheatParse(_inputText); + _thats = kNothing; + return; + } + + // Are we being interrogated right now? + if (_vm->_interrogation > 0) { + storeInterrogation(_vm->_interrogation); + _weirdWord = true; + return; + } + + // Actually process the command. + Common::String inputText = _inputText + ' '; + Common::String inputTextUpper = inputText; + byte n = 0; + inputTextUpper.toUppercase(); + while (!inputTextUpper.empty()) { + while ((!inputTextUpper.empty()) && (inputTextUpper[0] == ' ')) { + inputTextUpper.deleteChar(0); + inputText.deleteChar(0); + } + if (inputTextUpper.empty()) + break; + + // Get the following word of the strings. + byte size = getPos(Common::String(' '), inputTextUpper) + 1; + char *subStr = new char[size]; + Common::strlcpy(subStr, inputTextUpper.c_str(), size); + Common::String thisword = subStr; + Common::strlcpy(subStr, inputText.c_str(), size); + _realWords[n] = subStr; + delete[] subStr; + + stripPunctuation(inputTextUpper); + + bool notfound = true; + + // Check also[] first, which contains words about the actual room. + if (!thisword.empty()) { + for (int i = 0; i < 31; i++) { + if ((_vm->_also[i][0]) && (getPos(',' + thisword, *_vm->_also[i][0]) > -1)) { + _thats += Common::String(99 + i); + notfound = false; + } + } + } + + // Check Accis's own table (words[]) for "global" commands. + if (notfound) { + byte answer = wordNum(thisword); + if (answer == kPardon) { + notfound = true; + _thats = _thats + kPardon; + } else + _thats = _thats + answer; + n++; + } + + // Delete words we already processed. + int16 spacePos = getPos(Common::String(' '), inputTextUpper); + if (spacePos > -1) { + for (int i = 0; i <= spacePos; i++) + inputTextUpper.deleteChar(0); + } + + spacePos = getPos(Common::String(' '), inputText); + if (spacePos > -1) { + for (int i = 0; i <= spacePos; i++) + inputText.deleteChar(0); + } + } + + Common::String unkString; + int16 pos = getPos(Common::String('\xFE'), _thats); + if (pos > -1) + unkString = _realWords[pos]; + else + unkString.clear(); + + // Replace words' codes that mean the same. + replace(Common::String("\xFF"), 0); // zap noise words + replace(Common::String("\xD\xE2"), 1); // "look at" = "examine" + replace(Common::String("\xD\xE4"), 1); // "look in" = "examine" + replace(Common::String("\x4\xE6"), 17); // "get up" = "stand" + replace(Common::String("\x4\xE7"), 17); // "get down" = "stand"... well, why not? + replace(Common::String("\x12\xE4"), 2); // "go in" = "open [door]" + replace(Common::String("\x1C\xE5"), 253); // "P' off" is a swear word + replace(Common::String("\x4\x6"), 6); // "Take inventory" (remember Colossal Adventure?) + replace(Common::String("\x28\xE8"), 21); // "put on" = "don" + replace(Common::String("\x4\xE5"), 20); // "take off" = "doff" + + // Words that could mean more than one _person + if (_vm->_room == kRoomNottsPub) + replace(Common::String('\xCC'), 164); // Barman = Port + else + replace(Common::String('\xCC'), 154); // Barman = Malagauche + + switch (_vm->_room) { + case kRoomAylesOffice: + replace(Common::String('\xCB'), 163); // Monk = Ayles + break; + case kRoomMusicRoom: + replace(Common::String('\xCB'), 166); // Monk = Jacques + break; + default: + replace(Common::String('\xCB'), 162); // Monk = Ibythneth + } + + if (doPronouns()) { + _weirdWord = true; + _thats = kNothing; + return; + } + + // Second parsing. + _vm->_subjectNum = 0; // Find subject of conversation. + + for (int i = 0; (i < 11) && !_realWords[i].empty(); i++) { + if ((_realWords[i][0] == '\'') || (_realWords[i][0] == '\"')) { + _vm->_subjectNum = (byte)_thats[i]; + _thats.setChar(kMoved, i); + break; + } + } + + if ((_vm->_subjectNum == 0) && !_thats.empty()) { // Still not found. + for (uint16 i = 0; i < _thats.size() - 1; i++) { + if ((byte)_thats[i] == 252) { // The word is "about", or something similar. + _vm->_subjectNum = (byte)_thats[i + 1]; + _thats.setChar(0, i + 1); + break; + } + } + } + + if ((_vm->_subjectNum == 0) && !_thats.empty()) { // STILL not found! Must be the word after "say". + for (uint16 i = 0; i < _thats.size() - 1; i++) { + if (((byte)_thats[i] == 7) && ((byte)_thats[i + 1] != 0) && !((225 <= (byte)_thats[i + 1]) && ((byte)_thats[i + 1] <= 229))) { + // SAY not followed by a preposition + _vm->_subjectNum = (byte)_thats[i + 1]; + _thats.setChar(0, i + 1); + break; + } + } + } + + for (int16 i = _thats.size() - 1; i >= 0; i--) { // Reverse order, so first will be used. + byte curChar = (byte)_thats[i]; + if ((curChar == 253) || (curChar == 249) || ((1 <= curChar) && (curChar <= 49))) + _verb = (VerbCode)curChar; + else if ((50 <= curChar) && (curChar <= 149)) { + _thing2 = _thing; + _thing = curChar; + } else if ((150 <= curChar) && (curChar <= 199)) + _person = (People)curChar; + else if (curChar == 251) + _polite = true; + } + + if ((!unkString.empty()) && (_verb != kVerbCodeExam) && (_verb != kVerbCodeTalk) && + (_verb != kVerbCodeSave) && (_verb != kVerbCodeLoad) && (_verb != kVerbCodeDir)) { + Common::String tmpStr = Common::String::format("Sorry, but I have no idea what \"%s\" means. Can you rephrase it?", unkString.c_str()); + _vm->_dialogs->displayText(tmpStr); + _weirdWord = true; + } else + _weirdWord = false; + + if (_thats.empty()) + _thats = kNothing; + + if (_thing != kPardon) + _vm->_it = _thing; + + if (_person != kPardon) { + if (_person < kPeopleArkata) + _vm->_him = _person; + else + _vm->_her = _person; + } +} + +void Parser::examineObject() { + if (_thing != _vm->_thinks) + _vm->thinkAbout(_thing, AvalancheEngine::kThing); + switch (_thing) { + case kObjectWine : + // 4 is perfect wine. 0 is not holding the wine. + switch (_vm->_wineState) { + case 1: + // Normal examine wine scroll + _vm->_dialogs->displayScrollChain('t', 1); + break; + case 2: + // Bad wine + _vm->_dialogs->displayScrollChain('d', 6); + break; + case 3: + // Vinegar + _vm->_dialogs->displayScrollChain('d', 7); + break; + } + break; + case kObjectOnion: + if (_vm->_rottenOnion) + // Yucky onion + _vm->_dialogs->displayScrollChain('q', 21); + else + // Normal onion + _vm->_dialogs->displayScrollChain('t', 18); + break; + default: + // Ordinarily + _vm->_dialogs->displayScrollChain('t', _thing); + } +} + +bool Parser::isPersonHere() { + // Person equivalent of "isHolding". + if ((_person == kPeoplePardon) || (_person == kPeopleNone) || (_vm->getRoom(_person) == _vm->_room)) + return true; + else { + Common::String tmpStr; + if (_person < kPeopleArkata) + tmpStr = "He isn't around at the moment."; + else + tmpStr = "She isn't around at the moment."; + _vm->_dialogs->displayText(tmpStr); + return false; + } +} + +void Parser::exampers() { + if (isPersonHere()) { + if (_thing != _vm->_thinks) + _vm->thinkAbout(_person, AvalancheEngine::kPerson); + + byte newPerson = _person - 149; + + if ((_person == kPeopleDogfood) && _vm->_wonNim) + // "I'm Not Playing!" + _vm->_dialogs->displayScrollChain('Q', 8); + else if ((_person == kPeopleDuLustie) && _vm->_lustieIsAsleep) + // He's asleep. + _vm->_dialogs->displayScrollChain('Q', 65); + else + _vm->_dialogs->displayScrollChain('p', newPerson); + + if ((_person == kPeopleAyles) && !_vm->_aylesIsAwake) + _vm->_dialogs->displayScrollChain('Q', 13); + + // CHECKME: Present in the original, but it doesn't make sense. + // _person = newPerson; + } +} + +/** + * Return whether Avvy is holding an object or not + * @remarks Originally called 'holding' + */ +bool Parser::isHolding() { + // Also object + if ((51 <= _thing) && (_thing <= 99)) + return true; + + bool holdingResult = false; + + if (_thing > 100) + _vm->_dialogs->displayText("Be reasonable!"); + else if (!_vm->_objects[_thing - 1]) + // Verbs that need "_thing" to be in the inventory. + _vm->_dialogs->displayText("You're not holding it, Avvy."); + else + holdingResult = true; + + return holdingResult; +} + +void Parser::openBox(bool isOpening) { + if ((_vm->_room == kRoomYours) && (_thing == 54)) { + _vm->_background->draw(-1, -1, 4); + + _vm->_background->update(); + _vm->_animation->animLink(); + _vm->_graphics->refreshScreen(); + + _vm->_system->delayMillis(55); + + if (!isOpening) { + _vm->_background->draw(-1, -1, 5); + _vm->_background->update(); + _vm->_animation->animLink(); + _vm->_graphics->refreshScreen(); + } + } +} + +void Parser::examine() { + // EITHER it's an object OR it's an Also OR it's a _person OR it's something else. + if ((_person == kPeoplePardon) && (_thing != kPardon)) { + if (isHolding()) { + // Remember: it's been slipped! Ie subtract 49. + if ((1 <= _thing) && (_thing <= 49)) + // Standard object + examineObject(); + else if ((50 <= _thing) && (_thing <= 100)) { + // Also _thing + openBox(true); + _vm->_dialogs->displayText(*_vm->_also[_thing - 50][1]); + openBox(false); + } + } + } else if (_person != kPardon) + exampers(); + else + // Don't know: guess. + _vm->_dialogs->displayText("It's just as it looks on the picture."); +} + +void Parser::inventory() { + byte itemNum = 0; + Common::String tmpStr = Common::String("You're carrying "); + + for (int i = 0; i < kObjectNum; i++) { + if (_vm->_objects[i]) { + itemNum++; + if (itemNum == _vm->_carryNum) + tmpStr += "and "; + + tmpStr += _vm->getItem(i + 1); + + if ((i + 1) == _wearing) + tmpStr += ", which you're wearing"; + + if (itemNum < _vm->_carryNum) + tmpStr += ", "; + } + } + + if (_wearing == kNothing) + tmpStr += Common::String::format("...%c%c...and you're stark naked!", kControlNewLine, kControlNewLine); + else + tmpStr += '.'; + + _vm->_dialogs->displayText(tmpStr); +} + +/** + * Eat something. + */ +void Parser::swallow() { + switch (_thing) { + case kObjectWine: + // _wineState == 4 for perfect wine + switch (_vm->_wineState) { + case 1: + if (_vm->_teetotal) { + _vm->_dialogs->displayScrollChain('D', 6); + return; + } + _vm->_dialogs->displayScrollChain('U', 1); + _vm->_pingo->wobble(); + _vm->_dialogs->displayScrollChain('U', 2); + _vm->_objects[kObjectWine - 1] = false; + _vm->refreshObjectList(); + drink(); + break; + case 2: + case 3: + // You can't drink it! + _vm->_dialogs->displayScrollChain('d', 8); + break; + } + break; + case kObjectPotion: + _vm->_graphics->setBackgroundColor(kColorRed); + _vm->_dialogs->displayScrollChain('U', 3); + _vm->gameOver(); + _vm->_graphics->setBackgroundColor(kColorBlack); + break; + case kObjectInk: + _vm->_dialogs->displayScrollChain('U', 4); + break; + case kObjectChastity: + _vm->_dialogs->displayScrollChain('U', 5); + break; + case kObjectMushroom: + _vm->_dialogs->displayScrollChain('U', 6); + _vm->gameOver(); + break; + case kObjectOnion: + if (_vm->_rottenOnion) + _vm->_dialogs->displayScrollChain('U', 11); + else { + _vm->_dialogs->displayScrollChain('U', 8); + _vm->_objects[kObjectOnion - 1] = false; + _vm->refreshObjectList(); + } + break; + default: + if ((_vm->_room == kRoomArgentPub) || (_vm->_room == kRoomNottsPub)) + _vm->_dialogs->displayText("Try BUYing things before you drink them!"); + else + _vm->_dialogs->displayText("The taste of it makes you retch!"); + } +} + +void Parser::peopleInRoom() { + // First compute the number of people in the room. + byte numPeople = 0; + for (int i = 151; i < 179; i++) { // Start at 1 so we don't list Avvy himself! + if (_vm->getRoom((People)i) == _vm->_room) + numPeople++; + } + + // If nobody's here, we can cut out straight away. + if (numPeople == 0) + return; + + Common::String tmpStr; + byte actPerson = 0; + for (int i = 151; i < 179; i++) { + if (_vm->getRoom((People)i) == _vm->_room) { + actPerson++; + if (actPerson == 1) + // Display first name on the list. + tmpStr = _vm->getName((People)i); + else if (actPerson < numPeople) + // Display one the names in the middle of the list + tmpStr += ", " + _vm->getName((People)i); + else + // Display the last name of the list + tmpStr += " and " + _vm->getName((People)i); + } + } + + if (numPeople == 1) + tmpStr += " is"; + else + tmpStr += " are"; + + _vm->_dialogs->displayText(tmpStr + " here."); +} + +void Parser::lookAround() { + _vm->_dialogs->displayText(*_vm->_also[0][1]); + switch (_vm->_room) { + case kRoomSpludwicks: + if (_vm->_avariciusTalk > 0) + _vm->_dialogs->displayScrollChain('q', 23); + else + peopleInRoom(); + break; + case kRoomRobins: + if (_vm->_tiedUp) + _vm->_dialogs->displayScrollChain('q', 38); + if (_vm->_mushroomGrowing) + _vm->_dialogs->displayScrollChain('q', 55); + break; + case kRoomInsideCardiffCastle: + if (!_vm->_takenPen) + _vm->_dialogs->displayScrollChain('q', 49); + break; + case kRoomLustiesRoom: + if (_vm->_lustieIsAsleep) + _vm->_dialogs->displayScrollChain('q', 65); + break; + case kRoomCatacombs: + switch (_vm->_catacombY * 256 + _vm->_catacombX) { + case 258 : + // Inside art gallery. + _vm->_dialogs->displayScrollChain('q', 80); + break; + case 514 : + // Outside ditto. + _vm->_dialogs->displayScrollChain('q', 81); + break; + case 260 : + // Outside Geida's room. + _vm->_dialogs->displayScrollChain('q', 82); + break; + } + break; + default: + peopleInRoom(); + } +} + +void Parser::openDoor() { + // Special cases. + switch (_vm->_room) { + case kRoomYours: + if (_vm->_animation->inField(1)) { + // Opening the box. + _thing = 54; // The box. + _person = kPeoplePardon; + examine(); + return; + } + break; + case kRoomSpludwicks: + if (_thing == 61) { + _vm->_dialogs->displayScrollChain('q', 85); + return; + } + break; + default: + break; + } + + if ((!_vm->_userMovesAvvy) && (_vm->_room != kRoomLusties)) + // No doors can open if you can't move Avvy. + return; + + for (int i = 0; i < 7; i++) { + if (_vm->_animation->inField(i + 8)) { + MagicType *portal = &_vm->_portals[i]; + switch (portal->_operation) { + case kMagicExclaim: + _vm->_animation->_sprites[0]->bounce(); + _vm->_dialogs->displayScrollChain('x', portal->_data); + break; + case kMagicTransport: + _vm->flipRoom((Room)((portal->_data) >> 8), portal->_data & 0x0F); + break; + case kMagicUnfinished: + _vm->_animation->_sprites[0]->bounce(); + _vm->_dialogs->displayText("Sorry. This place is not available yet!"); + break; + case kMagicSpecial: + _vm->_animation->callSpecial(portal->_data); + break; + case kMagicOpenDoor: + _vm->openDoor((Room)(portal->_data >> 8), portal->_data & 0x0F, i + 9); + break; + } + + return; + } + } + + if (_vm->_room == kRoomMap) + _vm->_dialogs->displayText("Avvy, you can complete the whole game without ever going " \ + "to anywhere other than Argent, Birmingham, Cardiff, Nottingham and Norwich."); + else + _vm->_dialogs->displayText("Door? What door?"); +} + +void Parser::putProc() { + if (!isHolding()) + return; + + // Slip the second object. + _thing2 -= 49; + char temp = _thing; + _thing = _thing2; + if (!isHolding()) + return; + _thing = temp; + + // Thing is the _thing which you're putting in. _thing2 is where you're putting it. + switch (_thing2) { + case kObjectWine: + if (_thing == kObjectOnion) { + if (_vm->_rottenOnion) + _vm->_dialogs->displayText("That's a bit like shutting the stable door after the horse has bolted!"); + else { + // Put onion into wine? + if (_vm->_wineState != 3) { + Common::String tmpStr = Common::String::format("%cOignon au vin%c is a bit too strong for your tastes!", + kControlItalic, kControlRoman); + _vm->_dialogs->displayText(tmpStr); + } else { + // Put onion into vinegar! Yes! + _vm->_onionInVinegar = true; + _vm->incScore(7); + _vm->_dialogs->displayScrollChain('u', 9); + } + } + } else + _vm->_dialogs->saySilly(); + break; + + case 54: + if (_vm->_room == kRoomYours) { + // Put something into the box. + if (_vm->_boxContent != kNothing) + _vm->_dialogs->displayText("There's something in the box already, Avvy. Try taking that out first."); + else { + switch (_thing) { + case kObjectMoney: + _vm->_dialogs->displayText("You'd better keep some ready cash on you!"); + break; + case kObjectBell: + _vm->_dialogs->displayText("That's a silly place to keep a bell."); + break; + case kObjectBodkin: + _vm->_dialogs->displayText("But you might need it!"); + break; + case kObjectOnion: + _vm->_dialogs->displayText("Just give it to Spludwick, Avvy!"); + break; + default: + // Put the object into the box... + if (_wearing == _thing) { + Common::String tmpStr = Common::String::format("You'd better take %s off first!", _vm->getItem(_thing).c_str()); + _vm->_dialogs->displayText(tmpStr); + } else { + // Open box. + openBox(true); + + _vm->_boxContent = _thing; + _vm->_objects[_thing - 1] = false; + _vm->refreshObjectList(); + _vm->_dialogs->displayText("OK, it's in the box."); + + // Shut box. + openBox(false); + } + } + } + } else + _vm->_dialogs->saySilly(); + break; + + default: + _vm->_dialogs->saySilly(); + } +} + +/** + * Display text when ingredients are not in the right order + * @remarks Originally called 'not_in_order' + */ +void Parser::notInOrder() { + Common::String itemStr = _vm->getItem(_vm->kSpludwicksOrder[_vm->_givenToSpludwick]); + Common::String tmpStr = Common::String::format("Sorry, I need the ingredients in the right order for this potion. " \ + "What I need next is %s%c2%c", itemStr.c_str(), kControlRegister, kControlSpeechBubble); + _vm->_dialogs->displayText(tmpStr); +} + +/** + * Move Spludwick to cauldron + * @remarks Originally called 'go_to_cauldron' + */ +void Parser::goToCauldron() { + // Stops Geida_Procs. + _vm->_animation->_sprites[1]->_callEachStepFl = false; + _vm->_timer->addTimer(1, Timer::kProcSpludwickGoesToCauldron, Timer::kReasonSpludwickWalk); + _vm->_animation->_sprites[1]->walkTo(1); +} + +/** + * Check is it's possible to give something to Spludwick + * @remarks Originally called 'give2spludwick' + */ +bool Parser::giveToSpludwick() { + if (_vm->kSpludwicksOrder[_vm->_givenToSpludwick] != _thing) { + notInOrder(); + return false; + } + + switch (_thing) { + case kObjectOnion: + _vm->_objects[kObjectOnion - 1] = false; + if (_vm->_rottenOnion) + _vm->_dialogs->displayScrollChain('q', 22); + else { + _vm->_givenToSpludwick++; + _vm->_dialogs->displayScrollChain('q', 20); + goToCauldron(); + _vm->incScore(3); + } + _vm->refreshObjectList(); + break; + case kObjectInk: + _vm->_objects[kObjectInk - 1] = false; + _vm->refreshObjectList(); + _vm->_givenToSpludwick++; + _vm->_dialogs->displayScrollChain('q', 24); + goToCauldron(); + _vm->incScore(3); + break; + case kObjectMushroom: + _vm->_objects[kObjectMushroom - 1] = false; + _vm->_dialogs->displayScrollChain('q', 25); + _vm->incScore(5); + _vm->_givenToSpludwick++; + goToCauldron(); + _vm->_objects[kObjectPotion - 1] = true; + _vm->refreshObjectList(); + break; + default: + return true; + } + return false; +} + +void Parser::drink() { + _alcoholLevel++; + if (_alcoholLevel == 5) { + // Get the key. + _vm->_objects[kObjectKey - 1] = true; + _vm->_teetotal = true; + _vm->_avvyIsAwake = false; + _vm->_avvyInBed = true; + _vm->refreshObjectList(); + _vm->fadeOut(); + _vm->flipRoom(kRoomYours, 1); + _vm->_graphics->setBackgroundColor(kColorYellow); + _vm->_animation->_sprites[0]->_visible = false; + } +} + +void Parser::cardiffClimbing() { + if (_vm->_standingOnDais) { + // Clamber up. + _vm->_dialogs->displayText("You climb down, back onto the floor."); + _vm->_standingOnDais = false; + _vm->_animation->appearPed(0, 2); + } else if (_vm->_animation->inField(0)) { + // Clamber down + _vm->_dialogs->displayText("You clamber up onto the dais."); + _vm->_standingOnDais = true; + _vm->_animation->appearPed(0, 1); + } else + _vm->_dialogs->displayText("Get a bit closer, Avvy."); +} + +void Parser::already() { + _vm->_dialogs->displayText("You're already standing!"); +} + +void Parser::standUp() { + switch (_vm->_room) { + case kRoomYours: + // Avvy isn't asleep. + if (_vm->_avvyIsAwake && _vm->_avvyInBed) { + // But he's in bed. + if (_vm->_teetotal) { + _vm->_dialogs->displayScrollChain('d', 12); + _vm->_graphics->setBackgroundColor(kColorBlack); + _vm->_dialogs->displayScrollChain('d', 14); + } + _vm->_animation->_sprites[0]->_visible = true; + _vm->_userMovesAvvy = true; + _vm->_animation->appearPed(0, 1); + _vm->_animation->setDirection(kDirLeft); + // Display a picture of empty pillow in the background. + _vm->_background->draw(-1, -1, 3); + _vm->incScore(1); + _vm->_avvyInBed = false; + _vm->_timer->loseTimer(Timer::kReasonArkataShouts); + } else + already(); + break; + + case kRoomInsideCardiffCastle: + cardiffClimbing(); + break; + + case kRoomNottsPub: + if (_vm->_sittingInPub) { + // Not sitting down. + _vm->_background->draw(-1, -1, 3); + // But standing up. + _vm->_animation->_sprites[0]->_visible = true; + // And walking away. + _vm->_animation->appearPed(0, 3); + // Really not sitting down. + _vm->_sittingInPub = false; + // And ambulant. + _vm->_userMovesAvvy = true; + } else + already(); + break; + default: + already(); + } +} + +void Parser::getProc(char thing) { + switch (_vm->_room) { + case kRoomYours: + if (_vm->_animation->inField(1)) { + if (_vm->_boxContent == thing) { + _vm->_background->draw(-1, -1, 4); + _vm->_dialogs->displayText("OK, I've got it."); + _vm->_objects[thing - 1] = true; + _vm->refreshObjectList(); + _vm->_boxContent = kNothing; + _vm->_background->draw(-1, -1, 5); + } else { + Common::String tmpStr = Common::String::format("I can't see %s in the box.", _vm->getItem(thing).c_str()); + _vm->_dialogs->displayText(tmpStr); + } + } else + _vm->_dialogs->displayScrollChain('q', 57); + break; + case kRoomInsideCardiffCastle: + switch (thing) { + case kObjectPen: + if (_vm->_animation->inField(1)) { + // Standing on the dais. + if (_vm->_takenPen) + _vm->_dialogs->displayText("It's not there, Avvy."); + else { + // OK: we're taking the pen, and it's there. + // No pen there now. + _vm->_background->draw(-1, -1, 3); + // Zap! + _vm->_animation->callSpecial(3); + _vm->_takenPen = true; + _vm->_objects[kObjectPen - 1] = true; + _vm->refreshObjectList(); + _vm->_dialogs->displayText("Taken."); + } + } else if (_vm->_standingOnDais) + _vm->_dialogs->displayScrollChain('q', 53); + else + _vm->_dialogs->displayScrollChain('q', 51); + break; + case kObjectBolt: + _vm->_dialogs->displayScrollChain('q', 52); + break; + default: + _vm->_dialogs->displayScrollChain('q', 57); + } + break; + case kRoomRobins: + if ((thing == kObjectMushroom) & (_vm->_animation->inField(0)) & (_vm->_mushroomGrowing)) { + _vm->_background->draw(-1, -1, 2); + _vm->_dialogs->displayText("Got it!"); + _vm->_mushroomGrowing = false; + _vm->_takenMushroom = true; + _vm->_objects[kObjectMushroom - 1] = true; + _vm->refreshObjectList(); + _vm->incScore(3); + } else + _vm->_dialogs->displayScrollChain('q', 57); + break; + default: + _vm->_dialogs->displayScrollChain('q', 57); + } +} + +/** + * Give the lute to Geida + * @remarks Originally called 'give_Geida_the_lute' + */ +void Parser::giveGeidaTheLute() { + if (_vm->_room != kRoomLustiesRoom) { + Common::String tmpStr = Common::String::format("Not yet. Try later!%c2%c", kControlRegister, kControlSpeechBubble); + _vm->_dialogs->displayText(tmpStr); + return; + } + _vm->_objects[kObjectLute - 1] = false; + _vm->refreshObjectList(); + // She plays it. + _vm->_dialogs->displayScrollChain('q', 64); + + _vm->_timer->addTimer(1, Timer::kProcGiveLuteToGeida, Timer::kReasonGeidaSings); + //_vm->_enid->backToBootstrap(4); TODO: Replace it with proper ScummVM-friendly function(s)! Do not remove until then! +} + +void Parser::playHarp() { + if (_vm->_animation->inField(6)) + _vm->_dialogs->displayMusicalScroll(); + else + _vm->_dialogs->displayText("Get a bit closer to it, Avvy!"); +} + +void Parser::winSequence() { + _vm->_dialogs->displayScrollChain('q', 78); + _vm->_sequence->startWinSeq(); + _vm->_timer->addTimer(30, Timer::kProcWinning, Timer::kReasonWinning); +} + +/** + * @remarks Originally called 'do_that' + */ +void Parser::doThat() { + static const char booze[8][8] = {"Bitter", "GIED", "Whisky", "Cider", "", "", "", "Mead"}; + static const char kWhat[] = "That's not possible!"; + + if (_thats == Common::String(kNothing)) { + if (!_thats.empty()) + _thats.clear(); + return; + } + + if (_weirdWord) + return; + + if (_thing < 200) + // "Slip" object + _thing -= 49; + + + if ((_verb != kVerbCodeLoad) && (_verb != kVerbCodeSave) && (_verb != kVerbCodeQuit) && (_verb != kVerbCodeInfo) && (_verb != kVerbCodeHelp) + && (_verb != kVerbCodeLarrypass) && (_verb != kVerbCodePhaon) && (_verb != kVerbCodeBoss) && (_verb != kVerbCodeCheat) && (_verb != kVerbCodeRestart) + && (_verb != kVerbCodeDir) && (_verb != kVerbCodeScore) && (_verb != kVerbCodeHiscores) && (_verb != kVerbCodeSmartAlec)) { + if (!_vm->_alive) { + _vm->_dialogs->displayText("You're dead, so don't talk. What are you, a ghost or something? " \ + "Try restarting, or restoring a saved game!"); + return; + } + if (!_vm->_avvyIsAwake && (_verb != kVerbCodeDie) && (_verb != kVerbCodeExpletive) && (_verb != kVerbCodeWake)) { + _vm->_dialogs->displayText("Talking in your sleep? Try waking up!"); + return; + } + } + + switch (_verb) { + case kVerbCodeExam: + examine(); + break; + case kVerbCodeOpen: + openDoor(); + break; + case kVerbCodePause: { + // Note that the original game doesn't care about the "O.K." box neither, it accepts + // clicks from everywhere on the screen to continue. Just like my code. + Common::String tmpStr = Common::String::format("Game paused.%c%c%cPress Enter, Esc, or click the mouse on the `O.K.\" " \ + "box to continue.", kControlCenter, kControlNewLine, kControlNewLine); + _vm->_dialogs->displayText(tmpStr); + } + break; + case kVerbCodeGet: + if (_thing != kPardon) { + // Legitimate try to pick something up. + if (_vm->_carryNum >= kCarryLimit) + _vm->_dialogs->displayText("You can't carry any more!"); + else + getProc(_thing); + } else { + // Not... ditto. + if (_person != kPeoplePardon) + _vm->_dialogs->displayText("You can't sweep folk off their feet!"); + else + _vm->_dialogs->displayText("I assure you, you don't need it."); + } + break; + case kVerbCodeDrop: + _vm->_dialogs->displayText("Two years ago you dropped a florin in the street. Three days " \ + "later it was gone! So now you never leave ANYTHING lying around. OK?"); + break; + case kVerbCodeInv: + inventory(); + break; + case kVerbCodeTalk: + if (_person == kPeoplePardon) { + if (_vm->_subjectNum == 99) { + // They typed "say password". + Common::String tmpStr = Common::String::format("Yes, but what %cis%c the password?", kControlItalic, kControlRoman); + _vm->_dialogs->displayText(tmpStr); + } else if (((1 <= _vm->_subjectNum) && (_vm->_subjectNum <= 49)) || (_vm->_subjectNum == 253) || (_vm->_subjectNum == 249)) { + _thats.deleteChar(0); + + for (int i = 0; i < 10; i++) + _realWords[i] = _realWords[i + 1]; + + _verb = (VerbCode)_vm->_subjectNum; + doThat(); + return; + } else { + _person = (People)_vm->_subjectNum; + _vm->_subjectNum = 0; + if ((_person == kPeopleNone) || (_person == kPeoplePardon)) + _vm->_dialogs->displayText("Talk to whom?"); + else if (isPersonHere()) + _vm->_dialogs->talkTo(_person); + } + } else if (isPersonHere()) + _vm->_dialogs->talkTo(_person); + break; + case kVerbCodeGive: + if (isHolding()) { + if (_person == kPeoplePardon) + _vm->_dialogs->displayText("Give to whom?"); + else if (isPersonHere()) { + switch (_thing) { + case kObjectMoney : + _vm->_dialogs->displayText("You can't bring yourself to give away your moneybag."); + break; + case kObjectBodkin: + case kObjectBell: + case kObjectClothes: + case kObjectHabit : + _vm->_dialogs->displayText("Don't give it away, it might be useful!"); + break; + default: + switch (_person) { + case kPeopleCrapulus: + if (_thing == kObjectWine) { + _vm->_dialogs->displayText("Crapulus grabs the wine and gulps it down."); + _vm->_objects[kObjectWine - 1] = false; + } else + _vm->_dialogs->sayThanks(_thing - 1); + break; + case kPeopleCwytalot: + if ((_thing == kObjectCrossbow) || (_thing == kObjectBolt)) + _vm->_dialogs->displayText("You might be able to influence Cwytalot more if you used it!"); + else + _vm->_dialogs->sayThanks(_thing - 1); + break; + case kPeopleSpludwick: + if (giveToSpludwick()) + _vm->_dialogs->sayThanks(_thing - 1); + break; + case kPeopleIbythneth: + if (_thing == kObjectBadge) { + _vm->_dialogs->displayScrollChain('q', 32); // Thanks! Wow! + _vm->incScore(3); + _vm->_objects[kObjectBadge - 1] = false; + _vm->_objects[kObjectHabit - 1] = true; + _vm->_givenBadgeToIby = true; + _vm->_background->draw(-1, -1, 7); + _vm->_background->draw(-1, -1, 8); + } else + _vm->_dialogs->sayThanks(_thing - 1); + break; + case kPeopleAyles: + if (_vm->_aylesIsAwake) { + if (_thing == kObjectPen) { + _vm->_objects[kObjectPen - 1] = false; + _vm->_dialogs->displayScrollChain('q', 54); + _vm->_objects[kObjectInk - 1] = true; + _vm->_givenPenToAyles = true; + _vm->refreshObjectList(); + _vm->incScore(2); + } else + _vm->_dialogs->sayThanks(_thing - 1); + } else + _vm->_dialogs->displayText("But he's asleep!"); + break; + case kPeopleGeida: + switch (_thing) { + case kObjectPotion: + _vm->_objects[kObjectPotion - 1] = false; + // She drinks it. + _vm->_dialogs->displayScrollChain('u', 16); + _vm->incScore(2); + _vm->_givenPotionToGeida = true; + _vm->refreshObjectList(); + break; + case kObjectLute: + giveGeidaTheLute(); + break; + default: + _vm->_dialogs->sayThanks(_thing - 1); + } + break; + case kPeopleArkata: + switch (_thing) { + case kObjectPotion: + if (_vm->_givenPotionToGeida) + winSequence(); + else + // That Geida woman! + _vm->_dialogs->displayScrollChain('q', 77); + break; + default: + _vm->_dialogs->sayThanks(_thing - 1); + } + break; + default: + _vm->_dialogs->sayThanks(_thing - 1); + } + } + } + // Just in case... + _vm->refreshObjectList(); + } + break; + + case kVerbCodeEat: + case kVerbCodeDrink: + if (isHolding()) + swallow(); + break; + + case kVerbCodeLoad: { + GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser("Restore game:", "Restore", false); + int16 savegameId = dialog->runModalWithCurrentTarget(); + delete dialog; + + if (savegameId < 0) + // dialog aborted, nothing to load + return; + + _vm->loadGame(savegameId); + } + break; + case kVerbCodeSave: { + GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser("Save game:", "Save", true); + int16 savegameId = dialog->runModalWithCurrentTarget(); + Common::String savegameDescription = dialog->getResultString(); + delete dialog; + + if (savegameId < 0) + // dialog aborted, nothing to save + return; + + _vm->saveGame(savegameId, savegameDescription); + } + break; + case kVerbCodePay: + _vm->_dialogs->displayText("No money need change hands."); + break; + case kVerbCodeLook: + lookAround(); + break; + case kVerbCodeBreak: + _vm->_dialogs->displayText("Vandalism is prohibited within this game!"); + break; + case kVerbCodeQuit: + if (!_polite) + _vm->_dialogs->displayText("How about a `please\", Avvy?"); + else { + Common::String tmpStr = Common::String::format("%cC%cDo you really want to quit?", kControlRegister, kControlIcon); + if (_vm->_dialogs->displayQuestion(tmpStr)) + _vm->_letMeOut = true; + } + break; + case kVerbCodeGo: + _vm->_dialogs->displayText("Just use the arrow keys to walk there."); + break; + case kVerbCodeInfo: { + _vm->_dialogs->_aboutBox = true; + + Common::String toDisplay; + for (int i = 0; i < 7; i++) + toDisplay += kControlNewLine; + toDisplay = toDisplay + "LORD AVALOT D'ARGENT" + kControlCenter + kControlNewLine + + "The medi\x91val descendant of" + kControlNewLine + + "Denarius Avaricius Sextus" + kControlNewLine + kControlNewLine + + "version " + kVersionNum + kControlNewLine + kControlNewLine + "Copyright \xEF " + + kCopyright + ", Mark, Mike and Thomas Thurman." + kControlRegister + 'Y' + kControlIcon; + _vm->_dialogs->displayText(toDisplay); + _vm->_dialogs->_aboutBox = false; + } + break; + case kVerbCodeUndress: + if (_wearing == kNothing) + _vm->_dialogs->displayText("You're already stark naked!"); + else if (_vm->_avvysInTheCupboard) { + Common::String tmpStr = Common::String::format("You take off %s.", _vm->getItem(_wearing).c_str()); + _vm->_dialogs->displayText(tmpStr); + _wearing = kNothing; + _vm->refreshObjectList(); + } else + _vm->_dialogs->displayText("Hadn't you better find somewhere more private, Avvy?"); + break; + case kVerbCodeWear: + if (isHolding()) { // Wear something. + switch (_thing) { + case kObjectChastity: + // \? are used to avoid that ??! is parsed as a trigraph + _vm->_dialogs->displayText("Hey, what kind of a weirdo are you\?\?!"); + break; + case kObjectClothes: + case kObjectHabit: { + // Change clothes! + if (_wearing != kNothing) { + if (_wearing == _thing) + _vm->_dialogs->displayText("You're already wearing that."); + else + _vm->_dialogs->displayText("You'll be rather warm wearing two sets of clothes!"); + return; + } else + _wearing = _thing; + + _vm->refreshObjectList(); + + byte i; + if (_thing == kObjectHabit) + i = 3; + else + i = 0; + + _vm->_animation->setAvvyClothes(i); + } + break; + default: + _vm->_dialogs->displayText(kWhat); + } + } + break; + case kVerbCodePlay: + if (_thing == kPardon) { + // They just typed "play"... + switch (_vm->_room) { + case kRoomArgentPub: + // ...in the pub, => play Nim. + warning("STUB: Parser::doThat() - case kVerbCodeplay - play_nim()"); + // play_nim(); + + // The following parts are copied from play_nim(). + // The player automatically wins the game everytime he wins, until I implement the mini-game. + if (_vm->_wonNim) { // Already won the game. + _vm->_dialogs->displayScrollChain('Q', 6); + return; + } + + if (!_vm->_askedDogfoodAboutNim) { + _vm->_dialogs->displayScrollChain('q', 84); + return; + } + + _vm->_dialogs->displayScrollChain('Q', 3); + _playedNim++; + + // You won - strange! + + // You won! Give us a lute! + _vm->_dialogs->displayScrollChain('Q', 7); + _vm->_objects[kObjectLute - 1] = true; + _vm->refreshObjectList(); + _vm->_wonNim = true; + // Show the settle with no lute on it. + _vm->_background->draw(-1, -1, 0); + // 7 points for winning! + _vm->incScore(7); + + if (_playedNim == 1) + // 3 points for playing your 1st game. + _vm->incScore(3); + + // A warning to the player that there should have been a mini-game. TODO: Remove it later!!! + _vm->_dialogs->displayText(Common::String("P.S.: There should have been the mini-game called \"Nim\", " \ + "but I haven't implemented it yet: you win and get the lute automatically.") + + kControlNewLine + kControlNewLine + "Peter (uruk)"); + break; + case kRoomMusicRoom: + playHarp(); + break; + default: + break; + } + } else if (isHolding()) { + switch (_thing) { + case kObjectLute : + _vm->_dialogs->displayScrollChain('U', 7); + + if (_vm->getRoom(kPeopleCwytalot) == _vm->_room) + _vm->_dialogs->displayScrollChain('U', 10); + + if (_vm->getRoom(kPeopleDuLustie) == _vm->_room) + _vm->_dialogs->displayScrollChain('U', 15); + break; + case 52: + if (_vm->_room == kRoomMusicRoom) + playHarp(); + else + _vm->_dialogs->displayText(kWhat); + break; + case 55: + if (_vm->_room == kRoomArgentPub) + // play_nim(); + warning("STUB: Parser::doThat() - case kVerbCodeplay - play_nim()"); + else + _vm->_dialogs->displayText(kWhat); + break; + default: + _vm->_dialogs->displayText(kWhat); + } + } + break; + case kVerbCodeRing: + if (isHolding()) { + if (_thing == kObjectBell) { + _vm->_dialogs->displayText("Ding, dong, ding, dong, ding, dong, ding, dong..."); + if ((_vm->_bellsAreRinging) & (_vm->getFlag('B'))) + // '\?' are used to avoid that '??!' is parsed as a trigraph + _vm->_dialogs->displayText("(Are you trying to join in, Avvy\?\?!)"); + } else + _vm->_dialogs->displayText(kWhat); + } + break; + case kVerbCodeHelp: + // boot_help(); + warning("STUB: Parser::doThat() - case kVerbCodehelp"); + break; + case kVerbCodeLarrypass: + _vm->_dialogs->displayText("Wrong game!"); + break; + case kVerbCodePhaon: + _vm->_dialogs->displayText("Hello, Phaon!"); + break; + case kVerbCodeBoss: + // bosskey(); + warning("STUB: Parser::doThat() - case kVerbCodeboss"); + break; + case kVerbCodePee: + if (_vm->getFlag('P')) { + _vm->_dialogs->displayText("Hmm, I don't think anyone will notice..."); + _vm->_timer->addTimer(4, Timer::kProcUrinate, Timer::kReasonGoToToilet); + } else { + Common::String tmpStr = Common::String::format("It would be %cVERY%c unwise to do that here, Avvy!", kControlItalic, kControlRoman); + _vm->_dialogs->displayText(tmpStr); + } + break; + case kVerbCodeCheat: { + Common::String tmpStr = Common::String::format("%cCheat mode now enabled.", kControlItalic); + _vm->_dialogs->displayText(tmpStr); + _vm->_cheat = true; + } + break; + case kVerbCodeMagic: + if (_vm->_avariciusTalk > 0) + _vm->_dialogs->displayScrollChain('q', 19); + else { + if ((_vm->_room == kRoomSpludwicks) & (_vm->_animation->inField(1))) { + // Avaricius appears! + _vm->_dialogs->displayScrollChain('q', 17); + if (_vm->getRoom(kPeopleSpludwick) == kRoomSpludwicks) + _vm->_dialogs->displayScrollChain('q', 18); + else { + Avalanche::AnimationType *spr = _vm->_animation->_sprites[1]; + // Avaricius + spr->init(1, false); + _vm->_animation->appearPed(1, 3); + spr->walkTo(4); + spr->_callEachStepFl = true; + spr->_eachStepProc = Animation::kProcBackAndForth; + _vm->_avariciusTalk = 14; + _vm->_timer->addTimer(177, Timer::kProcAvariciusTalks, Timer::kReasonAvariciusTalks); + } + } else + _vm->_dialogs->displayText("Nothing appears to happen..."); + } + break; + case kVerbCodeSmartAlec: + _vm->_dialogs->displayText("Listen, smart alec, that was just rhetoric."); + break; + case kVerbCodeExpletive: + switch (_sworeNum) { + case 0: { + Common::String tmpStr = Common::String::format("Avvy! Do you mind? There might be kids playing!%c%c" \ + "(I shouldn't say it again, if I were you!)", kControlNewLine, kControlNewLine); + _vm->_dialogs->displayText(tmpStr); + } + break; + case 1: { + Common::String tmpStr = Common::String::format("You hear a distant rumble of thunder. Must you always" \ + "do things I tell you not to?%c%cDon't do it again!", kControlNewLine, kControlNewLine); + _vm->_dialogs->displayText(tmpStr); + } + break; + default: { + _vm->_pingo->zonk(); + Common::String tmpStr = Common::String::format("A crack of lightning shoots from the sky, and fries you." \ + "%c%c(`Such is the anger of the gods, Avvy!\")", kControlNewLine, kControlNewLine); + _vm->_dialogs->displayText(tmpStr); + _vm->gameOver(); + } + } + _sworeNum++; + break; + case kVerbCodeListen: + if ((_vm->_bellsAreRinging) & (_vm->getFlag('B'))) + _vm->_dialogs->displayText("All other noise is drowned out by the ringing of the bells."); + else if (_vm->_listen.empty()) + _vm->_dialogs->displayText("You can't hear anything much at the moment, Avvy."); + else + _vm->_dialogs->displayText(_vm->_listen); + break; + case kVerbCodeBuy: + // What are they trying to buy? + switch (_vm->_room) { + case kRoomArgentPub: + // We're in a pub, and near the bar. + if (_vm->_animation->inField(5)) { + switch (_thing) { + case 51: + case 53: + case 54: + case 58: + // Beer, whisky, cider or mead. + if (_vm->_malagauche == 177) { + // Already getting us one. + _vm->_dialogs->displayScrollChain('D', 15); + return; + } + + if (_vm->_teetotal) { + _vm->_dialogs->displayScrollChain('D', 6); + return; + } + + if (_alcoholLevel == 0) + _vm->incScore(3); + + _vm->_background->draw(-1, -1, 11); + _vm->_dialogs->displayText(Common::String(booze[_thing - 51]) + ", please." + kControlRegister + '1' + kControlSpeechBubble); + _vm->_drinking = _thing; + + _vm->_background->draw(-1, -1, 9); + _vm->_malagauche = 177; + _vm->_timer->addTimer(27, Timer::kProcBuyDrinks, Timer::kReasonDrinks); + break; + case 52: + examine(); + break; // We have a right one here - buy Pepsi??! + case kObjectWine: + if (_vm->_objects[kObjectWine - 1]) + // We've already got the wine! + // 1 bottle's shufishent! + _vm->_dialogs->displayScrollChain('D', 2); + else { + if (_vm->_malagauche == 177) { + // Already getting us one. + _vm->_dialogs->displayScrollChain('D', 15); + return; + } + + if (_vm->_carryNum >= kCarryLimit) { + _vm->_dialogs->displayText("Your hands are full."); + return; + } + + _vm->_background->draw(-1, -1, 11); + Common::String tmpStr = Common::String::format("Wine, please.%c1%c", kControlRegister, kControlSpeechBubble); + _vm->_dialogs->displayText(tmpStr); + if (_alcoholLevel == 0) + _vm->incScore(3); + _vm->_background->draw(-1, -1, 9); + _vm->_malagauche = 177; + + _vm->_timer->addTimer(27, Timer::kProcBuyWine, Timer::kReasonDrinks); + } + break; + } + } else + // Go to the bar! + _vm->_dialogs->displayScrollChain('D', 5); + break; + + case kRoomOutsideDucks: + if (_vm->_animation->inField(5)) { + if (_thing == kObjectOnion) { + if (_vm->_objects[kObjectOnion - 1]) + // Not planning to juggle with the things! + _vm->_dialogs->displayScrollChain('D', 10); + else if (_vm->_carryNum >= kCarryLimit) + _vm->_dialogs->displayText("Before you ask, you remember that your hands are full."); + else { + if (_boughtOnion) + _vm->_dialogs->displayScrollChain('D', 11); + else { + _vm->_dialogs->displayScrollChain('D', 9); + _vm->incScore(3); + } + // It costs thruppence. + _vm->decreaseMoney(3); + _vm->_objects[kObjectOnion - 1] = true; + _vm->refreshObjectList(); + _boughtOnion = true; + // It's OK when it leaves the stall! + _vm->_rottenOnion = false; + _vm->_onionInVinegar = false; + } + } else + _vm->_dialogs->displayScrollChain('D', 0); + } else + _vm->_dialogs->displayScrollChain('D', 0); + break; + + case kRoomNottsPub: + // Can't sell to southerners. + _vm->_dialogs->displayScrollChain('n', 15); + break; + default: + // Can't buy that. + _vm->_dialogs->displayScrollChain('D', 0); + } + break; + case kVerbCodeAttack: + if ((_vm->_room == kRoomBrummieRoad) && + ((_person == kPeopleCwytalot) || (_thing == kObjectCrossbow) || (_thing == kObjectBolt)) && + (_vm->getRoom(kPeopleCwytalot) == _vm->_room)) { + switch (_vm->_objects[kObjectBolt - 1] + _vm->_objects[kObjectCrossbow - 1] * 2) { + // 0 = neither, 1 = only bolt, 2 = only crossbow, 3 = both. + case 0: + _vm->_dialogs->displayScrollChain('Q', 10); + _vm->_dialogs->displayText("(At the very least, don't use your bare hands!)"); + break; + case 1: + _vm->_dialogs->displayText("Attack _vm->him with only a crossbow bolt? Are you planning on playing darts?!"); + break; + case 2: + _vm->_dialogs->displayText("Come on, Avvy! You're not going to get very far with only a crossbow!"); + break; + case 3: + _vm->_dialogs->displayScrollChain('Q', 11); + _vm->_cwytalotGone = true; + _vm->_objects[kObjectBolt - 1] = false; + _vm->_objects[kObjectCrossbow - 1] = false; + _vm->refreshObjectList(); + _vm->_magics[11]._operation = kMagicNothing; + _vm->incScore(7); + _vm->_animation->_sprites[1]->walkTo(1); + _vm->_animation->_sprites[1]->_vanishIfStill = true; + _vm->_animation->_sprites[1]->_callEachStepFl = false; + _vm->setRoom(kPeopleCwytalot, kRoomDummy); + break; + default: + // Please try not to be so violent! + _vm->_dialogs->displayScrollChain('Q', 10); + } + } else + _vm->_dialogs->displayScrollChain('Q', 10); + break; + case kVerbCodePasswd: + if (_vm->_room != kRoomBridge) + _vm->_dialogs->displayScrollChain('Q', 12); + else { + bool ok = true; + for (uint i = 0; i < _thats.size(); i++) { + Common::String temp = _realWords[i]; + temp.toUppercase(); + int pwdId = _vm->_passwordNum + kFirstPassword; + for (uint j = 0; j < _vocabulary[pwdId]._word.size(); j++) { + if (_vocabulary[pwdId]._word[j] != temp[j]) + ok = false; + } + } + + if (ok) { + if (_vm->_drawbridgeOpen != 0) + _vm->_dialogs->displayText("Contrary to your expectations, the drawbridge fails to close again."); + else { + _vm->incScore(4); + _vm->_dialogs->displayText("The drawbridge opens!"); + _vm->_timer->addTimer(7, Timer::kProcOpenDrawbridge, Timer::kReasonDrawbridgeFalls); + _vm->_drawbridgeOpen = 1; + } + } else + _vm->_dialogs->displayScrollChain('Q', 12); + } + break; + case kVerbCodeDie: + _vm->gameOver(); + break; + case kVerbCodeScore: { + Common::String tmpStr = Common::String::format("Your score is %d,%c%cout of a possible 128.%c%c " \ + "This gives you a rank of %s.%c%c%s", _vm->_dnascore, kControlCenter, kControlNewLine, kControlNewLine, + kControlNewLine, rank().c_str(), kControlNewLine, kControlNewLine, totalTime().c_str()); + _vm->_dialogs->displayText(tmpStr); + } + break; + case kVerbCodePut: + putProc(); + break; + case kVerbCodeStand: + standUp(); + break; + case kVerbCodeKiss: + if (_person == kPeoplePardon) + _vm->_dialogs->displayText("Kiss whom?"); + else if (isPersonHere()) { + switch (_person) { + case kPeopleArkata: + _vm->_dialogs->displayScrollChain('U', 12); + break; + case kPeopleGeida: + _vm->_dialogs->displayScrollChain('U', 13); + break; + case kPeopleWisewoman: + _vm->_dialogs->displayScrollChain('U', 14); + break; + default: + // You WHAT? + _vm->_dialogs->displayScrollChain('U', 5); + } + } else if ((kPeopleAvalot <= _person) && (_person < kPeopleArkata)) + _vm->_dialogs->displayText("Hey, what kind of a weirdo are you??"); + + break; + case kVerbCodeClimb: + if (_vm->_room == kRoomInsideCardiffCastle) + cardiffClimbing(); + else + // In the wrong room! + _vm->_dialogs->displayText("Not with your head for heights, Avvy!"); + break; + case kVerbCodeJump: + _vm->_timer->addTimer(1, Timer::kProcJump, Timer::kReasonJumping); + _vm->_userMovesAvvy = false; + break; + case kVerbCodeHiscores: + // show_highs(); + warning("STUB: Parser::doThat() - case kVerbCodehighscores"); + break; + case kVerbCodeWake: + if (isPersonHere()) + switch (_person) { + case kPeoplePardon: + case kPeopleAvalot: + case 0: + if (!_vm->_avvyIsAwake) { + _vm->_avvyIsAwake = true; + _vm->incScore(1); + _vm->_avvyInBed = true; + // Picture of Avvy, awake in bed. + _vm->_background->draw(-1, -1, 2); + if (_vm->_teetotal) + _vm->_dialogs->displayScrollChain('d', 13); + } else + _vm->_dialogs->displayText("You're already awake, Avvy!"); + break; + case kPeopleAyles: + if (!_vm->_aylesIsAwake) + _vm->_dialogs->displayText("You can't seem to wake him by yourself."); + break; + case kPeopleJacques: { + Common::String tmpStr = Common::String::format("Brother Jacques, Brother Jacques, are you asleep?%c1%c" \ + "Hmmm... that doesn't seem to do any good...", kControlRegister, kControlSpeechBubble); + _vm->_dialogs->displayText(tmpStr); + } + break; + default: + _vm->_dialogs->displayText("It's difficult to awaken people who aren't asleep...!"); + } + break; + case kVerbCodeSit: + if (_vm->_room == kRoomNottsPub) { + if (_vm->_sittingInPub) + _vm->_dialogs->displayText("You're already sitting!"); + else { + // Move Avvy to the place, and sit him down. + _vm->_animation->_sprites[0]->walkTo(3); + _vm->_timer->addTimer(1, Timer::kProcAvvySitDown, Timer::kReasonSittingDown); + } + } else { + // Default doodah. + _vm->fadeOut(); + _vm->fadeIn(); + Common::String tmpStr = Common::String::format("A few hours later...%cnothing much has happened...", kControlParagraph); + _vm->_dialogs->displayText(tmpStr); + } + break; + case kVerbCodeRestart: + if (_vm->_dialogs->displayQuestion("Restart game and lose changes?")) { + _vm->fadeOut(); + _vm->newGame(); + _vm->fadeIn(); + } + break; + case kVerbCodePardon: + _vm->_dialogs->displayText("Hey, a verb would be helpful!"); + break; + case kVerbCodeHello: + _vm->_dialogs->sayHello(); + break; + case kVerbCodeThanks: + _vm->_dialogs->sayOK(); + break; + default: + Common::String tmpStr = Common::String::format("%cUnhandled verb: %d", kControlBell, _verb); + _vm->_dialogs->displayText(tmpStr); + } +} + +void Parser::verbOpt(byte verb, Common::String &answer, char &ansKey) { + // kVerbCodegive isn't dealt with by this procedure, but by ddm__with. + switch (verb) { + case kVerbCodeExam: + answer = "Examine"; + ansKey = 'x'; + break; + case kVerbCodeDrink: + answer = "Drink"; + ansKey = 'D'; + break; + case kVerbCodeWear: + answer = "Wear"; + ansKey = 'W'; + break; + case kVerbCodeRing: + answer = "Ring"; + ansKey = 'R'; + break; // Only the bell! + case kVerbCodePlay: + answer = "Play"; + ansKey = 'P'; + break; + case kVerbCodeEat: + answer = "Eat"; + ansKey = 'E'; + break; + default: + answer = "? Unknown!"; // Bug! + ansKey = '?'; + } +} + +void Parser::doVerb(VerbCode id) { + _weirdWord = false; + _polite = true; + _verb = id; + doThat(); +} + +void Parser::resetVariables() { + _wearing = 0; + _sworeNum = 0; + _alcoholLevel = 0; + _playedNim = 0; + _boughtOnion = false; +} + +void Parser::synchronize(Common::Serializer &sz) { + sz.syncAsByte(_wearing); + sz.syncAsByte(_sworeNum); + sz.syncAsByte(_alcoholLevel); + sz.syncAsByte(_playedNim); + sz.syncAsByte(_boughtOnion); +} + +} // End of namespace Avalanche diff --git a/engines/avalanche/parser.h b/engines/avalanche/parser.h new file mode 100644 index 0000000000..261e5ecefe --- /dev/null +++ b/engines/avalanche/parser.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 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on the original source code of Lord Avalot d'Argent version 1.3. + * Copyright (c) 1994-1995 Mike, Mark and Thomas Thurman. + */ + +#ifndef AVALANCHE_PARSER_H +#define AVALANCHE_PARSER_H + +#include "avalanche/enums.h" + +#include "common/events.h" +#include "common/str.h" +#include "common/serializer.h" + + +namespace Avalanche { +class AvalancheEngine; + +class Parser { +public: + static const byte kPardon = 254; // Didn't understand / wasn't given. + static const int16 kParserWordsNum = 277; // How many words does the parser know? + static const byte kNothing = 250; + static const byte kMoved = 0; // This word was moved. (Usually because it was the subject of conversation.) + static const int16 kFirstPassword = 88; // words[kFirstPassword] should equal "TIROS". + + struct VocabEntry { + byte _number; + Common::String _word; + + void init(byte number, Common::String word) { + _number = number; + _word = word; + } + }; + + VocabEntry _vocabulary[kParserWordsNum]; + + Common::String _realWords[11]; + VerbCode _verb; + byte _thing; + People _person; + bool _polite; + Common::String _inputText; // Original name: current + Common::String _inputTextBackup; + byte _inputTextPos; // Original name: curpos + bool _quote; // 66 or 99 next? + bool _cursorState; + bool _weirdWord; + + byte _wearing; // what you're wearing + + Parser(AvalancheEngine *vm); + + void init(); + void parse(); + void doThat(); + void verbOpt(byte verb, Common::String &answer, char &ansKey); + void drink(); + + void handleInputText(const Common::Event &event); + void handleBackspace(); + void handleReturn(); + void handleFunctionKey(const Common::Event &event); + void plotText(); + void cursorOn(); + void cursorOff(); + void tryDropdown(); // This asks the parsekey proc in Dropdown if it knows it. + int16 getPos(const Common::String &crit, const Common::String &src); // Returns the index of the first appearance of crit in src. + void doVerb(VerbCode id); + + void resetVariables(); + void synchronize(Common::Serializer &sz); + +private: + AvalancheEngine *_vm; + + struct RankType { + uint16 _score; + char _title[20]; + }; + + static const char *kCopyright; + static const char *kVersionNum; + + Common::String _thats; + byte _thing2; + byte _sworeNum; // number of times you've sworn + byte _alcoholLevel; // Your blood alcohol level. + byte _playedNim; // How many times you've played Nim. + bool _boughtOnion; // Have you bought an onion yet? + + byte wordNum(Common::String word); + void replace(Common::String oldChars, byte newChar); + + Common::String rank(); + Common::String totalTime(); + + void clearWords(); + void cheatParse(Common::String codes); + void stripPunctuation(Common::String &word); // Strips punctuation from word. + void displayWhat(byte target, bool animate, bool &ambiguous); // << It's an adjective! + bool doPronouns(); + void properNouns(); + void lookAround(); // This is called when you say "look". + void openDoor(); + void storeInterrogation(byte interrogation); + void examineObject(); // Examine a standard object-thing + bool isPersonHere(); + void exampers(); + bool isHolding(); + void openBox(bool isOpening); + void examine(); + void inventory(); + void swallow(); + void peopleInRoom(); // This lists the other people in the room. + void putProc(); // Called when you call kVerbCodeput. + void notInOrder(); + void goToCauldron(); + bool giveToSpludwick(); // The result of this fn is whether or not he says "Hey, thanks!". + void cardiffClimbing(); + void already(); + void standUp(); // Called when you ask Avvy to stand. + void getProc(char thing); + void giveGeidaTheLute(); + void playHarp(); + void winSequence(); + void wipeText(); +}; + +} // End of namespace Avalanche + +#endif // AVALANCHE_PARSER_H diff --git a/engines/avalanche/pingo.cpp b/engines/avalanche/pingo.cpp new file mode 100644 index 0000000000..433924f594 --- /dev/null +++ b/engines/avalanche/pingo.cpp @@ -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 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on the original source code of Lord Avalot d'Argent version 1.3. + * Copyright (c) 1994-1995 Mike, Mark and Thomas Thurman. + */ + +/* PINGO Full-screen sub-parts of the game. */ + +#include "avalanche/avalanche.h" +#include "avalanche/pingo.h" + +namespace Avalanche { + +Pingo::Pingo(AvalancheEngine *vm) { + _vm = vm; +} + +void Pingo::dPlot(int16 x, int16 y, Common::String z) { + warning("STUB: Pingo::dPlot()"); +} + +void Pingo::bossKey() { + warning("STUB: Pingo::bossKey()"); +} + +void Pingo::copy02() { // taken from Wobble (below) + warning("STUB: Pingo::copy02()"); +} + +void Pingo::copy03() { // taken from Wobble (below) + warning("STUB: Pingo::copy03()"); +} + +void Pingo::copyPage(byte frp, byte top) { // taken from Copy02 (above) + warning("STUB: Pingo::copyPage()"); +} + +void Pingo::wobble() { + warning("STUB: Pingo::wobble()"); +} + +void Pingo::zl(int16 x1, int16 y1, int16 x2, int16 y2) { + warning("STUB: Pingo::zl()"); +} + +void Pingo::zonk() { + warning("STUB: Pingo::zonk()"); +} + +void Pingo::winningPic() { + Common::File f; + _vm->fadeOut(); + + if (!f.open("finale.avd")) + error("AVALANCHE: File not found: finale.avd"); + +#if 0 + for (int bit = 0; bit <= 3; bit++) { + port[0x3c4] = 2; + port[0x3ce] = 4; + port[0x3c5] = 1 << bit; + port[0x3cf] = bit; + blockread(f, mem[0xa000 * 0], 16000); + } +#endif + + f.close(); + + warning("STUB: Pingo::winningPic()"); + + _vm->fadeIn(); + +#if 0 + do { + _vm->check(); + } while (!(keypressed() || (mrelease > 0))); + while (keypressed()) + char r = readkey(); + major_redraw(); +#endif + + warning("STUB: Pingo::winningPic()"); +} + +} // End of namespace Avalanche. diff --git a/engines/avalanche/pingo.h b/engines/avalanche/pingo.h new file mode 100644 index 0000000000..72fdb54c2a --- /dev/null +++ b/engines/avalanche/pingo.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 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on the original source code of Lord Avalot d'Argent version 1.3. + * Copyright (c) 1994-1995 Mike, Mark and Thomas Thurman. + */ + +/* PINGO Full-screen sub-parts of the game. */ + +#ifndef AVALANCHE_PINGO_H +#define AVALANCHE_PINGO_H + +#include "common/str.h" + +namespace Avalanche { +class AvalancheEngine; + +class Pingo { +public: + Pingo(AvalancheEngine *vm); + + void bossKey(); + void copy02(); + void copy03(); + void copyPage(byte frp, byte top); + void wobble(); + void zonk(); + void winningPic(); + +private: + AvalancheEngine *_vm; + + void dPlot(int16 x, int16 y, Common::String z); + void zl(int16 x1, int16 y1, int16 x2, int16 y2); +}; + +} // End of namespace Avalanche. + +#endif // AVALANCHE_PINGO_H diff --git a/engines/avalanche/sequence.cpp b/engines/avalanche/sequence.cpp new file mode 100644 index 0000000000..10fa7f0a00 --- /dev/null +++ b/engines/avalanche/sequence.cpp @@ -0,0 +1,228 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on the original source code of Lord Avalot d'Argent version 1.3. + * Copyright (c) 1994-1995 Mike, Mark and Thomas Thurman. + */ + +/* SEQUENCE The sequencer. */ + +#include "avalanche/avalanche.h" +#include "avalanche/sequence.h" + +namespace Avalanche { + +Sequence::Sequence(AvalancheEngine *vm) { + _vm = vm; +} + +void Sequence::resetVariables() { + _flipToWhere = kRoomNowhere; + _flipToPed = 0; +} + +void Sequence::init(byte what) { + _seq[0] = what; + + for (int i = 1; i < kSeqLength; i++) + _seq[i] = 0; +} + +void Sequence::add(byte what) { + for (int16 i = 0; i < kSeqLength; i++) { + if (_seq[i] == 0) { + _seq[i] = what; + return; + } + } +} + +void Sequence::switchRoom(Room where, byte ped) { + add(kNowFlip); + + _flipToWhere = where; + _flipToPed = ped; +} + +void Sequence::startTimer() { + _vm->_timer->loseTimer(Timer::kReasonSequencer); + _vm->_timer->addTimer(7, Timer::kProcSequence, Timer::kReasonSequencer); +} + +void Sequence::startTimerImmobilized() { + // They can't move. + _vm->_userMovesAvvy = false; + // And they're not moving now. + _vm->_animation->stopWalking(); + // Apart from that, it's the same thing. + startTimer(); +} + +void Sequence::shoveLeft() { + for (uint i = 0; i < kSeqLength - 1; i++) + _seq[i] = _seq[i + 1]; + _seq[kSeqLength - 1] = 0; +} + +void Sequence::callSequencer() { + byte curSeq = _seq[0]; + + switch (curSeq) { + case 0: + // No more routines. + return; + break; + case kNowFlip: + // Flip room. + _vm->_userMovesAvvy = true; + _vm->flipRoom(_flipToWhere, _flipToPed); + shoveLeft(); + break; + } + + if (curSeq <= 176) { + // Show a frame. + _vm->_background->draw(-1, -1, curSeq - 1); + shoveLeft(); + } + + // Make sure this PROC gets called again. + startTimer(); +} + +void Sequence::startHallSeq(Room whither, byte ped) { + init(1); + add(2); + switchRoom(whither, ped); + startTimerImmobilized(); +} + +void Sequence::startOutsideSeq(Room whither, byte ped) { + init(1); + add(2); + add(3); + switchRoom(whither, ped); + startTimerImmobilized(); +} + +void Sequence::startCardiffSeq(Room whither, byte ped) { + init(1); + add(5); + switchRoom(whither, ped); + startTimerImmobilized(); +} + +void Sequence::startNaughtyDukeSeq() { + init(2); + startTimer(); +} + +void Sequence::startGardenSeq() { + init(2); + add(1); + add(3); + startTimer(); +} + +void Sequence::startDuckSeq() { + init(3); + add(2); + add(1); + add(4); + startTimer(); +} + +void Sequence::startLustiesSeq3(Room whither, byte ped) { + init(4); + add(5); + add(6); + switchRoom(whither, ped); + startTimerImmobilized(); +} + +void Sequence::startMusicRoomSeq2(Room whither, byte ped) { + init(5); + add(6); + switchRoom(whither, ped); + startTimerImmobilized(); +} + +void Sequence::startGeidaLuteSeq() { + init(5); + // He falls asleep... + add(6); + // Not really closing, but we're using the same procedure. + startTimer(); +} + +void Sequence::startMusicRoomSeq() { + init(6); + add(5); + add(7); + startTimer(); +} + +void Sequence::startWinSeq() { + init(7); + add(8); + add(9); + startTimer(); +} + +void Sequence::startCupboardSeq() { + init(8); + add(7); + startTimer(); +} + +void Sequence::startLustiesSeq2(Room whither, byte ped) { + init(8); + add(9); + switchRoom(whither, ped); + startTimerImmobilized(); +} + +void Sequence::startCardiffSeq2() { + init(1); + if (_vm->_arrowInTheDoor) + add(3); + else + add(2); + + if (_vm->_takenPen) + _vm->_background->draw(-1, -1, 3); + + startTimer(); +} + +void Sequence::startDummySeq(Room whither, byte ped) { + switchRoom(whither, ped); + startTimerImmobilized(); +} + +void Sequence::synchronize(Common::Serializer &sz) { + sz.syncBytes(_seq, kSeqLength); + sz.syncAsByte(_flipToWhere); + sz.syncAsByte(_flipToPed); +} +} // End of namespace Avalanche. diff --git a/engines/avalanche/sequence.h b/engines/avalanche/sequence.h new file mode 100644 index 0000000000..d3c1b54963 --- /dev/null +++ b/engines/avalanche/sequence.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 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on the original source code of Lord Avalot d'Argent version 1.3. + * Copyright (c) 1994-1995 Mike, Mark and Thomas Thurman. + */ + +/* SEQUENCE The sequencer. */ + +#ifndef AVALANCHE_SEQUENCE_H +#define AVALANCHE_SEQUENCE_H + +namespace Avalanche { +class AvalancheEngine; + +class Sequence { +private: + static const int16 kNowFlip = 177; + static const int16 kSeqLength = 10; + + byte _seq[kSeqLength]; + + Room _flipToWhere; + byte _flipToPed; + + AvalancheEngine *_vm; + + void shoveLeft(); // This is called by Timer when it's time to do another frame. It shifts everything to the left. + void init(byte what); + void add(byte what); + void switchRoom(Room where, byte ped); + void startTimer(); + void startTimerImmobilized(); + +public: + Sequence(AvalancheEngine *vm); + void synchronize(Common::Serializer &sz); + void resetVariables(); + void callSequencer(); + + void startCupboardSeq(); + void startMusicRoomSeq(); + void startMusicRoomSeq2(Room whither, byte ped); + void startGardenSeq(); + void startGeidaLuteSeq(); + void startWinSeq(); + void startNaughtyDukeSeq(); + void startLustiesSeq2(Room whither, byte ped); + void startLustiesSeq3(Room whither, byte ped); + void startHallSeq(Room whither, byte ped); + void startCardiffSeq(Room whither, byte ped); + void startOutsideSeq(Room whither, byte ped); + void startDuckSeq(); + void startCardiffSeq2(); + void startDummySeq(Room whither, byte ped); +}; + +} // End of namespace Avalanche. + +#endif // AVALANCHE_SEQUENCE_H diff --git a/engines/avalanche/sound.cpp b/engines/avalanche/sound.cpp new file mode 100644 index 0000000000..c324df4713 --- /dev/null +++ b/engines/avalanche/sound.cpp @@ -0,0 +1,88 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "avalanche/avalanche.h" +#include "avalanche/sound.h" + +#include "audio/audiostream.h" +#include "common/config-manager.h" + +namespace Avalanche { + +SoundHandler::SoundHandler(AvalancheEngine *vm) : _vm(vm) { + _soundFl = true; + _speakerStream = new Audio::PCSpeaker(_vm->_mixer->getOutputRate()); + _vm->_mixer->playStream(Audio::Mixer::kSFXSoundType, &_speakerHandle, + _speakerStream, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::YES, true); +} + +SoundHandler::~SoundHandler() { + _vm->_mixer->stopHandle(_speakerHandle); +} + +/** + * Stop any sound that might be playing + */ +void SoundHandler::stopSound() { + _vm->_mixer->stopAll(); +} + +/** + * Turn digitized sound on and off + */ +void SoundHandler::toggleSound() { + _soundFl = !_soundFl; +} + +void SoundHandler::syncVolume() { + int soundVolume; + + if (ConfMan.getBool("sfx_mute") || ConfMan.getBool("mute")) + soundVolume = -1; + else + soundVolume = MIN(255, ConfMan.getInt("sfx_volume")); + + _vm->_mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, soundVolume); +} + +void SoundHandler::playNote(int freq, int length) { + // Does the user not want any sound? + if (!_soundFl || !_vm->_mixer->isReady()) + return; + + // Start a note playing (we will stop it when the timer expires). + _speakerStream->play(Audio::PCSpeaker::kWaveFormSquare, freq, length); +} + +void SoundHandler::click() { + _vm->_mixer->stopAll(); + + playNote(7177, 1); +} + +void SoundHandler::blip() { + _vm->_mixer->stopAll(); + + playNote(177, 77); +} + +} // End of namespace Avalanche diff --git a/engines/avalanche/sound.h b/engines/avalanche/sound.h new file mode 100644 index 0000000000..25b6b267d3 --- /dev/null +++ b/engines/avalanche/sound.h @@ -0,0 +1,53 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef AVALANCHE_SOUND_H +#define AVALANCHE_SOUND_H + +#include "audio/mixer.h" +#include "audio/softsynth/pcspk.h" + +namespace Avalanche { + +class SoundHandler { +public: + bool _soundFl; + + SoundHandler(AvalancheEngine *vm); + ~SoundHandler(); + + void toggleSound(); + void playNote(int freq, int length); + void click(); + void blip(); + void syncVolume(); + void stopSound(); + +private: + AvalancheEngine *_vm; + Audio::PCSpeaker *_speakerStream; + Audio::SoundHandle _speakerHandle; +}; + +} // End of namespace Avalanche + +#endif // AVALANCHE_SOUND_H diff --git a/engines/avalanche/timer.cpp b/engines/avalanche/timer.cpp new file mode 100644 index 0000000000..4e90c7fe48 --- /dev/null +++ b/engines/avalanche/timer.cpp @@ -0,0 +1,693 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on the original source code of Lord Avalot d'Argent version 1.3. + * Copyright (c) 1994-1995 Mike, Mark and Thomas Thurman. + */ + +/* Original name: TIMEOUT The scheduling unit. */ + +#include "avalanche/avalanche.h" +#include "avalanche/timer.h" + +namespace Avalanche { + +Timer::Timer(AvalancheEngine *vm) { + _vm = vm; + + for (int i = 0; i < 7; i++) { + _times[i]._timeLeft = 0; + _times[i]._action = 0; + _times[i]._reason = 0; + } + _timerLost = false; +} + +/** + * Add a nex timer + * @remarks Originally called 'set_up_timer' + */ +void Timer::addTimer(int32 duration, byte action, byte reason) { + if ((_vm->_isLoaded == false) || (_timerLost == true)) { + byte i = 0; + while ((i < 7) && (_times[i]._timeLeft != 0)) + i++; + + if (i == 7) + return; // Oh dear... No timer left + + // Everything's OK here! + _times[i]._timeLeft = duration; + _times[i]._action = action; + _times[i]._reason = reason; + } else { + _vm->_isLoaded = false; + return; + } +} + +/** + * Update the timers + * @remarks Originally called 'one_tick' + */ +void Timer::updateTimer() { + if (_vm->_menu->isActive()) + return; + + for (int i = 0; i < 7; i++) { + if (_times[i]._timeLeft <= 0) + continue; + + _times[i]._timeLeft--; + + if (_times[i]._timeLeft == 0) { + switch (_times[i]._action) { + case kProcOpenDrawbridge : + openDrawbridge(); + break; + case kProcAvariciusTalks : + avariciusTalks(); + break; + case kProcUrinate : + urinate(); + break; + case kProcToilet : + toilet(); + break; + case kProcBang: + bang(); + break; + case kProcBang2: + bang2(); + break; + case kProcStairs: + stairs(); + break; + case kProcCardiffSurvey: + cardiffSurvey(); + break; + case kProcCardiffReturn: + cardiffReturn(); + break; + case kProcCwytalotInHerts: + cwytalotInHerts(); + break; + case kProcGetTiedUp: + getTiedUp(); + break; + case kProcGetTiedUp2: + getTiedUp2(); + break; + case kProcHangAround: + hangAround(); + break; + case kProcHangAround2: + hangAround2(); + break; + case kProcAfterTheShootemup: + afterTheShootemup(); + break; + case kProcJacquesWakesUp: + jacquesWakesUp(); + break; + case kProcNaughtyDuke: + naughtyDuke(); + break; + case kProcNaughtyDuke2: + naughtyDuke2(); + break; + case kProcNaughtyDuke3: + naughtyDuke3(); + break; + case kProcJump: + jump(); + break; + case kProcSequence: + _vm->_sequence->callSequencer(); + break; + case kProcCrapulusSpludOut: + crapulusSaysSpludOut(); + break; + case kProcDawnDelay: + _vm->fadeIn(); + break; + case kProcBuyDrinks: + buyDrinks(); + break; + case kProcBuyWine: + buyWine(); + break; + case kProcCallsGuards: + callsGuards(); + break; + case kProcGreetsMonk: + greetsMonk(); + break; + case kProcFallDownOubliette: + fallDownOubliette(); + break; + case kProcMeetAvaroid: + meetAvaroid(); + break; + case kProcRiseUpOubliette: + riseUpOubliette(); + break; + case kProcRobinHoodAndGeida: + robinHoodAndGeida(); + break; + case kProcRobinHoodAndGeidaTalk: + robinHoodAndGeidaTalk(); + break; + case kProcAvalotReturns: + avalotReturns(); + break; + case kProcAvvySitDown: + avvySitDown(); + break; + case kProcGhostRoomPhew: + ghostRoomPhew(); + break; + case kProcArkataShouts: + arkataShouts(); + break; + case kProcWinning: + winning(); + break; + case kProcAvalotFalls: + avalotFalls(); + break; + case kProcSpludwickGoesToCauldron: + spludwickGoesToCauldron(); + break; + case kProcSpludwickLeavesCauldron: + spludwickLeavesCauldron(); + break; + case kProcGiveLuteToGeida: + giveLuteToGeida(); + break; + } + } + } + _vm->_roomTime++; // Cycles since you've been in this room. + _vm->_totalTime++; // Total amount of time for this game. +} + +void Timer::loseTimer(byte which) { + for (int i = 0; i < 7; i++) { + if (_times[i]._reason == which) + _times[i]._timeLeft = 0; // Cancel this one! + } + + _timerLost = true; +} + +void Timer::openDrawbridge() { + _vm->_drawbridgeOpen++; + _vm->_background->draw(-1, -1, _vm->_drawbridgeOpen - 2); + + if (_vm->_drawbridgeOpen == 4) + _vm->_magics[1]._operation = kMagicNothing; // You may enter the drawbridge. + else + addTimer(7, kProcOpenDrawbridge, kReasonDrawbridgeFalls); +} + +void Timer::avariciusTalks() { + _vm->_dialogs->displayScrollChain('q', _vm->_avariciusTalk); + _vm->_avariciusTalk++; + + if (_vm->_avariciusTalk < 17) + addTimer(177, kProcAvariciusTalks, kReasonAvariciusTalks); + else + _vm->incScore(3); +} + +void Timer::urinate() { + _vm->_animation->_sprites[0]->turn(kDirUp); + _vm->_animation->stopWalking(); + _vm->drawDirection(); + addTimer(14, kProcToilet, kReasonGoToToilet); +} + +void Timer::toilet() { + _vm->_dialogs->displayText("That's better!"); +} + +void Timer::bang() { + Common::String tmpStr = Common::String::format("%c< BANG! >", kControlItalic); + _vm->_dialogs->displayText(tmpStr); + addTimer(30, kProcBang2, kReasonExplosion); +} + +void Timer::bang2() { + _vm->_dialogs->displayText("Hmm... sounds like Spludwick's up to something..."); +} + +void Timer::stairs() { + _vm->_sound->blip(); + _vm->_animation->_sprites[0]->walkTo(3); + _vm->_background->draw(-1, -1, 1); + _vm->_brummieStairs = 2; + _vm->_magics[10]._operation = kMagicSpecial; + _vm->_magics[10]._data = 2; // Reached the bottom of the stairs. + _vm->_magics[3]._operation = kMagicNothing; // Stop them hitting the sides (or the game will hang.) +} + +void Timer::cardiffSurvey() { + if (_vm->_cardiffQuestionNum == 0) { + _vm->_cardiffQuestionNum++; + _vm->_dialogs->displayScrollChain('q', 27); + } + + _vm->_dialogs->displayScrollChain('z', _vm->_cardiffQuestionNum); + _vm->_interrogation = _vm->_cardiffQuestionNum; + addTimer(182, kProcCardiffSurvey, kReasonCardiffsurvey); +} + +void Timer::cardiffReturn() { + _vm->_dialogs->displayScrollChain('q', 28); + cardiffSurvey(); // Add end of question. +} + +void Timer::cwytalotInHerts() { + _vm->_dialogs->displayScrollChain('q', 29); +} + +void Timer::getTiedUp() { + _vm->_dialogs->displayScrollChain('q', 34); // ...Trouble! + _vm->_userMovesAvvy = false; + _vm->_beenTiedUp = true; + _vm->_animation->stopWalking(); + + AnimationType *spr = _vm->_animation->_sprites[1]; + spr->stopWalk(); + spr->stopHoming(); + spr->_callEachStepFl = true; + spr->_eachStepProc = Animation::kProcGrabAvvy; + addTimer(70, kProcGetTiedUp2, kReasonGettingTiedUp); +} + +void Timer::getTiedUp2() { + _vm->_animation->_sprites[0]->walkTo(3); + _vm->_animation->_sprites[1]->walkTo(4); + _vm->_magics[3]._operation = kMagicNothing; // No effect when you touch the boundaries. + _vm->_friarWillTieYouUp = true; +} + +void Timer::hangAround() { + _vm->_animation->_sprites[1]->_doCheck = false; + + AnimationType *avvy = _vm->_animation->_sprites[0]; + avvy->init(7, true); // Robin Hood + _vm->setRoom(kPeopleRobinHood, kRoomRobins); + _vm->_animation->appearPed(0, 1); + _vm->_dialogs->displayScrollChain('q', 39); + avvy->walkTo(6); + addTimer(55, kProcHangAround2, kReasonHangingAround); +} + +void Timer::hangAround2() { + _vm->_dialogs->displayScrollChain('q', 40); + AnimationType *spr = _vm->_animation->_sprites[1]; + spr->_vanishIfStill = false; + spr->walkTo(3); + _vm->setRoom(kPeopleFriarTuck, kRoomRobins); + _vm->_dialogs->displayScrollChain('q', 41); + _vm->_animation->_sprites[0]->remove(); + spr->remove(); // Get rid of Robin Hood and Friar Tuck. + + addTimer(1, kProcAfterTheShootemup, kReasonHangingAround); + // Immediately call the following proc (when you have a chance). + + _vm->_tiedUp = false; + + // _vm->_enid->backToBootstrap(1); Call the shoot-'em-up. TODO: Replace it with proper ScummVM-friendly function(s)! Do not remove until then! +} + +void Timer::afterTheShootemup() { + // Only placed this here to replace the minigame. TODO: Remove it when the shoot em' up is implemented! + _vm->flipRoom(_vm->_room, 1); + + _vm->_animation->_sprites[0]->init(0, true); // Avalot. + _vm->_animation->appearPed(0, 1); + _vm->_userMovesAvvy = true; + _vm->_objects[kObjectCrossbow - 1] = true; + _vm->refreshObjectList(); + + // Same as the added line above: TODO: Remove it later!!! + _vm->_dialogs->displayText(Common::String("P.S.: There should have been the mini-game called \"shoot em' up\", " \ + "but I haven't implemented it yet: you get the crossbow automatically.") + kControlNewLine + kControlNewLine + "Peter (uruk)"); + +#if 0 + byte shootscore, gain; + + shootscore = mem[storage_seg * storage_ofs]; + gain = (shootscore + 5) / 10; // Rounding up. + + display(string("\6Your score was ") + strf(shootscore) + '.' + "\r\rYou gain (" + + strf(shootscore) + " 0xF6 10) = " + strf(gain) + " points."); + + if (gain > 20) { + display("But we won't let you have more than 20 points!"); + points(20); + } else + points(gain); +#endif + + warning("STUB: Timer::after_the_shootemup()"); + + _vm->_dialogs->displayScrollChain('q', 70); +} + +void Timer::jacquesWakesUp() { + _vm->_jacquesState++; + + switch (_vm->_jacquesState) { // Additional pictures. + case 1 : + _vm->_background->draw(-1, -1, 0); // Eyes open. + _vm->_dialogs->displayScrollChain('Q', 45); + break; + case 2 : // Going through the door. + _vm->_background->draw(-1, -1, 1); // Not on the floor. + _vm->_background->draw(-1, -1, 2); // But going through the door. + _vm->_magics[5]._operation = kMagicNothing; // You can't wake him up now. + break; + case 3 : // Gone through the door. + _vm->_background->draw(-1, -1, 1); // Not on the floor, either. + _vm->_background->draw(-1, -1, 3); // He's gone... so the door's open. + _vm->setRoom(kPeopleJacques, kRoomNowhere); // Gone! + break; + } + + if (_vm->_jacquesState == 5) { + _vm->_bellsAreRinging = true; + _vm->_aylesIsAwake = true; + _vm->incScore(2); + } + + switch (_vm->_jacquesState) { + case 1: + case 2: + case 3: + addTimer(12, kProcJacquesWakesUp, kReasonJacquesWakingUp); + break; + case 4: + addTimer(24, kProcJacquesWakesUp, kReasonJacquesWakingUp); + break; + } +} + +void Timer::naughtyDuke() { // This is when the Duke comes in and takes your money. + AnimationType *spr = _vm->_animation->_sprites[1]; + spr->init(9, false); // Here comes the Duke. + _vm->_animation->appearPed(1, 0); // He starts at the door... + spr->walkTo(2); // He walks over to you. + + // Let's get the door opening. + _vm->_background->draw(-1, -1, 0); + _vm->_sequence->startNaughtyDukeSeq(); + + addTimer(50, kProcNaughtyDuke2, kReasonNaughtyDuke); +} + +void Timer::naughtyDuke2() { + AnimationType *spr = _vm->_animation->_sprites[1]; + _vm->_dialogs->displayScrollChain('q', 48); // "Ha ha, it worked again!" + spr->walkTo(0); // Walk to the door. + spr->_vanishIfStill = true; // Then go away! + + addTimer(32, kProcNaughtyDuke3, kReasonNaughtyDuke); +} + +void Timer::naughtyDuke3() { + _vm->_background->draw(-1, -1, 0); + _vm->_sequence->startNaughtyDukeSeq(); +} + +void Timer::jump() { + AnimationType *avvy = _vm->_animation->_sprites[0]; + + _vm->_jumpStatus++; + switch (_vm->_jumpStatus) { + case 1: + case 2: + case 3: + case 5: + case 7: + case 9: + avvy->_y--; + break; + case 12: + case 13: + case 14: + case 16: + case 18: + case 19: + avvy->_y++; + break; + } + + if (_vm->_jumpStatus == 20) { // End of jump. + _vm->_userMovesAvvy = true; + _vm->_jumpStatus = 0; + } else // Still jumping. + addTimer(1, kProcJump, kReasonJumping); + + if ((_vm->_jumpStatus == 10) // You're at the highest point of your jump. + && (_vm->_room == kRoomInsideCardiffCastle) + && (_vm->_arrowInTheDoor == true) + && (_vm->_animation->inField(2))) { // Beside the wall + // Grab the arrow! + if (_vm->_carryNum >= kCarryLimit) + _vm->_dialogs->displayText("You fail to grab it, because your hands are full."); + else { + _vm->_background->draw(-1, -1, 1); + _vm->_arrowInTheDoor = false; // You've got it. + _vm->_objects[kObjectBolt - 1] = true; + _vm->refreshObjectList(); + _vm->_dialogs->displayScrollChain('q', 50); + _vm->incScore(3); + } + } +} + +void Timer::crapulusSaysSpludOut() { + _vm->_dialogs->displayScrollChain('q', 56); + _vm->_crapulusWillTell = false; +} + +void Timer::buyDrinks() { + _vm->_background->draw(-1, -1, 10); // Malagauche gets up again. + _vm->_malagauche = 0; + + _vm->_dialogs->displayScrollChain('D', _vm->_drinking); // Display message about it. + _vm->_pingo->wobble(); // Do the special effects. + _vm->_dialogs->displayScrollChain('D', 1); // That'll be thruppence. + if (_vm->decreaseMoney(3)) // Pay 3d. + _vm->_dialogs->displayScrollChain('D', 3); // Tell 'em you paid up. + _vm->_parser->drink(); +} + +void Timer::buyWine() { + _vm->_background->draw(-1, -1, 10); // Malagauche gets up again. + _vm->_malagauche = 0; + + _vm->_dialogs->displayScrollChain('D', 50); // You buy the wine. + _vm->_dialogs->displayScrollChain('D', 1); // It'll be thruppence. + if (_vm->decreaseMoney(3)) { + _vm->_dialogs->displayScrollChain('D', 4); // You paid up. + _vm->_objects[kObjectWine - 1] = true; + _vm->refreshObjectList(); + _vm->_wineState = 1; // OK Wine. + } +} + +void Timer::callsGuards() { + _vm->_dialogs->displayScrollChain('Q', 58); // "GUARDS!!!" + _vm->gameOver(); +} + +void Timer::greetsMonk() { + _vm->_dialogs->displayScrollChain('Q', 59); + _vm->_enteredLustiesRoomAsMonk = true; +} + +void Timer::fallDownOubliette() { + _vm->_magics[8]._operation = kMagicNothing; + + AnimationType *avvy = _vm->_animation->_sprites[0]; + avvy->_moveY++; // Increments dx/dy! + avvy->_y += avvy->_moveY; // Dowwwn we go... + addTimer(3, kProcFallDownOubliette, kReasonFallingDownOubliette); +} + +void Timer::meetAvaroid() { + if (_vm->_metAvaroid) { + Common::String tmpStr = Common::String::format("You can't expect to be %cthat%c lucky twice in a row!", + kControlItalic, kControlRoman); + _vm->_dialogs->displayText(tmpStr); + _vm->gameOver(); + } else { + _vm->_dialogs->displayScrollChain('Q', 60); + _vm->_metAvaroid = true; + addTimer(1, kProcRiseUpOubliette, kReasonRisingUpOubliette); + + AnimationType *avvy = _vm->_animation->_sprites[0]; + avvy->_facingDir = kDirLeft; + avvy->_x = 151; + avvy->_moveX = -3; + avvy->_moveY = -5; + + _vm->_graphics->setBackgroundColor(kColorGreen); + } +} + +void Timer::riseUpOubliette() { + AnimationType *avvy = _vm->_animation->_sprites[0]; + avvy->_visible = true; + avvy->_moveY++; // Decrements dx/dy! + avvy->_y -= avvy->_moveY; // Uuuupppp we go... + if (avvy->_moveY > 0) + addTimer(3, kProcRiseUpOubliette, kReasonRisingUpOubliette); + else + _vm->_userMovesAvvy = true; +} + +void Timer::robinHoodAndGeida() { + AnimationType *avvy = _vm->_animation->_sprites[0]; + avvy->init(7, true); + _vm->_animation->appearPed(0, 6); + avvy->walkTo(5); + + AnimationType *spr = _vm->_animation->_sprites[1]; + spr->stopWalk(); + spr->_facingDir = kDirLeft; + addTimer(20, kProcRobinHoodAndGeidaTalk, kReasonRobinHoodAndGeida); + _vm->_geidaFollows = false; +} + +void Timer::robinHoodAndGeidaTalk() { + _vm->_dialogs->displayScrollChain('q', 66); + + AnimationType *avvy = _vm->_animation->_sprites[0]; + AnimationType *spr = _vm->_animation->_sprites[1]; + avvy->walkTo(1); + spr->walkTo(1); + avvy->_vanishIfStill = true; + spr->_vanishIfStill = true; + + addTimer(162, kProcAvalotReturns, kReasonRobinHoodAndGeida); +} + +void Timer::avalotReturns() { + AnimationType *avvy = _vm->_animation->_sprites[0]; + AnimationType *spr = _vm->_animation->_sprites[1]; + avvy->remove(); + spr->remove(); + avvy->init(0, true); + _vm->_animation->appearPed(0, 0); + _vm->_dialogs->displayScrollChain('q', 67); + _vm->_userMovesAvvy = true; +} + +/** + * This is used when you sit down in the pub in Notts. It loops around + * so that it will happen when Avvy stops walking. + * @remarks Originally called 'avvy_sit_down' + */ +void Timer::avvySitDown() { + AnimationType *avvy = _vm->_animation->_sprites[0]; + if (avvy->_homing) // Still walking. + addTimer(1, kProcAvvySitDown, kReasonSittingDown); + else { + _vm->_background->draw(-1, -1, 2); + _vm->_sittingInPub = true; + _vm->_userMovesAvvy = false; + avvy->_visible = false; + } +} + +void Timer::ghostRoomPhew() { + Common::String tmpStr = Common::String::format("%cPHEW!%c You're glad to get out of %cthere!", + kControlItalic, kControlRoman, kControlItalic); + _vm->_dialogs->displayText(tmpStr); +} + +void Timer::arkataShouts() { + if (_vm->_teetotal) + return; + + _vm->_dialogs->displayScrollChain('q', 76); + addTimer(160, kProcArkataShouts, kReasonArkataShouts); +} + +void Timer::winning() { + _vm->_dialogs->displayScrollChain('q', 79); + _vm->_pingo->winningPic(); + + warning("STUB: Timer::winning()"); +#if 0 + do { + _vm->checkclick(); + } while (!(_vm->mrelease == 0)); +#endif + // TODO: To be implemented with Pingo::winningPic(). + + _vm->callVerb(kVerbCodeScore); + _vm->_dialogs->displayText(" T H E E N D "); + _vm->_letMeOut = true; +} + +void Timer::avalotFalls() { + AnimationType *avvy = _vm->_animation->_sprites[0]; + if (avvy->_stepNum < 5) { + avvy->_stepNum++; + addTimer(3, kProcAvalotFalls, kReasonFallingOver); + } else { + Common::String toDisplay = Common::String::format("%c%c%c%c%c%c%c%c%c%c%c%c%cZ%c", + kControlNewLine, kControlNewLine, kControlNewLine, kControlNewLine, + kControlNewLine, kControlNewLine, kControlInsertSpaces, kControlInsertSpaces, + kControlInsertSpaces, kControlInsertSpaces, kControlInsertSpaces, + kControlInsertSpaces, kControlRegister, kControlIcon); + _vm->_dialogs->displayText(toDisplay); + } +} + +void Timer::spludwickGoesToCauldron() { + if (_vm->_animation->_sprites[1]->_homing) + addTimer(1, kProcSpludwickGoesToCauldron, kReasonSpludwickWalk); + else + addTimer(17, kProcSpludwickLeavesCauldron, kReasonSpludwickWalk); +} + +void Timer::spludwickLeavesCauldron() { + _vm->_animation->_sprites[1]->_callEachStepFl = true; // So that normal procs will continue. +} + +void Timer::giveLuteToGeida() { // Moved here from Acci. + _vm->_dialogs->displayScrollChain('Q', 86); + _vm->incScore(4); + _vm->_lustieIsAsleep = true; + _vm->_sequence->startGeidaLuteSeq(); +} + +} // End of namespace Avalanche. diff --git a/engines/avalanche/timer.h b/engines/avalanche/timer.h new file mode 100644 index 0000000000..6cd894b0a5 --- /dev/null +++ b/engines/avalanche/timer.h @@ -0,0 +1,178 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on the original source code of Lord Avalot d'Argent version 1.3. + * Copyright (c) 1994-1995 Mike, Mark and Thomas Thurman. + */ + +/* Original name: TIMEOUT The scheduling unit. */ + +#ifndef AVALANCHE_TIMER_H +#define AVALANCHE_TIMER_H + +namespace Avalanche { +class AvalancheEngine; + +class Timer { +public: + // Reason runs between 1 and 28. + enum Reason { + kReasonDrawbridgeFalls = 2, + kReasonAvariciusTalks = 3, + kReasonGoToToilet = 4, + kReasonExplosion = 5, + kReasonBrummieStairs = 6, + kReasonCardiffsurvey = 7, + kReasonCwytalotInHerts = 8, + kReasonGettingTiedUp = 9, + kReasonHangingAround = 10, // Tied to the tree in Nottingham. + kReasonJacquesWakingUp = 11, + kReasonNaughtyDuke = 12, + kReasonJumping = 13, + kReasonSequencer = 14, + kReasonCrapulusSaysSpludwickOut = 15, + kReasonDawndelay = 16, + kReasonDrinks = 17, + kReasonDuLustieTalks = 18, + kReasonFallingDownOubliette = 19, + kReasonMeetingAvaroid = 20, + kReasonRisingUpOubliette = 21, + kReasonRobinHoodAndGeida = 22, + kReasonSittingDown = 23, + kReasonGhostRoomPhew = 1, + kReasonArkataShouts = 24, + kReasonWinning = 25, + kReasonFallingOver = 26, + kReasonSpludwickWalk = 27, + kReasonGeidaSings = 28 + }; + + // Proc runs between 1 and 41. + enum Proc { + kProcOpenDrawbridge = 3, + kProcAvariciusTalks = 4, + kProcUrinate = 5, + kProcToilet = 6, + kProcBang = 7, + kProcBang2 = 8, + kProcStairs = 9, + kProcCardiffSurvey = 10, + kProcCardiffReturn = 11, + kProcCwytalotInHerts = 12, + kProcGetTiedUp = 13, + kProcGetTiedUp2 = 1, + kProcHangAround = 14, + kProcHangAround2 = 15, + kProcAfterTheShootemup = 32, + kProcJacquesWakesUp = 16, + kProcNaughtyDuke = 17, + kProcNaughtyDuke2 = 18, + kProcNaughtyDuke3 = 38, + kProcJump = 19, + kProcSequence = 20, + kProcCrapulusSpludOut = 21, + kProcDawnDelay = 22, + kProcBuyDrinks = 23, + kProcBuyWine = 24, + kProcCallsGuards = 25, + kProcGreetsMonk = 26, + kProcFallDownOubliette = 27, + kProcMeetAvaroid = 28, + kProcRiseUpOubliette = 29, + kProcRobinHoodAndGeida = 2, + kProcRobinHoodAndGeidaTalk = 30, + kProcAvalotReturns = 31, + kProcAvvySitDown = 33, // In Nottingham. + kProcGhostRoomPhew = 34, + kProcArkataShouts = 35, + kProcWinning = 36, + kProcAvalotFalls = 37, + kProcSpludwickGoesToCauldron = 39, + kProcSpludwickLeavesCauldron = 40, + kProcGiveLuteToGeida = 41 + }; + + struct TimerType { + int32 _timeLeft; + byte _action; + byte _reason; + }; + + TimerType _times[7]; + bool _timerLost; // Is the timer "lost"? (Because of using loseTimer()) + + Timer(AvalancheEngine *vm); + + void addTimer(int32 duration, byte action, byte reason); + void updateTimer(); + void loseTimer(byte which); + + // Procedures to do things at the end of amounts of time: + void openDrawbridge(); + void avariciusTalks(); + void urinate(); + void toilet(); + void bang(); + void bang2(); + void stairs(); + void cardiffSurvey(); + void cardiffReturn(); + void cwytalotInHerts(); + void getTiedUp(); + void getTiedUp2(); + void hangAround(); + void hangAround2(); + void afterTheShootemup(); + void jacquesWakesUp(); + void naughtyDuke(); + void naughtyDuke2(); + void naughtyDuke3(); + void jump(); + void crapulusSaysSpludOut(); + void buyDrinks(); + void buyWine(); + void callsGuards(); + void greetsMonk(); + void fallDownOubliette(); + void meetAvaroid(); + void riseUpOubliette(); + void robinHoodAndGeida(); + void robinHoodAndGeidaTalk(); + void avalotReturns(); + void avvySitDown(); + void ghostRoomPhew(); + void arkataShouts(); + void winning(); + void avalotFalls(); + void spludwickGoesToCauldron(); + void spludwickLeavesCauldron(); + void giveLuteToGeida(); + +private: + AvalancheEngine *_vm; + +}; + +} // End of namespace Avalanche. + +#endif // AVALANCHE_TIMER_H diff --git a/engines/cine/script_fw.cpp b/engines/cine/script_fw.cpp index 176380c14f..2abe32f797 100644 --- a/engines/cine/script_fw.cpp +++ b/engines/cine/script_fw.cpp @@ -380,8 +380,7 @@ RawScript::RawScript(const FWScriptInfo &info, const byte *data, uint16 s) : * Copy constructor */ RawScript::RawScript(const RawScript &src) : _size(src._size), - _data(new byte[_size + 1]), _labels(src._labels) { - + _data(new byte[src._size + 1]), _labels(src._labels) { assert(_data); memcpy(_data, src._data, _size + 1); } diff --git a/engines/cine/sound.cpp b/engines/cine/sound.cpp index 10404ae56b..0df926675e 100644 --- a/engines/cine/sound.cpp +++ b/engines/cine/sound.cpp @@ -281,7 +281,7 @@ void PCSoundDriver::resetChannel(int channel) { } AdLibSoundDriver::AdLibSoundDriver(Audio::Mixer *mixer) - : _mixer(mixer) { + : _upCb(0), _upRef(0), _mixer(mixer) { _sampleRate = _mixer->getOutputRate(); _opl = makeAdLibOPL(_sampleRate); memset(_channelsVolumeTable, 0, sizeof(_channelsVolumeTable)); diff --git a/engines/composer/composer.cpp b/engines/composer/composer.cpp index 5db778dfda..2d7075cba1 100644 --- a/engines/composer/composer.cpp +++ b/engines/composer/composer.cpp @@ -48,6 +48,15 @@ namespace Composer { ComposerEngine::ComposerEngine(OSystem *syst, const ComposerGameDescription *gameDesc) : Engine(syst), _gameDescription(gameDesc) { _rnd = new Common::RandomSource("composer"); _audioStream = NULL; + _currSoundPriority = 0; + _currentTime = 0; + _lastTime = 0; + _needsUpdate = true; + _directoriesToStrip = 1; + _mouseVisible = true; + _mouseEnabled = false; + _mouseSpriteId = 0; + _lastButton = NULL; } ComposerEngine::~ComposerEngine() { @@ -79,12 +88,6 @@ Common::Error ComposerEngine::run() { _queuedScripts[i]._scriptId = 0; } - _mouseVisible = true; - _mouseEnabled = false; - _mouseSpriteId = 0; - _lastButton = NULL; - - _directoriesToStrip = 1; if (!_bookIni.loadFromFile("book.ini")) { _directoriesToStrip = 0; if (!_bookIni.loadFromFile("programs/book.ini")) { @@ -103,7 +106,6 @@ Common::Error ComposerEngine::run() { height = atoi(getStringFromConfig("Common", "Height").c_str()); initGraphics(width, height, true); _screen.create(width, height, Graphics::PixelFormat::createFormatCLUT8()); - _needsUpdate = true; Graphics::Cursor *cursor = Graphics::makeDefaultWinCursor(); CursorMan.replaceCursor(cursor->getSurface(), cursor->getWidth(), cursor->getHeight(), cursor->getHotspotX(), @@ -113,11 +115,12 @@ Common::Error ComposerEngine::run() { loadLibrary(0); - _currentTime = 0; - _lastTime = 0; - uint fps = atoi(getStringFromConfig("Common", "FPS").c_str()); - uint frameTime = 1000 / fps; + uint frameTime = 125; // Default to 125ms (1000/8) + if (fps != 0) + frameTime = 1000 / fps; + else + warning("FPS in book.ini is zero. Defaulting to 8..."); uint32 lastDrawTime = 0; while (!shouldQuit()) { diff --git a/engines/configure.engines b/engines/configure.engines index db8e341ee0..be1a91922b 100644 --- a/engines/configure.engines +++ b/engines/configure.engines @@ -6,6 +6,7 @@ add_engine he "HE71+ games" yes add_engine agi "AGI" yes add_engine agos "AGOS" yes "agos2" "AGOS 1 games" add_engine agos2 "AGOS 2 games" yes +add_engine avalanche "Lord Avalot d'Argent" no add_engine cge "CGE" yes add_engine cine "Cinematique evo 1" yes add_engine composer "Magic Composer" yes diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index 6aa8477887..06730cfba7 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -92,6 +92,32 @@ DraciEngine::DraciEngine(OSystem *syst, const ADGameDescription *gameDesc) DebugMan.addDebugChannel(kDraciWalkingDebugLevel, "walking", "Walking debug info"); _console = new DraciConsole(this); + + _screen = 0; + _mouse = 0; + _game = 0; + _script = 0; + _anims = 0; + _sound = 0; + _music = 0; + _smallFont = 0; + _bigFont = 0; + _iconsArchive = 0; + _objectsArchive = 0; + _spritesArchive = 0; + _paletteArchive = 0; + _roomsArchive = 0; + _overlaysArchive = 0; + _animationsArchive = 0; + _walkingMapsArchive = 0; + _itemsArchive = 0; + _itemImagesArchive = 0; + _initArchive = 0; + _stringsArchive = 0; + _soundsArchive = 0; + _dubbingArchive = 0; + _showWalkingMap = 0; + _pauseStartTime = 0; } bool DraciEngine::hasFeature(EngineFeature f) const { diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index c4108cc0c7..271eb1e02e 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -52,6 +52,36 @@ enum { Game::Game(DraciEngine *vm) : _vm(vm), _walkingState(vm) { uint i; + _dialogueLinesNum = 0; + _blockNum = 0; + + for (i = 0; i < kDialogueLines; i++) + _dialogueAnims[0] = 0; + + _loopStatus = kStatusOrdinary; + _loopSubstatus = kOuterLoop; + _shouldQuit = 0; + _shouldExitLoop = 0; + _isReloaded = 0; + _speechTick = 0; + _speechDuration = 0; + _objUnderCursor = 0; + _animUnderCursor = 0; + _markedAnimationIndex = 0; + _scheduledPalette = 0; + _fadePhases = 0; + _fadePhase = 0; + _fadeTick = 0; + _mouseChangeTick = 0; + _enableQuickHero = 0; + _wantQuickHero = 0; + _enableSpeedText = 0; + _titleAnim = 0; + _inventoryAnim = 0; + _walkingMapOverlay = 0; + _walkingShortestPathOverlay = 0; + _walkingObliquePathOverlay = 0; + BArchive *initArchive = _vm->_initArchive; const BAFile *file; @@ -953,7 +983,7 @@ void Game::dialogueMenu(int dialogueID) { "hit: %d, _lines[hit]: %d, lastblock: %d, dialogueLines: %d, dialogueExit: %d", hit, _lines[hit], _lastBlock, _dialogueLinesNum, _dialogueExit); - if ((!_dialogueExit) && (hit != -1) && (_lines[hit] != -1)) { + if ((!_dialogueExit) && (hit >= 0) && (_lines[hit] != -1)) { if ((oldLines == 1) && (_dialogueLinesNum == 1) && (_lines[hit] == _lastBlock)) { break; } diff --git a/engines/draci/sprite.cpp b/engines/draci/sprite.cpp index 965cdabf3e..9a78904d25 100644 --- a/engines/draci/sprite.cpp +++ b/engines/draci/sprite.cpp @@ -38,9 +38,9 @@ const Displacement kNoDisplacement = { 0, 0, 1.0, 1.0 }; * height height of the image in the buffer */ static void transformToRows(byte *img, uint16 width, uint16 height) { - byte *buf = new byte[width * height]; + byte *buf = new byte[(uint)(width * height)]; byte *tmp = buf; - memcpy(buf, img, width * height); + memcpy(buf, img, (uint)(width * height)); for (uint16 i = 0; i < width; ++i) { for (uint16 j = 0; j < height; ++j) { diff --git a/engines/draci/surface.cpp b/engines/draci/surface.cpp index 3676c6edac..4156398070 100644 --- a/engines/draci/surface.cpp +++ b/engines/draci/surface.cpp @@ -82,7 +82,7 @@ void Surface::markClean() { void Surface::fill(uint color) { byte *ptr = (byte *)getPixels(); - memset(ptr, color, w * h); + memset(ptr, color, (uint)(w * h)); } /** diff --git a/engines/draci/walking.cpp b/engines/draci/walking.cpp index f1ae769d80..195b968860 100644 --- a/engines/draci/walking.cpp +++ b/engines/draci/walking.cpp @@ -556,9 +556,15 @@ bool WalkingState::alignHeroToEdge(const Common::Point &p1, const Common::Point } bool reachedEnd; if (movement == kMoveLeft || movement == kMoveRight) { + if (p2Diff.x == 0) { + error("Wrong value for horizontal movement"); + } reachedEnd = movement == kMoveLeft ? hero->x <= p2.x : hero->x >= p2.x; hero->y += hero->x * p2Diff.y / p2Diff.x - prevHero.x * p2Diff.y / p2Diff.x; } else { + if (p2Diff.y == 0) { + error("Wrong value for vertical movement"); + } reachedEnd = movement == kMoveUp ? hero->y <= p2.y : hero->y >= p2.y; hero->x += hero->y * p2Diff.x / p2Diff.y - prevHero.y * p2Diff.x / p2Diff.y; } diff --git a/engines/draci/walking.h b/engines/draci/walking.h index a43aeb272a..7e4a3184f5 100644 --- a/engines/draci/walking.h +++ b/engines/draci/walking.h @@ -103,7 +103,17 @@ struct GPL2Program; class WalkingState { public: - explicit WalkingState(DraciEngine *vm) : _vm(vm) { stopWalking(); } + explicit WalkingState(DraciEngine *vm) : _vm(vm) { + _dir = kDirectionLast; + _startingDirection = kMoveUndefined; + _segment = 0; + _lastAnimPhase = 0; + _turningFinished = 0; + _callbackOffset = 0; + + stopWalking(); + } + ~WalkingState() {} void stopWalking(); diff --git a/engines/drascula/animation.cpp b/engines/drascula/animation.cpp index 1145c8c3ff..ee981c36da 100644 --- a/engines/drascula/animation.cpp +++ b/engines/drascula/animation.cpp @@ -1645,10 +1645,10 @@ void DrasculaEngine::animation_9_6() { int v_cd; - animate("fin.bin", 14); + (void)animate("fin.bin", 14); playMusic(13); flags[5] = 1; - animate("drf.bin", 16); + (void)animate("drf.bin", 16); fadeToBlack(0); clearRoom(); curX = -1; diff --git a/engines/drascula/converse.cpp b/engines/drascula/converse.cpp index 95a5f7d87f..b3749445ec 100644 --- a/engines/drascula/converse.cpp +++ b/engines/drascula/converse.cpp @@ -168,19 +168,19 @@ void DrasculaEngine::converse(int index) { // delete stream; if (currentChapter == 2 && !strcmp(fileName, "op_5.cal") && flags[38] == 1 && flags[33] == 1) { - strcpy(phrase3, _text[405]); + Common::strlcpy(phrase3, _text[405], 128); strcpy(sound3, "405.als"); answer3 = 31; } if (currentChapter == 6 && !strcmp(fileName, "op_12.cal") && flags[7] == 1) { - strcpy(phrase3, _text[273]); + Common::strlcpy(phrase3, _text[273], 128); strcpy(sound3, "273.als"); answer3 = 14; } if (currentChapter == 6 && !strcmp(fileName, "op_12.cal") && flags[10] == 1) { - strcpy(phrase3, _text[274]); + Common::strlcpy(phrase3, _text[274], 128); strcpy(sound3, "274.als"); answer3 = 15; } diff --git a/engines/drascula/drascula.cpp b/engines/drascula/drascula.cpp index cde00baa32..d25b37d18d 100644 --- a/engines/drascula/drascula.cpp +++ b/engines/drascula/drascula.cpp @@ -89,6 +89,33 @@ DrasculaEngine::DrasculaEngine(OSystem *syst, const DrasculaGameDescription *gam _talkSequences = 0; _currentSaveSlot = 0; + bjX = 0; + bjY = 0; + trackBJ = 0; + framesWithoutAction = 0; + term_int = 0; + currentChapter = 0; + _loadedDifferentChapter = 0; + musicStopped = 0; + FrameSSN = 0; + globalSpeed = 0; + LastFrame = 0; + flag_tv = 0; + _charMapSize = 0; + _itemLocationsSize = 0; + _polXSize = 0; + _verbBarXSize = 0; + _x1dMenuSize = 0; + _frameXSize = 0; + _candleXSize = 0; + _pianistXSize = 0; + _drunkXSize = 0; + _roomPreUpdatesSize = 0; + _roomUpdatesSize = 0; + _roomActionsSize = 0; + _talkSequencesSize = 0; + _numLangs = 0; + _color = 0; blinking = 0; _mouseX = 0; @@ -297,7 +324,7 @@ Common::Error DrasculaEngine::run() { memset(iconName, 0, sizeof(iconName)); for (i = 0; i < 6; i++) - strcpy(iconName[i + 1], _textverbs[i]); + Common::strlcpy(iconName[i + 1], _textverbs[i], 13); assignPalette(defaultPalette); diff --git a/engines/drascula/graphics.cpp b/engines/drascula/graphics.cpp index b28de669b6..fe954279c3 100644 --- a/engines/drascula/graphics.cpp +++ b/engines/drascula/graphics.cpp @@ -336,7 +336,7 @@ void DrasculaEngine::centerText(const char *message, int textX, int textY) { // original starts printing 4 lines above textY int y = CLIP<int>(textY - (4 * CHAR_HEIGHT), 0, 320); - strcpy(msg, message); + Common::strlcpy(msg, message, 200); // If the message fits on screen as-is, just print it here if (textFitsCentered(msg, textX)) { @@ -363,8 +363,8 @@ void DrasculaEngine::centerText(const char *message, int textX, int textY) { while (curWord != NULL) { // Check if the word and the current line fit on screen if (tmpMessageLine[0] != '\0') - strcat(tmpMessageLine, " "); - strcat(tmpMessageLine, curWord); + Common::strlcat(tmpMessageLine, " ", 200); + Common::strlcat(tmpMessageLine, curWord, 200); if (textFitsCentered(tmpMessageLine, textX)) { // Line fits, so add the word to the current message line strcpy(messageLine, tmpMessageLine); @@ -374,8 +374,8 @@ void DrasculaEngine::centerText(const char *message, int textX, int textY) { // If it goes off screen, print_abc will adjust it x = CLIP<int>(textX - strlen(messageLine) * CHAR_WIDTH / 2, 60, 255); print_abc(messageLine, x, y + curLine * CHAR_HEIGHT); - strcpy(messageLine, curWord); - strcpy(tmpMessageLine, curWord); + Common::strlcpy(messageLine, curWord, 200); + Common::strlcpy(tmpMessageLine, curWord, 200); curLine++; } diff --git a/engines/drascula/objects.cpp b/engines/drascula/objects.cpp index 35dfd3162a..519e919433 100644 --- a/engines/drascula/objects.cpp +++ b/engines/drascula/objects.cpp @@ -265,8 +265,9 @@ void DrasculaEngine::updateVisible() { } if (_roomNumber == 22 && flags[27] == 1) visible[3] = 0; - if (_roomNumber == 26 && flags[21] == 0) - strcpy(objName[2], _textmisc[0]); + if (_roomNumber == 26 && flags[21] == 0) { + Common::strlcpy(objName[2], _textmisc[0], 20); + } if (_roomNumber == 26 && flags[18] == 1) visible[2] = 0; if (_roomNumber == 26 && flags[12] == 1) diff --git a/engines/engines.mk b/engines/engines.mk index a3270007dc..1d9d8fd89b 100644 --- a/engines/engines.mk +++ b/engines/engines.mk @@ -26,6 +26,11 @@ DEFINES += -DENABLE_AGOS2 endif endif +ifdef ENABLE_AVALANCHE +DEFINES += -DENABLE_AVALANCHE=$(ENABLE_AVALANCHE) +MODULES += engines/avalanche +endif + ifdef ENABLE_CGE DEFINES += -DENABLE_CGE=$(ENABLE_CGE) MODULES += engines/cge diff --git a/engines/fullpipe/behavior.cpp b/engines/fullpipe/behavior.cpp index 1a2b7bb8e2..c1fe835b81 100644 --- a/engines/fullpipe/behavior.cpp +++ b/engines/fullpipe/behavior.cpp @@ -239,7 +239,7 @@ void BehaviorInfo::initObjectBehavior(GameVar *var, Scene *sc, StaticANIObject * } for (int i = 0; i < _itemsCount; i++) { - int maxDelay; + int maxDelay = 0; _bheItems.push_back(new BehaviorEntry(var->getSubVarByIndex(i), sc, ani, &maxDelay)); @@ -275,7 +275,7 @@ BehaviorEntry::BehaviorEntry(GameVar *var, Scene *sc, StaticANIObject *ani, int for (int i = 0; i < _itemsCount; i++) { GameVar *subvar = var->getSubVarByIndex(i); - int delay; + int delay = 0; _items[i] = new BehaviorEntryInfo(subvar, sc, &delay); totalPercent += delay; diff --git a/engines/fullpipe/fullpipe.cpp b/engines/fullpipe/fullpipe.cpp index 5e1af1227c..a0db6aa08c 100644 --- a/engines/fullpipe/fullpipe.cpp +++ b/engines/fullpipe/fullpipe.cpp @@ -176,7 +176,7 @@ Common::Error FullpipeEngine::run() { int scene = 0; if (ConfMan.hasKey("boot_param")) - scene = ConfMan.getInt("boot_param"); + scene = convertScene(ConfMan.getInt("boot_param")); if (!loadGam("fullpipe.gam", scene)) return Common::kNoGameDataFoundError; diff --git a/engines/fullpipe/fullpipe.h b/engines/fullpipe/fullpipe.h index 6872dd8356..22e4f1d8f4 100644 --- a/engines/fullpipe/fullpipe.h +++ b/engines/fullpipe/fullpipe.h @@ -219,6 +219,7 @@ public: bool sceneSwitcher(EntranceInfo *entrance); Scene *accessScene(int sceneId); void setSceneMusicParameters(GameVar *var); + int convertScene(int scene); NGIArchive *_currArchive; diff --git a/engines/fullpipe/gfx.h b/engines/fullpipe/gfx.h index 1f7284a6eb..9d5c45de0b 100644 --- a/engines/fullpipe/gfx.h +++ b/engines/fullpipe/gfx.h @@ -157,7 +157,9 @@ class PictureObject : public GameObject { PictureObject(); PictureObject(PictureObject *src); - bool load(MfcArchive &file, bool bigPicture); + virtual bool load(MfcArchive &file, bool bigPicture); + virtual bool load(MfcArchive &file) { assert(0); return false; } // Disable base class + Common::Point *getDimensions(Common::Point *p); void draw(); void drawAt(int x, int y); diff --git a/engines/fullpipe/interaction.cpp b/engines/fullpipe/interaction.cpp index 9fd42c15ae..80cbce946b 100644 --- a/engines/fullpipe/interaction.cpp +++ b/engines/fullpipe/interaction.cpp @@ -137,7 +137,7 @@ bool InteractionController::handleInteraction(StaticANIObject *subj, GameObject obj->setPicAniInfo(&aniInfo); if (abs(xpos - subj->_ox) > 1 || abs(ypos - subj->_oy) > 1) { - mq = getSc2MctlCompoundBySceneId(g_fullpipe->_currentScene->_sceneId)->method4C(subj, xpos, ypos, 1, cinter->_staticsId2); + mq = getSc2MctlCompoundBySceneId(g_fullpipe->_currentScene->_sceneId)->doWalkTo(subj, xpos, ypos, 1, cinter->_staticsId2); if (mq) { dur = mq->calcDuration(subj); delete mq; diff --git a/engines/fullpipe/messages.cpp b/engines/fullpipe/messages.cpp index b5f2cb8303..d58212dc29 100644 --- a/engines/fullpipe/messages.cpp +++ b/engines/fullpipe/messages.cpp @@ -309,6 +309,10 @@ void MessageQueue::messageQueueCallback1(int par) { debug(3, "STUB: MessageQueue::messageQueueCallback1()"); } +void MessageQueue::addExCommand(ExCommand *ex) { + _exCommands.push_front(ex); +} + ExCommand *MessageQueue::getExCommandByIndex(uint idx) { if (idx > _exCommands.size()) return 0; @@ -323,6 +327,23 @@ ExCommand *MessageQueue::getExCommandByIndex(uint idx) { return *it; } +void MessageQueue::deleteExCommandByIndex(uint idx, bool doFree) { + if (idx > _exCommands.size()) + return; + + Common::List<ExCommand *>::iterator it = _exCommands.begin(); + + while (idx) { + ++it; + idx--; + } + + _exCommands.erase(it); + + if (doFree) + delete *it; +} + void MessageQueue::sendNextCommand() { if (_exCommands.size()) { if (!(_flags & 4) && (_flags & 1)) { diff --git a/engines/fullpipe/messages.h b/engines/fullpipe/messages.h index 6b72364323..a3533e1bd2 100644 --- a/engines/fullpipe/messages.h +++ b/engines/fullpipe/messages.h @@ -119,7 +119,9 @@ class MessageQueue : public CObject { uint getCount() { return _exCommands.size(); } + void addExCommand(ExCommand *ex); ExCommand *getExCommandByIndex(uint idx); + void deleteExCommandByIndex(uint idx, bool doFree); void replaceKeyCode(int key1, int key2); diff --git a/engines/fullpipe/motion.cpp b/engines/fullpipe/motion.cpp index da0c614e72..b49b297451 100644 --- a/engines/fullpipe/motion.cpp +++ b/engines/fullpipe/motion.cpp @@ -62,7 +62,7 @@ bool MctlCompound::load(MfcArchive &file) { debug(6, "ConnectionPoint[%d]", j); MctlConnectionPoint *obj1 = (MctlConnectionPoint *)file.readClass(); - obj->_connectionPoints.push_back(*obj1); + obj->_connectionPoints.push_back(obj1); } obj->_field_20 = file.readUint32LE(); @@ -116,14 +116,76 @@ void MctlCompound::freeItems() { warning("STUB: MctlCompound::freeItems()"); } -MessageQueue *MctlCompound::method34(StaticANIObject *subj, int xpos, int ypos, int flag, int staticsId) { +MessageQueue *MctlCompound::method34(StaticANIObject *subj, int xpos, int ypos, int fuzzyMatch, int staticsId) { warning("STUB: MctlCompound::method34()"); return 0; } -MessageQueue *MctlCompound::method4C(StaticANIObject *subj, int xpos, int ypos, int flag, int staticsId) { - warning("STUB: MctlCompound::method4C()"); +MessageQueue *MctlCompound::doWalkTo(StaticANIObject *subj, int xpos, int ypos, int fuzzyMatch, int staticsId) { + int match1 = -1; + int match2 = -1; + + if (!subj) + return 0; + + for (uint i = 0; i < _motionControllers.size(); i++) { + if (_motionControllers[i]->_movGraphReactObj) { + if (_motionControllers[i]->_movGraphReactObj->pointInRegion(subj->_ox, subj->_oy)) { + match1 = i; + break; + } + } + } + + if (match1 == -1) + return 0; + + for (uint i = 0; i < _motionControllers.size(); i++) { + if (_motionControllers[i]->_movGraphReactObj) { + if (_motionControllers[i]->_movGraphReactObj->pointInRegion(xpos, ypos)) { + match2 = i; + break; + } + } + } + + if (match2 == -1) + return 0; + + if (match1 == match2) + return _motionControllers[match1]->_motionControllerObj->doWalkTo(subj, xpos, ypos, fuzzyMatch, staticsId); + + MctlConnectionPoint *closestP = findClosestConnectionPoint(subj->_ox, subj->_oy, match1, xpos, ypos, match2, &match2); + + if (!closestP) + return 0; + + MessageQueue *mq = _motionControllers[match1]->_motionControllerObj->doWalkTo(subj, closestP->_connectionX, closestP->_connectionY, 1, closestP->_field_14); + + ExCommand *ex; + + if (mq) { + for (uint i = 0; i < closestP->_messageQueueObj->getCount(); i++) { + ex = new ExCommand(closestP->_messageQueueObj->getExCommandByIndex(i)); + ex->_excFlags |= 2; + mq->_exCommands.push_back(ex); + } + + ex = new ExCommand(subj->_id, 51, 0, xpos, ypos, 0, 1, 0, 0, 0); + + ex->_field_20 = fuzzyMatch; + ex->_keyCode = subj->_okeyCode; + ex->_excFlags |= 2; + + mq->_exCommands.push_back(ex); + } + + return mq; +} + +MctlConnectionPoint *MctlCompound::findClosestConnectionPoint(int ox, int oy, int destIndex, int connectionX, int connectionY, int sourceIndex, int *minDistancePtr) { + warning("STUB: MctlCompound::findClosestConnectionPoint()"); return 0; } @@ -140,6 +202,25 @@ bool MctlCompoundArray::load(MfcArchive &file) { return true; } +MovGraphItem::MovGraphItem() { + ani = 0; + field_4 = 0; + field_8 = 0; + field_C = 0; + field_10 = 0; + field_14 = 0; + field_18 = 0; + field_1C = 0; + field_20 = 0; + field_24 = 0; + items = 0; + count = 0; + field_30 = 0; + field_34 = 0; + field_38 = 0; + field_3C = 0; +} + int MovGraph_messageHandler(ExCommand *cmd); int MovGraphCallback(int a1, int a2, int a3) { @@ -149,8 +230,6 @@ int MovGraphCallback(int a1, int a2, int a3) { } MovGraph::MovGraph() { - _itemsCount = 0; - _items = 0; _callback1 = MovGraphCallback; _field_44 = 0; insertMessageHandler(MovGraph_messageHandler, getMessageHandlersCount() - 1, 129); @@ -168,7 +247,20 @@ bool MovGraph::load(MfcArchive &file) { } void MovGraph::addObject(StaticANIObject *obj) { - warning("STUB: MovGraph::addObject()"); + _mgm.clear(); + _mgm.addItem(obj->_id); + + for (uint i = 0; i < _items.size(); i++) + if (_items[i]->ani == obj) + return; + + MovGraphItem *item = new MovGraphItem(); + + item->ani = obj; + + _items.push_back(item); + + _mgm.addItem(obj->_id); // FIXME: Is it really needed? } int MovGraph::removeObject(StaticANIObject *obj) { @@ -193,7 +285,7 @@ int MovGraph::method2C() { return 0; } -MessageQueue *MovGraph::method34(StaticANIObject *subj, int xpos, int ypos, int flag, int staticsId) { +MessageQueue *MovGraph::method34(StaticANIObject *subj, int xpos, int ypos, int fuzzyMatch, int staticsId) { warning("STUB: MovGraph::method34()"); return 0; @@ -217,8 +309,8 @@ int MovGraph::method44() { return 0; } -MessageQueue *MovGraph::method4C(StaticANIObject *subj, int xpos, int ypos, int flag, int staticsId) { - warning("STUB: MovGraph::method4C()"); +MessageQueue *MovGraph::doWalkTo(StaticANIObject *subj, int xpos, int ypos, int fuzzyMatch, int staticsId) { + warning("STUB: MovGraph::doWalkTo()"); return 0; } @@ -229,7 +321,7 @@ int MovGraph::method50() { return 0; } -double MovGraph::calcDistance(Common::Point *point, MovGraphLink *link, int flag) { +double MovGraph::calcDistance(Common::Point *point, MovGraphLink *link, int fuzzyMatch) { int n1x = link->_movGraphNode1->_x; int n1y = link->_movGraphNode1->_y; int n2x = link->_movGraphNode2->_x; @@ -244,7 +336,7 @@ double MovGraph::calcDistance(Common::Point *point, MovGraphLink *link, int flag double res = sqrt(1.0 - dist2 * dist2) * dist1; if (dist2 <= 0.0 || distm >= link->_distance) { - if (flag) { + if (fuzzyMatch) { if (dist2 > 0.0) { if (distm >= link->_distance) { point->x = n2x; @@ -273,6 +365,29 @@ int MovGraph2::getItemIndexByGameObjectId(int objectId) { return -1; } +int MovGraph2::getItemSubIndexByStaticsId(int idx, int staticsId) { + for (int i = 0; i < 4; i++) + if (_items[idx]->_subItems[i]._staticsId1 == staticsId || _items[idx]->_subItems[i]._staticsId2 == staticsId) + return i; + + return -1; +} + +int MovGraph2::getItemSubIndexByMovementId(int idx, int movId) { + for (int i = 0; i < 4; i++) + if (_items[idx]->_subItems[i]._walk[0]._movementId == movId || _items[idx]->_subItems[i]._turn[0]._movementId == movId || + _items[idx]->_subItems[i]._turnS[0]._movementId == movId) + return i; + + return -1; +} + +int MovGraph2::getItemSubIndexByMGM(int idx, StaticANIObject *ani) { + warning("STUB: MovGraph2::getItemSubIndexByMGM()"); + + return -1; +} + bool MovGraph2::initDirections(StaticANIObject *obj, MovGraph2Item *item) { item->_obj = obj; item->_objectId = obj->_id; @@ -309,7 +424,7 @@ bool MovGraph2::initDirections(StaticANIObject *obj, MovGraph2Item *item) { return false; for (int act = 0; act < 3; act++) { - int idx; + int idx = 0; switch(act) { case 0: @@ -336,7 +451,7 @@ bool MovGraph2::initDirections(StaticANIObject *obj, MovGraph2Item *item) { } for (int act = 0; act < 4; act++) { - int idx; + int idx = 0; switch(act) { case 0: @@ -366,7 +481,7 @@ bool MovGraph2::initDirections(StaticANIObject *obj, MovGraph2Item *item) { } for (int act = 0; act < 4; act++) { - int idx; + int idx = 0; switch(act) { case 0: @@ -420,6 +535,16 @@ void MovGraph2::addObject(StaticANIObject *obj) { } } +void MovGraph2::buildMovInfo1SubItems(MovInfo1 *movinfo, Common::Array<MovGraphLink *> *linkList, LinkInfo *lnkSrc, LinkInfo *lnkDst) { + warning("STUB: MovGraph2::buildMovInfo1SubItems()"); +} + +MessageQueue *MovGraph2::buildMovInfo1MessageQueue(MovInfo1 *movInfo) { + warning("STUB: MovGraph2::buildMovInfo1MessageQueue()"); + + return 0; +} + int MovGraph2::removeObject(StaticANIObject *obj) { warning("STUB: MovGraph2::removeObject()"); @@ -430,24 +555,425 @@ void MovGraph2::freeItems() { warning("STUB: MovGraph2::freeItems()"); } -MessageQueue *MovGraph2::method34(StaticANIObject *subj, int xpos, int ypos, int flag, int staticsId) { +MessageQueue *MovGraph2::method34(StaticANIObject *subj, int xpos, int ypos, int fuzzyMatch, int staticsId) { warning("STUB: MovGraph2::method34()"); return 0; } -MessageQueue *MovGraph2::method4C(StaticANIObject *subj, int xpos, int ypos, int flag, int staticsId) { - warning("STUB: MovGraph2::method4C()"); +MessageQueue *MovGraph2::doWalkTo(StaticANIObject *obj, int xpos, int ypos, int fuzzyMatch, int staticsId) { + LinkInfo linkInfoDest; + LinkInfo linkInfoSource; + MovInfo1 movInfo1; + PicAniInfo picAniInfo; + Common::Point point; + + int idx = getItemIndexByGameObjectId(obj->_id); + + if (idx < 0) + return 0; + + linkInfoSource.link = 0; + linkInfoSource.node = 0; + + linkInfoDest.link = 0; + linkInfoDest.node = 0; + + point.x = 0; + + obj->getPicAniInfo(&picAniInfo); + + int idxsub; + + if (obj->_movement) + idxsub = getItemSubIndexByMovementId(idx, obj->_movement->_id); + else + idxsub = getItemSubIndexByStaticsId(idx, obj->_statics->_staticsId); + + bool subMgm = false; + + if (idxsub == -1) { + idxsub = getItemSubIndexByMGM(idx, obj); + subMgm = true; + + if (idxsub == -1) + return 0; + } + + if (obj->_movement) { + int newx, newy; + + if (subMgm) { + obj->_messageQueueId = 0; + obj->changeStatics2(_items[idx]->_subItems[idxsub]._staticsId1); + newx = obj->_ox; + newy = obj->_oy; + } else { + obj->_movement->calcSomeXY(point, 0); + newx = obj->_movement->_ox - point.x; + newy = obj->_movement->_oy - point.y; + if (idxsub != 1 && idxsub) { + if (idxsub == 2 || idxsub == 3) { + newy = obj->_movement->_oy; + } + } else { + newx = obj->_movement->_ox; + } + } + + obj->_movement = 0; + obj->setOXY(newx, newy); + } + + if (obj->_ox == xpos && obj->_oy == ypos) { + g_fullpipe->_globalMessageQueueList->compact(); + + MessageQueue *mq = new MessageQueue(); + + if (staticsId && obj->_statics->_staticsId != staticsId) { + int idxwalk = getItemSubIndexByStaticsId(idx, staticsId); + if (idxwalk == -1) { + obj->setPicAniInfo(&picAniInfo); + + return 0; + } + + ExCommand *ex = new ExCommand(picAniInfo.objectId, 1, _items[idx]->_subItems[idxsub]._walk[idxwalk]._movementId, 0, 0, 0, 1, 0, 0, 0); + + ex->_field_24 = 1; + ex->_keyCode = picAniInfo.field_8; + ex->_excFlags |= 2; + + mq->_exCommands.push_back(ex); + } else { + ExCommand *ex = new ExCommand(picAniInfo.objectId, 22, obj->_statics->_staticsId, 0, 0, 0, 1, 0, 0, 0); + + ex->_keyCode = picAniInfo.field_8; + ex->_excFlags |= 3; + mq->_exCommands.push_back(ex); + + ex = new ExCommand(picAniInfo.objectId, 5, -1, obj->_ox, obj->_oy, 0, 1, 0, 0, 0); + + ex->_field_14 = -1; + ex->_keyCode = picAniInfo.field_8; + ex->_excFlags |= 3; + mq->_exCommands.push_back(ex); + } + + obj->setPicAniInfo(&picAniInfo); + + return mq; + } + + linkInfoSource.node = findNode(obj->_ox, obj->_oy, 0); + + if (!linkInfoSource.node) { + linkInfoSource.link = findLink1(obj->_ox, obj->_oy, idxsub, 0); + + if (!linkInfoSource.link) { + linkInfoSource.link = findLink2(obj->_ox, obj->_oy); + + if (!linkInfoSource.link) { + obj->setPicAniInfo(&picAniInfo); + + return 0; + } + } + } + + linkInfoDest.node = findNode(xpos, ypos, fuzzyMatch); + + if (!linkInfoDest.node) { + linkInfoDest.link = findLink1(xpos, ypos, idxsub, fuzzyMatch); + + if (!linkInfoDest.link) { + obj->setPicAniInfo(&picAniInfo); + + return 0; + } + } + + Common::Array<MovGraphLink *> tempLinkList; + + if (findMinPath(&linkInfoSource, &linkInfoDest, &tempLinkList) < 0.0 || + ((linkInfoSource.node != linkInfoDest.node || !linkInfoSource.node) && !tempLinkList.size())) + return 0; + + movInfo1.subIndex = idxsub; + movInfo1.pt1.x = obj->_ox; + movInfo1.pt1.y = obj->_oy; + + int dx1 = obj->_ox; + int dy1 = obj->_oy; + int dx2, dy2; + + if (linkInfoSource.node) + movInfo1.distance1 = linkInfoSource.node->_distance; + else + movInfo1.distance1 = linkInfoSource.link->_movGraphNode1->_distance; + + if (linkInfoDest.node) { + dx2 = linkInfoDest.node->_x; + dy2 = linkInfoDest.node->_y; + + movInfo1.pt2.x = linkInfoDest.node->_x; + movInfo1.pt2.y = linkInfoDest.node->_y; + + movInfo1.distance2 = linkInfoDest.node->_distance; + } else { + movInfo1.pt2.x = xpos; + movInfo1.pt2.y = ypos; + + MovGraphNode *nod = linkInfoDest.link->_movGraphNode1; + double dst1 = sqrt((double)((ypos - nod->_y) * (ypos - nod->_y) + (xpos - nod->_x) * (xpos - nod->_x))); + int dst = linkInfoDest.link->_movGraphNode2->_distance - nod->_distance; + + movInfo1.distance2 = nod->_distance + (dst1 * (double)dst / linkInfoDest.link->_distance); + + calcDistance(&movInfo1.pt2, linkInfoDest.link, 1); + + dx1 = movInfo1.pt1.x; + dy1 = movInfo1.pt1.y; + dx2 = movInfo1.pt2.x; + dy2 = movInfo1.pt2.y; + } + + if (staticsId) { + movInfo1.item1Index = getItemSubIndexByStaticsId(idx, staticsId); + } else if (tempLinkList.size() <= 1) { + if (tempLinkList.size() == 1) + movInfo1.item1Index = getShortSide(tempLinkList[0], dx2 - dx1, dy2 - dy1); + else + movInfo1.item1Index = getShortSide(0, dx2 - dx1, dy2 - dy1); + } else { + movInfo1.item1Index = findLink(&tempLinkList, tempLinkList.back(), 0, 0); + } + + movInfo1.flags = fuzzyMatch != 0; + + if (_items[idx]->_subItems[idxsub]._staticsId1 != obj->_statics->_staticsId) + movInfo1.flags |= 2; + + buildMovInfo1SubItems(&movInfo1, &tempLinkList, &linkInfoSource, &linkInfoDest); + + MessageQueue *mq = buildMovInfo1MessageQueue(&movInfo1); + + linkInfoDest.node = findNode(movInfo1.pt2.x, movInfo1.pt2.y, fuzzyMatch); + + if (!linkInfoDest.node) + linkInfoDest.link = findLink1(movInfo1.pt2.x, movInfo1.pt2.y, movInfo1.item1Index, fuzzyMatch); + + if (fuzzyMatch || linkInfoDest.link || linkInfoDest.node) { + if (mq && mq->getCount() > 0 && picAniInfo.movementId) { + ExCommand *ex = mq->getExCommandByIndex(0); + + if (ex && (ex->_messageKind == 1 || ex->_messageKind == 20) + && picAniInfo.movementId == ex->_messageNum + && picAniInfo.someDynamicPhaseIndex == ex->_field_14) { + mq->deleteExCommandByIndex(0, 1); + } else { + ex = new ExCommand(picAniInfo.objectId, 5, ex->_messageNum, obj->_ox, obj->_oy, 0, 1, 0, 0, 0); + ex->_field_14 = -1; + ex->_keyCode = picAniInfo.field_8; + ex->_excFlags |= 2; + mq->addExCommand(ex); + + ex = new ExCommand(picAniInfo.objectId, 22, _items[idx]->_subItems[idxsub]._staticsId1, 0, 0, 0, 1, 0, 0, 0); + + ex->_keyCode = picAniInfo.field_8; + ex->_excFlags |= 3; + mq->addExCommand(ex); + } + } + } else { + if (mq) + delete mq; + mq = 0; + } + + obj->setPicAniInfo(&picAniInfo); + + return mq; +} + +MovGraphNode *MovGraph2::findNode(int x, int y, int fuzzyMatch) { + for (ObList::iterator i = _nodes.begin(); i != _nodes.end(); ++i) { + assert(((CObject *)*i)->_objtype == kObjTypeMovGraphNode); + + MovGraphNode *node = (MovGraphNode *)*i; + + if (fuzzyMatch) { + if (abs(node->_x - x) < 15 && abs(node->_y - y) < 15) + return node; + } else { + if (node->_x == x && node->_y == y) + return node; + } + } + + return 0; +} + +int MovGraph2::getShortSide(MovGraphLink *lnk, int x, int y) { + warning("STUB: MovGraph2::getShortSide()"); return 0; } +int MovGraph2::findLink(Common::Array<MovGraphLink *> *linkList, MovGraphLink *lnk, Common::Rect *a3, Common::Point *a4) { + warning("STUB: MovGraphLink *MovGraph2::findLink()"); + + return 0; +} + +MovGraphLink *MovGraph2::findLink1(int x, int y, int idx, int fuzzyMatch) { + Common::Point point; + MovGraphLink *res = 0; + + for (ObList::iterator i = _links.begin(); i != _links.end(); ++i) { + assert(((CObject *)*i)->_objtype == kObjTypeMovGraphLink); + + MovGraphLink *lnk = (MovGraphLink *)*i; + + if (fuzzyMatch) { + point.x = x; + point.y = y; + double dst = calcDistance(&point, lnk, 0); + + if (dst >= 0.0 && dst < 2.0) + return lnk; + } else if (!(lnk->_flags & 0x20000000)) { + if (lnk->_movGraphReact->pointInRegion(x, y)) { + if (abs(lnk->_movGraphNode1->_x - lnk->_movGraphNode2->_x) <= abs(lnk->_movGraphNode1->_y - lnk->_movGraphNode2->_y)) { + if (idx == 2 || idx == 3) + return lnk; + res = lnk; + } else { + if (idx == 1 || !idx) + return lnk; + res = lnk; + } + } + } + } + + return res; +} + +MovGraphLink *MovGraph2::findLink2(int x, int y) { + double mindist = 1.0e20; + MovGraphLink *res; + + for (ObList::iterator i = _links.begin(); i != _links.end(); ++i) { + assert(((CObject *)*i)->_objtype == kObjTypeMovGraphLink); + + MovGraphLink *lnk = (MovGraphLink *)*i; + + if (!(lnk->_flags & 0x20000000)) { + double n1x = lnk->_movGraphNode1->_x; + double n1y = lnk->_movGraphNode1->_y; + double n2x = lnk->_movGraphNode2->_x; + double n2y = lnk->_movGraphNode2->_y; + double n1dx = n1x - x; + double n1dy = n1y - y; + double dst1 = sqrt(n1dy * n1dy + n1dx * n1dx); + double coeff1 = ((n1y - n2y) * n1dy + (n2x - n1x) * n1dx) / lnk->_distance / dst1; + double dst3 = coeff1 * dst1; + double dst2 = sqrt(1.0 - coeff1 * coeff1) * dst1; + + if (coeff1 * dst1 < 0.0) { + dst3 = 0.0; + dst2 = sqrt(n1dy * n1dy + n1dx * n1dx); + } + if (dst3 > lnk->_distance) { + dst3 = lnk->_distance; + dst2 = sqrt((n2x - x) * (n2x - x) + (n2y - y) * (n2y - y)); + } + if (dst3 >= 0.0 && dst3 <= lnk->_distance && dst2 < mindist) { + mindist = dst2; + res = lnk; + } + } + } + + if (mindist < 1.0e20) + return res; + else + return 0; +} + +double MovGraph2::findMinPath(LinkInfo *linkInfoSource, LinkInfo *linkInfoDest, Common::Array<MovGraphLink *> *listObj) { + warning("STUB: MovGraph2::findMinPath()"); + + return 0.0; +} + MovGraphNode *MovGraph::calcOffset(int ox, int oy) { warning("STUB: MovGraph::calcOffset()"); return 0; } +void MGM::clear() { + _items.clear(); +} + +MGMItem::MGMItem() { + objId = 0; +} + +MGMSubItem::MGMSubItem() { + movement = 0; + staticsIndex = 0; + field_8 = 0; + field_C = 0; + x = 0; + y = 0; +} + +void MGM::addItem(int objId) { + if (getItemIndexById(objId) == -1) { + MGMItem *item = new MGMItem(); + + item->objId = objId; + _items.push_back(item); + } + rebuildTables(objId); +} + +void MGM::rebuildTables(int objId) { + int idx = getItemIndexById(objId); + + if (idx == -1) + return; + + _items[idx]->subItems.clear(); + _items[idx]->statics.clear(); + _items[idx]->movements1.clear(); + _items[idx]->movements2.clear(); + + StaticANIObject *obj = g_fullpipe->_currentScene->getStaticANIObject1ById(objId, -1); + + if (!obj) + return; + + for (uint i = 0; i < obj->_staticsList.size(); i++) + _items[idx]->statics.push_back((Statics *)obj->_staticsList[i]); + + for (uint i = 0; i < obj->_movements.size(); i++) + _items[idx]->movements1.push_back((Movement *)obj->_movements[i]); + + _items[idx]->subItems.clear(); +} + +int MGM::getItemIndexById(int objId) { + for (uint i = 0; i < _items.size(); i++) + if (_items[i]->objId == objId) + return i; + + return -1; +} + MovGraphLink::MovGraphLink() { _distance = 0; _angle = 0; @@ -458,6 +984,8 @@ MovGraphLink::MovGraphLink() { _field_38 = 0; _movGraphReact = 0; _name = 0; + + _objtype = kObjTypeMovGraphLink; } bool MovGraphLink::load(MfcArchive &file) { @@ -500,7 +1028,6 @@ ReactParallel::ReactParallel() { _x2 = 0; _dy = 0; _dx = 0; - _points = 0; _y1 = 0; _y2 = 0; } @@ -536,19 +1063,22 @@ void ReactParallel::createRegion() { _points[1]->x = (int16)(_x2 - _dx * cs); _points[1]->y = (int16)(_y2 - _dx * sn); - _points[2]->x = (int16)(_x1 + _dy * cs); + _points[2]->x = (int16)(_x2 + _dy * cs); _points[2]->y = (int16)(_y2 + _dy * sn); _points[3]->x = (int16)(_x1 + _dy * cs); _points[3]->y = (int16)(_y1 + _dy * sn); + _pointCount = 4; // GdiObject::Attach(_rgn, CreatePolygonRgn(_points, 4, 2); } +void ReactParallel::method14() { + warning("STUB: ReactParallel::method14()"); +} + ReactPolygonal::ReactPolygonal() { _field_C = 0; - _points = 0; - _pointCount = 0; _field_10 = 0; } @@ -583,6 +1113,51 @@ void ReactPolygonal::createRegion() { } } +void ReactPolygonal::method14() { + warning("STUB: ReactPolygonal::method14()"); +} + +bool MovGraphReact::pointInRegion(int x, int y) { + if (_pointCount < 3) { + return false; + } + + int counter = 0; + double xinters; + Common::Point p, p1, p2; + + p.x = (double)x; + p.y = (double)y; + + p1.x = (double)_points[0]->x; + p1.y = (double)_points[0]->y; + + for (int i = 1; i <= _pointCount; i++) { + p2.x = (double)_points[i % _pointCount]->x; + p2.y = (double)_points[i % _pointCount]->y; + + if (p.y > MIN(p1.y, p2.y)) { + if (p.y <= MAX(p1.y, p2.y)) { + if (p.x <= MAX(p1.x, p2.x)) { + if (p1.y != p2.y) { + xinters = (p.y - p1.y) * (p2.x - p1.x) / (p2.y - p1.y) + p1.x; + if (p1.x == p2.x || p.x <= xinters) { + counter++; + } + } + } + } + } + p1 = p2; + } + + if (counter % 2 == 0) { + return false; + } else { + return true; + } +} + int startWalkTo(int objId, int objKey, int x, int y, int a5) { MctlCompound *mc = getSc2MctlCompoundBySceneId(g_fullpipe->_currentScene->_sceneId); diff --git a/engines/fullpipe/motion.h b/engines/fullpipe/motion.h index 99d8d3eb79..6901a7263a 100644 --- a/engines/fullpipe/motion.h +++ b/engines/fullpipe/motion.h @@ -25,6 +25,10 @@ namespace Fullpipe { +class Statics; +class Movement; +class MctlConnectionPoint; + int startWalkTo(int objId, int objKey, int x, int y, int a5); int doSomeAnimation(int objId, int objKey, int a3); int doSomeAnimation2(int objId, int objKey); @@ -48,20 +52,28 @@ public: virtual int method28() { return 0; } virtual int method2C() { return 0; } virtual int method30() { return 0; } - virtual MessageQueue *method34(StaticANIObject *subj, int xpos, int ypos, int flag, int staticsId) { return 0; } + virtual MessageQueue *method34(StaticANIObject *subj, int xpos, int ypos, int fuzzyMatch, int staticsId) { return 0; } virtual int changeCallback() { return 0; } virtual int method3C() { return 0; } virtual int method40() { return 0; } virtual int method44() { return 0; } virtual int method48() { return -1; } - virtual MessageQueue *method4C(StaticANIObject *subj, int xpos, int ypos, int flag, int staticsId) { return 0; } + virtual MessageQueue *doWalkTo(StaticANIObject *subj, int xpos, int ypos, int fuzzyMatch, int staticsId) { return 0; } }; class MovGraphReact : public CObject { - // Empty -}; +public: + int _pointCount; + Common::Point **_points; + +public: + MovGraphReact() : _pointCount(0), _points(0) {} + ~MovGraphReact() { free(_points); } -typedef Common::Array<CObject> MctlConnectionPointsArray; + virtual void method14() {} + virtual void createRegion() {} + virtual bool pointInRegion(int x, int y); +}; class MctlCompoundArrayItem : public CObject { friend class MctlCompound; @@ -69,7 +81,7 @@ class MctlCompoundArrayItem : public CObject { protected: MotionController *_motionControllerObj; MovGraphReact *_movGraphReactObj; - MctlConnectionPointsArray _connectionPoints; + Common::Array<MctlConnectionPoint *> _connectionPoints; int _field_20; int _field_24; int _field_28; @@ -94,31 +106,56 @@ class MctlCompound : public MotionController { virtual void addObject(StaticANIObject *obj); virtual int removeObject(StaticANIObject *obj); virtual void freeItems(); - virtual MessageQueue *method34(StaticANIObject *subj, int xpos, int ypos, int flag, int staticsId); - virtual MessageQueue *method4C(StaticANIObject *subj, int xpos, int ypos, int flag, int staticsId); + virtual MessageQueue *method34(StaticANIObject *subj, int xpos, int ypos, int fuzzyMatch, int staticsId); + virtual MessageQueue *doWalkTo(StaticANIObject *subj, int xpos, int ypos, int fuzzyMatch, int staticsId); void initMovGraph2(); + MctlConnectionPoint *findClosestConnectionPoint(int ox, int oy, int destIndex, int connectionX, int connectionY, int sourceIndex, int *minDistancePtr); }; -class Unk2 : public CObject { +struct MGMSubItem { + int movement; + int staticsIndex; + int field_8; + int field_C; + int x; + int y; + + MGMSubItem(); +}; + +struct MGMItem { + int16 objId; + Common::Array<MGMSubItem *> subItems; + Common::Array<Statics *> statics; + Common::Array<Movement *> movements1; + Common::Array<Movement *> movements2; + + MGMItem(); +}; + + +class MGM : public CObject { public: - int _items; - int _count; + Common::Array<MGMItem *> _items; public: - Unk2() : _items(0), _count(0) {} + void clear(); + void addItem(int objId); + void rebuildTables(int objId); + int getItemIndexById(int objId); }; class MovGraphNode : public CObject { - public: +public: int _x; int _y; int _distance; int16 _field_10; int _field_14; - public: - MovGraphNode() : _x(0), _y(0), _distance(0), _field_10(0), _field_14(0) {} +public: + MovGraphNode() : _x(0), _y(0), _distance(0), _field_10(0), _field_14(0) { _objtype = kObjTypeMovGraphNode; } virtual bool load(MfcArchive &file); }; @@ -130,25 +167,26 @@ class ReactParallel : public MovGraphReact { int _y2; int _dx; int _dy; - Common::Point **_points; public: ReactParallel(); virtual bool load(MfcArchive &file); - void createRegion(); + + virtual void method14(); + virtual void createRegion(); }; class ReactPolygonal : public MovGraphReact { //CRgn _rgn; int _field_C; int _field_10; - int _pointCount; - Common::Point **_points; public: ReactPolygonal(); virtual bool load(MfcArchive &file); - void createRegion(); + + virtual void method14(); + virtual void createRegion(); }; class MovGraphLink : public CObject { @@ -170,15 +208,35 @@ class MovGraphLink : public CObject { virtual bool load(MfcArchive &file); }; +struct MovGraphItem { + StaticANIObject *ani; + int field_4; + int field_8; + int field_C; + int field_10; + int field_14; + int field_18; + int field_1C; + int field_20; + int field_24; + int items; + int count; + int field_30; + int field_34; + int field_38; + int field_3C; + + MovGraphItem(); +}; + class MovGraph : public MotionController { public: ObList _nodes; ObList _links; int _field_44; - int _items; - int _itemsCount; + Common::Array<MovGraphItem *> _items; int (*_callback1)(int, int, int); - Unk2 _unk2; + MGM _mgm; public: MovGraph(); @@ -189,14 +247,14 @@ class MovGraph : public MotionController { virtual void freeItems(); virtual int method28(); virtual int method2C(); - virtual MessageQueue *method34(StaticANIObject *subj, int xpos, int ypos, int flag, int staticsId); + virtual MessageQueue *method34(StaticANIObject *subj, int xpos, int ypos, int fuzzyMatch, int staticsId); virtual int changeCallback(); virtual int method3C(); virtual int method44(); - virtual MessageQueue *method4C(StaticANIObject *subj, int xpos, int ypos, int flag, int staticsId); + virtual MessageQueue *doWalkTo(StaticANIObject *subj, int xpos, int ypos, int fuzzyMatch, int staticsId); virtual int method50(); - double calcDistance(Common::Point *point, MovGraphLink *link, int flag); + double calcDistance(Common::Point *point, MovGraphLink *link, int fuzzyMatch); MovGraphNode *calcOffset(int ox, int oy); }; @@ -217,6 +275,24 @@ struct MovGraph2ItemSub { MG2I _turnS[4]; }; +struct LinkInfo { + MovGraphLink *link; + MovGraphNode *node; +}; + +struct MovInfo1 { + int field_0; + Common::Point pt1; + Common::Point pt2; + int distance1; + int distance2; + int subIndex; + int item1Index; + int items; + int itemsCount; + int flags; +}; + struct MovGraph2Item { int _objectId; StaticANIObject *_obj; @@ -231,11 +307,25 @@ public: virtual void addObject(StaticANIObject *obj); virtual int removeObject(StaticANIObject *obj); virtual void freeItems(); - virtual MessageQueue *method34(StaticANIObject *subj, int xpos, int ypos, int flag, int staticsId); - virtual MessageQueue *method4C(StaticANIObject *subj, int xpos, int ypos, int flag, int staticsId); + virtual MessageQueue *method34(StaticANIObject *subj, int xpos, int ypos, int fuzzyMatch, int staticsId); + virtual MessageQueue *doWalkTo(StaticANIObject *subj, int xpos, int ypos, int fuzzyMatch, int staticsId); int getItemIndexByGameObjectId(int objectId); + int getItemSubIndexByStaticsId(int index, int staticsId); + int getItemSubIndexByMovementId(int index, int movId); + int getItemSubIndexByMGM(int idx, StaticANIObject *ani); + + int getShortSide(MovGraphLink *lnk, int x, int y); + int findLink(Common::Array<MovGraphLink *> *linkList, MovGraphLink *lnk, Common::Rect *a3, Common::Point *a4); + bool initDirections(StaticANIObject *obj, MovGraph2Item *item); + void buildMovInfo1SubItems(MovInfo1 *movinfo, Common::Array<MovGraphLink *> *linkList, LinkInfo *lnkSrc, LinkInfo *lnkDst); + MessageQueue *buildMovInfo1MessageQueue(MovInfo1 *movInfo); + + MovGraphNode *findNode(int x, int y, int fuzzyMatch); + MovGraphLink *findLink1(int x, int y, int idx, int fuzzyMatch); + MovGraphLink *findLink2(int x, int y); + double findMinPath(LinkInfo *linkInfoSource, LinkInfo *linkInfoDest, Common::Array<MovGraphLink *> *listObj); }; class MctlConnectionPoint : public CObject { @@ -246,7 +336,7 @@ public: int _field_10; int16 _field_14; int16 _field_16; - int _messageQueueObj; + MessageQueue *_messageQueueObj; int _motionControllerObj; }; diff --git a/engines/fullpipe/scenes.cpp b/engines/fullpipe/scenes.cpp index 9fb8a95f53..40d9f21afb 100644 --- a/engines/fullpipe/scenes.cpp +++ b/engines/fullpipe/scenes.cpp @@ -74,6 +74,23 @@ Vars::Vars() { selector = 0; } +static int scenes[] = { + SC_1, SC_2, SC_3, SC_4, SC_5, SC_6, SC_7, SC_8, SC_9, SC_10, + SC_11, SC_12, SC_13, SC_14, SC_15, SC_16, SC_17, SC_18, SC_19, SC_20, + SC_21, SC_22, SC_23, SC_24, SC_25, SC_26, SC_27, SC_28, SC_29, SC_30, + SC_31, SC_32, SC_33, SC_34, SC_35, SC_36, SC_37, SC_38, SC_DBGMENU +}; + +int FullpipeEngine::convertScene(int scene) { + if (!scene || scene >= SC_1) + return scene; + + if (scene < 1 || scene > 39) + return SC_1; + + return scenes[scene - 1]; +} + bool FullpipeEngine::sceneSwitcher(EntranceInfo *entrance) { GameVar *sceneVar; Common::Point sceneDim; diff --git a/engines/fullpipe/sound.h b/engines/fullpipe/sound.h index ea6987aae6..e2b271fe2c 100644 --- a/engines/fullpipe/sound.h +++ b/engines/fullpipe/sound.h @@ -35,7 +35,8 @@ class Sound : public MemoryObject { public: Sound(); - bool load(MfcArchive &file, NGIArchive *archive); + virtual bool load(MfcArchive &file, NGIArchive *archive); + virtual bool load(MfcArchive &file) { assert(0); return false; } // Disable base class void updateVolume(); void setPanAndVolumeByStaticAni(); @@ -48,7 +49,8 @@ class SoundList : public CObject { public: SoundList(); - bool load(MfcArchive &file, char *fname); + virtual bool load(MfcArchive &file, char *fname); + virtual bool load(MfcArchive &file) { assert(0); return false; } // Disable base class bool loadFile(const char *fname, char *libname); int getCount() { return _soundItemsCount; } diff --git a/engines/fullpipe/utils.h b/engines/fullpipe/utils.h index e593bd9f18..64f56ced0a 100644 --- a/engines/fullpipe/utils.h +++ b/engines/fullpipe/utils.h @@ -66,15 +66,17 @@ class MfcArchive : public Common::SeekableReadStream { enum ObjType { kObjTypeDefault, + kObjTypeMovGraph, + kObjTypeMovGraphLink, + kObjTypeMovGraphNode, + kObjTypeMctlCompound, kObjTypeObjstateCommand, - kObjTypeStaticANIObject, kObjTypePictureObject, - kObjTypeMovGraph, - kObjTypeMctlCompound + kObjTypeStaticANIObject }; class CObject { - public: +public: ObjType _objtype; CObject() : _objtype(kObjTypeDefault) {} diff --git a/engines/kyra/sequences_lok.cpp b/engines/kyra/sequences_lok.cpp index 2a2f9a5493..51f1ea51cf 100644 --- a/engines/kyra/sequences_lok.cpp +++ b/engines/kyra/sequences_lok.cpp @@ -1722,9 +1722,10 @@ int KyraEngine_LoK::handleBeadState() { _screen->addBitBlitRect(_beadState1.x, _beadState1.y, _beadState1.width2, _beadState1.height); ++_beadState1.tableIndex; - if (_beadState1.tableIndex > 24) + if (_beadState1.tableIndex > 24) { _beadState1.tableIndex = 0; _unkEndSeqVar4 = 1; + } if (_system->getMillis() > _beadStateTimer2 && _malcolmFlag == 7 && !_unkAmuletVar && !_text->printed()) { snd_playSoundEffect(0x0B); if (_currentCharacter->x1 > 233 && _currentCharacter->x1 < 305 && _currentCharacter->y1 > 85 && _currentCharacter->y1 < 105 && diff --git a/engines/lastexpress/entities/entity.h b/engines/lastexpress/entities/entity.h index c67d13db9e..5aa7c1be5a 100644 --- a/engines/lastexpress/entities/entity.h +++ b/engines/lastexpress/entities/entity.h @@ -330,7 +330,7 @@ public: }; struct EntityParametersSIII : EntityParameters { - char seq[12]; + char seq[13]; uint param4; uint param5; uint param6; @@ -338,7 +338,7 @@ public: uint param8; EntityParametersSIII() { - memset(&seq, 0, 12); + memset(&seq, 0, 13); param4 = 0; param5 = 0; param6 = 0; @@ -374,16 +374,16 @@ public: }; struct EntityParametersSIIS : EntityParameters { - char seq1[12]; + char seq1[13]; uint param4; uint param5; - char seq2[12]; + char seq2[13]; EntityParametersSIIS() { - memset(&seq1, 0, 12); + memset(&seq1, 0, 13); param4 = 0; param5 = 0; - memset(&seq2, 0, 12); + memset(&seq2, 0, 13); } Common::String toString() { @@ -410,14 +410,14 @@ public: struct EntityParametersISSI : EntityParameters { uint param1; - char seq1[12]; - char seq2[12]; + char seq1[13]; + char seq2[13]; uint param8; EntityParametersISSI() { param1 = 0; - memset(&seq1, 0, 12); - memset(&seq2, 0, 12); + memset(&seq1, 0, 13); + memset(&seq2, 0, 13); param8 = 0; } @@ -445,7 +445,7 @@ public: struct EntityParametersISII : EntityParameters { uint param1; - char seq[12]; + char seq[13]; uint param5; uint param6; uint param7; @@ -453,7 +453,7 @@ public: EntityParametersISII() { param1 = 0; - memset(&seq, 0, 12); + memset(&seq, 0, 13); param5 = 0; param6 = 0; param7 = 0; @@ -488,14 +488,14 @@ public: }; struct EntityParametersSSII : EntityParameters { - char seq1[12]; - char seq2[12]; + char seq1[13]; + char seq2[13]; uint param7; uint param8; EntityParametersSSII() { - memset(&seq1, 0, 12); - memset(&seq2, 0, 12); + memset(&seq1, 0, 13); + memset(&seq2, 0, 13); param7 = 0; param8 = 0; } @@ -523,14 +523,14 @@ public: }; struct EntityParametersSSS : EntityParameters { - char seq1[12]; - char seq2[12]; - char seq3[8]; + char seq1[13]; + char seq2[13]; + char seq3[9]; EntityParametersSSS() { - memset(&seq1, 0, 12); - memset(&seq2, 0, 12); - memset(&seq3, 0, 8); + memset(&seq1, 0, 13); + memset(&seq2, 0, 13); + memset(&seq3, 0, 9); } Common::String toString() { @@ -551,14 +551,14 @@ public: struct EntityParametersIISS : EntityParameters { uint param1; uint param2; - char seq1[12]; - char seq2[12]; + char seq1[13]; + char seq2[13]; EntityParametersIISS() { param1 = 0; param2 = 0; - memset(&seq1, 0, 12); - memset(&seq2, 0, 12); + memset(&seq1, 0, 13); + memset(&seq2, 0, 13); } Common::String toString() { @@ -586,7 +586,7 @@ public: struct EntityParametersIISI : EntityParameters { uint param1; uint param2; - char seq[12]; + char seq[13]; uint param6; uint param7; uint param8; @@ -594,7 +594,7 @@ public: EntityParametersIISI() { param1 = 0; param2 = 0; - memset(&seq, 0, 12); + memset(&seq, 0, 13); param6 = 0; param7 = 0; param8 = 0; @@ -631,7 +631,7 @@ public: uint param1; uint param2; uint param3; - char seq[12]; + char seq[13]; uint param7; uint param8; @@ -639,7 +639,7 @@ public: param1 = 0; param2 = 0; param3 = 0; - memset(&seq, 0, 12); + memset(&seq, 0, 13); param7 = 0; param8 = 0; } @@ -677,7 +677,7 @@ public: uint param3; uint param4; uint param5; - char seq[12]; + char seq[13]; EntityParametersI5S() { param1 = 0; @@ -685,7 +685,7 @@ public: param3 = 0; param4 = 0; param5 = 0; - memset(&seq, 0, 12); + memset(&seq, 0, 13); } void saveLoadWithSerializer(Common::Serializer &s) { diff --git a/engines/lastexpress/game/inventory.cpp b/engines/lastexpress/game/inventory.cpp index 11e7369ee1..2f1b0a8e76 100644 --- a/engines/lastexpress/game/inventory.cpp +++ b/engines/lastexpress/game/inventory.cpp @@ -52,6 +52,8 @@ Inventory::Inventory(LastExpressEngine *engine) : _engine(engine), _selectedItem _selectedItemRect = Common::Rect(44, 0, 76, 32); init(); + + debug(9, "_showingHourGlass: %d", _showingHourGlass); } Inventory::~Inventory() { diff --git a/engines/mohawk/cstime.cpp b/engines/mohawk/cstime.cpp index 3f9827581b..0f69d50a22 100644 --- a/engines/mohawk/cstime.cpp +++ b/engines/mohawk/cstime.cpp @@ -51,6 +51,15 @@ MohawkEngine_CSTime::MohawkEngine_CSTime(OSystem *syst, const MohawkGameDescript _state = kCSTStateStartup; reset(); + + _console = 0; + _gfx = 0; + _cursor = 0; + _interface = 0; + _view = 0; + _needsUpdate = false; + _case = 0; + _nextSceneId = 1; } MohawkEngine_CSTime::~MohawkEngine_CSTime() { diff --git a/engines/mohawk/cstime_game.cpp b/engines/mohawk/cstime_game.cpp index 2e21111025..91d2f895c0 100644 --- a/engines/mohawk/cstime_game.cpp +++ b/engines/mohawk/cstime_game.cpp @@ -1094,7 +1094,7 @@ void CSTimeScene::idleAmbientAnims() { bool CSTimeScene::eventIsActive() { return _vm->NISIsRunning() /* TODO || _vm->soundIsPlaying()*/ || _vm->getCurrentEventType() == kCSTimeEventWaitForClick - || _activeChar->_flappingState != 0xffff || _vm->getInterface()->getState() == 4; + || _activeChar->_flappingState != 0xffff || _vm->getInterface()->getState() == kCSTimeInterfaceDroppedInventory; } void CSTimeScene::cursorOverHotspot(uint id) { diff --git a/engines/mohawk/cstime_ui.cpp b/engines/mohawk/cstime_ui.cpp index de7d5bde80..6d5e5dd3ef 100644 --- a/engines/mohawk/cstime_ui.cpp +++ b/engines/mohawk/cstime_ui.cpp @@ -854,7 +854,7 @@ void CSTimeInterface::dropItemInInventory(uint16 id) { clearDialogArea(); _inventoryDisplay->show(); _inventoryDisplay->draw(); - _inventoryDisplay->setState(4); + _inventoryDisplay->setState(kCSTimeInterfaceDroppedInventory); } CSTimeHelp::CSTimeHelp(MohawkEngine_CSTime *vm) : _vm(vm) { diff --git a/engines/mohawk/cstime_ui.h b/engines/mohawk/cstime_ui.h index 27df7cac3e..3154d4b2ef 100644 --- a/engines/mohawk/cstime_ui.h +++ b/engines/mohawk/cstime_ui.h @@ -167,7 +167,8 @@ protected: enum CSTimeInterfaceState { kCSTimeInterfaceStateNormal = 1, kCSTimeInterfaceStateDragStart = 2, - kCSTimeInterfaceStateDragging = 3 + kCSTimeInterfaceStateDragging = 3, + kCSTimeInterfaceDroppedInventory = 4 }; class CSTimeInterface { diff --git a/engines/mortevielle/mouse.h b/engines/mortevielle/mouse.h index 1b9856e2c4..594031d816 100644 --- a/engines/mortevielle/mouse.h +++ b/engines/mortevielle/mouse.h @@ -37,7 +37,6 @@ class MouseHandler { private: MortevielleEngine *_vm; - int s_s[12][6]; int _counter; public: Common::Point _pos; diff --git a/engines/neverhood/console.cpp b/engines/neverhood/console.cpp index 708c68746c..34438d821f 100644 --- a/engines/neverhood/console.cpp +++ b/engines/neverhood/console.cpp @@ -29,6 +29,7 @@ #include "neverhood/smackerscene.h" #include "neverhood/sound.h" #include "neverhood/modules/module1600.h" +#include "neverhood/modules/module3000_sprites.h" namespace Neverhood { diff --git a/engines/neverhood/klaymen.cpp b/engines/neverhood/klaymen.cpp index 8ed27c825a..666b20a08a 100644 --- a/engines/neverhood/klaymen.cpp +++ b/engines/neverhood/klaymen.cpp @@ -47,17 +47,6 @@ static const KlaymenIdleTableItem klaymenIdleTable3[] = { {1, kIdleTeleporterHands2} }; -static const KlaymenIdleTableItem klaymenIdleTable4[] = { - {1, kIdleSpinHead}, - {1, kIdleChest}, - {1, kIdleHeadOff}, -}; - -static const KlaymenIdleTableItem klaymenIdleTable1002[] = { - {1, kIdlePickEar}, - {2, kIdleWonderAbout} -}; - // Klaymen Klaymen::Klaymen(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y, NRectArray *clipRects) @@ -65,7 +54,7 @@ Klaymen::Klaymen(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y, NRec _isWalkingOpenDoorNotified(false), _spitOutCountdown(0), _tapesToInsert(0), _keysToInsert(0), _busyStatus(0), _acceptInput(true), _attachedSprite(NULL), _isWalking(false), _actionStatus(1), _parentScene(parentScene), _isSneaking(false), _isLargeStep(false), _doYHitIncr(false), _isLeverDown(false), _isSittingInTeleporter(false), _actionStatusChanged(false), _ladderStatus(0), _pathPoints(NULL), _soundFlag(false), - _idleTableNum(0), _otherSprite(NULL), _moveObjectCountdown(0), _readyToSpit(false), _walkResumeFrameIncr(0) { + _idleTableNum(0), _otherSprite(NULL), _moveObjectCountdown(0), _walkResumeFrameIncr(0) { createSurface(1000, 320, 200); _x = x; @@ -628,36 +617,6 @@ void Klaymen::startWalkToX(int16 x, bool walkExt) { } } -void Klaymen::stWakeUp() { - _busyStatus = 1; - _acceptInput = false; - startAnimation(0x527AC970, 0, -1); - SetUpdateHandler(&Klaymen::update); - SetMessageHandler(&Klaymen::hmLowLevelAnimation); - SetSpriteUpdate(NULL); -} - -void Klaymen::stSleeping() { - _busyStatus = 0; - _acceptInput = true; - startAnimation(0x5A38C110, 0, -1); - SetUpdateHandler(&Klaymen::update); - SetMessageHandler(&Klaymen::hmSleeping); - SetSpriteUpdate(NULL); -} - -uint32 Klaymen::hmSleeping(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = hmLowLevel(messageNum, param, sender); - switch (messageNum) { - case 0x100D: - if (param.asInteger() == 0x03060012) { - playSound(0, 0xC0238244); - } - break; - } - return messageResult; -} - bool Klaymen::stStartAction(AnimationCb callback3) { if (_busyStatus == 1) { _busyStatus = 2; @@ -1512,112 +1471,11 @@ uint32 Klaymen::hmPeekWall(int messageNum, const MessageParam ¶m, Entity *se return hmLowLevelAnimation(messageNum, param, sender); } -void Klaymen::stJumpToRing1() { - if (!stStartAction(AnimationCallback(&Klaymen::stJumpToRing1))) { - _busyStatus = 0; - startAnimation(0xD82890BA, 0, -1); - setupJumpToRing(); - } -} - -void Klaymen::setupJumpToRing() { - _acceptInput = false; - SetUpdateHandler(&Klaymen::update); - SetMessageHandler(&Klaymen::hmJumpToRing); - SetSpriteUpdate(&Klaymen::suUpdateDestX); - NextState(&Klaymen::stHangOnRing); - sendMessage(_attachedSprite, 0x482B, 0); -} - -uint32 Klaymen::hmJumpToRing(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = hmLowLevelAnimation(messageNum, param, sender); - switch (messageNum) { - case 0x100D: - if (param.asInteger() == 0x168050A0) { - sendMessage(_attachedSprite, 0x4806, 0); - _acceptInput = true; - } else if (param.asInteger() == 0x320AC306) { - playSound(0, 0x5860C640); - } else if (param.asInteger() == 0x4AB28209) { - sendMessage(_attachedSprite, 0x482A, 0); - } else if (param.asInteger() == 0x88001184) { - sendMessage(_attachedSprite, 0x482B, 0); - } - break; - } - return messageResult; -} - void Klaymen::suUpdateDestX() { AnimatedSprite::updateDeltaXY(); _destX = _x; } -void Klaymen::stHangOnRing() { - _busyStatus = 0; - _acceptInput = true; - startAnimation(0x4829E0B8, 0, -1); - SetUpdateHandler(&Klaymen::update); - SetMessageHandler(&Klaymen::hmLowLevel); - SetSpriteUpdate(NULL); -} - -void Klaymen::stJumpToRing2() { - if (!stStartAction(AnimationCallback(&Klaymen::stJumpToRing2))) { - _busyStatus = 0; - startAnimation(0x900980B2, 0, -1); - setupJumpToRing(); - } -} - -void Klaymen::stJumpToRing3() { - if (!stStartAction(AnimationCallback(&Klaymen::stJumpToRing3))) { - _busyStatus = 0; - _acceptInput = false; - startAnimation(0xBA1910B2, 0, -1); - SetUpdateHandler(&Klaymen::update); - SetSpriteUpdate(&Klaymen::suUpdateDestX); - SetMessageHandler(&Klaymen::hmJumpToRing3); - NextState(&Klaymen::stHoldRing3); - sendMessage(_attachedSprite, 0x482B, 0); - } -} - -uint32 Klaymen::hmJumpToRing3(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = hmLowLevelAnimation(messageNum, param, sender); - switch (messageNum) { - case 0x100D: - if (param.asInteger() == 0x168050A0) { - sendMessage(_attachedSprite, 0x4806, 0); - } else if (param.asInteger() == 0x320AC306) { - playSound(0, 0x5860C640); - } else if (param.asInteger() == 0x4AB28209) { - sendMessage(_attachedSprite, 0x482A, 0); - } else if (param.asInteger() == 0x88001184) { - sendMessage(_attachedSprite, 0x482B, 0); - } - break; - } - return messageResult; -} - -void Klaymen::stHoldRing3() { - _busyStatus = 0; - _acceptInput = true; - startAnimation(0x4A293FB0, 0, -1); - SetUpdateHandler(&Klaymen::update); - SetMessageHandler(&Klaymen::hmHoldRing3); - SetSpriteUpdate(NULL); -} - -uint32 Klaymen::hmHoldRing3(int messageNum, const MessageParam ¶m, Entity *sender) { - if (messageNum == 0x1008) { - stReleaseRing(); - return 0; - } - return hmLowLevel(messageNum, param, sender); -} - void Klaymen::stReleaseRing() { _busyStatus = 1; _acceptInput = false; @@ -1629,14 +1487,6 @@ void Klaymen::stReleaseRing() { SetSpriteUpdate(NULL); } -void Klaymen::stJumpToRing4() { - if (!stStartAction(AnimationCallback(&Klaymen::stJumpToRing4))) { - _busyStatus = 0; - startAnimation(0xB8699832, 0, -1); - setupJumpToRing(); - } -} - void Klaymen::startWalkToAttachedSpriteXDistance(int16 distance) { startWalkToXDistance(_attachedSprite->getX(), distance); } @@ -1885,29 +1735,6 @@ uint32 Klaymen::hmTurnToBackToUse(int messageNum, const MessageParam ¶m, Ent return messageResult; } -void Klaymen::stClayDoorOpen() { - if (!stStartAction(AnimationCallback(&Klaymen::stClayDoorOpen))) { - _busyStatus = 2; - _acceptInput = false; - startAnimation(0x5CCCB330, 0, -1); - SetUpdateHandler(&Klaymen::update); - SetMessageHandler(&Klaymen::hmClayDoorOpen); - SetSpriteUpdate(&Klaymen::suUpdateDestX); - } -} - -uint32 Klaymen::hmClayDoorOpen(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = hmLowLevelAnimation(messageNum, param, sender); - switch (messageNum) { - case 0x100D: - if (param.asInteger() == 0x040D4186) { - sendMessage(_attachedSprite, 0x4808, 0); - } - break; - } - return messageResult; -} - void Klaymen::stTurnToUse() { if (!stStartAction(AnimationCallback(&Klaymen::stTurnToUse))) { _busyStatus = 2; @@ -2336,29 +2163,6 @@ uint32 Klaymen::hmTeleporterAppearDisappear(int messageNum, const MessageParam & return messageResult; } -uint32 Klaymen::hmShrink(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = hmLowLevelAnimation(messageNum, param, sender); - switch (messageNum) { - case 0x100D: - if (param.asInteger() == 0x80C110B5) - sendMessage(_parentScene, 0x482A, 0); - else if (param.asInteger() == 0x33288344) - playSound(2, 0x10688664); - break; - } - return messageResult; -} - -void Klaymen::stShrink() { - _busyStatus = 0; - _acceptInput = false; - playSound(0, 0x4C69EA53); - startAnimation(0x1AE88904, 0, -1); - SetUpdateHandler(&Klaymen::update); - SetMessageHandler(&Klaymen::hmShrink); - SetSpriteUpdate(&AnimatedSprite::updateDeltaXY); -} - void Klaymen::stStandWonderAbout() { if (_x > 260) setDoDeltaX(1); @@ -2537,61 +2341,6 @@ void Klaymen::stInsertKey() { } } -uint32 Klaymen::hmReadNote(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = hmLowLevelAnimation(messageNum, param, sender); - switch (messageNum) { - case 0x100D: - if (param.asInteger() == 0x04684052) { - _acceptInput = true; - sendMessage(_parentScene, 0x2002, 0); - } - break; - } - return messageResult; -} - -void Klaymen::stReadNote() { - _busyStatus = 2; - _acceptInput = false; - startAnimation(0x123E9C9F, 0, -1); - SetUpdateHandler(&Klaymen::update); - SetMessageHandler(&Klaymen::hmReadNote); - SetSpriteUpdate(&AnimatedSprite::updateDeltaXY); -} - -uint32 Klaymen::hmHitByDoor(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = hmLowLevelAnimation(messageNum, param, sender); - int16 speedUpFrameIndex; - switch (messageNum) { - case 0x1008: - speedUpFrameIndex = getFrameIndex(kKlaymenSpeedUpHash); - if (_currFrameIndex < speedUpFrameIndex) { - startAnimation(0x35AA8059, speedUpFrameIndex, -1); - _y = 438; - } - messageResult = 0; - break; - case 0x100D: - if (param.asInteger() == 0x1A1A0785) { - playSound(0, 0x40F0A342); - } else if (param.asInteger() == 0x60428026) { - playSound(0, 0x40608A59); - } - break; - } - return messageResult; -} - -void Klaymen::stHitByDoor() { - _busyStatus = 1; - _acceptInput = false; - startAnimation(0x35AA8059, 0, -1); - SetUpdateHandler(&Klaymen::update); - SetMessageHandler(&Klaymen::hmHitByDoor); - SetSpriteUpdate(&AnimatedSprite::updateDeltaXY); - playSound(0, 0x402E82D4); -} - uint32 Klaymen::hmPeekWallReturn(int messageNum, const MessageParam ¶m, Entity *sender) { uint32 messageResult = hmLowLevelAnimation(messageNum, param, sender); switch (messageNum) { @@ -2657,65 +2406,6 @@ void Klaymen::stPeekWallReturn() { SetSpriteUpdate(NULL); } -void Klaymen::stPullHammerLever() { - if (!stStartAction(AnimationCallback(&Klaymen::stPullHammerLever))) { - _busyStatus = 2; - _acceptInput = false; - startAnimation(0x00648953, 0, -1); - SetUpdateHandler(&Klaymen::update); - SetMessageHandler(&Klaymen::hmPullHammerLever); - SetSpriteUpdate(&AnimatedSprite::updateDeltaXY); - } -} - -uint32 Klaymen::hmPullHammerLever(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Klaymen::hmLever(messageNum, param, sender); - switch (messageNum) { - case 0x100D: - if (param.asInteger() == 0x4AB28209) - sendMessage(_attachedSprite, 0x480F, 0); - break; - } - return messageResult; -} - -void Klaymen::suRidePlatformDown() { - _platformDeltaY++; - _y += _platformDeltaY; - if (_y > 600) - sendMessage(this, 0x1019, 0); -} - -void Klaymen::stRidePlatformDown() { - if (!stStartActionFromIdle(AnimationCallback(&Klaymen::stRidePlatformDown))) { - _busyStatus = 1; - sendMessage(_parentScene, 0x4803, 0); - _acceptInput = false; - _platformDeltaY = 0; - startAnimation(0x5420E254, 0, -1); - SetUpdateHandler(&Klaymen::update); - SetMessageHandler(&Klaymen::hmLowLevel); - SetSpriteUpdate(&Klaymen::suRidePlatformDown); - _vm->_soundMan->playSoundLooping(0xD3B02847); - } -} - -void Klaymen::stCrashDown() { - playSound(0, 0x41648271); - _busyStatus = 1; - _acceptInput = false; - startAnimationByHash(0x000BAB02, 0x88003000, 0); - SetUpdateHandler(&Klaymen::update); - SetSpriteUpdate(NULL); - SetMessageHandler(&Klaymen::hmLowLevelAnimation); - NextState(&Klaymen::stCrashDownFinished); -} - -void Klaymen::stCrashDownFinished() { - setDoDeltaX(2); - stTryStandIdle(); -} - void Klaymen::upSpitOutFall() { Klaymen::update(); if (_spitOutCountdown != 0 && (--_spitOutCountdown == 0)) { @@ -2724,24 +2414,6 @@ void Klaymen::upSpitOutFall() { } } -uint32 Klaymen::hmJumpToRingVenusFlyTrap(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = hmLowLevelAnimation(messageNum, param, sender); - switch (messageNum) { - case 0x100D: - if (param.asInteger() == 0x168050A0) { - sendMessage(_attachedSprite, 0x480F, 0); - } else if (param.asInteger() == 0x586B0300) { - sendMessage(_otherSprite, 0x480E, 1); - } else if (param.asInteger() == 0x4AB28209) { - sendMessage(_attachedSprite, 0x482A, 0); - } else if (param.asInteger() == 0x88001184) { - sendMessage(_attachedSprite, 0x482B, 0); - } - break; - } - return messageResult; -} - uint32 Klaymen::hmStandIdleSpecial(int messageNum, const MessageParam ¶m, Entity *sender) { switch (messageNum) { case 0x4811: @@ -2784,53 +2456,6 @@ uint32 Klaymen::hmPressDoorButton(int messageNum, const MessageParam ¶m, Ent return messageResult; } -uint32 Klaymen::hmMoveVenusFlyTrap(int messageNum, const MessageParam ¶m, Entity *sender) { - switch (messageNum) { - case 0x100D: - if (param.asInteger() == 0x01084280) { - sendMessage(_attachedSprite, 0x480B, (uint32)_doDeltaX); - } else if (param.asInteger() == 0x02421405) { - if (_isMoveObjectRequested) { - if (sendMessage(_attachedSprite, 0x480C, (uint32)_doDeltaX) != 0) - stContinueMovingVenusFlyTrap(); - } else { - SetMessageHandler(&Klaymen::hmFirstMoveVenusFlyTrap); - } - } else if (param.asInteger() == 0x4AB28209) { - sendMessage(_attachedSprite, 0x482A, 0); - } else if (param.asInteger() == 0x88001184) { - sendMessage(_attachedSprite, 0x482B, 0); - } else if (param.asInteger() == 0x32180101) { - playSound(0, 0x405002D8); - } else if (param.asInteger() == 0x0A2A9098) { - playSound(0, 0x0460E2FA); - } - break; - case 0x480A: - _isMoveObjectRequested = true; - return 0; - } - return hmLowLevelAnimation(messageNum, param, sender); -} - -uint32 Klaymen::hmFirstMoveVenusFlyTrap(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = hmLowLevelAnimation(messageNum, param, sender); - switch (messageNum) { - case 0x100D: - if (param.asInteger() == 0x4AB28209) { - sendMessage(_attachedSprite, 0x482A, 0); - } else if (param.asInteger() == 0x88001184) { - sendMessage(_attachedSprite, 0x482B, 0); - } else if (param.asInteger() == 0x32180101) { - playSound(0, 0x405002D8); - } else if (param.asInteger() == 0x0A2A9098) { - playSound(0, 0x0460E2FA); - } - break; - } - return messageResult; -} - uint32 Klaymen::hmHitByBoxingGlove(int messageNum, const MessageParam ¶m, Entity *sender) { int16 speedUpFrameIndex; uint32 messageResult = hmLowLevelAnimation(messageNum, param, sender); @@ -2854,18 +2479,6 @@ uint32 Klaymen::hmHitByBoxingGlove(int messageNum, const MessageParam ¶m, En return messageResult; } -uint32 Klaymen::hmJumpAndFall(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = hmLowLevel(messageNum, param, sender); - switch (messageNum) { - case 0x100D: - if (param.asInteger() == 0x1307050A) { - playSound(0, 0x40428A09); - } - break; - } - return messageResult; -} - void Klaymen::suFallDown() { AnimatedSprite::updateDeltaXY(); HitRect *hitRect = _parentScene->findHitRectAtPos(_x, _y + 10); @@ -2877,19 +2490,6 @@ void Klaymen::suFallDown() { _parentScene->checkCollision(this, 0xFFFF, 0x4810, 0); } -void Klaymen::stJumpToRingVenusFlyTrap() { - if (!stStartAction(AnimationCallback(&Klaymen::stJumpToRingVenusFlyTrap))) { - _busyStatus = 2; - _acceptInput = false; - startAnimation(0x584984B4, 0, -1); - SetUpdateHandler(&Klaymen::update); - SetMessageHandler(&Klaymen::hmJumpToRingVenusFlyTrap); - SetSpriteUpdate(&AnimatedSprite::updateDeltaXY); - NextState(&Klaymen::stLandOnFeet); - sendMessage(_attachedSprite, 0x482B, 0); - } -} - void Klaymen::stStandIdleSpecial() { playSound(0, 0x56548280); _busyStatus = 0; @@ -2946,34 +2546,6 @@ void Klaymen::stFallTouchdown() { stTryStandIdle(); } -void Klaymen::stJumpAndFall() { - if (!stStartAction(AnimationCallback(&Klaymen::stJumpAndFall))) { - sendMessage(_parentScene, 0x1024, 3); - _busyStatus = 2; - _acceptInput = false; - startAnimation(0xB93AB151, 0, -1); - SetUpdateHandler(&Klaymen::update); - SetMessageHandler(&Klaymen::hmJumpAndFall); - SetSpriteUpdate(&Klaymen::suFallDown); - NextState(&Klaymen::stLandOnFeet); - } -} - -void Klaymen::stDropFromRing() { - if (_attachedSprite) { - _x = _attachedSprite->getX(); - sendMessage(_attachedSprite, 0x4807, 0); - _attachedSprite = NULL; - } - _busyStatus = 2; - _acceptInput = false; - startAnimation(0x586984B1, 0, -1); - SetUpdateHandler(&Klaymen::update); - SetMessageHandler(&Klaymen::hmLowLevel); - SetSpriteUpdate(&Klaymen::suFallDown); - NextState(&Klaymen::stLandOnFeet); -} - void Klaymen::stPressDoorButton() { _busyStatus = 2; _acceptInput = true; @@ -2998,34 +2570,6 @@ void Klaymen::evHitByBoxingGloveDone() { sendMessage(_parentScene, 0x1024, 1); } -void Klaymen::stMoveVenusFlyTrap() { - if (!stStartAction(AnimationCallback(&Klaymen::stMoveVenusFlyTrap))) { - _busyStatus = 2; - _isMoveObjectRequested = false; - _acceptInput = true; - setDoDeltaX(_attachedSprite->getX() < _x ? 1 : 0); - startAnimation(0x5C01A870, 0, -1); - SetUpdateHandler(&Klaymen::update); - SetMessageHandler(&Klaymen::hmMoveVenusFlyTrap); - SetSpriteUpdate(&AnimatedSprite::updateDeltaXY); - FinalizeState(&Klaymen::evMoveVenusFlyTrapDone); - } -} - -void Klaymen::stContinueMovingVenusFlyTrap() { - _isMoveObjectRequested = false; - _acceptInput = true; - startAnimationByHash(0x5C01A870, 0x01084280, 0); - SetUpdateHandler(&Klaymen::update); - SetMessageHandler(&Klaymen::hmMoveVenusFlyTrap); - SetSpriteUpdate(&AnimatedSprite::updateDeltaXY); - FinalizeState(&Klaymen::evMoveVenusFlyTrapDone); -} - -void Klaymen::evMoveVenusFlyTrapDone() { - sendMessage(_attachedSprite, 0x482A, 0); -} - void Klaymen::suFallSkipJump() { updateDeltaXY(); HitRect *hitRect = _parentScene->findHitRectAtPos(_x, _y + 10); @@ -3052,49 +2596,6 @@ void Klaymen::upMoveObject() { Klaymen::update(); } -uint32 Klaymen::hmMatch(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Klaymen::hmLowLevelAnimation(messageNum, param, sender); - switch (messageNum) { - case 0x100D: - if (param.asInteger() == 0x51281850) { - setGlobalVar(V_TNT_DUMMY_FUSE_LIT, 1); - } else if (param.asInteger() == 0x43000538) { - playSound(0, 0x21043059); - } else if (param.asInteger() == 0x02B20220) { - playSound(0, 0xC5408620); - } else if (param.asInteger() == 0x0A720138) { - playSound(0, 0xD4C08010); - } else if (param.asInteger() == 0xB613A180) { - playSound(0, 0x44051000); - } - break; - } - return messageResult; -} - -void Klaymen::stFetchMatch() { - if (!stStartAction(AnimationCallback(&Klaymen::stFetchMatch))) { - _busyStatus = 0; - _acceptInput = false; - setDoDeltaX(_attachedSprite->getX() < _x ? 1 : 0); - startAnimation(0x9CAA0218, 0, -1); - SetUpdateHandler(&Klaymen::update); - SetMessageHandler(&Klaymen::hmMatch); - SetSpriteUpdate(NULL); - NextState(&Klaymen::stLightMatch); - } -} - -void Klaymen::stLightMatch() { - _busyStatus = 1; - _acceptInput = false; - setDoDeltaX(_attachedSprite->getX() < _x ? 1 : 0); - startAnimation(0x1222A513, 0, -1); - SetUpdateHandler(&Klaymen::update); - SetMessageHandler(&Klaymen::hmMatch); - SetSpriteUpdate(NULL); -} - uint32 Klaymen::hmMoveObject(int messageNum, const MessageParam ¶m, Entity *sender) { switch (messageNum) { case 0x100D: @@ -3114,18 +2615,6 @@ uint32 Klaymen::hmMoveObject(int messageNum, const MessageParam ¶m, Entity * return Klaymen::hmLowLevelAnimation(messageNum, param, sender); } -uint32 Klaymen::hmTumbleHeadless(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Klaymen::hmLowLevelAnimation(messageNum, param, sender); - switch (messageNum) { - case 0x100D: - if (param.asInteger() == 0x000F0082) { - playSound(0, 0x74E2810F); - } - break; - } - return messageResult; -} - void Klaymen::stMoveObject() { if (!stStartAction(AnimationCallback(&Klaymen::stMoveObject))) { _busyStatus = 2; @@ -3147,93 +2636,6 @@ void Klaymen::stContinueMoveObject() { SetMessageHandler(&Klaymen::hmMoveObject); } -void Klaymen::stTumbleHeadless() { - if (!stStartActionFromIdle(AnimationCallback(&Klaymen::stTumbleHeadless))) { - _busyStatus = 1; - _acceptInput = false; - setDoDeltaX(0); - startAnimation(0x2821C590, 0, -1); - SetUpdateHandler(&Klaymen::update); - SetMessageHandler(&Klaymen::hmTumbleHeadless); - SetSpriteUpdate(&AnimatedSprite::updateDeltaXY); - NextState(&Klaymen::stTryStandIdle); - sendMessage(_parentScene, 0x8000, 0); - playSound(0, 0x62E0A356); - } -} - -void Klaymen::stCloseEyes() { - if (!stStartActionFromIdle(AnimationCallback(&Klaymen::stCloseEyes))) { - _busyStatus = 1; - _acceptInput = false; - startAnimation(0x5420E254, 0, -1); - SetUpdateHandler(&Klaymen::update); - SetMessageHandler(&Klaymen::hmLowLevel); - SetSpriteUpdate(NULL); - } -} - -uint32 Klaymen::hmSpit(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Klaymen::hmLowLevelAnimation(messageNum, param, sender); - switch (messageNum) { - case 0x100D: - if (param.asInteger() == 0x16401CA6) { - _canSpitPipe = true; - if (_contSpitPipe) - spitIntoPipe(); - } else if (param.asInteger() == 0xC11C0008) { - _canSpitPipe = false; - _acceptInput = false; - _readyToSpit = false; - } else if (param.asInteger() == 0x018A0001) { - sendMessage(_parentScene, 0x2001, _spitDestPipeIndex); - } - break; - } - return messageResult; -} - -void Klaymen::stTrySpitIntoPipe() { - if (_readyToSpit) { - _contSpitPipe = true; - _spitContDestPipeIndex = _spitPipeIndex; - if (_canSpitPipe) - spitIntoPipe(); - } else if (!stStartAction(AnimationCallback(&Klaymen::stTrySpitIntoPipe))) { - _busyStatus = 2; - _acceptInput = true; - _spitDestPipeIndex = _spitPipeIndex; - _readyToSpit = true; - _canSpitPipe = false; - _contSpitPipe = false; - startAnimation(0x1808B150, 0, -1); - SetUpdateHandler(&Klaymen::update); - SetMessageHandler(&Klaymen::hmSpit); - SetSpriteUpdate(NULL); - } -} - -void Klaymen::spitIntoPipe() { - _contSpitPipe = false; - _spitDestPipeIndex = _spitContDestPipeIndex; - _canSpitPipe = false; - _acceptInput = false; - startAnimation(0x1B08B553, 0, -1); - SetUpdateHandler(&Klaymen::update); - SetMessageHandler(&Klaymen::hmSpit); - SetSpriteUpdate(NULL); - NextState(&Klaymen::stContSpitIntoPipe); -} - -void Klaymen::stContSpitIntoPipe() { - _canSpitPipe = true; - _acceptInput = true; - startAnimationByHash(0x1808B150, 0x16401CA6, 0); - SetUpdateHandler(&Klaymen::update); - SetMessageHandler(&Klaymen::hmSpit); - SetSpriteUpdate(NULL); -} - void Klaymen::suRidePlatform() { _x = _attachedSprite->getX() - 20; _y = _attachedSprite->getY() + 46; @@ -3344,2798 +2746,4 @@ void Klaymen::stPeekInsideBlink() { _blinkCounterMax = _vm->_rnd->getRandomNumber(64 - 1) + 24; } -// KmScene1001 - -KmScene1001::KmScene1001(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) - : Klaymen(vm, parentScene, x, y) { -} - -uint32 KmScene1001::xHandleMessage(int messageNum, const MessageParam ¶m) { - switch (messageNum) { - case 0x4001: - case 0x4800: - startWalkToX(param.asPoint().x, false); - break; - case 0x4004: - GotoState(&Klaymen::stTryStandIdle); - break; - case 0x4804: - if (param.asInteger() == 2) - GotoState(&Klaymen::stSleeping); - break; - case 0x480D: - GotoState(&Klaymen::stPullHammerLever); - break; - case 0x4812: - GotoState(&Klaymen::stPickUpGeneric); - break; - case 0x4816: - if (param.asInteger() == 1) - GotoState(&Klaymen::stPressButton); - else if (param.asInteger() == 2) - GotoState(&Klaymen::stPressFloorButton); - else - GotoState(&Klaymen::stPressButtonSide); - break; - case 0x4817: - setDoDeltaX(param.asInteger()); - gotoNextStateExt(); - break; - case 0x481B: - if (param.asPoint().y != 0) - startWalkToXDistance(param.asPoint().y, param.asPoint().x); - else - startWalkToAttachedSpriteXDistance(param.asPoint().x); - break; - case 0x481F: - if (param.asInteger() == 0) - GotoState(&Klaymen::stWonderAboutHalf); - else if (param.asInteger() == 1) - GotoState(&Klaymen::stWonderAboutAfter); - else if (param.asInteger() == 3) - GotoState(&Klaymen::stTurnToUseHalf); - else if (param.asInteger() == 4) - GotoState(&Klaymen::stTurnAwayFromUse); - else - GotoState(&Klaymen::stWonderAbout); - break; - case 0x482D: - setDoDeltaX(_x > (int16)param.asInteger() ? 1 : 0); - gotoNextStateExt(); - break; - case 0x4836: - if (param.asInteger() == 1) { - sendMessage(_parentScene, 0x2002, 0); - GotoState(&Klaymen::stWakeUp); - } - break; - case 0x483F: - startSpecialWalkRight(param.asInteger()); - break; - case 0x4840: - startSpecialWalkLeft(param.asInteger()); - break; - } - return 0; -} - -// KmScene1002 - -KmScene1002::KmScene1002(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) - : Klaymen(vm, parentScene, x, y) { - - setKlaymenIdleTable1(); -} - -void KmScene1002::xUpdate() { - if (_x >= 250 && _x <= 435 && _y >= 420) { - if (_idleTableNum == 0) { - setKlaymenIdleTable(klaymenIdleTable1002, ARRAYSIZE(klaymenIdleTable1002)); - _idleTableNum = 1; - } - } else if (_idleTableNum == 1) { - setKlaymenIdleTable1(); - _idleTableNum = 0; - } -} - -uint32 KmScene1002::xHandleMessage(int messageNum, const MessageParam ¶m) { - switch (messageNum) { - case 0x2001: - GotoState(&Klaymen::stStandIdleSpecial); - break; - case 0x2007: - _otherSprite = (Sprite*)param.asEntity(); - break; - case 0x4001: - case 0x4800: - startWalkToX(param.asPoint().x, false); - break; - case 0x4004: - GotoState(&Klaymen::stTryStandIdle); - break; - case 0x4803: - if (param.asInteger() == 1) - GotoState(&Klaymen::stJumpAndFall); - else if (param.asInteger() == 2) - GotoState(&Klaymen::stDropFromRing); - break; - case 0x4804: - GotoState(&Klaymen::stPeekWall); - break; - case 0x4805: - switch (param.asInteger()) { - case 1: - GotoState(&Klaymen::stJumpToRing1); - break; - case 2: - GotoState(&Klaymen::stJumpToRing2); - break; - case 3: - GotoState(&Klaymen::stJumpToRing3); - break; - case 4: - GotoState(&Klaymen::stJumpToRing4); - break; - } - break; - case 0x480A: - GotoState(&Klaymen::stMoveVenusFlyTrap); - break; - case 0x480D: - GotoState(&Klaymen::stJumpToRingVenusFlyTrap); - break; - case 0x4816: - if (param.asInteger() == 0) - GotoState(&Klaymen::stPressDoorButton); - break; - case 0x4817: - setDoDeltaX(param.asInteger()); - gotoNextStateExt(); - break; - case 0x481B: - startWalkToAttachedSpriteXDistance(param.asInteger()); - break; - case 0x4820: - sendMessage(_parentScene, 0x2005, 0); - GotoState(&Klaymen::stContinueClimbLadderUp); - break; - case 0x4821: - sendMessage(_parentScene, 0x2005, 0); - _destY = param.asInteger(); - GotoState(&Klaymen::stStartClimbLadderDown); - break; - case 0x4822: - sendMessage(_parentScene, 0x2005, 0); - _destY = param.asInteger(); - GotoState(&Klaymen::stStartClimbLadderUp); - break; - case 0x4823: - sendMessage(_parentScene, 0x2006, 0); - GotoState(&Klaymen::stClimbLadderHalf); - break; - case 0x482E: - if (param.asInteger() == 1) - GotoState(&Klaymen::stWalkToFrontNoStep); - else - GotoState(&Klaymen::stWalkToFront); - break; - case 0x482F: - if (param.asInteger() == 1) - GotoState(&Klaymen::stTurnToFront); - else - GotoState(&Klaymen::stTurnToBack); - break; - case 0x483F: - startSpecialWalkRight(param.asInteger()); - break; - case 0x4840: - startSpecialWalkLeft(param.asInteger()); - break; - } - return 0; -} - -// KmScene1004 - -KmScene1004::KmScene1004(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) - : Klaymen(vm, parentScene, x, y) { - - _dataResource.load(0x01900A04); -} - -uint32 KmScene1004::xHandleMessage(int messageNum, const MessageParam ¶m) { - switch (messageNum) { - case 0x4001: - case 0x4800: - startWalkToX(param.asPoint().x, false); - break; - case 0x4004: - GotoState(&Klaymen::stTryStandIdle); - break; - case 0x4817: - setDoDeltaX(param.asInteger()); - gotoNextStateExt(); - break; - case 0x4818: - startWalkToX(_dataResource.getPoint(param.asInteger()).x, false); - break; - case 0x481E: - GotoState(&Klaymen::stReadNote); - break; - case 0x4820: - sendMessage(_parentScene, 0x2000, 0); - GotoState(&Klaymen::stContinueClimbLadderUp); - break; - case 0x4821: - sendMessage(_parentScene, 0x2000, 0); - _destY = param.asInteger(); - GotoState(&Klaymen::stStartClimbLadderDown); - break; - case 0x4822: - sendMessage(_parentScene, 0x2000, 0); - _destY = param.asInteger(); - GotoState(&Klaymen::stStartClimbLadderUp); - break; - case 0x4823: - sendMessage(_parentScene, 0x2001, 0); - GotoState(&Klaymen::stClimbLadderHalf); - break; - case 0x4824: - sendMessage(_parentScene, 0x2000, 0); - _destY = _dataResource.getPoint(param.asInteger()).y; - GotoState(&Klaymen::stStartClimbLadderDown); - break; - case 0x4825: - sendMessage(_parentScene, 0x2000, 0); - _destY = _dataResource.getPoint(param.asInteger()).y; - GotoState(&Klaymen::stStartClimbLadderUp); - break; - case 0x4828: - GotoState(&Klaymen::stTurnToBackToUse); - break; - case 0x483F: - startSpecialWalkRight(param.asInteger()); - break; - case 0x4840: - startSpecialWalkLeft(param.asInteger()); - break; - } - return 0; -} - -KmScene1109::KmScene1109(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) - : Klaymen(vm, parentScene, x, y) { - - // Empty -} - -uint32 KmScene1109::xHandleMessage(int messageNum, const MessageParam ¶m) { - uint32 messageResult = 0; - switch (messageNum) { - case 0x2000: - _isSittingInTeleporter = param.asInteger() != 0; - messageResult = 1; - break; - case 0x4001: - case 0x4800: - startWalkToX(param.asPoint().x, false); - break; - case 0x4004: - if (_isSittingInTeleporter) - GotoState(&Klaymen::stSitIdleTeleporter); - else - GotoState(&Klaymen::stTryStandIdle); - break; - case 0x4804: - if (param.asInteger() != 0) { - _destX = param.asInteger(); - GotoState(&Klaymen::stWalkingFirst); - } else - GotoState(&Klaymen::stPeekWall); - break; - case 0x4817: - setDoDeltaX(param.asInteger()); - gotoNextStateExt(); - break; - case 0x481D: - if (_isSittingInTeleporter) - GotoState(&Klaymen::stTurnToUseInTeleporter); - break; - case 0x481E: - if (_isSittingInTeleporter) - GotoState(&Klaymen::stReturnFromUseInTeleporter); - break; - case 0x4834: - GotoState(&Klaymen::stStepOver); - break; - case 0x4835: - sendMessage(_parentScene, 0x2000, 1); - _isSittingInTeleporter = true; - GotoState(&Klaymen::stSitInTeleporter); - break; - case 0x4836: - sendMessage(_parentScene, 0x2000, 0); - _isSittingInTeleporter = false; - GotoState(&Klaymen::stGetUpFromTeleporter); - break; - case 0x483D: - teleporterAppear(0x2C2A4A1C); - break; - case 0x483E: - teleporterDisappear(0x3C2E4245); - break; - } - return messageResult; -} - -// KmScene1201 - -KmScene1201::KmScene1201(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) - : Klaymen(vm, parentScene, x, y) { - - setKlaymenIdleTable(klaymenIdleTable4, ARRAYSIZE(klaymenIdleTable4)); - _doYHitIncr = true; -} - -uint32 KmScene1201::xHandleMessage(int messageNum, const MessageParam ¶m) { - switch (messageNum) { - case 0x4001: - case 0x4800: - startWalkToX(param.asPoint().x, false); - break; - case 0x4004: - GotoState(&Klaymen::stTryStandIdle); - break; - case 0x480A: - GotoState(&Klaymen::stMoveObject); - break; - case 0x4812: - GotoState(&Klaymen::stPickUpGeneric); - break; - case 0x4813: - GotoState(&Klaymen::stFetchMatch); - break; - case 0x4814: - GotoState(&Klaymen::stTumbleHeadless); - break; - case 0x4815: - GotoState(&Klaymen::stCloseEyes); - break; - case 0x4816: - if (param.asInteger() == 0) - GotoState(&Klaymen::stPressButtonSide); - break; - case 0x4817: - setDoDeltaX(param.asInteger()); - gotoNextStateExt(); - break; - case 0x481B: - if (param.asPoint().y != 0) - startWalkToXDistance(param.asPoint().y, param.asPoint().x); - else - startWalkToAttachedSpriteXDistance(param.asPoint().x); - break; - case 0x481D: - GotoState(&Klaymen::stTurnToUse); - break; - case 0x481E: - GotoState(&Klaymen::stReturnFromUse); - break; - case 0x481F: - GotoState(&Klaymen::stWonderAbout); - break; - case 0x482D: - setDoDeltaX(_x > (int16)param.asInteger() ? 1 : 0); - gotoNextStateExt(); - break; - case 0x483F: - startSpecialWalkRight(param.asInteger()); - break; - case 0x4840: - startSpecialWalkLeft(param.asInteger()); - break; - } - return 0; -} - -KmScene1303::KmScene1303(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) - : Klaymen(vm, parentScene, x, y) { - - // Empty -} - -uint32 KmScene1303::xHandleMessage(int messageNum, const MessageParam ¶m) { - switch (messageNum) { - case 0x4804: - GotoState(&Klaymen::stPeekWall1); - break; - case 0x483B: - GotoState(&Klaymen::stPeekWallReturn); - break; - case 0x483C: - GotoState(&Klaymen::stPeekWall2); - break; - } - return 0; -} - -KmScene1304::KmScene1304(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) - : Klaymen(vm, parentScene, x, y) { - - // Empty -} - -uint32 KmScene1304::xHandleMessage(int messageNum, const MessageParam ¶m) { - switch (messageNum) { - case 0x4001: - case 0x4800: - startWalkToX(param.asPoint().x, false); - break; - case 0x4004: - GotoState(&Klaymen::stTryStandIdle); - break; - case 0x4812: - if (param.asInteger() == 2) - GotoState(&Klaymen::stPickUpNeedle); - else if (param.asInteger() == 1) - GotoState(&Klaymen::stPickUpTube); - else - GotoState(&Klaymen::stPickUpGeneric); - break; - case 0x4817: - setDoDeltaX(param.asInteger()); - gotoNextStateExt(); - break; - case 0x481B: - if (param.asPoint().y != 0) - startWalkToXDistance(param.asPoint().y, param.asPoint().x); - else - startWalkToAttachedSpriteXDistance(param.asPoint().x); - break; - case 0x481F: - if (param.asInteger() == 1) - GotoState(&Klaymen::stTurnAwayFromUse); - else if (param.asInteger() == 0) - GotoState(&Klaymen::stTurnToUseHalf); - else - GotoState(&Klaymen::stWonderAbout); - break; - case 0x483F: - startSpecialWalkRight(param.asInteger()); - break; - case 0x4840: - startSpecialWalkLeft(param.asInteger()); - break; - } - return 0; -} - -KmScene1305::KmScene1305(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) - : Klaymen(vm, parentScene, x, y) { - - // Empty -} - -uint32 KmScene1305::xHandleMessage(int messageNum, const MessageParam ¶m) { - switch (messageNum) { - case 0x4001: - case 0x4800: - startWalkToX(param.asPoint().x, false); - break; - case 0x4004: - GotoState(&Klaymen::stTryStandIdle); - break; - case 0x4804: - GotoState(&Klaymen::stCrashDown); - break; - case 0x4817: - setDoDeltaX(param.asInteger()); - gotoNextStateExt(); - break; - } - return 0; -} - -KmScene1306::KmScene1306(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) - : Klaymen(vm, parentScene, x, y) { - - // Empty -} - -uint32 KmScene1306::xHandleMessage(int messageNum, const MessageParam ¶m) { - uint32 messageResult = 0; - switch (messageNum) { - case 0x2000: - _isSittingInTeleporter = param.asInteger() != 0; - messageResult = 1; - break; - case 0x4001: - case 0x4800: - startWalkToX(param.asPoint().x, false); - break; - case 0x4004: - if (_isSittingInTeleporter) - GotoState(&Klaymen::stSitIdleTeleporter); - else - GotoState(&Klaymen::stTryStandIdle); - break; - case 0x4812: - if (param.asInteger() == 2) - GotoState(&Klaymen::stPickUpNeedle); - else if (param.asInteger() == 1) - GotoState(&Klaymen::stPickUpTube); - else - GotoState(&Klaymen::stPickUpGeneric); - break; - case 0x4816: - if (param.asInteger() == 1) - GotoState(&Klaymen::stPressButton); - else if (param.asInteger() == 2) - GotoState(&Klaymen::stPressFloorButton); - else - GotoState(&Klaymen::stPressButtonSide); - break; - case 0x4817: - setDoDeltaX(param.asInteger()); - gotoNextStateExt(); - break; - case 0x481A: - GotoState(&Klaymen::stInsertDisk); - break; - case 0x481B: - if (param.asPoint().y != 0) - startWalkToXDistance(param.asPoint().y, param.asPoint().x); - else - startWalkToAttachedSpriteXDistance(param.asPoint().x); - break; - case 0x481D: - if (_isSittingInTeleporter) - GotoState(&Klaymen::stTurnToUseInTeleporter); - else - GotoState(&Klaymen::stTurnToUse); - break; - case 0x481E: - if (_isSittingInTeleporter) - GotoState(&Klaymen::stReturnFromUseInTeleporter); - else - GotoState(&Klaymen::stReturnFromUse); - break; - case 0x481F: - if (param.asInteger() == 1) - GotoState(&Klaymen::stWonderAboutAfter); - else if (param.asInteger() == 0) - GotoState(&Klaymen::stWonderAboutHalf); - else if (param.asInteger() == 4) - GotoState(&Klaymen::stTurnAwayFromUse); - else if (param.asInteger() == 3) - GotoState(&Klaymen::stTurnToUseHalf); - else - GotoState(&Klaymen::stWonderAbout); - break; - case 0x482D: - setDoDeltaX(_x > (int16)param.asInteger() ? 1 : 0); - gotoNextStateExt(); - break; - case 0x482E: - if (param.asInteger() == 1) - GotoState(&Klaymen::stWalkToFrontNoStep); - else - GotoState(&Klaymen::stWalkToFront); - break; - case 0x482F: - if (param.asInteger() == 1) - GotoState(&Klaymen::stTurnToFront); - else - GotoState(&Klaymen::stTurnToBack); - break; - case 0x4834: - GotoState(&Klaymen::stStepOver); - break; - case 0x4835: - sendMessage(_parentScene, 0x2000, 1); - _isSittingInTeleporter = true; - GotoState(&Klaymen::stSitInTeleporter); - break; - case 0x4836: - sendMessage(_parentScene, 0x2000, 0); - _isSittingInTeleporter = false; - GotoState(&Klaymen::stGetUpFromTeleporter); - break; - case 0x483D: - teleporterAppear(0xEE084A04); - break; - case 0x483E: - teleporterDisappear(0xB86A4274); - break; - case 0x483F: - startSpecialWalkRight(param.asInteger()); - break; - case 0x4840: - startSpecialWalkLeft(param.asInteger()); - break; - } - return messageResult; -} - -KmScene1308::KmScene1308(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) - : Klaymen(vm, parentScene, x, y) { - - // Empty -} - -uint32 KmScene1308::xHandleMessage(int messageNum, const MessageParam ¶m) { - switch (messageNum) { - case 0x4001: - case 0x4800: - startWalkToX(param.asPoint().x, false); - break; - case 0x4004: - GotoState(&Klaymen::stTryStandIdle); - break; - case 0x480A: - if (param.asInteger() == 1) - GotoState(&Klaymen::stMoveObjectSkipTurnFaceObject); - else - GotoState(&Klaymen::stMoveObjectFaceObject); - break; - case 0x480D: - GotoState(&Klaymen::stUseLever); - break; - case 0x4812: - if (param.asInteger() == 2) - GotoState(&Klaymen::stPickUpNeedle); - else if (param.asInteger() == 1) - GotoState(&Klaymen::stPickUpTube); - else - GotoState(&Klaymen::stPickUpGeneric); - break; - case 0x4817: - setDoDeltaX(param.asInteger()); - gotoNextStateExt(); - break; - case 0x481A: - if (param.asInteger() == 1) - GotoState(&Klaymen::stInsertKey); - else - GotoState(&Klaymen::stInsertDisk); - break; - case 0x481B: - if (param.asPoint().y != 0) - startWalkToXDistance(param.asPoint().y, param.asPoint().x); - else - startWalkToAttachedSpriteXDistance(param.asPoint().x); - break; - case 0x481D: - GotoState(&Klaymen::stTurnToUse); - break; - case 0x481E: - GotoState(&Klaymen::stReturnFromUse); - break; - case 0x4827: - GotoState(&Klaymen::stReleaseLever); - break; - case 0x4834: - GotoState(&Klaymen::stStepOver); - break; - case 0x483F: - startSpecialWalkRight(param.asInteger()); - break; - case 0x4840: - startSpecialWalkLeft(param.asInteger()); - break; - } - return 0; -} - -// KmScene1401 - -KmScene1401::KmScene1401(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) - : Klaymen(vm, parentScene, x, y) { - - // Empty -} - -uint32 KmScene1401::xHandleMessage(int messageNum, const MessageParam ¶m) { - switch (messageNum) { - case 0x4001: - case 0x4800: - startWalkToX(param.asPoint().x, false); - break; - case 0x4004: - GotoState(&Klaymen::stTryStandIdle); - break; - case 0x480A: - if (param.asInteger() == 1) - GotoState(&Klaymen::stMoveObjectSkipTurnFaceObject); - else - GotoState(&Klaymen::stMoveObjectFaceObject); - break; - case 0x4816: - if (param.asInteger() == 1) - GotoState(&Klaymen::stPressButton); - else if (param.asInteger() == 2) - GotoState(&Klaymen::stPressFloorButton); - else - GotoState(&Klaymen::stPressButtonSide); - break; - case 0x4817: - setDoDeltaX(param.asInteger()); - gotoNextStateExt(); - break; - case 0x481B: - if (param.asPoint().y != 0) - startWalkToXDistance(param.asPoint().y, param.asPoint().x); - else - startWalkToAttachedSpriteXDistance(param.asPoint().x); - break; - case 0x481F: - if (param.asInteger() == 1) - GotoState(&Klaymen::stTurnAwayFromUse); - else if (param.asInteger() == 0) - GotoState(&Klaymen::stTurnToUseHalf); - else - GotoState(&Klaymen::stWonderAbout); - break; - case 0x482D: - setDoDeltaX(_x > (int16)param.asInteger() ? 1 : 0); - gotoNextStateExt(); - break; - case 0x482E: - if (param.asInteger() == 1) - GotoState(&Klaymen::stWalkToFrontNoStep); - else - GotoState(&Klaymen::stWalkToFront); - break; - case 0x482F: - if (param.asInteger() == 1) - GotoState(&Klaymen::stTurnToFront); - else - GotoState(&Klaymen::stTurnToBack); - break; - } - return 0; -} - -// KmScene1402 - -KmScene1402::KmScene1402(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) - : Klaymen(vm, parentScene, x, y) { - - SetFilterY(&Sprite::defFilterY); -} - -uint32 KmScene1402::xHandleMessage(int messageNum, const MessageParam ¶m) { - switch (messageNum) { - case 0x4001: - case 0x4800: - startWalkToX(param.asPoint().x, false); - break; - case 0x4004: - GotoState(&Klaymen::stTryStandIdle); - break; - case 0x480A: - if (param.asInteger() == 1) - GotoState(&Klaymen::stMoveObjectSkipTurnFaceObject); - else - GotoState(&Klaymen::stMoveObjectFaceObject); - break; - case 0x4817: - setDoDeltaX(param.asInteger()); - gotoNextStateExt(); - break; - case 0x481B: - if (param.asPoint().y != 0) - startWalkToXDistance(param.asPoint().y, param.asPoint().x); - else - startWalkToAttachedSpriteXDistance(param.asPoint().x); - break; - case 0x481D: - GotoState(&Klaymen::stTurnToUse); - break; - case 0x481E: - GotoState(&Klaymen::stReturnFromUse); - break; - } - return 0; -} - -// KmScene1403 - -KmScene1403::KmScene1403(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) - : Klaymen(vm, parentScene, x, y) { - - setKlaymenIdleTable(klaymenIdleTable4, ARRAYSIZE(klaymenIdleTable4)); -} - -uint32 KmScene1403::xHandleMessage(int messageNum, const MessageParam ¶m) { - switch (messageNum) { - case 0x4001: - case 0x4800: - startWalkToX(param.asPoint().x, false); - break; - case 0x4004: - GotoState(&Klaymen::stTryStandIdle); - break; - case 0x480A: - if (param.asInteger() == 1) - GotoState(&Klaymen::stMoveObjectSkipTurnFaceObject); - else - GotoState(&Klaymen::stMoveObjectFaceObject); - break; - case 0x480D: - GotoState(&Klaymen::stUseLever); - break; - case 0x4812: - if (param.asInteger() == 2) - GotoState(&Klaymen::stPickUpNeedle); - else if (param.asInteger() == 1) - GotoState(&Klaymen::stPickUpTube); - else - GotoState(&Klaymen::stPickUpGeneric); - break; - case 0x4817: - setDoDeltaX(param.asInteger()); - gotoNextStateExt(); - break; - case 0x481B: - if (param.asPoint().y != 0) - startWalkToXDistance(param.asPoint().y, param.asPoint().x); - else - startWalkToAttachedSpriteXDistance(param.asPoint().x); - break; - case 0x4827: - GotoState(&Klaymen::stReleaseLever); - break; - case 0x483F: - startSpecialWalkRight(param.asInteger()); - break; - case 0x4840: - startSpecialWalkLeft(param.asInteger()); - break; - } - return 0; -} - -// KmScene1404 - -KmScene1404::KmScene1404(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) - : Klaymen(vm, parentScene, x, y) { - - // Empty -} - -uint32 KmScene1404::xHandleMessage(int messageNum, const MessageParam ¶m) { - switch (messageNum) { - case 0x4001: - case 0x4800: - startWalkToX(param.asPoint().x, false); - break; - case 0x4004: - GotoState(&Klaymen::stTryStandIdle); - break; - case 0x480A: - if (param.asInteger() == 1) - GotoState(&Klaymen::stMoveObjectSkipTurnFaceObject); - else - GotoState(&Klaymen::stMoveObjectFaceObject); - break; - case 0x4812: - if (param.asInteger() == 2) - GotoState(&Klaymen::stPickUpNeedle); - else if (param.asInteger() == 1) - GotoState(&Klaymen::stPickUpTube); - else - GotoState(&Klaymen::stPickUpGeneric); - break; - case 0x4817: - setDoDeltaX(param.asInteger()); - gotoNextStateExt(); - break; - case 0x481A: - GotoState(&Klaymen::stInsertDisk); - break; - case 0x481B: - if (param.asPoint().y != 0) - startWalkToXDistance(param.asPoint().y, param.asPoint().x); - else - startWalkToAttachedSpriteXDistance(param.asPoint().x); - break; - case 0x481D: - GotoState(&Klaymen::stTurnToUse); - break; - case 0x481E: - GotoState(&Klaymen::stReturnFromUse); - break; - case 0x481F: - if (param.asInteger() == 1) - GotoState(&Klaymen::stWonderAboutAfter); - else if (param.asInteger() == 0) - GotoState(&Klaymen::stWonderAboutHalf); - else if (param.asInteger() == 4) - GotoState(&Klaymen::stTurnAwayFromUse); - else if (param.asInteger() == 3) - GotoState(&Klaymen::stTurnToUseHalf); - else - GotoState(&Klaymen::stWonderAbout); - break; - case 0x482D: - setDoDeltaX(_x > (int16)param.asInteger() ? 1 : 0); - gotoNextStateExt(); - break; - case 0x483F: - startSpecialWalkRight(param.asInteger()); - break; - case 0x4840: - startSpecialWalkLeft(param.asInteger()); - break; - } - return 0; -} - -KmScene1608::KmScene1608(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) - : Klaymen(vm, parentScene, x, y) { - - // Empty -} - -uint32 KmScene1608::xHandleMessage(int messageNum, const MessageParam ¶m) { - uint32 messageResult = 0; - switch (messageNum) { - case 0x2032: - _isSittingInTeleporter = param.asInteger() != 0; - messageResult = 1; - break; - case 0x4001: - case 0x4800: - startWalkToX(param.asPoint().x, false); - break; - case 0x4004: - if (_isSittingInTeleporter) - GotoState(&Klaymen::stSitIdleTeleporter); - else - GotoState(&Klaymen::stTryStandIdle); - break; - case 0x4812: - if (param.asInteger() == 2) - GotoState(&Klaymen::stPickUpNeedle); - else if (param.asInteger() == 1) - GotoState(&Klaymen::stPickUpTube); - else - GotoState(&Klaymen::stPickUpGeneric); - break; - case 0x4817: - setDoDeltaX(param.asInteger()); - gotoNextStateExt(); - break; - case 0x481B: - if (param.asPoint().y != 0) - startWalkToXDistance(param.asPoint().y, param.asPoint().x); - else - startWalkToAttachedSpriteXDistance(param.asPoint().x); - break; - case 0x481D: - if (_isSittingInTeleporter) - GotoState(&Klaymen::stTurnToUseInTeleporter); - break; - case 0x481E: - if (_isSittingInTeleporter) - GotoState(&Klaymen::stReturnFromUseInTeleporter); - break; - case 0x481F: - if (param.asInteger() == 1) - GotoState(&Klaymen::stWonderAboutAfter); - else if (param.asInteger() == 0) - GotoState(&Klaymen::stWonderAboutHalf); - else if (param.asInteger() == 4) - GotoState(&Klaymen::stTurnAwayFromUse); - else if (param.asInteger() == 3) - GotoState(&Klaymen::stTurnToUseHalf); - else - GotoState(&Klaymen::stWonderAbout); - break; - case 0x482D: - setDoDeltaX(_x > (int16)param.asInteger() ? 1 : 0); - gotoNextStateExt(); - break; - case 0x4834: - GotoState(&Klaymen::stStepOver); - break; - case 0x4835: - sendMessage(_parentScene, 0x2032, 1); - _isSittingInTeleporter = true; - GotoState(&Klaymen::stSitInTeleporter); - break; - case 0x4836: - sendMessage(_parentScene, 0x2032, 0); - _isSittingInTeleporter = false; - GotoState(&Klaymen::stGetUpFromTeleporter); - break; - case 0x483F: - startSpecialWalkRight(param.asInteger()); - break; - case 0x4840: - startSpecialWalkLeft(param.asInteger()); - break; - } - return messageResult; -} - -// KmScene1705 - -KmScene1705::KmScene1705(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) - : Klaymen(vm, parentScene, x, y) { - - // Empty -} - -uint32 KmScene1705::xHandleMessage(int messageNum, const MessageParam ¶m) { - uint32 messageResult = 0; - switch (messageNum) { - case 0x2000: - _isSittingInTeleporter = param.asInteger() != 0; - messageResult = 1; - break; - case 0x4001: - case 0x4800: - startWalkToX(param.asPoint().x, false); - break; - case 0x4004: - if (_isSittingInTeleporter) - GotoState(&Klaymen::stSitIdleTeleporter); - else - GotoState(&Klaymen::stTryStandIdle); - break; - case 0x4803: - GotoState(&Klaymen::stFallSkipJump); - break; - case 0x4812: - if (param.asInteger() == 2) - GotoState(&Klaymen::stPickUpNeedle); - else if (param.asInteger() == 1) - GotoState(&Klaymen::stPickUpTube); - else - GotoState(&Klaymen::stPickUpGeneric); - break; - case 0x4817: - setDoDeltaX(param.asInteger()); - gotoNextStateExt(); - break; - case 0x481B: - if (param.asPoint().y != 0) - startWalkToXDistance(param.asPoint().y, param.asPoint().x); - else - startWalkToAttachedSpriteXDistance(param.asPoint().x); - break; - case 0x481D: - if (_isSittingInTeleporter) { - GotoState(&Klaymen::stTurnToUseInTeleporter); - } - break; - case 0x481E: - if (_isSittingInTeleporter) - GotoState(&Klaymen::stReturnFromUseInTeleporter); - break; - case 0x481F: - if (param.asInteger() == 1) - GotoState(&Klaymen::stWonderAboutAfter); - else if (param.asInteger() == 0) - GotoState(&Klaymen::stWonderAboutHalf); - else if (param.asInteger() == 4) - GotoState(&Klaymen::stTurnAwayFromUse); - else if (param.asInteger() == 3) - GotoState(&Klaymen::stTurnToUseHalf); - else - GotoState(&Klaymen::stWonderAbout); - break; - case 0x4834: - GotoState(&Klaymen::stStepOver); - break; - case 0x4835: - sendMessage(_parentScene, 0x2000, 1); - _isSittingInTeleporter = true; - GotoState(&Klaymen::stSitInTeleporter); - break; - case 0x4836: - sendMessage(_parentScene, 0x2000, 0); - _isSittingInTeleporter = false; - GotoState(&Klaymen::stGetUpFromTeleporter); - break; - case 0x483D: - teleporterAppear(0x5E0A4905); - break; - case 0x483E: - teleporterDisappear(0xD86E4477); - break; - } - return messageResult; -} - -KmScene1901::KmScene1901(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) - : Klaymen(vm, parentScene, x, y) { - - // Empty -} - -uint32 KmScene1901::xHandleMessage(int messageNum, const MessageParam ¶m) { - switch (messageNum) { - case 0x4001: - case 0x4800: - startWalkToX(param.asPoint().x, false); - break; - case 0x4004: - GotoState(&Klaymen::stTryStandIdle); - break; - case 0x4817: - setDoDeltaX(param.asInteger()); - gotoNextStateExt(); - break; - case 0x481D: - GotoState(&Klaymen::stTurnToUse); - break; - case 0x481E: - GotoState(&Klaymen::stReturnFromUse); - break; - case 0x482D: - setDoDeltaX(_x > (int16)param.asInteger() ? 1 : 0); - gotoNextStateExt(); - break; - case 0x483F: - startSpecialWalkRight(param.asInteger()); - break; - case 0x4840: - startSpecialWalkLeft(param.asInteger()); - break; - } - return 0; -} - -KmScene2001::KmScene2001(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) - : Klaymen(vm, parentScene, x, y) { - - // Empty -} - -uint32 KmScene2001::xHandleMessage(int messageNum, const MessageParam ¶m) { - uint32 messageResult = 0; - switch (messageNum) { - case 0x2000: - _isSittingInTeleporter = param.asInteger() != 0; - messageResult = 1; - break; - case 0x4001: - case 0x4800: - startWalkToX(param.asPoint().x, false); - break; - case 0x4004: - if (_isSittingInTeleporter) - GotoState(&Klaymen::stSitIdleTeleporter); - else - GotoState(&Klaymen::stTryStandIdle); - break; - case 0x4804: - if (param.asInteger() != 0) { - _destX = param.asInteger(); - GotoState(&Klaymen::stWalkingFirst); - } else - GotoState(&Klaymen::stPeekWall); - break; - case 0x4817: - setDoDeltaX(param.asInteger()); - gotoNextStateExt(); - break; - case 0x481D: - if (_isSittingInTeleporter) - GotoState(&Klaymen::stTurnToUseInTeleporter); - break; - case 0x481E: - if (_isSittingInTeleporter) - GotoState(&Klaymen::stReturnFromUseInTeleporter); - break; - case 0x4834: - GotoState(&Klaymen::stStepOver); - break; - case 0x4835: - sendMessage(_parentScene, 0x2000, 1); - _isSittingInTeleporter = true; - GotoState(&Klaymen::stSitInTeleporter); - break; - case 0x4836: - sendMessage(_parentScene, 0x2000, 0); - _isSittingInTeleporter = false; - GotoState(&Klaymen::stGetUpFromTeleporter); - break; - case 0x483D: - teleporterAppear(0xBE68CC54); - break; - case 0x483E: - teleporterDisappear(0x18AB4ED4); - break; - } - return messageResult; -} - -KmScene2101::KmScene2101(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) - : Klaymen(vm, parentScene, x, y) { - - // Empty -} - -uint32 KmScene2101::xHandleMessage(int messageNum, const MessageParam ¶m) { - uint32 messageResult = 0; - switch (messageNum) { - case 0x2000: - _isSittingInTeleporter = param.asInteger() != 0; - messageResult = 1; - break; - case 0x4001: - case 0x4800: - startWalkToX(param.asPoint().x, false); - break; - case 0x4004: - if (_isSittingInTeleporter) - GotoState(&Klaymen::stSitIdleTeleporter); - else - GotoState(&Klaymen::stTryStandIdle); - break; - case 0x4811: - GotoState(&Klaymen::stHitByDoor); - break; - case 0x4812: - if (param.asInteger() == 2) - GotoState(&Klaymen::stPickUpNeedle); - else if (param.asInteger() == 1) - GotoState(&Klaymen::stPickUpTube); - else - GotoState(&Klaymen::stPickUpGeneric); - break; - case 0x4816: - if (param.asInteger() == 1) - GotoState(&Klaymen::stPressButton); - else if (param.asInteger() == 2) - GotoState(&Klaymen::stPressFloorButton); - else - GotoState(&Klaymen::stPressButtonSide); - break; - case 0x4817: - setDoDeltaX(param.asInteger()); - gotoNextStateExt(); - break; - case 0x481B: - if (param.asPoint().y != 0) - startWalkToXDistance(param.asPoint().y, param.asPoint().x); - else - startWalkToAttachedSpriteXDistance(param.asPoint().x); - break; - case 0x481D: - if (_isSittingInTeleporter) - GotoState(&Klaymen::stTurnToUseInTeleporter); - break; - case 0x481E: - if (_isSittingInTeleporter) - GotoState(&Klaymen::stReturnFromUseInTeleporter); - break; - case 0x4834: - GotoState(&Klaymen::stStepOver); - break; - case 0x4835: - sendMessage(_parentScene, 0x2000, 1); - _isSittingInTeleporter = true; - GotoState(&Klaymen::stSitInTeleporter); - break; - case 0x4836: - sendMessage(_parentScene, 0x2000, 0); - _isSittingInTeleporter = false; - GotoState(&Klaymen::stGetUpFromTeleporter); - break; - case 0x483D: - teleporterAppear(0xFF290E30); - break; - case 0x483E: - teleporterDisappear(0x9A28CA1C); - break; - } - return messageResult; -} - -KmScene2201::KmScene2201(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y, NRect *clipRects, int clipRectsCount) - : Klaymen(vm, parentScene, x, y) { - - _surface->setClipRects(clipRects, clipRectsCount); - _dataResource.load(0x04104242); -} - -uint32 KmScene2201::xHandleMessage(int messageNum, const MessageParam ¶m) { - switch (messageNum) { - case 0x4001: - case 0x4800: - startWalkToX(param.asPoint().x, false); - break; - case 0x4004: - GotoState(&Klaymen::stTryStandIdle); - break; - case 0x4812: - GotoState(&Klaymen::stPickUpGeneric); - break; - case 0x4816: - if (param.asInteger() == 0) - GotoState(&Klaymen::stPressButtonSide); - break; - case 0x4817: - setDoDeltaX(param.asInteger() ? 1 : 0); - gotoNextStateExt(); - break; - case 0x4818: - startWalkToX(_dataResource.getPoint(param.asInteger()).x, false); - break; - case 0x481B: - if (param.asPoint().y != 0) - startWalkToXDistance(param.asPoint().y, param.asPoint().x); - else - startWalkToAttachedSpriteXDistance(param.asPoint().x); - break; - case 0x481D: - GotoState(&Klaymen::stTurnToUse); - break; - case 0x481E: - GotoState(&Klaymen::stReturnFromUse); - break; - case 0x482D: - setDoDeltaX(_x > (int16)param.asInteger() ? 1 : 0); - gotoNextStateExt(); - break; - case 0x482E: - if (param.asInteger() == 1) - GotoState(&Klaymen::stWalkToFrontNoStep); - else - GotoState(&Klaymen::stWalkToFront); - break; - case 0x482F: - if (param.asInteger() == 1) - GotoState(&Klaymen::stTurnToFront); - else - GotoState(&Klaymen::stTurnToBack); - break; - case 0x483F: - startSpecialWalkRight(param.asInteger()); - break; - case 0x4840: - startSpecialWalkLeft(param.asInteger()); - break; - } - return 0; -} - -KmScene2203::KmScene2203(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) - : Klaymen(vm, parentScene, x, y) { - - // Empty -} - -uint32 KmScene2203::xHandleMessage(int messageNum, const MessageParam ¶m) { - switch (messageNum) { - case 0x4001: - case 0x4800: - startWalkToX(param.asPoint().x, false); - break; - case 0x4004: - GotoState(&Klaymen::stTryStandIdle); - break; - case 0x4812: - if (param.asInteger() == 2) - GotoState(&Klaymen::stPickUpNeedle); - else if (param.asInteger() == 1) - GotoState(&Klaymen::stPickUpTube); - else - GotoState(&Klaymen::stPickUpGeneric); - break; - case 0x4816: - if (param.asInteger() == 1) - GotoState(&Klaymen::stPressButton); - else if (param.asInteger() == 2) - GotoState(&Klaymen::stPressFloorButton); - else - GotoState(&Klaymen::stPressButtonSide); - break; - case 0x4817: - setDoDeltaX(param.asInteger()); - gotoNextStateExt(); - break; - case 0x4818: - startWalkToX(_dataResource.getPoint(param.asInteger()).x, false); - break; - case 0x4819: - GotoState(&Klaymen::stClayDoorOpen); - break; - case 0x481A: - GotoState(&Klaymen::stInsertDisk); - break; - case 0x481B: - if (param.asPoint().y != 0) - startWalkToXDistance(param.asPoint().y, param.asPoint().x); - else - startWalkToAttachedSpriteXDistance(param.asPoint().x); - break; - case 0x481D: - GotoState(&Klaymen::stTurnToUse); - break; - case 0x481E: - GotoState(&Klaymen::stReturnFromUse); - break; - case 0x482D: - setDoDeltaX(_x > (int16)param.asInteger() ? 1 : 0); - gotoNextStateExt(); - break; - case 0x483F: - startSpecialWalkRight(param.asInteger()); - break; - case 0x4840: - startSpecialWalkLeft(param.asInteger()); - break; - } - return 0; -} - -KmScene2205::KmScene2205(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) - : Klaymen(vm, parentScene, x, y) { - - // Empty -} - -void KmScene2205::xUpdate() { - setGlobalVar(V_KLAYMEN_FRAMEINDEX, _currFrameIndex); -} - -uint32 KmScene2205::xHandleMessage(int messageNum, const MessageParam ¶m) { - switch (messageNum) { - case 0x4001: - case 0x4800: - startWalkToX(param.asPoint().x, false); - break; - case 0x4004: - GotoState(&Klaymen::stTryStandIdle); - break; - case 0x4804: - if (param.asInteger() != 0) { - _destX = param.asInteger(); - GotoState(&Klaymen::stStartWalkingResume); - } else - GotoState(&Klaymen::stPeekWall); - break; - case 0x4816: - if (param.asInteger() == 0) - GotoState(&Klaymen::stPressButtonSide); - break; - case 0x4817: - setDoDeltaX(param.asInteger()); - gotoNextStateExt(); - break; - case 0x4818: - startWalkToX(_dataResource.getPoint(param.asInteger()).x, false); - break; - case 0x483F: - startSpecialWalkRight(param.asInteger()); - break; - case 0x4840: - startSpecialWalkLeft(param.asInteger()); - break; - } - return 0; -} - -KmScene2206::KmScene2206(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) - : Klaymen(vm, parentScene, x, y) { - - _walkResumeFrameIncr = 1; - _vm->_soundMan->addSound(0x80101800, 0xD3B02847); -} - -KmScene2206::~KmScene2206() { - _vm->_soundMan->deleteSoundGroup(0x80101800); -} - -void KmScene2206::xUpdate() { - setGlobalVar(V_KLAYMEN_FRAMEINDEX, _currFrameIndex); -} - -uint32 KmScene2206::xHandleMessage(int messageNum, const MessageParam ¶m) { - switch (messageNum) { - case 0x4001: - case 0x4800: - startWalkToX(param.asPoint().x, false); - break; - case 0x4004: - GotoState(&Klaymen::stTryStandIdle); - break; - case 0x4803: - GotoState(&Klaymen::stRidePlatformDown); - break; - case 0x4804: - if (param.asInteger() != 0) { - _destX = param.asInteger(); - GotoState(&Klaymen::stStartWalkingResume); - } else - GotoState(&Klaymen::stPeekWall); - break; - case 0x4812: - if (param.asInteger() == 1) - GotoState(&Klaymen::stPickUpTube); - else - GotoState(&Klaymen::stPickUpGeneric); - break; - case 0x4816: - if (param.asInteger() == 1) - GotoState(&Klaymen::stPressButton); - else if (param.asInteger() == 2) - GotoState(&Klaymen::stPressFloorButton); - else - GotoState(&Klaymen::stPressButtonSide); - break; - case 0x4817: - setDoDeltaX(param.asInteger()); - gotoNextStateExt(); - break; - case 0x481B: - if (param.asPoint().y != 0) - startWalkToXDistance(param.asPoint().y, param.asPoint().x); - else - startWalkToAttachedSpriteXDistance(param.asPoint().x); - break; - case 0x481F: - if (param.asInteger() == 0) - GotoState(&Klaymen::stWonderAboutHalf); - else if (param.asInteger() == 1) - GotoState(&Klaymen::stWonderAboutAfter); - else if (param.asInteger() == 3) - GotoState(&Klaymen::stTurnToUseHalf); - else if (param.asInteger() == 4) - GotoState(&Klaymen::stTurnAwayFromUse); - else - GotoState(&Klaymen::stWonderAbout); - break; - case 0x482D: - setDoDeltaX(_x > (int16)param.asInteger() ? 1 : 0); - gotoNextStateExt(); - break; - case 0x482E: - if (param.asInteger() == 1) - GotoState(&Klaymen::stWalkToFrontNoStep); - else - GotoState(&Klaymen::stWalkToFront); - break; - case 0x482F: - if (param.asInteger() == 1) - GotoState(&Klaymen::stTurnToFront); - else - GotoState(&Klaymen::stTurnToBack); - break; - case 0x4837: - stopWalking(); - break; - case 0x483F: - startSpecialWalkRight(param.asInteger()); - break; - case 0x4840: - startSpecialWalkLeft(param.asInteger()); - break; - } - return 0; -} - -KmScene2207::KmScene2207(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) - : Klaymen(vm, parentScene, x, y) { - - // Empty -} - -uint32 KmScene2207::xHandleMessage(int messageNum, const MessageParam ¶m) { - switch (messageNum) { - case 0x2001: - GotoState(&Klaymen::stRidePlatform); - break; - case 0x2005: - suRidePlatform(); - GotoState(&Klaymen::stTryStandIdle); - break; - case 0x4001: - case 0x4800: - startWalkToX(param.asPoint().x, false); - break; - case 0x4004: - GotoState(&Klaymen::stTryStandIdle); - break; - case 0x480D: - GotoState(&Klaymen::stInteractLever); - break; - case 0x4812: - GotoState(&Klaymen::stPickUpGeneric); - break; - case 0x4816: - if (param.asInteger() == 1) - GotoState(&Klaymen::stPressButton); - else if (param.asInteger() == 2) - GotoState(&Klaymen::stPressFloorButton); - else - GotoState(&Klaymen::stPressButtonSide); - break; - case 0x4817: - setDoDeltaX(param.asInteger()); - gotoNextStateExt(); - break; - case 0x481B: - if (param.asPoint().y != 0) - startWalkToXDistance(param.asPoint().y, param.asPoint().x); - else - startWalkToAttachedSpriteXDistance(param.asPoint().x); - break; - case 0x4827: - GotoState(&Klaymen::stReleaseLever); - break; - case 0x482D: - setDoDeltaX(_x > (int16)param.asInteger() ? 1 : 0); - gotoNextStateExt(); - break; - case 0x483F: - startSpecialWalkRight(param.asInteger()); - break; - case 0x4840: - startSpecialWalkLeft(param.asInteger()); - break; - } - return 0; -} - -KmScene2242::KmScene2242(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) - : Klaymen(vm, parentScene, x, y) { - - // Empty -} - -void KmScene2242::xUpdate() { - setGlobalVar(V_KLAYMEN_FRAMEINDEX, _currFrameIndex); -} - -uint32 KmScene2242::xHandleMessage(int messageNum, const MessageParam ¶m) { - switch (messageNum) { - case 0x4001: - case 0x4800: - startWalkToX(param.asPoint().x, false); - break; - case 0x4004: - GotoState(&Klaymen::stTryStandIdle); - break; - case 0x4804: - if (param.asInteger() != 0) { - _destX = param.asInteger(); - GotoState(&Klaymen::stStartWalkingResume); - } else - GotoState(&Klaymen::stPeekWall); - break; - case 0x4812: - if (param.asInteger() == 2) - GotoState(&Klaymen::stPickUpNeedle); - else if (param.asInteger() == 1) - GotoState(&Klaymen::stPickUpTube); - else - GotoState(&Klaymen::stPickUpGeneric); - break; - case 0x4817: - setDoDeltaX(param.asInteger()); - gotoNextStateExt(); - break; - case 0x481B: - if (param.asPoint().y != 0) - startWalkToXDistance(param.asPoint().y, param.asPoint().x); - else - startWalkToAttachedSpriteXDistance(param.asPoint().x); - break; - case 0x481F: - if (param.asInteger() == 0) - GotoState(&Klaymen::stWonderAboutHalf); - else if (param.asInteger() == 1) - GotoState(&Klaymen::stWonderAboutAfter); - else if (param.asInteger() == 3) - GotoState(&Klaymen::stTurnToUseHalf); - else if (param.asInteger() == 4) - GotoState(&Klaymen::stTurnAwayFromUse); - else - GotoState(&Klaymen::stWonderAbout); - break; - case 0x482D: - setDoDeltaX(_x > (int16)param.asInteger() ? 1 : 0); - gotoNextStateExt(); - break; - case 0x4837: - stopWalking(); - break; - } - return 0; -} - -KmHallOfRecords::KmHallOfRecords(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) - : Klaymen(vm, parentScene, x, y) { - // Empty -} - -void KmHallOfRecords::xUpdate() { - setGlobalVar(V_KLAYMEN_FRAMEINDEX, _currFrameIndex); -} - -uint32 KmHallOfRecords::xHandleMessage(int messageNum, const MessageParam ¶m) { - switch (messageNum) { - case 0x4001: - case 0x4800: - startWalkToX(param.asPoint().x, false); - break; - case 0x4004: - GotoState(&Klaymen::stTryStandIdle); - break; - case 0x4804: - if (param.asInteger() != 0) { - _destX = param.asInteger(); - GotoState(&Klaymen::stStartWalkingResume); - } else - GotoState(&Klaymen::stPeekWall); - break; - case 0x4817: - setDoDeltaX(param.asInteger()); - gotoNextStateExt(); - break; - case 0x481F: - if (param.asInteger() == 0) - GotoState(&Klaymen::stWonderAboutHalf); - else if (param.asInteger() == 1) - GotoState(&Klaymen::stWonderAboutAfter); - else if (param.asInteger() == 3) - GotoState(&Klaymen::stTurnToUseHalf); - else if (param.asInteger() == 4) - GotoState(&Klaymen::stTurnAwayFromUse); - else - GotoState(&Klaymen::stWonderAbout); - break; - case 0x482D: - setDoDeltaX(_x > (int16)param.asInteger() ? 1 : 0); - gotoNextStateExt(); - break; - case 0x4837: - stopWalking(); - break; - } - return 0; -} - -KmScene2247::KmScene2247(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) - : Klaymen(vm, parentScene, x, y) { - - // Empty -} - -void KmScene2247::xUpdate() { - setGlobalVar(V_KLAYMEN_FRAMEINDEX, _currFrameIndex); -} - -uint32 KmScene2247::xHandleMessage(int messageNum, const MessageParam ¶m) { - switch (messageNum) { - case 0x4001: - case 0x4800: - startWalkToX(param.asPoint().x, false); - break; - case 0x4004: - GotoState(&Klaymen::stTryStandIdle); - break; - case 0x4804: - if (param.asInteger() != 0) { - _destX = param.asInteger(); - GotoState(&Klaymen::stStartWalkingResume); - } else - GotoState(&Klaymen::stPeekWall); - break; - case 0x4817: - setDoDeltaX(param.asInteger()); - gotoNextStateExt(); - break; - case 0x481F: - if (param.asInteger() == 0) - GotoState(&Klaymen::stWonderAboutHalf); - else if (param.asInteger() == 1) - GotoState(&Klaymen::stWonderAboutAfter); - else if (param.asInteger() == 3) - GotoState(&Klaymen::stTurnToUseHalf); - else if (param.asInteger() == 4) - GotoState(&Klaymen::stTurnAwayFromUse); - else - GotoState(&Klaymen::stWonderAbout); - break; - case 0x482D: - setDoDeltaX(_x > (int16)param.asInteger() ? 1 : 0); - gotoNextStateExt(); - break; - case 0x4837: - stopWalking(); - break; - } - return 0; -} - -KmScene2401::KmScene2401(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) - : Klaymen(vm, parentScene, x, y) { - - // Empty -} - -uint32 KmScene2401::xHandleMessage(int messageNum, const MessageParam ¶m) { - uint32 messageResult = 0; - switch (messageNum) { - case 0x4001: - case 0x4800: - startWalkToX(param.asPoint().x, false); - break; - case 0x4004: - GotoState(&Klaymen::stTryStandIdle); - break; - case 0x4816: - if (param.asInteger() == 1) - GotoState(&Klaymen::stPressButton); - else if (param.asInteger() == 2) - GotoState(&Klaymen::stPressFloorButton); - else - GotoState(&Klaymen::stPressButtonSide); - break; - case 0x4817: - setDoDeltaX(param.asInteger()); - gotoNextStateExt(); - break; - case 0x481B: - if (param.asPoint().y != 0) - startWalkToXDistance(param.asPoint().y, param.asPoint().x); - else - startWalkToAttachedSpriteXDistance(param.asPoint().x); - break; - case 0x481F: - if (param.asInteger() == 1) - GotoState(&Klaymen::stTurnAwayFromUse); - else if (param.asInteger() == 0) - GotoState(&Klaymen::stTurnToUseHalf); - else - GotoState(&Klaymen::stWonderAbout); - break; - case 0x482D: - setDoDeltaX(_x > (int16)param.asInteger() ? 1 : 0); - gotoNextStateExt(); - break; - case 0x482E: - if (param.asInteger() == 1) - GotoState(&Klaymen::stWalkToFrontNoStep); - else - GotoState(&Klaymen::stWalkToFront); - break; - case 0x482F: - if (param.asInteger() == 1) - GotoState(&Klaymen::stTurnToFront); - else - GotoState(&Klaymen::stTurnToBack); - break; - case 0x4832: - GotoState(&Klaymen::stUseTube); - break; - case 0x4833: - if (param.asInteger() == 1) - GotoState(&Klaymen::stWonderAbout); - else { - _spitPipeIndex = sendMessage(_parentScene, 0x2000, 0); - GotoState(&Klaymen::stTrySpitIntoPipe); - } - break; - case 0x483F: - startSpecialWalkRight(param.asInteger()); - break; - case 0x4840: - startSpecialWalkLeft(param.asInteger()); - break; - } - return messageResult; -} - -KmScene2402::KmScene2402(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) - : Klaymen(vm, parentScene, x, y) { - - // Empty -} - -uint32 KmScene2402::xHandleMessage(int messageNum, const MessageParam ¶m) { - uint32 messageResult = 0; - switch (messageNum) { - case 0x4001: - case 0x4800: - startWalkToX(param.asPoint().x, false); - break; - case 0x4004: - if (!getGlobalVar(V_TV_JOKE_TOLD)) - GotoState(&Klaymen::stStandWonderAbout); - else - GotoState(&Klaymen::stTryStandIdle); - break; - case 0x4804: - if (param.asInteger() != 0) { - _destX = param.asInteger(); - GotoState(&Klaymen::stWalkingFirst); - } else - GotoState(&Klaymen::stPeekWall); - break; - case 0x4812: - GotoState(&Klaymen::stPickUpGeneric); - break; - case 0x4816: - if (param.asInteger() == 1) - GotoState(&Klaymen::stPressButton); - else if (param.asInteger() == 2) - GotoState(&Klaymen::stPressFloorButton); - else - GotoState(&Klaymen::stPressButtonSide); - break; - case 0x4817: - setDoDeltaX(param.asInteger()); - gotoNextStateExt(); - break; - case 0x481B: - if (param.asPoint().y != 0) - startWalkToXDistance(param.asPoint().y, param.asPoint().x); - else - startWalkToAttachedSpriteXDistance(param.asPoint().x); - break; - case 0x481F: - if (param.asInteger() == 0) - GotoState(&Klaymen::stWonderAboutHalf); - else if (param.asInteger() == 1) - GotoState(&Klaymen::stWonderAboutAfter); - else if (param.asInteger() == 3) - GotoState(&Klaymen::stTurnToUseHalf); - else if (param.asInteger() == 4) - GotoState(&Klaymen::stTurnAwayFromUse); - else - GotoState(&Klaymen::stWonderAbout); - break; - case 0x483F: - startSpecialWalkRight(param.asInteger()); - break; - case 0x4840: - startSpecialWalkLeft(param.asInteger()); - break; - } - return messageResult; -} - -KmScene2403::KmScene2403(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) - : Klaymen(vm, parentScene, x, y) { - - // Empty -} - -uint32 KmScene2403::xHandleMessage(int messageNum, const MessageParam ¶m) { - uint32 messageResult = 0; - switch (messageNum) { - case 0x4001: - case 0x4800: - startWalkToX(param.asPoint().x, false); - break; - case 0x4004: - GotoState(&Klaymen::stTryStandIdle); - break; - case 0x480D: - GotoState(&Klaymen::stPullCord); - break; - case 0x4812: - GotoState(&Klaymen::stPickUpGeneric); - break; - case 0x4816: - if (param.asInteger() == 1) - GotoState(&Klaymen::stPressButton); - else if (param.asInteger() == 2) - GotoState(&Klaymen::stPressFloorButton); - else - GotoState(&Klaymen::stPressButtonSide); - break; - case 0x4817: - setDoDeltaX(param.asInteger()); - gotoNextStateExt(); - break; - case 0x481B: - if (param.asPoint().y != 0) - startWalkToXDistance(param.asPoint().y, param.asPoint().x); - else - startWalkToAttachedSpriteXDistance(param.asPoint().x); - break; - case 0x481F: - if (param.asInteger() == 0) - GotoState(&Klaymen::stWonderAboutHalf); - else if (param.asInteger() == 1) - GotoState(&Klaymen::stWonderAboutAfter); - else if (param.asInteger() == 3) - GotoState(&Klaymen::stTurnToUseHalf); - else if (param.asInteger() == 4) - GotoState(&Klaymen::stTurnAwayFromUse); - else - GotoState(&Klaymen::stWonderAbout); - break; - case 0x4820: - sendMessage(_parentScene, 0x2000, 0); - GotoState(&Klaymen::stContinueClimbLadderUp); - break; - case 0x4821: - sendMessage(_parentScene, 0x2000, 0); - _destY = param.asInteger(); - GotoState(&Klaymen::stStartClimbLadderDown); - break; - case 0x4822: - sendMessage(_parentScene, 0x2000, 0); - _destY = param.asInteger(); - GotoState(&Klaymen::stStartClimbLadderUp); - break; - case 0x4823: - sendMessage(_parentScene, 0x2001, 0); - GotoState(&Klaymen::stClimbLadderHalf); - break; - case 0x482D: - setDoDeltaX(_x > (int16)param.asInteger() ? 1 : 0); - gotoNextStateExt(); - break; - case 0x483F: - startSpecialWalkRight(param.asInteger()); - break; - case 0x4840: - startSpecialWalkLeft(param.asInteger()); - break; - } - return messageResult; -} - -KmScene2406::KmScene2406(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y, NRect *clipRects, int clipRectsCount) - : Klaymen(vm, parentScene, x, y) { - - _surface->setClipRects(clipRects, clipRectsCount); -} - -uint32 KmScene2406::xHandleMessage(int messageNum, const MessageParam ¶m) { - uint32 messageResult = 0; - switch (messageNum) { - case 0x4001: - case 0x4800: - startWalkToX(param.asPoint().x, false); - break; - case 0x4004: - GotoState(&Klaymen::stTryStandIdle); - break; - case 0x4804: - if (param.asInteger() != 0) { - _destX = param.asInteger(); - GotoState(&Klaymen::stWalkingFirst); - } else - GotoState(&Klaymen::stPeekWall); - break; - case 0x4812: - if (param.asInteger() == 2) - GotoState(&Klaymen::stPickUpNeedle); - else if (param.asInteger() == 1) - GotoState(&Klaymen::stPickUpTube); - else - GotoState(&Klaymen::stPickUpGeneric); - break; - case 0x4817: - setDoDeltaX(param.asInteger()); - gotoNextStateExt(); - break; - case 0x481A: - GotoState(&Klaymen::stInsertDisk); - break; - case 0x481B: - if (param.asPoint().y != 0) - startWalkToXDistance(param.asPoint().y, param.asPoint().x); - else - startWalkToAttachedSpriteXDistance(param.asPoint().x); - break; - case 0x481D: - GotoState(&Klaymen::stTurnToUse); - break; - case 0x481E: - GotoState(&Klaymen::stReturnFromUse); - break; - case 0x481F: - if (param.asInteger() == 0) - GotoState(&Klaymen::stWonderAboutHalf); - else if (param.asInteger() == 1) - GotoState(&Klaymen::stWonderAboutAfter); - else if (param.asInteger() == 3) - GotoState(&Klaymen::stTurnToUseHalf); - else if (param.asInteger() == 4) - GotoState(&Klaymen::stTurnAwayFromUse); - else - GotoState(&Klaymen::stWonderAbout); - break; - case 0x4820: - sendMessage(_parentScene, 0x2000, 0); - GotoState(&Klaymen::stContinueClimbLadderUp); - break; - case 0x4821: - sendMessage(_parentScene, 0x2000, 0); - _destY = param.asInteger(); - GotoState(&Klaymen::stStartClimbLadderDown); - break; - case 0x4822: - sendMessage(_parentScene, 0x2000, 0); - _destY = param.asInteger(); - GotoState(&Klaymen::stStartClimbLadderUp); - break; - case 0x4823: - sendMessage(_parentScene, 0x2001, 0); - GotoState(&Klaymen::stClimbLadderHalf); - break; - case 0x483F: - startSpecialWalkRight(param.asInteger()); - break; - case 0x4840: - startSpecialWalkLeft(param.asInteger()); - break; - } - return messageResult; -} - -KmScene2501::KmScene2501(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) - : Klaymen(vm, parentScene, x, y) { - - // Empty -} - -uint32 KmScene2501::xHandleMessage(int messageNum, const MessageParam ¶m) { - uint32 messageResult = 0; - switch (messageNum) { - case 0x2000: - _isSittingInTeleporter = param.asInteger() != 0; - messageResult = 1; - break; - case 0x4001: - case 0x4800: - startWalkToX(param.asPoint().x, false); - break; - case 0x4004: - if (_isSittingInTeleporter) - GotoState(&Klaymen::stSitIdleTeleporter); - else - GotoState(&Klaymen::stTryStandIdle); - break; - case 0x4817: - setDoDeltaX(param.asInteger()); - gotoNextStateExt(); - break; - case 0x481D: - if (_isSittingInTeleporter) - GotoState(&Klaymen::stTurnToUseInTeleporter); - break; - case 0x481E: - if (_isSittingInTeleporter) - GotoState(&Klaymen::stReturnFromUseInTeleporter); - break; - case 0x4834: - GotoState(&Klaymen::stStepOver); - break; - case 0x4835: - sendMessage(_parentScene, 0x2000, 1); - _isSittingInTeleporter = true; - GotoState(&Klaymen::stSitInTeleporter); - break; - case 0x4836: - sendMessage(_parentScene, 0x2000, 0); - _isSittingInTeleporter = false; - GotoState(&Klaymen::stGetUpFromTeleporter); - break; - } - return messageResult; -} - -KmScene2732::KmScene2732(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) - : Klaymen(vm, parentScene, x, y) { - - // Empty -} - -uint32 KmScene2732::xHandleMessage(int messageNum, const MessageParam ¶m) { - switch (messageNum) { - case 0x4804: - GotoState(&Klaymen::stPeekInside); - break; - case 0x483C: - GotoState(&Klaymen::stPeekInsideReturn); - break; - } - return 0; -} - -KmScene2801::KmScene2801(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) - : Klaymen(vm, parentScene, x, y) { - - // Empty -} - -uint32 KmScene2801::xHandleMessage(int messageNum, const MessageParam ¶m) { - switch (messageNum) { - case 0x4001: - case 0x4800: - startWalkToX(param.asPoint().x, false); - break; - case 0x4004: - GotoState(&Klaymen::stTryStandIdle); - break; - case 0x4812: - GotoState(&Klaymen::stPickUpGeneric); - break; - case 0x4817: - setDoDeltaX(param.asInteger()); - gotoNextStateExt(); - break; - case 0x481B: - if (param.asPoint().y != 0) - startWalkToXDistance(param.asPoint().y, param.asPoint().x); - else - startWalkToAttachedSpriteXDistance(param.asPoint().x); - break; - case 0x481D: - GotoState(&Klaymen::stTurnToUse); - break; - case 0x481E: - GotoState(&Klaymen::stReturnFromUse); - break; - case 0x481F: - if (param.asInteger() == 1) - GotoState(&Klaymen::stWonderAboutAfter); - else if (param.asInteger() == 0) - GotoState(&Klaymen::stWonderAboutHalf); - else if (param.asInteger() == 4) - GotoState(&Klaymen::stTurnAwayFromUse); - else if (param.asInteger() == 3) - GotoState(&Klaymen::stTurnToUseHalf); - else - GotoState(&Klaymen::stWonderAbout); - break; - case 0x482D: - setDoDeltaX(_x > (int16)param.asInteger() ? 1 : 0); - gotoNextStateExt(); - break; - case 0x482E: - if (param.asInteger() == 1) - GotoState(&Klaymen::stWalkToFrontNoStep); - else - GotoState(&Klaymen::stWalkToFront); - break; - case 0x482F: - if (param.asInteger() == 1) - GotoState(&Klaymen::stTurnToFront); - else - GotoState(&Klaymen::stTurnToBack); - break; - case 0x4837: - stopWalking(); - break; - } - return 0; -} - -KmScene2803::KmScene2803(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y, NRect *clipRects, int clipRectsCount) - : Klaymen(vm, parentScene, x, y) { - - _surface->setClipRects(clipRects, clipRectsCount); - _dataResource.load(0x00900849); -} - -uint32 KmScene2803::xHandleMessage(int messageNum, const MessageParam ¶m) { - switch (messageNum) { - case 0x4001: - case 0x4800: - startWalkToX(param.asPoint().x, false); - break; - case 0x4004: - GotoState(&Klaymen::stTryStandIdle); - break; - case 0x4803: - _destY = param.asInteger(); - GotoState(&Klaymen::stJumpToGrab); - break; - case 0x4804: - if (param.asInteger() == 3) - GotoState(&Klaymen::stFinishGrow); - break; - case 0x480D: - GotoState(&Klaymen::stPullCord); - break; - case 0x4817: - setDoDeltaX(param.asInteger()); - gotoNextStateExt(); - break; - case 0x4818: - startWalkToX(_dataResource.getPoint(param.asInteger()).x, false); - break; - case 0x481D: - GotoState(&Klaymen::stTurnToUse); - break; - case 0x481E: - GotoState(&Klaymen::stReturnFromUse); - break; - case 0x481F: - if (param.asInteger() == 1) - GotoState(&Klaymen::stWonderAboutAfter); - else - GotoState(&Klaymen::stWonderAboutHalf); - break; - case 0x482E: - GotoState(&Klaymen::stWalkToFront); - break; - case 0x482F: - GotoState(&Klaymen::stTurnToBack); - break; - case 0x4834: - GotoState(&Klaymen::stStepOver); - break; - case 0x4838: - GotoState(&Klaymen::stJumpToGrabRelease); - break; - } - return 0; -} - -KmScene2803Small::KmScene2803Small(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) - : Klaymen(vm, parentScene, x, y) { - - _dataResource.load(0x81120132); -} - -uint32 KmScene2803Small::xHandleMessage(int messageNum, const MessageParam ¶m) { - switch (messageNum) { - case 0x4001: - case 0x4800: - startWalkToXSmall(param.asPoint().x); - break; - case 0x4004: - GotoState(&Klaymen::stStandIdleSmall); - break; - case 0x4817: - setDoDeltaX(param.asInteger()); - gotoNextStateExt(); - break; - case 0x4818: - startWalkToXSmall(_dataResource.getPoint(param.asInteger()).x); - break; - case 0x481F: - if (param.asInteger() == 1) - GotoState(&Klaymen::stWonderAboutAfterSmall); - else if (param.asInteger() == 0) - GotoState(&Klaymen::stWonderAboutHalfSmall); - else - GotoState(&Klaymen::stWonderAboutSmall); - break; - case 0x482E: - if (param.asInteger() == 1) - GotoState(&Klaymen::stWalkToFrontNoStepSmall); - else if (param.asInteger() == 2) - GotoState(&Klaymen::stWalkToFront2Small); - else - GotoState(&Klaymen::stWalkToFrontSmall); - break; - case 0x482F: - if (param.asInteger() == 1) - GotoState(&Klaymen::stTurnToBackHalfSmall); - else if (param.asInteger() == 2) - GotoState(&Klaymen::stTurnToBackWalkSmall); - else - GotoState(&Klaymen::stTurnToBackSmall); - break; - case 0x4830: - GotoState(&Klaymen::stShrink); - break; - } - return 0; -} - -KmScene2805::KmScene2805(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) - : Klaymen(vm, parentScene, x, y) { - - // Empty -} - -uint32 KmScene2805::xHandleMessage(int messageNum, const MessageParam ¶m) { - uint32 messageResult = 0; - switch (messageNum) { - case 0x2000: - _isSittingInTeleporter = param.asInteger() != 0; - messageResult = 1; - break; - case 0x4001: - case 0x4800: - startWalkToX(param.asPoint().x, false); - break; - case 0x4004: - if (_isSittingInTeleporter) - GotoState(&Klaymen::stSitIdleTeleporter); - else - GotoState(&Klaymen::stTryStandIdle); - break; - case 0x4817: - setDoDeltaX(param.asInteger()); - gotoNextStateExt(); - break; - case 0x481D: - if (_isSittingInTeleporter) - GotoState(&Klaymen::stTurnToUseInTeleporter); - break; - case 0x481E: - if (_isSittingInTeleporter) - GotoState(&Klaymen::stReturnFromUseInTeleporter); - break; - case 0x4834: - GotoState(&Klaymen::stStepOver); - break; - case 0x4835: - sendMessage(_parentScene, 0x2000, 1); - _isSittingInTeleporter = true; - GotoState(&Klaymen::stSitInTeleporter); - break; - case 0x4836: - sendMessage(_parentScene, 0x2000, 0); - _isSittingInTeleporter = false; - GotoState(&Klaymen::stGetUpFromTeleporter); - break; - case 0x483D: - teleporterAppear(0xDE284B74); - break; - case 0x483E: - teleporterDisappear(0xD82A4094); - break; - } - return messageResult; -} - -KmScene2806::KmScene2806(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y, - bool needsLargeSurface, NRect *clipRects, uint clipRectsCount) - : Klaymen(vm, parentScene, x, y) { - - if (needsLargeSurface) { - NDimensions dimensions = _animResource.loadSpriteDimensions(0x2838C010); - delete _surface; - createSurface(1000, dimensions.width, dimensions.height); - loadSound(3, 0x58E0C341); - loadSound(4, 0x40A00342); - loadSound(5, 0xD0A1C348); - loadSound(6, 0x166FC6E0); - loadSound(7, 0x00018040); - } - - _dataResource.load(0x98182003); - _surface->setClipRects(clipRects, clipRectsCount); -} - -uint32 KmScene2806::xHandleMessage(int messageNum, const MessageParam ¶m) { - switch (messageNum) { - case 0x4001: - case 0x4800: - startWalkToX(param.asPoint().x, false); - break; - case 0x4004: - GotoState(&Klaymen::stTryStandIdle); - break; - case 0x4804: - startWalkToX(440, true); - break; - case 0x480D: - GotoState(&Klaymen::stPullCord); - break; - case 0x4816: - if (param.asInteger() == 0) - GotoState(&Klaymen::stPressButtonSide); - break; - case 0x4817: - setDoDeltaX(param.asInteger()); - gotoNextStateExt(); - break; - case 0x4818: - startWalkToX(_dataResource.getPoint(param.asInteger()).x, false); - break; - case 0x4831: - GotoState(&Klaymen::stGrow); - break; - case 0x4832: - if (param.asInteger() == 1) - GotoState(&Klaymen::stDrinkPotion); - else - GotoState(&Klaymen::stUseTube); - break; - } - return 0; -} - -KmScene2809::KmScene2809(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y, - bool needsLargeSurface, NRect *clipRects, uint clipRectsCount) - : Klaymen(vm, parentScene, x, y) { - - if (needsLargeSurface) { - NDimensions dimensions = _animResource.loadSpriteDimensions(0x2838C010); - delete _surface; - createSurface(1000, dimensions.width, dimensions.height); - loadSound(3, 0x58E0C341); - loadSound(4, 0x40A00342); - loadSound(5, 0xD0A1C348); - loadSound(6, 0x166FC6E0); - loadSound(7, 0x00018040); - } - - _dataResource.load(0x1830009A); - _surface->setClipRects(clipRects, clipRectsCount); -} - -uint32 KmScene2809::xHandleMessage(int messageNum, const MessageParam ¶m) { - switch (messageNum) { - case 0x4001: - case 0x4800: - startWalkToX(param.asPoint().x, false); - break; - case 0x4004: - GotoState(&Klaymen::stTryStandIdle); - break; - case 0x4804: - startWalkToX(226, true); - break; - case 0x480D: - GotoState(&Klaymen::stPullCord); - break; - case 0x4816: - if (param.asInteger() == 0) - GotoState(&Klaymen::stPressButtonSide); - break; - case 0x4817: - setDoDeltaX(param.asInteger()); - gotoNextStateExt(); - break; - case 0x4818: - startWalkToX(_dataResource.getPoint(param.asInteger()).x, false); - break; - case 0x4831: - GotoState(&Klaymen::stGrow); - break; - case 0x4832: - if (param.asInteger() == 1) - GotoState(&Klaymen::stDrinkPotion); - else - GotoState(&Klaymen::stUseTube); - break; - } - return 0; -} - -KmScene2810Small::KmScene2810Small(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) - : Klaymen(vm, parentScene, x, y) { - - // Empty -} - -uint32 KmScene2810Small::xHandleMessage(int messageNum, const MessageParam ¶m) { - switch (messageNum) { - case 0x4001: - case 0x4800: - startWalkToXSmall(param.asPoint().x); - break; - case 0x4004: - GotoState(&Klaymen::stStandIdleSmall); - break; - case 0x4817: - setDoDeltaX(param.asInteger()); - gotoNextStateExt(); - break; - case 0x4818: - startWalkToXSmall(_dataResource.getPoint(param.asInteger()).x); - break; - case 0x481F: - if (param.asInteger() == 1) - GotoState(&Klaymen::stWonderAboutAfterSmall); - else if (param.asInteger() == 0) - GotoState(&Klaymen::stWonderAboutHalfSmall); - else - GotoState(&Klaymen::stWonderAboutSmall); - break; - case 0x482E: - if (param.asInteger() == 1) - GotoState(&Klaymen::stWalkToFrontNoStepSmall); - else - GotoState(&Klaymen::stWalkToFrontSmall); - break; - case 0x482F: - if (param.asInteger() == 1) - GotoState(&Klaymen::stTurnToBackHalfSmall); - else - GotoState(&Klaymen::stTurnToBackSmall); - break; - case 0x4837: - stopWalking(); - break; - } - return 0; -} - -KmScene2810::KmScene2810(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y, NRect *clipRects, uint clipRectsCount) - : Klaymen(vm, parentScene, x, y) { - - _surface->setClipRects(clipRects, clipRectsCount); -} - -uint32 KmScene2810::xHandleMessage(int messageNum, const MessageParam ¶m) { - switch (messageNum) { - case 0x4001: - case 0x4800: - startWalkToX(param.asPoint().x, false); - break; - case 0x4004: - GotoState(&Klaymen::stTryStandIdle); - break; - case 0x4803: - _destY = param.asInteger(); - GotoState(&Klaymen::stJumpToGrab); - break; - case 0x4804: - if (param.asInteger() == 3) - GotoState(&Klaymen::stFinishGrow); - break; - case 0x4812: - GotoState(&Klaymen::stPickUpGeneric); - break; - case 0x4817: - setDoDeltaX(param.asInteger()); - gotoNextStateExt(); - break; - case 0x4818: - startWalkToX(_dataResource.getPoint(param.asInteger()).x, false); - break; - case 0x481B: - if (param.asPoint().y != 0) - startWalkToXDistance(param.asPoint().y, param.asPoint().x); - else - startWalkToAttachedSpriteXDistance(param.asPoint().x); - break; - case 0x481F: - if (param.asInteger() == 0) - GotoState(&Klaymen::stWonderAboutHalf); - else if (param.asInteger() == 1) - GotoState(&Klaymen::stWonderAboutAfter); - else if (param.asInteger() == 3) - GotoState(&Klaymen::stTurnToUseHalf); - else if (param.asInteger() == 4) - GotoState(&Klaymen::stTurnAwayFromUse); - else if (param.asInteger() == 5) - GotoState(&Klaymen::stTurnToUseExt); - else - GotoState(&Klaymen::stWonderAbout); - break; - case 0x4820: - sendMessage(_parentScene, 0x2000, 0); - GotoState(&Klaymen::stContinueClimbLadderUp); - break; - case 0x4821: - sendMessage(_parentScene, 0x2000, 0); - _destY = param.asInteger(); - GotoState(&Klaymen::stStartClimbLadderDown); - break; - case 0x4822: - sendMessage(_parentScene, 0x2000, 0); - _destY = param.asInteger(); - GotoState(&Klaymen::stStartClimbLadderUp); - break; - case 0x4823: - sendMessage(_parentScene, 0x2001, 0); - GotoState(&Klaymen::stClimbLadderHalf); - break; - case 0x4824: - sendMessage(_parentScene, 0x2000, 0); - _destY = _dataResource.getPoint(param.asInteger()).y; - GotoState(&Klaymen::stStartClimbLadderDown); - break; - case 0x4825: - sendMessage(_parentScene, 0x2000, 0); - _destY = _dataResource.getPoint(param.asInteger()).y; - GotoState(&Klaymen::stStartClimbLadderUp); - break; - case 0x482D: - setDoDeltaX(_x > (int16)param.asInteger() ? 1 : 0); - gotoNextStateExt(); - break; - case 0x4837: - stopWalking(); - break; - } - return 0; -} - -KmScene2812::KmScene2812(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) - : Klaymen(vm, parentScene, x, y) { - - // Empty -} - -uint32 KmScene2812::xHandleMessage(int messageNum, const MessageParam ¶m) { - switch (messageNum) { - case 0x4001: - case 0x4800: - startWalkToX(param.asPoint().x, false); - break; - case 0x4004: - GotoState(&Klaymen::stTryStandIdle); - break; - case 0x4805: - _destY = param.asInteger(); - GotoState(&Klaymen::stJumpToGrabFall); - break; - case 0x4812: - if (param.asInteger() == 2) - GotoState(&Klaymen::stPickUpNeedle); - else if (param.asInteger() == 1) - GotoState(&Klaymen::stPickUpTube); - else - GotoState(&Klaymen::stPickUpGeneric); - break; - case 0x4817: - setDoDeltaX(param.asInteger()); - gotoNextStateExt(); - break; - case 0x481A: - GotoState(&Klaymen::stInsertDisk); - break; - case 0x481B: - if (param.asPoint().y != 0) - startWalkToXDistance(param.asPoint().y, param.asPoint().x); - else - startWalkToAttachedSpriteXDistance(param.asPoint().x); - break; - case 0x481D: - GotoState(&Klaymen::stTurnToUse); - break; - case 0x481E: - GotoState(&Klaymen::stReturnFromUse); - break; - case 0x4820: - sendMessage(_parentScene, 0x2001, 0); - GotoState(&Klaymen::stContinueClimbLadderUp); - break; - case 0x4821: - sendMessage(_parentScene, 0x2001, 0); - _destY = param.asInteger(); - GotoState(&Klaymen::stStartClimbLadderDown); - break; - case 0x4822: - sendMessage(_parentScene, 0x2001, 0); - _destY = param.asInteger(); - GotoState(&Klaymen::stStartClimbLadderUp); - break; - case 0x4823: - sendMessage(_parentScene, 0x2002, 0); - GotoState(&Klaymen::stClimbLadderHalf); - break; - case 0x482D: - setDoDeltaX(_x > (int16)param.asInteger() ? 1 : 0); - gotoNextStateExt(); - break; - case 0x482E: - if (param.asInteger() == 1) - GotoState(&Klaymen::stWalkToFrontNoStep); - else - GotoState(&Klaymen::stWalkToFront); - break; - case 0x482F: - if (param.asInteger() == 1) - GotoState(&Klaymen::stTurnToFront); - else - GotoState(&Klaymen::stTurnToBack); - break; - case 0x483F: - startSpecialWalkRight(param.asInteger()); - break; - case 0x4840: - startSpecialWalkLeft(param.asInteger()); - break; - } - return 0; -} - } // End of namespace Neverhood diff --git a/engines/neverhood/klaymen.h b/engines/neverhood/klaymen.h index 9e461a9c9c..524bb9a9f2 100644 --- a/engines/neverhood/klaymen.h +++ b/engines/neverhood/klaymen.h @@ -33,7 +33,6 @@ namespace Neverhood { // TODO This code is horrible and weird and a lot of stuff needs renaming once a better name is found // TODO Also the methods should probably rearranged and be grouped together more consistently -class Klaymen; class Scene; const uint32 kKlaymenSpeedUpHash = 0x004A2148; @@ -67,29 +66,25 @@ public: void startIdleAnimation(uint32 fileHash, AnimationCb callback); void upIdleAnimation(); + // Idle animations - start void stIdlePickEar(); void evIdlePickEarDone(); - uint32 hmIdlePickEar(int messageNum, const MessageParam ¶m, Entity *sender); - void stIdleSpinHead(); - uint32 hmIdleSpinHead(int messageNum, const MessageParam ¶m, Entity *sender); - void stIdleArms(); void evIdleArmsDone(); - uint32 hmIdleArms(int messageNum, const MessageParam ¶m, Entity *sender); - void stIdleChest(); - uint32 hmIdleChest(int messageNum, const MessageParam ¶m, Entity *sender); - void stIdleHeadOff(); - uint32 hmIdleHeadOff(int messageNum, const MessageParam ¶m, Entity *sender); - void stIdleWonderAbout(); - void stIdleTeleporterHands(); - void stIdleTeleporterHands2(); + uint32 hmIdlePickEar(int messageNum, const MessageParam ¶m, Entity *sender); + uint32 hmIdleSpinHead(int messageNum, const MessageParam ¶m, Entity *sender); + uint32 hmIdleArms(int messageNum, const MessageParam ¶m, Entity *sender); + uint32 hmIdleChest(int messageNum, const MessageParam ¶m, Entity *sender); + uint32 hmIdleHeadOff(int messageNum, const MessageParam ¶m, Entity *sender); + // Idle animations - end + void stTryStandIdle(); void stStandAround(); void upStandIdle(); @@ -150,12 +145,6 @@ public: void stInsertKey(); uint32 hmInsertKey(int messageNum, const MessageParam ¶m, Entity *sender); - void stReadNote(); - uint32 hmReadNote(int messageNum, const MessageParam ¶m, Entity *sender); - - void stHitByDoor(); - uint32 hmHitByDoor(int messageNum, const MessageParam ¶m, Entity *sender); - void stPeekWall(); uint32 hmPeekWall(int messageNum, const MessageParam ¶m, Entity *sender); @@ -166,21 +155,8 @@ public: void upPeekWallBlink(); void stPeekWall1(); - void stPeekWall2(); - void stPullHammerLever(); - uint32 hmPullHammerLever(int messageNum, const MessageParam ¶m, Entity *sender); - - void stRidePlatformDown(); - void suRidePlatformDown(); - - void stCrashDown(); - void stCrashDownFinished(); - - void stShrink(); - uint32 hmShrink(int messageNum, const MessageParam ¶m, Entity *sender); - void stGrow(); uint32 hmGrow(int messageNum, const MessageParam ¶m, Entity *sender); @@ -203,11 +179,6 @@ public: void stLetGoOfLever(); void evLeverReleasedEvent(); - void stWakeUp(); - - void stSleeping(); - uint32 hmSleeping(int messageNum, const MessageParam ¶m, Entity *sender); - void stPressButton(); void stPressFloorButton(); void stPressButtonSide(); @@ -228,20 +199,6 @@ public: void stClimbLadderHalf(); uint32 hmClimbLadderHalf(int messageNum, const MessageParam ¶m, Entity *sender); - void setupJumpToRing(); - void stJumpToRing1(); - void stJumpToRing2(); - void stJumpToRing4(); - uint32 hmJumpToRing(int messageNum, const MessageParam ¶m, Entity *sender); - - void stHangOnRing(); - - void stJumpToRing3(); - uint32 hmJumpToRing3(int messageNum, const MessageParam ¶m, Entity *sender); - - void stHoldRing3(); - uint32 hmHoldRing3(int messageNum, const MessageParam ¶m, Entity *sender); - void stReleaseRing(); void stLandOnFeet(); @@ -272,24 +229,17 @@ public: void stSitIdleTeleporter(); void upSitIdleTeleporter(); - void stSitIdleTeleporterBlink(); - void stSitIdleTeleporterBlinkSecond(); void stTurnToUseInTeleporter(); - void stReturnFromUseInTeleporter(); - void stGetUpFromTeleporter(); void teleporterAppear(uint32 fileHash); void teleporterDisappear(uint32 fileHash); uint32 hmTeleporterAppearDisappear(int messageNum, const MessageParam ¶m, Entity *sender); - void stClayDoorOpen(); - uint32 hmClayDoorOpen(int messageNum, const MessageParam ¶m, Entity *sender); - void stFallSkipJump(); void suFallSkipJump(); @@ -298,15 +248,6 @@ public: uint32 hmMoveObject(int messageNum, const MessageParam ¶m, Entity *sender); void upMoveObject(); - void stCloseEyes(); - - void stTumbleHeadless(); - uint32 hmTumbleHeadless(int messageNum, const MessageParam ¶m, Entity *sender); - - void stFetchMatch(); - void stLightMatch(); - uint32 hmMatch(int messageNum, const MessageParam ¶m, Entity *sender); - void stHitByBoxingGlove(); uint32 hmHitByBoxingGlove(int messageNum, const MessageParam ¶m, Entity *sender); void evHitByBoxingGloveDone(); @@ -327,11 +268,6 @@ public: void stFinishGrow(); uint32 hmFinishGrow(int messageNum, const MessageParam ¶m, Entity *sender); - void stJumpToRingVenusFlyTrap(); - uint32 hmJumpToRingVenusFlyTrap(int messageNum, const MessageParam ¶m, Entity *sender); - - void stDropFromRing(); - void stStandIdleSpecial(); uint32 hmStandIdleSpecial(int messageNum, const MessageParam ¶m, Entity *sender); @@ -343,18 +279,9 @@ public: void suFallDown(); void upSpitOutFall(); - void stJumpAndFall(); - uint32 hmJumpAndFall(int messageNum, const MessageParam ¶m, Entity *sender); - void stFalling(); void stFallTouchdown(); - void stMoveVenusFlyTrap(); - void stContinueMovingVenusFlyTrap(); - uint32 hmMoveVenusFlyTrap(int messageNum, const MessageParam ¶m, Entity *sender); - uint32 hmFirstMoveVenusFlyTrap(int messageNum, const MessageParam ¶m, Entity *sender); - void evMoveVenusFlyTrapDone(); - void stPeekInside(); void stPeekInsideReturn(); void stPeekInsideBlink(); @@ -378,11 +305,6 @@ public: void setSoundFlag(bool value) { _soundFlag = value; } - void spitIntoPipe(); - void stTrySpitIntoPipe(); - void stContSpitIntoPipe(); - uint32 hmSpit(int messageNum, const MessageParam ¶m, Entity *sender); - void stRidePlatform(); void suRidePlatform(); void stPullLever(); @@ -432,13 +354,6 @@ protected: int _moveObjectCountdown; - bool _canSpitPipe; - bool _contSpitPipe; - bool _readyToSpit; - uint32 _spitPipeIndex; - uint32 _spitDestPipeIndex; - uint32 _spitContDestPipeIndex; - virtual void xUpdate(); virtual uint32 xHandleMessage(int messageNum, const MessageParam ¶m); @@ -459,311 +374,6 @@ protected: void enterIdleAnimation(uint idleAnimation); void walkAlongPathPoints(); - -}; - -class KmScene1001 : public Klaymen { -public: - KmScene1001(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); -protected: - uint32 xHandleMessage(int messageNum, const MessageParam ¶m); -}; - -class KmScene1002 : public Klaymen { -public: - KmScene1002(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); -protected: - void xUpdate(); - uint32 xHandleMessage(int messageNum, const MessageParam ¶m); -}; - -class KmScene1004 : public Klaymen { -public: - KmScene1004(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); -protected: - uint32 xHandleMessage(int messageNum, const MessageParam ¶m); -}; - -class KmScene1109 : public Klaymen { -public: - KmScene1109(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); -protected: - uint32 xHandleMessage(int messageNum, const MessageParam ¶m); -}; - -class KmScene1201 : public Klaymen { -public: - KmScene1201(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); -protected: - uint32 xHandleMessage(int messageNum, const MessageParam ¶m); -}; - -class KmScene1303 : public Klaymen { -public: - KmScene1303(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); -protected: - uint32 xHandleMessage(int messageNum, const MessageParam ¶m); -}; - -class KmScene1304 : public Klaymen { -public: - KmScene1304(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); -protected: - uint32 xHandleMessage(int messageNum, const MessageParam ¶m); -}; - -class KmScene1305 : public Klaymen { -public: - KmScene1305(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); -protected: - uint32 xHandleMessage(int messageNum, const MessageParam ¶m); -}; - -class KmScene1306 : public Klaymen { -public: - KmScene1306(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); -protected: - uint32 xHandleMessage(int messageNum, const MessageParam ¶m); -}; - -class KmScene1308 : public Klaymen { -public: - KmScene1308(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); -protected: - uint32 xHandleMessage(int messageNum, const MessageParam ¶m); -}; - -class KmScene1401 : public Klaymen { -public: - KmScene1401(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); -protected: - uint32 xHandleMessage(int messageNum, const MessageParam ¶m); -}; - -class KmScene1402 : public Klaymen { -public: - KmScene1402(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); -protected: - uint32 xHandleMessage(int messageNum, const MessageParam ¶m); -}; - -class KmScene1403 : public Klaymen { -public: - KmScene1403(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); -protected: - uint32 xHandleMessage(int messageNum, const MessageParam ¶m); -}; - -class KmScene1404 : public Klaymen { -public: - KmScene1404(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); -protected: - uint32 xHandleMessage(int messageNum, const MessageParam ¶m); -}; - -class KmScene1608 : public Klaymen { -public: - KmScene1608(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); -protected: - uint32 xHandleMessage(int messageNum, const MessageParam ¶m); -}; - -class KmScene1705 : public Klaymen { -public: - KmScene1705(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); -protected: - uint32 xHandleMessage(int messageNum, const MessageParam ¶m); -}; - -class KmScene1901 : public Klaymen { -public: - KmScene1901(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); -protected: - uint32 xHandleMessage(int messageNum, const MessageParam ¶m); -}; - -class KmScene2001 : public Klaymen { -public: - KmScene2001(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); -protected: - uint32 xHandleMessage(int messageNum, const MessageParam ¶m); -}; - -class KmScene2101 : public Klaymen { -public: - KmScene2101(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); -protected: - uint32 xHandleMessage(int messageNum, const MessageParam ¶m); -}; - -class KmScene2201 : public Klaymen { -public: - KmScene2201(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y, NRect *clipRects, int clipRectsCount); -protected: - uint32 xHandleMessage(int messageNum, const MessageParam ¶m); -}; - -class KmScene2203 : public Klaymen { -public: - KmScene2203(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); -protected: - uint32 xHandleMessage(int messageNum, const MessageParam ¶m); -}; - -class KmScene2205 : public Klaymen { -public: - KmScene2205(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); -protected: - void xUpdate(); - uint32 xHandleMessage(int messageNum, const MessageParam ¶m); -}; - -class KmScene2206 : public Klaymen { -public: - KmScene2206(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); - ~KmScene2206(); -protected: - void xUpdate(); - uint32 xHandleMessage(int messageNum, const MessageParam ¶m); -}; - -class KmScene2207 : public Klaymen { -public: - KmScene2207(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); -protected: - uint32 xHandleMessage(int messageNum, const MessageParam ¶m); -}; - -class KmScene2242 : public Klaymen { -public: - KmScene2242(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); -protected: - void xUpdate(); - uint32 xHandleMessage(int messageNum, const MessageParam ¶m); -}; - -class KmHallOfRecords : public Klaymen { -public: - KmHallOfRecords(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); -protected: - void xUpdate(); - uint32 xHandleMessage(int messageNum, const MessageParam ¶m); -}; - -class KmScene2247 : public Klaymen { -public: - KmScene2247(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); -protected: - void xUpdate(); - uint32 xHandleMessage(int messageNum, const MessageParam ¶m); -}; - -class KmScene2401 : public Klaymen { -public: - KmScene2401(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); -protected: - uint32 xHandleMessage(int messageNum, const MessageParam ¶m); -}; - -class KmScene2402 : public Klaymen { -public: - KmScene2402(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); -protected: - uint32 xHandleMessage(int messageNum, const MessageParam ¶m); -}; - -class KmScene2403 : public Klaymen { -public: - KmScene2403(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); -protected: - uint32 xHandleMessage(int messageNum, const MessageParam ¶m); -}; - -class KmScene2406 : public Klaymen { -public: - KmScene2406(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y, NRect *clipRects, int clipRectsCount); -protected: - uint32 xHandleMessage(int messageNum, const MessageParam ¶m); -}; - -class KmScene2501 : public Klaymen { -public: - KmScene2501(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); -protected: - uint32 xHandleMessage(int messageNum, const MessageParam ¶m); -}; - -class KmScene2732 : public Klaymen { -public: - KmScene2732(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); -protected: - uint32 xHandleMessage(int messageNum, const MessageParam ¶m); -}; - -class KmScene2801 : public Klaymen { -public: - KmScene2801(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); -protected: - uint32 xHandleMessage(int messageNum, const MessageParam ¶m); -}; - -class KmScene2803 : public Klaymen { -public: - KmScene2803(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y, NRect *clipRects, int clipRectsCount); -protected: - uint32 xHandleMessage(int messageNum, const MessageParam ¶m); -}; - -class KmScene2803Small : public Klaymen { -public: - KmScene2803Small(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); -protected: - uint32 xHandleMessage(int messageNum, const MessageParam ¶m); -}; - -class KmScene2805 : public Klaymen { -public: - KmScene2805(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); -protected: - uint32 xHandleMessage(int messageNum, const MessageParam ¶m); -}; - -class KmScene2806 : public Klaymen { -public: - KmScene2806(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y, - bool needsLargeSurface, NRect *clipRects, uint clipRectsCount); -protected: - uint32 xHandleMessage(int messageNum, const MessageParam ¶m); -}; - -class KmScene2809 : public Klaymen { -public: - KmScene2809(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y, - bool needsLargeSurface, NRect *clipRects, uint clipRectsCount); -protected: - uint32 xHandleMessage(int messageNum, const MessageParam ¶m); -}; - -class KmScene2810Small : public Klaymen { -public: - KmScene2810Small(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); -protected: - uint32 xHandleMessage(int messageNum, const MessageParam ¶m); -}; - -class KmScene2810 : public Klaymen { -public: - KmScene2810(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y, - NRect *clipRects, uint clipRectsCount); -protected: - uint32 xHandleMessage(int messageNum, const MessageParam ¶m); -}; - -class KmScene2812 : public Klaymen { -public: - KmScene2812(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); -protected: - uint32 xHandleMessage(int messageNum, const MessageParam ¶m); }; } // End of namespace Neverhood diff --git a/engines/neverhood/module.mk b/engines/neverhood/module.mk index 052c830182..9c1220134c 100644 --- a/engines/neverhood/module.mk +++ b/engines/neverhood/module.mk @@ -15,27 +15,44 @@ MODULE_OBJS = \ microtiles.o \ module.o \ modules/module1000.o \ + modules/module1000_sprites.o \ modules/module1100.o \ + modules/module1100_sprites.o \ modules/module1200.o \ + modules/module1200_sprites.o \ modules/module1300.o \ + modules/module1300_sprites.o \ modules/module1400.o \ + modules/module1400_sprites.o \ modules/module1500.o \ modules/module1600.o \ + modules/module1600_sprites.o \ modules/module1700.o \ + modules/module1700_sprites.o \ modules/module1800.o \ modules/module1900.o \ + modules/module1900_sprites.o \ modules/module2000.o \ + modules/module2000_sprites.o \ modules/module2100.o \ + modules/module2100_sprites.o \ modules/module2200.o \ + modules/module2200_sprites.o \ modules/module2300.o \ modules/module2400.o \ + modules/module2400_sprites.o \ modules/module2500.o \ + modules/module2500_sprites.o \ modules/module2600.o \ + modules/module2600_sprites.o \ modules/module2700.o \ + modules/module2700_sprites.o \ modules/module2800.o \ modules/module2800_sprites.o \ modules/module2900.o \ + modules/module2900_sprites.o \ modules/module3000.o \ + modules/module3000_sprites.o \ mouse.o \ navigationscene.o \ neverhood.o \ diff --git a/engines/neverhood/modules/module1000.cpp b/engines/neverhood/modules/module1000.cpp index 14ce5f4347..534fb2ec2f 100644 --- a/engines/neverhood/modules/module1000.cpp +++ b/engines/neverhood/modules/module1000.cpp @@ -21,6 +21,7 @@ */ #include "neverhood/modules/module1000.h" +#include "neverhood/modules/module1000_sprites.h" namespace Neverhood { @@ -118,219 +119,6 @@ void Module1000::updateScene() { } } -// Scene1001 - -AsScene1001Door::AsScene1001Door(NeverhoodEngine *vm) - : AnimatedSprite(vm, 1100) { - - createSurface(800, 137, 242); - _x = 726; - _y = 440; - stShowIdleDoor(); - loadSound(1, 0xED403E03); - SetUpdateHandler(&AnimatedSprite::update); - SetMessageHandler(&AsScene1001Door::handleMessage); -} - -uint32 AsScene1001Door::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x2000: - hammerHitsDoor(); - break; - case 0x3002: - gotoNextState(); - break; - } - return 0; -} - -void AsScene1001Door::hammerHitsDoor() { - switch (getGlobalVar(V_DOOR_STATUS)) { - case 0: - case 1: - playSound(0, 0x65482F03); - startAnimation(0x624C0498, 1, 3); - NextState(&AsScene1001Door::stShowIdleDoor); - break; - case 2: - playSound(1); - startAnimation(0x624C0498, 6, 6); - NextState(&AsScene1001Door::stBustedDoorMove); - break; - default: - // Nothing - break; - } - incGlobalVar(V_DOOR_STATUS, 1); -} - -void AsScene1001Door::stShowIdleDoor() { - switch (getGlobalVar(V_DOOR_STATUS)) { - case 1: - startAnimation(0x624C0498, 4, -1); - _newStickFrameIndex = 4; - break; - case 2: - startAnimation(0x624C0498, 1, -1); - _newStickFrameIndex = 1; - break; - case 3: - stopAnimation(); - setVisible(false); - break; - default: - startAnimation(0x624C0498, 0, -1); - _newStickFrameIndex = 0; - break; - } -} - -void AsScene1001Door::stBustedDoorMove() { - setGlobalVar(V_DOOR_BUSTED, 1); - startAnimation(0x624C0498, 6, 6); - NextState(&AsScene1001Door::stBustedDoorGone); - _x = 30; -} - -void AsScene1001Door::stBustedDoorGone() { - playSound(0); - stopAnimation(); - setVisible(false); -} - -AsScene1001Hammer::AsScene1001Hammer(NeverhoodEngine *vm, Sprite *asDoor) - : AnimatedSprite(vm, 1100), _asDoor(asDoor) { - - _x = 547; - _y = 206; - createSurface(900, 177, 192); - startAnimation(0x022C90D4, -1, -1); - _newStickFrameIndex = STICK_LAST_FRAME; - SetUpdateHandler(&AnimatedSprite::update); - SetMessageHandler(&AsScene1001Hammer::handleMessage); -} - -uint32 AsScene1001Hammer::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x100D: - if (param.asInteger() == 0x00352100) - sendMessage(_asDoor, 0x2000, 0); - else if (param.asInteger() == 0x0A1A0109) - playSound(0, 0x66410886); - break; - case 0x2000: - startAnimation(0x022C90D4, 1, -1); - playSound(0, 0xE741020A); - _newStickFrameIndex = STICK_LAST_FRAME; - break; - } - return 0; -} - -AsScene1001Window::AsScene1001Window(NeverhoodEngine *vm) - : AnimatedSprite(vm, 1200) { - - _x = 320; - _y = 240; - createSurface(100, 66, 129); - startAnimation(0xC68C2299, 0, -1); - _newStickFrameIndex = 0; - SetUpdateHandler(&AnimatedSprite::update); - SetMessageHandler(&AsScene1001Window::handleMessage); -} - -uint32 AsScene1001Window::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x100D: - if (param.asInteger() == 0x0E0A1410) - playSound(0, 0x60803F10); - break; - case 0x2001: - startAnimation(0xC68C2299, 0, -1); - break; - case 0x3002: - SetMessageHandler(NULL); - setGlobalVar(V_WINDOW_OPEN, 1); - setVisible(false); - break; - } - return 0; -} - -AsScene1001Lever::AsScene1001Lever(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y, int deltaXType) - : AnimatedSprite(vm, 1100), _parentScene(parentScene) { - - createSurface(1010, 71, 73); - setDoDeltaX(deltaXType); - startAnimation(0x04A98C36, 0, -1); - _newStickFrameIndex = 0; - _x = x; - _y = y; - SetUpdateHandler(&AnimatedSprite::update); - SetMessageHandler(&AsScene1001Lever::handleMessage); -} - -uint32 AsScene1001Lever::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x100D: - if (param.asInteger() == 0x00C0C444) - sendMessage(_parentScene, 0x480F, 0); - else if (param.asInteger() == 0xC41A02C0) - playSound(0, 0x40581882); - break; - case 0x1011: - sendMessage(_parentScene, 0x4826, 0); - messageResult = 1; - break; - case 0x3002: - startAnimation(0x04A98C36, 0, -1); - _newStickFrameIndex = 0; - break; - case 0x480F: - startAnimation(0x04A98C36, 0, -1); - break; - case 0x482A: - sendMessage(_parentScene, 0x1022, 990); - break; - case 0x482B: - sendMessage(_parentScene, 0x1022, 1010); - break; - } - return messageResult; -} - -SsCommonButtonSprite::SsCommonButtonSprite(NeverhoodEngine *vm, Scene *parentScene, uint32 fileHash, int surfacePriority, uint32 soundFileHash) - : StaticSprite(vm, fileHash, surfacePriority), _parentScene(parentScene), _countdown(0) { - - _priority = 1100; - _soundFileHash = soundFileHash ? soundFileHash : 0x44141000; - setVisible(false); - SetUpdateHandler(&SsCommonButtonSprite::update); - SetMessageHandler(&SsCommonButtonSprite::handleMessage); -} - -void SsCommonButtonSprite::update() { - if (_countdown != 0 && (--_countdown) == 0) - setVisible(false); -} - -uint32 SsCommonButtonSprite::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x480B: - sendMessage(_parentScene, 0x480B, 0); - setVisible(true); - _countdown = 8; - playSound(0, _soundFileHash); - break; - } - return messageResult; -} - Scene1001::Scene1001(NeverhoodEngine *vm, Module *parentModule, int which) : Scene(vm, parentModule), _asDoor(NULL), _asWindow(NULL) { @@ -439,719 +227,6 @@ uint32 Scene1001::handleMessage(int messageNum, const MessageParam ¶m, Entit return messageResult; } -// Scene1002 - -AsScene1002Ring::AsScene1002Ring(NeverhoodEngine *vm, Scene *parentScene, bool isSpecial, int16 x, int16 y, int16 clipY1, bool isRingLow) - : AnimatedSprite(vm, 1100), _parentScene(parentScene), _isSpecial(isSpecial) { - - SetUpdateHandler(&AsScene1002Ring::update); - - if (_isSpecial) { - createSurface(990, 68, 314); - if (isRingLow) { - startAnimation(0x04103090, 0, -1); - SetMessageHandler(&AsScene1002Ring::hmRingHangingLow); - } else { - startAnimation(0xA85C4011, _vm->_rnd->getRandomNumber(15), -1); - SetMessageHandler(&AsScene1002Ring::hmRingIdle); - } - } else { - createSurface(990, 68, 138); - startAnimation(0xA85C4011, _vm->_rnd->getRandomNumber(15), -1); - SetMessageHandler(&AsScene1002Ring::hmRingIdle); - } - - setClipRect(0, clipY1, 640, 480); - - _x = x; - _y = y; - - setDoDeltaX(_vm->_rnd->getRandomNumber(1)); - -} - -void AsScene1002Ring::update() { - updateAnim(); - updatePosition(); -} - -uint32 AsScene1002Ring::hmRingIdle(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x4806: - setDoDeltaX(((Sprite*)sender)->isDoDeltaX() ? 1 : 0); - sendMessage(_parentScene, 0x4806, 0); - SetMessageHandler(&AsScene1002Ring::hmRingPulled1); - startAnimation(_isSpecial ? 0x87502558 : 0x80DD4010, 0, -1); - break; - case 0x480F: - setDoDeltaX(((Sprite*)sender)->isDoDeltaX() ? 1 : 0); - sendMessage(_parentScene, 0x480F, 0); - SetMessageHandler(&AsScene1002Ring::hmRingPulled2); - startAnimation(0x861A2020, 0, -1); - break; - case 0x482A: - sendMessage(_parentScene, 0x1022, 990); - break; - case 0x482B: - sendMessage(_parentScene, 0x1022, 1010); - break; - } - return messageResult; -} - -uint32 AsScene1002Ring::hmRingPulled1(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x3002: - startAnimation(_isSpecial ? 0x78D0A812 : 0xB85D2A10, 0, -1); - SetMessageHandler(&AsScene1002Ring::hmRingHangingLow); - break; - case 0x4807: - sendMessage(_parentScene, 0x4807, 0); - setDoDeltaX(_vm->_rnd->getRandomNumber(1)); - startAnimation(0x8258A030, 0, -1); - SetMessageHandler(&AsScene1002Ring::hmRingReleased); - break; - case 0x482A: - sendMessage(_parentScene, 0x1022, 990); - break; - case 0x482B: - sendMessage(_parentScene, 0x1022, 1010); - break; - } - return messageResult; -} - -uint32 AsScene1002Ring::hmRingPulled2(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x3002: - startAnimation(0x04103090, 0, -1); - SetMessageHandler(&AsScene1002Ring::hmRingHangingLow); - break; - case 0x482A: - sendMessage(_parentScene, 0x1022, 990); - break; - case 0x482B: - sendMessage(_parentScene, 0x1022, 1010); - break; - } - return messageResult; -} - -uint32 AsScene1002Ring::hmRingHangingLow(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x4807: - sendMessage(_parentScene, 0x4807, 0); - setDoDeltaX(_vm->_rnd->getRandomNumber(1)); - startAnimation(0x8258A030, 0, -1); - SetMessageHandler(&AsScene1002Ring::hmRingReleased); - break; - case 0x482A: - sendMessage(_parentScene, 0x1022, 990); - break; - case 0x482B: - sendMessage(_parentScene, 0x1022, 1010); - break; - } - return messageResult; -} - -uint32 AsScene1002Ring::hmRingReleased(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = hmRingIdle(messageNum, param, sender); - switch (messageNum) { - case 0x100D: - if (param.asInteger() == 0x05410F72) - playSound(0, 0x21EE40A9); - break; - case 0x3002: - startAnimation(0xA85C4011, 0, -1); - break; - case 0x482A: - sendMessage(_parentScene, 0x1022, 990); - break; - case 0x482B: - sendMessage(_parentScene, 0x1022, 1010); - break; - } - return messageResult; -} - -AsScene1002Door::AsScene1002Door(NeverhoodEngine *vm, NRect &clipRect) - : StaticSprite(vm, 1200) { - - loadSprite(0x1052370F, kSLFDefDrawOffset | kSLFSetPosition, 800, 526, getGlobalVar(V_FLYTRAP_RING_DOOR) ? 49 : 239); - setClipRect(clipRect); - SetUpdateHandler(&AsScene1002Door::update); - SetMessageHandler(&AsScene1002Door::handleMessage); - SetSpriteUpdate(NULL); -} - -void AsScene1002Door::update() { - handleSpriteUpdate(); - updatePosition(); -} - -uint32 AsScene1002Door::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x4808: - setGlobalVar(V_FLYTRAP_RING_DOOR, 1); - SetSpriteUpdate(&AsScene1002Door::suOpenDoor); - break; - case 0x4809: - setGlobalVar(V_FLYTRAP_RING_DOOR, 0); - SetSpriteUpdate(&AsScene1002Door::suCloseDoor); - break; - } - return messageResult; -} - -void AsScene1002Door::suOpenDoor() { - if (_y > 49) { - _y -= 8; - if (_y < 49) { - SetSpriteUpdate(NULL); - _y = 49; - } - _needRefresh = true; - } -} - -void AsScene1002Door::suCloseDoor() { - if (_y < 239) { - _y += 8; - if (_y > 239) { - SetSpriteUpdate(NULL); - _y = 239; - } - _needRefresh = true; - } -} - -AsScene1002BoxingGloveHitEffect::AsScene1002BoxingGloveHitEffect(NeverhoodEngine *vm) - : AnimatedSprite(vm, 1400) { - - createSurface(1025, 88, 165); - setVisible(false); - SetUpdateHandler(&AnimatedSprite::update); - SetMessageHandler(&AsScene1002BoxingGloveHitEffect::handleMessage); -} - -uint32 AsScene1002BoxingGloveHitEffect::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x2004: - _x = ((Sprite*)sender)->getX() - 98; - _y = ((Sprite*)sender)->getY() - 111; - startAnimation(0x0422255A, 0, -1); - setVisible(true); - break; - case 0x3002: - stopAnimation(); - setVisible(false); - break; - } - return messageResult; -} - -AsScene1002DoorSpy::AsScene1002DoorSpy(NeverhoodEngine *vm, NRect &clipRect, Scene *parentScene, Sprite *asDoor, Sprite *asScene1002BoxingGloveHitEffect) - : AnimatedSprite(vm, 1300), _clipRect(clipRect), _parentScene(parentScene), _asDoor(asDoor), _asBoxingGloveHitEffect(asScene1002BoxingGloveHitEffect) { - - createSurface(800, 136, 147); - setClipRect(clipRect); - suDoorSpy(); - loadSound(0, 0xC0C40298); - startAnimation(0x586C1D48, 0, 0); - SetUpdateHandler(&AnimatedSprite::update); - SetMessageHandler(&AsScene1002DoorSpy::handleMessage); - SetSpriteUpdate(&AsScene1002DoorSpy::suDoorSpy); -} - -uint32 AsScene1002DoorSpy::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x100D: - if (param.asInteger() == 0xA61CA1C2) - sendMessage(_asBoxingGloveHitEffect, 0x2004, 0); - else if (param.asInteger() == 0x14CE0620) - playSound(0); - break; - case 0x2003: - stDoorSpyBoxingGlove(); - break; - } - return messageResult; -} - -uint32 AsScene1002DoorSpy::hmDoorSpyAnimation(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x3002: - gotoNextState(); - break; - } - return messageResult; -} - -void AsScene1002DoorSpy::suDoorSpy() { - _x = _asDoor->getX() + 34; - _y = _asDoor->getY() + 175; -} - -void AsScene1002DoorSpy::stDoorSpyIdle() { - setClipRect(_clipRect); - _parentScene->setSurfacePriority(getSurface(), 800); - startAnimation(0x586C1D48, 0, 0); - SetMessageHandler(&AsScene1002DoorSpy::handleMessage); -} - -void AsScene1002DoorSpy::stDoorSpyBoxingGlove() { - setClipRect(0, 0, 640, 480); - _parentScene->setSurfacePriority(getSurface(), 1200); - startAnimation(0x586C1D48, 1, -1); - SetMessageHandler(&AsScene1002DoorSpy::hmDoorSpyAnimation); - NextState(&AsScene1002DoorSpy::stDoorSpyIdle); -} - -SsCommonPressButton::SsCommonPressButton(NeverhoodEngine *vm, Scene *parentScene, uint32 fileHash1, uint32 fileHash2, int surfacePriority, uint32 soundFileHash) - : StaticSprite(vm, 1100), _parentScene(parentScene), _status(0), _countdown(0) { - - _soundFileHash = soundFileHash != 0 ? soundFileHash : 0x44141000; - _fileHashes[0] = fileHash1; - _fileHashes[1] = fileHash2; - createSurface(surfacePriority, 40, 40); - loadSprite(fileHash1, kSLFDefDrawOffset | kSLFDefPosition); - setVisible(false); - SetUpdateHandler(&SsCommonPressButton::update); - SetMessageHandler(&SsCommonPressButton::handleMessage); -} - -void SsCommonPressButton::setFileHashes(uint32 fileHash1, uint32 fileHash2) { - _fileHashes[0] = fileHash1; - _fileHashes[1] = fileHash2; - loadSprite(_status == 2 ? fileHash2 : fileHash1, kSLFDefDrawOffset | kSLFDefPosition); -} - -void SsCommonPressButton::update() { - if (_countdown != 0 && (--_countdown) == 0) { - if (_status == 1) { - _status = 2; - loadSprite(_fileHashes[1], kSLFDefDrawOffset | kSLFDefPosition); - _countdown = 4; - } else if (_status == 2) { - _status = 3; - loadSprite(_fileHashes[0], kSLFDefDrawOffset | kSLFDefPosition); - _countdown = 4; - } else if (_status == 3) { - _status = 0; - setVisible(false); - } - } -} - -uint32 SsCommonPressButton::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x480B: - sendMessage(_parentScene, 0x480B, 0); - _status = 1; - _countdown = 4; - setVisible(true); - playSound(0, _soundFileHash); - break; - } - return messageResult; -} - -AsScene1002VenusFlyTrap::AsScene1002VenusFlyTrap(NeverhoodEngine *vm, Scene *parentScene, Sprite *klaymen, bool isSecond) - : AnimatedSprite(vm, 1100), _parentScene(parentScene), _klaymen(klaymen), _isSecond(isSecond), _countdown(0) { - - createSurface(995, 175, 195); - if (!_isSecond) { - if (getGlobalVar(V_FLYTRAP_RING_DOOR)) { - setDoDeltaX(1); - _x = 366; - _y = 435; - stRingGrabbed(); - } else { - _x = 174 + getGlobalVar(V_FLYTRAP_POSITION_1) * 32; - _y = 435; - stIdle(); - } - } else { - _x = 186 + getGlobalVar(V_FLYTRAP_POSITION_2) * 32; - _y = 364; - if (getGlobalVar(V_FLYTRAP_RING_BRIDGE) || getGlobalVar(V_FLYTRAP_RING_FENCE)) { - stRingGrabbed(); - } else { - stIdle(); - } - } - _flags = 4; - SetUpdateHandler(&AsScene1002VenusFlyTrap::update); - SetMessageHandler(&AsScene1002VenusFlyTrap::handleMessage); - SetSpriteUpdate(&AnimatedSprite::updateDeltaXY); -} - -void AsScene1002VenusFlyTrap::update() { - if (_countdown != 0 && (--_countdown == 0)) - gotoNextState(); - AnimatedSprite::update(); -} - -void AsScene1002VenusFlyTrap::upIdle() { - if (_countdown == 0 && _klaymen->getX() - 20 > _x) - setDoDeltaX(1); - else if (_klaymen->getX() + 20 < _x) - setDoDeltaX(0); - update(); -} - -uint32 AsScene1002VenusFlyTrap::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x100D: - if (param.asInteger() == 0x000890C4) - playSound(0, 0xC21190D8); - else if (param.asInteger() == 0x522200A0) - playSound(0, 0x931080C8); - break; - case 0x1011: - if (_isSecond) { - if (_x >= 154 && _x <= 346) { - sendMessage(_parentScene, 0x2000, 0); - messageResult = 1; - } - } else { - if (_x >= 174 && _x <= 430) { - sendMessage(_parentScene, 0x2000, 0); - messageResult = 1; - } - } - break; - case 0x480B: - setDoDeltaX(param.asInteger() != 0 ? 1 : 0); - if (!_isSecond) { - if (getGlobalVar(V_FLYTRAP_RING_DOOR)) - stRelease(); - else - stWalk(); - } else { - if (getGlobalVar(V_FLYTRAP_RING_BRIDGE) || getGlobalVar(V_FLYTRAP_RING_FENCE)) - stRelease(); - else - stWalk(); - } - break; - case 0x480C: - if (_isSecond) { - if (_x >= 154 && _x <= 346) - messageResult = 1; - else - messageResult = 0; - } else { - if (_x >= 174 && _x <= 430) - messageResult = 1; - else - messageResult = 0; - } - break; - case 0x480E: - if (param.asInteger() == 1) - stGrabRing(); - break; - case 0x4810: - swallowKlaymen(); - break; - case 0x482A: - sendMessage(_parentScene, 0x1022, 995); - break; - case 0x482B: - sendMessage(_parentScene, 0x1022, 1015); - break; - } - return messageResult; -} - -uint32 AsScene1002VenusFlyTrap::hmAnimationSimple(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x3002: - gotoNextState(); - break; - } - return messageResult; -} - -uint32 AsScene1002VenusFlyTrap::hmAnimationExt(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x100D: - if (param.asInteger() == 0x000890C4) - playSound(0, 0xC21190D8); - else if (param.asInteger() == 0x41881801) { - if (_isSecond) { - if (_x > 330) - sendMessage(_klaymen, 0x4811, 2); - else - sendMessage(_klaymen, 0x4811, 0); - } else { - sendMessage(_klaymen, 0x4811, 0); - } - } else if (param.asInteger() == 0x522200A0) - playSound(0, 0x931080C8); - break; - case 0x3002: - gotoNextState(); - break; - case 0x482A: - sendMessage(_parentScene, 0x1022, 995); - break; - case 0x482B: - sendMessage(_parentScene, 0x1022, 1015); - break; - } - return messageResult; -} - -void AsScene1002VenusFlyTrap::stWalkBack() { - setDoDeltaX(2); - startAnimation(0xC4080034, 0, -1); - SetUpdateHandler(&AsScene1002VenusFlyTrap::update); - SetMessageHandler(&AsScene1002VenusFlyTrap::hmAnimationExt); - NextState(&AsScene1002VenusFlyTrap::stIdle); -} - -void AsScene1002VenusFlyTrap::stWalk() { - startAnimation(0xC4080034, 0, -1); - SetUpdateHandler(&AsScene1002VenusFlyTrap::update); - SetMessageHandler(&AsScene1002VenusFlyTrap::hmAnimationSimple); - NextState(&AsScene1002VenusFlyTrap::stIdle); -} - -void AsScene1002VenusFlyTrap::stRelease() { - sendMessage(_parentScene, 0x4807, 0); - startAnimation(0x82292851, 0, -1); - SetUpdateHandler(&AsScene1002VenusFlyTrap::update); - SetMessageHandler(&AsScene1002VenusFlyTrap::hmAnimationSimple); - NextState(&AsScene1002VenusFlyTrap::stIdle); -} - -void AsScene1002VenusFlyTrap::stGrabRing() { - setDoDeltaX(1); - startAnimation(0x86A82A11, 0, -1); - SetUpdateHandler(&AsScene1002VenusFlyTrap::update); - SetMessageHandler(&AsScene1002VenusFlyTrap::hmAnimationSimple); - NextState(&AsScene1002VenusFlyTrap::stRingGrabbed); -} - -void AsScene1002VenusFlyTrap::stRingGrabbed() { - startAnimation(0xB5A86034, 0, -1); - SetUpdateHandler(&AsScene1002VenusFlyTrap::update); - SetMessageHandler(&AsScene1002VenusFlyTrap::handleMessage); -} - -void AsScene1002VenusFlyTrap::stKlaymenInside() { - startAnimation(0x31303094, 0, -1); - SetUpdateHandler(&AsScene1002VenusFlyTrap::update); - SetMessageHandler(NULL); - NextState(&AsScene1002VenusFlyTrap::stKlaymenInsideMoving); - _countdown = 24; -} - -void AsScene1002VenusFlyTrap::stIdle() { - startAnimation(0xC8204250, 0, -1); - SetUpdateHandler(&AsScene1002VenusFlyTrap::upIdle); - SetMessageHandler(&AsScene1002VenusFlyTrap::handleMessage); - if (_isSecond) { - if (_x >= 154 && _x <= 346) - setGlobalVar(V_FLYTRAP_POSITION_2, (_x - 186) / 32); - else { - NextState(&AsScene1002VenusFlyTrap::stWalkBack); - _countdown = 12; - } - } else { - if (_x >= 174 && _x <= 430) - setGlobalVar(V_FLYTRAP_POSITION_1, (_x - 174) / 32); - else { - NextState(&AsScene1002VenusFlyTrap::stWalkBack); - _countdown = 12; - } - } -} - -void AsScene1002VenusFlyTrap::stKlaymenInsideMoving() { - startAnimation(0x152920C4, 0, -1); - SetUpdateHandler(&AsScene1002VenusFlyTrap::update); - SetMessageHandler(&AsScene1002VenusFlyTrap::hmAnimationExt); - NextState(&AsScene1002VenusFlyTrap::stSpitOutKlaymen); -} - -void AsScene1002VenusFlyTrap::stSpitOutKlaymen() { - startAnimation(0x84001117, 0, -1); - SetUpdateHandler(&AsScene1002VenusFlyTrap::update); - SetMessageHandler(&AsScene1002VenusFlyTrap::hmAnimationExt); - NextState(&AsScene1002VenusFlyTrap::stIdle); -} - -void AsScene1002VenusFlyTrap::swallowKlaymen() { - if (_x - 15 < _klaymen->getX() && _x + 15 > _klaymen->getX()) { - if (_isSecond) - setDoDeltaX(_x > 265 && _x < 330 ? 1 : 0); - else - setDoDeltaX(_x > 320 ? 1 : 0); - sendMessage(_klaymen, 0x2001, 0); - startAnimation(0x8C2C80D4, 0, -1); - SetUpdateHandler(&AsScene1002VenusFlyTrap::update); - SetMessageHandler(&AsScene1002VenusFlyTrap::hmAnimationExt); - NextState(&AsScene1002VenusFlyTrap::stKlaymenInside); - } -} - -AsScene1002OutsideDoorBackground::AsScene1002OutsideDoorBackground(NeverhoodEngine *vm) - : AnimatedSprite(vm, 1200), _countdown(0), _isDoorClosed(true) { - - createSurface(850, 186, 212); - _x = 320; - _y = 240; - if (getGlobalVar(V_FLYTRAP_RING_DOOR)) { - startAnimation(0x004A4495, -1, -1); - _newStickFrameIndex = STICK_LAST_FRAME; - } else - setVisible(false); - SetUpdateHandler(&AsScene1002OutsideDoorBackground::update); - SetMessageHandler(&AsScene1002OutsideDoorBackground::handleMessage); -} - -void AsScene1002OutsideDoorBackground::update() { - if (_countdown != 0 && (--_countdown == 0)) { - if (_isDoorClosed) - stCloseDoor(); - else - stOpenDoor(); - } - AnimatedSprite::update(); -} - -uint32 AsScene1002OutsideDoorBackground::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageResult) { - case 0x4808: - _isDoorClosed = false; - _countdown = 2; - break; - case 0x4809: - _isDoorClosed = true; - _countdown = 2; - break; - } - return messageResult; -} - -uint32 AsScene1002OutsideDoorBackground::hmAnimation(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = handleMessage(messageNum, param, sender); - switch (messageResult) { - case 0x3002: - gotoNextState(); - break; - } - return messageResult; -} - -void AsScene1002OutsideDoorBackground::stOpenDoor() { - startAnimation(0x004A4495, 0, -1); - _newStickFrameIndex = STICK_LAST_FRAME; - setVisible(true); - SetMessageHandler(&AsScene1002OutsideDoorBackground::handleMessage); -} - -void AsScene1002OutsideDoorBackground::stCloseDoor() { - startAnimation(0x004A4495, -1, -1); - _playBackwards = true; - setVisible(true); - SetMessageHandler(&AsScene1002OutsideDoorBackground::hmAnimation); - NextState(&AsScene1002OutsideDoorBackground::stDoorClosed); -} - -void AsScene1002OutsideDoorBackground::stDoorClosed() { - setVisible(false); - stopAnimation(); -} - -AsScene1002KlaymenLadderHands::AsScene1002KlaymenLadderHands(NeverhoodEngine *vm, Klaymen *klaymen) - : AnimatedSprite(vm, 1200), _klaymen(klaymen) { - - createSurface(1200, 40, 163); - setVisible(false); - SetUpdateHandler(&AsScene1002KlaymenLadderHands::update); - SetMessageHandler(&Sprite::handleMessage); -} - -void AsScene1002KlaymenLadderHands::update() { - if (_klaymen->getCurrAnimFileHash() == 0x3A292504) { - startAnimation(0xBA280522, _klaymen->getFrameIndex(), -1); - _newStickFrameIndex = _klaymen->getFrameIndex(); - setVisible(true); - _x = _klaymen->getX(); - _y = _klaymen->getY(); - setDoDeltaX(_klaymen->isDoDeltaX() ? 1 : 0); - } else if (_klaymen->getCurrAnimFileHash() == 0x122D1505) { - startAnimation(0x1319150C, _klaymen->getFrameIndex(), -1); - _newStickFrameIndex = _klaymen->getFrameIndex(); - setVisible(true); - _x = _klaymen->getX(); - _y = _klaymen->getY(); - setDoDeltaX(_klaymen->isDoDeltaX() ? 1 : 0); - } else - setVisible(false); - AnimatedSprite::update(); -} - -AsScene1002KlaymenPeekHand::AsScene1002KlaymenPeekHand(NeverhoodEngine *vm, Scene *parentScene, Klaymen *klaymen) - : AnimatedSprite(vm, 1200), _parentScene(parentScene), _klaymen(klaymen), - _isClipRectSaved(false) { - - createSurface(1000, 33, 41); - setVisible(false); - SetUpdateHandler(&AsScene1002KlaymenPeekHand::update); - SetMessageHandler(&AsScene1002KlaymenPeekHand::handleMessage); -} - -void AsScene1002KlaymenPeekHand::update() { - if (_klaymen->getCurrAnimFileHash() == 0xAC20C012 && _klaymen->getFrameIndex() < 50) { - startAnimation(0x9820C913, _klaymen->getFrameIndex(), -1); - _newStickFrameIndex = _klaymen->getFrameIndex(); - setVisible(true); - _x = _klaymen->getX(); - _y = _klaymen->getY(); - setDoDeltaX(_klaymen->isDoDeltaX() ? 1 : 0); - } else - setVisible(false); - AnimatedSprite::update(); -} - -uint32 AsScene1002KlaymenPeekHand::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x100D: - if (param.asInteger() == 0x4AB28209) { - sendMessage(_parentScene, 0x1022, 1200); - _isClipRectSaved = true; - _savedClipRect = _surface->getClipRect(); - setClipRect(0, 0, 640, 480); - } else if (param.asInteger() == 0x88001184) { - sendMessage(_parentScene, 0x1022, 1000); - if (_isClipRectSaved) - setClipRect(_savedClipRect); - } - break; - } - return messageResult; -} - Scene1002::Scene1002(NeverhoodEngine *vm, Module *parentModule, int which) : Scene(vm, parentModule), _isKlaymenFloor(false), _isClimbingLadder(false) { @@ -1383,38 +458,6 @@ uint32 Scene1002::handleMessage(int messageNum, const MessageParam ¶m, Entit return messageResult; } -// Scene1004 - -AsScene1004TrashCan::AsScene1004TrashCan(NeverhoodEngine *vm) - : AnimatedSprite(vm, 1100) { - - _x = 330; - _y = 327; - createSurface(800, 56, 50); - setVisible(false); - SetUpdateHandler(&AnimatedSprite::update); - SetMessageHandler(&AsScene1004TrashCan::handleMessage); -} - -uint32 AsScene1004TrashCan::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x100D: - if (param.asInteger() == 0x225A8587) - playSound(0, 0x109AFC4C); - break; - case 0x2002: - startAnimation(0xEB312C11, 0, -1); - setVisible(true); - break; - case 0x3002: - stopAnimation(); - setVisible(false); - break; - } - return 0; -} - Scene1004::Scene1004(NeverhoodEngine *vm, Module *parentModule, int which) : Scene(vm, parentModule), _paletteAreaStatus(-1) { @@ -1513,8 +556,6 @@ void Scene1004::updatePaletteArea() { } } -// Scene1005 - Scene1005::Scene1005(NeverhoodEngine *vm, Module *parentModule, int which) : Scene(vm, parentModule) { diff --git a/engines/neverhood/modules/module1000.h b/engines/neverhood/modules/module1000.h index 9e97e822f6..4b17c92b3b 100644 --- a/engines/neverhood/modules/module1000.h +++ b/engines/neverhood/modules/module1000.h @@ -29,8 +29,6 @@ namespace Neverhood { -// Module1000 - class Module1000 : public Module { public: Module1000(NeverhoodEngine *vm, Module *parentModule, int which); @@ -42,53 +40,6 @@ protected: void updateScene(); }; -// Scene1001 - -class AsScene1001Door : public AnimatedSprite { -public: - AsScene1001Door(NeverhoodEngine *vm); -protected: - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); - void hammerHitsDoor(); - void stShowIdleDoor(); - void stBustedDoorMove(); - void stBustedDoorGone(); -}; - -class AsScene1001Hammer : public AnimatedSprite { -public: - AsScene1001Hammer(NeverhoodEngine *vm, Sprite *asDoor); -protected: - Sprite *_asDoor; - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); -}; - -class AsScene1001Window : public AnimatedSprite { -public: - AsScene1001Window(NeverhoodEngine *vm); -protected: - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); -}; - -class AsScene1001Lever : public AnimatedSprite { -public: - AsScene1001Lever(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y, int deltaXType); -protected: - Scene *_parentScene; - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); -}; - -class SsCommonButtonSprite : public StaticSprite { -public: - SsCommonButtonSprite(NeverhoodEngine *vm, Scene *parentScene, uint32 fileHash, int surfacePriority, uint32 soundFileHash); -protected: - Scene *_parentScene; - uint32 _soundFileHash; - int16 _countdown; - void update(); - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); -}; - class Scene1001 : public Scene { public: Scene1001(NeverhoodEngine *vm, Module *parentModule, int which); @@ -102,127 +53,6 @@ protected: uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); }; -// Scene1002 - -class AsScene1002Ring : public AnimatedSprite { -public: - AsScene1002Ring(NeverhoodEngine *vm, Scene *parentScene, bool isSpecial, int16 x, int16 y, int16 clipY1, bool isRingLow); -protected: - Scene *_parentScene; - bool _isSpecial; - void update(); - uint32 hmRingIdle(int messageNum, const MessageParam ¶m, Entity *sender); - uint32 hmRingPulled1(int messageNum, const MessageParam ¶m, Entity *sender); - uint32 hmRingPulled2(int messageNum, const MessageParam ¶m, Entity *sender); - uint32 hmRingHangingLow(int messageNum, const MessageParam ¶m, Entity *sender); - uint32 hmRingReleased(int messageNum, const MessageParam ¶m, Entity *sender); -}; - -class AsScene1002Door : public StaticSprite { -public: - AsScene1002Door(NeverhoodEngine *vm, NRect &clipRect); -protected: - void update(); - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); - void suOpenDoor(); - void suCloseDoor(); -}; - -class AsScene1002BoxingGloveHitEffect : public AnimatedSprite { -public: - AsScene1002BoxingGloveHitEffect(NeverhoodEngine *vm); -protected: - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); -}; - -class AsScene1002DoorSpy : public AnimatedSprite { -public: - AsScene1002DoorSpy(NeverhoodEngine *vm, NRect &clipRect, Scene *parentScene, Sprite *asDoor, Sprite *asScene1002BoxingGloveHitEffect); -protected: - Scene *_parentScene; - Sprite *_asDoor; - Sprite *_asBoxingGloveHitEffect; - NRect _clipRect; - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); - uint32 hmDoorSpyAnimation(int messageNum, const MessageParam ¶m, Entity *sender); - void suDoorSpy(); - void stDoorSpyIdle(); - void stDoorSpyBoxingGlove(); -}; - -class SsCommonPressButton : public StaticSprite { -public: - SsCommonPressButton(NeverhoodEngine *vm, Scene *parentScene, uint32 fileHash1, uint32 fileHash2, int surfacePriority, uint32 soundFileHash); - void setFileHashes(uint32 fileHash1, uint32 fileHash2); -protected: - Scene *_parentScene; - uint32 _soundFileHash; - uint32 _fileHashes[2]; - int _status; - int _countdown; - void update(); - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); -}; - -class AsScene1002VenusFlyTrap : public AnimatedSprite { -public: - AsScene1002VenusFlyTrap(NeverhoodEngine *vm, Scene *parentScene, Sprite *klaymen, bool isSecond); -protected: - Scene *_parentScene; - Sprite *_klaymen; - int _countdown; - bool _isSecond; - void update(); - void upIdle(); - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); - uint32 hmAnimationSimple(int messageNum, const MessageParam ¶m, Entity *sender); - uint32 hmAnimationExt(int messageNum, const MessageParam ¶m, Entity *sender); - void stWalkBack(); - void stWalk(); - void stRelease(); - void stGrabRing(); - void stRingGrabbed(); - void stKlaymenInside(); - void stIdle(); - void stKlaymenInsideMoving(); - void stSpitOutKlaymen(); - void swallowKlaymen(); -}; - -class AsScene1002OutsideDoorBackground : public AnimatedSprite { -public: - AsScene1002OutsideDoorBackground(NeverhoodEngine *vm); -protected: - int _countdown; - bool _isDoorClosed; - void update(); - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); - uint32 hmAnimation(int messageNum, const MessageParam ¶m, Entity *sender); - void stOpenDoor(); - void stCloseDoor(); - void stDoorClosed(); -}; - -class AsScene1002KlaymenLadderHands : public AnimatedSprite { -public: - AsScene1002KlaymenLadderHands(NeverhoodEngine *vm, Klaymen *klaymen); -protected: - Klaymen *_klaymen; - void update(); -}; - -class AsScene1002KlaymenPeekHand : public AnimatedSprite { -public: - AsScene1002KlaymenPeekHand(NeverhoodEngine *vm, Scene *parentScene, Klaymen *klaymen); -protected: - Scene *_parentScene; - Klaymen *_klaymen; - bool _isClipRectSaved; - NRect _savedClipRect; - void update(); - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); -}; - class Scene1002 : public Scene { public: Scene1002(NeverhoodEngine *vm, Module *parentModule, int which); @@ -251,15 +81,6 @@ protected: uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); }; -// Scene1004 - -class AsScene1004TrashCan : public AnimatedSprite { -public: - AsScene1004TrashCan(NeverhoodEngine *vm); -protected: - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); -}; - class Scene1004 : public Scene { public: Scene1004(NeverhoodEngine *vm, Module *parentModule, int which); @@ -272,8 +93,6 @@ protected: void updatePaletteArea(); }; -// Scene1005 - class Scene1005 : public Scene { public: Scene1005(NeverhoodEngine *vm, Module *parentModule, int which); diff --git a/engines/neverhood/modules/module1000_sprites.cpp b/engines/neverhood/modules/module1000_sprites.cpp new file mode 100644 index 0000000000..55618f0124 --- /dev/null +++ b/engines/neverhood/modules/module1000_sprites.cpp @@ -0,0 +1,1567 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "neverhood/modules/module1000_sprites.h" + +namespace Neverhood { + +AsScene1001Door::AsScene1001Door(NeverhoodEngine *vm) + : AnimatedSprite(vm, 1100) { + + createSurface(800, 137, 242); + _x = 726; + _y = 440; + stShowIdleDoor(); + loadSound(1, 0xED403E03); + SetUpdateHandler(&AnimatedSprite::update); + SetMessageHandler(&AsScene1001Door::handleMessage); +} + +uint32 AsScene1001Door::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x2000: + hammerHitsDoor(); + break; + case 0x3002: + gotoNextState(); + break; + } + return 0; +} + +void AsScene1001Door::hammerHitsDoor() { + switch (getGlobalVar(V_DOOR_STATUS)) { + case 0: + case 1: + playSound(0, 0x65482F03); + startAnimation(0x624C0498, 1, 3); + NextState(&AsScene1001Door::stShowIdleDoor); + break; + case 2: + playSound(1); + startAnimation(0x624C0498, 6, 6); + NextState(&AsScene1001Door::stBustedDoorMove); + break; + default: + // Nothing + break; + } + incGlobalVar(V_DOOR_STATUS, 1); +} + +void AsScene1001Door::stShowIdleDoor() { + switch (getGlobalVar(V_DOOR_STATUS)) { + case 1: + startAnimation(0x624C0498, 4, -1); + _newStickFrameIndex = 4; + break; + case 2: + startAnimation(0x624C0498, 1, -1); + _newStickFrameIndex = 1; + break; + case 3: + stopAnimation(); + setVisible(false); + break; + default: + startAnimation(0x624C0498, 0, -1); + _newStickFrameIndex = 0; + break; + } +} + +void AsScene1001Door::stBustedDoorMove() { + setGlobalVar(V_DOOR_BUSTED, 1); + startAnimation(0x624C0498, 6, 6); + NextState(&AsScene1001Door::stBustedDoorGone); + _x = 30; +} + +void AsScene1001Door::stBustedDoorGone() { + playSound(0); + stopAnimation(); + setVisible(false); +} + +AsScene1001Hammer::AsScene1001Hammer(NeverhoodEngine *vm, Sprite *asDoor) + : AnimatedSprite(vm, 1100), _asDoor(asDoor) { + + _x = 547; + _y = 206; + createSurface(900, 177, 192); + startAnimation(0x022C90D4, -1, -1); + _newStickFrameIndex = STICK_LAST_FRAME; + SetUpdateHandler(&AnimatedSprite::update); + SetMessageHandler(&AsScene1001Hammer::handleMessage); +} + +uint32 AsScene1001Hammer::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x100D: + if (param.asInteger() == 0x00352100) + sendMessage(_asDoor, 0x2000, 0); + else if (param.asInteger() == 0x0A1A0109) + playSound(0, 0x66410886); + break; + case 0x2000: + startAnimation(0x022C90D4, 1, -1); + playSound(0, 0xE741020A); + _newStickFrameIndex = STICK_LAST_FRAME; + break; + } + return 0; +} + +AsScene1001Window::AsScene1001Window(NeverhoodEngine *vm) + : AnimatedSprite(vm, 1200) { + + _x = 320; + _y = 240; + createSurface(100, 66, 129); + startAnimation(0xC68C2299, 0, -1); + _newStickFrameIndex = 0; + SetUpdateHandler(&AnimatedSprite::update); + SetMessageHandler(&AsScene1001Window::handleMessage); +} + +uint32 AsScene1001Window::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x100D: + if (param.asInteger() == 0x0E0A1410) + playSound(0, 0x60803F10); + break; + case 0x2001: + startAnimation(0xC68C2299, 0, -1); + break; + case 0x3002: + SetMessageHandler(NULL); + setGlobalVar(V_WINDOW_OPEN, 1); + setVisible(false); + break; + } + return 0; +} + +AsScene1001Lever::AsScene1001Lever(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y, int deltaXType) + : AnimatedSprite(vm, 1100), _parentScene(parentScene) { + + createSurface(1010, 71, 73); + setDoDeltaX(deltaXType); + startAnimation(0x04A98C36, 0, -1); + _newStickFrameIndex = 0; + _x = x; + _y = y; + SetUpdateHandler(&AnimatedSprite::update); + SetMessageHandler(&AsScene1001Lever::handleMessage); +} + +uint32 AsScene1001Lever::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x100D: + if (param.asInteger() == 0x00C0C444) + sendMessage(_parentScene, 0x480F, 0); + else if (param.asInteger() == 0xC41A02C0) + playSound(0, 0x40581882); + break; + case 0x1011: + sendMessage(_parentScene, 0x4826, 0); + messageResult = 1; + break; + case 0x3002: + startAnimation(0x04A98C36, 0, -1); + _newStickFrameIndex = 0; + break; + case 0x480F: + startAnimation(0x04A98C36, 0, -1); + break; + case 0x482A: + sendMessage(_parentScene, 0x1022, 990); + break; + case 0x482B: + sendMessage(_parentScene, 0x1022, 1010); + break; + } + return messageResult; +} + +SsCommonButtonSprite::SsCommonButtonSprite(NeverhoodEngine *vm, Scene *parentScene, uint32 fileHash, int surfacePriority, uint32 soundFileHash) + : StaticSprite(vm, fileHash, surfacePriority), _parentScene(parentScene), _countdown(0) { + + _priority = 1100; + _soundFileHash = soundFileHash ? soundFileHash : 0x44141000; + setVisible(false); + SetUpdateHandler(&SsCommonButtonSprite::update); + SetMessageHandler(&SsCommonButtonSprite::handleMessage); +} + +void SsCommonButtonSprite::update() { + if (_countdown != 0 && (--_countdown) == 0) + setVisible(false); +} + +uint32 SsCommonButtonSprite::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x480B: + sendMessage(_parentScene, 0x480B, 0); + setVisible(true); + _countdown = 8; + playSound(0, _soundFileHash); + break; + } + return messageResult; +} + +AsScene1002Ring::AsScene1002Ring(NeverhoodEngine *vm, Scene *parentScene, bool isSpecial, int16 x, int16 y, int16 clipY1, bool isRingLow) + : AnimatedSprite(vm, 1100), _parentScene(parentScene), _isSpecial(isSpecial) { + + SetUpdateHandler(&AsScene1002Ring::update); + + if (_isSpecial) { + createSurface(990, 68, 314); + if (isRingLow) { + startAnimation(0x04103090, 0, -1); + SetMessageHandler(&AsScene1002Ring::hmRingHangingLow); + } else { + startAnimation(0xA85C4011, _vm->_rnd->getRandomNumber(15), -1); + SetMessageHandler(&AsScene1002Ring::hmRingIdle); + } + } else { + createSurface(990, 68, 138); + startAnimation(0xA85C4011, _vm->_rnd->getRandomNumber(15), -1); + SetMessageHandler(&AsScene1002Ring::hmRingIdle); + } + + setClipRect(0, clipY1, 640, 480); + + _x = x; + _y = y; + + setDoDeltaX(_vm->_rnd->getRandomNumber(1)); + +} + +void AsScene1002Ring::update() { + updateAnim(); + updatePosition(); +} + +uint32 AsScene1002Ring::hmRingIdle(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x4806: + setDoDeltaX(((Sprite*)sender)->isDoDeltaX() ? 1 : 0); + sendMessage(_parentScene, 0x4806, 0); + SetMessageHandler(&AsScene1002Ring::hmRingPulled1); + startAnimation(_isSpecial ? 0x87502558 : 0x80DD4010, 0, -1); + break; + case 0x480F: + setDoDeltaX(((Sprite*)sender)->isDoDeltaX() ? 1 : 0); + sendMessage(_parentScene, 0x480F, 0); + SetMessageHandler(&AsScene1002Ring::hmRingPulled2); + startAnimation(0x861A2020, 0, -1); + break; + case 0x482A: + sendMessage(_parentScene, 0x1022, 990); + break; + case 0x482B: + sendMessage(_parentScene, 0x1022, 1010); + break; + } + return messageResult; +} + +uint32 AsScene1002Ring::hmRingPulled1(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x3002: + startAnimation(_isSpecial ? 0x78D0A812 : 0xB85D2A10, 0, -1); + SetMessageHandler(&AsScene1002Ring::hmRingHangingLow); + break; + case 0x4807: + sendMessage(_parentScene, 0x4807, 0); + setDoDeltaX(_vm->_rnd->getRandomNumber(1)); + startAnimation(0x8258A030, 0, -1); + SetMessageHandler(&AsScene1002Ring::hmRingReleased); + break; + case 0x482A: + sendMessage(_parentScene, 0x1022, 990); + break; + case 0x482B: + sendMessage(_parentScene, 0x1022, 1010); + break; + } + return messageResult; +} + +uint32 AsScene1002Ring::hmRingPulled2(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x3002: + startAnimation(0x04103090, 0, -1); + SetMessageHandler(&AsScene1002Ring::hmRingHangingLow); + break; + case 0x482A: + sendMessage(_parentScene, 0x1022, 990); + break; + case 0x482B: + sendMessage(_parentScene, 0x1022, 1010); + break; + } + return messageResult; +} + +uint32 AsScene1002Ring::hmRingHangingLow(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x4807: + sendMessage(_parentScene, 0x4807, 0); + setDoDeltaX(_vm->_rnd->getRandomNumber(1)); + startAnimation(0x8258A030, 0, -1); + SetMessageHandler(&AsScene1002Ring::hmRingReleased); + break; + case 0x482A: + sendMessage(_parentScene, 0x1022, 990); + break; + case 0x482B: + sendMessage(_parentScene, 0x1022, 1010); + break; + } + return messageResult; +} + +uint32 AsScene1002Ring::hmRingReleased(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = hmRingIdle(messageNum, param, sender); + switch (messageNum) { + case 0x100D: + if (param.asInteger() == 0x05410F72) + playSound(0, 0x21EE40A9); + break; + case 0x3002: + startAnimation(0xA85C4011, 0, -1); + break; + case 0x482A: + sendMessage(_parentScene, 0x1022, 990); + break; + case 0x482B: + sendMessage(_parentScene, 0x1022, 1010); + break; + } + return messageResult; +} + +AsScene1002Door::AsScene1002Door(NeverhoodEngine *vm, NRect &clipRect) + : StaticSprite(vm, 1200) { + + loadSprite(0x1052370F, kSLFDefDrawOffset | kSLFSetPosition, 800, 526, getGlobalVar(V_FLYTRAP_RING_DOOR) ? 49 : 239); + setClipRect(clipRect); + SetUpdateHandler(&AsScene1002Door::update); + SetMessageHandler(&AsScene1002Door::handleMessage); + SetSpriteUpdate(NULL); +} + +void AsScene1002Door::update() { + handleSpriteUpdate(); + updatePosition(); +} + +uint32 AsScene1002Door::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x4808: + setGlobalVar(V_FLYTRAP_RING_DOOR, 1); + SetSpriteUpdate(&AsScene1002Door::suOpenDoor); + break; + case 0x4809: + setGlobalVar(V_FLYTRAP_RING_DOOR, 0); + SetSpriteUpdate(&AsScene1002Door::suCloseDoor); + break; + } + return messageResult; +} + +void AsScene1002Door::suOpenDoor() { + if (_y > 49) { + _y -= 8; + if (_y < 49) { + SetSpriteUpdate(NULL); + _y = 49; + } + _needRefresh = true; + } +} + +void AsScene1002Door::suCloseDoor() { + if (_y < 239) { + _y += 8; + if (_y > 239) { + SetSpriteUpdate(NULL); + _y = 239; + } + _needRefresh = true; + } +} + +AsScene1002BoxingGloveHitEffect::AsScene1002BoxingGloveHitEffect(NeverhoodEngine *vm) + : AnimatedSprite(vm, 1400) { + + createSurface(1025, 88, 165); + setVisible(false); + SetUpdateHandler(&AnimatedSprite::update); + SetMessageHandler(&AsScene1002BoxingGloveHitEffect::handleMessage); +} + +uint32 AsScene1002BoxingGloveHitEffect::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x2004: + _x = ((Sprite*)sender)->getX() - 98; + _y = ((Sprite*)sender)->getY() - 111; + startAnimation(0x0422255A, 0, -1); + setVisible(true); + break; + case 0x3002: + stopAnimation(); + setVisible(false); + break; + } + return messageResult; +} + +AsScene1002DoorSpy::AsScene1002DoorSpy(NeverhoodEngine *vm, NRect &clipRect, Scene *parentScene, Sprite *asDoor, Sprite *asScene1002BoxingGloveHitEffect) + : AnimatedSprite(vm, 1300), _clipRect(clipRect), _parentScene(parentScene), _asDoor(asDoor), _asBoxingGloveHitEffect(asScene1002BoxingGloveHitEffect) { + + createSurface(800, 136, 147); + setClipRect(clipRect); + suDoorSpy(); + loadSound(0, 0xC0C40298); + startAnimation(0x586C1D48, 0, 0); + SetUpdateHandler(&AnimatedSprite::update); + SetMessageHandler(&AsScene1002DoorSpy::handleMessage); + SetSpriteUpdate(&AsScene1002DoorSpy::suDoorSpy); +} + +uint32 AsScene1002DoorSpy::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x100D: + if (param.asInteger() == 0xA61CA1C2) + sendMessage(_asBoxingGloveHitEffect, 0x2004, 0); + else if (param.asInteger() == 0x14CE0620) + playSound(0); + break; + case 0x2003: + stDoorSpyBoxingGlove(); + break; + } + return messageResult; +} + +uint32 AsScene1002DoorSpy::hmDoorSpyAnimation(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x3002: + gotoNextState(); + break; + } + return messageResult; +} + +void AsScene1002DoorSpy::suDoorSpy() { + _x = _asDoor->getX() + 34; + _y = _asDoor->getY() + 175; +} + +void AsScene1002DoorSpy::stDoorSpyIdle() { + setClipRect(_clipRect); + _parentScene->setSurfacePriority(getSurface(), 800); + startAnimation(0x586C1D48, 0, 0); + SetMessageHandler(&AsScene1002DoorSpy::handleMessage); +} + +void AsScene1002DoorSpy::stDoorSpyBoxingGlove() { + setClipRect(0, 0, 640, 480); + _parentScene->setSurfacePriority(getSurface(), 1200); + startAnimation(0x586C1D48, 1, -1); + SetMessageHandler(&AsScene1002DoorSpy::hmDoorSpyAnimation); + NextState(&AsScene1002DoorSpy::stDoorSpyIdle); +} + +SsCommonPressButton::SsCommonPressButton(NeverhoodEngine *vm, Scene *parentScene, uint32 fileHash1, uint32 fileHash2, int surfacePriority, uint32 soundFileHash) + : StaticSprite(vm, 1100), _parentScene(parentScene), _status(0), _countdown(0) { + + _soundFileHash = soundFileHash != 0 ? soundFileHash : 0x44141000; + _fileHashes[0] = fileHash1; + _fileHashes[1] = fileHash2; + createSurface(surfacePriority, 40, 40); + loadSprite(fileHash1, kSLFDefDrawOffset | kSLFDefPosition); + setVisible(false); + SetUpdateHandler(&SsCommonPressButton::update); + SetMessageHandler(&SsCommonPressButton::handleMessage); +} + +void SsCommonPressButton::setFileHashes(uint32 fileHash1, uint32 fileHash2) { + _fileHashes[0] = fileHash1; + _fileHashes[1] = fileHash2; + loadSprite(_status == 2 ? fileHash2 : fileHash1, kSLFDefDrawOffset | kSLFDefPosition); +} + +void SsCommonPressButton::update() { + if (_countdown != 0 && (--_countdown) == 0) { + if (_status == 1) { + _status = 2; + loadSprite(_fileHashes[1], kSLFDefDrawOffset | kSLFDefPosition); + _countdown = 4; + } else if (_status == 2) { + _status = 3; + loadSprite(_fileHashes[0], kSLFDefDrawOffset | kSLFDefPosition); + _countdown = 4; + } else if (_status == 3) { + _status = 0; + setVisible(false); + } + } +} + +uint32 SsCommonPressButton::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x480B: + sendMessage(_parentScene, 0x480B, 0); + _status = 1; + _countdown = 4; + setVisible(true); + playSound(0, _soundFileHash); + break; + } + return messageResult; +} + +AsScene1002VenusFlyTrap::AsScene1002VenusFlyTrap(NeverhoodEngine *vm, Scene *parentScene, Sprite *klaymen, bool isSecond) + : AnimatedSprite(vm, 1100), _parentScene(parentScene), _klaymen(klaymen), _isSecond(isSecond), _countdown(0) { + + createSurface(995, 175, 195); + if (!_isSecond) { + if (getGlobalVar(V_FLYTRAP_RING_DOOR)) { + setDoDeltaX(1); + _x = 366; + _y = 435; + stRingGrabbed(); + } else { + _x = 174 + getGlobalVar(V_FLYTRAP_POSITION_1) * 32; + _y = 435; + stIdle(); + } + } else { + _x = 186 + getGlobalVar(V_FLYTRAP_POSITION_2) * 32; + _y = 364; + if (getGlobalVar(V_FLYTRAP_RING_BRIDGE) || getGlobalVar(V_FLYTRAP_RING_FENCE)) { + stRingGrabbed(); + } else { + stIdle(); + } + } + _flags = 4; + SetUpdateHandler(&AsScene1002VenusFlyTrap::update); + SetMessageHandler(&AsScene1002VenusFlyTrap::handleMessage); + SetSpriteUpdate(&AnimatedSprite::updateDeltaXY); +} + +void AsScene1002VenusFlyTrap::update() { + if (_countdown != 0 && (--_countdown == 0)) + gotoNextState(); + AnimatedSprite::update(); +} + +void AsScene1002VenusFlyTrap::upIdle() { + if (_countdown == 0 && _klaymen->getX() - 20 > _x) + setDoDeltaX(1); + else if (_klaymen->getX() + 20 < _x) + setDoDeltaX(0); + update(); +} + +uint32 AsScene1002VenusFlyTrap::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x100D: + if (param.asInteger() == 0x000890C4) + playSound(0, 0xC21190D8); + else if (param.asInteger() == 0x522200A0) + playSound(0, 0x931080C8); + break; + case 0x1011: + if (_isSecond) { + if (_x >= 154 && _x <= 346) { + sendMessage(_parentScene, 0x2000, 0); + messageResult = 1; + } + } else { + if (_x >= 174 && _x <= 430) { + sendMessage(_parentScene, 0x2000, 0); + messageResult = 1; + } + } + break; + case 0x480B: + setDoDeltaX(param.asInteger() != 0 ? 1 : 0); + if (!_isSecond) { + if (getGlobalVar(V_FLYTRAP_RING_DOOR)) + stRelease(); + else + stWalk(); + } else { + if (getGlobalVar(V_FLYTRAP_RING_BRIDGE) || getGlobalVar(V_FLYTRAP_RING_FENCE)) + stRelease(); + else + stWalk(); + } + break; + case 0x480C: + if (_isSecond) { + if (_x >= 154 && _x <= 346) + messageResult = 1; + else + messageResult = 0; + } else { + if (_x >= 174 && _x <= 430) + messageResult = 1; + else + messageResult = 0; + } + break; + case 0x480E: + if (param.asInteger() == 1) + stGrabRing(); + break; + case 0x4810: + swallowKlaymen(); + break; + case 0x482A: + sendMessage(_parentScene, 0x1022, 995); + break; + case 0x482B: + sendMessage(_parentScene, 0x1022, 1015); + break; + } + return messageResult; +} + +uint32 AsScene1002VenusFlyTrap::hmAnimationSimple(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x3002: + gotoNextState(); + break; + } + return messageResult; +} + +uint32 AsScene1002VenusFlyTrap::hmAnimationExt(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x100D: + if (param.asInteger() == 0x000890C4) + playSound(0, 0xC21190D8); + else if (param.asInteger() == 0x41881801) { + if (_isSecond) { + if (_x > 330) + sendMessage(_klaymen, 0x4811, 2); + else + sendMessage(_klaymen, 0x4811, 0); + } else { + sendMessage(_klaymen, 0x4811, 0); + } + } else if (param.asInteger() == 0x522200A0) + playSound(0, 0x931080C8); + break; + case 0x3002: + gotoNextState(); + break; + case 0x482A: + sendMessage(_parentScene, 0x1022, 995); + break; + case 0x482B: + sendMessage(_parentScene, 0x1022, 1015); + break; + } + return messageResult; +} + +void AsScene1002VenusFlyTrap::stWalkBack() { + setDoDeltaX(2); + startAnimation(0xC4080034, 0, -1); + SetUpdateHandler(&AsScene1002VenusFlyTrap::update); + SetMessageHandler(&AsScene1002VenusFlyTrap::hmAnimationExt); + NextState(&AsScene1002VenusFlyTrap::stIdle); +} + +void AsScene1002VenusFlyTrap::stWalk() { + startAnimation(0xC4080034, 0, -1); + SetUpdateHandler(&AsScene1002VenusFlyTrap::update); + SetMessageHandler(&AsScene1002VenusFlyTrap::hmAnimationSimple); + NextState(&AsScene1002VenusFlyTrap::stIdle); +} + +void AsScene1002VenusFlyTrap::stRelease() { + sendMessage(_parentScene, 0x4807, 0); + startAnimation(0x82292851, 0, -1); + SetUpdateHandler(&AsScene1002VenusFlyTrap::update); + SetMessageHandler(&AsScene1002VenusFlyTrap::hmAnimationSimple); + NextState(&AsScene1002VenusFlyTrap::stIdle); +} + +void AsScene1002VenusFlyTrap::stGrabRing() { + setDoDeltaX(1); + startAnimation(0x86A82A11, 0, -1); + SetUpdateHandler(&AsScene1002VenusFlyTrap::update); + SetMessageHandler(&AsScene1002VenusFlyTrap::hmAnimationSimple); + NextState(&AsScene1002VenusFlyTrap::stRingGrabbed); +} + +void AsScene1002VenusFlyTrap::stRingGrabbed() { + startAnimation(0xB5A86034, 0, -1); + SetUpdateHandler(&AsScene1002VenusFlyTrap::update); + SetMessageHandler(&AsScene1002VenusFlyTrap::handleMessage); +} + +void AsScene1002VenusFlyTrap::stKlaymenInside() { + startAnimation(0x31303094, 0, -1); + SetUpdateHandler(&AsScene1002VenusFlyTrap::update); + SetMessageHandler(NULL); + NextState(&AsScene1002VenusFlyTrap::stKlaymenInsideMoving); + _countdown = 24; +} + +void AsScene1002VenusFlyTrap::stIdle() { + startAnimation(0xC8204250, 0, -1); + SetUpdateHandler(&AsScene1002VenusFlyTrap::upIdle); + SetMessageHandler(&AsScene1002VenusFlyTrap::handleMessage); + if (_isSecond) { + if (_x >= 154 && _x <= 346) + setGlobalVar(V_FLYTRAP_POSITION_2, (_x - 186) / 32); + else { + NextState(&AsScene1002VenusFlyTrap::stWalkBack); + _countdown = 12; + } + } else { + if (_x >= 174 && _x <= 430) + setGlobalVar(V_FLYTRAP_POSITION_1, (_x - 174) / 32); + else { + NextState(&AsScene1002VenusFlyTrap::stWalkBack); + _countdown = 12; + } + } +} + +void AsScene1002VenusFlyTrap::stKlaymenInsideMoving() { + startAnimation(0x152920C4, 0, -1); + SetUpdateHandler(&AsScene1002VenusFlyTrap::update); + SetMessageHandler(&AsScene1002VenusFlyTrap::hmAnimationExt); + NextState(&AsScene1002VenusFlyTrap::stSpitOutKlaymen); +} + +void AsScene1002VenusFlyTrap::stSpitOutKlaymen() { + startAnimation(0x84001117, 0, -1); + SetUpdateHandler(&AsScene1002VenusFlyTrap::update); + SetMessageHandler(&AsScene1002VenusFlyTrap::hmAnimationExt); + NextState(&AsScene1002VenusFlyTrap::stIdle); +} + +void AsScene1002VenusFlyTrap::swallowKlaymen() { + if (_x - 15 < _klaymen->getX() && _x + 15 > _klaymen->getX()) { + if (_isSecond) + setDoDeltaX(_x > 265 && _x < 330 ? 1 : 0); + else + setDoDeltaX(_x > 320 ? 1 : 0); + sendMessage(_klaymen, 0x2001, 0); + startAnimation(0x8C2C80D4, 0, -1); + SetUpdateHandler(&AsScene1002VenusFlyTrap::update); + SetMessageHandler(&AsScene1002VenusFlyTrap::hmAnimationExt); + NextState(&AsScene1002VenusFlyTrap::stKlaymenInside); + } +} + +AsScene1002OutsideDoorBackground::AsScene1002OutsideDoorBackground(NeverhoodEngine *vm) + : AnimatedSprite(vm, 1200), _countdown(0), _isDoorClosed(true) { + + createSurface(850, 186, 212); + _x = 320; + _y = 240; + if (getGlobalVar(V_FLYTRAP_RING_DOOR)) { + startAnimation(0x004A4495, -1, -1); + _newStickFrameIndex = STICK_LAST_FRAME; + } else + setVisible(false); + SetUpdateHandler(&AsScene1002OutsideDoorBackground::update); + SetMessageHandler(&AsScene1002OutsideDoorBackground::handleMessage); +} + +void AsScene1002OutsideDoorBackground::update() { + if (_countdown != 0 && (--_countdown == 0)) { + if (_isDoorClosed) + stCloseDoor(); + else + stOpenDoor(); + } + AnimatedSprite::update(); +} + +uint32 AsScene1002OutsideDoorBackground::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageResult) { + case 0x4808: + _isDoorClosed = false; + _countdown = 2; + break; + case 0x4809: + _isDoorClosed = true; + _countdown = 2; + break; + } + return messageResult; +} + +uint32 AsScene1002OutsideDoorBackground::hmAnimation(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = handleMessage(messageNum, param, sender); + switch (messageResult) { + case 0x3002: + gotoNextState(); + break; + } + return messageResult; +} + +void AsScene1002OutsideDoorBackground::stOpenDoor() { + startAnimation(0x004A4495, 0, -1); + _newStickFrameIndex = STICK_LAST_FRAME; + setVisible(true); + SetMessageHandler(&AsScene1002OutsideDoorBackground::handleMessage); +} + +void AsScene1002OutsideDoorBackground::stCloseDoor() { + startAnimation(0x004A4495, -1, -1); + _playBackwards = true; + setVisible(true); + SetMessageHandler(&AsScene1002OutsideDoorBackground::hmAnimation); + NextState(&AsScene1002OutsideDoorBackground::stDoorClosed); +} + +void AsScene1002OutsideDoorBackground::stDoorClosed() { + setVisible(false); + stopAnimation(); +} + +AsScene1002KlaymenLadderHands::AsScene1002KlaymenLadderHands(NeverhoodEngine *vm, Klaymen *klaymen) + : AnimatedSprite(vm, 1200), _klaymen(klaymen) { + + createSurface(1200, 40, 163); + setVisible(false); + SetUpdateHandler(&AsScene1002KlaymenLadderHands::update); + SetMessageHandler(&Sprite::handleMessage); +} + +void AsScene1002KlaymenLadderHands::update() { + if (_klaymen->getCurrAnimFileHash() == 0x3A292504) { + startAnimation(0xBA280522, _klaymen->getFrameIndex(), -1); + _newStickFrameIndex = _klaymen->getFrameIndex(); + setVisible(true); + _x = _klaymen->getX(); + _y = _klaymen->getY(); + setDoDeltaX(_klaymen->isDoDeltaX() ? 1 : 0); + } else if (_klaymen->getCurrAnimFileHash() == 0x122D1505) { + startAnimation(0x1319150C, _klaymen->getFrameIndex(), -1); + _newStickFrameIndex = _klaymen->getFrameIndex(); + setVisible(true); + _x = _klaymen->getX(); + _y = _klaymen->getY(); + setDoDeltaX(_klaymen->isDoDeltaX() ? 1 : 0); + } else + setVisible(false); + AnimatedSprite::update(); +} + +AsScene1002KlaymenPeekHand::AsScene1002KlaymenPeekHand(NeverhoodEngine *vm, Scene *parentScene, Klaymen *klaymen) + : AnimatedSprite(vm, 1200), _parentScene(parentScene), _klaymen(klaymen), + _isClipRectSaved(false) { + + createSurface(1000, 33, 41); + setVisible(false); + SetUpdateHandler(&AsScene1002KlaymenPeekHand::update); + SetMessageHandler(&AsScene1002KlaymenPeekHand::handleMessage); +} + +void AsScene1002KlaymenPeekHand::update() { + if (_klaymen->getCurrAnimFileHash() == 0xAC20C012 && _klaymen->getFrameIndex() < 50) { + startAnimation(0x9820C913, _klaymen->getFrameIndex(), -1); + _newStickFrameIndex = _klaymen->getFrameIndex(); + setVisible(true); + _x = _klaymen->getX(); + _y = _klaymen->getY(); + setDoDeltaX(_klaymen->isDoDeltaX() ? 1 : 0); + } else + setVisible(false); + AnimatedSprite::update(); +} + +uint32 AsScene1002KlaymenPeekHand::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x100D: + if (param.asInteger() == 0x4AB28209) { + sendMessage(_parentScene, 0x1022, 1200); + _isClipRectSaved = true; + _savedClipRect = _surface->getClipRect(); + setClipRect(0, 0, 640, 480); + } else if (param.asInteger() == 0x88001184) { + sendMessage(_parentScene, 0x1022, 1000); + if (_isClipRectSaved) + setClipRect(_savedClipRect); + } + break; + } + return messageResult; +} + +AsScene1004TrashCan::AsScene1004TrashCan(NeverhoodEngine *vm) + : AnimatedSprite(vm, 1100) { + + _x = 330; + _y = 327; + createSurface(800, 56, 50); + setVisible(false); + SetUpdateHandler(&AnimatedSprite::update); + SetMessageHandler(&AsScene1004TrashCan::handleMessage); +} + +uint32 AsScene1004TrashCan::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x100D: + if (param.asInteger() == 0x225A8587) + playSound(0, 0x109AFC4C); + break; + case 0x2002: + startAnimation(0xEB312C11, 0, -1); + setVisible(true); + break; + case 0x3002: + stopAnimation(); + setVisible(false); + break; + } + return 0; +} + +static const KlaymenIdleTableItem klaymenIdleTable1002[] = { + {1, kIdlePickEar}, + {2, kIdleWonderAbout} +}; + +KmScene1001::KmScene1001(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) + : Klaymen(vm, parentScene, x, y) { +} + +uint32 KmScene1001::xHandleMessage(int messageNum, const MessageParam ¶m) { + switch (messageNum) { + case 0x4001: + case 0x4800: + startWalkToX(param.asPoint().x, false); + break; + case 0x4004: + GotoState(&Klaymen::stTryStandIdle); + break; + case 0x4804: + if (param.asInteger() == 2) + GotoState(&KmScene1001::stSleeping); + break; + case 0x480D: + GotoState(&KmScene1001::stPullHammerLever); + break; + case 0x4812: + GotoState(&Klaymen::stPickUpGeneric); + break; + case 0x4816: + if (param.asInteger() == 1) + GotoState(&Klaymen::stPressButton); + else if (param.asInteger() == 2) + GotoState(&Klaymen::stPressFloorButton); + else + GotoState(&Klaymen::stPressButtonSide); + break; + case 0x4817: + setDoDeltaX(param.asInteger()); + gotoNextStateExt(); + break; + case 0x481B: + if (param.asPoint().y != 0) + startWalkToXDistance(param.asPoint().y, param.asPoint().x); + else + startWalkToAttachedSpriteXDistance(param.asPoint().x); + break; + case 0x481F: + if (param.asInteger() == 0) + GotoState(&Klaymen::stWonderAboutHalf); + else if (param.asInteger() == 1) + GotoState(&Klaymen::stWonderAboutAfter); + else if (param.asInteger() == 3) + GotoState(&Klaymen::stTurnToUseHalf); + else if (param.asInteger() == 4) + GotoState(&Klaymen::stTurnAwayFromUse); + else + GotoState(&Klaymen::stWonderAbout); + break; + case 0x482D: + setDoDeltaX(_x > (int16)param.asInteger() ? 1 : 0); + gotoNextStateExt(); + break; + case 0x4836: + if (param.asInteger() == 1) { + sendMessage(_parentScene, 0x2002, 0); + GotoState(&KmScene1001::stWakeUp); + } + break; + case 0x483F: + startSpecialWalkRight(param.asInteger()); + break; + case 0x4840: + startSpecialWalkLeft(param.asInteger()); + break; + } + return 0; +} + +void KmScene1001::stWakeUp() { + _busyStatus = 1; + _acceptInput = false; + startAnimation(0x527AC970, 0, -1); + SetUpdateHandler(&Klaymen::update); + SetMessageHandler(&Klaymen::hmLowLevelAnimation); + SetSpriteUpdate(NULL); +} + +void KmScene1001::stSleeping() { + _busyStatus = 0; + _acceptInput = true; + startAnimation(0x5A38C110, 0, -1); + SetUpdateHandler(&Klaymen::update); + SetMessageHandler(&KmScene1001::hmSleeping); + SetSpriteUpdate(NULL); +} + +uint32 KmScene1001::hmSleeping(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = hmLowLevel(messageNum, param, sender); + switch (messageNum) { + case 0x100D: + if (param.asInteger() == 0x03060012) { + playSound(0, 0xC0238244); + } + break; + } + return messageResult; +} + +void KmScene1001::stPullHammerLever() { + if (!stStartAction(AnimationCallback(&KmScene1001::stPullHammerLever))) { + _busyStatus = 2; + _acceptInput = false; + startAnimation(0x00648953, 0, -1); + SetUpdateHandler(&Klaymen::update); + SetMessageHandler(&KmScene1001::hmPullHammerLever); + SetSpriteUpdate(&AnimatedSprite::updateDeltaXY); + } +} + +uint32 KmScene1001::hmPullHammerLever(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Klaymen::hmLever(messageNum, param, sender); + switch (messageNum) { + case 0x100D: + if (param.asInteger() == 0x4AB28209) + sendMessage(_attachedSprite, 0x480F, 0); + break; + } + return messageResult; +} + +KmScene1002::KmScene1002(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) + : Klaymen(vm, parentScene, x, y) { + + setKlaymenIdleTable1(); +} + +void KmScene1002::setupJumpToRing() { + _acceptInput = false; + SetUpdateHandler(&Klaymen::update); + SetMessageHandler(&KmScene1002::hmJumpToRing); + SetSpriteUpdate(&Klaymen::suUpdateDestX); + NextState(&KmScene1002::stHangOnRing); + sendMessage(_attachedSprite, 0x482B, 0); +} + +void KmScene1002::stJumpToRing1() { + if (!stStartAction(AnimationCallback(&KmScene1002::stJumpToRing1))) { + _busyStatus = 0; + startAnimation(0xD82890BA, 0, -1); + setupJumpToRing(); + } +} + +void KmScene1002::xUpdate() { + if (_x >= 250 && _x <= 435 && _y >= 420) { + if (_idleTableNum == 0) { + setKlaymenIdleTable(klaymenIdleTable1002, ARRAYSIZE(klaymenIdleTable1002)); + _idleTableNum = 1; + } + } else if (_idleTableNum == 1) { + setKlaymenIdleTable1(); + _idleTableNum = 0; + } +} + +uint32 KmScene1002::xHandleMessage(int messageNum, const MessageParam ¶m) { + switch (messageNum) { + case 0x2001: + GotoState(&Klaymen::stStandIdleSpecial); + break; + case 0x2007: + _otherSprite = (Sprite*)param.asEntity(); + break; + case 0x4001: + case 0x4800: + startWalkToX(param.asPoint().x, false); + break; + case 0x4004: + GotoState(&Klaymen::stTryStandIdle); + break; + case 0x4803: + if (param.asInteger() == 1) + GotoState(&KmScene1002::stJumpAndFall); + else if (param.asInteger() == 2) + GotoState(&KmScene1002::stDropFromRing); + break; + case 0x4804: + GotoState(&Klaymen::stPeekWall); + break; + case 0x4805: + switch (param.asInteger()) { + case 1: + GotoState(&KmScene1002::stJumpToRing1); + break; + case 2: + GotoState(&KmScene1002::stJumpToRing2); + break; + case 3: + GotoState(&KmScene1002::stJumpToRing3); + break; + case 4: + GotoState(&KmScene1002::stJumpToRing4); + break; + } + break; + case 0x480A: + GotoState(&KmScene1002::stMoveVenusFlyTrap); + break; + case 0x480D: + GotoState(&KmScene1002::stJumpToRingVenusFlyTrap); + break; + case 0x4816: + if (param.asInteger() == 0) + GotoState(&Klaymen::stPressDoorButton); + break; + case 0x4817: + setDoDeltaX(param.asInteger()); + gotoNextStateExt(); + break; + case 0x481B: + startWalkToAttachedSpriteXDistance(param.asInteger()); + break; + case 0x4820: + sendMessage(_parentScene, 0x2005, 0); + GotoState(&Klaymen::stContinueClimbLadderUp); + break; + case 0x4821: + sendMessage(_parentScene, 0x2005, 0); + _destY = param.asInteger(); + GotoState(&Klaymen::stStartClimbLadderDown); + break; + case 0x4822: + sendMessage(_parentScene, 0x2005, 0); + _destY = param.asInteger(); + GotoState(&Klaymen::stStartClimbLadderUp); + break; + case 0x4823: + sendMessage(_parentScene, 0x2006, 0); + GotoState(&Klaymen::stClimbLadderHalf); + break; + case 0x482E: + if (param.asInteger() == 1) + GotoState(&Klaymen::stWalkToFrontNoStep); + else + GotoState(&Klaymen::stWalkToFront); + break; + case 0x482F: + if (param.asInteger() == 1) + GotoState(&Klaymen::stTurnToFront); + else + GotoState(&Klaymen::stTurnToBack); + break; + case 0x483F: + startSpecialWalkRight(param.asInteger()); + break; + case 0x4840: + startSpecialWalkLeft(param.asInteger()); + break; + } + return 0; +} + +KmScene1004::KmScene1004(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) + : Klaymen(vm, parentScene, x, y) { + + _dataResource.load(0x01900A04); +} + +uint32 KmScene1004::xHandleMessage(int messageNum, const MessageParam ¶m) { + switch (messageNum) { + case 0x4001: + case 0x4800: + startWalkToX(param.asPoint().x, false); + break; + case 0x4004: + GotoState(&Klaymen::stTryStandIdle); + break; + case 0x4817: + setDoDeltaX(param.asInteger()); + gotoNextStateExt(); + break; + case 0x4818: + startWalkToX(_dataResource.getPoint(param.asInteger()).x, false); + break; + case 0x481E: + GotoState(&KmScene1004::stReadNote); + break; + case 0x4820: + sendMessage(_parentScene, 0x2000, 0); + GotoState(&Klaymen::stContinueClimbLadderUp); + break; + case 0x4821: + sendMessage(_parentScene, 0x2000, 0); + _destY = param.asInteger(); + GotoState(&Klaymen::stStartClimbLadderDown); + break; + case 0x4822: + sendMessage(_parentScene, 0x2000, 0); + _destY = param.asInteger(); + GotoState(&Klaymen::stStartClimbLadderUp); + break; + case 0x4823: + sendMessage(_parentScene, 0x2001, 0); + GotoState(&Klaymen::stClimbLadderHalf); + break; + case 0x4824: + sendMessage(_parentScene, 0x2000, 0); + _destY = _dataResource.getPoint(param.asInteger()).y; + GotoState(&Klaymen::stStartClimbLadderDown); + break; + case 0x4825: + sendMessage(_parentScene, 0x2000, 0); + _destY = _dataResource.getPoint(param.asInteger()).y; + GotoState(&Klaymen::stStartClimbLadderUp); + break; + case 0x4828: + GotoState(&Klaymen::stTurnToBackToUse); + break; + case 0x483F: + startSpecialWalkRight(param.asInteger()); + break; + case 0x4840: + startSpecialWalkLeft(param.asInteger()); + break; + } + return 0; +} + +uint32 KmScene1002::hmJumpToRing(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = hmLowLevelAnimation(messageNum, param, sender); + switch (messageNum) { + case 0x100D: + if (param.asInteger() == 0x168050A0) { + sendMessage(_attachedSprite, 0x4806, 0); + _acceptInput = true; + } else if (param.asInteger() == 0x320AC306) { + playSound(0, 0x5860C640); + } else if (param.asInteger() == 0x4AB28209) { + sendMessage(_attachedSprite, 0x482A, 0); + } else if (param.asInteger() == 0x88001184) { + sendMessage(_attachedSprite, 0x482B, 0); + } + break; + } + return messageResult; +} + +void KmScene1002::stHangOnRing() { + _busyStatus = 0; + _acceptInput = true; + startAnimation(0x4829E0B8, 0, -1); + SetUpdateHandler(&Klaymen::update); + SetMessageHandler(&Klaymen::hmLowLevel); + SetSpriteUpdate(NULL); +} + +void KmScene1002::stJumpToRing2() { + if (!stStartAction(AnimationCallback(&KmScene1002::stJumpToRing2))) { + _busyStatus = 0; + startAnimation(0x900980B2, 0, -1); + setupJumpToRing(); + } +} + +void KmScene1002::stJumpToRing3() { + if (!stStartAction(AnimationCallback(&KmScene1002::stJumpToRing3))) { + _busyStatus = 0; + _acceptInput = false; + startAnimation(0xBA1910B2, 0, -1); + SetUpdateHandler(&Klaymen::update); + SetSpriteUpdate(&Klaymen::suUpdateDestX); + SetMessageHandler(&KmScene1002::hmJumpToRing3); + NextState(&KmScene1002::stHoldRing3); + sendMessage(_attachedSprite, 0x482B, 0); + } +} + +uint32 KmScene1002::hmJumpToRing3(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = hmLowLevelAnimation(messageNum, param, sender); + switch (messageNum) { + case 0x100D: + if (param.asInteger() == 0x168050A0) { + sendMessage(_attachedSprite, 0x4806, 0); + } else if (param.asInteger() == 0x320AC306) { + playSound(0, 0x5860C640); + } else if (param.asInteger() == 0x4AB28209) { + sendMessage(_attachedSprite, 0x482A, 0); + } else if (param.asInteger() == 0x88001184) { + sendMessage(_attachedSprite, 0x482B, 0); + } + break; + } + return messageResult; +} + +void KmScene1002::stHoldRing3() { + _busyStatus = 0; + _acceptInput = true; + startAnimation(0x4A293FB0, 0, -1); + SetUpdateHandler(&Klaymen::update); + SetMessageHandler(&KmScene1002::hmHoldRing3); + SetSpriteUpdate(NULL); +} + +uint32 KmScene1002::hmHoldRing3(int messageNum, const MessageParam ¶m, Entity *sender) { + if (messageNum == 0x1008) { + stReleaseRing(); + return 0; + } + return hmLowLevel(messageNum, param, sender); +} + +void KmScene1002::stJumpToRing4() { + if (!stStartAction(AnimationCallback(&KmScene1002::stJumpToRing4))) { + _busyStatus = 0; + startAnimation(0xB8699832, 0, -1); + setupJumpToRing(); + } +} + +void KmScene1002::stJumpToRingVenusFlyTrap() { + if (!stStartAction(AnimationCallback(&KmScene1002::stJumpToRingVenusFlyTrap))) { + _busyStatus = 2; + _acceptInput = false; + startAnimation(0x584984B4, 0, -1); + SetUpdateHandler(&Klaymen::update); + SetMessageHandler(&KmScene1002::hmJumpToRingVenusFlyTrap); + SetSpriteUpdate(&AnimatedSprite::updateDeltaXY); + NextState(&KmScene1002::stLandOnFeet); + sendMessage(_attachedSprite, 0x482B, 0); + } +} + +uint32 KmScene1002::hmJumpToRingVenusFlyTrap(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = hmLowLevelAnimation(messageNum, param, sender); + switch (messageNum) { + case 0x100D: + if (param.asInteger() == 0x168050A0) { + sendMessage(_attachedSprite, 0x480F, 0); + } else if (param.asInteger() == 0x586B0300) { + sendMessage(_otherSprite, 0x480E, 1); + } else if (param.asInteger() == 0x4AB28209) { + sendMessage(_attachedSprite, 0x482A, 0); + } else if (param.asInteger() == 0x88001184) { + sendMessage(_attachedSprite, 0x482B, 0); + } + break; + } + return messageResult; +} + +void KmScene1002::stJumpAndFall() { + if (!stStartAction(AnimationCallback(&KmScene1002::stJumpAndFall))) { + sendMessage(_parentScene, 0x1024, 3); + _busyStatus = 2; + _acceptInput = false; + startAnimation(0xB93AB151, 0, -1); + SetUpdateHandler(&Klaymen::update); + SetMessageHandler(&KmScene1002::hmJumpAndFall); + SetSpriteUpdate(&Klaymen::suFallDown); + NextState(&KmScene1002::stLandOnFeet); + } +} + +void KmScene1002::stDropFromRing() { + if (_attachedSprite) { + _x = _attachedSprite->getX(); + sendMessage(_attachedSprite, 0x4807, 0); + _attachedSprite = NULL; + } + _busyStatus = 2; + _acceptInput = false; + startAnimation(0x586984B1, 0, -1); + SetUpdateHandler(&Klaymen::update); + SetMessageHandler(&Klaymen::hmLowLevel); + SetSpriteUpdate(&Klaymen::suFallDown); + NextState(&KmScene1002::stLandOnFeet); +} + +uint32 KmScene1002::hmJumpAndFall(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = hmLowLevel(messageNum, param, sender); + switch (messageNum) { + case 0x100D: + if (param.asInteger() == 0x1307050A) { + playSound(0, 0x40428A09); + } + break; + } + return messageResult; +} + +void KmScene1002::stMoveVenusFlyTrap() { + if (!stStartAction(AnimationCallback(&KmScene1002::stMoveVenusFlyTrap))) { + _busyStatus = 2; + _isMoveObjectRequested = false; + _acceptInput = true; + setDoDeltaX(_attachedSprite->getX() < _x ? 1 : 0); + startAnimation(0x5C01A870, 0, -1); + SetUpdateHandler(&Klaymen::update); + SetMessageHandler(&KmScene1002::hmMoveVenusFlyTrap); + SetSpriteUpdate(&AnimatedSprite::updateDeltaXY); + FinalizeState(&KmScene1002::evMoveVenusFlyTrapDone); + } +} + +void KmScene1002::stContinueMovingVenusFlyTrap() { + _isMoveObjectRequested = false; + _acceptInput = true; + startAnimationByHash(0x5C01A870, 0x01084280, 0); + SetUpdateHandler(&Klaymen::update); + SetMessageHandler(&KmScene1002::hmMoveVenusFlyTrap); + SetSpriteUpdate(&AnimatedSprite::updateDeltaXY); + FinalizeState(&KmScene1002::evMoveVenusFlyTrapDone); +} + +void KmScene1002::evMoveVenusFlyTrapDone() { + sendMessage(_attachedSprite, 0x482A, 0); +} + +uint32 KmScene1002::hmMoveVenusFlyTrap(int messageNum, const MessageParam ¶m, Entity *sender) { + switch (messageNum) { + case 0x100D: + if (param.asInteger() == 0x01084280) { + sendMessage(_attachedSprite, 0x480B, (uint32)_doDeltaX); + } else if (param.asInteger() == 0x02421405) { + if (_isMoveObjectRequested) { + if (sendMessage(_attachedSprite, 0x480C, (uint32)_doDeltaX) != 0) + stContinueMovingVenusFlyTrap(); + } else { + SetMessageHandler(&KmScene1002::hmFirstMoveVenusFlyTrap); + } + } else if (param.asInteger() == 0x4AB28209) { + sendMessage(_attachedSprite, 0x482A, 0); + } else if (param.asInteger() == 0x88001184) { + sendMessage(_attachedSprite, 0x482B, 0); + } else if (param.asInteger() == 0x32180101) { + playSound(0, 0x405002D8); + } else if (param.asInteger() == 0x0A2A9098) { + playSound(0, 0x0460E2FA); + } + break; + case 0x480A: + _isMoveObjectRequested = true; + return 0; + } + return hmLowLevelAnimation(messageNum, param, sender); +} + +uint32 KmScene1002::hmFirstMoveVenusFlyTrap(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = hmLowLevelAnimation(messageNum, param, sender); + switch (messageNum) { + case 0x100D: + if (param.asInteger() == 0x4AB28209) { + sendMessage(_attachedSprite, 0x482A, 0); + } else if (param.asInteger() == 0x88001184) { + sendMessage(_attachedSprite, 0x482B, 0); + } else if (param.asInteger() == 0x32180101) { + playSound(0, 0x405002D8); + } else if (param.asInteger() == 0x0A2A9098) { + playSound(0, 0x0460E2FA); + } + break; + } + return messageResult; +} + +uint32 KmScene1004::hmReadNote(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = hmLowLevelAnimation(messageNum, param, sender); + switch (messageNum) { + case 0x100D: + if (param.asInteger() == 0x04684052) { + _acceptInput = true; + sendMessage(_parentScene, 0x2002, 0); + } + break; + } + return messageResult; +} + +void KmScene1004::stReadNote() { + _busyStatus = 2; + _acceptInput = false; + startAnimation(0x123E9C9F, 0, -1); + SetUpdateHandler(&Klaymen::update); + SetMessageHandler(&KmScene1004::hmReadNote); + SetSpriteUpdate(&AnimatedSprite::updateDeltaXY); +} + +} // End of namespace Neverhood diff --git a/engines/neverhood/modules/module1000_sprites.h b/engines/neverhood/modules/module1000_sprites.h new file mode 100644 index 0000000000..540a258ddc --- /dev/null +++ b/engines/neverhood/modules/module1000_sprites.h @@ -0,0 +1,257 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef NEVERHOOD_MODULES_MODULE1000_SPRITES_H +#define NEVERHOOD_MODULES_MODULE1000_SPRITES_H + +#include "neverhood/neverhood.h" +#include "neverhood/module.h" +#include "neverhood/scene.h" + +namespace Neverhood { + +class AsScene1001Door : public AnimatedSprite { +public: + AsScene1001Door(NeverhoodEngine *vm); +protected: + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); + void hammerHitsDoor(); + void stShowIdleDoor(); + void stBustedDoorMove(); + void stBustedDoorGone(); +}; + +class AsScene1001Hammer : public AnimatedSprite { +public: + AsScene1001Hammer(NeverhoodEngine *vm, Sprite *asDoor); +protected: + Sprite *_asDoor; + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); +}; + +class AsScene1001Window : public AnimatedSprite { +public: + AsScene1001Window(NeverhoodEngine *vm); +protected: + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); +}; + +class AsScene1001Lever : public AnimatedSprite { +public: + AsScene1001Lever(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y, int deltaXType); +protected: + Scene *_parentScene; + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); +}; + +class SsCommonButtonSprite : public StaticSprite { +public: + SsCommonButtonSprite(NeverhoodEngine *vm, Scene *parentScene, uint32 fileHash, int surfacePriority, uint32 soundFileHash); +protected: + Scene *_parentScene; + uint32 _soundFileHash; + int16 _countdown; + void update(); + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); +}; + +class AsScene1002Ring : public AnimatedSprite { +public: + AsScene1002Ring(NeverhoodEngine *vm, Scene *parentScene, bool isSpecial, int16 x, int16 y, int16 clipY1, bool isRingLow); +protected: + Scene *_parentScene; + bool _isSpecial; + void update(); + uint32 hmRingIdle(int messageNum, const MessageParam ¶m, Entity *sender); + uint32 hmRingPulled1(int messageNum, const MessageParam ¶m, Entity *sender); + uint32 hmRingPulled2(int messageNum, const MessageParam ¶m, Entity *sender); + uint32 hmRingHangingLow(int messageNum, const MessageParam ¶m, Entity *sender); + uint32 hmRingReleased(int messageNum, const MessageParam ¶m, Entity *sender); +}; + +class AsScene1002Door : public StaticSprite { +public: + AsScene1002Door(NeverhoodEngine *vm, NRect &clipRect); +protected: + void update(); + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); + void suOpenDoor(); + void suCloseDoor(); +}; + +class AsScene1002BoxingGloveHitEffect : public AnimatedSprite { +public: + AsScene1002BoxingGloveHitEffect(NeverhoodEngine *vm); +protected: + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); +}; + +class AsScene1002DoorSpy : public AnimatedSprite { +public: + AsScene1002DoorSpy(NeverhoodEngine *vm, NRect &clipRect, Scene *parentScene, Sprite *asDoor, Sprite *asScene1002BoxingGloveHitEffect); +protected: + Scene *_parentScene; + Sprite *_asDoor; + Sprite *_asBoxingGloveHitEffect; + NRect _clipRect; + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); + uint32 hmDoorSpyAnimation(int messageNum, const MessageParam ¶m, Entity *sender); + void suDoorSpy(); + void stDoorSpyIdle(); + void stDoorSpyBoxingGlove(); +}; + +class SsCommonPressButton : public StaticSprite { +public: + SsCommonPressButton(NeverhoodEngine *vm, Scene *parentScene, uint32 fileHash1, uint32 fileHash2, int surfacePriority, uint32 soundFileHash); + void setFileHashes(uint32 fileHash1, uint32 fileHash2); +protected: + Scene *_parentScene; + uint32 _soundFileHash; + uint32 _fileHashes[2]; + int _status; + int _countdown; + void update(); + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); +}; + +class AsScene1002VenusFlyTrap : public AnimatedSprite { +public: + AsScene1002VenusFlyTrap(NeverhoodEngine *vm, Scene *parentScene, Sprite *klaymen, bool isSecond); +protected: + Scene *_parentScene; + Sprite *_klaymen; + int _countdown; + bool _isSecond; + void update(); + void upIdle(); + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); + uint32 hmAnimationSimple(int messageNum, const MessageParam ¶m, Entity *sender); + uint32 hmAnimationExt(int messageNum, const MessageParam ¶m, Entity *sender); + void stWalkBack(); + void stWalk(); + void stRelease(); + void stGrabRing(); + void stRingGrabbed(); + void stKlaymenInside(); + void stIdle(); + void stKlaymenInsideMoving(); + void stSpitOutKlaymen(); + void swallowKlaymen(); +}; + +class AsScene1002OutsideDoorBackground : public AnimatedSprite { +public: + AsScene1002OutsideDoorBackground(NeverhoodEngine *vm); +protected: + int _countdown; + bool _isDoorClosed; + void update(); + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); + uint32 hmAnimation(int messageNum, const MessageParam ¶m, Entity *sender); + void stOpenDoor(); + void stCloseDoor(); + void stDoorClosed(); +}; + +class AsScene1002KlaymenLadderHands : public AnimatedSprite { +public: + AsScene1002KlaymenLadderHands(NeverhoodEngine *vm, Klaymen *klaymen); +protected: + Klaymen *_klaymen; + void update(); +}; + +class AsScene1002KlaymenPeekHand : public AnimatedSprite { +public: + AsScene1002KlaymenPeekHand(NeverhoodEngine *vm, Scene *parentScene, Klaymen *klaymen); +protected: + Scene *_parentScene; + Klaymen *_klaymen; + bool _isClipRectSaved; + NRect _savedClipRect; + void update(); + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); +}; + +class AsScene1004TrashCan : public AnimatedSprite { +public: + AsScene1004TrashCan(NeverhoodEngine *vm); +protected: + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); +}; + +class KmScene1001 : public Klaymen { +public: + KmScene1001(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); +protected: + void stWakeUp(); + void stSleeping(); + void stPullHammerLever(); + uint32 hmSleeping(int messageNum, const MessageParam ¶m, Entity *sender); + uint32 hmPullHammerLever(int messageNum, const MessageParam ¶m, Entity *sender); + + uint32 xHandleMessage(int messageNum, const MessageParam ¶m); +}; + +class KmScene1002 : public Klaymen { +public: + KmScene1002(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); +protected: + void stJumpToRing1(); + void stJumpToRing2(); + void stJumpToRing3(); + void stJumpToRing4(); + void setupJumpToRing(); + void stHangOnRing(); + void stHoldRing3(); + void stDropFromRing(); + void stJumpToRingVenusFlyTrap(); + void stJumpAndFall(); + void stMoveVenusFlyTrap(); + void stContinueMovingVenusFlyTrap(); + void evMoveVenusFlyTrapDone(); + + uint32 hmJumpToRing(int messageNum, const MessageParam ¶m, Entity *sender); + uint32 hmJumpToRing3(int messageNum, const MessageParam ¶m, Entity *sender); + uint32 hmHoldRing3(int messageNum, const MessageParam ¶m, Entity *sender); + uint32 hmJumpToRingVenusFlyTrap(int messageNum, const MessageParam ¶m, Entity *sender); + uint32 hmJumpAndFall(int messageNum, const MessageParam ¶m, Entity *sender); + uint32 hmMoveVenusFlyTrap(int messageNum, const MessageParam ¶m, Entity *sender); + uint32 hmFirstMoveVenusFlyTrap(int messageNum, const MessageParam ¶m, Entity *sender); + + void xUpdate(); + uint32 xHandleMessage(int messageNum, const MessageParam ¶m); +}; + +class KmScene1004 : public Klaymen { +public: + KmScene1004(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); +protected: + void stReadNote(); + uint32 hmReadNote(int messageNum, const MessageParam ¶m, Entity *sender); + uint32 xHandleMessage(int messageNum, const MessageParam ¶m); +}; + +} // End of namespace Neverhood + +#endif /* NEVERHOOD_MODULES_MODULE1000_SPRITES_H */ diff --git a/engines/neverhood/modules/module1100.cpp b/engines/neverhood/modules/module1100.cpp index faa0516d7e..af2df2e742 100644 --- a/engines/neverhood/modules/module1100.cpp +++ b/engines/neverhood/modules/module1100.cpp @@ -20,9 +20,10 @@ * */ -#include "neverhood/modules/module1100.h" #include "neverhood/gamemodule.h" #include "neverhood/navigationscene.h" +#include "neverhood/modules/module1100.h" +#include "neverhood/modules/module1100_sprites.h" namespace Neverhood { @@ -236,6 +237,13 @@ void Module1100::updateScene() { } } +static const uint32 kScene1105BackgroundFileHashes[] = { + 0x20018662, + 0x20014202, + 0x20012202, + 0x20010002 // CHECKME: This used ?? +}; + static const uint32 kScene1105FileHashes[] = { 0x00028006, 0x0100A425, @@ -249,186 +257,6 @@ static const uint32 kScene1105FileHashes[] = { 0xB14A891E }; -static const uint32 kScene1105BackgroundFileHashes[] = { - 0x20018662, - 0x20014202, - 0x20012202, - 0x20010002 // CHECKME: This used ?? -}; - -static const uint32 kSsScene1105SymbolDieFileHashes[] = { - 0, - 0x90898414, - 0x91098414, - 0x92098414, - 0x94098414, - 0x98098414, - 0x80098414, - 0xB0098414, - 0xD0098414, - 0x10098414 -}; - -SsScene1105Button::SsScene1105Button(NeverhoodEngine *vm, Scene *parentScene, uint32 fileHash, NRect &collisionBounds) - : StaticSprite(vm, fileHash, 200), _parentScene(parentScene), _countdown(0) { - - _collisionBounds = collisionBounds; - SetMessageHandler(&SsScene1105Button::handleMessage); - SetUpdateHandler(&SsScene1105Button::update); - setVisible(false); -} - -void SsScene1105Button::update() { - if (_countdown != 0 && (--_countdown == 0)) { - sendMessage(_parentScene, 0x4807, 0); - setVisible(false); - } -} - -uint32 SsScene1105Button::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x1011: - if (_countdown == 0) { - sendMessage(_parentScene, 0x4826, 0); - messageResult = 1; - } - break; - case 0x480B: - _countdown = 8; - setVisible(true); - playSound(0, 0x44141000); - break; - } - return messageResult; -} - -SsScene1105Symbol::SsScene1105Symbol(NeverhoodEngine *vm, uint32 fileHash, int16 x, int16 y) - : StaticSprite(vm, 0) { - - loadSprite(fileHash, kSLFCenteredDrawOffset | kSLFSetPosition, 200, x, y); -} - -void SsScene1105Symbol::hide() { - setVisible(false); - _needRefresh = true; - updatePosition(); -} - -SsScene1105SymbolDie::SsScene1105SymbolDie(NeverhoodEngine *vm, uint dieIndex, int16 x, int16 y) - : StaticSprite(vm, 1100), _dieIndex(dieIndex) { - - _x = x; - _y = y; - createSurface(200, 50, 50); - loadSymbolSprite(); - SetMessageHandler(&SsScene1105SymbolDie::handleMessage); -} - -uint32 SsScene1105SymbolDie::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x2000: - loadSymbolSprite(); - break; - } - return messageResult; -} - -void SsScene1105SymbolDie::loadSymbolSprite() { - loadSprite(kSsScene1105SymbolDieFileHashes[getSubVar(VA_CURR_DICE_NUMBERS, _dieIndex)], kSLFCenteredDrawOffset); -} - -void SsScene1105SymbolDie::hide() { - setVisible(false); - _needRefresh = true; - updatePosition(); -} - -AsScene1105TeddyBear::AsScene1105TeddyBear(NeverhoodEngine *vm, Scene *parentScene) - : AnimatedSprite(vm, 1100), _parentScene(parentScene) { - - createSurface(100, 556, 328); - _x = 320; - _y = 240; - SetUpdateHandler(&AnimatedSprite::update); - SetMessageHandler(&AsScene1105TeddyBear::handleMessage); - startAnimation(0x65084002, 0, -1); - _newStickFrameIndex = 0; - setVisible(false); - _needRefresh = true; - updatePosition(); - loadSound(0, 0xCE840261); - loadSound(1, 0xCCA41A62); -} - -uint32 AsScene1105TeddyBear::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x2002: - if (getGlobalVar(V_ROBOT_TARGET)) { - startAnimation(0x6B0C0432, 0, -1); - playSound(0); - } else { - startAnimation(0x65084002, 0, -1); - playSound(1); - } - break; - case 0x3002: - sendMessage(_parentScene, 0x2003, 0); - stopAnimation(); - break; - } - return messageResult; -} - -void AsScene1105TeddyBear::show() { - setVisible(true); - _needRefresh = true; - updatePosition(); -} - -void AsScene1105TeddyBear::hide() { - setVisible(false); - _needRefresh = true; - updatePosition(); -} - -SsScene1105OpenButton::SsScene1105OpenButton(NeverhoodEngine *vm, Scene *parentScene) - : StaticSprite(vm, 900), _parentScene(parentScene), _countdown(0), _isClicked(false) { - - loadSprite(0x8228A46C, kSLFDefDrawOffset | kSLFDefPosition | kSLFDefCollisionBoundsOffset, 400); - setVisible(false); - loadSound(0, 0x44045140); - SetUpdateHandler(&SsScene1105OpenButton::update); - SetMessageHandler(&SsScene1105OpenButton::handleMessage); -} - -void SsScene1105OpenButton::update() { - updatePosition(); - if (_countdown != 0 && (--_countdown == 0)) { - setVisible(false); - sendMessage(_parentScene, 0x2001, 0); - } -} - -uint32 SsScene1105OpenButton::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = 0; - Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x1011: - if (_countdown == 0 && !_isClicked) { - playSound(0); - setVisible(true); - _isClicked = true; - _countdown = 4; - } - messageResult = 1; - break; - } - return messageResult; -} - Scene1105::Scene1105(NeverhoodEngine *vm, Module *parentModule) : Scene(vm, parentModule), _countdown(0), _isPanelOpen(false), _isActionButtonClicked(false), _doMoveTeddy(false), _isClosePanelDone(false), _leaveResult(0), _backgroundIndex(0) { diff --git a/engines/neverhood/modules/module1100.h b/engines/neverhood/modules/module1100.h index 373f6b703f..38bac1f298 100644 --- a/engines/neverhood/modules/module1100.h +++ b/engines/neverhood/modules/module1100.h @@ -29,8 +29,6 @@ namespace Neverhood { -// Module1100 - class Module1100 : public Module { public: Module1100(NeverhoodEngine *vm, Module *parentModule, int which); @@ -42,52 +40,9 @@ protected: void updateScene(); }; -class SsScene1105Button : public StaticSprite { -public: - SsScene1105Button(NeverhoodEngine *vm, Scene *parentScene, uint32 fileHash, NRect &collisionBounds); -protected: - Scene *_parentScene; - int _countdown; - void update(); - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); -}; - -class SsScene1105Symbol : public StaticSprite { -public: - SsScene1105Symbol(NeverhoodEngine *vm, uint32 fileHash, int16 x, int16 y); - void hide(); -}; - -class SsScene1105SymbolDie : public StaticSprite { -public: - SsScene1105SymbolDie(NeverhoodEngine *vm, uint dieIndex, int16 x, int16 y); - void hide(); -protected: - uint _dieIndex; - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); - void loadSymbolSprite(); -}; - -class AsScene1105TeddyBear : public AnimatedSprite { -public: - AsScene1105TeddyBear(NeverhoodEngine *vm, Scene *parentScene); - void show(); - void hide(); -protected: - Scene *_parentScene; - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); -}; - -class SsScene1105OpenButton : public StaticSprite { -public: - SsScene1105OpenButton(NeverhoodEngine *vm, Scene *parentScene); -protected: - Scene *_parentScene; - int _countdown; - bool _isClicked; - void update(); - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); -}; +class AsScene1105TeddyBear; +class SsScene1105Symbol; +class SsScene1105SymbolDie; class Scene1105 : public Scene { public: diff --git a/engines/neverhood/modules/module1100_sprites.cpp b/engines/neverhood/modules/module1100_sprites.cpp new file mode 100644 index 0000000000..51e0bb3f49 --- /dev/null +++ b/engines/neverhood/modules/module1100_sprites.cpp @@ -0,0 +1,265 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "neverhood/modules/module1100_sprites.h" + +namespace Neverhood { + +static const uint32 kSsScene1105SymbolDieFileHashes[] = { + 0, + 0x90898414, + 0x91098414, + 0x92098414, + 0x94098414, + 0x98098414, + 0x80098414, + 0xB0098414, + 0xD0098414, + 0x10098414 +}; + +SsScene1105Button::SsScene1105Button(NeverhoodEngine *vm, Scene *parentScene, uint32 fileHash, NRect &collisionBounds) + : StaticSprite(vm, fileHash, 200), _parentScene(parentScene), _countdown(0) { + + _collisionBounds = collisionBounds; + SetMessageHandler(&SsScene1105Button::handleMessage); + SetUpdateHandler(&SsScene1105Button::update); + setVisible(false); +} + +void SsScene1105Button::update() { + if (_countdown != 0 && (--_countdown == 0)) { + sendMessage(_parentScene, 0x4807, 0); + setVisible(false); + } +} + +uint32 SsScene1105Button::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x1011: + if (_countdown == 0) { + sendMessage(_parentScene, 0x4826, 0); + messageResult = 1; + } + break; + case 0x480B: + _countdown = 8; + setVisible(true); + playSound(0, 0x44141000); + break; + } + return messageResult; +} + +SsScene1105Symbol::SsScene1105Symbol(NeverhoodEngine *vm, uint32 fileHash, int16 x, int16 y) + : StaticSprite(vm, 0) { + + loadSprite(fileHash, kSLFCenteredDrawOffset | kSLFSetPosition, 200, x, y); +} + +void SsScene1105Symbol::hide() { + setVisible(false); + _needRefresh = true; + updatePosition(); +} + +SsScene1105SymbolDie::SsScene1105SymbolDie(NeverhoodEngine *vm, uint dieIndex, int16 x, int16 y) + : StaticSprite(vm, 1100), _dieIndex(dieIndex) { + + _x = x; + _y = y; + createSurface(200, 50, 50); + loadSymbolSprite(); + SetMessageHandler(&SsScene1105SymbolDie::handleMessage); +} + +uint32 SsScene1105SymbolDie::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x2000: + loadSymbolSprite(); + break; + } + return messageResult; +} + +void SsScene1105SymbolDie::loadSymbolSprite() { + loadSprite(kSsScene1105SymbolDieFileHashes[getSubVar(VA_CURR_DICE_NUMBERS, _dieIndex)], kSLFCenteredDrawOffset); +} + +void SsScene1105SymbolDie::hide() { + setVisible(false); + _needRefresh = true; + updatePosition(); +} + +AsScene1105TeddyBear::AsScene1105TeddyBear(NeverhoodEngine *vm, Scene *parentScene) + : AnimatedSprite(vm, 1100), _parentScene(parentScene) { + + createSurface(100, 556, 328); + _x = 320; + _y = 240; + SetUpdateHandler(&AnimatedSprite::update); + SetMessageHandler(&AsScene1105TeddyBear::handleMessage); + startAnimation(0x65084002, 0, -1); + _newStickFrameIndex = 0; + setVisible(false); + _needRefresh = true; + updatePosition(); + loadSound(0, 0xCE840261); + loadSound(1, 0xCCA41A62); +} + +uint32 AsScene1105TeddyBear::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x2002: + if (getGlobalVar(V_ROBOT_TARGET)) { + startAnimation(0x6B0C0432, 0, -1); + playSound(0); + } else { + startAnimation(0x65084002, 0, -1); + playSound(1); + } + break; + case 0x3002: + sendMessage(_parentScene, 0x2003, 0); + stopAnimation(); + break; + } + return messageResult; +} + +void AsScene1105TeddyBear::show() { + setVisible(true); + _needRefresh = true; + updatePosition(); +} + +void AsScene1105TeddyBear::hide() { + setVisible(false); + _needRefresh = true; + updatePosition(); +} + +SsScene1105OpenButton::SsScene1105OpenButton(NeverhoodEngine *vm, Scene *parentScene) + : StaticSprite(vm, 900), _parentScene(parentScene), _countdown(0), _isClicked(false) { + + loadSprite(0x8228A46C, kSLFDefDrawOffset | kSLFDefPosition | kSLFDefCollisionBoundsOffset, 400); + setVisible(false); + loadSound(0, 0x44045140); + SetUpdateHandler(&SsScene1105OpenButton::update); + SetMessageHandler(&SsScene1105OpenButton::handleMessage); +} + +void SsScene1105OpenButton::update() { + updatePosition(); + if (_countdown != 0 && (--_countdown == 0)) { + setVisible(false); + sendMessage(_parentScene, 0x2001, 0); + } +} + +uint32 SsScene1105OpenButton::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = 0; + Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x1011: + if (_countdown == 0 && !_isClicked) { + playSound(0); + setVisible(true); + _isClicked = true; + _countdown = 4; + } + messageResult = 1; + break; + } + return messageResult; +} + +KmScene1109::KmScene1109(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) + : Klaymen(vm, parentScene, x, y) { + + // Empty +} + +uint32 KmScene1109::xHandleMessage(int messageNum, const MessageParam ¶m) { + uint32 messageResult = 0; + switch (messageNum) { + case 0x2000: + _isSittingInTeleporter = param.asInteger() != 0; + messageResult = 1; + break; + case 0x4001: + case 0x4800: + startWalkToX(param.asPoint().x, false); + break; + case 0x4004: + if (_isSittingInTeleporter) + GotoState(&Klaymen::stSitIdleTeleporter); + else + GotoState(&Klaymen::stTryStandIdle); + break; + case 0x4804: + if (param.asInteger() != 0) { + _destX = param.asInteger(); + GotoState(&Klaymen::stWalkingFirst); + } else + GotoState(&Klaymen::stPeekWall); + break; + case 0x4817: + setDoDeltaX(param.asInteger()); + gotoNextStateExt(); + break; + case 0x481D: + if (_isSittingInTeleporter) + GotoState(&Klaymen::stTurnToUseInTeleporter); + break; + case 0x481E: + if (_isSittingInTeleporter) + GotoState(&Klaymen::stReturnFromUseInTeleporter); + break; + case 0x4834: + GotoState(&Klaymen::stStepOver); + break; + case 0x4835: + sendMessage(_parentScene, 0x2000, 1); + _isSittingInTeleporter = true; + GotoState(&Klaymen::stSitInTeleporter); + break; + case 0x4836: + sendMessage(_parentScene, 0x2000, 0); + _isSittingInTeleporter = false; + GotoState(&Klaymen::stGetUpFromTeleporter); + break; + case 0x483D: + teleporterAppear(0x2C2A4A1C); + break; + case 0x483E: + teleporterDisappear(0x3C2E4245); + break; + } + return messageResult; +} + +} // End of namespace Neverhood diff --git a/engines/neverhood/modules/module1100_sprites.h b/engines/neverhood/modules/module1100_sprites.h new file mode 100644 index 0000000000..c8e5a838da --- /dev/null +++ b/engines/neverhood/modules/module1100_sprites.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 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef NEVERHOOD_MODULES_MODULE1100_SPRITES_H +#define NEVERHOOD_MODULES_MODULE1100_SPRITES_H + +#include "neverhood/neverhood.h" +#include "neverhood/module.h" +#include "neverhood/scene.h" + +namespace Neverhood { + +class SsScene1105Button : public StaticSprite { +public: + SsScene1105Button(NeverhoodEngine *vm, Scene *parentScene, uint32 fileHash, NRect &collisionBounds); +protected: + Scene *_parentScene; + int _countdown; + void update(); + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); +}; + +class SsScene1105Symbol : public StaticSprite { +public: + SsScene1105Symbol(NeverhoodEngine *vm, uint32 fileHash, int16 x, int16 y); + void hide(); +}; + +class SsScene1105SymbolDie : public StaticSprite { +public: + SsScene1105SymbolDie(NeverhoodEngine *vm, uint dieIndex, int16 x, int16 y); + void hide(); +protected: + uint _dieIndex; + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); + void loadSymbolSprite(); +}; + +class AsScene1105TeddyBear : public AnimatedSprite { +public: + AsScene1105TeddyBear(NeverhoodEngine *vm, Scene *parentScene); + void show(); + void hide(); +protected: + Scene *_parentScene; + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); +}; + +class SsScene1105OpenButton : public StaticSprite { +public: + SsScene1105OpenButton(NeverhoodEngine *vm, Scene *parentScene); +protected: + Scene *_parentScene; + int _countdown; + bool _isClicked; + void update(); + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); +}; + +class KmScene1109 : public Klaymen { +public: + KmScene1109(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); +protected: + uint32 xHandleMessage(int messageNum, const MessageParam ¶m); +}; + +} // End of namespace Neverhood + +#endif /* NEVERHOOD_MODULES_MODULE1100_SPRITES_H */ diff --git a/engines/neverhood/modules/module1200.cpp b/engines/neverhood/modules/module1200.cpp index e7766419f9..975545091d 100644 --- a/engines/neverhood/modules/module1200.cpp +++ b/engines/neverhood/modules/module1200.cpp @@ -21,6 +21,7 @@ */ #include "neverhood/modules/module1200.h" +#include "neverhood/modules/module1200_sprites.h" namespace Neverhood { @@ -92,566 +93,10 @@ void Module1200::updateScene() { } } -// Scene1201 - static const uint32 kScene1201InitArray[] = { 1, 0, 2, 4, 5, 3, 6, 7, 8, 10, 9, 11, 13, 14, 12, 16, 17, 15 }; -static const NPoint kScene1201PointArray[] = { - {218, 193}, {410, 225}, {368, 277}, - {194, 227}, {366, 174}, {458, 224}, - {242, 228}, {512, 228}, {458, 277}, - {217, 233}, {458, 173}, {410, 276}, - {203, 280}, {371, 226}, {508, 279}, - {230, 273}, {410, 171}, {493, 174} -}; - -static const uint32 kScene1201TntFileHashList1[] = { - 0x2098212D, 0x1600437E, 0x1600437E, - 0x00A840E3, 0x1A1830F6, 0x1A1830F6, - 0x00212062, 0x384010B6, 0x384010B6, - 0x07A01080, 0xD80C2837, 0xD80C2837, - 0x03A22092, 0xD8802CB6, 0xD8802CB6, - 0x03A93831, 0xDA460476, 0xDA460476 -}; - -static const uint32 kScene1201TntFileHashList2[] = { - 0x3040C676, 0x10914448, 0x10914448, - 0x3448A066, 0x1288C049, 0x1288C049, - 0x78C0E026, 0x3098D05A, 0x3098D05A, - 0x304890E6, 0x1284E048, 0x1284E048, - 0xB140A1E6, 0x5088A068, 0x5088A068, - 0x74C4C866, 0x3192C059, 0x3192C059 -}; - -SsScene1201Tnt::SsScene1201Tnt(NeverhoodEngine *vm, uint32 elemIndex, uint32 pointIndex, int16 clipY2) - : StaticSprite(vm, 900) { - - int16 x = kScene1201PointArray[pointIndex].x; - int16 y = kScene1201PointArray[pointIndex].y; - if (x < 300) - loadSprite(kScene1201TntFileHashList1[elemIndex], kSLFDefDrawOffset | kSLFDefPosition, 50); - else - loadSprite(kScene1201TntFileHashList2[elemIndex], kSLFCenteredDrawOffset | kSLFSetPosition, 50, x, y - 20); - setClipRect(0, 0, 640, clipY2); -} - -AsScene1201Tape::AsScene1201Tape(NeverhoodEngine *vm, Scene *parentScene, uint32 nameHash, int surfacePriority, int16 x, int16 y, uint32 fileHash) - : AnimatedSprite(vm, fileHash, surfacePriority, x, y), _parentScene(parentScene), _nameHash(nameHash) { - - if (!getSubVar(VA_HAS_TAPE, _nameHash) && !getSubVar(VA_IS_TAPE_INSERTED, _nameHash)) { - SetMessageHandler(&AsScene1201Tape::handleMessage); - } else { - setVisible(false); - SetMessageHandler(NULL); - } -} - -uint32 AsScene1201Tape::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x1011: - sendMessage(_parentScene, 0x4826, 0); - messageResult = 1; - break; - case 0x4806: - setSubVar(VA_HAS_TAPE, _nameHash, 1); - setVisible(false); - SetMessageHandler(NULL); - break; - } - return messageResult; -} - -AsScene1201TntManRope::AsScene1201TntManRope(NeverhoodEngine *vm, bool isDummyHanging) - : AnimatedSprite(vm, 1200) { - - SetUpdateHandler(&AnimatedSprite::update); - SetMessageHandler(&AsScene1201TntManRope::handleMessage); - createSurface(10, 34, 149); - _x = 202; - _y = -32; - if (isDummyHanging) { - startAnimation(0x928F0C10, 15, -1); - _newStickFrameIndex = STICK_LAST_FRAME; - } else { - startAnimation(0x928F0C10, 0, -1); - _newStickFrameIndex = 0; - } -} - -uint32 AsScene1201TntManRope::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x100D: - if (param.asInteger() == 0x02060018) - playSound(0, 0x47900E06); - break; - case 0x2006: - startAnimation(0x928F0C10, 1, -1); - _newStickFrameIndex = STICK_LAST_FRAME; - break; - } - return messageResult; -} - -AsScene1201RightDoor::AsScene1201RightDoor(NeverhoodEngine *vm, Sprite *klaymen, bool isOpen) - : AnimatedSprite(vm, 1100), _klaymen(klaymen), _countdown(0) { - - createSurface1(0xD088AC30, 100); - _x = 320; - _y = 240; - SetUpdateHandler(&AsScene1201RightDoor::update); - SetMessageHandler(&AsScene1201RightDoor::handleMessage); - _newStickFrameIndex = STICK_LAST_FRAME; - if (isOpen) { - startAnimation(0xD088AC30, -1, -1); - _newStickFrameIndex = STICK_LAST_FRAME; - _countdown = 25; - } else { - stopAnimation(); - setVisible(false); - } -} - -void AsScene1201RightDoor::update() { - if (_countdown != 0 && (--_countdown == 0)) - stCloseDoor(); - AnimatedSprite::update(); -} - -uint32 AsScene1201RightDoor::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x3002: - gotoNextState(); - break; - case 0x4829: - stOpenDoor(); - break; - } - return messageResult; -} - -void AsScene1201RightDoor::stOpenDoor() { - startAnimation(0xD088AC30, 0, -1); - _newStickFrameIndex = STICK_LAST_FRAME; - setVisible(true); - playSound(0, calcHash("fxDoorOpen20")); -} - -void AsScene1201RightDoor::stCloseDoor() { - startAnimation(0xD088AC30, -1, -1); - _playBackwards = true; - setVisible(true); - playSound(0, calcHash("fxDoorClose20")); - NextState(&AsScene1201RightDoor::stCloseDoorDone); -} - -void AsScene1201RightDoor::stCloseDoorDone() { - stopAnimation(); - setVisible(false); -} - -AsScene1201KlaymenHead::AsScene1201KlaymenHead(NeverhoodEngine *vm) - : AnimatedSprite(vm, 1200) { - - createSurface(1200, 69, 98); - SetUpdateHandler(&AnimatedSprite::update); - SetMessageHandler(&AsScene1201KlaymenHead::handleMessage); - SetSpriteUpdate(&AnimatedSprite::updateDeltaXY); - setVisible(false); -} - -uint32 AsScene1201KlaymenHead::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x2006: - _x = 436; - _y = 339; - startAnimation(0xA060C599, 0, -1); - setVisible(true); - break; - case 0x3002: - stopAnimation(); - setVisible(false); - gotoNextState(); - break; - } - return messageResult; -} - -AsScene1201TntMan::AsScene1201TntMan(NeverhoodEngine *vm, Scene *parentScene, Sprite *asTntManRope, bool isComingDown) - : AnimatedSprite(vm, 1100), _parentScene(parentScene), _asTntManRope(asTntManRope), - _isMoving(false) { - - SetUpdateHandler(&AnimatedSprite::update); - SetMessageHandler(&AsScene1201TntMan::handleMessage); - createSurface(990, 106, 181); - _x = 201; - if (isComingDown) { - _y = 297; - stComingDown(); - } else { - _y = 334; - stStanding(); - } -} - -AsScene1201TntMan::~AsScene1201TntMan() { - _vm->_soundMan->deleteSoundGroup(0x01D00560); -} - -uint32 AsScene1201TntMan::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x100D: - if (param.asInteger() == 0x092870C0) - sendMessage(_asTntManRope, 0x2006, 0); - else if (param.asInteger() == 0x11CA0144) - playSound(0, 0x51800A04); - break; - case 0x1011: - sendMessage(_parentScene, 0x2002, 0); - messageResult = 1; - break; - case 0x480B: - if (!_isMoving) { - _sprite = (Sprite*)sender; - stMoving(); - } - break; - } - return messageResult; - -} - -uint32 AsScene1201TntMan::hmComingDown(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = AsScene1201TntMan::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x3002: - gotoNextState(); - break; - } - return messageResult; -} - -void AsScene1201TntMan::suMoving() { - _x = _sprite->getX() + 100; -} - -void AsScene1201TntMan::stStanding() { - startAnimation(0x654913D0, 0, -1); - SetMessageHandler(&AsScene1201TntMan::handleMessage); - SetSpriteUpdate(NULL); -} - -void AsScene1201TntMan::stComingDown() { - startAnimation(0x356803D0, 0, -1); - SetMessageHandler(&AsScene1201TntMan::hmComingDown); - SetSpriteUpdate(&AnimatedSprite::updateDeltaXY); - NextState(&AsScene1201TntMan::stStanding); -} - -void AsScene1201TntMan::stMoving() { - _vm->_soundMan->addSound(0x01D00560, 0x4B044624); - _vm->_soundMan->playSoundLooping(0x4B044624); - _isMoving = true; - startAnimation(0x85084190, 0, -1); - SetMessageHandler(&AsScene1201TntMan::handleMessage); - SetSpriteUpdate(&AsScene1201TntMan::suMoving); - _newStickFrameIndex = STICK_LAST_FRAME; -} - -AsScene1201TntManFlame::AsScene1201TntManFlame(NeverhoodEngine *vm, Sprite *asTntMan) - : AnimatedSprite(vm, 1200), _asTntMan(asTntMan) { - - createSurface1(0x828C0411, 995); - SetUpdateHandler(&AsScene1201TntManFlame::update); - SetMessageHandler(&Sprite::handleMessage); - SetSpriteUpdate(&AsScene1201TntManFlame::suUpdate); - startAnimation(0x828C0411, 0, -1); - setVisible(false); -} - -AsScene1201TntManFlame::~AsScene1201TntManFlame() { - _vm->_soundMan->deleteSoundGroup(0x041080A4); -} - -void AsScene1201TntManFlame::update() { - AnimatedSprite::update(); - if (getGlobalVar(V_TNT_DUMMY_FUSE_LIT)) { - setVisible(true); - SetUpdateHandler(&AnimatedSprite::update); - _vm->_soundMan->addSound(0x041080A4, 0x460A1050); - _vm->_soundMan->playSoundLooping(0x460A1050); - } -} - -void AsScene1201TntManFlame::suUpdate() { - _x = _asTntMan->getX() - 18; - _y = _asTntMan->getY() - 158; -} - -AsScene1201Match::AsScene1201Match(NeverhoodEngine *vm, Scene *parentScene) - : AnimatedSprite(vm, 1100), _parentScene(parentScene), _countdown(0) { - - createSurface(1100, 57, 60); - SetUpdateHandler(&AsScene1201Match::update); - SetMessageHandler(&AsScene1201Match::hmOnDoorFrameAboutToMove); - SetSpriteUpdate(&AnimatedSprite::updateDeltaXY); - switch (getGlobalVar(V_MATCH_STATUS)) { - case 0: - _x = 521; - _y = 112; - _status = 0; - stIdleOnDoorFrame(); - break; - case 1: - _x = 521; - _y = 112; - _status = 2; - stOnDoorFrameAboutToMove(); - loadSound(0, 0xD00230CD); - break; - case 2: - setDoDeltaX(1); - _x = 403; - _y = 337; - _status = 0; - stIdleOnFloor(); - break; - } -} - -void AsScene1201Match::update() { - if (_countdown != 0 && (--_countdown == 0)) - gotoNextState(); - updateAnim(); - handleSpriteUpdate(); - updatePosition(); -} - -uint32 AsScene1201Match::hmOnDoorFrameAboutToMove(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x100D: - if (param.asInteger() == 0x86668011) - playSound(0); - break; - } - return messageResult; -} - -uint32 AsScene1201Match::hmOnDoorFrameMoving(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = hmOnDoorFrameAboutToMove(messageNum, param, sender); - switch (messageNum) { - case 0x3002: - gotoNextState(); - break; - } - return messageResult; -} - -uint32 AsScene1201Match::hmIdle(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = hmOnDoorFrameAboutToMove(messageNum, param, sender); - switch (messageNum) { - case 0x1011: - sendMessage(_parentScene, 0x2001, 0); - messageResult = 1; - break; - case 0x4806: - setVisible(false); - setGlobalVar(V_MATCH_STATUS, 3); - break; - } - return messageResult; -} - -void AsScene1201Match::stOnDoorFrameMoving() { - startAnimation(0x00842374, 0, -1); - SetMessageHandler(&AsScene1201Match::hmOnDoorFrameMoving); - if (_status == 0) { - NextState(&AsScene1201Match::stFallingFromDoorFrame); - } else { - NextState(&AsScene1201Match::stOnDoorFrameAboutToMove); - } -} - -void AsScene1201Match::stFallingFromDoorFrame() { - setGlobalVar(V_MATCH_STATUS, 2); - _x -= 199; - _y += 119; - startAnimation(0x018D0240, 0, -1); - SetMessageHandler(&AsScene1201Match::hmOnDoorFrameMoving); - NextState(&AsScene1201Match::stIdleOnFloor); -} - -void AsScene1201Match::stOnDoorFrameAboutToMove() { - startAnimation(0x00842374, 0, -1); - SetMessageHandler(&AsScene1201Match::hmOnDoorFrameAboutToMove); - _newStickFrameIndex = 0; - if (_status != 0) { - _countdown = 36; - _status--; - NextState(&AsScene1201Match::stOnDoorFrameMoving); - } -} - -void AsScene1201Match::stIdleOnDoorFrame() { - startAnimation(0x00842374, 0, -1); - SetMessageHandler(&AsScene1201Match::hmIdle); - _newStickFrameIndex = 0; -} - -void AsScene1201Match::stIdleOnFloor() { - setDoDeltaX(1); - _x = 403; - _y = 337; - startAnimation(0x00842374, 0, -1); - SetMessageHandler(&AsScene1201Match::hmIdle); - _newStickFrameIndex = 0; -} - -AsScene1201Creature::AsScene1201Creature(NeverhoodEngine *vm, Scene *parentScene, Sprite *klaymen) - : AnimatedSprite(vm, 900), _parentScene(parentScene), _klaymen(klaymen), _klaymenTooClose(false) { - - // NOTE: _countdown2 and _countdown3 were unused/without effect and thus removed - - createSurface(1100, 203, 199); - SetUpdateHandler(&AsScene1201Creature::update); - SetMessageHandler(&AsScene1201Creature::hmWaiting); - _x = 540; - _y = 320; - stWaiting(); -} - -void AsScene1201Creature::update() { - bool oldKlaymenTooClose = _klaymenTooClose; - _klaymenTooClose = _klaymen->getX() >= 385; - if (_klaymenTooClose != oldKlaymenTooClose) - stWaiting(); - if (_countdown != 0 && (--_countdown == 0)) - gotoNextState(); - updateAnim(); - handleSpriteUpdate(); - updatePosition(); -} - -uint32 AsScene1201Creature::hmWaiting(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x100D: - if (param.asInteger() == 0x02060018) - playSound(0, 0xCD298116); - break; - case 0x2004: - GotoState(&AsScene1201Creature::stStartReachForTntDummy); - break; - case 0x2006: - GotoState(&AsScene1201Creature::stPincerSnapKlaymen); - break; - } - return messageResult; -} - -uint32 AsScene1201Creature::hmPincerSnap(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = hmWaiting(messageNum, param, sender); - switch (messageNum) { - case 0x3002: - gotoNextState(); - break; - } - return messageResult; -} - -uint32 AsScene1201Creature::hmPincerSnapKlaymen(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x100D: - if (param.asInteger() == 0x02060018) { - playSound(0, 0xCD298116); - sendMessage(_parentScene, 0x4814, 0); - sendMessage(_klaymen, 0x4814, 0); - } - break; - case 0x3002: - gotoNextState(); - break; - } - return messageResult; -} - -void AsScene1201Creature::stWaiting() { - startAnimation(0x08081513, 0, -1); - SetMessageHandler(&AsScene1201Creature::hmWaiting); - NextState(&AsScene1201Creature::stPincerSnap); - _countdown = 36; -} - -void AsScene1201Creature::stPincerSnap() { - if (!_klaymenTooClose) { - startAnimation(0xCA287133, 0, -1); - SetMessageHandler(&AsScene1201Creature::hmPincerSnap); - NextState(&AsScene1201Creature::stWaiting); - } -} - -void AsScene1201Creature::stStartReachForTntDummy() { - startAnimation(0x08081513, 0, -1); - SetMessageHandler(&AsScene1201Creature::hmWaiting); - NextState(&AsScene1201Creature::stReachForTntDummy); - _countdown = 48; -} - -void AsScene1201Creature::stReachForTntDummy() { - startAnimation(0x5A201453, 0, -1); - SetMessageHandler(&AsScene1201Creature::hmWaiting); - _countdown = 0; -} - -void AsScene1201Creature::stPincerSnapKlaymen() { - startAnimation(0xCA287133, 0, -1); - SetMessageHandler(&AsScene1201Creature::hmPincerSnapKlaymen); - NextState(&AsScene1201Creature::stWaiting); - _countdown = 0; -} - -AsScene1201LeftDoor::AsScene1201LeftDoor(NeverhoodEngine *vm, Sprite *klaymen) - : AnimatedSprite(vm, 1100), _klaymen(klaymen) { - - _x = 320; - _y = 240; - createSurface(800, 55, 199); - if (_klaymen->getX() < 100) { - startAnimation(0x508A111B, 0, -1); - _newStickFrameIndex = STICK_LAST_FRAME; - playSound(0, calcHash("fxDoorOpen03")); - } else { - startAnimation(0x508A111B, -1, -1); - _newStickFrameIndex = STICK_LAST_FRAME; - } - SetUpdateHandler(&AnimatedSprite::update); - SetMessageHandler(&AsScene1201LeftDoor::handleMessage); -} - -uint32 AsScene1201LeftDoor::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x4809: - stCloseDoor(); - break; - } - return messageResult; -} - -void AsScene1201LeftDoor::stCloseDoor() { - startAnimation(0x508A111B, -1, -1); - _playBackwards = true; - _newStickFrameIndex = 0; -} - Scene1201::Scene1201(NeverhoodEngine *vm, Module *parentModule, int which) : Scene(vm, parentModule), _creatureExploded(false), _asMatch(NULL), _asTntMan(NULL), _asCreature(NULL), _asTntManRope(NULL), _asLeftDoor(NULL), _asRightDoor(NULL), _asTape(NULL) { @@ -908,95 +353,10 @@ uint32 Scene1201::handleMessage(int messageNum, const MessageParam ¶m, Entit return messageResult; } -// Scene1202 - static const uint32 kScene1202Table[] = { 1, 2, 0, 4, 5, 3, 7, 8, 6, 10, 11, 9, 13, 14, 12, 16, 17, 15 }; -static const NPoint kScene1202Points[] = { - {203, 140}, {316, 212}, {277, 264}, - {176, 196}, {275, 159}, {366, 212}, - {230, 195}, {412, 212}, {368, 263}, - {204, 192}, {365, 164}, {316, 262}, - {191, 255}, {280, 213}, {406, 266}, - {214, 254}, {316, 158}, {402, 161} -}; - -static const uint32 kScene1202FileHashes[] = { - 0x1AC00B8, 0x1AC14B8, 0x1AC14B8, - 0x1AC30B8, 0x1AC14B8, 0x1AC14B8, - 0x1AC00B8, 0x1AC14B8, 0x1AC14B8, - 0x1AC90B8, 0x1AC18B8, 0x1AC18B8, - 0x1AC30B8, 0x1AC14B8, 0x1AC14B8, - 0x1AC50B8, 0x1AC14B8, 0x1AC14B8 -}; - -AsScene1202TntItem::AsScene1202TntItem(NeverhoodEngine *vm, Scene *parentScene, int itemIndex) - : AnimatedSprite(vm, 900), _parentScene(parentScene), _itemIndex(itemIndex) { - - int positionIndex; - - SetUpdateHandler(&AnimatedSprite::update); - SetMessageHandler(&AsScene1202TntItem::hmShowIdle); - positionIndex = getSubVar(VA_TNT_POSITIONS, _itemIndex); - createSurface(900, 37, 67); - _x = kScene1202Points[positionIndex].x; - _y = kScene1202Points[positionIndex].y; - stShowIdle(); -} - -uint32 AsScene1202TntItem::hmShowIdle(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x1011: - sendMessage(_parentScene, 0x2000, _itemIndex); - messageResult = 1; - break; - case 0x2001: - _newPosition = (int)param.asInteger(); - stChangePositionFadeOut(); - break; - } - return messageResult; -} - -uint32 AsScene1202TntItem::hmChangePosition(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x3002: - gotoNextState(); - break; - } - return messageResult; -} - -void AsScene1202TntItem::stShowIdle() { - startAnimation(kScene1202FileHashes[_itemIndex], 0, -1); - SetMessageHandler(&AsScene1202TntItem::hmShowIdle); - _newStickFrameIndex = 0; -} - -void AsScene1202TntItem::stChangePositionFadeOut() { - startAnimation(kScene1202FileHashes[_itemIndex], 0, -1); - SetMessageHandler(&AsScene1202TntItem::hmChangePosition); - NextState(&AsScene1202TntItem::stChangePositionFadeIn); -} - -void AsScene1202TntItem::stChangePositionFadeIn() { - _x = kScene1202Points[_newPosition].x; - _y = kScene1202Points[_newPosition].y; - startAnimation(kScene1202FileHashes[_itemIndex], 6, -1); - _playBackwards = true; - SetMessageHandler(&AsScene1202TntItem::hmChangePosition); - NextState(&AsScene1202TntItem::stChangePositionDone); -} - -void AsScene1202TntItem::stChangePositionDone() { - sendMessage(_parentScene, 0x2002, _itemIndex); - stShowIdle(); -} - Scene1202::Scene1202(NeverhoodEngine *vm, Module *parentModule) : Scene(vm, parentModule), _paletteResource(vm), _soundToggle(true), _isPuzzleSolved(false), _counter(0), _clickedIndex(-1) { diff --git a/engines/neverhood/modules/module1200.h b/engines/neverhood/modules/module1200.h index e85273185e..d9d4dd11f2 100644 --- a/engines/neverhood/modules/module1200.h +++ b/engines/neverhood/modules/module1200.h @@ -29,8 +29,6 @@ namespace Neverhood { -// Module1200 - class Module1200 : public Module { public: Module1200(NeverhoodEngine *vm, Module *parentModule, int which); @@ -41,121 +39,7 @@ protected: void updateScene(); }; -// Scene1201 - -class AsScene1201Tape : public AnimatedSprite { -public: - AsScene1201Tape(NeverhoodEngine *vm, Scene *parentScene, uint32 nameHash, int surfacePriority, int16 x, int16 y, uint32 fileHash); -protected: - Scene *_parentScene; - uint32 _nameHash; - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); -}; - -class AsScene1201TntManRope : public AnimatedSprite { -public: - AsScene1201TntManRope(NeverhoodEngine *vm, bool isDummyHanging); -protected: - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); -}; - -class AsScene1201RightDoor : public AnimatedSprite { -public: - AsScene1201RightDoor(NeverhoodEngine *vm, Sprite *klaymen, bool isOpen); -protected: - Sprite *_klaymen; - int _countdown; - void update(); - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); - void stOpenDoor(); - void stCloseDoor(); - void stCloseDoorDone(); -}; - -class AsScene1201KlaymenHead : public AnimatedSprite { -public: - AsScene1201KlaymenHead(NeverhoodEngine *vm); -protected: - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); -}; - -class AsScene1201TntMan : public AnimatedSprite { -public: - AsScene1201TntMan(NeverhoodEngine *vm, Scene *parentScene, Sprite *asTntManRope, bool isDown); - virtual ~AsScene1201TntMan(); -protected: - Scene *_parentScene; - Sprite *_asTntManRope; - Sprite *_sprite; - bool _isMoving; - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); - uint32 hmComingDown(int messageNum, const MessageParam ¶m, Entity *sender); - void suMoving(); - void stStanding(); - void stComingDown(); - void stMoving(); -}; - -class AsScene1201TntManFlame : public AnimatedSprite { -public: - AsScene1201TntManFlame(NeverhoodEngine *vm, Sprite *asTntMan); - ~AsScene1201TntManFlame(); -protected: - Sprite *_asTntMan; - void update(); - void suUpdate(); -}; - -class AsScene1201Match : public AnimatedSprite { -public: - AsScene1201Match(NeverhoodEngine *vm, Scene *parentScene); -protected: - Scene *_parentScene; - int _countdown; - int _status; - void update(); - uint32 hmOnDoorFrameAboutToMove(int messageNum, const MessageParam ¶m, Entity *sender); - uint32 hmOnDoorFrameMoving(int messageNum, const MessageParam ¶m, Entity *sender); - uint32 hmIdle(int messageNum, const MessageParam ¶m, Entity *sender); - void stOnDoorFrameMoving(); - void stFallingFromDoorFrame(); - void stOnDoorFrameAboutToMove(); - void stIdleOnDoorFrame(); - void stIdleOnFloor(); -}; - -class AsScene1201Creature : public AnimatedSprite { -public: - AsScene1201Creature(NeverhoodEngine *vm, Scene *parentScene, Sprite *klaymen); -protected: - Scene *_parentScene; - Sprite *_klaymen; - int _countdown; - bool _klaymenTooClose; - void update(); - uint32 hmWaiting(int messageNum, const MessageParam ¶m, Entity *sender); - uint32 hmPincerSnap(int messageNum, const MessageParam ¶m, Entity *sender); - uint32 hmPincerSnapKlaymen(int messageNum, const MessageParam ¶m, Entity *sender); - void stWaiting(); - void stPincerSnap(); - void stStartReachForTntDummy(); - void stReachForTntDummy(); - void stPincerSnapKlaymen(); -}; - -class AsScene1201LeftDoor : public AnimatedSprite { -public: - AsScene1201LeftDoor(NeverhoodEngine *vm, Sprite *klaymen); -protected: - Sprite *_klaymen; - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); - void stCloseDoor(); -}; - -class SsScene1201Tnt : public StaticSprite { -public: - SsScene1201Tnt(NeverhoodEngine *vm, uint32 elemIndex, uint32 pointIndex, int16 clipY2); -}; +class AsScene1201TntMan; class Scene1201 : public Scene { public: @@ -175,22 +59,6 @@ protected: uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); }; -// Scene1202 - -class AsScene1202TntItem : public AnimatedSprite { -public: - AsScene1202TntItem(NeverhoodEngine *vm, Scene *parentScene, int index); -protected: - Scene *_parentScene; - int _itemIndex, _newPosition; - uint32 hmShowIdle(int messageNum, const MessageParam ¶m, Entity *sender); - uint32 hmChangePosition(int messageNum, const MessageParam ¶m, Entity *sender); - void stShowIdle(); - void stChangePositionFadeOut(); - void stChangePositionFadeIn(); - void stChangePositionDone(); -}; - class Scene1202 : public Scene { public: Scene1202(NeverhoodEngine *vm, Module *parentModule); diff --git a/engines/neverhood/modules/module1200_sprites.cpp b/engines/neverhood/modules/module1200_sprites.cpp new file mode 100644 index 0000000000..da38924d9a --- /dev/null +++ b/engines/neverhood/modules/module1200_sprites.cpp @@ -0,0 +1,810 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "neverhood/modules/module1200_sprites.h" + +namespace Neverhood { + +static const uint32 kScene1201TntFileHashList1[] = { + 0x2098212D, 0x1600437E, 0x1600437E, + 0x00A840E3, 0x1A1830F6, 0x1A1830F6, + 0x00212062, 0x384010B6, 0x384010B6, + 0x07A01080, 0xD80C2837, 0xD80C2837, + 0x03A22092, 0xD8802CB6, 0xD8802CB6, + 0x03A93831, 0xDA460476, 0xDA460476 +}; + +static const uint32 kScene1201TntFileHashList2[] = { + 0x3040C676, 0x10914448, 0x10914448, + 0x3448A066, 0x1288C049, 0x1288C049, + 0x78C0E026, 0x3098D05A, 0x3098D05A, + 0x304890E6, 0x1284E048, 0x1284E048, + 0xB140A1E6, 0x5088A068, 0x5088A068, + 0x74C4C866, 0x3192C059, 0x3192C059 +}; + +SsScene1201Tnt::SsScene1201Tnt(NeverhoodEngine *vm, uint32 elemIndex, uint32 pointIndex, int16 clipY2) + : StaticSprite(vm, 900) { + + int16 x = kScene1201PointArray[pointIndex].x; + int16 y = kScene1201PointArray[pointIndex].y; + if (x < 300) + loadSprite(kScene1201TntFileHashList1[elemIndex], kSLFDefDrawOffset | kSLFDefPosition, 50); + else + loadSprite(kScene1201TntFileHashList2[elemIndex], kSLFCenteredDrawOffset | kSLFSetPosition, 50, x, y - 20); + setClipRect(0, 0, 640, clipY2); +} + +AsScene1201Tape::AsScene1201Tape(NeverhoodEngine *vm, Scene *parentScene, uint32 nameHash, int surfacePriority, int16 x, int16 y, uint32 fileHash) + : AnimatedSprite(vm, fileHash, surfacePriority, x, y), _parentScene(parentScene), _nameHash(nameHash) { + + if (!getSubVar(VA_HAS_TAPE, _nameHash) && !getSubVar(VA_IS_TAPE_INSERTED, _nameHash)) { + SetMessageHandler(&AsScene1201Tape::handleMessage); + } else { + setVisible(false); + SetMessageHandler(NULL); + } +} + +uint32 AsScene1201Tape::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x1011: + sendMessage(_parentScene, 0x4826, 0); + messageResult = 1; + break; + case 0x4806: + setSubVar(VA_HAS_TAPE, _nameHash, 1); + setVisible(false); + SetMessageHandler(NULL); + break; + } + return messageResult; +} + +AsScene1201TntManRope::AsScene1201TntManRope(NeverhoodEngine *vm, bool isDummyHanging) + : AnimatedSprite(vm, 1200) { + + SetUpdateHandler(&AnimatedSprite::update); + SetMessageHandler(&AsScene1201TntManRope::handleMessage); + createSurface(10, 34, 149); + _x = 202; + _y = -32; + if (isDummyHanging) { + startAnimation(0x928F0C10, 15, -1); + _newStickFrameIndex = STICK_LAST_FRAME; + } else { + startAnimation(0x928F0C10, 0, -1); + _newStickFrameIndex = 0; + } +} + +uint32 AsScene1201TntManRope::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x100D: + if (param.asInteger() == 0x02060018) + playSound(0, 0x47900E06); + break; + case 0x2006: + startAnimation(0x928F0C10, 1, -1); + _newStickFrameIndex = STICK_LAST_FRAME; + break; + } + return messageResult; +} + +AsScene1201RightDoor::AsScene1201RightDoor(NeverhoodEngine *vm, Sprite *klaymen, bool isOpen) + : AnimatedSprite(vm, 1100), _klaymen(klaymen), _countdown(0) { + + createSurface1(0xD088AC30, 100); + _x = 320; + _y = 240; + SetUpdateHandler(&AsScene1201RightDoor::update); + SetMessageHandler(&AsScene1201RightDoor::handleMessage); + _newStickFrameIndex = STICK_LAST_FRAME; + if (isOpen) { + startAnimation(0xD088AC30, -1, -1); + _newStickFrameIndex = STICK_LAST_FRAME; + _countdown = 25; + } else { + stopAnimation(); + setVisible(false); + } +} + +void AsScene1201RightDoor::update() { + if (_countdown != 0 && (--_countdown == 0)) + stCloseDoor(); + AnimatedSprite::update(); +} + +uint32 AsScene1201RightDoor::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x3002: + gotoNextState(); + break; + case 0x4829: + stOpenDoor(); + break; + } + return messageResult; +} + +void AsScene1201RightDoor::stOpenDoor() { + startAnimation(0xD088AC30, 0, -1); + _newStickFrameIndex = STICK_LAST_FRAME; + setVisible(true); + playSound(0, calcHash("fxDoorOpen20")); +} + +void AsScene1201RightDoor::stCloseDoor() { + startAnimation(0xD088AC30, -1, -1); + _playBackwards = true; + setVisible(true); + playSound(0, calcHash("fxDoorClose20")); + NextState(&AsScene1201RightDoor::stCloseDoorDone); +} + +void AsScene1201RightDoor::stCloseDoorDone() { + stopAnimation(); + setVisible(false); +} + +AsScene1201KlaymenHead::AsScene1201KlaymenHead(NeverhoodEngine *vm) + : AnimatedSprite(vm, 1200) { + + createSurface(1200, 69, 98); + SetUpdateHandler(&AnimatedSprite::update); + SetMessageHandler(&AsScene1201KlaymenHead::handleMessage); + SetSpriteUpdate(&AnimatedSprite::updateDeltaXY); + setVisible(false); +} + +uint32 AsScene1201KlaymenHead::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x2006: + _x = 436; + _y = 339; + startAnimation(0xA060C599, 0, -1); + setVisible(true); + break; + case 0x3002: + stopAnimation(); + setVisible(false); + gotoNextState(); + break; + } + return messageResult; +} + +AsScene1201TntMan::AsScene1201TntMan(NeverhoodEngine *vm, Scene *parentScene, Sprite *asTntManRope, bool isComingDown) + : AnimatedSprite(vm, 1100), _parentScene(parentScene), _asTntManRope(asTntManRope), + _isMoving(false) { + + SetUpdateHandler(&AnimatedSprite::update); + SetMessageHandler(&AsScene1201TntMan::handleMessage); + createSurface(990, 106, 181); + _x = 201; + if (isComingDown) { + _y = 297; + stComingDown(); + } else { + _y = 334; + stStanding(); + } +} + +AsScene1201TntMan::~AsScene1201TntMan() { + _vm->_soundMan->deleteSoundGroup(0x01D00560); +} + +uint32 AsScene1201TntMan::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x100D: + if (param.asInteger() == 0x092870C0) + sendMessage(_asTntManRope, 0x2006, 0); + else if (param.asInteger() == 0x11CA0144) + playSound(0, 0x51800A04); + break; + case 0x1011: + sendMessage(_parentScene, 0x2002, 0); + messageResult = 1; + break; + case 0x480B: + if (!_isMoving) { + _sprite = (Sprite*)sender; + stMoving(); + } + break; + } + return messageResult; + +} + +uint32 AsScene1201TntMan::hmComingDown(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = AsScene1201TntMan::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x3002: + gotoNextState(); + break; + } + return messageResult; +} + +void AsScene1201TntMan::suMoving() { + _x = _sprite->getX() + 100; +} + +void AsScene1201TntMan::stStanding() { + startAnimation(0x654913D0, 0, -1); + SetMessageHandler(&AsScene1201TntMan::handleMessage); + SetSpriteUpdate(NULL); +} + +void AsScene1201TntMan::stComingDown() { + startAnimation(0x356803D0, 0, -1); + SetMessageHandler(&AsScene1201TntMan::hmComingDown); + SetSpriteUpdate(&AnimatedSprite::updateDeltaXY); + NextState(&AsScene1201TntMan::stStanding); +} + +void AsScene1201TntMan::stMoving() { + _vm->_soundMan->addSound(0x01D00560, 0x4B044624); + _vm->_soundMan->playSoundLooping(0x4B044624); + _isMoving = true; + startAnimation(0x85084190, 0, -1); + SetMessageHandler(&AsScene1201TntMan::handleMessage); + SetSpriteUpdate(&AsScene1201TntMan::suMoving); + _newStickFrameIndex = STICK_LAST_FRAME; +} + +AsScene1201TntManFlame::AsScene1201TntManFlame(NeverhoodEngine *vm, Sprite *asTntMan) + : AnimatedSprite(vm, 1200), _asTntMan(asTntMan) { + + createSurface1(0x828C0411, 995); + SetUpdateHandler(&AsScene1201TntManFlame::update); + SetMessageHandler(&Sprite::handleMessage); + SetSpriteUpdate(&AsScene1201TntManFlame::suUpdate); + startAnimation(0x828C0411, 0, -1); + setVisible(false); +} + +AsScene1201TntManFlame::~AsScene1201TntManFlame() { + _vm->_soundMan->deleteSoundGroup(0x041080A4); +} + +void AsScene1201TntManFlame::update() { + AnimatedSprite::update(); + if (getGlobalVar(V_TNT_DUMMY_FUSE_LIT)) { + setVisible(true); + SetUpdateHandler(&AnimatedSprite::update); + _vm->_soundMan->addSound(0x041080A4, 0x460A1050); + _vm->_soundMan->playSoundLooping(0x460A1050); + } +} + +void AsScene1201TntManFlame::suUpdate() { + _x = _asTntMan->getX() - 18; + _y = _asTntMan->getY() - 158; +} + +AsScene1201Match::AsScene1201Match(NeverhoodEngine *vm, Scene *parentScene) + : AnimatedSprite(vm, 1100), _parentScene(parentScene), _countdown(0) { + + createSurface(1100, 57, 60); + SetUpdateHandler(&AsScene1201Match::update); + SetMessageHandler(&AsScene1201Match::hmOnDoorFrameAboutToMove); + SetSpriteUpdate(&AnimatedSprite::updateDeltaXY); + switch (getGlobalVar(V_MATCH_STATUS)) { + case 0: + _x = 521; + _y = 112; + _status = 0; + stIdleOnDoorFrame(); + break; + case 1: + _x = 521; + _y = 112; + _status = 2; + stOnDoorFrameAboutToMove(); + loadSound(0, 0xD00230CD); + break; + case 2: + setDoDeltaX(1); + _x = 403; + _y = 337; + _status = 0; + stIdleOnFloor(); + break; + } +} + +void AsScene1201Match::update() { + if (_countdown != 0 && (--_countdown == 0)) + gotoNextState(); + updateAnim(); + handleSpriteUpdate(); + updatePosition(); +} + +uint32 AsScene1201Match::hmOnDoorFrameAboutToMove(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x100D: + if (param.asInteger() == 0x86668011) + playSound(0); + break; + } + return messageResult; +} + +uint32 AsScene1201Match::hmOnDoorFrameMoving(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = hmOnDoorFrameAboutToMove(messageNum, param, sender); + switch (messageNum) { + case 0x3002: + gotoNextState(); + break; + } + return messageResult; +} + +uint32 AsScene1201Match::hmIdle(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = hmOnDoorFrameAboutToMove(messageNum, param, sender); + switch (messageNum) { + case 0x1011: + sendMessage(_parentScene, 0x2001, 0); + messageResult = 1; + break; + case 0x4806: + setVisible(false); + setGlobalVar(V_MATCH_STATUS, 3); + break; + } + return messageResult; +} + +void AsScene1201Match::stOnDoorFrameMoving() { + startAnimation(0x00842374, 0, -1); + SetMessageHandler(&AsScene1201Match::hmOnDoorFrameMoving); + if (_status == 0) { + NextState(&AsScene1201Match::stFallingFromDoorFrame); + } else { + NextState(&AsScene1201Match::stOnDoorFrameAboutToMove); + } +} + +void AsScene1201Match::stFallingFromDoorFrame() { + setGlobalVar(V_MATCH_STATUS, 2); + _x -= 199; + _y += 119; + startAnimation(0x018D0240, 0, -1); + SetMessageHandler(&AsScene1201Match::hmOnDoorFrameMoving); + NextState(&AsScene1201Match::stIdleOnFloor); +} + +void AsScene1201Match::stOnDoorFrameAboutToMove() { + startAnimation(0x00842374, 0, -1); + SetMessageHandler(&AsScene1201Match::hmOnDoorFrameAboutToMove); + _newStickFrameIndex = 0; + if (_status != 0) { + _countdown = 36; + _status--; + NextState(&AsScene1201Match::stOnDoorFrameMoving); + } +} + +void AsScene1201Match::stIdleOnDoorFrame() { + startAnimation(0x00842374, 0, -1); + SetMessageHandler(&AsScene1201Match::hmIdle); + _newStickFrameIndex = 0; +} + +void AsScene1201Match::stIdleOnFloor() { + setDoDeltaX(1); + _x = 403; + _y = 337; + startAnimation(0x00842374, 0, -1); + SetMessageHandler(&AsScene1201Match::hmIdle); + _newStickFrameIndex = 0; +} + +AsScene1201Creature::AsScene1201Creature(NeverhoodEngine *vm, Scene *parentScene, Sprite *klaymen) + : AnimatedSprite(vm, 900), _parentScene(parentScene), _klaymen(klaymen), _klaymenTooClose(false) { + + // NOTE: _countdown2 and _countdown3 were unused/without effect and thus removed + + createSurface(1100, 203, 199); + SetUpdateHandler(&AsScene1201Creature::update); + SetMessageHandler(&AsScene1201Creature::hmWaiting); + _x = 540; + _y = 320; + stWaiting(); +} + +void AsScene1201Creature::update() { + bool oldKlaymenTooClose = _klaymenTooClose; + _klaymenTooClose = _klaymen->getX() >= 385; + if (_klaymenTooClose != oldKlaymenTooClose) + stWaiting(); + if (_countdown != 0 && (--_countdown == 0)) + gotoNextState(); + updateAnim(); + handleSpriteUpdate(); + updatePosition(); +} + +uint32 AsScene1201Creature::hmWaiting(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x100D: + if (param.asInteger() == 0x02060018) + playSound(0, 0xCD298116); + break; + case 0x2004: + GotoState(&AsScene1201Creature::stStartReachForTntDummy); + break; + case 0x2006: + GotoState(&AsScene1201Creature::stPincerSnapKlaymen); + break; + } + return messageResult; +} + +uint32 AsScene1201Creature::hmPincerSnap(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = hmWaiting(messageNum, param, sender); + switch (messageNum) { + case 0x3002: + gotoNextState(); + break; + } + return messageResult; +} + +uint32 AsScene1201Creature::hmPincerSnapKlaymen(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x100D: + if (param.asInteger() == 0x02060018) { + playSound(0, 0xCD298116); + sendMessage(_parentScene, 0x4814, 0); + sendMessage(_klaymen, 0x4814, 0); + } + break; + case 0x3002: + gotoNextState(); + break; + } + return messageResult; +} + +void AsScene1201Creature::stWaiting() { + startAnimation(0x08081513, 0, -1); + SetMessageHandler(&AsScene1201Creature::hmWaiting); + NextState(&AsScene1201Creature::stPincerSnap); + _countdown = 36; +} + +void AsScene1201Creature::stPincerSnap() { + if (!_klaymenTooClose) { + startAnimation(0xCA287133, 0, -1); + SetMessageHandler(&AsScene1201Creature::hmPincerSnap); + NextState(&AsScene1201Creature::stWaiting); + } +} + +void AsScene1201Creature::stStartReachForTntDummy() { + startAnimation(0x08081513, 0, -1); + SetMessageHandler(&AsScene1201Creature::hmWaiting); + NextState(&AsScene1201Creature::stReachForTntDummy); + _countdown = 48; +} + +void AsScene1201Creature::stReachForTntDummy() { + startAnimation(0x5A201453, 0, -1); + SetMessageHandler(&AsScene1201Creature::hmWaiting); + _countdown = 0; +} + +void AsScene1201Creature::stPincerSnapKlaymen() { + startAnimation(0xCA287133, 0, -1); + SetMessageHandler(&AsScene1201Creature::hmPincerSnapKlaymen); + NextState(&AsScene1201Creature::stWaiting); + _countdown = 0; +} + +AsScene1201LeftDoor::AsScene1201LeftDoor(NeverhoodEngine *vm, Sprite *klaymen) + : AnimatedSprite(vm, 1100), _klaymen(klaymen) { + + _x = 320; + _y = 240; + createSurface(800, 55, 199); + if (_klaymen->getX() < 100) { + startAnimation(0x508A111B, 0, -1); + _newStickFrameIndex = STICK_LAST_FRAME; + playSound(0, calcHash("fxDoorOpen03")); + } else { + startAnimation(0x508A111B, -1, -1); + _newStickFrameIndex = STICK_LAST_FRAME; + } + SetUpdateHandler(&AnimatedSprite::update); + SetMessageHandler(&AsScene1201LeftDoor::handleMessage); +} + +uint32 AsScene1201LeftDoor::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x4809: + stCloseDoor(); + break; + } + return messageResult; +} + +void AsScene1201LeftDoor::stCloseDoor() { + startAnimation(0x508A111B, -1, -1); + _playBackwards = true; + _newStickFrameIndex = 0; +} + +static const NPoint kScene1202Points[] = { + {203, 140}, {316, 212}, {277, 264}, + {176, 196}, {275, 159}, {366, 212}, + {230, 195}, {412, 212}, {368, 263}, + {204, 192}, {365, 164}, {316, 262}, + {191, 255}, {280, 213}, {406, 266}, + {214, 254}, {316, 158}, {402, 161} +}; + +static const uint32 kScene1202FileHashes[] = { + 0x1AC00B8, 0x1AC14B8, 0x1AC14B8, + 0x1AC30B8, 0x1AC14B8, 0x1AC14B8, + 0x1AC00B8, 0x1AC14B8, 0x1AC14B8, + 0x1AC90B8, 0x1AC18B8, 0x1AC18B8, + 0x1AC30B8, 0x1AC14B8, 0x1AC14B8, + 0x1AC50B8, 0x1AC14B8, 0x1AC14B8 +}; + +AsScene1202TntItem::AsScene1202TntItem(NeverhoodEngine *vm, Scene *parentScene, int itemIndex) + : AnimatedSprite(vm, 900), _parentScene(parentScene), _itemIndex(itemIndex) { + + int positionIndex; + + SetUpdateHandler(&AnimatedSprite::update); + SetMessageHandler(&AsScene1202TntItem::hmShowIdle); + positionIndex = getSubVar(VA_TNT_POSITIONS, _itemIndex); + createSurface(900, 37, 67); + _x = kScene1202Points[positionIndex].x; + _y = kScene1202Points[positionIndex].y; + stShowIdle(); +} + +uint32 AsScene1202TntItem::hmShowIdle(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x1011: + sendMessage(_parentScene, 0x2000, _itemIndex); + messageResult = 1; + break; + case 0x2001: + _newPosition = (int)param.asInteger(); + stChangePositionFadeOut(); + break; + } + return messageResult; +} + +uint32 AsScene1202TntItem::hmChangePosition(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x3002: + gotoNextState(); + break; + } + return messageResult; +} + +void AsScene1202TntItem::stShowIdle() { + startAnimation(kScene1202FileHashes[_itemIndex], 0, -1); + SetMessageHandler(&AsScene1202TntItem::hmShowIdle); + _newStickFrameIndex = 0; +} + +void AsScene1202TntItem::stChangePositionFadeOut() { + startAnimation(kScene1202FileHashes[_itemIndex], 0, -1); + SetMessageHandler(&AsScene1202TntItem::hmChangePosition); + NextState(&AsScene1202TntItem::stChangePositionFadeIn); +} + +void AsScene1202TntItem::stChangePositionFadeIn() { + _x = kScene1202Points[_newPosition].x; + _y = kScene1202Points[_newPosition].y; + startAnimation(kScene1202FileHashes[_itemIndex], 6, -1); + _playBackwards = true; + SetMessageHandler(&AsScene1202TntItem::hmChangePosition); + NextState(&AsScene1202TntItem::stChangePositionDone); +} + +void AsScene1202TntItem::stChangePositionDone() { + sendMessage(_parentScene, 0x2002, _itemIndex); + stShowIdle(); +} + +static const KlaymenIdleTableItem klaymenIdleTable1201[] = { + {1, kIdleSpinHead}, + {1, kIdleChest}, + {1, kIdleHeadOff}, +}; + +KmScene1201::KmScene1201(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) + : Klaymen(vm, parentScene, x, y) { + + setKlaymenIdleTable(klaymenIdleTable1201, ARRAYSIZE(klaymenIdleTable1201)); + _doYHitIncr = true; +} + +uint32 KmScene1201::xHandleMessage(int messageNum, const MessageParam ¶m) { + switch (messageNum) { + case 0x4001: + case 0x4800: + startWalkToX(param.asPoint().x, false); + break; + case 0x4004: + GotoState(&Klaymen::stTryStandIdle); + break; + case 0x480A: + GotoState(&Klaymen::stMoveObject); + break; + case 0x4812: + GotoState(&Klaymen::stPickUpGeneric); + break; + case 0x4813: + GotoState(&KmScene1201::stFetchMatch); + break; + case 0x4814: + GotoState(&KmScene1201::stTumbleHeadless); + break; + case 0x4815: + GotoState(&KmScene1201::stCloseEyes); + break; + case 0x4816: + if (param.asInteger() == 0) + GotoState(&Klaymen::stPressButtonSide); + break; + case 0x4817: + setDoDeltaX(param.asInteger()); + gotoNextStateExt(); + break; + case 0x481B: + if (param.asPoint().y != 0) + startWalkToXDistance(param.asPoint().y, param.asPoint().x); + else + startWalkToAttachedSpriteXDistance(param.asPoint().x); + break; + case 0x481D: + GotoState(&Klaymen::stTurnToUse); + break; + case 0x481E: + GotoState(&Klaymen::stReturnFromUse); + break; + case 0x481F: + GotoState(&Klaymen::stWonderAbout); + break; + case 0x482D: + setDoDeltaX(_x > (int16)param.asInteger() ? 1 : 0); + gotoNextStateExt(); + break; + case 0x483F: + startSpecialWalkRight(param.asInteger()); + break; + case 0x4840: + startSpecialWalkLeft(param.asInteger()); + break; + } + return 0; +} + +void KmScene1201::stTumbleHeadless() { + if (!stStartActionFromIdle(AnimationCallback(&KmScene1201::stTumbleHeadless))) { + _busyStatus = 1; + _acceptInput = false; + setDoDeltaX(0); + startAnimation(0x2821C590, 0, -1); + SetUpdateHandler(&Klaymen::update); + SetMessageHandler(&KmScene1201::hmTumbleHeadless); + SetSpriteUpdate(&AnimatedSprite::updateDeltaXY); + NextState(&Klaymen::stTryStandIdle); + sendMessage(_parentScene, 0x8000, 0); + playSound(0, 0x62E0A356); + } +} + +void KmScene1201::stCloseEyes() { + if (!stStartActionFromIdle(AnimationCallback(&KmScene1201::stCloseEyes))) { + _busyStatus = 1; + _acceptInput = false; + startAnimation(0x5420E254, 0, -1); + SetUpdateHandler(&Klaymen::update); + SetMessageHandler(&Klaymen::hmLowLevel); + SetSpriteUpdate(NULL); + } +} + +uint32 KmScene1201::hmMatch(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Klaymen::hmLowLevelAnimation(messageNum, param, sender); + switch (messageNum) { + case 0x100D: + if (param.asInteger() == 0x51281850) { + setGlobalVar(V_TNT_DUMMY_FUSE_LIT, 1); + } else if (param.asInteger() == 0x43000538) { + playSound(0, 0x21043059); + } else if (param.asInteger() == 0x02B20220) { + playSound(0, 0xC5408620); + } else if (param.asInteger() == 0x0A720138) { + playSound(0, 0xD4C08010); + } else if (param.asInteger() == 0xB613A180) { + playSound(0, 0x44051000); + } + break; + } + return messageResult; +} + +void KmScene1201::stFetchMatch() { + if (!stStartAction(AnimationCallback(&KmScene1201::stFetchMatch))) { + _busyStatus = 0; + _acceptInput = false; + setDoDeltaX(_attachedSprite->getX() < _x ? 1 : 0); + startAnimation(0x9CAA0218, 0, -1); + SetUpdateHandler(&Klaymen::update); + SetMessageHandler(&KmScene1201::hmMatch); + SetSpriteUpdate(NULL); + NextState(&KmScene1201::stLightMatch); + } +} + +void KmScene1201::stLightMatch() { + _busyStatus = 1; + _acceptInput = false; + setDoDeltaX(_attachedSprite->getX() < _x ? 1 : 0); + startAnimation(0x1222A513, 0, -1); + SetUpdateHandler(&Klaymen::update); + SetMessageHandler(&KmScene1201::hmMatch); + SetSpriteUpdate(NULL); +} + +uint32 KmScene1201::hmTumbleHeadless(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Klaymen::hmLowLevelAnimation(messageNum, param, sender); + switch (messageNum) { + case 0x100D: + if (param.asInteger() == 0x000F0082) { + playSound(0, 0x74E2810F); + } + break; + } + return messageResult; +} + +} // End of namespace Neverhood diff --git a/engines/neverhood/modules/module1200_sprites.h b/engines/neverhood/modules/module1200_sprites.h new file mode 100644 index 0000000000..ef1ec40ced --- /dev/null +++ b/engines/neverhood/modules/module1200_sprites.h @@ -0,0 +1,187 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef NEVERHOOD_MODULES_MODULE1200_SPRITES_H +#define NEVERHOOD_MODULES_MODULE1200_SPRITES_H + +#include "neverhood/neverhood.h" +#include "neverhood/module.h" +#include "neverhood/scene.h" + +namespace Neverhood { + +// Used for both the scene sprites and the scene itself (for clipping) +static const NPoint kScene1201PointArray[] = { + {218, 193}, {410, 225}, {368, 277}, + {194, 227}, {366, 174}, {458, 224}, + {242, 228}, {512, 228}, {458, 277}, + {217, 233}, {458, 173}, {410, 276}, + {203, 280}, {371, 226}, {508, 279}, + {230, 273}, {410, 171}, {493, 174} +}; + +class AsScene1201Tape : public AnimatedSprite { +public: + AsScene1201Tape(NeverhoodEngine *vm, Scene *parentScene, uint32 nameHash, int surfacePriority, int16 x, int16 y, uint32 fileHash); +protected: + Scene *_parentScene; + uint32 _nameHash; + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); +}; + +class AsScene1201TntManRope : public AnimatedSprite { +public: + AsScene1201TntManRope(NeverhoodEngine *vm, bool isDummyHanging); +protected: + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); +}; + +class AsScene1201RightDoor : public AnimatedSprite { +public: + AsScene1201RightDoor(NeverhoodEngine *vm, Sprite *klaymen, bool isOpen); +protected: + Sprite *_klaymen; + int _countdown; + void update(); + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); + void stOpenDoor(); + void stCloseDoor(); + void stCloseDoorDone(); +}; + +class AsScene1201KlaymenHead : public AnimatedSprite { +public: + AsScene1201KlaymenHead(NeverhoodEngine *vm); +protected: + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); +}; + +class AsScene1201TntMan : public AnimatedSprite { +public: + AsScene1201TntMan(NeverhoodEngine *vm, Scene *parentScene, Sprite *asTntManRope, bool isDown); + virtual ~AsScene1201TntMan(); +protected: + Scene *_parentScene; + Sprite *_asTntManRope; + Sprite *_sprite; + bool _isMoving; + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); + uint32 hmComingDown(int messageNum, const MessageParam ¶m, Entity *sender); + void suMoving(); + void stStanding(); + void stComingDown(); + void stMoving(); +}; + +class AsScene1201TntManFlame : public AnimatedSprite { +public: + AsScene1201TntManFlame(NeverhoodEngine *vm, Sprite *asTntMan); + ~AsScene1201TntManFlame(); +protected: + Sprite *_asTntMan; + void update(); + void suUpdate(); +}; + +class AsScene1201Match : public AnimatedSprite { +public: + AsScene1201Match(NeverhoodEngine *vm, Scene *parentScene); +protected: + Scene *_parentScene; + int _countdown; + int _status; + void update(); + uint32 hmOnDoorFrameAboutToMove(int messageNum, const MessageParam ¶m, Entity *sender); + uint32 hmOnDoorFrameMoving(int messageNum, const MessageParam ¶m, Entity *sender); + uint32 hmIdle(int messageNum, const MessageParam ¶m, Entity *sender); + void stOnDoorFrameMoving(); + void stFallingFromDoorFrame(); + void stOnDoorFrameAboutToMove(); + void stIdleOnDoorFrame(); + void stIdleOnFloor(); +}; + +class AsScene1201Creature : public AnimatedSprite { +public: + AsScene1201Creature(NeverhoodEngine *vm, Scene *parentScene, Sprite *klaymen); +protected: + Scene *_parentScene; + Sprite *_klaymen; + int _countdown; + bool _klaymenTooClose; + void update(); + uint32 hmWaiting(int messageNum, const MessageParam ¶m, Entity *sender); + uint32 hmPincerSnap(int messageNum, const MessageParam ¶m, Entity *sender); + uint32 hmPincerSnapKlaymen(int messageNum, const MessageParam ¶m, Entity *sender); + void stWaiting(); + void stPincerSnap(); + void stStartReachForTntDummy(); + void stReachForTntDummy(); + void stPincerSnapKlaymen(); +}; + +class AsScene1201LeftDoor : public AnimatedSprite { +public: + AsScene1201LeftDoor(NeverhoodEngine *vm, Sprite *klaymen); +protected: + Sprite *_klaymen; + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); + void stCloseDoor(); +}; + +class SsScene1201Tnt : public StaticSprite { +public: + SsScene1201Tnt(NeverhoodEngine *vm, uint32 elemIndex, uint32 pointIndex, int16 clipY2); +}; + +class AsScene1202TntItem : public AnimatedSprite { +public: + AsScene1202TntItem(NeverhoodEngine *vm, Scene *parentScene, int index); +protected: + Scene *_parentScene; + int _itemIndex, _newPosition; + uint32 hmShowIdle(int messageNum, const MessageParam ¶m, Entity *sender); + uint32 hmChangePosition(int messageNum, const MessageParam ¶m, Entity *sender); + void stShowIdle(); + void stChangePositionFadeOut(); + void stChangePositionFadeIn(); + void stChangePositionDone(); +}; + +class KmScene1201 : public Klaymen { +public: + KmScene1201(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); +protected: + void stCloseEyes(); + void stTumbleHeadless(); + void stFetchMatch(); + void stLightMatch(); + + uint32 hmTumbleHeadless(int messageNum, const MessageParam ¶m, Entity *sender); + uint32 hmMatch(int messageNum, const MessageParam ¶m, Entity *sender); + + uint32 xHandleMessage(int messageNum, const MessageParam ¶m); +}; + +} // End of namespace Neverhood + +#endif /* NEVERHOOD_MODULES_MODULE1200_SPRITES_H */ diff --git a/engines/neverhood/modules/module1300.cpp b/engines/neverhood/modules/module1300.cpp index 0b883b217b..312fb85ae7 100644 --- a/engines/neverhood/modules/module1300.cpp +++ b/engines/neverhood/modules/module1300.cpp @@ -20,16 +20,15 @@ * */ -#include "neverhood/modules/module1300.h" -#include "neverhood/modules/module1000.h" -#include "neverhood/modules/module1200.h" -#include "neverhood/modules/module1400.h" -#include "neverhood/modules/module2200.h" -#include "neverhood/gamemodule.h" #include "neverhood/diskplayerscene.h" +#include "neverhood/gamemodule.h" #include "neverhood/menumodule.h" -#include "neverhood/navigationscene.h" -#include "neverhood/smackerscene.h" +#include "neverhood/modules/module1000_sprites.h" +#include "neverhood/modules/module1200_sprites.h" +#include "neverhood/modules/module1300.h" +#include "neverhood/modules/module1300_sprites.h" +#include "neverhood/modules/module1400_sprites.h" +#include "neverhood/modules/module2200_sprites.h" namespace Neverhood { @@ -311,113 +310,6 @@ void Module1300::updateScene() { } } -AsScene1302Bridge::AsScene1302Bridge(NeverhoodEngine *vm, Scene *parentScene) - : AnimatedSprite(vm, 1100), _parentScene(parentScene) { - - _x = 320; - _y = 240; - createSurface1(0x88148150, 500); - if (!getGlobalVar(V_FLYTRAP_RING_BRIDGE)) { - startAnimation(0x88148150, 0, -1); - _newStickFrameIndex = 0; - } else { - startAnimation(0x88148150, -1, -1); - _newStickFrameIndex = STICK_LAST_FRAME; - } - loadSound(0, 0x68895082); - loadSound(1, 0x689BD0C1); - SetUpdateHandler(&AnimatedSprite::update); - SetMessageHandler(&AsScene1302Bridge::handleMessage); -} - -uint32 AsScene1302Bridge::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x3002: - gotoNextState(); - break; - case 0x4808: - stLowerBridge(); - break; - case 0x4809: - stRaiseBridge(); - break; - } - return messageResult; -} - -void AsScene1302Bridge::stLowerBridge() { - startAnimation(0x88148150, 0, -1); - playSound(1); - NextState(&AsScene1302Bridge::cbLowerBridgeEvent); -} - -void AsScene1302Bridge::stRaiseBridge() { - startAnimation(0x88148150, 7, -1); - _playBackwards = true; - _newStickFrameIndex = 0; - playSound(0); -} - -void AsScene1302Bridge::cbLowerBridgeEvent() { - sendMessage(_parentScene, 0x2032, 0); - startAnimation(0x88148150, -1, -1); - _newStickFrameIndex = STICK_LAST_FRAME; -} - -SsScene1302Fence::SsScene1302Fence(NeverhoodEngine *vm) - : StaticSprite(vm, 0x11122122, 200) { - - _firstY = _y; - if (getGlobalVar(V_FLYTRAP_RING_FENCE)) - _y += 152; - loadSound(0, 0x7A00400C); - loadSound(1, 0x78184098); - SetUpdateHandler(&SsScene1302Fence::update); - SetMessageHandler(&SsScene1302Fence::handleMessage); - SetSpriteUpdate(NULL); -} - -void SsScene1302Fence::update() { - handleSpriteUpdate(); - updatePosition(); -} - -uint32 SsScene1302Fence::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x4808: - playSound(0); - SetMessageHandler(NULL); - SetSpriteUpdate(&SsScene1302Fence::suMoveDown); - break; - case 0x4809: - playSound(1); - SetMessageHandler(NULL); - SetSpriteUpdate(&SsScene1302Fence::suMoveUp); - break; - } - return messageResult; -} - -void SsScene1302Fence::suMoveDown() { - if (_y < _firstY + 152) - _y += 8; - else { - SetMessageHandler(&SsScene1302Fence::handleMessage); - SetSpriteUpdate(NULL); - } -} - -void SsScene1302Fence::suMoveUp() { - if (_y > _firstY) - _y -= 8; - else { - SetMessageHandler(&SsScene1302Fence::handleMessage); - SetSpriteUpdate(NULL); - } -} - Scene1302::Scene1302(NeverhoodEngine *vm, Module *parentModule, int which) : Scene(vm, parentModule) { @@ -581,54 +473,6 @@ uint32 Scene1302::handleMessage(int messageNum, const MessageParam ¶m, Entit return messageResult; } -AsScene1303Balloon::AsScene1303Balloon(NeverhoodEngine *vm, Scene *parentScene) - : AnimatedSprite(vm, 1100), _parentScene(parentScene) { - - createSurface(200, 128, 315); - _x = 289; - _y = 390; - startAnimation(0x800278D2, 0, -1); - SetUpdateHandler(&AnimatedSprite::update); - SetMessageHandler(&AsScene1303Balloon::handleMessage); - SetSpriteUpdate(&AnimatedSprite::updateDeltaXY); -} - -uint32 AsScene1303Balloon::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x1011: - sendMessage(_parentScene, 0x4826, 0); - messageResult = 1; - break; - case 0x2000: - stPopBalloon(); - break; - } - return messageResult; -} - -uint32 AsScene1303Balloon::hmBalloonPopped(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x100D: - if (param.asInteger() == 0x020B0003) - playSound(0, 0x742B0055); - break; - case 0x3002: - playSound(0, 0x470007EE); - stopAnimation(); - setVisible(false); - SetMessageHandler(NULL); - break; - } - return messageResult; -} - -void AsScene1303Balloon::stPopBalloon() { - startAnimation(0xAC004CD0, 0, -1); - SetMessageHandler(&AsScene1303Balloon::hmBalloonPopped); -} - Scene1303::Scene1303(NeverhoodEngine *vm, Module *parentModule) : Scene(vm, parentModule), _asBalloon(NULL) { @@ -668,29 +512,6 @@ uint32 Scene1303::handleMessage(int messageNum, const MessageParam ¶m, Entit return 0; } -AsScene1304Needle::AsScene1304Needle(NeverhoodEngine *vm, Scene *parentScene, int surfacePriority, int16 x, int16 y) - : AnimatedSprite(vm, 0x548E9411, surfacePriority, x, y), _parentScene(parentScene) { - - // NOTE: Skipped check if Klaymen already has the needle since that's done in the scene itself - SetMessageHandler(&AsScene1304Needle::handleMessage); -} - -uint32 AsScene1304Needle::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x1011: - sendMessage(_parentScene, 0x4826, 0); - messageResult = 1; - break; - case 0x4806: - setGlobalVar(V_HAS_NEEDLE, 1); - setVisible(false); - SetMessageHandler(NULL); - break; - } - return messageResult; -} - Scene1304::Scene1304(NeverhoodEngine *vm, Module *parentModule, int which) : Scene(vm, parentModule), _asNeedle(NULL) { @@ -781,91 +602,6 @@ uint32 Scene1305::handleMessage(int messageNum, const MessageParam ¶m, Entit return Scene::handleMessage(messageNum, param, sender); } -AsScene1306Elevator::AsScene1306Elevator(NeverhoodEngine *vm, Scene *parentScene, AnimatedSprite *asElevatorDoor) - : AnimatedSprite(vm, 1100), _parentScene(parentScene), _asElevatorDoor(asElevatorDoor), _isUp(false), _isDown(true), - _countdown(0) { - - _x = 320; - _y = 240; - createSurface1(0x043B0270, 100); - startAnimation(0x043B0270, 0, -1); - _newStickFrameIndex = 0; - loadSound(0, 0x1C100E83); - loadSound(1, 0x1C08CEC5); - loadSound(2, 0x5D011E87); - SetMessageHandler(&AsScene1306Elevator::handleMessage); -} - -void AsScene1306Elevator::update() { - if (_isUp && _countdown != 0 && (--_countdown == 0)) - stGoingDown(); - AnimatedSprite::update(); - if (_currFrameIndex == 7 && _asElevatorDoor->getVisible()) { - playSound(1); - _asElevatorDoor->setVisible(false); - } -} - -void AsScene1306Elevator::upGoingDown() { - AnimatedSprite::update(); - if (_currFrameIndex == 5) - _asElevatorDoor->setVisible(true); -} - -uint32 AsScene1306Elevator::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x2001: - if (_isUp) - _countdown = 144; - messageResult = _isUp ? 1 : 0; - break; - case 0x3002: - gotoNextState(); - break; - case 0x4808: - if (_isDown) - stGoingUp(); - break; - } - return messageResult; -} - -void AsScene1306Elevator::stGoingUp() { - setVisible(true); - _isDown = false; - startAnimation(0x043B0270, 0, -1); - playSound(0); - SetUpdateHandler(&AsScene1306Elevator::update); - NextState(&AsScene1306Elevator::cbGoingUpEvent); -} - -void AsScene1306Elevator::cbGoingUpEvent() { - sendMessage(_parentScene, 0x4808, 0); - _isUp = true; - _countdown = 144; - stopAnimation(); - setVisible(false); - SetUpdateHandler(&AsScene1306Elevator::update); -} - -void AsScene1306Elevator::stGoingDown() { - _isUp = false; - setVisible(true); - startAnimation(0x043B0270, -1, -1); - _playBackwards = true; - playSound(1); - SetUpdateHandler(&AsScene1306Elevator::upGoingDown); - NextState(&AsScene1306Elevator::cbGoingDownEvent); -} - -void AsScene1306Elevator::cbGoingDownEvent() { - _isDown = true; - sendMessage(_parentScene, 0x4809, 0); - stopAnimation(); - SetUpdateHandler(&AsScene1306Elevator::update); -} - Scene1306::Scene1306(NeverhoodEngine *vm, Module *parentModule, int which) : Scene(vm, parentModule) { @@ -1039,188 +775,6 @@ uint32 Scene1306::handleMessage416EB0(int messageNum, const MessageParam ¶m, return 0; } -static const uint32 kAsScene1307KeyResourceList1[] = { - 0x0438069C, 0x45B0023C, 0x05700217 -}; - -static const uint32 kAsScene1307KeyResourceList2[] = { - 0x04441334, 0x061433F0, 0x06019390 -}; - -static const uint32 kAsScene1307KeyResourceList3[] = { - 0x11A80030, 0x178812B1, 0x1488121C -}; - -static const uint32 *kAsScene1307KeyResourceLists[] = { - kAsScene1307KeyResourceList1, - kAsScene1307KeyResourceList2, - kAsScene1307KeyResourceList3 -}; - -static const int kAsScene1307KeySurfacePriorities[] = { - 700, 500, 300, 100 -}; - -const uint kAsScene1307KeyPointsCount = 12; - -static const NPoint kAsScene1307KeyPoints[] = { - {-2, 0}, {-5, 0}, { 5, 0}, - {12, 0}, {17, 0}, {25, 0}, - {16, -2}, {10, -6}, { 0, -7}, - {-7, -3}, {-3, 4}, { 2, 2} -}; - -const uint kAsScene1307KeyFrameIndicesCount = 20; - -static const int16 kAsScene1307KeyFrameIndices[] = { - 1, 4, 8, 11, 15, 16, 17, 17, 17, 16, - 15, 14, 12, 10, 9, 7, 5, 3, 2, 1 -}; - -const int kAsScene1307KeyDivValue = 200; -const int16 kAsScene1307KeyXDelta = 70; -const int16 kAsScene1307KeyYDelta = -12; - -AsScene1307Key::AsScene1307Key(NeverhoodEngine *vm, Scene *parentScene, uint keyIndex, NRect *clipRects) - : AnimatedSprite(vm, 1100), _parentScene(parentScene), _keyIndex(keyIndex), _clipRects(clipRects), - _isClickable(true) { - - NPoint pt; - const uint32 *fileHashes = kAsScene1307KeyResourceLists[_keyIndex]; - - _dataResource.load(0x22102142); - _pointList = _dataResource.getPointArray(0xAC849240); - pt = (*_pointList)[getSubVar(VA_CURR_KEY_SLOT_NUMBERS, _keyIndex)]; - _x = pt.x; - _y = pt.y; - createSurface(kAsScene1307KeySurfacePriorities[getSubVar(VA_CURR_KEY_SLOT_NUMBERS, _keyIndex) % 4], 190, 148); - startAnimation(fileHashes[0], 0, -1); - loadSound(0, 0xDC4A1280); - loadSound(1, 0xCC021233); - loadSound(2, 0xC4C23844); - loadSound(3, 0xC4523208); - SetUpdateHandler(&AnimatedSprite::update); - SetMessageHandler(&AsScene1307Key::handleMessage); -} - -uint32 AsScene1307Key::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x1011: - if (_isClickable) { - sendMessage(_parentScene, 0x4826, 0); - stRemoveKey(); - messageResult = 1; - } - break; - case 0x2000: - _isClickable = param.asInteger() != 0; - break; - case 0x2001: - setSubVar(VA_CURR_KEY_SLOT_NUMBERS, _keyIndex, param.asInteger()); - stMoveKey(); - break; - case 0x2003: - playSound(3); - stUnlock(); - break; - case 0x2004: - playSound(2); - stInsert(); - break; - } - return messageResult; -} - -void AsScene1307Key::suRemoveKey() { - if (_pointIndex < kAsScene1307KeyPointsCount) { - _x += kAsScene1307KeyPoints[_pointIndex].x; - _y += kAsScene1307KeyPoints[_pointIndex].y; - updateBounds(); - _pointIndex++; - } else { - SetSpriteUpdate(NULL); - } -} - -void AsScene1307Key::suInsertKey() { - if (_pointIndex < kAsScene1307KeyPointsCount) { - _x -= kAsScene1307KeyPoints[kAsScene1307KeyPointsCount - _pointIndex - 1].x; - _y -= kAsScene1307KeyPoints[kAsScene1307KeyPointsCount - _pointIndex - 1].y; - updateBounds(); - _pointIndex++; - if (_pointIndex == 7) - playSound(0); - } else { - SetSpriteUpdate(NULL); - sendMessage(_parentScene, 0x2002, 0); - } -} - -void AsScene1307Key::suMoveKey() { - if (_pointIndex < kAsScene1307KeyFrameIndicesCount) { - _frameIndex += kAsScene1307KeyFrameIndices[_pointIndex]; - _x = _prevX + (_deltaX * _frameIndex) / kAsScene1307KeyDivValue; - _y = _prevY + (_deltaY * _frameIndex) / kAsScene1307KeyDivValue; - updateBounds(); - _pointIndex++; - } else { - NPoint pt = (*_pointList)[getSubVar(VA_CURR_KEY_SLOT_NUMBERS, _keyIndex)]; - _x = pt.x + kAsScene1307KeyXDelta; - _y = pt.y + kAsScene1307KeyYDelta; - stInsertKey(); - } -} - -void AsScene1307Key::stRemoveKey() { - const uint32 *fileHashes = kAsScene1307KeyResourceLists[_keyIndex]; - _pointIndex = 0; - startAnimation(fileHashes[0], 0, -1); - playSound(1); - SetSpriteUpdate(&AsScene1307Key::suRemoveKey); -} - -void AsScene1307Key::stInsertKey() { - _pointIndex = 0; - sendMessage(_parentScene, 0x1022, kAsScene1307KeySurfacePriorities[getSubVar(VA_CURR_KEY_SLOT_NUMBERS, _keyIndex) % 4]); - setClipRect(_clipRects[getSubVar(VA_CURR_KEY_SLOT_NUMBERS, _keyIndex) % 4]); - _newStickFrameIndex = STICK_LAST_FRAME; - SetSpriteUpdate(&AsScene1307Key::suInsertKey); -} - -void AsScene1307Key::stMoveKey() { - NPoint pt = (*_pointList)[getSubVar(VA_CURR_KEY_SLOT_NUMBERS, _keyIndex)]; - int16 newX = pt.x + kAsScene1307KeyXDelta; - int16 newY = pt.y + kAsScene1307KeyYDelta; - sendMessage(_parentScene, 0x1022, 1000); - setClipRect(0, 0, 640, 480); - _prevX = _x; - _prevY = _y; - if (newX == _x && newY == _y) { - stInsertKey(); - } else { - const uint32 *fileHashes = kAsScene1307KeyResourceLists[_keyIndex]; - _pointIndex = 0; - _frameIndex = 0; - _deltaX = newX - _x; - _deltaY = newY - _y; - startAnimation(fileHashes[0], 0, -1); - SetSpriteUpdate(&AsScene1307Key::suMoveKey); - } -} - -void AsScene1307Key::stUnlock() { - const uint32 *fileHashes = kAsScene1307KeyResourceLists[_keyIndex]; - startAnimation(fileHashes[1], 0, -1); - _newStickFrameIndex = STICK_LAST_FRAME; -} - -void AsScene1307Key::stInsert() { - const uint32 *fileHashes = kAsScene1307KeyResourceLists[_keyIndex]; - startAnimation(fileHashes[2], 0, -1); - _newStickFrameIndex = STICK_LAST_FRAME; -} - Scene1307::Scene1307(NeverhoodEngine *vm, Module *parentModule) : Scene(vm, parentModule), _countdown(0), _asCurrKey(NULL), _isInsertingKey(false), _doLeaveScene(false), _isPuzzleSolved(false) { @@ -1360,164 +914,6 @@ static const uint32 kScene1308NumberFileHashes[] = { 0x00306322 }; -AsScene1308JaggyDoor::AsScene1308JaggyDoor(NeverhoodEngine *vm, Scene *parentScene) - : AnimatedSprite(vm, 0xBA0AE050, 1100, 320, 240), _parentScene(parentScene) { - - setVisible(false); - stopAnimation(); - SetMessageHandler(&AsScene1308JaggyDoor::handleMessage); -} - -uint32 AsScene1308JaggyDoor::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x3002: - gotoNextState(); - break; - case 0x4808: - stOpenDoor(); - break; - case 0x4809: - stCloseDoor(); - break; - } - return messageResult; -} - -void AsScene1308JaggyDoor::stOpenDoor() { - startAnimation(0xBA0AE050, 0, -1); - setVisible(true); - playSound(0, calcHash("fxDoorOpen38")); - NextState(&AsScene1308JaggyDoor::stOpenDoorDone); -} - -void AsScene1308JaggyDoor::stOpenDoorDone() { - sendMessage(_parentScene, 0x2000, 0); - stopAnimation(); - setVisible(false); -} - -void AsScene1308JaggyDoor::stCloseDoor() { - startAnimation(0xBA0AE050, -1, -1); - _playBackwards = true; - setVisible(true); - playSound(0, calcHash("fxDoorClose38")); - NextState(&AsScene1308JaggyDoor::stCloseDoorDone); -} - -void AsScene1308JaggyDoor::stCloseDoorDone() { - sendMessage(_parentScene, 0x2001, 0); - stopAnimation(); -} - -AsScene1308KeyboardDoor::AsScene1308KeyboardDoor(NeverhoodEngine *vm, Scene *parentScene) - : AnimatedSprite(vm, 0xA08A0851, 1100, 320, 240), _parentScene(parentScene) { - - playSound(0, 0x51456049); - SetMessageHandler(&AsScene1308KeyboardDoor::handleMessage); - NextState(&AsScene1308KeyboardDoor::stFallingKeys); -} - -uint32 AsScene1308KeyboardDoor::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x3002: - gotoNextState(); - break; - } - return messageResult; -} - -void AsScene1308KeyboardDoor::stFallingKeys() { - startAnimation(0x6238B191, 0, -1); - _x = 580; - _y = 383; - NextState(&AsScene1308KeyboardDoor::stFallingKeysDone); -} - -void AsScene1308KeyboardDoor::stFallingKeysDone() { - sendMessage(_parentScene, 0x2004, 0); - stopAnimation(); - setVisible(false); -} - -AsScene1308LightWallSymbols::AsScene1308LightWallSymbols(NeverhoodEngine *vm, Scene *parentScene) - : AnimatedSprite(vm, 0x80180A10, 100, 320, 240), _parentScene(parentScene) { - - setVisible(false); - stopAnimation(); - Entity::_priority = 1200; - SetMessageHandler(&AsScene1308LightWallSymbols::handleMessage); -} - -uint32 AsScene1308LightWallSymbols::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x2002: - stFadeIn(); - break; - case 0x2003: - stFadeOut(); - break; - case 0x3002: - gotoNextState(); - break; - } - return messageResult; -} - -void AsScene1308LightWallSymbols::stFadeIn() { - startAnimation(0x80180A10, 0, -1); - setVisible(true); - _newStickFrameIndex = STICK_LAST_FRAME; -} - -void AsScene1308LightWallSymbols::stFadeOut() { - startAnimation(0x80180A10, -1, -1); - _playBackwards = true; - NextState(&AsScene1308LightWallSymbols::stFadeOutDone); -} - -void AsScene1308LightWallSymbols::stFadeOutDone() { - sendMessage(_parentScene, 0x2003, 0); - stopAnimation(); - setVisible(false); -} - -SsScene1308Number::SsScene1308Number(NeverhoodEngine *vm, uint32 fileHash, int index) - : StaticSprite(vm, fileHash, 100) { - - setVisible(false); - _x = _spriteResource.getPosition().x + index * 20; - updatePosition(); -} - -AsScene1308Mouse::AsScene1308Mouse(NeverhoodEngine *vm) - : AnimatedSprite(vm, 1100) { - - _x = 286; - _y = 429; - createSurface1(0xA282C472, 100); - startAnimation(0xA282C472, 0, -1); - SetUpdateHandler(&AnimatedSprite::update); - SetMessageHandler(&AsScene1308Mouse::handleMessage); -} - -uint32 AsScene1308Mouse::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x100D: - if (param.asInteger() == 0x66382026) - playSound(0, 0x0CD84468); - else if (param.asInteger() == 0x6E28061C) - playSound(0, 0x78C8402C); - else if (param.asInteger() == 0x462F0410) - playSound(0, 0x60984E28); - break; - } - return messageResult; -} - Scene1308::Scene1308(NeverhoodEngine *vm, Module *parentModule, int which) : Scene(vm, parentModule), _isProjecting(false), _asProjector(NULL) { diff --git a/engines/neverhood/modules/module1300.h b/engines/neverhood/modules/module1300.h index 501f76304f..2f59ff16c2 100644 --- a/engines/neverhood/modules/module1300.h +++ b/engines/neverhood/modules/module1300.h @@ -30,8 +30,6 @@ namespace Neverhood { -// Module1300 - class Module1300 : public Module { public: Module1300(NeverhoodEngine *vm, Module *parentModule, int which); @@ -43,28 +41,6 @@ protected: void updateScene(); }; -class AsScene1302Bridge : public AnimatedSprite { -public: - AsScene1302Bridge(NeverhoodEngine *vm, Scene *parentScene); -protected: - Scene *_parentScene; - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); - void stLowerBridge(); - void stRaiseBridge(); - void cbLowerBridgeEvent(); -}; - -class SsScene1302Fence : public StaticSprite { -public: - SsScene1302Fence(NeverhoodEngine *vm); -protected: - int16 _firstY; - void update(); - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); - void suMoveDown(); - void suMoveUp(); -}; - class Scene1302 : public Scene { public: Scene1302(NeverhoodEngine *vm, Module *parentModule, int which); @@ -84,16 +60,6 @@ protected: uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); }; -class AsScene1303Balloon : public AnimatedSprite { -public: - AsScene1303Balloon(NeverhoodEngine *vm, Scene *parentScene); -protected: - Scene *_parentScene; - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); - uint32 hmBalloonPopped(int messageNum, const MessageParam ¶m, Entity *sender); - void stPopBalloon(); -}; - class Scene1303 : public Scene { public: Scene1303(NeverhoodEngine *vm, Module *parentModule); @@ -103,14 +69,6 @@ protected: uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); }; -class AsScene1304Needle : public AnimatedSprite { -public: - AsScene1304Needle(NeverhoodEngine *vm, Scene *parentScene, int surfacePriority, int16 x, int16 y); -protected: - Scene *_parentScene; - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); -}; - class Scene1304 : public Scene { public: Scene1304(NeverhoodEngine *vm, Module *parentModule, int which); @@ -128,24 +86,6 @@ protected: uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); }; -class AsScene1306Elevator : public AnimatedSprite { -public: - AsScene1306Elevator(NeverhoodEngine *vm, Scene *parentScene, AnimatedSprite *asElevatorDoor); -protected: - Scene *_parentScene; - AnimatedSprite *_asElevatorDoor; - bool _isUp; - bool _isDown; - int _countdown; - void update(); - void upGoingDown(); - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); - void stGoingUp(); - void cbGoingUpEvent(); - void stGoingDown(); - void cbGoingDownEvent(); -}; - class Scene1306 : public Scene { public: Scene1306(NeverhoodEngine *vm, Module *parentModule, int which); @@ -161,30 +101,6 @@ protected: uint32 handleMessage416EB0(int messageNum, const MessageParam ¶m, Entity *sender); }; -class AsScene1307Key : public AnimatedSprite { -public: - AsScene1307Key(NeverhoodEngine *vm, Scene *parentScene, uint keyIndex, NRect *clipRects); -protected: - Scene *_parentScene; - NPointArray *_pointList; - uint _pointIndex; - int _frameIndex; - uint _keyIndex; - NRect *_clipRects; - bool _isClickable; - int16 _prevX, _prevY; - int16 _deltaX, _deltaY; - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); - void suRemoveKey(); - void suInsertKey(); - void suMoveKey(); - void stRemoveKey(); - void stInsertKey(); - void stMoveKey(); - void stUnlock(); - void stInsert(); -}; - class Scene1307 : public Scene { public: Scene1307(NeverhoodEngine *vm, Module *parentModule); @@ -202,51 +118,6 @@ protected: uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); }; -class AsScene1308JaggyDoor : public AnimatedSprite { -public: - AsScene1308JaggyDoor(NeverhoodEngine *vm, Scene *parentScene); -protected: - Scene *_parentScene; - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); - void stOpenDoor(); - void stOpenDoorDone(); - void stCloseDoor(); - void stCloseDoorDone(); -}; - -class AsScene1308KeyboardDoor : public AnimatedSprite { -public: - AsScene1308KeyboardDoor(NeverhoodEngine *vm, Scene *parentScene); -protected: - Scene *_parentScene; - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); - void stFallingKeys(); - void stFallingKeysDone(); -}; - -class AsScene1308LightWallSymbols : public AnimatedSprite { -public: - AsScene1308LightWallSymbols(NeverhoodEngine *vm, Scene *parentScene); -protected: - Scene *_parentScene; - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); - void stFadeIn(); - void stFadeOut(); - void stFadeOutDone(); -}; - -class SsScene1308Number : public StaticSprite { -public: - SsScene1308Number(NeverhoodEngine *vm, uint32 fileHash, int index); -}; - -class AsScene1308Mouse : public AnimatedSprite { -public: - AsScene1308Mouse(NeverhoodEngine *vm); -protected: - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); -}; - class Scene1308 : public Scene { public: Scene1308(NeverhoodEngine *vm, Module *parentModule, int which); diff --git a/engines/neverhood/modules/module1300_sprites.cpp b/engines/neverhood/modules/module1300_sprites.cpp new file mode 100644 index 0000000000..a65f2363a3 --- /dev/null +++ b/engines/neverhood/modules/module1300_sprites.cpp @@ -0,0 +1,935 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "neverhood/modules/module1300_sprites.h" + +namespace Neverhood { + +AsScene1302Bridge::AsScene1302Bridge(NeverhoodEngine *vm, Scene *parentScene) + : AnimatedSprite(vm, 1100), _parentScene(parentScene) { + + _x = 320; + _y = 240; + createSurface1(0x88148150, 500); + if (!getGlobalVar(V_FLYTRAP_RING_BRIDGE)) { + startAnimation(0x88148150, 0, -1); + _newStickFrameIndex = 0; + } else { + startAnimation(0x88148150, -1, -1); + _newStickFrameIndex = STICK_LAST_FRAME; + } + loadSound(0, 0x68895082); + loadSound(1, 0x689BD0C1); + SetUpdateHandler(&AnimatedSprite::update); + SetMessageHandler(&AsScene1302Bridge::handleMessage); +} + +uint32 AsScene1302Bridge::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x3002: + gotoNextState(); + break; + case 0x4808: + stLowerBridge(); + break; + case 0x4809: + stRaiseBridge(); + break; + } + return messageResult; +} + +void AsScene1302Bridge::stLowerBridge() { + startAnimation(0x88148150, 0, -1); + playSound(1); + NextState(&AsScene1302Bridge::cbLowerBridgeEvent); +} + +void AsScene1302Bridge::stRaiseBridge() { + startAnimation(0x88148150, 7, -1); + _playBackwards = true; + _newStickFrameIndex = 0; + playSound(0); +} + +void AsScene1302Bridge::cbLowerBridgeEvent() { + sendMessage(_parentScene, 0x2032, 0); + startAnimation(0x88148150, -1, -1); + _newStickFrameIndex = STICK_LAST_FRAME; +} + +SsScene1302Fence::SsScene1302Fence(NeverhoodEngine *vm) + : StaticSprite(vm, 0x11122122, 200) { + + _firstY = _y; + if (getGlobalVar(V_FLYTRAP_RING_FENCE)) + _y += 152; + loadSound(0, 0x7A00400C); + loadSound(1, 0x78184098); + SetUpdateHandler(&SsScene1302Fence::update); + SetMessageHandler(&SsScene1302Fence::handleMessage); + SetSpriteUpdate(NULL); +} + +void SsScene1302Fence::update() { + handleSpriteUpdate(); + updatePosition(); +} + +uint32 SsScene1302Fence::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x4808: + playSound(0); + SetMessageHandler(NULL); + SetSpriteUpdate(&SsScene1302Fence::suMoveDown); + break; + case 0x4809: + playSound(1); + SetMessageHandler(NULL); + SetSpriteUpdate(&SsScene1302Fence::suMoveUp); + break; + } + return messageResult; +} + +void SsScene1302Fence::suMoveDown() { + if (_y < _firstY + 152) + _y += 8; + else { + SetMessageHandler(&SsScene1302Fence::handleMessage); + SetSpriteUpdate(NULL); + } +} + +void SsScene1302Fence::suMoveUp() { + if (_y > _firstY) + _y -= 8; + else { + SetMessageHandler(&SsScene1302Fence::handleMessage); + SetSpriteUpdate(NULL); + } +} + +AsScene1303Balloon::AsScene1303Balloon(NeverhoodEngine *vm, Scene *parentScene) + : AnimatedSprite(vm, 1100), _parentScene(parentScene) { + + createSurface(200, 128, 315); + _x = 289; + _y = 390; + startAnimation(0x800278D2, 0, -1); + SetUpdateHandler(&AnimatedSprite::update); + SetMessageHandler(&AsScene1303Balloon::handleMessage); + SetSpriteUpdate(&AnimatedSprite::updateDeltaXY); +} + +uint32 AsScene1303Balloon::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x1011: + sendMessage(_parentScene, 0x4826, 0); + messageResult = 1; + break; + case 0x2000: + stPopBalloon(); + break; + } + return messageResult; +} + +uint32 AsScene1303Balloon::hmBalloonPopped(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x100D: + if (param.asInteger() == 0x020B0003) + playSound(0, 0x742B0055); + break; + case 0x3002: + playSound(0, 0x470007EE); + stopAnimation(); + setVisible(false); + SetMessageHandler(NULL); + break; + } + return messageResult; +} + +void AsScene1303Balloon::stPopBalloon() { + startAnimation(0xAC004CD0, 0, -1); + SetMessageHandler(&AsScene1303Balloon::hmBalloonPopped); +} + +AsScene1304Needle::AsScene1304Needle(NeverhoodEngine *vm, Scene *parentScene, int surfacePriority, int16 x, int16 y) + : AnimatedSprite(vm, 0x548E9411, surfacePriority, x, y), _parentScene(parentScene) { + + // NOTE: Skipped check if Klaymen already has the needle since that's done in the scene itself + SetMessageHandler(&AsScene1304Needle::handleMessage); +} + +uint32 AsScene1304Needle::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x1011: + sendMessage(_parentScene, 0x4826, 0); + messageResult = 1; + break; + case 0x4806: + setGlobalVar(V_HAS_NEEDLE, 1); + setVisible(false); + SetMessageHandler(NULL); + break; + } + return messageResult; +} + +AsScene1306Elevator::AsScene1306Elevator(NeverhoodEngine *vm, Scene *parentScene, AnimatedSprite *asElevatorDoor) + : AnimatedSprite(vm, 1100), _parentScene(parentScene), _asElevatorDoor(asElevatorDoor), _isUp(false), _isDown(true), + _countdown(0) { + + _x = 320; + _y = 240; + createSurface1(0x043B0270, 100); + startAnimation(0x043B0270, 0, -1); + _newStickFrameIndex = 0; + loadSound(0, 0x1C100E83); + loadSound(1, 0x1C08CEC5); + loadSound(2, 0x5D011E87); + SetMessageHandler(&AsScene1306Elevator::handleMessage); +} + +void AsScene1306Elevator::update() { + if (_isUp && _countdown != 0 && (--_countdown == 0)) + stGoingDown(); + AnimatedSprite::update(); + if (_currFrameIndex == 7 && _asElevatorDoor->getVisible()) { + playSound(1); + _asElevatorDoor->setVisible(false); + } +} + +void AsScene1306Elevator::upGoingDown() { + AnimatedSprite::update(); + if (_currFrameIndex == 5) + _asElevatorDoor->setVisible(true); +} + +uint32 AsScene1306Elevator::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x2001: + if (_isUp) + _countdown = 144; + messageResult = _isUp ? 1 : 0; + break; + case 0x3002: + gotoNextState(); + break; + case 0x4808: + if (_isDown) + stGoingUp(); + break; + } + return messageResult; +} + +void AsScene1306Elevator::stGoingUp() { + setVisible(true); + _isDown = false; + startAnimation(0x043B0270, 0, -1); + playSound(0); + SetUpdateHandler(&AsScene1306Elevator::update); + NextState(&AsScene1306Elevator::cbGoingUpEvent); +} + +void AsScene1306Elevator::cbGoingUpEvent() { + sendMessage(_parentScene, 0x4808, 0); + _isUp = true; + _countdown = 144; + stopAnimation(); + setVisible(false); + SetUpdateHandler(&AsScene1306Elevator::update); +} + +void AsScene1306Elevator::stGoingDown() { + _isUp = false; + setVisible(true); + startAnimation(0x043B0270, -1, -1); + _playBackwards = true; + playSound(1); + SetUpdateHandler(&AsScene1306Elevator::upGoingDown); + NextState(&AsScene1306Elevator::cbGoingDownEvent); +} + +void AsScene1306Elevator::cbGoingDownEvent() { + _isDown = true; + sendMessage(_parentScene, 0x4809, 0); + stopAnimation(); + SetUpdateHandler(&AsScene1306Elevator::update); +} + +static const uint32 kAsScene1307KeyResourceList1[] = { + 0x0438069C, 0x45B0023C, 0x05700217 +}; + +static const uint32 kAsScene1307KeyResourceList2[] = { + 0x04441334, 0x061433F0, 0x06019390 +}; + +static const uint32 kAsScene1307KeyResourceList3[] = { + 0x11A80030, 0x178812B1, 0x1488121C +}; + +static const uint32 *kAsScene1307KeyResourceLists[] = { + kAsScene1307KeyResourceList1, + kAsScene1307KeyResourceList2, + kAsScene1307KeyResourceList3 +}; + +static const int kAsScene1307KeySurfacePriorities[] = { + 700, 500, 300, 100 +}; + +const uint kAsScene1307KeyPointsCount = 12; + +static const NPoint kAsScene1307KeyPoints[] = { + {-2, 0}, {-5, 0}, { 5, 0}, + {12, 0}, {17, 0}, {25, 0}, + {16, -2}, {10, -6}, { 0, -7}, + {-7, -3}, {-3, 4}, { 2, 2} +}; + +const uint kAsScene1307KeyFrameIndicesCount = 20; + +static const int16 kAsScene1307KeyFrameIndices[] = { + 1, 4, 8, 11, 15, 16, 17, 17, 17, 16, + 15, 14, 12, 10, 9, 7, 5, 3, 2, 1 +}; + +const int kAsScene1307KeyDivValue = 200; +const int16 kAsScene1307KeyXDelta = 70; +const int16 kAsScene1307KeyYDelta = -12; + +AsScene1307Key::AsScene1307Key(NeverhoodEngine *vm, Scene *parentScene, uint keyIndex, NRect *clipRects) + : AnimatedSprite(vm, 1100), _parentScene(parentScene), _keyIndex(keyIndex), _clipRects(clipRects), + _isClickable(true) { + + NPoint pt; + const uint32 *fileHashes = kAsScene1307KeyResourceLists[_keyIndex]; + + _dataResource.load(0x22102142); + _pointList = _dataResource.getPointArray(0xAC849240); + pt = (*_pointList)[getSubVar(VA_CURR_KEY_SLOT_NUMBERS, _keyIndex)]; + _x = pt.x; + _y = pt.y; + createSurface(kAsScene1307KeySurfacePriorities[getSubVar(VA_CURR_KEY_SLOT_NUMBERS, _keyIndex) % 4], 190, 148); + startAnimation(fileHashes[0], 0, -1); + loadSound(0, 0xDC4A1280); + loadSound(1, 0xCC021233); + loadSound(2, 0xC4C23844); + loadSound(3, 0xC4523208); + SetUpdateHandler(&AnimatedSprite::update); + SetMessageHandler(&AsScene1307Key::handleMessage); +} + +uint32 AsScene1307Key::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x1011: + if (_isClickable) { + sendMessage(_parentScene, 0x4826, 0); + stRemoveKey(); + messageResult = 1; + } + break; + case 0x2000: + _isClickable = param.asInteger() != 0; + break; + case 0x2001: + setSubVar(VA_CURR_KEY_SLOT_NUMBERS, _keyIndex, param.asInteger()); + stMoveKey(); + break; + case 0x2003: + playSound(3); + stUnlock(); + break; + case 0x2004: + playSound(2); + stInsert(); + break; + } + return messageResult; +} + +void AsScene1307Key::suRemoveKey() { + if (_pointIndex < kAsScene1307KeyPointsCount) { + _x += kAsScene1307KeyPoints[_pointIndex].x; + _y += kAsScene1307KeyPoints[_pointIndex].y; + updateBounds(); + _pointIndex++; + } else { + SetSpriteUpdate(NULL); + } +} + +void AsScene1307Key::suInsertKey() { + if (_pointIndex < kAsScene1307KeyPointsCount) { + _x -= kAsScene1307KeyPoints[kAsScene1307KeyPointsCount - _pointIndex - 1].x; + _y -= kAsScene1307KeyPoints[kAsScene1307KeyPointsCount - _pointIndex - 1].y; + updateBounds(); + _pointIndex++; + if (_pointIndex == 7) + playSound(0); + } else { + SetSpriteUpdate(NULL); + sendMessage(_parentScene, 0x2002, 0); + } +} + +void AsScene1307Key::suMoveKey() { + if (_pointIndex < kAsScene1307KeyFrameIndicesCount) { + _frameIndex += kAsScene1307KeyFrameIndices[_pointIndex]; + _x = _prevX + (_deltaX * _frameIndex) / kAsScene1307KeyDivValue; + _y = _prevY + (_deltaY * _frameIndex) / kAsScene1307KeyDivValue; + updateBounds(); + _pointIndex++; + } else { + NPoint pt = (*_pointList)[getSubVar(VA_CURR_KEY_SLOT_NUMBERS, _keyIndex)]; + _x = pt.x + kAsScene1307KeyXDelta; + _y = pt.y + kAsScene1307KeyYDelta; + stInsertKey(); + } +} + +void AsScene1307Key::stRemoveKey() { + const uint32 *fileHashes = kAsScene1307KeyResourceLists[_keyIndex]; + _pointIndex = 0; + startAnimation(fileHashes[0], 0, -1); + playSound(1); + SetSpriteUpdate(&AsScene1307Key::suRemoveKey); +} + +void AsScene1307Key::stInsertKey() { + _pointIndex = 0; + sendMessage(_parentScene, 0x1022, kAsScene1307KeySurfacePriorities[getSubVar(VA_CURR_KEY_SLOT_NUMBERS, _keyIndex) % 4]); + setClipRect(_clipRects[getSubVar(VA_CURR_KEY_SLOT_NUMBERS, _keyIndex) % 4]); + _newStickFrameIndex = STICK_LAST_FRAME; + SetSpriteUpdate(&AsScene1307Key::suInsertKey); +} + +void AsScene1307Key::stMoveKey() { + NPoint pt = (*_pointList)[getSubVar(VA_CURR_KEY_SLOT_NUMBERS, _keyIndex)]; + int16 newX = pt.x + kAsScene1307KeyXDelta; + int16 newY = pt.y + kAsScene1307KeyYDelta; + sendMessage(_parentScene, 0x1022, 1000); + setClipRect(0, 0, 640, 480); + _prevX = _x; + _prevY = _y; + if (newX == _x && newY == _y) { + stInsertKey(); + } else { + const uint32 *fileHashes = kAsScene1307KeyResourceLists[_keyIndex]; + _pointIndex = 0; + _frameIndex = 0; + _deltaX = newX - _x; + _deltaY = newY - _y; + startAnimation(fileHashes[0], 0, -1); + SetSpriteUpdate(&AsScene1307Key::suMoveKey); + } +} + +void AsScene1307Key::stUnlock() { + const uint32 *fileHashes = kAsScene1307KeyResourceLists[_keyIndex]; + startAnimation(fileHashes[1], 0, -1); + _newStickFrameIndex = STICK_LAST_FRAME; +} + +void AsScene1307Key::stInsert() { + const uint32 *fileHashes = kAsScene1307KeyResourceLists[_keyIndex]; + startAnimation(fileHashes[2], 0, -1); + _newStickFrameIndex = STICK_LAST_FRAME; +} + +AsScene1308JaggyDoor::AsScene1308JaggyDoor(NeverhoodEngine *vm, Scene *parentScene) + : AnimatedSprite(vm, 0xBA0AE050, 1100, 320, 240), _parentScene(parentScene) { + + setVisible(false); + stopAnimation(); + SetMessageHandler(&AsScene1308JaggyDoor::handleMessage); +} + +uint32 AsScene1308JaggyDoor::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x3002: + gotoNextState(); + break; + case 0x4808: + stOpenDoor(); + break; + case 0x4809: + stCloseDoor(); + break; + } + return messageResult; +} + +void AsScene1308JaggyDoor::stOpenDoor() { + startAnimation(0xBA0AE050, 0, -1); + setVisible(true); + playSound(0, calcHash("fxDoorOpen38")); + NextState(&AsScene1308JaggyDoor::stOpenDoorDone); +} + +void AsScene1308JaggyDoor::stOpenDoorDone() { + sendMessage(_parentScene, 0x2000, 0); + stopAnimation(); + setVisible(false); +} + +void AsScene1308JaggyDoor::stCloseDoor() { + startAnimation(0xBA0AE050, -1, -1); + _playBackwards = true; + setVisible(true); + playSound(0, calcHash("fxDoorClose38")); + NextState(&AsScene1308JaggyDoor::stCloseDoorDone); +} + +void AsScene1308JaggyDoor::stCloseDoorDone() { + sendMessage(_parentScene, 0x2001, 0); + stopAnimation(); +} + +AsScene1308KeyboardDoor::AsScene1308KeyboardDoor(NeverhoodEngine *vm, Scene *parentScene) + : AnimatedSprite(vm, 0xA08A0851, 1100, 320, 240), _parentScene(parentScene) { + + playSound(0, 0x51456049); + SetMessageHandler(&AsScene1308KeyboardDoor::handleMessage); + NextState(&AsScene1308KeyboardDoor::stFallingKeys); +} + +uint32 AsScene1308KeyboardDoor::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x3002: + gotoNextState(); + break; + } + return messageResult; +} + +void AsScene1308KeyboardDoor::stFallingKeys() { + startAnimation(0x6238B191, 0, -1); + _x = 580; + _y = 383; + NextState(&AsScene1308KeyboardDoor::stFallingKeysDone); +} + +void AsScene1308KeyboardDoor::stFallingKeysDone() { + sendMessage(_parentScene, 0x2004, 0); + stopAnimation(); + setVisible(false); +} + +AsScene1308LightWallSymbols::AsScene1308LightWallSymbols(NeverhoodEngine *vm, Scene *parentScene) + : AnimatedSprite(vm, 0x80180A10, 100, 320, 240), _parentScene(parentScene) { + + setVisible(false); + stopAnimation(); + Entity::_priority = 1200; + SetMessageHandler(&AsScene1308LightWallSymbols::handleMessage); +} + +uint32 AsScene1308LightWallSymbols::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x2002: + stFadeIn(); + break; + case 0x2003: + stFadeOut(); + break; + case 0x3002: + gotoNextState(); + break; + } + return messageResult; +} + +void AsScene1308LightWallSymbols::stFadeIn() { + startAnimation(0x80180A10, 0, -1); + setVisible(true); + _newStickFrameIndex = STICK_LAST_FRAME; +} + +void AsScene1308LightWallSymbols::stFadeOut() { + startAnimation(0x80180A10, -1, -1); + _playBackwards = true; + NextState(&AsScene1308LightWallSymbols::stFadeOutDone); +} + +void AsScene1308LightWallSymbols::stFadeOutDone() { + sendMessage(_parentScene, 0x2003, 0); + stopAnimation(); + setVisible(false); +} + +SsScene1308Number::SsScene1308Number(NeverhoodEngine *vm, uint32 fileHash, int index) + : StaticSprite(vm, fileHash, 100) { + + setVisible(false); + _x = _spriteResource.getPosition().x + index * 20; + updatePosition(); +} + +AsScene1308Mouse::AsScene1308Mouse(NeverhoodEngine *vm) + : AnimatedSprite(vm, 1100) { + + _x = 286; + _y = 429; + createSurface1(0xA282C472, 100); + startAnimation(0xA282C472, 0, -1); + SetUpdateHandler(&AnimatedSprite::update); + SetMessageHandler(&AsScene1308Mouse::handleMessage); +} + +uint32 AsScene1308Mouse::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x100D: + if (param.asInteger() == 0x66382026) + playSound(0, 0x0CD84468); + else if (param.asInteger() == 0x6E28061C) + playSound(0, 0x78C8402C); + else if (param.asInteger() == 0x462F0410) + playSound(0, 0x60984E28); + break; + } + return messageResult; +} + +KmScene1303::KmScene1303(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) + : Klaymen(vm, parentScene, x, y) { + + // Empty +} + +uint32 KmScene1303::xHandleMessage(int messageNum, const MessageParam ¶m) { + switch (messageNum) { + case 0x4804: + GotoState(&Klaymen::stPeekWall1); + break; + case 0x483B: + GotoState(&Klaymen::stPeekWallReturn); + break; + case 0x483C: + GotoState(&Klaymen::stPeekWall2); + break; + } + return 0; +} + +KmScene1304::KmScene1304(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) + : Klaymen(vm, parentScene, x, y) { + + // Empty +} + +uint32 KmScene1304::xHandleMessage(int messageNum, const MessageParam ¶m) { + switch (messageNum) { + case 0x4001: + case 0x4800: + startWalkToX(param.asPoint().x, false); + break; + case 0x4004: + GotoState(&Klaymen::stTryStandIdle); + break; + case 0x4812: + if (param.asInteger() == 2) + GotoState(&Klaymen::stPickUpNeedle); + else if (param.asInteger() == 1) + GotoState(&Klaymen::stPickUpTube); + else + GotoState(&Klaymen::stPickUpGeneric); + break; + case 0x4817: + setDoDeltaX(param.asInteger()); + gotoNextStateExt(); + break; + case 0x481B: + if (param.asPoint().y != 0) + startWalkToXDistance(param.asPoint().y, param.asPoint().x); + else + startWalkToAttachedSpriteXDistance(param.asPoint().x); + break; + case 0x481F: + if (param.asInteger() == 1) + GotoState(&Klaymen::stTurnAwayFromUse); + else if (param.asInteger() == 0) + GotoState(&Klaymen::stTurnToUseHalf); + else + GotoState(&Klaymen::stWonderAbout); + break; + case 0x483F: + startSpecialWalkRight(param.asInteger()); + break; + case 0x4840: + startSpecialWalkLeft(param.asInteger()); + break; + } + return 0; +} + +KmScene1305::KmScene1305(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) + : Klaymen(vm, parentScene, x, y) { + + // Empty +} + +uint32 KmScene1305::xHandleMessage(int messageNum, const MessageParam ¶m) { + switch (messageNum) { + case 0x4001: + case 0x4800: + startWalkToX(param.asPoint().x, false); + break; + case 0x4004: + GotoState(&Klaymen::stTryStandIdle); + break; + case 0x4804: + GotoState(&KmScene1305::stCrashDown); + break; + case 0x4817: + setDoDeltaX(param.asInteger()); + gotoNextStateExt(); + break; + } + return 0; +} + +void KmScene1305::stCrashDown() { + playSound(0, 0x41648271); + _busyStatus = 1; + _acceptInput = false; + startAnimationByHash(0x000BAB02, 0x88003000, 0); + SetUpdateHandler(&Klaymen::update); + SetSpriteUpdate(NULL); + SetMessageHandler(&Klaymen::hmLowLevelAnimation); + NextState(&KmScene1305::stCrashDownFinished); +} + +void KmScene1305::stCrashDownFinished() { + setDoDeltaX(2); + stTryStandIdle(); +} + +KmScene1306::KmScene1306(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) + : Klaymen(vm, parentScene, x, y) { + + // Empty +} + +uint32 KmScene1306::xHandleMessage(int messageNum, const MessageParam ¶m) { + uint32 messageResult = 0; + switch (messageNum) { + case 0x2000: + _isSittingInTeleporter = param.asInteger() != 0; + messageResult = 1; + break; + case 0x4001: + case 0x4800: + startWalkToX(param.asPoint().x, false); + break; + case 0x4004: + if (_isSittingInTeleporter) + GotoState(&Klaymen::stSitIdleTeleporter); + else + GotoState(&Klaymen::stTryStandIdle); + break; + case 0x4812: + if (param.asInteger() == 2) + GotoState(&Klaymen::stPickUpNeedle); + else if (param.asInteger() == 1) + GotoState(&Klaymen::stPickUpTube); + else + GotoState(&Klaymen::stPickUpGeneric); + break; + case 0x4816: + if (param.asInteger() == 1) + GotoState(&Klaymen::stPressButton); + else if (param.asInteger() == 2) + GotoState(&Klaymen::stPressFloorButton); + else + GotoState(&Klaymen::stPressButtonSide); + break; + case 0x4817: + setDoDeltaX(param.asInteger()); + gotoNextStateExt(); + break; + case 0x481A: + GotoState(&Klaymen::stInsertDisk); + break; + case 0x481B: + if (param.asPoint().y != 0) + startWalkToXDistance(param.asPoint().y, param.asPoint().x); + else + startWalkToAttachedSpriteXDistance(param.asPoint().x); + break; + case 0x481D: + if (_isSittingInTeleporter) + GotoState(&Klaymen::stTurnToUseInTeleporter); + else + GotoState(&Klaymen::stTurnToUse); + break; + case 0x481E: + if (_isSittingInTeleporter) + GotoState(&Klaymen::stReturnFromUseInTeleporter); + else + GotoState(&Klaymen::stReturnFromUse); + break; + case 0x481F: + if (param.asInteger() == 1) + GotoState(&Klaymen::stWonderAboutAfter); + else if (param.asInteger() == 0) + GotoState(&Klaymen::stWonderAboutHalf); + else if (param.asInteger() == 4) + GotoState(&Klaymen::stTurnAwayFromUse); + else if (param.asInteger() == 3) + GotoState(&Klaymen::stTurnToUseHalf); + else + GotoState(&Klaymen::stWonderAbout); + break; + case 0x482D: + setDoDeltaX(_x > (int16)param.asInteger() ? 1 : 0); + gotoNextStateExt(); + break; + case 0x482E: + if (param.asInteger() == 1) + GotoState(&Klaymen::stWalkToFrontNoStep); + else + GotoState(&Klaymen::stWalkToFront); + break; + case 0x482F: + if (param.asInteger() == 1) + GotoState(&Klaymen::stTurnToFront); + else + GotoState(&Klaymen::stTurnToBack); + break; + case 0x4834: + GotoState(&Klaymen::stStepOver); + break; + case 0x4835: + sendMessage(_parentScene, 0x2000, 1); + _isSittingInTeleporter = true; + GotoState(&Klaymen::stSitInTeleporter); + break; + case 0x4836: + sendMessage(_parentScene, 0x2000, 0); + _isSittingInTeleporter = false; + GotoState(&Klaymen::stGetUpFromTeleporter); + break; + case 0x483D: + teleporterAppear(0xEE084A04); + break; + case 0x483E: + teleporterDisappear(0xB86A4274); + break; + case 0x483F: + startSpecialWalkRight(param.asInteger()); + break; + case 0x4840: + startSpecialWalkLeft(param.asInteger()); + break; + } + return messageResult; +} + +KmScene1308::KmScene1308(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) + : Klaymen(vm, parentScene, x, y) { + + // Empty +} + +uint32 KmScene1308::xHandleMessage(int messageNum, const MessageParam ¶m) { + switch (messageNum) { + case 0x4001: + case 0x4800: + startWalkToX(param.asPoint().x, false); + break; + case 0x4004: + GotoState(&Klaymen::stTryStandIdle); + break; + case 0x480A: + if (param.asInteger() == 1) + GotoState(&Klaymen::stMoveObjectSkipTurnFaceObject); + else + GotoState(&Klaymen::stMoveObjectFaceObject); + break; + case 0x480D: + GotoState(&Klaymen::stUseLever); + break; + case 0x4812: + if (param.asInteger() == 2) + GotoState(&Klaymen::stPickUpNeedle); + else if (param.asInteger() == 1) + GotoState(&Klaymen::stPickUpTube); + else + GotoState(&Klaymen::stPickUpGeneric); + break; + case 0x4817: + setDoDeltaX(param.asInteger()); + gotoNextStateExt(); + break; + case 0x481A: + if (param.asInteger() == 1) + GotoState(&Klaymen::stInsertKey); + else + GotoState(&Klaymen::stInsertDisk); + break; + case 0x481B: + if (param.asPoint().y != 0) + startWalkToXDistance(param.asPoint().y, param.asPoint().x); + else + startWalkToAttachedSpriteXDistance(param.asPoint().x); + break; + case 0x481D: + GotoState(&Klaymen::stTurnToUse); + break; + case 0x481E: + GotoState(&Klaymen::stReturnFromUse); + break; + case 0x4827: + GotoState(&Klaymen::stReleaseLever); + break; + case 0x4834: + GotoState(&Klaymen::stStepOver); + break; + case 0x483F: + startSpecialWalkRight(param.asInteger()); + break; + case 0x4840: + startSpecialWalkLeft(param.asInteger()); + break; + } + return 0; +} + +} // End of namespace Neverhood diff --git a/engines/neverhood/modules/module1300_sprites.h b/engines/neverhood/modules/module1300_sprites.h new file mode 100644 index 0000000000..e044d3cec8 --- /dev/null +++ b/engines/neverhood/modules/module1300_sprites.h @@ -0,0 +1,200 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef NEVERHOOD_MODULES_MODULE1300_SPRITES_H +#define NEVERHOOD_MODULES_MODULE1300_SPRITES_H + +#include "neverhood/neverhood.h" +#include "neverhood/module.h" +#include "neverhood/scene.h" +#include "neverhood/smackerplayer.h" + +namespace Neverhood { + +class AsScene1302Bridge : public AnimatedSprite { +public: + AsScene1302Bridge(NeverhoodEngine *vm, Scene *parentScene); +protected: + Scene *_parentScene; + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); + void stLowerBridge(); + void stRaiseBridge(); + void cbLowerBridgeEvent(); +}; + +class SsScene1302Fence : public StaticSprite { +public: + SsScene1302Fence(NeverhoodEngine *vm); +protected: + int16 _firstY; + void update(); + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); + void suMoveDown(); + void suMoveUp(); +}; + +class AsScene1303Balloon : public AnimatedSprite { +public: + AsScene1303Balloon(NeverhoodEngine *vm, Scene *parentScene); +protected: + Scene *_parentScene; + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); + uint32 hmBalloonPopped(int messageNum, const MessageParam ¶m, Entity *sender); + void stPopBalloon(); +}; + +class AsScene1304Needle : public AnimatedSprite { +public: + AsScene1304Needle(NeverhoodEngine *vm, Scene *parentScene, int surfacePriority, int16 x, int16 y); +protected: + Scene *_parentScene; + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); +}; + +class AsScene1306Elevator : public AnimatedSprite { +public: + AsScene1306Elevator(NeverhoodEngine *vm, Scene *parentScene, AnimatedSprite *asElevatorDoor); +protected: + Scene *_parentScene; + AnimatedSprite *_asElevatorDoor; + bool _isUp; + bool _isDown; + int _countdown; + void update(); + void upGoingDown(); + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); + void stGoingUp(); + void cbGoingUpEvent(); + void stGoingDown(); + void cbGoingDownEvent(); +}; + +class AsScene1307Key : public AnimatedSprite { +public: + AsScene1307Key(NeverhoodEngine *vm, Scene *parentScene, uint keyIndex, NRect *clipRects); +protected: + Scene *_parentScene; + NPointArray *_pointList; + uint _pointIndex; + int _frameIndex; + uint _keyIndex; + NRect *_clipRects; + bool _isClickable; + int16 _prevX, _prevY; + int16 _deltaX, _deltaY; + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); + void suRemoveKey(); + void suInsertKey(); + void suMoveKey(); + void stRemoveKey(); + void stInsertKey(); + void stMoveKey(); + void stUnlock(); + void stInsert(); +}; + +class AsScene1308JaggyDoor : public AnimatedSprite { +public: + AsScene1308JaggyDoor(NeverhoodEngine *vm, Scene *parentScene); +protected: + Scene *_parentScene; + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); + void stOpenDoor(); + void stOpenDoorDone(); + void stCloseDoor(); + void stCloseDoorDone(); +}; + +class AsScene1308KeyboardDoor : public AnimatedSprite { +public: + AsScene1308KeyboardDoor(NeverhoodEngine *vm, Scene *parentScene); +protected: + Scene *_parentScene; + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); + void stFallingKeys(); + void stFallingKeysDone(); +}; + +class AsScene1308LightWallSymbols : public AnimatedSprite { +public: + AsScene1308LightWallSymbols(NeverhoodEngine *vm, Scene *parentScene); +protected: + Scene *_parentScene; + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); + void stFadeIn(); + void stFadeOut(); + void stFadeOutDone(); +}; + +class SsScene1308Number : public StaticSprite { +public: + SsScene1308Number(NeverhoodEngine *vm, uint32 fileHash, int index); +}; + +class AsScene1308Mouse : public AnimatedSprite { +public: + AsScene1308Mouse(NeverhoodEngine *vm); +protected: + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); +}; + +class KmScene1303 : public Klaymen { +public: + KmScene1303(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); +protected: + uint32 xHandleMessage(int messageNum, const MessageParam ¶m); +}; + +class KmScene1304 : public Klaymen { +public: + KmScene1304(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); +protected: + uint32 xHandleMessage(int messageNum, const MessageParam ¶m); +}; + +class KmScene1305 : public Klaymen { +public: + KmScene1305(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); +protected: + void stCrashDown(); + void stCrashDownFinished(); + + uint32 xHandleMessage(int messageNum, const MessageParam ¶m); +}; + +class KmScene1306 : public Klaymen { +public: + KmScene1306(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); +protected: + uint32 xHandleMessage(int messageNum, const MessageParam ¶m); +}; + +class KmScene1308 : public Klaymen { +public: + KmScene1308(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); +protected: + uint32 xHandleMessage(int messageNum, const MessageParam ¶m); +}; + +} // End of namespace Neverhood + +#endif /* NEVERHOOD_MODULES_MODULE1300_SPRITES_H */ diff --git a/engines/neverhood/modules/module1400.cpp b/engines/neverhood/modules/module1400.cpp index 0a029632b6..2fc1052ab1 100644 --- a/engines/neverhood/modules/module1400.cpp +++ b/engines/neverhood/modules/module1400.cpp @@ -20,12 +20,14 @@ * */ -#include "neverhood/modules/module1400.h" -#include "neverhood/modules/module1000.h" -#include "neverhood/modules/module2100.h" -#include "neverhood/modules/module2200.h" #include "neverhood/diskplayerscene.h" #include "neverhood/gamemodule.h" +#include "neverhood/modules/module1000_sprites.h" +#include "neverhood/modules/module1200_sprites.h" +#include "neverhood/modules/module1400.h" +#include "neverhood/modules/module1400_sprites.h" +#include "neverhood/modules/module2100_sprites.h" +#include "neverhood/modules/module2200_sprites.h" namespace Neverhood { @@ -135,497 +137,6 @@ void Module1400::updateScene() { } } -// Scene1401 - -AsScene1401Pipe::AsScene1401Pipe(NeverhoodEngine *vm) - : AnimatedSprite(vm, 1100), _countdown1(0), _countdown2(0) { - - createSurface(900, 152, 147); - _x = 454; - _y = 217; - startAnimation(0x4C210500, 0, -1); - SetUpdateHandler(&AsScene1401Pipe::update); - SetMessageHandler(&AsScene1401Pipe::handleMessage); -} - -AsScene1401Pipe::~AsScene1401Pipe() { - _vm->_soundMan->deleteSoundGroup(0x01104C08); -} - -void AsScene1401Pipe::update() { - AnimatedSprite::update(); - if (_countdown1 != 0 && (--_countdown1 == 0)) - stDoneSucking(); - if (_countdown2 != 0 && (--_countdown2 == 0)) { - _vm->_soundMan->addSound(0x01104C08, 0x4A116437); - _vm->_soundMan->playSoundLooping(0x4A116437); - } -} - -void AsScene1401Pipe::upSuckInProjector() { - AnimatedSprite::update(); - if (_countdown1 != 0) - _countdown1--; -} - -uint32 AsScene1401Pipe::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x100D: - if (param.asInteger() == 0x0A8A1490) - playSound(1, 0x6AB6666F); - break; - case 0x2000: - _countdown1 = 70; - _countdown2 = 8; - stStartSucking(); - break; - case 0x483A: - stSuckInProjector(); - break; - } - return messageResult; -} - -uint32 AsScene1401Pipe::hmSuckInProjector(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x3002: - if (_countdown1 != 0) - stStartSucking(); - else - stDoneSucking(); - SetMessageHandler(&AsScene1401Pipe::handleMessage); - SetUpdateHandler(&AsScene1401Pipe::update); - break; - } - return messageResult; -} - -void AsScene1401Pipe::stStartSucking() { - startAnimation(0x4C240100, 0, -1); - playSound(0, 0x4A30063F); -} - -void AsScene1401Pipe::stDoneSucking() { - _vm->_soundMan->deleteSound(0x4A116437); - playSound(0, 0x4A120435); - startAnimation(0x4C210500, 0, -1); -} - -void AsScene1401Pipe::stSuckInProjector() { - startAnimation(0x6C210810, 0, -1); - SetUpdateHandler(&AsScene1401Pipe::upSuckInProjector); - SetMessageHandler(&AsScene1401Pipe::hmSuckInProjector); -} - -AsScene1401Mouse::AsScene1401Mouse(NeverhoodEngine *vm) - : AnimatedSprite(vm, 1100) { - - createSurface(100, 71, 41); - _x = 478; - _y = 433; - startAnimation(0xA282C472, 0, -1); - SetUpdateHandler(&AnimatedSprite::update); - SetMessageHandler(&AsScene1401Mouse::handleMessage); -} - -uint32 AsScene1401Mouse::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x100D: - if (param.asInteger() == 0x66382026) - playSound(0, 0x0CD84468); - else if (param.asInteger() == 0x6E28061C) - playSound(0, 0x78C8402C); - else if (param.asInteger() == 0x462F0410) - playSound(0, 0x60984E28); - break; - case 0x4839: - stSuckedIn(); - break; - } - return messageResult; -} - -void AsScene1401Mouse::suSuckedIn() { - AnimatedSprite::updateDeltaXY(); - if (_collisionBounds.y1 <= 150) { - playSound(0, 0x0E32247F); - stopAnimation(); - setVisible(false); - SetMessageHandler(NULL); - SetSpriteUpdate(NULL); - } -} - -void AsScene1401Mouse::stSuckedIn() { - startAnimation(0x34880040, 0, -1); - SetSpriteUpdate(&AsScene1401Mouse::suSuckedIn); -} - -AsScene1401Cheese::AsScene1401Cheese(NeverhoodEngine *vm) - : AnimatedSprite(vm, 1100) { - - createSurface(200, 152, 147); - _x = 427; - _y = 433; - startAnimation(0x461A1490, 0, -1); - SetUpdateHandler(&AnimatedSprite::update); - SetMessageHandler(&AsScene1401Cheese::handleMessage); -} - -uint32 AsScene1401Cheese::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x4839: - stSuckedIn(); - break; - } - return messageResult; -} - -void AsScene1401Cheese::suSuckedIn() { - AnimatedSprite::updateDeltaXY(); - if (_collisionBounds.y1 <= 150) { - playSound(0, 0x18020439); - stopAnimation(); - setVisible(false); - SetMessageHandler(NULL); - SetSpriteUpdate(NULL); - } -} - -void AsScene1401Cheese::stSuckedIn() { - startAnimation(0x103B8020, 0, -1); - SetSpriteUpdate(&AsScene1401Cheese::suSuckedIn); -} - -AsScene1401BackDoor::AsScene1401BackDoor(NeverhoodEngine *vm, Sprite *klaymen, bool isOpen) - : AnimatedSprite(vm, 1100), _klaymen(klaymen), _countdown(0), _isOpen(isOpen) { - - _x = 320; - _y = 240; - createSurface1(0x04551900, 100); - if (isOpen) { - startAnimation(0x04551900, -1, -1); - _countdown = 48; - } else { - stopAnimation(); - setVisible(false); - } - _newStickFrameIndex = STICK_LAST_FRAME; - SetUpdateHandler(&AsScene1401BackDoor::update); - SetMessageHandler(&AsScene1401BackDoor::handleMessage); -} - -void AsScene1401BackDoor::update() { - if (_countdown != 0 && (--_countdown == 0)) - stCloseDoor(); - AnimatedSprite::update(); -} - - -uint32 AsScene1401BackDoor::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x2001: - if (_isOpen) - _countdown = 168; - messageResult = _isOpen ? 1 : 0; - break; - case 0x3002: - gotoNextState(); - break; - case 0x4808: - _countdown = 168; - if (!_isOpen) - stOpenDoor(); - break; - } - return messageResult; -} - -void AsScene1401BackDoor::stOpenDoor() { - _isOpen = true; - setVisible(true); - startAnimation(0x04551900, 0, -1); - _newStickFrameIndex = STICK_LAST_FRAME; - playSound(0, calcHash("fxDoorOpen24")); -} - -void AsScene1401BackDoor::stCloseDoor() { - _isOpen = false; - setVisible(true); - startAnimation(0x04551900, -1, -1); - playSound(0, calcHash("fxDoorClose24")); - _playBackwards = true; - NextState(&AsScene1401BackDoor::stCloseDoorDone); -} - -void AsScene1401BackDoor::stCloseDoorDone() { - stopAnimation(); - setVisible(false); -} - -static const AsCommonProjectorItem kAsCommonProjectorItems[] = { - {{154, 453}, 4, 2, 0, 0, 1}, - {{104, 391}, 4, -1, -1, 1, 1}, - {{ 22, 447}, 6, -1, -1, 1, 1}, - {{112, 406}, 2, -1, -1, 1, 0}, - {{262, 433}, 1, 1, 0, 0, 0} -}; - -AsCommonProjector::AsCommonProjector(NeverhoodEngine *vm, Scene *parentScene, Sprite *klaymen, Sprite *asPipe) - : AnimatedSprite(vm, 1100), _parentScene(parentScene), _klaymen(klaymen), _asPipe(asPipe) { - - _asProjectorItem = &kAsCommonProjectorItems[getGlobalVar(V_PROJECTOR_LOCATION)]; - createSurface(990, 101, 182); - startAnimation(0x10E3042B, 0, -1); - SetUpdateHandler(&AnimatedSprite::update); - SetMessageHandler(&AsCommonProjector::handleMessage); - _x = getGlobalVar(V_PROJECTOR_SLOT) * 108 + _asProjectorItem->point.x; - _lockedInSlot = true; - moveProjector(); - setDoDeltaX(1); - if ((int8)getGlobalVar(V_PROJECTOR_SLOT) == _asProjectorItem->lockSlotIndex) - stStayLockedInSlot(); - loadSound(2, 0xC8C2507C); -} - -AsCommonProjector::~AsCommonProjector() { - _vm->_soundMan->deleteSoundGroup(0x05331081); -} - -uint32 AsCommonProjector::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x1011: - sendMessage(_parentScene, 0x4826, 0); - messageResult = 1; - break; - case 0x4807: - setGlobalVar(V_PROJECTOR_SLOT, (_x - _asProjectorItem->point.x) / 108); - if ((int8)getGlobalVar(V_PROJECTOR_SLOT) == _asProjectorItem->lockSlotIndex) - stStartLockedInSlot(); - else - stIdle(); - break; - case 0x480B: - if (param.asInteger() != 1) { - if ((int8)getGlobalVar(V_PROJECTOR_SLOT) < _asProjectorItem->maxSlotCount) - incGlobalVar(V_PROJECTOR_SLOT, 1); - } else if (getGlobalVar(V_PROJECTOR_SLOT) > 0) - incGlobalVar(V_PROJECTOR_SLOT, -1); - stMoving(); - break; - case 0x480C: - // Check if the projector can be moved - if (param.asInteger() != 1) - messageResult = (int8)getGlobalVar(V_PROJECTOR_SLOT) < _asProjectorItem->maxSlotCount ? 1 : 0; - else - messageResult = getGlobalVar(V_PROJECTOR_SLOT) > 0 ? 1 : 0; - break; - case 0x482A: - sendMessage(_parentScene, 0x1022, 990); - break; - case 0x482B: - sendMessage(_parentScene, 0x1022, 1010); - break; - case 0x4839: - stStartSuckedIn(); - break; - } - return messageResult; -} - -uint32 AsCommonProjector::hmLockedInSlot(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x1011: - if (param.asPoint().x - _x >= 17 && param.asPoint().x - _x <= 56 && - param.asPoint().y - _y >= -120 && param.asPoint().y - _y <= -82) { - sendMessage(_parentScene, 0x4826, 1); - } else - sendMessage(_parentScene, 0x4826, 0); - messageResult = 1; - break; - case 0x4807: - sendMessage(_parentScene, 0x4807, 0); - stStopProjecting(); - break; - case 0x480B: - if (param.asInteger() != 1) { - if ((int8)getGlobalVar(V_PROJECTOR_SLOT) < _asProjectorItem->maxSlotCount) - incGlobalVar(V_PROJECTOR_SLOT, 1); - } else if (getGlobalVar(V_PROJECTOR_SLOT) > 0) - incGlobalVar(V_PROJECTOR_SLOT, -1); - stTurnToFront(); - break; - case 0x480C: - // Check if the projector can be moved - if (param.asInteger() != 1) - messageResult = (int8)getGlobalVar(V_PROJECTOR_SLOT) < _asProjectorItem->maxSlotCount ? 1 : 0; - else - messageResult = getGlobalVar(V_PROJECTOR_SLOT) > 0 ? 1 : 0; - break; - case 0x480F: - stStartProjecting(); - break; - case 0x482A: - sendMessage(_parentScene, 0x1022, 990); - break; - case 0x482B: - sendMessage(_parentScene, 0x1022, 1010); - break; - } - return messageResult; -} - -uint32 AsCommonProjector::hmAnimation(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x3002: - gotoNextState(); - break; - } - return messageResult; -} - -void AsCommonProjector::suMoving() { - if (_x <= _klaymen->getX()) - _x = _klaymen->getX() - 100; - else - _x = _klaymen->getX() + 100; - moveProjector(); - if (_beforeMoveX == _x) { - if (getGlobalVar(V_PROJECTOR_SLOT) == 0 && _asProjectorItem->leftBorderLeaves != 0) { - sendMessage(_parentScene, 0x1019, 0); - incGlobalVar(V_PROJECTOR_LOCATION, -1); - setGlobalVar(V_PROJECTOR_SLOT, kAsCommonProjectorItems[getGlobalVar(V_PROJECTOR_LOCATION)].maxSlotCount); - } else if ((int8)getGlobalVar(V_PROJECTOR_SLOT) == _asProjectorItem->maxSlotCount && _asProjectorItem->rightBorderLeaves != 0) { - sendMessage(_parentScene, 0x1019, 1); - incGlobalVar(V_PROJECTOR_LOCATION, +1); - setGlobalVar(V_PROJECTOR_SLOT, 0); - } - } - Sprite::updateBounds(); -} - -void AsCommonProjector::moveProjector() { - - bool nowLockedInSlot = false; - - _y = _asProjectorItem->point.y; - - if (_asProjectorItem->index1 != -1) { - int16 elX = _asProjectorItem->index1 * 108 + _asProjectorItem->point.x; - if (elX - 20 < _x && elX + 20 > _x) { - nowLockedInSlot = true; - _y = _asProjectorItem->point.y + 10; - } - } - - if (_asProjectorItem->lockSlotIndex != -1) { - int16 elX = _asProjectorItem->lockSlotIndex * 108 + _asProjectorItem->point.x; - if (elX - 20 < _x && elX + 20 > _x) { - nowLockedInSlot = true; - _y = _asProjectorItem->point.y + 10; - } - } - - if (_lockedInSlot && !nowLockedInSlot) - _lockedInSlot = false; - else if (!_lockedInSlot && nowLockedInSlot) { - playSound(1, 0x5440E474); - _lockedInSlot = true; - } - -} - -void AsCommonProjector::stSuckedIn() { - AnimatedSprite::updateDeltaXY(); - if (_collisionBounds.y1 <= 150) { - sendMessage(_asPipe, 0x483A, 0); - stopAnimation(); - setVisible(false); - SetMessageHandler(&Sprite::handleMessage); - SetSpriteUpdate(NULL); - } -} - -void AsCommonProjector::stIdle() { - startAnimation(0x10E3042B, 0, -1); - SetMessageHandler(&AsCommonProjector::handleMessage); - SetSpriteUpdate(NULL); -} - -void AsCommonProjector::stMoving() { - _beforeMoveX = getGlobalVar(V_PROJECTOR_SLOT) * 108 + _asProjectorItem->point.x; - startAnimation(0x14A10137, 0, -1); - playSound(1, 0xEC008474); - SetMessageHandler(&AsCommonProjector::handleMessage); - SetSpriteUpdate(&AsCommonProjector::suMoving); -} - -void AsCommonProjector::stStartLockedInSlot() { - startAnimation(0x80C32213, 0, -1); - SetMessageHandler(&AsCommonProjector::hmAnimation); - SetSpriteUpdate(NULL); - NextState(&AsCommonProjector::stStayLockedInSlot); -} - -void AsCommonProjector::stStayLockedInSlot() { - startAnimation(0xD23B207F, 0, -1); - SetMessageHandler(&AsCommonProjector::hmLockedInSlot); - SetSpriteUpdate(NULL); -} - -void AsCommonProjector::stStartProjecting() { - startAnimation(0x50A80517, 0, -1); - setGlobalVar(V_PROJECTOR_ACTIVE, 1); - playSound(0, 0xCC4A8456); - _vm->_soundMan->addSound(0x05331081, 0xCE428854); - _vm->_soundMan->playSoundLooping(0xCE428854); - SetMessageHandler(&AsCommonProjector::hmAnimation); - SetSpriteUpdate(NULL); - NextState(&AsCommonProjector::stLockedInSlot); -} - -void AsCommonProjector::stLockedInSlot() { - sendMessage(_parentScene, 0x480F, 0); - startAnimation(0xD833207F, 0, -1); - SetMessageHandler(&AsCommonProjector::hmLockedInSlot); - SetSpriteUpdate(NULL); -} - -void AsCommonProjector::stStopProjecting() { - startAnimation(0x50A94417, 0, -1); - setGlobalVar(V_PROJECTOR_ACTIVE, 0); - playSound(0, 0xCC4A8456); - _vm->_soundMan->deleteSound(0xCE428854); - SetMessageHandler(&AsCommonProjector::hmAnimation); - SetSpriteUpdate(NULL); - NextState(&AsCommonProjector::stStayLockedInSlot); -} - -void AsCommonProjector::stTurnToFront() { - _beforeMoveX = getGlobalVar(V_PROJECTOR_SLOT) * 108 + _asProjectorItem->point.x; - startAnimation(0x22CB4A33, 0, -1); - SetMessageHandler(&AsCommonProjector::hmAnimation); - SetSpriteUpdate(&AsCommonProjector::suMoving); - NextState(&AsCommonProjector::stMoving); -} - -void AsCommonProjector::stStartSuckedIn() { - setGlobalVar(V_PROJECTOR_LOCATION, 4); - setGlobalVar(V_PROJECTOR_SLOT, 0); - startAnimation(0x708D4712, 0, -1); - playSound(2); - SetMessageHandler(&Sprite::handleMessage); - SetSpriteUpdate(&AsCommonProjector::stSuckedIn); -} - Scene1401::Scene1401(NeverhoodEngine *vm, Module *parentModule, int which) : Scene(vm, parentModule), _projectorBorderFlag(false), _ssFloorButton(NULL), _asProjector(NULL), _asPipe(NULL), _asMouse(NULL), _asCheese(NULL), _asBackDoor(NULL), @@ -768,77 +279,6 @@ uint32 Scene1401::handleMessage(int messageNum, const MessageParam ¶m, Entit return 0; } -// Scene1402 - -SsScene1402BridgePart::SsScene1402BridgePart(NeverhoodEngine *vm, uint32 fileHash, int surfacePriority) - : StaticSprite(vm, fileHash, surfacePriority) { - - SetFilterY(&Sprite::defFilterY); - SetUpdateHandler(&StaticSprite::updatePosition); -} - -AsScene1402PuzzleBox::AsScene1402PuzzleBox(NeverhoodEngine *vm, Scene *parentScene, int status) - : AnimatedSprite(vm, 1100), _parentScene(parentScene) { - - createSurface(900, 347, 230); - - SetFilterY(&Sprite::defFilterY); - SetUpdateHandler(&AnimatedSprite::update); - SetMessageHandler(&AsScene1402PuzzleBox::handleMessage); - _x = 279; - _y = 270; - if (status == 2) { - // Puzzle box after the puzzle was solved - startAnimation(0x20060259, 0, -1); - playSound(0, 0x419014AC); - loadSound(1, 0x61901C29); - NextState(&AsScene1402PuzzleBox::stMoveDownSolvedDone); - } else if (status == 1) { - // Puzzle box appears - startAnimation(0x210A0213, 0, -1); - playSound(0, 0x41809C6C); - NextState(&AsScene1402PuzzleBox::stMoveUpDone); - } else { - // Puzzle box is here - startAnimation(0x20060259, -1, -1); - loadSound(1, 0x61901C29); - _newStickFrameIndex = STICK_LAST_FRAME; - } -} - -uint32 AsScene1402PuzzleBox::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x2002: - playSound(1); - startAnimation(0x20060259, -1, -1); - _playBackwards = true; - NextState(&AsScene1402PuzzleBox::stMoveDownDone); - break; - case 0x3002: - gotoNextState(); - break; - } - return messageResult; -} - -void AsScene1402PuzzleBox::stMoveUpDone() { - sendMessage(_parentScene, 0x2000, 0); - stopAnimation(); - setVisible(false); -} - -void AsScene1402PuzzleBox::stMoveDownDone() { - sendMessage(_parentScene, 0x2001, 0); - stopAnimation(); - setVisible(false); -} - -void AsScene1402PuzzleBox::stMoveDownSolvedDone() { - sendMessage(_parentScene, 0x2003, 0); - stopAnimation(); -} - Scene1402::Scene1402(NeverhoodEngine *vm, Module *parentModule, int which) : Scene(vm, parentModule), _isShaking(false), _asPuzzleBox(NULL), _asProjector(NULL) { @@ -988,237 +428,6 @@ void Scene1402::stopShaking() { _isShaking = false; } -// Scene1407 - -static const int16 kScene1407MouseFloorY[] = { - 106, 150, 191, 230, 267, 308, 350, 395 -}; - -static const struct { - int16 x; - int16 floorIndex; - int16 sectionIndex; - int16 nextHoleIndex; -} kScene1407MouseHoles[] = { - {125, 0, 0, 7}, - {452, 7, 21, 0}, - {337, 4, 11, 4}, - {286, 6, 17, 6}, - {348, 6, 17, 39}, - {536, 6, 18, 42}, - {111, 1, 3, 18}, - {203, 1, 3, 38}, - {270, 1, 3, 9}, - {197, 5, 14, 3}, - {252, 5, 14, 35}, - {297, 5, 14, 7}, - {359, 5, 14, 8}, - {422, 4, 12, 26}, - {467, 4, 12, 2}, - {539, 4, 12, 40}, - {111, 5, 13, 17}, - {211, 0, 1, 20}, - {258, 0, 1, 11}, - {322, 0, 1, 16}, - { 99, 6, 16, 31}, - {142, 6, 16, 27}, - {194, 6, 16, 12}, - {205, 2, 6, 45}, - {264, 2, 6, 10}, - { 98, 4, 10, 2}, - {152, 4, 10, 37}, - {199, 4, 10, 13}, - {258, 4, 10, 16}, - {100, 7, 19, 43}, - {168, 7, 19, 23}, - {123, 3, 8, 14}, - {181, 3, 8, 39}, - {230, 3, 8, 28}, - {292, 3, 8, 22}, - {358, 3, 8, 36}, - {505, 3, 9, 44}, - {400, 2, 7, 34}, - {454, 2, 7, 32}, - {532, 2, 7, 46}, - {484, 5, 15, 25}, - {529, 5, 15, 30}, - {251, 7, 20, 48}, - {303, 7, 20, 21}, - {360, 7, 20, 33}, - {503, 0, 2, 5}, - {459, 1, 4, 19}, - {530, 1, 4, 42}, - {111, 2, 5, 47}, - {442, 6, 18, 1} -}; - -static const struct { - int16 x1, x2; - int16 goodHoleIndex; -} kScene1407MouseSections[] = { - {100, 149, 0}, - {182, 351, 17}, - {430, 524, 45}, - { 89, 293, 7}, - {407, 555, 47}, - { 89, 132, 48}, - {178, 303, 23}, - {367, 551, 38}, - {105, 398, 31}, - {480, 537, 36}, - { 84, 275, 27}, - {318, 359, 2}, - {402, 560, 15}, - { 91, 132, 16}, - {179, 400, 10}, - {461, 552, 41}, - { 86, 218, 21}, - {267, 376, 4}, - {420, 560, 49}, - { 77, 188, 30}, - {237, 394, 44}, - {438, 515, 5} -}; - -AsScene1407Mouse::AsScene1407Mouse(NeverhoodEngine *vm, Scene *parentScene) - : AnimatedSprite(vm, 1100), _parentScene(parentScene), _currSectionIndex(0) { - - createSurface(100, 117, 45); - _x = 108; - _y = 106; - stIdleLookAtGoodHole(); - SetUpdateHandler(&AnimatedSprite::update); -} - -void AsScene1407Mouse::suWalkTo() { - int16 xdelta = _walkDestX - _x; - if (xdelta > _deltaX) - xdelta = _deltaX; - else if (xdelta < -_deltaX) - xdelta = -_deltaX; - _deltaX = 0; - if (_walkDestX == _x) - sendMessage(this, 0x1019, 0); - else { - _x += xdelta; - updateBounds(); - } -} - -void AsScene1407Mouse::upGoThroughHole() { - if (_countdown != 0 && (--_countdown == 0)) { - SetUpdateHandler(&AnimatedSprite::update); - gotoNextState(); - } - AnimatedSprite::update(); -} - -uint32 AsScene1407Mouse::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x0001: - { - int16 mouseX = param.asPoint().x; - int16 mouseY = param.asPoint().y; - int holeIndex; - for (holeIndex = 0; holeIndex < 50; holeIndex++) { - int16 holeX = kScene1407MouseHoles[holeIndex].x; - int16 holeY = kScene1407MouseFloorY[kScene1407MouseHoles[holeIndex].floorIndex]; - if (mouseX >= holeX - 14 && mouseX <= holeX + 14 && mouseY >= holeY - 36 && mouseY <= holeY) - break; - } - if (holeIndex < 50 && kScene1407MouseHoles[holeIndex].sectionIndex == _currSectionIndex) { - _nextHoleIndex = kScene1407MouseHoles[holeIndex].nextHoleIndex; - _walkDestX = kScene1407MouseHoles[holeIndex].x; - stWalkToHole(); - } else { - if (mouseX < kScene1407MouseSections[_currSectionIndex].x1) - _walkDestX = kScene1407MouseSections[_currSectionIndex].x1; - else if (mouseX > kScene1407MouseSections[_currSectionIndex].x2) - _walkDestX = kScene1407MouseSections[_currSectionIndex].x2; - else - _walkDestX = mouseX; - stWalkToDest(); - } - } - break; - case 0x1019: - gotoNextState(); - break; - case 0x2001: - { - // Reset the position - // Find the nearest hole and go through it, and exit at the first hole - int16 distance = 640; - int matchIndex = 50; - for (int index = 0; index < 50; index++) - if (kScene1407MouseHoles[index].sectionIndex == _currSectionIndex && - ABS(kScene1407MouseHoles[index].x - _x) < distance) { - matchIndex = index; - distance = ABS(kScene1407MouseHoles[index].x - _x); - } - if (matchIndex < 50) { - _nextHoleIndex = 0; - _walkDestX = kScene1407MouseHoles[matchIndex].x; - stWalkToHole(); - } - } - break; - } - return messageResult; -} - -void AsScene1407Mouse::stIdleLookAtGoodHole() { - setDoDeltaX(kScene1407MouseHoles[kScene1407MouseSections[_currSectionIndex].goodHoleIndex].x < _x ? 1 : 0); - startAnimation(0x72215194, 0, -1); - SetMessageHandler(&AsScene1407Mouse::handleMessage); - SetSpriteUpdate(NULL); -} - -void AsScene1407Mouse::stWalkToDest() { - if (_walkDestX != _x) { - setDoDeltaX(_walkDestX < _x ? 1 : 0); - startAnimation(0x22291510, 0, -1); - SetMessageHandler(&AsScene1407Mouse::handleMessage); - SetSpriteUpdate(&AsScene1407Mouse::suWalkTo); - NextState(&AsScene1407Mouse::stIdleLookAtGoodHole); - } -} - -void AsScene1407Mouse::stWalkToHole() { - setDoDeltaX(_walkDestX < _x ? 1 : 0); - startAnimation(0x22291510, 0, -1); - SetMessageHandler(&AsScene1407Mouse::handleMessage); - SetSpriteUpdate(&AsScene1407Mouse::suWalkTo); - NextState(&AsScene1407Mouse::stGoThroughHole); -} - -void AsScene1407Mouse::stGoThroughHole() { - startAnimation(0x72215194, 0, -1); - setVisible(false); - _countdown = 12; - SetUpdateHandler(&AsScene1407Mouse::upGoThroughHole); - SetMessageHandler(NULL); - SetSpriteUpdate(NULL); - NextState(&AsScene1407Mouse::stArriveAtHole); -} - -void AsScene1407Mouse::stArriveAtHole() { - _currSectionIndex = kScene1407MouseHoles[_nextHoleIndex].sectionIndex; - _x = kScene1407MouseHoles[_nextHoleIndex].x; - _y = kScene1407MouseFloorY[kScene1407MouseHoles[_nextHoleIndex].floorIndex]; - if (_nextHoleIndex == 1) { - sendMessage(_parentScene, 0x2000, 0); - _walkDestX = 512; - stWalkToDest(); - setVisible(true); - } else { - _walkDestX = _x + 14; - stWalkToDest(); - setVisible(true); - } -} - Scene1407::Scene1407(NeverhoodEngine *vm, Module *parentModule) : Scene(vm, parentModule), _puzzleSolvedCountdown(0), _resetButtonCountdown(0) { @@ -1275,8 +484,6 @@ uint32 Scene1407::handleMessage(int messageNum, const MessageParam ¶m, Entit return 0; } -// Scene1403 - Scene1403::Scene1403(NeverhoodEngine *vm, Module *parentModule, int which) : Scene(vm, parentModule), _asProjector(NULL), _isProjecting(false) { @@ -1379,8 +586,6 @@ uint32 Scene1403::handleMessage(int messageNum, const MessageParam ¶m, Entit return 0; } -// Scene1404 - Scene1404::Scene1404(NeverhoodEngine *vm, Module *parentModule, int which) : Scene(vm, parentModule), _asProjector(NULL), _asKey(NULL) { @@ -1480,77 +685,6 @@ uint32 Scene1404::handleMessage(int messageNum, const MessageParam ¶m, Entit return 0; } -// Scene1405 - -static const NPoint kAsScene1405TileItemPositions[] = { - {100, 80}, {162, 78}, {222, 76}, {292, 76}, - {356, 82}, {422, 84}, {488, 86}, {550, 90}, - {102, 134}, {164, 132}, {224, 136}, {294, 136}, - {360, 136}, {422, 138}, {484, 144}, {548, 146}, - { 98, 196}, {160, 200}, {228, 200}, {294, 202}, - {360, 198}, {424, 200}, {482, 202}, {548, 206}, - { 98, 260}, {160, 264}, {226, 260}, {296, 262}, - {358, 260}, {424, 262}, {486, 264}, {550, 266}, - { 94, 322}, {160, 316}, {226, 316}, {296, 320}, - {358, 322}, {422, 324}, {488, 322}, {550, 322}, - { 98, 380}, {160, 376}, {226, 376}, {294, 378}, - {356, 380}, {420, 380}, {490, 378}, {552, 376} -}; - -AsScene1405Tile::AsScene1405Tile(NeverhoodEngine *vm, Scene1405 *parentScene, uint32 tileIndex) - : AnimatedSprite(vm, 1100), _parentScene(parentScene), _tileIndex(tileIndex), _countdown(0), _isShowing(false) { - - loadSound(0, 0x05308101); - setSoundPan(0, (tileIndex % 8 * 4 + 4) * 25 / 8); - _x = kAsScene1405TileItemPositions[_tileIndex].x; - _y = kAsScene1405TileItemPositions[_tileIndex].y; - createSurface1(0x844B805C, 1100); - setVisible(false); - if (getSubVar(VA_IS_TILE_MATCH, _tileIndex)) - _countdown = _vm->_rnd->getRandomNumber(36 - 1) + 1; - startAnimation(0x844B805C, getSubVar(VA_TILE_SYMBOLS, _tileIndex), -1); - _newStickFrameIndex = (int16)getSubVar(VA_TILE_SYMBOLS, _tileIndex); - SetUpdateHandler(&AsScene1405Tile::update); - SetMessageHandler(&AsScene1405Tile::handleMessage); -} - -void AsScene1405Tile::update() { - updateAnim(); - updatePosition(); - if (_countdown != 0 && (--_countdown == 0)) - show(); -} - -uint32 AsScene1405Tile::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x1011: - if (getSubVar(VA_IS_TILE_MATCH, _tileIndex) == 0 && _parentScene->getCountdown() == 0) { - show(); - sendMessage(_parentScene, 0x2000, _tileIndex); - } - messageResult = 1; - break; - } - return messageResult; -} - -void AsScene1405Tile::show() { - if (!_isShowing) { - _isShowing = true; - playSound(0); - setVisible(true); - } -} - -void AsScene1405Tile::hide() { - if (_isShowing) { - _isShowing = false; - playSound(0); - setVisible(false); - } -} - Scene1405::Scene1405(NeverhoodEngine *vm, Module *parentModule) : Scene(vm, parentModule), _selectFirstTile(true), _tilesLeft(48), _countdown(0) { diff --git a/engines/neverhood/modules/module1400.h b/engines/neverhood/modules/module1400.h index 9a592c2952..53ad7125ab 100644 --- a/engines/neverhood/modules/module1400.h +++ b/engines/neverhood/modules/module1400.h @@ -26,7 +26,6 @@ #include "neverhood/neverhood.h" #include "neverhood/module.h" #include "neverhood/scene.h" -#include "neverhood/modules/module1200.h" namespace Neverhood { @@ -40,92 +39,9 @@ protected: void updateScene(); }; -// Scene1401 - -class AsScene1401Pipe : public AnimatedSprite { -public: - AsScene1401Pipe(NeverhoodEngine *vm); - virtual ~AsScene1401Pipe(); -protected: - int _countdown1; - int _countdown2; - void update(); - void upSuckInProjector(); - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); - uint32 hmSuckInProjector(int messageNum, const MessageParam ¶m, Entity *sender); - void stStartSucking(); - void stDoneSucking(); - void stSuckInProjector(); -}; - -class AsScene1401Mouse : public AnimatedSprite { -public: - AsScene1401Mouse(NeverhoodEngine *vm); -protected: - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); - void suSuckedIn(); - void stSuckedIn(); -}; - -class AsScene1401Cheese : public AnimatedSprite { -public: - AsScene1401Cheese(NeverhoodEngine *vm); -protected: - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); - void suSuckedIn(); - void stSuckedIn(); -}; - -class AsScene1401BackDoor : public AnimatedSprite { -public: - AsScene1401BackDoor(NeverhoodEngine *vm, Sprite *klaymen, bool isOpen); -protected: - Sprite *_klaymen; - int _countdown; - bool _isOpen; - void update(); - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); - void stOpenDoor(); - void stCloseDoor(); - void stCloseDoorDone(); -}; - -struct AsCommonProjectorItem { - NPoint point; - int8 maxSlotCount; - int8 lockSlotIndex; - int8 index1; - int8 leftBorderLeaves; - int8 rightBorderLeaves; -}; - -class AsCommonProjector : public AnimatedSprite { -public: - AsCommonProjector(NeverhoodEngine *vm, Scene *parentScene, Sprite *klaymen, Sprite *asPipe); - virtual ~AsCommonProjector(); -protected: - Scene *_parentScene; - Sprite *_klaymen; - Sprite *_asPipe; - const AsCommonProjectorItem *_asProjectorItem; - int16 _beforeMoveX; - bool _lockedInSlot; - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); - uint32 hmLockedInSlot(int messageNum, const MessageParam ¶m, Entity *sender); - uint32 hmAnimation(int messageNum, const MessageParam ¶m, Entity *sender); - void suMoving(); - void moveProjector(); - void stSuckedIn(); - void stIdle(); - void stMoving(); - void stStartLockedInSlot(); - void stStayLockedInSlot(); - void stStartProjecting(); - void stLockedInSlot(); - void stStopProjecting(); - void stTurnToFront(); - void stStartSuckedIn(); -}; +class AsCommonProjector; +class AsScene1201Tape; +class AsScene1405Tile; class Scene1401 : public Scene { public: @@ -146,24 +62,6 @@ protected: uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); }; -// Scene1402 - -class SsScene1402BridgePart : public StaticSprite { -public: - SsScene1402BridgePart(NeverhoodEngine *vm, uint32 fileHash, int surfacePriority); -}; - -class AsScene1402PuzzleBox : public AnimatedSprite { -public: - AsScene1402PuzzleBox(NeverhoodEngine *vm, Scene *parentScene, int status); -protected: - Scene *_parentScene; - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); - void stMoveUpDone(); - void stMoveDownDone(); - void stMoveDownSolvedDone(); -}; - class Scene1402 : public Scene { public: Scene1402(NeverhoodEngine *vm, Module *parentModule, int which); @@ -180,27 +78,6 @@ protected: void stopShaking(); }; -// Scene1407 - -class AsScene1407Mouse : public AnimatedSprite { -public: - AsScene1407Mouse(NeverhoodEngine *vm, Scene *parentScene); -protected: - Scene *_parentScene; - int16 _walkDestX; - int16 _currSectionIndex; - int16 _nextHoleIndex; - int _countdown; - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); - void suWalkTo(); - void upGoThroughHole(); - void stIdleLookAtGoodHole(); - void stWalkToDest(); - void stWalkToHole(); - void stGoThroughHole(); - void stArriveAtHole(); -}; - class Scene1407 : public Scene { public: Scene1407(NeverhoodEngine *vm, Module *parentModule); @@ -213,8 +90,6 @@ protected: uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); }; -// Scene1403 - class Scene1403 : public Scene { public: Scene1403(NeverhoodEngine *vm, Module *parentModule, int which); @@ -229,8 +104,6 @@ protected: uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); }; -// Scene1404 - class Scene1404 : public Scene { public: Scene1404(NeverhoodEngine *vm, Module *parentModule, int which); @@ -243,24 +116,6 @@ protected: uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); }; -// Scene1405 - -class Scene1405; - -class AsScene1405Tile : public AnimatedSprite { -public: - AsScene1405Tile(NeverhoodEngine *vm, Scene1405 *parentScene, uint32 tileIndex); - void show(); - void hide(); -protected: - Scene1405 *_parentScene; - bool _isShowing; - uint32 _tileIndex; - int _countdown; - void update(); - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); -}; - class Scene1405 : public Scene { public: Scene1405(NeverhoodEngine *vm, Module *parentModule); diff --git a/engines/neverhood/modules/module1400_sprites.cpp b/engines/neverhood/modules/module1400_sprites.cpp new file mode 100644 index 0000000000..c0ab73c93d --- /dev/null +++ b/engines/neverhood/modules/module1400_sprites.cpp @@ -0,0 +1,1129 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "neverhood/modules/module1400_sprites.h" +#include "neverhood/modules/module1400.h" + +namespace Neverhood { + +AsScene1401Pipe::AsScene1401Pipe(NeverhoodEngine *vm) + : AnimatedSprite(vm, 1100), _countdown1(0), _countdown2(0) { + + createSurface(900, 152, 147); + _x = 454; + _y = 217; + startAnimation(0x4C210500, 0, -1); + SetUpdateHandler(&AsScene1401Pipe::update); + SetMessageHandler(&AsScene1401Pipe::handleMessage); +} + +AsScene1401Pipe::~AsScene1401Pipe() { + _vm->_soundMan->deleteSoundGroup(0x01104C08); +} + +void AsScene1401Pipe::update() { + AnimatedSprite::update(); + if (_countdown1 != 0 && (--_countdown1 == 0)) + stDoneSucking(); + if (_countdown2 != 0 && (--_countdown2 == 0)) { + _vm->_soundMan->addSound(0x01104C08, 0x4A116437); + _vm->_soundMan->playSoundLooping(0x4A116437); + } +} + +void AsScene1401Pipe::upSuckInProjector() { + AnimatedSprite::update(); + if (_countdown1 != 0) + _countdown1--; +} + +uint32 AsScene1401Pipe::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x100D: + if (param.asInteger() == 0x0A8A1490) + playSound(1, 0x6AB6666F); + break; + case 0x2000: + _countdown1 = 70; + _countdown2 = 8; + stStartSucking(); + break; + case 0x483A: + stSuckInProjector(); + break; + } + return messageResult; +} + +uint32 AsScene1401Pipe::hmSuckInProjector(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x3002: + if (_countdown1 != 0) + stStartSucking(); + else + stDoneSucking(); + SetMessageHandler(&AsScene1401Pipe::handleMessage); + SetUpdateHandler(&AsScene1401Pipe::update); + break; + } + return messageResult; +} + +void AsScene1401Pipe::stStartSucking() { + startAnimation(0x4C240100, 0, -1); + playSound(0, 0x4A30063F); +} + +void AsScene1401Pipe::stDoneSucking() { + _vm->_soundMan->deleteSound(0x4A116437); + playSound(0, 0x4A120435); + startAnimation(0x4C210500, 0, -1); +} + +void AsScene1401Pipe::stSuckInProjector() { + startAnimation(0x6C210810, 0, -1); + SetUpdateHandler(&AsScene1401Pipe::upSuckInProjector); + SetMessageHandler(&AsScene1401Pipe::hmSuckInProjector); +} + +AsScene1401Mouse::AsScene1401Mouse(NeverhoodEngine *vm) + : AnimatedSprite(vm, 1100) { + + createSurface(100, 71, 41); + _x = 478; + _y = 433; + startAnimation(0xA282C472, 0, -1); + SetUpdateHandler(&AnimatedSprite::update); + SetMessageHandler(&AsScene1401Mouse::handleMessage); +} + +uint32 AsScene1401Mouse::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x100D: + if (param.asInteger() == 0x66382026) + playSound(0, 0x0CD84468); + else if (param.asInteger() == 0x6E28061C) + playSound(0, 0x78C8402C); + else if (param.asInteger() == 0x462F0410) + playSound(0, 0x60984E28); + break; + case 0x4839: + stSuckedIn(); + break; + } + return messageResult; +} + +void AsScene1401Mouse::suSuckedIn() { + AnimatedSprite::updateDeltaXY(); + if (_collisionBounds.y1 <= 150) { + playSound(0, 0x0E32247F); + stopAnimation(); + setVisible(false); + SetMessageHandler(NULL); + SetSpriteUpdate(NULL); + } +} + +void AsScene1401Mouse::stSuckedIn() { + startAnimation(0x34880040, 0, -1); + SetSpriteUpdate(&AsScene1401Mouse::suSuckedIn); +} + +AsScene1401Cheese::AsScene1401Cheese(NeverhoodEngine *vm) + : AnimatedSprite(vm, 1100) { + + createSurface(200, 152, 147); + _x = 427; + _y = 433; + startAnimation(0x461A1490, 0, -1); + SetUpdateHandler(&AnimatedSprite::update); + SetMessageHandler(&AsScene1401Cheese::handleMessage); +} + +uint32 AsScene1401Cheese::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x4839: + stSuckedIn(); + break; + } + return messageResult; +} + +void AsScene1401Cheese::suSuckedIn() { + AnimatedSprite::updateDeltaXY(); + if (_collisionBounds.y1 <= 150) { + playSound(0, 0x18020439); + stopAnimation(); + setVisible(false); + SetMessageHandler(NULL); + SetSpriteUpdate(NULL); + } +} + +void AsScene1401Cheese::stSuckedIn() { + startAnimation(0x103B8020, 0, -1); + SetSpriteUpdate(&AsScene1401Cheese::suSuckedIn); +} + +AsScene1401BackDoor::AsScene1401BackDoor(NeverhoodEngine *vm, Sprite *klaymen, bool isOpen) + : AnimatedSprite(vm, 1100), _klaymen(klaymen), _countdown(0), _isOpen(isOpen) { + + _x = 320; + _y = 240; + createSurface1(0x04551900, 100); + if (isOpen) { + startAnimation(0x04551900, -1, -1); + _countdown = 48; + } else { + stopAnimation(); + setVisible(false); + } + _newStickFrameIndex = STICK_LAST_FRAME; + SetUpdateHandler(&AsScene1401BackDoor::update); + SetMessageHandler(&AsScene1401BackDoor::handleMessage); +} + +void AsScene1401BackDoor::update() { + if (_countdown != 0 && (--_countdown == 0)) + stCloseDoor(); + AnimatedSprite::update(); +} + + +uint32 AsScene1401BackDoor::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x2001: + if (_isOpen) + _countdown = 168; + messageResult = _isOpen ? 1 : 0; + break; + case 0x3002: + gotoNextState(); + break; + case 0x4808: + _countdown = 168; + if (!_isOpen) + stOpenDoor(); + break; + } + return messageResult; +} + +void AsScene1401BackDoor::stOpenDoor() { + _isOpen = true; + setVisible(true); + startAnimation(0x04551900, 0, -1); + _newStickFrameIndex = STICK_LAST_FRAME; + playSound(0, calcHash("fxDoorOpen24")); +} + +void AsScene1401BackDoor::stCloseDoor() { + _isOpen = false; + setVisible(true); + startAnimation(0x04551900, -1, -1); + playSound(0, calcHash("fxDoorClose24")); + _playBackwards = true; + NextState(&AsScene1401BackDoor::stCloseDoorDone); +} + +void AsScene1401BackDoor::stCloseDoorDone() { + stopAnimation(); + setVisible(false); +} + +static const AsCommonProjectorItem kAsCommonProjectorItems[] = { + {{154, 453}, 4, 2, 0, 0, 1}, + {{104, 391}, 4, -1, -1, 1, 1}, + {{ 22, 447}, 6, -1, -1, 1, 1}, + {{112, 406}, 2, -1, -1, 1, 0}, + {{262, 433}, 1, 1, 0, 0, 0} +}; + +AsCommonProjector::AsCommonProjector(NeverhoodEngine *vm, Scene *parentScene, Sprite *klaymen, Sprite *asPipe) + : AnimatedSprite(vm, 1100), _parentScene(parentScene), _klaymen(klaymen), _asPipe(asPipe) { + + _asProjectorItem = &kAsCommonProjectorItems[getGlobalVar(V_PROJECTOR_LOCATION)]; + createSurface(990, 101, 182); + startAnimation(0x10E3042B, 0, -1); + SetUpdateHandler(&AnimatedSprite::update); + SetMessageHandler(&AsCommonProjector::handleMessage); + _x = getGlobalVar(V_PROJECTOR_SLOT) * 108 + _asProjectorItem->point.x; + _lockedInSlot = true; + moveProjector(); + setDoDeltaX(1); + if ((int8)getGlobalVar(V_PROJECTOR_SLOT) == _asProjectorItem->lockSlotIndex) + stStayLockedInSlot(); + loadSound(2, 0xC8C2507C); +} + +AsCommonProjector::~AsCommonProjector() { + _vm->_soundMan->deleteSoundGroup(0x05331081); +} + +uint32 AsCommonProjector::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x1011: + sendMessage(_parentScene, 0x4826, 0); + messageResult = 1; + break; + case 0x4807: + setGlobalVar(V_PROJECTOR_SLOT, (_x - _asProjectorItem->point.x) / 108); + if ((int8)getGlobalVar(V_PROJECTOR_SLOT) == _asProjectorItem->lockSlotIndex) + stStartLockedInSlot(); + else + stIdle(); + break; + case 0x480B: + if (param.asInteger() != 1) { + if ((int8)getGlobalVar(V_PROJECTOR_SLOT) < _asProjectorItem->maxSlotCount) + incGlobalVar(V_PROJECTOR_SLOT, 1); + } else if (getGlobalVar(V_PROJECTOR_SLOT) > 0) + incGlobalVar(V_PROJECTOR_SLOT, -1); + stMoving(); + break; + case 0x480C: + // Check if the projector can be moved + if (param.asInteger() != 1) + messageResult = (int8)getGlobalVar(V_PROJECTOR_SLOT) < _asProjectorItem->maxSlotCount ? 1 : 0; + else + messageResult = getGlobalVar(V_PROJECTOR_SLOT) > 0 ? 1 : 0; + break; + case 0x482A: + sendMessage(_parentScene, 0x1022, 990); + break; + case 0x482B: + sendMessage(_parentScene, 0x1022, 1010); + break; + case 0x4839: + stStartSuckedIn(); + break; + } + return messageResult; +} + +uint32 AsCommonProjector::hmLockedInSlot(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x1011: + if (param.asPoint().x - _x >= 17 && param.asPoint().x - _x <= 56 && + param.asPoint().y - _y >= -120 && param.asPoint().y - _y <= -82) { + sendMessage(_parentScene, 0x4826, 1); + } else + sendMessage(_parentScene, 0x4826, 0); + messageResult = 1; + break; + case 0x4807: + sendMessage(_parentScene, 0x4807, 0); + stStopProjecting(); + break; + case 0x480B: + if (param.asInteger() != 1) { + if ((int8)getGlobalVar(V_PROJECTOR_SLOT) < _asProjectorItem->maxSlotCount) + incGlobalVar(V_PROJECTOR_SLOT, 1); + } else if (getGlobalVar(V_PROJECTOR_SLOT) > 0) + incGlobalVar(V_PROJECTOR_SLOT, -1); + stTurnToFront(); + break; + case 0x480C: + // Check if the projector can be moved + if (param.asInteger() != 1) + messageResult = (int8)getGlobalVar(V_PROJECTOR_SLOT) < _asProjectorItem->maxSlotCount ? 1 : 0; + else + messageResult = getGlobalVar(V_PROJECTOR_SLOT) > 0 ? 1 : 0; + break; + case 0x480F: + stStartProjecting(); + break; + case 0x482A: + sendMessage(_parentScene, 0x1022, 990); + break; + case 0x482B: + sendMessage(_parentScene, 0x1022, 1010); + break; + } + return messageResult; +} + +uint32 AsCommonProjector::hmAnimation(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x3002: + gotoNextState(); + break; + } + return messageResult; +} + +void AsCommonProjector::suMoving() { + if (_x <= _klaymen->getX()) + _x = _klaymen->getX() - 100; + else + _x = _klaymen->getX() + 100; + moveProjector(); + if (_beforeMoveX == _x) { + if (getGlobalVar(V_PROJECTOR_SLOT) == 0 && _asProjectorItem->leftBorderLeaves != 0) { + sendMessage(_parentScene, 0x1019, 0); + incGlobalVar(V_PROJECTOR_LOCATION, -1); + setGlobalVar(V_PROJECTOR_SLOT, kAsCommonProjectorItems[getGlobalVar(V_PROJECTOR_LOCATION)].maxSlotCount); + } else if ((int8)getGlobalVar(V_PROJECTOR_SLOT) == _asProjectorItem->maxSlotCount && _asProjectorItem->rightBorderLeaves != 0) { + sendMessage(_parentScene, 0x1019, 1); + incGlobalVar(V_PROJECTOR_LOCATION, +1); + setGlobalVar(V_PROJECTOR_SLOT, 0); + } + } + Sprite::updateBounds(); +} + +void AsCommonProjector::moveProjector() { + + bool nowLockedInSlot = false; + + _y = _asProjectorItem->point.y; + + if (_asProjectorItem->index1 != -1) { + int16 elX = _asProjectorItem->index1 * 108 + _asProjectorItem->point.x; + if (elX - 20 < _x && elX + 20 > _x) { + nowLockedInSlot = true; + _y = _asProjectorItem->point.y + 10; + } + } + + if (_asProjectorItem->lockSlotIndex != -1) { + int16 elX = _asProjectorItem->lockSlotIndex * 108 + _asProjectorItem->point.x; + if (elX - 20 < _x && elX + 20 > _x) { + nowLockedInSlot = true; + _y = _asProjectorItem->point.y + 10; + } + } + + if (_lockedInSlot && !nowLockedInSlot) + _lockedInSlot = false; + else if (!_lockedInSlot && nowLockedInSlot) { + playSound(1, 0x5440E474); + _lockedInSlot = true; + } + +} + +void AsCommonProjector::stSuckedIn() { + AnimatedSprite::updateDeltaXY(); + if (_collisionBounds.y1 <= 150) { + sendMessage(_asPipe, 0x483A, 0); + stopAnimation(); + setVisible(false); + SetMessageHandler(&Sprite::handleMessage); + SetSpriteUpdate(NULL); + } +} + +void AsCommonProjector::stIdle() { + startAnimation(0x10E3042B, 0, -1); + SetMessageHandler(&AsCommonProjector::handleMessage); + SetSpriteUpdate(NULL); +} + +void AsCommonProjector::stMoving() { + _beforeMoveX = getGlobalVar(V_PROJECTOR_SLOT) * 108 + _asProjectorItem->point.x; + startAnimation(0x14A10137, 0, -1); + playSound(1, 0xEC008474); + SetMessageHandler(&AsCommonProjector::handleMessage); + SetSpriteUpdate(&AsCommonProjector::suMoving); +} + +void AsCommonProjector::stStartLockedInSlot() { + startAnimation(0x80C32213, 0, -1); + SetMessageHandler(&AsCommonProjector::hmAnimation); + SetSpriteUpdate(NULL); + NextState(&AsCommonProjector::stStayLockedInSlot); +} + +void AsCommonProjector::stStayLockedInSlot() { + startAnimation(0xD23B207F, 0, -1); + SetMessageHandler(&AsCommonProjector::hmLockedInSlot); + SetSpriteUpdate(NULL); +} + +void AsCommonProjector::stStartProjecting() { + startAnimation(0x50A80517, 0, -1); + setGlobalVar(V_PROJECTOR_ACTIVE, 1); + playSound(0, 0xCC4A8456); + _vm->_soundMan->addSound(0x05331081, 0xCE428854); + _vm->_soundMan->playSoundLooping(0xCE428854); + SetMessageHandler(&AsCommonProjector::hmAnimation); + SetSpriteUpdate(NULL); + NextState(&AsCommonProjector::stLockedInSlot); +} + +void AsCommonProjector::stLockedInSlot() { + sendMessage(_parentScene, 0x480F, 0); + startAnimation(0xD833207F, 0, -1); + SetMessageHandler(&AsCommonProjector::hmLockedInSlot); + SetSpriteUpdate(NULL); +} + +void AsCommonProjector::stStopProjecting() { + startAnimation(0x50A94417, 0, -1); + setGlobalVar(V_PROJECTOR_ACTIVE, 0); + playSound(0, 0xCC4A8456); + _vm->_soundMan->deleteSound(0xCE428854); + SetMessageHandler(&AsCommonProjector::hmAnimation); + SetSpriteUpdate(NULL); + NextState(&AsCommonProjector::stStayLockedInSlot); +} + +void AsCommonProjector::stTurnToFront() { + _beforeMoveX = getGlobalVar(V_PROJECTOR_SLOT) * 108 + _asProjectorItem->point.x; + startAnimation(0x22CB4A33, 0, -1); + SetMessageHandler(&AsCommonProjector::hmAnimation); + SetSpriteUpdate(&AsCommonProjector::suMoving); + NextState(&AsCommonProjector::stMoving); +} + +void AsCommonProjector::stStartSuckedIn() { + setGlobalVar(V_PROJECTOR_LOCATION, 4); + setGlobalVar(V_PROJECTOR_SLOT, 0); + startAnimation(0x708D4712, 0, -1); + playSound(2); + SetMessageHandler(&Sprite::handleMessage); + SetSpriteUpdate(&AsCommonProjector::stSuckedIn); +} + +SsScene1402BridgePart::SsScene1402BridgePart(NeverhoodEngine *vm, uint32 fileHash, int surfacePriority) + : StaticSprite(vm, fileHash, surfacePriority) { + + SetFilterY(&Sprite::defFilterY); + SetUpdateHandler(&StaticSprite::updatePosition); +} + +AsScene1402PuzzleBox::AsScene1402PuzzleBox(NeverhoodEngine *vm, Scene *parentScene, int status) + : AnimatedSprite(vm, 1100), _parentScene(parentScene) { + + createSurface(900, 347, 230); + + SetFilterY(&Sprite::defFilterY); + SetUpdateHandler(&AnimatedSprite::update); + SetMessageHandler(&AsScene1402PuzzleBox::handleMessage); + _x = 279; + _y = 270; + if (status == 2) { + // Puzzle box after the puzzle was solved + startAnimation(0x20060259, 0, -1); + playSound(0, 0x419014AC); + loadSound(1, 0x61901C29); + NextState(&AsScene1402PuzzleBox::stMoveDownSolvedDone); + } else if (status == 1) { + // Puzzle box appears + startAnimation(0x210A0213, 0, -1); + playSound(0, 0x41809C6C); + NextState(&AsScene1402PuzzleBox::stMoveUpDone); + } else { + // Puzzle box is here + startAnimation(0x20060259, -1, -1); + loadSound(1, 0x61901C29); + _newStickFrameIndex = STICK_LAST_FRAME; + } +} + +uint32 AsScene1402PuzzleBox::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x2002: + playSound(1); + startAnimation(0x20060259, -1, -1); + _playBackwards = true; + NextState(&AsScene1402PuzzleBox::stMoveDownDone); + break; + case 0x3002: + gotoNextState(); + break; + } + return messageResult; +} + +void AsScene1402PuzzleBox::stMoveUpDone() { + sendMessage(_parentScene, 0x2000, 0); + stopAnimation(); + setVisible(false); +} + +void AsScene1402PuzzleBox::stMoveDownDone() { + sendMessage(_parentScene, 0x2001, 0); + stopAnimation(); + setVisible(false); +} + +void AsScene1402PuzzleBox::stMoveDownSolvedDone() { + sendMessage(_parentScene, 0x2003, 0); + stopAnimation(); +} + +static const int16 kScene1407MouseFloorY[] = { + 106, 150, 191, 230, 267, 308, 350, 395 +}; + +static const struct { + int16 x; + int16 floorIndex; + int16 sectionIndex; + int16 nextHoleIndex; +} kScene1407MouseHoles[] = { + {125, 0, 0, 7}, + {452, 7, 21, 0}, + {337, 4, 11, 4}, + {286, 6, 17, 6}, + {348, 6, 17, 39}, + {536, 6, 18, 42}, + {111, 1, 3, 18}, + {203, 1, 3, 38}, + {270, 1, 3, 9}, + {197, 5, 14, 3}, + {252, 5, 14, 35}, + {297, 5, 14, 7}, + {359, 5, 14, 8}, + {422, 4, 12, 26}, + {467, 4, 12, 2}, + {539, 4, 12, 40}, + {111, 5, 13, 17}, + {211, 0, 1, 20}, + {258, 0, 1, 11}, + {322, 0, 1, 16}, + { 99, 6, 16, 31}, + {142, 6, 16, 27}, + {194, 6, 16, 12}, + {205, 2, 6, 45}, + {264, 2, 6, 10}, + { 98, 4, 10, 2}, + {152, 4, 10, 37}, + {199, 4, 10, 13}, + {258, 4, 10, 16}, + {100, 7, 19, 43}, + {168, 7, 19, 23}, + {123, 3, 8, 14}, + {181, 3, 8, 39}, + {230, 3, 8, 28}, + {292, 3, 8, 22}, + {358, 3, 8, 36}, + {505, 3, 9, 44}, + {400, 2, 7, 34}, + {454, 2, 7, 32}, + {532, 2, 7, 46}, + {484, 5, 15, 25}, + {529, 5, 15, 30}, + {251, 7, 20, 48}, + {303, 7, 20, 21}, + {360, 7, 20, 33}, + {503, 0, 2, 5}, + {459, 1, 4, 19}, + {530, 1, 4, 42}, + {111, 2, 5, 47}, + {442, 6, 18, 1} +}; + +static const struct { + int16 x1, x2; + int16 goodHoleIndex; +} kScene1407MouseSections[] = { + {100, 149, 0}, + {182, 351, 17}, + {430, 524, 45}, + { 89, 293, 7}, + {407, 555, 47}, + { 89, 132, 48}, + {178, 303, 23}, + {367, 551, 38}, + {105, 398, 31}, + {480, 537, 36}, + { 84, 275, 27}, + {318, 359, 2}, + {402, 560, 15}, + { 91, 132, 16}, + {179, 400, 10}, + {461, 552, 41}, + { 86, 218, 21}, + {267, 376, 4}, + {420, 560, 49}, + { 77, 188, 30}, + {237, 394, 44}, + {438, 515, 5} +}; + +AsScene1407Mouse::AsScene1407Mouse(NeverhoodEngine *vm, Scene *parentScene) + : AnimatedSprite(vm, 1100), _parentScene(parentScene), _currSectionIndex(0) { + + createSurface(100, 117, 45); + _x = 108; + _y = 106; + stIdleLookAtGoodHole(); + SetUpdateHandler(&AnimatedSprite::update); +} + +void AsScene1407Mouse::suWalkTo() { + int16 xdelta = _walkDestX - _x; + if (xdelta > _deltaX) + xdelta = _deltaX; + else if (xdelta < -_deltaX) + xdelta = -_deltaX; + _deltaX = 0; + if (_walkDestX == _x) + sendMessage(this, 0x1019, 0); + else { + _x += xdelta; + updateBounds(); + } +} + +void AsScene1407Mouse::upGoThroughHole() { + if (_countdown != 0 && (--_countdown == 0)) { + SetUpdateHandler(&AnimatedSprite::update); + gotoNextState(); + } + AnimatedSprite::update(); +} + +uint32 AsScene1407Mouse::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x0001: + { + int16 mouseX = param.asPoint().x; + int16 mouseY = param.asPoint().y; + int holeIndex; + for (holeIndex = 0; holeIndex < 50; holeIndex++) { + int16 holeX = kScene1407MouseHoles[holeIndex].x; + int16 holeY = kScene1407MouseFloorY[kScene1407MouseHoles[holeIndex].floorIndex]; + if (mouseX >= holeX - 14 && mouseX <= holeX + 14 && mouseY >= holeY - 36 && mouseY <= holeY) + break; + } + if (holeIndex < 50 && kScene1407MouseHoles[holeIndex].sectionIndex == _currSectionIndex) { + _nextHoleIndex = kScene1407MouseHoles[holeIndex].nextHoleIndex; + _walkDestX = kScene1407MouseHoles[holeIndex].x; + stWalkToHole(); + } else { + if (mouseX < kScene1407MouseSections[_currSectionIndex].x1) + _walkDestX = kScene1407MouseSections[_currSectionIndex].x1; + else if (mouseX > kScene1407MouseSections[_currSectionIndex].x2) + _walkDestX = kScene1407MouseSections[_currSectionIndex].x2; + else + _walkDestX = mouseX; + stWalkToDest(); + } + } + break; + case 0x1019: + gotoNextState(); + break; + case 0x2001: + { + // Reset the position + // Find the nearest hole and go through it, and exit at the first hole + int16 distance = 640; + int matchIndex = 50; + for (int index = 0; index < 50; index++) + if (kScene1407MouseHoles[index].sectionIndex == _currSectionIndex && + ABS(kScene1407MouseHoles[index].x - _x) < distance) { + matchIndex = index; + distance = ABS(kScene1407MouseHoles[index].x - _x); + } + if (matchIndex < 50) { + _nextHoleIndex = 0; + _walkDestX = kScene1407MouseHoles[matchIndex].x; + stWalkToHole(); + } + } + break; + } + return messageResult; +} + +void AsScene1407Mouse::stIdleLookAtGoodHole() { + setDoDeltaX(kScene1407MouseHoles[kScene1407MouseSections[_currSectionIndex].goodHoleIndex].x < _x ? 1 : 0); + startAnimation(0x72215194, 0, -1); + SetMessageHandler(&AsScene1407Mouse::handleMessage); + SetSpriteUpdate(NULL); +} + +void AsScene1407Mouse::stWalkToDest() { + if (_walkDestX != _x) { + setDoDeltaX(_walkDestX < _x ? 1 : 0); + startAnimation(0x22291510, 0, -1); + SetMessageHandler(&AsScene1407Mouse::handleMessage); + SetSpriteUpdate(&AsScene1407Mouse::suWalkTo); + NextState(&AsScene1407Mouse::stIdleLookAtGoodHole); + } +} + +void AsScene1407Mouse::stWalkToHole() { + setDoDeltaX(_walkDestX < _x ? 1 : 0); + startAnimation(0x22291510, 0, -1); + SetMessageHandler(&AsScene1407Mouse::handleMessage); + SetSpriteUpdate(&AsScene1407Mouse::suWalkTo); + NextState(&AsScene1407Mouse::stGoThroughHole); +} + +void AsScene1407Mouse::stGoThroughHole() { + startAnimation(0x72215194, 0, -1); + setVisible(false); + _countdown = 12; + SetUpdateHandler(&AsScene1407Mouse::upGoThroughHole); + SetMessageHandler(NULL); + SetSpriteUpdate(NULL); + NextState(&AsScene1407Mouse::stArriveAtHole); +} + +void AsScene1407Mouse::stArriveAtHole() { + _currSectionIndex = kScene1407MouseHoles[_nextHoleIndex].sectionIndex; + _x = kScene1407MouseHoles[_nextHoleIndex].x; + _y = kScene1407MouseFloorY[kScene1407MouseHoles[_nextHoleIndex].floorIndex]; + if (_nextHoleIndex == 1) { + sendMessage(_parentScene, 0x2000, 0); + _walkDestX = 512; + stWalkToDest(); + setVisible(true); + } else { + _walkDestX = _x + 14; + stWalkToDest(); + setVisible(true); + } +} + +static const NPoint kAsScene1405TileItemPositions[] = { + {100, 80}, {162, 78}, {222, 76}, {292, 76}, + {356, 82}, {422, 84}, {488, 86}, {550, 90}, + {102, 134}, {164, 132}, {224, 136}, {294, 136}, + {360, 136}, {422, 138}, {484, 144}, {548, 146}, + { 98, 196}, {160, 200}, {228, 200}, {294, 202}, + {360, 198}, {424, 200}, {482, 202}, {548, 206}, + { 98, 260}, {160, 264}, {226, 260}, {296, 262}, + {358, 260}, {424, 262}, {486, 264}, {550, 266}, + { 94, 322}, {160, 316}, {226, 316}, {296, 320}, + {358, 322}, {422, 324}, {488, 322}, {550, 322}, + { 98, 380}, {160, 376}, {226, 376}, {294, 378}, + {356, 380}, {420, 380}, {490, 378}, {552, 376} +}; + +AsScene1405Tile::AsScene1405Tile(NeverhoodEngine *vm, Scene1405 *parentScene, uint32 tileIndex) + : AnimatedSprite(vm, 1100), _parentScene(parentScene), _tileIndex(tileIndex), _countdown(0), _isShowing(false) { + + loadSound(0, 0x05308101); + setSoundPan(0, (tileIndex % 8 * 4 + 4) * 25 / 8); + _x = kAsScene1405TileItemPositions[_tileIndex].x; + _y = kAsScene1405TileItemPositions[_tileIndex].y; + createSurface1(0x844B805C, 1100); + setVisible(false); + if (getSubVar(VA_IS_TILE_MATCH, _tileIndex)) + _countdown = _vm->_rnd->getRandomNumber(36 - 1) + 1; + startAnimation(0x844B805C, getSubVar(VA_TILE_SYMBOLS, _tileIndex), -1); + _newStickFrameIndex = (int16)getSubVar(VA_TILE_SYMBOLS, _tileIndex); + SetUpdateHandler(&AsScene1405Tile::update); + SetMessageHandler(&AsScene1405Tile::handleMessage); +} + +void AsScene1405Tile::update() { + updateAnim(); + updatePosition(); + if (_countdown != 0 && (--_countdown == 0)) + show(); +} + +uint32 AsScene1405Tile::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x1011: + if (getSubVar(VA_IS_TILE_MATCH, _tileIndex) == 0 && _parentScene->getCountdown() == 0) { + show(); + sendMessage(_parentScene, 0x2000, _tileIndex); + } + messageResult = 1; + break; + } + return messageResult; +} + +void AsScene1405Tile::show() { + if (!_isShowing) { + _isShowing = true; + playSound(0); + setVisible(true); + } +} + +void AsScene1405Tile::hide() { + if (_isShowing) { + _isShowing = false; + playSound(0); + setVisible(false); + } +} + +KmScene1401::KmScene1401(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) + : Klaymen(vm, parentScene, x, y) { + + // Empty +} + +uint32 KmScene1401::xHandleMessage(int messageNum, const MessageParam ¶m) { + switch (messageNum) { + case 0x4001: + case 0x4800: + startWalkToX(param.asPoint().x, false); + break; + case 0x4004: + GotoState(&Klaymen::stTryStandIdle); + break; + case 0x480A: + if (param.asInteger() == 1) + GotoState(&Klaymen::stMoveObjectSkipTurnFaceObject); + else + GotoState(&Klaymen::stMoveObjectFaceObject); + break; + case 0x4816: + if (param.asInteger() == 1) + GotoState(&Klaymen::stPressButton); + else if (param.asInteger() == 2) + GotoState(&Klaymen::stPressFloorButton); + else + GotoState(&Klaymen::stPressButtonSide); + break; + case 0x4817: + setDoDeltaX(param.asInteger()); + gotoNextStateExt(); + break; + case 0x481B: + if (param.asPoint().y != 0) + startWalkToXDistance(param.asPoint().y, param.asPoint().x); + else + startWalkToAttachedSpriteXDistance(param.asPoint().x); + break; + case 0x481F: + if (param.asInteger() == 1) + GotoState(&Klaymen::stTurnAwayFromUse); + else if (param.asInteger() == 0) + GotoState(&Klaymen::stTurnToUseHalf); + else + GotoState(&Klaymen::stWonderAbout); + break; + case 0x482D: + setDoDeltaX(_x > (int16)param.asInteger() ? 1 : 0); + gotoNextStateExt(); + break; + case 0x482E: + if (param.asInteger() == 1) + GotoState(&Klaymen::stWalkToFrontNoStep); + else + GotoState(&Klaymen::stWalkToFront); + break; + case 0x482F: + if (param.asInteger() == 1) + GotoState(&Klaymen::stTurnToFront); + else + GotoState(&Klaymen::stTurnToBack); + break; + } + return 0; +} + +KmScene1402::KmScene1402(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) + : Klaymen(vm, parentScene, x, y) { + + SetFilterY(&Sprite::defFilterY); +} + +uint32 KmScene1402::xHandleMessage(int messageNum, const MessageParam ¶m) { + switch (messageNum) { + case 0x4001: + case 0x4800: + startWalkToX(param.asPoint().x, false); + break; + case 0x4004: + GotoState(&Klaymen::stTryStandIdle); + break; + case 0x480A: + if (param.asInteger() == 1) + GotoState(&Klaymen::stMoveObjectSkipTurnFaceObject); + else + GotoState(&Klaymen::stMoveObjectFaceObject); + break; + case 0x4817: + setDoDeltaX(param.asInteger()); + gotoNextStateExt(); + break; + case 0x481B: + if (param.asPoint().y != 0) + startWalkToXDistance(param.asPoint().y, param.asPoint().x); + else + startWalkToAttachedSpriteXDistance(param.asPoint().x); + break; + case 0x481D: + GotoState(&Klaymen::stTurnToUse); + break; + case 0x481E: + GotoState(&Klaymen::stReturnFromUse); + break; + } + return 0; +} + +static const KlaymenIdleTableItem klaymenIdleTable1403[] = { + {1, kIdleSpinHead}, + {1, kIdleChest}, + {1, kIdleHeadOff}, +}; + +KmScene1403::KmScene1403(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) + : Klaymen(vm, parentScene, x, y) { + + setKlaymenIdleTable(klaymenIdleTable1403, ARRAYSIZE(klaymenIdleTable1403)); +} + +uint32 KmScene1403::xHandleMessage(int messageNum, const MessageParam ¶m) { + switch (messageNum) { + case 0x4001: + case 0x4800: + startWalkToX(param.asPoint().x, false); + break; + case 0x4004: + GotoState(&Klaymen::stTryStandIdle); + break; + case 0x480A: + if (param.asInteger() == 1) + GotoState(&Klaymen::stMoveObjectSkipTurnFaceObject); + else + GotoState(&Klaymen::stMoveObjectFaceObject); + break; + case 0x480D: + GotoState(&Klaymen::stUseLever); + break; + case 0x4812: + if (param.asInteger() == 2) + GotoState(&Klaymen::stPickUpNeedle); + else if (param.asInteger() == 1) + GotoState(&Klaymen::stPickUpTube); + else + GotoState(&Klaymen::stPickUpGeneric); + break; + case 0x4817: + setDoDeltaX(param.asInteger()); + gotoNextStateExt(); + break; + case 0x481B: + if (param.asPoint().y != 0) + startWalkToXDistance(param.asPoint().y, param.asPoint().x); + else + startWalkToAttachedSpriteXDistance(param.asPoint().x); + break; + case 0x4827: + GotoState(&Klaymen::stReleaseLever); + break; + case 0x483F: + startSpecialWalkRight(param.asInteger()); + break; + case 0x4840: + startSpecialWalkLeft(param.asInteger()); + break; + } + return 0; +} + +// KmScene1404 + +KmScene1404::KmScene1404(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) + : Klaymen(vm, parentScene, x, y) { + + // Empty +} + +uint32 KmScene1404::xHandleMessage(int messageNum, const MessageParam ¶m) { + switch (messageNum) { + case 0x4001: + case 0x4800: + startWalkToX(param.asPoint().x, false); + break; + case 0x4004: + GotoState(&Klaymen::stTryStandIdle); + break; + case 0x480A: + if (param.asInteger() == 1) + GotoState(&Klaymen::stMoveObjectSkipTurnFaceObject); + else + GotoState(&Klaymen::stMoveObjectFaceObject); + break; + case 0x4812: + if (param.asInteger() == 2) + GotoState(&Klaymen::stPickUpNeedle); + else if (param.asInteger() == 1) + GotoState(&Klaymen::stPickUpTube); + else + GotoState(&Klaymen::stPickUpGeneric); + break; + case 0x4817: + setDoDeltaX(param.asInteger()); + gotoNextStateExt(); + break; + case 0x481A: + GotoState(&Klaymen::stInsertDisk); + break; + case 0x481B: + if (param.asPoint().y != 0) + startWalkToXDistance(param.asPoint().y, param.asPoint().x); + else + startWalkToAttachedSpriteXDistance(param.asPoint().x); + break; + case 0x481D: + GotoState(&Klaymen::stTurnToUse); + break; + case 0x481E: + GotoState(&Klaymen::stReturnFromUse); + break; + case 0x481F: + if (param.asInteger() == 1) + GotoState(&Klaymen::stWonderAboutAfter); + else if (param.asInteger() == 0) + GotoState(&Klaymen::stWonderAboutHalf); + else if (param.asInteger() == 4) + GotoState(&Klaymen::stTurnAwayFromUse); + else if (param.asInteger() == 3) + GotoState(&Klaymen::stTurnToUseHalf); + else + GotoState(&Klaymen::stWonderAbout); + break; + case 0x482D: + setDoDeltaX(_x > (int16)param.asInteger() ? 1 : 0); + gotoNextStateExt(); + break; + case 0x483F: + startSpecialWalkRight(param.asInteger()); + break; + case 0x4840: + startSpecialWalkLeft(param.asInteger()); + break; + } + return 0; +} + +} // End of namespace Neverhood diff --git a/engines/neverhood/modules/module1400_sprites.h b/engines/neverhood/modules/module1400_sprites.h new file mode 100644 index 0000000000..49b91fe0cf --- /dev/null +++ b/engines/neverhood/modules/module1400_sprites.h @@ -0,0 +1,198 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef NEVERHOOD_MODULES_MODULE1400_SPRITES_H +#define NEVERHOOD_MODULES_MODULE1400_SPRITES_H + +#include "neverhood/neverhood.h" +#include "neverhood/module.h" +#include "neverhood/scene.h" + +namespace Neverhood { + +class AsScene1401Pipe : public AnimatedSprite { +public: + AsScene1401Pipe(NeverhoodEngine *vm); + virtual ~AsScene1401Pipe(); +protected: + int _countdown1; + int _countdown2; + void update(); + void upSuckInProjector(); + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); + uint32 hmSuckInProjector(int messageNum, const MessageParam ¶m, Entity *sender); + void stStartSucking(); + void stDoneSucking(); + void stSuckInProjector(); +}; + +class AsScene1401Mouse : public AnimatedSprite { +public: + AsScene1401Mouse(NeverhoodEngine *vm); +protected: + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); + void suSuckedIn(); + void stSuckedIn(); +}; + +class AsScene1401Cheese : public AnimatedSprite { +public: + AsScene1401Cheese(NeverhoodEngine *vm); +protected: + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); + void suSuckedIn(); + void stSuckedIn(); +}; + +class AsScene1401BackDoor : public AnimatedSprite { +public: + AsScene1401BackDoor(NeverhoodEngine *vm, Sprite *klaymen, bool isOpen); +protected: + Sprite *_klaymen; + int _countdown; + bool _isOpen; + void update(); + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); + void stOpenDoor(); + void stCloseDoor(); + void stCloseDoorDone(); +}; + +struct AsCommonProjectorItem { + NPoint point; + int8 maxSlotCount; + int8 lockSlotIndex; + int8 index1; + int8 leftBorderLeaves; + int8 rightBorderLeaves; +}; + +class AsCommonProjector : public AnimatedSprite { +public: + AsCommonProjector(NeverhoodEngine *vm, Scene *parentScene, Sprite *klaymen, Sprite *asPipe); + virtual ~AsCommonProjector(); +protected: + Scene *_parentScene; + Sprite *_klaymen; + Sprite *_asPipe; + const AsCommonProjectorItem *_asProjectorItem; + int16 _beforeMoveX; + bool _lockedInSlot; + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); + uint32 hmLockedInSlot(int messageNum, const MessageParam ¶m, Entity *sender); + uint32 hmAnimation(int messageNum, const MessageParam ¶m, Entity *sender); + void suMoving(); + void moveProjector(); + void stSuckedIn(); + void stIdle(); + void stMoving(); + void stStartLockedInSlot(); + void stStayLockedInSlot(); + void stStartProjecting(); + void stLockedInSlot(); + void stStopProjecting(); + void stTurnToFront(); + void stStartSuckedIn(); +}; + +class SsScene1402BridgePart : public StaticSprite { +public: + SsScene1402BridgePart(NeverhoodEngine *vm, uint32 fileHash, int surfacePriority); +}; + +class AsScene1402PuzzleBox : public AnimatedSprite { +public: + AsScene1402PuzzleBox(NeverhoodEngine *vm, Scene *parentScene, int status); +protected: + Scene *_parentScene; + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); + void stMoveUpDone(); + void stMoveDownDone(); + void stMoveDownSolvedDone(); +}; + +class AsScene1407Mouse : public AnimatedSprite { +public: + AsScene1407Mouse(NeverhoodEngine *vm, Scene *parentScene); +protected: + Scene *_parentScene; + int16 _walkDestX; + int16 _currSectionIndex; + int16 _nextHoleIndex; + int _countdown; + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); + void suWalkTo(); + void upGoThroughHole(); + void stIdleLookAtGoodHole(); + void stWalkToDest(); + void stWalkToHole(); + void stGoThroughHole(); + void stArriveAtHole(); +}; + +class Scene1405; + +class AsScene1405Tile : public AnimatedSprite { +public: + AsScene1405Tile(NeverhoodEngine *vm, Scene1405 *parentScene, uint32 tileIndex); + void show(); + void hide(); +protected: + Scene1405 *_parentScene; + bool _isShowing; + uint32 _tileIndex; + int _countdown; + void update(); + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); +}; + +class KmScene1401 : public Klaymen { +public: + KmScene1401(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); +protected: + uint32 xHandleMessage(int messageNum, const MessageParam ¶m); +}; + +class KmScene1402 : public Klaymen { +public: + KmScene1402(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); +protected: + uint32 xHandleMessage(int messageNum, const MessageParam ¶m); +}; + +class KmScene1403 : public Klaymen { +public: + KmScene1403(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); +protected: + uint32 xHandleMessage(int messageNum, const MessageParam ¶m); +}; + +class KmScene1404 : public Klaymen { +public: + KmScene1404(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); +protected: + uint32 xHandleMessage(int messageNum, const MessageParam ¶m); +}; + +} // End of namespace Neverhood + +#endif /* NEVERHOOD_MODULES_MODULE1400_SPRITES_H */ diff --git a/engines/neverhood/modules/module1600.cpp b/engines/neverhood/modules/module1600.cpp index a5a785e130..0df7dd8925 100644 --- a/engines/neverhood/modules/module1600.cpp +++ b/engines/neverhood/modules/module1600.cpp @@ -20,10 +20,12 @@ * */ -#include "neverhood/modules/module1600.h" #include "neverhood/gamemodule.h" -#include "neverhood/modules/module1200.h" -#include "neverhood/modules/module2200.h" +#include "neverhood/modules/module1200_sprites.h" +#include "neverhood/modules/module1600.h" +#include "neverhood/modules/module1600_sprites.h" +#include "neverhood/modules/module2200_sprites.h" +#include "neverhood/modules/module3000_sprites.h" namespace Neverhood { @@ -183,825 +185,6 @@ void Module1600::updateScene() { } } -AsCommonCar::AsCommonCar(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) - : AnimatedSprite(vm, 1000), _parentScene(parentScene) { - - createSurface(200, 556, 328); - _x = x; - _y = y; - - _inMainArea = false; - _exitDirection = 0; - _currPointIndex = 0; - _hasAgainDestPoint = false; - _stepError = 0; - _hasAgainDestPointIndex = false; - _steps = 0; - _isBraking = false; - _yMoveTotalSteps = 0; - _isBusy = false; - _isIdle = false; - _isMoving = true; - _rectFlag = false; - _newDeltaXType = -1; - _soundCounter = 0; - _pathPoints = NULL; - _currMoveDirection = 0; - - startAnimation(0xD4220027, 0, -1); - setDoDeltaX(getGlobalVar(V_CAR_DELTA_X)); - - SetUpdateHandler(&AsCommonCar::update); - SetMessageHandler(&AsCommonCar::handleMessage); - SetSpriteUpdate(NULL); -} - -AsCommonCar::~AsCommonCar() { - if (_finalizeStateCb == AnimationCallback(&AsCommonCar::evTurnCarDone)) - setGlobalVar(V_CAR_DELTA_X, !getGlobalVar(V_CAR_DELTA_X)); -} - -void AsCommonCar::setPathPoints(NPointArray *pathPoints) { - _pathPoints = pathPoints; -} - -void AsCommonCar::update() { - if (_newDeltaXType >= 0) { - setDoDeltaX(_newDeltaXType); - _newDeltaXType = -1; - } - AnimatedSprite::update(); - if (_hasAgainDestPoint && _yMoveTotalSteps == 0 && !_isBusy) { - _hasAgainDestPoint = false; - _hasAgainDestPointIndex = false; - sendPointMessage(this, 0x2004, _againDestPoint); - } else if (_hasAgainDestPointIndex && _yMoveTotalSteps == 0 && !_isBusy) { - _hasAgainDestPointIndex = false; - sendMessage(this, 0x2003, _againDestPointIndex); - } - updateMovement(); - updateSound(); -} - -void AsCommonCar::upIdle() { - update(); - if (++_idleCounter >= _idleCounterMax) - stIdleBlink(); - updateSound(); -} - -uint32 AsCommonCar::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x1019: - SetSpriteUpdate(NULL); - break; - case 0x2002: - // Set the current position without moving - _currPointIndex = param.asInteger(); - _stepError = 0; - _x = pathPoint(_currPointIndex).x; - _y = pathPoint(_currPointIndex).y; - break; - case 0x2003: - // Move to a point by its index - { - int newPointIndex = param.asInteger(); - if (_yMoveTotalSteps <= 0 && !_isBusy) { - _destX = pathPoint(newPointIndex).x; - _destY = pathPoint(newPointIndex).y; - if (_currPointIndex < newPointIndex) { - moveToNextPoint(); - } else if (_currPointIndex == newPointIndex && _stepError == 0) { - if (_currPointIndex == 0) { - _yMoveTotalSteps = 0; - sendMessage(_parentScene, 0x2005, 0); - } else if (_currPointIndex == (int)_pathPoints->size()) { - _yMoveTotalSteps = 0; - sendMessage(_parentScene, 0x2006, 0); - } - } else { - moveToPrevPoint(); - } - } else { - _hasAgainDestPointIndex = true; - _againDestPointIndex = newPointIndex; - } - } - break; - case 0x2004: - // Move to the point closest to the parameter point - { - int minMatchIndex = -1; - int minMatchDistance, distance; - NPoint pt = param.asPoint(); - if (_yMoveTotalSteps <= 0 && !_isBusy) { - // Check if we're already exiting (or something) - if ((pt.x <= 20 && _exitDirection == 1) || - (pt.x >= 620 && _exitDirection == 3) || - (pt.y <= 20 && _exitDirection == 2) || - (pt.y >= 460 && _exitDirection == 4)) - break; - _destX = pt.x; - _destY = pt.y; - minMatchDistance = calcDistance(_destX, _destY, _x, _y) + 1; - for (int i = _currPointIndex + 1; i < (int)_pathPoints->size(); i++) { - distance = calcDistance(_destX, _destY, pathPoint(i).x, pathPoint(i).y); - if (distance >= minMatchDistance) - break; - minMatchDistance = distance; - minMatchIndex = i; - } - for (int i = _currPointIndex; i >= 0; i--) { - distance = calcDistance(_destX, _destY, pathPoint(i).x, pathPoint(i).y); - if (distance >= minMatchDistance) - break; - minMatchDistance = distance; - minMatchIndex = i; - } - if (minMatchIndex == -1) { - if (_currPointIndex == 0) - moveToPrevPoint(); - else - SetSpriteUpdate(NULL); - } else { - if (minMatchIndex > _currPointIndex) - moveToNextPoint(); - else - moveToPrevPoint(); - } - } else { - _hasAgainDestPoint = true; - _againDestPoint = pt; - } - } - break; - case 0x2007: - _yMoveTotalSteps = param.asInteger(); - _steps = 0; - _isBraking = false; - _lastDistance = 640; - SetSpriteUpdate(&AsCommonCar::suMoveToPrevPoint); - break; - case 0x2008: - _yMoveTotalSteps = param.asInteger(); - _steps = 0; - _isBraking = false; - _lastDistance = 640; - SetSpriteUpdate(&AsCommonCar::suMoveToNextPoint); - break; - case 0x2009: - stEnterCar(); - break; - case 0x200A: - stLeaveCar(); - break; - case 0x200E: - stTurnCar(); - break; - case 0x200F: - stCarAtHome(); - _newDeltaXType = param.asInteger(); - break; - } - return messageResult; -} - -uint32 AsCommonCar::hmAnimation(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = AsCommonCar::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x100D: - if (_isBusy && param.asInteger() == 0x025424A2) - gotoNextState(); - break; - case 0x3002: - gotoNextState(); - break; - } - return messageResult; -} - -uint32 AsCommonCar::hmLeaveCar(int messageNum, const MessageParam ¶m, Entity *sender) { - switch (messageNum) { - case 0x2009: - stEnterCar(); - break; - case 0x3002: - sendMessage(_parentScene, 0x200A, 0); - SetMessageHandler(&AsCommonCar::handleMessage); - break; - } - return 0; -} - -void AsCommonCar::stCarAtHome() { - bool doDeltaX = _doDeltaX; - SetSpriteUpdate(NULL); - _hasAgainDestPoint = false; - _hasAgainDestPointIndex = false; - _isBraking = false; - _isBusy = false; - _isIdle = false; - _isMoving = false; - _rectFlag = false; - NextState(&AsCommonCar::stLeanForwardIdle); - startAnimation(0x35698F78, 0, -1); - setDoDeltaX(doDeltaX ? 1 : 0); - _currMoveDirection = 0; - _newMoveDirection = 0; - _steps = 0; - _idleCounter = 0; - _idleCounterMax = _vm->_rnd->getRandomNumber(64 - 1) + 24; - SetUpdateHandler(&AsCommonCar::upIdle); - SetMessageHandler(&AsCommonCar::handleMessage); - FinalizeState(&AsCommonCar::evIdleDone); -} - -void AsCommonCar::updateTurnMovement() { - if (_turnMoveStatus == 1) { - _lastDistance = 640; - _isIdle = false; - _isBraking = false; - SetSpriteUpdate(&AsCommonCar::suMoveToNextPoint); - } else if (_turnMoveStatus == 2) { - _lastDistance = 640; - _isIdle = false; - _isBraking = false; - SetSpriteUpdate(&AsCommonCar::suMoveToPrevPoint); - } -} - -void AsCommonCar::updateMovement() { - if (_isBraking && !_isIdle && !_isBusy) { - gotoNextState(); - _isMoving = false; - _isIdle = true; - startAnimation(0x192ADD30, 0, -1); - SetUpdateHandler(&AsCommonCar::update); - SetMessageHandler(&AsCommonCar::hmAnimation); - NextState(&AsCommonCar::stLeanForwardIdle); - } else if (!_isBraking && _steps && _isIdle) { - gotoNextState(); - _isIdle = false; - startAnimation(0x9966B138, 0, -1); - SetUpdateHandler(&AsCommonCar::update); - SetMessageHandler(&AsCommonCar::hmAnimation); - NextState(&AsCommonCar::stUpdateMoveDirection); - } else if (_newMoveDirection != _currMoveDirection && _isMoving && !_isBusy) { - gotoNextState(); - _currMoveDirection = _newMoveDirection; - stUpdateMoveDirection(); - } -} - -void AsCommonCar::stEnterCar() { - startAnimation(0xA86A9538, 0, -1); - SetUpdateHandler(&AsCommonCar::update); - SetMessageHandler(&AsCommonCar::hmAnimation); - NextState(&AsCommonCar::stLeanForwardIdle); -} - -void AsCommonCar::stLeaveCar() { - startAnimation(0xA86A9538, -1, -1); - _playBackwards = true; - SetUpdateHandler(&AsCommonCar::update); - SetMessageHandler(&AsCommonCar::hmLeaveCar); -} - -void AsCommonCar::stLeanForwardIdle() { - startAnimation(0x35698F78, 0, -1); - _currMoveDirection = 0; - _newMoveDirection = 0; - _steps = 0; - _idleCounter = 0; - _idleCounterMax = _vm->_rnd->getRandomNumber(64 - 1) + 24; - SetUpdateHandler(&AsCommonCar::upIdle); - SetMessageHandler(&AsCommonCar::handleMessage); - FinalizeState(&AsCommonCar::evIdleDone); -} - -void AsCommonCar::evIdleDone() { - SetUpdateHandler(&AsCommonCar::update); -} - -void AsCommonCar::stIdleBlink() { - startAnimation(0xB579A77C, 0, -1); - _idleCounter = 0; - _idleCounterMax = _vm->_rnd->getRandomNumber(64 - 1) + 24; - SetUpdateHandler(&AsCommonCar::update); - SetMessageHandler(&AsCommonCar::hmAnimation); - NextState(&AsCommonCar::stLeanForwardIdle); -} - -void AsCommonCar::stUpdateMoveDirection() { - _isMoving = true; - if (_currMoveDirection == 1) - startAnimation(0xD4AA03A4, 0, -1); - else if (_currMoveDirection == 3) - startAnimation(0xD00A1364, 0, -1); - else if ((_currMoveDirection == 2 && _doDeltaX) || (_currMoveDirection == 4 && !_doDeltaX)) - stTurnCar(); - else - startAnimation(0xD4220027, 0, -1); - setGlobalVar(V_CAR_DELTA_X, _doDeltaX ? 1 : 0); -} - -void AsCommonCar::moveToNextPoint() { - if (_currPointIndex >= (int)_pathPoints->size() - 1) { - _yMoveTotalSteps = 0; - sendMessage(this, 0x1019, 0); - sendMessage(_parentScene, 0x2006, 0); - } else { - NPoint nextPt = pathPoint(_currPointIndex + 1); - NPoint currPt = pathPoint(_currPointIndex); - if (ABS(nextPt.y - currPt.y) <= ABS(nextPt.x - currPt.x) && - ((_currMoveDirection == 2 && nextPt.x < currPt.x) || - (_currMoveDirection == 4 && nextPt.x >= currPt.x))) { - if (_currMoveDirection == 2) - _currMoveDirection = 4; - else if (_currMoveDirection == 4) - _currMoveDirection = 2; - if (_isIdle) - stTurnCarMoveToNextPoint(); - else - stBrakeMoveToNextPoint(); - } else { - if (_steps == 0) { - gotoNextState(); - _isIdle = false; - startAnimation(0x9966B138, 0, -1); - SetMessageHandler(&AsCommonCar::hmAnimation); - SetUpdateHandler(&AsCommonCar::update); - NextState(&AsCommonCar::stUpdateMoveDirection); - } - _isBraking = false; - SetSpriteUpdate(&AsCommonCar::suMoveToNextPoint); - _lastDistance = 640; - } - } -} - -void AsCommonCar::stBrakeMoveToNextPoint() { - gotoNextState(); - _isBusy = true; - _isBraking = true; - startAnimation(0x192ADD30, 0, -1); - SetUpdateHandler(&AsCommonCar::update); - SetMessageHandler(&AsCommonCar::hmAnimation); - NextState(&AsCommonCar::stTurnCarMoveToNextPoint); -} - -void AsCommonCar::stTurnCar() { - // Turn to left/right #1 - gotoNextState(); - _isBusy = true; - startAnimation(0xF46A0324, 0, -1); - SetUpdateHandler(&AsCommonCar::update); - SetMessageHandler(&AsCommonCar::hmAnimation); - FinalizeState(&AsCommonCar::evTurnCarDone); - _turnMoveStatus = 0; - updateTurnMovement(); -} - -void AsCommonCar::stTurnCarMoveToNextPoint() { - // Turn to left/right #2 - gotoNextState(); - _isBusy = true; - startAnimation(0xF46A0324, 0, -1); - SetUpdateHandler(&AsCommonCar::update); - SetMessageHandler(&AsCommonCar::hmAnimation); - FinalizeState(&AsCommonCar::evTurnCarDone); - _turnMoveStatus = 1; - updateTurnMovement(); -} - -void AsCommonCar::stTurnCarMoveToPrevPoint() { - // Turn to left/right #3 - FinalizeState(NULL); - _isBusy = true; - startAnimation(0xF46A0324, 0, -1); - SetUpdateHandler(&AsCommonCar::update); - SetMessageHandler(&AsCommonCar::hmAnimation); - FinalizeState(&AsCommonCar::evTurnCarDone); - _turnMoveStatus = 2; - updateTurnMovement(); -} - -void AsCommonCar::moveToPrevPoint() { - if (_currPointIndex == 0 && _stepError == 0) { - _yMoveTotalSteps = 0; - sendMessage(this, 0x1019, 0); - sendMessage(_parentScene, 0x2005, 0); - } else { - NPoint prevPt; - NPoint currPt; - if (_stepError == 0) { - prevPt = pathPoint(_currPointIndex - 1); - currPt = pathPoint(_currPointIndex); - } else { - prevPt = pathPoint(_currPointIndex); - currPt = pathPoint(_currPointIndex + 1); - } - if (ABS(prevPt.y - currPt.y) <= ABS(prevPt.x - currPt.x) && - ((_currMoveDirection == 2 && prevPt.x < currPt.x) || - (_currMoveDirection == 4 && prevPt.x >= currPt.x))) { - if (_currMoveDirection == 2) - _currMoveDirection = 4; - else if (_currMoveDirection == 4) - _currMoveDirection = 2; - if (_isIdle) - stTurnCarMoveToPrevPoint(); - else - stBrakeMoveToPrevPoint(); - } else { - if (_steps == 0) { - gotoNextState(); - _isIdle = false; - startAnimation(0x9966B138, 0, -1); - SetMessageHandler(&AsCommonCar::hmAnimation); - SetUpdateHandler(&AsCommonCar::update); - NextState(&AsCommonCar::stUpdateMoveDirection); - } - _isBraking = false; - SetSpriteUpdate(&AsCommonCar::suMoveToPrevPoint); - _lastDistance = 640; - } - } -} - -void AsCommonCar::stBrakeMoveToPrevPoint() { - FinalizeState(NULL); - _isBusy = true; - _isBraking = true; - startAnimation(0x192ADD30, 0, -1); - SetUpdateHandler(&AsCommonCar::update); - SetMessageHandler(&AsCommonCar::hmAnimation); - NextState(&AsCommonCar::stTurnCarMoveToPrevPoint); -} - -void AsCommonCar::evTurnCarDone() { - _isBusy = false; - setDoDeltaX(2); - _newMoveDirection = 0; - stUpdateMoveDirection(); -} - -void AsCommonCar::suMoveToNextPoint() { - int16 newX = _x, newY = _y; - - if (_currPointIndex >= (int)_pathPoints->size()) { - _yMoveTotalSteps = 0; - sendMessage(this, 0x1019, 0); - sendMessage(_parentScene, 0x2006, 0); - return; - } - - if (_isBraking) { - if (_steps <= 0) { - sendMessage(this, 0x1019, 0); - return; - } else - _steps--; - } else if (_steps < 11) - _steps++; - - bool firstTime = true; - _ySteps = _steps; - int stepsCtr = _steps; - - while (stepsCtr > 0) { - NPoint pt1; - NPoint pt2 = pathPoint(_currPointIndex); - if (_currPointIndex + 1 >= (int)_pathPoints->size()) - pt1 = pathPoint(0); - else - pt1 = pathPoint(_currPointIndex + 1); - int16 deltaX = ABS(pt1.x - pt2.x); - int16 deltaY = ABS(pt1.y - pt2.y); - if (deltaX >= deltaY) { - _newMoveDirection = 2; - if (pt1.x < pt2.x) - _newMoveDirection = 4; - if (stepsCtr + _stepError >= deltaX) { - stepsCtr -= deltaX; - stepsCtr += _stepError; - _stepError = 0; - _currPointIndex++; - if (_currPointIndex == (int)_pathPoints->size() - 1) - stepsCtr = 0; - newX = pathPoint(_currPointIndex).x; - newY = pathPoint(_currPointIndex).y; - } else { - _stepError += stepsCtr; - if (pt1.x >= pt2.x) - newX += stepsCtr; - else - newX -= stepsCtr; - if (pt1.y >= pt2.y) - newY = pt2.y + (deltaY * _stepError) / deltaX; - else - newY = pt2.y - (deltaY * _stepError) / deltaX; - stepsCtr = 0; - } - } else { - _newMoveDirection = 3; - if (pt1.y < pt2.y) - _newMoveDirection = 1; - if (firstTime) { - if (pt1.y >= pt2.y) - stepsCtr += 7; - else { - stepsCtr -= 4; - if (stepsCtr < 0) - stepsCtr = 0; - } - _ySteps = stepsCtr; - } - if (stepsCtr + _stepError >= deltaY) { - stepsCtr -= deltaY; - stepsCtr += _stepError; - _stepError = 0; - _currPointIndex++; - if (_currPointIndex == (int)_pathPoints->size() - 1) - stepsCtr = 0; - newX = pathPoint(_currPointIndex).x; - newY = pathPoint(_currPointIndex).y; - } else { - _stepError += stepsCtr; - if (pt1.x >= pt2.x) - newX = pt2.x + (deltaX * _stepError) / deltaY; - else - newX = pt2.x - (deltaX * _stepError) / deltaY; - if (pt1.y >= pt2.y) - newY += stepsCtr; - else - newY -= stepsCtr; - stepsCtr = 0; - } - } - firstTime = false; - } - - if (_yMoveTotalSteps != 0) { - _x = newX; - _y = newY; - _yMoveTotalSteps -= _ySteps; - if (_yMoveTotalSteps <= 0) { - _isBraking = true; - _yMoveTotalSteps = 0; - } - } else { - int distance = calcDistance(_destX, _destY, _x, _y); - _x = newX; - _y = newY; - if (newX > 20 && newX < 620 && newY > 20 && newY < 460) { - _exitDirection = 0; - _inMainArea = true; - } else if (_inMainArea) { - _destX = pathPoint(_pathPoints->size() - 1).x; - _destY = pathPoint(_pathPoints->size() - 1).y; - _inMainArea = false; - if (_x <= 20) - _exitDirection = 1; - else if (_x >= 620) - _exitDirection = 3; - else if (_y <= 20) - _exitDirection = 2; - else if (_y >= 460) - _exitDirection = 4; - if (_exitDirection != 0 && _isBraking) { - _isBraking = false; - _steps = 11; - } - } - if ((distance < 20 && _exitDirection == 0 && _lastDistance < distance) || - (_exitDirection == 0 && _lastDistance + 20 < distance)) - _isBraking = true; - if (distance < _lastDistance) - _lastDistance = distance; - if (_currPointIndex == (int)_pathPoints->size() - 1) { - _isBraking = true; - _yMoveTotalSteps = 0; - sendMessage(this, 0x1019, 0); - sendMessage(_parentScene, 0x2006, 0); - } - } - -} - -void AsCommonCar::suMoveToPrevPoint() { - int16 newX = _x, newY = _y; - - if (_currPointIndex == 0 && _stepError == 0) { - _yMoveTotalSteps = 0; - sendMessage(this, 0x1019, 0); - sendMessage(_parentScene, 0x2005, 0); - return; - } - - if (_isBraking) { - if (_steps <= 0) { - sendMessage(this, 0x1019, 0); - return; - } else - _steps--; - } else if (_steps < 11) - _steps++; - - bool firstTime = true; - _ySteps = _steps; - int stepsCtr = _steps; - - while (stepsCtr > 0) { - if (_stepError == 0) - _currPointIndex--; - NPoint pt1; - NPoint pt2 = pathPoint(_currPointIndex); - if (_currPointIndex + 1 >= (int)_pathPoints->size()) - pt1 = pathPoint(0); - else - pt1 = pathPoint(_currPointIndex + 1); - int16 deltaX = ABS(pt1.x - pt2.x); - int16 deltaY = ABS(pt1.y - pt2.y); - if (deltaX >= deltaY) { - _newMoveDirection = 4; - if (pt1.x < pt2.x) - _newMoveDirection = 2; - if (_stepError == 0) - _stepError = deltaX; - if (stepsCtr > _stepError) { - stepsCtr -= _stepError; - _stepError = 0; - if (_currPointIndex == 0) - stepsCtr = 0; - newX = pathPoint(_currPointIndex).x; - newY = pathPoint(_currPointIndex).y; - } else { - _stepError -= stepsCtr; - if (pt1.x >= pt2.x) - newX -= stepsCtr; - else - newX += stepsCtr; - if (pt1.y >= pt2.y) - newY = pt2.y + (deltaY * _stepError) / deltaX; - else - newY = pt2.y - (deltaY * _stepError) / deltaX; - stepsCtr = 0; - } - } else { - _newMoveDirection = 1; - if (pt1.y < pt2.y) - _newMoveDirection = 3; - if (firstTime) { - if (pt1.y >= pt2.y) { - stepsCtr -= 4; - if (stepsCtr < 0) - stepsCtr = 0; - } else { - stepsCtr += 7; - } - _ySteps = stepsCtr; - } - if (_stepError == 0) - _stepError = deltaY; - if (stepsCtr > _stepError) { - stepsCtr -= _stepError; - _stepError = 0; - if (_currPointIndex == 0) - stepsCtr = 0; - newX = pathPoint(_currPointIndex).x; - newY = pathPoint(_currPointIndex).y; - } else { - _stepError -= stepsCtr; - if (pt1.x >= pt2.x) - newX = pt2.x + (deltaX * _stepError) / deltaY; - else - newX = pt2.x - (deltaX * _stepError) / deltaY; - if (pt1.y >= pt2.y) - newY -= stepsCtr; - else - newY += stepsCtr; - stepsCtr = 0; - } - } - firstTime = false; - } - - if (_yMoveTotalSteps != 0) { - _x = newX; - _y = newY; - _yMoveTotalSteps -= _ySteps; - if (_yMoveTotalSteps <= 0) { - _isBraking = true; - _yMoveTotalSteps = 0; - } - } else { - int distance = calcDistance(_destX, _destY, _x, _y); - _x = newX; - _y = newY; - if (newX > 20 && newX < 620 && newY > 20 && newY < 460) { - _exitDirection = 0; - _inMainArea = true; - } else if (_inMainArea) { - _destX = pathPoint(0).x; - _destY = pathPoint(0).y; - _inMainArea = false; - if (_x <= 20) - _exitDirection = 1; - else if (_x >= 620) - _exitDirection = 3; - else if (_y <= 20) - _exitDirection = 2; - else if (_y >= 460) - _exitDirection = 4; - if (_exitDirection != 0 && _isBraking) { - _isBraking = false; - _steps = 11; - } - } - if ((distance < 20 && _exitDirection == 0 && _lastDistance < distance) || - (_exitDirection == 0 && _lastDistance + 20 < distance)) - _isBraking = true; - if (distance < _lastDistance) - _lastDistance = distance; - if (_currPointIndex == 0 && _stepError == 0) { - _isBraking = true; - _yMoveTotalSteps = 0; - sendMessage(this, 0x1019, 0); - sendMessage(_parentScene, 0x2005, 0); - } - } - -} - -void AsCommonCar::updateSound() { - int maxSoundCounter = 0; - _soundCounter++; - if (_steps != 0 && !_isIdle) { - if (_currMoveDirection == 1) - maxSoundCounter = 18 - _steps; - else if (_currMoveDirection == 3) { - maxSoundCounter = 5 - _steps; - if (maxSoundCounter < 1) - maxSoundCounter = 1; - } else - maxSoundCounter = 14 - _steps; - } else - maxSoundCounter = 21; - if (_soundCounter >= maxSoundCounter) { - sendMessage(_parentScene, 0x200D, 0); - _soundCounter = 0; - } -} - -AsCommonIdleCarLower::AsCommonIdleCarLower(NeverhoodEngine *vm, int16 x, int16 y) - : AnimatedSprite(vm, 0x1209E09F, 1100, x, y) { - - setDoDeltaX(1); - startAnimation(0x1209E09F, 1, -1); - _newStickFrameIndex = 1; -} - -AsCommonIdleCarFull::AsCommonIdleCarFull(NeverhoodEngine *vm, int16 x, int16 y) - : AnimatedSprite(vm, 0x1209E09F, 100, x, y) { - - setDoDeltaX(1); - _newStickFrameIndex = 0; -} - -AsCommonCarConnector::AsCommonCarConnector(NeverhoodEngine *vm, AsCommonCar *asCar) - : AnimatedSprite(vm, 1100), _asCar(asCar) { - - createSurface1(0x60281C10, 150); - startAnimation(0x60281C10, -1, -1); - _newStickFrameIndex = STICK_LAST_FRAME; - SetUpdateHandler(&AsCommonCarConnector::update); -} - -void AsCommonCarConnector::update() { - _x = _asCar->getX(); - _y = _asCar->getY(); - AnimatedSprite::update(); -} - -void Tracks::findTrackPoint(NPoint pt, int &minMatchTrackIndex, int &minMatchDistance, - DataResource &dataResource) { - const uint trackCount = size(); - minMatchTrackIndex = -1; - minMatchDistance = 640; - for (uint trackIndex = 0; trackIndex < trackCount; trackIndex++) { - NPointArray *pointList = dataResource.getPointArray((*this)[trackIndex]->trackPointsName); - for (uint pointIndex = 0; pointIndex < pointList->size(); pointIndex++) { - NPoint testPt = (*pointList)[pointIndex]; - int distance = calcDistance(testPt.x, testPt.y, pt.x, pt.y); - if (distance < minMatchDistance) { - minMatchTrackIndex = trackIndex; - minMatchDistance = distance; - } - } - } -} - Scene1608::Scene1608(NeverhoodEngine *vm, Module *parentModule, int which) : Scene(vm, parentModule), _asCar(NULL), _countdown1(0) { diff --git a/engines/neverhood/modules/module1600.h b/engines/neverhood/modules/module1600.h index 5f0da528ab..f08eaad8fc 100644 --- a/engines/neverhood/modules/module1600.h +++ b/engines/neverhood/modules/module1600.h @@ -26,13 +26,9 @@ #include "neverhood/neverhood.h" #include "neverhood/module.h" #include "neverhood/scene.h" -#include "neverhood/console.h" -#include "neverhood/modules/module3000.h" namespace Neverhood { -// Module1600 - class Module1600 : public Module { public: Module1600(NeverhoodEngine *vm, Module *parentModule, int which); @@ -43,90 +39,7 @@ protected: void updateScene(); }; -class AsCommonCar : public AnimatedSprite { -public: - AsCommonCar(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); - ~AsCommonCar(); - void setPathPoints(NPointArray *pathPoints); -protected: - Scene *_parentScene; - NPointArray *_pathPoints; - int _newMoveDirection; - int _currMoveDirection; - int _exitDirection; - int _currPointIndex; - bool _hasAgainDestPoint; - NPoint _againDestPoint; - bool _hasAgainDestPointIndex; - int _againDestPointIndex; - bool _inMainArea; - bool _isBraking; - bool _isBusy; - bool _isIdle; - bool _isMoving; - bool _rectFlag; - int _idleCounter; - int _idleCounterMax; - int _steps; - int _stepError; - int _lastDistance; - int _yMoveTotalSteps; - int _ySteps; - int _newDeltaXType; - int _soundCounter; - int _turnMoveStatus; - int16 _destX, _destY; - NPoint pathPoint(uint index) { return (*_pathPoints)[index]; } - void update(); - void upIdle(); - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); - uint32 hmAnimation(int messageNum, const MessageParam ¶m, Entity *sender); - uint32 hmLeaveCar(int messageNum, const MessageParam ¶m, Entity *sender); - void stCarAtHome(); - void updateTurnMovement(); - void updateMovement(); - void stEnterCar(); - void stLeaveCar(); - void stLeanForwardIdle(); - void evIdleDone(); - void stIdleBlink(); - void stUpdateMoveDirection(); - void stTurnCar(); - void moveToNextPoint(); - void stBrakeMoveToNextPoint(); - void stTurnCarMoveToNextPoint(); - void moveToPrevPoint(); - void stBrakeMoveToPrevPoint(); - void stTurnCarMoveToPrevPoint(); - void evTurnCarDone(); - void suMoveToNextPoint(); - void suMoveToPrevPoint(); - void updateSound(); -}; - -class AsCommonIdleCarLower : public AnimatedSprite { -public: - AsCommonIdleCarLower(NeverhoodEngine *vm, int16 x, int16 y); -}; - -class AsCommonIdleCarFull : public AnimatedSprite { -public: - AsCommonIdleCarFull(NeverhoodEngine *vm, int16 x, int16 y); -}; - -class AsCommonCarConnector : public AnimatedSprite { -public: - AsCommonCarConnector(NeverhoodEngine *vm, AsCommonCar *asCar); -protected: - AsCommonCar *_asCar; - void update(); -}; - -class Tracks : public Common::Array<TrackInfo*> { -public: - void findTrackPoint(NPoint pt, int &minMatchTrackIndex, int &minMatchDistance, - DataResource &dataResource); -}; +class AsCommonCar; class Scene1608 : public Scene { public: @@ -162,6 +75,8 @@ protected: void updateKlaymenCliprect(); }; +class AsScene3011Symbol; + class Scene1609 : public Scene { friend class Console; public: diff --git a/engines/neverhood/modules/module1600_sprites.cpp b/engines/neverhood/modules/module1600_sprites.cpp new file mode 100644 index 0000000000..06a00c82c0 --- /dev/null +++ b/engines/neverhood/modules/module1600_sprites.cpp @@ -0,0 +1,934 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "neverhood/modules/module1600_sprites.h" + +namespace Neverhood { + +AsCommonCar::AsCommonCar(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) + : AnimatedSprite(vm, 1000), _parentScene(parentScene) { + + createSurface(200, 556, 328); + _x = x; + _y = y; + + _inMainArea = false; + _exitDirection = 0; + _currPointIndex = 0; + _hasAgainDestPoint = false; + _stepError = 0; + _hasAgainDestPointIndex = false; + _steps = 0; + _isBraking = false; + _yMoveTotalSteps = 0; + _isBusy = false; + _isIdle = false; + _isMoving = true; + _rectFlag = false; + _newDeltaXType = -1; + _soundCounter = 0; + _pathPoints = NULL; + _currMoveDirection = 0; + + startAnimation(0xD4220027, 0, -1); + setDoDeltaX(getGlobalVar(V_CAR_DELTA_X)); + + SetUpdateHandler(&AsCommonCar::update); + SetMessageHandler(&AsCommonCar::handleMessage); + SetSpriteUpdate(NULL); +} + +AsCommonCar::~AsCommonCar() { + if (_finalizeStateCb == AnimationCallback(&AsCommonCar::evTurnCarDone)) + setGlobalVar(V_CAR_DELTA_X, !getGlobalVar(V_CAR_DELTA_X)); +} + +void AsCommonCar::setPathPoints(NPointArray *pathPoints) { + _pathPoints = pathPoints; +} + +void AsCommonCar::update() { + if (_newDeltaXType >= 0) { + setDoDeltaX(_newDeltaXType); + _newDeltaXType = -1; + } + AnimatedSprite::update(); + if (_hasAgainDestPoint && _yMoveTotalSteps == 0 && !_isBusy) { + _hasAgainDestPoint = false; + _hasAgainDestPointIndex = false; + sendPointMessage(this, 0x2004, _againDestPoint); + } else if (_hasAgainDestPointIndex && _yMoveTotalSteps == 0 && !_isBusy) { + _hasAgainDestPointIndex = false; + sendMessage(this, 0x2003, _againDestPointIndex); + } + updateMovement(); + updateSound(); +} + +void AsCommonCar::upIdle() { + update(); + if (++_idleCounter >= _idleCounterMax) + stIdleBlink(); + updateSound(); +} + +uint32 AsCommonCar::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x1019: + SetSpriteUpdate(NULL); + break; + case 0x2002: + // Set the current position without moving + _currPointIndex = param.asInteger(); + _stepError = 0; + _x = pathPoint(_currPointIndex).x; + _y = pathPoint(_currPointIndex).y; + break; + case 0x2003: + // Move to a point by its index + { + int newPointIndex = param.asInteger(); + if (_yMoveTotalSteps <= 0 && !_isBusy) { + _destX = pathPoint(newPointIndex).x; + _destY = pathPoint(newPointIndex).y; + if (_currPointIndex < newPointIndex) { + moveToNextPoint(); + } else if (_currPointIndex == newPointIndex && _stepError == 0) { + if (_currPointIndex == 0) { + _yMoveTotalSteps = 0; + sendMessage(_parentScene, 0x2005, 0); + } else if (_currPointIndex == (int)_pathPoints->size()) { + _yMoveTotalSteps = 0; + sendMessage(_parentScene, 0x2006, 0); + } + } else { + moveToPrevPoint(); + } + } else { + _hasAgainDestPointIndex = true; + _againDestPointIndex = newPointIndex; + } + } + break; + case 0x2004: + // Move to the point closest to the parameter point + { + int minMatchIndex = -1; + int minMatchDistance, distance; + NPoint pt = param.asPoint(); + if (_yMoveTotalSteps <= 0 && !_isBusy) { + // Check if we're already exiting (or something) + if ((pt.x <= 20 && _exitDirection == 1) || + (pt.x >= 620 && _exitDirection == 3) || + (pt.y <= 20 && _exitDirection == 2) || + (pt.y >= 460 && _exitDirection == 4)) + break; + _destX = pt.x; + _destY = pt.y; + minMatchDistance = calcDistance(_destX, _destY, _x, _y) + 1; + for (int i = _currPointIndex + 1; i < (int)_pathPoints->size(); i++) { + distance = calcDistance(_destX, _destY, pathPoint(i).x, pathPoint(i).y); + if (distance >= minMatchDistance) + break; + minMatchDistance = distance; + minMatchIndex = i; + } + for (int i = _currPointIndex; i >= 0; i--) { + distance = calcDistance(_destX, _destY, pathPoint(i).x, pathPoint(i).y); + if (distance >= minMatchDistance) + break; + minMatchDistance = distance; + minMatchIndex = i; + } + if (minMatchIndex == -1) { + if (_currPointIndex == 0) + moveToPrevPoint(); + else + SetSpriteUpdate(NULL); + } else { + if (minMatchIndex > _currPointIndex) + moveToNextPoint(); + else + moveToPrevPoint(); + } + } else { + _hasAgainDestPoint = true; + _againDestPoint = pt; + } + } + break; + case 0x2007: + _yMoveTotalSteps = param.asInteger(); + _steps = 0; + _isBraking = false; + _lastDistance = 640; + SetSpriteUpdate(&AsCommonCar::suMoveToPrevPoint); + break; + case 0x2008: + _yMoveTotalSteps = param.asInteger(); + _steps = 0; + _isBraking = false; + _lastDistance = 640; + SetSpriteUpdate(&AsCommonCar::suMoveToNextPoint); + break; + case 0x2009: + stEnterCar(); + break; + case 0x200A: + stLeaveCar(); + break; + case 0x200E: + stTurnCar(); + break; + case 0x200F: + stCarAtHome(); + _newDeltaXType = param.asInteger(); + break; + } + return messageResult; +} + +uint32 AsCommonCar::hmAnimation(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = AsCommonCar::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x100D: + if (_isBusy && param.asInteger() == 0x025424A2) + gotoNextState(); + break; + case 0x3002: + gotoNextState(); + break; + } + return messageResult; +} + +uint32 AsCommonCar::hmLeaveCar(int messageNum, const MessageParam ¶m, Entity *sender) { + switch (messageNum) { + case 0x2009: + stEnterCar(); + break; + case 0x3002: + sendMessage(_parentScene, 0x200A, 0); + SetMessageHandler(&AsCommonCar::handleMessage); + break; + } + return 0; +} + +void AsCommonCar::stCarAtHome() { + bool doDeltaX = _doDeltaX; + SetSpriteUpdate(NULL); + _hasAgainDestPoint = false; + _hasAgainDestPointIndex = false; + _isBraking = false; + _isBusy = false; + _isIdle = false; + _isMoving = false; + _rectFlag = false; + NextState(&AsCommonCar::stLeanForwardIdle); + startAnimation(0x35698F78, 0, -1); + setDoDeltaX(doDeltaX ? 1 : 0); + _currMoveDirection = 0; + _newMoveDirection = 0; + _steps = 0; + _idleCounter = 0; + _idleCounterMax = _vm->_rnd->getRandomNumber(64 - 1) + 24; + SetUpdateHandler(&AsCommonCar::upIdle); + SetMessageHandler(&AsCommonCar::handleMessage); + FinalizeState(&AsCommonCar::evIdleDone); +} + +void AsCommonCar::updateTurnMovement() { + if (_turnMoveStatus == 1) { + _lastDistance = 640; + _isIdle = false; + _isBraking = false; + SetSpriteUpdate(&AsCommonCar::suMoveToNextPoint); + } else if (_turnMoveStatus == 2) { + _lastDistance = 640; + _isIdle = false; + _isBraking = false; + SetSpriteUpdate(&AsCommonCar::suMoveToPrevPoint); + } +} + +void AsCommonCar::updateMovement() { + if (_isBraking && !_isIdle && !_isBusy) { + gotoNextState(); + _isMoving = false; + _isIdle = true; + startAnimation(0x192ADD30, 0, -1); + SetUpdateHandler(&AsCommonCar::update); + SetMessageHandler(&AsCommonCar::hmAnimation); + NextState(&AsCommonCar::stLeanForwardIdle); + } else if (!_isBraking && _steps && _isIdle) { + gotoNextState(); + _isIdle = false; + startAnimation(0x9966B138, 0, -1); + SetUpdateHandler(&AsCommonCar::update); + SetMessageHandler(&AsCommonCar::hmAnimation); + NextState(&AsCommonCar::stUpdateMoveDirection); + } else if (_newMoveDirection != _currMoveDirection && _isMoving && !_isBusy) { + gotoNextState(); + _currMoveDirection = _newMoveDirection; + stUpdateMoveDirection(); + } +} + +void AsCommonCar::stEnterCar() { + startAnimation(0xA86A9538, 0, -1); + SetUpdateHandler(&AsCommonCar::update); + SetMessageHandler(&AsCommonCar::hmAnimation); + NextState(&AsCommonCar::stLeanForwardIdle); +} + +void AsCommonCar::stLeaveCar() { + startAnimation(0xA86A9538, -1, -1); + _playBackwards = true; + SetUpdateHandler(&AsCommonCar::update); + SetMessageHandler(&AsCommonCar::hmLeaveCar); +} + +void AsCommonCar::stLeanForwardIdle() { + startAnimation(0x35698F78, 0, -1); + _currMoveDirection = 0; + _newMoveDirection = 0; + _steps = 0; + _idleCounter = 0; + _idleCounterMax = _vm->_rnd->getRandomNumber(64 - 1) + 24; + SetUpdateHandler(&AsCommonCar::upIdle); + SetMessageHandler(&AsCommonCar::handleMessage); + FinalizeState(&AsCommonCar::evIdleDone); +} + +void AsCommonCar::evIdleDone() { + SetUpdateHandler(&AsCommonCar::update); +} + +void AsCommonCar::stIdleBlink() { + startAnimation(0xB579A77C, 0, -1); + _idleCounter = 0; + _idleCounterMax = _vm->_rnd->getRandomNumber(64 - 1) + 24; + SetUpdateHandler(&AsCommonCar::update); + SetMessageHandler(&AsCommonCar::hmAnimation); + NextState(&AsCommonCar::stLeanForwardIdle); +} + +void AsCommonCar::stUpdateMoveDirection() { + _isMoving = true; + if (_currMoveDirection == 1) + startAnimation(0xD4AA03A4, 0, -1); + else if (_currMoveDirection == 3) + startAnimation(0xD00A1364, 0, -1); + else if ((_currMoveDirection == 2 && _doDeltaX) || (_currMoveDirection == 4 && !_doDeltaX)) + stTurnCar(); + else + startAnimation(0xD4220027, 0, -1); + setGlobalVar(V_CAR_DELTA_X, _doDeltaX ? 1 : 0); +} + +void AsCommonCar::moveToNextPoint() { + if (_currPointIndex >= (int)_pathPoints->size() - 1) { + _yMoveTotalSteps = 0; + sendMessage(this, 0x1019, 0); + sendMessage(_parentScene, 0x2006, 0); + } else { + NPoint nextPt = pathPoint(_currPointIndex + 1); + NPoint currPt = pathPoint(_currPointIndex); + if (ABS(nextPt.y - currPt.y) <= ABS(nextPt.x - currPt.x) && + ((_currMoveDirection == 2 && nextPt.x < currPt.x) || + (_currMoveDirection == 4 && nextPt.x >= currPt.x))) { + if (_currMoveDirection == 2) + _currMoveDirection = 4; + else if (_currMoveDirection == 4) + _currMoveDirection = 2; + if (_isIdle) + stTurnCarMoveToNextPoint(); + else + stBrakeMoveToNextPoint(); + } else { + if (_steps == 0) { + gotoNextState(); + _isIdle = false; + startAnimation(0x9966B138, 0, -1); + SetMessageHandler(&AsCommonCar::hmAnimation); + SetUpdateHandler(&AsCommonCar::update); + NextState(&AsCommonCar::stUpdateMoveDirection); + } + _isBraking = false; + SetSpriteUpdate(&AsCommonCar::suMoveToNextPoint); + _lastDistance = 640; + } + } +} + +void AsCommonCar::stBrakeMoveToNextPoint() { + gotoNextState(); + _isBusy = true; + _isBraking = true; + startAnimation(0x192ADD30, 0, -1); + SetUpdateHandler(&AsCommonCar::update); + SetMessageHandler(&AsCommonCar::hmAnimation); + NextState(&AsCommonCar::stTurnCarMoveToNextPoint); +} + +void AsCommonCar::stTurnCar() { + // Turn to left/right #1 + gotoNextState(); + _isBusy = true; + startAnimation(0xF46A0324, 0, -1); + SetUpdateHandler(&AsCommonCar::update); + SetMessageHandler(&AsCommonCar::hmAnimation); + FinalizeState(&AsCommonCar::evTurnCarDone); + _turnMoveStatus = 0; + updateTurnMovement(); +} + +void AsCommonCar::stTurnCarMoveToNextPoint() { + // Turn to left/right #2 + gotoNextState(); + _isBusy = true; + startAnimation(0xF46A0324, 0, -1); + SetUpdateHandler(&AsCommonCar::update); + SetMessageHandler(&AsCommonCar::hmAnimation); + FinalizeState(&AsCommonCar::evTurnCarDone); + _turnMoveStatus = 1; + updateTurnMovement(); +} + +void AsCommonCar::stTurnCarMoveToPrevPoint() { + // Turn to left/right #3 + FinalizeState(NULL); + _isBusy = true; + startAnimation(0xF46A0324, 0, -1); + SetUpdateHandler(&AsCommonCar::update); + SetMessageHandler(&AsCommonCar::hmAnimation); + FinalizeState(&AsCommonCar::evTurnCarDone); + _turnMoveStatus = 2; + updateTurnMovement(); +} + +void AsCommonCar::moveToPrevPoint() { + if (_currPointIndex == 0 && _stepError == 0) { + _yMoveTotalSteps = 0; + sendMessage(this, 0x1019, 0); + sendMessage(_parentScene, 0x2005, 0); + } else { + NPoint prevPt; + NPoint currPt; + if (_stepError == 0) { + prevPt = pathPoint(_currPointIndex - 1); + currPt = pathPoint(_currPointIndex); + } else { + prevPt = pathPoint(_currPointIndex); + currPt = pathPoint(_currPointIndex + 1); + } + if (ABS(prevPt.y - currPt.y) <= ABS(prevPt.x - currPt.x) && + ((_currMoveDirection == 2 && prevPt.x < currPt.x) || + (_currMoveDirection == 4 && prevPt.x >= currPt.x))) { + if (_currMoveDirection == 2) + _currMoveDirection = 4; + else if (_currMoveDirection == 4) + _currMoveDirection = 2; + if (_isIdle) + stTurnCarMoveToPrevPoint(); + else + stBrakeMoveToPrevPoint(); + } else { + if (_steps == 0) { + gotoNextState(); + _isIdle = false; + startAnimation(0x9966B138, 0, -1); + SetMessageHandler(&AsCommonCar::hmAnimation); + SetUpdateHandler(&AsCommonCar::update); + NextState(&AsCommonCar::stUpdateMoveDirection); + } + _isBraking = false; + SetSpriteUpdate(&AsCommonCar::suMoveToPrevPoint); + _lastDistance = 640; + } + } +} + +void AsCommonCar::stBrakeMoveToPrevPoint() { + FinalizeState(NULL); + _isBusy = true; + _isBraking = true; + startAnimation(0x192ADD30, 0, -1); + SetUpdateHandler(&AsCommonCar::update); + SetMessageHandler(&AsCommonCar::hmAnimation); + NextState(&AsCommonCar::stTurnCarMoveToPrevPoint); +} + +void AsCommonCar::evTurnCarDone() { + _isBusy = false; + setDoDeltaX(2); + _newMoveDirection = 0; + stUpdateMoveDirection(); +} + +void AsCommonCar::suMoveToNextPoint() { + int16 newX = _x, newY = _y; + + if (_currPointIndex >= (int)_pathPoints->size()) { + _yMoveTotalSteps = 0; + sendMessage(this, 0x1019, 0); + sendMessage(_parentScene, 0x2006, 0); + return; + } + + if (_isBraking) { + if (_steps <= 0) { + sendMessage(this, 0x1019, 0); + return; + } else + _steps--; + } else if (_steps < 11) + _steps++; + + bool firstTime = true; + _ySteps = _steps; + int stepsCtr = _steps; + + while (stepsCtr > 0) { + NPoint pt1; + NPoint pt2 = pathPoint(_currPointIndex); + if (_currPointIndex + 1 >= (int)_pathPoints->size()) + pt1 = pathPoint(0); + else + pt1 = pathPoint(_currPointIndex + 1); + int16 deltaX = ABS(pt1.x - pt2.x); + int16 deltaY = ABS(pt1.y - pt2.y); + if (deltaX >= deltaY) { + _newMoveDirection = 2; + if (pt1.x < pt2.x) + _newMoveDirection = 4; + if (stepsCtr + _stepError >= deltaX) { + stepsCtr -= deltaX; + stepsCtr += _stepError; + _stepError = 0; + _currPointIndex++; + if (_currPointIndex == (int)_pathPoints->size() - 1) + stepsCtr = 0; + newX = pathPoint(_currPointIndex).x; + newY = pathPoint(_currPointIndex).y; + } else { + _stepError += stepsCtr; + if (pt1.x >= pt2.x) + newX += stepsCtr; + else + newX -= stepsCtr; + if (pt1.y >= pt2.y) + newY = pt2.y + (deltaY * _stepError) / deltaX; + else + newY = pt2.y - (deltaY * _stepError) / deltaX; + stepsCtr = 0; + } + } else { + _newMoveDirection = 3; + if (pt1.y < pt2.y) + _newMoveDirection = 1; + if (firstTime) { + if (pt1.y >= pt2.y) + stepsCtr += 7; + else { + stepsCtr -= 4; + if (stepsCtr < 0) + stepsCtr = 0; + } + _ySteps = stepsCtr; + } + if (stepsCtr + _stepError >= deltaY) { + stepsCtr -= deltaY; + stepsCtr += _stepError; + _stepError = 0; + _currPointIndex++; + if (_currPointIndex == (int)_pathPoints->size() - 1) + stepsCtr = 0; + newX = pathPoint(_currPointIndex).x; + newY = pathPoint(_currPointIndex).y; + } else { + _stepError += stepsCtr; + if (pt1.x >= pt2.x) + newX = pt2.x + (deltaX * _stepError) / deltaY; + else + newX = pt2.x - (deltaX * _stepError) / deltaY; + if (pt1.y >= pt2.y) + newY += stepsCtr; + else + newY -= stepsCtr; + stepsCtr = 0; + } + } + firstTime = false; + } + + if (_yMoveTotalSteps != 0) { + _x = newX; + _y = newY; + _yMoveTotalSteps -= _ySteps; + if (_yMoveTotalSteps <= 0) { + _isBraking = true; + _yMoveTotalSteps = 0; + } + } else { + int distance = calcDistance(_destX, _destY, _x, _y); + _x = newX; + _y = newY; + if (newX > 20 && newX < 620 && newY > 20 && newY < 460) { + _exitDirection = 0; + _inMainArea = true; + } else if (_inMainArea) { + _destX = pathPoint(_pathPoints->size() - 1).x; + _destY = pathPoint(_pathPoints->size() - 1).y; + _inMainArea = false; + if (_x <= 20) + _exitDirection = 1; + else if (_x >= 620) + _exitDirection = 3; + else if (_y <= 20) + _exitDirection = 2; + else if (_y >= 460) + _exitDirection = 4; + if (_exitDirection != 0 && _isBraking) { + _isBraking = false; + _steps = 11; + } + } + if ((distance < 20 && _exitDirection == 0 && _lastDistance < distance) || + (_exitDirection == 0 && _lastDistance + 20 < distance)) + _isBraking = true; + if (distance < _lastDistance) + _lastDistance = distance; + if (_currPointIndex == (int)_pathPoints->size() - 1) { + _isBraking = true; + _yMoveTotalSteps = 0; + sendMessage(this, 0x1019, 0); + sendMessage(_parentScene, 0x2006, 0); + } + } + +} + +void AsCommonCar::suMoveToPrevPoint() { + int16 newX = _x, newY = _y; + + if (_currPointIndex == 0 && _stepError == 0) { + _yMoveTotalSteps = 0; + sendMessage(this, 0x1019, 0); + sendMessage(_parentScene, 0x2005, 0); + return; + } + + if (_isBraking) { + if (_steps <= 0) { + sendMessage(this, 0x1019, 0); + return; + } else + _steps--; + } else if (_steps < 11) + _steps++; + + bool firstTime = true; + _ySteps = _steps; + int stepsCtr = _steps; + + while (stepsCtr > 0) { + if (_stepError == 0) + _currPointIndex--; + NPoint pt1; + NPoint pt2 = pathPoint(_currPointIndex); + if (_currPointIndex + 1 >= (int)_pathPoints->size()) + pt1 = pathPoint(0); + else + pt1 = pathPoint(_currPointIndex + 1); + int16 deltaX = ABS(pt1.x - pt2.x); + int16 deltaY = ABS(pt1.y - pt2.y); + if (deltaX >= deltaY) { + _newMoveDirection = 4; + if (pt1.x < pt2.x) + _newMoveDirection = 2; + if (_stepError == 0) + _stepError = deltaX; + if (stepsCtr > _stepError) { + stepsCtr -= _stepError; + _stepError = 0; + if (_currPointIndex == 0) + stepsCtr = 0; + newX = pathPoint(_currPointIndex).x; + newY = pathPoint(_currPointIndex).y; + } else { + _stepError -= stepsCtr; + if (pt1.x >= pt2.x) + newX -= stepsCtr; + else + newX += stepsCtr; + if (pt1.y >= pt2.y) + newY = pt2.y + (deltaY * _stepError) / deltaX; + else + newY = pt2.y - (deltaY * _stepError) / deltaX; + stepsCtr = 0; + } + } else { + _newMoveDirection = 1; + if (pt1.y < pt2.y) + _newMoveDirection = 3; + if (firstTime) { + if (pt1.y >= pt2.y) { + stepsCtr -= 4; + if (stepsCtr < 0) + stepsCtr = 0; + } else { + stepsCtr += 7; + } + _ySteps = stepsCtr; + } + if (_stepError == 0) + _stepError = deltaY; + if (stepsCtr > _stepError) { + stepsCtr -= _stepError; + _stepError = 0; + if (_currPointIndex == 0) + stepsCtr = 0; + newX = pathPoint(_currPointIndex).x; + newY = pathPoint(_currPointIndex).y; + } else { + _stepError -= stepsCtr; + if (pt1.x >= pt2.x) + newX = pt2.x + (deltaX * _stepError) / deltaY; + else + newX = pt2.x - (deltaX * _stepError) / deltaY; + if (pt1.y >= pt2.y) + newY -= stepsCtr; + else + newY += stepsCtr; + stepsCtr = 0; + } + } + firstTime = false; + } + + if (_yMoveTotalSteps != 0) { + _x = newX; + _y = newY; + _yMoveTotalSteps -= _ySteps; + if (_yMoveTotalSteps <= 0) { + _isBraking = true; + _yMoveTotalSteps = 0; + } + } else { + int distance = calcDistance(_destX, _destY, _x, _y); + _x = newX; + _y = newY; + if (newX > 20 && newX < 620 && newY > 20 && newY < 460) { + _exitDirection = 0; + _inMainArea = true; + } else if (_inMainArea) { + _destX = pathPoint(0).x; + _destY = pathPoint(0).y; + _inMainArea = false; + if (_x <= 20) + _exitDirection = 1; + else if (_x >= 620) + _exitDirection = 3; + else if (_y <= 20) + _exitDirection = 2; + else if (_y >= 460) + _exitDirection = 4; + if (_exitDirection != 0 && _isBraking) { + _isBraking = false; + _steps = 11; + } + } + if ((distance < 20 && _exitDirection == 0 && _lastDistance < distance) || + (_exitDirection == 0 && _lastDistance + 20 < distance)) + _isBraking = true; + if (distance < _lastDistance) + _lastDistance = distance; + if (_currPointIndex == 0 && _stepError == 0) { + _isBraking = true; + _yMoveTotalSteps = 0; + sendMessage(this, 0x1019, 0); + sendMessage(_parentScene, 0x2005, 0); + } + } + +} + +void AsCommonCar::updateSound() { + int maxSoundCounter = 0; + _soundCounter++; + if (_steps != 0 && !_isIdle) { + if (_currMoveDirection == 1) + maxSoundCounter = 18 - _steps; + else if (_currMoveDirection == 3) { + maxSoundCounter = 5 - _steps; + if (maxSoundCounter < 1) + maxSoundCounter = 1; + } else + maxSoundCounter = 14 - _steps; + } else + maxSoundCounter = 21; + if (_soundCounter >= maxSoundCounter) { + sendMessage(_parentScene, 0x200D, 0); + _soundCounter = 0; + } +} + +AsCommonIdleCarLower::AsCommonIdleCarLower(NeverhoodEngine *vm, int16 x, int16 y) + : AnimatedSprite(vm, 0x1209E09F, 1100, x, y) { + + setDoDeltaX(1); + startAnimation(0x1209E09F, 1, -1); + _newStickFrameIndex = 1; +} + +AsCommonIdleCarFull::AsCommonIdleCarFull(NeverhoodEngine *vm, int16 x, int16 y) + : AnimatedSprite(vm, 0x1209E09F, 100, x, y) { + + setDoDeltaX(1); + _newStickFrameIndex = 0; +} + +AsCommonCarConnector::AsCommonCarConnector(NeverhoodEngine *vm, AsCommonCar *asCar) + : AnimatedSprite(vm, 1100), _asCar(asCar) { + + createSurface1(0x60281C10, 150); + startAnimation(0x60281C10, -1, -1); + _newStickFrameIndex = STICK_LAST_FRAME; + SetUpdateHandler(&AsCommonCarConnector::update); +} + +void AsCommonCarConnector::update() { + _x = _asCar->getX(); + _y = _asCar->getY(); + AnimatedSprite::update(); +} + +void Tracks::findTrackPoint(NPoint pt, int &minMatchTrackIndex, int &minMatchDistance, + DataResource &dataResource) { + const uint trackCount = size(); + minMatchTrackIndex = -1; + minMatchDistance = 640; + for (uint trackIndex = 0; trackIndex < trackCount; trackIndex++) { + NPointArray *pointList = dataResource.getPointArray((*this)[trackIndex]->trackPointsName); + for (uint pointIndex = 0; pointIndex < pointList->size(); pointIndex++) { + NPoint testPt = (*pointList)[pointIndex]; + int distance = calcDistance(testPt.x, testPt.y, pt.x, pt.y); + if (distance < minMatchDistance) { + minMatchTrackIndex = trackIndex; + minMatchDistance = distance; + } + } + } +} + +KmScene1608::KmScene1608(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) + : Klaymen(vm, parentScene, x, y) { + + // Empty +} + +uint32 KmScene1608::xHandleMessage(int messageNum, const MessageParam ¶m) { + uint32 messageResult = 0; + switch (messageNum) { + case 0x2032: + _isSittingInTeleporter = param.asInteger() != 0; + messageResult = 1; + break; + case 0x4001: + case 0x4800: + startWalkToX(param.asPoint().x, false); + break; + case 0x4004: + if (_isSittingInTeleporter) + GotoState(&Klaymen::stSitIdleTeleporter); + else + GotoState(&Klaymen::stTryStandIdle); + break; + case 0x4812: + if (param.asInteger() == 2) + GotoState(&Klaymen::stPickUpNeedle); + else if (param.asInteger() == 1) + GotoState(&Klaymen::stPickUpTube); + else + GotoState(&Klaymen::stPickUpGeneric); + break; + case 0x4817: + setDoDeltaX(param.asInteger()); + gotoNextStateExt(); + break; + case 0x481B: + if (param.asPoint().y != 0) + startWalkToXDistance(param.asPoint().y, param.asPoint().x); + else + startWalkToAttachedSpriteXDistance(param.asPoint().x); + break; + case 0x481D: + if (_isSittingInTeleporter) + GotoState(&Klaymen::stTurnToUseInTeleporter); + break; + case 0x481E: + if (_isSittingInTeleporter) + GotoState(&Klaymen::stReturnFromUseInTeleporter); + break; + case 0x481F: + if (param.asInteger() == 1) + GotoState(&Klaymen::stWonderAboutAfter); + else if (param.asInteger() == 0) + GotoState(&Klaymen::stWonderAboutHalf); + else if (param.asInteger() == 4) + GotoState(&Klaymen::stTurnAwayFromUse); + else if (param.asInteger() == 3) + GotoState(&Klaymen::stTurnToUseHalf); + else + GotoState(&Klaymen::stWonderAbout); + break; + case 0x482D: + setDoDeltaX(_x > (int16)param.asInteger() ? 1 : 0); + gotoNextStateExt(); + break; + case 0x4834: + GotoState(&Klaymen::stStepOver); + break; + case 0x4835: + sendMessage(_parentScene, 0x2032, 1); + _isSittingInTeleporter = true; + GotoState(&Klaymen::stSitInTeleporter); + break; + case 0x4836: + sendMessage(_parentScene, 0x2032, 0); + _isSittingInTeleporter = false; + GotoState(&Klaymen::stGetUpFromTeleporter); + break; + case 0x483F: + startSpecialWalkRight(param.asInteger()); + break; + case 0x4840: + startSpecialWalkLeft(param.asInteger()); + break; + } + return messageResult; +} + +} // End of namespace Neverhood diff --git a/engines/neverhood/modules/module1600_sprites.h b/engines/neverhood/modules/module1600_sprites.h new file mode 100644 index 0000000000..fa59475dad --- /dev/null +++ b/engines/neverhood/modules/module1600_sprites.h @@ -0,0 +1,126 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef NEVERHOOD_MODULES_MODULE1600_SPRITES_H +#define NEVERHOOD_MODULES_MODULE1600_SPRITES_H + +#include "neverhood/neverhood.h" +#include "neverhood/module.h" +#include "neverhood/scene.h" + +namespace Neverhood { + +class AsCommonCar : public AnimatedSprite { +public: + AsCommonCar(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); + ~AsCommonCar(); + void setPathPoints(NPointArray *pathPoints); +protected: + Scene *_parentScene; + NPointArray *_pathPoints; + int _newMoveDirection; + int _currMoveDirection; + int _exitDirection; + int _currPointIndex; + bool _hasAgainDestPoint; + NPoint _againDestPoint; + bool _hasAgainDestPointIndex; + int _againDestPointIndex; + bool _inMainArea; + bool _isBraking; + bool _isBusy; + bool _isIdle; + bool _isMoving; + bool _rectFlag; + int _idleCounter; + int _idleCounterMax; + int _steps; + int _stepError; + int _lastDistance; + int _yMoveTotalSteps; + int _ySteps; + int _newDeltaXType; + int _soundCounter; + int _turnMoveStatus; + int16 _destX, _destY; + NPoint pathPoint(uint index) { return (*_pathPoints)[index]; } + void update(); + void upIdle(); + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); + uint32 hmAnimation(int messageNum, const MessageParam ¶m, Entity *sender); + uint32 hmLeaveCar(int messageNum, const MessageParam ¶m, Entity *sender); + void stCarAtHome(); + void updateTurnMovement(); + void updateMovement(); + void stEnterCar(); + void stLeaveCar(); + void stLeanForwardIdle(); + void evIdleDone(); + void stIdleBlink(); + void stUpdateMoveDirection(); + void stTurnCar(); + void moveToNextPoint(); + void stBrakeMoveToNextPoint(); + void stTurnCarMoveToNextPoint(); + void moveToPrevPoint(); + void stBrakeMoveToPrevPoint(); + void stTurnCarMoveToPrevPoint(); + void evTurnCarDone(); + void suMoveToNextPoint(); + void suMoveToPrevPoint(); + void updateSound(); +}; + +class AsCommonIdleCarLower : public AnimatedSprite { +public: + AsCommonIdleCarLower(NeverhoodEngine *vm, int16 x, int16 y); +}; + +class AsCommonIdleCarFull : public AnimatedSprite { +public: + AsCommonIdleCarFull(NeverhoodEngine *vm, int16 x, int16 y); +}; + +class AsCommonCarConnector : public AnimatedSprite { +public: + AsCommonCarConnector(NeverhoodEngine *vm, AsCommonCar *asCar); +protected: + AsCommonCar *_asCar; + void update(); +}; + +class Tracks : public Common::Array<TrackInfo*> { +public: + void findTrackPoint(NPoint pt, int &minMatchTrackIndex, int &minMatchDistance, + DataResource &dataResource); +}; + +class KmScene1608 : public Klaymen { +public: + KmScene1608(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); +protected: + uint32 xHandleMessage(int messageNum, const MessageParam ¶m); +}; + +} // End of namespace Neverhood + +#endif /* NEVERHOOD_MODULES_MODULE1600_SPRITES_H */ diff --git a/engines/neverhood/modules/module1700.cpp b/engines/neverhood/modules/module1700.cpp index 2aeae466ff..e3a5fc3663 100644 --- a/engines/neverhood/modules/module1700.cpp +++ b/engines/neverhood/modules/module1700.cpp @@ -20,8 +20,9 @@ * */ -#include "neverhood/modules/module1700.h" #include "neverhood/gamemodule.h" +#include "neverhood/modules/module1700.h" +#include "neverhood/modules/module1700_sprites.h" namespace Neverhood { @@ -126,8 +127,6 @@ void Module1700::updateScene() { } } -// Scene1705 - static const uint32 kScene1705FileHashes[] = { 0x910EA801, 0x920EA801, 0x940EA801, 0x980EA801, 0x800EA801, 0xB00EA801, @@ -135,47 +134,6 @@ static const uint32 kScene1705FileHashes[] = { 0xD10EA801, 0x110EA801, 0x910EA800 }; -SsScene1705WallSymbol::SsScene1705WallSymbol(NeverhoodEngine *vm, uint32 fileHash, int symbolIndex) - : StaticSprite(vm, fileHash, 100) { - - _x = _spriteResource.getPosition().x + symbolIndex * 30; - _y = _spriteResource.getPosition().y + 160; - updatePosition(); -} - -SsScene1705Tape::SsScene1705Tape(NeverhoodEngine *vm, Scene *parentScene, uint32 tapeIndex, int surfacePriority, int16 x, int16 y, uint32 fileHash) - : StaticSprite(vm, fileHash, surfacePriority, x - 24, y - 4), _parentScene(parentScene), _tapeIndex(tapeIndex) { - - if (!getSubVar(VA_HAS_TAPE, _tapeIndex) && !getSubVar(VA_IS_TAPE_INSERTED, _tapeIndex)) { - SetMessageHandler(&SsScene1705Tape::handleMessage); - } else { - setVisible(false); - SetMessageHandler(NULL); - } - _collisionBoundsOffset = _drawOffset; - _collisionBoundsOffset.x -= 4; - _collisionBoundsOffset.y -= 8; - _collisionBoundsOffset.width += 8; - _collisionBoundsOffset.height += 16; - Sprite::updateBounds(); -} - -uint32 SsScene1705Tape::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x1011: - sendMessage(_parentScene, 0x4826, 0); - messageResult = 1; - break; - case 0x4806: - setSubVar(VA_HAS_TAPE, _tapeIndex, 1); - setVisible(false); - SetMessageHandler(NULL); - break; - } - return messageResult; -} - Scene1705::Scene1705(NeverhoodEngine *vm, Module *parentModule, int which) : Scene(vm, parentModule), _paletteArea(1) { diff --git a/engines/neverhood/modules/module1700.h b/engines/neverhood/modules/module1700.h index deb5573f2b..09daff2acf 100644 --- a/engines/neverhood/modules/module1700.h +++ b/engines/neverhood/modules/module1700.h @@ -26,7 +26,6 @@ #include "neverhood/neverhood.h" #include "neverhood/module.h" #include "neverhood/scene.h" -#include "neverhood/smackerscene.h" namespace Neverhood { @@ -40,22 +39,6 @@ protected: void updateScene(); }; -// Scene1705 - -class SsScene1705WallSymbol : public StaticSprite { -public: - SsScene1705WallSymbol(NeverhoodEngine *vm, uint32 fileHash, int symbolIndex); -}; - -class SsScene1705Tape : public StaticSprite { -public: - SsScene1705Tape(NeverhoodEngine *vm, Scene *parentScene, uint32 tapeIndex, int surfacePriority, int16 x, int16 y, uint32 fileHash); -protected: - Scene *_parentScene; - uint32 _tapeIndex; - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); -}; - class Scene1705 : public Scene { public: Scene1705(NeverhoodEngine *vm, Module *parentModule, int which); diff --git a/engines/neverhood/modules/module1700_sprites.cpp b/engines/neverhood/modules/module1700_sprites.cpp new file mode 100644 index 0000000000..6274e5a8cc --- /dev/null +++ b/engines/neverhood/modules/module1700_sprites.cpp @@ -0,0 +1,156 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "neverhood/modules/module1700_sprites.h" + +namespace Neverhood { + +SsScene1705WallSymbol::SsScene1705WallSymbol(NeverhoodEngine *vm, uint32 fileHash, int symbolIndex) + : StaticSprite(vm, fileHash, 100) { + + _x = _spriteResource.getPosition().x + symbolIndex * 30; + _y = _spriteResource.getPosition().y + 160; + updatePosition(); +} + +SsScene1705Tape::SsScene1705Tape(NeverhoodEngine *vm, Scene *parentScene, uint32 tapeIndex, int surfacePriority, int16 x, int16 y, uint32 fileHash) + : StaticSprite(vm, fileHash, surfacePriority, x - 24, y - 4), _parentScene(parentScene), _tapeIndex(tapeIndex) { + + if (!getSubVar(VA_HAS_TAPE, _tapeIndex) && !getSubVar(VA_IS_TAPE_INSERTED, _tapeIndex)) { + SetMessageHandler(&SsScene1705Tape::handleMessage); + } else { + setVisible(false); + SetMessageHandler(NULL); + } + _collisionBoundsOffset = _drawOffset; + _collisionBoundsOffset.x -= 4; + _collisionBoundsOffset.y -= 8; + _collisionBoundsOffset.width += 8; + _collisionBoundsOffset.height += 16; + Sprite::updateBounds(); +} + +uint32 SsScene1705Tape::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x1011: + sendMessage(_parentScene, 0x4826, 0); + messageResult = 1; + break; + case 0x4806: + setSubVar(VA_HAS_TAPE, _tapeIndex, 1); + setVisible(false); + SetMessageHandler(NULL); + break; + } + return messageResult; +} + +KmScene1705::KmScene1705(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) + : Klaymen(vm, parentScene, x, y) { + + // Empty +} + +uint32 KmScene1705::xHandleMessage(int messageNum, const MessageParam ¶m) { + uint32 messageResult = 0; + switch (messageNum) { + case 0x2000: + _isSittingInTeleporter = param.asInteger() != 0; + messageResult = 1; + break; + case 0x4001: + case 0x4800: + startWalkToX(param.asPoint().x, false); + break; + case 0x4004: + if (_isSittingInTeleporter) + GotoState(&Klaymen::stSitIdleTeleporter); + else + GotoState(&Klaymen::stTryStandIdle); + break; + case 0x4803: + GotoState(&Klaymen::stFallSkipJump); + break; + case 0x4812: + if (param.asInteger() == 2) + GotoState(&Klaymen::stPickUpNeedle); + else if (param.asInteger() == 1) + GotoState(&Klaymen::stPickUpTube); + else + GotoState(&Klaymen::stPickUpGeneric); + break; + case 0x4817: + setDoDeltaX(param.asInteger()); + gotoNextStateExt(); + break; + case 0x481B: + if (param.asPoint().y != 0) + startWalkToXDistance(param.asPoint().y, param.asPoint().x); + else + startWalkToAttachedSpriteXDistance(param.asPoint().x); + break; + case 0x481D: + if (_isSittingInTeleporter) { + GotoState(&Klaymen::stTurnToUseInTeleporter); + } + break; + case 0x481E: + if (_isSittingInTeleporter) + GotoState(&Klaymen::stReturnFromUseInTeleporter); + break; + case 0x481F: + if (param.asInteger() == 1) + GotoState(&Klaymen::stWonderAboutAfter); + else if (param.asInteger() == 0) + GotoState(&Klaymen::stWonderAboutHalf); + else if (param.asInteger() == 4) + GotoState(&Klaymen::stTurnAwayFromUse); + else if (param.asInteger() == 3) + GotoState(&Klaymen::stTurnToUseHalf); + else + GotoState(&Klaymen::stWonderAbout); + break; + case 0x4834: + GotoState(&Klaymen::stStepOver); + break; + case 0x4835: + sendMessage(_parentScene, 0x2000, 1); + _isSittingInTeleporter = true; + GotoState(&Klaymen::stSitInTeleporter); + break; + case 0x4836: + sendMessage(_parentScene, 0x2000, 0); + _isSittingInTeleporter = false; + GotoState(&Klaymen::stGetUpFromTeleporter); + break; + case 0x483D: + teleporterAppear(0x5E0A4905); + break; + case 0x483E: + teleporterDisappear(0xD86E4477); + break; + } + return messageResult; +} + +} // End of namespace Neverhood diff --git a/engines/neverhood/modules/module1700_sprites.h b/engines/neverhood/modules/module1700_sprites.h new file mode 100644 index 0000000000..4117de01d9 --- /dev/null +++ b/engines/neverhood/modules/module1700_sprites.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 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef NEVERHOOD_MODULES_MODULE1700_SPRITES_H +#define NEVERHOOD_MODULES_MODULE1700_SPRITES_H + +#include "neverhood/neverhood.h" +#include "neverhood/module.h" +#include "neverhood/scene.h" + +namespace Neverhood { + +class SsScene1705WallSymbol : public StaticSprite { +public: + SsScene1705WallSymbol(NeverhoodEngine *vm, uint32 fileHash, int symbolIndex); +}; + +class SsScene1705Tape : public StaticSprite { +public: + SsScene1705Tape(NeverhoodEngine *vm, Scene *parentScene, uint32 tapeIndex, int surfacePriority, int16 x, int16 y, uint32 fileHash); +protected: + Scene *_parentScene; + uint32 _tapeIndex; + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); +}; + +class KmScene1705 : public Klaymen { +public: + KmScene1705(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); +protected: + uint32 xHandleMessage(int messageNum, const MessageParam ¶m); +}; + +} // End of namespace Neverhood + +#endif /* NEVERHOOD_MODULES_MODULE1700_SPRITES_H */ diff --git a/engines/neverhood/modules/module1800.cpp b/engines/neverhood/modules/module1800.cpp index b312678467..282292a516 100644 --- a/engines/neverhood/modules/module1800.cpp +++ b/engines/neverhood/modules/module1800.cpp @@ -20,9 +20,10 @@ * */ -#include "neverhood/modules/module1800.h" -#include "neverhood/navigationscene.h" +#include "neverhood/diskplayerscene.h" #include "neverhood/menumodule.h" +#include "neverhood/navigationscene.h" +#include "neverhood/modules/module1800.h" namespace Neverhood { diff --git a/engines/neverhood/modules/module1900.cpp b/engines/neverhood/modules/module1900.cpp index 29c20083f9..a920893755 100644 --- a/engines/neverhood/modules/module1900.cpp +++ b/engines/neverhood/modules/module1900.cpp @@ -21,7 +21,7 @@ */ #include "neverhood/modules/module1900.h" -#include "neverhood/gamemodule.h" +#include "neverhood/modules/module1900_sprites.h" namespace Neverhood { @@ -84,8 +84,6 @@ void Module1900::updateScene() { } } -// Scene1901 - Scene1901::Scene1901(NeverhoodEngine *vm, Module *parentModule, int which) : Scene(vm, parentModule) { @@ -126,395 +124,6 @@ Scene1901::Scene1901(NeverhoodEngine *vm, Module *parentModule, int which) } -static const NPoint kAsScene1907SymbolGroundPositions[] = { - {160, 310}, { 90, 340}, {210, 335}, - {210, 380}, {310, 340}, {290, 400}, - {400, 375}, {370, 435}, {475, 415} -}; - -static const NPoint kAsScene1907SymbolPluggedInPositions[] = { - {275, 125}, {244, 125}, {238, 131}, - {221, 135}, {199, 136}, {168, 149}, - {145, 152}, {123, 154}, {103, 157} -}; - -static const NPoint kAsScene1907SymbolGroundHitPositions[] = { - {275, 299}, {244, 299}, {238, 305}, - {221, 309}, {199, 310}, {168, 323}, - {145, 326}, {123, 328}, {103, 331} -}; - -static const NPoint kAsScene1907SymbolPluggedInDownPositions[] = { - {275, 136}, {244, 156}, {238, 183}, - {221, 207}, {199, 228}, {168, 262}, - {145, 285}, {123, 307}, {103, 331} -}; - -static const uint32 kAsScene1907SymbolFileHashes[] = { - 0x006A1034, 0x006A1010, 0x006A1814, - 0x006A1016, 0x006A0014, 0x002A1014, - 0x00EA1014, 0x206A1014, 0x046A1414 -}; - -bool AsScene1907Symbol::_plugInFailed = false; -int AsScene1907Symbol::_plugInTryCount = 0; - -AsScene1907Symbol::AsScene1907Symbol(NeverhoodEngine *vm, Scene1907 *parentScene, int elementIndex, int positionIndex) - : AnimatedSprite(vm, 1000 - positionIndex), _parentScene(parentScene), _elementIndex(elementIndex), _isMoving(false) { - - _plugInFailed = false; - _plugInTryCount = 0; - - if (getGlobalVar(V_STAIRS_PUZZLE_SOLVED)) { - _isPluggedIn = true; - _currPositionIndex = elementIndex; - if (!getGlobalVar(V_STAIRS_DOWN)) { - _x = kAsScene1907SymbolPluggedInPositions[_currPositionIndex].x; - _y = kAsScene1907SymbolPluggedInPositions[_currPositionIndex].y; - } else { - _x = kAsScene1907SymbolPluggedInDownPositions[_currPositionIndex].x; - _y = kAsScene1907SymbolPluggedInDownPositions[_currPositionIndex].y; - } - createSurface1(kAsScene1907SymbolFileHashes[_elementIndex], 1000 + _currPositionIndex); - startAnimation(kAsScene1907SymbolFileHashes[_elementIndex], -1, -1); - _newStickFrameIndex = STICK_LAST_FRAME; - } else { - _isPluggedIn = false; - _currPositionIndex = positionIndex; - loadSound(0, 0x74231924); - loadSound(1, 0x36691914); - loadSound(2, 0x5421D806); - _parentScene->setPositionFree(_currPositionIndex, false); - _x = kAsScene1907SymbolGroundPositions[_currPositionIndex].x; - _y = kAsScene1907SymbolGroundPositions[_currPositionIndex].y; - createSurface1(kAsScene1907SymbolFileHashes[_elementIndex], 1000 + _currPositionIndex); - startAnimation(kAsScene1907SymbolFileHashes[_elementIndex], 0, -1); - _newStickFrameIndex = 0; - } - _collisionBoundsOffset.set(0, 0, 80, 80); - Sprite::updateBounds(); - SetUpdateHandler(&AnimatedSprite::update); - SetMessageHandler(&AsScene1907Symbol::handleMessage); - -} - -void AsScene1907Symbol::update() { - updateAnim(); - handleSpriteUpdate(); - updatePosition(); - if (_plugInFailed && _plugInTryCount == 0) - _plugInFailed = false; -} - -uint32 AsScene1907Symbol::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x1011: - if (!_isPluggedIn && !_plugInFailed) { - tryToPlugIn(); - messageResult = 1; - } else - messageResult = 0; - break; - } - return messageResult; -} - -uint32 AsScene1907Symbol::hmTryToPlugIn(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x3002: - gotoNextState(); - break; - } - return messageResult; -} - -void AsScene1907Symbol::suTryToPlugIn() { - _currStep++; - _x -= _deltaX; - _y -= _deltaY; - if (_currStep == 16) { - _x -= _smallDeltaX; - _y -= _smallDeltaY; - SetSpriteUpdate(NULL); - } -} - -void AsScene1907Symbol::suFallOff() { - if (_fallOffDelay != 0) { - _fallOffDelay--; - } else { - _y += _yAccel; - _yAccel += 8; - if (_y >= kAsScene1907SymbolGroundHitPositions[_currPositionIndex].y) { - _y = kAsScene1907SymbolGroundHitPositions[_currPositionIndex].y; - stFallOffHitGround(); - } - } -} - -void AsScene1907Symbol::suFallOffHitGround() { - - if (_x == _someX - _xBreak) - _x -= _smallDeltaX; - else - _x -= _deltaX; - - if (_y == kAsScene1907SymbolGroundHitPositions[_currPositionIndex].y) { - _y -= _someY; - } - - if (_currStep < 8) { - _y -= _yAccel; - _yAccel -= 4; - if (_yAccel < 0) - _yAccel = 0; - } else if (_currStep < 15) { - _y += _yAccel; - _yAccel += 4; - } else { - _y = kAsScene1907SymbolGroundPositions[_newPositionIndex].y; - cbFallOffHitGroundEvent(); - } - - _currStep++; -} - -void AsScene1907Symbol::suMoveDown() { - _y += _yIncr; - if (_yIncr < 11) - _yIncr++; - if (_y >= kAsScene1907SymbolPluggedInDownPositions[_elementIndex].y) { - _y = kAsScene1907SymbolPluggedInDownPositions[_elementIndex].y; - _isMoving = false; - SetSpriteUpdate(NULL); - } -} - -void AsScene1907Symbol::suMoveUp() { - _y -= _yIncr; - if (getGlobalVar(V_WALL_BROKEN)) { - if (_y - (9 + (_elementIndex > 5 ? 31 : 0)) < kAsScene1907SymbolPluggedInPositions[_elementIndex].y) - _yIncr--; - else - _yIncr++; - } else - _yIncr = 2; - if (_yIncr > 9) - _yIncr = 9; - else if (_yIncr < 1) - _yIncr = 1; - if (_y < kAsScene1907SymbolPluggedInPositions[_elementIndex].y) { - _y = kAsScene1907SymbolPluggedInPositions[_elementIndex].y; - _isMoving = false; - SetSpriteUpdate(NULL); - } -} - -void AsScene1907Symbol::tryToPlugIn() { - _isPluggedIn = true; - _plugInTryCount++; - _newPositionIndex = _parentScene->getNextPosition(); - _parentScene->setPositionFree(_currPositionIndex, true); - sendMessage(_parentScene, 0x1022, 1100 + _newPositionIndex); - startAnimation(kAsScene1907SymbolFileHashes[_elementIndex], 0, -1); - SetUpdateHandler(&AsScene1907Symbol::update); - SetMessageHandler(&AsScene1907Symbol::hmTryToPlugIn); - SetSpriteUpdate(&AsScene1907Symbol::suTryToPlugIn); - _currStep = 0; - _deltaX = (_x - kAsScene1907SymbolPluggedInPositions[_newPositionIndex].x) / 16; - _smallDeltaX = _x - _deltaX * 16 - kAsScene1907SymbolPluggedInPositions[_newPositionIndex].x; - _deltaY = (_y - kAsScene1907SymbolPluggedInPositions[_newPositionIndex].y) / 16; - _smallDeltaY = _y - _deltaY * 16 - kAsScene1907SymbolPluggedInPositions[_newPositionIndex].y; - if (_elementIndex == _newPositionIndex) { - NextState(&AsScene1907Symbol::stPlugIn); - } else { - _plugInFailed = true; - NextState(&AsScene1907Symbol::stPlugInFail); - } -} - -void AsScene1907Symbol::fallOff(int newPositionIndex, int fallOffDelay) { - _isPluggedIn = false; - _newPositionIndex = newPositionIndex; - _fallOffDelay = fallOffDelay; - _parentScene->setPositionFree(_newPositionIndex, false); - _x = kAsScene1907SymbolPluggedInPositions[_currPositionIndex].x; - _y = kAsScene1907SymbolPluggedInPositions[_currPositionIndex].y; - _someX = _x; - _someY = _y; - startAnimation(kAsScene1907SymbolFileHashes[_elementIndex], -1, 0); - _playBackwards = true; - _newStickFrameIndex = STICK_LAST_FRAME; - _currStep = 0; - _yAccel = 1; - SetUpdateHandler(&AsScene1907Symbol::update); - SetMessageHandler(&AsScene1907Symbol::handleMessage); - SetSpriteUpdate(&AsScene1907Symbol::suFallOff); -} - -void AsScene1907Symbol::stFallOffHitGround() { - playSound(1); - sendMessage(_parentScene, 0x1022, 1000 + _newPositionIndex); - Entity::_priority = 1000 - _newPositionIndex; - _parentScene->removeCollisionSprite(this); - _parentScene->addCollisionSprite(this); - SetSpriteUpdate(&AsScene1907Symbol::suFallOffHitGround); - NextState(&AsScene1907Symbol::cbFallOffHitGroundEvent); - _newStickFrameIndex = 0; - _currStep = 0; - _yAccel = 30; - _deltaX = (_x - kAsScene1907SymbolGroundPositions[_newPositionIndex].x) / 15; - _xBreak = _deltaX * 15; - _smallDeltaX = _x - kAsScene1907SymbolGroundPositions[_newPositionIndex].x - _xBreak; - _someY = 0; - if (kAsScene1907SymbolGroundHitPositions[_currPositionIndex].y > kAsScene1907SymbolGroundPositions[_newPositionIndex].y) - _someY = kAsScene1907SymbolGroundHitPositions[_currPositionIndex].y - kAsScene1907SymbolGroundPositions[_newPositionIndex].y; -} - -void AsScene1907Symbol::cbFallOffHitGroundEvent() { - _currPositionIndex = _newPositionIndex; - if (_plugInTryCount > 0) - _plugInTryCount--; - startAnimation(kAsScene1907SymbolFileHashes[_elementIndex], 0, -1); - _newStickFrameIndex = 0; - SetUpdateHandler(&AnimatedSprite::update); - SetMessageHandler(&AsScene1907Symbol::handleMessage); - SetSpriteUpdate(NULL); - updateBounds(); - playSound(2); -} - -void AsScene1907Symbol::stPlugIn() { - playSound(0); - _currPositionIndex = _newPositionIndex; - stopAnimation(); - SetMessageHandler(&AsScene1907Symbol::handleMessage); - SetSpriteUpdate(NULL); - if (_elementIndex == 8) - sendMessage(_parentScene, 0x2001, 0); -} - -void AsScene1907Symbol::stPlugInFail() { - _currPositionIndex = _newPositionIndex; - stopAnimation(); - _parentScene->plugInFailed(); -} - -void AsScene1907Symbol::moveUp() { - startAnimation(kAsScene1907SymbolFileHashes[_elementIndex], -1, -1); - stopAnimation(); - SetMessageHandler(&AsScene1907Symbol::handleMessage); - SetSpriteUpdate(&AsScene1907Symbol::suMoveUp); - _yIncr = 1; - _isMoving = true; -} - -void AsScene1907Symbol::moveDown() { - startAnimation(kAsScene1907SymbolFileHashes[_elementIndex], -1, -1); - stopAnimation(); - SetMessageHandler(&AsScene1907Symbol::handleMessage); - SetSpriteUpdate(&AsScene1907Symbol::suMoveDown); - _yIncr = 4; - _isMoving = true; -} - -SsScene1907UpDownButton::SsScene1907UpDownButton(NeverhoodEngine *vm, Scene1907 *parentScene, AsScene1907Symbol *asScene1907Symbol) - : StaticSprite(vm, 1400), _parentScene(parentScene), _asScene1907Symbol(asScene1907Symbol), - _countdown1(0) { - - loadSprite(0x64516424, kSLFDefDrawOffset | kSLFDefPosition | kSLFDefCollisionBoundsOffset, 1400); - setVisible(false); - loadSound(0, 0x44061000); - SetUpdateHandler(&SsScene1907UpDownButton::update); - SetMessageHandler(&SsScene1907UpDownButton::handleMessage); - if (getGlobalVar(V_STAIRS_PUZZLE_SOLVED)) { - if (getGlobalVar(V_STAIRS_DOWN)) - setToDownPosition(); - else - setToUpPosition(); - } -} - -void SsScene1907UpDownButton::update() { - updatePosition(); - if (_countdown1 != 0 && (--_countdown1 == 0)) { - setVisible(false); - sendMessage(_parentScene, 0x2000, 0); - } -} - -uint32 SsScene1907UpDownButton::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x1011: - if (_countdown1 == 0 && !_asScene1907Symbol->isMoving() && getGlobalVar(V_STAIRS_PUZZLE_SOLVED)) { - setVisible(true); - _countdown1 = 4; - updatePosition(); - playSound(0); - } - messageResult = 1; - } - return messageResult; -} - -void SsScene1907UpDownButton::setToUpPosition() { - _y = _spriteResource.getPosition().y; - updateBounds(); - updatePosition(); -} - -void SsScene1907UpDownButton::setToDownPosition() { - _y = _spriteResource.getPosition().y + 174; - updateBounds(); - updatePosition(); -} - -AsScene1907WaterHint::AsScene1907WaterHint(NeverhoodEngine *vm) - : AnimatedSprite(vm, 1400) { - - createSurface1(0x110A1061, 1500); - _x = 320; - _y = 240; - startAnimation(0x110A1061, 0, -1); - _newStickFrameIndex = 0; - setVisible(false); - _needRefresh = true; - AnimatedSprite::updatePosition(); - SetUpdateHandler(&AsScene1907WaterHint::update); - SetMessageHandler(&Sprite::handleMessage); -} - -void AsScene1907WaterHint::update() { - updateAnim(); - updatePosition(); -} - -uint32 AsScene1907WaterHint::hmShowing(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x3002: - gotoNextState(); - break; - } - return messageResult; -} - -void AsScene1907WaterHint::show() { - setVisible(true); - startAnimation(0x110A1061, 0, -1); - SetMessageHandler(&AsScene1907WaterHint::hmShowing); - NextState(&AsScene1907WaterHint::hide); -} - -void AsScene1907WaterHint::hide() { - stopAnimation(); - setVisible(false); - SetMessageHandler(&Sprite::handleMessage); -} - Scene1907::Scene1907(NeverhoodEngine *vm, Module *parentModule) : Scene(vm, parentModule), _currMovingSymbolIndex(0), _pluggedInCount(0), _moveDownCountdown(0), _moveUpCountdown(0), _countdown3(0), _hasPlugInFailed(false) { diff --git a/engines/neverhood/modules/module1900.h b/engines/neverhood/modules/module1900.h index abb5eb1d87..d785c6f506 100644 --- a/engines/neverhood/modules/module1900.h +++ b/engines/neverhood/modules/module1900.h @@ -26,7 +26,6 @@ #include "neverhood/neverhood.h" #include "neverhood/module.h" #include "neverhood/scene.h" -#include "neverhood/modules/module1200.h" namespace Neverhood { @@ -41,80 +40,14 @@ protected: void updateScene(); }; -// Scene1901 - class Scene1901 : public Scene { public: Scene1901(NeverhoodEngine *vm, Module *parentModule, int which); }; -// Scene1907 - -class Scene1907; - -class AsScene1907Symbol : public AnimatedSprite { -public: - AsScene1907Symbol(NeverhoodEngine *vm, Scene1907 *parentScene, int elementIndex, int positionIndex); - void moveUp(); - void moveDown(); - void fallOff(int newPositionIndex, int fallOffDelay); - bool isPluggedIn() { return _isPluggedIn; } - bool isMoving() { return _isMoving; } -protected: - Scene1907 *_parentScene; - int _elementIndex; - int _currPositionIndex; - int _newPositionIndex; - bool _isPluggedIn; - bool _isMoving; - int _someX, _someY; - int _xBreak; - int _currStep; - int _yAccel; - int _yIncr; - int _fallOffDelay; - int _deltaX, _smallDeltaX; - int _deltaY, _smallDeltaY; - // Dumb, change if possible - static bool _plugInFailed; - static int _plugInTryCount; - void update(); - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); - uint32 hmTryToPlugIn(int messageNum, const MessageParam ¶m, Entity *sender); - void suTryToPlugIn(); - void suFallOff(); - void suFallOffHitGround(); - void suMoveDown(); - void suMoveUp(); - void tryToPlugIn(); - void stFallOffHitGround(); - void cbFallOffHitGroundEvent(); - void stPlugIn(); - void stPlugInFail(); -}; - -class AsScene1907WaterHint : public AnimatedSprite { -public: - AsScene1907WaterHint(NeverhoodEngine *vm); - void show(); -protected: - void update(); - uint32 hmShowing(int messageNum, const MessageParam ¶m, Entity *sender); - void hide(); -}; - -class SsScene1907UpDownButton : public StaticSprite { -public: - SsScene1907UpDownButton(NeverhoodEngine *vm, Scene1907 *parentScene, AsScene1907Symbol *asScene1907Symbol); - void setToUpPosition(); - void setToDownPosition(); -protected: - Scene1907 *_parentScene; - AsScene1907Symbol *_asScene1907Symbol; - int _countdown1; - void update(); - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); -}; +class AsScene1907Symbol; +class SsScene1907UpDownButton; +class AsScene1907WaterHint; class Scene1907 : public Scene { public: diff --git a/engines/neverhood/modules/module1900_sprites.cpp b/engines/neverhood/modules/module1900_sprites.cpp new file mode 100644 index 0000000000..09c0b132d5 --- /dev/null +++ b/engines/neverhood/modules/module1900_sprites.cpp @@ -0,0 +1,456 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "neverhood/modules/module1900.h" +#include "neverhood/modules/module1900_sprites.h" + +namespace Neverhood { + +static const NPoint kAsScene1907SymbolGroundPositions[] = { + {160, 310}, { 90, 340}, {210, 335}, + {210, 380}, {310, 340}, {290, 400}, + {400, 375}, {370, 435}, {475, 415} +}; + +static const NPoint kAsScene1907SymbolPluggedInPositions[] = { + {275, 125}, {244, 125}, {238, 131}, + {221, 135}, {199, 136}, {168, 149}, + {145, 152}, {123, 154}, {103, 157} +}; + +static const NPoint kAsScene1907SymbolGroundHitPositions[] = { + {275, 299}, {244, 299}, {238, 305}, + {221, 309}, {199, 310}, {168, 323}, + {145, 326}, {123, 328}, {103, 331} +}; + +static const NPoint kAsScene1907SymbolPluggedInDownPositions[] = { + {275, 136}, {244, 156}, {238, 183}, + {221, 207}, {199, 228}, {168, 262}, + {145, 285}, {123, 307}, {103, 331} +}; + +static const uint32 kAsScene1907SymbolFileHashes[] = { + 0x006A1034, 0x006A1010, 0x006A1814, + 0x006A1016, 0x006A0014, 0x002A1014, + 0x00EA1014, 0x206A1014, 0x046A1414 +}; + +bool AsScene1907Symbol::_plugInFailed = false; +int AsScene1907Symbol::_plugInTryCount = 0; + +AsScene1907Symbol::AsScene1907Symbol(NeverhoodEngine *vm, Scene1907 *parentScene, int elementIndex, int positionIndex) + : AnimatedSprite(vm, 1000 - positionIndex), _parentScene(parentScene), _elementIndex(elementIndex), _isMoving(false) { + + _plugInFailed = false; + _plugInTryCount = 0; + + if (getGlobalVar(V_STAIRS_PUZZLE_SOLVED)) { + _isPluggedIn = true; + _currPositionIndex = elementIndex; + if (!getGlobalVar(V_STAIRS_DOWN)) { + _x = kAsScene1907SymbolPluggedInPositions[_currPositionIndex].x; + _y = kAsScene1907SymbolPluggedInPositions[_currPositionIndex].y; + } else { + _x = kAsScene1907SymbolPluggedInDownPositions[_currPositionIndex].x; + _y = kAsScene1907SymbolPluggedInDownPositions[_currPositionIndex].y; + } + createSurface1(kAsScene1907SymbolFileHashes[_elementIndex], 1000 + _currPositionIndex); + startAnimation(kAsScene1907SymbolFileHashes[_elementIndex], -1, -1); + _newStickFrameIndex = STICK_LAST_FRAME; + } else { + _isPluggedIn = false; + _currPositionIndex = positionIndex; + loadSound(0, 0x74231924); + loadSound(1, 0x36691914); + loadSound(2, 0x5421D806); + _parentScene->setPositionFree(_currPositionIndex, false); + _x = kAsScene1907SymbolGroundPositions[_currPositionIndex].x; + _y = kAsScene1907SymbolGroundPositions[_currPositionIndex].y; + createSurface1(kAsScene1907SymbolFileHashes[_elementIndex], 1000 + _currPositionIndex); + startAnimation(kAsScene1907SymbolFileHashes[_elementIndex], 0, -1); + _newStickFrameIndex = 0; + } + _collisionBoundsOffset.set(0, 0, 80, 80); + Sprite::updateBounds(); + SetUpdateHandler(&AnimatedSprite::update); + SetMessageHandler(&AsScene1907Symbol::handleMessage); + +} + +void AsScene1907Symbol::update() { + updateAnim(); + handleSpriteUpdate(); + updatePosition(); + if (_plugInFailed && _plugInTryCount == 0) + _plugInFailed = false; +} + +uint32 AsScene1907Symbol::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x1011: + if (!_isPluggedIn && !_plugInFailed) { + tryToPlugIn(); + messageResult = 1; + } else + messageResult = 0; + break; + } + return messageResult; +} + +uint32 AsScene1907Symbol::hmTryToPlugIn(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x3002: + gotoNextState(); + break; + } + return messageResult; +} + +void AsScene1907Symbol::suTryToPlugIn() { + _currStep++; + _x -= _deltaX; + _y -= _deltaY; + if (_currStep == 16) { + _x -= _smallDeltaX; + _y -= _smallDeltaY; + SetSpriteUpdate(NULL); + } +} + +void AsScene1907Symbol::suFallOff() { + if (_fallOffDelay != 0) { + _fallOffDelay--; + } else { + _y += _yAccel; + _yAccel += 8; + if (_y >= kAsScene1907SymbolGroundHitPositions[_currPositionIndex].y) { + _y = kAsScene1907SymbolGroundHitPositions[_currPositionIndex].y; + stFallOffHitGround(); + } + } +} + +void AsScene1907Symbol::suFallOffHitGround() { + + if (_x == _someX - _xBreak) + _x -= _smallDeltaX; + else + _x -= _deltaX; + + if (_y == kAsScene1907SymbolGroundHitPositions[_currPositionIndex].y) { + _y -= _someY; + } + + if (_currStep < 8) { + _y -= _yAccel; + _yAccel -= 4; + if (_yAccel < 0) + _yAccel = 0; + } else if (_currStep < 15) { + _y += _yAccel; + _yAccel += 4; + } else { + _y = kAsScene1907SymbolGroundPositions[_newPositionIndex].y; + cbFallOffHitGroundEvent(); + } + + _currStep++; +} + +void AsScene1907Symbol::suMoveDown() { + _y += _yIncr; + if (_yIncr < 11) + _yIncr++; + if (_y >= kAsScene1907SymbolPluggedInDownPositions[_elementIndex].y) { + _y = kAsScene1907SymbolPluggedInDownPositions[_elementIndex].y; + _isMoving = false; + SetSpriteUpdate(NULL); + } +} + +void AsScene1907Symbol::suMoveUp() { + _y -= _yIncr; + if (getGlobalVar(V_WALL_BROKEN)) { + if (_y - (9 + (_elementIndex > 5 ? 31 : 0)) < kAsScene1907SymbolPluggedInPositions[_elementIndex].y) + _yIncr--; + else + _yIncr++; + } else + _yIncr = 2; + if (_yIncr > 9) + _yIncr = 9; + else if (_yIncr < 1) + _yIncr = 1; + if (_y < kAsScene1907SymbolPluggedInPositions[_elementIndex].y) { + _y = kAsScene1907SymbolPluggedInPositions[_elementIndex].y; + _isMoving = false; + SetSpriteUpdate(NULL); + } +} + +void AsScene1907Symbol::tryToPlugIn() { + _isPluggedIn = true; + _plugInTryCount++; + _newPositionIndex = _parentScene->getNextPosition(); + _parentScene->setPositionFree(_currPositionIndex, true); + sendMessage(_parentScene, 0x1022, 1100 + _newPositionIndex); + startAnimation(kAsScene1907SymbolFileHashes[_elementIndex], 0, -1); + SetUpdateHandler(&AsScene1907Symbol::update); + SetMessageHandler(&AsScene1907Symbol::hmTryToPlugIn); + SetSpriteUpdate(&AsScene1907Symbol::suTryToPlugIn); + _currStep = 0; + _deltaX = (_x - kAsScene1907SymbolPluggedInPositions[_newPositionIndex].x) / 16; + _smallDeltaX = _x - _deltaX * 16 - kAsScene1907SymbolPluggedInPositions[_newPositionIndex].x; + _deltaY = (_y - kAsScene1907SymbolPluggedInPositions[_newPositionIndex].y) / 16; + _smallDeltaY = _y - _deltaY * 16 - kAsScene1907SymbolPluggedInPositions[_newPositionIndex].y; + if (_elementIndex == _newPositionIndex) { + NextState(&AsScene1907Symbol::stPlugIn); + } else { + _plugInFailed = true; + NextState(&AsScene1907Symbol::stPlugInFail); + } +} + +void AsScene1907Symbol::fallOff(int newPositionIndex, int fallOffDelay) { + _isPluggedIn = false; + _newPositionIndex = newPositionIndex; + _fallOffDelay = fallOffDelay; + _parentScene->setPositionFree(_newPositionIndex, false); + _x = kAsScene1907SymbolPluggedInPositions[_currPositionIndex].x; + _y = kAsScene1907SymbolPluggedInPositions[_currPositionIndex].y; + _someX = _x; + _someY = _y; + startAnimation(kAsScene1907SymbolFileHashes[_elementIndex], -1, 0); + _playBackwards = true; + _newStickFrameIndex = STICK_LAST_FRAME; + _currStep = 0; + _yAccel = 1; + SetUpdateHandler(&AsScene1907Symbol::update); + SetMessageHandler(&AsScene1907Symbol::handleMessage); + SetSpriteUpdate(&AsScene1907Symbol::suFallOff); +} + +void AsScene1907Symbol::stFallOffHitGround() { + playSound(1); + sendMessage(_parentScene, 0x1022, 1000 + _newPositionIndex); + Entity::_priority = 1000 - _newPositionIndex; + _parentScene->removeCollisionSprite(this); + _parentScene->addCollisionSprite(this); + SetSpriteUpdate(&AsScene1907Symbol::suFallOffHitGround); + NextState(&AsScene1907Symbol::cbFallOffHitGroundEvent); + _newStickFrameIndex = 0; + _currStep = 0; + _yAccel = 30; + _deltaX = (_x - kAsScene1907SymbolGroundPositions[_newPositionIndex].x) / 15; + _xBreak = _deltaX * 15; + _smallDeltaX = _x - kAsScene1907SymbolGroundPositions[_newPositionIndex].x - _xBreak; + _someY = 0; + if (kAsScene1907SymbolGroundHitPositions[_currPositionIndex].y > kAsScene1907SymbolGroundPositions[_newPositionIndex].y) + _someY = kAsScene1907SymbolGroundHitPositions[_currPositionIndex].y - kAsScene1907SymbolGroundPositions[_newPositionIndex].y; +} + +void AsScene1907Symbol::cbFallOffHitGroundEvent() { + _currPositionIndex = _newPositionIndex; + if (_plugInTryCount > 0) + _plugInTryCount--; + startAnimation(kAsScene1907SymbolFileHashes[_elementIndex], 0, -1); + _newStickFrameIndex = 0; + SetUpdateHandler(&AnimatedSprite::update); + SetMessageHandler(&AsScene1907Symbol::handleMessage); + SetSpriteUpdate(NULL); + updateBounds(); + playSound(2); +} + +void AsScene1907Symbol::stPlugIn() { + playSound(0); + _currPositionIndex = _newPositionIndex; + stopAnimation(); + SetMessageHandler(&AsScene1907Symbol::handleMessage); + SetSpriteUpdate(NULL); + if (_elementIndex == 8) + sendMessage(_parentScene, 0x2001, 0); +} + +void AsScene1907Symbol::stPlugInFail() { + _currPositionIndex = _newPositionIndex; + stopAnimation(); + _parentScene->plugInFailed(); +} + +void AsScene1907Symbol::moveUp() { + startAnimation(kAsScene1907SymbolFileHashes[_elementIndex], -1, -1); + stopAnimation(); + SetMessageHandler(&AsScene1907Symbol::handleMessage); + SetSpriteUpdate(&AsScene1907Symbol::suMoveUp); + _yIncr = 1; + _isMoving = true; +} + +void AsScene1907Symbol::moveDown() { + startAnimation(kAsScene1907SymbolFileHashes[_elementIndex], -1, -1); + stopAnimation(); + SetMessageHandler(&AsScene1907Symbol::handleMessage); + SetSpriteUpdate(&AsScene1907Symbol::suMoveDown); + _yIncr = 4; + _isMoving = true; +} + +SsScene1907UpDownButton::SsScene1907UpDownButton(NeverhoodEngine *vm, Scene1907 *parentScene, AsScene1907Symbol *asScene1907Symbol) + : StaticSprite(vm, 1400), _parentScene(parentScene), _asScene1907Symbol(asScene1907Symbol), + _countdown1(0) { + + loadSprite(0x64516424, kSLFDefDrawOffset | kSLFDefPosition | kSLFDefCollisionBoundsOffset, 1400); + setVisible(false); + loadSound(0, 0x44061000); + SetUpdateHandler(&SsScene1907UpDownButton::update); + SetMessageHandler(&SsScene1907UpDownButton::handleMessage); + if (getGlobalVar(V_STAIRS_PUZZLE_SOLVED)) { + if (getGlobalVar(V_STAIRS_DOWN)) + setToDownPosition(); + else + setToUpPosition(); + } +} + +void SsScene1907UpDownButton::update() { + updatePosition(); + if (_countdown1 != 0 && (--_countdown1 == 0)) { + setVisible(false); + sendMessage(_parentScene, 0x2000, 0); + } +} + +uint32 SsScene1907UpDownButton::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x1011: + if (_countdown1 == 0 && !_asScene1907Symbol->isMoving() && getGlobalVar(V_STAIRS_PUZZLE_SOLVED)) { + setVisible(true); + _countdown1 = 4; + updatePosition(); + playSound(0); + } + messageResult = 1; + } + return messageResult; +} + +void SsScene1907UpDownButton::setToUpPosition() { + _y = _spriteResource.getPosition().y; + updateBounds(); + updatePosition(); +} + +void SsScene1907UpDownButton::setToDownPosition() { + _y = _spriteResource.getPosition().y + 174; + updateBounds(); + updatePosition(); +} + +AsScene1907WaterHint::AsScene1907WaterHint(NeverhoodEngine *vm) + : AnimatedSprite(vm, 1400) { + + createSurface1(0x110A1061, 1500); + _x = 320; + _y = 240; + startAnimation(0x110A1061, 0, -1); + _newStickFrameIndex = 0; + setVisible(false); + _needRefresh = true; + AnimatedSprite::updatePosition(); + SetUpdateHandler(&AsScene1907WaterHint::update); + SetMessageHandler(&Sprite::handleMessage); +} + +void AsScene1907WaterHint::update() { + updateAnim(); + updatePosition(); +} + +uint32 AsScene1907WaterHint::hmShowing(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x3002: + gotoNextState(); + break; + } + return messageResult; +} + +void AsScene1907WaterHint::show() { + setVisible(true); + startAnimation(0x110A1061, 0, -1); + SetMessageHandler(&AsScene1907WaterHint::hmShowing); + NextState(&AsScene1907WaterHint::hide); +} + +void AsScene1907WaterHint::hide() { + stopAnimation(); + setVisible(false); + SetMessageHandler(&Sprite::handleMessage); +} + +KmScene1901::KmScene1901(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) + : Klaymen(vm, parentScene, x, y) { + + // Empty +} + +uint32 KmScene1901::xHandleMessage(int messageNum, const MessageParam ¶m) { + switch (messageNum) { + case 0x4001: + case 0x4800: + startWalkToX(param.asPoint().x, false); + break; + case 0x4004: + GotoState(&Klaymen::stTryStandIdle); + break; + case 0x4817: + setDoDeltaX(param.asInteger()); + gotoNextStateExt(); + break; + case 0x481D: + GotoState(&Klaymen::stTurnToUse); + break; + case 0x481E: + GotoState(&Klaymen::stReturnFromUse); + break; + case 0x482D: + setDoDeltaX(_x > (int16)param.asInteger() ? 1 : 0); + gotoNextStateExt(); + break; + case 0x483F: + startSpecialWalkRight(param.asInteger()); + break; + case 0x4840: + startSpecialWalkLeft(param.asInteger()); + break; + } + return 0; +} + +} // End of namespace Neverhood diff --git a/engines/neverhood/modules/module1900_sprites.h b/engines/neverhood/modules/module1900_sprites.h new file mode 100644 index 0000000000..7e57b11618 --- /dev/null +++ b/engines/neverhood/modules/module1900_sprites.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 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef NEVERHOOD_MODULES_MODULE1900_SPRITES_H +#define NEVERHOOD_MODULES_MODULE1900_SPRITES_H + +#include "neverhood/neverhood.h" +#include "neverhood/module.h" +#include "neverhood/scene.h" + +namespace Neverhood { + +class Scene1907; + +class AsScene1907Symbol : public AnimatedSprite { +public: + AsScene1907Symbol(NeverhoodEngine *vm, Scene1907 *parentScene, int elementIndex, int positionIndex); + void moveUp(); + void moveDown(); + void fallOff(int newPositionIndex, int fallOffDelay); + bool isPluggedIn() { return _isPluggedIn; } + bool isMoving() { return _isMoving; } +protected: + Scene1907 *_parentScene; + int _elementIndex; + int _currPositionIndex; + int _newPositionIndex; + bool _isPluggedIn; + bool _isMoving; + int _someX, _someY; + int _xBreak; + int _currStep; + int _yAccel; + int _yIncr; + int _fallOffDelay; + int _deltaX, _smallDeltaX; + int _deltaY, _smallDeltaY; + // Dumb, change if possible + static bool _plugInFailed; + static int _plugInTryCount; + void update(); + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); + uint32 hmTryToPlugIn(int messageNum, const MessageParam ¶m, Entity *sender); + void suTryToPlugIn(); + void suFallOff(); + void suFallOffHitGround(); + void suMoveDown(); + void suMoveUp(); + void tryToPlugIn(); + void stFallOffHitGround(); + void cbFallOffHitGroundEvent(); + void stPlugIn(); + void stPlugInFail(); +}; + +class AsScene1907WaterHint : public AnimatedSprite { +public: + AsScene1907WaterHint(NeverhoodEngine *vm); + void show(); +protected: + void update(); + uint32 hmShowing(int messageNum, const MessageParam ¶m, Entity *sender); + void hide(); +}; + +class SsScene1907UpDownButton : public StaticSprite { +public: + SsScene1907UpDownButton(NeverhoodEngine *vm, Scene1907 *parentScene, AsScene1907Symbol *asScene1907Symbol); + void setToUpPosition(); + void setToDownPosition(); +protected: + Scene1907 *_parentScene; + AsScene1907Symbol *_asScene1907Symbol; + int _countdown1; + void update(); + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); +}; + +class KmScene1901 : public Klaymen { +public: + KmScene1901(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); +protected: + uint32 xHandleMessage(int messageNum, const MessageParam ¶m); +}; + +} // End of namespace Neverhood + +#endif /* NEVERHOOD_MODULES_MODULE1900_SPRITES_H */ diff --git a/engines/neverhood/modules/module2000.cpp b/engines/neverhood/modules/module2000.cpp index fcccdefbdd..3364f60f8b 100644 --- a/engines/neverhood/modules/module2000.cpp +++ b/engines/neverhood/modules/module2000.cpp @@ -21,8 +21,7 @@ */ #include "neverhood/modules/module2000.h" -#include "neverhood/gamemodule.h" -#include "neverhood/navigationscene.h" +#include "neverhood/modules/module2000_sprites.h" namespace Neverhood { diff --git a/engines/neverhood/modules/module2000.h b/engines/neverhood/modules/module2000.h index fa62f9a70e..8dc72c57dc 100644 --- a/engines/neverhood/modules/module2000.h +++ b/engines/neverhood/modules/module2000.h @@ -26,7 +26,6 @@ #include "neverhood/neverhood.h" #include "neverhood/module.h" #include "neverhood/scene.h" -#include "neverhood/modules/module1200.h" namespace Neverhood { @@ -41,8 +40,6 @@ protected: void updateScene(); }; -// Scene2001 - class Scene2001 : public Scene { public: Scene2001(NeverhoodEngine *vm, Module *parentModule, int which); diff --git a/engines/neverhood/modules/module2000_sprites.cpp b/engines/neverhood/modules/module2000_sprites.cpp new file mode 100644 index 0000000000..c9c1481aa7 --- /dev/null +++ b/engines/neverhood/modules/module2000_sprites.cpp @@ -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 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "neverhood/modules/module2000_sprites.h" + +namespace Neverhood { + +KmScene2001::KmScene2001(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) + : Klaymen(vm, parentScene, x, y) { + + // Empty +} + +uint32 KmScene2001::xHandleMessage(int messageNum, const MessageParam ¶m) { + uint32 messageResult = 0; + switch (messageNum) { + case 0x2000: + _isSittingInTeleporter = param.asInteger() != 0; + messageResult = 1; + break; + case 0x4001: + case 0x4800: + startWalkToX(param.asPoint().x, false); + break; + case 0x4004: + if (_isSittingInTeleporter) + GotoState(&Klaymen::stSitIdleTeleporter); + else + GotoState(&Klaymen::stTryStandIdle); + break; + case 0x4804: + if (param.asInteger() != 0) { + _destX = param.asInteger(); + GotoState(&Klaymen::stWalkingFirst); + } else + GotoState(&Klaymen::stPeekWall); + break; + case 0x4817: + setDoDeltaX(param.asInteger()); + gotoNextStateExt(); + break; + case 0x481D: + if (_isSittingInTeleporter) + GotoState(&Klaymen::stTurnToUseInTeleporter); + break; + case 0x481E: + if (_isSittingInTeleporter) + GotoState(&Klaymen::stReturnFromUseInTeleporter); + break; + case 0x4834: + GotoState(&Klaymen::stStepOver); + break; + case 0x4835: + sendMessage(_parentScene, 0x2000, 1); + _isSittingInTeleporter = true; + GotoState(&Klaymen::stSitInTeleporter); + break; + case 0x4836: + sendMessage(_parentScene, 0x2000, 0); + _isSittingInTeleporter = false; + GotoState(&Klaymen::stGetUpFromTeleporter); + break; + case 0x483D: + teleporterAppear(0xBE68CC54); + break; + case 0x483E: + teleporterDisappear(0x18AB4ED4); + break; + } + return messageResult; +} + +} // End of namespace Neverhood diff --git a/engines/neverhood/modules/module2000_sprites.h b/engines/neverhood/modules/module2000_sprites.h new file mode 100644 index 0000000000..ca84aa73ca --- /dev/null +++ b/engines/neverhood/modules/module2000_sprites.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 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef NEVERHOOD_MODULES_MODULE2000_SPRITES_H +#define NEVERHOOD_MODULES_MODULE2000_SPRITES_H + +#include "neverhood/neverhood.h" +#include "neverhood/module.h" +#include "neverhood/scene.h" + +namespace Neverhood { + +class KmScene2001 : public Klaymen { +public: + KmScene2001(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); +protected: + uint32 xHandleMessage(int messageNum, const MessageParam ¶m); +}; + +} // End of namespace Neverhood + +#endif /* NEVERHOOD_MODULES_MODULE2000_SPRITES_H */ diff --git a/engines/neverhood/modules/module2100.cpp b/engines/neverhood/modules/module2100.cpp index bcff9d9d1b..db7258b066 100644 --- a/engines/neverhood/modules/module2100.cpp +++ b/engines/neverhood/modules/module2100.cpp @@ -20,9 +20,9 @@ * */ +#include "neverhood/modules/module1200_sprites.h" #include "neverhood/modules/module2100.h" -#include "neverhood/gamemodule.h" -#include "neverhood/modules/module1200.h" +#include "neverhood/modules/module2100_sprites.h" namespace Neverhood { @@ -74,125 +74,6 @@ void Module2100::updateScene() { } } -// Scene2101 - -AsScene2101Door::AsScene2101Door(NeverhoodEngine *vm, bool isOpen) - : AnimatedSprite(vm, 1100) { - - createSurface(100, 328, 347); - _x = 320; - _y = 240; - SetUpdateHandler(&AnimatedSprite::update); - SetMessageHandler(&AsScene2101Door::handleMessage); - if (isOpen) { - startAnimation(0x0C202B9C, -1, -1); - _newStickFrameIndex = STICK_LAST_FRAME; - } else - setVisible(false); -} - -uint32 AsScene2101Door::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x3002: - gotoNextState(); - break; - case 0x4808: - stOpenDoor(); - break; - case 0x4809: - stCloseDoor(); - break; - } - return messageResult; -} - -void AsScene2101Door::stOpenDoor() { - startAnimation(0x0C202B9C, 0, -1); - _newStickFrameIndex = STICK_LAST_FRAME; - setVisible(true); - playSound(0, calcHash("fxDoorOpen32")); -} - -void AsScene2101Door::stCloseDoor() { - startAnimation(0xC222A8D4, 0, -1); - _newStickFrameIndex = STICK_LAST_FRAME; - setVisible(true); - playSound(0, calcHash("fxDoorClose32")); - NextState(&AsScene2101Door::stCloseDoorDone); -} - -void AsScene2101Door::stCloseDoorDone() { - stopAnimation(); - setVisible(false); -} - -AsScene2101HitByDoorEffect::AsScene2101HitByDoorEffect(NeverhoodEngine *vm, Sprite *klaymen) - : AnimatedSprite(vm, 1400), _klaymen(klaymen) { - - SetUpdateHandler(&AnimatedSprite::update); - SetMessageHandler(&AsScene2101HitByDoorEffect::handleMessage); - createSurface(1200, 88, 165); - setVisible(false); -} - -uint32 AsScene2101HitByDoorEffect::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x2001: - _x = _klaymen->getX(); - _y = _klaymen->getY() - 132; - startAnimation(0x0422255A, 0, -1); - setVisible(true); - break; - case 0x3002: - stopAnimation(); - setVisible(false); - break; - } - return messageResult; -} - -SsCommonFloorButton::SsCommonFloorButton(NeverhoodEngine *vm, Scene *parentScene, uint32 fileHash1, uint32 fileHash2, int surfacePriority, uint32 soundFileHash) - : StaticSprite(vm, 1100), _parentScene(parentScene), _countdown(0), - _fileHash1(fileHash1), _fileHash2(fileHash2), _soundFileHash(soundFileHash) { - - SetUpdateHandler(&SsCommonFloorButton::update); - SetMessageHandler(&SsCommonFloorButton::handleMessage); - if (_soundFileHash == 0) - _soundFileHash = 0x44141000; - createSurface(1010, 61, 30); - if (_fileHash1) - loadSprite(_fileHash1, kSLFDefDrawOffset | kSLFDefPosition); - else - setVisible(false); -} - -void SsCommonFloorButton::update() { - if (_countdown != 0 && (--_countdown == 0)) { - sendMessage(_parentScene, 0x1022, 1010); - if (_fileHash1) - loadSprite(_fileHash1, kSLFDefDrawOffset | kSLFDefPosition); - else - setVisible(false); - } -} - -uint32 SsCommonFloorButton::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x480B: - sendMessage(_parentScene, 0x480B, 0); - setVisible(true); - sendMessage(_parentScene, 0x1022, 990); - loadSprite(_fileHash2, kSLFDefDrawOffset | kSLFDefPosition); - _countdown = 16; - playSound(0, _soundFileHash); - break; - } - return messageResult; -} - Scene2101::Scene2101(NeverhoodEngine *vm, Module *parentModule, int which) : Scene(vm, parentModule) { diff --git a/engines/neverhood/modules/module2100.h b/engines/neverhood/modules/module2100.h index d76bed0780..c5256434d9 100644 --- a/engines/neverhood/modules/module2100.h +++ b/engines/neverhood/modules/module2100.h @@ -40,38 +40,6 @@ protected: void updateScene(); }; -// Scene1901 - -class AsScene2101Door : public AnimatedSprite { -public: - AsScene2101Door(NeverhoodEngine *vm, bool isOpen); -protected: - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); - void stOpenDoor(); - void stCloseDoor(); - void stCloseDoorDone(); -}; - -class AsScene2101HitByDoorEffect : public AnimatedSprite { -public: - AsScene2101HitByDoorEffect(NeverhoodEngine *vm, Sprite *klaymen); -protected: - Sprite *_klaymen; - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); -}; - -class SsCommonFloorButton : public StaticSprite { -public: - SsCommonFloorButton(NeverhoodEngine *vm, Scene *parentScene, uint32 fileHash1, uint32 fileHash2, int surfacePriority, uint32 soundFileHash); -protected: - Scene *_parentScene; - uint32 _soundFileHash; - uint32 _fileHash1, _fileHash2; - int16 _countdown; - void update(); - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); -}; - class Scene2101 : public Scene { public: Scene2101(NeverhoodEngine *vm, Module *parentModule, int which); diff --git a/engines/neverhood/modules/module2100_sprites.cpp b/engines/neverhood/modules/module2100_sprites.cpp new file mode 100644 index 0000000000..707ebe342f --- /dev/null +++ b/engines/neverhood/modules/module2100_sprites.cpp @@ -0,0 +1,260 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "neverhood/modules/module2100_sprites.h" + +namespace Neverhood { + +AsScene2101Door::AsScene2101Door(NeverhoodEngine *vm, bool isOpen) + : AnimatedSprite(vm, 1100) { + + createSurface(100, 328, 347); + _x = 320; + _y = 240; + SetUpdateHandler(&AnimatedSprite::update); + SetMessageHandler(&AsScene2101Door::handleMessage); + if (isOpen) { + startAnimation(0x0C202B9C, -1, -1); + _newStickFrameIndex = STICK_LAST_FRAME; + } else + setVisible(false); +} + +uint32 AsScene2101Door::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x3002: + gotoNextState(); + break; + case 0x4808: + stOpenDoor(); + break; + case 0x4809: + stCloseDoor(); + break; + } + return messageResult; +} + +void AsScene2101Door::stOpenDoor() { + startAnimation(0x0C202B9C, 0, -1); + _newStickFrameIndex = STICK_LAST_FRAME; + setVisible(true); + playSound(0, calcHash("fxDoorOpen32")); +} + +void AsScene2101Door::stCloseDoor() { + startAnimation(0xC222A8D4, 0, -1); + _newStickFrameIndex = STICK_LAST_FRAME; + setVisible(true); + playSound(0, calcHash("fxDoorClose32")); + NextState(&AsScene2101Door::stCloseDoorDone); +} + +void AsScene2101Door::stCloseDoorDone() { + stopAnimation(); + setVisible(false); +} + +AsScene2101HitByDoorEffect::AsScene2101HitByDoorEffect(NeverhoodEngine *vm, Sprite *klaymen) + : AnimatedSprite(vm, 1400), _klaymen(klaymen) { + + SetUpdateHandler(&AnimatedSprite::update); + SetMessageHandler(&AsScene2101HitByDoorEffect::handleMessage); + createSurface(1200, 88, 165); + setVisible(false); +} + +uint32 AsScene2101HitByDoorEffect::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x2001: + _x = _klaymen->getX(); + _y = _klaymen->getY() - 132; + startAnimation(0x0422255A, 0, -1); + setVisible(true); + break; + case 0x3002: + stopAnimation(); + setVisible(false); + break; + } + return messageResult; +} + +SsCommonFloorButton::SsCommonFloorButton(NeverhoodEngine *vm, Scene *parentScene, uint32 fileHash1, uint32 fileHash2, int surfacePriority, uint32 soundFileHash) + : StaticSprite(vm, 1100), _parentScene(parentScene), _countdown(0), + _fileHash1(fileHash1), _fileHash2(fileHash2), _soundFileHash(soundFileHash) { + + SetUpdateHandler(&SsCommonFloorButton::update); + SetMessageHandler(&SsCommonFloorButton::handleMessage); + if (_soundFileHash == 0) + _soundFileHash = 0x44141000; + createSurface(1010, 61, 30); + if (_fileHash1) + loadSprite(_fileHash1, kSLFDefDrawOffset | kSLFDefPosition); + else + setVisible(false); +} + +void SsCommonFloorButton::update() { + if (_countdown != 0 && (--_countdown == 0)) { + sendMessage(_parentScene, 0x1022, 1010); + if (_fileHash1) + loadSprite(_fileHash1, kSLFDefDrawOffset | kSLFDefPosition); + else + setVisible(false); + } +} + +uint32 SsCommonFloorButton::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x480B: + sendMessage(_parentScene, 0x480B, 0); + setVisible(true); + sendMessage(_parentScene, 0x1022, 990); + loadSprite(_fileHash2, kSLFDefDrawOffset | kSLFDefPosition); + _countdown = 16; + playSound(0, _soundFileHash); + break; + } + return messageResult; +} + +KmScene2101::KmScene2101(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) + : Klaymen(vm, parentScene, x, y) { + + // Empty +} + +uint32 KmScene2101::xHandleMessage(int messageNum, const MessageParam ¶m) { + uint32 messageResult = 0; + switch (messageNum) { + case 0x2000: + _isSittingInTeleporter = param.asInteger() != 0; + messageResult = 1; + break; + case 0x4001: + case 0x4800: + startWalkToX(param.asPoint().x, false); + break; + case 0x4004: + if (_isSittingInTeleporter) + GotoState(&Klaymen::stSitIdleTeleporter); + else + GotoState(&Klaymen::stTryStandIdle); + break; + case 0x4811: + GotoState(&KmScene2101::stHitByDoor); + break; + case 0x4812: + if (param.asInteger() == 2) + GotoState(&Klaymen::stPickUpNeedle); + else if (param.asInteger() == 1) + GotoState(&Klaymen::stPickUpTube); + else + GotoState(&Klaymen::stPickUpGeneric); + break; + case 0x4816: + if (param.asInteger() == 1) + GotoState(&Klaymen::stPressButton); + else if (param.asInteger() == 2) + GotoState(&Klaymen::stPressFloorButton); + else + GotoState(&Klaymen::stPressButtonSide); + break; + case 0x4817: + setDoDeltaX(param.asInteger()); + gotoNextStateExt(); + break; + case 0x481B: + if (param.asPoint().y != 0) + startWalkToXDistance(param.asPoint().y, param.asPoint().x); + else + startWalkToAttachedSpriteXDistance(param.asPoint().x); + break; + case 0x481D: + if (_isSittingInTeleporter) + GotoState(&Klaymen::stTurnToUseInTeleporter); + break; + case 0x481E: + if (_isSittingInTeleporter) + GotoState(&Klaymen::stReturnFromUseInTeleporter); + break; + case 0x4834: + GotoState(&Klaymen::stStepOver); + break; + case 0x4835: + sendMessage(_parentScene, 0x2000, 1); + _isSittingInTeleporter = true; + GotoState(&Klaymen::stSitInTeleporter); + break; + case 0x4836: + sendMessage(_parentScene, 0x2000, 0); + _isSittingInTeleporter = false; + GotoState(&Klaymen::stGetUpFromTeleporter); + break; + case 0x483D: + teleporterAppear(0xFF290E30); + break; + case 0x483E: + teleporterDisappear(0x9A28CA1C); + break; + } + return messageResult; +} + +uint32 KmScene2101::hmHitByDoor(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = hmLowLevelAnimation(messageNum, param, sender); + int16 speedUpFrameIndex; + switch (messageNum) { + case 0x1008: + speedUpFrameIndex = getFrameIndex(kKlaymenSpeedUpHash); + if (_currFrameIndex < speedUpFrameIndex) { + startAnimation(0x35AA8059, speedUpFrameIndex, -1); + _y = 438; + } + messageResult = 0; + break; + case 0x100D: + if (param.asInteger() == 0x1A1A0785) { + playSound(0, 0x40F0A342); + } else if (param.asInteger() == 0x60428026) { + playSound(0, 0x40608A59); + } + break; + } + return messageResult; +} + +void KmScene2101::stHitByDoor() { + _busyStatus = 1; + _acceptInput = false; + startAnimation(0x35AA8059, 0, -1); + SetUpdateHandler(&Klaymen::update); + SetMessageHandler(&KmScene2101::hmHitByDoor); + SetSpriteUpdate(&AnimatedSprite::updateDeltaXY); + playSound(0, 0x402E82D4); +} + +} // End of namespace Neverhood diff --git a/engines/neverhood/modules/module2100_sprites.h b/engines/neverhood/modules/module2100_sprites.h new file mode 100644 index 0000000000..85a6b9f27d --- /dev/null +++ b/engines/neverhood/modules/module2100_sprites.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 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef NEVERHOOD_MODULES_MODULE2100_SPRITES_H +#define NEVERHOOD_MODULES_MODULE2100_SPRITES_H + +#include "neverhood/neverhood.h" +#include "neverhood/module.h" +#include "neverhood/scene.h" + +namespace Neverhood { + +class AsScene2101Door : public AnimatedSprite { +public: + AsScene2101Door(NeverhoodEngine *vm, bool isOpen); +protected: + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); + void stOpenDoor(); + void stCloseDoor(); + void stCloseDoorDone(); +}; + +class AsScene2101HitByDoorEffect : public AnimatedSprite { +public: + AsScene2101HitByDoorEffect(NeverhoodEngine *vm, Sprite *klaymen); +protected: + Sprite *_klaymen; + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); +}; + +class SsCommonFloorButton : public StaticSprite { +public: + SsCommonFloorButton(NeverhoodEngine *vm, Scene *parentScene, uint32 fileHash1, uint32 fileHash2, int surfacePriority, uint32 soundFileHash); +protected: + Scene *_parentScene; + uint32 _soundFileHash; + uint32 _fileHash1, _fileHash2; + int16 _countdown; + void update(); + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); +}; + +class KmScene2101 : public Klaymen { +public: + KmScene2101(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); + + void stHitByDoor(); + uint32 hmHitByDoor(int messageNum, const MessageParam ¶m, Entity *sender); + +protected: + uint32 xHandleMessage(int messageNum, const MessageParam ¶m); +}; + +} // End of namespace Neverhood + +#endif /* NEVERHOOD_MODULES_MODULE2100_SPRITES_H */ diff --git a/engines/neverhood/modules/module2200.cpp b/engines/neverhood/modules/module2200.cpp index 99f21cad74..745af42f72 100644 --- a/engines/neverhood/modules/module2200.cpp +++ b/engines/neverhood/modules/module2200.cpp @@ -20,11 +20,12 @@ * */ -#include "neverhood/modules/module2200.h" -#include "neverhood/modules/module1000.h" -#include "neverhood/modules/module1200.h" -#include "neverhood/gamemodule.h" #include "neverhood/diskplayerscene.h" +#include "neverhood/gamemodule.h" +#include "neverhood/modules/module1000_sprites.h" +#include "neverhood/modules/module1200_sprites.h" +#include "neverhood/modules/module2200.h" +#include "neverhood/modules/module2200_sprites.h" namespace Neverhood { @@ -445,95 +446,6 @@ void Module2200::createHallOfRecordsScene(int which, uint32 hallOfRecordsInfoId) _childObject = new HallOfRecordsScene(_vm, this, which, hallOfRecordsInfoId); } -// Scene2201 - -AsScene2201CeilingFan::AsScene2201CeilingFan(NeverhoodEngine *vm) - : AnimatedSprite(vm, 1100) { - - _x = 403; - _y = 259; - createSurface(100, 233, 96); - startAnimation(0x8600866, 0, -1); - SetUpdateHandler(&AnimatedSprite::update); -} - -AsScene2201Door::AsScene2201Door(NeverhoodEngine *vm, Klaymen *klaymen, Sprite *ssDoorLight, bool isOpen) - : AnimatedSprite(vm, 1100), _klaymen(klaymen), _ssDoorLight(ssDoorLight), _countdown(0), _isOpen(isOpen) { - - _x = 408; - _y = 290; - createSurface(900, 63, 266); - SetUpdateHandler(&AsScene2201Door::update); - SetMessageHandler(&AsScene2201Door::handleMessage); - if (_isOpen) { - startAnimation(0xE2CB0412, -1, -1); - _countdown = 48; - _newStickFrameIndex = STICK_LAST_FRAME; - } else { - startAnimation(0xE2CB0412, 0, -1); - _newStickFrameIndex = 0; - _ssDoorLight->setVisible(false); - } -} - -void AsScene2201Door::update() { - if (_countdown != 0 && _isOpen && (--_countdown == 0)) - stCloseDoor(); - AnimatedSprite::update(); -} - -uint32 AsScene2201Door::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x100D: - if (param.asInteger() == 0x11001090) { - if (_isOpen) - _ssDoorLight->setVisible(true); - } else if (param.asInteger() == 0x11283090) { - if (!_isOpen) - _ssDoorLight->setVisible(false); - } - break; - case 0x2000: - if (_isOpen) - _countdown = 144; - messageResult = _isOpen ? 1 : 0; - break; - case 0x3002: - gotoNextState(); - break; - case 0x4808: - _countdown = 144; - if (!_isOpen) - stOpenDoor(); - break; - } - return messageResult; -} - -void AsScene2201Door::stOpenDoor() { - _isOpen = true; - startAnimation(0xE2CB0412, 0, -1); - _newStickFrameIndex = STICK_LAST_FRAME; - playSound(0, calcHash("fxDoorOpen33")); -} - -void AsScene2201Door::stCloseDoor() { - _isOpen = false; - startAnimation(0xE2CB0412, -1, -1); - _playBackwards = true; - _newStickFrameIndex = 0; - playSound(0, calcHash("fxDoorClose33")); -} - -SsScene2201PuzzleCube::SsScene2201PuzzleCube(NeverhoodEngine *vm, uint32 positionIndex, uint32 cubeIndex) - : StaticSprite(vm, 900) { - - createSurface(100, 16, 16); - loadSprite(kSsScene2201PuzzleCubeFileHashes[cubeIndex], kSLFCenteredDrawOffset | kSLFSetPosition, 0, - kSsScene2201PuzzleCubePoints[positionIndex].x, kSsScene2201PuzzleCubePoints[positionIndex].y); -} - Scene2201::Scene2201(NeverhoodEngine *vm, Module *parentModule, int which) : Scene(vm, parentModule), _isSoundPlaying(false) { @@ -661,215 +573,6 @@ uint32 Scene2201::handleMessage(int messageNum, const MessageParam ¶m, Entit return 0; } -static const NPoint kSsScene2202PuzzleCubePoints[] = { - {196, 105}, {323, 102}, {445, 106}, - {192, 216}, {319, 220}, {446, 216}, - {188, 320}, {319, 319}, {443, 322} -}; - -static const uint32 kSsScene2202PuzzleCubeFileHashes1[] = { - 0xA500800C, 0x2182910C, 0x2323980C, - 0x23049084, 0x21008080, 0x2303900C, - 0x6120980C, 0x2504D808 -}; - -static const uint32 kSsScene2202PuzzleCubeFileHashes2[] = { - 0x0AAD8080, 0x0A290291, 0x0A2BA398, - 0x822B8490, 0x86298080, 0x0A2B8390, - 0x0A69A098, 0x0E2D84D8 -}; - -SsScene2202PuzzleCube::SsScene2202PuzzleCube(NeverhoodEngine *vm, Scene *parentScene, int16 cubePosition, int16 cubeSymbol) - : StaticSprite(vm, 900), _parentScene(parentScene), _cubeSymbol(cubeSymbol), _cubePosition(cubePosition), _isMoving(false) { - - int surfacePriority; - - SetUpdateHandler(&SsScene2202PuzzleCube::update); - SetMessageHandler(&SsScene2202PuzzleCube::handleMessage); - if (_cubePosition >= 0 && _cubePosition <= 2) - surfacePriority = 100; - else if (_cubePosition >= 3 && _cubePosition <= 5) - surfacePriority = 300; - else - surfacePriority = 500; - debug(1, "TODO: Unused SurfacePriority: %d", surfacePriority); - loadSprite(kSsScene2202PuzzleCubeFileHashes2[_cubeSymbol], kSLFCenteredDrawOffset | kSLFSetPosition | kSLFDefCollisionBoundsOffset, 0, - kSsScene2202PuzzleCubePoints[_cubePosition].x, kSsScene2202PuzzleCubePoints[_cubePosition].y); - loadSound(0, 0x40958621); - loadSound(1, 0x51108241); -} - -void SsScene2202PuzzleCube::update() { - handleSpriteUpdate(); - updatePosition(); -} - -uint32 SsScene2202PuzzleCube::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x1011: - if (!_isMoving && !getGlobalVar(V_TILE_PUZZLE_SOLVED)) - sendMessage(_parentScene, 0x2000, _cubePosition); - messageResult = 1; - break; - case 0x2001: - _isMoving = true; - moveCube(param.asInteger()); - break; - } - return messageResult; -} - -void SsScene2202PuzzleCube::suMoveCubeX() { - - bool done = false; - - if (_counterDirection) { - if (_counter > 2) - _counter -= 2; - } else { - if (_counter < 20) - _counter += 2; - } - - for (int16 i = 0; i < _counter; i++) { - _x += _xIncr; - _errValue += _yDelta; - if (_errValue >= _xDelta) { - _errValue -= _xDelta; - _y += _yIncr; - } - if (_x == _newX && _y == _newY) { - done = true; - break; - } - if (_x == _xFlagPos) - _counterDirection = true; - } - - if (done) - stopMoving(); - - updateBounds(); - -} - -void SsScene2202PuzzleCube::suMoveCubeY() { - - bool done = false; - - if (_counterDirection) { - if (_counter > 2) - _counter -= 2; - } else { - if (_counter < 20) - _counter += 2; - } - - for (int16 i = 0; i < _counter; i++) { - _y += _yIncr; - _errValue += _xDelta; - if (_errValue >= _yDelta) { - _errValue -= _yDelta; - _x += _xIncr; - } - if (_x == _newX && _y == _newY) { - done = true; - break; - } - if (_x == _xFlagPos) - _counterDirection = true; - } - - if (done) - stopMoving(); - - updateBounds(); - -} - -void SsScene2202PuzzleCube::moveCube(int16 newCubePosition) { - - loadSprite(kSsScene2202PuzzleCubeFileHashes1[_cubeSymbol], kSLFCenteredDrawOffset); - - setSubVar(VA_CUBE_POSITIONS, _cubePosition, (uint32)-1); - setSubVar(VA_CUBE_POSITIONS, newCubePosition, (uint32)_cubeSymbol); - - _cubePosition = newCubePosition; - _errValue = 0; - _counterDirection = false; - _counter = 0; - _newX = kSsScene2202PuzzleCubePoints[newCubePosition].x; - _newY = kSsScene2202PuzzleCubePoints[newCubePosition].y; - - if (_x == _newX && _y == _newY) - return; - - if (_x <= _newX) { - if (_y <= _newY) { - _xDelta = _newX - _x; - _yDelta = _newY - _y; - _xIncr = 1; - _yIncr = 1; - } else { - _xDelta = _newX - _x; - _yDelta = _y - _newY; - _xIncr = 1; - _yIncr = -1; - } - } else { - if (_y <= _newY) { - _xDelta = _x - _newX; - _yDelta = _newY - _y; - _xIncr = -1; - _yIncr = 1; - } else { - _xDelta = _x - _newX; - _yDelta = _y - _newY; - _xIncr = -1; - _yIncr = -1; - } - } - - if (_xDelta > _yDelta) { - SetSpriteUpdate(&SsScene2202PuzzleCube::suMoveCubeX); - if (_xIncr > 0) { - if (_newX - _x >= 180) - _xFlagPos = _newX - 90; - else - _xFlagPos = _x + _newX / 2; - } else { - if (_x - _newX >= 180) - _xFlagPos = _x + 90; - else - _xFlagPos = _x / 2 + _newX; - } - playSound(0); - } else { - SetSpriteUpdate(&SsScene2202PuzzleCube::suMoveCubeY); - if (_yIncr > 0) { - if (_newY - _y >= 180) - _xFlagPos = _newY - 90; - else - _xFlagPos = _y + _newY / 2; - } else { - if (_y - _newY >= 180) - _xFlagPos = _y + 90; - else - _xFlagPos = _y / 2 + _newY; - } - playSound(1); - } - -} - -void SsScene2202PuzzleCube::stopMoving() { - loadSprite(kSsScene2202PuzzleCubeFileHashes2[_cubeSymbol], kSLFCenteredDrawOffset); - SetSpriteUpdate(NULL); - _isMoving = false; - sendMessage(_parentScene, 0x2002, _cubePosition); -} - Scene2202::Scene2202(NeverhoodEngine *vm, Module *parentModule, int which) : Scene(vm, parentModule), _isSolved(false), _leaveScene(false), _isCubeMoving(false), _ssMovingCube(NULL), _ssDoneMovingCube(NULL) { @@ -991,100 +694,6 @@ bool Scene2202::testIsSolved() { getSubVar(VA_CUBE_POSITIONS, 8) == 7; } -static const uint32 kAsCommonKeyFileHashes[] = { - 0x2450D850, 0x0C9CE8D0, 0x2C58A152 -}; - -AsCommonKey::AsCommonKey(NeverhoodEngine *vm, Scene *parentScene, int keyIndex, int surfacePriority, int16 x, int16 y) - : AnimatedSprite(vm, kAsCommonKeyFileHashes[keyIndex], surfacePriority, x, y), _parentScene(parentScene), _keyIndex(keyIndex) { - - if (!getSubVar(VA_HAS_KEY, _keyIndex) && !getSubVar(VA_IS_KEY_INSERTED, _keyIndex)) { - SetMessageHandler(&AsCommonKey::handleMessage); - } else { - // If Klaymen already has the key or it's already inserted then don't show it - setVisible(false); - SetMessageHandler(NULL); - } -} - -uint32 AsCommonKey::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x1011: - sendMessage(_parentScene, 0x4826, 0); - messageResult = 1; - break; - case 0x4806: - setSubVar(VA_HAS_KEY, _keyIndex, 1); - setVisible(false); - SetMessageHandler(NULL); - } - return messageResult; -} - -static const uint32 kAsScene2203DoorFileHashes[] = { - 0x7868AE10, 0x1A488110 -}; - -AsScene2203Door::AsScene2203Door(NeverhoodEngine *vm, Scene *parentScene, uint doorIndex) - : AnimatedSprite(vm, 1100), _parentScene(parentScene), _doorIndex(doorIndex) { - - SetUpdateHandler(&AnimatedSprite::update); - SetMessageHandler(&AsScene2203Door::handleMessage); - _x = 320; - _y = 240; - createSurface1(kAsScene2203DoorFileHashes[_doorIndex], 900); - if (getGlobalVar(V_LARGE_DOOR_NUMBER) == _doorIndex) { - startAnimation(kAsScene2203DoorFileHashes[_doorIndex], -1, -1); - _newStickFrameIndex = STICK_LAST_FRAME; - } else { - startAnimation(kAsScene2203DoorFileHashes[_doorIndex], 0, -1); - _newStickFrameIndex = 0; - } -} - -uint32 AsScene2203Door::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x1011: - if (_doorIndex == getGlobalVar(V_LARGE_DOOR_NUMBER)) - sendMessage(_parentScene, 0x2002, 0); - else - sendMessage(_parentScene, 0x2001, 0); - messageResult = 1; - break; - case 0x2000: - _otherDoor = (Sprite*)param.asEntity(); - break; - case 0x3002: - if (_doorIndex == getGlobalVar(V_LARGE_DOOR_NUMBER)) - sendMessage(_parentScene, 0x4808, 0); - stopAnimation(); - break; - case 0x4808: - setGlobalVar(V_LARGE_DOOR_NUMBER, _doorIndex); - sendMessage(_otherDoor, 0x4809, 0); - openDoor(); - break; - case 0x4809: - closeDoor(); - sendMessage(_parentScene, 0x2003, 0); - break; - } - return messageResult; -} - -void AsScene2203Door::openDoor() { - playSound(0, 0x341014C4); - startAnimation(kAsScene2203DoorFileHashes[_doorIndex], 1, -1); -} - -void AsScene2203Door::closeDoor() { - startAnimation(kAsScene2203DoorFileHashes[_doorIndex], -1, -1); - _playBackwards = true; - _newStickFrameIndex = 0; -} - Scene2203::Scene2203(NeverhoodEngine *vm, Module *parentModule, int which) : Scene(vm, parentModule) { @@ -1197,24 +806,6 @@ uint32 Scene2203::handleMessage(int messageNum, const MessageParam ¶m, Entit return messageResult; } -SsScene2205DoorFrame::SsScene2205DoorFrame(NeverhoodEngine *vm) - : StaticSprite(vm, 900) { - - SetMessageHandler(&SsScene2205DoorFrame::handleMessage); - createSurface(1100, 45, 206); - loadSprite(getGlobalVar(V_LIGHTS_ON) ? 0x24306227 : 0xD90032A0, kSLFDefDrawOffset | kSLFDefPosition); -} - -uint32 SsScene2205DoorFrame::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x2000: - loadSprite(getGlobalVar(V_LIGHTS_ON) ? 0x24306227 : 0xD90032A0, kSLFDefDrawOffset | kSLFDefPosition); - break; - } - return messageResult; -} - Scene2205::Scene2205(NeverhoodEngine *vm, Module *parentModule, int which) : Scene(vm, parentModule) { @@ -1325,134 +916,6 @@ static const int16 kScene2206XPositions[] = { 384, 480, 572 }; -static const uint32 kScene2206MessageIds1[] = { - 0x004B8998, 0x004B89B8, 0x004B89D8 -}; - -static const uint32 kScene2206MessageIds2[] = { - 0x004B89F8, 0x004B8A20, 0x004B8A48 -}; - -static const int16 kAsScene2206DoorSpikesXDeltasOpen[] = { - -24, -28, -18, 6, 9, -8 -}; - -static const int16 kAsScene2206DoorSpikesXDeltasClose[] = { - -8, 7, 11, 26, 13, 14 -}; - -AsScene2206DoorSpikes::AsScene2206DoorSpikes(NeverhoodEngine *vm, uint32 fileHash) - : StaticSprite(vm, fileHash, 200) { - - if (getGlobalVar(V_SPIKES_RETRACTED)) - _x -= 63; - SetUpdateHandler(&AsScene2206DoorSpikes::update); - SetMessageHandler(&AsScene2206DoorSpikes::handleMessage); - SetSpriteUpdate(NULL); -} - -void AsScene2206DoorSpikes::update() { - handleSpriteUpdate(); - updatePosition(); -} - -uint32 AsScene2206DoorSpikes::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x4808: - _deltaIndex = 0; - playSound(0, 0x032746E0); - SetMessageHandler(NULL); - SetSpriteUpdate(&AsScene2206DoorSpikes::suOpen); - break; - case 0x4809: - _deltaIndex = 0; - playSound(0, 0x002642C0); - SetMessageHandler(NULL); - SetSpriteUpdate(&AsScene2206DoorSpikes::suClose); - break; - } - return messageResult; -} - -void AsScene2206DoorSpikes::suOpen() { - if (_deltaIndex < 6) { - _x += kAsScene2206DoorSpikesXDeltasOpen[_deltaIndex]; - _deltaIndex++; - } else { - SetMessageHandler(&AsScene2206DoorSpikes::handleMessage); - SetSpriteUpdate(NULL); - } -} - -void AsScene2206DoorSpikes::suClose() { - if (_deltaIndex < 6) { - _x += kAsScene2206DoorSpikesXDeltasClose[_deltaIndex]; - _deltaIndex++; - } else { - SetMessageHandler(&AsScene2206DoorSpikes::handleMessage); - SetSpriteUpdate(NULL); - } -} - -AsScene2206Platform::AsScene2206Platform(NeverhoodEngine *vm, uint32 fileHash) - : StaticSprite(vm, fileHash, 50) { - - SetUpdateHandler(&AsScene2206Platform::update); - SetMessageHandler(&AsScene2206Platform::handleMessage); - SetSpriteUpdate(NULL); -} - -void AsScene2206Platform::update() { - handleSpriteUpdate(); - updatePosition(); -} - -uint32 AsScene2206Platform::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x4803: - _yDelta = 0; - SetMessageHandler(NULL); - SetSpriteUpdate(&AsScene2206Platform::suMoveDown); - break; - } - return messageResult; -} - -void AsScene2206Platform::suMoveDown() { - _yDelta++; - _y += _yDelta; -} - -SsScene2206TestTube::SsScene2206TestTube(NeverhoodEngine *vm, Scene *parentScene, int surfacePriority, uint32 fileHash) - : StaticSprite(vm, fileHash, surfacePriority), _parentScene(parentScene) { - - if (getGlobalVar(V_HAS_TEST_TUBE)) { - setVisible(false); - SetMessageHandler(NULL); - } else - SetMessageHandler(&SsScene2206TestTube::handleMessage); - _collisionBoundsOffset = _drawOffset; - updateBounds(); -} - -uint32 SsScene2206TestTube::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x1011: - sendMessage(_parentScene, 0x4826, 0); - messageResult = 1; - break; - case 0x4806: - setGlobalVar(V_HAS_TEST_TUBE, 1); - setVisible(false); - SetMessageHandler(NULL); - break; - } - return messageResult; -} - Scene2206::Scene2206(NeverhoodEngine *vm, Module *parentModule, int which) : Scene(vm, parentModule) { @@ -1597,6 +1060,14 @@ void Scene2206::klaymenBehindSpikes() { _klaymen->setClipRect(_sprite2->getDrawRect().x, 0, _sprite3->getDrawRect().x2(), _sprite1->getDrawRect().y2()); } +static const uint32 kScene2206MessageIds1[] = { + 0x004B8998, 0x004B89B8, 0x004B89D8 +}; + +static const uint32 kScene2206MessageIds2[] = { + 0x004B89F8, 0x004B8A20, 0x004B8A48 +}; + void Scene2206::readClickedColumn() { setGlobalVar(V_CLICKED_COLUMN_INDEX, (_mouseClickPos.x - 354) / 96); if (getGlobalVar(V_CLICKED_COLUMN_INDEX) > 2) @@ -1617,317 +1088,6 @@ static const uint32 kScene2207FileHashes[] = { 0x3BB1E12E, 0x23B1E12E, 0x13B1E12E }; -AsScene2207Elevator::AsScene2207Elevator(NeverhoodEngine *vm, Scene *parentScene) - : AnimatedSprite(vm, 900), _parentScene(parentScene), _pointIndex(0), _destPointIndex(0), _destPointIndexDelta(0) { - - NPoint pt; - - _dataResource.load(0x00524846); - _pointArray = _dataResource.getPointArray(0x005B02B7); - pt = _dataResource.getPoint(0x403A82B1); - _x = pt.x; - _y = pt.y; - createSurface(1100, 129, 103); - startAnimation(getGlobalVar(V_LIGHTS_ON) ? 0xC858CC19 : 0x294B3377, 0, 0); - _newStickFrameIndex = 0; - SetUpdateHandler(&AsScene2207Elevator::update); - SetMessageHandler(&AsScene2207Elevator::handleMessage); - SetSpriteUpdate(&AsScene2207Elevator::suSetPosition); -} - -AsScene2207Elevator::~AsScene2207Elevator() { - _vm->_soundMan->deleteSoundGroup(0x02700413); -} - -void AsScene2207Elevator::update() { - - if (_destPointIndex + _destPointIndexDelta > _pointIndex) { - _pointIndex++; - startAnimation(getGlobalVar(V_LIGHTS_ON) ? 0xC858CC19 : 0x294B3377, _pointIndex, _pointIndex); - _newStickFrameIndex = _pointIndex; - if (_destPointIndex + _destPointIndexDelta == _pointIndex) { - if (_destPointIndexDelta != 0) - _destPointIndexDelta = 0; - else { - _vm->_soundMan->deleteSound(0xD3B02847); - playSound(0, 0x53B8284A); - } - } - } - - if (_destPointIndex + _destPointIndexDelta < _pointIndex) { - _pointIndex--; - if (_pointIndex == 0) - sendMessage(_parentScene, 0x2003, 0); - startAnimation(getGlobalVar(V_LIGHTS_ON) ? 0xC858CC19 : 0x294B3377, _pointIndex, _pointIndex); - _newStickFrameIndex = _pointIndex; - if (_destPointIndex + _destPointIndexDelta == _pointIndex) { - if (_destPointIndexDelta != 0) - _destPointIndexDelta = 0; - else { - _vm->_soundMan->deleteSound(0xD3B02847); - playSound(0, 0x53B8284A); - } - } - } - - if (_pointIndex > 20 && _surface->getPriority() != 900) - sendMessage(_parentScene, 0x2002, 900); - else if (_pointIndex < 20 && _surface->getPriority() != 1100) - sendMessage(_parentScene, 0x2002, 1100); - - AnimatedSprite::update(); - - if (_destPointIndex + _destPointIndexDelta == _pointIndex && _isMoving) { - sendMessage(_parentScene, 0x2004, 0); - _isMoving = false; - } - -} - -void AsScene2207Elevator::suSetPosition() { - _x = (*_pointArray)[_pointIndex].x; - _y = (*_pointArray)[_pointIndex].y - 60; - updateBounds(); -} - -uint32 AsScene2207Elevator::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x2000: - moveToY(param.asInteger()); - break; - } - return messageResult; -} - -void AsScene2207Elevator::moveToY(int16 y) { - int16 minDistance = 480; - - if (!_pointArray || _pointArray->size() == 0) - return; - - for (uint i = 0; i < _pointArray->size(); i++) { - int16 distance = ABS(y - (*_pointArray)[i].y); - if (distance < minDistance) { - minDistance = distance; - _destPointIndex = i; - } - } - - if (_destPointIndex != _pointIndex) { - if (_destPointIndex == 0 || _destPointIndex == (int)_pointArray->size() - 1) - _destPointIndexDelta = 0; - else if (_destPointIndex < _pointIndex) - _destPointIndexDelta = -2; - else - _destPointIndexDelta = 2; - _vm->_soundMan->addSound(0x02700413, 0xD3B02847); - _vm->_soundMan->playSoundLooping(0xD3B02847); - } - - _isMoving = true; - -} - -AsScene2207Lever::AsScene2207Lever(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y, int doDeltaX) - : AnimatedSprite(vm, 1100), _parentScene(parentScene) { - - _x = x; - _y = y; - createSurface(1010, 71, 73); - setDoDeltaX(doDeltaX); - startAnimation(0x80880090, 0, -1); - _newStickFrameIndex = 0; - SetUpdateHandler(&AnimatedSprite::update); - SetMessageHandler(&AsScene2207Lever::handleMessage); -} - -uint32 AsScene2207Lever::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x1011: - sendMessage(_parentScene, 0x4826, 0); - messageResult = 1; - break; - case 0x3002: - gotoNextState(); - stopAnimation(); - break; - case 0x4807: - stLeverUp(); - break; - case 0x480F: - stLeverDown(); - break; - case 0x482A: - sendMessage(_parentScene, 0x1022, 990); - break; - case 0x482B: - sendMessage(_parentScene, 0x1022, 1010); - break; - } - return messageResult; -} - -void AsScene2207Lever::stLeverDown() { - startAnimation(0x80880090, 1, -1); - playSound(0, 0x40581882); - FinalizeState(&AsScene2207Lever::stLeverDownEvent); -} - -void AsScene2207Lever::stLeverDownEvent() { - sendMessage(_parentScene, 0x480F, 0); -} - -void AsScene2207Lever::stLeverUp() { - startAnimation(0x80880090, 6, -1); - _playBackwards = true; - playSound(0, 0x40581882); - FinalizeState(&AsScene2207Lever::stLeverUpEvent); -} - -void AsScene2207Lever::stLeverUpEvent() { - sendMessage(_parentScene, 0x4807, 0); -} - -AsScene2207WallRobotAnimation::AsScene2207WallRobotAnimation(NeverhoodEngine *vm, Scene *parentScene) - : AnimatedSprite(vm, 1200), _idle(true) { - - _x = 309; - _y = 320; - createSurface1(0xCCFD6090, 100); - startAnimation(0xCCFD6090, 0, -1); - _newStickFrameIndex = 0; - loadSound(1, 0x40330872); - loadSound(2, 0x72A2914A); - loadSound(3, 0xD4226080); - SetUpdateHandler(&AnimatedSprite::update); - SetMessageHandler(&AsScene2207WallRobotAnimation::handleMessage); -} - -AsScene2207WallRobotAnimation::~AsScene2207WallRobotAnimation() { - _vm->_soundMan->deleteSoundGroup(0x80D00820); -} - -uint32 AsScene2207WallRobotAnimation::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x100D: - if (!_idle) { - if (param.asInteger() == 0x3423093) { - _vm->_soundMan->addSound(0x80D00820, 0x12121943); - _vm->_soundMan->playSoundLooping(0x12121943); - } else if (param.asInteger() == 0x834AB011) { - stopSound(0); - stopSound(1); - stopSound(2); - stopSound(3); - _vm->_soundMan->deleteSound(0x12121943); - } else if (param.asInteger() == 0x3A980501) - playSound(1); - else if (param.asInteger() == 0x2A2AD498) - playSound(2); - else if (param.asInteger() == 0xC4980008) - playSound(3); - else if (param.asInteger() == 0x06B84228) - playSound(0, 0xE0702146); - } - break; - case 0x2006: - stStartAnimation(); - break; - case 0x2007: - stStopAnimation(); - break; - case 0x3002: - gotoNextState(); - break; - } - return messageResult; -} - -void AsScene2207WallRobotAnimation::stStartAnimation() { - if (!_idle) { - NextState(NULL); - } else { - startAnimation(0xCCFD6090, 0, -1); - _idle = false; - setVisible(true); - } -} - -void AsScene2207WallRobotAnimation::stStopAnimation() { - NextState(&AsScene2207WallRobotAnimation::cbStopAnimation); -} - -void AsScene2207WallRobotAnimation::cbStopAnimation() { - stopAnimation(); - stopSound(0); - stopSound(1); - stopSound(2); - stopSound(3); - _vm->_soundMan->deleteSound(0x12121943); - _idle = true; - setVisible(false); -} - -AsScene2207WallCannonAnimation::AsScene2207WallCannonAnimation(NeverhoodEngine *vm) - : AnimatedSprite(vm, 1200), _idle(true) { - - _x = 309; - _y = 320; - createSurface1(0x8CAA0099, 100); - startAnimation(0x8CAA0099, 0, -1); - _newStickFrameIndex = 0; - SetUpdateHandler(&AnimatedSprite::update); - SetMessageHandler(&AsScene2207WallCannonAnimation::handleMessage); -} - -uint32 AsScene2207WallCannonAnimation::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x2006: - stStartAnimation(); - break; - case 0x2007: - stStopAnimation(); - break; - case 0x3002: - gotoNextState(); - break; - } - return messageResult; -} - -void AsScene2207WallCannonAnimation::stStartAnimation() { - if (!_idle) { - NextState(NULL); - } else { - setVisible(true); - startAnimation(0x8CAA0099, 0, -1); - _idle = false; - } -} - -void AsScene2207WallCannonAnimation::stStopAnimation() { - NextState(&AsScene2207WallCannonAnimation::cbStopAnimation); -} - -void AsScene2207WallCannonAnimation::cbStopAnimation() { - stopAnimation(); - setVisible(false); - _idle = true; -} - -SsScene2207Symbol::SsScene2207Symbol(NeverhoodEngine *vm, uint32 fileHash, int index) - : StaticSprite(vm, fileHash, 100) { - - _x = 330; - _y = 246 + index * 50; - updatePosition(); -} - Scene2207::Scene2207(NeverhoodEngine *vm, Module *parentModule) : Scene(vm, parentModule), _klaymenAtElevator(true), _elevatorSurfacePriority(0) { diff --git a/engines/neverhood/modules/module2200.h b/engines/neverhood/modules/module2200.h index 5c19f2a818..6b414304ae 100644 --- a/engines/neverhood/modules/module2200.h +++ b/engines/neverhood/modules/module2200.h @@ -31,8 +31,6 @@ namespace Neverhood { -// Module2200 - class Module2200 : public Module { public: Module2200(NeverhoodEngine *vm, Module *parentModule, int which); @@ -44,43 +42,6 @@ protected: void createHallOfRecordsScene(int which, uint32 hallOfRecordsInfoId); }; -// Scene2201 - -static const NPoint kSsScene2201PuzzleCubePoints[] = { - {305, 305}, {321, 305}, {336, 305}, {305, 319}, - {321, 319}, {336, 319}, {305, 332}, {321, 332}, - {336, 333} -}; - -static const uint32 kSsScene2201PuzzleCubeFileHashes[] = { - 0x88134A44, 0xAA124340, 0xB8124602, 0xA902464C, - 0x890A4244, 0xA8124642, 0xB812C204, 0x381A4A4C -}; - -class AsScene2201CeilingFan : public AnimatedSprite { -public: - AsScene2201CeilingFan(NeverhoodEngine *vm); -}; - -class AsScene2201Door : public AnimatedSprite { -public: - AsScene2201Door(NeverhoodEngine *vm, Klaymen *klaymen, Sprite *ssDoorLight, bool isOpen); -protected: - Klaymen *_klaymen; - Sprite *_ssDoorLight; - bool _isOpen; - int _countdown; - void update(); - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); - void stOpenDoor(); - void stCloseDoor(); -}; - -class SsScene2201PuzzleCube : public StaticSprite { -public: - SsScene2201PuzzleCube(NeverhoodEngine *vm, uint32 positionIndex, uint32 cubeIndex); -}; - class Scene2201 : public Scene { public: Scene2201(NeverhoodEngine *vm, Module *parentModule, int which); @@ -96,30 +57,6 @@ protected: uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); }; -class SsScene2202PuzzleCube : public StaticSprite { -public: - SsScene2202PuzzleCube(NeverhoodEngine *vm, Scene *parentScene, int16 cubePosition, int16 cubeSymbol); -protected: - Scene *_parentScene; - int16 _cubeSymbol; - int16 _cubePosition; - int16 _newX, _newY; - int16 _xDelta, _yDelta; - int16 _xIncr; - int16 _yIncr; - int16 _errValue; - int16 _counter; - int16 _xFlagPos; - bool _counterDirection; - bool _isMoving; - void update(); - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); - void suMoveCubeX(); - void suMoveCubeY(); - void moveCube(int16 newCubePosition); - void stopMoving(); -}; - class Scene2202 : public Scene { public: Scene2202(NeverhoodEngine *vm, Module *parentModule, int which); @@ -138,27 +75,6 @@ protected: bool testIsSolved(); }; -class AsCommonKey : public AnimatedSprite { -public: - AsCommonKey(NeverhoodEngine *vm, Scene *parentScene, int keyIndex, int surfacePriority, int16 x, int16 y); -protected: - Scene *_parentScene; - int _keyIndex; - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); -}; - -class AsScene2203Door : public AnimatedSprite { -public: - AsScene2203Door(NeverhoodEngine *vm, Scene *parentScene, uint doorIndex); -protected: - Scene *_parentScene; - Sprite *_otherDoor; - uint _doorIndex; - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); - void openDoor(); - void closeDoor(); -}; - class Scene2203 : public Scene { public: Scene2203(NeverhoodEngine *vm, Module *parentModule, int which); @@ -175,12 +91,7 @@ protected: uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); }; -class SsScene2205DoorFrame : public StaticSprite { -public: - SsScene2205DoorFrame(NeverhoodEngine *vm); -protected: - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); -}; +class SsCommonPressButton; class Scene2205 : public Scene { public: @@ -194,35 +105,6 @@ protected: uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); }; -class AsScene2206DoorSpikes : public StaticSprite { -public: - AsScene2206DoorSpikes(NeverhoodEngine *vm, uint32 fileHash); -protected: - int _deltaIndex; - void update(); - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); - void suOpen(); - void suClose(); -}; - -class AsScene2206Platform : public StaticSprite { -public: - AsScene2206Platform(NeverhoodEngine *vm, uint32 fileHash); -protected: - int16 _yDelta; - void update(); - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); - void suMoveDown(); -}; - -class SsScene2206TestTube : public StaticSprite { -public: - SsScene2206TestTube(NeverhoodEngine *vm, Scene *parentScene, int surfacePriority, uint32 fileHash); -protected: - Scene *_parentScene; - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); -}; - class Scene2206 : public Scene { public: Scene2206(NeverhoodEngine *vm, Module *parentModule, int which); @@ -241,62 +123,6 @@ protected: void readClickedColumn(); }; -class AsScene2207Elevator : public AnimatedSprite { -public: - AsScene2207Elevator(NeverhoodEngine *vm, Scene *parentScene); - ~AsScene2207Elevator(); -protected: - Scene *_parentScene; - NPointArray *_pointArray; - int16 _pointIndex; - int16 _destPointIndex, _destPointIndexDelta; - bool _isMoving; - void update(); - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); - void suSetPosition(); - void moveToY(int16 y); -}; - -class AsScene2207Lever : public AnimatedSprite { -public: - AsScene2207Lever(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y, int doDeltaX); -protected: - Scene *_parentScene; - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); - void stLeverDown(); - void stLeverDownEvent(); - void stLeverUp(); - void stLeverUpEvent(); -}; - -class AsScene2207WallRobotAnimation : public AnimatedSprite { -public: - AsScene2207WallRobotAnimation(NeverhoodEngine *vm, Scene *parentScene); - ~AsScene2207WallRobotAnimation(); -protected: - bool _idle; - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); - void stStartAnimation(); - void stStopAnimation(); - void cbStopAnimation(); -}; - -class AsScene2207WallCannonAnimation : public AnimatedSprite { -public: - AsScene2207WallCannonAnimation(NeverhoodEngine *vm); -protected: - bool _idle; - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); - void stStartAnimation(); - void stStopAnimation(); - void cbStopAnimation(); -}; - -class SsScene2207Symbol : public StaticSprite { -public: - SsScene2207Symbol(NeverhoodEngine *vm, uint32 fileHash, int index); -}; - class Scene2207 : public Scene { public: Scene2207(NeverhoodEngine *vm, Module *parentModule); diff --git a/engines/neverhood/modules/module2200_sprites.cpp b/engines/neverhood/modules/module2200_sprites.cpp new file mode 100644 index 0000000000..30f0404cf1 --- /dev/null +++ b/engines/neverhood/modules/module2200_sprites.cpp @@ -0,0 +1,1429 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "neverhood/modules/module2200_sprites.h" + +namespace Neverhood { + +AsScene2201CeilingFan::AsScene2201CeilingFan(NeverhoodEngine *vm) + : AnimatedSprite(vm, 1100) { + + _x = 403; + _y = 259; + createSurface(100, 233, 96); + startAnimation(0x8600866, 0, -1); + SetUpdateHandler(&AnimatedSprite::update); +} + +AsScene2201Door::AsScene2201Door(NeverhoodEngine *vm, Klaymen *klaymen, Sprite *ssDoorLight, bool isOpen) + : AnimatedSprite(vm, 1100), _klaymen(klaymen), _ssDoorLight(ssDoorLight), _countdown(0), _isOpen(isOpen) { + + _x = 408; + _y = 290; + createSurface(900, 63, 266); + SetUpdateHandler(&AsScene2201Door::update); + SetMessageHandler(&AsScene2201Door::handleMessage); + if (_isOpen) { + startAnimation(0xE2CB0412, -1, -1); + _countdown = 48; + _newStickFrameIndex = STICK_LAST_FRAME; + } else { + startAnimation(0xE2CB0412, 0, -1); + _newStickFrameIndex = 0; + _ssDoorLight->setVisible(false); + } +} + +void AsScene2201Door::update() { + if (_countdown != 0 && _isOpen && (--_countdown == 0)) + stCloseDoor(); + AnimatedSprite::update(); +} + +uint32 AsScene2201Door::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x100D: + if (param.asInteger() == 0x11001090) { + if (_isOpen) + _ssDoorLight->setVisible(true); + } else if (param.asInteger() == 0x11283090) { + if (!_isOpen) + _ssDoorLight->setVisible(false); + } + break; + case 0x2000: + if (_isOpen) + _countdown = 144; + messageResult = _isOpen ? 1 : 0; + break; + case 0x3002: + gotoNextState(); + break; + case 0x4808: + _countdown = 144; + if (!_isOpen) + stOpenDoor(); + break; + } + return messageResult; +} + +void AsScene2201Door::stOpenDoor() { + _isOpen = true; + startAnimation(0xE2CB0412, 0, -1); + _newStickFrameIndex = STICK_LAST_FRAME; + playSound(0, calcHash("fxDoorOpen33")); +} + +void AsScene2201Door::stCloseDoor() { + _isOpen = false; + startAnimation(0xE2CB0412, -1, -1); + _playBackwards = true; + _newStickFrameIndex = 0; + playSound(0, calcHash("fxDoorClose33")); +} + +SsScene2201PuzzleCube::SsScene2201PuzzleCube(NeverhoodEngine *vm, uint32 positionIndex, uint32 cubeIndex) + : StaticSprite(vm, 900) { + + createSurface(100, 16, 16); + loadSprite(kSsScene2201PuzzleCubeFileHashes[cubeIndex], kSLFCenteredDrawOffset | kSLFSetPosition, 0, + kSsScene2201PuzzleCubePoints[positionIndex].x, kSsScene2201PuzzleCubePoints[positionIndex].y); +} + +static const NPoint kSsScene2202PuzzleCubePoints[] = { + {196, 105}, {323, 102}, {445, 106}, + {192, 216}, {319, 220}, {446, 216}, + {188, 320}, {319, 319}, {443, 322} +}; + +static const uint32 kSsScene2202PuzzleCubeFileHashes1[] = { + 0xA500800C, 0x2182910C, 0x2323980C, + 0x23049084, 0x21008080, 0x2303900C, + 0x6120980C, 0x2504D808 +}; + +static const uint32 kSsScene2202PuzzleCubeFileHashes2[] = { + 0x0AAD8080, 0x0A290291, 0x0A2BA398, + 0x822B8490, 0x86298080, 0x0A2B8390, + 0x0A69A098, 0x0E2D84D8 +}; + +SsScene2202PuzzleCube::SsScene2202PuzzleCube(NeverhoodEngine *vm, Scene *parentScene, int16 cubePosition, int16 cubeSymbol) + : StaticSprite(vm, 900), _parentScene(parentScene), _cubeSymbol(cubeSymbol), _cubePosition(cubePosition), _isMoving(false) { + + int surfacePriority; + + SetUpdateHandler(&SsScene2202PuzzleCube::update); + SetMessageHandler(&SsScene2202PuzzleCube::handleMessage); + if (_cubePosition >= 0 && _cubePosition <= 2) + surfacePriority = 100; + else if (_cubePosition >= 3 && _cubePosition <= 5) + surfacePriority = 300; + else + surfacePriority = 500; + debug(1, "TODO: Unused SurfacePriority: %d", surfacePriority); + loadSprite(kSsScene2202PuzzleCubeFileHashes2[_cubeSymbol], kSLFCenteredDrawOffset | kSLFSetPosition | kSLFDefCollisionBoundsOffset, 0, + kSsScene2202PuzzleCubePoints[_cubePosition].x, kSsScene2202PuzzleCubePoints[_cubePosition].y); + loadSound(0, 0x40958621); + loadSound(1, 0x51108241); +} + +void SsScene2202PuzzleCube::update() { + handleSpriteUpdate(); + updatePosition(); +} + +uint32 SsScene2202PuzzleCube::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x1011: + if (!_isMoving && !getGlobalVar(V_TILE_PUZZLE_SOLVED)) + sendMessage(_parentScene, 0x2000, _cubePosition); + messageResult = 1; + break; + case 0x2001: + _isMoving = true; + moveCube(param.asInteger()); + break; + } + return messageResult; +} + +void SsScene2202PuzzleCube::suMoveCubeX() { + + bool done = false; + + if (_counterDirection) { + if (_counter > 2) + _counter -= 2; + } else { + if (_counter < 20) + _counter += 2; + } + + for (int16 i = 0; i < _counter; i++) { + _x += _xIncr; + _errValue += _yDelta; + if (_errValue >= _xDelta) { + _errValue -= _xDelta; + _y += _yIncr; + } + if (_x == _newX && _y == _newY) { + done = true; + break; + } + if (_x == _xFlagPos) + _counterDirection = true; + } + + if (done) + stopMoving(); + + updateBounds(); + +} + +void SsScene2202PuzzleCube::suMoveCubeY() { + + bool done = false; + + if (_counterDirection) { + if (_counter > 2) + _counter -= 2; + } else { + if (_counter < 20) + _counter += 2; + } + + for (int16 i = 0; i < _counter; i++) { + _y += _yIncr; + _errValue += _xDelta; + if (_errValue >= _yDelta) { + _errValue -= _yDelta; + _x += _xIncr; + } + if (_x == _newX && _y == _newY) { + done = true; + break; + } + if (_x == _xFlagPos) + _counterDirection = true; + } + + if (done) + stopMoving(); + + updateBounds(); + +} + +void SsScene2202PuzzleCube::moveCube(int16 newCubePosition) { + + loadSprite(kSsScene2202PuzzleCubeFileHashes1[_cubeSymbol], kSLFCenteredDrawOffset); + + setSubVar(VA_CUBE_POSITIONS, _cubePosition, (uint32)-1); + setSubVar(VA_CUBE_POSITIONS, newCubePosition, (uint32)_cubeSymbol); + + _cubePosition = newCubePosition; + _errValue = 0; + _counterDirection = false; + _counter = 0; + _newX = kSsScene2202PuzzleCubePoints[newCubePosition].x; + _newY = kSsScene2202PuzzleCubePoints[newCubePosition].y; + + if (_x == _newX && _y == _newY) + return; + + if (_x <= _newX) { + if (_y <= _newY) { + _xDelta = _newX - _x; + _yDelta = _newY - _y; + _xIncr = 1; + _yIncr = 1; + } else { + _xDelta = _newX - _x; + _yDelta = _y - _newY; + _xIncr = 1; + _yIncr = -1; + } + } else { + if (_y <= _newY) { + _xDelta = _x - _newX; + _yDelta = _newY - _y; + _xIncr = -1; + _yIncr = 1; + } else { + _xDelta = _x - _newX; + _yDelta = _y - _newY; + _xIncr = -1; + _yIncr = -1; + } + } + + if (_xDelta > _yDelta) { + SetSpriteUpdate(&SsScene2202PuzzleCube::suMoveCubeX); + if (_xIncr > 0) { + if (_newX - _x >= 180) + _xFlagPos = _newX - 90; + else + _xFlagPos = _x + _newX / 2; + } else { + if (_x - _newX >= 180) + _xFlagPos = _x + 90; + else + _xFlagPos = _x / 2 + _newX; + } + playSound(0); + } else { + SetSpriteUpdate(&SsScene2202PuzzleCube::suMoveCubeY); + if (_yIncr > 0) { + if (_newY - _y >= 180) + _xFlagPos = _newY - 90; + else + _xFlagPos = _y + _newY / 2; + } else { + if (_y - _newY >= 180) + _xFlagPos = _y + 90; + else + _xFlagPos = _y / 2 + _newY; + } + playSound(1); + } + +} + +void SsScene2202PuzzleCube::stopMoving() { + loadSprite(kSsScene2202PuzzleCubeFileHashes2[_cubeSymbol], kSLFCenteredDrawOffset); + SetSpriteUpdate(NULL); + _isMoving = false; + sendMessage(_parentScene, 0x2002, _cubePosition); +} + +static const uint32 kAsCommonKeyFileHashes[] = { + 0x2450D850, 0x0C9CE8D0, 0x2C58A152 +}; + +AsCommonKey::AsCommonKey(NeverhoodEngine *vm, Scene *parentScene, int keyIndex, int surfacePriority, int16 x, int16 y) + : AnimatedSprite(vm, kAsCommonKeyFileHashes[keyIndex], surfacePriority, x, y), _parentScene(parentScene), _keyIndex(keyIndex) { + + if (!getSubVar(VA_HAS_KEY, _keyIndex) && !getSubVar(VA_IS_KEY_INSERTED, _keyIndex)) { + SetMessageHandler(&AsCommonKey::handleMessage); + } else { + // If Klaymen already has the key or it's already inserted then don't show it + setVisible(false); + SetMessageHandler(NULL); + } +} + +uint32 AsCommonKey::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x1011: + sendMessage(_parentScene, 0x4826, 0); + messageResult = 1; + break; + case 0x4806: + setSubVar(VA_HAS_KEY, _keyIndex, 1); + setVisible(false); + SetMessageHandler(NULL); + } + return messageResult; +} + +static const uint32 kAsScene2203DoorFileHashes[] = { + 0x7868AE10, 0x1A488110 +}; + +AsScene2203Door::AsScene2203Door(NeverhoodEngine *vm, Scene *parentScene, uint doorIndex) + : AnimatedSprite(vm, 1100), _parentScene(parentScene), _doorIndex(doorIndex) { + + SetUpdateHandler(&AnimatedSprite::update); + SetMessageHandler(&AsScene2203Door::handleMessage); + _x = 320; + _y = 240; + createSurface1(kAsScene2203DoorFileHashes[_doorIndex], 900); + if (getGlobalVar(V_LARGE_DOOR_NUMBER) == _doorIndex) { + startAnimation(kAsScene2203DoorFileHashes[_doorIndex], -1, -1); + _newStickFrameIndex = STICK_LAST_FRAME; + } else { + startAnimation(kAsScene2203DoorFileHashes[_doorIndex], 0, -1); + _newStickFrameIndex = 0; + } +} + +uint32 AsScene2203Door::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x1011: + if (_doorIndex == getGlobalVar(V_LARGE_DOOR_NUMBER)) + sendMessage(_parentScene, 0x2002, 0); + else + sendMessage(_parentScene, 0x2001, 0); + messageResult = 1; + break; + case 0x2000: + _otherDoor = (Sprite*)param.asEntity(); + break; + case 0x3002: + if (_doorIndex == getGlobalVar(V_LARGE_DOOR_NUMBER)) + sendMessage(_parentScene, 0x4808, 0); + stopAnimation(); + break; + case 0x4808: + setGlobalVar(V_LARGE_DOOR_NUMBER, _doorIndex); + sendMessage(_otherDoor, 0x4809, 0); + openDoor(); + break; + case 0x4809: + closeDoor(); + sendMessage(_parentScene, 0x2003, 0); + break; + } + return messageResult; +} + +void AsScene2203Door::openDoor() { + playSound(0, 0x341014C4); + startAnimation(kAsScene2203DoorFileHashes[_doorIndex], 1, -1); +} + +void AsScene2203Door::closeDoor() { + startAnimation(kAsScene2203DoorFileHashes[_doorIndex], -1, -1); + _playBackwards = true; + _newStickFrameIndex = 0; +} + +SsScene2205DoorFrame::SsScene2205DoorFrame(NeverhoodEngine *vm) + : StaticSprite(vm, 900) { + + SetMessageHandler(&SsScene2205DoorFrame::handleMessage); + createSurface(1100, 45, 206); + loadSprite(getGlobalVar(V_LIGHTS_ON) ? 0x24306227 : 0xD90032A0, kSLFDefDrawOffset | kSLFDefPosition); +} + +uint32 SsScene2205DoorFrame::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x2000: + loadSprite(getGlobalVar(V_LIGHTS_ON) ? 0x24306227 : 0xD90032A0, kSLFDefDrawOffset | kSLFDefPosition); + break; + } + return messageResult; +} + +static const int16 kAsScene2206DoorSpikesXDeltasOpen[] = { + -24, -28, -18, 6, 9, -8 +}; + +static const int16 kAsScene2206DoorSpikesXDeltasClose[] = { + -8, 7, 11, 26, 13, 14 +}; + +AsScene2206DoorSpikes::AsScene2206DoorSpikes(NeverhoodEngine *vm, uint32 fileHash) + : StaticSprite(vm, fileHash, 200) { + + if (getGlobalVar(V_SPIKES_RETRACTED)) + _x -= 63; + SetUpdateHandler(&AsScene2206DoorSpikes::update); + SetMessageHandler(&AsScene2206DoorSpikes::handleMessage); + SetSpriteUpdate(NULL); +} + +void AsScene2206DoorSpikes::update() { + handleSpriteUpdate(); + updatePosition(); +} + +uint32 AsScene2206DoorSpikes::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x4808: + _deltaIndex = 0; + playSound(0, 0x032746E0); + SetMessageHandler(NULL); + SetSpriteUpdate(&AsScene2206DoorSpikes::suOpen); + break; + case 0x4809: + _deltaIndex = 0; + playSound(0, 0x002642C0); + SetMessageHandler(NULL); + SetSpriteUpdate(&AsScene2206DoorSpikes::suClose); + break; + } + return messageResult; +} + +void AsScene2206DoorSpikes::suOpen() { + if (_deltaIndex < 6) { + _x += kAsScene2206DoorSpikesXDeltasOpen[_deltaIndex]; + _deltaIndex++; + } else { + SetMessageHandler(&AsScene2206DoorSpikes::handleMessage); + SetSpriteUpdate(NULL); + } +} + +void AsScene2206DoorSpikes::suClose() { + if (_deltaIndex < 6) { + _x += kAsScene2206DoorSpikesXDeltasClose[_deltaIndex]; + _deltaIndex++; + } else { + SetMessageHandler(&AsScene2206DoorSpikes::handleMessage); + SetSpriteUpdate(NULL); + } +} + +AsScene2206Platform::AsScene2206Platform(NeverhoodEngine *vm, uint32 fileHash) + : StaticSprite(vm, fileHash, 50) { + + SetUpdateHandler(&AsScene2206Platform::update); + SetMessageHandler(&AsScene2206Platform::handleMessage); + SetSpriteUpdate(NULL); +} + +void AsScene2206Platform::update() { + handleSpriteUpdate(); + updatePosition(); +} + +uint32 AsScene2206Platform::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x4803: + _yDelta = 0; + SetMessageHandler(NULL); + SetSpriteUpdate(&AsScene2206Platform::suMoveDown); + break; + } + return messageResult; +} + +void AsScene2206Platform::suMoveDown() { + _yDelta++; + _y += _yDelta; +} + +SsScene2206TestTube::SsScene2206TestTube(NeverhoodEngine *vm, Scene *parentScene, int surfacePriority, uint32 fileHash) + : StaticSprite(vm, fileHash, surfacePriority), _parentScene(parentScene) { + + if (getGlobalVar(V_HAS_TEST_TUBE)) { + setVisible(false); + SetMessageHandler(NULL); + } else + SetMessageHandler(&SsScene2206TestTube::handleMessage); + _collisionBoundsOffset = _drawOffset; + updateBounds(); +} + +uint32 SsScene2206TestTube::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x1011: + sendMessage(_parentScene, 0x4826, 0); + messageResult = 1; + break; + case 0x4806: + setGlobalVar(V_HAS_TEST_TUBE, 1); + setVisible(false); + SetMessageHandler(NULL); + break; + } + return messageResult; +} + +AsScene2207Elevator::AsScene2207Elevator(NeverhoodEngine *vm, Scene *parentScene) + : AnimatedSprite(vm, 900), _parentScene(parentScene), _pointIndex(0), _destPointIndex(0), _destPointIndexDelta(0) { + + NPoint pt; + + _dataResource.load(0x00524846); + _pointArray = _dataResource.getPointArray(0x005B02B7); + pt = _dataResource.getPoint(0x403A82B1); + _x = pt.x; + _y = pt.y; + createSurface(1100, 129, 103); + startAnimation(getGlobalVar(V_LIGHTS_ON) ? 0xC858CC19 : 0x294B3377, 0, 0); + _newStickFrameIndex = 0; + SetUpdateHandler(&AsScene2207Elevator::update); + SetMessageHandler(&AsScene2207Elevator::handleMessage); + SetSpriteUpdate(&AsScene2207Elevator::suSetPosition); +} + +AsScene2207Elevator::~AsScene2207Elevator() { + _vm->_soundMan->deleteSoundGroup(0x02700413); +} + +void AsScene2207Elevator::update() { + + if (_destPointIndex + _destPointIndexDelta > _pointIndex) { + _pointIndex++; + startAnimation(getGlobalVar(V_LIGHTS_ON) ? 0xC858CC19 : 0x294B3377, _pointIndex, _pointIndex); + _newStickFrameIndex = _pointIndex; + if (_destPointIndex + _destPointIndexDelta == _pointIndex) { + if (_destPointIndexDelta != 0) + _destPointIndexDelta = 0; + else { + _vm->_soundMan->deleteSound(0xD3B02847); + playSound(0, 0x53B8284A); + } + } + } + + if (_destPointIndex + _destPointIndexDelta < _pointIndex) { + _pointIndex--; + if (_pointIndex == 0) + sendMessage(_parentScene, 0x2003, 0); + startAnimation(getGlobalVar(V_LIGHTS_ON) ? 0xC858CC19 : 0x294B3377, _pointIndex, _pointIndex); + _newStickFrameIndex = _pointIndex; + if (_destPointIndex + _destPointIndexDelta == _pointIndex) { + if (_destPointIndexDelta != 0) + _destPointIndexDelta = 0; + else { + _vm->_soundMan->deleteSound(0xD3B02847); + playSound(0, 0x53B8284A); + } + } + } + + if (_pointIndex > 20 && _surface->getPriority() != 900) + sendMessage(_parentScene, 0x2002, 900); + else if (_pointIndex < 20 && _surface->getPriority() != 1100) + sendMessage(_parentScene, 0x2002, 1100); + + AnimatedSprite::update(); + + if (_destPointIndex + _destPointIndexDelta == _pointIndex && _isMoving) { + sendMessage(_parentScene, 0x2004, 0); + _isMoving = false; + } + +} + +void AsScene2207Elevator::suSetPosition() { + _x = (*_pointArray)[_pointIndex].x; + _y = (*_pointArray)[_pointIndex].y - 60; + updateBounds(); +} + +uint32 AsScene2207Elevator::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x2000: + moveToY(param.asInteger()); + break; + } + return messageResult; +} + +void AsScene2207Elevator::moveToY(int16 y) { + int16 minDistance = 480; + + if (!_pointArray || _pointArray->size() == 0) + return; + + for (uint i = 0; i < _pointArray->size(); i++) { + int16 distance = ABS(y - (*_pointArray)[i].y); + if (distance < minDistance) { + minDistance = distance; + _destPointIndex = i; + } + } + + if (_destPointIndex != _pointIndex) { + if (_destPointIndex == 0 || _destPointIndex == (int)_pointArray->size() - 1) + _destPointIndexDelta = 0; + else if (_destPointIndex < _pointIndex) + _destPointIndexDelta = -2; + else + _destPointIndexDelta = 2; + _vm->_soundMan->addSound(0x02700413, 0xD3B02847); + _vm->_soundMan->playSoundLooping(0xD3B02847); + } + + _isMoving = true; + +} + +AsScene2207Lever::AsScene2207Lever(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y, int doDeltaX) + : AnimatedSprite(vm, 1100), _parentScene(parentScene) { + + _x = x; + _y = y; + createSurface(1010, 71, 73); + setDoDeltaX(doDeltaX); + startAnimation(0x80880090, 0, -1); + _newStickFrameIndex = 0; + SetUpdateHandler(&AnimatedSprite::update); + SetMessageHandler(&AsScene2207Lever::handleMessage); +} + +uint32 AsScene2207Lever::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x1011: + sendMessage(_parentScene, 0x4826, 0); + messageResult = 1; + break; + case 0x3002: + gotoNextState(); + stopAnimation(); + break; + case 0x4807: + stLeverUp(); + break; + case 0x480F: + stLeverDown(); + break; + case 0x482A: + sendMessage(_parentScene, 0x1022, 990); + break; + case 0x482B: + sendMessage(_parentScene, 0x1022, 1010); + break; + } + return messageResult; +} + +void AsScene2207Lever::stLeverDown() { + startAnimation(0x80880090, 1, -1); + playSound(0, 0x40581882); + FinalizeState(&AsScene2207Lever::stLeverDownEvent); +} + +void AsScene2207Lever::stLeverDownEvent() { + sendMessage(_parentScene, 0x480F, 0); +} + +void AsScene2207Lever::stLeverUp() { + startAnimation(0x80880090, 6, -1); + _playBackwards = true; + playSound(0, 0x40581882); + FinalizeState(&AsScene2207Lever::stLeverUpEvent); +} + +void AsScene2207Lever::stLeverUpEvent() { + sendMessage(_parentScene, 0x4807, 0); +} + +AsScene2207WallRobotAnimation::AsScene2207WallRobotAnimation(NeverhoodEngine *vm, Scene *parentScene) + : AnimatedSprite(vm, 1200), _idle(true) { + + _x = 309; + _y = 320; + createSurface1(0xCCFD6090, 100); + startAnimation(0xCCFD6090, 0, -1); + _newStickFrameIndex = 0; + loadSound(1, 0x40330872); + loadSound(2, 0x72A2914A); + loadSound(3, 0xD4226080); + SetUpdateHandler(&AnimatedSprite::update); + SetMessageHandler(&AsScene2207WallRobotAnimation::handleMessage); +} + +AsScene2207WallRobotAnimation::~AsScene2207WallRobotAnimation() { + _vm->_soundMan->deleteSoundGroup(0x80D00820); +} + +uint32 AsScene2207WallRobotAnimation::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x100D: + if (!_idle) { + if (param.asInteger() == 0x3423093) { + _vm->_soundMan->addSound(0x80D00820, 0x12121943); + _vm->_soundMan->playSoundLooping(0x12121943); + } else if (param.asInteger() == 0x834AB011) { + stopSound(0); + stopSound(1); + stopSound(2); + stopSound(3); + _vm->_soundMan->deleteSound(0x12121943); + } else if (param.asInteger() == 0x3A980501) + playSound(1); + else if (param.asInteger() == 0x2A2AD498) + playSound(2); + else if (param.asInteger() == 0xC4980008) + playSound(3); + else if (param.asInteger() == 0x06B84228) + playSound(0, 0xE0702146); + } + break; + case 0x2006: + stStartAnimation(); + break; + case 0x2007: + stStopAnimation(); + break; + case 0x3002: + gotoNextState(); + break; + } + return messageResult; +} + +void AsScene2207WallRobotAnimation::stStartAnimation() { + if (!_idle) { + NextState(NULL); + } else { + startAnimation(0xCCFD6090, 0, -1); + _idle = false; + setVisible(true); + } +} + +void AsScene2207WallRobotAnimation::stStopAnimation() { + NextState(&AsScene2207WallRobotAnimation::cbStopAnimation); +} + +void AsScene2207WallRobotAnimation::cbStopAnimation() { + stopAnimation(); + stopSound(0); + stopSound(1); + stopSound(2); + stopSound(3); + _vm->_soundMan->deleteSound(0x12121943); + _idle = true; + setVisible(false); +} + +AsScene2207WallCannonAnimation::AsScene2207WallCannonAnimation(NeverhoodEngine *vm) + : AnimatedSprite(vm, 1200), _idle(true) { + + _x = 309; + _y = 320; + createSurface1(0x8CAA0099, 100); + startAnimation(0x8CAA0099, 0, -1); + _newStickFrameIndex = 0; + SetUpdateHandler(&AnimatedSprite::update); + SetMessageHandler(&AsScene2207WallCannonAnimation::handleMessage); +} + +uint32 AsScene2207WallCannonAnimation::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x2006: + stStartAnimation(); + break; + case 0x2007: + stStopAnimation(); + break; + case 0x3002: + gotoNextState(); + break; + } + return messageResult; +} + +void AsScene2207WallCannonAnimation::stStartAnimation() { + if (!_idle) { + NextState(NULL); + } else { + setVisible(true); + startAnimation(0x8CAA0099, 0, -1); + _idle = false; + } +} + +void AsScene2207WallCannonAnimation::stStopAnimation() { + NextState(&AsScene2207WallCannonAnimation::cbStopAnimation); +} + +void AsScene2207WallCannonAnimation::cbStopAnimation() { + stopAnimation(); + setVisible(false); + _idle = true; +} + +SsScene2207Symbol::SsScene2207Symbol(NeverhoodEngine *vm, uint32 fileHash, int index) + : StaticSprite(vm, fileHash, 100) { + + _x = 330; + _y = 246 + index * 50; + updatePosition(); +} + +KmScene2201::KmScene2201(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y, NRect *clipRects, int clipRectsCount) + : Klaymen(vm, parentScene, x, y) { + + _surface->setClipRects(clipRects, clipRectsCount); + _dataResource.load(0x04104242); +} + +uint32 KmScene2201::xHandleMessage(int messageNum, const MessageParam ¶m) { + switch (messageNum) { + case 0x4001: + case 0x4800: + startWalkToX(param.asPoint().x, false); + break; + case 0x4004: + GotoState(&Klaymen::stTryStandIdle); + break; + case 0x4812: + GotoState(&Klaymen::stPickUpGeneric); + break; + case 0x4816: + if (param.asInteger() == 0) + GotoState(&Klaymen::stPressButtonSide); + break; + case 0x4817: + setDoDeltaX(param.asInteger() ? 1 : 0); + gotoNextStateExt(); + break; + case 0x4818: + startWalkToX(_dataResource.getPoint(param.asInteger()).x, false); + break; + case 0x481B: + if (param.asPoint().y != 0) + startWalkToXDistance(param.asPoint().y, param.asPoint().x); + else + startWalkToAttachedSpriteXDistance(param.asPoint().x); + break; + case 0x481D: + GotoState(&Klaymen::stTurnToUse); + break; + case 0x481E: + GotoState(&Klaymen::stReturnFromUse); + break; + case 0x482D: + setDoDeltaX(_x > (int16)param.asInteger() ? 1 : 0); + gotoNextStateExt(); + break; + case 0x482E: + if (param.asInteger() == 1) + GotoState(&Klaymen::stWalkToFrontNoStep); + else + GotoState(&Klaymen::stWalkToFront); + break; + case 0x482F: + if (param.asInteger() == 1) + GotoState(&Klaymen::stTurnToFront); + else + GotoState(&Klaymen::stTurnToBack); + break; + case 0x483F: + startSpecialWalkRight(param.asInteger()); + break; + case 0x4840: + startSpecialWalkLeft(param.asInteger()); + break; + } + return 0; +} + +KmScene2203::KmScene2203(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) + : Klaymen(vm, parentScene, x, y) { + + // Empty +} + +uint32 KmScene2203::xHandleMessage(int messageNum, const MessageParam ¶m) { + switch (messageNum) { + case 0x4001: + case 0x4800: + startWalkToX(param.asPoint().x, false); + break; + case 0x4004: + GotoState(&Klaymen::stTryStandIdle); + break; + case 0x4812: + if (param.asInteger() == 2) + GotoState(&Klaymen::stPickUpNeedle); + else if (param.asInteger() == 1) + GotoState(&Klaymen::stPickUpTube); + else + GotoState(&Klaymen::stPickUpGeneric); + break; + case 0x4816: + if (param.asInteger() == 1) + GotoState(&Klaymen::stPressButton); + else if (param.asInteger() == 2) + GotoState(&Klaymen::stPressFloorButton); + else + GotoState(&Klaymen::stPressButtonSide); + break; + case 0x4817: + setDoDeltaX(param.asInteger()); + gotoNextStateExt(); + break; + case 0x4818: + startWalkToX(_dataResource.getPoint(param.asInteger()).x, false); + break; + case 0x4819: + GotoState(&KmScene2203::stClayDoorOpen); + break; + case 0x481A: + GotoState(&Klaymen::stInsertDisk); + break; + case 0x481B: + if (param.asPoint().y != 0) + startWalkToXDistance(param.asPoint().y, param.asPoint().x); + else + startWalkToAttachedSpriteXDistance(param.asPoint().x); + break; + case 0x481D: + GotoState(&Klaymen::stTurnToUse); + break; + case 0x481E: + GotoState(&Klaymen::stReturnFromUse); + break; + case 0x482D: + setDoDeltaX(_x > (int16)param.asInteger() ? 1 : 0); + gotoNextStateExt(); + break; + case 0x483F: + startSpecialWalkRight(param.asInteger()); + break; + case 0x4840: + startSpecialWalkLeft(param.asInteger()); + break; + } + return 0; +} + +void KmScene2203::stClayDoorOpen() { + if (!stStartAction(AnimationCallback(&KmScene2203::stClayDoorOpen))) { + _busyStatus = 2; + _acceptInput = false; + startAnimation(0x5CCCB330, 0, -1); + SetUpdateHandler(&Klaymen::update); + SetMessageHandler(&KmScene2203::hmClayDoorOpen); + SetSpriteUpdate(&Klaymen::suUpdateDestX); + } +} + +uint32 KmScene2203::hmClayDoorOpen(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = hmLowLevelAnimation(messageNum, param, sender); + switch (messageNum) { + case 0x100D: + if (param.asInteger() == 0x040D4186) { + sendMessage(_attachedSprite, 0x4808, 0); + } + break; + } + return messageResult; +} + +KmScene2205::KmScene2205(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) + : Klaymen(vm, parentScene, x, y) { + + // Empty +} + +void KmScene2205::xUpdate() { + setGlobalVar(V_KLAYMEN_FRAMEINDEX, _currFrameIndex); +} + +uint32 KmScene2205::xHandleMessage(int messageNum, const MessageParam ¶m) { + switch (messageNum) { + case 0x4001: + case 0x4800: + startWalkToX(param.asPoint().x, false); + break; + case 0x4004: + GotoState(&Klaymen::stTryStandIdle); + break; + case 0x4804: + if (param.asInteger() != 0) { + _destX = param.asInteger(); + GotoState(&Klaymen::stStartWalkingResume); + } else + GotoState(&Klaymen::stPeekWall); + break; + case 0x4816: + if (param.asInteger() == 0) + GotoState(&Klaymen::stPressButtonSide); + break; + case 0x4817: + setDoDeltaX(param.asInteger()); + gotoNextStateExt(); + break; + case 0x4818: + startWalkToX(_dataResource.getPoint(param.asInteger()).x, false); + break; + case 0x483F: + startSpecialWalkRight(param.asInteger()); + break; + case 0x4840: + startSpecialWalkLeft(param.asInteger()); + break; + } + return 0; +} + +KmScene2206::KmScene2206(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) + : Klaymen(vm, parentScene, x, y) { + + _walkResumeFrameIncr = 1; + _vm->_soundMan->addSound(0x80101800, 0xD3B02847); +} + +KmScene2206::~KmScene2206() { + _vm->_soundMan->deleteSoundGroup(0x80101800); +} + +void KmScene2206::xUpdate() { + setGlobalVar(V_KLAYMEN_FRAMEINDEX, _currFrameIndex); +} + +uint32 KmScene2206::xHandleMessage(int messageNum, const MessageParam ¶m) { + switch (messageNum) { + case 0x4001: + case 0x4800: + startWalkToX(param.asPoint().x, false); + break; + case 0x4004: + GotoState(&Klaymen::stTryStandIdle); + break; + case 0x4803: + GotoState(&KmScene2206::stRidePlatformDown); + break; + case 0x4804: + if (param.asInteger() != 0) { + _destX = param.asInteger(); + GotoState(&Klaymen::stStartWalkingResume); + } else + GotoState(&Klaymen::stPeekWall); + break; + case 0x4812: + if (param.asInteger() == 1) + GotoState(&Klaymen::stPickUpTube); + else + GotoState(&Klaymen::stPickUpGeneric); + break; + case 0x4816: + if (param.asInteger() == 1) + GotoState(&Klaymen::stPressButton); + else if (param.asInteger() == 2) + GotoState(&Klaymen::stPressFloorButton); + else + GotoState(&Klaymen::stPressButtonSide); + break; + case 0x4817: + setDoDeltaX(param.asInteger()); + gotoNextStateExt(); + break; + case 0x481B: + if (param.asPoint().y != 0) + startWalkToXDistance(param.asPoint().y, param.asPoint().x); + else + startWalkToAttachedSpriteXDistance(param.asPoint().x); + break; + case 0x481F: + if (param.asInteger() == 0) + GotoState(&Klaymen::stWonderAboutHalf); + else if (param.asInteger() == 1) + GotoState(&Klaymen::stWonderAboutAfter); + else if (param.asInteger() == 3) + GotoState(&Klaymen::stTurnToUseHalf); + else if (param.asInteger() == 4) + GotoState(&Klaymen::stTurnAwayFromUse); + else + GotoState(&Klaymen::stWonderAbout); + break; + case 0x482D: + setDoDeltaX(_x > (int16)param.asInteger() ? 1 : 0); + gotoNextStateExt(); + break; + case 0x482E: + if (param.asInteger() == 1) + GotoState(&Klaymen::stWalkToFrontNoStep); + else + GotoState(&Klaymen::stWalkToFront); + break; + case 0x482F: + if (param.asInteger() == 1) + GotoState(&Klaymen::stTurnToFront); + else + GotoState(&Klaymen::stTurnToBack); + break; + case 0x4837: + stopWalking(); + break; + case 0x483F: + startSpecialWalkRight(param.asInteger()); + break; + case 0x4840: + startSpecialWalkLeft(param.asInteger()); + break; + } + return 0; +} + +void KmScene2206::suRidePlatformDown() { + _platformDeltaY++; + _y += _platformDeltaY; + if (_y > 600) + sendMessage(this, 0x1019, 0); +} + +void KmScene2206::stRidePlatformDown() { + if (!stStartActionFromIdle(AnimationCallback(&KmScene2206::stRidePlatformDown))) { + _busyStatus = 1; + sendMessage(_parentScene, 0x4803, 0); + _acceptInput = false; + _platformDeltaY = 0; + startAnimation(0x5420E254, 0, -1); + SetUpdateHandler(&Klaymen::update); + SetMessageHandler(&Klaymen::hmLowLevel); + SetSpriteUpdate(&KmScene2206::suRidePlatformDown); + _vm->_soundMan->playSoundLooping(0xD3B02847); + } +} + +KmScene2207::KmScene2207(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) + : Klaymen(vm, parentScene, x, y) { + + // Empty +} + +uint32 KmScene2207::xHandleMessage(int messageNum, const MessageParam ¶m) { + switch (messageNum) { + case 0x2001: + GotoState(&Klaymen::stRidePlatform); + break; + case 0x2005: + suRidePlatform(); + GotoState(&Klaymen::stTryStandIdle); + break; + case 0x4001: + case 0x4800: + startWalkToX(param.asPoint().x, false); + break; + case 0x4004: + GotoState(&Klaymen::stTryStandIdle); + break; + case 0x480D: + GotoState(&Klaymen::stInteractLever); + break; + case 0x4812: + GotoState(&Klaymen::stPickUpGeneric); + break; + case 0x4816: + if (param.asInteger() == 1) + GotoState(&Klaymen::stPressButton); + else if (param.asInteger() == 2) + GotoState(&Klaymen::stPressFloorButton); + else + GotoState(&Klaymen::stPressButtonSide); + break; + case 0x4817: + setDoDeltaX(param.asInteger()); + gotoNextStateExt(); + break; + case 0x481B: + if (param.asPoint().y != 0) + startWalkToXDistance(param.asPoint().y, param.asPoint().x); + else + startWalkToAttachedSpriteXDistance(param.asPoint().x); + break; + case 0x4827: + GotoState(&Klaymen::stReleaseLever); + break; + case 0x482D: + setDoDeltaX(_x > (int16)param.asInteger() ? 1 : 0); + gotoNextStateExt(); + break; + case 0x483F: + startSpecialWalkRight(param.asInteger()); + break; + case 0x4840: + startSpecialWalkLeft(param.asInteger()); + break; + } + return 0; +} + +KmScene2242::KmScene2242(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) + : Klaymen(vm, parentScene, x, y) { + + // Empty +} + +void KmScene2242::xUpdate() { + setGlobalVar(V_KLAYMEN_FRAMEINDEX, _currFrameIndex); +} + +uint32 KmScene2242::xHandleMessage(int messageNum, const MessageParam ¶m) { + switch (messageNum) { + case 0x4001: + case 0x4800: + startWalkToX(param.asPoint().x, false); + break; + case 0x4004: + GotoState(&Klaymen::stTryStandIdle); + break; + case 0x4804: + if (param.asInteger() != 0) { + _destX = param.asInteger(); + GotoState(&Klaymen::stStartWalkingResume); + } else + GotoState(&Klaymen::stPeekWall); + break; + case 0x4812: + if (param.asInteger() == 2) + GotoState(&Klaymen::stPickUpNeedle); + else if (param.asInteger() == 1) + GotoState(&Klaymen::stPickUpTube); + else + GotoState(&Klaymen::stPickUpGeneric); + break; + case 0x4817: + setDoDeltaX(param.asInteger()); + gotoNextStateExt(); + break; + case 0x481B: + if (param.asPoint().y != 0) + startWalkToXDistance(param.asPoint().y, param.asPoint().x); + else + startWalkToAttachedSpriteXDistance(param.asPoint().x); + break; + case 0x481F: + if (param.asInteger() == 0) + GotoState(&Klaymen::stWonderAboutHalf); + else if (param.asInteger() == 1) + GotoState(&Klaymen::stWonderAboutAfter); + else if (param.asInteger() == 3) + GotoState(&Klaymen::stTurnToUseHalf); + else if (param.asInteger() == 4) + GotoState(&Klaymen::stTurnAwayFromUse); + else + GotoState(&Klaymen::stWonderAbout); + break; + case 0x482D: + setDoDeltaX(_x > (int16)param.asInteger() ? 1 : 0); + gotoNextStateExt(); + break; + case 0x4837: + stopWalking(); + break; + } + return 0; +} + +KmHallOfRecords::KmHallOfRecords(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) + : Klaymen(vm, parentScene, x, y) { + // Empty +} + +void KmHallOfRecords::xUpdate() { + setGlobalVar(V_KLAYMEN_FRAMEINDEX, _currFrameIndex); +} + +uint32 KmHallOfRecords::xHandleMessage(int messageNum, const MessageParam ¶m) { + switch (messageNum) { + case 0x4001: + case 0x4800: + startWalkToX(param.asPoint().x, false); + break; + case 0x4004: + GotoState(&Klaymen::stTryStandIdle); + break; + case 0x4804: + if (param.asInteger() != 0) { + _destX = param.asInteger(); + GotoState(&Klaymen::stStartWalkingResume); + } else + GotoState(&Klaymen::stPeekWall); + break; + case 0x4817: + setDoDeltaX(param.asInteger()); + gotoNextStateExt(); + break; + case 0x481F: + if (param.asInteger() == 0) + GotoState(&Klaymen::stWonderAboutHalf); + else if (param.asInteger() == 1) + GotoState(&Klaymen::stWonderAboutAfter); + else if (param.asInteger() == 3) + GotoState(&Klaymen::stTurnToUseHalf); + else if (param.asInteger() == 4) + GotoState(&Klaymen::stTurnAwayFromUse); + else + GotoState(&Klaymen::stWonderAbout); + break; + case 0x482D: + setDoDeltaX(_x > (int16)param.asInteger() ? 1 : 0); + gotoNextStateExt(); + break; + case 0x4837: + stopWalking(); + break; + } + return 0; +} + +KmScene2247::KmScene2247(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) + : Klaymen(vm, parentScene, x, y) { + + // Empty +} + +void KmScene2247::xUpdate() { + setGlobalVar(V_KLAYMEN_FRAMEINDEX, _currFrameIndex); +} + +uint32 KmScene2247::xHandleMessage(int messageNum, const MessageParam ¶m) { + switch (messageNum) { + case 0x4001: + case 0x4800: + startWalkToX(param.asPoint().x, false); + break; + case 0x4004: + GotoState(&Klaymen::stTryStandIdle); + break; + case 0x4804: + if (param.asInteger() != 0) { + _destX = param.asInteger(); + GotoState(&Klaymen::stStartWalkingResume); + } else + GotoState(&Klaymen::stPeekWall); + break; + case 0x4817: + setDoDeltaX(param.asInteger()); + gotoNextStateExt(); + break; + case 0x481F: + if (param.asInteger() == 0) + GotoState(&Klaymen::stWonderAboutHalf); + else if (param.asInteger() == 1) + GotoState(&Klaymen::stWonderAboutAfter); + else if (param.asInteger() == 3) + GotoState(&Klaymen::stTurnToUseHalf); + else if (param.asInteger() == 4) + GotoState(&Klaymen::stTurnAwayFromUse); + else + GotoState(&Klaymen::stWonderAbout); + break; + case 0x482D: + setDoDeltaX(_x > (int16)param.asInteger() ? 1 : 0); + gotoNextStateExt(); + break; + case 0x4837: + stopWalking(); + break; + } + return 0; +} + +} // End of namespace Neverhood diff --git a/engines/neverhood/modules/module2200_sprites.h b/engines/neverhood/modules/module2200_sprites.h new file mode 100644 index 0000000000..9aaf3b6aae --- /dev/null +++ b/engines/neverhood/modules/module2200_sprites.h @@ -0,0 +1,275 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef NEVERHOOD_MODULES_MODULE2200_SPRITES_H +#define NEVERHOOD_MODULES_MODULE2200_SPRITES_H + +#include "neverhood/neverhood.h" +#include "neverhood/module.h" +#include "neverhood/scene.h" +#include "neverhood/graphics.h" + +namespace Neverhood { + +static const NPoint kSsScene2201PuzzleCubePoints[] = { + {305, 305}, {321, 305}, {336, 305}, {305, 319}, + {321, 319}, {336, 319}, {305, 332}, {321, 332}, + {336, 333} +}; + +static const uint32 kSsScene2201PuzzleCubeFileHashes[] = { + 0x88134A44, 0xAA124340, 0xB8124602, 0xA902464C, + 0x890A4244, 0xA8124642, 0xB812C204, 0x381A4A4C +}; + +class AsScene2201CeilingFan : public AnimatedSprite { +public: + AsScene2201CeilingFan(NeverhoodEngine *vm); +}; + +class AsScene2201Door : public AnimatedSprite { +public: + AsScene2201Door(NeverhoodEngine *vm, Klaymen *klaymen, Sprite *ssDoorLight, bool isOpen); +protected: + Klaymen *_klaymen; + Sprite *_ssDoorLight; + bool _isOpen; + int _countdown; + void update(); + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); + void stOpenDoor(); + void stCloseDoor(); +}; + +class SsScene2201PuzzleCube : public StaticSprite { +public: + SsScene2201PuzzleCube(NeverhoodEngine *vm, uint32 positionIndex, uint32 cubeIndex); +}; + +class SsScene2202PuzzleCube : public StaticSprite { +public: + SsScene2202PuzzleCube(NeverhoodEngine *vm, Scene *parentScene, int16 cubePosition, int16 cubeSymbol); +protected: + Scene *_parentScene; + int16 _cubeSymbol; + int16 _cubePosition; + int16 _newX, _newY; + int16 _xDelta, _yDelta; + int16 _xIncr; + int16 _yIncr; + int16 _errValue; + int16 _counter; + int16 _xFlagPos; + bool _counterDirection; + bool _isMoving; + void update(); + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); + void suMoveCubeX(); + void suMoveCubeY(); + void moveCube(int16 newCubePosition); + void stopMoving(); +}; + +class AsCommonKey : public AnimatedSprite { +public: + AsCommonKey(NeverhoodEngine *vm, Scene *parentScene, int keyIndex, int surfacePriority, int16 x, int16 y); +protected: + Scene *_parentScene; + int _keyIndex; + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); +}; + +class AsScene2203Door : public AnimatedSprite { +public: + AsScene2203Door(NeverhoodEngine *vm, Scene *parentScene, uint doorIndex); +protected: + Scene *_parentScene; + Sprite *_otherDoor; + uint _doorIndex; + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); + void openDoor(); + void closeDoor(); +}; + +class SsScene2205DoorFrame : public StaticSprite { +public: + SsScene2205DoorFrame(NeverhoodEngine *vm); +protected: + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); +}; + +class AsScene2206DoorSpikes : public StaticSprite { +public: + AsScene2206DoorSpikes(NeverhoodEngine *vm, uint32 fileHash); +protected: + int _deltaIndex; + void update(); + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); + void suOpen(); + void suClose(); +}; + +class AsScene2206Platform : public StaticSprite { +public: + AsScene2206Platform(NeverhoodEngine *vm, uint32 fileHash); +protected: + int16 _yDelta; + void update(); + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); + void suMoveDown(); +}; + +class SsScene2206TestTube : public StaticSprite { +public: + SsScene2206TestTube(NeverhoodEngine *vm, Scene *parentScene, int surfacePriority, uint32 fileHash); +protected: + Scene *_parentScene; + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); +}; + +class AsScene2207Elevator : public AnimatedSprite { +public: + AsScene2207Elevator(NeverhoodEngine *vm, Scene *parentScene); + ~AsScene2207Elevator(); +protected: + Scene *_parentScene; + NPointArray *_pointArray; + int16 _pointIndex; + int16 _destPointIndex, _destPointIndexDelta; + bool _isMoving; + void update(); + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); + void suSetPosition(); + void moveToY(int16 y); +}; + +class AsScene2207Lever : public AnimatedSprite { +public: + AsScene2207Lever(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y, int doDeltaX); +protected: + Scene *_parentScene; + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); + void stLeverDown(); + void stLeverDownEvent(); + void stLeverUp(); + void stLeverUpEvent(); +}; + +class AsScene2207WallRobotAnimation : public AnimatedSprite { +public: + AsScene2207WallRobotAnimation(NeverhoodEngine *vm, Scene *parentScene); + ~AsScene2207WallRobotAnimation(); +protected: + bool _idle; + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); + void stStartAnimation(); + void stStopAnimation(); + void cbStopAnimation(); +}; + +class AsScene2207WallCannonAnimation : public AnimatedSprite { +public: + AsScene2207WallCannonAnimation(NeverhoodEngine *vm); +protected: + bool _idle; + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); + void stStartAnimation(); + void stStopAnimation(); + void cbStopAnimation(); +}; + +class SsScene2207Symbol : public StaticSprite { +public: + SsScene2207Symbol(NeverhoodEngine *vm, uint32 fileHash, int index); +}; + +class KmScene2201 : public Klaymen { +public: + KmScene2201(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y, NRect *clipRects, int clipRectsCount); +protected: + uint32 xHandleMessage(int messageNum, const MessageParam ¶m); +}; + +class KmScene2203 : public Klaymen { +public: + KmScene2203(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); +protected: + void stClayDoorOpen(); + uint32 hmClayDoorOpen(int messageNum, const MessageParam ¶m, Entity *sender); + + uint32 xHandleMessage(int messageNum, const MessageParam ¶m); +}; + +class KmScene2205 : public Klaymen { +public: + KmScene2205(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); +protected: + void xUpdate(); + uint32 xHandleMessage(int messageNum, const MessageParam ¶m); +}; + +class KmScene2206 : public Klaymen { +public: + KmScene2206(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); + ~KmScene2206(); +protected: + void stRidePlatformDown(); + void suRidePlatformDown(); + + void xUpdate(); + uint32 xHandleMessage(int messageNum, const MessageParam ¶m); +}; + +class KmScene2207 : public Klaymen { +public: + KmScene2207(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); +protected: + uint32 xHandleMessage(int messageNum, const MessageParam ¶m); +}; + +class KmScene2242 : public Klaymen { +public: + KmScene2242(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); +protected: + void xUpdate(); + uint32 xHandleMessage(int messageNum, const MessageParam ¶m); +}; + +class KmHallOfRecords : public Klaymen { +public: + KmHallOfRecords(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); +protected: + void xUpdate(); + uint32 xHandleMessage(int messageNum, const MessageParam ¶m); +}; + +class KmScene2247 : public Klaymen { +public: + KmScene2247(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); +protected: + void xUpdate(); + uint32 xHandleMessage(int messageNum, const MessageParam ¶m); +}; + +} // End of namespace Neverhood + +#endif /* NEVERHOOD_MODULES_MODULE2200_SPRITES_H */ diff --git a/engines/neverhood/modules/module2300.cpp b/engines/neverhood/modules/module2300.cpp index 2a46df1ee2..689d53570f 100644 --- a/engines/neverhood/modules/module2300.cpp +++ b/engines/neverhood/modules/module2300.cpp @@ -20,8 +20,8 @@ * */ -#include "neverhood/modules/module2300.h" #include "neverhood/navigationscene.h" +#include "neverhood/modules/module2300.h" namespace Neverhood { diff --git a/engines/neverhood/modules/module2400.cpp b/engines/neverhood/modules/module2400.cpp index 21ea390ba2..dab39b24f6 100644 --- a/engines/neverhood/modules/module2400.cpp +++ b/engines/neverhood/modules/module2400.cpp @@ -20,7 +20,13 @@ * */ +#include "neverhood/modules/module1000_sprites.h" +#include "neverhood/modules/module1200_sprites.h" #include "neverhood/modules/module2400.h" +#include "neverhood/modules/module2100_sprites.h" +#include "neverhood/modules/module2200_sprites.h" +#include "neverhood/modules/module2400_sprites.h" +#include "neverhood/modules/module2800_sprites.h" namespace Neverhood { @@ -175,198 +181,6 @@ static const NRect kScene2401Rects[] = { { 465, 331, 491, 389 } }; -static const uint32 kAsScene2401WaterSpitFileHashes2[] = { - 0x5C044690, 0x5C644690, 0x5CA44690, - 0x5D244690, 0x5E244690 -}; - -static const uint32 kAsScene2401WaterSpitFileHashes1[] = { - 0xF4418408, 0xF4418808, 0xF4419008, - 0xF441A008, 0xCD4F8411 -}; - -AsScene2401WaterSpit::AsScene2401WaterSpit(NeverhoodEngine *vm) - : AnimatedSprite(vm, 1200) { - - _x = 240; - _y = 447; - createSurface(100, 146, 74); - setVisible(false); - SetUpdateHandler(&AnimatedSprite::update); - SetMessageHandler(&AsScene2401WaterSpit::handleMessage); - SetSpriteUpdate(&AnimatedSprite::updateDeltaXY); -} - -uint32 AsScene2401WaterSpit::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x100D: - if (param.asInteger() == 0x120A0013) - playSound(0, kAsScene2401WaterSpitFileHashes1[_soundIndex]); - break; - case 0x2000: - _x = 240; - _y = 447; - _soundIndex = getSubVar(VA_CURR_WATER_PIPES_LEVEL, param.asInteger()); - startAnimation(kAsScene2401WaterSpitFileHashes2[param.asInteger()], 0, -1); - setVisible(true); - playSound(0, 0x48640244); - break; - case 0x3002: - stopAnimation(); - setVisible(false); - break; - } - return messageResult; -} - -AsScene2401FlowingWater::AsScene2401FlowingWater(NeverhoodEngine *vm) - : AnimatedSprite(vm, 1200), _isWaterFlowing(false) { - - _x = 88; - _y = 421; - createSurface1(0x10203116, 100); - setVisible(false); - SetUpdateHandler(&AnimatedSprite::update); - SetMessageHandler(&AsScene2401FlowingWater::handleMessage); -} - -AsScene2401FlowingWater::~AsScene2401FlowingWater() { - _vm->_soundMan->deleteSoundGroup(0x40F11C09); -} - -uint32 AsScene2401FlowingWater::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x100D: - if (_isWaterFlowing && param.asInteger() == 0x02421405) - startAnimationByHash(0x10203116, 0x01084280, 0); - break; - case 0x2002: - if (!_isWaterFlowing) { - _vm->_soundMan->addSound(0x40F11C09, 0x980C1420); - _vm->_soundMan->playSoundLooping(0x980C1420); - startAnimation(0x10203116, 0, -1); - setVisible(true); - _isWaterFlowing = true; - } - break; - case 0x2003: - _vm->_soundMan->deleteSound(0x980C1420); - _isWaterFlowing = false; - break; - case 0x3002: - stopAnimation(); - setVisible(false); - break; - } - return messageResult; -} - -AsScene2401WaterFlushing::AsScene2401WaterFlushing(NeverhoodEngine *vm, int16 x, int16 y) - : AnimatedSprite(vm, 1200), _countdown(0), _flushLoopCount(0) { - - _x = x; - _y = y; - createSurface1(0xB8596884, 100); - setVisible(false); - SetUpdateHandler(&AsScene2401WaterFlushing::update); - SetMessageHandler(&AsScene2401WaterFlushing::handleMessage); -} - -void AsScene2401WaterFlushing::update() { - if (_countdown != 0 && (--_countdown) == 0) { - setDoDeltaX(_vm->_rnd->getRandomNumber(1)); - startAnimation(0xB8596884, 0, -1); - setVisible(true); - } - AnimatedSprite::update(); -} - -uint32 AsScene2401WaterFlushing::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x100D: - if (_flushLoopCount > 0 && param.asInteger() == 0x02421405) { - startAnimationByHash(0xB8596884, 0x01084280, 0); - _flushLoopCount--; - } - break; - case 0x2002: - if (param.asInteger() > 0) { - _flushLoopCount = param.asInteger() - 1; - _countdown = _vm->_rnd->getRandomNumber(3) + 1; - } - break; - case 0x3002: - stopAnimation(); - setVisible(false); - break; - } - return messageResult; -} - -AsScene2401Door::AsScene2401Door(NeverhoodEngine *vm, bool isOpen) - : AnimatedSprite(vm, 1100), _countdown(0), _isOpen(isOpen) { - - _x = 320; - _y = 240; - createSurface1(0x44687810, 100); - _newStickFrameIndex = STICK_LAST_FRAME; - if (_isOpen) { - stopAnimation(); - setVisible(false); - _countdown = 48; - } else { - startAnimation(0x44687810, 0, -1); - _newStickFrameIndex = 0; - } - SetUpdateHandler(&AsScene2401Door::update); - SetMessageHandler(&AsScene2401Door::handleMessage); -} - -void AsScene2401Door::update() { - if (_isOpen && _countdown != 0 && (--_countdown) == 0) { - _isOpen = false; - setVisible(true); - startAnimation(0x44687810, -1, -1); - _newStickFrameIndex = 0; - _playBackwards = true; - playSound(0, calcHash("fxDoorClose38")); - } - AnimatedSprite::update(); -} - -uint32 AsScene2401Door::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x2004: - if (_isOpen) - _countdown = 168; - messageResult = _isOpen ? 1 : 0; - break; - case 0x3002: - gotoNextState(); - break; - case 0x4808: - if (!_isOpen) { - _countdown = 168; - _isOpen = true; - setVisible(true); - startAnimation(0x44687810, 0, -1); - playSound(0, calcHash("fxDoorOpen38")); - NextState(&AsScene2401Door::stDoorOpenFinished); - } - break; - } - return messageResult; -} - -void AsScene2401Door::stDoorOpenFinished() { - stopAnimation(); - setVisible(false); -} - Scene2401::Scene2401(NeverhoodEngine *vm, Module *parentModule, int which) : Scene(vm, parentModule), _countdown1(0), _countdown2(0), _unkFlag(false), _soundToggle(false), _asWaterSpitIndex(0) { @@ -546,143 +360,6 @@ static const uint32 kScene2402FileHashes[] = { 0xD0910068, 0xD09100A8 }; -AsScene2402Door::AsScene2402Door(NeverhoodEngine *vm, Scene *parentScene, bool isOpen) - : AnimatedSprite(vm, 1100), _parentScene(parentScene), _isOpen(isOpen), _countdown(0) { - - _x = 320; - _y = 240; - createSurface1(0x80495831, 100); - if (_isOpen) { - startAnimation(0x80495831, -1, -1); - _newStickFrameIndex = STICK_LAST_FRAME; - _countdown = 48; - } else { - stopAnimation(); - setVisible(false); - } - SetUpdateHandler(&AsScene2402Door::update); - SetMessageHandler(&AsScene2402Door::handleMessage); -} - -void AsScene2402Door::update() { - if (_isOpen && _countdown != 0 && (--_countdown) == 0) { - _isOpen = false; - setVisible(true); - startAnimation(0x80495831, -1, -1); - _playBackwards = true; - playSound(0, calcHash("fxDoorClose38")); - NextState(&AsScene2402Door::stDoorClosingFinished); - } - AnimatedSprite::update(); -} - -uint32 AsScene2402Door::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x2000: - if (_isOpen) - _countdown = 144; - messageResult = _isOpen ? 1 : 0; - break; - case 0x3002: - gotoNextState(); - break; - case 0x4808: - _countdown = 144; - _isOpen = true; - setVisible(true); - startAnimation(0x80495831, 0, -1); - _newStickFrameIndex = STICK_LAST_FRAME; - playSound(0, calcHash("fxDoorOpen38")); - break; - } - return messageResult; -} - -void AsScene2402Door::stDoorClosingFinished() { - sendMessage(_parentScene, 0x2001, 0); - setVisible(false); -} - -AsScene2402TV::AsScene2402TV(NeverhoodEngine *vm, Klaymen *klaymen) - : AnimatedSprite(vm, 1100), _klaymen(klaymen), _countdown1(0), _countdown2(0) { - - _x = 260; - _y = 210; - createSurface(100, 127, 90); - setDoDeltaX(1); - SetMessageHandler(&Sprite::handleMessage); - if (!getGlobalVar(V_TV_JOKE_TOLD)) { - loadSound(0, 0x58208810); - _countdown1 = 48; - startAnimation(0x4919397A, 0, -1); - _newStickFrameIndex = 0; - SetUpdateHandler(&AsScene2402TV::upWait); - } else { - int16 frameIndex; - if (_klaymen->getX() > 320) - _currFrameIndex = 29; - frameIndex = CLIP<int16>((_klaymen->getX() - _x + 150) / 10, 0, 29); - startAnimation(0x050A0103, frameIndex, -1); - _newStickFrameIndex = frameIndex; - _countdown1 = 0; - SetUpdateHandler(&AsScene2402TV::upFocusKlaymen); - } -} - -AsScene2402TV::~AsScene2402TV() { - _vm->_soundMan->deleteSoundGroup(0x01520123); -} - -void AsScene2402TV::upWait() { - if (_countdown1 != 0 && (--_countdown1) == 0) { - startAnimation(0x4919397A, 0, -1); - SetMessageHandler(&AsScene2402TV::hmJoke); - NextState(&AsScene2402TV::stJokeFinished); - } - AnimatedSprite::update(); -} - -void AsScene2402TV::upFocusKlaymen() { - int16 frameIndex = CLIP<int16>((_klaymen->getX() - _x + 150) / 10, 0, 29); - if (frameIndex != _currFrameIndex) { - if (frameIndex > _currFrameIndex) - _currFrameIndex++; - else if (frameIndex < _currFrameIndex) - _currFrameIndex--; - startAnimation(0x050A0103, _currFrameIndex, -1); - _newStickFrameIndex = _currFrameIndex; - if (_countdown2 == 0) { - _vm->_soundMan->addSound(0x01520123, 0xC42D4528); - _vm->_soundMan->playSoundLooping(0xC42D4528); - } - _countdown2 = 5; - } else if (_countdown2 != 0 && (--_countdown2 == 0)) - _vm->_soundMan->deleteSound(0xC42D4528); - AnimatedSprite::update(); -} - -void AsScene2402TV::stJokeFinished() { - setGlobalVar(V_TV_JOKE_TOLD, 1); - startAnimation(0x050A0103, 0, -1); - _newStickFrameIndex = 0; - SetUpdateHandler(&AsScene2402TV::upFocusKlaymen); -} - -uint32 AsScene2402TV::hmJoke(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x100D: - if (param.asInteger() == 0x431EA0B0) - playSound(0); - break; - case 0x3002: - gotoNextState(); - break; - } - return messageResult; -} - Scene2402::Scene2402(NeverhoodEngine *vm, Module *parentModule, int which) : Scene(vm, parentModule), _countdown(0), _soundToggle(false) { diff --git a/engines/neverhood/modules/module2400.h b/engines/neverhood/modules/module2400.h index 3802c747f1..61603f3e00 100644 --- a/engines/neverhood/modules/module2400.h +++ b/engines/neverhood/modules/module2400.h @@ -27,13 +27,6 @@ #include "neverhood/module.h" #include "neverhood/scene.h" #include "neverhood/gamemodule.h" -#include "neverhood/modules/module1000.h" -#include "neverhood/modules/module1100.h" -#include "neverhood/modules/module1200.h" -#include "neverhood/modules/module2100.h" -#include "neverhood/modules/module2200.h" -#include "neverhood/modules/module2800.h" -#include "neverhood/modules/module2800_sprites.h" #include "neverhood/diskplayerscene.h" namespace Neverhood { @@ -51,44 +44,6 @@ protected: uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); }; -class AsScene2401WaterSpit : public AnimatedSprite { -public: - AsScene2401WaterSpit(NeverhoodEngine *vm); -protected: - int _soundIndex; - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); -}; - -class AsScene2401FlowingWater : public AnimatedSprite { -public: - AsScene2401FlowingWater(NeverhoodEngine *vm); - virtual ~AsScene2401FlowingWater(); -protected: - bool _isWaterFlowing; - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); -}; - -class AsScene2401WaterFlushing : public AnimatedSprite { -public: - AsScene2401WaterFlushing(NeverhoodEngine *vm, int16 x, int16 y); -protected: - int _countdown; - int _flushLoopCount; - void update(); - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); -}; - -class AsScene2401Door : public AnimatedSprite { -public: - AsScene2401Door(NeverhoodEngine *vm, bool isOpen); -protected: - int _countdown; - bool _isOpen; - void update(); - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); - void stDoorOpenFinished(); -}; - class Scene2401 : public Scene { public: Scene2401(NeverhoodEngine *vm, Module *parentModule, int which); @@ -112,32 +67,6 @@ protected: void playPipeSound(uint32 fileHash); }; -class AsScene2402Door : public AnimatedSprite { -public: - AsScene2402Door(NeverhoodEngine *vm, Scene *parentScene, bool isOpen); -protected: - Scene *_parentScene; - int _countdown; - bool _isOpen; - void update(); - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); - void stDoorClosingFinished(); -}; - -class AsScene2402TV : public AnimatedSprite { -public: - AsScene2402TV(NeverhoodEngine *vm, Klaymen *klaymen); - virtual ~AsScene2402TV(); -protected: - Klaymen *_klaymen; - int _countdown1; - int _countdown2; - void upWait(); - void upFocusKlaymen(); - void stJokeFinished(); - uint32 hmJoke(int messageNum, const MessageParam ¶m, Entity *sender); -}; - class Scene2402 : public Scene { public: Scene2402(NeverhoodEngine *vm, Module *parentModule, int which); diff --git a/engines/neverhood/modules/module2400_sprites.cpp b/engines/neverhood/modules/module2400_sprites.cpp new file mode 100644 index 0000000000..bf85b0dc37 --- /dev/null +++ b/engines/neverhood/modules/module2400_sprites.cpp @@ -0,0 +1,741 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "neverhood/modules/module2400_sprites.h" + +namespace Neverhood { + +static const uint32 kAsScene2401WaterSpitFileHashes2[] = { + 0x5C044690, 0x5C644690, 0x5CA44690, + 0x5D244690, 0x5E244690 +}; + +static const uint32 kAsScene2401WaterSpitFileHashes1[] = { + 0xF4418408, 0xF4418808, 0xF4419008, + 0xF441A008, 0xCD4F8411 +}; + +AsScene2401WaterSpit::AsScene2401WaterSpit(NeverhoodEngine *vm) + : AnimatedSprite(vm, 1200) { + + _x = 240; + _y = 447; + createSurface(100, 146, 74); + setVisible(false); + SetUpdateHandler(&AnimatedSprite::update); + SetMessageHandler(&AsScene2401WaterSpit::handleMessage); + SetSpriteUpdate(&AnimatedSprite::updateDeltaXY); +} + +uint32 AsScene2401WaterSpit::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x100D: + if (param.asInteger() == 0x120A0013) + playSound(0, kAsScene2401WaterSpitFileHashes1[_soundIndex]); + break; + case 0x2000: + _x = 240; + _y = 447; + _soundIndex = getSubVar(VA_CURR_WATER_PIPES_LEVEL, param.asInteger()); + startAnimation(kAsScene2401WaterSpitFileHashes2[param.asInteger()], 0, -1); + setVisible(true); + playSound(0, 0x48640244); + break; + case 0x3002: + stopAnimation(); + setVisible(false); + break; + } + return messageResult; +} + +AsScene2401FlowingWater::AsScene2401FlowingWater(NeverhoodEngine *vm) + : AnimatedSprite(vm, 1200), _isWaterFlowing(false) { + + _x = 88; + _y = 421; + createSurface1(0x10203116, 100); + setVisible(false); + SetUpdateHandler(&AnimatedSprite::update); + SetMessageHandler(&AsScene2401FlowingWater::handleMessage); +} + +AsScene2401FlowingWater::~AsScene2401FlowingWater() { + _vm->_soundMan->deleteSoundGroup(0x40F11C09); +} + +uint32 AsScene2401FlowingWater::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x100D: + if (_isWaterFlowing && param.asInteger() == 0x02421405) + startAnimationByHash(0x10203116, 0x01084280, 0); + break; + case 0x2002: + if (!_isWaterFlowing) { + _vm->_soundMan->addSound(0x40F11C09, 0x980C1420); + _vm->_soundMan->playSoundLooping(0x980C1420); + startAnimation(0x10203116, 0, -1); + setVisible(true); + _isWaterFlowing = true; + } + break; + case 0x2003: + _vm->_soundMan->deleteSound(0x980C1420); + _isWaterFlowing = false; + break; + case 0x3002: + stopAnimation(); + setVisible(false); + break; + } + return messageResult; +} + +AsScene2401WaterFlushing::AsScene2401WaterFlushing(NeverhoodEngine *vm, int16 x, int16 y) + : AnimatedSprite(vm, 1200), _countdown(0), _flushLoopCount(0) { + + _x = x; + _y = y; + createSurface1(0xB8596884, 100); + setVisible(false); + SetUpdateHandler(&AsScene2401WaterFlushing::update); + SetMessageHandler(&AsScene2401WaterFlushing::handleMessage); +} + +void AsScene2401WaterFlushing::update() { + if (_countdown != 0 && (--_countdown) == 0) { + setDoDeltaX(_vm->_rnd->getRandomNumber(1)); + startAnimation(0xB8596884, 0, -1); + setVisible(true); + } + AnimatedSprite::update(); +} + +uint32 AsScene2401WaterFlushing::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x100D: + if (_flushLoopCount > 0 && param.asInteger() == 0x02421405) { + startAnimationByHash(0xB8596884, 0x01084280, 0); + _flushLoopCount--; + } + break; + case 0x2002: + if (param.asInteger() > 0) { + _flushLoopCount = param.asInteger() - 1; + _countdown = _vm->_rnd->getRandomNumber(3) + 1; + } + break; + case 0x3002: + stopAnimation(); + setVisible(false); + break; + } + return messageResult; +} + +AsScene2401Door::AsScene2401Door(NeverhoodEngine *vm, bool isOpen) + : AnimatedSprite(vm, 1100), _countdown(0), _isOpen(isOpen) { + + _x = 320; + _y = 240; + createSurface1(0x44687810, 100); + _newStickFrameIndex = STICK_LAST_FRAME; + if (_isOpen) { + stopAnimation(); + setVisible(false); + _countdown = 48; + } else { + startAnimation(0x44687810, 0, -1); + _newStickFrameIndex = 0; + } + SetUpdateHandler(&AsScene2401Door::update); + SetMessageHandler(&AsScene2401Door::handleMessage); +} + +void AsScene2401Door::update() { + if (_isOpen && _countdown != 0 && (--_countdown) == 0) { + _isOpen = false; + setVisible(true); + startAnimation(0x44687810, -1, -1); + _newStickFrameIndex = 0; + _playBackwards = true; + playSound(0, calcHash("fxDoorClose38")); + } + AnimatedSprite::update(); +} + +uint32 AsScene2401Door::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x2004: + if (_isOpen) + _countdown = 168; + messageResult = _isOpen ? 1 : 0; + break; + case 0x3002: + gotoNextState(); + break; + case 0x4808: + if (!_isOpen) { + _countdown = 168; + _isOpen = true; + setVisible(true); + startAnimation(0x44687810, 0, -1); + playSound(0, calcHash("fxDoorOpen38")); + NextState(&AsScene2401Door::stDoorOpenFinished); + } + break; + } + return messageResult; +} + +void AsScene2401Door::stDoorOpenFinished() { + stopAnimation(); + setVisible(false); +} + +AsScene2402Door::AsScene2402Door(NeverhoodEngine *vm, Scene *parentScene, bool isOpen) + : AnimatedSprite(vm, 1100), _parentScene(parentScene), _isOpen(isOpen), _countdown(0) { + + _x = 320; + _y = 240; + createSurface1(0x80495831, 100); + if (_isOpen) { + startAnimation(0x80495831, -1, -1); + _newStickFrameIndex = STICK_LAST_FRAME; + _countdown = 48; + } else { + stopAnimation(); + setVisible(false); + } + SetUpdateHandler(&AsScene2402Door::update); + SetMessageHandler(&AsScene2402Door::handleMessage); +} + +void AsScene2402Door::update() { + if (_isOpen && _countdown != 0 && (--_countdown) == 0) { + _isOpen = false; + setVisible(true); + startAnimation(0x80495831, -1, -1); + _playBackwards = true; + playSound(0, calcHash("fxDoorClose38")); + NextState(&AsScene2402Door::stDoorClosingFinished); + } + AnimatedSprite::update(); +} + +uint32 AsScene2402Door::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x2000: + if (_isOpen) + _countdown = 144; + messageResult = _isOpen ? 1 : 0; + break; + case 0x3002: + gotoNextState(); + break; + case 0x4808: + _countdown = 144; + _isOpen = true; + setVisible(true); + startAnimation(0x80495831, 0, -1); + _newStickFrameIndex = STICK_LAST_FRAME; + playSound(0, calcHash("fxDoorOpen38")); + break; + } + return messageResult; +} + +void AsScene2402Door::stDoorClosingFinished() { + sendMessage(_parentScene, 0x2001, 0); + setVisible(false); +} + +AsScene2402TV::AsScene2402TV(NeverhoodEngine *vm, Klaymen *klaymen) + : AnimatedSprite(vm, 1100), _klaymen(klaymen), _countdown1(0), _countdown2(0) { + + _x = 260; + _y = 210; + createSurface(100, 127, 90); + setDoDeltaX(1); + SetMessageHandler(&Sprite::handleMessage); + if (!getGlobalVar(V_TV_JOKE_TOLD)) { + loadSound(0, 0x58208810); + _countdown1 = 48; + startAnimation(0x4919397A, 0, -1); + _newStickFrameIndex = 0; + SetUpdateHandler(&AsScene2402TV::upWait); + } else { + int16 frameIndex; + if (_klaymen->getX() > 320) + _currFrameIndex = 29; + frameIndex = CLIP<int16>((_klaymen->getX() - _x + 150) / 10, 0, 29); + startAnimation(0x050A0103, frameIndex, -1); + _newStickFrameIndex = frameIndex; + _countdown1 = 0; + SetUpdateHandler(&AsScene2402TV::upFocusKlaymen); + } +} + +AsScene2402TV::~AsScene2402TV() { + _vm->_soundMan->deleteSoundGroup(0x01520123); +} + +void AsScene2402TV::upWait() { + if (_countdown1 != 0 && (--_countdown1) == 0) { + startAnimation(0x4919397A, 0, -1); + SetMessageHandler(&AsScene2402TV::hmJoke); + NextState(&AsScene2402TV::stJokeFinished); + } + AnimatedSprite::update(); +} + +void AsScene2402TV::upFocusKlaymen() { + int16 frameIndex = CLIP<int16>((_klaymen->getX() - _x + 150) / 10, 0, 29); + if (frameIndex != _currFrameIndex) { + if (frameIndex > _currFrameIndex) + _currFrameIndex++; + else if (frameIndex < _currFrameIndex) + _currFrameIndex--; + startAnimation(0x050A0103, _currFrameIndex, -1); + _newStickFrameIndex = _currFrameIndex; + if (_countdown2 == 0) { + _vm->_soundMan->addSound(0x01520123, 0xC42D4528); + _vm->_soundMan->playSoundLooping(0xC42D4528); + } + _countdown2 = 5; + } else if (_countdown2 != 0 && (--_countdown2 == 0)) + _vm->_soundMan->deleteSound(0xC42D4528); + AnimatedSprite::update(); +} + +void AsScene2402TV::stJokeFinished() { + setGlobalVar(V_TV_JOKE_TOLD, 1); + startAnimation(0x050A0103, 0, -1); + _newStickFrameIndex = 0; + SetUpdateHandler(&AsScene2402TV::upFocusKlaymen); +} + +uint32 AsScene2402TV::hmJoke(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x100D: + if (param.asInteger() == 0x431EA0B0) + playSound(0); + break; + case 0x3002: + gotoNextState(); + break; + } + return messageResult; +} + +KmScene2401::KmScene2401(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) + : Klaymen(vm, parentScene, x, y), + _canSpitPipe(false), _contSpitPipe(false), _readyToSpit(false), + _spitPipeIndex(0), _spitDestPipeIndex(0), _spitContDestPipeIndex(0) { + + // Empty +} + +uint32 KmScene2401::xHandleMessage(int messageNum, const MessageParam ¶m) { + uint32 messageResult = 0; + switch (messageNum) { + case 0x4001: + case 0x4800: + startWalkToX(param.asPoint().x, false); + break; + case 0x4004: + GotoState(&Klaymen::stTryStandIdle); + break; + case 0x4816: + if (param.asInteger() == 1) + GotoState(&Klaymen::stPressButton); + else if (param.asInteger() == 2) + GotoState(&Klaymen::stPressFloorButton); + else + GotoState(&Klaymen::stPressButtonSide); + break; + case 0x4817: + setDoDeltaX(param.asInteger()); + gotoNextStateExt(); + break; + case 0x481B: + if (param.asPoint().y != 0) + startWalkToXDistance(param.asPoint().y, param.asPoint().x); + else + startWalkToAttachedSpriteXDistance(param.asPoint().x); + break; + case 0x481F: + if (param.asInteger() == 1) + GotoState(&Klaymen::stTurnAwayFromUse); + else if (param.asInteger() == 0) + GotoState(&Klaymen::stTurnToUseHalf); + else + GotoState(&Klaymen::stWonderAbout); + break; + case 0x482D: + setDoDeltaX(_x > (int16)param.asInteger() ? 1 : 0); + gotoNextStateExt(); + break; + case 0x482E: + if (param.asInteger() == 1) + GotoState(&Klaymen::stWalkToFrontNoStep); + else + GotoState(&Klaymen::stWalkToFront); + break; + case 0x482F: + if (param.asInteger() == 1) + GotoState(&Klaymen::stTurnToFront); + else + GotoState(&Klaymen::stTurnToBack); + break; + case 0x4832: + GotoState(&Klaymen::stUseTube); + break; + case 0x4833: + if (param.asInteger() == 1) + GotoState(&Klaymen::stWonderAbout); + else { + _spitPipeIndex = sendMessage(_parentScene, 0x2000, 0); + GotoState(&KmScene2401::stTrySpitIntoPipe); + } + break; + case 0x483F: + startSpecialWalkRight(param.asInteger()); + break; + case 0x4840: + startSpecialWalkLeft(param.asInteger()); + break; + } + return messageResult; +} + +uint32 KmScene2401::hmSpit(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Klaymen::hmLowLevelAnimation(messageNum, param, sender); + switch (messageNum) { + case 0x100D: + if (param.asInteger() == 0x16401CA6) { + _canSpitPipe = true; + if (_contSpitPipe) + spitIntoPipe(); + } else if (param.asInteger() == 0xC11C0008) { + _canSpitPipe = false; + _acceptInput = false; + _readyToSpit = false; + } else if (param.asInteger() == 0x018A0001) { + sendMessage(_parentScene, 0x2001, _spitDestPipeIndex); + } + break; + } + return messageResult; +} + +void KmScene2401::stTrySpitIntoPipe() { + if (_readyToSpit) { + _contSpitPipe = true; + _spitContDestPipeIndex = _spitPipeIndex; + if (_canSpitPipe) + spitIntoPipe(); + } else if (!stStartAction(AnimationCallback(&KmScene2401::stTrySpitIntoPipe))) { + _busyStatus = 2; + _acceptInput = true; + _spitDestPipeIndex = _spitPipeIndex; + _readyToSpit = true; + _canSpitPipe = false; + _contSpitPipe = false; + startAnimation(0x1808B150, 0, -1); + SetUpdateHandler(&Klaymen::update); + SetMessageHandler(&KmScene2401::hmSpit); + SetSpriteUpdate(NULL); + } +} + +void KmScene2401::spitIntoPipe() { + _contSpitPipe = false; + _spitDestPipeIndex = _spitContDestPipeIndex; + _canSpitPipe = false; + _acceptInput = false; + startAnimation(0x1B08B553, 0, -1); + SetUpdateHandler(&Klaymen::update); + SetMessageHandler(&KmScene2401::hmSpit); + SetSpriteUpdate(NULL); + NextState(&KmScene2401::stContSpitIntoPipe); +} + +void KmScene2401::stContSpitIntoPipe() { + _canSpitPipe = true; + _acceptInput = true; + startAnimationByHash(0x1808B150, 0x16401CA6, 0); + SetUpdateHandler(&Klaymen::update); + SetMessageHandler(&KmScene2401::hmSpit); + SetSpriteUpdate(NULL); +} + +KmScene2402::KmScene2402(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) + : Klaymen(vm, parentScene, x, y) { + + // Empty +} + +uint32 KmScene2402::xHandleMessage(int messageNum, const MessageParam ¶m) { + uint32 messageResult = 0; + switch (messageNum) { + case 0x4001: + case 0x4800: + startWalkToX(param.asPoint().x, false); + break; + case 0x4004: + if (!getGlobalVar(V_TV_JOKE_TOLD)) + GotoState(&Klaymen::stStandWonderAbout); + else + GotoState(&Klaymen::stTryStandIdle); + break; + case 0x4804: + if (param.asInteger() != 0) { + _destX = param.asInteger(); + GotoState(&Klaymen::stWalkingFirst); + } else + GotoState(&Klaymen::stPeekWall); + break; + case 0x4812: + GotoState(&Klaymen::stPickUpGeneric); + break; + case 0x4816: + if (param.asInteger() == 1) + GotoState(&Klaymen::stPressButton); + else if (param.asInteger() == 2) + GotoState(&Klaymen::stPressFloorButton); + else + GotoState(&Klaymen::stPressButtonSide); + break; + case 0x4817: + setDoDeltaX(param.asInteger()); + gotoNextStateExt(); + break; + case 0x481B: + if (param.asPoint().y != 0) + startWalkToXDistance(param.asPoint().y, param.asPoint().x); + else + startWalkToAttachedSpriteXDistance(param.asPoint().x); + break; + case 0x481F: + if (param.asInteger() == 0) + GotoState(&Klaymen::stWonderAboutHalf); + else if (param.asInteger() == 1) + GotoState(&Klaymen::stWonderAboutAfter); + else if (param.asInteger() == 3) + GotoState(&Klaymen::stTurnToUseHalf); + else if (param.asInteger() == 4) + GotoState(&Klaymen::stTurnAwayFromUse); + else + GotoState(&Klaymen::stWonderAbout); + break; + case 0x483F: + startSpecialWalkRight(param.asInteger()); + break; + case 0x4840: + startSpecialWalkLeft(param.asInteger()); + break; + } + return messageResult; +} + +KmScene2403::KmScene2403(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) + : Klaymen(vm, parentScene, x, y) { + + // Empty +} + +uint32 KmScene2403::xHandleMessage(int messageNum, const MessageParam ¶m) { + uint32 messageResult = 0; + switch (messageNum) { + case 0x4001: + case 0x4800: + startWalkToX(param.asPoint().x, false); + break; + case 0x4004: + GotoState(&Klaymen::stTryStandIdle); + break; + case 0x480D: + GotoState(&Klaymen::stPullCord); + break; + case 0x4812: + GotoState(&Klaymen::stPickUpGeneric); + break; + case 0x4816: + if (param.asInteger() == 1) + GotoState(&Klaymen::stPressButton); + else if (param.asInteger() == 2) + GotoState(&Klaymen::stPressFloorButton); + else + GotoState(&Klaymen::stPressButtonSide); + break; + case 0x4817: + setDoDeltaX(param.asInteger()); + gotoNextStateExt(); + break; + case 0x481B: + if (param.asPoint().y != 0) + startWalkToXDistance(param.asPoint().y, param.asPoint().x); + else + startWalkToAttachedSpriteXDistance(param.asPoint().x); + break; + case 0x481F: + if (param.asInteger() == 0) + GotoState(&Klaymen::stWonderAboutHalf); + else if (param.asInteger() == 1) + GotoState(&Klaymen::stWonderAboutAfter); + else if (param.asInteger() == 3) + GotoState(&Klaymen::stTurnToUseHalf); + else if (param.asInteger() == 4) + GotoState(&Klaymen::stTurnAwayFromUse); + else + GotoState(&Klaymen::stWonderAbout); + break; + case 0x4820: + sendMessage(_parentScene, 0x2000, 0); + GotoState(&Klaymen::stContinueClimbLadderUp); + break; + case 0x4821: + sendMessage(_parentScene, 0x2000, 0); + _destY = param.asInteger(); + GotoState(&Klaymen::stStartClimbLadderDown); + break; + case 0x4822: + sendMessage(_parentScene, 0x2000, 0); + _destY = param.asInteger(); + GotoState(&Klaymen::stStartClimbLadderUp); + break; + case 0x4823: + sendMessage(_parentScene, 0x2001, 0); + GotoState(&Klaymen::stClimbLadderHalf); + break; + case 0x482D: + setDoDeltaX(_x > (int16)param.asInteger() ? 1 : 0); + gotoNextStateExt(); + break; + case 0x483F: + startSpecialWalkRight(param.asInteger()); + break; + case 0x4840: + startSpecialWalkLeft(param.asInteger()); + break; + } + return messageResult; +} + +KmScene2406::KmScene2406(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y, NRect *clipRects, int clipRectsCount) + : Klaymen(vm, parentScene, x, y) { + + _surface->setClipRects(clipRects, clipRectsCount); +} + +uint32 KmScene2406::xHandleMessage(int messageNum, const MessageParam ¶m) { + uint32 messageResult = 0; + switch (messageNum) { + case 0x4001: + case 0x4800: + startWalkToX(param.asPoint().x, false); + break; + case 0x4004: + GotoState(&Klaymen::stTryStandIdle); + break; + case 0x4804: + if (param.asInteger() != 0) { + _destX = param.asInteger(); + GotoState(&Klaymen::stWalkingFirst); + } else + GotoState(&Klaymen::stPeekWall); + break; + case 0x4812: + if (param.asInteger() == 2) + GotoState(&Klaymen::stPickUpNeedle); + else if (param.asInteger() == 1) + GotoState(&Klaymen::stPickUpTube); + else + GotoState(&Klaymen::stPickUpGeneric); + break; + case 0x4817: + setDoDeltaX(param.asInteger()); + gotoNextStateExt(); + break; + case 0x481A: + GotoState(&Klaymen::stInsertDisk); + break; + case 0x481B: + if (param.asPoint().y != 0) + startWalkToXDistance(param.asPoint().y, param.asPoint().x); + else + startWalkToAttachedSpriteXDistance(param.asPoint().x); + break; + case 0x481D: + GotoState(&Klaymen::stTurnToUse); + break; + case 0x481E: + GotoState(&Klaymen::stReturnFromUse); + break; + case 0x481F: + if (param.asInteger() == 0) + GotoState(&Klaymen::stWonderAboutHalf); + else if (param.asInteger() == 1) + GotoState(&Klaymen::stWonderAboutAfter); + else if (param.asInteger() == 3) + GotoState(&Klaymen::stTurnToUseHalf); + else if (param.asInteger() == 4) + GotoState(&Klaymen::stTurnAwayFromUse); + else + GotoState(&Klaymen::stWonderAbout); + break; + case 0x4820: + sendMessage(_parentScene, 0x2000, 0); + GotoState(&Klaymen::stContinueClimbLadderUp); + break; + case 0x4821: + sendMessage(_parentScene, 0x2000, 0); + _destY = param.asInteger(); + GotoState(&Klaymen::stStartClimbLadderDown); + break; + case 0x4822: + sendMessage(_parentScene, 0x2000, 0); + _destY = param.asInteger(); + GotoState(&Klaymen::stStartClimbLadderUp); + break; + case 0x4823: + sendMessage(_parentScene, 0x2001, 0); + GotoState(&Klaymen::stClimbLadderHalf); + break; + case 0x483F: + startSpecialWalkRight(param.asInteger()); + break; + case 0x4840: + startSpecialWalkLeft(param.asInteger()); + break; + } + return messageResult; +} + +} // End of namespace Neverhood diff --git a/engines/neverhood/modules/module2400_sprites.h b/engines/neverhood/modules/module2400_sprites.h new file mode 100644 index 0000000000..a901eb101c --- /dev/null +++ b/engines/neverhood/modules/module2400_sprites.h @@ -0,0 +1,139 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef NEVERHOOD_MODULES_MODULE2400_SPRITES_H +#define NEVERHOOD_MODULES_MODULE2400_SPRITES_H + +#include "neverhood/neverhood.h" +#include "neverhood/module.h" +#include "neverhood/scene.h" +#include "neverhood/gamemodule.h" + +namespace Neverhood { + +class AsScene2401WaterSpit : public AnimatedSprite { +public: + AsScene2401WaterSpit(NeverhoodEngine *vm); +protected: + int _soundIndex; + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); +}; + +class AsScene2401FlowingWater : public AnimatedSprite { +public: + AsScene2401FlowingWater(NeverhoodEngine *vm); + virtual ~AsScene2401FlowingWater(); +protected: + bool _isWaterFlowing; + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); +}; + +class AsScene2401WaterFlushing : public AnimatedSprite { +public: + AsScene2401WaterFlushing(NeverhoodEngine *vm, int16 x, int16 y); +protected: + int _countdown; + int _flushLoopCount; + void update(); + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); +}; + +class AsScene2401Door : public AnimatedSprite { +public: + AsScene2401Door(NeverhoodEngine *vm, bool isOpen); +protected: + int _countdown; + bool _isOpen; + void update(); + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); + void stDoorOpenFinished(); +}; + +class AsScene2402Door : public AnimatedSprite { +public: + AsScene2402Door(NeverhoodEngine *vm, Scene *parentScene, bool isOpen); +protected: + Scene *_parentScene; + int _countdown; + bool _isOpen; + void update(); + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); + void stDoorClosingFinished(); +}; + +class AsScene2402TV : public AnimatedSprite { +public: + AsScene2402TV(NeverhoodEngine *vm, Klaymen *klaymen); + virtual ~AsScene2402TV(); +protected: + Klaymen *_klaymen; + int _countdown1; + int _countdown2; + void upWait(); + void upFocusKlaymen(); + void stJokeFinished(); + uint32 hmJoke(int messageNum, const MessageParam ¶m, Entity *sender); +}; + +class KmScene2401 : public Klaymen { +public: + KmScene2401(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); +protected: + bool _canSpitPipe; + bool _contSpitPipe; + bool _readyToSpit; + uint32 _spitPipeIndex; + uint32 _spitDestPipeIndex; + uint32 _spitContDestPipeIndex; + + void spitIntoPipe(); + void stTrySpitIntoPipe(); + void stContSpitIntoPipe(); + uint32 hmSpit(int messageNum, const MessageParam ¶m, Entity *sender); + + uint32 xHandleMessage(int messageNum, const MessageParam ¶m); +}; + +class KmScene2402 : public Klaymen { +public: + KmScene2402(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); +protected: + uint32 xHandleMessage(int messageNum, const MessageParam ¶m); +}; + +class KmScene2403 : public Klaymen { +public: + KmScene2403(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); +protected: + uint32 xHandleMessage(int messageNum, const MessageParam ¶m); +}; + +class KmScene2406 : public Klaymen { +public: + KmScene2406(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y, NRect *clipRects, int clipRectsCount); +protected: + uint32 xHandleMessage(int messageNum, const MessageParam ¶m); +}; + +} // End of namespace Neverhood + +#endif /* NEVERHOOD_MODULES_MODULE2400_SPRITES_H */ diff --git a/engines/neverhood/modules/module2500.cpp b/engines/neverhood/modules/module2500.cpp index 46ce2ba4fc..d0e60adf65 100644 --- a/engines/neverhood/modules/module2500.cpp +++ b/engines/neverhood/modules/module2500.cpp @@ -20,8 +20,12 @@ * */ +#include "neverhood/modules/module1600.h" // for Scene1608 +#include "neverhood/modules/module1600_sprites.h" #include "neverhood/modules/module2500.h" -#include "neverhood/modules/module1600.h" +#include "neverhood/modules/module2500_sprites.h" +#include "neverhood/modules/module2700.h" // for Scene2704 +#include "neverhood/modules/module2700_sprites.h" namespace Neverhood { @@ -470,54 +474,6 @@ void Scene2501::updateKlaymenClipRect() { _kmScene2501->setClipRect(0, 0, 640, 388); } -SsScene2504Button::SsScene2504Button(NeverhoodEngine *vm) - : StaticSprite(vm, 1400), _countdown(0), _isSoundPlaying(false) { - - loadSprite(0x070220D9, kSLFDefDrawOffset | kSLFDefPosition | kSLFDefCollisionBoundsOffset, 400); - setVisible(false); - loadSound(0, 0x4600204C); - loadSound(1, 0x408C0034); - loadSound(2, 0x44043000); - loadSound(3, 0x44045000); - SetMessageHandler(&SsScene2504Button::handleMessage); - SetUpdateHandler(&SsScene2504Button::update); -} - -void SsScene2504Button::update() { - updatePosition(); - if (_isSoundPlaying && !isSoundPlaying(0) && !isSoundPlaying(1)) { - playSound(3); - setVisible(false); - _isSoundPlaying = false; - } - if (_countdown != 0 && (--_countdown) == 0) { - if (getSubVar(VA_LOCKS_DISABLED, 0x01180951)) - playSound(0); - else - playSound(1); - _isSoundPlaying = true; - } -} - -uint32 SsScene2504Button::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x1011: - if (_countdown == 0 && !_isSoundPlaying) { - setVisible(true); - _countdown = 2; - if (getSubVar(VA_LOCKS_DISABLED, 0x01180951)) - setSubVar(VA_LOCKS_DISABLED, 0x01180951, 0); - else - setSubVar(VA_LOCKS_DISABLED, 0x01180951, 1); - playSound(2); - } - messageResult = 1; - break; - } - return messageResult; -} - Scene2504::Scene2504(NeverhoodEngine *vm, Module *parentModule, int which) : Scene(vm, parentModule) { diff --git a/engines/neverhood/modules/module2500.h b/engines/neverhood/modules/module2500.h index 07db7907d5..de6226ef0c 100644 --- a/engines/neverhood/modules/module2500.h +++ b/engines/neverhood/modules/module2500.h @@ -26,14 +26,10 @@ #include "neverhood/neverhood.h" #include "neverhood/module.h" #include "neverhood/scene.h" -#include "neverhood/modules/module1000.h" -#include "neverhood/modules/module1600.h" -#include "neverhood/modules/module2700.h" +#include "neverhood/modules/module1600_sprites.h" // for Tracks namespace Neverhood { -// Module2500 - class Module2500 : public Module { public: Module2500(NeverhoodEngine *vm, Module *parentModule, int which); @@ -47,6 +43,8 @@ protected: void createScene2704(int which, uint32 sceneInfoId, int16 value, const uint32 *staticSprites = NULL, const NRect *clipRect = NULL); }; +class AsCommonCar; + class Scene2501 : public Scene { public: Scene2501(NeverhoodEngine *vm, Module *parentModule, int which); @@ -79,16 +77,6 @@ protected: void updateKlaymenClipRect(); }; -class SsScene2504Button : public StaticSprite { -public: - SsScene2504Button(NeverhoodEngine *vm); -protected: - int _countdown; - bool _isSoundPlaying; - void update(); - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); -}; - class Scene2504 : public Scene { public: Scene2504(NeverhoodEngine *vm, Module *parentModule, int which); diff --git a/engines/neverhood/modules/module2500_sprites.cpp b/engines/neverhood/modules/module2500_sprites.cpp new file mode 100644 index 0000000000..ab6b3dcfbe --- /dev/null +++ b/engines/neverhood/modules/module2500_sprites.cpp @@ -0,0 +1,127 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "neverhood/modules/module2500_sprites.h" + +namespace Neverhood { + +SsScene2504Button::SsScene2504Button(NeverhoodEngine *vm) + : StaticSprite(vm, 1400), _countdown(0), _isSoundPlaying(false) { + + loadSprite(0x070220D9, kSLFDefDrawOffset | kSLFDefPosition | kSLFDefCollisionBoundsOffset, 400); + setVisible(false); + loadSound(0, 0x4600204C); + loadSound(1, 0x408C0034); + loadSound(2, 0x44043000); + loadSound(3, 0x44045000); + SetMessageHandler(&SsScene2504Button::handleMessage); + SetUpdateHandler(&SsScene2504Button::update); +} + +void SsScene2504Button::update() { + updatePosition(); + if (_isSoundPlaying && !isSoundPlaying(0) && !isSoundPlaying(1)) { + playSound(3); + setVisible(false); + _isSoundPlaying = false; + } + if (_countdown != 0 && (--_countdown) == 0) { + if (getSubVar(VA_LOCKS_DISABLED, 0x01180951)) + playSound(0); + else + playSound(1); + _isSoundPlaying = true; + } +} + +uint32 SsScene2504Button::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x1011: + if (_countdown == 0 && !_isSoundPlaying) { + setVisible(true); + _countdown = 2; + if (getSubVar(VA_LOCKS_DISABLED, 0x01180951)) + setSubVar(VA_LOCKS_DISABLED, 0x01180951, 0); + else + setSubVar(VA_LOCKS_DISABLED, 0x01180951, 1); + playSound(2); + } + messageResult = 1; + break; + } + return messageResult; +} + +KmScene2501::KmScene2501(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) + : Klaymen(vm, parentScene, x, y) { + + // Empty +} + +uint32 KmScene2501::xHandleMessage(int messageNum, const MessageParam ¶m) { + uint32 messageResult = 0; + switch (messageNum) { + case 0x2000: + _isSittingInTeleporter = param.asInteger() != 0; + messageResult = 1; + break; + case 0x4001: + case 0x4800: + startWalkToX(param.asPoint().x, false); + break; + case 0x4004: + if (_isSittingInTeleporter) + GotoState(&Klaymen::stSitIdleTeleporter); + else + GotoState(&Klaymen::stTryStandIdle); + break; + case 0x4817: + setDoDeltaX(param.asInteger()); + gotoNextStateExt(); + break; + case 0x481D: + if (_isSittingInTeleporter) + GotoState(&Klaymen::stTurnToUseInTeleporter); + break; + case 0x481E: + if (_isSittingInTeleporter) + GotoState(&Klaymen::stReturnFromUseInTeleporter); + break; + case 0x4834: + GotoState(&Klaymen::stStepOver); + break; + case 0x4835: + sendMessage(_parentScene, 0x2000, 1); + _isSittingInTeleporter = true; + GotoState(&Klaymen::stSitInTeleporter); + break; + case 0x4836: + sendMessage(_parentScene, 0x2000, 0); + _isSittingInTeleporter = false; + GotoState(&Klaymen::stGetUpFromTeleporter); + break; + } + return messageResult; +} + +} // End of namespace Neverhood diff --git a/engines/neverhood/modules/module2500_sprites.h b/engines/neverhood/modules/module2500_sprites.h new file mode 100644 index 0000000000..e7f7b05702 --- /dev/null +++ b/engines/neverhood/modules/module2500_sprites.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 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef NEVERHOOD_MODULES_MODULE2500_SPRITES_H +#define NEVERHOOD_MODULES_MODULE2500_SPRITES_H + +#include "neverhood/neverhood.h" +#include "neverhood/module.h" +#include "neverhood/scene.h" + +namespace Neverhood { + +class SsScene2504Button : public StaticSprite { +public: + SsScene2504Button(NeverhoodEngine *vm); +protected: + int _countdown; + bool _isSoundPlaying; + void update(); + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); +}; + +class KmScene2501 : public Klaymen { +public: + KmScene2501(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); +protected: + uint32 xHandleMessage(int messageNum, const MessageParam ¶m); +}; + +} // End of namespace Neverhood + +#endif /* NEVERHOOD_MODULES_MODULE2500_SPRITES_H */ diff --git a/engines/neverhood/modules/module2600.cpp b/engines/neverhood/modules/module2600.cpp index 2fce82b777..a6484a4926 100644 --- a/engines/neverhood/modules/module2600.cpp +++ b/engines/neverhood/modules/module2600.cpp @@ -21,6 +21,7 @@ */ #include "neverhood/modules/module2600.h" +#include "neverhood/modules/module2600_sprites.h" namespace Neverhood { @@ -219,94 +220,6 @@ void Module2600::updateScene() { } } -SsScene2609Button::SsScene2609Button(NeverhoodEngine *vm, Scene *parentScene) - : StaticSprite(vm, 1400), _parentScene(parentScene), _countdown(0) { - - SetUpdateHandler(&SsScene2609Button::update); - SetMessageHandler(&SsScene2609Button::handleMessage); - - loadSprite(0x825A6923, kSLFDefDrawOffset | kSLFDefPosition | kSLFDefCollisionBoundsOffset, 400); - if (!getGlobalVar(V_WATER_RUNNING)) - setVisible(false); - loadSound(0, 0x10267160); - loadSound(1, 0x7027FD64); - loadSound(2, 0x44043000); - loadSound(3, 0x44045000); -} - -void SsScene2609Button::update() { - updatePosition(); - if (_countdown != 0 && (--_countdown == 0)) { - if (getGlobalVar(V_WATER_RUNNING)) { - setGlobalVar(V_WATER_RUNNING, 0); - sendMessage(_parentScene, 0x2001, 0); - } else { - setGlobalVar(V_WATER_RUNNING, 1); - sendMessage(_parentScene, 0x2002, 0); - } - } -} - -uint32 SsScene2609Button::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x1011: - if (_countdown == 0) { - sendMessage(_parentScene, 0x2000, 0); - if (getGlobalVar(V_WATER_RUNNING)) { - setVisible(false); - playSound(3); - playSound(1); - _countdown = 12; - } else { - setVisible(true); - playSound(2); - playSound(0); - _countdown = 96; - } - } - messageResult = 1; - break; - } - return messageResult; -} - -AsScene2609Water::AsScene2609Water(NeverhoodEngine *vm) - : AnimatedSprite(vm, 1000) { - - _x = 240; - _y = 420; - setDoDeltaX(1); - createSurface1(0x9C210C90, 1200); - setClipRect(260, 260, 400, 368); - _vm->_soundMan->addSound(0x08526C36, 0xDC2769B0); - SetUpdateHandler(&AnimatedSprite::update); - SetMessageHandler(&AsScene2609Water::handleMessage); - if (getGlobalVar(V_WATER_RUNNING)) - sendMessage(this, 0x2002, 0); -} - -AsScene2609Water::~AsScene2609Water() { - _vm->_soundMan->deleteSoundGroup(0x08526C36); -} - -uint32 AsScene2609Water::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x2001: - stopAnimation(); - setVisible(false); - _vm->_soundMan->stopSound(0xDC2769B0); - break; - case 0x2002: - startAnimation(0x9C210C90, 0, -1); - setVisible(true); - _vm->_soundMan->playSoundLooping(0xDC2769B0); - break; - } - return messageResult; -} - Scene2609::Scene2609(NeverhoodEngine *vm, Module *parentModule, int which) : Scene(vm, parentModule), _isBusy(false) { diff --git a/engines/neverhood/modules/module2600.h b/engines/neverhood/modules/module2600.h index d972e0fb0d..99ec3a34ca 100644 --- a/engines/neverhood/modules/module2600.h +++ b/engines/neverhood/modules/module2600.h @@ -41,24 +41,6 @@ protected: void updateScene(); }; -class SsScene2609Button : public StaticSprite { -public: - SsScene2609Button(NeverhoodEngine *vm, Scene *parentScene); -protected: - Scene *_parentScene; - int _countdown; - void update(); - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); -}; - -class AsScene2609Water : public AnimatedSprite { -public: - AsScene2609Water(NeverhoodEngine *vm); - virtual ~AsScene2609Water(); -protected: - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); -}; - class Scene2609 : public Scene { public: Scene2609(NeverhoodEngine *vm, Module *parentModule, int which); diff --git a/engines/neverhood/modules/module2600_sprites.cpp b/engines/neverhood/modules/module2600_sprites.cpp new file mode 100644 index 0000000000..2c24b533f3 --- /dev/null +++ b/engines/neverhood/modules/module2600_sprites.cpp @@ -0,0 +1,115 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "neverhood/modules/module2600_sprites.h" + +namespace Neverhood { + +SsScene2609Button::SsScene2609Button(NeverhoodEngine *vm, Scene *parentScene) + : StaticSprite(vm, 1400), _parentScene(parentScene), _countdown(0) { + + SetUpdateHandler(&SsScene2609Button::update); + SetMessageHandler(&SsScene2609Button::handleMessage); + + loadSprite(0x825A6923, kSLFDefDrawOffset | kSLFDefPosition | kSLFDefCollisionBoundsOffset, 400); + if (!getGlobalVar(V_WATER_RUNNING)) + setVisible(false); + loadSound(0, 0x10267160); + loadSound(1, 0x7027FD64); + loadSound(2, 0x44043000); + loadSound(3, 0x44045000); +} + +void SsScene2609Button::update() { + updatePosition(); + if (_countdown != 0 && (--_countdown == 0)) { + if (getGlobalVar(V_WATER_RUNNING)) { + setGlobalVar(V_WATER_RUNNING, 0); + sendMessage(_parentScene, 0x2001, 0); + } else { + setGlobalVar(V_WATER_RUNNING, 1); + sendMessage(_parentScene, 0x2002, 0); + } + } +} + +uint32 SsScene2609Button::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x1011: + if (_countdown == 0) { + sendMessage(_parentScene, 0x2000, 0); + if (getGlobalVar(V_WATER_RUNNING)) { + setVisible(false); + playSound(3); + playSound(1); + _countdown = 12; + } else { + setVisible(true); + playSound(2); + playSound(0); + _countdown = 96; + } + } + messageResult = 1; + break; + } + return messageResult; +} + +AsScene2609Water::AsScene2609Water(NeverhoodEngine *vm) + : AnimatedSprite(vm, 1000) { + + _x = 240; + _y = 420; + setDoDeltaX(1); + createSurface1(0x9C210C90, 1200); + setClipRect(260, 260, 400, 368); + _vm->_soundMan->addSound(0x08526C36, 0xDC2769B0); + SetUpdateHandler(&AnimatedSprite::update); + SetMessageHandler(&AsScene2609Water::handleMessage); + if (getGlobalVar(V_WATER_RUNNING)) + sendMessage(this, 0x2002, 0); +} + +AsScene2609Water::~AsScene2609Water() { + _vm->_soundMan->deleteSoundGroup(0x08526C36); +} + +uint32 AsScene2609Water::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x2001: + stopAnimation(); + setVisible(false); + _vm->_soundMan->stopSound(0xDC2769B0); + break; + case 0x2002: + startAnimation(0x9C210C90, 0, -1); + setVisible(true); + _vm->_soundMan->playSoundLooping(0xDC2769B0); + break; + } + return messageResult; +} + +} // End of namespace Neverhood diff --git a/engines/neverhood/modules/module2600_sprites.h b/engines/neverhood/modules/module2600_sprites.h new file mode 100644 index 0000000000..c36e72cae8 --- /dev/null +++ b/engines/neverhood/modules/module2600_sprites.h @@ -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 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef NEVERHOOD_MODULES_MODULE2600_SPRITES_H +#define NEVERHOOD_MODULES_MODULE2600_SPRITES_H + +#include "neverhood/neverhood.h" +#include "neverhood/module.h" +#include "neverhood/scene.h" + +namespace Neverhood { + +// Module2600 + +class SsScene2609Button : public StaticSprite { +public: + SsScene2609Button(NeverhoodEngine *vm, Scene *parentScene); +protected: + Scene *_parentScene; + int _countdown; + void update(); + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); +}; + +class AsScene2609Water : public AnimatedSprite { +public: + AsScene2609Water(NeverhoodEngine *vm); + virtual ~AsScene2609Water(); +protected: + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); +}; + +} // End of namespace Neverhood + +#endif /* NEVERHOOD_MODULES_MODULE2600_SPRITES_H */ diff --git a/engines/neverhood/modules/module2700.cpp b/engines/neverhood/modules/module2700.cpp index 7aea82f6b1..1b78615fdb 100644 --- a/engines/neverhood/modules/module2700.cpp +++ b/engines/neverhood/modules/module2700.cpp @@ -20,9 +20,10 @@ * */ -#include "neverhood/modules/module2700.h" #include "neverhood/gamemodule.h" -#include "neverhood/modules/module1000.h" +#include "neverhood/modules/module1600_sprites.h" +#include "neverhood/modules/module2700.h" +#include "neverhood/modules/module2700_sprites.h" namespace Neverhood { @@ -536,83 +537,6 @@ void Module2700::createScene2704(int which, uint32 trackInfoId, int16 value, con _childObject = new Scene2704(_vm, this, which, trackInfoId, value, staticSprites, clipRect); } -static const NPoint kCarShadowOffsets[] = { - {-63, 3}, {-48, 40}, {-33, 58}, - { 0, 65}, { 40, 53}, { 56, 27}, - { 63, 0}, {-30, 26}, { 0, 30}, - { 26, 25} -}; - -SsCommonTrackShadowBackground::SsCommonTrackShadowBackground(NeverhoodEngine *vm, uint32 fileHash) - : StaticSprite(vm, 0) { - - loadSprite(fileHash, kSLFDefDrawOffset | kSLFDefPosition, 0); -} - -AsCommonCarShadow::AsCommonCarShadow(NeverhoodEngine *vm, AnimatedSprite *asCar, BaseSurface *shadowSurface, uint index) - : AnimatedSprite(vm, 1100), _asCar(asCar), _index(index), _animFileHash(0) { - - SetUpdateHandler(&AsCommonCarShadow::update); - createShadowSurface(shadowSurface, 211, 147, 100); - updateShadow(); -} - -void AsCommonCarShadow::update() { - updateShadow(); - AnimatedSprite::update(); -} - -void AsCommonCarShadow::updateShadow() { - if (_asCar->getFrameIndex() != _currFrameIndex || _asCar->getCurrAnimFileHash() != _animFileHash) { - uint32 fileHash = _asCar->getCurrAnimFileHash(); - if (fileHash == 0x35698F78 || fileHash == 0x192ADD30 || fileHash == 0x9C220DA4 || - fileHash == 0x9966B138 || fileHash == 0xB579A77C || fileHash == 0xA86A9538 || - fileHash == 0xD4220027 || fileHash == 0xD00A1364 || fileHash == 0xD4AA03A4 || - fileHash == 0xF46A0324) { - startAnimation(fileHash, _asCar->getFrameIndex(), -1); - _newStickFrameIndex = _asCar->getFrameIndex(); - } - _animFileHash = fileHash; - } - _x = _asCar->getX() + kCarShadowOffsets[_index].x; - _y = _asCar->getY() + kCarShadowOffsets[_index].y; - if (!_asCar->getVisible()) { - startAnimation(0x1209E09F, 0, -1); - _newStickFrameIndex = 0; - } - setDoDeltaX(_asCar->isDoDeltaX() ? 1 : 0); -} - -AsCommonCarConnectorShadow::AsCommonCarConnectorShadow(NeverhoodEngine *vm, Sprite *asCar, BaseSurface *shadowSurface, uint index) - : AnimatedSprite(vm, 1100), _asCar(asCar), _index(index) { - - SetUpdateHandler(&AsCommonCarConnectorShadow::update); - createShadowSurface1(shadowSurface, 0x60281C10, 150); - startAnimation(0x60281C10, -1, -1); - _newStickFrameIndex = STICK_LAST_FRAME; -} - -void AsCommonCarConnectorShadow::update() { - _x = _asCar->getX() + kCarShadowOffsets[_index].x; - _y = _asCar->getY() + kCarShadowOffsets[_index].y; - AnimatedSprite::update(); -} - -AsCommonCarTrackShadow::AsCommonCarTrackShadow(NeverhoodEngine *vm, Sprite *asCar, BaseSurface *shadowSurface, int16 frameIndex) - : AnimatedSprite(vm, 1100), _asCar(asCar) { - - SetUpdateHandler(&AsCommonCarTrackShadow::update); - createShadowSurface1(shadowSurface, 0x0759129C, 100); - startAnimation(0x0759129C, frameIndex, -1); - _newStickFrameIndex = frameIndex; -} - -void AsCommonCarTrackShadow::update() { - _x = _asCar->getX(); - _y = _asCar->getY(); - AnimatedSprite::update(); -} - Scene2701::Scene2701(NeverhoodEngine *vm, Module *parentModule, int which) : Scene(vm, parentModule) { diff --git a/engines/neverhood/modules/module2700.h b/engines/neverhood/modules/module2700.h index 158bb609e9..97b4f1cbea 100644 --- a/engines/neverhood/modules/module2700.h +++ b/engines/neverhood/modules/module2700.h @@ -26,7 +26,7 @@ #include "neverhood/neverhood.h" #include "neverhood/module.h" #include "neverhood/scene.h" -#include "neverhood/modules/module1600.h" +#include "neverhood/modules/module1600_sprites.h" // for Tracks namespace Neverhood { @@ -49,38 +49,7 @@ protected: void createScene2704(int which, uint32 trackInfoId, int16 value, const uint32 *staticSprites = NULL, const NRect *clipRect = NULL); }; -class SsCommonTrackShadowBackground : public StaticSprite { -public: - SsCommonTrackShadowBackground(NeverhoodEngine *vm, uint32 fileHash); -}; - -class AsCommonCarShadow : public AnimatedSprite { -public: - AsCommonCarShadow(NeverhoodEngine *vm, AnimatedSprite *asCar, BaseSurface *shadowSurface, uint index); -protected: - uint _index; - AnimatedSprite *_asCar; - uint32 _animFileHash; - void update(); - void updateShadow(); -}; - -class AsCommonCarConnectorShadow : public AnimatedSprite { -public: - AsCommonCarConnectorShadow(NeverhoodEngine *vm, Sprite *asCar, BaseSurface *shadowSurface, uint index); -protected: - uint _index; - Sprite *_asCar; - void update(); -}; - -class AsCommonCarTrackShadow : public AnimatedSprite { -public: - AsCommonCarTrackShadow(NeverhoodEngine *vm, Sprite *asCar, BaseSurface *shadowSurface, int16 frameIndex); -protected: - Sprite *_asCar; - void update(); -}; +class AsCommonCar; class Scene2701 : public Scene { public: diff --git a/engines/neverhood/modules/module2700_sprites.cpp b/engines/neverhood/modules/module2700_sprites.cpp new file mode 100644 index 0000000000..8dd2fa3461 --- /dev/null +++ b/engines/neverhood/modules/module2700_sprites.cpp @@ -0,0 +1,178 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "neverhood/modules/module2700_sprites.h" + +namespace Neverhood { + +static const NRect kScene2710ClipRect = { 0, 0, 626, 480 }; + +static const uint32 kScene2710StaticSprites[] = { + 0x0D2016C0, + 0 +}; + +static const NRect kScene2711ClipRect = { 0, 0, 521, 480 }; + +static const uint32 kScene2711FileHashes1[] = { + 0, + 0x100801A1, + 0x201081A0, + 0x006800A4, + 0x40390120, + 0x000001B1, + 0x001000A1, + 0 +}; + +static const uint32 kScene2711FileHashes2[] = { + 0, + 0x40403308, + 0x71403168, + 0x80423928, + 0x224131A8, + 0x50401328, + 0x70423328, + 0 +}; + +static const uint32 kScene2711FileHashes3[] = { + 0, + 0x1088A021, + 0x108120E5, + 0x18A02321, + 0x148221A9, + 0x10082061, + 0x188820E1, + 0 +}; + +static const NRect kScene2724ClipRect = { 0, 141, 640, 480 }; + +static const uint32 kScene2724StaticSprites[] = { + 0xC20D00A5, + 0 +}; + +static const NRect kScene2725ClipRect = { 0, 0, 640, 413 }; + +static const uint32 kScene2725StaticSprites[] = { + 0xC20E00A5, + 0 +}; + +static const NPoint kCarShadowOffsets[] = { + {-63, 3}, {-48, 40}, {-33, 58}, + { 0, 65}, { 40, 53}, { 56, 27}, + { 63, 0}, {-30, 26}, { 0, 30}, + { 26, 25} +}; + +SsCommonTrackShadowBackground::SsCommonTrackShadowBackground(NeverhoodEngine *vm, uint32 fileHash) + : StaticSprite(vm, 0) { + + loadSprite(fileHash, kSLFDefDrawOffset | kSLFDefPosition, 0); +} + +AsCommonCarShadow::AsCommonCarShadow(NeverhoodEngine *vm, AnimatedSprite *asCar, BaseSurface *shadowSurface, uint index) + : AnimatedSprite(vm, 1100), _asCar(asCar), _index(index), _animFileHash(0) { + + SetUpdateHandler(&AsCommonCarShadow::update); + createShadowSurface(shadowSurface, 211, 147, 100); + updateShadow(); +} + +void AsCommonCarShadow::update() { + updateShadow(); + AnimatedSprite::update(); +} + +void AsCommonCarShadow::updateShadow() { + if (_asCar->getFrameIndex() != _currFrameIndex || _asCar->getCurrAnimFileHash() != _animFileHash) { + uint32 fileHash = _asCar->getCurrAnimFileHash(); + if (fileHash == 0x35698F78 || fileHash == 0x192ADD30 || fileHash == 0x9C220DA4 || + fileHash == 0x9966B138 || fileHash == 0xB579A77C || fileHash == 0xA86A9538 || + fileHash == 0xD4220027 || fileHash == 0xD00A1364 || fileHash == 0xD4AA03A4 || + fileHash == 0xF46A0324) { + startAnimation(fileHash, _asCar->getFrameIndex(), -1); + _newStickFrameIndex = _asCar->getFrameIndex(); + } + _animFileHash = fileHash; + } + _x = _asCar->getX() + kCarShadowOffsets[_index].x; + _y = _asCar->getY() + kCarShadowOffsets[_index].y; + if (!_asCar->getVisible()) { + startAnimation(0x1209E09F, 0, -1); + _newStickFrameIndex = 0; + } + setDoDeltaX(_asCar->isDoDeltaX() ? 1 : 0); +} + +AsCommonCarConnectorShadow::AsCommonCarConnectorShadow(NeverhoodEngine *vm, Sprite *asCar, BaseSurface *shadowSurface, uint index) + : AnimatedSprite(vm, 1100), _asCar(asCar), _index(index) { + + SetUpdateHandler(&AsCommonCarConnectorShadow::update); + createShadowSurface1(shadowSurface, 0x60281C10, 150); + startAnimation(0x60281C10, -1, -1); + _newStickFrameIndex = STICK_LAST_FRAME; +} + +void AsCommonCarConnectorShadow::update() { + _x = _asCar->getX() + kCarShadowOffsets[_index].x; + _y = _asCar->getY() + kCarShadowOffsets[_index].y; + AnimatedSprite::update(); +} + +AsCommonCarTrackShadow::AsCommonCarTrackShadow(NeverhoodEngine *vm, Sprite *asCar, BaseSurface *shadowSurface, int16 frameIndex) + : AnimatedSprite(vm, 1100), _asCar(asCar) { + + SetUpdateHandler(&AsCommonCarTrackShadow::update); + createShadowSurface1(shadowSurface, 0x0759129C, 100); + startAnimation(0x0759129C, frameIndex, -1); + _newStickFrameIndex = frameIndex; +} + +void AsCommonCarTrackShadow::update() { + _x = _asCar->getX(); + _y = _asCar->getY(); + AnimatedSprite::update(); +} + +KmScene2732::KmScene2732(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) + : Klaymen(vm, parentScene, x, y) { + + // Empty +} + +uint32 KmScene2732::xHandleMessage(int messageNum, const MessageParam ¶m) { + switch (messageNum) { + case 0x4804: + GotoState(&Klaymen::stPeekInside); + break; + case 0x483C: + GotoState(&Klaymen::stPeekInsideReturn); + break; + } + return 0; +} + +} // End of namespace Neverhood diff --git a/engines/neverhood/modules/module2700_sprites.h b/engines/neverhood/modules/module2700_sprites.h new file mode 100644 index 0000000000..394ba896a1 --- /dev/null +++ b/engines/neverhood/modules/module2700_sprites.h @@ -0,0 +1,74 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef NEVERHOOD_MODULES_MODULE2700_SPRITES_H +#define NEVERHOOD_MODULES_MODULE2700_SPRITES_H + +#include "neverhood/neverhood.h" +#include "neverhood/module.h" +#include "neverhood/scene.h" + +namespace Neverhood { + +class SsCommonTrackShadowBackground : public StaticSprite { +public: + SsCommonTrackShadowBackground(NeverhoodEngine *vm, uint32 fileHash); +}; + +class AsCommonCarShadow : public AnimatedSprite { +public: + AsCommonCarShadow(NeverhoodEngine *vm, AnimatedSprite *asCar, BaseSurface *shadowSurface, uint index); +protected: + uint _index; + AnimatedSprite *_asCar; + uint32 _animFileHash; + void update(); + void updateShadow(); +}; + +class AsCommonCarConnectorShadow : public AnimatedSprite { +public: + AsCommonCarConnectorShadow(NeverhoodEngine *vm, Sprite *asCar, BaseSurface *shadowSurface, uint index); +protected: + uint _index; + Sprite *_asCar; + void update(); +}; + +class AsCommonCarTrackShadow : public AnimatedSprite { +public: + AsCommonCarTrackShadow(NeverhoodEngine *vm, Sprite *asCar, BaseSurface *shadowSurface, int16 frameIndex); +protected: + Sprite *_asCar; + void update(); +}; + +class KmScene2732 : public Klaymen { +public: + KmScene2732(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); +protected: + uint32 xHandleMessage(int messageNum, const MessageParam ¶m); +}; + +} // End of namespace Neverhood + +#endif /* NEVERHOOD_MODULES_MODULE2700_SPRITES_H */ diff --git a/engines/neverhood/modules/module2800.cpp b/engines/neverhood/modules/module2800.cpp index 3a33598090..0578a5df2e 100644 --- a/engines/neverhood/modules/module2800.cpp +++ b/engines/neverhood/modules/module2800.cpp @@ -20,14 +20,15 @@ * */ -#include "neverhood/modules/module2800.h" +#include "neverhood/diskplayerscene.h" #include "neverhood/gamemodule.h" -#include "neverhood/modules/module1000.h" -#include "neverhood/modules/module1200.h" -#include "neverhood/modules/module1700.h" -#include "neverhood/modules/module2200.h" +#include "neverhood/scene.h" +#include "neverhood/modules/module1000_sprites.h" +#include "neverhood/modules/module1200_sprites.h" +#include "neverhood/modules/module1700_sprites.h" +#include "neverhood/modules/module2200_sprites.h" +#include "neverhood/modules/module2800.h" #include "neverhood/modules/module2800_sprites.h" -#include "neverhood/diskplayerscene.h" namespace Neverhood { diff --git a/engines/neverhood/modules/module2800_sprites.cpp b/engines/neverhood/modules/module2800_sprites.cpp index f7949b97c8..a600c55dd3 100644 --- a/engines/neverhood/modules/module2800_sprites.cpp +++ b/engines/neverhood/modules/module2800_sprites.cpp @@ -22,12 +22,6 @@ #include "neverhood/modules/module2800.h" #include "neverhood/modules/module2800_sprites.h" -#include "neverhood/gamemodule.h" -#include "neverhood/modules/module1000.h" -#include "neverhood/modules/module1200.h" -#include "neverhood/modules/module1700.h" -#include "neverhood/modules/module2200.h" -#include "neverhood/diskplayerscene.h" namespace Neverhood { @@ -1017,4 +1011,616 @@ uint32 AsScene2812TrapDoor::handleMessage(int messageNum, const MessageParam &pa return messageResult; } +KmScene2801::KmScene2801(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) + : Klaymen(vm, parentScene, x, y) { + + // Empty +} + +uint32 KmScene2801::xHandleMessage(int messageNum, const MessageParam ¶m) { + switch (messageNum) { + case 0x4001: + case 0x4800: + startWalkToX(param.asPoint().x, false); + break; + case 0x4004: + GotoState(&Klaymen::stTryStandIdle); + break; + case 0x4812: + GotoState(&Klaymen::stPickUpGeneric); + break; + case 0x4817: + setDoDeltaX(param.asInteger()); + gotoNextStateExt(); + break; + case 0x481B: + if (param.asPoint().y != 0) + startWalkToXDistance(param.asPoint().y, param.asPoint().x); + else + startWalkToAttachedSpriteXDistance(param.asPoint().x); + break; + case 0x481D: + GotoState(&Klaymen::stTurnToUse); + break; + case 0x481E: + GotoState(&Klaymen::stReturnFromUse); + break; + case 0x481F: + if (param.asInteger() == 1) + GotoState(&Klaymen::stWonderAboutAfter); + else if (param.asInteger() == 0) + GotoState(&Klaymen::stWonderAboutHalf); + else if (param.asInteger() == 4) + GotoState(&Klaymen::stTurnAwayFromUse); + else if (param.asInteger() == 3) + GotoState(&Klaymen::stTurnToUseHalf); + else + GotoState(&Klaymen::stWonderAbout); + break; + case 0x482D: + setDoDeltaX(_x > (int16)param.asInteger() ? 1 : 0); + gotoNextStateExt(); + break; + case 0x482E: + if (param.asInteger() == 1) + GotoState(&Klaymen::stWalkToFrontNoStep); + else + GotoState(&Klaymen::stWalkToFront); + break; + case 0x482F: + if (param.asInteger() == 1) + GotoState(&Klaymen::stTurnToFront); + else + GotoState(&Klaymen::stTurnToBack); + break; + case 0x4837: + stopWalking(); + break; + } + return 0; +} + +KmScene2803::KmScene2803(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y, NRect *clipRects, int clipRectsCount) + : Klaymen(vm, parentScene, x, y) { + + _surface->setClipRects(clipRects, clipRectsCount); + _dataResource.load(0x00900849); +} + +uint32 KmScene2803::xHandleMessage(int messageNum, const MessageParam ¶m) { + switch (messageNum) { + case 0x4001: + case 0x4800: + startWalkToX(param.asPoint().x, false); + break; + case 0x4004: + GotoState(&Klaymen::stTryStandIdle); + break; + case 0x4803: + _destY = param.asInteger(); + GotoState(&Klaymen::stJumpToGrab); + break; + case 0x4804: + if (param.asInteger() == 3) + GotoState(&Klaymen::stFinishGrow); + break; + case 0x480D: + GotoState(&Klaymen::stPullCord); + break; + case 0x4817: + setDoDeltaX(param.asInteger()); + gotoNextStateExt(); + break; + case 0x4818: + startWalkToX(_dataResource.getPoint(param.asInteger()).x, false); + break; + case 0x481D: + GotoState(&Klaymen::stTurnToUse); + break; + case 0x481E: + GotoState(&Klaymen::stReturnFromUse); + break; + case 0x481F: + if (param.asInteger() == 1) + GotoState(&Klaymen::stWonderAboutAfter); + else + GotoState(&Klaymen::stWonderAboutHalf); + break; + case 0x482E: + GotoState(&Klaymen::stWalkToFront); + break; + case 0x482F: + GotoState(&Klaymen::stTurnToBack); + break; + case 0x4834: + GotoState(&Klaymen::stStepOver); + break; + case 0x4838: + GotoState(&Klaymen::stJumpToGrabRelease); + break; + } + return 0; +} + +KmScene2803Small::KmScene2803Small(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) + : Klaymen(vm, parentScene, x, y) { + + _dataResource.load(0x81120132); +} + +uint32 KmScene2803Small::xHandleMessage(int messageNum, const MessageParam ¶m) { + switch (messageNum) { + case 0x4001: + case 0x4800: + startWalkToXSmall(param.asPoint().x); + break; + case 0x4004: + GotoState(&Klaymen::stStandIdleSmall); + break; + case 0x4817: + setDoDeltaX(param.asInteger()); + gotoNextStateExt(); + break; + case 0x4818: + startWalkToXSmall(_dataResource.getPoint(param.asInteger()).x); + break; + case 0x481F: + if (param.asInteger() == 1) + GotoState(&Klaymen::stWonderAboutAfterSmall); + else if (param.asInteger() == 0) + GotoState(&Klaymen::stWonderAboutHalfSmall); + else + GotoState(&Klaymen::stWonderAboutSmall); + break; + case 0x482E: + if (param.asInteger() == 1) + GotoState(&Klaymen::stWalkToFrontNoStepSmall); + else if (param.asInteger() == 2) + GotoState(&Klaymen::stWalkToFront2Small); + else + GotoState(&Klaymen::stWalkToFrontSmall); + break; + case 0x482F: + if (param.asInteger() == 1) + GotoState(&Klaymen::stTurnToBackHalfSmall); + else if (param.asInteger() == 2) + GotoState(&Klaymen::stTurnToBackWalkSmall); + else + GotoState(&Klaymen::stTurnToBackSmall); + break; + case 0x4830: + GotoState(&KmScene2803Small::stShrink); + break; + } + return 0; +} + +uint32 KmScene2803Small::hmShrink(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = hmLowLevelAnimation(messageNum, param, sender); + switch (messageNum) { + case 0x100D: + if (param.asInteger() == 0x80C110B5) + sendMessage(_parentScene, 0x482A, 0); + else if (param.asInteger() == 0x33288344) + playSound(2, 0x10688664); + break; + } + return messageResult; +} + +void KmScene2803Small::stShrink() { + _busyStatus = 0; + _acceptInput = false; + playSound(0, 0x4C69EA53); + startAnimation(0x1AE88904, 0, -1); + SetUpdateHandler(&Klaymen::update); + SetMessageHandler(&KmScene2803Small::hmShrink); + SetSpriteUpdate(&AnimatedSprite::updateDeltaXY); +} + +KmScene2805::KmScene2805(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) + : Klaymen(vm, parentScene, x, y) { + + // Empty +} + +uint32 KmScene2805::xHandleMessage(int messageNum, const MessageParam ¶m) { + uint32 messageResult = 0; + switch (messageNum) { + case 0x2000: + _isSittingInTeleporter = param.asInteger() != 0; + messageResult = 1; + break; + case 0x4001: + case 0x4800: + startWalkToX(param.asPoint().x, false); + break; + case 0x4004: + if (_isSittingInTeleporter) + GotoState(&Klaymen::stSitIdleTeleporter); + else + GotoState(&Klaymen::stTryStandIdle); + break; + case 0x4817: + setDoDeltaX(param.asInteger()); + gotoNextStateExt(); + break; + case 0x481D: + if (_isSittingInTeleporter) + GotoState(&Klaymen::stTurnToUseInTeleporter); + break; + case 0x481E: + if (_isSittingInTeleporter) + GotoState(&Klaymen::stReturnFromUseInTeleporter); + break; + case 0x4834: + GotoState(&Klaymen::stStepOver); + break; + case 0x4835: + sendMessage(_parentScene, 0x2000, 1); + _isSittingInTeleporter = true; + GotoState(&Klaymen::stSitInTeleporter); + break; + case 0x4836: + sendMessage(_parentScene, 0x2000, 0); + _isSittingInTeleporter = false; + GotoState(&Klaymen::stGetUpFromTeleporter); + break; + case 0x483D: + teleporterAppear(0xDE284B74); + break; + case 0x483E: + teleporterDisappear(0xD82A4094); + break; + } + return messageResult; +} + +KmScene2806::KmScene2806(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y, + bool needsLargeSurface, NRect *clipRects, uint clipRectsCount) + : Klaymen(vm, parentScene, x, y) { + + if (needsLargeSurface) { + NDimensions dimensions = _animResource.loadSpriteDimensions(0x2838C010); + delete _surface; + createSurface(1000, dimensions.width, dimensions.height); + loadSound(3, 0x58E0C341); + loadSound(4, 0x40A00342); + loadSound(5, 0xD0A1C348); + loadSound(6, 0x166FC6E0); + loadSound(7, 0x00018040); + } + + _dataResource.load(0x98182003); + _surface->setClipRects(clipRects, clipRectsCount); +} + +uint32 KmScene2806::xHandleMessage(int messageNum, const MessageParam ¶m) { + switch (messageNum) { + case 0x4001: + case 0x4800: + startWalkToX(param.asPoint().x, false); + break; + case 0x4004: + GotoState(&Klaymen::stTryStandIdle); + break; + case 0x4804: + startWalkToX(440, true); + break; + case 0x480D: + GotoState(&Klaymen::stPullCord); + break; + case 0x4816: + if (param.asInteger() == 0) + GotoState(&Klaymen::stPressButtonSide); + break; + case 0x4817: + setDoDeltaX(param.asInteger()); + gotoNextStateExt(); + break; + case 0x4818: + startWalkToX(_dataResource.getPoint(param.asInteger()).x, false); + break; + case 0x4831: + GotoState(&Klaymen::stGrow); + break; + case 0x4832: + if (param.asInteger() == 1) + GotoState(&Klaymen::stDrinkPotion); + else + GotoState(&Klaymen::stUseTube); + break; + } + return 0; +} + +KmScene2809::KmScene2809(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y, + bool needsLargeSurface, NRect *clipRects, uint clipRectsCount) + : Klaymen(vm, parentScene, x, y) { + + if (needsLargeSurface) { + NDimensions dimensions = _animResource.loadSpriteDimensions(0x2838C010); + delete _surface; + createSurface(1000, dimensions.width, dimensions.height); + loadSound(3, 0x58E0C341); + loadSound(4, 0x40A00342); + loadSound(5, 0xD0A1C348); + loadSound(6, 0x166FC6E0); + loadSound(7, 0x00018040); + } + + _dataResource.load(0x1830009A); + _surface->setClipRects(clipRects, clipRectsCount); +} + +uint32 KmScene2809::xHandleMessage(int messageNum, const MessageParam ¶m) { + switch (messageNum) { + case 0x4001: + case 0x4800: + startWalkToX(param.asPoint().x, false); + break; + case 0x4004: + GotoState(&Klaymen::stTryStandIdle); + break; + case 0x4804: + startWalkToX(226, true); + break; + case 0x480D: + GotoState(&Klaymen::stPullCord); + break; + case 0x4816: + if (param.asInteger() == 0) + GotoState(&Klaymen::stPressButtonSide); + break; + case 0x4817: + setDoDeltaX(param.asInteger()); + gotoNextStateExt(); + break; + case 0x4818: + startWalkToX(_dataResource.getPoint(param.asInteger()).x, false); + break; + case 0x4831: + GotoState(&Klaymen::stGrow); + break; + case 0x4832: + if (param.asInteger() == 1) + GotoState(&Klaymen::stDrinkPotion); + else + GotoState(&Klaymen::stUseTube); + break; + } + return 0; +} + +KmScene2810Small::KmScene2810Small(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) + : Klaymen(vm, parentScene, x, y) { + + // Empty +} + +uint32 KmScene2810Small::xHandleMessage(int messageNum, const MessageParam ¶m) { + switch (messageNum) { + case 0x4001: + case 0x4800: + startWalkToXSmall(param.asPoint().x); + break; + case 0x4004: + GotoState(&Klaymen::stStandIdleSmall); + break; + case 0x4817: + setDoDeltaX(param.asInteger()); + gotoNextStateExt(); + break; + case 0x4818: + startWalkToXSmall(_dataResource.getPoint(param.asInteger()).x); + break; + case 0x481F: + if (param.asInteger() == 1) + GotoState(&Klaymen::stWonderAboutAfterSmall); + else if (param.asInteger() == 0) + GotoState(&Klaymen::stWonderAboutHalfSmall); + else + GotoState(&Klaymen::stWonderAboutSmall); + break; + case 0x482E: + if (param.asInteger() == 1) + GotoState(&Klaymen::stWalkToFrontNoStepSmall); + else + GotoState(&Klaymen::stWalkToFrontSmall); + break; + case 0x482F: + if (param.asInteger() == 1) + GotoState(&Klaymen::stTurnToBackHalfSmall); + else + GotoState(&Klaymen::stTurnToBackSmall); + break; + case 0x4837: + stopWalking(); + break; + } + return 0; +} + +KmScene2810::KmScene2810(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y, NRect *clipRects, uint clipRectsCount) + : Klaymen(vm, parentScene, x, y) { + + _surface->setClipRects(clipRects, clipRectsCount); +} + +uint32 KmScene2810::xHandleMessage(int messageNum, const MessageParam ¶m) { + switch (messageNum) { + case 0x4001: + case 0x4800: + startWalkToX(param.asPoint().x, false); + break; + case 0x4004: + GotoState(&Klaymen::stTryStandIdle); + break; + case 0x4803: + _destY = param.asInteger(); + GotoState(&Klaymen::stJumpToGrab); + break; + case 0x4804: + if (param.asInteger() == 3) + GotoState(&Klaymen::stFinishGrow); + break; + case 0x4812: + GotoState(&Klaymen::stPickUpGeneric); + break; + case 0x4817: + setDoDeltaX(param.asInteger()); + gotoNextStateExt(); + break; + case 0x4818: + startWalkToX(_dataResource.getPoint(param.asInteger()).x, false); + break; + case 0x481B: + if (param.asPoint().y != 0) + startWalkToXDistance(param.asPoint().y, param.asPoint().x); + else + startWalkToAttachedSpriteXDistance(param.asPoint().x); + break; + case 0x481F: + if (param.asInteger() == 0) + GotoState(&Klaymen::stWonderAboutHalf); + else if (param.asInteger() == 1) + GotoState(&Klaymen::stWonderAboutAfter); + else if (param.asInteger() == 3) + GotoState(&Klaymen::stTurnToUseHalf); + else if (param.asInteger() == 4) + GotoState(&Klaymen::stTurnAwayFromUse); + else if (param.asInteger() == 5) + GotoState(&Klaymen::stTurnToUseExt); + else + GotoState(&Klaymen::stWonderAbout); + break; + case 0x4820: + sendMessage(_parentScene, 0x2000, 0); + GotoState(&Klaymen::stContinueClimbLadderUp); + break; + case 0x4821: + sendMessage(_parentScene, 0x2000, 0); + _destY = param.asInteger(); + GotoState(&Klaymen::stStartClimbLadderDown); + break; + case 0x4822: + sendMessage(_parentScene, 0x2000, 0); + _destY = param.asInteger(); + GotoState(&Klaymen::stStartClimbLadderUp); + break; + case 0x4823: + sendMessage(_parentScene, 0x2001, 0); + GotoState(&Klaymen::stClimbLadderHalf); + break; + case 0x4824: + sendMessage(_parentScene, 0x2000, 0); + _destY = _dataResource.getPoint(param.asInteger()).y; + GotoState(&Klaymen::stStartClimbLadderDown); + break; + case 0x4825: + sendMessage(_parentScene, 0x2000, 0); + _destY = _dataResource.getPoint(param.asInteger()).y; + GotoState(&Klaymen::stStartClimbLadderUp); + break; + case 0x482D: + setDoDeltaX(_x > (int16)param.asInteger() ? 1 : 0); + gotoNextStateExt(); + break; + case 0x4837: + stopWalking(); + break; + } + return 0; +} + +KmScene2812::KmScene2812(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) + : Klaymen(vm, parentScene, x, y) { + + // Empty +} + +uint32 KmScene2812::xHandleMessage(int messageNum, const MessageParam ¶m) { + switch (messageNum) { + case 0x4001: + case 0x4800: + startWalkToX(param.asPoint().x, false); + break; + case 0x4004: + GotoState(&Klaymen::stTryStandIdle); + break; + case 0x4805: + _destY = param.asInteger(); + GotoState(&Klaymen::stJumpToGrabFall); + break; + case 0x4812: + if (param.asInteger() == 2) + GotoState(&Klaymen::stPickUpNeedle); + else if (param.asInteger() == 1) + GotoState(&Klaymen::stPickUpTube); + else + GotoState(&Klaymen::stPickUpGeneric); + break; + case 0x4817: + setDoDeltaX(param.asInteger()); + gotoNextStateExt(); + break; + case 0x481A: + GotoState(&Klaymen::stInsertDisk); + break; + case 0x481B: + if (param.asPoint().y != 0) + startWalkToXDistance(param.asPoint().y, param.asPoint().x); + else + startWalkToAttachedSpriteXDistance(param.asPoint().x); + break; + case 0x481D: + GotoState(&Klaymen::stTurnToUse); + break; + case 0x481E: + GotoState(&Klaymen::stReturnFromUse); + break; + case 0x4820: + sendMessage(_parentScene, 0x2001, 0); + GotoState(&Klaymen::stContinueClimbLadderUp); + break; + case 0x4821: + sendMessage(_parentScene, 0x2001, 0); + _destY = param.asInteger(); + GotoState(&Klaymen::stStartClimbLadderDown); + break; + case 0x4822: + sendMessage(_parentScene, 0x2001, 0); + _destY = param.asInteger(); + GotoState(&Klaymen::stStartClimbLadderUp); + break; + case 0x4823: + sendMessage(_parentScene, 0x2002, 0); + GotoState(&Klaymen::stClimbLadderHalf); + break; + case 0x482D: + setDoDeltaX(_x > (int16)param.asInteger() ? 1 : 0); + gotoNextStateExt(); + break; + case 0x482E: + if (param.asInteger() == 1) + GotoState(&Klaymen::stWalkToFrontNoStep); + else + GotoState(&Klaymen::stWalkToFront); + break; + case 0x482F: + if (param.asInteger() == 1) + GotoState(&Klaymen::stTurnToFront); + else + GotoState(&Klaymen::stTurnToBack); + break; + case 0x483F: + startSpecialWalkRight(param.asInteger()); + break; + case 0x4840: + startSpecialWalkLeft(param.asInteger()); + break; + } + return 0; +} + } // End of namespace Neverhood diff --git a/engines/neverhood/modules/module2800_sprites.h b/engines/neverhood/modules/module2800_sprites.h index 39ca88ef73..91f26d7849 100644 --- a/engines/neverhood/modules/module2800_sprites.h +++ b/engines/neverhood/modules/module2800_sprites.h @@ -263,6 +263,75 @@ protected: uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); }; +class KmScene2801 : public Klaymen { +public: + KmScene2801(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); +protected: + uint32 xHandleMessage(int messageNum, const MessageParam ¶m); +}; + +class KmScene2803 : public Klaymen { +public: + KmScene2803(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y, NRect *clipRects, int clipRectsCount); +protected: + uint32 xHandleMessage(int messageNum, const MessageParam ¶m); +}; + +class KmScene2803Small : public Klaymen { +public: + KmScene2803Small(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); +protected: + void stShrink(); + uint32 hmShrink(int messageNum, const MessageParam ¶m, Entity *sender); + + uint32 xHandleMessage(int messageNum, const MessageParam ¶m); +}; + +class KmScene2805 : public Klaymen { +public: + KmScene2805(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); +protected: + uint32 xHandleMessage(int messageNum, const MessageParam ¶m); +}; + +class KmScene2806 : public Klaymen { +public: + KmScene2806(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y, + bool needsLargeSurface, NRect *clipRects, uint clipRectsCount); +protected: + uint32 xHandleMessage(int messageNum, const MessageParam ¶m); +}; + +class KmScene2809 : public Klaymen { +public: + KmScene2809(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y, + bool needsLargeSurface, NRect *clipRects, uint clipRectsCount); +protected: + uint32 xHandleMessage(int messageNum, const MessageParam ¶m); +}; + +class KmScene2810Small : public Klaymen { +public: + KmScene2810Small(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); +protected: + uint32 xHandleMessage(int messageNum, const MessageParam ¶m); +}; + +class KmScene2810 : public Klaymen { +public: + KmScene2810(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y, + NRect *clipRects, uint clipRectsCount); +protected: + uint32 xHandleMessage(int messageNum, const MessageParam ¶m); +}; + +class KmScene2812 : public Klaymen { +public: + KmScene2812(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); +protected: + uint32 xHandleMessage(int messageNum, const MessageParam ¶m); +}; + } // End of namespace Neverhood #endif /* NEVERHOOD_MODULES_MODULE2800_SPRITES_H */ diff --git a/engines/neverhood/modules/module2900.cpp b/engines/neverhood/modules/module2900.cpp index 9e51001a2e..bb0b69f35d 100644 --- a/engines/neverhood/modules/module2900.cpp +++ b/engines/neverhood/modules/module2900.cpp @@ -21,7 +21,7 @@ */ #include "neverhood/modules/module2900.h" -#include "neverhood/gamemodule.h" +#include "neverhood/modules/module2900_sprites.h" #include "neverhood/modules/module1100.h" #include "neverhood/modules/module1300.h" #include "neverhood/modules/module1700.h" @@ -141,211 +141,6 @@ static const uint32 kScene2901FileHashes2[] = { 0x08030029 }; -static const uint32 kSsScene2901LocationButtonFileHashes[] = { - 0x2311326A, - 0x212323AC, - 0x10098138, - 0x25213167, - 0x1119A363, - 0x94452612, - 0x39464212, - 0x01860450, - 0x53002104, - 0x58E68412, - 0x18600300, - 0xB650A890, - 0x2452A7C4, - 0xA0232748, - 0x08862B02, - 0x2491E648, - 0x0010EB46, - 0x214C8A11, - 0x16A31921, - 0x0AC33A00, - 0x238028AA, - 0x26737A21, - 0x063039A8, - 0x51286C60, - 0x464006B4, - 0x42242538, - 0x20716010, - 0x4A2000AE, - 0x225124A6, - 0x28E82E45, - 0x58652C04, - 0xC82210A4, - 0x62A84060, - 0xC0693CB4, - 0x22212C64, - 0x5034EA71 -}; - -static const NPoint kSsScene2901LocationButtonPoints[] = { - {525, 120}, {576, 149}, {587, 205}, - {538, 232}, {484, 205}, {479, 153} -}; - -static const uint32 kSsScene2901LocationButtonLightFileHashes1[] = { - 0x03136246, - 0x2106216E, - 0x4025A13A, - 0x21816927, - 0x110B2202, - 0xCC0522B2, - 0x3CC24258, - 0x59C600F0, - 0x534A2480, - 0x50E61019, - 0x34400150, - 0x225BA090, - 0xB059AFC4, - 0xE093A741, - 0x0086BF09, - 0x3281E760, - 0xA048AB42, - 0x20649C01, - 0x14611904, - 0x26E33850, - 0x23A52A68, - 0xA2733024, - 0x10203880, - 0x1B2DE860, - 0x0644A6EC, - 0x426E20BC, - 0x80292014, - 0x4360B02E, - 0x22742664, - 0x98682705, - 0x0925B82C, - 0x5C2918A4, - 0xD2284920, - 0x41083CA6, - 0x6824A864, - 0x50266B10 -}; - -static const uint32 kSsScene2901LocationButtonLightFileHashes2[] = { - 0x43C46D4C, - 0x43C4AD4C, - 0x43C52D4C, - 0x43C62D4C, - 0x43C02D4C, - 0x43CC2D4C -}; - -static const uint32 kSsScene2901BrokenButtonFileHashes[] = { - 0x3081BD3A, - 0xD3443003, - 0x0786A320, - 0xE3A22029, - 0x61611814, - 0x425848E2 -}; - -static const uint32 kSsScene2901BigButtonFileHashes[] = { - 0x010D7748, - 0x9D02019A, - 0x351A2F43, - 0x448138E5, - 0x02788CF0, - 0x71718024 -}; - -SsScene2901LocationButton::SsScene2901LocationButton(NeverhoodEngine *vm, Scene *parentScene, int which, uint index) - : StaticSprite(vm, 900), _parentScene(parentScene), _index(index), _countdown1(0) { - - const NPoint &pt = kSsScene2901LocationButtonPoints[_index]; - - loadSprite(kSsScene2901LocationButtonFileHashes[which * 6 + index], kSLFDefDrawOffset | kSLFDefPosition, 800); - _collisionBounds.set(pt.x - 25, pt.y - 25, pt.x + 25, pt.y + 25); - setVisible(false); - loadSound(0, 0x440430C0); - SetUpdateHandler(&SsScene2901LocationButton::update); - SetMessageHandler(&SsScene2901LocationButton::handleMessage); -} - -void SsScene2901LocationButton::update() { - updatePosition(); - if (_countdown1 != 0 && (--_countdown1) == 0) { - setVisible(false); - } -} - -uint32 SsScene2901LocationButton::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x1011: - if (_countdown1 == 0) { - playSound(0); - setVisible(true); - _countdown1 = 4; - sendMessage(_parentScene, 0x2001, _index); - } - messageResult = 1; - break; - } - return messageResult; -} - -SsScene2901LocationButtonLight::SsScene2901LocationButtonLight(NeverhoodEngine *vm, int which, uint index) - : StaticSprite(vm, 900), _index(index) { - - loadSprite(kSsScene2901LocationButtonLightFileHashes1[which * 6 + index], kSLFDefDrawOffset | kSLFDefPosition, 900); - setVisible(false); - loadSound(0, kSsScene2901LocationButtonLightFileHashes2[_index]); -} - -void SsScene2901LocationButtonLight::show() { - playSound(0); - setVisible(true); - updatePosition(); -} - -void SsScene2901LocationButtonLight::hide() { - setVisible(false); - updatePosition(); -} - -SsScene2901BrokenButton::SsScene2901BrokenButton(NeverhoodEngine *vm, int which) - : StaticSprite(vm, 900) { - - loadSprite(kSsScene2901BrokenButtonFileHashes[which], kSLFDefDrawOffset | kSLFDefPosition, 900); -} - -SsScene2901BigButton::SsScene2901BigButton(NeverhoodEngine *vm, Scene *parentScene, int which) - : StaticSprite(vm, 900), _parentScene(parentScene), _which(which), _countdown1(0) { - - loadSprite(kSsScene2901BigButtonFileHashes[which], kSLFDefDrawOffset | kSLFDefPosition, 400); - _collisionBounds.set(62, 94, 322, 350); - setVisible(false); - loadSound(0, 0xF3D420C8); - SetUpdateHandler(&SsScene2901BigButton::update); - SetMessageHandler(&SsScene2901BigButton::handleMessage); -} - -void SsScene2901BigButton::update() { - updatePosition(); - if (_countdown1 != 0 && (--_countdown1) == 0) { - setVisible(false); - sendMessage(_parentScene, 0x2000, 0); - } -} - -uint32 SsScene2901BigButton::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x1011: - if (_countdown1 == 0) { - playSound(0); - setVisible(true); - _countdown1 = 4; - } - messageResult = 1; - break; - } - return messageResult; -} - Scene2901::Scene2901(NeverhoodEngine *vm, Module *parentModule, int which) : Scene(vm, parentModule), _currLocationButtonNum(which), _selectedButtonNum(which), _currWhirlButtonNum(0), _prevWhirlButtonNum(0), _countdown1(1), _skipCountdown(0), _blinkOn(0) { diff --git a/engines/neverhood/modules/module2900.h b/engines/neverhood/modules/module2900.h index 142f39a35c..5f6ed29a12 100644 --- a/engines/neverhood/modules/module2900.h +++ b/engines/neverhood/modules/module2900.h @@ -42,41 +42,7 @@ protected: void updateMusic(bool halfVolume); }; -class SsScene2901LocationButton : public StaticSprite { -public: - SsScene2901LocationButton(NeverhoodEngine *vm, Scene *parentScene, int which, uint index); -protected: - Scene *_parentScene; - uint _index; - int _countdown1; - void update(); - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); -}; - -class SsScene2901LocationButtonLight : public StaticSprite { -public: - SsScene2901LocationButtonLight(NeverhoodEngine *vm, int which, uint index); - void show(); - void hide(); -protected: - uint _index; -}; - -class SsScene2901BrokenButton : public StaticSprite { -public: - SsScene2901BrokenButton(NeverhoodEngine *vm, int which); -}; - -class SsScene2901BigButton : public StaticSprite { -public: - SsScene2901BigButton(NeverhoodEngine *vm, Scene *parentScene, int which); -protected: - Scene *_parentScene; - int _which; - int _countdown1; - void update(); - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); -}; +class SsScene2901LocationButtonLight; class Scene2901 : public Scene { public: diff --git a/engines/neverhood/modules/module2900_sprites.cpp b/engines/neverhood/modules/module2900_sprites.cpp new file mode 100644 index 0000000000..59780b33a0 --- /dev/null +++ b/engines/neverhood/modules/module2900_sprites.cpp @@ -0,0 +1,232 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "neverhood/modules/module2900_sprites.h" + +namespace Neverhood { + +static const uint32 kSsScene2901LocationButtonFileHashes[] = { + 0x2311326A, + 0x212323AC, + 0x10098138, + 0x25213167, + 0x1119A363, + 0x94452612, + 0x39464212, + 0x01860450, + 0x53002104, + 0x58E68412, + 0x18600300, + 0xB650A890, + 0x2452A7C4, + 0xA0232748, + 0x08862B02, + 0x2491E648, + 0x0010EB46, + 0x214C8A11, + 0x16A31921, + 0x0AC33A00, + 0x238028AA, + 0x26737A21, + 0x063039A8, + 0x51286C60, + 0x464006B4, + 0x42242538, + 0x20716010, + 0x4A2000AE, + 0x225124A6, + 0x28E82E45, + 0x58652C04, + 0xC82210A4, + 0x62A84060, + 0xC0693CB4, + 0x22212C64, + 0x5034EA71 +}; + +static const NPoint kSsScene2901LocationButtonPoints[] = { + {525, 120}, {576, 149}, {587, 205}, + {538, 232}, {484, 205}, {479, 153} +}; + +static const uint32 kSsScene2901LocationButtonLightFileHashes1[] = { + 0x03136246, + 0x2106216E, + 0x4025A13A, + 0x21816927, + 0x110B2202, + 0xCC0522B2, + 0x3CC24258, + 0x59C600F0, + 0x534A2480, + 0x50E61019, + 0x34400150, + 0x225BA090, + 0xB059AFC4, + 0xE093A741, + 0x0086BF09, + 0x3281E760, + 0xA048AB42, + 0x20649C01, + 0x14611904, + 0x26E33850, + 0x23A52A68, + 0xA2733024, + 0x10203880, + 0x1B2DE860, + 0x0644A6EC, + 0x426E20BC, + 0x80292014, + 0x4360B02E, + 0x22742664, + 0x98682705, + 0x0925B82C, + 0x5C2918A4, + 0xD2284920, + 0x41083CA6, + 0x6824A864, + 0x50266B10 +}; + +static const uint32 kSsScene2901LocationButtonLightFileHashes2[] = { + 0x43C46D4C, + 0x43C4AD4C, + 0x43C52D4C, + 0x43C62D4C, + 0x43C02D4C, + 0x43CC2D4C +}; + +static const uint32 kSsScene2901BrokenButtonFileHashes[] = { + 0x3081BD3A, + 0xD3443003, + 0x0786A320, + 0xE3A22029, + 0x61611814, + 0x425848E2 +}; + +static const uint32 kSsScene2901BigButtonFileHashes[] = { + 0x010D7748, + 0x9D02019A, + 0x351A2F43, + 0x448138E5, + 0x02788CF0, + 0x71718024 +}; + +SsScene2901LocationButton::SsScene2901LocationButton(NeverhoodEngine *vm, Scene *parentScene, int which, uint index) + : StaticSprite(vm, 900), _parentScene(parentScene), _index(index), _countdown1(0) { + + const NPoint &pt = kSsScene2901LocationButtonPoints[_index]; + + loadSprite(kSsScene2901LocationButtonFileHashes[which * 6 + index], kSLFDefDrawOffset | kSLFDefPosition, 800); + _collisionBounds.set(pt.x - 25, pt.y - 25, pt.x + 25, pt.y + 25); + setVisible(false); + loadSound(0, 0x440430C0); + SetUpdateHandler(&SsScene2901LocationButton::update); + SetMessageHandler(&SsScene2901LocationButton::handleMessage); +} + +void SsScene2901LocationButton::update() { + updatePosition(); + if (_countdown1 != 0 && (--_countdown1) == 0) { + setVisible(false); + } +} + +uint32 SsScene2901LocationButton::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x1011: + if (_countdown1 == 0) { + playSound(0); + setVisible(true); + _countdown1 = 4; + sendMessage(_parentScene, 0x2001, _index); + } + messageResult = 1; + break; + } + return messageResult; +} + +SsScene2901LocationButtonLight::SsScene2901LocationButtonLight(NeverhoodEngine *vm, int which, uint index) + : StaticSprite(vm, 900), _index(index) { + + loadSprite(kSsScene2901LocationButtonLightFileHashes1[which * 6 + index], kSLFDefDrawOffset | kSLFDefPosition, 900); + setVisible(false); + loadSound(0, kSsScene2901LocationButtonLightFileHashes2[_index]); +} + +void SsScene2901LocationButtonLight::show() { + playSound(0); + setVisible(true); + updatePosition(); +} + +void SsScene2901LocationButtonLight::hide() { + setVisible(false); + updatePosition(); +} + +SsScene2901BrokenButton::SsScene2901BrokenButton(NeverhoodEngine *vm, int which) + : StaticSprite(vm, 900) { + + loadSprite(kSsScene2901BrokenButtonFileHashes[which], kSLFDefDrawOffset | kSLFDefPosition, 900); +} + +SsScene2901BigButton::SsScene2901BigButton(NeverhoodEngine *vm, Scene *parentScene, int which) + : StaticSprite(vm, 900), _parentScene(parentScene), _which(which), _countdown1(0) { + + loadSprite(kSsScene2901BigButtonFileHashes[which], kSLFDefDrawOffset | kSLFDefPosition, 400); + _collisionBounds.set(62, 94, 322, 350); + setVisible(false); + loadSound(0, 0xF3D420C8); + SetUpdateHandler(&SsScene2901BigButton::update); + SetMessageHandler(&SsScene2901BigButton::handleMessage); +} + +void SsScene2901BigButton::update() { + updatePosition(); + if (_countdown1 != 0 && (--_countdown1) == 0) { + setVisible(false); + sendMessage(_parentScene, 0x2000, 0); + } +} + +uint32 SsScene2901BigButton::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x1011: + if (_countdown1 == 0) { + playSound(0); + setVisible(true); + _countdown1 = 4; + } + messageResult = 1; + break; + } + return messageResult; +} + +} // End of namespace Neverhood diff --git a/engines/neverhood/modules/module2900_sprites.h b/engines/neverhood/modules/module2900_sprites.h new file mode 100644 index 0000000000..9f7df502e1 --- /dev/null +++ b/engines/neverhood/modules/module2900_sprites.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 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef NEVERHOOD_MODULES_MODULE2900_SPRITES_H +#define NEVERHOOD_MODULES_MODULE2900_SPRITES_H + +#include "neverhood/neverhood.h" +#include "neverhood/module.h" +#include "neverhood/scene.h" + +namespace Neverhood { + +// Module2900 + +class SsScene2901LocationButton : public StaticSprite { +public: + SsScene2901LocationButton(NeverhoodEngine *vm, Scene *parentScene, int which, uint index); +protected: + Scene *_parentScene; + uint _index; + int _countdown1; + void update(); + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); +}; + +class SsScene2901LocationButtonLight : public StaticSprite { +public: + SsScene2901LocationButtonLight(NeverhoodEngine *vm, int which, uint index); + void show(); + void hide(); +protected: + uint _index; +}; + +class SsScene2901BrokenButton : public StaticSprite { +public: + SsScene2901BrokenButton(NeverhoodEngine *vm, int which); +}; + +class SsScene2901BigButton : public StaticSprite { +public: + SsScene2901BigButton(NeverhoodEngine *vm, Scene *parentScene, int which); +protected: + Scene *_parentScene; + int _which; + int _countdown1; + void update(); + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); +}; + +} // End of namespace Neverhood + +#endif /* NEVERHOOD_MODULES_MODULE2900_SPRITES_H */ diff --git a/engines/neverhood/modules/module3000.cpp b/engines/neverhood/modules/module3000.cpp index ab3c18d1f4..a12776611e 100644 --- a/engines/neverhood/modules/module3000.cpp +++ b/engines/neverhood/modules/module3000.cpp @@ -20,9 +20,10 @@ * */ -#include "neverhood/modules/module3000.h" #include "neverhood/gamemodule.h" #include "neverhood/navigationscene.h" +#include "neverhood/modules/module3000.h" +#include "neverhood/modules/module3000_sprites.h" namespace Neverhood { @@ -415,343 +416,6 @@ static const uint32 kScene3009CannonActionVideos[] = { 0x240A1101 // 14 Lower the cannon }; -static const uint32 kSsScene3009SymbolEdgesFileHashes[] = { - 0x618827A0, - 0xB1A92322 -}; - -static const uint32 kSsScene3009TargetLineFileHashes[] = { - 0x4011018C, - 0x15086623 -}; - -static const NPoint kAsScene3009SymbolPoints[] = { - {289, 338}, - {285, 375}, - {284, 419}, - {456, 372}, - {498, 372}, - {541, 372} -}; - -static const uint32 kAsScene3009SymbolFileHashes[] = { - 0x24542582, - 0x1CD61D96 -}; - -static const uint32 kSsScene3009SymbolArrowFileHashes1[] = { - 0x24016060, - 0x21216221, - 0x486160A0, - 0x42216422, - 0x90A16120, - 0x84216824, - 0x08017029, - 0x08217029, - 0x10014032, - 0x10214032, - 0x20012004, - 0x20212004 -}; - -static const uint32 kSsScene3009SymbolArrowFileHashes2[] = { - 0x40092024, - 0x01636002, - 0x8071E028, - 0x02A56064, - 0x00806031, - 0x052960A8, - 0x0A116130, - 0x0A316130, - 0x14216200, - 0x14016200, - 0x28416460, - 0x28616460 -}; - -SsScene3009FireCannonButton::SsScene3009FireCannonButton(NeverhoodEngine *vm, Scene3009 *parentScene) - : StaticSprite(vm, 1400), _parentScene(parentScene), _isClicked(false) { - - loadSprite(0x120B24B0, kSLFDefDrawOffset | kSLFDefPosition | kSLFDefCollisionBoundsOffset, 400); - setVisible(false); - SetUpdateHandler(&SsScene3009FireCannonButton::update); - SetMessageHandler(&SsScene3009FireCannonButton::handleMessage); - loadSound(0, 0x3901B44F); -} - -void SsScene3009FireCannonButton::update() { - updatePosition(); - if (_isClicked && !isSoundPlaying(0)) { - sendMessage(_parentScene, 0x2000, 0); - setVisible(false); - } -} - -uint32 SsScene3009FireCannonButton::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x1011: - if (!_isClicked && !_parentScene->isTurning()) { - _isClicked = true; - setVisible(true); - playSound(0); - } - messageResult = 1; - break; - } - return messageResult; -} - -SsScene3009SymbolEdges::SsScene3009SymbolEdges(NeverhoodEngine *vm, int index) - : StaticSprite(vm, 1400), _blinkCountdown(0) { - - loadSprite(kSsScene3009SymbolEdgesFileHashes[index], kSLFDefDrawOffset | kSLFDefPosition, 600); - if (getGlobalVar(V_ROBOT_HIT)) - hide(); - else - startBlinking(); - SetUpdateHandler(&SsScene3009SymbolEdges::update); -} - -void SsScene3009SymbolEdges::update() { - if (_blinkCountdown != 0 && (--_blinkCountdown == 0)) { - if (_blinkToggle) { - setVisible(true); - } else { - setVisible(false); - } - updatePosition(); - _blinkCountdown = 3; - _blinkToggle = !_blinkToggle; - } -} - -void SsScene3009SymbolEdges::show() { - setVisible(true); - updatePosition(); - _blinkCountdown = 0; -} - -void SsScene3009SymbolEdges::hide() { - setVisible(false); - updatePosition(); - _blinkCountdown = 0; -} - -void SsScene3009SymbolEdges::startBlinking() { - setVisible(true); - updatePosition(); - _blinkCountdown = 3; - _blinkToggle = true; -} - -SsScene3009TargetLine::SsScene3009TargetLine(NeverhoodEngine *vm, int index) - : StaticSprite(vm, 1400) { - - loadSprite(kSsScene3009TargetLineFileHashes[index], kSLFDefDrawOffset | kSLFDefPosition, 600); - setVisible(false); -} - -void SsScene3009TargetLine::show() { - setVisible(true); - updatePosition(); -} - -SsScene3009SymbolArrow::SsScene3009SymbolArrow(NeverhoodEngine *vm, Sprite *asSymbol, int index) - : StaticSprite(vm, 1400), _asSymbol(asSymbol), _index(index), _enabled(true), _countdown(0) { - - _incrDecr = _index % 2; - - createSurface(1200, 33, 31); - loadSprite(kSsScene3009SymbolArrowFileHashes2[_index], kSLFDefPosition); - _drawOffset.set(0, 0, 33, 31); - _collisionBoundsOffset = _drawOffset; - updateBounds(); - _needRefresh = true; - - SetUpdateHandler(&SsScene3009SymbolArrow::update); - SetMessageHandler(&SsScene3009SymbolArrow::handleMessage); - loadSound(0, 0x2C852206); -} - -void SsScene3009SymbolArrow::hide() { - _enabled = false; - setVisible(false); -} - -void SsScene3009SymbolArrow::update() { - updatePosition(); - if (_countdown != 0 && (--_countdown == 0)) { - loadSprite(kSsScene3009SymbolArrowFileHashes2[_index], kSLFDefDrawOffset); - } -} - -uint32 SsScene3009SymbolArrow::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x1011: - if (_enabled && _countdown == 0) { - _countdown = 2; - loadSprite(kSsScene3009SymbolArrowFileHashes1[_index], kSLFDefDrawOffset); - playSound(0); - sendMessage(_asSymbol, 0x2005, _incrDecr); - } - messageResult = 1; - break; - } - return messageResult; -} - -AsScene3009VerticalIndicator::AsScene3009VerticalIndicator(NeverhoodEngine *vm, Scene3009 *parentScene, int index) - : AnimatedSprite(vm, 1000), _parentScene(parentScene), _enabled(false) { - - _x = 300; - _y = getGlobalVar(V_CANNON_RAISED) ? 52 : 266; - createSurface1(0xC2463913, 1200); - _needRefresh = true; - updatePosition(); - setVisible(false); - SetUpdateHandler(&AnimatedSprite::update); - SetMessageHandler(&AsScene3009VerticalIndicator::handleMessage); -} - -void AsScene3009VerticalIndicator::show() { - startAnimation(0xC2463913, 0, -1); - setVisible(true); - updatePosition(); - _enabled = true; -} - -uint32 AsScene3009VerticalIndicator::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x1011: - if (_enabled) { - sendMessage(_parentScene, 0x2002, 0); - } - messageResult = 1; - break; - } - return messageResult; -} - -AsScene3009HorizontalIndicator::AsScene3009HorizontalIndicator(NeverhoodEngine *vm, Scene3009 *parentScene, uint32 cannonTargetStatus) - : AnimatedSprite(vm, 1000), _parentScene(parentScene), _enabled(false) { - - _x = getGlobalVar(V_CANNON_TURNED) ? 533 : 92; - _y = 150; - createSurface1(0xC0C12954, 1200); - _needRefresh = true; - updatePosition(); - setVisible(false); - SetUpdateHandler(&AnimatedSprite::update); - SetMessageHandler(&AsScene3009HorizontalIndicator::handleMessage); - if (cannonTargetStatus == kCTSRightRobotNoTarget || cannonTargetStatus == kCTSRightRobotIsTarget || cannonTargetStatus == kCTSRightNoRobot) { - SetSpriteUpdate(&AsScene3009HorizontalIndicator::suMoveRight); - _x = 280; - } -} - -uint32 AsScene3009HorizontalIndicator::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x1011: - if (_enabled) { - sendMessage(_parentScene, 0x2004, 0); - } - messageResult = 1; - break; - } - return messageResult; -} - -void AsScene3009HorizontalIndicator::suMoveLeft() { - _x -= 6; - if (_x < 92) { - SetSpriteUpdate(NULL); - _x = 92; - } -} - -void AsScene3009HorizontalIndicator::suMoveRight() { - _x += 6; - if (_x > 533) { - SetSpriteUpdate(NULL); - _x = 533; - } -} - -void AsScene3009HorizontalIndicator::show() { - startAnimation(0xC0C12954, 0, -1); - setVisible(true); - updatePosition(); - _enabled = true; -} - -void AsScene3009HorizontalIndicator::stMoveLeft() { - _x = 533; - SetSpriteUpdate(&AsScene3009HorizontalIndicator::suMoveLeft); -} - -void AsScene3009HorizontalIndicator::stMoveRight() { - _x = 330; - SetSpriteUpdate(&AsScene3009HorizontalIndicator::suMoveRight); -} - -AsScene3009Symbol::AsScene3009Symbol(NeverhoodEngine *vm, Scene3009 *parentScene, int symbolPosition) - : AnimatedSprite(vm, 1100), _parentScene(parentScene), _symbolPosition(symbolPosition) { - - _symbolIndex = getSubVar(VA_CURR_CANNON_SYMBOLS, _symbolPosition); - - _x = kAsScene3009SymbolPoints[_symbolPosition].x; - _y = kAsScene3009SymbolPoints[_symbolPosition].y; - createSurface1(kAsScene3009SymbolFileHashes[_symbolPosition / 3], 1200); - startAnimation(kAsScene3009SymbolFileHashes[_symbolPosition / 3], _symbolIndex, -1); - _newStickFrameIndex = _symbolIndex; - _needRefresh = true; - updatePosition(); - SetUpdateHandler(&AnimatedSprite::update); - SetMessageHandler(&AsScene3009Symbol::handleMessage); - _ssArrowPrev = _parentScene->insertSprite<SsScene3009SymbolArrow>(this, _symbolPosition * 2 + 0); - _parentScene->addCollisionSprite(_ssArrowPrev); - _ssArrowNext = _parentScene->insertSprite<SsScene3009SymbolArrow>(this, _symbolPosition * 2 + 1); - _parentScene->addCollisionSprite(_ssArrowNext); -} - -uint32 AsScene3009Symbol::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x2005: - if (param.asInteger()) { - if (_symbolIndex == 11) - _symbolIndex = 0; - else - _symbolIndex++; - } else { - if (_symbolIndex == 0) - _symbolIndex = 11; - else - _symbolIndex--; - } - startAnimation(kAsScene3009SymbolFileHashes[_symbolPosition / 3], _symbolIndex, -1); - _newStickFrameIndex = _symbolIndex; - setSubVar(VA_CURR_CANNON_SYMBOLS, _symbolPosition, _symbolIndex); - if (_symbolPosition / 3 == 0) { - sendMessage(_parentScene, 0x2001, 0); - } else { - sendMessage(_parentScene, 0x2003, 0); - } - messageResult = 1; - break; - } - return messageResult; -} - -void AsScene3009Symbol::hide() { - _ssArrowPrev->hide(); - _ssArrowNext->hide(); -} - Scene3009::Scene3009(NeverhoodEngine *vm, Module *parentModule, int which) : Scene(vm, parentModule), _keepVideo(false), _moveCannonLeftFirst(false), _isTurning(false), _lockSymbolsPart1Countdown(1), _lockSymbolsPart2Countdown(1) { @@ -1015,206 +679,6 @@ static const uint32 kScene3010DeadBoltButtonFileHashes2[] = { 0x5000A7E8 }; -static const NPoint kAsScene3010DeadBoltPoints[] = { - {550, 307}, - {564, 415}, - {560, 514} -}; - -static const uint32 kAsScene3010DeadBoltFileHashes2[] = { - 0x181A0042, - 0x580A08F2, - 0x18420076 -}; - -static const uint32 kAsScene3010DeadBoltFileHashes1[] = { - 0x300E105A, - 0x804E0052, - 0x040E485A -}; - -SsScene3010DeadBoltButton::SsScene3010DeadBoltButton(NeverhoodEngine *vm, Scene *parentScene, int buttonIndex, int initCountdown, bool initDisabled) - : StaticSprite(vm, 900), _parentScene(parentScene), _buttonLocked(false), _countdown1(0), _countdown2(0), _buttonIndex(buttonIndex) { - - _buttonEnabled = getSubVar(VA_LOCKS_DISABLED, kScene3010ButtonNameHashes[_buttonIndex]) != 0; - createSurface(400, 88, 95); - setSprite(kScene3010DeadBoltButtonFileHashes2[_buttonIndex]); - if (initDisabled) - disableButton(); - else if (_buttonEnabled) - _countdown1 = initCountdown * 12 + 1; - loadSound(0, 0xF4217243); - loadSound(1, 0x44049000); - loadSound(2, 0x6408107E); - SetUpdateHandler(&SsScene3010DeadBoltButton::update); - SetMessageHandler(&SsScene3010DeadBoltButton::handleMessage); -} - -void SsScene3010DeadBoltButton::update() { - - if (_countdown1 != 0 && (--_countdown1 == 0)) { - playSound(0); - setVisible(false); - setSprite(kScene3010DeadBoltButtonFileHashes1[_buttonIndex]); - } - - if (_countdown2 != 0 && (--_countdown2 == 0)) { - setVisible(true); - setSprite(kScene3010DeadBoltButtonFileHashes2[_buttonIndex]); - } - -} - -uint32 SsScene3010DeadBoltButton::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x1011: - if (!_buttonLocked && _countdown1 == 0) { - if (_buttonEnabled) { - playSound(1); - playSound(2); - setVisible(true); - _buttonLocked = true; - sendMessage(_parentScene, 0x2000, _buttonIndex); - } else { - sendMessage(_parentScene, 0x2002, _buttonIndex); - } - _needRefresh = true; - updatePosition(); - } - messageResult = 1; - break; - } - return messageResult; -} - -void SsScene3010DeadBoltButton::disableButton() { - _buttonLocked = true; - setSprite(kScene3010DeadBoltButtonFileHashes1[_buttonIndex]); - setVisible(true); -} - -void SsScene3010DeadBoltButton::setSprite(uint32 fileHash) { - loadSprite(fileHash, kSLFDefDrawOffset | kSLFDefPosition | kSLFDefCollisionBoundsOffset); -} - -void SsScene3010DeadBoltButton::setCountdown(int count) { - _countdown2 = count * 18 + 1; -} - -AsScene3010DeadBolt::AsScene3010DeadBolt(NeverhoodEngine *vm, Scene *parentScene, int boltIndex, bool initUnlocked) - : AnimatedSprite(vm, 1100), _parentScene(parentScene), _boltIndex(boltIndex), _soundToggle(true), - _unlocked(false), _locked(false), _countdown(0) { - - _x = kAsScene3010DeadBoltPoints[_boltIndex].x; - _y = kAsScene3010DeadBoltPoints[_boltIndex].y; - - if (getSubVar(VA_LOCKS_DISABLED, kScene3010ButtonNameHashes[_boltIndex])) { - createSurface1(kAsScene3010DeadBoltFileHashes1[_boltIndex], 1200); - startAnimation(kAsScene3010DeadBoltFileHashes1[_boltIndex], 0, -1); - loadSound(0, 0x46005BC4); - } else { - createSurface1(kAsScene3010DeadBoltFileHashes2[_boltIndex], 1200); - startAnimation(kAsScene3010DeadBoltFileHashes2[_boltIndex], 0, -1); - loadSound(0, 0x420073DC); - loadSound(1, 0x420073DC); - } - - setVisible(false); - stIdle(); - if (initUnlocked) - unlock(true); - - _needRefresh = true; - AnimatedSprite::updatePosition(); - -} - -void AsScene3010DeadBolt::update() { - updateAnim(); - updatePosition(); - if (_countdown != 0 && (--_countdown == 0)) { - stDisabled(); - } -} - -uint32 AsScene3010DeadBolt::hmAnimation(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x3002: - gotoNextState(); - break; - } - return messageResult; -} - -void AsScene3010DeadBolt::stIdle() { - stopAnimation(); - SetUpdateHandler(&AsScene3010DeadBolt::update); - SetMessageHandler(&Sprite::handleMessage); - _locked = false; -} - -void AsScene3010DeadBolt::unlock(bool skipAnim) { - if (!_unlocked) { - setVisible(true); - if (skipAnim) { - startAnimation(kAsScene3010DeadBoltFileHashes1[_boltIndex], -1, 0); - _newStickFrameIndex = STICK_LAST_FRAME; - } else { - startAnimation(kAsScene3010DeadBoltFileHashes1[_boltIndex], 0, -1); - SetMessageHandler(&AsScene3010DeadBolt::hmAnimation); - FinalizeState(&AsScene3010DeadBolt::stIdleMessage); - NextState(&AsScene3010DeadBolt::stIdle); - playSound(0); - } - _unlocked = true; - loadSound(2, 0x4010C345); - } -} - -void AsScene3010DeadBolt::stIdleMessage() { - stopAnimation(); - SetMessageHandler(&Sprite::handleMessage); - sendMessage(_parentScene, 0x2001, _boltIndex); -} - -void AsScene3010DeadBolt::lock() { - if (!_locked) { - _locked = true; - setVisible(true); - startAnimation(kAsScene3010DeadBoltFileHashes2[_boltIndex], 0, -1); - SetMessageHandler(&AsScene3010DeadBolt::hmAnimation); - FinalizeState(&AsScene3010DeadBolt::stDisabledMessage); - NextState(&AsScene3010DeadBolt::stIdle); - if (_soundToggle) { - playSound(0); - } else { - playSound(1); - } - _soundToggle = !_soundToggle; - } -} - -void AsScene3010DeadBolt::setCountdown(int count) { - _countdown = count * 18 + 1; -} - -void AsScene3010DeadBolt::stDisabled() { - setVisible(true); - startAnimation(kAsScene3010DeadBoltFileHashes1[_boltIndex], 0, -1); - SetMessageHandler(&AsScene3010DeadBolt::hmAnimation); - FinalizeState(&AsScene3010DeadBolt::stDisabledMessage); - NextState(&AsScene3010DeadBolt::stIdle); - _playBackwards = true; - playSound(2); -} - -void AsScene3010DeadBolt::stDisabledMessage() { - setVisible(false); - sendMessage(_parentScene, 0x2003, _boltIndex); -} - Scene3010::Scene3010(NeverhoodEngine *vm, Module *parentModule, int which) : Scene(vm, parentModule), _countdown(0), _doorUnlocked(false), _checkUnlocked(false) { @@ -1317,127 +781,6 @@ uint32 Scene3010::handleMessage(int messageNum, const MessageParam ¶m, Entit return 0; } -// Scene3011 - -static const uint32 kAsScene3011SymbolFileHashes[] = { - 0x00C88050, - 0x01488050, - 0x02488050, - 0x04488050, - 0x08488050, - 0x10488050, - 0x20488050, - 0x40488050, - 0x80488050, - 0x00488051, - 0x00488052, - 0x00488054, - 0x008B0000, - 0x008D0000, - 0x00810000, - 0x00990000, - 0x00A90000, - 0x00C90000, - 0x00090000, - 0x01890000, - 0x02890000, - 0x04890000, - 0x08890000, - 0x10890000 -}; - -SsScene3011Button::SsScene3011Button(NeverhoodEngine *vm, Scene *parentScene, bool flag) - : StaticSprite(vm, 1400), _parentScene(parentScene), _countdown(0) { - - loadSprite(flag ? 0x11282020 : 0x994D0433, kSLFDefDrawOffset | kSLFDefPosition | kSLFDefCollisionBoundsOffset, 400); - setVisible(false); - loadSound(0, 0x44061000); - SetUpdateHandler(&SsScene3011Button::update); - SetMessageHandler(&SsScene3011Button::handleMessage); -} - -void SsScene3011Button::update() { - updatePosition(); - if (_countdown != 0 && (--_countdown == 0)) { - setVisible(false); - } -} - -uint32 SsScene3011Button::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - uint32 messageResult = 0; - StaticSprite::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x1011: - if (_countdown == 0) { - setVisible(true); - _countdown = 4; - sendMessage(_parentScene, 0x2000, 0); - playSound(0); - } - messageResult = 1; - break; - } - return messageResult; -} - -AsScene3011Symbol::AsScene3011Symbol(NeverhoodEngine *vm, int symbolIndex, bool largeSymbol) - : AnimatedSprite(vm, 1000), _symbolIndex(symbolIndex), _largeSymbol(largeSymbol), _isNoisy(false) { - - if (_largeSymbol) { - _x = 310; - _y = 200; - createSurface1(kAsScene3011SymbolFileHashes[_symbolIndex], 1200); - loadSound(0, 0x6052C60F); - loadSound(1, 0x6890433B); - } else { - _symbolIndex = 12; - _x = symbolIndex * 39 + 96; - _y = 225; - createSurface(1200, 41, 48); - loadSound(0, 0x64428609); - loadSound(1, 0x7080023B); - } - setVisible(false); - _needRefresh = true; - SetUpdateHandler(&AnimatedSprite::update); -} - -void AsScene3011Symbol::show(bool isNoisy) { - _isNoisy = isNoisy; - startAnimation(kAsScene3011SymbolFileHashes[_symbolIndex], 0, -1); - setVisible(true); - if (_isNoisy) { - playSound(1); - } else { - playSound(0); - } -} - -void AsScene3011Symbol::hide() { - stopAnimation(); - setVisible(false); -} - -void AsScene3011Symbol::stopSymbolSound() { - if (_isNoisy) { - stopSound(1); - } else { - stopSound(0); - } -} - -void AsScene3011Symbol::change(int symbolIndex, bool isNoisy) { - _symbolIndex = symbolIndex; - _isNoisy = isNoisy; - startAnimation(kAsScene3011SymbolFileHashes[_symbolIndex], 0, -1); - setVisible(true); - if (_isNoisy) { - playSound(1); - } else { - playSound(0); - } -} - Scene3011::Scene3011(NeverhoodEngine *vm, Module *parentModule, int which) : Scene(vm, parentModule), _updateStatus(0), _buttonClicked(false), _currentSymbolIndex(0), _countdown(0) { diff --git a/engines/neverhood/modules/module3000.h b/engines/neverhood/modules/module3000.h index a6cecb227e..a88dea513e 100644 --- a/engines/neverhood/modules/module3000.h +++ b/engines/neverhood/modules/module3000.h @@ -26,7 +26,6 @@ #include "neverhood/neverhood.h" #include "neverhood/module.h" #include "neverhood/scene.h" -#include "neverhood/modules/module1200.h" namespace Neverhood { @@ -41,89 +40,11 @@ protected: void updateScene(); }; -// Scene3009 - -class Scene3009; - -class SsScene3009FireCannonButton : public StaticSprite { -public: - SsScene3009FireCannonButton(NeverhoodEngine *vm, Scene3009 *parentScene); -protected: - Scene3009 *_parentScene; - bool _isClicked; - void update(); - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); -}; - -class SsScene3009SymbolEdges : public StaticSprite { -public: - SsScene3009SymbolEdges(NeverhoodEngine *vm, int index); - void show(); - void hide(); - void startBlinking(); -protected: - int _blinkCountdown; - bool _blinkToggle; - void update(); - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); -}; - -class SsScene3009TargetLine : public StaticSprite { -public: - SsScene3009TargetLine(NeverhoodEngine *vm, int index); - void show(); -}; - -class SsScene3009SymbolArrow : public StaticSprite { -public: - SsScene3009SymbolArrow(NeverhoodEngine *vm, Sprite *asSymbol, int index); - void hide(); -protected: - Sprite *_asSymbol; - int _index; - int _incrDecr; - bool _enabled; - int _countdown; - void update(); - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); -}; - -class AsScene3009VerticalIndicator : public AnimatedSprite { -public: - AsScene3009VerticalIndicator(NeverhoodEngine *vm, Scene3009 *parentScene, int index); - void show(); -protected: - Scene3009 *_parentScene; - bool _enabled; - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); -}; - -class AsScene3009HorizontalIndicator : public AnimatedSprite { -public: - AsScene3009HorizontalIndicator(NeverhoodEngine *vm, Scene3009 *parentScene, uint32 cannonTargetStatus); - void show(); - void stMoveLeft(); - void stMoveRight(); -protected: - Scene3009 *_parentScene; - bool _enabled; - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); - void suMoveLeft(); - void suMoveRight(); -}; - -class AsScene3009Symbol : public AnimatedSprite { -public: - AsScene3009Symbol(NeverhoodEngine *vm, Scene3009 *parentScene, int symbolPosition); - void hide(); -protected: - Scene3009 *_parentScene; - int _symbolPosition; - uint32 _symbolIndex; - SsScene3009SymbolArrow *_ssArrowPrev; - SsScene3009SymbolArrow *_ssArrowNext; - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); -}; +class SsScene3009SymbolEdges; +class SsScene3009TargetLine; +class AsScene3009VerticalIndicator; +class AsScene3009HorizontalIndicator; +class AsScene3009Symbol; class Scene3009 : public Scene { public: @@ -153,45 +74,8 @@ protected: void openSmacker(uint32 fileHash, bool keepLastFrame); }; -// Scene3010 - -class SsScene3010DeadBoltButton : public StaticSprite { -public: - SsScene3010DeadBoltButton(NeverhoodEngine *vm, Scene *parentScene, int buttonIndex, int initCountdown, bool initDisabled); - void setCountdown(int count); -protected: - Scene *_parentScene; - int _buttonIndex; - bool _buttonEnabled; - bool _buttonLocked; - int _countdown1; - int _countdown2; - void update(); - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); - void disableButton(); - void setSprite(uint32 fileHash); -}; - -class AsScene3010DeadBolt : public AnimatedSprite { -public: - AsScene3010DeadBolt(NeverhoodEngine *vm, Scene *parentScene, int boltIndex, bool initUnlocked); - void setCountdown(int count); - void lock(); - void unlock(bool skipAnim); -protected: - Scene *_parentScene; - int _boltIndex; - int _countdown; - bool _soundToggle; - bool _unlocked; - bool _locked; - void update(); - uint32 hmAnimation(int messageNum, const MessageParam ¶m, Entity *sender); - void stIdle(); - void stIdleMessage(); - void stDisabled(); - void stDisabledMessage(); -}; +class SsScene3010DeadBoltButton; +class AsScene3010DeadBolt; class Scene3010 : public Scene { public: @@ -208,31 +92,7 @@ protected: uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); }; -// Scene3011 - -class SsScene3011Button : public StaticSprite { -public: - SsScene3011Button(NeverhoodEngine *vm, Scene *parentScene, bool flag); -protected: - Scene *_parentScene; - int _countdown; - void update(); - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); -}; - -class AsScene3011Symbol : public AnimatedSprite { -public: - AsScene3011Symbol(NeverhoodEngine *vm, int symbolIndex, bool largeSymbol); - void show(bool isNoisy); - void hide(); - void stopSymbolSound(); - void change(int symbolIndex, bool isNoisy); - int getSymbolIndex() { return _largeSymbol ? _symbolIndex : _symbolIndex - 12; } -protected: - bool _largeSymbol; - bool _isNoisy; - int _symbolIndex; -}; +class AsScene3011Symbol; class Scene3011 : public Scene { public: diff --git a/engines/neverhood/modules/module3000_sprites.cpp b/engines/neverhood/modules/module3000_sprites.cpp new file mode 100644 index 0000000000..7d0162d7d0 --- /dev/null +++ b/engines/neverhood/modules/module3000_sprites.cpp @@ -0,0 +1,763 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "neverhood/modules/module3000.h" +#include "neverhood/modules/module3000_sprites.h" + +namespace Neverhood { + +// Scene3009 + +enum { + kCTSNull = 0, + kCTSBreakWall = 1, + kCTSWall = 2, + kCTSEmptyness = 3, + kCTSFireRobotNoTarget = 4, + kCTSFireRobotIsTarget = 5, + kCTSFireNoRobot = 6, + kCTSRaiseCannon = 7, + kCTSRightRobotNoTarget = 8, + kCTSRightRobotIsTarget = 9, + kCTSRightNoRobot = 10, + kCTSLeftRobotNoTarget = 11, + kCTSLeftRobotIsTarget = 12, + kCTSLeftNoRobot = 13, + kCTSLowerCannon = 14, + kCTSCount = 14 +}; + +static const uint32 kScene3009CannonScopeVideos[] = { + 0x1010000D, + 0x340A0049, + 0x340A0049, + 0x0282081D, + 0x0082080D, + 0x0882080D, + 0x0882080D, + 0x0282081D, + 0x004B000B, + 0x014B000B, + 0x044B000B, + 0x0282081D, + 0x0282081D, + 0x0282081D, + 0x340A0049 +}; + +static const uint32 kScene3009CannonActionVideos[] = { + 0x00000000, + 0x8004001B, // 1 Fire cannon at wall, it breaks (lowered) + 0x0004001A, // 2 Fire cannon at wall, nothing happens (lowered) + 0x1048404B, // 3 Fire cannon at emptyness (raised) + 0x50200109, // 4 Fire cannon, robot missed (raised) + 0x12032109, // 5 Fire cannon, robot hit (raised) + 0x10201109, // 6 Fire cannon, no robot (raised) + 0x000A2030, // 7 Raise the cannon + 0x000A0028, // 8 + 0x000A0028, // 9 + 0x000A0028, // 10 + 0x040A1069, // 11 + 0x040A1069, // 12 + 0x040A1069, // 13 + 0x240A1101 // 14 Lower the cannon +}; + +static const uint32 kSsScene3009SymbolEdgesFileHashes[] = { + 0x618827A0, + 0xB1A92322 +}; + +static const uint32 kSsScene3009TargetLineFileHashes[] = { + 0x4011018C, + 0x15086623 +}; + +static const NPoint kAsScene3009SymbolPoints[] = { + {289, 338}, + {285, 375}, + {284, 419}, + {456, 372}, + {498, 372}, + {541, 372} +}; + +static const uint32 kAsScene3009SymbolFileHashes[] = { + 0x24542582, + 0x1CD61D96 +}; + +static const uint32 kSsScene3009SymbolArrowFileHashes1[] = { + 0x24016060, + 0x21216221, + 0x486160A0, + 0x42216422, + 0x90A16120, + 0x84216824, + 0x08017029, + 0x08217029, + 0x10014032, + 0x10214032, + 0x20012004, + 0x20212004 +}; + +static const uint32 kSsScene3009SymbolArrowFileHashes2[] = { + 0x40092024, + 0x01636002, + 0x8071E028, + 0x02A56064, + 0x00806031, + 0x052960A8, + 0x0A116130, + 0x0A316130, + 0x14216200, + 0x14016200, + 0x28416460, + 0x28616460 +}; + +SsScene3009FireCannonButton::SsScene3009FireCannonButton(NeverhoodEngine *vm, Scene3009 *parentScene) + : StaticSprite(vm, 1400), _parentScene(parentScene), _isClicked(false) { + + loadSprite(0x120B24B0, kSLFDefDrawOffset | kSLFDefPosition | kSLFDefCollisionBoundsOffset, 400); + setVisible(false); + SetUpdateHandler(&SsScene3009FireCannonButton::update); + SetMessageHandler(&SsScene3009FireCannonButton::handleMessage); + loadSound(0, 0x3901B44F); +} + +void SsScene3009FireCannonButton::update() { + updatePosition(); + if (_isClicked && !isSoundPlaying(0)) { + sendMessage(_parentScene, 0x2000, 0); + setVisible(false); + } +} + +uint32 SsScene3009FireCannonButton::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x1011: + if (!_isClicked && !_parentScene->isTurning()) { + _isClicked = true; + setVisible(true); + playSound(0); + } + messageResult = 1; + break; + } + return messageResult; +} + +SsScene3009SymbolEdges::SsScene3009SymbolEdges(NeverhoodEngine *vm, int index) + : StaticSprite(vm, 1400), _blinkCountdown(0) { + + loadSprite(kSsScene3009SymbolEdgesFileHashes[index], kSLFDefDrawOffset | kSLFDefPosition, 600); + if (getGlobalVar(V_ROBOT_HIT)) + hide(); + else + startBlinking(); + SetUpdateHandler(&SsScene3009SymbolEdges::update); +} + +void SsScene3009SymbolEdges::update() { + if (_blinkCountdown != 0 && (--_blinkCountdown == 0)) { + if (_blinkToggle) { + setVisible(true); + } else { + setVisible(false); + } + updatePosition(); + _blinkCountdown = 3; + _blinkToggle = !_blinkToggle; + } +} + +void SsScene3009SymbolEdges::show() { + setVisible(true); + updatePosition(); + _blinkCountdown = 0; +} + +void SsScene3009SymbolEdges::hide() { + setVisible(false); + updatePosition(); + _blinkCountdown = 0; +} + +void SsScene3009SymbolEdges::startBlinking() { + setVisible(true); + updatePosition(); + _blinkCountdown = 3; + _blinkToggle = true; +} + +SsScene3009TargetLine::SsScene3009TargetLine(NeverhoodEngine *vm, int index) + : StaticSprite(vm, 1400) { + + loadSprite(kSsScene3009TargetLineFileHashes[index], kSLFDefDrawOffset | kSLFDefPosition, 600); + setVisible(false); +} + +void SsScene3009TargetLine::show() { + setVisible(true); + updatePosition(); +} + +SsScene3009SymbolArrow::SsScene3009SymbolArrow(NeverhoodEngine *vm, Sprite *asSymbol, int index) + : StaticSprite(vm, 1400), _asSymbol(asSymbol), _index(index), _enabled(true), _countdown(0) { + + _incrDecr = _index % 2; + + createSurface(1200, 33, 31); + loadSprite(kSsScene3009SymbolArrowFileHashes2[_index], kSLFDefPosition); + _drawOffset.set(0, 0, 33, 31); + _collisionBoundsOffset = _drawOffset; + updateBounds(); + _needRefresh = true; + + SetUpdateHandler(&SsScene3009SymbolArrow::update); + SetMessageHandler(&SsScene3009SymbolArrow::handleMessage); + loadSound(0, 0x2C852206); +} + +void SsScene3009SymbolArrow::hide() { + _enabled = false; + setVisible(false); +} + +void SsScene3009SymbolArrow::update() { + updatePosition(); + if (_countdown != 0 && (--_countdown == 0)) { + loadSprite(kSsScene3009SymbolArrowFileHashes2[_index], kSLFDefDrawOffset); + } +} + +uint32 SsScene3009SymbolArrow::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x1011: + if (_enabled && _countdown == 0) { + _countdown = 2; + loadSprite(kSsScene3009SymbolArrowFileHashes1[_index], kSLFDefDrawOffset); + playSound(0); + sendMessage(_asSymbol, 0x2005, _incrDecr); + } + messageResult = 1; + break; + } + return messageResult; +} + +AsScene3009VerticalIndicator::AsScene3009VerticalIndicator(NeverhoodEngine *vm, Scene3009 *parentScene, int index) + : AnimatedSprite(vm, 1000), _parentScene(parentScene), _enabled(false) { + + _x = 300; + _y = getGlobalVar(V_CANNON_RAISED) ? 52 : 266; + createSurface1(0xC2463913, 1200); + _needRefresh = true; + updatePosition(); + setVisible(false); + SetUpdateHandler(&AnimatedSprite::update); + SetMessageHandler(&AsScene3009VerticalIndicator::handleMessage); +} + +void AsScene3009VerticalIndicator::show() { + startAnimation(0xC2463913, 0, -1); + setVisible(true); + updatePosition(); + _enabled = true; +} + +uint32 AsScene3009VerticalIndicator::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x1011: + if (_enabled) { + sendMessage(_parentScene, 0x2002, 0); + } + messageResult = 1; + break; + } + return messageResult; +} + +AsScene3009HorizontalIndicator::AsScene3009HorizontalIndicator(NeverhoodEngine *vm, Scene3009 *parentScene, uint32 cannonTargetStatus) + : AnimatedSprite(vm, 1000), _parentScene(parentScene), _enabled(false) { + + _x = getGlobalVar(V_CANNON_TURNED) ? 533 : 92; + _y = 150; + createSurface1(0xC0C12954, 1200); + _needRefresh = true; + updatePosition(); + setVisible(false); + SetUpdateHandler(&AnimatedSprite::update); + SetMessageHandler(&AsScene3009HorizontalIndicator::handleMessage); + if (cannonTargetStatus == kCTSRightRobotNoTarget || cannonTargetStatus == kCTSRightRobotIsTarget || cannonTargetStatus == kCTSRightNoRobot) { + SetSpriteUpdate(&AsScene3009HorizontalIndicator::suMoveRight); + _x = 280; + } +} + +uint32 AsScene3009HorizontalIndicator::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x1011: + if (_enabled) { + sendMessage(_parentScene, 0x2004, 0); + } + messageResult = 1; + break; + } + return messageResult; +} + +void AsScene3009HorizontalIndicator::suMoveLeft() { + _x -= 6; + if (_x < 92) { + SetSpriteUpdate(NULL); + _x = 92; + } +} + +void AsScene3009HorizontalIndicator::suMoveRight() { + _x += 6; + if (_x > 533) { + SetSpriteUpdate(NULL); + _x = 533; + } +} + +void AsScene3009HorizontalIndicator::show() { + startAnimation(0xC0C12954, 0, -1); + setVisible(true); + updatePosition(); + _enabled = true; +} + +void AsScene3009HorizontalIndicator::stMoveLeft() { + _x = 533; + SetSpriteUpdate(&AsScene3009HorizontalIndicator::suMoveLeft); +} + +void AsScene3009HorizontalIndicator::stMoveRight() { + _x = 330; + SetSpriteUpdate(&AsScene3009HorizontalIndicator::suMoveRight); +} + +AsScene3009Symbol::AsScene3009Symbol(NeverhoodEngine *vm, Scene3009 *parentScene, int symbolPosition) + : AnimatedSprite(vm, 1100), _parentScene(parentScene), _symbolPosition(symbolPosition) { + + _symbolIndex = getSubVar(VA_CURR_CANNON_SYMBOLS, _symbolPosition); + + _x = kAsScene3009SymbolPoints[_symbolPosition].x; + _y = kAsScene3009SymbolPoints[_symbolPosition].y; + createSurface1(kAsScene3009SymbolFileHashes[_symbolPosition / 3], 1200); + startAnimation(kAsScene3009SymbolFileHashes[_symbolPosition / 3], _symbolIndex, -1); + _newStickFrameIndex = _symbolIndex; + _needRefresh = true; + updatePosition(); + SetUpdateHandler(&AnimatedSprite::update); + SetMessageHandler(&AsScene3009Symbol::handleMessage); + _ssArrowPrev = _parentScene->insertSprite<SsScene3009SymbolArrow>(this, _symbolPosition * 2 + 0); + _parentScene->addCollisionSprite(_ssArrowPrev); + _ssArrowNext = _parentScene->insertSprite<SsScene3009SymbolArrow>(this, _symbolPosition * 2 + 1); + _parentScene->addCollisionSprite(_ssArrowNext); +} + +uint32 AsScene3009Symbol::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x2005: + if (param.asInteger()) { + if (_symbolIndex == 11) + _symbolIndex = 0; + else + _symbolIndex++; + } else { + if (_symbolIndex == 0) + _symbolIndex = 11; + else + _symbolIndex--; + } + startAnimation(kAsScene3009SymbolFileHashes[_symbolPosition / 3], _symbolIndex, -1); + _newStickFrameIndex = _symbolIndex; + setSubVar(VA_CURR_CANNON_SYMBOLS, _symbolPosition, _symbolIndex); + if (_symbolPosition / 3 == 0) { + sendMessage(_parentScene, 0x2001, 0); + } else { + sendMessage(_parentScene, 0x2003, 0); + } + messageResult = 1; + break; + } + return messageResult; +} + +void AsScene3009Symbol::hide() { + _ssArrowPrev->hide(); + _ssArrowNext->hide(); +} + +// Scene3010 + +static const uint32 kScene3010ButtonNameHashes[] = { + 0x304008D2, + 0x40119852, + 0x01180951 +}; + +static const uint32 kScene3010DeadBoltButtonFileHashes1[] = { + 0x301024C2, + 0x20280580, + 0x30200452 +}; + +static const uint32 kScene3010DeadBoltButtonFileHashes2[] = { + 0x50C025A8, + 0x1020A0A0, + 0x5000A7E8 +}; + +static const NPoint kAsScene3010DeadBoltPoints[] = { + {550, 307}, + {564, 415}, + {560, 514} +}; + +static const uint32 kAsScene3010DeadBoltFileHashes2[] = { + 0x181A0042, + 0x580A08F2, + 0x18420076 +}; + +static const uint32 kAsScene3010DeadBoltFileHashes1[] = { + 0x300E105A, + 0x804E0052, + 0x040E485A +}; + +SsScene3010DeadBoltButton::SsScene3010DeadBoltButton(NeverhoodEngine *vm, Scene *parentScene, int buttonIndex, int initCountdown, bool initDisabled) + : StaticSprite(vm, 900), _parentScene(parentScene), _buttonLocked(false), _countdown1(0), _countdown2(0), _buttonIndex(buttonIndex) { + + _buttonEnabled = getSubVar(VA_LOCKS_DISABLED, kScene3010ButtonNameHashes[_buttonIndex]) != 0; + createSurface(400, 88, 95); + setSprite(kScene3010DeadBoltButtonFileHashes2[_buttonIndex]); + if (initDisabled) + disableButton(); + else if (_buttonEnabled) + _countdown1 = initCountdown * 12 + 1; + loadSound(0, 0xF4217243); + loadSound(1, 0x44049000); + loadSound(2, 0x6408107E); + SetUpdateHandler(&SsScene3010DeadBoltButton::update); + SetMessageHandler(&SsScene3010DeadBoltButton::handleMessage); +} + +void SsScene3010DeadBoltButton::update() { + + if (_countdown1 != 0 && (--_countdown1 == 0)) { + playSound(0); + setVisible(false); + setSprite(kScene3010DeadBoltButtonFileHashes1[_buttonIndex]); + } + + if (_countdown2 != 0 && (--_countdown2 == 0)) { + setVisible(true); + setSprite(kScene3010DeadBoltButtonFileHashes2[_buttonIndex]); + } + +} + +uint32 SsScene3010DeadBoltButton::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x1011: + if (!_buttonLocked && _countdown1 == 0) { + if (_buttonEnabled) { + playSound(1); + playSound(2); + setVisible(true); + _buttonLocked = true; + sendMessage(_parentScene, 0x2000, _buttonIndex); + } else { + sendMessage(_parentScene, 0x2002, _buttonIndex); + } + _needRefresh = true; + updatePosition(); + } + messageResult = 1; + break; + } + return messageResult; +} + +void SsScene3010DeadBoltButton::disableButton() { + _buttonLocked = true; + setSprite(kScene3010DeadBoltButtonFileHashes1[_buttonIndex]); + setVisible(true); +} + +void SsScene3010DeadBoltButton::setSprite(uint32 fileHash) { + loadSprite(fileHash, kSLFDefDrawOffset | kSLFDefPosition | kSLFDefCollisionBoundsOffset); +} + +void SsScene3010DeadBoltButton::setCountdown(int count) { + _countdown2 = count * 18 + 1; +} + +AsScene3010DeadBolt::AsScene3010DeadBolt(NeverhoodEngine *vm, Scene *parentScene, int boltIndex, bool initUnlocked) + : AnimatedSprite(vm, 1100), _parentScene(parentScene), _boltIndex(boltIndex), _soundToggle(true), + _unlocked(false), _locked(false), _countdown(0) { + + _x = kAsScene3010DeadBoltPoints[_boltIndex].x; + _y = kAsScene3010DeadBoltPoints[_boltIndex].y; + + if (getSubVar(VA_LOCKS_DISABLED, kScene3010ButtonNameHashes[_boltIndex])) { + createSurface1(kAsScene3010DeadBoltFileHashes1[_boltIndex], 1200); + startAnimation(kAsScene3010DeadBoltFileHashes1[_boltIndex], 0, -1); + loadSound(0, 0x46005BC4); + } else { + createSurface1(kAsScene3010DeadBoltFileHashes2[_boltIndex], 1200); + startAnimation(kAsScene3010DeadBoltFileHashes2[_boltIndex], 0, -1); + loadSound(0, 0x420073DC); + loadSound(1, 0x420073DC); + } + + setVisible(false); + stIdle(); + if (initUnlocked) + unlock(true); + + _needRefresh = true; + AnimatedSprite::updatePosition(); + +} + +void AsScene3010DeadBolt::update() { + updateAnim(); + updatePosition(); + if (_countdown != 0 && (--_countdown == 0)) { + stDisabled(); + } +} + +uint32 AsScene3010DeadBolt::hmAnimation(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x3002: + gotoNextState(); + break; + } + return messageResult; +} + +void AsScene3010DeadBolt::stIdle() { + stopAnimation(); + SetUpdateHandler(&AsScene3010DeadBolt::update); + SetMessageHandler(&Sprite::handleMessage); + _locked = false; +} + +void AsScene3010DeadBolt::unlock(bool skipAnim) { + if (!_unlocked) { + setVisible(true); + if (skipAnim) { + startAnimation(kAsScene3010DeadBoltFileHashes1[_boltIndex], -1, 0); + _newStickFrameIndex = STICK_LAST_FRAME; + } else { + startAnimation(kAsScene3010DeadBoltFileHashes1[_boltIndex], 0, -1); + SetMessageHandler(&AsScene3010DeadBolt::hmAnimation); + FinalizeState(&AsScene3010DeadBolt::stIdleMessage); + NextState(&AsScene3010DeadBolt::stIdle); + playSound(0); + } + _unlocked = true; + loadSound(2, 0x4010C345); + } +} + +void AsScene3010DeadBolt::stIdleMessage() { + stopAnimation(); + SetMessageHandler(&Sprite::handleMessage); + sendMessage(_parentScene, 0x2001, _boltIndex); +} + +void AsScene3010DeadBolt::lock() { + if (!_locked) { + _locked = true; + setVisible(true); + startAnimation(kAsScene3010DeadBoltFileHashes2[_boltIndex], 0, -1); + SetMessageHandler(&AsScene3010DeadBolt::hmAnimation); + FinalizeState(&AsScene3010DeadBolt::stDisabledMessage); + NextState(&AsScene3010DeadBolt::stIdle); + if (_soundToggle) { + playSound(0); + } else { + playSound(1); + } + _soundToggle = !_soundToggle; + } +} + +void AsScene3010DeadBolt::setCountdown(int count) { + _countdown = count * 18 + 1; +} + +void AsScene3010DeadBolt::stDisabled() { + setVisible(true); + startAnimation(kAsScene3010DeadBoltFileHashes1[_boltIndex], 0, -1); + SetMessageHandler(&AsScene3010DeadBolt::hmAnimation); + FinalizeState(&AsScene3010DeadBolt::stDisabledMessage); + NextState(&AsScene3010DeadBolt::stIdle); + _playBackwards = true; + playSound(2); +} + +void AsScene3010DeadBolt::stDisabledMessage() { + setVisible(false); + sendMessage(_parentScene, 0x2003, _boltIndex); +} + +// Scene3011 + +static const uint32 kAsScene3011SymbolFileHashes[] = { + 0x00C88050, + 0x01488050, + 0x02488050, + 0x04488050, + 0x08488050, + 0x10488050, + 0x20488050, + 0x40488050, + 0x80488050, + 0x00488051, + 0x00488052, + 0x00488054, + 0x008B0000, + 0x008D0000, + 0x00810000, + 0x00990000, + 0x00A90000, + 0x00C90000, + 0x00090000, + 0x01890000, + 0x02890000, + 0x04890000, + 0x08890000, + 0x10890000 +}; + +SsScene3011Button::SsScene3011Button(NeverhoodEngine *vm, Scene *parentScene, bool flag) + : StaticSprite(vm, 1400), _parentScene(parentScene), _countdown(0) { + + loadSprite(flag ? 0x11282020 : 0x994D0433, kSLFDefDrawOffset | kSLFDefPosition | kSLFDefCollisionBoundsOffset, 400); + setVisible(false); + loadSound(0, 0x44061000); + SetUpdateHandler(&SsScene3011Button::update); + SetMessageHandler(&SsScene3011Button::handleMessage); +} + +void SsScene3011Button::update() { + updatePosition(); + if (_countdown != 0 && (--_countdown == 0)) { + setVisible(false); + } +} + +uint32 SsScene3011Button::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = 0; + StaticSprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x1011: + if (_countdown == 0) { + setVisible(true); + _countdown = 4; + sendMessage(_parentScene, 0x2000, 0); + playSound(0); + } + messageResult = 1; + break; + } + return messageResult; +} + +AsScene3011Symbol::AsScene3011Symbol(NeverhoodEngine *vm, int symbolIndex, bool largeSymbol) + : AnimatedSprite(vm, 1000), _symbolIndex(symbolIndex), _largeSymbol(largeSymbol), _isNoisy(false) { + + if (_largeSymbol) { + _x = 310; + _y = 200; + createSurface1(kAsScene3011SymbolFileHashes[_symbolIndex], 1200); + loadSound(0, 0x6052C60F); + loadSound(1, 0x6890433B); + } else { + _symbolIndex = 12; + _x = symbolIndex * 39 + 96; + _y = 225; + createSurface(1200, 41, 48); + loadSound(0, 0x64428609); + loadSound(1, 0x7080023B); + } + setVisible(false); + _needRefresh = true; + SetUpdateHandler(&AnimatedSprite::update); +} + +void AsScene3011Symbol::show(bool isNoisy) { + _isNoisy = isNoisy; + startAnimation(kAsScene3011SymbolFileHashes[_symbolIndex], 0, -1); + setVisible(true); + if (_isNoisy) { + playSound(1); + } else { + playSound(0); + } +} + +void AsScene3011Symbol::hide() { + stopAnimation(); + setVisible(false); +} + +void AsScene3011Symbol::stopSymbolSound() { + if (_isNoisy) { + stopSound(1); + } else { + stopSound(0); + } +} + +void AsScene3011Symbol::change(int symbolIndex, bool isNoisy) { + _symbolIndex = symbolIndex; + _isNoisy = isNoisy; + startAnimation(kAsScene3011SymbolFileHashes[_symbolIndex], 0, -1); + setVisible(true); + if (_isNoisy) { + playSound(1); + } else { + playSound(0); + } +} + +} // End of namespace Neverhood diff --git a/engines/neverhood/modules/module3000_sprites.h b/engines/neverhood/modules/module3000_sprites.h new file mode 100644 index 0000000000..7316613327 --- /dev/null +++ b/engines/neverhood/modules/module3000_sprites.h @@ -0,0 +1,185 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef NEVERHOOD_MODULES_MODULE3000_SPRITES_H +#define NEVERHOOD_MODULES_MODULE3000_SPRITES_H + +#include "neverhood/neverhood.h" +#include "neverhood/module.h" +#include "neverhood/scene.h" +#include "neverhood/modules/module1200.h" + +namespace Neverhood { + +// Scene3009 + +class Scene3009; + +class SsScene3009FireCannonButton : public StaticSprite { +public: + SsScene3009FireCannonButton(NeverhoodEngine *vm, Scene3009 *parentScene); +protected: + Scene3009 *_parentScene; + bool _isClicked; + void update(); + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); +}; + +class SsScene3009SymbolEdges : public StaticSprite { +public: + SsScene3009SymbolEdges(NeverhoodEngine *vm, int index); + void show(); + void hide(); + void startBlinking(); +protected: + int _blinkCountdown; + bool _blinkToggle; + void update(); + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); +}; + +class SsScene3009TargetLine : public StaticSprite { +public: + SsScene3009TargetLine(NeverhoodEngine *vm, int index); + void show(); +}; + +class SsScene3009SymbolArrow : public StaticSprite { +public: + SsScene3009SymbolArrow(NeverhoodEngine *vm, Sprite *asSymbol, int index); + void hide(); +protected: + Sprite *_asSymbol; + int _index; + int _incrDecr; + bool _enabled; + int _countdown; + void update(); + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); +}; + +class AsScene3009VerticalIndicator : public AnimatedSprite { +public: + AsScene3009VerticalIndicator(NeverhoodEngine *vm, Scene3009 *parentScene, int index); + void show(); +protected: + Scene3009 *_parentScene; + bool _enabled; + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); +}; + +class AsScene3009HorizontalIndicator : public AnimatedSprite { +public: + AsScene3009HorizontalIndicator(NeverhoodEngine *vm, Scene3009 *parentScene, uint32 cannonTargetStatus); + void show(); + void stMoveLeft(); + void stMoveRight(); +protected: + Scene3009 *_parentScene; + bool _enabled; + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); + void suMoveLeft(); + void suMoveRight(); +}; + +class AsScene3009Symbol : public AnimatedSprite { +public: + AsScene3009Symbol(NeverhoodEngine *vm, Scene3009 *parentScene, int symbolPosition); + void hide(); +protected: + Scene3009 *_parentScene; + int _symbolPosition; + uint32 _symbolIndex; + SsScene3009SymbolArrow *_ssArrowPrev; + SsScene3009SymbolArrow *_ssArrowNext; + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); +}; + +// Scene3010 + +class SsScene3010DeadBoltButton : public StaticSprite { +public: + SsScene3010DeadBoltButton(NeverhoodEngine *vm, Scene *parentScene, int buttonIndex, int initCountdown, bool initDisabled); + void setCountdown(int count); +protected: + Scene *_parentScene; + int _buttonIndex; + bool _buttonEnabled; + bool _buttonLocked; + int _countdown1; + int _countdown2; + void update(); + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); + void disableButton(); + void setSprite(uint32 fileHash); +}; + +class AsScene3010DeadBolt : public AnimatedSprite { +public: + AsScene3010DeadBolt(NeverhoodEngine *vm, Scene *parentScene, int boltIndex, bool initUnlocked); + void setCountdown(int count); + void lock(); + void unlock(bool skipAnim); +protected: + Scene *_parentScene; + int _boltIndex; + int _countdown; + bool _soundToggle; + bool _unlocked; + bool _locked; + void update(); + uint32 hmAnimation(int messageNum, const MessageParam ¶m, Entity *sender); + void stIdle(); + void stIdleMessage(); + void stDisabled(); + void stDisabledMessage(); +}; + +// Scene3011 + +class SsScene3011Button : public StaticSprite { +public: + SsScene3011Button(NeverhoodEngine *vm, Scene *parentScene, bool flag); +protected: + Scene *_parentScene; + int _countdown; + void update(); + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); +}; + +class AsScene3011Symbol : public AnimatedSprite { +public: + AsScene3011Symbol(NeverhoodEngine *vm, int symbolIndex, bool largeSymbol); + void show(bool isNoisy); + void hide(); + void stopSymbolSound(); + void change(int symbolIndex, bool isNoisy); + int getSymbolIndex() { return _largeSymbol ? _symbolIndex : _symbolIndex - 12; } +protected: + bool _largeSymbol; + bool _isNoisy; + int _symbolIndex; +}; + +} // End of namespace Neverhood + +#endif /* NEVERHOOD_MODULES_MODULE3000_SPRITES_H */ diff --git a/engines/neverhood/resourceman.cpp b/engines/neverhood/resourceman.cpp index 518755a846..b7d560bbb3 100644 --- a/engines/neverhood/resourceman.cpp +++ b/engines/neverhood/resourceman.cpp @@ -96,9 +96,20 @@ struct EntrySizeFix { static const EntrySizeFix entrySizeFixes[] = { // fileHash offset diskSize size fixedSize // Fixes for the Russian "Dyadyushka Risech" version - // TODO + { 0x41137051, 667019, 23391, 41398, 41401 }, // "Options" menu header text + { 0x0f960021, 402268, 1704, 4378, 1870 }, // "Save" menu + { 0x1301a7ea, 1220008, 2373, 4146, 2877 }, // "Load" menu + { 0x84181e81, 201409, 1622, 5058, 1833 }, // "Delete" menu + { 0x08C0AC24, 1031009, 3030, 6498, 3646 }, // Overwrite dialog + { 0xc6604282, 12813649, 19623, 35894, 35895 }, // One of the fonts when reading Willie's notes + { 0x80283101, 13104841, 1961, 3712, 3511 }, // The first message from Willie + { 0x00918480, 17676417, 581, 916, 706 }, // The first wall in the museum + { 0x00800090C,16064875, 19555, 38518, 38526 }, // The first wall in the museum + { 0x058208810,46010519, 24852, 131874, 131776}, // The entry to hut with musical lock + // Fixes for the Russian "Fargus" version - // TODO + { 0x41137051, 758264, 29037, 49590, 49591 }, // "Options" menu header text + { 0xc10b2015, 787304, 4414, 15848, 15853 }, // Text on option buttons // { 0, 0, 0, 0, 0 } }; diff --git a/engines/neverhood/staticdata.cpp b/engines/neverhood/staticdata.cpp index 006992641a..ec9c852118 100644 --- a/engines/neverhood/staticdata.cpp +++ b/engines/neverhood/staticdata.cpp @@ -53,6 +53,22 @@ void StaticData::load(const char *filename) { messageItem.messageValue = fd.readUint32LE(); messageList->push_back(messageItem); } + + // WORKAROUND for a problem in two of the game's message lists: + // the message lists used when Klaymen is drinking the wrong potion + // have as a last element the animation itself (message 0x4832). + // However, when processMessageList() reaches the last element in a + // message list, it allows player input, which means that the player + // can erroneously skip these potion drinking animations. We insert + // another message at the end of these lists to prevent player input + // till the animations are finished + if (id == 0x004AF0C8 || id == 0x004B5BD0) { // wrong potion message lists + MessageItem messageItem; + messageItem.messageNum = 0x4004; // set Klaymen's state to idle + messageItem.messageValue = 0; + messageList->push_back(messageItem); + } + _messageLists[id] = messageList; } diff --git a/engines/parallaction/debug.cpp b/engines/parallaction/debug.cpp index 25acac9b06..4a8f8c71d7 100644 --- a/engines/parallaction/debug.cpp +++ b/engines/parallaction/debug.cpp @@ -62,8 +62,8 @@ void Debugger::postEnter() { bool Debugger::Cmd_Location(int argc, const char **argv) { - const char *character = _vm->_char.getName(); - const char *location = _vm->_location._name; + const char *character; // = _vm->_char.getName(); + const char *location; // = _vm->_location._name; char tmp[PATH_LEN]; diff --git a/engines/pegasus/neighborhood/norad/delta/globegame.cpp b/engines/pegasus/neighborhood/norad/delta/globegame.cpp index 1416c51c8d..0b95e9bc2b 100644 --- a/engines/pegasus/neighborhood/norad/delta/globegame.cpp +++ b/engines/pegasus/neighborhood/norad/delta/globegame.cpp @@ -905,6 +905,11 @@ void GlobeGame::clickGlobe(const Input &input) { _monitorMovie.start(); _owner->requestSpotSound(kMaximumDeactivationIn, kMaximumDeactivationOut, kFilterNoInput, kSpotSoundCompletedFlag); + + // This sound was left out of the original. + _owner->requestSpotSound(kAllSilosDeactivatedIn, kAllSilosDeactivatedOut, + kFilterNoInput, kSpotSoundCompletedFlag); + _gameState = kPlayerWon1; } else { _owner->requestDelay(2, 1, kFilterNoInput, kDelayCompletedFlag); @@ -1060,12 +1065,13 @@ void GlobeGame::doSolve() { _upperNamesMovie.hide(); _lowerNamesMovie.hide(); _countdown.hide(); - _monitorMovie.setSegment(kMaxDeactivatedStart * _monitorMovie.getScale(), kMaxDeactivatedStop * _monitorMovie.getScale()); - _monitorMovie.setTime(kMaxDeactivatedStart * _monitorMovie.getScale()); + _monitorMovie.setSegment(kMaxDeactivatedStart * _monitorMovie.getScale() + (kSiloDeactivatedOut - kSiloDeactivatedIn), kMaxDeactivatedStop * _monitorMovie.getScale()); + _monitorMovie.setTime(kMaxDeactivatedStart * _monitorMovie.getScale() + (kSiloDeactivatedOut - kSiloDeactivatedIn)); _monitorCallBack.setCallBackFlag(kMaxDeactivatedFinished); _monitorCallBack.scheduleCallBack(kTriggerAtStop, 0, 0); _monitorMovie.start(); _owner->requestSpotSound(kMaximumDeactivationIn, kMaximumDeactivationOut, kFilterNoInput, kSpotSoundCompletedFlag); + _owner->requestSpotSound(kAllSilosDeactivatedIn, kAllSilosDeactivatedOut, kFilterNoInput, kSpotSoundCompletedFlag); _gameState = kPlayerWon1; } diff --git a/engines/pegasus/neighborhood/norad/delta/noraddelta.cpp b/engines/pegasus/neighborhood/norad/delta/noraddelta.cpp index f2ea53ff89..1eea2f0156 100644 --- a/engines/pegasus/neighborhood/norad/delta/noraddelta.cpp +++ b/engines/pegasus/neighborhood/norad/delta/noraddelta.cpp @@ -565,6 +565,11 @@ void NoradDelta::activateHotspots() { } else if (GameState.getCurrentRoomAndView() == MakeRoomView(kNorad59, kWest)) { if (GameState.isCurrentDoorOpen()) _vm->getAllHotspots().deactivateOneHotspot(kNorad59WestSpotID); + } else if (GameState.getCurrentRoomAndView() == MakeRoomView(kNorad68, kWest)) { + // WORKAROUND: Make sure the retinal hotspot is disabled after the door opens. + // Fixes a bug in the original. + if (GameState.isCurrentDoorOpen()) + _vm->getAllHotspots().deactivateOneHotspot(kNorad68WestSpotID); } } diff --git a/engines/pegasus/neighborhood/tsa/fulltsa.cpp b/engines/pegasus/neighborhood/tsa/fulltsa.cpp index 9b843da5d6..99efe10272 100644 --- a/engines/pegasus/neighborhood/tsa/fulltsa.cpp +++ b/engines/pegasus/neighborhood/tsa/fulltsa.cpp @@ -2653,7 +2653,6 @@ void FullTSA::receiveNotification(Notification *notification, const Notification GameState.setWSCAnalyzerOn(false); GameState.setWSCDartInAnalyzer(false); GameState.setWSCAnalyzedDart(false); - GameState.setWSCPickedUpAntidote(false); GameState.setWSCSawMorph(false); GameState.setWSCDesignedAntidote(false); GameState.setWSCOfficeMessagesOpen(false); diff --git a/engines/pegasus/neighborhood/tsa/tinytsa.cpp b/engines/pegasus/neighborhood/tsa/tinytsa.cpp index 4f109620c1..0d11f5d904 100644 --- a/engines/pegasus/neighborhood/tsa/tinytsa.cpp +++ b/engines/pegasus/neighborhood/tsa/tinytsa.cpp @@ -337,7 +337,6 @@ void TinyTSA::receiveNotification(Notification *notification, const Notification GameState.setWSCRemovedDart(false); GameState.setWSCAnalyzerOn(false); GameState.setWSCAnalyzedDart(false); - GameState.setWSCPickedUpAntidote(false); GameState.setWSCSawMorph(false); GameState.setWSCDesignedAntidote(false); GameState.setWSCOfficeMessagesOpen(false); diff --git a/engines/pegasus/neighborhood/wsc/wsc.cpp b/engines/pegasus/neighborhood/wsc/wsc.cpp index 50b7774da4..09e2a48a52 100644 --- a/engines/pegasus/neighborhood/wsc/wsc.cpp +++ b/engines/pegasus/neighborhood/wsc/wsc.cpp @@ -2336,13 +2336,16 @@ Hotspot *WSC::getItemScreenSpot(Item *item, DisplayElement *element) { void WSC::pickedUpItem(Item *item) { switch (item->getObjectID()) { case kAntidote: + // WORKAROUND: Make sure the poison is cleared separately from deactivating + // the synthesizer video. + GameState.setWSCPoisoned(false); + GameState.setWSCRemovedDart(false); + _privateFlags.setFlag(kWSCDraggingAntidoteFlag, false); + playSpotSoundSync(kDrinkAntidoteIn, kDrinkAntidoteOut); + setUpPoison(); + if (!GameState.getWSCPickedUpAntidote()) { - GameState.setWSCPoisoned(false); - GameState.setWSCRemovedDart(false); GameState.setWSCPickedUpAntidote(true); - _privateFlags.setFlag(kWSCDraggingAntidoteFlag, false); - playSpotSoundSync(kDrinkAntidoteIn, kDrinkAntidoteOut); - setUpPoison(); startExtraSequence(kW03SouthDeactivate, kExtraCompletedFlag, kFilterNoInput); } break; diff --git a/engines/plugins_table.h b/engines/plugins_table.h index 04971a6764..38cd43ac74 100644 --- a/engines/plugins_table.h +++ b/engines/plugins_table.h @@ -8,6 +8,9 @@ LINK_PLUGIN(AGI) #if PLUGIN_ENABLED_STATIC(AGOS) LINK_PLUGIN(AGOS) #endif +#if PLUGIN_ENABLED_STATIC(AVALANCHE) +LINK_PLUGIN(AVALANCHE) +#endif #if PLUGIN_ENABLED_STATIC(CGE) LINK_PLUGIN(CGE) #endif diff --git a/engines/saga/introproc_ite.cpp b/engines/saga/introproc_ite.cpp index 484ebe1779..ed53e078a0 100644 --- a/engines/saga/introproc_ite.cpp +++ b/engines/saga/introproc_ite.cpp @@ -993,7 +993,7 @@ int Scene::ITEIntroTreeHouseProc(int param) { } // Queue game credits list - eventColumns = ITEQueueCredits(DISSOLVE_DURATION + 2000, CREDIT_DURATION1, n_credits1, credits1); + ITEQueueCredits(DISSOLVE_DURATION + 2000, CREDIT_DURATION1, n_credits1, credits1); eventColumns = ITEQueueCredits(DISSOLVE_DURATION + 7000, CREDIT_DURATION1, n_credits2, credits2); // End scene after credit display @@ -1073,7 +1073,7 @@ int Scene::ITEIntroFairePathProc(int param) { _vm->_events->chain(eventColumns, event); // Queue game credits list - eventColumns = ITEQueueCredits(DISSOLVE_DURATION + 2000, CREDIT_DURATION1, n_credits1, credits1); + ITEQueueCredits(DISSOLVE_DURATION + 2000, CREDIT_DURATION1, n_credits1, credits1); eventColumns = ITEQueueCredits(DISSOLVE_DURATION + 7000, CREDIT_DURATION1, n_credits2, credits2); // End scene after credit display diff --git a/engines/saga/sprite.cpp b/engines/saga/sprite.cpp index 2895c6800c..bf550659e9 100644 --- a/engines/saga/sprite.cpp +++ b/engines/saga/sprite.cpp @@ -71,17 +71,7 @@ Sprite::~Sprite() { } void Sprite::loadList(int resourceId, SpriteList &spriteList) { - SpriteInfo *spriteInfo; ByteArray spriteListData; - uint16 oldSpriteCount; - uint16 newSpriteCount; - uint16 spriteCount; - uint i; - int outputLength, inputLength; - uint32 offset; - const byte *spritePointer; - const byte *spriteDataPointer; - _vm->_resource->loadResource(_spriteContext, resourceId, spriteListData); if (spriteListData.empty()) { @@ -90,19 +80,19 @@ void Sprite::loadList(int resourceId, SpriteList &spriteList) { ByteArrayReadStreamEndian readS(spriteListData, _spriteContext->isBigEndian()); - spriteCount = readS.readUint16(); + uint16 spriteCount = readS.readUint16(); debug(9, "Sprites: %d", spriteCount); - oldSpriteCount = spriteList.size(); - newSpriteCount = oldSpriteCount + spriteCount; + uint16 oldSpriteCount = spriteList.size(); + uint16 newSpriteCount = oldSpriteCount + spriteCount; spriteList.resize(newSpriteCount); bool bigHeader = _vm->getGameId() == GID_IHNM || _vm->isMacResources(); - for (i = oldSpriteCount; i < spriteList.size(); i++) { - spriteInfo = &spriteList[i]; + for (uint i = oldSpriteCount; i < spriteList.size(); i++) { + uint32 offset; if (bigHeader) offset = readS.readUint32(); else @@ -115,9 +105,11 @@ void Sprite::loadList(int resourceId, SpriteList &spriteList) { return; } - spritePointer = spriteListData.getBuffer(); + const byte *spritePointer = spriteListData.getBuffer(); spritePointer += offset; + const byte *spriteDataPointer; + SpriteInfo *spriteInfo = &spriteList[i]; if (bigHeader) { Common::MemoryReadStreamEndian readS2(spritePointer, 8, _spriteContext->isBigEndian()); @@ -139,8 +131,8 @@ void Sprite::loadList(int resourceId, SpriteList &spriteList) { spriteDataPointer = spritePointer + readS2.pos(); } - outputLength = spriteInfo->width * spriteInfo->height; - inputLength = spriteListData.size() - (spriteDataPointer - spriteListData.getBuffer()); + int outputLength = spriteInfo->width * spriteInfo->height; + int inputLength = spriteListData.size() - (spriteDataPointer - spriteListData.getBuffer()); spriteInfo->decodedBuffer.resize(outputLength); if (outputLength > 0) { decodeRLEBuffer(spriteDataPointer, inputLength, outputLength); diff --git a/engines/sci/detection_tables.h b/engines/sci/detection_tables.h index d0a0db2a3b..5ad49acf5c 100644 --- a/engines/sci/detection_tables.h +++ b/engines/sci/detection_tables.h @@ -555,6 +555,14 @@ static const struct ADGameDescription SciGameDescriptions[] = { AD_LISTEND}, Common::ES_ESP, Common::kPlatformDOS, 0, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, + // Eco Quest 2 - German DOS Floppy (supplied by frankenbuam in bug report #3615072) + {"ecoquest2", "Floppy", { + {"resource.map", 0, "d8b20073e64f41f6437f73143a186753", 5643}, + {"resource.000", 0, "cc1d17e5637528dbe4a812699e1cbfc6", 4210876}, + {"resource.msg", 0, "2f231d31af172ea72ed533fd112f971b", 133458}, + AD_LISTEND}, + Common::DE_DEU, Common::kPlatformDOS, 0, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, + // Freddy Pharkas - English DOS demo (from FRG) // SCI interpreter version 1.001.069 {"freddypharkas", "Demo", { @@ -3736,6 +3744,14 @@ static const struct ADGameDescription SciGameDescriptions[] = { AD_LISTEND}, Common::EN_ANY, Common::kPlatformWindows, ADGF_CD, GUIO5(GUIO_MIDIGM, GAMEOPTION_SQ4_SILVER_CURSORS, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, + // Space Quest 4 - English DOS CD patch 1.2 (unofficial - NRS) - THIS VERSION IS PIRATED/CRACKED AND REPACKAGED =DO NOT RE-ADD= + // In essence, this "patch" includes a mixture the CD and floppy versions (the whole game), without the speech file + {"sq4", "CD", { + {"resource.map", 0, "38287a646458a1dabded55d094407793", 7139}, + {"resource.000", 0, "231fd8421e1f211e1bcf9d7b8b6408e7", 9525849}, + AD_LISTEND}, + Common::EN_ANY, Common::kPlatformDOS, ADGF_PIRATED, GUIO4(GAMEOPTION_SQ4_SILVER_CURSORS, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, + // Space Quest 4 - Spanish DOS CD (from jvprat, is still text only, not talkie, also includes english language) // Executable scanning reports "1.SQ4.057", VERSION file reports "1.000" // SCI interpreter version 1.000.200 (just a guess) diff --git a/engines/sci/graphics/picture.cpp b/engines/sci/graphics/picture.cpp index 91c72456a8..8ad4f535f9 100644 --- a/engines/sci/graphics/picture.cpp +++ b/engines/sci/graphics/picture.cpp @@ -658,6 +658,7 @@ void GfxPicture::drawVectorData(byte *data, int dataSize) { case 35: case 381: case 376: + //case 390: // in the blacklisted NRS patch 1.2 (bug #3615060) return; default: break; diff --git a/engines/scumm/imuse_digi/dimuse_sndmgr.cpp b/engines/scumm/imuse_digi/dimuse_sndmgr.cpp index abd0d68e56..af4f8775f4 100644 --- a/engines/scumm/imuse_digi/dimuse_sndmgr.cpp +++ b/engines/scumm/imuse_digi/dimuse_sndmgr.cpp @@ -667,15 +667,18 @@ int32 ImuseDigiSndMgr::getDataFromRegion(SoundDesc *soundDesc, int region, byte if (scumm_stricmp(fileName, soundDesc->lastFileName) != 0) { int32 offs = 0, len = 0; Common::SeekableReadStream *cmpFile; +#if defined(USE_FLAC) || defined(USE_VORBIS) || defined(USE_MAD) uint8 soundMode = 0; +#endif sprintf(fileName, "%s_reg%03d.fla", soundDesc->name, region); cmpFile = soundDesc->bundle->getFile(fileName, offs, len); if (len) { #ifndef USE_FLAC error("FLAC library compiled support needed"); -#endif +#else soundMode = 3; +#endif } if (!len) { sprintf(fileName, "%s_reg%03d.ogg", soundDesc->name, region); @@ -683,8 +686,9 @@ int32 ImuseDigiSndMgr::getDataFromRegion(SoundDesc *soundDesc, int region, byte if (len) { #ifndef USE_VORBIS error("Vorbis library compiled support needed"); -#endif +#else soundMode = 2; +#endif } } if (!len) { @@ -693,8 +697,9 @@ int32 ImuseDigiSndMgr::getDataFromRegion(SoundDesc *soundDesc, int region, byte if (len) { #ifndef USE_MAD error("Mad library compiled support needed"); -#endif +#else soundMode = 1; +#endif } } assert(len); diff --git a/engines/scumm/sound.cpp b/engines/scumm/sound.cpp index 5e5e8045b5..aaf7f90aca 100644 --- a/engines/scumm/sound.cpp +++ b/engines/scumm/sound.cpp @@ -470,8 +470,10 @@ static int compareMP3OffsetTable(const void *a, const void *b) { void Sound::startTalkSound(uint32 offset, uint32 b, int mode, Audio::SoundHandle *handle) { int num = 0, i; - int size = 0; int id = -1; +#if defined(USE_FLAC) || defined(USE_VORBIS) || defined(USE_MAD) + int size = 0; +#endif Common::ScopedPtr<ScummFile> file; if (_vm->_game.id == GID_CMI) { @@ -562,10 +564,14 @@ void Sound::startTalkSound(uint32 offset, uint32 b, int mode, Audio::SoundHandle num = result->num_tags; } offset = result->new_offset; +#if defined(USE_FLAC) || defined(USE_VORBIS) || defined(USE_MAD) size = result->compressed_size; +#endif } else { offset += 8; +#if defined(USE_FLAC) || defined(USE_VORBIS) || defined(USE_MAD) size = -1; +#endif } file.reset(new ScummFile()); diff --git a/engines/sword25/kernel/persistenceservice.cpp b/engines/sword25/kernel/persistenceservice.cpp index 27d669caa1..df26da7800 100644 --- a/engines/sword25/kernel/persistenceservice.cpp +++ b/engines/sword25/kernel/persistenceservice.cpp @@ -59,7 +59,7 @@ static const int VERSIONNUM = 2; char gameTarget[MAX_SAVEGAME_SIZE]; void setGameTarget(const char *target) { - strncpy(gameTarget, target, MAX_SAVEGAME_SIZE); + strncpy(gameTarget, target, MAX_SAVEGAME_SIZE - 1); } static Common::String generateSavegameFilename(uint slotID) { diff --git a/engines/sword25/math/region.cpp b/engines/sword25/math/region.cpp index b6ebaee23f..db888e432a 100644 --- a/engines/sword25/math/region.cpp +++ b/engines/sword25/math/region.cpp @@ -311,10 +311,10 @@ bool Region::persist(OutputPersistenceBlock &writer) { ++It; } - writer.write((uint32)_boundingBox.left); - writer.write((uint32)_boundingBox.top); - writer.write((uint32)_boundingBox.right); - writer.write((uint32)_boundingBox.bottom); + writer.write((int32)_boundingBox.left); + writer.write((int32)_boundingBox.top); + writer.write((int32)_boundingBox.right); + writer.write((int32)_boundingBox.bottom); return Result; } diff --git a/engines/sword25/sfx/soundengine.cpp b/engines/sword25/sfx/soundengine.cpp index d90849e449..8ff1b0cf2a 100644 --- a/engines/sword25/sfx/soundengine.cpp +++ b/engines/sword25/sfx/soundengine.cpp @@ -339,7 +339,10 @@ bool SoundEngine::persist(OutputPersistenceBlock &writer) { _handles[i].type = kFreeHandle; writer.writeString(_handles[i].fileName); - writer.write(_handles[i].sndType); + if (_handles[i].type == kFreeHandle) + writer.write((int32)-1); + else + writer.write(_handles[i].sndType); writer.write(_handles[i].volume); writer.write(_handles[i].pan); writer.write(_handles[i].loop); @@ -381,7 +384,7 @@ bool SoundEngine::unpersist(InputPersistenceBlock &reader) { reader.read(layer); if (reader.isGood()) { - if (sndType != kFreeHandle) + if (sndType != -1) playSoundEx(fileName, (SOUND_TYPES)sndType, volume, pan, loop, loopStart, loopEnd, layer, i); } else return false; diff --git a/engines/testbed/config-params.cpp b/engines/testbed/config-params.cpp index e89da0b07f..47e5dfa933 100644 --- a/engines/testbed/config-params.cpp +++ b/engines/testbed/config-params.cpp @@ -38,6 +38,8 @@ ConfigParams::ConfigParams() { _isInteractive = true; _isGameDataFound = true; _rerunTests = false; + + _testbedConfMan = 0; } void ConfigParams::initLogging(const char *dirname, const char *filename, bool enable) { diff --git a/engines/testbed/config.h b/engines/testbed/config.h index d611ae4ec3..7d479a74fd 100644 --- a/engines/testbed/config.h +++ b/engines/testbed/config.h @@ -113,7 +113,7 @@ private: class TestbedInteractionDialog : public GUI::Dialog { public: - TestbedInteractionDialog(uint x, uint y, uint w, uint h) : GUI::Dialog(x, y, w, h) {} + TestbedInteractionDialog(uint x, uint y, uint w, uint h) : GUI::Dialog(x, y, w, h), _xOffset(0), _yOffset(0) {} ~TestbedInteractionDialog() {} virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data); void addButton(uint w, uint h, const Common::String name, uint32 cmd, uint xOffset = 0, uint yPadding = 8); diff --git a/engines/testbed/events.cpp b/engines/testbed/events.cpp index 78de87e133..4b9ced2a53 100644 --- a/engines/testbed/events.cpp +++ b/engines/testbed/events.cpp @@ -83,11 +83,10 @@ struct keycodeToChar { char EventTests::keystrokeToChar() { Common::EventManager *eventMan = g_system->getEventManager(); - bool quitLoop = false; Common::Event event; // handle all keybd events - while (!quitLoop) { + while (true) { while (eventMan->pollEvent(event)) { // Quit if explicitly requested! if (Engine::shouldQuit()) { @@ -110,8 +109,6 @@ char EventTests::keystrokeToChar() { } } } - - return 0; } Common::Rect EventTests::drawFinishZone() { diff --git a/engines/tony/gfxcore.cpp b/engines/tony/gfxcore.cpp index 410f9b8971..3433ad3024 100644 --- a/engines/tony/gfxcore.cpp +++ b/engines/tony/gfxcore.cpp @@ -117,6 +117,7 @@ RMGfxBuffer::operator void *() { } RMGfxBuffer::RMGfxBuffer(int dimx, int dimy, int nBpp) { + _origBuf = _buf = NULL; create(dimx, dimy, nBpp); } diff --git a/engines/tsage/converse.cpp b/engines/tsage/converse.cpp index 9828ca71d4..9e7d84105a 100644 --- a/engines/tsage/converse.cpp +++ b/engines/tsage/converse.cpp @@ -836,6 +836,17 @@ void StripManager::signal() { break; } } + + // If no entry found, get the default response + if (!delayFlag) { + idx = 0; + while (obj44._list[idx + 1]._id) + ++idx; + + choiceList.push_back((const char *)&_script[0] + obj44._list[idx]._scriptOffset); + strIndex = idx; + delayFlag = true; + } } else { // Standard choices loading for (idx = 0; idx < OBJ0A_LIST_SIZE; ++idx) { diff --git a/engines/tsage/core.cpp b/engines/tsage/core.cpp index f7fbb1daa1..3332b12cf6 100644 --- a/engines/tsage/core.cpp +++ b/engines/tsage/core.cpp @@ -1749,9 +1749,22 @@ void SceneItem::display(int resNum, int lineNum, ...) { } g_globals->_sceneText.fixPriority(255); + + // In Return to Ringworld, if in voice mode only, don't show the text + if ((g_vm->getGameID() == GType_Ringworld2) && (R2_GLOBALS._speechSubtitles & SPEECH_VOICE) + && !(R2_GLOBALS._speechSubtitles & SPEECH_TEXT)) + g_globals->_sceneText.hide(); + g_globals->_sceneObjects->draw(); } + // For Return to Ringworld, play the voice overs in sequence + if ((g_vm->getGameID() == GType_Ringworld2) && (R2_GLOBALS._speechSubtitles & SPEECH_VOICE) + && !playList.empty()) { + R2_GLOBALS._playStream.play(*playList.begin(), NULL); + playList.pop_front(); + } + // Unless the flag is set to keep the message on-screen, show it until a mouse or keypress, then remove it if (!keepOnscreen && !msg.empty()) { Event event; @@ -1761,14 +1774,23 @@ void SceneItem::display(int resNum, int lineNum, ...) { EVENT_BUTTON_DOWN | EVENT_KEYPRESS)) { GLOBALS._screenSurface.updateScreen(); g_system->delayMillis(10); - } - // For Return to Ringworld, play the voice overs in sequence - if ((g_vm->getGameID() == GType_Ringworld2) && !playList.empty() && !R2_GLOBALS._playStream.isPlaying()) { - R2_GLOBALS._playStream.play(*playList.begin(), NULL); - playList.pop_front(); + if ((g_vm->getGameID() == GType_Ringworld2) && (R2_GLOBALS._speechSubtitles & SPEECH_VOICE)) { + // Allow the play stream to do processing + R2_GLOBALS._playStream.dispatch(); + if (!R2_GLOBALS._playStream.isPlaying()) { + // Check if there are further voice samples to play + if (!playList.empty()) { + R2_GLOBALS._playStream.play(*playList.begin(), NULL); + playList.pop_front(); + } + } + } } + if (g_vm->getGameID() == GType_Ringworld2) + R2_GLOBALS._playStream.stop(); + g_globals->_sceneText.remove(); } @@ -2482,7 +2504,8 @@ void SceneObject::postInit(SceneObjectList *OwnerList) { if (!OwnerList) OwnerList = g_globals->_sceneObjects; - if (!OwnerList->contains(this) || ((_flags & OBJFLAG_REMOVE) != 0)) { + bool isExisting = OwnerList->contains(this); + if (!isExisting || ((_flags & OBJFLAG_REMOVE) != 0)) { _percent = 100; _priority = 255; _flags = OBJFLAG_ZOOMED; @@ -2501,7 +2524,8 @@ void SceneObject::postInit(SceneObjectList *OwnerList) { _numFrames = 10; _regionBitList = 0; - OwnerList->push_back(this); + if (!isExisting) + OwnerList->push_back(this); _flags |= OBJFLAG_PANES; } } @@ -2812,6 +2836,11 @@ void BackgroundSceneObject::setup2(int visage, int stripFrameNum, int frameNum, void BackgroundSceneObject::copySceneToBackground() { GLOBALS._sceneManager._scene->_backSurface.copyFrom(g_globals->gfxManager().getSurface(), 0, 0); + + // WORKAROUND: Since savegames don't store the active screen data, once we copy the + // foreground objects to the background, we have to prevent the scene being saved. + if (g_vm->getGameID() == GType_Ringworld2) + ((Ringworld2::SceneExt *)GLOBALS._sceneManager._scene)->_preventSaving = true; } /*--------------------------------------------------------------------------*/ @@ -3322,20 +3351,24 @@ void Player::postInit(SceneObjectList *OwnerList) { void Player::disableControl() { _canWalk = false; - _uiEnabled = false; g_globals->_events.setCursor(CURSOR_NONE); _enabled = false; - if ((g_vm->getGameID() != GType_Ringworld) && T2_GLOBALS._uiElements._active) - T2_GLOBALS._uiElements.hide(); + if (g_vm->getGameID() != GType_Ringworld2) { + _uiEnabled = false; + + if ((g_vm->getGameID() != GType_Ringworld) && T2_GLOBALS._uiElements._active) + T2_GLOBALS._uiElements.hide(); + } } void Player::enableControl() { CursorType cursor; _canWalk = true; - _uiEnabled = true; _enabled = true; + if (g_vm->getGameID() != GType_Ringworld2) + _uiEnabled = true; switch (g_vm->getGameID()) { case GType_BlueForce: @@ -3343,7 +3376,7 @@ void Player::enableControl() { cursor = g_globals->_events.getCursor(); g_globals->_events.setCursor(cursor); - if (T2_GLOBALS._uiElements._active) + if (g_vm->getGameID() == GType_BlueForce && T2_GLOBALS._uiElements._active) T2_GLOBALS._uiElements.show(); break; @@ -4253,11 +4286,11 @@ void SceneHandler::process(Event &event) { g_vm->_debugger->onFrame(); } - if ((event.eventType == EVENT_KEYPRESS) && g_globals->_player._enabled && g_globals->_player._canWalk) { + if ((event.eventType == EVENT_KEYPRESS) && g_globals->_player._enabled) { // Keyboard shortcuts for different actions switch (event.kbd.keycode) { case Common::KEYCODE_w: - g_globals->_events.setCursor(CURSOR_WALK); + g_globals->_events.setCursor(GLOBALS._player._canWalk ? CURSOR_WALK : CURSOR_USE); event.handled = true; break; case Common::KEYCODE_l: diff --git a/engines/tsage/globals.cpp b/engines/tsage/globals.cpp index 9bd7249902..ece6ae3eda 100644 --- a/engines/tsage/globals.cpp +++ b/engines/tsage/globals.cpp @@ -541,7 +541,7 @@ void Ringworld2Globals::synchronize(Serializer &s) { s.syncAsSint16LE(_v57C2C); s.syncAsSint16LE(_speechSubtitles); - byte temp; + byte temp = 0; s.syncAsByte(temp); s.syncAsByte(_s1550PlayerArea[R2_QUINN].x); s.syncAsByte(_s1550PlayerArea[R2_SEEKER].x); diff --git a/engines/tsage/ringworld2/ringworld2_dialogs.cpp b/engines/tsage/ringworld2/ringworld2_dialogs.cpp index 057d91a46e..4ebbdd602d 100644 --- a/engines/tsage/ringworld2/ringworld2_dialogs.cpp +++ b/engines/tsage/ringworld2/ringworld2_dialogs.cpp @@ -165,7 +165,7 @@ void RightClickDialog::execute() { break; case 1: // Walk action - cursorNum = CURSOR_WALK; + cursorNum = R2_GLOBALS._player._canWalk ? CURSOR_WALK : CURSOR_USE; break; case 2: // Use action diff --git a/engines/tsage/ringworld2/ringworld2_logic.cpp b/engines/tsage/ringworld2/ringworld2_logic.cpp index b86b8283ed..90df72ab32 100644 --- a/engines/tsage/ringworld2/ringworld2_logic.cpp +++ b/engines/tsage/ringworld2/ringworld2_logic.cpp @@ -112,8 +112,10 @@ Scene *Ringworld2Game::createScene(int sceneNumber) { // Cutscene - trip in space return new Scene1010(); case 1020: + // Cutscene - trip in space 2 return new Scene1020(); case 1100: + // Canyon return new Scene1100(); case 1200: // ARM Base - Air Ducts Maze @@ -170,7 +172,6 @@ Scene *Ringworld2Game::createScene(int sceneNumber) { // Flup Tube Corridor Maze return new Scene1950(); /* Scene group #2 */ - // case 2000: // Spill Mountains return new Scene2000(); @@ -320,8 +321,11 @@ bool Ringworld2Game::canLoadGameStateCurrently() { * Returns true if it is currently okay to save the game */ bool Ringworld2Game::canSaveGameStateCurrently() { - // Don't allow a game to be saved if a dialog is active - return g_globals->_gfxManagers.size() == 1; + // Don't allow a game to be saved if a dialog is active, or if an animation + // is playing, or if an active scene prevents it + return g_globals->_gfxManagers.size() == 1 && R2_GLOBALS._animationCtr == 0 && + (!R2_GLOBALS._sceneManager._scene || + !((SceneExt *)R2_GLOBALS._sceneManager._scene)->_preventSaving); } /*--------------------------------------------------------------------------*/ @@ -336,6 +340,7 @@ SceneExt::SceneExt(): Scene() { _savedPlayerEnabled = false; _savedUiEnabled = false; _savedCanWalk = false; + _preventSaving = false; // WORKAROUND: In the original, playing animations don't reset the global _animationCtr // counter as scene changes unless the playing animation explicitly finishes. For now, @@ -591,6 +596,9 @@ void SceneExt::loadBlankScene() { void SceneHandlerExt::postInit(SceneObjectList *OwnerList) { SceneHandler::postInit(OwnerList); + + if (!R2_GLOBALS._playStream.setFile("SND4K.RES")) + warning("Could not find SND4K.RES voice file"); } void SceneHandlerExt::process(Event &event) { @@ -615,7 +623,7 @@ void SceneHandlerExt::process(Event &event) { void SceneHandlerExt::postLoad(int priorSceneBeforeLoad, int currentSceneBeforeLoad) { if (priorSceneBeforeLoad == -1 || priorSceneBeforeLoad == 50 - || priorSceneBeforeLoad == 180 || priorSceneBeforeLoad == 205) + || currentSceneBeforeLoad == 180 || priorSceneBeforeLoad == 205) setupPaletteMaps(); if (currentSceneBeforeLoad == 2900) { @@ -1788,7 +1796,9 @@ AnimationPlayer::~AnimationPlayer() { void AnimationPlayer::synchronize(Serializer &s) { EventHandler::synchronize(s); - warning("TODO AnimationPlayer::synchronize"); + + // TODO: Implement saving for animation player state. Currently, I disable saving + // when an animation is active, so saving it's state would a "nice to have". } void AnimationPlayer::remove() { diff --git a/engines/tsage/ringworld2/ringworld2_logic.h b/engines/tsage/ringworld2/ringworld2_logic.h index aeac2fdd6a..5c8af8d884 100644 --- a/engines/tsage/ringworld2/ringworld2_logic.h +++ b/engines/tsage/ringworld2/ringworld2_logic.h @@ -85,6 +85,7 @@ public: bool _savedPlayerEnabled; bool _savedUiEnabled; bool _savedCanWalk; + bool _preventSaving; Visage _cursorVisage; SynchronizedList<EventHandler *> _sceneAreas; diff --git a/engines/tsage/ringworld2/ringworld2_scenes0.cpp b/engines/tsage/ringworld2/ringworld2_scenes0.cpp index 4ca8eee5de..5e4b4e4191 100644 --- a/engines/tsage/ringworld2/ringworld2_scenes0.cpp +++ b/engines/tsage/ringworld2/ringworld2_scenes0.cpp @@ -31,6 +31,11 @@ namespace TsAGE { namespace Ringworld2 { +/*-------------------------------------------------------------------------- + * Scene 50 - Waking up cutscene + * + *--------------------------------------------------------------------------*/ + void Scene50::Action1::signal() { switch (_actionIndex++) { case 0: @@ -48,8 +53,8 @@ void Scene50::Action1::signal() { } void Scene50::postInit(SceneObjectList *OwnerList) { - SceneExt::postInit(OwnerList); loadScene(110); + SceneExt::postInit(OwnerList); R2_GLOBALS._uiElements._active = false; R2_GLOBALS._scenePalette.loadPalette(0); @@ -227,8 +232,6 @@ bool Scene100::Terminal::startAction(CursorType action, Event &event) { void Scene100::postInit(SceneObjectList *OwnerList) { loadScene(100); - R2_GLOBALS._scenePalette.loadPalette(0); - R2_GLOBALS._scenePalette.setEntry(255, 255, 255, 255); SceneExt::postInit(); if (R2_GLOBALS._sceneManager._previousScene != 125) @@ -404,7 +407,7 @@ bool Scene125::Food::startAction(CursorType action, Event &event) { Scene125::Icon::Icon(): SceneActor() { _lookLineNum = 0; - _field98 = 0; + _iconId = 0; _pressed = false; } @@ -427,7 +430,7 @@ void Scene125::Icon::postInit(SceneObjectList *OwnerList) { void Scene125::Icon::synchronize(Serializer &s) { SceneActor::synchronize(s); s.syncAsSint16LE(_lookLineNum); - s.syncAsSint16LE(_field98); + s.syncAsSint16LE(_iconId); s.syncAsSint16LE(_pressed); } @@ -507,7 +510,7 @@ void Scene125::Icon::process(Event &event) { void Scene125::Icon::setIcon(int id) { Scene125 *scene = (Scene125 *)R2_GLOBALS._sceneManager._scene; - _lookLineNum = _field98 = id; + _lookLineNum = _iconId = id; SceneActor::_lookLineNum = id; _sceneText1.remove(); @@ -614,8 +617,8 @@ Scene125::Scene125(): SceneExt() { } void Scene125::postInit(SceneObjectList *OwnerList) { - SceneExt::postInit(); loadScene(160); + SceneExt::postInit(); _palette.loadPalette(0); if (R2_GLOBALS._sceneManager._previousScene != 125) @@ -833,7 +836,7 @@ void Scene125::process(Event &event) { void Scene125::dispatch() { if (_soundCount) - R2_GLOBALS._playStream.proc1(); + R2_GLOBALS._playStream.dispatch(); Scene::dispatch(); } @@ -1214,8 +1217,8 @@ Common::String Scene125::parseMessage(const Common::String &msg) { *--------------------------------------------------------------------------*/ void Scene150::postInit(SceneObjectList *OwnerList) { - SceneExt::postInit(); loadScene(100); + SceneExt::postInit(); _door.postInit(); _door._state = 0; @@ -1421,8 +1424,8 @@ Scene160::Scene160(): SceneExt() { } void Scene160::postInit(SceneObjectList *OwnerList) { - SceneExt::postInit(); loadScene(4001); + SceneExt::postInit(); R2_GLOBALS._player._uiEnabled = false; R2_GLOBALS._player.enableControl(); @@ -1532,6 +1535,9 @@ void Scene180::remove() { // _stripManager._field2EA = -1; SceneExt::remove(); + R2_GLOBALS._scenePalette.loadPalette(0); + R2_GLOBALS._scenePalette.setEntry(255, 255, 255, 255); + R2_GLOBALS._events.setCursor(CURSOR_WALK); // word_575F7 = 0; R2_GLOBALS._playStream.stop(); @@ -2337,8 +2343,9 @@ Scene205::Scene205(): SceneExt() { } void Scene205::postInit(SceneObjectList *OwnerList) { - SceneExt::postInit(); loadScene(4000); + SceneExt::postInit(); + BF_GLOBALS._interfaceY = 200; R2_GLOBALS._player._uiEnabled = false; R2_GLOBALS._sound1.play(337); @@ -2600,8 +2607,10 @@ void Scene250::synchronize(Serializer &s) { void Scene250::postInit(SceneObjectList *OwnerList) { loadScene(250); SceneExt::postInit(); + BF_GLOBALS._interfaceY = 200; R2_GLOBALS._player.postInit(); + R2_GLOBALS._uiElements._active = false; R2_GLOBALS._player.setVisage(10); R2_GLOBALS._player.hide(); R2_GLOBALS._player.enableControl(); @@ -2611,12 +2620,12 @@ void Scene250::postInit(SceneObjectList *OwnerList) { _currentFloor.setup(250, 1, 5); _currentFloor.setDetails(250, 13, -1, -1, 1, (SceneItem *)NULL); - _button1.setFloor(11); - _button1.setup(250, 1, 3); - _button1.setPosition(Common::Point(400, 100)); - _button1.setDetails(250, 14, -1, -1, 1, (SceneItem *)NULL); - _button1.fixPriority(190); - _button1.hide(); + _destinationFloor.setFloor(11); + _destinationFloor.setup(250, 1, 3); + _destinationFloor.setPosition(Common::Point(400, 100)); + _destinationFloor.setDetails(250, 14, -1, -1, 1, (SceneItem *)NULL); + _destinationFloor.fixPriority(190); + _destinationFloor.hide(); _floor1.setFloor(1); _floor2.setFloor(2); @@ -2628,8 +2637,8 @@ void Scene250::postInit(SceneObjectList *OwnerList) { _floor8.setFloor(8); _floor9.setFloor(9); - _item2.setDetails(Rect(0, 0, 73, SCREEN_HEIGHT), 250, 9, -1, 9, 1, NULL); - _item4.setDetails(Rect(239, 16, 283, 164), 250, 6, -1, -1, 1, NULL); + _door.setDetails(Rect(0, 0, 73, SCREEN_HEIGHT), 250, 9, -1, 9, 1, NULL); + _directionIndicator.setDetails(Rect(239, 16, 283, 164), 250, 6, -1, -1, 1, NULL); _background.setDetails(Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 250, 0, 1, -1, 1, NULL); R2_GLOBALS._events.setCursor(CURSOR_USE); @@ -2764,8 +2773,8 @@ void Scene250::signal() { void Scene250::changeFloor(int floorNumber) { _destButtonY = (floorNumber - 1) * 12 + 43; - _button1.setPosition(Common::Point(111, _destButtonY)); - _button1.show(); + _destinationFloor.setPosition(Common::Point(111, _destButtonY)); + _destinationFloor.show(); _skippableFl = true; _sceneMode = (_currButtonY >= _destButtonY) ? 6 : 1; @@ -3001,7 +3010,7 @@ bool Scene300::Miranda::startAction(CursorType action, Event &event) { if (!R2_GLOBALS.getFlag(57)) { R2_GLOBALS._events.setCursor(CURSOR_ARROW); scene->_stripManager.start3(434, scene, R2_GLOBALS._stripManager_lookupList); - } else if (R2_GLOBALS._player._characterScene[R2_MIRANDA] != 500) { + } else if (R2_GLOBALS._player._characterScene[R2_SEEKER] != 500) { R2_GLOBALS._events.setCursor(CURSOR_ARROW); scene->_stripManager.start3(407, scene, R2_GLOBALS._stripManager_lookupList); } else { @@ -3134,17 +3143,15 @@ bool Scene300::Quinn::startAction(CursorType action, Event &event) { if (R2_GLOBALS._player._characterScene[R2_MIRANDA] == 500) scene->_stripId = 442; else if (!R2_GLOBALS.getFlag(44)) - scene->_stripId = 177 + R2_GLOBALS._randomSource.getRandomNumber(2); + scene->_stripId = 125 + R2_GLOBALS._randomSource.getRandomNumber(2); else if (!R2_GLOBALS.getFlag(55)) - scene->_stripId = 208; + scene->_stripId = 439; else - scene->_stripId = 441; - } else if (R2_GLOBALS._player._characterScene[R2_MIRANDA] == 500) { - scene->_stripId = 442; + scene->_stripId = 210; } else if (R2_GLOBALS.getFlag(44)) { - scene->_stripId = R2_GLOBALS.getFlag(55) ? 441 : 208; + scene->_stripId = R2_GLOBALS.getFlag(55) ? 439 : 210; } else { - scene->_stripId = 125 + R2_GLOBALS._randomSource.getRandomNumber(2); + scene->_stripId = 177 + R2_GLOBALS._randomSource.getRandomNumber(2); } scene->_stripManager.start3(scene->_stripId, scene, R2_GLOBALS._stripManager_lookupList); @@ -3277,7 +3284,7 @@ void Scene300::postInit(SceneObjectList *OwnerList) { _mirandaWorkstation1.setDetails(Rect(4, 128, 69, 167), 300, 33, 31, 35, 1, NULL); switch (R2_GLOBALS._player._characterIndex) { - case 1: + case R2_QUINN: _miranda.postInit(); _miranda.setup(302, 2, 1); _miranda.setPosition(Common::Point(47, 128)); @@ -3299,7 +3306,7 @@ void Scene300::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._player.disableControl(); break; - case 2: + case R2_SEEKER: _miranda.postInit(); _miranda.setup(302, 2, 1); _miranda.setPosition(Common::Point(47, 128)); @@ -3319,9 +3326,10 @@ void Scene300::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._player.setPosition(Common::Point(158, 108)); R2_GLOBALS._player.fixPriority(130); R2_GLOBALS._player.enableControl(CURSOR_USE); + R2_GLOBALS._player._canWalk = false; break; - case 3: + case R2_MIRANDA: if ((R2_GLOBALS._player._characterScene[R2_SEEKER] == 300) || (R2_GLOBALS._player._characterScene[R2_SEEKER] == 325)) { _seeker.postInit(); _seeker.setVisage(302); @@ -3343,6 +3351,7 @@ void Scene300::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._player.setup(302, 2, 1); R2_GLOBALS._player.setPosition(Common::Point(47, 128)); R2_GLOBALS._player.enableControl(CURSOR_USE); + R2_GLOBALS._player._canWalk = false; break; default: @@ -3513,7 +3522,7 @@ void Scene300::signal() { R2_GLOBALS.setFlag(40); break; case 5: - if (R2_GLOBALS._stripManager_lookupList[1] == 6) + if (R2_GLOBALS._stripManager_lookupList[0] == 6) R2_GLOBALS.setFlag(40); break; case 6: @@ -3685,6 +3694,8 @@ void Scene300::signal() { } void Scene300::signal309() { + // Sets up what conversation items will be available when to talking to the + // others on the Bridge, and will be set dependent on game flags if (R2_GLOBALS.getFlag(2)) R2_GLOBALS._stripManager_lookupList[0] = (R2_INVENTORY.getObjectScene(R2_READER) == 1) ? 3 : 2; @@ -3734,7 +3745,7 @@ const double ADJUST_FACTOR = 0.06419999999999999; Scene325::Icon::Icon(): SceneActor() { _lookLineNum = 0; - _field98 = 0; + _iconId = 0; _pressed = false; } @@ -3757,7 +3768,7 @@ void Scene325::Icon::postInit(SceneObjectList *OwnerList) { void Scene325::Icon::synchronize(Serializer &s) { SceneActor::synchronize(s); s.syncAsSint16LE(_lookLineNum); - s.syncAsSint16LE(_field98); + s.syncAsSint16LE(_iconId); s.syncAsSint16LE(_pressed); } @@ -3836,7 +3847,7 @@ void Scene325::Icon::process(Event &event) { void Scene325::Icon::setIcon(int id) { Scene325 *scene = (Scene325 *)R2_GLOBALS._sceneManager._scene; - _lookLineNum = _field98 = id; + _lookLineNum = _iconId = id; SceneActor::_lookLineNum = id; _sceneText1.remove(); @@ -3924,7 +3935,7 @@ void Scene325::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._player.hide(); R2_GLOBALS._player.disableControl(); - _item2.setDetails(1, 325, 3, 4, 5); + _terminal.setDetails(1, 325, 3, 4, 5); _background.setDetails(Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 325, 0, 1, 2, 1, (SceneItem *)NULL); _sceneMode = 1; signal(); @@ -4672,8 +4683,9 @@ bool Scene400::AttractorUnit::startAction(CursorType action, Event &event) { /*--------------------------------------------------------------------------*/ void Scene400::postInit(SceneObjectList *OwnerList) { - SceneExt::postInit(); loadScene(400); + SceneExt::postInit(); + _sound1.play(20); _door.postInit(); @@ -5002,6 +5014,39 @@ bool Scene500::AirLock::startAction(CursorType action, Event &event) { } } +void Scene500::TransparentDoor::draw() { + // Determine the area of the screen to be updated + Rect destRect = _bounds; + destRect.translate(-g_globals->_sceneManager._scene->_sceneBounds.left, + -g_globals->_sceneManager._scene->_sceneBounds.top); + + // Get the frame to be drawn + GfxSurface frame = getFrame(); + + Graphics::Surface s = frame.lockSurface(); + Graphics::Surface screen = g_globals->gfxManager().getSurface().lockSurface(); + + for (int yp = 0; yp < s.h; ++yp) { + byte *frameSrcP = (byte *)s.getBasePtr(0, yp); + byte *screenP = (byte *)screen.getBasePtr(destRect.left, destRect.top + yp); + + for (int xp = 0; xp < s.w; ++xp, ++frameSrcP, ++screenP) { + if (*frameSrcP != frame._transColor && *frameSrcP < 6) { + *frameSrcP = R2_GLOBALS._fadePaletteMap[*frameSrcP][*screenP]; + } + } + } + + // Finished updating the frame + frame.unlockSurface(); + g_globals->gfxManager().getSurface().unlockSurface(); + + // Draw the processed frame + Region *priorityRegion = g_globals->_sceneManager._scene->_priorities.find(_priority); + g_globals->gfxManager().copyFrom(frame, destRect, priorityRegion); + +} + bool Scene500::Aerosol::startAction(CursorType action, Event &event) { Scene500 *scene = (Scene500 *)R2_GLOBALS._sceneManager._scene; @@ -5162,38 +5207,40 @@ void Scene500::PanelDialog::Button::doButtonPress() { switch (_buttonId) { case 1: + // Rotate Left if (--R2_GLOBALS._landerSuitNumber == 0) - R2_GLOBALS._landerSuitNumber = 3; + R2_GLOBALS._landerSuitNumber = R2_MIRANDA; if (R2_GLOBALS.getFlag(35)) { scene->_sceneMode = 5; - scene->setAction(&scene->_sequenceManager1, scene, 509, &scene->_object1, - &scene->_suit, &scene->_object8, NULL); + scene->setAction(&scene->_sequenceManager1, scene, 509, &scene->_suits, + &scene->_suit, &scene->_transparentDoor, NULL); } else { scene->_sound1.play(127); - scene->_object1.animate(ANIM_MODE_6, scene); + scene->_suits.animate(ANIM_MODE_6, scene); } break; case 2: + // Rotate Right if (++R2_GLOBALS._landerSuitNumber == 4) - R2_GLOBALS._flubMazeArea = 1; + R2_GLOBALS._landerSuitNumber = R2_QUINN; if (R2_GLOBALS.getFlag(35)) { scene->_sceneMode = 6; - scene->setAction(&scene->_sequenceManager1, scene, 509, &scene->_object1, - &scene->_suit, &scene->_object8, NULL); + scene->setAction(&scene->_sequenceManager1, scene, 509, &scene->_suits, + &scene->_suit, &scene->_transparentDoor, NULL); } else { scene->_sound1.play(127); - scene->_object1.animate(ANIM_MODE_6, scene); + scene->_suits.animate(ANIM_MODE_6, scene); } break; case 3: if (R2_GLOBALS.getFlag(35)) { scene->_sceneMode = 509; - scene->setAction(&scene->_sequenceManager1, scene, 509, &scene->_object1, - &scene->_suit, &scene->_object8, NULL); + scene->setAction(&scene->_sequenceManager1, scene, 509, &scene->_suits, + &scene->_suit, &scene->_transparentDoor, NULL); } else { scene->_suit.postInit(); scene->_suit.hide(); @@ -5202,8 +5249,8 @@ void Scene500::PanelDialog::Button::doButtonPress() { scene->_suit.setup(502, R2_GLOBALS._landerSuitNumber + 2, 1); scene->setAction(&scene->_sequenceManager1, scene, 508, - &R2_GLOBALS._player, &scene->_object1, &scene->_suit, - &scene->_object8, NULL); + &R2_GLOBALS._player, &scene->_suits, &scene->_suit, + &scene->_transparentDoor, NULL); R2_GLOBALS.setFlag(35); } break; @@ -5217,10 +5264,9 @@ void Scene500::PanelDialog::Button::doButtonPress() { /*--------------------------------------------------------------------------*/ void Scene500::postInit(SceneObjectList *OwnerList) { - SceneExt::postInit(); loadScene(500); + SceneExt::postInit(); - Common::fill(&_buffer[0], &_buffer[2710], 0); _stripManager.setColors(60, 255); _stripManager.setFontNumber(50); _stripManager.addSpeaker(&_seekerSpeaker); @@ -5314,19 +5360,19 @@ void Scene500::postInit(SceneObjectList *OwnerList) { _sonicStunner.setDetails(500, 21, 22, 23, 1, (SceneItem *)NULL); } - _object1.postInit(); - _object1._effect = 1; - _object1.setup(502, 1, 1); - _object1.setPosition(Common::Point(258, 99)); - _object1.fixPriority(50); + _suits.postInit(); + _suits._effect = 1; + _suits.setup(502, 1, 1); + _suits.setPosition(Common::Point(258, 99)); + _suits.fixPriority(50); - _object8.postInit(); - _object8.setPosition(Common::Point(250, 111)); + _transparentDoor.postInit(); + _transparentDoor.setPosition(Common::Point(250, 111)); if (!R2_GLOBALS.getFlag(35)) { - _object8.setup(501, 3, 1); + _transparentDoor.setup(501, 3, 1); } else { - _object8.setup(500, 8, 7); + _transparentDoor.setup(500, 8, 7); _suit.postInit(); _suit._effect = 1; @@ -5348,7 +5394,7 @@ void Scene500::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._player._moveDiff.x = 5; _controlPanel.setDetails(Rect(175, 62, 191, 80), 500, 31, 32, 33, 1, (SceneItem *)NULL); - _item2.setDetails(Rect(13, 58, 70, 118), 500, 12, -1, -1, 1, (SceneItem *)NULL); + _airlockCorridor.setDetails(Rect(13, 58, 70, 118), 500, 12, -1, -1, 1, (SceneItem *)NULL); _background.setDetails(Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 500, 0, -1, -1, 1, (SceneItem *)NULL); if ((R2_GLOBALS._player._characterIndex == R2_QUINN) && (R2_GLOBALS._sceneManager._previousScene == 700)) { @@ -5380,7 +5426,7 @@ void Scene500::signal() { case 5: _sceneMode = 12; _sound1.play(127); - _object1.animate(ANIM_MODE_6, this); + _suits.animate(ANIM_MODE_6, this); R2_GLOBALS.clearFlag(35); _suit.remove(); @@ -5389,7 +5435,7 @@ void Scene500::signal() { case 6: _sceneMode = 11; _sound1.play(127); - _object1.animate(ANIM_MODE_5, this); + _suits.animate(ANIM_MODE_5, this); R2_GLOBALS.clearFlag(35); _suit.remove(); @@ -5397,7 +5443,7 @@ void Scene500::signal() { break; case 7: _sound1.play(126); - _object8.animate(ANIM_MODE_6, this); + _transparentDoor.animate(ANIM_MODE_6, this); R2_GLOBALS.clearFlag(35); _suit.remove(); @@ -5493,6 +5539,7 @@ void Scene500::signal() { * Scene 525 - Cutscene - Walking in hall * *--------------------------------------------------------------------------*/ + void Scene525::postInit(SceneObjectList *OwnerList) { loadScene(525); R2_GLOBALS._uiElements._active = false; @@ -5528,7 +5575,7 @@ bool Scene600::CompartmentHotspot::startAction(CursorType action, Event &event) return true; } -bool Scene600::Item4::startAction(CursorType action, Event &event) { +bool Scene600::EngineCompartment::startAction(CursorType action, Event &event) { if ((action != R2_NEGATOR_GUN) || (!R2_GLOBALS.getFlag(1))) return SceneHotspot::startAction(action, event); @@ -5550,13 +5597,19 @@ bool Scene600::Item4::startAction(CursorType action, Event &event) { R2_GLOBALS._player.disableControl(); Scene600 *scene = (Scene600 *)R2_GLOBALS._sceneManager._scene; - - scene->_object1.setup2(603, 3, 1, 239, 54, 10, 0); + + scene->_stasisArea.setup(603, 3, 1, 239, 54, 10); scene->_stasisField.postInit(); scene->_computer.postInit(); scene->_sceneMode = 612; scene->setAction(&scene->_sequenceManager1, scene, 612, &scene->_stasisField, &scene->_computer, &R2_GLOBALS._player, NULL); + + // WORKAROUND: For ScummVM, we use a SceneActor rather than BackgroundSceneObject + // for the stasis field since it doesn't work properly. We override the priority for + // the stasis field here so that the stasis field dissolve will show up + scene->_stasisField.fixPriority(12); + return true; } @@ -5610,7 +5663,7 @@ bool Scene600::Doorway::startAction(CursorType action, Event &event) { scene->_laser.setDetails(600, 11, -1, -1, 3, (SceneItem *) NULL); R2_GLOBALS.setFlag(6); scene->_sceneMode = 609; - scene->setAction(&scene->_sequenceManager1, scene, 609, &R2_GLOBALS._player, &scene->_doorway, &scene->_laser, &scene->_actor1, NULL); + scene->setAction(&scene->_sequenceManager1, scene, 609, &R2_GLOBALS._player, &scene->_doorway, &scene->_laser, &scene->_laserBeam, NULL); return true; } @@ -5701,7 +5754,7 @@ bool Scene600::Laser::startAction(CursorType action, Event &event) { } else { R2_GLOBALS._player.disableControl(); scene->_sceneMode = 610; - scene->setAction(&scene->_sequenceManager1, scene, 610, &scene->_actor1, &R2_GLOBALS._player, NULL); + scene->setAction(&scene->_sequenceManager1, scene, 610, &scene->_laserBeam, &R2_GLOBALS._player, NULL); return true; } } else @@ -5728,14 +5781,14 @@ bool Scene600::Aerosol::startAction(CursorType action, Event &event) { /*--------------------------------------------------------------------------*/ Scene600::Scene600() { - _field412 = 0; + _roomState = 0; Common::fill(&_pixelMap[0], &_pixelMap[256], 0); } void Scene600::synchronize(Serializer &s) { SceneExt::synchronize(s); - s.syncAsSint16LE(_field412); + s.syncAsSint16LE(_roomState); for (int i = 0; i < 256; i++) s.syncAsByte(_pixelMap[i]); } @@ -5763,7 +5816,7 @@ void Scene600::postInit(SceneObjectList *OwnerList) { SceneExt::postInit(); R2_GLOBALS.setFlag(39); R2_GLOBALS._walkRegions.disableRegion(3); - _field412 = 0; + _roomState = 0; // Initialize pixel map for the obscuring effect ScenePalette &pal = R2_GLOBALS._scenePalette; @@ -5814,14 +5867,14 @@ void Scene600::postInit(SceneObjectList *OwnerList) { _laser.setup(600, 2, 1); _laser.setDetails(600, 10, -1, -1, 1, (SceneItem *) NULL); - _actor1.postInit(); - _actor1.setup(600, 3, 5); - _actor1.setPosition(Common::Point(223, 51)); - _actor1.fixPriority(200); + _laserBeam.postInit(); + _laserBeam.setup(600, 3, 5); + _laserBeam.setPosition(Common::Point(223, 51)); + _laserBeam.fixPriority(200); } if (! R2_GLOBALS.getFlag(9)) - _object1.setup2(603, 1, 1, 244, 50, 10, 0); + _stasisArea.setup(603, 1, 1, 244, 50, 10); if (R2_GLOBALS.getFlag(5)) { if (R2_INVENTORY.getObjectScene(R2_AEROSOL) == 600) { @@ -5860,25 +5913,25 @@ void Scene600::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._player.animate(ANIM_MODE_1, NULL); R2_GLOBALS._player.disableControl(); - _item2.setDetails(12, 600, 17, -1, 19); - _item3.setDetails(11, 600, 14, -1, -1); + _quantumRegulator.setDetails(12, 600, 17, -1, 19); + _powerNode.setDetails(11, 600, 14, -1, -1); if (R2_GLOBALS.getFlag(9)) { - _background.setDetails(Rect(159, 3, 315, 95), 600, 7, -1, -1, 1, NULL); + _quantumDrive.setDetails(Rect(159, 3, 315, 95), 600, 7, -1, -1, 1, NULL); } else { - _item4.setDetails(Rect(173, 15, 315, 45), 600, 21, -1, 23, 1, NULL); - _background.setDetails(Rect(159, 3, 315, 95), 600, 6, -1, -1, 1, NULL); + _engineCompartment.setDetails(Rect(173, 15, 315, 45), 600, 21, -1, 23, 1, NULL); + _quantumDrive.setDetails(Rect(159, 3, 315, 95), 600, 6, -1, -1, 1, NULL); } - _item5.setDetails(Rect(0, 0, 320, 200), 600, 0, -1, -1, 1, NULL); + _background.setDetails(Rect(0, 0, 320, 200), 600, 0, -1, -1, 1, NULL); _sceneMode = 600; if (R2_GLOBALS._sceneManager._previousScene == 700) { if (R2_GLOBALS.getFlag(6)) { setAction(&_sequenceManager1, this, 600, &R2_GLOBALS._player, &_doorway, NULL); } else if (R2_GLOBALS.getFlag(5)) { - setAction(&_sequenceManager1, this, 603, &R2_GLOBALS._player, &_doorway, &_laser, &_actor1, NULL); + setAction(&_sequenceManager1, this, 603, &R2_GLOBALS._player, &_doorway, &_laser, &_laserBeam, NULL); } else { - setAction(&_sequenceManager1, this, 602, &R2_GLOBALS._player, &_doorway, &_laser, &_actor1, NULL); + setAction(&_sequenceManager1, this, 602, &R2_GLOBALS._player, &_doorway, &_laser, &_laserBeam, NULL); } } else if (R2_GLOBALS.getFlag(5)) { R2_GLOBALS._player.setPosition(Common::Point(50, 140)); @@ -5946,9 +5999,9 @@ void Scene600::signal() { // Deactivate stasis field R2_GLOBALS.setFlag(9); _stasisField.remove(); - R2_GLOBALS._sceneItems.remove(&_item4); - _computer.setDetails(600, 21, -1, 23, 4, &_item4); - _background.setDetails(600, 7, -1, -1, 3, (SceneItem *) NULL); + R2_GLOBALS._sceneItems.remove(&_engineCompartment); + _computer.setDetails(600, 21, -1, 23, 4, &_engineCompartment); + _engineCompartment.setDetails(600, 7, -1, -1, 3, (SceneItem *) NULL); R2_GLOBALS._player.enableControl(CURSOR_USE); break; case 614: @@ -5965,7 +6018,7 @@ void Scene600::signal() { R2_GLOBALS._player.enableControl(); break; default: - _field412 = 0; + _roomState = 0; _sceneMode = 0; R2_GLOBALS._player.enableControl(); break; @@ -5977,11 +6030,11 @@ void Scene600::process(Event &event) { && (R2_GLOBALS._events.getCursor() == CURSOR_WALK)) { if (!_doorway.contains(event.mousePos) || (_doorway._frame <= 1)) { if (R2_GLOBALS.getFlag(5)) { - _field412 += 10; + _roomState += 10; } else { R2_GLOBALS._player.disableControl(); _sceneMode = 604; - setAction(&_sequenceManager1, this, 604, &_actor1, &R2_GLOBALS._player, NULL); + setAction(&_sequenceManager1, this, 604, &_laserBeam, &R2_GLOBALS._player, NULL); event.handled = true; } } else { @@ -5990,36 +6043,36 @@ void Scene600::process(Event &event) { setAction(&_sequenceManager1, this, 613, &R2_GLOBALS._player, &_laser, NULL); event.handled = true; } - } else if ((!R2_GLOBALS.getFlag(6)) && (R2_GLOBALS._player._mover) && (_field412 < 10)){ - _field412 += 10; + } else if ((!R2_GLOBALS.getFlag(6)) && (R2_GLOBALS._player._mover) && (_roomState < 10)){ + _roomState += 10; } Scene::process(event); } void Scene600::dispatch() { - if ((_field412 != 0) && (_sceneMode != 600) && (_sceneMode != 603) && (_sceneMode != 602)) { + if ((_roomState != 0) && (_sceneMode != 600) && (_sceneMode != 603) && (_sceneMode != 602)) { if ( ((_laser._strip == 4) && (_laser._frame > 1)) || (_sceneMode == 601) || ((_sceneMode == 616) && (_doorway._frame > 1)) ) - _field412 = 0; + _roomState = 0; else { - _field412--; - if (_field412 % 10 == 0) { - _actor1.setAction(&_sequenceManager2, NULL, 611, &_actor1, NULL); + _roomState--; + if (_roomState % 10 == 0) { + _laserBeam.setAction(&_sequenceManager2, NULL, 611, &_laserBeam, NULL); } - if ((_field412 == 0) && (R2_GLOBALS._player._mover)) - _field412 = 10; + if ((_roomState == 0) && (R2_GLOBALS._player._mover)) + _roomState = 10; } } - if (_actor1._frame == 2) - _aSound1.play(40); + if (_laserBeam._frame == 2) + _sound1.play(40); Scene::dispatch(); if ((_smoke._strip == 3) && (_smoke._frame == 3)) { - _actor1.setStrip(4); - _actor1.setFrame(1); + _laserBeam.setStrip(4); + _laserBeam.setFrame(1); } } @@ -6027,6 +6080,7 @@ void Scene600::dispatch() { * Scene 700 - Lander Bay 2 * *--------------------------------------------------------------------------*/ + Scene700::Scene700() { _rotation = NULL; } @@ -6036,7 +6090,7 @@ void Scene700::synchronize(Serializer &s) { SYNC_POINTER(_rotation); } -bool Scene700::Item11::startAction(CursorType action, Event &event) { +bool Scene700::Loft::startAction(CursorType action, Event &event) { if ((action == CURSOR_USE) && (R2_GLOBALS._player._position.x < 100)) return false; @@ -6074,7 +6128,7 @@ bool Scene700::HandGrip::startAction(CursorType action, Event &event) { return true; } -bool Scene700::Actor2::startAction(CursorType action, Event &event) { +bool Scene700::LiftDoor::startAction(CursorType action, Event &event) { Scene700 *scene = (Scene700 *)R2_GLOBALS._sceneManager._scene; if (action != CURSOR_USE) @@ -6090,7 +6144,7 @@ bool Scene700::Actor2::startAction(CursorType action, Event &event) { return true; } -bool Scene700::Actor3::startAction(CursorType action, Event &event) { +bool Scene700::SuitRoomDoor::startAction(CursorType action, Event &event) { Scene700 *scene = (Scene700 *)R2_GLOBALS._sceneManager._scene; if (action != CURSOR_USE) @@ -6106,7 +6160,7 @@ bool Scene700::Actor3::startAction(CursorType action, Event &event) { return true; } -bool Scene700::Actor4::startAction(CursorType action, Event &event) { +bool Scene700::ControlPanel::startAction(CursorType action, Event &event) { Scene700 *scene = (Scene700 *)R2_GLOBALS._sceneManager._scene; if (action != CURSOR_USE) @@ -6174,7 +6228,7 @@ bool Scene700::Cable::startAction(CursorType action, Event &event) { return true; } -bool Scene700::Actor6::startAction(CursorType action, Event &event) { +bool Scene700::LoftDoor::startAction(CursorType action, Event &event) { Scene700 *scene = (Scene700 *)R2_GLOBALS._sceneManager._scene; if ((action != CURSOR_USE) || (R2_GLOBALS._player._position.y >= 100)) @@ -6201,43 +6255,43 @@ void Scene700::postInit(SceneObjectList *OwnerList) { _rotation->setDelay(5); _rotation->_countdown = 1; - _actor2.postInit(); - _actor2.setVisage(700); - _actor2.setPosition(Common::Point(21, 128)); - _actor2.fixPriority(10); - _actor2.setDetails(700, 3, -1, -1, 1, (SceneItem *) NULL); + _liftDoor.postInit(); + _liftDoor.setVisage(700); + _liftDoor.setPosition(Common::Point(21, 128)); + _liftDoor.fixPriority(10); + _liftDoor.setDetails(700, 3, -1, -1, 1, (SceneItem *) NULL); - _actor3.postInit(); - _actor3.setup(700, 2, 1); - _actor3.setPosition(Common::Point(217, 120)); - _actor3.fixPriority(10); - _actor3.setDetails(700, 15, -1, -1, 1, (SceneItem *) NULL); + _suitRoomDoor.postInit(); + _suitRoomDoor.setup(700, 2, 1); + _suitRoomDoor.setPosition(Common::Point(217, 120)); + _suitRoomDoor.fixPriority(10); + _suitRoomDoor.setDetails(700, 15, -1, -1, 1, (SceneItem *) NULL); - _actor1.postInit(); - _actor1.setup(700, 4, 1); - _actor1.setPosition(Common::Point(355 - ((R2_GLOBALS._electromagnetZoom * 8) / 5), ((R2_GLOBALS._electromagnetChangeAmount + 20 ) / 5) - 12)); - _actor1.fixPriority(10); - _actor1.setDetails(700, 12, -1, 14, 1, (SceneItem *) NULL); - - _actor6.postInit(); - _actor6.setup(700, 8, 1); - _actor6.setPosition(Common::Point(85, 53)); - _actor6.setDetails(700, 33, -1, 35, 1, (SceneItem *) NULL); - - _actor7.postInit(); - _actor7.setup(700, 8, 1); - _actor7.setPosition(Common::Point(164, 53)); - _actor7.setDetails(700, 33, -1, 35, 1, (SceneItem *) NULL); - - _actor8.postInit(); - _actor8.setup(700, 8, 1); - _actor8.setPosition(Common::Point(243, 53)); - _actor8.setDetails(700, 33, -1, 35, 1, (SceneItem *) NULL); - - _actor9.postInit(); - _actor9.setup(700, 8, 1); - _actor9.setPosition(Common::Point(324, 53)); - _actor9.setDetails(700, 33, -1, 35, 1, (SceneItem *) NULL); + _electromagnet.postInit(); + _electromagnet.setup(700, 4, 1); + _electromagnet.setPosition(Common::Point(355 - ((R2_GLOBALS._electromagnetZoom * 8) / 5), ((R2_GLOBALS._electromagnetChangeAmount + 20 ) / 5) - 12)); + _electromagnet.fixPriority(10); + _electromagnet.setDetails(700, 12, -1, 14, 1, (SceneItem *) NULL); + + _loftDoor1.postInit(); + _loftDoor1.setup(700, 8, 1); + _loftDoor1.setPosition(Common::Point(85, 53)); + _loftDoor1.setDetails(700, 33, -1, 35, 1, (SceneItem *) NULL); + + _loftDoor2.postInit(); + _loftDoor2.setup(700, 8, 1); + _loftDoor2.setPosition(Common::Point(164, 53)); + _loftDoor2.setDetails(700, 33, -1, 35, 1, (SceneItem *) NULL); + + _loftDoor3.postInit(); + _loftDoor3.setup(700, 8, 1); + _loftDoor3.setPosition(Common::Point(243, 53)); + _loftDoor3.setDetails(700, 33, -1, 35, 1, (SceneItem *) NULL); + + _loftDoor4.postInit(); + _loftDoor4.setup(700, 8, 1); + _loftDoor4.setPosition(Common::Point(324, 53)); + _loftDoor4.setDetails(700, 33, -1, 35, 1, (SceneItem *) NULL); if ((R2_INVENTORY.getObjectScene(R2_CABLE_HARNESS) != 1) && (R2_INVENTORY.getObjectScene(R2_ATTRACTOR_CABLE_HARNESS) != 1)) { _cable.postInit(); @@ -6276,7 +6330,7 @@ void Scene700::postInit(SceneObjectList *OwnerList) { _cable.setPosition(Common::Point(356 - (R2_GLOBALS._v565EB * 8), 148 - (((R2_GLOBALS._v565E9 + 10) / 5) * 4))); } else { _cable.setup(701, 1, 1); - _cable.setPosition(Common::Point(_actor1._position.x + 1, _actor1._position.y + 120)); + _cable.setPosition(Common::Point(_electromagnet._position.x + 1, _electromagnet._position.y + 120)); } _cable.setDetails(700, 38, -1, -1, 1, (SceneItem *) NULL); break; @@ -6288,23 +6342,23 @@ void Scene700::postInit(SceneObjectList *OwnerList) { } } - _actor4.postInit(); - _actor4.setup(700, 3, 1); - _actor4.setPosition(Common::Point(454, 117)); - _actor4.setDetails(700, 27, -1, -1, 1, (SceneItem *) NULL); + _controlPanel.postInit(); + _controlPanel.setup(700, 3, 1); + _controlPanel.setPosition(Common::Point(454, 117)); + _controlPanel.setDetails(700, 27, -1, -1, 1, (SceneItem *) NULL); _handGrip.setDetails(Rect(234, 90, 252, 110), 700, 39, -1, -1, 1, NULL); - _item6.setDetails(Rect(91, 158, 385, 167), 700, 6, -1, 8, 1, NULL); - _item2.setDetails(Rect(47, 115, 149, 124), 700, 40, -1, 41, 1, NULL); - _item3.setDetails(Rect(151, 108, 187, 124), 700, 40, -1, 41, 1, NULL); - _item4.setDetails(Rect(247, 108, 275, 124), 700, 40, -1, 41, 1, NULL); - _item5.setDetails(Rect(300, 105, 321, 124), 700, 40, -1, 41, 1, NULL); - _item7.setDetails(Rect(255, 74, 368, 115), 700, 9, -1, 11, 1, NULL); - _item8.setDetails(Rect(69, 74, 182, 115), 700, 9, -1, 11, 1, NULL); - _item9.setDetails(Rect(370, 58, 475, 103), 700, 18, -1, -1, 1, NULL); - _item10.setDetails(Rect(17, 11, 393, 31), 700, 24, -1, -1, 1, NULL); - _item11.setDetails(Rect(42, 32, 368, 66), 700, 30, -1, 32, 1, NULL); - _item1.setDetails(Rect(0, 0, 480, 200), 700, 0, -1, -1, 1, NULL); + _restraintCollar.setDetails(Rect(91, 158, 385, 167), 700, 6, -1, 8, 1, NULL); + _debris1.setDetails(Rect(47, 115, 149, 124), 700, 40, -1, 41, 1, NULL); + _debris2.setDetails(Rect(151, 108, 187, 124), 700, 40, -1, 41, 1, NULL); + _debris3.setDetails(Rect(247, 108, 275, 124), 700, 40, -1, 41, 1, NULL); + _debris4.setDetails(Rect(300, 105, 321, 124), 700, 40, -1, 41, 1, NULL); + _storage2.setDetails(Rect(255, 74, 368, 115), 700, 9, -1, 11, 1, NULL); + _storage1.setDetails(Rect(69, 74, 182, 115), 700, 9, -1, 11, 1, NULL); + _stars.setDetails(Rect(370, 58, 475, 103), 700, 18, -1, -1, 1, NULL); + _light.setDetails(Rect(17, 11, 393, 31), 700, 24, -1, -1, 1, NULL); + _loft.setDetails(Rect(42, 32, 368, 66), 700, 30, -1, 32, 1, NULL); + _background.setDetails(Rect(0, 0, 480, 200), 700, 0, -1, -1, 1, NULL); R2_GLOBALS._player.postInit(); R2_GLOBALS._player.setVisage(11); @@ -6318,14 +6372,14 @@ void Scene700::postInit(SceneObjectList *OwnerList) { switch (R2_GLOBALS._sceneManager._previousScene) { case 250: - setAction(&_sequenceManager, this, 700, &R2_GLOBALS._player, &_actor2, NULL); + setAction(&_sequenceManager, this, 700, &R2_GLOBALS._player, &_liftDoor, NULL); break; case 500: - setAction(&_sequenceManager, this, 703, &R2_GLOBALS._player, &_actor3, NULL); + setAction(&_sequenceManager, this, 703, &R2_GLOBALS._player, &_suitRoomDoor, NULL); break; case 600: { _sceneMode = 4; - _actor7.setFrame(5); + _loftDoor2.setFrame(5); R2_GLOBALS._player.setPosition(Common::Point(164, 74)); R2_GLOBALS._player.setStrip2(3); Common::Point pt(164, 69); @@ -6334,7 +6388,7 @@ void Scene700::postInit(SceneObjectList *OwnerList) { } break; case 900: - setAction(&_sequenceManager, this, 705, &R2_GLOBALS._player, &_actor4, NULL); + setAction(&_sequenceManager, this, 705, &R2_GLOBALS._player, &_controlPanel, NULL); break; default: if (R2_GLOBALS.getFlag(41)) @@ -6349,11 +6403,7 @@ void Scene700::postInit(SceneObjectList *OwnerList) { void Scene700::remove() { R2_GLOBALS._sound1.play(10); -// CHECKME: Present in the original... But it crashes badly. -// The instruction was removed as it's not used in other scene coded the same way -// and reversed by dreammaster. A double check is required in order to verify it doesn't hide -// a memory leak -// _rotation->remove(); + SceneExt::remove(); } @@ -6367,7 +6417,7 @@ void Scene700::signal() { R2_GLOBALS._player.enableControl(); } else { R2_GLOBALS._sound2.play(19); - _actor7.animate(ANIM_MODE_5, this); + _loftDoor2.animate(ANIM_MODE_5, this); } break; case 2: { @@ -6386,7 +6436,7 @@ void Scene700::signal() { R2_GLOBALS._player.setStrip2(-1); R2_GLOBALS._player.setObjectWrapper(new SceneObjectWrapper()); R2_GLOBALS._sound2.play(19); - _actor7.animate(ANIM_MODE_6, this); + _loftDoor2.animate(ANIM_MODE_6, this); R2_GLOBALS._player.setStrip(3); R2_GLOBALS.setFlag(41); break; @@ -6425,9 +6475,9 @@ void Scene700::signal() { _sceneMode = 17; _cable.setup(701, 1, 8); _cable.setDetails(700, 38, -1, -1, 3, (SceneItem *) NULL); - if ((R2_GLOBALS._v565E5 != 0) && (_cable._position.x == _actor1._position.x + 1) && (_cable._position.x == 148 - (((R2_GLOBALS._electromagnetChangeAmount + 10) / 5) * 4))) { + if ((R2_GLOBALS._v565E5 != 0) && (_cable._position.x == _electromagnet._position.x + 1) && (_cable._position.x == 148 - (((R2_GLOBALS._electromagnetChangeAmount + 10) / 5) * 4))) { _cable.animate(ANIM_MODE_6, NULL); - Common::Point pt(_cable._position.x, _actor1._position.y + 120); + Common::Point pt(_cable._position.x, _electromagnet._position.y + 120); NpcMover *mover = new NpcMover(); _cable.addMover(mover, &pt, NULL); R2_GLOBALS._v565E7 = 1; @@ -6903,18 +6953,19 @@ Scene825::Scene825(): SceneExt() { } void Scene825::postInit(SceneObjectList *OwnerList) { - SceneExt::postInit(); loadScene(825); - R2_GLOBALS._player._uiEnabled = false; + SceneExt::postInit(); BF_GLOBALS._interfaceY = 200; R2_GLOBALS._player.postInit(); + R2_GLOBALS._uiElements._active = false; R2_GLOBALS._player._effect = 0; R2_GLOBALS._player.setVisage(10); R2_GLOBALS._player.hide(); R2_GLOBALS._player.disableControl(); - _item2.setDetails(1, 825, 3, 4, 5); + + _console.setDetails(1, 825, 3, 4, 5); _background.setDetails(Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 825, 0, -1, -1, 1, NULL); _sceneMode = 10; @@ -6961,7 +7012,7 @@ void Scene825::signal() { R2_GLOBALS._player._canWalk = false; break; case 825: - _object5.remove(); + _vertLine5.remove(); _sceneText._color1 = 92; _sceneText._color2 = 0; _sceneText._width = 200; @@ -6979,7 +7030,7 @@ void Scene825::signal() { R2_GLOBALS._player._canWalk = false; break; case 827: - _object5.remove(); + _vertLine5.remove(); R2_INVENTORY.setObjectScene(R2_OPTO_DISK, 825); _sceneText.setPosition(Common::Point(108, 75)); _sceneText.setup(FOREIGN_OBJECT_EXTRACTED); @@ -7007,19 +7058,19 @@ void Scene825::process(Event &event) { } void Scene825::dispatch() { - if (R2_GLOBALS._sceneObjects->contains(&_object4) && - ((_object4._frame == 1) || (_object4._frame == 3)) && - (_object4._frame != _frame1)) { + if (R2_GLOBALS._sceneObjects->contains(&_vertLine4) && + ((_vertLine4._frame == 1) || (_vertLine4._frame == 3)) && + (_vertLine4._frame != _frame1)) { _sound2.play(25); } - if (R2_GLOBALS._sceneObjects->contains(&_object1) && - (_object1._frame == 3) && (_object1._frame != _frame2)) { + if (R2_GLOBALS._sceneObjects->contains(&_vertLine1) && + (_vertLine1._frame == 3) && (_vertLine1._frame != _frame2)) { _sound3.play(26); } - _frame1 = _object4._frame; - _frame2 = _object1._frame; + _frame1 = _vertLine4._frame; + _frame2 = _vertLine1._frame; Scene::dispatch(); } @@ -7036,9 +7087,9 @@ void Scene825::doButtonPress(int buttonId) { switch (buttonId) { case 2: R2_GLOBALS._player.disableControl(); - _object5.postInit(); + _vertLine5.postInit(); _sceneMode = 825; - setAction(&_sequenceManager1, this, 825, &R2_GLOBALS._player, &_object5, NULL); + setAction(&_sequenceManager1, this, 825, &R2_GLOBALS._player, &_vertLine5, NULL); break; case 3: R2_GLOBALS._player.disableControl(); @@ -7060,9 +7111,9 @@ void Scene825::doButtonPress(int buttonId) { } else { _button6._buttonId = 5; _sceneMode = 827; - _object5.postInit(); + _vertLine5.postInit(); - setAction(&_sequenceManager1, this, 827, &_object5, NULL); + setAction(&_sequenceManager1, this, 827, &_vertLine5, NULL); } } else { R2_GLOBALS.setFlag(2); @@ -7086,44 +7137,44 @@ void Scene825::doButtonPress(int buttonId) { _sound4.play(27); _button6._buttonId = 5; - _object1.postInit(); - _object1.setup(826, 7, 1); - _object1.setPosition(Common::Point(112, 67)); - _object1._numFrames = 1; - _object1.animate(ANIM_MODE_2); - - _object2.postInit(); - _object2.setup(826, 5, 1); - _object2.setPosition(Common::Point(158, 67)); - _object2._numFrames = 5; - _object2.animate(ANIM_MODE_2); - - _object3.postInit(); - _object3.setup(826, 6, 1); - _object3.setPosition(Common::Point(206, 67)); - _object3._numFrames = 1; - _object3.animate(ANIM_MODE_2); - - _object4.postInit(); - _object4.setup(826, 8, 1); - _object4.setPosition(Common::Point(158, 84)); - _object4._numFrames = 1; - _object4.animate(ANIM_MODE_2); - - _object5.postInit(); - _object5.setup(826, 4, 1); - _object5.setPosition(Common::Point(161, 110)); + _vertLine1.postInit(); + _vertLine1.setup(826, 7, 1); + _vertLine1.setPosition(Common::Point(112, 67)); + _vertLine1._numFrames = 1; + _vertLine1.animate(ANIM_MODE_2); + + _vertLine2.postInit(); + _vertLine2.setup(826, 5, 1); + _vertLine2.setPosition(Common::Point(158, 67)); + _vertLine2._numFrames = 5; + _vertLine2.animate(ANIM_MODE_2); + + _vertLine3.postInit(); + _vertLine3.setup(826, 6, 1); + _vertLine3.setPosition(Common::Point(206, 67)); + _vertLine3._numFrames = 1; + _vertLine3.animate(ANIM_MODE_2); + + _vertLine4.postInit(); + _vertLine4.setup(826, 8, 1); + _vertLine4.setPosition(Common::Point(158, 84)); + _vertLine4._numFrames = 1; + _vertLine4.animate(ANIM_MODE_2); + + _vertLine5.postInit(); + _vertLine5.setup(826, 4, 1); + _vertLine5.setPosition(Common::Point(161, 110)); break; case 5: R2_GLOBALS._player.disableControl(); if (_menuId == 4) { _menuId = 0; - _object1.remove(); - _object2.remove(); - _object3.remove(); - _object4.remove(); - _object5.remove(); + _vertLine1.remove(); + _vertLine2.remove(); + _vertLine3.remove(); + _vertLine4.remove(); + _vertLine5.remove(); _sound2.stop(); _sound3.stop(); @@ -7217,9 +7268,10 @@ bool Scene850::Clamp::startAction(CursorType action, Event &event) { return SceneActor::startAction(action, event); else { R2_GLOBALS._player.disableControl(); - scene->_object1.postInit(); + scene->_spark.postInit(); scene->_sceneMode = 850; - scene->setAction(&scene->_sequenceManager1, scene, 850, &R2_GLOBALS._player, this, &scene->_object1, NULL); + scene->setAction(&scene->_sequenceManager1, scene, 850, &R2_GLOBALS._player, this, + &scene->_spark, NULL); return true; } } @@ -7232,7 +7284,8 @@ bool Scene850::Panel::startAction(CursorType action, Event &event) { else { R2_GLOBALS._player.disableControl(); scene->_sceneMode = 852; - scene->setAction(&scene->_sequenceManager1, scene, 852, &R2_GLOBALS._player, this, &scene->_object1, NULL); + scene->setAction(&scene->_sequenceManager1, scene, 852, &R2_GLOBALS._player, + this, &scene->_spark, NULL); return true; } } @@ -7318,7 +7371,7 @@ void Scene850::signal() { case 850: R2_INVENTORY.setObjectScene(R2_CLAMP, 1); _clamp.remove(); - _object1.remove(); + _spark.remove(); R2_GLOBALS._player.enableControl(); break; case 851: @@ -7359,7 +7412,7 @@ void Scene900::Button::initButton(int buttonId) { } Scene900::Scene900() { - _field412 = 0; + _controlsScreenNumber = 0; _magnetChangeAmount.x = 0; _magnetChangeAmount.y = 0; } @@ -7367,7 +7420,7 @@ Scene900::Scene900() { void Scene900::synchronize(Serializer &s) { SceneExt::synchronize(s); - s.syncAsSint16LE(_field412); + s.syncAsSint16LE(_controlsScreenNumber); s.syncAsSint16LE(_magnetChangeAmount.x); s.syncAsSint16LE(_magnetChangeAmount.y); } @@ -7379,26 +7432,26 @@ bool Scene900::Button::startAction(CursorType action, Event &event) { R2_GLOBALS._sound2.play(14); switch (_buttonId) { case 2: - if (scene->_field412 == 1) { + if (scene->_controlsScreenNumber == 1) { scene->_sceneMode = 2; scene->signal(); - } else if (scene->_field412 == 2) { + } else if (scene->_controlsScreenNumber == 2) { if (R2_GLOBALS._v565E5 == 0) { scene->_aSound1.play(30); setup(900, 3, 11); R2_GLOBALS._v565E5 = 1; - if ((R2_INVENTORY.getObjectScene(R2_CABLE_HARNESS) == 0) && (R2_INVENTORY.getObjectScene(R2_ATTRACTOR_CABLE_HARNESS == 700)) && (R2_GLOBALS._electromagnetChangeAmount == 20) && (R2_GLOBALS._electromagnetZoom == 70) && (scene->_actor2._animateMode != ANIM_MODE_6)) { - scene->_actor2.animate(ANIM_MODE_6, NULL); + if ((R2_INVENTORY.getObjectScene(R2_CABLE_HARNESS) == 0) && (R2_INVENTORY.getObjectScene(R2_ATTRACTOR_CABLE_HARNESS == 700)) && (R2_GLOBALS._electromagnetChangeAmount == 20) && (R2_GLOBALS._electromagnetZoom == 70) && (scene->_cable._animateMode != ANIM_MODE_6)) { + scene->_cable.animate(ANIM_MODE_6, NULL); } else { - if (((scene->_electromagnet._percent * 49) / 100) + scene->_electromagnet._position.x == scene->_actor2._position.x) { - if (scene->_actor2._position.x == 166 - (R2_GLOBALS._electromagnetZoom / 15)) { + if (((scene->_electromagnet._percent * 49) / 100) + scene->_electromagnet._position.x == scene->_cable._position.x) { + if (scene->_cable._position.x == 166 - (R2_GLOBALS._electromagnetZoom / 15)) { R2_GLOBALS._player.disableControl(); scene->_sceneMode = 4; - scene->_actor2._moveDiff.y = (scene->_actor2._position.y - (scene->_electromagnet._position.y + ((scene->_electromagnet._percent * 3) / 10) - 2)) / 9; + scene->_cable._moveDiff.y = (scene->_cable._position.y - (scene->_electromagnet._position.y + ((scene->_electromagnet._percent * 3) / 10) - 2)) / 9; Common::Point pt(scene->_electromagnet._position.x + ((scene->_electromagnet._percent * 49) / 100), scene->_electromagnet._position.y + ((scene->_electromagnet._percent * 3) / 10) - 2); NpcMover *mover = new NpcMover(); - scene->_actor2.addMover(mover, &pt, this); - scene->_actor2.animate(ANIM_MODE_6, NULL); + scene->_cable.addMover(mover, &pt, this); + scene->_cable.animate(ANIM_MODE_6, NULL); } } } @@ -7407,18 +7460,18 @@ bool Scene900::Button::startAction(CursorType action, Event &event) { setup(900, 3, 9); R2_GLOBALS._v565E5 = 0; - if ((R2_INVENTORY.getObjectScene(R2_CABLE_HARNESS) == 0) && (R2_INVENTORY.getObjectScene(R2_ATTRACTOR_CABLE_HARNESS) == 700) && (scene->_actor2._frame < 8) && (scene->_actor2._animateMode != ANIM_MODE_5)) { - scene->_actor2.animate(ANIM_MODE_5, NULL); - } else if ((R2_INVENTORY.getObjectScene(R2_CABLE_HARNESS) == 700) && (R2_INVENTORY.getObjectScene(R2_ATTRACTOR_CABLE_HARNESS) == 700) && (scene->_actor2._frame < 8)) { + if ((R2_INVENTORY.getObjectScene(R2_CABLE_HARNESS) == 0) && (R2_INVENTORY.getObjectScene(R2_ATTRACTOR_CABLE_HARNESS) == 700) && (scene->_cable._frame < 8) && (scene->_cable._animateMode != ANIM_MODE_5)) { + scene->_cable.animate(ANIM_MODE_5, NULL); + } else if ((R2_INVENTORY.getObjectScene(R2_CABLE_HARNESS) == 700) && (R2_INVENTORY.getObjectScene(R2_ATTRACTOR_CABLE_HARNESS) == 700) && (scene->_cable._frame < 8)) { R2_GLOBALS._v565E7 = 0; - if (scene->_actor2._animateMode != 5) { + if (scene->_cable._animateMode != 5) { R2_GLOBALS._player.disableControl(); scene->_sceneMode = 5; - scene->_actor2.animate(ANIM_MODE_5, NULL); - scene->_actor2._moveDiff.y = (166 - scene->_actor2._position.y) / 9; - Common::Point pt(scene->_actor2._position.x, 166 - (R2_GLOBALS._electromagnetZoom / 15)); + scene->_cable.animate(ANIM_MODE_5, NULL); + scene->_cable._moveDiff.y = (166 - scene->_cable._position.y) / 9; + Common::Point pt(scene->_cable._position.x, 166 - (R2_GLOBALS._electromagnetZoom / 15)); NpcMover *mover = new NpcMover(); - scene->_actor2.addMover(mover, &pt, this); + scene->_cable.addMover(mover, &pt, this); } } } @@ -7426,7 +7479,7 @@ bool Scene900::Button::startAction(CursorType action, Event &event) { return true; break; case 3: - if (scene->_field412 == 1) { + if (scene->_controlsScreenNumber == 1) { scene->_sceneMode = 3; scene->signal(); } @@ -7469,7 +7522,7 @@ bool Scene900::Button::startAction(CursorType action, Event &event) { return true; break; default: - if (scene->_field412 == 1) { + if (scene->_controlsScreenNumber == 1) { R2_GLOBALS._player.disableControl(); scene->_button2.remove(); scene->_button3.remove(); @@ -7479,8 +7532,8 @@ bool Scene900::Button::startAction(CursorType action, Event &event) { scene->_button7.remove(); R2_GLOBALS._sound2.play(37); scene->_sceneMode = 901; - scene->setAction(&scene->_sequenceManager1, scene, 901, &scene->_actor1, this ,NULL); - } else if ((scene->_field412 == 2) || (scene->_field412 == 3)) { + scene->setAction(&scene->_sequenceManager1, scene, 901, &scene->_controls, this ,NULL); + } else if ((scene->_controlsScreenNumber == 2) || (scene->_controlsScreenNumber == 3)) { scene->_sceneMode = 1; scene->signal(); } @@ -7489,7 +7542,7 @@ bool Scene900::Button::startAction(CursorType action, Event &event) { break; } } else if (action == CURSOR_LOOK) { - SceneItem::display(900, ((_buttonId == 2) && (scene->_field412 == 2)) ? 21 : _buttonId + 11, + SceneItem::display(900, ((_buttonId == 2) && (scene->_controlsScreenNumber == 2)) ? 21 : _buttonId + 11, SET_WIDTH, 280, SET_X, 160, SET_POS_MODE, 1, SET_Y, 20, SET_EXT_BGCOLOR, 7, -999); return true; } else { @@ -7507,8 +7560,8 @@ void Scene900::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._player.hide(); R2_GLOBALS._player.disableControl(); - _actor1.postInit(); - _actor1.setDetails(900, 3, -1, -1, 1, (SceneItem *) NULL); + _controls.postInit(); + _controls.setDetails(900, 3, -1, -1, 1, (SceneItem *) NULL); _magnetChangeAmount.x = 0; _magnetChangeAmount.y = 0; @@ -7521,33 +7574,34 @@ void Scene900::postInit(SceneObjectList *OwnerList) { _electromagnet.setDetails(900, 6, -1, 8, 1, (SceneItem *) NULL); if ((R2_INVENTORY.getObjectScene(R2_CABLE_HARNESS) != 1) && (R2_INVENTORY.getObjectScene(R2_ATTRACTOR_CABLE_HARNESS) != 1)) { - _actor2.postInit(); - _actor2.setPosition(Common::Point(0, 0)); - _actor2.fixPriority(1); + _cable.postInit(); + _cable.setPosition(Common::Point(0, 0)); + _cable.fixPriority(1); if (R2_INVENTORY.getObjectScene(R2_CABLE_HARNESS) == 0) { if (R2_INVENTORY.getObjectScene(R2_ATTRACTOR_CABLE_HARNESS) != 700) { - _actor2.setup(901, 3, 2); + _cable.setup(901, 3, 2); } else if ((R2_GLOBALS._v565E5 != 0) && (R2_GLOBALS._electromagnetChangeAmount == 20) && (R2_GLOBALS._electromagnetZoom == 70)) { - _actor2.setup(901, 2, 1); + _cable.setup(901, 2, 1); } else { - _actor2.setup(901, 2, 8); + _cable.setup(901, 2, 8); } - _actor2.setPosition(Common::Point(171, 145)); - _actor2.setDetails(700, -1, -1, -1, 1, (SceneItem *) NULL); + _cable.setPosition(Common::Point(171, 145)); + _cable.setDetails(700, -1, -1, -1, 1, (SceneItem *) NULL); } else { - _actor2.setDetails(700, -1, -1, -1, 1, (SceneItem *) NULL); + _cable.setDetails(700, -1, -1, -1, 1, (SceneItem *) NULL); if (R2_GLOBALS._v565E7 == 0) { - _actor2.setup(901, 1, 8); + _cable.setup(901, 1, 8); // Original set two times the same values: skipped - _actor2.setPosition(Common::Point((((100 - ((R2_GLOBALS._v565EB * 350) / 100)) * 49) / 100) + ((R2_GLOBALS._v565E9 * _electromagnet._percent * 6) / 100) + 89, 166 - (R2_GLOBALS._v565EB / 3))); - _actor2.changeZoom(((100 - ((R2_GLOBALS._v565EB * 350) / 100) + 52) / 10) * 10); + _cable.setPosition(Common::Point((((100 - ((R2_GLOBALS._v565EB * 350) / 100)) * 49) / 100) + ((R2_GLOBALS._v565E9 * _electromagnet._percent * 6) / 100) + 89, 166 - (R2_GLOBALS._v565EB / 3))); + _cable.changeZoom(((100 - ((R2_GLOBALS._v565EB * 350) / 100) + 52) / 10) * 10); } } } - _item1.setDetails(Rect(0, 0, 320, 200), 900, 0, -1, -1, 1, NULL); + + _background.setDetails(Rect(0, 0, 320, 200), 900, 0, -1, -1, 1, NULL); _sceneMode = 900; - setAction(&_sequenceManager1, this, 900, &_actor1, NULL); + setAction(&_sequenceManager1, this, 900, &_controls, NULL); } void Scene900::remove() { @@ -7560,7 +7614,7 @@ void Scene900::remove() { void Scene900::signal() { switch (_sceneMode) { case 1: - _field412 = 1; + _controlsScreenNumber = 1; R2_GLOBALS._sound2.play(37); _button2.remove(); @@ -7579,7 +7633,7 @@ void Scene900::signal() { _button3.setPosition(Common::Point(117, 166)); break; case 2: - _field412 = 2; + _controlsScreenNumber = 2; _button2.remove(); _button3.remove(); @@ -7609,7 +7663,7 @@ void Scene900::signal() { break; case 3: - _field412 = 3; + _controlsScreenNumber = 3; _button2.remove(); _button3.remove(); @@ -7636,7 +7690,7 @@ void Scene900::signal() { R2_GLOBALS._player.enableControl(CURSOR_USE); R2_GLOBALS._player._canWalk = false; - _actor1.setup(900, 1, 1); + _controls.setup(900, 1, 1); _button1.initButton(1); _button1.setup(900, 1, 3); @@ -7679,27 +7733,27 @@ void Scene900::dispatch() { } } - if (R2_GLOBALS._sceneObjects->contains(&_actor2)) { + if (R2_GLOBALS._sceneObjects->contains(&_cable)) { if ((R2_GLOBALS._v565E5 != 0) && (R2_INVENTORY.getObjectScene(R2_CABLE_HARNESS) == 0) && (R2_INVENTORY.getObjectScene(R2_ATTRACTOR_CABLE_HARNESS) == 700) && (R2_GLOBALS._electromagnetChangeAmount == 20) && (R2_GLOBALS._electromagnetZoom == 70)) { - if ((_actor2._frame > 1) && (_actor2._animateMode != ANIM_MODE_6)) - _actor2.animate(ANIM_MODE_6, NULL); + if ((_cable._frame > 1) && (_cable._animateMode != ANIM_MODE_6)) + _cable.animate(ANIM_MODE_6, NULL); } else { - if ((_actor2._frame < 8) && (_actor2._animateMode != ANIM_MODE_5) && (R2_GLOBALS._v565E7 == 0) && (R2_INVENTORY.getObjectScene(R2_CABLE_HARNESS) == 0) && (R2_INVENTORY.getObjectScene(R2_ATTRACTOR_CABLE_HARNESS) == 700) && (_sceneMode != 4)) - _actor2.animate(ANIM_MODE_5, NULL); + if ((_cable._frame < 8) && (_cable._animateMode != ANIM_MODE_5) && (R2_GLOBALS._v565E7 == 0) && (R2_INVENTORY.getObjectScene(R2_CABLE_HARNESS) == 0) && (R2_INVENTORY.getObjectScene(R2_ATTRACTOR_CABLE_HARNESS) == 700) && (_sceneMode != 4)) + _cable.animate(ANIM_MODE_5, NULL); } } _electromagnet.changeZoom(100 - ((R2_GLOBALS._electromagnetZoom * 70) / 100)); _electromagnet.setPosition(Common::Point(((_electromagnet._percent * R2_GLOBALS._electromagnetChangeAmount * 6) / 100) + 89, R2_GLOBALS._electromagnetZoom)); - if ((R2_GLOBALS._sceneObjects->contains(&_actor2)) && (R2_GLOBALS._v565E7 != 0) && (!_actor2._mover) && (_actor2._animateMode == ANIM_MODE_NONE)) { - _actor2.setPosition(Common::Point(_electromagnet._position.x + ((_electromagnet._percent * 49) / 100), _electromagnet._position.y + ((_electromagnet._percent * 3) / 10))); + if ((R2_GLOBALS._sceneObjects->contains(&_cable)) && (R2_GLOBALS._v565E7 != 0) && (!_cable._mover) && (_cable._animateMode == ANIM_MODE_NONE)) { + _cable.setPosition(Common::Point(_electromagnet._position.x + ((_electromagnet._percent * 49) / 100), _electromagnet._position.y + ((_electromagnet._percent * 3) / 10))); if (R2_GLOBALS._electromagnetZoom >= 75) { - _actor2.setup(901, 1, 1); - _actor2.changeZoom(((_electromagnet._percent + 52) / 10) * 10); + _cable.setup(901, 1, 1); + _cable.changeZoom(((_electromagnet._percent + 52) / 10) * 10); } else { - _actor2.setup(901, 5, 1); - _actor2.changeZoom(((_electromagnet._percent / 10) * 10) + 30); + _cable.setup(901, 5, 1); + _cable.changeZoom(((_electromagnet._percent / 10) * 10) + 30); } } Scene::dispatch(); diff --git a/engines/tsage/ringworld2/ringworld2_scenes0.h b/engines/tsage/ringworld2/ringworld2_scenes0.h index b735f7cc23..fe42f1e33e 100644 --- a/engines/tsage/ringworld2/ringworld2_scenes0.h +++ b/engines/tsage/ringworld2/ringworld2_scenes0.h @@ -109,7 +109,7 @@ class Scene125: public SceneExt { class Icon: public SceneActor { public: - int _lookLineNum, _field98; + int _lookLineNum, _iconId; bool _pressed; SceneObject _object1, _object2; SceneText _sceneText1, _sceneText2; @@ -319,8 +319,8 @@ class Scene250: public SceneExt { public: int _currButtonY, _destButtonY, _elevatorSpeed; bool _skippingFl, _skippableFl; - NamedHotspot _background, _item2, _item3, _item4; - Button _button1, _currentFloor; + NamedHotspot _background, _door, _directionIndicator; + Button _destinationFloor, _currentFloor; Button _floor1, _floor2, _floor3, _floor4, _floor5; Button _floor6, _floor7, _floor8, _floor9; ASoundExt _sound1; @@ -428,7 +428,7 @@ public: class Scene325: public SceneExt { class Icon: public SceneActor { public: - int _lookLineNum, _field98; + int _lookLineNum, _iconId; bool _pressed; SceneObject _object1, _object2; SceneText _sceneText1, _sceneText2; @@ -456,7 +456,7 @@ public: int _soundQueue[10]; SpeakerQuinn _quinnSpeaker; ScenePalette _palette; - SceneHotspot _background, _item2; + SceneHotspot _background, _terminal; SceneObject _object1, _object2, _object3, _object4, _object5; SceneObject _object6, _object7, _object8, _object9, _object10; SceneObject _object11, _object12, _scannerTab; @@ -575,8 +575,9 @@ class Scene500: public SceneExt { public: virtual bool startAction(CursorType action, Event &event); }; - class Object8: public SceneActor { - // This classes uses a custom draw method + class TransparentDoor: public SceneActor { + public: + virtual void draw(); }; class Aerosol: public SceneActor { public: @@ -596,18 +597,17 @@ class Scene500: public SceneExt { }; public: int _stripNumber; - byte _buffer[2710]; SpeakerSeeker500 _seekerSpeaker; SpeakerQuinn500 _quinnSpeaker; - SceneHotspot _background, _item2; + SceneHotspot _background, _airlockCorridor; ControlPanel _controlPanel; - SceneActor _object1; + SceneActor _suits; Seeker _seeker; Suit _suit; Doorway _doorway; OxygenTanks _tanks1, _tanks2; AirLock _airLock; - Object8 _object8; + TransparentDoor _transparentDoor; Aerosol _aerosol; SonicStunner _sonicStunner; Locker1 _locker1; @@ -636,7 +636,7 @@ class Scene600 : public SceneExt { public: virtual bool startAction(CursorType action, Event &event); }; - class Item4 : public NamedHotspot { + class EngineCompartment : public NamedHotspot { public: virtual bool startAction(CursorType action, Event &event); }; @@ -664,14 +664,14 @@ class Scene600 : public SceneExt { virtual bool startAction(CursorType action, Event &event); }; public: - int _field412; + int _roomState; + CompartmentHotspot _quantumDrive; + CompartmentHotspot _quantumRegulator; + CompartmentHotspot _powerNode; + EngineCompartment _engineCompartment; CompartmentHotspot _background; - CompartmentHotspot _item2; - CompartmentHotspot _item3; - Item4 _item4; - CompartmentHotspot _item5; - BackgroundSceneObject _object1; - SceneActor _actor1; + SceneActor _stasisArea; + SceneActor _laserBeam; SceneActor _computer; SceneActor _stasisField; Smoke _smoke; @@ -679,7 +679,7 @@ public: Laser _laser; Aerosol _aerosol; Scanner _scanner; - ASoundExt _aSound1; + ASoundExt _sound1; SequenceManager _sequenceManager1; SequenceManager _sequenceManager2; byte _pixelMap[256]; @@ -694,7 +694,7 @@ public: }; class Scene700: public SceneExt { - class Item11 : public NamedHotspot { + class Loft : public NamedHotspot { public: virtual bool startAction(CursorType action, Event &event); }; @@ -703,15 +703,15 @@ class Scene700: public SceneExt { virtual bool startAction(CursorType action, Event &event); }; - class Actor2 : public SceneActor { + class LiftDoor : public SceneActor { public: virtual bool startAction(CursorType action, Event &event); }; - class Actor3 : public SceneActor { + class SuitRoomDoor : public SceneActor { public: virtual bool startAction(CursorType action, Event &event); }; - class Actor4 : public SceneActor { + class ControlPanel : public SceneActor { public: virtual bool startAction(CursorType action, Event &event); }; @@ -719,35 +719,34 @@ class Scene700: public SceneExt { public: virtual bool startAction(CursorType action, Event &event); }; - class Actor6 : public SceneActor { + class LoftDoor : public SceneActor { public: virtual bool startAction(CursorType action, Event &event); }; public: - NamedHotspot _item1; - NamedHotspot _item2; - NamedHotspot _item3; - NamedHotspot _item4; - NamedHotspot _item5; - NamedHotspot _item6; - NamedHotspot _item7; - NamedHotspot _item8; - NamedHotspot _item9; - NamedHotspot _item10; - Item11 _item11; + NamedHotspot _background; + NamedHotspot _debris1; + NamedHotspot _debris2; + NamedHotspot _debris3; + NamedHotspot _debris4; + NamedHotspot _restraintCollar; + NamedHotspot _storage2; + NamedHotspot _storage1; + NamedHotspot _stars; + NamedHotspot _light; + Loft _loft; HandGrip _handGrip; - SceneActor _actor1; - Actor2 _actor2; - Actor3 _actor3; - Actor4 _actor4; + SceneActor _electromagnet; + LiftDoor _liftDoor; + SuitRoomDoor _suitRoomDoor; + ControlPanel _controlPanel; Cable _cable; - Actor6 _actor6; - Actor6 _actor7; - Actor6 _actor8; - Actor6 _actor9; + LoftDoor _loftDoor1; + LoftDoor _loftDoor2; + LoftDoor _loftDoor3; + LoftDoor _loftDoor4; SequenceManager _sequenceManager; PaletteRotation *_rotation; - int _field100E; Scene700(); virtual void postInit(SceneObjectList *OwnerList = NULL); @@ -822,8 +821,8 @@ class Scene825: public SceneExt { virtual bool startAction(CursorType action, Event &event); }; public: - NamedHotspot _background, _item2; - SceneActor _object1, _object2, _object3, _object4, _object5; + NamedHotspot _background, _console; + SceneActor _vertLine1, _vertLine2, _vertLine3, _vertLine4, _vertLine5; Button _button1, _button2, _button3, _button4, _button5, _button6; ASoundExt _sound1, _sound2, _sound3, _sound4; SequenceManager _sequenceManager1; @@ -870,7 +869,7 @@ public: NamedHotspot _background, _eastDoor, _compartment, _sickBayIndicator; NamedHotspot _liftControls; Indicator _indicator; - SceneActor _object1, _fibre; + SceneActor _spark, _fibre; LiftDoor _liftDoor; SickBayDoor _sickBayDoor; Clamp _clamp; @@ -892,11 +891,11 @@ class Scene900 : public SceneExt { virtual bool startAction(CursorType action, Event &event); }; public: - int _field412; + int _controlsScreenNumber; Common::Point _magnetChangeAmount; - NamedHotspot _item1; - SceneActor _actor1; - SceneActor _actor2; + NamedHotspot _background; + SceneActor _controls; + SceneActor _cable; SceneActor _electromagnet; Button _button1; Button _button2; diff --git a/engines/tsage/ringworld2/ringworld2_scenes1.cpp b/engines/tsage/ringworld2/ringworld2_scenes1.cpp index 29bef2ccb2..0932c70f04 100644 --- a/engines/tsage/ringworld2/ringworld2_scenes1.cpp +++ b/engines/tsage/ringworld2/ringworld2_scenes1.cpp @@ -478,10 +478,11 @@ void Scene1000::dispatch() { *--------------------------------------------------------------------------*/ void Scene1010::postInit(SceneObjectList *OwnerList) { - SceneExt::postInit(); loadScene(1010); - + SceneExt::postInit(); + R2_GLOBALS._interfaceY = 200; R2_GLOBALS._uiElements._active = false; + setZoomPercents(100, 1, 160, 100); R2_GLOBALS._player.postInit(); R2_GLOBALS._player.setObjectWrapper(NULL); @@ -533,16 +534,18 @@ void Scene1010::signal() { } /*-------------------------------------------------------------------------- - * Scene 1020 - + * Scene 1020 - Cutscene - trip in space 2 * *--------------------------------------------------------------------------*/ + void Scene1020::postInit(SceneObjectList *OwnerList) { - SceneExt::postInit(); loadScene(1020); + SceneExt::postInit(); if (R2_GLOBALS._sceneManager._previousScene == 1010) - g_globals->gfxManager()._bounds.moveTo(Common::Point(160, 0)); + _sceneBounds = Rect(160, 0, SCREEN_WIDTH + 160, 200); + R2_GLOBALS._interfaceY = 200; R2_GLOBALS._v558B6.set(160, 0, 160, 161); R2_GLOBALS._uiElements._active = false; R2_GLOBALS._player.postInit(); @@ -658,9 +661,10 @@ void Scene1020::dispatch() { } /*-------------------------------------------------------------------------- - * Scene 1100 - + * Scene 1100 - Canyon * *--------------------------------------------------------------------------*/ + Scene1100::Scene1100() { _nextStripNum = 0; _paletteRefreshStatus = 0; @@ -801,16 +805,16 @@ void Scene1100::postInit(SceneObjectList *OwnerList) { scalePalette(65, 65, 65); - _actor2.postInit(); - _actor2.setup(1100, 1, 1); - _actor2.fixPriority(10); + _cloud.postInit(); + _cloud.setup(1100, 1, 1); + _cloud.fixPriority(10); R2_GLOBALS._scrollFollower = NULL; - _item3.setDetails(Rect(56, 47, 68, 83), 1100, 7, -1, -1, 1, NULL); - _item4.setDetails(Rect(167, 132, 183, 167), 1100, 7, -1, -1, 1, NULL); - _item5.setDetails(Rect(26, 112, 87, 145), 1100, 13, -1, -1, 1, NULL); - _item7.setDetails(Rect(4, 70, 79, 167), 1100, 16, -1, -1, 1, NULL); + _fuana1.setDetails(Rect(56, 47, 68, 83), 1100, 7, -1, -1, 1, NULL); + _fauna2.setDetails(Rect(167, 132, 183, 167), 1100, 7, -1, -1, 1, NULL); + _bouldersBlockingCave.setDetails(Rect(26, 112, 87, 145), 1100, 13, -1, -1, 1, NULL); + _trail.setDetails(Rect(4, 70, 79, 167), 1100, 16, -1, -1, 1, NULL); R2_GLOBALS._sound1.stop(); @@ -819,7 +823,7 @@ void Scene1100::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._player._characterIndex = R2_QUINN; R2_GLOBALS._player._characterScene[R2_QUINN] = 1100; R2_GLOBALS._player._characterScene[R2_SEEKER] = 1100; - _actor2.setPosition(Common::Point(150, 30)); + _cloud.setPosition(Common::Point(150, 30)); R2_GLOBALS._sound1.play(93); R2_GLOBALS._player.postInit(); R2_GLOBALS._player.hide(); @@ -848,18 +852,18 @@ void Scene1100::postInit(SceneObjectList *OwnerList) { _trooper._numFrames = 5; _trooper.setDetails(1100, 22, 23, 24, 1, (SceneItem *) NULL); - _actor1.postInit(); - _actor1.setup(1512, 1, 1); - _actor1.setPosition(Common::Point(187, -25)); - _actor1.fixPriority(48); - _actor1._moveDiff.y = 1; - _actor1.setDetails(1100, 37, -1, -1, 1, (SceneItem *) NULL); + _ship.postInit(); + _ship.setup(1512, 1, 1); + _ship.setPosition(Common::Point(187, -25)); + _ship.fixPriority(48); + _ship._moveDiff.y = 1; + _ship.setDetails(1100, 37, -1, -1, 1, (SceneItem *) NULL); _sceneMode = 20; setAction(&_sequenceManager1, this, 1, &R2_GLOBALS._player, NULL); } else if (R2_GLOBALS._sceneManager._previousScene == 1000) { - _actor2.setPosition(Common::Point(50, 30)); + _cloud.setPosition(Common::Point(50, 30)); _paletteRefreshStatus = 0; _palette1.loadPalette(1101); R2_GLOBALS._player.postInit(); @@ -899,7 +903,7 @@ void Scene1100::postInit(SceneObjectList *OwnerList) { setAction(&_sequenceManager1, this, 1, &R2_GLOBALS._player, NULL); } else { - _actor2.setPosition(Common::Point(180, 30)); + _cloud.setPosition(Common::Point(180, 30)); if (R2_GLOBALS.getFlag(52)) R2_GLOBALS._sound1.play(98); else @@ -969,16 +973,17 @@ void Scene1100::postInit(SceneObjectList *OwnerList) { _trooper.fixPriority(200); } - _actor1.postInit(); - _actor1.setup(1512, 1, 1); - _actor1.setPosition(Common::Point(187, 45)); - _actor1.fixPriority(48); - _actor1._moveDiff.y = 1; - _actor1.setDetails(1100, 37, -1, -1, 1, (SceneItem *) NULL); + _ship.postInit(); + _ship.setup(1512, 1, 1); + _ship.setPosition(Common::Point(187, 45)); + _ship.fixPriority(48); + _ship._moveDiff.y = 1; + _ship.setDetails(1100, 37, -1, -1, 1, (SceneItem *) NULL); } - _item6.setDetails(Rect(123, 69, 222, 105), 1100, 13, -1, -1, 1, NULL); - _item2.setDetails(Rect(0, 0, 480, 46), 1100, 0, -1, -1, 1, NULL); - _item1.setDetails(Rect(0, 0, 480, 200), 1100, 40, 41, 42, 1, NULL); + + _boulders.setDetails(Rect(123, 69, 222, 105), 1100, 13, -1, -1, 1, NULL); + _sky.setDetails(Rect(0, 0, 480, 46), 1100, 0, -1, -1, 1, NULL); + _background.setDetails(Rect(0, 0, 480, 200), 1100, 40, 41, 42, 1, NULL); } void Scene1100::remove() { @@ -1112,7 +1117,7 @@ void Scene1100::signal() { case 20: { Common::Point pt(187, -13); NpcMover *mover = new NpcMover(); - _actor1.addMover(mover, &pt, this); + _ship.addMover(mover, &pt, this); } break; case 21: { @@ -1120,7 +1125,7 @@ void Scene1100::signal() { _trooper.animate(ANIM_MODE_5, NULL); Common::Point pt(187, 45); NpcMover *mover = new NpcMover(); - _actor1.addMover(mover, &pt, this); + _ship.addMover(mover, &pt, this); } break; case 22: @@ -1259,7 +1264,7 @@ void Scene1100::signal() { R2_GLOBALS._sound1.play(101); Common::Point pt(187, -13); NpcMover *mover = new NpcMover(); - _actor1.addMover(mover, &pt, this); + _ship.addMover(mover, &pt, this); } break; default: @@ -1270,6 +1275,15 @@ void Scene1100::signal() { } void Scene1100::dispatch() { + // WORKAROUND: This fixes a problem with an overhang that gets blasted re-appearing + if (_animation._frame > 5 && _sceneMode == 13) { + _animation._endFrame = 9; + if (_animation._frame == 9) + // Use one of the scene's background scene objects to copy the scene to the background. + // This fixes the problem with the cliff overhang still appearing during the cutscene + _rightLandslide.copySceneToBackground(); + } + if ((g_globals->_sceneObjects->contains(&_laserShot)) && (_laserShot._visage == 1102) && (_laserShot._strip == 4) && (_laserShot._frame == 1) && (_laserShot._flags & OBJFLAG_HIDING)) { if (_paletteRefreshStatus == 1) { _paletteRefreshStatus = 2; @@ -6872,6 +6886,7 @@ void Scene1337::subD1A48(int arg1) { * Scene 1500 - Cutscene: Ship landing * *--------------------------------------------------------------------------*/ + void Scene1500::postInit(SceneObjectList *OwnerList) { loadScene(1500); R2_GLOBALS._uiElements._active = false; @@ -7030,6 +7045,7 @@ void Scene1500::dispatch() { * Scene 1525 - Cutscene - Ship * *--------------------------------------------------------------------------*/ + void Scene1525::postInit(SceneObjectList *OwnerList) { loadScene(1525); R2_GLOBALS._uiElements._active = false; @@ -7072,6 +7088,7 @@ void Scene1525::signal() { * Scene 1530 - Cutscene - Elevator * *--------------------------------------------------------------------------*/ + void Scene1530::postInit(SceneObjectList *OwnerList) { if (R2_GLOBALS._sceneManager._previousScene == 1000) loadScene(1650); @@ -9275,6 +9292,7 @@ void Scene1550::enterArea() { * Scene 1575 - * *--------------------------------------------------------------------------*/ + Scene1575::Scene1575() { _field412 = 0; _field414 = 0; @@ -9655,6 +9673,7 @@ void Scene1575::dispatch() { * Scene 1580 - Inside wreck * *--------------------------------------------------------------------------*/ + Scene1580::Scene1580() { _field412 = 0; } diff --git a/engines/tsage/ringworld2/ringworld2_scenes1.h b/engines/tsage/ringworld2/ringworld2_scenes1.h index 824df607b3..c0088236b4 100644 --- a/engines/tsage/ringworld2/ringworld2_scenes1.h +++ b/engines/tsage/ringworld2/ringworld2_scenes1.h @@ -94,15 +94,15 @@ public: SpeakerQuinn1100 _quinnSpeaker; SpeakerChief1100 _chiefSpeaker; ScenePalette _palette1; - NamedHotspot _item1; - NamedHotspot _item2; - NamedHotspot _item3; - NamedHotspot _item4; - NamedHotspot _item5; - NamedHotspot _item6; - NamedHotspot _item7; - SceneActor _actor1; - SceneActor _actor2; + NamedHotspot _background; + NamedHotspot _sky; + NamedHotspot _fuana1; + NamedHotspot _fauna2; + NamedHotspot _bouldersBlockingCave; + NamedHotspot _boulders; + NamedHotspot _trail; + SceneActor _ship; + SceneActor _cloud; SceneActor _shipFormation; SceneActor _shipFormationShadow; SceneActor _shotImpact1; @@ -111,7 +111,7 @@ public: SceneActor _shotImpact4; SceneActor _shotImpact5; SceneActor _laserShot; - SceneActor _animation; + SceneActor _animation; // Used for cliff collapse and ship theft SceneActor _leftImpacts; SceneActor _runningGuy1; SceneActor _runningGuy2; diff --git a/engines/tsage/ringworld2/ringworld2_scenes2.cpp b/engines/tsage/ringworld2/ringworld2_scenes2.cpp index a8e534d5cb..510855b162 100644 --- a/engines/tsage/ringworld2/ringworld2_scenes2.cpp +++ b/engines/tsage/ringworld2/ringworld2_scenes2.cpp @@ -1038,6 +1038,7 @@ void Scene2000::synchronize(Serializer &s) { * Scene 2350 - Balloon Launch Platform * *--------------------------------------------------------------------------*/ + bool Scene2350::Actor2::startAction(CursorType action, Event &event) { if (action != R2_SENSOR_PROBE) return(SceneActor::startAction(action, event)); @@ -1215,6 +1216,7 @@ void Scene2350::process(Event &event) { * Scene 2400 - Spill Mountains: Large empty room * *--------------------------------------------------------------------------*/ + void Scene2400::Exit1::changeScene() { Scene2400 *scene = (Scene2400 *)R2_GLOBALS._sceneManager._scene; @@ -1905,6 +1907,7 @@ void Scene2440::signal() { * Scene 2445 - Spill Mountains: * *--------------------------------------------------------------------------*/ + void Scene2445::postInit(SceneObjectList *OwnerList) { loadScene(2445); SceneExt::postInit(); @@ -2980,6 +2983,7 @@ void Scene2535::signal() { * Scene 2600 - Spill Mountains: Exit * *--------------------------------------------------------------------------*/ + Scene2600::Scene2600(): SceneExt() { _rotation = NULL; } diff --git a/engines/tsage/ringworld2/ringworld2_scenes3.cpp b/engines/tsage/ringworld2/ringworld2_scenes3.cpp index c64665a839..5cca1ee483 100644 --- a/engines/tsage/ringworld2/ringworld2_scenes3.cpp +++ b/engines/tsage/ringworld2/ringworld2_scenes3.cpp @@ -934,6 +934,7 @@ void Scene3175::signal() { * Scene 3200 - Cutscene : Guards - Discussion * *--------------------------------------------------------------------------*/ + void Scene3200::postInit(SceneObjectList *OwnerList) { loadScene(3200); R2_GLOBALS._uiElements._active = false; @@ -962,6 +963,7 @@ void Scene3200::signal() { * Scene 3210 - Cutscene : Captain and Private - Discussion * *--------------------------------------------------------------------------*/ + void Scene3210::postInit(SceneObjectList *OwnerList) { loadScene(3210); R2_GLOBALS._uiElements._active = false; @@ -988,6 +990,7 @@ void Scene3210::signal() { * Scene 3220 - Cutscene : Guards in cargo zone * *--------------------------------------------------------------------------*/ + void Scene3220::postInit(SceneObjectList *OwnerList) { loadScene(3220); R2_GLOBALS._uiElements._active = false; @@ -1014,6 +1017,7 @@ void Scene3220::signal() { * Scene 3230 - Cutscene : Guards on duty * *--------------------------------------------------------------------------*/ + void Scene3230::postInit(SceneObjectList *OwnerList) { loadScene(3230); R2_GLOBALS._uiElements._active = false; diff --git a/engines/tsage/ringworld2/ringworld2_speakers.cpp b/engines/tsage/ringworld2/ringworld2_speakers.cpp index 3091086980..a43938230e 100644 --- a/engines/tsage/ringworld2/ringworld2_speakers.cpp +++ b/engines/tsage/ringworld2/ringworld2_speakers.cpp @@ -44,6 +44,10 @@ VisualSpeaker::VisualSpeaker(): Speaker() { } void VisualSpeaker::remove() { + _numFrames = 0; + _delayAmount = 0; + R2_GLOBALS._playStream.stop(); + if (_object2) { if (_fieldF8) { _fieldF8 = 0; @@ -1176,7 +1180,7 @@ void SpeakerQuinn300::proc15() { int v = _speakerMode; if (!_object2) { - if (R2_GLOBALS._player._characterIndex == R2_MIRANDA) { + if (R2_GLOBALS._player._characterIndex == R2_QUINN) { _object2 = &R2_GLOBALS._player; } else { assert(R2_GLOBALS._sceneManager._sceneNumber == 300); @@ -1187,9 +1191,6 @@ void SpeakerQuinn300::proc15() { _object2->hide(); _object1.postInit(); _object1.setPosition(_object2->_position); - - if (_object2->_mover) - _object2->addMover(NULL); } if (v == 0) { @@ -1205,7 +1206,7 @@ void SpeakerQuinn300::proc15() { ((SceneItem *)_action)->_sceneRegionId = 0; switch (_object2->_visage) { - case 10: + case 10: _object1.setup((v - 1) / 4 + 4010, ((v - ((v - 1) / 4 * 4) - 1) % 8) * 2 + 1, 1); break; case 302: @@ -1214,6 +1215,8 @@ void SpeakerQuinn300::proc15() { case 308: _object1.setup(308, 5, 1); break; + default: + break; } _object1.animate(ANIM_MODE_5, this); diff --git a/engines/tsage/saveload.cpp b/engines/tsage/saveload.cpp index 7143305586..dbc122e6e4 100644 --- a/engines/tsage/saveload.cpp +++ b/engines/tsage/saveload.cpp @@ -151,8 +151,9 @@ Common::Error Saver::save(int slot, const Common::String &saveName) { // Save each registered SaveObject descendant object into the savegame file for (SynchronizedList<SavedObject *>::iterator i = _objList.begin(); i != _objList.end(); ++i) { - serializer.validate((*i)->getClassName()); - (*i)->synchronize(serializer); + SavedObject *so = *i; + serializer.validate(so->getClassName()); + so->synchronize(serializer); } // Save file complete diff --git a/engines/tsage/sound.cpp b/engines/tsage/sound.cpp index b9567cece2..02abc58178 100644 --- a/engines/tsage/sound.cpp +++ b/engines/tsage/sound.cpp @@ -22,6 +22,8 @@ #include "audio/decoders/raw.h" #include "common/config-manager.h" +#include "audio/decoders/raw.h" +#include "audio/audiostream.h" #include "tsage/core.h" #include "tsage/globals.h" #include "tsage/debugger.h" @@ -2505,6 +2507,168 @@ void ASoundExt::changeSound(int soundNum) { /*--------------------------------------------------------------------------*/ +void PlayStream::ResFileData::load(Common::SeekableReadStream &stream) { + // Validate that it's the correct data file + char header[4]; + stream.read(&header[0], 4); + if (strncmp(header, "SPAM", 4)) + error("Invalid voice resource data"); + + _fileChunkSize = stream.readUint32LE(); + stream.skip(2); + _indexSize = stream.readUint16LE(); + _chunkSize = stream.readUint16LE(); + + stream.skip(18); +} + +PlayStream::PlayStream(): EventHandler() { + _index = NULL; + _endAction = NULL; +} + +PlayStream::~PlayStream() { + remove(); +} + +bool PlayStream::setFile(const Common::String &filename) { + remove(); + + // Open the resource file for access + if (!_file.open(filename)) + return false; + + // Load header + _resData.load(_file); + + // Load the index + _index = new uint16[_resData._indexSize / 2]; + for (uint i = 0; i < (_resData._indexSize / 2); ++i) + _index[i] = _file.readUint16LE(); + + return true; +} + +bool PlayStream::play(int voiceNum, EventHandler *endAction) { + uint32 offset = getFileOffset(_index, _resData._fileChunkSize, voiceNum); + if (offset) { + _voiceNum = 0; + if (_sound.isPlaying()) + _sound.stop(); + + // Move to the offset for the start of the voice + _file.seek(offset); + + // Read in the header and validate it + char header[4]; + _file.read(&header[0], 4); + if (strncmp(header, "FEED", 4)) + error("Invalid stream data"); + + // Get basic details of first sound chunk + uint chunkSize = _file.readUint16LE() - 16; + _file.skip(4); + int rate = _file.readUint16LE(); + _file.skip(4); + + // Create the stream + Audio::QueuingAudioStream *audioStream = Audio::makeQueuingAudioStream(rate, false); + + // Load in the first chunk + byte *data = (byte *)malloc(chunkSize); + _file.read(data, chunkSize); + audioStream->queueBuffer(data, chunkSize, DisposeAfterUse::YES, Audio::FLAG_UNSIGNED); + + // If necessary, load further chunks of the voice in + while (chunkSize == (_resData._chunkSize - 16)) { + // Ensure the next chunk has the 'MORE' header + _file.read(&header[0], 4); + if (strncmp(header, "MORE", 4)) + error("Invalid stream data"); + + // Get the size of the chunk + chunkSize = _file.readUint16LE() - 16; + _file.skip(10); + + // Read in the data for this next chunk and queue it + data = (byte *)malloc(chunkSize); + _file.read(data, chunkSize); + audioStream->queueBuffer(data, chunkSize, DisposeAfterUse::YES, Audio::FLAG_UNSIGNED); + } + + g_vm->_mixer->playStream(Audio::Mixer::kSpeechSoundType, &_soundHandle, + audioStream, DisposeAfterUse::YES); + + return true; + } + + // If it reaches this point, no valid voice data found + return false; +} + +void PlayStream::stop() { + g_vm->_mixer->stopHandle(_soundHandle); + + _voiceNum = 0; + _endAction = NULL; +} + +bool PlayStream::isPlaying() const { + return _voiceNum != 0 && g_vm->_mixer->isSoundHandleActive(_soundHandle); +} + +void PlayStream::remove() { + stop(); + _file.close(); + + // Free index + delete[] _index; + _index = NULL; + + _endAction = NULL; + _voiceNum = 0; +} + +void PlayStream::dispatch() { + if (_voiceNum != 0 && !isPlaying()) { + // If voice has finished playing, reset fields + EventHandler *endAction = _endAction; + _endAction = NULL; + _voiceNum = 0; + + if (endAction) + // Signal given end action + endAction->signal(); + } +} + +uint32 PlayStream::getFileOffset(const uint16 *data, int count, int voiceNum) { + assert(data); + int bitsIndex = voiceNum & 7; + int byteIndex = voiceNum >> 3; + int shiftAmount = bitsIndex * 2; + int bitMask = 3 << shiftAmount; + int v = (data[byteIndex] & bitMask) >> shiftAmount; + uint32 offset = 0; + + if (!v) + return 0; + + // Loop to figure out offsets from index words skipped over + for (int i = 0; i < (voiceNum >> 3); ++i) { + for (int bit = 0; bit < 16; bit += 2) + offset += ((data[i] >> bit) & 3) * count; + } + + // Bit index loop + for (int i = 0; i < bitsIndex; ++i) + offset += ((data[byteIndex] >> (i * 2)) & 3) * count; + + return offset; +} + +/*--------------------------------------------------------------------------*/ + SoundDriver::SoundDriver() { _driverResID = 0; _minVersion = _maxVersion = 0; diff --git a/engines/tsage/sound.h b/engines/tsage/sound.h index 2f59afb49b..83cd4753d5 100644 --- a/engines/tsage/sound.h +++ b/engines/tsage/sound.h @@ -259,6 +259,7 @@ public: class Sound: public EventHandler { private: void _prime(int soundResID, bool dontQueue); + void _primeBuffer(const byte *soundData); void _unPrime(); public: bool _stoppedAsynchronously; @@ -414,15 +415,36 @@ public: virtual void signal(); }; -class PlayStream { -public: +class PlayStream: public EventHandler { + class ResFileData { + public: + int _fileChunkSize; + uint _indexSize; + uint _chunkSize; + + void load(Common::SeekableReadStream &stream); + }; +private: + Common::File _file; + ResFileData _resData; + Audio::SoundHandle _soundHandle; Sound _sound; + uint16 *_index; + EventHandler *_endAction; + int _voiceNum; - void setFile(const Common::String &filename) {} - bool play(int soundNum, EventHandler *endAction) { return false; } - void stop() {} - void proc1() {} - bool isPlaying() const { return false; } + static uint32 getFileOffset(const uint16 *data, int count, int voiceNum); +public: + PlayStream(); + virtual ~PlayStream(); + + bool setFile(const Common::String &filename); + bool play(int voiceNum, EventHandler *endAction); + void stop(); + bool isPlaying() const; + + virtual void remove(); + virtual void dispatch(); }; #define ADLIB_CHANNEL_COUNT 9 diff --git a/engines/wintermute/ad/ad_actor.cpp b/engines/wintermute/ad/ad_actor.cpp index 94df17c543..967270b9bd 100644 --- a/engines/wintermute/ad/ad_actor.cpp +++ b/engines/wintermute/ad/ad_actor.cpp @@ -119,7 +119,7 @@ AdActor::~AdActor() { ////////////////////////////////////////////////////////////////////////// bool AdActor::loadFile(const char *filename) { - byte *buffer = BaseFileManager::getEngineInstance()->readWholeFile(filename); + char *buffer = (char *)BaseFileManager::getEngineInstance()->readWholeFile(filename); if (buffer == nullptr) { _gameRef->LOG(0, "AdActor::LoadFile failed for file '%s'", filename); return STATUS_FAILED; @@ -179,7 +179,7 @@ TOKEN_DEF(EDITOR_PROPERTY) TOKEN_DEF(ANIMATION) TOKEN_DEF_END ////////////////////////////////////////////////////////////////////////// -bool AdActor::loadBuffer(byte *buffer, bool complete) { +bool AdActor::loadBuffer(char *buffer, bool complete) { TOKEN_TABLE_START(commands) TOKEN_TABLE(ACTOR) TOKEN_TABLE(X) @@ -219,12 +219,12 @@ bool AdActor::loadBuffer(byte *buffer, bool complete) { TOKEN_TABLE(ANIMATION) TOKEN_TABLE_END - byte *params; + char *params; int cmd; BaseParser parser; if (complete) { - if (parser.getCommand((char **)&buffer, commands, (char **)¶ms) != TOKEN_ACTOR) { + if (parser.getCommand(&buffer, commands, ¶ms) != TOKEN_ACTOR) { _gameRef->LOG(0, "'ACTOR' keyword expected."); return STATUS_FAILED; } @@ -234,55 +234,55 @@ bool AdActor::loadBuffer(byte *buffer, bool complete) { AdGame *adGame = (AdGame *)_gameRef; AdSpriteSet *spr = nullptr; int ar = 0, ag = 0, ab = 0, alpha = 0; - while ((cmd = parser.getCommand((char **)&buffer, commands, (char **)¶ms)) > 0) { + while ((cmd = parser.getCommand(&buffer, commands, ¶ms)) > 0) { switch (cmd) { case TOKEN_TEMPLATE: - if (DID_FAIL(loadFile((char *)params))) { + if (DID_FAIL(loadFile(params))) { cmd = PARSERR_GENERIC; } break; case TOKEN_X: - parser.scanStr((char *)params, "%d", &_posX); + parser.scanStr(params, "%d", &_posX); break; case TOKEN_Y: - parser.scanStr((char *)params, "%d", &_posY); + parser.scanStr(params, "%d", &_posY); break; case TOKEN_NAME: - setName((char *)params); + setName(params); break; case TOKEN_CAPTION: - setCaption((char *)params); + setCaption(params); break; case TOKEN_FONT: - setFont((char *)params); + setFont(params); break; case TOKEN_SCALABLE: - parser.scanStr((char *)params, "%b", &_zoomable); + parser.scanStr(params, "%b", &_zoomable); break; case TOKEN_ROTABLE: case TOKEN_ROTATABLE: - parser.scanStr((char *)params, "%b", &_rotatable); + parser.scanStr(params, "%b", &_rotatable); break; case TOKEN_REGISTRABLE: case TOKEN_INTERACTIVE: - parser.scanStr((char *)params, "%b", &_registrable); + parser.scanStr(params, "%b", &_registrable); break; case TOKEN_SHADOWABLE: case TOKEN_COLORABLE: - parser.scanStr((char *)params, "%b", &_shadowable); + parser.scanStr(params, "%b", &_shadowable); break; case TOKEN_ACTIVE: - parser.scanStr((char *)params, "%b", &_active); + parser.scanStr(params, "%b", &_active); break; case TOKEN_WALK: @@ -348,7 +348,7 @@ bool AdActor::loadBuffer(byte *buffer, bool complete) { break; case TOKEN_SCRIPT: - addScript((char *)params); + addScript(params); break; case TOKEN_CURSOR: @@ -362,12 +362,12 @@ bool AdActor::loadBuffer(byte *buffer, bool complete) { break; case TOKEN_SOUND_VOLUME: - parser.scanStr((char *)params, "%d", &_sFXVolume); + parser.scanStr(params, "%d", &_sFXVolume); break; case TOKEN_SCALE: { int s; - parser.scanStr((char *)params, "%d", &s); + parser.scanStr(params, "%d", &s); _scale = (float)s; } @@ -375,14 +375,14 @@ bool AdActor::loadBuffer(byte *buffer, bool complete) { case TOKEN_RELATIVE_SCALE: { int s; - parser.scanStr((char *)params, "%d", &s); + parser.scanStr(params, "%d", &s); _relativeScale = (float)s; } break; case TOKEN_SOUND_PANNING: - parser.scanStr((char *)params, "%b", &_autoSoundPanning); + parser.scanStr(params, "%b", &_autoSoundPanning); break; case TOKEN_PROPERTY: @@ -432,15 +432,15 @@ bool AdActor::loadBuffer(byte *buffer, bool complete) { break; case TOKEN_IGNORE_ITEMS: - parser.scanStr((char *)params, "%b", &_ignoreItems); + parser.scanStr(params, "%b", &_ignoreItems); break; case TOKEN_ALPHA_COLOR: - parser.scanStr((char *)params, "%d,%d,%d", &ar, &ag, &ab); + parser.scanStr(params, "%d,%d,%d", &ar, &ag, &ab); break; case TOKEN_ALPHA: - parser.scanStr((char *)params, "%d", &alpha); + parser.scanStr(params, "%d", &alpha); break; case TOKEN_EDITOR_PROPERTY: @@ -1410,20 +1410,20 @@ bool AdActor::mergeAnims(const char *animsFilename) { TOKEN_TABLE_END - byte *fileBuffer = BaseFileManager::getEngineInstance()->readWholeFile(animsFilename); + char *fileBuffer = (char *)BaseFileManager::getEngineInstance()->readWholeFile(animsFilename); if (fileBuffer == nullptr) { _gameRef->LOG(0, "AdActor::MergeAnims failed for file '%s'", animsFilename); return STATUS_FAILED; } - byte *buffer = fileBuffer; - byte *params; + char *buffer = fileBuffer; + char *params; int cmd; BaseParser parser; bool ret = STATUS_OK; - while ((cmd = parser.getCommand((char **)&buffer, commands, (char **)¶ms)) > 0) { + while ((cmd = parser.getCommand(&buffer, commands, ¶ms)) > 0) { switch (cmd) { case TOKEN_ANIMATION: { AdSpriteSet *anim = new AdSpriteSet(_gameRef, this); diff --git a/engines/wintermute/ad/ad_actor.h b/engines/wintermute/ad/ad_actor.h index 582b41b8b0..e836dd72cf 100644 --- a/engines/wintermute/ad/ad_actor.h +++ b/engines/wintermute/ad/ad_actor.h @@ -57,7 +57,7 @@ public: AdActor(BaseGame *inGame/*=nullptr*/); virtual ~AdActor(); bool loadFile(const char *filename); - bool loadBuffer(byte *buffer, bool complete = true); + bool loadBuffer(char *buffer, bool complete = true); private: diff --git a/engines/wintermute/ad/ad_entity.cpp b/engines/wintermute/ad/ad_entity.cpp index 388accf34f..2c0e13a4dc 100644 --- a/engines/wintermute/ad/ad_entity.cpp +++ b/engines/wintermute/ad/ad_entity.cpp @@ -100,7 +100,7 @@ const char *AdEntity::getItemName() const { ////////////////////////////////////////////////////////////////////////// bool AdEntity::loadFile(const char *filename) { - byte *buffer = BaseFileManager::getEngineInstance()->readWholeFile(filename); + char *buffer = (char *)BaseFileManager::getEngineInstance()->readWholeFile(filename); if (buffer == nullptr) { _gameRef->LOG(0, "AdEntity::LoadFile failed for file '%s'", filename); return STATUS_FAILED; @@ -166,7 +166,7 @@ TOKEN_DEF(WALK_TO_DIR) TOKEN_DEF(SAVE_STATE) TOKEN_DEF_END ////////////////////////////////////////////////////////////////////////// -bool AdEntity::loadBuffer(byte *buffer, bool complete) { +bool AdEntity::loadBuffer(char *buffer, bool complete) { TOKEN_TABLE_START(commands) TOKEN_TABLE(ENTITY) TOKEN_TABLE(SPRITE) @@ -212,12 +212,12 @@ bool AdEntity::loadBuffer(byte *buffer, bool complete) { TOKEN_TABLE(SAVE_STATE) TOKEN_TABLE_END - byte *params; + char *params; int cmd; BaseParser parser; if (complete) { - if (parser.getCommand((char **)&buffer, commands, (char **)¶ms) != TOKEN_ENTITY) { + if (parser.getCommand(&buffer, commands, ¶ms) != TOKEN_ENTITY) { _gameRef->LOG(0, "'ENTITY' keyword expected."); return STATUS_FAILED; } @@ -227,27 +227,27 @@ bool AdEntity::loadBuffer(byte *buffer, bool complete) { AdGame *adGame = (AdGame *)_gameRef; BaseSprite *spr = nullptr; int ar = 0, ag = 0, ab = 0, alpha = 0; - while ((cmd = parser.getCommand((char **)&buffer, commands, (char **)¶ms)) > 0) { + while ((cmd = parser.getCommand(&buffer, commands, ¶ms)) > 0) { switch (cmd) { case TOKEN_TEMPLATE: - if (DID_FAIL(loadFile((char *)params))) { + if (DID_FAIL(loadFile(params))) { cmd = PARSERR_GENERIC; } break; case TOKEN_X: - parser.scanStr((char *)params, "%d", &_posX); + parser.scanStr(params, "%d", &_posX); break; case TOKEN_Y: - parser.scanStr((char *)params, "%d", &_posY); + parser.scanStr(params, "%d", &_posY); break; case TOKEN_SPRITE: { delete _sprite; _sprite = nullptr; spr = new BaseSprite(_gameRef, this); - if (!spr || DID_FAIL(spr->loadFile((char *)params))) { + if (!spr || DID_FAIL(spr->loadFile(params))) { cmd = PARSERR_GENERIC; } else { _sprite = spr; @@ -257,7 +257,7 @@ bool AdEntity::loadBuffer(byte *buffer, bool complete) { case TOKEN_TALK: { spr = new BaseSprite(_gameRef, this); - if (!spr || DID_FAIL(spr->loadFile((char *)params, adGame->_texTalkLifeTime))) { + if (!spr || DID_FAIL(spr->loadFile(params, adGame->_texTalkLifeTime))) { cmd = PARSERR_GENERIC; } else { _talkSprites.add(spr); @@ -267,7 +267,7 @@ bool AdEntity::loadBuffer(byte *buffer, bool complete) { case TOKEN_TALK_SPECIAL: { spr = new BaseSprite(_gameRef, this); - if (!spr || DID_FAIL(spr->loadFile((char *)params, adGame->_texTalkLifeTime))) { + if (!spr || DID_FAIL(spr->loadFile(params, adGame->_texTalkLifeTime))) { cmd = PARSERR_GENERIC; } else { _talkSpritesEx.add(spr); @@ -276,28 +276,28 @@ bool AdEntity::loadBuffer(byte *buffer, bool complete) { break; case TOKEN_NAME: - setName((char *)params); + setName(params); break; case TOKEN_ITEM: - setItem((char *)params); + setItem(params); break; case TOKEN_CAPTION: - setCaption((char *)params); + setCaption(params); break; case TOKEN_FONT: - setFont((char *)params); + setFont(params); break; case TOKEN_SCALABLE: - parser.scanStr((char *)params, "%b", &_zoomable); + parser.scanStr(params, "%b", &_zoomable); break; case TOKEN_SCALE: { int s; - parser.scanStr((char *)params, "%d", &s); + parser.scanStr(params, "%d", &s); _scale = (float)s; } @@ -305,7 +305,7 @@ bool AdEntity::loadBuffer(byte *buffer, bool complete) { case TOKEN_RELATIVE_SCALE: { int s; - parser.scanStr((char *)params, "%d", &s); + parser.scanStr(params, "%d", &s); _relativeScale = (float)s; } @@ -313,27 +313,27 @@ bool AdEntity::loadBuffer(byte *buffer, bool complete) { case TOKEN_ROTABLE: case TOKEN_ROTATABLE: - parser.scanStr((char *)params, "%b", &_rotatable); + parser.scanStr(params, "%b", &_rotatable); break; case TOKEN_REGISTRABLE: case TOKEN_INTERACTIVE: - parser.scanStr((char *)params, "%b", &_registrable); + parser.scanStr(params, "%b", &_registrable); break; case TOKEN_SHADOWABLE: case TOKEN_COLORABLE: - parser.scanStr((char *)params, "%b", &_shadowable); + parser.scanStr(params, "%b", &_shadowable); break; case TOKEN_ACTIVE: - parser.scanStr((char *)params, "%b", &_active); + parser.scanStr(params, "%b", &_active); break; case TOKEN_CURSOR: delete _cursor; _cursor = new BaseSprite(_gameRef); - if (!_cursor || DID_FAIL(_cursor->loadFile((char *)params))) { + if (!_cursor || DID_FAIL(_cursor->loadFile(params))) { delete _cursor; _cursor = nullptr; cmd = PARSERR_GENERIC; @@ -341,7 +341,7 @@ bool AdEntity::loadBuffer(byte *buffer, bool complete) { break; case TOKEN_EDITOR_SELECTED: - parser.scanStr((char *)params, "%b", &_editorSelected); + parser.scanStr(params, "%b", &_editorSelected); break; case TOKEN_REGION: { @@ -402,11 +402,11 @@ bool AdEntity::loadBuffer(byte *buffer, bool complete) { break; case TOKEN_SCRIPT: - addScript((char *)params); + addScript(params); break; case TOKEN_SUBTYPE: { - if (scumm_stricmp((char *)params, "sound") == 0) { + if (scumm_stricmp(params, "sound") == 0) { delete _sprite; _sprite = nullptr; if (_gameRef->_editorMode) { @@ -430,23 +430,23 @@ bool AdEntity::loadBuffer(byte *buffer, bool complete) { break; case TOKEN_SOUND: - playSFX((char *)params, false, false); + playSFX(params, false, false); break; case TOKEN_SOUND_START_TIME: - parser.scanStr((char *)params, "%d", &_sFXStart); + parser.scanStr(params, "%d", &_sFXStart); break; case TOKEN_SOUND_VOLUME: - parser.scanStr((char *)params, "%d", &_sFXVolume); + parser.scanStr(params, "%d", &_sFXVolume); break; case TOKEN_SOUND_PANNING: - parser.scanStr((char *)params, "%b", &_autoSoundPanning); + parser.scanStr(params, "%b", &_autoSoundPanning); break; case TOKEN_SAVE_STATE: - parser.scanStr((char *)params, "%b", &_saveState); + parser.scanStr(params, "%b", &_saveState); break; case TOKEN_PROPERTY: @@ -454,15 +454,15 @@ bool AdEntity::loadBuffer(byte *buffer, bool complete) { break; case TOKEN_IGNORE_ITEMS: - parser.scanStr((char *)params, "%b", &_ignoreItems); + parser.scanStr(params, "%b", &_ignoreItems); break; case TOKEN_ALPHA_COLOR: - parser.scanStr((char *)params, "%d,%d,%d", &ar, &ag, &ab); + parser.scanStr(params, "%d,%d,%d", &ar, &ag, &ab); break; case TOKEN_ALPHA: - parser.scanStr((char *)params, "%d", &alpha); + parser.scanStr(params, "%d", &alpha); break; case TOKEN_EDITOR_PROPERTY: @@ -470,16 +470,16 @@ bool AdEntity::loadBuffer(byte *buffer, bool complete) { break; case TOKEN_WALK_TO_X: - parser.scanStr((char *)params, "%d", &_walkToX); + parser.scanStr(params, "%d", &_walkToX); break; case TOKEN_WALK_TO_Y: - parser.scanStr((char *)params, "%d", &_walkToY); + parser.scanStr(params, "%d", &_walkToY); break; case TOKEN_WALK_TO_DIR: { int i; - parser.scanStr((char *)params, "%d", &i); + parser.scanStr(params, "%d", &i); if (i < 0) { i = 0; } diff --git a/engines/wintermute/ad/ad_entity.h b/engines/wintermute/ad/ad_entity.h index bdbd271667..c4d60e86f3 100644 --- a/engines/wintermute/ad/ad_entity.h +++ b/engines/wintermute/ad/ad_entity.h @@ -48,7 +48,7 @@ public: AdEntity(BaseGame *inGame); virtual ~AdEntity(); bool loadFile(const char *filename); - bool loadBuffer(byte *buffer, bool complete = true); + bool loadBuffer(char *buffer, bool complete = true); int32 getWalkToX() const; int32 getWalkToY() const; diff --git a/engines/wintermute/ad/ad_game.cpp b/engines/wintermute/ad/ad_game.cpp index d5799e851b..86f470b8c3 100644 --- a/engines/wintermute/ad/ad_game.cpp +++ b/engines/wintermute/ad/ad_game.cpp @@ -1245,7 +1245,7 @@ bool AdGame::showCursor() { ////////////////////////////////////////////////////////////////////////// bool AdGame::loadFile(const char *filename) { - byte *buffer = BaseFileManager::getEngineInstance()->readWholeFile(filename); + char *buffer = (char *)BaseFileManager::getEngineInstance()->readWholeFile(filename); if (buffer == nullptr) { _gameRef->LOG(0, "AdGame::LoadFile failed for file '%s'", filename); return STATUS_FAILED; @@ -1281,7 +1281,7 @@ TOKEN_DEF(STARTUP_SCENE) TOKEN_DEF(DEBUG_STARTUP_SCENE) TOKEN_DEF_END ////////////////////////////////////////////////////////////////////////// -bool AdGame::loadBuffer(byte *buffer, bool complete) { +bool AdGame::loadBuffer(char *buffer, bool complete) { TOKEN_TABLE_START(commands) TOKEN_TABLE(GAME) TOKEN_TABLE(AD_GAME) @@ -1295,14 +1295,14 @@ bool AdGame::loadBuffer(byte *buffer, bool complete) { TOKEN_TABLE(DEBUG_STARTUP_SCENE) TOKEN_TABLE_END - byte *params; - byte *params2; + char *params; + char *params2; int cmd = 1; BaseParser parser; bool itemFound = false, itemsFound = false; - while (cmd > 0 && (cmd = parser.getCommand((char **)&buffer, commands, (char **)¶ms)) > 0) { + while (cmd > 0 && (cmd = parser.getCommand(&buffer, commands, ¶ms)) > 0) { switch (cmd) { case TOKEN_GAME: if (DID_FAIL(BaseGame::loadBuffer(params, false))) { @@ -1311,12 +1311,12 @@ bool AdGame::loadBuffer(byte *buffer, bool complete) { break; case TOKEN_AD_GAME: - while (cmd > 0 && (cmd = parser.getCommand((char **)¶ms, commands, (char **)¶ms2)) > 0) { + while (cmd > 0 && (cmd = parser.getCommand(¶ms, commands, ¶ms2)) > 0) { switch (cmd) { case TOKEN_RESPONSE_BOX: delete _responseBox; _responseBox = new AdResponseBox(_gameRef); - if (_responseBox && !DID_FAIL(_responseBox->loadFile((char *)params2))) { + if (_responseBox && !DID_FAIL(_responseBox->loadFile(params2))) { registerObject(_responseBox); } else { delete _responseBox; @@ -1328,7 +1328,7 @@ bool AdGame::loadBuffer(byte *buffer, bool complete) { case TOKEN_INVENTORY_BOX: delete _inventoryBox; _inventoryBox = new AdInventoryBox(_gameRef); - if (_inventoryBox && !DID_FAIL(_inventoryBox->loadFile((char *)params2))) { + if (_inventoryBox && !DID_FAIL(_inventoryBox->loadFile(params2))) { registerObject(_inventoryBox); } else { delete _inventoryBox; @@ -1339,7 +1339,7 @@ bool AdGame::loadBuffer(byte *buffer, bool complete) { case TOKEN_ITEMS: itemsFound = true; - BaseUtils::setString(&_itemsFile, (char *)params2); + BaseUtils::setString(&_itemsFile, params2); if (DID_FAIL(loadItemsFile(_itemsFile))) { delete[] _itemsFile; _itemsFile = nullptr; @@ -1348,9 +1348,9 @@ bool AdGame::loadBuffer(byte *buffer, bool complete) { break; case TOKEN_TALK_SKIP_BUTTON: - if (scumm_stricmp((char *)params2, "right") == 0) { + if (scumm_stricmp(params2, "right") == 0) { _talkSkipButton = TALK_SKIP_RIGHT; - } else if (scumm_stricmp((char *)params2, "both") == 0) { + } else if (scumm_stricmp(params2, "both") == 0) { _talkSkipButton = TALK_SKIP_BOTH; } else { _talkSkipButton = TALK_SKIP_LEFT; @@ -1359,7 +1359,7 @@ bool AdGame::loadBuffer(byte *buffer, bool complete) { case TOKEN_SCENE_VIEWPORT: { Rect32 rc; - parser.scanStr((char *)params2, "%d,%d,%d,%d", &rc.left, &rc.top, &rc.right, &rc.bottom); + parser.scanStr(params2, "%d,%d,%d,%d", &rc.left, &rc.top, &rc.right, &rc.bottom); if (!_sceneViewport) { _sceneViewport = new BaseViewport(_gameRef); } @@ -1374,11 +1374,11 @@ bool AdGame::loadBuffer(byte *buffer, bool complete) { break; case TOKEN_STARTUP_SCENE: - BaseUtils::setString(&_startupScene, (char *)params2); + BaseUtils::setString(&_startupScene, params2); break; case TOKEN_DEBUG_STARTUP_SCENE: - BaseUtils::setString(&_debugStartupScene, (char *)params2); + BaseUtils::setString(&_debugStartupScene, params2); break; } } @@ -1518,7 +1518,7 @@ bool AdGame::getVersion(byte *verMajor, byte *verMinor, byte *extMajor, byte *ex ////////////////////////////////////////////////////////////////////////// bool AdGame::loadItemsFile(const char *filename, bool merge) { - byte *buffer = BaseFileManager::getEngineInstance()->readWholeFile(filename); + char *buffer = (char *)BaseFileManager::getEngineInstance()->readWholeFile(filename); if (buffer == nullptr) { _gameRef->LOG(0, "AdGame::LoadItemsFile failed for file '%s'", filename); return STATUS_FAILED; @@ -1541,12 +1541,12 @@ bool AdGame::loadItemsFile(const char *filename, bool merge) { ////////////////////////////////////////////////////////////////////////// -bool AdGame::loadItemsBuffer(byte *buffer, bool merge) { +bool AdGame::loadItemsBuffer(char *buffer, bool merge) { TOKEN_TABLE_START(commands) TOKEN_TABLE(ITEM) TOKEN_TABLE_END - byte *params; + char *params; int cmd; BaseParser parser; @@ -1556,7 +1556,7 @@ bool AdGame::loadItemsBuffer(byte *buffer, bool merge) { } } - while ((cmd = parser.getCommand((char **)&buffer, commands, (char **)¶ms)) > 0) { + while ((cmd = parser.getCommand(&buffer, commands, ¶ms)) > 0) { switch (cmd) { case TOKEN_ITEM: { AdItem *item = new AdItem(_gameRef); @@ -1637,7 +1637,7 @@ bool AdGame::windowLoadHook(UIWindow *win, char **buffer, char **params) { switch (cmd) { case TOKEN_ENTITY_CONTAINER: { UIEntity *ent = new UIEntity(_gameRef); - if (!ent || DID_FAIL(ent->loadBuffer((byte *)*params, false))) { + if (!ent || DID_FAIL(ent->loadBuffer(*params, false))) { delete ent; ent = nullptr; cmd = PARSERR_GENERIC; diff --git a/engines/wintermute/ad/ad_game.h b/engines/wintermute/ad/ad_game.h index cb5147501d..019f2e6478 100644 --- a/engines/wintermute/ad/ad_game.h +++ b/engines/wintermute/ad/ad_game.h @@ -120,10 +120,10 @@ public: BaseArray<AdObject *> _objects; virtual bool loadFile(const char *filename); - virtual bool loadBuffer(byte *buffer, bool complete = true); + virtual bool loadBuffer(char *buffer, bool complete = true); bool loadItemsFile(const char *filename, bool merge = false); - bool loadItemsBuffer(byte *buffer, bool merge = false); + bool loadItemsBuffer(char *buffer, bool merge = false); // scripting interface virtual ScValue *scGetProperty(const Common::String &name) override; diff --git a/engines/wintermute/ad/ad_inventory_box.cpp b/engines/wintermute/ad/ad_inventory_box.cpp index d703de1714..4c904e78eb 100644 --- a/engines/wintermute/ad/ad_inventory_box.cpp +++ b/engines/wintermute/ad/ad_inventory_box.cpp @@ -120,8 +120,8 @@ bool AdInventoryBox::display() { if (_closeButton) { _closeButton->_posX = _closeButton->_posY = 0; - _closeButton->_width = _gameRef->_renderer->getWidth(); - _closeButton->_height = _gameRef->_renderer->getHeight(); + _closeButton->setWidth(_gameRef->_renderer->getWidth()); + _closeButton->setHeight(_gameRef->_renderer->getHeight()); _closeButton->display(); } @@ -165,7 +165,7 @@ bool AdInventoryBox::display() { ////////////////////////////////////////////////////////////////////////// bool AdInventoryBox::loadFile(const char *filename) { - byte *buffer = BaseFileManager::getEngineInstance()->readWholeFile(filename); + char *buffer = (char *)BaseFileManager::getEngineInstance()->readWholeFile(filename); if (buffer == nullptr) { _gameRef->LOG(0, "AdInventoryBox::LoadFile failed for file '%s'", filename); return STATUS_FAILED; @@ -203,7 +203,7 @@ TOKEN_DEF(HIDE_SELECTED) TOKEN_DEF(EDITOR_PROPERTY) TOKEN_DEF_END ////////////////////////////////////////////////////////////////////////// -bool AdInventoryBox::loadBuffer(byte *buffer, bool complete) { +bool AdInventoryBox::loadBuffer(char *buffer, bool complete) { TOKEN_TABLE_START(commands) TOKEN_TABLE(INVENTORY_BOX) TOKEN_TABLE(TEMPLATE) @@ -221,34 +221,34 @@ bool AdInventoryBox::loadBuffer(byte *buffer, bool complete) { TOKEN_TABLE(EDITOR_PROPERTY) TOKEN_TABLE_END - byte *params; + char *params; int cmd = 2; BaseParser parser; bool alwaysVisible = false; _exclusive = false; if (complete) { - if (parser.getCommand((char **)&buffer, commands, (char **)¶ms) != TOKEN_INVENTORY_BOX) { + if (parser.getCommand(&buffer, commands, ¶ms) != TOKEN_INVENTORY_BOX) { _gameRef->LOG(0, "'INVENTORY_BOX' keyword expected."); return STATUS_FAILED; } buffer = params; } - while (cmd > 0 && (cmd = parser.getCommand((char **)&buffer, commands, (char **)¶ms)) > 0) { + while (cmd > 0 && (cmd = parser.getCommand(&buffer, commands, ¶ms)) > 0) { switch (cmd) { case TOKEN_TEMPLATE: - if (DID_FAIL(loadFile((char *)params))) { + if (DID_FAIL(loadFile(params))) { cmd = PARSERR_GENERIC; } break; case TOKEN_NAME: - setName((char *)params); + setName(params); break; case TOKEN_CAPTION: - setCaption((char *)params); + setCaption(params); break; case TOKEN_WINDOW: @@ -264,35 +264,35 @@ bool AdInventoryBox::loadBuffer(byte *buffer, bool complete) { break; case TOKEN_AREA: - parser.scanStr((char *)params, "%d,%d,%d,%d", &_itemsArea.left, &_itemsArea.top, &_itemsArea.right, &_itemsArea.bottom); + parser.scanStr(params, "%d,%d,%d,%d", &_itemsArea.left, &_itemsArea.top, &_itemsArea.right, &_itemsArea.bottom); break; case TOKEN_EXCLUSIVE: - parser.scanStr((char *)params, "%b", &_exclusive); + parser.scanStr(params, "%b", &_exclusive); break; case TOKEN_HIDE_SELECTED: - parser.scanStr((char *)params, "%b", &_hideSelected); + parser.scanStr(params, "%b", &_hideSelected); break; case TOKEN_ALWAYS_VISIBLE: - parser.scanStr((char *)params, "%b", &alwaysVisible); + parser.scanStr(params, "%b", &alwaysVisible); break; case TOKEN_SPACING: - parser.scanStr((char *)params, "%d", &_spacing); + parser.scanStr(params, "%d", &_spacing); break; case TOKEN_ITEM_WIDTH: - parser.scanStr((char *)params, "%d", &_itemWidth); + parser.scanStr(params, "%d", &_itemWidth); break; case TOKEN_ITEM_HEIGHT: - parser.scanStr((char *)params, "%d", &_itemHeight); + parser.scanStr(params, "%d", &_itemHeight); break; case TOKEN_SCROLL_BY: - parser.scanStr((char *)params, "%d", &_scrollBy); + parser.scanStr(params, "%d", &_scrollBy); break; case TOKEN_EDITOR_PROPERTY: @@ -323,7 +323,7 @@ bool AdInventoryBox::loadBuffer(byte *buffer, bool complete) { if (_window) { for (uint32 i = 0; i < _window->_widgets.size(); i++) { - if (!_window->_widgets[i]->_listenerObject) { + if (!_window->_widgets[i]->getListener()) { _window->_widgets[i]->setListener(this, _window->_widgets[i], 0); } } diff --git a/engines/wintermute/ad/ad_inventory_box.h b/engines/wintermute/ad/ad_inventory_box.h index f65bd8d8f0..4d576625b2 100644 --- a/engines/wintermute/ad/ad_inventory_box.h +++ b/engines/wintermute/ad/ad_inventory_box.h @@ -51,7 +51,7 @@ public: AdInventoryBox(BaseGame *inGame); virtual ~AdInventoryBox(); bool loadFile(const char *filename); - bool loadBuffer(byte *buffer, bool complete = true); + bool loadBuffer(char *buffer, bool complete = true); virtual bool saveAsText(BaseDynamicBuffer *buffer, int indent) override; private: bool _exclusive; diff --git a/engines/wintermute/ad/ad_item.cpp b/engines/wintermute/ad/ad_item.cpp index 7d05461169..f9741d1ed2 100644 --- a/engines/wintermute/ad/ad_item.cpp +++ b/engines/wintermute/ad/ad_item.cpp @@ -84,7 +84,7 @@ AdItem::~AdItem() { ////////////////////////////////////////////////////////////////////////// bool AdItem::loadFile(const char *filename) { - byte *buffer = BaseFileManager::getEngineInstance()->readWholeFile(filename); + char *buffer = (char *)BaseFileManager::getEngineInstance()->readWholeFile(filename); if (buffer == nullptr) { _gameRef->LOG(0, "AdItem::LoadFile failed for file '%s'", filename); return STATUS_FAILED; @@ -134,7 +134,7 @@ TOKEN_DEF(AMOUNT_STRING) TOKEN_DEF(AMOUNT) TOKEN_DEF_END ////////////////////////////////////////////////////////////////////////// -bool AdItem::loadBuffer(byte *buffer, bool complete) { +bool AdItem::loadBuffer(char *buffer, bool complete) { TOKEN_TABLE_START(commands) TOKEN_TABLE(ITEM) TOKEN_TABLE(TEMPLATE) @@ -164,12 +164,12 @@ bool AdItem::loadBuffer(byte *buffer, bool complete) { TOKEN_TABLE(AMOUNT) TOKEN_TABLE_END - byte *params; + char *params; int cmd = 2; BaseParser parser; if (complete) { - if (parser.getCommand((char **)&buffer, commands, (char **)¶ms) != TOKEN_ITEM) { + if (parser.getCommand(&buffer, commands, ¶ms) != TOKEN_ITEM) { _gameRef->LOG(0, "'ITEM' keyword expected."); return STATUS_FAILED; } @@ -177,31 +177,31 @@ bool AdItem::loadBuffer(byte *buffer, bool complete) { } int ar = 0, ag = 0, ab = 0, alpha = 255; - while (cmd > 0 && (cmd = parser.getCommand((char **)&buffer, commands, (char **)¶ms)) > 0) { + while (cmd > 0 && (cmd = parser.getCommand(&buffer, commands, ¶ms)) > 0) { switch (cmd) { case TOKEN_TEMPLATE: - if (DID_FAIL(loadFile((char *)params))) { + if (DID_FAIL(loadFile(params))) { cmd = PARSERR_GENERIC; } break; case TOKEN_NAME: - setName((char *)params); + setName(params); break; case TOKEN_FONT: - setFont((char *)params); + setFont(params); break; case TOKEN_CAPTION: - setCaption((char *)params); + setCaption(params); break; case TOKEN_IMAGE: case TOKEN_SPRITE: delete _sprite; _sprite = new BaseSprite(_gameRef, this); - if (!_sprite || DID_FAIL(_sprite->loadFile((char *)params, ((AdGame *)_gameRef)->_texItemLifeTime))) { + if (!_sprite || DID_FAIL(_sprite->loadFile(params, ((AdGame *)_gameRef)->_texItemLifeTime))) { delete _sprite; cmd = PARSERR_GENERIC; } @@ -211,32 +211,32 @@ bool AdItem::loadBuffer(byte *buffer, bool complete) { case TOKEN_SPRITE_HOVER: delete _spriteHover; _spriteHover = new BaseSprite(_gameRef, this); - if (!_spriteHover || DID_FAIL(_spriteHover->loadFile((char *)params, ((AdGame *)_gameRef)->_texItemLifeTime))) { + if (!_spriteHover || DID_FAIL(_spriteHover->loadFile(params, ((AdGame *)_gameRef)->_texItemLifeTime))) { delete _spriteHover; cmd = PARSERR_GENERIC; } break; case TOKEN_AMOUNT: - parser.scanStr((char *)params, "%d", &_amount); + parser.scanStr(params, "%d", &_amount); break; case TOKEN_DISPLAY_AMOUNT: - parser.scanStr((char *)params, "%b", &_displayAmount); + parser.scanStr(params, "%b", &_displayAmount); break; case TOKEN_AMOUNT_OFFSET_X: - parser.scanStr((char *)params, "%d", &_amountOffsetX); + parser.scanStr(params, "%d", &_amountOffsetX); break; case TOKEN_AMOUNT_OFFSET_Y: - parser.scanStr((char *)params, "%d", &_amountOffsetY); + parser.scanStr(params, "%d", &_amountOffsetY); break; case TOKEN_AMOUNT_ALIGN: - if (scumm_stricmp((char *)params, "left") == 0) { + if (scumm_stricmp(params, "left") == 0) { _amountAlign = TAL_LEFT; - } else if (scumm_stricmp((char *)params, "right") == 0) { + } else if (scumm_stricmp(params, "right") == 0) { _amountAlign = TAL_RIGHT; } else { _amountAlign = TAL_CENTER; @@ -244,12 +244,12 @@ bool AdItem::loadBuffer(byte *buffer, bool complete) { break; case TOKEN_AMOUNT_STRING: - BaseUtils::setString(&_amountString, (char *)params); + BaseUtils::setString(&_amountString, params); break; case TOKEN_TALK: { BaseSprite *spr = new BaseSprite(_gameRef, this); - if (!spr || DID_FAIL(spr->loadFile((char *)params, ((AdGame *)_gameRef)->_texTalkLifeTime))) { + if (!spr || DID_FAIL(spr->loadFile(params, ((AdGame *)_gameRef)->_texTalkLifeTime))) { cmd = PARSERR_GENERIC; } else { _talkSprites.add(spr); @@ -259,7 +259,7 @@ bool AdItem::loadBuffer(byte *buffer, bool complete) { case TOKEN_TALK_SPECIAL: { BaseSprite *spr = new BaseSprite(_gameRef, this); - if (!spr || DID_FAIL(spr->loadFile((char *)params, ((AdGame *)_gameRef)->_texTalkLifeTime))) { + if (!spr || DID_FAIL(spr->loadFile(params, ((AdGame *)_gameRef)->_texTalkLifeTime))) { cmd = PARSERR_GENERIC; } else { _talkSpritesEx.add(spr); @@ -270,7 +270,7 @@ bool AdItem::loadBuffer(byte *buffer, bool complete) { case TOKEN_CURSOR: delete _cursorNormal; _cursorNormal = new BaseSprite(_gameRef); - if (!_cursorNormal || DID_FAIL(_cursorNormal->loadFile((char *)params, ((AdGame *)_gameRef)->_texItemLifeTime))) { + if (!_cursorNormal || DID_FAIL(_cursorNormal->loadFile(params, ((AdGame *)_gameRef)->_texItemLifeTime))) { delete _cursorNormal; _cursorNormal = nullptr; cmd = PARSERR_GENERIC; @@ -280,7 +280,7 @@ bool AdItem::loadBuffer(byte *buffer, bool complete) { case TOKEN_CURSOR_HOVER: delete _cursorHover; _cursorHover = new BaseSprite(_gameRef); - if (!_cursorHover || DID_FAIL(_cursorHover->loadFile((char *)params, ((AdGame *)_gameRef)->_texItemLifeTime))) { + if (!_cursorHover || DID_FAIL(_cursorHover->loadFile(params, ((AdGame *)_gameRef)->_texItemLifeTime))) { delete _cursorHover; _cursorHover = nullptr; cmd = PARSERR_GENERIC; @@ -288,11 +288,11 @@ bool AdItem::loadBuffer(byte *buffer, bool complete) { break; case TOKEN_CURSOR_COMBINED: - parser.scanStr((char *)params, "%b", &_cursorCombined); + parser.scanStr(params, "%b", &_cursorCombined); break; case TOKEN_SCRIPT: - addScript((char *)params); + addScript(params); break; case TOKEN_PROPERTY: @@ -300,11 +300,11 @@ bool AdItem::loadBuffer(byte *buffer, bool complete) { break; case TOKEN_ALPHA_COLOR: - parser.scanStr((char *)params, "%d,%d,%d", &ar, &ag, &ab); + parser.scanStr(params, "%d,%d,%d", &ar, &ag, &ab); break; case TOKEN_ALPHA: - parser.scanStr((char *)params, "%d", &alpha); + parser.scanStr(params, "%d", &alpha); break; case TOKEN_EDITOR_PROPERTY: diff --git a/engines/wintermute/ad/ad_item.h b/engines/wintermute/ad/ad_item.h index dd7039db43..935ea5d73d 100644 --- a/engines/wintermute/ad/ad_item.h +++ b/engines/wintermute/ad/ad_item.h @@ -35,6 +35,8 @@ namespace Wintermute { class AdItem : public AdTalkHolder { + using Wintermute::AdObject::display; + public: bool update(); DECLARE_PERSISTENT(AdItem, AdTalkHolder) @@ -48,7 +50,7 @@ public: AdItem(BaseGame *inGame); virtual ~AdItem(); bool loadFile(const char *filename); - bool loadBuffer(byte *buffer, bool complete = true); + bool loadBuffer(char *buffer, bool complete = true); // scripting interface virtual ScValue *scGetProperty(const Common::String &name) override; diff --git a/engines/wintermute/ad/ad_layer.cpp b/engines/wintermute/ad/ad_layer.cpp index c833b59163..752700d0d4 100644 --- a/engines/wintermute/ad/ad_layer.cpp +++ b/engines/wintermute/ad/ad_layer.cpp @@ -62,7 +62,7 @@ AdLayer::~AdLayer() { ////////////////////////////////////////////////////////////////////////// bool AdLayer::loadFile(const char *filename) { - byte *buffer = BaseFileManager::getEngineInstance()->readWholeFile(filename); + char *buffer = (char *)BaseFileManager::getEngineInstance()->readWholeFile(filename); if (buffer == nullptr) { _gameRef->LOG(0, "AdLayer::LoadFile failed for file '%s'", filename); return STATUS_FAILED; @@ -100,7 +100,7 @@ TOKEN_DEF(CLOSE_UP) TOKEN_DEF(EDITOR_PROPERTY) TOKEN_DEF_END ////////////////////////////////////////////////////////////////////////// -bool AdLayer::loadBuffer(byte *buffer, bool complete) { +bool AdLayer::loadBuffer(char *buffer, bool complete) { TOKEN_TABLE_START(commands) TOKEN_TABLE(LAYER) TOKEN_TABLE(TEMPLATE) @@ -119,52 +119,52 @@ bool AdLayer::loadBuffer(byte *buffer, bool complete) { TOKEN_TABLE(EDITOR_PROPERTY) TOKEN_TABLE_END - byte *params; + char *params; int cmd; BaseParser parser; if (complete) { - if (parser.getCommand((char **)&buffer, commands, (char **)¶ms) != TOKEN_LAYER) { + if (parser.getCommand(&buffer, commands, ¶ms) != TOKEN_LAYER) { _gameRef->LOG(0, "'LAYER' keyword expected."); return STATUS_FAILED; } buffer = params; } - while ((cmd = parser.getCommand((char **)&buffer, commands, (char **)¶ms)) > 0) { + while ((cmd = parser.getCommand(&buffer, commands, ¶ms)) > 0) { switch (cmd) { case TOKEN_TEMPLATE: - if (DID_FAIL(loadFile((char *)params))) { + if (DID_FAIL(loadFile(params))) { cmd = PARSERR_GENERIC; } break; case TOKEN_NAME: - setName((char *)params); + setName(params); break; case TOKEN_CAPTION: - setCaption((char *)params); + setCaption(params); break; case TOKEN_MAIN: - parser.scanStr((char *)params, "%b", &_main); + parser.scanStr(params, "%b", &_main); break; case TOKEN_CLOSE_UP: - parser.scanStr((char *)params, "%b", &_closeUp); + parser.scanStr(params, "%b", &_closeUp); break; case TOKEN_WIDTH: - parser.scanStr((char *)params, "%d", &_width); + parser.scanStr(params, "%d", &_width); break; case TOKEN_HEIGHT: - parser.scanStr((char *)params, "%d", &_height); + parser.scanStr(params, "%d", &_height); break; case TOKEN_ACTIVE: - parser.scanStr((char *)params, "%b", &_active); + parser.scanStr(params, "%b", &_active); break; case TOKEN_REGION: { @@ -203,11 +203,11 @@ bool AdLayer::loadBuffer(byte *buffer, bool complete) { break; case TOKEN_EDITOR_SELECTED: - parser.scanStr((char *)params, "%b", &_editorSelected); + parser.scanStr(params, "%b", &_editorSelected); break; case TOKEN_SCRIPT: - addScript((char *)params); + addScript(params); break; case TOKEN_PROPERTY: diff --git a/engines/wintermute/ad/ad_layer.h b/engines/wintermute/ad/ad_layer.h index b260b919fd..af7c3a364c 100644 --- a/engines/wintermute/ad/ad_layer.h +++ b/engines/wintermute/ad/ad_layer.h @@ -43,7 +43,7 @@ public: virtual ~AdLayer(); BaseArray<AdSceneNode *> _nodes; bool loadFile(const char *filename); - bool loadBuffer(byte *buffer, bool complete = true); + bool loadBuffer(char *buffer, bool complete = true); virtual bool saveAsText(BaseDynamicBuffer *buffer, int indent) override; // scripting interface diff --git a/engines/wintermute/ad/ad_region.cpp b/engines/wintermute/ad/ad_region.cpp index bc9ac903c6..1c0cf41e86 100644 --- a/engines/wintermute/ad/ad_region.cpp +++ b/engines/wintermute/ad/ad_region.cpp @@ -69,7 +69,7 @@ bool AdRegion::hasDecoration() const { ////////////////////////////////////////////////////////////////////////// bool AdRegion::loadFile(const char *filename) { - byte *buffer = BaseFileManager::getEngineInstance()->readWholeFile(filename); + char *buffer = (char *)BaseFileManager::getEngineInstance()->readWholeFile(filename); if (buffer == nullptr) { _gameRef->LOG(0, "AdRegion::LoadFile failed for file '%s'", filename); return STATUS_FAILED; @@ -110,7 +110,7 @@ TOKEN_DEF(PROPERTY) TOKEN_DEF(EDITOR_PROPERTY) TOKEN_DEF_END ////////////////////////////////////////////////////////////////////////// -bool AdRegion::loadBuffer(byte *buffer, bool complete) { +bool AdRegion::loadBuffer(char *buffer, bool complete) { TOKEN_TABLE_START(commands) TOKEN_TABLE(REGION) TOKEN_TABLE(TEMPLATE) @@ -131,12 +131,12 @@ bool AdRegion::loadBuffer(byte *buffer, bool complete) { TOKEN_TABLE(EDITOR_PROPERTY) TOKEN_TABLE_END - byte *params; + char *params; int cmd; BaseParser parser; if (complete) { - if (parser.getCommand((char **)&buffer, commands, (char **)¶ms) != TOKEN_REGION) { + if (parser.getCommand(&buffer, commands, ¶ms) != TOKEN_REGION) { _gameRef->LOG(0, "'REGION' keyword expected."); return STATUS_FAILED; } @@ -150,67 +150,67 @@ bool AdRegion::loadBuffer(byte *buffer, bool complete) { int ar = 255, ag = 255, ab = 255, alpha = 255; - while ((cmd = parser.getCommand((char **)&buffer, commands, (char **)¶ms)) > 0) { + while ((cmd = parser.getCommand(&buffer, commands, ¶ms)) > 0) { switch (cmd) { case TOKEN_TEMPLATE: - if (DID_FAIL(loadFile((char *)params))) { + if (DID_FAIL(loadFile(params))) { cmd = PARSERR_GENERIC; } break; case TOKEN_NAME: - setName((char *)params); + setName(params); break; case TOKEN_CAPTION: - setCaption((char *)params); + setCaption(params); break; case TOKEN_ACTIVE: - parser.scanStr((char *)params, "%b", &_active); + parser.scanStr(params, "%b", &_active); break; case TOKEN_BLOCKED: - parser.scanStr((char *)params, "%b", &_blocked); + parser.scanStr(params, "%b", &_blocked); break; case TOKEN_DECORATION: - parser.scanStr((char *)params, "%b", &_decoration); + parser.scanStr(params, "%b", &_decoration); break; case TOKEN_ZOOM: case TOKEN_SCALE: { int j; - parser.scanStr((char *)params, "%d", &j); + parser.scanStr(params, "%d", &j); _zoom = (float)j; } break; case TOKEN_POINT: { int x, y; - parser.scanStr((char *)params, "%d,%d", &x, &y); + parser.scanStr(params, "%d,%d", &x, &y); _points.add(new BasePoint(x, y)); } break; case TOKEN_ALPHA_COLOR: - parser.scanStr((char *)params, "%d,%d,%d", &ar, &ag, &ab); + parser.scanStr(params, "%d,%d,%d", &ar, &ag, &ab); break; case TOKEN_ALPHA: - parser.scanStr((char *)params, "%d", &alpha); + parser.scanStr(params, "%d", &alpha); break; case TOKEN_EDITOR_SELECTED: - parser.scanStr((char *)params, "%b", &_editorSelected); + parser.scanStr(params, "%b", &_editorSelected); break; case TOKEN_EDITOR_SELECTED_POINT: - parser.scanStr((char *)params, "%d", &_editorSelectedPoint); + parser.scanStr(params, "%d", &_editorSelectedPoint); break; case TOKEN_SCRIPT: - addScript((char *)params); + addScript(params); break; case TOKEN_PROPERTY: diff --git a/engines/wintermute/ad/ad_region.h b/engines/wintermute/ad/ad_region.h index 637c742c9c..f3674dcbfb 100644 --- a/engines/wintermute/ad/ad_region.h +++ b/engines/wintermute/ad/ad_region.h @@ -40,7 +40,7 @@ public: AdRegion(BaseGame *inGame); virtual ~AdRegion(); bool loadFile(const char *filename); - bool loadBuffer(byte *buffer, bool complete = true); + bool loadBuffer(char *buffer, bool complete = true); virtual bool saveAsText(BaseDynamicBuffer *buffer, int indent) override; bool hasDecoration() const; diff --git a/engines/wintermute/ad/ad_response_box.cpp b/engines/wintermute/ad/ad_response_box.cpp index 9d7c17ac74..2a5adb9234 100644 --- a/engines/wintermute/ad/ad_response_box.cpp +++ b/engines/wintermute/ad/ad_response_box.cpp @@ -121,12 +121,12 @@ void AdResponseBox::clearButtons() { ////////////////////////////////////////////////////////////////////////// bool AdResponseBox::invalidateButtons() { for (uint32 i = 0; i < _respButtons.size(); i++) { - _respButtons[i]->_image = nullptr; - _respButtons[i]->_cursor = nullptr; - _respButtons[i]->_font = nullptr; - _respButtons[i]->_fontHover = nullptr; - _respButtons[i]->_fontPress = nullptr; + _respButtons[i]->setImage(nullptr); + _respButtons[i]->setFont(nullptr); _respButtons[i]->setText(""); + _respButtons[i]->_cursor = nullptr; + _respButtons[i]->setFontHover(nullptr); + _respButtons[i]->setFontPress(nullptr); } return STATUS_OK; } @@ -141,16 +141,17 @@ bool AdResponseBox::createButtons() { UIButton *btn = new UIButton(_gameRef); if (btn) { btn->_parent = _window; - btn->_sharedFonts = btn->_sharedImages = true; + btn->setSharedFonts(true); + btn->setSharedImages(true); btn->_sharedCursors = true; // iconic if (_responses[i]->getIcon()) { - btn->_image = _responses[i]->getIcon(); + btn->setImage(_responses[i]->getIcon()); if (_responses[i]->getIconHover()) { - btn->_imageHover = _responses[i]->getIconHover(); + btn->setImageHover(_responses[i]->getIconHover()); } if (_responses[i]->getIconPressed()) { - btn->_imagePress = _responses[i]->getIconPressed(); + btn->setImagePress(_responses[i]->getIconPressed()); } btn->setCaption(_responses[i]->getText()); @@ -163,23 +164,30 @@ bool AdResponseBox::createButtons() { // textual else { btn->setText(_responses[i]->getText()); - btn->_font = (_font == nullptr) ? _gameRef->getSystemFont() : _font; - btn->_fontHover = (_fontHover == nullptr) ? _gameRef->getSystemFont() : _fontHover; - btn->_fontPress = btn->_fontHover; - btn->_align = _align; + if (_font == nullptr) { + btn->setFont(_gameRef->getSystemFont()); + } else { + btn->setFont(_font); + } + btn->setFontHover((_fontHover == nullptr) ? _gameRef->getSystemFont() : _fontHover); + btn->setFontPress(btn->getFontHover()); + btn->setTextAlign(_align); if (_gameRef->_touchInterface) { - btn->_fontHover = btn->_font; + btn->setFontHover(btn->getFont()); } if (_responses[i]->getFont()) { - btn->_font = _responses[i]->getFont(); + btn->setFont(_responses[i]->getFont()); } - btn->_width = _responseArea.right - _responseArea.left; - if (btn->_width <= 0) { - btn->_width = _gameRef->_renderer->getWidth(); + int width = _responseArea.right - _responseArea.left; + + if (width <= 0) { + btn->setWidth(_gameRef->_renderer->getWidth()); + } else { + btn->setWidth(width); } } btn->setName("response"); @@ -187,17 +195,17 @@ bool AdResponseBox::createButtons() { // make the responses touchable if (_gameRef->_touchInterface) { - btn->_height = MAX<int32>(btn->_height, 50); + btn->setHeight(MAX<int32>(btn->getHeight(), 50)); } //btn->SetListener(this, btn, _responses[i]->_iD); btn->setListener(this, btn, i); - btn->_visible = false; + btn->setVisible(false); _respButtons.add(btn); - if (_responseArea.bottom - _responseArea.top < btn->_height) { + if (_responseArea.bottom - _responseArea.top < btn->getHeight()) { _gameRef->LOG(0, "Warning: Response '%s' is too high to be displayed within response box. Correcting.", _responses[i]->getText()); - _responseArea.bottom += (btn->_height - (_responseArea.bottom - _responseArea.top)); + _responseArea.bottom += (btn->getHeight() - (_responseArea.bottom - _responseArea.top)); } } } @@ -209,7 +217,7 @@ bool AdResponseBox::createButtons() { ////////////////////////////////////////////////////////////////////////// bool AdResponseBox::loadFile(const char *filename) { - byte *buffer = BaseFileManager::getEngineInstance()->readWholeFile(filename); + char *buffer = (char *)BaseFileManager::getEngineInstance()->readWholeFile(filename); if (buffer == nullptr) { _gameRef->LOG(0, "AdResponseBox::LoadFile failed for file '%s'", filename); return STATUS_FAILED; @@ -245,7 +253,7 @@ TOKEN_DEF(VERTICAL_ALIGN) TOKEN_DEF(EDITOR_PROPERTY) TOKEN_DEF_END ////////////////////////////////////////////////////////////////////////// -bool AdResponseBox::loadBuffer(byte *buffer, bool complete) { +bool AdResponseBox::loadBuffer(char *buffer, bool complete) { TOKEN_TABLE_START(commands) TOKEN_TABLE(RESPONSE_BOX) TOKEN_TABLE(TEMPLATE) @@ -262,22 +270,22 @@ bool AdResponseBox::loadBuffer(byte *buffer, bool complete) { TOKEN_TABLE_END - byte *params; + char *params; int cmd; BaseParser parser; if (complete) { - if (parser.getCommand((char **)&buffer, commands, (char **)¶ms) != TOKEN_RESPONSE_BOX) { + if (parser.getCommand(&buffer, commands, ¶ms) != TOKEN_RESPONSE_BOX) { _gameRef->LOG(0, "'RESPONSE_BOX' keyword expected."); return STATUS_FAILED; } buffer = params; } - while ((cmd = parser.getCommand((char **)&buffer, commands, (char **)¶ms)) > 0) { + while ((cmd = parser.getCommand(&buffer, commands, ¶ms)) > 0) { switch (cmd) { case TOKEN_TEMPLATE: - if (DID_FAIL(loadFile((char *)params))) { + if (DID_FAIL(loadFile(params))) { cmd = PARSERR_GENERIC; } break; @@ -298,7 +306,7 @@ bool AdResponseBox::loadBuffer(byte *buffer, bool complete) { if (_font) { _gameRef->_fontStorage->removeFont(_font); } - _font = _gameRef->_fontStorage->addFont((char *)params); + _font = _gameRef->_fontStorage->addFont(params); if (!_font) { cmd = PARSERR_GENERIC; } @@ -308,24 +316,24 @@ bool AdResponseBox::loadBuffer(byte *buffer, bool complete) { if (_fontHover) { _gameRef->_fontStorage->removeFont(_fontHover); } - _fontHover = _gameRef->_fontStorage->addFont((char *)params); + _fontHover = _gameRef->_fontStorage->addFont(params); if (!_fontHover) { cmd = PARSERR_GENERIC; } break; case TOKEN_AREA: - parser.scanStr((char *)params, "%d,%d,%d,%d", &_responseArea.left, &_responseArea.top, &_responseArea.right, &_responseArea.bottom); + parser.scanStr(params, "%d,%d,%d,%d", &_responseArea.left, &_responseArea.top, &_responseArea.right, &_responseArea.bottom); break; case TOKEN_HORIZONTAL: - parser.scanStr((char *)params, "%b", &_horizontal); + parser.scanStr(params, "%b", &_horizontal); break; case TOKEN_TEXT_ALIGN: - if (scumm_stricmp((char *)params, "center") == 0) { + if (scumm_stricmp(params, "center") == 0) { _align = TAL_CENTER; - } else if (scumm_stricmp((char *)params, "right") == 0) { + } else if (scumm_stricmp(params, "right") == 0) { _align = TAL_RIGHT; } else { _align = TAL_LEFT; @@ -333,9 +341,9 @@ bool AdResponseBox::loadBuffer(byte *buffer, bool complete) { break; case TOKEN_VERTICAL_ALIGN: - if (scumm_stricmp((char *)params, "top") == 0) { + if (scumm_stricmp(params, "top") == 0) { _verticalAlign = VAL_TOP; - } else if (scumm_stricmp((char *)params, "center") == 0) { + } else if (scumm_stricmp(params, "center") == 0) { _verticalAlign = VAL_CENTER; } else { _verticalAlign = VAL_BOTTOM; @@ -343,7 +351,7 @@ bool AdResponseBox::loadBuffer(byte *buffer, bool complete) { break; case TOKEN_SPACING: - parser.scanStr((char *)params, "%d", &_spacing); + parser.scanStr(params, "%d", &_spacing); break; case TOKEN_EDITOR_PROPERTY: @@ -353,7 +361,7 @@ bool AdResponseBox::loadBuffer(byte *buffer, bool complete) { case TOKEN_CURSOR: delete _cursor; _cursor = new BaseSprite(_gameRef); - if (!_cursor || DID_FAIL(_cursor->loadFile((char *)params))) { + if (!_cursor || DID_FAIL(_cursor->loadFile(params))) { delete _cursor; _cursor = nullptr; cmd = PARSERR_GENERIC; @@ -368,7 +376,7 @@ bool AdResponseBox::loadBuffer(byte *buffer, bool complete) { if (_window) { for (uint32 i = 0; i < _window->_widgets.size(); i++) { - if (!_window->_widgets[i]->_listenerObject) { + if (!_window->_widgets[i]->getListener()) { _window->_widgets[i]->setListener(this, _window->_widgets[i], 0); } } @@ -461,7 +469,7 @@ bool AdResponseBox::display() { if (!_horizontal) { int totalHeight = 0; for (i = 0; i < _respButtons.size(); i++) { - totalHeight += (_respButtons[i]->_height + _spacing); + totalHeight += (_respButtons[i]->getHeight() + _spacing); } totalHeight -= _spacing; @@ -487,22 +495,22 @@ bool AdResponseBox::display() { // prepare response buttons bool scrollNeeded = false; for (i = _scrollOffset; i < _respButtons.size(); i++) { - if ((_horizontal && xxx + _respButtons[i]->_width > rect.right) - || (!_horizontal && yyy + _respButtons[i]->_height > rect.bottom)) { + if ((_horizontal && xxx + _respButtons[i]->getWidth() > rect.right) + || (!_horizontal && yyy + _respButtons[i]->getHeight() > rect.bottom)) { scrollNeeded = true; - _respButtons[i]->_visible = false; + _respButtons[i]->setVisible(false); break; } - _respButtons[i]->_visible = true; + _respButtons[i]->setVisible(true); _respButtons[i]->_posX = xxx; _respButtons[i]->_posY = yyy; if (_horizontal) { - xxx += (_respButtons[i]->_width + _spacing); + xxx += (_respButtons[i]->getWidth() + _spacing); } else { - yyy += (_respButtons[i]->_height + _spacing); + yyy += (_respButtons[i]->getHeight() + _spacing); } } @@ -515,8 +523,8 @@ bool AdResponseBox::display() { // go exclusive if (_shieldWindow) { _shieldWindow->_posX = _shieldWindow->_posY = 0; - _shieldWindow->_width = _gameRef->_renderer->getWidth(); - _shieldWindow->_height = _gameRef->_renderer->getHeight(); + _shieldWindow->setWidth(_gameRef->_renderer->getWidth()); + _shieldWindow->setHeight(_gameRef->_renderer->getHeight()); _shieldWindow->display(); } diff --git a/engines/wintermute/ad/ad_response_box.h b/engines/wintermute/ad/ad_response_box.h index 7598e8b569..9469bfda43 100644 --- a/engines/wintermute/ad/ad_response_box.h +++ b/engines/wintermute/ad/ad_response_box.h @@ -72,7 +72,7 @@ public: virtual ~AdResponseBox(); bool loadFile(const char *filename); - bool loadBuffer(byte *buffer, bool complete = true); + bool loadBuffer(char *buffer, bool complete = true); virtual bool saveAsText(BaseDynamicBuffer *buffer, int indent) override; UIWindow *getResponseWindow(); diff --git a/engines/wintermute/ad/ad_rot_level.cpp b/engines/wintermute/ad/ad_rot_level.cpp index d925b0d57a..b5bdc8ebe9 100644 --- a/engines/wintermute/ad/ad_rot_level.cpp +++ b/engines/wintermute/ad/ad_rot_level.cpp @@ -53,7 +53,7 @@ AdRotLevel::~AdRotLevel() { ////////////////////////////////////////////////////////////////////////// bool AdRotLevel::loadFile(const char *filename) { - byte *buffer = BaseFileManager::getEngineInstance()->readWholeFile(filename); + char *buffer = (char *)BaseFileManager::getEngineInstance()->readWholeFile(filename); if (buffer == nullptr) { _gameRef->LOG(0, "AdRotLevel::LoadFile failed for file '%s'", filename); return STATUS_FAILED; @@ -82,7 +82,7 @@ TOKEN_DEF(ROTATION) TOKEN_DEF(EDITOR_PROPERTY) TOKEN_DEF_END ////////////////////////////////////////////////////////////////////////// -bool AdRotLevel::loadBuffer(byte *buffer, bool complete) { +bool AdRotLevel::loadBuffer(char *buffer, bool complete) { TOKEN_TABLE_START(commands) TOKEN_TABLE(ROTATION_LEVEL) TOKEN_TABLE(TEMPLATE) @@ -91,33 +91,33 @@ bool AdRotLevel::loadBuffer(byte *buffer, bool complete) { TOKEN_TABLE(EDITOR_PROPERTY) TOKEN_TABLE_END - byte *params; + char *params; int cmd; BaseParser parser; if (complete) { - if (parser.getCommand((char **)&buffer, commands, (char **)¶ms) != TOKEN_ROTATION_LEVEL) { + if (parser.getCommand(&buffer, commands, ¶ms) != TOKEN_ROTATION_LEVEL) { _gameRef->LOG(0, "'ROTATION_LEVEL' keyword expected."); return STATUS_FAILED; } buffer = params; } - while ((cmd = parser.getCommand((char **)&buffer, commands, (char **)¶ms)) > 0) { + while ((cmd = parser.getCommand(&buffer, commands, ¶ms)) > 0) { switch (cmd) { case TOKEN_TEMPLATE: - if (DID_FAIL(loadFile((char *)params))) { + if (DID_FAIL(loadFile(params))) { cmd = PARSERR_GENERIC; } break; case TOKEN_X: - parser.scanStr((char *)params, "%d", &_posX); + parser.scanStr(params, "%d", &_posX); break; case TOKEN_ROTATION: { int i; - parser.scanStr((char *)params, "%d", &i); + parser.scanStr(params, "%d", &i); _rotation = (float)i; } break; diff --git a/engines/wintermute/ad/ad_rot_level.h b/engines/wintermute/ad/ad_rot_level.h index fe2d1691cd..47c621845a 100644 --- a/engines/wintermute/ad/ad_rot_level.h +++ b/engines/wintermute/ad/ad_rot_level.h @@ -42,7 +42,7 @@ public: float getRotation() const { return _rotation; } virtual bool saveAsText(BaseDynamicBuffer *buffer, int indent) override; bool loadFile(const char *filename); - bool loadBuffer(byte *buffer, bool complete = true); + bool loadBuffer(char *buffer, bool complete = true); }; } // End of namespace Wintermute diff --git a/engines/wintermute/ad/ad_scale_level.cpp b/engines/wintermute/ad/ad_scale_level.cpp index 59e6d57787..aa7f6f89cf 100644 --- a/engines/wintermute/ad/ad_scale_level.cpp +++ b/engines/wintermute/ad/ad_scale_level.cpp @@ -54,7 +54,7 @@ float AdScaleLevel::getScale() const { ////////////////////////////////////////////////////////////////////////// bool AdScaleLevel::loadFile(const char *filename) { - byte *buffer = BaseFileManager::getEngineInstance()->readWholeFile(filename); + char *buffer = (char *)BaseFileManager::getEngineInstance()->readWholeFile(filename); if (buffer == nullptr) { _gameRef->LOG(0, "AdScaleLevel::LoadFile failed for file '%s'", filename); return STATUS_FAILED; @@ -83,7 +83,7 @@ TOKEN_DEF(SCALE) TOKEN_DEF(EDITOR_PROPERTY) TOKEN_DEF_END ////////////////////////////////////////////////////////////////////////// -bool AdScaleLevel::loadBuffer(byte *buffer, bool complete) { +bool AdScaleLevel::loadBuffer(char *buffer, bool complete) { TOKEN_TABLE_START(commands) TOKEN_TABLE(SCALE_LEVEL) TOKEN_TABLE(TEMPLATE) @@ -92,33 +92,33 @@ bool AdScaleLevel::loadBuffer(byte *buffer, bool complete) { TOKEN_TABLE(EDITOR_PROPERTY) TOKEN_TABLE_END - byte *params; + char *params; int cmd; BaseParser parser; if (complete) { - if (parser.getCommand((char **)&buffer, commands, (char **)¶ms) != TOKEN_SCALE_LEVEL) { + if (parser.getCommand(&buffer, commands, ¶ms) != TOKEN_SCALE_LEVEL) { _gameRef->LOG(0, "'SCALE_LEVEL' keyword expected."); return STATUS_FAILED; } buffer = params; } - while ((cmd = parser.getCommand((char **)&buffer, commands, (char **)¶ms)) > 0) { + while ((cmd = parser.getCommand(&buffer, commands, ¶ms)) > 0) { switch (cmd) { case TOKEN_TEMPLATE: - if (DID_FAIL(loadFile((char *)params))) { + if (DID_FAIL(loadFile(params))) { cmd = PARSERR_GENERIC; } break; case TOKEN_Y: - parser.scanStr((char *)params, "%d", &_posY); + parser.scanStr(params, "%d", &_posY); break; case TOKEN_SCALE: { int i; - parser.scanStr((char *)params, "%d", &i); + parser.scanStr(params, "%d", &i); _scale = (float)i; } break; diff --git a/engines/wintermute/ad/ad_scale_level.h b/engines/wintermute/ad/ad_scale_level.h index b2dd7aa91f..768e79bbf7 100644 --- a/engines/wintermute/ad/ad_scale_level.h +++ b/engines/wintermute/ad/ad_scale_level.h @@ -41,7 +41,7 @@ public: virtual ~AdScaleLevel(); virtual bool saveAsText(BaseDynamicBuffer *buffer, int indent) override; bool loadFile(const char *filename); - bool loadBuffer(byte *buffer, bool complete = true); + bool loadBuffer(char *buffer, bool complete = true); float getScale() const; private: float _scale; diff --git a/engines/wintermute/ad/ad_scene.cpp b/engines/wintermute/ad/ad_scene.cpp index 668b39853b..bc8d9e96d2 100644 --- a/engines/wintermute/ad/ad_scene.cpp +++ b/engines/wintermute/ad/ad_scene.cpp @@ -538,7 +538,7 @@ bool AdScene::initLoop() { ////////////////////////////////////////////////////////////////////////// bool AdScene::loadFile(const char *filename) { - byte *buffer = BaseFileManager::getEngineInstance()->readWholeFile(filename); + char *buffer = (char *)BaseFileManager::getEngineInstance()->readWholeFile(filename); if (buffer == nullptr) { _gameRef->LOG(0, "AdScene::LoadFile failed for file '%s'", filename); return STATUS_FAILED; @@ -600,7 +600,7 @@ TOKEN_DEF(PERSISTENT_STATE) TOKEN_DEF(EDITOR_PROPERTY) TOKEN_DEF_END ////////////////////////////////////////////////////////////////////////// -bool AdScene::loadBuffer(byte *buffer, bool complete) { +bool AdScene::loadBuffer(char *buffer, bool complete) { TOKEN_TABLE_START(commands) TOKEN_TABLE(SCENE) TOKEN_TABLE(TEMPLATE) @@ -643,12 +643,12 @@ bool AdScene::loadBuffer(byte *buffer, bool complete) { cleanup(); - byte *params; + char *params; int cmd; BaseParser parser; if (complete) { - if (parser.getCommand((char **)&buffer, commands, (char **)¶ms) != TOKEN_SCENE) { + if (parser.getCommand(&buffer, commands, ¶ms) != TOKEN_SCENE) { _gameRef->LOG(0, "'SCENE' keyword expected."); return STATUS_FAILED; } @@ -659,20 +659,20 @@ bool AdScene::loadBuffer(byte *buffer, bool complete) { char camera[MAX_PATH_LENGTH] = ""; /* float waypointHeight = -1.0f; */ - while ((cmd = parser.getCommand((char **)&buffer, commands, (char **)¶ms)) > 0) { + while ((cmd = parser.getCommand(&buffer, commands, ¶ms)) > 0) { switch (cmd) { case TOKEN_TEMPLATE: - if (DID_FAIL(loadFile((char *)params))) { + if (DID_FAIL(loadFile(params))) { cmd = PARSERR_GENERIC; } break; case TOKEN_NAME: - setName((char *)params); + setName(params); break; case TOKEN_CAPTION: - setCaption((char *)params); + setCaption(params); break; case TOKEN_LAYER: { @@ -747,7 +747,7 @@ bool AdScene::loadBuffer(byte *buffer, bool complete) { case TOKEN_CURSOR: delete _cursor; _cursor = new BaseSprite(_gameRef); - if (!_cursor || DID_FAIL(_cursor->loadFile((char *)params))) { + if (!_cursor || DID_FAIL(_cursor->loadFile(params))) { delete _cursor; _cursor = nullptr; cmd = PARSERR_GENERIC; @@ -755,99 +755,99 @@ bool AdScene::loadBuffer(byte *buffer, bool complete) { break; case TOKEN_CAMERA: - Common::strlcpy(camera, (char *)params, MAX_PATH_LENGTH); + Common::strlcpy(camera, params, MAX_PATH_LENGTH); break; case TOKEN_EDITOR_MARGIN_H: - parser.scanStr((char *)params, "%d", &_editorMarginH); + parser.scanStr(params, "%d", &_editorMarginH); break; case TOKEN_EDITOR_MARGIN_V: - parser.scanStr((char *)params, "%d", &_editorMarginV); + parser.scanStr(params, "%d", &_editorMarginV); break; case TOKEN_EDITOR_COLOR_FRAME: - parser.scanStr((char *)params, "%d,%d,%d,%d", &ar, &ag, &ab, &aa); + parser.scanStr(params, "%d,%d,%d,%d", &ar, &ag, &ab, &aa); _editorColFrame = BYTETORGBA(ar, ag, ab, aa); break; case TOKEN_EDITOR_COLOR_ENTITY: - parser.scanStr((char *)params, "%d,%d,%d,%d", &ar, &ag, &ab, &aa); + parser.scanStr(params, "%d,%d,%d,%d", &ar, &ag, &ab, &aa); _editorColEntity = BYTETORGBA(ar, ag, ab, aa); break; case TOKEN_EDITOR_COLOR_ENTITY_SEL: - parser.scanStr((char *)params, "%d,%d,%d,%d", &ar, &ag, &ab, &aa); + parser.scanStr(params, "%d,%d,%d,%d", &ar, &ag, &ab, &aa); _editorColEntitySel = BYTETORGBA(ar, ag, ab, aa); break; case TOKEN_EDITOR_COLOR_REGION_SEL: - parser.scanStr((char *)params, "%d,%d,%d,%d", &ar, &ag, &ab, &aa); + parser.scanStr(params, "%d,%d,%d,%d", &ar, &ag, &ab, &aa); _editorColRegionSel = BYTETORGBA(ar, ag, ab, aa); break; case TOKEN_EDITOR_COLOR_DECORATION_SEL: - parser.scanStr((char *)params, "%d,%d,%d,%d", &ar, &ag, &ab, &aa); + parser.scanStr(params, "%d,%d,%d,%d", &ar, &ag, &ab, &aa); _editorColDecorSel = BYTETORGBA(ar, ag, ab, aa); break; case TOKEN_EDITOR_COLOR_BLOCKED_SEL: - parser.scanStr((char *)params, "%d,%d,%d,%d", &ar, &ag, &ab, &aa); + parser.scanStr(params, "%d,%d,%d,%d", &ar, &ag, &ab, &aa); _editorColBlockedSel = BYTETORGBA(ar, ag, ab, aa); break; case TOKEN_EDITOR_COLOR_WAYPOINTS_SEL: - parser.scanStr((char *)params, "%d,%d,%d,%d", &ar, &ag, &ab, &aa); + parser.scanStr(params, "%d,%d,%d,%d", &ar, &ag, &ab, &aa); _editorColWaypointsSel = BYTETORGBA(ar, ag, ab, aa); break; case TOKEN_EDITOR_COLOR_REGION: - parser.scanStr((char *)params, "%d,%d,%d,%d", &ar, &ag, &ab, &aa); + parser.scanStr(params, "%d,%d,%d,%d", &ar, &ag, &ab, &aa); _editorColRegion = BYTETORGBA(ar, ag, ab, aa); break; case TOKEN_EDITOR_COLOR_DECORATION: - parser.scanStr((char *)params, "%d,%d,%d,%d", &ar, &ag, &ab, &aa); + parser.scanStr(params, "%d,%d,%d,%d", &ar, &ag, &ab, &aa); _editorColDecor = BYTETORGBA(ar, ag, ab, aa); break; case TOKEN_EDITOR_COLOR_BLOCKED: - parser.scanStr((char *)params, "%d,%d,%d,%d", &ar, &ag, &ab, &aa); + parser.scanStr(params, "%d,%d,%d,%d", &ar, &ag, &ab, &aa); _editorColBlocked = BYTETORGBA(ar, ag, ab, aa); break; case TOKEN_EDITOR_COLOR_WAYPOINTS: - parser.scanStr((char *)params, "%d,%d,%d,%d", &ar, &ag, &ab, &aa); + parser.scanStr(params, "%d,%d,%d,%d", &ar, &ag, &ab, &aa); _editorColWaypoints = BYTETORGBA(ar, ag, ab, aa); break; case TOKEN_EDITOR_COLOR_SCALE: - parser.scanStr((char *)params, "%d,%d,%d,%d", &ar, &ag, &ab, &aa); + parser.scanStr(params, "%d,%d,%d,%d", &ar, &ag, &ab, &aa); _editorColScale = BYTETORGBA(ar, ag, ab, aa); break; case TOKEN_EDITOR_SHOW_REGIONS: - parser.scanStr((char *)params, "%b", &_editorShowRegions); + parser.scanStr(params, "%b", &_editorShowRegions); break; case TOKEN_EDITOR_SHOW_BLOCKED: - parser.scanStr((char *)params, "%b", &_editorShowBlocked); + parser.scanStr(params, "%b", &_editorShowBlocked); break; case TOKEN_EDITOR_SHOW_DECORATION: - parser.scanStr((char *)params, "%b", &_editorShowDecor); + parser.scanStr(params, "%b", &_editorShowDecor); break; case TOKEN_EDITOR_SHOW_ENTITIES: - parser.scanStr((char *)params, "%b", &_editorShowEntities); + parser.scanStr(params, "%b", &_editorShowEntities); break; case TOKEN_EDITOR_SHOW_SCALE: - parser.scanStr((char *)params, "%b", &_editorShowScale); + parser.scanStr(params, "%b", &_editorShowScale); break; case TOKEN_SCRIPT: - addScript((char *)params); + addScript(params); break; case TOKEN_PROPERTY: @@ -856,7 +856,7 @@ bool AdScene::loadBuffer(byte *buffer, bool complete) { case TOKEN_VIEWPORT: { Rect32 rc; - parser.scanStr((char *)params, "%d,%d,%d,%d", &rc.left, &rc.top, &rc.right, &rc.bottom); + parser.scanStr(params, "%d,%d,%d,%d", &rc.left, &rc.top, &rc.right, &rc.bottom); if (!_viewport) { _viewport = new BaseViewport(_gameRef); } @@ -864,13 +864,14 @@ bool AdScene::loadBuffer(byte *buffer, bool complete) { _viewport->setRect(rc.left, rc.top, rc.right, rc.bottom, true); } } + break; case TOKEN_PERSISTENT_STATE: - parser.scanStr((char *)params, "%b", &_persistentState); + parser.scanStr(params, "%b", &_persistentState); break; case TOKEN_PERSISTENT_STATE_SPRITES: - parser.scanStr((char *)params, "%b", &_persistentStateSprites); + parser.scanStr(params, "%b", &_persistentStateSprites); break; case TOKEN_EDITOR_PROPERTY: @@ -1014,8 +1015,8 @@ bool AdScene::traverseNodes(bool doUpdate) { } if (_shieldWindow) { _shieldWindow->_posX = _shieldWindow->_posY = 0; - _shieldWindow->_width = _gameRef->_renderer->getWidth(); - _shieldWindow->_height = _gameRef->_renderer->getHeight(); + _shieldWindow->setWidth(_gameRef->_renderer->getWidth()); + _shieldWindow->setHeight(_gameRef->_renderer->getHeight()); _shieldWindow->display(); } } diff --git a/engines/wintermute/ad/ad_scene.h b/engines/wintermute/ad/ad_scene.h index 5beb10e546..1f35a776b5 100644 --- a/engines/wintermute/ad/ad_scene.h +++ b/engines/wintermute/ad/ad_scene.h @@ -124,7 +124,7 @@ public: BaseArray<AdObject *> _objects; BaseArray<AdWaypointGroup *> _waypointGroups; bool loadFile(const char *filename); - bool loadBuffer(byte *buffer, bool complete = true); + bool loadBuffer(char *buffer, bool complete = true); int32 _width; int32 _height; bool addObject(AdObject *Object); diff --git a/engines/wintermute/ad/ad_sprite_set.cpp b/engines/wintermute/ad/ad_sprite_set.cpp index 9eb3bd0686..dd920492de 100644 --- a/engines/wintermute/ad/ad_sprite_set.cpp +++ b/engines/wintermute/ad/ad_sprite_set.cpp @@ -60,7 +60,7 @@ AdSpriteSet::~AdSpriteSet() { ////////////////////////////////////////////////////////////////////////// bool AdSpriteSet::loadFile(const char *filename, int lifeTime, TSpriteCacheType cacheType) { - byte *buffer = BaseFileManager::getEngineInstance()->readWholeFile(filename); + char *buffer = (char *)BaseFileManager::getEngineInstance()->readWholeFile(filename); if (buffer == nullptr) { _gameRef->LOG(0, "AdSpriteSet::LoadFile failed for file '%s'", filename); return STATUS_FAILED; @@ -93,7 +93,7 @@ TOKEN_DEF(TEMPLATE) TOKEN_DEF(EDITOR_PROPERTY) TOKEN_DEF_END ////////////////////////////////////////////////////////////////////////// -bool AdSpriteSet::loadBuffer(byte *buffer, bool complete, int lifeTime, TSpriteCacheType cacheType) { +bool AdSpriteSet::loadBuffer(char *buffer, bool complete, int lifeTime, TSpriteCacheType cacheType) { TOKEN_TABLE_START(commands) TOKEN_TABLE(SPRITESET) TOKEN_TABLE(NAME) @@ -109,12 +109,12 @@ bool AdSpriteSet::loadBuffer(byte *buffer, bool complete, int lifeTime, TSpriteC TOKEN_TABLE(EDITOR_PROPERTY) TOKEN_TABLE_END - byte *params; + char *params; int cmd; BaseParser parser; if (complete) { - if (parser.getCommand((char **)&buffer, commands, (char **)¶ms) != TOKEN_SPRITESET) { + if (parser.getCommand(&buffer, commands, ¶ms) != TOKEN_SPRITESET) { _gameRef->LOG(0, "'SPRITESET' keyword expected."); return STATUS_FAILED; } @@ -122,23 +122,23 @@ bool AdSpriteSet::loadBuffer(byte *buffer, bool complete, int lifeTime, TSpriteC } BaseSprite *spr = nullptr; - while ((cmd = parser.getCommand((char **)&buffer, commands, (char **)¶ms)) > 0) { + while ((cmd = parser.getCommand(&buffer, commands, ¶ms)) > 0) { switch (cmd) { case TOKEN_TEMPLATE: - if (DID_FAIL(loadFile((char *)params, lifeTime, cacheType))) { + if (DID_FAIL(loadFile(params, lifeTime, cacheType))) { cmd = PARSERR_GENERIC; } break; case TOKEN_NAME: - setName((char *)params); + setName(params); break; case TOKEN_LEFT: delete _sprites[DI_LEFT]; _sprites[DI_LEFT] = nullptr; spr = new BaseSprite(_gameRef, _owner); - if (!spr || DID_FAIL(spr->loadFile((char *)params, lifeTime, cacheType))) { + if (!spr || DID_FAIL(spr->loadFile(params, lifeTime, cacheType))) { cmd = PARSERR_GENERIC; } else { _sprites[DI_LEFT] = spr; @@ -149,7 +149,7 @@ bool AdSpriteSet::loadBuffer(byte *buffer, bool complete, int lifeTime, TSpriteC delete _sprites[DI_RIGHT]; _sprites[DI_RIGHT] = nullptr; spr = new BaseSprite(_gameRef, _owner); - if (!spr || DID_FAIL(spr->loadFile((char *)params, lifeTime, cacheType))) { + if (!spr || DID_FAIL(spr->loadFile(params, lifeTime, cacheType))) { cmd = PARSERR_GENERIC; } else { _sprites[DI_RIGHT] = spr; @@ -160,7 +160,7 @@ bool AdSpriteSet::loadBuffer(byte *buffer, bool complete, int lifeTime, TSpriteC delete _sprites[DI_UP]; _sprites[DI_UP] = nullptr; spr = new BaseSprite(_gameRef, _owner); - if (!spr || DID_FAIL(spr->loadFile((char *)params, lifeTime, cacheType))) { + if (!spr || DID_FAIL(spr->loadFile(params, lifeTime, cacheType))) { cmd = PARSERR_GENERIC; } else { _sprites[DI_UP] = spr; @@ -171,7 +171,7 @@ bool AdSpriteSet::loadBuffer(byte *buffer, bool complete, int lifeTime, TSpriteC delete _sprites[DI_DOWN]; _sprites[DI_DOWN] = nullptr; spr = new BaseSprite(_gameRef, _owner); - if (!spr || DID_FAIL(spr->loadFile((char *)params, lifeTime, cacheType))) { + if (!spr || DID_FAIL(spr->loadFile(params, lifeTime, cacheType))) { cmd = PARSERR_GENERIC; } else { _sprites[DI_DOWN] = spr; @@ -182,7 +182,7 @@ bool AdSpriteSet::loadBuffer(byte *buffer, bool complete, int lifeTime, TSpriteC delete _sprites[DI_UPLEFT]; _sprites[DI_UPLEFT] = nullptr; spr = new BaseSprite(_gameRef, _owner); - if (!spr || DID_FAIL(spr->loadFile((char *)params, lifeTime, cacheType))) { + if (!spr || DID_FAIL(spr->loadFile(params, lifeTime, cacheType))) { cmd = PARSERR_GENERIC; } else { _sprites[DI_UPLEFT] = spr; @@ -193,7 +193,7 @@ bool AdSpriteSet::loadBuffer(byte *buffer, bool complete, int lifeTime, TSpriteC delete _sprites[DI_UPRIGHT]; _sprites[DI_UPRIGHT] = nullptr; spr = new BaseSprite(_gameRef, _owner); - if (!spr || DID_FAIL(spr->loadFile((char *)params, lifeTime, cacheType))) { + if (!spr || DID_FAIL(spr->loadFile(params, lifeTime, cacheType))) { cmd = PARSERR_GENERIC; } else { _sprites[DI_UPRIGHT] = spr; @@ -204,7 +204,7 @@ bool AdSpriteSet::loadBuffer(byte *buffer, bool complete, int lifeTime, TSpriteC delete _sprites[DI_DOWNLEFT]; _sprites[DI_DOWNLEFT] = nullptr; spr = new BaseSprite(_gameRef, _owner); - if (!spr || DID_FAIL(spr->loadFile((char *)params, lifeTime, cacheType))) { + if (!spr || DID_FAIL(spr->loadFile(params, lifeTime, cacheType))) { cmd = PARSERR_GENERIC; } else { _sprites[DI_DOWNLEFT] = spr; @@ -215,7 +215,7 @@ bool AdSpriteSet::loadBuffer(byte *buffer, bool complete, int lifeTime, TSpriteC delete _sprites[DI_DOWNRIGHT]; _sprites[DI_DOWNRIGHT] = nullptr; spr = new BaseSprite(_gameRef, _owner); - if (!spr || DID_FAIL(spr->loadFile((char *)params, lifeTime, cacheType))) { + if (!spr || DID_FAIL(spr->loadFile(params, lifeTime, cacheType))) { cmd = PARSERR_GENERIC; } else { _sprites[DI_DOWNRIGHT] = spr; diff --git a/engines/wintermute/ad/ad_sprite_set.h b/engines/wintermute/ad/ad_sprite_set.h index ef5ef3a94f..ece71f7adb 100644 --- a/engines/wintermute/ad/ad_sprite_set.h +++ b/engines/wintermute/ad/ad_sprite_set.h @@ -44,7 +44,7 @@ public: AdSpriteSet(BaseGame *inGame, BaseObject *owner = nullptr); virtual ~AdSpriteSet(); bool loadFile(const char *filename, int lifeTime = -1, TSpriteCacheType cacheType = CACHE_ALL); - bool loadBuffer(byte *buffer, bool complete = true, int lifeTime = -1, TSpriteCacheType cacheType = CACHE_ALL); + bool loadBuffer(char *buffer, bool complete = true, int lifeTime = -1, TSpriteCacheType cacheType = CACHE_ALL); BaseSprite *_sprites[NUM_DIRECTIONS]; }; diff --git a/engines/wintermute/ad/ad_talk_def.cpp b/engines/wintermute/ad/ad_talk_def.cpp index f10a0e2fb9..1fdeed418f 100644 --- a/engines/wintermute/ad/ad_talk_def.cpp +++ b/engines/wintermute/ad/ad_talk_def.cpp @@ -71,7 +71,7 @@ AdTalkDef::~AdTalkDef() { ////////////////////////////////////////////////////////////////////////// bool AdTalkDef::loadFile(const char *filename) { - byte *buffer = BaseFileManager::getEngineInstance()->readWholeFile(filename); + char *buffer = (char *)BaseFileManager::getEngineInstance()->readWholeFile(filename); if (buffer == nullptr) { _gameRef->LOG(0, "AdTalkDef::LoadFile failed for file '%s'", filename); return STATUS_FAILED; @@ -101,7 +101,7 @@ TOKEN_DEF(DEFAULT_SPRITE) TOKEN_DEF(EDITOR_PROPERTY) TOKEN_DEF_END ////////////////////////////////////////////////////////////////////////// -bool AdTalkDef::loadBuffer(byte *buffer, bool complete) { +bool AdTalkDef::loadBuffer(char *buffer, bool complete) { TOKEN_TABLE_START(commands) TOKEN_TABLE(TALK) TOKEN_TABLE(TEMPLATE) @@ -112,22 +112,22 @@ bool AdTalkDef::loadBuffer(byte *buffer, bool complete) { TOKEN_TABLE(EDITOR_PROPERTY) TOKEN_TABLE_END - byte *params; + char *params; int cmd; BaseParser parser; if (complete) { - if (parser.getCommand((char **)&buffer, commands, (char **)¶ms) != TOKEN_TALK) { + if (parser.getCommand(&buffer, commands, ¶ms) != TOKEN_TALK) { _gameRef->LOG(0, "'TALK' keyword expected."); return STATUS_FAILED; } buffer = params; } - while ((cmd = parser.getCommand((char **)&buffer, commands, (char **)¶ms)) > 0) { + while ((cmd = parser.getCommand(&buffer, commands, ¶ms)) > 0) { switch (cmd) { case TOKEN_TEMPLATE: - if (DID_FAIL(loadFile((char *)params))) { + if (DID_FAIL(loadFile(params))) { cmd = PARSERR_GENERIC; } break; @@ -145,11 +145,11 @@ bool AdTalkDef::loadBuffer(byte *buffer, bool complete) { break; case TOKEN_DEFAULT_SPRITE: - BaseUtils::setString(&_defaultSpriteFilename, (char *)params); + BaseUtils::setString(&_defaultSpriteFilename, params); break; case TOKEN_DEFAULT_SPRITESET_FILE: - BaseUtils::setString(&_defaultSpriteSetFilename, (char *)params); + BaseUtils::setString(&_defaultSpriteSetFilename, params); break; case TOKEN_DEFAULT_SPRITESET: { diff --git a/engines/wintermute/ad/ad_talk_def.h b/engines/wintermute/ad/ad_talk_def.h index 726eefbe4c..5711906b4b 100644 --- a/engines/wintermute/ad/ad_talk_def.h +++ b/engines/wintermute/ad/ad_talk_def.h @@ -46,7 +46,7 @@ public: AdTalkDef(BaseGame *inGame); virtual ~AdTalkDef(); bool loadFile(const char *filename); - bool loadBuffer(byte *buffer, bool complete = true); + bool loadBuffer(char *buffer, bool complete = true); BaseArray<AdTalkNode *> _nodes; char *_defaultSpriteFilename; BaseSprite *_defaultSprite; diff --git a/engines/wintermute/ad/ad_talk_node.cpp b/engines/wintermute/ad/ad_talk_node.cpp index ce86dccd8e..eca4535288 100644 --- a/engines/wintermute/ad/ad_talk_node.cpp +++ b/engines/wintermute/ad/ad_talk_node.cpp @@ -79,7 +79,7 @@ TOKEN_DEF(PRECACHE) TOKEN_DEF(EDITOR_PROPERTY) TOKEN_DEF_END ////////////////////////////////////////////////////////////////////////// -bool AdTalkNode::loadBuffer(byte *buffer, bool complete) { +bool AdTalkNode::loadBuffer(char *buffer, bool complete) { TOKEN_TABLE_START(commands) TOKEN_TABLE(ACTION) TOKEN_TABLE(SPRITESET_FILE) @@ -92,12 +92,12 @@ bool AdTalkNode::loadBuffer(byte *buffer, bool complete) { TOKEN_TABLE(EDITOR_PROPERTY) TOKEN_TABLE_END - byte *params; + char *params; int cmd; BaseParser parser; if (complete) { - if (parser.getCommand((char **)&buffer, commands, (char **)¶ms) != TOKEN_ACTION) { + if (parser.getCommand(&buffer, commands, ¶ms) != TOKEN_ACTION) { _gameRef->LOG(0, "'ACTION' keyword expected."); return STATUS_FAILED; } @@ -108,14 +108,14 @@ bool AdTalkNode::loadBuffer(byte *buffer, bool complete) { _playToEnd = false; _preCache = false; - while ((cmd = parser.getCommand((char **)&buffer, commands, (char **)¶ms)) > 0) { + while ((cmd = parser.getCommand(&buffer, commands, ¶ms)) > 0) { switch (cmd) { case TOKEN_SPRITE: - BaseUtils::setString(&_spriteFilename, (char *)params); + BaseUtils::setString(&_spriteFilename, params); break; case TOKEN_SPRITESET_FILE: - BaseUtils::setString(&_spriteSetFilename, (char *)params); + BaseUtils::setString(&_spriteSetFilename, params); break; case TOKEN_SPRITESET: { @@ -130,20 +130,20 @@ bool AdTalkNode::loadBuffer(byte *buffer, bool complete) { break; case TOKEN_START_TIME: - parser.scanStr((char *)params, "%d", &_startTime); + parser.scanStr(params, "%d", &_startTime); break; case TOKEN_END_TIME: - parser.scanStr((char *)params, "%d", &_endTime); + parser.scanStr(params, "%d", &_endTime); break; case TOKEN_PRECACHE: - parser.scanStr((char *)params, "%b", &_preCache); + parser.scanStr(params, "%b", &_preCache); break; case TOKEN_COMMENT: if (_gameRef->_editorMode) { - BaseUtils::setString(&_comment, (char *)params); + BaseUtils::setString(&_comment, params); } break; diff --git a/engines/wintermute/ad/ad_talk_node.h b/engines/wintermute/ad/ad_talk_node.h index 01dfb6b4ff..7a014b2d9f 100644 --- a/engines/wintermute/ad/ad_talk_node.h +++ b/engines/wintermute/ad/ad_talk_node.h @@ -46,7 +46,7 @@ public: AdTalkNode(BaseGame *inGame); virtual ~AdTalkNode(); - bool loadBuffer(byte *buffer, bool complete = true); + bool loadBuffer(char *buffer, bool complete = true); virtual bool saveAsText(BaseDynamicBuffer *buffer, int indent = 0) override; char *_spriteFilename; BaseSprite *_sprite; diff --git a/engines/wintermute/ad/ad_waypoint_group.cpp b/engines/wintermute/ad/ad_waypoint_group.cpp index cc7982cb9d..f7735a4d9b 100644 --- a/engines/wintermute/ad/ad_waypoint_group.cpp +++ b/engines/wintermute/ad/ad_waypoint_group.cpp @@ -66,7 +66,7 @@ void AdWaypointGroup::cleanup() { ////////////////////////////////////////////////////////////////////////// bool AdWaypointGroup::loadFile(const char *filename) { - byte *buffer = BaseFileManager::getEngineInstance()->readWholeFile(filename); + char *buffer = (char *)BaseFileManager::getEngineInstance()->readWholeFile(filename); if (buffer == nullptr) { _gameRef->LOG(0, "AdWaypointGroup::LoadFile failed for file '%s'", filename); return STATUS_FAILED; @@ -98,7 +98,7 @@ TOKEN_DEF(PROPERTY) TOKEN_DEF(EDITOR_PROPERTY) TOKEN_DEF_END ////////////////////////////////////////////////////////////////////////// -bool AdWaypointGroup::loadBuffer(byte *buffer, bool complete) { +bool AdWaypointGroup::loadBuffer(char *buffer, bool complete) { TOKEN_TABLE_START(commands) TOKEN_TABLE(WAYPOINTS) TOKEN_TABLE(TEMPLATE) @@ -110,43 +110,43 @@ bool AdWaypointGroup::loadBuffer(byte *buffer, bool complete) { TOKEN_TABLE(EDITOR_PROPERTY) TOKEN_TABLE_END - byte *params; + char *params; int cmd; BaseParser parser; if (complete) { - if (parser.getCommand((char **)&buffer, commands, (char **)¶ms) != TOKEN_WAYPOINTS) { + if (parser.getCommand(&buffer, commands, ¶ms) != TOKEN_WAYPOINTS) { _gameRef->LOG(0, "'WAYPOINTS' keyword expected."); return STATUS_FAILED; } buffer = params; } - while ((cmd = parser.getCommand((char **)&buffer, commands, (char **)¶ms)) > 0) { + while ((cmd = parser.getCommand(&buffer, commands, ¶ms)) > 0) { switch (cmd) { case TOKEN_TEMPLATE: - if (DID_FAIL(loadFile((char *)params))) { + if (DID_FAIL(loadFile(params))) { cmd = PARSERR_GENERIC; } break; case TOKEN_NAME: - setName((char *)params); + setName(params); break; case TOKEN_POINT: { int x, y; - parser.scanStr((char *)params, "%d,%d", &x, &y); + parser.scanStr(params, "%d,%d", &x, &y); _points.add(new BasePoint(x, y)); } break; case TOKEN_EDITOR_SELECTED: - parser.scanStr((char *)params, "%b", &_editorSelected); + parser.scanStr(params, "%b", &_editorSelected); break; case TOKEN_EDITOR_SELECTED_POINT: - parser.scanStr((char *)params, "%d", &_editorSelectedPoint); + parser.scanStr(params, "%d", &_editorSelectedPoint); break; case TOKEN_PROPERTY: diff --git a/engines/wintermute/ad/ad_waypoint_group.h b/engines/wintermute/ad/ad_waypoint_group.h index af97a21290..47fd611be6 100644 --- a/engines/wintermute/ad/ad_waypoint_group.h +++ b/engines/wintermute/ad/ad_waypoint_group.h @@ -41,7 +41,7 @@ public: virtual bool saveAsText(BaseDynamicBuffer *buffer, int indent) override; AdWaypointGroup(BaseGame *inGame); bool loadFile(const char *filename); - bool loadBuffer(byte *buffer, bool complete = true); + bool loadBuffer(char *buffer, bool complete = true); virtual ~AdWaypointGroup(); bool _active; diff --git a/engines/wintermute/base/base.cpp b/engines/wintermute/base/base.cpp index a64770c577..91ca30db70 100644 --- a/engines/wintermute/base/base.cpp +++ b/engines/wintermute/base/base.cpp @@ -87,7 +87,7 @@ TOKEN_DEF(NAME) TOKEN_DEF(VALUE) TOKEN_DEF_END ////////////////////////////////////////////////////////////////////////// -bool BaseClass::parseEditorProperty(byte *buffer, bool complete) { +bool BaseClass::parseEditorProperty(char *buffer, bool complete) { TOKEN_TABLE_START(commands) TOKEN_TABLE(EDITOR_PROPERTY) TOKEN_TABLE(NAME) @@ -100,12 +100,12 @@ bool BaseClass::parseEditorProperty(byte *buffer, bool complete) { } - byte *params; + char *params; int cmd; BaseParser parser; if (complete) { - if (parser.getCommand((char **)&buffer, commands, (char **)¶ms) != TOKEN_EDITOR_PROPERTY) { + if (parser.getCommand(&buffer, commands, ¶ms) != TOKEN_EDITOR_PROPERTY) { BaseEngine::LOG(0, "'EDITOR_PROPERTY' keyword expected."); return STATUS_FAILED; } @@ -115,13 +115,13 @@ bool BaseClass::parseEditorProperty(byte *buffer, bool complete) { char *propName = nullptr; char *propValue = nullptr; - while ((cmd = parser.getCommand((char **)&buffer, commands, (char **)¶ms)) > 0) { + while ((cmd = parser.getCommand(&buffer, commands, ¶ms)) > 0) { switch (cmd) { case TOKEN_NAME: delete[] propName; - propName = new char[strlen((char *)params) + 1]; + propName = new char[strlen(params) + 1]; if (propName) { - strcpy(propName, (char *)params); + strcpy(propName, params); } else { cmd = PARSERR_GENERIC; } @@ -129,9 +129,9 @@ bool BaseClass::parseEditorProperty(byte *buffer, bool complete) { case TOKEN_VALUE: delete[] propValue; - propValue = new char[strlen((char *)params) + 1]; + propValue = new char[strlen(params) + 1]; if (propValue) { - strcpy(propValue, (char *)params); + strcpy(propValue, params); } else { cmd = PARSERR_GENERIC; } diff --git a/engines/wintermute/base/base.h b/engines/wintermute/base/base.h index 48ebe49a97..f4b0976019 100644 --- a/engines/wintermute/base/base.h +++ b/engines/wintermute/base/base.h @@ -46,7 +46,7 @@ public: bool setEditorProp(const Common::String &propName, const Common::String &propValue); Common::String getEditorProp(const Common::String &propName, const Common::String &initVal = nullptr); BaseClass(TDynamicConstructor, TDynamicConstructor) {} - bool parseEditorProperty(byte *buffer, bool complete = true); + bool parseEditorProperty(char *buffer, bool complete = true); virtual bool saveAsText(BaseDynamicBuffer *buffer, int indent = 0); BaseClass(); BaseClass(BaseGame *GameOwner); diff --git a/engines/wintermute/base/base_frame.cpp b/engines/wintermute/base/base_frame.cpp index eaad024120..1af8be02dd 100644 --- a/engines/wintermute/base/base_frame.cpp +++ b/engines/wintermute/base/base_frame.cpp @@ -142,7 +142,7 @@ TOKEN_DEF(EDITOR_PROPERTY) TOKEN_DEF(KILL_SOUND) TOKEN_DEF_END ////////////////////////////////////////////////////////////////////// -bool BaseFrame::loadBuffer(byte *buffer, int lifeTime, bool keepLoaded) { +bool BaseFrame::loadBuffer(char *buffer, int lifeTime, bool keepLoaded) { TOKEN_TABLE_START(commands) TOKEN_TABLE(DELAY) TOKEN_TABLE(IMAGE) @@ -184,7 +184,7 @@ bool BaseFrame::loadBuffer(byte *buffer, int lifeTime, bool keepLoaded) { BasePlatform::setRectEmpty(&rect); char *surface_file = nullptr; - while ((cmd = parser.getCommand((char **)&buffer, commands, ¶ms)) > 0) { + while ((cmd = parser.getCommand(&buffer, commands, ¶ms)) > 0) { switch (cmd) { case TOKEN_DELAY: parser.scanStr(params, "%d", &_delay); @@ -249,7 +249,7 @@ bool BaseFrame::loadBuffer(byte *buffer, int lifeTime, bool keepLoaded) { case TOKEN_SUBFRAME: { BaseSubFrame *subframe = new BaseSubFrame(_gameRef); - if (!subframe || DID_FAIL(subframe->loadBuffer((byte *)params, lifeTime, keepLoaded))) { + if (!subframe || DID_FAIL(subframe->loadBuffer(params, lifeTime, keepLoaded))) { delete subframe; cmd = PARSERR_GENERIC; } else { @@ -290,7 +290,7 @@ bool BaseFrame::loadBuffer(byte *buffer, int lifeTime, bool keepLoaded) { break; case TOKEN_EDITOR_PROPERTY: - parseEditorProperty((byte *)params, false); + parseEditorProperty(params, false); break; } } diff --git a/engines/wintermute/base/base_frame.h b/engines/wintermute/base/base_frame.h index bf1e40daa1..c4cfc443fa 100644 --- a/engines/wintermute/base/base_frame.h +++ b/engines/wintermute/base/base_frame.h @@ -52,7 +52,7 @@ public: uint32 _delay; BaseArray<BaseSubFrame *> _subframes; bool draw(int x, int y, BaseObject *registerOwner = nullptr, float zoomX = 100, float zoomY = 100, bool precise = true, uint32 alpha = 0xFFFFFFFF, bool allFrames = false, float rotate = 0.0f, TSpriteBlendMode blendMode = BLEND_NORMAL); - bool loadBuffer(byte *buffer, int lifeTime, bool keepLoaded); + bool loadBuffer(char *buffer, int lifeTime, bool keepLoaded); BaseFrame(BaseGame *inGame); virtual ~BaseFrame(); diff --git a/engines/wintermute/base/base_game.cpp b/engines/wintermute/base/base_game.cpp index b2c05d271d..0d8af0ce8a 100644 --- a/engines/wintermute/base/base_game.cpp +++ b/engines/wintermute/base/base_game.cpp @@ -573,7 +573,7 @@ bool BaseGame::initLoop() { _focusedWindow = nullptr; for (int i = _windows.size() - 1; i >= 0; i--) { - if (_windows[i]->_visible) { + if (_windows[i]->isVisible()) { _focusedWindow = _windows[i]; break; } @@ -620,7 +620,7 @@ void BaseGame::getOffset(int *offsetX, int *offsetY) const { ////////////////////////////////////////////////////////////////////////// bool BaseGame::loadFile(const char *filename) { - byte *buffer = BaseFileManager::getEngineInstance()->readWholeFile(filename); + char *buffer = (char *)BaseFileManager::getEngineInstance()->readWholeFile(filename); if (buffer == nullptr) { _gameRef->LOG(0, "BaseGame::LoadFile failed for file '%s'", filename); return STATUS_FAILED; @@ -690,7 +690,7 @@ TOKEN_DEF(GUID) TOKEN_DEF(COMPAT_KILL_METHOD_THREADS) TOKEN_DEF_END ////////////////////////////////////////////////////////////////////////// -bool BaseGame::loadBuffer(byte *buffer, bool complete) { +bool BaseGame::loadBuffer(char *buffer, bool complete) { TOKEN_TABLE_START(commands) TOKEN_TABLE(GAME) TOKEN_TABLE(TEMPLATE) @@ -740,32 +740,32 @@ bool BaseGame::loadBuffer(byte *buffer, bool complete) { Common::String loadImageName = ""; Common::String saveImageName = ""; - byte *params; + char *params; int cmd; BaseParser parser; if (complete) { - if (parser.getCommand((char **)&buffer, commands, (char **)¶ms) != TOKEN_GAME) { + if (parser.getCommand(&buffer, commands, ¶ms) != TOKEN_GAME) { _gameRef->LOG(0, "'GAME' keyword expected."); return STATUS_FAILED; } buffer = params; } - while ((cmd = parser.getCommand((char **)&buffer, commands, (char **)¶ms)) > 0) { + while ((cmd = parser.getCommand(&buffer, commands, ¶ms)) > 0) { switch (cmd) { case TOKEN_TEMPLATE: - if (DID_FAIL(loadFile((char *)params))) { + if (DID_FAIL(loadFile(params))) { cmd = PARSERR_GENERIC; } break; case TOKEN_NAME: - setName((char *)params); + setName(params); break; case TOKEN_CAPTION: - setCaption((char *)params); + setCaption(params); break; case TOKEN_SYSTEM_FONT: @@ -774,7 +774,7 @@ bool BaseGame::loadBuffer(byte *buffer, bool complete) { } _systemFont = nullptr; - _systemFont = _gameRef->_fontStorage->addFont((char *)params); + _systemFont = _gameRef->_fontStorage->addFont(params); break; case TOKEN_VIDEO_FONT: @@ -783,14 +783,14 @@ bool BaseGame::loadBuffer(byte *buffer, bool complete) { } _videoFont = nullptr; - _videoFont = _gameRef->_fontStorage->addFont((char *)params); + _videoFont = _gameRef->_fontStorage->addFont(params); break; case TOKEN_CURSOR: delete _cursor; _cursor = new BaseSprite(_gameRef); - if (!_cursor || DID_FAIL(_cursor->loadFile((char *)params))) { + if (!_cursor || DID_FAIL(_cursor->loadFile(params))) { delete _cursor; _cursor = nullptr; cmd = PARSERR_GENERIC; @@ -801,7 +801,7 @@ bool BaseGame::loadBuffer(byte *buffer, bool complete) { delete _activeCursor; _activeCursor = nullptr; _activeCursor = new BaseSprite(_gameRef); - if (!_activeCursor || DID_FAIL(_activeCursor->loadFile((char *)params))) { + if (!_activeCursor || DID_FAIL(_activeCursor->loadFile(params))) { delete _activeCursor; _activeCursor = nullptr; cmd = PARSERR_GENERIC; @@ -811,7 +811,7 @@ bool BaseGame::loadBuffer(byte *buffer, bool complete) { case TOKEN_NONINTERACTIVE_CURSOR: delete _cursorNoninteractive; _cursorNoninteractive = new BaseSprite(_gameRef); - if (!_cursorNoninteractive || DID_FAIL(_cursorNoninteractive->loadFile((char *)params))) { + if (!_cursorNoninteractive || DID_FAIL(_cursorNoninteractive->loadFile(params))) { delete _cursorNoninteractive; _cursorNoninteractive = nullptr; cmd = PARSERR_GENERIC; @@ -819,23 +819,23 @@ bool BaseGame::loadBuffer(byte *buffer, bool complete) { break; case TOKEN_SCRIPT: - addScript((char *)params); + addScript(params); break; case TOKEN_PERSONAL_SAVEGAMES: - parser.scanStr((char *)params, "%b", &_personalizedSave); + parser.scanStr(params, "%b", &_personalizedSave); break; case TOKEN_SUBTITLES: - parser.scanStr((char *)params, "%b", &_subtitles); + parser.scanStr(params, "%b", &_subtitles); break; case TOKEN_SUBTITLES_SPEED: - parser.scanStr((char *)params, "%d", &_subtitlesSpeed); + parser.scanStr(params, "%d", &_subtitlesSpeed); break; case TOKEN_VIDEO_SUBTITLES: - parser.scanStr((char *)params, "%b", &_videoSubtitles); + parser.scanStr(params, "%b", &_videoSubtitles); break; case TOKEN_PROPERTY: @@ -847,66 +847,66 @@ bool BaseGame::loadBuffer(byte *buffer, bool complete) { break; case TOKEN_THUMBNAIL_WIDTH: - parser.scanStr((char *)params, "%d", &_thumbnailWidth); + parser.scanStr(params, "%d", &_thumbnailWidth); break; case TOKEN_THUMBNAIL_HEIGHT: - parser.scanStr((char *)params, "%d", &_thumbnailHeight); + parser.scanStr(params, "%d", &_thumbnailHeight); break; case TOKEN_INDICATOR_X: - parser.scanStr((char *)params, "%d", &indicatorX); + parser.scanStr(params, "%d", &indicatorX); break; case TOKEN_INDICATOR_Y: - parser.scanStr((char *)params, "%d", &indicatorY); + parser.scanStr(params, "%d", &indicatorY); break; case TOKEN_INDICATOR_COLOR: { int r, g, b, a; - parser.scanStr((char *)params, "%d,%d,%d,%d", &r, &g, &b, &a); + parser.scanStr(params, "%d,%d,%d,%d", &r, &g, &b, &a); indicatorColor = BYTETORGBA(r, g, b, a); } break; case TOKEN_INDICATOR_WIDTH: - parser.scanStr((char *)params, "%d", &indicatorWidth); + parser.scanStr(params, "%d", &indicatorWidth); break; case TOKEN_INDICATOR_HEIGHT: - parser.scanStr((char *)params, "%d", &indicatorHeight); + parser.scanStr(params, "%d", &indicatorHeight); break; case TOKEN_SAVE_IMAGE: - saveImageName = (char *) params; + saveImageName = params; break; case TOKEN_SAVE_IMAGE_X: - parser.scanStr((char *)params, "%d", &saveImageX); + parser.scanStr(params, "%d", &saveImageX); break; case TOKEN_SAVE_IMAGE_Y: - parser.scanStr((char *)params, "%d", &saveImageY); + parser.scanStr(params, "%d", &saveImageY); break; case TOKEN_LOAD_IMAGE: - loadImageName = (char *) params; + loadImageName = params; break; case TOKEN_LOAD_IMAGE_X: - parser.scanStr((char *)params, "%d", &loadImageX); + parser.scanStr(params, "%d", &loadImageX); break; case TOKEN_LOAD_IMAGE_Y: - parser.scanStr((char *)params, "%d", &loadImageY); + parser.scanStr(params, "%d", &loadImageY); break; case TOKEN_LOCAL_SAVE_DIR: - _localSaveDir = (char *)params; + _localSaveDir = params; break; case TOKEN_COMPAT_KILL_METHOD_THREADS: - parser.scanStr((char *)params, "%b", &_compatKillMethodThreads); + parser.scanStr(params, "%b", &_compatKillMethodThreads); break; } } @@ -3019,10 +3019,10 @@ bool BaseGame::displayWindows(bool inGame) { bool res; // did we lose focus? focus topmost window - if (_focusedWindow == nullptr || !_focusedWindow->_visible || _focusedWindow->_disable) { + if (_focusedWindow == nullptr || !_focusedWindow->isVisible() || _focusedWindow->isDisabled()) { _focusedWindow = nullptr; for (int i = _windows.size() - 1; i >= 0; i--) { - if (_windows[i]->_visible && !_windows[i]->_disable) { + if (_windows[i]->isVisible() && !_windows[i]->isDisabled()) { _focusedWindow = _windows[i]; break; } @@ -3031,7 +3031,7 @@ bool BaseGame::displayWindows(bool inGame) { // display all windows for (uint32 i = 0; i < _windows.size(); i++) { - if (_windows[i]->_visible && _windows[i]->_inGame == inGame) { + if (_windows[i]->isVisible() && _windows[i]->getInGame() == inGame) { res = _windows[i]->display(); if (DID_FAIL(res)) { @@ -3131,7 +3131,7 @@ bool BaseGame::focusWindow(UIWindow *window) { _gameRef->_focusedWindow = window; } - if (window->_mode == WINDOW_NORMAL && prev != window && _gameRef->validObject(prev) && (prev->_mode == WINDOW_EXCLUSIVE || prev->_mode == WINDOW_SYSTEM_EXCLUSIVE)) { + if (window->getMode() == WINDOW_NORMAL && prev != window && _gameRef->validObject(prev) && (prev->getMode() == WINDOW_EXCLUSIVE || prev->getMode() == WINDOW_SYSTEM_EXCLUSIVE)) { return focusWindow(prev); } else { return STATUS_OK; diff --git a/engines/wintermute/base/base_game.h b/engines/wintermute/base/base_game.h index d295bb6b1a..742d6f548d 100644 --- a/engines/wintermute/base/base_game.h +++ b/engines/wintermute/base/base_game.h @@ -157,7 +157,7 @@ public: int32 _sequence; virtual bool loadFile(const char *filename); - virtual bool loadBuffer(byte *buffer, bool complete = true); + virtual bool loadBuffer(char *buffer, bool complete = true); int32 _viewportSP; diff --git a/engines/wintermute/base/base_game_settings.cpp b/engines/wintermute/base/base_game_settings.cpp index 1de8b31ca7..43809b5d1e 100644 --- a/engines/wintermute/base/base_game_settings.cpp +++ b/engines/wintermute/base/base_game_settings.cpp @@ -103,7 +103,7 @@ bool BaseGameSettings::loadSettings(const char *filename) { TOKEN_TABLE_END - byte *origBuffer = BaseFileManager::getEngineInstance()->readWholeFile(filename); + char *origBuffer = (char *)BaseFileManager::getEngineInstance()->readWholeFile(filename); if (origBuffer == nullptr) { BaseEngine::LOG(0, "BaseGame::LoadSettings failed for file '%s'", filename); return STATUS_FAILED; @@ -111,78 +111,78 @@ bool BaseGameSettings::loadSettings(const char *filename) { bool ret = STATUS_OK; - byte *buffer = origBuffer; - byte *params; + char *buffer = origBuffer; + char *params; int cmd; BaseParser parser; - if (parser.getCommand((char **)&buffer, commands, (char **)¶ms) != TOKEN_SETTINGS) { + if (parser.getCommand(&buffer, commands, ¶ms) != TOKEN_SETTINGS) { BaseEngine::LOG(0, "'SETTINGS' keyword expected in game settings file."); return STATUS_FAILED; } buffer = params; - while ((cmd = parser.getCommand((char **)&buffer, commands, (char **)¶ms)) > 0) { + while ((cmd = parser.getCommand(&buffer, commands, ¶ms)) > 0) { switch (cmd) { case TOKEN_GAME: delete[] _gameFile; - _gameFile = new char[strlen((char *)params) + 1]; + _gameFile = new char[strlen(params) + 1]; if (_gameFile) { - strcpy(_gameFile, (char *)params); + strcpy(_gameFile, params); } break; case TOKEN_STRING_TABLE: - if (DID_FAIL(_stringTable->loadFile((char *)params))) { + if (DID_FAIL(_stringTable->loadFile(params))) { cmd = PARSERR_GENERIC; } break; case TOKEN_RESOLUTION: - parser.scanStr((char *)params, "%d,%d", &_resWidth, &_resHeight); + parser.scanStr(params, "%d,%d", &_resWidth, &_resHeight); break; case TOKEN_REQUIRE_3D_ACCELERATION: - parser.scanStr((char *)params, "%b", &_requireAcceleration); + parser.scanStr(params, "%b", &_requireAcceleration); break; case TOKEN_REQUIRE_SOUND: - parser.scanStr((char *)params, "%b", &_requireSound); + parser.scanStr(params, "%b", &_requireSound); break; case TOKEN_HWTL_MODE: - parser.scanStr((char *)params, "%d", &_TLMode); + parser.scanStr(params, "%d", &_TLMode); break; case TOKEN_ALLOW_WINDOWED_MODE: - parser.scanStr((char *)params, "%b", &_allowWindowed); + parser.scanStr(params, "%b", &_allowWindowed); break; case TOKEN_ALLOW_DESKTOP_RES: - parser.scanStr((char *)params, "%b", &_allowDesktopRes); + parser.scanStr(params, "%b", &_allowDesktopRes); break; case TOKEN_ALLOW_ADVANCED: - parser.scanStr((char *)params, "%b", &_allowAdvanced); + parser.scanStr(params, "%b", &_allowAdvanced); break; case TOKEN_ALLOW_ACCESSIBILITY_TAB: - parser.scanStr((char *)params, "%b", &_allowAccessTab); + parser.scanStr(params, "%b", &_allowAccessTab); break; case TOKEN_ALLOW_ABOUT_TAB: - parser.scanStr((char *)params, "%b", &_allowAboutTab); + parser.scanStr(params, "%b", &_allowAboutTab); break; case TOKEN_REGISTRY_PATH: - //BaseEngine::instance().getRegistry()->setBasePath((char *)params); + //BaseEngine::instance().getRegistry()->setBasePath(params); break; case TOKEN_RICH_SAVED_GAMES: - parser.scanStr((char *)params, "%b", &_richSavedGames); + parser.scanStr(params, "%b", &_richSavedGames); break; case TOKEN_SAVED_GAME_EXT: - _savedGameExt = (char *)params; + _savedGameExt = params; break; case TOKEN_GUID: diff --git a/engines/wintermute/base/base_region.cpp b/engines/wintermute/base/base_region.cpp index 36036a1f18..581583c922 100644 --- a/engines/wintermute/base/base_region.cpp +++ b/engines/wintermute/base/base_region.cpp @@ -102,7 +102,7 @@ bool BaseRegion::pointInRegion(int x, int y) { ////////////////////////////////////////////////////////////////////////// bool BaseRegion::loadFile(const char *filename) { - byte *buffer = BaseFileManager::getEngineInstance()->readWholeFile(filename); + char *buffer = (char *)BaseFileManager::getEngineInstance()->readWholeFile(filename); if (buffer == nullptr) { BaseEngine::LOG(0, "BaseRegion::LoadFile failed for file '%s'", filename); return STATUS_FAILED; @@ -135,7 +135,7 @@ TOKEN_DEF(EDITOR_SELECTED_POINT) TOKEN_DEF(PROPERTY) TOKEN_DEF_END ////////////////////////////////////////////////////////////////////////// -bool BaseRegion::loadBuffer(byte *buffer, bool complete) { +bool BaseRegion::loadBuffer(char *buffer, bool complete) { TOKEN_TABLE_START(commands) TOKEN_TABLE(REGION) TOKEN_TABLE(TEMPLATE) @@ -148,12 +148,12 @@ bool BaseRegion::loadBuffer(byte *buffer, bool complete) { TOKEN_TABLE(PROPERTY) TOKEN_TABLE_END - byte *params; + char *params; int cmd; BaseParser parser; if (complete) { - if (parser.getCommand((char **)&buffer, commands, (char **)¶ms) != TOKEN_REGION) { + if (parser.getCommand(&buffer, commands, ¶ms) != TOKEN_REGION) { BaseEngine::LOG(0, "'REGION' keyword expected."); return STATUS_FAILED; } @@ -165,39 +165,39 @@ bool BaseRegion::loadBuffer(byte *buffer, bool complete) { } _points.clear(); - while ((cmd = parser.getCommand((char **)&buffer, commands, (char **)¶ms)) > 0) { + while ((cmd = parser.getCommand(&buffer, commands, ¶ms)) > 0) { switch (cmd) { case TOKEN_TEMPLATE: - if (DID_FAIL(loadFile((char *)params))) { + if (DID_FAIL(loadFile(params))) { cmd = PARSERR_GENERIC; } break; case TOKEN_NAME: - setName((char *)params); + setName(params); break; case TOKEN_CAPTION: - setCaption((char *)params); + setCaption(params); break; case TOKEN_ACTIVE: - parser.scanStr((char *)params, "%b", &_active); + parser.scanStr(params, "%b", &_active); break; case TOKEN_POINT: { int x, y; - parser.scanStr((char *)params, "%d,%d", &x, &y); + parser.scanStr(params, "%d,%d", &x, &y); _points.add(new BasePoint(x, y)); } break; case TOKEN_SCRIPT: - addScript((char *)params); + addScript(params); break; case TOKEN_EDITOR_SELECTED_POINT: - parser.scanStr((char *)params, "%d", &_editorSelectedPoint); + parser.scanStr(params, "%d", &_editorSelectedPoint); break; case TOKEN_PROPERTY: diff --git a/engines/wintermute/base/base_region.h b/engines/wintermute/base/base_region.h index 93ad6a6fbe..846dcfc341 100644 --- a/engines/wintermute/base/base_region.h +++ b/engines/wintermute/base/base_region.h @@ -48,7 +48,7 @@ public: bool pointInRegion(int x, int y); bool createRegion(); bool loadFile(const char *filename); - bool loadBuffer(byte *buffer, bool complete = true); + bool loadBuffer(char *buffer, bool complete = true); Rect32 _rect; BaseArray<BasePoint *> _points; virtual bool saveAsText(BaseDynamicBuffer *buffer, int indent) { return saveAsText(buffer, indent, nullptr); } diff --git a/engines/wintermute/base/base_script_holder.cpp b/engines/wintermute/base/base_script_holder.cpp index 25b8775a98..a670ebf1af 100644 --- a/engines/wintermute/base/base_script_holder.cpp +++ b/engines/wintermute/base/base_script_holder.cpp @@ -370,19 +370,19 @@ TOKEN_DEF(NAME) TOKEN_DEF(VALUE) TOKEN_DEF_END ////////////////////////////////////////////////////////////////////////// -bool BaseScriptHolder::parseProperty(byte *buffer, bool complete) { +bool BaseScriptHolder::parseProperty(char *buffer, bool complete) { TOKEN_TABLE_START(commands) TOKEN_TABLE(PROPERTY) TOKEN_TABLE(NAME) TOKEN_TABLE(VALUE) TOKEN_TABLE_END - byte *params; + char *params; int cmd; BaseParser parser; if (complete) { - if (parser.getCommand((char **)&buffer, commands, (char **)¶ms) != TOKEN_PROPERTY) { + if (parser.getCommand(&buffer, commands, ¶ms) != TOKEN_PROPERTY) { BaseEngine::LOG(0, "'PROPERTY' keyword expected."); return STATUS_FAILED; } @@ -392,13 +392,13 @@ bool BaseScriptHolder::parseProperty(byte *buffer, bool complete) { char *propName = nullptr; char *propValue = nullptr; - while ((cmd = parser.getCommand((char **)&buffer, commands, (char **)¶ms)) > 0) { + while ((cmd = parser.getCommand(&buffer, commands, ¶ms)) > 0) { switch (cmd) { case TOKEN_NAME: delete[] propName; - propName = new char[strlen((char *)params) + 1]; + propName = new char[strlen(params) + 1]; if (propName) { - strcpy(propName, (char *)params); + strcpy(propName, params); } else { cmd = PARSERR_GENERIC; } @@ -406,9 +406,9 @@ bool BaseScriptHolder::parseProperty(byte *buffer, bool complete) { case TOKEN_VALUE: delete[] propValue; - propValue = new char[strlen((char *)params) + 1]; + propValue = new char[strlen(params) + 1]; if (propValue) { - strcpy(propValue, (char *)params); + strcpy(propValue, params); } else { cmd = PARSERR_GENERIC; } diff --git a/engines/wintermute/base/base_script_holder.h b/engines/wintermute/base/base_script_holder.h index c34b0378a1..b4e22a59ee 100644 --- a/engines/wintermute/base/base_script_holder.h +++ b/engines/wintermute/base/base_script_holder.h @@ -53,7 +53,7 @@ public: bool applyEvent(const char *eventName, bool unbreakable = false); void setFilename(const char *filename); const char *getFilename() { return _filename; } - bool parseProperty(byte *buffer, bool complete = true); + bool parseProperty(char *buffer, bool complete = true); bool _freezable; bool _ready; diff --git a/engines/wintermute/base/base_sprite.cpp b/engines/wintermute/base/base_sprite.cpp index ab78c5ac7c..383655e0af 100644 --- a/engines/wintermute/base/base_sprite.cpp +++ b/engines/wintermute/base/base_sprite.cpp @@ -168,7 +168,7 @@ bool BaseSprite::loadFile(const Common::String &filename, int lifeTime, TSpriteC ret = STATUS_OK; } } else { - byte *buffer = BaseFileManager::getEngineInstance()->readWholeFile(filename); + char *buffer = (char *)BaseFileManager::getEngineInstance()->readWholeFile(filename); if (buffer) { if (DID_FAIL(ret = loadBuffer(buffer, true, lifeTime, cacheType))) { BaseEngine::LOG(0, "Error parsing SPRITE file '%s'", filename.c_str()); @@ -204,7 +204,7 @@ TOKEN_DEF(EDITOR_BG_ALPHA) TOKEN_DEF(EDITOR_PROPERTY) TOKEN_DEF_END ////////////////////////////////////////////////////////////////////// -bool BaseSprite::loadBuffer(byte *buffer, bool complete, int lifeTime, TSpriteCacheType cacheType) { +bool BaseSprite::loadBuffer(char *buffer, bool complete, int lifeTime, TSpriteCacheType cacheType) { TOKEN_TABLE_START(commands) TOKEN_TABLE(CONTINUOUS) TOKEN_TABLE(SPRITE) @@ -223,7 +223,7 @@ bool BaseSprite::loadBuffer(byte *buffer, bool complete, int lifeTime, TSpriteCa TOKEN_TABLE(EDITOR_PROPERTY) TOKEN_TABLE_END - byte *params; + char *params; int cmd; BaseParser parser; @@ -231,7 +231,7 @@ bool BaseSprite::loadBuffer(byte *buffer, bool complete, int lifeTime, TSpriteCa if (complete) { - if (parser.getCommand((char **)&buffer, commands, (char **)¶ms) != TOKEN_SPRITE) { + if (parser.getCommand(&buffer, commands, ¶ms) != TOKEN_SPRITE) { BaseEngine::LOG(0, "'SPRITE' keyword expected."); return STATUS_FAILED; } @@ -240,30 +240,30 @@ bool BaseSprite::loadBuffer(byte *buffer, bool complete, int lifeTime, TSpriteCa int frameCount = 1; BaseFrame *frame; - while ((cmd = parser.getCommand((char **)&buffer, commands, (char **)¶ms)) > 0) { + while ((cmd = parser.getCommand(&buffer, commands, ¶ms)) > 0) { switch (cmd) { case TOKEN_CONTINUOUS: - parser.scanStr((char *)params, "%b", &_continuous); + parser.scanStr(params, "%b", &_continuous); break; case TOKEN_EDITOR_MUTED: - parser.scanStr((char *)params, "%b", &_editorMuted); + parser.scanStr(params, "%b", &_editorMuted); break; case TOKEN_SCRIPT: - addScript((char *)params); + addScript(params); break; case TOKEN_LOOPING: - parser.scanStr((char *)params, "%b", &_looping); + parser.scanStr(params, "%b", &_looping); break; case TOKEN_PRECISE: - parser.scanStr((char *)params, "%b", &_precise); + parser.scanStr(params, "%b", &_precise); break; case TOKEN_STREAMED: - parser.scanStr((char *)params, "%b", &_streamed); + parser.scanStr(params, "%b", &_streamed); if (_streamed && lifeTime == -1) { lifeTime = 500; cacheType = CACHE_ALL; @@ -271,33 +271,33 @@ bool BaseSprite::loadBuffer(byte *buffer, bool complete, int lifeTime, TSpriteCa break; case TOKEN_STREAMED_KEEP_LOADED: - parser.scanStr((char *)params, "%b", &_streamedKeepLoaded); + parser.scanStr(params, "%b", &_streamedKeepLoaded); break; case TOKEN_NAME: - setName((char *)params); + setName(params); break; case TOKEN_EDITOR_BG_FILE: if (_gameRef->_editorMode) { delete[] _editorBgFile; - _editorBgFile = new char[strlen((char *)params) + 1]; + _editorBgFile = new char[strlen(params) + 1]; if (_editorBgFile) { - strcpy(_editorBgFile, (char *)params); + strcpy(_editorBgFile, params); } } break; case TOKEN_EDITOR_BG_OFFSET_X: - parser.scanStr((char *)params, "%d", &_editorBgOffsetX); + parser.scanStr(params, "%d", &_editorBgOffsetX); break; case TOKEN_EDITOR_BG_OFFSET_Y: - parser.scanStr((char *)params, "%d", &_editorBgOffsetY); + parser.scanStr(params, "%d", &_editorBgOffsetY); break; case TOKEN_EDITOR_BG_ALPHA: - parser.scanStr((char *)params, "%d", &_editorBgAlpha); + parser.scanStr(params, "%d", &_editorBgAlpha); _editorBgAlpha = MIN<int32>(_editorBgAlpha, 255); _editorBgAlpha = MAX<int32>(_editorBgAlpha, 0); break; diff --git a/engines/wintermute/base/base_sprite.h b/engines/wintermute/base/base_sprite.h index 1387796895..54d595f655 100644 --- a/engines/wintermute/base/base_sprite.h +++ b/engines/wintermute/base/base_sprite.h @@ -53,7 +53,7 @@ public: void reset(); bool isChanged(); bool isFinished(); - bool loadBuffer(byte *buffer, bool compete = true, int lifeTime = -1, TSpriteCacheType cacheType = CACHE_ALL); + bool loadBuffer(char *buffer, bool compete = true, int lifeTime = -1, TSpriteCacheType cacheType = CACHE_ALL); bool loadFile(const Common::String &filename, int lifeTime = -1, TSpriteCacheType cacheType = CACHE_ALL); bool draw(int x, int y, BaseObject *Register = nullptr, float zoomX = kDefaultZoomX, float zoomY = kDefaultZoomY, uint32 alpha = kDefaultRgbaMod); bool _looping; diff --git a/engines/wintermute/base/base_sub_frame.cpp b/engines/wintermute/base/base_sub_frame.cpp index c22e0982a6..1055987f6b 100644 --- a/engines/wintermute/base/base_sub_frame.cpp +++ b/engines/wintermute/base/base_sub_frame.cpp @@ -97,7 +97,7 @@ TOKEN_DEF(EDITOR_SELECTED) TOKEN_DEF(EDITOR_PROPERTY) TOKEN_DEF_END ////////////////////////////////////////////////////////////////////// -bool BaseSubFrame::loadBuffer(byte *buffer, int lifeTime, bool keepLoaded) { +bool BaseSubFrame::loadBuffer(char *buffer, int lifeTime, bool keepLoaded) { TOKEN_TABLE_START(commands) TOKEN_TABLE(IMAGE) TOKEN_TABLE(TRANSPARENT) @@ -127,7 +127,7 @@ bool BaseSubFrame::loadBuffer(byte *buffer, int lifeTime, bool keepLoaded) { delete _surface; _surface = nullptr; - while ((cmd = parser.getCommand((char **)&buffer, commands, ¶ms)) > 0) { + while ((cmd = parser.getCommand(&buffer, commands, ¶ms)) > 0) { switch (cmd) { case TOKEN_IMAGE: surfaceFile = params; @@ -179,7 +179,7 @@ bool BaseSubFrame::loadBuffer(byte *buffer, int lifeTime, bool keepLoaded) { break; case TOKEN_EDITOR_PROPERTY: - parseEditorProperty((byte *)params, false); + parseEditorProperty(params, false); break; } } diff --git a/engines/wintermute/base/base_sub_frame.h b/engines/wintermute/base/base_sub_frame.h index ba3d5b955a..4e164467e2 100644 --- a/engines/wintermute/base/base_sub_frame.h +++ b/engines/wintermute/base/base_sub_frame.h @@ -51,7 +51,7 @@ public: bool _editorSelected; BaseSubFrame(BaseGame *inGame); virtual ~BaseSubFrame(); - bool loadBuffer(byte *buffer, int lifeTime, bool keepLoaded); + bool loadBuffer(char *buffer, int lifeTime, bool keepLoaded); bool draw(int x, int y, BaseObject *registerOwner = nullptr, float zoomX = 100, float zoomY = 100, bool precise = true, uint32 alpha = 0xFFFFFFFF, float rotate = 0.0f, TSpriteBlendMode blendMode = BLEND_NORMAL); bool getBoundingRect(Rect32 *rect, int x, int y, float scaleX = 100, float scaleY = 100); const char* getSurfaceFilename(); diff --git a/engines/wintermute/base/file/base_disk_file.cpp b/engines/wintermute/base/file/base_disk_file.cpp index 7391d819fc..808dc9e00d 100644 --- a/engines/wintermute/base/file/base_disk_file.cpp +++ b/engines/wintermute/base/file/base_disk_file.cpp @@ -117,6 +117,8 @@ Common::SeekableReadStream *openDiskFile(const Common::String &filename) { if (fixedFilename.contains(':')) { if (fixedFilename.hasPrefix("c:/windows/fonts/")) { // East Side Story refers to "c:\windows\fonts\framd.ttf" fixedFilename = filename.c_str() + 14; + } else if (fixedFilename.hasPrefix("c:/carol6/svn/data/")) { // Carol Reed 6: Black Circle refers to "c:\carol6\svn\data\sprites\system\help.png" + fixedFilename = fixedFilename.c_str() + 19; } else { error("openDiskFile::Absolute path or invalid filename used in %s", filename.c_str()); } @@ -149,7 +151,8 @@ Common::SeekableReadStream *openDiskFile(const Common::String &filename) { } if (compressed) { - uint32 dataOffset, compSize, uncompSize; + uint32 dataOffset, compSize; + unsigned long uncompSize; dataOffset = file->readUint32LE(); compSize = file->readUint32LE(); uncompSize = file->readUint32LE(); @@ -171,7 +174,7 @@ Common::SeekableReadStream *openDiskFile(const Common::String &filename) { file->seek(dataOffset + prefixSize, SEEK_SET); file->read(compBuffer, compSize); - if (Common::uncompress(data, (unsigned long *)&uncompSize, compBuffer, compSize) != true) { + if (Common::uncompress(data, &uncompSize, compBuffer, compSize) != true) { error("Error uncompressing file '%s'", filename.c_str()); delete[] compBuffer; delete file; diff --git a/engines/wintermute/base/font/base_font.cpp b/engines/wintermute/base/font/base_font.cpp index 26bc0e7985..2a394616d1 100644 --- a/engines/wintermute/base/font/base_font.cpp +++ b/engines/wintermute/base/font/base_font.cpp @@ -118,18 +118,18 @@ bool BaseFont::isTrueType(BaseGame *gameRef, const Common::String &filename) { TOKEN_TABLE_END - byte *buffer = BaseFileManager::getEngineInstance()->readWholeFile(filename); + char *buffer = (char *)BaseFileManager::getEngineInstance()->readWholeFile(filename); if (buffer == nullptr) { return false; } - byte *workBuffer = buffer; + char *workBuffer = buffer; char *params; BaseParser parser; bool ret = false; - if (parser.getCommand((char **)&workBuffer, commands, (char **)¶ms) == TOKEN_TTFONT) { + if (parser.getCommand(&workBuffer, commands, ¶ms) == TOKEN_TTFONT) { ret = true; } diff --git a/engines/wintermute/base/font/base_font_bitmap.cpp b/engines/wintermute/base/font/base_font_bitmap.cpp index 890a9a2f83..23a633a5a8 100644 --- a/engines/wintermute/base/font/base_font_bitmap.cpp +++ b/engines/wintermute/base/font/base_font_bitmap.cpp @@ -272,7 +272,7 @@ void BaseFontBitmap::drawChar(byte c, int x, int y) { ////////////////////////////////////////////////////////////////////// bool BaseFontBitmap::loadFile(const Common::String &filename) { - byte *buffer = BaseFileManager::getEngineInstance()->readWholeFile(filename); + char *buffer = (char *)BaseFileManager::getEngineInstance()->readWholeFile(filename); if (buffer == nullptr) { _gameRef->LOG(0, "BaseFontBitmap::LoadFile failed for file '%s'", filename.c_str()); return STATUS_FAILED; @@ -311,7 +311,7 @@ TOKEN_DEF(WIDTHS_FRAME) TOKEN_DEF(PAINT_WHOLE_CELL) TOKEN_DEF_END ////////////////////////////////////////////////////////////////////// -bool BaseFontBitmap::loadBuffer(byte *buffer) { +bool BaseFontBitmap::loadBuffer(char *buffer) { TOKEN_TABLE_START(commands) TOKEN_TABLE(FONTEXT_FIX) TOKEN_TABLE(FONT) @@ -335,11 +335,11 @@ bool BaseFontBitmap::loadBuffer(byte *buffer) { int cmd; BaseParser parser; - if (parser.getCommand((char **)&buffer, commands, (char **)¶ms) != TOKEN_FONT) { + if (parser.getCommand(&buffer, commands, ¶ms) != TOKEN_FONT) { _gameRef->LOG(0, "'FONT' keyword expected."); return STATUS_FAILED; } - buffer = (byte *)params; + buffer = params; int widths[300]; int num = 0, defaultWidth = 8; @@ -354,15 +354,15 @@ bool BaseFontBitmap::loadBuffer(byte *buffer) { int spaceWidth = 0; int expandWidth = 0; - while ((cmd = parser.getCommand((char **)&buffer, commands, (char **)¶ms)) > 0) { + while ((cmd = parser.getCommand(&buffer, commands, ¶ms)) > 0) { switch (cmd) { case TOKEN_IMAGE: - surfaceFile = (char *)params; + surfaceFile = params; break; case TOKEN_SPRITE: - spriteFile = (char *)params; + spriteFile = params; break; case TOKEN_TRANSPARENT: @@ -418,7 +418,7 @@ bool BaseFontBitmap::loadBuffer(byte *buffer) { break; case TOKEN_EDITOR_PROPERTY: - parseEditorProperty((byte *)params, false); + parseEditorProperty(params, false); break; } diff --git a/engines/wintermute/base/font/base_font_bitmap.h b/engines/wintermute/base/font/base_font_bitmap.h index c810777446..77620d8b88 100644 --- a/engines/wintermute/base/font/base_font_bitmap.h +++ b/engines/wintermute/base/font/base_font_bitmap.h @@ -37,7 +37,7 @@ class BaseSubFrame; class BaseFontBitmap : public BaseFont { public: DECLARE_PERSISTENT(BaseFontBitmap, BaseFont) - bool loadBuffer(byte *Buffer); + bool loadBuffer(char *buffer); bool loadFile(const Common::String &filename); virtual int getTextWidth(const byte *text, int maxLength = -1) override; virtual int getTextHeight(const byte *text, int width) override; diff --git a/engines/wintermute/base/font/base_font_truetype.cpp b/engines/wintermute/base/font/base_font_truetype.cpp index 8e0eb8a004..bbc66902a1 100644 --- a/engines/wintermute/base/font/base_font_truetype.cpp +++ b/engines/wintermute/base/font/base_font_truetype.cpp @@ -324,7 +324,7 @@ int BaseFontTT::getLetterHeight() { ////////////////////////////////////////////////////////////////////// bool BaseFontTT::loadFile(const Common::String &filename) { - byte *buffer = BaseFileManager::getEngineInstance()->readWholeFile(filename); + char *buffer = (char *)BaseFileManager::getEngineInstance()->readWholeFile(filename); if (buffer == nullptr) { _gameRef->LOG(0, "BaseFontTT::LoadFile failed for file '%s'", filename.c_str()); return STATUS_FAILED; @@ -361,7 +361,7 @@ TOKEN_DEF(OFFSET_X) TOKEN_DEF(OFFSET_Y) TOKEN_DEF_END ////////////////////////////////////////////////////////////////////// -bool BaseFontTT::loadBuffer(byte *buffer) { +bool BaseFontTT::loadBuffer(char *buffer) { TOKEN_TABLE_START(commands) TOKEN_TABLE(TTFONT) TOKEN_TABLE(SIZE) @@ -381,15 +381,15 @@ bool BaseFontTT::loadBuffer(byte *buffer) { int cmd; BaseParser parser; - if (parser.getCommand((char **)&buffer, commands, (char **)¶ms) != TOKEN_TTFONT) { + if (parser.getCommand(&buffer, commands, ¶ms) != TOKEN_TTFONT) { _gameRef->LOG(0, "'TTFONT' keyword expected."); return STATUS_FAILED; } - buffer = (byte *)params; + buffer = params; uint32 baseColor = 0x00000000; - while ((cmd = parser.getCommand((char **)&buffer, commands, (char **)¶ms)) > 0) { + while ((cmd = parser.getCommand(&buffer, commands, ¶ms)) > 0) { switch (cmd) { case TOKEN_SIZE: parser.scanStr(params, "%d", &_fontHeight); @@ -439,7 +439,7 @@ bool BaseFontTT::loadBuffer(byte *buffer) { case TOKEN_LAYER: { BaseTTFontLayer *layer = new BaseTTFontLayer; - if (layer && DID_SUCCEED(parseLayer(layer, (byte *)params))) { + if (layer && DID_SUCCEED(parseLayer(layer, params))) { _layers.add(layer); } else { delete layer; @@ -472,7 +472,7 @@ bool BaseFontTT::loadBuffer(byte *buffer) { ////////////////////////////////////////////////////////////////////////// -bool BaseFontTT::parseLayer(BaseTTFontLayer *layer, byte *buffer) { +bool BaseFontTT::parseLayer(BaseTTFontLayer *layer, char *buffer) { TOKEN_TABLE_START(commands) TOKEN_TABLE(OFFSET_X) TOKEN_TABLE(OFFSET_Y) @@ -484,7 +484,7 @@ bool BaseFontTT::parseLayer(BaseTTFontLayer *layer, byte *buffer) { int cmd; BaseParser parser; - while ((cmd = parser.getCommand((char **)&buffer, commands, (char **)¶ms)) > 0) { + while ((cmd = parser.getCommand(&buffer, commands, ¶ms)) > 0) { switch (cmd) { case TOKEN_OFFSET_X: parser.scanStr(params, "%d", &layer->_offsetX); diff --git a/engines/wintermute/base/font/base_font_truetype.h b/engines/wintermute/base/font/base_font_truetype.h index fdbae30684..9e0a082593 100644 --- a/engines/wintermute/base/font/base_font_truetype.h +++ b/engines/wintermute/base/font/base_font_truetype.h @@ -105,7 +105,7 @@ public: virtual void drawText(const byte *text, int x, int y, int width, TTextAlign align = TAL_LEFT, int max_height = -1, int maxLength = -1) override; virtual int getLetterHeight() override; - bool loadBuffer(byte *buffer); + bool loadBuffer(char *buffer); bool loadFile(const Common::String &filename); float getLineHeight() const { @@ -116,7 +116,7 @@ public: void initLoop(); private: - bool parseLayer(BaseTTFontLayer *layer, byte *buffer); + bool parseLayer(BaseTTFontLayer *layer, char *buffer); void measureText(const WideString &text, int maxWidth, int maxHeight, int &textWidth, int &textHeight); diff --git a/engines/wintermute/base/gfx/base_surface.h b/engines/wintermute/base/gfx/base_surface.h index 42fd593f61..a53748e9aa 100644 --- a/engines/wintermute/base/gfx/base_surface.h +++ b/engines/wintermute/base/gfx/base_surface.h @@ -56,7 +56,7 @@ public: virtual bool display(int x, int y, Rect32 rect, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) = 0; virtual bool displayTransform(int x, int y, Rect32 rect, Rect32 newRect, const TransformStruct &transform) = 0; virtual bool displayZoom(int x, int y, Rect32 rect, float zoomX, float zoomY, uint32 alpha = 0xFFFFFFFF, bool transparent = false, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) = 0; - virtual bool repeatLastDisplayOp(int offsetX, int offsetY, int numTimesX, int numTimesY) = 0; + virtual bool displayTiled(int x, int y, Rect32 rect, int numTimesX, int numTimesY) = 0; virtual bool restore(); virtual bool create(const Common::String &filename, bool defaultCK, byte ckRed, byte ckGreen, byte ckBlue, int lifeTime = -1, bool keepLoaded = false) = 0; virtual bool create(int width, int height); diff --git a/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp b/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp index e4c19fde8b..ff63789d18 100644 --- a/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp +++ b/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp @@ -51,22 +51,19 @@ BaseRenderer *makeOSystemRenderer(BaseGame *inGame) { BaseRenderOSystem::BaseRenderOSystem(BaseGame *inGame) : BaseRenderer(inGame) { _renderSurface = new Graphics::Surface(); _blankSurface = new Graphics::Surface(); - _drawNum = 1; + _lastFrameIter = _renderQueue.end(); _needsFlip = true; - _spriteBatch = false; - _batchNum = 0; _skipThisFrame = false; - _previousTicket = nullptr; _borderLeft = _borderRight = _borderTop = _borderBottom = 0; _ratioX = _ratioY = 1.0f; - _colorMod = kDefaultRgbaMod; _dirtyRect = nullptr; _disableDirtyRects = false; - _tempDisableDirtyRects = 0; if (ConfMan.hasKey("dirty_rects")) { _disableDirtyRects = !ConfMan.getBool("dirty_rects"); } + + _lastScreenChangeID = g_system->getScreenChangeID(); } ////////////////////////////////////////////////////////////////////////// @@ -155,20 +152,24 @@ bool BaseRenderOSystem::indicatorFlip() { } bool BaseRenderOSystem::flip() { - if (_renderQueue.size() > DIRTY_RECT_LIMIT) { - _tempDisableDirtyRects++; - } if (_skipThisFrame) { _skipThisFrame = false; delete _dirtyRect; _dirtyRect = nullptr; g_system->updateScreen(); _needsFlip = false; - _drawNum = 1; + + // Reset ticketing state + _lastFrameIter = _renderQueue.end(); + RenderQueueIterator it; + for (it = _renderQueue.begin(); it != _renderQueue.end(); ++it) { + (*it)->_wantsDraw = false; + } + addDirtyRect(_renderRect); return true; } - if (!_tempDisableDirtyRects && !_disableDirtyRects) { + if (!_disableDirtyRects) { drawTickets(); } else { // Clear the scale-buffered tickets that wasn't reused. @@ -184,33 +185,23 @@ bool BaseRenderOSystem::flip() { } } } - if (_needsFlip || _disableDirtyRects || _tempDisableDirtyRects) { - if (_disableDirtyRects || _tempDisableDirtyRects) { + + int oldScreenChangeID = _lastScreenChangeID; + _lastScreenChangeID = g_system->getScreenChangeID(); + bool screenChanged = _lastScreenChangeID != oldScreenChangeID; + + if (_needsFlip || _disableDirtyRects || screenChanged) { + if (_disableDirtyRects || screenChanged) { g_system->copyRectToScreen((byte *)_renderSurface->getPixels(), _renderSurface->pitch, 0, 0, _renderSurface->w, _renderSurface->h); } // g_system->copyRectToScreen((byte *)_renderSurface->getPixels(), _renderSurface->pitch, _dirtyRect->left, _dirtyRect->top, _dirtyRect->width(), _dirtyRect->height()); delete _dirtyRect; _dirtyRect = nullptr; - g_system->updateScreen(); _needsFlip = false; } - _drawNum = 1; - - if (_tempDisableDirtyRects && !_disableDirtyRects) { - _tempDisableDirtyRects--; - if (!_tempDisableDirtyRects) { - Common::Rect screen(_screenRect.top, _screenRect.left, _screenRect.bottom, _screenRect.right); - addDirtyRect(screen); - - // The queue has been ignored but updated, and is guaranteed to be in draw-order when run without dirty-rects. - RenderQueueIterator it = _renderQueue.begin(); - int drawNum = 1; - while (it != _renderQueue.end()) { - (*it)->_drawNum = drawNum++; - ++it; - } - } - } + _lastFrameIter = _renderQueue.end(); + + g_system->updateScreen(); return STATUS_OK; } @@ -218,7 +209,7 @@ bool BaseRenderOSystem::flip() { ////////////////////////////////////////////////////////////////////////// bool BaseRenderOSystem::fill(byte r, byte g, byte b, Common::Rect *rect) { _clearColor = _renderSurface->format.ARGBToColor(0xFF, r, g, b); - if (!_disableDirtyRects && !_tempDisableDirtyRects) { + if (!_disableDirtyRects) { return STATUS_OK; } if (!rect) { @@ -279,22 +270,14 @@ Graphics::PixelFormat BaseRenderOSystem::getPixelFormat() const { void BaseRenderOSystem::drawSurface(BaseSurfaceOSystem *owner, const Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRect, TransformStruct &transform) { - if (_tempDisableDirtyRects || _disableDirtyRects) { + if (_disableDirtyRects) { RenderTicket *ticket = new RenderTicket(owner, surf, srcRect, dstRect, transform); - ticket->_transform._rgbaMod = _colorMod; ticket->_wantsDraw = true; _renderQueue.push_back(ticket); - _previousTicket = ticket; drawFromSurface(ticket); return; } - // Start searching from the beginning for the first and second items (since it's empty the first time around - // then keep incrementing the start-position, to avoid comparing against already used tickets. - if (_drawNum == 0 || _drawNum == 1) { - _lastAddedTicket = _renderQueue.begin(); - } - // Skip rects that are completely outside the screen: if ((dstRect->left < 0 && dstRect->right < 0) || (dstRect->top < 0 && dstRect->bottom < 0)) { return; @@ -302,28 +285,19 @@ void BaseRenderOSystem::drawSurface(BaseSurfaceOSystem *owner, const Graphics::S if (owner) { // Fade-tickets are owner-less RenderTicket compare(owner, nullptr, srcRect, dstRect, transform); - compare._batchNum = _batchNum; - if (_spriteBatch) { - _batchNum++; - } - RenderQueueIterator it; + RenderQueueIterator it = _lastFrameIter; + ++it; // Avoid calling end() and operator* every time, when potentially going through // LOTS of tickets. RenderQueueIterator endIterator = _renderQueue.end(); RenderTicket *compareTicket = nullptr; - for (it = _lastAddedTicket; it != endIterator; ++it) { + for (; it != endIterator; ++it) { compareTicket = *it; if (*(compareTicket) == compare && compareTicket->_isValid) { - compareTicket->_transform._rgbaMod = transform._rgbaMod; if (_disableDirtyRects) { drawFromSurface(compareTicket); } else { - drawFromTicket(compareTicket); - _previousTicket = compareTicket; - } - if (_renderQueue.size() > DIRTY_RECT_LIMIT) { - drawTickets(); - _tempDisableDirtyRects = 3; + drawFromQueuedTicket(it); } return; } @@ -332,57 +306,13 @@ void BaseRenderOSystem::drawSurface(BaseSurfaceOSystem *owner, const Graphics::S RenderTicket *ticket = new RenderTicket(owner, surf, srcRect, dstRect, transform); if (!_disableDirtyRects) { drawFromTicket(ticket); - _previousTicket = ticket; } else { ticket->_wantsDraw = true; _renderQueue.push_back(ticket); - _previousTicket = ticket; drawFromSurface(ticket); } } -void BaseRenderOSystem::repeatLastDraw(int offsetX, int offsetY, int numTimesX, int numTimesY) { - if (_previousTicket && _lastAddedTicket != _renderQueue.end()) { - RenderTicket *origTicket = _previousTicket; - - // Make sure drawSurface WILL start from the correct _lastAddedTicket - if (!_tempDisableDirtyRects && !_disableDirtyRects && *_lastAddedTicket != origTicket) { - RenderQueueIterator it; - RenderQueueIterator endIterator = _renderQueue.end(); - for (it = _renderQueue.begin(); it != endIterator; ++it) { - if ((*it) == _previousTicket) { - _lastAddedTicket = it; - break; - } - } - } - Common::Rect srcRect(0, 0, 0, 0); - srcRect.setWidth(origTicket->getSrcRect()->width()); - srcRect.setHeight(origTicket->getSrcRect()->height()); - - Common::Rect dstRect = origTicket->_dstRect; - int initLeft = dstRect.left; - int initRight = dstRect.right; - - TransformStruct temp = TransformStruct(kDefaultZoomX, kDefaultZoomY, kDefaultAngle, kDefaultHotspotX, kDefaultHotspotY, BLEND_NORMAL, kDefaultRgbaMod, false, false, kDefaultOffsetX, kDefaultOffsetY); - - for (int i = 0; i < numTimesY; i++) { - if (i == 0) { - dstRect.translate(offsetX, 0); - } - for (int j = (i == 0 ? 1 : 0); j < numTimesX; j++) { - drawSurface(origTicket->_owner, origTicket->getSurface(), &srcRect, &dstRect, temp); - dstRect.translate(offsetX, 0); - } - dstRect.left = initLeft; - dstRect.right = initRight; - dstRect.translate(0, offsetY); - } - } else { - error("Repeat-draw failed (did you forget to draw something before this?)"); - } -} - void BaseRenderOSystem::invalidateTicket(RenderTicket *renderTicket) { addDirtyRect(renderTicket->_dstRect); renderTicket->_isValid = false; @@ -400,59 +330,37 @@ void BaseRenderOSystem::invalidateTicketsFromSurface(BaseSurfaceOSystem *surf) { void BaseRenderOSystem::drawFromTicket(RenderTicket *renderTicket) { renderTicket->_wantsDraw = true; - // A new item always has _drawNum == 0 - if (renderTicket->_drawNum == 0) { - // In-order - if (_renderQueue.empty() || _drawNum > (_renderQueue.back())->_drawNum) { - renderTicket->_drawNum = _drawNum++; - _renderQueue.push_back(renderTicket); - addDirtyRect(renderTicket->_dstRect); - ++_lastAddedTicket; - } else { - // Before something - RenderQueueIterator pos; - for (pos = _renderQueue.begin(); pos != _renderQueue.end(); pos++) { - if ((*pos)->_drawNum >= _drawNum) { - break; - } - } - _renderQueue.insert(pos, renderTicket); - renderTicket->_drawNum = _drawNum++; - // Increment the following tickets, so they still are in line - RenderQueueIterator it; - for (it = pos; it != _renderQueue.end(); ++it) { - (*it)->_drawNum++; - (*it)->_wantsDraw = false; - } - addDirtyRect(renderTicket->_dstRect); - _lastAddedTicket = pos; - } + + ++_lastFrameIter; + // In-order + if (_renderQueue.empty() || _lastFrameIter == _renderQueue.end()) { + _lastFrameIter--; + _renderQueue.push_back(renderTicket); + ++_lastFrameIter; + addDirtyRect(renderTicket->_dstRect); } else { - // Was drawn last round, still in the same order - if (_drawNum == renderTicket->_drawNum) { - _drawNum++; - ++_lastAddedTicket; - } else { - // Remove the ticket from the list - RenderQueueIterator it = _renderQueue.begin(); - while (it != _renderQueue.end()) { - if ((*it) == renderTicket) { - it = _renderQueue.erase(it); - break; - } else { - ++it; - } - } - if (it != _renderQueue.end()) { - // Decreement the following tickets. - for (; it != _renderQueue.end(); ++it) { - (*it)->_drawNum--; - } - } - // Is not in order, so readd it as if it was a new ticket - renderTicket->_drawNum = 0; - drawFromTicket(renderTicket); - } + // Before something + RenderQueueIterator pos = _lastFrameIter; + _renderQueue.insert(pos, renderTicket); + --_lastFrameIter; + addDirtyRect(renderTicket->_dstRect); + } +} + +void BaseRenderOSystem::drawFromQueuedTicket(const RenderQueueIterator &ticket) { + RenderTicket *renderTicket = *ticket; + assert(!renderTicket->_wantsDraw); + renderTicket->_wantsDraw = true; + + ++_lastFrameIter; + // Not in the same order? + if (*_lastFrameIter != renderTicket) { + --_lastFrameIter; + // Remove the ticket from the list + assert(*_lastFrameIter != renderTicket); + _renderQueue.erase(ticket); + // Is not in order, so readd it as if it was a new ticket + drawFromTicket(renderTicket); } } @@ -471,16 +379,13 @@ void BaseRenderOSystem::drawTickets() { // Note: We draw invalid tickets too, otherwise we wouldn't be honouring // the draw request they obviously made BEFORE becoming invalid, either way // we have a copy of their data, so their invalidness won't affect us. - uint32 decrement = 0; while (it != _renderQueue.end()) { if ((*it)->_wantsDraw == false) { RenderTicket *ticket = *it; addDirtyRect((*it)->_dstRect); it = _renderQueue.erase(it); delete ticket; - decrement++; } else { - (*it)->_drawNum -= decrement; ++it; } } @@ -493,17 +398,12 @@ void BaseRenderOSystem::drawTickets() { } return; } - // The color-mods are stored in the RenderTickets on add, since we set that state again during - // draw, we need to keep track of what it was prior to draw. - uint32 oldColorMod = _colorMod; // Apply the clear-color to the dirty rect. _renderSurface->fillRect(*_dirtyRect, _clearColor); - _drawNum = 1; + _lastFrameIter = _renderQueue.end(); for (it = _renderQueue.begin(); it != _renderQueue.end(); ++it) { RenderTicket *ticket = *it; - assert(ticket->_drawNum == _drawNum); - ++_drawNum; if (ticket->_dstRect.intersects(*_dirtyRect)) { // dstClip is the area we want redrawn. Common::Rect dstClip(ticket->_dstRect); @@ -516,7 +416,6 @@ void BaseRenderOSystem::drawTickets() { // convert from screen-coords to surface-coords. dstClip.translate(-offsetX, -offsetY); - _colorMod = ticket->_transform._rgbaMod; drawFromSurface(ticket, &pos, &dstClip); _needsFlip = true; } @@ -525,21 +424,15 @@ void BaseRenderOSystem::drawTickets() { } g_system->copyRectToScreen((byte *)_renderSurface->getBasePtr(_dirtyRect->left, _dirtyRect->top), _renderSurface->pitch, _dirtyRect->left, _dirtyRect->top, _dirtyRect->width(), _dirtyRect->height()); - // Revert the colorMod-state. - _colorMod = oldColorMod; - it = _renderQueue.begin(); // Clean out the old tickets - decrement = 0; while (it != _renderQueue.end()) { if ((*it)->_isValid == false) { RenderTicket *ticket = *it; addDirtyRect((*it)->_dstRect); it = _renderQueue.erase(it); delete ticket; - decrement++; } else { - (*it)->_drawNum -= decrement; ++it; } } @@ -559,7 +452,7 @@ void BaseRenderOSystem::drawFromSurface(RenderTicket *ticket, Common::Rect *dstR bool BaseRenderOSystem::drawLine(int x1, int y1, int x2, int y2, uint32 color) { // This function isn't used outside of indicator-displaying, and thus quite unused in // BaseRenderOSystem when dirty-rects are enabled. - if (!_tempDisableDirtyRects && !_disableDirtyRects && !_indicatorDisplay) { + if (!_disableDirtyRects && !_indicatorDisplay) { error("BaseRenderOSystem::DrawLine - doesn't work for dirty rects yet"); } @@ -665,12 +558,10 @@ void BaseRenderOSystem::endSaveLoad() { it = _renderQueue.erase(it); delete ticket; } - _lastAddedTicket = _renderQueue.begin(); - _previousTicket = nullptr; // HACK: After a save the buffer will be drawn before the scripts get to update it, // so just skip this single frame. _skipThisFrame = true; - _drawNum = 1; + _lastFrameIter = _renderQueue.end(); _renderSurface->fillRect(Common::Rect(0, 0, _renderSurface->h, _renderSurface->w), _renderSurface->format.ARGBToColor(255, 0, 0, 0)); g_system->copyRectToScreen((byte *)_renderSurface->getPixels(), _renderSurface->pitch, 0, 0, _renderSurface->w, _renderSurface->h); @@ -678,14 +569,10 @@ void BaseRenderOSystem::endSaveLoad() { } bool BaseRenderOSystem::startSpriteBatch() { - _spriteBatch = true; - _batchNum = 1; return STATUS_OK; } bool BaseRenderOSystem::endSpriteBatch() { - _spriteBatch = false; - _batchNum = 0; return STATUS_OK; } diff --git a/engines/wintermute/base/gfx/osystem/base_render_osystem.h b/engines/wintermute/base/gfx/osystem/base_render_osystem.h index 306563af3b..8996c8b2e8 100644 --- a/engines/wintermute/base/gfx/osystem/base_render_osystem.h +++ b/engines/wintermute/base/gfx/osystem/base_render_osystem.h @@ -62,6 +62,8 @@ public: BaseRenderOSystem(BaseGame *inGame); ~BaseRenderOSystem(); + typedef Common::List<RenderTicket *>::iterator RenderQueueIterator; + Common::String getName() const; bool initRenderer(int width, int height, bool windowed) override; @@ -79,11 +81,16 @@ public: void invalidateTicket(RenderTicket *renderTicket); void invalidateTicketsFromSurface(BaseSurfaceOSystem *surf); /** - * Insert a ticket into the queue, adding a dirty rect if it's - * new, or out-of-order from last draw from the ticket. - * param renderTicket the ticket to be added. + * Insert a new ticket into the queue, adding a dirty rect + * @param renderTicket the ticket to be added. */ void drawFromTicket(RenderTicket *renderTicket); + /** + * Re-insert an existing ticket into the queue, adding a dirty rect + * out-of-order from last draw from the ticket. + * @param ticket iterator pointing to the ticket to be added. + */ + void drawFromQueuedTicket(const RenderQueueIterator &ticket); bool setViewport(int left, int top, int right, int bottom) override; bool setViewport(Rect32 *rect) override { return BaseRenderer::setViewport(rect); } @@ -104,7 +111,6 @@ public: virtual bool endSpriteBatch() override; void endSaveLoad(); void drawSurface(BaseSurfaceOSystem *owner, const Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRect, TransformStruct &transform); - void repeatLastDraw(int offsetX, int offsetY, int numTimesX, int numTimesY); BaseSurface *createSurface() override; private: /** @@ -120,14 +126,11 @@ private: void drawFromSurface(RenderTicket *ticket); // Dirty-rects: void drawFromSurface(RenderTicket *ticket, Common::Rect *dstRect, Common::Rect *clipRect); - typedef Common::List<RenderTicket *>::iterator RenderQueueIterator; Common::Rect *_dirtyRect; Common::List<RenderTicket *> _renderQueue; - RenderQueueIterator _lastAddedTicket; - RenderTicket *_previousTicket; bool _needsFlip; - uint32 _drawNum; ///< The global number of the current draw-operation. + RenderQueueIterator _lastFrameIter; Common::Rect _renderRect; Graphics::Surface *_renderSurface; Graphics::Surface *_blankSurface; @@ -138,15 +141,12 @@ private: int _borderBottom; bool _disableDirtyRects; - uint32 _tempDisableDirtyRects; - bool _spriteBatch; - uint32 _batchNum; float _ratioX; float _ratioY; - uint32 _colorMod; uint32 _clearColor; bool _skipThisFrame; + int _lastScreenChangeID; // previous value of OSystem::getScreenChangeID() }; } // End of namespace Wintermute diff --git a/engines/wintermute/base/gfx/osystem/base_surface_osystem.cpp b/engines/wintermute/base/gfx/osystem/base_surface_osystem.cpp index e04af45dd9..9ec8573a87 100644 --- a/engines/wintermute/base/gfx/osystem/base_surface_osystem.cpp +++ b/engines/wintermute/base/gfx/osystem/base_surface_osystem.cpp @@ -37,6 +37,7 @@ #include "graphics/decoders/jpeg.h" #include "graphics/decoders/tga.h" #include "engines/wintermute/graphics/transparent_surface.h" +#include "engines/wintermute/graphics/transform_tools.h" #include "graphics/pixelformat.h" #include "graphics/surface.h" #include "common/stream.h" @@ -381,6 +382,14 @@ bool BaseSurfaceOSystem::displayTransform(int x, int y, Rect32 rect, Rect32 newR } ////////////////////////////////////////////////////////////////////////// +bool BaseSurfaceOSystem::displayTiled(int x, int y, Rect32 rect, int numTimesX, int numTimesY) { + assert(numTimesX > 0 && numTimesY > 0); + TransformStruct transform(numTimesX, numTimesY); + return drawSprite(x, y, &rect, nullptr, transform); +} + + +////////////////////////////////////////////////////////////////////////// bool BaseSurfaceOSystem::drawSprite(int x, int y, Rect32 *rect, Rect32 *newRect, TransformStruct transform) { BaseRenderOSystem *renderer = static_cast<BaseRenderOSystem *>(_gameRef->_renderer); @@ -392,13 +401,6 @@ bool BaseSurfaceOSystem::drawSprite(int x, int y, Rect32 *rect, Rect32 *newRect, transform._rgbaMod = renderer->_forceAlphaColor; } -#if 0 // These are kept for reference if BlendMode is reimplemented at some point. - if (alphaDisable) { - SDL_SetTextureBlendMode(_texture, SDL_BLENDMODE_NONE); - } else { - SDL_SetTextureBlendMode(_texture, SDL_BLENDMODE_BLEND); - } -#endif // TODO: This _might_ miss the intended behaviour by 1 in each direction // But I think it fits the model used in Wintermute. Common::Rect srcRect; @@ -408,24 +410,26 @@ bool BaseSurfaceOSystem::drawSprite(int x, int y, Rect32 *rect, Rect32 *newRect, srcRect.setHeight(rect->bottom - rect->top); Common::Rect position; - position.left = x + transform._offset.x; - position.top = y + transform._offset.y; - // Crop off-by-ones: - if (position.left == -1) { - position.left = 0; // TODO: Something is wrong - } - if (position.top == -1) { - position.top = 0; // TODO: Something is wrong - } if (newRect) { position.top = y; position.left = x; position.setWidth(newRect->width()); position.setHeight(newRect->height()); } else { - position.setWidth((int16)((float)srcRect.width() * transform._zoom.x / kDefaultZoomX)); - position.setHeight((int16)((float)srcRect.height() * transform._zoom.y / kDefaultZoomY)); + + Rect32 r; + r.top = 0; + r.left = 0; + r.setWidth(rect->width()); + r.setHeight(rect->height()); + + r = TransformTools::newRect(r, transform, 0); + + position.top = r.top + y + transform._offset.y; + position.left = r.left + x + transform._offset.x; + position.setWidth(r.width() * transform._numTimesX); + position.setHeight(r.height() * transform._numTimesY); } renderer->modTargetRect(&position); @@ -441,12 +445,6 @@ bool BaseSurfaceOSystem::drawSprite(int x, int y, Rect32 *rect, Rect32 *newRect, return STATUS_OK; } -bool BaseSurfaceOSystem::repeatLastDisplayOp(int offsetX, int offsetY, int numTimesX, int numTimesY) { - BaseRenderOSystem *renderer = static_cast<BaseRenderOSystem *>(_gameRef->_renderer); - renderer->repeatLastDraw(offsetX, offsetY, numTimesX, numTimesY); - return STATUS_OK; -} - bool BaseSurfaceOSystem::putSurface(const Graphics::Surface &surface, bool hasAlpha) { _loaded = true; _surface->free(); diff --git a/engines/wintermute/base/gfx/osystem/base_surface_osystem.h b/engines/wintermute/base/gfx/osystem/base_surface_osystem.h index 340a5a5ffc..67f45f66db 100644 --- a/engines/wintermute/base/gfx/osystem/base_surface_osystem.h +++ b/engines/wintermute/base/gfx/osystem/base_surface_osystem.h @@ -58,7 +58,7 @@ public: bool display(int x, int y, Rect32 rect, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) override; bool displayZoom(int x, int y, Rect32 rect, float zoomX, float zoomY, uint32 alpha = kDefaultRgbaMod, bool transparent = false, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) override; bool displayTransform(int x, int y, Rect32 rect, Rect32 newRect, const TransformStruct &transform) override; - bool repeatLastDisplayOp(int offsetX, int offsetY, int numTimesX, int numTimesY) override; + virtual bool displayTiled(int x, int y, Rect32 rect, int numTimesX, int numTimesY); virtual bool putSurface(const Graphics::Surface &surface, bool hasAlpha = false) override; /* static unsigned DLL_CALLCONV ReadProc(void *buffer, unsigned size, unsigned count, fi_handle handle); static int DLL_CALLCONV SeekProc(fi_handle handle, long offset, int origin); diff --git a/engines/wintermute/base/gfx/osystem/render_ticket.cpp b/engines/wintermute/base/gfx/osystem/render_ticket.cpp index d79d5bac4b..1cd35e3b04 100644 --- a/engines/wintermute/base/gfx/osystem/render_ticket.cpp +++ b/engines/wintermute/base/gfx/osystem/render_ticket.cpp @@ -38,11 +38,9 @@ RenderTicket::RenderTicket(BaseSurfaceOSystem *owner, const Graphics::Surface *s _owner(owner), _srcRect(*srcRect), _dstRect(*dstRect), - _drawNum(0), _isValid(true), _wantsDraw(true), _transform(transform) { - _batchNum = 0; if (surf) { _surface = new Graphics::Surface(); _surface->create((uint16)srcRect->width(), (uint16)srcRect->height(), surf->format); @@ -52,13 +50,22 @@ RenderTicket::RenderTicket(BaseSurfaceOSystem *owner, const Graphics::Surface *s memcpy(_surface->getBasePtr(0, i), surf->getBasePtr(srcRect->left, srcRect->top + i), srcRect->width() * _surface->format.bytesPerPixel); } // Then scale it if necessary + // + // NB: The numTimesX/numTimesY properties don't yet mix well with + // scaling and rotation, but there is no need for that functionality at + // the moment. + // NB: Mirroring and rotation are probably done in the wrong order. + // (Mirroring should most likely be done before rotation. See also + // TransformTools.) if (_transform._angle != kDefaultAngle) { TransparentSurface src(*_surface, false); Graphics::Surface *temp = src.rotoscale(transform); _surface->free(); delete _surface; _surface = temp; - } else if (dstRect->width() != srcRect->width() || dstRect->height() != srcRect->height()) { + } else if ((dstRect->width() != srcRect->width() || + dstRect->height() != srcRect->height()) && + _transform._numTimesX * _transform._numTimesY == 1) { TransparentSurface src(*_surface, false); Graphics::Surface *temp = src.scale(dstRect->width(), dstRect->height()); _surface->free(); @@ -67,14 +74,6 @@ RenderTicket::RenderTicket(BaseSurfaceOSystem *owner, const Graphics::Surface *s } } else { _surface = nullptr; - - if (transform._angle != kDefaultAngle) { // Make sure comparison-tickets get the correct width - Rect32 newDstRect; - Point32 newHotspot; - newDstRect = TransformTools::newRect(_srcRect, transform, &newHotspot); - _dstRect.setWidth(newDstRect.right - newDstRect.left); - _dstRect.setHeight(newDstRect.bottom - newDstRect.top); - } } } @@ -87,7 +86,6 @@ RenderTicket::~RenderTicket() { bool RenderTicket::operator==(const RenderTicket &t) const { if ((t._owner != _owner) || - (t._batchNum != _batchNum) || (t._transform != _transform) || (t._dstRect != _dstRect) || (t._srcRect != _srcRect) @@ -107,12 +105,24 @@ void RenderTicket::drawToSurface(Graphics::Surface *_targetSurface) const { if (_owner) { if (_transform._alphaDisable) { - src._alphaMode = TransparentSurface::ALPHA_OPAQUE; + src.setAlphaMode(TransparentSurface::ALPHA_OPAQUE); } else { - src._alphaMode = _owner->getAlphaType(); + src.setAlphaMode(_owner->getAlphaType()); + } + } + + int y = _dstRect.top; + int w = _dstRect.width() / _transform._numTimesX; + int h = _dstRect.height() / _transform._numTimesY; + + for (int ry = 0; ry < _transform._numTimesY; ++ry) { + int x = _dstRect.left; + for (int rx = 0; rx < _transform._numTimesX; ++rx) { + src.blit(*_targetSurface, x, y, _transform._flip, &clipRect, _transform._rgbaMod, clipRect.width(), clipRect.height()); + x += w; } + y += h; } - src.blit(*_targetSurface, _dstRect.left, _dstRect.top, _transform._flip, &clipRect, _transform._rgbaMod, clipRect.width(), clipRect.height()); } void RenderTicket::drawToSurface(Graphics::Surface *_targetSurface, Common::Rect *dstRect, Common::Rect *clipRect) const { @@ -121,18 +131,58 @@ void RenderTicket::drawToSurface(Graphics::Surface *_targetSurface, Common::Rect if (!clipRect) { doDelete = true; clipRect = new Common::Rect(); - clipRect->setWidth(getSurface()->w); - clipRect->setHeight(getSurface()->h); + clipRect->setWidth(getSurface()->w * _transform._numTimesX); + clipRect->setHeight(getSurface()->h * _transform._numTimesY); } if (_owner) { if (_transform._alphaDisable) { - src._alphaMode = TransparentSurface::ALPHA_OPAQUE; + src.setAlphaMode(TransparentSurface::ALPHA_OPAQUE); } else { - src._alphaMode = _owner->getAlphaType(); + src.setAlphaMode(_owner->getAlphaType()); + } + } + + if (_transform._numTimesX * _transform._numTimesY == 1) { + + src.blit(*_targetSurface, dstRect->left, dstRect->top, _transform._flip, clipRect, _transform._rgbaMod, clipRect->width(), clipRect->height(), _transform._blendMode); + + } else { + + // clipRect is a subrect of the full numTimesX*numTimesY rect + Common::Rect subRect; + + int y = 0; + int w = getSurface()->w; + int h = getSurface()->h; + assert(w == _dstRect.width() / _transform._numTimesX); + assert(h == _dstRect.height() / _transform._numTimesY); + + int basex = dstRect->left - clipRect->left; + int basey = dstRect->top - clipRect->top; + + for (int ry = 0; ry < _transform._numTimesY; ++ry) { + int x = 0; + for (int rx = 0; rx < _transform._numTimesX; ++rx) { + + subRect.left = x; + subRect.top = y; + subRect.setWidth(w); + subRect.setHeight(h); + + if (subRect.intersects(*clipRect)) { + subRect.clip(*clipRect); + subRect.translate(-x, -y); + src.blit(*_targetSurface, basex + x + subRect.left, basey + y + subRect.top, _transform._flip, &subRect, _transform._rgbaMod, subRect.width(), subRect.height(), _transform._blendMode); + + } + + x += w; + } + y += h; } } - src.blit(*_targetSurface, dstRect->left, dstRect->top, _transform._flip, clipRect, _transform._rgbaMod, clipRect->width(), clipRect->height(), _transform._blendMode); + if (doDelete) { delete clipRect; } diff --git a/engines/wintermute/base/gfx/osystem/render_ticket.h b/engines/wintermute/base/gfx/osystem/render_ticket.h index 875102d01c..e824c09fe7 100644 --- a/engines/wintermute/base/gfx/osystem/render_ticket.h +++ b/engines/wintermute/base/gfx/osystem/render_ticket.h @@ -52,7 +52,7 @@ class BaseSurfaceOSystem; class RenderTicket { public: RenderTicket(BaseSurfaceOSystem *owner, const Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRest, TransformStruct transform); - RenderTicket() : _isValid(true), _wantsDraw(false), _drawNum(0), _transform(TransformStruct()) {} + RenderTicket() : _isValid(true), _wantsDraw(false), _transform(TransformStruct()) {} ~RenderTicket(); const Graphics::Surface *getSurface() const { return _surface; } // Non-dirty-rects: @@ -61,11 +61,9 @@ public: void drawToSurface(Graphics::Surface *_targetSurface, Common::Rect *dstRect, Common::Rect *clipRect) const; Common::Rect _dstRect; - uint32 _batchNum; bool _isValid; bool _wantsDraw; - uint32 _drawNum; TransformStruct _transform; diff --git a/engines/wintermute/graphics/transform_struct.cpp b/engines/wintermute/graphics/transform_struct.cpp index 643c6b413f..822c06f42f 100644 --- a/engines/wintermute/graphics/transform_struct.cpp +++ b/engines/wintermute/graphics/transform_struct.cpp @@ -35,6 +35,8 @@ void TransformStruct::init(Point32 zoom, uint32 angle, Point32 hotspot, bool alp _flip += TransparentSurface::FLIP_H * mirrorX; _flip += TransparentSurface::FLIP_V * mirrorY; _offset = offset; + _numTimesX = 1; + _numTimesY = 1; } TransformStruct::TransformStruct(int32 zoomX, int32 zoomY, uint32 angle, int32 hotspotX, int32 hotspotY, TSpriteBlendMode blendMode, uint32 rgbaMod, bool mirrorX, bool mirrorY, int32 offsetX, int32 offsetY) { @@ -83,6 +85,19 @@ TransformStruct::TransformStruct(int32 zoomX, int32 zoomY, uint32 angle, int32 h Point32(kDefaultOffsetX, kDefaultOffsetY)); } +TransformStruct::TransformStruct(int32 numTimesX, int32 numTimesY) { + init(Point32(kDefaultZoomX, kDefaultZoomY), + kDefaultAngle, + Point32(kDefaultHotspotX, kDefaultHotspotY), + false, + BLEND_NORMAL, + kDefaultRgbaMod, + false, false, + Point32(kDefaultOffsetX, kDefaultOffsetY)); + _numTimesX = numTimesX; + _numTimesY = numTimesY; +} + TransformStruct::TransformStruct() { init(Point32(kDefaultZoomX, kDefaultZoomY), kDefaultAngle, diff --git a/engines/wintermute/graphics/transform_struct.h b/engines/wintermute/graphics/transform_struct.h index 90a4c1f846..d5a03ea331 100644 --- a/engines/wintermute/graphics/transform_struct.h +++ b/engines/wintermute/graphics/transform_struct.h @@ -51,6 +51,7 @@ public: TransformStruct(float zoomX, float zoomY, uint32 angle, int32 hotspotX, int32 hotspotY, TSpriteBlendMode blendMode, uint32 alpha, bool mirrorX = false, bool mirrorY = false, int32 offsetX = 0, int32 offsetY = 0); TransformStruct(int32 zoomX, int32 zoomY, TSpriteBlendMode blendMode, uint32 alpha, bool mirrorX = false, bool mirrorY = false); TransformStruct(int32 zoomX, int32 zoomY, uint32 angle, int32 hotspotX = 0, int32 hotspotY = 0); + TransformStruct(int32 numTimesX, int32 numTimesY); TransformStruct(); Point32 _zoom; ///< Zoom; 100 = no zoom @@ -61,6 +62,8 @@ public: TSpriteBlendMode _blendMode; uint32 _rgbaMod; ///< RGBa Point32 _offset; + int32 _numTimesX; + int32 _numTimesY; bool getMirrorX() const; bool getMirrorY() const; @@ -72,7 +75,9 @@ public: compare._offset == _offset && compare._alphaDisable == _alphaDisable && compare._rgbaMod == _rgbaMod && - compare._blendMode == _blendMode + compare._blendMode == _blendMode && + compare._numTimesX == _numTimesX && + compare._numTimesY == _numTimesY ); } diff --git a/engines/wintermute/graphics/transform_tools.cpp b/engines/wintermute/graphics/transform_tools.cpp index ebf9092aaa..dc92cdbbfd 100644 --- a/engines/wintermute/graphics/transform_tools.cpp +++ b/engines/wintermute/graphics/transform_tools.cpp @@ -26,11 +26,23 @@ namespace Wintermute { -FloatPoint TransformTools::transformPoint(const FloatPoint &point, const float rotate, const Point32 &zoom, const bool mirrorX, const bool mirrorY) { +FloatPoint TransformTools::transformPoint(FloatPoint point, const float rotate, const Point32 &zoom, const bool mirrorX, const bool mirrorY) { float rotateRad = rotate * M_PI / 180.0f; + float x = point.x; + float y = point.y; + x = (x * zoom.x) / kDefaultZoomX; + y = (y * zoom.y) / kDefaultZoomY; +#if 0 + // TODO: Mirroring should be done before rotation, but the blitting + // code does the inverse, so we match that for now. + if (mirrorX) + x *= -1; + if (mirrorY) + y *= -1; +#endif FloatPoint newPoint; - newPoint.x = (point.x * cos(rotateRad) - point.y * sin(rotateRad)) * zoom.x / kDefaultZoomX; - newPoint.y = (point.x * sin(rotateRad) + point.y * cos(rotateRad)) * zoom.y / kDefaultZoomY; + newPoint.x = x * cos(rotateRad) - y * sin(rotateRad); + newPoint.y = x * sin(rotateRad) + y * cos(rotateRad); if (mirrorX) { newPoint.x *= -1; } @@ -58,10 +70,12 @@ Rect32 TransformTools::newRect(const Rect32 &oldRect, const TransformStruct &tra float left = MIN(nw1.x, MIN(ne1.x, MIN(sw1.x, se1.x))); float right = MAX(nw1.x, MAX(ne1.x, MAX(sw1.x, se1.x))); - Rect32 res; - newHotspot->y = (uint32)(-floor(top)); - newHotspot->x = (uint32)(-floor(left)); + if (newHotspot) { + newHotspot->y = (uint32)(-floor(top)); + newHotspot->x = (uint32)(-floor(left)); + } + Rect32 res; res.top = (int32)(floor(top)) + transform._hotspot.y; res.bottom = (int32)(ceil(bottom)) + transform._hotspot.y; res.left = (int32)(floor(left)) + transform._hotspot.x; diff --git a/engines/wintermute/graphics/transform_tools.h b/engines/wintermute/graphics/transform_tools.h index c92b81fd11..9a73e3b69f 100644 --- a/engines/wintermute/graphics/transform_tools.h +++ b/engines/wintermute/graphics/transform_tools.h @@ -34,7 +34,7 @@ public: /** * Basic transform (scale + rotate) for a single point */ - static FloatPoint transformPoint(const FloatPoint &point, const float rotate, const Point32 &zoom, const bool mirrorX = false, const bool mirrorY = false); + static FloatPoint transformPoint(FloatPoint point, const float rotate, const Point32 &zoom, const bool mirrorX = false, const bool mirrorY = false); /** * @param &point the point on which the transform is to be applied diff --git a/engines/wintermute/graphics/transparent_surface.cpp b/engines/wintermute/graphics/transparent_surface.cpp index 411ff1f477..43deb62db6 100644 --- a/engines/wintermute/graphics/transparent_surface.cpp +++ b/engines/wintermute/graphics/transparent_surface.cpp @@ -17,8 +17,16 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * + * The bottom part of this is file is adapted from SDL_rotozoom.c. The + * relevant copyright notice for those specific functions can be found at the + * top of that section. + * */ + + #include "common/algorithm.h" #include "common/endian.h" #include "common/util.h" @@ -29,6 +37,8 @@ #include "engines/wintermute/graphics/transparent_surface.h" #include "engines/wintermute/graphics/transform_tools.h" +//#define ENABLE_BILINEAR + namespace Wintermute { void doBlitOpaqueFast(byte *ino, byte *outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep); @@ -38,26 +48,26 @@ void doBlitBinaryFast(byte *ino, byte *outo, uint32 width, uint32 height, uint32 class BlenderAdditive { public: - static void blendPixel(byte ina, byte inr, byte ing, byte inb, byte *outa, byte *outr, byte *outg, byte *outb); - static void blendPixel(byte ina, byte inr, byte ing, byte inb, byte *outa, byte *outr, byte *outg, byte *outb, byte *ca, byte *cr, byte *cg, byte *cb); - static void blendPixel(byte *in, byte *out); - static void blendPixel(byte *in, byte *out, int colorMod); + inline void blendPixel(byte ina, byte inr, byte ing, byte inb, byte *outa, byte *outr, byte *outg, byte *outb); + inline void blendPixel(byte ina, byte inr, byte ing, byte inb, byte *outa, byte *outr, byte *outg, byte *outb, byte *ca, byte *cr, byte *cg, byte *cb); + inline void blendPixel(byte *in, byte *out); + inline void blendPixel(byte *in, byte *out, int colorMod); }; class BlenderSubtractive { public: - static void blendPixel(byte ina, byte inr, byte ing, byte inb, byte *outa, byte *outr, byte *outg, byte *outb); - static void blendPixel(byte ina, byte inr, byte ing, byte inb, byte *outa, byte *outr, byte *outg, byte *outb, byte *ca, byte *cr, byte *cg, byte *cb); - static void blendPixel(byte *in, byte *out); - static void blendPixel(byte *in, byte *out, int colorMod); + inline void blendPixel(byte ina, byte inr, byte ing, byte inb, byte *outa, byte *outr, byte *outg, byte *outb); + inline void blendPixel(byte ina, byte inr, byte ing, byte inb, byte *outa, byte *outr, byte *outg, byte *outb, byte *ca, byte *cr, byte *cg, byte *cb); + inline void blendPixel(byte *in, byte *out); + inline void blendPixel(byte *in, byte *out, int colorMod); }; class BlenderNormal { public: - static void blendPixel(byte ina, byte inr, byte ing, byte inb, byte *outa, byte *outr, byte *outg, byte *outb); - static void blendPixel(byte ina, byte inr, byte ing, byte inb, byte *outa, byte *outr, byte *outg, byte *outb, byte *ca, byte *cr, byte *cg, byte *cb); - static void blendPixel(byte *in, byte *out); - static void blendPixel(byte *in, byte *out, int colorMod); + inline void blendPixel(byte ina, byte inr, byte ing, byte inb, byte *outa, byte *outr, byte *outg, byte *outb); + inline void blendPixel(byte ina, byte inr, byte ing, byte inb, byte *outa, byte *outr, byte *outg, byte *outb, byte *ca, byte *cr, byte *cg, byte *cb); + inline void blendPixel(byte *in, byte *out); + inline void blendPixel(byte *in, byte *out, int colorMod); }; /** @@ -269,119 +279,6 @@ void BlenderAdditive::blendPixel(byte ina, byte inr, byte ing, byte inb, byte *o } } -#if ENABLE_BILINEAR -void TransparentSurface::copyPixelBilinear(float projX, float projY, int dstX, int dstY, const Common::Rect &srcRect, const Common::Rect &dstRect, const TransparentSurface *src, TransparentSurface *dst) { - - // TODO: Do some optimization on this. This is completely naive. - - int srcW = srcRect.width(); - int srcH = srcRect.height(); - int dstW = dstRect.width(); - int dstH = dstRect.height(); - - assert(dstX >= 0 && dstX < dstW); - assert(dstY >= 0 && dstY < dstH); - - float x1 = floor(projX); - float x2 = ceil(projX); - float y1 = floor(projY); - float y2 = ceil(projY); - - uint32 Q11, Q12, Q21, Q22; - - if (x1 >= srcW || x1 < 0 || y1 >= srcH || y1 < 0) { - Q11 = 0; - } else { - Q11 = READ_UINT32((const byte *)src->getBasePtr((int)(x1 + srcRect.left), (int)(y1 + srcRect.top))); - } - - if (x1 >= srcW || x1 < 0 || y2 >= srcH || y2 < 0) { - Q12 = 0; - } else { - Q12 = READ_UINT32((const byte *)src->getBasePtr((int)(x1 + srcRect.left), (int)(y2 + srcRect.top))); - } - - if (x2 >= srcW || x2 < 0 || y1 >= srcH || y1 < 0) { - Q21 = 0; - } else { - Q21 = READ_UINT32((const byte *)src->getBasePtr((int)(x2 + srcRect.left), (int)(y1 + srcRect.top))); - } - - if (x2 >= srcW || x2 < 0 || y2 >= srcH || y2 < 0) { - Q22 = 0; - } else { - Q22 = READ_UINT32((const byte *)src->getBasePtr((int)(x2 + srcRect.left), (int)(y2 + srcRect.top))); - } - - byte *Q11s = (byte *)&Q11; - byte *Q12s = (byte *)&Q12; - byte *Q21s = (byte *)&Q21; - byte *Q22s = (byte *)&Q22; - - uint32 color; - byte *dest = (byte *)&color; - - float q11x = (x2 - projX); - float q11y = (y2 - projY); - float q21x = (projX - x1); - float q21y = (y2 - projY); - float q12x = (x2 - projX); - float q12y = (projY - y1); - - if (x1 == x2 && y1 == y2) { - for (int c = 0; c < 4; c++) { - dest[c] = ((float)Q11s[c]); - } - } else { - - if (x1 == x2) { - q11x = 0.5; - q12x = 0.5; - q21x = 0.5; - } else if (y1 == y2) { - q11y = 0.5; - q12y = 0.5; - q21y = 0.5; - } - - for (int c = 0; c < 4; c++) { - dest[c] = (byte)( - ((float)Q11s[c]) * q11x * q11y + - ((float)Q21s[c]) * q21x * q21y + - ((float)Q12s[c]) * q12x * q12y + - ((float)Q22s[c]) * (1.0 - - q11x * q11y - - q21x * q21y - - q12x * q12y) - ); - } - } - WRITE_UINT32((byte *)dst->getBasePtr(dstX + dstRect.left, dstY + dstRect.top), color); -} -#else -void TransparentSurface::copyPixelNearestNeighbor(float projX, float projY, int dstX, int dstY, const Common::Rect &srcRect, const Common::Rect &dstRect, const TransparentSurface *src, TransparentSurface *dst) { - - // TODO: Have the Rect arguments become completely useless at this point? - - int srcW = srcRect.width(); - int srcH = srcRect.height(); - int dstW = dstRect.width(); - int dstH = dstRect.height(); - - assert(dstX >= 0 && dstX < dstW); - assert(dstY >= 0 && dstY < dstH); - - uint32 color; - - if (projX >= srcW || projX < 0 || projY >= srcH || projY < 0) { - color = 0; - } else { - color = READ_UINT32((const byte *)src->getBasePtr((int)projX, (int)projY)); - } - - WRITE_UINT32((byte *)dst->getBasePtr(dstX, dstY), color); -} -#endif TransparentSurface::TransparentSurface() : Surface(), _alphaMode(ALPHA_FULL) {} @@ -465,7 +362,7 @@ void doBlitBinaryFast(byte *ino, byte *outo, uint32 width, uint32 height, uint32 template<class Blender> void doBlit(byte *ino, byte *outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep, uint32 color) { - + Blender b; byte *in; byte *out; @@ -481,7 +378,7 @@ void doBlit(byte *ino, byte *outo, uint32 width, uint32 height, uint32 pitch, in byte *outg = &out[TransparentSurface::kGIndex]; byte *outb = &out[TransparentSurface::kBIndex]; - Blender::blendPixel(in[TransparentSurface::kAIndex], + b.blendPixel(in[TransparentSurface::kAIndex], in[TransparentSurface::kRIndex], in[TransparentSurface::kGIndex], in[TransparentSurface::kBIndex], @@ -510,7 +407,7 @@ void doBlit(byte *ino, byte *outo, uint32 width, uint32 height, uint32 pitch, in byte *outg = &out[TransparentSurface::kGIndex]; byte *outb = &out[TransparentSurface::kBIndex]; - Blender::blendPixel(in[TransparentSurface::kAIndex], + b.blendPixel(in[TransparentSurface::kAIndex], in[TransparentSurface::kRIndex], in[TransparentSurface::kGIndex], in[TransparentSurface::kBIndex], @@ -655,6 +552,88 @@ Common::Rect TransparentSurface::blit(Graphics::Surface &target, int posX, int p return retSize; } +/** + * Writes a color key to the alpha channel of the surface + * @param rKey the red component of the color key + * @param gKey the green component of the color key + * @param bKey the blue component of the color key + * @param overwriteAlpha if true, all other alpha will be set fully opaque + */ +void TransparentSurface::applyColorKey(uint8 rKey, uint8 gKey, uint8 bKey, bool overwriteAlpha) { + assert(format.bytesPerPixel == 4); + for (int i = 0; i < h; i++) { + for (int j = 0; j < w; j++) { + uint32 pix = ((uint32 *)pixels)[i * w + j]; + uint8 r, g, b, a; + format.colorToARGB(pix, a, r, g, b); + if (r == rKey && g == gKey && b == bKey) { + a = 0; + ((uint32 *)pixels)[i * w + j] = format.ARGBToColor(a, r, g, b); + } else if (overwriteAlpha) { + a = 255; + ((uint32 *)pixels)[i * w + j] = format.ARGBToColor(a, r, g, b); + } + } + } +} + +TransparentSurface::AlphaType TransparentSurface::getAlphaMode() const { + return _alphaMode; +} + +void TransparentSurface::setAlphaMode(TransparentSurface::AlphaType mode) { + _alphaMode = mode; +} + + + + + + +/* + +The below two functions are adapted from SDL_rotozoom.c, +taken from SDL_gfx-2.0.18. + +Its copyright notice: + +============================================================================= +SDL_rotozoom.c: rotozoomer, zoomer and shrinker for 32bit or 8bit surfaces + +Copyright (C) 2001-2012 Andreas Schiffler + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + +Andreas Schiffler -- aschiffler at ferzkopp dot net +============================================================================= + + +The functions have been adapted for different structures and coordinate +systems. + +*/ + + + + + TransparentSurface *TransparentSurface::rotoscale(const TransformStruct &transform) const { assert(transform._angle != 0); // This would not be ideal; rotoscale() should never be called in conditional branches where angle = 0 anyway. @@ -667,33 +646,98 @@ TransparentSurface *TransparentSurface::rotoscale(const TransformStruct &transfo TransparentSurface *target = new TransparentSurface(); assert(format.bytesPerPixel == 4); + int srcW = w; + int srcH = h; int dstW = dstRect.width(); int dstH = dstRect.height(); target->create((uint16)dstW, (uint16)dstH, this->format); + if (transform._zoom.x == 0 || transform._zoom.y == 0) + return target; + uint32 invAngle = 360 - (transform._angle % 360); float invCos = cos(invAngle * M_PI / 180.0); float invSin = sin(invAngle * M_PI / 180.0); - float targX; - float targY; - for (int y = 0; y < dstH; y++) { - for (int x = 0; x < dstW; x++) { - int x1 = x - newHotspot.x; - int y1 = y - newHotspot.y; + struct tColorRGBA { byte r; byte g; byte b; byte a; }; + int icosx = (int)(invCos * (65536.0f * kDefaultZoomX / transform._zoom.x)); + int isinx = (int)(invSin * (65536.0f * kDefaultZoomX / transform._zoom.x)); + int icosy = (int)(invCos * (65536.0f * kDefaultZoomY / transform._zoom.y)); + int isiny = (int)(invSin * (65536.0f * kDefaultZoomY / transform._zoom.y)); - targX = ((x1 * invCos - y1 * invSin)) * kDefaultZoomX / transform._zoom.x + srcRect.left; - targY = ((x1 * invSin + y1 * invCos)) * kDefaultZoomY / transform._zoom.y + srcRect.top; - targX += transform._hotspot.x; - targY += transform._hotspot.y; + bool flipx = false, flipy = false; // TODO: See mirroring comment in RenderTicket ctor -#if ENABLE_BILINEAR - copyPixelBilinear(targX, targY, x, y, srcRect, dstRect, this, target); + int xd = (srcRect.left + transform._hotspot.x) << 16; + int yd = (srcRect.top + transform._hotspot.y) << 16; + int cx = newHotspot.x; + int cy = newHotspot.y; + + int ax = -icosx * cx; + int ay = -isiny * cx; + int sw = srcW - 1; + int sh = srcH - 1; + + tColorRGBA *pc = (tColorRGBA*)target->getBasePtr(0, 0); + + for (int y = 0; y < dstH; y++) { + int t = cy - y; + int sdx = ax + (isinx * t) + xd; + int sdy = ay - (icosy * t) + yd; + for (int x = 0; x < dstW; x++) { + int dx = (sdx >> 16); + int dy = (sdy >> 16); + if (flipx) dx = sw - dx; + if (flipy) dy = sh - dy; + +#ifdef ENABLE_BILINEAR + if ((dx > -1) && (dy > -1) && (dx < sw) && (dy < sh)) { + const tColorRGBA *sp = (const tColorRGBA *)getBasePtr(dx, dy); + tColorRGBA c00, c01, c10, c11, cswap; + c00 = *sp; + sp += 1; + c01 = *sp; + sp += (this->pitch/4); + c11 = *sp; + sp -= 1; + c10 = *sp; + if (flipx) { + cswap = c00; c00=c01; c01=cswap; + cswap = c10; c10=c11; c11=cswap; + } + if (flipy) { + cswap = c00; c00=c10; c10=cswap; + cswap = c01; c01=c11; c11=cswap; + } + /* + * Interpolate colors + */ + int ex = (sdx & 0xffff); + int ey = (sdy & 0xffff); + int t1, t2; + t1 = ((((c01.r - c00.r) * ex) >> 16) + c00.r) & 0xff; + t2 = ((((c11.r - c10.r) * ex) >> 16) + c10.r) & 0xff; + pc->r = (((t2 - t1) * ey) >> 16) + t1; + t1 = ((((c01.g - c00.g) * ex) >> 16) + c00.g) & 0xff; + t2 = ((((c11.g - c10.g) * ex) >> 16) + c10.g) & 0xff; + pc->g = (((t2 - t1) * ey) >> 16) + t1; + t1 = ((((c01.b - c00.b) * ex) >> 16) + c00.b) & 0xff; + t2 = ((((c11.b - c10.b) * ex) >> 16) + c10.b) & 0xff; + pc->b = (((t2 - t1) * ey) >> 16) + t1; + t1 = ((((c01.a - c00.a) * ex) >> 16) + c00.a) & 0xff; + t2 = ((((c11.a - c10.a) * ex) >> 16) + c10.a) & 0xff; + pc->a = (((t2 - t1) * ey) >> 16) + t1; + } #else - copyPixelNearestNeighbor(targX, targY, x, y, srcRect, dstRect, this, target); + if ((dx >= 0) && (dy >= 0) && (dx < srcW) && (dy < srcH)) { + const tColorRGBA *sp = (const tColorRGBA *)getBasePtr(dx, dy); + *pc = *sp; + } #endif + sdx += icosx; + sdy += isiny; + pc++; } } return target; @@ -715,47 +759,173 @@ TransparentSurface *TransparentSurface::scale(uint16 newWidth, uint16 newHeight) target->create((uint16)dstW, (uint16)dstH, this->format); +#ifdef ENABLE_BILINEAR - float projX; - float projY; - for (int y = 0; y < dstH; y++) { - for (int x = 0; x < dstW; x++) { - projX = x / (float)dstW * srcW; - projY = y / (float)dstH * srcH; -#if ENABLE_BILINEAR - copyPixelBilinear(projX, projY, x, y, srcRect, dstRect, this, target); -#else - copyPixelNearestNeighbor(projX, projY, x, y, srcRect, dstRect, this, target); -#endif + // NB: The actual order of these bytes may not be correct, but + // since all values are treated equal, that does not matter. + struct tColorRGBA { byte r; byte g; byte b; byte a; }; + + bool flipx = false, flipy = false; // TODO: See mirroring comment in RenderTicket ctor + + + int *sax = new int[dstW+1]; + int *say = new int[dstH+1]; + assert(sax && say); + + /* + * Precalculate row increments + */ + int spixelw = (srcW - 1); + int spixelh = (srcH - 1); + int sx = (int) (65536.0f * (float) spixelw / (float) (dstW - 1)); + int sy = (int) (65536.0f * (float) spixelh / (float) (dstH - 1)); + + /* Maximum scaled source size */ + int ssx = (srcW << 16) - 1; + int ssy = (srcH << 16) - 1; + + /* Precalculate horizontal row increments */ + int csx = 0; + int *csax = sax; + for (int x = 0; x <= dstW; x++) { + *csax = csx; + csax++; + csx += sx; + + /* Guard from overflows */ + if (csx > ssx) { + csx = ssx; } } - return target; -} + /* Precalculate vertical row increments */ + int csy = 0; + int *csay = say; + for (int y = 0; y <= dstH; y++) { + *csay = csy; + csay++; + csy += sy; + + /* Guard from overflows */ + if (csy > ssy) { + csy = ssy; + } + } -/** - * Writes a color key to the alpha channel of the surface - * @param rKey the red component of the color key - * @param gKey the green component of the color key - * @param bKey the blue component of the color key - * @param overwriteAlpha if true, all other alpha will be set fully opaque - */ -void TransparentSurface::applyColorKey(uint8 rKey, uint8 gKey, uint8 bKey, bool overwriteAlpha) { - assert(format.bytesPerPixel == 4); - for (int i = 0; i < h; i++) { - for (int j = 0; j < w; j++) { - uint32 pix = ((uint32 *)pixels)[i * w + j]; - uint8 r, g, b, a; - format.colorToARGB(pix, a, r, g, b); - if (r == rKey && g == gKey && b == bKey) { - a = 0; - ((uint32 *)pixels)[i * w + j] = format.ARGBToColor(a, r, g, b); - } else if (overwriteAlpha) { - a = 255; - ((uint32 *)pixels)[i * w + j] = format.ARGBToColor(a, r, g, b); + const tColorRGBA *sp = (const tColorRGBA *) getBasePtr(0,0); + tColorRGBA *dp = (tColorRGBA *) target->getBasePtr(0,0); + int spixelgap = srcW; + + if (flipx) + sp += spixelw; + if (flipy) + sp += spixelgap * spixelh; + + csay = say; + for (int y = 0; y < dstH; y++) { + const tColorRGBA *csp = sp; + csax = sax; + for (int x = 0; x < dstW; x++) { + /* + * Setup color source pointers + */ + int ex = (*csax & 0xffff); + int ey = (*csay & 0xffff); + int cx = (*csax >> 16); + int cy = (*csay >> 16); + + const tColorRGBA *c00, *c01, *c10, *c11; + c00 = sp; + c01 = sp; + c10 = sp; + if (cy < spixelh) { + if (flipy) + c10 -= spixelgap; + else + c10 += spixelgap; + } + c11 = c10; + if (cx < spixelw) { + if (flipx) { + c01--; + c11--; + } else { + c01++; + c11++; + } } + + /* + * Draw and interpolate colors + */ + int t1, t2; + t1 = ((((c01->r - c00->r) * ex) >> 16) + c00->r) & 0xff; + t2 = ((((c11->r - c10->r) * ex) >> 16) + c10->r) & 0xff; + dp->r = (((t2 - t1) * ey) >> 16) + t1; + t1 = ((((c01->g - c00->g) * ex) >> 16) + c00->g) & 0xff; + t2 = ((((c11->g - c10->g) * ex) >> 16) + c10->g) & 0xff; + dp->g = (((t2 - t1) * ey) >> 16) + t1; + t1 = ((((c01->b - c00->b) * ex) >> 16) + c00->b) & 0xff; + t2 = ((((c11->b - c10->b) * ex) >> 16) + c10->b) & 0xff; + dp->b = (((t2 - t1) * ey) >> 16) + t1; + t1 = ((((c01->a - c00->a) * ex) >> 16) + c00->a) & 0xff; + t2 = ((((c11->a - c10->a) * ex) >> 16) + c10->a) & 0xff; + dp->a = (((t2 - t1) * ey) >> 16) + t1; + + /* + * Advance source pointer x + */ + int *salastx = csax; + csax++; + int sstepx = (*csax >> 16) - (*salastx >> 16); + if (flipx) + sp -= sstepx; + else + sp += sstepx; + + /* + * Advance destination pointer x + */ + dp++; } + /* + * Advance source pointer y + */ + int *salasty = csay; + csay++; + int sstepy = (*csay >> 16) - (*salasty >> 16); + sstepy *= spixelgap; + if (flipy) + sp = csp - sstepy; + else + sp = csp + sstepy; } + + delete[] sax; + delete[] say; + +#else + + int *scaleCacheX = new int[dstW]; + for (int x = 0; x < dstW; x++) + scaleCacheX[x] = (x * srcW) / dstW; + + for (int y = 0; y < dstH; y++) { + uint32 *destP = (uint32 *)target->getBasePtr(0, y); + const uint32 *srcP = (const uint32 *)getBasePtr(0, (y * srcH) / dstH); + for (int x = 0; x < dstW; x++) + *destP++ = srcP[scaleCacheX[x]]; + } + delete[] scaleCacheX; + +#endif + + return target; + } + + + + } // End of namespace Wintermute diff --git a/engines/wintermute/graphics/transparent_surface.h b/engines/wintermute/graphics/transparent_surface.h index 821b5c5943..b887c05fa8 100644 --- a/engines/wintermute/graphics/transparent_surface.h +++ b/engines/wintermute/graphics/transparent_surface.h @@ -25,9 +25,6 @@ #include "graphics/surface.h" #include "engines/wintermute/graphics/transform_struct.h" -#define ENABLE_BILINEAR 0 - - /* * This code is based on Broken Sword 2.5 engine * @@ -53,31 +50,6 @@ struct TransparentSurface : public Graphics::Surface { void setColorKey(char r, char g, char b); void disableColorKey(); -#if ENABLE_BILINEAR - /* - * Pick color from a point in source and copy it to a pixel in target. - * The point in the source can be a float - we have subpixel accuracy in the arguments. - * We do bilinear interpolation to estimate the color of the point even if the - * point is specuified w/subpixel accuracy. - * - * @param projX, projY, point in the source to pick color from. - * @param dstX, dstY destionation pixel - * @param *src, *dst pointer to the source and dest surfaces - */ - static void copyPixelBilinear(float projX, float projY, int dstX, int dstY, const Common::Rect &srcRect, const Common::Rect &dstRect, const TransparentSurface *src, TransparentSurface *dst); -#else - /* - * Pick color from a point in source and copy it to a pixel in target. - * The point in the source can be a float - we have subpixel accuracy in the arguments. - * HOWEVER, this particular function just does nearest neighbor. - * Use copyPixelBilinear if you interpolation. - * - * @param projX, projY, point in the source to pick color from. - * @param dstX, dstY destionation pixel - * @param *src, *dst pointer to the source and dest surfaces - */ - static void copyPixelNearestNeighbor(float projX, float projY, int dstX, int dstY, const Common::Rect &srcRect, const Common::Rect &dstRect, const TransparentSurface *src, TransparentSurface *dst); -#endif // Enums /** @brief The possible flipping parameters for the blit methode. @@ -101,8 +73,6 @@ struct TransparentSurface : public Graphics::Surface { ALPHA_FULL = 2 }; - AlphaType _alphaMode; - #ifdef SCUMM_LITTLE_ENDIAN static const int kAIndex = 0; static const int kBIndex = 1; @@ -180,6 +150,11 @@ struct TransparentSurface : public Graphics::Surface { * */ TransparentSurface *rotoscale(const TransformStruct &transform) const; + AlphaType getAlphaMode() const; + void setAlphaMode(AlphaType); +private: + AlphaType _alphaMode; + }; /** diff --git a/engines/wintermute/ui/ui_button.cpp b/engines/wintermute/ui/ui_button.cpp index b2e6c3953b..42a873a0b4 100644 --- a/engines/wintermute/ui/ui_button.cpp +++ b/engines/wintermute/ui/ui_button.cpp @@ -103,7 +103,7 @@ UIButton::~UIButton() { ////////////////////////////////////////////////////////////////////////// bool UIButton::loadFile(const char *filename) { - byte *buffer = BaseFileManager::getEngineInstance()->readWholeFile(filename); + char *buffer = (char *)BaseFileManager::getEngineInstance()->readWholeFile(filename); if (buffer == nullptr) { _gameRef->LOG(0, "UIButton::LoadFile failed for file '%s'", filename); return STATUS_FAILED; @@ -162,7 +162,7 @@ TOKEN_DEF(PIXEL_PERFECT) TOKEN_DEF(EDITOR_PROPERTY) TOKEN_DEF_END ////////////////////////////////////////////////////////////////////////// -bool UIButton::loadBuffer(byte *buffer, bool complete) { +bool UIButton::loadBuffer(char *buffer, bool complete) { TOKEN_TABLE_START(commands) TOKEN_TABLE(BUTTON) TOKEN_TABLE(TEMPLATE) @@ -202,38 +202,38 @@ bool UIButton::loadBuffer(byte *buffer, bool complete) { TOKEN_TABLE(EDITOR_PROPERTY) TOKEN_TABLE_END - byte *params; + char *params; int cmd = 2; BaseParser parser; if (complete) { - if (parser.getCommand((char **)&buffer, commands, (char **)¶ms) != TOKEN_BUTTON) { + if (parser.getCommand(&buffer, commands, ¶ms) != TOKEN_BUTTON) { _gameRef->LOG(0, "'BUTTON' keyword expected."); return STATUS_FAILED; } buffer = params; } - while (cmd > 0 && (cmd = parser.getCommand((char **)&buffer, commands, (char **)¶ms)) > 0) { + while (cmd > 0 && (cmd = parser.getCommand(&buffer, commands, ¶ms)) > 0) { switch (cmd) { case TOKEN_TEMPLATE: - if (DID_FAIL(loadFile((char *)params))) { + if (DID_FAIL(loadFile(params))) { cmd = PARSERR_GENERIC; } break; case TOKEN_NAME: - setName((char *)params); + setName(params); break; case TOKEN_CAPTION: - setCaption((char *)params); + setCaption(params); break; case TOKEN_BACK: delete _back; _back = new UITiledImage(_gameRef); - if (!_back || DID_FAIL(_back->loadFile((char *)params))) { + if (!_back || DID_FAIL(_back->loadFile(params))) { delete _back; _back = nullptr; cmd = PARSERR_GENERIC; @@ -243,7 +243,7 @@ bool UIButton::loadBuffer(byte *buffer, bool complete) { case TOKEN_BACK_HOVER: delete _backHover; _backHover = new UITiledImage(_gameRef); - if (!_backHover || DID_FAIL(_backHover->loadFile((char *)params))) { + if (!_backHover || DID_FAIL(_backHover->loadFile(params))) { delete _backHover; _backHover = nullptr; cmd = PARSERR_GENERIC; @@ -253,7 +253,7 @@ bool UIButton::loadBuffer(byte *buffer, bool complete) { case TOKEN_BACK_PRESS: delete _backPress; _backPress = new UITiledImage(_gameRef); - if (!_backPress || DID_FAIL(_backPress->loadFile((char *)params))) { + if (!_backPress || DID_FAIL(_backPress->loadFile(params))) { delete _backPress; _backPress = nullptr; cmd = PARSERR_GENERIC; @@ -263,7 +263,7 @@ bool UIButton::loadBuffer(byte *buffer, bool complete) { case TOKEN_BACK_DISABLE: delete _backDisable; _backDisable = new UITiledImage(_gameRef); - if (!_backDisable || DID_FAIL(_backDisable->loadFile((char *)params))) { + if (!_backDisable || DID_FAIL(_backDisable->loadFile(params))) { delete _backDisable; _backDisable = nullptr; cmd = PARSERR_GENERIC; @@ -273,7 +273,7 @@ bool UIButton::loadBuffer(byte *buffer, bool complete) { case TOKEN_BACK_FOCUS: delete _backFocus; _backFocus = new UITiledImage(_gameRef); - if (!_backFocus || DID_FAIL(_backFocus->loadFile((char *)params))) { + if (!_backFocus || DID_FAIL(_backFocus->loadFile(params))) { delete _backFocus; _backFocus = nullptr; cmd = PARSERR_GENERIC; @@ -283,7 +283,7 @@ bool UIButton::loadBuffer(byte *buffer, bool complete) { case TOKEN_IMAGE: delete _image; _image = new BaseSprite(_gameRef); - if (!_image || DID_FAIL(_image->loadFile((char *)params))) { + if (!_image || DID_FAIL(_image->loadFile(params))) { delete _image; _image = nullptr; cmd = PARSERR_GENERIC; @@ -293,7 +293,7 @@ bool UIButton::loadBuffer(byte *buffer, bool complete) { case TOKEN_IMAGE_HOVER: delete _imageHover; _imageHover = new BaseSprite(_gameRef); - if (!_imageHover || DID_FAIL(_imageHover->loadFile((char *)params))) { + if (!_imageHover || DID_FAIL(_imageHover->loadFile(params))) { delete _imageHover; _imageHover = nullptr; cmd = PARSERR_GENERIC; @@ -303,7 +303,7 @@ bool UIButton::loadBuffer(byte *buffer, bool complete) { case TOKEN_IMAGE_PRESS: delete _imagePress; _imagePress = new BaseSprite(_gameRef); - if (!_imagePress || DID_FAIL(_imagePress->loadFile((char *)params))) { + if (!_imagePress || DID_FAIL(_imagePress->loadFile(params))) { delete _imagePress; _imagePress = nullptr; cmd = PARSERR_GENERIC; @@ -313,7 +313,7 @@ bool UIButton::loadBuffer(byte *buffer, bool complete) { case TOKEN_IMAGE_DISABLE: delete _imageDisable; _imageDisable = new BaseSprite(_gameRef); - if (!_imageDisable || DID_FAIL(_imageDisable->loadFile((char *)params))) { + if (!_imageDisable || DID_FAIL(_imageDisable->loadFile(params))) { delete _imageDisable; _imageDisable = nullptr; cmd = PARSERR_GENERIC; @@ -323,7 +323,7 @@ bool UIButton::loadBuffer(byte *buffer, bool complete) { case TOKEN_IMAGE_FOCUS: delete _imageFocus; _imageFocus = new BaseSprite(_gameRef); - if (!_imageFocus || DID_FAIL(_imageFocus->loadFile((char *)params))) { + if (!_imageFocus || DID_FAIL(_imageFocus->loadFile(params))) { delete _imageFocus; _imageFocus = nullptr; cmd = PARSERR_GENERIC; @@ -334,7 +334,7 @@ bool UIButton::loadBuffer(byte *buffer, bool complete) { if (_font) { _gameRef->_fontStorage->removeFont(_font); } - _font = _gameRef->_fontStorage->addFont((char *)params); + _font = _gameRef->_fontStorage->addFont(params); if (!_font) { cmd = PARSERR_GENERIC; } @@ -344,7 +344,7 @@ bool UIButton::loadBuffer(byte *buffer, bool complete) { if (_fontHover) { _gameRef->_fontStorage->removeFont(_fontHover); } - _fontHover = _gameRef->_fontStorage->addFont((char *)params); + _fontHover = _gameRef->_fontStorage->addFont(params); if (!_fontHover) { cmd = PARSERR_GENERIC; } @@ -354,7 +354,7 @@ bool UIButton::loadBuffer(byte *buffer, bool complete) { if (_fontPress) { _gameRef->_fontStorage->removeFont(_fontPress); } - _fontPress = _gameRef->_fontStorage->addFont((char *)params); + _fontPress = _gameRef->_fontStorage->addFont(params); if (!_fontPress) { cmd = PARSERR_GENERIC; } @@ -364,7 +364,7 @@ bool UIButton::loadBuffer(byte *buffer, bool complete) { if (_fontDisable) { _gameRef->_fontStorage->removeFont(_fontDisable); } - _fontDisable = _gameRef->_fontStorage->addFont((char *)params); + _fontDisable = _gameRef->_fontStorage->addFont(params); if (!_fontDisable) { cmd = PARSERR_GENERIC; } @@ -374,21 +374,21 @@ bool UIButton::loadBuffer(byte *buffer, bool complete) { if (_fontFocus) { _gameRef->_fontStorage->removeFont(_fontFocus); } - _fontFocus = _gameRef->_fontStorage->addFont((char *)params); + _fontFocus = _gameRef->_fontStorage->addFont(params); if (!_fontFocus) { cmd = PARSERR_GENERIC; } break; case TOKEN_TEXT: - setText((char *)params); + setText(params); _gameRef->expandStringByStringTable(&_text); break; case TOKEN_TEXT_ALIGN: - if (scumm_stricmp((char *)params, "left") == 0) { + if (scumm_stricmp(params, "left") == 0) { _align = TAL_LEFT; - } else if (scumm_stricmp((char *)params, "right") == 0) { + } else if (scumm_stricmp(params, "right") == 0) { _align = TAL_RIGHT; } else { _align = TAL_CENTER; @@ -396,25 +396,25 @@ bool UIButton::loadBuffer(byte *buffer, bool complete) { break; case TOKEN_X: - parser.scanStr((char *)params, "%d", &_posX); + parser.scanStr(params, "%d", &_posX); break; case TOKEN_Y: - parser.scanStr((char *)params, "%d", &_posY); + parser.scanStr(params, "%d", &_posY); break; case TOKEN_WIDTH: - parser.scanStr((char *)params, "%d", &_width); + parser.scanStr(params, "%d", &_width); break; case TOKEN_HEIGHT: - parser.scanStr((char *)params, "%d", &_height); + parser.scanStr(params, "%d", &_height); break; case TOKEN_CURSOR: delete _cursor; _cursor = new BaseSprite(_gameRef); - if (!_cursor || DID_FAIL(_cursor->loadFile((char *)params))) { + if (!_cursor || DID_FAIL(_cursor->loadFile(params))) { delete _cursor; _cursor = nullptr; cmd = PARSERR_GENERIC; @@ -422,35 +422,35 @@ bool UIButton::loadBuffer(byte *buffer, bool complete) { break; case TOKEN_SCRIPT: - addScript((char *)params); + addScript(params); break; case TOKEN_PARENT_NOTIFY: - parser.scanStr((char *)params, "%b", &_parentNotify); + parser.scanStr(params, "%b", &_parentNotify); break; case TOKEN_DISABLED: - parser.scanStr((char *)params, "%b", &_disable); + parser.scanStr(params, "%b", &_disable); break; case TOKEN_VISIBLE: - parser.scanStr((char *)params, "%b", &_visible); + parser.scanStr(params, "%b", &_visible); break; case TOKEN_FOCUSABLE: - parser.scanStr((char *)params, "%b", &_canFocus); + parser.scanStr(params, "%b", &_canFocus); break; case TOKEN_CENTER_IMAGE: - parser.scanStr((char *)params, "%b", &_centerImage); + parser.scanStr(params, "%b", &_centerImage); break; case TOKEN_PRESSED: - parser.scanStr((char *)params, "%b", &_stayPressed); + parser.scanStr(params, "%b", &_stayPressed); break; case TOKEN_PIXEL_PERFECT: - parser.scanStr((char *)params, "%b", &_pixelPerfect); + parser.scanStr(params, "%b", &_pixelPerfect); break; case TOKEN_EDITOR_PROPERTY: @@ -660,7 +660,7 @@ bool UIButton::display(int offsetX, int offsetY) { _hover = (!_disable && _gameRef->_activeObject == this && (_gameRef->_interactive || _gameRef->_state == GAME_SEMI_FROZEN)); if ((_press && _hover && !_gameRef->_mouseLeftDown) || - (_oneTimePress && g_system->getMillis() - _oneTimePressTime >= 100)) { + (_oneTimePress && g_system->getMillis() - _oneTimePressTime >= 100)) { press(); } @@ -1206,4 +1206,28 @@ bool UIButton::persist(BasePersistenceManager *persistMgr) { return STATUS_OK; } +void UIButton::setFontHover(BaseFont *font) { + _fontHover = font; +} + +BaseFont *UIButton::getFontHover() { + return _fontHover; +} + +void UIButton::setFontPress(BaseFont *font) { + _fontPress = font; +} + +void UIButton::setImageHover(BaseSprite *sprite) { + _imageHover = sprite; +} + +void UIButton::setImagePress(BaseSprite *sprite) { + _imagePress = sprite; +} + +void UIButton::setTextAlign(TTextAlign align) { + _align = align; +} + } // End of namespace Wintermute diff --git a/engines/wintermute/ui/ui_button.h b/engines/wintermute/ui/ui_button.h index b5002f3166..6452cfc4f7 100644 --- a/engines/wintermute/ui/ui_button.h +++ b/engines/wintermute/ui/ui_button.h @@ -37,35 +37,18 @@ namespace Wintermute { class UIButton : public UIObject { public: - bool _pixelPerfect; - bool _stayPressed; - bool _centerImage; - bool _oneTimePress; - uint32 _oneTimePressTime; + DECLARE_PERSISTENT(UIButton, UIObject) void press(); virtual bool display() { return display(0, 0); } virtual bool display(int offsetX, int offsetY); - bool _press; - bool _hover; + void correctSize(); - TTextAlign _align; - BaseSprite *_imageHover; - BaseSprite *_imagePress; - BaseSprite *_imageDisable; - BaseSprite *_imageFocus; - BaseFont *_fontDisable; - BaseFont *_fontPress; - BaseFont *_fontHover; - BaseFont *_fontFocus; - UITiledImage *_backPress; - UITiledImage *_backHover; - UITiledImage *_backDisable; - UITiledImage *_backFocus; + UIButton(BaseGame *inGame = nullptr); virtual ~UIButton(); bool loadFile(const char *filename); - bool loadBuffer(byte *buffer, bool complete = true); + bool loadBuffer(char *buffer, bool complete = true); virtual bool saveAsText(BaseDynamicBuffer *buffer, int indent) override; // scripting interface @@ -73,6 +56,39 @@ public: virtual bool scSetProperty(const char *name, ScValue *value) override; virtual bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) override; virtual const char *scToString() override; + + + void setFontHover(BaseFont *font); + BaseFont *getFontHover(); + void setFontPress(BaseFont *font); + + void setTextAlign(TTextAlign align); + + void setImageHover(BaseSprite *sprite); + void setImagePress(BaseSprite *sprite); + +private: + bool _pixelPerfect; + bool _stayPressed; + bool _centerImage; + bool _oneTimePress; + UITiledImage *_backPress; + UITiledImage *_backHover; + UITiledImage *_backDisable; + UITiledImage *_backFocus; + bool _press; + bool _hover; + BaseFont *_fontDisable; + BaseFont *_fontPress; + BaseFont *_fontHover; + BaseFont *_fontFocus; + BaseSprite *_imageHover; + BaseSprite *_imagePress; + BaseSprite *_imageDisable; + BaseSprite *_imageFocus; + uint32 _oneTimePressTime; + TTextAlign _align; + }; } // End of namespace Wintermute diff --git a/engines/wintermute/ui/ui_edit.cpp b/engines/wintermute/ui/ui_edit.cpp index caed157e0b..4de1965b59 100644 --- a/engines/wintermute/ui/ui_edit.cpp +++ b/engines/wintermute/ui/ui_edit.cpp @@ -94,7 +94,7 @@ UIEdit::~UIEdit() { ////////////////////////////////////////////////////////////////////////// bool UIEdit::loadFile(const char *filename) { - byte *buffer = BaseFileManager::getEngineInstance()->readWholeFile(filename); + char *buffer = (char *)BaseFileManager::getEngineInstance()->readWholeFile(filename); if (buffer == nullptr) { _gameRef->LOG(0, "UIEdit::LoadFile failed for file '%s'", filename); return STATUS_FAILED; @@ -139,7 +139,7 @@ TOKEN_DEF(EDIT) TOKEN_DEF(CAPTION) TOKEN_DEF_END ////////////////////////////////////////////////////////////////////////// -bool UIEdit::loadBuffer(byte *buffer, bool complete) { +bool UIEdit::loadBuffer(char *buffer, bool complete) { TOKEN_TABLE_START(commands) TOKEN_TABLE(TEMPLATE) TOKEN_TABLE(DISABLED) @@ -165,34 +165,34 @@ bool UIEdit::loadBuffer(byte *buffer, bool complete) { TOKEN_TABLE(CAPTION) TOKEN_TABLE_END - byte *params; + char *params; int cmd = 2; BaseParser parser; if (complete) { - if (parser.getCommand((char **)&buffer, commands, (char **)¶ms) != TOKEN_EDIT) { + if (parser.getCommand(&buffer, commands, ¶ms) != TOKEN_EDIT) { _gameRef->LOG(0, "'EDIT' keyword expected."); return STATUS_FAILED; } buffer = params; } - while (cmd > 0 && (cmd = parser.getCommand((char **)&buffer, commands, (char **)¶ms)) > 0) { + while (cmd > 0 && (cmd = parser.getCommand(&buffer, commands, ¶ms)) > 0) { switch (cmd) { case TOKEN_TEMPLATE: - if (DID_FAIL(loadFile((char *)params))) { + if (DID_FAIL(loadFile(params))) { cmd = PARSERR_GENERIC; } break; case TOKEN_NAME: - setName((char *)params); + setName(params); break; case TOKEN_BACK: delete _back; _back = new UITiledImage(_gameRef); - if (!_back || DID_FAIL(_back->loadFile((char *)params))) { + if (!_back || DID_FAIL(_back->loadFile(params))) { delete _back; _back = nullptr; cmd = PARSERR_GENERIC; @@ -202,7 +202,7 @@ bool UIEdit::loadBuffer(byte *buffer, bool complete) { case TOKEN_IMAGE: delete _image; _image = new BaseSprite(_gameRef); - if (!_image || DID_FAIL(_image->loadFile((char *)params))) { + if (!_image || DID_FAIL(_image->loadFile(params))) { delete _image; _image = nullptr; cmd = PARSERR_GENERIC; @@ -213,7 +213,7 @@ bool UIEdit::loadBuffer(byte *buffer, bool complete) { if (_font) { _gameRef->_fontStorage->removeFont(_font); } - _font = _gameRef->_fontStorage->addFont((char *)params); + _font = _gameRef->_fontStorage->addFont(params); if (!_font) { cmd = PARSERR_GENERIC; } @@ -223,45 +223,45 @@ bool UIEdit::loadBuffer(byte *buffer, bool complete) { if (_fontSelected) { _gameRef->_fontStorage->removeFont(_fontSelected); } - _fontSelected = _gameRef->_fontStorage->addFont((char *)params); + _fontSelected = _gameRef->_fontStorage->addFont(params); if (!_fontSelected) { cmd = PARSERR_GENERIC; } break; case TOKEN_TEXT: - setText((char *)params); + setText(params); _gameRef->expandStringByStringTable(&_text); break; case TOKEN_X: - parser.scanStr((char *)params, "%d", &_posX); + parser.scanStr(params, "%d", &_posX); break; case TOKEN_Y: - parser.scanStr((char *)params, "%d", &_posY); + parser.scanStr(params, "%d", &_posY); break; case TOKEN_WIDTH: - parser.scanStr((char *)params, "%d", &_width); + parser.scanStr(params, "%d", &_width); break; case TOKEN_HEIGHT: - parser.scanStr((char *)params, "%d", &_height); + parser.scanStr(params, "%d", &_height); break; case TOKEN_MAX_LENGTH: - parser.scanStr((char *)params, "%d", &_maxLength); + parser.scanStr(params, "%d", &_maxLength); break; case TOKEN_CAPTION: - setCaption((char *)params); + setCaption(params); break; case TOKEN_CURSOR: delete _cursor; _cursor = new BaseSprite(_gameRef); - if (!_cursor || DID_FAIL(_cursor->loadFile((char *)params))) { + if (!_cursor || DID_FAIL(_cursor->loadFile(params))) { delete _cursor; _cursor = nullptr; cmd = PARSERR_GENERIC; @@ -269,27 +269,27 @@ bool UIEdit::loadBuffer(byte *buffer, bool complete) { break; case TOKEN_CURSOR_BLINK_RATE: - parser.scanStr((char *)params, "%d", &_cursorBlinkRate); + parser.scanStr(params, "%d", &_cursorBlinkRate); break; case TOKEN_FRAME_WIDTH: - parser.scanStr((char *)params, "%d", &_frameWidth); + parser.scanStr(params, "%d", &_frameWidth); break; case TOKEN_SCRIPT: - addScript((char *)params); + addScript(params); break; case TOKEN_PARENT_NOTIFY: - parser.scanStr((char *)params, "%b", &_parentNotify); + parser.scanStr(params, "%b", &_parentNotify); break; case TOKEN_DISABLED: - parser.scanStr((char *)params, "%b", &_disable); + parser.scanStr(params, "%b", &_disable); break; case TOKEN_VISIBLE: - parser.scanStr((char *)params, "%b", &_visible); + parser.scanStr(params, "%b", &_visible); break; case TOKEN_EDITOR_PROPERTY: @@ -627,9 +627,9 @@ bool UIEdit::display(int offsetX, int offsetY) { curFirst = true; } else { while (font->getTextWidth((byte *)_text + _scrollOffset, MAX<int32>(0, _selStart - _scrollOffset)) + - sfont->getTextWidth((byte *)(_text + MAX<int32>(_scrollOffset, _selStart)), _selEnd - MAX(_scrollOffset, _selStart)) + sfont->getTextWidth((byte *)(_text + MAX<int32>(_scrollOffset, _selStart)), _selEnd - MAX(_scrollOffset, _selStart)) - > _width - cursorWidth - 2 * _frameWidth) { + > _width - cursorWidth - 2 * _frameWidth) { _scrollOffset++; if (_scrollOffset >= (int)strlen(_text)) { break; diff --git a/engines/wintermute/ui/ui_edit.h b/engines/wintermute/ui/ui_edit.h index a057be9ead..19ea5ecc5d 100644 --- a/engines/wintermute/ui/ui_edit.h +++ b/engines/wintermute/ui/ui_edit.h @@ -38,26 +38,20 @@ class BaseFont; class UIEdit : public UIObject { public: DECLARE_PERSISTENT(UIEdit, UIObject) - int32 _maxLength; + int insertChars(int pos, const byte *chars, int num); int deleteChars(int start, int end); - bool _cursorVisible; - uint32 _lastBlinkTime; + virtual bool display(int offsetX, int offsetY); virtual bool handleKeypress(Common::Event *event, bool printable = false); - int32 _scrollOffset; - int32 _frameWidth; - uint32 _cursorBlinkRate; + void setCursorChar(const char *character); - char *_cursorChar; - int32 _selEnd; - int32 _selStart; - BaseFont *_fontSelected; + UIEdit(BaseGame *inGame); virtual ~UIEdit(); bool loadFile(const char *filename); - bool loadBuffer(byte *buffer, bool complete = true); + bool loadBuffer(char *buffer, bool complete = true); virtual bool saveAsText(BaseDynamicBuffer *buffer, int indent); // scripting interface @@ -65,6 +59,17 @@ public: virtual bool scSetProperty(const char *name, ScValue *value) override; virtual bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) override; virtual const char *scToString() override; +private: + uint32 _cursorBlinkRate; + uint32 _lastBlinkTime; + int32 _selEnd; + int32 _selStart; + int32 _scrollOffset; + int32 _frameWidth; + BaseFont *_fontSelected; + int32 _maxLength; + bool _cursorVisible; + char *_cursorChar; }; } // End of namespace Wintermute diff --git a/engines/wintermute/ui/ui_entity.cpp b/engines/wintermute/ui/ui_entity.cpp index 6d4cfdb7eb..0dbf8df00b 100644 --- a/engines/wintermute/ui/ui_entity.cpp +++ b/engines/wintermute/ui/ui_entity.cpp @@ -58,7 +58,7 @@ UIEntity::~UIEntity() { ////////////////////////////////////////////////////////////////////////// bool UIEntity::loadFile(const char *filename) { - byte *buffer = BaseFileManager::getEngineInstance()->readWholeFile(filename); + char *buffer = (char *)BaseFileManager::getEngineInstance()->readWholeFile(filename); if (buffer == nullptr) { _gameRef->LOG(0, "UIEntity::LoadFile failed for file '%s'", filename); return STATUS_FAILED; @@ -92,7 +92,7 @@ TOKEN_DEF(SCRIPT) TOKEN_DEF(EDITOR_PROPERTY) TOKEN_DEF_END ////////////////////////////////////////////////////////////////////////// -bool UIEntity::loadBuffer(byte *buffer, bool complete) { +bool UIEntity::loadBuffer(char *buffer, bool complete) { TOKEN_TABLE_START(commands) TOKEN_TABLE(ENTITY_CONTAINER) TOKEN_TABLE(TEMPLATE) @@ -106,54 +106,54 @@ bool UIEntity::loadBuffer(byte *buffer, bool complete) { TOKEN_TABLE(EDITOR_PROPERTY) TOKEN_TABLE_END - byte *params; + char *params; int cmd = 2; BaseParser parser; if (complete) { - if (parser.getCommand((char **)&buffer, commands, (char **)¶ms) != TOKEN_ENTITY_CONTAINER) { + if (parser.getCommand(&buffer, commands, ¶ms) != TOKEN_ENTITY_CONTAINER) { _gameRef->LOG(0, "'ENTITY_CONTAINER' keyword expected."); return STATUS_FAILED; } buffer = params; } - while (cmd > 0 && (cmd = parser.getCommand((char **)&buffer, commands, (char **)¶ms)) > 0) { + while (cmd > 0 && (cmd = parser.getCommand(&buffer, commands, ¶ms)) > 0) { switch (cmd) { case TOKEN_TEMPLATE: - if (DID_FAIL(loadFile((char *)params))) { + if (DID_FAIL(loadFile(params))) { cmd = PARSERR_GENERIC; } break; case TOKEN_NAME: - setName((char *)params); + setName(params); break; case TOKEN_X: - parser.scanStr((char *)params, "%d", &_posX); + parser.scanStr(params, "%d", &_posX); break; case TOKEN_Y: - parser.scanStr((char *)params, "%d", &_posY); + parser.scanStr(params, "%d", &_posY); break; case TOKEN_DISABLED: - parser.scanStr((char *)params, "%b", &_disable); + parser.scanStr(params, "%b", &_disable); break; case TOKEN_VISIBLE: - parser.scanStr((char *)params, "%b", &_visible); + parser.scanStr(params, "%b", &_visible); break; case TOKEN_ENTITY: - if (DID_FAIL(setEntity((char *)params))) { + if (DID_FAIL(setEntity(params))) { cmd = PARSERR_GENERIC; } break; case TOKEN_SCRIPT: - addScript((char *)params); + addScript(params); break; case TOKEN_EDITOR_PROPERTY: diff --git a/engines/wintermute/ui/ui_entity.h b/engines/wintermute/ui/ui_entity.h index 1b6e8a10d6..63f0026412 100644 --- a/engines/wintermute/ui/ui_entity.h +++ b/engines/wintermute/ui/ui_entity.h @@ -39,12 +39,11 @@ public: UIEntity(BaseGame *inGame); virtual ~UIEntity(); bool loadFile(const char *filename); - bool loadBuffer(byte *buffer, bool complete); + bool loadBuffer(char *buffer, bool complete); virtual bool saveAsText(BaseDynamicBuffer *buffer, int indent) override; virtual bool display() override { return display(0, 0); } virtual bool display(int offsetX, int offsetY) override; - AdEntity *_entity; bool setEntity(const char *filename); // scripting interface @@ -52,6 +51,9 @@ public: virtual bool scSetProperty(const char *name, ScValue *value) override; virtual bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name); virtual const char *scToString(); + +private: + AdEntity *_entity; }; } // End of namespace Wintermute diff --git a/engines/wintermute/ui/ui_object.cpp b/engines/wintermute/ui/ui_object.cpp index c32ae75c20..a8da89b011 100644 --- a/engines/wintermute/ui/ui_object.cpp +++ b/engines/wintermute/ui/ui_object.cpp @@ -648,4 +648,79 @@ bool UIObject::saveAsText(BaseDynamicBuffer *buffer, int indent) { return STATUS_FAILED; } +int32 UIObject::getWidth() const { + return _width; +} + +int32 UIObject::getHeight() const { + return _height; +} + +void UIObject::setWidth(int32 width) { + assert(width >= 0); + _width = width; +} + +void UIObject::setHeight(int32 height) { + assert(height >= 0); + _height = height; +} + +bool UIObject::isDisabled() const { + return _disable; +} + +bool UIObject::isVisible() const { + return _visible; +} + +void UIObject::setVisible(bool visible) { + _visible = visible; +} + +void UIObject::setDisabled(bool disable) { + _disable = disable; +} + +bool UIObject::hasSharedFonts() const { + return _sharedFonts; +} + +void UIObject::setSharedFonts(bool shared) { + _sharedFonts = shared; +} + +bool UIObject::hasSharedImages() const { + return _sharedImages; +} + +void UIObject::setSharedImages(bool shared) { + _sharedImages = shared; +} + +BaseSprite *UIObject::getImage() const { + return _image; +} + +void UIObject::setImage(BaseSprite *image) { + _image = image; +} + +bool UIObject::canFocus() const { + return _canFocus; +} + +void UIObject::setFont(BaseFont *font) { + _font = font; +} + +BaseFont *UIObject::getFont() { + return _font; +} + +BaseScriptHolder *UIObject::getListener() const { + return _listenerObject; +} + + } // End of namespace Wintermute diff --git a/engines/wintermute/ui/ui_object.h b/engines/wintermute/ui/ui_object.h index 5d9508c2cf..8d14d8a6a4 100644 --- a/engines/wintermute/ui/ui_object.h +++ b/engines/wintermute/ui/ui_object.h @@ -41,35 +41,23 @@ class UIObject : public BaseObject { public: bool getTotalOffset(int *offsetX, int *offsetY); - bool _canFocus; bool focus(); virtual bool handleMouse(TMouseEvent event, TMouseButton button); bool isFocused(); - bool _parentNotify; + DECLARE_PERSISTENT(UIObject, BaseObject) UIObject *_parent; virtual bool display() override { return display(0, 0); } virtual bool display(int offsetX) { return display(offsetX, 0); } virtual bool display(int offsetX, int offsetY); virtual void correctSize(); - bool _sharedFonts; - bool _sharedImages; void setText(const char *text); - char *_text; - BaseFont *_font; - bool _visible; - UITiledImage *_back; - bool _disable; + UIObject(BaseGame *inGame = nullptr); virtual ~UIObject(); - int32 _width; - int32 _height; - TUIObjectType _type; - BaseSprite *_image; void setListener(BaseScriptHolder *object, BaseScriptHolder *listenerObject, uint32 listenerParam); - BaseScriptHolder *_listenerParamObject; - uint32 _listenerParamDWORD; - BaseScriptHolder *_listenerObject; + BaseScriptHolder *getListener() const; + UIObject *_focusedWidget; virtual bool saveAsText(BaseDynamicBuffer *buffer, int indent) override; @@ -78,6 +66,42 @@ public: virtual bool scSetProperty(const char *name, ScValue *value) override; virtual bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) override; virtual const char *scToString() override; + TUIObjectType _type; + + int32 getWidth() const; + int32 getHeight() const; + void setHeight(int32 height); + void setWidth(int32 width); + bool isDisabled() const; + void setDisabled(bool disable); + bool isVisible() const; + void setVisible(bool visible); + bool hasSharedFonts() const; + void setSharedFonts(bool shared); + bool hasSharedImages() const; + void setSharedImages(bool shared); + BaseSprite *getImage() const; + void setImage(BaseSprite *image); + void setFont(BaseFont *font); + BaseFont *getFont(); + bool canFocus() const; + +protected: + BaseScriptHolder *_listenerParamObject; + uint32 _listenerParamDWORD; + BaseScriptHolder *_listenerObject; + BaseSprite *_image; + BaseFont *_font; + bool _sharedFonts; + bool _sharedImages; + char *_text; + bool _visible; + bool _disable; + int32 _width; + int32 _height; + bool _canFocus; + bool _parentNotify; + UITiledImage *_back; }; } // End of namespace Wintermute diff --git a/engines/wintermute/ui/ui_text.cpp b/engines/wintermute/ui/ui_text.cpp index 5dc25f5852..117b1ff6cf 100644 --- a/engines/wintermute/ui/ui_text.cpp +++ b/engines/wintermute/ui/ui_text.cpp @@ -103,7 +103,7 @@ bool UIText::display(int offsetX, int offsetY) { ////////////////////////////////////////////////////////////////////////// bool UIText::loadFile(const char *filename) { - byte *buffer = BaseFileManager::getEngineInstance()->readWholeFile(filename); + char *buffer = (char *)BaseFileManager::getEngineInstance()->readWholeFile(filename); if (buffer == nullptr) { _gameRef->LOG(0, "UIText::LoadFile failed for file '%s'", filename); return STATUS_FAILED; @@ -146,7 +146,7 @@ TOKEN_DEF(PARENT_NOTIFY) TOKEN_DEF(EDITOR_PROPERTY) TOKEN_DEF_END ////////////////////////////////////////////////////////////////////////// -bool UIText::loadBuffer(byte *buffer, bool complete) { +bool UIText::loadBuffer(char *buffer, bool complete) { TOKEN_TABLE_START(commands) TOKEN_TABLE(STATIC) TOKEN_TABLE(TEMPLATE) @@ -170,38 +170,38 @@ bool UIText::loadBuffer(byte *buffer, bool complete) { TOKEN_TABLE(EDITOR_PROPERTY) TOKEN_TABLE_END - byte *params; + char *params; int cmd = 2; BaseParser parser; if (complete) { - if (parser.getCommand((char **)&buffer, commands, (char **)¶ms) != TOKEN_STATIC) { + if (parser.getCommand(&buffer, commands, ¶ms) != TOKEN_STATIC) { _gameRef->LOG(0, "'STATIC' keyword expected."); return STATUS_FAILED; } buffer = params; } - while (cmd > 0 && (cmd = parser.getCommand((char **)&buffer, commands, (char **)¶ms)) > 0) { + while (cmd > 0 && (cmd = parser.getCommand(&buffer, commands, ¶ms)) > 0) { switch (cmd) { case TOKEN_TEMPLATE: - if (DID_FAIL(loadFile((char *)params))) { + if (DID_FAIL(loadFile(params))) { cmd = PARSERR_GENERIC; } break; case TOKEN_NAME: - setName((char *)params); + setName(params); break; case TOKEN_CAPTION: - setCaption((char *)params); + setCaption(params); break; case TOKEN_BACK: delete _back; _back = new UITiledImage(_gameRef); - if (!_back || DID_FAIL(_back->loadFile((char *)params))) { + if (!_back || DID_FAIL(_back->loadFile(params))) { delete _back; _back = nullptr; cmd = PARSERR_GENERIC; @@ -211,7 +211,7 @@ bool UIText::loadBuffer(byte *buffer, bool complete) { case TOKEN_IMAGE: delete _image; _image = new BaseSprite(_gameRef); - if (!_image || DID_FAIL(_image->loadFile((char *)params))) { + if (!_image || DID_FAIL(_image->loadFile(params))) { delete _image; _image = nullptr; cmd = PARSERR_GENERIC; @@ -222,21 +222,21 @@ bool UIText::loadBuffer(byte *buffer, bool complete) { if (_font) { _gameRef->_fontStorage->removeFont(_font); } - _font = _gameRef->_fontStorage->addFont((char *)params); + _font = _gameRef->_fontStorage->addFont(params); if (!_font) { cmd = PARSERR_GENERIC; } break; case TOKEN_TEXT: - setText((char *)params); + setText(params); _gameRef->expandStringByStringTable(&_text); break; case TOKEN_TEXT_ALIGN: - if (scumm_stricmp((char *)params, "left") == 0) { + if (scumm_stricmp(params, "left") == 0) { _textAlign = TAL_LEFT; - } else if (scumm_stricmp((char *)params, "right") == 0) { + } else if (scumm_stricmp(params, "right") == 0) { _textAlign = TAL_RIGHT; } else { _textAlign = TAL_CENTER; @@ -244,9 +244,9 @@ bool UIText::loadBuffer(byte *buffer, bool complete) { break; case TOKEN_VERTICAL_ALIGN: - if (scumm_stricmp((char *)params, "top") == 0) { + if (scumm_stricmp(params, "top") == 0) { _verticalAlign = VAL_TOP; - } else if (scumm_stricmp((char *)params, "bottom") == 0) { + } else if (scumm_stricmp(params, "bottom") == 0) { _verticalAlign = VAL_BOTTOM; } else { _verticalAlign = VAL_CENTER; @@ -254,25 +254,25 @@ bool UIText::loadBuffer(byte *buffer, bool complete) { break; case TOKEN_X: - parser.scanStr((char *)params, "%d", &_posX); + parser.scanStr(params, "%d", &_posX); break; case TOKEN_Y: - parser.scanStr((char *)params, "%d", &_posY); + parser.scanStr(params, "%d", &_posY); break; case TOKEN_WIDTH: - parser.scanStr((char *)params, "%d", &_width); + parser.scanStr(params, "%d", &_width); break; case TOKEN_HEIGHT: - parser.scanStr((char *)params, "%d", &_height); + parser.scanStr(params, "%d", &_height); break; case TOKEN_CURSOR: delete _cursor; _cursor = new BaseSprite(_gameRef); - if (!_cursor || DID_FAIL(_cursor->loadFile((char *)params))) { + if (!_cursor || DID_FAIL(_cursor->loadFile(params))) { delete _cursor; _cursor = nullptr; cmd = PARSERR_GENERIC; @@ -280,19 +280,19 @@ bool UIText::loadBuffer(byte *buffer, bool complete) { break; case TOKEN_SCRIPT: - addScript((char *)params); + addScript(params); break; case TOKEN_PARENT_NOTIFY: - parser.scanStr((char *)params, "%b", &_parentNotify); + parser.scanStr(params, "%b", &_parentNotify); break; case TOKEN_DISABLED: - parser.scanStr((char *)params, "%b", &_disable); + parser.scanStr(params, "%b", &_disable); break; case TOKEN_VISIBLE: - parser.scanStr((char *)params, "%b", &_visible); + parser.scanStr(params, "%b", &_visible); break; case TOKEN_EDITOR_PROPERTY: diff --git a/engines/wintermute/ui/ui_text.h b/engines/wintermute/ui/ui_text.h index 29ed62a5ef..c39260b228 100644 --- a/engines/wintermute/ui/ui_text.h +++ b/engines/wintermute/ui/ui_text.h @@ -37,15 +37,15 @@ namespace Wintermute { class UIText : public UIObject { private: bool sizeToFit(); + TTextAlign _textAlign; + TVerticalAlign _verticalAlign; public: virtual bool display(int offsetX, int offsetY); DECLARE_PERSISTENT(UIText, UIObject) UIText(BaseGame *inGame = nullptr); virtual ~UIText(); - TTextAlign _textAlign; - TVerticalAlign _verticalAlign; bool loadFile(const char *filename); - bool loadBuffer(byte *buffer, bool complete = true); + bool loadBuffer(char *buffer, bool complete = true); virtual bool saveAsText(BaseDynamicBuffer *buffer, int indent) override; // scripting interface diff --git a/engines/wintermute/ui/ui_tiled_image.cpp b/engines/wintermute/ui/ui_tiled_image.cpp index de4b86a6dd..e647e0d894 100644 --- a/engines/wintermute/ui/ui_tiled_image.cpp +++ b/engines/wintermute/ui/ui_tiled_image.cpp @@ -75,8 +75,6 @@ bool UITiledImage::display(int x, int y, int width, int height) { int nuColumns = (width - (_middleLeft.right - _middleLeft.left) - (_middleRight.right - _middleRight.left)) / tileWidth; int nuRows = (height - (_upMiddle.bottom - _upMiddle.top) - (_downMiddle.bottom - _downMiddle.top)) / tileHeight; - int col, row; - _gameRef->_renderer->startSpriteBatch(); // top left/right @@ -88,27 +86,24 @@ bool UITiledImage::display(int x, int y, int width, int height) { _image->_surface->displayTrans(x + (_upLeft.right - _upLeft.left) + nuColumns * tileWidth, y + (_upMiddle.bottom - _upMiddle.top) + nuRows * tileHeight, _downRight); // left/right - int yyy = y + (_upMiddle.bottom - _upMiddle.top); - for (row = 0; row < nuRows; row++) { - _image->_surface->displayTrans(x, yyy, _middleLeft); - _image->_surface->displayTrans(x + (_middleLeft.right - _middleLeft.left) + nuColumns * tileWidth, yyy, _middleRight); - yyy += tileWidth; + if (nuRows > 0) { + int yyy = y + (_upMiddle.bottom - _upMiddle.top); + _image->_surface->displayTiled(x, yyy, _middleLeft, 1, nuRows); + _image->_surface->displayTiled(x + (_middleLeft.right - _middleLeft.left) + nuColumns * tileWidth, yyy, _middleRight, 1, nuRows); } // top/bottom - int xxx = x + (_upLeft.right - _upLeft.left); - for (col = 0; col < nuColumns; col++) { - _image->_surface->displayTrans(xxx, y, _upMiddle); - _image->_surface->displayTrans(xxx, y + (_upMiddle.bottom - _upMiddle.top) + nuRows * tileHeight, _downMiddle); - xxx += tileWidth; + if (nuColumns > 0) { + int xxx = x + (_upLeft.right - _upLeft.left); + _image->_surface->displayTiled(xxx, y, _upMiddle, nuColumns, 1); + _image->_surface->displayTiled(xxx, y + (_upMiddle.bottom - _upMiddle.top) + nuRows * tileHeight, _downMiddle, nuColumns, 1); } // tiles if (nuRows > 0 && nuColumns > 0) { - yyy = y + (_upMiddle.bottom - _upMiddle.top); - xxx = x + (_upLeft.right - _upLeft.left); - _image->_surface->displayTrans(xxx, yyy, _middleMiddle); - _image->_surface->repeatLastDisplayOp(tileWidth, tileWidth, nuColumns, nuRows); + int yyy = y + (_upMiddle.bottom - _upMiddle.top); + int xxx = x + (_upLeft.right - _upLeft.left); + _image->_surface->displayTiled(xxx, yyy, _middleMiddle, nuColumns, nuRows); } _gameRef->_renderer->endSpriteBatch(); @@ -119,7 +114,7 @@ bool UITiledImage::display(int x, int y, int width, int height) { ////////////////////////////////////////////////////////////////////////// bool UITiledImage::loadFile(const char *filename) { - byte *buffer = BaseFileManager::getEngineInstance()->readWholeFile(filename); + char *buffer = (char *)BaseFileManager::getEngineInstance()->readWholeFile(filename); if (buffer == nullptr) { _gameRef->LOG(0, "UITiledImage::LoadFile failed for file '%s'", filename); return STATUS_FAILED; @@ -158,7 +153,7 @@ TOKEN_DEF(HORIZONTAL_TILES) TOKEN_DEF(EDITOR_PROPERTY) TOKEN_DEF_END ////////////////////////////////////////////////////////////////////////// -bool UITiledImage::loadBuffer(byte *buffer, bool complete) { +bool UITiledImage::loadBuffer(char *buffer, bool complete) { TOKEN_TABLE_START(commands) TOKEN_TABLE(TILED_IMAGE) TOKEN_TABLE(TEMPLATE) @@ -177,7 +172,7 @@ bool UITiledImage::loadBuffer(byte *buffer, bool complete) { TOKEN_TABLE(EDITOR_PROPERTY) TOKEN_TABLE_END - byte *params; + char *params; int cmd; BaseParser parser; bool hTiles = false, vTiles = false; @@ -185,17 +180,17 @@ bool UITiledImage::loadBuffer(byte *buffer, bool complete) { int v1 = 0, v2 = 0, v3 = 0; if (complete) { - if (parser.getCommand((char **)&buffer, commands, (char **)¶ms) != TOKEN_TILED_IMAGE) { + if (parser.getCommand(&buffer, commands, ¶ms) != TOKEN_TILED_IMAGE) { _gameRef->LOG(0, "'TILED_IMAGE' keyword expected."); return STATUS_FAILED; } buffer = params; } - while ((cmd = parser.getCommand((char **)&buffer, commands, (char **)¶ms)) > 0) { + while ((cmd = parser.getCommand(&buffer, commands, ¶ms)) > 0) { switch (cmd) { case TOKEN_TEMPLATE: - if (DID_FAIL(loadFile((char *)params))) { + if (DID_FAIL(loadFile(params))) { cmd = PARSERR_GENERIC; } break; @@ -203,7 +198,7 @@ bool UITiledImage::loadBuffer(byte *buffer, bool complete) { case TOKEN_IMAGE: delete _image; _image = new BaseSubFrame(_gameRef); - if (!_image || DID_FAIL(_image->setSurface((char *)params))) { + if (!_image || DID_FAIL(_image->setSurface(params))) { delete _image; _image = nullptr; cmd = PARSERR_GENERIC; @@ -211,48 +206,48 @@ bool UITiledImage::loadBuffer(byte *buffer, bool complete) { break; case TOKEN_UP_LEFT: - parser.scanStr((char *)params, "%d,%d,%d,%d", &_upLeft.left, &_upLeft.top, &_upLeft.right, &_upLeft.bottom); + parser.scanStr(params, "%d,%d,%d,%d", &_upLeft.left, &_upLeft.top, &_upLeft.right, &_upLeft.bottom); break; case TOKEN_UP_RIGHT: - parser.scanStr((char *)params, "%d,%d,%d,%d", &_upRight.left, &_upRight.top, &_upRight.right, &_upRight.bottom); + parser.scanStr(params, "%d,%d,%d,%d", &_upRight.left, &_upRight.top, &_upRight.right, &_upRight.bottom); break; case TOKEN_UP_MIDDLE: - parser.scanStr((char *)params, "%d,%d,%d,%d", &_upMiddle.left, &_upMiddle.top, &_upMiddle.right, &_upMiddle.bottom); + parser.scanStr(params, "%d,%d,%d,%d", &_upMiddle.left, &_upMiddle.top, &_upMiddle.right, &_upMiddle.bottom); break; case TOKEN_DOWN_LEFT: - parser.scanStr((char *)params, "%d,%d,%d,%d", &_downLeft.left, &_downLeft.top, &_downLeft.right, &_downLeft.bottom); + parser.scanStr(params, "%d,%d,%d,%d", &_downLeft.left, &_downLeft.top, &_downLeft.right, &_downLeft.bottom); break; case TOKEN_DOWN_RIGHT: - parser.scanStr((char *)params, "%d,%d,%d,%d", &_downRight.left, &_downRight.top, &_downRight.right, &_downRight.bottom); + parser.scanStr(params, "%d,%d,%d,%d", &_downRight.left, &_downRight.top, &_downRight.right, &_downRight.bottom); break; case TOKEN_DOWN_MIDDLE: - parser.scanStr((char *)params, "%d,%d,%d,%d", &_downMiddle.left, &_downMiddle.top, &_downMiddle.right, &_downMiddle.bottom); + parser.scanStr(params, "%d,%d,%d,%d", &_downMiddle.left, &_downMiddle.top, &_downMiddle.right, &_downMiddle.bottom); break; case TOKEN_MIDDLE_LEFT: - parser.scanStr((char *)params, "%d,%d,%d,%d", &_middleLeft.left, &_middleLeft.top, &_middleLeft.right, &_middleLeft.bottom); + parser.scanStr(params, "%d,%d,%d,%d", &_middleLeft.left, &_middleLeft.top, &_middleLeft.right, &_middleLeft.bottom); break; case TOKEN_MIDDLE_RIGHT: - parser.scanStr((char *)params, "%d,%d,%d,%d", &_middleRight.left, &_middleRight.top, &_middleRight.right, &_middleRight.bottom); + parser.scanStr(params, "%d,%d,%d,%d", &_middleRight.left, &_middleRight.top, &_middleRight.right, &_middleRight.bottom); break; case TOKEN_MIDDLE_MIDDLE: - parser.scanStr((char *)params, "%d,%d,%d,%d", &_middleMiddle.left, &_middleMiddle.top, &_middleMiddle.right, &_middleMiddle.bottom); + parser.scanStr(params, "%d,%d,%d,%d", &_middleMiddle.left, &_middleMiddle.top, &_middleMiddle.right, &_middleMiddle.bottom); break; case TOKEN_HORIZONTAL_TILES: - parser.scanStr((char *)params, "%d,%d,%d", &h1, &h2, &h3); + parser.scanStr(params, "%d,%d,%d", &h1, &h2, &h3); hTiles = true; break; case TOKEN_VERTICAL_TILES: - parser.scanStr((char *)params, "%d,%d,%d", &v1, &v2, &v3); + parser.scanStr(params, "%d,%d,%d", &v1, &v2, &v3); vTiles = true; break; diff --git a/engines/wintermute/ui/ui_tiled_image.h b/engines/wintermute/ui/ui_tiled_image.h index 39bc6495a9..fa92c46781 100644 --- a/engines/wintermute/ui/ui_tiled_image.h +++ b/engines/wintermute/ui/ui_tiled_image.h @@ -36,11 +36,13 @@ namespace Wintermute { class BaseSubFrame; class UITiledImage : public BaseObject { + using Wintermute::BaseObject::display; + public: DECLARE_PERSISTENT(UITiledImage, BaseObject) void correctSize(int32 *width, int32 *height); bool loadFile(const char *filename); - bool loadBuffer(byte *buffer, bool complete = true); + bool loadBuffer(char *buffer, bool complete = true); virtual bool saveAsText(BaseDynamicBuffer *buffer, int indent) override; bool display(int x, int y, int width, int height); diff --git a/engines/wintermute/ui/ui_window.cpp b/engines/wintermute/ui/ui_window.cpp index 9066ee9f5b..9051ce8217 100644 --- a/engines/wintermute/ui/ui_window.cpp +++ b/engines/wintermute/ui/ui_window.cpp @@ -141,8 +141,8 @@ bool UIWindow::display(int offsetX, int offsetY) { } if (_shieldButton) { _shieldButton->_posX = _shieldButton->_posY = 0; - _shieldButton->_width = _gameRef->_renderer->getWidth(); - _shieldButton->_height = _gameRef->_renderer->getHeight(); + _shieldButton->setWidth(_gameRef->_renderer->getWidth()); + _shieldButton->setHeight(_gameRef->_renderer->getHeight()); _shieldButton->display(); } @@ -170,7 +170,7 @@ bool UIWindow::display(int offsetX, int offsetY) { _dragFrom.y = _gameRef->_mousePos.y; } - if (!_focusedWidget || (!_focusedWidget->_canFocus || _focusedWidget->_disable || !_focusedWidget->_visible)) { + if (!_focusedWidget || (!_focusedWidget->canFocus() || _focusedWidget->isDisabled() || !_focusedWidget->isVisible())) { moveFocus(); } @@ -239,7 +239,7 @@ bool UIWindow::display(int offsetX, int offsetY) { ////////////////////////////////////////////////////////////////////////// bool UIWindow::loadFile(const char *filename) { - byte *buffer = BaseFileManager::getEngineInstance()->readWholeFile(filename); + char *buffer = (char *)BaseFileManager::getEngineInstance()->readWholeFile(filename); if (buffer == nullptr) { _gameRef->LOG(0, "UIWindow::LoadFile failed for file '%s'", filename); return STATUS_FAILED; @@ -298,7 +298,7 @@ TOKEN_DEF(EDITOR_PROPERTY) TOKEN_DEF(EDIT) TOKEN_DEF_END ////////////////////////////////////////////////////////////////////////// -bool UIWindow::loadBuffer(byte *buffer, bool complete) { +bool UIWindow::loadBuffer(char *buffer, bool complete) { TOKEN_TABLE_START(commands) TOKEN_TABLE(WINDOW) TOKEN_TABLE(ALPHA_COLOR) @@ -338,7 +338,7 @@ bool UIWindow::loadBuffer(byte *buffer, bool complete) { TOKEN_TABLE(EDIT) TOKEN_TABLE_END - byte *params; + char *params; int cmd = 2; BaseParser parser; @@ -346,33 +346,33 @@ bool UIWindow::loadBuffer(byte *buffer, bool complete) { int ar = 0, ag = 0, ab = 0, alpha = 0; if (complete) { - if (parser.getCommand((char **)&buffer, commands, (char **)¶ms) != TOKEN_WINDOW) { + if (parser.getCommand(&buffer, commands, ¶ms) != TOKEN_WINDOW) { _gameRef->LOG(0, "'WINDOW' keyword expected."); return STATUS_FAILED; } buffer = params; } - while (cmd >= PARSERR_TOKENNOTFOUND && (cmd = parser.getCommand((char **)&buffer, commands, (char **)¶ms)) >= PARSERR_TOKENNOTFOUND) { + while (cmd >= PARSERR_TOKENNOTFOUND && (cmd = parser.getCommand(&buffer, commands, ¶ms)) >= PARSERR_TOKENNOTFOUND) { switch (cmd) { case TOKEN_TEMPLATE: - if (DID_FAIL(loadFile((char *)params))) { + if (DID_FAIL(loadFile(params))) { cmd = PARSERR_GENERIC; } break; case TOKEN_NAME: - setName((char *)params); + setName(params); break; case TOKEN_CAPTION: - setCaption((char *)params); + setCaption(params); break; case TOKEN_BACK: delete _back; _back = new UITiledImage(_gameRef); - if (!_back || DID_FAIL(_back->loadFile((char *)params))) { + if (!_back || DID_FAIL(_back->loadFile(params))) { delete _back; _back = nullptr; cmd = PARSERR_GENERIC; @@ -382,7 +382,7 @@ bool UIWindow::loadBuffer(byte *buffer, bool complete) { case TOKEN_BACK_INACTIVE: delete _backInactive; _backInactive = new UITiledImage(_gameRef); - if (!_backInactive || DID_FAIL(_backInactive->loadFile((char *)params))) { + if (!_backInactive || DID_FAIL(_backInactive->loadFile(params))) { delete _backInactive; _backInactive = nullptr; cmd = PARSERR_GENERIC; @@ -392,7 +392,7 @@ bool UIWindow::loadBuffer(byte *buffer, bool complete) { case TOKEN_IMAGE: delete _image; _image = new BaseSprite(_gameRef); - if (!_image || DID_FAIL(_image->loadFile((char *)params))) { + if (!_image || DID_FAIL(_image->loadFile(params))) { delete _image; _image = nullptr; cmd = PARSERR_GENERIC; @@ -400,9 +400,9 @@ bool UIWindow::loadBuffer(byte *buffer, bool complete) { break; case TOKEN_IMAGE_INACTIVE: - delete _imageInactive, - _imageInactive = new BaseSprite(_gameRef); - if (!_imageInactive || DID_FAIL(_imageInactive->loadFile((char *)params))) { + delete _imageInactive; + _imageInactive = new BaseSprite(_gameRef); + if (!_imageInactive || DID_FAIL(_imageInactive->loadFile(params))) { delete _imageInactive; _imageInactive = nullptr; cmd = PARSERR_GENERIC; @@ -413,7 +413,7 @@ bool UIWindow::loadBuffer(byte *buffer, bool complete) { if (_font) { _gameRef->_fontStorage->removeFont(_font); } - _font = _gameRef->_fontStorage->addFont((char *)params); + _font = _gameRef->_fontStorage->addFont(params); if (!_font) { cmd = PARSERR_GENERIC; } @@ -423,21 +423,21 @@ bool UIWindow::loadBuffer(byte *buffer, bool complete) { if (_fontInactive) { _gameRef->_fontStorage->removeFont(_fontInactive); } - _fontInactive = _gameRef->_fontStorage->addFont((char *)params); + _fontInactive = _gameRef->_fontStorage->addFont(params); if (!_fontInactive) { cmd = PARSERR_GENERIC; } break; case TOKEN_TITLE: - setText((char *)params); + setText(params); _gameRef->expandStringByStringTable(&_text); break; case TOKEN_TITLE_ALIGN: - if (scumm_stricmp((char *)params, "left") == 0) { + if (scumm_stricmp(params, "left") == 0) { _titleAlign = TAL_LEFT; - } else if (scumm_stricmp((char *)params, "right") == 0) { + } else if (scumm_stricmp(params, "right") == 0) { _titleAlign = TAL_RIGHT; } else { _titleAlign = TAL_CENTER; @@ -445,33 +445,33 @@ bool UIWindow::loadBuffer(byte *buffer, bool complete) { break; case TOKEN_TITLE_RECT: - parser.scanStr((char *)params, "%d,%d,%d,%d", &_titleRect.left, &_titleRect.top, &_titleRect.right, &_titleRect.bottom); + parser.scanStr(params, "%d,%d,%d,%d", &_titleRect.left, &_titleRect.top, &_titleRect.right, &_titleRect.bottom); break; case TOKEN_DRAG_RECT: - parser.scanStr((char *)params, "%d,%d,%d,%d", &_dragRect.left, &_dragRect.top, &_dragRect.right, &_dragRect.bottom); + parser.scanStr(params, "%d,%d,%d,%d", &_dragRect.left, &_dragRect.top, &_dragRect.right, &_dragRect.bottom); break; case TOKEN_X: - parser.scanStr((char *)params, "%d", &_posX); + parser.scanStr(params, "%d", &_posX); break; case TOKEN_Y: - parser.scanStr((char *)params, "%d", &_posY); + parser.scanStr(params, "%d", &_posY); break; case TOKEN_WIDTH: - parser.scanStr((char *)params, "%d", &_width); + parser.scanStr(params, "%d", &_width); break; case TOKEN_HEIGHT: - parser.scanStr((char *)params, "%d", &_height); + parser.scanStr(params, "%d", &_height); break; case TOKEN_CURSOR: delete _cursor; _cursor = new BaseSprite(_gameRef); - if (!_cursor || DID_FAIL(_cursor->loadFile((char *)params))) { + if (!_cursor || DID_FAIL(_cursor->loadFile(params))) { delete _cursor; _cursor = nullptr; cmd = PARSERR_GENERIC; @@ -532,48 +532,48 @@ bool UIWindow::loadBuffer(byte *buffer, bool complete) { case TOKEN_TRANSPARENT: - parser.scanStr((char *)params, "%b", &_transparent); + parser.scanStr(params, "%b", &_transparent); break; case TOKEN_SCRIPT: - addScript((char *)params); + addScript(params); break; case TOKEN_PARENT_NOTIFY: - parser.scanStr((char *)params, "%b", &_parentNotify); + parser.scanStr(params, "%b", &_parentNotify); break; case TOKEN_PAUSE_MUSIC: - parser.scanStr((char *)params, "%b", &_pauseMusic); + parser.scanStr(params, "%b", &_pauseMusic); break; case TOKEN_DISABLED: - parser.scanStr((char *)params, "%b", &_disable); + parser.scanStr(params, "%b", &_disable); break; case TOKEN_VISIBLE: - parser.scanStr((char *)params, "%b", &_visible); + parser.scanStr(params, "%b", &_visible); break; case TOKEN_MENU: - parser.scanStr((char *)params, "%b", &_isMenu); + parser.scanStr(params, "%b", &_isMenu); break; case TOKEN_IN_GAME: - parser.scanStr((char *)params, "%b", &_inGame); + parser.scanStr(params, "%b", &_inGame); break; case TOKEN_CLIP_CONTENTS: - parser.scanStr((char *)params, "%b", &_clipContents); + parser.scanStr(params, "%b", &_clipContents); break; case TOKEN_FADE_COLOR: - parser.scanStr((char *)params, "%d,%d,%d", &fadeR, &fadeG, &fadeB); + parser.scanStr(params, "%d,%d,%d", &fadeR, &fadeG, &fadeB); _fadeBackground = true; break; case TOKEN_FADE_ALPHA: - parser.scanStr((char *)params, "%d", &fadeA); + parser.scanStr(params, "%d", &fadeA); _fadeBackground = true; break; @@ -582,16 +582,16 @@ bool UIWindow::loadBuffer(byte *buffer, bool complete) { break; case TOKEN_ALPHA_COLOR: - parser.scanStr((char *)params, "%d,%d,%d", &ar, &ag, &ab); + parser.scanStr(params, "%d,%d,%d", &ar, &ag, &ab); break; case TOKEN_ALPHA: - parser.scanStr((char *)params, "%d", &alpha); + parser.scanStr(params, "%d", &alpha); break; default: - if (DID_FAIL(_gameRef->windowLoadHook(this, (char **)&buffer, (char **)params))) { + if (DID_FAIL(_gameRef->windowLoadHook(this, &buffer, ¶ms))) { cmd = PARSERR_GENERIC; } } @@ -737,7 +737,7 @@ bool UIWindow::saveAsText(BaseDynamicBuffer *buffer, int indent) { bool UIWindow::enableWidget(const char *name, bool enable) { for (uint32 i = 0; i < _widgets.size(); i++) { if (scumm_stricmp(_widgets[i]->getName(), name) == 0) { - _widgets[i]->_disable = !enable; + _widgets[i]->setDisabled(!enable); } } return STATUS_OK; @@ -748,7 +748,7 @@ bool UIWindow::enableWidget(const char *name, bool enable) { bool UIWindow::showWidget(const char *name, bool visible) { for (uint32 i = 0; i < _widgets.size(); i++) { if (scumm_stricmp(_widgets[i]->getName(), name) == 0) { - _widgets[i]->_visible = visible; + _widgets[i]->setVisible(visible); } } return STATUS_OK; @@ -1309,7 +1309,7 @@ bool UIWindow::moveFocus(bool forward) { bool done = false; while (numTries <= (int32)_widgets.size()) { - if (_widgets[i] != _focusedWidget && _widgets[i]->_canFocus && _widgets[i]->_visible && !_widgets[i]->_disable) { + if (_widgets[i] != _focusedWidget && _widgets[i]->canFocus() && _widgets[i]->isVisible() && !_widgets[i]->isDisabled()) { _focusedWidget = _widgets[i]; done = true; break; @@ -1419,7 +1419,7 @@ void UIWindow::makeFreezable(bool freezable) { bool UIWindow::getWindowObjects(BaseArray<UIObject *> &objects, bool interactiveOnly) { for (uint32 i = 0; i < _widgets.size(); i++) { UIObject *control = _widgets[i]; - if (control->_disable && interactiveOnly) { + if (control->isDisabled() && interactiveOnly) { continue; } @@ -1442,4 +1442,14 @@ bool UIWindow::getWindowObjects(BaseArray<UIObject *> &objects, bool interactive return STATUS_OK; } +bool UIWindow::getInGame() const { + return _inGame; +} + +TWindowMode UIWindow::getMode() const { + return _mode; +} + + + } // End of namespace Wintermute diff --git a/engines/wintermute/ui/ui_window.h b/engines/wintermute/ui/ui_window.h index 8a726fdff8..6b4d970581 100644 --- a/engines/wintermute/ui/ui_window.h +++ b/engines/wintermute/ui/ui_window.h @@ -38,47 +38,32 @@ namespace Wintermute { class UIButton; class BaseViewport; class UIWindow : public UIObject { - uint32 _fadeColor; public: bool getWindowObjects(BaseArray<UIObject *> &Objects, bool InteractiveOnly); - bool _pauseMusic; void cleanup(); virtual void makeFreezable(bool freezable); - BaseViewport *_viewport; - bool _clipContents; - bool _inGame; - bool _isMenu; - bool _fadeBackground; virtual bool handleMouseWheel(int delta); - UIWindow *_shieldWindow; - UIButton *_shieldButton; + bool close(); bool goSystemExclusive(); bool goExclusive(); - TWindowMode _mode; bool moveFocus(bool forward = true); virtual bool handleMouse(TMouseEvent Event, TMouseButton Button); - Point32 _dragFrom; - bool _dragging; DECLARE_PERSISTENT(UIWindow, UIObject) - bool _transparent; bool showWidget(const char *name, bool visible = true); bool enableWidget(const char *name, bool enable = true); - Rect32 _titleRect; - Rect32 _dragRect; + virtual bool display(int offsetX = 0, int offsetY = 0) override; UIWindow(BaseGame *inGame); virtual ~UIWindow(); virtual bool handleKeypress(Common::Event *event, bool printable = false) override; BaseArray<UIObject *> _widgets; - TTextAlign _titleAlign; + bool loadFile(const char *filename); - bool loadBuffer(byte *buffer, bool complete = true); - UITiledImage *_backInactive; - BaseFont *_fontInactive; - BaseSprite *_imageInactive; + bool loadBuffer(char *buffer, bool complete = true); + virtual bool listen(BaseScriptHolder *param1, uint32 param2); virtual bool saveAsText(BaseDynamicBuffer *buffer, int indent) override; @@ -87,6 +72,30 @@ public: virtual bool scSetProperty(const char *name, ScValue *value) override; virtual bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) override; virtual const char *scToString(); + + bool getInGame() const; + TWindowMode getMode() const; + +private: + bool _pauseMusic; + BaseViewport *_viewport; + bool _clipContents; + bool _inGame; + bool _isMenu; + bool _fadeBackground; + TWindowMode _mode; + Point32 _dragFrom; + bool _dragging; + bool _transparent; + uint32 _fadeColor; + UIWindow *_shieldWindow; + UIButton *_shieldButton; + Rect32 _titleRect; + Rect32 _dragRect; + UITiledImage *_backInactive; + BaseFont *_fontInactive; + BaseSprite *_imageInactive; + TTextAlign _titleAlign; }; } // End of namespace Wintermute diff --git a/graphics/cursorman.cpp b/graphics/cursorman.cpp index 6825767dfd..133ee5fd71 100644 --- a/graphics/cursorman.cpp +++ b/graphics/cursorman.cpp @@ -253,6 +253,7 @@ CursorManager::Cursor::Cursor(const void *data, uint w, uint h, int hotspotX, in _hotspotX = hotspotX; _hotspotY = hotspotY; _dontScale = dontScale; + _visible = false; } CursorManager::Cursor::~Cursor() { diff --git a/graphics/decoders/png.cpp b/graphics/decoders/png.cpp index 505475213f..5acb7b36f7 100644 --- a/graphics/decoders/png.cpp +++ b/graphics/decoders/png.cpp @@ -38,7 +38,7 @@ namespace Graphics { -PNGDecoder::PNGDecoder() : _outputSurface(0), _palette(0), _paletteColorCount(0) { +PNGDecoder::PNGDecoder() : _outputSurface(0), _palette(0), _paletteColorCount(0), _stream(0) { } PNGDecoder::~PNGDecoder() { diff --git a/gui/credits.h b/gui/credits.h index b4d1680842..aca3745631 100644 --- a/gui/credits.h +++ b/gui/credits.h @@ -77,6 +77,12 @@ static const char *credits[] = { "C0""Ludvig Strigeus", "C2""(retired)", "", +"C1""AVALANCHE", +"A0""Peter Bozso", +"C0""Peter Bozs\363", +"A0""Arnaud Boutonne", +"C0""Arnaud Boutonn\351", +"", "C1""CGE", "A0""Arnaud Boutonne", "C0""Arnaud Boutonn\351", @@ -621,6 +627,8 @@ static const char *credits[] = { "C2""Several fixes for Simon1", "C0""Jeroen Janssen", "C2""Numerous readability and bugfix patches", +"C0""Keith Kaisershot", +"C2""Several Pegasus Prime patches", "C0""Andreas Karlsson", "C2""Initial port for SymbianOS", "C0""Claudio Matsuoka", diff --git a/gui/predictivedialog.cpp b/gui/predictivedialog.cpp index 5ce093e054..ef94ec6d50 100644 --- a/gui/predictivedialog.cpp +++ b/gui/predictivedialog.cpp @@ -69,7 +69,7 @@ enum { PredictiveDialog::PredictiveDialog() : Dialog("Predictive") { new StaticTextWidget(this, "Predictive.Headline", "Enter Text"); - _btns = (ButtonWidget **)calloc(1, sizeof(ButtonWidget *) * 16); + _btns = (ButtonWidget **)calloc(16, sizeof(ButtonWidget *)); _btns[kCancelAct] = new ButtonWidget(this, "Predictive.Cancel", _("Cancel") , 0, kCancelCmd); _btns[kOkAct] = new ButtonWidget(this, "Predictive.OK", _("Ok") , 0, kOkCmd); @@ -144,6 +144,7 @@ PredictiveDialog::PredictiveDialog() : Dialog("Predictive") { _currentWord.clear(); _wordNumber = 0; _numMatchingWords = 0; + memset(_predictiveResult, 0, sizeof(_predictiveResult)); _lastbutton = kNoAct; _mode = kModePre; @@ -420,6 +421,9 @@ void PredictiveDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 d case kCancelCmd: saveUserDictToFile(); close(); + // When we cancel the dialog no result should be returned. Thus, we + // will invalidate any result here. + _predictiveResult[0] = 0; return; case kOkCmd: _currBtn = kOkAct; @@ -614,7 +618,7 @@ void PredictiveDialog::handleTickle() { void PredictiveDialog::mergeDicts() { _unitedDict.dictLineCount = _predictiveDict.dictLineCount + _userDict.dictLineCount; - _unitedDict.dictLine = (char **)calloc(1, sizeof(char *) * _unitedDict.dictLineCount); + _unitedDict.dictLine = (char **)calloc(_unitedDict.dictLineCount, sizeof(char *)); if (!_unitedDict.dictLine) { debug("Predictive Dialog: cannot allocate memory for united dic"); @@ -853,7 +857,7 @@ void PredictiveDialog::addWord(Dict &dict, const Common::String &word, const Com } // start from here are INSERTING new line to dictionaty ( dict ) - char **newDictLine = (char **)calloc(1, sizeof(char *) * (dict.dictLineCount + 1)); + char **newDictLine = (char **)calloc(dict.dictLineCount + 1, sizeof(char *)); if (!newDictLine) { warning("Predictive Dialog: cannot allocate memory for index buffer"); @@ -861,7 +865,6 @@ void PredictiveDialog::addWord(Dict &dict, const Common::String &word, const Com return; } - newDictLine[dict.dictLineCount] = '\0'; int k = 0; bool inserted = false; @@ -883,7 +886,7 @@ void PredictiveDialog::addWord(Dict &dict, const Common::String &word, const Com free(dict.dictLine); dict.dictLineCount += 1; - dict.dictLine = (char **)calloc(1, sizeof(char *) * dict.dictLineCount); + dict.dictLine = (char **)calloc(dict.dictLineCount, sizeof(char *)); if (!dict.dictLine) { warning("Predictive Dialog: cannot allocate memory for index buffer"); free(newDictLine); @@ -935,7 +938,7 @@ void PredictiveDialog::loadDictionary(Common::SeekableReadStream *in, Dict &dict ptr++; } - dict.dictLine = (char **)calloc(1, sizeof(char *) * lines); + dict.dictLine = (char **)calloc(lines, sizeof(char *)); if (dict.dictLine == NULL) { warning("Predictive Dialog: Cannot allocate memory for line index buffer"); return; diff --git a/gui/recorderdialog.h b/gui/recorderdialog.h index eb690a4f38..9c5965f56d 100644 --- a/gui/recorderdialog.h +++ b/gui/recorderdialog.h @@ -34,6 +34,8 @@ class ContainerWidget; class StaticTextWidget; class RecorderDialog : public GUI::Dialog { + using GUI::Dialog::runModal; + private: bool _firstScreenshotUpdate; Common::PlaybackFile _playbackFile; diff --git a/gui/widgets/list.cpp b/gui/widgets/list.cpp index 473d5f04df..8ecb31311f 100644 --- a/gui/widgets/list.cpp +++ b/gui/widgets/list.cpp @@ -91,6 +91,9 @@ ListWidget::ListWidget(Dialog *boss, int x, int y, int w, int h, const char *too // FIXME: This flag should come from widget definition _editable = true; + + _quickSelect = true; + _editColor = ThemeEngine::kFontColorNormal; } ListWidget::~ListWidget() { |