aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore7
-rw-r--r--audio/decoders/voc.cpp6
-rw-r--r--audio/mpu401.cpp5
-rw-r--r--audio/rate.cpp3
-rw-r--r--audio/softsynth/opl/mame.cpp2
-rw-r--r--backends/module.mk6
-rw-r--r--backends/platform/sdl/posix/posix.cpp11
-rw-r--r--backends/platform/sdl/sdl.cpp22
-rw-r--r--backends/platform/sdl/sdl.h4
-rw-r--r--backends/platform/sdl/win32/win32.cpp32
-rw-r--r--backends/taskbar/unity/unity-taskbar.cpp114
-rw-r--r--backends/taskbar/unity/unity-taskbar.h58
-rw-r--r--backends/taskbar/win32/mingw-compat.h148
-rw-r--r--backends/taskbar/win32/win32-taskbar.cpp272
-rw-r--r--backends/taskbar/win32/win32-taskbar.h66
-rw-r--r--backends/vkeybd/virtual-keyboard-parser.cpp6
-rw-r--r--base/commandLine.cpp9
-rw-r--r--common/forbidden.h7
-rw-r--r--common/system.cpp9
-rw-r--r--common/system.h24
-rw-r--r--common/taskbar.h133
-rw-r--r--common/translation.cpp33
-rwxr-xr-xconfigure75
-rw-r--r--devtools/create_project/create_project.cpp6
-rwxr-xr-xdevtools/tasmrecover/tasm-recover3
-rw-r--r--engines/agos/string.cpp3
-rw-r--r--engines/draci/script.cpp4
-rw-r--r--engines/draci/sound.cpp13
-rw-r--r--engines/dreamweb/dreamgen.cpp47
-rw-r--r--engines/dreamweb/stubs.cpp22
-rw-r--r--engines/kyra/debugger.cpp9
-rw-r--r--engines/lastexpress/debug.cpp3
-rw-r--r--engines/lastexpress/entities/anna.cpp3
-rw-r--r--engines/lastexpress/entities/ivo.cpp3
-rw-r--r--engines/lastexpress/entities/milos.cpp3
-rw-r--r--engines/lastexpress/entities/salko.cpp3
-rw-r--r--engines/lastexpress/entities/vesna.cpp3
-rw-r--r--engines/lastexpress/fight/fight.cpp407
-rw-r--r--engines/lastexpress/fight/fight.h125
-rw-r--r--engines/lastexpress/fight/fighter.cpp248
-rw-r--r--engines/lastexpress/fight/fighter.h123
-rw-r--r--engines/lastexpress/fight/fighter_anna.cpp186
-rw-r--r--engines/lastexpress/fight/fighter_anna.h48
-rw-r--r--engines/lastexpress/fight/fighter_ivo.cpp244
-rw-r--r--engines/lastexpress/fight/fighter_ivo.h51
-rw-r--r--engines/lastexpress/fight/fighter_milos.cpp221
-rw-r--r--engines/lastexpress/fight/fighter_milos.h51
-rw-r--r--engines/lastexpress/fight/fighter_salko.cpp201
-rw-r--r--engines/lastexpress/fight/fighter_salko.h51
-rw-r--r--engines/lastexpress/fight/fighter_vesna.cpp264
-rw-r--r--engines/lastexpress/fight/fighter_vesna.h51
-rw-r--r--engines/lastexpress/game/fight.cpp1583
-rw-r--r--engines/lastexpress/game/fight.h266
-rw-r--r--engines/lastexpress/game/logic.cpp4
-rw-r--r--engines/lastexpress/game/menu.cpp3
-rw-r--r--engines/lastexpress/lastexpress.cpp20
-rw-r--r--engines/lastexpress/module.mk8
-rw-r--r--engines/lure/debugger.cpp14
-rw-r--r--engines/lure/memory.cpp8
-rw-r--r--engines/saga/actor.cpp1
-rw-r--r--engines/sci/decompressor.cpp45
-rw-r--r--engines/sword25/fmv/theora_decoder.cpp11
-rw-r--r--engines/sword25/gfx/image/art.cpp69
-rw-r--r--engines/sword25/gfx/image/art.h5
-rw-r--r--engines/sword25/gfx/image/vectorimage.cpp2
-rw-r--r--engines/sword25/gfx/image/vectorimagerenderer.cpp7
-rw-r--r--engines/sword25/package/packagemanager.h3
-rw-r--r--engines/teenagent/resources.cpp11
-rw-r--r--engines/teenagent/teenagent.cpp129
-rw-r--r--engines/toon/path.cpp24
-rw-r--r--engines/touche/resource.cpp22
-rw-r--r--engines/tsage/resources.cpp11
-rw-r--r--engines/tsage/ringworld_logic.cpp15
-rw-r--r--engines/tsage/ringworld_scenes1.cpp2
-rw-r--r--graphics/font.cpp4
-rw-r--r--graphics/fonts/winfont.cpp14
-rw-r--r--graphics/scaler.cpp4
-rw-r--r--gui/massadd.cpp23
-rw-r--r--gui/massadd.h1
-rw-r--r--gui/themes/translations.datbin220518 -> 220969 bytes
-rw-r--r--po/hu_HU.po9
81 files changed, 3742 insertions, 2024 deletions
diff --git a/.gitignore b/.gitignore
index 32fb0b91b6..4ad9f07b34 100644
--- a/.gitignore
+++ b/.gitignore
@@ -86,6 +86,7 @@ project.xcworkspace
/dists/msvc*/[Dd]ebug*/
/dists/msvc*/[Rr]elease*/
+/dists/msvc*/[Aa]nalysis*/
/dists/msvc*/*.lib
/dists/msvc*/*.SAV
/dists/msvc*/*.dat
@@ -156,3 +157,9 @@ ipch/
#Ignore default Visual Studio build folders
[Dd]ebug/
[Rr]elease/
+
+#Ignore Qt Creator project files
+ScummVM.config
+ScummVM.creator
+ScummVM.files
+ScummVM.includes
diff --git a/audio/decoders/voc.cpp b/audio/decoders/voc.cpp
index 74ea4440a1..be53f945ac 100644
--- a/audio/decoders/voc.cpp
+++ b/audio/decoders/voc.cpp
@@ -118,7 +118,11 @@ static byte *loadVOCFromStream(Common::ReadStream &stream, int &size, int &rate,
debug(9, "VOC Data Block: %d, %d, %d", rate, packing, len);
if (packing == 0) {
if (size) {
- ret_sound = (byte *)realloc(ret_sound, size + len);
+ byte *tmp = (byte *)realloc(ret_sound, size + len);
+ if (!tmp)
+ error("Cannot reallocate memory for VOC Data Block");
+
+ ret_sound = tmp;
} else {
ret_sound = (byte *)malloc(len);
}
diff --git a/audio/mpu401.cpp b/audio/mpu401.cpp
index caad945258..966e367a93 100644
--- a/audio/mpu401.cpp
+++ b/audio/mpu401.cpp
@@ -33,7 +33,10 @@ void MidiChannel_MPU401::init(MidiDriver *owner, byte channel) {
bool MidiChannel_MPU401::allocate() {
if (_allocated)
return false;
- return (_allocated = true);
+
+ _allocated = true;
+
+ return true;
}
MidiDriver *MidiChannel_MPU401::device() {
diff --git a/audio/rate.cpp b/audio/rate.cpp
index 83abd6150b..0fc23a8a54 100644
--- a/audio/rate.cpp
+++ b/audio/rate.cpp
@@ -298,6 +298,9 @@ public:
_bufferSize = osamp;
}
+ if (!_buffer)
+ error("[CopyRateConverter::flow] Cannot allocate memory for temp buffer");
+
// Read up to 'osamp' samples into our temporary buffer
len = input.readBuffer(_buffer, osamp);
diff --git a/audio/softsynth/opl/mame.cpp b/audio/softsynth/opl/mame.cpp
index 74699ba4c6..15e869ba33 100644
--- a/audio/softsynth/opl/mame.cpp
+++ b/audio/softsynth/opl/mame.cpp
@@ -725,6 +725,8 @@ static int OPLOpenTable(void) {
ENV_CURVE = (int *)malloc(sizeof(int) * (2*EG_ENT+1));
+ if (!ENV_CURVE)
+ error("[OPLOpenTable] Cannot allocate memory");
/* envelope counter -> envelope output table */
for (i=0; i < EG_ENT; i++) {
diff --git a/backends/module.mk b/backends/module.mk
index 79ad1c5dd0..63774cc4d0 100644
--- a/backends/module.mk
+++ b/backends/module.mk
@@ -80,7 +80,8 @@ MODULE_OBJS += \
fs/posix/posix-fs.o \
fs/posix/posix-fs-factory.o \
plugins/posix/posix-provider.o \
- saves/posix/posix-saves.o
+ saves/posix/posix-saves.o \
+ taskbar/unity/unity-taskbar.o
endif
ifdef MACOSX
@@ -94,7 +95,8 @@ MODULE_OBJS += \
fs/windows/windows-fs.o \
fs/windows/windows-fs-factory.o \
midi/windows.o \
- plugins/win32/win32-provider.o
+ plugins/win32/win32-provider.o \
+ taskbar/win32/win32-taskbar.o
endif
ifdef AMIGAOS
diff --git a/backends/platform/sdl/posix/posix.cpp b/backends/platform/sdl/posix/posix.cpp
index d757186134..05c779a4e0 100644
--- a/backends/platform/sdl/posix/posix.cpp
+++ b/backends/platform/sdl/posix/posix.cpp
@@ -33,6 +33,7 @@
#include "backends/platform/sdl/posix/posix.h"
#include "backends/saves/posix/posix-saves.h"
#include "backends/fs/posix/posix-fs-factory.h"
+#include "backends/taskbar/unity/unity-taskbar.h"
#include <errno.h>
#include <sys/stat.h>
@@ -49,6 +50,11 @@ void OSystem_POSIX::init() {
// Initialze File System Factory
_fsFactory = new POSIXFilesystemFactory();
+#if defined(USE_TASKBAR) && defined(USE_TASKBAR_UNITY)
+ // Initialize taskbar manager
+ _taskbarManager = new UnityTaskbarManager();
+#endif
+
// Invoke parent implementation of this method
OSystem_SDL::init();
}
@@ -60,6 +66,11 @@ void OSystem_POSIX::initBackend() {
// Invoke parent implementation of this method
OSystem_SDL::initBackend();
+
+#if defined(USE_TASKBAR) && defined(USE_TASKBAR_UNITY)
+ // Register the taskbar manager as an event source (this is necessary for the glib event loop to be run)
+ _eventManager->getEventDispatcher()->registerSource((UnityTaskbarManager *)_taskbarManager, false);
+#endif
}
bool OSystem_POSIX::hasFeature(Feature f) {
diff --git a/backends/platform/sdl/sdl.cpp b/backends/platform/sdl/sdl.cpp
index 7972b19689..d05cca4d1f 100644
--- a/backends/platform/sdl/sdl.cpp
+++ b/backends/platform/sdl/sdl.cpp
@@ -31,6 +31,7 @@
#include "backends/platform/sdl/sdl.h"
#include "common/config-manager.h"
#include "common/EventRecorder.h"
+#include "common/taskbar.h"
#include "common/textconsole.h"
#include "backends/saves/default/default-saves.h"
@@ -132,6 +133,11 @@ void OSystem_SDL::init() {
if (_timerManager == 0)
_timerManager = new SdlTimerManager();
+#if defined(USE_TASKBAR)
+ if (_taskbarManager == 0)
+ _taskbarManager = new Common::TaskbarManager();
+#endif
+
#ifdef USE_OPENGL
// Setup a list with both SDL and OpenGL graphics modes
setupGraphicsModes();
@@ -219,6 +225,21 @@ void OSystem_SDL::initBackend() {
}
+#if defined(USE_TASKBAR)
+void OSystem_SDL::engineInit() {
+ // Add the started engine to the list of recent tasks
+ _taskbarManager->addRecent(ConfMan.getActiveDomainName(), ConfMan.get("description"));
+
+ // Set the overlay icon the current running engine
+ _taskbarManager->setOverlayIcon(ConfMan.getActiveDomainName(), ConfMan.get("description"));
+}
+
+void OSystem_SDL::engineDone() {
+ // Remove overlay icon
+ _taskbarManager->setOverlayIcon("", "");
+}
+#endif
+
void OSystem_SDL::initSDL() {
// Check if SDL has not been initialized
if (!_initedSDL) {
@@ -406,6 +427,7 @@ void OSystem_SDL::setupIcon() {
for (i = 0; i < ncols; i++) {
unsigned char code;
char color[32];
+ memset(color, 0, sizeof(color));
unsigned int col;
if (sscanf(scummvm_icon[1 + i], "%c c %s", &code, color) != 2) {
warning("Wrong format of scummvm_icon[%d] (%s)", 1 + i, scummvm_icon[1 + i]);
diff --git a/backends/platform/sdl/sdl.h b/backends/platform/sdl/sdl.h
index 707ad8bc55..395b2b3aac 100644
--- a/backends/platform/sdl/sdl.h
+++ b/backends/platform/sdl/sdl.h
@@ -54,6 +54,10 @@ public:
// Override functions from ModularBackend and OSystem
virtual void initBackend();
+#if defined(USE_TASKBAR)
+ virtual void engineInit();
+ virtual void engineDone();
+#endif
virtual Common::HardwareKeySet *getHardwareKeySet();
virtual void quit();
virtual void fatalError();
diff --git a/backends/platform/sdl/win32/win32.cpp b/backends/platform/sdl/win32/win32.cpp
index 432f7077ae..814f1955fe 100644
--- a/backends/platform/sdl/win32/win32.cpp
+++ b/backends/platform/sdl/win32/win32.cpp
@@ -36,6 +36,7 @@
#include "backends/platform/sdl/win32/win32.h"
#include "backends/fs/windows/windows-fs-factory.h"
+#include "backends/taskbar/win32/win32-taskbar.h"
#include "common/memstream.h"
@@ -81,9 +82,14 @@ void OSystem_Win32::init() {
}
#endif
- // Initialze File System Factory
+ // Initialize File System Factory
_fsFactory = new WindowsFilesystemFactory();
+#if defined(USE_TASKBAR)
+ // Initialize taskbar manager
+ _taskbarManager = new Win32TaskbarManager();
+#endif
+
// Invoke parent implementation of this method
OSystem_SDL::init();
}
@@ -149,18 +155,31 @@ Common::String OSystem_Win32::getDefaultConfigFileName() {
error("Unable to access user profile directory");
strcat(configFile, "\\Application Data");
- CreateDirectory(configFile, NULL);
+
+ // If the directory already exists (as it should in most cases),
+ // we don't want to fail, but we need to stop on other errors (such as ERROR_PATH_NOT_FOUND)
+ if (!CreateDirectory(configFile, NULL)) {
+ if (GetLastError() != ERROR_ALREADY_EXISTS)
+ error("Cannot create Application data folder");
+ }
}
strcat(configFile, "\\ScummVM");
- CreateDirectory(configFile, NULL);
+ if (!CreateDirectory(configFile, NULL)) {
+ if (GetLastError() != ERROR_ALREADY_EXISTS)
+ error("Cannot create ScummVM application data folder");
+ }
+
strcat(configFile, "\\" DEFAULT_CONFIG_FILE);
FILE *tmp = NULL;
if ((tmp = fopen(configFile, "r")) == NULL) {
// Check windows directory
char oldConfigFile[MAXPATHLEN];
- GetWindowsDirectory(oldConfigFile, MAXPATHLEN);
+ uint ret = GetWindowsDirectory(oldConfigFile, MAXPATHLEN);
+ if (ret == 0 || ret > MAXPATHLEN)
+ error("Cannot retrieve the path of the Windows directory");
+
strcat(oldConfigFile, "\\" DEFAULT_CONFIG_FILE);
if ((tmp = fopen(oldConfigFile, "r"))) {
strcpy(configFile, oldConfigFile);
@@ -172,7 +191,10 @@ Common::String OSystem_Win32::getDefaultConfigFileName() {
}
} else {
// Check windows directory
- GetWindowsDirectory(configFile, MAXPATHLEN);
+ uint ret = GetWindowsDirectory(configFile, MAXPATHLEN);
+ if (ret == 0 || ret > MAXPATHLEN)
+ error("Cannot retrieve the path of the Windows directory");
+
strcat(configFile, "\\" DEFAULT_CONFIG_FILE);
}
diff --git a/backends/taskbar/unity/unity-taskbar.cpp b/backends/taskbar/unity/unity-taskbar.cpp
new file mode 100644
index 0000000000..da053734d2
--- /dev/null
+++ b/backends/taskbar/unity/unity-taskbar.cpp
@@ -0,0 +1,114 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#define FORBIDDEN_SYMBOL_EXCEPTION_unistd_h
+#define FORBIDDEN_SYMBOL_EXCEPTION_time_h
+#include "common/scummsys.h"
+
+#if defined(POSIX) && defined(USE_TASKBAR) && defined(USE_TASKBAR_UNITY)
+
+#include "backends/taskbar/unity/unity-taskbar.h"
+
+#include "common/textconsole.h"
+
+#include <unity.h>
+
+UnityTaskbarManager::UnityTaskbarManager() {
+ g_type_init();
+
+ _loop = g_main_loop_new(NULL, FALSE);
+
+ _launcher = unity_launcher_entry_get_for_desktop_id("scummvm.desktop");
+}
+
+UnityTaskbarManager::~UnityTaskbarManager() {
+ g_main_loop_unref(_loop);
+ _loop = NULL;
+}
+
+void UnityTaskbarManager::setProgressValue(int completed, int total) {
+ if (_launcher == NULL)
+ return;
+
+ double percentage = (double)completed / (double)total;
+ unity_launcher_entry_set_progress(_launcher, percentage);
+ unity_launcher_entry_set_progress_visible(_launcher, TRUE);
+}
+
+void UnityTaskbarManager::setProgressState(TaskbarProgressState state) {
+ if (_launcher == NULL)
+ return;
+
+ switch (state) {
+ default:
+ warning("[UnityTaskbarManager::setProgressState] Unknown state / Not implemented (%d)", state);
+ // fallback to noprogress state
+
+ case kTaskbarNoProgress:
+ unity_launcher_entry_set_progress_visible(_launcher, FALSE);
+ break;
+
+ // Unity only support two progress states as of 3.0: visible or not visible
+ // We show progress in all of those states
+ case kTaskbarIndeterminate:
+ case kTaskbarNormal:
+ case kTaskbarError:
+ case kTaskbarPaused:
+ unity_launcher_entry_set_progress_visible(_launcher, TRUE);
+ break;
+ }
+}
+
+void UnityTaskbarManager::addRecent(const Common::String &name, const Common::String &description) {
+ warning("[UnityTaskbarManager::addRecent] Not implemented");
+}
+
+void UnityTaskbarManager::setCount(int count) {
+ if (_launcher == NULL)
+ return;
+
+ unity_launcher_entry_set_count(_launcher, count);
+
+ unity_launcher_entry_set_count_visible(_launcher, (count == 0) ? FALSE : TRUE);
+}
+
+// Unity requires the glib event loop to the run to function properly
+// as events are sent asynchronously
+bool UnityTaskbarManager::pollEvent(Common::Event &event) {
+ if (!_loop)
+ return false;
+
+ // Get context
+ GMainContext *context = g_main_loop_get_context(_loop);
+ if (!context)
+ return false;
+
+ // Dispatch events
+ g_main_context_iteration(context, FALSE);
+
+ return false;
+}
+
+#endif
diff --git a/backends/taskbar/unity/unity-taskbar.h b/backends/taskbar/unity/unity-taskbar.h
new file mode 100644
index 0000000000..06ea0ca769
--- /dev/null
+++ b/backends/taskbar/unity/unity-taskbar.h
@@ -0,0 +1,58 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef BACKEND_UNITY_TASKBAR_H
+#define BACKEND_UNITY_TASKBAR_H
+
+#if defined(POSIX) && defined(USE_TASKBAR) && defined(USE_TASKBAR_UNITY)
+
+#include "common/events.h"
+#include "common/str.h"
+#include "common/taskbar.h"
+
+typedef struct _GMainLoop GMainLoop;
+typedef struct _UnityLauncherEntry UnityLauncherEntry;
+
+class UnityTaskbarManager : public Common::TaskbarManager, public Common::EventSource {
+public:
+ UnityTaskbarManager();
+ virtual ~UnityTaskbarManager();
+
+ virtual void setProgressValue(int completed, int total);
+ virtual void setProgressState(TaskbarProgressState state);
+ virtual void addRecent(const Common::String &name, const Common::String &description);
+ virtual void setCount(int count);
+
+ // Implementation of the EventSource interface
+ virtual bool pollEvent(Common::Event &event);
+
+private:
+ GMainLoop *_loop;
+ UnityLauncherEntry *_launcher;
+};
+
+#endif
+
+#endif // BACKEND_UNITY_TASKBAR_H
diff --git a/backends/taskbar/win32/mingw-compat.h b/backends/taskbar/win32/mingw-compat.h
new file mode 100644
index 0000000000..bf03db9abd
--- /dev/null
+++ b/backends/taskbar/win32/mingw-compat.h
@@ -0,0 +1,148 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+// TODO: Remove header when the latest changes to the Windows SDK have been integrated into MingW
+// For reference, the interface definitions here are imported the SDK headers and from the
+// EcWin7 project (https://code.google.com/p/dukto/)
+
+#ifndef BACKEND_WIN32_TASKBAR_MINGW_H
+#define BACKEND_WIN32_TASKBAR_MINGW_H
+
+#if defined(WIN32)
+#if defined(__GNUC__)
+#ifdef __MINGW32__
+
+#ifdef _WIN32_WINNT
+ #undef _WIN32_WINNT
+#endif
+#define _WIN32_WINNT 0x0501
+#include <windows.h>
+#include <commctrl.h>
+#include <initguid.h>
+#include <shlwapi.h>
+#include <shlguid.h>
+#define CMIC_MASK_ASYNCOK SEE_MASK_ASYNCOK
+
+// Misc enumeration values
+#ifndef SHARD_LINK
+#define SHARD_LINK 0x00000006
+#endif
+
+// Taskbar GUID definitions
+DEFINE_GUID(CLSID_TaskbarList,0x56fdf344,0xfd6d,0x11d0,0x95,0x8a,0x0,0x60,0x97,0xc9,0xa0,0x90);
+DEFINE_GUID(IID_ITaskbarList3,0xea1afb91,0x9e28,0x4b86,0x90,0xE9,0x9e,0x9f,0x8a,0x5e,0xef,0xaf);
+DEFINE_GUID(IID_IPropertyStore,0x886d8eeb,0x8cf2,0x4446,0x8d,0x02,0xcd,0xba,0x1d,0xbd,0xcf,0x99);
+
+// Property key
+typedef struct _tagpropertykey {
+ GUID fmtid;
+ DWORD pid;
+} PROPERTYKEY;
+
+#define REFPROPERTYKEY const PROPERTYKEY &
+
+typedef struct tagPROPVARIANT PROPVARIANT;
+#define REFPROPVARIANT const PROPVARIANT &
+
+// Property store
+DECLARE_INTERFACE_(IPropertyStore, IUnknown) {
+ STDMETHOD (GetCount) (DWORD *cProps) PURE;
+ STDMETHOD (GetAt) (DWORD iProp, PROPERTYKEY *pkey) PURE;
+ STDMETHOD (GetValue) (REFPROPERTYKEY key, PROPVARIANT *pv) PURE;
+ STDMETHOD (SetValue) (REFPROPERTYKEY key, REFPROPVARIANT propvar) PURE;
+ STDMETHOD (Commit) (void) PURE;
+};
+typedef IPropertyStore *LPIPropertyStore;
+
+// Mingw-specific defines for taskbar integration
+typedef enum THUMBBUTTONMASK {
+ THB_BITMAP = 0x1,
+ THB_ICON = 0x2,
+ THB_TOOLTIP = 0x4,
+ THB_FLAGS = 0x8
+} THUMBBUTTONMASK;
+
+typedef enum THUMBBUTTONFLAGS {
+ THBF_ENABLED = 0,
+ THBF_DISABLED = 0x1,
+ THBF_DISMISSONCLICK = 0x2,
+ THBF_NOBACKGROUND = 0x4,
+ THBF_HIDDEN = 0x8,
+ THBF_NONINTERACTIVE = 0x10
+} THUMBBUTTONFLAGS;
+
+typedef struct THUMBBUTTON {
+ THUMBBUTTONMASK dwMask;
+ UINT iId;
+ UINT iBitmap;
+ HICON hIcon;
+ WCHAR szTip[260];
+ THUMBBUTTONFLAGS dwFlags;
+} THUMBBUTTON;
+typedef struct THUMBBUTTON *LPTHUMBBUTTON;
+
+typedef enum TBPFLAG {
+ TBPF_NOPROGRESS = 0,
+ TBPF_INDETERMINATE = 0x1,
+ TBPF_NORMAL = 0x2,
+ TBPF_ERROR = 0x4,
+ TBPF_PAUSED = 0x8
+} TBPFLAG;
+
+// Taskbar interface
+DECLARE_INTERFACE_(ITaskbarList3, IUnknown) {
+ // IUnknown
+ STDMETHOD(QueryInterface) (THIS_ REFIID riid, void **ppv) PURE;
+ STDMETHOD_(ULONG,AddRef) (THIS) PURE;
+ STDMETHOD_(ULONG,Release) (THIS) PURE;
+ // ITaskbarList
+ STDMETHOD(HrInit) (THIS) PURE;
+ STDMETHOD(AddTab) (THIS_ HWND hwnd) PURE;
+ STDMETHOD(DeleteTab) (THIS_ HWND hwnd) PURE;
+ STDMETHOD(ActivateTab) (THIS_ HWND hwnd) PURE;
+ STDMETHOD(SetActiveAlt) (THIS_ HWND hwnd) PURE;
+ STDMETHOD (MarkFullscreenWindow) (THIS_ HWND hwnd, int fFullscreen) PURE;
+ // ITaskbarList3
+ STDMETHOD (SetProgressValue) (THIS_ HWND hwnd, ULONGLONG ullCompleted, ULONGLONG ullTotal) PURE;
+ STDMETHOD (SetProgressState) (THIS_ HWND hwnd, TBPFLAG tbpFlags) PURE;
+ STDMETHOD (RegisterTab) (THIS_ HWND hwndTab, HWND hwndMDI) PURE;
+ STDMETHOD (UnregisterTab) (THIS_ HWND hwndTab) PURE;
+ STDMETHOD (SetTabOrder) (THIS_ HWND hwndTab, HWND hwndInsertBefore) PURE;
+ STDMETHOD (SetTabActive) (THIS_ HWND hwndTab, HWND hwndMDI, DWORD dwReserved) PURE;
+ STDMETHOD (ThumbBarAddButtons) (THIS_ HWND hwnd, UINT cButtons, LPTHUMBBUTTON pButton) PURE;
+ STDMETHOD (ThumbBarUpdateButtons) (THIS_ HWND hwnd, UINT cButtons, LPTHUMBBUTTON pButton) PURE;
+ STDMETHOD (ThumbBarSetImageList) (THIS_ HWND hwnd, HIMAGELIST himl) PURE;
+ STDMETHOD (SetOverlayIcon) (THIS_ HWND hwnd, HICON hIcon, LPCWSTR pszDescription) PURE;
+ STDMETHOD (SetThumbnailTooltip) (THIS_ HWND hwnd, LPCWSTR pszTip) PURE;
+ STDMETHOD (SetThumbnailClip) (THIS_ HWND hwnd, RECT *prcClip) PURE;
+};
+
+typedef ITaskbarList3 *LPITaskbarList3;
+
+#endif // __MINGW32__
+#endif // __GNUC__
+#endif // WIN32
+
+#endif // BACKEND_WIN32_TASKBAR_MINGW_H
diff --git a/backends/taskbar/win32/win32-taskbar.cpp b/backends/taskbar/win32/win32-taskbar.cpp
new file mode 100644
index 0000000000..0cfd81e3f2
--- /dev/null
+++ b/backends/taskbar/win32/win32-taskbar.cpp
@@ -0,0 +1,272 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+// We cannot use common/scummsys.h directly as it will include
+// windows.h and we need to do it by hand to allow excluded functions
+#if defined(HAVE_CONFIG_H)
+#include "config.h"
+#endif
+
+#if defined(WIN32) && defined(USE_TASKBAR)
+
+// Needed for taskbar functions
+#if defined(__GNUC__)
+#ifdef __MINGW32__
+ #include "backends/taskbar/win32/mingw-compat.h"
+#else
+ #error Only compilation with MingW is supported
+#endif
+#else
+ // We need certain functions that are excluded by default
+ #undef NONLS
+ #undef NOICONS
+ #include <windows.h>
+ #if defined(ARRAYSIZE)
+ #undef ARRAYSIZE
+ #endif
+
+ // Default MSVC headers for ITaskbarList3 and IShellLink
+ #include <SDKDDKVer.h>
+#endif
+#include <shlobj.h>
+
+// For HWND
+#include <SDL_syswm.h>
+
+#include "common/scummsys.h"
+
+#include "backends/taskbar/win32/win32-taskbar.h"
+
+#include "common/config-manager.h"
+#include "common/textconsole.h"
+#include "common/file.h"
+
+// System.Title property key, values taken from http://msdn.microsoft.com/en-us/library/bb787584.aspx
+const PROPERTYKEY PKEY_Title = { /* fmtid = */ { 0xF29F85E0, 0x4FF9, 0x1068, { 0xAB, 0x91, 0x08, 0x00, 0x2B, 0x27, 0xB3, 0xD9 } }, /* propID = */ 2 };
+
+Win32TaskbarManager::Win32TaskbarManager() {
+ // Do nothing if not running on Windows 7 or later
+ if (!isWin7OrLater())
+ return;
+
+ CoInitialize(NULL);
+
+ // Try creating instance (on fail, _taskbar will contain NULL)
+ HRESULT hr = CoCreateInstance(CLSID_TaskbarList,
+ 0,
+ CLSCTX_INPROC_SERVER,
+ IID_ITaskbarList3,
+ reinterpret_cast<void**> (&(_taskbar)));
+
+ if (SUCCEEDED(hr)) {
+ // Initialize taskbar object
+ if (FAILED(_taskbar->HrInit())) {
+ _taskbar->Release();
+ _taskbar = NULL;
+ }
+ } else {
+ warning("[Win32TaskbarManager::init] Cannot create taskbar instance");
+ }
+}
+
+Win32TaskbarManager::~Win32TaskbarManager() {
+ if (_taskbar)
+ _taskbar->Release();
+ _taskbar = NULL;
+
+ CoUninitialize();
+}
+
+void Win32TaskbarManager::setOverlayIcon(const Common::String &name, const Common::String &description) {
+ //warning("[Win32TaskbarManager::setOverlayIcon] Setting overlay icon to: %s (%s)", name.c_str(), description.c_str());
+
+ if (_taskbar == NULL)
+ return;
+
+ if (name.empty()) {
+ _taskbar->SetOverlayIcon(getHwnd(), NULL, L"");
+ return;
+ }
+
+ // Compute full icon path
+ Common::String path = getIconPath(name);
+ if (path.empty())
+ return;
+
+ HICON pIcon = (HICON)::LoadImage(NULL, path.c_str(), IMAGE_ICON, 16, 16, LR_LOADFROMFILE);
+ if (!pIcon) {
+ warning("[Win32TaskbarManager::setOverlayIcon] Cannot load icon!");
+ return;
+ }
+
+ // Sets the overlay icon
+ LPWSTR desc = ansiToUnicode(description.c_str());
+ _taskbar->SetOverlayIcon(getHwnd(), pIcon, desc);
+
+ DestroyIcon(pIcon);
+
+ delete[] desc;
+}
+
+void Win32TaskbarManager::setProgressValue(int completed, int total) {
+ if (_taskbar == NULL)
+ return;
+
+ _taskbar->SetProgressValue(getHwnd(), completed, total);
+}
+
+void Win32TaskbarManager::setProgressState(TaskbarProgressState state) {
+ if (_taskbar == NULL)
+ return;
+
+ _taskbar->SetProgressState(getHwnd(), (TBPFLAG)state);
+}
+
+void Win32TaskbarManager::addRecent(const Common::String &name, const Common::String &description) {
+ //warning("[Win32TaskbarManager::addRecent] Adding recent list entry: %s (%s)", name.c_str(), description.c_str());
+
+ if (_taskbar == NULL)
+ return;
+
+ // ANSI version doesn't seem to work correctly with Win7 jump lists, so explicitly use Unicode interface.
+ IShellLinkW *link;
+
+ // Get the ScummVM executable path.
+ WCHAR path[MAX_PATH];
+ GetModuleFileNameW(NULL, path, MAX_PATH);
+
+ // Create a shell link.
+ if (SUCCEEDED(CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC, IID_IShellLinkW, reinterpret_cast<void**> (&link)))) {
+ // Convert game name and description to Unicode.
+ LPWSTR game = ansiToUnicode(name.c_str());
+ LPWSTR desc = ansiToUnicode(description.c_str());
+
+ // Set link properties.
+ link->SetPath(path);
+ link->SetArguments(game);
+
+ Common::String iconPath = getIconPath(name);
+ if (iconPath.empty()) {
+ link->SetIconLocation(path, 0); // No game-specific icon available
+ } else {
+ LPWSTR icon = ansiToUnicode(iconPath.c_str());
+
+ link->SetIconLocation(icon, 0);
+
+ delete[] icon;
+ }
+
+ // The link's display name must be set via property store.
+ IPropertyStore* propStore;
+ HRESULT hr = link->QueryInterface(IID_IPropertyStore, reinterpret_cast<void**> (&(propStore)));
+ if (SUCCEEDED(hr)) {
+ PROPVARIANT pv;
+ pv.vt = VT_LPWSTR;
+ pv.pwszVal = desc;
+
+ hr = propStore->SetValue(PKEY_Title, pv);
+
+ propStore->Commit();
+ propStore->Release();
+ }
+
+ // SHAddToRecentDocs will cause the games to be added to the Recent list, allowing the user to pin them.
+ SHAddToRecentDocs(SHARD_LINK, link);
+ link->Release();
+ delete[] game;
+ delete[] desc;
+ }
+}
+
+Common::String Win32TaskbarManager::getIconPath(Common::String target) {
+ // We first try to look for a iconspath configuration variable then
+ // fallback to the extra path
+ //
+ // Icons can be either in a subfolder named "icons" or directly in the path
+
+ Common::String iconsPath = ConfMan.get("iconspath");
+ Common::String extraPath = ConfMan.get("extrapath");
+
+#define TRY_ICON_PATH(path) { \
+ Common::FSNode node((path)); \
+ if (node.exists()) \
+ return (path); \
+}
+
+ if (!iconsPath.empty()) {
+ TRY_ICON_PATH(iconsPath + "/" + target + ".ico");
+ TRY_ICON_PATH(iconsPath + "/" + ConfMan.get("gameid") + ".ico");
+ TRY_ICON_PATH(iconsPath + "/icons/" + target + ".ico");
+ TRY_ICON_PATH(iconsPath + "/icons/" + ConfMan.get("gameid") + ".ico");
+ }
+
+ if (!extraPath.empty()) {
+ TRY_ICON_PATH(extraPath + "/" + target + ".ico");
+ TRY_ICON_PATH(extraPath + "/" + ConfMan.get("gameid") + ".ico");
+ TRY_ICON_PATH(extraPath + "/icons/" + target + ".ico");
+ TRY_ICON_PATH(extraPath + "/icons/" + ConfMan.get("gameid") + ".ico");
+ }
+
+ return "";
+}
+
+bool Win32TaskbarManager::isWin7OrLater() {
+ OSVERSIONINFOEX versionInfo;
+ DWORDLONG conditionMask = 0;
+
+ ZeroMemory(&versionInfo, sizeof(OSVERSIONINFOEX));
+ versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
+ versionInfo.dwMajorVersion = 6;
+ versionInfo.dwMinorVersion = 1;
+
+ VER_SET_CONDITION(conditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL);
+ VER_SET_CONDITION(conditionMask, VER_MINORVERSION, VER_GREATER_EQUAL);
+
+ return VerifyVersionInfo(&versionInfo, VER_MAJORVERSION | VER_MINORVERSION, conditionMask);
+}
+
+LPWSTR Win32TaskbarManager::ansiToUnicode(const char *s) {
+ DWORD size = MultiByteToWideChar(0, 0, s, -1, NULL, 0);
+
+ if (size > 0) {
+ LPWSTR result = new WCHAR[size];
+ if (MultiByteToWideChar(0, 0, s, -1, result, size) != 0)
+ return result;
+ }
+
+ return NULL;
+}
+
+HWND Win32TaskbarManager::getHwnd() {
+ SDL_SysWMinfo wmi;
+ SDL_VERSION(&wmi.version);
+
+ if(!SDL_GetWMInfo(&wmi))
+ return NULL;
+
+ return wmi.window;
+}
+
+#endif
diff --git a/backends/taskbar/win32/win32-taskbar.h b/backends/taskbar/win32/win32-taskbar.h
new file mode 100644
index 0000000000..3415a79bd7
--- /dev/null
+++ b/backends/taskbar/win32/win32-taskbar.h
@@ -0,0 +1,66 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef BACKEND_WIN32_TASKBAR_H
+#define BACKEND_WIN32_TASKBAR_H
+
+#if defined(WIN32) && defined(USE_TASKBAR)
+
+#include "common/str.h"
+#include "common/taskbar.h"
+
+struct ITaskbarList3;
+
+class Win32TaskbarManager : public Common::TaskbarManager {
+public:
+ Win32TaskbarManager();
+ virtual ~Win32TaskbarManager();
+
+ virtual void setOverlayIcon(const Common::String &name, const Common::String &description);
+ virtual void setProgressValue(int completed, int total);
+ virtual void setProgressState(TaskbarProgressState state);
+ virtual void addRecent(const Common::String &name, const Common::String &description);
+
+private:
+ ITaskbarList3 *_taskbar;
+
+ /**
+ * Get the path to an icon for the game
+ *
+ * @param target The game target
+ *
+ * @return The icon path (or "" if no icon was found)
+ */
+ Common::String getIconPath(Common::String target);
+
+ // Helper functions
+ bool isWin7OrLater();
+ LPWSTR ansiToUnicode(const char *s);
+ HWND getHwnd();
+};
+
+#endif
+
+#endif // BACKEND_WIN32_TASKBAR_H
diff --git a/backends/vkeybd/virtual-keyboard-parser.cpp b/backends/vkeybd/virtual-keyboard-parser.cpp
index 5e4ce11fe4..58f0c468f6 100644
--- a/backends/vkeybd/virtual-keyboard-parser.cpp
+++ b/backends/vkeybd/virtual-keyboard-parser.cpp
@@ -205,6 +205,9 @@ bool VirtualKeyboardParser::parserCallback_event(ParserNode *node) {
evt->type = VirtualKeyboard::kVKEventModifier;
byte *flags = (byte*) malloc(sizeof(byte));
+ if (!flags)
+ error("[VirtualKeyboardParser::parserCallback_event] Cannot allocate memory");
+
*(flags) = parseFlags(node->values["modifiers"]);
evt->data = flags;
@@ -217,6 +220,9 @@ bool VirtualKeyboardParser::parserCallback_event(ParserNode *node) {
evt->type = VirtualKeyboard::kVKEventSwitchMode;
String& mode = node->values["mode"];
char *str = (char*) malloc(sizeof(char) * mode.size() + 1);
+ if (!str)
+ error("[VirtualKeyboardParser::parserCallback_event] Cannot allocate memory");
+
memcpy(str, mode.c_str(), sizeof(char) * mode.size());
str[mode.size()] = 0;
evt->data = str;
diff --git a/base/commandLine.cpp b/base/commandLine.cpp
index 61853a1ebc..6cb858525e 100644
--- a/base/commandLine.cpp
+++ b/base/commandLine.cpp
@@ -25,6 +25,9 @@
#define FORBIDDEN_SYMBOL_EXCEPTION_exit
+#include <errno.h>
+#include <limits.h>
+
#include "engines/metaengine.h"
#include "base/commandLine.h"
#include "base/plugins.h"
@@ -267,8 +270,10 @@ void registerDefaults() {
#define DO_OPTION_INT(shortCmd, longCmd) \
DO_OPTION(shortCmd, longCmd) \
char *endptr = 0; \
- strtol(option, &endptr, 0); \
- if (endptr == NULL || *endptr != 0) usage("--%s: Invalid number '%s'", longCmd, option);
+ errno = 0; \
+ long int retval = strtol(option, &endptr, 0); \
+ if (endptr == NULL || *endptr != 0 || (errno != 0 && retval == 0) || (errno == ERANGE && (retval == LONG_MAX || retval == LONG_MIN))) \
+ usage("--%s: Invalid number '%s'", longCmd, option);
// Use this for boolean options; this distinguishes between "-x" and "-X",
// resp. between "--some-option" and "--no-some-option".
diff --git a/common/forbidden.h b/common/forbidden.h
index 9cba19cf5e..95c1a47d65 100644
--- a/common/forbidden.h
+++ b/common/forbidden.h
@@ -29,7 +29,7 @@
* infrastructure code do not make use of certain "forbidden" APIs, such
* as fopen(), setjmp(), etc.
* This is achieved by re-#defining various symbols to a "garbage"
- * string which then trigers a compiler error.
+ * string which then triggers a compiler error.
*
* Backend files may #define FORBIDDEN_SYMBOL_ALLOW_ALL if they
* have to access functions like fopen, fread etc.
@@ -203,6 +203,11 @@
#define exit(a) FORBIDDEN_SYMBOL_REPLACEMENT
#endif
+#ifndef FORBIDDEN_SYMBOL_EXCEPTION_abort
+#undef abort
+#define abort() FORBIDDEN_SYMBOL_REPLACEMENT
+#endif
+
#ifndef FORBIDDEN_SYMBOL_EXCEPTION_getenv
#undef getenv
#define getenv(a) FORBIDDEN_SYMBOL_REPLACEMENT
diff --git a/common/system.cpp b/common/system.cpp
index 1645a6be10..8d5bfd39cd 100644
--- a/common/system.cpp
+++ b/common/system.cpp
@@ -27,6 +27,7 @@
#include "common/fs.h"
#include "common/savefile.h"
#include "common/str.h"
+#include "common/taskbar.h"
#include "common/textconsole.h"
#include "backends/audiocd/default/default-audiocd.h"
@@ -40,6 +41,9 @@ OSystem::OSystem() {
_eventManager = 0;
_timerManager = 0;
_savefileManager = 0;
+#if defined(USE_TASKBAR)
+ _taskbarManager = 0;
+#endif
_fsFactory = 0;
}
@@ -53,6 +57,11 @@ OSystem::~OSystem() {
delete _timerManager;
_timerManager = 0;
+#if defined(USE_TASKBAR)
+ delete _taskbarManager;
+ _taskbarManager = 0;
+#endif
+
delete _savefileManager;
_savefileManager = 0;
diff --git a/common/system.h b/common/system.h
index 3e740ff0c1..15fbe386b1 100644
--- a/common/system.h
+++ b/common/system.h
@@ -42,6 +42,9 @@ struct Rect;
class SaveFileManager;
class SearchSet;
class String;
+#if defined(USE_TASKBAR)
+class TaskbarManager;
+#endif
class TimerManager;
class SeekableReadStream;
class WriteStream;
@@ -149,6 +152,15 @@ protected:
*/
Common::SaveFileManager *_savefileManager;
+#if defined(USE_TASKBAR)
+ /**
+ * No default value is provided for _savefileManager by OSystem.
+ *
+ * @note _savefileManager is deleted by the OSystem destructor.
+ */
+ Common::TaskbarManager *_taskbarManager;
+#endif
+
/**
* No default value is provided for _fsFactory by OSystem.
*
@@ -1047,6 +1059,18 @@ public:
return _savefileManager;
}
+#if defined(USE_TASKBAR)
+ /**
+ * Returns the TaskbarManager, used to handle progress bars,
+ * icon overlay, tasks and recent items list on the taskbar.
+ *
+ * @return the TaskbarManager for the current architecture
+ */
+ virtual Common::TaskbarManager *getTaskbarManager() {
+ return _taskbarManager;
+ }
+#endif
+
/**
* Returns the FilesystemFactory object, depending on the current architecture.
*
diff --git a/common/taskbar.h b/common/taskbar.h
new file mode 100644
index 0000000000..023227e5e0
--- /dev/null
+++ b/common/taskbar.h
@@ -0,0 +1,133 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ */
+
+#ifndef COMMON_TASKBAR_MANAGER_H
+#define COMMON_TASKBAR_MANAGER_H
+
+#include "common/scummsys.h"
+#include "common/str.h"
+
+#if defined(USE_TASKBAR)
+
+namespace Common {
+
+/**
+ * The TaskbarManager allows interaction with the ScummVM application icon:
+ * - in the taskbar on Windows 7 and later
+ * - in the launcher for Unity
+ * - in the dock on MacOSX
+ * - ...
+ *
+ * This allows GUI code and engines to display a progress bar, an overlay icon and/or count
+ * associated with the ScummVM icon as well as add the started engine to the recent items
+ * list (so that the user can start the engine directly in one click).
+ *
+ * Examples of use:
+ * - Track search progress and found engines when running the Mass Add dialog
+ * - Add an entry to the recent items when starting an engine
+ * - Show the current running engine icon as an overlay
+ *
+ * @note functionality will vary between supported platforms (due to API limitations)
+ * and some of the methods will just be no-ops or approximate the functionality
+ * as best as possible
+ */
+class TaskbarManager {
+public:
+ /**
+ * Values representing the taskbar progress state
+ */
+ enum TaskbarProgressState {
+ kTaskbarNoProgress = 0,
+ kTaskbarIndeterminate = 1,
+ kTaskbarNormal = 2,
+ kTaskbarError = 4,
+ kTaskbarPaused = 8
+ };
+
+ TaskbarManager() {}
+ virtual ~TaskbarManager() {}
+
+ /**
+ * Sets an overlay icon on the taskbar icon
+ *
+ * When an empty name is given, no icon is shown
+ * and the current overlay icon (if any) is removed
+ *
+ * @param name Path to the icon
+ * @param description The description
+ *
+ * @note on Windows, the icon should be an ICO file
+ */
+ virtual void setOverlayIcon(const String &name, const String &description) {}
+
+ /**
+ * Sets a progress value on the taskbar icon
+ *
+ * @param completed The current progress value.
+ * @param total The maximum progress value.
+ */
+ virtual void setProgressValue(int completed, int total) {}
+
+ /**
+ * Sets the progress state on the taskbar icon
+ *
+ * State can be any of the following:
+ * - NoProgress: disable display of progress state
+ * - Indeterminate
+ * - Normal
+ * - Error
+ * - Paused
+ *
+ * @param state The progress state
+ */
+ virtual void setProgressState(TaskbarProgressState state) {}
+
+ /**
+ * Sets the count number associated with the icon as an overlay
+ *
+ * @param count The count
+ *
+ * @note Setting a count of 0 will hide the count
+ */
+ virtual void setCount(int count) {}
+
+ /**
+ * Adds an engine to the recent items list
+ *
+ * Path is automatically set to the current executable path,
+ * an icon name is generated (with fallback to default icon)
+ * and the command line is set to start the engine on click.
+ *
+ * @param name The target name.
+ * @param description The description.
+ */
+ virtual void addRecent(const String &name, const String &description) {}
+
+};
+
+} // End of namespace Common
+
+#endif
+
+#endif // COMMON_TASKBAR_MANAGER_H
diff --git a/common/translation.cpp b/common/translation.cpp
index 526bebcec6..59488c2dd5 100644
--- a/common/translation.cpp
+++ b/common/translation.cpp
@@ -223,9 +223,17 @@ String TranslationManager::getLangById(int id) const {
}
bool TranslationManager::openTranslationsFile(File& inFile) {
- // First try to open it directly (i.e. using the SearchMan).
- if (inFile.open("translations.dat"))
- return true;
+ // First try to open it using the SearchMan.
+ ArchiveMemberList fileList;
+ SearchMan.listMatchingMembers(fileList, "translations.dat");
+ for (ArchiveMemberList::iterator it = fileList.begin(); it != fileList.end(); ++it) {
+ SeekableReadStream *stream = it->get()->createReadStream();
+ if (stream && inFile.open(stream, it->get()->getName())) {
+ if (checkHeader(inFile))
+ return true;
+ inFile.close();
+ }
+ }
// Then look in the Themepath if we can find the file.
if (ConfMan.hasKey("themepath"))
@@ -243,8 +251,11 @@ bool TranslationManager::openTranslationsFile(const FSNode &node, File& inFile,
// necessary to make them here. But it avoid printing warnings.
FSNode fileNode = node.getChild("translations.dat");
if (fileNode.exists() && fileNode.isReadable() && !fileNode.isDirectory()) {
- if (inFile.open(fileNode))
- return true;
+ if (inFile.open(fileNode)) {
+ if (checkHeader(inFile))
+ return true;
+ inFile.close();
+ }
}
// Check if we exceeded the given recursion depth
@@ -268,13 +279,10 @@ bool TranslationManager::openTranslationsFile(const FSNode &node, File& inFile,
void TranslationManager::loadTranslationsInfoDat() {
File in;
if (!openTranslationsFile(in)) {
- warning("You are missing the 'translations.dat' file. GUI translation will not be available");
+ warning("You are missing a valid 'translations.dat' file. GUI translation will not be available");
return;
}
- if (!checkHeader(in))
- return;
-
char buf[256];
int len;
@@ -326,9 +334,6 @@ void TranslationManager::loadLanguageDat(int index) {
if (!openTranslationsFile(in))
return;
- if (!checkHeader(in))
- return;
-
char buf[1024];
int len;
@@ -386,7 +391,7 @@ bool TranslationManager::checkHeader(File &in) {
// Check header
if (strcmp(buf, "TRANSLATIONS")) {
- warning("Your 'translations.dat' file is corrupt. GUI translation will not be available");
+ warning("File '%s' is not a valid translations data file. Skipping this file", in.getName());
return false;
}
@@ -394,7 +399,7 @@ bool TranslationManager::checkHeader(File &in) {
ver = in.readByte();
if (ver != TRANSLATIONS_DAT_VER) {
- warning("Your 'translations.dat' file has a mismatching version, expected was %d but you got %d. GUI translation will not be available", TRANSLATIONS_DAT_VER, ver);
+ warning("File '%s' has a mismatching version, expected was %d but you got %d. Skipping this file", in.getName(), TRANSLATIONS_DAT_VER, ver);
return false;
}
diff --git a/configure b/configure
index 61443326d2..0c0b34adc1 100755
--- a/configure
+++ b/configure
@@ -142,6 +142,8 @@ _fluidsynth=auto
_opengl=auto
_opengles=auto
_readline=auto
+_taskbar=yes
+_libunity=auto
# Default option behaviour yes/no
_debug_build=auto
_release_build=auto
@@ -768,6 +770,7 @@ Optional Features:
--disable-scalers exclude scalers
--disable-hq-scalers exclude HQ2x and HQ3x scalers
--disable-translation don't build support for translated messages
+ --disable-taskbar don't build support for taskbar and launcher integration
--enable-text-console use text console instead of graphical console
--enable-verbose-build enable regular echoing of commands during build
process
@@ -817,6 +820,9 @@ Optional Libraries:
--with-readline-prefix=DIR Prefix where readline is installed (optional)
--disable-readline disable readline support in text console [autodetect]
+ --with-libunity-prefix=DIR Prefix where libunity is installed (optional)
+ --disable-libunity disable Unity launcher integration [autodetect]
+
Some influential environment variables:
LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
nonstandard directory <lib dir>
@@ -864,6 +870,10 @@ for ac_option in $@; do
--disable-fluidsynth) _fluidsynth=no ;;
--enable-readline) _readline=yes ;;
--disable-readline) _readline=no ;;
+ --enable-taskbar) _taskbar=yes ;;
+ --disable-taskbar) _taskbar=no ;;
+ --enable-libunity) _libunity=yes ;;
+ --disable-libunity) _libunity=no ;;
--enable-opengl) _opengl=yes ;;
--disable-opengl) _opengl=no ;;
--enable-verbose-build) _verbose_build=yes ;;
@@ -939,6 +949,11 @@ for ac_option in $@; do
READLINE_CFLAGS="-I$arg/include"
READLINE_LIBS="-L$arg/lib"
;;
+ --with-libunity-prefix=*)
+ arg=`echo $ac_option | cut -d '=' -f 2`
+ LIBUNITY_CFLAGS="-I$arg/include"
+ LIBUNITY_LIBS="-L$arg/lib"
+ ;;
--with-opengl-prefix=*)
arg=`echo $ac_option | cut -d '=' -f 2`
OPENGL_CFLAGS="-I$arg/include"
@@ -3013,6 +3028,43 @@ define_in_config_h_if_yes "$_readline" 'USE_READLINE'
define_in_config_h_if_yes "$_text_console" 'USE_TEXT_CONSOLE_FOR_DEBUGGER'
#
+# Check for Unity if taskbar integration is enabled
+#
+echocheck "libunity"
+if test "$_unix" = no || test "$_taskbar" = no; then
+ _libunity=no
+else
+if test "$_libunity" = auto ; then
+ case $_host_os in
+ mingw*)
+ # pkgconfig and unity are not supported on mingw
+ _libunity=no
+ ;;
+ *)
+ # Unity has a lots of dependencies, update the libs and cflags var with them
+ LIBUNITY_LIBS="$LIBUNITY_LIBS $(pkg-config --libs unity = 3.8.4 2>> "$TMPLOG")"
+ LIBUNITY_CFLAGS="$LIBUNITY_CFLAGS $(pkg-config --cflags unity = 3.8.4 2>> "$TMPLOG")"
+ _libunity=no
+ cat > $TMPC << EOF
+#include <unity.h>
+int main(void) {
+ unity_launcher_entry_get_for_desktop_id("scummvm.desktop");
+ return 0;
+}
+EOF
+ cc_check $LIBUNITY_CFLAGS $LIBUNITY_LIBS && _libunity=yes
+ ;;
+ esac
+fi
+if test "$_libunity" = yes ; then
+ LIBS="$LIBS $LIBUNITY_LIBS"
+ INCLUDES="$INCLUDES $LIBUNITY_CFLAGS"
+fi
+define_in_config_h_if_yes "$_libunity" 'USE_TASKBAR_UNITY'
+fi
+echo "$_libunity"
+
+#
# Check for OpenGL (ES)
#
echocheck "OpenGL"
@@ -3188,6 +3240,29 @@ EOF
fi
#
+# Check whether to build taskbar integration support
+#
+echo_n "Building taskbar integration support... "
+define_in_config_if_yes $_taskbar 'USE_TASKBAR'
+if test "$_taskbar" = yes; then
+ case $_host_os in
+ mingw*)
+ LIBS="$LIBS -lole32 -luuid"
+ echo "win32"
+ ;;
+ *)
+ if test "$_libunity" = yes; then
+ echo "unity"
+ else
+ echo "$_taskbar"
+ fi
+ ;;
+ esac
+else
+ echo "$_taskbar"
+fi
+
+#
# Figure out installation directories
#
test "x$prefix" = xNONE && prefix=/usr/local
diff --git a/devtools/create_project/create_project.cpp b/devtools/create_project/create_project.cpp
index 29bc5bfcd5..35d08561bf 100644
--- a/devtools/create_project/create_project.cpp
+++ b/devtools/create_project/create_project.cpp
@@ -364,6 +364,11 @@ int main(int argc, char *argv[]) {
provider = new CreateProjectTool::CodeBlocksProvider(globalWarnings, projectWarnings);
+
+ // Those libraries are automatically added by MSVC, but we need to add them manually with mingw
+ setup.libraries.push_back("ole32");
+ setup.libraries.push_back("uuid");
+
break;
case kProjectMSVC:
@@ -774,6 +779,7 @@ const Feature s_features[] = {
{ "mt32emu", "USE_MT32EMU", "", true, "integrated MT-32 emulator" },
{ "nasm", "USE_NASM", "", true, "IA-32 assembly support" }, // This feature is special in the regard, that it needs additional handling.
{ "opengl", "USE_OPENGL", "opengl32", true, "OpenGL support" },
+ { "taskbar", "USE_TASKBAR", "", true, "Taskbar integration support" },
{ "translation", "USE_TRANSLATION", "", true, "Translation support" },
{ "vkeybd", "ENABLE_VKEYBD", "", false, "Virtual keyboard support"},
{ "langdetect", "USE_DETECTLANG", "", true, "System language detection support" } // This feature actually depends on "translation", there
diff --git a/devtools/tasmrecover/tasm-recover b/devtools/tasmrecover/tasm-recover
index 96fd6c45fa..d6c6a2523f 100755
--- a/devtools/tasmrecover/tasm-recover
+++ b/devtools/tasmrecover/tasm-recover
@@ -22,6 +22,7 @@ generator = cpp(context, "DreamGen", blacklist = [
'width160',
'convertkey',
'readabyte',
- 'readoneblock'
+ 'readoneblock',
+ 'frameoutv'
])
generator.generate('dreamweb') #start routine
diff --git a/engines/agos/string.cpp b/engines/agos/string.cpp
index f9a06cbecb..410fd5a1ce 100644
--- a/engines/agos/string.cpp
+++ b/engines/agos/string.cpp
@@ -517,8 +517,7 @@ void AGOSEngine::printScreenText(uint vgaSpriteId, uint color, const char *strin
y -= textHeight;
} else
pos = stringLength;
- padding = (lettersPerRow - pos) % 2 ?
- (lettersPerRow - pos) / 2 + 1 : (lettersPerRow - pos) / 2;
+ padding = ((lettersPerRow - pos) % 2) ? (lettersPerRow - pos) / 2 + 1 : (lettersPerRow - pos) / 2;
while (padding--)
*convertedString2++ = ' ';
stringLength -= pos;
diff --git a/engines/draci/script.cpp b/engines/draci/script.cpp
index c4df9d9dde..8ff60033ed 100644
--- a/engines/draci/script.cpp
+++ b/engines/draci/script.cpp
@@ -1160,9 +1160,7 @@ void Script::run(const GPL2Program &program, uint16 offset) {
}
}
} else {
- debugC(1, kDraciBytecodeDebugLevel, "Unknown opcode %d, %d",
- num, subnum);
- abort();
+ error("Unknown opcode %d, %d", num, subnum);
}
GPLHandler handler = cmd->_handler;
diff --git a/engines/draci/sound.cpp b/engines/draci/sound.cpp
index 106167ef8a..d534f46a6e 100644
--- a/engines/draci/sound.cpp
+++ b/engines/draci/sound.cpp
@@ -67,8 +67,12 @@ void LegacySoundArchive::openArchive(const char *path) {
debugC(1, kDraciArchiverDebugLevel, "Loading header");
uint totalLength = _f->readUint32LE();
+
const uint kMaxSamples = 4095; // The no-sound file is exactly 16K bytes long, so don't fail on short reads
- uint sampleStarts[kMaxSamples];
+ uint *sampleStarts = (uint *)malloc(kMaxSamples * sizeof(uint));
+ if (!sampleStarts)
+ error("[LegacySoundArchive::openArchive] Cannot allocate buffer for no-sound file");
+
for (uint i = 0; i < kMaxSamples; ++i) {
sampleStarts[i] = _f->readUint32LE();
}
@@ -90,17 +94,22 @@ void LegacySoundArchive::openArchive(const char *path) {
}
if (_samples[_sampleCount-1]._offset + _samples[_sampleCount-1]._length != totalLength &&
_samples[_sampleCount-1]._offset + _samples[_sampleCount-1]._length - _samples[0]._offset != totalLength) {
- // WORKAROUND: the stored length is stored with the header for sounds and without the hader for dubbing. Crazy.
+ // WORKAROUND: the stored length is stored with the header for sounds and without the header for dubbing. Crazy.
debugC(1, kDraciArchiverDebugLevel, "Broken sound archive: %d != %d",
_samples[_sampleCount-1]._offset + _samples[_sampleCount-1]._length,
totalLength);
closeArchive();
+
+ free(sampleStarts);
+
return;
}
} else {
debugC(1, kDraciArchiverDebugLevel, "Archive info: empty");
}
+ free(sampleStarts);
+
// Indicate that the archive has been successfully opened
_opened = true;
}
diff --git a/engines/dreamweb/dreamgen.cpp b/engines/dreamweb/dreamgen.cpp
index da0d71f7fe..462ae596f8 100644
--- a/engines/dreamweb/dreamgen.cpp
+++ b/engines/dreamweb/dreamgen.cpp
@@ -4329,52 +4329,6 @@ noeffects:
cx = pop();
}
-void DreamGenContext::frameoutv() {
- STACK_CHECK;
- push(dx);
- ax = bx;
- bx = dx;
- _mul(bx);
- _add(di, ax);
- dx = pop();
- push(cx);
- ch = 0;
- _sub(dx, cx);
- cx = pop();
-frameloop1:
- push(cx);
- ch = 0;
-frameloop2:
- _lodsb();
- _cmp(al, 0);
- if (!flags.z())
- goto backtosolid;
-backtoother:
- _inc(di);
- if (--cx)
- goto frameloop2;
- cx = pop();
- _add(di, dx);
- _dec(ch);
- if (!flags.z())
- goto frameloop1;
- return;
-frameloop3:
- _lodsb();
- _cmp(al, 0);
- if (flags.z())
- goto backtoother;
-backtosolid:
- _stosb();
- if (--cx)
- goto frameloop3;
- cx = pop();
- _add(di, dx);
- _dec(ch);
- if (!flags.z())
- goto frameloop1;
-}
-
void DreamGenContext::frameoutbh() {
STACK_CHECK;
push(dx);
@@ -22126,7 +22080,6 @@ void DreamGenContext::__dispatch_call(uint16 addr) {
case 0xc214: delthisone(); break;
case 0xc228: doblocks(); break;
case 0xc22c: showframe(); break;
- case 0xc230: frameoutv(); break;
case 0xc238: frameoutbh(); break;
case 0xc23c: frameoutfx(); break;
case 0xc240: transferinv(); break;
diff --git a/engines/dreamweb/stubs.cpp b/engines/dreamweb/stubs.cpp
index eebfbeb0d4..1869f1b109 100644
--- a/engines/dreamweb/stubs.cpp
+++ b/engines/dreamweb/stubs.cpp
@@ -503,4 +503,26 @@ void DreamGenContext::showpcx() {
pcxFile.close();
}
+void DreamGenContext::frameoutv() {
+ uint16 pitch = dx;
+ uint16 width = cx & 0xff;
+ uint16 height = cx >> 8;
+ uint16 stride = pitch - width;
+
+ const uint8* src = ds.ptr(si, width * height);
+ uint8* base = es.ptr(di, stride * height);
+ uint8* dst = base + pitch * bx;
+
+ // NB: Original code assumes non-zero width and height, "for" are unneeded, do-while would suffice but would be less readable
+ for (uint16 y = 0; y < height; ++y) {
+ for (uint16 x = 0; x < width; ++x) {
+ uint8 pixel = *src++;
+ if (pixel)
+ *dst = pixel;
+ ++dst;
+ }
+ dst += stride;
+ }
+}
+
} /*namespace dreamgen */
diff --git a/engines/kyra/debugger.cpp b/engines/kyra/debugger.cpp
index d0baf8a133..e8dd9e9a15 100644
--- a/engines/kyra/debugger.cpp
+++ b/engines/kyra/debugger.cpp
@@ -71,11 +71,18 @@ bool Debugger::cmd_loadPalette(int argc, const char **argv) {
}
if (_vm->game() != GI_KYRA1 && _vm->resource()->getFileSize(argv[1]) != 768) {
- uint8 buffer[320*200];
+ uint8 *buffer = (uint8 *)malloc(320 * 200 * sizeof(uint8));
+ if (!buffer) {
+ DebugPrintf("ERROR: Cannot allocate buffer for screen region!\n");
+ return true;
+ }
+
_vm->screen()->copyRegionToBuffer(5, 0, 0, 320, 200, buffer);
_vm->screen()->loadBitmap(argv[1], 5, 5, 0);
palette.copy(_vm->screen()->getCPagePtr(5), 0, 256);
_vm->screen()->copyBlockToPage(5, 0, 0, 320, 200, buffer);
+
+ free(buffer);
} else if (!_vm->screen()->loadPalette(argv[1], palette)) {
DebugPrintf("ERROR: Palette '%s' not found!\n", argv[1]);
return true;
diff --git a/engines/lastexpress/debug.cpp b/engines/lastexpress/debug.cpp
index 4b7c5f6a9a..d5c7df0e55 100644
--- a/engines/lastexpress/debug.cpp
+++ b/engines/lastexpress/debug.cpp
@@ -31,9 +31,10 @@
#include "lastexpress/data/snd.h"
#include "lastexpress/data/subtitle.h"
+#include "lastexpress/fight/fight.h"
+
#include "lastexpress/game/action.h"
#include "lastexpress/game/beetle.h"
-#include "lastexpress/game/fight.h"
#include "lastexpress/game/inventory.h"
#include "lastexpress/game/logic.h"
#include "lastexpress/game/object.h"
diff --git a/engines/lastexpress/entities/anna.cpp b/engines/lastexpress/entities/anna.cpp
index 0bedda41e8..bce99ad16d 100644
--- a/engines/lastexpress/entities/anna.cpp
+++ b/engines/lastexpress/entities/anna.cpp
@@ -22,9 +22,10 @@
#include "lastexpress/entities/anna.h"
+#include "lastexpress/fight/fight.h"
+
#include "lastexpress/game/action.h"
#include "lastexpress/game/entities.h"
-#include "lastexpress/game/fight.h"
#include "lastexpress/game/inventory.h"
#include "lastexpress/game/logic.h"
#include "lastexpress/game/object.h"
diff --git a/engines/lastexpress/entities/ivo.cpp b/engines/lastexpress/entities/ivo.cpp
index 35f4ccfb8c..861c3cf9bd 100644
--- a/engines/lastexpress/entities/ivo.cpp
+++ b/engines/lastexpress/entities/ivo.cpp
@@ -22,9 +22,10 @@
#include "lastexpress/entities/ivo.h"
+#include "lastexpress/fight/fight.h"
+
#include "lastexpress/game/action.h"
#include "lastexpress/game/entities.h"
-#include "lastexpress/game/fight.h"
#include "lastexpress/game/logic.h"
#include "lastexpress/game/object.h"
#include "lastexpress/game/savepoint.h"
diff --git a/engines/lastexpress/entities/milos.cpp b/engines/lastexpress/entities/milos.cpp
index 587c43cade..45fd6883f0 100644
--- a/engines/lastexpress/entities/milos.cpp
+++ b/engines/lastexpress/entities/milos.cpp
@@ -24,9 +24,10 @@
#include "lastexpress/entities/vesna.h"
+#include "lastexpress/fight/fight.h"
+
#include "lastexpress/game/action.h"
#include "lastexpress/game/entities.h"
-#include "lastexpress/game/fight.h"
#include "lastexpress/game/inventory.h"
#include "lastexpress/game/logic.h"
#include "lastexpress/game/object.h"
diff --git a/engines/lastexpress/entities/salko.cpp b/engines/lastexpress/entities/salko.cpp
index 4d510bb9bf..bbaff5f1d9 100644
--- a/engines/lastexpress/entities/salko.cpp
+++ b/engines/lastexpress/entities/salko.cpp
@@ -22,9 +22,10 @@
#include "lastexpress/entities/salko.h"
+#include "lastexpress/fight/fight.h"
+
#include "lastexpress/game/action.h"
#include "lastexpress/game/entities.h"
-#include "lastexpress/game/fight.h"
#include "lastexpress/game/logic.h"
#include "lastexpress/game/object.h"
#include "lastexpress/game/savepoint.h"
diff --git a/engines/lastexpress/entities/vesna.cpp b/engines/lastexpress/entities/vesna.cpp
index 8e09dbf7b0..79ac934ef9 100644
--- a/engines/lastexpress/entities/vesna.cpp
+++ b/engines/lastexpress/entities/vesna.cpp
@@ -22,9 +22,10 @@
#include "lastexpress/entities/vesna.h"
+#include "lastexpress/fight/fight.h"
+
#include "lastexpress/game/action.h"
#include "lastexpress/game/entities.h"
-#include "lastexpress/game/fight.h"
#include "lastexpress/game/logic.h"
#include "lastexpress/game/object.h"
#include "lastexpress/game/savepoint.h"
diff --git a/engines/lastexpress/fight/fight.cpp b/engines/lastexpress/fight/fight.cpp
new file mode 100644
index 0000000000..685b3b09d1
--- /dev/null
+++ b/engines/lastexpress/fight/fight.cpp
@@ -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.
+ *
+ */
+
+#include "lastexpress/fight/fight.h"
+
+#include "lastexpress/fight/fighter_anna.h"
+#include "lastexpress/fight/fighter_ivo.h"
+#include "lastexpress/fight/fighter_milos.h"
+#include "lastexpress/fight/fighter_salko.h"
+#include "lastexpress/fight/fighter_vesna.h"
+
+#include "lastexpress/data/cursor.h"
+#include "lastexpress/data/sequence.h"
+
+#include "lastexpress/game/inventory.h"
+#include "lastexpress/game/logic.h"
+#include "lastexpress/game/object.h"
+#include "lastexpress/game/scenes.h"
+#include "lastexpress/game/state.h"
+
+#include "lastexpress/graphics.h"
+#include "lastexpress/helpers.h"
+#include "lastexpress/lastexpress.h"
+#include "lastexpress/resource.h"
+
+namespace LastExpress {
+
+Fight::FightData::FightData() {
+ player = NULL;
+ opponent = NULL;
+
+ index = 0;
+
+ isFightRunning = false;
+}
+
+Fight::FightData::~FightData() {
+ SAFE_DELETE(player);
+ SAFE_DELETE(opponent);
+}
+
+Fight::Fight(LastExpressEngine *engine) : _engine(engine), _data(NULL), _endType(kFightEndLost), _state(0), _handleTimer(false) {
+}
+
+Fight::~Fight() {
+ clearData();
+ _data = NULL;
+
+ // Zero passed pointers
+ _engine = NULL;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Events
+//////////////////////////////////////////////////////////////////////////
+void Fight::eventMouse(const Common::Event &ev) {
+ if (!_data || _data->index)
+ return;
+
+ // TODO move all the egg handling to inventory functions
+
+ getFlags()->mouseLeftClick = false;
+ getFlags()->shouldRedraw = false;
+ getFlags()->mouseRightClick = false;
+
+ if (ev.mouse.x < 608 || ev.mouse.y < 448 || ev.mouse.x >= 640 || ev.mouse.x >= 480) {
+
+ // Handle right button click
+ if (ev.type == Common::EVENT_RBUTTONUP) {
+ getSound()->removeFromQueue(kEntityTables0);
+ setStopped();
+
+ getGlobalTimer() ? _state = 0 : ++_state;
+
+ getFlags()->mouseRightClick = true;
+ }
+
+ if (_handleTimer) {
+ // Timer expired => show with full brightness
+ if (!getGlobalTimer())
+ getInventory()->drawBlinkingEgg();
+
+ _handleTimer = false;
+ }
+
+ // Check hotspots
+ Scene *scene = getScenes()->get(getState()->scene);
+ SceneHotspot *hotspot = NULL;
+
+ if (!scene->checkHotSpot(ev.mouse, &hotspot)) {
+ _engine->getCursor()->setStyle(kCursorNormal);
+ } else {
+ _engine->getCursor()->setStyle((CursorStyle)hotspot->cursor);
+
+ // Call player function
+ if (_data->player->canInteract((Fighter::FightAction)hotspot->action)) {
+ if (ev.type == Common::EVENT_LBUTTONUP)
+ _data->player->handleAction((Fighter::FightAction)hotspot->action);
+ } else {
+ _engine->getCursor()->setStyle(kCursorNormal);
+ }
+ }
+ } else {
+ // Handle clicks on menu icon
+
+ if (!_handleTimer) {
+ // Timer expired => show with full brightness
+ if (!getGlobalTimer())
+ getInventory()->drawBlinkingEgg();
+
+ _handleTimer = true;
+ }
+
+ // Stop fight if clicked
+ if (ev.type == Common::EVENT_LBUTTONUP) {
+ _handleTimer = false;
+ getSound()->removeFromQueue(kEntityTables0);
+ bailout(kFightEndExit);
+ }
+
+ // Reset timer on right click
+ if (ev.type == Common::EVENT_RBUTTONUP) {
+ if (getGlobalTimer()) {
+ if (getSound()->isBuffered("TIMER"))
+ getSound()->removeFromQueue("TIMER");
+
+ setGlobalTimer(900);
+ }
+ }
+ }
+
+ getFlags()->shouldRedraw = true;
+}
+
+void Fight::eventTick(const Common::Event &ev) {
+ handleTick(ev, true);
+}
+
+void Fight::handleTick(const Common::Event &ev, bool isProcessing) {
+ // TODO move all the egg handling to inventory functions
+
+ // Blink egg
+ if (getGlobalTimer()) {
+ warning("Fight::handleMouseMove - egg blinking not implemented!");
+ }
+
+ if (!_data || _data->index)
+ return;
+
+ SceneHotspot *hotspot = NULL;
+ if (!getScenes()->get(getState()->scene)->checkHotSpot(ev.mouse, &hotspot) || !_data->player->canInteract((Fighter::FightAction)hotspot->action)) {
+ _engine->getCursor()->setStyle(kCursorNormal);
+ } else {
+ _engine->getCursor()->setStyle((CursorStyle)hotspot->cursor);
+ }
+
+ _data->player->update();
+ _data->opponent->update();
+
+ // Draw sequences
+ if (!_data->isFightRunning)
+ return;
+
+ if (isProcessing)
+ getScenes()->drawFrames(true);
+
+ if (_data->index) {
+ // Set next sequence name index
+ _data->index--;
+ _data->sequences[_data->index] = loadSequence(_data->names[_data->index]);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Setup
+//////////////////////////////////////////////////////////////////////////
+Fight::FightEndType Fight::setup(FightType type) {
+ if (_data)
+ error("Fight::setup - calling fight setup again while a fight is already in progress!");
+
+ //////////////////////////////////////////////////////////////////////////
+ // Prepare UI & state
+ if (_state >= 5 && (type == kFightSalko || type == kFightVesna)) {
+ _state = 0;
+ return kFightEndWin;
+ }
+
+ getInventory()->showHourGlass();
+ // TODO events function
+ getFlags()->flag_0 = false;
+ getFlags()->mouseRightClick = false;
+ getEntities()->reset();
+
+ // Compute scene to use
+ SceneIndex sceneIndex;
+ switch(type) {
+ default:
+ sceneIndex = kSceneFightDefault;
+ break;
+
+ case kFightMilos:
+ sceneIndex = (getObjects()->get(kObjectCompartment1).location2 < kObjectLocation3) ? kSceneFightMilos : kSceneFightMilosBedOpened;
+ break;
+
+ case kFightAnna:
+ sceneIndex = kSceneFightAnna;
+ break;
+
+ case kFightIvo:
+ sceneIndex = kSceneFightIvo;
+ break;
+
+ case kFightSalko:
+ sceneIndex = kSceneFightSalko;
+ break;
+
+ case kFightVesna:
+ sceneIndex = kSceneFightVesna;
+ break;
+ }
+
+ if (getFlags()->shouldRedraw) {
+ getFlags()->shouldRedraw = false;
+ askForRedraw();
+ //redrawScreen();
+ }
+
+ // Load the scene object
+ Scene *scene = getScenes()->get(sceneIndex);
+
+ // Update game entities and state
+ getEntityData(kEntityPlayer)->entityPosition = scene->entityPosition;
+ getEntityData(kEntityPlayer)->location = scene->location;
+
+ getState()->scene = sceneIndex;
+
+ getFlags()->flag_3 = true;
+
+ // Draw the scene
+ _engine->getGraphicsManager()->draw(scene, GraphicsManager::kBackgroundC);
+ // FIXME move to start of fight?
+ askForRedraw();
+ redrawScreen();
+
+ //////////////////////////////////////////////////////////////////////////
+ // Setup the fight
+ _data = new FightData;
+ loadData(type);
+
+ // Show opponents & egg button
+ Common::Event emptyEvent;
+ handleTick(emptyEvent, false);
+ getInventory()->drawEgg();
+
+ // Start fight
+ _endType = kFightEndLost;
+ while (_data->isFightRunning) {
+ if (_engine->handleEvents())
+ continue;
+
+ getSound()->updateQueue();
+ }
+
+ // Cleanup after fight is over
+ clearData();
+
+ return _endType;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Status
+//////////////////////////////////////////////////////////////////////////
+void Fight::setStopped() {
+ if (_data)
+ _data->isFightRunning = false;
+}
+
+void Fight::bailout(FightEndType type) {
+ _state = 0;
+ _endType = type;
+ setStopped();
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Cleanup
+//////////////////////////////////////////////////////////////////////////
+void Fight::clearData() {
+ if (!_data)
+ return;
+
+ // Clear data
+ SAFE_DELETE(_data);
+
+ _engine->restoreEventHandlers();
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Loading
+//////////////////////////////////////////////////////////////////////////
+void Fight::loadData(FightType type) {
+ if (!_data)
+ error("Fight::loadData - invalid data!");
+
+ switch (type) {
+ default:
+ break;
+
+ case kFightMilos:
+ _data->player = new FighterPlayerMilos(_engine);
+ _data->opponent = new FighterOpponentMilos(_engine);
+ break;
+
+ case kFightAnna:
+ _data->player = new FighterPlayerAnna(_engine);
+ _data->opponent = new FighterOpponentAnna(_engine);
+ break;
+
+ case kFightIvo:
+ _data->player = new FighterPlayerIvo(_engine);
+ _data->opponent = new FighterOpponentIvo(_engine);
+ break;
+
+ case kFightSalko:
+ _data->player = new FighterPlayerSalko(_engine);
+ _data->opponent = new FighterOpponentSalko(_engine);
+ break;
+
+ case kFightVesna:
+ _data->player = new FighterPlayerVesna(_engine);
+ _data->opponent = new FighterOpponentVesna(_engine);
+ break;
+ }
+
+ if (!_data->player || !_data->opponent)
+ error("Fight::loadData - error loading fight data (type=%d)", type);
+
+ // Setup opponent pointers
+ setOpponents();
+
+ //////////////////////////////////////////////////////////////////////////
+ // Start running the fight
+ _data->isFightRunning = true;
+
+ if (_state < 5) {
+ _data->player->setSequenceAndDraw(0, Fighter::kFightSequenceType0);
+ _data->opponent->setSequenceAndDraw(0, Fighter::kFightSequenceType0);
+ goto end_load;
+ }
+
+ switch(type) {
+ default:
+ break;
+
+ case kFightMilos:
+ _data->opponent->setCountdown(1);
+ _data->player->setSequenceAndDraw(4, Fighter::kFightSequenceType0);
+ _data->opponent->setSequenceAndDraw(0, Fighter::kFightSequenceType0);
+ break;
+
+ case kFightIvo:
+ _data->opponent->setCountdown(1);
+ _data->player->setSequenceAndDraw(3, Fighter::kFightSequenceType0);
+ _data->opponent->setSequenceAndDraw(6, Fighter::kFightSequenceType0);
+ break;
+
+ case kFightVesna:
+ _data->opponent->setCountdown(1);
+ _data->player->setSequenceAndDraw(0, Fighter::kFightSequenceType0);
+ _data->player->setSequenceAndDraw(3, Fighter::kFightSequenceType2);
+ _data->opponent->setSequenceAndDraw(5, Fighter::kFightSequenceType0);
+ break;
+ }
+
+end_load:
+ // Setup event handlers
+ _engine->backupEventHandlers();
+ SET_EVENT_HANDLERS(Fight, this);
+}
+
+void Fight::setOpponents() {
+ _data->player->setOpponent(_data->opponent);
+ _data->opponent->setOpponent(_data->player);
+
+ _data->player->setFight(this);
+ _data->opponent->setFight(this);
+}
+
+} // End of namespace LastExpress
diff --git a/engines/lastexpress/fight/fight.h b/engines/lastexpress/fight/fight.h
new file mode 100644
index 0000000000..fffb520789
--- /dev/null
+++ b/engines/lastexpress/fight/fight.h
@@ -0,0 +1,125 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can 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 LASTEXPRESS_FIGHT_H
+#define LASTEXPRESS_FIGHT_H
+
+/*
+ Fight structure
+ ---------------
+ uint32 {4} - player struct
+ uint32 {4} - opponent struct
+ uint32 {4} - hasLost flag
+
+ byte {1} - isRunning
+
+ Fight participant structure
+ ---------------------------
+ uint32 {4} - function pointer
+ uint32 {4} - pointer to fight structure
+ uint32 {4} - pointer to opponent (fight participant structure)
+ uint32 {4} - array of sequences
+ uint32 {4} - number of sequences
+ uint32 {4} - ??
+ uint32 {4} - ??
+ uint32 {4} - ??
+ uint32 {4} - ??
+ uint32 {4} - ??
+ uint32 {4} - ??
+ uint32 {4} - ??
+ uint32 {4} - ??
+ uint16 {2} - ??
+ uint16 {2} - ?? - only for opponent structure
+ uint32 {4} - ?? - only for opponent structure
+
+*/
+
+#include "lastexpress/shared.h"
+
+#include "lastexpress/eventhandler.h"
+
+namespace LastExpress {
+
+class LastExpressEngine;
+class Sequence;
+
+class Fighter;
+class Opponent;
+
+class Fight : public EventHandler {
+public:
+ enum FightEndType {
+ kFightEndWin = 0,
+ kFightEndLost = 1,
+ kFightEndExit = 2
+ };
+
+ Fight(LastExpressEngine *engine);
+ ~Fight();
+
+ FightEndType setup(FightType type);
+
+ void eventMouse(const Common::Event &ev);
+ void eventTick(const Common::Event &ev);
+
+ // State
+ bool isRunning() { return _data->isFightRunning; }
+ void setRunningState(bool state) { _data->isFightRunning = state; }
+ void bailout(FightEndType type);
+ void setStopped();
+ void resetState() { _state = 0; }
+ void setEndType(FightEndType endType) { _endType = endType; }
+
+private:
+ struct FightData {
+ Fighter *player;
+ Opponent *opponent;
+ int32 index;
+
+ Sequence *sequences[20];
+ Common::String names[20];
+
+ bool isFightRunning;
+
+ FightData();
+ ~FightData();
+ };
+
+ LastExpressEngine *_engine;
+ FightData *_data;
+ FightEndType _endType;
+ int _state;
+
+ bool _handleTimer;
+
+ // Events
+ void handleTick(const Common::Event &ev, bool unknown);
+
+ // Data
+ void loadData(FightType type);
+ void clearData();
+ void setOpponents();
+};
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_FIGHT_H
diff --git a/engines/lastexpress/fight/fighter.cpp b/engines/lastexpress/fight/fighter.cpp
new file mode 100644
index 0000000000..fcd69183fb
--- /dev/null
+++ b/engines/lastexpress/fight/fighter.cpp
@@ -0,0 +1,248 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can 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 "lastexpress/fight/fighter.h"
+
+#include "lastexpress/data/sequence.h"
+
+#include "lastexpress/game/scenes.h"
+#include "lastexpress/game/sound.h"
+
+#include "lastexpress/helpers.h"
+#include "lastexpress/lastexpress.h"
+
+namespace LastExpress {
+
+Fighter::Fighter(LastExpressEngine *engine) : _engine(engine) {
+ _opponent = NULL;
+ _fight = NULL;
+
+ _sequenceIndex = 0;
+ _sequence = NULL;
+ _frame = NULL;
+ _frameIndex = 0;
+
+ _field_24 = 0;
+
+ _action = kFightAction101;
+ _sequenceIndex2 = 0;
+
+ _countdown = 1;
+
+ _field_34 = 0;
+}
+
+Fighter::~Fighter() {
+ clearSequences();
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Cleanup
+//////////////////////////////////////////////////////////////////////////
+void Fighter::clearSequences() {
+ // The original game resets the function pointers to default values, just before deleting the struct
+
+ getScenes()->removeAndRedraw(&_frame, false);
+
+ // Free sequences
+ for (int i = 0; i < (int)_sequences.size(); i++)
+ SAFE_DELETE(_sequences[i]);
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Drawing
+//////////////////////////////////////////////////////////////////////////
+void Fighter::setSequenceAndDraw(uint32 sequenceIndex, FightSequenceType type) {
+ if (_sequences.size() < sequenceIndex)
+ return;
+
+ switch (type) {
+ default:
+ break;
+
+ case kFightSequenceType0:
+ if (_sequenceIndex)
+ return;
+
+ _sequence = _sequences[sequenceIndex];
+ _sequenceIndex = sequenceIndex;
+ draw();
+ break;
+
+ case kFightSequenceType1:
+ _sequence = _sequences[sequenceIndex];
+ _sequenceIndex = sequenceIndex;
+ _sequenceIndex2 = 0;
+ draw();
+ break;
+
+ case kFightSequenceType2:
+ _sequenceIndex2 = sequenceIndex;
+ break;
+ }
+}
+
+void Fighter::draw() {
+ getScenes()->removeAndRedraw(&_frame, false);
+
+ _frameIndex = 0;
+ _field_24 = 0;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Processing
+//////////////////////////////////////////////////////////////////////////
+void Fighter::process() {
+ if (!_sequence) {
+ if (_frame) {
+ getScenes()->removeFromQueue(_frame);
+ getScenes()->setCoordinates(_frame);
+ }
+ SAFE_DELETE(_frame);
+ return;
+ }
+
+ if (_sequence->count() <= _frameIndex) {
+ switch(_action) {
+ default:
+ break;
+
+ case kFightAction101:
+ setSequenceAndDraw(_sequenceIndex2, kFightSequenceType1);
+ _sequenceIndex2 = 0;
+ break;
+
+ case kFightActionResetFrame:
+ _frameIndex = 0;
+ break;
+
+ case kFightAction103:
+ setSequenceAndDraw(0, kFightSequenceType1);
+ handleAction(kFightAction101);
+ _opponent->setSequenceAndDraw(0, kFightSequenceType1);
+ _opponent->handleAction(kFightAction101);
+ _opponent->update();
+ break;
+
+ case kFightActionWin:
+ _fight->bailout(Fight::kFightEndWin);
+ break;
+
+ case kFightActionLost:
+ _fight->bailout(Fight::kFightEndLost);
+ break;
+ }
+ }
+
+ if (_fight->isRunning()) {
+
+ // Get the current sequence frame
+ SequenceFrame *frame = new SequenceFrame(_sequence, (uint16)_frameIndex);
+ frame->getInfo()->location = 1;
+
+ if (_frame == frame) {
+ delete frame;
+ return;
+ }
+
+ getSound()->playFightSound(frame->getInfo()->soundAction, frame->getInfo()->field_31);
+
+ // Add current frame to queue and advance
+ getScenes()->addToQueue(frame);
+ _frameIndex++;
+
+ if (_frame) {
+ getScenes()->removeFromQueue(_frame);
+
+ if (!frame->getInfo()->field_2E)
+ getScenes()->setCoordinates(_frame);
+ }
+
+ // Replace by new frame
+ delete _frame;
+ _frame = frame;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Default actions
+//////////////////////////////////////////////////////////////////////////
+void Fighter::handleAction(FightAction action) {
+ switch (action) {
+ default:
+ return;
+
+ case kFightAction101:
+ break;
+
+ case kFightActionResetFrame:
+ _countdown--;
+ break;
+
+ case kFightAction103:
+ _opponent->handleAction(kFightActionResetFrame);
+ break;
+
+ case kFightActionWin:
+ _fight->setEndType(Fight::kFightEndWin);
+ _opponent->handleAction(kFightActionResetFrame);
+ break;
+
+ case kFightActionLost:
+ _fight->setEndType(Fight::kFightEndLost);
+ _opponent->handleAction(kFightActionResetFrame);
+ break;
+ }
+
+ // Update action
+ _action = action;
+}
+
+bool Fighter::canInteract(FightAction /*action = kFightActionNone*/ ) {
+ return (_action == kFightAction101 && !_sequenceIndex);
+}
+
+void Fighter::update() {
+ process();
+
+ if (_frame)
+ _frame->getInfo()->location = (_action == kFightActionResetFrame ? 2 : 0);
+}
+
+void Opponent::update() {
+ process();
+
+ if (_field_38 && !_sequenceIndex)
+ _field_38--;
+
+ if (_frame)
+ _frame->getInfo()->location = 1;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Helpers
+//////////////////////////////////////////////////////////////////////////
+bool Fighter::checkFrame(uint32 val) {
+ return (_frame->getInfo()->field_33 & val);
+}
+
+} // End of namespace LastExpress
diff --git a/engines/lastexpress/fight/fighter.h b/engines/lastexpress/fight/fighter.h
new file mode 100644
index 0000000000..e37fe49d86
--- /dev/null
+++ b/engines/lastexpress/fight/fighter.h
@@ -0,0 +1,123 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can 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 LASTEXPRESS_FIGHTER_H
+#define LASTEXPRESS_FIGHTER_H
+
+#include "lastexpress/fight/fight.h"
+
+#include "common/array.h"
+
+namespace LastExpress {
+
+class Fight;
+class Sequence;
+class SequenceFrame;
+
+class Fighter {
+public:
+ enum FightAction {
+ kFightActionNone = 0,
+ kFightAction1 = 1,
+ kFightAction2 = 2,
+ kFightAction3 = 3,
+ kFightAction4 = 4,
+ kFightAction5 = 5,
+ kFightAction101 = 101,
+ kFightActionResetFrame = 102,
+ kFightAction103 = 103,
+ kFightActionWin = 104,
+ kFightActionLost = 105,
+ kFightAction128 = 128,
+ kFightAction129 = 129,
+ kFightAction130 = 130,
+ kFightAction131 = 131,
+ kFightAction132 = 132
+ };
+
+ enum FightSequenceType {
+ kFightSequenceType0 = 0,
+ kFightSequenceType1 = 1,
+ kFightSequenceType2 = 2
+ };
+
+ Fighter(LastExpressEngine *engine);
+ virtual ~Fighter();
+
+ // Default functions
+ virtual void handleAction(FightAction action);
+ virtual void update();
+ virtual bool canInteract(FightAction action = kFightActionNone);
+
+ // Drawing
+ void setSequenceAndDraw(uint32 sequenceIndex, FightSequenceType type);
+
+ // Accessors
+ void setOpponent(Fighter *opponent) { _opponent = opponent; }
+ void setCountdown(int32 countdown) { _countdown = countdown; }
+ void setFight(Fight *fight) { _fight = fight; }
+
+ int getCountdown() { return _countdown; }
+ uint32 getSequenceIndex() { return _sequenceIndex; }
+ uint32 getField34() { return _field_34; }
+
+protected:
+ LastExpressEngine *_engine;
+ Fight *_fight;
+ Fighter *_opponent;
+ Sequence *_sequence;
+ SequenceFrame *_frame;
+ uint32 _sequenceIndex;
+ Common::Array<Sequence *> _sequences;
+ uint32 _frameIndex;
+ uint32 _field_24;
+ FightAction _action;
+ uint32 _sequenceIndex2;
+ int32 _countdown; // countdown before loosing ?
+ uint32 _field_34;
+
+ // Drawing and processing
+ void draw();
+ void process();
+
+ // Cleanup
+ void clearSequences();
+
+ // Helpers
+ bool checkFrame(uint32 val);
+};
+
+class Opponent : public Fighter {
+public:
+ Opponent(LastExpressEngine *engine) : Fighter(engine) {
+ _field_38 = 0;
+ }
+
+ virtual void update();
+
+protected:
+ int32 _field_38;
+};
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_FIGHTER_H
diff --git a/engines/lastexpress/fight/fighter_anna.cpp b/engines/lastexpress/fight/fighter_anna.cpp
new file mode 100644
index 0000000000..db2ab54c4b
--- /dev/null
+++ b/engines/lastexpress/fight/fighter_anna.cpp
@@ -0,0 +1,186 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can 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 "lastexpress/fight/fighter_anna.h"
+
+#include "lastexpress/data/sequence.h"
+
+#include "lastexpress/game/sound.h"
+
+#include "lastexpress/helpers.h"
+#include "lastexpress/lastexpress.h"
+#include "lastexpress/resource.h"
+
+namespace LastExpress {
+
+//////////////////////////////////////////////////////////////////////////
+// Player
+//////////////////////////////////////////////////////////////////////////
+FighterPlayerAnna::FighterPlayerAnna(LastExpressEngine *engine) : Fighter(engine) {
+ _sequences.push_back(loadSequence("2002cr.seq"));
+ _sequences.push_back(loadSequence("2002cdl.seq"));
+ _sequences.push_back(loadSequence("2002cdr.seq"));
+ _sequences.push_back(loadSequence("2002cdm.seq"));
+ _sequences.push_back(loadSequence("2002lbk.seq"));
+}
+
+void FighterPlayerAnna::handleAction(FightAction action) {
+ switch (action) {
+ default:
+ Fighter::handleAction(action);
+ return;
+
+ case kFightAction1:
+ if ((_sequenceIndex != 1 && _sequenceIndex != 3) || checkFrame(4)) {
+ setSequenceAndDraw(4, kFightSequenceType1);
+ _opponent->setSequenceAndDraw(4, kFightSequenceType1);
+
+ _opponent->handleAction(kFightAction103);
+ update();
+ } else {
+ _field_34++;
+ }
+ break;
+
+ case kFightAction2:
+ if ((_sequenceIndex != 2 && _sequenceIndex != 3) || checkFrame(4)) {
+ setSequenceAndDraw(4, kFightSequenceType1);
+ _opponent->setSequenceAndDraw(5, kFightSequenceType1);
+
+ _opponent->handleAction(kFightAction103);
+ update();
+ } else {
+ _field_34++;
+ }
+ break;
+
+ case kFightAction3:
+ if ((_sequenceIndex != 2 && _sequenceIndex != 1) || checkFrame(4)) {
+ setSequenceAndDraw(4, kFightSequenceType1);
+ _opponent->setSequenceAndDraw(6, kFightSequenceType1);
+
+ _opponent->handleAction(kFightAction103);
+ update();
+ } else {
+ _field_34++;
+ }
+ break;
+
+ case kFightAction128:
+ switch (_opponent->getSequenceIndex()) {
+ default:
+ setSequenceAndDraw(3, kFightSequenceType0);
+ break;
+
+ case 1:
+ setSequenceAndDraw(1, kFightSequenceType0);
+ break;
+
+ case 2:
+ setSequenceAndDraw(3, kFightSequenceType0);
+ break;
+
+ case 3:
+ setSequenceAndDraw(2, kFightSequenceType0);
+ break;
+ }
+ break;
+ }
+
+ if (_field_34 > 4) {
+ getSound()->removeFromQueue(kEntityTables0);
+ _fight->bailout(Fight::kFightEndWin);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Opponent
+//////////////////////////////////////////////////////////////////////////
+FighterOpponentAnna::FighterOpponentAnna(LastExpressEngine *engine) : Opponent(engine) {
+ _sequences.push_back(loadSequence("2002or.seq"));
+ _sequences.push_back(loadSequence("2002oal.seq"));
+ _sequences.push_back(loadSequence("2002oam.seq"));
+ _sequences.push_back(loadSequence("2002oar.seq"));
+ _sequences.push_back(loadSequence("2002okr.seq"));
+ _sequences.push_back(loadSequence("2002okml.seq"));
+ _sequences.push_back(loadSequence("2002okm.seq"));
+
+ getSound()->playSound(kEntityTables0, "MUS030", SoundManager::kFlagDefault);
+
+ _field_38 = 30;
+}
+
+void FighterOpponentAnna::update() {
+ if (!_field_38 && canInteract(kFightAction1) && !_sequenceIndex2) {
+
+ if (_opponent->getField34() >= 2) {
+ switch (rnd(6)) {
+ default:
+ break;
+
+ case 0:
+ setSequenceAndDraw(1, kFightSequenceType0);
+ break;
+
+ case 1:
+ setSequenceAndDraw(2, kFightSequenceType0);
+ break;
+
+ case 2:
+ setSequenceAndDraw(3, kFightSequenceType0);
+ break;
+
+ case 3:
+ setSequenceAndDraw(3, kFightSequenceType0);
+ setSequenceAndDraw(2, kFightSequenceType2);
+ break;
+
+ case 4:
+ setSequenceAndDraw(1, kFightSequenceType0);
+ setSequenceAndDraw(2, kFightSequenceType2);
+ break;
+
+ case 5:
+ setSequenceAndDraw(3, kFightSequenceType0);
+ setSequenceAndDraw(2, kFightSequenceType2);
+ break;
+ }
+ }
+
+ // Update field_38
+ _field_38 = (int32)rnd(15);
+ }
+
+ if (_frame && checkFrame(2)) {
+ if (_sequenceIndex == 1 || _sequenceIndex == 2 || _sequenceIndex == 3)
+ _opponent->handleAction((FightAction)_sequenceIndex);
+
+ if (_opponent->getCountdown() <= 0) {
+ getSound()->removeFromQueue(kEntityTables0);
+ handleAction(kFightActionLost);
+ }
+ }
+
+ Fighter::update();
+}
+
+} // End of namespace LastExpress
diff --git a/engines/lastexpress/fight/fighter_anna.h b/engines/lastexpress/fight/fighter_anna.h
new file mode 100644
index 0000000000..abb6f9dc64
--- /dev/null
+++ b/engines/lastexpress/fight/fighter_anna.h
@@ -0,0 +1,48 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 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 LASTEXPRESS_FIGHTER_ANNA_H
+#define LASTEXPRESS_FIGHTER_ANNA_H
+
+#include "lastexpress/fight/fighter.h"
+
+namespace LastExpress {
+
+class LastExpressEngine;
+
+class FighterPlayerAnna : public Fighter {
+public:
+ FighterPlayerAnna(LastExpressEngine *engine);
+
+ virtual void handleAction(FightAction action);
+};
+
+class FighterOpponentAnna : public Opponent {
+public:
+ FighterOpponentAnna(LastExpressEngine *engine);
+
+ virtual void update();
+};
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_FIGHTER_ANNA_H
diff --git a/engines/lastexpress/fight/fighter_ivo.cpp b/engines/lastexpress/fight/fighter_ivo.cpp
new file mode 100644
index 0000000000..423b6b4ce5
--- /dev/null
+++ b/engines/lastexpress/fight/fighter_ivo.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.
+ *
+ */
+
+#include "lastexpress/fight/fighter_ivo.h"
+
+#include "lastexpress/data/sequence.h"
+
+#include "lastexpress/game/sound.h"
+
+#include "lastexpress/helpers.h"
+#include "lastexpress/lastexpress.h"
+#include "lastexpress/resource.h"
+
+namespace LastExpress {
+
+//////////////////////////////////////////////////////////////////////////
+// Player
+//////////////////////////////////////////////////////////////////////////
+FighterPlayerIvo::FighterPlayerIvo(LastExpressEngine *engine) : Fighter(engine) {
+ _sequences.push_back(loadSequence("2003cr.seq"));
+ _sequences.push_back(loadSequence("2003car.seq"));
+ _sequences.push_back(loadSequence("2003cal.seq"));
+ _sequences.push_back(loadSequence("2003cdr.seq"));
+ _sequences.push_back(loadSequence("2003cdm.seq"));
+ _sequences.push_back(loadSequence("2003chr.seq"));
+ _sequences.push_back(loadSequence("2003chl.seq"));
+ _sequences.push_back(loadSequence("2003ckr.seq"));
+ _sequences.push_back(loadSequence("2003lbk.seq"));
+ _sequences.push_back(loadSequence("2003fbk.seq"));
+
+ _countdown = 5;
+}
+
+void FighterPlayerIvo::handleAction(FightAction action) {
+ switch (action) {
+ default:
+ Fighter::handleAction(action);
+ return;
+
+ case kFightAction1:
+ if (_sequenceIndex != 1 || checkFrame(4)) {
+ setSequenceAndDraw(7, kFightSequenceType1);
+ _opponent->setSequenceAndDraw(4, kFightSequenceType1);
+
+ _opponent->handleAction(kFightAction103);
+ update();
+ }
+ break;
+
+ case kFightAction2:
+ if ((_sequenceIndex != 2 && _sequenceIndex != 3) || checkFrame(4)) {
+ setSequenceAndDraw(7, kFightSequenceType1);
+ _opponent->setSequenceAndDraw(5, kFightSequenceType1);
+
+ _opponent->handleAction(kFightAction103);
+ update();
+ }
+ break;
+
+ case kFightAction128:
+ switch (_opponent->getSequenceIndex()) {
+ default:
+ case 1:
+ setSequenceAndDraw(1, kFightSequenceType0);
+ break;
+
+ case 2:
+ setSequenceAndDraw(2, kFightSequenceType0);
+ break;
+ }
+ break;
+
+ case kFightAction129:
+ setSequenceAndDraw((_opponent->getCountdown() > 1) ? 4 : 3, _sequenceIndex ? kFightSequenceType2 : kFightSequenceType0);
+ break;
+
+ case kFightAction130:
+ setSequenceAndDraw(3, _sequenceIndex ? kFightSequenceType2 : kFightSequenceType0);
+ break;
+ }
+}
+
+void FighterPlayerIvo::update() {
+
+ if ((_sequenceIndex == 3 || _sequenceIndex == 4) && !_frameIndex)
+ _opponent->handleAction(kFightAction131);
+
+ if (_frame && checkFrame(2)) {
+
+ // Draw sequences
+ if (_opponent->getCountdown() <= 0) {
+ setSequenceAndDraw(9, kFightSequenceType1);
+ _opponent->setSequenceAndDraw(8, kFightSequenceType1);
+ getSound()->removeFromQueue(kEntityTables0);
+
+ handleAction(kFightActionWin);
+ return;
+ }
+
+ if (_sequenceIndex == 3 || _sequenceIndex == 4)
+ _opponent->handleAction((FightAction)_sequenceIndex);
+ }
+
+ Fighter::update();
+}
+
+bool FighterPlayerIvo::canInteract(FightAction action) {
+ if (action == kFightAction129 || action == kFightAction130)
+ return (_sequenceIndex >= 8);
+
+ return Fighter::canInteract();
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Opponent
+//////////////////////////////////////////////////////////////////////////
+FighterOpponentIvo::FighterOpponentIvo(LastExpressEngine *engine) : Opponent(engine) {
+ _sequences.push_back(loadSequence("2003or.seq"));
+ _sequences.push_back(loadSequence("2003oal.seq"));
+ _sequences.push_back(loadSequence("2003oar.seq"));
+ _sequences.push_back(loadSequence("2003odm.seq"));
+ _sequences.push_back(loadSequence("2003okl.seq"));
+ _sequences.push_back(loadSequence("2003okj.seq"));
+ _sequences.push_back(loadSequence("blank.seq"));
+ _sequences.push_back(loadSequence("csdr.seq"));
+ _sequences.push_back(loadSequence("2003l.seq"));
+
+ getSound()->playSound(kEntityTables0, "MUS032", SoundManager::kFlagDefault);
+
+ _countdown = 5;
+ _field_38 = 15;
+}
+
+void FighterOpponentIvo::handleAction(FightAction action) {
+ switch (action) {
+ default:
+ Fighter::handleAction(action);
+ break;
+
+ case kFightAction3:
+ if ((_sequenceIndex != 1 && _sequenceIndex != 3) || checkFrame(4)) {
+ setSequenceAndDraw(6, kFightSequenceType1);
+ _opponent->setSequenceAndDraw(6, kFightSequenceType1);
+ _opponent->handleAction(kFightAction103);
+ }
+ break;
+
+ case kFightAction4:
+ if ((_sequenceIndex != 2 && _sequenceIndex != 3) || checkFrame(4)) {
+ setSequenceAndDraw(6, kFightSequenceType1);
+ _opponent->setSequenceAndDraw(5, kFightSequenceType1);
+ _opponent->handleAction(kFightAction103);
+ }
+ break;
+
+ case kFightAction131:
+ if (_sequenceIndex)
+ break;
+
+ if (rnd(100) <= (unsigned int)(_countdown > 2 ? 60 : 75)) {
+ setSequenceAndDraw(3 , kFightSequenceType1);
+ if (_opponent->getSequenceIndex() == 4)
+ setSequenceAndDraw(2, kFightSequenceType2);
+ }
+ break;
+ }
+}
+
+void FighterOpponentIvo::update() {
+ if (!_field_38 && canInteract(kFightAction1) && !_sequenceIndex2) {
+
+ if (_opponent->getField34() >= 2) {
+ switch (rnd(5)) {
+ default:
+ break;
+
+ case 0:
+ setSequenceAndDraw(1, kFightSequenceType0);
+ break;
+
+ case 1:
+ setSequenceAndDraw(2, kFightSequenceType0);
+ break;
+
+ case 2:
+ setSequenceAndDraw(1, kFightSequenceType0);
+ setSequenceAndDraw(2, kFightSequenceType2);
+ break;
+
+ case 3:
+ setSequenceAndDraw(0, kFightSequenceType2);
+ setSequenceAndDraw(1, kFightSequenceType2);
+ break;
+
+ case 4:
+ setSequenceAndDraw(0, kFightSequenceType1);
+ setSequenceAndDraw(1, kFightSequenceType2);
+ break;
+ }
+ }
+
+ // Update field_38
+ _field_38 = 3 * _countdown + (int32)rnd(10);
+ }
+
+ if (_frame && checkFrame(2)) {
+
+ if (_opponent->getCountdown() <= 0) {
+ setSequenceAndDraw(7, kFightSequenceType1);
+ _opponent->setSequenceAndDraw(8, kFightSequenceType1);
+ getSound()->removeFromQueue(kEntityTables0);
+
+ _opponent->handleAction(kFightActionWin);
+
+ return;
+ }
+
+ if (_sequenceIndex == 1 || _sequenceIndex == 2)
+ _opponent->handleAction((FightAction)_sequenceIndex);
+ }
+
+ Fighter::update();
+}
+
+} // End of namespace LastExpress
diff --git a/engines/lastexpress/fight/fighter_ivo.h b/engines/lastexpress/fight/fighter_ivo.h
new file mode 100644
index 0000000000..ca54fea904
--- /dev/null
+++ b/engines/lastexpress/fight/fighter_ivo.h
@@ -0,0 +1,51 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef LASTEXPRESS_FIGHTER_IVO_H
+#define LASTEXPRESS_FIGHTER_IVO_H
+
+#include "lastexpress/fight/fighter.h"
+
+namespace LastExpress {
+
+class LastExpressEngine;
+
+class FighterPlayerIvo : public Fighter {
+public:
+ FighterPlayerIvo(LastExpressEngine *engine);
+
+ virtual void handleAction(FightAction action);
+ virtual void update();
+ virtual bool canInteract(FightAction action = kFightActionNone);
+};
+
+class FighterOpponentIvo : public Opponent {
+public:
+ FighterOpponentIvo(LastExpressEngine *engine);
+
+ virtual void handleAction(FightAction action);
+ virtual void update();
+};
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_FIGHTER_IVO_H
diff --git a/engines/lastexpress/fight/fighter_milos.cpp b/engines/lastexpress/fight/fighter_milos.cpp
new file mode 100644
index 0000000000..46e4bde7a6
--- /dev/null
+++ b/engines/lastexpress/fight/fighter_milos.cpp
@@ -0,0 +1,221 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can 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 "lastexpress/fight/fighter_milos.h"
+
+#include "lastexpress/data/cursor.h"
+#include "lastexpress/data/sequence.h"
+
+#include "lastexpress/game/sound.h"
+
+#include "lastexpress/helpers.h"
+#include "lastexpress/lastexpress.h"
+#include "lastexpress/resource.h"
+
+namespace LastExpress {
+
+//////////////////////////////////////////////////////////////////////////
+// Player
+//////////////////////////////////////////////////////////////////////////
+FighterPlayerMilos::FighterPlayerMilos(LastExpressEngine *engine) : Fighter(engine) {
+ _sequences.push_back(loadSequence("2001cr.seq"));
+ _sequences.push_back(loadSequence("2001cdl.seq"));
+ _sequences.push_back(loadSequence("2001cdr.seq"));
+ _sequences.push_back(loadSequence("2001cdm.seq"));
+ _sequences.push_back(loadSequence("2001csgr.seq"));
+ _sequences.push_back(loadSequence("2001csgl.seq"));
+ _sequences.push_back(loadSequence("2001dbk.seq"));
+}
+
+void FighterPlayerMilos::handleAction(FightAction action) {
+ switch (action) {
+ default:
+ Fighter::handleAction(action);
+ return;
+
+ case kFightAction1:
+ if (_sequenceIndex != 1 || checkFrame(4)) {
+ setSequenceAndDraw(6, kFightSequenceType1);
+ _opponent->setSequenceAndDraw(3, kFightSequenceType1);
+
+ _opponent->handleAction(kFightAction103);
+ update();
+ } else {
+ _field_34++;
+ }
+ break;
+
+ case kFightAction2:
+ if ((_sequenceIndex != 2 && _sequenceIndex != 3) || checkFrame(4)) {
+ setSequenceAndDraw(6, kFightSequenceType1);
+ _opponent->setSequenceAndDraw(4, kFightSequenceType1);
+
+ _opponent->handleAction(kFightAction103);
+ update();
+ } else {
+ _field_34++;
+ }
+ break;
+
+ case kFightAction128:
+ if (_sequenceIndex != 1 || checkFrame(4) || _opponent->getSequenceIndex() != 1) {
+ switch (_opponent->getSequenceIndex()) {
+ default:
+ setSequenceAndDraw(rnd(3) + 1, kFightSequenceType0);
+ break;
+
+ case 1:
+ setSequenceAndDraw(1, kFightSequenceType0);
+ break;
+
+ case 2:
+ setSequenceAndDraw(3, kFightSequenceType0);
+ break;
+ }
+ } else {
+ setSequenceAndDraw(4, kFightSequenceType1);
+ update();
+ }
+ break;
+ }
+}
+
+void FighterPlayerMilos::update() {
+ if (_frame && checkFrame(2)) {
+
+ // Draw sequences
+ if (_opponent->getCountdown() <= 0) {
+ setSequenceAndDraw(5, kFightSequenceType1);
+ _opponent->setSequenceAndDraw(6, kFightSequenceType1);
+
+ getSound()->removeFromQueue(kEntityTables0);
+ getSound()->playSound(kEntityTrain, "MUS029", SoundManager::kFlagDefault);
+
+ handleAction(kFightActionWin);
+ }
+
+ if (_sequenceIndex == 4) {
+ _opponent->handleAction(kFightAction4);
+ _fight->setEndType(Fight::kFightEndLost);
+ }
+ }
+
+ Fighter::update();
+}
+
+bool FighterPlayerMilos::canInteract(FightAction action) {
+ if (action != kFightAction128
+ || _sequenceIndex != 1
+ || !_frame
+ || checkFrame(4)
+ || _opponent->getSequenceIndex() != 1) {
+ return Fighter::canInteract();
+ }
+
+ _engine->getCursor()->setStyle(kCursorHand);
+
+ return true;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Opponent
+//////////////////////////////////////////////////////////////////////////
+FighterOpponentMilos::FighterOpponentMilos(LastExpressEngine *engine) : Opponent(engine) {
+ _sequences.push_back(loadSequence("2001or.seq"));
+ _sequences.push_back(loadSequence("2001oal.seq"));
+ _sequences.push_back(loadSequence("2001oam.seq"));
+ _sequences.push_back(loadSequence("2001okl.seq"));
+ _sequences.push_back(loadSequence("2001okm.seq"));
+ _sequences.push_back(loadSequence("2001dbk.seq"));
+ _sequences.push_back(loadSequence("2001wbk.seq"));
+
+ getSound()->playSound(kEntityTables0, "MUS027", SoundManager::kFlagDefault);
+
+ _field_38 = 35;
+}
+
+void FighterOpponentMilos::handleAction(FightAction action) {
+ if (action == kFightAction4) {
+ setSequenceAndDraw(5, kFightSequenceType1);
+ _opponent->handleAction(kFightAction103);
+ } else {
+ if (action != kFightAction131)
+ Fighter::handleAction(action);
+ }
+}
+
+void FighterOpponentMilos::update() {
+ if (!_field_38 && canInteract(kFightAction1) && !_sequenceIndex2) {
+
+ if (_opponent->getField34() >= 2) {
+ switch (rnd(5)) {
+ default:
+ break;
+
+ case 0:
+ setSequenceAndDraw(1, kFightSequenceType0);
+ break;
+
+ case 1:
+ setSequenceAndDraw(2, kFightSequenceType0);
+ break;
+
+ case 2:
+ setSequenceAndDraw(2, kFightSequenceType0);
+ setSequenceAndDraw(2, kFightSequenceType1);
+ break;
+
+ case 3:
+ setSequenceAndDraw(1, kFightSequenceType0);
+ setSequenceAndDraw(2, kFightSequenceType2);
+ break;
+
+ case 4:
+ setSequenceAndDraw(1, kFightSequenceType0);
+ setSequenceAndDraw(1, kFightSequenceType2);
+ break;
+ }
+ } else {
+ setSequenceAndDraw(2, kFightSequenceType0);
+ }
+
+ // Update field_38
+ if (_opponent->getField34() < 5)
+ _field_38 = 6 * (5 - _opponent->getField34());
+ else
+ _field_38 = 0;
+ }
+
+ if (_frame && checkFrame(2)) {
+ if (_sequenceIndex == 1 || _sequenceIndex == 2)
+ _opponent->handleAction((FightAction)_sequenceIndex);
+
+ if (_opponent->getCountdown() <= 0) {
+ getSound()->removeFromQueue(kEntityTables0);
+ handleAction(kFightActionLost);
+ }
+ }
+
+ Fighter::update();
+}
+
+} // End of namespace LastExpress
diff --git a/engines/lastexpress/fight/fighter_milos.h b/engines/lastexpress/fight/fighter_milos.h
new file mode 100644
index 0000000000..2126dd1838
--- /dev/null
+++ b/engines/lastexpress/fight/fighter_milos.h
@@ -0,0 +1,51 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef LASTEXPRESS_FIGHTER_MILOS_H
+#define LASTEXPRESS_FIGHTER_MILOS_H
+
+#include "lastexpress/fight/fighter.h"
+
+namespace LastExpress {
+
+class LastExpressEngine;
+
+class FighterPlayerMilos : public Fighter {
+public:
+ FighterPlayerMilos(LastExpressEngine *engine);
+
+ virtual void handleAction(FightAction action);
+ virtual void update();
+ virtual bool canInteract(FightAction action = kFightActionNone);
+};
+
+class FighterOpponentMilos : public Opponent {
+public:
+ FighterOpponentMilos(LastExpressEngine *engine);
+
+ virtual void handleAction(FightAction action);
+ virtual void update();
+};
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_FIGHTER_MILOS_H
diff --git a/engines/lastexpress/fight/fighter_salko.cpp b/engines/lastexpress/fight/fighter_salko.cpp
new file mode 100644
index 0000000000..795dd41b93
--- /dev/null
+++ b/engines/lastexpress/fight/fighter_salko.cpp
@@ -0,0 +1,201 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can 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 "lastexpress/fight/fighter_salko.h"
+
+#include "lastexpress/data/cursor.h"
+#include "lastexpress/data/sequence.h"
+
+#include "lastexpress/game/sound.h"
+
+#include "lastexpress/helpers.h"
+#include "lastexpress/lastexpress.h"
+#include "lastexpress/resource.h"
+
+namespace LastExpress {
+
+//////////////////////////////////////////////////////////////////////////
+// Player
+//////////////////////////////////////////////////////////////////////////
+FighterPlayerSalko::FighterPlayerSalko(LastExpressEngine *engine) : Fighter(engine) {
+ _sequences.push_back(loadSequence("2004cr.seq"));
+ _sequences.push_back(loadSequence("2004cdr.seq"));
+ _sequences.push_back(loadSequence("2004chj.seq"));
+ _sequences.push_back(loadSequence("2004bk.seq"));
+
+ _countdown = 2;
+}
+
+void FighterPlayerSalko::handleAction(FightAction action) {
+ switch (action) {
+ default:
+ Fighter::handleAction(action);
+ return;
+
+ case kFightAction1:
+ case kFightAction2:
+ if (_sequenceIndex != 1 && checkFrame(4)) {
+ _field_34 = 0;
+
+ setSequenceAndDraw(3, kFightSequenceType1);
+ _opponent->setSequenceAndDraw((action == kFightAction1 ? 3 : 4), kFightSequenceType1);
+
+ _opponent->handleAction(kFightAction103);
+
+ if (action == kFightAction2)
+ _countdown= 0;
+
+ update();
+ } else {
+ _field_34++;
+ }
+ break;
+
+ case kFightAction5:
+ if (_sequenceIndex != 3) {
+ _opponent->handleAction(kFightAction103);
+ update();
+ }
+ break;
+
+ case kFightAction128:
+ setSequenceAndDraw(1, kFightSequenceType0);
+ _field_34 = 0;
+ break;
+
+ case kFightAction131:
+ setSequenceAndDraw(2, (_sequenceIndex ? kFightSequenceType2 : kFightSequenceType0));
+ break;
+ }
+}
+
+void FighterPlayerSalko::update() {
+ Fighter::update();
+
+ // The original doesn't check for currentSequence2 != NULL (might not happen when everything is working properly, but crashes with our current implementation)
+ if (_frame && checkFrame(2)) {
+
+ if (_opponent->getCountdown() <= 0) {
+ getSound()->removeFromQueue(kEntityTables0);
+ _fight->bailout(Fight::kFightEndWin);
+
+ return;
+ }
+
+ if (_sequenceIndex == 2)
+ _opponent->handleAction(kFightAction2);
+ }
+}
+
+bool FighterPlayerSalko::canInteract(FightAction action) {
+ if (action == kFightAction131) {
+ if (_sequenceIndex == 1) {
+ if (_opponent->getCountdown() <= 0)
+ _engine->getCursor()->setStyle(kCursorHand);
+
+ return true;
+ }
+
+ return false;
+ }
+
+ return Fighter::canInteract();
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Opponent
+//////////////////////////////////////////////////////////////////////////
+FighterOpponentSalko::FighterOpponentSalko(LastExpressEngine *engine) : Opponent(engine) {
+ _sequences.push_back(loadSequence("2004or.seq"));
+ _sequences.push_back(loadSequence("2004oam.seq"));
+ _sequences.push_back(loadSequence("2004oar.seq"));
+ _sequences.push_back(loadSequence("2004okr.seq"));
+ _sequences.push_back(loadSequence("2004ohm.seq"));
+ _sequences.push_back(loadSequence("blank.seq"));
+
+ getSound()->playSound(kEntityTables0, "MUS035", SoundManager::kFlagDefault);
+
+ _countdown = 3;
+ _field_38 = 30;
+}
+
+void FighterOpponentSalko::handleAction(FightAction action) {
+ if (action == kFightAction2) {
+ setSequenceAndDraw(5, kFightSequenceType1);
+ _opponent->handleAction(kFightAction103);
+ } else {
+ Fighter::handleAction(action);
+ }
+}
+
+void FighterOpponentSalko::update() {
+ if (!_field_38 && canInteract(kFightAction1) && !_sequenceIndex2) {
+
+ switch (rnd(5)) {
+ default:
+ break;
+
+ case 0:
+ setSequenceAndDraw(1, kFightSequenceType0);
+ break;
+
+ case 1:
+ setSequenceAndDraw(2, kFightSequenceType0);
+ break;
+
+ case 2:
+ setSequenceAndDraw(1, kFightSequenceType0);
+ setSequenceAndDraw(2, kFightSequenceType2);
+ break;
+
+ case 3:
+ setSequenceAndDraw(2, kFightSequenceType0);
+ setSequenceAndDraw(1, kFightSequenceType2);
+ break;
+
+ case 4:
+ setSequenceAndDraw(1, kFightSequenceType0);
+ setSequenceAndDraw(1, kFightSequenceType2);
+ break;
+ }
+
+ // Update field_38
+ _field_38 = 4 * _countdown;
+ }
+
+ if (_frame && checkFrame(2)) {
+ if (_opponent->getCountdown() <= 0) {
+ getSound()->removeFromQueue(kEntityTables0);
+ _fight->bailout(Fight::kFightEndLost);
+
+ // Stop processing
+ return;
+ }
+
+ if (_sequenceIndex == 1 || _sequenceIndex == 2)
+ _opponent->handleAction((FightAction)_sequenceIndex);
+ }
+
+ Fighter::update();
+}
+
+} // End of namespace LastExpress
diff --git a/engines/lastexpress/fight/fighter_salko.h b/engines/lastexpress/fight/fighter_salko.h
new file mode 100644
index 0000000000..0a2a615867
--- /dev/null
+++ b/engines/lastexpress/fight/fighter_salko.h
@@ -0,0 +1,51 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef LASTEXPRESS_FIGHTER_SALKO_H
+#define LASTEXPRESS_FIGHTER_SALKO_H
+
+#include "lastexpress/fight/fighter.h"
+
+namespace LastExpress {
+
+class LastExpressEngine;
+
+class FighterPlayerSalko : public Fighter {
+public:
+ FighterPlayerSalko(LastExpressEngine *engine);
+
+ virtual void handleAction(FightAction action);
+ virtual void update();
+ virtual bool canInteract(FightAction action = kFightActionNone);
+};
+
+class FighterOpponentSalko : public Opponent {
+public:
+ FighterOpponentSalko(LastExpressEngine *engine);
+
+ virtual void handleAction(FightAction action);
+ virtual void update();
+};
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_FIGHTER_SALKO_H
diff --git a/engines/lastexpress/fight/fighter_vesna.cpp b/engines/lastexpress/fight/fighter_vesna.cpp
new file mode 100644
index 0000000000..a2460106b0
--- /dev/null
+++ b/engines/lastexpress/fight/fighter_vesna.cpp
@@ -0,0 +1,264 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 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 "lastexpress/fight/fighter_vesna.h"
+
+#include "lastexpress/data/cursor.h"
+#include "lastexpress/data/sequence.h"
+
+#include "lastexpress/game/sound.h"
+
+#include "lastexpress/helpers.h"
+#include "lastexpress/lastexpress.h"
+#include "lastexpress/resource.h"
+
+namespace LastExpress {
+
+//////////////////////////////////////////////////////////////////////////
+// Player
+//////////////////////////////////////////////////////////////////////////
+FighterPlayerVesna::FighterPlayerVesna(LastExpressEngine *engine) : Fighter(engine) {
+ _sequences.push_back(loadSequence("2005cr.seq"));
+ _sequences.push_back(loadSequence("2005cdr.seq"));
+ _sequences.push_back(loadSequence("2005cbr.seq"));
+ _sequences.push_back(loadSequence("2005bk.seq"));
+ _sequences.push_back(loadSequence("2005cdm1.seq"));
+ _sequences.push_back(loadSequence("2005chl.seq"));
+}
+
+void FighterPlayerVesna::handleAction(FightAction action) {
+ switch (action) {
+ default:
+ Fighter::handleAction(action);
+ return;
+
+ case kFightAction1:
+ if (_sequenceIndex != 1) {
+ _opponent->handleAction(kFightAction103);
+ update();
+ } else {
+ _field_34++;
+ }
+ break;
+
+ case kFightAction2:
+ if (_sequenceIndex != 2) {
+ _opponent->handleAction(kFightAction103);
+ update();
+ } else {
+ _field_34++;
+ }
+ break;
+
+ case kFightAction5:
+ if (_sequenceIndex != 3) {
+ _opponent->handleAction(kFightAction103);
+ update();
+ }
+ break;
+
+ case kFightAction128:
+ if (_sequenceIndex == 1 && _opponent->getSequenceIndex() == 1 && checkFrame(4)) {
+ setSequenceAndDraw(5, kFightSequenceType1);
+ } else {
+ setSequenceAndDraw((_opponent->getSequenceIndex() == 5) ? 3 : 1, kFightSequenceType0);
+ }
+ break;
+
+ case kFightAction132:
+ setSequenceAndDraw(2, kFightSequenceType0);
+ break;
+ }
+
+ if (_field_34 > 10) {
+ _opponent->setSequenceAndDraw(5, kFightSequenceType2);
+ _opponent->setCountdown(1);
+ _field_34 = 0;
+ }
+}
+
+void FighterPlayerVesna::update() {
+ if (_frame && checkFrame(2)) {
+
+ if (_sequenceIndex == 3)
+ _opponent->handleAction(kFightAction3);
+
+ if (_opponent->getCountdown() <= 0) {
+ getSound()->removeFromQueue(kEntityTables0);
+ _fight->bailout(Fight::kFightEndWin);
+ return;
+ }
+
+ if (_sequenceIndex == 5)
+ _opponent->handleAction(kFightAction5);
+ }
+
+ Fighter::update();
+}
+
+bool FighterPlayerVesna::canInteract(FightAction action) {
+ if (action != kFightAction128)
+ return Fighter::canInteract();
+
+ if (_sequenceIndex != 1) {
+
+ if (_opponent->getSequenceIndex() == 5) {
+ _engine->getCursor()->setStyle(kCursorDown);
+ return true;
+ }
+
+ return Fighter::canInteract();
+ }
+
+ if (_opponent->getSequenceIndex() == 1 && checkFrame(4)) {
+ _engine->getCursor()->setStyle(kCursorPunchLeft);
+ return true;
+ }
+
+ return false;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Opponent
+//////////////////////////////////////////////////////////////////////////
+FighterOpponentVesna::FighterOpponentVesna(LastExpressEngine *engine) : Opponent(engine) {
+ _sequences.push_back(loadSequence("2005or.seq"));
+ _sequences.push_back(loadSequence("2005oam.seq"));
+ _sequences.push_back(loadSequence("2005oar.seq"));
+ _sequences.push_back(loadSequence("2005okml.seq"));
+ _sequences.push_back(loadSequence("2005okr.seq"));
+ _sequences.push_back(loadSequence("2005odm1.seq"));
+ _sequences.push_back(loadSequence("2005csbm.seq"));
+ _sequences.push_back(loadSequence("2005oam4.seq"));
+
+ getSound()->playSound(kEntityTables0, "MUS038", SoundManager::kFlagDefault);
+
+ _countdown = 4;
+ _field_38 = 30;
+}
+
+void FighterOpponentVesna::handleAction(FightAction action) {
+ switch (action) {
+ default:
+ Fighter::handleAction(action);
+ break;
+
+ case kFightAction3:
+ _opponent->handleAction(kFightAction103);
+ break;
+
+ case kFightAction5:
+ setSequenceAndDraw(7, kFightSequenceType1);
+ _opponent->handleAction(kFightAction103);
+ if (_countdown <= 1)
+ _countdown = 1;
+ break;
+
+ case kFightAction131:
+ break;
+ }
+}
+
+void FighterOpponentVesna::update() {
+ if (!_field_38 && canInteract(kFightAction1) && !_sequenceIndex2) {
+
+ if (_opponent->getField34() == 1) {
+ setSequenceAndDraw(2, kFightSequenceType0);
+ } else {
+ switch (rnd(6)) {
+ default:
+ break;
+
+ case 0:
+ setSequenceAndDraw(1, kFightSequenceType0);
+ break;
+
+ case 1:
+ setSequenceAndDraw(1, kFightSequenceType0);
+ setSequenceAndDraw(1, kFightSequenceType2);
+ break;
+
+ case 2:
+ setSequenceAndDraw(2, kFightSequenceType0);
+ break;
+
+ case 3:
+ setSequenceAndDraw(2, kFightSequenceType0);
+ setSequenceAndDraw(2, kFightSequenceType2);
+ break;
+
+ case 4:
+ setSequenceAndDraw(1, kFightSequenceType0);
+ setSequenceAndDraw(2, kFightSequenceType2);
+ break;
+
+ case 5:
+ setSequenceAndDraw(2, kFightSequenceType0);
+ setSequenceAndDraw(1, kFightSequenceType2);
+ break;
+ }
+ }
+
+ // Update field_38
+ _field_38 = 4 * _countdown;
+ }
+
+ if (_frame && checkFrame(2)) {
+ if (_sequenceIndex == 1 || _sequenceIndex == 2 || _sequenceIndex == 5)
+ _opponent->handleAction((FightAction)_sequenceIndex);
+
+ if (_opponent->getCountdown() <= 0) {
+
+ switch (_sequenceIndex) {
+ default:
+ break;
+
+ case 1:
+ setSequenceAndDraw(3, kFightSequenceType1);
+ break;
+
+ case 2:
+ setSequenceAndDraw(4, kFightSequenceType1);
+ break;
+
+ case 5:
+ setSequenceAndDraw(6, kFightSequenceType1);
+ break;
+ }
+
+ _opponent->setSequenceAndDraw(4, kFightSequenceType1);
+
+ handleAction(kFightActionLost);
+ _opponent->update();
+ Fighter::update();
+
+ getSound()->removeFromQueue(kEntityTables0);
+
+ // Stop processing
+ return;
+ }
+ }
+
+ Fighter::update();
+}
+
+} // End of namespace LastExpress
diff --git a/engines/lastexpress/fight/fighter_vesna.h b/engines/lastexpress/fight/fighter_vesna.h
new file mode 100644
index 0000000000..5c8ec855ae
--- /dev/null
+++ b/engines/lastexpress/fight/fighter_vesna.h
@@ -0,0 +1,51 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef LASTEXPRESS_FIGHTER_VESNA_H
+#define LASTEXPRESS_FIGHTER_VESNA_H
+
+#include "lastexpress/fight/fighter.h"
+
+namespace LastExpress {
+
+class LastExpressEngine;
+
+class FighterPlayerVesna : public Fighter {
+public:
+ FighterPlayerVesna(LastExpressEngine *engine);
+
+ virtual void handleAction(FightAction action);
+ virtual void update();
+ virtual bool canInteract(FightAction action = kFightActionNone);
+};
+
+class FighterOpponentVesna : public Opponent {
+public:
+ FighterOpponentVesna(LastExpressEngine *engine);
+
+ virtual void handleAction(FightAction action);
+ virtual void update();
+};
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_FIGHTER_VESNA_H
diff --git a/engines/lastexpress/game/fight.cpp b/engines/lastexpress/game/fight.cpp
deleted file mode 100644
index ecc43bed2b..0000000000
--- a/engines/lastexpress/game/fight.cpp
+++ /dev/null
@@ -1,1583 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 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 "lastexpress/game/fight.h"
-
-#include "lastexpress/data/cursor.h"
-#include "lastexpress/data/scene.h"
-#include "lastexpress/data/sequence.h"
-
-#include "lastexpress/game/entities.h"
-#include "lastexpress/game/inventory.h"
-#include "lastexpress/game/logic.h"
-#include "lastexpress/game/object.h"
-#include "lastexpress/game/scenes.h"
-#include "lastexpress/game/sound.h"
-#include "lastexpress/game/state.h"
-
-#include "lastexpress/graphics.h"
-#include "lastexpress/helpers.h"
-#include "lastexpress/lastexpress.h"
-#include "lastexpress/resource.h"
-
-#include "common/func.h"
-
-namespace LastExpress {
-
-#define CALL_FUNCTION0(fighter, name) \
- (*fighter->name)(fighter)
-
-#define CALL_FUNCTION1(fighter, name, a) \
- (*fighter->name)(fighter, a)
-
-#define REGISTER_PLAYER_FUNCTIONS(name) \
- if (!_data) \
- error("Fight::load##namePlayer - invalid data!"); \
- _data->player->handleAction = new Common::Functor2Mem<Fighter *, FightAction, void, Fight>(this, &Fight::handleAction##name); \
- _data->player->update = new Common::Functor1Mem<Fighter *, void, Fight>(this, &Fight::update##name); \
- _data->player->canInteract = new Common::Functor2Mem<Fighter const *, FightAction, bool, Fight>(this, &Fight::canInteract##name);
-
-#define REGISTER_OPPONENT_FUNCTIONS(name) \
- if (!_data) \
- error("Fight::load##nameOpponent - invalid data!"); \
- _data->opponent->handleAction = new Common::Functor2Mem<Fighter *, FightAction, void, Fight>(this, &Fight::handleOpponentAction##name); \
- _data->opponent->update = new Common::Functor1Mem<Fighter *, void, Fight>(this, &Fight::updateOpponent##name); \
- _data->opponent->canInteract = new Common::Functor2Mem<Fighter const *, FightAction, bool, Fight>(this, &Fight::canInteract);
-
-#define CHECK_SEQUENCE2(fighter, value) \
- (fighter->frame->getInfo()->field_33 & value)
-
-Fight::Fight(LastExpressEngine *engine) : _engine(engine), _data(NULL), _endType(kFightEndLost), _state(0), _handleTimer(false) {}
-
-Fight::~Fight() {
- clearData();
- _data = NULL;
-
- // Zero passed pointers
- _engine = NULL;
-}
-
-//////////////////////////////////////////////////////////////////////////
-// Events
-//////////////////////////////////////////////////////////////////////////
-
-void Fight::eventMouse(const Common::Event &ev) {
- if (!_data || _data->index)
- return;
-
- // TODO move all the egg handling to inventory functions
-
- getFlags()->mouseLeftClick = false;
- getFlags()->shouldRedraw = false;
- getFlags()->mouseRightClick = false;
-
- if (ev.mouse.x < 608 || ev.mouse.y < 448 || ev.mouse.x >= 640 || ev.mouse.x >= 480) {
-
- // Handle right button click
- if (ev.type == Common::EVENT_RBUTTONUP) {
- getSound()->removeFromQueue(kEntityTables0);
- setStopped();
-
- getGlobalTimer() ? _state = 0 : ++_state;
-
- getFlags()->mouseRightClick = true;
- }
-
- if (_handleTimer) {
- // Timer expired => show with full brightness
- if (!getGlobalTimer())
- getInventory()->drawBlinkingEgg();
-
- _handleTimer = false;
- }
-
- // Check hotspots
- Scene *scene = getScenes()->get(getState()->scene);
- SceneHotspot *hotspot = NULL;
-
- if (!scene->checkHotSpot(ev.mouse, &hotspot)) {
- _engine->getCursor()->setStyle(kCursorNormal);
- } else {
- _engine->getCursor()->setStyle((CursorStyle)hotspot->cursor);
-
- // Call player function
- if (CALL_FUNCTION1(_data->player, canInteract, (FightAction)hotspot->action)) {
- if (ev.type == Common::EVENT_LBUTTONUP)
- CALL_FUNCTION1(_data->player, handleAction, (FightAction)hotspot->action);
- } else {
- _engine->getCursor()->setStyle(kCursorNormal);
- }
- }
- } else {
- // Handle clicks on menu icon
-
- if (!_handleTimer) {
- // Timer expired => show with full brightness
- if (!getGlobalTimer())
- getInventory()->drawBlinkingEgg();
-
- _handleTimer = true;
- }
-
- // Stop fight if clicked
- if (ev.type == Common::EVENT_LBUTTONUP) {
- _handleTimer = false;
- getSound()->removeFromQueue(kEntityTables0);
- bailout(kFightEndExit);
- }
-
- // Reset timer on right click
- if (ev.type == Common::EVENT_RBUTTONUP) {
- if (getGlobalTimer()) {
- if (getSound()->isBuffered("TIMER"))
- getSound()->removeFromQueue("TIMER");
-
- setGlobalTimer(900);
- }
- }
- }
-
- getFlags()->shouldRedraw = true;
-}
-
-void Fight::eventTick(const Common::Event &ev) {
- handleTick(ev, true);
-}
-
-void Fight::handleTick(const Common::Event &ev, bool isProcessing) {
- // TODO move all the egg handling to inventory functions
-
- // Blink egg
- if (getGlobalTimer()) {
- warning("Fight::handleMouseMove - egg blinking not implemented!");
- }
-
- if (!_data || _data->index)
- return;
-
- SceneHotspot *hotspot = NULL;
- if (!getScenes()->get(getState()->scene)->checkHotSpot(ev.mouse, &hotspot) || !CALL_FUNCTION1(_data->player, canInteract, (FightAction)hotspot->action)) {
- _engine->getCursor()->setStyle(kCursorNormal);
- } else {
- _engine->getCursor()->setStyle((CursorStyle)hotspot->cursor);
- }
-
- CALL_FUNCTION0(_data->player, update);
- CALL_FUNCTION0(_data->opponent, update);
-
- // Draw sequences
- if (!_data->isRunning)
- return;
-
- if (isProcessing)
- getScenes()->drawFrames(true);
-
- if (_data->index) {
- // Set next sequence name index
- _data->index--;
- _data->sequences[_data->index] = loadSequence(_data->names[_data->index]);
- }
-}
-
-//////////////////////////////////////////////////////////////////////////
-// Setup
-//////////////////////////////////////////////////////////////////////////
-
-Fight::FightEndType Fight::setup(FightType type) {
- if (_data)
- error("Fight::setup - calling fight setup again while a fight is already in progress!");
-
- //////////////////////////////////////////////////////////////////////////
- // Prepare UI & state
- if (_state >= 5 && (type == kFightSalko || type == kFightVesna)) {
- _state = 0;
- return kFightEndWin;
- }
-
- getInventory()->showHourGlass();
- // TODO events function
- getFlags()->flag_0 = false;
- getFlags()->mouseRightClick = false;
- getEntities()->reset();
-
- // Compute scene to use
- SceneIndex sceneIndex;
- switch(type) {
- default:
- sceneIndex = kSceneFightDefault;
- break;
-
- case kFightMilos:
- sceneIndex = (getObjects()->get(kObjectCompartment1).location2 < kObjectLocation3) ? kSceneFightMilos : kSceneFightMilosBedOpened;
- break;
-
- case kFightAnna:
- sceneIndex = kSceneFightAnna;
- break;
-
- case kFightIvo:
- sceneIndex = kSceneFightIvo;
- break;
-
- case kFightSalko:
- sceneIndex = kSceneFightSalko;
- break;
-
- case kFightVesna:
- sceneIndex = kSceneFightVesna;
- break;
- }
-
- if (getFlags()->shouldRedraw) {
- getFlags()->shouldRedraw = false;
- askForRedraw();
- //redrawScreen();
- }
-
- // Load the scene object
- Scene *scene = getScenes()->get(sceneIndex);
-
- // Update game entities and state
- getEntityData(kEntityPlayer)->entityPosition = scene->entityPosition;
- getEntityData(kEntityPlayer)->location = scene->location;
-
- getState()->scene = sceneIndex;
-
- getFlags()->flag_3 = true;
-
- // Draw the scene
- _engine->getGraphicsManager()->draw(scene, GraphicsManager::kBackgroundC);
- // FIXME move to start of fight?
- askForRedraw();
- redrawScreen();
-
- //////////////////////////////////////////////////////////////////////////
- // Setup the fight
- _data = new FightData;
- loadData(type);
-
- // Show opponents & egg button
- Common::Event emptyEvent;
- handleTick(emptyEvent, false);
- getInventory()->drawEgg();
-
- // Start fight
- _endType = kFightEndLost;
- while (_data->isRunning) {
- if (_engine->handleEvents())
- continue;
-
- getSound()->updateQueue();
- }
-
- // Cleanup after fight is over
- clearData();
-
- return _endType;
-}
-
-//////////////////////////////////////////////////////////////////////////
-// Status
-//////////////////////////////////////////////////////////////////////////
-
-void Fight::setStopped() {
- if (_data)
- _data->isRunning = false;
-}
-
-void Fight::bailout(FightEndType type) {
- _state = 0;
- _endType = type;
- setStopped();
-}
-
-//////////////////////////////////////////////////////////////////////////
-// Cleanup
-//////////////////////////////////////////////////////////////////////////
-
-void Fight::clearData() {
- if (!_data)
- return;
-
- // Clear data
- clearSequences(_data->player);
- clearSequences(_data->opponent);
-
- SAFE_DELETE(_data->player);
- SAFE_DELETE(_data->opponent);
-
- SAFE_DELETE(_data);
-
- _engine->restoreEventHandlers();
-}
-
-void Fight::clearSequences(Fighter *combatant) const {
- if (!combatant)
- return;
-
- // The original game resets the function pointers to default values, just before deleting the struct
- getScenes()->removeAndRedraw(&combatant->frame, false);
-
- // Free sequences
- for (int i = 0; i < (int)combatant->sequences.size(); i++)
- SAFE_DELETE(combatant->sequences[i]);
-}
-
-//////////////////////////////////////////////////////////////////////////
-// Drawing
-//////////////////////////////////////////////////////////////////////////
-
-void Fight::setSequenceAndDraw(Fighter *combatant, uint32 sequenceIndex, FightSequenceType type) const {
- if (combatant->sequences.size() < sequenceIndex)
- return;
-
- switch (type) {
- default:
- break;
-
- case kFightSequenceType0:
- if (combatant->sequenceIndex)
- return;
-
- combatant->sequence = combatant->sequences[sequenceIndex];
- combatant->sequenceIndex = sequenceIndex;
- draw(combatant);
- break;
-
- case kFightSequenceType1:
- combatant->sequence = combatant->sequences[sequenceIndex];
- combatant->sequenceIndex = sequenceIndex;
- combatant->sequenceIndex2 = 0;
- draw(combatant);
- break;
-
- case kFightSequenceType2:
- combatant->sequenceIndex2 = sequenceIndex;
- break;
- }
-}
-
-void Fight::draw(Fighter *combatant) const {
- getScenes()->removeAndRedraw(&combatant->frame, false);
-
- combatant->frameIndex = 0;
- combatant->field_24 = 0;
-}
-
-//////////////////////////////////////////////////////////////////////////
-// Loading
-//////////////////////////////////////////////////////////////////////////
-
-void Fight::loadData(FightType type) {
- if (!_data)
- error("Fight::loadData - invalid data!");
-
- switch (type) {
- default:
- break;
-
- case kFightMilos:
- loadMilosPlayer();
- loadMilosOpponent();
- break;
-
- case kFightAnna:
- loadAnnaPlayer();
- loadAnnaOpponent();
- break;
-
- case kFightIvo:
- loadIvoPlayer();
- loadIvoOpponent();
- break;
-
- case kFightSalko:
- loadSalkoPlayer();
- loadSalkoOpponent();
- break;
-
- case kFightVesna:
- loadVesnaPlayer();
- loadVesnaOpponent();
- break;
- }
-
- if (!_data->player || !_data->opponent)
- error("Fight::loadData - error loading fight data (type=%d)", type);
-
- //////////////////////////////////////////////////////////////////////////
- // Start running the fight
- _data->isRunning = true;
-
- if (_state < 5) {
- setSequenceAndDraw(_data->player, 0, kFightSequenceType0);
- setSequenceAndDraw(_data->opponent, 0, kFightSequenceType0);
- goto end_load;
- }
-
- switch(type) {
- default:
- break;
-
- case kFightMilos:
- _data->opponent->countdown = 1;
- setSequenceAndDraw(_data->player, 4, kFightSequenceType0);
- setSequenceAndDraw(_data->opponent, 0, kFightSequenceType0);
- break;
-
- case kFightIvo:
- _data->opponent->countdown = 1;
- setSequenceAndDraw(_data->player, 3, kFightSequenceType0);
- setSequenceAndDraw(_data->opponent, 6, kFightSequenceType0);
- break;
-
- case kFightVesna:
- _data->opponent->countdown = 1;
- setSequenceAndDraw(_data->player, 0, kFightSequenceType0);
- setSequenceAndDraw(_data->player, 3, kFightSequenceType2);
- setSequenceAndDraw(_data->opponent, 5, kFightSequenceType0);
- break;
- }
-
-end_load:
- // Setup event handlers
- _engine->backupEventHandlers();
- SET_EVENT_HANDLERS(Fight, this);
-}
-
-//////////////////////////////////////////////////////////////////////////
-// Shared
-//////////////////////////////////////////////////////////////////////////
-void Fight::processFighter(Fighter *fighter) {
- if (!_data)
- error("Fight::processFighter - invalid data!");
-
- if (!fighter->sequence) {
- if (fighter->frame) {
- getScenes()->removeFromQueue(fighter->frame);
- getScenes()->setCoordinates(fighter->frame);
- }
- SAFE_DELETE(fighter->frame);
- return;
- }
-
- if (fighter->sequence->count() <= fighter->frameIndex) {
- switch(fighter->action) {
- default:
- break;
-
- case kFightAction101:
- setSequenceAndDraw(fighter, fighter->sequenceIndex2, kFightSequenceType1);
- fighter->sequenceIndex2 = 0;
- break;
-
- case kFightActionResetFrame:
- fighter->frameIndex = 0;
- break;
-
- case kFightAction103:
- setSequenceAndDraw(fighter, 0, kFightSequenceType1);
- CALL_FUNCTION1(fighter, handleAction, kFightAction101);
- setSequenceAndDraw(fighter->opponent, 0, kFightSequenceType1);
- CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction101);
- CALL_FUNCTION0(fighter->opponent, update);
- break;
-
- case kFightActionWin:
- bailout(kFightEndWin);
- break;
-
- case kFightActionLost:
- bailout(kFightEndLost);
- break;
- }
- }
-
- if (_data->isRunning) {
-
- // Get the current sequence frame
- SequenceFrame *frame = new SequenceFrame(fighter->sequence, (uint16)fighter->frameIndex);
- frame->getInfo()->location = 1;
-
- if (fighter->frame == frame) {
- delete frame;
- return;
- }
-
- getSound()->playFightSound(frame->getInfo()->soundAction, frame->getInfo()->field_31);
-
- // Add current frame to queue and advance
- getScenes()->addToQueue(frame);
- fighter->frameIndex++;
-
- if (fighter->frame) {
- getScenes()->removeFromQueue(fighter->frame);
-
- if (!frame->getInfo()->field_2E)
- getScenes()->setCoordinates(fighter->frame);
- }
-
- // Replace by new frame
- delete fighter->frame;
- fighter->frame = frame;
- }
-}
-
-void Fight::handleAction(Fighter *fighter, FightAction action) {
- switch (action) {
- default:
- return;
-
- case kFightAction101:
- break;
-
- case kFightActionResetFrame:
- fighter->countdown--;
- break;
-
- case kFightAction103:
- CALL_FUNCTION1(fighter->opponent, handleAction, kFightActionResetFrame);
- break;
-
- case kFightActionWin:
- _endType = kFightEndWin;
- CALL_FUNCTION1(fighter->opponent, handleAction, kFightActionResetFrame);
- break;
-
- case kFightActionLost:
- _endType = kFightEndLost;
- CALL_FUNCTION1(fighter->opponent, handleAction, kFightActionResetFrame);
- break;
- }
-
- // Update action
- fighter->action = action;
-}
-
-bool Fight::canInteract(Fighter const *fighter, FightAction /*= (FightAction)0*/ ) {
- return (fighter->action == kFightAction101 && !fighter->sequenceIndex);
-}
-
-void Fight::update(Fighter *fighter) {
-
- processFighter(fighter);
-
- if (fighter->frame)
- fighter->frame->getInfo()->location = (fighter->action == kFightActionResetFrame ? 2 : 0);
-}
-
-void Fight::updateOpponent(Fighter *fighter) {
-
- // This is an opponent struct!
- Opponent *opponent = (Opponent *)fighter;
-
- processFighter(opponent);
-
- if (opponent->field_38 && !opponent->sequenceIndex)
- opponent->field_38--;
-
- if (fighter->frame)
- fighter->frame->getInfo()->location = 1;
-}
-
-//////////////////////////////////////////////////////////////////////////
-// Milos
-//////////////////////////////////////////////////////////////////////////
-
-void Fight::loadMilosPlayer() {
- REGISTER_PLAYER_FUNCTIONS(Milos)
-
- _data->player->sequences.push_back(loadSequence("2001cr.seq"));
- _data->player->sequences.push_back(loadSequence("2001cdl.seq"));
- _data->player->sequences.push_back(loadSequence("2001cdr.seq"));
- _data->player->sequences.push_back(loadSequence("2001cdm.seq"));
- _data->player->sequences.push_back(loadSequence("2001csgr.seq"));
- _data->player->sequences.push_back(loadSequence("2001csgl.seq"));
- _data->player->sequences.push_back(loadSequence("2001dbk.seq"));
-}
-
-void Fight::loadMilosOpponent() {
- REGISTER_OPPONENT_FUNCTIONS(Milos)
-
- _data->opponent->sequences.push_back(loadSequence("2001or.seq"));
- _data->opponent->sequences.push_back(loadSequence("2001oal.seq"));
- _data->opponent->sequences.push_back(loadSequence("2001oam.seq"));
- _data->opponent->sequences.push_back(loadSequence("2001okl.seq"));
- _data->opponent->sequences.push_back(loadSequence("2001okm.seq"));
- _data->opponent->sequences.push_back(loadSequence("2001dbk.seq"));
- _data->opponent->sequences.push_back(loadSequence("2001wbk.seq"));
-
- getSound()->playSound(kEntityTables0, "MUS027", SoundManager::kFlagDefault);
-
- _data->opponent->field_38 = 35;
-}
-
-void Fight::handleActionMilos(Fighter *fighter, FightAction action) {
- switch (action) {
- default:
- handleAction(fighter, action);
- return;
-
- case kFightAction1:
- if (fighter->sequenceIndex != 1 || CHECK_SEQUENCE2(fighter, 4)) {
- setSequenceAndDraw(fighter, 6, kFightSequenceType1);
- setSequenceAndDraw(fighter->opponent, 3, kFightSequenceType1);
-
- CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103);
- CALL_FUNCTION0(fighter, update);
- } else {
- fighter->field_34++;
- }
- break;
-
- case kFightAction2:
- if ((fighter->sequenceIndex != 2 && fighter->sequenceIndex != 3) || CHECK_SEQUENCE2(fighter, 4)) {
- setSequenceAndDraw(fighter, 6, kFightSequenceType1);
- setSequenceAndDraw(fighter->opponent, 4, kFightSequenceType1);
-
- CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103);
- CALL_FUNCTION0(fighter, update);
- } else {
- fighter->field_34++;
- }
- break;
-
- case kFightAction128:
- if (fighter->sequenceIndex != 1 || CHECK_SEQUENCE2(fighter, 4) || fighter->opponent->sequenceIndex != 1) {
- switch (fighter->opponent->sequenceIndex) {
- default:
- setSequenceAndDraw(fighter, rnd(3) + 1, kFightSequenceType0);
- break;
-
- case 1:
- setSequenceAndDraw(fighter, 1, kFightSequenceType0);
- break;
-
- case 2:
- setSequenceAndDraw(fighter, 3, kFightSequenceType0);
- break;
- }
- } else {
- setSequenceAndDraw(fighter, 4, kFightSequenceType1);
- CALL_FUNCTION0(fighter, update);
- }
- break;
- }
-}
-
-void Fight::updateMilos(Fighter *fighter) {
- if (fighter->frame && CHECK_SEQUENCE2(fighter, 2)) {
-
- // Draw sequences
- if (fighter->opponent->countdown <= 0) {
- setSequenceAndDraw(fighter, 5, kFightSequenceType1);
- setSequenceAndDraw(fighter->opponent, 6, kFightSequenceType1);
-
- getSound()->removeFromQueue(kEntityTables0);
- getSound()->playSound(kEntityTrain, "MUS029", SoundManager::kFlagDefault);
-
- CALL_FUNCTION1(fighter, handleAction, kFightActionWin);
- }
-
- if (fighter->sequenceIndex == 4) {
- CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction4);
- _endType = kFightEndLost;
- }
- }
-
- update(fighter);
-}
-
-bool Fight::canInteractMilos(Fighter const *fighter, FightAction action) {
- if (!_data)
- error("Fight::canInteractMilos - invalid data!");
-
- if (action != kFightAction128
- || _data->player->sequenceIndex != 1
- || !fighter->frame
- || CHECK_SEQUENCE2(fighter, 4)
- || fighter->opponent->sequenceIndex != 1) {
- return canInteract(fighter);
- }
-
- _engine->getCursor()->setStyle(kCursorHand);
-
- return true;
-}
-
-void Fight::handleOpponentActionMilos(Fighter *fighter, FightAction action) {
- if (action == kFightAction4) {
- setSequenceAndDraw(fighter, 5, kFightSequenceType1);
- CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103);
- } else {
- if (action != kFightAction131)
- handleAction(fighter, action);
- }
-}
-
-void Fight::updateOpponentMilos(Fighter *fighter) {
- // This is an opponent struct!
- Opponent *opponent = (Opponent *)fighter;
-
- if (!opponent->field_38 && CALL_FUNCTION1(opponent, canInteract, kFightAction1) && !opponent->sequenceIndex2) {
-
- if (opponent->opponent->field_34 >= 2) {
- switch (rnd(5)) {
- default:
- break;
-
- case 0:
- setSequenceAndDraw(opponent, 1, kFightSequenceType0);
- break;
-
- case 1:
- setSequenceAndDraw(opponent, 2, kFightSequenceType0);
- break;
-
- case 2:
- setSequenceAndDraw(opponent, 2, kFightSequenceType0);
- setSequenceAndDraw(opponent, 2, kFightSequenceType1);
- break;
-
- case 3:
- setSequenceAndDraw(opponent, 1, kFightSequenceType0);
- setSequenceAndDraw(opponent, 2, kFightSequenceType2);
- break;
-
- case 4:
- setSequenceAndDraw(opponent, 1, kFightSequenceType0);
- setSequenceAndDraw(opponent, 1, kFightSequenceType2);
- break;
- }
- } else {
- setSequenceAndDraw(opponent, 2, kFightSequenceType0);
- }
-
- // Update field_38
- if (opponent->opponent->field_34 < 5)
- opponent->field_38 = 6 * (5 - opponent->opponent->field_34);
- else
- opponent->field_38 = 0;
- }
-
- if (opponent->frame && CHECK_SEQUENCE2(opponent, 2)) {
- if (opponent->sequenceIndex == 1 || opponent->sequenceIndex == 2)
- CALL_FUNCTION1(opponent->opponent, handleAction, (FightAction)opponent->sequenceIndex);
-
- if (opponent->opponent->countdown <= 0) {
- getSound()->removeFromQueue(kEntityTables0);
- CALL_FUNCTION1(opponent, handleAction, kFightActionLost);
- }
- }
-
- updateOpponent(opponent);
-}
-
-//////////////////////////////////////////////////////////////////////////
-// Anna
-//////////////////////////////////////////////////////////////////////////
-
-void Fight::loadAnnaPlayer() {
- if (!_data)
- error("Fight::loadAnnaPlayer - invalid data!");
-
- // Special case: we are using some shared functions directly
- _data->player->handleAction = new Common::Functor2Mem<Fighter *, FightAction, void, Fight>(this, &Fight::handleActionAnna);
- _data->player->update = new Common::Functor1Mem<Fighter *, void, Fight>(this, &Fight::update);
- _data->player->canInteract = new Common::Functor2Mem<Fighter const *, FightAction, bool, Fight>(this, &Fight::canInteract);
-
- _data->player->sequences.push_back(loadSequence("2002cr.seq"));
- _data->player->sequences.push_back(loadSequence("2002cdl.seq"));
- _data->player->sequences.push_back(loadSequence("2002cdr.seq"));
- _data->player->sequences.push_back(loadSequence("2002cdm.seq"));
- _data->player->sequences.push_back(loadSequence("2002lbk.seq"));
-}
-
-void Fight::loadAnnaOpponent() {
- if (!_data)
- error("Fight::loadAnnaOpponent - invalid data!");
-
- // Special case: we are using some shared functions directly
- _data->opponent->handleAction = new Common::Functor2Mem<Fighter *, FightAction, void, Fight>(this, &Fight::handleAction);
- _data->opponent->update = new Common::Functor1Mem<Fighter *, void, Fight>(this, &Fight::updateOpponentAnna);
- _data->opponent->canInteract = new Common::Functor2Mem<Fighter const *, FightAction, bool, Fight>(this, &Fight::canInteract);
-
- _data->opponent->sequences.push_back(loadSequence("2002or.seq"));
- _data->opponent->sequences.push_back(loadSequence("2002oal.seq"));
- _data->opponent->sequences.push_back(loadSequence("2002oam.seq"));
- _data->opponent->sequences.push_back(loadSequence("2002oar.seq"));
- _data->opponent->sequences.push_back(loadSequence("2002okr.seq"));
- _data->opponent->sequences.push_back(loadSequence("2002okml.seq"));
- _data->opponent->sequences.push_back(loadSequence("2002okm.seq"));
-
- getSound()->playSound(kEntityTables0, "MUS030", SoundManager::kFlagDefault);
-
- _data->opponent->field_38 = 30;
-}
-
-void Fight::handleActionAnna(Fighter *fighter, FightAction action) {
- switch (action) {
- default:
- handleAction(fighter, action);
- return;
-
- case kFightAction1:
- if ((fighter->sequenceIndex != 1 && fighter->sequenceIndex != 3) || CHECK_SEQUENCE2(fighter, 4)) {
- setSequenceAndDraw(fighter, 4, kFightSequenceType1);
- setSequenceAndDraw(fighter->opponent, 4, kFightSequenceType1);
-
- CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103);
- CALL_FUNCTION0(fighter, update);
- } else {
- fighter->field_34++;
- }
- break;
-
- case kFightAction2:
- if ((fighter->sequenceIndex != 2 && fighter->sequenceIndex != 3) || CHECK_SEQUENCE2(fighter, 4)) {
- setSequenceAndDraw(fighter, 4, kFightSequenceType1);
- setSequenceAndDraw(fighter->opponent, 5, kFightSequenceType1);
-
- CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103);
- CALL_FUNCTION0(fighter, update);
- } else {
- fighter->field_34++;
- }
- break;
-
- case kFightAction3:
- if ((fighter->sequenceIndex != 2 && fighter->sequenceIndex != 1) || CHECK_SEQUENCE2(fighter, 4)) {
- setSequenceAndDraw(fighter, 4, kFightSequenceType1);
- setSequenceAndDraw(fighter->opponent, 6, kFightSequenceType1);
-
- CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103);
- CALL_FUNCTION0(fighter, update);
- } else {
- fighter->field_34++;
- }
- break;
-
- case kFightAction128:
- switch (fighter->opponent->sequenceIndex) {
- default:
- setSequenceAndDraw(fighter, 3, kFightSequenceType0);
- break;
-
- case 1:
- setSequenceAndDraw(fighter, 1, kFightSequenceType0);
- break;
-
- case 2:
- setSequenceAndDraw(fighter, 3, kFightSequenceType0);
- break;
-
- case 3:
- setSequenceAndDraw(fighter, 2, kFightSequenceType0);
- break;
- }
- break;
- }
-
- if (fighter->field_34 > 4) {
- getSound()->removeFromQueue(kEntityTables0);
- bailout(kFightEndWin);
- }
-}
-
-void Fight::updateOpponentAnna(Fighter *fighter) {
- // This is an opponent struct!
- Opponent *opponent = (Opponent *)fighter;
-
- if (!opponent->field_38 && CALL_FUNCTION1(opponent, canInteract, kFightAction1) && !opponent->sequenceIndex2) {
-
- if (opponent->opponent->field_34 >= 2) {
- switch (rnd(6)) {
- default:
- break;
-
- case 0:
- setSequenceAndDraw(opponent, 1, kFightSequenceType0);
- break;
-
- case 1:
- setSequenceAndDraw(opponent, 2, kFightSequenceType0);
- break;
-
- case 2:
- setSequenceAndDraw(opponent, 3, kFightSequenceType0);
- break;
-
- case 3:
- setSequenceAndDraw(opponent, 3, kFightSequenceType0);
- setSequenceAndDraw(opponent, 2, kFightSequenceType2);
- break;
-
- case 4:
- setSequenceAndDraw(opponent, 1, kFightSequenceType0);
- setSequenceAndDraw(opponent, 2, kFightSequenceType2);
- break;
-
- case 5:
- setSequenceAndDraw(opponent, 3, kFightSequenceType0);
- setSequenceAndDraw(opponent, 2, kFightSequenceType2);
- break;
- }
- }
-
- // Update field_38
- opponent->field_38 = (int32)rnd(15);
- }
-
- if (opponent->frame && CHECK_SEQUENCE2(opponent, 2)) {
- if (opponent->sequenceIndex == 1 || opponent->sequenceIndex == 2 || opponent->sequenceIndex == 3)
- CALL_FUNCTION1(opponent->opponent, handleAction, (FightAction)opponent->sequenceIndex);
-
- if (opponent->opponent->countdown <= 0) {
- getSound()->removeFromQueue(kEntityTables0);
- CALL_FUNCTION1(opponent, handleAction, kFightActionLost);
- }
- }
-
- updateOpponent(opponent);
-}
-
-//////////////////////////////////////////////////////////////////////////
-// Ivo
-//////////////////////////////////////////////////////////////////////////
-
-void Fight::loadIvoPlayer() {
- REGISTER_PLAYER_FUNCTIONS(Ivo)
-
- _data->player->sequences.push_back(loadSequence("2003cr.seq"));
- _data->player->sequences.push_back(loadSequence("2003car.seq"));
- _data->player->sequences.push_back(loadSequence("2003cal.seq"));
- _data->player->sequences.push_back(loadSequence("2003cdr.seq"));
- _data->player->sequences.push_back(loadSequence("2003cdm.seq"));
- _data->player->sequences.push_back(loadSequence("2003chr.seq"));
- _data->player->sequences.push_back(loadSequence("2003chl.seq"));
- _data->player->sequences.push_back(loadSequence("2003ckr.seq"));
- _data->player->sequences.push_back(loadSequence("2003lbk.seq"));
- _data->player->sequences.push_back(loadSequence("2003fbk.seq"));
-
- _data->player->countdown = 5;
-}
-
-void Fight::loadIvoOpponent() {
- REGISTER_OPPONENT_FUNCTIONS(Ivo)
-
- _data->opponent->sequences.push_back(loadSequence("2003or.seq"));
- _data->opponent->sequences.push_back(loadSequence("2003oal.seq"));
- _data->opponent->sequences.push_back(loadSequence("2003oar.seq"));
- _data->opponent->sequences.push_back(loadSequence("2003odm.seq"));
- _data->opponent->sequences.push_back(loadSequence("2003okl.seq"));
- _data->opponent->sequences.push_back(loadSequence("2003okj.seq"));
- _data->opponent->sequences.push_back(loadSequence("blank.seq"));
- _data->opponent->sequences.push_back(loadSequence("csdr.seq"));
- _data->opponent->sequences.push_back(loadSequence("2003l.seq"));
-
- getSound()->playSound(kEntityTables0, "MUS032", SoundManager::kFlagDefault);
-
- _data->opponent->countdown = 5;
- _data->opponent->field_38 = 15;
-}
-
-void Fight::handleActionIvo(Fighter *fighter, FightAction action) {
- switch (action) {
- default:
- handleAction(fighter, action);
- return;
-
- case kFightAction1:
- if (fighter->sequenceIndex != 1 || CHECK_SEQUENCE2(fighter, 4)) {
- setSequenceAndDraw(fighter, 7, kFightSequenceType1);
- setSequenceAndDraw(fighter->opponent, 4, kFightSequenceType1);
-
- CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103);
- CALL_FUNCTION0(fighter, update);
- }
- break;
-
- case kFightAction2:
- if ((fighter->sequenceIndex != 2 && fighter->sequenceIndex != 3) || CHECK_SEQUENCE2(fighter, 4)) {
- setSequenceAndDraw(fighter, 7, kFightSequenceType1);
- setSequenceAndDraw(fighter->opponent, 5, kFightSequenceType1);
-
- CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103);
- CALL_FUNCTION0(fighter, update);
- }
- break;
-
- case kFightAction128:
- switch (fighter->opponent->sequenceIndex) {
- default:
- case 1:
- setSequenceAndDraw(fighter, 1, kFightSequenceType0);
- break;
-
- case 2:
- setSequenceAndDraw(fighter, 2, kFightSequenceType0);
- break;
- }
- break;
-
- case kFightAction129:
- setSequenceAndDraw(fighter, (fighter->opponent->countdown > 1) ? 4 : 3, fighter->sequenceIndex ? kFightSequenceType2 : kFightSequenceType0);
- break;
-
- case kFightAction130:
- setSequenceAndDraw(fighter, 3, fighter->sequenceIndex ? kFightSequenceType2 : kFightSequenceType0);
- break;
- }
-}
-
-void Fight::updateIvo(Fighter *fighter) {
-
- if ((fighter->sequenceIndex == 3 || fighter->sequenceIndex == 4) && !fighter->frameIndex)
- CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction131);
-
- if (fighter->frame && CHECK_SEQUENCE2(fighter, 2)) {
-
- // Draw sequences
- if (fighter->opponent->countdown <= 0) {
- setSequenceAndDraw(fighter, 9, kFightSequenceType1);
- setSequenceAndDraw(fighter->opponent, 8, kFightSequenceType1);
- getSound()->removeFromQueue(kEntityTables0);
-
- CALL_FUNCTION1(fighter, handleAction, kFightActionWin);
- return;
- }
-
- if (fighter->sequenceIndex == 3 || fighter->sequenceIndex == 4)
- CALL_FUNCTION1(fighter->opponent, handleAction, (FightAction)fighter->sequenceIndex);
- }
-
- update(fighter);
-}
-
-bool Fight::canInteractIvo(Fighter const *fighter, FightAction action) {
- if (action == kFightAction129 || action == kFightAction130)
- return (fighter->sequenceIndex >= 8);
-
- return canInteract(fighter);
-}
-
-void Fight::handleOpponentActionIvo(Fighter *fighter, FightAction action) {
- // This is an opponent struct!
- Opponent *opponent = (Opponent *)fighter;
-
- switch (action) {
- default:
- handleAction(fighter, action);
- break;
-
- case kFightAction3:
- if ((opponent->sequenceIndex != 1 && opponent->sequenceIndex != 3) || CHECK_SEQUENCE2(opponent, 4)) {
- setSequenceAndDraw(opponent, 6, kFightSequenceType1);
- setSequenceAndDraw(opponent->opponent, 6, kFightSequenceType1);
- CALL_FUNCTION1(opponent->opponent, handleAction, kFightAction103);
- }
- break;
-
- case kFightAction4:
- if ((opponent->sequenceIndex != 2 && opponent->sequenceIndex != 3) || CHECK_SEQUENCE2(opponent, 4)) {
- setSequenceAndDraw(opponent, 6, kFightSequenceType1);
- setSequenceAndDraw(opponent->opponent, 5, kFightSequenceType1);
- CALL_FUNCTION1(opponent->opponent, handleAction, kFightAction103);
- }
- break;
-
- case kFightAction131:
- if (opponent->sequenceIndex)
- break;
-
- if (rnd(100) <= (unsigned int)(opponent->countdown > 2 ? 60 : 75)) {
- setSequenceAndDraw(opponent, 3 , kFightSequenceType1);
- if (opponent->opponent->sequenceIndex == 4)
- setSequenceAndDraw(opponent, 2, kFightSequenceType2);
- }
- break;
- }
-}
-
-void Fight::updateOpponentIvo(Fighter *fighter) {
- // This is an opponent struct!
- Opponent *opponent = (Opponent *)fighter;
-
- if (!opponent->field_38 && CALL_FUNCTION1(opponent, canInteract, kFightAction1) && !opponent->sequenceIndex2) {
-
- if (opponent->opponent->field_34 >= 2) {
- switch (rnd(5)) {
- default:
- break;
-
- case 0:
- setSequenceAndDraw(opponent, 1, kFightSequenceType0);
- break;
-
- case 1:
- setSequenceAndDraw(opponent, 2, kFightSequenceType0);
- break;
-
- case 2:
- setSequenceAndDraw(opponent, 1, kFightSequenceType0);
- setSequenceAndDraw(opponent, 2, kFightSequenceType2);
- break;
-
- case 3:
- setSequenceAndDraw(opponent, 0, kFightSequenceType2);
- setSequenceAndDraw(opponent, 1, kFightSequenceType2);
- break;
-
- case 4:
- setSequenceAndDraw(opponent, 0, kFightSequenceType1);
- setSequenceAndDraw(opponent, 1, kFightSequenceType2);
- break;
- }
- }
-
- // Update field_38
- opponent->field_38 = 3 * opponent->countdown + (int32)rnd(10);
- }
-
- if (opponent->frame && CHECK_SEQUENCE2(opponent, 2)) {
-
- if (opponent->opponent->countdown <= 0) {
- setSequenceAndDraw(opponent, 7, kFightSequenceType1);
- setSequenceAndDraw(opponent->opponent, 8, kFightSequenceType1);
- getSound()->removeFromQueue(kEntityTables0);
-
- CALL_FUNCTION1(opponent->opponent, handleAction, kFightActionWin);
-
- return;
- }
-
- if (opponent->sequenceIndex == 1 || opponent->sequenceIndex == 2)
- CALL_FUNCTION1(opponent->opponent, handleAction, (FightAction)opponent->sequenceIndex);
- }
-
- updateOpponent(opponent);
-}
-
-//////////////////////////////////////////////////////////////////////////
-// Salko
-//////////////////////////////////////////////////////////////////////////
-
-void Fight::loadSalkoPlayer() {
- REGISTER_PLAYER_FUNCTIONS(Salko)
-
- _data->player->sequences.push_back(loadSequence("2004cr.seq"));
- _data->player->sequences.push_back(loadSequence("2004cdr.seq"));
- _data->player->sequences.push_back(loadSequence("2004chj.seq"));
- _data->player->sequences.push_back(loadSequence("2004bk.seq"));
-
- _data->player->countdown = 2;
-}
-
-void Fight::loadSalkoOpponent() {
- REGISTER_OPPONENT_FUNCTIONS(Salko)
-
- _data->opponent->sequences.push_back(loadSequence("2004or.seq"));
- _data->opponent->sequences.push_back(loadSequence("2004oam.seq"));
- _data->opponent->sequences.push_back(loadSequence("2004oar.seq"));
- _data->opponent->sequences.push_back(loadSequence("2004okr.seq"));
- _data->opponent->sequences.push_back(loadSequence("2004ohm.seq"));
- _data->opponent->sequences.push_back(loadSequence("blank.seq"));
-
- getSound()->playSound(kEntityTables0, "MUS035", SoundManager::kFlagDefault);
-
- _data->opponent->countdown = 3;
- _data->opponent->field_38 = 30;
-}
-
-void Fight::handleActionSalko(Fighter *fighter, FightAction action) {
- switch (action) {
- default:
- handleAction(fighter, action);
- return;
-
- case kFightAction1:
- case kFightAction2:
- if (fighter->sequenceIndex != 1 && CHECK_SEQUENCE2(fighter, 4)) {
- fighter->field_34 = 0;
-
- setSequenceAndDraw(fighter, 3, kFightSequenceType1);
- setSequenceAndDraw(fighter->opponent, (action == kFightAction1 ? 3 : 4), kFightSequenceType1);
-
- CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103);
-
- if (action == kFightAction2)
- fighter->countdown= 0;
-
- CALL_FUNCTION0(fighter, update);
- } else {
- fighter->field_34++;
- }
- break;
-
- case kFightAction5:
- if (fighter->sequenceIndex != 3) {
- CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103);
- CALL_FUNCTION0(fighter, update);
- }
- break;
-
- case kFightAction128:
- setSequenceAndDraw(fighter, 1, kFightSequenceType0);
- fighter->field_34 = 0;
- break;
-
- case kFightAction131:
- setSequenceAndDraw(fighter, 2, (fighter->sequenceIndex ? kFightSequenceType2 : kFightSequenceType0));
- break;
- }
-}
-
-void Fight::updateSalko(Fighter *fighter) {
- update(fighter);
-
- // The original doesn't check for currentSequence2 != NULL (might not happen when everything is working properly, but crashes with our current implementation)
- if (fighter->frame && CHECK_SEQUENCE2(fighter, 2)) {
-
- if (fighter->opponent->countdown <= 0) {
- getSound()->removeFromQueue(kEntityTables0);
- bailout(kFightEndWin);
-
- return;
- }
-
- if (fighter->sequenceIndex == 2)
- CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction2);
- }
-}
-
-bool Fight::canInteractSalko(Fighter const *fighter, FightAction action) {
- if (action == kFightAction131) {
- if (fighter->sequenceIndex == 1) {
- if (fighter->opponent->countdown <= 0)
- _engine->getCursor()->setStyle(kCursorHand);
-
- return true;
- }
-
- return false;
- }
-
- return canInteract(fighter);
-}
-
-void Fight::handleOpponentActionSalko(Fighter *fighter, FightAction action) {
- if (action == kFightAction2) {
- setSequenceAndDraw(fighter, 5, kFightSequenceType1);
- CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103);
- } else {
- handleAction(fighter, action);
- }
-}
-
-void Fight::updateOpponentSalko(Fighter *fighter) {
- // This is an opponent struct
- Opponent *opponent = (Opponent *)fighter;
-
- if (!opponent->field_38 && CALL_FUNCTION1(opponent, canInteract, kFightAction1) && !opponent->sequenceIndex2) {
-
- switch (rnd(5)) {
- default:
- break;
-
- case 0:
- setSequenceAndDraw(opponent, 1, kFightSequenceType0);
- break;
-
- case 1:
- setSequenceAndDraw(opponent, 2, kFightSequenceType0);
- break;
-
- case 2:
- setSequenceAndDraw(opponent, 1, kFightSequenceType0);
- setSequenceAndDraw(opponent, 2, kFightSequenceType2);
- break;
-
- case 3:
- setSequenceAndDraw(opponent, 2, kFightSequenceType0);
- setSequenceAndDraw(opponent, 1, kFightSequenceType2);
- break;
-
- case 4:
- setSequenceAndDraw(opponent, 1, kFightSequenceType0);
- setSequenceAndDraw(opponent, 1, kFightSequenceType2);
- break;
- }
-
- // Update field_38
- opponent->field_38 = 4 * opponent->countdown;
- }
-
- if (opponent->frame && CHECK_SEQUENCE2(opponent, 2)) {
- if (opponent->opponent->countdown <= 0) {
- getSound()->removeFromQueue(kEntityTables0);
- bailout(kFightEndLost);
-
- // Stop processing
- return;
- }
-
- if (opponent->sequenceIndex == 1 || opponent->sequenceIndex == 2)
- CALL_FUNCTION1(opponent->opponent, handleAction, (FightAction)opponent->sequenceIndex);
- }
-
- updateOpponent(opponent);
-}
-
-//////////////////////////////////////////////////////////////////////////
-// Vesna
-//////////////////////////////////////////////////////////////////////////
-
-void Fight::loadVesnaPlayer() {
- REGISTER_PLAYER_FUNCTIONS(Vesna)
-
- _data->player->sequences.push_back(loadSequence("2005cr.seq"));
- _data->player->sequences.push_back(loadSequence("2005cdr.seq"));
- _data->player->sequences.push_back(loadSequence("2005cbr.seq"));
- _data->player->sequences.push_back(loadSequence("2005bk.seq"));
- _data->player->sequences.push_back(loadSequence("2005cdm1.seq"));
- _data->player->sequences.push_back(loadSequence("2005chl.seq"));
-}
-
-void Fight::loadVesnaOpponent() {
- REGISTER_OPPONENT_FUNCTIONS(Vesna)
-
- _data->opponent->sequences.push_back(loadSequence("2005or.seq"));
- _data->opponent->sequences.push_back(loadSequence("2005oam.seq"));
- _data->opponent->sequences.push_back(loadSequence("2005oar.seq"));
- _data->opponent->sequences.push_back(loadSequence("2005okml.seq"));
- _data->opponent->sequences.push_back(loadSequence("2005okr.seq"));
- _data->opponent->sequences.push_back(loadSequence("2005odm1.seq"));
- _data->opponent->sequences.push_back(loadSequence("2005csbm.seq"));
- _data->opponent->sequences.push_back(loadSequence("2005oam4.seq"));
-
- getSound()->playSound(kEntityTables0, "MUS038", SoundManager::kFlagDefault);
-
- _data->opponent->countdown = 4;
- _data->opponent->field_38 = 30;
-}
-
-void Fight::handleActionVesna(Fighter *fighter, FightAction action) {
- switch (action) {
- default:
- handleAction(fighter, action);
- return;
-
- case kFightAction1:
- if (fighter->sequenceIndex != 1) {
- CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103);
- CALL_FUNCTION0(fighter, update);
- } else {
- fighter->field_34++;
- }
- break;
-
- case kFightAction2:
- if (fighter->sequenceIndex != 2) {
- CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103);
- CALL_FUNCTION0(fighter, update);
- } else {
- fighter->field_34++;
- }
- break;
-
- case kFightAction5:
- if (fighter->sequenceIndex != 3) {
- CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103);
- CALL_FUNCTION0(fighter, update);
- }
- break;
-
- case kFightAction128:
- if (fighter->sequenceIndex == 1 && fighter->opponent->sequenceIndex == 1 && CHECK_SEQUENCE2(fighter, 4)) {
- setSequenceAndDraw(fighter, 5, kFightSequenceType1);
- } else {
- setSequenceAndDraw(fighter, (fighter->opponent->sequenceIndex == 5) ? 3 : 1, kFightSequenceType0);
- }
- break;
-
- case kFightAction132:
- setSequenceAndDraw(fighter, 2, kFightSequenceType0);
- break;
- }
-
- if (fighter->field_34 > 10) {
- setSequenceAndDraw(fighter->opponent, 5, kFightSequenceType2);
- fighter->opponent->countdown = 1;
- fighter->field_34 = 0;
- }
-}
-
-void Fight::updateVesna(Fighter *fighter) {
- if (fighter->frame && CHECK_SEQUENCE2(fighter, 2)) {
-
- if (fighter->sequenceIndex == 3)
- CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction3);
-
- if (fighter->opponent->countdown <= 0) {
- getSound()->removeFromQueue(kEntityTables0);
- bailout(kFightEndWin);
- return;
- }
-
- if (fighter->sequenceIndex == 5)
- CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction5);
- }
-
- update(fighter);
-}
-
-bool Fight::canInteractVesna(Fighter const *fighter, FightAction action) {
- if (action != kFightAction128)
- return canInteract(fighter);
-
- if (fighter->sequenceIndex != 1) {
-
- if (fighter->opponent->sequenceIndex == 5) {
- _engine->getCursor()->setStyle(kCursorDown);
- return true;
- }
-
- return canInteract(fighter);
- }
-
- if (fighter->opponent->sequenceIndex == 1 && CHECK_SEQUENCE2(fighter, 4)) {
- _engine->getCursor()->setStyle(kCursorPunchLeft);
- return true;
- }
-
- return false;
-}
-
-void Fight::handleOpponentActionVesna(Fighter *fighter, FightAction action) {
- switch (action) {
- default:
- handleAction(fighter, action);
- break;
-
- case kFightAction3:
- CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103);
- break;
-
- case kFightAction5:
- setSequenceAndDraw(fighter, 7, kFightSequenceType1);
- CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103);
- if (fighter->countdown <= 1)
- fighter->countdown = 1;
- break;
-
- case kFightAction131:
- break;
- }
-}
-
-void Fight::updateOpponentVesna(Fighter *fighter) {
- // This is an opponent struct
- Opponent *opponent = (Opponent *)fighter;
-
- if (!opponent->field_38 && CALL_FUNCTION1(opponent, canInteract, kFightAction1) && !opponent->sequenceIndex2) {
-
- if (opponent->opponent->field_34 == 1) {
- setSequenceAndDraw(opponent, 2, kFightSequenceType0);
- } else {
- switch (rnd(6)) {
- default:
- break;
-
- case 0:
- setSequenceAndDraw(opponent, 1, kFightSequenceType0);
- break;
-
- case 1:
- setSequenceAndDraw(opponent, 1, kFightSequenceType0);
- setSequenceAndDraw(opponent, 1, kFightSequenceType2);
- break;
-
- case 2:
- setSequenceAndDraw(opponent, 2, kFightSequenceType0);
- break;
-
- case 3:
- setSequenceAndDraw(opponent, 2, kFightSequenceType0);
- setSequenceAndDraw(opponent, 2, kFightSequenceType2);
- break;
-
- case 4:
- setSequenceAndDraw(opponent, 1, kFightSequenceType0);
- setSequenceAndDraw(opponent, 2, kFightSequenceType2);
- break;
-
- case 5:
- setSequenceAndDraw(opponent, 2, kFightSequenceType0);
- setSequenceAndDraw(opponent, 1, kFightSequenceType2);
- break;
- }
- }
-
- // Update field_38
- opponent->field_38 = 4 * opponent->countdown;
- }
-
- if (opponent->frame && CHECK_SEQUENCE2(opponent, 2)) {
- if (opponent->sequenceIndex == 1 || opponent->sequenceIndex == 2 || opponent->sequenceIndex == 5)
- CALL_FUNCTION1(opponent->opponent, handleAction, (FightAction)opponent->sequenceIndex);
-
- if (opponent->opponent->countdown <= 0) {
-
- switch (opponent->sequenceIndex) {
- default:
- break;
-
- case 1:
- setSequenceAndDraw(opponent, 3, kFightSequenceType1);
- break;
-
- case 2:
- setSequenceAndDraw(opponent, 4, kFightSequenceType1);
- break;
-
- case 5:
- setSequenceAndDraw(opponent, 6, kFightSequenceType1);
- break;
- }
-
- setSequenceAndDraw(opponent->opponent, 4, kFightSequenceType1);
-
- CALL_FUNCTION1(opponent, handleAction, kFightActionLost);
- CALL_FUNCTION0(opponent->opponent, update);
- CALL_FUNCTION0(opponent, update);
-
- getSound()->removeFromQueue(kEntityTables0);
-
- // Stop processing
- return;
- }
- }
-
- updateOpponent(opponent);
-}
-
-} // End of namespace LastExpress
diff --git a/engines/lastexpress/game/fight.h b/engines/lastexpress/game/fight.h
deleted file mode 100644
index a33cc93a29..0000000000
--- a/engines/lastexpress/game/fight.h
+++ /dev/null
@@ -1,266 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 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 LASTEXPRESS_FIGHT_H
-#define LASTEXPRESS_FIGHT_H
-
-/*
- Fight structure
- ---------------
- uint32 {4} - player struct
- uint32 {4} - opponent struct
- uint32 {4} - hasLost flag
-
- byte {1} - isRunning
-
- Fight participant structure
- ---------------------------
- uint32 {4} - function pointer
- uint32 {4} - pointer to fight structure
- uint32 {4} - pointer to opponent (fight participant structure)
- uint32 {4} - array of sequences
- uint32 {4} - number of sequences
- uint32 {4} - ??
- uint32 {4} - ??
- uint32 {4} - ??
- uint32 {4} - ??
- uint32 {4} - ??
- uint32 {4} - ??
- uint32 {4} - ??
- uint32 {4} - ??
- uint16 {2} - ??
- uint16 {2} - ?? - only for opponent structure
- uint32 {4} - ?? - only for opponent structure
-
-*/
-
-#include "lastexpress/shared.h"
-
-#include "lastexpress/eventhandler.h"
-
-#include "common/array.h"
-
-namespace LastExpress {
-
-class LastExpressEngine;
-class Sequence;
-class SequenceFrame;
-
-//////////////////////////////////////////////////////////////////////////
-// TODO : objectify!
-class Fight : public EventHandler {
-public:
- enum FightEndType {
- kFightEndWin = 0,
- kFightEndLost = 1,
- kFightEndExit = 2
- };
-
- Fight(LastExpressEngine *engine);
- ~Fight();
-
- FightEndType setup(FightType type);
-
- void eventMouse(const Common::Event &ev);
- void eventTick(const Common::Event &ev);
-
- void setStopped();
- void resetState() { _state = 0; }
-
-private:
- enum FightSequenceType {
- kFightSequenceType0 = 0,
- kFightSequenceType1 = 1,
- kFightSequenceType2 = 2
- };
-
- enum FightAction {
- kFightAction1 = 1,
- kFightAction2 = 2,
- kFightAction3 = 3,
- kFightAction4 = 4,
- kFightAction5 = 5,
- kFightAction101 = 101,
- kFightActionResetFrame = 102,
- kFightAction103 = 103,
- kFightActionWin = 104,
- kFightActionLost = 105,
- kFightAction128 = 128,
- kFightAction129 = 129,
- kFightAction130 = 130,
- kFightAction131 = 131,
- kFightAction132 = 132
- };
-
- struct Fighter {
- Common::Functor2<Fighter *, FightAction, void> *handleAction;
- Common::Functor1<Fighter *, void> *update;
- Common::Functor2<Fighter const *, FightAction, bool> *canInteract;
- Fighter *opponent;
- Common::Array<Sequence *> sequences;
- uint32 sequenceIndex;
- Sequence *sequence;
- SequenceFrame *frame;
- uint32 frameIndex;
- uint32 field_24;
- FightAction action;
- uint32 sequenceIndex2;
- int32 countdown; // countdown before loosing ?
- uint32 field_34;
-
- Fighter() {
- handleAction = NULL;
- update = NULL;
- canInteract = NULL;
-
- opponent = NULL;
-
- sequenceIndex = 0;
- sequence = NULL;
- frame = NULL;
- frameIndex = 0;
-
- field_24 = 0;
-
- action = kFightAction101;
- sequenceIndex2 = 0;
-
- countdown = 1;
-
- field_34 = 0;
- }
- };
-
- // Opponent struct
- struct Opponent : Fighter {
- int32 field_38;
-
- Opponent() : Fighter() {
- field_38 = 0;
- }
- };
-
- struct FightData {
- Fighter *player;
- Opponent *opponent;
- int32 index;
-
- Sequence *sequences[20];
- Common::String names[20];
-
- bool isRunning;
-
- FightData() {
- player = new Fighter();
- opponent = new Opponent();
-
- // Set opponents
- player->opponent = opponent;
- opponent->opponent = player;
-
- index = 0;
-
- isRunning = false;
- }
- };
-
- LastExpressEngine *_engine;
- FightData *_data;
- FightEndType _endType;
- int _state;
-
- bool _handleTimer;
-
- // Events
- void handleTick(const Common::Event &ev, bool unknown);
-
- // State
- void bailout(FightEndType type);
-
-
- // Drawing
- void setSequenceAndDraw(Fighter *fighter, uint32 sequenceIndex, FightSequenceType type) const;
- void draw(Fighter *fighter) const;
-
- // Cleanup
- void clearData();
- void clearSequences(Fighter *fighter) const;
-
- //////////////////////////////////////////////////////////////////////////
- // Loading
- void loadData(FightType type);
-
- // Shared
- void processFighter(Fighter *fighter);
-
- // Default functions
- void handleAction(Fighter *fighter, FightAction action);
- void update(Fighter *fighter);
- bool canInteract(Fighter const *fighter, FightAction = (FightAction)0);
- void updateOpponent(Fighter *fighter);
-
- // Milos
- void loadMilosPlayer();
- void loadMilosOpponent();
- void handleActionMilos(Fighter *fighter, FightAction action);
- void updateMilos(Fighter *fighter);
- bool canInteractMilos(Fighter const *fighter, FightAction action);
- void handleOpponentActionMilos(Fighter *fighter, FightAction action);
- void updateOpponentMilos(Fighter *fighter);
-
- // Anna
- void loadAnnaPlayer();
- void loadAnnaOpponent();
- void handleActionAnna(Fighter *fighter, FightAction action);
- void updateOpponentAnna(Fighter *fighter);
-
- // Ivo
- void loadIvoPlayer();
- void loadIvoOpponent();
- void handleActionIvo(Fighter *fighter, FightAction action);
- void updateIvo(Fighter *fighter);
- bool canInteractIvo(Fighter const *fighter, FightAction action);
- void handleOpponentActionIvo(Fighter *fighter, FightAction action);
- void updateOpponentIvo(Fighter *fighter);
-
- // Salko
- void loadSalkoPlayer();
- void loadSalkoOpponent();
- void handleActionSalko(Fighter *fighter, FightAction action);
- void updateSalko(Fighter *fighter);
- bool canInteractSalko(Fighter const *fighter, FightAction action);
- void handleOpponentActionSalko(Fighter *fighter, FightAction action);
- void updateOpponentSalko(Fighter *fighter);
-
- // Vesna
- void loadVesnaPlayer();
- void loadVesnaOpponent();
- void handleActionVesna(Fighter *fighter, FightAction action);
- void updateVesna(Fighter *fighter);
- bool canInteractVesna(Fighter const *fighter, FightAction action);
- void handleOpponentActionVesna(Fighter *fighter, FightAction action);
- void updateOpponentVesna(Fighter *fighter);
-};
-
-} // End of namespace LastExpress
-
-#endif // LASTEXPRESS_FIGHT_H
diff --git a/engines/lastexpress/game/logic.cpp b/engines/lastexpress/game/logic.cpp
index 0911c60de0..a8a2ce87b1 100644
--- a/engines/lastexpress/game/logic.cpp
+++ b/engines/lastexpress/game/logic.cpp
@@ -30,11 +30,13 @@
// Entities
#include "lastexpress/entities/chapters.h"
+// Fight
+#include "lastexpress/fight/fight.h"
+
// Game
#include "lastexpress/game/action.h"
#include "lastexpress/game/beetle.h"
#include "lastexpress/game/entities.h"
-#include "lastexpress/game/fight.h"
#include "lastexpress/game/inventory.h"
#include "lastexpress/game/menu.h"
#include "lastexpress/game/object.h"
diff --git a/engines/lastexpress/game/menu.cpp b/engines/lastexpress/game/menu.cpp
index f9eef26326..27a43d8f61 100644
--- a/engines/lastexpress/game/menu.cpp
+++ b/engines/lastexpress/game/menu.cpp
@@ -28,7 +28,8 @@
#include "lastexpress/data/snd.h"
#include "lastexpress/data/scene.h"
-#include "lastexpress/game/fight.h"
+#include "lastexpress/fight/fight.h"
+
#include "lastexpress/game/inventory.h"
#include "lastexpress/game/logic.h"
#include "lastexpress/game/savegame.h"
diff --git a/engines/lastexpress/lastexpress.cpp b/engines/lastexpress/lastexpress.cpp
index e162998719..120e6eb28b 100644
--- a/engines/lastexpress/lastexpress.cpp
+++ b/engines/lastexpress/lastexpress.cpp
@@ -288,22 +288,34 @@ void LastExpressEngine::handleSoundTimer() {
/// Event Handling
///////////////////////////////////////////////////////////////////////////////////
void LastExpressEngine::backupEventHandlers() {
+ if (_eventMouseBackup != NULL || _eventTickBackup != NULL)
+ error("[LastExpressEngine::backupEventHandlers] backup event handlers are already set");
+
_eventMouseBackup = _eventMouse;
_eventTickBackup = _eventTick;
}
void LastExpressEngine::restoreEventHandlers() {
if (_eventMouseBackup == NULL || _eventTickBackup == NULL)
- error("LastExpressEngine::restoreEventHandlers: restore called before backing up the event handlers!");
+ error("[LastExpressEngine::restoreEventHandlers] restore called before backing up the event handlers");
+
+ // Cleanup previous event handlers
+ SAFE_DELETE(_eventMouse);
+ SAFE_DELETE(_eventTick);
_eventMouse = _eventMouseBackup;
_eventTick = _eventTickBackup;
+
+ _eventMouseBackup = NULL;
+ _eventTickBackup = NULL;
}
void LastExpressEngine::setEventHandlers(EventHandler::EventFunction *mouse, EventHandler::EventFunction *tick) {
- // Cleanup previous event handlers
- delete _eventMouse;
- delete _eventTick;
+ if (_eventMouse != _eventMouseBackup)
+ SAFE_DELETE(_eventMouse);
+
+ if (_eventTick != _eventTickBackup)
+ SAFE_DELETE(_eventTick);
_eventMouse = mouse;
_eventTick = tick;
diff --git a/engines/lastexpress/module.mk b/engines/lastexpress/module.mk
index 12fbb4f85b..e81151910b 100644
--- a/engines/lastexpress/module.mk
+++ b/engines/lastexpress/module.mk
@@ -45,10 +45,16 @@ MODULE_OBJS := \
entities/verges.o \
entities/vesna.o \
entities/yasmin.o \
+ fight/fight.o \
+ fight/fighter.o \
+ fight/fighter_anna.o \
+ fight/fighter_ivo.o \
+ fight/fighter_milos.o \
+ fight/fighter_salko.o \
+ fight/fighter_vesna.o \
game/action.o \
game/beetle.o \
game/entities.o \
- game/fight.o \
game/inventory.o \
game/logic.o \
game/menu.o \
diff --git a/engines/lure/debugger.cpp b/engines/lure/debugger.cpp
index 68410875f7..ef4a22f73a 100644
--- a/engines/lure/debugger.cpp
+++ b/engines/lure/debugger.cpp
@@ -549,14 +549,19 @@ bool Debugger::cmd_showAnim(int argc, const char **argv) {
}
bool Debugger::cmd_saveStrings(int argc, const char **argv) {
- StringData &strings = StringData::getReference();
- char buffer[32768];
-
if (argc != 2) {
DebugPrintf("strings <stringId>\n");
return true;
}
+ StringData &strings = StringData::getReference();
+
+ char *buffer = (char *)malloc(32768);
+ if (!buffer) {
+ DebugPrintf("Cannot allocate strings buffer\n");
+ return true;
+ }
+
uint16 id = strToInt(argv[1]);
strings.getString(id, buffer, NULL, NULL);
DebugPrintf("%s\n", buffer);
@@ -577,6 +582,9 @@ bool Debugger::cmd_saveStrings(int argc, const char **argv) {
DebugPrintf("Done\n");
*/
+
+ free(buffer);
+
return true;
}
diff --git a/engines/lure/memory.cpp b/engines/lure/memory.cpp
index c5c28fa8bc..137a8f6bee 100644
--- a/engines/lure/memory.cpp
+++ b/engines/lure/memory.cpp
@@ -93,8 +93,12 @@ void MemoryBlock::copyFrom(const byte *src, uint32 srcPos, uint32 destPos, uint3
void MemoryBlock::reallocate(uint32 size1) {
_size = size1;
- _data = (byte *) realloc(_data, size1);
- if (!_data) error ("Failed reallocating memory block");
+
+ byte *tmp = (byte *) realloc(_data, size1);
+ if (!tmp)
+ error ("[MemoryBlock::reallocate] Failed reallocating memory block");
+
+ _data = tmp;
}
} // End of namespace Lure
diff --git a/engines/saga/actor.cpp b/engines/saga/actor.cpp
index 862a0b4d64..06ce335518 100644
--- a/engines/saga/actor.cpp
+++ b/engines/saga/actor.cpp
@@ -385,6 +385,7 @@ void Actor::loadActorList(int protagonistIdx, int actorCount, int actorsResource
ByteArrayReadStreamEndian actorS(actorListData);
+ _actors.clear();
_actors.resize(actorCount);
i = 0;
for (ActorDataArray::iterator actor = _actors.begin(); actor != _actors.end(); ++actor, i++) {
diff --git a/engines/sci/decompressor.cpp b/engines/sci/decompressor.cpp
index 03a06d240d..7e7acab994 100644
--- a/engines/sci/decompressor.cpp
+++ b/engines/sci/decompressor.cpp
@@ -181,16 +181,27 @@ int DecompressorLZW::unpackLZW(Common::ReadStream *src, byte *dest, uint32 nPack
init(src, dest, nPacked, nUnpacked);
uint16 token; // The last received value
-
- uint16 tokenlist[4096]; // pointers to dest[]
- uint16 tokenlengthlist[4096]; // char length of each token
uint16 tokenlastlength = 0;
+ uint16 *tokenlist = (uint16 *)malloc(4096 * sizeof(uint16)); // pointers to dest[]
+ uint16* tokenlengthlist = (uint16 *)malloc(4096 * sizeof(uint16)); // char length of each token
+ if (!tokenlist || !tokenlengthlist) {
+ free(tokenlist);
+ free(tokenlengthlist);
+
+ error("[DecompressorLZW::unpackLZW] Cannot allocate token memory buffers");
+ }
+
while (!isFinished()) {
token = getBitsLSB(_numbits);
- if (token == 0x101)
+ if (token == 0x101) {
+ free(tokenlist);
+ free(tokenlengthlist);
+
return 0; // terminator
+ }
+
if (token == 0x100) { // reset command
_numbits = 9;
_endtoken = 0x1FF;
@@ -199,6 +210,10 @@ int DecompressorLZW::unpackLZW(Common::ReadStream *src, byte *dest, uint32 nPack
if (token > 0xff) {
if (token >= _curtoken) {
warning("unpackLZW: Bad token %x", token);
+
+ free(tokenlist);
+ free(tokenlengthlist);
+
return SCI_ERROR_DECOMPRESSION_ERROR;
}
tokenlastlength = tokenlengthlist[token] + 1;
@@ -231,6 +246,9 @@ int DecompressorLZW::unpackLZW(Common::ReadStream *src, byte *dest, uint32 nPack
}
}
+ free(tokenlist);
+ free(tokenlengthlist);
+
return _dwWrote == _szUnpacked ? 0 : SCI_ERROR_DECOMPRESSION_ERROR;
}
@@ -238,12 +256,19 @@ int DecompressorLZW::unpackLZW1(Common::ReadStream *src, byte *dest, uint32 nPac
uint32 nUnpacked) {
init(src, dest, nPacked, nUnpacked);
- byte stak[0x1014];
- byte lastchar = 0;
- uint16 stakptr = 0, lastbits = 0;
- Tokenlist tokens[0x1004];
+ byte *stak = (byte *)malloc(0x1014);
+ Tokenlist *tokens = (Tokenlist *)malloc(0x1004 * sizeof(Tokenlist));
+ if (!stak || !tokens) {
+ free(stak);
+ free(tokens);
+
+ error("[DecompressorLZW::unpackLZW1] Cannot allocate decompression buffers");
+ }
+
memset(tokens, 0, sizeof(tokens));
+ byte lastchar = 0;
+ uint16 stakptr = 0, lastbits = 0;
byte decryptstart = 0;
uint16 bitstring;
@@ -310,6 +335,10 @@ int DecompressorLZW::unpackLZW1(Common::ReadStream *src, byte *dest, uint32 nPac
break;
}
}
+
+ free(stak);
+ free(tokens);
+
return _dwWrote == _szUnpacked ? 0 : SCI_ERROR_DECOMPRESSION_ERROR;
}
diff --git a/engines/sword25/fmv/theora_decoder.cpp b/engines/sword25/fmv/theora_decoder.cpp
index 098bd2c6b9..a7ebb5df8c 100644
--- a/engines/sword25/fmv/theora_decoder.cpp
+++ b/engines/sword25/fmv/theora_decoder.cpp
@@ -424,6 +424,12 @@ bool TheoraDecoder::queueAudio() {
if (!_audStream)
return false;
+ // An audio buffer should have been allocated (either in the constructor or after queuing the current buffer)
+ if (!_audiobuf) {
+ warning("[TheoraDecoder::queueAudio] Invalid audio buffer");
+ return false;
+ }
+
bool queuedAudio = false;
for (;;) {
@@ -454,6 +460,11 @@ bool TheoraDecoder::queueAudio() {
// The audio mixer is now responsible for the old audio buffer.
// We need to create a new one.
_audiobuf = (ogg_int16_t *)malloc(AUDIOFD_FRAGSIZE * sizeof(ogg_int16_t));
+ if (!_audiobuf) {
+ warning("[TheoraDecoder::queueAudio] Cannot allocate memory for audio buffer");
+ return false;
+ }
+
_audiobufFill = 0;
queuedAudio = true;
}
diff --git a/engines/sword25/gfx/image/art.cpp b/engines/sword25/gfx/image/art.cpp
index 2df8bd4f3e..e9715481c6 100644
--- a/engines/sword25/gfx/image/art.cpp
+++ b/engines/sword25/gfx/image/art.cpp
@@ -151,6 +151,8 @@ ArtSVP *art_svp_from_vpath(ArtVpath *vpath) {
n_segs_max = 16;
svp = (ArtSVP *)malloc(sizeof(ArtSVP) +
(n_segs_max - 1) * sizeof(ArtSVPSeg));
+ if (!svp)
+ error("[art_svp_from_vpath] Cannot allocate memory");
dir = 0;
n_points = 0;
@@ -167,9 +169,14 @@ ArtSVP *art_svp_from_vpath(ArtVpath *vpath) {
if (points != NULL && n_points >= 2) {
if (n_segs == n_segs_max) {
n_segs_max <<= 1;
- svp = (ArtSVP *)realloc(svp, sizeof(ArtSVP) +
- (n_segs_max - 1) *
- sizeof(ArtSVPSeg));
+ ArtSVP *tmp = (ArtSVP *)realloc(svp, sizeof(ArtSVP) +
+ (n_segs_max - 1) *
+ sizeof(ArtSVPSeg));
+
+ if (!tmp)
+ error("Cannot reallocate memory in art_svp_from_vpath()");
+
+ svp = tmp;
}
svp->segs[n_segs].n_points = n_points;
svp->segs[n_segs].dir = (dir > 0);
@@ -204,9 +211,14 @@ ArtSVP *art_svp_from_vpath(ArtVpath *vpath) {
y = points[n_points - 1].y;
if (n_segs == n_segs_max) {
n_segs_max <<= 1;
- svp = (ArtSVP *)realloc(svp, sizeof(ArtSVP) +
- (n_segs_max - 1) *
- sizeof(ArtSVPSeg));
+ ArtSVP *tmp = (ArtSVP *)realloc(svp, sizeof(ArtSVP) +
+ (n_segs_max - 1) *
+ sizeof(ArtSVPSeg));
+
+ if (!tmp)
+ error("Cannot reallocate memory in art_svp_from_vpath()");
+
+ svp = tmp;
}
svp->segs[n_segs].n_points = n_points;
svp->segs[n_segs].dir = (dir > 0);
@@ -246,9 +258,14 @@ ArtSVP *art_svp_from_vpath(ArtVpath *vpath) {
if (n_points >= 2) {
if (n_segs == n_segs_max) {
n_segs_max <<= 1;
- svp = (ArtSVP *)realloc(svp, sizeof(ArtSVP) +
- (n_segs_max - 1) *
- sizeof(ArtSVPSeg));
+ ArtSVP *tmp = (ArtSVP *)realloc(svp, sizeof(ArtSVP) +
+ (n_segs_max - 1) *
+ sizeof(ArtSVPSeg));
+
+ if (!tmp)
+ error("Cannot reallocate memory in art_svp_from_vpath()");
+
+ svp = tmp;
}
svp->segs[n_segs].n_points = n_points;
svp->segs[n_segs].dir = (dir > 0);
@@ -1026,6 +1043,8 @@ struct _ArtPriPoint {
static ArtPriQ *art_pri_new(void) {
ArtPriQ *result = art_new(ArtPriQ, 1);
+ if (!result)
+ error("[art_pri_new] Cannot allocate memory");
result->n_items = 0;
result->n_items_max = 16;
@@ -1157,8 +1176,13 @@ static int art_svp_writer_rewind_add_segment(ArtSvpWriter *self, int wind_left,
(swr->n_segs_max - 1) *
sizeof(ArtSVPSeg));
swr->svp = svp;
- swr->n_points_max = art_renew(swr->n_points_max, int,
- swr->n_segs_max);
+ int *tmp = art_renew(swr->n_points_max, int,
+ swr->n_segs_max);
+
+ if (!tmp)
+ error("Cannot reallocate memory in art_svp_writer_rewind_add_segment()");
+
+ swr->n_points_max = tmp;
}
seg = &svp->segs[seg_num];
seg->n_points = 1;
@@ -1169,6 +1193,9 @@ static int art_svp_writer_rewind_add_segment(ArtSvpWriter *self, int wind_left,
seg->bbox.x1 = x;
seg->bbox.y1 = y;
seg->points = art_new(ArtPoint, init_n_points_max);
+ if (!seg->points)
+ error("[art_svp_writer_rewind_add_segment] Cannot allocate memory");
+
seg->points[0].x = x;
seg->points[0].y = y;
return seg_num;
@@ -1213,6 +1240,8 @@ ArtSVP *art_svp_writer_rewind_reap(ArtSvpWriter *self) {
ArtSvpWriter *art_svp_writer_rewind_new(ArtWindRule rule) {
ArtSvpWriterRewind *result = art_new(ArtSvpWriterRewind, 1);
+ if (!result)
+ error("[art_svp_writer_rewind_new] Cannot allocate memory");
result->super.add_segment = art_svp_writer_rewind_add_segment;
result->super.add_point = art_svp_writer_rewind_add_point;
@@ -1222,6 +1251,9 @@ ArtSvpWriter *art_svp_writer_rewind_new(ArtWindRule rule) {
result->n_segs_max = 16;
result->svp = (ArtSVP *)malloc(sizeof(ArtSVP) +
(result->n_segs_max - 1) * sizeof(ArtSVPSeg));
+ if (!result->svp)
+ error("[art_svp_writer_rewind_new] Cannot allocate memory");
+
result->svp->n_segs = 0;
result->n_points_max = art_new(int, result->n_segs_max);
@@ -1392,6 +1424,9 @@ static void art_svp_intersect_push_pt(ArtIntersectCtx *ctx, ArtActiveSeg *seg,
seg->y1 = y;
pri_pt = art_new(ArtPriPoint, 1);
+ if (!pri_pt)
+ error("[art_svp_intersect_push_pt] Cannot allocate memory");
+
pri_pt->x = x;
pri_pt->y = y;
pri_pt->user_data = seg;
@@ -1855,6 +1890,8 @@ static void art_svp_intersect_horiz(ArtIntersectCtx *ctx, ArtActiveSeg *seg,
return;
hs = art_new(ArtActiveSeg, 1);
+ if (!hs)
+ error("[art_svp_intersect_horiz] Cannot allocate memory");
hs->flags = ART_ACTIVE_FLAGS_DEL | (seg->flags & ART_ACTIVE_FLAGS_OUT);
if (seg->flags & ART_ACTIVE_FLAGS_OUT) {
@@ -1997,6 +2034,8 @@ static void art_svp_intersect_add_seg(ArtIntersectCtx *ctx, const ArtSVPSeg *in_
ArtActiveSeg *last = NULL;
ArtActiveSeg *left, *right;
ArtPriPoint *pri_pt = art_new(ArtPriPoint, 1);
+ if (!pri_pt)
+ error("[art_svp_intersect_add_seg] Cannot allocate memory");
seg->flags = 0;
seg->in_seg = in_seg;
@@ -2166,6 +2205,9 @@ void art_svp_intersector(const ArtSVP *in, ArtSvpWriter *out) {
return;
ctx = art_new(ArtIntersectCtx, 1);
+ if (!ctx)
+ error("[art_svp_intersector] Cannot allocate memory");
+
ctx->in = in;
ctx->out = out;
pq = art_pri_new();
@@ -2178,6 +2220,9 @@ void art_svp_intersector(const ArtSVP *in, ArtSvpWriter *out) {
ctx->in_curs = 0;
first_point = art_new(ArtPriPoint, 1);
+ if (!first_point)
+ error("[art_svp_intersector] Cannot allocate memory");
+
first_point->x = in->segs[0].points[0].x;
first_point->y = in->segs[0].points[0].y;
first_point->user_data = NULL;
@@ -2319,6 +2364,8 @@ static void art_svp_render_delete_active(int *active_segs, int j, int n_active_s
ArtSVPRenderAAIter *art_svp_render_aa_iter(const ArtSVP *svp,
int x0, int y0, int x1, int y1) {
ArtSVPRenderAAIter *iter = art_new(ArtSVPRenderAAIter, 1);
+ if (!iter)
+ error("[art_svp_render_aa_iter] Cannot allocate memory");
iter->svp = svp;
iter->y = y0;
diff --git a/engines/sword25/gfx/image/art.h b/engines/sword25/gfx/image/art.h
index bfeb31cc30..8c9c97bc57 100644
--- a/engines/sword25/gfx/image/art.h
+++ b/engines/sword25/gfx/image/art.h
@@ -51,10 +51,13 @@ namespace Sword25 {
#define art_expand(p, type, max) \
do { \
if(max) {\
- p = art_renew(p, type, max <<= 1); \
+ type *tmp = art_renew(p, type, max <<= 1); \
+ if (!tmp) error("Cannot reallocate memory for art data"); \
+ p = tmp; \
} else { \
max = 1; \
p = art_new(type, 1); \
+ if (!p) error("Cannot allocate memory for art data"); \
} \
} while (0)
diff --git a/engines/sword25/gfx/image/vectorimage.cpp b/engines/sword25/gfx/image/vectorimage.cpp
index 9235ec2fcf..b9ce5f7e00 100644
--- a/engines/sword25/gfx/image/vectorimage.cpp
+++ b/engines/sword25/gfx/image/vectorimage.cpp
@@ -321,6 +321,8 @@ ArtBpath *VectorImage::storeBez(ArtBpath *bez, int lineStyle, int fillStyle0, in
bez[*bezNodes].code = ART_END;
ArtBpath *bez1 = art_new(ArtBpath, *bezNodes + 1);
+ if (!bez1)
+ error("[VectorImage::storeBez] Cannot allocate memory");
for (int i = 0; i <= *bezNodes; i++)
bez1[i] = bez[i];
diff --git a/engines/sword25/gfx/image/vectorimagerenderer.cpp b/engines/sword25/gfx/image/vectorimagerenderer.cpp
index 97dad3346d..6d4dc213f2 100644
--- a/engines/sword25/gfx/image/vectorimagerenderer.cpp
+++ b/engines/sword25/gfx/image/vectorimagerenderer.cpp
@@ -270,6 +270,9 @@ ArtVpath *art_vpath_cat(ArtVpath *a, ArtVpath *b) {
len_a = art_vpath_len(a);
len_b = art_vpath_len(b);
dest = art_new(ArtVpath, len_a + len_b + 1);
+ if (!dest)
+ error("[art_vpath_cat] Cannot allocate memory");
+
p = dest;
for (int i = 0; i < len_a; i++)
@@ -299,6 +302,8 @@ ArtVpath *art_vpath_reverse(ArtVpath *a) {
len = art_vpath_len(a);
dest = art_new(ArtVpath, len + 1);
+ if (!dest)
+ error("[art_vpath_reverse] Cannot allocate memory");
for (i = 0; i < len; i++) {
it = a[len - i - 1];
@@ -371,6 +376,8 @@ void drawBez(ArtBpath *bez1, ArtBpath *bez2, byte *buffer, int width, int height
int size = art_vpath_len(vec);
ArtVpath *vect = art_new(ArtVpath, size + 1);
+ if (!vect)
+ error("[drawBez] Cannot allocate memory");
int k;
for (k = 0; k < size; k++) {
diff --git a/engines/sword25/package/packagemanager.h b/engines/sword25/package/packagemanager.h
index c57c30636d..b0c6718008 100644
--- a/engines/sword25/package/packagemanager.h
+++ b/engines/sword25/package/packagemanager.h
@@ -141,6 +141,9 @@ public:
uint fileSize;
char *data = (char *)getFile(fileName, &fileSize);
char *result = (char *)malloc(fileSize + strlen(versionStr) + 1);
+ if (!result)
+ error("[PackageManager::getXmlFile] Cannot allocate memory");
+
strcpy(result, versionStr);
Common::copy(data, data + fileSize, result + strlen(versionStr));
result[fileSize + strlen(versionStr)] = '\0';
diff --git a/engines/teenagent/resources.cpp b/engines/teenagent/resources.cpp
index 9e69383215..597ca670c0 100644
--- a/engines/teenagent/resources.cpp
+++ b/engines/teenagent/resources.cpp
@@ -106,13 +106,20 @@ void Resources::loadOff(Graphics::Surface &surface, byte *palette, int id) {
error("invalid background %d", id);
return;
}
- byte buf[64768];
- off.read(id, buf, sizeof(buf));
+
+ const uint bufferSize = 64768;
+ byte *buf = (byte *)malloc(bufferSize);
+ if (!buf)
+ error("[Resources::loadOff] Cannot allocate buffer");
+
+ off.read(id, buf, bufferSize);
byte *src = buf;
byte *dst = (byte *)surface.pixels;
memcpy(dst, src, 64000);
memcpy(palette, buf + 64000, 768);
+
+ free(buf);
}
Common::SeekableReadStream *Resources::loadLan(uint32 id) const {
diff --git a/engines/teenagent/teenagent.cpp b/engines/teenagent/teenagent.cpp
index 724f75be2f..0289b994e6 100644
--- a/engines/teenagent/teenagent.cpp
+++ b/engines/teenagent/teenagent.cpp
@@ -216,14 +216,22 @@ Common::Error TeenAgentEngine::loadGameState(int slot) {
Resources *res = Resources::instance();
- assert(res->dseg.size() >= 0x6478 + 0x777a);
- char data[0x777a];
+ const uint dataSize = 0x777a;
+ assert(res->dseg.size() >= 0x6478 + dataSize);
+
+ char *data = (char *)malloc(dataSize);
+ if (!data)
+ error("[TeenAgentEngine::loadGameState] Cannot allocate buffer");
+
in->seek(0);
- if (in->read(data, 0x777a) != 0x777a) {
+ if (in->read(data, dataSize) != dataSize) {
+ free(data);
return Common::kReadingFailed;
}
- memcpy(res->dseg.ptr(0x6478), data, sizeof(data));
+ memcpy(res->dseg.ptr(0x6478), data, dataSize);
+
+ free(data);
scene->clear();
inventory->activate(false);
@@ -290,17 +298,32 @@ bool TeenAgentEngine::showCDLogo() {
if (!cdlogo.exists("cdlogo.res") || !cdlogo.open("cdlogo.res"))
return true;
- byte bg[0xfa00];
- byte palette[3*256];
+ const uint bgSize = 0xfa00;
+ const uint paletteSize = 3 * 256;
+
+ byte *bg = (byte *)malloc(bgSize);
+ if (!bg)
+ error("[TeenAgentEngine::showCDLogo] Cannot allocate background buffer");
+
+ byte *palette = (byte *)malloc(paletteSize);
+ if (!palette) {
+ free(bg);
+ error("[TeenAgentEngine::showCDLogo] Cannot allocate palette buffer");
+ }
+
+ cdlogo.read(bg, bgSize);
+ cdlogo.read(palette, paletteSize);
- cdlogo.read(bg, sizeof(bg));
- cdlogo.read(palette, sizeof(palette));
- for (uint c = 0; c < 3*256; ++c)
+ for (uint c = 0; c < paletteSize; ++c)
palette[c] *= 4;
+
_system->getPaletteManager()->setPalette(palette, 0, 0x100);
_system->copyRectToScreen(bg, 320, 0, 0, 320, 200);
_system->updateScreen();
+ free(bg);
+ free(palette);
+
for(uint i = 0; i < 20; ++i) {
int r = skipEvents();
if (r != 0)
@@ -317,43 +340,66 @@ bool TeenAgentEngine::showLogo() {
if (!logo.open("unlogic.res"))
return true;
- byte bg[0xfa00];
- byte palette[3*256];
-
Common::ScopedPtr<Common::SeekableReadStream> frame(logo.getStream(1));
if (!frame)
return true;
- frame->read(bg, sizeof(bg));
- frame->read(palette, sizeof(palette));
- for (uint c = 0; c < 3*256; ++c)
+ const uint bgSize = 0xfa00;
+ const uint paletteSize = 3 * 256;
+
+ byte *bg = (byte *)malloc(bgSize);
+ if (!bg)
+ error("[TeenAgentEngine::showLogo] Cannot allocate background buffer");
+
+ byte *palette = (byte *)malloc(paletteSize);
+ if (!palette) {
+ free(bg);
+ error("[TeenAgentEngine::showLogo] Cannot allocate palette buffer");
+ }
+
+ frame->read(bg, bgSize);
+ frame->read(palette, paletteSize);
+
+ for (uint c = 0; c < paletteSize; ++c)
palette[c] *= 4;
+
_system->getPaletteManager()->setPalette(palette, 0, 0x100);
+ free(palette);
+
uint n = logo.fileCount();
for(uint f = 0; f < 4; ++f)
for(uint i = 2; i <= n; ++i) {
{
int r = skipEvents();
- if (r != 0)
+ if (r != 0) {
+ free(bg);
return r > 0? true: false;
+ }
}
_system->copyRectToScreen(bg, 320, 0, 0, 320, 200);
frame.reset(logo.getStream(i));
- if (!frame)
+ if (!frame) {
+ free(bg);
return true;
+ }
Surface s;
s.load(frame, Surface::kTypeOns);
- if (s.empty())
+ if (s.empty()) {
+ free(bg);
return true;
+ }
_system->copyRectToScreen((const byte *)s.pixels, s.w, s.x, s.y, s.w, s.h);
_system->updateScreen();
_system->delayMillis(100);
}
+
+ free(bg);
+
return true;
}
@@ -364,29 +410,53 @@ bool TeenAgentEngine::showMetropolis() {
FilePack varia;
varia.open("varia.res");
- byte palette[3*256];
+ const uint paletteSize = 3 * 256;
+ byte *palette = (byte *)malloc(paletteSize);
+ if (!palette)
+ error("[TeenAgentEngine::showMetropolis] Cannot allocate palette buffer");
+
{
Common::ScopedPtr<Common::SeekableReadStream> s(varia.getStream(5));
- s->read(palette, sizeof(palette));
- for (uint c = 0; c < 3*256; ++c)
+ s->read(palette, paletteSize);
+ for (uint c = 0; c < paletteSize; ++c)
palette[c] *= 4;
}
_system->getPaletteManager()->setPalette(palette, 0, 0x100);
- byte varia_6[21760], varia_9[18302];
- varia.read(6, varia_6, sizeof(varia_6));
- varia.read(9, varia_9, sizeof(varia_9));
+ free(palette);
- byte colors[56 * 160 * 2];
- memset(colors, 0, sizeof(colors));
+ const uint varia6Size = 21760;
+ const uint varia9Size = 18302;
+ byte *varia_6 = (byte *)malloc(varia6Size);
+ byte *varia_9 = (byte *)malloc(varia9Size);
+ if (!varia_6 || !varia_9) {
+ free(varia_6);
+ free(varia_9);
+
+ error("[TeenAgentEngine::showMetropolis] Cannot allocate buffer");
+ }
+
+ varia.read(6, varia_6, varia6Size);
+ varia.read(9, varia_9, varia9Size);
+
+ const uint colorsSize = 56 * 160 * 2;
+ byte *colors = (byte *)malloc(colorsSize);
+ if (!colors)
+ error("[TeenAgentEngine::showMetropolis] Cannot allocate colors buffer");
+
+ memset(colors, 0, colorsSize);
int logo_y = -56;
for(uint f = 0; f < 300; ++f) {
{
int r = skipEvents();
- if (r != 0)
+ if (r != 0) {
+ free(varia_6);
+ free(varia_9);
+ free(colors);
return r > 0? true: false;
+ }
}
Graphics::Surface *surface = _system->lockScreen();
@@ -441,6 +511,11 @@ bool TeenAgentEngine::showMetropolis() {
_system->updateScreen();
_system->delayMillis(100);
}
+
+ free(varia_6);
+ free(varia_9);
+ free(colors);
+
return true;
}
diff --git a/engines/toon/path.cpp b/engines/toon/path.cpp
index dde7be07d0..43a134e39b 100644
--- a/engines/toon/path.cpp
+++ b/engines/toon/path.cpp
@@ -342,8 +342,15 @@ next:
curX = destx;
curY = desty;
- int32 retPathX[4096];
- int32 retPathY[4096];
+ int32 *retPathX = (int32 *)malloc(4096 * sizeof(int32));
+ int32 *retPathY = (int32 *)malloc(4096 * sizeof(int32));
+ if (!retPathX || !retPathY) {
+ free(retPathX);
+ free(retPathY);
+
+ error("[PathFinding::findPath] Cannot allocate pathfinding buffers");
+ }
+
int32 numpath = 0;
retPathX[numpath] = curX;
@@ -377,8 +384,12 @@ next:
}
}
- if (bestX < 0 || bestY < 0)
+ if (bestX < 0 || bestY < 0) {
+ free(retPathX);
+ free(retPathY);
+
return 0;
+ }
retPathX[numpath] = bestX;
retPathY[numpath] = bestY;
@@ -389,6 +400,10 @@ next:
memcpy(_tempPathX, retPathX, sizeof(int32) * numpath);
memcpy(_tempPathY, retPathY, sizeof(int32) * numpath);
+
+ free(retPathX);
+ free(retPathY);
+
return true;
}
@@ -396,6 +411,9 @@ next:
curY = bestY;
}
+ free(retPathX);
+ free(retPathY);
+
return false;
}
diff --git a/engines/touche/resource.cpp b/engines/touche/resource.cpp
index 8f4752e912..6df6fc0e5f 100644
--- a/engines/touche/resource.cpp
+++ b/engines/touche/resource.cpp
@@ -468,14 +468,22 @@ void ToucheEngine::res_loadSprite(int num, int index) {
if (size > spr->size) {
debug(8, "Reallocating memory for sprite %d (index %d), %d bytes needed", num, index, size - spr->size);
spr->size = size;
- if (spr->ptr) {
- spr->ptr = (uint8 *)realloc(spr->ptr, size);
- } else {
- spr->ptr = (uint8 *)malloc(size);
- }
- if (!spr->ptr) {
- error("Unable to reallocate memory for sprite %d (%d bytes)", num, size);
+
+ uint8 *buffer = NULL;
+ if (spr->ptr)
+ buffer = (uint8 *)realloc(spr->ptr, size);
+
+ if (!buffer) {
+ // Free previously allocated sprite (when realloc failed)
+ free(spr->ptr);
+
+ buffer = (uint8 *)malloc(size);
}
+
+ if (!buffer)
+ error("[ToucheEngine::res_loadSprite] Unable to reallocate memory for sprite %d (%d bytes)", num, size);
+
+ spr->ptr = buffer;
}
for (int i = 0; i < _currentImageHeight; ++i) {
res_decodeScanLineImageRLE(spr->ptr + _currentImageWidth * i, _currentImageWidth);
diff --git a/engines/tsage/resources.cpp b/engines/tsage/resources.cpp
index d24c564a1f..e6a561f3a7 100644
--- a/engines/tsage/resources.cpp
+++ b/engines/tsage/resources.cpp
@@ -237,8 +237,13 @@ byte *TLib::getResource(uint16 id, bool suppressErrors) {
uint16 ctrCurrent = 0x102, ctrMax = 0x200;
uint16 word_48050 = 0, currentToken = 0, word_48054 =0;
byte byte_49068 = 0, byte_49069 = 0;
- DecodeReference table[0x1000];
- for (int i = 0; i < 0x1000; ++i) {
+
+ const uint tableSize = 0x1000;
+ DecodeReference *table = (DecodeReference *)malloc(tableSize * sizeof(DecodeReference));
+ if (!table)
+ error("[TLib::getResource] Cannot allocate table buffer");
+
+ for (int i = 0; i < tableSize; ++i) {
table[i].vByte = table[i].vWord = 0;
}
Common::Stack<uint16> tokenList;
@@ -302,6 +307,8 @@ byte *TLib::getResource(uint16 id, bool suppressErrors) {
}
}
+ free(table);
+
assert(bytesWritten == re->uncompressedSize);
delete compStream;
return dataOut;
diff --git a/engines/tsage/ringworld_logic.cpp b/engines/tsage/ringworld_logic.cpp
index 1dd905b3b6..58501172af 100644
--- a/engines/tsage/ringworld_logic.cpp
+++ b/engines/tsage/ringworld_logic.cpp
@@ -1333,9 +1333,20 @@ void RingworldGame::start() {
RING_INVENTORY._scanner._sceneNumber = 1;
RING_INVENTORY._ring._sceneNumber = 1;
+ int slot = -1;
+
+ if (ConfMan.hasKey("save_slot")) {
+ slot = ConfMan.getInt("save_slot");
+ Common::String file = _vm->generateSaveName(slot);
+ Common::InSaveFile *in = _vm->_system->getSavefileManager()->openForLoading(file);
+ if (in)
+ delete in;
+ else
+ slot = -1;
+ }
- if (ConfMan.hasKey("save_slot"))
- _globals->_sceneHandler._loadGameSlot = ConfMan.getInt("save_slot");
+ if (slot >= 0)
+ _globals->_sceneHandler._loadGameSlot = slot;
else
// Switch to the title screen
_globals->_sceneManager.setNewScene(1000);
diff --git a/engines/tsage/ringworld_scenes1.cpp b/engines/tsage/ringworld_scenes1.cpp
index 29b7c9b997..7fe2610fd7 100644
--- a/engines/tsage/ringworld_scenes1.cpp
+++ b/engines/tsage/ringworld_scenes1.cpp
@@ -342,7 +342,7 @@ void Scene20::Action2::signal() {
}
case 8:
scene->_sound.release();
- scene->_sound.fadeOut(this);
+ _globals->_soundHandler.fadeOut(this);
break;
case 9:
SceneItem::display(0, 0, LIST_END);
diff --git a/graphics/font.cpp b/graphics/font.cpp
index cdf9090625..d254c64264 100644
--- a/graphics/font.cpp
+++ b/graphics/font.cpp
@@ -214,6 +214,8 @@ int bdf_read_header(Common::SeekableReadStream &fp, NewFontData* pf) {
char buf[256];
char facename[256];
char copyright[256];
+ memset(facename, 0, sizeof(facename));
+ memset(copyright, 0, sizeof(copyright));
/* set certain values to errors for later error checking*/
pf->defaultchar = -1;
@@ -235,6 +237,7 @@ int bdf_read_header(Common::SeekableReadStream &fp, NewFontData* pf) {
warning("Error: bad 'FONT'");
return 0;
}
+
pf->facename = strdup(facename);
continue;
}
@@ -243,6 +246,7 @@ int bdf_read_header(Common::SeekableReadStream &fp, NewFontData* pf) {
warning("Error: bad 'COPYRIGHT'");
return 0;
}
+
pf->copyright = strdup(copyright);
continue;
}
diff --git a/graphics/fonts/winfont.cpp b/graphics/fonts/winfont.cpp
index 8b60f8aa6b..3bad92236d 100644
--- a/graphics/fonts/winfont.cpp
+++ b/graphics/fonts/winfont.cpp
@@ -120,15 +120,18 @@ bool WinFont::loadFromNE(const Common::String &fileName, const WinFontDirEntry &
}
bool WinFont::loadFromPE(const Common::String &fileName, const WinFontDirEntry &dirEntry) {
- Common::PEResources exe;
+ Common::PEResources *exe = new Common::PEResources();
- if (!exe.loadFromEXE(fileName))
+ if (!exe->loadFromEXE(fileName)) {
+ delete exe;
return false;
+ }
// Let's pull out the font directory
- Common::SeekableReadStream *fontDirectory = exe.getResource(Common::kPEFontDir, Common::String("FONTDIR"));
+ Common::SeekableReadStream *fontDirectory = exe->getResource(Common::kPEFontDir, Common::String("FONTDIR"));
if (!fontDirectory) {
warning("No font directory in '%s'", fileName.c_str());
+ delete exe;
return false;
}
@@ -139,18 +142,21 @@ bool WinFont::loadFromPE(const Common::String &fileName, const WinFontDirEntry &
// Couldn't match the face name
if (fontId == 0xffffffff) {
warning("Could not find face '%s' in '%s'", dirEntry.faceName.c_str(), fileName.c_str());
+ delete exe;
return false;
}
// Actually go get our font now...
- Common::SeekableReadStream *fontStream = exe.getResource(Common::kPEFont, fontId);
+ Common::SeekableReadStream *fontStream = exe->getResource(Common::kPEFont, fontId);
if (!fontStream) {
warning("Could not find font %d in %s", fontId, fileName.c_str());
+ delete exe;
return false;
}
bool ok = loadFromFNT(*fontStream);
delete fontStream;
+ delete exe;
return ok;
}
diff --git a/graphics/scaler.cpp b/graphics/scaler.cpp
index a35fb9046e..9ade0e6c57 100644
--- a/graphics/scaler.cpp
+++ b/graphics/scaler.cpp
@@ -24,6 +24,7 @@
#include "graphics/scaler/scalebit.h"
#include "common/util.h"
#include "common/system.h"
+#include "common/textconsole.h"
int gBitFormat = 565;
@@ -90,6 +91,9 @@ void InitLUT(Graphics::PixelFormat format) {
if (RGBtoYUV == 0)
RGBtoYUV = (uint32 *)malloc(65536 * sizeof(uint32));
+ if (!RGBtoYUV)
+ error("[InitLUT] Cannot allocate memory for YUV/LUT buffers");
+
for (int color = 0; color < 65536; ++color) {
format.colorToRGB(color, r, g, b);
Y = (r + g + b) >> 2;
diff --git a/gui/massadd.cpp b/gui/massadd.cpp
index b0adce3f47..70580e8b9c 100644
--- a/gui/massadd.cpp
+++ b/gui/massadd.cpp
@@ -24,6 +24,7 @@
#include "common/config-manager.h"
#include "common/debug.h"
#include "common/system.h"
+#include "common/taskbar.h"
#include "common/translation.h"
#include "gui/launcher.h" // For addGameToConf()
@@ -60,6 +61,7 @@ MassAddDialog::MassAddDialog(const Common::FSNode &startDir)
: Dialog("MassAdd"),
_dirsScanned(0),
_oldGamesCount(0),
+ _dirTotal(0),
_okButton(0),
_dirProgressText(0),
_gameProgressText(0) {
@@ -69,14 +71,14 @@ MassAddDialog::MassAddDialog(const Common::FSNode &startDir)
// The dir we start our scan at
_scanStack.push(startDir);
-// Removed for now... Why would you put a title on mass add dialog called "Mass Add Dialog"?
-// new StaticTextWidget(this, "massadddialog_caption", "Mass Add Dialog");
+ // Removed for now... Why would you put a title on mass add dialog called "Mass Add Dialog"?
+ // new StaticTextWidget(this, "massadddialog_caption", "Mass Add Dialog");
_dirProgressText = new StaticTextWidget(this, "MassAdd.DirProgressText",
- _("... progress ..."));
+ _("... progress ..."));
_gameProgressText = new StaticTextWidget(this, "MassAdd.GameProgressText",
- _("... progress ..."));
+ _("... progress ..."));
_dirProgressText->setAlign(Graphics::kTextAlignCenter);
_gameProgressText->setAlign(Graphics::kTextAlignCenter);
@@ -130,6 +132,12 @@ struct GameDescLess {
void MassAddDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) {
+#if defined(USE_TASKBAR)
+ // Remove progress bar and count from taskbar
+ g_system->getTaskbarManager()->setProgressState(Common::TaskbarManager::kTaskbarNoProgress);
+ g_system->getTaskbarManager()->setCount(0);
+#endif
+
// FIXME: It's a really bad thing that we use two arbitrary constants
if (cmd == kOkCmd) {
// Sort the detected games. This is not strictly necessary, but nice for
@@ -226,10 +234,17 @@ void MassAddDialog::handleTickle() {
for (Common::FSList::const_iterator file = files.begin(); file != files.end(); ++file) {
if (file->isDirectory()) {
_scanStack.push(*file);
+
+ _dirTotal++;
}
}
_dirsScanned++;
+
+#if defined(USE_TASKBAR)
+ g_system->getTaskbarManager()->setProgressValue(_dirsScanned, _dirTotal);
+ g_system->getTaskbarManager()->setCount(_games.size());
+#endif
}
diff --git a/gui/massadd.h b/gui/massadd.h
index 15cef7ba68..7350213835 100644
--- a/gui/massadd.h
+++ b/gui/massadd.h
@@ -60,6 +60,7 @@ private:
int _dirsScanned;
int _oldGamesCount;
+ int _dirTotal;
Widget *_okButton;
StaticTextWidget *_dirProgressText;
diff --git a/gui/themes/translations.dat b/gui/themes/translations.dat
index 83155bba1b..f218747182 100644
--- a/gui/themes/translations.dat
+++ b/gui/themes/translations.dat
Binary files differ
diff --git a/po/hu_HU.po b/po/hu_HU.po
index 78062e9d41..4663df0ded 100644
--- a/po/hu_HU.po
+++ b/po/hu_HU.po
@@ -8,7 +8,7 @@ msgstr ""
"Project-Id-Version: ScummVM 1.3.0svn\n"
"Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n"
"POT-Creation-Date: 2011-06-20 23:09+0100\n"
-"PO-Revision-Date: 2011-06-15 07:42+0100\n"
+"PO-Revision-Date: 2011-06-21 09:54+0100\n"
"Last-Translator: Gruby <grubycza@hotmail.com>\n"
"Language-Team: Hungarian\n"
"MIME-Version: 1.0\n"
@@ -1081,7 +1081,7 @@ msgstr "A motor nem támogatja a játékállás mentését"
#: common/error.cpp:71
msgid "User canceled"
-msgstr ""
+msgstr "Felhasználói megszakítás"
#: common/error.cpp:75
msgid "Unknown error"
@@ -1239,10 +1239,13 @@ msgid ""
"ScummVM. As such, it is likely to be unstable, and any saves you make might "
"not work in future versions of ScummVM."
msgstr ""
+"FIGYELEM: A játékot amit indítani akarsz még nem teljesen támogatotja a "
+"ScummVM. Számíts rá hogy nem stabilan fut, és a mentések nem működnek a "
+"jövőbeni ScummVM verziókkal."
#: engines/engine.cpp:408
msgid "Start anyway"
-msgstr ""
+msgstr "Indítás így is"
#: engines/scumm/dialogs.cpp:281
msgid "~P~revious"