diff options
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; } @@ -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 Binary files differindex 83155bba1b..f218747182 100644 --- a/gui/themes/translations.dat +++ b/gui/themes/translations.dat 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" |