aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS5
-rw-r--r--backends/platform/3ds/sprite.cpp2
-rw-r--r--backends/platform/android/android.mk3
-rw-r--r--backends/platform/android/events.cpp21
-rw-r--r--backends/platform/android/org/scummvm/scummvm/ScummVMEvents.java2
-rw-r--r--common/array.h78
-rw-r--r--common/recorderfile.cpp4
-rw-r--r--common/scummsys.h4
-rw-r--r--common/str.cpp20
-rw-r--r--dists/android/AndroidManifest.xml16
-rw-r--r--dists/android/AndroidManifest.xml.in16
-rw-r--r--dists/android/res/drawable-xhdpi/leanback_icon.pngbin0 -> 25962 bytes
-rw-r--r--dists/macosx/scummvm_appcast.xml10
-rw-r--r--doc/de/Neues5
-rw-r--r--engines/access/access.cpp4
-rw-r--r--engines/access/access.h8
-rw-r--r--engines/access/amazon/amazon_game.cpp2
-rw-r--r--engines/access/asurface.cpp51
-rw-r--r--engines/access/asurface.h30
-rw-r--r--engines/access/bubble_box.cpp2
-rw-r--r--engines/access/detection.cpp2
-rw-r--r--engines/access/font.cpp4
-rw-r--r--engines/access/font.h4
-rw-r--r--engines/access/screen.cpp10
-rw-r--r--engines/access/screen.h4
-rw-r--r--engines/access/video.cpp6
-rw-r--r--engines/access/video.h8
-rw-r--r--engines/agi/global.cpp1
-rw-r--r--engines/agi/graphics.cpp12
-rw-r--r--engines/agi/preagi.cpp8
-rw-r--r--engines/agi/preagi.h3
-rw-r--r--engines/agi/saveload.cpp2
-rw-r--r--engines/agi/sound.cpp10
-rw-r--r--engines/agi/sound.h14
-rw-r--r--engines/agi/sound_2gs.cpp5
-rw-r--r--engines/agi/sound_pcjr.cpp5
-rw-r--r--engines/agi/sound_sarien.cpp5
-rw-r--r--engines/agi/systemui.cpp2
-rw-r--r--engines/agos/animation.cpp1
-rw-r--r--engines/agos/feeble.cpp1
-rw-r--r--engines/cge/detection.cpp2
-rw-r--r--engines/cge2/detection.cpp2
-rw-r--r--engines/gnap/character.cpp1415
-rw-r--r--engines/gnap/character.h146
-rw-r--r--engines/gnap/configure.engine3
-rw-r--r--engines/gnap/datarchive.cpp124
-rw-r--r--engines/gnap/datarchive.h80
-rw-r--r--engines/gnap/debugger.cpp42
-rw-r--r--engines/gnap/debugger.h54
-rw-r--r--engines/gnap/detection.cpp197
-rw-r--r--engines/gnap/fontdata.h849
-rw-r--r--engines/gnap/gamesys.cpp1260
-rw-r--r--engines/gnap/gamesys.h211
-rw-r--r--engines/gnap/gnap.cpp1190
-rw-r--r--engines/gnap/gnap.h477
-rw-r--r--engines/gnap/grid.cpp995
-rw-r--r--engines/gnap/menu.cpp888
-rw-r--r--engines/gnap/module.mk32
-rw-r--r--engines/gnap/music.cpp104
-rw-r--r--engines/gnap/music.h50
-rw-r--r--engines/gnap/resource.cpp121
-rw-r--r--engines/gnap/resource.h190
-rw-r--r--engines/gnap/scenes/arcade.cpp2729
-rw-r--r--engines/gnap/scenes/arcade.h290
-rw-r--r--engines/gnap/scenes/group0.cpp3570
-rw-r--r--engines/gnap/scenes/group0.h401
-rw-r--r--engines/gnap/scenes/group1.cpp4500
-rw-r--r--engines/gnap/scenes/group1.h454
-rw-r--r--engines/gnap/scenes/group2.cpp3423
-rw-r--r--engines/gnap/scenes/group2.h407
-rw-r--r--engines/gnap/scenes/group3.cpp1612
-rw-r--r--engines/gnap/scenes/group3.h240
-rw-r--r--engines/gnap/scenes/group4.cpp2799
-rw-r--r--engines/gnap/scenes/group4.h298
-rw-r--r--engines/gnap/scenes/group5.cpp381
-rw-r--r--engines/gnap/scenes/group5.h77
-rw-r--r--engines/gnap/scenes/groupcs.cpp430
-rw-r--r--engines/gnap/scenes/groupcs.h122
-rw-r--r--engines/gnap/scenes/intro.cpp182
-rw-r--r--engines/gnap/scenes/intro.h47
-rw-r--r--engines/gnap/scenes/scenecore.cpp740
-rw-r--r--engines/gnap/scenes/scenecore.h70
-rw-r--r--engines/gnap/sound.cpp96
-rw-r--r--engines/gnap/sound.h57
-rw-r--r--engines/groovie/cell.cpp1
-rw-r--r--engines/groovie/cursor.cpp2
-rw-r--r--engines/groovie/font.h2
-rw-r--r--engines/groovie/graphics.cpp2
-rw-r--r--engines/groovie/music.cpp5
-rw-r--r--engines/groovie/music.h2
-rw-r--r--engines/groovie/player.cpp3
-rw-r--r--engines/hopkins/detection.cpp2
-rw-r--r--engines/lab/detection.cpp2
-rw-r--r--engines/mads/detection.cpp2
-rw-r--r--engines/mads/dragonsphere/dragonsphere_scenes.cpp4
-rw-r--r--engines/mads/dragonsphere/dragonsphere_scenes.h4
-rw-r--r--engines/mads/font.cpp2
-rw-r--r--engines/mads/font.h2
-rw-r--r--engines/mads/messages.cpp2
-rw-r--r--engines/mads/messages.h2
-rw-r--r--engines/mads/msurface.cpp26
-rw-r--r--engines/mads/msurface.h34
-rw-r--r--engines/mads/nebular/nebular_scenes.cpp4
-rw-r--r--engines/mads/nebular/nebular_scenes.h4
-rw-r--r--engines/mads/phantom/phantom_scenes.cpp4
-rw-r--r--engines/mads/phantom/phantom_scenes.h4
-rw-r--r--engines/mads/scene_data.cpp8
-rw-r--r--engines/mads/scene_data.h12
-rw-r--r--engines/mads/screen.cpp4
-rw-r--r--engines/mads/screen.h6
-rw-r--r--engines/mads/sprites.cpp2
-rw-r--r--engines/mads/user_interface.cpp4
-rw-r--r--engines/mads/user_interface.h2
-rw-r--r--engines/parallaction/adlib.cpp9
-rw-r--r--engines/parallaction/balloons.cpp15
-rw-r--r--engines/parallaction/debug.cpp1
-rw-r--r--engines/parallaction/dialogue.cpp16
-rw-r--r--engines/parallaction/disk_br.cpp5
-rw-r--r--engines/parallaction/disk_ns.cpp2
-rw-r--r--engines/parallaction/exec.cpp2
-rw-r--r--engines/parallaction/font.cpp2
-rw-r--r--engines/parallaction/gfxbase.cpp3
-rw-r--r--engines/parallaction/graphics.cpp2
-rw-r--r--engines/parallaction/graphics.h2
-rw-r--r--engines/parallaction/gui_br.cpp6
-rw-r--r--engines/parallaction/gui_ns.cpp15
-rw-r--r--engines/parallaction/input.cpp3
-rw-r--r--engines/parallaction/objects.cpp5
-rw-r--r--engines/parallaction/parallaction_ns.cpp2
-rw-r--r--engines/parallaction/parser.cpp1
-rw-r--r--engines/parallaction/parser.h2
-rw-r--r--engines/parallaction/saveload.cpp2
-rw-r--r--engines/parallaction/sound_br.cpp7
-rw-r--r--engines/parallaction/sound_ns.cpp7
-rw-r--r--engines/sci/console.cpp9
-rw-r--r--engines/sci/engine/kernel_tables.h2
-rw-r--r--engines/sci/engine/kgraphics32.cpp3
-rw-r--r--engines/sci/engine/kscripts.cpp3
-rw-r--r--engines/sci/engine/savegame.cpp2
-rw-r--r--engines/sci/engine/workarounds.cpp1
-rw-r--r--engines/sci/graphics/celobj32.cpp54
-rw-r--r--engines/sci/graphics/celobj32.h8
-rw-r--r--engines/sci/graphics/compare.cpp20
-rw-r--r--engines/sci/graphics/controls32.cpp5
-rw-r--r--engines/sci/graphics/frameout.cpp8
-rw-r--r--engines/sci/graphics/plane32.cpp14
-rw-r--r--engines/sci/graphics/plane32.h20
-rw-r--r--engines/sci/graphics/screen_item32.cpp18
-rw-r--r--engines/sci/graphics/screen_item32.h4
-rw-r--r--engines/sci/graphics/text32.cpp20
-rw-r--r--engines/sci/graphics/text32.h16
-rw-r--r--engines/scumm/actor.cpp7
-rw-r--r--engines/scumm/he/intern_he.h29
-rw-r--r--engines/scumm/he/logic/moonbase_logic.cpp42
-rw-r--r--engines/scumm/he/logic_he.cpp2
-rw-r--r--engines/scumm/he/logic_he.h2
-rw-r--r--engines/scumm/he/moonbase/ai_defenseunit.cpp142
-rw-r--r--engines/scumm/he/moonbase/ai_defenseunit.h45
-rw-r--r--engines/scumm/he/moonbase/ai_main.cpp653
-rw-r--r--engines/scumm/he/moonbase/ai_main.h225
-rw-r--r--engines/scumm/he/moonbase/ai_node.h4
-rw-r--r--engines/scumm/he/moonbase/ai_targetacquisition.cpp153
-rw-r--r--engines/scumm/he/moonbase/ai_targetacquisition.h6
-rw-r--r--engines/scumm/he/moonbase/ai_traveller.cpp94
-rw-r--r--engines/scumm/he/moonbase/ai_traveller.h5
-rw-r--r--engines/scumm/he/moonbase/ai_tree.cpp100
-rw-r--r--engines/scumm/he/moonbase/ai_tree.h31
-rw-r--r--engines/scumm/he/moonbase/ai_types.cpp1
-rw-r--r--engines/scumm/he/moonbase/ai_weapon.cpp1
-rw-r--r--engines/scumm/he/moonbase/moonbase.cpp30
-rw-r--r--engines/scumm/he/moonbase/moonbase.h9
-rw-r--r--engines/scumm/he/script_v100he.cpp38
-rw-r--r--engines/scumm/he/script_v72he.cpp42
-rw-r--r--engines/scumm/he/wiz_he.cpp8
-rw-r--r--engines/scumm/scumm.cpp23
-rw-r--r--engines/scumm/scumm.h2
-rw-r--r--engines/scumm/scumm_v2.h1
-rw-r--r--engines/scumm/vars.cpp5
-rw-r--r--engines/sherlock/fonts.cpp2
-rw-r--r--engines/sherlock/fonts.h4
-rw-r--r--engines/sherlock/scalpel/scalpel_inventory.cpp2
-rw-r--r--engines/sherlock/screen.cpp5
-rw-r--r--engines/sherlock/screen.h3
-rw-r--r--engines/sherlock/surface.cpp15
-rw-r--r--engines/sherlock/surface.h28
-rw-r--r--engines/tsage/detection.cpp2
-rw-r--r--engines/tsage/graphics.cpp6
-rw-r--r--engines/tsage/graphics.h14
-rw-r--r--engines/tsage/screen.cpp7
-rw-r--r--engines/tsage/screen.h11
-rw-r--r--engines/voyeur/detection.cpp2
-rw-r--r--engines/voyeur/files.h8
-rw-r--r--engines/wintermute/detection.cpp2
-rw-r--r--graphics/module.mk1
-rw-r--r--graphics/nine_patch.cpp244
-rw-r--r--graphics/nine_patch.h97
-rw-r--r--graphics/screen.h2
-rw-r--r--image/codecs/msrle4.cpp2
-rw-r--r--po/be_BY.po56
-rw-r--r--po/ru_RU.po20
-rw-r--r--test/common/array.h41
-rw-r--r--test/module.mk1
202 files changed, 33309 insertions, 1182 deletions
diff --git a/NEWS b/NEWS
index 508970d499..252975c5ab 100644
--- a/NEWS
+++ b/NEWS
@@ -10,6 +10,11 @@ For a more comprehensive changelog of the latest experimental code, see:
- Added optional "pause, when entering commands" feature, that was only
available in the original interpreter for Hercules rendering.
+ SCI:
+ - Fix a missing dialog line in QfG3 which awards the player with 3 additional
+ points. This is a bug in the original game interpreter. Due to this bug,
+ it was not possible to get all points in the original game.
+
1.8.1 (2016-05-25)
New ports:
- Added Nintendo 3DS port.
diff --git a/backends/platform/3ds/sprite.cpp b/backends/platform/3ds/sprite.cpp
index a0aee385a9..f97c611473 100644
--- a/backends/platform/3ds/sprite.cpp
+++ b/backends/platform/3ds/sprite.cpp
@@ -62,7 +62,7 @@ void Sprite::create(uint16 width, uint16 height, const Graphics::PixelFormat &f)
actualHeight = height;
format = f;
w = MAX(nextHigher2(width), 64u);
- h = MAX(nextHigher2(height), 64u);;
+ h = MAX(nextHigher2(height), 64u);
pitch = w * format.bytesPerPixel;
dirtyPixels = true;
diff --git a/backends/platform/android/android.mk b/backends/platform/android/android.mk
index e11ad0724e..38128c62b0 100644
--- a/backends/platform/android/android.mk
+++ b/backends/platform/android/android.mk
@@ -3,7 +3,7 @@
# These must be incremented for each market upload
ANDROID_VERSIONCODE = 6
-ANDROID_TARGET_VERSION = 14
+ANDROID_TARGET_VERSION = 23
NDK_BUILD = $(ANDROID_NDK)/ndk-build APP_ABI=$(ABI)
SDK_ANDROID = $(ANDROID_SDK)/tools/android
@@ -20,6 +20,7 @@ RESOURCES = \
$(PATH_BUILD_RES)/layout/main.xml \
$(PATH_BUILD_RES)/drawable/scummvm.png \
$(PATH_BUILD_RES)/drawable/scummvm_big.png \
+ $(PATH_BUILD_RES)/drawable-xhdpi/leanback_icon.png \
$(PATH_BUILD_RES)/drawable-xhdpi/ouya_icon.png
DIST_ANDROID_MK = $(PATH_DIST)/jni/Android.mk
diff --git a/backends/platform/android/events.cpp b/backends/platform/android/events.cpp
index 8039981a92..b146945a01 100644
--- a/backends/platform/android/events.cpp
+++ b/backends/platform/android/events.cpp
@@ -101,7 +101,9 @@ enum {
JKEYCODE_MEDIA_NEXT = 87,
JKEYCODE_MEDIA_PREVIOUS = 88,
JKEYCODE_MEDIA_REWIND = 89,
- JKEYCODE_MEDIA_FAST_FORWARD = 90
+ JKEYCODE_MEDIA_FAST_FORWARD = 90,
+ JKEYCODE_MEDIA_PLAY = 126,
+ JKEYCODE_MEDIA_PAUSE = 127
};
// five-way navigation control
@@ -380,6 +382,19 @@ void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3,
return;
+ case JKEYCODE_MEDIA_PAUSE:
+ case JKEYCODE_MEDIA_PLAY:
+ case JKEYCODE_MEDIA_PLAY_PAUSE:
+ if (arg1 == JACTION_DOWN) {
+ e.type = Common::EVENT_MAINMENU;
+
+ lockMutex(_event_queue_lock);
+ _event_queue.push(e);
+ unlockMutex(_event_queue_lock);
+ }
+
+ return;
+
case JKEYCODE_CAMERA:
case JKEYCODE_SEARCH:
if (arg1 == JACTION_DOWN)
@@ -888,6 +903,10 @@ void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3,
e.kbd.ascii = Common::ASCII_ESCAPE;
break;
+ case JKEYCODE_BUTTON_Y:
+ e.type = Common::EVENT_MAINMENU;
+ break;
+
default:
LOGW("unmapped gamepad key: %d", arg2);
return;
diff --git a/backends/platform/android/org/scummvm/scummvm/ScummVMEvents.java b/backends/platform/android/org/scummvm/scummvm/ScummVMEvents.java
index 32c65d3395..e81000d8b1 100644
--- a/backends/platform/android/org/scummvm/scummvm/ScummVMEvents.java
+++ b/backends/platform/android/org/scummvm/scummvm/ScummVMEvents.java
@@ -119,6 +119,8 @@ public class ScummVMEvents implements
case KeyEvent.KEYCODE_MENU:
case KeyEvent.KEYCODE_CAMERA:
case KeyEvent.KEYCODE_SEARCH:
+ case KeyEvent.KEYCODE_MEDIA_PLAY:
+ case KeyEvent.KEYCODE_MEDIA_PAUSE:
break;
default:
diff --git a/common/array.h b/common/array.h
index db1a62ba34..e9b97aa38a 100644
--- a/common/array.h
+++ b/common/array.h
@@ -361,6 +361,84 @@ protected:
};
+/**
+ * Double linked list with sorted nodes.
+ */
+template<class T>
+class SortedArray : public Array<T> {
+public:
+ typedef T *iterator;
+ typedef uint size_type;
+
+ SortedArray(int (*comparator)(const void *, const void *)) {
+ _comparator = comparator;
+ }
+
+ /**
+ * Inserts element at the sorted position.
+ */
+ void insert(const T &element) {
+ if (!this->_size) {
+ this->insert_aux(this->_storage, &element, &element + 1);
+ return;
+ }
+
+ T *where = (T *)bsearchMin(element, this->front(), this->_size, sizeof(T), _comparator);
+ insert(where, element);
+ }
+
+ T &operator[](size_type idx) {
+ error("Operation not allowed with SortedArray");
+ }
+
+ void insert_at(size_type idx, const T &element) {
+ error("Operation not allowed with SortedArray");
+ }
+
+ void insert_at(size_type idx, const Array<T> &array) {
+ error("Operation not allowed with SortedArray");
+ }
+
+ void insert(iterator pos, const T &element) {
+ error("Operation not allowed with SortedArray");
+ }
+
+ void push_back(const T &element) {
+ error("Operation not allowed with SortedArray");
+ }
+
+ void push_back(const Array<T> &array) {
+ error("Operation not allowed with SortedArray");
+ }
+
+private:
+ // Based on code Copyright (C) 2008-2009 Ksplice, Inc.
+ // Author: Tim Abbott <tabbott@ksplice.com>
+ // Licensed under GPLv2+
+ void *bsearchMin(void *key, void *base, uint num, uint size_,
+ int (*cmp)(const void *key, const void *elt)) {
+ uint start_ = 0, end_ = num;
+ int result;
+
+ while (start_ < end_) {
+ uint mid = start_ + (end_ - start_) / 2;
+
+ result = cmp(key, (byte *)base + mid * size_);
+ if (result < 0)
+ end_ = mid;
+ else if (result > 0)
+ start_ = mid + 1;
+ else
+ return (void *)((byte *)base + mid * size_);
+ }
+
+ return (void *)((byte *)base + start_ * size_);
+ }
+
+private:
+ int (*_comparator)(const void *, const void *);
+};
+
} // End of namespace Common
#endif
diff --git a/common/recorderfile.cpp b/common/recorderfile.cpp
index 71f8272b44..04802aa0c8 100644
--- a/common/recorderfile.cpp
+++ b/common/recorderfile.cpp
@@ -30,6 +30,8 @@
#include "graphics/surface.h"
#include "graphics/scaler.h"
+#ifdef ENABLE_EVENTRECORDER
+
#define RECORD_VERSION 1
namespace Common {
@@ -714,3 +716,5 @@ void PlaybackFile::checkRecordedMD5() {
}
+
+#endif // ENABLE_EVENTRECORDER
diff --git a/common/scummsys.h b/common/scummsys.h
index 5e1069fb46..3513ee2d7d 100644
--- a/common/scummsys.h
+++ b/common/scummsys.h
@@ -215,6 +215,10 @@
#include "config.h"
#endif
+// Now we need to adjust some settings when running tests
+#ifdef COMPILING_TESTS
+#undef ENABLE_EVENTRECORDER
+#endif
// In the following we configure various targets, in particular those
// which can't use our "configure" tool and hence don't use config.h.
diff --git a/common/str.cpp b/common/str.cpp
index c41e958349..3ff49a90c6 100644
--- a/common/str.cpp
+++ b/common/str.cpp
@@ -144,7 +144,7 @@ void String::ensureCapacity(uint32 new_size, bool keep_old) {
// Allocate new storage
newStorage = new char[newCapacity];
assert(newStorage);
-
+
// Copy old data if needed, elsewise reset the new storage.
if (keep_old) {
@@ -447,12 +447,12 @@ void String::replace(uint32 pos, uint32 count, const char *str) {
replace(pos, count, str, 0, strlen(str));
}
-void String::replace(iterator begin, iterator end, const String &str) {
- replace(begin - _str, end - begin, str._str, 0, str._size);
+void String::replace(iterator begin_, iterator end_, const String &str) {
+ replace(begin_ - _str, end_ - begin_, str._str, 0, str._size);
}
-void String::replace(iterator begin, iterator end, const char *str) {
- replace(begin - _str, end - begin, str, 0, strlen(str));
+void String::replace(iterator begin_, iterator end_, const char *str) {
+ replace(begin_ - _str, end_ - begin_, str, 0, strlen(str));
}
void String::replace(uint32 posOri, uint32 countOri, const String &str,
@@ -472,21 +472,21 @@ void String::replace(uint32 posOri, uint32 countOri, const char *str,
_size = newSize;
// Push the old characters to the end of the string
- for (uint32 i = _size; i >= posOri + countDest; i--)
+ for (uint32 i = _size; i >= posOri + countDest; i--)
_str[i] = _str[i - offset];
} else if (countOri > countDest){
uint32 offset = countOri - countDest; ///< Number of positions that we have to pull back
// Pull the remainder string back
- for (uint32 i = posOri + countDest; i < _size; i++)
- _str[i] = _str[i + offset];
+ for (uint32 i = posOri + countDest; i < _size; i++)
+ _str[i] = _str[i + offset];
- _size -= offset;
+ _size -= offset;
}
// Copy the replaced part of the string
- for (uint32 i = 0; i < countDest; i++)
+ for (uint32 i = 0; i < countDest; i++)
_str[posOri + i] = str[posDest + i];
}
diff --git a/dists/android/AndroidManifest.xml b/dists/android/AndroidManifest.xml
index d605d9b3cc..14161668fe 100644
--- a/dists/android/AndroidManifest.xml
+++ b/dists/android/AndroidManifest.xml
@@ -15,6 +15,7 @@
<application
android:label="@string/app_name"
android:description="@string/app_desc"
+ android:isGame="true"
android:icon="@drawable/scummvm">
<activity android:name=".ScummVMActivity"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
@@ -27,6 +28,14 @@
<category android:name="tv.ouya.intent.category.GAME"/>
</intent-filter>
</activity>
+ <activity android:name=".ScummVMActivity"
+ android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
+ android:banner="@drawable/leanback_icon">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LEANBACK_LAUNCHER"/>
+ </intent-filter>
+ </activity>
</application>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
@@ -42,4 +51,11 @@
<uses-configuration android:reqTouchScreen="stylus"
android:reqKeyboardType="qwerty"/>
+
+ <uses-feature android:name="android.hardware.touchscreen"
+ android:required="false" />
+
+ <uses-feature android:name="android.software.leanback"
+ android:required="false" />
+
</manifest>
diff --git a/dists/android/AndroidManifest.xml.in b/dists/android/AndroidManifest.xml.in
index d90e282e3d..de2f2d905e 100644
--- a/dists/android/AndroidManifest.xml.in
+++ b/dists/android/AndroidManifest.xml.in
@@ -15,6 +15,7 @@
<application
android:label="@string/app_name"
android:description="@string/app_desc"
+ android:isGame="true"
android:icon="@drawable/scummvm">
<activity android:name=".ScummVMActivity"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
@@ -27,6 +28,14 @@
<category android:name="tv.ouya.intent.category.GAME"/>
</intent-filter>
</activity>
+ <activity android:name=".ScummVMActivity"
+ android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
+ android:banner="@drawable/leanback_icon">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LEANBACK_LAUNCHER"/>
+ </intent-filter>
+ </activity>
</application>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
@@ -42,4 +51,11 @@
<uses-configuration android:reqTouchScreen="stylus"
android:reqKeyboardType="qwerty"/>
+
+ <uses-feature android:name="android.hardware.touchscreen"
+ android:required="false" />
+
+ <uses-feature android:name="android.software.leanback"
+ android:required="false" />
+
</manifest>
diff --git a/dists/android/res/drawable-xhdpi/leanback_icon.png b/dists/android/res/drawable-xhdpi/leanback_icon.png
new file mode 100644
index 0000000000..28a7196b7f
--- /dev/null
+++ b/dists/android/res/drawable-xhdpi/leanback_icon.png
Binary files differ
diff --git a/dists/macosx/scummvm_appcast.xml b/dists/macosx/scummvm_appcast.xml
index 3d47c94bbc..35fbc54908 100644
--- a/dists/macosx/scummvm_appcast.xml
+++ b/dists/macosx/scummvm_appcast.xml
@@ -6,6 +6,16 @@
<description>Most recent changes with links to updates.</description>
<language>en</language>
<item>
+ <title>Version 1.8.1</title>
+ <sparkle:releaseNotesLink>
+ https://scummvm.org/frs/scummvm/1.8.1/ReleaseNotes
+ </sparkle:releaseNotesLink>
+ <pubDate>Wed, 25 May 2016 19:26:00 +0000</pubDate>
+ <enclosure url="https://www.scummvm.org/frs/scummvm/1.8.1/scummvm-1.8.1-macosx.dmg"
+ sparkle:version="1.8.1" length="15791070" type="application/octet-stream"
+ sparkle:dsaSignature="MC0CFQDF0u/pGH51pMPzCbsv07eCNxuGDQIUdrKWVTznbF69fzuzIieR4Lc0U2Y=" />
+ </item>
+ <item>
<title>Version 1.8.0</title>
<sparkle:releaseNotesLink>
https://scummvm.org/frs/scummvm/1.8.0/ReleaseNotes
diff --git a/doc/de/Neues b/doc/de/Neues
index 8015feb05b..8d459a1864 100644
--- a/doc/de/Neues
+++ b/doc/de/Neues
@@ -11,6 +11,11 @@ Programmcodes finden Sie auf Englisch unter:
Diese Funktion war im originalen Interpreter nur im Hercules-Darstellungsmodus
verfУМgbar.
+ SCI:
+ - Fehlende Dialogzeile in QfG3 hinzugefУМgt, die mit drei zusУЄtzlichen Punkten
+ belohnt wird. Diese Dialogzeile fehlt im Originalspiel, weshalb
+ es bislang unmУЖglich war, die maximale Punktzahl im Spiel zu erreichen.
+
1.8.1 (25.05.2016)
Neue Portierungen:
- Portierung fУМr den Nintendo 3DS hinzugefУМgt.
diff --git a/engines/access/access.cpp b/engines/access/access.cpp
index c12761af4a..6f91bd76dd 100644
--- a/engines/access/access.cpp
+++ b/engines/access/access.cpp
@@ -244,7 +244,7 @@ void AccessEngine::freeCells() {
}
}
-void AccessEngine::speakText(ASurface *s, const Common::String &msg) {
+void AccessEngine::speakText(BaseSurface *s, const Common::String &msg) {
Common::String lines = msg;
Common::String line;
int curPage = 0;
@@ -325,7 +325,7 @@ void AccessEngine::speakText(ASurface *s, const Common::String &msg) {
}
}
-void AccessEngine::printText(ASurface *s, const Common::String &msg) {
+void AccessEngine::printText(BaseSurface *s, const Common::String &msg) {
Common::String lines = msg;
Common::String line;
int width = 0;
diff --git a/engines/access/access.h b/engines/access/access.h
index 2ca4a3468e..972dd4c380 100644
--- a/engines/access/access.h
+++ b/engines/access/access.h
@@ -156,8 +156,8 @@ public:
MusicManager *_midi;
VideoPlayer *_video;
- ASurface *_destIn;
- ASurface *_current;
+ BaseSurface *_destIn;
+ BaseSurface *_current;
ASurface _buffer1;
ASurface _buffer2;
ASurface _vidBuf;
@@ -280,8 +280,8 @@ public:
/**
* Draw a string on a given surface and update text positioning
*/
- void printText(ASurface *s, const Common::String &msg);
- void speakText(ASurface *s, const Common::String &msg);
+ void printText(BaseSurface *s, const Common::String &msg);
+ void speakText(BaseSurface *s, const Common::String &msg);
/**
* Load a savegame
diff --git a/engines/access/amazon/amazon_game.cpp b/engines/access/amazon/amazon_game.cpp
index 0a671d23d2..8467d8b623 100644
--- a/engines/access/amazon/amazon_game.cpp
+++ b/engines/access/amazon/amazon_game.cpp
@@ -496,7 +496,7 @@ void AmazonEngine::drawHelp(const Common::String str) {
_files->loadScreen(95, 2);
if (_moreHelp == 1) {
- ASurface *oldDest = _destIn;
+ BaseSurface *oldDest = _destIn;
_destIn = _screen;
int oldClip = _screen->_clipHeight;
_screen->_clipHeight = 200;
diff --git a/engines/access/asurface.cpp b/engines/access/asurface.cpp
index 2518ff6ad8..37f4c7082e 100644
--- a/engines/access/asurface.cpp
+++ b/engines/access/asurface.cpp
@@ -107,10 +107,11 @@ void ImageEntryList::addToList(ImageEntry &ie) {
/*------------------------------------------------------------------------*/
-int ASurface::_clipWidth;
-int ASurface::_clipHeight;
+int BaseSurface::_clipWidth;
+int BaseSurface::_clipHeight;
-ASurface::ASurface(): Graphics::ManagedSurface() {
+BaseSurface::BaseSurface(): Graphics::Screen(0, 0) {
+ free(); // Free the 0x0 surface allocated by Graphics::Screen
_leftSkip = _rightSkip = 0;
_topSkip = _bottomSkip = 0;
_lastBoundsX = _lastBoundsY = 0;
@@ -121,16 +122,16 @@ ASurface::ASurface(): Graphics::ManagedSurface() {
_maxChars = 0;
}
-ASurface::~ASurface() {
+BaseSurface::~BaseSurface() {
_savedBlock.free();
}
-void ASurface::clearBuffer() {
+void BaseSurface::clearBuffer() {
byte *pSrc = (byte *)getPixels();
Common::fill(pSrc, pSrc + w * h, 0);
}
-void ASurface::plotImage(SpriteResource *sprite, int frameNum, const Common::Point &pt) {
+void BaseSurface::plotImage(SpriteResource *sprite, int frameNum, const Common::Point &pt) {
SpriteFrame *frame = sprite->getFrame(frameNum);
Common::Rect r(pt.x, pt.y, pt.x + frame->w, pt.y + frame->h);
@@ -144,38 +145,38 @@ void ASurface::plotImage(SpriteResource *sprite, int frameNum, const Common::Poi
}
}
-void ASurface::copyBuffer(Graphics::ManagedSurface *src) {
+void BaseSurface::copyBuffer(Graphics::ManagedSurface *src) {
blitFrom(*src);
}
-void ASurface::plotF(SpriteFrame *frame, const Common::Point &pt) {
+void BaseSurface::plotF(SpriteFrame *frame, const Common::Point &pt) {
sPlotF(frame, Common::Rect(pt.x, pt.y, pt.x + frame->w, pt.y + frame->h));
}
-void ASurface::plotB(SpriteFrame *frame, const Common::Point &pt) {
+void BaseSurface::plotB(SpriteFrame *frame, const Common::Point &pt) {
sPlotB(frame, Common::Rect(pt.x, pt.y, pt.x + frame->w, pt.y + frame->h));
}
-void ASurface::sPlotF(SpriteFrame *frame, const Common::Rect &bounds) {
+void BaseSurface::sPlotF(SpriteFrame *frame, const Common::Rect &bounds) {
transBlitFrom(*frame, Common::Rect(0, 0, frame->w, frame->h), bounds, TRANSPARENCY, false);
}
-void ASurface::sPlotB(SpriteFrame *frame, const Common::Rect &bounds) {
+void BaseSurface::sPlotB(SpriteFrame *frame, const Common::Rect &bounds) {
transBlitFrom(*frame, Common::Rect(0, 0, frame->w, frame->h), bounds, TRANSPARENCY, true);
}
-void ASurface::copyBlock(ASurface *src, const Common::Rect &bounds) {
+void BaseSurface::copyBlock(BaseSurface *src, const Common::Rect &bounds) {
copyRectToSurface(*src, bounds.left, bounds.top, bounds);
}
-void ASurface::copyTo(ASurface *dest) {
+void BaseSurface::copyTo(BaseSurface *dest) {
if (dest->empty())
dest->create(this->w, this->h);
dest->blitFrom(*this);
}
-void ASurface::saveBlock(const Common::Rect &bounds) {
+void BaseSurface::saveBlock(const Common::Rect &bounds) {
_savedBounds = bounds;
_savedBounds.clip(Common::Rect(0, 0, this->w, this->h));
@@ -185,7 +186,7 @@ void ASurface::saveBlock(const Common::Rect &bounds) {
_savedBlock.copyRectToSurface(*this, 0, 0, _savedBounds);
}
-void ASurface::restoreBlock() {
+void BaseSurface::restoreBlock() {
if (!_savedBounds.isEmpty()) {
copyRectToSurface(_savedBlock, _savedBounds.left, _savedBounds.top,
Common::Rect(0, 0, _savedBlock.w, _savedBlock.h));
@@ -195,26 +196,26 @@ void ASurface::restoreBlock() {
}
}
-void ASurface::drawRect() {
+void BaseSurface::drawRect() {
Graphics::ManagedSurface::fillRect(Common::Rect(_orgX1, _orgY1, _orgX2, _orgY2), _lColor);
}
-void ASurface::drawLine(int x1, int y1, int x2, int y2, int col) {
+void BaseSurface::drawLine(int x1, int y1, int x2, int y2, int col) {
Graphics::ManagedSurface::drawLine(x1, y1, x2, y2, col);
}
-void ASurface::drawLine() {
+void BaseSurface::drawLine() {
Graphics::ManagedSurface::drawLine(_orgX1, _orgY1, _orgX2, _orgY1, _lColor);
}
-void ASurface::drawBox() {
+void BaseSurface::drawBox() {
Graphics::ManagedSurface::drawLine(_orgX1, _orgY1, _orgX2, _orgY1, _lColor);
Graphics::ManagedSurface::drawLine(_orgX1, _orgY2, _orgX2, _orgY2, _lColor);
Graphics::ManagedSurface::drawLine(_orgX2, _orgY1, _orgX2, _orgY1, _lColor);
Graphics::ManagedSurface::drawLine(_orgX2, _orgY2, _orgX2, _orgY2, _lColor);
}
-void ASurface::flipHorizontal(ASurface &dest) {
+void BaseSurface::flipHorizontal(BaseSurface &dest) {
dest.create(this->w, this->h);
for (int y = 0; y < h; ++y) {
const byte *pSrc = (const byte *)getBasePtr(this->w - 1, y);
@@ -225,27 +226,27 @@ void ASurface::flipHorizontal(ASurface &dest) {
}
}
-void ASurface::moveBufferLeft() {
+void BaseSurface::moveBufferLeft() {
byte *p = (byte *)getPixels();
Common::copy(p + TILE_WIDTH, p + (w * h), p);
}
-void ASurface::moveBufferRight() {
+void BaseSurface::moveBufferRight() {
byte *p = (byte *)getPixels();
Common::copy_backward(p, p + (pitch * h) - TILE_WIDTH, p + (pitch * h));
}
-void ASurface::moveBufferUp() {
+void BaseSurface::moveBufferUp() {
byte *p = (byte *)getPixels();
Common::copy(p + (pitch * TILE_HEIGHT), p + (pitch * h), p);
}
-void ASurface::moveBufferDown() {
+void BaseSurface::moveBufferDown() {
byte *p = (byte *)getPixels();
Common::copy_backward(p, p + (pitch * (h - TILE_HEIGHT)), p + (pitch * h));
}
-bool ASurface::clip(Common::Rect &r) {
+bool BaseSurface::clip(Common::Rect &r) {
int skip;
_leftSkip = _rightSkip = 0;
_topSkip = _bottomSkip = 0;
diff --git a/engines/access/asurface.h b/engines/access/asurface.h
index ec18ec09c3..64ddf3d0ee 100644
--- a/engines/access/asurface.h
+++ b/engines/access/asurface.h
@@ -27,7 +27,7 @@
#include "common/array.h"
#include "common/memstream.h"
#include "common/rect.h"
-#include "graphics/managed_surface.h"
+#include "graphics/screen.h"
#include "access/data.h"
namespace Access {
@@ -35,11 +35,16 @@ namespace Access {
class SpriteResource;
class SpriteFrame;
-class ASurface : virtual public Graphics::ManagedSurface {
+/**
+ * Base Access surface class. This derivces from Graphics::Screen
+ * because it has logic we'll need for our own Screen class that
+ * derives from this one
+ */
+class BaseSurface : virtual public Graphics::Screen {
private:
Graphics::Surface _savedBlock;
- void flipHorizontal(ASurface &dest);
+ void flipHorizontal(BaseSurface &dest);
protected:
Common::Rect _savedBounds;
public:
@@ -57,9 +62,9 @@ public:
public:
static int _clipWidth, _clipHeight;
public:
- ASurface();
+ BaseSurface();
- virtual ~ASurface();
+ virtual ~BaseSurface();
void clearBuffer();
@@ -85,7 +90,7 @@ public:
*/
void plotB(SpriteFrame *frame, const Common::Point &pt);
- virtual void copyBlock(ASurface *src, const Common::Rect &bounds);
+ virtual void copyBlock(BaseSurface *src, const Common::Rect &bounds);
virtual void restoreBlock();
@@ -99,7 +104,7 @@ public:
virtual void copyBuffer(Graphics::ManagedSurface *src);
- void copyTo(ASurface *dest);
+ void copyTo(BaseSurface *dest);
void saveBlock(const Common::Rect &bounds);
@@ -114,6 +119,17 @@ public:
bool clip(Common::Rect &r);
};
+class ASurface : public BaseSurface {
+protected:
+ /**
+ * Override the addDirtyRect from Graphics::Screen, since for standard
+ * surfaces we don't need dirty rects to be tracked
+ */
+ virtual void addDirtyRect(const Common::Rect &r) {}
+public:
+ ASurface() : BaseSurface() {}
+};
+
class SpriteFrame : public ASurface {
public:
SpriteFrame(AccessEngine *vm, Common::SeekableReadStream *stream, int frameSize);
diff --git a/engines/access/bubble_box.cpp b/engines/access/bubble_box.cpp
index e55701900a..29b58a3f1b 100644
--- a/engines/access/bubble_box.cpp
+++ b/engines/access/bubble_box.cpp
@@ -228,7 +228,7 @@ void BubbleBox::drawBubble(int index) {
void BubbleBox::doBox(int item, int box) {
FontManager &fonts = _vm->_fonts;
- ASurface &screen = *_vm->_screen;
+ Screen &screen = *_vm->_screen;
_startItem = item;
_startBox = box;
diff --git a/engines/access/detection.cpp b/engines/access/detection.cpp
index 2cd7e50f0f..368753f117 100644
--- a/engines/access/detection.cpp
+++ b/engines/access/detection.cpp
@@ -94,7 +94,7 @@ public:
}
virtual const char *getOriginalCopyright() const {
- return "Access Engine (c) 1989-1994 Access Software";
+ return "Access Engine (C) 1989-1994 Access Software";
}
virtual bool hasFeature(MetaEngineFeature f) const;
diff --git a/engines/access/font.cpp b/engines/access/font.cpp
index 6ae65e43f0..8e02f80769 100644
--- a/engines/access/font.cpp
+++ b/engines/access/font.cpp
@@ -139,7 +139,7 @@ bool Font::getLine(Common::String &s, int maxWidth, Common::String &line, int &w
return true;
}
-void Font::drawString(ASurface *s, const Common::String &msg, const Common::Point &pt) {
+void Font::drawString(BaseSurface *s, const Common::String &msg, const Common::Point &pt) {
Common::Point currPt = pt;
const char *msgP = msg.c_str();
@@ -149,7 +149,7 @@ void Font::drawString(ASurface *s, const Common::String &msg, const Common::Poin
}
}
-int Font::drawChar(ASurface *s, char c, Common::Point &pt) {
+int Font::drawChar(BaseSurface *s, char c, Common::Point &pt) {
Graphics::Surface &ch = _chars[c - ' '];
Graphics::Surface dest = s->getSubArea(Common::Rect(pt.x, pt.y, pt.x + ch.w, pt.y + ch.h));
diff --git a/engines/access/font.h b/engines/access/font.h
index 6a812051ca..9234078af2 100644
--- a/engines/access/font.h
+++ b/engines/access/font.h
@@ -78,12 +78,12 @@ public:
/**
* Draw a string on a given surface
*/
- void drawString(ASurface *s, const Common::String &msg, const Common::Point &pt);
+ void drawString(BaseSurface *s, const Common::String &msg, const Common::Point &pt);
/**
* Draw a character on a given surface
*/
- int drawChar(ASurface *s, char c, Common::Point &pt);
+ int drawChar(BaseSurface *s, char c, Common::Point &pt);
};
diff --git a/engines/access/screen.cpp b/engines/access/screen.cpp
index 9700640b71..2d29ad0718 100644
--- a/engines/access/screen.cpp
+++ b/engines/access/screen.cpp
@@ -253,7 +253,7 @@ void Screen::restoreScreen() {
_screenYOff = _screenSave._screenYOff;
}
-void Screen::copyBlock(ASurface *src, const Common::Rect &bounds) {
+void Screen::copyBlock(BaseSurface *src, const Common::Rect &bounds) {
Common::Rect destBounds = bounds;
destBounds.translate(_windowXAdd, _windowYAdd + _screenYOff);
@@ -264,22 +264,22 @@ void Screen::copyBlock(ASurface *src, const Common::Rect &bounds) {
void Screen::restoreBlock() {
if (!_savedBounds.isEmpty())
addDirtyRect(_savedBounds);
- ASurface::restoreBlock();
+ BaseSurface::restoreBlock();
}
void Screen::drawRect() {
addDirtyRect(Common::Rect(_orgX1, _orgY1, _orgX2, _orgY2));
- ASurface::drawRect();
+ BaseSurface::drawRect();
}
void Screen::drawBox() {
addDirtyRect(Common::Rect(_orgX1, _orgY1, _orgX2, _orgY2));
- ASurface::drawBox();
+ BaseSurface::drawBox();
}
void Screen::copyBuffer(Graphics::ManagedSurface *src) {
addDirtyRect(Common::Rect(0, 0, src->w, src->h));
- ASurface::copyBuffer(src);
+ BaseSurface::copyBuffer(src);
}
void Screen::setPaletteCycle(int startCycle, int endCycle, int timer) {
diff --git a/engines/access/screen.h b/engines/access/screen.h
index a022741f91..1c1932511d 100644
--- a/engines/access/screen.h
+++ b/engines/access/screen.h
@@ -45,7 +45,7 @@ struct ScreenSave {
int _screenYOff;
};
-class Screen : public virtual ASurface, public virtual Graphics::Screen {
+class Screen : public BaseSurface {
private:
AccessEngine *_vm;
byte _tempPalette[PALETTE_SIZE];
@@ -86,7 +86,7 @@ public:
*/
virtual void update();
- virtual void copyBlock(ASurface *src, const Common::Rect &bounds);
+ virtual void copyBlock(BaseSurface *src, const Common::Rect &bounds);
virtual void restoreBlock();
diff --git a/engines/access/video.cpp b/engines/access/video.cpp
index e3ff457c3b..22842a5855 100644
--- a/engines/access/video.cpp
+++ b/engines/access/video.cpp
@@ -48,7 +48,7 @@ VideoPlayer::~VideoPlayer() {
closeVideo();
}
-void VideoPlayer::setVideo(ASurface *vidSurface, const Common::Point &pt, int rate) {
+void VideoPlayer::setVideo(BaseSurface *vidSurface, const Common::Point &pt, int rate) {
_vidSurface = vidSurface;
vidSurface->_orgX1 = pt.x;
vidSurface->_orgY1 = pt.y;
@@ -87,14 +87,14 @@ void VideoPlayer::setVideo(ASurface *vidSurface, const Common::Point &pt, int ra
_videoEnd = false;
}
-void VideoPlayer::setVideo(ASurface *vidSurface, const Common::Point &pt, const Common::String filename, int rate) {
+void VideoPlayer::setVideo(BaseSurface *vidSurface, const Common::Point &pt, const Common::String filename, int rate) {
// Open up video stream
_videoData = _vm->_files->loadFile(filename);
setVideo(vidSurface, pt, rate);
}
-void VideoPlayer::setVideo(ASurface *vidSurface, const Common::Point &pt, const FileIdent &videoFile, int rate) {
+void VideoPlayer::setVideo(BaseSurface *vidSurface, const Common::Point &pt, const FileIdent &videoFile, int rate) {
// Open up video stream
_videoData = _vm->_files->loadFile(videoFile);
diff --git a/engines/access/video.h b/engines/access/video.h
index 83c8995d3e..65dff3ebea 100644
--- a/engines/access/video.h
+++ b/engines/access/video.h
@@ -40,7 +40,7 @@ class VideoPlayer : public Manager {
VideoFlags _flags;
};
private:
- ASurface *_vidSurface;
+ BaseSurface *_vidSurface;
Resource *_videoData;
VideoHeader _header;
byte *_startCoord;
@@ -51,7 +51,7 @@ private:
Common::Rect _videoBounds;
void getFrame();
- void setVideo(ASurface *vidSurface, const Common::Point &pt, int rate);
+ void setVideo(BaseSurface *vidSurface, const Common::Point &pt, int rate);
public:
int _videoFrame;
bool _soundFlag;
@@ -64,8 +64,8 @@ public:
/**
* Start up a video
*/
- void setVideo(ASurface *vidSurface, const Common::Point &pt, const FileIdent &videoFile, int rate);
- void setVideo(ASurface *vidSurface, const Common::Point &pt, const Common::String filename, int rate);
+ void setVideo(BaseSurface *vidSurface, const Common::Point &pt, const FileIdent &videoFile, int rate);
+ void setVideo(BaseSurface *vidSurface, const Common::Point &pt, const Common::String filename, int rate);
/**
* Decodes a frame of the video
diff --git a/engines/agi/global.cpp b/engines/agi/global.cpp
index 23256f27fb..6f83f02a4e 100644
--- a/engines/agi/global.cpp
+++ b/engines/agi/global.cpp
@@ -21,6 +21,7 @@
*/
#include "common/config-manager.h"
+#include "audio/mixer.h"
#include "agi/agi.h"
#include "agi/graphics.h"
diff --git a/engines/agi/graphics.cpp b/engines/agi/graphics.cpp
index 6d3563a451..24cd4f43d3 100644
--- a/engines/agi/graphics.cpp
+++ b/engines/agi/graphics.cpp
@@ -605,7 +605,7 @@ void GfxMgr::render_BlockEGA(int16 x, int16 y, int16 width, int16 height, bool c
switch (_upscaledHires) {
case DISPLAY_UPSCALED_640x400:
- offsetDisplay += _displayScreenWidth;;
+ offsetDisplay += _displayScreenWidth;
break;
default:
break;
@@ -660,7 +660,7 @@ void GfxMgr::render_BlockCGA(int16 x, int16 y, int16 width, int16 height, bool c
switch (_upscaledHires) {
case DISPLAY_UPSCALED_640x400:
- offsetDisplay += _displayScreenWidth;;
+ offsetDisplay += _displayScreenWidth;
break;
default:
break;
@@ -743,7 +743,7 @@ void GfxMgr::render_BlockHercules(int16 x, int16 y, int16 width, int16 height, b
offsetVisual += SCRIPT_WIDTH - width;
offsetDisplay += _displayScreenWidth - displayWidth;
- offsetDisplay += _displayScreenWidth;;
+ offsetDisplay += _displayScreenWidth;
remainingHeight--;
}
@@ -1178,13 +1178,17 @@ void GfxMgr::drawCharacterOnDisplay(int16 x, int16 y, const byte character, byte
#define SHAKE_HORIZONTAL_PIXELS 4
// Sierra used some EGA port trickery to do it, we have to do it by copying pixels around
+//
+// Shaking locations:
+// - Fanmade "Enclosure" right during the intro
+// - Space Quest 2 almost right at the start when getting captured (after walking into the space ship)
void GfxMgr::shakeScreen(int16 repeatCount) {
int shakeNr, shakeCount;
uint8 *blackSpace;
int16 shakeHorizontalPixels = SHAKE_HORIZONTAL_PIXELS * (2 + _displayWidthMulAdjust);
int16 shakeVerticalPixels = SHAKE_VERTICAL_PIXELS * (1 + _displayHeightMulAdjust);
- if ((blackSpace = (uint8 *)calloc(shakeVerticalPixels * _displayScreenWidth, 1)) == NULL)
+ if ((blackSpace = (uint8 *)calloc(shakeHorizontalPixels * _displayScreenWidth, 1)) == NULL)
return;
shakeCount = repeatCount * 8; // effectively 4 shakes per repeat
diff --git a/engines/agi/preagi.cpp b/engines/agi/preagi.cpp
index 7e2e65a3eb..f8630db0b6 100644
--- a/engines/agi/preagi.cpp
+++ b/engines/agi/preagi.cpp
@@ -20,6 +20,7 @@
*
*/
+#include "audio/mixer.h"
#include "audio/softsynth/pcspk.h"
#include "common/debug-channels.h"
@@ -50,6 +51,8 @@ PreAgiEngine::PreAgiEngine(OSystem *syst, const AGIGameDescription *gameDesc) :
memset(&_game, 0, sizeof(struct AgiGame));
memset(&_debug, 0, sizeof(struct AgiDebug));
memset(&_mouse, 0, sizeof(struct Mouse));
+
+ _speakerHandle = new Audio::SoundHandle();
}
void PreAgiEngine::initialize() {
@@ -74,7 +77,7 @@ void PreAgiEngine::initialize() {
_gfx->initVideo();
_speakerStream = new Audio::PCSpeaker(_mixer->getOutputRate());
- _mixer->playStream(Audio::Mixer::kSFXSoundType, &_speakerHandle,
+ _mixer->playStream(Audio::Mixer::kSFXSoundType, _speakerHandle,
_speakerStream, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
debugC(2, kDebugLevelMain, "Detect game");
@@ -89,8 +92,9 @@ void PreAgiEngine::initialize() {
}
PreAgiEngine::~PreAgiEngine() {
- _mixer->stopHandle(_speakerHandle);
+ _mixer->stopHandle(*_speakerHandle);
delete _speakerStream;
+ delete _speakerHandle;
delete _picture;
delete _gfx;
diff --git a/engines/agi/preagi.h b/engines/agi/preagi.h
index d6026a5d4d..6950aa30cd 100644
--- a/engines/agi/preagi.h
+++ b/engines/agi/preagi.h
@@ -26,6 +26,7 @@
#include "agi/agi.h"
namespace Audio {
+class SoundHandle;
class PCSpeaker;
}
@@ -110,7 +111,7 @@ private:
int _defaultColor;
Audio::PCSpeaker *_speakerStream;
- Audio::SoundHandle _speakerHandle;
+ Audio::SoundHandle *_speakerHandle;
};
} // End of namespace Agi
diff --git a/engines/agi/saveload.cpp b/engines/agi/saveload.cpp
index aa46cf4e9f..fc4aea3169 100644
--- a/engines/agi/saveload.cpp
+++ b/engines/agi/saveload.cpp
@@ -829,7 +829,7 @@ SavedGameSlotIdArray AgiEngine::getSavegameSlotIds() {
filenames = _saveFileMan->listSavefiles(_targetName + ".###");
Common::StringArray::iterator it;
- Common::StringArray::iterator end = filenames.end();;
+ Common::StringArray::iterator end = filenames.end();
// convert to lower-case, just to be sure
for (it = filenames.begin(); it != end; it++) {
diff --git a/engines/agi/sound.cpp b/engines/agi/sound.cpp
index edf17960ad..8834068ace 100644
--- a/engines/agi/sound.cpp
+++ b/engines/agi/sound.cpp
@@ -29,9 +29,19 @@
#include "agi/sound_pcjr.h"
#include "common/textconsole.h"
+#include "audio/mixer.h"
namespace Agi {
+SoundGen::SoundGen(AgiBase *vm, Audio::Mixer *pMixer) : _vm(vm), _mixer(pMixer) {
+ _sampleRate = pMixer->getOutputRate();
+ _soundHandle = new Audio::SoundHandle();
+}
+
+SoundGen::~SoundGen() {
+ delete _soundHandle;
+}
+
//
// TODO: add support for variable sampling rate in the output device
//
diff --git a/engines/agi/sound.h b/engines/agi/sound.h
index 4b668e8cf2..8aa7a5d1df 100644
--- a/engines/agi/sound.h
+++ b/engines/agi/sound.h
@@ -23,7 +23,10 @@
#ifndef AGI_SOUND_H
#define AGI_SOUND_H
-#include "audio/mixer.h"
+namespace Audio {
+class Mixer;
+class SoundHandle;
+}
namespace Agi {
@@ -71,11 +74,8 @@ class SoundMgr;
class SoundGen {
public:
- SoundGen(AgiBase *vm, Audio::Mixer *pMixer) : _vm(vm), _mixer(pMixer) {
- _sampleRate = pMixer->getOutputRate();
- }
-
- virtual ~SoundGen() {}
+ SoundGen(AgiBase *vm, Audio::Mixer *pMixer);
+ virtual ~SoundGen();
virtual void play(int resnum) = 0;
virtual void stop(void) = 0;
@@ -83,7 +83,7 @@ public:
AgiBase *_vm;
Audio::Mixer *_mixer;
- Audio::SoundHandle _soundHandle;
+ Audio::SoundHandle *_soundHandle;
uint32 _sampleRate;
};
diff --git a/engines/agi/sound_2gs.cpp b/engines/agi/sound_2gs.cpp
index b1bcee3920..4992b6516c 100644
--- a/engines/agi/sound_2gs.cpp
+++ b/engines/agi/sound_2gs.cpp
@@ -27,6 +27,7 @@
#include "common/memstream.h"
#include "common/str-array.h"
#include "common/textconsole.h"
+#include "audio/mixer.h"
#include "agi/agi.h"
#include "agi/sound_2gs.h"
@@ -55,11 +56,11 @@ SoundGen2GS::SoundGen2GS(AgiBase *vm, Audio::Mixer *pMixer) : SoundGen(vm, pMixe
// Load instruments
_disableMidi = !loadInstruments();
- _mixer->playStream(Audio::Mixer::kMusicSoundType, &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
+ _mixer->playStream(Audio::Mixer::kMusicSoundType, _soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
}
SoundGen2GS::~SoundGen2GS() {
- _mixer->stopHandle(_soundHandle);
+ _mixer->stopHandle(*_soundHandle);
delete[] _wavetable;
delete[] _out;
}
diff --git a/engines/agi/sound_pcjr.cpp b/engines/agi/sound_pcjr.cpp
index 9d556e048a..0a0c456e14 100644
--- a/engines/agi/sound_pcjr.cpp
+++ b/engines/agi/sound_pcjr.cpp
@@ -54,6 +54,7 @@
*
*/
+#include "audio/mixer.h"
#include "agi/agi.h"
#include "agi/sound.h"
#include "agi/sound_pcjr.h"
@@ -123,7 +124,7 @@ SoundGenPCJr::SoundGenPCJr(AgiBase *vm, Audio::Mixer *pMixer) : SoundGen(vm, pMi
memset(_channel, 0, sizeof(_channel));
memset(_tchannel, 0, sizeof(_tchannel));
- _mixer->playStream(Audio::Mixer::kMusicSoundType, &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
+ _mixer->playStream(Audio::Mixer::kMusicSoundType, _soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
_v1data = NULL;
_v1size = 0;
@@ -132,7 +133,7 @@ SoundGenPCJr::SoundGenPCJr(AgiBase *vm, Audio::Mixer *pMixer) : SoundGen(vm, pMi
SoundGenPCJr::~SoundGenPCJr() {
free(_chanData);
- _mixer->stopHandle(_soundHandle);
+ _mixer->stopHandle(*_soundHandle);
}
void SoundGenPCJr::play(int resnum) {
diff --git a/engines/agi/sound_sarien.cpp b/engines/agi/sound_sarien.cpp
index 939c3d2c77..1b3542b89c 100644
--- a/engines/agi/sound_sarien.cpp
+++ b/engines/agi/sound_sarien.cpp
@@ -21,6 +21,7 @@
*/
#include "common/random.h"
+#include "audio/mixer.h"
#include "agi/agi.h"
@@ -92,11 +93,11 @@ SoundGenSarien::SoundGenSarien(AgiBase *vm, Audio::Mixer *pMixer) : SoundGen(vm,
debug(0, "Initializing sound: envelopes disabled");
}
- _mixer->playStream(Audio::Mixer::kMusicSoundType, &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
+ _mixer->playStream(Audio::Mixer::kMusicSoundType, _soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
}
SoundGenSarien::~SoundGenSarien() {
- _mixer->stopHandle(_soundHandle);
+ _mixer->stopHandle(*_soundHandle);
free(_sndBuffer);
}
diff --git a/engines/agi/systemui.cpp b/engines/agi/systemui.cpp
index aeb1ded4a2..1f26267ad6 100644
--- a/engines/agi/systemui.cpp
+++ b/engines/agi/systemui.cpp
@@ -585,7 +585,7 @@ void SystemUI::readSavedGameSlots(bool filterNonexistant, bool withAutoSaveSlot)
slotIdArray.push_back(SYSTEMUI_SAVEDGAME_MAXIMUM_SLOTS); // so that the loop will process all slots
SavedGameSlotIdArray::iterator it;
- SavedGameSlotIdArray::iterator end = slotIdArray.end();;
+ SavedGameSlotIdArray::iterator end = slotIdArray.end();
for (it = slotIdArray.begin(); it != end; it++) {
curSlotId = *it;
diff --git a/engines/agos/animation.cpp b/engines/agos/animation.cpp
index 83682d567b..123e5805dd 100644
--- a/engines/agos/animation.cpp
+++ b/engines/agos/animation.cpp
@@ -57,6 +57,7 @@ MoviePlayer::MoviePlayer(AGOSEngine_Feeble *vm)
memset(baseName, 0, sizeof(baseName));
_ticks = 0;
+ _bgSoundStream = nullptr;
}
MoviePlayer::~MoviePlayer() {
diff --git a/engines/agos/feeble.cpp b/engines/agos/feeble.cpp
index bfd11fa8ea..91772621ad 100644
--- a/engines/agos/feeble.cpp
+++ b/engines/agos/feeble.cpp
@@ -39,6 +39,7 @@ AGOSEngine_Feeble::AGOSEngine_Feeble(OSystem *system, const AGOSGameDescription
_moviePlayer = 0;
_vgaCurSpritePriority = 0;
_mouseToggle = false;
+ _opcodesFeeble = nullptr;
}
AGOSEngine_Feeble::~AGOSEngine_Feeble() {
diff --git a/engines/cge/detection.cpp b/engines/cge/detection.cpp
index 52168dc934..82d27f8d54 100644
--- a/engines/cge/detection.cpp
+++ b/engines/cge/detection.cpp
@@ -123,7 +123,7 @@ public:
}
virtual const char *getOriginalCopyright() const {
- return "Soltys (c) 1994-1996 L.K. Avalon";
+ return "Soltys (C) 1994-1996 L.K. Avalon";
}
virtual const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const;
diff --git a/engines/cge2/detection.cpp b/engines/cge2/detection.cpp
index 01119bb1fd..2b84d167c7 100644
--- a/engines/cge2/detection.cpp
+++ b/engines/cge2/detection.cpp
@@ -119,7 +119,7 @@ public:
}
virtual const char *getOriginalCopyright() const {
- return "Sfinx (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon";
+ return "Sfinx (C) 1994-1997 Janus B. Wisniewski and L.K. Avalon";
}
virtual const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const;
diff --git a/engines/gnap/character.cpp b/engines/gnap/character.cpp
new file mode 100644
index 0000000000..36d849acbf
--- /dev/null
+++ b/engines/gnap/character.cpp
@@ -0,0 +1,1415 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can 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 "gnap/gnap.h"
+#include "gnap/character.h"
+#include "gnap/gamesys.h"
+
+namespace Gnap {
+
+Character::Character(GnapEngine *vm) : _vm(vm) {
+ _pos = Common::Point(0, 0);
+ _idleFacing = kDirIdleLeft;
+ _actionStatus = 0;
+ _sequenceId = 0;
+ _sequenceDatNum = 0;
+ _id = 0;
+ _gridX = 0;
+ _gridY = 0;
+
+ _walkNodesCount = 0;
+ _walkDestX = _walkDestY = 0;
+ _walkDeltaX = _walkDeltaY = 0;
+ _walkDirX = _walkDirY = 0;
+ _walkDirXIncr = _walkDirYIncr = 0;
+
+ for(int i = 0; i < kMaxGridStructs; i++) {
+ _walkNodes[i]._id = 0;
+ _walkNodes[i]._sequenceId = 0;
+ _walkNodes[i]._deltaX = 0;
+ _walkNodes[i]._deltaY = 0;
+ _walkNodes[i]._gridX1 = 0;
+ _walkNodes[i]._gridY1 = 0;
+ }
+}
+
+Character::~Character() {}
+
+void Character::walkStep() {
+ for (int i = 1; i < _vm->_gridMaxX; ++i) {
+ Common::Point checkPt = Common::Point(_pos.x + i, _pos.y);
+ if (!_vm->isPointBlocked(checkPt)) {
+ walkTo(checkPt, -1, -1, 1);
+ break;
+ }
+
+ checkPt = Common::Point(_pos.x - i, _pos.y);
+ if (!_vm->isPointBlocked(checkPt)) {
+ walkTo(checkPt, -1, -1, 1);
+ break;
+ }
+
+ checkPt = Common::Point(_pos.x, _pos.y + 1);
+ if (!_vm->isPointBlocked(checkPt)) {
+ walkTo(checkPt, -1, -1, 1);
+ break;
+ }
+
+ checkPt = Common::Point(_pos.x, _pos.y - 1);
+ if (!_vm->isPointBlocked(checkPt)) {
+ walkTo(checkPt, -1, -1, 1);
+ break;
+ }
+
+ checkPt = Common::Point(_pos.x + 1, _pos.y + 1);
+ if (!_vm->isPointBlocked(checkPt)) {
+ walkTo(checkPt, -1, -1, 1);
+ break;
+ }
+
+ checkPt = Common::Point(_pos.x - 1, _pos.y + 1);
+ if (!_vm->isPointBlocked(checkPt)) {
+ walkTo(checkPt, -1, -1, 1);
+ break;
+ }
+
+ checkPt = Common::Point(_pos.x + 1, _pos.y - 1);
+ if (!_vm->isPointBlocked(checkPt)) {
+ walkTo(checkPt, -1, -1, 1);
+ break;
+ }
+
+ checkPt = Common::Point(_pos.x - 1, _pos.y - 1);
+ if (!_vm->isPointBlocked(checkPt)) {
+ walkTo(checkPt, -1, -1, 1);
+ break;
+ }
+ }
+}
+/************************************************************************************************/
+
+PlayerGnap::PlayerGnap(GnapEngine * vm) : Character(vm) {
+ _brainPulseNum = 0;
+ _brainPulseRndValue = 0;
+}
+
+int PlayerGnap::getSequenceId(int kind, Common::Point gridPos) {
+ int sequenceId = 0;
+
+ switch (kind) {
+ case kGSPullOutDevice:
+ if (gridPos.x > 0 && gridPos.y > 0) {
+ if (_pos.y > gridPos.y) {
+ if (_pos.x > gridPos.x) {
+ sequenceId = 0x83F;
+ _idleFacing = kDirUpLeft;
+ } else {
+ sequenceId = 0x83D;
+ _idleFacing = kDirUpRight;
+ }
+ } else {
+ if (_pos.x > gridPos.x) {
+ sequenceId = 0x83B;
+ _idleFacing = kDirBottomLeft;
+ } else {
+ sequenceId = 0x839;
+ _idleFacing = kDirBottomRight;
+ }
+ }
+ } else {
+ switch (_idleFacing) {
+ case kDirBottomRight:
+ sequenceId = 0x839;
+ break;
+ case kDirBottomLeft:
+ sequenceId = 0x83B;
+ break;
+ case kDirUpRight:
+ sequenceId = 0x83D;
+ break;
+ default:
+ sequenceId = 0x83F;
+ break;
+ }
+ }
+ break;
+
+ case kGSPullOutDeviceNonWorking:
+ if (gridPos.x > 0 && gridPos.y > 0) {
+ if (_pos.y > gridPos.y) {
+ if (_pos.x > gridPos.x) {
+ sequenceId = 0x829;
+ _idleFacing = kDirUpLeft;
+ } else {
+ sequenceId = 0x828;
+ _idleFacing = kDirUpRight;
+ }
+ } else {
+ if (_pos.x > gridPos.x) {
+ sequenceId = 0x827;
+ _idleFacing = kDirBottomLeft;
+ } else {
+ sequenceId = 0x826;
+ _idleFacing = kDirBottomRight;
+ }
+ }
+ } else {
+ switch (_idleFacing) {
+ case kDirBottomRight:
+ sequenceId = 0x826;
+ break;
+ case kDirBottomLeft:
+ sequenceId = 0x827;
+ break;
+ case kDirUpRight:
+ sequenceId = 0x828;
+ break;
+ default:
+ sequenceId = 0x829;
+ break;
+ }
+ }
+ break;
+
+ case kGSScratchingHead:
+ if (gridPos.x > 0 && gridPos.y > 0) {
+ if (_pos.y > gridPos.y) {
+ if (_pos.x > gridPos.x) {
+ sequenceId = 0x834;
+ _idleFacing = kDirBottomLeft;
+ } else {
+ sequenceId = 0x885;
+ _idleFacing = kDirUpRight;
+ }
+ } else {
+ if (_pos.x > gridPos.x) {
+ sequenceId = 0x834;
+ _idleFacing = kDirBottomLeft;
+ } else {
+ sequenceId = 0x833;
+ _idleFacing = kDirBottomRight;
+ }
+ }
+ } else {
+ switch (_idleFacing) {
+ case kDirBottomRight:
+ sequenceId = 0x833;
+ _idleFacing = kDirBottomRight;
+ break;
+ case kDirBottomLeft:
+ sequenceId = 0x834;
+ _idleFacing = kDirBottomLeft;
+ break;
+ case kDirUpRight:
+ sequenceId = 0x885;
+ _idleFacing = kDirUpRight;
+ break;
+ default:
+ sequenceId = 0x834;
+ _idleFacing = kDirBottomLeft;
+ break;
+ }
+ }
+ break;
+
+ case kGSIdle:
+ if (gridPos.x > 0 && gridPos.y > 0) {
+ if (_pos.y > gridPos.y) {
+ if (_pos.x > gridPos.x) {
+ sequenceId = 0x7BC;
+ _idleFacing = kDirUpLeft;
+ } else {
+ sequenceId = 0x7BB;
+ _idleFacing = kDirUpRight;
+ }
+ } else {
+ if (_pos.x > gridPos.x) {
+ sequenceId = 0x7BA;
+ _idleFacing = kDirBottomLeft;
+ } else {
+ sequenceId = 0x7B9;
+ _idleFacing = kDirBottomRight;
+ }
+ }
+ } else {
+ switch (_idleFacing) {
+ case kDirBottomRight:
+ sequenceId = 0x7B9;
+ break;
+ case kDirBottomLeft:
+ sequenceId = 0x7BA;
+ break;
+ case kDirUpRight:
+ sequenceId = 0x7BB;
+ break;
+ default:
+ sequenceId = 0x7BC;
+ break;
+ }
+ }
+ break;
+
+ case kGSBrainPulsating:
+ _brainPulseNum = (_brainPulseNum + 1) & 1;
+ if (gridPos.x > 0 && gridPos.y > 0) {
+ if (_pos.y > gridPos.y) {
+ if (_pos.x > gridPos.x) {
+ sequenceId = _brainPulseRndValue + _brainPulseNum + 0x812;
+ _idleFacing = kDirUpLeft;
+ } else {
+ sequenceId = _brainPulseRndValue + _brainPulseNum + 0x7FE;
+ _idleFacing = kDirUpRight;
+ }
+ } else {
+ if (_pos.x > gridPos.x) {
+ sequenceId = _brainPulseRndValue + _brainPulseNum + 0x7D6;
+ _idleFacing = kDirBottomLeft;
+ } else {
+ sequenceId = _brainPulseRndValue + _brainPulseNum + 0x7EA;
+ _idleFacing = kDirBottomRight;
+ }
+ }
+ } else {
+ switch (_idleFacing) {
+ case kDirBottomRight:
+ sequenceId = _brainPulseRndValue + _brainPulseNum + 0x7EA;
+ break;
+ case kDirBottomLeft:
+ sequenceId = _brainPulseRndValue + _brainPulseNum + 0x7D6;
+ break;
+ case kDirUpRight:
+ sequenceId = _brainPulseRndValue + _brainPulseNum + 0x7FE;
+ break;
+ default:
+ sequenceId = _brainPulseRndValue + _brainPulseNum + 0x812;
+ break;
+ }
+ }
+ break;
+
+ case kGSImpossible:
+ if (gridPos.x > 0 && gridPos.y > 0) {
+ if (_pos.y > gridPos.y) {
+ if (_pos.x > gridPos.x) {
+ sequenceId = 0x831;
+ _idleFacing = kDirBottomLeft;
+ } else {
+ sequenceId = 0x7A8;
+ _idleFacing = kDirBottomRight;
+ }
+ } else {
+ if (_pos.x > gridPos.x) {
+ sequenceId = 0x831;
+ _idleFacing = kDirBottomLeft;
+ } else {
+ if (_pos.x % 2)
+ sequenceId = 0x7A8;
+ else
+ sequenceId = 0x89A;
+ _idleFacing = kDirBottomRight;
+ }
+ }
+ } else if (_idleFacing != kDirBottomRight && _idleFacing != kDirUpRight) {
+ sequenceId = 0x831;
+ _idleFacing = kDirBottomLeft;
+ } else {
+ if (_vm->_currentSceneNum % 2)
+ sequenceId = 0x7A8;
+ else
+ sequenceId = 0x89A;
+ _idleFacing = kDirBottomRight;
+ }
+ break;
+
+ case kGSDeflect:
+ if (gridPos.x > 0 && gridPos.y > 0) {
+ if (_pos.y > gridPos.y) {
+ if (_pos.x > gridPos.x) {
+ sequenceId = 0x830;
+ _idleFacing = kDirUpLeft;
+ } else {
+ sequenceId = 0x82F;
+ _idleFacing = kDirUpRight;
+ }
+ } else {
+ if (_pos.x > gridPos.x) {
+ sequenceId = 0x82E;
+ _idleFacing = kDirBottomLeft;
+ } else {
+ sequenceId = 0x7A7;
+ _idleFacing = kDirBottomRight;
+ }
+ }
+ } else {
+ switch (_idleFacing) {
+ case kDirBottomRight:
+ sequenceId = 0x7A7;
+ break;
+ case kDirBottomLeft:
+ sequenceId = 0x82E;
+ break;
+ case kDirUpLeft:
+ sequenceId = 0x830;
+ break;
+ case kDirUpRight:
+ sequenceId = 0x82F;
+ break;
+ case kDirIdleLeft:
+ case kDirIdleRight:
+ break;
+ }
+ }
+ break;
+
+ case kGSUseDevice:
+ switch (_idleFacing) {
+ case kDirBottomRight:
+ sequenceId = 0x83A;
+ break;
+ case kDirBottomLeft:
+ sequenceId = 0x83C;
+ break;
+ case kDirUpLeft:
+ sequenceId = 0x840;
+ break;
+ case kDirUpRight:
+ sequenceId = 0x83E;
+ break;
+ case kDirIdleLeft:
+ case kDirIdleRight:
+ break;
+ }
+ break;
+
+ case kGSMoan1:
+ if (gridPos.x > 0 && gridPos.y > 0) {
+ if (_pos.y > gridPos.y) {
+ if (_pos.x > gridPos.x) {
+ sequenceId = 0x832;
+ _idleFacing = kDirBottomLeft;
+ } else {
+ sequenceId = 0x7AA;
+ _idleFacing = kDirBottomRight;
+ }
+ } else {
+ if (_pos.x > gridPos.x) {
+ sequenceId = 0x832;
+ _idleFacing = kDirBottomLeft;
+ } else {
+ sequenceId = 0x7AA;
+ _idleFacing = kDirBottomRight;
+ }
+ }
+ } else if (_idleFacing != kDirBottomRight && _idleFacing != kDirUpRight) {
+ sequenceId = 0x832;
+ _idleFacing = kDirBottomLeft;
+ } else {
+ sequenceId = 0x7AA;
+ _idleFacing = kDirBottomRight;
+ }
+ break;
+
+ case kGSMoan2:
+ if (gridPos.x > 0 && gridPos.y > 0) {
+ if (_pos.x > gridPos.x) {
+ sequenceId = 0x832;
+ _idleFacing = kDirBottomLeft;
+ } else {
+ sequenceId = 0x7AA;
+ _idleFacing = kDirBottomRight;
+ }
+ } else if (_idleFacing != kDirBottomRight && _idleFacing != kDirUpRight) {
+ sequenceId = 0x832;
+ _idleFacing = kDirBottomLeft;
+ } else {
+ sequenceId = 0x7AA;
+ _idleFacing = kDirBottomRight;
+ }
+ break;
+ }
+
+ return sequenceId | 0x10000;
+}
+
+void PlayerGnap::useJointOnPlatypus() {
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->setGrabCursorSprite(-1);
+ if (doPlatypusAction(1, 0, 0x107C1, 0)) {
+ _actionStatus = 100;
+ _vm->_gameSys->setAnimation(0, 0, 1);
+ _vm->_gameSys->setAnimation(0x10876, plat._id, 0);
+ _vm->_gameSys->insertSequence(0x10875, _id,
+ makeRid(_sequenceDatNum, _sequenceId), _id,
+ kSeqSyncWait, 0, 15 * (5 * _pos.x - 30), 48 * (_pos.y - 7));
+ _sequenceDatNum = 1;
+ _sequenceId = 0x875;
+ _vm->_gameSys->insertSequence(0x10876, plat._id,
+ plat._sequenceId | (plat._sequenceDatNum << 16), plat._id,
+ kSeqSyncWait, 0, 15 * (5 * plat._pos.x - 25), 48 * (plat._pos.y - 7));
+ plat._sequenceDatNum = 1;
+ plat._sequenceId = 0x876;
+ plat._idleFacing = kDirIdleLeft;
+ playSequence(0x107B5);
+ walkStep();
+ while (_vm->_gameSys->getAnimationStatus(0) != 2 && !_vm->_gameDone) {
+ _vm->updateMouseCursor();
+ _vm->gameUpdateTick();
+ }
+ _vm->_gameSys->setAnimation(0, 0, 0);
+ _actionStatus = -1;
+ } else {
+ playSequence(getSequenceId(kGSScratchingHead, plat._pos) | 0x10000);
+ }
+}
+
+void PlayerGnap::kissPlatypus(int callback) {
+ PlayerPlat& plat = *_vm->_plat;
+
+ if (doPlatypusAction(-1, 0, 0x107D1, callback)) {
+ _actionStatus = 100;
+ _vm->_gameSys->setAnimation(0, 0, 1);
+ _vm->_gameSys->setAnimation(0x10847, _id, 0);
+ _vm->_gameSys->insertSequence(0x10847, _id,
+ makeRid(_sequenceDatNum, _sequenceId), _id,
+ kSeqSyncWait, 0, 15 * (5 * _pos.x - 20) - (21 - _vm->_gridMinX), 48 * (_pos.y - 6) - (146 - _vm->_gridMinY));
+ _sequenceDatNum = 1;
+ _sequenceId = 0x847;
+ _vm->_gameSys->insertSequence(0x107CB, plat._id,
+ makeRid(plat._sequenceDatNum, plat._sequenceId), plat._id,
+ kSeqSyncWait, _vm->getSequenceTotalDuration(0x10847), 75 * plat._pos.x - plat._gridX, 48 * plat._pos.y - plat._gridY);
+ plat._sequenceDatNum = 1;
+ plat._sequenceId = 0x7CB;
+ plat._idleFacing = kDirIdleLeft;
+ playSequence(0x107B5);
+ while (_vm->_gameSys->getAnimationStatus(0) != 2 && !_vm->_gameDone) {
+ _vm->updateMouseCursor();
+ _vm->doCallback(callback);
+ _vm->gameUpdateTick();
+ }
+ _vm->_gameSys->setAnimation(0, 0, 0);
+ _actionStatus = -1;
+ } else {
+ playSequence(getSequenceId(kGSScratchingHead, plat._pos) | 0x10000);
+ }
+}
+
+void PlayerGnap::useDeviceOnPlatypus() {
+ PlayerPlat& plat = *_vm->_plat;
+
+ playSequence(makeRid(1, getSequenceId(kGSPullOutDevice, plat._pos)));
+
+ if (plat._idleFacing != kDirIdleLeft) {
+ _vm->_gameSys->insertSequence(makeRid(1, 0x7D5), plat._id,
+ makeRid(plat._sequenceDatNum, plat._sequenceId), plat._id,
+ kSeqSyncWait, 0, 75 * plat._pos.x - plat._gridX, 48 * plat._pos.y - plat._gridY);
+ plat._sequenceId = 0x7D5;
+ plat._sequenceDatNum = 1;
+ } else {
+ _vm->_gameSys->insertSequence(makeRid(1, 0x7D4), plat._id,
+ makeRid(plat._sequenceDatNum, plat._sequenceId), plat._id,
+ kSeqSyncWait, 0, 75 * plat._pos.x - plat._gridX, 48 * plat._pos.y - plat._gridY);
+ plat._sequenceId = 0x7D4;
+ plat._sequenceDatNum = 1;
+ }
+
+ int newSequenceId = getSequenceId(kGSUseDevice, Common::Point(0, 0));
+ _vm->_gameSys->insertSequence(makeRid(1, newSequenceId), _id,
+ makeRid(_sequenceDatNum, _sequenceId), _id,
+ kSeqSyncWait, 0, 75 * _pos.x - _gridX, 48 * _pos.y - _gridY);
+ _sequenceId = newSequenceId;
+ _sequenceDatNum = 1;
+}
+
+void PlayerGnap::initBrainPulseRndValue() {
+ _brainPulseRndValue = 2 * _vm->getRandom(10);
+}
+
+void PlayerGnap::playSequence(int sequenceId) {
+ _vm->_timers[2] = _vm->getRandom(30) + 20;
+ _vm->_timers[3] = 300;
+ idle();
+ _vm->_gameSys->insertSequence(sequenceId, _id,
+ makeRid(_sequenceDatNum, _sequenceId), _id,
+ kSeqScale | kSeqSyncWait, 0, 75 * _pos.x - _gridX, 48 * _pos.y - _gridY);
+ _sequenceId = ridToEntryIndex(sequenceId);
+ _sequenceDatNum = ridToDatIndex(sequenceId);
+}
+
+void PlayerGnap::updateIdleSequence() {
+ if (_actionStatus < 0) {
+ if (_vm->_timers[2] > 0) {
+ if (_vm->_timers[3] == 0) {
+ _vm->_timers[2] = 60;
+ _vm->_timers[3] = 300;
+ if (_idleFacing == kDirBottomRight) {
+ switch (_vm->getRandom(5)) {
+ case 0:
+ playSequence(0x107A6);
+ break;
+ case 1:
+ playSequence(0x107AA);
+ break;
+ case 2:
+ playSequence(0x10841);
+ break;
+ default:
+ playSequence(0x108A2);
+ break;
+ }
+ } else if (_idleFacing == kDirBottomLeft) {
+ if (_vm->getRandom(5) > 2)
+ playSequence(0x10832);
+ else
+ playSequence(0x10842);
+ }
+ }
+ } else {
+ _vm->_timers[2] = _vm->getRandom(30) + 20;
+ if (_idleFacing == kDirBottomRight) {
+ _vm->_gameSys->insertSequence(0x107BD, _id,
+ makeRid(_sequenceDatNum, _sequenceId), _id,
+ kSeqSyncWait, 0, 75 * _pos.x - _gridX, 48 * _pos.y - _gridY);
+ _sequenceId = 0x7BD;
+ _sequenceDatNum = 1;
+ } else if (_idleFacing == kDirBottomLeft) {
+ _vm->_gameSys->insertSequence(0x107BE, _id,
+ makeRid(_sequenceDatNum, _sequenceId), _id,
+ kSeqSyncWait, 0, 75 * _pos.x - _gridX, 48 * _pos.y - _gridY);
+ _sequenceId = 0x7BE;
+ _sequenceDatNum = 1;
+ }
+ }
+ } else {
+ _vm->_timers[2] = _vm->getRandom(30) + 20;
+ _vm->_timers[3] = 300;
+ }
+}
+
+void PlayerGnap::updateIdleSequence2() {
+ if (_actionStatus < 0) {
+ if (_vm->_timers[2] > 0) {
+ if (_vm->_timers[3] == 0) {
+ _vm->_timers[2] = 60;
+ _vm->_timers[3] = 300;
+ if (_idleFacing == kDirBottomRight) {
+ playSequence(0x107AA);
+ } else if (_idleFacing == kDirBottomLeft) {
+ playSequence(0x10832);
+ }
+ }
+ } else {
+ _vm->_timers[2] = _vm->getRandom(30) + 20;
+ if (_idleFacing == kDirBottomRight) {
+ _vm->_gameSys->insertSequence(0x107BD, _id,
+ makeRid(_sequenceDatNum, _sequenceId), _id,
+ kSeqSyncWait, 0, 75 * _pos.x - _gridX, 48 * _pos.y - _gridY);
+ _sequenceId = 0x7BD;
+ _sequenceDatNum = 1;
+ } else if (_idleFacing == kDirBottomLeft) {
+ _vm->_gameSys->insertSequence(0x107BE, _id,
+ makeRid(_sequenceDatNum, _sequenceId), _id,
+ kSeqSyncWait, 0, 75 * _pos.x - _gridX, 48 * _pos.y - _gridY);
+ _sequenceId = 0x7BE;
+ _sequenceDatNum = 1;
+ }
+ }
+ } else {
+ _vm->_timers[2] = _vm->getRandom(30) + 20;
+ _vm->_timers[3] = 300;
+ }
+}
+
+void PlayerGnap::initPos(int gridX, int gridY, Facing facing) {
+ _vm->_timers[2] = 30;
+ _vm->_timers[3] = 300;
+ _pos = Common::Point(gridX, gridY);
+ if (facing == kDirIdleLeft)
+ _idleFacing = kDirBottomRight;
+ else
+ _idleFacing = facing;
+
+ if (_idleFacing == kDirBottomLeft) {
+ _sequenceId = 0x7B8;
+ } else {
+ _sequenceId = 0x7B5;
+ _idleFacing = kDirBottomRight;
+ }
+ _id = 20 * _pos.y;
+ _sequenceDatNum = 1;
+ _vm->_gameSys->insertSequence(makeRid(1, _sequenceId), 20 * _pos.y,
+ 0, 0,
+ kSeqScale, 0, 75 * _pos.x - _gridX, 48 * _pos.y - _gridY);
+}
+
+int PlayerGnap::getWalkSequenceId(int deltaX, int deltaY) {
+ static const int walkSequenceIds[9] = {
+ 0x7B2, 0x000, 0x7B4,
+ 0x7AD, 0x000, 0x7AE,
+ 0x7B1, 0x000, 0x7B3
+ };
+
+ int id = 3 * (deltaX + 1) + deltaY + 1;
+ assert(id >= 0 && id < 9);
+
+ return walkSequenceIds[id];
+}
+
+bool PlayerGnap::walkTo(Common::Point gridPos, int animationIndex, int sequenceId, int flags) {
+ PlayerPlat& plat = *_vm->_plat;
+ int datNum = flags & 3;
+
+ _vm->_timers[2] = 200;
+ _vm->_timers[3] = 300;
+
+ int gridX = gridPos.x;
+ if (gridX < 0)
+ gridX = (_vm->_leftClickMouseX - _vm->_gridMinX + 37) / 75;
+
+ int gridY = gridPos.y;
+ if (gridY < 0)
+ gridY = (_vm->_leftClickMouseY - _vm->_gridMinY + 24) / 48;
+
+ _walkDestX = CLIP(gridX, 0, _vm->_gridMaxX - 1);
+ _walkDestY = CLIP(gridY, 0, _vm->_gridMaxY - 1);
+
+ if (animationIndex >= 0 && _walkDestX == plat._pos.x && _walkDestY == plat._pos.y)
+ plat.makeRoom();
+
+ bool done = findPath1(_pos.x, _pos.y, 0);
+
+ if (!done)
+ done = findPath2(_pos.x, _pos.y, 0);
+
+ if (!done)
+ done = findPath3(_pos.x, _pos.y);
+
+ if (!done)
+ done = findPath4(_pos.x, _pos.y);
+
+ idle();
+
+ int gnapSequenceId = _sequenceId;
+ int gnapId = _id;
+ int gnapSequenceDatNum = _sequenceDatNum;
+
+ debugC(kDebugBasic, "_gnap->_walkNodesCount: %d", _walkNodesCount);
+
+ for (int index = 0; index < _walkNodesCount; ++index) {
+ _walkNodes[index]._id = index + 20 * _walkNodes[index]._gridY1;
+ if (_walkNodes[index]._deltaX == 1 && _walkNodes[index]._deltaY == 0) {
+ if (index % 2) {
+ _vm->_gameSys->insertSequence(makeRid(datNum, 0x7AB), _walkNodes[index]._id,
+ makeRid(gnapSequenceDatNum, gnapSequenceId), gnapId,
+ kSeqScale | kSeqSyncWait, 0, 75 * _walkNodes[index]._gridX1 - _gridX, 48 * _walkNodes[index]._gridY1 - _gridY);
+ _walkNodes[index]._sequenceId = 0x7AB;
+ gnapSequenceId = 0x7AB;
+ } else {
+ _vm->_gameSys->insertSequence(makeRid(datNum, 0x7AC), _walkNodes[index]._id,
+ makeRid(gnapSequenceDatNum, gnapSequenceId), gnapId,
+ kSeqScale | kSeqSyncWait, 0, 75 * _walkNodes[index]._gridX1 - _gridX, 48 * _walkNodes[index]._gridY1 - _gridY);
+ _walkNodes[index]._sequenceId = 0x7AC;
+ gnapSequenceId = 0x7AC;
+ }
+ } else if (_walkNodes[index]._deltaX == -1 && _walkNodes[index]._deltaY == 0) {
+ if (index % 2) {
+ _vm->_gameSys->insertSequence(makeRid(datNum, 0x7AF), _walkNodes[index]._id,
+ makeRid(gnapSequenceDatNum, gnapSequenceId), gnapId,
+ kSeqScale | kSeqSyncWait, 0, 75 * _walkNodes[index]._gridX1 - _gridX, 48 * _walkNodes[index]._gridY1 - _gridY);
+ _walkNodes[index]._sequenceId = 0x7AF;
+ gnapSequenceId = 0x7AF;
+ } else {
+ _vm->_gameSys->insertSequence(makeRid(datNum, 0x7B0), _walkNodes[index]._id,
+ makeRid(gnapSequenceDatNum, gnapSequenceId), gnapId,
+ kSeqScale | kSeqSyncWait, 0, 75 * _walkNodes[index]._gridX1 - _gridX, 48 * _walkNodes[index]._gridY1 - _gridY);
+ _walkNodes[index]._sequenceId = 0x7B0;
+ gnapSequenceId = 0x7B0;
+ }
+ } else {
+ if (_walkNodes[index]._deltaY == -1)
+ _walkNodes[index]._id -= 10;
+ else
+ _walkNodes[index]._id += 10;
+ int newSequenceId = getWalkSequenceId(_walkNodes[index]._deltaX, _walkNodes[index]._deltaY);
+ _vm->_gameSys->insertSequence(makeRid(datNum, newSequenceId), _walkNodes[index]._id,
+ makeRid(gnapSequenceDatNum, gnapSequenceId), gnapId,
+ kSeqScale | kSeqSyncWait, 0, 75 * _walkNodes[index]._gridX1 - _gridX, 48 * _walkNodes[index]._gridY1 - _gridY);
+ _walkNodes[index]._sequenceId = newSequenceId;
+ gnapSequenceId = newSequenceId;
+ }
+ gnapId = _walkNodes[index]._id;
+ gnapSequenceDatNum = datNum;
+ }
+
+ if (flags & 8) {
+ if (_walkNodesCount > 0) {
+ _sequenceId = gnapSequenceId;
+ _id = gnapId;
+ _idleFacing = getWalkFacing(_walkNodes[_walkNodesCount - 1]._deltaX, _walkNodes[_walkNodesCount - 1]._deltaY);
+ _sequenceDatNum = datNum;
+ if (animationIndex >= 0)
+ _vm->_gameSys->setAnimation(makeRid(_sequenceDatNum, _sequenceId), _id, animationIndex);
+ } else if (animationIndex >= 0) {
+ _vm->_gameSys->setAnimation(0x107D3, 1, animationIndex);
+ _vm->_gameSys->insertSequence(0x107D3, 1, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ } else {
+ if (sequenceId >= 0 && sequenceId != -1) {
+ _sequenceId = ridToEntryIndex(sequenceId);
+ _sequenceDatNum = ridToDatIndex(sequenceId);
+ if (_sequenceId == 0x7B9) {
+ _idleFacing = kDirBottomRight;
+ } else {
+ switch (_sequenceId) {
+ case 0x7BA:
+ _idleFacing = kDirBottomLeft;
+ break;
+ case 0x7BB:
+ _idleFacing = kDirUpRight;
+ break;
+ case 0x7BC:
+ _idleFacing = kDirUpLeft;
+ break;
+ }
+ }
+ } else {
+ if (_walkNodesCount > 0) {
+ _sequenceId = getWalkStopSequenceId(_walkNodes[_walkNodesCount - 1]._deltaX, _walkNodes[_walkNodesCount - 1]._deltaY);
+ _idleFacing = getWalkFacing(_walkNodes[_walkNodesCount - 1]._deltaX, _walkNodes[_walkNodesCount - 1]._deltaY);
+ } else if (gridX >= 0 || gridY >= 0) {
+ switch (_idleFacing) {
+ case kDirBottomRight:
+ _sequenceId = 0x7B9;
+ break;
+ case kDirBottomLeft:
+ _sequenceId = 0x7BA;
+ break;
+ case kDirUpRight:
+ _sequenceId = 0x7BB;
+ break;
+ default:
+ _sequenceId = 0x7BC;
+ break;
+ }
+ } else {
+ int dirX = _vm->_leftClickMouseX - (_vm->_gridMinX + 75 * _pos.x);
+ int dirY = _vm->_leftClickMouseY - (_vm->_gridMinY + 48 * _pos.y);
+ if (dirX == 0)
+ dirX = 1;
+ if (dirY == 0)
+ dirY = 1;
+ _sequenceId = getWalkStopSequenceId(dirX / abs(dirX), dirY / abs(dirY));
+ _idleFacing = getWalkFacing(dirX / abs(dirX), dirY / abs(dirY));
+ }
+ _sequenceDatNum = datNum;
+ }
+
+ if (animationIndex < 0) {
+ _id = 20 * _walkDestY + 1;
+ } else {
+ _id = _walkNodesCount + animationIndex + 20 * _walkDestY;
+ _vm->_gameSys->setAnimation(makeRid(_sequenceDatNum, _sequenceId), _walkNodesCount + animationIndex + 20 * _walkDestY, animationIndex);
+ }
+
+ if (flags & 4) {
+ _vm->_gameSys->insertSequence(makeRid(_sequenceDatNum, _sequenceId), _id,
+ makeRid(gnapSequenceDatNum, gnapSequenceId), gnapId,
+ kSeqScale | kSeqSyncWait, 0, 0, 0);
+ } else {
+ _vm->_gameSys->insertSequence(makeRid(_sequenceDatNum, _sequenceId), _id,
+ makeRid(gnapSequenceDatNum, gnapSequenceId), gnapId,
+ kSeqScale | kSeqSyncWait, 0, 75 * _walkDestX - _gridX, 48 * _walkDestY - _gridY);
+ }
+ }
+
+ _pos = Common::Point(_walkDestX, _walkDestY);
+
+ return done;
+}
+
+int PlayerGnap::getShowSequenceId(int index, int gridX, int gridY) {
+ int sequenceId;
+ Facing facing = _idleFacing;
+
+ if (gridY > 0 && gridX > 0) {
+ if (_pos.x > gridX)
+ _idleFacing = kDirUpLeft;
+ else
+ _idleFacing = kDirUpRight;
+ } else if (_idleFacing != kDirBottomRight && _idleFacing != kDirUpRight) {
+ _idleFacing = kDirUpLeft;
+ } else {
+ _idleFacing = kDirUpRight;
+ }
+
+ switch (index) {
+ case 0:
+ if (_idleFacing == kDirUpRight)
+ sequenceId = 0x8A0;
+ else
+ sequenceId = 0x8A1;
+ break;
+ case 1:
+ if (_idleFacing == kDirUpRight)
+ sequenceId = 0x880;
+ else
+ sequenceId = 0x895;
+ break;
+ case 2:
+ if (_idleFacing == kDirUpRight)
+ sequenceId = 0x884;
+ else
+ sequenceId = 0x899;
+ break;
+ //Skip 3
+ case 4:
+ if (_idleFacing == kDirUpRight)
+ sequenceId = 0x881;
+ else
+ sequenceId = 0x896;
+ break;
+ case 5:
+ if (_idleFacing == kDirUpRight)
+ sequenceId = 0x883;
+ else
+ sequenceId = 0x898;
+ break;
+ case 6:
+ if (_idleFacing == kDirUpRight)
+ sequenceId = 0x87E;
+ else
+ sequenceId = 0x893;
+ break;
+ case 7:
+ if (_idleFacing == kDirUpRight)
+ sequenceId = 0x848;
+ else
+ sequenceId = 0x890;
+ break;
+ case 8:
+ case 12:
+ if (_idleFacing == kDirUpRight)
+ sequenceId = 0x87D;
+ else
+ sequenceId = 0x892;
+ break;
+ case 9:
+ if (_idleFacing == kDirUpRight)
+ sequenceId = 0x882;
+ else
+ sequenceId = 0x897;
+ break;
+ case 10:
+ case 11:
+ if (_idleFacing == kDirUpRight)
+ sequenceId = 0x87C;
+ else
+ sequenceId = 0x891;
+ break;
+ case 13:
+ if (_idleFacing == kDirUpRight)
+ sequenceId = 0x888;
+ else
+ sequenceId = 0x89D;
+ break;
+ case 14:
+ if (_idleFacing == kDirUpRight)
+ sequenceId = 0x87F;
+ else
+ sequenceId = 0x894;
+ break;
+ case 15:
+ if (_idleFacing == kDirUpRight)
+ sequenceId = 0x87B;
+ else
+ sequenceId = 0x8A3;
+ break;
+ case 16:
+ if (_idleFacing == kDirUpRight)
+ sequenceId = 0x877;
+ else
+ sequenceId = 0x88C;
+ break;
+ //Skip 17
+ case 18:
+ sequenceId = 0x887;
+ break;
+ case 19:
+ case 25:
+ if (_idleFacing == kDirUpRight)
+ sequenceId = 0x87A;
+ else
+ sequenceId = 0x88F;
+ break;
+ case 20:
+ if (_idleFacing == kDirUpRight)
+ sequenceId = 0x878;
+ else
+ sequenceId = 0x88D;
+ break;
+ case 21:
+ if (_idleFacing == kDirUpRight)
+ sequenceId = 0x879;
+ else
+ sequenceId = 0x88E;
+ break;
+ case 22:
+ if (_idleFacing == kDirUpRight)
+ sequenceId = 0x88A;
+ else
+ sequenceId = 0x89F;
+ break;
+ case 23:
+ if (_idleFacing == kDirUpRight)
+ sequenceId = 0x889;
+ else
+ sequenceId = 0x89E;
+ break;
+ case 24:
+ if (_idleFacing == kDirUpRight)
+ sequenceId = 0x886;
+ else
+ sequenceId = 0x89B;
+ break;
+ //Skip 26
+ //Skip 27
+ //Skip 28
+ //Skip 29
+ default:
+ _idleFacing = facing;
+ sequenceId = getSequenceId(kGSImpossible, Common::Point(0, 0));
+ break;
+ }
+
+ return sequenceId;
+}
+
+void PlayerGnap::idle() {
+ if (_sequenceDatNum == 1 &&
+ (_sequenceId == 0x7A6 || _sequenceId == 0x7AA ||
+ _sequenceId == 0x832 || _sequenceId == 0x841 ||
+ _sequenceId == 0x842 || _sequenceId == 0x8A2 ||
+ _sequenceId == 0x833 || _sequenceId == 0x834 ||
+ _sequenceId == 0x885 || _sequenceId == 0x7A8 ||
+ _sequenceId == 0x831 || _sequenceId == 0x89A)) {
+ _vm->_gameSys->insertSequence(getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, _id,
+ makeRid(_sequenceDatNum, _sequenceId), _id,
+ kSeqSyncExists, 0, 75 * _pos.x - _gridX, 48 * _pos.y - _gridY);
+ _sequenceId = getSequenceId(kGSIdle, Common::Point(0, 0));
+ _sequenceDatNum = 1;
+ }
+}
+
+void PlayerGnap::actionIdle(int sequenceId) {
+ if (_sequenceId != -1 && ridToDatIndex(sequenceId) == _sequenceDatNum && ridToEntryIndex(sequenceId) == _sequenceId) {
+ _vm->_gameSys->insertSequence(getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, _id,
+ makeRid(_sequenceDatNum, _sequenceId), _id,
+ kSeqSyncExists, 0, 75 * _pos.x - _gridX, 48 * _pos.y - _gridY);
+ _sequenceId = getSequenceId(kGSIdle, Common::Point(0, 0));
+ _sequenceDatNum = 1;
+ }
+}
+
+void PlayerGnap::playImpossible(Common::Point gridPos) {
+ playSequence(getSequenceId(kGSImpossible, gridPos) | 0x10000);
+}
+
+void PlayerGnap::playScratchingHead(Common::Point gridPos) {
+ playSequence(getSequenceId(kGSScratchingHead, gridPos) | 0x10000);
+}
+
+void PlayerGnap::playMoan1(Common::Point gridPos) {
+ playSequence(getSequenceId(kGSMoan1, gridPos) | 0x10000);
+}
+
+void PlayerGnap::playMoan2(Common::Point gridPos) {
+ playSequence(getSequenceId(kGSMoan2, gridPos) | 0x10000);
+}
+
+void PlayerGnap::playBrainPulsating(Common::Point gridPos) {
+ playSequence(getSequenceId(kGSBrainPulsating, gridPos) | 0x10000);
+}
+
+void PlayerGnap::playPullOutDevice(Common::Point gridPos) {
+ playSequence(getSequenceId(kGSPullOutDevice, gridPos) | 0x10000);
+}
+
+void PlayerGnap::playPullOutDeviceNonWorking(Common::Point gridPos) {
+ playSequence(getSequenceId(kGSPullOutDeviceNonWorking, gridPos) | 0x10000);
+}
+
+void PlayerGnap::playUseDevice(Common::Point gridPos) {
+ playSequence(getSequenceId(kGSUseDevice, gridPos) | 0x10000);
+}
+
+void PlayerGnap::playIdle(Common::Point gridPos) {
+ playSequence(getSequenceId(kGSIdle, gridPos) | 0x10000);
+}
+
+void PlayerGnap::playShowItem(int itemIndex, int gridLookX, int gridLookY) {
+ playSequence(getShowSequenceId(itemIndex, gridLookX, gridLookY) | 0x10000);
+}
+
+void PlayerGnap::playShowCurrItem(Common::Point destPos, int gridLookX, int gridLookY) {
+ PlayerPlat& plat = *_vm->_plat;
+
+ if (plat._pos == destPos)
+ plat.makeRoom();
+ walkTo(destPos, -1, -1, 1);
+ playShowItem(_vm->_grabCursorSpriteIndex, gridLookX, gridLookY);
+}
+
+bool PlayerGnap::doPlatypusAction(int gridX, int gridY, int platSequenceId, int callback) {
+ PlayerPlat& plat = *_vm->_plat;
+ bool result = false;
+
+ if (_actionStatus <= -1 && plat._actionStatus <= -1) {
+ _actionStatus = 100;
+ Common::Point checkPt = plat._pos + Common::Point(gridX, gridY);
+ if (_vm->isPointBlocked(checkPt) && (_pos != checkPt)) {
+ plat.walkStep();
+ checkPt = plat._pos + Common::Point(gridX, gridY);
+ }
+
+ if (!_vm->isPointBlocked(checkPt) && (_pos != checkPt)) {
+ walkTo(checkPt, 0, 0x107B9, 1);
+ while (_vm->_gameSys->getAnimationStatus(0) != 2 && !_vm->_gameDone) {
+ _vm->updateMouseCursor();
+ _vm->doCallback(callback);
+ _vm->gameUpdateTick();
+ }
+ _vm->_gameSys->setAnimation(0, 0, 0);
+ if (_pos == plat._pos + Common::Point(gridX, gridY)) {
+ _vm->_gameSys->setAnimation(platSequenceId, plat._id, 1);
+ plat.playSequence(platSequenceId);
+ while (_vm->_gameSys->getAnimationStatus(1) != 2 && !_vm->_gameDone) {
+ _vm->updateMouseCursor();
+ _vm->doCallback(callback);
+ _vm->gameUpdateTick();
+ }
+ result = true;
+ }
+ }
+ _actionStatus = -1;
+ }
+ return result;
+}
+
+void PlayerGnap::useDisguiseOnPlatypus() {
+ _vm->_gameSys->setAnimation(0x10846, _id, 0);
+ playSequence(0x10846);
+ while (_vm->_gameSys->getAnimationStatus(0) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+
+ _vm->_newSceneNum = 47;
+ _vm->_isLeavingScene = true;
+ _vm->_sceneDone = true;
+ _vm->setFlag(kGFPlatypusDisguised);
+}
+
+/************************************************************************************************/
+
+PlayerPlat::PlayerPlat(GnapEngine * vm) : Character(vm) {}
+
+int PlayerPlat::getSequenceId(int kind, Common::Point gridPos) {
+ // The original had 3 parameters, all always set to 0.
+ // The code to handle the other values has been removed.
+
+ int sequenceId = 0x7CB;
+
+ if (_idleFacing != kDirIdleLeft) {
+ sequenceId = 0x7CC;
+ _idleFacing = kDirIdleRight;
+ }
+
+ return sequenceId | 0x10000;
+}
+
+void PlayerPlat::playSequence(int sequenceId) {
+ _vm->_gameSys->insertSequence(sequenceId, _id,
+ makeRid(_sequenceDatNum, _sequenceId), _id,
+ kSeqScale | kSeqSyncWait, 0, 75 * _pos.x - _gridX, 48 * _pos.y - _gridY);
+ _sequenceId = ridToEntryIndex(sequenceId);
+ _sequenceDatNum = ridToDatIndex(sequenceId);
+}
+
+void PlayerPlat::updateIdleSequence() {
+ if (_actionStatus < 0 && _vm->_gnap->_actionStatus < 0) {
+ if (_vm->_timers[0] > 0) {
+ if (_vm->_timers[1] == 0) {
+ _vm->_timers[1] = _vm->getRandom(20) + 30;
+ int rnd = _vm->getRandom(10);
+ if (_idleFacing != kDirIdleLeft) {
+ if (rnd != 0 || _sequenceId != 0x7CA) {
+ if (rnd != 1 || _sequenceId != 0x7CA)
+ playSequence(0x107CA);
+ else
+ playSequence(0x10845);
+ } else {
+ playSequence(0x107CC);
+ }
+ } else if (rnd != 0 || _sequenceId != 0x7C9) {
+ if (rnd != 1 || _sequenceId != 0x7C9) {
+ if (rnd != 2 || _sequenceId != 0x7C9)
+ playSequence(0x107C9);
+ else
+ playSequence(0x108A4);
+ } else {
+ playSequence(0x10844);
+ }
+ } else {
+ playSequence(0x107CB);
+ }
+ }
+ } else {
+ _vm->_timers[0] = _vm->getRandom(75) + 75;
+ makeRoom();
+ }
+ } else {
+ _vm->_timers[0] = 100;
+ _vm->_timers[1] = 35;
+ }
+}
+
+void PlayerPlat::updateIdleSequence2() {
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (_actionStatus < 0 && gnap._actionStatus < 0) {
+ if (_vm->_timers[0]) {
+ if (!_vm->_timers[1]) {
+ _vm->_timers[1] = _vm->getRandom(20) + 30;
+ if (_idleFacing != kDirIdleLeft) {
+ if (_vm->getRandom(10) >= 2 || _sequenceId != 0x7CA)
+ playSequence(0x107CA);
+ else
+ playSequence(0x107CC);
+ } else {
+ if (_vm->getRandom(10) >= 2 || _sequenceId != 0x7C9) {
+ playSequence(0x107C9);
+ } else {
+ playSequence(0x107CB);
+ }
+ }
+ }
+ } else {
+ _vm->_timers[0] = _vm->getRandom(75) + 75;
+ makeRoom();
+ }
+ } else {
+ _vm->_timers[0] = 100;
+ _vm->_timers[1] = 35;
+ }
+}
+
+void PlayerPlat::initPos(int gridX, int gridY, Facing facing) {
+ _vm->_timers[0] = 50;
+ _vm->_timers[1] = 20;
+ _pos = Common::Point(gridX, gridY);
+ if (facing == kDirIdleLeft)
+ _idleFacing = kDirIdleLeft;
+ else
+ _idleFacing = facing;
+ if (_idleFacing == kDirIdleRight) {
+ _sequenceId = 0x7D1;
+ } else {
+ _sequenceId = 0x7C1;
+ _idleFacing = kDirIdleLeft;
+ }
+ _id = 20 * _pos.y;
+ _sequenceDatNum = 1;
+ _vm->_gameSys->insertSequence(makeRid(1, _sequenceId), 20 * _pos.y,
+ 0, 0,
+ kSeqScale, 0, 75 * _pos.x - _gridX, 48 * _pos.y - _gridY);
+}
+
+int PlayerPlat::getWalkSequenceId(int deltaX, int deltaY) {
+ static const int walkSequenceIds[9] = {
+ 0x7C5, 0x000, 0x7C8,
+ 0x7C4, 0x000, 0x7C7,
+ 0x7C3, 0x000, 0x7C6
+ };
+
+ int id = 3 * (deltaX + 1) + deltaY + 1;
+ assert(id >= 0 && id < 9);
+
+ return walkSequenceIds[id];
+}
+
+bool PlayerPlat::walkTo(Common::Point gridPos, int animationIndex, int sequenceId, int flags) {
+ // Note: flags is always 1. The code could be simplified.
+
+ int datNum = flags & 3;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ _vm->_timers[1] = 60;
+
+ int gridX = gridPos.x;
+ if (gridX < 0)
+ gridX = (_vm->_leftClickMouseX - _vm->_gridMinX + 37) / 75;
+
+ int gridY = gridPos.y;
+ if (gridY < 0)
+ gridY = (_vm->_leftClickMouseY - _vm->_gridMinY + 24) / 48;
+
+ _walkDestX = CLIP(gridX, 0, _vm->_gridMaxX - 1);
+ _walkDestY = CLIP(gridY, 0, _vm->_gridMaxY - 1);
+
+ if (animationIndex >= 0 && gnap._pos == Common::Point(_walkDestX, _walkDestY))
+ gnap.walkStep();
+
+ bool done = findPath1(_pos.x, _pos.y, 0);
+
+ if (!done)
+ done = findPath2(_pos.x, _pos.y, 0);
+
+ if (!done)
+ done = findPath3(_pos.x, _pos.y);
+
+ if (!done)
+ done = findPath4(_pos.x, _pos.y);
+
+ int platSequenceId = _sequenceId;
+ int platId = _id;
+ int platSequenceDatNum = _sequenceDatNum;
+
+ for (int index = 0; index < _walkNodesCount; ++index) {
+ _walkNodes[index]._id = index + 20 * _walkNodes[index]._gridY1;
+ if (_walkNodes[index]._deltaX == 1 && _walkNodes[index]._deltaY == 0) {
+ if (index % 2) {
+ _vm->_gameSys->insertSequence(makeRid(datNum, 0x7CD), _walkNodes[index]._id,
+ makeRid(platSequenceDatNum, platSequenceId), platId,
+ kSeqScale | kSeqSyncWait, 0, 75 * _walkNodes[index]._gridX1 - _gridX, 48 * _walkNodes[index]._gridY1 - _gridY);
+ _walkNodes[index]._sequenceId = 0x7CD;
+ platSequenceId = 0x7CD;
+ } else {
+ _vm->_gameSys->insertSequence(makeRid(datNum, 0x7CE), _walkNodes[index]._id,
+ makeRid(platSequenceDatNum, platSequenceId), platId,
+ kSeqScale | kSeqSyncWait, 0, 75 * _walkNodes[index]._gridX1 - _gridX, 48 * _walkNodes[index]._gridY1 - _gridY);
+ _walkNodes[index]._sequenceId = 0x7CE;
+ platSequenceId = 0x7CE;
+ }
+ } else if (_walkNodes[index]._deltaX == -1 && _walkNodes[index]._deltaY == 0) {
+ if (index % 2) {
+ _vm->_gameSys->insertSequence(makeRid(datNum, 0x7CF), _walkNodes[index]._id,
+ makeRid(platSequenceDatNum, platSequenceId), platId,
+ kSeqScale | kSeqSyncWait, 0, 75 * _walkNodes[index]._gridX1 - _gridX, 48 * _walkNodes[index]._gridY1 - _gridY);
+ _walkNodes[index]._sequenceId = 0x7CF;
+ platSequenceId = 0x7CF;
+ } else {
+ _vm->_gameSys->insertSequence(makeRid(datNum, 0x7D0), _walkNodes[index]._id,
+ makeRid(platSequenceDatNum, platSequenceId), platId,
+ kSeqScale | kSeqSyncWait, 0, 75 * _walkNodes[index]._gridX1 - _gridX, 48 * _walkNodes[index]._gridY1 - _gridY);
+ _walkNodes[index]._sequenceId = 0x7D0;
+ platSequenceId = 0x7D0;
+ }
+ } else {
+ if (_walkNodes[index]._deltaY == -1)
+ _walkNodes[index]._id -= 10;
+ else
+ _walkNodes[index]._id += 10;
+ int newSequenceId = getWalkSequenceId(_walkNodes[index]._deltaX, _walkNodes[index]._deltaY);
+ _vm->_gameSys->insertSequence(makeRid(datNum, newSequenceId), _walkNodes[index]._id,
+ makeRid(platSequenceDatNum, platSequenceId), platId,
+ kSeqScale | kSeqSyncWait, 0, 75 * _walkNodes[index]._gridX1 - _gridX, 48 * _walkNodes[index]._gridY1 - _gridY);
+ _walkNodes[index]._sequenceId = newSequenceId;
+ platSequenceId = newSequenceId;
+ }
+ platId = _walkNodes[index]._id;
+ platSequenceDatNum = datNum;
+ }
+
+ if (flags & 8) {
+ if (_walkNodesCount > 0) {
+ _sequenceId = platSequenceId;
+ _id = platId;
+ _sequenceDatNum = datNum;
+ if (_walkNodes[_walkNodesCount - 1]._deltaX > 0)
+ _idleFacing = kDirIdleLeft;
+ else if (_walkNodes[_walkNodesCount - 1]._deltaX < 0)
+ _idleFacing = kDirIdleRight;
+ else if (_walkNodes[_walkNodesCount - 1]._gridX1 % 2)
+ _idleFacing = kDirIdleRight;
+ else
+ _idleFacing = kDirIdleLeft;
+ if (animationIndex >= 0)
+ _vm->_gameSys->setAnimation(makeRid(_sequenceDatNum, _sequenceId), _id, animationIndex);
+ } else if (animationIndex >= 0) {
+ _vm->_gameSys->setAnimation(0x107D3, 1, animationIndex);
+ _vm->_gameSys->insertSequence(0x107D3, 1, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ } else {
+ if (sequenceId >= 0 && sequenceId != -1) {
+ _sequenceId = ridToEntryIndex(sequenceId);
+ _sequenceDatNum = ridToDatIndex(sequenceId);
+ if (_sequenceId == 0x7C2) {
+ _idleFacing = kDirIdleLeft;
+ } else if (_sequenceId == 0x7D2) {
+ _idleFacing = kDirIdleRight;
+ }
+ } else {
+ if (_walkNodesCount > 0) {
+ if (_walkNodes[_walkNodesCount - 1]._deltaX > 0) {
+ _sequenceId = 0x7C2;
+ _idleFacing = kDirIdleLeft;
+ } else if (_walkNodes[_walkNodesCount - 1]._deltaX < 0) {
+ _sequenceId = 0x7D2;
+ _idleFacing = kDirIdleRight;
+ } else if (_walkNodes[0]._deltaX > 0) {
+ _sequenceId = 0x7C2;
+ _idleFacing = kDirIdleLeft;
+ } else if (_walkNodes[0]._deltaX < 0) {
+ _sequenceId = 0x7D2;
+ _idleFacing = kDirIdleRight;
+ } else {
+ _sequenceId = 0x7D2;
+ _idleFacing = kDirIdleRight;
+ }
+ } else if (_idleFacing != kDirIdleLeft) {
+ _sequenceId = 0x7D2;
+ } else {
+ _sequenceId = 0x7C2;
+ }
+ _sequenceDatNum = datNum;
+ }
+
+ if (animationIndex < 0) {
+ _id = 20 * _walkDestY;
+ } else {
+ _id = animationIndex + 20 * _walkDestY;
+ _vm->_gameSys->setAnimation(makeRid(_sequenceDatNum, _sequenceId), animationIndex + 20 * _walkDestY, animationIndex);
+ }
+
+ if (flags & 4)
+ _vm->_gameSys->insertSequence(makeRid(_sequenceDatNum, _sequenceId), _id,
+ makeRid(platSequenceDatNum, platSequenceId), platId,
+ 9, 0, 0, 0);
+ else
+ _vm->_gameSys->insertSequence(makeRid(_sequenceDatNum, _sequenceId), _id,
+ makeRid(platSequenceDatNum, platSequenceId), platId,
+ 9, 0, 75 * _walkDestX - _gridX, 48 * _walkDestY - _gridY);
+ }
+
+ _pos = Common::Point(_walkDestX, _walkDestY);
+
+ return done;
+}
+} // End of namespace Gnap
diff --git a/engines/gnap/character.h b/engines/gnap/character.h
new file mode 100644
index 0000000000..27e98be15c
--- /dev/null
+++ b/engines/gnap/character.h
@@ -0,0 +1,146 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can 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 GNAP_CHARACTER_H
+#define GNAP_CHARACTER_H
+
+namespace Gnap {
+
+class GnapEngine;
+
+enum Facing {
+ kDirIdleLeft = 0,
+ kDirBottomRight = 1,
+ kDirBottomLeft = 3,
+ kDirIdleRight = 4,
+ kDirUpLeft = 5,
+ kDirUpRight = 7
+};
+
+struct GridStruct {
+ int _deltaX, _deltaY;
+ int _gridX1, _gridY1;
+ int _sequenceId;
+ int _id;
+};
+
+const int kMaxGridStructs = 30;
+
+class Character {
+public:
+ Character(GnapEngine *vm);
+ virtual ~Character();
+
+ void walkStep();
+
+ virtual int getSequenceId(int kind, Common::Point gridPos) = 0;
+ virtual void playSequence(int sequenceId) = 0;
+ virtual void updateIdleSequence() = 0;
+ virtual void updateIdleSequence2() = 0;
+ virtual void initPos(int gridX, int gridY, Facing facing) = 0;
+ virtual int getWalkSequenceId(int deltaX, int deltaY) = 0;
+ virtual bool walkTo(Common::Point gridPos, int animationIndex, int sequenceId, int flags) = 0;
+
+ Common::Point _pos;
+ Facing _idleFacing;
+ int _actionStatus;
+ int _sequenceId;
+ int _sequenceDatNum;
+ int _id;
+ int _gridX;
+ int _gridY;
+ int _walkNodesCount;
+ GridStruct _walkNodes[kMaxGridStructs];
+ int _walkDestX, _walkDestY;
+ int _walkDeltaX, _walkDeltaY, _walkDirX, _walkDirY, _walkDirXIncr, _walkDirYIncr;
+
+protected:
+ GnapEngine *_vm;
+};
+
+class PlayerGnap : public Character {
+public:
+ PlayerGnap(GnapEngine *vm);
+ virtual int getSequenceId(int kind, Common::Point gridPos);
+ virtual void initPos(int gridX, int gridY, Facing facing);
+ virtual void playSequence(int sequenceId);
+ virtual void updateIdleSequence();
+ virtual void updateIdleSequence2();
+ virtual int getWalkSequenceId(int deltaX, int deltaY);
+ virtual bool walkTo(Common::Point gridPos, int animationIndex, int sequenceId, int flags);
+
+ void actionIdle(int sequenceId);
+ bool doPlatypusAction(int gridX, int gridY, int platSequenceId, int callback);
+ int getShowSequenceId(int index, int gridX, int gridY);
+ Facing getWalkFacing(int deltaX, int deltaY);
+ int getWalkStopSequenceId(int deltaX, int deltaY);
+ void idle();
+ void initBrainPulseRndValue();
+ void kissPlatypus(int callback);
+ void playBrainPulsating(Common::Point gridPos = Common::Point(0, 0));
+ void playIdle(Common::Point gridPos = Common::Point(0, 0));
+ void playImpossible(Common::Point gridPos = Common::Point(0, 0));
+ void playMoan1(Common::Point gridPos = Common::Point(0, 0));
+ void playMoan2(Common::Point gridPos = Common::Point(0, 0));
+ void playPullOutDevice(Common::Point gridPos = Common::Point(0, 0));
+ void playPullOutDeviceNonWorking(Common::Point gridPos = Common::Point(0, 0));
+ void playScratchingHead(Common::Point gridPos = Common::Point(0, 0));
+ void playShowCurrItem(Common::Point destPos, int gridLookX, int gridLookY);
+ void playShowItem(int itemIndex, int gridLookX, int gridLookY);
+ void playUseDevice(Common::Point gridPos = Common::Point(0, 0));
+ void useDeviceOnPlatypus();
+ void useDisguiseOnPlatypus();
+ void useJointOnPlatypus();
+
+ int _brainPulseNum;
+ int _brainPulseRndValue;
+
+private:
+ bool findPath1(int gridX, int gridY, int index);
+ bool findPath2(int gridX, int gridY, int index);
+ bool findPath3(int gridX, int gridY);
+ bool findPath4(int gridX, int gridY);
+};
+
+class PlayerPlat : public Character {
+public:
+ PlayerPlat(GnapEngine *vm);
+ virtual ~PlayerPlat() {}
+ virtual int getSequenceId(int kind = 0, Common::Point gridPos = Common::Point(0, 0));
+ virtual void initPos(int gridX, int gridY, Facing facing);
+ virtual void playSequence(int sequenceId);
+ virtual void updateIdleSequence();
+ virtual void updateIdleSequence2();
+ virtual int getWalkSequenceId(int deltaX, int deltaY);
+ virtual bool walkTo(Common::Point gridPos, int animationIndex, int sequenceId, int flags);
+
+ void makeRoom();
+
+private:
+ bool findPath1(int gridX, int gridY, int index);
+ bool findPath2(int gridX, int gridY, int index);
+ bool findPath3(int gridX, int gridY);
+ bool findPath4(int gridX, int gridY);
+};
+} // End of namespace Gnap
+
+#endif // GNAP_CHARACTER_H
diff --git a/engines/gnap/configure.engine b/engines/gnap/configure.engine
new file mode 100644
index 0000000000..7aa538fd2c
--- /dev/null
+++ b/engines/gnap/configure.engine
@@ -0,0 +1,3 @@
+# This file is included from the main "configure" script
+# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps]
+add_engine gnap "UFOs" no
diff --git a/engines/gnap/datarchive.cpp b/engines/gnap/datarchive.cpp
new file mode 100644
index 0000000000..c74766bd03
--- /dev/null
+++ b/engines/gnap/datarchive.cpp
@@ -0,0 +1,124 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/dcl.h"
+#include "common/file.h"
+#include "common/stream.h"
+#include "common/substream.h"
+
+#include "gnap/gnap.h"
+#include "gnap/datarchive.h"
+
+#include "engines/util.h"
+
+namespace Gnap {
+
+// DatArchive
+
+DatArchive::DatArchive(const char *filename) {
+ _fd = new Common::File();
+ if (!_fd->open(filename))
+ error("DatArchive::DatArchive() Could not open %s", filename);
+ _fd->skip(8); // Skip signature
+ _fd->skip(2); // Skip unknown
+ _fd->skip(2); // Skip unknown
+ _entriesCount = _fd->readUint32LE();
+ debugC(kDebugBasic, "_entriesCount: %d", _entriesCount);
+ _fd->skip(4); // Skip unknown
+ _entries = new DatEntry[_entriesCount];
+ for (int i = 0; i < _entriesCount; ++i) {
+ _entries[i]._ofs = _fd->readUint32LE();
+ _entries[i]._outSize1 = _fd->readUint32LE();
+ _entries[i]._type = _fd->readUint32LE();
+ _entries[i]._outSize2 = _fd->readUint32LE();
+ }
+}
+
+DatArchive::~DatArchive() {
+ _fd->close();
+ delete _fd;
+ delete[] _entries;
+}
+
+byte *DatArchive::load(int index) {
+ _fd->seek(_entries[index]._ofs);
+ debugC(kDebugBasic, "_entries[index].outSize2: %d; _entries[index].outSize1: %d", _entries[index]._outSize2, _entries[index]._outSize1);
+ byte *buffer = new byte[_entries[index]._outSize1];
+ if (!Common::decompressDCL(_fd, buffer, _entries[index]._outSize2, _entries[index]._outSize1))
+ error("DatArchive::load() Error during decompression of entry %d", index);
+ return buffer;
+}
+
+// DatManager
+
+DatManager::DatManager() {
+ for (int i = 0; i < kMaxDatArchives; ++i)
+ _datArchives[i] = nullptr;
+}
+
+DatManager::~DatManager() {
+ for (int i = 0; i < kMaxDatArchives; ++i)
+ delete _datArchives[i];
+}
+
+void DatManager::open(int index, const char *filename) {
+ close(index);
+ _datArchives[index] = new DatArchive(filename);
+ warning("Loading %s - %d", filename, index);
+}
+
+void DatManager::close(int index) {
+ delete _datArchives[index];
+ _datArchives[index] = nullptr;
+}
+
+byte *DatManager::loadResource(int resourceId) {
+ const int datIndex = ridToDatIndex(resourceId);
+ const int entryIndex = ridToEntryIndex(resourceId);
+ return _datArchives[datIndex] ? _datArchives[datIndex]->load(entryIndex) : 0;
+}
+
+uint32 DatManager::getResourceType(int resourceId) {
+ const int datIndex = ridToDatIndex(resourceId);
+ const int entryIndex = ridToEntryIndex(resourceId);
+ return _datArchives[datIndex] ? _datArchives[datIndex]->getEntryType(entryIndex) : 0;
+}
+
+uint32 DatManager::getResourceSize(int resourceId) {
+ const int datIndex = ridToDatIndex(resourceId);
+ const int entryIndex = ridToEntryIndex(resourceId);
+ return _datArchives[datIndex] ? _datArchives[datIndex]->getEntrySize(entryIndex) : 0;
+}
+
+int ridToDatIndex(int resourceId) {
+ return (resourceId & 0xFFFF0000) >> 16;
+}
+
+int ridToEntryIndex(int resourceId) {
+ return resourceId & 0xFFFF;
+}
+
+int makeRid(int datIndex, int entryIndex) {
+ return (datIndex << 16) | entryIndex;
+}
+
+} // End of namespace Gnap
diff --git a/engines/gnap/datarchive.h b/engines/gnap/datarchive.h
new file mode 100644
index 0000000000..e9220f8e6f
--- /dev/null
+++ b/engines/gnap/datarchive.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.
+ *
+ */
+
+#ifndef GNAP_DATARCHIVE_H
+#define GNAP_DATARCHIVE_H
+
+#include "common/array.h"
+#include "common/events.h"
+#include "common/file.h"
+#include "common/memstream.h"
+#include "common/random.h"
+#include "common/str.h"
+#include "common/substream.h"
+#include "common/system.h"
+#include "engines/engine.h"
+
+namespace Gnap {
+
+struct DatEntry {
+ uint32 _ofs;
+ uint32 _outSize1;
+ uint32 _type;
+ uint32 _outSize2;
+};
+
+class DatArchive {
+public:
+ DatArchive(const char *filename);
+ ~DatArchive();
+ byte *load(int index);
+ int getCount() const { return _entriesCount; }
+ uint32 getEntryType(int index) { return _entries[index]._type; }
+ uint32 getEntrySize(int index) { return _entries[index]._outSize1; }
+protected:
+ Common::File *_fd;
+ int _entriesCount;
+ DatEntry *_entries;
+};
+
+const int kMaxDatArchives = 2;
+
+class DatManager {
+public:
+ DatManager();
+ ~DatManager();
+ void open(int index, const char *filename);
+ void close(int index);
+ byte *loadResource(int resourceId);
+ uint32 getResourceType(int resourceId);
+ uint32 getResourceSize(int resourceId);
+protected:
+ DatArchive *_datArchives[kMaxDatArchives];
+};
+
+int ridToDatIndex(int resourceId);
+int ridToEntryIndex(int resourceId);
+int makeRid(int datIndex, int entryIndex);
+
+} // End of namespace Gnap
+
+#endif // GNAP_DATARCHIVE_H
diff --git a/engines/gnap/debugger.cpp b/engines/gnap/debugger.cpp
new file mode 100644
index 0000000000..07f3f6714c
--- /dev/null
+++ b/engines/gnap/debugger.cpp
@@ -0,0 +1,42 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "gnap/debugger.h"
+#include "gnap/gnap.h"
+
+namespace Gnap {
+
+Debugger::Debugger(GnapEngine *vm) : GUI::Debugger(), _vm(vm) {
+ // Register methods
+ registerCmd("hotspots", WRAP_METHOD(Debugger, Cmd_Hotspots));
+
+ // Set fields
+ _showHotspotNumber = false;
+}
+
+bool Debugger::Cmd_Hotspots(int argc, const char **argv) {
+ _showHotspotNumber ^= 1;
+
+ return true;
+}
+
+} // End of namespace Gnap
diff --git a/engines/gnap/debugger.h b/engines/gnap/debugger.h
new file mode 100644
index 0000000000..ac83cc5504
--- /dev/null
+++ b/engines/gnap/debugger.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 GNAP_DEBUGGER_H
+#define GNAP_DEBUGGER_H
+
+#include "common/scummsys.h"
+#include "gui/debugger.h"
+
+namespace Gnap {
+
+class GnapEngine;
+
+class Debugger : public GUI::Debugger {
+private:
+ GnapEngine *_vm;
+public:
+ /*
+ * Specifies whether to show the hotspot IDs
+ */
+ bool _showHotspotNumber;
+protected:
+ /**
+ * List the active hotspots during the current time period
+ */
+ bool Cmd_Hotspots(int argc, const char **argv);
+
+public:
+ Debugger(GnapEngine *vm);
+ virtual ~Debugger() {}
+};
+
+} // End of namespace Gnap
+
+#endif
diff --git a/engines/gnap/detection.cpp b/engines/gnap/detection.cpp
new file mode 100644
index 0000000000..a7e9eece4a
--- /dev/null
+++ b/engines/gnap/detection.cpp
@@ -0,0 +1,197 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can 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 "gnap/gnap.h"
+
+#include "common/config-manager.h"
+#include "engines/advancedDetector.h"
+#include "common/savefile.h"
+#include "common/system.h"
+#include "base/plugins.h"
+#include "graphics/thumbnail.h"
+
+static const PlainGameDescriptor gnapGames[] = {
+ { "gnap", "Gnap" },
+ { 0, 0 }
+};
+
+namespace Gnap {
+
+static const ADGameDescription gameDescriptions[] = {
+ {
+ "gnap", "",
+ {
+ {"stock_n.dat", 0, "46819043d019a2f36b727cc2bdd6980f", 12515823},
+ AD_LISTEND
+ },
+ Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO0()
+ },
+ {
+ "gnap", "",
+ {
+ {"stock_n.dat", 0, "46819043d019a2f36b727cc2bdd6980f", 12995485},
+ AD_LISTEND
+ },
+ Common::RU_RUS, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO0()
+ },
+
+ AD_TABLE_END_MARKER
+};
+
+} // End of namespace Gnap
+
+class GnapMetaEngine : public AdvancedMetaEngine {
+public:
+ GnapMetaEngine() : AdvancedMetaEngine(Gnap::gameDescriptions, sizeof(ADGameDescription), gnapGames) {
+ _singleId = "gnap";
+ _maxScanDepth = 3;
+ }
+
+ virtual const char *getName() const {
+ return "Gnap";
+ }
+
+ virtual const char *getOriginalCopyright() const {
+ return "Gnap (C) Artech Digital Entertainment 1997";
+ }
+
+ virtual bool hasFeature(MetaEngineFeature f) const;
+ virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const;
+ virtual int getMaximumSaveSlot() const;
+ virtual SaveStateList listSaves(const char *target) const;
+ SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const;
+ virtual void removeSaveState(const char *target, int slot) const;
+};
+
+bool GnapMetaEngine::hasFeature(MetaEngineFeature f) const {
+ return
+ (f == kSupportsListSaves) ||
+ (f == kSupportsLoadingDuringStartup) ||
+ (f == kSupportsDeleteSave) ||
+ (f == kSavesSupportMetaInfo) ||
+ (f == kSavesSupportThumbnail) ||
+ (f == kSavesSupportCreationDate);
+}
+
+bool Gnap::GnapEngine::hasFeature(EngineFeature f) const {
+ return
+ (f == kSupportsRTL) ||
+ (f == kSupportsLoadingDuringRuntime) ||
+ (f == kSupportsSavingDuringRuntime);
+}
+
+void GnapMetaEngine::removeSaveState(const char *target, int slot) const {
+ Common::String fileName = Common::String::format("%s.%03d", target, slot);
+ g_system->getSavefileManager()->removeSavefile(fileName);
+}
+
+int GnapMetaEngine::getMaximumSaveSlot() const { return 99; }
+
+SaveStateList GnapMetaEngine::listSaves(const char *target) const {
+ Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
+ Common::StringArray filenames;
+ Common::String saveDesc;
+ Common::String pattern = Common::String::format("%s.0##", target);
+ Gnap::GnapSavegameHeader header;
+
+ filenames = saveFileMan->listSavefiles(pattern);
+
+ SaveStateList saveList;
+ for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) {
+ const char *ext = strrchr(file->c_str(), '.');
+ int slot = ext ? atoi(ext + 1) : -1;
+
+ if (slot >= 0 && slot < getMaximumSaveSlot()) {
+ Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(*file);
+
+ if (in) {
+ Gnap::GnapEngine::readSavegameHeader(in, header);
+ saveList.push_back(SaveStateDescriptor(slot, header._saveName));
+
+ if (header._thumbnail) {
+ header._thumbnail->free();
+ delete header._thumbnail;
+ }
+ delete in;
+ }
+ }
+ }
+
+ // Sort saves based on slot number.
+ Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
+ return saveList;
+}
+
+SaveStateDescriptor GnapMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
+ Common::String fileName = Common::String::format("%s.%03d", target, slot);
+ Common::InSaveFile *file = g_system->getSavefileManager()->openForLoading(fileName);
+ if (file) {
+ char saveIdentBuffer[5];
+ file->read(saveIdentBuffer, 5);
+
+ int32 version = file->readByte();
+ if (version > GNAP_SAVEGAME_VERSION) {
+ delete file;
+ return SaveStateDescriptor();
+ }
+
+ char saveName[256];
+ char ch;
+ int i = 0;
+ while ((ch = (char)file->readByte()) != '\0')
+ saveName[i++] = ch;
+
+ SaveStateDescriptor desc(slot, saveName);
+
+ if (version != 1) {
+ Graphics::Surface *const thumbnail = Graphics::loadThumbnail(*file);
+ desc.setThumbnail(thumbnail);
+ }
+
+ int year = file->readSint16LE();
+ int month = file->readSint16LE();
+ int day = file->readSint16LE();
+ int hour = file->readSint16LE();
+ int minutes = file->readSint16LE();
+
+ desc.setSaveDate(year, month, day);
+ desc.setSaveTime(hour, minutes);
+
+ delete file;
+ return desc;
+ }
+
+ return SaveStateDescriptor();
+}
+
+bool GnapMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const {
+ if (desc) {
+ *engine = new Gnap::GnapEngine(syst, desc);
+ }
+ return desc != 0;
+}
+
+#if PLUGIN_ENABLED_DYNAMIC(GNAP)
+ REGISTER_PLUGIN_DYNAMIC(GNAP, PLUGIN_TYPE_ENGINE, GnapMetaEngine);
+#else
+ REGISTER_PLUGIN_STATIC(GNAP, PLUGIN_TYPE_ENGINE, GnapMetaEngine);
+#endif
diff --git a/engines/gnap/fontdata.h b/engines/gnap/fontdata.h
new file mode 100644
index 0000000000..ef39df960e
--- /dev/null
+++ b/engines/gnap/fontdata.h
@@ -0,0 +1,849 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can 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 GNAP_FONTDATA_H
+#define GNAP_FONTDATA_H
+
+namespace Gnap {
+
+struct FONT_CHAR_INFO {
+ const byte _width; // width, in bits (or pixels), of the character
+ const uint16 _offset; // offset of the character's bitmap, in bytes, into the the FONT_INFO's data array
+};
+
+/*
+** Font data for DejaVu Sans 9pt
+*/
+
+/* Character bitmaps for DejaVu Sans 9pt */
+const byte _dejaVuSans9ptCharBitmaps[] = {
+ /* @0 ' ' (5 pixels wide) */
+ 0x00, 0x00, /* */
+ 0x00, 0x00, /* */
+ 0x00, 0x00, /* */
+ 0x00, 0x00, /* */
+ 0x00, 0x00, /* */
+
+ /* @10 '!' (1 pixels wide) */
+ 0x1B, 0xF0, /* ## ###### */
+
+ /* @12 '"' (3 pixels wide) */
+ 0x00, 0x70, /* ### */
+ 0x00, 0x00, /* */
+ 0x00, 0x70, /* ### */
+
+ /* @18 '#' (8 pixels wide) */
+ 0x04, 0x00, /* # */
+ 0x14, 0x80, /* # # # */
+ 0x0F, 0x80, /* ##### */
+ 0x04, 0xE0, /* # ### */
+ 0x1C, 0x80, /* ### # */
+ 0x07, 0xC0, /* ##### */
+ 0x04, 0xA0, /* # # # */
+ 0x00, 0x80, /* # */
+
+ /* @34 '$' (5 pixels wide) */
+ 0x09, 0xC0, /* # ### */
+ 0x11, 0x20, /* # # # */
+ 0x7F, 0xF0, /* ########### */
+ 0x12, 0x20, /* # # # */
+ 0x0E, 0x40, /* ### # */
+
+ /* @44 '%' (10 pixels wide) */
+ 0x00, 0xE0, /* ### */
+ 0x01, 0x10, /* # # */
+ 0x11, 0x10, /* # # # */
+ 0x0C, 0xE0, /* ## ### */
+ 0x03, 0x00, /* ## */
+ 0x01, 0x80, /* ## */
+ 0x0E, 0x60, /* ### ## */
+ 0x11, 0x10, /* # # # */
+ 0x11, 0x00, /* # # */
+ 0x0E, 0x00, /* ### */
+
+ /* @64 '&' (8 pixels wide) */
+ 0x0E, 0x00, /* ### */
+ 0x19, 0xE0, /* ## #### */
+ 0x10, 0x90, /* # # # */
+ 0x11, 0x10, /* # # # */
+ 0x12, 0x20, /* # # # */
+ 0x0C, 0x00, /* ## */
+ 0x14, 0x00, /* # # */
+ 0x13, 0x00, /* # ## */
+
+ /* @80 ''' (1 pixels wide) */
+ 0x00, 0x70, /* ### */
+
+ /* @82 '(' (3 pixels wide) */
+ 0x07, 0xC0, /* ##### */
+ 0x38, 0x38, /* ### ### */
+ 0x20, 0x08, /* # # */
+
+ /* @88 ')' (3 pixels wide) */
+ 0x20, 0x08, /* # # */
+ 0x38, 0x38, /* ### ### */
+ 0x07, 0xC0, /* ##### */
+
+ /* @94 '*' (5 pixels wide) */
+ 0x01, 0x20, /* # # */
+ 0x00, 0xC0, /* ## */
+ 0x03, 0xF0, /* ###### */
+ 0x00, 0xC0, /* ## */
+ 0x01, 0x20, /* # # */
+
+ /* @104 '+' (7 pixels wide) */
+ 0x02, 0x00, /* # */
+ 0x02, 0x00, /* # */
+ 0x02, 0x00, /* # */
+ 0x1F, 0xC0, /* ####### */
+ 0x02, 0x00, /* # */
+ 0x02, 0x00, /* # */
+ 0x02, 0x00, /* # */
+
+ /* @118 ',' (1 pixels wide) */
+ 0x38, 0x00, /* ### */
+
+ /* @120 '-' (3 pixels wide) */
+ 0x02, 0x00, /* # */
+ 0x02, 0x00, /* # */
+ 0x02, 0x00, /* # */
+
+ /* @126 '.' (1 pixels wide) */
+ 0x18, 0x00, /* ## */
+
+ /* @128 '/' (4 pixels wide) */
+ 0x30, 0x00, /* ## */
+ 0x0E, 0x00, /* ### */
+ 0x01, 0xC0, /* ### */
+ 0x00, 0x30, /* ## */
+
+ /* @136 '0' (6 pixels wide) */
+ 0x07, 0xC0, /* ##### */
+ 0x18, 0x30, /* ## ## */
+ 0x10, 0x10, /* # # */
+ 0x10, 0x10, /* # # */
+ 0x18, 0x30, /* ## ## */
+ 0x07, 0xC0, /* ##### */
+
+ /* @148 '1' (5 pixels wide) */
+ 0x10, 0x10, /* # # */
+ 0x10, 0x10, /* # # */
+ 0x1F, 0xF0, /* ######### */
+ 0x10, 0x00, /* # */
+ 0x10, 0x00, /* # */
+
+ /* @158 '2' (6 pixels wide) */
+ 0x10, 0x20, /* # # */
+ 0x18, 0x10, /* ## # */
+ 0x14, 0x10, /* # # # */
+ 0x12, 0x10, /* # # # */
+ 0x11, 0x30, /* # # ## */
+ 0x10, 0xE0, /* # ### */
+
+ /* @170 '3' (6 pixels wide) */
+ 0x08, 0x20, /* # # */
+ 0x10, 0x10, /* # # */
+ 0x11, 0x10, /* # # # */
+ 0x11, 0x10, /* # # # */
+ 0x11, 0x10, /* # # # */
+ 0x0E, 0xE0, /* ### ### */
+
+ /* @182 '4' (6 pixels wide) */
+ 0x06, 0x00, /* ## */
+ 0x05, 0x80, /* # ## */
+ 0x04, 0x40, /* # # */
+ 0x04, 0x30, /* # ## */
+ 0x1F, 0xF0, /* ######### */
+ 0x04, 0x00, /* # */
+
+ /* @194 '5' (6 pixels wide) */
+ 0x08, 0xF0, /* # #### */
+ 0x10, 0x90, /* # # # */
+ 0x10, 0x90, /* # # # */
+ 0x10, 0x90, /* # # # */
+ 0x19, 0x90, /* ## ## # */
+ 0x0F, 0x00, /* #### */
+
+ /* @206 '6' (6 pixels wide) */
+ 0x07, 0xC0, /* ##### */
+ 0x19, 0x20, /* ## # # */
+ 0x10, 0x90, /* # # # */
+ 0x10, 0x90, /* # # # */
+ 0x19, 0x90, /* ## ## # */
+ 0x0F, 0x20, /* #### # */
+
+ /* @218 '7' (6 pixels wide) */
+ 0x00, 0x10, /* # */
+ 0x10, 0x10, /* # # */
+ 0x0C, 0x10, /* ## # */
+ 0x03, 0x10, /* ## # */
+ 0x00, 0xD0, /* ## # */
+ 0x00, 0x30, /* ## */
+
+ /* @230 '8' (6 pixels wide) */
+ 0x0E, 0xE0, /* ### ### */
+ 0x11, 0x10, /* # # # */
+ 0x11, 0x10, /* # # # */
+ 0x11, 0x10, /* # # # */
+ 0x11, 0x10, /* # # # */
+ 0x0E, 0xE0, /* ### ### */
+
+ /* @242 '9' (6 pixels wide) */
+ 0x09, 0xE0, /* # #### */
+ 0x13, 0x30, /* # ## ## */
+ 0x12, 0x10, /* # # # */
+ 0x12, 0x10, /* # # # */
+ 0x09, 0x30, /* # # ## */
+ 0x07, 0xC0, /* ##### */
+
+ /* @254 ':' (1 pixels wide) */
+ 0x19, 0x80, /* ## ## */
+
+ /* @256 ';' (1 pixels wide) */
+ 0x39, 0x80, /* ### ## */
+
+ /* @258 '<' (8 pixels wide) */
+ 0x03, 0x00, /* ## */
+ 0x03, 0x00, /* ## */
+ 0x03, 0x00, /* ## */
+ 0x04, 0x80, /* # # */
+ 0x04, 0x80, /* # # */
+ 0x04, 0x80, /* # # */
+ 0x0C, 0xC0, /* ## ## */
+ 0x08, 0x40, /* # # */
+
+ /* @274 '=' (8 pixels wide) */
+ 0x05, 0x00, /* # # */
+ 0x05, 0x00, /* # # */
+ 0x05, 0x00, /* # # */
+ 0x05, 0x00, /* # # */
+ 0x05, 0x00, /* # # */
+ 0x05, 0x00, /* # # */
+ 0x05, 0x00, /* # # */
+ 0x05, 0x00, /* # # */
+
+ /* @290 '>' (8 pixels wide) */
+ 0x08, 0x40, /* # # */
+ 0x0C, 0xC0, /* ## ## */
+ 0x04, 0x80, /* # # */
+ 0x04, 0x80, /* # # */
+ 0x04, 0x80, /* # # */
+ 0x03, 0x00, /* ## */
+ 0x03, 0x00, /* ## */
+ 0x03, 0x00, /* ## */
+
+ /* @306 '?' (5 pixels wide) */
+ 0x00, 0x20, /* # */
+ 0x00, 0x10, /* # */
+ 0x1B, 0x10, /* ## ## # */
+ 0x00, 0x90, /* # # */
+ 0x00, 0x60, /* ## */
+
+ /* @316 '@' (11 pixels wide) */
+ 0x0F, 0x80, /* ##### */
+ 0x10, 0x40, /* # # */
+ 0x20, 0x20, /* # # */
+ 0x47, 0x10, /* # ### # */
+ 0x48, 0x90, /* # # # # */
+ 0x48, 0x90, /* # # # # */
+ 0x48, 0x90, /* # # # # */
+ 0x4F, 0x90, /* # ##### # */
+ 0x28, 0x20, /* # # # */
+ 0x04, 0x60, /* # ## */
+ 0x03, 0x80, /* ### */
+
+ /* @338 'A' (8 pixels wide) */
+ 0x10, 0x00, /* # */
+ 0x0E, 0x00, /* ### */
+ 0x05, 0xC0, /* # ### */
+ 0x04, 0x30, /* # ## */
+ 0x04, 0x30, /* # ## */
+ 0x05, 0xC0, /* # ### */
+ 0x0E, 0x00, /* ### */
+ 0x10, 0x00, /* # */
+
+ /* @354 'B' (6 pixels wide) */
+ 0x1F, 0xF0, /* ######### */
+ 0x11, 0x10, /* # # # */
+ 0x11, 0x10, /* # # # */
+ 0x11, 0x10, /* # # # */
+ 0x11, 0x10, /* # # # */
+ 0x0E, 0xE0, /* ### ### */
+
+ /* @366 'C' (6 pixels wide) */
+ 0x07, 0xC0, /* ##### */
+ 0x08, 0x20, /* # # */
+ 0x10, 0x10, /* # # */
+ 0x10, 0x10, /* # # */
+ 0x10, 0x10, /* # # */
+ 0x08, 0x20, /* # # */
+
+ /* @378 'D' (7 pixels wide) */
+ 0x1F, 0xF0, /* ######### */
+ 0x10, 0x10, /* # # */
+ 0x10, 0x10, /* # # */
+ 0x10, 0x10, /* # # */
+ 0x10, 0x10, /* # # */
+ 0x08, 0x20, /* # # */
+ 0x07, 0xC0, /* ##### */
+
+ /* @392 'E' (6 pixels wide) */
+ 0x1F, 0xF0, /* ######### */
+ 0x11, 0x10, /* # # # */
+ 0x11, 0x10, /* # # # */
+ 0x11, 0x10, /* # # # */
+ 0x11, 0x10, /* # # # */
+ 0x11, 0x10, /* # # # */
+
+ /* @404 'F' (5 pixels wide) */
+ 0x1F, 0xF0, /* ######### */
+ 0x01, 0x10, /* # # */
+ 0x01, 0x10, /* # # */
+ 0x01, 0x10, /* # # */
+ 0x01, 0x10, /* # # */
+
+ /* @414 'G' (7 pixels wide) */
+ 0x07, 0xC0, /* ##### */
+ 0x08, 0x20, /* # # */
+ 0x10, 0x10, /* # # */
+ 0x10, 0x10, /* # # */
+ 0x11, 0x10, /* # # # */
+ 0x11, 0x10, /* # # # */
+ 0x0F, 0x20, /* #### # */
+
+ /* @428 'H' (7 pixels wide) */
+ 0x1F, 0xF0, /* ######### */
+ 0x01, 0x00, /* # */
+ 0x01, 0x00, /* # */
+ 0x01, 0x00, /* # */
+ 0x01, 0x00, /* # */
+ 0x01, 0x00, /* # */
+ 0x1F, 0xF0, /* ######### */
+
+ /* @442 'I' (1 pixels wide) */
+ 0x1F, 0xF0, /* ######### */
+
+ /* @444 'J' (3 pixels wide) */
+ 0x40, 0x00, /* # */
+ 0x40, 0x00, /* # */
+ 0x3F, 0xF0, /* ########## */
+
+ /* @450 'K' (6 pixels wide) */
+ 0x1F, 0xF0, /* ######### */
+ 0x01, 0x00, /* # */
+ 0x02, 0x80, /* # # */
+ 0x04, 0x40, /* # # */
+ 0x08, 0x20, /* # # */
+ 0x10, 0x10, /* # # */
+
+ /* @462 'L' (5 pixels wide) */
+ 0x1F, 0xF0, /* ######### */
+ 0x10, 0x00, /* # */
+ 0x10, 0x00, /* # */
+ 0x10, 0x00, /* # */
+ 0x10, 0x00, /* # */
+
+ /* @472 'M' (8 pixels wide) */
+ 0x1F, 0xF0, /* ######### */
+ 0x00, 0x60, /* ## */
+ 0x01, 0x80, /* ## */
+ 0x06, 0x00, /* ## */
+ 0x06, 0x00, /* ## */
+ 0x01, 0x80, /* ## */
+ 0x00, 0x60, /* ## */
+ 0x1F, 0xF0, /* ######### */
+
+ /* @488 'N' (7 pixels wide) */
+ 0x1F, 0xF0, /* ######### */
+ 0x00, 0x30, /* ## */
+ 0x00, 0xC0, /* ## */
+ 0x01, 0x00, /* # */
+ 0x06, 0x00, /* ## */
+ 0x18, 0x00, /* ## */
+ 0x1F, 0xF0, /* ######### */
+
+ /* @502 'O' (7 pixels wide) */
+ 0x07, 0xC0, /* ##### */
+ 0x08, 0x20, /* # # */
+ 0x10, 0x10, /* # # */
+ 0x10, 0x10, /* # # */
+ 0x10, 0x10, /* # # */
+ 0x08, 0x20, /* # # */
+ 0x07, 0xC0, /* ##### */
+
+ /* @516 'P' (6 pixels wide) */
+ 0x1F, 0xF0, /* ######### */
+ 0x01, 0x10, /* # # */
+ 0x01, 0x10, /* # # */
+ 0x01, 0x10, /* # # */
+ 0x01, 0x10, /* # # */
+ 0x00, 0xE0, /* ### */
+
+ /* @528 'Q' (7 pixels wide) */
+ 0x07, 0xC0, /* ##### */
+ 0x08, 0x20, /* # # */
+ 0x10, 0x10, /* # # */
+ 0x10, 0x10, /* # # */
+ 0x30, 0x10, /* ## # */
+ 0x48, 0x20, /* # # # */
+ 0x07, 0xC0, /* ##### */
+
+ /* @542 'R' (7 pixels wide) */
+ 0x1F, 0xF0, /* ######### */
+ 0x01, 0x10, /* # # */
+ 0x01, 0x10, /* # # */
+ 0x01, 0x10, /* # # */
+ 0x03, 0x10, /* ## # */
+ 0x0C, 0xE0, /* ## ### */
+ 0x10, 0x00, /* # */
+
+ /* @556 'S' (6 pixels wide) */
+ 0x08, 0xE0, /* # ### */
+ 0x11, 0x90, /* # ## # */
+ 0x11, 0x10, /* # # # */
+ 0x11, 0x10, /* # # # */
+ 0x11, 0x10, /* # # # */
+ 0x0E, 0x20, /* ### # */
+
+ /* @568 'T' (7 pixels wide) */
+ 0x00, 0x10, /* # */
+ 0x00, 0x10, /* # */
+ 0x00, 0x10, /* # */
+ 0x1F, 0xF0, /* ######### */
+ 0x00, 0x10, /* # */
+ 0x00, 0x10, /* # */
+ 0x00, 0x10, /* # */
+
+ /* @582 'U' (7 pixels wide) */
+ 0x0F, 0xF0, /* ######## */
+ 0x18, 0x00, /* ## */
+ 0x10, 0x00, /* # */
+ 0x10, 0x00, /* # */
+ 0x10, 0x00, /* # */
+ 0x18, 0x00, /* ## */
+ 0x0F, 0xF0, /* ######## */
+
+ /* @596 'V' (8 pixels wide) */
+ 0x00, 0x30, /* ## */
+ 0x01, 0xC0, /* ### */
+ 0x06, 0x00, /* ## */
+ 0x18, 0x00, /* ## */
+ 0x18, 0x00, /* ## */
+ 0x06, 0x00, /* ## */
+ 0x01, 0xC0, /* ### */
+ 0x00, 0x30, /* ## */
+
+ /* @612 'W' (11 pixels wide) */
+ 0x00, 0x10, /* # */
+ 0x00, 0xE0, /* ### */
+ 0x07, 0x00, /* ### */
+ 0x18, 0x00, /* ## */
+ 0x07, 0x80, /* #### */
+ 0x00, 0x70, /* ### */
+ 0x07, 0x80, /* #### */
+ 0x18, 0x00, /* ## */
+ 0x07, 0x00, /* ### */
+ 0x00, 0xE0, /* ### */
+ 0x00, 0x10, /* # */
+
+ /* @634 'X' (7 pixels wide) */
+ 0x10, 0x10, /* # # */
+ 0x08, 0x30, /* # ## */
+ 0x06, 0xC0, /* ## ## */
+ 0x01, 0x00, /* # */
+ 0x06, 0xC0, /* ## ## */
+ 0x08, 0x30, /* # ## */
+ 0x10, 0x10, /* # # */
+
+ /* @648 'Y' (7 pixels wide) */
+ 0x00, 0x10, /* # */
+ 0x00, 0x60, /* ## */
+ 0x01, 0x80, /* ## */
+ 0x1E, 0x00, /* #### */
+ 0x01, 0x80, /* ## */
+ 0x00, 0x60, /* ## */
+ 0x00, 0x10, /* # */
+
+ /* @662 'Z' (7 pixels wide) */
+ 0x18, 0x10, /* ## # */
+ 0x14, 0x10, /* # # # */
+ 0x12, 0x10, /* # # # */
+ 0x11, 0x10, /* # # # */
+ 0x10, 0x90, /* # # # */
+ 0x10, 0x50, /* # # # */
+ 0x10, 0x30, /* # ## */
+
+ /* @676 '[' (2 pixels wide) */
+ 0x7F, 0xF0, /* ########### */
+ 0x40, 0x10, /* # # */
+
+ /* @680 '\' (4 pixels wide) */
+ 0x00, 0x30, /* ## */
+ 0x01, 0xC0, /* ### */
+ 0x0E, 0x00, /* ### */
+ 0x30, 0x00, /* ## */
+
+ /* @688 ']' (2 pixels wide) */
+ 0x40, 0x10, /* # # */
+ 0x7F, 0xF0, /* ########### */
+
+ /* @692 '^' (6 pixels wide) */
+ 0x00, 0x40, /* # */
+ 0x00, 0x20, /* # */
+ 0x00, 0x10, /* # */
+ 0x00, 0x10, /* # */
+ 0x00, 0x20, /* # */
+ 0x00, 0x40, /* # */
+
+ /* @704 '_' (6 pixels wide) */
+ 0x80, 0x00, /* # */
+ 0x80, 0x00, /* # */
+ 0x80, 0x00, /* # */
+ 0x80, 0x00, /* # */
+ 0x80, 0x00, /* # */
+ 0x80, 0x00, /* # */
+
+ /* @716 '`' (2 pixels wide) */
+ 0x00, 0x08, /* # */
+ 0x00, 0x10, /* # */
+
+ /* @720 'a' (6 pixels wide) */
+ 0x0C, 0x80, /* ## # */
+ 0x12, 0x40, /* # # # */
+ 0x12, 0x40, /* # # # */
+ 0x12, 0x40, /* # # # */
+ 0x0A, 0x40, /* # # # */
+ 0x1F, 0x80, /* ###### */
+
+ /* @732 'b' (6 pixels wide) */
+ 0x1F, 0xF8, /* ########## */
+ 0x18, 0xC0, /* ## ## */
+ 0x10, 0x40, /* # # */
+ 0x10, 0x40, /* # # */
+ 0x18, 0xC0, /* ## ## */
+ 0x0F, 0x80, /* ##### */
+
+ /* @744 'c' (5 pixels wide) */
+ 0x0F, 0x80, /* ##### */
+ 0x18, 0xC0, /* ## ## */
+ 0x10, 0x40, /* # # */
+ 0x10, 0x40, /* # # */
+ 0x08, 0x80, /* # # */
+
+ /* @754 'd' (6 pixels wide) */
+ 0x0F, 0x80, /* ##### */
+ 0x18, 0xC0, /* ## ## */
+ 0x10, 0x40, /* # # */
+ 0x10, 0x40, /* # # */
+ 0x18, 0xC0, /* ## ## */
+ 0x1F, 0xF8, /* ########## */
+
+ /* @766 'e' (6 pixels wide) */
+ 0x0F, 0x80, /* ##### */
+ 0x0A, 0xC0, /* # # ## */
+ 0x12, 0x40, /* # # # */
+ 0x12, 0x40, /* # # # */
+ 0x12, 0xC0, /* # # ## */
+ 0x0B, 0x80, /* # ### */
+
+ /* @778 'f' (4 pixels wide) */
+ 0x00, 0x40, /* # */
+ 0x1F, 0xF0, /* ######### */
+ 0x00, 0x48, /* # # */
+ 0x00, 0x48, /* # # */
+
+ /* @786 'g' (6 pixels wide) */
+ 0x0F, 0x80, /* ##### */
+ 0x58, 0xC0, /* # ## ## */
+ 0x90, 0x40, /* # # # */
+ 0x90, 0x40, /* # # # */
+ 0xD8, 0xC0, /* ## ## ## */
+ 0x7F, 0xC0, /* ######### */
+
+ /* @798 'h' (6 pixels wide) */
+ 0x1F, 0xF8, /* ########## */
+ 0x00, 0x80, /* # */
+ 0x00, 0x40, /* # */
+ 0x00, 0x40, /* # */
+ 0x00, 0x40, /* # */
+ 0x1F, 0x80, /* ###### */
+
+ /* @810 'i' (1 pixels wide) */
+ 0x1F, 0xD0, /* ####### # */
+
+ /* @812 'j' (2 pixels wide) */
+ 0x80, 0x00, /* # */
+ 0xFF, 0xD0, /* ########## # */
+
+ /* @816 'k' (5 pixels wide) */
+ 0x1F, 0xF8, /* ########## */
+ 0x02, 0x00, /* # */
+ 0x05, 0x00, /* # # */
+ 0x08, 0x80, /* # # */
+ 0x10, 0x40, /* # # */
+
+ /* @826 'l' (1 pixels wide) */
+ 0x1F, 0xF8, /* ########## */
+
+ /* @828 'm' (9 pixels wide) */
+ 0x1F, 0xC0, /* ####### */
+ 0x00, 0x40, /* # */
+ 0x00, 0x40, /* # */
+ 0x00, 0x40, /* # */
+ 0x1F, 0x80, /* ###### */
+ 0x00, 0x40, /* # */
+ 0x00, 0x40, /* # */
+ 0x00, 0x40, /* # */
+ 0x1F, 0x80, /* ###### */
+
+ /* @846 'n' (6 pixels wide) */
+ 0x1F, 0xC0, /* ####### */
+ 0x00, 0x80, /* # */
+ 0x00, 0x40, /* # */
+ 0x00, 0x40, /* # */
+ 0x00, 0x40, /* # */
+ 0x1F, 0x80, /* ###### */
+
+ /* @858 'o' (6 pixels wide) */
+ 0x0F, 0x80, /* ##### */
+ 0x18, 0xC0, /* ## ## */
+ 0x10, 0x40, /* # # */
+ 0x10, 0x40, /* # # */
+ 0x18, 0xC0, /* ## ## */
+ 0x0F, 0x80, /* ##### */
+
+ /* @870 'p' (6 pixels wide) */
+ 0xFF, 0xC0, /* ########## */
+ 0x18, 0xC0, /* ## ## */
+ 0x10, 0x40, /* # # */
+ 0x10, 0x40, /* # # */
+ 0x18, 0xC0, /* ## ## */
+ 0x0F, 0x80, /* ##### */
+
+ /* @882 'q' (6 pixels wide) */
+ 0x0F, 0x80, /* ##### */
+ 0x18, 0xC0, /* ## ## */
+ 0x10, 0x40, /* # # */
+ 0x10, 0x40, /* # # */
+ 0x18, 0xC0, /* ## ## */
+ 0xFF, 0xC0, /* ########## */
+
+ /* @894 'r' (4 pixels wide) */
+ 0x1F, 0xC0, /* ####### */
+ 0x00, 0x80, /* # */
+ 0x00, 0x40, /* # */
+ 0x00, 0x40, /* # */
+
+ /* @902 's' (5 pixels wide) */
+ 0x09, 0x80, /* # ## */
+ 0x12, 0x40, /* # # # */
+ 0x12, 0x40, /* # # # */
+ 0x12, 0x40, /* # # # */
+ 0x0C, 0x80, /* ## # */
+
+ /* @912 't' (4 pixels wide) */
+ 0x00, 0x40, /* # */
+ 0x1F, 0xF0, /* ######### */
+ 0x10, 0x40, /* # # */
+ 0x10, 0x40, /* # # */
+
+ /* @920 'u' (6 pixels wide) */
+ 0x0F, 0xC0, /* ###### */
+ 0x10, 0x00, /* # */
+ 0x10, 0x00, /* # */
+ 0x10, 0x00, /* # */
+ 0x08, 0x00, /* # */
+ 0x1F, 0xC0, /* ####### */
+
+ /* @932 'v' (6 pixels wide) */
+ 0x00, 0xC0, /* ## */
+ 0x07, 0x00, /* ### */
+ 0x18, 0x00, /* ## */
+ 0x18, 0x00, /* ## */
+ 0x07, 0x00, /* ### */
+ 0x00, 0xC0, /* ## */
+
+ /* @944 'w' (9 pixels wide) */
+ 0x00, 0xC0, /* ## */
+ 0x07, 0x00, /* ### */
+ 0x18, 0x00, /* ## */
+ 0x07, 0x00, /* ### */
+ 0x00, 0xC0, /* ## */
+ 0x07, 0x00, /* ### */
+ 0x18, 0x00, /* ## */
+ 0x07, 0x00, /* ### */
+ 0x00, 0xC0, /* ## */
+
+ /* @962 'x' (6 pixels wide) */
+ 0x10, 0x40, /* # # */
+ 0x0D, 0x80, /* ## ## */
+ 0x02, 0x00, /* # */
+ 0x02, 0x00, /* # */
+ 0x0D, 0x80, /* ## ## */
+ 0x10, 0x40, /* # # */
+
+ /* @974 'y' (6 pixels wide) */
+ 0x80, 0xC0, /* # ## */
+ 0x83, 0x00, /* # ## */
+ 0x4C, 0x00, /* # ## */
+ 0x38, 0x00, /* ### */
+ 0x07, 0x00, /* ### */
+ 0x00, 0xC0, /* ## */
+
+ /* @986 'z' (5 pixels wide) */
+ 0x18, 0x40, /* ## # */
+ 0x14, 0x40, /* # # # */
+ 0x12, 0x40, /* # # # */
+ 0x11, 0x40, /* # # # */
+ 0x10, 0xC0, /* # ## */
+
+ /* @996 '{' (5 pixels wide) */
+ 0x02, 0x00, /* # */
+ 0x02, 0x00, /* # */
+ 0x7D, 0xF0, /* ##### ##### */
+ 0x40, 0x10, /* # # */
+ 0x40, 0x10, /* # # */
+
+ /* @1006 '|' (1 pixels wide) */
+ 0xFF, 0xF0, /* ############ */
+
+ /* @1008 '}' (5 pixels wide) */
+ 0x40, 0x10, /* # # */
+ 0x40, 0x10, /* # # */
+ 0x7D, 0xF0, /* ##### ##### */
+ 0x02, 0x00, /* # */
+ 0x02, 0x00, /* # */
+
+ /* @1018 '~' (8 pixels wide) */
+ 0x02, 0x00, /* # */
+ 0x01, 0x00, /* # */
+ 0x01, 0x00, /* # */
+ 0x01, 0x00, /* # */
+ 0x02, 0x00, /* # */
+ 0x02, 0x00, /* # */
+ 0x02, 0x00, /* # */
+ 0x01, 0x00, /* # */
+};
+
+/* Character descriptors for DejaVu Sans 9pt */
+/* { [Char width in bits], [Offset into dejaVuSans9ptCharBitmaps in bytes] } */
+const FONT_CHAR_INFO _dejaVuSans9ptCharDescriptors[] = {
+ {5, 0}, /* */
+ {1, 10}, /* ! */
+ {3, 12}, /* " */
+ {8, 18}, /* # */
+ {5, 34}, /* $ */
+ {10, 44}, /* % */
+ {8, 64}, /* & */
+ {1, 80}, /* ' */
+ {3, 82}, /* ( */
+ {3, 88}, /* ) */
+ {5, 94}, /* * */
+ {7, 104}, /* + */
+ {1, 118}, /* , */
+ {3, 120}, /* - */
+ {1, 126}, /* . */
+ {4, 128}, /* / */
+ {6, 136}, /* 0 */
+ {5, 148}, /* 1 */
+ {6, 158}, /* 2 */
+ {6, 170}, /* 3 */
+ {6, 182}, /* 4 */
+ {6, 194}, /* 5 */
+ {6, 206}, /* 6 */
+ {6, 218}, /* 7 */
+ {6, 230}, /* 8 */
+ {6, 242}, /* 9 */
+ {1, 254}, /* : */
+ {1, 256}, /* ; */
+ {8, 258}, /* < */
+ {8, 274}, /* = */
+ {8, 290}, /* > */
+ {5, 306}, /* ? */
+ {11, 316}, /* @ */
+ {8, 338}, /* A */
+ {6, 354}, /* B */
+ {6, 366}, /* C */
+ {7, 378}, /* D */
+ {6, 392}, /* E */
+ {5, 404}, /* F */
+ {7, 414}, /* G */
+ {7, 428}, /* H */
+ {1, 442}, /* I */
+ {3, 444}, /* J */
+ {6, 450}, /* K */
+ {5, 462}, /* L */
+ {8, 472}, /* M */
+ {7, 488}, /* N */
+ {7, 502}, /* O */
+ {6, 516}, /* P */
+ {7, 528}, /* Q */
+ {7, 542}, /* R */
+ {6, 556}, /* S */
+ {7, 568}, /* T */
+ {7, 582}, /* U */
+ {8, 596}, /* V */
+ {11, 612}, /* W */
+ {7, 634}, /* X */
+ {7, 648}, /* Y */
+ {7, 662}, /* Z */
+ {2, 676}, /* [ */
+ {4, 680}, /* \ */
+ {2, 688}, /* ] */
+ {6, 692}, /* ^ */
+ {6, 704}, /* _ */
+ {2, 716}, /* ` */
+ {6, 720}, /* a */
+ {6, 732}, /* b */
+ {5, 744}, /* c */
+ {6, 754}, /* d */
+ {6, 766}, /* e */
+ {4, 778}, /* f */
+ {6, 786}, /* g */
+ {6, 798}, /* h */
+ {1, 810}, /* i */
+ {2, 812}, /* j */
+ {5, 816}, /* k */
+ {1, 826}, /* l */
+ {9, 828}, /* m */
+ {6, 846}, /* n */
+ {6, 858}, /* o */
+ {6, 870}, /* p */
+ {6, 882}, /* q */
+ {4, 894}, /* r */
+ {5, 902}, /* s */
+ {4, 912}, /* t */
+ {6, 920}, /* u */
+ {6, 932}, /* v */
+ {9, 944}, /* w */
+ {6, 962}, /* x */
+ {6, 974}, /* y */
+ {5, 986}, /* z */
+ {5, 996}, /* { */
+ {1, 1006}, /* | */
+ {5, 1008}, /* } */
+ {8, 1018}, /* ~ */
+};
+
+} // End of namespace Gnap
+
+#endif // GNAP_RESOURCE_H
diff --git a/engines/gnap/gamesys.cpp b/engines/gnap/gamesys.cpp
new file mode 100644
index 0000000000..e59662f08a
--- /dev/null
+++ b/engines/gnap/gamesys.cpp
@@ -0,0 +1,1260 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can 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 "gnap/gamesys.h"
+#include "gnap/fontdata.h"
+#include "graphics/fontman.h"
+#include "graphics/font.h"
+#include "image/bmp.h"
+
+namespace Gnap {
+
+void GfxItem::testUpdRect(const Common::Rect &updRect) {
+ Common::Rect intersectingRect;
+ if (!_updFlag && _prevFrame._spriteId != -1 &&
+ _updRectsCount < 20 && intersectRect(intersectingRect, _prevFrame._rect, updRect))
+ _updRects[_updRectsCount++] = intersectingRect;
+}
+
+// GameSys
+
+GameSys::GameSys(GnapEngine *vm) : _vm(vm) {
+ _newSpriteDrawItemsCount = 0;
+ _removeSequenceItemsCount = 0;
+ _removeSpriteDrawItemsCount = 0;
+ _grabSpriteId = -1;
+ _grabSpriteChanged = false;
+ _reqRemoveSequenceItem = false;
+ _removeSequenceItemSequenceId = -1;
+ _removeSequenceItemValue = 0;
+ _gfxItemsCount = 0;
+ _animationsCount = 0;
+ _backgroundImageValue3 = 0;
+ _backgroundImageValue1 = 0;
+ _backgroundImageValue4 = 1000;
+ _backgroundImageValue2 = 1000;
+ _gameSysClock = 0;
+ _lastUpdateClock = 0;
+ _backgroundSurface = nullptr;
+ _frontSurface = nullptr;
+ for (int i = 0; i < kMaxAnimations; ++i) {
+ _animations[i]._sequenceId = -1;
+ _animations[i]._id = -1;
+ _animations[i]._status = 0;
+ }
+ _removeSequenceItems->_sequenceId = -1;
+ _removeSequenceItems->_id = -1;
+ _removeSequenceItems->_forceFrameReset = false;
+ _removeSpriteDrawItems->_id = -1;
+ _removeSpriteDrawItems->_surface = nullptr;
+
+ _grabSpriteSurface1 = _grabSpriteSurface2 = nullptr;
+
+ _screenRect = Common::Rect(0, 0, 800, 600);
+}
+
+GameSys::~GameSys() {
+ if (_frontSurface)
+ _frontSurface->free();
+ delete _frontSurface;
+}
+
+void GameSys::insertSequence(int sequenceId, int id, int sequenceId2, int id2, int flags, int totalDuration, int16 x, int16 y) {
+ debugC(kDebugBasic, "GameSys::insertSequence() [%08X, %d] -> [%08X, %d] (%d, %d)", sequenceId, id, sequenceId2, id2, x, y);
+ Sequence sequence;
+ SequenceResource *sequenceResource = _vm->_sequenceCache->get(sequenceId);
+ sequenceResource->_sequenceId = sequenceId;
+ sequence._sequenceId = sequenceId;
+ sequence._id = id != -1 ? id : sequenceResource->_defaultId;
+ sequence._sequenceId2 = sequenceId2 != (int32)0x80000000 ? sequenceId2 : sequenceResource->_sequenceId2;
+ sequence._id2 = id2 != -1 ? id2 : sequenceResource->_defaultId2;
+ sequence._flags = flags != -1 ? flags : sequenceResource->_flags;
+ sequence._totalDuration = totalDuration != -1 ? totalDuration : sequenceResource->_totalDuration;
+ sequence._x = (x < 10000 && x > -10000) ? x : sequenceResource->_xOffs;
+ sequence._y = (y < 10000 && y > -10000) ? y : sequenceResource->_yOffs;
+ _fatSequenceItems.push_back(sequence);
+}
+
+void GameSys::insertDirtyRect(const Common::Rect &rect) {
+ _dirtyRects.push_back(rect);
+}
+
+void GameSys::removeSequence(int sequenceId, int id, bool resetFl) {
+ //WaitForSingleObject(removeSequence2Mutex, INFINITE);
+ if (_removeSequenceItemsCount < kMaxSequenceItems) {
+ _removeSequenceItems[_removeSequenceItemsCount]._sequenceId = sequenceId;
+ _removeSequenceItems[_removeSequenceItemsCount]._id = id;
+ _removeSequenceItems[_removeSequenceItemsCount]._forceFrameReset = resetFl;
+ ++_removeSequenceItemsCount;
+ //ResetEvent(removeSequenceItemsEvent);
+ //ReleaseMutex(removeSequence2Mutex);
+ //WaitForSingleObject(removeSequenceItemsEvent, INFINITE);
+ }
+}
+
+void GameSys::invalidateGrabCursorSprite(int id, Common::Rect &rect, Graphics::Surface *surface1, Graphics::Surface *surface2) {
+ //WaitForSingleObject(grabSpriteMutex, INFINITE);
+ _grabSpriteId = id;
+ _grabSpriteRect = rect;
+ _grabSpriteSurface2 = surface2;
+ _grabSpriteSurface1 = surface1;
+ //ResetEvent(grabSpriteEvent);
+ _grabSpriteChanged = true;
+ //ReleaseMutex(grabSpriteMutex);
+ //WaitForSingleObject(grabSpriteEvent, INFINITE);
+}
+
+void GameSys::requestClear2(bool resetFl) {
+ _fatSequenceItems.clear();
+ _seqItems.clear();
+ for (int i = 0; i < _gfxItemsCount; ++i) {
+ GfxItem *gfxItem = &_gfxItems[i];
+ gfxItem->_sequenceId = -1;
+ gfxItem->_animation = nullptr;
+ if (resetFl) {
+ gfxItem->_currFrame._duration = 0;
+ gfxItem->_currFrame._spriteId = -1;
+ gfxItem->_currFrame._soundId = -1;
+ gfxItem->_updFlag = true;
+ } else {
+ gfxItem->_updFlag = false;
+ }
+ }
+ _lastUpdateClock = 0;
+ _gameSysClock = 0;
+}
+
+void GameSys::requestClear1() {
+ _gfxItemsCount = 0;
+ _fatSequenceItems.clear();
+ _seqItems.clear();
+ _lastUpdateClock = 0;
+ _gameSysClock = 0;
+}
+
+void GameSys::requestRemoveSequence(int sequenceId, int id) {
+ //WaitForSingleObject(removeSequence2Mutex, INFINITE);
+ _reqRemoveSequenceItem = true;
+ _removeSequenceItemSequenceId = sequenceId;
+ _removeSequenceItemValue = id;
+
+ handleReqRemoveSequenceItem(); //CHECKME?
+
+ //ResetEvent(reqClearEvent);
+ //ReleaseMutex(removeSequence2Mutex);
+ //WaitForSingleObject(reqClearEvent, INFINITE);
+}
+
+void GameSys::waitForUpdate() {
+ //ResetEvent(updateEvent);
+ //WaitForSingleObject(updateEvent, INFINITE);
+}
+
+int GameSys::isSequenceActive(int sequenceId, int id) {
+ for (uint i = 0; i < _seqItems.size(); ++i)
+ if (_seqItems[i]._sequenceId == sequenceId && _seqItems[i]._id == id)
+ return true;
+ return false;
+}
+
+void GameSys::setBackgroundSurface(Graphics::Surface *surface, int a4, int a5, int a6, int a7) {
+ debugC(kDebugBasic, "GameSys::setBackgroundSurface() Setting background image");
+
+ _backgroundSurface = surface;
+ if (!_backgroundSurface) {
+ return;
+ }
+
+ if (!_frontSurface || _frontSurface->w != surface->w || _frontSurface->h != surface->h) {
+ debugC(kDebugBasic, "GameSys::setBackgroundSurface() Creating background working surface");
+ if (_frontSurface)
+ _frontSurface->free();
+ delete _frontSurface;
+ _frontSurface = new Graphics::Surface();
+ _frontSurface->create(surface->w, surface->h, surface->format);
+ }
+
+ memcpy(_frontSurface->getPixels(), surface->getPixels(), surface->pitch * surface->h);
+ _vm->_system->copyRectToScreen(_frontSurface->getPixels(), _frontSurface->pitch, 0, 0, _frontSurface->w, _frontSurface->h);
+
+ _backgroundImageValue1 = a4;
+ _backgroundImageValue3 = a6;
+ _backgroundImageValue2 = a5;
+ _backgroundImageValue4 = a7;
+ _lastUpdateClock = 0;
+ _gameSysClock = 0;
+}
+
+void GameSys::setScaleValues(int a1, int a2, int a3, int a4) {
+ _backgroundImageValue1 = a1;
+ _backgroundImageValue3 = a3;
+ _backgroundImageValue2 = a2;
+ _backgroundImageValue4 = a4;
+}
+
+void GameSys::insertSpriteDrawItem(Graphics::Surface *surface, int x, int y, int id) {
+ if (surface && _newSpriteDrawItemsCount < kMaxSpriteDrawItems) {
+ _newSpriteDrawItems[_newSpriteDrawItemsCount]._id = id;
+ _newSpriteDrawItems[_newSpriteDrawItemsCount]._rect = Common::Rect(x, y, x + surface->w, y + surface->h);
+ _newSpriteDrawItems[_newSpriteDrawItemsCount]._surface = surface;
+ ++_newSpriteDrawItemsCount;
+ }
+}
+
+void GameSys::removeSpriteDrawItem(Graphics::Surface *surface, int id) {
+ if (surface && _removeSpriteDrawItemsCount < kMaxSpriteDrawItems) {
+ _removeSpriteDrawItems[_removeSpriteDrawItemsCount]._id = id;
+ _removeSpriteDrawItems[_removeSpriteDrawItemsCount]._surface = surface;
+ ++_removeSpriteDrawItemsCount;
+ }
+}
+
+void GameSys::drawSpriteToBackground(int x, int y, int resourceId) {
+ SpriteResource *spriteResource = _vm->_spriteCache->get(resourceId);
+ uint32 *sourcePalette = spriteResource->_palette;
+ byte *sourcePixels = spriteResource->_pixels;
+ int spriteWidth = spriteResource->_width;
+ int spriteHeight = spriteResource->_height;
+ Common::Rect dstRect(0, 0, spriteWidth, spriteHeight);
+ blitSprite32(_backgroundSurface, x, y, sourcePixels, spriteResource->_width, dstRect, sourcePalette, spriteResource->_transparent);
+ _vm->_spriteCache->release(resourceId);
+
+ // Add dirty rect so the modified background is redrawn
+ insertDirtyRect(Common::Rect(x, y, x + spriteWidth, y + spriteHeight));
+}
+
+Graphics::Surface *GameSys::allocSurface(int width, int height) {
+ Graphics::Surface *surface = new Graphics::Surface();
+ surface->create(width, height, _backgroundSurface->format);
+ surface->fillRect(Common::Rect(0, 0, surface->w, surface->h), 0xFFFFFF00);
+ return surface;
+}
+
+Graphics::Surface *GameSys::createSurface(int resourceId) {
+ debugC(kDebugBasic, "GameSys::createSurface() resourceId: %08X", resourceId);
+
+ SpriteResource *spriteResource = _vm->_spriteCache->get(resourceId);
+ Graphics::Surface *surface = allocSurface(spriteResource->_width, spriteResource->_height);
+ _vm->_spriteCache->release(resourceId);
+
+ drawSpriteToSurface(surface, 0, 0, resourceId);
+
+ return surface;
+}
+
+void GameSys::drawSpriteToSurface(Graphics::Surface *surface, int x, int y, int resourceId) {
+ SpriteResource *spriteResource = _vm->_spriteCache->get(resourceId);
+ uint32 *sourcePalette = spriteResource->_palette;
+ byte *sourcePixels = spriteResource->_pixels;
+ Common::Rect dstRect(0, 0, spriteResource->_width, spriteResource->_height);
+ blitSprite32(surface, x, y, sourcePixels, spriteResource->_width, dstRect, sourcePalette, true);
+ _vm->_spriteCache->release(resourceId);
+}
+
+void GameSys::drawTextToSurface(Graphics::Surface *surface, int x, int y, byte r, byte g, byte b, const char *text) {
+ bool doDirty = false;
+
+ if (!surface) {
+ surface = _backgroundSurface;
+ doDirty = true;
+ }
+
+ uint32 color = surface->format.RGBToColor(r, g, b);
+ if (_vm->_font) {
+ _vm->_font->drawString(surface, text, x, y, _vm->_font->getStringWidth(text), color);
+
+ if (doDirty)
+ insertDirtyRect(Common::Rect(x, y, x + _vm->_font->getStringWidth(text), y + _vm->_font->getFontHeight()));
+ } else {
+ for (const char *cp = text; *cp != 0; ++cp) {
+ byte c = *cp;
+ if (c < 32 || c >= 127)
+ c = (byte)'_';
+ c -= 32;
+ int w = _dejaVuSans9ptCharDescriptors[c]._width;
+ const byte *data = _dejaVuSans9ptCharBitmaps + _dejaVuSans9ptCharDescriptors[c]._offset;
+ for (int xc = 0; xc < w; ++xc) {
+ for (int yc = 15; yc >= 0; --yc) {
+ byte *dst = (byte *)surface->getBasePtr(x + xc, y + yc);
+ if (data[1 - (yc >> 3)] & (1 << (yc & 7)))
+ WRITE_LE_UINT32(dst, color);
+ }
+ data += 2;
+ }
+ x += w + 1;
+ }
+
+ if (doDirty)
+ insertDirtyRect(Common::Rect(x, y, x + getTextWidth(text), y + 16));
+ }
+}
+
+int GameSys::getTextHeight(const char *text) {
+ byte height = 0;
+ for (const char *cp = text; *cp != 0; ++cp) {
+ byte c = *cp;
+ if (c < 32 || c >= 127)
+ c = (byte)'_';
+ c -= 32;
+ height = MAX(height, _dejaVuSans9ptCharDescriptors[c]._width);
+ }
+ return height;
+}
+
+int GameSys::getTextWidth(const char *text) {
+ int width = 0;
+ for (const char *cp = text; *cp != 0; ++cp) {
+ byte c = *cp;
+ if (c < 32 || c >= 127)
+ c = (byte)'_';
+ c -= 32;
+ width += _dejaVuSans9ptCharDescriptors[c]._width + 1;
+ }
+ return width;
+}
+
+void GameSys::fillSurface(Graphics::Surface *surface, int x, int y, int width, int height, byte r, byte g, byte b) {
+ Common::Rect rect(x, y, x + width, y + height);
+ if (!surface) {
+ _backgroundSurface->fillRect(rect, _backgroundSurface->format.RGBToColor(r, g, b));
+ insertDirtyRect(rect);
+ } else {
+ surface->fillRect(rect, surface->format.RGBToColor(r, g, b));
+ }
+}
+
+void GameSys::setAnimation(int sequenceId, int id, int animationIndex) {
+ if (animationIndex < kMaxAnimations) {
+ _animations[animationIndex]._sequenceId = sequenceId;
+ _animations[animationIndex]._id = id;
+ _animations[animationIndex]._status = 0;
+ }
+}
+
+int GameSys::getAnimationStatus(int animationIndex) {
+ int result = -1;
+ if (animationIndex < kMaxAnimations)
+ result = _animations[animationIndex]._status;
+ return result;
+}
+
+int GameSys::getSpriteWidthById(int resourceId) {
+ SpriteResource *spriteResource = _vm->_spriteCache->get(resourceId);
+ const int width = spriteResource->_width;
+ _vm->_spriteCache->release(resourceId);
+ return width;
+}
+
+int GameSys::getSpriteHeightById(int resourceId) {
+ SpriteResource *spriteResource = _vm->_spriteCache->get(resourceId);
+ const int height = spriteResource->_height;
+ _vm->_spriteCache->release(resourceId);
+ return height;
+}
+
+Graphics::Surface *GameSys::loadBitmap(int resourceId) {
+ debugC(kDebugBasic, "GameSys::loadBitmap() resourceId: %08X", resourceId);
+ if (_vm->_dat->getResourceType(resourceId) != 1)
+ return nullptr;
+ byte *resourceData = _vm->_dat->loadResource(resourceId);
+ uint32 resourceSize = _vm->_dat->getResourceSize(resourceId);
+ Common::MemoryReadStream stream(resourceData, resourceSize, DisposeAfterUse::NO);
+ Graphics::Surface *bmpSurface;
+ Image::BitmapDecoder bmp;
+ if (!bmp.loadStream(stream))
+ error("GameSys::loadBitmap() Could not load bitmap resource %08X", resourceId);
+ bmpSurface = bmp.getSurface()->convertTo(_vm->_system->getScreenFormat());
+ delete[] resourceData;
+ return bmpSurface;
+}
+
+void GameSys::drawBitmap(int resourceId) {
+ assert(_backgroundSurface);
+
+ Graphics::Surface *bmpSurface = loadBitmap(resourceId);
+ if (!bmpSurface)
+ error("GameSys::drawBitmap() Error loading the bitmap");
+
+ if (bmpSurface->format != _backgroundSurface->format
+ || bmpSurface->w != _backgroundSurface->w || bmpSurface->h != _backgroundSurface->h)
+ error("GameSys::drawBitmap() Different bitmap properties than current background");
+
+ byte *src = (byte *)bmpSurface->getPixels();
+ byte *dst = (byte *)_backgroundSurface->getPixels();
+ const int pitch = bmpSurface->pitch;
+ int height = bmpSurface->h;
+ while (height--) {
+ memcpy(dst, src, pitch);
+ src += pitch;
+ dst += pitch;
+ }
+
+ bmpSurface->free();
+ delete bmpSurface;
+
+ insertDirtyRect(Common::Rect(0, 0, 800, 600));
+}
+
+Sequence *GameSys::seqFind(int sequenceId, int id, int *outIndex) {
+ for (uint i = 0; i < _seqItems.size(); ++i)
+ if (_seqItems[i]._sequenceId == sequenceId && _seqItems[i]._id == id) {
+ if (outIndex)
+ *outIndex = i;
+ return &_seqItems[i];
+ }
+ return nullptr;
+}
+
+int GameSys::seqLocateGfx(int sequenceId, int id, int *outGfxIndex) {
+ for (int i = 0; i < _gfxItemsCount; ++i) {
+ GfxItem *gfxItem = &_gfxItems[i];
+ if (gfxItem->_sequenceId == sequenceId && gfxItem->_id == id) {
+ if (outGfxIndex)
+ *outGfxIndex = i;
+ return gfxItem->_sequenceId;
+ }
+ if (gfxItem->_id > id) {
+ if (outGfxIndex)
+ *outGfxIndex = i;
+ return 0;
+ }
+ }
+ if (outGfxIndex)
+ *outGfxIndex = _gfxItemsCount;
+ return 0;
+}
+
+void GameSys::seqInsertGfx(int index, int duration) {
+ Sequence *seqItem = &_seqItems[index];
+ SequenceResource *sequenceResource = _vm->_sequenceCache->get(seqItem->_sequenceId);
+
+ if (sequenceResource->_animationsCount > 50 - _gfxItemsCount)
+ return;
+
+ int gfxIndex;
+ seqLocateGfx(seqItem->_sequenceId, seqItem->_id, &gfxIndex);
+
+ if (gfxIndex != _gfxItemsCount)
+ memmove(&_gfxItems[gfxIndex + sequenceResource->_animationsCount], &_gfxItems[gfxIndex], sizeof(GfxItem) * (_gfxItemsCount - gfxIndex));
+ _gfxItemsCount += sequenceResource->_animationsCount;
+
+ for (int i = 0; i < sequenceResource->_animationsCount; ++i) {
+ GfxItem *gfxItem = &_gfxItems[i + gfxIndex];
+ SequenceAnimation *animation = &sequenceResource->_animations[i];
+
+ debugC(kDebugBasic, "GameSys::seqInsertGfx() seqItem->sequenceId: %08X", seqItem->_sequenceId);
+
+ gfxItem->_sequenceId = seqItem->_sequenceId;
+ gfxItem->_id = seqItem->_id;
+ gfxItem->_animation = animation;
+ gfxItem->_currFrameNum = 0;
+ gfxItem->_flags = 0;
+ gfxItem->_delayTicks = seqItem->_totalDuration + animation->_additionalDelay;
+ gfxItem->_updFlag = false;
+ gfxItem->_updRectsCount = 0;
+ gfxItem->_prevFrame._duration = 0;
+ gfxItem->_prevFrame._spriteId = -1;
+ gfxItem->_prevFrame._soundId = -1;
+ int totalDuration = duration;
+ if ((seqItem->_flags & kSeqUnk) && totalDuration > 0) {
+ gfxItem->_prevFrame._duration = 1;
+ if (gfxItem->_delayTicks <= totalDuration)
+ gfxItem->_delayTicks = 0;
+ else
+ gfxItem->_delayTicks -= totalDuration + 1;
+ gfxItem->_updFlag = false;
+ } else if (gfxItem->_delayTicks <= totalDuration) {
+ int j;
+ totalDuration -= gfxItem->_delayTicks;
+ gfxItem->_delayTicks = 0;
+ for (j = gfxItem->_currFrameNum; j < animation->_framesCount && animation->frames[j]._duration <= totalDuration; ++j) {
+ if (animation->frames[j]._soundId != -1)
+ _soundIds.push_back((gfxItem->_sequenceId & 0xFFFF0000) | animation->frames[j]._soundId);
+ totalDuration -= animation->frames[j]._duration;
+ }
+ if (animation->_framesCount > j)
+ gfxItem->_currFrame = animation->frames[j++];
+ else
+ gfxItem->_currFrame = animation->frames[j - 1];
+ if (gfxItem->_currFrame._spriteId != -1 && (seqItem->_x != 0 || seqItem->_y != 0))
+ gfxItem->_currFrame._rect.translate(seqItem->_x, seqItem->_y);
+ // Update sprite scaling
+ if ((seqItem->_flags & kSeqScale) && gfxItem->_currFrame._rect.bottom >= _backgroundImageValue1 && gfxItem->_currFrame._rect.bottom <= _backgroundImageValue3) {
+ int scaleValue = _backgroundImageValue2 + (gfxItem->_currFrame._rect.bottom - _backgroundImageValue1) *
+ (_backgroundImageValue4 - _backgroundImageValue2) /
+ (_backgroundImageValue3 - _backgroundImageValue1);
+ gfxItem->_currFrame._rect.top = gfxItem->_currFrame._rect.bottom - scaleValue * (gfxItem->_currFrame._rect.bottom - gfxItem->_currFrame._rect.top) / 1000;
+ gfxItem->_currFrame._rect.right = scaleValue * (gfxItem->_currFrame._rect.right - gfxItem->_currFrame._rect.left) / 1000 + gfxItem->_currFrame._rect.left;
+ gfxItem->_currFrame._isScaled = true;
+ }
+ gfxItem->_currFrame._duration -= totalDuration;
+ if (gfxItem->_currFrame._soundId != -1)
+ _soundIds.push_back((gfxItem->_sequenceId & 0xFFFF0000) | gfxItem->_currFrame._soundId);
+ gfxItem->_currFrameNum = j;
+ gfxItem->_updFlag = true;
+ } else {
+ gfxItem->_delayTicks -= totalDuration + 1;
+ gfxItem->_updFlag = false;
+ }
+ }
+
+ for (int k = 0; k < kMaxAnimations; ++k) {
+ if (_animations[k]._sequenceId != -1 && _animations[k]._sequenceId == seqItem->_sequenceId && _animations[k]._id == seqItem->_id) {
+ _animations[k]._status = 1;
+ break;
+ }
+ }
+}
+
+void GameSys::seqRemoveGfx(int sequenceId, int id) {
+ int gfxIndex;
+ if (seqLocateGfx(sequenceId, id, &gfxIndex)) {
+ GfxItem *gfxItem = &_gfxItems[gfxIndex];
+ while (gfxIndex < _gfxItemsCount && gfxItem->_sequenceId == sequenceId && gfxItem->_id == id) {
+ if (gfxItem->_prevFrame._spriteId == -1) {
+ --_gfxItemsCount;
+ if (gfxIndex != _gfxItemsCount)
+ memmove(&_gfxItems[gfxIndex], &_gfxItems[gfxIndex + 1], sizeof(GfxItem) * (_gfxItemsCount - gfxIndex));
+ } else {
+ gfxItem->_sequenceId = -1;
+ gfxItem->_animation = nullptr;
+ gfxItem->_currFrame._duration = 0;
+ gfxItem->_currFrame._spriteId = -1;
+ gfxItem->_currFrame._soundId = -1;
+ gfxItem->_updFlag = true;
+ ++gfxIndex;
+ gfxItem = &_gfxItems[gfxIndex];
+ }
+ }
+ }
+}
+
+bool GameSys::updateSequenceDuration(int sequenceId, int id, int *outDuration) {
+ bool found = false;
+ int duration = 0x7FFFFFFF;
+ for (int i = 0; i < _gfxItemsCount; ++i) {
+ GfxItem *gfxItem = &_gfxItems[i];
+ if (gfxItem->_sequenceId == sequenceId && gfxItem->_id == id) {
+ found = true;
+ SequenceAnimation *animation = gfxItem->_animation;
+ if (animation) {
+ if (gfxItem->_currFrameNum < animation->_framesCount)
+ return false;
+ if (gfxItem->_updFlag) {
+ if (gfxItem->_currFrame._duration > 0)
+ return false;
+ if (-gfxItem->_currFrame._duration < duration)
+ duration = -gfxItem->_currFrame._duration;
+ } else {
+ if (gfxItem->_prevFrame._duration > 0)
+ return false;
+ if (-gfxItem->_prevFrame._duration < duration)
+ duration = -gfxItem->_prevFrame._duration;
+ }
+ }
+ }
+ }
+ if (found)
+ *outDuration = duration;
+ return found;
+}
+
+void GameSys::updateAnimationsStatus(int sequenceId, int id) {
+ Animation *foundAnimation = nullptr;
+ for (int animationIndex = 0; animationIndex < kMaxAnimations; ++animationIndex) {
+ Animation *animation = &_animations[animationIndex];
+ if (animation->_sequenceId != -1 && animation->_sequenceId == sequenceId && animation->_id == id) {
+ foundAnimation = animation;
+ break;
+ }
+ }
+
+ if (!foundAnimation)
+ return;
+
+ bool foundSequence = false;
+ for (int i = 0; i < _gfxItemsCount; ++i) {
+ GfxItem *gfxItem = &_gfxItems[i];
+ SequenceAnimation *animation = gfxItem->_animation;
+ if (gfxItem->_sequenceId == sequenceId && gfxItem->_id == id && animation) {
+ foundSequence = true;
+ if (animation->_framesCount > gfxItem->_currFrameNum ||
+ (gfxItem->_updFlag && gfxItem->_currFrame._duration > 1) ||
+ gfxItem->_prevFrame._duration > 1)
+ foundSequence = false;
+ break;
+ }
+ }
+
+ if (foundSequence) {
+ foundAnimation->_sequenceId = -1;
+ foundAnimation->_status = 2;
+ }
+}
+
+void GameSys::restoreBackgroundRect(const Common::Rect &rect) {
+ Common::Rect clipRect;
+ if (!intersectRect(clipRect, rect, _screenRect))
+ return;
+ byte *src = (byte *)_backgroundSurface->getBasePtr(clipRect.left, clipRect.top);
+ byte *dst = (byte *)_frontSurface->getBasePtr(clipRect.left, clipRect.top);
+ const int bytes = _backgroundSurface->format.bytesPerPixel * clipRect.width();
+ int height = clipRect.height();
+ while (height--) {
+ memcpy(dst, src, bytes);
+ src += _backgroundSurface->pitch;
+ dst += _frontSurface->pitch;
+ }
+}
+
+void GameSys::blitSurface32(Graphics::Surface *destSurface, int x, int y, Graphics::Surface *sourceSurface,
+ Common::Rect &sourceRect, bool transparent) {
+
+ const int sourcePitch = sourceSurface->pitch;
+ byte *dst = (byte *)destSurface->getBasePtr(x, y);
+ byte *src = (byte *)sourceSurface->getBasePtr(sourceRect.left, sourceRect.top);
+ int width = sourceRect.width();
+ int height = sourceRect.height();
+ while (height--) {
+ byte *rsrc = src;
+ byte *rdst = dst;
+ for (int xc = 0; xc < width; ++xc) {
+ uint32 pixel = READ_LE_UINT32(rsrc);
+ if (!transparent || pixel != 0xFFFFFF00)
+ WRITE_LE_UINT32(rdst, pixel);
+ rsrc += 4;
+ rdst += 4;
+ }
+ dst += destSurface->pitch;
+ src += sourcePitch;
+ }
+}
+
+void GameSys::blitSprite32(Graphics::Surface *destSurface, int x, int y, byte *sourcePixels,
+ int sourceWidth, Common::Rect &sourceRect, uint32 *sourcePalette, bool transparent) {
+
+ const int sourcePitch = (sourceWidth + 3) & 0xFFFFFFFC;
+ byte *dst = (byte *)destSurface->getBasePtr(x, y);
+ byte *src = sourcePixels + sourceRect.left + sourcePitch * sourceRect.top;
+ int width = sourceRect.width();
+ int height = sourceRect.height();
+ while (height--) {
+ byte *rdst = dst;
+ for (int xc = 0; xc < width; ++xc) {
+ byte srcPixel = src[xc];
+ if (!transparent || srcPixel) {
+ uint32 rgb = sourcePalette[srcPixel];
+ rdst[0] = 0xFF;
+ rdst[1] = rgb & 0x000000FF;
+ rdst[2] = (rgb & 0x0000FF00) >> 8;
+ rdst[3] = (rgb & 0x00FF0000) >> 16;
+ }
+ rdst += 4;
+ }
+ dst += destSurface->pitch;
+ src += sourcePitch;
+ }
+}
+
+void GameSys::blitSpriteScaled32(Graphics::Surface *destSurface, Common::Rect &frameRect,
+ Common::Rect &destRect, byte *sourcePixels, int sourceWidth, Common::Rect &sourceRect, uint32 *sourcePalette) {
+
+ if (frameRect.height() <= 0 || frameRect.width() <= 0)
+ return;
+
+ const int ys = ((sourceRect.bottom - sourceRect.top - 1) << 16) / (frameRect.bottom - frameRect.top - 1);
+ const int xs = ((sourceRect.right - sourceRect.left - 1) << 16) / (frameRect.right - frameRect.left - 1);
+ const int destPitch = destSurface->pitch;
+ const int sourcePitch = (sourceWidth + 3) & 0xFFFFFFFC;
+
+ if (!frameRect.equals(destRect)) {
+ byte *dst = (byte *)destSurface->getBasePtr(destRect.left, destRect.top);
+ byte *src = sourcePixels + sourcePitch * sourceRect.top + sourceRect.left;
+ const int height = destRect.bottom - destRect.top;
+ const int width = destRect.right - destRect.left;
+ int yi = ys * (destRect.top - frameRect.top);
+ byte *hsrc = src + sourcePitch * ((yi + 0x8000) >> 16);
+ for (int i = 0; i < height; ++i) {
+ byte *wdst = dst;
+ int xi = xs * (destRect.left - frameRect.left);
+ byte *wsrc = hsrc + ((xi + 0x8000) >> 16);
+ for (int j = 0; j < width; ++j) {
+ byte srcPixel = *wsrc;
+ if (srcPixel) {
+ uint32 rgb = sourcePalette[srcPixel];
+ wdst[0] = 0xFF;
+ wdst[1] = rgb & 0x000000FF;
+ wdst[2] = (rgb & 0x0000FF00) >> 8;
+ wdst[3] = (rgb & 0x00FF0000) >> 16;
+ }
+ wdst += 4;
+ xi += xs;
+ wsrc = hsrc + ((xi + 0x8000) >> 16);
+ }
+ dst += destPitch;
+ yi += ys;
+ hsrc = src + sourcePitch * ((yi + 0x8000) >> 16);
+ }
+ } else {
+ byte *dst = (byte *)destSurface->getBasePtr(frameRect.left, frameRect.top);
+ byte *src = sourcePixels + sourcePitch * sourceRect.top + sourceRect.left;
+ const int height = frameRect.bottom - frameRect.top;
+ const int width = frameRect.right - frameRect.left;
+ byte *hsrc = sourcePixels + sourcePitch * sourceRect.top + sourceRect.left;
+ int yi = 0;
+ for (int i = 0; i < height; ++i) {
+ byte *wdst = dst;
+ byte *wsrc = hsrc;
+ int xi = 0;
+ for (int j = 0; j < width; ++j) {
+ byte srcPixel = *wsrc;
+ if (srcPixel) {
+ uint32 rgb = sourcePalette[srcPixel];
+ wdst[0] = 0xFF;
+ wdst[1] = rgb & 0x000000FF;
+ wdst[2] = (rgb & 0x0000FF00) >> 8;
+ wdst[3] = (rgb & 0x00FF0000) >> 16;
+ }
+ wdst += 4;
+ xi += xs;
+ wsrc = hsrc + ((xi + 0x8000) >> 16);
+ }
+ dst += destPitch;
+ yi += ys;
+ hsrc = src + sourcePitch * ((yi + 0x8000) >> 16);
+ }
+ }
+
+}
+
+void GameSys::seqDrawStaticFrame(Graphics::Surface *surface, SequenceFrame &frame, Common::Rect *subRect) {
+ debugC(kDebugBasic, "GameSys::seqDrawStaticFrame() rect: (%d, %d, %d, %d)",
+ frame._rect.left, frame._rect.top, frame._rect.right, frame._rect.bottom);
+
+ Common::Rect srcRect = subRect ? *subRect : frame._rect;
+ Common::Rect clipRect;
+
+ if (!intersectRect(clipRect, srcRect, _screenRect)) {
+ debugC(kDebugBasic, "GameSys::seqDrawStaticFrame() Surface not inside screen");
+ return;
+ }
+
+ const int x = clipRect.left, y = clipRect.top;
+
+ clipRect.translate(-frame._rect.left, -frame._rect.top);
+
+ // TODO Save transparent flag somewhere
+ blitSurface32(_frontSurface, x, y, surface, clipRect, true);
+}
+
+void GameSys::seqDrawSpriteFrame(SpriteResource *spriteResource, SequenceFrame &frame, Common::Rect *subRect) {
+ debugC(kDebugBasic, "GameSys::seqDrawSpriteFrame() spriteId: %04X; rect: (%d, %d, %d, %d)",
+ frame._spriteId, frame._rect.left, frame._rect.top, frame._rect.right, frame._rect.bottom);
+
+ Common::Rect srcRect = subRect ? *subRect : frame._rect;
+ Common::Rect clipRect;
+
+ if (!intersectRect(clipRect, srcRect, _screenRect)) {
+ debugC(kDebugBasic, "GameSys::seqDrawSpriteFrame() Sprite not inside screen");
+ return;
+ }
+
+ uint32 *sourcePalette = spriteResource->_palette;
+ byte *sourcePixels = spriteResource->_pixels;
+
+ const int x = clipRect.left, y = clipRect.top;
+
+ debugC(kDebugBasic, "GameSys::seqDrawSpriteFrame() destX: %d; destY: %d; frame.isScaled: %d", x, y, frame._isScaled ? 1 : 0);
+
+ // 32bit sprite drawing
+ if (frame._isScaled) {
+ Common::Rect sourceRect(0, 0, spriteResource->_width, spriteResource->_height);
+ blitSpriteScaled32(_frontSurface, frame._rect, clipRect, sourcePixels, spriteResource->_width, sourceRect, sourcePalette);
+ } else {
+ clipRect.translate(-frame._rect.left, -frame._rect.top);
+ blitSprite32(_frontSurface, x, y, sourcePixels, spriteResource->_width, clipRect, sourcePalette, true);
+ }
+}
+
+void GameSys::drawSprites() {
+ debugC(kDebugBasic, "GameSys::drawSprites() _gfxItemsCount: %d", _gfxItemsCount);
+
+ // Restore dirty background and collect rects to be redrawn for all sprites
+ // which aren't marked to be redrawn yet
+ Common::Rect intersectingRect;
+ for (uint i = 0; i < _dirtyRects.size(); ++i) {
+ restoreBackgroundRect(_dirtyRects[i]);
+ for (int j = 0; j < _gfxItemsCount; ++j)
+ _gfxItems[j].testUpdRect(_dirtyRects[i]);
+ }
+
+ for (int k = 0; k < _gfxItemsCount; ++k) {
+ GfxItem *gfxItem2 = &_gfxItems[k];
+
+ if (!gfxItem2->_updFlag)
+ continue;
+
+ if (gfxItem2->_prevFrame._spriteId != -1) {
+ bool transparent = false;
+ if (gfxItem2->_currFrame._spriteId != -1) {
+ if (gfxItem2->_flags) {
+ transparent = true;
+ } else {
+ int resourceId = (gfxItem2->_sequenceId & 0xFFFF0000) | gfxItem2->_currFrame._spriteId;
+ SpriteResource *spriteResource = _vm->_spriteCache->get(resourceId);
+ transparent = spriteResource->_transparent;
+ _vm->_spriteCache->release(resourceId);
+ }
+ }
+ if (gfxItem2->_currFrame._spriteId == -1 || !gfxItem2->_prevFrame._rect.equals(gfxItem2->_currFrame._rect) || !transparent) {
+ restoreBackgroundRect(gfxItem2->_prevFrame._rect);
+ for (int l = 0; l < _gfxItemsCount; ++l)
+ _gfxItems[l].testUpdRect(gfxItem2->_prevFrame._rect);
+ }
+ }
+
+ if (gfxItem2->_currFrame._spriteId != -1) {
+ bool transparent = false;
+ if (gfxItem2->_flags) {
+ transparent = true;
+ } else {
+ int resourceId = (gfxItem2->_sequenceId & 0xFFFF0000) | gfxItem2->_currFrame._spriteId;
+ SpriteResource *spriteResource = _vm->_spriteCache->get(resourceId);
+ transparent = spriteResource->_transparent;
+ _vm->_spriteCache->release(resourceId);
+ }
+ if (gfxItem2->_prevFrame._spriteId == -1 || !gfxItem2->_prevFrame._rect.equals(gfxItem2->_currFrame._rect) || transparent) {
+ for (int l = k; l < _gfxItemsCount; ++l)
+ _gfxItems[l].testUpdRect(gfxItem2->_currFrame._rect);
+ }
+ }
+ }
+
+ for (int m = 0; m < _gfxItemsCount; ++m) {
+ GfxItem *gfxItem5 = &_gfxItems[m];
+
+ debugC(kDebugBasic, "DrawGfxItem(%d) updFlag: %d; currFrame.spriteId: %04X; updRectsCount: %d; flags: %04X; sequenceId: %08X",
+ m, gfxItem5->_updFlag, gfxItem5->_currFrame._spriteId, gfxItem5->_updRectsCount, gfxItem5->_flags, gfxItem5->_sequenceId);
+
+ if (gfxItem5->_updFlag) {
+ if (gfxItem5->_currFrame._spriteId != -1) {
+ if (gfxItem5->_flags) {
+ seqDrawStaticFrame(gfxItem5->_surface, gfxItem5->_currFrame, nullptr);
+ } else {
+ int resourceId = (gfxItem5->_sequenceId & 0xFFFF0000) | gfxItem5->_currFrame._spriteId;
+ SpriteResource *spriteResource = _vm->_spriteCache->get(resourceId);
+ seqDrawSpriteFrame(spriteResource, gfxItem5->_currFrame, nullptr);
+ _vm->_spriteCache->release(resourceId);
+ }
+ }
+ } else if (gfxItem5->_updRectsCount > 0) {
+ if (gfxItem5->_flags) {
+ for (int n = 0; n < gfxItem5->_updRectsCount; ++n)
+ seqDrawStaticFrame(gfxItem5->_surface, gfxItem5->_prevFrame, &gfxItem5->_updRects[n]);
+ } else {
+ int resourceId = (gfxItem5->_sequenceId & 0xFFFF0000) | gfxItem5->_prevFrame._spriteId;
+ SpriteResource *spriteResource = _vm->_spriteCache->get(resourceId);
+ for (int n = 0; n < gfxItem5->_updRectsCount; ++n)
+ seqDrawSpriteFrame(spriteResource, gfxItem5->_prevFrame, &gfxItem5->_updRects[n]);
+ _vm->_spriteCache->release(resourceId);
+ }
+ }
+ }
+
+ debugC(kDebugBasic, "GameSys::drawSprites() OK");
+}
+
+void GameSys::updateRect(const Common::Rect &r) {
+ debugC(kDebugBasic, "GameSys::updateRect() %d, %d, %d, %d [%d, %d]", r.left, r.top, r.right, r.bottom, r.width(), r.height());
+ if (r.width() > 0 && r.height() > 0) {
+ byte *pixels = (byte *)_frontSurface->getBasePtr(r.left, r.top);
+ _vm->_system->copyRectToScreen(pixels, _frontSurface->pitch, r.left, r.top,
+ r.width(), r.height());
+ }
+}
+
+void GameSys::updateScreen() {
+ debugC(kDebugBasic, "GameSys::updateScreen()");
+
+ for (uint i = 0; i < _dirtyRects.size(); ++i)
+ updateRect(_dirtyRects[i]);
+
+ if (_dirtyRects.size() > 0) {
+ _dirtyRects.clear();
+ _lastUpdateClock = 0;
+ _gameSysClock = 0;
+ }
+
+ Common::Rect dstRect, srcRect, rcSrc2;
+
+ for (int j = 0; j < _gfxItemsCount; ++j) {
+
+ GfxItem *gfxItem = &_gfxItems[j];
+
+ if (!gfxItem->_updFlag)
+ continue;
+
+ if (gfxItem->_prevFrame._spriteId == -1 ||
+ !intersectRect(srcRect, _screenRect, gfxItem->_prevFrame._rect)) {
+ if (gfxItem->_currFrame._spriteId != -1 && intersectRect(rcSrc2, _screenRect, gfxItem->_currFrame._rect))
+ updateRect(rcSrc2);
+ } else if (gfxItem->_currFrame._spriteId != -1 &&
+ intersectRect(rcSrc2, _screenRect, gfxItem->_currFrame._rect)) {
+ updateRect(srcRect);
+ updateRect(rcSrc2);
+ }
+ gfxItem->_prevFrame = gfxItem->_currFrame;
+ }
+
+ updateRect(Common::Rect(0, 0, 800, 600));
+
+ debugC(kDebugBasic, "GameSys::updateScreen() OK");
+}
+
+void GameSys::handleReqRemoveSequenceItem() {
+ if (_reqRemoveSequenceItem) {
+ int gfxIndex2;
+ _reqRemoveSequenceItem = false;
+ if (seqFind(_removeSequenceItemSequenceId, _removeSequenceItemValue, &gfxIndex2))
+ _seqItems.remove_at(gfxIndex2);
+ if (seqLocateGfx(_removeSequenceItemSequenceId, _removeSequenceItemValue, &gfxIndex2)) {
+ int gfxIndex2a = gfxIndex2;
+ for (GfxItem *gfxItem = &_gfxItems[gfxIndex2a];
+ gfxIndex2a < _gfxItemsCount && gfxItem->_sequenceId == _removeSequenceItemSequenceId && gfxItem->_id == _removeSequenceItemValue;
+ gfxItem = &_gfxItems[gfxIndex2a])
+ ++gfxIndex2a;
+ _gfxItemsCount -= gfxIndex2a - gfxIndex2;
+ if (_gfxItemsCount != gfxIndex2)
+ memmove(&_gfxItems[gfxIndex2], &_gfxItems[gfxIndex2a], sizeof(GfxItem) * (_gfxItemsCount - gfxIndex2));
+ }
+ }
+}
+
+void GameSys::handleReqRemoveSequenceItems() {
+ if (_removeSequenceItemsCount > 0) {
+ for (int i = 0; i < _removeSequenceItemsCount; ++i) {
+ int gfxIndex;
+ if (seqFind(_removeSequenceItems[i]._sequenceId, _removeSequenceItems[i]._id, &gfxIndex))
+ _seqItems.remove_at(gfxIndex);
+ seqLocateGfx(_removeSequenceItems[i]._sequenceId, _removeSequenceItems[i]._id, &gfxIndex);
+ for (GfxItem *gfxItem = &_gfxItems[gfxIndex];
+ gfxIndex < _gfxItemsCount && gfxItem->_sequenceId == _removeSequenceItems[i]._sequenceId && gfxItem->_id == _removeSequenceItems[i]._id;
+ gfxItem = &_gfxItems[gfxIndex]) {
+ gfxItem->_sequenceId = -1;
+ gfxItem->_animation = nullptr;
+ if (_removeSequenceItems[i]._forceFrameReset) {
+ gfxItem->_currFrame._duration = 0;
+ gfxItem->_currFrame._spriteId = -1;
+ gfxItem->_currFrame._soundId = -1;
+ gfxItem->_updFlag = true;
+ } else {
+ gfxItem->_updFlag = false;
+ }
+ ++gfxIndex;
+ }
+ }
+ _removeSequenceItemsCount = 0;
+ }
+}
+
+void GameSys::handleReqRemoveSpriteDrawItems() {
+ if (_removeSpriteDrawItemsCount > 0) {
+ for (int j = 0; j < _removeSpriteDrawItemsCount; ++j) {
+ for (int i = 0; i < _gfxItemsCount; ++i) {
+ GfxItem *gfxItem = &_gfxItems[i];
+ if (gfxItem->_sequenceId == -1 && !gfxItem->_animation && gfxItem->_flags
+ && gfxItem->_id == _removeSpriteDrawItems[j]._id && _removeSpriteDrawItems[j]._surface == gfxItem->_surface) {
+ gfxItem->_flags = 0;
+ gfxItem->_currFrame._duration = 0;
+ gfxItem->_currFrame._spriteId = -1;
+ gfxItem->_currFrame._soundId = -1;
+ gfxItem->_updFlag = true;
+ }
+ }
+ }
+ _removeSpriteDrawItemsCount = 0;
+ }
+}
+
+void GameSys::fatUpdateFrame() {
+ debugC(kDebugBasic, "GameSys::fatUpdateFrame()");
+
+ int32 clockDelta = _gameSysClock - _lastUpdateClock;
+ _lastUpdateClock = _gameSysClock;
+
+ debugC(kDebugBasic, "GameSys::fatUpdateFrame() clockDelta: %d", clockDelta);
+
+ if (clockDelta <= 0)
+ return;
+
+ int duration, currFrameNum;
+
+ for (int i = 0; i < _gfxItemsCount; ++i) {
+ GfxItem *gfxItem = &_gfxItems[i];
+ SequenceAnimation *animation = gfxItem->_animation;
+ if ((gfxItem->_sequenceId != -1 && animation) || gfxItem->_prevFrame._spriteId != -1 || gfxItem->_prevFrame._duration > 0) {
+ if (gfxItem->_sequenceId != -1 && !gfxItem->_updFlag) {
+ Sequence *seqItem = seqFind(gfxItem->_sequenceId, gfxItem->_id, nullptr);
+ if (!animation) {
+ gfxItem->_sequenceId = -1;
+ gfxItem->_animation = nullptr;
+ gfxItem->_currFrame._duration = 0;
+ gfxItem->_currFrame._spriteId = -1;
+ gfxItem->_currFrame._soundId = -1;
+ gfxItem->_updFlag = true;
+ } else if (!seqItem) {
+ gfxItem->_animation = nullptr;
+ gfxItem->_currFrame._duration = 0;
+ gfxItem->_currFrame._spriteId = -1;
+ gfxItem->_currFrame._soundId = -1;
+ gfxItem->_updFlag = true;
+ } else if ((seqItem->_flags & kSeqUnk) && clockDelta > 1) {
+ if (gfxItem->_delayTicks < clockDelta) {
+ duration = clockDelta - gfxItem->_delayTicks;
+ gfxItem->_delayTicks = 0;
+ if (gfxItem->_prevFrame._duration <= duration)
+ gfxItem->_prevFrame._duration = 1;
+ else
+ gfxItem->_prevFrame._duration -= duration;
+ } else {
+ gfxItem->_delayTicks -= clockDelta;
+ }
+ gfxItem->_updFlag = false;
+ } else if (gfxItem->_delayTicks < clockDelta) {
+ duration = clockDelta - gfxItem->_delayTicks;
+ gfxItem->_delayTicks = 0;
+ if (gfxItem->_prevFrame._duration <= duration) {
+ bool v20 = false;
+ if (gfxItem->_prevFrame._duration > 0) {
+ duration -= gfxItem->_prevFrame._duration;
+ gfxItem->_prevFrame._duration = -duration;
+ } else {
+ gfxItem->_prevFrame._duration = 0;
+ v20 = true;
+ }
+ currFrameNum = gfxItem->_currFrameNum;
+ if (animation->_framesCount > currFrameNum) {
+ while (animation->_framesCount > currFrameNum
+ && animation->frames[currFrameNum]._duration <= duration) {
+ if (animation->frames[currFrameNum]._soundId != -1)
+ _soundIds.push_back((gfxItem->_sequenceId & 0xFFFF0000) | animation->frames[currFrameNum]._soundId);
+ duration -= animation->frames[currFrameNum]._duration;
+ ++currFrameNum;
+ }
+ if (animation->_framesCount > currFrameNum)
+ gfxItem->_currFrame = animation->frames[currFrameNum++];
+ else
+ gfxItem->_currFrame = animation->frames[currFrameNum - 1];
+ if (gfxItem->_currFrame._spriteId != -1 && (seqItem->_x != 0 || seqItem->_y != 0))
+ gfxItem->_currFrame._rect.translate(seqItem->_x, seqItem->_y);
+ // Update sprite scaling
+ if ((seqItem->_flags & kSeqScale) && gfxItem->_currFrame._rect.bottom >= _backgroundImageValue1 && gfxItem->_currFrame._rect.bottom <= _backgroundImageValue3) {
+ int v17 = _backgroundImageValue2 + (gfxItem->_currFrame._rect.bottom - _backgroundImageValue1) *
+ (_backgroundImageValue4 - _backgroundImageValue2) /
+ (_backgroundImageValue3 - _backgroundImageValue1);
+ gfxItem->_currFrame._rect.top = gfxItem->_currFrame._rect.bottom - v17 * (gfxItem->_currFrame._rect.bottom - gfxItem->_currFrame._rect.top) / 1000;
+ gfxItem->_currFrame._rect.right = v17 * (gfxItem->_currFrame._rect.right - gfxItem->_currFrame._rect.left) / 1000 + gfxItem->_currFrame._rect.left;
+ gfxItem->_currFrame._isScaled = true;
+ }
+ gfxItem->_currFrame._duration -= duration;
+ if (gfxItem->_currFrame._soundId != -1)
+ _soundIds.push_back((gfxItem->_sequenceId & 0xFFFF0000) | gfxItem->_currFrame._soundId);
+ gfxItem->_currFrameNum = currFrameNum;
+ gfxItem->_updFlag = true;
+ } else if (v20 && gfxItem->_prevFrame._spriteId == -1) {
+ --_gfxItemsCount;
+ if (_gfxItemsCount != i)
+ memmove(&_gfxItems[i], &_gfxItems[i + 1], sizeof(GfxItem) * (_gfxItemsCount - i));
+ --i;
+ } else {
+ gfxItem->_updFlag = false;
+ }
+ } else {
+ gfxItem->_prevFrame._duration -= duration;
+ gfxItem->_updFlag = false;
+ }
+ } else {
+ gfxItem->_delayTicks -= clockDelta;
+ gfxItem->_updFlag = false;
+ }
+ }
+ } else {
+ --_gfxItemsCount;
+ if (_gfxItemsCount != i)
+ memmove(&_gfxItems[i], &_gfxItems[i + 1], sizeof(GfxItem) * (_gfxItemsCount - i));
+ --i;
+ }
+ }
+
+ if (_newSpriteDrawItemsCount > 0) {
+ debugC(kDebugBasic, "_newSpriteDrawItemsCount: %d", _newSpriteDrawItemsCount);
+ for (int k = 0; k < _newSpriteDrawItemsCount; ++k) {
+ if (_gfxItemsCount < 50) {
+ int insertIndex;
+ seqLocateGfx(-1, _newSpriteDrawItems[k]._id, &insertIndex);
+ if (_gfxItemsCount != insertIndex)
+ memmove(&_gfxItems[insertIndex + 1], &_gfxItems[insertIndex], sizeof(GfxItem) * (_gfxItemsCount - insertIndex));
+ ++_gfxItemsCount;
+ GfxItem *gfxItem = &_gfxItems[insertIndex];
+ gfxItem->_sequenceId = -1;
+ gfxItem->_id = _newSpriteDrawItems[k]._id;
+ gfxItem->_animation = nullptr;
+ gfxItem->_currFrameNum = 0;
+ gfxItem->_flags = 1;
+ gfxItem->_delayTicks = 0;
+ gfxItem->_updFlag = true;
+ gfxItem->_updRectsCount = 0;
+ gfxItem->_surface = _newSpriteDrawItems[k]._surface;
+ gfxItem->_prevFrame._duration = 0;
+ gfxItem->_prevFrame._spriteId = -1;
+ gfxItem->_prevFrame._soundId = -1;
+ gfxItem->_currFrame._duration = 0;
+ gfxItem->_currFrame._isScaled = false;
+ gfxItem->_currFrame._rect = _newSpriteDrawItems[k]._rect;
+ gfxItem->_currFrame._spriteId = _newSpriteDrawItems[k]._surface ? 0xCAFEBABE : -1;// TODO
+ gfxItem->_currFrame._soundId = -1;
+ }
+ }
+ _newSpriteDrawItemsCount = 0;
+ }
+
+ if (_grabSpriteChanged) {
+ for (int i = 0; i < _gfxItemsCount; ++i) {
+ GfxItem *gfxItem = &_gfxItems[i];
+ if (gfxItem->_sequenceId == -1 && !gfxItem->_animation && gfxItem->_flags
+ && gfxItem->_id == _grabSpriteId && gfxItem->_surface == _grabSpriteSurface1) {
+ gfxItem->_currFrame._duration = 0;
+ gfxItem->_currFrame._isScaled = false;
+ gfxItem->_currFrame._rect = _grabSpriteRect;
+ gfxItem->_currFrame._spriteId = _grabSpriteSurface2 ? 1 : -1;// TODO
+ gfxItem->_currFrame._soundId = -1;
+ gfxItem->_updFlag = true;
+ gfxItem->_surface = _grabSpriteSurface2;
+ break;
+ }
+ }
+ _grabSpriteChanged = false;
+ }
+
+ debugC(kDebugBasic, "GameSys::fatUpdateFrame() _fatSequenceItems.size(): %d", _fatSequenceItems.size());
+
+ for (uint i = 0; i < _fatSequenceItems.size(); ++i) {
+ Sequence *seqItem = &_fatSequenceItems[i];
+ if (((seqItem->_flags & kSeqSyncWait) || (seqItem->_flags & kSeqSyncExists)) && seqItem->_sequenceId2 != -1) {
+ duration = 0;
+ if (((seqItem->_flags & kSeqSyncExists) && seqLocateGfx(seqItem->_sequenceId2, seqItem->_id2, nullptr)) ||
+ updateSequenceDuration(seqItem->_sequenceId2, seqItem->_id2, &duration)) {
+ int index = -1;
+ bool found = false;
+ if (seqItem->_sequenceId2 == seqItem->_sequenceId && seqItem->_id == seqItem->_id2 &&
+ seqFind(seqItem->_sequenceId, seqItem->_id, &index)) {
+ _seqItems[index] = *seqItem;
+ found = true;
+ } else if (_seqItems.size() < 50) {
+ index = _seqItems.size();
+ _seqItems.push_back(*seqItem);
+ found = true;
+ }
+ if (found) {
+ seqRemoveGfx(seqItem->_sequenceId2, seqItem->_id2);
+ seqRemoveGfx(seqItem->_sequenceId, seqItem->_id);
+ _fatSequenceItems.remove_at(i);
+ --i;
+ seqInsertGfx(index, duration);
+ }
+ }
+ } else {
+ if (seqItem->_totalDuration < clockDelta) {
+ int index;
+ bool found = false;
+ duration = clockDelta - seqItem->_totalDuration;
+ seqItem->_totalDuration = 0;
+ if (seqFind(seqItem->_sequenceId, seqItem->_id, &index)) {
+ _seqItems[index] = *seqItem;
+ found = true;
+ } else if (_seqItems.size() < 50) {
+ index = _seqItems.size();
+ _seqItems.push_back(*seqItem);
+ found = true;
+ }
+ if (found) {
+ seqRemoveGfx(seqItem->_sequenceId, seqItem->_id);
+ _fatSequenceItems.remove_at(i);
+ --i;
+ seqInsertGfx(index, duration - 1);
+ }
+ } else {
+ seqItem->_totalDuration -= clockDelta;
+ }
+ }
+ }
+
+ debugC(kDebugBasic, "GameSys::fatUpdateFrame() _seqItems.size(): %d", _seqItems.size());
+
+ for (uint i = 0; i < _seqItems.size(); ++i) {
+ Sequence *seqItem = &_seqItems[i];
+ if (seqLocateGfx(seqItem->_sequenceId, seqItem->_id, nullptr)) {
+ updateAnimationsStatus(seqItem->_sequenceId, seqItem->_id);
+ if (seqItem->_flags & kSeqLoop) {
+ int gfxDuration;
+ if (updateSequenceDuration(seqItem->_sequenceId, seqItem->_id, &gfxDuration)) {
+ seqRemoveGfx(seqItem->_sequenceId, seqItem->_id);
+ seqInsertGfx(i, gfxDuration);
+ }
+ }
+ } else {
+ _seqItems.remove_at(i);
+ --i;
+ }
+ }
+}
+
+void GameSys::fatUpdate() {
+ debugC(kDebugBasic, "GameSys::fatUpdate() _gfxItemsCount: %d", _gfxItemsCount);
+
+ for (int i = 0; i < _gfxItemsCount; ++i) {
+ _gfxItems[i]._updFlag = false;
+ _gfxItems[i]._updRectsCount = 0;
+ }
+
+ handleReqRemoveSequenceItem();
+ handleReqRemoveSequenceItems();
+ handleReqRemoveSpriteDrawItems();
+
+ fatUpdateFrame();
+}
+
+void GameSys::updatePlaySounds() {
+ for (uint i = 0; i < _soundIds.size(); ++i)
+ _vm->playSound(_soundIds[i], false);
+ _soundIds.clear();
+}
+
+bool intersectRect(Common::Rect &intersectingRect, const Common::Rect &r1, const Common::Rect &r2) {
+ if (r1.intersects(r2)) {
+ intersectingRect = r1.findIntersectingRect(r2);
+ return true;
+ } else
+ return false;
+}
+
+} // End of namespace Gnap
diff --git a/engines/gnap/gamesys.h b/engines/gnap/gamesys.h
new file mode 100644
index 0000000000..98014f1bac
--- /dev/null
+++ b/engines/gnap/gamesys.h
@@ -0,0 +1,211 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can 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 GNAP_GAMESYS_H
+#define GNAP_GAMESYS_H
+
+#include "gnap/gnap.h"
+#include "gnap/resource.h"
+#include "common/array.h"
+#include "common/rect.h"
+#include "graphics/surface.h"
+
+namespace Gnap {
+
+const int kMaxSequenceItems = 40;
+const int kMaxSpriteDrawItems = 30;
+const int kMaxSoundIds = 50;
+const int kMaxSeqItems = 50;
+const int kMaxUpdRects = 20;
+const int kMaxGfxItems = 50;
+const int kMaxAnimations = 12;
+
+enum {
+ kSeqNone = 0x00,
+ kSeqScale = 0x01, // Enable scaling
+ kSeqLoop = 0x02, // Loop
+ kSeqUnk = 0x04, // Unknown
+ kSeqSyncWait = 0x08, // Start if other sequence is done
+ kSeqSyncExists = 0x20 // Start if other sequence exists
+};
+
+struct Sequence {
+ int32 _sequenceId;
+ int32 _id;
+ int32 _sequenceId2;
+ int32 _id2;
+ uint32 _flags;
+ int32 _totalDuration;
+ int16 _x, _y;
+};
+
+struct SpriteDrawItem {
+ int _id;
+ Common::Rect _rect;
+ Graphics::Surface *_surface;
+};
+
+struct RemoveSequenceItem {
+ int _sequenceId;
+ int _id;
+ bool _forceFrameReset;
+};
+
+struct RemoveSpriteDrawItem {
+ int _id;
+ Graphics::Surface *_surface;
+};
+
+struct GfxItem {
+ int _sequenceId;
+ int _id;
+ int _flags;
+ SequenceAnimation *_animation;
+ int _currFrameNum;
+ int _delayTicks;
+ bool _updFlag;
+ int _updRectsCount;
+ Graphics::Surface *_surface;
+ Common::Rect _updRects[kMaxUpdRects];
+ SequenceFrame _prevFrame;
+ SequenceFrame _currFrame;
+ void testUpdRect(const Common::Rect &updRect);
+};
+
+struct Animation {
+ int _sequenceId;
+ int _id;
+ int _status;
+};
+
+class GameSys {
+public:
+ GameSys(GnapEngine *vm);
+ ~GameSys();
+ void insertSequence(int sequenceId, int id, int sequenceId2, int id2, int flags, int totalDuration, int16 x, int16 y);
+ void insertDirtyRect(const Common::Rect &rect);
+ void removeSequence(int sequenceId, int id, bool resetFl);
+ void invalidateGrabCursorSprite(int id, Common::Rect &rect, Graphics::Surface *surface1, Graphics::Surface *surface2);
+ void requestClear2(bool resetFl);
+ void requestClear1();
+ void requestRemoveSequence(int sequenceId, int id);
+ void waitForUpdate();
+ int isSequenceActive(int sequenceId, int id);
+ void setBackgroundSurface(Graphics::Surface *surface, int a4, int a5, int a6, int a7);
+ void setScaleValues(int a1, int a2, int a3, int a4);
+ void insertSpriteDrawItem(Graphics::Surface *surface, int x, int y, int id);
+ void removeSpriteDrawItem(Graphics::Surface *surface, int id);
+ void drawSpriteToBackground(int x, int y, int resourceId);
+ Graphics::Surface *allocSurface(int width, int height);
+ Graphics::Surface *createSurface(int resourceId);
+ void drawSpriteToSurface(Graphics::Surface *surface, int x, int y, int resourceId);
+ void drawTextToSurface(Graphics::Surface *surface, int x, int y, byte r, byte g, byte b, const char *text);
+ int getTextHeight(const char *text);
+ int getTextWidth(const char *text);
+ void fillSurface(Graphics::Surface *surface, int x, int y, int width, int height, byte r, byte g, byte b);
+ void setAnimation(int sequenceId, int id, int animationIndex);
+ int getAnimationStatus(int animationIndex);
+ int getSpriteWidthById(int resourceId);
+ int getSpriteHeightById(int resourceId);
+ Graphics::Surface *loadBitmap(int resourceId);
+ void drawBitmap(int resourceId);
+public:
+ GnapEngine *_vm;
+
+ Common::Array<Common::Rect> _dirtyRects;
+
+ SpriteDrawItem _newSpriteDrawItems[kMaxSpriteDrawItems];
+ int _newSpriteDrawItemsCount;
+
+ RemoveSequenceItem _removeSequenceItems[kMaxSequenceItems];
+ int _removeSequenceItemsCount;
+
+ RemoveSpriteDrawItem _removeSpriteDrawItems[kMaxSpriteDrawItems];
+ int _removeSpriteDrawItemsCount;
+
+ int _grabSpriteId;
+ Common::Rect _grabSpriteRect;
+ bool _grabSpriteChanged;
+ Graphics::Surface *_grabSpriteSurface1, *_grabSpriteSurface2;
+
+ bool _reqRemoveSequenceItem;
+ int _removeSequenceItemSequenceId, _removeSequenceItemValue;
+
+ Common::Array<int> _soundIds;
+
+ ////////////////////////////////////////////////////////////////////////////
+
+ Common::Array<Sequence> _seqItems;
+ Common::Array<Sequence> _fatSequenceItems;
+
+ GfxItem _gfxItems[kMaxGfxItems];
+ int _gfxItemsCount;
+
+ Animation _animations[kMaxAnimations];
+ int _animationsCount;
+
+ int _backgroundImageValue3, _backgroundImageValue1;
+ int _backgroundImageValue4, _backgroundImageValue2;
+
+ int32 _gameSysClock, _lastUpdateClock;
+
+ Graphics::Surface *_backgroundSurface;
+ Graphics::Surface *_frontSurface;
+ Common::Rect _screenRect;
+
+ Sequence *seqFind(int sequenceId, int id, int *outIndex);
+ int seqLocateGfx(int sequenceId, int id, int *outGfxIndex);
+ void seqInsertGfx(int index, int duration);
+ void seqRemoveGfx(int sequenceId, int id);
+ bool updateSequenceDuration(int sequenceId, int id, int *outDuration);
+ void updateAnimationsStatus(int sequenceId, int id);
+
+ void restoreBackgroundRect(const Common::Rect &rect);
+
+ void blitSurface32(Graphics::Surface *destSurface, int x, int y, Graphics::Surface *sourceSurface,
+ Common::Rect &sourceRect, bool transparent);
+ void blitSprite32(Graphics::Surface *destSurface, int x, int y, byte *sourcePixels,
+ int sourceWidth, Common::Rect &sourceRect, uint32 *sourcePalette, bool transparent);
+ void blitSpriteScaled32(Graphics::Surface *destSurface, Common::Rect &frameRect,
+ Common::Rect &destRect, byte *sourcePixels, int sourceWidth, Common::Rect &sourceRect, uint32 *sourcePalette);
+
+ void seqDrawStaticFrame(Graphics::Surface *surface, SequenceFrame &frame, Common::Rect *subRect);
+ void seqDrawSpriteFrame(SpriteResource *spriteResource, SequenceFrame &frame, Common::Rect *subRect);
+
+ void drawSprites();
+ void updateRect(const Common::Rect &r);
+ void updateScreen();
+
+ void handleReqRemoveSequenceItem();
+ void handleReqRemoveSequenceItems();
+ void handleReqRemoveSpriteDrawItems();
+ void fatUpdateFrame();
+ void fatUpdate();
+ void updatePlaySounds();
+
+};
+
+bool intersectRect(Common::Rect &intersectingRect, const Common::Rect &r1, const Common::Rect &r2);
+
+} // End of namespace Gnap
+
+#endif // GNAP_GAMESYS_H
diff --git a/engines/gnap/gnap.cpp b/engines/gnap/gnap.cpp
new file mode 100644
index 0000000000..ed2d25f3de
--- /dev/null
+++ b/engines/gnap/gnap.cpp
@@ -0,0 +1,1190 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can 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 "graphics/cursorman.h"
+#include "gnap/gnap.h"
+#include "gnap/datarchive.h"
+#include "gnap/gamesys.h"
+#include "gnap/resource.h"
+#include "gnap/sound.h"
+
+#include "common/config-manager.h"
+#include "common/debug-channels.h"
+#include "common/timer.h"
+
+#include "engines/util.h"
+
+namespace Gnap {
+
+static const int kCursors[] = {
+ LOOK_CURSOR,
+ GRAB_CURSOR,
+ TALK_CURSOR,
+ PLAT_CURSOR
+};
+
+static const int kDisabledCursors[] = {
+ NOLOOK_CURSOR,
+ NOGRAB_CURSOR,
+ NOTALK_CURSOR,
+ NOPLAT_CURSOR
+};
+
+static const char *kCursorNames[] = {
+ "LOOK_CURSOR",
+ "GRAB_CURSOR",
+ "TALK_CURSOR",
+ "PLAT_CURSOR",
+ "NOLOOK_CURSOR",
+ "NOGRAB_CURSOR",
+ "NOTALK_CURSOR",
+ "NOPLAT_CURSOR",
+ "EXIT_L_CURSOR",
+ "EXIT_R_CURSOR",
+ "EXIT_U_CURSOR",
+ "EXIT_D_CURSOR",
+ "EXIT_NE_CURSOR",
+ "EXIT_NW_CURSOR",
+ "EXIT_SE_CURSOR",
+ "EXIT_SW_CURSOR",
+ "WAIT_CURSOR"
+};
+
+
+static const int kCursorSpriteIds[30] = {
+ 0x005, 0x008, 0x00A, 0x004, 0x009, 0x003,
+ 0x006, 0x007, 0x00D, 0x00F, 0x00B, 0x00C,
+ 0x019, 0x01C, 0x015, 0x014, 0x010, 0x01A,
+ 0x018, 0x013, 0x011, 0x012, 0x01B, 0x016,
+ 0x017, 0x01D, 0x01E, 0x01F, 0x76A, 0x76B
+};
+
+static const char *kSceneNames[] = {
+ "open", "pigpn", "truck", "creek", "mafrm", "frbrn", "inbrn", "crash",
+ "porch", "barbk", "kitch", "bar", "juke", "wash", "john", "jkbox",
+ "brawl", "stret", "frtoy", "intoy", "frgro", "park", "cash", "ingro",
+ "frcir", "booth", "circ", "outcl", "incln", "monk", "elcir", "beer",
+ "pig2", "trk2", "creek", "frbrn", "inbrn", "mafrm", "infrm", "efair",
+ "fair", "souv", "chick", "ship", "kiss", "disco", "boot", "can",
+ "can2", "drive", "tung", "puss", "space", "phone", "can3"
+};
+
+GnapEngine::GnapEngine(OSystem *syst, const ADGameDescription *gd) :
+ Engine(syst), _gameDescription(gd) {
+
+ _random = new Common::RandomSource("gnap");
+ DebugMan.addDebugChannel(kDebugBasic, "basic", "Basic debug level");
+
+ Engine::syncSoundSettings();
+ _scene = nullptr;
+ _music = nullptr;
+ _tempThumbnail = nullptr;
+
+ _wasSavegameLoaded = false;
+ for (int i = 0; i < kMaxTimers; ++i)
+ _savedTimers[i] = _timers[i] = 0;
+
+ _isWaiting = false;
+ _sceneWaiting = false;
+
+ _mousePos = Common::Point(0, 0);
+ _currGrabCursorX = _currGrabCursorY = 0;
+
+ _idleTimerIndex = -1;
+ _menuStatus = 0;
+ _menuSpritesIndex = -1;
+ _menuDone = false;
+ _menuBackgroundSurface = nullptr;
+ _menuQuitQuerySprite = nullptr;
+ _largeSprite = nullptr;
+ _menuSaveLoadSprite = nullptr;
+ _menuSprite2 = nullptr;
+ _menuSprite1 = nullptr;
+ _spriteHandle = nullptr;
+ _cursorSprite = nullptr;
+ _savegameIndex = -1;
+ _gridMinX = 0;
+ _gridMinY = 0;
+ _gridMaxX = 0;
+ _gridMaxY = 0;
+ _toyUfoNextSequenceId = -1;
+ _toyUfoSequenceId = -1;
+ _toyUfoId = -1;
+ _toyUfoActionStatus = -1;
+ _toyUfoX = 0;
+ _toyUfoY = 0;
+ _s18GarbageCanPos = 0;
+
+ for (int i = 0; i < 7; i++)
+ _savegameSprites[i] = nullptr;
+ for (int i = 0; i < 30; i++)
+ _menuInventorySprites[i] = nullptr;
+}
+
+GnapEngine::~GnapEngine() {
+ delete _random;
+ delete _music;
+ delete _tempThumbnail;
+}
+
+Common::Error GnapEngine::run() {
+ // Initialize the graphics mode to RGBA8888
+ Graphics::PixelFormat format = Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0);
+ initGraphics(800, 600, true, &format);
+
+ // We do not support color conversion yet
+ if (_system->getScreenFormat() != format)
+ return Common::kUnsupportedColorMode;
+
+ _lastUpdateClock = 0;
+
+ // >>>>> Variable initialization
+ _cursorIndex = -1;
+ _verbCursor = 1;
+
+ _loadGameSlot = -1;
+ if (ConfMan.hasKey("save_slot"))
+ _loadGameSlot = ConfMan.getInt("save_slot");
+
+ invClear();
+ clearFlags();
+
+ _grabCursorSprite = nullptr;
+ _newGrabCursorSpriteIndex = -1;
+ _backgroundSurface = nullptr;
+ _isStockDatLoaded = false;
+ _gameDone = false;
+ _isPaused = false;
+ _pauseSprite = nullptr;
+
+ ////////////////////////////////////////////////////////////////////////////
+
+ _exe = new Common::PEResources();
+ if (!_exe->loadFromEXE("ufos.exe"))
+ error("Could not load ufos.exe");
+
+#ifdef USE_FREETYPE2
+ Common::SeekableReadStream *stream = _exe->getResource(Common::kPEFont, 2000);
+ _font = Graphics::loadTTFFont(*stream, 24);
+ if (!_font)
+ warning("Unable to load font");
+ delete stream;
+#else
+ _font = nullptr;
+#endif
+
+ _dat = new DatManager();
+ _spriteCache = new SpriteCache(_dat);
+ _soundCache = new SoundCache(_dat);
+ _sequenceCache = new SequenceCache(_dat);
+ _gameSys = new GameSys(this);
+ _soundMan = new SoundMan(this);
+ _debugger = new Debugger(this);
+ _gnap = new PlayerGnap(this);
+ _plat = new PlayerPlat(this);
+
+ _menuBackgroundSurface = nullptr;
+
+ initGlobalSceneVars();
+ mainLoop();
+
+ delete _plat;
+ delete _gnap;
+ delete _soundMan;
+ delete _gameSys;
+ delete _sequenceCache;
+ delete _soundCache;
+ delete _spriteCache;
+ delete _dat;
+ delete _debugger;
+ delete _font;
+ delete _exe;
+
+ return Common::kNoError;
+}
+
+void GnapEngine::updateEvents() {
+ Common::Event event;
+
+ while (_eventMan->pollEvent(event)) {
+ switch (event.type) {
+ case Common::EVENT_KEYDOWN:
+ // Check for debugger
+ if (event.kbd.keycode == Common::KEYCODE_d && (event.kbd.flags & Common::KBD_CTRL)) {
+ // Attach to the debugger
+ _debugger->attach();
+ _debugger->onFrame();
+ }
+
+ _keyPressState[event.kbd.keycode] = 1;
+ _keyDownState[event.kbd.keycode] = 1;
+ break;
+ case Common::EVENT_KEYUP:
+ _keyDownState[event.kbd.keycode] = 0;
+ break;
+ case Common::EVENT_MOUSEMOVE:
+ _mousePos = event.mouse;
+ break;
+ case Common::EVENT_LBUTTONUP:
+ _mouseButtonState._left = false;
+ break;
+ case Common::EVENT_LBUTTONDOWN:
+ _leftClickMouseX = event.mouse.x;
+ _leftClickMouseY = event.mouse.y;
+ _mouseButtonState._left = true;
+ _mouseClickState._left = true;
+ break;
+ case Common::EVENT_RBUTTONUP:
+ _mouseButtonState._right = false;
+ break;
+ case Common::EVENT_RBUTTONDOWN:
+ _mouseButtonState._right = true;
+ _mouseClickState._right = true;
+ break;
+ case Common::EVENT_QUIT:
+ quitGame();
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+void GnapEngine::gameUpdateTick() {
+ updateEvents();
+
+ if (shouldQuit()) {
+ _gameDone = true;
+ _sceneDone = true;
+ }
+
+ int currClock = _system->getMillis();
+ if (currClock >= _lastUpdateClock + 66) {
+ _gameSys->fatUpdate();
+ _gameSys->drawSprites();
+ _gameSys->updateScreen();
+ _gameSys->updatePlaySounds();
+ _gameSys->_gameSysClock++;
+ updateTimers();
+ _lastUpdateClock = currClock;
+ }
+
+ _soundMan->update();
+ _system->updateScreen();
+ _system->delayMillis(5);
+}
+
+void GnapEngine::saveTimers() {
+ for (int i = 0; i < kMaxTimers; ++i )
+ _savedTimers[i] = _timers[i];
+}
+
+void GnapEngine::restoreTimers() {
+ for (int i = 0; i < kMaxTimers; ++i )
+ _timers[i] = _savedTimers[i];
+}
+
+void GnapEngine::pauseGame() {
+ if (!_isPaused) {
+ saveTimers();
+ hideCursor();
+ setGrabCursorSprite(-1);
+ _pauseSprite = _gameSys->createSurface(0x1076C);
+ _gameSys->insertSpriteDrawItem(_pauseSprite, (800 - _pauseSprite->w) / 2, (600 - _pauseSprite->h) / 2, 356);
+ _lastUpdateClock = 0;
+ gameUpdateTick();
+ playMidi("pause.mid");
+ _isPaused = true;
+ }
+}
+
+void GnapEngine::resumeGame() {
+ if (_isPaused) {
+ restoreTimers();
+ _gameSys->removeSpriteDrawItem(_pauseSprite, 356);
+ _lastUpdateClock = 0;
+ gameUpdateTick();
+ deleteSurface(&_pauseSprite);
+ stopMidi();
+ _isPaused = false;
+ clearAllKeyStatus1();
+ _mouseClickState._left = false;
+ _mouseClickState._right = false;
+ showCursor();
+ _gameSys->_gameSysClock = 0;
+ _gameSys->_lastUpdateClock = 0;
+ }
+}
+
+void GnapEngine::updatePause() {
+ while (_isPaused && !_gameDone) {
+ gameUpdateTick();
+ if (isKeyStatus1(Common::KEYCODE_p)) {
+ clearKeyStatus1(Common::KEYCODE_p);
+ resumeGame();
+ }
+ }
+}
+
+int GnapEngine::getRandom(int max) {
+ return _random->getRandomNumber(max - 1);
+}
+
+int GnapEngine::readSavegameDescription(int savegameNum, Common::String &description) {
+ description = Common::String::format("Savegame %d", savegameNum);
+ return 0;
+}
+
+int GnapEngine::loadSavegame(int savegameNum) {
+ return 1;
+}
+
+void GnapEngine::delayTicks(int val, int idx = 0, bool updateCursor = false) {
+ int startTick = _timers[idx];
+
+ _timers[idx] = val;
+
+ while (_timers[idx] && !_gameDone) {
+ gameUpdateTick();
+
+ if (updateCursor)
+ updateGrabCursorSprite(0, 0);
+ }
+
+ startTick -= _timers[idx];
+ if (startTick < 0)
+ startTick = 0;
+
+ _timers[idx] = startTick;
+}
+
+void GnapEngine::delayTicksA(int val, int idx) {
+ delayTicks(val, idx);
+}
+
+void GnapEngine::delayTicksCursor(int val) {
+ delayTicks(val, 0, true);
+}
+
+void GnapEngine::setHotspot(int index, int16 x1, int16 y1, int16 x2, int16 y2, uint16 flags,
+ int16 walkX, int16 walkY) {
+ _hotspots[index]._rect = Common::Rect(x1, y1, x2, y2);
+ _hotspots[index]._flags = flags;
+ _hotspotsWalkPos[index] = Common::Point(walkX, walkY);
+}
+
+int GnapEngine::getHotspotIndexAtPos(Common::Point pos) {
+ for (int i = 0; i < _hotspotsCount; ++i) {
+ if (!_hotspots[i].isFlag(SF_DISABLED) && _hotspots[i].isPointInside(pos))
+ return i;
+ }
+ return -1;
+}
+
+void GnapEngine::updateCursorByHotspot() {
+ if (!_isWaiting) {
+ int hotspotIndex = getHotspotIndexAtPos(_mousePos);
+
+ if (_debugger->_showHotspotNumber) {
+ // NOTE This causes some display glitches
+ char t[256];
+ sprintf(t, "hotspot = %2d", hotspotIndex);
+ if (!_font)
+ _gameSys->fillSurface(nullptr, 10, 10, 80, 16, 0, 0, 0);
+ else
+ _gameSys->fillSurface(nullptr, 8, 9, _font->getStringWidth(t) + 10, _font->getFontHeight() + 2, 0, 0, 0);
+ _gameSys->drawTextToSurface(nullptr, 10, 10, 255, 255, 255, t);
+ }
+
+ if (hotspotIndex < 0)
+ setCursor(kDisabledCursors[_verbCursor]);
+ else if (_hotspots[hotspotIndex]._flags & SF_EXIT_L_CURSOR)
+ setCursor(EXIT_L_CURSOR);
+ else if (_hotspots[hotspotIndex]._flags & SF_EXIT_R_CURSOR)
+ setCursor(EXIT_R_CURSOR);
+ else if (_hotspots[hotspotIndex]._flags & SF_EXIT_U_CURSOR)
+ setCursor(EXIT_U_CURSOR);
+ else if (_hotspots[hotspotIndex]._flags & SF_EXIT_D_CURSOR)
+ setCursor(EXIT_D_CURSOR);
+ else if (_hotspots[hotspotIndex]._flags & SF_EXIT_NE_CURSOR)
+ setCursor(EXIT_NE_CURSOR);
+ else if (_hotspots[hotspotIndex]._flags & SF_EXIT_NW_CURSOR)
+ setCursor(EXIT_NW_CURSOR);
+ else if (_hotspots[hotspotIndex]._flags & SF_EXIT_SE_CURSOR)
+ setCursor(EXIT_SE_CURSOR);
+ else if (_hotspots[hotspotIndex]._flags & SF_EXIT_SW_CURSOR)
+ setCursor(EXIT_SW_CURSOR);
+ else if (_hotspots[hotspotIndex]._flags & (1 << _verbCursor))
+ setCursor(kCursors[_verbCursor]);
+ else
+ setCursor(kDisabledCursors[_verbCursor]);
+ }
+ // Update platypus hotspot
+ _hotspots[0]._rect = Common::Rect(_gridMinX + 75 * _plat->_pos.x - 30, _gridMinY + 48 * _plat->_pos.y - 100
+ , _gridMinX + 75 * _plat->_pos.x + 30, _gridMinY + 48 * _plat->_pos.y);
+}
+
+int GnapEngine::getClickedHotspotId() {
+ int result = -1;
+ if (_isWaiting)
+ _mouseClickState._left = false;
+ else if (_mouseClickState._left) {
+ int hotspotIndex = getHotspotIndexAtPos(Common::Point(_leftClickMouseX, _leftClickMouseY));
+ if (hotspotIndex >= 0) {
+ _mouseClickState._left = false;
+ _timers[3] = 300;
+ result = hotspotIndex;
+ }
+ }
+ return result;
+}
+
+int GnapEngine::getInventoryItemSpriteNum(int index) {
+ return kCursorSpriteIds[index];
+}
+
+void GnapEngine::updateMouseCursor() {
+ if (_mouseClickState._right) {
+ // Switch through the verb cursors
+ _mouseClickState._right = false;
+ _timers[3] = 300;
+ _verbCursor = (_verbCursor + 1) % 4;
+ if (!isFlag(kGFPlatypus) && _verbCursor == PLAT_CURSOR && _cursorValue == 1)
+ _verbCursor = (_verbCursor + 1) % 4;
+ if (!_isWaiting)
+ setCursor(kDisabledCursors[_verbCursor]);
+ setGrabCursorSprite(-1);
+ }
+ if (_isWaiting && ((_gnap->_actionStatus < 0 && _plat->_actionStatus < 0) || _sceneWaiting)) {
+ setCursor(kDisabledCursors[_verbCursor]);
+ _isWaiting = false;
+ } else if (!_isWaiting && (_gnap->_actionStatus >= 0 || _plat->_actionStatus >= 0) && !_sceneWaiting) {
+ setCursor(WAIT_CURSOR);
+ _isWaiting = true;
+ }
+}
+
+void GnapEngine::setVerbCursor(int verbCursor) {
+ _verbCursor = verbCursor;
+ if (!_isWaiting)
+ setCursor(kDisabledCursors[_verbCursor]);
+}
+
+void GnapEngine::setCursor(int cursorIndex) {
+ if (_cursorIndex != cursorIndex) {
+ const char *cursorName = kCursorNames[cursorIndex];
+ Graphics::WinCursorGroup *cursorGroup = Graphics::WinCursorGroup::createCursorGroup(*_exe, Common::WinResourceID(cursorName));
+ if (cursorGroup) {
+ Graphics::Cursor *cursor = cursorGroup->cursors[0].cursor;
+ CursorMan.replaceCursor(cursor->getSurface(), cursor->getWidth(), cursor->getHeight(),
+ cursor->getHotspotX(), cursor->getHotspotY(), cursor->getKeyColor());
+ CursorMan.replaceCursorPalette(cursor->getPalette(), 0, 256);
+ delete cursorGroup;
+ }
+ _cursorIndex = cursorIndex;
+ }
+}
+
+void GnapEngine::showCursor() {
+ CursorMan.showMouse(true);
+}
+
+void GnapEngine::hideCursor() {
+ CursorMan.showMouse(false);
+}
+
+void GnapEngine::setGrabCursorSprite(int index) {
+ freeGrabCursorSprite();
+ if (index >= 0) {
+ createGrabCursorSprite(makeRid(1, kCursorSpriteIds[index]));
+ setVerbCursor(GRAB_CURSOR);
+ }
+ _grabCursorSpriteIndex = index;
+}
+
+void GnapEngine::createGrabCursorSprite(int spriteId) {
+ _grabCursorSprite = _gameSys->createSurface(spriteId);
+ _gameSys->insertSpriteDrawItem(_grabCursorSprite,
+ _mousePos.x - (_grabCursorSprite->w / 2),
+ _mousePos.y - (_grabCursorSprite->h / 2),
+ 300);
+ delayTicks(5);
+}
+
+void GnapEngine::freeGrabCursorSprite() {
+ if (_grabCursorSprite) {
+ _gameSys->removeSpriteDrawItem(_grabCursorSprite, 300);
+ _gameSys->removeSpriteDrawItem(_grabCursorSprite, 301);
+ delayTicks(5);
+ deleteSurface(&_grabCursorSprite);
+ }
+}
+
+void GnapEngine::updateGrabCursorSprite(int x, int y) {
+ if (_grabCursorSprite) {
+ int newGrabCursorX = _mousePos.x - (_grabCursorSprite->w / 2) - x;
+ int newGrabCursorY = _mousePos.y - (_grabCursorSprite->h / 2) - y;
+ if (_currGrabCursorX != newGrabCursorX || _currGrabCursorY != newGrabCursorY) {
+ _currGrabCursorX = newGrabCursorX;
+ _currGrabCursorY = newGrabCursorY;
+ Common::Rect rect(newGrabCursorX, newGrabCursorY,
+ newGrabCursorX + _grabCursorSprite->w, newGrabCursorY + _grabCursorSprite->h);
+ _gameSys->invalidateGrabCursorSprite(300, rect, _grabCursorSprite, _grabCursorSprite);
+ }
+ }
+}
+
+void GnapEngine::invClear() {
+ _inventory = 0;
+}
+
+void GnapEngine::invAdd(int itemId) {
+ _inventory |= (1 << itemId);
+}
+
+void GnapEngine::invRemove(int itemId) {
+ _inventory &= ~(1 << itemId);
+}
+
+bool GnapEngine::invHas(int itemId) {
+ return (_inventory & (1 << itemId)) != 0;
+}
+
+void GnapEngine::clearFlags() {
+ _gameFlags = 0;
+}
+
+void GnapEngine::setFlag(int num) {
+ _gameFlags |= (1 << num);
+}
+
+void GnapEngine::clearFlag(int num) {
+ _gameFlags &= ~(1 << num);
+}
+
+bool GnapEngine::isFlag(int num) {
+ return (_gameFlags & (1 << num)) != 0;
+}
+
+Graphics::Surface *GnapEngine::addFullScreenSprite(int resourceId, int id) {
+ _fullScreenSpriteId = id;
+ _fullScreenSprite = _gameSys->createSurface(resourceId);
+ _gameSys->insertSpriteDrawItem(_fullScreenSprite, 0, 0, id);
+ return _fullScreenSprite;
+}
+
+void GnapEngine::removeFullScreenSprite() {
+ _gameSys->removeSpriteDrawItem(_fullScreenSprite, _fullScreenSpriteId);
+ deleteSurface(&_fullScreenSprite);
+}
+
+void GnapEngine::showFullScreenSprite(int resourceId) {
+ hideCursor();
+ setGrabCursorSprite(-1);
+ addFullScreenSprite(resourceId, 256);
+ while (!_mouseClickState._left && !isKeyStatus1(Common::KEYCODE_ESCAPE)
+ && !isKeyStatus1(Common::KEYCODE_SPACE) && !isKeyStatus1(Common::KEYCODE_RETURN) && !_gameDone) {
+ gameUpdateTick();
+ }
+ _mouseClickState._left = false;
+ clearKeyStatus1(Common::KEYCODE_ESCAPE);
+ clearKeyStatus1(Common::KEYCODE_RETURN);
+ clearKeyStatus1(Common::KEYCODE_SPACE);
+ removeFullScreenSprite();
+ showCursor();
+}
+
+void GnapEngine::queueInsertDeviceIcon() {
+ _gameSys->insertSequence(0x10849, 20, 0, 0, kSeqNone, 0, _deviceX1, _deviceY1);
+}
+
+void GnapEngine::insertDeviceIconActive() {
+ _gameSys->insertSequence(0x1084A, 21, 0, 0, kSeqNone, 0, _deviceX1, _deviceY1);
+}
+
+void GnapEngine::removeDeviceIconActive() {
+ _gameSys->removeSequence(0x1084A, 21, true);
+}
+
+void GnapEngine::setDeviceHotspot(int hotspotIndex, int x1, int y1, int x2, int y2) {
+ _deviceX1 = x1;
+ _deviceX2 = x2;
+ _deviceY1 = y1;
+ _deviceY2 = y2;
+ if (x1 == -1)
+ _deviceX1 = 730;
+ if (x2 == -1)
+ _deviceX2 = 780;
+ if (y1 == -1)
+ _deviceY1 = 14;
+ if (y2 == -1)
+ _deviceY2 = 79;
+
+ _hotspots[hotspotIndex]._rect = Common::Rect(_deviceX1, _deviceY1, _deviceX2, _deviceY2);
+ _hotspots[hotspotIndex]._flags = SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR;
+}
+
+int GnapEngine::getSequenceTotalDuration(int resourceId) {
+ SequenceResource *sequenceResource = _sequenceCache->get(resourceId);
+ int maxValue = 0;
+ for (int i = 0; i < sequenceResource->_animationsCount; ++i) {
+ SequenceAnimation *animation = &sequenceResource->_animations[i];
+ if (animation->_additionalDelay + animation->_maxTotalDuration > maxValue)
+ maxValue = animation->_additionalDelay + animation->_maxTotalDuration;
+ }
+ int totalDuration = maxValue + sequenceResource->_totalDuration;
+ _sequenceCache->release(resourceId);
+ return totalDuration;
+}
+
+bool GnapEngine::isSoundPlaying(int resourceId) {
+ return _soundMan->isSoundPlaying(resourceId);
+}
+
+void GnapEngine::playSound(int resourceId, bool looping) {
+ debugC(kDebugBasic, "playSound(%08X, %d)", resourceId, looping);
+ _soundMan->playSound(resourceId, looping);
+}
+
+void GnapEngine::stopSound(int resourceId) {
+ _soundMan->stopSound(resourceId);
+}
+
+void GnapEngine::setSoundVolume(int resourceId, int volume) {
+ _soundMan->setSoundVolume(resourceId, volume);
+}
+
+void GnapEngine::updateTimers() {
+ for (int i = 0; i < kMaxTimers; ++i)
+ if (_timers[i] > 0)
+ --_timers[i];
+}
+
+void GnapEngine::initGameFlags(int num) {
+ invClear();
+ invAdd(kItemMagazine);
+ switch (num) {
+ case 1:
+ setFlag(kGFPlatypusTalkingToAssistant);
+ break;
+ case 2:
+ clearFlags();
+ break;
+ case 3:
+ invAdd(kItemDiceQuarterHole);
+ clearFlags();
+ break;
+ case 4:
+ invAdd(kItemDiceQuarterHole);
+ invAdd(kItemHorn);
+ invAdd(kItemLightbulb);
+ clearFlags();
+ setFlag(kGFPlatypus);
+ setFlag(kGFMudTaken);
+ setFlag(kGFNeedleTaken);
+ setFlag(kGFTwigTaken);
+ setFlag(kGFUnk04);
+ setFlag(kGFKeysTaken);
+ setFlag(kGFGrassTaken);
+ setFlag(kGFBarnPadlockOpen);
+ break;
+ }
+}
+
+void GnapEngine::loadStockDat() {
+ if (!_isStockDatLoaded) {
+ _isStockDatLoaded = true;
+ _dat->open(1, "stock_n.dat");
+ // The pre-loading of data is skipped as it's no longer required on modern hardware
+ }
+}
+
+void GnapEngine::mainLoop() {
+ _newCursorValue = 1;
+ _cursorValue = -1;
+ _newSceneNum = 0;
+ _currentSceneNum = 55;
+ _prevSceneNum = 55;
+ invClear();
+ clearFlags();
+ _grabCursorSpriteIndex = -1;
+ _grabCursorSprite = nullptr;
+
+ loadStockDat();
+
+ if (_loadGameSlot != -1) {
+ // Load a savegame
+ int slot = _loadGameSlot;
+ _loadGameSlot = -1;
+ loadGameState(slot);
+ _wasSavegameLoaded = true;
+
+ showCursor();
+ }
+
+ while (!_gameDone) {
+ debugC(kDebugBasic, "New scene: %d", _newSceneNum);
+
+ _prevSceneNum = _currentSceneNum;
+ _currentSceneNum = _newSceneNum;
+
+ debugC(kDebugBasic, "GnapEngine::mainLoop() _prevSceneNum: %d; _currentSceneNum: %d", _prevSceneNum, _currentSceneNum);
+
+ if (_newCursorValue != _cursorValue) {
+ debugC(kDebugBasic, "_newCursorValue: %d", _newCursorValue);
+ _cursorValue = _newCursorValue;
+ if (!_wasSavegameLoaded)
+ initGameFlags(_cursorValue);
+ }
+
+ _sceneSavegameLoaded = _wasSavegameLoaded;
+ _wasSavegameLoaded = false;
+
+ initScene();
+
+ runSceneLogic();
+ afterScene();
+
+ _soundMan->stopAll();
+
+ // Force purge all resources
+ _sequenceCache->purge(true);
+ _soundCache->purge(true);
+ _spriteCache->purge(true);
+ }
+
+ if (_backgroundSurface)
+ deleteSurface(&_backgroundSurface);
+
+ _dat->close(1);
+}
+
+void GnapEngine::initScene() {
+ Common::String datFilename;
+
+ _isLeavingScene = false;
+ _sceneDone = false;
+ _newSceneNum = 55;
+ _gnap->_actionStatus = -1;
+ _plat->_actionStatus = -1;
+ _gnap->initBrainPulseRndValue();
+ hideCursor();
+ clearAllKeyStatus1();
+ _mouseClickState._left = false;
+ _mouseClickState._right = false;
+ _sceneClickedHotspot = -1;
+
+ datFilename = Common::String::format("%s_n.dat", kSceneNames[_currentSceneNum]);
+
+ debugC(kDebugBasic, "GnapEngine::initScene() datFilename: %s", datFilename.c_str());
+
+ _dat->open(0, datFilename.c_str());
+
+ int backgroundId = initSceneLogic();
+
+ if (!_backgroundSurface) {
+ if (_currentSceneNum != 0)
+ _backgroundSurface = _gameSys->loadBitmap(makeRid(1, 0x8AA));
+ else
+ _backgroundSurface = _gameSys->loadBitmap(makeRid(0, backgroundId));
+ _gameSys->setBackgroundSurface(_backgroundSurface, 0, 500, 1, 1000);
+ }
+
+ if (_currentSceneNum != 0 && _currentSceneNum != 16 && _currentSceneNum != 47 &&
+ _currentSceneNum != 48 && _currentSceneNum != 54) {
+ _gameSys->drawBitmap(backgroundId);
+ }
+
+ if ((_cursorValue == 4 && isFlag(kGFGnapControlsToyUFO)) || _currentSceneNum == 41)
+ playSound(makeRid(1, 0x8F6), true);
+
+}
+
+void GnapEngine::endSceneInit() {
+ showCursor();
+ if (_newGrabCursorSpriteIndex >= 0)
+ setGrabCursorSprite(_newGrabCursorSpriteIndex);
+}
+
+void GnapEngine::afterScene() {
+ if (_gameDone)
+ return;
+
+ if (_newCursorValue == _cursorValue && _newSceneNum != 0 && _newSceneNum != 16 &&
+ _newSceneNum != 47 && _newSceneNum != 48 && _newSceneNum != 54 && _newSceneNum != 49 &&
+ _newSceneNum != 50 && _newSceneNum != 51 && _newSceneNum != 52)
+ _newGrabCursorSpriteIndex = _grabCursorSpriteIndex;
+ else
+ _newGrabCursorSpriteIndex = -1;
+
+ setGrabCursorSprite(-1);
+
+ _gameSys->requestClear2(false);
+ _gameSys->requestClear1();
+ _gameSys->waitForUpdate();
+
+ _gameSys->requestClear2(false);
+ _gameSys->requestClear1();
+ _gameSys->waitForUpdate();
+
+ screenEffect(0, 0, 0, 0);
+
+ _dat->close(0);
+
+ for (int animationIndex = 0; animationIndex < 12; ++animationIndex)
+ _gameSys->setAnimation(0, 0, animationIndex);
+
+ clearKeyStatus1(Common::KEYCODE_p);
+
+ _mouseClickState._left = false;
+ _mouseClickState._right = false;
+
+}
+
+void GnapEngine::checkGameKeys() {
+ if (isKeyStatus1(Common::KEYCODE_p)) {
+ clearKeyStatus1(Common::KEYCODE_p);
+ pauseGame();
+ updatePause();
+ }
+}
+
+void GnapEngine::startSoundTimerA(int timerIndex) {
+ _soundTimerIndexA = timerIndex;
+ _timers[timerIndex] = getRandom(50) + 100;
+}
+
+int GnapEngine::playSoundA() {
+ static const int kSoundIdsA[] = {
+ 0x93E, 0x93F, 0x941, 0x942, 0x943, 0x944,
+ 0x945, 0x946, 0x947, 0x948, 0x949
+ };
+
+ int soundId = -1;
+
+ if (!_timers[_soundTimerIndexA]) {
+ _timers[_soundTimerIndexA] = getRandom(50) + 100;
+ soundId = kSoundIdsA[getRandom(11)];
+ playSound(soundId | 0x10000, false);
+ }
+ return soundId;
+}
+
+void GnapEngine::startSoundTimerB(int timerIndex) {
+ _soundTimerIndexB = timerIndex;
+ _timers[timerIndex] = getRandom(50) + 150;
+}
+
+int GnapEngine::playSoundB() {
+ static const int kSoundIdsB[] = {
+ 0x93D, 0x929, 0x92A, 0x92B, 0x92C, 0x92D,
+ 0x92E, 0x92F, 0x930, 0x931, 0x932, 0x933,
+ 0x934, 0x935, 0x936, 0x937, 0x938, 0x939,
+ 0x93A
+ };
+
+ int soundId = -1;
+
+ if (!_timers[_soundTimerIndexB]) {
+ _timers[_soundTimerIndexB] = getRandom(50) + 150;
+ soundId = kSoundIdsB[getRandom(19)];
+ playSound(soundId | 0x10000, false);
+ }
+ return soundId;
+}
+
+void GnapEngine::startSoundTimerC(int timerIndex) {
+ _soundTimerIndexC = timerIndex;
+ _timers[timerIndex] = getRandom(50) + 150;
+}
+
+int GnapEngine::playSoundC() {
+ static const int kSoundIdsC[] = {
+ 0x918, 0x91F, 0x920, 0x922, 0x923, 0x924,
+ 0x926
+ };
+
+ int soundId = -1;
+
+ if (!_timers[_soundTimerIndexC]) {
+ _timers[_soundTimerIndexC] = getRandom(50) + 150;
+ soundId = kSoundIdsC[getRandom(7)] ;
+ playSound(soundId | 0x10000, false);
+ }
+ return soundId;
+}
+
+void GnapEngine::startIdleTimer(int timerIndex) {
+ _idleTimerIndex = timerIndex;
+ _timers[timerIndex] = 3000;
+}
+
+void GnapEngine::updateIdleTimer() {
+ if (!_timers[_idleTimerIndex]) {
+ _timers[_idleTimerIndex] = 3000;
+ _gameSys->insertSequence(0x1088B, 255, 0, 0, kSeqNone, 0, 0, 75);
+ }
+}
+
+void GnapEngine::screenEffect(int dir, byte r, byte g, byte b) {
+ int startVal = 0;
+ if (dir == 1)
+ startVal = 300;
+
+ for (int y = startVal; y < startVal + 300 && !_gameDone; y += 50) {
+ _gameSys->fillSurface(nullptr, 0, y, 800, 50, r, g, b);
+ _gameSys->fillSurface(nullptr, 0, 549 - y + 1, 800, 50, r, g, b);
+ gameUpdateTick();
+ _system->delayMillis(50);
+ }
+}
+
+bool GnapEngine::isKeyStatus1(int key) {
+ return _keyPressState[key] != 0;
+}
+
+bool GnapEngine::isKeyStatus2(int key) {
+ return _keyDownState[key] != 0;
+}
+
+void GnapEngine::clearKeyStatus1(int key) {
+ _keyPressState[key] = 0;
+ _keyDownState[key] = 0;
+}
+
+void GnapEngine::clearAllKeyStatus1() {
+ _keyStatus1[0] = 0;
+ _keyStatus1[1] = 0;
+ memset(_keyPressState, 0, sizeof(_keyPressState));
+ memset(_keyDownState, 0, sizeof(_keyDownState));
+}
+
+void GnapEngine::deleteSurface(Graphics::Surface **surface) {
+ if (surface && *surface) {
+ (*surface)->free();
+ delete *surface;
+ *surface = nullptr;
+ }
+}
+
+bool GnapEngine::testWalk(int animationIndex, int someStatus, int gridX1, int gridY1, int gridX2, int gridY2) {
+ if (_mouseClickState._left && someStatus == _gnap->_actionStatus) {
+ _isLeavingScene = false;
+ _gameSys->setAnimation(0, 0, animationIndex);
+ _gnap->_actionStatus = -1;
+ _plat->_actionStatus = -1;
+ _gnap->walkTo(Common::Point(gridX1, gridY1), -1, -1, 1);
+ _plat->walkTo(Common::Point(gridX2, gridY2), -1, -1, 1);
+ _mouseClickState._left = false;
+ return true;
+ }
+ return false;
+}
+
+void GnapEngine::doCallback(int callback) {
+ switch (callback) {
+ case 8:
+ case 10:
+ case 20:
+ _scene->updateAnimationsCb();
+ break;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+void GnapEngine::initGlobalSceneVars() {
+ // Shared by scenes 17 && 18
+ _s18GarbageCanPos = 8;
+
+ // Toy UFO
+ _toyUfoId = 0;
+ _toyUfoActionStatus = -1;
+ _toyUfoX = 0;
+ _toyUfoY = 50;
+}
+
+void GnapEngine::playSequences(int fullScreenSpriteId, int sequenceId1, int sequenceId2, int sequenceId3) {
+ setGrabCursorSprite(-1);
+ _gameSys->setAnimation(sequenceId2, _gnap->_id, 0);
+ _gameSys->insertSequence(sequenceId2, _gnap->_id,
+ makeRid(_gnap->_sequenceDatNum, _gnap->_sequenceId), _gnap->_id,
+ kSeqSyncWait, 0, 15 * (5 * _gnap->_pos.x - 25), 48 * (_gnap->_pos.y - 8));
+ _gnap->_sequenceId = sequenceId2;
+ _gnap->_sequenceDatNum = 0;
+ while (_gameSys->getAnimationStatus(0) != 2 && !_gameDone)
+ gameUpdateTick();
+ hideCursor();
+ addFullScreenSprite(fullScreenSpriteId, 255);
+ _gameSys->setAnimation(sequenceId1, 256, 0);
+ _gameSys->insertSequence(sequenceId1, 256, 0, 0, kSeqNone, 0, 0, 0);
+ while (_gameSys->getAnimationStatus(0) != 2 && !_gameDone)
+ gameUpdateTick();
+ _gameSys->setAnimation(sequenceId3, _gnap->_id, 0);
+ _gameSys->insertSequence(sequenceId3, _gnap->_id,
+ makeRid(_gnap->_sequenceDatNum, _gnap->_sequenceId), _gnap->_id,
+ kSeqSyncWait, 0, 15 * (5 * _gnap->_pos.x - 25), 48 * (_gnap->_pos.y - 8));
+ removeFullScreenSprite();
+ showCursor();
+ _gnap->_sequenceId = sequenceId3;
+}
+
+void GnapEngine::toyUfoSetStatus(int flagNum) {
+ clearFlag(kGFUnk16);
+ clearFlag(kGFJointTaken);
+ clearFlag(kGFUnk18);
+ clearFlag(kGFGroceryStoreHatTaken);
+ setFlag(flagNum);
+}
+
+int GnapEngine::toyUfoGetSequenceId() {
+ if (isFlag(kGFUnk16))
+ return 0x84E;
+ if (isFlag(kGFJointTaken))
+ return 0x84B;
+ if (isFlag(kGFUnk18))
+ return 0x84D;
+ if (isFlag(kGFGroceryStoreHatTaken))
+ return 0x84C;
+ return 0x84E;
+}
+
+bool GnapEngine::toyUfoCheckTimer() {
+ if (!isFlag(kGFGnapControlsToyUFO) || isFlag(kGFUnk18) || _timers[9] ||
+ _toyUfoSequenceId == 0x870 || _toyUfoSequenceId == 0x871 || _toyUfoSequenceId == 0x872 || _toyUfoSequenceId == 0x873)
+ return false;
+ _sceneDone = true;
+ _newSceneNum = 41;
+ return true;
+}
+
+void GnapEngine::toyUfoFlyTo(int destX, int destY, int minX, int maxX, int minY, int maxY, int animationIndex) {
+ GridStruct flyNodes[34];
+
+ if (destX == -1)
+ destX = _leftClickMouseX;
+
+ if (destY == -1)
+ destY = _leftClickMouseY;
+
+ int clippedDestX = CLIP(destX, minX, maxX);
+ int clippedDestY = CLIP(destY, minY, maxY);
+ int dirX = 0, dirY = 0; // 0, -1 or 1
+
+ if (clippedDestX != _toyUfoX)
+ dirX = (clippedDestX - _toyUfoX) / ABS(clippedDestX - _toyUfoX);
+
+ if (clippedDestY != _toyUfoY)
+ dirY = (clippedDestY - _toyUfoY) / ABS(clippedDestY - _toyUfoY);
+
+ int deltaX = ABS(clippedDestX - _toyUfoX);
+ int deltaY = ABS(clippedDestY - _toyUfoY);
+
+ int i = 0;
+ if (deltaY > deltaX) {
+ int flyDirYIncr = 32;
+ int gridDistY = deltaY / flyDirYIncr;
+ int curMove = 0;
+ while (curMove < deltaY && i < 34) {
+ if (gridDistY - 5 >= i) {
+ flyDirYIncr = MIN(36, 8 * i + 8);
+ } else {
+ flyDirYIncr = MAX(6, flyDirYIncr - 3);
+ }
+ curMove += flyDirYIncr;
+ flyNodes[i]._gridX1 = _toyUfoX + dirX * deltaX * curMove / deltaY;
+ flyNodes[i]._gridY1 = _toyUfoY + dirY * curMove;
+ ++i;
+ }
+ } else {
+ int flyDirXIncr = 36;
+ int gridDistX = deltaX / flyDirXIncr;
+ int curMove = 0;
+ while (curMove < deltaX && i < 34) {
+ if (gridDistX - 5 >= i) {
+ flyDirXIncr = MIN(38, 8 * i + 8);
+ } else {
+ flyDirXIncr = MAX(6, flyDirXIncr - 3);
+ }
+ curMove += flyDirXIncr;
+ flyNodes[i]._gridX1 = _toyUfoX + dirX * curMove;
+ flyNodes[i]._gridY1 = _toyUfoY + dirY * deltaY * curMove / deltaX;
+ ++i;
+ }
+ }
+
+ int nodesCount = i - 1;
+
+ _toyUfoX = clippedDestX;
+ _toyUfoY = clippedDestY;
+
+ if (nodesCount > 0) {
+ int seqId = 0;
+ if (isFlag(kGFUnk16))
+ seqId = 0x867;
+ else if (isFlag(kGFJointTaken))
+ seqId = 0x84F;
+ else if (isFlag(kGFUnk18))
+ seqId = 0x85F;
+ else if (isFlag(kGFGroceryStoreHatTaken))
+ seqId = 0x857;
+ else
+ error("Unhandled flag in GnapEngine::toyUfoFlyTo(): 0x%x", _gameFlags);
+ flyNodes[0]._sequenceId = seqId;
+ flyNodes[0]._id = 0;
+ _gameSys->insertSequence(seqId | 0x10000, 0,
+ _toyUfoSequenceId | 0x10000, _toyUfoId,
+ kSeqSyncWait, 0, flyNodes[0]._gridX1 - 365, flyNodes[0]._gridY1 - 128);
+ for (i = 1; i < nodesCount; ++i) {
+ flyNodes[i]._sequenceId = seqId + (i % 8);
+ flyNodes[i]._id = i;
+ _gameSys->insertSequence(flyNodes[i]._sequenceId | 0x10000, flyNodes[i]._id,
+ flyNodes[i - 1]._sequenceId | 0x10000, flyNodes[i - 1]._id,
+ kSeqSyncWait, 0,
+ flyNodes[i]._gridX1 - 365, flyNodes[i]._gridY1 - 128);
+ }
+
+ _toyUfoSequenceId = flyNodes[nodesCount - 1]._sequenceId;
+ _toyUfoId = flyNodes[nodesCount - 1]._id;
+
+ if (animationIndex >= 0)
+ _gameSys->setAnimation(_toyUfoSequenceId | 0x10000, _toyUfoId, animationIndex);
+
+ }
+}
+
+void GnapEngine::playMidi(const char *name) {
+ if (_music)
+ return;
+
+ _music = new MusicPlayer(name);
+ _music->playSMF(true);
+}
+
+void GnapEngine::stopMidi() {
+ if (_music) {
+ _music->stop();
+ delete _music;
+ _music = nullptr;
+ }
+}
+} // End of namespace Gnap
diff --git a/engines/gnap/gnap.h b/engines/gnap/gnap.h
new file mode 100644
index 0000000000..84c40e2969
--- /dev/null
+++ b/engines/gnap/gnap.h
@@ -0,0 +1,477 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 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 GNAP_GNAP_H
+#define GNAP_GNAP_H
+
+#include "common/array.h"
+#include "common/events.h"
+#include "common/file.h"
+#include "common/memstream.h"
+#include "common/random.h"
+#include "common/savefile.h"
+#include "common/serializer.h"
+#include "common/str.h"
+#include "common/substream.h"
+#include "common/system.h"
+#include "common/winexe.h"
+#include "common/winexe_pe.h"
+#include "engines/engine.h"
+#include "graphics/pixelformat.h"
+#include "graphics/wincursor.h"
+#include "graphics/fontman.h"
+#include "graphics/font.h"
+#include "graphics/fonts/ttf.h"
+
+#include "gnap/debugger.h"
+#include "gnap/resource.h"
+#include "gnap/scenes/scenecore.h"
+#include "gnap/character.h"
+#include "gnap/music.h"
+
+struct ADGameDescription;
+
+namespace Gnap {
+
+class DatManager;
+class SequenceResource;
+class SpriteResource;
+class GameSys;
+class SoundMan;
+class MusicPlayer;
+
+#define GNAP_SAVEGAME_VERSION 2
+
+struct MouseButtonState {
+ bool _left;
+ bool _right;
+ MouseButtonState() : _left(false), _right(false) {
+ }
+};
+
+struct Hotspot {
+ Common::Rect _rect;
+ uint16 _flags;
+
+ bool isPointInside(Common::Point pos) const {
+ return _rect.contains(pos);
+ }
+
+ bool isFlag(uint16 flag) const {
+ return (_flags & flag) != 0;
+ }
+
+ void clearRect() {
+ _rect = Common::Rect(0, 0, 0, 0);
+ }
+};
+
+const int kMaxTimers = 10;
+
+enum GnapDebugChannels {
+ kDebugBasic = 1 << 0,
+ kDebugMusic = 1 << 1
+};
+
+enum {
+ SF_NONE = 0x0000,
+ SF_LOOK_CURSOR = 0x0001,
+ SF_GRAB_CURSOR = 0x0002,
+ SF_TALK_CURSOR = 0x0004,
+ SF_PLAT_CURSOR = 0x0008,
+ SF_DISABLED = 0x0010,
+ SF_WALKABLE = 0x0020,
+ SF_EXIT_L_CURSOR = 0x0040,
+ SF_EXIT_R_CURSOR = 0x0080,
+ SF_EXIT_U_CURSOR = 0x0100,
+ SF_EXIT_D_CURSOR = 0x0200,
+ SF_EXIT_NW_CURSOR = 0x0400,
+ SF_EXIT_NE_CURSOR = 0x0800,
+ SF_EXIT_SW_CURSOR = 0x1000,
+ SF_EXIT_SE_CURSOR = 0x2000
+};
+
+enum {
+ LOOK_CURSOR = 0,
+ GRAB_CURSOR = 1,
+ TALK_CURSOR = 2,
+ PLAT_CURSOR = 3,
+ NOLOOK_CURSOR = 4,
+ NOGRAB_CURSOR = 5,
+ NOTALK_CURSOR = 6,
+ NOPLAT_CURSOR = 7,
+ EXIT_L_CURSOR = 8,
+ EXIT_R_CURSOR = 9,
+ EXIT_U_CURSOR = 10,
+ EXIT_D_CURSOR = 11,
+ EXIT_NE_CURSOR = 12,
+ EXIT_NW_CURSOR = 13,
+ EXIT_SE_CURSOR = 14,
+ EXIT_SW_CURSOR = 15,
+ WAIT_CURSOR = 16
+};
+
+enum {
+ kGSPullOutDevice = 0,
+ kGSPullOutDeviceNonWorking = 1,
+ kGSIdle = 2,
+ kGSBrainPulsating = 3,
+ kGSImpossible = 4,
+ kGSScratchingHead = 5,
+ kGSDeflect = 6,
+ kGSUseDevice = 7,
+ kGSMoan1 = 8,
+ kGSMoan2 = 9
+};
+
+enum {
+ kItemMagazine = 0,
+ kItemMud = 1,
+ kItemGrass = 2,
+ kItemDisguise = 3,
+ kItemNeedle = 4,
+ kItemTwig = 5,
+ kItemGas = 6,
+ kItemKeys = 7,
+ kItemDice = 8,
+ kItemTongs = 9,
+ kItemQuarter = 10,
+ kItemQuarterWithHole = 11,
+ kItemDiceQuarterHole = 12,
+ kItemWrench = 13,
+ kItemCowboyHat = 14,
+ kItemGroceryStoreHat = 15,
+ kItemBanana = 16,
+ kItemTickets = 17,
+ kItemPicture = 18,
+ kItemEmptyBucket = 19,
+ kItemBucketWithBeer = 20,
+ kItemBucketWithPill = 21,
+ kItemPill = 22,
+ kItemHorn = 23,
+ kItemJoint = 24,
+ kItemChickenBucket = 25,
+ kItemGum = 26,
+ kItemSpring = 27,
+ kItemLightbulb = 28,
+ kItemCereals = 29
+};
+
+enum {
+ kGFPlatypus = 0,
+ kGFMudTaken = 1,
+ kGFNeedleTaken = 2,
+ kGFTwigTaken = 3,
+ kGFUnk04 = 4,
+ kGFKeysTaken = 5,
+ kGFGrassTaken = 6,
+ kGFBarnPadlockOpen = 7,
+ kGFTruckFilledWithGas = 8,
+ kGFTruckKeysUsed = 9,
+ kGFPlatypusDisguised = 10,
+ kGFSceneFlag1 = 11,
+ kGFGnapControlsToyUFO = 12,
+ kGFUnk13 = 13, // Tongue Fight Won?
+ kGFUnk14 = 14,
+ kGFSpringTaken = 15,
+ kGFUnk16 = 16,
+ kGFJointTaken = 17,
+ kGFUnk18 = 18,
+ kGFGroceryStoreHatTaken = 19,
+ kGFPictureTaken = 20,
+ kGFUnk21 = 21,
+ kGFUnk22 = 22,
+ kGFUnk23 = 23,
+ kGFUnk24 = 24,
+ kGFUnk25 = 25,
+ kGFPlatypusTalkingToAssistant = 26,
+ kGFUnk27 = 27,
+ kGFUnk28 = 28,
+ kGFGasTaken = 29,
+ kGFUnk30 = 30,
+ kGFUnk31 = 31
+};
+
+struct GnapSavegameHeader {
+ uint8 _version;
+ Common::String _saveName;
+ Graphics::Surface *_thumbnail;
+ int _year, _month, _day;
+ int _hour, _minute;
+};
+
+class GnapEngine : public Engine {
+protected:
+ Common::Error run();
+ virtual bool hasFeature(EngineFeature f) const;
+public:
+ GnapEngine(OSystem *syst, const ADGameDescription *gd);
+ ~GnapEngine();
+private:
+ const ADGameDescription *_gameDescription;
+ Graphics::PixelFormat _pixelFormat;
+ int _loadGameSlot;
+
+public:
+ Common::RandomSource *_random;
+ Common::PEResources *_exe;
+
+ DatManager *_dat;
+ SpriteCache *_spriteCache;
+ SoundCache *_soundCache;
+ SequenceCache *_sequenceCache;
+ GameSys *_gameSys;
+ SoundMan *_soundMan;
+ Debugger *_debugger;
+ Scene *_scene;
+ PlayerGnap *_gnap;
+ PlayerPlat *_plat;
+ MusicPlayer *_music;
+ Graphics::Font *_font;
+
+ Common::MemoryWriteStreamDynamic *_tempThumbnail;
+
+ int _lastUpdateClock;
+ bool _gameDone;
+
+ byte _keyPressState[512];
+ byte _keyDownState[512];
+
+ bool _isPaused;
+ Graphics::Surface *_pauseSprite;
+ int _timers[kMaxTimers], _savedTimers[kMaxTimers];
+
+ MouseButtonState _mouseButtonState;
+ MouseButtonState _mouseClickState;
+
+ uint32 _keyStatus1[2];
+
+ bool _sceneSavegameLoaded, _wasSavegameLoaded;
+
+ Graphics::Surface *_backgroundSurface;
+ int _prevSceneNum, _currentSceneNum, _newSceneNum;
+ bool _sceneDone, _sceneWaiting;
+
+ uint32 _inventory, _gameFlags;
+
+ Hotspot _hotspots[20];
+ Common::Point _hotspotsWalkPos[20];
+ int _hotspotsCount;
+ int _sceneClickedHotspot;
+
+ bool _isWaiting;
+ bool _isLeavingScene;
+
+ bool _isStockDatLoaded;
+
+ int _newCursorValue, _cursorValue;
+
+ int _verbCursor, _cursorIndex;
+ Common::Point _mousePos;
+ int _leftClickMouseX, _leftClickMouseY;
+
+ Graphics::Surface *_grabCursorSprite;
+ int _currGrabCursorX, _currGrabCursorY;
+ int _grabCursorSpriteIndex, _newGrabCursorSpriteIndex;
+
+ Graphics::Surface *_fullScreenSprite;
+ int _fullScreenSpriteId;
+
+ int _deviceX1, _deviceY1, _deviceX2, _deviceY2;
+
+ int _soundTimerIndexA;
+ int _soundTimerIndexB;
+ int _soundTimerIndexC;
+ int _idleTimerIndex;
+
+ void updateEvents();
+ void gameUpdateTick();
+ void saveTimers();
+ void restoreTimers();
+
+ void pauseGame();
+ void resumeGame();
+ void updatePause();
+
+ int getRandom(int max);
+
+ int readSavegameDescription(int savegameNum, Common::String &description);
+ int loadSavegame(int savegameNum);
+ Common::Error saveGameState(int slot, const Common::String &desc);
+ Common::Error loadGameState(int slot);
+ Common::String generateSaveName(int slot);
+ void synchronize(Common::Serializer &s);
+ void writeSavegameHeader(Common::OutSaveFile *out, GnapSavegameHeader &header);
+ static bool readSavegameHeader(Common::InSaveFile *in, GnapSavegameHeader &header);
+
+ void delayTicks(int val, int idx, bool updateCursor);
+ void delayTicksA(int val, int idx);
+ void delayTicksCursor(int val);
+
+ void setHotspot(int index, int16 x1, int16 y1, int16 x2, int16 y2, uint16 flags = SF_NONE,
+ int16 walkX = -1, int16 walkY = -1);
+ int getHotspotIndexAtPos(Common::Point pos);
+ void updateCursorByHotspot();
+ int getClickedHotspotId();
+
+ int getInventoryItemSpriteNum(int index);
+
+ void updateMouseCursor();
+ void setVerbCursor(int verbCursor);
+ void setCursor(int cursorIndex);
+ void showCursor();
+ void hideCursor();
+
+ void setGrabCursorSprite(int index);
+ void createGrabCursorSprite(int spriteId);
+ void freeGrabCursorSprite();
+ void updateGrabCursorSprite(int x, int y);
+
+ void invClear();
+ void invAdd(int itemId);
+ void invRemove(int itemId);
+ bool invHas(int itemId);
+
+ void clearFlags();
+ void setFlag(int num);
+ void clearFlag(int num);
+ bool isFlag(int num);
+
+ Graphics::Surface *addFullScreenSprite(int resourceId, int id);
+ void removeFullScreenSprite();
+ void showFullScreenSprite(int resourceId);
+
+ void queueInsertDeviceIcon();
+ void insertDeviceIconActive();
+ void removeDeviceIconActive();
+ void setDeviceHotspot(int hotspotIndex, int x1, int y1, int x2, int y2);
+
+ int getSequenceTotalDuration(int resourceId);
+
+ bool isSoundPlaying(int resourceId);
+ void playSound(int resourceId, bool looping);
+ void stopSound(int resourceId);
+ void setSoundVolume(int resourceId, int volume);
+
+ void updateTimers();
+
+ void initGameFlags(int num);
+ void loadStockDat();
+
+ void mainLoop();
+ void initScene();
+ void endSceneInit();
+ void afterScene();
+
+ int initSceneLogic();
+ void runSceneLogic();
+
+ void checkGameKeys();
+
+ void startSoundTimerA(int timerIndex);
+ int playSoundA();
+ void startSoundTimerB(int timerIndex);
+ int playSoundB();
+ void startSoundTimerC(int timerIndex);
+ int playSoundC();
+ void startIdleTimer(int timerIndex);
+ void updateIdleTimer();
+
+ void screenEffect(int dir, byte r, byte g, byte b);
+
+ bool isKeyStatus1(int key);
+ bool isKeyStatus2(int key);
+ void clearKeyStatus1(int key);
+ void clearAllKeyStatus1();
+
+ void deleteSurface(Graphics::Surface **surface);
+
+ // Menu
+ int _menuStatus;
+ int _menuSpritesIndex;
+ bool _menuDone;
+ Graphics::Surface *_menuBackgroundSurface;
+ Graphics::Surface *_menuQuitQuerySprite;
+ Graphics::Surface *_largeSprite;
+ Graphics::Surface *_menuSaveLoadSprite;
+ Graphics::Surface *_menuSprite2;
+ Graphics::Surface *_menuSprite1;
+ char _savegameFilenames[7][30];
+ Graphics::Surface *_savegameSprites[7];
+ Graphics::Surface *_spriteHandle;
+ Graphics::Surface *_cursorSprite;
+ int _menuInventoryIndices[30];
+ Graphics::Surface *_menuInventorySprites[30];
+ int _savegameIndex;
+ void createMenuSprite();
+ void freeMenuSprite();
+ void initMenuHotspots1();
+ void initMenuHotspots2();
+ void initMenuQuitQueryHotspots();
+ void initSaveLoadHotspots();
+ void drawInventoryFrames();
+ void insertInventorySprites();
+ void removeInventorySprites();
+ void runMenu();
+ void updateMenuStatusInventory();
+ void updateMenuStatusMainMenu();
+ void updateMenuStatusSaveGame();
+ void updateMenuStatusLoadGame();
+ void updateMenuStatusQueryQuit();
+
+ // Grid common
+ int _gridMinX, _gridMinY;
+ int _gridMaxX, _gridMaxY;
+ bool isPointBlocked(int gridX, int gridY);
+ bool isPointBlocked(Common::Point gridPos);
+ void initSceneGrid(int gridMinX, int gridMinY, int gridMaxX, int gridMaxY);
+ bool testWalk(int animationIndex, int someStatus, int gridX1, int gridY1, int gridX2, int gridY2);
+
+ // Gnap
+ void doCallback(int callback);
+
+ // Scenes
+ int _toyUfoNextSequenceId, _toyUfoSequenceId;
+ int _toyUfoId;
+ int _toyUfoActionStatus;
+ int _toyUfoX;
+ int _toyUfoY;
+
+ void initGlobalSceneVars();
+ void playSequences(int fullScreenSpriteId, int sequenceId1, int sequenceId2, int sequenceId3);
+
+ // Shared by scenes 17 & 18
+ int _s18GarbageCanPos;
+
+ // Scene 4x
+ void toyUfoSetStatus(int flagNum);
+ int toyUfoGetSequenceId();
+ bool toyUfoCheckTimer();
+ void toyUfoFlyTo(int destX, int destY, int minX, int maxX, int minY, int maxY, int animationIndex);
+
+ void playMidi(const char *name);
+ void stopMidi();
+};
+
+} // End of namespace Gnap
+
+#endif // GNAP_GNAP_H
diff --git a/engines/gnap/grid.cpp b/engines/gnap/grid.cpp
new file mode 100644
index 0000000000..aa6da71395
--- /dev/null
+++ b/engines/gnap/grid.cpp
@@ -0,0 +1,995 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can 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 "gnap/gnap.h"
+#include "gnap/datarchive.h"
+#include "gnap/gamesys.h"
+#include "gnap/resource.h"
+
+namespace Gnap {
+
+void GnapEngine::initSceneGrid(int gridMinX, int gridMinY, int gridMaxX, int gridMaxY) {
+ _gridMinX = gridMinX;
+ _gridMinY = gridMinY;
+ _gridMaxX = gridMaxX;
+ _gridMaxY = gridMaxY;
+ _gnap->_gridX = 410 - gridMinX;
+ _gnap->_gridY = 450 - gridMinY;
+ _plat->_gridX = 396 - gridMinX;
+ _plat->_gridY = 347 - gridMinY;
+}
+
+bool GnapEngine::isPointBlocked(Common::Point gridPos) {
+ return isPointBlocked(gridPos.x, gridPos.y);
+}
+
+bool GnapEngine::isPointBlocked(int gridX, int gridY) {
+
+ if (gridX < 0 || gridX >= _gridMaxX || gridY < 0 || gridY >= _gridMaxY)
+ return true;
+
+ if ((_gnap->_pos == Common::Point(gridX, gridY)) || (_plat->_pos == Common::Point(gridX, gridY)))
+ return true;
+
+ Common::Point pos = Common::Point(_gridMinX + 75 * gridX, _gridMinY + 48 * gridY);
+
+ for (int i = 0; i < _hotspotsCount; ++i) {
+ if (_hotspots[i].isPointInside(pos) && !(_hotspots[i]._flags & SF_WALKABLE))
+ return true;
+ }
+
+ return false;
+}
+
+/******************************************************************************/
+
+int PlayerGnap::getWalkStopSequenceId(int deltaX, int deltaY) {
+ static const int gnapWalkStopSequenceIds[9] = {
+ 0x7BC, 0x7BA, 0x7BA,
+ 0x7BC, 0x000, 0x7BA,
+ 0x7BB, 0x7B9, 0x7B9
+ };
+
+ int id = 3 * (deltaX + 1) + deltaY + 1;
+ assert (id >= 0 && id < 9 );
+ return gnapWalkStopSequenceIds[id];
+}
+
+Facing PlayerGnap::getWalkFacing(int deltaX, int deltaY) {
+ static const Facing gnapWalkFacings[9] = {
+ kDirUpLeft, kDirBottomLeft, kDirBottomLeft,
+ kDirUpLeft, kDirIdleLeft, kDirBottomLeft,
+ kDirUpRight, kDirBottomRight, kDirBottomRight
+ };
+
+ int id = 3 * (deltaX + 1) + deltaY + 1;
+ assert (id >= 0 && id < 9 );
+ return gnapWalkFacings[id];
+}
+
+bool PlayerGnap::findPath1(int gridX, int gridY, int index) {
+ _walkNodesCount = index;
+ _walkDirXIncr = 0;
+ _walkDirYIncr = 0;
+ _walkDeltaX = ABS(_walkDestX - gridX);
+ _walkDeltaY = ABS(_walkDestY - gridY);
+
+ if (_walkDeltaX)
+ _walkDirX = (_walkDestX - gridX) / _walkDeltaX;
+ else
+ _walkDirX = 0;
+
+ if (_walkDeltaY)
+ _walkDirY = (_walkDestY - gridY) / _walkDeltaY;
+ else
+ _walkDirY = 0;
+
+ while (_walkDirXIncr < _walkDeltaX && _walkDirYIncr < _walkDeltaY) {
+ _walkNodes[_walkNodesCount]._gridX1 = gridX + _walkDirX * _walkDirXIncr;
+ _walkNodes[_walkNodesCount]._gridY1 = gridY + _walkDirY * _walkDirYIncr;
+ if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirXIncr;
+ ++_walkDirYIncr;
+ } else if (_walkDeltaY - _walkDirYIncr > _walkDeltaX - _walkDirXIncr) {
+ if (!_vm->isPointBlocked(_walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = 0;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirYIncr;
+ } else if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = 0;
+ ++_walkDirXIncr;
+ } else
+ return false;
+ } else {
+ if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = 0;
+ ++_walkDirXIncr;
+ } else if (!_vm->isPointBlocked(_walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = 0;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirYIncr;
+ } else
+ return false;
+ }
+ ++_walkNodesCount;
+ }
+
+ while (_walkDirXIncr < _walkDeltaX) {
+ _walkNodes[_walkNodesCount]._gridX1 = gridX + _walkDirX * _walkDirXIncr;
+ _walkNodes[_walkNodesCount]._gridY1 = _walkDestY;
+ if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkDestY)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = 0;
+ ++_walkDirXIncr;
+ ++_walkNodesCount;
+ } else
+ return false;
+ }
+
+ while (_walkDirYIncr < _walkDeltaY) {
+ _walkNodes[_walkNodesCount]._gridX1 = _walkDestX;
+ _walkNodes[_walkNodesCount]._gridY1 = gridY + _walkDirY * _walkDirYIncr;
+ if (!_vm->isPointBlocked(_walkDestX, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = 0;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirYIncr;
+ ++_walkNodesCount;
+ } else
+ return false;
+ }
+
+ return true;
+}
+
+bool PlayerGnap::findPath2(int gridX, int gridY, int index) {
+ _walkNodesCount = index;
+ _walkDirXIncr = 0;
+ _walkDirYIncr = 0;
+ _walkDeltaX = ABS(_walkDestX - gridX);
+ _walkDeltaY = ABS(_walkDestY - gridY);
+
+ if (_walkDeltaX)
+ _walkDirX = (_walkDestX - gridX) / _walkDeltaX;
+ else
+ _walkDirX = 0;
+
+ if (_walkDeltaY)
+ _walkDirY = (_walkDestY - gridY) / _walkDeltaY;
+ else
+ _walkDirY = 0;
+
+ while (_walkDeltaY < _walkDeltaX - _walkDirXIncr) {
+ _walkNodes[_walkNodesCount]._gridX1 = gridX + _walkDirX * _walkDirXIncr;
+ _walkNodes[_walkNodesCount]._gridY1 = gridY;
+ if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, gridY)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = 0;
+ ++_walkDirXIncr;
+ ++_walkNodesCount;
+ } else
+ return false;
+ }
+
+ while (_walkDeltaX < _walkDeltaY - _walkDirYIncr) {
+ _walkNodes[_walkNodesCount]._gridX1 = gridX;
+ _walkNodes[_walkNodesCount]._gridY1 = gridY + _walkDirY * _walkDirYIncr;
+ if (!_vm->isPointBlocked(gridX, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = 0;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirYIncr;
+ ++_walkNodesCount;
+ } else
+ return false;
+ }
+
+ while (_walkDirXIncr < _walkDeltaX && _walkDirYIncr < _walkDeltaY) {
+ _walkNodes[_walkNodesCount]._gridX1 = gridX + _walkDirX * _walkDirXIncr;
+ _walkNodes[_walkNodesCount]._gridY1 = gridY + _walkDirY * _walkDirYIncr;
+ if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirXIncr;
+ ++_walkDirYIncr;
+ } else if (_walkDeltaY - _walkDirYIncr > _walkDeltaX - _walkDirXIncr) {
+ if (!_vm->isPointBlocked(_walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = 0;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirYIncr;
+ } else if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = 0;
+ ++_walkDirXIncr;
+ } else
+ return false;
+ } else {
+ if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = 0;
+ ++_walkDirXIncr;
+ } else if (!_vm->isPointBlocked(_walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = 0;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirYIncr;
+ } else
+ return false;
+ }
+ ++_walkNodesCount;
+ }
+
+ while (_walkDirXIncr < _walkDeltaX) {
+ _walkNodes[_walkNodesCount]._gridX1 = gridX + _walkDirX * _walkDirXIncr;
+ _walkNodes[_walkNodesCount]._gridY1 = _walkDestY;
+ if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkDestY)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = 0;
+ ++_walkDirXIncr;
+ ++_walkNodesCount;
+ } else
+ return false;
+ }
+
+ while (_walkDirYIncr < _walkDeltaY) {
+ _walkNodes[_walkNodesCount]._gridX1 = _walkDestX;
+ _walkNodes[_walkNodesCount]._gridY1 = gridY + _walkDirY * _walkDirYIncr;
+ if (!_vm->isPointBlocked(_walkDestX, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = 0;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirYIncr;
+ ++_walkNodesCount;
+ } else
+ return false;
+ }
+
+ return true;
+}
+
+bool PlayerGnap::findPath3(int gridX, int gridY) {
+ int gridIncr = 1;
+ bool done = false;
+
+ while (!done && gridIncr < _vm->_gridMaxX) {
+ if (!_vm->isPointBlocked(gridX + gridIncr, gridY) && findPath1(gridX + gridIncr, gridY, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = gridX + i;
+ _walkNodes[i]._gridY1 = gridY;
+ _walkNodes[i]._deltaX = 1;
+ _walkNodes[i]._deltaY = 0;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(gridX - gridIncr, gridY) && findPath1(gridX - gridIncr, gridY, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = gridX - i;
+ _walkNodes[i]._gridY1 = gridY;
+ _walkNodes[i]._deltaX = -1;
+ _walkNodes[i]._deltaY = 0;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(gridX, gridY + gridIncr) && findPath1(gridX, gridY + gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = gridX;
+ _walkNodes[i]._gridY1 = gridY + i;
+ _walkNodes[i]._deltaX = 0;
+ _walkNodes[i]._deltaY = 1;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(gridX, gridY - gridIncr) && findPath1(gridX, gridY - gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = gridX;
+ _walkNodes[i]._gridY1 = gridY - i;
+ _walkNodes[i]._deltaX = 0;
+ _walkNodes[i]._deltaY = -1;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(gridX + gridIncr, gridY + gridIncr) && findPath1(gridX + gridIncr, gridY + gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = gridX + i;
+ _walkNodes[i]._gridY1 = gridY + i;
+ _walkNodes[i]._deltaX = 1;
+ _walkNodes[i]._deltaY = 1;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(gridX - gridIncr, gridY + gridIncr) && findPath1(gridX - gridIncr, gridY + gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = gridX - i;
+ _walkNodes[i]._gridY1 = gridY + i;
+ _walkNodes[i]._deltaX = -1;
+ _walkNodes[i]._deltaY = 1;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(gridX + gridIncr, gridY - gridIncr) && findPath1(gridX + gridIncr, gridY - gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = gridX + i;
+ _walkNodes[i]._gridY1 = gridY - i;
+ _walkNodes[i]._deltaX = 1;
+ _walkNodes[i]._deltaY = -1;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(gridX - gridIncr, gridY - gridIncr) && findPath1(gridX - gridIncr, gridY - gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = gridX - i;
+ _walkNodes[i]._gridY1 = gridY - i;
+ _walkNodes[i]._deltaX = -1;
+ _walkNodes[i]._deltaY = -1;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(gridX + gridIncr, gridY) && findPath2(gridX + gridIncr, gridY, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = gridX + i;
+ _walkNodes[i]._gridY1 = gridY;
+ _walkNodes[i]._deltaX = 1;
+ _walkNodes[i]._deltaY = 0;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(gridX - gridIncr, gridY) && findPath2(gridX - gridIncr, gridY, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = gridX - i;
+ _walkNodes[i]._gridY1 = gridY;
+ _walkNodes[i]._deltaX = -1;
+ _walkNodes[i]._deltaY = 0;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(gridX, gridY + gridIncr) && findPath2(gridX, gridY + gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = gridX;
+ _walkNodes[i]._gridY1 = gridY + i;
+ _walkNodes[i]._deltaX = 0;
+ _walkNodes[i]._deltaY = 1;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(gridX, gridY - gridIncr) && findPath2(gridX, gridY - gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = gridX;
+ _walkNodes[i]._gridY1 = gridY - i;
+ _walkNodes[i]._deltaX = 0;
+ _walkNodes[i]._deltaY = -1;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(gridX + gridIncr, gridY + gridIncr) && findPath2(gridX + gridIncr, gridY + gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = gridX + i;
+ _walkNodes[i]._gridY1 = gridY + i;
+ _walkNodes[i]._deltaX = 1;
+ _walkNodes[i]._deltaY = 1;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(gridX - gridIncr, gridY + gridIncr) && findPath2(gridX - gridIncr, gridY + gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = gridX - i;
+ _walkNodes[i]._gridY1 = gridY + i;
+ _walkNodes[i]._deltaX = -1;
+ _walkNodes[i]._deltaY = 1;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(gridX + gridIncr, gridY - gridIncr) && findPath2(gridX + gridIncr, gridY - gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = gridX + i;
+ _walkNodes[i]._gridY1 = gridY - i;
+ _walkNodes[i]._deltaX = 1;
+ _walkNodes[i]._deltaY = -1;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(gridX - gridIncr, gridY - gridIncr) && findPath2(gridX - gridIncr, gridY - gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = gridX - i;
+ _walkNodes[i]._gridY1 = gridY - i;
+ _walkNodes[i]._deltaX = -1;
+ _walkNodes[i]._deltaY = -1;
+ }
+ done = true;
+ break;
+ }
+ ++gridIncr;
+ }
+
+ return done;
+}
+
+bool PlayerGnap::findPath4(int gridX, int gridY) {
+ bool result = false;
+
+ _walkNodesCount = 0;
+ _walkDirXIncr = 0;
+ _walkDirYIncr = 0;
+ _walkDeltaX = ABS(_walkDestX - gridX);
+ _walkDeltaY = ABS(_walkDestY - gridY);
+
+ if (_walkDeltaX)
+ _walkDirX = (_walkDestX - gridX) / _walkDeltaX;
+ else
+ _walkDirX = 0;
+
+ if (_walkDeltaY)
+ _walkDirY = (_walkDestY - gridY) / _walkDeltaY;
+ else
+ _walkDirY = 0;
+
+ while (_walkDirXIncr < _walkDeltaX && _walkDirYIncr < _walkDeltaY) {
+ _walkNodes[_walkNodesCount]._gridX1 = gridX + _walkDirX * _walkDirXIncr;
+ _walkNodes[_walkNodesCount]._gridY1 = gridY + _walkDirY * _walkDirYIncr;
+ if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirXIncr;
+ ++_walkDirYIncr;
+ } else if (_walkDeltaY - _walkDirYIncr > _walkDeltaX - _walkDirXIncr) {
+ if (!_vm->isPointBlocked(_walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = 0;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirYIncr;
+ } else if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = 0;
+ ++_walkDirXIncr;
+ } else {
+ _walkDeltaX = _walkDirXIncr;
+ _walkDeltaY = _walkDirYIncr;
+ --_walkNodesCount;
+ }
+ } else {
+ if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = 0;
+ ++_walkDirXIncr;
+ } else if (!_vm->isPointBlocked(_walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = 0;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirYIncr;
+ } else {
+ _walkDeltaX = _walkDirXIncr;
+ _walkDeltaY = _walkDirYIncr;
+ --_walkNodesCount;
+ }
+ }
+ ++_walkNodesCount;
+ }
+
+ while (_walkDirXIncr < _walkDeltaX) {
+ _walkNodes[_walkNodesCount]._gridX1 = gridX + _walkDirX * _walkDirXIncr;
+ _walkNodes[_walkNodesCount]._gridY1 = _walkDestY;
+ if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkDestY)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = 0;
+ ++_walkDirXIncr;
+ ++_walkNodesCount;
+ } else {
+ _walkDeltaX = _walkDirXIncr;
+ }
+ }
+
+ while (_walkDirYIncr < _walkDeltaY) {
+ _walkNodes[_walkNodesCount]._gridX1 = _walkDestX;
+ _walkNodes[_walkNodesCount]._gridY1 = gridY + _walkDirY * _walkDirYIncr;
+ if (!_vm->isPointBlocked(_walkDestX, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = 0;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirYIncr;
+ ++_walkNodesCount;
+ } else {
+ _walkDeltaY = _walkDirYIncr;
+ }
+ }
+
+ if (gridX + _walkDirX * _walkDirXIncr != _walkDestX || gridY + _walkDirY * _walkDirYIncr != _walkDestY) {
+ _walkDestX = gridX + _walkDirX * _walkDirXIncr;
+ _walkDestY = gridY + _walkDirY * _walkDirYIncr;
+ result = false;
+ } else {
+ result = true;
+ }
+
+ return result;
+}
+
+/******************************************************************************/
+
+bool PlayerPlat::findPath1(int gridX, int gridY, int index) {
+ _walkNodesCount = index;
+ _walkDirXIncr = 0;
+ _walkDirYIncr = 0;
+ _walkDeltaX = ABS(_walkDestX - gridX);
+ _walkDeltaY = ABS(_walkDestY - gridY);
+
+ if (_walkDeltaX)
+ _walkDirX = (_walkDestX - gridX) / _walkDeltaX;
+ else
+ _walkDirX = 0;
+
+ if (_walkDeltaY)
+ _walkDirY = (_walkDestY - gridY) / _walkDeltaY;
+ else
+ _walkDirY = 0;
+
+ while (_walkDirXIncr < _walkDeltaX && _walkDirYIncr < _walkDeltaY) {
+ _walkNodes[_walkNodesCount]._gridX1 = gridX + _walkDirX * _walkDirXIncr;
+ _walkNodes[_walkNodesCount]._gridY1 = gridY + _walkDirY * _walkDirYIncr;
+ if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirXIncr;
+ ++_walkDirYIncr;
+ } else if (_walkDeltaY - _walkDirYIncr > _walkDeltaX - _walkDirXIncr) {
+ if (!_vm->isPointBlocked(_walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = 0;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirYIncr;
+ } else if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = 0;
+ ++_walkDirXIncr;
+ } else
+ return false;
+ } else {
+ if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = 0;
+ ++_walkDirXIncr;
+ } else if (!_vm->isPointBlocked(_walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = 0;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirYIncr;
+ } else
+ return false;
+ }
+ ++_walkNodesCount;
+ }
+
+ while (_walkDirXIncr < _walkDeltaX) {
+ _walkNodes[_walkNodesCount]._gridX1 = gridX + _walkDirX * _walkDirXIncr;
+ _walkNodes[_walkNodesCount]._gridY1 = _walkDestY;
+ if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkDestY)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = 0;
+ ++_walkDirXIncr;
+ ++_walkNodesCount;
+ } else
+ return false;
+ }
+
+ while (_walkDirYIncr < _walkDeltaY) {
+ _walkNodes[_walkNodesCount]._gridX1 = _walkDestX;
+ _walkNodes[_walkNodesCount]._gridY1 = gridY + _walkDirY * _walkDirYIncr;
+ if (!_vm->isPointBlocked(_walkDestX, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = 0;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirYIncr;
+ ++_walkNodesCount;
+ } else
+ return false;
+ }
+
+ return true;
+}
+
+bool PlayerPlat::findPath2(int gridX, int gridY, int index) {
+ _walkNodesCount = index;
+ _walkDirXIncr = 0;
+ _walkDirYIncr = 0;
+ _walkDeltaX = ABS(_walkDestX - gridX);
+ _walkDeltaY = ABS(_walkDestY - gridY);
+
+ if (_walkDeltaX)
+ _walkDirX = (_walkDestX - gridX) / _walkDeltaX;
+ else
+ _walkDirX = 0;
+
+ if (_walkDeltaY)
+ _walkDirY = (_walkDestY - gridY) / _walkDeltaY;
+ else
+ _walkDirY = 0;
+
+ while (_walkDeltaY < _walkDeltaX - _walkDirXIncr) {
+ _walkNodes[_walkNodesCount]._gridX1 = gridX + _walkDirX * _walkDirXIncr;
+ _walkNodes[_walkNodesCount]._gridY1 = gridY;
+ if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, gridY)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = 0;
+ ++_walkDirXIncr;
+ ++_walkNodesCount;
+ } else
+ return false;
+ }
+
+ while (_walkDeltaX < _walkDeltaY - _walkDirYIncr) {
+ _walkNodes[_walkNodesCount]._gridX1 = gridX;
+ _walkNodes[_walkNodesCount]._gridY1 = gridY + _walkDirY * _walkDirYIncr;
+ if (!_vm->isPointBlocked(gridX, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = 0;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirYIncr;
+ ++_walkNodesCount;
+ } else
+ return false;
+ }
+
+ while (_walkDirXIncr < _walkDeltaX && _walkDirYIncr < _walkDeltaY) {
+ _walkNodes[_walkNodesCount]._gridX1 = gridX + _walkDirX * _walkDirXIncr;
+ _walkNodes[_walkNodesCount]._gridY1 = gridY + _walkDirY * _walkDirYIncr;
+ if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirXIncr;
+ ++_walkDirYIncr;
+ } else if (_walkDeltaY - _walkDirYIncr > _walkDeltaX - _walkDirXIncr) {
+ if (!_vm->isPointBlocked(_walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = 0;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirYIncr;
+ } else if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = 0;
+ ++_walkDirXIncr;
+ } else
+ return false;
+ } else {
+ if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = 0;
+ ++_walkDirXIncr;
+ } else if (!_vm->isPointBlocked(_walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = 0;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirYIncr;
+ } else
+ return false;
+ }
+ ++_walkNodesCount;
+ }
+
+ while (_walkDirXIncr < _walkDeltaX) {
+ _walkNodes[_walkNodesCount]._gridX1 = gridX + _walkDirX * _walkDirXIncr;
+ _walkNodes[_walkNodesCount]._gridY1 = _walkDestY;
+ if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkDestY)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = 0;
+ ++_walkDirXIncr;
+ ++_walkNodesCount;
+ } else
+ return false;
+ }
+
+ while (_walkDirYIncr < _walkDeltaY) {
+ _walkNodes[_walkNodesCount]._gridX1 = _walkDestX;
+ _walkNodes[_walkNodesCount]._gridY1 = gridY + _walkDirY * _walkDirYIncr;
+ if (!_vm->isPointBlocked(_walkDestX, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = 0;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirYIncr;
+ ++_walkNodesCount;
+ } else
+ return false;
+ }
+
+ return true;
+}
+
+bool PlayerPlat::findPath3(int gridX, int gridY) {
+ int gridIncr = 1;
+ bool done = false;
+
+ while (!done && gridIncr < _vm->_gridMaxX) {
+ if (!_vm->isPointBlocked(_pos.x + gridIncr, _pos.y) && findPath1(_pos.x + gridIncr, _pos.y, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = _pos.x + i;
+ _walkNodes[i]._gridY1 = _pos.y;
+ _walkNodes[i]._deltaX = 1;
+ _walkNodes[i]._deltaY = 0;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(_pos.x - gridIncr, _pos.y) && findPath1(_pos.x - gridIncr, _pos.y, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = _pos.x - i;
+ _walkNodes[i]._gridY1 = _pos.y;
+ _walkNodes[i]._deltaX = -1;
+ _walkNodes[i]._deltaY = 0;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(_pos.x, _pos.y + gridIncr) && findPath1(_pos.x, _pos.y + gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = _pos.x;
+ _walkNodes[i]._gridY1 = _pos.y + i;
+ _walkNodes[i]._deltaX = 0;
+ _walkNodes[i]._deltaY = 1;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(_pos.x, _pos.y - gridIncr) && findPath1(_pos.x, _pos.y - gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = _pos.x;
+ _walkNodes[i]._gridY1 = _pos.y - i;
+ _walkNodes[i]._deltaX = 0;
+ _walkNodes[i]._deltaY = -1;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(_pos.x + gridIncr, _pos.y + gridIncr) && findPath1(_pos.x + gridIncr, _pos.y + gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = _pos.x + i;
+ _walkNodes[i]._gridY1 = _pos.y + i;
+ _walkNodes[i]._deltaX = 1;
+ _walkNodes[i]._deltaY = 1;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(_pos.x - gridIncr, _pos.y + gridIncr) && findPath1(_pos.x - gridIncr, _pos.y + gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = _pos.x - i;
+ _walkNodes[i]._gridY1 = _pos.y + i;
+ _walkNodes[i]._deltaX = -1;
+ _walkNodes[i]._deltaY = 1;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(_pos.x + gridIncr, _pos.y - gridIncr) && findPath1(_pos.x + gridIncr, _pos.y - gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = _pos.x + i;
+ _walkNodes[i]._gridY1 = _pos.y - i;
+ _walkNodes[i]._deltaX = 1;
+ _walkNodes[i]._deltaY = -1;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(_pos.x - gridIncr, _pos.y - gridIncr) && findPath1(_pos.x - gridIncr, _pos.y - gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = _pos.x - i;
+ _walkNodes[i]._gridY1 = _pos.y - i;
+ _walkNodes[i]._deltaX = -1;
+ _walkNodes[i]._deltaY = -1;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(_pos.x + gridIncr, _pos.y) && findPath2(_pos.x + gridIncr, _pos.y, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = _pos.x + i;
+ _walkNodes[i]._gridY1 = _pos.y;
+ _walkNodes[i]._deltaX = 1;
+ _walkNodes[i]._deltaY = 0;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(_pos.x - gridIncr, _pos.y) && findPath2(_pos.x - gridIncr, _pos.y, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = _pos.x - i;
+ _walkNodes[i]._gridY1 = _pos.y;
+ _walkNodes[i]._deltaX = -1;
+ _walkNodes[i]._deltaY = 0;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(_pos.x, _pos.y + gridIncr) && findPath2(_pos.x, _pos.y + gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = _pos.x;
+ _walkNodes[i]._gridY1 = _pos.y + i;
+ _walkNodes[i]._deltaX = 0;
+ _walkNodes[i]._deltaY = 1;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(_pos.x, _pos.y - gridIncr) && findPath2(_pos.x, _pos.y - gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = _pos.x;
+ _walkNodes[i]._gridY1 = _pos.y - i;
+ _walkNodes[i]._deltaX = 0;
+ _walkNodes[i]._deltaY = -1;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(_pos.x + gridIncr, _pos.y + gridIncr) && findPath2(_pos.x + gridIncr, _pos.y + gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = _pos.x + i;
+ _walkNodes[i]._gridY1 = _pos.y + i;
+ _walkNodes[i]._deltaX = 1;
+ _walkNodes[i]._deltaY = 1;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(_pos.x - gridIncr, _pos.y + gridIncr) && findPath2(_pos.x - gridIncr, _pos.y + gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = _pos.x - i;
+ _walkNodes[i]._gridY1 = _pos.y + i;
+ _walkNodes[i]._deltaX = -1;
+ _walkNodes[i]._deltaY = 1;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(_pos.x + gridIncr, _pos.y - gridIncr) && findPath2(_pos.x + gridIncr, _pos.y - gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = _pos.x + i;
+ _walkNodes[i]._gridY1 = _pos.y - i;
+ _walkNodes[i]._deltaX = 1;
+ _walkNodes[i]._deltaY = -1;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(_pos.x - gridIncr, _pos.y - gridIncr) && findPath2(_pos.x - gridIncr, _pos.y - gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = _pos.x - i;
+ _walkNodes[i]._gridY1 = _pos.y - i;
+ _walkNodes[i]._deltaX = -1;
+ _walkNodes[i]._deltaY = -1;
+ }
+ done = true;
+ break;
+ }
+ ++gridIncr;
+ }
+
+ return done;
+}
+
+bool PlayerPlat::findPath4(int gridX, int gridY) {
+ bool result = false;
+
+ _walkNodesCount = 0;
+ _walkDirXIncr = 0;
+ _walkDirYIncr = 0;
+ _walkDeltaX = ABS(_walkDestX - gridX);
+ _walkDeltaY = ABS(_walkDestY - gridY);
+
+ if (_walkDeltaX)
+ _walkDirX = (_walkDestX - gridX) / _walkDeltaX;
+ else
+ _walkDirX = 0;
+
+ if (_walkDeltaY)
+ _walkDirY = (_walkDestY - gridY) / _walkDeltaY;
+ else
+ _walkDirY = 0;
+
+ while (_walkDirXIncr < _walkDeltaX && _walkDirYIncr < _walkDeltaY) {
+ _walkNodes[_walkNodesCount]._gridX1 = gridX + _walkDirX * _walkDirXIncr;
+ _walkNodes[_walkNodesCount]._gridY1 = gridY + _walkDirY * _walkDirYIncr;
+ if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirXIncr;
+ ++_walkDirYIncr;
+ } else if (_walkDeltaY - _walkDirYIncr > _walkDeltaX - _walkDirXIncr) {
+ if (!_vm->isPointBlocked(_walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = 0;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirYIncr;
+ } else if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = 0;
+ ++_walkDirXIncr;
+ } else {
+ _walkDeltaX = _walkDirXIncr;
+ _walkDeltaY = _walkDirYIncr;
+ --_walkNodesCount;
+ }
+ } else {
+ if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = 0;
+ ++_walkDirXIncr;
+ } else if (!_vm->isPointBlocked(_walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = 0;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirYIncr;
+ } else {
+ _walkDeltaX = _walkDirXIncr;
+ _walkDeltaY = _walkDirYIncr;
+ --_walkNodesCount;
+ }
+ }
+ ++_walkNodesCount;
+ }
+
+ while (_walkDirXIncr < _walkDeltaX) {
+ _walkNodes[_walkNodesCount]._gridX1 = gridX + _walkDirX * _walkDirXIncr;
+ _walkNodes[_walkNodesCount]._gridY1 = _walkDestY;
+ if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkDestY)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = 0;
+ ++_walkDirXIncr;
+ ++_walkNodesCount;
+ } else {
+ _walkDeltaX = _walkDirXIncr;
+ }
+ }
+
+ while (_walkDirYIncr < _walkDeltaY) {
+ _walkNodes[_walkNodesCount]._gridX1 = _walkDestX;
+ _walkNodes[_walkNodesCount]._gridY1 = gridY + _walkDirY * _walkDirYIncr;
+ if (!_vm->isPointBlocked(_walkDestX, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = 0;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirYIncr;
+ ++_walkNodesCount;
+ } else {
+ _walkDeltaY = _walkDirYIncr;
+ }
+ }
+
+ if (gridX + _walkDirX * _walkDirXIncr != _walkDestX || gridY + _walkDirY * _walkDirYIncr != _walkDestY) {
+ _walkDestX = gridX + _walkDirX * _walkDirXIncr;
+ _walkDestY = gridY + _walkDirY * _walkDirYIncr;
+ result = false;
+ } else {
+ result = true;
+ }
+
+ return result;
+}
+
+void PlayerPlat::makeRoom() {
+ int rndGridX, rndGridY;
+ do {
+ rndGridY = _vm->getRandom(_vm->_gridMaxY);
+ rndGridX = _vm->getRandom(_vm->_gridMaxX);
+ } while (ABS(rndGridX - _pos.x) > 4 || ABS(rndGridY - _pos.y) > 3 ||
+ _vm->isPointBlocked(rndGridX, rndGridY));
+ walkTo(Common::Point(rndGridX, rndGridY), -1, -1, 1);
+}
+
+} // End of namespace Gnap
diff --git a/engines/gnap/menu.cpp b/engines/gnap/menu.cpp
new file mode 100644
index 0000000000..2bfe7300df
--- /dev/null
+++ b/engines/gnap/menu.cpp
@@ -0,0 +1,888 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/config-manager.h"
+#include "common/savefile.h"
+#include "common/translation.h"
+
+#include "gui/saveload.h"
+#include "graphics/thumbnail.h"
+
+#include "gnap/gnap.h"
+#include "gnap/datarchive.h"
+#include "gnap/gamesys.h"
+#include "gnap/resource.h"
+
+namespace Gnap {
+
+void GnapEngine::createMenuSprite() {
+ _menuBackgroundSurface = _gameSys->createSurface(0x10002);
+}
+
+void GnapEngine::freeMenuSprite() {
+ _gameSys->removeSpriteDrawItem(_menuBackgroundSurface, 260);
+ delayTicksCursor(5);
+ deleteSurface(&_menuBackgroundSurface);
+}
+
+void GnapEngine::initMenuHotspots1() {
+ int curId = 0;
+
+ for (int i = 0; i < 3; ++i) {
+ int top = 74 * i + 69;
+ for (int j = 0; j < 3; ++j) {
+ int left = 87 * j + 262;
+ _hotspots[curId]._rect = Common::Rect(left, top, left + 79, top + 66);
+ _hotspots[curId]._flags = SF_NONE;
+ ++curId;
+ }
+ }
+
+ _hotspots[curId]._rect = Common::Rect(330, 350, 430, 460);
+ _hotspots[curId]._flags = SF_GRAB_CURSOR;
+
+ ++curId;
+ _hotspots[curId]._rect = Common::Rect(180, 15, 620, 580);
+ _hotspots[curId]._flags = SF_NONE;
+
+ ++curId;
+ _hotspots[curId]._rect = Common::Rect(0, 0, 799, 599);
+ _hotspots[curId]._flags = SF_NONE;
+
+ _hotspotsCount = curId + 1;
+}
+
+void GnapEngine::initMenuHotspots2() {
+ int curId = 0;
+
+ for (int i = 0; i < 4; ++i) {
+ int top = 48 * i + 85;
+ _hotspots[curId]._rect = Common::Rect(312, top, 465, top + 37);
+ _hotspots[curId]._flags = SF_GRAB_CURSOR;
+ ++curId;
+ }
+
+ _hotspots[curId]._rect = Common::Rect(500, 72, 527, 99);
+ _hotspots[curId]._flags = SF_DISABLED;
+
+ ++curId;
+ _hotspots[curId]._rect = Common::Rect(330, 350, 430, 460);
+ _hotspots[curId]._flags = SF_GRAB_CURSOR;
+
+ ++curId;
+ _hotspots[curId]._rect = Common::Rect(180, 15, 620, 580);
+ _hotspots[curId]._flags = SF_NONE;
+
+ ++curId;
+ _hotspots[curId]._rect = Common::Rect(0, 0, 799, 599);
+ _hotspots[curId]._flags = SF_NONE;
+
+ _hotspotsCount = curId + 1;
+}
+
+void GnapEngine::initMenuQuitQueryHotspots() {
+ _hotspots[0]._rect = Common::Rect(311, 197, 377, 237);
+ _hotspots[0]._flags = SF_GRAB_CURSOR;
+
+ _hotspots[1]._rect = Common::Rect(403, 197, 469, 237);
+ _hotspots[1]._flags = SF_GRAB_CURSOR;
+
+ _hotspots[2]._rect = Common::Rect(330, 350, 430, 460);
+ _hotspots[2]._flags = SF_GRAB_CURSOR;
+
+ _hotspots[3]._rect = Common::Rect(180, 15, 620, 580);
+ _hotspots[3]._flags = SF_NONE;
+
+ _hotspots[4]._rect = Common::Rect(0, 0, 799, 599);
+ _hotspots[4]._flags = SF_NONE;
+
+ _hotspotsCount = 5;
+}
+
+void GnapEngine::initSaveLoadHotspots() {
+ int curId = 0;
+
+ for (int i = 0; i < 7; ++i ) {
+ int top = 31 * i + 74;
+ _hotspots[curId]._rect = Common::Rect(288, top, 379, top + 22);
+ _hotspots[curId]._flags = SF_GRAB_CURSOR;
+ ++curId;
+ }
+
+ if (_menuStatus == 2) {
+ _hotspots[curId]._rect = Common::Rect(416, 160, 499, 188);
+ _hotspots[curId]._flags = SF_GRAB_CURSOR;
+ ++curId;
+ }
+
+ _hotspots[curId]._rect = Common::Rect(416, 213, 499, 241);
+ _hotspots[curId]._flags = SF_GRAB_CURSOR;
+
+ ++curId;
+ _hotspots[curId]._rect = Common::Rect(330, 350, 430, 460);
+ _hotspots[curId]._flags = SF_GRAB_CURSOR;
+
+ ++curId;
+ _hotspots[curId]._rect = Common::Rect(180, 15, 620, 580);
+ _hotspots[curId]._flags = SF_NONE;
+
+ ++curId;
+ _hotspots[curId]._rect = Common::Rect(0, 0, 799, 599);
+ _hotspots[curId]._flags = SF_NONE;
+
+ _hotspotsCount = curId + 1;
+}
+
+void GnapEngine::drawInventoryFrames() {
+ for (int i = 0; i < 9; ++i)
+ _gameSys->drawSpriteToSurface(_menuBackgroundSurface, _hotspots[i]._rect.left - 93, _hotspots[i]._rect.top, 0x10001);
+}
+
+void GnapEngine::insertInventorySprites() {
+ for (int i = 0; i < 9; ++i) {
+ _menuInventoryIndices[i] = -1;
+ _gameSys->removeSpriteDrawItem(_menuInventorySprites[_sceneClickedHotspot], 261);
+ _menuInventorySprites[i] = 0;
+ }
+
+ _menuSpritesIndex = 0;
+
+ for (int index = 0; index < 30 && _menuSpritesIndex < 9; ++index) {
+ if (invHas(index)) {
+ _gameSys->drawSpriteToSurface(_menuBackgroundSurface,
+ _hotspots[_menuSpritesIndex]._rect.left - 93, _hotspots[_menuSpritesIndex]._rect.top, 0x10000);
+ _menuInventorySprites[_menuSpritesIndex] = _gameSys->createSurface(getInventoryItemSpriteNum(index) | 0x10000);
+ if (index != _grabCursorSpriteIndex) {
+ _menuInventoryIndices[_menuSpritesIndex] = index;
+ _gameSys->insertSpriteDrawItem(_menuInventorySprites[_menuSpritesIndex],
+ _hotspots[_menuSpritesIndex]._rect.left + ((79 - _menuInventorySprites[_menuSpritesIndex]->w) / 2),
+ _hotspots[_menuSpritesIndex]._rect.top + ((66 - _menuInventorySprites[_menuSpritesIndex]->h) / 2),
+ 261);
+ }
+ _hotspots[_menuSpritesIndex]._flags = SF_GRAB_CURSOR;
+ ++_menuSpritesIndex;
+ }
+ }
+}
+
+void GnapEngine::removeInventorySprites() {
+ for (int i = 0; i < _menuSpritesIndex; ++i)
+ if (_menuInventorySprites[i])
+ _gameSys->removeSpriteDrawItem(_menuInventorySprites[i], 261);
+ delayTicksCursor(5);
+ for (int j = 0; j < _menuSpritesIndex; ++j) {
+ if (_menuInventorySprites[j]) {
+ deleteSurface(&_menuInventorySprites[j]);
+ _menuInventorySprites[j] = 0;
+ _menuInventoryIndices[j] = -1;
+ }
+ }
+ _menuSpritesIndex = 0;
+}
+
+void GnapEngine::runMenu() {
+ _spriteHandle = nullptr;
+ _cursorSprite = nullptr;
+ _menuSprite1 = nullptr;
+ _menuSprite2 = nullptr;
+ _menuSaveLoadSprite = nullptr;
+ _menuQuitQuerySprite = nullptr;
+
+ _menuStatus = 0;
+ _menuDone = false;
+
+ delete _tempThumbnail;
+ _tempThumbnail = new Common::MemoryWriteStreamDynamic;
+ Graphics::saveThumbnail(*_tempThumbnail);
+
+ createMenuSprite();
+ insertDeviceIconActive();
+
+ for (int i = 0; i < 7; ++i) {
+ _savegameFilenames[i][0] = 0;
+ _savegameSprites[i] = nullptr;
+ }
+
+ if (_menuStatus == 0) {
+ invAdd(kItemMagazine);
+ setGrabCursorSprite(-1);
+ hideCursor();
+ initMenuHotspots1();
+ drawInventoryFrames();
+ insertInventorySprites();
+ _gameSys->insertSpriteDrawItem(_menuBackgroundSurface, 93, 0, 260);
+ showCursor();
+ // SetCursorPos(400, 300);
+ setVerbCursor(GRAB_CURSOR);
+ // pollMessages();
+ }
+
+ _timers[2] = 10;
+
+ while (!isKeyStatus1(Common::KEYCODE_BACKSPACE) && !isKeyStatus1(Common::KEYCODE_ESCAPE) && !_sceneDone && !_menuDone) {
+ updateCursorByHotspot();
+
+ switch (_menuStatus) {
+ case 0:
+ updateMenuStatusInventory();
+ break;
+ case 1:
+ updateMenuStatusMainMenu();
+ break;
+ case 2:
+ updateMenuStatusSaveGame();
+ break;
+ case 3:
+ updateMenuStatusLoadGame();
+ break;
+ case 4:
+ updateMenuStatusQueryQuit();
+ break;
+ }
+
+ gameUpdateTick();
+ }
+
+ removeInventorySprites();
+ if (_spriteHandle)
+ _gameSys->removeSpriteDrawItem(_spriteHandle, 261);
+ if (_menuSprite1)
+ _gameSys->removeSpriteDrawItem(_menuSprite1, 262);
+ if (_menuSprite2)
+ _gameSys->removeSpriteDrawItem(_menuSprite2, 262);
+ for (int i = 0; i < 7; ++i)
+ if (_savegameSprites[i])
+ _gameSys->removeSpriteDrawItem(_savegameSprites[i], 263);
+ if (_cursorSprite)
+ _gameSys->removeSpriteDrawItem(_cursorSprite, 264);
+ if (_menuSaveLoadSprite)
+ _gameSys->removeSpriteDrawItem(_menuSaveLoadSprite, 262);
+ if (_menuQuitQuerySprite)
+ _gameSys->removeSpriteDrawItem(_menuQuitQuerySprite, 262);
+ if (_menuBackgroundSurface)
+ _gameSys->removeSpriteDrawItem(_menuBackgroundSurface, 260);
+
+ delayTicksCursor(5);
+
+ deleteSurface(&_spriteHandle);
+ deleteSurface(&_menuSprite1);
+ deleteSurface(&_menuSprite2);
+ for (int i = 0; i < 7; ++i)
+ deleteSurface(&_savegameSprites[i]);
+ deleteSurface(&_cursorSprite);
+ deleteSurface(&_menuSaveLoadSprite);
+ deleteSurface(&_menuQuitQuerySprite);
+
+ _sceneClickedHotspot = -1;
+
+ _timers[2] = getRandom(20) + 30;
+ _timers[3] = getRandom(200) + 50;
+ _timers[0] = getRandom(75) + 75;
+ _timers[1] = getRandom(20) + 30;
+
+ clearAllKeyStatus1();
+
+ _mouseClickState._left = false;
+
+ removeDeviceIconActive();
+
+ freeMenuSprite();//??? CHECKME
+}
+
+void GnapEngine::updateMenuStatusInventory() {
+ static const struct {
+ int item1, item2, resultItem;
+ } kCombineItems[] = {
+ {kItemGrass, kItemMud, kItemDisguise},
+ {kItemDice, kItemQuarterWithHole, kItemDiceQuarterHole},
+ {kItemPill, kItemBucketWithBeer, kItemBucketWithPill}
+ };
+
+ updateGrabCursorSprite(0, 0);
+ _hotspots[0]._rect = Common::Rect(262, 69, 341, 135);
+ _sceneClickedHotspot = -1;
+ if (_timers[2] == 0)
+ _sceneClickedHotspot = getClickedHotspotId();
+ if (_sceneClickedHotspot == -1 || _sceneClickedHotspot >= _menuSpritesIndex) {
+ if (_sceneClickedHotspot == _hotspotsCount - 3) {
+ if (_grabCursorSpriteIndex == -1) {
+ _timers[2] = 10;
+ playSound(0x108F4, false);
+ _menuStatus = 1;
+ Common::Rect dirtyRect(_hotspots[0]._rect.left, _hotspots[0]._rect.top, _hotspots[2]._rect.right, _hotspots[_hotspotsCount - 4]._rect.bottom);
+ drawInventoryFrames();
+ initMenuHotspots2();
+ removeInventorySprites();
+ if (!_menuSprite1)
+ _menuSprite1 = _gameSys->createSurface(0x104F8);
+ _gameSys->insertSpriteDrawItem(_menuSprite1, 288, 79, 262);
+ _gameSys->insertDirtyRect(dirtyRect);
+ } else {
+ playSound(0x108F5, false);
+ }
+ } else if (_sceneClickedHotspot == _hotspotsCount - 1) {
+ _timers[2] = 10;
+ playSound(0x108F5, false);
+ _menuDone = true;
+ }
+ } else if (_sceneClickedHotspot != -1 && _menuInventoryIndices[_sceneClickedHotspot] != -1 && _grabCursorSpriteIndex == -1) {
+ _gameSys->removeSpriteDrawItem(_menuInventorySprites[_sceneClickedHotspot], 261);
+ setGrabCursorSprite(_menuInventoryIndices[_sceneClickedHotspot]);
+ _menuInventoryIndices[_sceneClickedHotspot] = -1;
+ } else if (_sceneClickedHotspot != -1 && _menuInventoryIndices[_sceneClickedHotspot] == -1 && _grabCursorSpriteIndex != -1) {
+ _menuInventoryIndices[_sceneClickedHotspot] = _grabCursorSpriteIndex;
+ _gameSys->insertSpriteDrawItem(_menuInventorySprites[_sceneClickedHotspot],
+ _hotspots[_sceneClickedHotspot]._rect.left + ((79 - _menuInventorySprites[_sceneClickedHotspot]->w) / 2),
+ _hotspots[_sceneClickedHotspot]._rect.top + (66 - _menuInventorySprites[_sceneClickedHotspot]->h) / 2,
+ 261);
+ setGrabCursorSprite(-1);
+ } else if (_sceneClickedHotspot != -1 && _menuInventoryIndices[_sceneClickedHotspot] != -1 && _grabCursorSpriteIndex != -1) {
+ int combineIndex = -1;
+ for (int i = 0; i < ARRAYSIZE(kCombineItems); ++i) {
+ if ((_grabCursorSpriteIndex == kCombineItems[i].item1 && _menuInventoryIndices[_sceneClickedHotspot] == kCombineItems[i].item2) ||
+ (_grabCursorSpriteIndex == kCombineItems[i].item2 && _menuInventoryIndices[_sceneClickedHotspot] == kCombineItems[i].item1)) {
+ combineIndex = i;
+ break;
+ }
+ }
+ if (combineIndex >= 0) {
+ invRemove(kCombineItems[combineIndex].item1);
+ invRemove(kCombineItems[combineIndex].item2);
+ invAdd(kCombineItems[combineIndex].resultItem);
+ playSound(0x108AE, false);
+ deleteSurface(&_spriteHandle); // CHECKME
+ _spriteHandle = _gameSys->createSurface(0x10001);
+ _gameSys->insertSpriteDrawItem(_spriteHandle, _hotspots[_menuSpritesIndex - 1]._rect.left, _hotspots[_menuSpritesIndex - 1]._rect.top, 261);
+ setGrabCursorSprite(kCombineItems[combineIndex].resultItem);
+ removeInventorySprites();
+ insertInventorySprites();
+ delayTicksCursor(5);
+ } else {
+ playSound(0x108F5, false);
+ }
+ }
+}
+
+void GnapEngine::updateMenuStatusMainMenu() {
+ _hotspots[0]._rect = Common::Rect(312, 85, 465, 122);
+ _sceneClickedHotspot = -1;
+ if (!_timers[2])
+ _sceneClickedHotspot = getClickedHotspotId();
+
+ if (_sceneClickedHotspot != 1 && _sceneClickedHotspot != 0) {
+ if (_sceneClickedHotspot != 2 && _hotspotsCount - 1 != _sceneClickedHotspot) {
+ if (_sceneClickedHotspot == 3) {
+ // Quit
+ _timers[2] = 10;
+ playSound(0x108F4, false);
+ _gameSys->removeSpriteDrawItem(_menuSprite1, 262);
+ initMenuQuitQueryHotspots();
+ _menuStatus = 4;
+ if (!_menuQuitQuerySprite)
+ _menuQuitQuerySprite = _gameSys->createSurface(0x104FC);
+ _gameSys->insertSpriteDrawItem(_menuQuitQuerySprite, 254, 93, 262);
+ } else if (_sceneClickedHotspot == 4) {
+ // Pause ?
+ playSound(0x108F4, false);
+ Common::Rect dirtyRect(0, 0, 799, 599);
+ hideCursor();
+ _largeSprite = _gameSys->allocSurface(800, 600);
+
+ for (int i = 0; i < 3; ++i) {
+ _timers[2] = 10;
+
+ if (i == 0) {
+ _gameSys->drawSpriteToSurface(_largeSprite, 0, 0, 0x1078D);
+ _gameSys->insertSpriteDrawItem(_largeSprite, 0, 0, 300);
+ playMidi("pause.mid");
+ } else if (i == 1) {
+ _gameSys->drawSpriteToSurface(_largeSprite, 0, 0, 0x1078E);
+ _gameSys->insertDirtyRect(dirtyRect);
+ } else if (i == 2) {
+ _gameSys->drawSpriteToSurface(_largeSprite, 0, 0, 0x1078F);
+ _gameSys->insertDirtyRect(dirtyRect);
+ }
+
+ while (!_mouseClickState._left && !isKeyStatus1(Common::KEYCODE_ESCAPE) && !isKeyStatus1(Common::KEYCODE_RETURN)
+ && !isKeyStatus1(Common::KEYCODE_SPACE) && !_timers[2] && !_gameDone)
+ gameUpdateTick();
+
+ playSound(0x108F5, false);
+ _mouseClickState._left = false;
+ clearKeyStatus1(Common::KEYCODE_ESCAPE);
+ clearKeyStatus1(Common::KEYCODE_RETURN);
+ clearKeyStatus1(Common::KEYCODE_SPACE);
+ }
+
+ _gameSys->removeSpriteDrawItem(_largeSprite, 300);
+ delayTicksCursor(5);
+ deleteSurface(&_largeSprite);
+ showCursor();
+ } else if (_hotspotsCount - 3 == _sceneClickedHotspot) {
+ // Button - Return to the inventory
+ _timers[2] = 10;
+ playSound(0x108F4, false);
+ initMenuHotspots1();
+ _menuStatus = 0;
+ if (_menuSprite1)
+ _gameSys->removeSpriteDrawItem(_menuSprite1, 262);
+ insertInventorySprites();
+ Common::Rect dirtyRect(_hotspots[0]._rect.left, _hotspots[0]._rect.top, _hotspots[2]._rect.right, _hotspots[_hotspotsCount - 4]._rect.bottom);
+ _gameSys->insertDirtyRect(dirtyRect);
+ }
+ } else {
+ // Resume
+ playSound(0x108F5, false);
+ _menuDone = true;
+ }
+ } else {
+ // Save / Load
+#if 1
+ _timers[2] = 10;
+ playSound(0x108F4, false);
+
+ if (_sceneClickedHotspot == 1) {
+ GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Save game:"), _("Save"), true);
+ int16 savegameId = dialog->runModalWithCurrentTarget();
+ Common::String savegameDescription = dialog->getResultString();
+ delete dialog;
+
+ if (savegameId != -1) {
+ saveGameState(savegameId, savegameDescription);
+ }
+ } else {
+ GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Restore game:"), _("Restore"), false);
+ int16 savegameId = dialog->runModalWithCurrentTarget();
+ delete dialog;
+
+ if (savegameId != -1) {
+ loadGameState(savegameId);
+ _wasSavegameLoaded = true;
+ _menuDone = true;
+ _sceneDone = true;
+ playSound(0x108F4, false);
+ } else {
+ playSound(0x108F5, false);
+ }
+ }
+ }
+#else
+ // NOTE:
+ // This is the code for the original behavior.
+ // It's currently not working prolery, but could be
+ // fixed to replace the ScummVM screens currently
+ // used.
+ _timers[2] = 10;
+ playSound(0x108F4, false);
+ _gameSys->removeSpriteDrawItem(_menuSprite1, 262);
+ if (_menuSaveLoadSprite)
+ deleteSurface(&_menuSaveLoadSprite);
+ if (_sceneClickedHotspot == 1) {
+ // Save
+ _menuStatus = 2;
+ initSaveLoadHotspots();
+ _menuSaveLoadSprite = _gameSys->createSurface(0x104FB);
+ } else {
+ // Load
+ _menuStatus = 3;
+ initSaveLoadHotspots();
+ _menuSaveLoadSprite = _gameSys->createSurface(0x104FA);
+ }
+ _gameSys->insertSpriteDrawItem(_menuSaveLoadSprite, 403, 72, 262);
+ if (!_menuSprite2)
+ _menuSprite2 = _gameSys->createSurface(0x104F9);
+ _gameSys->insertSpriteDrawItem(_menuSprite2, 277, 66, 262);
+ for (int i = 0; i < 7; ++i) {
+ Common::String savegameDescription;
+ if (!_savegameSprites[i])
+ _savegameSprites[i] = _gameSys->allocSurface(111, 40);
+ if (readSavegameDescription(i + 1, savegameDescription) == 0)
+ strncpy(_savegameFilenames[i], savegameDescription.c_str(), 40);
+ _gameSys->drawTextToSurface(_savegameSprites[i], 0, 0, 255, 0, 0, _savegameFilenames[i]);
+ _gameSys->insertSpriteDrawItem(_savegameSprites[i], 288, _hotspots[i].top, 263);
+ }
+ _savegameIndex = -1;
+ }
+#endif
+}
+
+Common::Error GnapEngine::saveGameState(int slot, const Common::String &desc) {
+ Common::OutSaveFile *out = g_system->getSavefileManager()->openForSaving(
+ generateSaveName(slot));
+ if (!out)
+ return Common::kCreatingFileFailed;
+
+ GnapSavegameHeader header;
+ header._saveName = desc;
+ writeSavegameHeader(out, header);
+
+ Common::Serializer s(nullptr, out);
+ synchronize(s);
+
+ out->finalize();
+ delete out;
+
+ return Common::kNoError;
+}
+
+void GnapEngine::synchronize(Common::Serializer &s) {
+ if (s.isSaving()) {
+ s.syncAsSint32LE(_currentSceneNum);
+ s.syncAsSint32LE(_prevSceneNum);
+ s.syncAsSint32LE(_cursorValue);
+ s.syncAsUint32LE(_inventory);
+ s.syncAsUint32LE(_gameFlags);
+ } else {
+ s.syncAsSint32LE(_newSceneNum);
+ s.syncAsSint32LE(_currentSceneNum);
+ s.syncAsSint32LE(_newCursorValue);
+ s.syncAsUint32LE(_inventory);
+ s.syncAsUint32LE(_gameFlags);
+
+ if (isFlag(kGFUnk24))
+ _timers[9] = 600;
+ }
+}
+
+const char *const SAVEGAME_STR = "GNAP";
+#define SAVEGAME_STR_SIZE 4
+void GnapEngine::writeSavegameHeader(Common::OutSaveFile *out, GnapSavegameHeader &header) {
+ // Write out a savegame header
+ out->write(SAVEGAME_STR, SAVEGAME_STR_SIZE + 1);
+
+ out->writeByte(GNAP_SAVEGAME_VERSION);
+
+ // Write savegame name
+ out->writeString(header._saveName);
+ out->writeByte('\0');
+
+ // This implies the menu is used
+ // If we want to save/load at any time, then a check should be added
+ out->write(_tempThumbnail->getData(), _tempThumbnail->size());
+
+ // Write out the save date/time
+ TimeDate td;
+ g_system->getTimeAndDate(td);
+ out->writeSint16LE(td.tm_year + 1900);
+ out->writeSint16LE(td.tm_mon + 1);
+ out->writeSint16LE(td.tm_mday);
+ out->writeSint16LE(td.tm_hour);
+ out->writeSint16LE(td.tm_min);
+}
+
+bool GnapEngine::readSavegameHeader(Common::InSaveFile *in, GnapSavegameHeader &header) {
+ char saveIdentBuffer[SAVEGAME_STR_SIZE + 1];
+ header._thumbnail = nullptr;
+
+ // Validate the header Id
+ in->read(saveIdentBuffer, SAVEGAME_STR_SIZE + 1);
+ if (strncmp(saveIdentBuffer, SAVEGAME_STR, SAVEGAME_STR_SIZE))
+ return false;
+
+ header._version = in->readByte();
+ if (header._version > GNAP_SAVEGAME_VERSION)
+ return false;
+
+ // Read in the string
+ header._saveName.clear();
+ char ch;
+ while ((ch = (char)in->readByte()) != '\0')
+ header._saveName += ch;
+
+ // Get the thumbnail, saved in v2 or later
+ if (header._version == 1)
+ header._thumbnail = nullptr;
+ else {
+ header._thumbnail = Graphics::loadThumbnail(*in);
+ if (!header._thumbnail)
+ return false;
+ }
+
+ // Read in save date/time
+ header._year = in->readSint16LE();
+ header._month = in->readSint16LE();
+ header._day = in->readSint16LE();
+ header._hour = in->readSint16LE();
+ header._minute = in->readSint16LE();
+
+ return true;
+}
+
+Common::Error GnapEngine::loadGameState(int slot) {
+ Common::InSaveFile *saveFile = g_system->getSavefileManager()->openForLoading(
+ generateSaveName(slot));
+ if (!saveFile)
+ return Common::kReadingFailed;
+
+ Common::Serializer s(saveFile, nullptr);
+
+ // Load the savegame header
+ GnapSavegameHeader header;
+ if (!readSavegameHeader(saveFile, header))
+ error("Invalid savegame");
+
+ if (header._thumbnail) {
+ header._thumbnail->free();
+ delete header._thumbnail;
+ }
+
+ synchronize(s);
+ delete saveFile;
+
+ _loadGameSlot = slot;
+ return Common::kNoError;
+}
+
+Common::String GnapEngine::generateSaveName(int slot) {
+ return Common::String::format("%s.%03d", _targetName.c_str(), slot);
+}
+
+void GnapEngine::updateMenuStatusSaveGame() {
+#if 0
+ // NOTE:
+ // This is the code for the original screen game.
+ // It could be eventually fixed and could replace
+ // the ScummVM screens currently used.
+
+ char v43[30];
+ int v46;
+ v43[0] = '\0';
+ _hotspots[0]._x1 = 288;
+ _hotspots[0]._y1 = 74;
+ _hotspots[0]._x2 = 379;
+ _hotspots[0]._y2 = 96;
+ _sceneClickedHotspot = -1;
+
+ if (!_timers[2])
+ _sceneClickedHotspot = getClickedHotspotId();
+
+ if (_hotspotsCount - 3 == _sceneClickedHotspot) {
+ // Button
+ _timers[2] = 10;
+ playSound(0x108F4, false);
+ _menuStatus = 1;
+ warning("writeSavegame(_savegameIndex + 1, (int)&_savegameFilenames[30 * _savegameIndex], 1);");
+ } else if (_hotspotsCount - 4 == _sceneClickedHotspot) {
+ // Cancel
+ _timers[2] = 10;
+ playSound(0x108F5, false);
+ _menuStatus = 1;
+ if (strcmp(v43, _savegameFilenames[_savegameIndex]) && _savegameIndex != -1) {
+ strcpy(_savegameFilenames[_savegameIndex], v43);
+ if (_savegameSprites[_savegameIndex] != nullptr) {
+ _gameSys->removeSpriteDrawItem(_savegameSprites[_savegameIndex], 263);
+ delayTicksCursor(5);
+ warning("memFreeHandle(_savegameSprites[_savegameIndex]);");
+ }
+ int v16 = _gameSys->getSpriteWidthById(0x104F9);
+ warning("_savegameSprites[_savegameIndex] = allocSprite(v16, 40, 128, 0);");
+ }
+ } else if (_hotspotsCount - 5 == _sceneClickedHotspot) {
+ // OK
+ _timers[2] = 10;
+ playSound(0x108F4, false);
+ if (_savegameIndex != -1)
+ warning("writeSavegame(_savegameIndex + 1, (int)&_savegameFilenames[30 * _savegameIndex], 1);");
+ _menuStatus = 1;
+ } else if (_hotspotsCount - 1 == _sceneClickedHotspot) {
+ // in background
+ _menuDone = true;
+ } else if (_sceneClickedHotspot != -1 && _hotspotsCount - 2 != _sceneClickedHotspot) {
+ // Savegame name
+ _timers[2] = 10;
+ playSound(0x108F4, false);
+ if (strcmp(v43, _savegameFilenames[_savegameIndex]) & (_savegameIndex != -1)) {
+ strcpy(_savegameFilenames[_savegameIndex], v43);
+ if (_savegameSprites[_savegameIndex] != nullptr) {
+ _gameSys->removeSpriteDrawItem(_savegameSprites[_savegameIndex], 263);
+ delayTicksCursor(5);
+ warning("memFreeHandle(_savegameSprites[_savegameIndex]);");
+ }
+ int v18 = _gameSys->getSpriteWidthById(0x104F9);
+ _savegameSprites[_savegameIndex] = _gameSys->allocSurface(v18, 40);
+ _gameSys->drawTextToSurface(_savegameSprites[_savegameIndex], 0, 0, 255, 0, 0, _savegameFilenames[_savegameIndex]);
+ _gameSys->insertSpriteDrawItem(_savegameSprites[_savegameIndex], 288, _hotspots[_savegameIndex]._y1, 263);
+ }
+ _savegameIndex = _sceneClickedHotspot;
+ v46 = strlen(_savegameFilenames[_sceneClickedHotspot]);
+ strcpy(v43, _savegameFilenames[_sceneClickedHotspot]);
+ if (_cursorSprite == nullptr) {
+ int v19 = _gameSys->getTextHeight("_");
+ int v20 = _gameSys->getTextWidth("_");
+ _cursorSprite = _gameSys->allocSurface(v20, v19);
+ _gameSys->drawTextToSurface(_cursorSprite, 0, 0, 255, 0, 0, "_");
+ } else {
+ _gameSys->removeSpriteDrawItem(_cursorSprite, 264);
+ }
+ int v21 = _hotspots[_savegameIndex]._x2;
+ int v22 = v21 - _gameSys->getTextWidth("_");
+ if (v22 > _gameSys->getTextWidth(_savegameFilenames[_savegameIndex]) + 288) {
+ int v25 = _gameSys->getTextWidth(_savegameFilenames[_savegameIndex]) + 288;
+ _gameSys->insertSpriteDrawItem(_cursorSprite, v25, _hotspots[_savegameIndex]._y1, 264);
+ } else {
+ int v23 = _hotspots[_savegameIndex]._x2;
+ int v24 = v23 - _gameSys->getTextWidth("_");
+ _gameSys->insertSpriteDrawItem(_cursorSprite, v24, _hotspots[_savegameIndex]._y1, 264);
+ }
+ }
+
+ updateEvents();
+ Common::Event event;
+ _eventMan->pollEvent(event);
+
+ Common::KeyCode keycode = event.kbd.keycode;
+ if (_savegameIndex != -1 && keycode) {
+ if ((keycode < Common::KEYCODE_a || keycode > Common::KEYCODE_z) && (keycode < Common::KEYCODE_0 || keycode > Common::KEYCODE_9) && keycode != Common::KEYCODE_SPACE) {
+ if (keycode == Common::KEYCODE_BACKSPACE) {
+ if (v46 > 0)
+ --v46;
+ _savegameFilenames[_savegameIndex][v46] = '\0';
+ if (_savegameSprites[_savegameIndex] != nullptr) {
+ _gameSys->removeSpriteDrawItem(_savegameSprites[_savegameIndex], 263);
+ warning("memFreeHandle(_savegameSprites[_savegameIndex]);");
+ }
+ int v32 = _gameSys->getSpriteWidthById(0x104F9);
+ _savegameSprites[_savegameIndex] = _gameSys->allocSurface(v32, 40);
+ _gameSys->drawTextToSurface(_savegameSprites[_savegameIndex], 0, 0, 255, 0, 0, _savegameFilenames[_savegameIndex]);
+ _gameSys->insertSpriteDrawItem(_savegameSprites[_savegameIndex], 288, _hotspots[_savegameIndex]._y1, 263);
+ _gameSys->removeSpriteDrawItem(_cursorSprite, 264);
+ int v33 = _hotspots[_savegameIndex]._y1;
+ int v34 = _gameSys->getTextWidth(_savegameFilenames[_savegameIndex]);
+ _gameSys->insertSpriteDrawItem(_cursorSprite, _hotspots[_savegameIndex]._x1 + v34, v33, 264);
+ } else if (keycode == Common::KEYCODE_RETURN) {
+ _menuStatus = 1;
+ warning("writeSavegame(_savegameIndex + 1, (int)&_savegameFilenames[30 * _savegameIndex], 1);");
+ }
+ } else {
+ _savegameFilenames[_savegameIndex][v46] = event.kbd.ascii;
+ if (v46 < 28)
+ ++v46;
+ _savegameFilenames[_savegameIndex][v46] = '\0';
+ if (_gameSys->getTextWidth(_savegameFilenames[_savegameIndex]) > 91) {
+ --v46;
+ _savegameFilenames[_savegameIndex][v46] = '\0';
+ }
+ _gameSys->drawTextToSurface(_savegameSprites[_savegameIndex], 0, 0, 255, 0, 0, _savegameFilenames[_savegameIndex]);
+ int v26 = _gameSys->getTextWidth(_savegameFilenames[_savegameIndex]);
+ Common::Rect rect;
+ rect.right = _hotspots[_savegameIndex]._x1 + v26;
+ int v27 = rect.right;
+ rect.left = v27 - 2 * _gameSys->getTextWidth("W");
+ rect.top = _hotspots[_savegameIndex]._y1;
+ rect.bottom = _hotspots[_savegameIndex]._y2;
+ _gameSys->insertDirtyRect(rect);
+ _gameSys->removeSpriteDrawItem(_cursorSprite, 264);
+ int v28 = _hotspots[_savegameIndex]._x2;
+ int v29 = _gameSys->getTextWidth("_");
+ if (v28 - v29 > rect.right)
+ _gameSys->insertSpriteDrawItem(_cursorSprite, rect.right, rect.top, 264);
+ else {
+ int v30 = _hotspots[_savegameIndex]._x2;
+ int v31 = v30 - _gameSys->getTextWidth("_");
+ _gameSys->insertSpriteDrawItem(_cursorSprite, v31, rect.top, 264);
+ }
+ clearKeyStatus1(8);
+ }
+ }
+
+// warning("keybChar = 0;");
+ if (_menuStatus == 1 || _menuDone) {
+ _gameSys->removeSpriteDrawItem(_menuSprite2, 262);
+ _gameSys->removeSpriteDrawItem(_menuSaveLoadSprite, 262);
+ for (int i = 0; i < 7; ++i)
+ _gameSys->removeSpriteDrawItem(_savegameSprites[i], 263);
+ _gameSys->removeSpriteDrawItem(_cursorSprite, 264);
+ if (!_menuDone) {
+ initMenuHotspots2();
+ _gameSys->insertSpriteDrawItem(_menuSprite1, 288, 79, 262);
+ }
+ }
+#endif
+}
+
+void GnapEngine::updateMenuStatusLoadGame() {
+ _hotspots[0]._rect = Common::Rect(288, 74, 379, 96);
+ _sceneClickedHotspot = -1;
+ if (!_timers[2])
+ _sceneClickedHotspot = getClickedHotspotId();
+ if (_sceneClickedHotspot != -1 && _hotspotsCount - 2 != _sceneClickedHotspot) {
+ _timers[2] = 10;
+ if (_hotspotsCount - 4 <= _sceneClickedHotspot) {
+ playSound(0x108F5, false);
+ _gameSys->removeSpriteDrawItem(_menuSprite2, 262);
+ _gameSys->removeSpriteDrawItem(_menuSaveLoadSprite, 262);
+ for (int i = 0; i < 7; ++i)
+ _gameSys->removeSpriteDrawItem(_savegameSprites[i], 263);
+ if (_hotspotsCount - 1 == _sceneClickedHotspot) {
+ _menuDone = true;
+ } else {
+ _menuStatus = 1;
+ initMenuHotspots2();
+ _gameSys->insertSpriteDrawItem(_menuSprite1, 288, 79, 262);
+ }
+ } else if (loadSavegame(_sceneClickedHotspot + 1)) {
+ playSound(0x108F5, false);
+ } else {
+ playSound(0x108F4, false);
+ _sceneDone = true;
+ }
+ }
+}
+
+void GnapEngine::updateMenuStatusQueryQuit() {
+ _hotspots[0]._rect = Common::Rect(311, 197, 377, 237);
+ _sceneClickedHotspot = -1;
+
+ if (!_timers[2])
+ _sceneClickedHotspot = getClickedHotspotId();
+
+ /* _sceneClickedHotspot
+ 0 Yes
+ 1 No
+ 2 Button
+ 3 Display
+ 4 Background
+ */
+
+ if (_sceneClickedHotspot == 0) {
+ // Quit the game
+ playSound(0x108F5, false);
+ _gameSys->removeSpriteDrawItem(_menuQuitQuerySprite, 262);
+ _sceneDone = true;
+ _gameDone = true;
+ } else if (_sceneClickedHotspot == 4) {
+ // Exit the device
+ playSound(0x108F4, false);
+ _gameSys->removeSpriteDrawItem(_menuQuitQuerySprite, 262);
+ _menuDone = true;
+ } else if (_sceneClickedHotspot != -1) {
+ // Return to the main menu
+ playSound(0x108F4, false);
+ _gameSys->removeSpriteDrawItem(_menuQuitQuerySprite, 262);
+ _timers[2] = 10;
+ _menuStatus = 1;
+ initMenuHotspots2();
+ _gameSys->insertSpriteDrawItem(_menuSprite1, 288, 79, 262);
+ }
+}
+
+} // End of namespace Gnap
diff --git a/engines/gnap/module.mk b/engines/gnap/module.mk
new file mode 100644
index 0000000000..ab507cbf94
--- /dev/null
+++ b/engines/gnap/module.mk
@@ -0,0 +1,32 @@
+MODULE := engines/gnap
+
+MODULE_OBJS := \
+ character.o \
+ datarchive.o \
+ debugger.o \
+ detection.o \
+ gamesys.o \
+ gnap.o \
+ grid.o \
+ menu.o \
+ music.o \
+ resource.o \
+ sound.o \
+ scenes/arcade.o \
+ scenes/groupcs.o \
+ scenes/group0.o \
+ scenes/group1.o \
+ scenes/group2.o \
+ scenes/group3.o \
+ scenes/group4.o \
+ scenes/group5.o \
+ scenes/intro.o \
+ scenes/scenecore.o
+
+# This module can be built as a plugin
+ifeq ($(ENABLE_GNAP), DYNAMIC_PLUGIN)
+PLUGIN := 1
+endif
+
+# Include common rules
+include $(srcdir)/rules.mk
diff --git a/engines/gnap/music.cpp b/engines/gnap/music.cpp
new file mode 100644
index 0000000000..af33786a8f
--- /dev/null
+++ b/engines/gnap/music.cpp
@@ -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.
+ *
+ */
+
+// MIDI and digital music class
+
+#include "audio/mididrv.h"
+#include "audio/midiparser.h"
+#include "common/debug.h"
+#include "common/file.h"
+
+#include "gnap/music.h"
+#include "gnap/gnap.h"
+
+namespace Gnap {
+
+MusicPlayer::MusicPlayer(const char *filename) : _filename(filename) {
+
+ MidiPlayer::createDriver();
+
+ int ret = _driver->open();
+ if (ret == 0) {
+ if (_nativeMT32)
+ _driver->sendMT32Reset();
+ else
+ _driver->sendGMReset();
+
+ _driver->setTimerCallback(this, &timerCallback);
+ }
+}
+
+void MusicPlayer::sendToChannel(byte channel, uint32 b) {
+ if (!_channelsTable[channel]) {
+ _channelsTable[channel] = (channel == 9) ? _driver->getPercussionChannel() : _driver->allocateChannel();
+ // If a new channel is allocated during the playback, make sure
+ // its volume is correctly initialized.
+ if (_channelsTable[channel])
+ _channelsTable[channel]->volume(_channelsVolume[channel] * _masterVolume / 255);
+ }
+
+ if (_channelsTable[channel])
+ _channelsTable[channel]->send(b);
+}
+
+void MusicPlayer::playSMF(bool loop) {
+ Common::StackLock lock(_mutex);
+
+ stop();
+
+ // Load MIDI resource data
+ Common::File musicFile;
+ musicFile.open(_filename);
+ if (!musicFile.isOpen()) {
+ debugC(2, kDebugMusic, "Cannot open music file %s", _filename.c_str());
+ return;
+ }
+ int midiMusicSize = musicFile.size();
+ free(_midiData);
+ _midiData = (byte *)malloc(midiMusicSize);
+ musicFile.read(_midiData, midiMusicSize);
+ musicFile.close();
+
+ MidiParser *parser = MidiParser::createParser_SMF();
+ if (parser->loadMusic(_midiData, midiMusicSize)) {
+ parser->setTrack(0);
+ parser->setMidiDriver(this);
+ parser->setTimerRate(_driver->getBaseTempo());
+ parser->property(MidiParser::mpCenterPitchWheelOnUnload, 1);
+
+ _parser = parser;
+
+ syncVolume();
+
+ _isLooping = loop;
+ _isPlaying = true;
+ } else {
+ debugC(2, kDebugMusic, "Cannot play music file %s", _filename.c_str());
+ delete parser;
+ }
+}
+
+void MusicPlayer::stop() {
+ Audio::MidiPlayer::stop();
+}
+
+} // End of namespace Gnap
diff --git a/engines/gnap/music.h b/engines/gnap/music.h
new file mode 100644
index 0000000000..c5938937eb
--- /dev/null
+++ b/engines/gnap/music.h
@@ -0,0 +1,50 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 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.
+ *
+ */
+
+// Music class
+
+#ifndef GNAP_MUSIC_H
+#define GNAP_MUSIC_H
+
+#include "audio/midiplayer.h"
+
+namespace Gnap {
+
+// Taken from Draci, which took it from MADE, which took it from SAGA.
+
+class MusicPlayer : public Audio::MidiPlayer {
+public:
+ MusicPlayer(const char *filename);
+
+ void playSMF(bool loop);
+ void stop();
+
+ // Overload Audio::MidiPlayer method
+ virtual void sendToChannel(byte channel, uint32 b);
+
+protected:
+ Common::String _filename;
+};
+
+} // End of namespace Gnap
+
+#endif
diff --git a/engines/gnap/resource.cpp b/engines/gnap/resource.cpp
new file mode 100644
index 0000000000..8244213a7f
--- /dev/null
+++ b/engines/gnap/resource.cpp
@@ -0,0 +1,121 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 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 "gnap/gnap.h"
+#include "gnap/resource.h"
+
+namespace Gnap {
+
+// SequenceFrame
+
+void SequenceFrame::loadFromStream(Common::MemoryReadStream &stream) {
+ _duration = stream.readUint16LE();
+ _isScaled = (stream.readUint16LE() != 0);
+ _rect.left = stream.readUint32LE();
+ _rect.top = stream.readUint32LE();
+ _rect.right = stream.readUint32LE();
+ _rect.bottom = stream.readUint32LE();
+ _spriteId = stream.readUint32LE();
+ _soundId = stream.readUint32LE();
+
+ // Skip an unused value
+ stream.readUint32LE();
+
+ debugC(kDebugBasic, "SequenceFrame() spriteId: %d; soundId: %d", _spriteId, _soundId);
+}
+
+// SequenceAnimation
+
+void SequenceAnimation::loadFromStream(Common::MemoryReadStream &stream) {
+ // Skip two unused values
+ stream.readUint32LE();
+
+ _additionalDelay = stream.readUint32LE();
+ _framesCount = stream.readUint16LE();
+ _maxTotalDuration = stream.readUint16LE();
+ debugC(kDebugBasic, "SequenceAnimation() framesCount: %d", _framesCount);
+ frames = new SequenceFrame[_framesCount];
+ for (int i = 0; i < _framesCount; ++i)
+ frames[i].loadFromStream(stream);
+}
+
+// SequenceResource
+SequenceResource::SequenceResource(byte *data, uint32 size) {
+ Common::MemoryReadStream stream(data, size, DisposeAfterUse::NO);
+
+ // Skip an unused value
+ stream.readUint32LE();
+
+ _sequenceId = stream.readUint32LE();
+ _defaultId = stream.readUint32LE();
+ _sequenceId2 = stream.readUint32LE();
+ _defaultId2 = stream.readUint32LE();
+ _flags = stream.readUint32LE();
+ _totalDuration = stream.readUint32LE();
+ _xOffs = stream.readUint16LE();
+ _yOffs = stream.readUint16LE();
+ _animationsCount = stream.readUint32LE();
+ _animations = new SequenceAnimation[_animationsCount];
+ debugC(kDebugBasic, "SequenceResource() _animationsCount: %d", _animationsCount);
+ for (int i = 0; i < _animationsCount; ++i) {
+ uint32 animationOffs = stream.readUint32LE();
+ debugC(kDebugBasic, "animationOffs: %08X", animationOffs);
+ uint32 oldOffs = stream.pos();
+ stream.seek(animationOffs);
+ _animations[i].loadFromStream(stream);
+ stream.seek(oldOffs);
+ }
+}
+
+SequenceResource::~SequenceResource() {
+ delete[] _animations;
+}
+
+// SpriteResource
+SpriteResource::SpriteResource(byte *data, uint32 size) {
+ _data = data;
+ _width = READ_LE_UINT16(_data);
+ _height = READ_LE_UINT16(_data + 2);
+ _unknownVal1 = READ_LE_UINT16(_data + 4);
+ _unknownVal2 = READ_LE_UINT16(_data + 6);
+ _transparent = (READ_LE_UINT16(_data + 8) != 0);
+ _colorsCount = READ_LE_UINT16(_data + 10);
+ _palette = (uint32 *)(_data + 12);
+ _pixels = _data + 12 + _colorsCount * 4;
+ debugC(kDebugBasic, "SpriteResource() width: %d; height: %d; colorsCount: %d", _width, _height, _colorsCount);
+}
+
+SpriteResource::~SpriteResource() {
+ delete[] _data;
+}
+
+// SoundResource
+SoundResource::SoundResource(byte *data, uint32 size) {
+ _data = data;
+ _size = size;
+}
+
+SoundResource::~SoundResource() {
+ delete[] _data;
+}
+
+} // End of namespace Gnap
diff --git a/engines/gnap/resource.h b/engines/gnap/resource.h
new file mode 100644
index 0000000000..f4a3669eda
--- /dev/null
+++ b/engines/gnap/resource.h
@@ -0,0 +1,190 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can 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 GNAP_RESOURCE_H
+#define GNAP_RESOURCE_H
+
+#include "common/array.h"
+#include "common/events.h"
+#include "common/file.h"
+#include "common/memstream.h"
+#include "common/str.h"
+#include "common/stream.h"
+#include "common/substream.h"
+#include "common/system.h"
+
+#include "graphics/surface.h"
+
+#include "gnap/datarchive.h"
+
+namespace Gnap {
+
+enum {
+ kResTypeSprite = 0,
+ kResTypeBitmap = 1,
+ kResTypeSound = 2,
+ kResTypeSequence = 3
+};
+
+struct SequenceFrame {
+ int16 _duration;
+ bool _isScaled;
+ Common::Rect _rect;
+ int32 _spriteId;
+ int32 _soundId;
+ void loadFromStream(Common::MemoryReadStream &stream);
+};
+
+struct SequenceAnimation {
+ int32 _additionalDelay;
+ int16 _framesCount;
+ int16 _maxTotalDuration;
+ SequenceFrame *frames;
+
+ SequenceAnimation() : frames(nullptr), _additionalDelay(0), _framesCount(0), _maxTotalDuration(0) {}
+ ~SequenceAnimation() { delete[] frames; }
+ void loadFromStream(Common::MemoryReadStream &stream);
+};
+
+class SequenceResource {
+public:
+ SequenceResource(byte *data, uint32 size);
+ ~SequenceResource();
+public:
+ int32 _sequenceId;
+ int32 _defaultId;
+ int32 _sequenceId2;
+ uint32 _defaultId2;
+ uint32 _flags;
+ int32 _totalDuration;
+ int16 _xOffs;
+ int16 _yOffs;
+ int32 _animationsCount;
+ SequenceAnimation *_animations;
+};
+
+class SpriteResource {
+public:
+ SpriteResource(byte *data, uint32 size);
+ ~SpriteResource();
+public:
+ byte *_data;
+ byte *_pixels;
+ uint32 *_palette;
+ int16 _width, _height;
+ uint16 _unknownVal1;
+ uint16 _unknownVal2;
+ bool _transparent;
+ uint16 _colorsCount;
+};
+
+class SoundResource {
+public:
+ SoundResource(byte *data, uint32 size);
+ ~SoundResource();
+public:
+ byte *_data;
+ uint32 _size;
+};
+
+template <class ResourceClass, int ResourceType, bool FreeAfterLoad>
+class ResourceCacheTemplate {
+public:
+
+ ResourceCacheTemplate(DatManager *dat) : _dat(dat) {
+ }
+
+ ~ResourceCacheTemplate() {
+ }
+
+ ResourceClass *get(int resourceId) {
+ Resource *resource = find(resourceId);
+ if (!resource) {
+ debug(9, "Loading resource type %d with ID %08X from disk", ResourceType, resourceId);
+ resource = new Resource(load(resourceId));
+ _cache[resourceId] = resource;
+ } else {
+ debug(9, "Resource type %d with ID %08X was in cache", ResourceType, resourceId);
+ }
+ resource->_isLocked = true;
+ return resource->_obj;
+ }
+
+ void release(int resourceId) {
+ Resource *resource = find(resourceId);
+ if (resource)
+ resource->_isLocked = false;
+ }
+
+ void purge(bool force = false) {
+ for (CacheMapIterator it = _cache.begin(); it != _cache.end(); ++it) {
+ Resource *resource = it->_value;
+ if (force || !resource->_isLocked) {
+ delete resource;
+ _cache.erase(it);
+ }
+ }
+ }
+
+protected:
+
+ struct Resource {
+ ResourceClass *_obj;
+ bool _isLocked;
+ Resource(ResourceClass *obj) : _obj(obj), _isLocked(false) {}
+ ~Resource() { delete _obj; }
+ };
+
+ typedef Common::HashMap<int, Resource *> CacheMap;
+ typedef typename CacheMap::iterator CacheMapIterator;
+
+ DatManager *_dat;
+ CacheMap _cache;
+
+ Resource *find(int resourceId) {
+ CacheMapIterator it = _cache.find(resourceId);
+ if (it != _cache.end())
+ return it->_value;
+ return nullptr;
+ }
+
+ ResourceClass *load(int resourceId) {
+ if (_dat->getResourceType(resourceId) != ResourceType)
+ error("ResourceCache::load() Wrong resource type: Expected %d, got %d", ResourceType, _dat->getResourceType(resourceId));
+
+ byte *resourceData = _dat->loadResource(resourceId);
+ uint32 resourceSize = _dat->getResourceSize(resourceId);
+ ResourceClass *obj = new ResourceClass(resourceData, resourceSize);
+ if (FreeAfterLoad)
+ delete[] resourceData;
+ return obj;
+ }
+
+};
+
+typedef ResourceCacheTemplate<SpriteResource, kResTypeSprite, false> SpriteCache;
+typedef ResourceCacheTemplate<SoundResource, kResTypeSound, false> SoundCache;
+typedef ResourceCacheTemplate<SequenceResource, kResTypeSequence, true> SequenceCache;
+
+} // End of namespace Gnap
+
+#endif // GNAP_RESOURCE_H
diff --git a/engines/gnap/scenes/arcade.cpp b/engines/gnap/scenes/arcade.cpp
new file mode 100644
index 0000000000..028a9006d0
--- /dev/null
+++ b/engines/gnap/scenes/arcade.cpp
@@ -0,0 +1,2729 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can 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 "gnap/gnap.h"
+#include "gnap/gamesys.h"
+#include "gnap/resource.h"
+#include "gnap/scenes/arcade.h"
+
+namespace Gnap {
+
+static const ObstacleDef kObstacleDefs[] = {
+ {0xB4, 15}, {0xCB, 14}, {0xCD, 13}, {0xCF, 15}, {0xBA, 14},
+ {0xCD, 13}, {0xCF, 12}, {0xCB, 15}, {0xBD, 13}, {0xCF, 12},
+ {0xCD, 11}, {0xCB, 15}, {0xB7, 12}, {0xCD, 11}, {0xCB, 10},
+ {0xCF, 15}, {0xCF, 14}, {0xBD, 13}, {0xCF, 12}, {0xCD, 11},
+ {0xCB, 15}, {0xCB, 13}, {0xB4, 12}, {0xCB, 11}, {0xCD, 10},
+ {0xCF, 15}, {0xCD, 12}, {0xBA, 12}, {0xCD, 12}, {0xCF, 12},
+ {0xCB, 15}, {0xCB, 9}, {0xCD, 9}, {0xCF, 9}, {0xCD, 9},
+ {0xCB, 9}, {0xCD, 9}, {0xCF, 5}, {0xBD, 13}, {0xCF, 8},
+ {0xCB, 8}, {0xCD, 15}, {0xB4, 1}, {0xBD, 7}, {0xCF, 7},
+ {0xCD, 7}, {0xCB, 7}, {0xCD, 7}, {0xCF, 15}, {0xCF, 15}
+};
+
+Scene49::Scene49(GnapEngine *vm) : Scene(vm) {
+ _scoreBarFlash = false;
+ _scoreBarPos = -1;
+ _scoreLevel = -1;
+ _obstacleIndex = -1;
+ _truckSequenceId = -1;
+ _truckId = -1;
+ _truckLaneNum = -1;
+
+ for (int i = 0; i < 5; i++) {
+ _obstacles[i]._currSequenceId = -1;
+ _obstacles[i]._closerSequenceId = -1;
+ _obstacles[i]._passedSequenceId = -1;
+ _obstacles[i]._splashSequenceId = -1;
+ _obstacles[i]._collisionSequenceId = -1;
+ _obstacles[i]._prevId = -1;
+ _obstacles[i]._currId = -1;
+ _obstacles[i]._laneNum = -1;
+ }
+}
+
+int Scene49::init() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ gameSys.setAnimation(0, 0, 0);
+ gameSys.setAnimation(0, 0, 1);
+ for (int i = 0; i < 5; ++i)
+ gameSys.setAnimation(0, 0, i + 2);
+ _vm->_timers[2] = 0;
+ _vm->_timers[0] = 0;
+ _vm->_timers[1] = 0;
+ _vm->clearKeyStatus1(Common::KEYCODE_ESCAPE);
+ _vm->clearKeyStatus1(Common::KEYCODE_RIGHT);
+ _vm->clearKeyStatus1(Common::KEYCODE_LEFT);
+ return 0xD5;
+}
+
+void Scene49::updateHotspots() {
+ _vm->_hotspotsCount = 0;
+}
+
+void Scene49::checkObstacles() {
+ if (_vm->_timers[2] == 0) {
+ if (_vm->_timers[3] == 0) {
+ for (int i = 0; i < 5; ++i)
+ clearObstacle(i);
+ }
+
+ for (int j = 0; j < 5; ++j) {
+ if (_obstacles[j]._currSequenceId == 0) {
+ _vm->_timers[3] = 35;
+ _obstacles[j]._currSequenceId = kObstacleDefs[_obstacleIndex]._sequenceId;
+ switch (_obstacles[j]._currSequenceId) {
+ case 0xB4:
+ _obstacles[j]._laneNum = 1;
+ _obstacles[j]._closerSequenceId = 180;
+ _obstacles[j]._passedSequenceId = 181;
+ _obstacles[j]._splashSequenceId = 182;
+ _obstacles[j]._collisionSequenceId = 192;
+ break;
+ case 0xB7:
+ _obstacles[j]._laneNum = 2;
+ _obstacles[j]._closerSequenceId = 183;
+ _obstacles[j]._passedSequenceId = 184;
+ _obstacles[j]._splashSequenceId = 185;
+ _obstacles[j]._collisionSequenceId = 193;
+ break;
+ case 0xBD:
+ _obstacles[j]._laneNum = 3;
+ _obstacles[j]._closerSequenceId = 189;
+ _obstacles[j]._passedSequenceId = 190;
+ _obstacles[j]._splashSequenceId = 191;
+ _obstacles[j]._collisionSequenceId = 195;
+ break;
+ case 0xBA:
+ _obstacles[j]._laneNum = 2;
+ _obstacles[j]._closerSequenceId = 186;
+ _obstacles[j]._passedSequenceId = 187;
+ _obstacles[j]._splashSequenceId = 188;
+ _obstacles[j]._collisionSequenceId = 194;
+ break;
+ case 0xCB:
+ _obstacles[j]._laneNum = 1;
+ _obstacles[j]._closerSequenceId = 203;
+ _obstacles[j]._passedSequenceId = 204;
+ _obstacles[j]._splashSequenceId = 0;
+ _obstacles[j]._collisionSequenceId = 209;
+ break;
+ case 0xCD:
+ _obstacles[j]._laneNum = 2;
+ _obstacles[j]._closerSequenceId = 205;
+ _obstacles[j]._passedSequenceId = 206;
+ _obstacles[j]._splashSequenceId = 0;
+ _obstacles[j]._collisionSequenceId = 210;
+ break;
+ case 0xCF:
+ _obstacles[j]._laneNum = 3;
+ _obstacles[j]._closerSequenceId = 207;
+ _obstacles[j]._passedSequenceId = 208;
+ _obstacles[j]._splashSequenceId = 0;
+ _obstacles[j]._collisionSequenceId = 211;
+ break;
+ }
+ _obstacles[j]._prevId = _truckId;
+ _obstacles[j]._currId = _obstacles[j]._prevId;
+ _vm->_gameSys->setAnimation(_obstacles[j]._currSequenceId, _obstacles[j]._currId, j + 2);
+ _vm->_gameSys->insertSequence(_obstacles[j]._currSequenceId, _obstacles[j]._currId, 0, 0, kSeqNone, 0, 0, -50);
+ _vm->_timers[2] = kObstacleDefs[_obstacleIndex]._ticks;
+ ++_obstacleIndex;
+ if (_obstacleIndex == 50)
+ _obstacleIndex = 0;
+ break;
+ }
+ }
+ }
+}
+
+void Scene49::updateObstacle(int id) {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ Scene49Obstacle &obstacle = _obstacles[id];
+ obstacle._currId = obstacle._prevId;
+
+ switch (obstacle._laneNum) {
+ case 1:
+ obstacle._prevId = _truckId + 1;
+ break;
+ case 2:
+ if (_truckLaneNum != 2 && _truckLaneNum != 3)
+ obstacle._prevId = _truckId - 1;
+ else
+ obstacle._prevId = _truckId + 1;
+ break;
+ case 3:
+ if (_truckLaneNum != 1 && _truckLaneNum != 2)
+ obstacle._prevId = _truckId;
+ else
+ obstacle._prevId = _truckId - 1;
+ break;
+ }
+
+ if (obstacle._currSequenceId == obstacle._closerSequenceId) {
+ if (_truckLaneNum == obstacle._laneNum) {
+ if (obstacle._splashSequenceId) {
+ gameSys.setAnimation(obstacle._collisionSequenceId, obstacle._prevId, id + 2);
+ gameSys.insertSequence(obstacle._collisionSequenceId, obstacle._prevId,
+ obstacle._currSequenceId, obstacle._currId,
+ kSeqSyncWait, 0, 0, -50);
+ obstacle._currSequenceId = obstacle._collisionSequenceId;
+ _vm->playSound(0xE0, false);
+ increaseScore(30);
+ } else if ((obstacle._laneNum == 1 && _truckSequenceId == 0xB0) ||
+ (obstacle._laneNum == 2 && (_truckSequenceId == 0xB1 || _truckSequenceId == 0xB2)) ||
+ (obstacle._laneNum == 3 && _truckSequenceId == 0xB3)) {
+ gameSys.setAnimation(obstacle._passedSequenceId, obstacle._prevId, id + 2);
+ gameSys.insertSequence(obstacle._passedSequenceId, obstacle._prevId,
+ obstacle._currSequenceId, obstacle._currId,
+ kSeqSyncWait, 0, 0, -50);
+ obstacle._currSequenceId = obstacle._passedSequenceId;
+ } else {
+ gameSys.setAnimation(obstacle._collisionSequenceId, 256, 0);
+ gameSys.setAnimation(obstacle._passedSequenceId, obstacle._prevId, id + 2);
+ gameSys.insertSequence(obstacle._passedSequenceId, obstacle._prevId,
+ obstacle._currSequenceId, obstacle._currId,
+ kSeqSyncWait, 0, 0, -50);
+ gameSys.insertSequence(obstacle._collisionSequenceId, 256,
+ _truckSequenceId, _truckId,
+ kSeqSyncExists, 0, 0, -50);
+ _truckSequenceId = obstacle._collisionSequenceId;
+ _truckId = 256;
+ obstacle._currSequenceId = obstacle._passedSequenceId;
+ _vm->playSound(0xE1, false);
+ decreaseScore(30);
+ }
+ } else {
+ gameSys.setAnimation(obstacle._passedSequenceId, obstacle._prevId, id + 2);
+ gameSys.insertSequence(obstacle._passedSequenceId, obstacle._prevId,
+ obstacle._currSequenceId, obstacle._currId,
+ kSeqSyncWait, 0, 0, -50);
+ obstacle._currSequenceId = obstacle._passedSequenceId;
+ }
+ } else if (obstacle._currSequenceId == obstacle._passedSequenceId) {
+ if (_truckLaneNum == obstacle._laneNum) {
+ if (obstacle._splashSequenceId) {
+ gameSys.setAnimation(obstacle._collisionSequenceId, obstacle._prevId, id + 2);
+ gameSys.insertSequence(obstacle._collisionSequenceId, obstacle._prevId,
+ obstacle._currSequenceId, obstacle._currId,
+ kSeqSyncWait, 0, 0, -50);
+ obstacle._currSequenceId = obstacle._collisionSequenceId;
+ _vm->playSound(0xE0, false);
+ increaseScore(30);
+ }
+ } else if (obstacle._splashSequenceId) {
+ gameSys.setAnimation(obstacle._splashSequenceId, obstacle._prevId, id + 2);
+ gameSys.insertSequence(obstacle._splashSequenceId, obstacle._prevId,
+ obstacle._currSequenceId, obstacle._currId,
+ kSeqSyncWait, 0, 0, -50);
+ obstacle._currSequenceId = obstacle._splashSequenceId;
+ }
+ } else {
+ gameSys.setAnimation(0, 0, id + 2);
+ clearObstacle(id);
+ }
+}
+
+void Scene49::increaseScore(int amount) {
+ if (_scoreBarPos + amount <= 556) {
+ _scoreBarPos += amount;
+ _vm->_gameSys->fillSurface(nullptr, _scoreBarPos, 508, amount, 22, 255, 0, 0);
+ }
+
+ _scoreLevel = (_scoreBarPos + amount >= 556) ? 1 : 0;
+}
+
+void Scene49::decreaseScore(int amount) {
+ if (_scoreBarPos >= 226 && _scoreLevel == 0) {
+ if (_scoreBarFlash)
+ refreshScoreBar();
+ _vm->_gameSys->fillSurface(nullptr, _scoreBarPos, 508, amount, 22, 89, 0, 5);
+ _scoreBarPos -= amount;
+ _scoreLevel = 0;
+ }
+}
+
+void Scene49::refreshScoreBar() {
+ if (_scoreBarFlash)
+ _vm->_gameSys->fillSurface(nullptr, 226, 508, 330, 22, 255, 0, 0);
+ else
+ _vm->_gameSys->fillSurface(nullptr, 226, 508, 330, 22, 89, 0, 5);
+ _scoreBarFlash = !_scoreBarFlash;
+}
+
+void Scene49::clearObstacle(int index) {
+ _obstacles[index]._currSequenceId = 0;
+ _obstacles[index]._closerSequenceId = 0;
+ _obstacles[index]._passedSequenceId = 0;
+ _obstacles[index]._splashSequenceId = 0;
+ _obstacles[index]._collisionSequenceId = 0;
+ _obstacles[index]._prevId = 0;
+ _obstacles[index]._currId = 0;
+ _obstacles[index]._laneNum = 0;
+}
+
+void Scene49::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ bool animToggle6 = false;
+ bool animToggle5 = false;
+ bool animToggle4 = false;
+ bool animToggle3 = false;
+ bool streetAnimToggle = false;
+ bool bgAnimToggle = false;
+
+ _vm->playSound(0xE2, true);
+ _vm->setSoundVolume(0xE2, 75);
+
+ _vm->hideCursor();
+ _vm->setGrabCursorSprite(-1);
+
+ _scoreBarPos = 196;
+ _scoreLevel = 0;
+ _scoreBarFlash = false;
+
+ switch (_vm->getRandom(3)) {
+ case 0:
+ _truckSequenceId = 0xAD;
+ _truckLaneNum = 1;
+ break;
+ case 1:
+ _truckSequenceId = 0xAE;
+ _truckLaneNum = 2;
+ break;
+ case 2:
+ _truckSequenceId = 0xAF;
+ _truckLaneNum = 3;
+ break;
+ }
+
+ int bgWidth1 = gameSys.getSpriteWidthById(0x5E);
+ int bgX1 = 600;
+
+ int bgWidth2 = gameSys.getSpriteWidthById(0x5F);
+ int bgX2 = 400;
+
+ int bgWidth3 = gameSys.getSpriteWidthById(4);
+ int bgX3 = 700;
+
+ int bgWidth4 = gameSys.getSpriteWidthById(5);
+ int bgX4 = 500;
+
+ int bgWidth5 = gameSys.getSpriteWidthById(6);
+ int bgX5 = 300;
+
+ int bgWidth6 = gameSys.getSpriteWidthById(7);
+ int bgX6 = 100;
+
+ gameSys.setAnimation(0xC8, 251, 1);
+ gameSys.setAnimation(_truckSequenceId, 256, 0);
+ gameSys.insertSequence(0xC9, 256, 0, 0, kSeqNone, 0, 600, 85);
+ gameSys.insertSequence(0xCA, 257, 0, 0, kSeqNone, 0, 400, 100);
+ gameSys.insertSequence(0xC4, 256, 0, 0, kSeqNone, 0, 700, 140);
+ gameSys.insertSequence(0xC5, 257, 0, 0, kSeqNone, 0, 500, 160);
+ gameSys.insertSequence(0xC6, 258, 0, 0, kSeqNone, 0, 300, 140);
+ gameSys.insertSequence(0xC7, 259, 0, 0, kSeqNone, 0, 100, 140);
+ gameSys.insertSequence(0xC8, 251, 0, 0, kSeqNone, 0, 0, -50);
+ gameSys.insertSequence(_truckSequenceId, 256, 0, 0, kSeqNone, 0, 0, -50);
+
+ _vm->_timers[0] = 2;
+
+ for (int i = 0; i < 5; ++i)
+ clearObstacle(i);
+
+ _obstacleIndex = 0;
+
+ _vm->_timers[2] = _vm->getRandom(20) + 10;
+
+ _truckId = 256;
+ _vm->_timers[3] = 35;
+
+ while (!_vm->_sceneDone) {
+ if (_vm->_timers[0] == 0) {
+ // Update background animations (clouds etc.)
+ --bgX1;
+ bgX2 -= 2;
+ bgX3 -= 5;
+ --bgX4;
+ --bgX5;
+ --bgX6;
+ if (bgX1 <= -bgWidth1)
+ bgX1 = 799;
+ if (bgX2 <= -bgWidth2)
+ bgX2 = 799;
+ if (bgX3 <= -bgWidth3)
+ bgX3 = 799;
+ if (bgX4 <= -bgWidth4)
+ bgX4 = 799;
+ if (bgX5 <= -bgWidth5)
+ bgX5 = 799;
+ if (bgX6 <= -bgWidth6)
+ bgX6 = 799;
+ bgAnimToggle = !bgAnimToggle;
+ gameSys.insertSequence(0xC9, (bgAnimToggle ? 1 : 0) + 256, 0xC9, (bgAnimToggle ? 0 : 1) + 256, kSeqSyncWait, 0, bgX1, 85);
+ gameSys.insertSequence(0xCA, (bgAnimToggle ? 1 : 0) + 257, 0xCA, (bgAnimToggle ? 0 : 1) + 257, kSeqSyncWait, 0, bgX2, 100);
+ gameSys.insertSequence(0xC4, (bgAnimToggle ? 1 : 0) + 256, 0xC4, (bgAnimToggle ? 0 : 1) + 256, kSeqSyncWait, 0, bgX3, 140);
+ gameSys.insertSequence(0xC5, (bgAnimToggle ? 1 : 0) + 257, 0xC5, (bgAnimToggle ? 0 : 1) + 257, kSeqSyncWait, 0, bgX4, 160);
+ gameSys.insertSequence(0xC6, (bgAnimToggle ? 1 : 0) + 258, 0xC6, (bgAnimToggle ? 0 : 1) + 258, kSeqSyncWait, 0, bgX5, 140);
+ gameSys.insertSequence(0xC7, (bgAnimToggle ? 1 : 0) + 259, 0xC7, (bgAnimToggle ? 0 : 1) + 259, kSeqSyncWait, 0, bgX6, 140);
+ _vm->_timers[0] = 2;
+ }
+
+ if (gameSys.getAnimationStatus(1) == 2) {
+ streetAnimToggle = !streetAnimToggle;
+ gameSys.setAnimation(0xC8, (streetAnimToggle ? 1 : 0) + 251, 1);
+ gameSys.insertSequence(0xC8, (streetAnimToggle ? 1 : 0) + 251, 200, (streetAnimToggle ? 0 : 1) + 251, kSeqSyncWait, 0, 0, -50);
+ }
+
+ checkObstacles();
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ switch (_truckSequenceId) {
+ case 0xB1:
+ _truckLaneNum = 1;
+ break;
+ case 0xB0:
+ case 0xB3:
+ _truckLaneNum = 2;
+ break;
+ case 0xB2:
+ _truckLaneNum = 3;
+ break;
+ }
+ animToggle3 = !animToggle3;
+ if (_truckLaneNum == 1) {
+ gameSys.setAnimation(0xAD, (animToggle3 ? 1 : 0) + 256, 0);
+ gameSys.insertSequence(0xAD, (animToggle3 ? 1 : 0) + 256, _truckSequenceId, _truckId, kSeqSyncWait, 0, 0, -50);
+ _truckSequenceId = 0xAD;
+ } else if (_truckLaneNum == 2) {
+ gameSys.setAnimation(0xAE, (animToggle3 ? 1 : 0) + 256, 0);
+ gameSys.insertSequence(0xAE, (animToggle3 ? 1 : 0) + 256, _truckSequenceId, _truckId, kSeqSyncWait, 0, 0, -50);
+ _truckSequenceId = 0xAE;
+ } else {
+ gameSys.setAnimation(0xAF, (animToggle3 ? 1 : 0) + 256, 0);
+ gameSys.insertSequence(0xAF, (animToggle3 ? 1 : 0) + 256, _truckSequenceId, _truckId, kSeqSyncWait, 0, 0, -50);
+ _truckSequenceId = 0xAF;
+ }
+ _truckId = (animToggle3 ? 1 : 0) + 256;
+ if (_scoreLevel == 1) {
+ if (!gameSys.isSequenceActive(0xD4, 266)) {
+ gameSys.setAnimation(0xD4, 266, 8);
+ gameSys.insertSequence(0xD4, 266, 0, 0, kSeqNone, 0, 0, -50);
+ }
+ ++_scoreLevel;
+ _vm->_timers[1] = 2;
+ animToggle4 = false;
+ animToggle5 = false;
+ animToggle6 = false;
+ _scoreBarFlash = false;
+ }
+ }
+
+ if (_scoreLevel != 0 && !_vm->_timers[1]) {
+ refreshScoreBar();
+ _vm->_timers[1] = 8;
+ if (animToggle6) {
+ if (animToggle5) {
+ if (animToggle4 && !gameSys.isSequenceActive(212, 266))
+ gameSys.insertSequence(212, 266, 0, 0, kSeqNone, 0, 0, -50);
+ animToggle4 = !animToggle4;
+ }
+ animToggle5 = !animToggle5;
+ }
+ animToggle6 = !animToggle6;
+ }
+
+ updateAnimations();
+
+ if (clearKeyStatus()) {
+ _vm->_sceneDone = true;
+ _vm->_newSceneNum = 2;
+ _vm->_newCursorValue = 1;
+ }
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_RIGHT)) {
+ // Steer right
+ if (_truckSequenceId == 0xB3)
+ _truckLaneNum = 2;
+ if (_truckSequenceId == 0xB1)
+ _truckLaneNum = 1;
+ if (_truckLaneNum != 3 && _truckLaneNum != 2) {
+ if (_scoreLevel) {
+ _vm->_sceneDone = true;
+ _vm->_newSceneNum = 47;
+ }
+ } else {
+ int steerSequenceId = (_truckLaneNum == 3) ? 0xB3 : 0xB1;
+ if (_truckSequenceId == 0xAE || _truckSequenceId == 0xAF) {
+ gameSys.setAnimation(steerSequenceId, 256, 0);
+ gameSys.insertSequence(steerSequenceId, 256, _truckSequenceId, _truckId, kSeqSyncExists, 0, 0, -50);
+ _truckSequenceId = steerSequenceId;
+ _truckId = 256;
+ }
+ }
+ _vm->clearKeyStatus1(Common::KEYCODE_RIGHT);
+ }
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_LEFT)) {
+ // Steer left
+ if (_truckSequenceId == 0xB0)
+ _truckLaneNum = 2;
+ if (_truckSequenceId == 0xB2)
+ _truckLaneNum = 3;
+ if (_truckLaneNum == 1 || _truckLaneNum == 2) {
+ int steerSequenceId = (_truckLaneNum == 1) ? 0xB0 : 0xB2;
+ if (_truckSequenceId == 0xAD || _truckSequenceId == 0xAE) {
+ gameSys.setAnimation(steerSequenceId, 256, 0);
+ gameSys.insertSequence(steerSequenceId, 256, _truckSequenceId, _truckId, kSeqSyncExists, 0, 0, -50);
+ _truckSequenceId = steerSequenceId;
+ _truckId = 256;
+ }
+ }
+ _vm->clearKeyStatus1(Common::KEYCODE_LEFT);
+ }
+ _vm->gameUpdateTick();
+ }
+ _vm->stopSound(0xE2);
+}
+
+void Scene49::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ for (int i = 0; i < 5; ++i) {
+ if (gameSys.getAnimationStatus(i + 2) == 2) {
+ if (_obstacles[i]._currSequenceId)
+ updateObstacle(i);
+ }
+ }
+
+ if (gameSys.getAnimationStatus(8) == 2) {
+ _vm->_sceneDone = true;
+ _vm->_newSceneNum = 47;
+ }
+}
+
+/*****************************************************************************/
+
+Scene50::Scene50(GnapEngine *vm) : Scene(vm) {
+ _fightDone = false;
+
+ _roundNum = -1;
+ _timeRemaining = -1;
+ _leftTongueRoundsWon = -1;
+ _rightTongueRoundsWon = -1;
+ _leftTongueSequenceId = -1;
+ _leftTongueId = -1;
+ _leftTongueNextSequenceId = -1;
+ _leftTongueNextId = -1;
+ _rightTongueSequenceId = -1;
+ _rightTongueId = -1;
+ _rightTongueNextSequenceId = -1;
+ _rightTongueNextId = -1;
+ _leftTongueEnergy = -1;
+ _rightTongueEnergy = -1;
+
+ _timesPlayed = 0;
+ _timesPlayedModifier = 0;
+ _attackCounter = 0;
+ _leftTongueEnergyBarPos = 10;
+ _leftTongueNextIdCtr = 0;
+ _rightTongueEnergyBarPos = 10;
+ _rightTongueNextIdCtr = 0;
+}
+
+int Scene50::init() {
+ return 0xC7;
+}
+
+void Scene50::updateHotspots() {
+ _vm->_hotspotsCount = 0;
+}
+
+bool Scene50::tongueWinsRound(int tongueNum) {
+ if (tongueNum == 1)
+ ++_leftTongueRoundsWon;
+ else
+ ++_rightTongueRoundsWon;
+ playWinBadgeAnim(tongueNum);
+ bool fightOver = _rightTongueRoundsWon == 2 || _leftTongueRoundsWon == 2;
+ playWinAnim(tongueNum, fightOver);
+ return fightOver;
+}
+
+void Scene50::playWinAnim(int tongueNum, bool fightOver) {
+ if (tongueNum == 1) {
+ if (fightOver) {
+ _vm->_gameSys->insertSequence(0xAD, 140, 0xAC, 140, kSeqSyncWait, 0, 0, 0);
+ _vm->_gameSys->insertSequence(0xB4, 100, _leftTongueSequenceId, _leftTongueId, kSeqSyncWait, 0, 0, 0);
+ _vm->_gameSys->insertSequence(0xBD, 100, _rightTongueSequenceId, _rightTongueId, kSeqSyncWait, 0, 0, 0);
+ _vm->_gameSys->insertSequence(0xBC, 100, 0xBD, 100, kSeqSyncWait, 0, 0, 0);
+ _leftTongueSequenceId = 0xB4;
+ _rightTongueSequenceId = 0xBC;
+ _rightTongueId = 100;
+ _leftTongueId = 100;
+ _vm->_gameSys->setAnimation(0xB4, 100, 6);
+ _vm->_gameSys->setAnimation(_rightTongueSequenceId, 100, 5);
+ waitForAnim(6);
+ waitForAnim(5);
+ _vm->invAdd(kItemGum);
+ _vm->setFlag(kGFUnk13);
+ } else {
+ _vm->_gameSys->insertSequence(0xB4, 100, _leftTongueSequenceId, _leftTongueId, kSeqSyncWait, 0, 0, 0);
+ _vm->_gameSys->insertSequence(0xBD, 100, _rightTongueSequenceId, _rightTongueId, kSeqSyncWait, 0, 0, 0);
+ _vm->_gameSys->insertSequence(0xBC, 100, 0xBD, 100, kSeqSyncWait, 0, 0, 0);
+ _leftTongueSequenceId = 0xB4;
+ _rightTongueSequenceId = 0xBC;
+ _rightTongueId = 100;
+ _leftTongueId = 100;
+ _vm->_gameSys->setAnimation(0xB4, 100, 6);
+ _vm->_gameSys->setAnimation(_rightTongueSequenceId, 100, 5);
+ waitForAnim(6);
+ waitForAnim(5);
+ }
+ } else {
+ _vm->_gameSys->insertSequence(0xBE, 100, _rightTongueSequenceId, _rightTongueId, kSeqSyncWait, 0, 0, 0);
+ _vm->_gameSys->setAnimation(0xBE, 100, 5);
+ waitForAnim(5);
+ _vm->_gameSys->insertSequence(0xBF, 100, 0xBE, 100, kSeqSyncWait, 0, 0, 0);
+ _vm->_gameSys->insertSequence(0xB5, 100, _leftTongueSequenceId, _leftTongueId, kSeqSyncWait, 0, 0, 0);
+ _rightTongueSequenceId = 0xBF;
+ _leftTongueSequenceId = 0xB5;
+ _rightTongueId = 100;
+ _leftTongueId = 100;
+ _vm->_gameSys->setAnimation(0xB5, 100, 6);
+ _vm->_gameSys->setAnimation(_rightTongueSequenceId, 100, 5);
+ waitForAnim(6);
+ waitForAnim(5);
+ }
+ _vm->delayTicksA(1, 7);
+}
+
+void Scene50::delayTicks() {
+ _vm->delayTicksA(3, 7);
+}
+
+void Scene50::initRound() {
+ _leftTongueEnergy = 10;
+ _rightTongueEnergy = 10;
+ _fightDone = false;
+ _vm->_timers[3] = getRightTongueActionTicks();
+ _vm->_timers[4] = 0;
+ _vm->_timers[6] = 0;
+ _vm->_gameSys->fillSurface(nullptr, 91, 73, 260, 30, 212, 0, 0);
+ _vm->_gameSys->fillSurface(nullptr, 450, 73, 260, 30, 212, 0, 0);
+ _timeRemaining = 40;
+ drawCountdown(40);
+}
+
+bool Scene50::updateCountdown() {
+ if (!_vm->_timers[5]) {
+ --_timeRemaining;
+ if (_timeRemaining < 0) {
+ return true;
+ } else {
+ _vm->_timers[5] = 15;
+ drawCountdown(_timeRemaining);
+ }
+ }
+ return false;
+}
+
+void Scene50::drawCountdown(int value) {
+ char str[8];
+ sprintf(str, "%02d", value);
+ _vm->_gameSys->fillSurface(nullptr, 371, 505, 50, 27, 0, 0, 0);
+ _vm->_gameSys->drawTextToSurface(nullptr, 381, 504, 255, 255, 255, str);
+}
+
+void Scene50::playTonguesIdle() {
+ _vm->_gameSys->insertSequence(0xBA, 100, _leftTongueSequenceId, _leftTongueId, kSeqSyncWait, 0, 0, 0);
+ _vm->_gameSys->insertSequence(0xC2, 100, _rightTongueSequenceId, _rightTongueId, kSeqSyncWait, 0, 0, 0);
+ _leftTongueSequenceId = 0xBA;
+ _rightTongueSequenceId = 0xC2;
+ _rightTongueNextSequenceId = -1;
+ _leftTongueNextSequenceId = -1;
+ _leftTongueId = 100;
+ _rightTongueId = 100;
+ _vm->_gameSys->setAnimation(0xC2, 100, 5);
+ _vm->_gameSys->setAnimation(_leftTongueSequenceId, _leftTongueId, 6);
+}
+
+void Scene50::playRoundAnim(int roundNum) {
+ int sequenceId = 0;
+
+ switch (roundNum) {
+ case 1:
+ sequenceId = 0xAF;
+ break;
+ case 2:
+ sequenceId = 0xB0;
+ break;
+ case 3:
+ sequenceId = 0xB1;
+ break;
+ }
+
+ _vm->_gameSys->insertSequence(sequenceId, 256, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->_gameSys->setAnimation(sequenceId, 256, 7);
+ waitForAnim(7);
+
+ _vm->_gameSys->insertSequence(0xAB, 256, sequenceId, 256, kSeqSyncWait, 0, 0, 0);
+ _vm->_gameSys->setAnimation(0xAB, 256, 7);
+ waitForAnim(7);
+}
+
+bool Scene50::updateEnergyBars(int newLeftBarPos, int newRightBarPos) {
+ if (newLeftBarPos != _leftTongueEnergyBarPos) {
+ if (newLeftBarPos < 0)
+ newLeftBarPos = 0;
+ _leftTongueEnergyBarPos = newLeftBarPos;
+ _vm->_gameSys->fillSurface(nullptr, 26 * newLeftBarPos + 91, 73, 260 - 26 * newLeftBarPos, 30, 0, 0, 0);
+ }
+
+ if (newRightBarPos != _rightTongueEnergyBarPos) {
+ if (newRightBarPos < 0)
+ newRightBarPos = 0;
+ _rightTongueEnergyBarPos = newRightBarPos;
+ if (newRightBarPos != 10)
+ _vm->_gameSys->fillSurface(nullptr, 26 * (9 - newRightBarPos) + 450, 73, 26, 30, 0, 0, 0);
+ }
+
+ if (newLeftBarPos * newRightBarPos > 0)
+ return false;
+
+ _leftTongueEnergyBarPos = 10;
+ _rightTongueEnergyBarPos = 10;
+ return true;
+}
+
+void Scene50::waitForAnim(int animationIndex) {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ while (gameSys.getAnimationStatus(animationIndex) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+
+ gameSys.setAnimation(0, 0, animationIndex);
+}
+
+int Scene50::checkInput() {
+ int sequenceId = -1;
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_RIGHT)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_RIGHT);
+ sequenceId = 0xB6;
+ } else if (_vm->isKeyStatus1(Common::KEYCODE_LEFT)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_LEFT);
+ sequenceId = 0xB3;
+ } else if (_vm->isKeyStatus1(Common::KEYCODE_ESCAPE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_ESCAPE);
+ _fightDone = true;
+ }
+
+ return sequenceId;
+}
+
+int Scene50::getRightTongueAction() {
+ int sequenceId = -1;
+
+ if (!_vm->_timers[3]) {
+ _vm->_timers[3] = getRightTongueActionTicks();
+ if (_rightTongueEnergy >= _leftTongueEnergy) {
+ switch (_vm->getRandom(5)) {
+ case 0:
+ sequenceId = 0xBE;
+ break;
+ case 1:
+ sequenceId = 0xBE;
+ break;
+ case 2:
+ sequenceId = 0xBB;
+ break;
+ case 3:
+ sequenceId = 0xBB;
+ break;
+ case 4:
+ sequenceId = 0xBB;
+ break;
+ }
+ } else {
+ switch (_vm->getRandom(4)) {
+ case 0:
+ sequenceId = 0xBE;
+ break;
+ case 1:
+ sequenceId = 0xBB;
+ break;
+ case 2:
+ sequenceId = 0xBE;
+ break;
+ case 3:
+ sequenceId = 0xBE;
+ break;
+ }
+ }
+ }
+
+ return sequenceId;
+}
+
+void Scene50::updateAnimations() {
+ if (!_vm->_timers[4])
+ _attackCounter = 0;
+
+ if (_vm->_gameSys->getAnimationStatus(5) == 2) {
+ if (_rightTongueSequenceId == 0xBE) {
+ if (_leftTongueSequenceId != 0xB3 && _leftTongueSequenceId != 0xB8)
+ _rightTongueNextSequenceId = 0xBF;
+ else
+ _rightTongueNextSequenceId = 0xC0;
+ }
+ if (_rightTongueNextSequenceId == -1)
+ _rightTongueNextSequenceId = 0xC2;
+ if (_rightTongueNextSequenceId == 0xBF) {
+ _leftTongueNextId = getLeftTongueNextId();
+ _rightTongueNextId = getRightTongueNextId();
+ _vm->_gameSys->setAnimation(_rightTongueNextSequenceId, _rightTongueNextId, 5);
+ _vm->_gameSys->setAnimation(0xB9, _leftTongueNextId, 6);
+ _vm->_gameSys->insertSequence(_rightTongueNextSequenceId, _rightTongueNextId, _rightTongueSequenceId, _rightTongueId, kSeqSyncWait, 0, 0, 0);
+ _vm->_gameSys->insertSequence(0xB9, _leftTongueNextId, _leftTongueSequenceId, _leftTongueId, kSeqSyncExists, 0, 0, 0);
+ _rightTongueSequenceId = _rightTongueNextSequenceId;
+ _rightTongueNextSequenceId = -1;
+ _leftTongueSequenceId = 0xB9;
+ _leftTongueNextSequenceId = -1;
+ _rightTongueId = _rightTongueNextId;
+ _leftTongueId = _leftTongueNextId;
+ _leftTongueEnergy -= _vm->getRandom(1) + 1;
+ } else {
+ _rightTongueNextId = getRightTongueNextId();
+ _vm->_gameSys->setAnimation(_rightTongueNextSequenceId, _rightTongueNextId, 5);
+ _vm->_gameSys->insertSequence(_rightTongueNextSequenceId, _rightTongueNextId, _rightTongueSequenceId, _rightTongueId, kSeqSyncWait, 0, 0, 0);
+ _rightTongueSequenceId = _rightTongueNextSequenceId;
+ _rightTongueNextSequenceId = -1;
+ _rightTongueId = _rightTongueNextId;
+ }
+ }
+
+ if (_vm->_gameSys->getAnimationStatus(6) == 2) {
+ if (_leftTongueSequenceId == 0xB6) {
+ ++_attackCounter;
+ if (_timesPlayedModifier + 3 <= _attackCounter) {
+ _leftTongueNextSequenceId = 0xB8;
+ } else {
+ _vm->_timers[4] = 20;
+ if (_rightTongueSequenceId != 0xBB && _rightTongueSequenceId != 0xC0 && _vm->getRandom(7) != _roundNum)
+ _leftTongueNextSequenceId = 0xB7;
+ else
+ _leftTongueNextSequenceId = 0xB8;
+ }
+ }
+ if (_leftTongueNextSequenceId == 0xB3)
+ --_attackCounter;
+ if (_leftTongueNextSequenceId == -1)
+ _leftTongueNextSequenceId = 0xBA;
+ if (_leftTongueNextSequenceId == 0xB7) {
+ _leftTongueNextId = getLeftTongueNextId();
+ _rightTongueNextId = getRightTongueNextId();
+ _vm->_gameSys->setAnimation(_leftTongueNextSequenceId, _leftTongueNextId, 6);
+ _vm->_gameSys->setAnimation(0xC1, _rightTongueNextId, 5);
+ _vm->_gameSys->insertSequence(_leftTongueNextSequenceId, _leftTongueNextId, _leftTongueSequenceId, _leftTongueId, kSeqSyncWait, 0, 0, 0);
+ _vm->_gameSys->insertSequence(0xC1, _rightTongueNextId, _rightTongueSequenceId, _rightTongueId, kSeqSyncExists, 0, 0, 0);
+ _leftTongueSequenceId = _leftTongueNextSequenceId;
+ _leftTongueNextSequenceId = -1;
+ _rightTongueSequenceId = 0xC1;
+ _rightTongueNextSequenceId = -1;
+ _rightTongueId = _rightTongueNextId;
+ _leftTongueId = _leftTongueNextId;
+ --_rightTongueEnergy;
+ } else if (_leftTongueNextSequenceId != 0xB8 || _rightTongueSequenceId != 0xC2) {
+ _leftTongueNextId = getLeftTongueNextId();
+ _vm->_gameSys->setAnimation(_leftTongueNextSequenceId, _leftTongueNextId, 6);
+ _vm->_gameSys->insertSequence(_leftTongueNextSequenceId, _leftTongueNextId, _leftTongueSequenceId, _leftTongueId, kSeqSyncWait, 0, 0, 0);
+ _leftTongueSequenceId = _leftTongueNextSequenceId;
+ _leftTongueNextSequenceId = -1;
+ _leftTongueId = _leftTongueNextId;
+ } else {
+ _leftTongueNextId = getLeftTongueNextId();
+ _rightTongueNextId = getRightTongueNextId();
+ _vm->_gameSys->setAnimation(0xBB, _rightTongueNextId, 5);
+ _vm->_gameSys->setAnimation(_leftTongueNextSequenceId, _leftTongueNextId, 6);
+ _vm->_gameSys->insertSequence(_leftTongueNextSequenceId, _leftTongueNextId, _leftTongueSequenceId, _leftTongueId, kSeqSyncWait, 0, 0, 0);
+ _vm->_gameSys->insertSequence(0xBB, _rightTongueNextId, _rightTongueSequenceId, _rightTongueId, kSeqSyncExists, 0, 0, 0);
+ _rightTongueSequenceId = 0xBB;
+ _rightTongueId = _rightTongueNextId;
+ _rightTongueNextSequenceId = -1;
+ _leftTongueSequenceId = _leftTongueNextSequenceId;
+ _leftTongueNextSequenceId = -1;
+ _leftTongueId = _leftTongueNextId;
+ }
+ }
+}
+
+int Scene50::getRightTongueActionTicks() {
+ return 15 - 5 * _roundNum + 1;
+}
+
+int Scene50::getLeftTongueNextId() {
+ _leftTongueNextIdCtr = (_leftTongueNextIdCtr + 1) % 3;
+ return _leftTongueNextIdCtr + 100;
+}
+
+int Scene50::getRightTongueNextId() {
+ _rightTongueNextIdCtr = (_rightTongueNextIdCtr + 1) % 3;
+ return _rightTongueNextIdCtr + 100;
+}
+
+void Scene50::playWinBadgeAnim(int tongueNum) {
+ int sequenceId;
+
+ if (tongueNum == 1) {
+ if (_leftTongueRoundsWon == 1)
+ sequenceId = 0xC3;
+ else
+ sequenceId = 0xC4;
+ } else {
+ if (_rightTongueRoundsWon == 1)
+ sequenceId = 0xC5;
+ else
+ sequenceId = 0xC6;
+ }
+
+ _vm->_gameSys->setAnimation(sequenceId, 120, 7);
+ _vm->_gameSys->insertSequence(sequenceId, 120, 0, 0, kSeqNone, 0, 0, 0);
+ waitForAnim(7);
+}
+
+void Scene50::run() {
+ ++_timesPlayed;
+ _timesPlayedModifier = _timesPlayed / 4;
+ _leftTongueRoundsWon = 0;
+ _rightTongueRoundsWon = 0;
+ // initFont();
+ _leftTongueSequenceId = 186;
+ _rightTongueSequenceId = 194;
+ _rightTongueNextSequenceId = -1;
+ _leftTongueNextSequenceId = -1;
+ _leftTongueId = 100;
+ _rightTongueId = 100;
+
+ _vm->_gameSys->setAnimation(194, 100, 5);
+ _vm->_gameSys->setAnimation(_leftTongueSequenceId, _leftTongueId, 6);
+ _vm->_gameSys->insertSequence(_leftTongueSequenceId, _leftTongueId, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->_gameSys->insertSequence(_rightTongueSequenceId, _rightTongueId, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->_gameSys->insertSequence(172, 140, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->endSceneInit();
+
+ initRound();
+
+ _roundNum = 1;
+
+ _vm->setGrabCursorSprite(-1);
+ _vm->hideCursor();
+
+ _vm->delayTicksA(1, 7);
+
+ playRoundAnim(_roundNum);
+
+ _vm->_timers[5] = 15;
+
+ while (!_fightDone && !_vm->_gameDone) {
+ int playerSequenceId = checkInput();
+ if (playerSequenceId != -1)
+ _leftTongueNextSequenceId = playerSequenceId;
+
+ int rightSequenceId = getRightTongueAction();
+ if (rightSequenceId != -1)
+ _rightTongueNextSequenceId = rightSequenceId;
+
+ updateAnimations();
+
+ if (updateCountdown() ||
+ updateEnergyBars(_leftTongueEnergy, _rightTongueEnergy)) {
+ bool v0;
+ if (_rightTongueEnergy < _leftTongueEnergy)
+ v0 = tongueWinsRound(1);
+ else
+ v0 = tongueWinsRound(2);
+ if (v0) {
+ delayTicks();
+ _fightDone = true;
+ } else {
+ ++_roundNum;
+ initRound();
+ playTonguesIdle();
+ updateEnergyBars(_leftTongueEnergy, _rightTongueEnergy);
+ playRoundAnim(_roundNum);
+ _vm->_timers[5] = 15;
+ }
+ }
+ _vm->gameUpdateTick();
+ }
+
+ _vm->_gameSys->setAnimation(0, 0, 7);
+ _vm->_gameSys->setAnimation(0, 0, 6);
+ _vm->_gameSys->setAnimation(0, 0, 5);
+ _vm->_gameSys->setAnimation(0, 0, 3);
+
+ _vm->showCursor();
+}
+
+/*****************************************************************************/
+
+static const int kDigitSequenceIds[] = {
+ 0xCA, 0xCB, 0xCC, 0xCD, 0xCE,
+ 0xCF, 0xD0, 0xD1, 0xD2, 0xD3
+};
+
+static const int kDigitPositions[4] = {
+ 0, 34, 83, 119
+};
+
+/*
+ 0xBA Falling banana peel
+ 0xBC Banana peel goes away
+ 0xBD Falling coin
+ 0xBE Fallen coin
+ 0xC0 Falling banknote
+ 0xB6 Platypus tripping (right)
+ 0xB7 Platypus tripping (left)
+ 0x76 Platypus jumping (right)
+*/
+
+Scene51::Scene51(GnapEngine *vm) : Scene(vm) {
+ _dropLoseCash = false;
+
+ _cashAmount = -1;
+ _guySequenceId = -1;
+ _guyNextSequenceId = -1;
+ _itemsCaughtCtr = -1;
+ _dropSpeedTicks = -1;
+ _nextDropItemKind = -1;
+ _itemInsertX = -1;
+ _itemInsertDirection = -1;
+ _platypusSequenceId = -1;
+ _platypusNextSequenceId = -1;
+ _platypusJumpSequenceId = -1;
+ _itemsCtr = -1;
+ _itemsCtr1 = -1;
+ _itemsCtr2 = -1;
+
+ for (int i = 0; i < 4; i++) {
+ _digits[i] = 0;
+ _digitSequenceIds[i] = -1;
+ }
+
+ for (int i = 0; i < 6; i++) {
+ _items[i]._currSequenceId = -1;
+ _items[i]._droppedSequenceId = 0;
+ _items[i]._x = 0;
+ _items[i]._y = 0;
+ _items[i]._collisionX = 0;
+ _items[i]._canCatch = false;
+ _items[i]._isCollision = false;
+ _items[i]._x2 = 0;
+ _items[i]._id = -1;
+ }
+}
+
+int Scene51::init() {
+ _vm->_gameSys->setAnimation(0, 0, 0);
+ for (int i = 0; i < 6; ++i)
+ _vm->_gameSys->setAnimation(0, 0, i + 1);
+ return 0xD4;
+}
+
+void Scene51::updateHotspots() {
+ _vm->_hotspotsCount = 0;
+}
+
+void Scene51::clearItem(Scene51Item *item) {
+ item->_currSequenceId = 0;
+ item->_droppedSequenceId = 0;
+ item->_x = 0;
+ item->_y = 0;
+ item->_x2 = 0;
+ item->_collisionX = 0;
+ item->_canCatch = false;
+}
+
+void Scene51::dropNextItem() {
+ if (_vm->_timers[0])
+ return;
+
+ int index = 0;
+ while (index < 6 && _items[index]._currSequenceId)
+ ++index;
+
+ if (index == 6)
+ return;
+
+ switch (_nextDropItemKind) {
+ case 0:
+ if (_vm->getRandom(10) != 0 || _itemsCtr2 >= 2) {
+ _items[index]._currSequenceId = 0xBD;
+ } else {
+ --_itemsCtr1;
+ _items[index]._currSequenceId = 0xBA;
+ ++_itemsCtr2;
+ }
+ break;
+
+ case 1:
+ if (_vm->getRandom(8) != 0 || _itemsCtr2 >= 2) {
+ if (_vm->getRandom(5) == 0) {
+ if (_itemInsertDirection)
+ _itemInsertX -= 70;
+ else
+ _itemInsertX += 70;
+ }
+ _items[index]._currSequenceId = 0xBD;
+ } else {
+ --_itemsCtr1;
+ _items[index]._currSequenceId = 0xBA;
+ ++_itemsCtr2;
+ }
+ break;
+
+ case 2:
+ if (_vm->getRandom(6) != 0 || _itemsCtr2 >= 2) {
+ _items[index]._currSequenceId = 0xBD;
+ } else {
+ --_itemsCtr1;
+ _items[index]._currSequenceId = 0xBA;
+ ++_itemsCtr2;
+ }
+ break;
+
+ case 3:
+ case 4:
+ if (_itemsCtr == 0)
+ _itemsCtr1 = 3;
+ _items[index]._currSequenceId = 0xC0;
+ break;
+
+ case 5:
+ case 6:
+ if (_vm->getRandom(5) != 0 || _itemsCtr2 >= 2) {
+ if (_vm->getRandom(5) != 0)
+ _items[index]._currSequenceId = 0xBD;
+ else
+ _items[index]._currSequenceId = 0xC0;
+ } else {
+ --_itemsCtr1;
+ _items[index]._currSequenceId = 0xBA;
+ ++_itemsCtr2;
+ }
+ break;
+
+ case 7:
+ if (_vm->getRandom(5) != 0 || _itemsCtr2 >= 2) {
+ if (_vm->getRandom(5) == 0) {
+ if (_itemInsertDirection)
+ _itemInsertX -= 40;
+ else
+ _itemInsertX += 40;
+ }
+ if (_vm->getRandom(9) != 0)
+ _items[index]._currSequenceId = 0xBD;
+ else
+ _items[index]._currSequenceId = 0xC0;
+ } else {
+ --_itemsCtr1;
+ _items[index]._currSequenceId = 0xBA;
+ ++_itemsCtr2;
+ }
+ break;
+
+ default:
+ if (_vm->getRandom(4) != 0 || _itemsCtr2 >= 2) {
+ if (_vm->getRandom(9) != 0)
+ _items[index]._currSequenceId = 0xBD;
+ else
+ _items[index]._currSequenceId = 0xC0;
+ } else {
+ --_itemsCtr1;
+ _items[index]._currSequenceId = 0xBA;
+ ++_itemsCtr2;
+ }
+ break;
+ }
+
+ if (_itemInsertDirection) {
+ _itemInsertX -= 73;
+ if (_itemInsertX < 129) {
+ _itemInsertX += 146;
+ _itemInsertDirection = 0;
+ }
+ } else {
+ _itemInsertX += 73;
+ if (_itemInsertX > 685) {
+ _itemInsertX -= 146;
+ _itemInsertDirection = 1;
+ }
+ }
+
+ if (_itemInsertX > 685)
+ _itemInsertX = 685;
+
+ if (_itemInsertX < 129)
+ _itemInsertX = 129;
+
+ if (_items[index]._currSequenceId == 0xBA) {
+ _items[index]._x2 = _vm->getRandom(350) + 200;
+ _items[index]._x = _items[index]._x2 - 362;
+ _items[index]._y = 15;
+ _items[index]._id = 249 - index;
+ } else {
+ _items[index]._collisionX = _itemInsertX;
+ _items[index]._x = _items[index]._collisionX - 395;
+ if (_items[index]._currSequenceId == 0xC0)
+ _items[index]._x -= 65;
+ _items[index]._id = index + 250;
+ _items[index]._canCatch = true;
+ }
+
+ _vm->_gameSys->setAnimation(_items[index]._currSequenceId, _items[index]._id, index + 1);
+ _vm->_gameSys->insertSequence(_items[index]._currSequenceId, _items[index]._id, 0, 0,
+ kSeqNone, 0, _items[index]._x, _items[index]._y);
+
+ _vm->_timers[0] = _dropSpeedTicks;
+
+ if (_nextDropItemKind >= 3)
+ _vm->_timers[0] = 20;
+
+ if (_nextDropItemKind >= 5)
+ _vm->_timers[0] = 5;
+
+ if (_nextDropItemKind == 8)
+ _vm->_timers[0] = 4;
+
+ ++_itemsCtr;
+}
+
+void Scene51::updateItemAnimations() {
+ for (int i = 0; i < 6; ++i) {
+ if (_vm->_gameSys->getAnimationStatus(i + 1) == 2)
+ updateItemAnimation(&_items[i], i);
+ }
+}
+
+int Scene51::checkCollision(int sequenceId) {
+ if (!isJumping(sequenceId))
+ return false;
+
+ bool jumpingLeft = false, jumpingRight = false;
+ int v8 = 0, v4 = 0;
+ int result = 0;
+
+ bool checkFl = false;
+ for (int i = 0; i < 6; i++)
+ checkFl |= _items[i]._isCollision;
+
+ if (!checkFl)
+ return false;
+
+ if (isJumpingRight(sequenceId)) {
+ v8 = getPosRight(sequenceId);
+ v4 = getPosRight(sequenceId + 1);
+ jumpingRight = true;
+ } else if (isJumpingLeft(sequenceId)) {
+ v4 = getPosLeft(sequenceId - 1) + 33;
+ v8 = getPosLeft(sequenceId) + 33;
+ jumpingLeft = true;
+ }
+
+ if (jumpingRight || jumpingLeft) {
+ int v5 = 0;
+ int i;
+ for (i = 0; i < 6; ++i) {
+ if (_items[i]._isCollision) {
+ if (jumpingRight && _items[i]._x2 > v8 && _items[i]._x2 < v4) {
+ v5 = v8 - 359;
+ if (v5 == 0)
+ v5 = 1;
+ _platypusNextSequenceId = 0xB6;
+ break;
+ } else if (jumpingLeft && _items[i]._x2 < v4 && _items[i]._x2 > v8) {
+ v5 = v8 - 344;
+ if (v5 == 0)
+ v5 = 1;
+ _platypusNextSequenceId = 0xB7;
+ break;
+ }
+ }
+ }
+ if (v5) {
+ _vm->_gameSys->setAnimation(0xBC, _items[i]._id, i + 1);
+ _vm->_gameSys->insertSequence(0xBC, _items[i]._id, _items[i]._currSequenceId, _items[i]._id, kSeqSyncWait, 0, _items[i]._x, 15);
+ _items[i]._isCollision = false;
+ _items[i]._currSequenceId = 0xBC;
+ --_itemsCtr2;
+ }
+ result = v5;
+ }
+
+ return result;
+}
+
+void Scene51::updateItemAnimation(Scene51Item *item, int index) {
+
+ switch (item->_currSequenceId) {
+ case 0xBD:
+ case 0xC0:
+ case 0xC1:
+ // Falling coin and banknote
+ if (!itemIsCaught(item)) {
+ if (_dropLoseCash) {
+ if (item->_currSequenceId == 0xBD)
+ _cashAmount -= 2;
+ else
+ _cashAmount -= 25;
+ if (_cashAmount < 0)
+ _cashAmount = 0;
+ updateCash(_cashAmount);
+ }
+ item->_droppedSequenceId = item->_currSequenceId + 1;
+ if (item->_currSequenceId != 0xC0) {
+ item->_canCatch = false;
+ _dropLoseCash = true;
+ _itemsCtr = 0;
+ _vm->_timers[0] = 10;
+ }
+ if (item->_droppedSequenceId) {
+ _vm->_gameSys->setAnimation(item->_droppedSequenceId, item->_id, index + 1);
+ _vm->_gameSys->insertSequence(item->_droppedSequenceId, item->_id, item->_currSequenceId, item->_id, kSeqSyncWait, 0, item->_x, item->_y);
+ item->_currSequenceId = item->_droppedSequenceId;
+ item->_y = 0;
+ }
+ } else {
+ _vm->_gameSys->removeSequence(item->_currSequenceId, item->_id, true);
+ _vm->_gameSys->setAnimation(0, 0, index + 1);
+ _vm->playSound(0xDA, false);
+ if (incCashAmount(item->_currSequenceId) == 1995) {
+ winMinigame();
+ _vm->_sceneDone = true;
+ } else {
+ clearItem(item);
+ ++_itemsCaughtCtr;
+ if (_itemsCaughtCtr == 5)
+ --_dropSpeedTicks;
+ if (_itemsCaughtCtr == 8)
+ --_dropSpeedTicks;
+ if (_itemsCaughtCtr == 11)
+ --_dropSpeedTicks;
+ if (_itemsCaughtCtr == 14)
+ --_dropSpeedTicks;
+ if (_itemsCaughtCtr >= 15 && _dropSpeedTicks > 4)
+ --_dropSpeedTicks;
+ if (_itemsCtr1 <= _itemsCaughtCtr) {
+ ++_nextDropItemKind;
+ _dropSpeedTicks = 10;
+ _itemsCtr = 0;
+ _itemsCtr1 = 20;
+ _dropLoseCash = false;
+ _itemsCaughtCtr = 0;
+ removeCollidedItems();
+ }
+ }
+ }
+ break;
+
+ case 0xBE:
+ // Fallen coin
+ item->_droppedSequenceId = item->_currSequenceId + 1;
+ if (item->_droppedSequenceId) {
+ _vm->_gameSys->setAnimation(item->_droppedSequenceId, item->_id, index + 1);
+ _vm->_gameSys->insertSequence(item->_droppedSequenceId, item->_id, item->_currSequenceId, item->_id, kSeqSyncWait, 0, item->_x, item->_y);
+ item->_currSequenceId = item->_droppedSequenceId;
+ item->_y = 0;
+ }
+ break;
+
+ case 0xBF:
+ case 0xC2:
+ // Bouncing coin and banknote
+ _vm->_gameSys->setAnimation(0, 0, index + 1);
+ _vm->_gameSys->removeSequence(item->_currSequenceId, item->_id, true);
+ clearItem(item);
+ break;
+
+ case 0xBA:
+ // Falling banana peel
+ item->_droppedSequenceId = 0xBB;
+ item->_y = 15;
+ if (item->_droppedSequenceId) {
+ _vm->_gameSys->setAnimation(item->_droppedSequenceId, item->_id, index + 1);
+ _vm->_gameSys->insertSequence(item->_droppedSequenceId, item->_id, item->_currSequenceId, item->_id, kSeqSyncWait, 0, item->_x, item->_y);
+ item->_currSequenceId = item->_droppedSequenceId;
+ item->_y = 0;
+ }
+ break;
+
+ case 0xBB:
+ item->_isCollision = true;
+ item->_droppedSequenceId = 0;
+ _vm->_gameSys->setAnimation(0, 0, index + 1);
+ break;
+
+ case 0xBC:
+ _vm->_gameSys->removeSequence(item->_currSequenceId, item->_id, true);
+ _vm->_gameSys->setAnimation(0, 0, index + 1);
+ clearItem(item);
+ break;
+
+ default:
+ if (item->_droppedSequenceId) {
+ _vm->_gameSys->setAnimation(item->_droppedSequenceId, item->_id, index + 1);
+ _vm->_gameSys->insertSequence(item->_droppedSequenceId, item->_id, item->_currSequenceId, item->_id, kSeqSyncWait, 0, item->_x, item->_y);
+ item->_currSequenceId = item->_droppedSequenceId;
+ item->_y = 0;
+ }
+ break;
+ }
+}
+
+void Scene51::removeCollidedItems() {
+ for (int i = 0; i < 6; ++i) {
+ if (_items[i]._isCollision) {
+ _vm->_gameSys->removeSequence(_items[i]._currSequenceId, _items[i]._id, true);
+ _vm->_gameSys->setAnimation(0, 0, i + 1);
+ clearItem(&_items[i]);
+ }
+ }
+ _itemsCtr2 = 0;
+}
+
+int Scene51::itemIsCaught(Scene51Item *item) {
+ if (!item->_canCatch)
+ return 0;
+
+ if (isJumpingRight(_platypusJumpSequenceId)) {
+ int v4 = getPosRight(_platypusJumpSequenceId) + 97;
+ if (item->_collisionX < v4 && v4 - item->_collisionX < 56)
+ return 1;
+ } else {
+ int v2 = getPosLeft(_platypusJumpSequenceId);
+ if (item->_collisionX > v2 && item->_collisionX - v2 < 56)
+ return 1;
+ }
+
+ if (item->_currSequenceId == 0xC1) {
+ int v3 = item->_collisionX + 100;
+ if (isJumpingRight(_platypusJumpSequenceId)) {
+ if (ABS(getPosRight(_platypusJumpSequenceId) + 46 - v3) < 56)
+ return 1;
+ } else if (ABS(getPosLeft(_platypusJumpSequenceId) + 46 - v3) < 56) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+bool Scene51::isJumpingRight(int sequenceId) {
+ return sequenceId >= 0x76 && sequenceId <= 0x95;
+}
+
+bool Scene51::isJumpingLeft(int sequenceId) {
+ return sequenceId >= 0x96 && sequenceId <= 0xB5;
+}
+
+bool Scene51::isJumping(int sequenceId) {
+ return sequenceId >= 0x76 && sequenceId <= 0xB5;
+}
+
+void Scene51::waitForAnim(int animationIndex) {
+ while (_vm->_gameSys->getAnimationStatus(animationIndex) != 2 && _vm->_gameDone) {
+ updateItemAnimations();
+ _vm->gameUpdateTick();
+ }
+}
+
+int Scene51::getPosRight(int sequenceId) {
+ static const int kRightPosTbl[] = {
+ 131, 159, 178, 195, 203, 219, 238, 254,
+ 246, 274, 293, 310, 318, 334, 353, 369,
+ 362, 390, 409, 426, 434, 450, 469, 485,
+ 477, 505, 524, 541, 549, 565, 584, 600
+ };
+
+ if (sequenceId >= 118 && sequenceId <= 149)
+ return kRightPosTbl[sequenceId - 118];
+ return -1;
+}
+
+int Scene51::getPosLeft(int sequenceId) {
+ static const int kLeftPosTbl[] = {
+ 580, 566, 550, 536, 526, 504, 488, 469,
+ 460, 446, 430, 416, 406, 384, 368, 349,
+ 342, 328, 312, 298, 288, 266, 250, 231,
+ 220, 206, 190, 176, 166, 144, 128, 109
+ };
+
+ if (sequenceId >= 150 && sequenceId <= 181)
+ return kLeftPosTbl[sequenceId - 150];
+ return -1;
+}
+
+void Scene51::playIntroAnim() {
+ int soundCtr = 0;
+
+ _platypusSequenceId = 0x76;
+ _platypusNextSequenceId = 0x76;
+
+ for (int i = 0; i < 6; ++i)
+ clearItem(&_items[i]);
+
+ _items[0]._currSequenceId = 0xBA;
+ _items[0]._x2 = 320;
+ _items[0]._x = -42;
+ _items[0]._y = 15;
+ _items[0]._id = 249;
+ _items[0]._isCollision = true;
+
+ _vm->_gameSys->insertSequence(_platypusSequenceId, 256, 0, 0, kSeqNone, 0, -179, 0);
+ _vm->_gameSys->insertSequence(0xBA, 249, 0, 0, kSeqNone, 0, _items[0]._x, _items[0]._y);
+ _vm->_gameSys->setAnimation(0xBA, 249, 1);
+ _vm->_gameSys->setAnimation(_platypusSequenceId, 256, 0);
+
+ while (_platypusSequenceId < 0x80) {
+ waitForAnim(0);
+ ++_platypusNextSequenceId;
+ _vm->_gameSys->setAnimation(_platypusNextSequenceId, 256, 0);
+ _vm->_gameSys->insertSequence(_platypusNextSequenceId, 256, _platypusSequenceId, 256, kSeqSyncWait, 0, -179, 0);
+ _platypusSequenceId = _platypusNextSequenceId;
+ ++soundCtr;
+ if (soundCtr % 4 == 0)
+ _vm->playSound(0xD6, false);
+ }
+
+ _platypusNextSequenceId = 0x75;
+
+ while (_platypusSequenceId != 0x84) {
+ waitForAnim(0);
+ ++_platypusNextSequenceId;
+ int oldSequenceId = _platypusNextSequenceId;
+ int v0 = checkCollision(_platypusNextSequenceId);
+ _vm->_gameSys->setAnimation(_platypusNextSequenceId, 256, 0);
+ _vm->_gameSys->insertSequence(_platypusNextSequenceId, 256, _platypusSequenceId, 256, kSeqSyncWait, 0, v0, 0);
+ _platypusSequenceId = _platypusNextSequenceId;
+ if (v0) {
+ _platypusNextSequenceId = oldSequenceId;
+ } else {
+ ++soundCtr;
+ if (soundCtr % 4 == 0)
+ _vm->playSound(0xD6, false);
+ }
+ }
+ waitForAnim(0);
+}
+
+void Scene51::updateGuyAnimation() {
+ if (!_vm->_timers[4]) {
+ _vm->_timers[4] = _vm->getRandom(20) + 60;
+
+ switch (_vm->getRandom(5)) {
+ case 0:
+ _guyNextSequenceId = 0xC3;
+ break;
+ case 1:
+ _guyNextSequenceId = 0xC4;
+ break;
+ case 2:
+ _guyNextSequenceId = 0xC5;
+ break;
+ case 3:
+ _guyNextSequenceId = 0xC6;
+ break;
+ case 4:
+ _guyNextSequenceId = 0xC7;
+ break;
+ }
+
+ _vm->_gameSys->insertSequence(_guyNextSequenceId, 39, _guySequenceId, 39, kSeqSyncWait, 0, 0, 0);
+ _guySequenceId = _guyNextSequenceId;
+ _guyNextSequenceId = -1;
+ }
+}
+
+int Scene51::incCashAmount(int sequenceId) {
+ switch (sequenceId) {
+ case 0xBD:
+ _cashAmount += 10;
+ break;
+ case 0xC0:
+ case 0xC1:
+ _cashAmount += 100;
+ break;
+ case 0xB6:
+ case 0xB7:
+ _cashAmount -= 10 * _vm->getRandom(5) + 50;
+ if (_cashAmount < 0)
+ _cashAmount = 0;
+ break;
+ }
+ if (_cashAmount > 1995)
+ _cashAmount = 1995;
+ updateCash(_cashAmount);
+ return _cashAmount;
+}
+
+void Scene51::winMinigame() {
+ updateCash(1995);
+ _vm->playSound(0xDA, false);
+ _vm->delayTicksA(1, 5);
+ _vm->_newSceneNum = 48;
+ _vm->invRemove(kItemBanana);
+}
+
+void Scene51::playCashAppearAnim() {
+ _vm->_gameSys->setAnimation(0xC8, 252, 0);
+ _vm->_gameSys->insertSequence(0xC8, 252, 0, 0, kSeqNone, 0, -20, -20);
+
+ while (_vm->_gameSys->getAnimationStatus(0) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+}
+
+void Scene51::updateCash(int amount) {
+ drawDigit(amount / 1000, 0);
+ drawDigit(amount / 100 % 10, 1);
+ drawDigit(amount / 10 % 10, 2);
+ drawDigit(amount % 10, 3);
+}
+
+void Scene51::drawDigit(int digit, int position) {
+ if (digit != _digits[position]) {
+ _vm->_gameSys->insertSequence(kDigitSequenceIds[digit], 253 + position,
+ _digitSequenceIds[position], 253 + position,
+ kSeqSyncWait, 0, kDigitPositions[position] - 20, -20);
+ _digitSequenceIds[position] = kDigitSequenceIds[digit];
+ _digits[position] = digit;
+ }
+}
+
+void Scene51::initCashDisplay() {
+ for (int position = 0; position < 4; ++position) {
+ _digits[position] = 0;
+ _digitSequenceIds[position] = kDigitSequenceIds[0];
+ _vm->_gameSys->insertSequence(kDigitSequenceIds[0], 253 + position, 0, 0, kSeqNone, 0, kDigitPositions[position] - 20, -20);
+ }
+ _cashAmount = 0;
+}
+
+void Scene51::run() {
+ int soundCtr = 0;
+ bool isIdle = true;
+
+ _itemsCtr = 0;
+ _vm->_newSceneNum = _vm->_prevSceneNum;
+ _cashAmount = 0;
+ _platypusJumpSequenceId = 0x84;
+ _vm->endSceneInit();
+
+ _vm->hideCursor();
+ _vm->setGrabCursorSprite(-1);
+
+ _guySequenceId = 0xC3;
+ _guyNextSequenceId = -1;
+
+ _vm->_gameSys->insertSequence(0xC3, 39, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->_timers[4] = _vm->getRandom(20) + 60;
+
+ playCashAppearAnim();
+ initCashDisplay();
+ playIntroAnim();
+
+ _platypusNextSequenceId = 0x74;
+ _vm->_gameSys->setAnimation(0x74, 256, 0);
+ _vm->_gameSys->insertSequence(_platypusNextSequenceId, 256, _platypusSequenceId, 256, kSeqSyncWait, 0, getPosRight(_platypusJumpSequenceId) - 362, 0);
+ _platypusSequenceId = _platypusNextSequenceId;
+
+ _itemInsertDirection = 0;
+ _itemInsertX = 685;
+ _dropSpeedTicks = 10;
+ _nextDropItemKind = 0;
+
+ for (int i = 0; i < 6; ++i)
+ clearItem(&_items[i]);
+
+ _itemInsertX = _vm->getRandom(556) + 129;
+ _vm->_timers[0] = 15;
+
+ _itemsCaughtCtr = 0;
+ _dropLoseCash = false;
+ _itemsCtr1 = 20;
+
+ _vm->clearKeyStatus1(Common::KEYCODE_RIGHT);
+ _vm->clearKeyStatus1(Common::KEYCODE_LEFT);
+ _vm->clearKeyStatus1(Common::KEYCODE_UP);
+ _vm->clearKeyStatus1(Common::KEYCODE_SPACE);
+ _vm->clearKeyStatus1(Common::KEYCODE_ESCAPE);
+
+ bool isCollision = false;
+ bool startWalk = true;
+
+ while (!_vm->_sceneDone) {
+ if (clearKeyStatus())
+ _vm->_sceneDone = true;
+
+ _vm->gameUpdateTick();
+
+ updateGuyAnimation();
+ dropNextItem();
+ updateItemAnimations();
+
+ if (_vm->isKeyStatus2(Common::KEYCODE_UP) || _vm->isKeyStatus2(Common::KEYCODE_SPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_UP);
+ _vm->clearKeyStatus1(Common::KEYCODE_SPACE);
+ if (isJumpingRight(_platypusJumpSequenceId)) {
+ waitForAnim(0);
+ _vm->_gameSys->setAnimation(0xB8, 256, 0);
+ _vm->_gameSys->insertSequence(0xB8, 256, _platypusSequenceId, 256, kSeqSyncWait, 0, getPosRight(_platypusJumpSequenceId) - 348, 0);
+ _platypusSequenceId = 0xB8;
+ waitForAnim(0);
+ _platypusNextSequenceId += 6;
+ if (_platypusNextSequenceId > 0x95)
+ _platypusNextSequenceId = 0x95;
+ _platypusJumpSequenceId = _platypusNextSequenceId;
+ } else {
+ waitForAnim(0);
+ _vm->_gameSys->setAnimation(0xB9, 256, 0);
+ _vm->_gameSys->insertSequence(0xB9, 256, _platypusSequenceId, 256, kSeqSyncWait, 0, getPosLeft(_platypusJumpSequenceId) - 338, 0);
+ _platypusSequenceId = 0xB9;
+ waitForAnim(0);
+ _platypusNextSequenceId += 6;
+ if (_platypusNextSequenceId > 0xB5)
+ _platypusNextSequenceId = 0xB5;
+ _platypusJumpSequenceId = _platypusNextSequenceId;
+ }
+ isIdle = false;
+ }
+
+ while (_vm->isKeyStatus2(Common::KEYCODE_RIGHT) && _platypusNextSequenceId != 0x96 && !_vm->_gameDone) {
+ if (_platypusNextSequenceId == 0xB6)
+ _platypusNextSequenceId = 0x76;
+ updateItemAnimations();
+ if (startWalk) {
+ _platypusNextSequenceId = 0x86;
+ startWalk = false;
+ }
+
+ if (_vm->_gameSys->getAnimationStatus(0) == 2) {
+ int collisionX = checkCollision(_platypusNextSequenceId);
+ if (collisionX)
+ incCashAmount(_platypusNextSequenceId);
+ _vm->_gameSys->setAnimation(_platypusNextSequenceId, 256, 0);
+ _vm->_gameSys->insertSequence(_platypusNextSequenceId, 256, _platypusSequenceId, 256, kSeqSyncWait, 0, collisionX, 0);
+ _platypusSequenceId = _platypusNextSequenceId;
+ if (collisionX) {
+ isCollision = true;
+ ++_platypusJumpSequenceId;
+ _platypusNextSequenceId = _platypusJumpSequenceId;
+ } else {
+ _platypusJumpSequenceId = _platypusNextSequenceId;
+ }
+ if (isJumpingRight(_platypusJumpSequenceId)) {
+ ++_platypusNextSequenceId;
+ if (!isCollision) {
+ if (_vm->isKeyStatus2(Common::KEYCODE_UP) || _vm->isKeyStatus2(Common::KEYCODE_SPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_UP);
+ _vm->clearKeyStatus1(Common::KEYCODE_SPACE);
+ waitForAnim(0);
+ _vm->_gameSys->setAnimation(0xB8, 256, 0);
+ _vm->_gameSys->insertSequence(0xB8, 256, _platypusSequenceId, 256, kSeqSyncWait, 0, getPosRight(_platypusJumpSequenceId) - 348, 0);
+ _platypusSequenceId = 0xB8;
+ waitForAnim(0);
+ _platypusNextSequenceId += 6;
+ if (_platypusNextSequenceId > 0x95)
+ _platypusNextSequenceId = 0x95;
+ _platypusJumpSequenceId = _platypusNextSequenceId;
+ } else {
+ ++soundCtr;
+ if (soundCtr % 4 == 0)
+ _vm->playSound(0xD6, false);
+ }
+ }
+ } else {
+ _platypusNextSequenceId = 150 - (_platypusJumpSequenceId - 150);
+ }
+ isCollision = false;
+ isIdle = false;
+ }
+ _vm->gameUpdateTick();
+ }
+
+ while (_vm->isKeyStatus2(Common::KEYCODE_LEFT) && _platypusNextSequenceId != 0xB6 && !_vm->_gameDone) {
+ updateItemAnimations();
+ if (startWalk) {
+ _platypusNextSequenceId = 0xA5;
+ startWalk = false;
+ }
+
+ if (_vm->_gameSys->getAnimationStatus(0) == 2) {
+ int collisionX = checkCollision(_platypusNextSequenceId);
+ if (collisionX)
+ incCashAmount(_platypusNextSequenceId);
+ _vm->_gameSys->setAnimation(_platypusNextSequenceId, 256, 0);
+ _vm->_gameSys->insertSequence(_platypusNextSequenceId, 256, _platypusSequenceId, 256, kSeqSyncWait, 0, collisionX, 0);
+ _platypusSequenceId = _platypusNextSequenceId;
+ if (collisionX) {
+ isCollision = true;
+ ++_platypusJumpSequenceId;
+ _platypusNextSequenceId = _platypusJumpSequenceId;
+ } else {
+ _platypusJumpSequenceId = _platypusNextSequenceId;
+ }
+ if (isJumpingLeft(_platypusJumpSequenceId)) {
+ ++_platypusNextSequenceId;
+ if (!isCollision) {
+ if (_vm->isKeyStatus2(Common::KEYCODE_UP) || _vm->isKeyStatus2(Common::KEYCODE_SPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_UP);
+ _vm->clearKeyStatus1(Common::KEYCODE_SPACE);
+ waitForAnim(0);
+ _vm->_gameSys->setAnimation(0xB9, 256, 0);
+ _vm->_gameSys->insertSequence(0xB9, 256, _platypusSequenceId, 256, kSeqSyncWait, 0, getPosLeft(_platypusJumpSequenceId) - 338, 0);
+ _platypusSequenceId = 0xB9;
+ waitForAnim(0);
+ _platypusNextSequenceId += 6;
+ if (_platypusNextSequenceId > 0xB5)
+ _platypusNextSequenceId = 0xB5;
+ _platypusJumpSequenceId = _platypusNextSequenceId;
+ } else {
+ ++soundCtr;
+ if (soundCtr % 4 == 0)
+ _vm->playSound(0xD6, false);
+ }
+ }
+ } else {
+ _platypusNextSequenceId = 182 - (_platypusJumpSequenceId - 118);
+ }
+ isCollision = false;
+ isIdle = false;
+ }
+ _vm->gameUpdateTick();
+ }
+
+ if (!isIdle && _vm->_gameSys->getAnimationStatus(0) == 2) {
+ if (isJumpingRight(_platypusJumpSequenceId)) {
+ _vm->_gameSys->setAnimation(0x74, 256, 0);
+ _vm->_gameSys->insertSequence(0x74, 256, _platypusSequenceId, 256, kSeqSyncWait, 0, getPosRight(_platypusJumpSequenceId) - 362, 0);
+ _platypusSequenceId = 0x74;
+ } else {
+ _vm->_gameSys->setAnimation(0x75, 256, 0);
+ _vm->_gameSys->insertSequence(0x75, 256, _platypusSequenceId, 256, kSeqSyncWait, 0, getPosLeft(_platypusJumpSequenceId) - 341, 0);
+ _platypusSequenceId = 0x75;
+ }
+ waitForAnim(0);
+ isIdle = true;
+ }
+ }
+
+ _vm->clearKeyStatus1(Common::KEYCODE_ESCAPE);
+ _vm->clearKeyStatus1(Common::KEYCODE_UP);
+ _vm->clearKeyStatus1(Common::KEYCODE_SPACE);
+ _vm->clearKeyStatus1(Common::KEYCODE_RIGHT);
+ _vm->clearKeyStatus1(Common::KEYCODE_LEFT);
+
+ _vm->_gameSys->setAnimation(0, 0, 0);
+ for (int i = 0; i < 6; ++i)
+ _vm->_gameSys->setAnimation(0, 0, i + 1);
+
+ _vm->showCursor();
+}
+
+/*****************************************************************************/
+
+Scene52::Scene52(GnapEngine *vm) : Scene(vm) {
+ _gameScore = 0;
+ _aliensInitialized = false;
+ _alienDirection = 0;
+ _soundToggle = false;
+ _arcadeScreenBottom = 0;
+ _shipsLeft = 0;
+ _shipPosX = 0;
+ _shipCannonPosX = 0;
+ _shipCannonPosY = 0;
+ _shipCannonFiring = false;
+ _shipCannonFired = false;
+ _shipCannonWidth = 0;
+ _shipCannonHeight = 0;
+ _shipCannonTopY = 0;
+ _shipMidX = 0;
+ _shipMidY = 0;
+ _shipFlag = false;
+ _alienSpeed = 0;
+ _alienWidth = 0;
+ _alienHeight = 0;
+ _alienLeftX = 0;
+ _alienTopY = 0;
+ _alienRowDownCtr = 0;
+ _alienWave = false;
+ _alienSingle = false;
+ _alienCounter = 0;
+ _bottomAlienFlag = false;
+ _aliensCount = 0;
+ _nextUfoSequenceId = -1;
+ _ufoSequenceId = -1;
+}
+
+int Scene52::init() {
+ initAnims();
+ return 0x2B;
+}
+
+void Scene52::updateHotspots() {
+ _vm->_hotspotsCount = 0;
+}
+
+void Scene52::update() {
+ for (int rowNum = 0; rowNum < 7 && !_vm->_gameDone; ++rowNum) {
+ _vm->gameUpdateTick();
+ if (_vm->_gameSys->getAnimationStatus(_alienRowAnims[rowNum]) == 2) {
+ updateAlienRow(rowNum);
+ rowNum = 0;
+ }
+ }
+
+ if (_liveAlienRows == 0 && !_alienSingle) {
+ _alienWave = false;
+ _vm->playSound(0x30, false);
+ ++_alienCounter;
+ if (_alienCounter != 3) {
+ _vm->_timers[0] = 50;
+ _vm->_timers[2] = 100;
+ _alienRowDownCtr = 0;
+ _alienSingle = true;
+ }
+ }
+
+ if (_alienSingle && !_vm->_timers[0]) {
+ initAliens();
+ _alienSingle = false;
+ _vm->_timers[2] = 5;
+ _alienWave = true;
+ }
+
+ if ((_alienRowDownCtr || _liveAlienRows == 0) && !_alienSingle) {
+ moveDownAlienRow();
+ _alienRowDownCtr = 0;
+ }
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_UP) || _vm->isKeyStatus1(Common::KEYCODE_SPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_SPACE);
+ _vm->clearKeyStatus1(Common::KEYCODE_UP);
+ if (!_aliensCount)
+ fireShipCannon(_shipPosX);
+ }
+
+ if (_shipCannonFiring)
+ updateShipCannon();
+
+ fireAlienCannon();
+ updateAlienCannons();
+
+ if (_aliensCount == 1) {
+ _alienWave = false;
+ _vm->_timers[3] = 20;
+ _vm->_timers[2] = 100;
+ ++_aliensCount;
+ }
+
+ if (_aliensCount && !_vm->_timers[3]) {
+ updateAliens();
+ loseShip();
+ if (_shipsLeft != 0) {
+ _vm->_timers[3] = 40;
+ while (_vm->_timers[3] && !_vm->_gameDone) {
+ updateAlienCannons();
+ if (_shipCannonFiring)
+ updateShipCannon();
+ _vm->gameUpdateTick();
+ }
+ initAliens();
+ _shipPosX = (800 - _shipMidX) / 2;
+ _vm->_gameSys->setAnimation(_nextUfoSequenceId, 256, 7);
+ _vm->_gameSys->insertSequence(_nextUfoSequenceId, 256, 0, 0, kSeqNone, 0, _shipPosX, _arcadeScreenBottom);
+ _ufoSequenceId = _nextUfoSequenceId;
+ _vm->_timers[2] = 5;
+ _alienWave = true;
+ } else {
+ _vm->_sceneDone = true;
+ }
+ }
+
+ _nextUfoSequenceId = 34;
+ if (_ufoSequenceId != 34)
+ _shipFlag = true;
+
+ if (_shipFlag) {
+ if (_vm->_gameSys->getAnimationStatus(7) == 2) {
+ _vm->_gameSys->setAnimation(_nextUfoSequenceId, 256, 7);
+ _vm->_gameSys->insertSequence(_nextUfoSequenceId, 256, _ufoSequenceId, 256, kSeqSyncWait, 0, _shipPosX, _arcadeScreenBottom);
+ _ufoSequenceId = _nextUfoSequenceId;
+ }
+ _shipFlag = false;
+ }
+
+ if (_alienWave && !_vm->_timers[0]) {
+ playSound();
+ int delay = CLIP(_alienSpeed, 2, 10);
+ _vm->_timers[0] = delay;
+ }
+}
+
+void Scene52::initShipCannon(int bottomY) {
+ _shipCannonFired = false;
+ _shipCannonWidth = MAX(_vm->_gameSys->getSpriteWidthById(14), _vm->_gameSys->getSpriteWidthById(16));
+ _shipCannonHeight = MAX(_vm->_gameSys->getSpriteHeightById(14), _vm->_gameSys->getSpriteHeightById(16));
+ _shipCannonTopY = bottomY - _shipCannonHeight;
+ _shipCannonFiring = false;
+}
+
+void Scene52::initAlienCannons() {
+ for (int i = 0; i < 3; ++i) {
+ _alienCannonIds[i] = 0;
+ _alienCannonFired[i] = 0;
+ }
+ _alienCannonSequenceIds[0] = 30;
+ _alienCannonSequenceIds[1] = 31;
+ _alienCannonSequenceIds[2] = 32;
+}
+
+void Scene52::fireShipCannon(int posX) {
+ if (_vm->_timers[1])
+ return;
+
+ int cannonNum = getFreeShipCannon();
+ if (cannonNum != -1) {
+ _shipCannonPosX = _shipMidX / 2 + posX - _shipCannonWidth / 2;
+ _shipCannonPosY = _shipCannonTopY;
+ _vm->_gameSys->setAnimation(0x23, cannonNum + 256, cannonNum + 8);
+ _vm->_gameSys->insertSequence(0x23, cannonNum + 256, 0, 0, kSeqNone, 0, _shipCannonPosX, _shipCannonPosY);
+ _vm->playSound(0x2D, false);
+ if (shipCannonHitShield(cannonNum)) {
+ _vm->_gameSys->setAnimation(0, 0, cannonNum + 8);
+ _vm->_gameSys->removeSequence(0x23, cannonNum + 256, true);
+ } else {
+ _shipCannonFired = true;
+ _shipCannonPosY -= 13;
+ _shipCannonFiring = true;
+ }
+ _vm->_timers[1] = 5;
+ }
+}
+
+void Scene52::fireAlienCannon() {
+ if (_vm->_timers[2])
+ return;
+
+ int cannonNum = getFreeAlienCannon();
+ if (cannonNum != -1) {
+ int alienX1 = _alienLeftX + _alienRowXOfs[0];
+ int alienX2 = _alienLeftX + _alienRowXOfs[0] + 5 * _alienWidth - (_alienWidth / 2 - 15);
+ _alienCannonPosX[cannonNum] = _vm->getRandom(alienX2 - alienX1) + alienX1;
+ _alienCannonPosY[cannonNum] = 104;
+ _alienCannonFired[cannonNum] = 1;
+ _vm->_gameSys->setAnimation(_alienCannonSequenceIds[cannonNum], _alienCannonIds[cannonNum] + 256, cannonNum + 9);
+ _vm->_gameSys->insertSequence(_alienCannonSequenceIds[cannonNum], _alienCannonIds[cannonNum] + 256, 0, 0,
+ kSeqNone, 0, _alienCannonPosX[cannonNum], _alienCannonPosY[cannonNum]);
+ _alienCannonPosY[cannonNum] -= 13;
+ _vm->_timers[2] = 5;
+ }
+}
+
+int Scene52::getFreeShipCannon() {
+ if (!_shipCannonFired)
+ return 0;
+ return -1;
+}
+
+int Scene52::getFreeAlienCannon() {
+ for (int i = 0; i < 3; ++i)
+ if (!_alienCannonFired[i])
+ return i;
+ return -1;
+}
+
+void Scene52::updateShipCannon() {
+ if (_shipCannonFired && _vm->_gameSys->getAnimationStatus(8) == 2) {
+ _shipCannonPosY -= 13;
+ if (_shipCannonPosY - 13 >= 135) {
+ if (updateHitAlien()) {
+ _vm->_gameSys->setAnimation(0, 0, 8);
+ _vm->_gameSys->removeSequence(35, 256, true);
+ _shipCannonFired = false;
+ drawScore(_gameScore);
+ } else {
+ _vm->_gameSys->setAnimation(35, 256, 8);
+ _vm->_gameSys->insertSequence(35, 256, 35, 256, kSeqSyncWait, 0, _shipCannonPosX, _shipCannonPosY);
+ _shipCannonPosY -= 13;
+ }
+ } else {
+ _vm->_gameSys->setAnimation(0, 0, 8);
+ _vm->_gameSys->removeSequence(35, 256, true);
+ _shipCannonFired = false;
+ }
+ }
+}
+
+void Scene52::updateAlienCannons() {
+ for (int i = 0; i < 3; ++i) {
+ if (_alienCannonFired[i] && _vm->_gameSys->getAnimationStatus(i + 9) == 2) {
+ _alienCannonPosY[i] += 13;
+ if (_shipCannonHeight + _alienCannonPosY[i] + 13 <= 550) {
+ if (alienCannonHitShip(i)) {
+ _vm->_gameSys->setAnimation(0, 0, i + 9);
+ _alienCannonFired[i] = 0;
+ shipExplode();
+ } else if (alienCannonHitShield(i)) {
+ _alienCannonFired[i] = 0;
+ } else {
+ _vm->_gameSys->insertSequence(_alienCannonSequenceIds[i], 1 - _alienCannonIds[i] + 256, 0, 0,
+ kSeqNone, 0, _alienCannonPosX[i], _alienCannonPosY[i]);
+ _vm->_gameSys->setAnimation(_alienCannonSequenceIds[i], 1 - _alienCannonIds[i] + 256, i + 9);
+ _alienCannonIds[i] = 1 - _alienCannonIds[i];
+ _alienCannonPosY[i] += 13;
+ }
+ } else {
+ _vm->_gameSys->setAnimation(0, 0, i + 9);
+ _alienCannonFired[i] = 0;
+ }
+ }
+ }
+}
+
+void Scene52::initAliens() {
+ if (!_aliensInitialized) {
+ initAlienSize();
+ _aliensInitialized = true;
+ }
+
+ _liveAlienRows = 0;
+ _alienSpeed = 0;
+ _bottomAlienFlag = false;
+ _aliensCount = 0;
+ _alienSingle = false;
+ _alienRowDownCtr = 0;
+
+ initShields();
+
+ _alienRowKind[0] = -1;
+ _alienRowKind[1] = -1;
+ _alienRowKind[2] = -1;
+ _alienRowKind[3] = -1;
+ _alienRowKind[4] = _vm->getRandom(2) != 0 ? 24 : 27;
+ _alienRowKind[5] = _vm->getRandom(2) != 0 ? 25 : 28;
+ _alienRowKind[6] = _vm->getRandom(2) != 0 ? 26 : 29;
+
+ for (int i = 0; i < 7; ++i) {
+ _alienRowAnims[i] = i;
+ _alienRowXOfs[i] = 0;
+ initAlienRowKind(i, _alienRowKind[i]);
+ insertAlienRow(i);
+ }
+}
+
+void Scene52::initAlienRowKind(int rowNum, int alienKind) {
+ for (int i = 0; i < 5; ++i)
+ _items[rowNum][i] = alienKind;
+}
+
+void Scene52::insertAlienRow(int rowNum) {
+ if (_alienRowKind[rowNum] >= 0) {
+ insertAlienRowAliens(rowNum);
+ _alienRowIds[rowNum] = 256;
+ _vm->_gameSys->setAnimation(_alienRowKind[rowNum], _alienRowIds[rowNum], _alienRowAnims[rowNum]);
+ ++_liveAlienRows;
+ }
+}
+
+void Scene52::insertAlienRowAliens(int rowNum) {
+ int xOffs = _alienLeftX;
+ int yOffs = _alienTopY - 52 * rowNum - _alienHeight + 10;
+ for (int i = 0; i < 5; ++i) {
+ if (_items[rowNum][i] >= 0) {
+ _vm->_gameSys->insertSequence(_items[rowNum][i], i + 256, 0, 0, kSeqNone, 0, xOffs, yOffs);
+ ++_alienSpeed;
+ }
+ xOffs += _alienWidth;
+ }
+}
+
+void Scene52::updateAlienRow(int rowNum) {
+ if (_alienRowKind[rowNum] != -1 && !checkAlienRow(rowNum)) {
+ updateAlienRowXOfs();
+ _alienRowIds[rowNum] = -1;
+ int xOffs = _alienLeftX + _alienRowXOfs[rowNum];
+ int yOffs = _alienTopY - 52 * rowNum - _alienHeight + 10;
+ for (int i = 0; i < 5; ++i) {
+ if (_items[rowNum][i] >= 0) {
+ _vm->_gameSys->insertSequence(_items[rowNum][i], i + 256, _items[rowNum][i], i + 256, kSeqSyncWait, 0, xOffs, yOffs);
+ if (_alienRowIds[rowNum] == -1)
+ _alienRowIds[rowNum] = i + 256;
+ } else if (_items[rowNum][i] == -2) {
+ _vm->_gameSys->removeSequence(_alienRowKind[rowNum], i + 256, true);
+ _items[rowNum][i] = -1;
+ --_alienSpeed;
+ }
+ xOffs += _alienWidth;
+ }
+ if (_alienRowIds[rowNum] == -1) {
+ _vm->_gameSys->setAnimation(0, 0, _alienRowAnims[rowNum]);
+ // MessageBoxA(0, "No live aliens!", "Error 3:", 0x30u);
+ } else {
+ _vm->_gameSys->setAnimation(_alienRowKind[rowNum], _alienRowIds[rowNum], _alienRowAnims[rowNum]);
+ }
+ if (rowNum == 1) {
+ for (int j = 0; j < 3; ++j) {
+ if (_shieldSpriteIds[j] != -1) {
+ _vm->_gameSys->fillSurface(nullptr, _shieldPosX[j], _arcadeScreenBottom - 44, 33, 44, 0, 0, 0);
+ _shieldSpriteIds[j] = -1;
+ }
+ }
+ }
+ if (rowNum == 0 && _bottomAlienFlag)
+ shipExplode();
+ }
+}
+
+void Scene52::moveDownAlienRow() {
+ int v2[5], v3, v1, v0, v4;
+
+ for (int i = 0; i < 5; ++i)
+ v2[i] = _items[0][i];
+
+ v3 = _alienRowIds[0];
+ v1 = _alienRowAnims[0];
+ v0 = _alienRowKind[0];
+ v4 = _alienRowXOfs[0];
+
+ for (int j = 0; j < 7; ++j) {
+ for (int i = 0; i < 5; ++i)
+ _items[j][i] = _items[j + 1][i];
+ _alienRowIds[j] = _alienRowIds[j + 1];
+ _alienRowAnims[j] = _alienRowAnims[j + 1];
+ _alienRowKind[j] = _alienRowKind[j + 1];
+ _alienRowXOfs[j] = _alienRowXOfs[j + 1];
+ }
+
+ for (int i = 0; i < 5; ++i)
+ _items[6][i] = v2[i];
+
+ _alienRowIds[6] = v3;
+ _alienRowAnims[6] = v1;
+ _alienRowKind[6] = v0;
+ _alienRowXOfs[6] = v4;
+
+ updateAlien(6);
+ initAlienRowKind(6, _alienRowKind[6]);
+ insertAlienRow(6);
+
+ _bottomAlienFlag = _alienRowKind[0] > -1;
+}
+
+int Scene52::updateHitAlien() {
+ int result = 0, rowNum, ya;
+
+ int y = _shipCannonTopY - _shipCannonPosY;
+
+ if (y == 26) {
+ rowNum = 1;
+ ya = _shipCannonPosY + 26;
+ } else {
+ if (y % 52)
+ return 0;
+ rowNum = y / 52 + 1;
+ ya = _shipCannonPosY;
+ }
+
+ if (rowNum < 7) {
+ int hitAlienNum = getHitAlienNum(rowNum);
+ if (hitAlienNum != -1 && _items[rowNum][hitAlienNum] >= 0) {
+ _gameScore = ((_items[rowNum][hitAlienNum] - 24) % 3 + _gameScore + 1) % 1000;
+ _items[rowNum][hitAlienNum] = -2;
+ _vm->playSound(0x2C, false);
+ _vm->_gameSys->insertSequence(0x21, 266, 0, 0,
+ kSeqNone, 0, _alienLeftX + hitAlienNum * _alienWidth + _alienRowXOfs[rowNum] - 10, ya - _alienHeight);
+ result = 1;
+ }
+ }
+
+ return result;
+}
+
+int Scene52::getHitAlienNum(int rowNum) {
+ int result = -1;
+
+ int v3 = _alienLeftX + _alienRowXOfs[rowNum];
+
+ if (_shipCannonPosX >= v3) {
+ int v8 = _alienWidth / 2 - 15;
+ if (v3 + 5 * _alienWidth - v8 >= _shipCannonPosX) {
+ int v4 = v3 + _alienWidth;
+ if (_shipCannonPosX >= v4 - v8) {
+ int v5 = v4 + _alienWidth;
+ if (_shipCannonPosX >= v5 - v8) {
+ int v6 = v5 + _alienWidth;
+ if (_shipCannonPosX >= v6 - v8) {
+ int v7 = v6 + _alienWidth;
+ if (_shipCannonPosX >= v7 - v8) {
+ if (_shipCannonPosX >= v7 + _alienWidth - v8)
+ result = -1;
+ else
+ result = 4;
+ } else {
+ result = 3;
+ }
+ } else {
+ result = 2;
+ }
+ } else {
+ result = 1;
+ }
+ } else {
+ result = 0;
+ }
+ } else {
+ result = -1;
+ }
+ } else {
+ result = -1;
+ }
+ return result;
+}
+
+int Scene52::alienCannonHitShip(int cannonNum) {
+ int result = 0;
+
+ if (_aliensCount) {
+ result = 0;
+ } else {
+ int cannonY = _alienCannonPosY[cannonNum] - 13;
+ if (_arcadeScreenBottom <= cannonY) {
+ if (_shipMidY + _arcadeScreenBottom > cannonY) {
+ if (_alienCannonPosX[cannonNum] >= _shipPosX)
+ result = _alienCannonPosX[cannonNum] < _shipMidX + _shipPosX;
+ else
+ result = 0;
+ } else {
+ result = 0;
+ }
+ } else {
+ result = 0;
+ }
+ }
+ return result;
+}
+
+int Scene52::alienCannonHitShield(int cannonNum) {
+ int result = 0;
+
+ int v3 = _alienCannonPosY[cannonNum] + 39;
+ if (_arcadeScreenBottom - 44 > v3)
+ return 0;
+
+ if (_arcadeScreenBottom <= v3)
+ return 0;
+
+ if (_alienCannonPosX[cannonNum] < _shieldPosX[0])
+ return 0;
+
+ if (_alienCannonPosX[cannonNum] > _shieldPosX[2] + 33)
+ return 0;
+
+ int shieldNum = -1;
+ if (_alienCannonPosX[cannonNum] < _shieldPosX[0] + 33)
+ shieldNum = 0;
+
+ if (shieldNum < 0 && _alienCannonPosX[cannonNum] < _shieldPosX[1])
+ return 0;
+
+ if (shieldNum < 0 && _alienCannonPosX[cannonNum] < _shieldPosX[1] + 33)
+ shieldNum = 1;
+
+ if (shieldNum < 0) {
+ if (_alienCannonPosX[cannonNum] < _shieldPosX[2])
+ return 0;
+ shieldNum = 2;
+ }
+
+ if (_shieldSpriteIds[shieldNum] == -1) {
+ result = 0;
+ } else {
+ ++_shieldSpriteIds[shieldNum];
+ if (_shieldSpriteIds[shieldNum] <= 21) {
+ _vm->_gameSys->drawSpriteToBackground(_shieldPosX[shieldNum], _arcadeScreenBottom - 44, _shieldSpriteIds[shieldNum]);
+ } else {
+ _vm->_gameSys->fillSurface(nullptr, _shieldPosX[shieldNum], _arcadeScreenBottom - 44, 33, 44, 0, 0, 0);
+ _shieldSpriteIds[shieldNum] = -1;
+ }
+ _vm->_gameSys->setAnimation(0, 0, cannonNum + 9);
+ _vm->_gameSys->insertSequence(0x21, shieldNum + 257, 0, 0, kSeqNone, 0, _alienCannonPosX[cannonNum] - 18, _arcadeScreenBottom - 44);
+ _vm->playSound(0x2C, false);
+ result = 1;
+ }
+
+ return result;
+}
+
+bool Scene52::shipCannonHitShield(int cannonNum) {
+ bool result = false;
+
+ if (_shipCannonPosX < _shieldPosX[0])
+ return result;
+
+ if (_shipCannonPosX > _shieldPosX[2] + 33)
+ return result;
+
+ int shieldNum = -1;
+ if (_shipCannonPosX < _shieldPosX[0] + 33)
+ shieldNum = 0;
+
+ if (shieldNum < 0 && _shipCannonPosX < _shieldPosX[1])
+ return result;
+
+ if (shieldNum < 0 && _shipCannonPosX < _shieldPosX[1] + 33)
+ shieldNum = 1;
+
+ if (shieldNum < 0) {
+ if (_shipCannonPosX < _shieldPosX[2])
+ return result;
+ shieldNum = 2;
+ }
+
+ if (_shieldSpriteIds[shieldNum] == -1) {
+ result = false;
+ } else {
+ ++_shieldSpriteIds[shieldNum];
+ if (_shieldSpriteIds[shieldNum] <= 21) {
+ _vm->_gameSys->drawSpriteToBackground(_shieldPosX[shieldNum], _arcadeScreenBottom - 44, _shieldSpriteIds[shieldNum]);
+ } else {
+ _vm->_gameSys->fillSurface(nullptr, _shieldPosX[shieldNum], _arcadeScreenBottom - 44, 33, 44, 0, 0, 0);
+ _shieldSpriteIds[shieldNum] = -1;
+ }
+ _vm->_gameSys->insertSequence(0x21, shieldNum + 257, 0, 0, kSeqNone, 0, _shipCannonPosX - 18, _arcadeScreenBottom - 44);
+ _vm->playSound(0x2C, false);
+ result = true;
+ }
+
+ return result;
+}
+
+bool Scene52::shipCannonHitAlien() {
+ bool result = false;
+
+ if (_aliensCount || checkAlienRow(0))
+ return false;
+
+ int alienNextX = _alienLeftX + _alienRowXOfs[0];
+ if (_shipMidX + _shipPosX >= alienNextX) {
+ int startX = _alienWidth / 2 - 15;
+ if (alienNextX + 5 * _alienWidth - startX >= _shipPosX) {
+ int alienNextDeltaX = alienNextX + _alienWidth;
+ if (_items[0][0] <= -1 || alienNextDeltaX - startX <= _shipPosX) {
+ alienNextDeltaX += _alienWidth;
+ if (_items[0][1] <= -1 || alienNextDeltaX - startX <= _shipPosX) {
+ alienNextDeltaX += _alienWidth;
+ if (_items[0][2] <= -1 || alienNextDeltaX - startX <= _shipPosX) {
+ alienNextDeltaX += _alienWidth;
+ if (_items[0][3] <= -1 || alienNextDeltaX - startX <= _shipPosX) {
+ alienNextDeltaX += _alienWidth;
+ result = _items[0][4] > -1 && alienNextDeltaX - startX > _shipPosX;
+ } else {
+ result = true;
+ }
+ } else {
+ result = true;
+ }
+ } else {
+ result = true;
+ }
+ } else {
+ result = true;
+ }
+ } else {
+ result = false;
+ }
+ } else {
+ result = false;
+ }
+
+ return result;
+}
+
+void Scene52::shipExplode() {
+ if (!_aliensCount) {
+ _vm->_gameSys->setAnimation(0, 0, 7);
+ _vm->_gameSys->removeSequence(_ufoSequenceId, 256, true);
+ _vm->playSound(0x2C, false);
+ _vm->_gameSys->insertSequence(0x21, 266, 0, 0, kSeqNone, 0, _shipPosX, _arcadeScreenBottom);
+ _aliensCount = 1;
+ _vm->playSound(0x31, false);
+ }
+}
+
+bool Scene52::checkAlienRow(int rowNum) {
+ for (int i = 0; i < 5; ++i) {
+ if (_items[rowNum][i] >= 0)
+ return false;
+ }
+
+ bool found = false;
+ for (int j = 0; j < 5; ++j)
+ if (_items[rowNum][j] == -2) {
+ _vm->_gameSys->removeSequence(_alienRowKind[rowNum], j + 256, true);
+ _items[rowNum][j] = -1;
+ --_alienSpeed;
+ found = true;
+ }
+
+ if (found) {
+ _vm->_gameSys->setAnimation(0, 0, _alienRowAnims[rowNum]);
+ --_liveAlienRows;
+ }
+
+ if (_liveAlienRows < 0)
+ _liveAlienRows = 0;
+
+ return true;
+}
+
+void Scene52::updateAlienRowXOfs() {
+ int amount = 2 * (3 - _liveAlienRows) + 1;
+
+ if (_alienSpeed == 2)
+ amount *= 4;
+ else if (_alienSpeed == 1)
+ amount *= 10;
+
+ if (_alienDirection) {
+ for (int i = 0; i < 7; ++i) {
+ _alienRowXOfs[i] -= amount;
+ if (_alienRowXOfs[i] <= -100) {
+ _alienRowXOfs[i] = -100;
+ _alienDirection = 0;
+ ++_alienRowDownCtr;
+ }
+ }
+ } else {
+ for (int j = 0; j < 7; ++j) {
+ _alienRowXOfs[j] += amount;
+ if (_alienRowXOfs[j] >= 100) {
+ _alienRowXOfs[j] = 100;
+ _alienDirection = 1;
+ ++_alienRowDownCtr;
+ }
+ }
+ }
+}
+
+void Scene52::initAlienSize() {
+ _alienWidth = _vm->_gameSys->getSpriteWidthById(0);
+ if (_vm->_gameSys->getSpriteWidthById(1) > _alienWidth)
+ _alienWidth = _vm->_gameSys->getSpriteWidthById(1);
+ if (_vm->_gameSys->getSpriteWidthById(4) > _alienWidth)
+ _alienWidth = _vm->_gameSys->getSpriteWidthById(4);
+ if (_vm->_gameSys->getSpriteWidthById(5) > _alienWidth)
+ _alienWidth = _vm->_gameSys->getSpriteWidthById(5);
+ if (_vm->_gameSys->getSpriteWidthById(12) > _alienWidth)
+ _alienWidth = _vm->_gameSys->getSpriteWidthById(12);
+ if (_vm->_gameSys->getSpriteWidthById(13) > _alienWidth)
+ _alienWidth = _vm->_gameSys->getSpriteWidthById(13);
+
+ _alienHeight = _vm->_gameSys->getSpriteHeightById(0);
+ if (_vm->_gameSys->getSpriteHeightById(1) > _alienHeight)
+ _alienHeight = _vm->_gameSys->getSpriteHeightById(1);
+ if (_vm->_gameSys->getSpriteHeightById(4) > _alienHeight)
+ _alienHeight = _vm->_gameSys->getSpriteHeightById(4);
+ if (_vm->_gameSys->getSpriteHeightById(5) > _alienHeight)
+ _alienHeight = _vm->_gameSys->getSpriteHeightById(5);
+ if (_vm->_gameSys->getSpriteHeightById(12) > _alienHeight)
+ _alienHeight = _vm->_gameSys->getSpriteHeightById(12);
+ if (_vm->_gameSys->getSpriteHeightById(13) > _alienHeight)
+ _alienHeight = _vm->_gameSys->getSpriteHeightById(13);
+
+ _alienTopY = _shipCannonTopY + 52;
+ _alienLeftX = (800 - 5 * _alienWidth) / 2;
+}
+
+void Scene52::playSound() {
+ if (_soundToggle) {
+ _vm->playSound(0x2F, false);
+ _soundToggle = false;
+ } else {
+ _vm->playSound(0x2E, false);
+ _soundToggle = true;
+ }
+}
+
+void Scene52::updateAliens() {
+ for (int i = 0; i < 7; ++i)
+ updateAlien(i);
+}
+
+void Scene52::updateAlien(int rowNum) {
+ if (_alienRowKind[rowNum] >= 0 && !checkAlienRow(rowNum)) {
+ for (int i = 0; i < 5; ++i) {
+ if (_items[rowNum][i] >= 0)
+ _items[rowNum][i] = -2;
+ }
+ checkAlienRow(rowNum);
+ }
+}
+
+void Scene52::loseShip() {
+ --_shipsLeft;
+ if (_shipsLeft == 2) {
+ _vm->_gameSys->fillSurface(nullptr, 120, 140, _shipMidX, _shipMidY, 0, 0, 0);
+ } else if (_shipsLeft == 1) {
+ _vm->_gameSys->fillSurface(nullptr, 120, 185, _shipMidX, _shipMidY, 0, 0, 0);
+ }
+}
+
+void Scene52::initShields() {
+ for (int i = 0; i < 3; ++i) {
+ _vm->_gameSys->drawSpriteToBackground(_shieldPosX[i], _arcadeScreenBottom - 44, 17);
+ _shieldSpriteIds[i] = 17;
+ }
+}
+
+void Scene52::initAnims() {
+ for (int i = 0; i < 7; ++i)
+ _vm->_gameSys->setAnimation(0, 0, i);
+ _vm->_gameSys->setAnimation(0, 0, 7);
+ for (int j = 0; j < 1; ++j)
+ _vm->_gameSys->setAnimation(0, 0, j + 8);
+ for (int k = 0; k < 3; ++k)
+ _vm->_gameSys->setAnimation(0, 0, k + 9);
+}
+
+void Scene52::drawScore(int score) {
+ char str[4];
+ sprintf(str, "%03d", score);
+ _vm->_gameSys->fillSurface(nullptr, 420, 80, 48, 30, 0, 0, 0);
+ _vm->_gameSys->drawTextToSurface(nullptr, 420, 80, 255, 255, 255, str);
+}
+
+void Scene52::run() {
+ _vm->_timers[1] = 0;
+
+ _vm->hideCursor();
+
+ _gameScore = 0;
+ _vm->_gameSys->drawTextToSurface(nullptr, 300, 80, 255, 255, 255, "SCORE");
+ _vm->_gameSys->drawTextToSurface(nullptr, 468, 80, 255, 255, 255, "0");
+
+ drawScore(0);
+
+ _shipMidX = 33;
+ _shipMidY = _vm->_gameSys->getSpriteHeightById(15);
+ _shipPosX = (800 - _shipMidX) / 2;
+ _arcadeScreenBottom = 496;
+ _arcadeScreenRight = 595 - _shipMidX;
+ _arcadeScreenLeft = 210;
+ _shipsLeft = 3;
+ _alienCounter = 0;
+
+ _shieldPosX[0] = 247;
+ _shieldPosX[1] = 387;
+ _shieldPosX[2] = 525;
+
+ for (int i = 0; i < 3; ++i)
+ _shieldSpriteIds[i] = -1;
+
+ _vm->_gameSys->drawSpriteToBackground(120, 140, 0xF);
+ _vm->_gameSys->drawSpriteToBackground(120, 185, 0xF);
+
+ initShipCannon(_arcadeScreenBottom);
+ initAlienCannons();
+ initAliens();
+
+ _nextUfoSequenceId = 0x22;
+ _vm->_gameSys->setAnimation(0x22, 256, 7);
+ _vm->_gameSys->insertSequence(_nextUfoSequenceId, 256, 0, 0, kSeqNone, 0, _shipPosX, _arcadeScreenBottom);
+
+ _ufoSequenceId = _nextUfoSequenceId;
+
+ _vm->clearKeyStatus1(Common::KEYCODE_RIGHT);
+ _vm->clearKeyStatus1(Common::KEYCODE_LEFT);
+ _vm->clearKeyStatus1(Common::KEYCODE_SPACE);
+ _vm->clearKeyStatus1(Common::KEYCODE_UP);
+ _vm->clearKeyStatus1(Common::KEYCODE_ESCAPE);
+
+ _vm->_timers[2] = 5;
+ _shipFlag = false;
+
+ _vm->_timers[0] = 10;
+ _alienWave = true;
+
+ while (!_vm->_sceneDone) {
+ _vm->gameUpdateTick();
+
+ while (_vm->isKeyStatus2(Common::KEYCODE_RIGHT)) {
+ update();
+ if (_vm->_gameSys->getAnimationStatus(7) == 2) {
+ if (_shipPosX < _arcadeScreenRight) {
+ _shipPosX += 15;
+ if (_shipPosX > _arcadeScreenRight)
+ _shipPosX = _arcadeScreenRight;
+ _vm->_gameSys->setAnimation(_nextUfoSequenceId, 256, 7);
+ _vm->_gameSys->insertSequence(_nextUfoSequenceId, 256, _ufoSequenceId, 256, kSeqSyncWait, 0, _shipPosX, _arcadeScreenBottom);
+ _ufoSequenceId = _nextUfoSequenceId;
+ if (_bottomAlienFlag && shipCannonHitAlien())
+ shipExplode();
+ }
+ break;
+ }
+ }
+
+ while (_vm->isKeyStatus2(Common::KEYCODE_LEFT)) {
+ update();
+ if (_vm->_gameSys->getAnimationStatus(7) == 2) {
+ if (_shipPosX > _arcadeScreenLeft) {
+ _shipPosX -= 15;
+ if (_shipPosX < _arcadeScreenLeft)
+ _shipPosX = _arcadeScreenLeft;
+ _vm->_gameSys->setAnimation(_nextUfoSequenceId, 256, 7);
+ _vm->_gameSys->insertSequence(_nextUfoSequenceId, 256, _ufoSequenceId, 256, kSeqSyncWait, 0, _shipPosX, _arcadeScreenBottom);
+ _ufoSequenceId = _nextUfoSequenceId;
+ if (_bottomAlienFlag && shipCannonHitAlien())
+ shipExplode();
+ }
+ break;
+ }
+ }
+
+ update();
+
+ if (clearKeyStatus()) {
+ _alienWave = false;
+ _vm->_gameSys->waitForUpdate();
+ initAnims();
+ _vm->clearKeyStatus1(Common::KEYCODE_SPACE);
+ _vm->_sceneDone = true;
+ }
+ }
+ _vm->_gameSys->waitForUpdate();
+}
+
+} // End of namespace Gnap
diff --git a/engines/gnap/scenes/arcade.h b/engines/gnap/scenes/arcade.h
new file mode 100644
index 0000000000..e472e00508
--- /dev/null
+++ b/engines/gnap/scenes/arcade.h
@@ -0,0 +1,290 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can 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 GNAP_ARCADE_H
+#define GNAP_ARCADE_H
+
+#include "gnap/debugger.h"
+
+namespace Gnap {
+
+class GnapEngine;
+class CutScene;
+
+struct Scene49Obstacle {
+ int _currSequenceId;
+ int _closerSequenceId;
+ int _passedSequenceId;
+ int _splashSequenceId;
+ int _collisionSequenceId;
+ int _prevId;
+ int _currId;
+ int _laneNum;
+};
+
+struct ObstacleDef {
+ int _sequenceId;
+ int _ticks;
+};
+
+class Scene49: public Scene {
+public:
+ Scene49(GnapEngine *vm);
+ ~Scene49() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _scoreBarPos;
+ int _scoreLevel;
+ bool _scoreBarFlash;
+ int _obstacleIndex;
+ Scene49Obstacle _obstacles[5];
+ int _truckSequenceId;
+ int _truckId;
+ int _truckLaneNum;
+
+ void checkObstacles();
+ void updateObstacle(int id);
+ void increaseScore(int amount);
+ void decreaseScore(int amount);
+ void refreshScoreBar();
+ void clearObstacle(int index);
+};
+
+/*****************************************************************************/
+
+class Scene50: public Scene {
+public:
+ Scene50(GnapEngine *vm);
+ ~Scene50() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ bool _fightDone;
+ int _timesPlayed;
+ int _timesPlayedModifier;
+ int _attackCounter;
+ int _roundNum;
+ int _timeRemaining;
+ int _leftTongueRoundsWon;
+ int _rightTongueRoundsWon;
+ int _leftTongueEnergyBarPos;
+ int _rightTongueEnergyBarPos;
+ int _leftTongueSequenceId;
+ int _leftTongueId;
+ int _leftTongueNextSequenceId;
+ int _leftTongueNextId;
+ int _leftTongueNextIdCtr;
+ int _rightTongueSequenceId;
+ int _rightTongueId;
+ int _rightTongueNextSequenceId;
+ int _rightTongueNextId;
+ int _rightTongueNextIdCtr;
+ int _leftTongueEnergy;
+ int _rightTongueEnergy;
+
+ bool tongueWinsRound(int tongueNum);
+ void playWinAnim(int tongueNum, bool fightOver);
+ void delayTicks();
+ void initRound();
+ bool updateCountdown();
+ void drawCountdown(int value);
+ void playTonguesIdle();
+ void playRoundAnim(int roundNum);
+ bool updateEnergyBars(int newLeftBarPos, int newRightBarPos);
+ void waitForAnim(int animationIndex);
+ int checkInput();
+ int getRightTongueAction();
+ int getRightTongueActionTicks();
+ int getLeftTongueNextId();
+ int getRightTongueNextId();
+ void playWinBadgeAnim(int tongueNum);
+};
+
+/*****************************************************************************/
+
+struct Scene51Item {
+ int _currSequenceId;
+ int _droppedSequenceId;
+ int _x, _y;
+ int _collisionX;
+ bool _canCatch;
+ bool _isCollision;
+ int _x2;
+ int _id;
+};
+
+class Scene51: public Scene {
+public:
+ Scene51(GnapEngine *vm);
+ ~Scene51() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations() {};
+ virtual void updateAnimationsCb() {};
+
+private:
+ bool _dropLoseCash;
+
+ int _cashAmount;
+ int _digits[4];
+ int _digitSequenceIds[4];
+ int _guySequenceId;
+ int _guyNextSequenceId;
+ int _itemsCaughtCtr;
+ int _dropSpeedTicks;
+ int _nextDropItemKind;
+ int _itemInsertX;
+ int _itemInsertDirection;
+ int _platypusSequenceId;
+ int _platypusNextSequenceId;
+ int _platypusJumpSequenceId;
+ int _itemsCtr;
+ int _itemsCtr1;
+ int _itemsCtr2;
+
+ Scene51Item _items[6];
+
+ void clearItem(Scene51Item *item);
+ void dropNextItem();
+ void updateItemAnimations();
+ int checkCollision(int sequenceId);
+ void updateItemAnimation(Scene51Item *item, int index);
+ void removeCollidedItems();
+ int itemIsCaught(Scene51Item *item);
+ bool isJumpingRight(int sequenceId);
+ bool isJumpingLeft(int sequenceId);
+ bool isJumping(int sequenceId);
+ void waitForAnim(int animationIndex);
+ int getPosRight(int sequenceId);
+ int getPosLeft(int sequenceId);
+ void playIntroAnim();
+ void updateGuyAnimation();
+ int incCashAmount(int sequenceId);
+ void winMinigame();
+ void playCashAppearAnim();
+ void updateCash(int amount);
+ void drawDigit(int digit, int position);
+ void initCashDisplay();
+};
+
+/*****************************************************************************/
+
+class Scene52: public Scene {
+public:
+ Scene52(GnapEngine *vm);
+ ~Scene52() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations() {};
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _liveAlienRows;
+ int _gameScore;
+ bool _soundToggle;
+ int _arcadeScreenLeft;
+ int _arcadeScreenRight;
+ int _arcadeScreenBottom;
+ int _shipsLeft;
+ int _shieldSpriteIds[3];
+ int _shieldPosX[3];
+ int _shipPosX;
+ int _shipCannonPosX, _shipCannonPosY;
+ bool _shipCannonFiring;
+ bool _shipCannonFired;
+ int _shipCannonWidth, _shipCannonHeight;
+ int _shipCannonTopY;
+ int _shipMidX, _shipMidY;
+ bool _shipFlag;
+ bool _aliensInitialized;
+ int _alienSpeed, _alienDirection;
+ int _alienWidth, _alienHeight;
+ int _alienLeftX, _alienTopY;
+ int _alienRowDownCtr;
+ int _alienRowKind[8];
+ int _alienRowAnims[8];
+ int _alienRowIds[8];
+ int _alienRowXOfs[8];
+ int _alienCannonFired[3];
+ int _alienCannonPosX[3];
+ int _alienCannonPosY[3];
+ int _alienCannonSequenceIds[3];
+ int _alienCannonIds[3];
+ bool _alienWave, _alienSingle;
+ int _alienCounter;
+ bool _bottomAlienFlag;
+ int _aliensCount;
+ int _items[8][5];
+ int _nextUfoSequenceId, _ufoSequenceId;
+
+ void update();
+ void initShipCannon(int bottomY);
+ void initAlienCannons();
+ void fireShipCannon(int posX);
+ void fireAlienCannon();
+ int getFreeShipCannon();
+ int getFreeAlienCannon();
+ void updateShipCannon();
+ void updateAlienCannons();
+ void initAliens();
+ void initAlienRowKind(int rowNum, int alienKind);
+ void insertAlienRow(int rowNum);
+ void insertAlienRowAliens(int rowNum);
+ void updateAlienRow(int rowNum);
+ void moveDownAlienRow();
+ int updateHitAlien();
+ int getHitAlienNum(int rowNum);
+ int alienCannonHitShip(int cannonNum);
+ int alienCannonHitShield(int cannonNum);
+ bool shipCannonHitShield(int cannonNum);
+ bool shipCannonHitAlien();
+ void shipExplode();
+ bool checkAlienRow(int rowNum);
+ void updateAlienRowXOfs();
+ void initAlienSize();
+ void playSound();
+ void updateAliens();
+ void updateAlien(int rowNum);
+ void loseShip();
+ void initShields();
+ void initAnims();
+ void drawScore(int score);
+};
+
+} // End of namespace Gnap
+
+#endif // GNAP_ARCADE_H
diff --git a/engines/gnap/scenes/group0.cpp b/engines/gnap/scenes/group0.cpp
new file mode 100644
index 0000000000..b2351b08ad
--- /dev/null
+++ b/engines/gnap/scenes/group0.cpp
@@ -0,0 +1,3570 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can 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 "gnap/gnap.h"
+#include "gnap/character.h"
+#include "gnap/gamesys.h"
+#include "gnap/resource.h"
+#include "gnap/scenes/group0.h"
+
+namespace Gnap {
+
+Scene01::Scene01(GnapEngine *vm) : Scene(vm) {
+ _pigsIdCtr = 0;
+ _smokeIdCtr = 0;
+ _spaceshipSurface = nullptr;
+}
+
+Scene01::~Scene01() {
+ delete _spaceshipSurface;
+}
+
+int Scene01::init() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ gameSys.setAnimation(0, 0, 0);
+ gameSys.setAnimation(0, 0, 3);
+ return 0x88;
+}
+
+void Scene01::updateHotspots() {
+ _vm->setHotspot(kHS01Platypus, 0, 0, 0, 0, SF_DISABLED | SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS01ExitTruck, 780, 226, 800, 455, SF_EXIT_R_CURSOR | SF_WALKABLE, 10, 6);
+ _vm->setHotspot(kHS01Mud, 138, 282, 204, 318, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 3, 5);
+ _vm->setHotspot(kHS01Pigs, 408, 234, 578, 326, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 6, 4);
+ _vm->setHotspot(kHS01Spaceship, 0, 200, 94, 292, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 1, 6);
+ _vm->setHotspot(kHS01WalkArea1, 0, 0, 162, 426);
+ _vm->setHotspot(kHS01WalkArea2, 162, 0, 237, 396);
+ _vm->setHotspot(kHS01WalkArea3, 237, 0, 319, 363);
+ _vm->setHotspot(kHS01WalkArea4, 520, 0, 800, 404);
+ _vm->setHotspot(kHS01WalkArea5, 300, 447, 800, 600);
+ _vm->setHotspot(kHS01WalkArea6, 678, 0, 800, 404);
+ _vm->setHotspot(kHS01WalkArea7, 0, 0, 520, 351);
+ _vm->setHotspot(kHS01WalkArea8, 0, 546, 300, 600);
+ _vm->setDeviceHotspot(kHS01Device, -1, -1, -1, -1);
+ if (_vm->isFlag(kGFPlatypus))
+ _vm->_hotspots[kHS01Platypus]._flags = SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR;
+ if (_vm->isFlag(kGFMudTaken))
+ _vm->_hotspots[kHS01Mud]._flags = SF_WALKABLE | SF_DISABLED;
+ _vm->_hotspotsCount = 14;
+}
+
+void Scene01::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->playSound(0x1091C, true);
+ _vm->startSoundTimerC(5);
+
+ gameSys.setAnimation(134, 20, 4);
+ gameSys.insertSequence(134, 20, 0, 0, kSeqNone, 0, 0, 0);
+
+ gameSys.setAnimation(0x7F, 40, 2);
+ gameSys.insertSequence(0x7F, 40, 0, 0, kSeqNone, 0, 0, 0);
+
+ _vm->_timers[4] = _vm->getRandom(100) + 300;
+
+ if (!_vm->isFlag(kGFMudTaken))
+ gameSys.insertSequence(129, 40, 0, 0, kSeqNone, 0, 0, 0);
+
+ _vm->queueInsertDeviceIcon();
+
+ if (_vm->_prevSceneNum == 2) {
+ gnap.initPos(11, 6, kDirBottomLeft);
+ if (_vm->isFlag(kGFPlatypus))
+ plat.initPos(12, 6, kDirIdleRight);
+ _vm->endSceneInit();
+ if (_vm->isFlag(kGFPlatypus))
+ plat.walkTo(Common::Point(9, 6), -1, 0x107C2, 1);
+ gnap.walkTo(Common::Point(8, 6), -1, 0x107B9, 1);
+ } else {
+ gnap.initPos(1, 6, kDirBottomRight);
+ if (_vm->isFlag(kGFPlatypus))
+ plat.initPos(1, 7, kDirIdleLeft);
+ _vm->endSceneInit();
+ }
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+ _vm->testWalk(0, 3, -1, -1, -1, -1);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS01Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS01Platypus:
+ if (gnap._actionStatus < 0 && _vm->isFlag(kGFPlatypus)) {
+ if (_vm->_grabCursorSpriteIndex == kItemDisguise) {
+ gnap.useDisguiseOnPlatypus();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ if (_vm->isFlag(kGFKeysTaken))
+ gnap.playMoan1(plat._pos);
+ else
+ gnap.playScratchingHead(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS01Spaceship:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[4], 0, 2);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap._idleFacing = kDirUpLeft;
+ if (gnap.walkTo(_vm->_hotspotsWalkPos[4], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1))
+ gnap._actionStatus = kAS01LookSpaceship;
+ break;
+ case GRAB_CURSOR:
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS01Mud:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[2], 2, 3);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(3, 3));
+ break;
+ case GRAB_CURSOR:
+ gnap.walkTo(_vm->_hotspotsWalkPos[2], 0, gnap.getSequenceId(kGSIdle, Common::Point(2, 3)) | 0x10000, 1);
+ gnap._actionStatus = kAS01TakeMud;
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS01Pigs:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[3], 7, 2);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[3], 0, gnap.getSequenceId(kGSIdle, Common::Point(7, 2)) | 0x10000, 1);
+ gnap._actionStatus = kAS01LookPigs;
+ break;
+ case GRAB_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[3], 0, gnap.getSequenceId(kGSIdle, Common::Point(7, 2)) | 0x10000, 1);
+ gnap._actionStatus = kAS01UsePigs;
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[3], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(7, 2)) | 0x10000, 1);
+ gnap._actionStatus = kAS01LookPigs;
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS01ExitTruck:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(_vm->_hotspotsWalkPos[1], 0, 0x107AB, 1);
+ gnap._actionStatus = kAS01LeaveScene;
+ if (_vm->isFlag(kGFPlatypus))
+ plat.walkTo(_vm->_hotspotsWalkPos[1] + Common::Point(0, 1), -1, 0x107CD, 1);
+ _vm->_newSceneNum = 2;
+ }
+ break;
+
+ case kHS01WalkArea1:
+ case kHS01WalkArea2:
+ case kHS01WalkArea3:
+ case kHS01WalkArea4:
+ case kHS01WalkArea5:
+ case kHS01WalkArea6:
+ case kHS01WalkArea7:
+ case kHS01WalkArea8:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left && gnap._actionStatus < 0) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+
+ }
+
+ updateAnimations();
+
+ if (!_vm->isSoundPlaying(0x1091C))
+ _vm->playSound(0x1091C, true);
+
+ if (!_vm->_isLeavingScene) {
+ if (plat._actionStatus < 0 && _vm->isFlag(kGFPlatypus))
+ plat.updateIdleSequence();
+ if (gnap._actionStatus < 0)
+ gnap.updateIdleSequence();
+ if (_vm->_timers[4] == 0) {
+ // Update bird animation
+ _vm->_timers[4] = _vm->getRandom(100) + 300;
+ if (_vm->getRandom(1) == 0)
+ gameSys.insertSequence(0x84, 180, 0, 0, kSeqNone, 0, 0, 0);
+ else
+ gameSys.insertSequence(0x83, 180, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ _vm->playSoundC();
+ }
+
+ _vm->checkGameKeys();
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene01::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS01LookSpaceship:
+ _spaceshipSurface = gameSys.createSurface(47);
+ gameSys.insertSpriteDrawItem(_spaceshipSurface, 0, 0, 255);
+ gameSys.setAnimation(133, 256, 0);
+ gameSys.insertSequence(133, 256, 0, 0, kSeqNone, 0, 0, 0);
+ gnap._actionStatus = kAS01LookSpaceshipDone;
+ break;
+
+ case kAS01LookSpaceshipDone:
+ gameSys.removeSequence(133, 256, true);
+ gameSys.removeSpriteDrawItem(_spaceshipSurface, 255);
+ _vm->deleteSurface(&_spaceshipSurface);
+ gnap._actionStatus = -1;
+ break;
+
+ case kAS01LeaveScene:
+ _vm->_sceneDone = true;
+ break;
+
+ case kAS01TakeMud:
+ gnap.playPullOutDevice(Common::Point(2, 3));
+ gnap.playUseDevice();
+ gameSys.insertSequence(128, 40, 129, 40, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(128, 40, 3);
+ gnap._actionStatus = -1;
+ break;
+
+ case kAS01LookPigs:
+ _vm->playSound(0x8A, false);
+ _vm->playSound(0x8B, false);
+ _vm->playSound(0x8C, false);
+ gnap._actionStatus = -1;
+ break;
+
+ case kAS01UsePigs:
+ gnap.playPullOutDevice(Common::Point(7, 2));
+ gnap.playUseDevice();
+ gameSys.insertSequence(135, 39, 0, 0, kSeqNone, 25, _vm->getRandom(140) - 40, 0);
+ gnap._actionStatus = -1;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2) {
+ gameSys.setAnimation(0, 0, 3);
+ _vm->invAdd(kItemMud);
+ _vm->setGrabCursorSprite(kItemMud);
+ _vm->setFlag(kGFMudTaken);
+ updateHotspots();
+ }
+
+ if (gameSys.getAnimationStatus(4) == 2) {
+ _smokeIdCtr = (_smokeIdCtr + 1) % 2;
+ gameSys.setAnimation(0x86, _smokeIdCtr + 20, 4);
+ gameSys.insertSequence(0x86, _smokeIdCtr + 20,
+ 0x86, (_smokeIdCtr + 1) % 2 + 20,
+ kSeqSyncWait, 0, 0, 0);
+ }
+
+ if (gameSys.getAnimationStatus(2) == 2) {
+ _pigsIdCtr = (_pigsIdCtr + 1) % 2;
+ gameSys.setAnimation(0x7F, _pigsIdCtr + 40, 2);
+ gameSys.insertSequence(0x7F, _pigsIdCtr + 40,
+ 0x7F, (_pigsIdCtr + 1) % 2 + 40,
+ kSeqSyncWait, 0, 0, 0);
+ }
+}
+
+/*****************************************************************************/
+
+Scene02::Scene02(GnapEngine *vm) : Scene(vm) {
+ _truckGrillCtr = 0;
+ _nextChickenSequenceId = 0;
+ _currChickenSequenceId = 0;
+ _gnapTruckSequenceId = 0;
+}
+
+int Scene02::init() {
+ _vm->_gameSys->setAnimation(0, 0, 0);
+ return _vm->isFlag(kGFTruckKeysUsed) ? 0x15A : 0x15B;
+}
+
+void Scene02::updateHotspots() {
+ _vm->setHotspot(kHS02Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ if (!_vm->isFlag(kGFPlatypus))
+ _vm->_hotspots[kHS02Platypus]._flags |= SF_DISABLED;
+ _vm->setHotspot(kHS02Chicken, 606, 455, 702, 568, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 7, 8);
+ _vm->setHotspot(kHS02Truck1, 385, 258, 464, 304, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 6, 5);
+ _vm->setHotspot(kHS02Truck2, 316, 224, 390, 376, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 5, 6);
+ _vm->setHotspot(kHS02TruckGrill, 156, 318, 246, 390, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 2, 7);
+ _vm->setHotspot(kHS02ExitHouse, 480, 120, 556, 240, SF_EXIT_U_CURSOR, 7, 5);
+ _vm->setHotspot(kHS02ExitBarn, 610, 0, 800, 164, SF_EXIT_U_CURSOR, 10, 5);
+ _vm->setHotspot(kHS02ExitCreek, 780, 336, 800, 556, SF_EXIT_R_CURSOR | SF_WALKABLE, 10, 8);
+ _vm->setHotspot(kHS02ExitPigpen, 0, 300, 20, 600, SF_EXIT_L_CURSOR | SF_WALKABLE, 0, 8);
+ _vm->setHotspot(kHS02WalkArea1, 92, 140, 304, 430, SF_NONE, 3, 1);
+ _vm->setHotspot(kHS02WalkArea2, 0, 0, 800, 380);
+ _vm->setHotspot(kHS02WalkArea3, 0, 0, 386, 445);
+ _vm->setHotspot(kHS02WalkArea4, 386, 0, 509, 410);
+ _vm->setDeviceHotspot(kHS02Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 14;
+}
+
+void Scene02::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->playSound(0x1091C, true);
+ _vm->startSoundTimerC(6);
+
+ _currChickenSequenceId = 0x14B;
+ gameSys.setAnimation(0x14B, 179, 2);
+ gameSys.insertSequence(0x14B, 179, 0, 0, kSeqNone, 0, 0, 0);
+
+ _nextChickenSequenceId = -1;
+ _vm->_timers[5] = _vm->getRandom(20) + 30;
+ _vm->_timers[4] = _vm->getRandom(100) + 300;
+
+ _vm->queueInsertDeviceIcon();
+
+ switch (_vm->_prevSceneNum) {
+ case 3:
+ gnap.initPos(11, 6, kDirBottomLeft);
+ if (_vm->isFlag(kGFPlatypus))
+ plat.initPos(12, 6, kDirIdleRight);
+ _vm->endSceneInit();
+ if (_vm->isFlag(kGFPlatypus))
+ plat.walkTo(Common::Point(9, 6), -1, 0x107C2, 1);
+ gnap.walkTo(Common::Point(8, 6), -1, 0x107BA, 1);
+ break;
+ case 4:
+ gnap.initPos(_vm->_hotspotsWalkPos[6].x, _vm->_hotspotsWalkPos[6].y, kDirBottomLeft);
+ if (_vm->isFlag(kGFPlatypus))
+ plat.initPos(_vm->_hotspotsWalkPos[6].x + 1, _vm->_hotspotsWalkPos[6].y, kDirIdleRight);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(7, 6), 0, 0x107B9, 1);
+ if (_vm->isFlag(kGFPlatypus))
+ plat.walkTo(Common::Point(8, 6), 1, 0x107C2, 1);
+ updateHotspots();
+ gameSys.waitForUpdate();
+ break;
+ case 47:
+ _vm->clearFlag(kGFUnk25);
+ gnap.initPos(5, 6, kDirBottomLeft);
+ plat.initPos(6, 7, kDirIdleRight);
+ _vm->endSceneInit();
+ break;
+ case 49:
+ gnap.initPos(5, 6, kDirBottomRight);
+ if (_vm->isFlag(kGFPlatypus))
+ plat.initPos(6, 7, kDirIdleLeft);
+ _vm->endSceneInit();
+ break;
+ default:
+ gnap.initPos(-1, 6, kDirBottomRight);
+ if (_vm->isFlag(kGFPlatypus))
+ plat.initPos(-1, 7, kDirIdleLeft);
+ _vm->endSceneInit();
+ if (_vm->isFlag(kGFPlatypus))
+ plat.walkTo(Common::Point(2, 7), -1, 0x107C2, 1);
+ gnap.walkTo(Common::Point(2, 8), -1, 0x107B9, 1);
+ break;
+ }
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->testWalk(0, 6, 7, 6, 8, 6);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS02Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS02Platypus:
+ if (gnap._actionStatus < 0 && _vm->isFlag(kGFPlatypus)) {
+ if (_vm->_grabCursorSpriteIndex == kItemDisguise) {
+ gnap.useDisguiseOnPlatypus();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ if (_vm->isFlag(kGFKeysTaken))
+ gnap.playMoan1(plat._pos);
+ else
+ gnap.playScratchingHead(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS02Chicken:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemTwig) {
+ gnap._idleFacing = kDirUpRight;
+ Common::Point destPos = _vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot] + Common::Point(0, 1);
+ gnap.walkTo(destPos, 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS02UseTwigWithChicken;
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[1] + Common::Point(0, 1), 9, 8);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan2(Common::Point(9, 8));
+ break;
+ case GRAB_CURSOR:
+ gnap._idleFacing = kDirBottomRight;
+ if (gnap.walkTo(_vm->_hotspotsWalkPos[1], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1))
+ gnap._actionStatus = kAS02GrabChicken;
+ else
+ gnap._actionStatus = -1;
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirBottomRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[1], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS02TalkChicken;
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS02Truck1:
+ case kHS02Truck2:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemKeys) {
+ if (gnap.walkTo(_vm->_hotspotsWalkPos[3], 0, gnap.getSequenceId(kGSIdle, Common::Point(2, 2)) | 0x10000, 1)) {
+ _vm->setGrabCursorSprite(-1);
+ _vm->invRemove(kItemKeys);
+ if (_vm->isFlag(kGFTruckFilledWithGas))
+ gnap._actionStatus = kAS02UseTruckGas;
+ else
+ gnap._actionStatus = kAS02UseTruckNoGas;
+ }
+ } else if (_vm->_grabCursorSpriteIndex == kItemGas) {
+ _vm->_hotspots[kHS02WalkArea4]._flags |= SF_WALKABLE;
+ if (gnap.walkTo(_vm->_hotspotsWalkPos[2], 0, gnap.getSequenceId(kGSIdle, Common::Point(2, 2)) | 0x10000, 1))
+ gnap._actionStatus = kAS02UseGasWithTruck;
+ _vm->_hotspots[kHS02WalkArea4]._flags &= ~SF_WALKABLE;
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[2], 2, 2);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(2, 2));
+ break;
+ case GRAB_CURSOR:
+ if (_vm->isFlag(kGFTruckKeysUsed)) {
+ if (gnap.walkTo(_vm->_hotspotsWalkPos[3], 0, gnap.getSequenceId(kGSIdle, Common::Point(2, 2)) | 0x10000, 1)) {
+ if (_vm->isFlag(kGFTruckFilledWithGas))
+ gnap._actionStatus = kAS02UseTruckGas;
+ else
+ gnap._actionStatus = kAS02UseTruckNoGas;
+ }
+ } else {
+ gnap._idleFacing = kDirIdleRight;
+ if (gnap.walkTo(_vm->_hotspotsWalkPos[3], 0, gnap.getSequenceId(kGSIdle, Common::Point(2, 2)) | 0x10000, 1))
+ gnap._actionStatus = kAS02UseTruckNoKeys;
+ }
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS02TruckGrill:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[4], 2, 4);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan2(Common::Point(2, 4));
+ break;
+ case GRAB_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[4], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS02GrabTruckGrill;
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS02ExitHouse:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(_vm->_hotspotsWalkPos[6], 0, 0x107AD, 1);
+ gnap._actionStatus = kAS02LeaveScene;
+ if (_vm->isFlag(kGFPlatypus))
+ plat.walkTo(_vm->_hotspotsWalkPos[6] + Common::Point(1, 0), -1, 0x107C1, 1);
+ updateHotspots();
+ _vm->_newSceneNum = 4;
+ }
+ break;
+
+ case kHS02ExitBarn:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(_vm->_hotspotsWalkPos[7], 0, 0x107AD, 1);
+ gnap._actionStatus = kAS02LeaveScene;
+ if (_vm->isFlag(kGFPlatypus))
+ plat.walkTo(_vm->_hotspotsWalkPos[7] + Common::Point(1, 0), -1, 0x107C1, 1);
+ updateHotspots();
+ _vm->_newSceneNum = 5;
+ }
+ break;
+
+ case kHS02ExitCreek:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(_vm->_hotspotsWalkPos[8], 0, 0x107AB, 1);
+ gnap._actionStatus = kAS02LeaveScene;
+ if (_vm->isFlag(kGFPlatypus))
+ plat.walkTo(_vm->_hotspotsWalkPos[8], -1, 0x107CD, 1);
+ _vm->_newSceneNum = 3;
+ }
+ break;
+
+ case kHS02ExitPigpen:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(_vm->_hotspotsWalkPos[9], 0, 0x107AF, 1);
+ gnap._actionStatus = kAS02LeaveScene;
+ if (_vm->isFlag(kGFPlatypus))
+ plat.walkTo(_vm->_hotspotsWalkPos[9], -1, 0x107CF, 1);
+ _vm->_newSceneNum = 1;
+ }
+ break;
+
+ case kHS02WalkArea1:
+ case kHS02WalkArea2:
+ case kHS02WalkArea3:
+ case kHS02WalkArea4:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left && gnap._actionStatus < 0) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+ }
+
+ updateAnimations();
+
+ if (!_vm->isSoundPlaying(0x1091C))
+ _vm->playSound(0x1091C, true);
+
+ if (!_vm->_isLeavingScene) {
+ if (plat._actionStatus < 0 && _vm->isFlag(kGFPlatypus))
+ plat.updateIdleSequence();
+ if (gnap._actionStatus < 0)
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[4]) {
+ // Update bird animation
+ _vm->_timers[4] = _vm->getRandom(100) + 300;
+ if (_vm->getRandom(2) != 0)
+ gameSys.insertSequence(0x156, 256, 0, 0, kSeqNone, 0, 0, 0);
+ else
+ gameSys.insertSequence(0x154, 256, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ if (!_vm->_timers[5] && _nextChickenSequenceId == -1 && gnap._actionStatus != 7 && gnap._actionStatus != 8) {
+ if (_vm->getRandom(6) != 0) {
+ _nextChickenSequenceId = 0x14B;
+ _vm->_timers[5] = _vm->getRandom(20) + 30;
+ } else {
+ _nextChickenSequenceId = 0x14D;
+ _vm->_timers[5] = _vm->getRandom(20) + 50;
+ }
+ }
+ _vm->playSoundC();
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene02::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ switch (gnap._actionStatus) {
+ case kAS02UseTruckNoKeys:
+ gameSys.insertSequence(0x14E, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(0x14E, gnap._id, 0);
+ gnap._sequenceId = 0x14E;
+ gnap._sequenceDatNum = 0;
+ gnap._actionStatus = kAS02UseTruckNoKeysDone;
+ break;
+ case kAS02UseGasWithTruck:
+ gameSys.insertSequence(0x151, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(0x151, gnap._id, 0);
+ gnap._sequenceId = 0x151;
+ gnap._sequenceDatNum = 0;
+ _vm->invRemove(kItemGas);
+ _vm->setGrabCursorSprite(-1);
+ _vm->setFlag(kGFTruckFilledWithGas);
+ gnap._actionStatus = kAS02UseGasWithTruckDone;
+ break;
+ case kAS02UseTruckGas:
+ _vm->_timers[5] = 9999;
+ _vm->_timers[4] = 9999;
+ _vm->hideCursor();
+ _vm->setGrabCursorSprite(-1);
+ if (!_vm->isFlag(kGFTruckKeysUsed)) {
+ gameSys.insertSequence(0x14F, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.waitForUpdate();
+ _vm->setFlag(kGFTruckKeysUsed);
+ gnap._sequenceId = 0x14F;
+ gnap._sequenceDatNum = 0;
+ _vm->invRemove(kItemKeys);
+ _vm->setGrabCursorSprite(-1);
+ }
+ _vm->_newSceneNum = 47;
+ _vm->_sceneDone = true;
+ break;
+ case kAS02UseTruckNoGas:
+ _vm->hideCursor();
+ _vm->setGrabCursorSprite(-1);
+ _vm->_timers[4] = 250;
+ if (!_vm->isFlag(kGFTruckKeysUsed)) {
+ gameSys.insertSequence(0x14F, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.waitForUpdate();
+ _vm->setFlag(kGFTruckKeysUsed);
+ gnap._sequenceId = 0x14F;
+ gnap._sequenceDatNum = 0;
+ _vm->invRemove(kItemKeys);
+ _vm->setGrabCursorSprite(-1);
+ }
+ _vm->_newSceneNum = 47;
+ _vm->_sceneDone = true;
+ _vm->setFlag(kGFUnk25);
+ break;
+ case kAS02GrabTruckGrill:
+ switch (_truckGrillCtr) {
+ case 0:
+ _gnapTruckSequenceId = 0x158;
+ break;
+ case 1:
+ _gnapTruckSequenceId = 0x159;
+ break;
+ case 2:
+ _gnapTruckSequenceId = 0x157;
+ break;
+ }
+ _truckGrillCtr = (_truckGrillCtr + 1) % 3;
+ gameSys.insertSequence(_gnapTruckSequenceId, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_gnapTruckSequenceId, gnap._id, 0);
+ gnap._sequenceId = _gnapTruckSequenceId;
+ gnap._sequenceDatNum = 0;
+ gnap._actionStatus = -1;
+ break;
+ case kAS02LeaveScene:
+ _vm->_sceneDone = true;
+ break;
+ case kAS02TalkChicken:
+ _nextChickenSequenceId = 0x14C;
+ break;
+ case kAS02GrabChicken:
+ _nextChickenSequenceId = 0x150;
+ _vm->_timers[2] = 100;
+ break;
+ case kAS02GrabChickenDone:
+ gameSys.insertSequence(0x107B5, gnap._id, 0x150, 179, kSeqSyncWait, 0, 75 * gnap._pos.x - gnap._gridX, 48 * gnap._pos.y - gnap._gridY);
+ gnap._sequenceId = 0x7B5;
+ gnap._sequenceDatNum = 1;
+ _currChickenSequenceId = 0x14B;
+ gameSys.setAnimation(0x14B, 179, 2);
+ gameSys.insertSequence(_currChickenSequenceId, 179, 0, 0, kSeqNone, 0, 0, 0);
+ gnap._actionStatus = -1;
+ _vm->_timers[5] = 30;
+ break;
+ case kAS02UseTwigWithChicken:
+ gnap.playShowItem(5, 0, 0);
+ gameSys.insertSequence(0x155, 179, _currChickenSequenceId, 179, kSeqSyncExists, 0, 0, 0);
+ _currChickenSequenceId = 0x155;
+ _nextChickenSequenceId = -1;
+ gnap._actionStatus = -1;
+ break;
+ case kAS02UseTruckNoKeysDone:
+ case kAS02UseGasWithTruckDone:
+ default:
+ gnap._actionStatus = -1;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(2) == 2) {
+ if (_nextChickenSequenceId == 0x150) {
+ gameSys.setAnimation(_nextChickenSequenceId, 179, 0);
+ gameSys.insertSequence(_nextChickenSequenceId, 179, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.removeSequence(_currChickenSequenceId, 179, true);
+ _nextChickenSequenceId = -1;
+ _currChickenSequenceId = -1;
+ gnap._actionStatus = kAS02GrabChickenDone;
+ _vm->_timers[5] = 500;
+ } else if (_nextChickenSequenceId == 0x14C) {
+ gameSys.setAnimation(_nextChickenSequenceId, 179, 2);
+ gameSys.insertSequence(_nextChickenSequenceId, 179, _currChickenSequenceId, 179, kSeqSyncWait, 0, 0, 0);
+ _currChickenSequenceId = _nextChickenSequenceId;
+ _nextChickenSequenceId = -1;
+ gnap._actionStatus = -1;
+ } else if (_nextChickenSequenceId != -1) {
+ gameSys.setAnimation(_nextChickenSequenceId, 179, 2);
+ gameSys.insertSequence(_nextChickenSequenceId, 179, _currChickenSequenceId, 179, kSeqSyncWait, 0, 0, 0);
+ _currChickenSequenceId = _nextChickenSequenceId;
+ _nextChickenSequenceId = -1;
+ }
+ }
+}
+
+/*****************************************************************************/
+
+Scene03::Scene03(GnapEngine *vm) : Scene(vm) {
+ _nextPlatSequenceId = -1;
+ _platypusScared = false;
+ _platypusHypnotized = false;
+ _nextFrogSequenceId = -1;
+ _currFrogSequenceId = -1;
+}
+
+int Scene03::init() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ gameSys.setAnimation(0, 0, 0);
+ gameSys.setAnimation(0, 0, 1);
+ gameSys.setAnimation(0, 0, 5);
+ return 0x1CC;
+}
+
+void Scene03::updateHotspots() {
+ _vm->setHotspot(kHS03Platypus, 0, 0, 0, 0, SF_DISABLED | SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS03Grass, 646, 408, 722, 458, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 9, 6);
+ _vm->setHotspot(kHS03ExitTruck, 218, 64, 371, 224, SF_EXIT_U_CURSOR | SF_WALKABLE, 4, 4);
+ _vm->setHotspot(kHS03Creek, 187, 499, 319, 587, SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 3, 7);
+ _vm->setHotspot(kHS03TrappedPlatypus, 450, 256, 661, 414, SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 2, 5);
+ _vm->setHotspot(kHS03WalkAreas1, 0, 500, 300, 600);
+ _vm->setHotspot(kHS03WalkAreas2, 300, 447, 800, 600);
+ _vm->setHotspot(kHS03PlatypusWalkArea, 235, 0, 800, 600);
+ _vm->setHotspot(kHS03WalkAreas3, 0, 0, 800, 354);
+ _vm->setDeviceHotspot(kHS03Device, -1, -1, -1, -1);
+ if (_vm->isFlag(kGFPlatypus))
+ _vm->_hotspots[kHS03Platypus]._flags = SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR;
+ if (_vm->isFlag(kGFGrassTaken))
+ _vm->_hotspots[kHS03Grass]._flags = SF_WALKABLE | SF_DISABLED;
+ if (_vm->isFlag(kGFPlatypus))
+ _vm->_hotspots[kHS03TrappedPlatypus]._flags = SF_DISABLED;
+ if (_vm->isFlag(kGFPlatypus) || _platypusHypnotized)
+ _vm->_hotspots[kHS03PlatypusWalkArea]._flags |= SF_WALKABLE;
+ _vm->_hotspotsCount = 10;
+}
+
+void Scene03::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->playSound(0x10925, true);
+ _vm->startSoundTimerC(7);
+
+ gameSys.insertSequence(0x1CA, 251, 0, 0, kSeqLoop, 0, 0, 0);
+ gameSys.insertSequence(0x1CB, 251, 0, 0, kSeqLoop, 0, 0, 0);
+
+ _platypusHypnotized = false;
+ gnap.initPos(3, 4, kDirBottomRight);
+
+ gameSys.insertSequence(0x1C6, 253, 0, 0, kSeqNone, 0, 0, 0);
+
+ _currFrogSequenceId = 0x1C6;
+ _nextFrogSequenceId = -1;
+ gameSys.setAnimation(0x1C6, 253, 2);
+
+ _vm->_timers[6] = _vm->getRandom(20) + 30;
+ _vm->_timers[4] = _vm->getRandom(100) + 300;
+ _vm->_timers[5] = _vm->getRandom(100) + 200;
+
+ if (_vm->isFlag(kGFPlatypus)) {
+ plat.initPos(5, 4, kDirIdleLeft);
+ } else {
+ _vm->_timers[1] = _vm->getRandom(40) + 20;
+ gameSys.setAnimation(0x1C2, 99, 1);
+ gameSys.insertSequence(0x1C2, 99, 0, 0, kSeqNone, 0, 0, 0);
+ plat._sequenceId = 0x1C2;
+ plat._sequenceDatNum = 0;
+ }
+
+ gameSys.insertSequence(0x1C4, 255, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (!_vm->isFlag(kGFGrassTaken))
+ gameSys.insertSequence(0x1B2, 253, 0, 0, kSeqNone, 0, 0, 0);
+
+ _vm->queueInsertDeviceIcon();
+
+ _vm->endSceneInit();
+
+ if (_vm->isFlag(kGFPlatypus))
+ plat.walkTo(Common::Point(4, 7), -1, 0x107C2, 1);
+ gnap.walkTo(Common::Point(3, 6), -1, 0x107B9, 1);
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS03Platypus:
+ if (gnap._actionStatus < 0 && _vm->isFlag(kGFPlatypus)) {
+ if (_vm->_grabCursorSpriteIndex == kItemDisguise) {
+ gnap.useDisguiseOnPlatypus();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ if (_vm->isFlag(kGFKeysTaken))
+ gnap.playMoan1(plat._pos);
+ else
+ gnap.playScratchingHead(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS03Grass:
+ if (gnap._actionStatus < 0) {
+ if (_vm->isFlag(kGFGrassTaken)) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowItem(_vm->_grabCursorSpriteIndex, 9, 6);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(9, 6));
+ break;
+ case GRAB_CURSOR:
+ gnap.playPullOutDevice(Common::Point(9, 6));
+ gnap.playUseDevice();
+ gameSys.insertSequence(0x1B3, 253, 0x1B2, 253, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(0x1B3, 253, 5);
+ _vm->_hotspots[kHS03Grass]._flags |= SF_WALKABLE | SF_DISABLED;
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS03ExitTruck:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_hotspots[kHS03PlatypusWalkArea]._flags |= SF_WALKABLE;
+ gnap.walkTo(_vm->_hotspotsWalkPos[2], 0, 0x107AD, 1);
+ gnap._actionStatus = kAS03LeaveScene;
+ if (_vm->isFlag(kGFPlatypus))
+ plat.walkTo(_vm->_hotspotsWalkPos[2], -1, 0x107C2, 1);
+ _vm->_hotspots[kHS03PlatypusWalkArea]._flags &= ~SF_WALKABLE;
+ if (_vm->_cursorValue == 1)
+ _vm->_newSceneNum = 2;
+ else
+ _vm->_newSceneNum = 33;
+ }
+ break;
+
+ case kHS03Creek:
+ if (gnap._actionStatus == -1) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan2(Common::Point(2, 8));
+ break;
+ case GRAB_CURSOR:
+ if (!_vm->isFlag(kGFPlatypus))
+ _vm->_hotspots[kHS03PlatypusWalkArea]._flags |= SF_WALKABLE;
+ if (gnap.walkTo(_vm->_hotspotsWalkPos[3], 0, gnap.getSequenceId(kGSIdle, _vm->_hotspotsWalkPos[3] + Common::Point(1, 1)) | 0x10000, 1))
+ gnap._actionStatus = kAS03GrabCreek;
+ if (!_vm->isFlag(kGFPlatypus))
+ _vm->_hotspots[kHS03PlatypusWalkArea]._flags &= ~SF_WALKABLE;
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS03TrappedPlatypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->isFlag(kGFPlatypus)) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowItem(_vm->_grabCursorSpriteIndex, 8, 4);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(8, 4));
+ break;
+ case GRAB_CURSOR:
+ if (_platypusHypnotized) {
+ gnap.walkTo(Common::Point(7, 6), 0, 0x107B5, 1);
+ gnap._actionStatus = kAS03FreePlatypus;
+ } else {
+ gnap.walkTo(_vm->_hotspotsWalkPos[4], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ if (_platypusScared)
+ gnap._actionStatus = kAS03GrabScaredPlatypus;
+ else
+ gnap._actionStatus = kAS03GrabPlatypus;
+ }
+ break;
+ case TALK_CURSOR:
+ if (_platypusHypnotized) {
+ gnap.playBrainPulsating(Common::Point(8, 4));
+ } else {
+ gnap._idleFacing = kDirBottomRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[4], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ if (_platypusScared)
+ gnap._actionStatus = kAS03HypnotizeScaredPlat;
+ else
+ gnap._actionStatus = kAS03HypnotizePlat;
+ }
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS03Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS03WalkAreas1:
+ case kHS03WalkAreas2:
+ case kHS03WalkAreas3:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ case kHS03PlatypusWalkArea:
+ if (gnap._actionStatus < 0) {
+ if (_vm->isFlag(kGFPlatypus) || _platypusHypnotized) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ } else {
+ gnap.walkTo(_vm->_hotspotsWalkPos[4], 0, 0x107B5, 1);
+ if (_platypusScared)
+ gnap._actionStatus = kAS03GrabScaredPlatypus;
+ else
+ gnap._actionStatus = kAS03GrabPlatypus;
+ }
+ }
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left && gnap._actionStatus < 0) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+
+ }
+
+ updateAnimations();
+
+ if (!_vm->isSoundPlaying(0x10925))
+ _vm->playSound(0x10925, true);
+
+ if (!_vm->_isLeavingScene) {
+ if (plat._actionStatus < 0 && _vm->isFlag(kGFPlatypus))
+ plat.updateIdleSequence();
+ if (gnap._actionStatus < 0)
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[1] && !_platypusScared) {
+ _vm->_timers[1] = _vm->getRandom(40) + 20;
+ if (gnap._actionStatus < 0 && plat._actionStatus < 0 && !_vm->isFlag(kGFPlatypus) && !_platypusHypnotized)
+ _nextPlatSequenceId = 450;
+ }
+ if (!_vm->_timers[6]) {
+ _vm->_timers[6] = _vm->getRandom(20) + 30;
+ if (gnap._actionStatus < 0 && plat._actionStatus < 0 && _nextFrogSequenceId == -1) {
+ if (_vm->getRandom(5) == 1)
+ _nextFrogSequenceId = 0x1C6;
+ else
+ _nextFrogSequenceId = 0x1C7;
+ }
+ }
+ if (!_vm->_timers[4]) {
+ // Update bird animation
+ _vm->_timers[4] = _vm->getRandom(100) + 300;
+ if (gnap._actionStatus < 0 && plat._actionStatus < 0)
+ gameSys.insertSequence(_vm->getRandom(2) != 0 ? 0x1C8 : 0x1C3, 253, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ if (!_vm->_timers[5]) {
+ _vm->_timers[5] = _vm->getRandom(100) + 200;
+ if (gnap._actionStatus < 0 && plat._actionStatus < 0) {
+ gameSys.setAnimation(0x1C5, 253, 4);
+ gameSys.insertSequence(0x1C5, 253, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ }
+ _vm->playSoundC();
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[5] = _vm->getRandom(100) + 200;
+ _vm->_timers[4] = _vm->getRandom(100) + 300;
+ _vm->_timers[6] = _vm->getRandom(20) + 30;
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene03::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS03LeaveScene:
+ _vm->_sceneDone = true;
+ break;
+ case kAS03FreePlatypus:
+ _nextPlatSequenceId = 0x1BC;
+ break;
+ case kAS03FreePlatypusDone:
+ gnap._actionStatus = -1;
+ plat._pos = Common::Point(6, 6);
+ plat._idleFacing = kDirIdleRight;
+ plat._id = 120;
+ gameSys.insertSequence(0x107CA, plat._id, 0x1BC, 99,
+ kSeqSyncWait, 0, 75 * plat._pos.x - plat._gridX, 48 * plat._pos.y - plat._gridY);
+ gameSys.insertSequence(0x1B7, 99, 0, 0, kSeqNone, 0, 0, 0);
+ plat._sequenceDatNum = 1;
+ plat._sequenceId = 0x7CA;
+ _vm->setFlag(kGFPlatypus);
+ _nextPlatSequenceId = -1;
+ updateHotspots();
+ break;
+ case kAS03HypnotizePlat:
+ gnap.playBrainPulsating();
+ _vm->addFullScreenSprite(0x106, 255);
+ gameSys.setAnimation(0x1C9, 256, 1);
+ gameSys.insertSequence(0x1C9, 256, 0, 0, kSeqNone, 0, 0, 0);
+ while (gameSys.getAnimationStatus(1) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+ _vm->removeFullScreenSprite();
+ gameSys.setAnimation(0x1BA, 99, 1);
+ gameSys.insertSequence(0x1BA, 99, plat._sequenceId | (plat._sequenceDatNum << 16), 99, kSeqSyncExists, 0, 0, 0);
+ plat._sequenceDatNum = 0;
+ plat._sequenceId = 0x1BA;
+ gnap._actionStatus = -1;
+ _platypusHypnotized = true;
+ updateHotspots();
+ break;
+ case kAS03HypnotizeScaredPlat:
+ gnap.playBrainPulsating();
+ gameSys.insertSequence(0x1BF, 99, plat._sequenceId | (plat._sequenceDatNum << 16), 99, kSeqSyncExists, 0, 0, 0);
+ gameSys.setAnimation(0x1BF, 99, 1);
+ while (gameSys.getAnimationStatus(1) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+ _vm->addFullScreenSprite(0x106, 255);
+ gameSys.setAnimation(0x1C9, 256, 1);
+ gameSys.insertSequence(0x1C9, 256, 0, 0, kSeqNone, 0, 0, 0);
+ while (gameSys.getAnimationStatus(1) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+ _vm->removeFullScreenSprite();
+ gameSys.setAnimation(0x1BA, 99, 1);
+ gameSys.insertSequence(0x1BA, 99, 447, 99, kSeqSyncWait, 0, 0, 0);
+ plat._sequenceDatNum = 0;
+ plat._sequenceId = 0x1BA;
+ gnap._actionStatus = -1;
+ _platypusHypnotized = true;
+ updateHotspots();
+ break;
+ case kAS03GrabPlatypus:
+ _nextPlatSequenceId = 0x1BD;
+ _platypusHypnotized = false;
+ break;
+ case kAS03GrabScaredPlatypus:
+ _nextPlatSequenceId = 0x1C0;
+ _platypusHypnotized = false;
+ break;
+ case kAS03GrabCreek:
+ gameSys.insertSequence(0x1B4, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(0x1B4, gnap._id, 0);
+ gnap._sequenceId = 0x1B4;
+ gnap._sequenceDatNum = 0;
+ gnap._actionStatus = kAS03GrabCreekDone;
+ break;
+ default:
+ gnap._actionStatus = -1;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(1) == 2) {
+ if (_nextPlatSequenceId == 0x1BD || _nextPlatSequenceId == 0x1C0) {
+ gameSys.setAnimation(0, 0, 1);
+ _platypusScared = true;
+ gameSys.insertSequence(0x1B5, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(_nextPlatSequenceId, 99, plat._sequenceId | (plat._sequenceDatNum << 16), 99, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x1B5;
+ gnap._sequenceDatNum = 0;
+ gnap._idleFacing = kDirIdleLeft;
+ plat._sequenceId = _nextPlatSequenceId;
+ plat._sequenceDatNum = 0;
+ gameSys.setAnimation(_nextPlatSequenceId, 99, 1);
+ _nextPlatSequenceId = -1;
+ gnap._actionStatus = -1;
+ } else if (_nextPlatSequenceId == 0x1BC) {
+ gnap._pos = Common::Point(3, 6);
+ gameSys.insertSequence(0x1B6, 120, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x1BC, 99, plat._sequenceId | (plat._sequenceDatNum << 16), 99, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(0x1BC, 99, 0);
+ gnap._id = 20 * gnap._pos.y;
+ gnap._sequenceId = 0x1B6;
+ gnap._sequenceDatNum = 0;
+ gnap._idleFacing = kDirIdleLeft;
+ gnap._actionStatus = kAS03FreePlatypusDone;
+ _nextPlatSequenceId = -1;
+ } else if (_nextPlatSequenceId == 0x1C2 && !_platypusScared) {
+ gameSys.setAnimation(0, 0, 1);
+ gameSys.insertSequence(0x1C2, 99, plat._sequenceId | (plat._sequenceDatNum << 16), 99, kSeqSyncWait, 0, 0, 0);
+ plat._sequenceId = 0x1C2;
+ plat._sequenceDatNum = 0;
+ gameSys.setAnimation(0x1C2, 99, 1);
+ _nextPlatSequenceId = -1;
+ } else if (_nextPlatSequenceId == -1 && _platypusScared && !_platypusHypnotized) {
+ gameSys.setAnimation(0, 0, 1);
+ gameSys.setAnimation(0x1BE, 99, 1);
+ gameSys.insertSequence(0x1BE, 99, plat._sequenceId | (plat._sequenceDatNum << 16), 99, kSeqSyncWait, 0, 0, 0);
+ plat._sequenceId = 0x1BE;
+ plat._sequenceDatNum = 0;
+ _nextPlatSequenceId = -1;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(2) == 2 && _nextFrogSequenceId != -1) {
+ gameSys.setAnimation(_nextFrogSequenceId, 253, 2);
+ gameSys.insertSequence(_nextFrogSequenceId, 253, _currFrogSequenceId, 253, kSeqSyncWait, 0, 0, 0);
+ _currFrogSequenceId = _nextFrogSequenceId;
+ _nextFrogSequenceId = -1;
+ }
+
+ if (gameSys.getAnimationStatus(5) == 2) {
+ gameSys.setAnimation(0, 0, 5);
+ _vm->invAdd(kItemGrass);
+ _vm->setGrabCursorSprite(kItemGrass);
+ _vm->setFlag(kGFGrassTaken);
+ updateHotspots();
+ }
+}
+
+/*****************************************************************************/
+
+Scene04::Scene04(GnapEngine *vm) : Scene(vm) {
+ _dogIdCtr = 0;
+ _triedWindow = false;
+ _nextDogSequenceId = -1;
+ _currDogSequenceId = -1;
+}
+
+int Scene04::init() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ gameSys.setAnimation(0, 0, 0);
+ gameSys.setAnimation(0, 0, 1);
+ gameSys.setAnimation(0, 0, 2);
+ return 0x214;
+}
+
+void Scene04::updateHotspots() {
+ _vm->setHotspot(kHS04Platypus, 0, 0, 0, 0, SF_DISABLED | SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS04Twig, 690, 394, 769, 452, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 9, 6);
+ _vm->setHotspot(kHS04Dog, 550, 442, 680, 552, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 6, 8);
+ _vm->setHotspot(kHS04Axe, 574, 342, 680, 412, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 6, 7);
+ _vm->setHotspot(kHS04Door, 300, 244, 386, 410, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 6, 7);
+ _vm->setHotspot(kHS04ExitTruck, 226, 580, 688, 600, SF_EXIT_D_CURSOR | SF_WALKABLE, 5, 9);
+ _vm->setHotspot(kHS04Window, 121, 295, 237, 342, SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 3, 7);
+ _vm->setHotspot(kHS04ExitBarn, 585, 154, 800, 276, SF_EXIT_U_CURSOR, 10, 8);
+ _vm->setHotspot(kHS04WalkArea1, 0, 0, 562, 461);
+ _vm->setHotspot(kHS04WalkArea2, 562, 0, 800, 500);
+ _vm->setDeviceHotspot(kHS04Device, -1, -1, -1, -1);
+ if (_vm->isFlag(kGFPlatypus))
+ _vm->_hotspots[kHS04Platypus]._flags = SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR;
+ if (_vm->isFlag(kGFTwigTaken))
+ _vm->_hotspots[kHS04Twig]._flags = SF_WALKABLE | SF_DISABLED;
+ if (_vm->isFlag(kGFPlatypusTalkingToAssistant) || _vm->_cursorValue == 1)
+ _vm->_hotspots[kHS04Axe]._flags = SF_DISABLED;
+ _vm->_hotspotsCount = 11;
+}
+
+void Scene04::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->playSound(0x1091C, true);
+ _vm->startSoundTimerC(4);
+
+ gameSys.insertSequence(0x210, 139 - _dogIdCtr, 0, 0, kSeqNone, 0, 0, 0);
+
+ _currDogSequenceId = 0x210;
+ _nextDogSequenceId = -1;
+
+ gameSys.setAnimation(0x210, 139 - _dogIdCtr, 3);
+ _dogIdCtr = (_dogIdCtr + 1) % 2;
+ _vm->_timers[6] = _vm->getRandom(20) + 60;
+ _vm->_timers[5] = _vm->getRandom(150) + 300;
+ _vm->_timers[7] = _vm->getRandom(150) + 200;
+ _vm->_timers[8] = _vm->getRandom(150) + 400;
+
+ if (!_vm->isFlag(kGFPlatypusTalkingToAssistant) && _vm->_cursorValue == 4)
+ gameSys.insertSequence(0x212, 100, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (!_vm->isFlag(kGFTwigTaken))
+ gameSys.insertSequence(0x1FE, 100, 0, 0, kSeqNone, 0, 0, 0);
+
+ _vm->queueInsertDeviceIcon();
+
+ if (_vm->isFlag(kGFPlatypusDisguised)) {
+ _vm->_timers[3] = 300;
+ _vm->setGrabCursorSprite(kItemKeys);
+ gnap._pos = Common::Point(4, 7);
+ gnap._id = 140;
+ plat._pos = Common::Point(6, 7);
+ plat._id = 141;
+ gameSys.insertSequence(0x107B5, 140, 0, 0, kSeqNone, 0, 300 - gnap._gridX, 336 - gnap._gridY);
+ gameSys.insertSequence(0x20C, 141, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.insertSequence(0x208, 121, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.insertSequence(0x209, 121, 0x208, 121, kSeqSyncWait, 0, 0, 0);
+ _vm->endSceneInit();
+ _vm->invRemove(kItemDisguise);
+ _vm->invAdd(kItemKeys);
+ _vm->setFlag(kGFKeysTaken);
+ _vm->clearFlag(kGFPlatypusDisguised);
+ plat._sequenceId = 0x20C;
+ plat._sequenceDatNum = 0;
+ plat._idleFacing = kDirBottomRight;
+ gnap._sequenceId = 0x7B5;
+ gnap._sequenceDatNum = 1;
+ gameSys.waitForUpdate();
+ } else {
+ gameSys.insertSequence(0x209, 121, 0, 0, kSeqNone, 0, 0, 0);
+ if (_vm->_prevSceneNum == 2) {
+ gnap.initPos(5, 11, kDirUpRight);
+ if (_vm->isFlag(kGFPlatypus))
+ plat.initPos(6, 11, kDirUpLeft);
+ _vm->endSceneInit();
+ if (_vm->isFlag(kGFPlatypus))
+ plat.walkTo(Common::Point(5, 8), -1, 0x107C2, 1);
+ gnap.walkTo(Common::Point(6, 9), -1, 0x107BA, 1);
+ } else if (_vm->_prevSceneNum == 38) {
+ gnap.initPos(5, 7, kDirBottomRight);
+ plat.initPos(4, 7, kDirIdleLeft);
+ _vm->endSceneInit();
+ } else {
+ gnap.initPos(12, 9, kDirBottomRight);
+ if (_vm->isFlag(kGFPlatypus))
+ plat.initPos(12, 8, kDirIdleLeft);
+ _vm->endSceneInit();
+ if (_vm->isFlag(kGFPlatypus))
+ plat.walkTo(Common::Point(9, 8), -1, 0x107C2, 1);
+ gnap.walkTo(Common::Point(9, 9), -1, 0x107BA, 1);
+ }
+ }
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->testWalk(0, 4, -1, -1, -1, -1);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS04Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS04Platypus:
+ if (gnap._actionStatus < 0 && _vm->isFlag(kGFPlatypus)) {
+ if (_vm->_grabCursorSpriteIndex == kItemDisguise) {
+ gnap.useDisguiseOnPlatypus();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ if (_vm->isFlag(kGFKeysTaken))
+ gnap.playMoan1(plat._pos);
+ else
+ gnap.playScratchingHead(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ if (_vm->_cursorValue == 4)
+ gnap.kissPlatypus(0);
+ else
+ gnap.playMoan1(plat._pos);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS04Twig:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowItem(_vm->_grabCursorSpriteIndex, 9, 6);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(_vm->_hotspotsWalkPos[1]);
+ break;
+ case GRAB_CURSOR:
+ gnap.playPullOutDevice(_vm->_hotspotsWalkPos[1]);
+ gnap.playUseDevice(_vm->_hotspotsWalkPos[1]);
+ gameSys.insertSequence(0x1FD, 100, 510, 100, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(0x1FD, 100, 2);
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS04Axe:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[3], 9, 5);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan2(_vm->_hotspotsWalkPos[3]);
+ break;
+ case GRAB_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[3], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS04GrabAxe;
+ _vm->setFlag(kGFPlatypusTalkingToAssistant);
+ updateHotspots();
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS04Dog:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[2], 9, 7);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ if (gnap.walkTo(gnap._pos, 0, -1, 1)) {
+ gnap.playMoan2(_vm->_hotspotsWalkPos[2]);
+ _nextDogSequenceId = 0x20F;
+ }
+ break;
+ case GRAB_CURSOR:
+ gnap._idleFacing = kDirBottomRight;
+ if (gnap.walkTo(_vm->_hotspotsWalkPos[2], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1))
+ gnap._actionStatus = kAS04GrabDog;
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirBottomRight;
+ if (gnap.walkTo(gnap._pos, 0, -1, 1)) {
+ gnap.playBrainPulsating(_vm->_hotspotsWalkPos[2]);
+ _nextDogSequenceId = 0x20E;
+ }
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS04Door:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot], 4, 3);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playScratchingHead(Common::Point(4, 3));
+ break;
+ case GRAB_CURSOR:
+ if (_vm->_cursorValue == 1) {
+ gnap.walkTo(_vm->_hotspotsWalkPos[4], 0, 0x107BC, 1);
+ gnap._actionStatus = kAS04OpenDoor;
+ _vm->_timers[5] = 300;
+ gnap._idleFacing = kDirUpLeft;
+ } else {
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(_vm->_hotspotsWalkPos[4], 0, 0x107BC, 1);
+ gnap._actionStatus = kAS04LeaveScene;
+ _vm->_newSceneNum = 38;
+ }
+ break;
+ case TALK_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS04ExitTruck:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(_vm->_hotspotsWalkPos[5], 0, 0x107AE, 1);
+ gnap._actionStatus = kAS04LeaveScene;
+ if (_vm->isFlag(kGFPlatypus))
+ plat.walkTo(_vm->_hotspotsWalkPos[5], -1, 0x107C7, 1);
+ if (_vm->_cursorValue == 1)
+ _vm->_newSceneNum = 2;
+ else
+ _vm->_newSceneNum = 33;
+ }
+ break;
+
+ case kHS04Window:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot], 2, 3);
+ } else if (_vm->isFlag(kGFKeysTaken)) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ if (gnap.walkTo(_vm->_hotspotsWalkPos[7], 0, gnap.getSequenceId(kGSIdle, Common::Point(10, 2)) | 0x10000, 1)) {
+ if (_triedWindow) {
+ gnap._actionStatus = kAS04GetKeyAnother;
+ } else {
+ gnap._actionStatus = kAS04GetKeyFirst;
+ _triedWindow = true;
+ }
+ }
+ break;
+ case GRAB_CURSOR:
+ gnap.playScratchingHead(_vm->_hotspotsWalkPos[7]);
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS04ExitBarn:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(_vm->_hotspotsWalkPos[8], 0, 0x107AB, 1);
+ gnap._actionStatus = kAS04LeaveScene;
+ if (_vm->isFlag(kGFPlatypus))
+ plat.walkTo(_vm->_hotspotsWalkPos[8] + Common::Point(0, 1), -1, 0x107C1, 1);
+ if (_vm->_cursorValue == 1)
+ _vm->_newSceneNum = 5;
+ else
+ _vm->_newSceneNum = 35;
+ }
+ break;
+
+ case kHS04WalkArea1:
+ case kHS04WalkArea2:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left && gnap._actionStatus < 0) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+
+ }
+
+ updateAnimations();
+
+ if (!_vm->isSoundPlaying(0x1091C))
+ _vm->playSound(0x1091C, true);
+
+ if (!_vm->_isLeavingScene) {
+ if (plat._actionStatus < 0 && _vm->isFlag(kGFPlatypus))
+ plat.updateIdleSequence2();
+ if (gnap._actionStatus < 0)
+ gnap.updateIdleSequence2();
+ if (!_vm->_timers[5]) {
+ _vm->_timers[5] = _vm->getRandom(150) + 300;
+ if (gnap._actionStatus < 0)
+ gameSys.insertSequence(0x20D, 79, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ if (!_vm->_timers[7]) {
+ _vm->_timers[7] = _vm->getRandom(150) + 200;
+ gameSys.insertSequence(0x1FC, 59, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ if (!_vm->_timers[6]) {
+ _vm->_timers[6] = _vm->getRandom(20) + 60;
+ if (_nextDogSequenceId == -1)
+ _nextDogSequenceId = 0x210;
+ }
+ if (!_vm->_timers[8]) {
+ _vm->_timers[8] = _vm->getRandom(150) + 400;
+ gameSys.insertSequence(0x213, 20, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ _vm->playSoundC();
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene04::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS04LeaveScene:
+ _vm->_sceneDone = true;
+ break;
+ case kAS04OpenDoor:
+ gameSys.insertSequence(0x205, gnap._id, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.insertSequence(0x207, 121, 521, 121, kSeqSyncWait, 0, 0, 0);
+ gnap._pos = Common::Point(6, 7);
+ gameSys.insertSequence(0x107B5, gnap._id,
+ makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id,
+ kSeqSyncWait, _vm->getSequenceTotalDuration(0x205) - 1, 450 - gnap._gridX, 336 - gnap._gridY);
+ gameSys.setAnimation(0x107B5, gnap._id, 0);
+ gnap._sequenceId = 0x7B5;
+ gnap._sequenceDatNum = 1;
+ gnap._actionStatus = kAS04OpenDoorDone;
+ break;
+ case kAS04OpenDoorDone:
+ gameSys.insertSequence(0x209, 121, 0x207, 121, kSeqSyncWait, 0, 0, 0);
+ gnap._actionStatus = -1;
+ break;
+ case kAS04GetKeyFirst:
+ gameSys.insertSequence(0x204, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(0x204, gnap._id, 0);
+ gnap._sequenceId = 0x204;
+ gnap._sequenceDatNum = 0;
+ gnap._actionStatus = kAS04GetKeyFirst2;
+ break;
+ case kAS04GetKeyFirst2:
+ gameSys.insertSequence(0x206, 255, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x1FF, 256, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.insertSequence(0x20B, 256, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.setAnimation(0x20B, 256, 0);
+ gnap._sequenceId = 0x206;
+ gnap._sequenceDatNum = 0;
+ gnap._actionStatus = kAS04GetKeyFirstDone;
+ break;
+ case kAS04GetKeyFirstDone:
+ gameSys.requestRemoveSequence(0x1FF, 256);
+ gameSys.requestRemoveSequence(0x20B, 256);
+ gameSys.insertSequence(0x107B5, gnap._id,
+ makeRid(gnap._sequenceDatNum, gnap._sequenceId), 255,
+ kSeqSyncWait, 0, 75 * gnap._pos.x - gnap._gridX, 48 * gnap._pos.y - gnap._gridY);
+ gnap._idleFacing = kDirBottomRight;
+ gnap._sequenceId = 0x7B5;
+ gnap._sequenceDatNum = 1;
+ gnap._actionStatus = -1;
+ break;
+ case kAS04GetKeyAnother:
+ gameSys.insertSequence(0x202, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(0x202, gnap._id, 0);
+ gnap._sequenceId = 0x202;
+ gnap._sequenceDatNum = 0;
+ gnap._actionStatus = kAS04GetKeyAnother2;
+ break;
+ case kAS04GetKeyAnother2:
+ gameSys.insertSequence(0x203, 255, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x1FF, 256, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.insertSequence(0x20A, 256, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.setAnimation(0x20A, 256, 0);
+ gnap._sequenceId = 0x203;
+ gnap._sequenceDatNum = 0;
+ gnap._actionStatus = kAS04GetKeyAnotherDone;
+ break;
+ case kAS04GetKeyAnotherDone:
+ gameSys.removeSequence(0x1FF, 256, true);
+ gameSys.removeSequence(0x20A, 256, true);
+ gameSys.insertSequence(0x107B5, gnap._id,
+ makeRid(gnap._sequenceDatNum, gnap._sequenceId), 255,
+ kSeqSyncWait, 0, 75 * gnap._pos.x - gnap._gridX, 48 * gnap._pos.y - gnap._gridY);
+ gnap._sequenceId = 0x7B5;
+ gnap._sequenceDatNum = 1;
+ gnap._idleFacing = kDirBottomRight;
+ gnap._actionStatus = -1;
+ break;
+ case kAS04GrabDog:
+ _nextDogSequenceId = 0x201;
+ break;
+ case kAS04GrabAxe:
+ gameSys.insertSequence(0x211, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.requestRemoveSequence(0x212, 100);
+ gnap._sequenceDatNum = 0;
+ gnap._sequenceId = 0x211;
+ gnap._actionStatus = -1;
+ break;
+ default:
+ gnap._actionStatus = -1;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(2) == 2) {
+ gameSys.setAnimation(0, 0, 2);
+ _vm->invAdd(kItemTwig);
+ _vm->setGrabCursorSprite(kItemTwig);
+ _vm->setFlag(kGFTwigTaken);
+ updateHotspots();
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2) {
+ if (_nextDogSequenceId == 0x201) {
+ gameSys.insertSequence(_nextDogSequenceId, 139 - _dogIdCtr,
+ _currDogSequenceId, 139 - (_dogIdCtr + 1) % 2,
+ kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x200, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextDogSequenceId, 139 - _dogIdCtr, 3);
+ _dogIdCtr = (_dogIdCtr + 1) % 2;
+ _currDogSequenceId = 0x201;
+ gnap._sequenceId = 0x200;
+ gnap._sequenceDatNum = 0;
+ gnap._actionStatus = -1;
+ _vm->_timers[6] = _vm->getRandom(20) + 60;
+ _nextDogSequenceId = -1;
+ } else if (_nextDogSequenceId != -1) {
+ gameSys.insertSequence(_nextDogSequenceId, 139 - _dogIdCtr,
+ _currDogSequenceId, 139 - (_dogIdCtr + 1) % 2,
+ kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextDogSequenceId, 139 - _dogIdCtr, 3);
+ _dogIdCtr = (_dogIdCtr + 1) % 2;
+ _currDogSequenceId = _nextDogSequenceId;
+ _nextDogSequenceId = -1;
+ }
+ }
+}
+
+/*****************************************************************************/
+
+Scene05::Scene05(GnapEngine *vm) : Scene(vm) {
+ _nextChickenSequenceId = -1;
+ _currChickenSequenceId = -1;
+}
+
+int Scene05::init() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ gameSys.setAnimation(0, 0, 0);
+ gameSys.setAnimation(0, 0, 1);
+ gameSys.setAnimation(0, 0, 3);
+ return _vm->isFlag(kGFBarnPadlockOpen) ? 0x151 : 0x150;
+}
+
+void Scene05::updateHotspots() {
+ _vm->setHotspot(kHS05Platypus, 0, 0, 0, 0, SF_DISABLED | SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS05Haystack, 236, 366, 372, 442, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 5, 7);
+ _vm->setHotspot(kHS05Padlock, 386, 230, 626, 481, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 5, 7);
+ _vm->setHotspot(kHS05Ladder, 108, 222, 207, 444, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 4, 7);
+ _vm->setHotspot(kHS05ExitHouse, 0, 395, 20, 600, SF_EXIT_L_CURSOR | SF_WALKABLE, 0, 8);
+ _vm->setHotspot(kHS05Chicken, 612, 462, 722, 564, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 7, 8);
+ _vm->setHotspot(kHS05WalkArea1, 104, 0, 421, 480);
+ _vm->setHotspot(kHS05WalkArea2, 422, 0, 800, 487);
+ _vm->setHotspot(kHS05WalkArea3, 0, 0, 104, 499);
+ _vm->setDeviceHotspot(kHS05Device, -1, -1, -1, -1);
+ if (_vm->isFlag(kGFPlatypus))
+ _vm->_hotspots[kHS05Platypus]._flags = SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR;
+ if (_vm->isFlag(kGFBarnPadlockOpen))
+ _vm->_hotspots[kHS05Padlock]._flags = SF_EXIT_U_CURSOR;
+ _vm->_hotspotsCount = 10;
+}
+
+void Scene05::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->playSound(0x1091C, true);
+ _vm->startSoundTimerC(7);
+
+ _currChickenSequenceId = 0x142;
+ gameSys.setAnimation(0x142, 100, 3);
+ gameSys.insertSequence(0x142, 100, 0, 0, kSeqNone, 0, 0, 0);
+
+ _nextChickenSequenceId = -1;
+
+ _vm->_timers[5] = _vm->getRandom(10) + 30;
+ _vm->_timers[6] = _vm->getRandom(150) + 300;
+
+ if (_vm->isFlag(kGFBarnPadlockOpen))
+ gameSys.insertSequence(0x14A, 141, 0, 0, kSeqNone, 0, 0, 0);
+
+ _vm->queueInsertDeviceIcon();
+
+ if (_vm->_prevSceneNum != 6 && _vm->_prevSceneNum != 36) {
+ gnap.initPos(-1, 8, kDirBottomRight);
+ if (_vm->isFlag(kGFPlatypus))
+ plat.initPos(-1, 9, kDirIdleLeft);
+ _vm->endSceneInit();
+ if (_vm->isFlag(kGFPlatypus))
+ plat.walkTo(Common::Point(2, 8), -1, 0x107C2, 1);
+ gnap.walkTo(Common::Point(2, 9), -1, 0x107B9, 1);
+ } else {
+ gnap.initPos(6, 8, kDirBottomRight);
+ if (_vm->isFlag(kGFPlatypus))
+ plat.initPos(7, 9, kDirIdleLeft);
+ _vm->endSceneInit();
+ }
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->testWalk(0, 12, -1, -1, -1, -1);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS05Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS05Platypus:
+ if (gnap._actionStatus < 0 && _vm->isFlag(kGFPlatypus)) {
+ if (_vm->_grabCursorSpriteIndex == kItemDisguise) {
+ gnap.useDisguiseOnPlatypus();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ if (_vm->isFlag(kGFKeysTaken))
+ gnap.playMoan1(plat._pos);
+ else
+ gnap.playScratchingHead(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS05Haystack:
+ if (gnap._actionStatus < 0 && plat._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[1] + Common::Point(-2, 0), 4, 5);
+ } else if (_vm->isFlag(kGFNeedleTaken)) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(_vm->_hotspotsWalkPos[1] + Common::Point(0, -1));
+ break;
+ case GRAB_CURSOR:
+ case TALK_CURSOR:
+ gnap.playImpossible();
+ break;
+ case PLAT_CURSOR:
+ if (_vm->isFlag(kGFPlatypus)) {
+ gnap.useDeviceOnPlatypus();
+ if (plat.walkTo(_vm->_hotspotsWalkPos[1], 1, 0x107C2, 1)) {
+ plat._actionStatus = kAS05PlatSearchHaystack;
+ plat._idleFacing = kDirIdleRight;
+ }
+ if (gnap._pos.x == 4 && (gnap._pos.y == 8 || gnap._pos.y == 7))
+ gnap.walkStep();
+ gnap.playIdle(plat._pos);
+ }
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS05Chicken:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemTwig) {
+ gnap._idleFacing = kDirUpRight;
+ Common::Point checkPt = _vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot] + Common::Point(0, 1);
+ gnap.walkTo(checkPt, 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS05UseTwigWithChicken;
+ } else if (_vm->_grabCursorSpriteIndex >= 0)
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot] + Common::Point(0, 1), 9, 7);
+ else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan2(Common::Point(9, 7));
+ break;
+ case GRAB_CURSOR:
+ gnap._idleFacing = kDirBottomRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[5], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS05GrabChicken;
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirBottomRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[5], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS05TalkChicken;
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS05Ladder:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot], 2, 5);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan2(Common::Point(2, 4));
+ break;
+ case GRAB_CURSOR:
+ gnap._idleFacing = kDirBottomLeft;
+ gnap.walkTo(_vm->_hotspotsWalkPos[3], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS05GrabLadder;
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS05Padlock:
+ if (_vm->isFlag(kGFBarnPadlockOpen)) {
+ _vm->_isLeavingScene = true;
+ Common::Point destPt = _vm->_hotspotsWalkPos[2] + Common::Point(- 1, 1);
+ gnap.walkTo(destPt, 0, -1, 1);
+ gnap._actionStatus = kAS05EnterBarn;
+ if (_vm->_cursorValue == 1)
+ _vm->_newSceneNum = 6;
+ else
+ _vm->_newSceneNum = 36;
+ } else if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemNeedle) {
+ if (gnap.walkTo(_vm->_hotspotsWalkPos[2], 0,
+ gnap.getSequenceId(kGSIdle, _vm->_hotspotsWalkPos[2]) | 0x10000, 1))
+ gnap._actionStatus = kAS05PickPadlock;
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[2], 7, 4);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(7, 4));
+ break;
+ case GRAB_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS05TryPickPadlock;
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS05ExitHouse:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(_vm->_hotspotsWalkPos[4], 0, 0x107AF, 1);
+ gnap._actionStatus = kAS05LeaveScene;
+ if (_vm->isFlag(kGFPlatypus))
+ plat.walkTo(_vm->_hotspotsWalkPos[4] + Common::Point(0, 1), -1, 0x107C7, 1);
+ if (_vm->_cursorValue == 1)
+ _vm->_newSceneNum = 4;
+ else
+ _vm->_newSceneNum = 37;
+ }
+ break;
+
+ case kHS05WalkArea1:
+ case kHS05WalkArea2:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ case kHS05WalkArea3:
+ // Nothing
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left && gnap._actionStatus < 0) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+
+ }
+
+ updateAnimations();
+
+ if (!_vm->isSoundPlaying(0x1091C))
+ _vm->playSound(0x1091C, true);
+
+ if (!_vm->_isLeavingScene) {
+ if (_vm->isFlag(kGFPlatypus))
+ plat.updateIdleSequence();
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[5]) {
+ _vm->_timers[5] = _vm->getRandom(20) + 30;
+ if (gnap._actionStatus != kAS05TalkChicken && _nextChickenSequenceId == -1) {
+ if (_vm->getRandom(4) != 0)
+ _nextChickenSequenceId = 0x142;
+ else
+ _nextChickenSequenceId = 0x143;
+ }
+ }
+ if (!_vm->_timers[6]) {
+ _vm->_timers[6] = _vm->getRandom(150) + 300;
+ if (gnap._actionStatus < 0)
+ gameSys.insertSequence(0x149, 39, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ _vm->playSoundC();
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[5] = _vm->getRandom(20) + 30;
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene05::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS05LeaveScene:
+ _vm->_sceneDone = true;
+ gnap._actionStatus = -1;
+ break;
+ case kAS05TryPickPadlock:
+ gameSys.insertSequence(0x148, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x148;
+ gnap._sequenceDatNum = 0;
+ gnap._actionStatus = -1;
+ break;
+ case kAS05PickPadlock:
+ gameSys.setAnimation(0x147, gnap._id, 0);
+ gameSys.insertSequence(0x147, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x147;
+ gnap._sequenceDatNum = 0;
+ _vm->setFlag(kGFBarnPadlockOpen);
+ _vm->setFlag(kGFSceneFlag1);
+ _vm->setGrabCursorSprite(-1);
+ _vm->_newSceneNum = 6;
+ _vm->_timers[2] = 100;
+ _vm->invRemove(kItemNeedle);
+ gnap._actionStatus = kAS05LeaveScene;
+ break;
+ case kAS05TalkChicken:
+ _nextChickenSequenceId = 0x144;
+ gnap._actionStatus = -1;
+ break;
+ case kAS05GrabChicken:
+ _nextChickenSequenceId = 0x14B;
+ break;
+ case kAS05GrabLadder:
+ while (gameSys.isSequenceActive(0x149, 39) && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+ gameSys.insertSequence(0x14E, gnap._id + 1, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.insertSequence(0x14D, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x14D;
+ gnap._sequenceDatNum = 0;
+ _vm->_timers[2] = 200;
+ _vm->_timers[6] = 300;
+ gnap._actionStatus = -1;
+ break;
+ case kAS05EnterBarn:
+ gameSys.insertSequence(0x107B1, 1,
+ makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id,
+ kSeqSyncWait, 0, 75 * gnap._pos.x - gnap._gridX, 48 * gnap._pos.y - gnap._gridY);
+ gameSys.setAnimation(0x107B1, 1, 0);
+ gnap._actionStatus = kAS05LeaveScene;
+ break;
+ case kAS05UseTwigWithChicken:
+ gnap.playShowItem(5, 0, 0);
+ _nextChickenSequenceId = 0x14F;
+ gnap._actionStatus = -1;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(1) == 2) {
+ PlayerPlat& plat = *_vm->_plat;
+ if (plat._sequenceId == 0x146) {
+ plat._pos = Common::Point(4, 8);
+ gameSys.insertSequence(0x107C1, 160, 0x146, 256, kSeqSyncWait, 0, 300 - plat._gridX, 384 - plat._gridY);
+ plat._sequenceId = 0x7C1;
+ plat._sequenceDatNum = 1;
+ plat._id = 20 * plat._pos.y;
+ _vm->invAdd(kItemNeedle);
+ _vm->setFlag(kGFNeedleTaken);
+ _vm->setGrabCursorSprite(kItemNeedle);
+ _vm->showCursor();
+ _vm->_timers[1] = 30;
+ plat._actionStatus = -1;
+ }
+ if (plat._actionStatus == kAS05PlatSearchHaystack) {
+ gameSys.setAnimation(0, 0, 1);
+ gameSys.insertSequence(0x145, plat._id, plat._sequenceId | (plat._sequenceDatNum << 16), plat._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x146, 256, 0x145, plat._id, kSeqSyncWait, 0, 0, 0);
+ _vm->hideCursor();
+ _vm->setGrabCursorSprite(-1);
+ plat._sequenceId = 0x146;
+ plat._sequenceDatNum = 0;
+ gameSys.setAnimation(0x146, 256, 1);
+ _vm->_timers[1] = 300;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2) {
+ if (_nextChickenSequenceId == 0x14B) {
+ gameSys.setAnimation(_nextChickenSequenceId, 100, 3);
+ gameSys.insertSequence(_nextChickenSequenceId, 100, _currChickenSequenceId, 100, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x14C, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceDatNum = 0;
+ gnap._sequenceId = 0x14C;
+ _currChickenSequenceId = _nextChickenSequenceId;
+ _nextChickenSequenceId = -1;
+ gnap._actionStatus = -1;
+ } else if (_nextChickenSequenceId != -1) {
+ gameSys.setAnimation(_nextChickenSequenceId, 100, 3);
+ gameSys.insertSequence(_nextChickenSequenceId, 100, _currChickenSequenceId, 100, kSeqSyncWait, 0, 0, 0);
+ _currChickenSequenceId = _nextChickenSequenceId;
+ _nextChickenSequenceId = -1;
+ }
+ }
+}
+
+/*****************************************************************************/
+
+Scene06::Scene06(GnapEngine *vm) : Scene(vm) {
+ _horseTurnedBack = false;
+ _nextPlatSequenceId = -1;
+ _nextHorseSequenceId = -1;
+ _currHorseSequenceId = -1;
+}
+
+int Scene06::init() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ gameSys.setAnimation(0, 0, 0);
+ gameSys.setAnimation(0, 0, 1);
+ gameSys.setAnimation(0, 0, 2);
+ if (_vm->isFlag(kGFSceneFlag1)) {
+ _vm->playSound(0x11B, false);
+ _vm->clearFlag(kGFSceneFlag1);
+ }
+ return 0x101;
+}
+
+void Scene06::updateHotspots() {
+ _vm->setHotspot(kHS06Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS06Gas, 300, 120, 440, 232, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 4, 7);
+ _vm->setHotspot(kHS06Ladder, 497, 222, 614, 492, SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 6, 8);
+ _vm->setHotspot(kHS06Horse, 90, 226, 259, 376, SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 4, 7);
+ _vm->setHotspot(kHS06ExitOutsideBarn, 226, 580, 688, 600, SF_EXIT_D_CURSOR | SF_WALKABLE, 5, 10);
+ _vm->setHotspot(kHS06WalkArea1, 0, 0, 200, 515);
+ _vm->setHotspot(kHS06WalkArea2, 200, 0, 285, 499);
+ _vm->setHotspot(kHS06WalkArea3, 688, 0, 800, 499);
+ _vm->setHotspot(kHS06WalkArea4, 475, 469, 800, 505);
+ _vm->setHotspot(kHS06WalkArea5, 0, 0, 800, 504);
+ _vm->setDeviceHotspot(kHS06Device, -1, -1, -1, -1);
+ if (_vm->isFlag(kGFGasTaken))
+ _vm->_hotspots[kHS06Ladder]._flags = SF_DISABLED;
+ if (_vm->_cursorValue == 4) {
+ _vm->_hotspots[kHS06Ladder]._flags = SF_DISABLED;
+ _vm->_hotspots[kHS06Gas]._flags = SF_DISABLED;
+ }
+ _vm->_hotspotsCount = 11;
+}
+
+void Scene06::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ bool triedDeviceOnGas = false;
+
+ _vm->startSoundTimerC(7);
+
+ _horseTurnedBack = false;
+ gameSys.insertSequence(0xF1, 120, 0, 0, kSeqNone, 0, 0, 0);
+
+ _currHorseSequenceId = 0xF1;
+ _nextHorseSequenceId = -1;
+
+ gameSys.setAnimation(0xF1, 120, 2);
+ _vm->_timers[4] = _vm->getRandom(40) + 25;
+
+ if (_vm->isFlag(kGFUnk04))
+ gameSys.insertSequence(0xF7, 20, 0, 0, kSeqNone, 0, 0, 0);
+ else
+ gameSys.insertSequence(0xF8, 20, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (!_vm->isFlag(kGFGasTaken) && _vm->_cursorValue != 4)
+ gameSys.insertSequence(0xFE, 20, 0, 0, kSeqNone, 0, 0, 0);
+
+ _vm->queueInsertDeviceIcon();
+
+ gnap.initPos(5, 12, kDirBottomRight);
+ plat.initPos(6, 12, kDirIdleLeft);
+ _vm->endSceneInit();
+
+ plat.walkTo(Common::Point(6, 8), -1, 0x107C2, 1);
+ gnap.walkTo(Common::Point(5, 8), -1, 0x107B9, 1);
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->testWalk(0, 5, -1, -1, -1, -1);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS06Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS06Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemDisguise) {
+ gnap.useDisguiseOnPlatypus();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ if (_vm->isFlag(kGFKeysTaken))
+ gnap.playMoan1(plat._pos);
+ else
+ gnap.playScratchingHead(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS06Gas:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot], 5, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(5, 0));
+ break;
+ case GRAB_CURSOR:
+ if (_vm->isFlag(kGFUnk04)) {
+ gnap.playImpossible();
+ } else if (triedDeviceOnGas) {
+ _vm->_hotspots[kHS06WalkArea5]._flags |= SF_WALKABLE;
+ gnap.walkTo(_vm->_hotspotsWalkPos[1], 0, 0x107BC, 1);
+ _vm->_hotspots[kHS06WalkArea5]._flags &= ~SF_WALKABLE;
+ gnap._actionStatus = kAS06TryToGetGas;
+ } else {
+ triedDeviceOnGas = true;
+ gnap.playPullOutDeviceNonWorking(_vm->_hotspotsWalkPos[1]);
+ }
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ if (_vm->isFlag(kGFUnk04))
+ gnap.playImpossible();
+ else
+ gnap.playScratchingHead(Common::Point(5, 0));
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS06Ladder:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot], 8, 4);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(8, 4));
+ break;
+ case GRAB_CURSOR:
+ if (_vm->isFlag(kGFGasTaken))
+ gnap.playImpossible();
+ else {
+ gnap.walkTo(_vm->_hotspotsWalkPos[2], 0, 0x107BB, 1);
+ gnap._actionStatus = kAS06TryToClimbLadder;
+ _vm->setFlag(kGFGasTaken);
+ }
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS06Horse:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemTwig && _horseTurnedBack) {
+ _vm->_hotspots[kHS06WalkArea5]._flags |= SF_WALKABLE;
+ gnap.walkTo(_vm->_hotspotsWalkPos[3], 0, 0x107BC, 1);
+ _vm->_hotspots[kHS06WalkArea5]._flags &= ~SF_WALKABLE;
+ gnap._idleFacing = kDirUpLeft;
+ plat.walkTo(Common::Point(6, 8), 1, 0x107C2, 1);
+ plat._idleFacing = kDirIdleLeft;
+ gnap._actionStatus = kAS06UseTwigOnHorse;
+ _vm->setGrabCursorSprite(-1);
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot], 3, 2);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(3, 2));
+ break;
+ case TALK_CURSOR:
+ if (_horseTurnedBack) {
+ gnap.walkTo(_vm->_hotspotsWalkPos[3], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(3, 2)) | 0x10000, 1);
+ } else {
+ gnap._idleFacing = kDirBottomLeft;
+ _vm->_hotspots[kHS06WalkArea5]._flags |= SF_WALKABLE;
+ gnap.walkTo(_vm->_hotspotsWalkPos[3], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ _vm->_hotspots[kHS06WalkArea5]._flags &= ~SF_WALKABLE;
+ gnap._actionStatus = kAS06TalkToHorse;
+ }
+ break;
+ case GRAB_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS06ExitOutsideBarn:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(_vm->_hotspotsWalkPos[4], 0, 0x107AE, 1);
+ gnap._actionStatus = kAS06LeaveScene;
+ if (_vm->_cursorValue == 1)
+ _vm->_newSceneNum = 5;
+ else
+ _vm->_newSceneNum = 35;
+ }
+ break;
+
+ case kHS06WalkArea1:
+ case kHS06WalkArea2:
+ case kHS06WalkArea3:
+ case kHS06WalkArea4:
+ case kHS06WalkArea5:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left && gnap._actionStatus < 0) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+
+ }
+
+ updateAnimations();
+
+ if (!_vm->_isLeavingScene) {
+ if (plat._actionStatus < 0)
+ plat.updateIdleSequence();
+ if (gnap._actionStatus < 0)
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[4]) {
+ _vm->_timers[4] = _vm->getRandom(40) + 25;
+ if (gnap._actionStatus < 0 && plat._actionStatus < 0 && _nextHorseSequenceId == -1) {
+ if (_horseTurnedBack) {
+ _nextHorseSequenceId = 0xF5;
+ } else {
+ switch (_vm->getRandom(5)) {
+ case 0:
+ case 1:
+ case 2:
+ _nextHorseSequenceId = 0xF1;
+ break;
+ case 3:
+ _nextHorseSequenceId = 0xF3;
+ break;
+ case 4:
+ _nextHorseSequenceId = 0xF4;
+ break;
+ }
+ }
+ }
+ }
+ _vm->playSoundC();
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene06::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS06LeaveScene:
+ _vm->_sceneDone = true;
+ gnap._actionStatus = -1;
+ break;
+ case kAS06TryToGetGas:
+ gameSys.insertSequence(0xFC, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0xFC;
+ gnap._sequenceDatNum = 0;
+ gnap._actionStatus = -1;
+ break;
+ case kAS06TryToClimbLadder:
+ gameSys.insertSequence(0xFF, 20, 0xFE, 20, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(0xFD, gnap._id, 0);
+ gameSys.insertSequence(0xFD, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0xFD;
+ gnap._sequenceDatNum = 0;
+ gnap._actionStatus = kAS06TryToClimbLadderDone;
+ break;
+ case kAS06TryToClimbLadderDone:
+ gnap._pos = Common::Point(6, 7);
+ gnap._actionStatus = -1;
+ break;
+ case kAS06TalkToHorse:
+ _nextHorseSequenceId = 0xF6;
+ break;
+ case kAS06UseTwigOnHorse:
+ _nextPlatSequenceId = 0xFB;
+ break;
+ default:
+ gnap._actionStatus = -1;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(1) == 2) {
+ gameSys.setAnimation(0, 0, 1);
+ if (plat._sequenceId == 0xFA) {
+ gameSys.setAnimation(0, 0, 1);
+ _vm->invAdd(kItemGas);
+ _vm->setFlag(kGFGasTaken);
+ _vm->_hotspots[kHS06Ladder]._flags = SF_DISABLED;
+ _vm->setGrabCursorSprite(kItemGas);
+ plat._actionStatus = -1;
+ plat._pos = Common::Point(6, 8);
+ gameSys.insertSequence(0x107C1, plat._id, 0, 0, kSeqNone, 0, 450 - plat._gridX, 384 - plat._gridY);
+ plat._sequenceId = 0x7C1;
+ plat._sequenceDatNum = 1;
+ _vm->setFlag(kGFUnk04);
+ gnap._actionStatus = -1;
+ _vm->showCursor();
+ }
+ if (_nextPlatSequenceId == 0xFB) {
+ gameSys.setAnimation(0, 0, 1);
+ _nextHorseSequenceId = 0xF2;
+ plat._actionStatus = 6;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(2) == 2 && _nextHorseSequenceId != -1) {
+ switch (_nextHorseSequenceId) {
+ case 0xF2:
+ _vm->setGrabCursorSprite(-1);
+ _vm->hideCursor();
+ gameSys.setAnimation(0xFA, 256, 1);
+ gameSys.insertSequence(0xF2, 120, _currHorseSequenceId, 120, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x100, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0xF7, 20, 0xF8, 20, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0xFB, plat._id, plat._sequenceId | (plat._sequenceDatNum << 16), plat._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0xFA, 256, 0xFB, plat._id, kSeqSyncWait, 0, 0, 0);
+ plat._sequenceId = 0xFA;
+ plat._sequenceDatNum = 0;
+ gameSys.insertSequence(0x107B7, gnap._id, 0x100, gnap._id,
+ kSeqSyncWait, 0, 75 * gnap._pos.x - gnap._gridX, 48 * gnap._pos.y - gnap._gridY);
+ gnap._sequenceId = 0x7B7;
+ gnap._sequenceDatNum = 1;
+ _currHorseSequenceId = _nextHorseSequenceId;
+ _nextHorseSequenceId = -1;
+ _nextPlatSequenceId = -1;
+ _vm->invRemove(kItemTwig);
+ break;
+ case 0xF6:
+ gameSys.setAnimation(_nextHorseSequenceId, 120, 2);
+ gameSys.insertSequence(0xF6, 120, _currHorseSequenceId, 120, kSeqSyncWait, 0, 0, 0);
+ _horseTurnedBack = true;
+ _currHorseSequenceId = _nextHorseSequenceId;
+ _nextHorseSequenceId = -1;
+ gnap._actionStatus = -1;
+ break;
+ default:
+ gameSys.setAnimation(_nextHorseSequenceId, 120, 2);
+ gameSys.insertSequence(_nextHorseSequenceId, 120, _currHorseSequenceId, 120, kSeqSyncWait, 0, 0, 0);
+ _currHorseSequenceId = _nextHorseSequenceId;
+ _nextHorseSequenceId = -1;
+ break;
+ }
+ }
+}
+
+/*****************************************************************************/
+
+Scene07::Scene07(GnapEngine *vm) : Scene(vm) {
+}
+
+int Scene07::init() {
+ return 0x92;
+}
+
+void Scene07::updateHotspots() {
+ _vm->setHotspot(kHS07Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS07ExitHouse, 700, 125, 799, 290, SF_EXIT_NE_CURSOR);
+ _vm->setHotspot(kHS07Dice, 200, 290, 270, 360, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS07WalkArea1, 0, 0, 325, 445);
+ _vm->setHotspot(kHS07WalkArea2, 325, 0, 799, 445, _vm->_isLeavingScene ? SF_WALKABLE : SF_NONE);
+ _vm->setHotspot(kHS07WalkArea3, 160, 0, 325, 495);
+ _vm->setDeviceHotspot(kHS07Device, -1, -1, -1, -1);
+ if (_vm->isFlag(kGFPlatypus))
+ _vm->_hotspots[kHS07Dice]._flags = SF_DISABLED;
+ _vm->_hotspotsCount = 7;
+}
+
+void Scene07::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->queueInsertDeviceIcon();
+ gameSys.insertSequence(0x8C, 1, 0, 0, kSeqLoop, 0, 0, 0);
+ gameSys.insertSequence(0x90, 1, 0, 0, kSeqLoop, 0, 0, 0);
+
+ _vm->invRemove(kItemGas);
+ _vm->invRemove(kItemNeedle);
+
+ if (!_vm->isFlag(kGFPlatypus))
+ gameSys.insertSequence(0x8D, 1, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (_vm->_prevSceneNum == 8) {
+ gnap.initPos(7, 7, kDirBottomLeft);
+ plat.initPos(9, 7, kDirIdleRight);
+ _vm->endSceneInit();
+ } else {
+ gnap._pos = Common::Point(6, 7);
+ gnap._id = 140;
+ gnap._sequenceId = 0x8F;
+ gnap._sequenceDatNum = 0;
+ gnap._idleFacing = kDirBottomRight;
+ gameSys.insertSequence(0x8F, 140, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.setAnimation(makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, 0);
+ gnap._actionStatus = kAS07Wait;
+ plat._pos = Common::Point(3, 8);
+ plat._id = 160;
+ plat._sequenceId = 0x91;
+ plat._sequenceDatNum = 0;
+ plat._idleFacing = kDirIdleLeft;
+ gameSys.insertSequence(0x91, 160, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->endSceneInit();
+ }
+
+ _vm->_timers[3] = 600;
+ _vm->_timers[4] = _vm->getRandom(40) + 50;
+
+ while (!_vm->_sceneDone) {
+ if (!_vm->isSoundPlaying(0x10919))
+ _vm->playSound(0x10919, true);
+
+ if (_vm->testWalk(0, 1, 8, 7, 6, 7))
+ updateHotspots();
+
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS07Platypus:
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ break;
+ }
+ break;
+
+ case kHS07ExitHouse:
+ _vm->_isLeavingScene = true;
+ if (gnap._pos.x > 8)
+ gnap.walkTo(Common::Point(gnap._pos.x, 7), 0, 0x107AD, 1);
+ else
+ gnap.walkTo(Common::Point(8, 7), 0, 0x107AD, 1);
+ gnap._actionStatus = kAS07LeaveScene;
+ break;
+
+ case kHS07Dice:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(4, 8), 3, 3);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ break;
+ case GRAB_CURSOR:
+ _vm->setFlag(kGFPlatypus);
+ _vm->invAdd(kItemDice);
+ updateHotspots();
+ gnap.playPullOutDevice(Common::Point(3, 3));
+ gameSys.setAnimation(0x8E, 1, 2);
+ gameSys.insertSequence(0x8E, 1, 141, 1, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(gnap.getSequenceId(kGSUseDevice, Common::Point(0, 0)) | 0x10000, gnap._id,
+ makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id,
+ kSeqSyncWait, 0, 75 * gnap._pos.x - gnap._gridX, 48 * gnap._pos.y - gnap._gridY);
+ gnap._sequenceId = gnap.getSequenceId(kGSUseDevice, Common::Point(0, 0));
+ gnap._sequenceDatNum = 1;
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ break;
+
+ case kHS07Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[4] = _vm->getRandom(40) + 50;
+ }
+ break;
+
+ case kHS07WalkArea1:
+ case kHS07WalkArea2:
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ case kHS07WalkArea3:
+ // Nothing
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+ }
+
+ updateAnimations();
+
+ if (!_vm->_isLeavingScene) {
+ gnap.updateIdleSequence();
+ if (plat._actionStatus < 0 && gnap._actionStatus < 0) {
+ if (_vm->_timers[0]) {
+ if (!_vm->_timers[1]) {
+ _vm->_timers[1] = _vm->getRandom(20) + 30;
+ int gnapRandomValue = _vm->getRandom(20);
+ if (plat._idleFacing != kDirIdleLeft) {
+ if (gnapRandomValue == 0 && plat._sequenceId == 0x7CA)
+ plat.playSequence(0x107CC);
+ else if (gnapRandomValue == 1 && plat._sequenceId == 0x7CA)
+ plat.playSequence(0x10845);
+ else if (plat._pos.y == 9)
+ plat.playSequence(0x107CA);
+ } else if (gnapRandomValue == 0 && plat._sequenceId == 0x7C9)
+ plat.playSequence(0x107CB);
+ else if (gnapRandomValue == 1 && plat._sequenceId == 0x7C9)
+ plat.playSequence(0x10844);
+ else if (plat._pos.y == 9)
+ plat.playSequence(0x107C9);
+ gameSys.setAnimation(plat._sequenceId | (plat._sequenceDatNum << 16), plat._id, 1);
+ }
+ } else {
+ _vm->_timers[0] = _vm->getRandom(75) + 75;
+ plat.makeRoom();
+ }
+ } else {
+ _vm->_timers[0] = 100;
+ _vm->_timers[1] = 35;
+ }
+ playRandomSound(4);
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[4] = _vm->getRandom(40) + 50;
+ }
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene07::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS07LeaveScene:
+ _vm->_newSceneNum = 8;
+ _vm->_sceneDone = true;
+ break;
+ }
+ gnap._actionStatus = -1;
+ }
+
+ if (gameSys.getAnimationStatus(2) == 2) {
+ gameSys.setAnimation(0, 0, 2);
+ _vm->setGrabCursorSprite(kItemDice);
+ }
+}
+
+/*****************************************************************************/
+
+Scene08::Scene08(GnapEngine *vm) : Scene(vm) {
+ _nextDogSequenceId = -1;
+ _currDogSequenceId = -1;
+ _nextManSequenceId = -1;
+ _currManSequenceId = -1;
+}
+
+int Scene08::init() {
+ return 0x150;
+}
+
+void Scene08::updateHotspots() {
+ _vm->setHotspot(kH08SPlatypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS08ExitBackdoor, 0, 280, 10, 400, SF_EXIT_L_CURSOR | SF_WALKABLE);
+ _vm->setHotspot(kHS08ExitCrash, 200, 590, 400, 599, SF_EXIT_D_CURSOR | SF_WALKABLE);
+ _vm->setHotspot(kHS08Man, 510, 150, 610, 380, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS08Door, 350, 170, 500, 410, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS08Meat, 405, 450, 480, 485, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS08Bone, 200, 405, 270, 465, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS08Toy, 540, 430, 615, 465, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS08WalkArea1, 290, 340, -1, -1);
+ _vm->setHotspot(kHS08WalkArea2, 0, 0, 799, 420);
+ _vm->setDeviceHotspot(kHS08Device, -1, -1, -1, -1);
+ if (_vm->isFlag(kGFBarnPadlockOpen))
+ _vm->_hotspots[kHS08Meat]._flags = SF_WALKABLE | SF_DISABLED;
+ if (_vm->isFlag(kGFTruckFilledWithGas))
+ _vm->_hotspots[kHS08Bone]._flags = SF_WALKABLE | SF_DISABLED;
+ if (_vm->isFlag(kGFTruckKeysUsed))
+ _vm->_hotspots[kHS08Toy]._flags = SF_WALKABLE | SF_DISABLED;
+ _vm->_hotspotsCount = 11;
+}
+
+void Scene08::updateAnimationsCb() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ if (gameSys.getAnimationStatus(3) == 2) {
+ gameSys.setAnimation(_nextDogSequenceId, 100, 3);
+ gameSys.insertSequence(_nextDogSequenceId, 100, _currDogSequenceId, 100, kSeqSyncWait, 0, 0, 0);
+ _currDogSequenceId = _nextDogSequenceId;
+ if ( _nextDogSequenceId != 0x135 )
+ _nextDogSequenceId = 0x134;
+ }
+}
+
+void Scene08::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->queueInsertDeviceIcon();
+
+ gameSys.insertSequence(0x14F, 1, 0, 0, kSeqLoop, 0, 0, 0);
+ gameSys.insertSequence(0x14E, 256, 0, 0, kSeqNone, 0, 0, 0);
+
+ _currDogSequenceId = 0x135;
+ _nextDogSequenceId = 0x135;
+
+ gameSys.setAnimation(0x135, 100, 3);
+ gameSys.insertSequence(_currDogSequenceId, 100, 0, 0, kSeqNone, 0, 0, 0);
+
+ _currManSequenceId = 0x140;
+ _nextManSequenceId = -1;
+
+ gameSys.setAnimation(0x140, 100, 2);
+ gameSys.insertSequence(_currManSequenceId, 100, 0, 0, kSeqNone, 0, 0, 0);
+
+ _vm->_timers[4] = _vm->getRandom(50) + 75;
+
+ if (!_vm->isFlag(kGFBarnPadlockOpen))
+ gameSys.insertSequence(0x144, 1, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (!_vm->isFlag(kGFTruckFilledWithGas))
+ gameSys.insertSequence(0x145, 1, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (!_vm->isFlag(kGFTruckKeysUsed))
+ gameSys.insertSequence(0x146, 1, 0, 0, kSeqNone, 0, 0, 0);
+
+ gnap.initPos(-1, 8, kDirBottomRight);
+ plat.initPos(-1, 7, kDirIdleLeft);
+
+ _vm->endSceneInit();
+
+ gnap.walkTo(Common::Point(1, 8), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(1, 7), -1, 0x107C2, 1);
+
+ _vm->_timers[5] = _vm->getRandom(40) + 50;
+
+ while (!_vm->_sceneDone) {
+ if (!_vm->isSoundPlaying(0x10919))
+ _vm->playSound(0x10919, true);
+
+ _vm->testWalk(0, 0, -1, -1, -1, -1);
+
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS08Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[4] = _vm->getRandom(50) + 75;
+ _vm->_timers[5] = _vm->getRandom(40) + 50;
+ }
+ break;
+
+ case kH08SPlatypus:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ if (_vm->isFlag(kGFSceneFlag1))
+ gnap.playMoan1(plat._pos);
+ else
+ gnap.playScratchingHead(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.actionIdle(0x14D);
+ gnap.kissPlatypus(8);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ break;
+ }
+ }
+ break;
+
+ case kHS08ExitBackdoor:
+ _vm->_isLeavingScene = true;
+ gnap.actionIdle(0x14D);
+ gnap.walkTo(Common::Point(0, 6), 0, 0x107AF, 1);
+ gnap._actionStatus = kAS08LeaveScene;
+ plat.walkTo(Common::Point(0, 7), 1, 0x107CF, 1);
+ _vm->_newSceneNum = 9;
+ break;
+
+ case kHS08ExitCrash:
+ _vm->_isLeavingScene = true;
+ gnap.actionIdle(0x14D);
+ gnap.walkTo(Common::Point(3, 9), 0, 0x107AE, 1);
+ gnap._actionStatus = kAS08LeaveScene;
+ plat.walkTo(Common::Point(4, 9), 1, 0x107C1, 1);
+ _vm->_newSceneNum = 7;
+ break;
+
+ case kHS08Man:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(6, 6), 7, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.actionIdle(0x14D);
+ gnap.walkTo(Common::Point(6, 6), 0, 0x107BB, 1);
+ gnap._actionStatus = kAS08LookMan;
+ gnap._idleFacing = kDirUpRight;
+ break;
+ case GRAB_CURSOR:
+ gnap.playImpossible();
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpLeft;
+ gnap.actionIdle(0x14D);
+ gnap.walkTo(Common::Point(8, 6), 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS08TalkMan;
+ break;
+ case PLAT_CURSOR:
+ gnap.actionIdle(0x14D);
+ gnap.useDeviceOnPlatypus();
+ plat.walkTo(Common::Point(6, 6), 1, 0x107C2, 1);
+ plat._actionStatus = kAS08PlatWithMan;
+ plat._idleFacing = kDirIdleLeft;
+ gnap.playIdle(Common::Point(6, 6));
+ break;
+ }
+ }
+ break;
+
+ case kHS08Door:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(4, 7), 5, 0);
+ gameSys.setAnimation(makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, 0);
+ gnap._actionStatus = kAS08GrabDog;
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(6, 0));
+ gameSys.setAnimation(makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, 0);
+ gnap._actionStatus = kAS08LookDog;
+ break;
+ case GRAB_CURSOR:
+ gnap.walkTo(Common::Point(4, 7), 0, 0x107BB, 1);
+ gnap._actionStatus = kAS08GrabDog;
+ gnap._idleFacing = kDirUpRight;
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.actionIdle(0x14D);
+ gnap.walkTo(Common::Point(4, 7), 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS08TalkDog;
+ break;
+ case PLAT_CURSOR:
+ _vm->setFlag(kGFSceneFlag1);
+ gnap.actionIdle(0x14D);
+ gnap.useDeviceOnPlatypus();
+ plat.walkTo(Common::Point(3, 7), 1, 0x107C2, 1);
+ plat._actionStatus = kAS08PlatWithDog;
+ plat._idleFacing = kDirIdleLeft;
+ gnap.playIdle(Common::Point(3, 7));
+ break;
+ }
+ }
+ break;
+
+ case kHS08Meat:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(6, 8), 5, 6);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(6, 7));
+ break;
+ case GRAB_CURSOR:
+ if (_currDogSequenceId == 0x135) {
+ gnap.playScratchingHead(Common::Point(6, 7));
+ } else {
+ gnap.actionIdle(0x14D);
+ gnap.playPullOutDevice(Common::Point(6, 7));
+ gnap.playUseDevice();
+ _nextDogSequenceId = 0x149;
+ }
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ break;
+
+ case kHS08Bone:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(2, 7), 3, 6);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(3, 6));
+ break;
+ case GRAB_CURSOR:
+ if (_currDogSequenceId == 0x135) {
+ gnap.playScratchingHead(Common::Point(3, 6));
+ } else {
+ gnap.actionIdle(0x14D);
+ gnap.playPullOutDevice(Common::Point(3, 6));
+ gnap.playUseDevice();
+ _nextDogSequenceId = 0x14A;
+ }
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ break;
+
+ case kHS08Toy:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(8, 7), 7, 6);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(7, 6));
+ break;
+ case GRAB_CURSOR:
+ if (_currDogSequenceId == 0x135) {
+ gnap.playScratchingHead(Common::Point(7, 6));
+ } else {
+ gnap.actionIdle(0x14D);
+ gnap.playPullOutDevice(Common::Point(7, 6));
+ gnap.playUseDevice();
+ _nextDogSequenceId = 0x14B;
+ }
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ break;
+
+ case kHS08WalkArea1:
+ case kHS08WalkArea2:
+ gnap.actionIdle(0x14D);
+ gnap.walkTo(Common::Point(-1, 6), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left) {
+ gnap.actionIdle(0x14D);
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+ }
+
+ updateAnimations();
+
+ if (!_vm->_isLeavingScene) {
+ plat.updateIdleSequence();
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[4]) {
+ _vm->_timers[4] = _vm->getRandom(50) + 125;
+ if (gnap._actionStatus < 0 && plat._actionStatus < 0 && _nextManSequenceId == -1 &&
+ (_currDogSequenceId == 0x134 || _currDogSequenceId == 0x135)) {
+ int _gnapRandomValue = _vm->getRandom(4);
+ switch (_gnapRandomValue) {
+ case 0:
+ _nextManSequenceId = 0x138;
+ break;
+ case 1:
+ _nextManSequenceId = 0x136;
+ break;
+ case 2:
+ _nextManSequenceId = 0x13B;
+ break;
+ case 3:
+ _nextManSequenceId = 0x13A;
+ break;
+ }
+ }
+ }
+ playRandomSound(5);
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[4] = _vm->getRandom(50) + 75;
+ _vm->_timers[5] = _vm->getRandom(40) + 50;
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene08::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS08LeaveScene:
+ _vm->_sceneDone = true;
+ gnap._actionStatus = -1;
+ break;
+ case kAS08TalkMan:
+ _nextManSequenceId = 0x13F;
+ gnap._actionStatus = -1;
+ break;
+ case kAS08LookMan:
+ _nextManSequenceId = 0x140;
+ gnap._actionStatus = -1;
+ break;
+ case kAS08LookDog:
+ _nextManSequenceId = 0x137;
+ gnap._actionStatus = -1;
+ break;
+ case kAS08GrabDog:
+ if (_currDogSequenceId == 0x135)
+ _nextDogSequenceId = 0x133;
+ else
+ _nextDogSequenceId = 0x13C;
+ gnap._actionStatus = -1;
+ break;
+ case kAS08TalkDog:
+ if (_currDogSequenceId == 0x135)
+ _nextDogSequenceId = 0x133;
+ else
+ _nextDogSequenceId = 0x13C;
+ gnap._actionStatus = -1;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(1) == 2) {
+ gameSys.setAnimation(0, 0, 1);
+ switch (plat._actionStatus) {
+ case kAS08PlatWithDog:
+ _nextDogSequenceId = 0x147;
+ break;
+ case kAS08PlatWithMan:
+ _nextManSequenceId = 0x140;
+ plat._actionStatus = -1;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(2) == 2 && _nextManSequenceId != -1) {
+ gameSys.setAnimation(_nextManSequenceId, 100, 2);
+ gameSys.insertSequence(_nextManSequenceId, 100, _currManSequenceId, 100, kSeqSyncWait, 0, 0, 0);
+ _currManSequenceId = _nextManSequenceId;
+ _nextManSequenceId = -1;
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2) {
+ if (_currDogSequenceId == 0x147)
+ plat._actionStatus = -1;
+ if (_currDogSequenceId == 0x149 || _currDogSequenceId == 0x14A || _currDogSequenceId == 0x14B) {
+ if (_vm->getRandom(2) != 0)
+ _nextManSequenceId = 0x13D;
+ else
+ _nextManSequenceId = 0x13E;
+ } else if (_currDogSequenceId == 0x133)
+ _nextManSequenceId = 0x139;
+ if (_nextDogSequenceId == 0x149 || _nextDogSequenceId == 0x14A || _nextDogSequenceId == 0x14B) {
+ gameSys.setAnimation(_nextDogSequenceId, 100, 3);
+ gameSys.insertSequence(_nextDogSequenceId, 100, _currDogSequenceId, 100, kSeqSyncWait, 0, 0, 0);
+ switch (_nextDogSequenceId) {
+ case 0x149:
+ _vm->setFlag(kGFBarnPadlockOpen);
+ _vm->_hotspots[kHS08Meat]._flags = SF_DISABLED | SF_WALKABLE;
+ gameSys.removeSequence(0x144, 1, true);
+ break;
+ case 0x14A:
+ _vm->setFlag(kGFTruckFilledWithGas);
+ _vm->_hotspots[kHS08Bone]._flags = SF_DISABLED | SF_WALKABLE;
+ gameSys.removeSequence(0x145, 1, true);
+ break;
+ case 0x14B:
+ _vm->setFlag(kGFTruckKeysUsed);
+ _vm->_hotspots[kHS08Toy]._flags = SF_DISABLED | SF_WALKABLE;
+ gameSys.removeSequence(0x146, 1, true);
+ break;
+ }
+ _currDogSequenceId = _nextDogSequenceId;
+ _nextDogSequenceId = 0x134;
+ } else if (_nextDogSequenceId == 0x147) {
+ gameSys.setAnimation(_nextDogSequenceId, 100, 3);
+ gameSys.insertSequence(_nextDogSequenceId, 100, _currDogSequenceId, 100, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x148, 160, plat._sequenceId | (plat._sequenceDatNum << 16), plat._id, kSeqSyncWait, 0, 0, 0);
+ _currDogSequenceId = _nextDogSequenceId;
+ _nextDogSequenceId = 0x134;
+ plat._pos = Common::Point(1, 8);
+ plat._id = 160;
+ plat._sequenceId = 0x148;
+ plat._idleFacing = kDirIdleRight;
+ plat._sequenceDatNum = 0;
+ if (gnap._pos == Common::Point(1, 8))
+ gnap.walkStep();
+ } else if (_nextDogSequenceId != -1) {
+ gameSys.setAnimation(_nextDogSequenceId, 100, 3);
+ gameSys.insertSequence(_nextDogSequenceId, 100, _currDogSequenceId, 100, kSeqSyncWait, 0, 0, 0);
+ _currDogSequenceId = _nextDogSequenceId;
+ if (_nextDogSequenceId != 0x135)
+ _nextDogSequenceId = 0x134;
+ if (_currDogSequenceId == 0x133) {
+ _vm->_timers[2] = _vm->getRandom(30) + 20;
+ _vm->_timers[3] = _vm->getRandom(50) + 200;
+ gameSys.insertSequence(0x14D, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x14D;
+ gnap._idleFacing = kDirUpRight;
+ gnap._sequenceDatNum = 0;
+ gnap._actionStatus = -1;
+ }
+ }
+ }
+}
+
+/*****************************************************************************/
+
+Scene09::Scene09(GnapEngine *vm) : Scene(vm) {
+}
+
+int Scene09::init() {
+ return 0x4E;
+}
+
+void Scene09::updateHotspots() {
+ _vm->setHotspot(kHS09Platypus, 0, 200, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS09ExitKitchen, 280, 200, 380, 400, SF_EXIT_U_CURSOR);
+ _vm->setHotspot(kHS09ExitHouse, 790, 200, 799, 450, SF_EXIT_R_CURSOR | SF_WALKABLE);
+ _vm->setHotspot(kHS09Trash, 440, 310, 680, 420, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS09WalkArea1, 0, 0, 799, 400);
+ _vm->setHotspot(kHS09WalkArea2, 0, 0, 630, 450);
+ _vm->setHotspot(kHS09WalkArea2, 0, 0, 175, 495);
+ _vm->setDeviceHotspot(kHS09Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 8;
+}
+
+void Scene09::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->queueInsertDeviceIcon();
+
+ gameSys.insertSequence(0x4D, 1, 0, 0, kSeqLoop, 0, 0, 0);
+ gameSys.insertSequence(0x4B, 2, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (_vm->_prevSceneNum == 8) {
+ gnap.initPos(11, 8, kDirBottomLeft);
+ plat.initPos(12, 7, kDirIdleRight);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(9, 8), -1, 0x107BA, 1);
+ plat.walkTo(Common::Point(9, 7), -1, 0x107D2, 1);
+ } else {
+ gnap.initPos(4, 7, kDirBottomRight);
+ plat.initPos(5, 7, kDirIdleLeft);
+ _vm->endSceneInit();
+ }
+
+ _vm->_timers[4] = _vm->getRandom(150) + 50;
+ _vm->_timers[5] = _vm->getRandom(40) + 50;
+
+ while (!_vm->_sceneDone) {
+ if (!_vm->isSoundPlaying(0x10919))
+ _vm->playSound(0x10919, true);
+
+ _vm->testWalk(0, 0, -1, -1, -1, -1);
+
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS09Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[4] = _vm->getRandom(150) + 50;
+ _vm->_timers[5] = _vm->getRandom(40) + 50;
+ }
+ break;
+
+ case kHS09Platypus:
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ break;
+ }
+ break;
+
+ case kHS09ExitKitchen:
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 10;
+ gnap.walkTo(Common::Point(4, 7), 0, 0x107BF, 1);
+ gnap._actionStatus = kAS09LeaveScene;
+ plat.walkTo(Common::Point(4, 8), -1, 0x107D2, 1);
+ plat._idleFacing = kDirIdleRight;
+ break;
+
+ case kHS09ExitHouse:
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 8;
+ gnap.walkTo(Common::Point(10, -1), 0, 0x107AB, 1);
+ gnap._actionStatus = kAS09LeaveScene;
+ plat.walkTo(Common::Point(10, -1), -1, 0x107CD, 1);
+ plat._idleFacing = kDirIdleRight;
+ break;
+
+ case kHS09Trash:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(9, 6), 8, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(8, 3));
+ break;
+ case GRAB_CURSOR:
+ gnap._actionStatus = kAS09SearchTrash;
+ gnap.walkTo(Common::Point(9, 6), 0, 0x107BC, 1);
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ break;
+
+ case kHS09WalkArea1:
+ case kHS09WalkArea2:
+ case kHS09WalkArea3:
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+ }
+
+ updateAnimations();
+
+ if (!_vm->_isLeavingScene && gnap._actionStatus != 1 && gnap._actionStatus != 2) {
+ plat.updateIdleSequence();
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[4]) {
+ _vm->_timers[4] = _vm->getRandom(150) + 100;
+ if (_vm->_timers[4] & 1)
+ gameSys.insertSequence(0x49, 1, 0, 0, kSeqNone, 0, 0, 0);
+ else
+ gameSys.insertSequence(0x4A, 1, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ playRandomSound(5);
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[4] = _vm->getRandom(150) + 50;
+ _vm->_timers[5] = _vm->getRandom(40) + 50;
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene09::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS09LeaveScene:
+ _vm->_sceneDone = true;
+ gnap._actionStatus = -1;
+ break;
+ case kAS09SearchTrash:
+ gameSys.setAnimation(0x4C, 120, 0);
+ gameSys.insertSequence(0x4C, 120, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.removeSequence(0x4B, 2, true);
+ gnap._sequenceId = 0x4C;
+ gnap._id = 120;
+ gnap._idleFacing = kDirUpLeft;
+ gnap._sequenceDatNum = 0;
+ gnap._pos = Common::Point(9, 6);
+ gnap._actionStatus = kAS09SearchTrashDone;
+ break;
+ case kAS09SearchTrashDone:
+ gameSys.insertSequence(0x4B, 2, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->_timers[2] = 360;
+ _vm->_timers[4] = _vm->getRandom(150) + 100;
+ gnap._actionStatus = -1;
+ break;
+ }
+ }
+}
+
+} // End of namespace Gnap
diff --git a/engines/gnap/scenes/group0.h b/engines/gnap/scenes/group0.h
new file mode 100644
index 0000000000..e06380926d
--- /dev/null
+++ b/engines/gnap/scenes/group0.h
@@ -0,0 +1,401 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can 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 GNAP_GROUP0_H
+#define GNAP_GROUP0_H
+
+#include "gnap/debugger.h"
+
+namespace Gnap {
+
+enum {
+ kHS01Platypus = 0,
+ kHS01ExitTruck = 1,
+ kHS01Mud = 2,
+ kHS01Pigs = 3,
+ kHS01Spaceship = 4,
+ kHS01Device = 5,
+ kHS01WalkArea1 = 6,
+ kHS01WalkArea2 = 7,
+ kHS01WalkArea3 = 8,
+ kHS01WalkArea4 = 9,
+ kHS01WalkArea5 = 10,
+ kHS01WalkArea6 = 11,
+ kHS01WalkArea7 = 12,
+ kHS01WalkArea8 = 13
+};
+
+enum {
+ kHS02Platypus = 0,
+ kHS02Chicken = 1,
+ kHS02Truck1 = 2,
+ kHS02Truck2 = 3,
+ kHS02TruckGrill = 4,
+ kHS02Device = 5,
+ kHS02ExitHouse = 6,
+ kHS02ExitBarn = 7,
+ kHS02ExitCreek = 8,
+ kHS02ExitPigpen = 9,
+ kHS02WalkArea1 = 10,
+ kHS02WalkArea2 = 11,
+ kHS02WalkArea3 = 12,
+ kHS02WalkArea4 = 13
+};
+
+enum {
+ kHS03Platypus = 0,
+ kHS03Grass = 1,
+ kHS03ExitTruck = 2,
+ kHS03Creek = 3,
+ kHS03TrappedPlatypus = 4,
+ kHS03Device = 5,
+ kHS03WalkAreas1 = 6,
+ kHS03WalkAreas2 = 7,
+ kHS03PlatypusWalkArea = 8,
+ kHS03WalkAreas3 = 9
+};
+
+enum {
+ kHS04Platypus = 0,
+ kHS04Twig = 1,
+ kHS04Dog = 2,
+ kHS04Axe = 3,
+ kHS04Door = 4,
+ kHS04ExitTruck = 5,
+ kHS04Device = 6,
+ kHS04Window = 7,
+ kHS04ExitBarn = 8,
+ kHS04WalkArea1 = 9,
+ kHS04WalkArea2 = 10
+};
+
+enum {
+ kHS05Platypus = 0,
+ kHS05Haystack = 1,
+ kHS05Padlock = 2,
+ kHS05Ladder = 3,
+ kHS05ExitHouse = 4,
+ kHS05Chicken = 5,
+ kHS05Device = 6,
+ kHS05WalkArea1 = 7,
+ kHS05WalkArea2 = 8,
+ kHS05WalkArea3 = 9
+};
+
+enum {
+ kHS06Platypus = 0,
+ kHS06Gas = 1,
+ kHS06Ladder = 2,
+ kHS06Horse = 3,
+ kHS06ExitOutsideBarn = 4,
+ kHS06Device = 5,
+ kHS06WalkArea1 = 6,
+ kHS06WalkArea2 = 7,
+ kHS06WalkArea3 = 8,
+ kHS06WalkArea4 = 9,
+ kHS06WalkArea5 = 10
+};
+
+enum {
+ kHS07Platypus = 0,
+ kHS07ExitHouse = 1,
+ kHS07Dice = 2,
+ kHS07Device = 3,
+ kHS07WalkArea1 = 4,
+ kHS07WalkArea2 = 5,
+ kHS07WalkArea3 = 6
+};
+
+enum {
+ kH08SPlatypus = 0,
+ kHS08ExitBackdoor = 1,
+ kHS08ExitCrash = 2,
+ kHS08Man = 3,
+ kHS08Door = 4,
+ kHS08Meat = 5,
+ kHS08Bone = 6,
+ kHS08Toy = 7,
+ kHS08WalkArea1 = 8,
+ kHS08Device = 9,
+ kHS08WalkArea2 = 10
+};
+
+enum {
+ kHS09Platypus = 0,
+ kHS09ExitKitchen = 1,
+ kHS09ExitHouse = 2,
+ kHS09Trash = 3,
+ kHS09Device = 4,
+ kHS09WalkArea1 = 5,
+ kHS09WalkArea2 = 6,
+ kHS09WalkArea3 = 7
+};
+
+enum {
+ kAS01LookSpaceship = 1,
+ kAS01LookSpaceshipDone = 2,
+ kAS01LeaveScene = 3,
+ kAS01TakeMud = 5,
+ kAS01LookPigs = 6,
+ kAS01UsePigs = 7
+};
+
+enum {
+ kAS02UseTruckNoKeys = 0,
+ kAS02UseGasWithTruck = 1,
+ kAS02UseTruckGas = 2,
+ kAS02UseTruckNoGas = 3,
+ kAS02GrabTruckGrill = 5,
+ kAS02LeaveScene = 6,
+ kAS02TalkChicken = 7,
+ kAS02GrabChicken = 8,
+ kAS02GrabChickenDone = 9,
+ kAS02UseTruckNoKeysDone = 11,
+ kAS02UseGasWithTruckDone = 12,
+ kAS02UseTwigWithChicken = 16
+};
+
+enum {
+ kAS03LeaveScene = 0,
+ kAS03FreePlatypus = 1,
+ kAS03HypnotizePlat = 2,
+ kAS03HypnotizeScaredPlat= 3,
+ kAS03FreePlatypusDone = 4,
+ kAS03GrabPlatypus = 5,
+ kAS03GrabCreek = 6,
+ kAS03GrabCreekDone = 7,
+ kAS03GrabScaredPlatypus = 8
+};
+
+enum {
+ kAS04OpenDoor = 1,
+ kAS04GetKeyFirst = 2,
+ kAS04GetKeyAnother = 3,
+ kAS04LeaveScene = 4,
+ kAS04GetKeyFirstDone = 6,
+ kAS04GetKeyFirst2 = 7,
+ kAS04GetKeyAnother2 = 8,
+ kAS04GetKeyAnotherDone = 9,
+ kAS04OpenDoorDone = 10,
+ kAS04GrabDog = 12,
+ kAS04GrabAxe = 13
+};
+
+enum {
+ kAS05PlatSearchHaystack = 0,
+ kAS05TryPickPadlock = 1,
+ kAS05PickPadlock = 2,
+ kAS05TalkChicken = 3,
+ kAS05GrabChicken = 4,
+ kAS05GrabLadder = 5,
+ kAS05EnterBarn = 6,
+ kAS05UseTwigWithChicken = 11,
+ kAS05LeaveScene = 12
+};
+
+enum {
+ kAS06TryToGetGas = 0,
+ kAS06TryToClimbLadder = 1,
+ kAS06TryToClimbLadderDone = 2,
+ kAS06TalkToHorse = 3,
+ kAS06UseTwigOnHorse = 4,
+ kAS06LeaveScene = 5
+};
+
+enum {
+ kAS07Wait = 0,
+ kAS07LeaveScene = 1
+};
+
+enum {
+ kAS08LeaveScene = 0,
+ kAS08TalkMan = 1,
+ kAS08LookMan = 2,
+ kAS08LookDog = 3,
+ kAS08GrabDog = 4,
+ kAS08TalkDog = 5,
+ kAS08PlatWithMan = 6,
+ kAS08PlatWithDog = 7
+};
+
+enum {
+ kAS09LeaveScene = 0,
+ kAS09SearchTrash = 1,
+ kAS09SearchTrashDone = 2
+};
+
+/*****************************************************************************/
+
+class GnapEngine;
+class CutScene;
+
+class Scene01: public Scene {
+public:
+ Scene01(GnapEngine *vm);
+ virtual ~Scene01();
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {}
+
+private:
+ int _pigsIdCtr;
+ int _smokeIdCtr;
+ Graphics::Surface *_spaceshipSurface;
+};
+
+class Scene02: public Scene {
+public:
+ Scene02(GnapEngine *vm);
+ virtual ~Scene02() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {}
+
+private:
+ int _truckGrillCtr;
+ int _nextChickenSequenceId;
+ int _currChickenSequenceId;
+ int _gnapTruckSequenceId;
+};
+
+class Scene03: public Scene {
+public:
+ Scene03(GnapEngine *vm);
+ virtual ~Scene03() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {}
+
+private:
+ bool _platypusHypnotized;
+ bool _platypusScared;
+ int _nextPlatSequenceId;
+ int _nextFrogSequenceId;
+ int _currFrogSequenceId;
+};
+
+class Scene04: public Scene {
+public:
+ Scene04(GnapEngine *vm);
+ virtual ~Scene04() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {}
+
+private:
+ bool _triedWindow;
+ int _dogIdCtr;
+ int _nextDogSequenceId;
+ int _currDogSequenceId;
+};
+
+class Scene05: public Scene {
+public:
+ Scene05(GnapEngine *vm);
+ virtual ~Scene05() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {}
+
+private:
+ int _nextChickenSequenceId;
+ int _currChickenSequenceId;
+};
+
+class Scene06: public Scene {
+public:
+ Scene06(GnapEngine *vm);
+ virtual ~Scene06() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {}
+
+private:
+ bool _horseTurnedBack;
+ int _nextPlatSequenceId;
+ int _nextHorseSequenceId;
+ int _currHorseSequenceId;
+};
+
+class Scene07: public Scene {
+public:
+ Scene07(GnapEngine *vm);
+ virtual ~Scene07() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {}
+};
+
+class Scene08: public Scene {
+public:
+ Scene08(GnapEngine *vm);
+ virtual ~Scene08() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb();
+
+private:
+ int _nextDogSequenceId;
+ int _currDogSequenceId;
+ int _nextManSequenceId;
+ int _currManSequenceId;
+};
+
+class Scene09: public Scene {
+public:
+ Scene09(GnapEngine *vm);
+ virtual ~Scene09() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {}
+};
+
+} // End of namespace Gnap
+
+#endif // GNAP_GROUP0_H
diff --git a/engines/gnap/scenes/group1.cpp b/engines/gnap/scenes/group1.cpp
new file mode 100644
index 0000000000..bd152c7f39
--- /dev/null
+++ b/engines/gnap/scenes/group1.cpp
@@ -0,0 +1,4500 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can 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 "gnap/gnap.h"
+#include "gnap/gamesys.h"
+#include "gnap/resource.h"
+#include "gnap/scenes/group1.h"
+
+namespace Gnap {
+
+Scene10::Scene10(GnapEngine *vm) : Scene(vm) {
+ _nextCookSequenceId = -1;
+ _currCookSequenceId = -1;
+}
+
+int Scene10::init() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ gameSys.setAnimation(0, 0, 0);
+ gameSys.setAnimation(0, 0, 1);
+ gameSys.setAnimation(0, 0, 2);
+ return 0x10F;
+}
+
+void Scene10::updateHotspots() {
+ _vm->setHotspot(kHS10Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS10ExitBar, 0, 75, 85, 455, SF_EXIT_NW_CURSOR);
+ _vm->setHotspot(kHS10ExitBackdoor, 75, 590, 500, 599, SF_EXIT_D_CURSOR | SF_WALKABLE);
+ _vm->setHotspot(kHS10Cook, 370, 205, 495, 460, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS10Tongs, 250, 290, 350, 337, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS10Box, 510, 275, 565, 330, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS10Oven, 690, 280, 799, 420, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS10WalkArea1, 59, 0, 495, 460);
+ _vm->setHotspot(kHS10WalkArea2, 495, 0, 650, 420);
+ _vm->setHotspot(kHS10WalkArea3, 651, 0, 725, 400);
+ _vm->setHotspot(kHS10WalkArea4, 725, 0, 799, 441);
+ _vm->setDeviceHotspot(kHS10Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 12;
+}
+
+void Scene10::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _currCookSequenceId = 0x103;
+
+ gameSys.setAnimation(0x103, 100, 2);
+ gameSys.insertSequence(0x103, 100, 0, 0, kSeqNone, 0, 0, 0);
+
+ _nextCookSequenceId = 0x106;
+ if (!_vm->isFlag(kGFMudTaken))
+ gameSys.insertSequence(0x107, 100, 0, 0, kSeqNone, 0, 0, 0);
+
+ _vm->queueInsertDeviceIcon();
+
+ if (_vm->_prevSceneNum == 9) {
+ gnap.initPos(11, 8, kDirBottomLeft);
+ plat.initPos(12, 7, kDirIdleRight);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(9, 8), -1, 0x107BA, 1);
+ plat.walkTo(Common::Point(9, 7), -1, 0x107D2, 1);
+ } else {
+ gnap.initPos(-1, 7, kDirBottomRight);
+ plat.initPos(-2, 8, kDirIdleLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(1, 7), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(1, 8), -1, 0x107C2, 1);
+ }
+
+ _vm->_timers[4] = _vm->getRandom(80) + 150;
+ _vm->_timers[5] = _vm->getRandom(100) + 100;
+
+ while (!_vm->_sceneDone) {
+ if (!_vm->isSoundPlaying(0x1091E))
+ _vm->playSound(0x1091E, true);
+
+ if (!_vm->isSoundPlaying(0x1091A))
+ _vm->playSound(0x1091A, true);
+
+ _vm->updateMouseCursor();
+
+ _vm->testWalk(0, 0, -1, -1, -1, -1);
+
+ _vm->updateCursorByHotspot();
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS10Platypus:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ if (_vm->isFlag(kGFMudTaken))
+ gnap.playMoan1(plat._pos);
+ else
+ gnap.playScratchingHead(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(10);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ break;
+ }
+ }
+ break;
+
+ case kHS10ExitBar:
+ _vm->_isLeavingScene = true;
+ gnap.actionIdle(0x10C);
+ gnap.walkTo(Common::Point(0, 7), 0, 0x107AF, 1);
+ gnap._actionStatus = kAS10LeaveScene;
+ plat.walkTo(Common::Point(0, 7), -1, 0x107CF, 1);
+ _vm->_newSceneNum = 11;
+ break;
+
+ case kHS10ExitBackdoor:
+ _vm->_isLeavingScene = true;
+ gnap.actionIdle(0x10C);
+ gnap.walkTo(Common::Point(2, 9), 0, 0x107AE, 1);
+ gnap._actionStatus = kAS10LeaveScene;
+ plat.walkTo(Common::Point(3, 9), -1, 0x107C7, 1);
+ _vm->_newSceneNum = 9;
+ break;
+
+ case kHS10Cook:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(4, 8), 6, 0);
+ gameSys.setAnimation(makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, 0);
+ gnap._actionStatus = kAS10AnnoyCook;
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(6, 0));
+ break;
+ case GRAB_CURSOR:
+ gnap.playImpossible();
+ gnap._idleFacing = kDirBottomRight;
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.actionIdle(0x10C);
+ gnap.walkTo(Common::Point(4, 8), 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS10AnnoyCook;
+ break;
+ case PLAT_CURSOR:
+ gnap.actionIdle(0x10C);
+ gnap.useDeviceOnPlatypus();
+ plat.walkTo(Common::Point(4, 6), -1, -1, 1);
+ gnap.walkTo(Common::Point(4, 8), 0, 0x107BB, 1);
+ gnap._actionStatus = kAS10AnnoyCook;
+ break;
+ }
+ }
+ break;
+
+ case kHS10Tongs:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(3, 7), 4, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ if (_vm->isFlag(kGFMudTaken))
+ gnap.playMoan2(Common::Point(-1, -1));
+ else
+ gnap.playScratchingHead(Common::Point(4, 3));
+ break;
+ case GRAB_CURSOR:
+ if (_vm->isFlag(kGFMudTaken))
+ gnap.playMoan2(Common::Point(-1, -1));
+ else {
+ gnap.actionIdle(0x10C);
+ gnap.walkTo(Common::Point(4, 8), 0, 0x107BB, 1);
+ gnap._actionStatus = kAS10AnnoyCook;
+ }
+ break;
+ case TALK_CURSOR:
+ gnap.playImpossible();
+ break;
+ case PLAT_CURSOR:
+ if (_vm->isFlag(kGFMudTaken))
+ gnap.playMoan2(Common::Point(-1, -1));
+ else {
+ gnap.actionIdle(0x10C);
+ gnap.useDeviceOnPlatypus();
+ plat.walkTo(Common::Point(3, 7), -1, -1, 1);
+ gnap.walkTo(Common::Point(4, 8), 0, 0x107BB, 1);
+ gnap._actionStatus = kAS10AnnoyCook;
+ }
+ break;
+ }
+ }
+ break;
+
+ case kHS10Box:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(7, 6), 6, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(7, 3));
+ break;
+ case GRAB_CURSOR:
+ gnap.actionIdle(0x10C);
+ gnap.walkTo(Common::Point(4, 8), 0, 0x107BB, 1);
+ gnap._actionStatus = kAS10AnnoyCook;
+ break;
+ case TALK_CURSOR:
+ gnap.playImpossible();
+ break;
+ case PLAT_CURSOR:
+ if (_vm->isFlag(kGFMudTaken))
+ gnap.playMoan2(Common::Point(-1, -1));
+ else {
+ _vm->invAdd(kItemTongs);
+ _vm->setFlag(kGFMudTaken);
+ gnap.actionIdle(0x10C);
+ gnap.useDeviceOnPlatypus();
+ plat.walkTo(Common::Point(7, 6), 1, 0x107D2, 1);
+ plat._actionStatus = kAS10PlatWithBox;
+ plat._idleFacing = kDirIdleRight;
+ _vm->_largeSprite = gameSys.createSurface(0xC3);
+ gnap.playIdle(Common::Point(7, 6));
+ }
+ break;
+ }
+ }
+ break;
+
+ case kHS10Oven:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(9, 6), 10, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playSequence(gnap.getSequenceId(kGSDeflect, Common::Point(10, 5)) | 0x10000);
+ break;
+ case GRAB_CURSOR:
+ gnap.actionIdle(0x10C);
+ gnap.walkTo(Common::Point(9, 6), 0, 0x107BB, 1);
+ gameSys.insertSequence(0x10E, 120, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x10E;
+ gnap._id = 120;
+ gnap._idleFacing = kDirUpRight;
+ gnap._sequenceDatNum = 0;
+ gnap._pos = Common::Point(9, 6);
+ _vm->_timers[2] = 360;
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ break;
+
+ case kHS10WalkArea1:
+ case kHS10WalkArea2:
+ case kHS10WalkArea3:
+ case kHS10WalkArea4:
+ gnap.actionIdle(0x10C);
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ case kHS10Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left) {
+ gnap.actionIdle(0x10C);
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+ }
+
+ updateAnimations();
+
+ if (!_vm->_isLeavingScene) {
+ plat.updateIdleSequence();
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[4]) {
+ _vm->_timers[4] = _vm->getRandom(80) + 150;
+ _vm->playSound(0x12B, false);
+ }
+ if (!_vm->_timers[5]) {
+ _vm->_timers[5] = _vm->getRandom(100) + 100;
+ int _gnapRandomValue = _vm->getRandom(4);
+ if (_gnapRandomValue) {
+ int sequenceId;
+ if (_gnapRandomValue == 1) {
+ sequenceId = 0x8A5;
+ } else if (_gnapRandomValue == 2) {
+ sequenceId = 0x8A6;
+ } else {
+ sequenceId = 0x8A7;
+ }
+ gameSys.insertSequence(sequenceId | 0x10000, 179, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ }
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene10::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS10LeaveScene:
+ _vm->_sceneDone = true;
+ break;
+ case kAS10AnnoyCook:
+ _nextCookSequenceId = 0x105;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(1) == 2) {
+ gameSys.setAnimation(0, 0, 1);
+ switch (plat._actionStatus) {
+ case kAS10PlatWithBox:
+ _nextCookSequenceId = 0x109;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(2) == 2 && _nextCookSequenceId != -1) {
+
+ switch (_nextCookSequenceId) {
+ case 0x109:
+ plat._pos = Common::Point(4, 8);
+ gameSys.insertSequence(0x109, 100, _currCookSequenceId, 100, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x107C9, 160,
+ plat._sequenceId | (plat._sequenceDatNum << 16), plat._id,
+ kSeqSyncWait, _vm->getSequenceTotalDuration(0x109) + _vm->getSequenceTotalDuration(0x10A) + _vm->getSequenceTotalDuration(0x10843),
+ 75 * plat._pos.x - plat._gridX, 48 * plat._pos.y - plat._gridY);
+ gameSys.removeSequence(0x107, 100, true);
+ _currCookSequenceId = 0x109;
+ _nextCookSequenceId = 0x843;
+ plat._sequenceId = 0x7C9;
+ plat._id = 160;
+ plat._idleFacing = kDirIdleLeft;
+ plat._sequenceDatNum = 1;
+ break;
+ case 0x843:
+ _vm->hideCursor();
+ gameSys.insertSpriteDrawItem(_vm->_largeSprite, 0, 0, 300);
+ gameSys.insertSequence(0x10843, 301, _currCookSequenceId, 100, kSeqSyncWait, 0, 0, 0);
+ _currCookSequenceId = 0x843;
+ _nextCookSequenceId = 0x10A;
+ break;
+ case 0x10A:
+ gameSys.insertSequence(_nextCookSequenceId, 100, 0x10843, 301, kSeqSyncWait, 0, 0, 0);
+ _currCookSequenceId = _nextCookSequenceId;
+ _nextCookSequenceId = 0x104;
+ _vm->showCursor();
+ gameSys.removeSpriteDrawItem(_vm->_largeSprite, 300);
+ _vm->delayTicksCursor(5);
+ _vm->deleteSurface(&_vm->_largeSprite);
+ _vm->setGrabCursorSprite(kItemTongs);
+ if (plat._actionStatus == kAS10PlatWithBox)
+ plat._actionStatus = -1;
+ if (gnap._pos == Common::Point(4, 8))
+ gnap.walkStep();
+ break;
+ default:
+ gameSys.insertSequence(_nextCookSequenceId, 100, _currCookSequenceId, 100, kSeqSyncWait, 0, 0, 0);
+ _currCookSequenceId = _nextCookSequenceId;
+ break;
+ }
+
+ switch (_currCookSequenceId) {
+ case 0x106:
+ if (gnap._actionStatus >= 0 || plat._actionStatus >= 0)
+ _nextCookSequenceId = 0x106;
+ else {
+ int rnd = _vm->getRandom(7);
+ switch (rnd) {
+ case 0:
+ _nextCookSequenceId = 0x104;
+ break;
+ case 1:
+ _nextCookSequenceId = 0x103;
+ break;
+ case 2:
+ _nextCookSequenceId = 0x106;
+ gameSys.insertSequence(0x10D, 1, 0, 0, kSeqNone, 0, 0, 0);
+ break;
+ default:
+ _nextCookSequenceId = 0x106;
+ }
+ }
+ break;
+ case 0x103:
+ if (gnap._actionStatus >= 0 || plat._actionStatus >= 0)
+ _nextCookSequenceId = 0x106;
+ else if (_vm->getRandom(7) == 0)
+ _nextCookSequenceId = 0x104;
+ else
+ _nextCookSequenceId = 0x106;
+ break;
+ case 0x104:
+ if (gnap._actionStatus >= 0 || plat._actionStatus >= 0)
+ _nextCookSequenceId = 0x106;
+ else if (_vm->getRandom(7) == 0)
+ _nextCookSequenceId = 0x103;
+ else
+ _nextCookSequenceId = 0x106;
+ break;
+ case 0x105:
+ if (gnap._actionStatus >= 0 || plat._actionStatus >= 0)
+ _nextCookSequenceId = 0x106;
+ else {
+ int rnd = _vm->getRandom(7);
+ switch (rnd) {
+ case 0:
+ _nextCookSequenceId = 0x104;
+ break;
+ case 1:
+ _nextCookSequenceId = 0x103;
+ break;
+ default:
+ _nextCookSequenceId = 0x106;
+ }
+ }
+ _vm->_timers[2] = _vm->getRandom(30) + 20;
+ _vm->_timers[3] = 300;
+ gameSys.insertSequence(0x10C, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x10C;
+ gnap._idleFacing = kDirUpRight;
+ gnap._sequenceDatNum = 0;
+ gnap._actionStatus = -1;
+ plat._actionStatus = -1;
+ break;
+ }
+ if (_currCookSequenceId == 0x843)
+ gameSys.setAnimation(_currCookSequenceId | 0x10000, 301, 2);
+ else
+ gameSys.setAnimation(_currCookSequenceId, 100, 2);
+ }
+}
+
+void Scene10::updateAnimationsCb() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ if (gameSys.getAnimationStatus(2) == 2) {
+ gameSys.setAnimation(_nextCookSequenceId, 100, 2);
+ gameSys.insertSequence(_nextCookSequenceId, 100, _currCookSequenceId, 100, kSeqSyncWait, 0, 0, 0);
+ _currCookSequenceId = _nextCookSequenceId;
+ _nextCookSequenceId = 0x106;
+ }
+}
+
+/*****************************************************************************/
+
+Scene11::Scene11(GnapEngine *vm) : Scene(vm) {
+ _billardBallCtr = 0;
+ _nextHookGuySequenceId = -1;
+ _currHookGuySequenceId = -1;
+ _nextGoggleGuySequenceId = -1;
+ _currGoggleGuySequenceId = -1;
+}
+
+int Scene11::init() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ gameSys.setAnimation(0, 0, 0);
+ gameSys.setAnimation(0, 0, 3);
+ gameSys.setAnimation(0, 0, 2);
+ if (_vm->_prevSceneNum == 10 || _vm->_prevSceneNum == 13) {
+ _vm->playSound(0x108EC, false);
+ _vm->playSound(0x10928, false);
+ }
+ return 0x209;
+}
+
+void Scene11::updateHotspots() {
+ _vm->setHotspot(kHS11Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS11ExitKitchen, 420, 140, 520, 345, SF_EXIT_U_CURSOR);
+ _vm->setHotspot(kHS11ExitToilet, 666, 130, 740, 364, SF_EXIT_R_CURSOR);
+ _vm->setHotspot(kHS11ExitLeft, 0, 350, 10, 599, SF_EXIT_L_CURSOR | SF_WALKABLE);
+ _vm->setHotspot(kHS11GoggleGuy, 90, 185, 185, 340, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS11HookGuy, 210, 240, 340, 430, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS11Billard, 640, 475, 700, 530, SF_WALKABLE | SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS11WalkArea1, 0, 0, 365, 453);
+ _vm->setHotspot(kHS11WalkArea2, 0, 0, 629, 353);
+ _vm->setHotspot(kHS11WalkArea3, 629, 0, 799, 364);
+ _vm->setHotspot(kHS11WalkArea4, 735, 0, 799, 397);
+ _vm->setHotspot(kHS11WalkArea5, 510, 540, 799, 599);
+ _vm->setDeviceHotspot(kHS11Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 13;
+}
+
+void Scene11::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ bool flag = true;
+
+ _vm->_timers[7] = 50;
+ _vm->_hotspots[kHS11Billard]._flags |= SF_DISABLED;
+
+ _currGoggleGuySequenceId = 0x1F9;
+ _currHookGuySequenceId = 0x201;
+
+ switch (_vm->_prevSceneNum) {
+ case 13:
+ gnap.initPos(8, 5, kDirBottomLeft);
+ plat.initPos(9, 6, kDirIdleRight);
+ break;
+ case 47:
+ gnap.initPos(8, 5, kDirBottomLeft);
+ plat.initPos(9, 5, kDirIdleRight);
+ _currGoggleGuySequenceId = 0x1FA;
+ _currHookGuySequenceId = 0x1FF;
+ _vm->_timers[7] = 180;
+ break;
+ case 12:
+ gnap.initPos(-1, 9, kDirBottomRight);
+ plat.initPos(-2, 8, kDirIdleLeft);
+ break;
+ default:
+ gnap.initPos(6, 6, kDirBottomLeft);
+ plat.initPos(6, 5, kDirIdleRight);
+ break;
+ }
+
+ _vm->queueInsertDeviceIcon();
+
+ gameSys.insertSequence(_currHookGuySequenceId, 120, 0, 0, kSeqNone, 0, 0, 0);
+
+ _nextHookGuySequenceId = -1;
+
+ gameSys.setAnimation(_currHookGuySequenceId, 120, 3);
+ gameSys.insertSequence(_currGoggleGuySequenceId, 121, 0, 0, kSeqNone, 0, 0, 0);
+
+ _nextGoggleGuySequenceId = -1;
+
+ gameSys.setAnimation(_currGoggleGuySequenceId, 121, 2);
+
+ _vm->_timers[5] = _vm->getRandom(100) + 75;
+ _vm->_timers[4] = _vm->getRandom(40) + 20;
+ _vm->_timers[6] = _vm->getRandom(100) + 100;
+ _vm->endSceneInit();
+
+ if (_vm->_prevSceneNum == 12) {
+ gnap.walkTo(Common::Point(2, 8), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(1, 8), -1, 0x107C2, 1);
+ }
+
+ gameSys.insertSequence(0x208, 256, 0, 0, kSeqNone, 40, 0, 0);
+
+ while (!_vm->_sceneDone) {
+ _vm->testWalk(0, 0, -1, -1, -1, -1);
+
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS11Platypus:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ break;
+ }
+ }
+ break;
+
+ case kHS11ExitKitchen:
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(Common::Point(6, 5), 0, 0x107BF, 1);
+ gnap._actionStatus = kAS11LeaveScene;
+ plat.walkTo(Common::Point(6, 6), -1, -1, 1);
+ _vm->_newSceneNum = 10;
+ break;
+
+ case kHS11ExitToilet:
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(Common::Point(8, 5), 0, 0x107BF, 1);
+ gnap._actionStatus = kAS11LeaveScene;
+ plat.walkTo(Common::Point(8, 6), -1, -1, 1);
+ _vm->_newSceneNum = 13;
+ break;
+
+ case kHS11ExitLeft:
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(Common::Point(-1, 8), 0, 0x107AF, 1);
+ gnap._actionStatus = kAS11LeaveScene;
+ plat.walkTo(Common::Point(-1, 9), -1, 0x107CF, 1);
+ _vm->_newSceneNum = 12;
+ break;
+
+ case kHS11GoggleGuy:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemMagazine) {
+ gnap.walkTo(Common::Point(3, 7), 0, 0x107BC, 1);
+ gnap._actionStatus = kAS11ShowMagazineToGoggleGuy;
+ gnap.playShowItem(_vm->_grabCursorSpriteIndex, 2, 0);
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(3, 7), 2, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(1, 6));
+ break;
+ case GRAB_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpLeft;
+ gnap.walkTo(Common::Point(3, 7), 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS11TalkGoggleGuy;
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS11HookGuy:
+ if (gnap._actionStatus < 0) {
+ gnap._idleFacing = kDirUpRight;
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.walkTo(Common::Point(5, 6), 0, 0x107BC, 9);
+ gnap._actionStatus = kAS11ShowItemToHookGuy;
+ gnap.playShowItem(_vm->_grabCursorSpriteIndex, 4, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playSequence(gnap.getSequenceId(kGSDeflect, Common::Point(3, 6)) | 0x10000);
+ break;
+ case GRAB_CURSOR:
+ gnap.walkTo(Common::Point(5, 6), 0, 0x107BC, 1);
+ gnap._actionStatus = kAS11GrabHookGuy;
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirBottomLeft;
+ gnap.walkTo(Common::Point(5, 6), 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS11TalkHookGuy;
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS11Billard:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible(Common::Point(9, 8));
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(9, 8));
+ break;
+ case GRAB_CURSOR:
+ gnap.walkTo(Common::Point(9, 8), 0, 0x107BA, 1);
+ gnap._actionStatus = kAS11GrabBillardBall;
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible(Common::Point(9, 8));
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS11WalkArea1:
+ case kHS11WalkArea2:
+ case kHS11WalkArea3:
+ case kHS11WalkArea4:
+ case kHS11WalkArea5:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ case kHS11Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left && gnap._actionStatus < 0) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+
+ }
+
+ updateAnimations();
+
+ if (!_vm->_isLeavingScene) {
+ if (flag && !_vm->_timers[7]) {
+ flag = false;
+ gameSys.setAnimation(0x207, 257, 4);
+ gameSys.insertSequence(0x207, 257, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ plat.updateIdleSequence2();
+ gnap.updateIdleSequence2();
+ if (!_vm->_timers[5]) {
+ _vm->_timers[5] = _vm->getRandom(100) + 75;
+ if (gnap._actionStatus < 0 && plat._actionStatus < 0 && _nextGoggleGuySequenceId == -1) {
+ if (_vm->getRandom(2))
+ _nextGoggleGuySequenceId = 0x1F6;
+ else
+ _nextGoggleGuySequenceId = 0x1F9;
+ }
+ }
+ if (!_vm->_timers[4]) {
+ _vm->_timers[4] = _vm->getRandom(40) + 20;
+ if (gnap._actionStatus < 0 && plat._actionStatus < 0 && _nextHookGuySequenceId == -1) {
+ if (_currHookGuySequenceId == 0x201) {
+ switch (_vm->getRandom(7)) {
+ case 0:
+ _nextHookGuySequenceId = 0x200;
+ break;
+ case 1:
+ _nextHookGuySequenceId = 0x205;
+ break;
+ case 2:
+ _nextHookGuySequenceId = 0x202;
+ break;
+ default:
+ _nextHookGuySequenceId = 0x201;
+ break;
+ }
+ } else {
+ _nextHookGuySequenceId = 0x201;
+ }
+ }
+ }
+ if (!_vm->_timers[6]) {
+ _vm->_timers[6] = _vm->getRandom(100) + 100;
+ int _gnapRandomValue = _vm->getRandom(3);
+ switch (_gnapRandomValue) {
+ case 0:
+ gameSys.insertSequence(0x8A5 | 0x10000, 179, 0, 0, kSeqNone, 0, 0, 0);
+ break;
+ case 1:
+ gameSys.insertSequence(0x8A7 | 0x10000, 179, 0, 0, kSeqNone, 0, 0, 0);
+ break;
+ case 2:
+ gameSys.insertSequence(0x8A6 | 0x10000, 179, 0, 0, kSeqNone, 0, 0, 0);
+ break;
+ }
+ }
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[5] = _vm->getRandom(50) + 75;
+ _vm->_timers[4] = _vm->getRandom(40) + 20;
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene11::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ if (gnap._actionStatus != kAS11GrabBillardBall)
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS11LeaveScene:
+ _vm->_sceneDone = true;
+ break;
+ case kAS11ShowMagazineToGoggleGuy:
+ _nextGoggleGuySequenceId = 0x1F7;
+ break;
+ case kAS11TalkGoggleGuy:
+ _nextGoggleGuySequenceId = 0x1FB;
+ break;
+ case kAS11GrabHookGuy:
+ _nextHookGuySequenceId = 0x204;
+ break;
+ case kAS11ShowItemToHookGuy:
+ _nextHookGuySequenceId = 0x203;
+ break;
+ case kAS11TalkHookGuy:
+ _nextHookGuySequenceId = 0x206;
+ break;
+ case kAS11GrabBillardBall:
+ if (gameSys.getAnimationStatus(2) == 2 && gameSys.getAnimationStatus(3) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ _vm->_timers[2] = _vm->getRandom(30) + 20;
+ _vm->_timers[3] = _vm->getRandom(50) + 200;
+ gameSys.insertSequence(0x1F4, 255, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x1F4;
+ gnap._id = 255;
+ gnap._sequenceDatNum = 0;
+ gameSys.removeSequence(0x207, 257, true);
+ gameSys.removeSequence(0x208, 256, true);
+ _nextGoggleGuySequenceId = 0x1F8;
+ _vm->_timers[5] = _vm->getRandom(100) + 75;
+ gameSys.insertSequence(_nextGoggleGuySequenceId, 121, _currGoggleGuySequenceId, 121, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextGoggleGuySequenceId, 121, 2);
+ _currGoggleGuySequenceId = _nextGoggleGuySequenceId;
+ _nextGoggleGuySequenceId = -1;
+ switch (_billardBallCtr) {
+ case 0:
+ _nextHookGuySequenceId = 0x1FC;
+ break;
+ case 1:
+ _nextHookGuySequenceId = 0x1FD;
+ break;
+ default:
+ _nextHookGuySequenceId = 0x1FE;
+ break;
+ }
+ ++_billardBallCtr;
+ gameSys.insertSequence(_nextHookGuySequenceId, 120, _currHookGuySequenceId, 120, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextHookGuySequenceId, 120, 3);
+ _currHookGuySequenceId = _nextHookGuySequenceId;
+ _nextHookGuySequenceId = -1;
+ _vm->_timers[4] = _vm->getRandom(40) + 20;
+ gameSys.insertSequence(0x208, 256, 0, 0, kSeqNone, _vm->getSequenceTotalDuration(0x1F4) - 5, 0, 0);
+ _vm->_hotspots[kHS11Billard]._flags |= SF_DISABLED;
+ gameSys.setAnimation(0x207, 257, 4);
+ gameSys.insertSequence(0x207, 257, 0, 0, kSeqNone, _vm->getSequenceTotalDuration(0x1FE), 0, 0);
+ gnap._actionStatus = -1;
+ }
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(2) == 2 && _nextGoggleGuySequenceId != -1) {
+ _vm->_timers[5] = _vm->getRandom(100) + 75;
+ gameSys.insertSequence(_nextGoggleGuySequenceId, 121, _currGoggleGuySequenceId, 121, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextGoggleGuySequenceId, 121, 2);
+ _currGoggleGuySequenceId = _nextGoggleGuySequenceId;
+ _nextGoggleGuySequenceId = -1;
+ if (gnap._actionStatus >= 1 && gnap._actionStatus <= 4)
+ gnap._actionStatus = -1;
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2) {
+ if (_nextHookGuySequenceId == 0x204) {
+ gameSys.setAnimation(_nextHookGuySequenceId, 120, 3);
+ gameSys.insertSequence(0x204, 120, _currHookGuySequenceId, 120, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x1F5, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ _currHookGuySequenceId = 0x204;
+ _nextHookGuySequenceId = -1;
+ gnap._sequenceId = 0x1F5;
+ gnap._sequenceDatNum = 0;
+ _vm->_timers[4] = _vm->getRandom(40) + 20;
+ _vm->_timers[2] = _vm->getRandom(20) + 70;
+ _vm->_timers[3] = _vm->getRandom(50) + 200;
+ if (gnap._actionStatus == kAS11GrabHookGuy)
+ gnap._actionStatus = -1;
+ } else if (_nextHookGuySequenceId != -1) {
+ gameSys.insertSequence(_nextHookGuySequenceId, 120, _currHookGuySequenceId, 120, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextHookGuySequenceId, 120, 3);
+ _currHookGuySequenceId = _nextHookGuySequenceId;
+ _nextHookGuySequenceId = -1;
+ _vm->_timers[4] = _vm->getRandom(40) + 20;
+ if (gnap._actionStatus >= 6 && gnap._actionStatus <= 9)
+ gnap._actionStatus = -1;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(4) == 2) {
+ gameSys.setAnimation(0, 0, 4);
+ _vm->_hotspots[kHS11Billard]._flags &= ~SF_DISABLED;
+ }
+}
+
+/*****************************************************************************/
+
+Scene12::Scene12(GnapEngine *vm) : Scene(vm) {
+ _nextBeardGuySequenceId = -1;
+ _currBeardGuySequenceId = -1;
+ _nextToothGuySequenceId = -1;
+ _currToothGuySequenceId = -1;
+ _nextBarkeeperSequenceId = -1;
+ _currBarkeeperSequenceId = -1;
+}
+
+int Scene12::init() {
+ return 0x209;
+}
+
+void Scene12::updateHotspots() {
+ _vm->setHotspot(kHS12Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS12ExitRight, 790, 360, 799, 599, SF_EXIT_R_CURSOR);
+ _vm->setHotspot(kHS12ToothGuy, 80, 180, 160, 380, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS12Barkeeper, 490, 175, 580, 238, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS12BeardGuy, 620, 215, 720, 350, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS12Jukebox, 300, 170, 410, 355, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS12WalkArea1, 0, 0, 260, 460);
+ _vm->setHotspot(kHS12WalkArea2, 0, 0, 380, 410);
+ _vm->setHotspot(kHS12WalkArea3, 0, 0, 799, 395);
+ _vm->setHotspot(kHS12WalkArea4, 585, 0, 799, 455);
+ _vm->setDeviceHotspot(kHS12Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 11;
+}
+
+void Scene12::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ int v18 = 1;
+
+ _vm->queueInsertDeviceIcon();
+
+ gameSys.insertSequence(0x207, 256, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.insertSequence(0x200, 50, 0, 0, kSeqNone, 0, 0, 0);
+
+ _currToothGuySequenceId = 0x200;
+ _nextToothGuySequenceId = -1;
+
+ gameSys.setAnimation(0x200, 50, 2);
+ gameSys.insertSequence(0x202, 50, 0, 0, kSeqNone, 0, 0, 0);
+
+ _currBeardGuySequenceId = 0x202;
+ _nextBeardGuySequenceId = -1;
+
+ gameSys.setAnimation(0x202, 50, 4);
+ gameSys.insertSequence(0x203, 50, 0, 0, kSeqNone, 0, 0, 0);
+
+ _currBarkeeperSequenceId = 0x203;
+ _nextBarkeeperSequenceId = -1;
+
+ gameSys.setAnimation(0x203, 50, 3);
+
+ _vm->_timers[4] = 30;
+ _vm->_timers[6] = _vm->getRandom(30) + 20;
+ _vm->_timers[5] = _vm->getRandom(30) + 20;
+ _vm->_timers[7] = _vm->getRandom(100) + 100;
+
+ if (_vm->_prevSceneNum == 15) {
+ gnap.initPos(5, 6, kDirBottomRight);
+ plat.initPos(3, 7, kDirIdleLeft);
+ _vm->endSceneInit();
+ } else {
+ gnap.initPos(11, 8, kDirBottomLeft);
+ plat.initPos(12, 8, kDirIdleRight);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(8, 8), -1, 0x107BA, 1);
+ plat.walkTo(Common::Point(9, 8), -1, 0x107D2, 1);
+ }
+
+ while (!_vm->_sceneDone) {
+ _vm->testWalk(0, 0, -1, -1, -1, -1);
+
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS12Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS12Platypus:
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ break;
+ }
+ break;
+
+ case kHS12ExitRight:
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(Common::Point(10, -1), 0, 0x107AB, 1);
+ gnap._actionStatus = kAS12LeaveScene;
+ plat.walkTo(Common::Point(10, -1), -1, -1, 1);
+ _vm->_newSceneNum = 11;
+ break;
+
+ case kHS12ToothGuy:
+ if (_vm->_grabCursorSpriteIndex == kItemQuarter) {
+ _vm->_largeSprite = gameSys.createSurface(0x141);
+ gnap.walkTo(Common::Point(3, 7), 0, 0x107BC, 9);
+ gnap._idleFacing = kDirUpLeft;
+ gnap._actionStatus = kAS12QuarterToToothGuy;
+ gnap.playShowItem(_vm->_grabCursorSpriteIndex, 2, 0);
+ _vm->setGrabCursorSprite(-1);
+ } else if (_vm->_grabCursorSpriteIndex == kItemQuarterWithHole) {
+ gnap.walkTo(Common::Point(3, 7), 0, 0x107BC, 9);
+ gnap._idleFacing = kDirUpLeft;
+ gnap._actionStatus = kAS12QuarterWithHoleToToothGuy;
+ gnap.playShowItem(_vm->_grabCursorSpriteIndex, 2, 0);
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.walkTo(Common::Point(3, 7), 0, 0x107BC, 9);
+ gnap._idleFacing = kDirUpLeft;
+ gnap._actionStatus = kAS12ShowItemToToothGuy;
+ gnap.playShowItem(_vm->_grabCursorSpriteIndex, 2, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(1, 2));
+ break;
+ case GRAB_CURSOR:
+ gnap.walkTo(Common::Point(3, 7), 0, 0x107BC, 1);
+ gnap._actionStatus = kAS12GrabToothGuy;
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpLeft;
+ gnap.walkTo(Common::Point(3, 7), 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS12TalkToothGuy;
+ break;
+ case PLAT_CURSOR:
+ gnap.useDeviceOnPlatypus();
+ plat.walkTo(Common::Point(3, 7), 1, 0x107D2, 1);
+ plat._actionStatus = kAS12PlatWithToothGuy;
+ plat._idleFacing = kDirIdleRight;
+ gnap.playIdle(Common::Point(2, 7));
+ break;
+ }
+ }
+ break;
+
+ case kHS12Barkeeper:
+ if (_vm->_grabCursorSpriteIndex == kItemQuarter || _vm->_grabCursorSpriteIndex == kItemQuarterWithHole) {
+ gnap.walkTo(Common::Point(6, 6), 0, 0x107BB, 9);
+ gnap._idleFacing = kDirUpRight;
+ gnap._actionStatus = kAS12QuarterWithBarkeeper;
+ gnap.playShowItem(_vm->_grabCursorSpriteIndex, 7, 0);
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.walkTo(Common::Point(6, 6), 0, 0x107BB, 9);
+ gnap._idleFacing = kDirUpRight;
+ gnap._actionStatus = kAS12ShowItemToBarkeeper;
+ gnap.playShowItem(_vm->_grabCursorSpriteIndex, 7, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.walkTo(Common::Point(6, 6), 0, 0x107BB, 1);
+ gnap._idleFacing = kDirUpRight;
+ gnap._actionStatus = kAS12LookBarkeeper;
+ break;
+ case GRAB_CURSOR:
+ gnap.playImpossible();
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(Common::Point(6, 6), 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS12TalkBarkeeper;
+ break;
+ case PLAT_CURSOR:
+ gnap.playPullOutDevice(plat._pos);
+ gameSys.setAnimation(makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, 0);
+ gnap._actionStatus = kAS12PlatWithBarkeeper;
+ break;
+ }
+ }
+ break;
+
+ case kHS12BeardGuy:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.walkTo(Common::Point(7, 6), 0, 0x107BB, 9);
+ gnap._idleFacing = kDirUpRight;
+ gnap._actionStatus = kAS12ShowItemToBeardGuy;
+ gnap.playShowItem(_vm->_grabCursorSpriteIndex, 8, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.walkTo(Common::Point(7, 6), 0, 0x107BB, 1);
+ gnap._idleFacing = kDirUpRight;
+ gnap._actionStatus = kAS12LookBeardGuy;
+ break;
+ case GRAB_CURSOR:
+ // NOTE Bug in the original. It has 9 as flags which seems wrong here.
+ gnap.walkTo(Common::Point(7, 6), 0, 0x107BB, 1);
+ gnap._idleFacing = kDirUpRight;
+ gnap._actionStatus = kAS12GrabBeardGuy;
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(Common::Point(7, 6), 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS12TalkBeardGuy;
+ break;
+ case PLAT_CURSOR:
+ gnap.useDeviceOnPlatypus();
+ plat.walkTo(Common::Point(7, 6), 1, 0x107C2, 1);
+ plat._actionStatus = kAS12PlatWithBeardGuy;
+ plat._idleFacing = kDirIdleLeft;
+ gnap.playIdle(Common::Point(7, 6));
+ break;
+ }
+ }
+ break;
+
+ case kHS12Jukebox:
+ _vm->_newSceneNum = 15;
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(Common::Point(5, 6), 0, 0x107BC, 1);
+ gnap._actionStatus = kAS12LeaveScene;
+ break;
+
+ case kHS12WalkArea1:
+ case kHS12WalkArea2:
+ case kHS12WalkArea3:
+ case kHS12WalkArea4:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left && gnap._actionStatus < 0) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+
+ }
+
+ updateAnimations();
+
+ if (!_vm->_isLeavingScene) {
+ plat.updateIdleSequence();
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[4]) {
+ _vm->_timers[4] = 15;
+ if (_nextToothGuySequenceId == -1) {
+ if (v18 == 0 && _currBeardGuySequenceId == 0x202 && _currBarkeeperSequenceId == 0x203 && gnap._actionStatus < 0 && plat._actionStatus < 0) {
+ if (_vm->getRandom(2) != 0)
+ _nextToothGuySequenceId = 0x1EC;
+ else
+ _nextToothGuySequenceId = 0x204;
+ } else if (_currToothGuySequenceId != 0x200)
+ _nextToothGuySequenceId = 0x200;
+ v18 = (v18 + 1) % 15;
+ }
+ }
+ if (!_vm->_timers[5]) {
+ _vm->_timers[5] = _vm->getRandom(30) + 20;
+ if (_nextBarkeeperSequenceId == -1 && gnap._actionStatus < 0 && plat._actionStatus < 0) {
+ if (v18 == 0 && _currToothGuySequenceId == 0x200 && _currBeardGuySequenceId == 0x202 && gnap._actionStatus < 0 && plat._actionStatus < 0) {
+ if (_vm->getRandom(2) != 0)
+ _nextBarkeeperSequenceId = 0x208;
+ else
+ _nextBarkeeperSequenceId = 0x1FB;
+ } else
+ _nextBarkeeperSequenceId = 0x203;
+ v18 = (v18 + 1) % 15;
+ }
+ }
+ if (!_vm->_timers[6]) {
+ _vm->_timers[6] = _vm->getRandom(30) + 15;
+ if (_nextBeardGuySequenceId == -1 && gnap._actionStatus < 0 && plat._actionStatus < 0) {
+ if (v18 == 0 && _currToothGuySequenceId == 0x200 && _currBarkeeperSequenceId == 0x203 && gnap._actionStatus < 0 && plat._actionStatus < 0)
+ _nextBeardGuySequenceId = 0x1F2;
+ else
+ _nextBeardGuySequenceId = 0x202;
+ v18 = (v18 + 1) % 15;
+ }
+ }
+ if (!_vm->_timers[7]) {
+ _vm->_timers[7] = _vm->getRandom(100) + 100;
+ int _gnapRandomValue = _vm->getRandom(3);
+ switch (_gnapRandomValue) {
+ case 0:
+ gameSys.insertSequence(0x8A5 | 0x10000, 179, 0, 0, kSeqNone, 0, 0, 0);
+ break;
+ case 1:
+ gameSys.insertSequence(0x8A7 | 0x10000, 179, 0, 0, kSeqNone, 0, 0, 0);
+ break;
+ case 2:
+ gameSys.insertSequence(0x8A6 | 0x10000, 179, 0, 0, kSeqNone, 0, 0, 0);
+ break;
+ }
+ }
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[4] = 30;
+ _vm->_timers[5] = _vm->getRandom(30) + 20;
+ _vm->_timers[6] = _vm->getRandom(30) + 20;
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene12::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS12LeaveScene:
+ _vm->_sceneDone = true;
+ break;
+ case kAS12TalkToothGuy:
+ if (_vm->isKeyStatus1(Common::KEYCODE_j)) {
+ // Easter egg
+ _vm->clearKeyStatus1(Common::KEYCODE_j);
+ _nextToothGuySequenceId = 0x206;
+ } else {
+ _nextToothGuySequenceId = 0x1EE;
+ }
+ break;
+ case 3:
+ break;
+ case kAS12GrabToothGuy:
+ if (_vm->isKeyStatus1(Common::KEYCODE_j)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_j);
+ _nextToothGuySequenceId = 0x206;
+ } else {
+ _nextToothGuySequenceId = 0x1EF;
+ }
+ break;
+ case kAS12ShowItemToToothGuy:
+ if (_vm->isKeyStatus1(Common::KEYCODE_j)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_j);
+ _nextToothGuySequenceId = 0x206;
+ } else {
+ _nextToothGuySequenceId = 0x1ED;
+ }
+ break;
+ case kAS12QuarterWithHoleToToothGuy:
+ if (_vm->isKeyStatus1(Common::KEYCODE_j)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_j);
+ _nextToothGuySequenceId = 0x206;
+ } else {
+ _nextToothGuySequenceId = 0x1EA;
+ }
+ break;
+ case kAS12QuarterToToothGuy:
+ if (_vm->isKeyStatus1(Common::KEYCODE_j)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_j);
+ _nextToothGuySequenceId = 0x206;
+ } else {
+ _nextToothGuySequenceId = 0x1E9;
+ }
+ break;
+ case kAS12QuarterToToothGuyDone:
+ gnap._actionStatus = -1;
+ _vm->showCursor();
+ gameSys.removeSpriteDrawItem(_vm->_largeSprite, 300);
+ _vm->deleteSurface(&_vm->_largeSprite);
+ _vm->setGrabCursorSprite(kItemQuarterWithHole);
+ break;
+ case kAS12TalkBeardGuy:
+ _nextBeardGuySequenceId = 0x1F4;
+ break;
+ case kAS12LookBeardGuy:
+ _nextBeardGuySequenceId = 0x1F3;
+ break;
+ case kAS12GrabBeardGuy:
+ _nextBeardGuySequenceId = 0x1F1;
+ break;
+ case kAS12ShowItemToBeardGuy:
+ _nextBeardGuySequenceId = 0x1F0;
+ break;
+ case kAS12TalkBarkeeper:
+ if (_vm->getRandom(2) != 0)
+ _nextBarkeeperSequenceId = 0x1FD;
+ else
+ _nextBarkeeperSequenceId = 0x1FF;
+ break;
+ case kAS12LookBarkeeper:
+ _nextBarkeeperSequenceId = 0x1F8;
+ break;
+ case 14:
+ _nextBarkeeperSequenceId = 0x1F6;
+ break;
+ case kAS12ShowItemToBarkeeper:
+ _nextBarkeeperSequenceId = 0x1F5;
+ break;
+ case kAS12QuarterWithBarkeeper:
+ _nextBarkeeperSequenceId = 0x1FA;
+ break;
+ case kAS12PlatWithBarkeeper:
+ _nextBarkeeperSequenceId = 0x1F9;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(1) == 2) {
+ gameSys.setAnimation(0, 0, 1);
+ switch (plat._actionStatus) {
+ case kAS12PlatWithToothGuy:
+ _nextToothGuySequenceId = 0x1EB;
+ break;
+ case kAS12PlatWithBeardGuy:
+ _nextBeardGuySequenceId = 0x1F3;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(2) == 2) {
+ if (_currToothGuySequenceId == 0x1E9) {
+ gameSys.setAnimation(0, 0, 2);
+ _vm->hideCursor();
+ gameSys.setAnimation(0x10843, 301, 0);
+ gnap._actionStatus = kAS12QuarterToToothGuyDone;
+ gameSys.insertSpriteDrawItem(_vm->_largeSprite, 0, 0, 300);
+ gameSys.insertSequence(0x10843, 301, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x107B7, gnap._id, 0x10843, 301,
+ kSeqSyncWait, 0, 75 * gnap._pos.x - gnap._gridX, 48 * gnap._pos.y - gnap._gridY);
+ gnap._sequenceId = 0x7B7;
+ gnap._sequenceDatNum = 1;
+ _vm->setFlag(kGFTwigTaken);
+ _vm->invAdd(kItemQuarterWithHole);
+ _vm->invRemove(kItemQuarter);
+ }
+ if (_nextToothGuySequenceId == 0x1EF) {
+ gameSys.setAnimation(_nextToothGuySequenceId, 50, 2);
+ gameSys.insertSequence(_nextToothGuySequenceId, 50, _currToothGuySequenceId, 50, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x205, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ _currToothGuySequenceId = _nextToothGuySequenceId;
+ _nextToothGuySequenceId = -1;
+ gnap._sequenceId = 0x205;
+ gnap._sequenceDatNum = 0;
+ _vm->_timers[4] = 40;
+ _vm->_timers[2] = _vm->getRandom(20) + 70;
+ _vm->_timers[3] = _vm->getRandom(50) + 200;
+ if (gnap._actionStatus == kAS12GrabToothGuy)
+ gnap._actionStatus = -1;
+ } else if (_nextToothGuySequenceId != -1) {
+ gameSys.insertSequence(_nextToothGuySequenceId, 50, _currToothGuySequenceId, 50, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextToothGuySequenceId, 50, 2);
+ _currToothGuySequenceId = _nextToothGuySequenceId;
+ _nextToothGuySequenceId = -1;
+ _vm->_timers[4] = 50;
+ if (gnap._actionStatus >= kAS12TalkToothGuy && gnap._actionStatus <= kAS12QuarterToToothGuy && _currToothGuySequenceId != 0x1E9 &&
+ _currToothGuySequenceId != 0x1EC && _currToothGuySequenceId != 0x200)
+ gnap._actionStatus = -1;
+ if (plat._actionStatus == kAS12PlatWithToothGuy)
+ plat._actionStatus = -1;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2) {
+ if (gnap._actionStatus == kAS12PlatWithBarkeeper && _currBarkeeperSequenceId == 0x1F9) {
+ gnap._actionStatus = -1;
+ gnap.playIdle(Common::Point(7, 6));
+ _vm->_timers[5] = 0;
+ }
+ if (_nextBarkeeperSequenceId != -1) {
+ gameSys.insertSequence(_nextBarkeeperSequenceId, 50, _currBarkeeperSequenceId, 50, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextBarkeeperSequenceId, 50, 3);
+ _currBarkeeperSequenceId = _nextBarkeeperSequenceId;
+ _nextBarkeeperSequenceId = -1;
+ _vm->_timers[5] = _vm->getRandom(30) + 20;
+ if (gnap._actionStatus >= kAS12TalkBarkeeper && gnap._actionStatus <= kAS12QuarterWithBarkeeper && _currBarkeeperSequenceId != 0x203 &&
+ _currBarkeeperSequenceId != 0x1FB && _currBarkeeperSequenceId != 0x208)
+ gnap._actionStatus = -1;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(4) == 2 && _nextBeardGuySequenceId != -1) {
+ gameSys.insertSequence(_nextBeardGuySequenceId, 50, _currBeardGuySequenceId, 50, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextBeardGuySequenceId, 50, 4);
+ _currBeardGuySequenceId = _nextBeardGuySequenceId;
+ _nextBeardGuySequenceId = -1;
+ _vm->_timers[6] = _vm->getRandom(30) + 20;
+ if (gnap._actionStatus >= kAS12TalkBeardGuy && gnap._actionStatus <= kAS12ShowItemToBeardGuy && _currBeardGuySequenceId != 0x202 && _currBeardGuySequenceId != 0x1F2)
+ gnap._actionStatus = -1;
+ if (plat._actionStatus == kAS12PlatWithBeardGuy)
+ plat._actionStatus = -1;
+ }
+}
+
+/*****************************************************************************/
+
+Scene13::Scene13(GnapEngine *vm) : Scene(vm) {
+ _backToiletCtr = -1;
+}
+
+int Scene13::init() {
+ _vm->playSound(0x108EC, false);
+ return 0xAC;
+}
+
+void Scene13::updateHotspots() {
+ _vm->setHotspot(kHS13Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS13ExitBar, 113, 160, 170, 455, SF_EXIT_L_CURSOR);
+ _vm->setHotspot(kHS13BackToilet, 385, 195, 478, 367, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS13FrontToilet, 497, 182, 545, 432, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS13Urinal, 680, 265, 760, 445, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS13Scribble, 560, 270, 660, 370, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS13Sink, 310, 520, 560, 599, SF_WALKABLE | SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS13WalkArea1, 268, 270, 325, 385);
+ _vm->setHotspot(kHS13WalkArea2, 0, 0, 52, 599);
+ _vm->setHotspot(kHS13WalkArea3, 0, 0, 113, 550);
+ _vm->setHotspot(kHS13WalkArea4, 0, 0, 226, 438);
+ _vm->setHotspot(kHS13WalkArea5, 0, 0, 268, 400);
+ _vm->setHotspot(kHS13WalkArea6, 0, 0, 799, 367);
+ _vm->setHotspot(kHS13WalkArea7, 478, 0, 799, 401);
+ _vm->setHotspot(kHS13WalkArea8, 545, 0, 799, 473);
+ _vm->setHotspot(kHS13WalkArea9, 0, 549, 799, 599);
+ _vm->setDeviceHotspot(kHS13Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 17;
+}
+
+void Scene13::showScribble() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ _vm->hideCursor();
+ _vm->_largeSprite = gameSys.createSurface(0x6F);
+ gameSys.insertSpriteDrawItem(_vm->_largeSprite, 0, 0, 300);
+ while (!_vm->_mouseClickState._left && !_vm->isKeyStatus1(Common::KEYCODE_ESCAPE) &&
+ !_vm->isKeyStatus1(Common::KEYCODE_SPACE) && !_vm->isKeyStatus1(Common::KEYCODE_RETURN) && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+ _vm->_mouseClickState._left = false;
+ _vm->clearKeyStatus1(Common::KEYCODE_ESCAPE);
+ _vm->clearKeyStatus1(Common::KEYCODE_RETURN);
+ _vm->clearKeyStatus1(Common::KEYCODE_SPACE);
+ gameSys.removeSpriteDrawItem(_vm->_largeSprite, 300);
+ _vm->deleteSurface(&_vm->_largeSprite);
+ _vm->showCursor();
+}
+
+void Scene13::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ int currSoundId = 0;
+
+ _vm->queueInsertDeviceIcon();
+ gameSys.insertSequence(0xAA, 256, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (_vm->_prevSceneNum == 14) {
+ gnap.initPos(6, 6, kDirBottomLeft);
+ plat.initPos(9, 8, kDirIdleLeft);
+ } else {
+ gnap.initPos(3, 7, kDirBottomRight);
+ plat.initPos(2, 7, kDirIdleLeft);
+ }
+
+ _vm->endSceneInit();
+
+ _vm->_timers[4] = _vm->getRandom(20) + 20;
+ _vm->_timers[5] = _vm->getRandom(50) + 50;
+
+ while (!_vm->_sceneDone) {
+ if (!_vm->isSoundPlaying(0x1091A))
+ _vm->playSound(0x1091A, true);
+
+ _vm->testWalk(0, 0, -1, -1, -1, -1);
+
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS13Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[4] = _vm->getRandom(20) + 20;
+ _vm->_timers[5] = _vm->getRandom(50) + 50;
+ }
+ break;
+
+ case kHS13Platypus:
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ break;
+ }
+ break;
+
+ case kHS13ExitBar:
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(Common::Point(2, 7), 0, 0x107C0, 1);
+ gnap._actionStatus = kAS13LeaveScene;
+ plat.walkTo(Common::Point(2, 8), -1, -1, 1);
+ if (_vm->isFlag(kGFUnk14) || _vm->isFlag(kGFSpringTaken)) {
+ _vm->_newSceneNum = 11;
+ } else {
+ _vm->setFlag(kGFSpringTaken);
+ _vm->_newSceneNum = 47;
+ }
+ break;
+
+ case kHS13BackToilet:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(5, 5), 6, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ case GRAB_CURSOR:
+ case TALK_CURSOR:
+ if (gnap._pos == Common::Point(5, 5)) {
+ _backToiletCtr = MIN(5, _backToiletCtr + 1);
+ gameSys.setAnimation(_backToiletCtr + 0xA3, gnap._id, 0);
+ gameSys.insertSequence(_backToiletCtr + 0xA3, gnap._id,
+ makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id,
+ kSeqScale | kSeqSyncWait, 0, 0, 0);
+ gnap._actionStatus = kAS13Wait;
+ gnap._sequenceId = _backToiletCtr + 0xA3;
+ gnap._idleFacing = kDirUpRight;
+ gnap._sequenceDatNum = 0;
+ } else {
+ gnap.walkTo(Common::Point(5, 5), 0, 0x107BB, 1);
+ gnap._actionStatus = kAS13BackToilet;
+ gnap._idleFacing = kDirUpRight;
+ }
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ break;
+
+ case kHS13FrontToilet:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(6, 7), 7, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ case GRAB_CURSOR:
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.walkTo(Common::Point(6, 7), 0, 0xA9, 5);
+ gnap._actionStatus = kAS13FrontToilet;
+ gnap._idleFacing = kDirBottomRight;
+ break;
+ }
+ }
+ break;
+
+ case kHS13Scribble:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(7, 7), 8, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.walkTo(Common::Point(7, 7), 0, 0x107BB, 1);
+ gnap._actionStatus = kAS13LookScribble;
+ gnap._idleFacing = kDirUpRight;
+ break;
+ case GRAB_CURSOR:
+ gnap.playScratchingHead();
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(Common::Point(7, 7), -1, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)), 1);
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ break;
+
+ case kHS13Urinal:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(8, 7), 9, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playSequence(gnap.getSequenceId(kGSDeflect, Common::Point(9, 6)));
+ gnap.walkTo(gnap._pos, 0, -1, 1);
+ gnap._actionStatus = kAS13Wait;
+ break;
+ case GRAB_CURSOR:
+ gnap.walkTo(Common::Point(8, 7), 0, -1, 1);
+ gnap._actionStatus = kAS13GrabUrinal;
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ break;
+
+ case kHS13Sink:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playSequence(gnap.getSequenceId(kGSDeflect, Common::Point(5, 9)));
+ gnap.walkTo(gnap._pos, 0, -1, 1);
+ gnap._actionStatus = kAS13Wait;
+ break;
+ case GRAB_CURSOR:
+ gnap.walkTo(Common::Point(4, 8), 0, 0x107B9, 1);
+ gnap._actionStatus = kAS13GrabSink;
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ break;
+
+ case kHS13WalkArea2:
+ case kHS13WalkArea3:
+ case kHS13WalkArea4:
+ case kHS13WalkArea5:
+ case kHS13WalkArea6:
+ case kHS13WalkArea7:
+ case kHS13WalkArea8:
+ case kHS13WalkArea9:
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ case kHS13WalkArea1:
+ // Nothing
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+ }
+
+ updateAnimations();
+
+ if (!_vm->_isLeavingScene) {
+ plat.updateIdleSequence();
+ if (plat._pos.y == 5 || plat._pos.y == 6)
+ plat.walkTo(Common::Point(-1, 7), -1, -1, 1);
+ if (gnap._actionStatus < 0)
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[4]) {
+ _vm->_timers[4] = _vm->getRandom(20) + 20;
+ switch (_vm->getRandom(5)) {
+ case 0:
+ _vm->playSound(0xD2, false);
+ break;
+ case 1:
+ _vm->playSound(0xD3, false);
+ break;
+ case 2:
+ _vm->playSound(0xD4, false);
+ break;
+ case 3:
+ _vm->playSound(0xD5, false);
+ break;
+ case 4:
+ _vm->playSound(0xD6, false);
+ break;
+ }
+ }
+ if (!_vm->_timers[5]) {
+ int newSoundId;
+ _vm->_timers[5] = _vm->getRandom(50) + 50;
+ switch (_vm->getRandom(7)) {
+ case 0:
+ newSoundId = 0xD7;
+ _vm->_timers[5] = 2 * _vm->getRandom(50) + 100;
+ break;
+ case 1:
+ case 2:
+ newSoundId = 0xCF;
+ break;
+ case 3:
+ case 4:
+ newSoundId = 0xD0;
+ break;
+ default:
+ newSoundId = 0xD1;
+ break;
+ }
+ if (newSoundId != currSoundId) {
+ _vm->playSound(newSoundId, false);
+ currSoundId = newSoundId;
+ }
+ }
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[4] = _vm->getRandom(20) + 20;
+ _vm->_timers[5] = _vm->getRandom(50) + 50;
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene13::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS13LeaveScene:
+ _vm->_sceneDone = true;
+ gnap._actionStatus = -1;
+ break;
+ case kAS13BackToilet:
+ _backToiletCtr = MIN(5, _backToiletCtr + 1);
+ gameSys.insertSequence(_backToiletCtr + 0xA3, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, 9, 0, 0, 0);
+ gnap._sequenceId = _backToiletCtr + 0xA3;
+ gnap._sequenceDatNum = 0;
+ gnap._actionStatus = -1;
+ break;
+ case kAS13FrontToilet:
+ _vm->_sceneDone = true;
+ _vm->_newSceneNum = 14;
+ break;
+ case kAS13LookScribble:
+ gnap._actionStatus = -1;
+ showScribble();
+ break;
+ case kAS13GrabSink:
+ gameSys.setAnimation(0xAB, 160, 0);
+ gameSys.insertSequence(0xAB, 160, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.removeSequence(0xAA, 256, true);
+ gnap._sequenceId = 0xAB;
+ gnap._id = 160;
+ gnap._idleFacing = kDirBottomRight;
+ gnap._sequenceDatNum = 0;
+ gnap._pos = Common::Point(4, 8);
+ _vm->_timers[2] = 360;
+ gnap._actionStatus = kAS13GrabSinkDone;
+ break;
+ case kAS13GrabSinkDone:
+ gameSys.insertSequence(0xAA, 256, 0, 0, kSeqNone, 0, 0, 0);
+ gnap._actionStatus = -1;
+ break;
+ case kAS13Wait:
+ gnap._actionStatus = -1;
+ break;
+ case kAS13GrabUrinal:
+ gameSys.setAnimation(0xA2, 120, 0);
+ gameSys.insertSequence(0xA2, 120, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0xA2;
+ gnap._id = 120;
+ gnap._idleFacing = kDirBottomLeft;
+ gnap._sequenceDatNum = 0;
+ gnap._pos = Common::Point(4, 6);
+ _vm->_timers[2] = 360;
+ gnap._actionStatus = kAS13Wait;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(1) == 2) {
+ gameSys.setAnimation(0, 0, 1);
+ _vm->_plat->_actionStatus = -1;
+ }
+}
+
+/*****************************************************************************/
+
+Scene14::Scene14(GnapEngine *vm) : Scene(vm) {
+}
+
+int Scene14::init() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ gameSys.setAnimation(0, 0, 0);
+ gameSys.setAnimation(0, 0, 1);
+ return 0x27;
+}
+
+void Scene14::updateHotspots() {
+ _vm->setHotspot(kHS14Platypus, 0, 0, 0, 0);
+ _vm->setHotspot(kHS14Exit, 0, 590, 799, 599, SF_EXIT_D_CURSOR);
+ _vm->setHotspot(kHS14Coin, 330, 390, 375, 440, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS14Toilet, 225, 250, 510, 500, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setDeviceHotspot(kHS14Device, -1, -1, -1, -1);
+ if (_vm->isFlag(kGFNeedleTaken))
+ _vm->_hotspots[kHS14Coin]._flags = SF_DISABLED;
+ _vm->_hotspotsCount = 5;
+}
+
+void Scene14::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ _vm->_largeSprite = nullptr;
+ _vm->queueInsertDeviceIcon();
+
+ if (!_vm->isFlag(kGFNeedleTaken))
+ gameSys.insertSequence(0x23, 10, 0, 0, kSeqNone, 0, 0, 0);
+
+ _vm->endSceneInit();
+
+ if (!_vm->isFlag(kGFNeedleTaken) && _vm->invHas(kItemTongs))
+ _vm->_largeSprite = gameSys.createSurface(1);
+
+ if (!_vm->isFlag(kGFNeedleTaken)) {
+ gameSys.insertSequence(0x24, 10, 0x23, 10, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x24;
+ _vm->_timers[2] = _vm->getRandom(40) + 50;
+ }
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS14Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS14Exit:
+ _vm->_sceneDone = true;
+ _vm->_newSceneNum = 13;
+ break;
+
+ case kHS14Coin:
+ if (_vm->_grabCursorSpriteIndex == kItemTongs) {
+ _vm->invAdd(kItemQuarter);
+ _vm->setFlag(kGFNeedleTaken);
+ _vm->setGrabCursorSprite(-1);
+ _vm->hideCursor();
+ gameSys.setAnimation(0x26, 10, 0);
+ gameSys.insertSequence(0x26, 10, gnap._sequenceId, 10, kSeqSyncWait, 0, 0, 0);
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ _vm->playSound(0x108E9, false);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ _vm->playSound(0x108E9, false);
+ break;
+ case GRAB_CURSOR:
+ gameSys.insertSequence(0x25, 10, gnap._sequenceId, 10, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x23, 10, 0x25, 10, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x23;
+ break;
+ case TALK_CURSOR:
+ _vm->playSound((_vm->getRandom(5) + 0x8D5) | 0x10000, false);
+ break;
+ case PLAT_CURSOR:
+ gameSys.insertSequence(0x107A8, 1, 0, 0, kSeqNone, 0, 900 - gnap._gridX, 576 - gnap._gridY);
+ break;
+ }
+ }
+ break;
+
+ case kHS14Toilet:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gameSys.insertSequence(0x107A8, 1, 0, 0, kSeqNone, 0, 900 - gnap._gridX, 576 - gnap._gridY);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ case GRAB_CURSOR:
+ _vm->playSound(0x108B1, false);
+ break;
+ case TALK_CURSOR:
+ _vm->playSound((_vm->getRandom(5) + 0x8D5) | 0x10000, false);
+ break;
+ case PLAT_CURSOR:
+ gameSys.insertSequence(0x107A8, 1, 0, 0, kSeqNone, 0, 900 - gnap._gridX, 576 - gnap._gridY);
+ break;
+ }
+ }
+ break;
+
+ default:
+ _vm->_mouseClickState._left = false;
+ break;
+ }
+
+ updateAnimations();
+ _vm->checkGameKeys();
+
+ if (!_vm->isFlag(kGFNeedleTaken) && !_vm->_timers[2]) {
+ gameSys.insertSequence(0x24, 10, gnap._sequenceId, 10, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x24;
+ _vm->_timers[2] = _vm->getRandom(40) + 50;
+ }
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+
+ if (_vm->_largeSprite)
+ _vm->deleteSurface(&_vm->_largeSprite);
+}
+
+void Scene14::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ gameSys.insertSpriteDrawItem(_vm->_largeSprite, 0, 0, 300);
+ gameSys.setAnimation(0x10843, 301, 1);
+ gameSys.insertSequence(0x10843, 301, 0x26, 10, kSeqSyncWait, 0, 0, 0);
+ }
+
+ if (gameSys.getAnimationStatus(1) == 2) {
+ gameSys.setAnimation(0, 0, 1);
+ _vm->_sceneDone = true;
+ _vm->_newSceneNum = 13;
+ _vm->_grabCursorSpriteIndex = kItemQuarter;
+ }
+}
+
+/*****************************************************************************/
+
+Scene15::Scene15(GnapEngine *vm) : Scene(vm) {
+ _nextRecordSequenceId = -1;
+ _currRecordSequenceId = -1;
+ _nextSlotSequenceId = -1;
+ _currSlotSequenceId = -1;
+ _nextUpperButtonSequenceId = -1;
+ _currUpperButtonSequenceId = -1;
+ _nextLowerButtonSequenceId = -1;
+ _currLowerButtonSequenceId = -1;
+}
+
+int Scene15::init() {
+ return 0xDD;
+}
+
+void Scene15::updateHotspots() {
+ _vm->setHotspot(kHS15Platypus, 0, 0, 0, 0, SF_DISABLED);
+ _vm->setHotspot(kHS15Exit, 50, 590, 750, 599, SF_EXIT_D_CURSOR);
+ _vm->setHotspot(kHS15Button1, 210, 425, 260, 475, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS15Button2, 280, 425, 325, 475, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS15Button3, 340, 425, 385, 475, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS15Button4, 400, 425, 445, 475, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS15Button5, 460, 425, 510, 475, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS15Button6, 520, 425, 560, 475, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS15ButtonA, 205, 480, 250, 535, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS15ButtonB, 270, 480, 320, 535, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS15ButtonC, 335, 480, 380, 535, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS15ButtonD, 395, 480, 445, 535, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS15ButtonE, 460, 480, 505, 535, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS15ButtonF, 515, 480, 560, 535, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS15CoinSlot, 585, 475, 620, 535, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS15PlayButton, 622, 431, 650, 482, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setDeviceHotspot(kHS15Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 17;
+}
+
+void Scene15::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ _currSlotSequenceId = -1;
+ _currUpperButtonSequenceId = -1;
+ _currLowerButtonSequenceId = -1;
+ _nextSlotSequenceId = -1;
+ _nextUpperButtonSequenceId = -1;
+ _nextLowerButtonSequenceId = -1;
+ _currRecordSequenceId = 0xD5;
+ _nextRecordSequenceId = -1;
+
+ gameSys.setAnimation(0xD5, 1, 0);
+ gameSys.insertSequence(_currRecordSequenceId, 1, 0, 0, kSeqNone, 0, 0, 0);
+
+ _vm->queueInsertDeviceIcon();
+
+ _vm->endSceneInit();
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->_hotspots[kHS15Platypus].clearRect();
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS15Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS15Exit:
+ _vm->_newSceneNum = 12;
+ _vm->_isLeavingScene = true;
+ break;
+
+ case kHS15CoinSlot:
+ if (_vm->_grabCursorSpriteIndex == kItemQuarter || _vm->_grabCursorSpriteIndex == kItemQuarterWithHole) {
+ _nextSlotSequenceId = 0xDC; // Insert coin
+ } else if (_vm->_grabCursorSpriteIndex == kItemDiceQuarterHole) {
+ _nextSlotSequenceId = 0xDB;
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gameSys.insertSequence(0x107A8, 1, 0, 0, kSeqNone, 0, 900 - gnap._gridX, 576 - gnap._gridY);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ case GRAB_CURSOR:
+ _vm->playSound(0x108E9, false);
+ break;
+ case TALK_CURSOR:
+ _vm->playSound((_vm->getRandom(5) + 0x8D5) | 0x10000, false);
+ break;
+ case PLAT_CURSOR:
+ gameSys.insertSequence(0x107A8, 1, 0, 0, kSeqNone, 0, 900 - gnap._gridX, 576 - gnap._gridY);
+ break;
+ }
+ }
+ break;
+
+ case kHS15PlayButton:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gameSys.insertSequence(0x107A8, 1, 0, 0, kSeqNone, 0, 900 - gnap._gridX, 576 - gnap._gridY);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ if (_vm->isFlag(kGFGnapControlsToyUFO) || _vm->isFlag(kGFUnk13))
+ _vm->playSound(0x108E9, false);
+ else
+ _nextSlotSequenceId = 0xDA;
+ break;
+ case GRAB_CURSOR:
+ if (_vm->isFlag(kGFGnapControlsToyUFO) || _vm->isFlag(kGFUnk13))
+ _nextSlotSequenceId = 0xD9;
+ else
+ _nextSlotSequenceId = 0xDA;
+ break;
+ case TALK_CURSOR:
+ _vm->playSound((_vm->getRandom(5) + 0x8D5) | 0x10000, false);
+ break;
+ case PLAT_CURSOR:
+ gameSys.insertSequence(0x107A8, 1, 0, 0, kSeqNone, 0, 900 - gnap._gridX, 576 - gnap._gridY);
+ break;
+ }
+ }
+ break;
+
+ case kHS15Button1:
+ case kHS15Button2:
+ case kHS15Button3:
+ case kHS15Button4:
+ case kHS15Button5:
+ case kHS15Button6:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gameSys.insertSequence(0x107A8, 1, 0, 0, kSeqNone, 0, 900 - gnap._gridX, 576 - gnap._gridY);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ _vm->playSound(0x108E9, false);
+ break;
+ case GRAB_CURSOR:
+ _nextUpperButtonSequenceId = _vm->_sceneClickedHotspot + 0xC5;
+ break;
+ case TALK_CURSOR:
+ _vm->playSound((_vm->getRandom(5) + 0x8D5) | 0x10000, false);
+ break;
+ case PLAT_CURSOR:
+ gameSys.insertSequence(0x107A8, 1, 0, 0, kSeqNone, 0, 900 - gnap._gridX, 576 - gnap._gridY);
+ break;
+ }
+ }
+ break;
+
+ case kHS15ButtonA:
+ case kHS15ButtonB:
+ case kHS15ButtonC:
+ case kHS15ButtonD:
+ case kHS15ButtonE:
+ case kHS15ButtonF:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gameSys.insertSequence(0x107A8, 1, 0, 0, kSeqNone, 0, 900 - gnap._gridX, 576 - gnap._gridY);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ _vm->playSound(0x108E9, false);
+ break;
+ case GRAB_CURSOR:
+ _nextLowerButtonSequenceId = _vm->_sceneClickedHotspot + 0xC5;
+ break;
+ case TALK_CURSOR:
+ _vm->playSound((_vm->getRandom(5) + 0x8D5) | 0x10000, false);
+ break;
+ case PLAT_CURSOR:
+ gameSys.insertSequence(0x107A8, 1, 0, 0, kSeqNone, 0, 900 - gnap._gridX, 576 - gnap._gridY);
+ break;
+ }
+ }
+ break;
+
+ default:
+ _vm->_mouseClickState._left = false;
+ break;
+
+ }
+
+ updateAnimations();
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene15::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ if (_vm->_isLeavingScene) {
+ _vm->_sceneDone = true;
+ } else if (_nextSlotSequenceId != -1) {
+ gameSys.setAnimation(_nextSlotSequenceId, 1, 0);
+ gameSys.insertSequence(_nextSlotSequenceId, 1, 0, 0, kSeqNone, 0, 0, 0);
+ _currSlotSequenceId = _nextSlotSequenceId;
+ _nextSlotSequenceId = -1;
+ switch (_currSlotSequenceId) {
+ case 0xDC:
+ if (_vm->_grabCursorSpriteIndex == kItemQuarter) {
+ _vm->invRemove(kItemQuarter);
+ } else {
+ _vm->invRemove(kItemQuarterWithHole);
+ _vm->setFlag(kGFUnk13);
+ }
+ _vm->setGrabCursorSprite(-1);
+ break;
+ case 0xDB:
+ _vm->setFlag(kGFUnk14);
+ _vm->setGrabCursorSprite(-1);
+ _nextSlotSequenceId = 0xD8;
+ break;
+ case 0xD9:
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ _vm->clearFlag(kGFGnapControlsToyUFO);
+ _vm->invAdd(kItemQuarter);
+ _vm->_newGrabCursorSpriteIndex = kItemQuarter;
+ } else if (_vm->isFlag(kGFUnk13)) {
+ _vm->clearFlag(kGFUnk13);
+ _vm->invAdd(kItemQuarterWithHole);
+ _vm->_newGrabCursorSpriteIndex = kItemQuarterWithHole;
+ }
+ _vm->_newSceneNum = 12;
+ _vm->_isLeavingScene = true;
+ break;
+ case 0xD8:
+ case 0xDA:
+ if (_currUpperButtonSequenceId != -1) {
+ gameSys.removeSequence(_currUpperButtonSequenceId, 1, true);
+ _currUpperButtonSequenceId = -1;
+ }
+ if (_currLowerButtonSequenceId != -1) {
+ gameSys.removeSequence(_currLowerButtonSequenceId, 1, true);
+ _currLowerButtonSequenceId = -1;
+ }
+ break;
+ }
+ } else if (_nextRecordSequenceId != -1) {
+ gameSys.setAnimation(_nextRecordSequenceId, 1, 0);
+ gameSys.insertSequence(_nextRecordSequenceId, 1, _currRecordSequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ _currRecordSequenceId = _nextRecordSequenceId;
+ _nextRecordSequenceId = -1;
+ if (_currRecordSequenceId == 0xD3) {
+ _vm->invRemove(kItemDiceQuarterHole);
+ _vm->_newSceneNum = 16;
+ _vm->_isLeavingScene = true;
+ }
+ gameSys.removeSequence(_currUpperButtonSequenceId, 1, true);
+ _currUpperButtonSequenceId = -1;
+ gameSys.removeSequence(_currLowerButtonSequenceId, 1, true);
+ _currLowerButtonSequenceId = -1;
+ } else if (_nextUpperButtonSequenceId != -1) {
+ gameSys.setAnimation(_nextUpperButtonSequenceId, 1, 0);
+ if (_currUpperButtonSequenceId == -1)
+ gameSys.insertSequence(_nextUpperButtonSequenceId, 1, 0, 0, kSeqNone, 0, 0, 0);
+ else
+ gameSys.insertSequence(_nextUpperButtonSequenceId, 1, _currUpperButtonSequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ _currUpperButtonSequenceId = _nextUpperButtonSequenceId;
+ _nextUpperButtonSequenceId = -1;
+ if (_currLowerButtonSequenceId != -1 && _vm->isFlag(kGFUnk14)) {
+ if (_currUpperButtonSequenceId == 0xCC && _currLowerButtonSequenceId == 0xCE)
+ _nextRecordSequenceId = 0xD3;
+ else
+ _nextRecordSequenceId = 0xD4;
+ }
+ } else if (_nextLowerButtonSequenceId != -1) {
+ gameSys.setAnimation(_nextLowerButtonSequenceId, 1, 0);
+ if (_currLowerButtonSequenceId == -1)
+ gameSys.insertSequence(_nextLowerButtonSequenceId, 1, 0, 0, kSeqNone, 0, 0, 0);
+ else
+ gameSys.insertSequence(_nextLowerButtonSequenceId, 1, _currLowerButtonSequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ _currLowerButtonSequenceId = _nextLowerButtonSequenceId;
+ _nextLowerButtonSequenceId = -1;
+ if (_currUpperButtonSequenceId != -1 && _vm->isFlag(kGFUnk14)) {
+ if (_currUpperButtonSequenceId == 0xCC && _currLowerButtonSequenceId == 0xCE)
+ _nextRecordSequenceId = 0xD3;
+ else
+ _nextRecordSequenceId = 0xD4;
+ }
+ }
+ }
+}
+
+/*****************************************************************************/
+
+Scene17::Scene17(GnapEngine *vm) : Scene(vm) {
+ _platTryGetWrenchCtr = 0;
+ _wrenchCtr = 2;
+ _nextCarWindowSequenceId = -1;
+ _nextWrenchSequenceId = -1;
+ _canTryGetWrench = true;
+ _platPhoneCtr = 0;
+ _nextPhoneSequenceId = -1;
+ _currPhoneSequenceId = -1;
+ _currWrenchSequenceId = -1;
+ _currCarWindowSequenceId = -1;
+}
+
+int Scene17::init() {
+ return 0x263;
+}
+
+void Scene17::updateHotspots() {
+ _vm->setHotspot(kHS17Platypus, 1, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS17Phone1, 61, 280, 97, 322, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 1, 7);
+ _vm->setHotspot(kHS17Phone2, 80, 204, 178, 468, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 1, 7);
+ _vm->setHotspot(kHS17ExitGrubCity, 196, 207, 280, 304, SF_EXIT_U_CURSOR, 3, 5);
+ _vm->setHotspot(kHS17ExitToyStore, 567, 211, 716, 322, SF_EXIT_U_CURSOR, 5, 6);
+ _vm->setHotspot(kHS17Wrench, 586, 455, 681, 547, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 5, 7);
+ _vm->setHotspot(kHS17WalkArea1, 0, 0, 800, 434);
+ _vm->setHotspot(kHS17WalkArea2, 541, 0, 800, 600);
+ _vm->setHotspot(kHS17WalkArea3, 0, 204, 173, 468);
+ _vm->setDeviceHotspot(kHS17Device, -1, -1, -1, -1);
+ if (_vm->isFlag(kGFGrassTaken))
+ _vm->_hotspots[kHS17Wrench]._flags = SF_NONE;
+ if (_vm->isFlag(kGFPlatypusTalkingToAssistant)) {
+ _vm->_hotspots[kHS17Device]._flags = SF_DISABLED;
+ _vm->_hotspots[kHS17Platypus]._flags = SF_DISABLED;
+ }
+ _vm->_hotspotsCount = 10;
+}
+
+void Scene17::update() {
+ _vm->gameUpdateTick();
+ _vm->updateMouseCursor();
+ _vm->updateGrabCursorSprite(0, 0);
+ if (_vm->_mouseClickState._left) {
+ _vm->_gnap->walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+}
+
+void Scene17::platHangUpPhone() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ int savedGnapActionStatus = gnap._actionStatus;
+
+ if (plat._actionStatus == kAS17PlatPhoningAssistant) {
+ gnap._actionStatus = kAS17PlatHangUpPhone;
+ _vm->updateMouseCursor();
+ _platPhoneCtr = 0;
+ plat._actionStatus = -1;
+ gameSys.setAnimation(0x257, 254, 4);
+ gameSys.insertSequence(0x257, 254, _currPhoneSequenceId, 254, kSeqSyncExists, 0, 0, 0);
+ while (gameSys.getAnimationStatus(4) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+ gameSys.setAnimation(0x25B, plat._id, 1);
+ gameSys.insertSequence(0x25B, plat._id, plat._sequenceId | (plat._sequenceDatNum << 16), plat._id, kSeqSyncWait, 0, 0, 0);
+ plat._sequenceId = 0x25B;
+ plat._sequenceDatNum = 0;
+ _currPhoneSequenceId = -1;
+ _nextPhoneSequenceId = -1;
+ _vm->clearFlag(kGFPlatypusTalkingToAssistant);
+ while (gameSys.getAnimationStatus(1) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+ gnap._actionStatus = savedGnapActionStatus;
+ _vm->updateMouseCursor();
+ }
+ updateHotspots();
+}
+
+void Scene17::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->playSound(0x10940, true);
+ _vm->startSoundTimerA(8);
+ _vm->_sceneWaiting = false;
+ _vm->_timers[4] = _vm->getRandom(100) + 200;
+ _vm->_timers[3] = 200;
+ _vm->_timers[5] = _vm->getRandom(30) + 80;
+ _vm->_timers[6] = _vm->getRandom(30) + 200;
+ _vm->_timers[7] = _vm->getRandom(100) + 100;
+
+ if (_vm->isFlag(kGFTruckKeysUsed)) {
+ gameSys.insertSequence(0x25F, 20, 0, 0, kSeqNone, 0, 0, 0);
+ } else {
+ if (_vm->_s18GarbageCanPos >= 8) {
+ gameSys.insertSequence(0x260, 20, 0, 0, kSeqNone, 0, 97, 1);
+ } else if (_vm->_s18GarbageCanPos >= 6) {
+ gameSys.insertSequence(0x260, 20, 0, 0, kSeqNone, 0, 68, 2);
+ } else if (_vm->_s18GarbageCanPos >= 5) {
+ gameSys.insertSequence(0x260, 20, 0, 0, kSeqNone, 0, 23, -1);
+ } else if (_vm->_s18GarbageCanPos >= 4) {
+ gameSys.insertSequence(0x260, 20, 0, 0, kSeqNone, 0, -11, -5);
+ } else {
+ gameSys.insertSequence(0x260, 20, 0, 0, kSeqNone, 0, -54, -8);
+ }
+ }
+
+ if (_vm->isFlag(kGFGroceryStoreHatTaken))
+ gameSys.insertSequence(0x262, 1, 0, 0, kSeqNone, 0, 0, 0);
+
+ _vm->queueInsertDeviceIcon();
+
+ if (_vm->isFlag(kGFGrassTaken))
+ _currWrenchSequenceId = 0x22D;
+ else
+ _currWrenchSequenceId = 0x22F;
+
+ _currCarWindowSequenceId = 0x244;
+
+ if (_vm->isFlag(kGFUnk14))
+ gameSys.insertSequence(0x261, 1, 0, 0, kSeqNone, 0, 0, 0);
+
+ gameSys.setAnimation(_currWrenchSequenceId, 40, 2);
+ gameSys.insertSequence(_currWrenchSequenceId, 40, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (_vm->isFlag(kGFGrassTaken)) {
+ gameSys.setAnimation(0, 0, 3);
+ } else {
+ gameSys.setAnimation(_currCarWindowSequenceId, 40, 3);
+ gameSys.insertSequence(_currCarWindowSequenceId, 40, 0, 0, kSeqNone, 0, 0, 0);
+ }
+
+ _canTryGetWrench = true;
+
+ if (_vm->isFlag(kGFUnk18))
+ gameSys.insertSequence(0x24F, 100, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (_vm->_prevSceneNum == 53 || _vm->_prevSceneNum == 18 || _vm->_prevSceneNum == 20 || _vm->_prevSceneNum == 19) {
+ if (_vm->_prevSceneNum == 20) {
+ gnap.initPos(4, 6, kDirBottomRight);
+ plat.initPos(5, 6, kDirIdleLeft);
+ _vm->endSceneInit();
+ plat.walkTo(Common::Point(5, 9), -1, 0x107C2, 1);
+ gnap.walkTo(Common::Point(4, 8), -1, 0x107B9, 1);
+ } else if (_vm->isFlag(kGFUnk27)) {
+ gnap.initPos(3, 9, kDirUpLeft);
+ plat._pos = _vm->_hotspotsWalkPos[2];
+ plat._id = 20 * _vm->_hotspotsWalkPos[2].y;
+ gameSys.insertSequence(0x25A, 20 * _vm->_hotspotsWalkPos[2].y, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.insertSequence(0x257, 254, 0, 0, kSeqNone, 0, 0, 0);
+ plat._sequenceId = 0x25A;
+ plat._sequenceDatNum = 0;
+ _vm->endSceneInit();
+ _vm->clearFlag(kGFSpringTaken);
+ _vm->clearFlag(kGFUnk16);
+ plat._actionStatus = kAS17PlatPhoningAssistant;
+ platHangUpPhone();
+ gameSys.setAnimation(0, 0, 4);
+ _vm->clearFlag(kGFPlatypusTalkingToAssistant);
+ _vm->clearFlag(kGFUnk27);
+ updateHotspots();
+ } else if (_vm->isFlag(kGFUnk25)) {
+ _vm->clearFlag(kGFSpringTaken);
+ _vm->clearFlag(kGFUnk16);
+ plat.initPos(7, 9, kDirIdleLeft);
+ gnap._pos = _vm->_hotspotsWalkPos[2];
+ gnap._id = 20 * _vm->_hotspotsWalkPos[2].y;
+ gameSys.insertSequence(601, 20 * _vm->_hotspotsWalkPos[2].y, 0, 0, kSeqNone, 0, 0, 0);
+ gnap._sequenceDatNum = 0;
+ gnap._sequenceId = 601;
+ gnap._actionStatus = kAS17GnapHangUpPhone;
+ _vm->clearFlag(kGFUnk25);
+ gameSys.insertSequence(0x251, 254, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->endSceneInit();
+ gameSys.setAnimation(0x257, 254, 0);
+ gameSys.insertSequence(0x257, 254, 0x251, 254, kSeqSyncWait, 0, 0, 0);
+ } else if (_vm->isFlag(kGFPlatypusTalkingToAssistant)) {
+ _vm->clearFlag(kGFSpringTaken);
+ _vm->clearFlag(kGFUnk16);
+ _vm->_sceneWaiting = true;
+ gnap.initPos(3, 9, kDirUpLeft);
+ plat._pos = _vm->_hotspotsWalkPos[2];
+ plat._id = 20 * _vm->_hotspotsWalkPos[2].y;
+ _currPhoneSequenceId = 0x251;
+ gameSys.insertSequence(0x25A, 20 * _vm->_hotspotsWalkPos[2].y, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.insertSequence(_currPhoneSequenceId, 254, 0, 0, kSeqNone, 0, 0, 0);
+ plat._sequenceId = 0x25A;
+ plat._sequenceDatNum = 0;
+ _vm->endSceneInit();
+ gameSys.setAnimation(_currPhoneSequenceId, 254, 1);
+ plat._actionStatus = kAS17PlatPhoningAssistant;
+ updateHotspots();
+ } else if (_vm->_prevSceneNum == 18) {
+ gnap.initPos(6, 6, kDirBottomRight);
+ plat.initPos(5, 6, kDirIdleLeft);
+ _vm->endSceneInit();
+ plat.walkTo(Common::Point(5, 9), -1, 0x107C2, 1);
+ gnap.walkTo(Common::Point(4, 8), -1, 0x107B9, 1);
+ } else {
+ if (_vm->isFlag(kGFSpringTaken)) {
+ gnap.initPos(_vm->_hotspotsWalkPos[2].x, _vm->_hotspotsWalkPos[2].y, kDirBottomRight);
+ plat.initPos(1, 9, kDirIdleLeft);
+ _vm->endSceneInit();
+ } else {
+ gnap.initPos(3, 7, kDirBottomRight);
+ plat.initPos(1, 7, kDirIdleLeft);
+ _vm->endSceneInit();
+ }
+ _vm->clearFlag(kGFSpringTaken);
+ _vm->clearFlag(kGFUnk16);
+ _vm->endSceneInit();
+ }
+ } else {
+ gnap._pos = Common::Point(3, 6);
+ gnap._id = 120;
+ gnap._sequenceId = 0x23D;
+ gnap._sequenceDatNum = 0;
+ gnap._idleFacing = kDirBottomRight;
+ gameSys.insertSequence(makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, 0, 0, kSeqNone, 0, 0, 0);
+ plat._pos = Common::Point(-1, 8);
+ plat._id = 160;
+ gameSys.insertSequence(0x241, 160, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.insertSequence(0x107C1, plat._id, 0x241, plat._id,
+ kSeqScale | kSeqSyncWait, 0, 75 * plat._pos.x - plat._gridX, 48 * plat._pos.y - plat._gridY);
+ gameSys.insertSequence(0x22C, 2, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->delayTicksA(2, 9);
+ _vm->endSceneInit();
+ plat._sequenceId = 0x7C1;
+ plat._sequenceDatNum = 1;
+ plat._idleFacing = kDirBottomRight;
+ plat.walkTo(Common::Point(2, 9), -1, 0x107C2, 1);
+ }
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS17Device:
+ if (gnap._actionStatus < 0 || gnap._actionStatus == 3) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS17Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemJoint) {
+ if (_vm->isFlag(kGFGrassTaken)) {
+ gnap.useJointOnPlatypus();
+ } else {
+ gnap.useDeviceOnPlatypus();
+ plat.walkTo(_vm->_hotspotsWalkPos[6], 1, 0x107C2, 1);
+ gnap.walkTo(_vm->_hotspotsWalkPos[6] + Common::Point(1, 0), 0, 0x107BA, 1);
+ plat._actionStatus = kAS17GetWrench1;
+ gnap._actionStatus = kAS17GetWrench1;
+ _vm->_timers[5] = _vm->getRandom(30) + 80;
+ _vm->setGrabCursorSprite(-1);
+ _vm->invRemove(kItemJoint);
+ }
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playScratchingHead(plat._pos);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ case GRAB_CURSOR:
+ gnap.playScratchingHead(plat._pos);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS17Wrench:
+ if (gnap._actionStatus < 0) {
+ if (_vm->isFlag(kGFGrassTaken)) {
+ gnap.playImpossible();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot], 8, 7);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ case GRAB_CURSOR:
+ gnap.playScratchingHead(Common::Point(8, 7));
+ break;
+ case TALK_CURSOR:
+ gnap.playImpossible();
+ break;
+ case PLAT_CURSOR:
+ if (_canTryGetWrench) {
+ platHangUpPhone();
+ gnap.useDeviceOnPlatypus();
+ plat.walkTo(_vm->_hotspotsWalkPos[6] + Common::Point(1, 0), 1, 0x107C2, 1);
+ plat._actionStatus = kAS17TryGetWrench;
+ gnap._actionStatus = kAS17TryGetWrench;
+ _vm->_timers[5] = _vm->getRandom(30) + 80;
+ } else
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS17Phone1:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemDiceQuarterHole) {
+ gnap.walkTo(_vm->_hotspotsWalkPos[2], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS17PutCoinIntoPhone;
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[2], 1, 3);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(1, 3));
+ break;
+ case GRAB_CURSOR:
+ if (_vm->isFlag(kGFUnk18)) {
+ platHangUpPhone();
+ gnap.walkTo(gnap._pos, 0, gnap.getSequenceId(kGSIdle, _vm->_hotspotsWalkPos[2]) | 0x10000, 1);
+ gnap._actionStatus = kAS17GetCoinFromPhone;
+ } else
+ gnap.playImpossible();
+ break;
+ case TALK_CURSOR:
+ gnap.playImpossible();
+ break;
+ case PLAT_CURSOR:
+ if (_vm->isFlag(kGFUnk18)) {
+ platHangUpPhone();
+ _vm->_isLeavingScene = true;
+ gnap.useDeviceOnPlatypus();
+ plat._idleFacing = kDirUpLeft;
+ plat.walkTo(_vm->_hotspotsWalkPos[2], 1, 0x107C2, 1);
+ _vm->setFlag(kGFUnk16);
+ plat._actionStatus = kAS17PlatUsePhone;
+ gnap._actionStatus = kAS17PlatUsePhone;
+ } else
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS17Phone2:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemDiceQuarterHole) {
+ gnap.walkTo(_vm->_hotspotsWalkPos[2], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS17PutCoinIntoPhone;
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[2], 1, 3);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(1, 3));
+ break;
+ case GRAB_CURSOR:
+ if (_vm->isFlag(kGFUnk18)) {
+ platHangUpPhone();
+ _vm->_isLeavingScene = true;
+ gnap._idleFacing = kDirUpLeft;
+ gnap.walkTo(_vm->_hotspotsWalkPos[2], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS17GnapUsePhone;
+ _vm->setFlag(kGFSpringTaken);
+ } else
+ gnap.playImpossible();
+ break;
+ case TALK_CURSOR:
+ gnap.playImpossible();
+ break;
+ case PLAT_CURSOR:
+ if (_vm->isFlag(kGFUnk18)) {
+ platHangUpPhone();
+ _vm->_isLeavingScene = true;
+ gnap.useDeviceOnPlatypus();
+ plat._idleFacing = kDirUpLeft;
+ plat.walkTo(_vm->_hotspotsWalkPos[2], 1, 0x107C2, 1);
+ _vm->setFlag(kGFUnk16);
+ plat._actionStatus = kAS17PlatUsePhone;
+ gnap._actionStatus = kAS17PlatUsePhone;
+ } else
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS17ExitToyStore:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 18;
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[5], 0, 0x107BB, 1);
+ gnap._actionStatus = kAS17LeaveScene;
+ if (plat._actionStatus != kAS17PlatPhoningAssistant)
+ plat.walkTo(_vm->_hotspotsWalkPos[5] + Common::Point(-1, 0), -1, 0x107C2, 1);
+ }
+ break;
+
+ case kHS17ExitGrubCity:
+ if (gnap._actionStatus < 0) {
+ platHangUpPhone();
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 20;
+ gnap._idleFacing = kDirUpLeft;
+ gnap.walkTo(_vm->_hotspotsWalkPos[3], 0, 0x107BC, 1);
+ gnap._actionStatus = kAS17LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[3] + Common::Point(1, 0), -1, 0x107C2, 1);
+ }
+ break;
+
+ case kHS17WalkArea1:
+ case kHS17WalkArea2:
+ case kHS17WalkArea3:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left && gnap._actionStatus < 0) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = 0;
+ }
+ break;
+ }
+
+ updateAnimations();
+
+ if (!_vm->isSoundPlaying(0x10940))
+ _vm->playSound(0x10940, true);
+
+ if (!_vm->_isLeavingScene) {
+ if (plat._actionStatus < 0)
+ plat.updateIdleSequence2();
+ gnap.updateIdleSequence2();
+ if (!_vm->_timers[4]) {
+ _vm->_timers[4] = _vm->getRandom(100) + 200;
+ if (gnap._actionStatus < 0 && plat._actionStatus < 0)
+ gameSys.insertSequence(0x22B, 21, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ if (!_vm->_timers[7]) {
+ _vm->_timers[7] = _vm->getRandom(100) + 100;
+ if (gnap._actionStatus < 0 && plat._actionStatus < 0) {
+ switch (_vm->getRandom(3)) {
+ case 0:
+ gameSys.insertSequence(0x25C, 255, 0, 0, kSeqNone, 0, 0, 0);
+ break;
+ case 1:
+ gameSys.insertSequence(0x25D, 255, 0, 0, kSeqNone, 0, 0, 0);
+ break;
+ case 2:
+ gameSys.insertSequence(0x25E, 255, 0, 0, kSeqNone, 0, 0, 0);
+ break;
+ }
+ }
+ }
+ if (plat._actionStatus < 0 && !_vm->_timers[5]) {
+ _vm->_timers[5] = _vm->getRandom(30) + 80;
+ if (_vm->isFlag(kGFGrassTaken) && _nextWrenchSequenceId == -1) {
+ _nextWrenchSequenceId = 0x236;
+ } else if (_canTryGetWrench) {
+ switch (_vm->getRandom(6)) {
+ case 0:
+ _nextWrenchSequenceId = 0x231;
+ break;
+ case 1:
+ _nextWrenchSequenceId = 0x232;
+ break;
+ case 2:
+ case 3:
+ _nextWrenchSequenceId = 0x23C;
+ break;
+ case 4:
+ case 5:
+ _nextWrenchSequenceId = 0x22E;
+ break;
+ }
+ } else {
+ --_wrenchCtr;
+ if (_wrenchCtr) {
+ switch (_vm->getRandom(6)) {
+ case 0:
+ _nextWrenchSequenceId = 0x237;
+ break;
+ case 1:
+ _nextWrenchSequenceId = 0x238;
+ break;
+ case 2:
+ _nextWrenchSequenceId = 0x239;
+ break;
+ case 3:
+ _nextWrenchSequenceId = 0x23A;
+ break;
+ case 4:
+ _nextWrenchSequenceId = 0x23B;
+ break;
+ case 5:
+ _nextWrenchSequenceId = 0x235;
+ break;
+ }
+ } else {
+ _wrenchCtr = 2;
+ _nextWrenchSequenceId = 0x235;
+ }
+ }
+ }
+ if (!_vm->_timers[6]) {
+ _vm->_timers[6] = _vm->getRandom(30) + 200;
+ if (_nextCarWindowSequenceId == -1 && !_vm->isFlag(kGFGrassTaken))
+ _nextCarWindowSequenceId = 0x246;
+ }
+ _vm->playSoundA();
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene17::updateAnimations() {
+ static const int kPlatPhoneSequenceIds[] = {
+ 0x251, 0x252, 0x253, 0x254, 0x255, 0x256, 0x257
+ };
+
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS17GetWrench1:
+ gnap._actionStatus = kAS17GetWrenchGnapReady;
+ break;
+ case kAS17GetCoinFromPhone:
+ gnap.playPullOutDevice(Common::Point(1, 3));
+ gnap.playUseDevice();
+ gameSys.setAnimation(0x250, 100, 0);
+ gameSys.insertSequence(0x250, 100, 591, 100, kSeqSyncWait, 0, 0, 0);
+ _vm->invAdd(kItemDiceQuarterHole);
+ _vm->clearFlag(kGFUnk18);
+ gnap._actionStatus = kAS17GetCoinFromPhoneDone;
+ break;
+ case kAS17GetCoinFromPhoneDone:
+ _vm->setGrabCursorSprite(kItemDiceQuarterHole);
+ gnap._actionStatus = -1;
+ break;
+ case kAS17PutCoinIntoPhone:
+ gameSys.setAnimation(0x24C, gnap._id, 0);
+ gameSys.insertSequence(0x24C, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceDatNum = 0;
+ gnap._sequenceId = 0x24C;
+ _vm->invRemove(kItemDiceQuarterHole);
+ _vm->setGrabCursorSprite(-1);
+ _vm->setFlag(kGFUnk18);
+ gnap._actionStatus = kAS17PutCoinIntoPhoneDone;
+ break;
+ case kAS17PutCoinIntoPhoneDone:
+ gameSys.insertSequence(0x24F, 100, 0, 0, kSeqNone, 0, 0, 0);
+ gnap._actionStatus = -1;
+ break;
+ case kAS17GnapUsePhone:
+ gameSys.setAnimation(0x24D, gnap._id, 0);
+ gameSys.insertSequence(0x24D, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._actionStatus = kAS17LeaveScene;
+ _vm->_newSceneNum = 53;
+ break;
+ case kAS17GnapHangUpPhone:
+ gameSys.insertSequence(0x258, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceDatNum = 0;
+ gnap._sequenceId = 0x258;
+ gnap._actionStatus = -1;
+ break;
+ case kAS17LeaveScene:
+ _vm->_sceneDone = true;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(1) == 2) {
+ gameSys.setAnimation(0, 0, 1);
+ switch (plat._actionStatus) {
+ case kAS17TryGetWrench:
+ plat._actionStatus = -1;
+ ++_platTryGetWrenchCtr;
+ if (_platTryGetWrenchCtr % 2 != 0)
+ _nextWrenchSequenceId = 0x233;
+ else
+ _nextWrenchSequenceId = 0x234;
+ _canTryGetWrench = false;
+ break;
+ case kAS17GetWrench1:
+ _nextWrenchSequenceId = 0x230;
+ break;
+ case kAS17GetWrench2:
+ _nextCarWindowSequenceId = 0x249;
+ break;
+ case kAS17GetWrenchDone:
+ plat._actionStatus = -1;
+ _vm->invAdd(kItemWrench);
+ _vm->setGrabCursorSprite(kItemWrench);
+ break;
+ case kAS17PlatUsePhone:
+ gameSys.setAnimation(0x24E, plat._id, 1);
+ gameSys.insertSequence(0x24E, plat._id, plat._sequenceId | (plat._sequenceDatNum << 16), plat._id, kSeqSyncWait, 0, 0, 0);
+ plat._sequenceDatNum = 0;
+ plat._sequenceId = 0x24E;
+ plat._actionStatus = kAS17LeaveScene;
+ _vm->_newSceneNum = 53;
+ break;
+ case kAS17PlatPhoningAssistant:
+ ++_platPhoneCtr;
+ if (_platPhoneCtr >= 7) {
+ _platPhoneCtr = 0;
+ _nextPhoneSequenceId = -1;
+ _currPhoneSequenceId = -1;
+ gameSys.insertSequence(0x25B, plat._id, 0x25A, plat._id, kSeqSyncWait, 0, 0, 0);
+ plat._sequenceDatNum = 0;
+ plat._sequenceId = 0x25B;
+ plat._actionStatus = -1;
+ _vm->clearFlag(kGFPlatypusTalkingToAssistant);
+ _vm->_sceneWaiting = false;
+ updateHotspots();
+ } else {
+ _nextPhoneSequenceId = kPlatPhoneSequenceIds[_platPhoneCtr];
+ gameSys.setAnimation(_nextPhoneSequenceId, 254, 1);
+ gameSys.insertSequence(_nextPhoneSequenceId, 254, _currPhoneSequenceId, 254, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x25A, plat._id, 0x25A, plat._id, kSeqSyncWait, 0, 0, 0);
+ plat._sequenceDatNum = 0;
+ plat._sequenceId = 0x25A;
+ _currPhoneSequenceId = _nextPhoneSequenceId;
+ }
+ break;
+ case kAS17LeaveScene:
+ _vm->_sceneDone = true;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(2) == 2) {
+ switch (_nextWrenchSequenceId) {
+ case 0x233:
+ gnap._actionStatus = -1;
+ gameSys.insertSequence(0x243, plat._id,
+ plat._sequenceId | (plat._sequenceDatNum << 16), plat._id,
+ kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(_nextWrenchSequenceId, 40, _currWrenchSequenceId, 40, kSeqSyncWait, 0, 0, 0);
+ _currWrenchSequenceId = _nextWrenchSequenceId;
+ _nextWrenchSequenceId = -1;
+ plat._sequenceId = 0x243;
+ plat._sequenceDatNum = 0;
+ gameSys.setAnimation(0x243, plat._id, 1);
+ break;
+ case 0x234:
+ gnap._actionStatus = -1;
+ gameSys.insertSequence(0x242, plat._id,
+ plat._sequenceId | (plat._sequenceDatNum << 16), plat._id,
+ kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(_nextWrenchSequenceId, 40, _currWrenchSequenceId, 40, kSeqSyncWait, 0, 0, 0);
+ _currWrenchSequenceId = _nextWrenchSequenceId;
+ _nextWrenchSequenceId = -1;
+ plat._sequenceId = 0x242;
+ plat._sequenceDatNum = 0;
+ gameSys.setAnimation(0x242, plat._id, 1);
+ break;
+ case 0x231:
+ if (_vm->getRandom(2) != 0)
+ _nextCarWindowSequenceId = 0x245;
+ else
+ _nextCarWindowSequenceId = 0x248;
+ gameSys.setAnimation(0, 0, 2);
+ break;
+ case 0x232:
+ _nextCarWindowSequenceId = 0x247;
+ gameSys.setAnimation(0, 0, 2);
+ break;
+ case 0x22E:
+ case 0x235:
+ if (_nextWrenchSequenceId == 0x235)
+ _vm->_hotspots[kHS17Wrench]._flags &= ~SF_DISABLED;
+ else
+ _vm->_hotspots[kHS17Wrench]._flags |= SF_DISABLED;
+ _canTryGetWrench = !_canTryGetWrench;
+ gameSys.setAnimation(_nextWrenchSequenceId, 40, 2);
+ gameSys.insertSequence(_nextWrenchSequenceId, 40, _currWrenchSequenceId, 40, kSeqSyncWait, 0, 0, 0);
+ _currWrenchSequenceId = _nextWrenchSequenceId;
+ _nextWrenchSequenceId = -1;
+ break;
+ case 0x230:
+ if (gnap._actionStatus == kAS17GetWrenchGnapReady) {
+ gameSys.setAnimation(0, 0, 2);
+ if (_canTryGetWrench) {
+ gameSys.insertSequence(0x22E, 40, _currWrenchSequenceId, 40, kSeqSyncWait, 0, 0, 0);
+ _currWrenchSequenceId = 0x22E;
+ _canTryGetWrench = false;
+ }
+ gameSys.setAnimation(0x23F, plat._id, 1);
+ gameSys.insertSequence(0x10875, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x23F, plat._id,
+ plat._sequenceId | (plat._sequenceDatNum << 16), plat._id,
+ kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceDatNum = 1;
+ plat._sequenceDatNum = 0;
+ gnap._sequenceId = 0x875;
+ plat._sequenceId = 0x23F;
+ gnap.walkTo(Common::Point(3, 8), -1, 0x107B9, 1);
+ plat._actionStatus = kAS17GetWrench2;
+ }
+ break;
+ default:
+ if (_nextWrenchSequenceId != -1) {
+ gameSys.setAnimation(_nextWrenchSequenceId, 40, 2);
+ gameSys.insertSequence(_nextWrenchSequenceId, 40, _currWrenchSequenceId, 40, kSeqSyncWait, 0, 0, 0);
+ _currWrenchSequenceId = _nextWrenchSequenceId;
+ _nextWrenchSequenceId = -1;
+ }
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2) {
+ switch (_nextCarWindowSequenceId) {
+ case 0x246:
+ gameSys.setAnimation(_nextCarWindowSequenceId, 40, 3);
+ gameSys.insertSequence(_nextCarWindowSequenceId, 40, _currCarWindowSequenceId, 40, kSeqSyncWait, 0, 0, 0);
+ _currCarWindowSequenceId = _nextCarWindowSequenceId;
+ _nextCarWindowSequenceId = -1;
+ break;
+ case 0x245:
+ case 0x247:
+ case 0x248:
+ gameSys.setAnimation(_nextWrenchSequenceId, 40, 2);
+ gameSys.insertSequence(_nextWrenchSequenceId, 40, _currWrenchSequenceId, 40, kSeqSyncWait, 0, 0, 0);
+ while (gameSys.getAnimationStatus(2) != 2)
+ update();
+ gameSys.setAnimation(_nextCarWindowSequenceId, 40, 3);
+ gameSys.insertSequence(_nextCarWindowSequenceId, 40, _currCarWindowSequenceId, 40, kSeqSyncWait, 0, 0, 0);
+ _currCarWindowSequenceId = _nextCarWindowSequenceId;
+ _nextCarWindowSequenceId = -1;
+ _currWrenchSequenceId = _nextWrenchSequenceId;
+ _nextWrenchSequenceId = -1;
+ break;
+ case 0x249:
+ gameSys.setAnimation(0x230, 40, 2);
+ gameSys.setAnimation(0x240, plat._id, 1);
+ gameSys.insertSequence(0x230, 40, _currWrenchSequenceId, 40, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(_nextCarWindowSequenceId, 40, _currCarWindowSequenceId, 40, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x240, plat._id, plat._sequenceId, plat._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x23E, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x23E;
+ gnap._sequenceDatNum = 0;
+ plat._sequenceId = 0x240;
+ plat._sequenceDatNum = 0;
+ gameSys.setAnimation(0x24A, 40, 3);
+ gameSys.insertSequence(0x24A, 40, _nextCarWindowSequenceId, 40, kSeqSyncWait, 0, 0, 0);
+ while (gameSys.getAnimationStatus(2) != 2) {
+ update();
+ if (gameSys.getAnimationStatus(3) == 2) {
+ gameSys.setAnimation(0x24A, 40, 3);
+ gameSys.insertSequence(0x24A, 40, 586, 40, kSeqSyncWait, 0, 0, 0);
+ }
+ }
+ gameSys.insertSequence(0x22D, 40, 560, 40, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(0x24B, 40, 3);
+ gameSys.insertSequence(0x24B, 40, 586, 40, kSeqSyncWait, 0, 0, 0);
+ _currCarWindowSequenceId = 0x24B;
+ _nextCarWindowSequenceId = -1;
+ _currWrenchSequenceId = 0x22D;
+ _nextWrenchSequenceId = -1;
+ _vm->setFlag(kGFGrassTaken);
+ gnap._actionStatus = -1;
+ plat._actionStatus = 2;
+ updateHotspots();
+ _vm->_timers[5] = _vm->getRandom(30) + 80;
+ break;
+ }
+ }
+
+}
+
+/*****************************************************************************/
+
+static const int kScene18SequenceIds[] = {
+ 0x219, 0x21A, 0x21B, 0x21C, 0x21D
+};
+
+Scene18::Scene18(GnapEngine *vm) : Scene(vm) {
+ _cowboyHatSurface = nullptr;
+
+ _platPhoneCtr = 0;
+ _platPhoneIter = 0;
+ _nextPhoneSequenceId = -1;
+ _currPhoneSequenceId = -1;
+}
+
+Scene18::~Scene18() {
+ delete _cowboyHatSurface;
+}
+
+int Scene18::init() {
+ _vm->_gameSys->setAnimation(0, 0, 3);
+ return 0x222;
+}
+
+void Scene18::updateHotspots() {
+ _vm->setHotspot(kHS18Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS18GarbageCan, _vm->_gridMinX + 75 * _vm->_s18GarbageCanPos - 35, _vm->_gridMinY + 230, _vm->_gridMinX + 75 * _vm->_s18GarbageCanPos + 35, _vm->_gridMinY + 318,
+ SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, _vm->_s18GarbageCanPos, 7);
+ _vm->setHotspot(kHS18ExitToyStore, 460, 238, 592, 442, SF_EXIT_U_CURSOR, 7, 7);
+ _vm->setHotspot(kHS18ExitPhoneBooth, 275, 585, 525, 600, SF_EXIT_D_CURSOR | SF_WALKABLE, 5, 10);
+ _vm->setHotspot(kHS18ExitGrubCity, 0, 350, 15, 600, SF_EXIT_L_CURSOR, 0, 9);
+ _vm->setHotspot(kHS18HydrantTopValve, 100, 345, 182, 410, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 1, 8);
+ _vm->setHotspot(kHS18HydrantRightValve, 168, 423, 224, 470, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 3, 7);
+ _vm->setHotspot(kHS18CowboyHat, 184, 63, 289, 171, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 4, 7);
+ _vm->setHotspot(kHS18WalkArea1, 0, 0, 800, 448);
+ _vm->setHotspot(kHS18WalkArea2, 0, 0, 214, 515);
+ _vm->setDeviceHotspot(kHS18Device, -1, -1, -1, -1);
+ if (_vm->isFlag(kGFTruckFilledWithGas)) {
+ if (_vm->isFlag(kGFTruckKeysUsed)) {
+ _vm->_hotspots[kHS18HydrantTopValve]._flags = SF_DISABLED;
+ _vm->_hotspots[kHS18HydrantRightValve]._rect.left = 148;
+ _vm->_hotspots[kHS18HydrantRightValve]._rect.top = 403;
+ _vm->_hotspots[kHS18GarbageCan]._flags = SF_DISABLED;
+ _vm->_hotspotsWalkPos[kHS18GarbageCan] = Common::Point(3, 7);
+ } else {
+ _vm->_hotspots[kHS18HydrantTopValve]._rect.top = 246;
+ }
+ } else if (_vm->isFlag(kGFBarnPadlockOpen)) {
+ _vm->_hotspots[kHS18HydrantRightValve]._flags = SF_DISABLED;
+ _vm->_hotspots[kHS18HydrantTopValve]._rect.left = 105;
+ _vm->_hotspots[kHS18HydrantTopValve]._rect.right = 192;
+ } else if (_vm->isFlag(kGFTruckKeysUsed)) {
+ _vm->_hotspots[kHS18GarbageCan]._rect = Common::Rect(115, 365, 168, 470);
+ _vm->_hotspots[kHS18GarbageCan]._flags = SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR;
+ _vm->_hotspotsWalkPos[kHS18GarbageCan] = Common::Point(3, 7);
+ }
+ if (_vm->isFlag(kGFPlatypusDisguised))
+ _vm->_hotspots[kHS18GarbageCan]._flags = SF_DISABLED;
+ if (_vm->isFlag(kGFPlatypusTalkingToAssistant)) {
+ _vm->_hotspots[kHS18Device]._flags = SF_DISABLED;
+ _vm->_hotspots[kHS18HydrantTopValve]._flags = SF_DISABLED;
+ _vm->_hotspots[kHS18HydrantRightValve]._flags = SF_DISABLED;
+ _vm->_hotspots[kHS18Platypus]._flags = SF_DISABLED;
+ }
+ if (_vm->isFlag(kGFUnk14)) {
+ _vm->_hotspots[kHS18HydrantTopValve]._flags = SF_DISABLED;
+ _vm->_hotspots[kHS18CowboyHat]._flags = SF_DISABLED;
+ }
+ _vm->_hotspotsCount = 11;
+}
+
+void Scene18::gnapCarryGarbageCanTo(int gridX) {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ int gnapSeqId, gnapId, gnapDatNum, gnapGridX;
+ int destGridX, direction;
+
+ int curGridX = (_vm->_leftClickMouseX - _vm->_gridMinX + 37) / 75;
+
+ if (curGridX >= gnap._pos.x)
+ destGridX = curGridX - 1;
+ else
+ destGridX = curGridX + 1;
+
+ if (gridX < 0)
+ gridX = 4;
+
+ if (destGridX <= gridX)
+ destGridX = gridX;
+
+ int nextGridX = _vm->_gridMaxX - 1;
+ if (nextGridX >= destGridX)
+ nextGridX = destGridX;
+
+ if (nextGridX == gnap._pos.x) {
+ gnapSeqId = gnap._sequenceId;
+ gnapId = gnap._id;
+ gnapDatNum = gnap._sequenceDatNum;
+ gnapGridX = gnap._pos.x;
+ if (gnap._pos.x <= curGridX)
+ direction = 1;
+ else
+ direction = -1;
+ } else {
+ PlayerPlat& plat = *_vm->_plat;
+ if (gnap._pos.y == plat._pos.y) {
+ if (nextGridX >= gnap._pos.x) {
+ if (nextGridX >= plat._pos.x && gnap._pos.x <= plat._pos.x)
+ plat.makeRoom();
+ } else if (nextGridX <= plat._pos.x && gnap._pos.x >= plat._pos.x) {
+ plat.makeRoom();
+ }
+ }
+ gnapSeqId = gnap._sequenceId;
+ gnapId = gnap._id;
+ gnapDatNum = gnap._sequenceDatNum;
+ gnapGridX = gnap._pos.x;
+ int seqId;
+ if (nextGridX < gnap._pos.x) {
+ direction = -1;
+ seqId = 0x204;
+ } else {
+ direction = 1;
+ seqId = 0x203;
+ }
+
+ int seqId2 = 20 * gnap._pos.y + 1;
+ do {
+ if (_vm->isPointBlocked(gnapGridX + direction, gnap._pos.y))
+ break;
+ seqId2 += direction;
+ gameSys.insertSequence(seqId, seqId2,
+ gnapSeqId | (gnapDatNum << 16), gnapId,
+ kSeqSyncWait, 0, 75 * gnapGridX - gnap._gridX, 48 * gnap._pos.y - gnap._gridY);
+ gnapSeqId = seqId;
+ gnapId = seqId2;
+ gnapDatNum = 0;
+ gnapGridX += direction;
+ } while (nextGridX != gnapGridX);
+ }
+
+ if (direction == 1)
+ gnap._sequenceId = 0x20A;
+ else
+ gnap._sequenceId = 0x209;
+ gnap._sequenceDatNum = 0;
+
+ if (direction == 1)
+ gnap._idleFacing = kDirBottomRight;
+ else
+ gnap._idleFacing = kDirBottomLeft;
+
+ gnap._id = 20 * gnap._pos.y + 1;
+
+ gameSys.setAnimation(makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, 0);
+ gameSys.insertSequence(makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id,
+ gnapSeqId | (gnapDatNum << 16), gnapId,
+ kSeqScale | kSeqSyncWait, 0, 75 * gnapGridX - gnap._gridX, 48 * gnap._pos.y - gnap._gridY);
+
+ gnap._pos.x = gnapGridX;
+}
+
+void Scene18::putDownGarbageCan(int animationIndex) {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (animationIndex >= 0) {
+ while (gameSys.getAnimationStatus(animationIndex) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+ }
+ if (gnap._idleFacing != kDirIdleLeft && gnap._idleFacing != kDirBottomRight && gnap._idleFacing != kDirUpRight)
+ _vm->_s18GarbageCanPos = gnap._pos.x - 1;
+ else
+ _vm->_s18GarbageCanPos = gnap._pos.x + 1;
+ _vm->clearFlag(kGFPlatypusDisguised);
+ updateHotspots();
+ if (gnap._idleFacing != kDirIdleLeft && gnap._idleFacing != kDirBottomRight && gnap._idleFacing != kDirUpRight) {
+ gameSys.insertSequence(0x107BA, gnap._id,
+ makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id,
+ kSeqSyncWait, 0, 75 * gnap._pos.x - gnap._gridX, 48 * gnap._pos.y - gnap._gridY);
+ gnap._sequenceId = 0x7BA;
+ } else {
+ gameSys.insertSequence(0x107B9, gnap._id,
+ makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id,
+ kSeqSyncWait, 0, 75 * gnap._pos.x - gnap._gridX, 48 * gnap._pos.y - gnap._gridY);
+ gnap._sequenceId = 0x7B9;
+ }
+ gnap._sequenceDatNum = 1;
+ gameSys.insertSequence(0x1FB, 19, 0, 0, kSeqNone, 0, 15 * (5 * _vm->_s18GarbageCanPos - 40), 0);
+ gameSys.setAnimation(0x1FA, 19, 4);
+ gameSys.insertSequence(0x1FA, 19, 507, 19, kSeqSyncWait, 0, 15 * (5 * _vm->_s18GarbageCanPos - 40), 0);
+ while (gameSys.getAnimationStatus(4) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+}
+
+void Scene18::platEndPhoning(bool platFl) {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerPlat& plat = *_vm->_plat;
+
+ if (_vm->isFlag(kGFPlatypusTalkingToAssistant)) {
+ _platPhoneIter = 0;
+ _platPhoneCtr = 0;
+ plat._actionStatus = -1;
+ if (_currPhoneSequenceId != -1) {
+ gameSys.setAnimation(0x21E, 254, 3);
+ gameSys.insertSequence(0x21E, 254, _currPhoneSequenceId, 254, kSeqSyncExists, 0, 0, 0);
+ while (gameSys.getAnimationStatus(3) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+ }
+ gameSys.removeSequence(0x21F, 254, true);
+ gameSys.setAnimation(0, 0, 3);
+ _vm->clearFlag(kGFPlatypusTalkingToAssistant);
+ if (platFl) {
+ plat._actionStatus = kAS18PlatComesHere;
+ _vm->_timers[6] = 50;
+ _vm->_sceneWaiting = true;
+ }
+ _currPhoneSequenceId = -1;
+ _nextPhoneSequenceId = -1;
+ updateHotspots();
+ }
+}
+
+void Scene18::closeHydrantValve() {
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ gnap._actionStatus = kAS18LeaveScene;
+ _vm->updateMouseCursor();
+ if (_vm->isFlag(kGFTruckFilledWithGas)) {
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS18HydrantRightValve], 0, 0x107BA, 1);
+ if (_vm->isFlag(kGFTruckKeysUsed)) {
+ gnap._actionStatus = kAS18CloseRightValveWithGarbageCan;
+ waitForGnapAction();
+ } else {
+ gnap._actionStatus = kAS18CloseRightValveNoGarbageCan;
+ waitForGnapAction();
+ }
+ } else if (_vm->isFlag(kGFBarnPadlockOpen)) {
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS18HydrantTopValve], 0, 0x107BA, 1);
+ gnap._actionStatus = kAS18CloseTopValve;
+ waitForGnapAction();
+ }
+}
+
+void Scene18::waitForGnapAction() {
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ while (gnap._actionStatus >= 0 && !_vm->_gameDone) {
+ updateAnimations();
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene18::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _cowboyHatSurface = nullptr;
+
+ _vm->playSound(0x10940, true);
+ _vm->startSoundTimerA(4);
+ _vm->_timers[5] = _vm->getRandom(100) + 100;
+ _vm->queueInsertDeviceIcon();
+ _vm->clearFlag(kGFPlatypusDisguised);
+
+ if (!_vm->isFlag(kGFUnk14))
+ gameSys.insertSequence(0x1F8, 19, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (_vm->isFlag(kGFTruckKeysUsed)) {
+ if (_vm->isFlag(kGFTruckFilledWithGas)) {
+ gameSys.insertSequence(0x214, 39, 0, 0, kSeqLoop, 0, 0, 0);
+ gameSys.insertSequence(0x20D, 39, 0, 0, kSeqLoop, 0, 0, 0);
+ _vm->playSound(0x22B, true);
+ } else {
+ gameSys.insertSequence(0x1F9, 19, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ } else {
+ gameSys.insertSequence(0x1FA, 19, 0, 0, kSeqNone, 0, 15 * (5 * _vm->_s18GarbageCanPos - 40), 0);
+ if (_vm->isFlag(kGFTruckFilledWithGas)) {
+ gameSys.insertSequence(0x212, 39, 0, 0, kSeqLoop, 0, 0, 0);
+ gameSys.insertSequence(0x20D, 39, 0, 0, kSeqLoop, 0, 0, 0);
+ _vm->playSound(0x22B, true);
+ } else if (_vm->isFlag(kGFBarnPadlockOpen)) {
+ gameSys.insertSequence(0x20E, 39, 0, 0, kSeqLoop, 0, 0, 0);
+ gameSys.insertSequence(0x217, 39, 0, 0, kSeqLoop, 0, 0, 0);
+ _vm->playSound(0x22B, true);
+ }
+ }
+
+ if (_vm->isFlag(kGFPlatypusTalkingToAssistant)) {
+ if (_vm->_prevSceneNum == 17)
+ gnap.initPos(4, 11, kDirBottomRight);
+ else
+ gnap.initPos(4, 7, kDirBottomRight);
+ _platPhoneCtr = _vm->getRandom(5);
+ if (_vm->isFlag(kGFUnk27)) {
+ gameSys.insertSequence(0x21E, 254, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->endSceneInit();
+ _currPhoneSequenceId = -1;
+ platEndPhoning(true);
+ _vm->clearFlag(kGFUnk27);
+ } else {
+ _currPhoneSequenceId = kScene18SequenceIds[_platPhoneCtr];
+ _platPhoneIter = 0;
+ gameSys.insertSequence(0x21F, 254, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.insertSequence(_currPhoneSequenceId, 254, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->endSceneInit();
+ }
+ if (_vm->isFlag(kGFUnk27)) {
+ platEndPhoning(true);
+ _vm->clearFlag(kGFUnk27);
+ } else {
+ gameSys.setAnimation(_currPhoneSequenceId, 254, 3);
+ }
+ gnap.walkTo(Common::Point(4, 8), -1, 0x107B9, 1);
+ } else {
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ _vm->clearFlag(kGFGnapControlsToyUFO);
+ _vm->setGrabCursorSprite(kItemCowboyHat);
+ _vm->_prevSceneNum = 19;
+ }
+ if (_vm->_prevSceneNum == 17) {
+ gnap.initPos(4, 11, kDirBottomRight);
+ plat.initPos(5, 11, kDirIdleLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(4, 8), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(5, 9), -1, 0x107C2, 1);
+ } else if (_vm->_prevSceneNum == 19) {
+ gnap.initPos(7, 7, kDirBottomRight);
+ plat.initPos(8, 7, kDirIdleLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(7, 8), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(8, 8), -1, 0x107C2, 1);
+ } else {
+ gnap.initPos(-1, 10, kDirBottomRight);
+ plat.initPos(-1, 10, kDirIdleLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(3, 7), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(3, 8), -1, 0x107C2, 1);
+ }
+ }
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->testWalk(0, 20, -1, -1, -1, -1);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS18Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS18Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->isFlag(kGFPlatypusDisguised)) {
+ gnapCarryGarbageCanTo(-1);
+ putDownGarbageCan(0);
+ }
+ if (_vm->_grabCursorSpriteIndex == kItemJoint) {
+ gnap.useJointOnPlatypus();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowItem(_vm->_grabCursorSpriteIndex, plat._pos.x, plat._pos.y);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS18CowboyHat:
+ if (gnap._actionStatus == kAS18StandingOnHydrant) {
+ gnap._actionStatus = kAS18GrabCowboyHat;
+ _vm->_sceneWaiting = false;
+ } else if (gnap._actionStatus < 0) {
+ if (_vm->isFlag(kGFPlatypusDisguised)) {
+ gnapCarryGarbageCanTo(-1);
+ putDownGarbageCan(0);
+ }
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS18CowboyHat], 3, 2);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(3, 2));
+ break;
+ case GRAB_CURSOR:
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS18CowboyHat], 0, gnap.getSequenceId(kGSPullOutDeviceNonWorking, Common::Point(3, 2)) | 0x10000, 1);
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS18GarbageCan:
+ if (gnap._actionStatus < 0) {
+ if (_vm->isFlag(kGFUnk14)) {
+ if (_vm->_grabCursorSpriteIndex >= 0)
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS18GarbageCan], 1, 5);
+ else
+ gnap.playImpossible();
+ } else {
+ if (_vm->isFlag(kGFPlatypusTalkingToAssistant))
+ platEndPhoning(true);
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ if (!_vm->isFlag(kGFTruckKeysUsed)) {
+ Common::Point destPos;
+ destPos.x = _vm->_hotspotsWalkPos[kHS18GarbageCan].x - (gnap._pos.x < _vm->_s18GarbageCanPos ? 1 : -1);
+ destPos.y = _vm->_hotspotsWalkPos[kHS18GarbageCan].y;
+ gnap.playShowCurrItem(destPos, _vm->_hotspotsWalkPos[kHS18GarbageCan].x, _vm->_hotspotsWalkPos[kHS18GarbageCan].y);
+ } else
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS18GarbageCan], 2, 4);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ if (!_vm->isFlag(kGFTruckKeysUsed))
+ gnap.playScratchingHead(Common::Point(_vm->_hotspotsWalkPos[kHS18GarbageCan].x - (gnap._pos.x < _vm->_s18GarbageCanPos ? 1 : -1), _vm->_hotspotsWalkPos[kHS18GarbageCan].y));
+ else if (!_vm->isFlag(kGFTruckFilledWithGas))
+ gnap.playScratchingHead(Common::Point(2, 4));
+ break;
+ case GRAB_CURSOR:
+ if (!_vm->isFlag(kGFTruckKeysUsed)) {
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS18GarbageCan] + Common::Point((gnap._pos.x < _vm->_s18GarbageCanPos ? 1 : -1), 0),
+ -1, -1, 1);
+ gnap.walkTo(gnap._pos, 0, gnap.getSequenceId(kGSIdle, Common::Point(_vm->_s18GarbageCanPos, gnap._pos.y)) | 0x10000, 1);
+ gnap._actionStatus = kAS18GrabGarbageCanFromStreet;
+ } else if (!_vm->isFlag(kGFTruckFilledWithGas)) {
+ if (gnap.walkTo(_vm->_hotspotsWalkPos[kHS18GarbageCan], 0, -1, 1))
+ gnap._actionStatus = kAS18GrabGarbageCanFromHydrant;
+ }
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ }
+ break;
+
+ case kHS18HydrantTopValve:
+ if (gnap._actionStatus < 0) {
+ if (_vm->isFlag(kGFPlatypusDisguised)) {
+ // While carrying garbage can
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnapCarryGarbageCanTo(-1);
+ putDownGarbageCan(0);
+ gnap.playShowItem(_vm->_grabCursorSpriteIndex, 0, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnapCarryGarbageCanTo(-1);
+ putDownGarbageCan(0);
+ gnap.playScratchingHead();
+ break;
+ case GRAB_CURSOR:
+ if (_vm->isFlag(kGFTruckFilledWithGas)) {
+ gnapCarryGarbageCanTo(2);
+ gnap._actionStatus = kAS18PutGarbageCanOnRunningHydrant;
+ } else if (!_vm->isFlag(kGFBarnPadlockOpen)) {
+ gnapCarryGarbageCanTo(2);
+ gnap._actionStatus = kAS18PutGarbageCanOnHydrant;
+ } else {
+ gnapCarryGarbageCanTo(-1);
+ putDownGarbageCan(0);
+ gnap.playImpossible();
+ }
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnapCarryGarbageCanTo(-1);
+ putDownGarbageCan(0);
+ gnap.playImpossible();
+ break;
+ }
+ }
+ } else {
+ if (_vm->_grabCursorSpriteIndex == kItemWrench) {
+ gnap.walkTo(gnap._pos, 0, gnap.getSequenceId(kGSIdle, Common::Point(2, 8)) | 0x10000, 1);
+ gnap._actionStatus = kAS18OpenTopValve;
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS18HydrantTopValve], 1, 5);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(1, 5));
+ break;
+ case GRAB_CURSOR:
+ if (_vm->isFlag(kGFBarnPadlockOpen)) {
+ _vm->_hotspots[kHS18WalkArea2]._flags |= SF_WALKABLE;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS18HydrantTopValve], 0, 0x107BA, 1);
+ _vm->_hotspots[kHS18WalkArea2]._flags &= ~SF_WALKABLE;
+ gnap._actionStatus = kAS18CloseTopValve;
+ } else
+ gnap.playImpossible();
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ }
+ break;
+
+ case kHS18HydrantRightValve:
+ if (gnap._actionStatus < 0) {
+ if (_vm->isFlag(kGFUnk14)) {
+ if (_vm->_grabCursorSpriteIndex == -1) {
+ gnap.playImpossible();
+ } else {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS18HydrantRightValve], 1, 5);
+ }
+ } else {
+ if (_vm->isFlag(kGFPlatypusDisguised)) {
+ gnapCarryGarbageCanTo(-1);
+ putDownGarbageCan(0);
+ }
+ if (_vm->_grabCursorSpriteIndex == kItemWrench) {
+ gnap.walkTo(gnap._pos, 0, gnap.getSequenceId(kGSIdle, Common::Point(2, 8)) | 0x10000, 1);
+ if (_vm->isFlag(kGFTruckKeysUsed))
+ gnap._actionStatus = kAS18OpenRightValveWithGarbageCan;
+ else
+ gnap._actionStatus = kAS18OpenRightValveNoGarbageCan;
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS18HydrantRightValve], 1, 5);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(1, 5));
+ break;
+ case GRAB_CURSOR:
+ if (_vm->isFlag(kGFTruckFilledWithGas)) {
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS18HydrantRightValve], 0, 0x107BA, 1);
+ if (_vm->isFlag(kGFTruckKeysUsed))
+ gnap._actionStatus = kAS18CloseRightValveWithGarbageCan;
+ else
+ gnap._actionStatus = kAS18CloseRightValveNoGarbageCan;
+ }
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ }
+ break;
+
+ case kHS18ExitToyStore:
+ if (gnap._actionStatus < 0) {
+ if (_vm->isFlag(kGFPlatypusDisguised)) {
+ gnapCarryGarbageCanTo(-1);
+ putDownGarbageCan(0);
+ }
+ if (_vm->isFlag(kGFPictureTaken)) {
+ gnap.playImpossible();
+ } else {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 19;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS18ExitToyStore], 0, 0x107C0, 1);
+ gnap._actionStatus = kAS18LeaveScene;
+ if (!_vm->isFlag(kGFPlatypusTalkingToAssistant))
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS18ExitToyStore] + Common::Point(1, 0), -1, 0x107C2, 1);
+ }
+ }
+ break;
+
+ case kHS18ExitPhoneBooth:
+ if (gnap._actionStatus < 0) {
+ if (_vm->isFlag(kGFPlatypusDisguised)) {
+ gnapCarryGarbageCanTo(-1);
+ putDownGarbageCan(0);
+ }
+ closeHydrantValve();
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 17;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS18ExitPhoneBooth], 0, 0x107AE, 1);
+ gnap._actionStatus = kAS18LeaveScene;
+ if (_vm->isFlag(kGFPlatypusTalkingToAssistant))
+ _vm->setFlag(kGFUnk27);
+ else
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS18ExitPhoneBooth] + Common::Point(1, 0), -1, 0x107C2, 1);
+ }
+ break;
+
+ case kHS18ExitGrubCity:
+ if (gnap._actionStatus < 0) {
+ if (_vm->isFlag(kGFPlatypusDisguised)) {
+ gnapCarryGarbageCanTo(-1);
+ putDownGarbageCan(0);
+ }
+ closeHydrantValve();
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 20;
+ _vm->_hotspots[kHS18WalkArea2]._flags |= SF_WALKABLE;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS18ExitGrubCity], 0, 0x107B2, 1);
+ gnap._actionStatus = kAS18LeaveScene;
+ if (_vm->isFlag(kGFPlatypusTalkingToAssistant))
+ platEndPhoning(false);
+ else
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS18ExitGrubCity] + Common::Point(0, -1), -1, 0x107CF, 1);
+ _vm->_hotspots[kHS18WalkArea2]._flags &= ~SF_WALKABLE;
+ }
+ break;
+
+ case kHS18WalkArea1:
+ case kHS18WalkArea2:
+ if (gnap._actionStatus < 0) {
+ if (_vm->isFlag(kGFPlatypusDisguised)) {
+ gnapCarryGarbageCanTo(-1);
+ putDownGarbageCan(0);
+ } else {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ }
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+
+ default:
+ if (gnap._actionStatus != kAS18StandingOnHydrant && _vm->_mouseClickState._left) {
+ if (_vm->isFlag(kGFPlatypusDisguised)) {
+ gnapCarryGarbageCanTo(-1);
+ putDownGarbageCan(0);
+ } else {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ }
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+ }
+
+ updateAnimations();
+
+ if (!_vm->isSoundPlaying(0x10940))
+ _vm->playSound(0x10940, true);
+
+ if ((_vm->isFlag(kGFTruckFilledWithGas) || _vm->isFlag(kGFBarnPadlockOpen)) && !_vm->isSoundPlaying(0x22B) &&
+ gnap._actionStatus != kAS18OpenRightValveNoGarbageCanDone && gnap._actionStatus != kAS18OpenRightValveNoGarbageCan &&
+ gnap._actionStatus != kAS18OpenTopValve && gnap._actionStatus != kAS18OpenTopValveDone &&
+ gnap._actionStatus != kAS18OpenRightValveWithGarbageCan && gnap._actionStatus != kAS18OpenRightValveWithGarbageCanDone)
+ _vm->playSound(0x22B, true);
+
+ if (!_vm->_isLeavingScene) {
+ if (!_vm->isFlag(kGFPlatypusTalkingToAssistant)) {
+ if (plat._actionStatus == kAS18PlatComesHere) {
+ if (!_vm->_timers[6]) {
+ plat._actionStatus = -1;
+ _vm->_sceneWaiting = false;
+ plat.initPos(-1, 10, kDirIdleLeft);
+ plat.walkTo(Common::Point(3, 9), -1, 0x107C2, 1);
+ _vm->clearFlag(kGFPlatypusTalkingToAssistant);
+ }
+ } else {
+ _vm->_hotspots[kHS18WalkArea1]._rect.bottom += 48;
+ _vm->_hotspots[kHS18WalkArea2]._rect.left += 75;
+ plat.updateIdleSequence();
+ _vm->_hotspots[kHS18WalkArea2]._rect.left -= 75;
+ _vm->_hotspots[kHS18WalkArea1]._rect.bottom -= 48;
+ }
+ if (!_vm->_timers[5]) {
+ _vm->_timers[5] = _vm->getRandom(100) + 100;
+ if (gnap._actionStatus < 0) {
+ if (_vm->getRandom(2) == 1)
+ gameSys.insertSequence(0x220, 255, 0, 0, kSeqNone, 0, 0, 0);
+ else
+ gameSys.insertSequence(0x221, 255, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ }
+ _vm->playSoundA();
+ }
+ if (!_vm->isFlag(kGFPlatypusDisguised))
+ gnap.updateIdleSequence();
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+
+ if (_vm->isFlag(kGFGnapControlsToyUFO))
+ _vm->deleteSurface(&_cowboyHatSurface);
+}
+
+void Scene18::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS18GrabGarbageCanFromStreet:
+ if (gnap._idleFacing != kDirUpRight && gnap._idleFacing != kDirBottomRight) {
+ gameSys.insertSequence(0x1FC, gnap._id,
+ makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id,
+ kSeqSyncWait, 0, 75 * gnap._pos.x - 675, 0);
+ gnap._sequenceDatNum = 0;
+ gnap._sequenceId = 0x1FC;
+ } else {
+ gameSys.insertSequence(0x1FD, gnap._id,
+ makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id,
+ kSeqSyncWait, 0, 75 * gnap._pos.x - 525, 0);
+ gnap._sequenceDatNum = 0;
+ gnap._sequenceId = 0x1FD;
+ }
+ gameSys.removeSequence(0x1FA, 19, true);
+ _vm->setFlag(kGFPlatypusDisguised);
+ updateHotspots();
+ gnap._actionStatus = -1;
+ break;
+ case kAS18GrabGarbageCanFromHydrant:
+ gameSys.insertSequence(0x1FE, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.removeSequence(0x1F9, 19, true);
+ gnap._sequenceDatNum = 0;
+ gnap._sequenceId = 0x1FE;
+ _vm->clearFlag(kGFTruckKeysUsed);
+ _vm->setFlag(kGFPlatypusDisguised);
+ updateHotspots();
+ gnap._actionStatus = -1;
+ break;
+ case kAS18CloseRightValveNoGarbageCan:
+ gameSys.insertSequence(0x205, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.removeSequence(0x20D, 39, true);
+ gameSys.removeSequence(0x212, 39, true);
+ gameSys.removeSequence(0x211, 39, true);
+ _vm->stopSound(0x22B);
+ gnap._sequenceDatNum = 0;
+ gnap._sequenceId = 0x205;
+ _vm->clearFlag(kGFTruckFilledWithGas);
+ _vm->invAdd(kItemWrench);
+ _vm->setGrabCursorSprite(kItemWrench);
+ updateHotspots();
+ gnap._actionStatus = -1;
+ break;
+ case kAS18OpenTopValve:
+ _vm->setFlag(kGFBarnPadlockOpen);
+ updateHotspots();
+ gnap.playPullOutDevice(Common::Point(2, 7));
+ gnap.playUseDevice();
+ gameSys.insertSequence(0x20C, 19, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->_hotspots[kHS18WalkArea2]._flags |= SF_WALKABLE;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS18HydrantTopValve], 0, 0x107BB, 1);
+ _vm->_hotspots[kHS18WalkArea2]._flags &= ~SF_WALKABLE;
+ gnap._actionStatus = kAS18OpenTopValveDone;
+ break;
+ case kAS18OpenTopValveDone:
+ _vm->setGrabCursorSprite(-1);
+ gameSys.insertSequence(0x208, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x216, 39, 0, 0, kSeqNone, 21, 0, 0);
+ gameSys.removeSequence(0x20C, 19, true);
+ gameSys.setAnimation(0x217, 39, 5);
+ gameSys.insertSequence(0x217, 39, 0x216, 39, kSeqLoop | kSeqSyncWait, 0, 0, 0);
+ while (gameSys.getAnimationStatus(5) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+ _vm->playSound(0x22B, true);
+ gameSys.insertSequence(0x20E, 39, 0, 0, kSeqNone, 0, 0, 0);
+ gnap._sequenceDatNum = 0;
+ gnap._sequenceId = 0x208;
+ _vm->invRemove(kItemWrench);
+ _vm->setGrabCursorSprite(-1);
+ gnap._actionStatus = -1;
+ break;
+ case kAS18CloseTopValve:
+ gameSys.insertSequence(0x206, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.removeSequence(0x20E, 39, true);
+ gameSys.removeSequence(0x216, 39, true);
+ gameSys.removeSequence(0x217, 39, true);
+ _vm->stopSound(0x22B);
+ gnap._sequenceDatNum = 0;
+ gnap._sequenceId = 0x206;
+ _vm->clearFlag(kGFBarnPadlockOpen);
+ _vm->invAdd(kItemWrench);
+ _vm->setGrabCursorSprite(kItemWrench);
+ updateHotspots();
+ gnap._actionStatus = -1;
+ break;
+ case kAS18GrabCowboyHat:
+ gameSys.setAnimation(0x200, gnap._id, 0);
+ gameSys.insertSequence(0x200, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceDatNum = 0;
+ gnap._sequenceId = 0x200;
+ gnap._actionStatus = kAS18GrabCowboyHatDone;
+ break;
+ case kAS18GrabCowboyHatDone:
+ _vm->hideCursor();
+ _vm->setGrabCursorSprite(-1);
+ _cowboyHatSurface = _vm->addFullScreenSprite(0x1D2, 255);
+ gameSys.setAnimation(0x218, 256, 0);
+ gameSys.insertSequence(0x218, 256, 0, 0, kSeqNone, 0, 0, 0);
+ while (gameSys.getAnimationStatus(0) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+ _vm->_newSceneNum = 18;
+ _vm->invAdd(kItemCowboyHat);
+ _vm->invAdd(kItemWrench);
+ _vm->setFlag(kGFGnapControlsToyUFO);
+ _vm->setFlag(kGFUnk14);
+ _vm->clearFlag(kGFTruckFilledWithGas);
+ _vm->setFlag(kGFTruckKeysUsed);
+ _vm->setFlag(kGFUnk14); // Useless, already set
+ updateHotspots();
+ gnap._actionStatus = kAS18LeaveScene;
+ break;
+ case kAS18LeaveScene:
+ _vm->_sceneDone = true;
+ gnap._actionStatus = -1;
+ break;
+ case kAS18PutGarbageCanOnRunningHydrant:
+ _vm->setFlag(kGFTruckKeysUsed);
+ _vm->clearFlag(kGFPlatypusDisguised);
+ gameSys.requestRemoveSequence(0x211, 39);
+ gameSys.requestRemoveSequence(0x212, 39);
+ gameSys.insertSequence(0x210, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ _vm->stopSound(0x22B);
+ gameSys.setAnimation(0x210, gnap._id, 0);
+ gnap._sequenceDatNum = 0;
+ gnap._sequenceId = 0x210;
+ gnap._actionStatus = kAS18PutGarbageCanOnRunningHydrant2;
+ break;
+ case kAS18PutGarbageCanOnRunningHydrant2:
+ _vm->playSound(0x22B, true);
+ gameSys.setAnimation(0x1FF, gnap._id, 0);
+ gameSys.insertSequence(0x1FF, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceDatNum = 0;
+ gnap._sequenceId = 0x1FF;
+ _vm->_sceneWaiting = true;
+ gnap._actionStatus = kAS18StandingOnHydrant;
+ break;
+ case kAS18StandingOnHydrant:
+ gameSys.setAnimation(0x1FF, gnap._id, 0);
+ gameSys.insertSequence(0x1FF, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ break;
+ case kAS18OpenRightValveNoGarbageCan:
+ case kAS18OpenRightValveWithGarbageCan:
+ _vm->setFlag(kGFTruckFilledWithGas);
+ updateHotspots();
+ gnap.playPullOutDevice(Common::Point(2, 7));
+ gnap.playUseDevice();
+ gameSys.insertSequence(0x20B, 19, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->_hotspots[kHS18WalkArea2]._flags |= SF_WALKABLE;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS18HydrantRightValve], 0, 0x107BA, 1);
+ _vm->_hotspots[kHS18WalkArea2]._flags &= ~SF_WALKABLE;
+ if (gnap._actionStatus == kAS18OpenRightValveNoGarbageCan)
+ gnap._actionStatus = kAS18OpenRightValveNoGarbageCanDone;
+ else
+ gnap._actionStatus = kAS18OpenRightValveWithGarbageCanDone;
+ break;
+ case kAS18OpenRightValveWithGarbageCanDone:
+ _vm->setGrabCursorSprite(-1);
+ gameSys.insertSequence(0x207, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x213, 39, 0, 0, kSeqNone, 21, 0, 0);
+ gameSys.requestRemoveSequence(0x1F9, 19);
+ gameSys.removeSequence(0x20B, 19, true);
+ gameSys.setAnimation(0x213, 39, 5);
+ gameSys.insertSequence(0x214, 39, 0x213, 39, kSeqLoop | kSeqSyncWait, 0, 0, 0);
+ while (gameSys.getAnimationStatus(5) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+ _vm->playSound(0x22B, true);
+ gameSys.insertSequence(0x20D, 39, 0, 0, kSeqNone, 0, 0, 0);
+ gnap._sequenceDatNum = 0;
+ gnap._sequenceId = 0x207;
+ _vm->invRemove(kItemWrench);
+ gnap._actionStatus = -1;
+ break;
+ case kAS18OpenRightValveNoGarbageCanDone:
+ _vm->setGrabCursorSprite(-1);
+ gameSys.insertSequence(0x207, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x211, 39, 0, 0, kSeqNone, 21, 0, 0);
+ gameSys.removeSequence(0x20B, 19, true);
+ gameSys.setAnimation(0x211, 39, 5);
+ gameSys.insertSequence(0x212, 39, 0x211, 39, kSeqLoop | kSeqSyncWait, 0, 0, 0);
+ while (gameSys.getAnimationStatus(5) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+ _vm->playSound(0x22B, true);
+ gameSys.insertSequence(0x20D, 39, 0, 0, kSeqNone, 0, 0, 0);
+ gnap._sequenceDatNum = 0;
+ gnap._sequenceId = 0x207;
+ _vm->invRemove(kItemWrench);
+ gnap._actionStatus = -1;
+ break;
+ case kAS18CloseRightValveWithGarbageCan:
+ gameSys.insertSequence(0x205, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.removeSequence(0x20D, 39, true);
+ gameSys.insertSequence(0x215, 39, 0x214, 39, kSeqSyncWait, 0, 0, 0);
+ _vm->stopSound(0x22B);
+ gameSys.setAnimation(0x1F9, 19, 0);
+ gameSys.insertSequence(0x1F9, 19, 0x215, 39, kSeqSyncWait, 0, 0, 0);
+ _vm->clearFlag(kGFTruckFilledWithGas);
+ _vm->invAdd(kItemWrench);
+ _vm->setGrabCursorSprite(kItemWrench);
+ gameSys.insertSequence(0x107B5, gnap._id, 517, gnap._id, kSeqSyncWait, 0, 75 * gnap._pos.x - gnap._gridX, 48 * gnap._pos.y - gnap._gridY);
+ updateHotspots();
+ gnap._sequenceDatNum = 1;
+ gnap._sequenceId = 0x7B5;
+ gnap._actionStatus = kAS18CloseRightValveWithGarbageCanDone;
+ break;
+ case kAS18CloseRightValveWithGarbageCanDone:
+ gnap._actionStatus = -1;
+ break;
+ case kAS18PutGarbageCanOnHydrant:
+ _vm->setFlag(kGFTruckKeysUsed);
+ _vm->clearFlag(kGFPlatypusDisguised);
+ gameSys.insertSequence(0x20F, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(0x20F, gnap._id, 0);
+ gnap._sequenceDatNum = 0;
+ gnap._sequenceId = 0x20F;
+ gnap._actionStatus = kAS18PutGarbageCanOnHydrantDone;
+ break;
+ case kAS18PutGarbageCanOnHydrantDone:
+ gameSys.insertSequence(0x1F9, 19, 0x20F, gnap._id, kSeqNone, 0, 0, 0);
+ updateHotspots();
+ gnap._actionStatus = -1;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2) {
+ gameSys.setAnimation(0, 0, 3);
+ ++_platPhoneIter;
+ if (_platPhoneIter <= 4) {
+ ++_platPhoneCtr;
+ _nextPhoneSequenceId = kScene18SequenceIds[_platPhoneCtr % 5];
+ gameSys.setAnimation(_nextPhoneSequenceId, 254, 3);
+ gameSys.insertSequence(_nextPhoneSequenceId, 254, _currPhoneSequenceId, 254, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x21F, 254, 0x21F, 254, kSeqSyncWait, 0, 0, 0);
+ _currPhoneSequenceId = _nextPhoneSequenceId;
+ } else {
+ platEndPhoning(true);
+ }
+ }
+}
+
+/*****************************************************************************/
+
+static const int kS19ShopAssistantSequenceIds[] = {
+ 0x6F, 0x70, 0x71, 0x72, 0x73
+};
+
+Scene19::Scene19(GnapEngine *vm) : Scene(vm) {
+ _toyGrabCtr = 0;
+ _shopAssistantCtr = 0;
+ _currShopAssistantSequenceId = -1;
+ _nextShopAssistantSequenceId = -1;
+
+ _pictureSurface = nullptr;
+}
+
+Scene19::~Scene19() {
+ delete _pictureSurface;
+}
+
+int Scene19::init() {
+ _vm->playSound(0x79, false);
+ return _vm->isFlag(kGFPlatypusTalkingToAssistant) ? 0x77 : 0x76;
+}
+
+void Scene19::updateHotspots() {
+ _vm->setHotspot(kHS19Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS19ExitOutsideToyStore, 36, 154, 142, 338, SF_EXIT_NW_CURSOR, 4, 6);
+ _vm->setHotspot(kHS19Picture, 471, 237, 525, 283, SF_DISABLED, 7, 2);
+ _vm->setHotspot(kHS19ShopAssistant, 411, 151, 575, 279, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 5, 7);
+ _vm->setHotspot(kHS19Phone, 647, 166, 693, 234, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 9, 0);
+ _vm->setHotspot(kHS19Toy1, 181, 11, 319, 149, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 3, 0);
+ _vm->setHotspot(kHS19Toy2, 284, 85, 611, 216, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 6, 0);
+ _vm->setHotspot(kHS19Toy3, 666, 38, 755, 154, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 9, 0);
+ _vm->setHotspot(kHS19Toy4, 154, 206, 285, 327, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 3, 3);
+ _vm->setHotspot(kHS19Toy5, 494, 301, 570, 448, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 7, 5);
+ _vm->setHotspot(kHS19Toy6, 0, 320, 188, 600, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 1, 6);
+ _vm->setHotspot(kHS19Toy7, 597, 434, 800, 600, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 9, 8);
+ _vm->setHotspot(kHS19WalkArea1, 0, 0, 170, 600);
+ _vm->setHotspot(kHS19WalkArea2, 622, 0, 800, 600);
+ _vm->setHotspot(kHS19WalkArea3, 0, 0, 800, 437);
+ _vm->setDeviceHotspot(kHS19Device, -1, -1, -1, -1);
+ if (_vm->isFlag(kGFPlatypusTalkingToAssistant)) {
+ _vm->_hotspots[kHS19Toy1]._flags = SF_DISABLED;
+ _vm->_hotspots[kHS19Toy2]._flags = SF_DISABLED;
+ _vm->_hotspots[kHS19Toy3]._flags = SF_DISABLED;
+ _vm->_hotspots[kHS19Toy4]._flags = SF_DISABLED;
+ _vm->_hotspots[kHS19Toy5]._flags = SF_DISABLED;
+ _vm->_hotspots[kHS19Toy6]._flags = SF_DISABLED;
+ _vm->_hotspots[kHS19Toy7]._flags = SF_DISABLED;
+ _vm->_hotspots[kHS19ShopAssistant]._flags = SF_DISABLED;
+ _vm->_hotspots[kHS19Phone]._flags = SF_DISABLED;
+ _vm->_hotspots[kHS19Platypus]._flags = SF_DISABLED;
+ _vm->_hotspots[kHS19Picture]._flags = SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR;
+ }
+ _vm->_hotspotsCount = 16;
+}
+
+void Scene19::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->queueInsertDeviceIcon();
+ _toyGrabCtr = 0;
+ _pictureSurface = nullptr;
+
+ gameSys.insertSequence(0x74, 254, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.insertSequence(0x75, 254, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (!_vm->isFlag(kGFPictureTaken))
+ gameSys.insertSequence(0x69, 19, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (_vm->isFlag(kGFPlatypusTalkingToAssistant)) {
+ gnap.initPos(3, 6, kDirBottomRight);
+ _currShopAssistantSequenceId = kS19ShopAssistantSequenceIds[_vm->getRandom(5)];
+ _nextShopAssistantSequenceId = _currShopAssistantSequenceId;
+ gameSys.setAnimation(_currShopAssistantSequenceId, 20, 4);
+ gameSys.insertSequence(0x6E, 254, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.insertSequence(_currShopAssistantSequenceId, 20, 0, 0, kSeqNone, 0, 0, 0);
+ _shopAssistantCtr = 0;
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(4, 9), -1, 0x107B9, 1);
+ updateHotspots();
+ } else {
+ _currShopAssistantSequenceId = 0x6D;
+ _nextShopAssistantSequenceId = -1;
+ gameSys.setAnimation(0x6D, 20, 4);
+ gameSys.insertSequence(_currShopAssistantSequenceId, 20, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->_timers[6] = _vm->getRandom(40) + 50;
+ gnap.initPos(3, 6, kDirBottomRight);
+ plat.initPos(4, 6, kDirIdleLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(4, 9), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(5, 9), -1, 0x107C2, 1);
+ }
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->testWalk(0, 5, -1, -1, -1, -1);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS19Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS19Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemJoint) {
+ gnap.useJointOnPlatypus();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible(plat._pos);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS19ExitOutsideToyStore:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 18;
+ _vm->_hotspots[kHS19WalkArea1]._flags |= SF_WALKABLE;
+ gnap.walkTo(_vm->_hotspotsWalkPos[1], 0, 0x107B2, 1);
+ gnap._actionStatus = kAS19LeaveScene;
+ if (_vm->isFlag(kGFPlatypusTalkingToAssistant))
+ _vm->setFlag(kGFUnk27);
+ else
+ plat.walkTo(_vm->_hotspotsWalkPos[1] + Common::Point(1, 0), -1, 0x107C5, 1);
+ _vm->_hotspots[kHS19WalkArea1]._flags &= ~SF_WALKABLE;
+ }
+ break;
+
+ case kHS19Picture:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot], 6, 2);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(6, 2));
+ break;
+ case GRAB_CURSOR:
+ if (!_vm->isFlag(kGFPictureTaken)) {
+ gnap.walkTo(gnap._pos, 0, gnap.getSequenceId(kGSIdle, _vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot]) | 0x10000, 1);
+ gnap._actionStatus = kAS19GrabPicture;
+ }
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS19ShopAssistant:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot], 6, 2);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(6, 2));
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS19TalkShopAssistant;
+ break;
+ case GRAB_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS19Toy1:
+ case kHS19Toy2:
+ case kHS19Toy3:
+ case kHS19Toy4:
+ case kHS19Toy5:
+ case kHS19Toy6:
+ case kHS19Toy7:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot]);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan2(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot]);
+ break;
+ case GRAB_CURSOR:
+ gnap.walkTo(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot], 0, -1, 1);
+ gnap.playIdle(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot]);
+ gnap._actionStatus = kAS19GrabToy;
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS19Phone:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot], 9, 1);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(9, 1));
+ break;
+ case GRAB_CURSOR:
+ gnap.walkTo(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot], 0, -1, 1);
+ gnap.playIdle(Common::Point(8, 2));
+ gnap._actionStatus = kAS19UsePhone;
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS19WalkArea1:
+ case kHS19WalkArea2:
+ case kHS19WalkArea3:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = 0;
+ }
+ }
+
+ updateAnimations();
+
+ if (!_vm->_isLeavingScene) {
+ gnap.updateIdleSequence();
+ if (!_vm->isFlag(kGFPlatypusTalkingToAssistant)) {
+ plat.updateIdleSequence();
+ if (!_vm->_timers[6] && _nextShopAssistantSequenceId == -1) {
+ _vm->_timers[6] = _vm->getRandom(40) + 50;
+ if (_vm->getRandom(4) != 0) {
+ _nextShopAssistantSequenceId = 0x64;
+ } else if (_vm->isFlag(kGFPictureTaken)) {
+ _nextShopAssistantSequenceId = 0x64;
+ } else {
+ _nextShopAssistantSequenceId = 0x6C;
+ }
+ }
+ }
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+
+ if (_pictureSurface)
+ _vm->deleteSurface(&_pictureSurface);
+}
+
+void Scene19::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS19UsePhone:
+ _nextShopAssistantSequenceId = 0x67;
+ break;
+ case kAS19GrabToy:
+ ++_toyGrabCtr;
+ switch (_toyGrabCtr) {
+ case 1:
+ _nextShopAssistantSequenceId = 0x62;
+ break;
+ case 2:
+ _nextShopAssistantSequenceId = 0x6B;
+ break;
+ case 3:
+ _nextShopAssistantSequenceId = 0x66;
+ break;
+ default:
+ _nextShopAssistantSequenceId = 0x65;
+ break;
+ }
+ break;
+ case kAS19GrabPicture:
+ gnap.playPullOutDevice(Common::Point(6, 2));
+ gnap.playUseDevice();
+ gameSys.setAnimation(0x68, 19, 0);
+ gameSys.insertSequence(0x68, 19, 105, 19, kSeqSyncWait, 0, 0, 0);
+ _vm->invAdd(kItemPicture);
+ _vm->setFlag(kGFPictureTaken);
+ updateHotspots();
+ gnap._actionStatus = kAS19GrabPictureDone;
+ break;
+ case kAS19GrabPictureDone:
+ _vm->setGrabCursorSprite(-1);
+ _vm->hideCursor();
+ _pictureSurface = _vm->addFullScreenSprite(0xF, 255);
+ gameSys.setAnimation(0x61, 256, 0);
+ gameSys.insertSequence(0x61, 256, 0, 0, kSeqNone, 0, 0, 0);
+ while (gameSys.getAnimationStatus(0) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+
+ _vm->setFlag(kGFUnk27);
+ _vm->showCursor();
+ _vm->_newSceneNum = 17;
+ _vm->_isLeavingScene = true;
+ _vm->_sceneDone = true;
+ _nextShopAssistantSequenceId = -1;
+ break;
+ case kAS19TalkShopAssistant:
+ _nextShopAssistantSequenceId = 0x6D;
+ gnap._actionStatus = -1;
+ break;
+ case kAS19LeaveScene:
+ _vm->_sceneDone = true;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(4) == 2) {
+ switch (_nextShopAssistantSequenceId) {
+ case 0x6F:
+ case 0x70:
+ case 0x71:
+ case 0x72:
+ case 0x73:
+ _shopAssistantCtr = (_shopAssistantCtr + 1) % 5;
+ _nextShopAssistantSequenceId = kS19ShopAssistantSequenceIds[_shopAssistantCtr];
+ gameSys.setAnimation(_nextShopAssistantSequenceId, 20, 4);
+ gameSys.insertSequence(_nextShopAssistantSequenceId, 20, _currShopAssistantSequenceId, 20, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x6E, 254, 0x6E, 254, kSeqSyncWait, 0, 0, 0);
+ _currShopAssistantSequenceId = _nextShopAssistantSequenceId;
+ break;
+ case 0x62:
+ case 0x66:
+ case 0x6B:
+ gameSys.setAnimation(_nextShopAssistantSequenceId, 20, 4);
+ gameSys.insertSequence(_nextShopAssistantSequenceId, 20, _currShopAssistantSequenceId, 20, kSeqSyncWait, 0, 0, 0);
+ _currShopAssistantSequenceId = _nextShopAssistantSequenceId;
+ _nextShopAssistantSequenceId = -1;
+ _vm->_timers[5] = 10;
+ while (_vm->_timers[5] && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+
+ gnap.playIdle(Common::Point(6, 2));
+ gnap._actionStatus = -1;
+ break;
+ case 0x67:
+ gameSys.setAnimation(_nextShopAssistantSequenceId, 20, 4);
+ gameSys.insertSequence(_nextShopAssistantSequenceId, 20, _currShopAssistantSequenceId, 20, kSeqSyncWait, 0, 0, 0);
+ _currShopAssistantSequenceId = _nextShopAssistantSequenceId;
+ _nextShopAssistantSequenceId = -1;
+ gnap._actionStatus = -1;
+ break;
+ case 0x65:
+ gnap.playIdle(Common::Point(6, 2));
+ gameSys.setAnimation(_nextShopAssistantSequenceId, 20, 0);
+ gameSys.insertSequence(_nextShopAssistantSequenceId, 20, _currShopAssistantSequenceId, 20, kSeqSyncWait, 0, 0, 0);
+ _currShopAssistantSequenceId = _nextShopAssistantSequenceId;
+ _nextShopAssistantSequenceId = -1;
+ _vm->_newSceneNum = 18;
+ gnap._actionStatus = kAS19LeaveScene;
+ break;
+ case 0x6D:
+ gameSys.setAnimation(_nextShopAssistantSequenceId, 20, 4);
+ gameSys.insertSequence(_nextShopAssistantSequenceId, 20, _currShopAssistantSequenceId, 20, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x69, 19, 0x69, 19, kSeqSyncWait, _vm->getSequenceTotalDuration(_nextShopAssistantSequenceId), 0, 0);
+ _currShopAssistantSequenceId = _nextShopAssistantSequenceId;
+ _nextShopAssistantSequenceId = -1;
+ break;
+ case 0x64:
+ case 0x6C:
+ gameSys.setAnimation(_nextShopAssistantSequenceId, 20, 4);
+ gameSys.insertSequence(_nextShopAssistantSequenceId, 20, _currShopAssistantSequenceId, 20, kSeqSyncWait, 0, 0, 0);
+ _currShopAssistantSequenceId = _nextShopAssistantSequenceId;
+ _nextShopAssistantSequenceId = -1;
+ break;
+ }
+ }
+}
+
+} // End of namespace Gnap
diff --git a/engines/gnap/scenes/group1.h b/engines/gnap/scenes/group1.h
new file mode 100644
index 0000000000..30771d017a
--- /dev/null
+++ b/engines/gnap/scenes/group1.h
@@ -0,0 +1,454 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can 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 GNAP_GROUP1_H
+#define GNAP_GROUP1_H
+
+#include "gnap/debugger.h"
+
+namespace Gnap {
+
+enum {
+ kHS10Platypus = 0,
+ kHS10ExitBar = 1,
+ kHS10ExitBackdoor = 2,
+ kHS10Cook = 3,
+ kHS10Tongs = 4,
+ kHS10Box = 5,
+ kHS10Oven = 6,
+ kHS10WalkArea1 = 7,
+ kHS10Device = 8,
+ kHS10WalkArea2 = 9,
+ kHS10WalkArea3 = 10,
+ kHS10WalkArea4 = 11
+};
+
+enum {
+ kHS11Platypus = 0,
+ kHS11ExitKitchen = 1,
+ kHS11ExitToilet = 2,
+ kHS11ExitLeft = 3,
+ kHS11GoggleGuy = 4,
+ kHS11HookGuy = 5,
+ kHS11Billard = 6,
+ kHS11WalkArea1 = 7,
+ kHS11Device = 8,
+ kHS11WalkArea2 = 9,
+ kHS11WalkArea3 = 10,
+ kHS11WalkArea4 = 11,
+ kHS11WalkArea5 = 12
+};
+
+enum {
+ kHS12Platypus = 0,
+ kHS12ExitRight = 1,
+ kHS12ToothGuy = 2,
+ kHS12Barkeeper = 3,
+ kHS12BeardGuy = 4,
+ kHS12Jukebox = 5,
+ kHS12WalkArea1 = 6,
+ kHS12Device = 7,
+ kHS12WalkArea2 = 8,
+ kHS12WalkArea3 = 9,
+ kHS12WalkArea4 = 10
+};
+
+enum {
+ kHS13Platypus = 0,
+ kHS13ExitBar = 1,
+ kHS13WalkArea1 = 2,
+ kHS13BackToilet = 3,
+ kHS13FrontToilet= 4,
+ kHS13Urinal = 5,
+ kHS13Scribble = 6,
+ kHS13Sink = 7,
+ kHS13WalkArea2 = 8,
+ kHS13Device = 9,
+ kHS13WalkArea3 = 10,
+ kHS13WalkArea4 = 11,
+ kHS13WalkArea5 = 12,
+ kHS13WalkArea6 = 13,
+ kHS13WalkArea7 = 14,
+ kHS13WalkArea8 = 15,
+ kHS13WalkArea9 = 16
+};
+
+enum {
+ kHS14Platypus = 0,
+ kHS14Exit = 1,
+ kHS14Coin = 2,
+ kHS14Toilet = 3,
+ kHS14Device = 4
+};
+
+enum {
+ kHS15Platypus = 0,
+ kHS15Exit = 1,
+ kHS15Button1 = 2,
+ kHS15Button2 = 3,
+ kHS15Button3 = 4,
+ kHS15Button4 = 5,
+ kHS15Button5 = 6,
+ kHS15Button6 = 7,
+ kHS15ButtonA = 8,
+ kHS15ButtonB = 9,
+ kHS15ButtonC = 10,
+ kHS15ButtonD = 11,
+ kHS15ButtonE = 12,
+ kHS15ButtonF = 13,
+ kHS15CoinSlot = 14,
+ kHS15PlayButton = 15,
+ kHS15Device = 16
+};
+
+enum {
+ kHS17Platypus = 0,
+ kHS17Phone1 = 1,
+ kHS17Phone2 = 2,
+ kHS17ExitGrubCity = 3,
+ kHS17Device = 4,
+ kHS17ExitToyStore = 5,
+ kHS17Wrench = 6,
+ kHS17WalkArea1 = 7,
+ kHS17WalkArea2 = 8,
+ kHS17WalkArea3 = 9
+};
+
+enum {
+ kHS18Platypus = 0,
+ kHS18GarbageCan = 1,
+ kHS18Device = 2,
+ kHS18ExitToyStore = 3,
+ kHS18ExitPhoneBooth = 4,
+ kHS18ExitGrubCity = 5,
+ kHS18HydrantTopValve = 6,
+ kHS18HydrantRightValve = 7,
+ kHS18CowboyHat = 8,
+ kHS18WalkArea1 = 9,
+ kHS18WalkArea2 = 10
+};
+
+enum {
+ kHS19Platypus = 0,
+ kHS19ExitOutsideToyStore= 1,
+ kHS19Device = 2,
+ kHS19Picture = 3,
+ kHS19ShopAssistant = 4,
+ kHS19Toy1 = 5,
+ kHS19Toy2 = 6,
+ kHS19Toy3 = 7,
+ kHS19Phone = 8,
+ kHS19Toy4 = 9,
+ kHS19Toy5 = 10,
+ kHS19Toy6 = 11,
+ kHS19Toy7 = 12,
+ kHS19WalkArea1 = 13,
+ kHS19WalkArea2 = 14,
+ kHS19WalkArea3 = 15
+};
+
+enum {
+ kAS10LeaveScene = 0,
+ kAS10AnnoyCook = 1,
+ kAS10PlatWithBox = 4
+};
+
+enum {
+ kAS11LeaveScene = 0,
+ kAS11ShowMagazineToGoggleGuy = 3,
+ kAS11TalkGoggleGuy = 4,
+ kAS11GrabHookGuy = 6,
+ kAS11ShowItemToHookGuy = 8,
+ kAS11TalkHookGuy = 9,
+ kAS11GrabBillardBall = 11
+};
+
+enum {
+ kAS12LeaveScene = 0,
+ kAS12QuarterToToothGuyDone = 1,
+ kAS12TalkToothGuy = 2,
+ kAS12GrabToothGuy = 4,
+ kAS12ShowItemToToothGuy = 5,
+ kAS12QuarterWithHoleToToothGuy = 6,
+ kAS12QuarterToToothGuy = 7,
+ kAS12TalkBeardGuy = 8,
+ kAS12LookBeardGuy = 9,
+ kAS12GrabBeardGuy = 10,
+ kAS12ShowItemToBeardGuy = 11,
+ kAS12TalkBarkeeper = 12,
+ kAS12LookBarkeeper = 13,
+ kAS12ShowItemToBarkeeper = 15,
+ kAS12QuarterWithBarkeeper = 16,
+ kAS12PlatWithBarkeeper = 17,
+ kAS12PlatWithToothGuy = 18,
+ kAS12PlatWithBeardGuy = 19
+};
+
+enum {
+ kAS13LeaveScene = 0,
+ kAS13BackToilet = 1,
+ kAS13FrontToilet = 2,
+ kAS13LookScribble = 6,
+ kAS13GrabSink = 7,
+ kAS13GrabSinkDone = 8,
+ kAS13Wait = 12,
+ kAS13GrabUrinal = 13
+};
+
+enum {
+ kAS17TryGetWrench = 0,
+ kAS17GetWrench2 = 1,
+ kAS17GetWrenchDone = 2,
+ kAS17GetWrench1 = 3,
+ kAS17PlatUsePhone = 4,
+ kAS17PutCoinIntoPhone = 5,
+ kAS17GetCoinFromPhone = 6,
+ kAS17GetCoinFromPhoneDone = 7,
+ kAS17PutCoinIntoPhoneDone = 8,
+ kAS17GnapUsePhone = 9,
+ kAS17GetWrenchGnapReady = 10,
+ kAS17GnapHangUpPhone = 11,
+ kAS17PlatPhoningAssistant = 12,
+ kAS17PlatHangUpPhone = 14,
+ kAS17LeaveScene = 15
+};
+
+enum {
+ kAS18OpenRightValveNoGarbageCanDone = 0,
+ kAS18OpenRightValveNoGarbageCan = 1,
+ kAS18CloseRightValveNoGarbageCan = 2,
+ kAS18OpenTopValveDone = 3,
+ kAS18OpenTopValve = 4,
+ kAS18CloseTopValve = 5,
+ kAS18GrabGarbageCanFromStreet = 6,
+ kAS18GrabCowboyHat = 7,
+ kAS18GrabGarbageCanFromHydrant = 8,
+ kAS18PutGarbageCanOnRunningHydrant = 9,
+ kAS18PutGarbageCanOnRunningHydrant2 = 10,
+ kAS18GrabCowboyHatDone = 11,
+ kAS18StandingOnHydrant = 12,
+ kAS18OpenRightValveWithGarbageCan = 13,
+ kAS18OpenRightValveWithGarbageCanDone = 14,
+ kAS18CloseRightValveWithGarbageCan = 15,
+ kAS18PutGarbageCanOnHydrant = 16,
+ kAS18PutGarbageCanOnHydrantDone = 17,
+ kAS18PlatComesHere = 18,
+ kAS18CloseRightValveWithGarbageCanDone = 19,
+ kAS18LeaveScene = 20
+};
+
+enum {
+ kAS19UsePhone = 0,
+ kAS19GrabToy = 1,
+ kAS19GrabPicture = 2,
+ kAS19GrabPictureDone = 3,
+ kAS19TalkShopAssistant = 4,
+ kAS19LeaveScene = 5
+};
+
+/*****************************************************************************/
+
+class GnapEngine;
+class CutScene;
+
+class Scene10: public Scene {
+public:
+ Scene10(GnapEngine *vm);
+ virtual ~Scene10() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb();
+
+private:
+ int _nextCookSequenceId;
+ int _currCookSequenceId;
+};
+
+class Scene11: public Scene {
+public:
+ Scene11(GnapEngine *vm);
+ virtual ~Scene11() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _billardBallCtr;
+ int _nextHookGuySequenceId;
+ int _currHookGuySequenceId;
+ int _nextGoggleGuySequenceId;
+ int _currGoggleGuySequenceId;
+};
+
+class Scene12: public Scene {
+public:
+ Scene12(GnapEngine *vm);
+ virtual ~Scene12() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _nextBeardGuySequenceId;
+ int _currBeardGuySequenceId;
+ int _nextToothGuySequenceId;
+ int _currToothGuySequenceId;
+ int _nextBarkeeperSequenceId;
+ int _currBarkeeperSequenceId;
+};
+
+class Scene13: public Scene {
+public:
+ Scene13(GnapEngine *vm);
+ virtual ~Scene13() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _backToiletCtr;
+
+ void showScribble();
+};
+
+class Scene14: public Scene {
+public:
+ Scene14(GnapEngine *vm);
+ virtual ~Scene14() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+};
+
+class Scene15: public Scene {
+public:
+ Scene15(GnapEngine *vm);
+ virtual ~Scene15() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _nextRecordSequenceId;
+ int _currRecordSequenceId;
+ int _nextSlotSequenceId;
+ int _currSlotSequenceId;
+ int _nextUpperButtonSequenceId;
+ int _currUpperButtonSequenceId;
+ int _nextLowerButtonSequenceId;
+ int _currLowerButtonSequenceId;
+};
+
+class Scene17: public Scene {
+public:
+ Scene17(GnapEngine *vm);
+ virtual ~Scene17() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ bool _canTryGetWrench;
+ int _wrenchCtr;
+ int _platPhoneCtr;
+ int _platTryGetWrenchCtr;
+ int _nextPhoneSequenceId;
+ int _currPhoneSequenceId;
+ int _nextWrenchSequenceId;
+ int _currWrenchSequenceId;
+ int _nextCarWindowSequenceId;
+ int _currCarWindowSequenceId;
+
+ void update();
+ void platHangUpPhone();
+};
+
+class Scene18: public Scene {
+public:
+ Scene18(GnapEngine *vm);
+ virtual ~Scene18();
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ Graphics::Surface *_cowboyHatSurface;
+
+ int _platPhoneCtr;
+ int _platPhoneIter;
+ int _nextPhoneSequenceId;
+ int _currPhoneSequenceId;
+
+ void gnapCarryGarbageCanTo(int a5);
+ void putDownGarbageCan(int animationIndex);
+ void platEndPhoning(bool platFl);
+ void closeHydrantValve();
+ void waitForGnapAction();
+};
+
+class Scene19: public Scene {
+public:
+ Scene19(GnapEngine *vm);
+ virtual ~Scene19();
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _currShopAssistantSequenceId;
+ int _nextShopAssistantSequenceId;
+ int _toyGrabCtr;
+ int _shopAssistantCtr;
+
+ Graphics::Surface *_pictureSurface;
+};
+
+} // End of namespace Gnap
+
+#endif // GNAP_GROUP1_H
diff --git a/engines/gnap/scenes/group2.cpp b/engines/gnap/scenes/group2.cpp
new file mode 100644
index 0000000000..522a3f4337
--- /dev/null
+++ b/engines/gnap/scenes/group2.cpp
@@ -0,0 +1,3423 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can 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 "gnap/gnap.h"
+#include "gnap/gamesys.h"
+#include "gnap/resource.h"
+#include "gnap/scenes/group2.h"
+
+namespace Gnap {
+
+Scene20::Scene20(GnapEngine *vm) : Scene(vm) {
+ _stonerGuyCtr = 3;
+ _stonerGuyShowingJoint = false;
+ _groceryStoreGuyCtr = 0;
+ _currStonerGuySequenceId = -1;
+ _nextStonerGuySequenceId = -1;
+ _currGroceryStoreGuySequenceId = -1;
+ _nextGroceryStoreGuySequenceId = -1;
+}
+
+int Scene20::init() {
+ return 0x186;
+}
+
+void Scene20::updateHotspots() {
+ _vm->setHotspot(kHS20Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS20GroceryStoreHat, 114, 441, 174, 486, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 0, 7);
+ _vm->setHotspot(kHS20ExitParkingLot, 0, 300, 15, 600, SF_EXIT_L_CURSOR | SF_WALKABLE, 0, 7);
+ _vm->setHotspot(kHS20StonerGuy, 276, 290, 386, 450, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 3, 8);
+ _vm->setHotspot(kHS20GroceryStoreGuy, 123, 282, 258, 462, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 3, 7);
+ _vm->setHotspot(kHS20ExitInsideGrubCity, 519, 250, 581, 413, SF_EXIT_L_CURSOR, 8, 7);
+ _vm->setHotspot(kHS20ExitOutsideCircusWorld, 660, 222, 798, 442, SF_EXIT_NE_CURSOR, 9, 6);
+ _vm->setHotspot(kHS20ExitOutsideToyStore, 785, 350, 800, 600, SF_EXIT_R_CURSOR, 11, 8);
+ _vm->setHotspot(kHS20ExitPhone, 250, 585, 650, 600, SF_EXIT_D_CURSOR | SF_WALKABLE, 5, 10);
+ _vm->setHotspot(kHS20WalkArea1, 0, 0, 800, 468);
+ _vm->setHotspot(kHS20WalkArea2, 605, 0, 800, 600);
+ _vm->setDeviceHotspot(kHS20Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 12;
+}
+
+void Scene20::updateAnimationsCb() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(2) == 2) {
+ switch (_nextStonerGuySequenceId) {
+ case 0x16B:
+ if (!_vm->_timers[4]) {
+ _stonerGuyShowingJoint = false;
+ gameSys.insertSequence(0x16B, 21, _currStonerGuySequenceId, 21, kSeqSyncWait, 0, 0, 0);
+ _currStonerGuySequenceId = 0x16B;
+ _nextStonerGuySequenceId = -1;
+ }
+ break;
+ case 0x16A:
+ // Grab joint
+ gnap.playPullOutDevice(Common::Point(4, 4));
+ gnap.playUseDevice();
+ gameSys.setAnimation(0x16A, 21, 0);
+ gameSys.insertSequence(0x16A, 21, _currStonerGuySequenceId, 21, kSeqSyncWait, 0, 0, 0);
+ _currStonerGuySequenceId = 0x16A;
+ _nextStonerGuySequenceId = -1;
+ _vm->invAdd(kItemJoint);
+ _vm->setFlag(kGFJointTaken);
+ _stonerGuyShowingJoint = false;
+ gnap._actionStatus = kAS20GrabJointDone;
+ break;
+ case 0x16E:
+ gameSys.setAnimation(0x16E, 21, 2);
+ gameSys.insertSequence(0x16E, 21, _currStonerGuySequenceId, 21, kSeqSyncWait, 0, 0, 0);
+ _currStonerGuySequenceId = 0x16E;
+ _nextStonerGuySequenceId = -1;
+ _nextGroceryStoreGuySequenceId = 0x175;
+ break;
+ case 0x16D:
+ gameSys.setAnimation(_nextStonerGuySequenceId, 21, 2);
+ gameSys.setAnimation(_nextStonerGuySequenceId, 21, 0);
+ gameSys.insertSequence(_nextStonerGuySequenceId, 21, _currStonerGuySequenceId, 21, kSeqSyncWait, 0, 0, 0);
+ _currStonerGuySequenceId = _nextStonerGuySequenceId;
+ _nextStonerGuySequenceId = -1;
+ gnap._actionStatus = kAS20ActionDone;
+ break;
+ case 0x16F:
+ gameSys.setAnimation(_nextStonerGuySequenceId, 21, 2);
+ gameSys.setAnimation(0x17A, 20, 3);
+ gameSys.insertSequence(_nextStonerGuySequenceId, 21, _currStonerGuySequenceId, 21, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x17A, 20, _currGroceryStoreGuySequenceId, 20, kSeqSyncWait, 0, 0, 0);
+ _currGroceryStoreGuySequenceId = 0x17A;
+ _nextGroceryStoreGuySequenceId = -1;
+ _currStonerGuySequenceId = _nextStonerGuySequenceId;
+ _nextStonerGuySequenceId = -1;
+ break;
+ case 0x171:
+ _stonerGuyCtr = (_stonerGuyCtr + 1) % 3;
+ switch (_stonerGuyCtr) {
+ case 1:
+ _nextStonerGuySequenceId = 0x171;
+ break;
+ case 2:
+ _nextStonerGuySequenceId = 0x172;
+ break;
+ case 3:
+ _nextStonerGuySequenceId = 0x173;
+ break;
+ default:
+ _nextStonerGuySequenceId = 0x171;
+ break;
+ }
+ gameSys.insertSequence(_nextStonerGuySequenceId, 21, _currStonerGuySequenceId, 21, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x17C, 20, _currGroceryStoreGuySequenceId, 20, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(0x17C, 20, 3);
+ gameSys.setAnimation(_nextStonerGuySequenceId, 21, 2);
+ _currGroceryStoreGuySequenceId = 0x17C;
+ _nextGroceryStoreGuySequenceId = -1;
+ _currStonerGuySequenceId = _nextStonerGuySequenceId;
+ _nextStonerGuySequenceId = -1;
+ break;
+ default:
+ _nextStonerGuySequenceId = 0x16C;
+ gameSys.setAnimation(0x16C, 21, 2);
+ gameSys.insertSequence(_nextStonerGuySequenceId, 21, _currStonerGuySequenceId, 21, kSeqSyncWait, 0, 0, 0);
+ _currStonerGuySequenceId = _nextStonerGuySequenceId;
+ _nextStonerGuySequenceId = -1;
+ break;
+ }
+ }
+}
+
+void Scene20::stopSounds() {
+ _vm->stopSound(0x18E);
+ _vm->stopSound(0x18F);
+ _vm->stopSound(0x190);
+ _vm->stopSound(0x191);
+ _vm->stopSound(0x194);
+ _vm->stopSound(0x195);
+ _vm->stopSound(0x192);
+ _vm->stopSound(0x193);
+ _vm->stopSound(0x196);
+ _vm->stopSound(0x197);
+ _vm->stopSound(0x198);
+ _vm->stopSound(0x199);
+ _vm->stopSound(0x19A);
+}
+
+void Scene20::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->playSound(0x10940, true);
+ _vm->startSoundTimerA(8);
+
+ _stonerGuyShowingJoint = false;
+ _vm->_timers[7] = _vm->getRandom(100) + 100;
+
+ _stonerGuyCtr = (_stonerGuyCtr + 1) % 3;
+ switch (_stonerGuyCtr) {
+ case 1:
+ _currStonerGuySequenceId = 0x171;
+ break;
+ case 2:
+ _currStonerGuySequenceId = 0x172;
+ break;
+ case 3:
+ _currStonerGuySequenceId = 0x173;
+ break;
+ }
+
+ _nextStonerGuySequenceId = -1;
+ gameSys.setAnimation(_currStonerGuySequenceId, 21, 2);
+ gameSys.insertSequence(_currStonerGuySequenceId, 21, 0, 0, kSeqNone, 0, 0, 0);
+
+ _vm->_timers[6] = _vm->getRandom(20) + 30;
+
+ _currGroceryStoreGuySequenceId = 0x17C;
+ _nextGroceryStoreGuySequenceId = -1;
+ gameSys.setAnimation(0x17C, 20, 3);
+ gameSys.insertSequence(0x17C, 20, 0, 0, kSeqNone, 0, 0, 0);
+
+ _vm->_timers[5] = _vm->getRandom(50) + 130;
+ if (_vm->isFlag(kGFGroceryStoreHatTaken))
+ gameSys.insertSequence(0x17F, 20, 0, 0, kSeqNone, 0, 0, 0);
+ else
+ gameSys.insertSequence(0x174, 20, 0, 0, kSeqNone, 0, 0, 0);
+
+ _vm->queueInsertDeviceIcon();
+
+ if (_vm->isFlag(kGFSceneFlag1)) {
+ _vm->clearFlag(kGFSceneFlag1);
+ _vm->endSceneInit();
+ gameSys.setAnimation(0x182, 140, 0);
+ gameSys.insertSequence(0x182, 140, 0, 0, kSeqNone, 0, 0, 0);
+ while (gameSys.getAnimationStatus(0) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+
+ gnap.initPos(11, 8, kDirBottomLeft);
+ plat.initPos(11, 9, kDirIdleRight);
+ gnap.walkTo(Common::Point(5, 8), -1, 0x107BA, 1);
+ plat.walkTo(Common::Point(6, 9), -1, 0x107C2, 1);
+ } else {
+ switch (_vm->_prevSceneNum) {
+ case 17:
+ gnap.initPos(5, 11, kDirBottomRight);
+ plat.initPos(6, 11, kDirIdleLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(5, 8), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(6, 9), -1, 0x107C2, 1);
+ break;
+ case 18:
+ gnap.initPos(11, 8, kDirBottomLeft);
+ plat.initPos(11, 9, kDirIdleRight);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(5, 8), -1, 0x107BA, 1);
+ plat.walkTo(Common::Point(6, 9), -1, 0x107C2, 1);
+ break;
+ case 21:
+ gnap.initPos(-1, 8, kDirBottomLeft);
+ plat.initPos(-1, 9, kDirIdleRight);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(3, 8), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(3, 9), -1, 0x107C2, 1);
+ break;
+ case 22:
+ gnap.initPos(7, 6, kDirBottomRight);
+ plat.initPos(8, 6, kDirIdleLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(8, 8), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(9, 9), -1, 0x107C2, 1);
+ break;
+ default:
+ gnap.initPos(8, 6, kDirBottomLeft);
+ plat.initPos(9, 6, kDirIdleRight);
+ _vm->endSceneInit();
+ _vm->_hotspots[kHS20WalkArea2]._flags |= SF_WALKABLE;
+ gnap.walkTo(Common::Point(8, 8), -1, 0x107BA, 1);
+ plat.walkTo(Common::Point(9, 9), -1, 0x107C2, 1);
+ _vm->_hotspots[kHS20WalkArea2]._flags &= ~SF_WALKABLE;
+ break;
+ }
+ }
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->testWalk(0, 0, -1, -1, -1, -1);
+ _vm->testWalk(0, 1, 7, 9, 8, 9);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS20Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS20Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemJoint) {
+ gnap.useJointOnPlatypus();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(20);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS20ExitParkingLot:
+ if (gnap._actionStatus < 0) {
+ if (_stonerGuyShowingJoint)
+ _vm->_timers[4] = 0;
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 21;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS20ExitParkingLot], 0, 0x107AF, 1);
+ gnap._actionStatus = kAS20LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS20ExitParkingLot] + Common::Point(0, 1), -1, 0x107CF, 1);
+ plat._idleFacing = kDirIdleRight;
+ }
+ break;
+
+ case kHS20ExitPhone:
+ if (gnap._actionStatus < 0) {
+ if (_stonerGuyShowingJoint)
+ _vm->_timers[4] = 0;
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 17;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS20ExitPhone], 0, 0x107AE, 1);
+ gnap._actionStatus = kAS20LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS20ExitPhone] + Common::Point(1, 0), -1, 0x107C2, 1);
+ }
+ break;
+
+ case kHS20ExitOutsideToyStore:
+ if (gnap._actionStatus < 0) {
+ if (_stonerGuyShowingJoint)
+ _vm->_timers[4] = 0;
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 18;
+ _vm->_hotspots[kHS20WalkArea2]._flags |= SF_WALKABLE;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS20ExitOutsideToyStore], 0, 0x107AB, 1);
+ gnap._actionStatus = kAS20LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS20ExitOutsideToyStore] + Common::Point(0, 1), -1, 0x107CD, 1);
+ _vm->_hotspots[kHS20WalkArea2]._flags &= ~SF_WALKABLE;
+ }
+ break;
+
+ case kHS20ExitInsideGrubCity:
+ if (gnap._actionStatus < 0) {
+ if (_stonerGuyShowingJoint)
+ _vm->_timers[4] = 0;
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 22;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS20ExitInsideGrubCity] + Common::Point(0, - 1), 0, 0x107BB, 1);
+ gnap._actionStatus = kAS20LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS20ExitInsideGrubCity] + Common::Point(1, 0), -1, 0x107C2, 1);
+ plat._idleFacing = kDirIdleRight;
+ }
+ break;
+
+ case kHS20ExitOutsideCircusWorld:
+ if (gnap._actionStatus < 0) {
+ if (_stonerGuyShowingJoint)
+ _vm->_timers[4] = 0;
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 24;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS20ExitOutsideCircusWorld], 0, 0x107BB, 1);
+ gnap._actionStatus = kAS20LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS20ExitOutsideCircusWorld] + Common::Point(1, 0), -1, 0x107C2, 1);
+ }
+ break;
+
+ case kHS20StonerGuy:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS20StonerGuy], 5, 4);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan2(Common::Point(5, 4));
+ break;
+ case GRAB_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS20StonerGuy], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ if (_stonerGuyShowingJoint)
+ gnap._actionStatus = kAS20GrabJoint;
+ else
+ gnap.playImpossible();
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS20StonerGuy], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ if (_vm->isFlag(kGFJointTaken))
+ gnap._actionStatus = kAS20TalkStonerGuyNoJoint;
+ else
+ gnap._actionStatus = kAS20TalkStonerGuyHasJoint;
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS20GroceryStoreGuy:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS20GroceryStoreGuy], 2, 4);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(2, 3));
+ break;
+ case GRAB_CURSOR:
+ _stonerGuyShowingJoint = false;
+ gnap._idleFacing = kDirUpLeft;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS20GroceryStoreGuy], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS20GrabGroceryStoreGuy;
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpLeft;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS20GroceryStoreGuy], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS20TalkGroceryStoreGuy;
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS20GroceryStoreHat:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemCowboyHat) {
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS20GroceryStoreHat], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS20SwitchGroceryStoreHat;
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS20GroceryStoreHat], 1, 6);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(1, 6));
+ break;
+ case GRAB_CURSOR:
+ _stonerGuyShowingJoint = false;
+ gnap._idleFacing = kDirUpLeft;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS20GroceryStoreGuy], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS20GrabGroceryStoreHat;
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS20WalkArea1:
+ case kHS20WalkArea2:
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+
+ }
+
+ updateAnimations();
+
+ if (!_vm->isSoundPlaying(0x10940))
+ _vm->playSound(0x10940, true);
+
+ if (!_vm->_isLeavingScene) {
+ if (plat._actionStatus < 0) {
+ _vm->_hotspots[kHS20WalkArea1]._rect.bottom += 48;
+ plat.updateIdleSequence();
+ _vm->_hotspots[kHS20WalkArea1]._rect.bottom -= 48;
+ }
+ if (gnap._actionStatus < 0)
+ gnap.updateIdleSequence();
+ if (gnap._actionStatus < 0 && !_vm->_timers[5] && _nextGroceryStoreGuySequenceId == -1) {
+ _vm->_timers[5] = _vm->getRandom(50) + 130;
+ if (_vm->getRandom(4) != 0)
+ _nextGroceryStoreGuySequenceId = 0x17C;
+ else
+ _nextGroceryStoreGuySequenceId = 0x17A;
+ }
+ if (!_vm->_timers[7]) {
+ _vm->_timers[7] = _vm->getRandom(100) + 100;
+ if (gnap._actionStatus < 0 && plat._actionStatus < 0) {
+ switch (_vm->getRandom(3)) {
+ case 0:
+ gameSys.insertSequence(0x183, 253, 0, 0, kSeqNone, 0, 0, 0);
+ break;
+ case 1:
+ gameSys.insertSequence(0x184, 253, 0, 0, kSeqNone, 0, 0, 0);
+ break;
+ case 2:
+ gameSys.insertSequence(0x185, 253, 0, 0, kSeqNone, 0, 0, 0);
+ break;
+ }
+ }
+ }
+ _vm->playSoundA();
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene20::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS20LeaveScene:
+ _vm->_sceneDone = true;
+ break;
+ case kAS20TalkStonerGuyNoJoint:
+ gameSys.setAnimation(0x170, 21, 2);
+ gameSys.setAnimation(0x17B, 20, 3);
+ gameSys.insertSequence(0x17B, 20, _currGroceryStoreGuySequenceId, 20, kSeqSyncExists, 0, 0, 0);
+ gameSys.insertSequence(0x170, 21, _currStonerGuySequenceId, 21, kSeqSyncExists, 0, 0, 0);
+ _vm->stopSound(0x1A1);
+ stopSounds();
+ _currGroceryStoreGuySequenceId = 0x17B;
+ _currStonerGuySequenceId = 0x170;
+ _nextGroceryStoreGuySequenceId = -1;
+ _nextStonerGuySequenceId = 0x16E;
+ _vm->_timers[5] = 100;
+ _vm->_timers[6] = 100;
+ break;
+ case kAS20TalkStonerGuyHasJoint:
+ gameSys.setAnimation(0x168, 21, 2);
+ gameSys.setAnimation(379, 20, 3);
+ gameSys.insertSequence(0x17B, 20, _currGroceryStoreGuySequenceId, 20, kSeqSyncExists, 0, 0, 0);
+ gameSys.insertSequence(0x170, 21, _currStonerGuySequenceId, 21, kSeqSyncExists, 0, 0, 0);
+ gameSys.insertSequence(0x168, 21, 0x170, 21, kSeqSyncWait, 0, 0, 0);
+ _vm->stopSound(0x1A1);
+ stopSounds();
+ _currGroceryStoreGuySequenceId = 0x17B;
+ _currStonerGuySequenceId = 0x168;
+ _nextGroceryStoreGuySequenceId = -1;
+ _nextStonerGuySequenceId = 0x16B;
+ _vm->_timers[5] = 200;
+ _vm->_timers[6] = 200;
+ _vm->_timers[4] = 100;
+ _stonerGuyShowingJoint = true;
+ gnap._actionStatus = -1;
+ break;
+ case kAS20GrabJoint:
+ _nextStonerGuySequenceId = 0x16A;
+ break;
+ case kAS20ActionDone:
+ gnap._actionStatus = -1;
+ break;
+ case kAS20TalkGroceryStoreGuy:
+ gameSys.setAnimation(0x170, 21, 2);
+ gameSys.setAnimation(0x17B, 20, 3);
+ gameSys.insertSequence(0x17B, 20, _currGroceryStoreGuySequenceId, 20, kSeqSyncExists, 0, 0, 0);
+ gameSys.insertSequence(0x170, 21, _currStonerGuySequenceId, 21, kSeqSyncExists, 0, 0, 0);
+ _vm->stopSound(0x1A1);
+ stopSounds();
+ _currGroceryStoreGuySequenceId = 0x17B;
+ _currStonerGuySequenceId = 0x170;
+ _groceryStoreGuyCtr = (_groceryStoreGuyCtr + 1) % 2;
+ if (_groceryStoreGuyCtr != 0)
+ _nextGroceryStoreGuySequenceId = 0x176;
+ else
+ _nextGroceryStoreGuySequenceId = 0x177;
+ _vm->_timers[5] = 100;
+ _vm->_timers[6] = 100;
+ break;
+ case kAS20GrabGroceryStoreGuy:
+ gameSys.setAnimation(0x170, 21, 2);
+ gameSys.setAnimation(0x17B, 20, 3);
+ gameSys.insertSequence(0x170, 21, _currStonerGuySequenceId, 21, kSeqSyncExists, 0, 0, 0);
+ gameSys.insertSequence(0x17B, 20, _currGroceryStoreGuySequenceId, 20, kSeqSyncExists, 0, 0, 0);
+ _vm->stopSound(0x1A1);
+ stopSounds();
+ _currGroceryStoreGuySequenceId = 0x17B;
+ _currStonerGuySequenceId = 0x170;
+ _vm->_timers[5] = 120;
+ _vm->_timers[6] = 120;
+ _nextGroceryStoreGuySequenceId = 0x178;
+ break;
+ case kAS20GrabGroceryStoreHat:
+ gameSys.setAnimation(0x170, 21, 2);
+ gameSys.setAnimation(0x17B, 20, 3);
+ gameSys.insertSequence(0x17B, 20, _currGroceryStoreGuySequenceId, 20, kSeqSyncExists, 0, 0, 0);
+ gameSys.insertSequence(0x170, 21, _currStonerGuySequenceId, 21, kSeqSyncExists, 0, 0, 0);
+ _vm->stopSound(0x1A1);
+ stopSounds();
+ _currGroceryStoreGuySequenceId = 0x17B;
+ _currStonerGuySequenceId = 0x170;
+ _nextGroceryStoreGuySequenceId = 0x179;
+ break;
+ case kAS20SwitchGroceryStoreHat:
+ _vm->setGrabCursorSprite(-1);
+ gameSys.setAnimation(0x180, gnap._id, 0);
+ gameSys.insertSequence(0x180, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x180;
+ gnap._sequenceDatNum = 0;
+ _vm->invRemove(kItemCowboyHat);
+ _vm->invAdd(kItemGroceryStoreHat);
+ gnap._actionStatus = kAS20SwitchGroceryStoreHatDone;
+ break;
+ case kAS20SwitchGroceryStoreHatDone:
+ gameSys.insertSequence(0x17F, 20, 372, 20, kSeqSyncWait, 0, 0, 0);
+ _vm->setFlag(kGFGroceryStoreHatTaken);
+ _vm->hideCursor();
+ _vm->setGrabCursorSprite(-1);
+ _vm->addFullScreenSprite(0x12C, 255);
+ gameSys.setAnimation(0x181, 256, 0);
+ gameSys.insertSequence(0x181, 256, 0, 0, kSeqNone, 0, 0, 0);
+ while (gameSys.getAnimationStatus(0) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+ _vm->removeFullScreenSprite();
+ _vm->showCursor();
+ _vm->setGrabCursorSprite(kItemGroceryStoreHat);
+ gnap._idleFacing = kDirBottomRight;
+ gnap.walkTo(Common::Point(3, 8), -1, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = -1;
+ break;
+ case kAS20GrabJointDone:
+ _vm->setGrabCursorSprite(kItemJoint);
+ gnap._actionStatus = -1;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2) {
+ switch (_nextGroceryStoreGuySequenceId) {
+ case 0x176:
+ case 0x177:
+ gameSys.setAnimation(_nextGroceryStoreGuySequenceId, 20, 3);
+ gameSys.insertSequence(_nextGroceryStoreGuySequenceId, 20, _currGroceryStoreGuySequenceId, 20, kSeqSyncWait, 0, 0, 0);
+ _currGroceryStoreGuySequenceId = _nextGroceryStoreGuySequenceId;
+ _nextGroceryStoreGuySequenceId = -1;
+ _nextStonerGuySequenceId = 0x16D;
+ break;
+ case 0x178:
+ gameSys.setAnimation(_nextGroceryStoreGuySequenceId, 20, 3);
+ gameSys.setAnimation(0x17D, gnap._id, 0);
+ gameSys.insertSequence(_nextGroceryStoreGuySequenceId, 20, _currGroceryStoreGuySequenceId, 20, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x17D, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x17D;
+ gnap._sequenceDatNum = 0;
+ gnap._actionStatus = kAS20ActionDone;
+ gameSys.setAnimation(0x16D, 21, 2);
+ gameSys.insertSequence(0x16D, 21, _currStonerGuySequenceId, 21, kSeqSyncWait, 0, 0, 0);
+ _currStonerGuySequenceId = 0x16D;
+ _currGroceryStoreGuySequenceId = 0x178;
+ _nextGroceryStoreGuySequenceId = -1;
+ _nextStonerGuySequenceId = -1;
+ break;
+ case 0x179:
+ gameSys.setAnimation(_nextGroceryStoreGuySequenceId, 20, 3);
+ gameSys.setAnimation(0x16D, 21, 0);
+ gameSys.insertSequence(_nextGroceryStoreGuySequenceId, 20, _currGroceryStoreGuySequenceId, 20, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x17E, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x17E;
+ gnap._sequenceDatNum = 0;
+ gnap._actionStatus = kAS20ActionDone;
+ gameSys.setAnimation(0x16D, 21, 2);
+ gameSys.insertSequence(0x16D, 21, _currStonerGuySequenceId, 21, kSeqSyncWait, 0, 0, 0);
+ _currStonerGuySequenceId = 0x16D;
+ _currGroceryStoreGuySequenceId = 377;
+ _nextGroceryStoreGuySequenceId = -1;
+ _nextStonerGuySequenceId = -1;
+ gnap.walkTo(Common::Point(4, 8), -1, 0x107BB, 1);
+ break;
+ case 0x17C:
+ gameSys.setAnimation(0, 0, 3);
+ _nextStonerGuySequenceId = 0x171;
+ break;
+ case 0x17A:
+ gameSys.setAnimation(0, 0, 3);
+ _nextStonerGuySequenceId = 0x16F;
+ break;
+ case 0x175:
+ gameSys.setAnimation(0x175, 20, 0);
+ gameSys.setAnimation(0x175, 20, 3);
+ gameSys.insertSequence(0x175, 20, _currGroceryStoreGuySequenceId, 20, kSeqSyncWait, 0, 0, 0);
+ _currGroceryStoreGuySequenceId = 0x175;
+ _nextGroceryStoreGuySequenceId = -1;
+ gnap._actionStatus = kAS20ActionDone;
+ break;
+ default:
+ if (_nextGroceryStoreGuySequenceId != -1) {
+ gameSys.setAnimation(_nextGroceryStoreGuySequenceId, 20, 3);
+ gameSys.insertSequence(_nextGroceryStoreGuySequenceId, 20, _currGroceryStoreGuySequenceId, 20, kSeqSyncWait, 0, 0, 0);
+ _currGroceryStoreGuySequenceId = _nextGroceryStoreGuySequenceId;
+ _nextGroceryStoreGuySequenceId = -1;
+ }
+ break;
+ }
+ }
+
+ updateAnimationsCb();
+}
+
+/*****************************************************************************/
+
+Scene21::Scene21(GnapEngine *vm) : Scene(vm) {
+ _currOldLadySequenceId = -1;
+ _nextOldLadySequenceId = -1;
+}
+
+int Scene21::init() {
+ _vm->_gameSys->setAnimation(0, 0, 3);
+
+ return _vm->isFlag(kGFTwigTaken) ? 0x94 : 0x93;
+}
+
+void Scene21::updateHotspots() {
+ _vm->setHotspot(kHS21Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS21Banana, 94, 394, 146, 430, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 2, 6);
+ _vm->setHotspot(kHS21OldLady, 402, 220, 528, 430, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 4, 7);
+ _vm->setHotspot(kHS21ExitOutsideGrubCity, 522, 498, 800, 600, SF_EXIT_SE_CURSOR | SF_WALKABLE, 5, 10);
+ _vm->setHotspot(kHS21WalkArea1, 0, 0, 800, 440);
+ _vm->setHotspot(kHS21WalkArea2, 698, 0, 800, 600);
+ _vm->setDeviceHotspot(kHS21Device, -1, -1, -1, -1);
+ if (_vm->isFlag(kGFUnk04) || !_vm->isFlag(kGFTwigTaken))
+ _vm->_hotspots[kHS21Banana]._flags = SF_WALKABLE | SF_DISABLED;
+ if (_vm->isFlag(kGFTwigTaken))
+ _vm->_hotspots[kHS21OldLady]._flags = SF_DISABLED;
+ _vm->_hotspotsCount = 7;
+}
+
+void Scene21::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->playSound(0x10940, true);
+ _vm->startSoundTimerA(6);
+ _vm->_timers[5] = _vm->getRandom(100) + 100;
+ _vm->queueInsertDeviceIcon();
+
+ if (_vm->isFlag(kGFTwigTaken)) {
+ if (_vm->isFlag(kGFKeysTaken)) {
+ gnap.initPos(5, 8, kDirBottomRight);
+ plat.initPos(6, 8, kDirIdleLeft);
+ gameSys.insertSequence(0x8E, 2, 0, 0, kSeqNone, 0, 0, 0);
+ if (!_vm->isFlag(kGFUnk04))
+ gameSys.insertSequence(0x8D, 59, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->endSceneInit();
+ _vm->clearFlag(kGFKeysTaken);
+ } else {
+ gnap.initPos(5, 11, kDirBottomRight);
+ plat.initPos(6, 11, kDirIdleLeft);
+ if (!_vm->isFlag(kGFUnk04))
+ gameSys.insertSequence(0x8D, 59, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(5, 8), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(6, 8), -1, 0x107C2, 1);
+ }
+ } else {
+ gnap.initPos(5, 11, kDirBottomRight);
+ plat.initPos(6, 11, kDirIdleLeft);
+ _currOldLadySequenceId = 0x89;
+ gameSys.setAnimation(0x89, 79, 3);
+ gameSys.insertSequence(_currOldLadySequenceId, 79, 0, 0, kSeqNone, 0, 0, 0);
+ _nextOldLadySequenceId = -1;
+ _vm->_timers[4] = _vm->getRandom(30) + 50;
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(5, 8), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(6, 8), -1, 0x107C2, 1);
+ }
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS21Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS21Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemJoint) {
+ gnap.useJointOnPlatypus();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS21Banana:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowItem(_vm->_grabCursorSpriteIndex, 2, 5);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(2, 5));
+ break;
+ case GRAB_CURSOR:
+ gnap.walkTo(gnap._pos, 0, gnap.getSequenceId(kGSIdle, _vm->_hotspotsWalkPos[kHS21Banana]) | 0x10000, 1);
+ gnap.playPullOutDevice(Common::Point(2, 5));
+ gnap.playUseDevice();
+ gnap._actionStatus = kAS21GrabBanana;
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS21OldLady:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemGroceryStoreHat) {
+ _vm->_newSceneNum = 47;
+ gnap.walkTo(Common::Point(4, 6), 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS21UseHatWithOldLady;
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(4, 6), 7, 4);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(7, 4));
+ break;
+ case GRAB_CURSOR:
+ gnap._idleFacing = kDirUpLeft;
+ _vm->_hotspots[kHS21WalkArea1]._flags |= SF_WALKABLE;
+ gnap.walkTo(Common::Point(7, 6), 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS21GrabOldLady;
+ _vm->_hotspots[kHS21WalkArea1]._flags &= ~SF_WALKABLE;
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS21OldLady], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS21TalkOldLady;
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS21ExitOutsideGrubCity:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 20;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS21ExitOutsideGrubCity], 0, 0x107B3, 1);
+ gnap._actionStatus = kAS21LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS21ExitOutsideGrubCity] + Common::Point(1, 0), -1, 0x107C2, 1);
+ }
+ break;
+
+ case kHS21WalkArea1:
+ case kHS21WalkArea2:
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+
+ }
+
+ updateAnimations();
+
+ if (!_vm->isSoundPlaying(0x10940))
+ _vm->playSound(0x10940, true);
+
+ if (!_vm->_isLeavingScene) {
+ plat.updateIdleSequence();
+ gnap.updateIdleSequence();
+ if (!_vm->isFlag(kGFTwigTaken) && !_vm->_timers[4] && _nextOldLadySequenceId == -1 && gnap._actionStatus == -1) {
+ _vm->_timers[4] = _vm->getRandom(30) + 50;
+ switch (_vm->getRandom(5)) {
+ case 0:
+ _nextOldLadySequenceId = 0x88;
+ break;
+ case 1:
+ _nextOldLadySequenceId = 0x8A;
+ break;
+ default:
+ _nextOldLadySequenceId = 0x89;
+ break;
+ }
+ }
+ if (!_vm->_timers[5]) {
+ _vm->_timers[5] = _vm->getRandom(100) + 100;
+ gameSys.insertSequence(0x92, 255, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ _vm->playSoundA();
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene21::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS21TalkOldLady:
+ _nextOldLadySequenceId = 0x8B;
+ gnap._actionStatus = -1;
+ break;
+ case kAS21GrabBanana:
+ gameSys.setAnimation(0x8C, 59, 0);
+ gameSys.insertSequence(0x8C, 59, 141, 59, kSeqSyncWait, 0, 0, 0);
+ _vm->setFlag(kGFUnk04);
+ _vm->invAdd(kItemBanana);
+ updateHotspots();
+ gnap._actionStatus = kAS21GrabBananaDone;
+ break;
+ case kAS21GrabBananaDone:
+ _vm->setGrabCursorSprite(kItemBanana);
+ gnap._actionStatus = -1;
+ break;
+ case kAS21GrabOldLady:
+ _vm->_timers[4] = _vm->getRandom(30) + 50;
+ _nextOldLadySequenceId = 0x87;
+ break;
+ case kAS21UseHatWithOldLady:
+ gameSys.setAnimation(0x8F, gnap._id, 0);
+ gameSys.insertSequence(0x8F, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceDatNum = 0;
+ gnap._sequenceId = 0x8F;
+ gnap._actionStatus = kAS21UseHatWithOldLadyDone;
+ _vm->invAdd(kItemTickets);
+ _vm->invRemove(kItemGroceryStoreHat);
+ _vm->setGrabCursorSprite(-1);
+ break;
+ case kAS21UseHatWithOldLadyDone:
+ _nextOldLadySequenceId = 0x91;
+ break;
+ case kAS21LeaveScene:
+ _vm->_sceneDone = true;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2 && _nextOldLadySequenceId != -1) {
+ if (_nextOldLadySequenceId == 0x87) {
+ gameSys.setAnimation(_nextOldLadySequenceId, 79, 3);
+ gameSys.insertSequence(_nextOldLadySequenceId, 79, _currOldLadySequenceId, 79, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x86, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x86;
+ gnap._sequenceDatNum = 0;
+ gnap._actionStatus = -1;
+ _currOldLadySequenceId = _nextOldLadySequenceId;
+ _nextOldLadySequenceId = -1;
+ } else if (_nextOldLadySequenceId == 0x91) {
+ gameSys.setAnimation(0x91, 79, 0);
+ gameSys.insertSequence(_nextOldLadySequenceId, 79, _currOldLadySequenceId, 79, kSeqSyncWait, 0, 0, 0);
+ gnap._actionStatus = kAS21LeaveScene;
+ _currOldLadySequenceId = _nextOldLadySequenceId;
+ _nextOldLadySequenceId = -1;
+ } else {
+ gameSys.setAnimation(_nextOldLadySequenceId, 79, 3);
+ gameSys.insertSequence(_nextOldLadySequenceId, 79, _currOldLadySequenceId, 79, kSeqSyncWait, 0, 0, 0);
+ _currOldLadySequenceId = _nextOldLadySequenceId;
+ _nextOldLadySequenceId = -1;
+ }
+ }
+}
+
+/*****************************************************************************/
+
+Scene22::Scene22(GnapEngine *vm) : Scene(vm) {
+ _caughtBefore = false;
+ _cashierCtr = 3;
+ _nextCashierSequenceId = -1;
+}
+
+int Scene22::init() {
+ return 0x5E;
+}
+
+void Scene22::updateHotspots() {
+ _vm->setHotspot(kHS22Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS22ExitOutsideGrubCity, 0, 180, 184, 472, SF_EXIT_L_CURSOR, 3, 6);
+ _vm->setHotspot(kHS22ExitBackGrubCity, 785, 405, 800, 585, SF_EXIT_R_CURSOR, 11, 9);
+ _vm->setHotspot(kHS22Cashier, 578, 230, 660, 376, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 6, 8);
+ _vm->setHotspot(kHS22WalkArea1, 553, 0, 800, 542);
+ _vm->setHotspot(kHS22WalkArea2, 0, 0, 552, 488);
+ _vm->setDeviceHotspot(kHS22Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 7;
+}
+
+void Scene22::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ gameSys.insertSequence(0x5D, 254, 0, 0, kSeqNone, 0, 0, 0);
+
+ _currCashierSequenceId = 0x59;
+ _nextCashierSequenceId = -1;
+
+ gameSys.setAnimation(0x59, 1, 3);
+ gameSys.insertSequence(_currCashierSequenceId, 1, 0, 0, kSeqNone, 0, 0, 0);
+
+ _vm->_timers[6] = _vm->getRandom(30) + 20;
+
+ _vm->queueInsertDeviceIcon();
+
+ if (_vm->_prevSceneNum == 20) {
+ gnap.initPos(2, 8, kDirBottomRight);
+ plat.initPos(1, 8, kDirIdleLeft);
+ _vm->endSceneInit();
+ } else {
+ gnap.initPos(11, _vm->_hotspotsWalkPos[kHS22ExitBackGrubCity].y, kDirBottomRight);
+ plat.initPos(11, _vm->_hotspotsWalkPos[kHS22ExitBackGrubCity].y + 1, kDirIdleLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(8, 8), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(9, 8), -1, 0x107C2, 1);
+ }
+
+ if (_vm->isFlag(kGFSceneFlag1)) {
+ int storeDetectiveSeqId;
+ _vm->setGrabCursorSprite(-1);
+ _vm->invRemove(kItemCereals);
+ if (_caughtBefore) {
+ switch (_vm->getRandom(3)) {
+ case 0:
+ storeDetectiveSeqId = 0x55;
+ break;
+ case 1:
+ storeDetectiveSeqId = 0x56;
+ break;
+ default:
+ storeDetectiveSeqId = 0x57;
+ break;
+ }
+ } else {
+ _caughtBefore = true;
+ storeDetectiveSeqId = 0x54;
+ }
+ gameSys.waitForUpdate();
+ gameSys.requestClear1();
+ gameSys.drawSpriteToBackground(0, 0, 0x44);
+ gameSys.setAnimation(storeDetectiveSeqId, 256, 4);
+ gameSys.insertSequence(storeDetectiveSeqId, 256, 0, 0, kSeqNone, 0, 0, 0);
+ while (gameSys.getAnimationStatus(4) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+
+ _vm->_sceneDone = true;
+ _vm->_newSceneNum = 20;
+ _caughtBefore = true;
+ }
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->testWalk(0, 0, -1, -1, -1, -1);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS22Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS22Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemJoint) {
+ gnap.useJointOnPlatypus();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS22ExitOutsideGrubCity:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 20;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS22ExitOutsideGrubCity], 0, 0x107AF, 1);
+ gnap._actionStatus = kAS22LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS22ExitOutsideGrubCity] + Common::Point(0, 1), -1, 0x107C2, 1);
+ }
+ break;
+
+ case kHS22ExitBackGrubCity:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 23;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS22ExitBackGrubCity], 0, 0x107AB, 1);
+ gnap._actionStatus = kAS22LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS22ExitBackGrubCity] + Common::Point(0, 1), -1, 0x107C2, 1);
+ }
+ break;
+
+ case kHS22Cashier:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS22Cashier], 8, 4);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(8, 4));
+ break;
+ case GRAB_CURSOR:
+ gnap.playImpossible();
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS22Cashier], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS22TalkCashier;
+ break;
+ case PLAT_CURSOR:
+ gnap.useDeviceOnPlatypus();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS22WalkArea1:
+ case kHS22WalkArea2:
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+ }
+
+ updateAnimations();
+
+ if (!_vm->_isLeavingScene) {
+ plat.updateIdleSequence();
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[6] && _nextCashierSequenceId == -1) {
+ _vm->_timers[6] = _vm->getRandom(30) + 20;
+ if (_vm->getRandom(8) != 0) {
+ _nextCashierSequenceId = 0x59;
+ } else {
+ _cashierCtr = (_cashierCtr + 1) % 3;
+ switch (_cashierCtr) {
+ case 1:
+ _nextCashierSequenceId = 0x58;
+ break;
+ case 2:
+ _nextCashierSequenceId = 0x5A;
+ break;
+ case 3:
+ _nextCashierSequenceId = 0x5B;
+ break;
+ default:
+ _nextCashierSequenceId = 0x58;
+ break;
+ }
+ }
+ }
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[2] = _vm->getRandom(30) + 20;
+ _vm->_timers[3] = 400;
+ _vm->_timers[1] = _vm->getRandom(20) + 30;
+ _vm->_timers[0] = _vm->getRandom(75) + 75;
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene22::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS22LeaveScene:
+ _vm->_sceneDone = true;
+ break;
+ case kAS22TalkCashier:
+ _nextCashierSequenceId = 0x5C;
+ break;
+ }
+ gnap._actionStatus = -1;
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2 && _nextCashierSequenceId != -1) {
+ gameSys.setAnimation(_nextCashierSequenceId, 1, 3);
+ gameSys.insertSequence(_nextCashierSequenceId, 1, _currCashierSequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ _currCashierSequenceId = _nextCashierSequenceId;
+ _nextCashierSequenceId = -1;
+ }
+}
+
+/*****************************************************************************/
+
+Scene23::Scene23(GnapEngine *vm) : Scene(vm) {
+ _currStoreClerkSequenceId = -1;
+ _nextStoreClerkSequenceId = -1;
+}
+
+int Scene23::init() {
+ return 0xC0;
+}
+
+void Scene23::updateHotspots() {
+ _vm->setHotspot(kHS23Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS23ExitFrontGrubCity, 0, 250, 15, 550, SF_EXIT_L_CURSOR | SF_WALKABLE, 0, 7);
+ _vm->setHotspot(kHS23Cereals, 366, 332, 414, 408, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 4, 7);
+ _vm->setHotspot(kHS23WalkArea1, 0, 0, 340, 460);
+ _vm->setHotspot(kHS23WalkArea2, 340, 0, 800, 501);
+ _vm->setDeviceHotspot(kHS23Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 6;
+}
+
+void Scene23::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->_timers[4] = _vm->getRandom(100) + 200;
+ _vm->_timers[5] = _vm->getRandom(100) + 200;
+
+ _currStoreClerkSequenceId = 0xB4;
+ _nextStoreClerkSequenceId = -1;
+
+ gameSys.setAnimation(0xB4, 1, 4);
+ gameSys.insertSequence(_currStoreClerkSequenceId, 1, 0, 0, kSeqNone, 0, 0, 0);
+
+ _vm->queueInsertDeviceIcon();
+
+ gnap.initPos(-1, 7, kDirBottomRight);
+ plat.initPos(-2, 7, kDirIdleLeft);
+ gameSys.insertSequence(0xBD, 255, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.insertSequence(0xBF, 2, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->endSceneInit();
+
+ plat.walkTo(Common::Point(1, 7), -1, 0x107C2, 1);
+
+ if (_vm->isFlag(kGFUnk24)) {
+ gnap.walkTo(Common::Point(2, 7), -1, 0x107B9, 1);
+ } else {
+ gnap.walkTo(Common::Point(2, 7), 0, 0x107B9, 1);
+ while (gameSys.getAnimationStatus(0) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+
+ _vm->playSequences(0x48, 0xBA, 0xBB, 0xBC);
+ _vm->setFlag(kGFUnk24);
+ }
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->testWalk(0, 3, -1, -1, -1, -1);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS23Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS23Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemJoint) {
+ gnap.useJointOnPlatypus();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS23Cereals:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS23Cereals], 5, 4);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ if (_vm->isFlag(kGFSceneFlag1))
+ gnap.playMoan2();
+ else {
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS23Cereals], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS23LookCereals;
+ }
+ break;
+ case GRAB_CURSOR:
+ if (_vm->isFlag(kGFSceneFlag1))
+ gnap.playImpossible();
+ else {
+ gnap._idleFacing = kDirBottomRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS23Cereals], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ _vm->setFlag(kGFSceneFlag1);
+ gnap._actionStatus = kAS23GrabCereals;
+ _vm->invAdd(kItemCereals);
+ }
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS23ExitFrontGrubCity:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 22;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS23ExitFrontGrubCity], 0, 0x107AF, 1);
+ gnap._actionStatus = kAS23LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS23ExitFrontGrubCity] + Common::Point(0, -1), -1, 0x107C2, 1);
+ }
+ break;
+
+ case kHS23WalkArea1:
+ case kHS23WalkArea2:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+ }
+
+ updateAnimations();
+
+ if (!_vm->_isLeavingScene) {
+ plat.updateIdleSequence();
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[4] && gnap._actionStatus == -1) {
+ _vm->_timers[4] = _vm->getRandom(100) + 200;
+ switch (_vm->getRandom(4)) {
+ case 0:
+ gameSys.insertSequence(0xB7, 256, 0, 0, kSeqNone, 0, 0, 0);
+ break;
+ case 1:
+ gameSys.insertSequence(0xB8, 256, 0, 0, kSeqNone, 0, 0, 0);
+ break;
+ case 2:
+ case 3:
+ gameSys.insertSequence(0xB9, 256, 0, 0, kSeqNone, 0, 0, 0);
+ break;
+ }
+ }
+ if (!_vm->_timers[5]) {
+ _vm->_timers[5] = _vm->getRandom(100) + 200;
+ switch (_vm->getRandom(3)) {
+ case 0:
+ _vm->playSound(0xCE, false);
+ break;
+ case 1:
+ _vm->playSound(0xD0, false);
+ break;
+ case 2:
+ _vm->playSound(0xCF, false);
+ break;
+ }
+ }
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene23::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS23LookCereals:
+ _vm->showFullScreenSprite(0x48);
+ gnap._actionStatus = -1;
+ break;
+ case kAS23GrabCereals:
+ gameSys.setAnimation(0xBE, gnap._id, 0);
+ gameSys.insertSequence(0xBE, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.requestRemoveSequence(0xBF, 2);
+ gnap._sequenceDatNum = 0;
+ gnap._sequenceId = 0xBE;
+ gnap._actionStatus = kAS23GrabCerealsDone;
+ break;
+ case kAS23GrabCerealsDone:
+ _vm->setGrabCursorSprite(kItemCereals);
+ gnap._actionStatus = -1;
+ break;
+ case kAS23LeaveScene:
+ _vm->_sceneDone = true;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(4) == 2 && _nextStoreClerkSequenceId == -1) {
+ switch (_vm->getRandom(8)) {
+ case 0:
+ case 1:
+ case 2:
+ _nextStoreClerkSequenceId = 0xB4;
+ break;
+ case 3:
+ case 4:
+ case 5:
+ _nextStoreClerkSequenceId = 0xB5;
+ break;
+ default:
+ _nextStoreClerkSequenceId = 0xB6;
+ break;
+ }
+ gameSys.setAnimation(_nextStoreClerkSequenceId, 1, 4);
+ gameSys.insertSequence(_nextStoreClerkSequenceId, 1, _currStoreClerkSequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ _currStoreClerkSequenceId = _nextStoreClerkSequenceId;
+ _nextStoreClerkSequenceId = -1;
+ }
+}
+
+/*****************************************************************************/
+
+Scene24::Scene24(GnapEngine *vm) : Scene(vm) {
+ _currWomanSequenceId = -1;
+ _nextWomanSequenceId = -1;
+ _boySequenceId = -1;
+ _girlSequenceId = -1;
+}
+
+int Scene24::init() {
+ return 0x3B;
+}
+
+void Scene24::updateHotspots() {
+ _vm->setHotspot(kHS24Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS24ExitCircusWorld, 785, 128, 800, 600, SF_EXIT_R_CURSOR, 8, 7);
+ _vm->setHotspot(kHS24ExitOutsideGrubCity, 0, 213, 91, 600, SF_EXIT_NW_CURSOR, 1, 8);
+ _vm->setHotspot(kHS24WalkArea1, 0, 0, 0, 0);
+ _vm->setHotspot(kHS24WalkArea2, 530, 0, 800, 600);
+ _vm->setHotspot(kHS24WalkArea3, 0, 0, 800, 517);
+ _vm->setDeviceHotspot(kHS24Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 7;
+}
+
+void Scene24::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ int counter = 0;
+
+ _vm->playSound(0x10940, true);
+ _vm->startSoundTimerA(9);
+
+ _vm->_timers[7] = _vm->getRandom(100) + 100;
+
+ gameSys.insertSequence(0x2F, 256, 0, 0, kSeqNone, 0, 0, 0);
+
+ _vm->_timers[4] = _vm->getRandom(20) + 50;
+ _vm->_timers[5] = _vm->getRandom(20) + 40;
+ _vm->_timers[6] = _vm->getRandom(50) + 30;
+
+ gameSys.insertSequence(0x36, 20, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.insertSequence(0x30, 20, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.insertSequence(0x35, 20, 0, 0, kSeqNone, 0, 0, 0);
+
+ _currWomanSequenceId = 0x35;
+ _girlSequenceId = 0x36;
+ _boySequenceId = 0x30;
+
+ _vm->queueInsertDeviceIcon();
+
+ if (_vm->_prevSceneNum == 20) {
+ gnap.initPos(1, 8, kDirBottomRight);
+ plat.initPos(2, 8, kDirIdleLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(1, 9), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(2, 9), -1, 0x107C2, 1);
+ } else {
+ gnap.initPos(8, 8, kDirBottomLeft);
+ plat.initPos(8, 8, kDirIdleRight);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(2, 8), -1, 0x107BA, 1);
+ plat.walkTo(Common::Point(3, 8), -1, 0x107C2, 1);
+ }
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->testWalk(0, 0, -1, -1, -1, -1);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+
+ case kHS24Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS24Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemJoint) {
+ gnap.useJointOnPlatypus();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS24ExitCircusWorld:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 25;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS24ExitCircusWorld], 0, 0x107AB, 1);
+ gnap._actionStatus = kAS24LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS24ExitCircusWorld] + Common::Point(1, 0), -1, 0x107C2, 1);
+ }
+ break;
+
+ case kHS24ExitOutsideGrubCity:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 20;
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS24ExitOutsideGrubCity], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS24LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS24ExitOutsideGrubCity] + Common::Point(1, 0), -1, 0x107C2, 1);
+ }
+ break;
+
+ case kHS24WalkArea1:
+ case kHS24WalkArea2:
+ case kHS24WalkArea3:
+ if (gnap._actionStatus == -1)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+ }
+
+ updateAnimations();
+
+ if (!_vm->isSoundPlaying(0x10940))
+ _vm->playSound(0x10940, true);
+
+ if (!_vm->_isLeavingScene) {
+ plat.updateIdleSequence();
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[4]) {
+ _vm->_timers[4] = _vm->getRandom(20) + 50;
+ gameSys.insertSequence(0x37, 20, _girlSequenceId, 20, kSeqSyncWait, 0, 0, 0);
+ _girlSequenceId = 0x37;
+ }
+ if (!_vm->_timers[5]) {
+ _vm->_timers[5] = _vm->getRandom(20) + 40;
+ gameSys.insertSequence(0x31, 20, _boySequenceId, 20, kSeqSyncWait, 0, 0, 0);
+ _boySequenceId = 0x31;
+ }
+ if (!_vm->_timers[6]) {
+ _vm->_timers[6] = _vm->getRandom(50) + 30;
+ counter = (counter + 1) % 3;
+ switch (counter) {
+ case 0:
+ _nextWomanSequenceId = 0x32;
+ break;
+ case 1:
+ _nextWomanSequenceId = 0x33;
+ break;
+ case 2:
+ _nextWomanSequenceId = 0x34;
+ break;
+ }
+ gameSys.insertSequence(_nextWomanSequenceId, 20, _currWomanSequenceId, 20, kSeqSyncWait, 0, 0, 0);
+ _currWomanSequenceId = _nextWomanSequenceId;
+ }
+ if (!_vm->_timers[7]) {
+ _vm->_timers[7] = _vm->getRandom(100) + 100;
+ switch (_vm->getRandom(3)) {
+ case 0:
+ gameSys.insertSequence(0x38, 253, 0, 0, kSeqNone, 0, 0, 0);
+ break;
+ case 1:
+ gameSys.insertSequence(0x39, 253, 0, 0, kSeqNone, 0, 0, 0);
+ break;
+ case 2:
+ gameSys.insertSequence(0x3A, 253, 0, 0, kSeqNone, 0, 0, 0);
+ break;
+ }
+ }
+ _vm->playSoundA();
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene24::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ if (gnap._actionStatus == kAS24LeaveScene)
+ _vm->_sceneDone = true;
+ gnap._actionStatus = -1;
+ }
+}
+
+/*****************************************************************************/
+
+Scene25::Scene25(GnapEngine *vm) : Scene(vm) {
+ _currTicketVendorSequenceId = -1;
+ _nextTicketVendorSequenceId = -1;
+}
+
+int Scene25::init() {
+ return 0x62;
+}
+
+void Scene25::updateHotspots() {
+ _vm->setHotspot(kHS25Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS25TicketVendor, 416, 94, 574, 324, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 5, 5);
+ _vm->setHotspot(kHS25ExitOutsideCircusWorld, 0, 519, 205, 600, SF_EXIT_SW_CURSOR, 5, 10);
+ _vm->setHotspot(kHS25ExitInsideCircusWorld, 321, 70, 388, 350, SF_EXIT_NE_CURSOR, 3, 6);
+ _vm->setHotspot(kHS25Posters1, 0, 170, 106, 326, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 1, 7);
+ _vm->setHotspot(kHS25Posters2, 146, 192, 254, 306, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 3, 7);
+ _vm->setHotspot(kHS25Posters3, 606, 162, 654, 368, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 7, 7);
+ _vm->setHotspot(kHS25Posters4, 708, 114, 754, 490, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 7, 8);
+ _vm->setHotspot(kHS25WalkArea1, 0, 0, 800, 439);
+ _vm->setHotspot(kHS25WalkArea2, 585, 0, 800, 600);
+ _vm->setDeviceHotspot(kHS25Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 11;
+}
+
+void Scene25::playAnims(int index) {
+ if (index > 4)
+ return;
+
+ GameSys& gameSys = *_vm->_gameSys;
+
+ _vm->hideCursor();
+ _vm->setGrabCursorSprite(-1);
+ switch (index) {
+ case 1:
+ _vm->_largeSprite = gameSys.createSurface(0x25);
+ break;
+ case 2:
+ _vm->_largeSprite = gameSys.createSurface(0x26);
+ break;
+ case 3:
+ _vm->_largeSprite = gameSys.createSurface(0x27);
+ break;
+ case 4:
+ _vm->_largeSprite = gameSys.createSurface(0x28);
+ break;
+ }
+ gameSys.insertSpriteDrawItem(_vm->_largeSprite, 0, 0, 300);
+ _vm->delayTicksCursor(5);
+ while (!_vm->_mouseClickState._left && !_vm->isKeyStatus1(Common::KEYCODE_ESCAPE) && !_vm->isKeyStatus1(Common::KEYCODE_SPACE) &&
+ !_vm->isKeyStatus1(Common::KEYCODE_RETURN) && !_vm->_gameDone) {
+ _vm->gameUpdateTick();
+ }
+ _vm->_mouseClickState._left = false;
+ _vm->clearKeyStatus1(Common::KEYCODE_ESCAPE);
+ _vm->clearKeyStatus1(Common::KEYCODE_RETURN);
+ _vm->clearKeyStatus1(Common::KEYCODE_SPACE);
+ gameSys.removeSpriteDrawItem(_vm->_largeSprite, 300);
+ _vm->delayTicksCursor(5);
+ _vm->deleteSurface(&_vm->_largeSprite);
+ _vm->showCursor();
+}
+
+void Scene25::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->playSound(0x10940, true);
+ _vm->startSoundTimerA(5);
+
+ _currTicketVendorSequenceId = 0x52;
+ gameSys.setAnimation(0x52, 39, 3);
+ gameSys.insertSequence(_currTicketVendorSequenceId, 39, 0, 0, kSeqNone, 0, 0, 0);
+
+ _nextTicketVendorSequenceId = -1;
+ _vm->_timers[4] = _vm->getRandom(20) + 20;
+
+ _vm->queueInsertDeviceIcon();
+
+ if (_vm->_prevSceneNum == 24) {
+ gnap.initPos(5, 11, kDirUpLeft);
+ plat.initPos(6, 11, kDirIdleRight);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(5, 7), -1, 0x107BA, 1);
+ plat.walkTo(Common::Point(6, 7), -1, 0x107C2, 1);
+ } else {
+ gnap.initPos(5, 6, kDirBottomRight);
+ plat.initPos(6, 6, kDirIdleLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(5, 8), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(6, 8), -1, 0x107C2, 1);
+ }
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS25Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS25Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemJoint) {
+ gnap.useJointOnPlatypus();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS25TicketVendor:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemTickets) {
+ gnap._actionStatus = kAS25ShowTicketToVendor;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS25TicketVendor], 0, gnap.getSequenceId(kGSIdle, Common::Point(9, 4)) | 0x10000, 1);
+ gnap.playPullOutDevice();
+ gnap.playUseDevice();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS25TicketVendor], 6, 1);
+ _nextTicketVendorSequenceId = 0x5B;
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(6, 1));
+ _nextTicketVendorSequenceId = (_vm->getRandom(2) == 1) ? 0x59 : 0x56;
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS25TicketVendor], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS25TalkTicketVendor;
+ break;
+ case GRAB_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS25ExitOutsideCircusWorld:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 24;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS25ExitOutsideCircusWorld], 0, 0x107B4, 1);
+ gnap._actionStatus = kAS25LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS25ExitOutsideCircusWorld] + Common::Point(1, 0), -1, 0x107C2, 1);
+ }
+ break;
+
+ case kHS25ExitInsideCircusWorld:
+ if (gnap._actionStatus < 0) {
+ if (_vm->isFlag(kGFNeedleTaken)) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 26;
+ _vm->_hotspots[kHS25WalkArea1]._flags |= SF_WALKABLE;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS25ExitInsideCircusWorld], 0, 0x107B1, 1);
+ gnap._actionStatus = kAS25LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS25ExitInsideCircusWorld] + Common::Point(1, 0), -1, 0x107C2, 1);
+ _vm->_hotspots[kHS25WalkArea1]._flags &= ~SF_WALKABLE;
+ } else {
+ _vm->_hotspots[kHS25WalkArea1]._flags |= SF_WALKABLE;
+ gnap.walkTo(Common::Point(4, 5), 0, 0x107BB, 1);
+ gnap._actionStatus = kAS25EnterCircusWihoutTicket;
+ _vm->_hotspots[kHS25WalkArea1]._flags &= ~SF_WALKABLE;
+ }
+ }
+ break;
+
+ case kHS25Posters1:
+ case kHS25Posters2:
+ case kHS25Posters3:
+ case kHS25Posters4:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.walkTo(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot], -1, -1, 1);
+ if (_vm->_sceneClickedHotspot == 5 || _vm->_sceneClickedHotspot == 6)
+ gnap._idleFacing = kDirUpLeft;
+ else if (_vm->_sceneClickedHotspot == 8)
+ gnap._idleFacing = kDirBottomRight;
+ else
+ gnap._idleFacing = kDirUpRight;
+ gnap.playIdle();
+ playAnims(8 - _vm->_sceneClickedHotspot + 1);
+ break;
+ case GRAB_CURSOR:
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playMoan2();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS25WalkArea1:
+ case kHS25WalkArea2:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+ }
+
+ updateAnimations();
+
+ if (!_vm->_isLeavingScene) {
+ plat.updateIdleSequence();
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[4] && _nextTicketVendorSequenceId == -1 && gnap._actionStatus == -1) {
+ _vm->_timers[4] = _vm->getRandom(20) + 20;
+ switch (_vm->getRandom(13)) {
+ case 0:
+ _nextTicketVendorSequenceId = 0x54;
+ break;
+ case 1:
+ _nextTicketVendorSequenceId = 0x58;
+ break;
+ case 2:
+ _nextTicketVendorSequenceId = 0x55;
+ break;
+ case 3:
+ _nextTicketVendorSequenceId = 0x5A;
+ break;
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ _nextTicketVendorSequenceId = 0x5B;
+ break;
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ _nextTicketVendorSequenceId = 0x5C;
+ break;
+ case 12:
+ _nextTicketVendorSequenceId = 0x5D;
+ break;
+ default:
+ _nextTicketVendorSequenceId = 0x52;
+ break;
+ }
+ }
+ _vm->playSoundA();
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene25::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS25TalkTicketVendor:
+ _nextTicketVendorSequenceId = (_vm->getRandom(2) == 1) ? 0x57 : 0x5F;
+ gnap._actionStatus = -1;
+ break;
+ case kAS25EnterCircusWihoutTicket:
+ _nextTicketVendorSequenceId = 0x5E;
+ gameSys.setAnimation(0x5E, 39, 0);
+ gameSys.setAnimation(_nextTicketVendorSequenceId, 39, 3);
+ gameSys.insertSequence(_nextTicketVendorSequenceId, 39, _currTicketVendorSequenceId, 39, kSeqSyncExists, 0, 0, 0);
+ gameSys.insertSequence(0x60, 2, 0, 0, kSeqNone, 0, 0, 0);
+ _currTicketVendorSequenceId = _nextTicketVendorSequenceId;
+ _nextTicketVendorSequenceId = -1;
+ _vm->_hotspots[kHS25WalkArea1]._flags |= SF_WALKABLE;
+ gnap.playIdle();
+ gnap.walkTo(_vm->_hotspotsWalkPos[3], -1, 0x107BB, 1);
+ _vm->_hotspots[kHS25WalkArea1]._flags &= ~SF_WALKABLE;
+ gnap._actionStatus = kAS25EnterCircusWihoutTicketDone;
+ break;
+ case kAS25EnterCircusWihoutTicketDone:
+ gnap._actionStatus = -1;
+ break;
+ case kAS25ShowTicketToVendor:
+ _vm->setGrabCursorSprite(-1);
+ _vm->invRemove(kItemTickets);
+ _vm->setFlag(kGFNeedleTaken);
+ gameSys.setAnimation(0x61, 40, 0);
+ gameSys.insertSequence(0x61, 40, 0, 0, kSeqNone, 0, 0, 0);
+ gnap._actionStatus = kAS25ShowTicketToVendorDone;
+ break;
+ case kAS25ShowTicketToVendorDone:
+ _nextTicketVendorSequenceId = 0x53;
+ break;
+ case kAS25LeaveScene:
+ _vm->_sceneDone = true;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2) {
+ if (_nextTicketVendorSequenceId == 0x53) {
+ gameSys.insertSequence(_nextTicketVendorSequenceId, 39, _currTicketVendorSequenceId, 39, kSeqSyncWait, 0, 0, 0);
+ _currTicketVendorSequenceId = _nextTicketVendorSequenceId;
+ _nextTicketVendorSequenceId = -1;
+ gnap._actionStatus = -1;
+ } else if (_nextTicketVendorSequenceId != -1) {
+ gameSys.setAnimation(_nextTicketVendorSequenceId, 39, 3);
+ gameSys.insertSequence(_nextTicketVendorSequenceId, 39, _currTicketVendorSequenceId, 39, kSeqSyncWait, 0, 0, 0);
+ _currTicketVendorSequenceId = _nextTicketVendorSequenceId;
+ _nextTicketVendorSequenceId = -1;
+ }
+ }
+}
+
+/*****************************************************************************/
+
+Scene26::Scene26(GnapEngine *vm) : Scene(vm) {
+ _currKidSequenceId = -1;
+ _nextKidSequenceId = -1;
+}
+
+int Scene26::init() {
+ return _vm->isFlag(kGFUnk23) ? 0x61 : 0x60;
+}
+
+void Scene26::updateHotspots() {
+ _vm->setHotspot(kHS26Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS26ExitOutsideCircusWorld, 0, 590, 300, 600, SF_EXIT_D_CURSOR | SF_WALKABLE, 1, 10);
+ _vm->setHotspot(kHS26ExitOutsideClown, 200, 265, 265, 350, SF_EXIT_U_CURSOR, 3, 8);
+ _vm->setHotspot(kHS26ExitArcade, 0, 295, 150, 400, SF_EXIT_NW_CURSOR, 2, 8);
+ _vm->setHotspot(kHS26ExitElephant, 270, 290, 485, 375, SF_EXIT_U_CURSOR, 5, 8);
+ _vm->setHotspot(kHS26ExitBeerStand, 530, 290, 620, 350, SF_EXIT_NE_CURSOR, 5, 8);
+ _vm->setHotspot(kHS26WalkArea1, 0, 0, 800, 500);
+ _vm->setHotspot(kHS26WalkArea2, 281, 0, 800, 600);
+ _vm->setDeviceHotspot(kHS26Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 9;
+}
+
+void Scene26::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->startSoundTimerB(7);
+ _vm->playSound(0x1093B, true);
+
+ _currKidSequenceId = 0x5B;
+ _nextKidSequenceId = -1;
+ gameSys.setAnimation(0x5B, 160, 3);
+ gameSys.insertSequence(_currKidSequenceId, 160, 0, 0, kSeqNone, 0, 0, 0);
+
+ _vm->_timers[5] = _vm->getRandom(20) + 50;
+ _vm->_timers[4] = _vm->getRandom(20) + 50;
+ _vm->_timers[6] = _vm->getRandom(50) + 100;
+
+ _vm->queueInsertDeviceIcon();
+
+ gameSys.insertSequence(0x58, 40, 0, 0, kSeqLoop, 0, 0, 0);
+ gameSys.insertSequence(0x5C, 40, 0, 0, kSeqLoop, 0, 0, 0);
+ gameSys.insertSequence(0x5D, 40, 0, 0, kSeqLoop, 0, 0, 0);
+ gameSys.insertSequence(0x5E, 40, 0, 0, kSeqLoop, 0, 0, 0);
+
+ if (_vm->_prevSceneNum == 25) {
+ gnap.initPos(-1, 8, kDirBottomRight);
+ plat.initPos(-2, 8, kDirIdleLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(2, 8), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(1, 8), -1, 0x107C2, 1);
+ } else {
+ gnap.initPos(2, 8, kDirBottomRight);
+ plat.initPos(3, 8, kDirIdleLeft);
+ _vm->endSceneInit();
+ }
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS26Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS26Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemJoint) {
+ gnap.useJointOnPlatypus();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS26ExitOutsideCircusWorld:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 25;
+ gnap.walkTo(Common::Point(-1, _vm->_hotspotsWalkPos[kHS26ExitOutsideCircusWorld].y), 0, 0x107AE, 1);
+ gnap._actionStatus = kAS26LeaveScene;
+ }
+ break;
+
+ case kHS26ExitOutsideClown:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 27;
+ gnap.walkTo(Common::Point(-1, _vm->_hotspotsWalkPos[kHS26ExitOutsideClown].y), 0, 0x107BC, 1);
+ gnap._actionStatus = kAS26LeaveScene;
+ }
+ break;
+
+ case kHS26ExitArcade:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 29;
+ gnap.walkTo(Common::Point(-1, _vm->_hotspotsWalkPos[kHS26ExitArcade].y), 0, 0x107BC, 1);
+ gnap._actionStatus = kAS26LeaveScene;
+ }
+ break;
+
+ case kHS26ExitElephant:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 30;
+ gnap.walkTo(Common::Point(-1, _vm->_hotspotsWalkPos[kHS26ExitElephant].y), 0, 0x107BC, 1);
+ gnap._actionStatus = kAS26LeaveScene;
+ }
+ break;
+
+ case kHS26ExitBeerStand:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 31;
+ gnap.walkTo(Common::Point(-1, _vm->_hotspotsWalkPos[kHS26ExitBeerStand].y), 0, 0x107BB, 1);
+ gnap._actionStatus = kAS26LeaveScene;
+ }
+ break;
+
+ case kHS26WalkArea1:
+ case kHS26WalkArea2:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+ }
+
+ updateAnimations();
+
+ if (!_vm->isSoundPlaying(0x1093B))
+ _vm->playSound(0x1093B, true);
+
+ if (!_vm->_isLeavingScene) {
+ plat.updateIdleSequence();
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[5] && _nextKidSequenceId == -1) {
+ _vm->_timers[5] = _vm->getRandom(20) + 50;
+ if (_vm->getRandom(5) != 0)
+ _nextKidSequenceId = 0x5B;
+ else
+ _nextKidSequenceId = 0x5A;
+ }
+ if (!_vm->_timers[4]) {
+ _vm->_timers[4] = _vm->getRandom(20) + 130;
+ gameSys.insertSequence(0x59, 40, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ if (!_vm->_timers[6]) {
+ _vm->_timers[6] = _vm->getRandom(50) + 100;
+ gameSys.insertSequence(0x5F, 40, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ _vm->playSoundB();
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene26::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ if (gnap._actionStatus == kAS26LeaveScene)
+ _vm->_sceneDone = true;
+ gnap._actionStatus = -1;
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2 && _nextKidSequenceId != -1) {
+ gameSys.insertSequence(_nextKidSequenceId, 160, _currKidSequenceId, 160, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextKidSequenceId, 160, 3);
+ _currKidSequenceId = _nextKidSequenceId;
+ _nextKidSequenceId = -1;
+ }
+}
+
+/*****************************************************************************/
+
+Scene27::Scene27(GnapEngine *vm) : Scene(vm) {
+ _nextJanitorSequenceId = -1;
+ _currJanitorSequenceId = -1;
+}
+
+int Scene27::init() {
+ return 0xD5;
+}
+
+void Scene27::updateHotspots() {
+ _vm->setHotspot(kHS27Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS27Janitor, 488, 204, 664, 450, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 8, 8);
+ _vm->setHotspot(kHS27Bucket, 129, 406, 186, 453, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 3, 6);
+ _vm->setHotspot(kHS27ExitCircus, 200, 585, 700, 600, SF_EXIT_D_CURSOR | SF_WALKABLE, 5, 9);
+ _vm->setHotspot(kHS27ExitArcade, 0, 0, 15, 600, SF_EXIT_L_CURSOR, 0, 6);
+ _vm->setHotspot(kHS27ExitBeerStand, 785, 0, 800, 600, SF_EXIT_R_CURSOR, 11, 7);
+ _vm->setHotspot(kHS27ExitClown, 340, 240, 460, 420, SF_EXIT_U_CURSOR, 6, 8);
+ _vm->setHotspot(kHS27WalkArea1, 0, 0, 800, 507);
+ _vm->setDeviceHotspot(kHS27Device, -1, -1, -1, -1);
+ if (_vm->isFlag(kGFUnk13))
+ _vm->_hotspots[kHS27Bucket]._flags = SF_DISABLED;
+ _vm->_hotspotsCount = 9;
+}
+
+void Scene27::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->playSound(0x1093B, true);
+ _vm->startSoundTimerB(4);
+ _vm->_timers[7] = _vm->getRandom(100) + 300;
+ _vm->queueInsertDeviceIcon();
+
+ if (!_vm->isFlag(kGFUnk13))
+ gameSys.insertSequence(0xD3, 39, 0, 0, kSeqNone, 0, 0, 0);
+
+ gameSys.insertSequence(0xCB, 39, 0, 0, kSeqNone, 0, 0, 0);
+
+ _currJanitorSequenceId = 0xCB;
+ _nextJanitorSequenceId = -1;
+
+ gameSys.setAnimation(0xCB, 39, 3);
+ _vm->_timers[5] = _vm->getRandom(20) + 60;
+
+ switch (_vm->_prevSceneNum) {
+ case 26:
+ gnap.initPos(7, 12, kDirBottomRight);
+ plat.initPos(6, 12, kDirIdleLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(7, 8), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(6, 8), -1, 0x107C2, 1);
+ break;
+ case 29:
+ gnap.initPos(-1, 8, kDirBottomRight);
+ plat.initPos(-1, 9, kDirIdleLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(3, 8), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(3, 9), -1, 0x107C2, 1);
+ break;
+ case 31:
+ gnap.initPos(12, 8, kDirBottomLeft);
+ plat.initPos(12, 9, kDirIdleRight);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(8, 8), -1, 0x107BA, 1);
+ plat.walkTo(Common::Point(8, 9), -1, 0x107C2, 1);
+ break;
+ default:
+ gnap.initPos(6, 8, kDirBottomRight);
+ plat.initPos(5, 9, kDirIdleLeft);
+ _vm->endSceneInit();
+ break;
+ }
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+ _vm->_sceneClickedHotspot = -1;
+ if (gnap._actionStatus < 0)
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS27Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS27Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemJoint) {
+ gnap.useJointOnPlatypus();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS27Janitor:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemPicture) {
+ gnap._idleFacing = kDirUpLeft;
+ if (gnap.walkTo(_vm->_hotspotsWalkPos[kHS27Janitor], 0, 0x107BC, 1))
+ gnap._actionStatus = kAS27ShowPictureToJanitor;
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS27Janitor], 7, 3);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(6, 3));
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpLeft;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS27Janitor], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS27TalkJanitor;
+ break;
+ case GRAB_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS27Bucket:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowItem(_vm->_grabCursorSpriteIndex, 3, 3);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(3, 3));
+ break;
+ case GRAB_CURSOR:
+ gnap._idleFacing = kDirUpLeft;
+ gnap.walkTo(gnap._pos, 0, gnap.getSequenceId(kGSIdle, _vm->_hotspotsWalkPos[kHS27Bucket]) | 0x10000, 1);
+ gnap._actionStatus = kAS27GrabBucket;
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS27ExitCircus:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 26;
+ gnap.walkTo(Common::Point(-1, _vm->_hotspotsWalkPos[kHS27ExitCircus].y), 0, 0x107AE, 1);
+ gnap._actionStatus = kAS27LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS27ExitCircus] + Common::Point(1, 0), -1, 0x107C7, 1);
+ }
+ break;
+
+ case kHS27ExitArcade:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 29;
+ gnap.walkTo(Common::Point(-1, _vm->_hotspotsWalkPos[kHS27ExitArcade].y), 0, 0x107AF, 1);
+ gnap._actionStatus = kAS27LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS27ExitArcade] + Common::Point(0, 1), -1, 0x107CF, 1);
+ }
+ break;
+
+ case kHS27ExitBeerStand:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 31;
+ gnap.walkTo(Common::Point(-1, _vm->_hotspotsWalkPos[kHS27ExitBeerStand].y), 0, 0x107AB, 1);
+ gnap._actionStatus = kAS27LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS27ExitBeerStand] + Common::Point(0, 1), -1, 0x107CD, 1);
+ }
+ break;
+
+ case kHS27ExitClown:
+ if (gnap._actionStatus < 0) {
+ if (_vm->isFlag(kGFPlatypus)) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 28;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS27ExitClown], 0, 0x107AD, 1);
+ gnap._actionStatus = kAS27LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS27ExitClown] + Common::Point(1, 0), -1, 0x107C4, 1);
+ } else {
+ _vm->_hotspots[kHS27WalkArea1]._flags |= SF_WALKABLE;
+ gnap.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS27ExitClown].x, 7), 0, 0x107BC, 1);
+ _vm->_hotspots[kHS27WalkArea1]._flags &= SF_WALKABLE;
+ gnap._actionStatus = kAS27TryEnterClownTent;
+ }
+ }
+ break;
+
+ case kHS27WalkArea1:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left && gnap._actionStatus < 0) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+
+ }
+
+ updateAnimations();
+
+ if (!_vm->isSoundPlaying(0x1093B))
+ _vm->playSound(0x1093B, true);
+
+ if (!_vm->_isLeavingScene) {
+ plat.updateIdleSequence();
+ if (gnap._actionStatus < 0)
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[5]) {
+ _vm->_timers[5] = _vm->getRandom(20) + 60;
+ if (gnap._actionStatus < 0) {
+ if (_vm->getRandom(3) != 0)
+ _nextJanitorSequenceId = 0xCB;
+ else
+ _nextJanitorSequenceId = 0xCF;
+ }
+ }
+ if (!_vm->_timers[7]) {
+ _vm->_timers[7] = _vm->getRandom(100) + 300;
+ if (gnap._actionStatus < 0)
+ gameSys.insertSequence(0xD4, 120, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ _vm->playSoundB();
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene27::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS27TalkJanitor:
+ switch (_vm->getRandom(3)) {
+ case 0:
+ _nextJanitorSequenceId = 0xCC;
+ break;
+ case 1:
+ _nextJanitorSequenceId = 0xCD;
+ break;
+ case 2:
+ _nextJanitorSequenceId = 0xCE;
+ break;
+ }
+ break;
+ case kAS27GrabBucket:
+ gnap.playPullOutDevice();
+ gnap.playUseDevice();
+ _vm->_hotspots[kHS27Bucket]._flags = SF_DISABLED;
+ _vm->invAdd(kItemEmptyBucket);
+ _vm->setFlag(kGFUnk13);
+ gameSys.setAnimation(0xD2, 39, 0);
+ gameSys.insertSequence(0xD2, 39, 211, 39, kSeqSyncWait, 0, 0, 0);
+ gnap._actionStatus = kAS27GrabBucketDone;
+ break;
+ case kAS27GrabBucketDone:
+ _vm->setGrabCursorSprite(kItemEmptyBucket);
+ gnap._actionStatus = -1;
+ break;
+ case kAS27ShowPictureToJanitor:
+ _nextJanitorSequenceId = 0xD0;
+ break;
+ case kAS27TryEnterClownTent:
+ _nextJanitorSequenceId = 0xD1;
+ gameSys.insertSequence(0xD1, 39, _currJanitorSequenceId, 39, kSeqSyncExists, 0, 0, 0);
+ gameSys.setAnimation(_nextJanitorSequenceId, 39, 3);
+ gameSys.setAnimation(_nextJanitorSequenceId, 39, 0);
+ _currJanitorSequenceId = _nextJanitorSequenceId;
+ _nextJanitorSequenceId = -1;
+ gnap._actionStatus = kAS27TryEnterClownTentDone;
+ break;
+ case kAS27TryEnterClownTentDone:
+ _vm->_hotspots[kHS27WalkArea1]._flags |= SF_WALKABLE;
+ gnap.walkTo(Common::Point(_vm->_hotspotsWalkPos[7].x, 9), -1, 0x107BC, 1);
+ _vm->_hotspots[kHS27WalkArea1]._flags &= ~SF_WALKABLE;
+ gnap._actionStatus = -1;
+ break;
+ case kAS27EnterClownTent:
+ gnap.walkTo(gnap._pos, 0, 0x107B2, 1);
+ gnap._actionStatus = kAS27LeaveScene;
+ break;
+ case kAS27LeaveScene:
+ _vm->_sceneDone = true;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2) {
+ switch (_nextJanitorSequenceId) {
+ case -1:
+ _nextJanitorSequenceId = 0xCB;
+ gameSys.insertSequence(0xCB, 39, _currJanitorSequenceId, 39, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextJanitorSequenceId, 39, 3);
+ _currJanitorSequenceId = _nextJanitorSequenceId;
+ _nextJanitorSequenceId = -1;
+ break;
+ case 0xCC:
+ case 0xCD:
+ case 0xCE:
+ gnap._actionStatus = -1;
+ gameSys.insertSequence(_nextJanitorSequenceId, 39, _currJanitorSequenceId, 39, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextJanitorSequenceId, 39, 3);
+ gameSys.setAnimation(_nextJanitorSequenceId, 39, 0);
+ _currJanitorSequenceId = _nextJanitorSequenceId;
+ _nextJanitorSequenceId = -1;
+ break;
+ case 0xD0:
+ // Show picture to janitor
+ gnap.playPullOutDevice();
+ gnap.playUseDevice();
+ gameSys.insertSequence(_nextJanitorSequenceId, 39, _currJanitorSequenceId, 39, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextJanitorSequenceId, 39, 0);
+ gnap._actionStatus = kAS27EnterClownTent;
+ _currJanitorSequenceId = _nextJanitorSequenceId;
+ _nextJanitorSequenceId = -1;
+ _vm->setFlag(kGFPlatypus);
+ _vm->setGrabCursorSprite(-1);
+ _vm->invRemove(kItemPicture);
+ _vm->_newSceneNum = 28;
+ break;
+ default:
+ gameSys.insertSequence(_nextJanitorSequenceId, 39, _currJanitorSequenceId, 39, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextJanitorSequenceId, 39, 3);
+ _currJanitorSequenceId = _nextJanitorSequenceId;
+ _nextJanitorSequenceId = -1;
+ break;
+ }
+ }
+}
+
+/*****************************************************************************/
+
+Scene28::Scene28(GnapEngine *vm) : Scene(vm) {
+ _currClownSequenceId = -1;
+ _nextClownSequenceId = -1;
+ _clownTalkCtr = 0;
+}
+
+int Scene28::init() {
+ return 0x125;
+}
+
+void Scene28::updateHotspots() {
+ _vm->setHotspot(kHS28Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS28Horn, 148, 352, 215, 383, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 1, 7);
+ _vm->setHotspot(kHS28Clown, 130, 250, 285, 413, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 3, 5);
+ _vm->setHotspot(kHS28ExitOutsideClown, 660, 190, 799, 400, SF_EXIT_R_CURSOR, 9, 6);
+ _vm->setHotspot(kHS28EmptyBucket, 582, 421, 643, 478, SF_WALKABLE | SF_DISABLED, 9, 7);
+ _vm->setHotspot(kHS28WalkArea1, 0, 0, 799, 523);
+ _vm->setHotspot(kHS28WalkArea2, 0, 0, 0, 0, 7, SF_DISABLED);
+ _vm->setDeviceHotspot(kHS28Device, -1, -1, -1, -1);
+ if (_vm->invHas(kItemHorn))
+ _vm->_hotspots[kHS28Horn]._flags = SF_DISABLED;
+ if (_vm->isFlag(kGFUnk22))
+ _vm->_hotspots[kHS28EmptyBucket]._flags = SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR;
+ _vm->_hotspotsCount = 8;
+}
+
+void Scene28::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->playSound(0x1093C, true);
+ _nextClownSequenceId = -1;
+ _vm->queueInsertDeviceIcon();
+ gameSys.insertSequence(0x124, 255, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (_vm->isFlag(kGFUnk22))
+ gameSys.insertSequence(0x112, 99, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (_vm->isFlag(kGFMudTaken)) {
+ if (_vm->isFlag(kGFUnk21)) {
+ gameSys.setAnimation(0x11C, 39, 3);
+ gameSys.insertSequence(0x11C, 39, 0, 0, kSeqNone, 0, 0, 0);
+ if (!_vm->invHas(kItemHorn))
+ gameSys.insertSequence(0x118, 59, 0, 0, kSeqNone, 0, 0, 0);
+ _currClownSequenceId = 0x11C;
+ } else {
+ _currClownSequenceId = 0x11B;
+ gameSys.setAnimation(0x11B, 39, 3);
+ gameSys.insertSequence(_currClownSequenceId, 39, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->_timers[4] = _vm->getRandom(20) + 80;
+ }
+ gnap.initPos(8, 8, kDirBottomLeft);
+ plat.initPos(9, 8, kDirIdleRight);
+ _vm->endSceneInit();
+ } else {
+ gameSys.insertSequence(0x11B, 39, 0, 0, kSeqNone, 0, 0, 0);
+ gnap.initPos(8, 8, kDirBottomLeft);
+ plat.initPos(9, 8, kDirIdleRight);
+ _vm->endSceneInit();
+ _vm->playSequences(0xF7, 0x121, 0x122, 0x123);
+ _currClownSequenceId = 0x115;
+ _vm->setFlag(kGFMudTaken);
+ gameSys.setAnimation(0x115, 39, 3);
+ gameSys.insertSequence(_currClownSequenceId, 39, 0x11B, 39, kSeqSyncWait, 0, 0, 0);
+ _nextClownSequenceId = -1;
+ _vm->_timers[4] = _vm->getRandom(20) + 80;
+ gnap._actionStatus = kAS28GnapWaiting;
+ while (gameSys.getAnimationStatus(3) != 2 && !_vm->_gameDone) {
+ _vm->gameUpdateTick();
+ _vm->updateMouseCursor();
+ }
+ gnap._actionStatus = -1;
+ }
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS28Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS28Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemJoint) {
+ gnap.useJointOnPlatypus();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS28Horn:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(2, 8), 3, 4);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(2, 4));
+ break;
+ case GRAB_CURSOR:
+ if (_vm->isFlag(kGFUnk21)) {
+ if (!_vm->invHas(kItemHorn)) {
+ gnap.walkTo(gnap._pos, 0, gnap.getSequenceId(kGSIdle, _vm->_hotspotsWalkPos[kHS28Horn]) | 0x10000, 1);
+ gnap._actionStatus = kAS28GrabHornSuccess;
+ }
+ } else {
+ gnap._idleFacing = kDirUpLeft;
+ gnap.walkTo(Common::Point(2, 8), 0, 0x107BB, 1);
+ _vm->_hotspots[kHS28WalkArea1]._flags |= SF_WALKABLE;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS28Horn], 0, 0x107BB, 1);
+ _vm->_hotspots[kHS28WalkArea1]._flags &= ~SF_WALKABLE;
+ gnap._actionStatus = kAS28GrabHornFails;
+ }
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS28Clown:
+ if (gnap._actionStatus < 0) {
+ if (_vm->isFlag(kGFUnk21)) {
+ if (_vm->_verbCursor == LOOK_CURSOR)
+ gnap.playScratchingHead(Common::Point(5, 2));
+ else
+ gnap.playImpossible();
+ } else if (_vm->_grabCursorSpriteIndex == kItemBucketWithBeer) {
+ gnap._idleFacing = kDirUpLeft;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS28Clown], 0, 0x107BC, 1);
+ gnap.playPullOutDevice();
+ gnap.playUseDevice();
+ gnap._actionStatus = kAS28UseBeerBucketWithClown;
+ } else if (_vm->_grabCursorSpriteIndex == kItemBucketWithPill) {
+ gnap._idleFacing = kDirUpLeft;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS28Clown], 0, 0x107BC, 1);
+ gnap.playPullOutDevice();
+ gnap.playUseDevice();
+ gnap._actionStatus = kAS28UsePillBucketWithClown;
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS28Clown], 2, 4);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(5, 2));
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpLeft;
+ gnap.walkTo(Common::Point(5, 8), 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS28TalkClown;
+ break;
+ case GRAB_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS28ExitOutsideClown:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 27;
+ _vm->_hotspots[kHS28WalkArea1]._flags |= SF_WALKABLE;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS28ExitOutsideClown], 0, 0x107BF, 1);
+ gnap._actionStatus = kAS28LeaveScene;
+ _vm->_hotspots[kHS28WalkArea1]._flags &= ~SF_WALKABLE;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS28ExitOutsideClown] + Common::Point(-1, 0), -1, 0x107C2, 1);
+ }
+ break;
+
+ case kHS28EmptyBucket:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowItem(_vm->_grabCursorSpriteIndex, 8, 6);
+ } else if (_vm->isFlag(kGFUnk21)) {
+ gnap.playImpossible(Common::Point(8, 6));
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(8, 6));
+ break;
+ case GRAB_CURSOR:
+ gnap.walkTo(gnap._pos, 0, gnap.getSequenceId(kGSIdle, _vm->_hotspotsWalkPos[kHS28EmptyBucket]) | 0x10000, 1);
+ gnap._actionStatus = kAS28GrabEmptyBucket;
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS28WalkArea1:
+ case kHS28WalkArea2:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left && gnap._actionStatus < 0) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+ }
+
+ updateAnimations();
+
+ if (!_vm->isSoundPlaying(0x1093C))
+ _vm->playSound(0x1093C, true);
+
+ if (!_vm->_isLeavingScene) {
+ plat.updateIdleSequence();
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[4]) {
+ _vm->_timers[4] = _vm->getRandom(20) + 80;
+ if (gnap._actionStatus < 0 && !_vm->isFlag(kGFUnk21))
+ _nextClownSequenceId = 0x114;
+ }
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene28::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS28UseBeerBucketWithClown:
+ _vm->setFlag(kGFUnk22);
+ _nextClownSequenceId = 0x113;
+ _vm->invRemove(kItemBucketWithBeer);
+ updateHotspots();
+ break;
+ case kAS28UsePillBucketWithClown:
+ _nextClownSequenceId = 0x116;
+ _vm->invRemove(kItemBucketWithPill);
+ _vm->setFlag(kGFUnk22);
+ _vm->setFlag(kGFUnk21);
+ updateHotspots();
+ break;
+ case kAS28GrabHornFails:
+ _nextClownSequenceId = 0x119;
+ break;
+ case kAS28GrabHornSuccess:
+ gnap.playPullOutDevice();
+ gnap.playUseDevice();
+ gameSys.setAnimation(0x117, 59, 0);
+ gameSys.insertSequence(0x117, 59, 280, 59, kSeqSyncWait, 0, 0, 0);
+ gnap._actionStatus = kAS28GrabHornSuccessDone;
+ break;
+ case kAS28GrabHornSuccessDone:
+ _vm->hideCursor();
+ _vm->setGrabCursorSprite(-1);
+ _vm->addFullScreenSprite(0xF6, 255);
+ gameSys.setAnimation(0x120, 256, 0);
+ gameSys.insertSequence(0x120, 256, 0, 0, kSeqNone, 0, 0, 0);
+ while (gameSys.getAnimationStatus(0) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+
+ _vm->removeFullScreenSprite();
+ _vm->showCursor();
+ _vm->setGrabCursorSprite(kItemHorn);
+ _vm->invAdd(kItemHorn);
+ updateHotspots();
+ gnap._actionStatus = -1;
+ break;
+ case kAS28GrabEmptyBucket:
+ gnap.playPullOutDevice();
+ gnap.playUseDevice();
+ gameSys.setAnimation(0x111, 99, 0);
+ gameSys.insertSequence(0x111, 99, 274, 99, kSeqSyncWait, 0, 0, 0);
+ gnap._actionStatus = kAS28GrabEmptyBucketDone;
+ break;
+ case kAS28GrabEmptyBucketDone:
+ _vm->setGrabCursorSprite(kItemEmptyBucket);
+ _vm->clearFlag(kGFUnk22);
+ updateHotspots();
+ _vm->invAdd(kItemEmptyBucket);
+ gnap._actionStatus = -1;
+ break;
+ case kAS28GrabHornFailsDone:
+ gameSys.insertSequence(0x107B5, gnap._id, 281, 39, kSeqSyncWait, 0, 75 * gnap._pos.x - gnap._gridX, 48 * gnap._pos.y - gnap._gridY);
+ gnap._sequenceId = 0x7B5;
+ gnap._sequenceDatNum = 1;
+ gameSys.insertSequence(0x11B, 39, 0, 0, kSeqNone, 0, 0, 0);
+ _currClownSequenceId = 0x11B;
+ _nextClownSequenceId = -1;
+ gnap._actionStatus = -1;
+ gnap.walkTo(Common::Point(2, 8), -1, 0x107BB, 1);
+ break;
+ case kAS28TalkClown:
+ // The original was only using the first two sequences,
+ // due to a bug.
+ _clownTalkCtr = (_clownTalkCtr + 1) % 3;
+ if (_clownTalkCtr == 0)
+ _nextClownSequenceId = 0x11D;
+ else if (_clownTalkCtr == 1)
+ _nextClownSequenceId = 0x11E;
+ else if (_clownTalkCtr == 2)
+ _nextClownSequenceId = 0x11F;
+ break;
+ case kAS28GnapWaiting:
+ gnap._actionStatus = -1;
+ break;
+ case kAS28LeaveScene:
+ _vm->_sceneDone = true;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2) {
+ switch (_nextClownSequenceId) {
+ case 0x113:
+ _vm->setGrabCursorSprite(-1);
+ gameSys.setAnimation(_nextClownSequenceId, 39, 0);
+ gameSys.insertSequence(0x112, 99, 0, 0, kSeqNone, _vm->getSequenceTotalDuration(_nextClownSequenceId), 0, 0);
+ gameSys.insertSequence(_nextClownSequenceId, 39, _currClownSequenceId, 39, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x11B, 39, _nextClownSequenceId, 39, kSeqSyncWait, 0, 0, 0);
+ _currClownSequenceId = 0x11B;
+ _nextClownSequenceId = -1;
+ gnap._actionStatus = kAS28GnapWaiting;
+ break;
+ case 0x116:
+ _vm->setGrabCursorSprite(-1);
+ gameSys.setAnimation(_nextClownSequenceId, 39, 0);
+ gameSys.insertSequence(0x112, 99, 0, 0, kSeqNone, _vm->getSequenceTotalDuration(_nextClownSequenceId), 0, 0);
+ gameSys.insertSequence(_nextClownSequenceId, 39, _currClownSequenceId, 39, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x11C, 39, _nextClownSequenceId, 39, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x118, 59, 0, 0, kSeqNone, _vm->getSequenceTotalDuration(_nextClownSequenceId), 0, 0);
+ _currClownSequenceId = _nextClownSequenceId;
+ _nextClownSequenceId = -1;
+ gnap._actionStatus = kAS28GnapWaiting;
+ break;
+ case 0x11D:
+ case 0x11E:
+ case 0x11F:
+ gnap._actionStatus = -1;
+ break;
+ case 0x119:
+ gameSys.insertSequence(_nextClownSequenceId, 39, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextClownSequenceId, 39, 0);
+ gameSys.removeSequence(_currClownSequenceId, 39, true);
+ gnap._actionStatus = kAS28GrabHornFailsDone;
+ gnap._sequenceId = _nextClownSequenceId;
+ gnap._sequenceDatNum = 0;
+ _nextClownSequenceId = -1;
+ break;
+ }
+ if (_nextClownSequenceId != -1) {
+ gameSys.insertSequence(_nextClownSequenceId, 39, _currClownSequenceId, 39, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextClownSequenceId, 39, 3);
+ _currClownSequenceId = _nextClownSequenceId;
+ _nextClownSequenceId = -1;
+ }
+ }
+}
+
+/*****************************************************************************/
+
+Scene29::Scene29(GnapEngine *vm) : Scene(vm) {
+ _currMonkeySequenceId = -1;
+ _nextMonkeySequenceId = -1;
+ _currManSequenceId = -1;
+ _nextManSequenceId = -1;
+}
+
+int Scene29::init() {
+ return 0xF6;
+}
+
+void Scene29::updateHotspots() {
+ _vm->setHotspot(kHS29Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS29Monkey, 410, 374, 518, 516, SF_WALKABLE | SF_DISABLED, 3, 7);
+ _vm->setHotspot(kHS29ExitCircus, 150, 585, 650, 600, SF_EXIT_D_CURSOR | SF_WALKABLE, 5, 9);
+ _vm->setHotspot(kHS29ExitOutsideClown, 785, 0, 800, 600, SF_EXIT_R_CURSOR | SF_WALKABLE, 11, 9);
+ _vm->setHotspot(kHS29Arcade, 88, 293, 155, 384, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 3, 8);
+ _vm->setHotspot(kHS29WalkArea1, 0, 0, 800, 478);
+ _vm->setDeviceHotspot(kHS29Device, -1, -1, -1, -1);
+ if (_vm->invHas(kItemHorn))
+ _vm->_hotspots[kHS29Monkey]._flags = SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR;
+ _vm->_hotspotsCount = 7;
+}
+
+void Scene29::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->playSound(0x1093B, true);
+ _vm->startSoundTimerB(6);
+ _vm->queueInsertDeviceIcon();
+
+ if (_vm->invHas(kItemHorn)) {
+ _currMonkeySequenceId = 0xE8;
+ _nextMonkeySequenceId = -1;
+ gameSys.setAnimation(0xE8, 159, 4);
+ gameSys.insertSequence(_currMonkeySequenceId, 159, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.insertSequence(0xED, 39, 0, 0, kSeqNone, 0, 0, 0);
+ _currManSequenceId = 0xED;
+ _nextManSequenceId = -1;
+ gameSys.setAnimation(0xED, 39, 3);
+ _vm->_timers[4] = _vm->getRandom(20) + 60;
+ } else {
+ gameSys.insertSequence(0xF4, 19, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.setAnimation(0, 0, 4);
+ gameSys.insertSequence(0xED, 39, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.setAnimation(0, 0, 3);
+ }
+
+ gameSys.insertSequence(0xF3, 39, 0, 0, kSeqLoop, 0, 0, 0);
+ gameSys.insertSequence(0xF5, 38, 0, 0, kSeqLoop, 0, 0, 0);
+
+ if (_vm->_prevSceneNum == 27) {
+ gnap.initPos(12, 7, kDirBottomRight);
+ plat.initPos(12, 8, kDirIdleLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(8, 7), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(8, 8), -1, 0x107C2, 1);
+ } else {
+ gnap.initPos(-1, 7, kDirBottomRight);
+ plat.initPos(-2, 7, kDirIdleLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(2, 7), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(1, 7), -1, 0x107C2, 1);
+ }
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS29Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS29Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemJoint) {
+ gnap.useJointOnPlatypus();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS29Monkey:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemBanana) {
+ gnap._idleFacing = kDirBottomRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS29Monkey], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS29UseBananaWithMonkey;
+ _vm->_newSceneNum = 51;
+ _vm->_isLeavingScene = true;
+ _vm->setGrabCursorSprite(-1);
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS29Monkey], 5, 6);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(5, 6));
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(_vm->_hotspotsWalkPos[kHS29Monkey]);
+ break;
+ case GRAB_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS29ExitCircus:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 26;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS29ExitCircus], 0, 0x107AE, 1);
+ gnap._actionStatus = kAS29LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS29ExitCircus] + Common::Point(1, 0), -1, -1, 1);
+ }
+ break;
+
+ case kHS29ExitOutsideClown:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 27;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS29ExitOutsideClown], 0, 0x107AB, 1);
+ gnap._actionStatus = kAS29LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS29ExitOutsideClown] + Common::Point(0, -1), -1, 0x107CD, 1);
+ }
+ break;
+
+ case kHS29Arcade:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemDiceQuarterHole) {
+ _vm->setGrabCursorSprite(-1);
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 52;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS29Arcade], 0, -1, 1);
+ gnap.playIdle(_vm->_hotspotsWalkPos[kHS29Arcade]);
+ gnap._actionStatus = kAS29LeaveScene;
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS29Arcade], 2, 3);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan2();
+ break;
+ case GRAB_CURSOR:
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS29WalkArea1:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+ }
+
+ updateAnimations();
+
+ if (!_vm->isSoundPlaying(0x1093B))
+ _vm->playSound(0x1093B, true);
+
+ if (!_vm->_isLeavingScene) {
+ if (gnap._actionStatus < 0) {
+ gnap.updateIdleSequence();
+ plat.updateIdleSequence();
+ }
+ if (!_vm->_timers[4]) {
+ if (_vm->invHas(kItemHorn)) {
+ _vm->_timers[4] = _vm->getRandom(20) + 60;
+ if (gnap._actionStatus < 0) {
+ switch (_vm->getRandom(5)) {
+ case 0:
+ _nextManSequenceId = 0xED;
+ break;
+ case 1:
+ _nextManSequenceId = 0xEE;
+ break;
+ case 2:
+ _nextManSequenceId = 0xEF;
+ break;
+ case 3:
+ _nextManSequenceId = 0xF0;
+ break;
+ case 4:
+ _nextManSequenceId = 0xF1;
+ break;
+ }
+ }
+ }
+ }
+ _vm->playSoundB();
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene29::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS29UseBananaWithMonkey:
+ _nextMonkeySequenceId = 0xE5;
+ break;
+ case kAS29LeaveScene:
+ _vm->_sceneDone = true;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2 && _nextManSequenceId != -1) {
+ gameSys.insertSequence(_nextManSequenceId, 39, _currManSequenceId, 39, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextManSequenceId, 39, 3);
+ _currManSequenceId = _nextManSequenceId;
+ _nextManSequenceId = -1;
+ }
+
+ if (gameSys.getAnimationStatus(4) == 2) {
+ if (_nextMonkeySequenceId == 0xE5) {
+ gameSys.insertSequence(0xF2, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceDatNum = 0;
+ gnap._sequenceId = 0xF2;
+ gameSys.setAnimation(0xE6, 159, 0);
+ gameSys.setAnimation(0, 159, 4);
+ gameSys.insertSequence(_nextMonkeySequenceId, 159, _currMonkeySequenceId, 159, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0xE6, 159, _nextMonkeySequenceId, 159, kSeqSyncWait, 0, 0, 0);
+ gnap._actionStatus = kAS29LeaveScene;
+ _currMonkeySequenceId = 0xE6;
+ _nextMonkeySequenceId = -1;
+ _vm->_timers[5] = 30;
+ while (_vm->_timers[5] && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+
+ _vm->_plat->walkTo(Common::Point(0, 8), 1, 0x107CF, 1);
+
+ while (gameSys.getAnimationStatus(1) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+ } else if (_nextMonkeySequenceId == -1) {
+ switch (_vm->getRandom(6)) {
+ case 0:
+ _nextMonkeySequenceId = 0xE8;
+ break;
+ case 1:
+ _nextMonkeySequenceId = 0xE9;
+ break;
+ case 2:
+ _nextMonkeySequenceId = 0xEA;
+ break;
+ case 3:
+ _nextMonkeySequenceId = 0xEB;
+ break;
+ case 4:
+ _nextMonkeySequenceId = 0xEC;
+ break;
+ case 5:
+ _nextMonkeySequenceId = 0xE7;
+ break;
+ }
+ gameSys.insertSequence(_nextMonkeySequenceId, 159, _currMonkeySequenceId, 159, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextMonkeySequenceId, 159, 4);
+ _currMonkeySequenceId = _nextMonkeySequenceId;
+ _nextMonkeySequenceId = -1;
+ } else {
+ gameSys.insertSequence(_nextMonkeySequenceId, 159, _currMonkeySequenceId, 159, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextMonkeySequenceId, 159, 4);
+ _currMonkeySequenceId = _nextMonkeySequenceId;
+ _nextMonkeySequenceId = -1;
+ }
+ }
+}
+
+} // End of namespace Gnap
diff --git a/engines/gnap/scenes/group2.h b/engines/gnap/scenes/group2.h
new file mode 100644
index 0000000000..8f56594f16
--- /dev/null
+++ b/engines/gnap/scenes/group2.h
@@ -0,0 +1,407 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can 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 GNAP_GROUP2_H
+#define GNAP_GROUP2_H
+
+#include "gnap/debugger.h"
+
+namespace Gnap {
+
+enum {
+ kHS20Platypus = 0,
+ kHS20GroceryStoreHat = 1,
+ kHS20ExitParkingLot = 2,
+ kHS20StonerGuy = 3,
+ kHS20GroceryStoreGuy = 4,
+ kHS20Device = 5,
+ kHS20ExitInsideGrubCity = 6,
+ kHS20ExitOutsideCircusWorld = 7,
+ kHS20ExitOutsideToyStore = 8,
+ kHS20ExitPhone = 9,
+ kHS20WalkArea1 = 10,
+ kHS20WalkArea2 = 11
+};
+
+enum {
+ kHS21Platypus = 0,
+ kHS21Banana = 1,
+ kHS21OldLady = 2,
+ kHS21Device = 3,
+ kHS21ExitOutsideGrubCity = 4,
+ kHS21WalkArea1 = 5,
+ kHS21WalkArea2 = 6
+};
+
+enum {
+ kHS22Platypus = 0,
+ kHS22ExitOutsideGrubCity = 1,
+ kHS22ExitBackGrubCity = 2,
+ kHS22Cashier = 3,
+ kHS22Device = 4,
+ kHS22WalkArea1 = 5,
+ kHS22WalkArea2 = 6
+};
+
+enum {
+ kHS23Platypus = 0,
+ kHS23ExitFrontGrubCity = 1,
+ kHS23Device = 2,
+ kHS23Cereals = 3,
+ kHS23WalkArea1 = 4,
+ kHS23WalkArea2 = 5
+};
+
+enum {
+ kHS24Platypus = 0,
+ kHS24ExitCircusWorld = 1,
+ kHS24ExitOutsideGrubCity = 2,
+ kHS24Device = 3,
+ kHS24WalkArea1 = 4,
+ kHS24WalkArea2 = 5,
+ kHS24WalkArea3 = 6
+};
+
+enum {
+ kHS25Platypus = 0,
+ kHS25TicketVendor = 1,
+ kHS25ExitOutsideCircusWorld = 2,
+ kHS25ExitInsideCircusWorld = 3,
+ kHS25Device = 4,
+ kHS25Posters1 = 5,
+ kHS25Posters2 = 6,
+ kHS25Posters3 = 7,
+ kHS25Posters4 = 8,
+ kHS25WalkArea1 = 9,
+ kHS25WalkArea2 = 10
+};
+
+enum {
+ kHS26Platypus = 0,
+ kHS26ExitOutsideCircusWorld = 1,
+ kHS26ExitOutsideClown = 2,
+ kHS26ExitArcade = 3,
+ kHS26ExitElephant = 4,
+ kHS26ExitBeerStand = 5,
+ kHS26Device = 6,
+ kHS26WalkArea1 = 7,
+ kHS26WalkArea2 = 8
+};
+
+enum {
+ kHS27Platypus = 0,
+ kHS27Janitor = 1,
+ kHS27Device = 2,
+ kHS27Bucket = 3,
+ kHS27ExitCircus = 4,
+ kHS27ExitArcade = 5,
+ kHS27ExitBeerStand = 6,
+ kHS27ExitClown = 7,
+ kHS27WalkArea1 = 8
+};
+
+enum {
+ kHS28Platypus = 0,
+ kHS28Horn = 1,
+ kHS28Clown = 2,
+ kHS28ExitOutsideClown = 3,
+ kHS28EmptyBucket = 4,
+ kHS28Device = 5,
+ kHS28WalkArea1 = 6,
+ kHS28WalkArea2 = 7
+};
+
+enum {
+ kHS29Platypus = 0,
+ kHS29Monkey = 1,
+ kHS29Device = 2,
+ kHS29ExitCircus = 3,
+ kHS29ExitOutsideClown = 4,
+ kHS29Arcade = 5,
+ kHS29WalkArea1 = 6
+};
+
+enum {
+ kAS20LeaveScene = 0,
+ kAS20TalkStonerGuyNoJoint = 2,
+ kAS20TalkStonerGuyHasJoint = 3,
+ kAS20GrabJoint = 4,
+ kAS20ActionDone = 5,
+ kAS20TalkGroceryStoreGuy = 6,
+ kAS20GrabGroceryStoreGuy = 9,
+ kAS20GrabGroceryStoreHat = 10,
+ kAS20SwitchGroceryStoreHat = 11,
+ kAS20SwitchGroceryStoreHatDone = 12,
+ kAS20GrabJointDone = 13
+};
+
+enum {
+ kAS21TalkOldLady = 0,
+ kAS21GrabBanana = 1,
+ kAS21GrabBananaDone = 2,
+ kAS21GrabOldLady = 3,
+ kAS21UseHatWithOldLady = 4,
+ kAS21UseHatWithOldLadyDone = 5,
+ kAS21LeaveScene = 6
+};
+
+enum {
+ kAS22LeaveScene = 0,
+ kAS22TalkCashier = 1
+};
+
+enum {
+ kAS23LookCereals = 0,
+ kAS23GrabCereals = 1,
+ kAS23GrabCerealsDone = 2,
+ kAS23LeaveScene = 3
+};
+
+enum {
+ kAS24LeaveScene = 0
+};
+
+enum {
+ kAS25TalkTicketVendor = 0,
+ kAS25EnterCircusWihoutTicket = 1,
+ kAS25ShowTicketToVendor = 2,
+ kAS25ShowTicketToVendorDone = 3,
+ kAS25EnterCircusWihoutTicketDone = 4,
+ kAS25LeaveScene = 5
+};
+
+enum {
+ kAS26LeaveScene = 0
+};
+
+enum {
+ kAS27TalkJanitor = 0,
+ kAS27GrabBucket = 1,
+ kAS27GrabBucketDone = 2,
+ kAS27ShowPictureToJanitor = 3,
+ kAS27TryEnterClownTent = 4,
+ kAS27TryEnterClownTentDone = 5,
+ kAS27EnterClownTent = 6,
+ kAS27LeaveScene = 7
+};
+
+enum {
+ kAS28UseBeerBucketWithClown = 0,
+ kAS28UsePillBucketWithClown = 1,
+ kAS28GrabHornFails = 2,
+ kAS28GrabEmptyBucket = 3,
+ kAS28GrabHornSuccess = 4,
+ kAS28GrabHornSuccessDone = 5,
+ kAS28GrabEmptyBucketDone = 6,
+ kAS28GrabHornFailsDone = 7,
+ kAS28TalkClown = 8,
+ kAS28GnapWaiting = 9,
+ kAS28LeaveScene = 10
+};
+
+enum {
+ kAS29UseBananaWithMonkey = 0,
+ kAS29LeaveScene = 2
+};
+
+class GnapEngine;
+class CutScene;
+
+class Scene20: public Scene {
+public:
+ Scene20(GnapEngine *vm);
+ virtual ~Scene20() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb();
+
+private:
+ int _currStonerGuySequenceId;
+ int _nextStonerGuySequenceId;
+ int _currGroceryStoreGuySequenceId;
+ int _nextGroceryStoreGuySequenceId;
+ int _stonerGuyCtr;
+ int _groceryStoreGuyCtr;
+ bool _stonerGuyShowingJoint;
+
+ void stopSounds();
+};
+
+class Scene21: public Scene {
+public:
+ Scene21(GnapEngine *vm);
+ virtual ~Scene21() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _currOldLadySequenceId;
+ int _nextOldLadySequenceId;
+};
+
+class Scene22: public Scene {
+public:
+ Scene22(GnapEngine *vm);
+ virtual ~Scene22() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _currCashierSequenceId;
+ int _nextCashierSequenceId;
+ bool _caughtBefore;
+ int _cashierCtr;
+};
+
+class Scene23: public Scene {
+public:
+ Scene23(GnapEngine *vm);
+ virtual ~Scene23() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _currStoreClerkSequenceId;
+ int _nextStoreClerkSequenceId;
+};
+
+class Scene24: public Scene {
+public:
+ Scene24(GnapEngine *vm);
+ virtual ~Scene24() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _currWomanSequenceId;
+ int _nextWomanSequenceId;
+ int _boySequenceId;
+ int _girlSequenceId;
+};
+
+class Scene25: public Scene {
+public:
+ Scene25(GnapEngine *vm);
+ virtual ~Scene25() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _currTicketVendorSequenceId;
+ int _nextTicketVendorSequenceId;
+
+ void playAnims(int index);
+};
+
+class Scene26: public Scene {
+public:
+ Scene26(GnapEngine *vm);
+ virtual ~Scene26() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _currKidSequenceId;
+ int _nextKidSequenceId;
+};
+
+class Scene27: public Scene {
+public:
+ Scene27(GnapEngine *vm);
+ virtual ~Scene27() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _nextJanitorSequenceId;
+ int _currJanitorSequenceId;
+};
+
+class Scene28: public Scene {
+public:
+ Scene28(GnapEngine *vm);
+ virtual ~Scene28() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _currClownSequenceId;
+ int _nextClownSequenceId;
+ int _clownTalkCtr;
+};
+
+class Scene29: public Scene {
+public:
+ Scene29(GnapEngine *vm);
+ virtual ~Scene29() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _currMonkeySequenceId;
+ int _nextMonkeySequenceId;
+ int _currManSequenceId;
+ int _nextManSequenceId;
+};
+
+} // End of namespace Gnap
+
+#endif // GNAP_GROUP1_H
diff --git a/engines/gnap/scenes/group3.cpp b/engines/gnap/scenes/group3.cpp
new file mode 100644
index 0000000000..98a4f6c454
--- /dev/null
+++ b/engines/gnap/scenes/group3.cpp
@@ -0,0 +1,1612 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 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 "gnap/gnap.h"
+#include "gnap/gamesys.h"
+#include "gnap/resource.h"
+#include "gnap/scenes/group3.h"
+
+namespace Gnap {
+
+Scene30::Scene30(GnapEngine *vm) : Scene(vm) {
+ _kidSequenceId = -1;
+}
+
+int Scene30::init() {
+ return _vm->isFlag(kGFUnk23) ? 0x10B : 0x10A;
+}
+
+void Scene30::updateHotspots() {
+ _vm->setHotspot(kHS30Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS30PillMachine, 598, 342, 658, 426, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 9, 7);
+ _vm->setHotspot(kHS30ExitCircus, 100, 590 - _vm->_deviceY1, 700, 600, SF_EXIT_D_CURSOR | SF_WALKABLE, 5, 9);
+ _vm->setHotspot(kHS30WalkArea1, 0, 0, 800, 514);
+ _vm->setDeviceHotspot(kHS30Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 5;
+}
+
+void Scene30::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ bool hasTakenPill = false;
+
+ _vm->playSound(0x1093B, true);
+ _vm->startSoundTimerB(6);
+
+ _vm->queueInsertDeviceIcon();
+
+ if (_vm->isFlag(kGFUnk23))
+ gameSys.insertSequence(0x106, 1, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (!_vm->isFlag(kGFUnk13))
+ gameSys.insertSequence(0x107, 1, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->_timers[5] = _vm->getRandom(50) + 180;
+
+ gameSys.insertSequence(0x101, 40, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->_timers[4] = _vm->getRandom(100) + 300;
+
+ _kidSequenceId = 0x101;
+ gnap.initPos(7, 12, kDirBottomRight);
+ plat.initPos(6, 12, kDirIdleLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(7, 8), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(6, 8), -1, 0x107C2, 1);
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS30Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS30Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemJoint) {
+ gnap.useJointOnPlatypus();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS30PillMachine:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemDiceQuarterHole && !_vm->isFlag(kGFUnk23)) {
+ _vm->_hotspots[kHS30WalkArea1]._flags |= SF_WALKABLE;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS30PillMachine], 0, 0x107BC, 1);
+ _vm->_hotspots[kHS30WalkArea1]._flags &= ~SF_WALKABLE;
+ gnap._actionStatus = kAS30UsePillMachine;
+ hasTakenPill = true;
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS30PillMachine], 8, 5);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.walkTo(Common::Point(9, 8), 0, 0x107BC, 1);
+ gnap._actionStatus = kAS30LookPillMachine;
+ break;
+ case GRAB_CURSOR:
+ gnap.playScratchingHead(Common::Point(8, 5));
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible(Common::Point(8, 5));
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS30ExitCircus:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ if (hasTakenPill)
+ _vm->_newSceneNum = 47;
+ else
+ _vm->_newSceneNum = 26;
+ gnap.walkTo(Common::Point(-1, _vm->_hotspotsWalkPos[kHS30ExitCircus].y), 0, 0x107AE, 1);
+ gnap._actionStatus = kAS30LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS30ExitCircus] + Common::Point(1, 0), -1, 0x107C2, 1);
+ }
+ break;
+
+ case kHS30WalkArea1:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+ }
+
+ updateAnimations();
+
+ if (!_vm->isSoundPlaying(0x1093B))
+ _vm->playSound(0x1093B, true);
+
+ if (!_vm->_isLeavingScene) {
+ plat.updateIdleSequence();
+ if (gnap._actionStatus < 0)
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[4]) {
+ _vm->_timers[4] = _vm->getRandom(100) + 300;
+ if (gnap._actionStatus < 0) {
+ if (_vm->getRandom(5) == 1) {
+ gameSys.insertSequence(0xFF, 40, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.insertSequence(0x100, 40, _kidSequenceId, 40, kSeqSyncWait, 0, 0, 0);
+ _kidSequenceId = 0x100;
+ } else {
+ gameSys.insertSequence(0xFE, 40, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ }
+ }
+ if (!_vm->_timers[5]) {
+ _vm->_timers[5] = _vm->getRandom(50) + 180;
+ if (gnap._actionStatus < 0) {
+ if (!_vm->isFlag(kGFUnk23) || hasTakenPill)
+ gameSys.insertSequence(0x109, 20, 0, 0, kSeqNone, 0, 0, 0);
+ else
+ gameSys.insertSequence(0x108, 20, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ }
+ _vm->playSoundB();
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene30::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS30LeaveScene:
+ _vm->_sceneDone = true;
+ break;
+ case kAS30UsePillMachine:
+ _vm->setGrabCursorSprite(-1);
+ gameSys.setAnimation(0x105, gnap._id, 0);
+ gameSys.insertSequence(0x105, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x105;
+ gnap._sequenceDatNum = 0;
+ gnap._actionStatus = kAS30UsePillMachine2;
+ break;
+ case kAS30UsePillMachine2:
+ _vm->hideCursor();
+ _vm->setGrabCursorSprite(-1);
+ _vm->addFullScreenSprite(0x3F, 255);
+ gameSys.removeSequence(0x105, gnap._id, true);
+ gameSys.setAnimation(0x102, 256, 0);
+ gameSys.insertSequence(0x102, 256, 0, 0, kSeqNone, 0, 0, 0);
+ while (gameSys.getAnimationStatus(0) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+ gameSys.setAnimation(0x103, gnap._id, 0);
+ gameSys.insertSequence(0x103, gnap._id, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->removeFullScreenSprite();
+ _vm->showCursor();
+ gnap._actionStatus = kAS30UsePillMachine3;
+ _vm->invAdd(kItemPill);
+ _vm->setFlag(kGFUnk23);
+ break;
+ case kAS30UsePillMachine3:
+ gameSys.setAnimation(0x104, gnap._id, 0);
+ gameSys.insertSequence(0x104, gnap._id, makeRid(gnap._sequenceDatNum, 0x103), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x104;
+ gnap._sequenceDatNum = 0;
+ gnap._actionStatus = kAS30UsePillMachine4;
+ _vm->setGrabCursorSprite(kItemDiceQuarterHole);
+ break;
+ case kAS30UsePillMachine4:
+ gameSys.insertSequence(0x106, 1, 0, 0, kSeqNone, 0, 0, 0);
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS30PillMachine] + Common::Point(0, 1), -1, 0x107BC, 1);
+ gnap._actionStatus = -1;
+ break;
+ case kAS30LookPillMachine:
+ if (_vm->isFlag(kGFUnk23))
+ _vm->showFullScreenSprite(0xE3);
+ else
+ _vm->showFullScreenSprite(0xE2);
+ gnap._actionStatus = -1;
+ break;
+ }
+ }
+}
+
+/*****************************************************************************/
+
+Scene31::Scene31(GnapEngine *vm) : Scene(vm) {
+ _beerGuyDistracted = false;
+ _currClerkSequenceId = -1;
+ _nextClerkSequenceId = -1;
+ _clerkMeasureCtr = -1;
+ _clerkMeasureMaxCtr = 3;
+}
+
+int Scene31::init() {
+ return 0x105;
+}
+
+void Scene31::updateHotspots() {
+ _vm->setHotspot(kHS31Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS31MeasuringClown, 34, 150, 256, 436, SF_WALKABLE | SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 0, 6);
+ _vm->setHotspot(kHS31BeerBarrel, 452, 182, 560, 306, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 6, 7);
+ _vm->setHotspot(kHS31ExitCircus, 150, 585, 650, 600, SF_EXIT_D_CURSOR | SF_WALKABLE, 5, 9);
+ _vm->setHotspot(kHS31ExitOutsideClown, 0, 0, 15, 600, SF_EXIT_L_CURSOR | SF_WALKABLE, 0, 8);
+ _vm->setHotspot(kHS31WalkArea1, 0, 0, 800, 480);
+ _vm->setDeviceHotspot(kHS31Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 7;
+}
+
+void Scene31::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->playSound(0x1093B, true);
+ _vm->startSoundTimerB(6);
+ _vm->queueInsertDeviceIcon();
+
+ _beerGuyDistracted = false;
+ gameSys.insertSequence(0xFB, 39, 0, 0, kSeqNone, 0, 0, 0);
+
+ _currClerkSequenceId = 0xFB;
+ _nextClerkSequenceId = -1;
+
+ gameSys.setAnimation(0xFB, 39, 3);
+
+ _vm->_timers[4] = _vm->getRandom(20) + 60;
+ _vm->_timers[5] = _vm->getRandom(50) + 180;
+
+ if (_vm->_prevSceneNum == 27) {
+ gnap.initPos(-1, 8, kDirBottomLeft);
+ plat.initPos(-1, 9, kDirIdleRight);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(3, 8), -1, 0x107BA, 1);
+ plat.walkTo(Common::Point(3, 9), -1, 0x107D2, 1);
+ } else {
+ gnap.initPos(7, 12, kDirBottomRight);
+ plat.initPos(6, 12, kDirIdleLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(7, 8), -1, 0x107BA, 1);
+ plat.walkTo(Common::Point(6, 8), -1, 0x107D2, 1);
+ }
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS31Device:
+ if (gnap._actionStatus < 0 || gnap._actionStatus == kAS31PlatMeasuringClown) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS31Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemJoint) {
+ gnap.useJointOnPlatypus();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS31MeasuringClown:
+ if (gnap._actionStatus < 0 || gnap._actionStatus == kAS31PlatMeasuringClown) {
+ if (gnap._actionStatus == kAS31PlatMeasuringClown) {
+ if (_vm->_verbCursor == LOOK_CURSOR)
+ gnap.playScratchingHead(Common::Point(2, 2));
+ else
+ gnap.playImpossible();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS31MeasuringClown] + Common::Point(0, 1), 2, 2);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(2, 2));
+ break;
+ case GRAB_CURSOR:
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS31MeasuringClown] + Common::Point(0, 1), -1, -1, 1);
+ _vm->_hotspots[kHS31WalkArea1]._flags |= SF_WALKABLE;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS31MeasuringClown], 0, 0x107B9, 1);
+ _vm->_hotspots[kHS31WalkArea1]._flags &= ~SF_WALKABLE;
+ gnap._actionStatus = kAS31UseMeasuringClown;
+ _vm->_timers[4] = 300;
+ break;
+ case TALK_CURSOR:
+ gnap.playImpossible();
+ break;
+ case PLAT_CURSOR:
+ if (!_vm->invHas(kItemBucketWithBeer)) {
+ gnap.useDeviceOnPlatypus();
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS31MeasuringClown] + Common::Point(0, 1), 1, 0x107C2, 1);
+ _vm->_hotspots[kHS31WalkArea1]._flags |= SF_WALKABLE;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS31MeasuringClown], 1, 0x107C2, 1);
+ _vm->_hotspots[kHS31WalkArea1]._flags &= ~SF_WALKABLE;
+ plat._actionStatus = kAS31PlatMeasuringClown;
+ gnap._actionStatus = kAS31PlatMeasuringClown;
+ _vm->_timers[4] = 300;
+ } else
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS31BeerBarrel:
+ if (gnap._actionStatus < 0 || gnap._actionStatus == kAS31PlatMeasuringClown) {
+ if (_vm->_grabCursorSpriteIndex == kItemEmptyBucket && _beerGuyDistracted) {
+ _vm->setGrabCursorSprite(-1);
+ gnap.walkTo(gnap._pos, -1, gnap.getSequenceId(kGSIdle, _vm->_hotspotsWalkPos[kHS31BeerBarrel]) | 0x10000, 1);
+ _clerkMeasureMaxCtr += 5;
+ gameSys.insertSequence(0xF8, 59, 0, 0, kSeqNone, 0, 0, 0);
+ gnap.playPullOutDevice(Common::Point(6, 8));
+ gnap.playUseDevice();
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS31BeerBarrel], 0, 0x107BC, 1);
+ gnap._actionStatus = kAS31FillEmptyBucketWithBeer;
+ _vm->_timers[4] = 300;
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS31BeerBarrel], 6, 2);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(6, 2));
+ break;
+ case GRAB_CURSOR:
+ if (_beerGuyDistracted) {
+ gnap.playScratchingHead(Common::Point(6, 2));
+ } else {
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS31BeerBarrel], 0, 0x107BC, 1);
+ gnap._actionStatus = kAS31UseBeerBarrel;
+ gnap._idleFacing = kDirUpLeft;
+ }
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS31ExitCircus:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 26;
+ gnap.walkTo(Common::Point(-1, _vm->_hotspotsWalkPos[kHS31ExitCircus].y), 0, 0x107AE, 1);
+ gnap._actionStatus = kAS31LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS31ExitCircus] + Common::Point(1, 0), -1, -1, 1);
+ }
+ break;
+
+ case kHS31ExitOutsideClown:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 27;
+ gnap.walkTo(Common::Point(-1, _vm->_hotspotsWalkPos[kHS31ExitOutsideClown].y), 0, 0x107AF, 1);
+ gnap._actionStatus = kAS31LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS31ExitOutsideClown] + Common::Point(0, 1), -1, 0x107CF, 1);
+ }
+ break;
+
+ case kHS31WalkArea1:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+ }
+
+ updateAnimations();
+
+ if (!_vm->isSoundPlaying(0x1093B))
+ _vm->playSound(0x1093B, true);
+
+ if (!_vm->_isLeavingScene) {
+ if (plat._actionStatus < 0)
+ plat.updateIdleSequence();
+ if (gnap._actionStatus < 0)
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[4]) {
+ _vm->_timers[4] = _vm->getRandom(20) + 60;
+ if (gnap._actionStatus < 0 && _nextClerkSequenceId == -1) {
+ switch (_vm->getRandom(6)){
+ case 0:
+ _nextClerkSequenceId = 0xFF;
+ break;
+ case 1:
+ _nextClerkSequenceId = 0x100;
+ break;
+ case 2:
+ _nextClerkSequenceId = 0x101;
+ break;
+ default:
+ _nextClerkSequenceId = 0xFB;
+ break;
+ }
+ }
+ }
+ if (!_vm->_timers[5]) {
+ _vm->_timers[5] = _vm->getRandom(50) + 180;
+ if (gnap._actionStatus < 0) {
+ if (_vm->getRandom(2) != 0)
+ gameSys.insertSequence(0x104, 20, 0, 0, kSeqNone, 0, 0, 0);
+ else
+ gameSys.insertSequence(0x103, 20, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ }
+ _vm->playSoundB();
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene31::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS31UseBeerBarrel:
+ _nextClerkSequenceId = 0xFE;
+ break;
+ case kAS31FillEmptyBucketWithBeer:
+ gameSys.setAnimation(0x102, 59, 0);
+ gameSys.insertSequence(0x102, 59, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._pos = Common::Point(5, 7);
+ gnap._sequenceDatNum = 0;
+ gnap._sequenceId = 0x102;
+ gnap._id = 59;
+ gnap._actionStatus = kAS31FillEmptyBucketWithBeerDone;
+ break;
+ case kAS31FillEmptyBucketWithBeerDone:
+ gnap._idleFacing = kDirBottomLeft;
+ gnap.playPullOutDevice();
+ gnap.playUseDevice();
+ gameSys.insertSequence(0xF9, 59, 0xF8, 59, kSeqSyncWait, 0, 0, 0);
+ gnap._actionStatus = -1;
+ _vm->invAdd(kItemBucketWithBeer);
+ _vm->invRemove(kItemEmptyBucket);
+ _vm->setGrabCursorSprite(kItemBucketWithBeer);
+ break;
+ case kAS31UseMeasuringClown:
+ _nextClerkSequenceId = 0xFA;
+ _clerkMeasureMaxCtr = 1;
+ break;
+ case kAS31LeaveScene:
+ _vm->_sceneDone = true;
+ gnap._actionStatus = -1;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(1) == 2) {
+ gameSys.setAnimation(0, 0, 1);
+ if (plat._actionStatus == kAS31PlatMeasuringClown) {
+ _vm->_sceneWaiting = true;
+ _beerGuyDistracted = true;
+ _nextClerkSequenceId = 0xFA;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2) {
+ switch (_nextClerkSequenceId) {
+ case 0xFA:
+ gameSys.insertSequence(_nextClerkSequenceId, 39, _currClerkSequenceId, 39, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0xFC, 39, _nextClerkSequenceId, 39, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(0xFC, 39, 3);
+ _currClerkSequenceId = 0xFC;
+ _nextClerkSequenceId = 0xFC;
+ _clerkMeasureCtr = 0;
+ break;
+ case 0xFC:
+ ++_clerkMeasureCtr;
+ if (_clerkMeasureCtr >= _clerkMeasureMaxCtr) {
+ if (gnap._actionStatus != 5)
+ plat._actionStatus = -1;
+ _vm->_timers[0] = 40;
+ gameSys.insertSequence(0xFD, 39, _currClerkSequenceId, 39, kSeqSyncWait, 0, 0, 0);
+ _currClerkSequenceId = 0xFD;
+ _nextClerkSequenceId = -1;
+ if (gnap._actionStatus != kAS31FillEmptyBucketWithBeerDone && gnap._actionStatus != kAS31FillEmptyBucketWithBeer)
+ gnap._actionStatus = -1;
+ _beerGuyDistracted = false;
+ _clerkMeasureMaxCtr = 3;
+ gameSys.setAnimation(0xFD, 39, 3);
+ _vm->_sceneWaiting = false;
+ } else {
+ gameSys.insertSequence(_nextClerkSequenceId, 39, _currClerkSequenceId, 39, kSeqSyncWait, 0, 0, 0);
+ _currClerkSequenceId = _nextClerkSequenceId;
+ _nextClerkSequenceId = 0xFC;
+ gameSys.setAnimation(0xFC, 39, 3);
+ }
+ break;
+ case 0xFE:
+ gameSys.insertSequence(_nextClerkSequenceId, 39, _currClerkSequenceId, 39, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextClerkSequenceId, 39, 3);
+ _currClerkSequenceId = _nextClerkSequenceId;
+ _nextClerkSequenceId = -1;
+ gnap._actionStatus = -1;
+ break;
+ default:
+ if (_nextClerkSequenceId != -1) {
+ gameSys.insertSequence(_nextClerkSequenceId, 39, _currClerkSequenceId, 39, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextClerkSequenceId, 39, 3);
+ _currClerkSequenceId = _nextClerkSequenceId;
+ _nextClerkSequenceId = -1;
+ }
+ break;
+ }
+ }
+}
+
+/*****************************************************************************/
+
+Scene32::Scene32(GnapEngine *vm) : Scene(vm) {}
+
+int Scene32::init() {
+ _vm->_gameSys->setAnimation(0, 0, 0);
+ return _vm->isFlag(kGFPlatypusTalkingToAssistant) ? 0xF : 0x10;
+}
+
+void Scene32::updateHotspots() {
+ _vm->setHotspot(kHS32Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS32ExitTruck, 780, 226, 800, 455, SF_EXIT_R_CURSOR | SF_WALKABLE, 10, 6);
+ _vm->setHotspot(kHS32WalkArea1, 0, 0, 162, 426);
+ _vm->setHotspot(kHS32WalkArea2, 162, 0, 237, 396);
+ _vm->setHotspot(kHS32WalkArea3, 237, 0, 319, 363);
+ _vm->setHotspot(kHS32WalkArea4, 520, 0, 800, 404);
+ _vm->setHotspot(kHS32WalkArea5, 300, 447, 800, 600);
+ _vm->setHotspot(kHS32WalkArea6, 678, 0, 800, 404);
+ _vm->setHotspot(kHS32WalkArea7, 0, 0, 520, 351);
+ _vm->setHotspot(kHS32WalkArea8, 0, 546, 300, 600);
+ _vm->setDeviceHotspot(kHS32Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 11;
+}
+
+void Scene32::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->playSound(0x1091C, true);
+ _vm->startSoundTimerC(5);
+ _vm->queueInsertDeviceIcon();
+ _vm->_timers[4] = _vm->getRandom(100) + 300;
+
+ if (_vm->_prevSceneNum == 33) {
+ gnap.initPos(11, 6, kDirBottomLeft);
+ plat.initPos(12, 6, kDirIdleRight);
+ _vm->endSceneInit();
+ plat.walkTo(Common::Point(9, 6), -1, 0x107D2, 1);
+ gnap.walkTo(Common::Point(8, 6), -1, 0x107BA, 1);
+ } else {
+ gnap.initPos(1, 6, kDirBottomRight);
+ plat.initPos(1, 7, kDirIdleLeft);
+ _vm->endSceneInit();
+ }
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+ _vm->testWalk(0, 0, -1, -1, -1, -1);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS32Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS32Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible(plat._pos);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible(plat._pos);
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS32ExitTruck:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->setGrabCursorSprite(-1);
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS32ExitTruck], 0, 0x107AB, 1);
+ gnap._actionStatus = kAS32LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS32ExitTruck] + Common::Point(0, 1), -1, 0x107CD, 1);
+ _vm->_newSceneNum = 33;
+ }
+ break;
+
+ case kHS32WalkArea1:
+ case kHS32WalkArea2:
+ case kHS32WalkArea3:
+ case kHS32WalkArea4:
+ case kHS32WalkArea5:
+ case kHS32WalkArea6:
+ case kHS32WalkArea7:
+ case kHS32WalkArea8:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ }
+
+ if (_vm->_mouseClickState._left && gnap._actionStatus < 0) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = 0;
+ }
+
+ updateAnimations();
+
+ if (!_vm->isSoundPlaying(0x1091C))
+ _vm->playSound(0x1091C, true);
+
+ if (!_vm->_isLeavingScene) {
+ if (plat._actionStatus < 0)
+ plat.updateIdleSequence();
+ if (gnap._actionStatus < 0)
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[4]) {
+ _vm->_timers[4] = _vm->getRandom(100) + 300;
+ if (_vm->getRandom(2) != 0)
+ gameSys.insertSequence(0x0E, 180, 0, 0, kSeqNone, 0, 0, 0);
+ else
+ gameSys.insertSequence(0x0D, 180, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ _vm->playSoundC();
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene32::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ if (_vm->_gnap->_actionStatus == kAS32LeaveScene)
+ _vm->_sceneDone = true;
+ }
+}
+
+/*****************************************************************************/
+
+Scene33::Scene33(GnapEngine *vm) : Scene(vm) {
+ _currChickenSequenceId = -1;
+ _nextChickenSequenceId = -1;
+}
+
+int Scene33::init() {
+ return _vm->isFlag(kGFPlatypusTalkingToAssistant) ? 0x84 : 0x85;
+}
+
+void Scene33::updateHotspots() {
+ _vm->setHotspot(kHS33Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS33Chicken, 606, 455, 702, 568, SF_WALKABLE | SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 7, 8);
+ _vm->setHotspot(kHS33ExitHouse, 480, 120, 556, 240, SF_EXIT_U_CURSOR, 7, 3);
+ _vm->setHotspot(kHS33ExitBarn, 610, 75, 800, 164, SF_EXIT_U_CURSOR, 10, 3);
+ _vm->setHotspot(kHS33ExitCreek, 780, 336, 800, 556, SF_EXIT_R_CURSOR | SF_WALKABLE, 10, 8);
+ _vm->setHotspot(kHS33ExitPigpen, 0, 300, 20, 600, SF_EXIT_L_CURSOR | SF_WALKABLE, 0, 8);
+ _vm->setHotspot(kHS33WalkArea1, 120, 0, 514, 458);
+ _vm->setHotspot(kHS33WalkArea2, 0, 0, 800, 452);
+ _vm->setDeviceHotspot(kHS33Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 9;
+}
+
+void Scene33::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->playSound(0x1091C, true);
+ _vm->startSoundTimerC(6);
+ _vm->queueInsertDeviceIcon();
+
+ _currChickenSequenceId = 0x7E;
+ gameSys.setAnimation(0x7E, 179, 2);
+ gameSys.insertSequence(_currChickenSequenceId, 179, 0, 0, kSeqNone, 0, 0, 0);
+ _nextChickenSequenceId = -1;
+ _vm->_timers[5] = _vm->getRandom(20) + 30;
+ _vm->_timers[4] = _vm->getRandom(100) + 300;
+
+ switch (_vm->_prevSceneNum) {
+ case 34:
+ gnap.initPos(11, 7, kDirBottomLeft);
+ plat.initPos(12, 7, kDirIdleRight);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(8, 7), -1, 0x107BA, 1);
+ plat.walkTo(Common::Point(9, 7), -1, 0x107D2, 1);
+ break;
+ case 37:
+ gnap.initPos(7, 7, kDirBottomRight);
+ plat.initPos(8, 7, kDirIdleLeft);
+ _vm->endSceneInit();
+ break;
+ case 32:
+ gnap.initPos(-1, 6, kDirBottomRight);
+ plat.initPos(-1, 7, kDirIdleLeft);
+ _vm->endSceneInit();
+ plat.walkTo(Common::Point(2, 7), -1, 0x107C2, 1);
+ gnap.walkTo(Common::Point(2, 8), -1, 0x107B9, 1);
+ break;
+ default:
+ gnap.initPos(3, 7, kDirBottomRight);
+ plat.initPos(2, 7, kDirIdleLeft);
+ _vm->endSceneInit();
+ break;
+ }
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+ _vm->testWalk(0, 0, 7, 6, 8, 6);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS33Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS33Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible(plat._pos);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible(plat._pos);
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS33Chicken:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(7, 9), 9, 8);
+ } else {
+ switch (_vm->_verbCursor) {
+ case GRAB_CURSOR:
+ gnap._idleFacing = kDirBottomRight;
+ if (gnap.walkTo(_vm->_hotspotsWalkPos[kHS33Chicken], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1))
+ gnap._actionStatus = kAS33UseChicken;
+ else
+ gnap._actionStatus = -1;
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirBottomRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS33Chicken], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS33TalkChicken;
+ break;
+ case LOOK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS33ExitHouse:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ gnap._actionStatus = kAS33LeaveScene;
+ _vm->_newSceneNum = 37;
+ if (gnap._pos.x > 6)
+ gnap.walkTo(gnap._pos, 0, 0x107AD, 1);
+ else
+ gnap.walkTo(Common::Point(6, 7), 0, 0x107B1, 1);
+ }
+ break;
+
+ case kHS33ExitBarn:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ gnap._actionStatus = kAS33LeaveScene;
+ _vm->_newSceneNum = 35;
+ if (gnap._pos.x > 7)
+ gnap.walkTo(gnap._pos, 0, 0x107AD, 1);
+ else
+ gnap.walkTo(Common::Point(7, 7), 0, 0x107B1, 1);
+ }
+ break;
+
+ case kHS33ExitCreek:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS33ExitCreek], 0, 0x107AB, 1);
+ gnap._actionStatus = kAS33LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS33ExitCreek], -1, 0x107CD, 1);
+ _vm->_newSceneNum = 34;
+ }
+ break;
+
+ case kHS33ExitPigpen:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS33ExitPigpen], 0, 0x107AF, 1);
+ gnap._actionStatus = kAS33LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS33ExitPigpen], -1, 0x107CF, 1);
+ _vm->_newSceneNum = 32;
+ }
+ break;
+
+ case kHS33WalkArea1:
+ case kHS33WalkArea2:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left && gnap._actionStatus < 0) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+ }
+
+ updateAnimations();
+
+ if (!_vm->isSoundPlaying(0x1091C))
+ _vm->playSound(0x1091C, true);
+
+ if (!_vm->_isLeavingScene) {
+ if (plat._actionStatus < 0)
+ plat.updateIdleSequence();
+ if (gnap._actionStatus < 0)
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[4]) {
+ _vm->_timers[4] = _vm->getRandom(100) + 300;
+ if (_vm->getRandom(2) != 0)
+ gameSys.insertSequence(0x83, 256, 0, 0, kSeqNone, 0, 0, 0);
+ else
+ gameSys.insertSequence(0x82, 256, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ if (!_vm->_timers[5] && _nextChickenSequenceId == -1 && gnap._actionStatus != kAS33TalkChicken && gnap._actionStatus != kAS33UseChicken) {
+ if (_vm->getRandom(6) != 0) {
+ _nextChickenSequenceId = 0x7E;
+ _vm->_timers[5] = _vm->getRandom(20) + 30;
+ } else {
+ _nextChickenSequenceId = 0x80;
+ _vm->_timers[5] = _vm->getRandom(20) + 50;
+ }
+ }
+ _vm->playSoundC();
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene33::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ switch (gnap._actionStatus) {
+ case kAS33LeaveScene:
+ _vm->_sceneDone = true;
+ break;
+ case kAS33TalkChicken:
+ _nextChickenSequenceId = 0x7F;
+ break;
+ case kAS33UseChicken:
+ _nextChickenSequenceId = 0x81;
+ _vm->_timers[2] = 100;
+ break;
+ case kAS33UseChickenDone:
+ gameSys.insertSequence(0x107B5, gnap._id, 0x81, 179, kSeqSyncWait, 0, 75 * gnap._pos.x - gnap._gridX, 48 * gnap._pos.y - gnap._gridY);
+ gnap._sequenceId = 0x7B5;
+ gnap._sequenceDatNum = 1;
+ _currChickenSequenceId = 0x7E;
+ gameSys.setAnimation(0x7E, 179, 2);
+ gameSys.insertSequence(_currChickenSequenceId, 179, 0, 0, kSeqNone, 0, 0, 0);
+ gnap._actionStatus = -1;
+ _vm->_timers[5] = 30;
+ break;
+ default:
+ gnap._actionStatus = -1;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(2) == 2) {
+ if (_nextChickenSequenceId == 0x81) {
+ gameSys.setAnimation(_nextChickenSequenceId, 179, 0);
+ gameSys.insertSequence(_nextChickenSequenceId, 179, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.removeSequence(_currChickenSequenceId, 179, true);
+ _nextChickenSequenceId = -1;
+ _currChickenSequenceId = -1;
+ gnap._actionStatus = kAS33UseChickenDone;
+ _vm->_timers[5] = 500;
+ } else if (_nextChickenSequenceId == 0x7F) {
+ gameSys.setAnimation(_nextChickenSequenceId, 179, 2);
+ gameSys.insertSequence(_nextChickenSequenceId, 179, _currChickenSequenceId, 179, kSeqSyncWait, 0, 0, 0);
+ _currChickenSequenceId = _nextChickenSequenceId;
+ _nextChickenSequenceId = -1;
+ gnap._actionStatus = -1;
+ } else if (_nextChickenSequenceId != -1) {
+ gameSys.setAnimation(_nextChickenSequenceId, 179, 2);
+ gameSys.insertSequence(_nextChickenSequenceId, 179, _currChickenSequenceId, 179, kSeqSyncWait, 0, 0, 0);
+ _currChickenSequenceId = _nextChickenSequenceId;
+ _nextChickenSequenceId = -1;
+ }
+ }
+}
+
+/*****************************************************************************/
+
+Scene38::Scene38(GnapEngine *vm) : Scene(vm) {
+}
+
+int Scene38::init() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ gameSys.setAnimation(0, 0, 0);
+ gameSys.setAnimation(0, 0, 1);
+ return 0xA5;
+}
+
+void Scene38::updateHotspots() {
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->setHotspot(kHS38Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS38ExitHouse, 150, 585, 650, 600, SF_EXIT_D_CURSOR, 0, 8);
+ _vm->setHotspot(kHS38ExitCave, 430, 440, 655, 470, SF_WALKABLE, 0, 8);
+ _vm->setHotspot(kHS38TrapDoorLid1, 525, 265, 640, 350, SF_DISABLED);
+ _vm->setHotspot(kHS38TrapDoorLid2, 555, 350, 670, 430, SF_DISABLED);
+ _vm->setHotspot(kHS38HuntingTrophy, 170, 85, 250, 190, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 0, 8);
+ _vm->setHotspot(kHS38WalkArea1, 330, 270, 640, 380, SF_DISABLED | SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 0, 8);
+ _vm->setHotspot(kHS38WalkArea2, 0, 0, 799, 396);
+ _vm->setHotspot(kHS38WalkArea3, 0, 585, 799, 599, SF_WALKABLE | SF_DISABLED);
+ _vm->setHotspot(kHS38WalkArea4, 0, 0, 97, 445);
+ _vm->setHotspot(kHS38WalkArea5, 770, 0, 799, 445);
+ _vm->setHotspot(kHS38WalkArea6, 393, 0, 698, 445, SF_WALKABLE | SF_DISABLED);
+ _vm->setDeviceHotspot(kHS38Device, -1, -1, -1, -1);
+ if (plat._actionStatus == kAS38PlatypusHoldingTrapDoor)
+ _vm->_hotspots[kHS38Platypus]._flags = SF_WALKABLE | SF_DISABLED;
+ if (plat._actionStatus == kAS38PlatypusHoldingTrapDoor)
+ _vm->_hotspots[kHS38ExitCave]._flags = SF_EXIT_D_CURSOR;
+ else if (gnap._actionStatus == kAS38HoldingHuntingTrophy)
+ _vm->_hotspots[kHS38ExitCave]._flags = SF_EXIT_D_CURSOR;
+ if (plat._actionStatus == kAS38PlatypusHoldingTrapDoor)
+ _vm->_hotspots[kHS38TrapDoorLid1]._flags = SF_DISABLED;
+ else if (gnap._actionStatus == kAS38HoldingHuntingTrophy)
+ _vm->_hotspots[kHS38TrapDoorLid1]._flags = SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR;
+ if (plat._actionStatus == kAS38PlatypusHoldingTrapDoor)
+ _vm->_hotspots[kHS38TrapDoorLid2]._flags = SF_DISABLED;
+ else if (gnap._actionStatus == kAS38HoldingHuntingTrophy)
+ _vm->_hotspots[kHS38TrapDoorLid2]._flags = SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR;
+ if (plat._actionStatus == kAS38PlatypusHoldingTrapDoor)
+ _vm->_hotspots[kHS38WalkArea6]._flags = SF_NONE;
+ _vm->_hotspotsCount = 13;
+}
+
+void Scene38::run() {
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->queueInsertDeviceIcon();
+ _vm->_gameSys->insertSequence(0x9B, 0, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (_vm->_prevSceneNum == 39) {
+ gnap.initPos(3, 7, kDirBottomLeft);
+ plat.initPos(4, 7, kDirIdleRight);
+ } else {
+ gnap.initPos(3, 8, kDirBottomRight);
+ plat.initPos(4, 8, kDirIdleLeft);
+ }
+ _vm->endSceneInit();
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS38Device:
+ _vm->runMenu();
+ updateHotspots();
+ break;
+
+ case kHS38Platypus:
+ if (gnap._actionStatus == kAS38HoldingHuntingTrophy) {
+ gnap._actionStatus = kAS38ReleaseHuntingTrophy;
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible(plat._pos);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible(plat._pos);
+ break;
+ }
+ }
+ break;
+
+ case kHS38ExitHouse:
+ if (gnap._actionStatus == kAS38HoldingHuntingTrophy) {
+ gnap._actionStatus = kAS38ReleaseHuntingTrophy;
+ } else {
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(Common::Point(-1, -1), 0, 0x107AE, 1);
+ gnap._actionStatus = kAS38LeaveScene;
+ _vm->_newSceneNum = 37;
+ }
+ break;
+
+ case kHS38ExitCave:
+ if (gnap._actionStatus == kAS38HoldingHuntingTrophy) {
+ gnap._actionStatus = kAS38ReleaseHuntingTrophy;
+ if (plat._actionStatus == kAS38PlatypusHoldingTrapDoor)
+ _vm->_isLeavingScene = true;
+ } else if (plat._actionStatus == kAS38PlatypusHoldingTrapDoor) {
+ _vm->_sceneWaiting = false;
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(Common::Point(5, 7), 0, 0x107BB, 1);
+ _vm->_newSceneNum = 39;
+ gnap._actionStatus = kAS38ExitCave;
+ }
+ break;
+
+ case kHS38TrapDoorLid1:
+ case kHS38TrapDoorLid2:
+ if (gnap._actionStatus == kAS38HoldingHuntingTrophy) {
+ if (_vm->_verbCursor == PLAT_CURSOR && plat._actionStatus != kAS38PlatypusHoldingTrapDoor)
+ gnap._actionStatus = kAS38UsePlatypusWithTrapDoor;
+ else
+ gnap._actionStatus = kAS38ReleaseHuntingTrophy;
+ }
+ break;
+
+ case kHS38HuntingTrophy:
+ if (gnap._actionStatus != kAS38HoldingHuntingTrophy) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(3, 6), 2, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead();
+ break;
+ case GRAB_CURSOR:
+ if (plat._actionStatus == kAS38PlatypusHoldingTrapDoor)
+ gnap.playImpossible();
+ else {
+ gnap.walkTo(Common::Point(3, 6), 0, 0x107BB, 1);
+ plat.walkTo(Common::Point(4, 8), -1, -1, 1);
+ gnap._actionStatus = kAS38UseHuntingTrophy;
+ }
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(Common::Point(2, 0));
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS38WalkArea1:
+ // Nothing
+ break;
+
+ case kHS38WalkArea2:
+ case kHS38WalkArea3:
+ case kHS38WalkArea4:
+ case kHS38WalkArea5:
+ case kHS38WalkArea6:
+ if (gnap._actionStatus == kAS38HoldingHuntingTrophy)
+ gnap._actionStatus = kAS38ReleaseHuntingTrophy;
+ else if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left) {
+ if (gnap._actionStatus == kAS38HoldingHuntingTrophy)
+ gnap._actionStatus = kAS38ReleaseHuntingTrophy;
+ else if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+ }
+
+ updateAnimations();
+
+ if (!_vm->_isLeavingScene) {
+ plat.updateIdleSequence();
+ gnap.updateIdleSequence();
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene38::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS38LeaveScene:
+ _vm->_sceneDone = true;
+ break;
+ case kAS38ExitCave:
+ gameSys.removeSequence(plat._sequenceId | (plat._sequenceDatNum << 16), plat._id, true);
+ gameSys.insertSequence(0xA3, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0xA3;
+ gnap._sequenceDatNum = 0;
+ gameSys.setAnimation(0xA3, gnap._id, 0);
+ gnap._actionStatus = kAS38LeaveScene;
+ break;
+ case kAS38UseHuntingTrophy:
+ gameSys.removeSequence(0x9B, 0, true);
+ gameSys.insertSequence(0x9C, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x9C;
+ gnap._sequenceDatNum = 0;
+ gameSys.setAnimation(0x9C, gnap._id, 0);
+ gnap._actionStatus = kAS38HoldingHuntingTrophy;
+ updateHotspots();
+ break;
+ case kAS38HoldingHuntingTrophy:
+ if (plat._actionStatus != kAS38PlatypusHoldingTrapDoor)
+ _vm->_sceneWaiting = true;
+ if (gnap._sequenceId == 0xA4) {
+ gameSys.insertSequence(0x9D, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x9D;
+ } else {
+ gameSys.insertSequence(0xA4, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0xA4;
+ }
+ gnap._sequenceDatNum = 0;
+ gameSys.setAnimation(gnap._sequenceId, gnap._id, 0);
+ break;
+ case kAS38ReleaseHuntingTrophy:
+ if (gnap._sequenceId == 0x9E) {
+ gameSys.insertSequence(0x9B, 0, 0, 0, kSeqNone, 0, 0, 0);
+ gnap._actionStatus = -1;
+ } else if (plat._actionStatus == kAS38PlatypusHoldingTrapDoor) {
+ gameSys.insertSequence(0xA0, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0xA0;
+ gnap._sequenceDatNum = 0;
+ gnap._pos = Common::Point(3, 6);
+ gnap._idleFacing = kDirBottomRight;
+ if (_vm->_isLeavingScene) {
+ _vm->_sceneWaiting = false;
+ gnap.walkTo(Common::Point(5, 7), 0, 0x107BB, 1);
+ _vm->_newSceneNum = 39;
+ gnap._actionStatus = kAS38ExitCave;
+ } else {
+ gnap._actionStatus = -1;
+ }
+ } else {
+ gameSys.insertSequence(0x9E, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x9E;
+ gnap._sequenceDatNum = 0;
+ gnap._pos = Common::Point(3, 6);
+ gnap._idleFacing = kDirBottomRight;
+ gameSys.setAnimation(0x9E, gnap._id, 0);
+ _vm->_sceneWaiting = false;
+ updateHotspots();
+ }
+ break;
+ case kAS38UsePlatypusWithTrapDoor:
+ _vm->_sceneWaiting = false;
+ gameSys.insertSequence(0x9F, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x9F;
+ gnap._sequenceDatNum = 0;
+ gameSys.setAnimation(0x9F, gnap._id, 0);
+ gnap._actionStatus = kAS38HoldingHuntingTrophy;
+ if (plat._idleFacing != kDirIdleLeft)
+ plat.playSequence(0x107D5);
+ else
+ plat.playSequence(0x107D4);
+ plat.walkTo(Common::Point(8, 7), -1, 0x107D2, 1);
+ gameSys.insertSequence(0xA1, gnap._id + 1, plat._sequenceId | (plat._sequenceDatNum << 16), plat._id, kSeqSyncWait, 0, 0, 0);
+ plat._sequenceId = 0xA1;
+ plat._sequenceDatNum = 0;
+ plat._id = gnap._id + 1;
+ gameSys.setAnimation(0xA1, gnap._id + 1, 1);
+ plat._actionStatus = kAS38PlatypusHoldingTrapDoor;
+ updateHotspots();
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(1) == 2) {
+ gameSys.setAnimation(0, 0, 1);
+ if (plat._actionStatus == kAS38PlatypusHoldingTrapDoor) {
+ gameSys.insertSequence(0xA2, plat._id, plat._sequenceId | (plat._sequenceDatNum << 16), plat._id, kSeqSyncWait, 0, 0, 0);
+ plat._sequenceId = 0xA2;
+ plat._sequenceDatNum = 0;
+ updateHotspots();
+ _vm->_sceneWaiting = true;
+ }
+ }
+}
+
+/*****************************************************************************/
+
+Scene39::Scene39(GnapEngine *vm) : Scene(vm) {
+ _currGuySequenceId = -1;
+ _nextGuySequenceId = -1;
+}
+
+int Scene39::init() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ gameSys.setAnimation(0, 0, 0);
+ gameSys.setAnimation(0, 0, 1);
+ return 0x35;
+}
+
+void Scene39::updateHotspots() {
+ _vm->setHotspot(kHS39Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS39ExitInsideHouse, 0, 0, 140, 206, SF_EXIT_U_CURSOR, 4, 8);
+ _vm->setHotspot(kHS39ExitUfoParty, 360, 204, 480, 430, SF_EXIT_R_CURSOR, 6, 8);
+ _vm->setHotspot(kHS39Sign, 528, 232, 607, 397, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 7, 3);
+ _vm->setHotspot(kHS39WalkArea1, 0, 0, 800, 466);
+ _vm->setHotspot(kHS39WalkArea2, 502, 466, 800, 600);
+ _vm->setDeviceHotspot(kHS39Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 7;
+}
+
+void Scene39::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ // Bug in the original? Timer was never initialized.
+ _vm->_timers[5] = 0;
+
+ _vm->queueInsertDeviceIcon();
+ _currGuySequenceId = 0x33;
+
+ gameSys.setAnimation(0x33, 21, 3);
+ gameSys.insertSequence(_currGuySequenceId, 21, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.insertSequence(0x34, 21, 0, 0, kSeqLoop, 0, 0, 0);
+
+ _nextGuySequenceId = -1;
+ if (_vm->_prevSceneNum == 38) {
+ gnap.initPos(3, 7, kDirUpRight);
+ plat.initPos(2, 7, kDirUpLeft);
+ _vm->endSceneInit();
+ } else {
+ gnap.initPos(4, 7, kDirBottomRight);
+ plat.initPos(5, 7, kDirIdleLeft);
+ _vm->endSceneInit();
+ }
+
+ while (!_vm->_sceneDone) {
+ if (!_vm->isSoundPlaying(0x1094B)) {
+ _vm->playSound(0x1094B, true);
+ _vm->setSoundVolume(0x1094B, 60);
+ }
+
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->testWalk(0, 0, -1, -1, -1, -1);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS39Device:
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[5] = _vm->getRandom(20) + 50;
+ break;
+
+ case kHS39Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible(plat._pos);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible(plat._pos);
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS39ExitUfoParty:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_sceneDone = true;
+ gnap.walkTo(gnap._pos, 0, 0x107AB, 1);
+ gnap._actionStatus = kAS39LeaveScene;
+ _vm->_newSceneNum = 40;
+ }
+ break;
+
+ case kHS39Sign:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS39Sign], 0, -1, 1);
+ gnap.playIdle(_vm->_hotspotsWalkPos[kHS39Sign]);
+ _vm->showFullScreenSprite(0x1C);
+ break;
+ case GRAB_CURSOR:
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS39ExitInsideHouse:
+ if (gnap._actionStatus < 0) {
+ _vm->_sceneDone = true;
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 38;
+ }
+ break;
+
+ case kHS39WalkArea1:
+ case kHS39WalkArea2:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left && gnap._actionStatus < 0) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+ }
+
+ updateAnimations();
+
+ if (!_vm->_isLeavingScene) {
+ if (plat._actionStatus < 0)
+ plat.updateIdleSequence();
+ if (gnap._actionStatus < 0)
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[5]) {
+ _vm->_timers[5] = _vm->getRandom(20) + 50;
+ switch (_vm->getRandom(4)) {
+ case 0:
+ _nextGuySequenceId = 0x30;
+ break;
+ case 1:
+ _nextGuySequenceId = 0x31;
+ break;
+ case 2:
+ _nextGuySequenceId = 0x32;
+ break;
+ case 3:
+ _nextGuySequenceId = 0x33;
+ break;
+ }
+ }
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[5] = _vm->getRandom(20) + 50;
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene39::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ if (gnap._actionStatus == kAS39LeaveScene)
+ _vm->_sceneDone = true;
+ else
+ gnap._actionStatus = -1;
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2 && _nextGuySequenceId != -1) {
+ gameSys.setAnimation(_nextGuySequenceId, 21, 3);
+ gameSys.insertSequence(_nextGuySequenceId, 21, _currGuySequenceId, 21, kSeqSyncWait, 0, 0, 0);
+ _currGuySequenceId = _nextGuySequenceId;
+ _nextGuySequenceId = -1;
+ }
+}
+
+} // End of namespace Gnap
diff --git a/engines/gnap/scenes/group3.h b/engines/gnap/scenes/group3.h
new file mode 100644
index 0000000000..6fbbdd79aa
--- /dev/null
+++ b/engines/gnap/scenes/group3.h
@@ -0,0 +1,240 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can 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 GNAP_GROUP3_H
+#define GNAP_GROUP3_H
+
+#include "gnap/debugger.h"
+
+namespace Gnap {
+
+enum {
+ kHS30Platypus = 0,
+ kHS30PillMachine = 1,
+ kHS30Device = 2,
+ kHS30ExitCircus = 3,
+ kHS30WalkArea1 = 4
+};
+
+enum {
+ kHS31Platypus = 0,
+ kHS31MeasuringClown = 1,
+ kHS31BeerBarrel = 2,
+ kHS31Device = 3,
+ kHS31ExitCircus = 4,
+ kHS31ExitOutsideClown = 5,
+ kHS31WalkArea1 = 6
+};
+
+enum {
+ kHS32Platypus = 0,
+ kHS32ExitTruck = 1,
+ kHS32Device = 2,
+ kHS32WalkArea1 = 3,
+ kHS32WalkArea2 = 4,
+ kHS32WalkArea3 = 5,
+ kHS32WalkArea4 = 6,
+ kHS32WalkArea5 = 7,
+ kHS32WalkArea6 = 8,
+ kHS32WalkArea7 = 9,
+ kHS32WalkArea8 = 10
+};
+
+enum {
+ kHS33Platypus = 0,
+ kHS33Chicken = 1,
+ kHS33Device = 2,
+ kHS33ExitHouse = 3,
+ kHS33ExitBarn = 4,
+ kHS33ExitCreek = 5,
+ kHS33ExitPigpen = 6,
+ kHS33WalkArea1 = 7,
+ kHS33WalkArea2 = 8
+};
+
+enum {
+ kHS38Platypus = 0,
+ kHS38ExitHouse = 1,
+ kHS38ExitCave = 2,
+ kHS38TrapDoorLid1 = 3,
+ kHS38TrapDoorLid2 = 4,
+ kHS38HuntingTrophy = 5,
+ kHS38WalkArea1 = 6,
+ kHS38Device = 7,
+ kHS38WalkArea2 = 8,
+ kHS38WalkArea3 = 9,
+ kHS38WalkArea4 = 10,
+ kHS38WalkArea5 = 11,
+ kHS38WalkArea6 = 12
+};
+
+enum {
+ kHS39Platypus = 0,
+ kHS39ExitInsideHouse = 1,
+ kHS39ExitUfoParty = 2,
+ kHS39Sign = 3,
+ kHS39Device = 4,
+ kHS39WalkArea1 = 5,
+ kHS39WalkArea2 = 6
+};
+
+enum {
+ kAS30LeaveScene = 0,
+ kAS30UsePillMachine = 1,
+ kAS30UsePillMachine2 = 2,
+ kAS30LookPillMachine = 3,
+ kAS30UsePillMachine3 = 4,
+ kAS30UsePillMachine4 = 5
+};
+
+enum {
+ kAS31UseBeerBarrel = 1,
+ kAS31FillEmptyBucketWithBeer = 2,
+ kAS31FillEmptyBucketWithBeerDone = 3,
+ kAS31PlatMeasuringClown = 4,
+ kAS31UseMeasuringClown = 5,
+ kAS31LeaveScene = 6
+};
+
+enum {
+ kAS32LeaveScene = 0
+};
+
+enum {
+ kAS33LeaveScene = 0,
+ kAS33TalkChicken = 1,
+ kAS33UseChicken = 2,
+ kAS33UseChickenDone = 3
+};
+
+enum {
+ kAS38LeaveScene = 0,
+ kAS38ExitCave = 1,
+ kAS38UseHuntingTrophy = 2,
+ kAS38HoldingHuntingTrophy = 3,
+ kAS38ReleaseHuntingTrophy = 4,
+ kAS38UsePlatypusWithTrapDoor = 5,
+ kAS38PlatypusHoldingTrapDoor = 6
+};
+
+enum {
+ kAS39LeaveScene = 0
+};
+
+/*****************************************************************************/
+
+class GnapEngine;
+class CutScene;
+
+class Scene30: public Scene {
+public:
+ Scene30(GnapEngine *vm);
+ virtual ~Scene30() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _kidSequenceId;
+};
+
+class Scene31: public Scene {
+public:
+ Scene31(GnapEngine *vm);
+ virtual ~Scene31() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ bool _beerGuyDistracted;
+ int _currClerkSequenceId;
+ int _nextClerkSequenceId;
+ int _clerkMeasureCtr;
+ int _clerkMeasureMaxCtr;
+};
+
+class Scene32: public Scene {
+public:
+ Scene32(GnapEngine *vm);
+ virtual ~Scene32() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+};
+
+class Scene33: public Scene {
+public:
+ Scene33(GnapEngine *vm);
+ virtual ~Scene33() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _currChickenSequenceId;
+ int _nextChickenSequenceId;
+};
+
+class Scene38: public Scene {
+public:
+ Scene38(GnapEngine *vm);
+ virtual ~Scene38() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+};
+
+class Scene39: public Scene {
+public:
+ Scene39(GnapEngine *vm);
+ virtual ~Scene39() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _currGuySequenceId;
+ int _nextGuySequenceId;
+};
+
+} // End of namespace Gnap
+
+#endif // GNAP_GROUP3_H
diff --git a/engines/gnap/scenes/group4.cpp b/engines/gnap/scenes/group4.cpp
new file mode 100644
index 0000000000..f37be2c25d
--- /dev/null
+++ b/engines/gnap/scenes/group4.cpp
@@ -0,0 +1,2799 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can 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 "gnap/gnap.h"
+#include "gnap/gamesys.h"
+#include "gnap/resource.h"
+#include "gnap/scenes/group4.h"
+
+namespace Gnap {
+
+Scene40::Scene40(GnapEngine *vm) : Scene(vm) {
+}
+
+int Scene40::init() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ gameSys.setAnimation(0, 0, 0);
+ gameSys.setAnimation(0, 0, 1);
+ return _vm->isFlag(kGFUnk23) ? 0x01 : 0x00;
+}
+
+void Scene40::updateHotspots() {
+ _vm->setHotspot(kHS40Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_DISABLED | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS40ExitCave, 169, 510, 264, 600, SF_EXIT_D_CURSOR, 0, 8);
+ _vm->setHotspot(kHS40ExitToyStand, 238, 297, 328, 376, SF_EXIT_L_CURSOR, 0, 8);
+ _vm->setHotspot(kHS40ExitBBQ, 328, 220, 401, 306, SF_EXIT_L_CURSOR, 0, 8);
+ _vm->setHotspot(kHS40ExitUfo, 421, 215, 501, 282, SF_EXIT_U_CURSOR, 0, 8);
+ _vm->setHotspot(kHS40ExitKissinBooth, 476, 284, 556, 345, SF_EXIT_R_CURSOR, 0, 8);
+ _vm->setHotspot(kHS40ExitDancefloor, 317, 455, 445, 600, SF_EXIT_D_CURSOR, 0, 8);
+ _vm->setHotspot(kHS40ExitShoe, 455, 346, 549, 417, SF_EXIT_D_CURSOR, 0, 8);
+ _vm->setDeviceHotspot(kHS40Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 9;
+}
+
+void Scene40::run() {
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->queueInsertDeviceIcon();
+ _vm->endSceneInit();
+
+ while (!_vm->_sceneDone) {
+ if (!_vm->isSoundPlaying(0x1094B))
+ _vm->playSound(0x1094B, true);
+
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->testWalk(0, 0, -1, -1, -1, -1);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS40Device:
+ _vm->runMenu();
+ updateHotspots();
+ break;
+
+ case kHS40Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible(plat._pos);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible(plat._pos);
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS40ExitCave:
+ if (gnap._actionStatus < 0) {
+ _vm->_newSceneNum = 39;
+ _vm->_sceneDone = true;
+ }
+ break;
+
+ case kHS40ExitToyStand:
+ if (gnap._actionStatus < 0) {
+ _vm->_newSceneNum = 41;
+ _vm->_sceneDone = true;
+ }
+ break;
+
+ case kHS40ExitBBQ:
+ if (gnap._actionStatus < 0) {
+ _vm->_newSceneNum = 42;
+ _vm->_sceneDone = true;
+ }
+ break;
+
+ case kHS40ExitUfo:
+ if (gnap._actionStatus < 0) {
+ _vm->_newSceneNum = 43;
+ _vm->_sceneDone = true;
+ }
+ break;
+
+ case kHS40ExitKissinBooth:
+ if (gnap._actionStatus < 0) {
+ _vm->_newSceneNum = 44;
+ _vm->_sceneDone = true;
+ }
+ break;
+
+ case kHS40ExitDancefloor:
+ if (gnap._actionStatus < 0) {
+ _vm->_newSceneNum = 45;
+ _vm->_sceneDone = true;
+ }
+ break;
+
+ case kHS40ExitShoe:
+ if (gnap._actionStatus < 0) {
+ _vm->_newSceneNum = 46;
+ _vm->_sceneDone = true;
+ }
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left && gnap._actionStatus < 0)
+ _vm->_mouseClickState._left = false;
+ break;
+
+ }
+
+ updateAnimations();
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene40::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ if (gnap._actionStatus)
+ gnap._actionStatus = -1;
+ else
+ _vm->_sceneDone = true;
+ }
+}
+
+/*****************************************************************************/
+
+Scene41::Scene41(GnapEngine *vm) : Scene(vm) {
+ _currKidSequenceId = -1;
+ _nextKidSequenceId = -1;
+ _currToyVendorSequenceId = -1;
+ _nextToyVendorSequenceId = -1;
+}
+
+int Scene41::init() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ gameSys.setAnimation(0, 0, 0);
+ gameSys.setAnimation(0, 0, 1);
+ gameSys.setAnimation(0, 0, 2);
+ return 0x129;
+}
+
+void Scene41::updateHotspots() {
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ _vm->setHotspot(kHS41Platypus, 0, 0, 0, 0, SF_DISABLED);
+ _vm->setHotspot(kHS41UfoExitLeft, 0, 0, 10, 500, SF_EXIT_L_CURSOR | SF_DISABLED);
+ _vm->setHotspot(kHS41UfoExitRight, 790, 0, 799, 500, SF_EXIT_R_CURSOR);
+ _vm->setHotspot(kHS41UfoWalkArea1, 0, 0, 800, 470, SF_DISABLED);
+ _vm->setDeviceHotspot(kHS41UfoDevice, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 5;
+ } else {
+ _vm->setHotspot(kHS41Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS41ExitCave, 150, 590, 650, 600, SF_EXIT_D_CURSOR | SF_WALKABLE, 5, 9);
+ _vm->setHotspot(kHS41Exit, 0, 100, 10, 599, SF_EXIT_L_CURSOR | SF_DISABLED, 0, 8);
+ _vm->setHotspot(kHS41ExitBBQ, 790, 100, 799, 599, SF_EXIT_R_CURSOR | SF_WALKABLE, 10, 8);
+ _vm->setHotspot(kHS41ToyVendor, 320, 150, 430, 310, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS41Kid, 615, 340, 710, 460, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS41ToyUfo, 0, 0, 0, 0, SF_GRAB_CURSOR);
+ _vm->setHotspot(kHS41WalkArea1, 0, 0, 800, 470);
+ _vm->setDeviceHotspot(kHS41Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 9;
+ }
+}
+
+void Scene41::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->queueInsertDeviceIcon();
+
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ _vm->_toyUfoX = 770;
+ if (_vm->_toyUfoY < 0 || _vm->_toyUfoY > 300)
+ _vm->_toyUfoY = 150;
+ if (!_vm->_timers[9])
+ gnap._actionStatus = kAS41GiveBackToyUfo;
+ } else {
+ if (!_vm->isFlag(kGFUnk16) && !_vm->isFlag(kGFJointTaken) && !_vm->isFlag(kGFUnk18) && !_vm->isFlag(kGFGroceryStoreHatTaken))
+ _vm->toyUfoSetStatus(kGFUnk16);
+ _vm->_toyUfoX = 600;
+ _vm->_toyUfoY = 200;
+ }
+
+ _vm->_toyUfoId = 0;
+ _vm->_toyUfoActionStatus = -1;
+ _vm->_toyUfoSequenceId = _vm->toyUfoGetSequenceId();
+ _vm->_toyUfoNextSequenceId = _vm->_toyUfoSequenceId;
+
+ gameSys.setAnimation(_vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, 2);
+ gameSys.insertSequence(_vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, 0, 0, kSeqNone, 0, _vm->_toyUfoX - 274, _vm->_toyUfoY - 128);
+ gameSys.insertSequence(0x128, 0, 0, 0, kSeqLoop, 0, 0, 0);
+
+ if (_vm->isFlag(kGFGnapControlsToyUFO))
+ _currKidSequenceId = 0x11B;
+ else
+ _currKidSequenceId = 0x11D;
+
+ _nextKidSequenceId = -1;
+
+ gameSys.setAnimation(_currKidSequenceId, 1, 4);
+ gameSys.insertSequence(_currKidSequenceId, 1, 0, 0, kSeqNone, 0, 0, 0);
+
+ _currToyVendorSequenceId = 0x118;
+ _nextToyVendorSequenceId = -1;
+
+ gameSys.setAnimation(0x118, 1, 3);
+ gameSys.insertSequence(_currToyVendorSequenceId, 1, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.insertSequence(0x127, 2, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ gnap._sequenceId = 0x120;
+ gnap._sequenceDatNum = 0;
+ gnap._idleFacing = kDirUpRight;
+ gnap._pos = Common::Point(7, 7);
+ gnap._id = 140;
+ gameSys.insertSequence(0x120, 140, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.setAnimation(makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, 0);
+ plat.initPos(8, 10, kDirBottomLeft);
+ _vm->endSceneInit();
+ } else if (_vm->_prevSceneNum == 45) {
+ gnap.initPos(-1, 8, kDirUpRight);
+ plat.initPos(-2, 8, kDirUpLeft);
+ _vm->endSceneInit();
+ plat.walkTo(Common::Point(1, 8), -1, 0x107C2, 1);
+ gnap.walkTo(Common::Point(2, 8), -1, 0x107B9, 1);
+ } else if (_vm->_prevSceneNum == 42) {
+ gnap.initPos(11, 8, kDirUpRight);
+ plat.initPos(11, 9, kDirUpLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(8, 8), -1, 0x107BA, 1);
+ plat.walkTo(Common::Point(9, 8), -1, 0x107D2, 1);
+ } else {
+ gnap.initPos(5, 8, kDirBottomRight);
+ plat.initPos(6, 8, kDirBottomLeft);
+ _vm->endSceneInit();
+ }
+
+ _vm->_timers[4] = _vm->getRandom(100) + 100;
+ _vm->_timers[5] = _vm->getRandom(30) + 20;
+
+ while (!_vm->_sceneDone) {
+ if (!_vm->isSoundPlaying(0x1094B))
+ _vm->playSound(0x1094B, true);
+
+ if (!_vm->isFlag(kGFGnapControlsToyUFO))
+ _vm->_hotspots[kHS41ToyUfo]._rect = Common::Rect(_vm->_toyUfoX - 25, _vm->_toyUfoY - 20, _vm->_toyUfoX + 25, _vm->_toyUfoY + 20);
+
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->testWalk(0, 0, -1, -1, -1, -1);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS41UfoExitLeft:
+ if (_vm->_toyUfoActionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_toyUfoActionStatus = kAS41ToyUfoLeaveScene;
+ _vm->_newSceneNum = 45;
+ _vm->toyUfoFlyTo(-35, -1, -35, 799, 0, 300, 2);
+ }
+ break;
+
+ case kHS41UfoExitRight:
+ if (_vm->_toyUfoActionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_toyUfoActionStatus = kAS41ToyUfoLeaveScene;
+ _vm->_newSceneNum = 42;
+ _vm->toyUfoFlyTo(835, -1, 0, 835, 0, 300, 2);
+ }
+ break;
+
+ case kHS41UfoDevice:
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[4] = _vm->getRandom(100) + 100;
+ _vm->_timers[5] = _vm->getRandom(30) + 20;
+ break;
+ }
+ } else {
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS41Device:
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[4] = _vm->getRandom(100) + 100;
+ _vm->_timers[5] = _vm->getRandom(30) + 20;
+ break;
+
+ case kHS41Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible(plat._pos);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible(plat._pos);
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS41ExitCave:
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS41ExitCave], 0, 0x107AE, 1);
+ gnap._actionStatus = kAS41LeaveScene;
+ _vm->_newSceneNum = 40;
+ break;
+
+ case kHS41Exit:
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS41Exit].x, -1), 0, 0x107AF, 1);
+ gnap._actionStatus = kAS41LeaveScene;
+ plat.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS41Exit].x, -1), -1, 0x107CF, 1);
+ _vm->_newSceneNum = 45;
+ break;
+
+ case kHS41ExitBBQ:
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS41ExitBBQ].x, -1), 0, 0x107AB, 1);
+ gnap._actionStatus = kAS41LeaveScene;
+ plat.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS41ExitBBQ].x, -1), -1, 0x107CD, 1);
+ _vm->_newSceneNum = 42;
+ break;
+
+ case kHS41ToyVendor:
+ if (_vm->_grabCursorSpriteIndex == kItemDiceQuarterHole) {
+ gnap._actionStatus = kAS41UseQuarterWithToyVendor;
+ gnap.walkTo(Common::Point(4, 7), 0, 0x107BB, 9);
+ gnap.playShowItem(_vm->_grabCursorSpriteIndex, 5, 0);
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(4, 7), 5, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(Common::Point(5, 0));
+ break;
+ case GRAB_CURSOR:
+ gnap.playImpossible();
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(Common::Point(4, 7), 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS41TalkToyVendor;
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ break;
+
+ case kHS41Kid:
+ if (_vm->_grabCursorSpriteIndex == kItemChickenBucket) {
+ gnap.walkTo(Common::Point(7, 7), 0, 0x107BB, 1);
+ gnap._idleFacing = kDirUpRight;
+ gnap._actionStatus = kAS41UseChickenBucketWithKid;
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(7, 7), 8, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(9, 0));
+ break;
+ case GRAB_CURSOR:
+ gnap.walkTo(Common::Point(7, 7), 0, 0x107BB, 1);
+ gnap._idleFacing = kDirUpRight;
+ gnap._actionStatus = kAS41GrabKid;
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(Common::Point(7, 7), 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ break;
+
+ case kHS41ToyUfo:
+ if (_vm->_grabCursorSpriteIndex == kItemGum) {
+ gnap.playPullOutDevice(Common::Point(9, 0));
+ gameSys.setAnimation(makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, 0);
+ gnap._actionStatus = kAS41UseGumWithToyUfo;
+ }
+ break;
+
+ case kHS41WalkArea1:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+ }
+ }
+
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ if (!_vm->_timers[9] && gnap._actionStatus < 0) {
+ gnap._actionStatus = kAS41GiveBackToyUfo;
+ if (gnap._sequenceId == 0x121 || gnap._sequenceId == 0x122) {
+ gameSys.insertSequence(0x123, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x123;
+ gnap._sequenceDatNum = 0;
+ gameSys.setAnimation(0x123, gnap._id, 0);
+ }
+ }
+ }
+
+ if (_vm->_mouseClickState._left && gnap._actionStatus < 0) {
+ _vm->_mouseClickState._left = false;
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ int sequenceId;
+ if (_vm->_leftClickMouseX >= 400) {
+ if (gnap._sequenceId == 0x11F || gnap._sequenceId == 0x120 || gnap._sequenceId == 0x123 || gnap._sequenceId == 0x126)
+ sequenceId = 0x120;
+ else if (_vm->_leftClickMouseX - _vm->_toyUfoX >= 400)
+ sequenceId = 0x126;
+ else
+ sequenceId = 0x123;
+ } else {
+ if (gnap._sequenceId == 0x121 || gnap._sequenceId == 0x125 || gnap._sequenceId == 0x122)
+ sequenceId = 0x122;
+ else if (_vm->_toyUfoX - _vm->_leftClickMouseX >= 400)
+ sequenceId = 0x125;
+ else
+ sequenceId = 0x121;
+ }
+ gameSys.insertSequence(sequenceId, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = sequenceId;
+ gnap._sequenceDatNum = 0;
+ gameSys.setAnimation(sequenceId, gnap._id, 0);
+ _vm->_toyUfoActionStatus = kAS41ToyUfoRefresh;
+ _vm->toyUfoFlyTo(-1, -1, 0, 799, 0, 300, 2);
+ } else {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ }
+ }
+
+ updateAnimations();
+
+ if (!_vm->_isLeavingScene) {
+ if (plat._actionStatus < 0)
+ plat.updateIdleSequence();
+ if (gnap._actionStatus < 0 && !_vm->isFlag(kGFGnapControlsToyUFO))
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[4]) {
+ _vm->_timers[4] = _vm->getRandom(100) + 100;
+ if (gnap._actionStatus < 0 && plat._actionStatus < 0 && _vm->_toyUfoActionStatus == -1 && _nextToyVendorSequenceId == -1) {
+ switch (_vm->getRandom(3)) {
+ case 0:
+ _nextToyVendorSequenceId = 0x113;
+ break;
+ case 1:
+ _nextToyVendorSequenceId = 0x117;
+ break;
+ case 2:
+ _nextToyVendorSequenceId = 0x119;
+ break;
+ }
+ if (_nextToyVendorSequenceId == _currToyVendorSequenceId)
+ _nextToyVendorSequenceId = -1;
+ }
+ }
+ if (!_vm->_timers[5]) {
+ _vm->_timers[5] = _vm->getRandom(30) + 20;
+ if (gnap._actionStatus < 0 && plat._actionStatus < 0 && _vm->_toyUfoActionStatus == -1 && _nextKidSequenceId == -1) {
+ if (_vm->isFlag(kGFGnapControlsToyUFO))
+ _nextKidSequenceId = 0x11B;
+ else if (_vm->getRandom(3) != 0)
+ _nextKidSequenceId = 0x11D;
+ else
+ _nextKidSequenceId = 0x11E;
+ }
+ }
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[4] = _vm->getRandom(100) + 100;
+ _vm->_timers[5] = _vm->getRandom(30) + 20;
+ }
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene41::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ switch (gnap._actionStatus) {
+ case kAS41LeaveScene:
+ gameSys.setAnimation(0, 0, 0);
+ _vm->_sceneDone = true;
+ gnap._actionStatus = -1;
+ break;
+ case kAS41UseQuarterWithToyVendor:
+ gameSys.setAnimation(0, 0, 0);
+ _nextToyVendorSequenceId = 0x114;
+ gnap._actionStatus = -1;
+ break;
+ case kAS41TalkToyVendor:
+ gameSys.setAnimation(0, 0, 0);
+ _nextToyVendorSequenceId = 0x116;
+ gnap._actionStatus = -1;
+ break;
+ case kAS41UseGumWithToyUfo:
+ gameSys.setAnimation(0, 0, 0);
+ gnap.playUseDevice(Common::Point(9, 0));
+ gnap._actionStatus = -1;
+ _vm->setGrabCursorSprite(-1);
+ _vm->invRemove(kItemGum);
+ _vm->_toyUfoActionStatus = kAS41UfoGumAttached;
+ break;
+ case kAS41UseChickenBucketWithKid:
+ if (gameSys.getAnimationStatus(4) == 2) {
+ _vm->_timers[2] = _vm->getRandom(30) + 20;
+ _vm->_timers[3] = _vm->getRandom(50) + 200;
+ _vm->setGrabCursorSprite(-1);
+ gameSys.insertSequence(0x11F, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x11F;
+ gnap._sequenceDatNum = 0;
+ gameSys.setAnimation(0x11F, gnap._id, 0);
+ _nextKidSequenceId = 0x11A;
+ gameSys.insertSequence(0x11A, 1, _currKidSequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextKidSequenceId, 1, 4);
+ _currKidSequenceId = _nextKidSequenceId;
+ _nextKidSequenceId = 0x11B;
+ _vm->_timers[5] = _vm->getRandom(30) + 20;
+ gnap._actionStatus = -1;
+ _vm->setFlag(kGFGnapControlsToyUFO);
+ updateHotspots();
+ _vm->_timers[9] = 600;
+ }
+ break;
+ case kAS41GrabKid:
+ if (gameSys.getAnimationStatus(3) == 2 && gameSys.getAnimationStatus(4) == 2) {
+ _vm->_timers[2] = _vm->getRandom(30) + 20;
+ _vm->_timers[3] = _vm->getRandom(50) + 200;
+ gameSys.insertSequence(0x110, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x110;
+ gnap._sequenceDatNum = 0;
+ gameSys.setAnimation(0x110, gnap._id, 0);
+ _nextToyVendorSequenceId = 0x111;
+ gameSys.insertSequence(0x111, 1, _currToyVendorSequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextToyVendorSequenceId, 1, 3);
+ _currToyVendorSequenceId = _nextToyVendorSequenceId;
+ _nextToyVendorSequenceId = -1;
+ _vm->_timers[4] = _vm->getRandom(100) + 100;
+ _nextKidSequenceId = 0x10F;
+ gameSys.insertSequence(0x10F, 1, _currKidSequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextKidSequenceId, 1, 4);
+ _currKidSequenceId = _nextKidSequenceId;
+ _nextKidSequenceId = -1;
+ _vm->_timers[5] = _vm->getRandom(30) + 20;
+ gnap._actionStatus = -1;
+ }
+ break;
+ case kAS41GiveBackToyUfo:
+ if (gameSys.getAnimationStatus(3) == 2 && gameSys.getAnimationStatus(4) == 2) {
+ _vm->_timers[2] = _vm->getRandom(30) + 20;
+ _vm->_timers[3] = _vm->getRandom(50) + 200;
+ gameSys.insertSequence(0x124, gnap._id,
+ makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id,
+ kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x124;
+ gnap._sequenceDatNum = 0;
+ gameSys.setAnimation(0x124, gnap._id, 0);
+ _nextToyVendorSequenceId = 0x112;
+ gameSys.insertSequence(0x112, 1, _currToyVendorSequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextToyVendorSequenceId, 1, 3);
+ _currToyVendorSequenceId = _nextToyVendorSequenceId;
+ _nextToyVendorSequenceId = -1;
+ _vm->_timers[4] = _vm->getRandom(100) + 100;
+ _nextKidSequenceId = 0x11C;
+ gameSys.insertSequence(0x11C, 1, _currKidSequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextKidSequenceId, 1, 4);
+ _currKidSequenceId = _nextKidSequenceId;
+ _nextKidSequenceId = -1;
+ _vm->_timers[5] = _vm->getRandom(30) + 20;
+ gnap._actionStatus = -1;
+ _vm->clearFlag(kGFGnapControlsToyUFO);
+ updateHotspots();
+ }
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(2) == 2) {
+ switch (_vm->_toyUfoActionStatus) {
+ case kAS41ToyUfoLeaveScene:
+ _vm->_sceneDone = true;
+ break;
+ case kAS41UfoGumAttached:
+ _vm->_toyUfoNextSequenceId = 0x873;
+ gameSys.insertSequence(0x10873, _vm->_toyUfoId, _vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId,
+ kSeqSyncWait, 0, _vm->_toyUfoX - 365, _vm->_toyUfoY - 128);
+ _vm->_toyUfoSequenceId = _vm->_toyUfoNextSequenceId;
+ gameSys.setAnimation(_vm->_toyUfoNextSequenceId | 0x10000, _vm->_toyUfoId, 2);
+ _vm->toyUfoSetStatus(kGFJointTaken);
+ break;
+ default:
+ _vm->_toyUfoNextSequenceId = _vm->toyUfoGetSequenceId();
+ gameSys.insertSequence(_vm->_toyUfoNextSequenceId | 0x10000, _vm->_toyUfoId + 1, _vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId,
+ kSeqSyncWait, 0, _vm->_toyUfoX - 274, _vm->_toyUfoY - 128);
+ _vm->_toyUfoSequenceId = _vm->_toyUfoNextSequenceId;
+ ++_vm->_toyUfoId;
+ gameSys.setAnimation(_vm->_toyUfoNextSequenceId | 0x10000, _vm->_toyUfoId, 2);
+ break;
+ }
+ _vm->_toyUfoActionStatus = -1;
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2 && _nextToyVendorSequenceId != -1) {
+ gameSys.insertSequence(_nextToyVendorSequenceId, 1, _currToyVendorSequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextToyVendorSequenceId, 1, 3);
+ _currToyVendorSequenceId = _nextToyVendorSequenceId;
+ _nextToyVendorSequenceId = -1;
+ _vm->_timers[4] = _vm->getRandom(100) + 100;
+ }
+
+ if (gameSys.getAnimationStatus(4) == 2 && _nextKidSequenceId != -1) {
+ gameSys.insertSequence(_nextKidSequenceId, 1, _currKidSequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextKidSequenceId, 1, 4);
+ _currKidSequenceId = _nextKidSequenceId;
+ _nextKidSequenceId = -1;
+ _vm->_timers[5] = _vm->getRandom(30) + 20;
+ if (_currKidSequenceId == 0x11E) {
+ _vm->_toyUfoActionStatus = kAS41ToyUfoRefresh;
+ _vm->toyUfoFlyTo(_vm->getRandom(300) + 500, _vm->getRandom(225) + 75, 0, 799, 0, 300, 2);
+ }
+ }
+}
+
+/*****************************************************************************/
+
+Scene42::Scene42(GnapEngine *vm) : Scene(vm) {
+ _currBBQVendorSequenceId = -1;
+ _nextBBQVendorSequenceId = -1;
+}
+
+int Scene42::init() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ gameSys.setAnimation(0, 0, 0);
+ gameSys.setAnimation(0, 0, 1);
+ gameSys.setAnimation(0, 0, 2);
+ if (_vm->isFlag(kGFPictureTaken) || (_vm->isFlag(kGFUnk18) && _vm->isFlag(kGFUnk23)))
+ return 0x153;
+ return 0x152;
+}
+
+void Scene42::updateHotspots() {
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ _vm->setHotspot(kHS42Platypus, 0, 0, 0, 0, SF_DISABLED);
+ _vm->setHotspot(kHS42UfoExitLeft, 0, 0, 10, 599, SF_EXIT_L_CURSOR);
+ _vm->setHotspot(kHS42UfoExitRight, 790, 0, 799, 599, SF_EXIT_R_CURSOR);
+ _vm->setHotspot(kHS42UfoHotSauce, 335, 110, 440, 175, SF_DISABLED);
+ _vm->setDeviceHotspot(kHS42UfoDevice, -1, 534, -1, 599);
+ if ((_vm->isFlag(kGFPictureTaken) || _vm->isFlag(kGFUnk18)) && _vm->isFlag(kGFUnk23) && !_vm->isFlag(kGFUnk24))
+ _vm->_hotspots[kHS42UfoHotSauce]._flags = SF_GRAB_CURSOR;
+ _vm->_hotspotsCount = 5;
+ } else {
+ _vm->setHotspot(kHS42Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS42ExitUfoParty, 150, 585, 650, 600, SF_EXIT_D_CURSOR | SF_WALKABLE, 5, 9);
+ _vm->setHotspot(kHS42ExitToyStand, 0, 100, 10, 599, SF_EXIT_L_CURSOR, 0, 8);
+ _vm->setHotspot(kHS42ExitUfo, 790, 100, 799, 599, SF_EXIT_R_CURSOR, 10, 8);
+ _vm->setHotspot(kHS42BBQVendor, 410, 200, 520, 365, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 4, 8);
+ _vm->setHotspot(kHS42ChickenLeg, 530, 340, 620, 430, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 8, 7);
+ _vm->setHotspot(kHS42WalkArea1, 0, 0, 800, 445);
+ _vm->setHotspot(kHS42WalkArea2, 240, 0, 550, 495);
+ _vm->setDeviceHotspot(kHS42Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 9;
+ }
+}
+
+void Scene42::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->queueInsertDeviceIcon();
+
+ _currBBQVendorSequenceId = 0x14A;
+ _nextBBQVendorSequenceId = -1;
+
+ gameSys.setAnimation(0x14A, 1, 2);
+ gameSys.insertSequence(_currBBQVendorSequenceId, 1, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ _vm->_toyUfoId = 0;
+ _vm->_toyUfoActionStatus = -1;
+ if (_vm->_prevSceneNum == 43 && _vm->isFlag(kGFUnk18)) {
+ _vm->_toyUfoSequenceId = 0x872;
+ _vm->_toyUfoNextSequenceId = _vm->toyUfoGetSequenceId();
+ gameSys.insertSequence(_vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->_toyUfoX = 317;
+ _vm->_toyUfoY = 61;
+ _vm->toyUfoSetStatus(kGFJointTaken);
+ _vm->setFlag(kGFPictureTaken);
+ _vm->_timers[9] = 600;
+ } else {
+ _vm->_toyUfoSequenceId = _vm->toyUfoGetSequenceId();
+ _vm->_toyUfoNextSequenceId = _vm->_toyUfoSequenceId;
+ if (_vm->_prevSceneNum == 41)
+ _vm->_toyUfoX = 30;
+ else
+ _vm->_toyUfoX = 770;
+ gameSys.insertSequence(_vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, 0, 0, kSeqNone, 0, _vm->_toyUfoX - 274, _vm->_toyUfoY - 128);
+ }
+ gameSys.setAnimation(_vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, 3);
+ _vm->endSceneInit();
+ if (_vm->_toyUfoSequenceId == 0x872)
+ _vm->setGrabCursorSprite(-1);
+ } else if (_vm->_prevSceneNum == 41) {
+ gnap.initPos(-1, 8, kDirUpRight);
+ plat.initPos(-1, 9, kDirUpLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(2, 8), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(1, 8), -1, 0x107C2, 1);
+ } else if (_vm->_prevSceneNum == 43) {
+ gnap.initPos(11, 8, kDirUpRight);
+ plat.initPos(11, 9, kDirUpLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(8, 8), -1, 0x107BA, 1);
+ plat.walkTo(Common::Point(9, 8), -1, 0x107D2, 1);
+ } else {
+ gnap.initPos(5, 11, kDirUpRight);
+ plat.initPos(6, 11, kDirUpLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(5, 8), -1, 0x107BA, 1);
+ plat.walkTo(Common::Point(6, 8), -1, 0x107C2, 1);
+ }
+
+ while (!_vm->_sceneDone) {
+ if (!_vm->isSoundPlaying(0x1094B))
+ _vm->playSound(0x1094B, true);
+
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->testWalk(0, 0, -1, -1, -1, -1);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS42UfoExitLeft:
+ if (_vm->_toyUfoActionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_toyUfoActionStatus = kAS42ToyUfoLeaveScene;
+ _vm->_newSceneNum = 41;
+ _vm->toyUfoFlyTo(-35, -1, -35, 799, 0, 300, 3);
+ }
+ break;
+
+ case kHS42UfoExitRight:
+ if (_vm->_toyUfoActionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_toyUfoActionStatus = kAS42ToyUfoLeaveScene;
+ _vm->_newSceneNum = 43;
+ _vm->toyUfoFlyTo(835, -1, 0, 835, 0, 300, 3);
+ }
+ break;
+
+ case kHS42UfoHotSauce:
+ if (_vm->isFlag(kGFJointTaken)) {
+ _vm->_toyUfoActionStatus = kAS42ToyUfoPickUpHotSauce;
+ _vm->toyUfoFlyTo(384, 77, 0, 799, 0, 300, 3);
+ _vm->_timers[9] = 600;
+ } else {
+ _vm->_toyUfoActionStatus = kAS42ToyUfoRefresh;
+ _vm->toyUfoFlyTo(-1, -1, 0, 799, 0, 300, 3);
+ }
+ break;
+
+ case kHS42UfoDevice:
+ _vm->runMenu();
+ updateHotspots();
+ break;
+ }
+ } else {
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS42Device:
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[4] = _vm->getRandom(20) + 30;
+ break;
+
+ case kHS42Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible(plat._pos);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible(plat._pos);
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS42ExitUfoParty:
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(Common::Point(gnap._pos.x, _vm->_hotspotsWalkPos[kHS42ExitUfoParty].y), 0, 0x107AE, 1);
+ gnap._actionStatus = kAS42LeaveScene;
+ plat.walkTo(Common::Point(plat._pos.x, _vm->_hotspotsWalkPos[kHS42ExitUfoParty].y), -1, 0x107C7, 1);
+ _vm->_newSceneNum = 40;
+ break;
+
+ case kHS42ExitToyStand:
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS42ExitToyStand].x, gnap._pos.y), 0, 0x107AF, 1);
+ gnap._actionStatus = kAS42LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS42ExitToyStand], -1, 0x107CF, 1);
+ _vm->_newSceneNum = 41;
+ break;
+
+ case kHS42ExitUfo:
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS42ExitUfo].x, gnap._pos.y), 0, 0x107AB, 1);
+ gnap._actionStatus = kAS42LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS42ExitUfo], -1, 0x107CD, 1);
+ _vm->_newSceneNum = 43;
+ break;
+
+ case kHS42BBQVendor:
+ if (_vm->_grabCursorSpriteIndex == kItemDiceQuarterHole) {
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS42BBQVendor], 0, 0x107BB, 1);
+ gnap._actionStatus = kAS42UseQuarterWithBBQVendor;
+ if (plat._pos.y < 9)
+ plat.walkTo(Common::Point(plat._pos.x, 9), -1, -1, 1);
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS42BBQVendor], _vm->_hotspotsWalkPos[kHS42BBQVendor].x + 1, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(_vm->_hotspotsWalkPos[kHS42BBQVendor].x - 1, 0));
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS42BBQVendor], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS42TalkBBQVendor;
+ break;
+ case GRAB_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ break;
+
+ case kHS42ChickenLeg:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS42ChickenLeg], _vm->_hotspotsWalkPos[kHS42ChickenLeg].x - 1, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(_vm->_hotspotsWalkPos[kHS42ChickenLeg].x - 1, 0));
+ break;
+ case GRAB_CURSOR:
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS42ChickenLeg], 0, 0x107BC, 1);
+ gnap._actionStatus = kAS42GrabChickenLeg;
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ break;
+
+ case kHS42WalkArea1:
+ case kHS42WalkArea2:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ }
+ }
+
+ if (_vm->_mouseClickState._left && gnap._actionStatus < 0) {
+ _vm->_mouseClickState._left = false;
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ _vm->_toyUfoActionStatus = kAS42ToyUfoRefresh;
+ _vm->toyUfoFlyTo(-1, -1, 0, 799, 0, 300, 3);
+ } else {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ }
+ }
+
+ updateAnimations();
+
+ _vm->toyUfoCheckTimer();
+
+ if (!_vm->_isLeavingScene) {
+ if (plat._actionStatus < 0 && !_vm->isFlag(kGFGnapControlsToyUFO))
+ plat.updateIdleSequence();
+ if (gnap._actionStatus < 0 && !_vm->isFlag(kGFGnapControlsToyUFO))
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[4]) {
+ _vm->_timers[4] = _vm->getRandom(20) + 30;
+ if (gnap._actionStatus < 0 && plat._actionStatus < 0 && _nextBBQVendorSequenceId == -1) {
+ switch (_vm->getRandom(8)) {
+ case 0:
+ _nextBBQVendorSequenceId = 0x14C;
+ break;
+ case 1:
+ case 2:
+ _nextBBQVendorSequenceId = 0x149;
+ break;
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ _nextBBQVendorSequenceId = 0x14D;
+ break;
+ case 7:
+ _nextBBQVendorSequenceId = 0x14A;
+ break;
+ }
+ if (_nextBBQVendorSequenceId == _currBBQVendorSequenceId && _nextBBQVendorSequenceId != 0x14D)
+ _nextBBQVendorSequenceId = -1;
+ }
+ }
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[4] = _vm->getRandom(20) + 30;
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene42::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ switch (gnap._actionStatus) {
+ case kAS42LeaveScene:
+ gameSys.setAnimation(0, 0, 0);
+ gnap._actionStatus = -1;
+ _vm->_sceneDone = true;
+ break;
+ case kAS42TalkBBQVendor:
+ gameSys.setAnimation(0, 0, 0);
+ gnap._actionStatus = -1;
+ _nextBBQVendorSequenceId = 0x14B;
+ break;
+ case kAS42UseQuarterWithBBQVendor:
+ case kAS42GrabChickenLeg:
+ if (gameSys.getAnimationStatus(2) == 2) {
+ int sequenceId;
+ if (gnap._actionStatus == kAS42UseQuarterWithBBQVendor) {
+ _vm->invRemove(kItemDiceQuarterHole);
+ _vm->invAdd(kItemChickenBucket);
+ _vm->setGrabCursorSprite(-1);
+ sequenceId = 0x150;
+ _nextBBQVendorSequenceId = 0x148;
+ } else if (_vm->isFlag(kGFUnk27)) {
+ if (_vm->isFlag(kGFUnk28)) {
+ sequenceId = 0x7B7;
+ _nextBBQVendorSequenceId = 0x145;
+ } else {
+ _vm->setFlag(kGFUnk28);
+ sequenceId = 0x14F;
+ _nextBBQVendorSequenceId = 0x147;
+ }
+ } else {
+ _vm->setFlag(kGFUnk27);
+ sequenceId = 0x14E;
+ _nextBBQVendorSequenceId = 0x146;
+ }
+ if (sequenceId == 0x7B7) {
+ gameSys.insertSequence(0x107B7, gnap._id,
+ makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id,
+ kSeqSyncWait, _vm->getSequenceTotalDuration(_nextBBQVendorSequenceId),
+ 75 * gnap._pos.x - gnap._gridX, 48 * gnap._pos.y - gnap._gridY);
+ gnap._sequenceDatNum = 1;
+ } else {
+ gameSys.insertSequence(sequenceId, gnap._id,
+ makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id,
+ kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceDatNum = 0;
+ }
+ gnap._sequenceId = sequenceId;
+ gameSys.setAnimation(sequenceId | (gnap._sequenceDatNum << 16), gnap._id, 0);
+ if (gnap._actionStatus == kAS42UseQuarterWithBBQVendor)
+ gnap._actionStatus = kAS42UseQuarterWithBBQVendorDone;
+ else
+ gnap._actionStatus = -1;
+ gameSys.insertSequence(_nextBBQVendorSequenceId, 1, _currBBQVendorSequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextBBQVendorSequenceId, 1, 2);
+ _currBBQVendorSequenceId = _nextBBQVendorSequenceId;
+ if (_nextBBQVendorSequenceId == 0x145)
+ _nextBBQVendorSequenceId = 0x14A;
+ else
+ _nextBBQVendorSequenceId = -1;
+ _vm->_timers[4] = _vm->getRandom(20) + 30;
+ _vm->_timers[2] = _vm->getRandom(30) + 20;
+ _vm->_timers[3] = _vm->getRandom(50) + 200;
+ }
+ break;
+ case kAS42UseQuarterWithBBQVendorDone:
+ gameSys.setAnimation(0, 0, 0);
+ _vm->setGrabCursorSprite(kItemChickenBucket);
+ gnap._actionStatus = -1;
+ break;
+ default:
+ gameSys.setAnimation(0, 0, 0);
+ gnap._actionStatus = -1;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(2) == 2 && _nextBBQVendorSequenceId != -1) {
+ gameSys.insertSequence(_nextBBQVendorSequenceId, 1, _currBBQVendorSequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextBBQVendorSequenceId, 1, 2);
+ _currBBQVendorSequenceId = _nextBBQVendorSequenceId;
+ _nextBBQVendorSequenceId = -1;
+ _vm->_timers[4] = _vm->getRandom(20) + 30;
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2) {
+ switch (_vm->_toyUfoActionStatus) {
+ case kAS42ToyUfoLeaveScene:
+ _vm->_sceneDone = true;
+ break;
+ case kAS42ToyUfoPickUpHotSauce:
+ gameSys.insertSequence(0x10870, _vm->_toyUfoId, _vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, kSeqSyncWait, 0, 0, 0);
+ _vm->setFlag(kGFUnk24);
+ updateHotspots();
+ _vm->toyUfoSetStatus(kGFGroceryStoreHatTaken);
+ _vm->_toyUfoSequenceId = 0x870;
+ gameSys.setAnimation(0x10870, _vm->_toyUfoId, 3);
+ _vm->_toyUfoActionStatus = -1;
+ _vm->_toyUfoX = 0x181;
+ _vm->_toyUfoY = 53;
+ break;
+ default:
+ if (_vm->_toyUfoSequenceId == 0x872) {
+ _vm->hideCursor();
+ _vm->addFullScreenSprite(0x13E, 255);
+ gameSys.setAnimation(0x151, 256, 0);
+ gameSys.insertSequence(0x151, 256, 0, 0, kSeqNone, 0, 0, 0);
+ while (gameSys.getAnimationStatus(0) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+ _vm->removeFullScreenSprite();
+ _vm->showCursor();
+ }
+ _vm->_toyUfoNextSequenceId = _vm->toyUfoGetSequenceId();
+ gameSys.setAnimation(_vm->_toyUfoNextSequenceId | 0x10000, (_vm->_toyUfoId + 1) % 10, 3);
+ gameSys.insertSequence(_vm->_toyUfoNextSequenceId | 0x10000, (_vm->_toyUfoId + 1) % 10,
+ _vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId,
+ kSeqSyncWait, 0, _vm->_toyUfoX - 274, _vm->_toyUfoY - 128);
+ _vm->_toyUfoSequenceId = _vm->_toyUfoNextSequenceId;
+ _vm->_toyUfoId = (_vm->_toyUfoId + 1) % 10;
+ break;
+ }
+ _vm->_toyUfoActionStatus = -1;
+ }
+}
+
+/*****************************************************************************/
+
+Scene43::Scene43(GnapEngine *vm) : Scene(vm) {
+ _currTwoHeadedGuySequenceId = -1;
+ _nextTwoHeadedGuySequenceId = -1;
+}
+
+int Scene43::init() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ gameSys.setAnimation(0, 0, 0);
+ gameSys.setAnimation(0, 0, 1);
+ gameSys.setAnimation(0, 0, 2);
+ return 0x13F;
+}
+
+void Scene43::updateHotspots() {
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ _vm->setHotspot(kHS43Platypus, 0, 0, 0, 0, SF_DISABLED);
+ _vm->setHotspot(kHS43UfoExitLeft, 0, 0, 10, 599, SF_EXIT_L_CURSOR);
+ _vm->setHotspot(kHS43UfoExitRight, 790, 0, 799, 599, SF_EXIT_R_CURSOR);
+ _vm->setHotspot(kHS43UfoKey, 140, 170, 185, 260, SF_GRAB_CURSOR);
+ _vm->setHotspot(kHS43UfoBucket, 475, 290, 545, 365, SF_DISABLED);
+ _vm->setDeviceHotspot(kHS43UfoDevice, -1, 534, -1, 599);
+ if (_vm->isFlag(kGFGroceryStoreHatTaken))
+ _vm->_hotspots[kHS43UfoBucket]._flags = SF_GRAB_CURSOR;
+ // NOTE Bug in the original. Key hotspot wasn't disabled.
+ if (_vm->isFlag(kGFUnk14))
+ _vm->_hotspots[kHS43UfoKey]._flags = SF_DISABLED;
+ _vm->_hotspotsCount = 6;
+ } else {
+ _vm->setHotspot(kHS43Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS43ExitUfoParty, 150, 580, 650, 600, SF_EXIT_D_CURSOR | SF_WALKABLE, 5, 9);
+ _vm->setHotspot(kHS43ExitBBQ, 0, 100, 10, 599, SF_EXIT_L_CURSOR, 0, 8);
+ _vm->setHotspot(kHS43ExitKissinBooth, 790, 100, 799, 599, SF_EXIT_R_CURSOR, 10, 8);
+ _vm->setHotspot(kHS43TwoHeadedGuy, 470, 240, 700, 470, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS43Key, 140, 170, 185, 260, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS43Ufo, 110, 0, 690, 350, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS43WalkArea1, 0, 0, 800, 445);
+ _vm->setHotspot(kHS43WalkArea2, 465, 0, 800, 493);
+ _vm->setDeviceHotspot(kHS43Device, -1, -1, -1, -1);
+ if (_vm->isFlag(kGFUnk14))
+ _vm->_hotspots[kHS43Key]._flags = SF_DISABLED;
+ _vm->_hotspotsCount = 10;
+ }
+}
+
+void Scene43::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->queueInsertDeviceIcon();
+
+ if (!_vm->isFlag(kGFUnk14))
+ gameSys.insertSequence(0x1086F, 1, 0, 0, kSeqNone, 0, 0, 0);
+
+ _currTwoHeadedGuySequenceId = 0x13C;
+ _nextTwoHeadedGuySequenceId = -1;
+
+ gameSys.setAnimation(0x13C, 1, 2);
+ gameSys.insertSequence(_currTwoHeadedGuySequenceId, 1, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ _vm->_toyUfoId = 0;
+ _vm->_toyUfoActionStatus = -1;
+ _vm->_toyUfoSequenceId = _vm->toyUfoGetSequenceId();
+ _vm->_toyUfoNextSequenceId = _vm->_toyUfoSequenceId;
+ if (_vm->_prevSceneNum == 42)
+ _vm->_toyUfoX = 30;
+ else
+ _vm->_toyUfoX = 770;
+ gameSys.setAnimation(_vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, 3);
+ gameSys.insertSequence(_vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, 0, 0, kSeqNone, 0, _vm->_toyUfoX - 274, _vm->_toyUfoY - 128);
+ _vm->endSceneInit();
+ } else {
+ switch (_vm->_prevSceneNum) {
+ case 42:
+ gnap.initPos(-1, 8, kDirUpRight);
+ plat.initPos(-1, 9, kDirUpLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(2, 8), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(1, 8), -1, 0x107C2, 1);
+ break;
+ case 44:
+ gnap.initPos(11, 8, kDirUpRight);
+ plat.initPos(11, 9, kDirUpLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(8, 8), -1, 0x107BA, 1);
+ plat.walkTo(Common::Point(9, 8), -1, 0x107D2, 1);
+ break;
+ case 54:
+ gnap.initPos(4, 7, kDirBottomLeft);
+ plat.initPos(11, 8, kDirUpLeft);
+ _vm->endSceneInit();
+ plat.walkTo(Common::Point(9, 8), -1, 0x107D2, 1);
+ break;
+ default:
+ gnap.initPos(5, 11, kDirUpRight);
+ plat.initPos(6, 11, kDirUpLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(5, 8), -1, 0x107BA, 1);
+ plat.walkTo(Common::Point(6, 8), -1, 0x107C2, 1);
+ break;
+ }
+ }
+
+ while (!_vm->_sceneDone) {
+ if (!_vm->isSoundPlaying(0x1094B))
+ _vm->playSound(0x1094B, true);
+
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->testWalk(0, 0, -1, -1, -1, -1);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS43UfoDevice:
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[4] = _vm->getRandom(100) + 100;
+ break;
+
+ case kHS43UfoExitLeft:
+ if (_vm->_toyUfoActionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_toyUfoActionStatus = 4;
+ _vm->_newSceneNum = 42;
+ _vm->toyUfoFlyTo(-35, -1, -35, 799, 0, 300, 3);
+ }
+ break;
+
+ case kHS43UfoExitRight:
+ if (_vm->_toyUfoActionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_toyUfoActionStatus = 4;
+ _vm->_newSceneNum = 44;
+ _vm->toyUfoFlyTo(835, -1, 0, 835, 0, 300, 3);
+ }
+ break;
+
+ case kHS43UfoKey:
+ if (_vm->isFlag(kGFJointTaken)) {
+ _vm->_toyUfoActionStatus = 6;
+ _vm->toyUfoFlyTo(163, 145, 0, 799, 0, 300, 3);
+ } else {
+ _vm->_toyUfoActionStatus = 5;
+ _vm->toyUfoFlyTo(-1, -1, 0, 799, 0, 300, 3);
+ }
+ break;
+
+ case kHS43UfoBucket:
+ _vm->_toyUfoActionStatus = 7;
+ _vm->toyUfoFlyTo(497, 143, 0, 799, 0, 300, 3);
+ _vm->_timers[9] = 600;
+ break;
+ }
+ } else {
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS43Device:
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[4] = _vm->getRandom(100) + 100;
+ break;
+
+ case kHS43Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible(plat._pos);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible(plat._pos);
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS43ExitUfoParty:
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS43ExitUfoParty], 0, 0x107AE, 1);
+ gnap._actionStatus = 0;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS43ExitUfoParty], -1, 0x107C7, 1);
+ _vm->_newSceneNum = 40;
+ break;
+
+ case kHS43ExitBBQ:
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS43ExitBBQ].x, gnap._pos.y), 0, 0x107AF, 1);
+ gnap._actionStatus = 0;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS43ExitBBQ], -1, 0x107CF, 1);
+ _vm->_newSceneNum = 42;
+ break;
+
+ case kHS43ExitKissinBooth:
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS43ExitKissinBooth].x, gnap._pos.y), 0, 0x107AB, 1);
+ gnap._actionStatus = 0;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS43ExitKissinBooth], -1, 0x107CD, 1);
+ _vm->_newSceneNum = 44;
+ break;
+
+ case kHS43TwoHeadedGuy:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(6, 8), 7, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(7, 0));
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(Common::Point(5, 8), 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = 2;
+ break;
+ case GRAB_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ break;
+
+ case kHS43Key:
+ case kHS43Ufo:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(3, 7), 2, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead();
+ break;
+ case GRAB_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(Common::Point(3, 7), 0, 67515, 1);
+ gnap._actionStatus = 1;
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ break;
+
+ case kHS43WalkArea1:
+ case kHS43WalkArea2:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+ }
+ }
+
+ if (_vm->_mouseClickState._left && gnap._actionStatus < 0) {
+ _vm->_mouseClickState._left = false;
+ if (_vm->isFlag(kGFGnapControlsToyUFO) && (_vm->_toyUfoActionStatus == 5 || _vm->_toyUfoActionStatus == -1)) {
+ _vm->_toyUfoActionStatus = 5;
+ _vm->toyUfoFlyTo(-1, -1, 0, 799, 0, 300, 3);
+ } else {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ }
+ }
+
+ updateAnimations();
+
+ _vm->toyUfoCheckTimer();
+
+ if (!_vm->_isLeavingScene) {
+ if (plat._actionStatus < 0 && !_vm->isFlag(kGFGnapControlsToyUFO))
+ plat.updateIdleSequence();
+ if (gnap._actionStatus < 0 && !_vm->isFlag(kGFGnapControlsToyUFO))
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[4] && (!_vm->isFlag(kGFGnapControlsToyUFO) || !_vm->isFlag(kGFGroceryStoreHatTaken))) {
+ _vm->_timers[4] = _vm->getRandom(100) + 100;
+ if (gnap._actionStatus < 0 && plat._actionStatus < 0 && _nextTwoHeadedGuySequenceId == -1) {
+ switch (_vm->getRandom(5)) {
+ case 0:
+ _nextTwoHeadedGuySequenceId = 0x13C;
+ break;
+ case 1:
+ _nextTwoHeadedGuySequenceId = 0x134;
+ break;
+ case 2:
+ _nextTwoHeadedGuySequenceId = 0x135;
+ break;
+ case 3:
+ _nextTwoHeadedGuySequenceId = 0x136;
+ break;
+ case 4:
+ _nextTwoHeadedGuySequenceId = 0x13A;
+ break;
+ }
+ if (_nextTwoHeadedGuySequenceId == _currTwoHeadedGuySequenceId)
+ _nextTwoHeadedGuySequenceId = -1;
+ }
+ }
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[4] = _vm->getRandom(100) + 100;
+ }
+
+ _vm->gameUpdateTick();
+ }
+
+ if (_vm->_newSceneNum == 54)
+ _vm->clearFlag(kGFGnapControlsToyUFO);
+}
+
+void Scene43::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ switch (gnap._actionStatus) {
+ case 0:
+ gameSys.setAnimation(0, 0, 0);
+ _vm->_sceneDone = true;
+ break;
+
+ case 1:
+ if (gameSys.getAnimationStatus(2) == 2) {
+ _vm->_timers[2] = _vm->getRandom(30) + 20;
+ _vm->_timers[3] = _vm->getRandom(50) + 200;
+ gameSys.insertSequence(0x13D, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x13D;
+ gnap._sequenceDatNum = 0;
+ gameSys.setAnimation(0x13D, gnap._id, 0);
+ _nextTwoHeadedGuySequenceId = 0x13B;
+ gameSys.insertSequence(0x13B, 1, _currTwoHeadedGuySequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextTwoHeadedGuySequenceId, 1, 2);
+ _currTwoHeadedGuySequenceId = _nextTwoHeadedGuySequenceId;
+ _nextTwoHeadedGuySequenceId = -1;
+ _vm->_timers[4] = _vm->getRandom(100) + 100;
+ gnap._actionStatus = -1;
+ }
+ break;
+
+ default:
+ gameSys.setAnimation(0, 0, 0);
+ gnap._actionStatus = -1;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(2) == 2) {
+ if (_currTwoHeadedGuySequenceId == 0x13A) {
+ if (_vm->isFlag(kGFGroceryStoreHatTaken)) {
+ _nextTwoHeadedGuySequenceId = 0x13E;
+ _vm->stopSound(0x108F6);
+ } else if (_vm->getRandom(2) != 0) {
+ _nextTwoHeadedGuySequenceId = 0x137;
+ } else {
+ _nextTwoHeadedGuySequenceId = 0x138;
+ }
+ } else if (_currTwoHeadedGuySequenceId == 0x13E) {
+ _vm->_sceneDone = true;
+ _vm->_newSceneNum = 54;
+ }
+ if (_nextTwoHeadedGuySequenceId != -1) {
+ gameSys.insertSequence(_nextTwoHeadedGuySequenceId, 1, _currTwoHeadedGuySequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextTwoHeadedGuySequenceId, 1, 2);
+ _currTwoHeadedGuySequenceId = _nextTwoHeadedGuySequenceId;
+ _nextTwoHeadedGuySequenceId = -1;
+ _vm->_timers[4] = _vm->getRandom(100) + 100;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2) {
+ switch (_vm->_toyUfoActionStatus) {
+ case 4:
+ _vm->_sceneDone = true;
+ _vm->_toyUfoActionStatus = -1;
+ break;
+ case 6:
+ gameSys.insertSequence(0x10871, _vm->_toyUfoId, _vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, kSeqSyncWait, 0, 0, 0);
+ gameSys.removeSequence(0x1086F, 1, true);
+ _vm->setFlag(kGFUnk14);
+ updateHotspots();
+ _vm->toyUfoSetStatus(kGFUnk18);
+ _vm->_toyUfoSequenceId = 0x871;
+ gameSys.setAnimation(0x10871, _vm->_toyUfoId, 3);
+ _vm->_toyUfoActionStatus = -1;
+ _vm->_toyUfoX = 96;
+ _vm->_toyUfoY = 131;
+ break;
+ case 7:
+ gameSys.insertSequence(0x10874, _vm->_toyUfoId, _vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, kSeqSyncWait, 0, 0, 0);
+ _vm->_toyUfoSequenceId = 0x874;
+ gameSys.setAnimation(0x10874, _vm->_toyUfoId, 3);
+ _vm->_toyUfoActionStatus = 8;
+ _vm->setFlag(kGFJointTaken);
+ gnap._actionStatus = 3;
+ break;
+ case 8:
+ _nextTwoHeadedGuySequenceId = 0x13A;
+ _vm->_toyUfoX = 514;
+ _vm->_toyUfoY = 125;
+ _vm->toyUfoFlyTo(835, 125, 0, 835, 0, 300, 3);
+ _vm->_toyUfoActionStatus = 9;
+ break;
+ case 9:
+ // Nothing
+ break;
+ default:
+ _vm->_toyUfoNextSequenceId = _vm->toyUfoGetSequenceId();
+ gameSys.insertSequence(_vm->_toyUfoNextSequenceId | 0x10000, _vm->_toyUfoId + 1,
+ _vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId,
+ kSeqSyncWait, 0, _vm->_toyUfoX - 274, _vm->_toyUfoY - 128);
+ _vm->_toyUfoSequenceId = _vm->_toyUfoNextSequenceId;
+ ++_vm->_toyUfoId;
+ gameSys.setAnimation(_vm->_toyUfoNextSequenceId | 0x10000, _vm->_toyUfoId, 3);
+ _vm->_toyUfoActionStatus = -1;
+ break;
+ }
+ }
+}
+
+/*****************************************************************************/
+
+Scene44::Scene44(GnapEngine *vm) : Scene(vm) {
+ _nextSpringGuySequenceId = -1;
+ _nextKissingLadySequenceId = -1;
+ _currSpringGuySequenceId = -1;
+ _currKissingLadySequenceId = -1;
+}
+
+int Scene44::init() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ gameSys.setAnimation(0, 0, 0);
+ gameSys.setAnimation(0, 0, 1);
+ gameSys.setAnimation(0, 0, 2);
+ gameSys.setAnimation(0, 0, 3);
+ return 0xFF;
+}
+
+void Scene44::updateHotspots() {
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ _vm->setHotspot(kHS44Platypus, 0, 0, 0, 0, SF_DISABLED);
+ _vm->setHotspot(kHS44UfoExitLeft, 0, 0, 10, 599, SF_EXIT_L_CURSOR);
+ _vm->setHotspot(kHS44UfoExitRight, 790, 0, 799, 599, SF_EXIT_R_CURSOR);
+ _vm->setDeviceHotspot(kHS44UfoDevice, -1, 534, -1, 599);
+ _vm->_hotspotsCount = 4;
+ } else {
+ _vm->setHotspot(kHS44Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS44ExitUfoParty, 150, 580, 650, 600, SF_EXIT_D_CURSOR | SF_WALKABLE, 5, 9);
+ _vm->setHotspot(kHS44ExitUfo, 0, 100, 10, 599, SF_EXIT_L_CURSOR, 0, 8);
+ _vm->setHotspot(kHS44ExitShow, 790, 100, 799, 599, SF_EXIT_R_CURSOR, 10, 8);
+ _vm->setHotspot(kHS44KissingLady, 300, 160, 400, 315, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 5, 7);
+ _vm->setHotspot(kHS44Spring, 580, 310, 635, 375, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 7, 8);
+ _vm->setHotspot(kHS44SpringGuy, 610, 375, 690, 515, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 7, 8);
+ _vm->setHotspot(kHS44WalkArea1, 0, 0, 800, 445);
+ _vm->setHotspot(kHS44WalkArea2, 617, 0, 800, 600);
+ _vm->setDeviceHotspot(kHS44Device, -1, -1, -1, -1);
+ if (_vm->isFlag(kGFUnk13))
+ _vm->_hotspots[kHS44KissingLady]._flags = SF_DISABLED;
+ if (_vm->isFlag(kGFSpringTaken))
+ _vm->_hotspots[kHS44Spring]._flags = SF_DISABLED;
+ _vm->_hotspotsCount = 10;
+ }
+}
+
+void Scene44::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->queueInsertDeviceIcon();
+
+ gameSys.insertSequence(0xF7, 0, 0, 0, kSeqLoop, 0, 0, 0);
+ gameSys.insertSequence(0xFC, 256, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (_vm->isFlag(kGFSpringTaken))
+ _currSpringGuySequenceId = 0xF8;
+ else
+ _currSpringGuySequenceId = 0xF9;
+
+ _nextSpringGuySequenceId = -1;
+ gameSys.setAnimation(_currSpringGuySequenceId, 1, 4);
+ gameSys.insertSequence(_currSpringGuySequenceId, 1, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (_vm->isFlag(kGFUnk13)) {
+ if (_vm->_prevSceneNum != 50 || _vm->_sceneSavegameLoaded) {
+ _currKissingLadySequenceId = 0xF6;
+ _nextKissingLadySequenceId = -1;
+ } else {
+ _vm->setGrabCursorSprite(kItemGum);
+ _currKissingLadySequenceId = 0xF5;
+ _nextKissingLadySequenceId = 0xF6;
+ gameSys.setAnimation(0xF5, 1, 2);
+ }
+ } else {
+ _currKissingLadySequenceId = 0xEC;
+ _nextKissingLadySequenceId = -1;
+ gameSys.setAnimation(0xEC, 1, 2);
+ }
+
+ gameSys.insertSequence(_currKissingLadySequenceId, 1, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ _vm->_toyUfoId = 0;
+ _vm->_toyUfoActionStatus = -1;
+ _vm->_toyUfoSequenceId = _vm->toyUfoGetSequenceId();
+ _vm->_toyUfoNextSequenceId = _vm->_toyUfoSequenceId;
+ if (_vm->_prevSceneNum == 43)
+ _vm->_toyUfoX = 30;
+ else
+ _vm->_toyUfoX = 770;
+ gameSys.setAnimation(_vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, 3);
+ gameSys.insertSequence(_vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, 0, 0, kSeqNone, 0, _vm->_toyUfoX - 274, _vm->_toyUfoY - 128);
+ _vm->endSceneInit();
+ } else {
+ switch (_vm->_prevSceneNum) {
+ case 43:
+ gnap.initPos(-1, 8, kDirUpRight);
+ plat.initPos(-1, 7, kDirUpLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(2, 8), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(1, 8), -1, 0x107C2, 1);
+ break;
+ case 46:
+ gnap.initPos(11, 8, kDirUpRight);
+ plat.initPos(11, 8, kDirUpLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(6, 8), -1, 0x107BA, 1);
+ plat.walkTo(Common::Point(7, 8), -1, 0x107D2, 1);
+ break;
+ case 50:
+ gnap.initPos(4, 8, kDirBottomRight);
+ if (_vm->_sceneSavegameLoaded) {
+ plat.initPos(_vm->_hotspotsWalkPos[4].x, _vm->_hotspotsWalkPos[4].y, kDirIdleRight);
+ } else if (!_vm->isFlag(kGFUnk13)) {
+ _vm->_timers[0] = 50;
+ _vm->_timers[1] = 20;
+ plat._pos = Common::Point(5, 8);
+ plat._sequenceId = 0xFD;
+ plat._idleFacing = kDirIdleLeft;
+ plat._id = 160;
+ plat._sequenceDatNum = 0;
+ gameSys.insertSequence(0xFD, 160, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ _vm->endSceneInit();
+ break;
+ default:
+ gnap.initPos(5, 11, kDirUpRight);
+ plat.initPos(6, 11, kDirUpLeft);
+ _vm->endSceneInit();
+ plat.walkTo(Common::Point(6, 8), -1, 0x107C2, 1);
+ gnap.walkTo(Common::Point(5, 8), -1, 0x107BA, 1);
+ break;
+ }
+ }
+
+ while (!_vm->_sceneDone) {
+ if (!_vm->isSoundPlaying(0x1094B))
+ _vm->playSound(0x1094B, true);
+
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->testWalk(0, 0, -1, -1, -1, -1);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS44UfoExitLeft:
+ if (_vm->_toyUfoActionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_toyUfoActionStatus = 6;
+ _vm->_newSceneNum = 43;
+ _vm->toyUfoFlyTo(-35, -1, -35, 799, 0, 300, 3);
+ }
+ break;
+
+ case kHS44UfoExitRight:
+ if (_vm->_toyUfoActionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_toyUfoActionStatus = 6;
+ _vm->_newSceneNum = 46;
+ _vm->toyUfoFlyTo(835, -1, 0, 835, 0, 300, 3);
+ }
+ break;
+
+ case kHS44UfoDevice:
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[4] = _vm->getRandom(20) + 20;
+ break;
+ }
+ } else if (_vm->_sceneClickedHotspot <= 9) {
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS44Device:
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[4] = _vm->getRandom(20) + 20;
+ break;
+
+ case kHS44Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible(plat._pos);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible(plat._pos);
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS44ExitUfoParty:
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS44ExitUfoParty], 0, 0x107AE, 1);
+ gnap._actionStatus = 0;
+ _vm->_newSceneNum = 40;
+ break;
+
+ case kHS44ExitUfo:
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS44ExitUfo].x, gnap._pos.y), 0, 0x107AF, 1);
+ gnap._actionStatus = 0;
+ plat.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS44ExitUfo].x, plat._pos.y), -1, 0x107CF, 1);
+ _vm->_newSceneNum = 43;
+ break;
+
+ case kHS44ExitShow:
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS44ExitShow], 0, 0x107AB, 1);
+ gnap._actionStatus = 0;
+ _vm->_newSceneNum = 46;
+ break;
+
+ case kHS44KissingLady:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap._actionStatus = 2;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS44KissingLady], 0, -1, 9);
+ gnap.playShowItem(_vm->_grabCursorSpriteIndex, _vm->_hotspotsWalkPos[kHS44KissingLady].x - 1, _vm->_hotspotsWalkPos[kHS44KissingLady].y);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(4, 3));
+ break;
+ case GRAB_CURSOR:
+ gnap.playImpossible();
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpLeft;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS44KissingLady], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = 1;
+ break;
+ case PLAT_CURSOR:
+ gnap.useDeviceOnPlatypus();
+ plat.walkTo(Common::Point(6, 7), 1, 0x107D2, 1);
+ if (gnap._pos == Common::Point(7, 7))
+ gnap.walkStep();
+ gnap.playIdle(Common::Point(5, 7));
+ plat._actionStatus = 4;
+ break;
+ }
+ }
+ break;
+
+ case kHS44Spring:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS44Spring], 8, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(8, 7));
+ break;
+ case GRAB_CURSOR:
+ gnap.playPullOutDevice(Common::Point(8, 0));
+ gnap.playUseDevice(Common::Point(8, 0));
+ _nextSpringGuySequenceId = 0xFB;
+ _vm->invAdd(kItemSpring);
+ _vm->setFlag(kGFSpringTaken);
+ updateHotspots();
+ break;
+ case TALK_CURSOR:
+ gnap.playImpossible();
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ break;
+
+ case kHS44SpringGuy:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS44SpringGuy], 8, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ if (_vm->isFlag(kGFSpringTaken))
+ gnap.playMoan1(Common::Point(8, 7));
+ else
+ gnap.playScratchingHead(Common::Point(8, 7));
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS44SpringGuy], -1, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ break;
+ case GRAB_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ break;
+
+ case kHS44WalkArea1:
+ case kHS44WalkArea2:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ }
+ }
+
+ if (_vm->_mouseClickState._left && gnap._actionStatus < 0) {
+ _vm->_mouseClickState._left = false;
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ _vm->_toyUfoActionStatus = 7;
+ _vm->toyUfoFlyTo(-1, -1, 0, 799, 0, 300, 3);
+ } else {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ }
+ }
+
+ updateAnimations();
+ _vm->toyUfoCheckTimer();
+
+ if (!_vm->_isLeavingScene) {
+ if (plat._actionStatus < 0 && !_vm->isFlag(kGFGnapControlsToyUFO) && _currKissingLadySequenceId != 0xF5)
+ plat.updateIdleSequence();
+ if (gnap._actionStatus < 0 && !_vm->isFlag(kGFGnapControlsToyUFO))
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[4]) {
+ _vm->_timers[4] = _vm->getRandom(20) + 20;
+ if (gnap._actionStatus < 0 && plat._actionStatus < 0 && _nextKissingLadySequenceId == -1) {
+ switch (_vm->getRandom(20)) {
+ case 0:
+ _nextKissingLadySequenceId = 0xED;
+ break;
+ case 1:
+ _nextKissingLadySequenceId = 0xEE;
+ break;
+ case 2:
+ _nextKissingLadySequenceId = 0xF0;
+ break;
+ case 3:
+ _nextKissingLadySequenceId = 0xF3;
+ break;
+ case 4:
+ _nextKissingLadySequenceId = 0xF4;
+ break;
+ default:
+ _nextKissingLadySequenceId = 0xEC;
+ break;
+ }
+ if (_nextKissingLadySequenceId != 0xEC && _nextKissingLadySequenceId == _currKissingLadySequenceId)
+ _nextKissingLadySequenceId = -1;
+ }
+ }
+ if (!_vm->_timers[5]) {
+ _vm->_timers[5] = _vm->getRandom(20) + 20;
+ if (gnap._actionStatus < 0 && plat._actionStatus < 0 && _nextSpringGuySequenceId == -1) {
+ if (_vm->getRandom(5) != 0) {
+ if (!_vm->isFlag(kGFSpringTaken))
+ _nextSpringGuySequenceId = 0xF9;
+ } else {
+ if (_vm->isFlag(kGFSpringTaken))
+ _nextSpringGuySequenceId = 0xF8;
+ else
+ _nextSpringGuySequenceId = 0xFA;
+ }
+ }
+ }
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[4] = _vm->getRandom(20) + 20;
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene44::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case 0:
+ _vm->_sceneDone = true;
+ break;
+ case 1:
+ _nextKissingLadySequenceId = 0xEF;
+ break;
+ case 2:
+ _nextKissingLadySequenceId = 0xF2;
+ break;
+ }
+ gnap._actionStatus = -1;
+ }
+
+ if (gameSys.getAnimationStatus(1) == 2) {
+ gameSys.setAnimation(0, 0, 1);
+ switch (plat._actionStatus) {
+ case 4:
+ if (gameSys.getAnimationStatus(2) == 2) {
+ gameSys.insertSequence(0xFE, plat._id, plat._sequenceId | (plat._sequenceDatNum << 16), plat._id, kSeqSyncWait, 0, 0, 0);
+ plat._sequenceId = 0xFE;
+ plat._sequenceDatNum = 0;
+ gameSys.setAnimation(0xFE, plat._id, 1);
+ gameSys.removeSequence(_currKissingLadySequenceId, 1, true);
+ plat._actionStatus = 5;
+ }
+ break;
+ case 5:
+ _vm->_sceneDone = true;
+ _vm->_newSceneNum = 50;
+ break;
+ default:
+ plat._actionStatus = -1;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(2) == 2) {
+ if (_nextKissingLadySequenceId == 0xF6) {
+ gameSys.insertSequence(_nextKissingLadySequenceId, 1, _currKissingLadySequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ plat.initPos(5, 8, kDirIdleLeft);
+ _currKissingLadySequenceId = _nextKissingLadySequenceId;
+ _nextKissingLadySequenceId = -1;
+ gameSys.setAnimation(0, 0, 2);
+ } else if (_nextKissingLadySequenceId != -1) {
+ gameSys.insertSequence(_nextKissingLadySequenceId, 1, _currKissingLadySequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextKissingLadySequenceId, 1, 2);
+ _currKissingLadySequenceId = _nextKissingLadySequenceId;
+ _nextKissingLadySequenceId = -1;
+ _vm->_timers[4] = _vm->getRandom(20) + 20;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(4) == 2) {
+ if (_currSpringGuySequenceId == 0xFB) {
+ _vm->setGrabCursorSprite(kItemSpring);
+ _nextSpringGuySequenceId = 0xF8;
+ }
+ if (_nextSpringGuySequenceId != -1) {
+ gameSys.insertSequence(_nextSpringGuySequenceId, 1, _currSpringGuySequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextSpringGuySequenceId, 1, 4);
+ _currSpringGuySequenceId = _nextSpringGuySequenceId;
+ _nextSpringGuySequenceId = -1;
+ _vm->_timers[5] = _vm->getRandom(20) + 20;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2) {
+ switch (_vm->_toyUfoActionStatus) {
+ case 6:
+ _vm->_sceneDone = true;
+ break;
+ default:
+ _vm->_toyUfoNextSequenceId = _vm->toyUfoGetSequenceId();
+ gameSys.insertSequence(_vm->_toyUfoNextSequenceId | 0x10000, _vm->_toyUfoId + 1,
+ _vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId,
+ kSeqSyncWait, 0, _vm->_toyUfoX - 274, _vm->_toyUfoY - 128);
+ _vm->_toyUfoSequenceId = _vm->_toyUfoNextSequenceId;
+ ++_vm->_toyUfoId;
+ gameSys.setAnimation(_vm->_toyUfoNextSequenceId | 0x10000, _vm->_toyUfoId, 3);
+ break;
+ }
+ _vm->_toyUfoActionStatus = -1;
+ }
+}
+
+/*****************************************************************************/
+
+Scene45::Scene45(GnapEngine *vm) : Scene(vm) {
+ _currDancerSequenceId = -1;
+}
+
+int Scene45::init() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ gameSys.setAnimation(0, 0, 0);
+ gameSys.setAnimation(0, 0, 1);
+ gameSys.setAnimation(0, 0, 2);
+ gameSys.setAnimation(0, 0, 3);
+ gameSys.setAnimation(0, 0, 4);
+ gameSys.setAnimation(0, 0, 5);
+ return _vm->isFlag(kGFUnk23) ? 0xA2 : 0xA1;
+}
+
+void Scene45::updateHotspots() {
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ _vm->setHotspot(kHS45Platypus, 0, 0, 0, 0, SF_DISABLED);
+ _vm->setHotspot(kHS45UfoExitLeft, 0, 0, 10, 599, SF_EXIT_L_CURSOR);
+ _vm->setHotspot(kHS45UfoExitRight, 794, 0, 799, 599, SF_EXIT_R_CURSOR | SF_DISABLED);
+ _vm->setDeviceHotspot(kHS45UfoDevice, -1, 534, -1, 599);
+ _vm->_hotspotsCount = 4;
+ } else {
+ _vm->setHotspot(kHS45Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS45ExitUfoParty, 150, 580, 650, 600, SF_EXIT_D_CURSOR | SF_WALKABLE, 5, 9);
+ _vm->setHotspot(kHS45ExitShoe, 0, 100, 10, 599, SF_EXIT_L_CURSOR, 0, 8);
+ _vm->setHotspot(kHS45ExitRight, 794, 100, 799, 599, SF_EXIT_R_CURSOR | SF_DISABLED, 10, 8);
+ _vm->setHotspot(kHS45ExitDiscoBall, 200, 0, 600, 10, SF_DISABLED);
+ _vm->setHotspot(kHS45DiscoBall, 370, 10, 470, 125, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 6, 7);
+ _vm->setHotspot(kHS45WalkArea1, 0, 0, 800, 472);
+ _vm->setDeviceHotspot(kHS45Device, -1, -1, -1, -1);
+ if (_vm->isFlag(kGFUnk22)) {
+ _vm->_hotspots[kHS45Platypus]._flags = SF_DISABLED;
+ _vm->_hotspots[kHS45ExitUfoParty]._flags = SF_DISABLED;
+ _vm->_hotspots[kHS45ExitShoe]._flags = SF_DISABLED;
+ _vm->_hotspots[kHS45ExitRight]._flags = SF_DISABLED;
+ _vm->_hotspots[kHS45ExitDiscoBall]._flags = SF_EXIT_U_CURSOR;
+ }
+ if (_vm->isFlag(kGFUnk23) || _vm->isFlag(kGFUnk22))
+ _vm->_hotspots[kHS45DiscoBall]._flags = SF_DISABLED;
+ _vm->_hotspotsCount = 8;
+ }
+}
+
+void Scene45::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ if (!_vm->isSoundPlaying(0x1094A))
+ _vm->playSound(0x1094A, true);
+
+ _vm->queueInsertDeviceIcon();
+
+ gameSys.insertSequence(0x96, 1, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.setAnimation(0x96, 1, 3);
+ gameSys.insertSequence(0x99, 1, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.setAnimation(0x99, 1, 4);
+ _currDancerSequenceId = 0x8F;
+ gameSys.setAnimation(_currDancerSequenceId, 1, 2);
+ gameSys.insertSequence(_currDancerSequenceId, 1, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ _vm->_toyUfoId = 0;
+ _vm->_toyUfoActionStatus = -1;
+ _vm->_toyUfoSequenceId = _vm->toyUfoGetSequenceId();
+ _vm->_toyUfoNextSequenceId = _vm->_toyUfoSequenceId;
+ if (_vm->_prevSceneNum == 46)
+ _vm->_toyUfoX = 30;
+ else
+ _vm->_toyUfoX = 770;
+ gameSys.setAnimation(_vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, 5);
+ gameSys.insertSequence(_vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, 0, 0, kSeqNone, 0, _vm->_toyUfoX - 274, _vm->_toyUfoY - 128);
+ _vm->endSceneInit();
+ } else if (_vm->isFlag(kGFUnk22)) {
+ gnap._sequenceId = 0x9E;
+ gnap._sequenceDatNum = 0;
+ gnap._id = 1;
+ gameSys.setAnimation(0x9E, 1, 0);
+ gnap._actionStatus = 1;
+ gameSys.insertSequence(gnap._sequenceId, gnap._id, 0, 0, kSeqNone, 0, 0, 0);
+ plat.initPos(4, 8, kDirIdleLeft);
+ _vm->endSceneInit();
+ } else if (_vm->_prevSceneNum == 46) {
+ gnap.initPos(-1, 8, kDirUpRight);
+ plat.initPos(-1, 9, kDirUpLeft);
+ _vm->endSceneInit();
+ plat.walkTo(Common::Point(4, 8), -1, 0x107C2, 1);
+ gnap.walkTo(Common::Point(2, 7), -1, 0x107B9, 1);
+ } else if (_vm->_prevSceneNum == 41) {
+ gnap.initPos(11, 8, kDirUpRight);
+ plat.initPos(11, 9, kDirUpLeft);
+ _vm->endSceneInit();
+ plat.walkTo(Common::Point(4, 8), -1, 0x107D2, 1);
+ gnap.walkTo(Common::Point(10, 9), -1, 0x107BA, 1);
+ } else {
+ gnap.initPos(2, 11, kDirUpRight);
+ plat.initPos(6, 11, kDirUpLeft);
+ _vm->endSceneInit();
+ plat.walkTo(Common::Point(4, 8), -1, 0x107C2, 1);
+ gnap.walkTo(Common::Point(2, 7), -1, 0x107B9, 1);
+ }
+
+ if (!_vm->isFlag(kGFUnk21) && !_vm->isFlag(kGFGnapControlsToyUFO)) {
+ _vm->setFlag(kGFUnk21);
+ _vm->setGrabCursorSprite(-1);
+ gameSys.setAnimation(0x9D, gnap._id, 0);
+ gameSys.insertSequence(0x9D, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ while (gameSys.getAnimationStatus(0) != 2 && !_vm->_gameDone) {
+ _vm->gameUpdateTick();
+ if (gameSys.getAnimationStatus(2) == 2) {
+ gameSys.setAnimation(0, 0, 2);
+ int newSeqId = _vm->getRandom(7) + 0x8F;
+ gameSys.insertSequence(newSeqId, 1, _currDancerSequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(newSeqId, 1, 2);
+ _currDancerSequenceId = newSeqId;
+ }
+ if (gameSys.getAnimationStatus(3) == 2 && gameSys.getAnimationStatus(4) == 2) {
+ gameSys.insertSequence(0x96, 1, 0x96, 1, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(0x96, 1, 3);
+ gameSys.insertSequence(0x99, 1, 0x99, 1, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(0x99, 1, 4);
+ }
+ }
+ gnap._sequenceId = 0x9D;
+ gnap._sequenceDatNum = 0;
+ _vm->hideCursor();
+ _vm->addFullScreenSprite(0x8A, 255);
+ gameSys.setAnimation(0xA0, 256, 0);
+ gameSys.insertSequence(0xA0, 256, 0, 0, kSeqNone, 0, 0, 0);
+ while (gameSys.getAnimationStatus(0) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+ gameSys.setAnimation(0x107BD, gnap._id, 0);
+ gameSys.insertSequence(0x107BD, gnap._id,
+ makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id,
+ kSeqSyncWait, 0, 75 * gnap._pos.x - gnap._gridX, 48 * gnap._pos.y - gnap._gridY);
+ _vm->removeFullScreenSprite();
+ _vm->showCursor();
+ gnap._sequenceId = 0x7BD;
+ gnap._sequenceDatNum = 1;
+ }
+
+ plat.playSequence(0x9A);
+ gameSys.setAnimation(plat._sequenceId, plat._id, 1);
+
+ while (!_vm->_sceneDone) {
+ if (!_vm->isSoundPlaying(0x1094A))
+ _vm->playSound(0x1094A, true);
+
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->testWalk(0, 0, -1, -1, -1, -1);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS45UfoExitLeft:
+ if (_vm->_toyUfoActionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_toyUfoActionStatus = 2;
+ _vm->_newSceneNum = 46;
+ _vm->toyUfoFlyTo(-35, -1, -35, 799, 0, 300, 5);
+ }
+ break;
+
+ case kHS45UfoExitRight:
+ if (_vm->_toyUfoActionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_toyUfoActionStatus = 2;
+ _vm->_newSceneNum = 41;
+ _vm->toyUfoFlyTo(835, -1, 0, 835, 0, 300, 5);
+ }
+ break;
+
+ case kHS45UfoDevice:
+ _vm->runMenu();
+ updateHotspots();
+ break;
+ }
+ } else {
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS45Device:
+ _vm->runMenu();
+ updateHotspots();
+ break;
+
+ case kHS45Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible(plat._pos);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ plat.playSequence(0x9A);
+ gameSys.setAnimation(plat._sequenceId, plat._id, 1);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible(plat._pos);
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS45ExitUfoParty:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(Common::Point(gnap._pos.x, _vm->_hotspotsWalkPos[kHS45ExitUfoParty].y), 0, 0x107AE, 1);
+ gnap._actionStatus = 0;
+ _vm->_newSceneNum = 40;
+ }
+ break;
+
+ case kHS45ExitShoe:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS45ExitShoe].x, gnap._pos.y), 0, 0x107AF, 1);
+ gnap._actionStatus = 0;
+ plat.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS45ExitShoe].x, plat._pos.y), -1, 0x107CF, 1);
+ _vm->_newSceneNum = 46;
+ }
+ break;
+
+ case kHS45ExitRight:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS45ExitRight].x, gnap._pos.y), 0, 0x107AB, 1);
+ gnap._actionStatus = 0;
+ plat.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS45ExitRight].x, plat._pos.y), -1, 0x107CD, 1);
+ _vm->_newSceneNum = 41;
+ }
+ break;
+
+ case kHS45ExitDiscoBall:
+ _vm->clearFlag(kGFUnk22);
+ _vm->setFlag(kGFUnk23);
+ _vm->_sceneDone = true;
+ _vm->_newSceneNum = 54;
+ break;
+
+ case kHS45DiscoBall:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemSpring) {
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS45DiscoBall], 0, 0x9F, 5);
+ gnap._actionStatus = 1;
+ _vm->setGrabCursorSprite(-1);
+ _vm->invRemove(kItemSpring);
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowItem(_vm->_grabCursorSpriteIndex, 5, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(5, 0));
+ break;
+ case GRAB_CURSOR:
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS45WalkArea1:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+ }
+ }
+
+ if (_vm->_mouseClickState._left && gnap._actionStatus < 0) {
+ _vm->_mouseClickState._left = false;
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ _vm->_toyUfoActionStatus = 3;
+ _vm->toyUfoFlyTo(-1, -1, 0, 799, 0, 300, 5);
+ } else {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ }
+ }
+
+ updateAnimations();
+ _vm->toyUfoCheckTimer();
+
+ if (!_vm->_isLeavingScene && gnap._actionStatus < 0 && !_vm->isFlag(kGFGnapControlsToyUFO))
+ gnap.updateIdleSequence();
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+
+ _vm->_sceneWaiting = false;
+}
+
+void Scene45::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case 0:
+ _vm->_sceneDone = true;
+ break;
+ case 1:
+ _vm->_sceneWaiting = true;
+ _vm->setFlag(kGFUnk22);
+ updateHotspots();
+ gameSys.insertSequence(0x9E, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x9E;
+ gnap._sequenceDatNum = 0;
+ gameSys.setAnimation(0x9E, gnap._id, 0);
+ break;
+ default:
+ gnap._actionStatus = -1;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(1) == 2) {
+ gameSys.setAnimation(0, 0, 1);
+ if (_vm->getRandom(2) != 0)
+ plat.playSequence(0x9B);
+ else
+ plat.playSequence(0x9C);
+ gameSys.setAnimation(plat._sequenceId, plat._id, 1);
+ }
+
+ if (gameSys.getAnimationStatus(2) == 2) {
+ gameSys.setAnimation(0, 0, 2);
+ int newSeqId = _vm->getRandom(7) + 0x8F;
+ gameSys.insertSequence(newSeqId, 1, _currDancerSequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(newSeqId, 1, 2);
+ _currDancerSequenceId = newSeqId;
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2 && gameSys.getAnimationStatus(4) == 2) {
+ gameSys.insertSequence(0x96, 1, 0x96, 1, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(0x96, 1, 3);
+ gameSys.insertSequence(0x99, 1, 0x99, 1, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(0x99, 1, 4);
+ }
+
+ if (gameSys.getAnimationStatus(5) == 2) {
+ switch (_vm->_toyUfoActionStatus) {
+ case 2:
+ _vm->_sceneDone = true;
+ break;
+ default:
+ _vm->_toyUfoNextSequenceId = _vm->toyUfoGetSequenceId();
+ gameSys.insertSequence(_vm->_toyUfoNextSequenceId | 0x10000, _vm->_toyUfoId + 1,
+ _vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId,
+ kSeqSyncWait, 0, _vm->_toyUfoX - 274, _vm->_toyUfoY - 128);
+ _vm->_toyUfoSequenceId = _vm->_toyUfoNextSequenceId;
+ ++_vm->_toyUfoId;
+ gameSys.setAnimation(_vm->_toyUfoNextSequenceId | 0x10000, _vm->_toyUfoId, 5);
+ break;
+ }
+ _vm->_toyUfoActionStatus = -1;
+ }
+}
+
+/*****************************************************************************/
+
+Scene46::Scene46(GnapEngine *vm) : Scene(vm) {
+ _currSackGuySequenceId = -1;
+ _nextItchyGuySequenceId = -1;
+ _nextSackGuySequenceId = -1;
+ _currItchyGuySequenceId = -1;
+}
+
+int Scene46::init() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ gameSys.setAnimation(0, 0, 0);
+ gameSys.setAnimation(0, 0, 1);
+ gameSys.setAnimation(0, 0, 2);
+ gameSys.setAnimation(0, 0, 3);
+ gameSys.setAnimation(0, 0, 4);
+ return 0x4E;
+}
+
+void Scene46::updateHotspots() {
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ _vm->setHotspot(kHS46Platypus, 0, 0, 0, 0, SF_DISABLED);
+ _vm->setHotspot(kHS46UfoExitLeft, 0, 0, 10, 599, SF_EXIT_L_CURSOR);
+ _vm->setHotspot(kHS46UfoExitRight, 790, 0, 799, 599, SF_EXIT_R_CURSOR);
+ _vm->setDeviceHotspot(kHS46UfoDevice, -1, 534, -1, 599);
+ _vm->_hotspotsCount = 4;
+ } else {
+ _vm->setHotspot(kHS46Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS46ExitUfoParty, 150, 580, 650, 600, SF_EXIT_D_CURSOR | SF_WALKABLE, 5, 9);
+ _vm->setHotspot(kHS46ExitKissinBooth, 0, 100, 10, 599, SF_EXIT_L_CURSOR, 0, 8);
+ _vm->setHotspot(kHS46ExitDisco, 790, 100, 799, 599, SF_EXIT_R_CURSOR, 10, 8);
+ _vm->setHotspot(kHS46SackGuy, 180, 370, 235, 490, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 3, 8);
+ _vm->setHotspot(kHS46ItchyGuy, 535, 210, 650, 480, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 6, 8);
+ _vm->setHotspot(kHS46WalkArea1, 0, 0, 800, 485);
+ _vm->setDeviceHotspot(kHS46Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 8;
+ }
+}
+
+void Scene46::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->queueInsertDeviceIcon();
+ gameSys.insertSequence(0x4D, 0, 0, 0, kSeqLoop, 0, 0, 0);
+
+ _currSackGuySequenceId = 0x4B;
+ _nextSackGuySequenceId = -1;
+ gameSys.setAnimation(0x4B, 1, 3);
+ gameSys.insertSequence(_currSackGuySequenceId, 1, 0, 0, kSeqNone, 0, 0, 0);
+
+ _currItchyGuySequenceId = 0x47;
+ _nextItchyGuySequenceId = -1;
+ gameSys.setAnimation(0x47, 1, 4);
+ gameSys.insertSequence(_currItchyGuySequenceId, 1, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ _vm->_toyUfoId = 0;
+ _vm->_toyUfoActionStatus = -1;
+ _vm->_toyUfoSequenceId = _vm->toyUfoGetSequenceId();
+ _vm->_toyUfoNextSequenceId = _vm->_toyUfoSequenceId;
+ if (_vm->_prevSceneNum == 44)
+ _vm->_toyUfoX = 30;
+ else
+ _vm->_toyUfoX = 770;
+ gameSys.setAnimation(_vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, 2);
+ gameSys.insertSequence(_vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, 0, 0, kSeqNone, 0, _vm->_toyUfoX - 274, _vm->_toyUfoY - 128);
+ _vm->endSceneInit();
+ } else if (_vm->_prevSceneNum == 44) {
+ gnap.initPos(-1, 8, kDirUpRight);
+ plat.initPos(-1, 8, kDirUpLeft);
+ _vm->endSceneInit();
+ plat.walkTo(Common::Point(1, 8), -1, 0x107C2, 1);
+ gnap.walkTo(Common::Point(2, 8), -1, 0x107B9, 1);
+ } else if (_vm->_prevSceneNum == 45) {
+ gnap.initPos(11, 8, kDirUpRight);
+ plat.initPos(12, 8, kDirUpLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(8, 8), -1, 0x107BA, 1);
+ plat.walkTo(Common::Point(9, 8), -1, 0x107D2, 1);
+ } else {
+ gnap.initPos(5, 11, kDirUpRight);
+ plat.initPos(6, 11, kDirUpLeft);
+ _vm->endSceneInit();
+ plat.walkTo(Common::Point(5, 8), -1, 0x107C2, 1);
+ gnap.walkTo(Common::Point(6, 8), -1, 0x107BA, 1);
+ }
+
+ _vm->_timers[4] = _vm->getRandom(50) + 80;
+ _vm->_timers[5] = _vm->getRandom(50) + 80;
+
+ while (!_vm->_sceneDone) {
+ if (!_vm->isSoundPlaying(0x1094B))
+ _vm->playSound(0x1094B, true);
+
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->testWalk(0, 0, -1, -1, -1, -1);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS46UfoExitLeft:
+ if (_vm->_toyUfoActionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_toyUfoActionStatus = 3;
+ _vm->_newSceneNum = 44;
+ _vm->toyUfoFlyTo(-35, -1, -35, 799, 0, 300, 2);
+ }
+ break;
+
+ case kHS46UfoExitRight:
+ if (_vm->_toyUfoActionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_toyUfoActionStatus = 3;
+ _vm->_newSceneNum = 45;
+ _vm->toyUfoFlyTo(835, -1, 0, 835, 0, 300, 2);
+ }
+ break;
+
+ case kHS46UfoDevice:
+ _vm->runMenu();
+ updateHotspots();
+ break;
+ }
+ } else {
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS46Device:
+ _vm->runMenu();
+ updateHotspots();
+ break;
+
+ case kHS46Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible(plat._pos);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible(plat._pos);
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS46SackGuy:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS46SackGuy], 2, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(Common::Point(_vm->_hotspotsWalkPos[kHS46SackGuy].x + 1, 0));
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpLeft;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS46SackGuy], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = 2;
+ break;
+ case GRAB_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ break;
+
+ case kHS46ItchyGuy:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS46ItchyGuy], 7, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(Common::Point(_vm->_hotspotsWalkPos[kHS46ItchyGuy].x - 1, 0));
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS46ItchyGuy], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = 1;
+ break;
+ case GRAB_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ break;
+
+ case kHS46ExitUfoParty:
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(Common::Point(gnap._pos.x, _vm->_hotspotsWalkPos[kHS46ExitUfoParty].y), 0, 0x107AE, 1);
+ gnap._actionStatus = 0;
+ _vm->_newSceneNum = 40;
+ break;
+
+ case kHS46ExitKissinBooth:
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS46ExitKissinBooth].x, gnap._pos.y), 0, 0x107AF, 1);
+ gnap._actionStatus = 0;
+ plat.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS46ExitKissinBooth].x, plat._pos.y), -1, 0x107CF, 1);
+ _vm->_newSceneNum = 44;
+ break;
+
+ case kHS46ExitDisco:
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS46ExitDisco].x, gnap._pos.y), 0, 0x107AB, 1);
+ gnap._actionStatus = 0;
+ plat.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS46ExitDisco].x, plat._pos.y), -1, 0x107CD, 1);
+ _vm->_newSceneNum = 45;
+ break;
+
+ case kHS46WalkArea1:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+ }
+ }
+
+ if (_vm->_mouseClickState._left && gnap._actionStatus < 0) {
+ _vm->_mouseClickState._left = false;
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ _vm->_toyUfoActionStatus = 4;
+ _vm->toyUfoFlyTo(-1, -1, 0, 799, 0, 300, 2);
+ } else {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ }
+ }
+
+ updateAnimations();
+ _vm->toyUfoCheckTimer();
+
+ if (!_vm->_isLeavingScene) {
+ if (plat._actionStatus < 0 && !_vm->isFlag(kGFGnapControlsToyUFO))
+ plat.updateIdleSequence();
+ if (gnap._actionStatus < 0 && !_vm->isFlag(kGFGnapControlsToyUFO))
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[4]) {
+ _vm->_timers[4] = _vm->getRandom(50) + 80;
+ if (gnap._actionStatus < 0 && plat._actionStatus < 0 && _nextItchyGuySequenceId == -1) {
+ if (_vm->getRandom(2) != 0)
+ _nextItchyGuySequenceId = 0x49;
+ else
+ _nextItchyGuySequenceId = 0x48;
+ }
+ }
+ if (!_vm->_timers[5]) {
+ _vm->_timers[5] = _vm->getRandom(50) + 80;
+ if (gnap._actionStatus < 0 && plat._actionStatus < 0 && _nextSackGuySequenceId == -1)
+ _nextSackGuySequenceId = 0x4C;
+ }
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene46::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case 0:
+ _vm->_sceneDone = true;
+ break;
+ case 1:
+ _nextItchyGuySequenceId = 0x46;
+ break;
+ case 2:
+ _nextSackGuySequenceId = 0x4A;
+ break;
+ }
+ gnap._actionStatus = -1;
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2 && _nextSackGuySequenceId != -1) {
+ gameSys.insertSequence(_nextSackGuySequenceId, 1, _currSackGuySequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextSackGuySequenceId, 1, 3);
+ _currSackGuySequenceId = _nextSackGuySequenceId;
+ _nextSackGuySequenceId = -1;
+ _vm->_timers[5] = _vm->getRandom(50) + 80;
+ }
+
+ if (gameSys.getAnimationStatus(4) == 2 && _nextItchyGuySequenceId != -1) {
+ gameSys.insertSequence(_nextItchyGuySequenceId, 1, _currItchyGuySequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextItchyGuySequenceId, 1, 4);
+ _currItchyGuySequenceId = _nextItchyGuySequenceId;
+ _nextItchyGuySequenceId = -1;
+ _vm->_timers[4] = _vm->getRandom(50) + 80;
+ }
+
+ if (gameSys.getAnimationStatus(2) == 2) {
+ switch (_vm->_toyUfoActionStatus) {
+ case 3:
+ _vm->_sceneDone = true;
+ break;
+ default:
+ _vm->_toyUfoNextSequenceId = _vm->toyUfoGetSequenceId();
+ gameSys.insertSequence(_vm->_toyUfoNextSequenceId | 0x10000, _vm->_toyUfoId + 1,
+ _vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId,
+ kSeqSyncWait, 0, _vm->_toyUfoX - 274, _vm->_toyUfoY - 128);
+ _vm->_toyUfoSequenceId = _vm->_toyUfoNextSequenceId;
+ ++_vm->_toyUfoId;
+ gameSys.setAnimation(_vm->_toyUfoNextSequenceId | 0x10000, _vm->_toyUfoId, 2);
+ break;
+ }
+ _vm->_toyUfoActionStatus = -1;
+ }
+}
+
+} // End of namespace Gnap
diff --git a/engines/gnap/scenes/group4.h b/engines/gnap/scenes/group4.h
new file mode 100644
index 0000000000..afcd62e9e7
--- /dev/null
+++ b/engines/gnap/scenes/group4.h
@@ -0,0 +1,298 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can 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 GNAP_GROUP4_H
+#define GNAP_GROUP4_H
+
+#include "gnap/debugger.h"
+
+namespace Gnap {
+
+enum {
+ kHS40Platypus = 0,
+ kHS40ExitCave = 1,
+ kHS40ExitToyStand = 2,
+ kHS40ExitBBQ = 3,
+ kHS40ExitUfo = 4,
+ kHS40ExitKissinBooth = 5,
+ kHS40ExitDancefloor = 6,
+ kHS40ExitShoe = 7,
+ kHS40Device = 8
+};
+
+enum {
+ kHS41Platypus = 0,
+ kHS41ExitCave = 1,
+ kHS41Exit = 2,
+ kHS41ExitBBQ = 3,
+ kHS41ToyVendor = 4,
+ kHS41Kid = 5,
+ kHS41ToyUfo = 6,
+ kHS41Device = 7,
+ kHS41WalkArea1 = 8
+};
+
+enum {
+ kHS41UfoExitLeft = 1,
+ kHS41UfoExitRight = 2,
+ kHS41UfoDevice = 3,
+ kHS41UfoWalkArea1 = 4
+};
+
+enum {
+ kHS42Platypus = 0,
+ kHS42ExitUfoParty = 1,
+ kHS42ExitToyStand = 2,
+ kHS42ExitUfo = 3,
+ kHS42BBQVendor = 4,
+ kHS42ChickenLeg = 5,
+ kHS42Device = 6,
+ kHS42WalkArea1 = 7,
+ kHS42WalkArea2 = 8
+};
+
+enum {
+ kHS42UfoExitLeft = 1,
+ kHS42UfoExitRight = 2,
+ kHS42UfoHotSauce = 3,
+ kHS42UfoDevice = 4
+};
+
+enum {
+ kHS43Platypus = 0,
+ kHS43Device = 1,
+ kHS43ExitUfoParty = 2,
+ kHS43ExitBBQ = 3,
+ kHS43ExitKissinBooth = 4,
+ kHS43TwoHeadedGuy = 5,
+ kHS43Key = 6,
+ kHS43Ufo = 7,
+ kHS43WalkArea1 = 8,
+ kHS43WalkArea2 = 9
+};
+
+enum {
+ kHS43UfoExitLeft = 1,
+ kHS43UfoExitRight = 2,
+ kHS43UfoKey = 3,
+ kHS43UfoBucket = 4,
+ kHS43UfoDevice = 5
+};
+
+enum {
+ kHS44Platypus = 0,
+ kHS44ExitUfoParty = 1,
+ kHS44ExitUfo = 2,
+ kHS44ExitShow = 3,
+ kHS44KissingLady = 4,
+ kHS44Spring = 5,
+ kHS44SpringGuy = 6,
+ kHS44Device = 7,
+ kHS44WalkArea1 = 8,
+ kHS44WalkArea2 = 9
+};
+
+enum {
+ kHS44UfoExitLeft = 1,
+ kHS44UfoExitRight = 2,
+ kHS44UfoDevice = 3
+};
+
+enum {
+ kHS45Platypus = 0,
+ kHS45ExitUfoParty = 1,
+ kHS45ExitShoe = 2,
+ kHS45ExitRight = 3,
+ kHS45ExitDiscoBall = 4,
+ kHS45DiscoBall = 5,
+ kHS45Device = 6,
+ kHS45WalkArea1 = 7
+};
+
+enum {
+ kHS45UfoExitLeft = 1,
+ kHS45UfoExitRight = 2,
+ kHS45UfoDevice = 3
+};
+
+enum {
+ kHS46Platypus = 0,
+ kHS46ExitUfoParty = 1,
+ kHS46ExitKissinBooth = 2,
+ kHS46ExitDisco = 3,
+ kHS46SackGuy = 4,
+ kHS46ItchyGuy = 5,
+ kHS46Device = 6,
+ kHS46WalkArea1 = 7
+};
+
+enum {
+ kHS46UfoExitLeft = 1,
+ kHS46UfoExitRight = 2,
+ kHS46UfoDevice = 3
+};
+
+enum {
+ kAS41LeaveScene = 0,
+ kAS41UseQuarterWithToyVendor = 1,
+ kAS41TalkToyVendor = 2,
+ kAS41UseGumWithToyUfo = 3,
+ kAS41UseChickenBucketWithKid = 4,
+ kAS41GrabKid = 5,
+ kAS41GiveBackToyUfo = 6,
+ kAS41ToyUfoLeaveScene = 7,
+ kAS41ToyUfoRefresh = 8,
+ kAS41UfoGumAttached = 9
+};
+
+enum {
+ kAS42LeaveScene = 0,
+ kAS42TalkBBQVendor = 1,
+ kAS42UseQuarterWithBBQVendor = 2,
+ kAS42UseQuarterWithBBQVendorDone = 3,
+ kAS42GrabChickenLeg = 4,
+ kAS42ToyUfoLeaveScene = 5,
+ kAS42ToyUfoRefresh = 6,
+ kAS42ToyUfoPickUpHotSauce = 7
+};
+
+/*****************************************************************************/
+
+class GnapEngine;
+class CutScene;
+
+class Scene40: public Scene {
+public:
+ Scene40(GnapEngine *vm);
+ virtual ~Scene40() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+};
+
+class Scene41: public Scene {
+public:
+ Scene41(GnapEngine *vm);
+ virtual ~Scene41() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _currKidSequenceId;
+ int _nextKidSequenceId;
+ int _currToyVendorSequenceId;
+ int _nextToyVendorSequenceId;
+};
+
+class Scene42: public Scene {
+public:
+ Scene42(GnapEngine *vm);
+ virtual ~Scene42() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _currBBQVendorSequenceId;
+ int _nextBBQVendorSequenceId;
+};
+
+class Scene43: public Scene {
+public:
+ Scene43(GnapEngine *vm);
+ virtual ~Scene43() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _currTwoHeadedGuySequenceId;
+ int _nextTwoHeadedGuySequenceId;
+};
+
+class Scene44: public Scene {
+public:
+ Scene44(GnapEngine *vm);
+ virtual ~Scene44() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _nextSpringGuySequenceId;
+ int _nextKissingLadySequenceId;
+ int _currSpringGuySequenceId;
+ int _currKissingLadySequenceId;
+};
+
+class Scene45: public Scene {
+public:
+ Scene45(GnapEngine *vm);
+ virtual ~Scene45() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _currDancerSequenceId;
+};
+
+class Scene46: public Scene {
+public:
+ Scene46(GnapEngine *vm);
+ virtual ~Scene46() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _currSackGuySequenceId;
+ int _nextItchyGuySequenceId;
+ int _nextSackGuySequenceId;
+ int _currItchyGuySequenceId;
+};
+
+} // End of namespace Gnap
+
+#endif // GNAP_GROUP4_H
diff --git a/engines/gnap/scenes/group5.cpp b/engines/gnap/scenes/group5.cpp
new file mode 100644
index 0000000000..46f4c51e5d
--- /dev/null
+++ b/engines/gnap/scenes/group5.cpp
@@ -0,0 +1,381 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 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 "gnap/gnap.h"
+#include "gnap/gamesys.h"
+#include "gnap/resource.h"
+#include "gnap/scenes/group5.h"
+
+namespace Gnap {
+
+Scene53::Scene53(GnapEngine *vm) : Scene(vm) {
+ _isGnapPhoning = false;
+ _currHandSequenceId = -1;
+ _callsMadeCtr = 0;
+ _callsRndUsed = 0;
+}
+
+int Scene53::init() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ gameSys.setAnimation(0, 0, 0);
+ gameSys.setAnimation(0, 0, 1);
+ return 0x75;
+}
+
+void Scene53::updateHotspots() {
+ _vm->setHotspot(kHS53Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS53PhoneKey1, 336, 238, 361, 270, SF_GRAB_CURSOR);
+ _vm->setHotspot(kHS53PhoneKey2, 376, 243, 405, 274, SF_GRAB_CURSOR);
+ _vm->setHotspot(kHS53PhoneKey3, 415, 248, 441, 276, SF_GRAB_CURSOR);
+ _vm->setHotspot(kHS53PhoneKey4, 329, 276, 358, 303, SF_GRAB_CURSOR);
+ _vm->setHotspot(kHS53PhoneKey5, 378, 282, 408, 311, SF_GRAB_CURSOR);
+ _vm->setHotspot(kHS53PhoneKey6, 417, 286, 446, 319, SF_GRAB_CURSOR);
+ _vm->setHotspot(kHS53PhoneKey7, 332, 311, 361, 342, SF_GRAB_CURSOR);
+ _vm->setHotspot(kHS53PhoneKey8, 376, 318, 407, 349, SF_GRAB_CURSOR);
+ _vm->setHotspot(kHS53PhoneKey9, 417, 320, 447, 353, SF_GRAB_CURSOR);
+ _vm->setHotspot(kHS53PhoneKey0, 377, 352, 405, 384, SF_GRAB_CURSOR);
+ _vm->setHotspot(kHS53PhoneKeySharp, 419, 358, 450, 394, SF_GRAB_CURSOR);
+ _vm->setHotspot(kHS53PhoneKeyStar, 328, 346, 359, 379, SF_GRAB_CURSOR);
+ _vm->setHotspot(kHS53PhoneExit, 150, 585, 650, 600, SF_EXIT_D_CURSOR);
+
+ _vm->setDeviceHotspot(kHS53Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 15;
+}
+
+int Scene53::pressPhoneNumberButton(int phoneNumber, int buttonNum) {
+ static const int kGnapHandSequenceIds[13] = {
+ 0x00,
+ 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B,
+ 0x4C, 0x4D, 0x4E, 0x50, 0x51, 0x4F
+ };
+
+ static const int kPlatypusHandSequenceIds[13] = {
+ 0x00,
+ 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+ 0x58, 0x59, 0x5A, 0x5C, 0x5D, 0x5B
+ };
+
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (_isGnapPhoning) {
+ gameSys.setAnimation(kGnapHandSequenceIds[buttonNum], 40, 6);
+ gameSys.insertSequence(kGnapHandSequenceIds[buttonNum], 40, _currHandSequenceId, 40, kSeqSyncWait, 0, 0, 0);
+ _currHandSequenceId = kGnapHandSequenceIds[buttonNum];
+ } else {
+ gameSys.setAnimation(kPlatypusHandSequenceIds[buttonNum], 40, 6);
+ gameSys.insertSequence(kPlatypusHandSequenceIds[buttonNum], 40, _currHandSequenceId, 40, kSeqSyncWait, 0, 0, 0);
+ _currHandSequenceId = kPlatypusHandSequenceIds[buttonNum];
+ }
+
+ gnap._actionStatus = 6;
+ while (gameSys.getAnimationStatus(6) != 2 && !_vm->_gameDone) {
+ _vm->updateMouseCursor();
+ _vm->gameUpdateTick();
+ }
+ gnap._actionStatus = -1;
+
+ if (buttonNum < 11)
+ phoneNumber = buttonNum % 10 + 10 * phoneNumber;
+
+ return phoneNumber;
+}
+
+int Scene53::getRandomCallIndex() {
+ int index, tries = 0;
+ if (_callsRndUsed == 0x7FFF)
+ _callsRndUsed = 0;
+ do {
+ index = _vm->getRandom(16);
+ if (++tries == 300)
+ _callsRndUsed = 0;
+ } while (_callsRndUsed & (1 << index));
+ _callsRndUsed |= (1 << index);
+ return index;
+}
+
+void Scene53::runRandomCall() {
+ static const int kCallSequenceIds[15] = {
+ 0x60, 0x61, 0x62, 0x63, 0x64,
+ 0x65, 0x66, 0x67, 0x68, 0x69,
+ 0x6A, 0x6B, 0x6C, 0x6D, 0x71
+ };
+
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ ++_callsMadeCtr;
+ if (_callsMadeCtr <= 10) {
+ int index;
+
+ do {
+ index = getRandomCallIndex();
+ } while (!_isGnapPhoning && (index == 0 || index == 3 || index == 4 || index == 11));
+ gameSys.setAnimation(kCallSequenceIds[index], 1, 6);
+ gameSys.insertSequence(kCallSequenceIds[index], 1, 0, 0, kSeqNone, 16, 0, 0);
+ } else {
+ gameSys.setAnimation(0x74, 1, 6);
+ gameSys.insertSequence(0x74, 1, 0, 0, kSeqNone, 16, 0, 0);
+ _callsMadeCtr = 0;
+ }
+
+ gnap._actionStatus = 1;
+ while (gameSys.getAnimationStatus(6) != 2 && !_vm->_gameDone) {
+ _vm->updateMouseCursor();
+ _vm->gameUpdateTick();
+ }
+ gnap._actionStatus = -1;
+}
+
+void Scene53::runChitChatLine() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ bool flag = false;
+ int sequenceId = -1;
+
+ gameSys.setAnimation(0x6E, 1, 6);
+ gameSys.insertSequence(0x6E, 1, 0, 0, kSeqNone, 16, 0, 0);
+
+ gnap._actionStatus = 1;
+ while (gameSys.getAnimationStatus(6) != 2 && !_vm->_gameDone) {
+ _vm->updateMouseCursor();
+ _vm->gameUpdateTick();
+ }
+ gnap._actionStatus = -1;
+
+ if (_vm->isFlag(kGFSpringTaken)) {
+ gameSys.insertSequence(0x45, 40, _currHandSequenceId, 40, kSeqSyncWait, 0, 0, 0);
+ _currHandSequenceId = 0x45;
+ } else {
+ gameSys.insertSequence(0x45, 40, _currHandSequenceId, 40, kSeqSyncWait, 0, 0, 0);
+ _currHandSequenceId = 0x5E;
+ }
+
+ _vm->_hotspots[kHS53Device]._flags = SF_DISABLED;
+
+ while (!flag) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->testWalk(0, 0, -1, -1, -1, -1);
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case 2:
+ sequenceId = 0x6F;
+ flag = 1;
+ break;
+ case 3:
+ sequenceId = 0x70;
+ flag = 1;
+ break;
+ case 4:
+ sequenceId = 0x71;
+ flag = 1;
+ break;
+ case 14:
+ sequenceId = -1;
+ flag = 1;
+ _vm->_isLeavingScene = true;
+ _vm->_sceneDone = true;
+ gnap._actionStatus = 0;
+ _vm->_newSceneNum = 17;
+ break;
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ pressPhoneNumberButton(0, _vm->_sceneClickedHotspot - 1);
+ break;
+ }
+
+ if (flag && sequenceId != -1) {
+ _vm->stopSound(0xA0);
+ pressPhoneNumberButton(0, _vm->_sceneClickedHotspot - 1);
+ gnap._actionStatus = 1;
+ gameSys.setAnimation(sequenceId, 1, 6);
+ gameSys.insertSequence(sequenceId, 1, 0, 0, kSeqNone, 16, 0, 0);
+ gnap._actionStatus = 1;
+ while (gameSys.getAnimationStatus(6) != 2 && !_vm->_gameDone) {
+ _vm->updateMouseCursor();
+ _vm->gameUpdateTick();
+ }
+ gnap._actionStatus = -1;
+ gameSys.setAnimation(0x72, 1, 6);
+ gameSys.insertSequence(0x72, 1, 0, 0, kSeqNone, 16, 0, 0);
+ gnap._actionStatus = 1;
+ while (gameSys.getAnimationStatus(6) != 2 && !_vm->_gameDone) {
+ _vm->updateMouseCursor();
+ _vm->gameUpdateTick();
+ }
+ gnap._actionStatus = -1;
+ }
+ }
+
+ updateHotspots();
+
+ gnap._actionStatus = 1;
+
+ if (_vm->isFlag(kGFSpringTaken)) {
+ gameSys.setAnimation(0x73, 40, 6);
+ gameSys.insertSequence(0x73, 40, _currHandSequenceId, 40, kSeqSyncWait, 0, 0, 0);
+ while (gameSys.getAnimationStatus(6) != 2 && !_vm->_gameDone) {
+ _vm->updateMouseCursor();
+ _vm->gameUpdateTick();
+ }
+ _currHandSequenceId = 0x73;
+ gnap._actionStatus = -1;
+ }
+}
+
+void Scene53::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ int phoneNumber = 0;
+ int phoneNumberLen = 0;
+
+ _vm->queueInsertDeviceIcon();
+
+ if (_vm->isFlag(kGFSpringTaken)) {
+ _currHandSequenceId = 0x45;
+ _isGnapPhoning = true;
+ } else {
+ _currHandSequenceId = 0x5E;
+ _isGnapPhoning = false;
+ }
+
+ gameSys.insertSequence(_currHandSequenceId, 40, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->endSceneInit();
+ _vm->setVerbCursor(GRAB_CURSOR);
+ _vm->playSound(0xA0, true);
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->testWalk(0, 0, -1, -1, -1, -1);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS53Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+ case kHS53PhoneKey1:
+ case kHS53PhoneKey2:
+ case kHS53PhoneKey3:
+ case kHS53PhoneKey4:
+ case kHS53PhoneKey5:
+ case kHS53PhoneKey6:
+ case kHS53PhoneKey7:
+ case kHS53PhoneKey8:
+ case kHS53PhoneKey9:
+ case kHS53PhoneKey0:
+ _vm->stopSound(0xA0);
+ ++phoneNumberLen;
+ phoneNumber = pressPhoneNumberButton(phoneNumber, _vm->_sceneClickedHotspot - 1);
+ debugC(kDebugBasic, "phoneNumber: %d", phoneNumber);
+ if (phoneNumberLen == 7) {
+ gnap._actionStatus = 1;
+ if (_vm->isFlag(kGFSpringTaken)) {
+ gameSys.setAnimation(0x73, 40, 6);
+ gameSys.insertSequence(0x73, 40, _currHandSequenceId, 40, kSeqSyncWait, 0, 0, 0);
+ while (gameSys.getAnimationStatus(6) != 2 && !_vm->_gameDone) {
+ _vm->updateMouseCursor();
+ _vm->gameUpdateTick();
+ }
+ _currHandSequenceId = 0x73;
+ gnap._actionStatus = -1;
+ }
+ if (phoneNumber == 7284141) {
+ runChitChatLine();
+ phoneNumber = 0;
+ phoneNumberLen = 0;
+ _vm->_sceneDone = true;
+ _vm->_newSceneNum = 17;
+ } else if (phoneNumber != 5556789 || _vm->isFlag(kGFPictureTaken)) {
+ runRandomCall();
+ phoneNumber = 0;
+ phoneNumberLen = 0;
+ _vm->_sceneDone = true;
+ _vm->_newSceneNum = 17;
+ } else {
+ phoneNumber = 0;
+ phoneNumberLen = 0;
+ _vm->_sceneDone = true;
+ _vm->_newSceneNum = 17;
+ if (_isGnapPhoning)
+ _vm->setFlag(kGFUnk25);
+ else
+ _vm->setFlag(kGFPlatypusTalkingToAssistant);
+ }
+ }
+ break;
+ case kHS53PhoneKeySharp:
+ case kHS53PhoneKeyStar:
+ pressPhoneNumberButton(0, _vm->_sceneClickedHotspot - 1);
+ break;
+ case kHS53PhoneExit:
+ if (gnap._actionStatus < 0) {
+ gnap._actionStatus = 1;
+ if (_vm->isFlag(kGFSpringTaken)) {
+ gameSys.setAnimation(0x73, 40, 6);
+ gameSys.insertSequence(0x73, 40, _currHandSequenceId, 40, kSeqSyncWait, 0, 0, 0);
+ while (gameSys.getAnimationStatus(6) != 2 && !_vm->_gameDone) {
+ _vm->updateMouseCursor();
+ _vm->gameUpdateTick();
+ }
+ _currHandSequenceId = 0x73;
+ gnap._actionStatus = -1;
+ }
+ _vm->_isLeavingScene = true;
+ _vm->_sceneDone = true;
+ gnap._actionStatus = 0;
+ _vm->_newSceneNum = 17;
+ }
+ break;
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+ _vm->gameUpdateTick();
+ }
+}
+
+} // End of namespace Gnap
diff --git a/engines/gnap/scenes/group5.h b/engines/gnap/scenes/group5.h
new file mode 100644
index 0000000000..dd238ec65c
--- /dev/null
+++ b/engines/gnap/scenes/group5.h
@@ -0,0 +1,77 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 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 GNAP_GROUP5_H
+#define GNAP_GROUP5_H
+
+#include "gnap/debugger.h"
+#include "gnap/scenes/scenecore.h"
+
+namespace Gnap {
+
+enum {
+ kHS53Platypus = 0,
+ kHS53Device = 1,
+ kHS53PhoneKey1 = 2,
+ kHS53PhoneKey2 = 3,
+ kHS53PhoneKey3 = 4,
+ kHS53PhoneKey4 = 5,
+ kHS53PhoneKey5 = 6,
+ kHS53PhoneKey6 = 7,
+ kHS53PhoneKey7 = 8,
+ kHS53PhoneKey8 = 9,
+ kHS53PhoneKey9 = 10,
+ kHS53PhoneKey0 = 11,
+ kHS53PhoneKeySharp = 12,
+ kHS53PhoneKeyStar = 13,
+ kHS53PhoneExit = 14
+};
+
+/*****************************************************************************/
+
+class GnapEngine;
+
+class Scene53: public Scene {
+public:
+ Scene53(GnapEngine *vm);
+ virtual ~Scene53() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations() {};
+ virtual void updateAnimationsCb() {};
+
+private:
+ bool _isGnapPhoning;
+ int _currHandSequenceId;
+ int _callsMadeCtr;
+ uint _callsRndUsed;
+
+ int pressPhoneNumberButton(int phoneNumber, int buttonNum);
+ int getRandomCallIndex();
+ void runRandomCall();
+ void runChitChatLine();
+};
+
+} // End of namespace Gnap
+#endif // GNAP_GROUP5_H
diff --git a/engines/gnap/scenes/groupcs.cpp b/engines/gnap/scenes/groupcs.cpp
new file mode 100644
index 0000000000..c096eae27c
--- /dev/null
+++ b/engines/gnap/scenes/groupcs.cpp
@@ -0,0 +1,430 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can 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 "gnap/gnap.h"
+#include "gnap/gamesys.h"
+#include "gnap/resource.h"
+#include "gnap/scenes/groupcs.h"
+
+
+namespace Gnap {
+
+Scene16::Scene16(GnapEngine *vm) : CutScene(vm) {}
+
+int Scene16::init() {
+ _sequenceIdArr[0] = 0x1F2;
+ _sequenceIdArr[1] = 0x201;
+ _sequenceIdArr[2] = 0x1FC;
+ _sequenceIdArr[3] = 0x1F4;
+ _sequenceIdArr[4] = 0x1FB;
+ _sequenceIdArr[5] = 0x1F0;
+ _sequenceIdArr[6] = 0x1FD;
+ _sequenceIdArr[7] = 0x1FE;
+ _sequenceIdArr[8] = 0x1F7;
+ _sequenceIdArr[9] = 0x1F9;
+ _sequenceIdArr[10] = 0x1F8;
+ _sequenceIdArr[11] = 0x1F1;
+ _sequenceIdArr[12] = 0x202;
+ _sequenceIdArr[13] = 0x1F6;
+ _sequenceIdArr[14] = 0x1F3;
+ _sequenceIdArr[15] = 0x1FA;
+ _sequenceIdArr[16] = 0x1FF;
+ _sequenceIdArr[17] = 0x200;
+ _sequenceIdArr[18] = 0x203;
+ _sequenceIdArr[19] = 0x206;
+ _sequenceIdArr[20] = 0x207;
+ _sequenceIdArr[21] = 0x204;
+ _sequenceIdArr[22] = 0x205;
+ _resourceIdArr[0] = 0x1C;
+ _resourceIdArr[1] = 2;
+ _resourceIdArr[2] = 0x1B;
+ _resourceIdArr[3] = 0;
+ _resourceIdArr[4] = 0x167;
+ _resourceIdArr[5] = 1;
+ _resourceIdArr[6] = 0x15B;
+ _resourceIdArr[7] = 0x15A;
+ _resourceIdArr[8] = 0x170;
+ _resourceIdArr[9] = 0x1EB;
+ _resourceIdArr[10] = 0x1EC;
+ _resourceIdArr[11] = 0x1BE;
+ _resourceIdArr[12] = 0x1BF;
+ _sequenceCountArr[0] = 4;
+ _sequenceCountArr[1] = 1;
+ _sequenceCountArr[2] = 1;
+ _sequenceCountArr[3] = 6;
+ _sequenceCountArr[4] = 1;
+ _sequenceCountArr[5] = 3;
+ _sequenceCountArr[6] = 1;
+ _sequenceCountArr[7] = 1;
+ _sequenceCountArr[8] = 1;
+ _sequenceCountArr[9] = 1;
+ _sequenceCountArr[10] = 1;
+ _sequenceCountArr[11] = 1;
+ _sequenceCountArr[12] = 1;
+ _itemsCount = 13;
+
+ return -1;
+}
+
+/*****************************************************************************/
+
+Scene471::Scene471(GnapEngine *vm) : CutScene(vm) {}
+
+int Scene471::init() {
+ _sequenceIdArr[0] = 0x301;
+ _sequenceIdArr[1] = 0x305;
+ _sequenceIdArr[2] = 0x302;
+ _sequenceIdArr[3] = 0x304;
+ _sequenceIdArr[4] = 0x300;
+ _resourceIdArr[0] = 3;
+ _resourceIdArr[1] = 0;
+ _resourceIdArr[2] = 1;
+ _resourceIdArr[3] = 0;
+ _resourceIdArr[4] = 2;
+ _sequenceCountArr[0] = 1;
+ _sequenceCountArr[1] = 1;
+ _sequenceCountArr[2] = 1;
+ _sequenceCountArr[3] = 1;
+ _sequenceCountArr[4] = 1;
+ _canSkip[0] = false;
+ _canSkip[1] = false;
+ _canSkip[2] = false;
+ _canSkip[3] = false;
+ _canSkip[4] = false;
+ _itemsCount = 5;
+
+ return -1;
+}
+
+Scene472::Scene472(GnapEngine *vm) : CutScene(vm) {}
+
+int Scene472::init() {
+ _sequenceIdArr[0] = 0x306;
+ _sequenceIdArr[1] = 0x309;
+ _sequenceIdArr[2] = 0x307;
+ _sequenceIdArr[3] = 0x308;
+ _sequenceIdArr[4] = 0x30A;
+ _resourceIdArr[0] = 0x8E;
+ _resourceIdArr[1] = 0x90;
+ _resourceIdArr[2] = 0x8F;
+ _resourceIdArr[3] = 0x91;
+ _sequenceCountArr[0] = 2;
+ _sequenceCountArr[1] = 1;
+ _sequenceCountArr[2] = 1;
+ _sequenceCountArr[3] = 1;
+ _canSkip[0] = false;
+ _canSkip[1] = false;
+ _canSkip[2] = false;
+ _canSkip[3] = false;
+ _itemsCount = 4;
+
+ return -1;
+}
+
+Scene473::Scene473(GnapEngine *vm) : CutScene(vm) {}
+
+int Scene473::init() {
+ _sequenceIdArr[0] = 0x320;
+ _sequenceIdArr[1] = 0x321;
+ _resourceIdArr[0] = 0x142;
+ _resourceIdArr[1] = 0x143;
+ _sequenceCountArr[0] = 1;
+ _sequenceCountArr[1] = 1;
+ _canSkip[0] = false;
+ _canSkip[1] = false;
+ _itemsCount = 2;
+
+ return -1;
+}
+
+Scene474::Scene474(GnapEngine *vm) : CutScene(vm) {}
+
+int Scene474::init() {
+ _sequenceIdArr[0] = 0x30C;
+ _sequenceIdArr[1] = 0x30D;
+ _sequenceIdArr[2] = 0x30B;
+ _resourceIdArr[0] = 0x142;
+ _resourceIdArr[1] = 0x141;
+ _resourceIdArr[2] = 0x177;
+ _sequenceCountArr[0] = 1;
+ _sequenceCountArr[1] = 1;
+ _sequenceCountArr[2] = 1;
+ _canSkip[0] = false;
+ _canSkip[1] = false;
+ _canSkip[2] = false;
+ _itemsCount = 3;
+
+ return -1;
+}
+
+Scene475::Scene475(GnapEngine *vm) : CutScene(vm) {}
+
+int Scene475::init() {
+ _sequenceIdArr[0] = 0x30E;
+ _sequenceIdArr[1] = 0x30F;
+ _sequenceIdArr[2] = 0x310;
+ _sequenceIdArr[3] = 0x311;
+ _resourceIdArr[0] = 0x206;
+ _resourceIdArr[1] = 0x207;
+ _sequenceCountArr[0] = 3;
+ _sequenceCountArr[1] = 1;
+ _canSkip[0] = false;
+ _canSkip[1] = false;
+ _itemsCount = 2;
+
+ return -1;
+}
+
+Scene476::Scene476(GnapEngine *vm) : CutScene(vm) {}
+
+int Scene476::init() {
+ _sequenceIdArr[0] = 0x31E;
+ _sequenceIdArr[1] = 0x31F;
+ _resourceIdArr[0] = 0x2FA;
+ _sequenceCountArr[0] = 2;
+ _canSkip[0] = false;
+ _itemsCount = 1;
+
+ return -1;
+}
+
+Scene477::Scene477(GnapEngine *vm) : CutScene(vm) {}
+
+int Scene477::init() {
+ int v0, v4, v2, v3;
+
+ _sequenceIdArr[0] = 0x316;
+ _sequenceIdArr[1] = 0x31A;
+ _sequenceIdArr[2] = 0x314;
+ _sequenceIdArr[3] = 0x31B;
+ int v1 = 4;
+ if (!_vm->isFlag(kGFTwigTaken)) {
+ _sequenceIdArr[4] = 0x31C;
+ v1 = 5;
+ }
+ if (!_vm->isFlag(kGFPlatypusTalkingToAssistant))
+ _sequenceIdArr[v1++] = 0x31D;
+ v4 = v1;
+ _sequenceIdArr[v1] = 0x319;
+ v0 = v1 + 1;
+ v3 = v0;
+ _sequenceIdArr[v0++] = 0x317;
+ _sequenceIdArr[v0++] = 0x312;
+ _sequenceIdArr[v0] = 0x31A;
+ v2 = v0 + 1;
+ if (!_vm->isFlag(kGFTwigTaken))
+ _sequenceIdArr[v2++] = 0x31C;
+ if (!_vm->isFlag(kGFPlatypusTalkingToAssistant))
+ _sequenceIdArr[v2++] = 0x31D;
+ _sequenceIdArr[v2] = 0x313;
+ _sequenceIdArr[v2 + 1] = 0x315;
+ _resourceIdArr[0] = 0x2B8;
+ _resourceIdArr[1] = 0x20C;
+ _resourceIdArr[2] = 0x2B8;
+ _resourceIdArr[3] = 0x20B;
+ _resourceIdArr[4] = 0x20B;
+ _sequenceCountArr[0] = v4;
+ _sequenceCountArr[1] = 1;
+ _sequenceCountArr[2] = v2 - v3;
+ _sequenceCountArr[3] = 1;
+ _sequenceCountArr[4] = 1;
+ _canSkip[0] = false;
+ _canSkip[1] = false;
+ _canSkip[2] = false;
+ _canSkip[3] = false;
+ _canSkip[4] = false;
+ _itemsCount = 5;
+
+ return -1;
+}
+
+/*****************************************************************************/
+
+Scene48::Scene48(GnapEngine *vm) : CutScene(vm) {}
+
+int Scene48::init() {
+ _sequenceIdArr[0] = 390;
+ _sequenceIdArr[1] = 391;
+ _sequenceIdArr[2] = 392;
+ _sequenceIdArr[3] = 393;
+ _sequenceIdArr[4] = 394;
+ _sequenceIdArr[5] = 395;
+ _sequenceIdArr[6] = 396;
+ _sequenceIdArr[7] = 397;
+ _sequenceIdArr[8] = 398;
+ _sequenceIdArr[9] = 399;
+ _sequenceIdArr[10] = 400;
+ _sequenceIdArr[11] = 401;
+ _sequenceIdArr[12] = 402;
+ _resourceIdArr[0] = 238;
+ _resourceIdArr[1] = 42;
+ _resourceIdArr[2] = 2;
+ _resourceIdArr[3] = 37;
+ _resourceIdArr[4] = 35;
+ _resourceIdArr[5] = 38;
+ _resourceIdArr[6] = 39;
+ _resourceIdArr[7] = 40;
+ _resourceIdArr[8] = 41;
+ _resourceIdArr[9] = 36;
+ _resourceIdArr[10] = 41;
+ _resourceIdArr[11] = 388;
+ _resourceIdArr[12] = 387;
+ _sequenceCountArr[0] = 1;
+ _sequenceCountArr[1] = 1;
+ _sequenceCountArr[2] = 1;
+ _sequenceCountArr[3] = 1;
+ _sequenceCountArr[4] = 1;
+ _sequenceCountArr[5] = 1;
+ _sequenceCountArr[6] = 1;
+ _sequenceCountArr[7] = 1;
+ _sequenceCountArr[8] = 1;
+ _sequenceCountArr[9] = 1;
+ _sequenceCountArr[10] = 1;
+ _sequenceCountArr[11] = 1;
+ _sequenceCountArr[12] = 1;
+ _canSkip[0] = false;
+ _canSkip[1] = false;
+ _canSkip[2] = false;
+ _canSkip[3] = false;
+ _canSkip[4] = false;
+ _canSkip[5] = false;
+ _canSkip[6] = false;
+ _canSkip[7] = false;
+ _canSkip[8] = false;
+ _canSkip[9] = false;
+ _canSkip[10] = false;
+ _canSkip[11] = false;
+ _canSkip[12] = false;
+ _itemsCount = 13;
+
+ return -1;
+}
+
+/*****************************************************************************/
+
+Scene541::Scene541(GnapEngine *vm) : CutScene(vm) {}
+
+int Scene541::init() {
+ _sequenceIdArr[0] = 0x1BE;
+ _sequenceIdArr[1] = 0x1BF;
+ _sequenceIdArr[2] = 0x1BA;
+ _sequenceIdArr[3] = 0x1BB;
+ _sequenceIdArr[4] = 0x1BD;
+ _sequenceIdArr[5] = 0x1BC;
+ _resourceIdArr[0] = 0x3C;
+ _resourceIdArr[1] = 0x43;
+ _resourceIdArr[2] = 0x44;
+ if (_vm->isFlag(kGFPictureTaken))
+ _resourceIdArr[3] = 0x47;
+ else
+ _resourceIdArr[3] = 0x46;
+ _resourceIdArr[4] = 0x45;
+ _sequenceCountArr[0] = 1;
+ _sequenceCountArr[1] = 1;
+ _sequenceCountArr[2] = 1;
+ _sequenceCountArr[3] = 2;
+ _sequenceCountArr[4] = 1;
+ _canSkip[0] = false;
+ _canSkip[1] = false;
+ _canSkip[2] = false;
+ _canSkip[3] = false;
+ _canSkip[4] = false;
+ _itemsCount = 5;
+
+ return -1;
+}
+
+Scene542::Scene542(GnapEngine *vm) : CutScene(vm) {}
+
+int Scene542::init() {
+ _sequenceIdArr[0] = 0x1C9;
+ _sequenceIdArr[1] = 0x1C7;
+ _sequenceIdArr[2] = 0x1CC;
+ _sequenceIdArr[3] = 0x1C8;
+ _sequenceIdArr[4] = 0x1CB;
+ _sequenceIdArr[5] = 0x1C0;
+ _sequenceIdArr[6] = 0x1CA;
+ _sequenceIdArr[7] = 0x1CE;
+ _sequenceIdArr[8] = 0x1CD;
+ _sequenceIdArr[9] = 0x1C1;
+ _sequenceIdArr[10] = 0x1C2;
+ _sequenceIdArr[11] = 0x1C3;
+ _sequenceIdArr[12] = 0x1C4;
+ _sequenceIdArr[13] = 0x1C6;
+ _sequenceIdArr[14] = 0x1C5;
+ _sequenceIdArr[15] = 0x1D0;
+ _sequenceIdArr[16] = 0x1D0;
+ _sequenceIdArr[17] = 0x1D0;
+ _resourceIdArr[0] = 0xD5;
+ _resourceIdArr[1] = 0x14C;
+ _resourceIdArr[2] = 0xD5;
+ _resourceIdArr[3] = 0xBF;
+ _resourceIdArr[4] = 0xD6;
+ _resourceIdArr[5] = 0x154;
+ _resourceIdArr[6] = 0x155;
+ _resourceIdArr[7] = 0xB9;
+ _resourceIdArr[8] = 0xBA;
+ _resourceIdArr[9] = 0x17B;
+ _resourceIdArr[10] = 0x17A;
+ _resourceIdArr[11] = 0x17C;
+ _resourceIdArr[12] = 0x17A;
+ _resourceIdArr[13] = 0x1B7;
+ _resourceIdArr[14] = 0x1B8;
+ _resourceIdArr[15] = 0x1B9;
+ _sequenceCountArr[0] = 2;
+ _sequenceCountArr[1] = 1;
+ _sequenceCountArr[2] = 2;
+ _sequenceCountArr[3] = 1;
+ _sequenceCountArr[4] = 1;
+ _sequenceCountArr[5] = 1;
+ _sequenceCountArr[6] = 1;
+ _sequenceCountArr[7] = 1;
+ _sequenceCountArr[8] = 1;
+ _sequenceCountArr[9] = 1;
+ _sequenceCountArr[10] = 1;
+ _sequenceCountArr[11] = 1;
+ _sequenceCountArr[12] = 1;
+ _sequenceCountArr[13] = 1;
+ _sequenceCountArr[14] = 1;
+ _sequenceCountArr[15] = 1;
+ _canSkip[0] = false;
+ _canSkip[1] = false;
+ _canSkip[2] = false;
+ _canSkip[3] = false;
+ _canSkip[4] = false;
+ _canSkip[5] = false;
+ _canSkip[6] = false;
+ _canSkip[7] = false;
+ _canSkip[8] = false;
+ _canSkip[9] = false;
+ _canSkip[10] = false;
+ _canSkip[11] = false;
+ _canSkip[12] = false;
+ _canSkip[13] = true;
+ _canSkip[14] = true;
+ _canSkip[15] = false;
+ _itemsCount = 16;
+
+ return -1;
+}
+
+} // End of namespace Gnap
diff --git a/engines/gnap/scenes/groupcs.h b/engines/gnap/scenes/groupcs.h
new file mode 100644
index 0000000000..58033564ce
--- /dev/null
+++ b/engines/gnap/scenes/groupcs.h
@@ -0,0 +1,122 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can 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 GNAP_GROUPCS_H
+#define GNAP_GROUPCS_H
+
+#include "gnap/debugger.h"
+
+namespace Gnap {
+
+class GnapEngine;
+class CutScene;
+
+class Scene16: public CutScene {
+public:
+ Scene16(GnapEngine *vm);
+ virtual ~Scene16() {}
+
+ virtual int init();
+};
+
+class Scene471: public CutScene {
+public:
+ Scene471(GnapEngine *vm);
+ virtual ~Scene471() {}
+
+ virtual int init();
+};
+
+class Scene472: public CutScene {
+public:
+ Scene472(GnapEngine *vm);
+ virtual ~Scene472() {}
+
+ virtual int init();
+};
+
+class Scene473: public CutScene {
+public:
+ Scene473(GnapEngine *vm);
+ virtual ~Scene473() {}
+
+ virtual int init();
+};
+
+class Scene474: public CutScene {
+public:
+ Scene474(GnapEngine *vm);
+ virtual ~Scene474() {}
+
+ virtual int init();
+};
+
+class Scene475: public CutScene {
+public:
+ Scene475(GnapEngine *vm);
+ virtual ~Scene475() {}
+
+ virtual int init();
+};
+
+class Scene476: public CutScene {
+public:
+ Scene476(GnapEngine *vm);
+ virtual ~Scene476() {}
+
+ virtual int init();
+};
+
+class Scene477: public CutScene {
+public:
+ Scene477(GnapEngine *vm);
+ virtual ~Scene477() {}
+
+ virtual int init();
+};
+
+class Scene48: public CutScene {
+public:
+ Scene48(GnapEngine *vm);
+ virtual ~Scene48() {}
+
+ virtual int init();
+};
+
+class Scene541: public CutScene {
+public:
+ Scene541(GnapEngine *vm);
+ virtual ~Scene541() {}
+
+ virtual int init();
+};
+
+class Scene542: public CutScene {
+public:
+ Scene542(GnapEngine *vm);
+ virtual ~Scene542() {}
+
+ virtual int init();
+};
+} // End of namespace Gnap
+
+#endif // GNAP_GROUPCS_H
diff --git a/engines/gnap/scenes/intro.cpp b/engines/gnap/scenes/intro.cpp
new file mode 100644
index 0000000000..b4ba2f5201
--- /dev/null
+++ b/engines/gnap/scenes/intro.cpp
@@ -0,0 +1,182 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can 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 "video/avi_decoder.h"
+
+#include "gnap/gnap.h"
+#include "gnap/gamesys.h"
+#include "gnap/resource.h"
+#include "gnap/scenes/intro.h"
+
+namespace Gnap {
+
+SceneIntro::SceneIntro(GnapEngine *vm) : Scene(vm) {
+}
+
+int SceneIntro::init() {
+ return 0x37C;
+}
+
+void SceneIntro::run() {
+ const int animIdArr[] = {
+ 0x356, 0x357, 0x358, 0x35A, 0x35F,
+ 0x360, 0x361, 0x362, 0x363, 0x364,
+ 0x365, 0x368, 0x369, 0x36B, 0x378,
+ 0x36C, 0x36D, 0x36E, 0x36F, 0x370,
+ 0x371, 0x372, 0x373, 0x374, 0x375,
+ 0x376, 0x377, 0x378, 0x379, 0x37A,
+ 0x37B, 0};
+
+ const int backgroundIdArr[] = {
+ 0x354, 0x355, 0, 1, 3,
+ 4, 5, 6, 7, 8,
+ 7, 9, 0xA, 0xB, 0xC,
+ 0xD, 0xE, 0xF, 0x10, 0x11,
+ 0x12, 0x13, 0x17, 0x14, 0x19,
+ 0x1A, 0x14, 0x15, 0x16, 0x14,
+ 0x19, 0};
+
+ GameSys& gameSys = *_vm->_gameSys;
+ int index = 0;
+ bool skip = false;
+
+ _vm->hideCursor();
+ _vm->_dat->open(1, "musop_n.dat");
+
+ Video::VideoDecoder *videoDecoder = new Video::AVIDecoder();
+ if (!videoDecoder->loadFile("hoffman.avi")) {
+ delete videoDecoder;
+ warning("Unable to open video 'hoffman.avi' - Skipping intro");
+ return;
+ }
+ videoDecoder->start();
+
+ int vidPosX = (800 - videoDecoder->getWidth()) / 2;
+ int vidPosY = (600 - videoDecoder->getHeight()) / 2;
+ bool skipVideo = false;
+
+ _vm->screenEffect(1, 255, 255, 255);
+
+ while (!_vm->shouldQuit() && !videoDecoder->endOfVideo() && !skipVideo) {
+ if (videoDecoder->needsUpdate()) {
+ const Graphics::Surface *frame = videoDecoder->decodeNextFrame();
+ if (frame) {
+ if (frame->format.bytesPerPixel == 1) {
+ _vm->_system->copyRectToScreen(frame->getPixels(), frame->pitch, vidPosX, vidPosY, frame->w, frame->h);
+ } else if (frame->format.bytesPerPixel != 4) {
+ Graphics::Surface *frame1 = frame->convertTo(_vm->_system->getScreenFormat());
+ _vm->_system->copyRectToScreen(frame1->getPixels(), frame1->pitch, vidPosX, vidPosY, frame1->w, frame1->h);
+ frame1->free();
+ delete frame1;
+ } else {
+ // The intro AVI is played upside down, it's the only video played in the English version
+ for (uint16 y = 0; y < frame->h / 2; y++) {
+ uint32 *ptrFrom = (uint32 *)frame->getBasePtr(0, y);
+ uint32 *ptrTo = (uint32 *)frame->getBasePtr(0, frame->h - y - 1);
+ for (uint16 x = 0; x < frame->w; x++) {
+ uint32 t = *ptrFrom;
+ *ptrFrom = *ptrTo;
+ *ptrTo = t;
+ ptrFrom++;
+ ptrTo++;
+ }
+ }
+
+ Graphics::Surface *frame1 = frame->convertTo(_vm->_system->getScreenFormat());
+ _vm->_system->copyRectToScreen(frame1->getPixels(), frame1->pitch, vidPosX, vidPosY, frame1->w, frame1->h);
+ frame1->free();
+ delete frame1;
+ }
+ _vm->_system->updateScreen();
+ }
+ }
+
+ Common::Event event;
+ while (g_system->getEventManager()->pollEvent(event)) {
+ if ((event.type == Common::EVENT_KEYDOWN && event.kbd.keycode == Common::KEYCODE_ESCAPE) ||
+ event.type == Common::EVENT_LBUTTONUP)
+ skipVideo = true;
+ }
+
+ _vm->_system->delayMillis(10);
+ }
+
+ delete videoDecoder;
+
+ gameSys.drawSpriteToBackground(0, 0, backgroundIdArr[index]);
+ gameSys.insertSequence(0x356, 2, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.setAnimation(0x356, 2, 0);
+
+ while (!_vm->_sceneDone) {
+ _vm->gameUpdateTick();
+
+ if (gameSys.getAnimationStatus(0) == 2 || skip ) {
+ skip = false;
+ gameSys.requestClear2(false);
+ gameSys.requestClear1();
+ if ( index == 11 || index == 1 )
+ _vm->screenEffect(0, 0, 0, 0);
+
+ gameSys.setAnimation(0, 0, 0);
+ if (++index >= 31)
+ _vm->_sceneDone = true;
+ else {
+ gameSys.insertSequence(animIdArr[index], 2, 0, 0, kSeqNone, 0, 0, 0);
+ if (index == 2) {
+ _vm->playSound(0x10000, false);
+ gameSys.insertSequence(0x359, 2, 0, 0, 0, 0, 0, 0);
+ } else if (index == 3)
+ gameSys.insertSequence(0x35B, 2, 0, 0, kSeqNone, 0, 0, 0);
+ else if (index == 12)
+ gameSys.insertSequence(0x36A, 2, 0, 0, kSeqNone, 0, 0, 0);
+
+ gameSys.drawSpriteToBackground(0, 0, backgroundIdArr[index]);
+ gameSys.setAnimation(animIdArr[index], 2, 0);
+
+ if (index == 11)
+ _vm->stopSound(0x10000);
+ }
+ }
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_ESCAPE) || _vm->isKeyStatus1(Common::KEYCODE_SPACE) || _vm->isKeyStatus1(Common::KEYCODE_RETURN)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_ESCAPE);
+ _vm->clearKeyStatus1(Common::KEYCODE_SPACE);
+ _vm->clearKeyStatus1(Common::KEYCODE_RETURN);
+ if (index == 0) {
+ skip = true;
+ _vm->stopSound(0x3CF);
+ } else if (index == 1)
+ skip = true;
+ else
+ _vm->_sceneDone = true;
+ }
+ }
+
+ _vm->stopSound(0x10000);
+
+ _vm->_newSceneNum = 1;
+ _vm->_newCursorValue = 1;
+
+ _vm->_dat->open(1, "stock_n.dat");
+}
+
+} // End of namespace Gnap
diff --git a/engines/gnap/scenes/intro.h b/engines/gnap/scenes/intro.h
new file mode 100644
index 0000000000..15aedfc4fc
--- /dev/null
+++ b/engines/gnap/scenes/intro.h
@@ -0,0 +1,47 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 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 GNAP_INTRO_H
+#define GNAP_INTRO_H
+
+#include "gnap/debugger.h"
+#include "gnap/scenes/scenecore.h"
+
+namespace Gnap {
+
+class GnapEngine;
+
+class SceneIntro: public Scene {
+public:
+ SceneIntro(GnapEngine *vm);
+ virtual ~SceneIntro() {}
+
+ virtual int init();
+ virtual void updateHotspots() {}
+ virtual void run();
+ virtual void updateAnimations() {}
+ virtual void updateAnimationsCb() {}
+};
+
+} // End of namespace Gnap
+
+#endif // GNAP_INTRO_H
diff --git a/engines/gnap/scenes/scenecore.cpp b/engines/gnap/scenes/scenecore.cpp
new file mode 100644
index 0000000000..fb6f91c954
--- /dev/null
+++ b/engines/gnap/scenes/scenecore.cpp
@@ -0,0 +1,740 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can 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 "gnap/gnap.h"
+#include "gnap/gamesys.h"
+#include "gnap/resource.h"
+
+#include "gnap/scenes/scenecore.h"
+
+#include "gnap/scenes/arcade.h"
+#include "gnap/scenes/groupcs.h"
+#include "gnap/scenes/group0.h"
+#include "gnap/scenes/group1.h"
+#include "gnap/scenes/group2.h"
+#include "gnap/scenes/group3.h"
+#include "gnap/scenes/group4.h"
+#include "gnap/scenes/group5.h"
+#include "gnap/scenes/intro.h"
+
+namespace Gnap {
+
+int GnapEngine::initSceneLogic() {
+ int backgroundId = -1;
+
+ switch (_currentSceneNum) {
+ case 0:
+ _scene = new SceneIntro(this);
+ backgroundId = _scene->init();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ break;
+ case 1:
+ _scene = new Scene01(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 2:
+ _scene = new Scene02(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 3:
+ _scene = new Scene03(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 4:
+ _scene = new Scene04(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 5:
+ _scene = new Scene05(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 6:
+ _scene = new Scene06(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 7:
+ _scene = new Scene07(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 8:
+ _scene = new Scene08(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 9:
+ _scene = new Scene09(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 10:
+ _scene = new Scene10(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 11:
+ _scene = new Scene11(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 12:
+ _scene = new Scene12(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 13:
+ _scene = new Scene13(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 14:
+ _scene = new Scene14(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ break;
+ case 15:
+ _scene = new Scene15(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ break;
+ case 16:
+ case 47:
+ case 48:
+ case 54:
+ backgroundId = -1;
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ break;
+ case 17:
+ _scene = new Scene17(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 18:
+ _scene = new Scene18(this);
+ backgroundId = _scene->init();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ _scene->updateHotspots();
+ break;
+ case 19:
+ _scene = new Scene19(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 20:
+ _scene = new Scene20(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 21:
+ _scene = new Scene21(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 22:
+ _scene = new Scene22(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 23:
+ _scene = new Scene23(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 24:
+ _scene = new Scene24(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 136, 11, 10);
+ break;
+ case 25:
+ _scene = new Scene25(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 26:
+ _scene = new Scene26(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 27:
+ _scene = new Scene27(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 28:
+ _scene = new Scene28(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 29:
+ _scene = new Scene29(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 30:
+ _scene = new Scene30(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 31:
+ _scene = new Scene31(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 32:
+ _scene = new Scene32(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 33:
+ _scene = new Scene33(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 34:
+ _scene = new Scene03(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 35:
+ _scene = new Scene05(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 36:
+ _scene = new Scene06(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 37:
+ _scene = new Scene04(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 38:
+ _scene = new Scene38(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 39:
+ _scene = new Scene39(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 40:
+ _scene = new Scene40(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 41:
+ _scene = new Scene41(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 42:
+ _scene = new Scene42(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 43:
+ _scene = new Scene43(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 44:
+ _scene = new Scene44(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 45:
+ _scene = new Scene45(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 46:
+ _scene = new Scene46(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 49:
+ _scene = new Scene49(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 50:
+ _scene = new Scene50(this);
+ backgroundId = _scene->init();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 51:
+ _scene = new Scene51(this);
+ backgroundId = _scene->init();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 52:
+ _scene = new Scene52(this);
+ backgroundId = _scene->init();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 53:
+ _scene = new Scene53(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ }
+
+ return backgroundId;
+}
+
+void GnapEngine::runSceneLogic() {
+ switch (_currentSceneNum) {
+ case 0:
+ _scene->run();
+ delete _scene;
+ if (_newSceneNum == 55)
+ _newSceneNum = 8;
+ break;
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ _scene->run();
+ delete _scene;
+ if (_newSceneNum == 55)
+ _newSceneNum = 4;
+ break;
+ case 7:
+ _scene->run();
+ delete _scene;
+ if (_newSceneNum == 55)
+ _newSceneNum = 8;
+ break;
+ case 8:
+ _scene->run();
+ delete _scene;
+ if (_newSceneNum == 55)
+ _newSceneNum = 9;
+ break;
+ case 9:
+ _scene->run();
+ delete _scene;
+ if (_newSceneNum == 55)
+ _newSceneNum = 10;
+ break;
+ case 10:
+ case 12:
+ case 13:
+ _scene->run();
+ delete _scene;
+ if (_newSceneNum == 55)
+ _newSceneNum = 11;
+ break;
+ case 11:
+ case 15:
+ _scene->run();
+ delete _scene;
+ if (_newSceneNum == 55)
+ _newSceneNum = 12;
+ break;
+ case 14:
+ _scene->run();
+ delete _scene;
+ if (_newSceneNum == 55)
+ _newSceneNum = 13;
+ break;
+ case 16:
+ _scene = new Scene16(this);
+ _scene->init();
+ _newSceneNum = 17;
+ _newCursorValue = 3;
+ _scene->run();
+ delete _scene;
+ break;
+ case 17:
+ case 18:
+ case 21:
+ case 22:
+ case 23:
+ case 24:
+ case 25:
+ case 26:
+ case 27:
+ case 28:
+ case 29:
+ case 30:
+ case 31:
+ _scene->run();
+ delete _scene;
+ if (_newSceneNum == 55)
+ _newSceneNum = 20;
+ break;
+ case 19:
+ _scene->run();
+ delete _scene;
+ if (_newSceneNum == 55)
+ _newSceneNum = 19;
+ break;
+ case 20:
+ _scene->run();
+ delete _scene;
+ if (_newSceneNum == 55)
+ _newSceneNum = 22;
+ break;
+ case 32:
+ case 33:
+ case 34:
+ case 35:
+ case 36:
+ case 37:
+ case 38:
+ case 39:
+ case 40:
+ case 41:
+ case 42:
+ case 43:
+ case 44:
+ case 45:
+ case 46:
+ _scene->run();
+ delete _scene;
+ if (_newSceneNum == 55)
+ _newSceneNum = 37;
+ break;
+ case 47:
+ if (_prevSceneNum == 49) {
+ _scene = new Scene471(this);
+ _scene->init();
+ _newSceneNum = 7;
+ _newCursorValue = 2;
+ } else if (_prevSceneNum == 13) {
+ _scene = new Scene472(this);
+ _scene->init();
+ _newSceneNum = 11;
+ } else if (!isFlag(kGFPlatypusDisguised) && _prevSceneNum == 2) {//CHECKME
+ if (isFlag(kGFUnk25)) {
+ _scene = new Scene473(this);
+ _scene->init();
+ _newSceneNum = 2;
+ } else {
+ _scene = new Scene474(this);
+ _scene->init();
+ _newSceneNum = 49;
+ }
+ } else if (_prevSceneNum == 21) {
+ _scene = new Scene475(this);
+ _scene->init();
+ _newSceneNum = 21;
+ setFlag(kGFTwigTaken);
+ setFlag(kGFKeysTaken);
+ } else if (_prevSceneNum == 30) {
+ _scene = new Scene476(this);
+ _scene->init();
+ _newSceneNum = 26;
+ } else if (isFlag(kGFPlatypusDisguised) && _cursorValue == 1) {
+ _scene = new Scene477(this);
+ _scene->init();
+ _newSceneNum = 4;
+ }
+ _scene->run();
+ delete _scene;
+ break;
+ case 48:
+ _scene = new Scene48(this);
+ _scene->init();
+ _newSceneNum = 33;
+ _newCursorValue = 4;
+ _scene->run();
+ delete _scene;
+ break;
+ case 49:
+ _scene->run();
+ delete _scene;
+ if (_newSceneNum == 55)
+ _newSceneNum = 47;
+ break;
+ case 50:
+ _scene->run();
+ delete _scene;
+ _newSceneNum = _prevSceneNum;
+ break;
+ case 51:
+ _scene->run();
+ delete _scene;
+ break;
+ case 52:
+ _scene->run();
+ delete _scene;
+ _newSceneNum = _prevSceneNum;
+ break;
+ case 53:
+ _scene->run();
+ delete _scene;
+ if (_newSceneNum == 55)
+ _newSceneNum = 53;
+ break;
+ case 54:
+ if (_prevSceneNum == 45) {
+ _scene = new Scene541(this);
+ _scene->init();
+ _newSceneNum = 43;
+ _scene->run();
+ delete _scene;
+ } else {
+ _scene = new Scene542(this);
+ _scene->init();
+ _scene->run();
+ delete _scene;
+ _gameDone = true;
+ }
+ break;
+ }
+}
+
+void Scene::playRandomSound(int timerIndex) {
+ if (!_vm->_timers[timerIndex]) {
+ _vm->_timers[timerIndex] = _vm->getRandom(40) + 50;
+ switch (_vm->getRandom(4)) {
+ case 0:
+ _vm->playSound(0x1091B, false);
+ break;
+ case 1:
+ _vm->playSound(0x10921, false);
+ break;
+ case 2:
+ _vm->playSound(0x10927, false);
+ break;
+ case 3:
+ _vm->playSound(0x1091D, false);
+ break;
+ }
+ }
+}
+
+bool Scene::clearKeyStatus() {
+ if (_vm->isKeyStatus1(Common::KEYCODE_ESCAPE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_ESCAPE);
+ _vm->clearKeyStatus1(Common::KEYCODE_UP);
+ _vm->clearKeyStatus1(Common::KEYCODE_RIGHT);
+ _vm->clearKeyStatus1(Common::KEYCODE_LEFT);
+ _vm->clearKeyStatus1(Common::KEYCODE_p);
+ return true;
+ }
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_p)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_p);
+ _vm->pauseGame();
+ _vm->updatePause();
+ }
+
+ return false;
+}
+
+/****************************************************************************/
+
+CutScene::CutScene(GnapEngine *vm) : Scene(vm) {
+ _itemsCount = -1;
+
+ for (int i = 0; i < 16; i++) {
+ _resourceIdArr[i] = -1;
+ _sequenceCountArr[i] = -1;
+ _canSkip[i] = false;
+ }
+
+ for (int i = 0; i < 50; i++)
+ _sequenceIdArr[i] = -1;
+}
+
+void CutScene::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ int itemIndex = 0;
+ int soundId = -1;
+ int volume = 100;
+ int duration = 0;
+ bool skip = false;
+
+ if (_vm->_prevSceneNum == 2) {
+ soundId = 0x36B;
+ duration = MAX(1, 300 / _vm->getSequenceTotalDuration(_sequenceIdArr[_itemsCount - 1]));
+ _vm->_timers[0] = 0;
+ }
+
+ if (soundId != -1)
+ _vm->playSound(soundId, false);
+
+ _vm->hideCursor();
+
+ gameSys.drawSpriteToBackground(0, 0, _resourceIdArr[0]);
+
+ for (int j = 0; j < _sequenceCountArr[0]; ++j)
+ gameSys.insertSequence(_sequenceIdArr[j], j + 2, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.setAnimation(_sequenceIdArr[0], 2, 0);
+
+ _vm->clearKeyStatus1(Common::KEYCODE_ESCAPE);
+ _vm->clearKeyStatus1(Common::KEYCODE_SPACE);
+ _vm->clearKeyStatus1(Common::KEYCODE_RETURN);
+
+ _vm->_mouseClickState._left = false;
+
+ int firstSequenceIndex = 0;
+ while (!_vm->_sceneDone) {
+ _vm->gameUpdateTick();
+
+ if (gameSys.getAnimationStatus(0) == 2 || skip) {
+ skip = false;
+ gameSys.requestClear2(false);
+ gameSys.requestClear1();
+ gameSys.setAnimation(0, 0, 0);
+ firstSequenceIndex += _sequenceCountArr[itemIndex++];
+ if (itemIndex >= _itemsCount) {
+ _vm->_sceneDone = true;
+ } else {
+ for (int m = 0; m < _sequenceCountArr[itemIndex]; ++m)
+ gameSys.insertSequence(_sequenceIdArr[firstSequenceIndex + m], m + 2, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.drawSpriteToBackground(0, 0, _resourceIdArr[itemIndex]);
+ gameSys.setAnimation(_sequenceIdArr[firstSequenceIndex], 2, 0);
+ }
+ }
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_ESCAPE) || _vm->isKeyStatus1(Common::KEYCODE_SPACE) || _vm->isKeyStatus1(Common::KEYCODE_RETURN)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_ESCAPE);
+ _vm->clearKeyStatus1(Common::KEYCODE_SPACE);
+ _vm->clearKeyStatus1(Common::KEYCODE_RETURN);
+ if (_canSkip[itemIndex])
+ skip = true;
+ else
+ _vm->_sceneDone = true;
+ }
+
+ if (!_vm->_timers[0] && itemIndex == _itemsCount - 1) {
+ _vm->_timers[0] = 2;
+ volume = MAX(1, volume - duration);
+ _vm->setSoundVolume(soundId, volume);
+ }
+ }
+
+ if (soundId != -1)
+ _vm->stopSound(soundId);
+}
+
+} // End of namespace Gnap
diff --git a/engines/gnap/scenes/scenecore.h b/engines/gnap/scenes/scenecore.h
new file mode 100644
index 0000000000..c54b5a7bc5
--- /dev/null
+++ b/engines/gnap/scenes/scenecore.h
@@ -0,0 +1,70 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 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 GNAP_SCENECORE_H
+#define GNAP_SCENECORE_H
+
+#include "gnap/debugger.h"
+
+namespace Gnap {
+
+class GnapEngine;
+
+class Scene {
+public:
+ Scene(GnapEngine *vm) : _vm(vm) {};
+ virtual ~Scene() {};
+
+ void playRandomSound(int timerIndex);
+ bool clearKeyStatus();
+
+ virtual int init() = 0;
+ virtual void updateHotspots() = 0;
+ virtual void run() = 0;
+ virtual void updateAnimations() = 0;
+ virtual void updateAnimationsCb() = 0;
+
+protected:
+ GnapEngine *_vm;
+};
+
+class CutScene : public Scene {
+public:
+ CutScene(GnapEngine *vm);
+ virtual ~CutScene() {};
+
+ virtual int init() = 0;
+ void updateHotspots() {}
+ void run();
+ void updateAnimations() {}
+ void updateAnimationsCb() {}
+
+protected:
+ int _itemsCount;
+ int _resourceIdArr[16];
+ int _sequenceCountArr[16];
+ int _sequenceIdArr[50];
+ bool _canSkip[16];
+};
+} // End of namespace Gnap
+
+#endif // GNAP_SCENECORE_H
diff --git a/engines/gnap/sound.cpp b/engines/gnap/sound.cpp
new file mode 100644
index 0000000000..75cfb5555c
--- /dev/null
+++ b/engines/gnap/sound.cpp
@@ -0,0 +1,96 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 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 "gnap/sound.h"
+#include "audio/audiostream.h"
+#include "audio/decoders/wave.h"
+
+namespace Gnap {
+
+SoundMan::SoundMan(GnapEngine *vm)
+ : _vm(vm) {
+}
+
+SoundMan::~SoundMan() {
+}
+
+void SoundMan::playSound(int resourceId, bool looping) {
+ SoundItem soundItem;
+ soundItem._resourceId = resourceId;
+
+ SoundResource *soundResource = _vm->_soundCache->get(resourceId);
+ Common::MemoryReadStream *stream = new Common::MemoryReadStream(soundResource->_data, soundResource->_size, DisposeAfterUse::NO);
+ Audio::AudioStream *audioStream = Audio::makeLoopingAudioStream(Audio::makeWAVStream(stream, DisposeAfterUse::YES), looping ? 0 : 1);
+
+ _vm->_mixer->playStream(Audio::Mixer::kPlainSoundType, &soundItem._handle, audioStream);
+
+ _items.push_back(soundItem);
+
+}
+
+void SoundMan::stopSound(int resourceId) {
+ const int index = find(resourceId);
+ if (index >= 0) {
+ _vm->_soundCache->release(_items[index]._resourceId);
+ _vm->_mixer->stopHandle(_items[index]._handle);
+ _items.remove_at(index);
+ }
+}
+
+void SoundMan::setSoundVolume(int resourceId, int volume) {
+ if (resourceId == -1 || volume < 0 || volume > 100)
+ return;
+
+ const int index = find(resourceId);
+ int realVol = volume * 2.55;
+ _vm->_mixer->setChannelVolume(_items[index]._handle, realVol);
+}
+
+bool SoundMan::isSoundPlaying(int resourceId) {
+ const int index = find(resourceId);
+ return index >= 0 && _vm->_mixer->isSoundHandleActive(_items[index]._handle);
+}
+
+void SoundMan::stopAll() {
+ for (int index = 0; index < (int)_items.size(); ++index) {
+ _vm->_soundCache->release(_items[index]._resourceId);
+ _vm->_mixer->stopHandle(_items[index]._handle);
+ }
+}
+
+void SoundMan::update() {
+ for (int index = 0; index < (int)_items.size(); ++index)
+ if (!_vm->_mixer->isSoundHandleActive(_items[index]._handle)) {
+ _vm->_soundCache->release(_items[index]._resourceId);
+ _items.remove_at(index);
+ --index;
+ }
+}
+
+int SoundMan::find(int resourceId) {
+ for (int index = 0; index < (int)_items.size(); ++index)
+ if (_items[index]._resourceId == resourceId)
+ return index;
+ return -1;
+}
+
+} // End of namespace Gnap
diff --git a/engines/gnap/sound.h b/engines/gnap/sound.h
new file mode 100644
index 0000000000..de3981245d
--- /dev/null
+++ b/engines/gnap/sound.h
@@ -0,0 +1,57 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 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 GNAP_SOUND_H
+#define GNAP_SOUND_H
+
+#include "gnap/gnap.h"
+#include "gnap/resource.h"
+#include "audio/mixer.h"
+#include "common/array.h"
+
+namespace Gnap {
+
+struct SoundItem {
+ int _resourceId;
+ Audio::SoundHandle _handle;
+};
+
+class SoundMan {
+public:
+ SoundMan(GnapEngine *vm);
+ ~SoundMan();
+ void playSound(int resourceId, bool looping);
+ void stopSound(int resourceId);
+ void setSoundVolume(int resourceId, int volume);
+ bool isSoundPlaying(int resourceId);
+ void stopAll();
+ void update();
+protected:
+ GnapEngine *_vm;
+ Common::Array<SoundItem> _items;
+
+ int find(int resourceId);
+};
+
+} // End of namespace Gnap
+
+#endif // GNAP_SOUND_H
diff --git a/engines/groovie/cell.cpp b/engines/groovie/cell.cpp
index 24fac17e44..5fceb8f74e 100644
--- a/engines/groovie/cell.cpp
+++ b/engines/groovie/cell.cpp
@@ -30,6 +30,7 @@ CellGame::CellGame() {
_stack_index = _boardStackPtr = 0;
_flag4 = false;
_flag2 = false;
+ _flag1 = false;
_coeff3 = 0;
_moveCount = 0;
diff --git a/engines/groovie/cursor.cpp b/engines/groovie/cursor.cpp
index 442f0bfada..d56698095f 100644
--- a/engines/groovie/cursor.cpp
+++ b/engines/groovie/cursor.cpp
@@ -35,7 +35,7 @@ namespace Groovie {
// Cursor Manager
GrvCursorMan::GrvCursorMan(OSystem *system) :
- _syst(system), _lastTime(0), _current(255), _cursor(NULL) {
+ _syst(system), _lastTime(0), _current(255), _cursor(NULL), _lastFrame(0) {
}
GrvCursorMan::~GrvCursorMan() {
diff --git a/engines/groovie/font.h b/engines/groovie/font.h
index 23e060faf3..5c479b6919 100644
--- a/engines/groovie/font.h
+++ b/engines/groovie/font.h
@@ -44,7 +44,7 @@ private:
int _maxHeight, _maxWidth;
struct Glyph {
- Glyph() : pixels(0) {}
+ Glyph() : pixels(0), width(0), height(0), julia(0) {}
~Glyph() { delete[] pixels; }
byte width;
diff --git a/engines/groovie/graphics.cpp b/engines/groovie/graphics.cpp
index e0c198f377..45956416cd 100644
--- a/engines/groovie/graphics.cpp
+++ b/engines/groovie/graphics.cpp
@@ -31,7 +31,7 @@
namespace Groovie {
GraphicsMan::GraphicsMan(GroovieEngine *vm) :
- _vm(vm), _changed(false), _fading(0) {
+ _vm(vm), _changed(false), _fading(0), _fadeStartTime(0) {
// Create the game surfaces
_foreground.create(640, 320, _vm->_pixelFormat);
_background.create(640, 320, _vm->_pixelFormat);
diff --git a/engines/groovie/music.cpp b/engines/groovie/music.cpp
index cf65e012c8..9244dd7c31 100644
--- a/engines/groovie/music.cpp
+++ b/engines/groovie/music.cpp
@@ -44,7 +44,8 @@ namespace Groovie {
MusicPlayer::MusicPlayer(GroovieEngine *vm) :
_vm(vm), _isPlaying(false), _backgroundFileRef(0), _gameVolume(100),
- _prevCDtrack(0), _backgroundDelay(0) {
+ _prevCDtrack(0), _backgroundDelay(0), _fadingStartTime(0), _fadingStartVolume(0),
+ _fadingEndVolume(0), _fadingDuration(0), _userVolume(0) {
}
MusicPlayer::~MusicPlayer() {
@@ -391,6 +392,8 @@ MusicPlayerXMI::MusicPlayerXMI(GroovieEngine *vm, const Common::String &gtlName)
bool milesAudioEnabled = true;
MidiParser::XMidiNewTimbreListProc newTimbreListProc = NULL;
+ _musicType = 0;
+
if (milesAudioEnabled) {
// 7th Guest uses FAT.AD/FAT.OPL/FAT.MT
// 11th Hour uses SAMPLE.AD/SAMPLE.OPL/SAMPLE.MT
diff --git a/engines/groovie/music.h b/engines/groovie/music.h
index c549527c77..8b46cddc1f 100644
--- a/engines/groovie/music.h
+++ b/engines/groovie/music.h
@@ -141,7 +141,7 @@ private:
// Timbres
class Timbre {
public:
- Timbre() : data(NULL) {}
+ Timbre() : data(NULL), patch(0), bank(0), size(0) {}
byte patch;
byte bank;
uint32 size;
diff --git a/engines/groovie/player.cpp b/engines/groovie/player.cpp
index dea32386f2..bbc8918902 100644
--- a/engines/groovie/player.cpp
+++ b/engines/groovie/player.cpp
@@ -29,7 +29,8 @@
namespace Groovie {
VideoPlayer::VideoPlayer(GroovieEngine *vm) :
- _vm(vm), _syst(vm->_system), _file(NULL), _audioStream(NULL), _fps(0), _overrideSpeed(false) {
+ _vm(vm), _syst(vm->_system), _file(NULL), _audioStream(NULL), _fps(0), _overrideSpeed(false), _flags(0),
+ _begunPlaying(false), _millisBetweenFrames(0), _lastFrameTime(0) {
}
bool VideoPlayer::load(Common::SeekableReadStream *file, uint16 flags) {
diff --git a/engines/hopkins/detection.cpp b/engines/hopkins/detection.cpp
index cc1e84f5f8..cfdbf8030c 100644
--- a/engines/hopkins/detection.cpp
+++ b/engines/hopkins/detection.cpp
@@ -111,7 +111,7 @@ public:
}
virtual const char *getOriginalCopyright() const {
- return "Hopkins FBI (c)1997-2003 MP Entertainment";
+ return "Hopkins FBI (C)1997-2003 MP Entertainment";
}
virtual bool hasFeature(MetaEngineFeature f) const;
diff --git a/engines/lab/detection.cpp b/engines/lab/detection.cpp
index 1fd3ca8944..30890b5acf 100644
--- a/engines/lab/detection.cpp
+++ b/engines/lab/detection.cpp
@@ -127,7 +127,7 @@ public:
}
virtual const char *getOriginalCopyright() const {
- return "Labyrinth of Time (c) 2004 The Wyrmkeep Entertainment Co. and Terra Nova Development";
+ return "Labyrinth of Time (C) 2004 The Wyrmkeep Entertainment Co. and Terra Nova Development";
}
virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const {
diff --git a/engines/mads/detection.cpp b/engines/mads/detection.cpp
index b3ba60b6d0..4736503a38 100644
--- a/engines/mads/detection.cpp
+++ b/engines/mads/detection.cpp
@@ -149,7 +149,7 @@ public:
}
virtual const char *getOriginalCopyright() const {
- return "MADS (c)";
+ return "MADS (C)";
}
virtual bool hasFeature(MetaEngineFeature f) const;
diff --git a/engines/mads/dragonsphere/dragonsphere_scenes.cpp b/engines/mads/dragonsphere/dragonsphere_scenes.cpp
index a18d03d143..c20eeb72fa 100644
--- a/engines/mads/dragonsphere/dragonsphere_scenes.cpp
+++ b/engines/mads/dragonsphere/dragonsphere_scenes.cpp
@@ -201,7 +201,7 @@ Common::String DragonsphereScene::formAnimName(char sepChar, int suffixNum) {
/*------------------------------------------------------------------------*/
-void SceneInfoDragonsphere::loadCodes(MSurface &depthSurface, int variant) {
+void SceneInfoDragonsphere::loadCodes(BaseSurface &depthSurface, int variant) {
Common::String ext = Common::String::format(".WW%d", variant);
Common::String fileName = Resources::formatName(RESPREFIX_RM, _sceneId, ext);
if (!Common::File::exists(fileName))
@@ -217,7 +217,7 @@ void SceneInfoDragonsphere::loadCodes(MSurface &depthSurface, int variant) {
f.close();
}
-void SceneInfoDragonsphere::loadCodes(MSurface &depthSurface, Common::SeekableReadStream *stream) {
+void SceneInfoDragonsphere::loadCodes(BaseSurface &depthSurface, Common::SeekableReadStream *stream) {
byte *destP = (byte *)depthSurface.getPixels();
byte *walkMap = new byte[stream->size()];
stream->read(walkMap, stream->size());
diff --git a/engines/mads/dragonsphere/dragonsphere_scenes.h b/engines/mads/dragonsphere/dragonsphere_scenes.h
index e9b48715db..22d894b9d9 100644
--- a/engines/mads/dragonsphere/dragonsphere_scenes.h
+++ b/engines/mads/dragonsphere/dragonsphere_scenes.h
@@ -647,9 +647,9 @@ public:
class SceneInfoDragonsphere : public SceneInfo {
friend class SceneInfo;
protected:
- virtual void loadCodes(MSurface &depthSurface, int variant);
+ virtual void loadCodes(BaseSurface &depthSurface, int variant);
- virtual void loadCodes(MSurface &depthSurface, Common::SeekableReadStream *stream);
+ virtual void loadCodes(BaseSurface &depthSurface, Common::SeekableReadStream *stream);
/**
* Constructor
diff --git a/engines/mads/font.cpp b/engines/mads/font.cpp
index 3828c3df8e..684418da91 100644
--- a/engines/mads/font.cpp
+++ b/engines/mads/font.cpp
@@ -145,7 +145,7 @@ void Font::setColorMode(SelectionMode mode) {
}
}
-int Font::writeString(MSurface *surface, const Common::String &msg, const Common::Point &pt,
+int Font::writeString(BaseSurface *surface, const Common::String &msg, const Common::Point &pt,
int spaceWidth, int width) {
int xEnd;
if (width > 0)
diff --git a/engines/mads/font.h b/engines/mads/font.h
index 486cadcfff..a27de6e283 100644
--- a/engines/mads/font.h
+++ b/engines/mads/font.h
@@ -86,7 +86,7 @@ public:
int maxWidth() const { return _maxWidth; }
int getWidth(const Common::String &msg, int spaceWidth = -1);
int getHeight() const { return _maxHeight; }
- int writeString(MSurface *surface, const Common::String &msg, const Common::Point &pt,
+ int writeString(BaseSurface *surface, const Common::String &msg, const Common::Point &pt,
int spaceWidth = 0, int width = 0);
};
diff --git a/engines/mads/messages.cpp b/engines/mads/messages.cpp
index 2bee77dae7..773ebd309c 100644
--- a/engines/mads/messages.cpp
+++ b/engines/mads/messages.cpp
@@ -558,7 +558,7 @@ void TextDisplayList::setDirtyAreas2() {
}
}
-void TextDisplayList::draw(MSurface *s) {
+void TextDisplayList::draw(BaseSurface *s) {
for (uint idx = 0; idx < size(); ++idx) {
TextDisplay &td = (*this)[idx];
if (td._active && (td._expire >= 0)) {
diff --git a/engines/mads/messages.h b/engines/mads/messages.h
index 2b673a8a4d..ced8c5bb6d 100644
--- a/engines/mads/messages.h
+++ b/engines/mads/messages.h
@@ -170,7 +170,7 @@ public:
* Draw any text in the list to the specified surface
* @param surface Surface
*/
- void draw(MSurface *s);
+ void draw(BaseSurface *s);
/**
* Determine dirty areas for active text areas
diff --git a/engines/mads/msurface.cpp b/engines/mads/msurface.cpp
index 40c69c0f08..8ea9c39bf5 100644
--- a/engines/mads/msurface.cpp
+++ b/engines/mads/msurface.cpp
@@ -30,9 +30,9 @@
namespace MADS {
-MADSEngine *MSurface::_vm = nullptr;
+MADSEngine *BaseSurface::_vm = nullptr;
-int MSurface::scaleValue(int value, int scale, int err) {
+int BaseSurface::scaleValue(int value, int scale, int err) {
int scaled = 0;
while (value--) {
err -= scale;
@@ -44,7 +44,7 @@ int MSurface::scaleValue(int value, int scale, int err) {
return scaled;
}
-void MSurface::drawSprite(const Common::Point &pt, SpriteInfo &info, const Common::Rect &clipRect) {
+void BaseSurface::drawSprite(const Common::Point &pt, SpriteInfo &info, const Common::Rect &clipRect) {
enum {
kStatusSkip,
kStatusScale,
@@ -171,7 +171,7 @@ void MSurface::drawSprite(const Common::Point &pt, SpriteInfo &info, const Commo
delete[] scaledLineBuf;
}
-void MSurface::scrollX(int xAmount) {
+void BaseSurface::scrollX(int xAmount) {
if (xAmount == 0)
return;
@@ -203,7 +203,7 @@ void MSurface::scrollX(int xAmount) {
markAllDirty();
}
-void MSurface::scrollY(int yAmount) {
+void BaseSurface::scrollY(int yAmount) {
if (yAmount == 0)
return;
@@ -238,7 +238,7 @@ void MSurface::scrollY(int yAmount) {
delete[] tempData;
}
-void MSurface::translate(Common::Array<RGB6> &palette) {
+void BaseSurface::translate(Common::Array<RGB6> &palette) {
for (int y = 0; y < this->h; ++y) {
byte *pDest = (byte *)getBasePtr(0, y);
@@ -251,7 +251,7 @@ void MSurface::translate(Common::Array<RGB6> &palette) {
markAllDirty();
}
-void MSurface::translate(byte map[PALETTE_COUNT]) {
+void BaseSurface::translate(byte map[PALETTE_COUNT]) {
for (int y = 0; y < this->h; ++y) {
byte *pDest = (byte *)getBasePtr(0, y);
@@ -263,7 +263,7 @@ void MSurface::translate(byte map[PALETTE_COUNT]) {
markAllDirty();
}
-MSurface *MSurface::flipHorizontal() const {
+BaseSurface *BaseSurface::flipHorizontal() const {
MSurface *dest = new MSurface(this->w, this->h);
for (int y = 0; y < this->h; ++y) {
@@ -277,7 +277,7 @@ MSurface *MSurface::flipHorizontal() const {
return dest;
}
-void MSurface::copyRectTranslate(MSurface &srcSurface, const byte *paletteMap,
+void BaseSurface::copyRectTranslate(BaseSurface &srcSurface, const byte *paletteMap,
const Common::Point &destPos, const Common::Rect &srcRect) {
// Loop through the lines
for (int yCtr = 0; yCtr < srcRect.height(); ++yCtr) {
@@ -294,7 +294,7 @@ void MSurface::copyRectTranslate(MSurface &srcSurface, const byte *paletteMap,
destPos.y + srcRect.height()));
}
-void MSurface::copyFrom(MSurface &src, const Common::Point &destPos, int depth,
+void BaseSurface::copyFrom(BaseSurface &src, const Common::Point &destPos, int depth,
DepthSurface *depthSurface, int scale, bool flipped, int transparentColor) {
int destX = destPos.x, destY = destPos.y;
int frameWidth = src.w;
@@ -337,15 +337,13 @@ void MSurface::copyFrom(MSurface &src, const Common::Point &destPos, int depth,
if (destX < 0) {
copyRect.left += -destX;
destX = 0;
- }
- else if (destX + copyRect.width() > w) {
+ } else if (destX + copyRect.width() > w) {
copyRect.right -= destX + copyRect.width() - w;
}
if (destY < 0) {
copyRect.top += -destY;
destY = 0;
- }
- else if (destY + copyRect.height() > h) {
+ } else if (destY + copyRect.height() > h) {
copyRect.bottom -= destY + copyRect.height() - h;
}
diff --git a/engines/mads/msurface.h b/engines/mads/msurface.h
index e92770900d..5b5a1d62c1 100644
--- a/engines/mads/msurface.h
+++ b/engines/mads/msurface.h
@@ -25,7 +25,7 @@
#include "common/scummsys.h"
#include "common/rect.h"
-#include "graphics/managed_surface.h"
+#include "graphics/screen.h"
#include "mads/palette.h"
namespace MADS {
@@ -48,9 +48,11 @@ struct SpriteInfo {
};
/*
- * MADS graphics surface
+ * Base MADS surface class. This derivces from Graphics::Screen
+ * because it has logic we'll need for our own Screen class that
+ * derives from this one
*/
-class MSurface : virtual public Graphics::ManagedSurface {
+class BaseSurface : public Graphics::Screen {
private:
/**
* Helper method for calculating new dimensions when scaling a sprite
@@ -72,17 +74,19 @@ public:
/**
* Basic constructor
*/
- MSurface() : Graphics::ManagedSurface() {}
+ BaseSurface() : Graphics::Screen(0, 0) {
+ free(); // Free the 0x0 surface allocated by Graphics::Screen
+ }
/**
* Constructor for a surface with fixed dimensions
*/
- MSurface(int width, int height) : Graphics::ManagedSurface(width, height) {}
+ BaseSurface(int width, int height) : Graphics::Screen(width, height) {}
/**
* Destructor
*/
- virtual ~MSurface() {}
+ virtual ~BaseSurface() {}
/**
* Return a rect containing the bounds of the surface
@@ -142,13 +146,13 @@ public:
/**
* Create a new surface which is a flipped horizontal copy of the current one
*/
- MSurface *flipHorizontal() const;
+ BaseSurface *flipHorizontal() const;
/**
* Copy an area from one surface to another, translating it using a palette
* map as it's done
*/
- void copyRectTranslate(MSurface &srcSurface, const byte *paletteMap,
+ void copyRectTranslate(BaseSurface &srcSurface, const byte *paletteMap,
const Common::Point &destPos, const Common::Rect &srcRect);
/**
@@ -161,10 +165,22 @@ public:
* @param flipped Flag for whether image is to be flipped
* @param transparentColor Transparency palette index
*/
- void copyFrom(MSurface &src, const Common::Point &destPos, int depth, DepthSurface *depthSurface,
+ void copyFrom(BaseSurface &src, const Common::Point &destPos, int depth, DepthSurface *depthSurface,
int scale, bool flipped, int transparentColor = -1);
};
+class MSurface : public BaseSurface {
+protected:
+ /**
+ * Override the addDirtyRect from Graphics::Screen, since for standard
+ * surfaces we don't need dirty rects to be tracked
+ */
+ virtual void addDirtyRect(const Common::Rect &r) {}
+public:
+ MSurface() : BaseSurface() {}
+ MSurface(int width, int height) : BaseSurface(width, height) {}
+};
+
class DepthSurface : public MSurface {
public:
/**
diff --git a/engines/mads/nebular/nebular_scenes.cpp b/engines/mads/nebular/nebular_scenes.cpp
index 40228b4b7d..9502d273ea 100644
--- a/engines/mads/nebular/nebular_scenes.cpp
+++ b/engines/mads/nebular/nebular_scenes.cpp
@@ -311,7 +311,7 @@ Common::String NebularScene::formAnimName(char sepChar, int suffixNum) {
/*------------------------------------------------------------------------*/
-void SceneInfoNebular::loadCodes(MSurface &depthSurface, int variant) {
+void SceneInfoNebular::loadCodes(BaseSurface &depthSurface, int variant) {
File f(Resources::formatName(RESPREFIX_RM, _sceneId, ".DAT"));
MadsPack codesPack(&f);
Common::SeekableReadStream *stream = codesPack.getItemStream(variant + 1);
@@ -322,7 +322,7 @@ void SceneInfoNebular::loadCodes(MSurface &depthSurface, int variant) {
f.close();
}
-void SceneInfoNebular::loadCodes(MSurface &depthSurface, Common::SeekableReadStream *stream) {
+void SceneInfoNebular::loadCodes(BaseSurface &depthSurface, Common::SeekableReadStream *stream) {
byte *destP = (byte *)depthSurface.getPixels();
byte *endP = (byte *)depthSurface.getBasePtr(0, depthSurface.h);
diff --git a/engines/mads/nebular/nebular_scenes.h b/engines/mads/nebular/nebular_scenes.h
index 58a6d1c98f..b600c6dbe1 100644
--- a/engines/mads/nebular/nebular_scenes.h
+++ b/engines/mads/nebular/nebular_scenes.h
@@ -1373,9 +1373,9 @@ public:
class SceneInfoNebular : public SceneInfo {
friend class SceneInfo;
protected:
- virtual void loadCodes(MSurface &depthSurface, int variant);
+ virtual void loadCodes(BaseSurface &depthSurface, int variant);
- virtual void loadCodes(MSurface &depthSurface, Common::SeekableReadStream *stream);
+ virtual void loadCodes(BaseSurface &depthSurface, Common::SeekableReadStream *stream);
/**
* Constructor
diff --git a/engines/mads/phantom/phantom_scenes.cpp b/engines/mads/phantom/phantom_scenes.cpp
index 7ef627ceeb..bfb521e369 100644
--- a/engines/mads/phantom/phantom_scenes.cpp
+++ b/engines/mads/phantom/phantom_scenes.cpp
@@ -174,7 +174,7 @@ Common::String PhantomScene::formAnimName(char sepChar, int suffixNum) {
/*------------------------------------------------------------------------*/
-void SceneInfoPhantom::loadCodes(MSurface &depthSurface, int variant) {
+void SceneInfoPhantom::loadCodes(BaseSurface &depthSurface, int variant) {
Common::String ext = Common::String::format(".WW%d", variant);
Common::String fileName = Resources::formatName(RESPREFIX_RM, _sceneId, ext);
if (!Common::File::exists(fileName))
@@ -190,7 +190,7 @@ void SceneInfoPhantom::loadCodes(MSurface &depthSurface, int variant) {
f.close();
}
-void SceneInfoPhantom::loadCodes(MSurface &depthSurface, Common::SeekableReadStream *stream) {
+void SceneInfoPhantom::loadCodes(BaseSurface &depthSurface, Common::SeekableReadStream *stream) {
byte *destP = (byte *)depthSurface.getPixels();
byte *walkMap = new byte[stream->size()];
stream->read(walkMap, stream->size());
diff --git a/engines/mads/phantom/phantom_scenes.h b/engines/mads/phantom/phantom_scenes.h
index a6a8395a2c..6b7ab697f3 100644
--- a/engines/mads/phantom/phantom_scenes.h
+++ b/engines/mads/phantom/phantom_scenes.h
@@ -474,9 +474,9 @@ public:
class SceneInfoPhantom : public SceneInfo {
friend class SceneInfo;
protected:
- virtual void loadCodes(MSurface &depthSurface, int variant);
+ virtual void loadCodes(BaseSurface &depthSurface, int variant);
- virtual void loadCodes(MSurface &depthSurface, Common::SeekableReadStream *stream);
+ virtual void loadCodes(BaseSurface &depthSurface, Common::SeekableReadStream *stream);
/**
* Constructor
diff --git a/engines/mads/scene_data.cpp b/engines/mads/scene_data.cpp
index 5323178ec7..21fd4f9026 100644
--- a/engines/mads/scene_data.cpp
+++ b/engines/mads/scene_data.cpp
@@ -128,7 +128,7 @@ SceneInfo *SceneInfo::init(MADSEngine *vm) {
}
void SceneInfo::load(int sceneId, int variant, const Common::String &resName,
- int flags, DepthSurface &depthSurface, MSurface &bgSurface) {
+ int flags, DepthSurface &depthSurface, BaseSurface &bgSurface) {
bool sceneFlag = sceneId >= 0;
// Figure out the resource to use
@@ -299,7 +299,7 @@ void SceneInfo::load(int sceneId, int variant, const Common::String &resName,
}
}
-void SceneInfo::loadPalette(int sceneId, int artFileNum, const Common::String &resName, int flags, MSurface &bgSurface) {
+void SceneInfo::loadPalette(int sceneId, int artFileNum, const Common::String &resName, int flags, BaseSurface &bgSurface) {
bool sceneFlag = sceneId >= 0;
Common::String resourceName;
bool isV2 = (_vm->getGameID() != GType_RexNebular);
@@ -351,7 +351,7 @@ void SceneInfo::loadPalette(int sceneId, int artFileNum, const Common::String &r
}
}
-void SceneInfo::loadMadsV1Background(int sceneId, const Common::String &resName, int flags, MSurface &bgSurface) {
+void SceneInfo::loadMadsV1Background(int sceneId, const Common::String &resName, int flags, BaseSurface &bgSurface) {
bool sceneFlag = sceneId >= 0;
Common::String resourceName;
Common::SeekableReadStream *stream;
@@ -397,7 +397,7 @@ void SceneInfo::loadMadsV1Background(int sceneId, const Common::String &resName,
artFile.close();
}
-void SceneInfo::loadMadsV2Background(int sceneId, const Common::String &resName, int flags, MSurface &bgSurface) {
+void SceneInfo::loadMadsV2Background(int sceneId, const Common::String &resName, int flags, BaseSurface &bgSurface) {
Common::String tileMapResourceName = Resources::formatName(RESPREFIX_RM, sceneId, ".MM");
File tileMapFile(tileMapResourceName);
MadsPack tileMapPack(&tileMapFile);
diff --git a/engines/mads/scene_data.h b/engines/mads/scene_data.h
index 41a08f74eb..a28c42c5ab 100644
--- a/engines/mads/scene_data.h
+++ b/engines/mads/scene_data.h
@@ -189,36 +189,36 @@ public:
* loads the data
*/
void load(int sceneId, int variant, const Common::String &resName, int flags,
- DepthSurface &depthSurface, MSurface &bgSurface);
+ DepthSurface &depthSurface, BaseSurface &bgSurface);
/**
* Loads the palette for a scene
*/
- void loadPalette(int sceneId, int artFileNum, const Common::String &resName, int flags, MSurface &bgSurface);
+ void loadPalette(int sceneId, int artFileNum, const Common::String &resName, int flags, BaseSurface &bgSurface);
/**
* Loads a V1 game background
*/
- void loadMadsV1Background(int sceneId, const Common::String &resName, int flags, MSurface &bgSurface);
+ void loadMadsV1Background(int sceneId, const Common::String &resName, int flags, BaseSurface &bgSurface);
/**
* Loads a V2 game background
*/
- void loadMadsV2Background(int sceneId, const Common::String &resName, int flags, MSurface &bgSurface);
+ void loadMadsV2Background(int sceneId, const Common::String &resName, int flags, BaseSurface &bgSurface);
/**
* Loads the given surface with depth information of a given scene
* @param depthSurface Depth/walk surface
* @param variant Variant number to load
*/
- virtual void loadCodes(MSurface &depthSurface, int variant) = 0;
+ virtual void loadCodes(BaseSurface &depthSurface, int variant) = 0;
/**
* Loads the given surface with depth information of a given scene
* @param depthSurface Depth/walk surface
* @param stream Stream to load the data from
*/
- virtual void loadCodes(MSurface &depthSurface, Common::SeekableReadStream *stream) = 0;
+ virtual void loadCodes(BaseSurface &depthSurface, Common::SeekableReadStream *stream) = 0;
};
} // End of namespace MADS
diff --git a/engines/mads/screen.cpp b/engines/mads/screen.cpp
index 05f9de61e2..b17b6e93b8 100644
--- a/engines/mads/screen.cpp
+++ b/engines/mads/screen.cpp
@@ -201,7 +201,7 @@ void DirtyAreas::mergeAreas(int idx1, int idx2) {
da1._textActive = true;
}
-void DirtyAreas::copy(MSurface *srcSurface, MSurface *destSurface, const Common::Point &posAdjust) {
+void DirtyAreas::copy(BaseSurface *srcSurface, BaseSurface *destSurface, const Common::Point &posAdjust) {
for (uint i = 0; i < size(); ++i) {
const Common::Rect &srcBounds = (*this)[i]._bounds;
@@ -555,7 +555,7 @@ void ScreenObjects::synchronize(Common::Serializer &s) {
/*------------------------------------------------------------------------*/
-Screen::Screen(): Graphics::Screen(), MSurface() {
+Screen::Screen(): BaseSurface() {
// Create the screen surface separately on another surface, since the screen
// surface will be subject to change as the clipping area is altered
_rawSurface.create(MADS_SCREEN_WIDTH, MADS_SCREEN_HEIGHT);
diff --git a/engines/mads/screen.h b/engines/mads/screen.h
index 626080580e..eeb15453f8 100644
--- a/engines/mads/screen.h
+++ b/engines/mads/screen.h
@@ -25,7 +25,6 @@
#include "common/scummsys.h"
#include "common/array.h"
-#include "graphics/screen.h"
#include "mads/msurface.h"
#include "mads/action.h"
@@ -118,7 +117,7 @@ public:
* @param destSurface Dest surface
* @param posAdjust Position adjustment
*/
- void copy(MSurface *srcSurface, MSurface *destSurface, const Common::Point &posAdjust);
+ void copy(BaseSurface *srcSurface, BaseSurface *destSurface, const Common::Point &posAdjust);
/**
* Use the lsit of dirty areas to copy areas of the screen surface to
@@ -129,7 +128,6 @@ public:
void reset();
};
-
class ScreenObject {
public:
bool _active;
@@ -208,7 +206,7 @@ public:
void synchronize(Common::Serializer &s);
};
-class Screen : virtual public Graphics::Screen, virtual public MSurface {
+class Screen : public BaseSurface {
private:
uint16 _random;
MSurface _rawSurface;
diff --git a/engines/mads/sprites.cpp b/engines/mads/sprites.cpp
index fc8ddf22d2..84060ccdfe 100644
--- a/engines/mads/sprites.cpp
+++ b/engines/mads/sprites.cpp
@@ -337,7 +337,7 @@ void SpriteSlots::drawSprites(MSurface *s) {
s->copyFrom(*sprite, Common::Point(xp, yp), slot._depth, &scene._depthSurface,
-1, flipped, sprite->getTransparencyIndex());
} else {
- MSurface *spr = sprite;
+ BaseSurface *spr = sprite;
if (flipped) {
// Create a flipped copy of the sprite temporarily
spr = sprite->flipHorizontal();
diff --git a/engines/mads/user_interface.cpp b/engines/mads/user_interface.cpp
index 8f7cb0a24b..204f71fe43 100644
--- a/engines/mads/user_interface.cpp
+++ b/engines/mads/user_interface.cpp
@@ -161,7 +161,7 @@ void UISlots::draw(bool updateFlag, bool delFlag) {
MSprite *sprite = asset->getFrame(frameNumber - 1);
if (flipped) {
- MSurface *spr = sprite->flipHorizontal();
+ BaseSurface *spr = sprite->flipHorizontal();
userInterface.mergeFrom(spr, spr->getBounds(), slot._position,
sprite->getTransparencyIndex());
spr->free();
@@ -429,7 +429,7 @@ void UserInterface::drawTextElements() {
}
}
-void UserInterface::mergeFrom(MSurface *src, const Common::Rect &srcBounds,
+void UserInterface::mergeFrom(BaseSurface *src, const Common::Rect &srcBounds,
const Common::Point &destPos, int transparencyIndex) {
// Validation of the rectangle and position
int destX = destPos.x, destY = destPos.y;
diff --git a/engines/mads/user_interface.h b/engines/mads/user_interface.h
index 9232dc1bb1..6c9485998a 100644
--- a/engines/mads/user_interface.h
+++ b/engines/mads/user_interface.h
@@ -238,7 +238,7 @@ public:
* @param destPos Destination position to draw in current surface
* @param transparencyIndex Transparency color
*/
- void mergeFrom(MSurface *src, const Common::Rect &srcBounds, const Common::Point &destPos,
+ void mergeFrom(BaseSurface *src, const Common::Rect &srcBounds, const Common::Point &destPos,
int transparencyIndex = -1);
/**
diff --git a/engines/parallaction/adlib.cpp b/engines/parallaction/adlib.cpp
index 568ad190aa..a981a5553b 100644
--- a/engines/parallaction/adlib.cpp
+++ b/engines/parallaction/adlib.cpp
@@ -277,6 +277,15 @@ public:
_channels[i].init(this, i);
_isOpen = false;
+
+ _opl = NULL;
+ memset(_voices, 0, sizeof(_voices));
+
+ _lastVoice = 0;
+ _percussionMask = 0;
+
+ _adlibTimerProc = NULL;
+ _adlibTimerParam = NULL;
}
int open();
diff --git a/engines/parallaction/balloons.cpp b/engines/parallaction/balloons.cpp
index 234abff59a..c0a516eb0f 100644
--- a/engines/parallaction/balloons.cpp
+++ b/engines/parallaction/balloons.cpp
@@ -55,7 +55,7 @@ protected:
}
public:
- WrappedLineFormatter(Font *font) : _font(font) { }
+ WrappedLineFormatter(Font *font) : _font(font), _lines(0), _lineWidth(0) { }
virtual ~WrappedLineFormatter() { }
virtual void calc(const Common::String &text, uint16 maxwidth) {
@@ -136,7 +136,7 @@ protected:
}
public:
- StringExtent_NS(Font *font) : WrappedLineFormatter(font) { }
+ StringExtent_NS(Font *font) : WrappedLineFormatter(font), _width(0), _height(0) { }
uint width() const { return _width; }
uint height() const { return _height; }
@@ -189,7 +189,8 @@ protected:
}
public:
- StringWriter_NS(Parallaction_ns *vm, Font *font) : WrappedLineFormatter(font), _vm(vm) { }
+ StringWriter_NS(Parallaction_ns *vm, Font *font) : WrappedLineFormatter(font), _vm(vm),
+ _width(0), _height(0), _color(0), _surf(NULL) { }
void write(const Common::String &text, uint maxWidth, byte color, Graphics::Surface *surf) {
StringExtent_NS se(_font);
@@ -464,7 +465,7 @@ protected:
}
public:
- StringExtent_BR(Font *font) : WrappedLineFormatter(font) { }
+ StringExtent_BR(Font *font) : WrappedLineFormatter(font), _width(0), _height(0) { }
uint width() const { return _width; }
uint height() const { return _height; }
@@ -480,7 +481,8 @@ class StringWriter_BR : public WrappedLineFormatter {
Graphics::Surface *_surf;
protected:
- StringWriter_BR(Font *font, byte color) : WrappedLineFormatter(font) {
+ StringWriter_BR(Font *font, byte color) : WrappedLineFormatter(font), _width(0), _height(0),
+ _color(color), _x(0), _y(0), _surf(NULL) {
}
@@ -504,7 +506,8 @@ protected:
}
public:
- StringWriter_BR(Font *font) : WrappedLineFormatter(font) { }
+ StringWriter_BR(Font *font) : WrappedLineFormatter(font), _width(0), _height(0),
+ _color(0), _x(0), _y(0), _surf(NULL) { }
void write(const Common::String &text, uint maxWidth, byte color, Graphics::Surface *surf) {
StringExtent_BR se(_font);
diff --git a/engines/parallaction/debug.cpp b/engines/parallaction/debug.cpp
index a7087c64d7..0bf2babb5b 100644
--- a/engines/parallaction/debug.cpp
+++ b/engines/parallaction/debug.cpp
@@ -32,6 +32,7 @@ namespace Parallaction {
Debugger::Debugger(Parallaction *vm)
: GUI::Debugger() {
_vm = vm;
+ _mouseState = MOUSE_ENABLED_SHOW;
registerCmd("continue", WRAP_METHOD(Debugger, cmdExit));
registerCmd("location", WRAP_METHOD(Debugger, Cmd_Location));
diff --git a/engines/parallaction/dialogue.cpp b/engines/parallaction/dialogue.cpp
index 62e2152816..771715b95e 100644
--- a/engines/parallaction/dialogue.cpp
+++ b/engines/parallaction/dialogue.cpp
@@ -140,6 +140,19 @@ DialogueManager::DialogueManager(Parallaction *vm, ZonePtr z) : _vm(vm), _z(z) {
_cmdList = 0;
_answerId = 0;
+
+ _faceId = 0;
+
+ _q = NULL;
+ memset(_visAnswers, 0, sizeof(_visAnswers));
+ _numVisAnswers = 0;
+
+ _selection = _oldSelection = 0;
+
+ _isKeyDown = false;
+ _downKey = 0;
+
+ _mouseButtons = 0;
}
void DialogueManager::start() {
@@ -412,7 +425,8 @@ protected:
}
public:
- DialogueManager_ns(Parallaction_ns *vm, ZonePtr z) : DialogueManager(vm, z), _vm(vm) {
+ DialogueManager_ns(Parallaction_ns *vm, ZonePtr z) : DialogueManager(vm, z), _vm(vm),
+ _passwordChanged(false), _askPassword(false) {
_ballonPos._questionBalloon = Common::Point(140, 10);
_ballonPos._questionChar = Common::Point(190, 80);
_ballonPos._answerChar = Common::Point(10, 80);
diff --git a/engines/parallaction/disk_br.cpp b/engines/parallaction/disk_br.cpp
index 7458065b8c..af2d2b82e0 100644
--- a/engines/parallaction/disk_br.cpp
+++ b/engines/parallaction/disk_br.cpp
@@ -762,14 +762,11 @@ Common::String AmigaDisk_br::selectArchive(const Common::String& name) {
}
-Disk_br::Disk_br(Parallaction *vm) : _vm(vm), _baseDir(0) {
-
+Disk_br::Disk_br(Parallaction *vm) : _vm(vm), _baseDir(0), _language(0) {
}
Disk_br::~Disk_br() {
_sset.clear();
}
-
-
} // namespace Parallaction
diff --git a/engines/parallaction/disk_ns.cpp b/engines/parallaction/disk_ns.cpp
index 28e61b04f9..c25236acbd 100644
--- a/engines/parallaction/disk_ns.cpp
+++ b/engines/parallaction/disk_ns.cpp
@@ -238,7 +238,7 @@ void Disk_ns::setLanguage(uint16 language) {
#pragma mark -
-DosDisk_ns::DosDisk_ns(Parallaction* vm) : Disk_ns(vm) {
+DosDisk_ns::DosDisk_ns(Parallaction* vm) : Disk_ns(vm), _gfx(NULL) {
}
diff --git a/engines/parallaction/exec.cpp b/engines/parallaction/exec.cpp
index ceba072173..3d4e9bd803 100644
--- a/engines/parallaction/exec.cpp
+++ b/engines/parallaction/exec.cpp
@@ -81,7 +81,7 @@ void ProgramExec::runScripts(ProgramList::iterator first, ProgramList::iterator
return;
}
-ProgramExec::ProgramExec() : _modCounter(0) {
+ProgramExec::ProgramExec() : _modCounter(0), _instructionNames(NULL) {
}
diff --git a/engines/parallaction/font.cpp b/engines/parallaction/font.cpp
index 57b04deb12..f1c3b89ae8 100644
--- a/engines/parallaction/font.cpp
+++ b/engines/parallaction/font.cpp
@@ -302,7 +302,7 @@ protected:
}
public:
- DosFont(Cnv *cnv) : _data(cnv), _pitch(cnv->_width) {
+ DosFont(Cnv *cnv) : _data(cnv), _pitch(cnv->_width), _cp(NULL), _bufPitch(0) {
}
~DosFont() {
diff --git a/engines/parallaction/gfxbase.cpp b/engines/parallaction/gfxbase.cpp
index f1499f7782..819804bfe7 100644
--- a/engines/parallaction/gfxbase.cpp
+++ b/engines/parallaction/gfxbase.cpp
@@ -32,7 +32,8 @@ namespace Parallaction {
GfxObj::GfxObj(uint objType, Frames *frames, const char* name) :
_frames(frames), x(0), y(0), z(0), _prog(0), _flags(0),
- type(objType), frame(0), layer(3), scale(100), _hasMask(false), _hasPath(false) {
+ type(objType), frame(0), layer(3), scale(100), _hasMask(false), _hasPath(false),
+ transparentKey(0), _maskId(0), _pathId(0) {
if (name) {
_name = strdup(name);
diff --git a/engines/parallaction/graphics.cpp b/engines/parallaction/graphics.cpp
index 06b315016a..162671b68a 100644
--- a/engines/parallaction/graphics.cpp
+++ b/engines/parallaction/graphics.cpp
@@ -743,6 +743,8 @@ Gfx::Gfx(Parallaction* vm) :
_nextProjectorPos = 0;
_hbCircleRadius = 0;
+ _overlayMode = false;
+
_unpackedBitmap = new byte[MAXIMUM_UNPACKED_BITMAP_SIZE];
assert(_unpackedBitmap);
diff --git a/engines/parallaction/graphics.h b/engines/parallaction/graphics.h
index 55e2bbca84..03b4dd97ef 100644
--- a/engines/parallaction/graphics.h
+++ b/engines/parallaction/graphics.h
@@ -57,7 +57,7 @@ protected:
public:
- Font() {}
+ Font() : _color(0) {}
virtual ~Font() {}
virtual void setColor(byte color) {
diff --git a/engines/parallaction/gui_br.cpp b/engines/parallaction/gui_br.cpp
index ae3d136b0e..17d759d26f 100644
--- a/engines/parallaction/gui_br.cpp
+++ b/engines/parallaction/gui_br.cpp
@@ -43,7 +43,8 @@ protected:
int _fadeSteps;
public:
- SplashInputState_BR(Parallaction *vm, const Common::String &name, MenuInputHelper *helper) : MenuInputState(name, helper), _vm(vm) {
+ SplashInputState_BR(Parallaction *vm, const Common::String &name, MenuInputHelper *helper) : MenuInputState(name, helper), _vm(vm),
+ _timeOut(0), _startTime(0), _fadeSteps(0) {
}
virtual MenuInputState* run() {
@@ -382,6 +383,9 @@ public:
_menuObj->getRect(0, _menuRect);
_cellW = _menuRect.width() / 3;
_cellH = _menuRect.height() / 2;
+
+ _menuObjId = _mscMenuObjId = _sfxMenuObjId = 0;
+ _sfxStatus = _mscStatus = 0;
}
~IngameMenuInputState_BR() {
diff --git a/engines/parallaction/gui_ns.cpp b/engines/parallaction/gui_ns.cpp
index 3d977c9e51..3c312c4f2d 100644
--- a/engines/parallaction/gui_ns.cpp
+++ b/engines/parallaction/gui_ns.cpp
@@ -43,7 +43,8 @@ protected:
Parallaction *_vm;
public:
- SplashInputState_NS(Parallaction *vm, const Common::String &name, MenuInputHelper *helper) : MenuInputState(name, helper), _vm(vm) {
+ SplashInputState_NS(Parallaction *vm, const Common::String &name, MenuInputHelper *helper) : MenuInputState(name, helper), _vm(vm),
+ _timeOut(0), _startTime(0) {
}
virtual MenuInputState* run() {
@@ -298,7 +299,7 @@ class LoadGameInputState_NS : public MenuInputState {
Parallaction *_vm;
public:
- LoadGameInputState_NS(Parallaction *vm, MenuInputHelper *helper) : MenuInputState("loadgame", helper), _vm(vm) { }
+ LoadGameInputState_NS(Parallaction *vm, MenuInputHelper *helper) : MenuInputState("loadgame", helper), _vm(vm), _result(false) { }
virtual MenuInputState* run() {
if (!_result) {
@@ -477,6 +478,11 @@ public:
_labels[0] = 0;
_labels[1] = 0;
+ _fail = false;
+ _len = 0;
+ _startTime = 0;
+ _state = 0;
+
_codeSelectBlocks[0] = Common::Rect( 111, 129, 127, 153 ); // na
_codeSelectBlocks[1] = Common::Rect( 128, 120, 144, 144 ); // wa
_codeSelectBlocks[2] = Common::Rect( 145, 111, 161, 135 ); // ra
@@ -689,6 +695,9 @@ public:
ShowCreditsInputState_NS(Parallaction *vm, MenuInputHelper *helper) : MenuInputState("showcredits", helper), _vm(vm) {
_labels[0] = 0;
_labels[1] = 0;
+
+ _current = 0;
+ _startTime = 0;
}
~ShowCreditsInputState_NS() {
@@ -827,6 +836,8 @@ public:
_labels[1] = 0;
_labels[2] = 0;
_labels[3] = 0;
+
+ _allPartsComplete = false;
}
void destroyLabels() {
diff --git a/engines/parallaction/input.cpp b/engines/parallaction/input.cpp
index 290af339bb..2cd85d7f1c 100644
--- a/engines/parallaction/input.cpp
+++ b/engines/parallaction/input.cpp
@@ -70,6 +70,9 @@ Input::Input(Parallaction *vm) : _vm(vm) {
_mouseButtons = 0;
_delayedActionZone.reset();
+ _inputMode = 0;
+ _hasKeyPressEvent = false;
+
_dinoCursor = 0;
_dougCursor = 0;
_donnaCursor = 0;
diff --git a/engines/parallaction/objects.cpp b/engines/parallaction/objects.cpp
index 8f895f1532..950d62a841 100644
--- a/engines/parallaction/objects.cpp
+++ b/engines/parallaction/objects.cpp
@@ -145,6 +145,8 @@ Program::Program() {
_locals = new LocalVariable[NUM_LOCALS];
_numLocals = 0;
_status = kProgramIdle;
+ _ip = 0;
+ _loopStart = 0;
}
Program::~Program() {
@@ -259,6 +261,8 @@ Answer::Answer() {
_noFlags = 0;
_yesFlags = 0;
_hasCounterCondition = false;
+ _counterValue = 0;
+ _counterOp = 0;
}
bool Answer::textIsNull() {
@@ -298,6 +302,7 @@ Instruction::Instruction() {
// common
_immediate = 0;
+ _endif = 0;
// BRA specific
_text = 0;
diff --git a/engines/parallaction/parallaction_ns.cpp b/engines/parallaction/parallaction_ns.cpp
index 144c2b3a98..5fd6d87985 100644
--- a/engines/parallaction/parallaction_ns.cpp
+++ b/engines/parallaction/parallaction_ns.cpp
@@ -395,7 +395,7 @@ void Parallaction_ns::changeLocation() {
changeCharacter(locname.character());
}
- strcpy(g_saveData1, locname.location());
+ Common::strlcpy(g_saveData1, locname.location(), 30);
parseLocation(g_saveData1);
if (_location._startPosition.x != -1000) {
diff --git a/engines/parallaction/parser.cpp b/engines/parallaction/parser.cpp
index c37cee692e..725a8b5996 100644
--- a/engines/parallaction/parser.cpp
+++ b/engines/parallaction/parser.cpp
@@ -226,6 +226,7 @@ uint16 Script::readLineToken(bool errorOnEOF) {
void Parser::reset() {
_currentOpcodes = 0;
_currentStatements = 0;
+ _lookup = 0;
_statements.clear();
_opcodes.clear();
diff --git a/engines/parallaction/parser.h b/engines/parallaction/parser.h
index 7b77f58eb0..e7ae7dcc36 100644
--- a/engines/parallaction/parser.h
+++ b/engines/parallaction/parser.h
@@ -405,7 +405,7 @@ protected:
virtual void parseRValue(ScriptVar &var, const char *str);
public:
- ProgramParser_br(Parallaction_br *vm) : ProgramParser_ns((Parallaction_ns*)vm), _vm(vm) {
+ ProgramParser_br(Parallaction_br *vm) : ProgramParser_ns((Parallaction_ns*)vm), _vm(vm), _openIfStatement(0) {
}
virtual void init();
diff --git a/engines/parallaction/saveload.cpp b/engines/parallaction/saveload.cpp
index eff088d5ee..0f4ceae7a5 100644
--- a/engines/parallaction/saveload.cpp
+++ b/engines/parallaction/saveload.cpp
@@ -93,7 +93,7 @@ void SaveLoad_ns::doLoadGame(uint16 slot) {
uint16 _si;
for (_si = 0; _si < _vm->_numLocations; _si++) {
s = f->readLine();
- strcpy(_vm->_locationNames[_si], s.c_str());
+ Common::strlcpy(_vm->_locationNames[_si], s.c_str(), 32);
s = f->readLine();
_vm->_localFlags[_si] = atoi(s.c_str());
diff --git a/engines/parallaction/sound_br.cpp b/engines/parallaction/sound_br.cpp
index d13b318ace..0147d3cd90 100644
--- a/engines/parallaction/sound_br.cpp
+++ b/engines/parallaction/sound_br.cpp
@@ -86,7 +86,7 @@ protected:
byte *_trackEnd;
public:
- MidiParser_MSC() : byte_11C5A(false) {
+ MidiParser_MSC() : byte_11C5A(false), _beats(0), _lastEvent(0), _trackEnd(NULL) {
}
};
@@ -467,6 +467,11 @@ SoundMan_br::SoundMan_br(Parallaction_br *vm) : _vm(vm) {
_musicEnabled = true;
_sfxEnabled = true;
+
+ _sfxLooping = false;
+ _sfxVolume = 0;
+ _sfxRate = 0;
+ _sfxChannel = 0;
}
SoundMan_br::~SoundMan_br() {
diff --git a/engines/parallaction/sound_ns.cpp b/engines/parallaction/sound_ns.cpp
index 692389b490..6073f82b82 100644
--- a/engines/parallaction/sound_ns.cpp
+++ b/engines/parallaction/sound_ns.cpp
@@ -323,6 +323,11 @@ void AmigaSoundMan_ns::playLocationMusic(const char *location) {
SoundMan_ns::SoundMan_ns(Parallaction_ns *vm) : _vm(vm) {
_mixer = _vm->_mixer;
+ _sfxLooping = false;
+ _sfxVolume = 0;
+ _sfxRate = 0;
+ _sfxChannel = 0;
+ _musicType = 0;
}
void SoundMan_ns::setMusicVolume(int value) {
@@ -330,7 +335,7 @@ void SoundMan_ns::setMusicVolume(int value) {
}
void SoundMan_ns::setMusicFile(const char *filename) {
- strcpy(_musicFile, filename);
+ Common::strlcpy(_musicFile, filename, PATH_LEN);
}
void SoundMan_ns::execute(int command, const char *parm = 0) {
diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp
index 1661f92cfe..51fb52bb21 100644
--- a/engines/sci/console.cpp
+++ b/engines/sci/console.cpp
@@ -2565,9 +2565,14 @@ bool Console::cmdVMVars(int argc, const char **argv) {
case 1:
case 2:
case 3: {
- // for global, local, temp and param, we need an index
if (argc < 3) {
- debugPrintf("Variable number must be specified for requested type\n");
+ for (int i = 0; i < s->variablesMax[varType]; ++i) {
+ curValue = &s->variables[varType][i];
+ debugPrintf("%s var %d == %04x:%04x", varNames[varType], i, PRINT_REG(*curValue));
+ printBasicVarInfo(*curValue);
+ debugPrintf("\n");
+ }
+
return true;
}
if (argc > 4) {
diff --git a/engines/sci/engine/kernel_tables.h b/engines/sci/engine/kernel_tables.h
index 3463d05e77..0ede307e6b 100644
--- a/engines/sci/engine/kernel_tables.h
+++ b/engines/sci/engine/kernel_tables.h
@@ -465,7 +465,7 @@ static SciKernelMapEntry s_kernelMap[] = {
{ MAP_CALL(CelWide), SIG_SCI16, SIGFOR_ALL, "ii(i)", NULL, kCelWide_workarounds },
#ifdef ENABLE_SCI32
{ "CelHigh", kCelHigh32, SIG_SCI32, SIGFOR_ALL, "iii", NULL, NULL },
- { "CelWide", kCelWide32, SIG_SCI32, SIGFOR_ALL, "iii", NULL, NULL },
+ { "CelWide", kCelWide32, SIG_SCI32, SIGFOR_ALL, "iii", NULL, kCelWide_workarounds },
#endif
{ MAP_CALL(CheckFreeSpace), SIG_SCI32, SIGFOR_ALL, "r.*", NULL, NULL },
{ MAP_CALL(CheckFreeSpace), SIG_SCI11, SIGFOR_ALL, "r(i)", NULL, NULL },
diff --git a/engines/sci/engine/kgraphics32.cpp b/engines/sci/engine/kgraphics32.cpp
index d5540f72b1..6c51ec4284 100644
--- a/engines/sci/engine/kgraphics32.cpp
+++ b/engines/sci/engine/kgraphics32.cpp
@@ -216,6 +216,9 @@ reg_t kTextSize32(EngineState *s, int argc, reg_t *argv) {
g_sci->_gfxText32->setFont(argv[2].toUint16());
reg_t *rect = s->_segMan->derefRegPtr(argv[0], 4);
+ if (rect == nullptr) {
+ error("kTextSize: %04x:%04x cannot be dereferenced", PRINT_REG(argv[0]));
+ }
Common::String text = s->_segMan->getString(argv[1]);
int16 maxWidth = argc > 3 ? argv[3].toSint16() : 0;
diff --git a/engines/sci/engine/kscripts.cpp b/engines/sci/engine/kscripts.cpp
index 303de079aa..6fd130bceb 100644
--- a/engines/sci/engine/kscripts.cpp
+++ b/engines/sci/engine/kscripts.cpp
@@ -260,9 +260,6 @@ reg_t kDisposeScript(EngineState *s, int argc, reg_t *argv) {
if (argc != 2) {
return s->r_acc;
} else {
- // This exists in the KQ5CD and GK1 interpreter. We know it is used
- // when GK1 starts up, before the Sierra logo.
- warning("kDisposeScript called with 2 parameters, still untested");
return argv[1];
}
}
diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp
index 0cc1e752e1..302f046458 100644
--- a/engines/sci/engine/savegame.cpp
+++ b/engines/sci/engine/savegame.cpp
@@ -806,8 +806,6 @@ void GfxPalette32::saveLoadWithSerializer(Common::Serializer &s) {
s.syncAsUint16LE(cycler->numTimesPaused);
}
}
-
- // TODO: _clutTable
}
#endif
diff --git a/engines/sci/engine/workarounds.cpp b/engines/sci/engine/workarounds.cpp
index 3832f4cf04..0cb8ff48d7 100644
--- a/engines/sci/engine/workarounds.cpp
+++ b/engines/sci/engine/workarounds.cpp
@@ -407,6 +407,7 @@ const SciWorkaroundEntry kCelWide_workarounds[] = {
{ GID_PQ2, -1, 255, 0, "DIcon", "setSize", NULL, 0, { WORKAROUND_STILLCALL, 0 } }, // when showing picture within windows, called with 2nd/3rd parameters as objects
{ GID_SQ1, 1, 255, 0, "DIcon", "setSize", NULL, 0, { WORKAROUND_STILLCALL, 0 } }, // DEMO: Called with 2nd/3rd parameters as objects when clicking on the menu - bug #5012
{ GID_FANMADE, -1, 979, 0, "DIcon", "setSize", NULL, 0, { WORKAROUND_STILLCALL, 0 } }, // In The Gem Scenario and perhaps other fanmade games, this is called with 2nd/3rd parameters as objects - bug #5144
+ { GID_LSL6HIRES, -1, 94, 0, "ll6ControlPanel", "init", NULL, 0, { WORKAROUND_STILLCALL, 0 } }, // when opening the "controls" panel from the main menu, the third argument is missing
SCI_WORKAROUNDENTRY_TERMINATOR
};
diff --git a/engines/sci/graphics/celobj32.cpp b/engines/sci/graphics/celobj32.cpp
index 693bc5f196..77d333a717 100644
--- a/engines/sci/graphics/celobj32.cpp
+++ b/engines/sci/graphics/celobj32.cpp
@@ -120,6 +120,7 @@ struct SCALER_NoScale {
const int16 _sourceY;
SCALER_NoScale(const CelObj &celObj, const int16 maxWidth, const Common::Point &scaledPosition) :
+ _row(nullptr),
_reader(celObj, FLIP ? celObj._width : maxWidth),
_lastIndex(celObj._width - 1),
_sourceX(scaledPosition.x),
@@ -166,6 +167,7 @@ struct SCALER_Scale {
static int16 _valuesY[1024];
SCALER_Scale(const CelObj &celObj, const Common::Rect &targetRect, const Common::Point &scaledPosition, const Ratio scaleX, const Ratio scaleY) :
+ _row(nullptr),
#ifndef NDEBUG
_maxX(targetRect.right - 1),
#endif
@@ -525,30 +527,30 @@ int CelObj::_nextCacheId = 1;
CelCache *CelObj::_cache = nullptr;
int CelObj::searchCache(const CelInfo32 &celInfo, int *nextInsertIndex) const {
+ *nextInsertIndex = -1;
int oldestId = _nextCacheId + 1;
- int oldestIndex = -1;
+ int oldestIndex = 0;
for (int i = 0, len = _cache->size(); i < len; ++i) {
CelCacheEntry &entry = (*_cache)[i];
- if (entry.celObj != nullptr) {
- if (entry.celObj->_info == celInfo) {
- entry.id = ++_nextCacheId;
- return i;
+ if (entry.celObj == nullptr) {
+ if (*nextInsertIndex == -1) {
+ *nextInsertIndex = i;
}
-
- if (oldestId > entry.id) {
- oldestId = entry.id;
- oldestIndex = i;
- }
- } else if (oldestIndex == -1) {
+ } else if (entry.celObj->_info == celInfo) {
+ entry.id = ++_nextCacheId;
+ return i;
+ } else if (oldestId > entry.id) {
+ oldestId = entry.id;
oldestIndex = i;
}
}
- // NOTE: Unlike the original SCI engine code, the out-param
- // here is only updated if there was not a cache hit.
- *nextInsertIndex = oldestIndex;
+ if (*nextInsertIndex == -1) {
+ *nextInsertIndex = oldestIndex;
+ }
+
return -1;
}
@@ -734,7 +736,11 @@ CelObjView::CelObjView(const GuiResourceId viewId, const int16 loopNo, const int
int cacheIndex = searchCache(_info, &cacheInsertIndex);
if (cacheIndex != -1) {
CelCacheEntry &entry = (*_cache)[cacheIndex];
- *this = *dynamic_cast<CelObjView *>(entry.celObj);
+ const CelObjView *const cachedCelObj = dynamic_cast<CelObjView *>(entry.celObj);
+ if (cachedCelObj == nullptr) {
+ error("Expected a CelObjView in cache slot %d", cacheIndex);
+ }
+ *this = *cachedCelObj;
entry.id = ++_nextCacheId;
return;
}
@@ -866,7 +872,11 @@ CelObjView *CelObjView::duplicate() const {
}
byte *CelObjView::getResPointer() const {
- return g_sci->getResMan()->findResource(ResourceId(kResourceTypeView, _info.resourceId), false)->data;
+ const Resource *const resource = g_sci->getResMan()->findResource(ResourceId(kResourceTypeView, _info.resourceId), false);
+ if (resource == nullptr) {
+ error("Failed to load view %d from resource manager", _info.resourceId);
+ }
+ return resource->data;
}
#pragma mark -
@@ -885,7 +895,11 @@ CelObjPic::CelObjPic(const GuiResourceId picId, const int16 celNo) {
int cacheIndex = searchCache(_info, &cacheInsertIndex);
if (cacheIndex != -1) {
CelCacheEntry &entry = (*_cache)[cacheIndex];
- *this = *dynamic_cast<CelObjPic *>(entry.celObj);
+ const CelObjPic *const cachedCelObj = dynamic_cast<CelObjPic *>(entry.celObj);
+ if (cachedCelObj == nullptr) {
+ error("Expected a CelObjPic in cache slot %d", cacheIndex);
+ }
+ *this = *cachedCelObj;
entry.id = ++_nextCacheId;
return;
}
@@ -979,7 +993,11 @@ CelObjPic *CelObjPic::duplicate() const {
}
byte *CelObjPic::getResPointer() const {
- return g_sci->getResMan()->findResource(ResourceId(kResourceTypePic, _info.resourceId), false)->data;
+ const Resource *const resource = g_sci->getResMan()->findResource(ResourceId(kResourceTypePic, _info.resourceId), false);
+ if (resource == nullptr) {
+ error("Failed to load pic %d from resource manager", _info.resourceId);
+ }
+ return resource->data;
}
#pragma mark -
diff --git a/engines/sci/graphics/celobj32.h b/engines/sci/graphics/celobj32.h
index 0bb4b03ae2..6e401b3df4 100644
--- a/engines/sci/graphics/celobj32.h
+++ b/engines/sci/graphics/celobj32.h
@@ -474,7 +474,7 @@ private:
bool analyzeForRemap() const;
public:
- CelObjView(GuiResourceId viewId, int16 loopNo, int16 celNo);
+ CelObjView(const GuiResourceId viewId, const int16 loopNo, const int16 celNo);
virtual ~CelObjView() override {};
using CelObj::draw;
@@ -525,7 +525,7 @@ public:
*/
int16 _priority;
- CelObjPic(GuiResourceId pictureId, int16 celNo);
+ CelObjPic(const GuiResourceId pictureId, const int16 celNo);
virtual ~CelObjPic() override {};
using CelObj::draw;
@@ -546,7 +546,7 @@ public:
*/
class CelObjMem : public CelObj {
public:
- CelObjMem(reg_t bitmap);
+ CelObjMem(const reg_t bitmap);
virtual ~CelObjMem() override {};
virtual CelObjMem *duplicate() const override;
@@ -562,7 +562,7 @@ public:
*/
class CelObjColor : public CelObj {
public:
- CelObjColor(uint8 color, int16 width, int16 height);
+ CelObjColor(const uint8 color, const int16 width, const int16 height);
virtual ~CelObjColor() override {};
using CelObj::draw;
diff --git a/engines/sci/graphics/compare.cpp b/engines/sci/graphics/compare.cpp
index 729eeeaf81..130416ff60 100644
--- a/engines/sci/graphics/compare.cpp
+++ b/engines/sci/graphics/compare.cpp
@@ -162,12 +162,20 @@ reg_t GfxCompare::kernelCantBeHere32(const reg_t curObject, const reg_t listRefe
// rects before operating on them, but this call leverages SCI16 engine
// code that operates on inclusive rects, so the rect's bottom-right
// point is not modified like in other SCI32 kernel calls
- Common::Rect checkRect(
- readSelectorValue(_segMan, curObject, SELECTOR(brLeft)),
- readSelectorValue(_segMan, curObject, SELECTOR(brTop)),
- readSelectorValue(_segMan, curObject, SELECTOR(brRight)),
- readSelectorValue(_segMan, curObject, SELECTOR(brBottom))
- );
+ Common::Rect checkRect;
+
+ // At least LSL6 hires passes invalid rectangles which trigger the
+ // isValidRect assertion in the Rect constructor; this is avoided by
+ // assigning the properties after construction and then testing the
+ // rect for validity ourselves here. SSCI does not care about whether
+ // or not the rects are valid
+ checkRect.left = readSelectorValue(_segMan, curObject, SELECTOR(brLeft));
+ checkRect.top = readSelectorValue(_segMan, curObject, SELECTOR(brTop));
+ checkRect.right = readSelectorValue(_segMan, curObject, SELECTOR(brRight));
+ checkRect.bottom = readSelectorValue(_segMan, curObject, SELECTOR(brBottom));
+ if (!checkRect.isValidRect()) {
+ return make_reg(0, 0);
+ }
uint16 result = 0;
uint16 signal = readSelectorValue(_segMan, curObject, SELECTOR(signal));
diff --git a/engines/sci/graphics/controls32.cpp b/engines/sci/graphics/controls32.cpp
index a877d8c276..faf1d7d1a2 100644
--- a/engines/sci/graphics/controls32.cpp
+++ b/engines/sci/graphics/controls32.cpp
@@ -104,10 +104,7 @@ reg_t GfxControls32::kernelEditText(const reg_t controlObject) {
bool dimmed = readSelectorValue(_segMan, controlObject, SELECTOR(dimmed));
editor.bitmap = _gfxText32->createFontBitmap(width, height, editor.textRect, editor.text, editor.foreColor, editor.backColor, editor.skipColor, editor.fontId, alignment, editor.borderColor, dimmed, true);
} else {
- Common::String title = _segMan->getString(titleObject);
- int16 titleBackColor = readSelectorValue(_segMan, controlObject, SELECTOR(titleBack));
- int16 titleForeColor = readSelectorValue(_segMan, controlObject, SELECTOR(titleFore));
- editor.bitmap = _gfxText32->createTitledBitmap(width, height, editor.textRect, editor.text, editor.foreColor, editor.backColor, editor.skipColor, editor.fontId, alignment, editor.borderColor, title, titleForeColor, titleBackColor, titleFontId, true);
+ error("Titled bitmaps are not known to be used by any game. Please submit a bug report with details about the game you were playing and what you were doing that triggered this error. Thanks!");
}
}
diff --git a/engines/sci/graphics/frameout.cpp b/engines/sci/graphics/frameout.cpp
index 6454a1eb32..64ae828a50 100644
--- a/engines/sci/graphics/frameout.cpp
+++ b/engines/sci/graphics/frameout.cpp
@@ -680,7 +680,7 @@ void GfxFrameout::calcLists(ScreenItemListList &drawLists, EraseListList &eraseL
int splitCount = splitRects(*rectlist[rectIndex], _planes[innerIndex]->_screenRect, outRects);
if (splitCount == 0) {
- if (visibleInnerPlane != nullptr) {
+ if (visibleInnerPlane != nullptr && visibleOuterPlane != nullptr) {
// same priority, or relative priority between inner/outer changed
if ((visibleOuterPlane->_priority - visibleInnerPlane->_priority) * (outerPlane->_priority - innerPlane->_priority) <= 0) {
if (outerPlane->_priority <= innerPlane->_priority) {
@@ -697,7 +697,7 @@ void GfxFrameout::calcLists(ScreenItemListList &drawLists, EraseListList &eraseL
rectlist.add(outRects[i]);
}
- if (visibleInnerPlane != nullptr) {
+ if (visibleInnerPlane != nullptr && visibleOuterPlane != nullptr) {
// same priority, or relative priority between inner/outer changed
if ((visibleOuterPlane->_priority - visibleInnerPlane->_priority) * (outerPlane->_priority - innerPlane->_priority) <= 0) {
*rectlist[rectIndex] = outerPlane->_screenRect.findIntersectingRect(innerPlane->_screenRect);
@@ -987,7 +987,7 @@ void GfxFrameout::alterVmap(const Palette &palette1, const Palette &palette2, co
if (styleRanges[paletteIndex] == style) {
int minDiff = 262140;
- int minDiffIndex;
+ int minDiffIndex = paletteIndex;
for (int i = 0; i < 236; ++i) {
if (styleRanges[i] != style) {
@@ -1007,7 +1007,7 @@ void GfxFrameout::alterVmap(const Palette &palette1, const Palette &palette2, co
if (style == 1 && styleRanges[paletteIndex] == 0) {
int minDiff = 262140;
- int minDiffIndex;
+ int minDiffIndex = paletteIndex;
for (int i = 0; i < 236; ++i) {
int r = palette2.colors[i].r;
diff --git a/engines/sci/graphics/plane32.cpp b/engines/sci/graphics/plane32.cpp
index d05e4f79e1..470986fb3c 100644
--- a/engines/sci/graphics/plane32.cpp
+++ b/engines/sci/graphics/plane32.cpp
@@ -45,8 +45,6 @@ void DrawList::add(ScreenItem *screenItem, const Common::Rect &rect) {
uint16 Plane::_nextObjectId = 20000;
Plane::Plane(const Common::Rect &gameRect, PlanePictureCodes pictureId) :
-_width(g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth),
-_height(g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight),
_pictureId(pictureId),
_mirrored(false),
_back(0),
@@ -65,8 +63,6 @@ _gameRect(gameRect) {
}
Plane::Plane(reg_t object) :
-_width(g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth),
-_height(g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight),
_priorityChanged(false),
_object(object),
_redrawAllCount(g_sci->_gfxFrameout->getScreenCount()),
@@ -97,8 +93,6 @@ _moved(0) {
Plane::Plane(const Plane &other) :
_pictureId(other._pictureId),
_mirrored(other._mirrored),
-_field_34(other._field_34), _field_38(other._field_38),
-_field_3C(other._field_3C), _field_40(other._field_40),
_back(other._back),
_object(other._object),
_priority(other._priority),
@@ -116,11 +110,7 @@ void Plane::operator=(const Plane &other) {
_mirrored = other._mirrored;
_priority = other._priority;
_back = other._back;
- _width = other._width;
- _field_34 = other._field_34;
- _height = other._height;
_screenRect = other._screenRect;
- _field_3C = other._field_3C;
_priorityChanged = other._priorityChanged;
}
@@ -183,7 +173,7 @@ void Plane::addPicInternal(const GuiResourceId pictureId, const Common::Point *p
screenItem->_pictureId = pictureId;
screenItem->_mirrorX = mirrorX;
screenItem->_priority = celObj->_priority;
- screenItem->_fixPriority = true;
+ screenItem->_fixedPriority = true;
if (position != nullptr) {
screenItem->_position = *position + celObj->_relativePosition;
} else {
@@ -769,8 +759,6 @@ void Plane::sync(const Plane *other, const Common::Rect &screenRect) {
}
convertGameRectToPlaneRect();
- _width = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth;
- _height = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight;
_screenRect = _planeRect;
// NOTE: screenRect originally was retrieved through globals
// instead of being passed into the function
diff --git a/engines/sci/graphics/plane32.h b/engines/sci/graphics/plane32.h
index 770a6fa445..c93fb5b64e 100644
--- a/engines/sci/graphics/plane32.h
+++ b/engines/sci/graphics/plane32.h
@@ -101,16 +101,6 @@ private:
static uint16 _nextObjectId;
/**
- * The dimensions of the plane, in game script
- * coordinates.
- * TODO: These are never used and are always
- * scriptWidth x scriptHeight in SCI engine? The actual
- * dimensions of the plane are always in
- * gameRect/planeRect.
- */
- int16 _width, _height;
-
- /**
* For planes that are used to render picture data, the
* resource ID of the picture to be displayed. This
* value may also be one of the special
@@ -135,10 +125,6 @@ private:
*/
bool _pictureChanged;
- // TODO: Are these ever actually used?
- int _field_34, _field_38; // probably a point or ratio
- int _field_3C, _field_40; // probably a point or ratio
-
/**
* Converts the dimensions of the game rect used by
* scripts to the dimensions of the plane rect used to
@@ -275,7 +261,11 @@ public:
* given screen rect.
*/
inline void clipScreenRect(const Common::Rect &screenRect) {
- if (_screenRect.intersects(screenRect)) {
+ // LSL6 hires creates planes with invalid rects; SSCI does not
+ // care about this, but `Common::Rect::clip` does, so we need to
+ // check whether or not the rect is actually valid before clipping
+ // and only clip valid rects
+ if (_screenRect.isValidRect() && _screenRect.intersects(screenRect)) {
_screenRect.clip(screenRect);
} else {
_screenRect.left = 0;
diff --git a/engines/sci/graphics/screen_item32.cpp b/engines/sci/graphics/screen_item32.cpp
index c3fdbb6845..fba0fa0422 100644
--- a/engines/sci/graphics/screen_item32.cpp
+++ b/engines/sci/graphics/screen_item32.cpp
@@ -55,7 +55,7 @@ _useInsetRect(false),
_z(0),
_celInfo(celInfo),
_celObj(nullptr),
-_fixPriority(false),
+_fixedPriority(false),
_position(0, 0),
_object(make_reg(0, _nextObjectId++)),
_pictureId(-1),
@@ -70,7 +70,7 @@ _useInsetRect(false),
_z(0),
_celInfo(celInfo),
_celObj(nullptr),
-_fixPriority(false),
+_fixedPriority(false),
_position(rect.left, rect.top),
_object(make_reg(0, _nextObjectId++)),
_pictureId(-1),
@@ -90,7 +90,7 @@ _useInsetRect(false),
_z(0),
_celInfo(celInfo),
_celObj(nullptr),
-_fixPriority(false),
+_fixedPriority(false),
_position(position),
_object(make_reg(0, _nextObjectId++)),
_pictureId(-1),
@@ -209,10 +209,10 @@ void ScreenItem::setFromObject(SegManager *segMan, const reg_t object, const boo
}
if (readSelectorValue(segMan, object, SELECTOR(fixPriority))) {
- _fixPriority = true;
+ _fixedPriority = true;
_priority = readSelectorValue(segMan, object, SELECTOR(priority));
} else {
- _fixPriority = false;
+ _fixedPriority = false;
writeSelectorValue(segMan, object, SELECTOR(priority), _position.y);
}
@@ -326,6 +326,9 @@ void ScreenItem::calcRects(const Plane &plane) {
mulinc(temp, celToScreenX, Ratio());
CelObjPic *celObjPic = dynamic_cast<CelObjPic *>(_celObj);
+ if (celObjPic == nullptr) {
+ error("Expected a CelObjPic");
+ }
temp.translate((celObjPic->_relativePosition.x * scriptToScreenX).toInt() - displaceX, 0);
// TODO: This is weird.
@@ -369,6 +372,9 @@ void ScreenItem::calcRects(const Plane &plane) {
}
CelObjPic *celObjPic = dynamic_cast<CelObjPic *>(_celObj);
+ if (celObjPic == nullptr) {
+ error("Expected a CelObjPic");
+ }
temp.translate(celObjPic->_relativePosition.x - (displaceX * scaleX).toInt(), celObjPic->_relativePosition.y - (celObj._displace.y * scaleY).toInt());
// TODO: This is weird.
@@ -402,7 +408,7 @@ void ScreenItem::calcRects(const Plane &plane) {
_screenRect.top = 0;
}
- if (!_fixPriority) {
+ if (!_fixedPriority) {
_priority = _z + _position.y;
}
} else {
diff --git a/engines/sci/graphics/screen_item32.h b/engines/sci/graphics/screen_item32.h
index 977d80ebad..91f54b48e9 100644
--- a/engines/sci/graphics/screen_item32.h
+++ b/engines/sci/graphics/screen_item32.h
@@ -132,7 +132,7 @@ public:
* in place. Otherwise, the priority of the screen item
* is calculated from its y-position + z-index.
*/
- bool _fixPriority;
+ bool _fixedPriority;
/**
* The rendering priority of the screen item, relative
@@ -273,7 +273,7 @@ public:
typedef StablePointerArray<ScreenItem, 250> ScreenItemListBase;
class ScreenItemList : public ScreenItemListBase {
- static bool inline sortHelper(const ScreenItem *a, const ScreenItem *b) {
+ inline static bool sortHelper(const ScreenItem *a, const ScreenItem *b) {
return *a < *b;
}
public:
diff --git a/engines/sci/graphics/text32.cpp b/engines/sci/graphics/text32.cpp
index 99ffc6e328..d1c223d5d5 100644
--- a/engines/sci/graphics/text32.cpp
+++ b/engines/sci/graphics/text32.cpp
@@ -48,12 +48,6 @@ GfxText32::GfxText32(SegManager *segMan, GfxCache *fonts) :
// Not a typo, the original engine did not initialise height, only width
_width(0),
_text(""),
- _field_20(0),
- _field_2C(2),
- _field_30(0),
- _field_34(0),
- _field_38(0),
- _field_3C(0),
_bitmap(NULL_REG) {
_fontId = _defaultFontId;
_font = _cache->getFont(_defaultFontId);
@@ -61,7 +55,6 @@ GfxText32::GfxText32(SegManager *segMan, GfxCache *fonts) :
reg_t GfxText32::createFontBitmap(int16 width, int16 height, const Common::Rect &rect, const Common::String &text, const uint8 foreColor, const uint8 backColor, const uint8 skipColor, const GuiResourceId fontId, const TextAlign alignment, const int16 borderColor, const bool dimmed, const bool doScaling) {
- _field_22 = 0;
_borderColor = borderColor;
_text = text;
_textRect = rect;
@@ -111,7 +104,6 @@ reg_t GfxText32::createFontBitmap(int16 width, int16 height, const Common::Rect
}
reg_t GfxText32::createFontBitmap(const CelInfo32 &celInfo, const Common::Rect &rect, const Common::String &text, const int16 foreColor, const int16 backColor, const GuiResourceId fontId, const int16 skipColor, const int16 borderColor, const bool dimmed) {
- _field_22 = 0;
_borderColor = borderColor;
_text = text;
_textRect = rect;
@@ -171,11 +163,6 @@ reg_t GfxText32::createFontBitmap(const CelInfo32 &celInfo, const Common::Rect &
return _bitmap;
}
-reg_t GfxText32::createTitledBitmap(const int16 width, const int16 height, const Common::Rect &textRect, const Common::String &text, const int16 foreColor, const int16 backColor, const int16 skipColor, const GuiResourceId fontId, const TextAlign alignment, const int16 borderColor, Common::String &title, const int16 titleForeColor, const int16 titleBackColor, const GuiResourceId titleFontId, const bool doScaling) {
- warning("TODO: createTitledBitmap incomplete !");
- return createFontBitmap(width, height, textRect, text, foreColor, backColor, skipColor, fontId, alignment, borderColor, false, doScaling);
-}
-
void GfxText32::setFont(const GuiResourceId fontId) {
// NOTE: In SCI engine this calls FontMgr::BuildFontTable and then a font
// table is built on the FontMgr directly; instead, because we already have
@@ -558,12 +545,7 @@ Common::Rect GfxText32::getTextSize(const Common::String &text, int16 maxWidth,
if (maxWidth >= 0) {
if (maxWidth == 0) {
- // TODO: This was hardcoded to 192, but guessing
- // that it was originally 60% of the scriptWidth
- // before the compiler took over.
- // Verify this by looking at a game that uses a
- // scriptWidth other than 320, like LSL7
- maxWidth = _scaledWidth * (scriptWidth * 0.6) / scriptWidth;
+ maxWidth = _scaledWidth * 3 / 5;
}
result.right = maxWidth;
diff --git a/engines/sci/graphics/text32.h b/engines/sci/graphics/text32.h
index 5768ea0c59..20adb3d7c7 100644
--- a/engines/sci/graphics/text32.h
+++ b/engines/sci/graphics/text32.h
@@ -304,17 +304,6 @@ private:
*/
TextAlign _alignment;
- int16 _field_20;
-
- /**
- * TODO: Document
- */
- int16 _field_22;
-
- int _field_2C, _field_30, _field_34, _field_38;
-
- int16 _field_3C;
-
/**
* The position of the text draw cursor.
*/
@@ -392,11 +381,6 @@ public:
*/
reg_t createFontBitmap(const CelInfo32 &celInfo, const Common::Rect &rect, const Common::String &text, const int16 foreColor, const int16 backColor, const GuiResourceId fontId, const int16 skipColor, const int16 borderColor, const bool dimmed);
- /**
- * Creates a font bitmap with a title.
- */
- reg_t createTitledBitmap(const int16 width, const int16 height, const Common::Rect &textRect, const Common::String &text, const int16 foreColor, const int16 backColor, const int16 skipColor, const GuiResourceId fontId, const TextAlign alignment, const int16 borderColor, Common::String &title, const int16 titleForeColor, const int16 titleBackColor, const GuiResourceId titleFontId, const bool doScaling);
-
inline int scaleUpWidth(int value) const {
const int scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth;
return (value * scriptWidth + _scaledWidth - 1) / _scaledWidth;
diff --git a/engines/scumm/actor.cpp b/engines/scumm/actor.cpp
index 3a69b5f03c..cd54c175cc 100644
--- a/engines/scumm/actor.cpp
+++ b/engines/scumm/actor.cpp
@@ -2479,6 +2479,13 @@ void ScummEngine::setActorRedrawFlags() {
_actors[j]->_needRedraw = true;
}
} else {
+ if (_game.heversion >= 72) {
+ for (j = 1; j < _numActors; j++) {
+ if (_actors[j]->_costume && _actors[j]->_heXmapNum)
+ _actors[j]->_needRedraw = true;
+ }
+ }
+
for (i = 0; i < _gdi->_numStrips; i++) {
int strip = _screenStartStrip + i;
if (testGfxAnyUsageBits(strip)) {
diff --git a/engines/scumm/he/intern_he.h b/engines/scumm/he/intern_he.h
index 72c11c95a1..7f7babc604 100644
--- a/engines/scumm/he/intern_he.h
+++ b/engines/scumm/he/intern_he.h
@@ -455,9 +455,6 @@ protected:
Sprite *_sprite;
public:
- Moonbase *_moonbase;
-
-public:
ScummEngine_v90he(OSystem *syst, const DetectorResult &dr);
~ScummEngine_v90he();
@@ -553,15 +550,8 @@ protected:
byte VAR_NUM_PALETTES;
byte VAR_NUM_UNK;
-public: // FIXME. TODO. Should be protected. Used by Moonbase
byte VAR_U32_VERSION;
byte VAR_U32_ARRAY_UNK;
- byte VAR_U32_USER_VAR_A;
- byte VAR_U32_USER_VAR_B;
- byte VAR_U32_USER_VAR_C;
- byte VAR_U32_USER_VAR_D;
- byte VAR_U32_USER_VAR_E;
- byte VAR_U32_USER_VAR_F;
};
class ScummEngine_v99he : public ScummEngine_v90he {
@@ -585,16 +575,25 @@ protected:
};
class ScummEngine_v100he : public ScummEngine_v99he {
+friend class AI;
+
protected:
ResType _heResType;
int32 _heResId;
byte _debugInputBuffer[256];
+
+public:
+ Moonbase *_moonbase;
+
public:
- ScummEngine_v100he(OSystem *syst, const DetectorResult &dr) : ScummEngine_v99he(syst, dr) {}
+ ScummEngine_v100he(OSystem *syst, const DetectorResult &dr);
+ ~ScummEngine_v100he();
virtual void resetScumm();
+ virtual void setupScummVars();
+
protected:
virtual void setupOpcodes();
@@ -640,6 +639,14 @@ protected:
void o100_getSpriteInfo();
void o100_getWizData();
void o100_getVideoData();
+
+protected:
+ byte VAR_U32_USER_VAR_A;
+ byte VAR_U32_USER_VAR_B;
+ byte VAR_U32_USER_VAR_C;
+ byte VAR_U32_USER_VAR_D;
+ byte VAR_U32_USER_VAR_E;
+ byte VAR_U32_USER_VAR_F;
};
class ScummEngine_vCUPhe : public Engine {
diff --git a/engines/scumm/he/logic/moonbase_logic.cpp b/engines/scumm/he/logic/moonbase_logic.cpp
index a32356614f..1b596fc54c 100644
--- a/engines/scumm/he/logic/moonbase_logic.cpp
+++ b/engines/scumm/he/logic/moonbase_logic.cpp
@@ -23,6 +23,7 @@
#include "scumm/he/intern_he.h"
#include "scumm/he/logic_he.h"
#include "scumm/he/moonbase/moonbase.h"
+#include "scumm/he/moonbase/ai_main.h"
namespace Scumm {
@@ -32,7 +33,7 @@ namespace Scumm {
*/
class LogicHEmoonbase : public LogicHE {
public:
- LogicHEmoonbase(ScummEngine_v90he *vm) : LogicHE(vm) {}
+ LogicHEmoonbase(ScummEngine_v100he *vm) : LogicHE(vm) { _vm1 = vm; }
int versionID();
@@ -48,10 +49,13 @@ private:
int op_set_fow_image(int op, int numArgs, int32 *args);
void op_ai_test_kludge(int op, int numArgs, int32 *args);
- void op_ai_master_control_program(int op, int numArgs, int32 *args);
+ int op_ai_master_control_program(int op, int numArgs, int32 *args);
void op_ai_reset(int op, int numArgs, int32 *args);
void op_ai_set_type(int op, int numArgs, int32 *args);
void op_ai_clean_up(int op, int numArgs, int32 *args);
+
+private:
+ ScummEngine_v100he *_vm1;
};
int LogicHEmoonbase::versionID() {
@@ -137,14 +141,12 @@ int32 LogicHEmoonbase::dispatch(int op, int numArgs, int32 *args) {
break;
case OP_SET_FOW_IMAGE:
return op_set_fow_image(op, numArgs, args);
- break;
case OP_AI_TEST_KLUDGE:
op_ai_test_kludge(op, numArgs, args);
break;
case OP_AI_MASTER_CONTROL_PROGRAM:
- op_ai_master_control_program(op, numArgs, args);
- break;
+ return op_ai_master_control_program(op, numArgs, args);
case OP_AI_RESET:
op_ai_reset(op, numArgs, args);
break;
@@ -185,9 +187,9 @@ void LogicHEmoonbase::op_dos_command(int op, int numArgs, int32 *args) {
void LogicHEmoonbase::op_set_fow_sentinel(int32 *args) {
debug(2, "op_set_fow_sentinel(%d, %d, %d)", args[0], args[1], args[2]);
- _vm->_moonbase->_fowSentinelImage = args[0];
- _vm->_moonbase->_fowSentinelState = args[1];
- _vm->_moonbase->_fowSentinelConditionBits = args[2];
+ _vm1->_moonbase->_fowSentinelImage = args[0];
+ _vm1->_moonbase->_fowSentinelState = args[1];
+ _vm1->_moonbase->_fowSentinelConditionBits = args[2];
}
void LogicHEmoonbase::op_set_fow_information(int op, int numArgs, int32 *args) {
@@ -201,7 +203,7 @@ void LogicHEmoonbase::op_set_fow_information(int op, int numArgs, int32 *args) {
debug(2, "%s", str.c_str());
- _vm->_moonbase->setFOWInfo(
+ _vm1->_moonbase->setFOWInfo(
args[0], // array
args[1], // array down dimension
args[2], // array across dimension
@@ -218,7 +220,7 @@ void LogicHEmoonbase::op_set_fow_information(int op, int numArgs, int32 *args) {
int LogicHEmoonbase::op_set_fow_image(int op, int numArgs, int32 *args) {
debug(2, "op_set_fow_image(%d)", args[0]);
- return _vm->_moonbase->setFOWImage(args[0]) ? 1 : 0;
+ return _vm1->_moonbase->setFOWImage(args[0]) ? 1 : 0;
}
void LogicHEmoonbase::op_ai_test_kludge(int op, int numArgs, int32 *args) {
@@ -226,27 +228,27 @@ void LogicHEmoonbase::op_ai_test_kludge(int op, int numArgs, int32 *args) {
LogicHE::dispatch(op, numArgs, args);
}
-void LogicHEmoonbase::op_ai_master_control_program(int op, int numArgs, int32 *args) {
- warning("STUB: op_ai_master_control_program()");
- LogicHE::dispatch(op, numArgs, args);
+int LogicHEmoonbase::op_ai_master_control_program(int op, int numArgs, int32 *args) {
+ warning("op_ai_master_control_program()");
+ return _vm1->_moonbase->_ai->masterControlProgram(numArgs, args);
}
void LogicHEmoonbase::op_ai_reset(int op, int numArgs, int32 *args) {
- warning("STUB: op_ai_reset)");
- LogicHE::dispatch(op, numArgs, args);
+ warning("op_ai_reset())");
+ _vm1->_moonbase->_ai->resetAI();
}
void LogicHEmoonbase::op_ai_set_type(int op, int numArgs, int32 *args) {
- warning("STUB: op_ai_set_type()");
- LogicHE::dispatch(op, numArgs, args);
+ warning("op_ai_set_type()");
+ _vm1->_moonbase->_ai->setAIType(numArgs, args);
}
void LogicHEmoonbase::op_ai_clean_up(int op, int numArgs, int32 *args) {
- warning("STUB: op_ai_clean_up()");
- LogicHE::dispatch(op, numArgs, args);
+ warning("op_ai_clean_up()");
+ _vm1->_moonbase->_ai->cleanUpAI();
}
-LogicHE *makeLogicHEmoonbase(ScummEngine_v90he *vm) {
+LogicHE *makeLogicHEmoonbase(ScummEngine_v100he *vm) {
return new LogicHEmoonbase(vm);
}
diff --git a/engines/scumm/he/logic_he.cpp b/engines/scumm/he/logic_he.cpp
index 366cd3be26..33f5c40464 100644
--- a/engines/scumm/he/logic_he.cpp
+++ b/engines/scumm/he/logic_he.cpp
@@ -102,7 +102,7 @@ LogicHE *LogicHE::makeLogicHE(ScummEngine_v90he *vm) {
return makeLogicHEbasketball(vm);
case GID_MOONBASE:
- return makeLogicHEmoonbase(vm);
+ return makeLogicHEmoonbase((ScummEngine_v100he *)vm);
default:
return new LogicHE(vm);
diff --git a/engines/scumm/he/logic_he.h b/engines/scumm/he/logic_he.h
index cd547f1616..5002ee9434 100644
--- a/engines/scumm/he/logic_he.h
+++ b/engines/scumm/he/logic_he.h
@@ -65,7 +65,7 @@ LogicHE *makeLogicHEfootball2002(ScummEngine_v90he *vm);
LogicHE *makeLogicHEsoccer(ScummEngine_v90he *vm);
LogicHE *makeLogicHEbaseball2001(ScummEngine_v90he *vm);
LogicHE *makeLogicHEbasketball(ScummEngine_v90he *vm);
-LogicHE *makeLogicHEmoonbase(ScummEngine_v90he *vm);
+LogicHE *makeLogicHEmoonbase(ScummEngine_v100he *vm);
} // End of namespace Scumm
diff --git a/engines/scumm/he/moonbase/ai_defenseunit.cpp b/engines/scumm/he/moonbase/ai_defenseunit.cpp
index f1f0251dc6..ab61297603 100644
--- a/engines/scumm/he/moonbase/ai_defenseunit.cpp
+++ b/engines/scumm/he/moonbase/ai_defenseunit.cpp
@@ -23,16 +23,24 @@
#include "common/rect.h"
#include "common/util.h"
#include "scumm/he/intern_he.h"
+#include "scumm/he/moonbase/moonbase.h"
#include "scumm/he/moonbase/ai_defenseunit.h"
#include "scumm/he/moonbase/ai_main.h"
namespace Scumm {
-DefenseUnit::DefenseUnit() {
+DefenseUnit::DefenseUnit(AI *ai) : _ai(ai) {
_state = DUS_ON;
+
+ _id = -1;
+ _distanceTo = 0;
+ _state = 0;
+ _radius = 0;
+ _armor = 0;
+ _cost = 0;
}
-DefenseUnit::DefenseUnit(DefenseUnit *inUnit) {
+DefenseUnit::DefenseUnit(DefenseUnit *inUnit, AI *ai) : _ai(ai) {
_id = inUnit->getID();
_pos.x = inUnit->getPosX();
_pos.y = inUnit->getPosY();
@@ -40,6 +48,7 @@ DefenseUnit::DefenseUnit(DefenseUnit *inUnit) {
_state = inUnit->getState();
_radius = inUnit->getRadius();
_armor = inUnit->getArmor();
+ _cost = inUnit->getCost();
}
DefenseUnit::~DefenseUnit() {
@@ -71,14 +80,14 @@ Common::Point *AntiAirUnit::createTargetPos(int index, int distance, int weaponT
targetPos->y = getPosY();
} else {
ratio = MAX(0, (getRadius() / distance));
- targetPos->x = getPosX() - ratio * (getPosX() - sourceX);
- targetPos->y = getPosY() - ratio * (getPosY() - sourceY);
+ targetPos->x = (int16)(getPosX() - ratio * (getPosX() - sourceX));
+ targetPos->y = (int16)(getPosY() - ratio * (getPosY() - sourceY));
}
break;
case ITEM_EMP:
- if (getRadius() + 215 > distance) { //emp radius
+ if (getRadius() + 215 > distance) { // Emp radius
double x1 = static_cast<double>(sourceX);
double y1 = static_cast<double>(sourceY);
double x2 = static_cast<double>(getPosX());
@@ -87,17 +96,17 @@ Common::Point *AntiAirUnit::createTargetPos(int index, int distance, int weaponT
double r2 = static_cast<double>(getRadius() + 3);
double d = static_cast<double>(distance);
- //formulae for calculating one point of intersection of two circles
+ // Formulae for calculating one point of intersection of two circles
float root = sqrt((((r1 + r2) * (r1 + r2)) - (d * d)) * ((d * d) - ((r2 - r1) * (r2 - r1))));
- int x = ((x1 + x2) / 2) + ((x2 - x1) * (r1 * r1 - r2 * r2)) / (2 * d * d) + ((y2 - y1) / (2 * d * d)) * root;
- int y = ((y1 + y2) / 2) + ((y2 - y1) * (r1 * r1 - r2 * r2)) / (2 * d * d) - ((x2 - x1) / (2 * d * d)) * root;
+ int x = (int)(((x1 + x2) / 2) + ((x2 - x1) * (r1 * r1 - r2 * r2)) / (2 * d * d) + ((y2 - y1) / (2 * d * d)) * root);
+ int y = (int)(((y1 + y2) / 2) + ((y2 - y1) * (r1 * r1 - r2 * r2)) / (2 * d * d) - ((x2 - x1) / (2 * d * d)) * root);
targetPos->x = x;
targetPos->y = y;
} else {
ratio = 1 - (getRadius() / static_cast<float>(distance - 20));
- targetPos->x = sourceX + ratio * (getPosX() - sourceX);
- targetPos->y = sourceY + ratio * (getPosY() - sourceY);
+ targetPos->x = (int16)(sourceX + ratio * (getPosX() - sourceX));
+ targetPos->y = (int16)(sourceY + ratio * (getPosY() - sourceY));
}
break;
@@ -123,14 +132,14 @@ int AntiAirUnit::selectWeapon(int index) {
case 2:
if (getState() == DUS_OFF) {
- if (getPlayerEnergy() > 6) {
- if (!_vm->_rnd.getRandomNumber(3)) {
+ if (_ai->getPlayerEnergy() > 6) {
+ if (!_ai->_vm->_rnd.getRandomNumber(3)) {
return ITEM_VIRUS;
}
}
- if (getPlayerEnergy() > 2) {
- if (!_vm->_rnd.getRandomNumber(1)) {
+ if (_ai->getPlayerEnergy() > 2) {
+ if (!_ai->_vm->_rnd.getRandomNumber(1)) {
return ITEM_SPIKE;
}
}
@@ -169,8 +178,8 @@ Common::Point *ShieldUnit::createTargetPos(int index, int distance, int weaponTy
case ITEM_CRAWLER:
ratio = MAX(0.0, 1.0 - (static_cast<float>(getRadius()) / static_cast<float>(distance - 20)));
{
- int maxX = getMaxX();
- int maxY = getMaxY();
+ int maxX = _ai->getMaxX();
+ int maxY = _ai->getMaxY();
int thisX = (static_cast<int>(sourceX + ratio * (getPosX() - sourceX)) + maxX) % maxX;
int thisY = (static_cast<int>(sourceY + ratio * (getPosY() - sourceY)) + maxY) % maxY;
targetPos->x = thisX;
@@ -179,7 +188,7 @@ Common::Point *ShieldUnit::createTargetPos(int index, int distance, int weaponTy
break;
case ITEM_EMP:
- if (getRadius() + 215 > distance) { //emp radius
+ if (getRadius() + 215 > distance) { // Emp radius
double x1 = static_cast<double>(sourceX);
double y1 = static_cast<double>(sourceY);
double x2 = static_cast<double>(getPosX());
@@ -188,17 +197,17 @@ Common::Point *ShieldUnit::createTargetPos(int index, int distance, int weaponTy
double r2 = static_cast<double>(getRadius() + 10);
double d = static_cast<double>(distance);
- //formulae for calculating one point of intersection of two circles
+ // Formulae for calculating one point of intersection of two circles
float root = sqrt((((r1 + r2) * (r1 + r2)) - (d * d)) * ((d * d) - ((r2 - r1) * (r2 - r1))));
- int x = ((x1 + x2) / 2) + ((x2 - x1) * (r1 * r1 - r2 * r2)) / (2 * d * d) + ((y2 - y1) / (2 * d * d)) * root;
- int y = ((y1 + y2) / 2) + ((y2 - y1) * (r1 * r1 - r2 * r2)) / (2 * d * d) - ((x2 - x1) / (2 * d * d)) * root;
+ int x = (int)(((x1 + x2) / 2) + ((x2 - x1) * (r1 * r1 - r2 * r2)) / (2 * d * d) + ((y2 - y1) / (2 * d * d)) * root);
+ int y = (int)(((y1 + y2) / 2) + ((y2 - y1) * (r1 * r1 - r2 * r2)) / (2 * d * d) - ((x2 - x1) / (2 * d * d)) * root);
targetPos->x = x;
targetPos->y = y;
} else {
ratio = 1 - (getRadius() / static_cast<float>(distance - 20));
- targetPos->x = sourceX + ratio * (getPosX() - sourceX);
- targetPos->y = sourceY + ratio * (getPosY() - sourceY);
+ targetPos->x = (int16)(sourceX + ratio * (getPosX() - sourceX));
+ targetPos->y = (int16)(sourceY + ratio * (getPosY() - sourceY));
}
if (distance < getRadius()) {
@@ -221,8 +230,8 @@ Common::Point *ShieldUnit::createTargetPos(int index, int distance, int weaponTy
int ShieldUnit::selectWeapon(int index) {
warning("Shield weapon select");
- int myUnit = getClosestUnit(getPosX(), getPosY(), getMaxX(), getCurrentPlayer(), 1, BUILDING_MAIN_BASE, 1, 0);
- int dist = getDistance(getPosX(), getPosY(), getHubX(myUnit), getHubY(myUnit));
+ int myUnit = _ai->getClosestUnit(getPosX(), getPosY(), _ai->getMaxX(), _ai->getCurrentPlayer(), 1, BUILDING_MAIN_BASE, 1, 0);
+ int dist = _ai->getDistance(getPosX(), getPosY(), _ai->getHubX(myUnit), _ai->getHubY(myUnit));
if ((dist < (getRadius() - 20)) && (dist > 90)) {
return ITEM_SPIKE;
@@ -231,7 +240,7 @@ int ShieldUnit::selectWeapon(int index) {
switch (index) {
case 0:
if (getState() == DUS_OFF) {
- if (getPlayerEnergy() < 3) {
+ if (_ai->getPlayerEnergy() < 3) {
return ITEM_BOMB;
} else {
return ITEM_SPIKE;
@@ -273,8 +282,8 @@ Common::Point *MineUnit::createTargetPos(int index, int distance, int weaponType
case ITEM_EMP:
ratio = 1 - (getRadius() / static_cast<float>(distance - 20));
- targetPos->x = sourceX + ratio * (getPosX() - sourceX);
- targetPos->y = sourceY + ratio * (getPosY() - sourceY);
+ targetPos->x = (int16)(sourceX + ratio * (getPosX() - sourceX));
+ targetPos->y = (int16)(sourceY + ratio * (getPosY() - sourceY));
break;
default:
@@ -287,11 +296,11 @@ Common::Point *MineUnit::createTargetPos(int index, int distance, int weaponType
}
int MineUnit::selectWeapon(int index) {
- int myUnit = getClosestUnit(getPosX(), getPosY(), getMaxX(), getCurrentPlayer(), 1, 0, 0, 0);
+ int myUnit = _ai->getClosestUnit(getPosX(), getPosY(), _ai->getMaxX(), _ai->getCurrentPlayer(), 1, 0, 0, 0);
int x = getPosX();
int y = getPosY();
- int dist = getDistance(x, y, getHubX(myUnit), getHubY(myUnit));
+ int dist = _ai->getDistance(x, y, _ai->getHubX(myUnit), _ai->getHubY(myUnit));
if ((getState() == DUS_ON) && (dist < 110)) {
return ITEM_EMP;
@@ -334,34 +343,34 @@ Common::Point *HubUnit::createTargetPos(int index, int distance, int weaponType,
int HubUnit::selectWeapon(int index) {
warning("Hub weapon select");
- int energy = getPlayerEnergy();
+ int energy = _ai->getPlayerEnergy();
if (energy > 6) {
//possibly choose crawler
- if (getBuildingWorth(getID()) > 21) {
+ if (_ai->getBuildingWorth(getID()) > 21) {
return ITEM_CRAWLER;
}
}
//choose betw/ bomb and cluster
- if (getBuildingArmor(getID()) < 1.5) {
+ if (_ai->getBuildingArmor(getID()) < 1.5) {
return ITEM_CLUSTER;
}
if (energy > 2) {
- if (!_vm->_rnd.getRandomNumber(3)) {
+ if (!_ai->_vm->_rnd.getRandomNumber(3)) {
return ITEM_SPIKE;
}
- if (!_vm->_rnd.getRandomNumber(4)) {
+ if (!_ai->_vm->_rnd.getRandomNumber(4)) {
return ITEM_GUIDED;
}
- if (!_vm->_rnd.getRandomNumber(4)) {
+ if (!_ai->_vm->_rnd.getRandomNumber(4)) {
return ITEM_MINE;
}
- if (!_vm->_rnd.getRandomNumber(9)) {
+ if (!_ai->_vm->_rnd.getRandomNumber(9)) {
return ITEM_EMP;
}
}
@@ -449,7 +458,6 @@ int BridgeUnit::selectWeapon(int index) {
}
}
-
Common::Point *EnergyUnit::createTargetPos(int index, int distance, int weaponType, int sourceX, int sourceY) {
Common::Point *targetPos = new Common::Point;
@@ -483,22 +491,22 @@ Common::Point *EnergyUnit::createTargetPos(int index, int distance, int weaponTy
int EnergyUnit::selectWeapon(int index) {
warning("Energy weapon select");
- int energy = getPlayerEnergy();
+ int energy = _ai->getPlayerEnergy();
if (energy > 6) {
//possibly choose crawler
- if (getBuildingWorth(getID()) > 21) {
+ if (_ai->getBuildingWorth(getID()) > 21) {
return ITEM_CRAWLER;
}
}
//choose betw/ bomb and cluster
- if (getBuildingArmor(getID()) < 1.5) {
+ if (_ai->getBuildingArmor(getID()) < 1.5) {
return ITEM_CLUSTER;
}
if (energy > 2) {
- if (!_vm->_rnd.getRandomNumber(3)) {
+ if (!_ai->_vm->_rnd.getRandomNumber(3)) {
return ITEM_EMP;
}
}
@@ -539,17 +547,17 @@ Common::Point *OffenseUnit::createTargetPos(int index, int distance, int weaponT
int OffenseUnit::selectWeapon(int index) {
warning("Offense weapon select");
- int energy = getPlayerEnergy();
+ int energy = _ai->getPlayerEnergy();
if (energy > 6) {
//possibly choose crawler
- if (getBuildingWorth(getID()) > 21) {
+ if (_ai->getBuildingWorth(getID()) > 21) {
return ITEM_CRAWLER;
}
}
//choose betw/ bomb and cluster
- if (getBuildingArmor(getID()) < 1.5) {
+ if (_ai->getBuildingArmor(getID()) < 1.5) {
return ITEM_CLUSTER;
}
@@ -589,13 +597,13 @@ Common::Point *CrawlerUnit::createTargetPos(int index, int distance, int weaponT
int CrawlerUnit::selectWeapon(int index) {
warning("Crawler weapon select");
- int myUnit = getClosestUnit(getPosX(), getPosY(), getMaxX(), getCurrentPlayer(), 1, 0, 0, 0);
- int dist = getDistance(getHubX(myUnit), getHubY(myUnit), getPosX(), getPosY());
+ int myUnit = _ai->getClosestUnit(getPosX(), getPosY(), _ai->getMaxX(), _ai->getCurrentPlayer(), 1, 0, 0, 0);
+ int dist = _ai->getDistance(_ai->getHubX(myUnit), _ai->getHubY(myUnit), getPosX(), getPosY());
int x = getPosX();
int y = getPosY();
- int energy = getPlayerEnergy();
- int terrain = getTerrain(x, y);
+ int energy = _ai->getPlayerEnergy();
+ int terrain = _ai->getTerrain(x, y);
if (terrain != TERRAIN_TYPE_WATER) {
if ((energy > 2) && (dist < 220)) {
@@ -609,7 +617,7 @@ int CrawlerUnit::selectWeapon(int index) {
}
if (energy > 2) {
- if (_vm->_rnd.getRandomNumber(1)) {
+ if (_ai->_vm->_rnd.getRandomNumber(1)) {
return ITEM_MINE;
} else {
return ITEM_TIME_EXPIRED;
@@ -620,61 +628,61 @@ int CrawlerUnit::selectWeapon(int index) {
return SKIP_TURN;
}
-AntiAirUnit::AntiAirUnit() {
+AntiAirUnit::AntiAirUnit(AI *ai) : DefenseUnit(ai) {
setRadius(190);
setArmor(3);
setCost(1);
}
-ShieldUnit::ShieldUnit() {
+ShieldUnit::ShieldUnit(AI *ai) : DefenseUnit(ai) {
setRadius(170);
setArmor(3);
setCost(7);
}
-MineUnit::MineUnit() {
+MineUnit::MineUnit(AI *ai) : DefenseUnit(ai) {
setRadius(80);
setArmor(1);
setCost(3);
}
-HubUnit::HubUnit() {
+HubUnit::HubUnit(AI *ai) : DefenseUnit(ai) {
setRadius(1);
setArmor(5);
setCost(7);
}
-TowerUnit::TowerUnit() {
+TowerUnit::TowerUnit(AI *ai) : DefenseUnit(ai) {
setRadius(1);
setArmor(3);
setCost(1);
}
-BridgeUnit::BridgeUnit() {
+BridgeUnit::BridgeUnit(AI *ai) : DefenseUnit(ai) {
setRadius(1);
setArmor(3);
setCost(1);
}
-EnergyUnit::EnergyUnit() {
+EnergyUnit::EnergyUnit(AI *ai) : DefenseUnit(ai) {
setRadius(1);
setArmor(5);
setCost(7);
}
-OffenseUnit::OffenseUnit() {
+OffenseUnit::OffenseUnit(AI *ai) : DefenseUnit(ai) {
setRadius(1);
setArmor(3);
setCost(7);
}
-CrawlerUnit::CrawlerUnit() {
+CrawlerUnit::CrawlerUnit(AI *ai) : DefenseUnit(ai) {
setRadius(1);
setArmor(3);
setCost(7);
}
-AntiAirUnit::AntiAirUnit(DefenseUnit *inUnit) : DefenseUnit(inUnit) {
+AntiAirUnit::AntiAirUnit(DefenseUnit *inUnit, AI *ai) : DefenseUnit(inUnit, ai) {
setID(inUnit->getID());
setPos(inUnit->getPosX(), inUnit->getPosY());
setDistanceTo(inUnit->getDistanceTo());
@@ -684,7 +692,7 @@ AntiAirUnit::AntiAirUnit(DefenseUnit *inUnit) : DefenseUnit(inUnit) {
}
-ShieldUnit::ShieldUnit(DefenseUnit *inUnit) : DefenseUnit(inUnit) {
+ShieldUnit::ShieldUnit(DefenseUnit *inUnit, AI *ai) : DefenseUnit(inUnit, ai) {
setID(inUnit->getID());
setPos(inUnit->getPosX(), inUnit->getPosY());
setDistanceTo(inUnit->getDistanceTo());
@@ -693,7 +701,7 @@ ShieldUnit::ShieldUnit(DefenseUnit *inUnit) : DefenseUnit(inUnit) {
setArmor(inUnit->getArmor());
}
-MineUnit::MineUnit(DefenseUnit *inUnit) : DefenseUnit(inUnit) {
+MineUnit::MineUnit(DefenseUnit *inUnit, AI *ai) : DefenseUnit(inUnit, ai) {
setID(inUnit->getID());
setPos(inUnit->getPosX(), inUnit->getPosY());
setDistanceTo(inUnit->getDistanceTo());
@@ -702,7 +710,7 @@ MineUnit::MineUnit(DefenseUnit *inUnit) : DefenseUnit(inUnit) {
setArmor(inUnit->getArmor());
}
-HubUnit::HubUnit(DefenseUnit *inUnit) : DefenseUnit(inUnit) {
+HubUnit::HubUnit(DefenseUnit *inUnit, AI *ai) : DefenseUnit(inUnit, ai) {
setID(inUnit->getID());
setPos(inUnit->getPosX(), inUnit->getPosY());
setDistanceTo(inUnit->getDistanceTo());
@@ -711,7 +719,7 @@ HubUnit::HubUnit(DefenseUnit *inUnit) : DefenseUnit(inUnit) {
setArmor(inUnit->getArmor());
}
-TowerUnit::TowerUnit(DefenseUnit *inUnit) : DefenseUnit(inUnit) {
+TowerUnit::TowerUnit(DefenseUnit *inUnit, AI *ai) : DefenseUnit(inUnit, ai) {
setID(inUnit->getID());
setPos(inUnit->getPosX(), inUnit->getPosY());
setDistanceTo(inUnit->getDistanceTo());
@@ -720,7 +728,7 @@ TowerUnit::TowerUnit(DefenseUnit *inUnit) : DefenseUnit(inUnit) {
setArmor(inUnit->getArmor());
}
-BridgeUnit::BridgeUnit(DefenseUnit *inUnit) : DefenseUnit(inUnit) {
+BridgeUnit::BridgeUnit(DefenseUnit *inUnit, AI *ai) : DefenseUnit(inUnit, ai) {
setID(inUnit->getID());
setPos(inUnit->getPosX(), inUnit->getPosY());
setDistanceTo(inUnit->getDistanceTo());
@@ -729,7 +737,7 @@ BridgeUnit::BridgeUnit(DefenseUnit *inUnit) : DefenseUnit(inUnit) {
setArmor(inUnit->getArmor());
}
-EnergyUnit::EnergyUnit(DefenseUnit *inUnit) : DefenseUnit(inUnit) {
+EnergyUnit::EnergyUnit(DefenseUnit *inUnit, AI *ai) : DefenseUnit(inUnit, ai) {
setID(inUnit->getID());
setPos(inUnit->getPosX(), inUnit->getPosY());
setDistanceTo(inUnit->getDistanceTo());
@@ -738,7 +746,7 @@ EnergyUnit::EnergyUnit(DefenseUnit *inUnit) : DefenseUnit(inUnit) {
setArmor(inUnit->getArmor());
}
-OffenseUnit::OffenseUnit(DefenseUnit *inUnit) : DefenseUnit(inUnit) {
+OffenseUnit::OffenseUnit(DefenseUnit *inUnit, AI *ai) : DefenseUnit(inUnit, ai) {
setID(inUnit->getID());
setPos(inUnit->getPosX(), inUnit->getPosY());
setDistanceTo(inUnit->getDistanceTo());
@@ -747,7 +755,7 @@ OffenseUnit::OffenseUnit(DefenseUnit *inUnit) : DefenseUnit(inUnit) {
setArmor(inUnit->getArmor());
}
-CrawlerUnit::CrawlerUnit(DefenseUnit *inUnit) : DefenseUnit(inUnit) {
+CrawlerUnit::CrawlerUnit(DefenseUnit *inUnit, AI *ai) : DefenseUnit(inUnit, ai) {
setID(inUnit->getID());
setPos(inUnit->getPosX(), inUnit->getPosY());
setDistanceTo(inUnit->getDistanceTo());
diff --git a/engines/scumm/he/moonbase/ai_defenseunit.h b/engines/scumm/he/moonbase/ai_defenseunit.h
index e658fc31ab..a6085da859 100644
--- a/engines/scumm/he/moonbase/ai_defenseunit.h
+++ b/engines/scumm/he/moonbase/ai_defenseunit.h
@@ -25,6 +25,8 @@
namespace Scumm {
+class AI;
+
enum {
DUT_ANTI_AIR = 1,
DUT_SHIELD = 2,
@@ -53,9 +55,12 @@ private:
int _armor;
int _cost;
+protected:
+ AI *_ai;
+
public:
- DefenseUnit();
- DefenseUnit(DefenseUnit *inUnit);
+ DefenseUnit(AI *ai);
+ DefenseUnit(DefenseUnit *inUnit, AI *ai);
virtual ~DefenseUnit();
@@ -90,8 +95,8 @@ class AntiAirUnit : public DefenseUnit {
private:
public:
- AntiAirUnit();
- AntiAirUnit(DefenseUnit *inUnit);
+ AntiAirUnit(AI *ai);
+ AntiAirUnit(DefenseUnit *inUnit, AI *ai);
int getType() const { return DUT_ANTI_AIR; }
Common::Point *createTargetPos(int index, int distance, int weaponType, int sourceX, int sourceY);
int selectWeapon(int index);
@@ -101,8 +106,8 @@ class ShieldUnit : public DefenseUnit {
private:
public:
- ShieldUnit();
- ShieldUnit(DefenseUnit *inUnit);
+ ShieldUnit(AI *ai);
+ ShieldUnit(DefenseUnit *inUnit, AI *ai);
int getType() const { return DUT_SHIELD; }
Common::Point *createTargetPos(int index, int distance, int weaponType, int sourceX, int sourceY);
int selectWeapon(int index);
@@ -112,8 +117,8 @@ class MineUnit : public DefenseUnit {
private:
public:
- MineUnit();
- MineUnit(DefenseUnit *inUnit);
+ MineUnit(AI *ai);
+ MineUnit(DefenseUnit *inUnit, AI *ai);
int getType() const { return DUT_MINE; }
Common::Point *createTargetPos(int index, int distance, int weaponType, int sourceX, int sourceY);
int selectWeapon(int index);
@@ -123,8 +128,8 @@ class HubUnit : public DefenseUnit {
private:
public:
- HubUnit();
- HubUnit(DefenseUnit *inUnit);
+ HubUnit(AI *ai);
+ HubUnit(DefenseUnit *inUnit, AI *ai);
int getType() const { return DUT_HUB; }
Common::Point *createTargetPos(int index, int distance, int weaponType, int sourceX, int sourceY);
int selectWeapon(int index);
@@ -134,8 +139,8 @@ class TowerUnit : public DefenseUnit {
private:
public:
- TowerUnit();
- TowerUnit(DefenseUnit *inUnit);
+ TowerUnit(AI *ai);
+ TowerUnit(DefenseUnit *inUnit, AI *ai);
int getType() const { return DUT_TOWER; }
Common::Point *createTargetPos(int index, int distance, int weaponType, int sourceX, int sourceY);
int selectWeapon(int index);
@@ -145,8 +150,8 @@ class BridgeUnit : public DefenseUnit {
private:
public:
- BridgeUnit();
- BridgeUnit(DefenseUnit *inUnit);
+ BridgeUnit(AI *ai);
+ BridgeUnit(DefenseUnit *inUnit, AI *ai);
int getType() const { return DUT_BRIDGE; }
Common::Point *createTargetPos(int index, int distance, int weaponType, int sourceX, int sourceY);
int selectWeapon(int index);
@@ -156,8 +161,8 @@ class EnergyUnit : public DefenseUnit {
private:
public:
- EnergyUnit();
- EnergyUnit(DefenseUnit *inUnit);
+ EnergyUnit(AI *ai);
+ EnergyUnit(DefenseUnit *inUnit, AI *ai);
int getType() const { return DUT_ENERGY; }
Common::Point *createTargetPos(int index, int distance, int weaponType, int sourceX, int sourceY);
int selectWeapon(int index);
@@ -167,8 +172,8 @@ class OffenseUnit : public DefenseUnit {
private:
public:
- OffenseUnit();
- OffenseUnit(DefenseUnit *inUnit);
+ OffenseUnit(AI *ai);
+ OffenseUnit(DefenseUnit *inUnit, AI *ai);
int getType() const { return DUT_OFFENSE; }
Common::Point *createTargetPos(int index, int distance, int weaponType, int sourceX, int sourceY);
int selectWeapon(int index);
@@ -178,8 +183,8 @@ class CrawlerUnit : public DefenseUnit {
private:
public:
- CrawlerUnit();
- CrawlerUnit(DefenseUnit *inUnit);
+ CrawlerUnit(AI *ai);
+ CrawlerUnit(DefenseUnit *inUnit, AI *ai);
int getType() const { return DUT_CRAWLER; }
Common::Point *createTargetPos(int index, int distance, int weaponType, int sourceX, int sourceY);
int selectWeapon(int index);
diff --git a/engines/scumm/he/moonbase/ai_main.cpp b/engines/scumm/he/moonbase/ai_main.cpp
index 1a191a1328..9c9ff8bb01 100644
--- a/engines/scumm/he/moonbase/ai_main.cpp
+++ b/engines/scumm/he/moonbase/ai_main.cpp
@@ -31,8 +31,6 @@
namespace Scumm {
-ScummEngine_v90he *_vm;
-
enum {
F_GET_SCUMM_DATA = 0,
F_GET_WORLD_DIST = 1,
@@ -154,84 +152,80 @@ enum {
TREE_DEPTH = 2
};
-AIEntity *AItype[5];
-
-int AIstate = STATE_CHOOSE_BEHAVIOR;
-int behavior = 2;
-
-patternList *moveList[5];
+AI::AI(ScummEngine_v100he *vm) : _vm(vm) {
+ memset(_aiType, 0, sizeof(_aiType));
+ _aiState = STATE_CHOOSE_BEHAVIOR;
+ _behavior = 2;
+ _energyHogType = 0;
-int *storedLaunchAction[5] = {NULL};
-
-const int *MCP_params;
-
-Common::Array<int> lastXCoord[5];
-Common::Array<int> lastYCoord[5];
+ memset(_moveList, 0, sizeof(_moveList));
+ _mcpParams = 0;
+}
-void resetAI() {
- AIstate = STATE_CHOOSE_BEHAVIOR;
+void AI::resetAI() {
+ _aiState = STATE_CHOOSE_BEHAVIOR;
warning("----------------------> Resetting AI");
for (int i = 1; i != 5; i++) {
- if (AItype[i]) {
- delete AItype[i];
- AItype[i] = NULL;
+ if (_aiType[i]) {
+ delete _aiType[i];
+ _aiType[i] = NULL;
}
- AItype[i] = new AIEntity(BRUTAKAS);
+ _aiType[i] = new AIEntity(BRUTAKAS);
}
for (int i = 1; i != 5; i++) {
- if (moveList[i]) {
- delete moveList[i];
- moveList[i] = NULL;
+ if (_moveList[i]) {
+ delete _moveList[i];
+ _moveList[i] = NULL;
}
- moveList[i] = new patternList;
+ _moveList[i] = new patternList;
}
}
-void cleanUpAI() {
+void AI::cleanUpAI() {
warning("----------------------> Cleaning Up AI");
for (int i = 1; i != 5; i++) {
- if (AItype[i]) {
- delete AItype[i];
- AItype[i] = NULL;
+ if (_aiType[i]) {
+ delete _aiType[i];
+ _aiType[i] = NULL;
}
}
for (int i = 1; i != 5; i++) {
- if (moveList[i]) {
- delete moveList[i];
- moveList[i] = NULL;
+ if (_moveList[i]) {
+ delete _moveList[i];
+ _moveList[i] = NULL;
}
}
}
-void setAIType(const int paramCount, const int *params) {
- if (AItype[params[AI_TYPE_PLAYER_NUM]]) {
- delete AItype[params[AI_TYPE_PLAYER_NUM]];
- AItype[params[AI_TYPE_PLAYER_NUM]] = NULL;
+void AI::setAIType(const int paramCount, const int32 *params) {
+ if (_aiType[params[AI_TYPE_PLAYER_NUM]]) {
+ delete _aiType[params[AI_TYPE_PLAYER_NUM]];
+ _aiType[params[AI_TYPE_PLAYER_NUM]] = NULL;
}
- AItype[params[AI_TYPE_PLAYER_NUM]] = new AIEntity(params[AI_TYPE_TYPE]);
+ _aiType[params[AI_TYPE_PLAYER_NUM]] = new AIEntity(params[AI_TYPE_TYPE]);
if (params[AI_TYPE_TYPE] == ENERGY_HOG) {
- energyHogType = 1;
+ _energyHogType = 1;
} else {
- energyHogType = 0;
+ _energyHogType = 0;
}
- warning("AI for player %d is %s", params[AI_TYPE_PLAYER_NUM], AItype[params[AI_TYPE_PLAYER_NUM]]->getNameString());
+ warning("AI for player %d is %s", params[AI_TYPE_PLAYER_NUM], _aiType[params[AI_TYPE_PLAYER_NUM]]->getNameString());
}
-int masterControlProgram(const int paramCount, const int *params) {
+int AI::masterControlProgram(const int paramCount, const int32 *params) {
static Tree *myTree;
static int index;
- MCP_params = params;
+ _mcpParams = params;
static int lastSource[5];
static int lastAngle[5];
@@ -282,7 +276,7 @@ int masterControlProgram(const int paramCount, const int *params) {
int timerValue = getTimerValue(3);
// If timer has run out
- if ((AIstate > STATE_CHOOSE_BEHAVIOR) && ((maxTime) && (timerValue > maxTime))) {
+ if ((_aiState > STATE_CHOOSE_BEHAVIOR) && ((maxTime) && (timerValue > maxTime))) {
if (myTree != NULL) {
delete myTree;
myTree = NULL;
@@ -309,41 +303,43 @@ int masterControlProgram(const int paramCount, const int *params) {
launchAction[1] = SKIP_TURN;
}
- AIstate = STATE_LAUNCH;
+ _aiState = STATE_LAUNCH;
}
- static int oldAIstate = 0;
+ static int old_aiState = 0;
- if (oldAIstate != AIstate) {
- warning("<<%d>>", AIstate);
- oldAIstate = AIstate;
+ if (old_aiState != _aiState) {
+ warning("<<%d>>", _aiState);
+ old_aiState = _aiState;
}
- switch (AIstate) {
+ switch (_aiState) {
case STATE_CHOOSE_BEHAVIOR:
- behavior = chooseBehavior();
- warning("Behavior mode: %d", behavior);
+ _behavior = chooseBehavior();
+ warning("Behavior mode: %d", _behavior);
- if (_vm->_rnd.getRandomNumber(99) < AItype[getCurrentPlayer()]->getBehaviorVariation() * AI_VAR_BASE_BEHAVIOR + 1) {
+ if ((int)_vm->_rnd.getRandomNumber(99) < _aiType[getCurrentPlayer()]->getBehaviorVariation() * AI_VAR_BASE_BEHAVIOR + 1) {
if (_vm->_rnd.getRandomNumber(1)) {
- behavior--;
+ _behavior--;
- if (behavior < ENERGY_MODE) behavior = DEFENSE_MODE;
+ if (_behavior < ENERGY_MODE)
+ _behavior = DEFENSE_MODE;
} else {
- behavior++;
+ _behavior++;
- if (behavior > DEFENSE_MODE) behavior = ENERGY_MODE;
+ if (_behavior > DEFENSE_MODE)
+ _behavior = ENERGY_MODE;
}
- warning("Alternative behavior: %d", behavior);
+ warning("Alternative behavior: %d", _behavior);
}
- if (behavior == ENERGY_MODE)
+ if (_behavior == ENERGY_MODE)
if (!getNumberOfPools())
- behavior = OFFENSE_MODE;
+ _behavior = OFFENSE_MODE;
- if (AItype[getCurrentPlayer()]->getID() == CRAWLER_CHUCKER)
- behavior = OFFENSE_MODE;
+ if (_aiType[getCurrentPlayer()]->getID() == CRAWLER_CHUCKER)
+ _behavior = OFFENSE_MODE;
if (launchAction != NULL) {
delete launchAction;
@@ -351,16 +347,16 @@ int masterControlProgram(const int paramCount, const int *params) {
}
index = 0;
- AIstate = STATE_CHOOSE_TARGET;
+ _aiState = STATE_CHOOSE_TARGET;
break;
case STATE_CHOOSE_TARGET:
- target = chooseTarget(behavior);
+ target = chooseTarget(_behavior);
if (!target)
target = chooseTarget(OFFENSE_MODE);
- if (behavior == ENERGY_MODE) {
+ if (_behavior == ENERGY_MODE) {
int energyPoolScummArray = getEnergyPoolsArray();
targetX = _vm->_moonbase->readFromArray(energyPoolScummArray, target, ENERGY_POOL_X);
targetY = _vm->_moonbase->readFromArray(energyPoolScummArray, target, ENERGY_POOL_Y);
@@ -372,9 +368,9 @@ int masterControlProgram(const int paramCount, const int *params) {
warning("Target (%d, %d) id: %d", targetX, targetY, target);
if (getFOW())
- AIstate = STATE_ATTEMPT_SEARCH;
+ _aiState = STATE_ATTEMPT_SEARCH;
else
- AIstate = STATE_INIT_APPROACH_TARGET;
+ _aiState = STATE_INIT_APPROACH_TARGET;
break;
@@ -404,7 +400,7 @@ int masterControlProgram(const int paramCount, const int *params) {
nextBuilding = _vm->_moonbase->readFromArray(unitsArray, 0, unitsCounter);
}
- _vm->nukeArray(unitsArray);
+ _vm->_moonbase->deallocateArray(unitsArray);
if (!balloonFlag) {
launchAction = new int[4];
@@ -424,26 +420,26 @@ int masterControlProgram(const int paramCount, const int *params) {
targetX = newTargetPos % getMaxX();
targetY = newTargetPos / getMaxY();
- AIstate = STATE_INIT_ACQUIRE_TARGET;
+ _aiState = STATE_INIT_ACQUIRE_TARGET;
break;
}
}
- AIstate = STATE_INIT_APPROACH_TARGET;
+ _aiState = STATE_INIT_APPROACH_TARGET;
break;
case STATE_INIT_APPROACH_TARGET:
{
int closestOL = getClosestUnit(targetX, targetY, 900, currentPlayer, 1, BUILDING_OFFENSIVE_LAUNCHER, 1);
- if (closestOL && (behavior == OFFENSE_MODE)) {
- AIstate = STATE_OFFEND_TARGET;
+ if (closestOL && (_behavior == OFFENSE_MODE)) {
+ _aiState = STATE_OFFEND_TARGET;
break;
}
}
// get closest hub...if attack mode and almost close enough, maybe throw an offense
- if ((behavior == OFFENSE_MODE) && (getPlayerEnergy() > 6)) {
+ if ((_behavior == OFFENSE_MODE) && (getPlayerEnergy() > 6)) {
if (!_vm->_rnd.getRandomNumber(2)) {
int closestHub = getClosestUnit(targetX, targetY, getMaxX(), currentPlayer, 1, BUILDING_MAIN_BASE, 1);
@@ -458,19 +454,19 @@ int masterControlProgram(const int paramCount, const int *params) {
targetX = getHubX(closestHub);
targetY = getHubY(closestHub);
- AIstate = STATE_DEFEND_TARGET;
+ _aiState = STATE_DEFEND_TARGET;
break;
}
}
}
}
- if ((behavior == OFFENSE_MODE) && (AItype[currentPlayer]->getID() == RANGER) && (getPlayerEnergy() > 2)) {
+ if ((_behavior == OFFENSE_MODE) && (_aiType[currentPlayer]->getID() == RANGER) && (getPlayerEnergy() > 2)) {
int closestHub = getClosestUnit(targetX, targetY, getMaxX(), currentPlayer, 1, BUILDING_MAIN_BASE, 1);
int dist = getDistance(targetX, targetY, getHubX(closestHub), getHubY(closestHub));
if (dist < 750) {
- AIstate = STATE_OFFEND_TARGET;
+ _aiState = STATE_OFFEND_TARGET;
break;
}
}
@@ -479,21 +475,21 @@ int masterControlProgram(const int paramCount, const int *params) {
// If no need to approach, apply appropriate behavior
if (retNode == myTree->getBaseNode()) {
- switch (behavior) {
+ switch (_behavior) {
case 0:
- AIstate = STATE_ENERGIZE_TARGET;
+ _aiState = STATE_ENERGIZE_TARGET;
break;
case 1:
- AIstate = STATE_OFFEND_TARGET;
+ _aiState = STATE_OFFEND_TARGET;
break;
case 2:
- AIstate = STATE_DEFEND_TARGET;
+ _aiState = STATE_DEFEND_TARGET;
break;
case -1:
- AIstate = STATE_LAUNCH;
+ _aiState = STATE_LAUNCH;
break;
}
@@ -507,8 +503,8 @@ int masterControlProgram(const int paramCount, const int *params) {
if (getPlayerEnergy() < 7) {
if (!_vm->_rnd.getRandomNumber(3)) {
- behavior = DEFENSE_MODE;
- AIstate = STATE_CHOOSE_TARGET;
+ _behavior = DEFENSE_MODE;
+ _aiState = STATE_CHOOSE_TARGET;
} else {
if (launchAction == NULL) {
launchAction = new int[4];
@@ -520,7 +516,7 @@ int masterControlProgram(const int paramCount, const int *params) {
launchAction[1] = SKIP_TURN;
}
- AIstate = STATE_LAUNCH;
+ _aiState = STATE_LAUNCH;
}
delete myTree;
@@ -528,7 +524,7 @@ int masterControlProgram(const int paramCount, const int *params) {
break;
}
- AIstate = STATE_CRAWLER_DECISION;
+ _aiState = STATE_CRAWLER_DECISION;
break;
// If behavior is offense, possibly just chuck a crawler
@@ -537,7 +533,7 @@ int masterControlProgram(const int paramCount, const int *params) {
// Brace just here to scope throwCrawler
int throwCrawler = 0;
- if (behavior == OFFENSE_MODE) {
+ if (_behavior == OFFENSE_MODE) {
if (getPlayerEnergy() > 6) {
int crawlerTest = _vm->_rnd.getRandomNumber(9);
@@ -546,7 +542,7 @@ int masterControlProgram(const int paramCount, const int *params) {
}
}
- if (AItype[getCurrentPlayer()]->getID() == CRAWLER_CHUCKER) {
+ if (_aiType[getCurrentPlayer()]->getID() == CRAWLER_CHUCKER) {
if (getPlayerEnergy() > 6) {
throwCrawler = 1;
} else {
@@ -557,7 +553,7 @@ int masterControlProgram(const int paramCount, const int *params) {
else
launchAction[1] = SKIP_TURN;
- AIstate = STATE_LAUNCH;
+ _aiState = STATE_LAUNCH;
delete myTree;
myTree = NULL;
}
@@ -585,11 +581,11 @@ int masterControlProgram(const int paramCount, const int *params) {
targetX = (targetX + getMaxX()) % getMaxX();
targetY = (targetY + getMaxY()) % getMaxY();
- AIstate = STATE_INIT_ACQUIRE_TARGET;
+ _aiState = STATE_INIT_ACQUIRE_TARGET;
delete myTree;
myTree = NULL;
} else {
- AIstate = STATE_APPROACH_TARGET;
+ _aiState = STATE_APPROACH_TARGET;
}
break;
}
@@ -612,7 +608,7 @@ int masterControlProgram(const int paramCount, const int *params) {
delete launchAction;
launchAction = NULL;
- AIstate = STATE_DEFEND_TARGET;
+ _aiState = STATE_DEFEND_TARGET;
delete myTree;
myTree = NULL;
break;
@@ -625,8 +621,8 @@ int masterControlProgram(const int paramCount, const int *params) {
targetX = (targetX + getMaxX()) % getMaxX();
targetY = (targetY + getMaxY()) % getMaxY();
- AIstate = STATE_INIT_ACQUIRE_TARGET;
- behavior = -1;
+ _aiState = STATE_INIT_ACQUIRE_TARGET;
+ _behavior = -1;
delete myTree;
myTree = NULL;
@@ -644,10 +640,10 @@ int masterControlProgram(const int paramCount, const int *params) {
if (launchAction[1] == ITEM_HUB) {
index = 0;
retNodeFlag = 0;
- AIstate = STATE_INIT_ACQUIRE_TARGET;
+ _aiState = STATE_INIT_ACQUIRE_TARGET;
} else {
index = 0;
- AIstate = STATE_INIT_ACQUIRE_TARGET;
+ _aiState = STATE_INIT_ACQUIRE_TARGET;
}
} else {
index++;
@@ -655,10 +651,10 @@ int masterControlProgram(const int paramCount, const int *params) {
launchAction = NULL;
}
} else {
- behavior = DEFENSE_MODE;
+ _behavior = DEFENSE_MODE;
retNodeFlag = 0;
index = 0;
- AIstate = STATE_CHOOSE_TARGET;
+ _aiState = STATE_CHOOSE_TARGET;
}
break;
@@ -668,7 +664,7 @@ int masterControlProgram(const int paramCount, const int *params) {
if (launchAction != NULL) {
if (launchAction[0]) {
retNodeFlag = 0;
- AIstate = STATE_INIT_ACQUIRE_TARGET;
+ _aiState = STATE_INIT_ACQUIRE_TARGET;
} else {
index++;
delete launchAction;
@@ -683,7 +679,7 @@ int masterControlProgram(const int paramCount, const int *params) {
if (launchAction != NULL) {
if (launchAction[0]) {
retNodeFlag = 0;
- AIstate = STATE_INIT_ACQUIRE_TARGET;
+ _aiState = STATE_INIT_ACQUIRE_TARGET;
if (launchAction[LAUNCH_UNIT] != ITEM_BRIDGE) {
if (OLflag) {
@@ -709,7 +705,7 @@ int masterControlProgram(const int paramCount, const int *params) {
myTree = initAcquireTarget(targetX, targetY, &retNode);
if (myTree == NULL) {
- AIstate = STATE_LAUNCH;
+ _aiState = STATE_LAUNCH;
break;
}
@@ -719,7 +715,7 @@ int masterControlProgram(const int paramCount, const int *params) {
_acquireTarget = 0;
- AIstate = STATE_ACQUIRE_TARGET;
+ _aiState = STATE_ACQUIRE_TARGET;
break;
case STATE_ACQUIRE_TARGET: {
@@ -761,7 +757,7 @@ int masterControlProgram(const int paramCount, const int *params) {
assert(launchAction != NULL);
delete myTree;
myTree = NULL;
- AIstate = STATE_LAUNCH;
+ _aiState = STATE_LAUNCH;
}
}
break;
@@ -770,7 +766,7 @@ int masterControlProgram(const int paramCount, const int *params) {
break;
}
- if (AIstate == STATE_LAUNCH) {
+ if (_aiState == STATE_LAUNCH) {
static float randomAttenuation = 1;
if (((launchAction[LAUNCH_UNIT] == ITEM_REPAIR) || (launchAction[LAUNCH_UNIT] == ITEM_ANTIAIR) || (launchAction[LAUNCH_UNIT] == ITEM_BRIDGE) || (launchAction[LAUNCH_UNIT] == ITEM_TOWER) || (launchAction[LAUNCH_UNIT] == ITEM_RECLAIMER) || (launchAction[LAUNCH_UNIT] == ITEM_BALLOON) || (launchAction[LAUNCH_UNIT] == ITEM_MINE) || (launchAction[LAUNCH_UNIT] == ITEM_ENERGY) || (launchAction[LAUNCH_UNIT] == ITEM_SHIELD) || (launchAction[LAUNCH_UNIT] == ITEM_OFFENSE) || (launchAction[LAUNCH_UNIT] == ITEM_HUB)) && (getBuildingType(launchAction[LAUNCH_SOURCE_HUB]) == BUILDING_OFFENSIVE_LAUNCHER)) {
@@ -821,8 +817,7 @@ int masterControlProgram(const int paramCount, const int *params) {
{
// ANGLE setting
- int angleAdjustment = 0;
- angleAdjustment = _vm->_rnd.getRandomNumber(AItype[getCurrentPlayer()]->getAngleVariation() * AI_VAR_BASE_ANGLE) * 3.6;
+ int angleAdjustment = (int)(_vm->_rnd.getRandomNumber(_aiType[getCurrentPlayer()]->getAngleVariation() * AI_VAR_BASE_ANGLE) * 3.6);
//pos or neg choice
angleAdjustment *= ((_vm->_rnd.getRandomNumber(1) * 2) - 1);
angleAdjustment *= randomAttenuation;
@@ -854,7 +849,7 @@ int masterControlProgram(const int paramCount, const int *params) {
{
// POWER setting
int powerRangeFactor = (getMaxPower() - getMinPower()) / 100;
- int powerAdjustment = static_cast<float>(_vm->_rnd.getRandomNumber(AItype[getCurrentPlayer()]->getPowerVariation() * AI_VAR_BASE_POWER)) * powerRangeFactor;
+ int powerAdjustment = static_cast<float>(_vm->_rnd.getRandomNumber(_aiType[getCurrentPlayer()]->getPowerVariation() * AI_VAR_BASE_POWER)) * powerRangeFactor;
//pos or neg choice
powerAdjustment *= ((_vm->_rnd.getRandomNumber(1) * 2) - 1);
powerAdjustment *= randomAttenuation;
@@ -904,7 +899,7 @@ int masterControlProgram(const int paramCount, const int *params) {
opponentBuilding = _vm->_moonbase->readFromArray(nearbyOpponents, 0, opponentCounter);
}
- _vm->nukeArray(nearbyOpponents);
+ _vm->_moonbase->deallocateArray(nearbyOpponents);
if (defenseOn && defenseOff) {
if (!_vm->_rnd.getRandomNumber(1)) {
@@ -936,10 +931,10 @@ int masterControlProgram(const int paramCount, const int *params) {
}
}
- delete launchAction;
+ delete[] launchAction;
launchAction = NULL;
- AIstate = STATE_CHOOSE_BEHAVIOR;
+ _aiState = STATE_CHOOSE_BEHAVIOR;
int rSh, rU, rP, rA = 0;
rSh = _vm->readVar(_vm->VAR_U32_USER_VAR_A);
@@ -951,11 +946,11 @@ int masterControlProgram(const int paramCount, const int *params) {
{
// Checking for patterns
- if ((AItype[currentPlayer]->getID() != CRAWLER_CHUCKER) &&
- (AItype[currentPlayer]->getID() != ENERGY_HOG) && (getBuildingStackPtr() > 5))
- moveList[currentPlayer]->addPattern(rSh, rU, rP, rA);
+ if ((_aiType[currentPlayer]->getID() != CRAWLER_CHUCKER) &&
+ (_aiType[currentPlayer]->getID() != ENERGY_HOG) && (getBuildingStackPtr() > 5))
+ _moveList[currentPlayer]->addPattern(rSh, rU, rP, rA);
- int patternFound = moveList[currentPlayer]->evaluatePattern(rSh, rU, rP, rA);
+ int patternFound = _moveList[currentPlayer]->evaluatePattern(rSh, rU, rP, rA);
if (!_vm->_rnd.getRandomNumber(9))
patternFound = 0;
@@ -964,26 +959,26 @@ int masterControlProgram(const int paramCount, const int *params) {
warning("------------------------------------------>Eliminating pattern");
if (_vm->_rnd.getRandomNumber(1)) {
- behavior--;
+ _behavior--;
- if (behavior < ENERGY_MODE)
- behavior = DEFENSE_MODE;
+ if (_behavior < ENERGY_MODE)
+ _behavior = DEFENSE_MODE;
} else {
- behavior++;
+ _behavior++;
- if (behavior > DEFENSE_MODE)
- behavior = ENERGY_MODE;
+ if (_behavior > DEFENSE_MODE)
+ _behavior = ENERGY_MODE;
}
- if (behavior == ENERGY_MODE)
+ if (_behavior == ENERGY_MODE)
if (!getNumberOfPools())
- behavior = OFFENSE_MODE;
+ _behavior = OFFENSE_MODE;
_vm->writeVar(_vm->VAR_U32_USER_VAR_A, 0);
_vm->writeVar(_vm->VAR_U32_USER_VAR_B, 0);
_vm->writeVar(_vm->VAR_U32_USER_VAR_C, 0);
_vm->writeVar(_vm->VAR_U32_USER_VAR_D, 0);
- AIstate = STATE_CHOOSE_TARGET;
+ _aiState = STATE_CHOOSE_TARGET;
}
}
@@ -1015,7 +1010,7 @@ int masterControlProgram(const int paramCount, const int *params) {
if (selectedUnit) {
if (selectedUnit > 0)
- _vm->writeVar(_vm->VAR_U32_USER_VAR_E, behavior);
+ _vm->writeVar(_vm->VAR_U32_USER_VAR_E, _behavior);
else
_vm->writeVar(_vm->VAR_U32_USER_VAR_E, -999);
}
@@ -1023,102 +1018,62 @@ int masterControlProgram(const int paramCount, const int *params) {
return 1;
}
-int chooseBehavior() {
+int AI::chooseBehavior() {
static int dominantMode = 0;
- int modeValue[3];
-
- const int DEFAULT_SCALE = 5;
-
if (getBuildingStackPtr() < 5)
return OFFENSE_MODE;
int currentPlayer = getCurrentPlayer();
- int AIpersonality = AItype[currentPlayer]->getID();
+ int AIpersonality = _aiType[currentPlayer]->getID();
switch (AIpersonality) {
case BRUTAKAS:
- modeValue[ENERGY_MODE] = DEFAULT_SCALE;
- modeValue[OFFENSE_MODE] = 2 * DEFAULT_SCALE;
- modeValue[DEFENSE_MODE] = 0;
dominantMode = OFFENSE_MODE;
break;
case AGI:
- modeValue[ENERGY_MODE] = DEFAULT_SCALE;
- modeValue[OFFENSE_MODE] = 0;
- modeValue[DEFENSE_MODE] = 2 * DEFAULT_SCALE;
dominantMode = DEFENSE_MODE;
break;
case EL_GATO:
- modeValue[ENERGY_MODE] = 2 * DEFAULT_SCALE;
- modeValue[OFFENSE_MODE] = DEFAULT_SCALE;
- modeValue[DEFENSE_MODE] = 0;
dominantMode = ENERGY_MODE;
break;
case PIXELAHT:
- modeValue[ENERGY_MODE] = DEFAULT_SCALE;
- modeValue[OFFENSE_MODE] = 0;
- modeValue[DEFENSE_MODE] = DEFAULT_SCALE;
dominantMode = DEFENSE_MODE;
break;
case CYBALL:
- modeValue[ENERGY_MODE] = 0;
- modeValue[OFFENSE_MODE] = 0;
- modeValue[DEFENSE_MODE] = 0;
dominantMode = ENERGY_MODE;
break;
case NEEP:
- modeValue[ENERGY_MODE] = 0;
- modeValue[OFFENSE_MODE] = DEFAULT_SCALE;
- modeValue[DEFENSE_MODE] = DEFAULT_SCALE;
dominantMode = DEFENSE_MODE;
break;
case WARCUPINE:
- modeValue[ENERGY_MODE] = 5 * DEFAULT_SCALE;
- modeValue[OFFENSE_MODE] = DEFAULT_SCALE;
- modeValue[DEFENSE_MODE] = 0;
dominantMode = ENERGY_MODE;
break;
case AONE:
- modeValue[ENERGY_MODE] = 0;
- modeValue[OFFENSE_MODE] = DEFAULT_SCALE;
- modeValue[DEFENSE_MODE] = 2 * DEFAULT_SCALE;
dominantMode = DEFENSE_MODE;
break;
case SPANDO:
- modeValue[ENERGY_MODE] = DEFAULT_SCALE;
- modeValue[OFFENSE_MODE] = DEFAULT_SCALE;
- modeValue[DEFENSE_MODE] = DEFAULT_SCALE;
dominantMode = ENERGY_MODE;
break;
case ORBNU_LUNATEK:
- modeValue[ENERGY_MODE] = 0;
- modeValue[OFFENSE_MODE] = 0;
- modeValue[DEFENSE_MODE] = 0;
dominantMode = ENERGY_MODE;
break;
case CRAWLER_CHUCKER:
- modeValue[ENERGY_MODE] = 0;
- modeValue[OFFENSE_MODE] = 2 * DEFAULT_SCALE;
- modeValue[DEFENSE_MODE] = 0;
dominantMode = OFFENSE_MODE;
break;
case ENERGY_HOG:
- modeValue[ENERGY_MODE] = 2 * DEFAULT_SCALE;
- modeValue[OFFENSE_MODE] = 0;
- modeValue[DEFENSE_MODE] = 0;
dominantMode = ENERGY_MODE;
{
int breakFlag = 0;
@@ -1133,9 +1088,6 @@ int chooseBehavior() {
break;
case RANGER:
- modeValue[ENERGY_MODE] = 2 * DEFAULT_SCALE;
- modeValue[OFFENSE_MODE] = 0;
- modeValue[DEFENSE_MODE] = 0;
dominantMode = OFFENSE_MODE;
//random chance of defense if really early in game, otherwise offense
@@ -1146,9 +1098,6 @@ int chooseBehavior() {
break;
default: //BRUTAKAS
- modeValue[ENERGY_MODE] = DEFAULT_SCALE;
- modeValue[OFFENSE_MODE] = 2 * DEFAULT_SCALE;
- modeValue[DEFENSE_MODE] = 0;
dominantMode = OFFENSE_MODE;
break;
}
@@ -1207,7 +1156,7 @@ int chooseBehavior() {
energyBuilding = _vm->_moonbase->readFromArray(energyUnits, 0, energyCounter);
}
- _vm->nukeArray(energyUnits);
+ _vm->_moonbase->deallocateArray(energyUnits);
if (energyCount < poolMaxCount) {
int closestHub = getClosestUnit(poolX, poolY, 300, currentPlayer, 1, BUILDING_MAIN_BASE, 1);
@@ -1300,7 +1249,7 @@ int chooseBehavior() {
defenseBuilding = _vm->_moonbase->readFromArray(defArray, 0, defCounter);
}
- _vm->nukeArray(defArray);
+ _vm->_moonbase->deallocateArray(defArray);
if (!numDefenders) {
int defArray2 = getUnitsWithinRadius(hubX, hubY, 170);
@@ -1319,7 +1268,7 @@ int chooseBehavior() {
defenseBuilding2 = _vm->_moonbase->readFromArray(defArray, 0, defCounter);
}
- _vm->nukeArray(defArray2);
+ _vm->_moonbase->deallocateArray(defArray2);
}
@@ -1357,7 +1306,7 @@ int chooseBehavior() {
}
}
- _vm->nukeArray(enemyArray);
+ _vm->_moonbase->deallocateArray(enemyArray);
offCon--;
}
@@ -1406,7 +1355,7 @@ int chooseBehavior() {
closeBuilding = _vm->_moonbase->readFromArray(closeBuildingsArray, 0, closeBuildingCounter);
}
- _vm->nukeArray(closeBuildingsArray);
+ _vm->_moonbase->deallocateArray(closeBuildingsArray);
int defCounter = 0;
int defArray = getUnitsWithinRadius(hubX, hubY, 170);
@@ -1425,7 +1374,7 @@ int chooseBehavior() {
defenseBuilding = _vm->_moonbase->readFromArray(defArray, 0, defCounter);
}
- _vm->nukeArray(defArray);
+ _vm->_moonbase->deallocateArray(defArray);
if (numDefenders > 2)
defCon++;
@@ -1463,7 +1412,7 @@ int chooseBehavior() {
defCon += 2;
}
- warning("%s-------------------------------> Energy: %d Offense: %d Defense: %d", AItype[currentPlayer]->getNameString(), eneCon, offCon, defCon);
+ warning("%s-------------------------------> Energy: %d Offense: %d Defense: %d", _aiType[currentPlayer]->getNameString(), eneCon, offCon, defCon);
if (dominantMode == DEFENSE_MODE)
if ((defCon <= offCon) && (defCon <= eneCon))
@@ -1489,7 +1438,7 @@ int chooseBehavior() {
return -1;
}
-int chooseTarget(int behavior1) {
+int AI::chooseTarget(int behavior) {
int numPools = getNumberOfPools();
int currentPlayer = getCurrentPlayer();
@@ -1497,7 +1446,7 @@ int chooseTarget(int behavior1) {
int selectionValues[50] = {0};
int selectionDist = 10000000;
- if (behavior1 == ENERGY_MODE) {
+ if (behavior == ENERGY_MODE) {
// loop through energy pool array
int energyPoolScummArray = getEnergyPoolsArray();
@@ -1524,7 +1473,7 @@ int chooseTarget(int behavior1) {
thisPoolUnit = _vm->_moonbase->readFromArray(poolUnitsArray, 0, j);
}
- _vm->nukeArray(poolUnitsArray);
+ _vm->_moonbase->deallocateArray(poolUnitsArray);
// if enemy collector, put at bottom
if (enemyPool) {
@@ -1558,7 +1507,7 @@ int chooseTarget(int behavior1) {
return selection;
}
- if (behavior1 == OFFENSE_MODE) {
+ if (behavior == OFFENSE_MODE) {
int returnBuilding = 0;
int attackableArray[500];
int nearAttackableArray[500];
@@ -1575,7 +1524,7 @@ int chooseTarget(int behavior1) {
if ((getTerrain(getHubX(thisBuilding), getHubY(thisBuilding)) != TERRAIN_TYPE_WATER) || (getPlayerEnergy() > 6)) {
if (getClosestUnit(getHubX(thisBuilding), getHubY(thisBuilding), 380, currentPlayer, 1, BUILDING_MAIN_BASE, 1)) {
returnBuilding = thisBuilding;
- _vm->nukeArray(enemyArray);
+ _vm->_moonbase->deallocateArray(enemyArray);
return returnBuilding;
}
} else {
@@ -1601,7 +1550,7 @@ int chooseTarget(int behavior1) {
}
}
- _vm->nukeArray(enemyArray);
+ _vm->_moonbase->deallocateArray(enemyArray);
if (attackableIndex) {
int thisWorth = 0;
@@ -1690,7 +1639,7 @@ int chooseTarget(int behavior1) {
return returnBuilding;
}
- if (behavior1 == DEFENSE_MODE) {
+ if (behavior == DEFENSE_MODE) {
int returnBuilding = 0;
int savedTally = 0;
@@ -1761,7 +1710,7 @@ int chooseTarget(int behavior1) {
defenseBuilding = _vm->_moonbase->readFromArray(defenseArray, 0, j);
}
- _vm->nukeArray(defenseArray);
+ _vm->_moonbase->deallocateArray(defenseArray);
// Calculate if this unit is attackable
// get dist to nearest enemy hub, offense
@@ -1848,15 +1797,15 @@ int chooseTarget(int behavior1) {
return 0;
}
-Tree *initApproachTarget(int targetX, int targetY, Node **retNode) {
+Tree *AI::initApproachTarget(int targetX, int targetY, Node **retNode) {
int sourceHub = 0;
- if (behavior == 2)
+ if (_behavior == 2)
sourceHub = getClosestUnit(targetX + 10, targetY, getMaxX(), getCurrentPlayer(), 1, BUILDING_MAIN_BASE, 1);
else
sourceHub = getClosestUnit(targetX + 10, targetY, getMaxX(), getCurrentPlayer(), 1, BUILDING_MAIN_BASE, 1, MIN_DIST);
- Traveller *myTraveller = new Traveller(getHubX(sourceHub), getHubY(sourceHub));
+ Traveller *myTraveller = new Traveller(getHubX(sourceHub), getHubY(sourceHub), this);
myTraveller->setSourceHub(sourceHub);
//target adjustment so that room is allowed for the appropriate shot
@@ -1868,17 +1817,17 @@ Tree *initApproachTarget(int targetX, int targetY, Node **retNode) {
Traveller::setTargetPosY(targetY + adjY);
Traveller::setMaxDist(340);
- Tree *myTree = new Tree(myTraveller, TREE_DEPTH);
+ Tree *myTree = new Tree(myTraveller, TREE_DEPTH, this);
*retNode = myTree->aStarSearch_singlePassInit();
return myTree;
}
-int *approachTarget(Tree *myTree, int &xTarget, int &yTarget, Node **currentNode) {
+int *AI::approachTarget(Tree *myTree, int &xTarget, int &yTarget, Node **currentNode) {
int *retVal = NULL;
*currentNode = NULL;
- Node *retNode = myTree->aStarSearch_singlePass(currentNode);
+ Node *retNode = myTree->aStarSearch_singlePass();
if (*currentNode != NULL)
warning("########################################### Got a possible solution");
@@ -1928,13 +1877,13 @@ int *approachTarget(Tree *myTree, int &xTarget, int &yTarget, Node **currentNode
int whoseTurn = getCurrentPlayer();
- if ((lastXCoord[whoseTurn]).size() >= MAX_MEMORY) {
- (lastXCoord[whoseTurn]).erase((lastXCoord[whoseTurn]).begin());
- (lastYCoord[whoseTurn]).erase((lastYCoord[whoseTurn]).begin());
+ if ((_lastXCoord[whoseTurn]).size() >= MAX_MEMORY) {
+ (_lastXCoord[whoseTurn]).erase((_lastXCoord[whoseTurn]).begin());
+ (_lastYCoord[whoseTurn]).erase((_lastYCoord[whoseTurn]).begin());
}
- (lastXCoord[whoseTurn]).push_back(retTraveller->getPosX());
- (lastYCoord[whoseTurn]).push_back(retTraveller->getPosY());
+ (_lastXCoord[whoseTurn]).push_back(retTraveller->getPosX());
+ (_lastYCoord[whoseTurn]).push_back(retTraveller->getPosY());
int temp = static_cast<int>(retTraveller->calcT());
int temp2 = static_cast<int>(retTraveller->getValueG());
@@ -1948,13 +1897,13 @@ int *approachTarget(Tree *myTree, int &xTarget, int &yTarget, Node **currentNode
return retVal;
}
-Tree *initAcquireTarget(int targetX, int targetY, Node **retNode) {
+Tree *AI::initAcquireTarget(int targetX, int targetY, Node **retNode) {
int sourceHub = getClosestUnit(targetX, targetY, getMaxX(), getCurrentPlayer(), 1, BUILDING_MAIN_BASE, 1, MIN_DIST);
warning("My coords (%d): %d %d", sourceHub, getHubX(sourceHub), getHubY(sourceHub));
Sortie::setSourcePos(getHubX(sourceHub), getHubY(sourceHub));
Sortie::setTargetPos(targetX, targetY);
- Sortie *myBaseTarget = new Sortie();
+ Sortie *myBaseTarget = new Sortie(this);
myBaseTarget->setValueG(0);
myBaseTarget->setUnitType(ITEM_BOMB);
@@ -1968,26 +1917,24 @@ Tree *initAcquireTarget(int targetX, int targetY, Node **retNode) {
int thisElement = _vm->_moonbase->readFromArray(unitsArray, 0, 0);
- _vm->nukeArray(unitsArray);
+ _vm->_moonbase->deallocateArray(unitsArray);
if (!thisElement) {
delete myBaseTarget;
return NULL;
}
- Tree *myTree = new Tree(myBaseTarget, 4);
+ Tree *myTree = new Tree(myBaseTarget, 4, this);
*retNode = myTree->aStarSearch_singlePassInit();
return myTree;
}
-
-int *acquireTarget(int targetX, int targetY, Tree *myTree, int &errorCode) {
+int *AI::acquireTarget(int targetX, int targetY, Tree *myTree, int &errorCode) {
int currentPlayer = getCurrentPlayer();
int *retVal = NULL;
- Node *currentNode = NULL;
- Node *retNode = myTree->aStarSearch_singlePass(&currentNode);
+ Node *retNode = myTree->aStarSearch_singlePass();
if (myTree->IsBaseNode(retNode))
return acquireTarget(targetX, targetY);
@@ -2049,7 +1996,7 @@ int *acquireTarget(int targetX, int targetY, Tree *myTree, int &errorCode) {
return retVal;
}
-int *acquireTarget(int targetX, int targetY) {
+int *AI::acquireTarget(int targetX, int targetY) {
int *retVal = new int[4];
int sourceHub = getClosestUnit(targetX, targetY, getMaxX(), getCurrentPlayer(), 1, BUILDING_MAIN_BASE, 1, 110);
@@ -2067,7 +2014,7 @@ int *acquireTarget(int targetX, int targetY) {
return retVal;
}
-int *energizeTarget(int &targetX, int &targetY, int index) {
+int *AI::energizeTarget(int &targetX, int &targetY, int index) {
int n = 10;
static int currentPlayer = 0;
static int pool = 0;
@@ -2106,7 +2053,7 @@ int *energizeTarget(int &targetX, int &targetY, int index) {
}
if (poolUnitsArray)
- _vm->nukeArray(poolUnitsArray);
+ _vm->_moonbase->deallocateArray(poolUnitsArray);
poolUnitsArray = getUnitsWithinRadius(targetX, targetY, 450);
assert(poolUnitsArray);
@@ -2219,14 +2166,14 @@ int *energizeTarget(int &targetX, int &targetY, int index) {
if (nextUnit <= 0)
retVal[0] = 0;
- _vm->nukeArray(poolUnitsArray);
+ _vm->_moonbase->deallocateArray(poolUnitsArray);
poolUnitsArray = 0;
return retVal;
}
}
if (result > 0) {
- _vm->nukeArray(poolUnitsArray);
+ _vm->_moonbase->deallocateArray(poolUnitsArray);
poolUnitsArray = 0;
targetX = xPos;
@@ -2249,7 +2196,7 @@ int *energizeTarget(int &targetX, int &targetY, int index) {
} else {
int *retVal = new int[4];
retVal[0] = 0;
- _vm->nukeArray(poolUnitsArray);
+ _vm->_moonbase->deallocateArray(poolUnitsArray);
poolUnitsArray = 0;
return retVal;
@@ -2268,12 +2215,12 @@ int *energizeTarget(int &targetX, int &targetY, int index) {
j = 0;
}
} else {
- _vm->nukeArray(poolUnitsArray);
+ _vm->_moonbase->deallocateArray(poolUnitsArray);
poolUnitsArray = 0;
return NULL;
}
- _vm->nukeArray(poolUnitsArray);
+ _vm->_moonbase->deallocateArray(poolUnitsArray);
poolUnitsArray = 0;
int *retVal = new int[4];
retVal[0] = 0;
@@ -2281,7 +2228,7 @@ int *energizeTarget(int &targetX, int &targetY, int index) {
return retVal;
}
-int *offendTarget(int &targetX, int &targetY, int index) {
+int *AI::offendTarget(int &targetX, int &targetY, int index) {
int *retVal = NULL;
int target = getClosestUnit(targetX + 10, targetY, 20, 0, 0, 0, 0);
@@ -2297,35 +2244,35 @@ int *offendTarget(int &targetX, int &targetY, int index) {
switch (type) {
case BUILDING_OFFENSIVE_LAUNCHER:
- thisUnit = new OffenseUnit();
+ thisUnit = new OffenseUnit(this);
break;
case BUILDING_TOWER:
- thisUnit = new TowerUnit();
+ thisUnit = new TowerUnit(this);
break;
case BUILDING_MAIN_BASE:
- thisUnit = new HubUnit();
+ thisUnit = new HubUnit(this);
break;
case BUILDING_ENERGY_COLLECTOR:
- thisUnit = new EnergyUnit();
+ thisUnit = new EnergyUnit(this);
break;
case BUILDING_CRAWLER:
- thisUnit = new CrawlerUnit();
+ thisUnit = new CrawlerUnit(this);
break;
case BUILDING_BRIDGE:
- thisUnit = new BridgeUnit();
+ thisUnit = new BridgeUnit(this);
break;
case BUILDING_SHIELD:
- thisUnit = new ShieldUnit();
+ thisUnit = new ShieldUnit(this);
break;
default:
- thisUnit = new HubUnit();
+ thisUnit = new HubUnit(this);
break;
}
@@ -2399,9 +2346,9 @@ int *offendTarget(int &targetX, int &targetY, int index) {
return retVal;
}
-int *defendTarget(int &targetX, int &targetY, int index) {
+int *AI::defendTarget(int &targetX, int &targetY, int index) {
int *retVal = NULL;
- Defender *thisDefender = new Defender;
+ Defender *thisDefender = new Defender(this);
int defStatus = thisDefender->calculateDefenseUnitPosition(targetX, targetY, index);
if (defStatus > 0) {
@@ -2451,337 +2398,339 @@ int *defendTarget(int &targetX, int &targetY, int index) {
return retVal;
}
-int getClosestUnit(int x, int y, int radius, int player, int alignment, int unitType, int checkUnitEnabled) {
+int AI::getClosestUnit(int x, int y, int radius, int player, int alignment, int unitType, int checkUnitEnabled) {
assert((unitType >= 0) && (unitType <= 12));
- int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_CLOSEST_UNIT], 7, x, y, radius, player, alignment, unitType, checkUnitEnabled);
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_CLOSEST_UNIT], 7, x, y, radius, player, alignment, unitType, checkUnitEnabled);
return retVal;
}
-int getClosestUnit(int x, int y, int radius, int player, int alignment, int unitType, int checkUnitEnabled, int minDist) {
+int AI::getClosestUnit(int x, int y, int radius, int player, int alignment, int unitType, int checkUnitEnabled, int minDist) {
assert((unitType >= 0) && (unitType <= 12));
- int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_CLOSEST_UNIT], 8, x, y, radius, player, alignment, unitType, checkUnitEnabled, minDist);
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_CLOSEST_UNIT], 8, x, y, radius, player, alignment, unitType, checkUnitEnabled, minDist);
return retVal;
}
-int getDistance(int originX, int originY, int endX, int endY) {
- int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_WORLD_DIST], 4, originX, originY, endX, endY);
+int AI::getDistance(int originX, int originY, int endX, int endY) {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_WORLD_DIST], 4, originX, originY, endX, endY);
return retVal;
}
-int calcAngle(int originX, int originY, int endX, int endY) {
- int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_WORLD_ANGLE], 5, originX, originY, endX, endY, 0);
+int AI::calcAngle(int originX, int originY, int endX, int endY) {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_WORLD_ANGLE], 5, originX, originY, endX, endY, 0);
return retVal;
}
-int calcAngle(int originX, int originY, int endX, int endY, int noWrapFlag) {
- int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_WORLD_ANGLE], 5, originX, originY, endX, endY, noWrapFlag);
+int AI::calcAngle(int originX, int originY, int endX, int endY, int noWrapFlag) {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_WORLD_ANGLE], 5, originX, originY, endX, endY, noWrapFlag);
return retVal;
}
-int getTerrain(int x, int y) {
- int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_TERRAIN_TYPE], 2, x, y);
+int AI::getTerrain(int x, int y) {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_TERRAIN_TYPE], 2, x, y);
return retVal;
}
-int estimateNextRoundEnergy(int player) {
- int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_ESTIMATE_NEXT_ROUND_ENERGY], 1, player);
+int AI::estimateNextRoundEnergy(int player) {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_ESTIMATE_NEXT_ROUND_ENERGY], 1, player);
return retVal / 10;
}
-int getHubX(int hub) {
+int AI::getHubX(int hub) {
assert(hub >= 0 && hub <= 500);
- int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 2, D_GET_HUB_X, hub);
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 2, D_GET_HUB_X, hub);
return retVal;
}
-int getHubY(int hub) {
+int AI::getHubY(int hub) {
assert(hub >= 0 && hub <= 500);
- int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 2, D_GET_HUB_Y, hub);
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 2, D_GET_HUB_Y, hub);
return retVal;
}
-int getMaxX() {
- int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 1, D_GET_WORLD_X_SIZE);
+int AI::getMaxX() {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 1, D_GET_WORLD_X_SIZE);
return retVal;
}
-int getMaxY() {
- int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 1, D_GET_WORLD_Y_SIZE);
+int AI::getMaxY() {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 1, D_GET_WORLD_Y_SIZE);
return retVal;
}
-int getCurrentPlayer() {
- int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 1, D_GET_CURRENT_PLAYER);
+int AI::getCurrentPlayer() {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 1, D_GET_CURRENT_PLAYER);
assert(retVal != 0);
return retVal;
}
-int getMaxPower() {
- int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 1, D_GET_MAX_POWER);
+int AI::getMaxPower() {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 1, D_GET_MAX_POWER);
return retVal;
}
-int getMinPower() {
- int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 1, D_GET_MIN_POWER);
+int AI::getMinPower() {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 1, D_GET_MIN_POWER);
return retVal;
}
-int getTerrainSquareSize() {
- int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 1, D_GET_TERRAIN_SQUARE_SIZE);
+int AI::getTerrainSquareSize() {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 1, D_GET_TERRAIN_SQUARE_SIZE);
return retVal;
}
-int getBuildingOwner(int building) {
+int AI::getBuildingOwner(int building) {
assert((building > 0) && (building < 501));
- int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 2, D_GET_BUILDING_OWNER, building);
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 2, D_GET_BUILDING_OWNER, building);
return retVal;
}
-int getBuildingState(int building) {
+int AI::getBuildingState(int building) {
assert((building > 0) && (building < 501));
- int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 2, D_GET_BUILDING_STATE, building);
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 2, D_GET_BUILDING_STATE, building);
return retVal;
}
-int getBuildingType(int building) {
+int AI::getBuildingType(int building) {
assert((building > 0) && (building < 501));
- int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 2, D_GET_BUILDING_TYPE, building);
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 2, D_GET_BUILDING_TYPE, building);
return retVal;
}
-int getBuildingArmor(int building) {
+int AI::getBuildingArmor(int building) {
assert((building > 0) && (building < 501));
- int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 2, D_GET_BUILDING_ARMOR, building);
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 2, D_GET_BUILDING_ARMOR, building);
return retVal;
}
-int getBuildingWorth(int building) {
+int AI::getBuildingWorth(int building) {
assert((building > 0) && (building < 501));
- int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 2, D_GET_BUILDING_WORTH, building);
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 2, D_GET_BUILDING_WORTH, building);
return retVal;
}
-int getEnergyPoolsArray() {
- int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 1, D_GET_ENERGY_POOLS_ARRAY);
+int AI::getEnergyPoolsArray() {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 1, D_GET_ENERGY_POOLS_ARRAY);
return retVal;
}
-int getCoordinateVisibility(int x, int y, int playerNum) {
- int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 4, D_GET_COORDINATE_VISIBILITY, x, y, playerNum);
+int AI::getCoordinateVisibility(int x, int y, int playerNum) {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 4, D_GET_COORDINATE_VISIBILITY, x, y, playerNum);
return retVal;
}
-int getUnitVisibility(int unit, int playerNum) {
- int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 3, D_GET_UNIT_VISIBILITY, unit, playerNum);
+int AI::getUnitVisibility(int unit, int playerNum) {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 3, D_GET_UNIT_VISIBILITY, unit, playerNum);
return retVal;
}
-int getEnergyPoolVisibility(int pool, int playerNum) {
- int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 3, D_GET_ENERGY_POOL_VISIBILITY, pool, playerNum);
+int AI::getEnergyPoolVisibility(int pool, int playerNum) {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 3, D_GET_ENERGY_POOL_VISIBILITY, pool, playerNum);
return retVal;
}
-int getNumberOfPools() {
+int AI::getNumberOfPools() {
int retVal = 0;
- if (AItype[getCurrentPlayer()]->getID() == ENERGY_HOG) {
+ if (_aiType[getCurrentPlayer()]->getID() == ENERGY_HOG) {
retVal = 1;
} else {
- retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 1, D_GET_NUMBER_OF_POOLS);
+ retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 1, D_GET_NUMBER_OF_POOLS);
}
return retVal;
}
-int getNumberOfPlayers() {
- int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 1, D_GET_NUMBER_OF_PLAYERS);
+int AI::getNumberOfPlayers() {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 1, D_GET_NUMBER_OF_PLAYERS);
return retVal;
}
-int getPlayerEnergy() {
- int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 1, D_GET_PLAYER_ENERGY);
+int AI::getPlayerEnergy() {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 1, D_GET_PLAYER_ENERGY);
return static_cast<int>(static_cast<float>(retVal) / 10.0);
}
-int getPlayerMaxTime() {
- int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 1, D_GET_PLAYER_MAX_TIME);
+int AI::getPlayerMaxTime() {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 1, D_GET_PLAYER_MAX_TIME);
return retVal;
}
-int getWindXSpeed() {
- int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 1, D_GET_WIND_X_SPEED);
+int AI::getWindXSpeed() {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 1, D_GET_WIND_X_SPEED);
return retVal;
}
-int getWindYSpeed() {
- int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 1, D_GET_WIND_Y_SPEED);
+int AI::getWindYSpeed() {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 1, D_GET_WIND_Y_SPEED);
return retVal;
}
-int getTotalWindSpeed() {
- int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 1, D_GET_TOTAL_WIND_SPEED);
+int AI::getTotalWindSpeed() {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 1, D_GET_TOTAL_WIND_SPEED);
return retVal;
}
-int getWindXSpeedMax() {
- int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 1, D_GET_WIND_X_SPEED_MAX);
+int AI::getWindXSpeedMax() {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 1, D_GET_WIND_X_SPEED_MAX);
return retVal;
}
-int getWindYSpeedMax() {
- int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 1, D_GET_WIND_Y_SPEED_MAX);
+int AI::getWindYSpeedMax() {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 1, D_GET_WIND_Y_SPEED_MAX);
return retVal;
}
-int getBigXSize() {
- int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 1, D_GET_BIG_X_SIZE);
+int AI::getBigXSize() {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 1, D_GET_BIG_X_SIZE);
return retVal;
}
-int getBigYSize() {
- int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 1, D_GET_BIG_Y_SIZE);
+int AI::getBigYSize() {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 1, D_GET_BIG_Y_SIZE);
return retVal;
}
-int getEnergyPoolWidth(int pool) {
- int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 2, D_GET_ENERGY_POOL_WIDTH, pool);
+int AI::getEnergyPoolWidth(int pool) {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 2, D_GET_ENERGY_POOL_WIDTH, pool);
return retVal;
}
-int getBuildingMaxArmor(int building) {
- int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 2, D_GET_BUILDING_MAX_ARMOR, building);
+int AI::getBuildingMaxArmor(int building) {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 2, D_GET_BUILDING_MAX_ARMOR, building);
return retVal;
}
-int getTimerValue(int timerNum) {
- int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 2, D_GET_TIMER_VALUE, timerNum);
+int AI::getTimerValue(int timerNum) {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 2, D_GET_TIMER_VALUE, timerNum);
return retVal;
}
-int getLastAttacked(int &x, int &y) {
+int AI::getLastAttacked(int &x, int &y) {
int currentPlayer = getCurrentPlayer();
- x = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 2, D_GET_LAST_ATTACKED_X, currentPlayer);
- y = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 2, D_GET_LAST_ATTACKED_Y, currentPlayer);
+ x = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 2, D_GET_LAST_ATTACKED_X, currentPlayer);
+ y = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 2, D_GET_LAST_ATTACKED_Y, currentPlayer);
if (x || y) return 1;
return 0;
}
-int getPlayerTeam(int player) {
- int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 2, D_GET_PLAYER_TEAM, player);
+int AI::getPlayerTeam(int player) {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 2, D_GET_PLAYER_TEAM, player);
return retVal;
}
-int getBuildingTeam(int building) {
+int AI::getBuildingTeam(int building) {
assert((building >= 1) && (building <= 500));
if (getBuildingOwner(building) == 0) return 0;
- int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 2, D_GET_BUILDING_TEAM, building);
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 2, D_GET_BUILDING_TEAM, building);
return retVal;
}
-int getFOW() {
- int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 1, D_GET_FOW);
+int AI::getFOW() {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 1, D_GET_FOW);
return retVal;
}
-int getAnimSpeed() {
- int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 1, D_GET_ANIM_SPEED);
+int AI::getAnimSpeed() {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 1, D_GET_ANIM_SPEED);
return retVal;
}
-int getBuildingStackPtr() {
- int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 1, D_GET_BUILDING_STACK_PTR);
+int AI::getBuildingStackPtr() {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 1, D_GET_BUILDING_STACK_PTR);
return retVal;
}
-int getTurnCounter() {
- int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 1, D_GET_TURN_COUNTER);
+int AI::getTurnCounter() {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 1, D_GET_TURN_COUNTER);
return retVal;
}
-int getGroundAltitude(int x, int y) {
- int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_GROUND_ALTITUDE], 2, x, y);
+int AI::getGroundAltitude(int x, int y) {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_GROUND_ALTITUDE], 2, x, y);
return retVal;
}
-int checkForCordOverlap(int xStart, int yStart, int affectRadius, int simulateFlag) {
- int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_CHECK_FOR_CORD_OVERLAP], 4, xStart, yStart, affectRadius, simulateFlag);
+int AI::checkForCordOverlap(int xStart, int yStart, int affectRadius, int simulateFlag) {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_CHECK_FOR_CORD_OVERLAP], 4, xStart, yStart, affectRadius, simulateFlag);
return retVal;
}
-int checkForAngleOverlap(int unit, int angle) {
+int AI::checkForAngleOverlap(int unit, int angle) {
assert(angle > -721);
assert(angle < 721);
if (!unit) return 0;
- int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_CHECK_FOR_ANGLE_OVERLAP], 2, unit, angle);
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_CHECK_FOR_ANGLE_OVERLAP], 2, unit, angle);
return retVal;
}
-int checkForUnitOverlap(int x, int y, int radius, int ignoredUnit) {
- int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_CHECK_FOR_UNIT_OVERLAP], 4, x, y, radius, ignoredUnit);
+int AI::checkForUnitOverlap(int x, int y, int radius, int ignoredUnit) {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_CHECK_FOR_UNIT_OVERLAP], 4, x, y, radius, ignoredUnit);
return retVal;
}
-int checkForEnergySquare(int x, int y) {
- int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_CHECK_FOR_ENERGY_SQUARE], 2, x, y);
+int AI::checkForEnergySquare(int x, int y) {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_CHECK_FOR_ENERGY_SQUARE], 2, x, y);
return retVal;
}
-int aiChat() {
- int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_AI_CHAT], 0);
+int AI::aiChat() {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_AI_CHAT], 0);
return retVal;
}
-int getPowerAngleFromPoint(int originX, int originY, int endX, int endY, int threshold, int olFlag) {
- int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_POWER_ANGLE_FROM_POINT], 6, originX, originY, endX, endY, threshold, olFlag);
+int AI::getPowerAngleFromPoint(int originX, int originY, int endX, int endY, int threshold, int olFlag) {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_POWER_ANGLE_FROM_POINT], 6, originX, originY, endX, endY, threshold, olFlag);
return retVal;
}
-int getPowerAngleFromPoint(int originX, int originY, int endX, int endY, int threshold) {
- int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_POWER_ANGLE_FROM_POINT], 5, originX, originY, endX, endY, threshold);
+int AI::getPowerAngleFromPoint(int originX, int originY, int endX, int endY, int threshold) {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_POWER_ANGLE_FROM_POINT], 5, originX, originY, endX, endY, threshold);
return retVal;
}
-int checkIfWaterState(int x, int y) {
- int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_CHECK_IF_WATER_STATE], 2, x, y);
+int AI::checkIfWaterState(int x, int y) {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_CHECK_IF_WATER_STATE], 2, x, y);
return retVal;
}
-int checkIfWaterSquare(int x, int y) {
- int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_CHECK_IF_WATER_SQUARE], 2, x, y);
+int AI::checkIfWaterSquare(int x, int y) {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_CHECK_IF_WATER_SQUARE], 2, x, y);
return retVal;
}
-int getUnitsWithinRadius(int x, int y, int radius) {
+int AI::getUnitsWithinRadius(int x, int y, int radius) {
assert(x >= 0);
assert(y >= 0);
assert(radius >= 0);
- int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_UNITS_WITHIN_RADIUS], 3, x, y, radius);
+ debug(0, "getUnitsWithinRadius(%d, %d, %d)", x, y, radius);
+
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_UNITS_WITHIN_RADIUS], 3, x, y, radius);
return retVal;
}
-int getLandingPoint(int x, int y, int power, int angle) {
- int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_LANDING_POINT], 4, x, y, power, angle);
+int AI::getLandingPoint(int x, int y, int power, int angle) {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_LANDING_POINT], 4, x, y, power, angle);
return retVal;
}
-int getEnemyUnitsVisible(int playerNum) {
- int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_ENEMY_UNITS_VISIBLE], 1, playerNum);
+int AI::getEnemyUnitsVisible(int playerNum) {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_ENEMY_UNITS_VISIBLE], 1, playerNum);
return retVal;
}
-float degToRad(float degrees) {
+float AI::degToRad(float degrees) {
return degrees * M_PI / 180.;
}
-void limitLocation(int &a, int &b, int c, int d) {
+void AI::limitLocation(int &a, int &b, int c, int d) {
if (a >= 0) {
a = (a % c);
} else {
@@ -2795,7 +2744,7 @@ void limitLocation(int &a, int &b, int c, int d) {
}
}
-int energyPoolSize(int pool) {
+int AI::energyPoolSize(int pool) {
int width = getEnergyPoolWidth(pool);
switch (width) {
@@ -2812,7 +2761,7 @@ int energyPoolSize(int pool) {
return 0;
}
-int getMaxCollectors(int pool) {
+int AI::getMaxCollectors(int pool) {
int width = getEnergyPoolWidth(pool);
switch (width) {
@@ -2829,7 +2778,7 @@ int getMaxCollectors(int pool) {
return 0;
}
-int simulateBuildingLaunch(int x, int y, int power, int angle, int numSteps, int isEnergy) {
+int AI::simulateBuildingLaunch(int x, int y, int power, int angle, int numSteps, int isEnergy) {
static int sXSpeed = 0;
static int sYSpeed = 0;
static int sZSpeed = 0;
@@ -2879,9 +2828,6 @@ int simulateBuildingLaunch(int x, int y, int power, int angle, int numSteps, int
sWhichUnit = getClosestUnit(x + 10, y, 30, getCurrentPlayer(), 1, BUILDING_MAIN_BASE, 0, 0);
}
- int savedUnscaledXLoc = 0;
- int savedUnscaledYLoc = 0;
-
for (int i = 1; i <= numSteps; i++) {
unscaledXLoc = sXLoc / SCALE_X;
unscaledYLoc = sYLoc / SCALE_Y;
@@ -2924,9 +2870,6 @@ int simulateBuildingLaunch(int x, int y, int power, int angle, int numSteps, int
if (!isEnergy)
cfes = checkForEnergySquare(unscaledXLoc, unscaledYLoc);
- savedUnscaledXLoc = unscaledXLoc;
- savedUnscaledYLoc = unscaledYLoc;
-
if (cfco || cfuo || cfes || cfao) {
sXSpeed = 0;
sYSpeed = 0;
@@ -2987,7 +2930,7 @@ int simulateBuildingLaunch(int x, int y, int power, int angle, int numSteps, int
return 0;
}
-int simulateWeaponLaunch(int x, int y, int power, int angle, int numSteps) {
+int AI::simulateWeaponLaunch(int x, int y, int power, int angle, int numSteps) {
static int sXSpeed = 0;
static int sYSpeed = 0;
static int sZSpeed = 0;
@@ -3102,7 +3045,7 @@ int simulateWeaponLaunch(int x, int y, int power, int angle, int numSteps) {
return 0;
}
-int fakeSimulateWeaponLaunch(int x, int y, int power, int angle) {
+int AI::fakeSimulateWeaponLaunch(int x, int y, int power, int angle) {
int distance = power * 480 / getMaxPower();
float radAngle = degToRad(angle);
int maxX = getMaxX();
@@ -3117,8 +3060,8 @@ int fakeSimulateWeaponLaunch(int x, int y, int power, int angle) {
return MAX(1, x + y * maxX);
}
-int getEnergyHogType() {
- return energyHogType;
+int AI::getEnergyHogType() {
+ return _energyHogType;
}
} // End of namespace Scumm
diff --git a/engines/scumm/he/moonbase/ai_main.h b/engines/scumm/he/moonbase/ai_main.h
index 4937eced0f..7a38de9458 100644
--- a/engines/scumm/he/moonbase/ai_main.h
+++ b/engines/scumm/he/moonbase/ai_main.h
@@ -23,15 +23,14 @@
#ifndef SCUMM_HE_MOONBASE_AI_MAIN_H
#define SCUMM_HE_MOONBASE_AI_MAIN_H
+#include "common/array.h"
#include "scumm/he/moonbase/ai_tree.h"
namespace Scumm {
-class ScummEngine_v90he;
-
-extern ScummEngine_v90he *_vm;
-
-typedef Common::Array<int>::iterator intVecItr;
+class ScummEngine_v100he;
+class AIEntity;
+class patternList;
enum {
TERRAIN_TYPE_GOOD = 0,
@@ -84,100 +83,128 @@ enum {
MIN_DIST = 108
};
-static int energyHogType = 0;
-
-void resetAI();
-void cleanUpAI();
-void setAIType(const int paramCount, const int *params);
-int masterControlProgram(const int paramCount, const int *params);
-
-int chooseBehavior();
-int chooseTarget(int behavior);
-
-Tree *initApproachTarget(int targetX, int targetY, Node **retNode);
-int *approachTarget(Tree *myTree, int &x, int &y, Node **currentNode);
-Tree *initAcquireTarget(int targetX, int targetY, Node **retNode);
-int *acquireTarget(int targetX, int targetY);
-int *acquireTarget(int targetX, int targetY, Tree *myTree, int &errorCode);
-int *offendTarget(int &targetX, int &targetY, int index);
-int *defendTarget(int &targetX, int &targetY, int index);
-int *energizeTarget(int &targetX, int &targetY, int index);
-
-int getClosestUnit(int x, int y, int radius, int player, int alignment, int unitType, int checkUnitEnabled);
-int getClosestUnit(int x, int y, int radius, int player, int alignment, int unitType, int checkUnitEnabled, int minDist);
-
-int getDistance(int originX, int originY, int endX, int endY);
-int calcAngle(int originX, int originY, int endX, int endY);
-int calcAngle(int originX, int originY, int endX, int endY, int noWrapFlag);
-int getTerrain(int x, int y);
-int getHubX(int hub);
-int getHubY(int hub);
-int getMaxX();
-int getMaxY();
-int getCurrentPlayer();
-int getMaxPower();
-int getMinPower();
-int getTerrainSquareSize();
-int getBuildingOwner(int building);
-int getBuildingState(int building);
-int getBuildingType(int building);
-int getBuildingArmor(int building);
-int getBuildingWorth(int building);
-int getEnergyPoolsArray();
-int getCoordinateVisibility(int x, int y, int playerNum);
-int getUnitVisibility(int unit, int playerNum);
-int getEnergyPoolVisibility(int pool, int playerNum);
-int getNumberOfPools();
-int getNumberOfPlayers();
-int getPlayerEnergy();
-int getPlayerMaxTime();
-int getWindXSpeed();
-int getWindYSpeed();
-int getTotalWindSpeed();
-int getWindXSpeedMax();
-int getWindYSpeedMax();
-int getBigXSize();
-int getBigYSize();
-int getEnergyPoolWidth(int pool);
-int getBuildingMaxArmor(int building);
-int getTimerValue(int timerNum);
-int getLastAttacked(int &x, int &y);
-int getPlayerTeam(int player);
-int getBuildingTeam(int building);
-int getFOW();
-int getAnimSpeed();
-int getBuildingStackPtr();
-int getTurnCounter();
-
-int getGroundAltitude(int x, int y);
-int checkForCordOverlap(int xStart, int yStart, int affectRadius, int simulateFlag);
-int checkForAngleOverlap(int unit, int angle);
-int estimateNextRoundEnergy(int player);
-int checkForUnitOverlap(int x, int y, int radius, int ignoredUnit);
-int checkForEnergySquare(int x, int y);
-int aiChat();
-
-int simulateBuildingLaunch(int x, int y, int power, int angle, int numSteps, int isEnergy);
-int simulateWeaponLaunch(int x, int y, int power, int angle, int numSteps);
-int fakeSimulateWeaponLaunch(int x, int y, int power, int angle);
-
-int getPowerAngleFromPoint(int originX, int originY, int endX, int endY, int threshold, int olFlag);
-int getPowerAngleFromPoint(int originX, int originY, int endX, int endY, int threshold);
-int checkIfWaterState(int x, int y);
-int checkIfWaterSquare(int x, int y);
-int getUnitsWithinRadius(int x, int y, int radius);
-int getLandingPoint(int x, int y, int power, int angle);
-int getEnemyUnitsVisible(int playerNum);
-
-float degToRad(float degrees);
-void limitLocation(int &a, int &b, int c, int d);
-int energyPoolSize(int pool);
-int getMaxCollectors(int pool);
-
-int getEnergyHogType();
-
-extern Common::Array<int> lastXCoord[];
-extern Common::Array<int> lastYCoord[];
+class AI {
+public:
+ AI(ScummEngine_v100he *vm);
+
+ void resetAI();
+ void cleanUpAI();
+ void setAIType(const int paramCount, const int32 *params);
+ int masterControlProgram(const int paramCount, const int32 *params);
+
+private:
+ int chooseBehavior();
+ int chooseTarget(int behavior);
+
+ Tree *initApproachTarget(int targetX, int targetY, Node **retNode);
+ int *approachTarget(Tree *myTree, int &x, int &y, Node **currentNode);
+ Tree *initAcquireTarget(int targetX, int targetY, Node **retNode);
+ int *acquireTarget(int targetX, int targetY);
+ int *acquireTarget(int targetX, int targetY, Tree *myTree, int &errorCode);
+ int *offendTarget(int &targetX, int &targetY, int index);
+ int *defendTarget(int &targetX, int &targetY, int index);
+ int *energizeTarget(int &targetX, int &targetY, int index);
+
+public:
+ int getClosestUnit(int x, int y, int radius, int player, int alignment, int unitType, int checkUnitEnabled);
+ int getClosestUnit(int x, int y, int radius, int player, int alignment, int unitType, int checkUnitEnabled, int minDist);
+
+ int getDistance(int originX, int originY, int endX, int endY);
+ int calcAngle(int originX, int originY, int endX, int endY);
+ int calcAngle(int originX, int originY, int endX, int endY, int noWrapFlag);
+ int getTerrain(int x, int y);
+
+ int getHubX(int hub);
+ int getHubY(int hub);
+ int getMaxX();
+ int getMaxY();
+
+ int getCurrentPlayer();
+ int getMaxPower();
+ int getMinPower();
+ int getTerrainSquareSize();
+ int getBuildingOwner(int building);
+ int getBuildingState(int building);
+ int getBuildingType(int building);
+ int getBuildingArmor(int building);
+ int getBuildingMaxArmor(int building);
+ int getBuildingWorth(int building);
+ int getBuildingTeam(int building);
+
+ int getPlayerEnergy();
+ int getPlayerMaxTime();
+ int getTimerValue(int timerNum);
+ int getPlayerTeam(int player);
+
+ int getAnimSpeed();
+
+ int simulateBuildingLaunch(int x, int y, int power, int angle, int numSteps, int isEnergy);
+
+ int getPowerAngleFromPoint(int originX, int originY, int endX, int endY, int threshold, int olFlag);
+ int getPowerAngleFromPoint(int originX, int originY, int endX, int endY, int threshold);
+ int checkIfWaterState(int x, int y);
+ int getUnitsWithinRadius(int x, int y, int radius);
+
+ float degToRad(float degrees);
+
+ int getEnergyHogType();
+
+private:
+ int getEnergyPoolsArray();
+ int getCoordinateVisibility(int x, int y, int playerNum);
+ int getUnitVisibility(int unit, int playerNum);
+ int getEnergyPoolVisibility(int pool, int playerNum);
+ int getNumberOfPools();
+ int getNumberOfPlayers();
+ int getWindXSpeed();
+ int getWindYSpeed();
+ int getTotalWindSpeed();
+ int getWindXSpeedMax();
+ int getWindYSpeedMax();
+ int getBigXSize();
+ int getBigYSize();
+ int getEnergyPoolWidth(int pool);
+ int getLastAttacked(int &x, int &y);
+ int getFOW();
+ int getBuildingStackPtr();
+ int getTurnCounter();
+
+ int getGroundAltitude(int x, int y);
+ int checkForCordOverlap(int xStart, int yStart, int affectRadius, int simulateFlag);
+ int checkForAngleOverlap(int unit, int angle);
+ int estimateNextRoundEnergy(int player);
+ int checkForUnitOverlap(int x, int y, int radius, int ignoredUnit);
+ int checkForEnergySquare(int x, int y);
+ int aiChat();
+
+ int simulateWeaponLaunch(int x, int y, int power, int angle, int numSteps);
+ int fakeSimulateWeaponLaunch(int x, int y, int power, int angle);
+
+ int checkIfWaterSquare(int x, int y);
+
+ int getLandingPoint(int x, int y, int power, int angle);
+ int getEnemyUnitsVisible(int playerNum);
+
+ void limitLocation(int &a, int &b, int c, int d);
+ int energyPoolSize(int pool);
+ int getMaxCollectors(int pool);
+
+public:
+ Common::Array<int> _lastXCoord[5];
+ Common::Array<int> _lastYCoord[5];
+
+ ScummEngine_v100he *_vm;
+
+ AIEntity *_aiType[5];
+
+ int _aiState;
+ int _behavior;
+ int _energyHogType;
+
+ patternList *_moveList[5];
+
+ const int32 *_mcpParams;
+};
} // End of namespace Scumm
diff --git a/engines/scumm/he/moonbase/ai_node.h b/engines/scumm/he/moonbase/ai_node.h
index 0a60dee9ca..0c3ef2f023 100644
--- a/engines/scumm/he/moonbase/ai_node.h
+++ b/engines/scumm/he/moonbase/ai_node.h
@@ -40,8 +40,8 @@ protected:
virtual float calcH() { return 0; }
public:
- IContainedObject() { _valueG = 0; }
- IContainedObject(float inG) { _valueG = inG; }
+ IContainedObject() { _valueG = 0; _objID = -1; }
+ IContainedObject(float inG) { _valueG = inG; _objID = -1; }
IContainedObject(IContainedObject &sourceContainedObject);
virtual ~IContainedObject() {}
diff --git a/engines/scumm/he/moonbase/ai_targetacquisition.cpp b/engines/scumm/he/moonbase/ai_targetacquisition.cpp
index fb74d8ae3c..02c49dc1a7 100644
--- a/engines/scumm/he/moonbase/ai_targetacquisition.cpp
+++ b/engines/scumm/he/moonbase/ai_targetacquisition.cpp
@@ -43,28 +43,28 @@ Sortie::~Sortie() {
void Sortie::setEnemyDefenses(int enemyDefensesScummArray, int defendX, int defendY) {
DefenseUnit *thisUnit;
- int currentPlayer = getCurrentPlayer();
+ int currentPlayer = _ai->getCurrentPlayer();
for (int i = 0; i < 200; i++) {
- int thisElement = _vm->_moonbase->readFromArray(enemyDefensesScummArray, 0, i);
+ int thisElement = _ai->_vm->_moonbase->readFromArray(enemyDefensesScummArray, 0, i);
if (thisElement) {
- if (getBuildingOwner(thisElement)) {
- if (getPlayerTeam(currentPlayer) != getBuildingTeam(thisElement)) {
- int type = getBuildingType(thisElement);
+ if (_ai->getBuildingOwner(thisElement)) {
+ if (_ai->getPlayerTeam(currentPlayer) != _ai->getBuildingTeam(thisElement)) {
+ int type = _ai->getBuildingType(thisElement);
switch (type) {
case BUILDING_ANTI_AIR:
- thisUnit = new AntiAirUnit();
+ thisUnit = new AntiAirUnit(_ai);
break;
case BUILDING_SHIELD:
- thisUnit = new ShieldUnit();
+ thisUnit = new ShieldUnit(_ai);
break;
case BUILDING_EXPLOSIVE_MINE:
- if (getDistance(getHubX(thisElement), getHubY(thisElement), defendX, defendY) < 90)
- thisUnit = new MineUnit();
+ if (_ai->getDistance(_ai->getHubX(thisElement), _ai->getHubY(thisElement), defendX, defendY) < 90)
+ thisUnit = new MineUnit(_ai);
else
thisUnit = NULL;
@@ -81,9 +81,9 @@ void Sortie::setEnemyDefenses(int enemyDefensesScummArray, int defendX, int defe
if (thisUnit != NULL) {
thisUnit->setID(thisElement);
- thisUnit->setPos(getHubX(thisElement), getHubY(thisElement));
+ thisUnit->setPos(_ai->getHubX(thisElement), _ai->getHubY(thisElement));
- if (getBuildingState(thisElement)) thisUnit->setState(DUS_OFF);
+ if (_ai->getBuildingState(thisElement)) thisUnit->setState(DUS_OFF);
_enemyDefenses.push_back(thisUnit);
}
@@ -111,7 +111,7 @@ int Sortie::numChildrenToGen() {
IContainedObject *Sortie::createChildObj(int index, int &completionFlag) {
float thisDamage;
- Sortie *retSortie = new Sortie;
+ Sortie *retSortie = new Sortie(_ai);
int activeDefenses = 0;
Common::Array<DefenseUnit *> thisEnemyDefenses;
@@ -122,23 +122,23 @@ IContainedObject *Sortie::createChildObj(int index, int &completionFlag) {
switch ((*k)->getType()) {
case DUT_ANTI_AIR:
- temp = new AntiAirUnit(*k);
+ temp = new AntiAirUnit(*k, _ai);
break;
case DUT_SHIELD:
- temp = new ShieldUnit(*k);
+ temp = new ShieldUnit(*k, _ai);
break;
case DUT_MINE:
- temp = new MineUnit(*k);
+ temp = new MineUnit(*k, _ai);
break;
case DUT_CRAWLER:
- temp = new CrawlerUnit(*k);
+ temp = new CrawlerUnit(*k, _ai);
break;
default:
- temp = new ShieldUnit(*k);
+ temp = new ShieldUnit(*k, _ai);
break;
}
@@ -155,7 +155,7 @@ IContainedObject *Sortie::createChildObj(int index, int &completionFlag) {
retSortie->setUnitType(currentWeapon->getTypeID());
// Calculate distance from target to source hub
- int distance = getDistance(currentTarget->getPosX(), currentTarget->getPosY(), getSourcePosX(), getSourcePosY());
+ int distance = _ai->getDistance(currentTarget->getPosX(), currentTarget->getPosY(), getSourcePosX(), getSourcePosY());
// Pick correct shot position according to index
Common::Point *targetCoords;
@@ -169,7 +169,7 @@ IContainedObject *Sortie::createChildObj(int index, int &completionFlag) {
// Loop through defensive units, toggling anti-air units and deciding if this weapon will land safely
for (Common::Array<DefenseUnit *>::iterator i = thisEnemyDefenses.begin(); i != thisEnemyDefenses.end(); i++) {
- distance = getDistance((*i)->getPosX(), (*i)->getPosY(), targetCoords->x, targetCoords->y);
+ distance = _ai->getDistance((*i)->getPosX(), (*i)->getPosY(), targetCoords->x, targetCoords->y);
// Check to see if we're within an active defense's radius
if ((distance < (*i)->getRadius()) && ((*i)->getState() == DUS_ON)) {
@@ -210,10 +210,10 @@ IContainedObject *Sortie::createChildObj(int index, int &completionFlag) {
for (Common::Array<DefenseUnit *>::iterator i = thisEnemyDefenses.begin(); i != thisEnemyDefenses.end(); ) {
// Special simulated crawler detonation location used, since it walks a bit
if (currentWeapon->getTypeID() == ITEM_CRAWLER)
- distance = getDistance((*i)->getPosX(), (*i)->getPosY(), currentTarget->getPosX(), currentTarget->getPosY());
+ distance = _ai->getDistance((*i)->getPosX(), (*i)->getPosY(), currentTarget->getPosX(), currentTarget->getPosY());
// Normal detonation location used here
else {
- distance = getDistance((*i)->getPosX(), (*i)->getPosY(), targetCoords->x, targetCoords->y);
+ distance = _ai->getDistance((*i)->getPosX(), (*i)->getPosY(), targetCoords->x, targetCoords->y);
}
if (distance < currentWeapon->getRadius()) {
@@ -223,10 +223,10 @@ IContainedObject *Sortie::createChildObj(int index, int &completionFlag) {
if ((AAcounter != 3) && (currentWeapon->getTypeID() == ITEM_CLUSTER))
thisDamage = 0;
- if (!_vm->_rnd.getRandomNumber(4))
+ if (!_ai->_vm->_rnd.getRandomNumber(4))
currentWeapon->setTypeID(ITEM_MINE);
- (*i)->setDamage(thisDamage);
+ (*i)->setDamage((int)thisDamage);
// Apply emp effect
if (currentWeapon->getTypeID() == ITEM_EMP) {
@@ -278,7 +278,8 @@ float Sortie::calcH() {
}
int Sortie::checkSuccess() {
- if (!_enemyDefenses.size()) return SUCCESS;
+ if (!_enemyDefenses.size())
+ return SUCCESS;
int targetX = getTargetPosX();
int targetY = getTargetPosY();
@@ -320,10 +321,10 @@ void Sortie::printEnemyDefenses() {
}
int Defender::calculateDefenseUnitPosition(int targetX, int targetY, int index) {
- int currentPlayer = getCurrentPlayer();
+ int currentPlayer = _ai->getCurrentPlayer();
//get list of near hubs
- int unitsArray = getUnitsWithinRadius(targetX + 5, targetY, 480);
+ int unitsArray = _ai->getUnitsWithinRadius(targetX + 5, targetY, 480);
const int NUM_HUBS = 10;
//Order on dist
@@ -331,14 +332,14 @@ int Defender::calculateDefenseUnitPosition(int targetX, int targetY, int index)
int hubIndex = 0;
for (int i = 0; i < 200; i++) {
- int thisUnit = _vm->_moonbase->readFromArray(unitsArray, 0, i);
+ int thisUnit = _ai->_vm->_moonbase->readFromArray(unitsArray, 0, i);
if (thisUnit) {
- if (((getBuildingType(thisUnit) == BUILDING_MAIN_BASE) || (getBuildingType(thisUnit) == BUILDING_OFFENSIVE_LAUNCHER)) && (getBuildingOwner(thisUnit) == currentPlayer)) {
+ if (((_ai->getBuildingType(thisUnit) == BUILDING_MAIN_BASE) || (_ai->getBuildingType(thisUnit) == BUILDING_OFFENSIVE_LAUNCHER)) && (_ai->getBuildingOwner(thisUnit) == currentPlayer)) {
for (int j = 0; j < NUM_HUBS; j++) {
if (hubArray[j]) {
- int distCurrent = getDistance(targetX, targetY, getHubX(thisUnit), getHubY(thisUnit));
- int distSaved = getDistance(targetX, targetY, getHubX(hubArray[j]), getHubY(hubArray[j]));
+ int distCurrent = _ai->getDistance(targetX, targetY, _ai->getHubX(thisUnit), _ai->getHubY(thisUnit));
+ int distSaved = _ai->getDistance(targetX, targetY, _ai->getHubX(hubArray[j]), _ai->getHubY(hubArray[j]));
if (distCurrent < distSaved) {
hubArray[hubIndex] = hubArray[j];
@@ -361,37 +362,37 @@ int Defender::calculateDefenseUnitPosition(int targetX, int targetY, int index)
}
}
- _vm->nukeArray(unitsArray);
+ _ai->_vm->_moonbase->deallocateArray(unitsArray);
//Check if repair is needed
- int targetUnit = getClosestUnit(targetX + 5, targetY, 15, currentPlayer, 1, 0, 0, 0);
+ int targetUnit = _ai->getClosestUnit(targetX + 5, targetY, 15, currentPlayer, 1, 0, 0, 0);
- if (targetUnit && (targetUnit != BUILDING_CRAWLER) && (getBuildingTeam(targetUnit) == getPlayerTeam(currentPlayer))) {
- int armor = getBuildingArmor(targetUnit);
+ if (targetUnit && (targetUnit != BUILDING_CRAWLER) && (_ai->getBuildingTeam(targetUnit) == _ai->getPlayerTeam(currentPlayer))) {
+ int armor = _ai->getBuildingArmor(targetUnit);
- if (armor < getBuildingMaxArmor(targetUnit)) {
- unitsArray = getUnitsWithinRadius(targetX + 5, targetY, 170);
+ if (armor < _ai->getBuildingMaxArmor(targetUnit)) {
+ unitsArray = _ai->getUnitsWithinRadius(targetX + 5, targetY, 170);
int defCount = 0;
for (int i = 0; i < 200; i++) {
- int thisUnit = _vm->_moonbase->readFromArray(unitsArray, 0, i);
+ int thisUnit = _ai->_vm->_moonbase->readFromArray(unitsArray, 0, i);
if (thisUnit) {
- if (((getBuildingType(thisUnit) == BUILDING_SHIELD) || (getBuildingType(thisUnit) == BUILDING_ANTI_AIR)) && (getBuildingOwner(thisUnit) == currentPlayer) && (getBuildingState(thisUnit) == 0)) {
+ if (((_ai->getBuildingType(thisUnit) == BUILDING_SHIELD) || (_ai->getBuildingType(thisUnit) == BUILDING_ANTI_AIR)) && (_ai->getBuildingOwner(thisUnit) == currentPlayer) && (_ai->getBuildingState(thisUnit) == 0)) {
defCount++;
i = 200;
}
}
}
- _vm->nukeArray(unitsArray);
+ _ai->_vm->_moonbase->deallocateArray(unitsArray);
if (defCount) {
//repair
- int hubUnit = getClosestUnit(targetX, targetY, 480, currentPlayer, 1, BUILDING_MAIN_BASE, 1, 110);
+ int hubUnit = _ai->getClosestUnit(targetX, targetY, 480, currentPlayer, 1, BUILDING_MAIN_BASE, 1, 110);
if (hubUnit && (hubUnit != targetUnit)) {
- int powAngle = abs(getPowerAngleFromPoint(getHubX(hubUnit), getHubY(hubUnit), targetX, targetY, 20));
+ int powAngle = abs(_ai->getPowerAngleFromPoint(_ai->getHubX(hubUnit), _ai->getHubY(hubUnit), targetX, targetY, 20));
int power = powAngle / 360;
int angle = powAngle - (power * 360);
@@ -411,30 +412,30 @@ int Defender::calculateDefenseUnitPosition(int targetX, int targetY, int index)
//For each hub
for (int i = 0; i < MIN(NUM_HUBS, hubIndex); i++) {
- int hubX = getHubX(hubArray[i]);
- int hubY = getHubY(hubArray[i]);
+ int hubX = _ai->getHubX(hubArray[i]);
+ int hubY = _ai->getHubY(hubArray[i]);
//get angle to hub
int directAngleToHub = 0;
//If this hub is the target
if ((hubX == targetX) && (hubY == targetY)) {
//make the angle seed point at the closest enemy
- int enemyUnit = getClosestUnit(hubX, hubY, getMaxX(), currentPlayer, 0, 0, 0);
- directAngleToHub = calcAngle(targetX, targetY, getHubX(enemyUnit), getHubY(enemyUnit));
+ int enemyUnit = _ai->getClosestUnit(hubX, hubY, _ai->getMaxX(), currentPlayer, 0, 0, 0);
+ directAngleToHub = _ai->calcAngle(targetX, targetY, _ai->getHubX(enemyUnit), _ai->getHubY(enemyUnit));
} else {
- directAngleToHub = calcAngle(targetX, targetY, hubX, hubY);
+ directAngleToHub = _ai->calcAngle(targetX, targetY, hubX, hubY);
}
//Number of random chances to land
for (int j = 0; j < 3; j++) {
//Pick random angle and dist within semicircle (-90 to +90) and (40 to 150)
- int randAngle = directAngleToHub + _vm->_rnd.getRandomNumber(179) - 90;
- int randDist = _vm->_rnd.getRandomNumber(109) + 40;
+ int randAngle = directAngleToHub + _ai->_vm->_rnd.getRandomNumber(179) - 90;
+ int randDist = _ai->_vm->_rnd.getRandomNumber(109) + 40;
- int x = targetX + randDist * cos(degToRad(randAngle));
- int y = targetY + randDist * sin(degToRad(randAngle));
+ int x = (int)(targetX + randDist * cos(_ai->degToRad(randAngle)));
+ int y = (int)(targetY + randDist * sin(_ai->degToRad(randAngle)));
- int powAngle = getPowerAngleFromPoint(hubX, hubY, x, y, 20);
+ int powAngle = _ai->getPowerAngleFromPoint(hubX, hubY, x, y, 20);
if (powAngle < 0)
continue;
@@ -443,7 +444,7 @@ int Defender::calculateDefenseUnitPosition(int targetX, int targetY, int index)
int angle = powAngle - (power * 360);
int coords = 0;
- coords = simulateBuildingLaunch(hubX, hubY, power, angle, 100, 0);
+ coords = _ai->simulateBuildingLaunch(hubX, hubY, power, angle, 100, 0);
//if valid, return
if (coords > 0) {
@@ -451,28 +452,28 @@ int Defender::calculateDefenseUnitPosition(int targetX, int targetY, int index)
setSourceX(hubX);
setSourceY(hubY);
- setTargetX((x + getMaxX()) % getMaxX());
- setTargetY((y + getMaxY()) % getMaxY());
+ setTargetX((x + _ai->getMaxX()) % _ai->getMaxX());
+ setTargetY((y + _ai->getMaxY()) % _ai->getMaxY());
setSourceUnit(hubArray[i]);
- int unitsArray2 = getUnitsWithinRadius(targetX + 5, targetY, 200);
+ int unitsArray2 = _ai->getUnitsWithinRadius(targetX + 5, targetY, 200);
int shieldCount = 0;
for (int k = 0; k < 200; k++) {
- int thisUnit = _vm->_moonbase->readFromArray(unitsArray2, 0, k);
+ int thisUnit = _ai->_vm->_moonbase->readFromArray(unitsArray2, 0, k);
if (thisUnit) {
- if ((getBuildingType(thisUnit) == BUILDING_SHIELD) && (getBuildingOwner(thisUnit) == currentPlayer))
+ if ((_ai->getBuildingType(thisUnit) == BUILDING_SHIELD) && (_ai->getBuildingOwner(thisUnit) == currentPlayer))
shieldCount++;
- if ((getBuildingType(thisUnit) == BUILDING_BRIDGE) && (getBuildingOwner(thisUnit) == currentPlayer)) {
+ if ((_ai->getBuildingType(thisUnit) == BUILDING_BRIDGE) && (_ai->getBuildingOwner(thisUnit) == currentPlayer)) {
shieldCount--;
shieldCount = MAX(-1, shieldCount);
}
}
}
- if ((_vm->_rnd.getRandomNumber((int)pow(3.0f, shieldCount + 1) - 1) == 0) && (getPlayerEnergy() > 6))
+ if ((_ai->_vm->_rnd.getRandomNumber((int)pow(3.0f, shieldCount + 1) - 1) == 0) && (_ai->getPlayerEnergy() > 6))
setUnit(ITEM_SHIELD);
else
setUnit(ITEM_ANTIAIR);
@@ -480,30 +481,30 @@ int Defender::calculateDefenseUnitPosition(int targetX, int targetY, int index)
setPower(power);
setAngle(angle);
- _vm->nukeArray(unitsArray2);
+ _ai->_vm->_moonbase->deallocateArray(unitsArray2);
return 1;
}
if (coords < 0) {
//drop a bridge for the cord
- int yCoord = -coords / getMaxX();
- int xCoord = -coords - (yCoord * getMaxX());
+ int yCoord = -coords / _ai->getMaxX();
+ int xCoord = -coords - (yCoord * _ai->getMaxX());
- if (checkIfWaterState(xCoord, yCoord)) {
- int terrainSquareSize = getTerrainSquareSize();
+ if (_ai->checkIfWaterState(xCoord, yCoord)) {
+ int terrainSquareSize = _ai->getTerrainSquareSize();
xCoord = ((xCoord / terrainSquareSize * terrainSquareSize) + (terrainSquareSize / 2));
yCoord = ((yCoord / terrainSquareSize * terrainSquareSize) + (terrainSquareSize / 2));
int xDist = xCoord - x;
int yDist = yCoord - y;
- x = xCoord + (terrainSquareSize * 1.414 * (xDist / (abs(xDist) + 1)));
- y = yCoord + (terrainSquareSize * 1.414 * (yDist / (abs(yDist) + 1)));
+ x = (int)(xCoord + (terrainSquareSize * 1.414 * (xDist / (abs(xDist) + 1))));
+ y = (int)(yCoord + (terrainSquareSize * 1.414 * (yDist / (abs(yDist) + 1))));
setTargetX(x);
setTargetY(y);
- int nextUnit = getClosestUnit(x, y, 480, getCurrentPlayer(), 1, BUILDING_MAIN_BASE, 1, 120);
- powAngle = getPowerAngleFromPoint(getHubX(nextUnit), getHubY(nextUnit), x, y, 15);
+ int nextUnit = _ai->getClosestUnit(x, y, 480, _ai->getCurrentPlayer(), 1, BUILDING_MAIN_BASE, 1, 120);
+ powAngle = _ai->getPowerAngleFromPoint(_ai->getHubX(nextUnit), _ai->getHubY(nextUnit), x, y, 15);
powAngle = abs(powAngle);
power = powAngle / 360;
@@ -527,24 +528,24 @@ int Defender::calculateDefenseUnitPosition(int targetX, int targetY, int index)
if (hubIndex == 0) return -3;
do {
- int sourceHub = hubArray[_vm->_rnd.getRandomNumber(hubIndex - 1)];
+ int sourceHub = hubArray[_ai->_vm->_rnd.getRandomNumber(hubIndex - 1)];
- setSourceX(getHubX(sourceHub));
- setSourceY(getHubY(sourceHub));
+ setSourceX(_ai->getHubX(sourceHub));
+ setSourceY(_ai->getHubY(sourceHub));
setSourceUnit(sourceHub);
setUnit(ITEM_HUB);
- setPower(_vm->_rnd.getRandomNumber(299) + 200);
- setAngle(_vm->_rnd.getRandomNumber(359));
+ setPower(_ai->_vm->_rnd.getRandomNumber(299) + 200);
+ setAngle(_ai->_vm->_rnd.getRandomNumber(359));
count++;
if (count > (NUM_HUBS * 3)) break;
- coords = simulateBuildingLaunch(getSourceX(), getSourceY(), getPower(), getAngle(), 100, 0);
+ coords = _ai->simulateBuildingLaunch(getSourceX(), getSourceY(), getPower(), getAngle(), 100, 0);
} while (coords <= 0);
if (coords > 0) {
- setTargetX(coords % getMaxX());
- setTargetY(coords / getMaxX());
+ setTargetX(coords % _ai->getMaxX());
+ setTargetY(coords / _ai->getMaxX());
} else {
setTargetX(0);
setTargetY(0);
diff --git a/engines/scumm/he/moonbase/ai_targetacquisition.h b/engines/scumm/he/moonbase/ai_targetacquisition.h
index cf8f295c70..9afe0f50ab 100644
--- a/engines/scumm/he/moonbase/ai_targetacquisition.h
+++ b/engines/scumm/he/moonbase/ai_targetacquisition.h
@@ -44,10 +44,10 @@ private:
int _unitType;
int _shotPosX, _shotPosY;
Common::Array<DefenseUnit *> _enemyDefenses;
-
+ AI *_ai;
public:
- Sortie() {}
+ Sortie(AI *ai) { _ai = ai; _unitType = 0; _shotPosX = _shotPosY = 0; }
virtual ~Sortie();
static void setSourcePos(int x, int y) {
@@ -109,8 +109,10 @@ private:
int _power;
int _angle;
int _unit;
+ AI *_ai;
public:
+ Defender(AI *ai) : _ai(ai) {}
void setSourceX(int sourceX) { _sourceX = sourceX; }
void setSourceY(int sourceY) { _sourceY = sourceY; }
void setTargetX(int targetX) { _targetX = targetX; }
diff --git a/engines/scumm/he/moonbase/ai_traveller.cpp b/engines/scumm/he/moonbase/ai_traveller.cpp
index 68cf0c0d76..b1c9985b9d 100644
--- a/engines/scumm/he/moonbase/ai_traveller.cpp
+++ b/engines/scumm/he/moonbase/ai_traveller.cpp
@@ -20,6 +20,8 @@
*
*/
+#include "scumm/he/intern_he.h"
+#include "scumm/he/moonbase/moonbase.h"
#include "scumm/he/moonbase/ai_traveller.h"
#include "scumm/he/moonbase/ai_main.h"
@@ -32,23 +34,39 @@ int Traveller::_maxDist = 0;
int Traveller::_numToGen = 0;
int Traveller::_sizeAngleStep = 0;
-Traveller::Traveller() {
+Traveller::Traveller(AI *ai) : _ai(ai) {
_waterFlag = 0;
setValueG(0);
unsetDisabled();
+
+ _sourceHub = 0;
+ _angleTo = 0;
+ _powerTo = 0;
+ _waterSourceX = 0;
+ _waterSourceY = 0;
+ _waterDestX = 0;
+ _waterDestY = 0;
}
-Traveller::Traveller(int originX, int originY) {
+Traveller::Traveller(int originX, int originY, AI *ai) : _ai(ai) {
_waterFlag = 0;
setValueG(0);
unsetDisabled();
_posX = originX;
_posY = originY;
+
+ _sourceHub = 0;
+ _angleTo = 0;
+ _powerTo = 0;
+ _waterSourceX = 0;
+ _waterSourceY = 0;
+ _waterDestX = 0;
+ _waterDestY = 0;
}
void Traveller::adjustPosX(int offsetX) {
- int maxX = getMaxX();
+ int maxX = _ai->getMaxX();
int deltaX = _posX + offsetX;
if (deltaX < 0) _posX = maxX + deltaX;
@@ -57,7 +75,7 @@ void Traveller::adjustPosX(int offsetX) {
}
void Traveller::adjustPosY(int offsetY) {
- int maxY = getMaxX();
+ int maxY = _ai->getMaxX();
int deltaY = _posY + offsetY;
if (deltaY < 0) _posY = maxY + deltaY;
@@ -73,7 +91,7 @@ void Traveller::adjustXY(int offsetX, int offsetY) {
float Traveller::calcH() {
float retVal = 0;
// Calc dist from here to target
- retVal = getDistance(_posX, _posY, _targetPosX, _targetPosY);
+ retVal = _ai->getDistance(_posX, _posY, _targetPosX, _targetPosY);
// Divide by _maxDist to get minimum number of jumps to goal
retVal /= static_cast<float>(_maxDist);
@@ -82,7 +100,7 @@ float Traveller::calcH() {
int Traveller::numChildrenToGen() {
if (!_numToGen)
- _numToGen = getAnimSpeed() + 2;
+ _numToGen = _ai->getAnimSpeed() + 2;
return _numToGen;
}
@@ -95,7 +113,7 @@ IContainedObject *Traveller::createChildObj(int index, int &completionFlag) {
nodeCount++;
- Traveller *retTraveller = new Traveller;
+ Traveller *retTraveller = new Traveller(_ai);
static int dir, angle, power;
@@ -103,14 +121,14 @@ IContainedObject *Traveller::createChildObj(int index, int &completionFlag) {
// Calculate angle between here and target
int directAngle = 0;
- if (getEnergyHogType())
- directAngle = calcAngle(_posX, _posY, _targetPosX, _targetPosY, 1);
+ if (_ai->getEnergyHogType())
+ directAngle = _ai->calcAngle(_posX, _posY, _targetPosX, _targetPosY, 1);
else
- directAngle = calcAngle(_posX, _posY, _targetPosX, _targetPosY);
+ directAngle = _ai->calcAngle(_posX, _posY, _targetPosX, _targetPosY);
// Calculate the offset angle for this index
if (!_sizeAngleStep)
- _sizeAngleStep = 52 - (getAnimSpeed() * 7);
+ _sizeAngleStep = 52 - (_ai->getAnimSpeed() * 7);
dir = _sizeAngleStep * ((static_cast<int>(index / NUM_POWER_STEPS) + 1) >> 1);
// Calculate the sign value for the offset for this index
@@ -120,15 +138,15 @@ IContainedObject *Traveller::createChildObj(int index, int &completionFlag) {
// Calculate power for this index
int maxPower = 0;
- int directDist = getDistance(_posX, _posY, _targetPosX, _targetPosY);
+ int directDist = _ai->getDistance(_posX, _posY, _targetPosX, _targetPosY);
if (directDist > _maxDist + 120)
- maxPower = getMaxPower();
+ maxPower = _ai->getMaxPower();
else
- maxPower = (static_cast<float>(directDist) / static_cast<float>(_maxDist + 120)) * getMaxPower();
+ maxPower = (int)((static_cast<float>(directDist) / static_cast<float>(_maxDist + 120)) * _ai->getMaxPower());
maxPower -= 70;
- power = maxPower * (1 - ((index % NUM_POWER_STEPS) * SIZE_POWER_STEP));
+ power = (int)(maxPower * (1 - ((index % NUM_POWER_STEPS) * SIZE_POWER_STEP)));
}
retTraveller->setAngleTo(angle);
@@ -139,7 +157,7 @@ IContainedObject *Traveller::createChildObj(int index, int &completionFlag) {
int coords = 0;
if (!(index % NUM_POWER_STEPS) || (!lastSuccessful)) {
- coords = simulateBuildingLaunch(_posX, _posY, power, angle, 10, 0);
+ coords = _ai->simulateBuildingLaunch(_posX, _posY, power, angle, 10, 0);
lastSuccessful = 0;
} else {
completionState = 1;
@@ -156,34 +174,34 @@ IContainedObject *Traveller::createChildObj(int index, int &completionFlag) {
completionState = 1;
}
- int whoseTurn = getCurrentPlayer();
- int maxX = getMaxX();
+ int whoseTurn = _ai->getCurrentPlayer();
+ int maxX = _ai->getMaxX();
// Check new position to see if landing is clear
if (coords > 0) {
int yCoord = coords / maxX;
int xCoord = coords - (yCoord * maxX);
- int terrain = getTerrain(xCoord, yCoord);
+ int terrain = _ai->getTerrain(xCoord, yCoord);
assert(terrain == TERRAIN_TYPE_GOOD);
- float pwr = getMinPower() * .3;
+ float pwr = _ai->getMinPower() * .3;
float cosine = cos((static_cast<float>(angle) / 360) * (2 * M_PI));
float sine = sin((static_cast<float>(angle) / 360) * (2 * M_PI));
- int xParam = xCoord + (pwr * cosine);
- int yParam = yCoord + (pwr * sine);
+ int xParam = (int)(xCoord + (pwr * cosine));
+ int yParam = (int)(yCoord + (pwr * sine));
if (xParam < 0)
- xParam += getMaxX();
- else if (xParam > getMaxX())
- xParam -= getMaxX();
+ xParam += _ai->getMaxX();
+ else if (xParam > _ai->getMaxX())
+ xParam -= _ai->getMaxX();
if (yParam < 0)
- yParam += getMaxY();
- else if (yParam > getMaxY())
- yParam -= getMaxY();
+ yParam += _ai->getMaxY();
+ else if (yParam > _ai->getMaxY())
+ yParam -= _ai->getMaxY();
- if (checkIfWaterState(xParam, yParam)) {
+ if (_ai->checkIfWaterState(xParam, yParam)) {
delete retTraveller;
return NULL;
}
@@ -192,7 +210,7 @@ IContainedObject *Traveller::createChildObj(int index, int &completionFlag) {
retTraveller->setPosX(xCoord);
// Iterate through the previous action list, making sure this one isn't on it
- for (intVecItr i = (lastXCoord[whoseTurn]).begin(), j = (lastYCoord[whoseTurn]).begin(); i != (lastXCoord[whoseTurn]).end(); i++, j++) {
+ for (Common::Array<int>::iterator i = (_ai->_lastXCoord[whoseTurn]).begin(), j = (_ai->_lastYCoord[whoseTurn]).begin(); i != (_ai->_lastXCoord[whoseTurn]).end(); i++, j++) {
// Check if this shot is the same as the last time we tried
if ((*i == retTraveller->getPosX()) && (*j == retTraveller->getPosY())) {
retTraveller->setDisabled();
@@ -208,20 +226,20 @@ IContainedObject *Traveller::createChildObj(int index, int &completionFlag) {
int xCoord = -coords - (yCoord * maxX);
// If landing fault is because of water, add 1 extra to g and turn on water flag. Also set coords, and adjust power to water fault location
- if (checkIfWaterState(xCoord, yCoord)) {
- int terrainSquareSize = getTerrainSquareSize();
+ if (_ai->checkIfWaterState(xCoord, yCoord)) {
+ int terrainSquareSize = _ai->getTerrainSquareSize();
xCoord = ((xCoord / terrainSquareSize * terrainSquareSize) + (terrainSquareSize / 2));
yCoord = ((yCoord / terrainSquareSize * terrainSquareSize) + (terrainSquareSize / 2));
int xDist = xCoord - _posX;
int yDist = yCoord - _posY;
- retTraveller->setPosX(xCoord + (terrainSquareSize * 1.414 * (xDist / (abs(xDist) + 1))));
- retTraveller->setPosY(yCoord + (terrainSquareSize * 1.414 * (yDist / (abs(yDist) + 1))));
+ retTraveller->setPosX((int)(xCoord + (terrainSquareSize * 1.414 * (xDist / (abs(xDist) + 1)))));
+ retTraveller->setPosY((int)(yCoord + (terrainSquareSize * 1.414 * (yDist / (abs(yDist) + 1)))));
- int closestHub = getClosestUnit(retTraveller->getPosX(), retTraveller->getPosY(), getMaxX(), getCurrentPlayer(), 1, BUILDING_MAIN_BASE, 1, 110);
+ int closestHub = _ai->getClosestUnit(retTraveller->getPosX(), retTraveller->getPosY(), _ai->getMaxX(), _ai->getCurrentPlayer(), 1, BUILDING_MAIN_BASE, 1, 110);
- retTraveller->setWaterSourceX(getHubX(closestHub));
- retTraveller->setWaterSourceY(getHubY(closestHub));
+ retTraveller->setWaterSourceX(_ai->getHubX(closestHub));
+ retTraveller->setWaterSourceY(_ai->getHubY(closestHub));
retTraveller->setWaterDestX(retTraveller->getPosX());
retTraveller->setWaterDestY(retTraveller->getPosY());
@@ -242,7 +260,7 @@ IContainedObject *Traveller::createChildObj(int index, int &completionFlag) {
}
int Traveller::checkSuccess() {
- if (getDistance(_posX + 1, _posY, _targetPosX, _targetPosY) < _maxDist)
+ if (_ai->getDistance(_posX + 1, _posY, _targetPosX, _targetPosY) < _maxDist)
return SUCCESS;
return 0;
diff --git a/engines/scumm/he/moonbase/ai_traveller.h b/engines/scumm/he/moonbase/ai_traveller.h
index 63a56d77af..20e69eb76c 100644
--- a/engines/scumm/he/moonbase/ai_traveller.h
+++ b/engines/scumm/he/moonbase/ai_traveller.h
@@ -58,13 +58,14 @@ private:
int _waterDestX;
int _waterDestY;
+ AI *_ai;
protected:
virtual float calcH();
public:
- Traveller();
- Traveller(int originX, int originY);
+ Traveller(AI *ai);
+ Traveller(int originX, int originY, AI *ai);
~Traveller() {}
IContainedObject *duplicate() { return this; }
diff --git a/engines/scumm/he/moonbase/ai_tree.cpp b/engines/scumm/he/moonbase/ai_tree.cpp
index efbf3e3a99..d18536812b 100644
--- a/engines/scumm/he/moonbase/ai_tree.cpp
+++ b/engines/scumm/he/moonbase/ai_tree.cpp
@@ -20,36 +20,64 @@
*
*/
+#include "scumm/he/intern_he.h"
+
+#include "scumm/he/moonbase/moonbase.h"
#include "scumm/he/moonbase/ai_tree.h"
#include "scumm/he/moonbase/ai_main.h"
namespace Scumm {
-Tree::Tree() {
+static int compareTreeNodes(const void *a, const void *b) {
+ if (((const TreeNode *)a)->value < ((const TreeNode *)b)->value)
+ return -1;
+ else if (((const TreeNode *)a)->value > ((const TreeNode *)b)->value)
+ return 1;
+ else
+ return 0;
+}
+
+Tree::Tree(AI *ai) : _ai(ai) {
pBaseNode = new Node;
_maxDepth = MAX_DEPTH;
_maxNodes = MAX_NODES;
+ _currentNode = 0;
+ _currentChildIndex = 0;
+
+ _currentMap = new Common::SortedArray<TreeNode *>(compareTreeNodes);
}
-Tree::Tree(IContainedObject *contents) {
+Tree::Tree(IContainedObject *contents, AI *ai) : _ai(ai) {
pBaseNode = new Node;
pBaseNode->setContainedObject(contents);
_maxDepth = MAX_DEPTH;
_maxNodes = MAX_NODES;
+ _currentNode = 0;
+ _currentChildIndex = 0;
+
+ _currentMap = new Common::SortedArray<TreeNode *>(compareTreeNodes);
}
-Tree::Tree(IContainedObject *contents, int maxDepth) {
+Tree::Tree(IContainedObject *contents, int maxDepth, AI *ai) : _ai(ai) {
pBaseNode = new Node;
pBaseNode->setContainedObject(contents);
_maxDepth = maxDepth;
_maxNodes = MAX_NODES;
+ _currentNode = 0;
+ _currentChildIndex = 0;
+
+ _currentMap = new Common::SortedArray<TreeNode *>(compareTreeNodes);
}
-Tree::Tree(IContainedObject *contents, int maxDepth, int maxNodes) {
+Tree::Tree(IContainedObject *contents, int maxDepth, int maxNodes, AI *ai) : _ai(ai) {
pBaseNode = new Node;
pBaseNode->setContainedObject(contents);
_maxDepth = maxDepth;
_maxNodes = maxNodes;
+ _currentNode = 0;
+ _currentChildIndex = 0;
+
+ _currentMap = new Common::SortedArray<TreeNode *>(compareTreeNodes);
}
void Tree::duplicateTree(Node *sourceNode, Node *destNode) {
@@ -64,10 +92,13 @@ void Tree::duplicateTree(Node *sourceNode, Node *destNode) {
}
}
-Tree::Tree(const Tree *sourceTree) {
+Tree::Tree(const Tree *sourceTree, AI *ai) : _ai(ai) {
pBaseNode = new Node(sourceTree->getBaseNode());
_maxDepth = sourceTree->getMaxDepth();
_maxNodes = sourceTree->getMaxNodes();
+ _currentMap = new Common::SortedArray<TreeNode *>(compareTreeNodes);
+ _currentNode = 0;
+ _currentChildIndex = 0;
duplicateTree(sourceTree->getBaseNode(), pBaseNode);
}
@@ -80,7 +111,6 @@ Tree::~Tree() {
while (pNodeItr != NULL) {
// If any children are left, move to one of them
if (!(pNodeItr->getChildren().empty())) {
- //int size = (pNodeItr->getChildren()).size();
pNodeItr = pNodeItr->popChild();
} else {
// Delete this node, and move up to the parent for further processing
@@ -90,13 +120,12 @@ Tree::~Tree() {
pTemp = NULL;
}
}
-}
+ delete _currentMap;
+}
Node *Tree::aStarSearch() {
- return NULL;
-#if 0
- fnpMMap mmfpOpen;
+ Common::SortedArray<TreeNode *> mmfpOpen(compareTreeNodes);
Node *currentNode = NULL;
float currentT;
@@ -106,24 +135,24 @@ Node *Tree::aStarSearch() {
float temp = pBaseNode->getContainedObject()->calcT();
if (static_cast<int>(temp) != SUCCESS) {
-
- mmfpOpen.insert(fnpMMap::value_type(pBaseNode->getObjectT(), pBaseNode));
+ mmfpOpen.insert(new TreeNode(pBaseNode->getObjectT(), pBaseNode));
while (mmfpOpen.size() && (retNode == NULL)) {
- currentNode = mmfpOpen.begin()->second;
+ currentNode = mmfpOpen.front()->node;
mmfpOpen.erase(mmfpOpen.begin());
if ((currentNode->getDepth() < _maxDepth) && (Node::getNodeCount() < _maxNodes)) {
// Generate nodes
- int numChildren = currentNode->generateChildren();
Common::Array<Node *> vChildren = currentNode->getChildren();
for (Common::Array<Node *>::iterator i = vChildren.begin(); i != vChildren.end(); i++) {
IContainedObject *pTemp = (*i)->getContainedObject();
currentT = pTemp->calcT();
- if (currentT == SUCCESS) retNode = *i;
- else mmfpOpen.insert(fnpMMap::value_type(currentT, (*i)));
+ if (currentT == SUCCESS)
+ retNode = *i;
+ else
+ mmfpOpen.insert(new TreeNode(currentT, (*i)));
}
} else {
retNode = currentNode;
@@ -134,20 +163,18 @@ Node *Tree::aStarSearch() {
}
return retNode;
-#endif
}
Node *Tree::aStarSearch_singlePassInit() {
Node *retNode = NULL;
- currentChildIndex = 1;
+ _currentChildIndex = 1;
float temp = pBaseNode->getContainedObject()->calcT();
if (static_cast<int>(temp) != SUCCESS) {
- //_currentMap.insert(fnpMMap::value_type(pBaseNode->getObjectT(), pBaseNode));
- //assert(_currentMap.size());
+ _currentMap->insert(new TreeNode(pBaseNode->getObjectT(), pBaseNode));
} else {
retNode = pBaseNode;
}
@@ -155,37 +182,35 @@ Node *Tree::aStarSearch_singlePassInit() {
return retNode;
}
-Node *Tree::aStarSearch_singlePass(Node **currentNode) {
- currentNode = NULL;
+Node *Tree::aStarSearch_singlePass() {
+ float currentT = 0.0;
Node *retNode = NULL;
-#if 0
- float currentT;
static int maxTime = 0;
- if (currentChildIndex == 1) {
- maxTime = getPlayerMaxTime();
+ if (_currentChildIndex == 1) {
+ maxTime = _ai->getPlayerMaxTime();
}
- if (currentChildIndex) {
- if (!(_currentMap.size())) {
+ if (_currentChildIndex) {
+ if (!(_currentMap->size())) {
retNode = _currentNode;
return retNode;
}
- _currentNode = _currentMap.begin()->second;
- _currentMap.erase(_currentMap.begin());
+ _currentNode = _currentMap->front()->node;
+ _currentMap->erase(_currentMap->begin());
}
- if ((_currentNode->getDepth() < _maxDepth) && (Node::getNodeCount() < _maxNodes) && ((!maxTime) || (getTimerValue(3) < maxTime))) {
+ if ((_currentNode->getDepth() < _maxDepth) && (Node::getNodeCount() < _maxNodes) && ((!maxTime) || (_ai->getTimerValue(3) < maxTime))) {
// Generate nodes
- currentChildIndex = _currentNode->generateChildren();
+ _currentChildIndex = _currentNode->generateChildren();
- if (currentChildIndex) {
+ if (_currentChildIndex) {
Common::Array<Node *> vChildren = _currentNode->getChildren();
- if (!vChildren.size() && !_currentMap.size()) {
- currentChildIndex = 0;
+ if (!vChildren.size() && !_currentMap->size()) {
+ _currentChildIndex = 0;
retNode = _currentNode;
}
@@ -197,11 +222,11 @@ Node *Tree::aStarSearch_singlePass(Node **currentNode) {
retNode = *i;
i = vChildren.end() - 1;
} else {
- _currentMap.insert(fnpMMap::value_type(currentT, (*i)));
+ _currentMap->insert(new TreeNode(currentT, (*i)));
}
}
- if (!(_currentMap.size()) && (currentT != SUCCESS)) {
+ if (!(_currentMap->size()) && (currentT != SUCCESS)) {
assert(_currentNode != NULL);
retNode = _currentNode;
}
@@ -209,7 +234,6 @@ Node *Tree::aStarSearch_singlePass(Node **currentNode) {
} else {
retNode = _currentNode;
}
-#endif
return retNode;
}
diff --git a/engines/scumm/he/moonbase/ai_tree.h b/engines/scumm/he/moonbase/ai_tree.h
index 1097665a7a..45d4963bc1 100644
--- a/engines/scumm/he/moonbase/ai_tree.h
+++ b/engines/scumm/he/moonbase/ai_tree.h
@@ -23,16 +23,23 @@
#ifndef SCUMM_HE_MOONBASE_AI_TREE_H
#define SCUMM_HE_MOONBASE_AI_TREE_H
-#include "common/hash-str.h"
+#include "common/array.h"
#include "scumm/he/moonbase/ai_node.h"
namespace Scumm {
-//typedef std::multimap< float, Node *, std::less<float> > fnpMMap;
-
const int MAX_DEPTH = 100;
const int MAX_NODES = 1000000;
+class AI;
+
+struct TreeNode {
+ float value;
+ Node *node;
+
+ TreeNode(float v, Node *n) { value = v; node = n; }
+};
+
class Tree {
private:
Node *pBaseNode;
@@ -40,17 +47,19 @@ private:
int _maxDepth;
int _maxNodes;
- int currentChildIndex;
+ int _currentChildIndex;
- Common::StringMap _currentMap;
+ Common::SortedArray<TreeNode *> *_currentMap;
Node *_currentNode;
+ AI *_ai;
+
public:
- Tree();
- Tree(IContainedObject *contents);
- Tree(IContainedObject *contents, int maxDepth);
- Tree(IContainedObject *contents, int maxDepth, int maxNodes);
- Tree(const Tree *sourceTree);
+ Tree(AI *ai);
+ Tree(IContainedObject *contents, AI *ai);
+ Tree(IContainedObject *contents, int maxDepth, AI *ai);
+ Tree(IContainedObject *contents, int maxDepth, int maxNodes, AI *ai);
+ Tree(const Tree *sourceTree, AI *ai);
~Tree();
void duplicateTree(Node *sourceNode, Node *destNode);
@@ -65,7 +74,7 @@ public:
Node *aStarSearch();
Node *aStarSearch_singlePassInit();
- Node *aStarSearch_singlePass(Node **currentNode);
+ Node *aStarSearch_singlePass();
int IsBaseNode(Node *thisNode);
};
diff --git a/engines/scumm/he/moonbase/ai_types.cpp b/engines/scumm/he/moonbase/ai_types.cpp
index 1674e03777..e134f5ee12 100644
--- a/engines/scumm/he/moonbase/ai_types.cpp
+++ b/engines/scumm/he/moonbase/ai_types.cpp
@@ -27,6 +27,7 @@ namespace Scumm {
AIEntity::AIEntity(int id) {
switch (id) {
+ default:
case BRUTAKAS:
warning("BRUTAKAS");
_id = id;
diff --git a/engines/scumm/he/moonbase/ai_weapon.cpp b/engines/scumm/he/moonbase/ai_weapon.cpp
index b13d1efebe..ba50aae4d1 100644
--- a/engines/scumm/he/moonbase/ai_weapon.cpp
+++ b/engines/scumm/he/moonbase/ai_weapon.cpp
@@ -27,6 +27,7 @@ namespace Scumm {
Weapon::Weapon(int typeID) { //, float damage, int radius)
switch (typeID) {
+ default:
case ITEM_BOMB:
becomeBomb();
break;
diff --git a/engines/scumm/he/moonbase/moonbase.cpp b/engines/scumm/he/moonbase/moonbase.cpp
index cc25c270e4..15ababd321 100644
--- a/engines/scumm/he/moonbase/moonbase.cpp
+++ b/engines/scumm/he/moonbase/moonbase.cpp
@@ -22,20 +22,30 @@
#include "scumm/he/intern_he.h"
#include "scumm/he/moonbase/moonbase.h"
+#include "scumm/he/moonbase/ai_main.h"
namespace Scumm {
-Moonbase::Moonbase(ScummEngine_v71he *vm) : _vm(vm) {
+Moonbase::Moonbase(ScummEngine_v100he *vm) : _vm(vm) {
initFOW();
+
+ _ai = new AI(_vm);
}
Moonbase::~Moonbase() {
+ delete _ai;
}
int Moonbase::readFromArray(int array, int y, int x) {
- _vm->VAR(((ScummEngine_v90he *)_vm)->VAR_U32_ARRAY_UNK) = array;
+ _vm->VAR(_vm->VAR_U32_ARRAY_UNK) = array;
- return _vm->readArray(116, y, x);
+ return _vm->readArray(_vm->VAR_U32_ARRAY_UNK, y, x);
+}
+
+void Moonbase::deallocateArray(int array) {
+ _vm->VAR(_vm->VAR_U32_ARRAY_UNK) = array;
+
+ return _vm->nukeArray(_vm->VAR_U32_ARRAY_UNK);
}
int Moonbase::callScummFunction(int scriptNumber, int paramCount,...) {
@@ -43,9 +53,21 @@ int Moonbase::callScummFunction(int scriptNumber, int paramCount,...) {
va_start(va_params, paramCount);
int args[25];
- for (int i = 0; i < paramCount; i++)
+ memset(args, 0, sizeof(args));
+
+ Common::String str;
+ str = Common::String::format("callScummFunction(%d, [", scriptNumber);
+
+ for (int i = 0; i < paramCount; i++) {
args[i] = va_arg(va_params, int);
+ str += Common::String::format("%d ", args[i]);
+ }
+ str += "])";
+
+ debug(0, "%s", str.c_str());
+
+
va_end(va_params);
_vm->runScript(scriptNumber, 0, 1, args);
diff --git a/engines/scumm/he/moonbase/moonbase.h b/engines/scumm/he/moonbase/moonbase.h
index 7d93661dec..243d53a11d 100644
--- a/engines/scumm/he/moonbase/moonbase.h
+++ b/engines/scumm/he/moonbase/moonbase.h
@@ -29,12 +29,15 @@
namespace Scumm {
+class AI;
+
class Moonbase {
public:
- Moonbase(ScummEngine_v71he *vm);
+ Moonbase(ScummEngine_v100he *vm);
~Moonbase();
int readFromArray(int array, int y, int x);
+ void deallocateArray(int array);
int callScummFunction(int scriptNumber, int paramCount,...);
void blitT14WizImage(uint8 *dst, int dstw, int dsth, int dstPitch, const Common::Rect *clipBox,
@@ -65,8 +68,10 @@ public:
int _fowSentinelState;
uint32 _fowSentinelConditionBits;
+ AI *_ai;
+
private:
- ScummEngine_v71he *_vm;
+ ScummEngine_v100he *_vm;
int _fowFrameBaseNumber;
int _fowAnimationFrames;
diff --git a/engines/scumm/he/script_v100he.cpp b/engines/scumm/he/script_v100he.cpp
index cd807f06b8..2e7b4c4bf5 100644
--- a/engines/scumm/he/script_v100he.cpp
+++ b/engines/scumm/he/script_v100he.cpp
@@ -356,38 +356,38 @@ void ScummEngine_v100he::o100_actorOps() {
// FIXME: check stack parameters
debug(0,"o100_actorOps: case 0 UNHANDLED");
break;
- case 3:
+ case 3: // SO_ANIMATION
pop();
pop();
pop();
break;
- case 4: // SO_ANIMATION_SPEED
+ case 4: // SO_ANIMATION_SPEED
a->setAnimSpeed(pop());
break;
- case 6:
+ case 6: // SO_AT
j = pop();
i = pop();
a->putActor(i, j);
break;
- case 8:
+ case 8: // SO_BACKGROUND_OFF
a->_drawToBackBuf = false;
a->_needRedraw = true;
a->_needBgReset = true;
break;
- case 9:
+ case 9: // SO_BACKGROUND_ON
a->drawActorToBackBuf(a->getPos().x, a->getPos().y);
break;
- case 14:
+ case 14: // SO_CHARSET
a->_charset = pop();
break;
- case 18:
+ case 18: // SO_CLIPPED
a->_clipOverride.bottom = pop();
a->_clipOverride.right = pop();
a->_clipOverride.top = pop();
a->_clipOverride.left = pop();
adjustRect(a->_clipOverride);
break;
- case 22:
+ case 22: // SO_CONDITION
k = getStackList(args, ARRAYSIZE(args));
for (i = 0; i < k; ++i) {
a->setUserCondition(args[i] & 0x7F, args[i] & 0x80);
@@ -399,7 +399,7 @@ void ScummEngine_v100he::o100_actorOps() {
case 27: // SO_DEFAULT
a->initActor(0);
break;
- case 32:
+ case 32: // SO_ERASE
k = pop();
a->setHEFlag(1, k);
break;
@@ -417,11 +417,11 @@ void ScummEngine_v100he::o100_actorOps() {
a->remapActorPaletteColor(i, j);
a->_needRedraw = true;
break;
- case 59:
+ case 59: // SO_PRIORITY
a->_layer = pop();
a->_needRedraw = true;
break;
- case 63:
+ case 63: // SO_ROOM_PALETTE
a->_hePaletteNum = pop();
a->_needRedraw = true;
break;
@@ -438,7 +438,7 @@ void ScummEngine_v100he::o100_actorOps() {
i = pop();
a->setActorWalkSpeed(i, j);
break;
- case 78:
+ case 78: // SO_TALKIE
{
copyScriptString(string, sizeof(string));
int slot = pop();
@@ -461,7 +461,7 @@ void ScummEngine_v100he::o100_actorOps() {
case 89: // SO_NEVER_ZCLIP
a->_forceClip = 0;
break;
- case 128:
+ case 128: // SO_ACTOR_DEFAULT_CLIPPED
_actorClipOverride.bottom = pop();
_actorClipOverride.right = pop();
_actorClipOverride.top = pop();
@@ -517,7 +517,7 @@ void ScummEngine_v100he::o100_actorOps() {
case 141: // SO_TALK_COLOR
a->_talkColor = pop();
break;
- case 142:
+ case 142: // SO_TALK_CONDITION
k = pop();
if (k == 0)
k = _rnd.getRandomNumberRng(1, 10);
@@ -583,7 +583,7 @@ void ScummEngine_v100he::o100_arrayOps() {
writeArray(array, 0, b + c, pop());
}
break;
- case 130: //
+ case 130: // SO_COMPLEX_ARRAY_ASSIGNMENT
len = getStackList(list, ARRAYSIZE(list));
dim1end = pop();
dim1start = pop();
@@ -1617,13 +1617,13 @@ void ScummEngine_v100he::o100_roomOps() {
setPalColor(d, a, b, c);
break;
- case 129:
+ case 129: // SO_OBJECT_ORDER
b = pop();
a = pop();
swapObjects(a, b);
break;
- case 130:
+ case 130: // SO_ROOM_COPY_PALETTE
a = pop();
b = pop();
if (_game.features & GF_16BIT_COLOR)
@@ -1658,7 +1658,7 @@ void ScummEngine_v100he::o100_roomOps() {
setCurrentPalette(a);
break;
- case 135:
+ case 135: // SO_ROOM_PALETTE_IN_ROOM
b = pop();
a = pop();
setRoomPalette(a, b);
@@ -1670,7 +1670,7 @@ void ScummEngine_v100he::o100_roomOps() {
_saveLoadFlag = pop();
break;
- case 137:
+ case 137: // SO_ROOM_SAVEGAME_BY_NAME
byte buffer[256];
copyScriptString((byte *)buffer, sizeof(buffer));
diff --git a/engines/scumm/he/script_v72he.cpp b/engines/scumm/he/script_v72he.cpp
index 31b4887d10..d32eb766cb 100644
--- a/engines/scumm/he/script_v72he.cpp
+++ b/engines/scumm/he/script_v72he.cpp
@@ -119,7 +119,7 @@ byte *ScummEngine_v72he::defineArray(int array, int type, int dim2start, int dim
id = findFreeArrayId();
- debug(9,"defineArray (array %d, dim2start %d, dim2end %d dim1start %d dim1end %d", id, dim2start, dim2end, dim1start, dim1end);
+ debug(9, "defineArray (array %d, dim2start %d, dim2end %d dim1start %d dim1end %d", id, dim2start, dim2end, dim1start, dim1end);
if (array & 0x80000000) {
error("Can't define bit variable as array pointer");
@@ -699,13 +699,13 @@ void ScummEngine_v72he::o72_roomOps() {
setCurrentPalette(a);
break;
- case 220:
+ case 220: // SO_ROOM_COPY_PALETTE
a = pop();
b = pop();
copyPalColor(a, b);
break;
- case 221:
+ case 221: // SO_ROOM_SAVEGAME_BY_NAME
byte buffer[256];
copyScriptString((byte *)buffer, sizeof(buffer));
@@ -718,13 +718,13 @@ void ScummEngine_v72he::o72_roomOps() {
_saveTemporaryState = true;
break;
- case 234:
+ case 234: // SO_OBJECT_ORDER
b = pop();
a = pop();
swapObjects(a, b);
break;
- case 236:
+ case 236: // SO_ROOM_PALETTE_IN_ROOM
b = pop();
a = pop();
setRoomPalette(a, b);
@@ -752,43 +752,43 @@ void ScummEngine_v72he::o72_actorOps() {
return;
switch (subOp) {
- case 21: // HE 80+
+ case 21: // SO_CONDITION (HE 80+)
k = getStackList(args, ARRAYSIZE(args));
for (i = 0; i < k; ++i) {
a->setUserCondition(args[i] & 0x7F, args[i] & 0x80);
}
break;
- case 24: // HE 80+
+ case 24: // SO_TALK_CONDITION (HE 80+)
k = pop();
if (k == 0)
k = _rnd.getRandomNumberRng(1, 10);
a->_heNoTalkAnimation = 1;
a->setTalkCondition(k);
break;
- case 43: // HE 90+
+ case 43: // SO_PRIORITY (HE 90+)
a->_layer = pop();
a->_needRedraw = true;
break;
- case 64:
+ case 64: // SO_ACTOR_DEFAULT_CLIPPED
_actorClipOverride.bottom = pop();
_actorClipOverride.right = pop();
_actorClipOverride.top = pop();
_actorClipOverride.left = pop();
adjustRect(_actorClipOverride);
break;
- case 65: // HE 98+
+ case 65: // SO_AT (HE 98+)
j = pop();
i = pop();
a->putActor(i, j);
break;
- case 67: // HE 99+
+ case 67: // SO_CLIPPED (HE 99+)
a->_clipOverride.bottom = pop();
a->_clipOverride.right = pop();
a->_clipOverride.top = pop();
a->_clipOverride.left = pop();
adjustRect(a->_clipOverride);
break;
- case 68: // HE 90+
+ case 68: // // SO_ERASE (HE 90+)
k = pop();
a->setHEFlag(1, k);
break;
@@ -887,10 +887,10 @@ void ScummEngine_v72he::o72_actorOps() {
a->_talkPosY = pop();
a->_talkPosX = pop();
break;
- case 156: // HE 72+
+ case 156: // SO_CHARSET (HE 72+)
a->_charset = pop();
break;
- case 175: // HE 99+
+ case 175: // SO_ROOM_PALETTE (HE 99+)
a->_hePaletteNum = pop();
a->_needRedraw = true;
break;
@@ -907,15 +907,15 @@ void ScummEngine_v72he::o72_actorOps() {
case 217: // SO_ACTOR_NEW
a->initActor(2);
break;
- case 218:
+ case 218: // SO_BACKGROUND_ON
a->drawActorToBackBuf(a->getPos().x, a->getPos().y);
break;
- case 219:
+ case 219: // SO_BACKGROUND_OFF
a->_drawToBackBuf = false;
a->_needRedraw = true;
a->_needBgReset = true;
break;
- case 225:
+ case 225: // SO_TALKIE
{
copyScriptString(string, sizeof(string));
int slot = pop();
@@ -1077,7 +1077,7 @@ void ScummEngine_v72he::o72_arrayOps() {
memcpy(data, string, len);
break;
- case 126:
+ case 126: // SO_COMPLEX_ARRAY_ASSIGNMENT
len = getStackList(list, ARRAYSIZE(list));
dim1end = pop();
dim1start = pop();
@@ -1101,7 +1101,7 @@ void ScummEngine_v72he::o72_arrayOps() {
dim2start++;
}
break;
- case 127:
+ case 127: // SO_COMPLEX_ARRAY_COPY_OPERATION
{
int a2_dim1end = pop();
int a2_dim1start = pop();
@@ -1118,7 +1118,7 @@ void ScummEngine_v72he::o72_arrayOps() {
copyArray(array, a1_dim2start, a1_dim2end, a1_dim1start, a1_dim1end, array2, a2_dim2start, a2_dim2end, a2_dim1start, a2_dim1end);
}
break;
- case 128:
+ case 128: // SO_RANGE_ARRAY_ASSIGNMENT
b = pop();
c = pop();
dim1end = pop();
@@ -1149,7 +1149,7 @@ void ScummEngine_v72he::o72_arrayOps() {
dim2start++;
}
break;
- case 194:
+ case 194: // SO_FORMATTED_STRING
decodeScriptString(string);
len = resStrLen(string);
data = defineArray(array, kStringArray, 0, 0, 0, len);
diff --git a/engines/scumm/he/wiz_he.cpp b/engines/scumm/he/wiz_he.cpp
index 0ebfe67245..d730cb2894 100644
--- a/engines/scumm/he/wiz_he.cpp
+++ b/engines/scumm/he/wiz_he.cpp
@@ -1573,8 +1573,8 @@ uint8 *Wiz::drawWizImage(int resNum, int state, int maskNum, int maskState, int
}
if (_vm->_game.id == GID_MOONBASE &&
- ((ScummEngine_v90he *)_vm)->_moonbase->isFOW(resNum, state, conditionBits)) {
- ((ScummEngine_v90he *)_vm)->_moonbase->renderFOW(dst, dstPitch, dstType, cw, ch, flags);
+ ((ScummEngine_v100he *)_vm)->_moonbase->isFOW(resNum, state, conditionBits)) {
+ ((ScummEngine_v100he *)_vm)->_moonbase->renderFOW(dst, dstPitch, dstType, cw, ch, flags);
x1 = 0;
y1 = 0;
width = rScreen.width();
@@ -1748,7 +1748,7 @@ void Wiz::copyCompositeWizImage(uint8 *dst, uint8 *wizPtr, uint8 *compositeInfoB
drawFlags = flags;
}
- uint srcw1, srch1;
+ uint srcw1 = 0, srch1 = 0;
if (drawFlags & (kWIFFlipX | kWIFFlipY)) {
uint8 *wizh = _vm->findWrappedBlock(MKTAG('W','I','Z','H'), wizPtr, subState, 0);
assert(wizh);
@@ -1814,7 +1814,7 @@ void Wiz::copy555WizImage(uint8 *dst, uint8 *wizd, int dstPitch, int dstType,
uint32 compID = READ_LE_UINT32(wizd);
if (compID == 0x12340102) {
- ((ScummEngine_v90he *)_vm)->_moonbase->blitT14WizImage(dst, dstw, dsth, dstPitch, clipBox, wizd, srcx, srcy, rawROP, paramROP);
+ ((ScummEngine_v100he *)_vm)->_moonbase->blitT14WizImage(dst, dstw, dsth, dstPitch, clipBox, wizd, srcx, srcy, rawROP, paramROP);
} else if (compID == 0x12340802) {
warning("Distorion codec");
} else if (compID == 0x12340902) {
diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index 4adf0c5066..d5727f2a7c 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -885,7 +885,20 @@ ScummEngine_v90he::ScummEngine_v90he(OSystem *syst, const DetectorResult &dr)
VAR_U32_VERSION = 0xFF;
VAR_U32_ARRAY_UNK = 0xFF;
+}
+ScummEngine_v90he::~ScummEngine_v90he() {
+ delete _moviePlay;
+ delete _sprite;
+ if (_game.heversion >= 98) {
+ delete _logicHE;
+ }
+ if (_game.heversion >= 99) {
+ free(_hePalettes);
+ }
+}
+
+ScummEngine_v100he::ScummEngine_v100he(OSystem *syst, const DetectorResult &dr) : ScummEngine_v99he(syst, dr) {
/* Moonbase stuff */
_moonbase = 0;
@@ -900,15 +913,7 @@ ScummEngine_v90he::ScummEngine_v90he(OSystem *syst, const DetectorResult &dr)
VAR_U32_USER_VAR_F = 0xFF;
}
-ScummEngine_v90he::~ScummEngine_v90he() {
- delete _moviePlay;
- delete _sprite;
- if (_game.heversion >= 98) {
- delete _logicHE;
- }
- if (_game.heversion >= 99) {
- free(_hePalettes);
- }
+ScummEngine_v100he::~ScummEngine_v100he() {
delete _moonbase;
}
diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h
index a3fa329728..f9758aec33 100644
--- a/engines/scumm/scumm.h
+++ b/engines/scumm/scumm.h
@@ -700,8 +700,6 @@ protected:
void ignoreScriptWord() { fetchScriptWord(); }
void ignoreScriptByte() { fetchScriptByte(); }
void push(int a);
-
-public: // TODO. FIXME should be protected. Used by Moonbase
int pop();
virtual int readVar(uint var);
virtual void writeVar(uint var, int value);
diff --git a/engines/scumm/scumm_v2.h b/engines/scumm/scumm_v2.h
index 763bbc061c..2a9e7a96e6 100644
--- a/engines/scumm/scumm_v2.h
+++ b/engines/scumm/scumm_v2.h
@@ -78,7 +78,6 @@ protected:
void getResultPosIndirect();
virtual void getResultPos();
-public: // TODO. FIXME. Should be protected. Used by Moonbase
virtual int readVar(uint var);
virtual void writeVar(uint var, int value);
diff --git a/engines/scumm/vars.cpp b/engines/scumm/vars.cpp
index 5254aa4af2..e5ba4a68ee 100644
--- a/engines/scumm/vars.cpp
+++ b/engines/scumm/vars.cpp
@@ -340,6 +340,11 @@ void ScummEngine_v90he::setupScummVars() {
VAR_NUM_PALETTES = 130;
VAR_NUM_UNK = 131;
}
+}
+
+void ScummEngine_v100he::setupScummVars() {
+ ScummEngine_v90he::setupScummVars();
+
if (_game.id == GID_MOONBASE) {
VAR_U32_USER_VAR_A = 108;
VAR_U32_USER_VAR_B = 109;
diff --git a/engines/sherlock/fonts.cpp b/engines/sherlock/fonts.cpp
index 5a14881f1c..dc7ecd521e 100644
--- a/engines/sherlock/fonts.cpp
+++ b/engines/sherlock/fonts.cpp
@@ -195,7 +195,7 @@ inline byte Fonts::translateChar(byte c) {
}
}
-void Fonts::writeString(Surface *surface, const Common::String &str,
+void Fonts::writeString(BaseSurface *surface, const Common::String &str,
const Common::Point &pt, int overrideColor) {
Common::Point charPos = pt;
diff --git a/engines/sherlock/fonts.h b/engines/sherlock/fonts.h
index 3594d466c2..6c805447b3 100644
--- a/engines/sherlock/fonts.h
+++ b/engines/sherlock/fonts.h
@@ -31,7 +31,7 @@ namespace Sherlock {
class SherlockEngine;
class ImageFile;
-class Surface;
+class BaseSurface;
class Fonts {
private:
@@ -44,7 +44,7 @@ protected:
static int _widestChar;
static uint16 _charCount;
- static void writeString(Surface *surface, const Common::String &str,
+ static void writeString(BaseSurface *surface, const Common::String &str,
const Common::Point &pt, int overrideColor = 0);
static inline byte translateChar(byte c);
diff --git a/engines/sherlock/scalpel/scalpel_inventory.cpp b/engines/sherlock/scalpel/scalpel_inventory.cpp
index 6eb8c2c05c..07659b41f2 100644
--- a/engines/sherlock/scalpel/scalpel_inventory.cpp
+++ b/engines/sherlock/scalpel/scalpel_inventory.cpp
@@ -109,7 +109,7 @@ void ScalpelInventory::drawInventory(InvNewMode mode) {
_invMode = (InvMode)((int)mode);
if (mode != PLAIN_INVENTORY) {
- assert(mode < sizeof(_hotkeysIndexed));
+ assert((uint)mode < sizeof(_hotkeysIndexed));
ui._oldKey = _hotkeysIndexed[mode];
} else {
ui._oldKey = -1;
diff --git a/engines/sherlock/screen.cpp b/engines/sherlock/screen.cpp
index d96310abb3..a829ab22e6 100644
--- a/engines/sherlock/screen.cpp
+++ b/engines/sherlock/screen.cpp
@@ -40,7 +40,9 @@ Screen *Screen::init(SherlockEngine *vm) {
return new Scalpel::ScalpelScreen(vm);
}
-Screen::Screen(SherlockEngine *vm) : Graphics::Screen(), _vm(vm) {
+Screen::Screen(SherlockEngine *vm) : BaseSurface(), _vm(vm),
+ _backBuffer1(vm->getGameID() == GType_RoseTattoo ? 640 : 320, vm->getGameID() == GType_RoseTattoo ? 480 : 200),
+ _backBuffer2(vm->getGameID() == GType_RoseTattoo ? 640 : 320, vm->getGameID() == GType_RoseTattoo ? 480 : 200) {
_transitionSeed = 1;
_fadeStyle = false;
Common::fill(&_cMap[0], &_cMap[PALETTE_SIZE], 0);
@@ -55,6 +57,7 @@ Screen::Screen(SherlockEngine *vm) : Graphics::Screen(), _vm(vm) {
_oldFadePercent = 0;
_flushScreen = false;
+ create(_backBuffer1.w, _backBuffer1.h);
_backBuffer.create(_backBuffer1, _backBuffer1.getBounds());
}
diff --git a/engines/sherlock/screen.h b/engines/sherlock/screen.h
index f05a4f0a90..fb44c6dde2 100644
--- a/engines/sherlock/screen.h
+++ b/engines/sherlock/screen.h
@@ -25,7 +25,6 @@
#include "common/list.h"
#include "common/rect.h"
-#include "graphics/screen.h"
#include "sherlock/image_file.h"
#include "sherlock/surface.h"
#include "sherlock/resources.h"
@@ -39,7 +38,7 @@ namespace Sherlock {
class SherlockEngine;
-class Screen : virtual public Graphics::Screen, virtual public Surface {
+class Screen : public BaseSurface {
private:
uint32 _transitionSeed;
diff --git a/engines/sherlock/surface.cpp b/engines/sherlock/surface.cpp
index 47b7d4a780..93bc001149 100644
--- a/engines/sherlock/surface.cpp
+++ b/engines/sherlock/surface.cpp
@@ -25,19 +25,20 @@
namespace Sherlock {
-Surface::Surface() : Graphics::ManagedSurface(), Fonts() {
+BaseSurface::BaseSurface() : Graphics::Screen(0, 0), Fonts() {
+ free(); // Free the 0x0 surface allocated by Graphics::Screen
}
-Surface::Surface(int width, int height) : Graphics::ManagedSurface(width, height),
+BaseSurface::BaseSurface(int width, int height) : Graphics::Screen(width, height),
Fonts() {
create(width, height);
}
-void Surface::writeString(const Common::String &str, const Common::Point &pt, uint overrideColor) {
+void BaseSurface::writeString(const Common::String &str, const Common::Point &pt, uint overrideColor) {
Fonts::writeString(this, str, pt, overrideColor);
}
-void Surface::writeFancyString(const Common::String &str, const Common::Point &pt, uint overrideColor1, uint overrideColor2) {
+void BaseSurface::writeFancyString(const Common::String &str, const Common::Point &pt, uint overrideColor1, uint overrideColor2) {
writeString(str, Common::Point(pt.x, pt.y), overrideColor1);
writeString(str, Common::Point(pt.x + 1, pt.y), overrideColor1);
writeString(str, Common::Point(pt.x + 2, pt.y), overrideColor1);
@@ -49,19 +50,19 @@ void Surface::writeFancyString(const Common::String &str, const Common::Point &p
writeString(str, Common::Point(pt.x + 1, pt.y + 1), overrideColor2);
}
-void Surface::SHtransBlitFrom(const ImageFrame &src, const Common::Point &pt,
+void BaseSurface::SHtransBlitFrom(const ImageFrame &src, const Common::Point &pt,
bool flipped, int overrideColor, int scaleVal) {
Common::Point drawPt(pt.x + src.sDrawXOffset(scaleVal), pt.y + src.sDrawYOffset(scaleVal));
SHtransBlitFrom(src._frame, drawPt, flipped, overrideColor, scaleVal);
}
-void Surface::SHtransBlitFrom(const Graphics::Surface &src, const Common::Point &pt,
+void BaseSurface::SHtransBlitFrom(const Graphics::Surface &src, const Common::Point &pt,
bool flipped, int overrideColor, int scaleVal) {
Common::Rect srcRect(0, 0, src.w, src.h);
Common::Rect destRect(pt.x, pt.y, pt.x + src.w * SCALE_THRESHOLD / scaleVal,
pt.y + src.h * SCALE_THRESHOLD / scaleVal);
- Graphics::ManagedSurface::transBlitFrom(src, srcRect, destRect, TRANSPARENCY,
+ Graphics::Screen::transBlitFrom(src, srcRect, destRect, TRANSPARENCY,
flipped, overrideColor);
}
diff --git a/engines/sherlock/surface.h b/engines/sherlock/surface.h
index 7f946b467f..807fbeb1d1 100644
--- a/engines/sherlock/surface.h
+++ b/engines/sherlock/surface.h
@@ -25,7 +25,7 @@
#include "common/rect.h"
#include "common/platform.h"
-#include "graphics/managed_surface.h"
+#include "graphics/screen.h"
#include "sherlock/fonts.h"
#include "sherlock/image_file.h"
@@ -35,21 +35,21 @@ namespace Sherlock {
#define TRANSPARENCY 255
/**
- * Implements a descendent surface that combines both a managed surface and the font
+ * Implements a base surface that combines both a managed surface and the font
* drawing code. It also introduces a series of drawing method stubs that the 3DO
* Serrated Scalpel screen overrides to implement sprite doubling
*/
-class Surface: virtual public Graphics::ManagedSurface, public Fonts {
+class BaseSurface: public Graphics::Screen, public Fonts {
public:
/**
* Constructor
*/
- Surface();
-
+ BaseSurface();
+
/**
* Constructor
*/
- Surface(int width, int height);
+ BaseSurface(int width, int height);
/**
* Draws a surface on this surface
@@ -95,7 +95,7 @@ public:
* Return the width of the surface
*/
virtual uint16 width() const { return this->w; }
-
+
/**
* Return the height of the surface
*/
@@ -105,13 +105,25 @@ public:
* Draws the given string into the back buffer using the images stored in _font
*/
void writeString(const Common::String &str, const Common::Point &pt, uint overrideColor);
-
+
/**
* Draws a fancy version of the given string at the given position
*/
void writeFancyString(const Common::String &str, const Common::Point &pt, uint overrideColor1, uint overrideColor2);
};
+class Surface : public BaseSurface {
+protected:
+ /**
+ * Override the addDirtyRect from Graphics::Screen, since for standard
+ * surfaces we don't need dirty rects to be tracked
+ */
+ virtual void addDirtyRect(const Common::Rect &r) {}
+public:
+ Surface() : BaseSurface() {}
+ Surface(int w, int h) : BaseSurface(w, h) {}
+};
+
} // End of namespace Sherlock
#endif
diff --git a/engines/tsage/detection.cpp b/engines/tsage/detection.cpp
index fe555f2fdb..584ad87742 100644
--- a/engines/tsage/detection.cpp
+++ b/engines/tsage/detection.cpp
@@ -83,7 +83,7 @@ public:
}
virtual const char *getOriginalCopyright() const {
- return "(c) Tsunami Media";
+ return "(C) Tsunami Media";
}
virtual bool hasFeature(MetaEngineFeature f) const {
diff --git a/engines/tsage/graphics.cpp b/engines/tsage/graphics.cpp
index 58fa5b8094..7b7b41f0aa 100644
--- a/engines/tsage/graphics.cpp
+++ b/engines/tsage/graphics.cpp
@@ -229,14 +229,16 @@ void Rect::synchronize(Serializer &s) {
/*--------------------------------------------------------------------------*/
-GfxSurface::GfxSurface() : Graphics::ManagedSurface(), _bounds(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT) {
+GfxSurface::GfxSurface() : Graphics::Screen(0, 0), _bounds(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT) {
+ free(); // Free the 0x0 surface allocated by Graphics::Screen
_disableUpdates = false;
_lockSurfaceCtr = 0;
_transColor = -1;
_flags = 0;
}
-GfxSurface::GfxSurface(const GfxSurface &s): Graphics::ManagedSurface() {
+GfxSurface::GfxSurface(const GfxSurface &s): Graphics::Screen(0, 0) {
+ free(); // Free the 0x0 surface allocated by Graphics::Screen
_lockSurfaceCtr = 0;
operator=(s);
diff --git a/engines/tsage/graphics.h b/engines/tsage/graphics.h
index 3b395b7625..51636c4119 100644
--- a/engines/tsage/graphics.h
+++ b/engines/tsage/graphics.h
@@ -28,7 +28,7 @@
#include "common/list.h"
#include "common/rect.h"
#include "common/system.h"
-#include "graphics/managed_surface.h"
+#include "graphics/screen.h"
namespace TsAGE {
@@ -73,13 +73,23 @@ public:
enum FrameFlag { FRAME_FLIP_CENTROID_X = 4, FRAME_FLIP_CENTROID_Y = 8 };
-class GfxSurface: virtual public Graphics::ManagedSurface {
+/**
+ * Surface class. This derivces from Graphics::Screen because it has
+ * logic we'll need for our own Screen class that derives from this one
+ */
+ class GfxSurface: public Graphics::Screen {
private:
int _lockSurfaceCtr;
Graphics::ManagedSurface _rawSurface;
bool _disableUpdates;
Rect _bounds;
+ protected:
+ /**
+ * Override the addDirtyRect from Graphics::Screen, since for standard
+ * surfaces we don't need dirty rects to be tracked
+ */
+ virtual void addDirtyRect(const Common::Rect &r) {}
public:
Common::Point _centroid;
int _transColor;
diff --git a/engines/tsage/screen.cpp b/engines/tsage/screen.cpp
index f11c384797..eaf2067c32 100644
--- a/engines/tsage/screen.cpp
+++ b/engines/tsage/screen.cpp
@@ -25,10 +25,15 @@
namespace TsAGE {
-Screen::Screen(): GfxSurface(), Graphics::Screen() {
+Screen::Screen(): GfxSurface() {
create(SCREEN_WIDTH, SCREEN_HEIGHT);
}
+Screen::~Screen() {
+ // Delete the screen's surface
+ free();
+}
+
void Screen::update() {
// When dialogs are active, the screen surface may be remapped to
// sub-sections of the screen. But for drawing we'll need to temporarily
diff --git a/engines/tsage/screen.h b/engines/tsage/screen.h
index bf5057e4d6..c5cfee754a 100644
--- a/engines/tsage/screen.h
+++ b/engines/tsage/screen.h
@@ -36,7 +36,14 @@ namespace TsAGE {
#define SCREEN_CENTER_Y 100
#define UI_INTERFACE_Y 168
-class Screen : virtual public Graphics::Screen, virtual public GfxSurface {
+class Screen : public GfxSurface {
+ /**
+ * Override the addDirtyRect from GfxSurface, since for our screen
+ * class we need to reintroduce the standard Graphics::Screen implementation
+ */
+ virtual void addDirtyRect(const Common::Rect &r) {
+ Graphics::Screen::addDirtyRect(r);
+ }
public:
/**
* Constructor
@@ -46,7 +53,7 @@ public:
/**
* Destructor
*/
- virtual ~Screen() {}
+ virtual ~Screen();
/**
* Update the screen
diff --git a/engines/voyeur/detection.cpp b/engines/voyeur/detection.cpp
index 9e5320aac8..7b9fa6722e 100644
--- a/engines/voyeur/detection.cpp
+++ b/engines/voyeur/detection.cpp
@@ -75,7 +75,7 @@ public:
}
virtual const char *getOriginalCopyright() const {
- return "Voyeur (c) Philips P.O.V. Entertainment Group";
+ return "Voyeur (C) Philips P.O.V. Entertainment Group";
}
virtual bool hasFeature(MetaEngineFeature f) const;
diff --git a/engines/voyeur/files.h b/engines/voyeur/files.h
index 8726b38ddf..92b43958d3 100644
--- a/engines/voyeur/files.h
+++ b/engines/voyeur/files.h
@@ -325,9 +325,13 @@ private:
ViewPortAddPtr addFn, ViewPortRestorePtr restoreFn);
public:
ViewPortResource *_parent;
+ ViewPortSetupPtr _setupFn;
int _pageCount;
+ ViewPortAddPtr _addFn;
int _pageIndex;
+ ViewPortRestorePtr _restoreFn;
int _lastPage;
+ ScreenMethodPtr _fn1;
Common::Rect _bounds;
PictureResource *_currentPic;
PictureResource *_activePage;
@@ -340,10 +344,6 @@ public:
int _rectListCount[3];
Common::Rect _clipRect;
- ScreenMethodPtr _fn1;
- ViewPortSetupPtr _setupFn;
- ViewPortAddPtr _addFn;
- ViewPortRestorePtr _restoreFn;
Common::Rect _fontRect;
public:
ViewPortResource(BoltFilesState &state, const byte *src);
diff --git a/engines/wintermute/detection.cpp b/engines/wintermute/detection.cpp
index f77eb5c64d..4e8eab505f 100644
--- a/engines/wintermute/detection.cpp
+++ b/engines/wintermute/detection.cpp
@@ -85,7 +85,7 @@ public:
}
virtual const char *getOriginalCopyright() const {
- return "Copyright (c) 2011 Jan Nedoma";
+ return "Copyright (C) 2011 Jan Nedoma";
}
virtual const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
diff --git a/graphics/module.mk b/graphics/module.mk
index 90f6a3199c..7331a56c93 100644
--- a/graphics/module.mk
+++ b/graphics/module.mk
@@ -13,6 +13,7 @@ MODULE_OBJS := \
fonts/winfont.o \
maccursor.o \
managed_surface.o \
+ nine_patch.o \
pixelformat.o \
primitives.o \
scaler.o \
diff --git a/graphics/nine_patch.cpp b/graphics/nine_patch.cpp
new file mode 100644
index 0000000000..fea0d8ae66
--- /dev/null
+++ b/graphics/nine_patch.cpp
@@ -0,0 +1,244 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can 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 Nine Patch code by Matthew Leverton
+ taken from https://github.com/konforce/Allegro-Nine-Patch
+
+ Copyright (C) 2011 Matthew Leverton
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
+ this software and associated documentation files (the "Software"), to deal in
+ the Software without restriction, including without limitation the rights to
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ of the Software, and to permit persons to whom the Software is furnished to do
+ so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ */
+
+
+#include "common/array.h"
+#include "graphics/transparent_surface.h"
+#include "graphics/nine_patch.h"
+
+namespace Graphics {
+
+NinePatchSide::~NinePatchSide() {
+ for (uint i = 0; i < _m.size(); i++)
+ delete _m[i];
+
+ _m.clear();
+}
+
+
+bool NinePatchSide::init(Graphics::TransparentSurface *bmp, bool vertical) {
+ const int len = vertical ? bmp->h : bmp->w;
+ int i;
+ int s, t, n, z;
+
+ _m.clear();
+
+ for (i = 1, s = -1, t = 0, n = 0, z = -1; i < len; ++i) {
+ int zz;
+ uint8 r, g, b, a;
+ uint32 *color = vertical ? (uint32 *)bmp->getBasePtr(0, i) : (uint32 *)bmp->getBasePtr(i, 0);
+ bmp->format.colorToARGB(*color, a, r, g, b);
+
+ if (i == len - 1)
+ zz = -1;
+ else if (r == 0 && g == 0 && b == 0 && a == 255)
+ zz = 0;
+ else if (a == 0 || r + g + b + a == 255 * 4)
+ zz = 1;
+ else
+ return false;
+
+ if (z != zz) {
+ if (s != -1) {
+ NinePatchMark *mrk = new NinePatchMark;
+
+ mrk->offset = s;
+ mrk->length = i - s;
+ if (z == 0) {
+ mrk->ratio = 1;
+ t += mrk->length;
+ } else {
+ mrk->ratio = 0;
+ }
+ _m.push_back(mrk);
+ }
+ s = i;
+ z = zz;
+ }
+ }
+
+ _fix = len - 2 - t;
+ for (i = 0; i < _m.size(); ++i) {
+ if (_m[i]->ratio)
+ _m[i]->ratio = _m[i]->length / (float)t;
+ }
+
+ return true;
+}
+
+void NinePatchSide::calcOffsets(int len) {
+ uint i, j;
+ int dest_offset = 0;
+ int remaining_stretch = len - _fix;
+
+ for (i = 0, j = 0; i < _m.size(); ++i) {
+ _m[i]->dest_offset = dest_offset;
+ if (_m[i]->ratio == 0) {
+ _m[i]->dest_length = _m[i]->length;
+ } else {
+ _m[i]->dest_length = (len - _fix) * _m[i]->ratio;
+ remaining_stretch -= _m[i]->dest_length;
+ j = i;
+ }
+
+ dest_offset += _m[i]->dest_length;
+ }
+
+ if (remaining_stretch) {
+ _m[j]->dest_length += remaining_stretch;
+ if (j + 1 < _m.size())
+ _m[j + 1]->dest_offset += remaining_stretch;
+ }
+}
+
+NinePatchBitmap::NinePatchBitmap(Graphics::TransparentSurface *bmp, bool owns_bitmap) {
+ int i;
+ uint8 r, g, b, a;
+
+ _bmp = bmp;
+ _destroy_bmp = owns_bitmap;
+ _h._m.clear();
+ _v._m.clear();
+ _cached_dw = 0;
+ _cached_dh = 0;
+ _width = bmp->w - 2;
+ _height = bmp->h - 2;
+
+ if (_width <= 0 || _height <= 0)
+ goto bad_bitmap;
+
+ /* make sure all four corners are transparent */
+#define _check_pixel(x, y) \
+ bmp->format.colorToARGB(*(uint32 *)bmp->getBasePtr(x, y), a, r, g, b); \
+ if (a != 0 && r + g + b + a != 4) goto bad_bitmap;
+
+ _check_pixel(0,0);
+ _check_pixel(bmp->w - 1, 0);
+ _check_pixel(0, bmp->h - 1);
+ _check_pixel(bmp->w - 1, bmp->h - 1);
+#undef _check_pixel
+
+ _padding.top = _padding.right = _padding.bottom = _padding.left = -1;
+
+ i = 1;
+ while (i < bmp->w) {
+ bmp->format.colorToARGB(*(uint32 *)bmp->getBasePtr(i, bmp->h - 1), a, r, g, b);
+
+ if (r + g + b == 0 && a == 1) {
+ if (_padding.left == -1)
+ _padding.left = i - 1;
+ else if (_padding.right != -1)
+ goto bad_bitmap;
+ } else if (a == 0 || r + g + b + a == 4) {
+ if (_padding.left != -1 && _padding.right == -1)
+ _padding.right = bmp->w - i - 1;
+ }
+ ++i;
+ }
+
+ i = 1;
+ while (i < bmp->h) {
+ bmp->format.colorToARGB(*(uint32 *)bmp->getBasePtr(bmp->w - 1, i), a, r, g, b);
+
+ if (r + g + b == 0 && a == 1) {
+ if (_padding.top == -1)
+ _padding.top = i - 1;
+ else if (_padding.bottom != -1)
+ goto bad_bitmap;
+ } else if (a == 0 || r + g + b + a == 4) {
+ if (_padding.top != -1 && _padding.bottom == -1)
+ _padding.bottom = bmp->h - i - 1;
+ }
+ ++i;
+ }
+
+ if (!_h.init(bmp, false) || !_v.init(bmp, true)) {
+bad_bitmap:
+ _h._m.clear();
+ _v._m.clear();
+ }
+}
+
+void NinePatchBitmap::blit(Graphics::Surface &target, int dx, int dy, int dw, int dh) {
+ /* don't draw bitmaps that are smaller than the fixed area */
+ if (dw < _h._fix || dh < _v._fix)
+ return;
+
+ /* if the bitmap is the same size as the origin, then draw it as-is */
+ if (dw == _width && dh == _height) {
+ Common::Rect r(1, 1, dw, dh);
+
+ _bmp->blit(target, dx, dy, Graphics::FLIP_NONE, &r);
+ return;
+ }
+
+ /* only recalculate the offsets if they have changed since the last draw */
+ if (_cached_dw != dw || _cached_dh != dh) {
+ _h.calcOffsets(dw);
+ _v.calcOffsets(dh);
+
+ _cached_dw = dw;
+ _cached_dh = dh;
+ }
+
+ /* draw each region */
+ for (uint i = 0; i < _v._m.size(); ++i) {
+ for (uint j = 0; j < _h._m.size(); ++j) {
+ Common::Rect r(_h._m[j]->offset, _v._m[i]->offset,
+ _h._m[j]->offset + _h._m[j]->length, _v._m[i]->offset + _v._m[i]->length);
+
+ _bmp->blit(target, dx + _h._m[j]->dest_offset, dy + _v._m[i]->dest_offset,
+ Graphics::FLIP_NONE, &r, TS_ARGB(255, 255, 255, 255),
+ _h._m[j]->dest_length, _v._m[i]->dest_length);
+ }
+ }
+}
+
+NinePatchBitmap::~NinePatchBitmap() {
+ if (_destroy_bmp)
+ delete _bmp;
+}
+
+} // end of namespace Graphics
diff --git a/graphics/nine_patch.h b/graphics/nine_patch.h
new file mode 100644
index 0000000000..c62de3f6e2
--- /dev/null
+++ b/graphics/nine_patch.h
@@ -0,0 +1,97 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 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 Nine Patch code by Matthew Leverton
+ taken from https://github.com/konforce/Allegro-Nine-Patch
+
+ Copyright (C) 2011 Matthew Leverton
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
+ this software and associated documentation files (the "Software"), to deal in
+ the Software without restriction, including without limitation the rights to
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ of the Software, and to permit persons to whom the Software is furnished to do
+ so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ */
+
+#ifndef GRAPHICS_NINE_PATCH_H
+#define GRAPHICS_NINE_PATCH_H
+
+#include "common/array.h"
+
+namespace Graphics {
+
+struct NinePatchMark {
+ int offset;
+ int length;
+ int dest_offset;
+ int dest_length;
+ float ratio;
+};
+
+class NinePatchSide {
+public:
+ Common::Array<NinePatchMark *> _m;
+ int _fix;
+
+ NinePatchSide() : _fix(0) {}
+ ~NinePatchSide();
+
+ bool init(Graphics::TransparentSurface *bmp, bool vertical);
+ void calcOffsets(int len);
+};
+
+class NinePatchBitmap {
+ Graphics::TransparentSurface *_bmp;
+ NinePatchSide _h, _v;
+ Common::Rect _padding;
+ bool _destroy_bmp;
+ int _width, _height;
+ int _cached_dw, _cached_dh;
+
+public:
+ NinePatchBitmap(Graphics::TransparentSurface *bmp, bool owns_bitmap);
+ ~NinePatchBitmap();
+
+ void blit(Graphics::Surface &target, int dx, int dy, int dw, int dh);
+
+ int getWidth() { return _width; }
+ int getHeight() { return _height; }
+ int getMinWidth() { return _h._fix; }
+ int getMinHeight() { return _v._fix; }
+ Graphics::TransparentSurface *getSource() { return _bmp; }
+ Common::Rect &getPadding() { return _padding; }
+};
+
+} // end of namespace Graphics
+
+#endif // GRAPHICS_NINE_PATCH_H
diff --git a/graphics/screen.h b/graphics/screen.h
index 29816120f1..b3bb2d3eb2 100644
--- a/graphics/screen.h
+++ b/graphics/screen.h
@@ -39,7 +39,7 @@ namespace Graphics {
* calls, and provides an update that method that blits the affected
* areas to the physical screen
*/
-class Screen : virtual public ManagedSurface {
+class Screen : public ManagedSurface {
private:
/**
* List of affected areas of the screen
diff --git a/image/codecs/msrle4.cpp b/image/codecs/msrle4.cpp
index cd9a8717bc..fc18af8364 100644
--- a/image/codecs/msrle4.cpp
+++ b/image/codecs/msrle4.cpp
@@ -85,7 +85,7 @@ void MSRLE4Decoder::decode4(Common::SeekableReadStream &stream) {
return;
}
- output = (byte *)_surface->getBasePtr(x, y);;
+ output = (byte *)_surface->getBasePtr(x, y);
} else {
// Copy data
diff --git a/po/be_BY.po b/po/be_BY.po
index 20bc062b5e..84a4435946 100644
--- a/po/be_BY.po
+++ b/po/be_BY.po
@@ -8,7 +8,7 @@ msgstr ""
"Project-Id-Version: ScummVM 1.8.0git\n"
"Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n"
"POT-Creation-Date: 2016-04-07 08:55+0100\n"
-"PO-Revision-Date: 2016-02-21 23:32+0300\n"
+"PO-Revision-Date: 2016-05-22 17:05+0300\n"
"Last-Translator: Ivan Lukyanov <greencis@mail.ru>\n"
"Language-Team: Ivan Lukyanov <greencis@mail.ru>\n"
"Language: Belarusian\n"
@@ -1054,15 +1054,15 @@ msgstr "Мова графічнага інтэрфейсу ScummVM"
#: gui/options.cpp:1235
msgid "Update check:"
-msgstr ""
+msgstr "Правяраць абнаўленні:"
#: gui/options.cpp:1235
msgid "How often to check ScummVM updates"
-msgstr ""
+msgstr "Як часта правяраць абнаўленні ScummVM"
#: gui/options.cpp:1247
msgid "Check now"
-msgstr ""
+msgstr "Праверыць цяпер"
#: gui/options.cpp:1382
msgid "You have to restart ScummVM before your changes will take effect."
@@ -1264,19 +1264,22 @@ msgid ""
"\n"
"Would you like to enable this feature?"
msgstr ""
+"ScummVM стаў падтрымліваць аўтаматычную праверку\n"
+"абнаўленняў, якая патрабуе доступу ў Інтэрнэт.\n"
+"\n"
+"Ці жадаеце вы ўключыць гэту опцыю?"
#: gui/updates-dialog.cpp:55
msgid "(You can always enable it in the options dialog on the Misc tab)"
-msgstr ""
+msgstr "(Вы заўсёды можаце ўключыць яе ў наладах на закладцы \"Рознае\")"
#: gui/updates-dialog.cpp:92
-#, fuzzy
msgid "Check for updates automatically"
-msgstr "Правяраю абнаўленні..."
+msgstr "Аўтаматычна правяраць абнаўленні"
#: gui/updates-dialog.cpp:111
msgid "Proceed"
-msgstr ""
+msgstr "Працягнуць"
#: gui/widget.cpp:327 gui/widget.cpp:329 gui/widget.cpp:335 gui/widget.cpp:337
msgid "Clear value"
@@ -1407,20 +1410,19 @@ msgstr "Hercules Бурштынавы"
#: common/updates.cpp:58
msgid "Daily"
-msgstr ""
+msgstr "Штодзень"
#: common/updates.cpp:60
msgid "Weekly"
-msgstr ""
+msgstr "Штотыдзень"
#: common/updates.cpp:62
msgid "Monthly"
-msgstr ""
+msgstr "Штомесяц"
#: common/updates.cpp:64
-#, fuzzy
msgid "<Bad value>"
-msgstr "Ачысціць значэнне"
+msgstr "<Хібнае значэнне>"
#: engines/advancedDetector.cpp:334
#, c-format
@@ -2404,23 +2406,26 @@ msgstr ""
"меню гульні."
#: engines/agi/detection.cpp:177
-#, fuzzy
msgid "Use Hercules hires font"
-msgstr "Hercules Зялёны"
+msgstr "Выкарыстоўваць шрыфт Hercules"
#: engines/agi/detection.cpp:178
msgid "Uses Hercules hires font, when font file is available."
msgstr ""
+"Выкарыстоўвае шрыфт высокага адрознення Hercules, калі даступны файл са "
+"шрыфтам."
#: engines/agi/detection.cpp:187
msgid "Pause when entering commands"
-msgstr ""
+msgstr "Паўза падчас уводу каманд"
#: engines/agi/detection.cpp:188
msgid ""
"Shows a command prompt window and pauses the game (like in SCI) instead of a "
"real-time prompt."
msgstr ""
+"Паказвае акно з радком уводу каманды і ставіць гульню на паўзу (як у SCI) "
+"замест уводу ў рэальным часе."
#: engines/agi/saveload.cpp:777 engines/avalanche/parser.cpp:1887
#: engines/cge/events.cpp:85 engines/cge2/events.cpp:78
@@ -2712,11 +2717,11 @@ msgstr ""
#: engines/mohawk/detection.cpp:168
msgid "Play the Myst fly by movie"
-msgstr ""
+msgstr "Прайграваць ролік пралёту над Myst"
#: engines/mohawk/detection.cpp:169
msgid "The Myst fly by movie was not played by the original engine."
-msgstr ""
+msgstr "Ролік пралёту над Myst не прайграваўся арыгінальным рухавічком."
#. I18N: Option for fast scene switching
#: engines/mohawk/dialogs.cpp:96 engines/mohawk/dialogs.cpp:239
@@ -2733,14 +2738,12 @@ msgid "~D~rop Page"
msgstr "~В~ыкінуць старонку"
#: engines/mohawk/dialogs.cpp:103
-#, fuzzy
msgid "Show ~M~ap"
-msgstr "П~а~казаць карту"
+msgstr "Паказаць ~к~арту"
#: engines/mohawk/dialogs.cpp:109
-#, fuzzy
msgid "Main Men~u~"
-msgstr "~Г~алоўнае меню"
+msgstr "Галоўнае мен~ю~"
#: engines/mohawk/dialogs.cpp:240
msgid "~W~ater Effect Enabled"
@@ -2933,13 +2936,12 @@ msgstr ""
"Выкарыстоўваць альтэрнатыўны набор срэбных курсораў замест звычайных залатых"
#: engines/scumm/detection.cpp:1335
-#, fuzzy
msgid "Show Object Line"
-msgstr "Паказваць назвы аб'ектаў"
+msgstr "Паказваць радок аб'ектаў"
#: engines/scumm/detection.cpp:1336
msgid "Show the names of objects at the bottom of the screen"
-msgstr ""
+msgstr "Паказваць назвы аб'ектаў унізе экрана"
#: engines/scumm/dialogs.cpp:176
#, c-format
@@ -3800,12 +3802,14 @@ msgstr "Паказвае назвы аб'ектаў пры навядзенні курсора мышы"
#: engines/sword25/detection.cpp:46
msgid "Use English speech"
-msgstr ""
+msgstr "Выкарыстоўваць англійскую агучку"
#: engines/sword25/detection.cpp:47
msgid ""
"Use English speech instead of German for every language other than German"
msgstr ""
+"Выкарыстоўваць англійскую агучку замест нямецкай для ўсіх моў, акрамя "
+"нямецкай"
#: engines/teenagent/resources.cpp:95
msgid ""
diff --git a/po/ru_RU.po b/po/ru_RU.po
index 514d094e64..339bc7769b 100644
--- a/po/ru_RU.po
+++ b/po/ru_RU.po
@@ -8,7 +8,7 @@ msgstr ""
"Project-Id-Version: ScummVM 1.8.0svn\n"
"Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n"
"POT-Creation-Date: 2016-04-07 08:55+0100\n"
-"PO-Revision-Date: 2016-02-21 23:32+0300\n"
+"PO-Revision-Date: 2016-05-22 17:04+0300\n"
"Last-Translator: Eugene Sandulenko <sev@scummvm.org>\n"
"Language-Team: Russian\n"
"Language: Russian\n"
@@ -1267,17 +1267,17 @@ msgid ""
"Would you like to enable this feature?"
msgstr ""
"ScummVM стал поддерживать автоматическую проверку\n"
-"обновлений, которая требует доступа в Интернет\n"
+"обновлений, которая требует доступа в Интернет.\n"
"\n"
-"Хотели бы вы включить эту опцию?"
+"Вы хотите включить эту опцию?"
#: gui/updates-dialog.cpp:55
msgid "(You can always enable it in the options dialog on the Misc tab)"
-msgstr "(Вы можете всегда её включыть в Опциях на закладку Другое)"
+msgstr "(Вы всегда можете включить её в настройках на закладке \"Разное\")"
#: gui/updates-dialog.cpp:92
msgid "Check for updates automatically"
-msgstr "Автоматически проверить обновления"
+msgstr "Автоматически проверять обновления"
#: gui/updates-dialog.cpp:111
msgid "Proceed"
@@ -2424,7 +2424,7 @@ msgid ""
"real-time prompt."
msgstr ""
"Показывает окно со строкой ввода команды и ставит игру на паузу (как в SCI) "
-"вместоввода в реальном времени."
+"вместо ввода в реальном времени."
#: engines/agi/saveload.cpp:777 engines/avalanche/parser.cpp:1887
#: engines/cge/events.cpp:85 engines/cge2/events.cpp:78
@@ -2739,11 +2739,11 @@ msgstr "~В~ыбросить страницу"
#: engines/mohawk/dialogs.cpp:103
msgid "Show ~M~ap"
-msgstr "П~о~казать карту"
+msgstr "Показать ~к~арту"
#: engines/mohawk/dialogs.cpp:109
msgid "Main Men~u~"
-msgstr "~Г~лавное меню"
+msgstr "Главное мен~ю~"
#: engines/mohawk/dialogs.cpp:240
msgid "~W~ater Effect Enabled"
@@ -2939,7 +2939,7 @@ msgstr ""
#: engines/scumm/detection.cpp:1335
msgid "Show Object Line"
-msgstr "Показывать линии объектов"
+msgstr "Показывать строку объектов"
#: engines/scumm/detection.cpp:1336
msgid "Show the names of objects at the bottom of the screen"
@@ -3808,7 +3808,7 @@ msgstr "Использовать английскую озвучку"
msgid ""
"Use English speech instead of German for every language other than German"
msgstr ""
-"Использовать английскую озвучку вместо немецкой для всех языков кроме "
+"Использовать английскую озвучку вместо немецкой для всех языков, кроме "
"немецкого"
#: engines/teenagent/resources.cpp:95
diff --git a/test/common/array.h b/test/common/array.h
index 64354abc00..7473398058 100644
--- a/test/common/array.h
+++ b/test/common/array.h
@@ -354,3 +354,44 @@ class ArrayTestSuite : public CxxTest::TestSuite
}
};
+
+struct ListElement {
+ int value;
+
+ ListElement(int v) : value(v) {}
+};
+
+static int compareInts(const void *a, const void *b) {
+ return ((ListElement *)a)->value - ((ListElement *)a)->value;
+}
+
+class SortedArrayTestSuite : public CxxTest::TestSuite {
+public:
+ void test_insert() {
+ Common::SortedArray<ListElement *> container(compareInts);
+ Common::SortedArray<ListElement *>::iterator iter;
+
+ // Fill the container with some random data
+ container.insert(new ListElement(1));
+ return;
+
+ container.insert(new ListElement(7));
+ container.insert(new ListElement(8));
+ container.insert(new ListElement(3));
+ container.insert(new ListElement(5));
+ container.insert(new ListElement(4));
+ container.insert(new ListElement(9));
+ container.insert(new ListElement(2));
+ container.insert(new ListElement(6));
+
+ // Verify contents are correct
+ iter = container.begin();
+
+ for (int i = 1; i < 10; i++) {
+ TS_ASSERT_EQUALS((*iter)->value, i);
+ ++iter;
+ TS_ASSERT_DIFFERS(iter, container.end());
+ }
+ }
+
+};
diff --git a/test/module.mk b/test/module.mk
index 11ee6bd200..e591854ace 100644
--- a/test/module.mk
+++ b/test/module.mk
@@ -26,6 +26,7 @@ endif
#TEST_LDFLAGS += -L/usr/X11R6/lib -lX11
+test: CXXFLAGS += -DCOMPILING_TESTS=1
test: test/runner
./test/runner
test/runner: test/runner.cpp $(TEST_LIBS)