Initial commit
This commit is contained in:
1
engines/tony/POTFILES
Normal file
1
engines/tony/POTFILES
Normal file
@@ -0,0 +1 @@
|
||||
engines/tony/tony.cpp
|
||||
3
engines/tony/configure.engine
Normal file
3
engines/tony/configure.engine
Normal file
@@ -0,0 +1,3 @@
|
||||
# This file is included from the main "configure" script
|
||||
# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps] [components]
|
||||
add_engine tony "Tony Tough and the Night of Roasted Moths" yes "" "" "16bit highres"
|
||||
5
engines/tony/credits.pl
Normal file
5
engines/tony/credits.pl
Normal file
@@ -0,0 +1,5 @@
|
||||
begin_section("Tony");
|
||||
add_person("Arnaud Boutonné", "Strangerke", "");
|
||||
add_person("Paul Gilbert", "dreammaster", "");
|
||||
add_person("Alyssa Milburn", "fuzzie", "");
|
||||
end_section();
|
||||
2505
engines/tony/custom.cpp
Normal file
2505
engines/tony/custom.cpp
Normal file
File diff suppressed because it is too large
Load Diff
84
engines/tony/custom.h
Normal file
84
engines/tony/custom.h
Normal file
@@ -0,0 +1,84 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on original Tony Tough source code
|
||||
*
|
||||
* Copyright (c) 1997-2003 Nayma Software
|
||||
*/
|
||||
|
||||
#ifndef TONY_CUSTOM_H
|
||||
#define TONY_CUSTOM_H
|
||||
|
||||
#include "common/str.h"
|
||||
#include "tony/mpal/mpal.h"
|
||||
|
||||
namespace Tony {
|
||||
|
||||
using namespace MPAL;
|
||||
|
||||
struct MusicFileEntry {
|
||||
const char *_name;
|
||||
int _sync;
|
||||
};
|
||||
|
||||
#define INIT_CUSTOM_FUNCTION MapCustomFunctions
|
||||
|
||||
#define BEGIN_CUSTOM_FUNCTION_MAP() \
|
||||
static void AssignError(int num) { \
|
||||
error("Custom function %u has been already assigned!", num); \
|
||||
} \
|
||||
void INIT_CUSTOM_FUNCTION(LPCUSTOMFUNCTION *lpMap, Common::String *lpStrMap) \
|
||||
{
|
||||
|
||||
#define END_CUSTOM_FUNCTION_MAP() \
|
||||
}
|
||||
|
||||
#define ASSIGN(num, func) \
|
||||
if (lpMap[num] != NULL) \
|
||||
AssignError(num); \
|
||||
lpMap[num] = func; \
|
||||
lpStrMap[num] = #func;
|
||||
|
||||
class RMTony;
|
||||
class RMPointer;
|
||||
class RMGameBoxes;
|
||||
class RMLocation;
|
||||
class RMInventory;
|
||||
class RMInput;
|
||||
|
||||
void charsSaveAll(Common::OutSaveFile *f);
|
||||
void charsLoadAll(Common::InSaveFile *f);
|
||||
void mCharResetCodes();
|
||||
void saveChangedHotspot(Common::OutSaveFile *f);
|
||||
void loadChangedHotspot(Common::InSaveFile *f);
|
||||
void reapplyChangedHotspot();
|
||||
|
||||
void restoreMusic(CORO_PARAM);
|
||||
void saveMusic(Common::OutSaveFile *f);
|
||||
void loadMusic(Common::InSaveFile *f);
|
||||
|
||||
void INIT_CUSTOM_FUNCTION(LPCUSTOMFUNCTION *lpMap, Common::String *lpStrMap);
|
||||
void setupGlobalVars(RMTony *tony, RMPointer *ptr, RMGameBoxes *box, RMLocation *loc, RMInventory *inv, RMInput *input);
|
||||
|
||||
#endif
|
||||
|
||||
} // end of namespace Tony
|
||||
128
engines/tony/debugger.cpp
Normal file
128
engines/tony/debugger.cpp
Normal file
@@ -0,0 +1,128 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/coroutines.h"
|
||||
#include "tony/debugger.h"
|
||||
#include "tony/globals.h"
|
||||
#include "tony/tony.h"
|
||||
|
||||
namespace Tony {
|
||||
|
||||
Debugger::Debugger() : GUI::Debugger() {
|
||||
registerCmd("continue", WRAP_METHOD(Debugger, cmdExit));
|
||||
registerCmd("scene", WRAP_METHOD(Debugger, Cmd_Scene));
|
||||
registerCmd("dirty_rects", WRAP_METHOD(Debugger, Cmd_DirtyRects));
|
||||
}
|
||||
|
||||
static int strToInt(const char *s) {
|
||||
if (!*s)
|
||||
// No string at all
|
||||
return 0;
|
||||
else if (toupper(s[strlen(s) - 1]) != 'H')
|
||||
// Standard decimal string
|
||||
return atoi(s);
|
||||
|
||||
// Hexadecimal string
|
||||
uint tmp = 0;
|
||||
int read = sscanf(s, "%xh", &tmp);
|
||||
if (read < 1)
|
||||
error("strToInt failed on string \"%s\"", s);
|
||||
return (int)tmp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Support process for changing the scene
|
||||
*/
|
||||
struct ChangeSceneDetails {
|
||||
int sceneNumber;
|
||||
int x;
|
||||
int y;
|
||||
};
|
||||
|
||||
void DebugChangeScene(CORO_PARAM, const void *param) {
|
||||
CORO_BEGIN_CONTEXT;
|
||||
CORO_END_CONTEXT(_ctx);
|
||||
|
||||
uint32 result;
|
||||
const ChangeSceneDetails *details = (const ChangeSceneDetails *)param;
|
||||
RMPoint scenePos(details->x, details->y);
|
||||
|
||||
CORO_BEGIN_CODE(_ctx);
|
||||
|
||||
CORO_INVOKE_2(g_vm->getEngine()->unloadLocation, false, &result);
|
||||
|
||||
g_vm->getEngine()->loadLocation(details->sceneNumber, scenePos, RMPoint(-1, -1));
|
||||
|
||||
mainEnableGUI();
|
||||
|
||||
CORO_END_CODE;
|
||||
}
|
||||
|
||||
/**
|
||||
* This command loads up the specified new scene number
|
||||
*/
|
||||
bool Debugger::Cmd_Scene(int argc, const char **argv) {
|
||||
if (argc < 2) {
|
||||
debugPrintf("Usage: %s <scene number> [<x> <y>]\n", argv[0]);
|
||||
return true;
|
||||
}
|
||||
|
||||
int sceneNumber = strToInt(argv[1]);
|
||||
if (sceneNumber >= g_vm->_theBoxes.getLocBoxesCount()) {
|
||||
debugPrintf("Invalid scene\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
RMPoint scenePos;
|
||||
if (argc >= 4) {
|
||||
scenePos._x = strToInt(argv[2]);
|
||||
scenePos._y = strToInt(argv[3]);
|
||||
} else {
|
||||
// Get the box areas for the scene, and choose one so as to have a default
|
||||
// position for Tony that will be in the walkable areas
|
||||
RMBoxLoc *box = g_vm->_theBoxes.getBoxes(sceneNumber);
|
||||
scenePos.set(box->_boxes[0]._hotspot[0]._hotx, box->_boxes[0]._hotspot[0]._hoty);
|
||||
}
|
||||
|
||||
// Set up a process to change the scene
|
||||
ChangeSceneDetails details;
|
||||
details.sceneNumber = sceneNumber;
|
||||
details.x = scenePos._x;
|
||||
details.y = scenePos._y;
|
||||
CoroScheduler.createProcess(DebugChangeScene, &details, sizeof(ChangeSceneDetails));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns showing dirty rects on or off
|
||||
*/
|
||||
bool Debugger::Cmd_DirtyRects(int argc, const char **argv) {
|
||||
if (argc != 2) {
|
||||
debugPrintf("Usage; %s [on | off]\n", argv[0]);
|
||||
return true;
|
||||
} else {
|
||||
g_vm->_window.showDirtyRects(strcmp(argv[1], "on") == 0);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Tony
|
||||
42
engines/tony/debugger.h
Normal file
42
engines/tony/debugger.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TONY_DEBUGGER_H
|
||||
#define TONY_DEBUGGER_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "gui/debugger.h"
|
||||
|
||||
namespace Tony {
|
||||
|
||||
class Debugger : public GUI::Debugger {
|
||||
public:
|
||||
Debugger();
|
||||
~Debugger() override {}
|
||||
|
||||
protected:
|
||||
bool Cmd_Scene(int argc, const char **argv);
|
||||
bool Cmd_DirtyRects(int argc, const char **argv);
|
||||
};
|
||||
|
||||
} // End of namespace Tony
|
||||
|
||||
#endif
|
||||
74
engines/tony/detection.cpp
Normal file
74
engines/tony/detection.cpp
Normal file
@@ -0,0 +1,74 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "base/plugins.h"
|
||||
|
||||
#include "engines/advancedDetector.h"
|
||||
|
||||
#include "tony/detection.h"
|
||||
#include "tony/tony.h"
|
||||
|
||||
static const PlainGameDescriptor tonyGames[] = {
|
||||
{"tony", "Tony Tough and the Night of Roasted Moths"},
|
||||
{0, 0}
|
||||
};
|
||||
|
||||
static const DebugChannelDef debugFlagList[] = {
|
||||
{Tony::kTonyDebugAnimations, "animations", "Animations debugging"},
|
||||
{Tony::kTonyDebugActions, "actions", "Actions debugging"},
|
||||
{Tony::kTonyDebugSound, "sound", "Sound debugging"},
|
||||
{Tony::kTonyDebugMusic, "music", "Music debugging"},
|
||||
DEBUG_CHANNEL_END
|
||||
};
|
||||
|
||||
#include "tony/detection_tables.h"
|
||||
|
||||
static const char *const directoryGlobs[] = {
|
||||
"roasted",
|
||||
"voices",
|
||||
0
|
||||
};
|
||||
|
||||
class TonyMetaEngineDetection : public AdvancedMetaEngineDetection<Tony::TonyGameDescription> {
|
||||
public:
|
||||
TonyMetaEngineDetection() : AdvancedMetaEngineDetection(Tony::gameDescriptions, tonyGames) {
|
||||
_maxScanDepth = 2;
|
||||
_directoryGlobs = directoryGlobs;
|
||||
}
|
||||
|
||||
const char *getName() const override {
|
||||
return "tony";
|
||||
}
|
||||
|
||||
const char *getEngineName() const override {
|
||||
return "Tony Tough and the Night of Roasted Moths";
|
||||
}
|
||||
|
||||
const char *getOriginalCopyright() const override {
|
||||
return "Tony Tough and the Night of Roasted Moths (C) Protonic Interactive";
|
||||
}
|
||||
|
||||
const DebugChannelDef *getDebugChannels() const override {
|
||||
return debugFlagList;
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_PLUGIN_STATIC(TONY_DETECTION, PLUGIN_TYPE_ENGINE_DETECTION, TonyMetaEngineDetection);
|
||||
39
engines/tony/detection.h
Normal file
39
engines/tony/detection.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TONY_DETECTION_H
|
||||
#define TONY_DETECTION_H
|
||||
|
||||
namespace Tony {
|
||||
|
||||
enum {
|
||||
GF_COMPRESSED = (1 << 0)
|
||||
};
|
||||
|
||||
struct TonyGameDescription {
|
||||
AD_GAME_DESCRIPTION_HELPERS(desc);
|
||||
|
||||
ADGameDescription desc;
|
||||
};
|
||||
|
||||
} // End of namespace Tony
|
||||
|
||||
#endif // TONY_DETECTION_H
|
||||
279
engines/tony/detection_tables.h
Normal file
279
engines/tony/detection_tables.h
Normal file
@@ -0,0 +1,279 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace Tony {
|
||||
|
||||
static const TonyGameDescription gameDescriptions[] = {
|
||||
{
|
||||
// Tony Tough English
|
||||
{
|
||||
"tony",
|
||||
0,
|
||||
{
|
||||
{ "roasted.mpc", 0, "57c4a3860cf899443c357e0078ea6f49", 366773 },
|
||||
{ "roasted.mpr", 0, "06203dbbc85fdd1e6dc8fc211c1a6207", 135911071 },
|
||||
{ "voices.vdb", 0, "aebc6eb607ee19cc94bfe9c11898bb8c", 243003502 },
|
||||
AD_LISTEND
|
||||
},
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_DROPPLATFORM,
|
||||
GUIO1(GUIO_NOMIDI)
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
// Tony Tough Czech
|
||||
{
|
||||
"tony",
|
||||
0,
|
||||
{
|
||||
{ "roasted.mpc", 0, "a8283a101878f3ca105f1f83f07e2c40", 386491 },
|
||||
{ "roasted.mpr", 0, "06203dbbc85fdd1e6dc8fc211c1a6207", 135911071 },
|
||||
{ "voices.vdb", 0, "3384bdcb70d1e1ecedbde26e79683ede", 299019523 },
|
||||
AD_LISTEND
|
||||
},
|
||||
Common::CS_CZE,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_DROPPLATFORM,
|
||||
GUIO1(GUIO_NOMIDI)
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
// Tony Tough French "Collection Aventure" provided by Strangerke
|
||||
{
|
||||
"tony",
|
||||
0,
|
||||
{
|
||||
{ "roasted.mpc", 0, "e890c6a41238827bdfa9874a65618b69", 374135 },
|
||||
{ "roasted.mpr", 0, "06203dbbc85fdd1e6dc8fc211c1a6207", 135911071 },
|
||||
{ "voices.vdb", 0, "aebc6eb607ee19cc94bfe9c11898bb8c", 243003502 },
|
||||
AD_LISTEND
|
||||
},
|
||||
Common::FR_FRA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_DROPPLATFORM,
|
||||
GUIO1(GUIO_NOMIDI)
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
// Tony Tough Spanish provided by Pakolmo
|
||||
{
|
||||
"tony",
|
||||
0,
|
||||
{
|
||||
{ "roasted.mpc", 0, "bcca7985db2fba9c1c4a0886618ec835", 515967 },
|
||||
{ "roasted.mpr", 0, "06203dbbc85fdd1e6dc8fc211c1a6207", 135911071 },
|
||||
{ "voices.vdb", 0, "aebc6eb607ee19cc94bfe9c11898bb8c", 243003502 },
|
||||
AD_LISTEND
|
||||
},
|
||||
Common::ES_ESP,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_DROPPLATFORM,
|
||||
GUIO1(GUIO_NOMIDI)
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
// Tony Tough German "Shoe Box" provided by Strangerke
|
||||
{
|
||||
"tony",
|
||||
0,
|
||||
{
|
||||
{ "roasted.mpc", 0, "ccf7ab939a34de1b13df538596431684", 389554 },
|
||||
{ "roasted.mpr", 0, "06203dbbc85fdd1e6dc8fc211c1a6207", 135911071 },
|
||||
{ "voices.vdb", 0, "6a3c2f5426ab762bf4dc9826796aa320", 279745055 },
|
||||
AD_LISTEND
|
||||
},
|
||||
Common::DE_DEU,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_DROPPLATFORM,
|
||||
GUIO1(GUIO_NOMIDI)
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
// Tony Tough German "Gamestar" provided in bug #6138
|
||||
{
|
||||
"tony",
|
||||
0,
|
||||
{
|
||||
{ "roasted.mpc", 0, "187de6f88f4083808cb66342ab55a7fd", 389904 },
|
||||
{ "roasted.mpr", 0, "06203dbbc85fdd1e6dc8fc211c1a6207", 135911071 },
|
||||
{ "voices.vdb", 0, 0, AD_NO_SIZE }, // FIXME
|
||||
AD_LISTEND
|
||||
},
|
||||
Common::DE_DEU,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_DROPPLATFORM,
|
||||
GUIO1(GUIO_NOMIDI)
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
// Tony Tough Italian provided by Fabio Barzagli
|
||||
{
|
||||
"tony",
|
||||
0,
|
||||
{
|
||||
{ "roasted.mpc", 0, "1dc896cdb945170d7408598f803411c1", 380001 },
|
||||
{ "roasted.mpr", 0, "06203dbbc85fdd1e6dc8fc211c1a6207", 135911071 },
|
||||
{ "voices.vdb", 0, "f9f1ac8f63a909bb3ed972490dae65c4", 286130226 },
|
||||
AD_LISTEND
|
||||
},
|
||||
Common::IT_ITA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_DROPPLATFORM,
|
||||
GUIO1(GUIO_NOMIDI)
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
// Tony Tough Italian provided by Giovanni Bajo
|
||||
{
|
||||
"tony",
|
||||
0,
|
||||
{
|
||||
{ "roasted.mpc", 0, "6202816f991b15af82aab84e3e4be011", 380183 },
|
||||
{ "roasted.mpr", 0, "06203dbbc85fdd1e6dc8fc211c1a6207", 135911071 },
|
||||
{ "voices.vdb", 0, "f9f1ac8f63a909bb3ed972490dae65c4", 286130226 },
|
||||
AD_LISTEND
|
||||
},
|
||||
Common::IT_ITA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_DROPPLATFORM,
|
||||
GUIO1(GUIO_NOMIDI)
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
// Tony Tough Polish provided by iGom bug #11546
|
||||
{
|
||||
"tony",
|
||||
0,
|
||||
{
|
||||
{ "roasted.mpc", 0, "c212a81e34edf92bc177a80f24780bd2", 380200 },
|
||||
{ "roasted.mpr", 0, "06203dbbc85fdd1e6dc8fc211c1a6207", 135911071 },
|
||||
{ "voices.vdb", 0, "544b1db3a41b0f89567267d0664183bb", 321349288 },
|
||||
AD_LISTEND
|
||||
},
|
||||
Common::PL_POL,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_DROPPLATFORM,
|
||||
GUIO1(GUIO_NOMIDI)
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
// Tony Tough Polish provided by Fabio Barzagli
|
||||
{
|
||||
"tony",
|
||||
0,
|
||||
{
|
||||
{ "roasted.mpc", 0, "89733ea710669acc8e7900b115f4afef", 389625 },
|
||||
{ "roasted.mpr", 0, "06203dbbc85fdd1e6dc8fc211c1a6207", 135911071 },
|
||||
{ "voices.vdb", 0, "544b1db3a41b0f89567267d0664183bb", 310906270 },
|
||||
AD_LISTEND
|
||||
},
|
||||
Common::PL_POL,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_DROPPLATFORM,
|
||||
GUIO1(GUIO_NOMIDI)
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
// Tony Tough Russian, reported in bug #6589
|
||||
{
|
||||
"tony",
|
||||
0,
|
||||
{
|
||||
{ "roasted.mpc", 0, "377d6e24adeedc6c5c09c31b92231218", 391536 },
|
||||
{ "roasted.mpr", 0, "06203dbbc85fdd1e6dc8fc211c1a6207", 135911071 },
|
||||
{ "voices.vdb", 0, "af4061f49b934086710f0d41e6250a15", 325225827 },
|
||||
AD_LISTEND
|
||||
},
|
||||
Common::RU_RUS,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_DROPPLATFORM,
|
||||
GUIO1(GUIO_NOMIDI)
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
// Tony Tough English Demo
|
||||
{
|
||||
"tony",
|
||||
"Extracted Demo",
|
||||
{
|
||||
{ "roasted.mpc", 0, "1e247922ec869712bfd96625bc4d3c7c", 39211 },
|
||||
{ "roasted.mpr", 0, "06203dbbc85fdd1e6dc8fc211c1a6207", 14972409 },
|
||||
{ "voices.vdb", 0, "f9f1ac8f63a909bb3ed972490dae65c4", 20189260 },
|
||||
AD_LISTEND
|
||||
},
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_DEMO | ADGF_DROPPLATFORM,
|
||||
GUIO1(GUIO_NOMIDI)
|
||||
},
|
||||
},
|
||||
|
||||
#if 0
|
||||
// Disabling this detection entry. The package contains _only_ standard list
|
||||
// of InnoSetup files:
|
||||
//
|
||||
// DATA.TAG SETUP.INI _ISDEL.EXE _sys1.cab data1.cab layout.bin
|
||||
// setup.bmp setup.lid SETUP.EXE _INST32I.EX_ _setup.dll _user1.cab
|
||||
// lang.dat os.dat setup.ins
|
||||
//
|
||||
// As a result, adding this entry will lead to a false "unknown variant for tony-demo"
|
||||
// For practically all games which use InnoSetup.
|
||||
//
|
||||
// The current AdvancedDetector code always will show the end user the detected
|
||||
// game AND this entry, which is very annoying
|
||||
//
|
||||
// The only potential solution is to make AD work with the InnoSetup archives,
|
||||
// that is, make it look inside of the archive and if it contains the matching
|
||||
// file names, only then report it as an unknown variant.
|
||||
{
|
||||
// Tony Tough English Demo (Compressed)
|
||||
{
|
||||
"tony",
|
||||
"Demo",
|
||||
{
|
||||
{ "data1.cab", 0, "7d8b6d308f96aee3968ad7910fb11e6d", 58660608 },
|
||||
{ "data.tag", 0, "e9af151040745e83081e691356abeed7", 137 },
|
||||
AD_LISTEND
|
||||
},
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_DEMO | GF_COMPRESSED | ADGF_DROPPLATFORM,
|
||||
GUIO1(GUIO_NOMIDI)
|
||||
},
|
||||
},
|
||||
#endif
|
||||
|
||||
{ AD_TABLE_END_MARKER }
|
||||
};
|
||||
|
||||
} // End of namespace Tony
|
||||
1175
engines/tony/font.cpp
Normal file
1175
engines/tony/font.cpp
Normal file
File diff suppressed because it is too large
Load Diff
374
engines/tony/font.h
Normal file
374
engines/tony/font.h
Normal file
@@ -0,0 +1,374 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* This code is based on original Tony Tough source code
|
||||
*
|
||||
* Copyright (c) 1997-2003 Nayma Software
|
||||
*/
|
||||
|
||||
#ifndef TONY_FONT_H
|
||||
#define TONY_FONT_H
|
||||
|
||||
#include "common/system.h"
|
||||
#include "common/coroutines.h"
|
||||
#include "tony/gfxcore.h"
|
||||
#include "tony/resid.h"
|
||||
|
||||
namespace Tony {
|
||||
|
||||
class RMInput;
|
||||
class RMInventory;
|
||||
class RMItem;
|
||||
class RMLoc;
|
||||
class RMLocation;
|
||||
class RMPointer;
|
||||
|
||||
/**
|
||||
* Manages a font, in which there is a different surface for each letter
|
||||
*/
|
||||
class RMFont : public RMGfxTaskSetPrior {
|
||||
protected:
|
||||
int _nLetters;
|
||||
RMGfxSourceBuffer8RLEByte *_letter;
|
||||
public:
|
||||
int _fontDimx, _fontDimy;
|
||||
|
||||
private:
|
||||
int _dimx, _dimy;
|
||||
|
||||
class RMFontPrimitive : public RMGfxPrimitive {
|
||||
public:
|
||||
RMFontPrimitive() : RMGfxPrimitive() { _nChar = 0; }
|
||||
RMFontPrimitive(RMGfxTask *task) : RMGfxPrimitive(task) { _nChar = 0; }
|
||||
~RMFontPrimitive() override { }
|
||||
RMGfxPrimitive *duplicate() override {
|
||||
return new RMFontPrimitive(*this);
|
||||
}
|
||||
|
||||
int _nChar;
|
||||
};
|
||||
|
||||
protected:
|
||||
// Loads the font
|
||||
void load(uint32 resID, int nChars, int dimx, int dimy, uint32 palResID = RES_F_PAL);
|
||||
void load(const byte *buf, int nChars, int dimx, int dimy, uint32 palResID = RES_F_PAL);
|
||||
|
||||
// Remove the font
|
||||
void unload();
|
||||
|
||||
protected:
|
||||
// Conversion form character to font index
|
||||
virtual int convertToLetter(byte nChar) = 0;
|
||||
|
||||
// Character width
|
||||
virtual int letterLength(int nChar, int nNext = 0) = 0;
|
||||
|
||||
public:
|
||||
virtual int letterHeight() = 0;
|
||||
|
||||
public:
|
||||
RMFont();
|
||||
~RMFont() override;
|
||||
|
||||
// Initialization and closing
|
||||
virtual void init() = 0;
|
||||
virtual void close();
|
||||
|
||||
// Drawing
|
||||
void draw(CORO_PARAM, RMGfxTargetBuffer &bigBug, RMGfxPrimitive *prim) override;
|
||||
|
||||
// Create a primitive for a letter
|
||||
RMGfxPrimitive *makeLetterPrimitive(byte bChar, int &nLength);
|
||||
|
||||
// Length in pixels of a string with the current font
|
||||
int stringLen(const Common::String &text);
|
||||
int stringLen(char bChar, char bNext = 0);
|
||||
};
|
||||
|
||||
class RMFontColor : public virtual RMFont {
|
||||
private:
|
||||
byte _fontR, _fontG, _fontB;
|
||||
|
||||
public:
|
||||
RMFontColor();
|
||||
~RMFontColor() override;
|
||||
virtual void setBaseColor(byte r, byte g, byte b);
|
||||
};
|
||||
|
||||
class RMFontWithTables : public virtual RMFont {
|
||||
protected:
|
||||
int _cTable[256];
|
||||
int _lTable[256];
|
||||
int _lDefault;
|
||||
int _hDefault;
|
||||
signed char _l2Table[256][256];
|
||||
|
||||
protected:
|
||||
// Overloaded methods
|
||||
int convertToLetter(byte nChar) override;
|
||||
int letterLength(int nChar, int nNext = 0) override;
|
||||
|
||||
public:
|
||||
int letterHeight() override {
|
||||
return _hDefault;
|
||||
}
|
||||
~RMFontWithTables() override {}
|
||||
};
|
||||
|
||||
class RMFontDialog : public RMFontColor, public RMFontWithTables {
|
||||
public:
|
||||
void init() override;
|
||||
~RMFontDialog() override {}
|
||||
};
|
||||
|
||||
class RMFontObj : public RMFontColor, public RMFontWithTables {
|
||||
private:
|
||||
void setBothCase(int nChar, int nNext, signed char spiazz);
|
||||
|
||||
public:
|
||||
void init() override;
|
||||
~RMFontObj() override {}
|
||||
};
|
||||
|
||||
class RMFontMacc : public RMFontColor, public RMFontWithTables {
|
||||
public:
|
||||
void init() override;
|
||||
~RMFontMacc() override {}
|
||||
};
|
||||
|
||||
class RMFontCredits : public RMFontColor, public RMFontWithTables {
|
||||
public:
|
||||
void init() override;
|
||||
~RMFontCredits() override {}
|
||||
void setBaseColor(byte r, byte g, byte b) override {}
|
||||
};
|
||||
|
||||
/**
|
||||
* Manages writing text onto9 the screen
|
||||
*/
|
||||
class RMText : public RMGfxWoodyBuffer {
|
||||
private:
|
||||
static RMFontColor *_fonts[4];
|
||||
int _maxLineLength;
|
||||
|
||||
public:
|
||||
enum HorAlign {
|
||||
HLEFT,
|
||||
HLEFTPAR,
|
||||
HCENTER,
|
||||
HRIGHT
|
||||
};
|
||||
|
||||
enum VerAlign {
|
||||
VTOP,
|
||||
VCENTER,
|
||||
VBOTTOM
|
||||
};
|
||||
|
||||
private:
|
||||
HorAlign _aHorType;
|
||||
VerAlign _aVerType;
|
||||
byte _textR, _textG, _textB;
|
||||
|
||||
protected:
|
||||
virtual void clipOnScreen(RMGfxPrimitive *prim);
|
||||
|
||||
public:
|
||||
RMText();
|
||||
~RMText() override;
|
||||
static void initStatics();
|
||||
static void unload();
|
||||
|
||||
// Set the alignment type
|
||||
void setAlignType(HorAlign aHor, VerAlign aVer);
|
||||
|
||||
// Sets the maximum length of a line in pixels (used to format the text)
|
||||
void setMaxLineLength(int max);
|
||||
|
||||
// Write the text
|
||||
void writeText(const Common::String &text, int font, int *time = NULL);
|
||||
void writeText(Common::String text, RMFontColor *font, int *time = NULL);
|
||||
|
||||
// Overloaded function to decide when you delete the object from the OT list
|
||||
void removeThis(CORO_PARAM, bool &result) override;
|
||||
|
||||
// Overloading of the Draw to center the text, if necessary
|
||||
void draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim) override;
|
||||
|
||||
// Set the base color
|
||||
void setColor(byte r, byte g, byte b);
|
||||
};
|
||||
|
||||
/**
|
||||
* Manages text in a dialog
|
||||
*/
|
||||
class RMTextDialog : public RMText {
|
||||
protected:
|
||||
int _startTime;
|
||||
int _time;
|
||||
bool _bSkipStatus;
|
||||
RMPoint _dst;
|
||||
uint32 _hEndDisplay;
|
||||
bool _bShowed;
|
||||
bool _bForceTime;
|
||||
bool _bForceNoTime;
|
||||
uint32 _hCustomSkip;
|
||||
uint32 _hCustomSkip2;
|
||||
RMInput *_input;
|
||||
bool _bAlwaysDisplay;
|
||||
bool _bNoTab;
|
||||
|
||||
public:
|
||||
RMTextDialog();
|
||||
~RMTextDialog() override;
|
||||
|
||||
// Write the text
|
||||
void writeText(const Common::String &text, int font, int *time = NULL);
|
||||
void writeText(const Common::String &text, RMFontColor *font, int *time = NULL);
|
||||
|
||||
// Overloaded function to decide when you delete the object from the OT list
|
||||
void removeThis(CORO_PARAM, bool &result) override;
|
||||
|
||||
// Overloaded de-registration
|
||||
void unregister() override;
|
||||
|
||||
// Overloading of the Draw to center the text, if necessary
|
||||
void draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim) override;
|
||||
|
||||
// Set the position
|
||||
void setPosition(const RMPoint &pt);
|
||||
|
||||
// Waiting
|
||||
void waitForEndDisplay(CORO_PARAM);
|
||||
void setCustomSkipHandle(uint32 hCustomSkip);
|
||||
void setCustomSkipHandle2(uint32 hCustomSkip);
|
||||
void setSkipStatus(bool bEnabled);
|
||||
void setForcedTime(uint32 dwTime);
|
||||
void setNoTab();
|
||||
void forceTime();
|
||||
void forceNoTime();
|
||||
void setAlwaysDisplay();
|
||||
|
||||
// Set the input device, to allow skip from mouse
|
||||
void setInput(RMInput *input);
|
||||
|
||||
void show();
|
||||
void hide(CORO_PARAM);
|
||||
};
|
||||
|
||||
class RMTextDialogScrolling : public RMTextDialog {
|
||||
protected:
|
||||
RMLocation *_curLoc;
|
||||
RMPoint _startScroll;
|
||||
|
||||
void clipOnScreen(RMGfxPrimitive *prim) override;
|
||||
|
||||
public:
|
||||
RMTextDialogScrolling();
|
||||
RMTextDialogScrolling(RMLocation *loc);
|
||||
~RMTextDialogScrolling() override;
|
||||
|
||||
void draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim) override;
|
||||
};
|
||||
|
||||
/**
|
||||
* Manages the name of a selected item on the screen
|
||||
*/
|
||||
class RMTextItemName : protected RMText {
|
||||
protected:
|
||||
RMPoint _mpos;
|
||||
RMPoint _curscroll;
|
||||
RMItem *_item;
|
||||
|
||||
public:
|
||||
RMTextItemName();
|
||||
~RMTextItemName() override;
|
||||
|
||||
void setMouseCoord(const RMPoint &m);
|
||||
|
||||
void doFrame(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMLocation &loc, RMPointer &ptr, RMInventory &inv);
|
||||
void draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim) override;
|
||||
|
||||
RMPoint getHotspot();
|
||||
RMItem *getSelectedItem();
|
||||
bool isItemSelected();
|
||||
|
||||
void removeThis(CORO_PARAM, bool &result) override;
|
||||
};
|
||||
|
||||
/**
|
||||
* Manages the selection of screen items in a box
|
||||
*/
|
||||
class RMDialogChoice : public RMGfxWoodyBuffer {
|
||||
private:
|
||||
int _curSelection;
|
||||
int _numChoices;
|
||||
RMText *_drawedStrings;
|
||||
RMPoint *_ptDrawStrings;
|
||||
int _curAdded;
|
||||
bool _bShow;
|
||||
RMGfxSourceBuffer8 _dlgText;
|
||||
RMGfxSourceBuffer8 _dlgTextLine;
|
||||
RMPoint _ptDrawPos;
|
||||
uint32 _hUnreg;
|
||||
bool _bRemoveFromOT;
|
||||
|
||||
protected:
|
||||
void prepare(CORO_PARAM);
|
||||
void setSelected(CORO_PARAM, int pos);
|
||||
|
||||
public:
|
||||
void removeThis(CORO_PARAM, bool &result) override;
|
||||
void draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim) override;
|
||||
void unregister() override;
|
||||
|
||||
public:
|
||||
// Initialization
|
||||
RMDialogChoice();
|
||||
~RMDialogChoice() override;
|
||||
|
||||
// Initialization and closure
|
||||
using RMGfxWoodyBuffer::init;
|
||||
void init();
|
||||
void close();
|
||||
|
||||
// Sets the number of possible sentences, which then be added with AddChoice()
|
||||
void setNumChoices(int num);
|
||||
|
||||
// Adds a string with the choice
|
||||
void addChoice(const Common::String &string);
|
||||
|
||||
// Show and hide the selection, with possible animations.
|
||||
// NOTE: If no parameter is passed to Show(), it is the obligation of
|
||||
// caller to ensure that the class is inserted into OT list
|
||||
void show(CORO_PARAM, RMGfxTargetBuffer *bigBuf = NULL);
|
||||
void hide(CORO_PARAM);
|
||||
|
||||
// Polling Update
|
||||
void doFrame(CORO_PARAM, RMPoint ptMousePos);
|
||||
|
||||
// Returns the currently selected item, or -1 if none is selected
|
||||
int getSelection();
|
||||
};
|
||||
|
||||
} // End of namespace Tony
|
||||
|
||||
#endif
|
||||
1609
engines/tony/game.cpp
Normal file
1609
engines/tony/game.cpp
Normal file
File diff suppressed because it is too large
Load Diff
339
engines/tony/game.h
Normal file
339
engines/tony/game.h
Normal file
@@ -0,0 +1,339 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on original Tony Tough source code
|
||||
*
|
||||
* Copyright (c) 1997-2003 Nayma Software
|
||||
*/
|
||||
|
||||
#ifndef TONY_GAME_H
|
||||
#define TONY_GAME_H
|
||||
|
||||
#include "tony/gfxcore.h"
|
||||
#include "tony/input.h"
|
||||
#include "tony/loc.h"
|
||||
#include "tony/utils.h"
|
||||
|
||||
namespace Tony {
|
||||
|
||||
#define INIT_GFX16_FROMRAW(dwRes, buf16) \
|
||||
raw = new RMResRaw(dwRes); \
|
||||
assert(raw->isValid()); \
|
||||
assert((buf16) == NULL); \
|
||||
(buf16) = new RMGfxSourceBuffer16(false); \
|
||||
(buf16)->init(*raw, raw->width(), raw->height()); \
|
||||
delete raw;
|
||||
|
||||
#define INIT_GFX8_FROMRAW(raw, dwRes, buf8) \
|
||||
raw = new RMResRaw(dwRes); \
|
||||
assert(raw->isValid()); \
|
||||
assert((buf8) == NULL); \
|
||||
(buf8) = new RMGfxSourceBuffer8RLEByte(); \
|
||||
(buf8)->init(*raw, raw->width(), raw->height(), true); \
|
||||
delete raw;
|
||||
|
||||
// X & Y dimensions of the adventure
|
||||
#define RM_SX 640
|
||||
#define RM_SY 480
|
||||
|
||||
// X & Y dimensions of bigbuf
|
||||
#define RM_BBX (RM_SX)
|
||||
#define RM_BBY (RM_SY)
|
||||
|
||||
// Skipping X & Y
|
||||
#define RM_SKIPY ((RM_BBY - RM_SY) / 2)
|
||||
#define RM_SKIPX 0
|
||||
|
||||
// Tony's actions
|
||||
enum RMTonyAction {
|
||||
TA_GOTO = 0,
|
||||
TA_TAKE,
|
||||
TA_USE,
|
||||
TA_EXAMINE,
|
||||
TA_TALK,
|
||||
TA_PERORATE,
|
||||
|
||||
TA_COMBINE = 10,
|
||||
TA_RECEIVECOMBINE,
|
||||
TA_COMBINEGIVE,
|
||||
TA_RECEIVECOMBINEGIVE
|
||||
};
|
||||
|
||||
// Global Functions
|
||||
void mainEnableGUI();
|
||||
void mainDisableGUI();
|
||||
|
||||
// Classes
|
||||
class RMPointer {
|
||||
public:
|
||||
enum PointerType {
|
||||
PTR_NONE = 0,
|
||||
PTR_ARROWUP,
|
||||
PTR_ARROWDOWN,
|
||||
PTR_ARROWLEFT,
|
||||
PTR_ARROWRIGHT,
|
||||
PTR_ARROWMAP,
|
||||
PTR_CUSTOM
|
||||
};
|
||||
|
||||
private:
|
||||
RMGfxSourceBuffer8 *_pointer[16];
|
||||
RMPoint _hotspot[16];
|
||||
RMPoint _cursorHotspot;
|
||||
|
||||
RMItem *_specialPointer[16];
|
||||
|
||||
int _nCurPointer;
|
||||
int _nCurSpecialPointer;
|
||||
|
||||
RMGfxSourceBuffer8 *_nCurCustomPointer;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructor & destructor
|
||||
*/
|
||||
RMPointer();
|
||||
virtual ~RMPointer();
|
||||
|
||||
/**
|
||||
* Initialization
|
||||
*/
|
||||
void init();
|
||||
|
||||
/**
|
||||
* Deinitialization
|
||||
*/
|
||||
void close();
|
||||
|
||||
/**
|
||||
* Process a frame
|
||||
*/
|
||||
void doFrame();
|
||||
|
||||
/**
|
||||
* draw method
|
||||
*/
|
||||
void draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim);
|
||||
|
||||
/**
|
||||
* Sets a new action as current
|
||||
*/
|
||||
void setAction(RMTonyAction action);
|
||||
|
||||
/**
|
||||
* Sets a new pointer
|
||||
*/
|
||||
void setSpecialPointer(PointerType ptr);
|
||||
|
||||
PointerType getSpecialPointer();
|
||||
|
||||
/**
|
||||
* Set the new custom pointer
|
||||
*/
|
||||
void setCustomPointer(RMGfxSourceBuffer8 *ptr);
|
||||
|
||||
/**
|
||||
* Return the current action to be applied according to the pointer
|
||||
*/
|
||||
int curAction();
|
||||
|
||||
/**
|
||||
* Update the cursor
|
||||
*/
|
||||
void updateCursor();
|
||||
|
||||
/**
|
||||
* Show the cursor
|
||||
*/
|
||||
void showCursor();
|
||||
|
||||
/**
|
||||
* Hide the cursor
|
||||
*/
|
||||
void hideCursor();
|
||||
};
|
||||
|
||||
class RMOptionButton: public RMGfxTaskSetPrior {
|
||||
public:
|
||||
RMRect _rect;
|
||||
RMGfxSourceBuffer16 *_buf;
|
||||
bool _bActive;
|
||||
bool _bHasGfx;
|
||||
bool _bDoubleState;
|
||||
|
||||
public:
|
||||
RMOptionButton(uint32 dwRes, RMPoint pt, bool bDoubleState = false);
|
||||
RMOptionButton(const RMRect &pt);
|
||||
~RMOptionButton() override;
|
||||
|
||||
bool doFrame(const RMPoint &mousePos, bool bLeftClick, bool bRightClick);
|
||||
void draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim) override;
|
||||
void addToList(RMGfxTargetBuffer &bigBuf);
|
||||
bool isActive();
|
||||
void setActiveState(bool bState);
|
||||
};
|
||||
|
||||
class RMOptionSlide : public RMGfxTaskSetPrior {
|
||||
private:
|
||||
RMOptionButton *_pushLeft;
|
||||
RMOptionButton *_pushRight;
|
||||
RMGfxSourceBuffer16 *_sliderCenter;
|
||||
RMGfxSourceBuffer16 *_sliderLeft;
|
||||
RMGfxSourceBuffer16 *_sliderRight;
|
||||
RMGfxSourceBuffer16 *_sliderSingle;
|
||||
int _nSlideSize;
|
||||
RMPoint _pos;
|
||||
int _nValue;
|
||||
int _nMax;
|
||||
int _nStep;
|
||||
|
||||
public:
|
||||
RMOptionSlide(const RMPoint &pt, int m_nRange = 100, int m_nStartValue = 0, int slideSize = 300);
|
||||
~RMOptionSlide() override;
|
||||
|
||||
bool doFrame(const RMPoint &mousePos, bool bLeftClick, bool bRightClick);
|
||||
void draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim) override;
|
||||
void addToList(RMGfxTargetBuffer &bigBuf);
|
||||
|
||||
int getValue();
|
||||
};
|
||||
|
||||
class RMOptionScreen : public RMGfxWoodyBuffer {
|
||||
private:
|
||||
RMGfxSourceBuffer16 *_menu;
|
||||
RMGfxSourceBuffer16 *_quitConfirm;
|
||||
RMGfxSourceBuffer16 *_hideLoadSave;
|
||||
RMOptionButton *_buttonQuitYes;
|
||||
RMOptionButton *_buttonQuitNo;
|
||||
RMOptionButton *_buttonExit;
|
||||
RMOptionButton *_buttonQuit;
|
||||
RMOptionButton *_buttonLoad;
|
||||
RMOptionButton *_buttonSave;
|
||||
RMOptionButton *_buttonGameMenu;
|
||||
RMOptionButton *_buttonGfxMenu;
|
||||
RMOptionButton *_buttonSoundMenu;
|
||||
RMGfxSourceBuffer8 *_saveEasy;
|
||||
RMGfxSourceBuffer8 *_saveHard;
|
||||
RMGfxSourceBuffer16 *_curThumb[6];
|
||||
Common::String _curThumbName[6];
|
||||
byte _curThumbDiff[6];
|
||||
RMOptionButton *_buttonSave_States[6];
|
||||
RMOptionButton *_buttonSave_ArrowLeft;
|
||||
RMOptionButton *_buttonSave_ArrowRight;
|
||||
RMOptionButton *_buttonGfx_Tips;
|
||||
|
||||
RMOptionButton *_buttonSound_DubbingOn;
|
||||
RMOptionButton *_buttonSound_MusicOn;
|
||||
RMOptionButton *_buttonSound_SFXOn;
|
||||
|
||||
RMOptionSlide *_slideTonySpeed;
|
||||
RMOptionSlide *_slideTextSpeed;
|
||||
|
||||
|
||||
int _statePos;
|
||||
bool _bEditSaveName;
|
||||
int _nEditPos;
|
||||
char _editName[256];
|
||||
|
||||
union {
|
||||
RMOptionButton *_buttonGame_Lock;
|
||||
RMOptionButton *_buttonGfx_Anni30;
|
||||
RMOptionSlide *_sliderSound_Music;
|
||||
};
|
||||
union {
|
||||
RMOptionButton *_buttonGame_TimerizedText;
|
||||
RMOptionButton *_buttonGfx_AntiAlias;
|
||||
RMOptionSlide *_sliderSound_SFX;
|
||||
};
|
||||
union {
|
||||
RMOptionButton *_buttonGame_Scrolling;
|
||||
RMOptionButton *_buttonGfx_Sottotitoli;
|
||||
RMOptionSlide *_sliderSound_Dubbing;
|
||||
};
|
||||
union {
|
||||
RMOptionButton *_buttonGame_InterUp;
|
||||
RMOptionButton *_buttonGfx_Trans;
|
||||
};
|
||||
|
||||
int _fadeStep;
|
||||
bool _bExit;
|
||||
bool _bQuitConfirm;
|
||||
int _fadeY;
|
||||
int _fadeTime;
|
||||
bool _bLoadMenuOnly;
|
||||
bool _bNoLoadSave;
|
||||
bool _bAlterGfx;
|
||||
|
||||
enum OptionScreenState {
|
||||
MENUGAME,
|
||||
MENUGFX,
|
||||
MENUSOUND,
|
||||
MENULOAD,
|
||||
MENUSAVE,
|
||||
MENUNONE
|
||||
};
|
||||
|
||||
OptionScreenState _nState;
|
||||
OptionScreenState _nLastState;
|
||||
|
||||
public:
|
||||
RMOptionScreen();
|
||||
~RMOptionScreen() override;
|
||||
|
||||
using RMGfxWoodyBuffer::init;
|
||||
void init(CORO_PARAM, RMGfxTargetBuffer &bigBuf, bool &result);
|
||||
void initLoadMenuOnly(CORO_PARAM, RMGfxTargetBuffer &bigBuf, bool bAlternateGfx, bool &result);
|
||||
void initSaveMenuOnly(CORO_PARAM, RMGfxTargetBuffer &bigBuf, bool bAlternateGfx, bool &result);
|
||||
void initNoLoadSave(CORO_PARAM, RMGfxTargetBuffer &bigBuf, bool &result);
|
||||
void reInit(RMGfxTargetBuffer &bigBuf);
|
||||
bool close();
|
||||
bool isClosing();
|
||||
|
||||
// Overloaded methods
|
||||
int priority() override;
|
||||
void draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim) override;
|
||||
void removeThis(CORO_PARAM, bool &result) override;
|
||||
|
||||
/**
|
||||
* Polling for the option screen
|
||||
*/
|
||||
void doFrame(CORO_PARAM, RMInput *m_input);
|
||||
|
||||
/**
|
||||
* Retrieves a savegame's thumbnail, description, and difficulty level
|
||||
*/
|
||||
static bool loadThumbnailFromSaveState(int numState, byte *lpDestBuf, Common::String &name, byte &diff);
|
||||
|
||||
protected:
|
||||
// Initialization and state change
|
||||
void initState(CORO_PARAM);
|
||||
void closeState();
|
||||
void changeState(CORO_PARAM, OptionScreenState newState);
|
||||
|
||||
// Repaint the options menu
|
||||
void refreshAll(CORO_PARAM);
|
||||
void refreshThumbnails();
|
||||
};
|
||||
|
||||
} // End of namespace Tony
|
||||
|
||||
#endif
|
||||
2152
engines/tony/gfxcore.cpp
Normal file
2152
engines/tony/gfxcore.cpp
Normal file
File diff suppressed because it is too large
Load Diff
502
engines/tony/gfxcore.h
Normal file
502
engines/tony/gfxcore.h
Normal file
@@ -0,0 +1,502 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on original Tony Tough source code
|
||||
*
|
||||
* Copyright (c) 1997-2003 Nayma Software
|
||||
*/
|
||||
|
||||
#ifndef TONY_GFXCORE_H
|
||||
#define TONY_GFXCORE_H
|
||||
|
||||
#include "common/system.h"
|
||||
#include "common/coroutines.h"
|
||||
#include "tony/utils.h"
|
||||
|
||||
namespace Tony {
|
||||
|
||||
/****************************************************************************\
|
||||
* Class prototype
|
||||
\****************************************************************************/
|
||||
|
||||
// Class Name Family Treee Abstract?
|
||||
class RMGfxTask; // Yes
|
||||
class RMGfxTaskSetPrior; // Task Yes
|
||||
class RMGfxBuffer; //
|
||||
class RMGfxSourceBuffer; // TaskP+[Buffer] Yes
|
||||
class RMGfxTargetBuffer; // [Buffer]
|
||||
class RMGfxSourceBufferPal; // Source Yes
|
||||
class RMGfxSourceBuffer4; // SourcePal
|
||||
class RMGfxSourceBuffer8; // SourcePal
|
||||
class RMGfxSourceBuffer16; // Source
|
||||
class RMGfxWoodyBuffer; // Source16+Target
|
||||
class RMGfxClearTask; // Task
|
||||
|
||||
/**
|
||||
* Graphics buffer
|
||||
*/
|
||||
class RMGfxBuffer {
|
||||
protected:
|
||||
int _dimx, _dimy;
|
||||
byte *_buf;
|
||||
byte *_origBuf;
|
||||
|
||||
public:
|
||||
RMGfxBuffer();
|
||||
RMGfxBuffer(int dimx, int dimy, int nBpp);
|
||||
virtual ~RMGfxBuffer();
|
||||
|
||||
// Attributes
|
||||
int getDimx();
|
||||
int getDimy();
|
||||
|
||||
// Creation
|
||||
void create(int dimx, int dimy, int nBpp);
|
||||
virtual void destroy();
|
||||
|
||||
// These are valid only if the buffer is locked
|
||||
operator byte *();
|
||||
operator void *();
|
||||
|
||||
// Getting the offset for a given Y position
|
||||
void offsetY(int nLines, int nBpp);
|
||||
};
|
||||
|
||||
/**
|
||||
* Graphics primitive
|
||||
*/
|
||||
class RMGfxPrimitive {
|
||||
public:
|
||||
RMGfxTask *_task;
|
||||
|
||||
protected:
|
||||
RMRect _src;
|
||||
RMRect _dst;
|
||||
|
||||
bool _bStretch;
|
||||
byte _bFlag;
|
||||
|
||||
public:
|
||||
RMGfxPrimitive();
|
||||
RMGfxPrimitive(RMGfxTask *task);
|
||||
RMGfxPrimitive(RMGfxTask *task, const RMRect &src, RMRect &dst);
|
||||
RMGfxPrimitive(RMGfxTask *task, const RMPoint &src, RMRect &dst);
|
||||
RMGfxPrimitive(RMGfxTask *task, const RMPoint &src, RMPoint &dst);
|
||||
RMGfxPrimitive(RMGfxTask *task, const RMRect &src, RMPoint &dst);
|
||||
RMGfxPrimitive(RMGfxTask *task, const RMRect &dst);
|
||||
RMGfxPrimitive(RMGfxTask *task, const RMPoint &dst);
|
||||
virtual ~RMGfxPrimitive();
|
||||
void setFlag(byte bFlag);
|
||||
void setTask(RMGfxTask *task);
|
||||
void setSrc(const RMRect &src);
|
||||
void setSrc(const RMPoint &src);
|
||||
void setDst(const RMRect &dst);
|
||||
void setDst(const RMPoint &dst);
|
||||
void setStretch(bool bStretch);
|
||||
bool haveDst();
|
||||
RMRect &getDst();
|
||||
bool haveSrc();
|
||||
RMRect &getSrc();
|
||||
|
||||
// Flags
|
||||
bool isFlipped();
|
||||
|
||||
// Duplicate
|
||||
virtual RMGfxPrimitive *duplicate();
|
||||
};
|
||||
|
||||
/**
|
||||
* Graphic drawing task
|
||||
*/
|
||||
class RMGfxTask {
|
||||
protected:
|
||||
int _nPrior;
|
||||
int _nInList;
|
||||
|
||||
public:
|
||||
// Standard constructor
|
||||
RMGfxTask();
|
||||
virtual ~RMGfxTask() { }
|
||||
|
||||
virtual int priority();
|
||||
virtual void draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim) = 0;
|
||||
virtual void removeThis(CORO_PARAM, bool &result);
|
||||
|
||||
// Registration
|
||||
virtual void Register();
|
||||
virtual void unregister();
|
||||
};
|
||||
|
||||
/**
|
||||
* Graphic drawing with priority
|
||||
*/
|
||||
class RMGfxTaskSetPrior : public RMGfxTask {
|
||||
public:
|
||||
~RMGfxTaskSetPrior() override { }
|
||||
void setPriority(int nPrior);
|
||||
};
|
||||
|
||||
/**
|
||||
* Task that cleans the destination buffer
|
||||
*/
|
||||
class RMGfxClearTask : public RMGfxTask {
|
||||
public:
|
||||
~RMGfxClearTask() override { }
|
||||
|
||||
int priority() override;
|
||||
void draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim) override;
|
||||
void removeThis(CORO_PARAM, bool &result) override;
|
||||
};
|
||||
|
||||
/**
|
||||
* Task that draws a colored box
|
||||
*/
|
||||
class RMGfxBox : public RMGfxTaskSetPrior {
|
||||
protected:
|
||||
uint16 _wFillColor;
|
||||
|
||||
public:
|
||||
~RMGfxBox() override { }
|
||||
|
||||
void setColor(byte r, byte g, byte b);
|
||||
void draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim) override;
|
||||
void removeThis(CORO_PARAM, bool &result) override;
|
||||
};
|
||||
|
||||
/**
|
||||
* Buffer source for the design, which is a task. This is an abstract base.
|
||||
*/
|
||||
class RMGfxSourceBuffer : public virtual RMGfxBuffer, public RMGfxTaskSetPrior {
|
||||
public:
|
||||
// Load the data for the surface
|
||||
virtual int init(uint32 resID, int dimx, int dimy, bool bLoadPalette = false);
|
||||
virtual int init(const byte *buf, int dimx, int dimy, bool bLoadPalette = false);
|
||||
virtual void init(Common::ReadStream &ds, int dimx, int dimy, bool bLoadPalette = false);
|
||||
|
||||
~RMGfxSourceBuffer() override;
|
||||
|
||||
protected:
|
||||
virtual void prepareImage();
|
||||
bool clip2D(int &x1, int &y1, int &u, int &v, int &width, int &height, bool bUseSrc, RMGfxTargetBuffer *buf);
|
||||
void offsetY(int nLines);
|
||||
|
||||
public:
|
||||
virtual int getBpp() = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* 16-bit color source
|
||||
*/
|
||||
class RMGfxSourceBuffer16 : public RMGfxSourceBuffer {
|
||||
public:
|
||||
void prepareImage() override;
|
||||
|
||||
protected:
|
||||
bool _bTrasp0;
|
||||
|
||||
public:
|
||||
RMGfxSourceBuffer16(bool bUseTrasp = false);
|
||||
RMGfxSourceBuffer16(int dimx, int dimy);
|
||||
~RMGfxSourceBuffer16() override;
|
||||
|
||||
// Initialization
|
||||
void create(int dimx, int dimy);
|
||||
|
||||
int getBpp() override;
|
||||
void draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim) override;
|
||||
};
|
||||
|
||||
/**
|
||||
* Buffer source with palette
|
||||
*/
|
||||
class RMGfxSourceBufferPal : public RMGfxSourceBuffer {
|
||||
protected:
|
||||
// The size of the palette is (1 << Bpp()) * 4
|
||||
byte _pal[256 * 3];
|
||||
uint16 _palFinal[256];
|
||||
|
||||
// Post process to prepare the palette for drawing
|
||||
virtual void preparePalette();
|
||||
|
||||
public:
|
||||
~RMGfxSourceBufferPal() override;
|
||||
|
||||
int init(const byte *buf, int dimx, int dimy, bool bLoadPalette = false) override;
|
||||
void init(Common::ReadStream &ds, int dimx, int dimy, bool bLoadPalette = false) override;
|
||||
|
||||
int loadPaletteWA(uint32 resID, bool bSwapped = false);
|
||||
int loadPaletteWA(const byte *buf, bool bSwapped = false);
|
||||
int loadPalette(uint32 resID);
|
||||
int loadPalette(const byte *buf);
|
||||
};
|
||||
|
||||
/**
|
||||
* Buffer source with a 256 color palette
|
||||
*/
|
||||
class RMGfxSourceBuffer8 : public RMGfxSourceBufferPal {
|
||||
protected:
|
||||
bool _bTrasp0;
|
||||
|
||||
public:
|
||||
RMGfxSourceBuffer8(bool bTrasp0 = true);
|
||||
RMGfxSourceBuffer8(int dimx, int dimy);
|
||||
~RMGfxSourceBuffer8() override;
|
||||
|
||||
// Initialization
|
||||
void create(int dimx, int dimy);
|
||||
|
||||
int getBpp() override;
|
||||
void draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim) override;
|
||||
};
|
||||
|
||||
/**
|
||||
* Buffer source with a 256 color palette, and alpha blending
|
||||
*/
|
||||
class RMGfxSourceBuffer8AB : public RMGfxSourceBuffer8 {
|
||||
protected:
|
||||
int calcTrasp(int f, int b);
|
||||
|
||||
public:
|
||||
~RMGfxSourceBuffer8AB() override;
|
||||
void draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim) override;
|
||||
};
|
||||
|
||||
/**
|
||||
* Buffer source with a 256 color palette, RLE compressed
|
||||
*/
|
||||
|
||||
class RMGfxSourceBuffer8RLE : public virtual RMGfxSourceBuffer8 {
|
||||
protected:
|
||||
int _alphaBlendColor;
|
||||
int _alphaR, _alphaB, _alphaG;
|
||||
bool _bNeedRLECompress;
|
||||
|
||||
protected:
|
||||
static byte _megaRLEBuf[];
|
||||
|
||||
virtual void rleWriteTrasp(byte *&cur, int rep) = 0;
|
||||
virtual void rleWriteData(byte *&cur, int rep, byte *src) = 0;
|
||||
virtual void rleWriteEOL(byte *&cur) = 0;
|
||||
virtual void rleWriteAlphaBlend(byte *&cur, int rep) = 0;
|
||||
virtual void rleDecompressLine(uint16 *dst, byte *src, int nStartSkip, int nLength) = 0;
|
||||
virtual void rleDecompressLineFlipped(uint16 *dst, byte *src, int nStartSkip, int nLength) = 0;
|
||||
|
||||
// Perform image compression in RLE
|
||||
void compressRLE();
|
||||
|
||||
protected:
|
||||
// Overriding initialization methods
|
||||
void prepareImage() override;
|
||||
void preparePalette() override;
|
||||
|
||||
public:
|
||||
RMGfxSourceBuffer8RLE();
|
||||
~RMGfxSourceBuffer8RLE() override;
|
||||
|
||||
// Overload of the initialization method
|
||||
void init(Common::ReadStream &ds, int dimx, int dimy, bool bLoadPalette = false) override;
|
||||
int init(const byte *buf, int dimx, int dimy, bool bLoadPalette = false) override;
|
||||
|
||||
// Draw image with RLE decompression
|
||||
void draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim) override;
|
||||
|
||||
// Sets the color that will be alpha blended
|
||||
void setAlphaBlendColor(int color);
|
||||
|
||||
// Warn if the data is already compressed
|
||||
void setAlreadyCompressed();
|
||||
};
|
||||
|
||||
class RMGfxSourceBuffer8RLEByte : public RMGfxSourceBuffer8RLE {
|
||||
protected:
|
||||
void rleWriteTrasp(byte * &cur, int rep) override;
|
||||
void rleWriteAlphaBlend(byte * &cur, int rep) override;
|
||||
void rleWriteData(byte * &cur, int rep, byte *src) override;
|
||||
void rleWriteEOL(byte * &cur) override;
|
||||
void rleDecompressLine(uint16 *dst, byte *src, int nStartSkip, int nLength) override;
|
||||
void rleDecompressLineFlipped(uint16 *dst, byte *src, int nStartSkip, int nLength) override;
|
||||
|
||||
public:
|
||||
~RMGfxSourceBuffer8RLEByte() override;
|
||||
};
|
||||
|
||||
class RMGfxSourceBuffer8RLEWord : public RMGfxSourceBuffer8RLE {
|
||||
protected:
|
||||
void rleWriteTrasp(byte * &cur, int rep) override;
|
||||
void rleWriteAlphaBlend(byte * &cur, int rep) override;
|
||||
void rleWriteData(byte * &cur, int rep, byte *src) override;
|
||||
void rleWriteEOL(byte * &cur) override;
|
||||
void rleDecompressLine(uint16 *dst, byte *src, int nStartSkip, int nLength) override;
|
||||
void rleDecompressLineFlipped(uint16 *dst, byte *src, int nStartSkip, int nLength) override;
|
||||
|
||||
public:
|
||||
~RMGfxSourceBuffer8RLEWord() override;
|
||||
};
|
||||
|
||||
class RMGfxSourceBuffer8RLEWordAB : public RMGfxSourceBuffer8RLEWord {
|
||||
protected:
|
||||
void rleDecompressLine(uint16 *dst, byte *src, int nStartSkip, int nLength) override;
|
||||
|
||||
public:
|
||||
~RMGfxSourceBuffer8RLEWordAB() override;
|
||||
};
|
||||
|
||||
/**
|
||||
* Buffer source with a 256 color palette, with anti-aliasing
|
||||
*/
|
||||
class RMGfxSourceBuffer8AA : public virtual RMGfxSourceBuffer8 {
|
||||
protected:
|
||||
static byte _megaAABuf[];
|
||||
static byte _megaAABuf2[];
|
||||
byte *_aabuf;
|
||||
|
||||
// Calculate the buffer for the anti-aliasing
|
||||
void calculateAA();
|
||||
|
||||
// Draw the AA
|
||||
void drawAA(RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim);
|
||||
|
||||
protected:
|
||||
void prepareImage() override;
|
||||
|
||||
public:
|
||||
RMGfxSourceBuffer8AA();
|
||||
~RMGfxSourceBuffer8AA() override;
|
||||
|
||||
// Draw with anti-aliasing
|
||||
void draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim) override;
|
||||
};
|
||||
|
||||
class RMGfxSourceBuffer8RLEByteAA : public RMGfxSourceBuffer8RLEByte, public RMGfxSourceBuffer8AA {
|
||||
protected:
|
||||
void prepareImage() override;
|
||||
|
||||
public:
|
||||
void draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim) override;
|
||||
|
||||
// Overloaded initialization methods
|
||||
void init(Common::ReadStream &ds, int dimx, int dimy, bool bLoadPalette = false) override;
|
||||
int init(const byte *buf, int dimx, int dimy, bool bLoadPalette = false) override;
|
||||
|
||||
~RMGfxSourceBuffer8RLEByteAA() override;
|
||||
};
|
||||
|
||||
class RMGfxSourceBuffer8RLEWordAA : public RMGfxSourceBuffer8RLEWord, public RMGfxSourceBuffer8AA {
|
||||
protected:
|
||||
void prepareImage() override;
|
||||
|
||||
public:
|
||||
void draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim) override;
|
||||
|
||||
// Overloaded initialization methods
|
||||
void init(Common::ReadStream &ds, int dimx, int dimy, bool bLoadPalette = false) override;
|
||||
int init(const byte *buf, int dimx, int dimy, bool bLoadPalette = false) override;
|
||||
|
||||
~RMGfxSourceBuffer8RLEWordAA() override;
|
||||
};
|
||||
|
||||
/**
|
||||
* Source buffer with 16 colors
|
||||
*/
|
||||
class RMGfxSourceBuffer4 : public RMGfxSourceBufferPal {
|
||||
public:
|
||||
RMGfxSourceBuffer4();
|
||||
RMGfxSourceBuffer4(int dimx, int dimy);
|
||||
|
||||
// Initialization
|
||||
void create(int dimx, int dimy);
|
||||
|
||||
int getBpp() override;
|
||||
void draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim) override;
|
||||
};
|
||||
|
||||
/**
|
||||
* Destination buffer which manages its own internal list of tasks
|
||||
*/
|
||||
class RMGfxTargetBuffer : public virtual RMGfxBuffer {
|
||||
private:
|
||||
struct OTList {
|
||||
RMGfxPrimitive *_prim;
|
||||
OTList *_next;
|
||||
|
||||
OTList();
|
||||
OTList(RMGfxPrimitive *pr) {
|
||||
_prim = pr;
|
||||
_next = NULL;
|
||||
}
|
||||
};
|
||||
|
||||
bool _trackDirtyRects;
|
||||
Common::List<Common::Rect> _currentDirtyRects, _previousDirtyRects, _dirtyRects;
|
||||
|
||||
void mergeDirtyRects();
|
||||
|
||||
private:
|
||||
//Common::Mutex csModifyingOT;
|
||||
|
||||
protected:
|
||||
OTList *_otlist;
|
||||
int _otSize;
|
||||
|
||||
public:
|
||||
RMGfxTargetBuffer();
|
||||
~RMGfxTargetBuffer() override;
|
||||
|
||||
static uint16 *_precalcTable;
|
||||
static void createBWPrecalcTable();
|
||||
static void freeBWPrecalcTable();
|
||||
|
||||
// management of the OT list
|
||||
void clearOT();
|
||||
void drawOT(CORO_PARAM);
|
||||
void addPrim(RMGfxPrimitive *prim); // The pointer must be delted
|
||||
|
||||
operator byte *();
|
||||
operator void *();
|
||||
operator uint16 *();
|
||||
|
||||
// Offseting buffer
|
||||
void offsetY(int nLines);
|
||||
|
||||
// Dirty rect methods
|
||||
void addDirtyRect(const Common::Rect &r);
|
||||
Common::List<Common::Rect> &getDirtyRects();
|
||||
void clearDirtyRects();
|
||||
void setTrackDirtyRects(bool v);
|
||||
bool getTrackDirtyRects() const;
|
||||
};
|
||||
|
||||
/**
|
||||
* Ring buffer, which is both source and by destination
|
||||
*/
|
||||
class RMGfxWoodyBuffer: public RMGfxSourceBuffer16, public RMGfxTargetBuffer {
|
||||
public:
|
||||
RMGfxWoodyBuffer();
|
||||
RMGfxWoodyBuffer(int dimx, int dimy);
|
||||
~RMGfxWoodyBuffer() override;
|
||||
|
||||
void draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim) override;
|
||||
};
|
||||
|
||||
} // End of namespace Tony
|
||||
|
||||
#endif
|
||||
839
engines/tony/gfxengine.cpp
Normal file
839
engines/tony/gfxengine.cpp
Normal file
@@ -0,0 +1,839 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on original Tony Tough source code
|
||||
*
|
||||
* Copyright (c) 1997-2003 Nayma Software
|
||||
*/
|
||||
|
||||
#include "common/savefile.h"
|
||||
#include "tony/mpal/lzo.h"
|
||||
#include "tony/mpal/mpalutils.h"
|
||||
#include "tony/custom.h"
|
||||
#include "tony/gfxengine.h"
|
||||
#include "tony/tony.h"
|
||||
|
||||
namespace Tony {
|
||||
|
||||
/****************************************************************************\
|
||||
* RMGfxEngine Methods
|
||||
\****************************************************************************/
|
||||
|
||||
void exitAllIdles(CORO_PARAM, const void *param) {
|
||||
CORO_BEGIN_CONTEXT;
|
||||
CORO_END_CONTEXT(_ctx);
|
||||
|
||||
int nCurLoc = *(const int *)param;
|
||||
|
||||
CORO_BEGIN_CODE(_ctx);
|
||||
|
||||
// Closes idle
|
||||
GLOBALS._bSkipSfxNoLoop = true;
|
||||
|
||||
CORO_INVOKE_2(mpalEndIdlePoll, nCurLoc, NULL);
|
||||
|
||||
GLOBALS._bIdleExited = true;
|
||||
GLOBALS._bSkipSfxNoLoop = false;
|
||||
|
||||
CORO_END_CODE;
|
||||
}
|
||||
|
||||
RMGfxEngine::RMGfxEngine() {
|
||||
// Create big buffer where the frame will be rendered
|
||||
_bigBuf.create(RM_BBX, RM_BBY, 16);
|
||||
_bigBuf.offsetY(RM_SKIPY);
|
||||
_bigBuf.setTrackDirtyRects(true);
|
||||
|
||||
_nCurLoc = 0;
|
||||
_curAction = TA_GOTO;
|
||||
_curActionObj = 0;
|
||||
_nWipeType = 0;
|
||||
_hWipeEvent = 0;
|
||||
_nWipeStep = 0;
|
||||
_bMustEnterMenu = false;
|
||||
_bWiping = false;
|
||||
_bGUIOption = false;
|
||||
_bGUIInterface = false;
|
||||
_bGUIInventory = false;
|
||||
_bAlwaysDrawMouse = false;
|
||||
_bOption = false;
|
||||
_bLocationLoaded = false;
|
||||
_bInput = false;
|
||||
}
|
||||
|
||||
RMGfxEngine::~RMGfxEngine() {
|
||||
// Close the buffer
|
||||
_bigBuf.destroy();
|
||||
}
|
||||
|
||||
void RMGfxEngine::openOptionScreen(CORO_PARAM, int type) {
|
||||
CORO_BEGIN_CONTEXT;
|
||||
bool bRes;
|
||||
CORO_END_CONTEXT(_ctx);
|
||||
|
||||
CORO_BEGIN_CODE(_ctx);
|
||||
|
||||
_ctx->bRes = false;
|
||||
|
||||
if (type == 0)
|
||||
CORO_INVOKE_2(_opt.init, _bigBuf, _ctx->bRes);
|
||||
else if (type == 1)
|
||||
CORO_INVOKE_3(_opt.initLoadMenuOnly, _bigBuf, true, _ctx->bRes);
|
||||
else if (type == 2)
|
||||
CORO_INVOKE_2(_opt.initNoLoadSave, _bigBuf, _ctx->bRes);
|
||||
else if (type == 3)
|
||||
CORO_INVOKE_3(_opt.initLoadMenuOnly, _bigBuf, false, _ctx->bRes);
|
||||
else if (type == 4)
|
||||
CORO_INVOKE_3(_opt.initSaveMenuOnly, _bigBuf, false, _ctx->bRes);
|
||||
|
||||
if (_ctx->bRes) {
|
||||
g_vm->pauseSound(true);
|
||||
|
||||
disableInput();
|
||||
_inv.endCombine();
|
||||
_curActionObj = 0;
|
||||
_curAction = TA_GOTO;
|
||||
_point.setAction(_curAction);
|
||||
_point.setSpecialPointer(RMPointer::PTR_NONE);
|
||||
_point.setCustomPointer(NULL);
|
||||
enableMouse();
|
||||
g_vm->grabThumbnail();
|
||||
|
||||
// Exists the IDLE to avoid premature death in loading
|
||||
_bMustEnterMenu = true;
|
||||
if (type == 1 || type == 2) {
|
||||
GLOBALS._bIdleExited = true;
|
||||
} else {
|
||||
CORO_INVOKE_0(_tony.stopNoAction);
|
||||
|
||||
GLOBALS._bIdleExited = false;
|
||||
|
||||
CoroScheduler.createProcess(exitAllIdles, &_nCurLoc, sizeof(int));
|
||||
}
|
||||
}
|
||||
|
||||
CORO_END_CODE;
|
||||
}
|
||||
|
||||
void RMGfxEngine::doFrame(CORO_PARAM, bool bDrawLocation) {
|
||||
CORO_BEGIN_CONTEXT;
|
||||
CORO_END_CONTEXT(_ctx);
|
||||
|
||||
CORO_BEGIN_CODE(_ctx);
|
||||
|
||||
// Poll of input devices
|
||||
_input.poll();
|
||||
|
||||
if (_bMustEnterMenu && GLOBALS._bIdleExited) {
|
||||
_bOption = true;
|
||||
_bMustEnterMenu = false;
|
||||
GLOBALS._bIdleExited = false;
|
||||
}
|
||||
|
||||
if (_bOption) {
|
||||
CORO_INVOKE_1(_opt.doFrame, &_input);
|
||||
_bOption = !_opt.isClosing();
|
||||
if (!_bOption) {
|
||||
disableMouse();
|
||||
enableInput();
|
||||
mpalStartIdlePoll(_nCurLoc);
|
||||
g_vm->pauseSound(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (bDrawLocation && _bLocationLoaded) {
|
||||
// Location and objects
|
||||
_loc.doFrame(&_bigBuf);
|
||||
|
||||
// Check the mouse input
|
||||
if (_bInput && !_tony.inAction()) {
|
||||
// If we are on the inventory, it is it who controls all input
|
||||
if (_inv.haveFocus(_input.mousePos()) && !_inter.active()) {
|
||||
// Left Click
|
||||
// **********
|
||||
if (_input.mouseLeftClicked()/* && m_itemName.IsItemSelected()*/) {
|
||||
// Left click activates the combine, if we are on an object
|
||||
if (_inv.leftClick(_input.mousePos(), _curActionObj)) {
|
||||
_curAction = TA_COMBINE;
|
||||
_point.setAction(_curAction);
|
||||
}
|
||||
} else
|
||||
|
||||
// Right Click
|
||||
// ***********
|
||||
if (_input.mouseRightClicked()) {
|
||||
if (_itemName.isItemSelected()) {
|
||||
_curActionObj = 0;
|
||||
_inv.rightClick(_input.mousePos());
|
||||
} else
|
||||
_inv.rightClick(_input.mousePos());
|
||||
} else
|
||||
|
||||
// Right Release
|
||||
// *************
|
||||
if (_input.mouseRightReleased()) {
|
||||
if (_inv.rightRelease(_input.mousePos(), _curAction)) {
|
||||
CORO_INVOKE_3(_tony.moveAndDoAction, _itemName.getHotspot(), _itemName.getSelectedItem(), _curAction);
|
||||
|
||||
_curAction = TA_GOTO;
|
||||
_point.setAction(_curAction);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Options Menu
|
||||
// ************
|
||||
if (_bGUIOption) {
|
||||
if (!_tony.inAction() && _bInput) {
|
||||
if ((_input.mouseLeftClicked() && _input.mousePos()._x < 3 && _input.mousePos()._y < 3)) {
|
||||
CORO_INVOKE_1(openOptionScreen, 0);
|
||||
goto SKIPCLICKSINISTRO;
|
||||
} else if (_input.getAsyncKeyState(Common::KEYCODE_ESCAPE))
|
||||
CORO_INVOKE_1(openOptionScreen, 0);
|
||||
else if (!g_vm->getIsDemo()) {
|
||||
if (_input.getAsyncKeyState(Common::KEYCODE_F3) || _input.getAsyncKeyState(Common::KEYCODE_F5))
|
||||
// Save game screen
|
||||
CORO_INVOKE_1(openOptionScreen, 4);
|
||||
else if (_input.getAsyncKeyState(Common::KEYCODE_F2) || _input.getAsyncKeyState(Common::KEYCODE_F7))
|
||||
// Load game screen
|
||||
CORO_INVOKE_1(openOptionScreen, 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Left Click
|
||||
// **************
|
||||
if (_input.mouseLeftClicked() && !_inter.active()) {
|
||||
|
||||
if (_curAction != TA_COMBINE)
|
||||
CORO_INVOKE_3(_tony.moveAndDoAction, _itemName.getHotspot(), _itemName.getSelectedItem(), _point.curAction());
|
||||
else if (_itemName.getSelectedItem() != NULL)
|
||||
CORO_INVOKE_4(_tony.moveAndDoAction, _itemName.getHotspot(), _itemName.getSelectedItem(), TA_COMBINE, _curActionObj);
|
||||
|
||||
if (_curAction == TA_COMBINE) {
|
||||
_inv.endCombine();
|
||||
_point.setSpecialPointer(RMPointer::PTR_NONE);
|
||||
}
|
||||
|
||||
_curAction = TA_GOTO;
|
||||
_point.setAction(_curAction);
|
||||
}
|
||||
|
||||
SKIPCLICKSINISTRO:
|
||||
// Right Click
|
||||
// ************
|
||||
if (_curAction == TA_COMBINE) {
|
||||
// During a combine, it cancels it
|
||||
if (_input.mouseRightClicked()) {
|
||||
_inv.endCombine();
|
||||
_curActionObj = 0;
|
||||
_curAction = TA_GOTO;
|
||||
_point.setAction(_curAction);
|
||||
_point.setSpecialPointer(RMPointer::PTR_NONE);
|
||||
}
|
||||
} else if (_input.mouseRightClicked() && _itemName.isItemSelected() && _point.getSpecialPointer() == RMPointer::PTR_NONE) {
|
||||
if (_bGUIInterface) {
|
||||
// Before opening the interface, replaces GOTO
|
||||
_curAction = TA_GOTO;
|
||||
_curActionObj = 0;
|
||||
_point.setAction(_curAction);
|
||||
_inter.clicked(_input.mousePos());
|
||||
}
|
||||
}
|
||||
|
||||
// Right Release
|
||||
// *************
|
||||
if (_input.mouseRightReleased()) {
|
||||
if (_bGUIInterface) {
|
||||
if (_inter.released(_input.mousePos(), _curAction)) {
|
||||
_point.setAction(_curAction);
|
||||
CORO_INVOKE_3(_tony.moveAndDoAction, _itemName.getHotspot(), _itemName.getSelectedItem(), _curAction);
|
||||
|
||||
_curAction = TA_GOTO;
|
||||
_point.setAction(_curAction);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update the name under the mouse pointer
|
||||
_itemName.setMouseCoord(_input.mousePos());
|
||||
if (!_inter.active() && !_inv.miniActive())
|
||||
CORO_INVOKE_4(_itemName.doFrame, _bigBuf, _loc, _point, _inv);
|
||||
}
|
||||
|
||||
// Interface & Inventory
|
||||
_inter.doFrame(_bigBuf, _input.mousePos());
|
||||
_inv.doFrame(_bigBuf, _point, _input.mousePos(), (!_tony.inAction() && !_inter.active() && _bGUIInventory));
|
||||
}
|
||||
|
||||
// Animate Tony
|
||||
CORO_INVOKE_2(_tony.doFrame, &_bigBuf, _nCurLoc);
|
||||
|
||||
// Update screen scrolling to keep Tony in focus
|
||||
if (_tony.mustUpdateScrolling() && _bLocationLoaded) {
|
||||
RMPoint showThis = _tony.position();
|
||||
showThis._y -= 60;
|
||||
_loc.updateScrolling(showThis);
|
||||
}
|
||||
|
||||
if (_bLocationLoaded)
|
||||
_tony.setScrollPosition(_loc.scrollPosition());
|
||||
|
||||
if ((!_tony.inAction() && _bInput) || _bAlwaysDrawMouse) {
|
||||
_point.showCursor();
|
||||
} else {
|
||||
_point.hideCursor();
|
||||
}
|
||||
_point.doFrame();
|
||||
|
||||
// **********************
|
||||
// Draw the list in the OT
|
||||
// **********************
|
||||
CORO_INVOKE_0(_bigBuf.drawOT);
|
||||
|
||||
#define FSTEP (480/32)
|
||||
|
||||
// Wipe
|
||||
if (_bWiping) {
|
||||
switch (_nWipeType) {
|
||||
case 1:
|
||||
if (!(_rcWipeEllipse.bottom - _rcWipeEllipse.top >= FSTEP * 2)) {
|
||||
CoroScheduler.setEvent(_hWipeEvent);
|
||||
_nWipeType = 3;
|
||||
break;
|
||||
}
|
||||
|
||||
_rcWipeEllipse.top += FSTEP;
|
||||
_rcWipeEllipse.left += FSTEP;
|
||||
_rcWipeEllipse.right -= FSTEP;
|
||||
_rcWipeEllipse.bottom -= FSTEP;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
if (!(_rcWipeEllipse.bottom - _rcWipeEllipse.top < 480 - FSTEP)) {
|
||||
CoroScheduler.setEvent(_hWipeEvent);
|
||||
_nWipeType = 3;
|
||||
break;
|
||||
}
|
||||
|
||||
_rcWipeEllipse.top -= FSTEP;
|
||||
_rcWipeEllipse.left -= FSTEP;
|
||||
_rcWipeEllipse.right += FSTEP;
|
||||
_rcWipeEllipse.bottom += FSTEP;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
CORO_END_CODE;
|
||||
}
|
||||
|
||||
void RMGfxEngine::initCustomDll() {
|
||||
setupGlobalVars(&_tony, &_point, &g_vm->_theBoxes, &_loc, &_inv, &_input);
|
||||
}
|
||||
|
||||
void RMGfxEngine::itemIrq(uint32 dwItem, int nPattern, int nStatus) {
|
||||
assert(GLOBALS._gfxEngine);
|
||||
|
||||
if (GLOBALS._gfxEngine->_bLocationLoaded) {
|
||||
RMItem *item = GLOBALS._gfxEngine->_loc.getItemFromCode(dwItem);
|
||||
if (item != NULL) {
|
||||
if (nPattern != -1) {
|
||||
item->setPattern(nPattern, true);
|
||||
}
|
||||
if (nStatus != -1)
|
||||
item->setStatus(nStatus);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RMGfxEngine::initForNewLocation(int nLoc, RMPoint ptTonyStart, RMPoint start) {
|
||||
if (start._x == -1 || start._y == -1) {
|
||||
start._x = ptTonyStart._x - RM_SX / 2;
|
||||
start._y = ptTonyStart._y - RM_SY / 2;
|
||||
}
|
||||
|
||||
_loc.setScrollPosition(start);
|
||||
|
||||
if (ptTonyStart._x == 0 && ptTonyStart._y == 0) {
|
||||
} else {
|
||||
_tony.setPosition(ptTonyStart, nLoc);
|
||||
_tony.setScrollPosition(start);
|
||||
}
|
||||
|
||||
_curAction = TA_GOTO;
|
||||
_point.setCustomPointer(NULL);
|
||||
_point.setSpecialPointer(RMPointer::PTR_NONE);
|
||||
_point.setAction(_curAction);
|
||||
_inter.reset();
|
||||
_inv.reset();
|
||||
|
||||
mpalStartIdlePoll(_nCurLoc);
|
||||
}
|
||||
|
||||
uint32 RMGfxEngine::loadLocation(int nLoc, RMPoint ptTonyStart, RMPoint start) {
|
||||
_nCurLoc = nLoc;
|
||||
|
||||
bool bLoaded = false;
|
||||
for (int i = 0; i < 5; i++) {
|
||||
// Try the loading of the location
|
||||
RMRes res(_nCurLoc);
|
||||
if (!res.isValid())
|
||||
continue;
|
||||
|
||||
Common::SeekableReadStream *ds = res.getReadStream();
|
||||
_loc.load(*ds);
|
||||
delete ds;
|
||||
|
||||
initForNewLocation(nLoc, ptTonyStart, start);
|
||||
bLoaded = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!bLoaded)
|
||||
error("Location was not loaded");
|
||||
|
||||
if (_bOption)
|
||||
_opt.reInit(_bigBuf);
|
||||
|
||||
_bLocationLoaded = true;
|
||||
|
||||
// On entering the location
|
||||
return CORO_INVALID_PID_VALUE; //mpalQueryDoAction(0, m_nCurLoc, 0);
|
||||
}
|
||||
|
||||
void RMGfxEngine::unloadLocation(CORO_PARAM, bool bDoOnExit, uint32 *result) {
|
||||
CORO_BEGIN_CONTEXT;
|
||||
uint32 h;
|
||||
CORO_END_CONTEXT(_ctx);
|
||||
|
||||
CORO_BEGIN_CODE(_ctx);
|
||||
|
||||
// Release the location
|
||||
CORO_INVOKE_2(mpalEndIdlePoll, _nCurLoc, NULL);
|
||||
|
||||
// On Exit?
|
||||
if (bDoOnExit) {
|
||||
_ctx->h = mpalQueryDoAction(1, _nCurLoc, 0);
|
||||
if (_ctx->h != CORO_INVALID_PID_VALUE)
|
||||
CORO_INVOKE_2(CoroScheduler.waitForSingleObject, _ctx->h, CORO_INFINITE);
|
||||
}
|
||||
|
||||
_bLocationLoaded = false;
|
||||
|
||||
_bigBuf.clearOT();
|
||||
_loc.unload();
|
||||
|
||||
if (result != NULL)
|
||||
*result = CORO_INVALID_PID_VALUE;
|
||||
|
||||
CORO_END_CODE;
|
||||
}
|
||||
|
||||
void RMGfxEngine::init() {
|
||||
// Screen loading
|
||||
RMGfxSourceBuffer16 *load = NULL;
|
||||
RMResRaw *raw;
|
||||
INIT_GFX16_FROMRAW(20038, load);
|
||||
_bigBuf.addPrim(new RMGfxPrimitive(load));
|
||||
_bigBuf.drawOT(Common::nullContext);
|
||||
_bigBuf.clearOT();
|
||||
delete load;
|
||||
|
||||
// Display 'Loading' screen
|
||||
_bigBuf.addDirtyRect(Common::Rect(0, 0, RM_SX, RM_SY));
|
||||
g_vm->_window.getNewFrame(*this, NULL);
|
||||
g_vm->_window.repaint();
|
||||
|
||||
// Activate GUI
|
||||
_bGUIOption = true;
|
||||
_bGUIInterface = true;
|
||||
_bGUIInventory = true;
|
||||
|
||||
GLOBALS._bSkipSfxNoLoop = false;
|
||||
_bMustEnterMenu = false;
|
||||
GLOBALS._bIdleExited = false;
|
||||
_bOption = false;
|
||||
_bWiping = false;
|
||||
_hWipeEvent = CoroScheduler.createEvent(false, false);
|
||||
|
||||
// Initialize the IRQ function for items for MPAL
|
||||
GLOBALS._gfxEngine = this;
|
||||
mpalInstallItemIrq(itemIrq);
|
||||
|
||||
// Initialize the mouse pointer
|
||||
_point.init();
|
||||
|
||||
// Initialize Tony
|
||||
_tony.init();
|
||||
_tony.linkToBoxes(&g_vm->_theBoxes);
|
||||
|
||||
// Initialize the inventory and the interface
|
||||
_inv.init();
|
||||
_inter.init();
|
||||
|
||||
// Download the location and set priorities @@@@@
|
||||
_bLocationLoaded = false;
|
||||
|
||||
enableInput();
|
||||
|
||||
// Starting the game
|
||||
_tony.executeAction(20, 1, 0);
|
||||
}
|
||||
|
||||
void RMGfxEngine::close() {
|
||||
_bigBuf.clearOT();
|
||||
|
||||
_inter.close();
|
||||
_inv.close();
|
||||
_tony.close();
|
||||
_point.close();
|
||||
}
|
||||
|
||||
void RMGfxEngine::enableInput() {
|
||||
_bInput = true;
|
||||
}
|
||||
|
||||
void RMGfxEngine::disableInput() {
|
||||
_bInput = false;
|
||||
_inter.reset();
|
||||
}
|
||||
|
||||
void RMGfxEngine::enableMouse() {
|
||||
_bAlwaysDrawMouse = true;
|
||||
}
|
||||
|
||||
void RMGfxEngine::disableMouse() {
|
||||
_bAlwaysDrawMouse = false;
|
||||
}
|
||||
|
||||
#define TONY_SAVEGAME_VERSION 8
|
||||
|
||||
void RMGfxEngine::saveState(const Common::String &fn, byte *curThumb, const Common::String &name) {
|
||||
Common::OutSaveFile *f = g_system->getSavefileManager()->openForSaving(fn);
|
||||
if (f == NULL)
|
||||
return;
|
||||
|
||||
byte *state;
|
||||
char buf[4];
|
||||
RMPoint tp = _tony.position();
|
||||
|
||||
// Saving: MPAL variables, current location, and Tony inventory position
|
||||
|
||||
// For now, we only save the MPAL state
|
||||
uint size = mpalGetSaveStateSize();
|
||||
state = new byte[size];
|
||||
mpalSaveState(state);
|
||||
|
||||
uint thumbsize = 160 * 120 * 2;
|
||||
|
||||
buf[0] = 'R';
|
||||
buf[1] = 'M';
|
||||
buf[2] = 'S';
|
||||
buf[3] = TONY_SAVEGAME_VERSION;
|
||||
|
||||
f->write(buf, 4);
|
||||
f->writeUint32LE(thumbsize);
|
||||
f->write(curThumb, thumbsize);
|
||||
|
||||
// Difficulty level
|
||||
int i = mpalQueryGlobalVar("VERSIONEFACILE");
|
||||
f->writeByte(i);
|
||||
|
||||
i = strlen(name.c_str());
|
||||
f->writeByte(i);
|
||||
f->write(name.c_str(), i);
|
||||
f->writeUint32LE(_nCurLoc);
|
||||
f->writeUint32LE(tp._x);
|
||||
f->writeUint32LE(tp._y);
|
||||
|
||||
f->writeUint32LE(size);
|
||||
f->write(state, size);
|
||||
delete[] state;
|
||||
|
||||
// Inventory
|
||||
size = _inv.getSaveStateSize();
|
||||
state = new byte[size];
|
||||
_inv.saveState(state);
|
||||
f->writeUint32LE(size);
|
||||
f->write(state, size);
|
||||
delete[] state;
|
||||
|
||||
// boxes
|
||||
size = g_vm->_theBoxes.getSaveStateSize();
|
||||
state = new byte[size];
|
||||
g_vm->_theBoxes.saveState(state);
|
||||
f->writeUint32LE(size);
|
||||
f->write(state, size);
|
||||
delete[] state;
|
||||
|
||||
// New Ver5
|
||||
// Saves the state of the shepherdess and show yourself
|
||||
bool bStat = _tony.getShepherdess();
|
||||
f->writeByte(bStat);
|
||||
bStat = _inter.getPerorate();
|
||||
f->writeByte(bStat);
|
||||
|
||||
// Save the chars
|
||||
charsSaveAll(f);
|
||||
|
||||
// Save the options
|
||||
f->writeByte(GLOBALS._bCfgInvLocked);
|
||||
f->writeByte(GLOBALS._bCfgInvNoScroll);
|
||||
f->writeByte(GLOBALS._bCfgTimerizedText);
|
||||
f->writeByte(GLOBALS._bCfgInvUp);
|
||||
f->writeByte(GLOBALS._bCfgAnni30);
|
||||
f->writeByte(GLOBALS._bCfgAntiAlias);
|
||||
f->writeByte(GLOBALS._bShowSubtitles);
|
||||
f->writeByte(GLOBALS._bCfgTransparence);
|
||||
f->writeByte(GLOBALS._bCfgInterTips);
|
||||
f->writeByte(GLOBALS._bCfgDubbing);
|
||||
f->writeByte(GLOBALS._bCfgMusic);
|
||||
f->writeByte(GLOBALS._bCfgSFX);
|
||||
f->writeByte(GLOBALS._nCfgTonySpeed);
|
||||
f->writeByte(GLOBALS._nCfgTextSpeed);
|
||||
f->writeByte(GLOBALS._nCfgDubbingVolume);
|
||||
f->writeByte(GLOBALS._nCfgMusicVolume);
|
||||
f->writeByte(GLOBALS._nCfgSFXVolume);
|
||||
|
||||
// Save the hotspots
|
||||
saveChangedHotspot(f);
|
||||
|
||||
// Save the music
|
||||
saveMusic(f);
|
||||
|
||||
f->finalize();
|
||||
delete f;
|
||||
}
|
||||
|
||||
void RMGfxEngine::loadState(CORO_PARAM, const Common::String &fn) {
|
||||
// PROBLEM: You should change the location in a separate process to do the OnEnter
|
||||
CORO_BEGIN_CONTEXT;
|
||||
Common::InSaveFile *f;
|
||||
byte *state, *statecmp;
|
||||
uint32 size, sizecmp;
|
||||
char buf[4];
|
||||
RMPoint tp;
|
||||
int loc;
|
||||
int ver;
|
||||
int i;
|
||||
CORO_END_CONTEXT(_ctx);
|
||||
|
||||
CORO_BEGIN_CODE(_ctx);
|
||||
|
||||
_ctx->f = g_system->getSavefileManager()->openForLoading(fn);
|
||||
if (_ctx->f == NULL)
|
||||
return;
|
||||
_ctx->f->read(_ctx->buf, 4);
|
||||
|
||||
if (_ctx->buf[0] != 'R' || _ctx->buf[1] != 'M' || _ctx->buf[2] != 'S') {
|
||||
delete _ctx->f;
|
||||
return;
|
||||
}
|
||||
|
||||
_ctx->ver = _ctx->buf[3];
|
||||
|
||||
if (_ctx->ver == 0 || _ctx->ver > TONY_SAVEGAME_VERSION) {
|
||||
delete _ctx->f;
|
||||
return;
|
||||
}
|
||||
|
||||
if (_ctx->ver >= 0x3) {
|
||||
// There is a thumbnail. If the version is between 5 and 7, it's compressed
|
||||
if ((_ctx->ver >= 0x5) && (_ctx->ver <= 0x7)) {
|
||||
_ctx->i = 0;
|
||||
_ctx->i = _ctx->f->readUint32LE();
|
||||
_ctx->f->seek(_ctx->i);
|
||||
} else {
|
||||
if (_ctx->ver >= 8)
|
||||
// Skip thumbnail size
|
||||
_ctx->f->skip(4);
|
||||
|
||||
_ctx->f->seek(160 * 120 * 2, SEEK_CUR);
|
||||
}
|
||||
}
|
||||
|
||||
if (_ctx->ver >= 0x5) {
|
||||
// Skip the difficulty level
|
||||
_ctx->f->seek(1, SEEK_CUR);
|
||||
}
|
||||
|
||||
if (_ctx->ver >= 0x4) { // Skip the savegame name, which serves no purpose
|
||||
_ctx->i = _ctx->f->readByte();
|
||||
_ctx->f->seek(_ctx->i, SEEK_CUR);
|
||||
}
|
||||
|
||||
_ctx->loc = _ctx->f->readUint32LE();
|
||||
_ctx->tp._x = _ctx->f->readUint32LE();
|
||||
_ctx->tp._y = _ctx->f->readUint32LE();
|
||||
_ctx->size = _ctx->f->readUint32LE();
|
||||
|
||||
if ((_ctx->ver >= 0x5) && (_ctx->ver <= 7)) {
|
||||
// MPAL was packed!
|
||||
_ctx->sizecmp = _ctx->f->readUint32LE();
|
||||
_ctx->state = new byte[_ctx->size];
|
||||
_ctx->statecmp = new byte[_ctx->sizecmp];
|
||||
_ctx->f->read(_ctx->statecmp, _ctx->sizecmp);
|
||||
lzo1x_decompress(_ctx->statecmp, _ctx->sizecmp, _ctx->state, &_ctx->size);
|
||||
delete[] _ctx->statecmp;
|
||||
} else {
|
||||
// Read uncompressed MPAL data
|
||||
_ctx->state = new byte[_ctx->size];
|
||||
_ctx->f->read(_ctx->state, _ctx->size);
|
||||
}
|
||||
|
||||
mpalLoadState(_ctx->state);
|
||||
delete[] _ctx->state;
|
||||
|
||||
// Inventory
|
||||
_ctx->size = _ctx->f->readUint32LE();
|
||||
_ctx->state = new byte[_ctx->size];
|
||||
_ctx->f->read(_ctx->state, _ctx->size);
|
||||
_inv.loadState(_ctx->state);
|
||||
delete[] _ctx->state;
|
||||
|
||||
if (_ctx->ver >= 0x2) { // Version 2: box please
|
||||
_ctx->size = _ctx->f->readUint32LE();
|
||||
_ctx->state = new byte[_ctx->size];
|
||||
_ctx->f->read(_ctx->state, _ctx->size);
|
||||
g_vm->_theBoxes.loadState(_ctx->state);
|
||||
delete[] _ctx->state;
|
||||
}
|
||||
|
||||
if (_ctx->ver >= 5) {
|
||||
// Version 5
|
||||
bool bStat = _ctx->f->readByte();
|
||||
_tony.setShepherdess(bStat);
|
||||
bStat = _ctx->f->readByte();
|
||||
_inter.setPerorate(bStat);
|
||||
|
||||
charsLoadAll(_ctx->f);
|
||||
}
|
||||
|
||||
if (_ctx->ver >= 6) {
|
||||
// Load options
|
||||
GLOBALS._bCfgInvLocked = _ctx->f->readByte();
|
||||
GLOBALS._bCfgInvNoScroll = _ctx->f->readByte();
|
||||
GLOBALS._bCfgTimerizedText = _ctx->f->readByte();
|
||||
GLOBALS._bCfgInvUp = _ctx->f->readByte();
|
||||
GLOBALS._bCfgAnni30 = _ctx->f->readByte();
|
||||
GLOBALS._bCfgAntiAlias = _ctx->f->readByte();
|
||||
GLOBALS._bShowSubtitles = _ctx->f->readByte();
|
||||
GLOBALS._bCfgTransparence = _ctx->f->readByte();
|
||||
GLOBALS._bCfgInterTips = _ctx->f->readByte();
|
||||
GLOBALS._bCfgDubbing = _ctx->f->readByte();
|
||||
GLOBALS._bCfgMusic = _ctx->f->readByte();
|
||||
GLOBALS._bCfgSFX = _ctx->f->readByte();
|
||||
GLOBALS._nCfgTonySpeed = _ctx->f->readByte();
|
||||
GLOBALS._nCfgTextSpeed = _ctx->f->readByte();
|
||||
GLOBALS._nCfgDubbingVolume = _ctx->f->readByte();
|
||||
GLOBALS._nCfgMusicVolume = _ctx->f->readByte();
|
||||
GLOBALS._nCfgSFXVolume = _ctx->f->readByte();
|
||||
|
||||
// Load hotspots
|
||||
loadChangedHotspot(_ctx->f);
|
||||
}
|
||||
|
||||
if (_ctx->ver >= 7) {
|
||||
loadMusic(_ctx->f);
|
||||
}
|
||||
|
||||
delete _ctx->f;
|
||||
|
||||
CORO_INVOKE_2(unloadLocation, false, NULL);
|
||||
loadLocation(_ctx->loc, _ctx->tp, RMPoint(-1, -1));
|
||||
_tony.setPattern(RMTony::PAT_STANDRIGHT);
|
||||
|
||||
// On older versions, need to an enter action
|
||||
if (_ctx->ver < 5)
|
||||
mpalQueryDoAction(0, _ctx->loc, 0);
|
||||
else {
|
||||
// In the new ones, we just reset the mcode
|
||||
mCharResetCodes();
|
||||
}
|
||||
|
||||
if (_ctx->ver >= 6)
|
||||
reapplyChangedHotspot();
|
||||
|
||||
CORO_INVOKE_0(restoreMusic);
|
||||
|
||||
_bGUIInterface = true;
|
||||
_bGUIInventory = true;
|
||||
_bGUIOption = true;
|
||||
|
||||
CORO_END_CODE;
|
||||
}
|
||||
|
||||
void RMGfxEngine::pauseSound(bool bPause) {
|
||||
if (_bLocationLoaded)
|
||||
_loc.pauseSound(bPause);
|
||||
}
|
||||
|
||||
void RMGfxEngine::initWipe(int type) {
|
||||
_bWiping = true;
|
||||
_nWipeType = type;
|
||||
_nWipeStep = 0;
|
||||
|
||||
if (_nWipeType == 1)
|
||||
_rcWipeEllipse = Common::Rect(80, 0, 640 - 80, 480);
|
||||
else if (_nWipeType == 2)
|
||||
_rcWipeEllipse = Common::Rect(320 - FSTEP, 240 - FSTEP, 320 + FSTEP, 240 + FSTEP);
|
||||
}
|
||||
|
||||
void RMGfxEngine::closeWipe() {
|
||||
_bWiping = false;
|
||||
}
|
||||
|
||||
void RMGfxEngine::waitWipeEnd(CORO_PARAM) {
|
||||
CoroScheduler.waitForSingleObject(coroParam, _hWipeEvent, CORO_INFINITE);
|
||||
}
|
||||
|
||||
bool RMGfxEngine::canLoadSave() {
|
||||
return _bInput && !_tony.inAction() && !g_vm->getIsDemo();
|
||||
}
|
||||
|
||||
RMGfxEngine::operator RMGfxTargetBuffer &() {
|
||||
return _bigBuf;
|
||||
}
|
||||
|
||||
RMInput &RMGfxEngine::getInput() {
|
||||
return _input;
|
||||
}
|
||||
|
||||
RMPointer &RMGfxEngine::getPointer() {
|
||||
return _point;
|
||||
}
|
||||
|
||||
/**
|
||||
* Link to graphic task
|
||||
*/
|
||||
void RMGfxEngine::linkGraphicTask(RMGfxTask *task) {
|
||||
_bigBuf.addPrim(new RMGfxPrimitive(task));
|
||||
}
|
||||
|
||||
void RMGfxEngine::setPerorate(bool bpal) {
|
||||
_inter.setPerorate(bpal);
|
||||
}
|
||||
|
||||
} // End of namespace Tony
|
||||
138
engines/tony/gfxengine.h
Normal file
138
engines/tony/gfxengine.h
Normal file
@@ -0,0 +1,138 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on original Tony Tough source code
|
||||
*
|
||||
* Copyright (c) 1997-2003 Nayma Software
|
||||
*/
|
||||
|
||||
#ifndef TONY_GFXENGINE_H
|
||||
#define TONY_GFXENGINE_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "common/system.h"
|
||||
#include "common/rect.h"
|
||||
#include "tony/mpal/memory.h"
|
||||
#include "tony/game.h"
|
||||
#include "tony/gfxcore.h"
|
||||
#include "tony/input.h"
|
||||
#include "tony/inventory.h"
|
||||
#include "tony/tonychar.h"
|
||||
#include "tony/utils.h"
|
||||
|
||||
namespace Tony {
|
||||
|
||||
class RMGfxEngine {
|
||||
private:
|
||||
RMGfxTargetBuffer _bigBuf;
|
||||
RMInput _input;
|
||||
RMPointer _point;
|
||||
RMLocation _loc;
|
||||
RMOptionScreen _opt;
|
||||
RMTony _tony;
|
||||
RMInventory _inv;
|
||||
RMInterface _inter;
|
||||
RMTextItemName _itemName;
|
||||
|
||||
bool _bOption;
|
||||
bool _bLocationLoaded;
|
||||
|
||||
bool _bInput;
|
||||
bool _bAlwaysDrawMouse;
|
||||
|
||||
int _nCurLoc;
|
||||
RMTonyAction _curAction;
|
||||
int _curActionObj;
|
||||
|
||||
int _nWipeType;
|
||||
uint32 _hWipeEvent;
|
||||
int _nWipeStep;
|
||||
|
||||
bool _bMustEnterMenu;
|
||||
protected:
|
||||
static void itemIrq(uint32 dwItem, int nPattern, int nStatus);
|
||||
void initForNewLocation(int nLoc, RMPoint ptTonyStart, RMPoint start);
|
||||
public:
|
||||
bool _bWiping;
|
||||
Common::Rect _rcWipeEllipse;
|
||||
bool _bGUIOption;
|
||||
bool _bGUIInterface;
|
||||
bool _bGUIInventory;
|
||||
public:
|
||||
RMGfxEngine();
|
||||
virtual ~RMGfxEngine();
|
||||
|
||||
// Draw the next frame
|
||||
void doFrame(CORO_PARAM, bool bDrawLocation);
|
||||
|
||||
// Initializes the graphics engine
|
||||
void init();
|
||||
|
||||
// Closes the graphics engine
|
||||
void close();
|
||||
|
||||
// Warns when entering or exits the options menu
|
||||
void openOptionScreen(CORO_PARAM, int type);
|
||||
|
||||
// Enables or disables mouse input
|
||||
void enableInput();
|
||||
void disableInput();
|
||||
|
||||
// Enables and disables mouse draw
|
||||
void enableMouse();
|
||||
void disableMouse();
|
||||
|
||||
operator RMGfxTargetBuffer &();
|
||||
RMInput &getInput();
|
||||
RMPointer &getPointer();
|
||||
|
||||
// Link to the custom function list
|
||||
void initCustomDll();
|
||||
|
||||
// Link to graphic task
|
||||
void linkGraphicTask(RMGfxTask *task);
|
||||
|
||||
// Manage a location
|
||||
uint32 loadLocation(int nLoc, RMPoint ptTonyStart, RMPoint start);
|
||||
void unloadLocation(CORO_PARAM, bool bDoOnExit, uint32 *result);
|
||||
int getCurrentLocation() const { return _nCurLoc; }
|
||||
|
||||
// State management
|
||||
void saveState(const Common::String &fn, byte *curThumb, const Common::String &name);
|
||||
void loadState(CORO_PARAM, const Common::String &fn);
|
||||
|
||||
// Pauses sound
|
||||
void pauseSound(bool bPause);
|
||||
|
||||
// Wipe
|
||||
void initWipe(int type);
|
||||
void closeWipe();
|
||||
void waitWipeEnd(CORO_PARAM);
|
||||
|
||||
void setPerorate(bool bpal);
|
||||
|
||||
bool canLoadSave();
|
||||
};
|
||||
|
||||
} // End of namespace Tony
|
||||
|
||||
#endif
|
||||
134
engines/tony/globals.cpp
Normal file
134
engines/tony/globals.cpp
Normal file
@@ -0,0 +1,134 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/algorithm.h"
|
||||
#include "tony/globals.h"
|
||||
|
||||
namespace Tony {
|
||||
|
||||
Globals::Globals() {
|
||||
_nextLoop = false;
|
||||
_nextChannel = 0;
|
||||
_nextSync = 0;
|
||||
_curChannel = 0;
|
||||
_flipflop = 0;
|
||||
_curBackText = NULL;
|
||||
_bTonyIsSpeaking = false;
|
||||
_curChangedHotspot = 0;
|
||||
_tony = NULL;
|
||||
_pointer = NULL;
|
||||
_boxes = NULL;
|
||||
_loc = NULL;
|
||||
_inventory = NULL;
|
||||
_input = NULL;
|
||||
_gfxEngine = NULL;
|
||||
EnableGUI = NULL;
|
||||
DisableGUI = NULL;
|
||||
|
||||
_dwTonyNumTexts = 0;
|
||||
_bTonyInTexts = false;
|
||||
_bStaticTalk = false;
|
||||
_bAlwaysDisplay = false;
|
||||
_bIdleExited = false;
|
||||
_bSkipSfxNoLoop = false;
|
||||
_bNoBullsEye = false;
|
||||
_curDialog = 0;
|
||||
_curSoundEffect = 0;
|
||||
_bFadeOutStop = false;
|
||||
|
||||
_bSkipIdle = false;
|
||||
_hSkipIdle = 0;
|
||||
_lastMusic = 0;
|
||||
_lastTappeto = 0;
|
||||
Common::fill(&_ambiance[0], &_ambiance[200], 0);
|
||||
_fullScreenMessageLoc = 0;
|
||||
|
||||
// MPAL global variables
|
||||
_mpalError = 0;
|
||||
_lpiifCustom = NULL;
|
||||
_lplpFunctions = NULL;
|
||||
_lplpFunctionStrings = NULL;
|
||||
_nObjs = 0;
|
||||
_nVars = 0;
|
||||
_hVars = NULL;
|
||||
_lpmvVars = NULL;
|
||||
_nMsgs = 0;
|
||||
_hMsgs = NULL;
|
||||
_lpmmMsgs = NULL;
|
||||
_nDialogs = 0;
|
||||
_hDialogs = NULL;
|
||||
_lpmdDialogs = NULL;
|
||||
_nItems = 0;
|
||||
_hItems = NULL;
|
||||
_lpmiItems = NULL;
|
||||
_nLocations = 0;
|
||||
_hLocations = NULL;
|
||||
_lpmlLocations = NULL;
|
||||
_nScripts = 0;
|
||||
_hScripts = NULL;
|
||||
_lpmsScripts = NULL;
|
||||
_nResources = 0;
|
||||
_lpResources = NULL;
|
||||
_bExecutingAction = false;
|
||||
_bExecutingDialog = false;
|
||||
Common::fill(&_nPollingLocations[0], &_nPollingLocations[MAXPOLLINGLOCATIONS], 0);
|
||||
Common::fill(&_hEndPollingLocations[0], &_hEndPollingLocations[MAXPOLLINGLOCATIONS], 0);
|
||||
Common::fill(&_pollingThreads[0], &_pollingThreads[MAXPOLLINGLOCATIONS], 0);
|
||||
_hAskChoice = 0;
|
||||
_hDoneChoice = 0;
|
||||
_nExecutingAction = 0;
|
||||
_nExecutingDialog = 0;
|
||||
_nExecutingChoice = 0;
|
||||
_nSelectedChoice = 0;
|
||||
_nTonyNextTalkType = RMTony::TALK_NORMAL;
|
||||
_saveTonyLoc = 0;
|
||||
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
Common::fill((byte *)&_character[i], (byte *)&_character[i] + sizeof(CharacterStruct), 0);
|
||||
_isMChar[i] = false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 10; ++i)
|
||||
Common::fill((byte *)&_mCharacter[i], (byte *)&_mCharacter[i] + sizeof(MCharacterStruct), 0);
|
||||
for (int i = 0; i < 256; ++i)
|
||||
Common::fill((byte *)&_changedHotspot[i], (byte *)&_changedHotspot[i] + sizeof(ChangedHotspotStruct), 0);
|
||||
|
||||
// Set up globals that have explicit initial values
|
||||
_bCfgInvLocked = false;
|
||||
_bCfgInvNoScroll = false;
|
||||
_bCfgTimerizedText = true;
|
||||
_bCfgInvUp = false;
|
||||
_bCfgAnni30 = false;
|
||||
_bCfgAntiAlias = false;
|
||||
_bCfgTransparence = true;
|
||||
_bCfgInterTips = true;
|
||||
_bShowSubtitles = true;
|
||||
_nCfgTonySpeed = 3;
|
||||
_nCfgTextSpeed = 5;
|
||||
_bCfgDubbing = true;
|
||||
_bCfgMusic = true;
|
||||
_bCfgSFX = true;
|
||||
_nCfgDubbingVolume = 10;
|
||||
_nCfgMusicVolume = 7;
|
||||
_nCfgSFXVolume = 10;
|
||||
}
|
||||
|
||||
} // End of namespace Tony
|
||||
287
engines/tony/globals.h
Normal file
287
engines/tony/globals.h
Normal file
@@ -0,0 +1,287 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TONY_GLOBALS
|
||||
#define TONY_GLOBALS
|
||||
|
||||
#include "common/savefile.h"
|
||||
#include "tony/gfxengine.h"
|
||||
#include "tony/input.h"
|
||||
#include "tony/inventory.h"
|
||||
#include "tony/loc.h"
|
||||
#include "tony/tonychar.h"
|
||||
#include "tony/mpal/mpal.h"
|
||||
#include "tony/mpal/mpaldll.h"
|
||||
|
||||
namespace Tony {
|
||||
|
||||
#define AMBIANCE_CRICKETS 1
|
||||
#define AMBIANCE_CRICKETSMUFFLED 2
|
||||
#define AMBIANCE_CRICKETSWIND 3
|
||||
#define AMBIANCE_CRICKETSWIND1 4
|
||||
#define AMBIANCE_WIND 5
|
||||
#define AMBIANCE_SEA 6
|
||||
#define AMBIANCE_SEAHALFVOLUME 7
|
||||
|
||||
struct CharacterStruct {
|
||||
uint32 _code;
|
||||
RMItem *_item;
|
||||
byte _r, _g, _b;
|
||||
int _talkPattern;
|
||||
int _standPattern;
|
||||
int _startTalkPattern, _endTalkPattern;
|
||||
int _numTexts;
|
||||
|
||||
void save(Common::OutSaveFile *f) {
|
||||
f->writeUint32LE(_code);
|
||||
f->writeUint32LE(0);
|
||||
f->writeByte(_r);
|
||||
f->writeByte(_g);
|
||||
f->writeByte(_b);
|
||||
f->writeUint32LE(_talkPattern);
|
||||
f->writeUint32LE(_standPattern);
|
||||
f->writeUint32LE(_startTalkPattern);
|
||||
f->writeUint32LE(_endTalkPattern);
|
||||
f->writeUint32LE(_numTexts);
|
||||
}
|
||||
|
||||
void load(Common::InSaveFile *f) {
|
||||
_code = f->readUint32LE();
|
||||
f->readUint32LE();
|
||||
_item = NULL;
|
||||
_r = f->readByte();
|
||||
_g = f->readByte();
|
||||
_b = f->readByte();
|
||||
_talkPattern = f->readUint32LE();
|
||||
_standPattern = f->readUint32LE();
|
||||
_startTalkPattern = f->readUint32LE();
|
||||
_endTalkPattern = f->readUint32LE();
|
||||
_numTexts = f->readUint32LE();
|
||||
}
|
||||
};
|
||||
|
||||
struct MCharacterStruct {
|
||||
uint32 _code;
|
||||
RMItem *_item;
|
||||
byte _r, _g, _b;
|
||||
int _x, _y;
|
||||
int _numTalks[10];
|
||||
int _curGroup;
|
||||
int _numTexts;
|
||||
bool _bInTexts;
|
||||
int _curTalk;
|
||||
bool _bAlwaysBack;
|
||||
|
||||
void save(Common::OutSaveFile *f) {
|
||||
f->writeUint32LE(_code);
|
||||
f->writeUint32LE(0);
|
||||
f->writeByte(_r);
|
||||
f->writeByte(_g);
|
||||
f->writeByte(_b);
|
||||
f->writeUint32LE(_x);
|
||||
f->writeUint32LE(_y);
|
||||
for (int i = 0; i < 10; ++i)
|
||||
f->writeUint32LE(_numTalks[i]);
|
||||
f->writeUint32LE(_curGroup);
|
||||
f->writeUint32LE(_numTexts);
|
||||
f->writeByte(_bInTexts);
|
||||
f->writeUint32LE(_curTalk);
|
||||
f->writeByte(_bAlwaysBack);
|
||||
}
|
||||
|
||||
void load(Common::InSaveFile *f) {
|
||||
_code = f->readUint32LE();
|
||||
f->readUint32LE();
|
||||
_item = NULL;
|
||||
_r = f->readByte();
|
||||
_g = f->readByte();
|
||||
_b = f->readByte();
|
||||
_x = f->readUint32LE();
|
||||
_y = f->readUint32LE();
|
||||
for (int i = 0; i < 10; ++i)
|
||||
_numTalks[i] = f->readUint32LE();
|
||||
_curGroup = f->readUint32LE();
|
||||
_numTexts = f->readUint32LE();
|
||||
_bInTexts = f->readByte();
|
||||
_curTalk = f->readUint32LE();
|
||||
_bAlwaysBack = f->readByte();
|
||||
}
|
||||
};
|
||||
|
||||
struct ChangedHotspotStruct {
|
||||
uint32 _dwCode;
|
||||
uint32 _nX, _nY;
|
||||
|
||||
void save(Common::OutSaveFile *f) {
|
||||
f->writeUint32LE(_dwCode);
|
||||
f->writeUint32LE(_nX);
|
||||
f->writeUint32LE(_nY);
|
||||
}
|
||||
|
||||
void load(Common::InSaveFile *f) {
|
||||
_dwCode = f->readUint32LE();
|
||||
_nX = f->readUint32LE();
|
||||
_nY = f->readUint32LE();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Description of a call to a custom function.
|
||||
*/
|
||||
typedef struct {
|
||||
int _nCf;
|
||||
int _arg1, _arg2, _arg3, _arg4;
|
||||
} CfCall;
|
||||
|
||||
typedef CfCall *LpCfCall;
|
||||
|
||||
struct CoroutineMutex {
|
||||
CoroutineMutex() : _eventId(0), _ownerPid(0), _lockCount(0) { }
|
||||
|
||||
uint32 _eventId;
|
||||
uint32 _ownerPid;
|
||||
uint32 _lockCount;
|
||||
};
|
||||
|
||||
/****************************************************************************\
|
||||
* Global variables
|
||||
\****************************************************************************/
|
||||
|
||||
/**
|
||||
* Globals class
|
||||
*/
|
||||
class Globals {
|
||||
public:
|
||||
Globals();
|
||||
|
||||
Common::String _nextMusic;
|
||||
bool _nextLoop;
|
||||
int _nextChannel;
|
||||
int _nextSync;
|
||||
int _curChannel;
|
||||
int _flipflop;
|
||||
CharacterStruct _character[16];
|
||||
MCharacterStruct _mCharacter[10];
|
||||
ChangedHotspotStruct _changedHotspot[256];
|
||||
bool _isMChar[16];
|
||||
bool _bAlwaysDisplay;
|
||||
RMPoint _saveTonyPos;
|
||||
int _saveTonyLoc;
|
||||
RMTextDialog *_curBackText;
|
||||
bool _bTonyIsSpeaking;
|
||||
int _curChangedHotspot;
|
||||
bool _bCfgInvLocked;
|
||||
bool _bCfgInvNoScroll;
|
||||
bool _bCfgTimerizedText;
|
||||
bool _bCfgInvUp;
|
||||
bool _bCfgAnni30;
|
||||
bool _bCfgAntiAlias;
|
||||
bool _bShowSubtitles;
|
||||
bool _bCfgTransparence;
|
||||
bool _bCfgInterTips;
|
||||
bool _bCfgDubbing;
|
||||
bool _bCfgMusic;
|
||||
bool _bCfgSFX;
|
||||
int _nCfgTonySpeed;
|
||||
int _nCfgTextSpeed;
|
||||
int _nCfgDubbingVolume;
|
||||
int _nCfgMusicVolume;
|
||||
int _nCfgSFXVolume;
|
||||
bool _bSkipSfxNoLoop;
|
||||
bool _bIdleExited;
|
||||
bool _bNoBullsEye;
|
||||
int _curDialog;
|
||||
int _curSoundEffect;
|
||||
bool _bFadeOutStop;
|
||||
|
||||
RMTony *_tony;
|
||||
RMPointer *_pointer;
|
||||
RMGameBoxes *_boxes;
|
||||
RMLocation *_loc;
|
||||
RMInventory *_inventory;
|
||||
RMInput *_input;
|
||||
RMGfxEngine *_gfxEngine;
|
||||
|
||||
void (*EnableGUI)();
|
||||
void (*DisableGUI)();
|
||||
|
||||
uint32 _dwTonyNumTexts;
|
||||
bool _bTonyInTexts;
|
||||
bool _bStaticTalk;
|
||||
RMTony::CharacterTalkType _nTonyNextTalkType;
|
||||
|
||||
RMPoint _startLocPos[256];
|
||||
CoroutineMutex _mut[10];
|
||||
|
||||
bool _bSkipIdle;
|
||||
uint32 _hSkipIdle;
|
||||
|
||||
int _lastMusic, _lastTappeto;
|
||||
|
||||
int _ambiance[200];
|
||||
RMPoint _fullScreenMessagePt;
|
||||
int _fullScreenMessageLoc;
|
||||
|
||||
/**
|
||||
* @defgroup MPAL variables
|
||||
*/
|
||||
uint32 _mpalError;
|
||||
LPITEMIRQFUNCTION _lpiifCustom;
|
||||
LPLPCUSTOMFUNCTION _lplpFunctions;
|
||||
Common::String *_lplpFunctionStrings;
|
||||
uint16 _nObjs;
|
||||
uint16 _nVars;
|
||||
MpalHandle _hVars;
|
||||
LpMpalVar _lpmvVars;
|
||||
uint16 _nMsgs;
|
||||
MpalHandle _hMsgs;
|
||||
LpMpalMsg _lpmmMsgs;
|
||||
uint16 _nDialogs;
|
||||
MpalHandle _hDialogs;
|
||||
LpMpalDialog _lpmdDialogs;
|
||||
uint16 _nItems;
|
||||
MpalHandle _hItems;
|
||||
LpMpalItem _lpmiItems;
|
||||
uint16 _nLocations;
|
||||
MpalHandle _hLocations;
|
||||
LpMpalLocation _lpmlLocations;
|
||||
uint16 _nScripts;
|
||||
MpalHandle _hScripts;
|
||||
LpMpalScript _lpmsScripts;
|
||||
Common::File _hMpr;
|
||||
uint16 _nResources;
|
||||
uint32 *_lpResources;
|
||||
bool _bExecutingAction;
|
||||
bool _bExecutingDialog;
|
||||
uint32 _nPollingLocations[MAXPOLLINGLOCATIONS];
|
||||
uint32 _hEndPollingLocations[MAXPOLLINGLOCATIONS];
|
||||
uint32 _pollingThreads[MAXPOLLINGLOCATIONS];
|
||||
uint32 _hAskChoice;
|
||||
uint32 _hDoneChoice;
|
||||
uint32 _nExecutingAction;
|
||||
uint32 _nExecutingDialog;
|
||||
uint32 _nExecutingChoice;
|
||||
uint32 _nSelectedChoice;
|
||||
};
|
||||
|
||||
} // End of namespace Tony
|
||||
|
||||
#endif // TONY_GLOBALS
|
||||
127
engines/tony/input.cpp
Normal file
127
engines/tony/input.cpp
Normal file
@@ -0,0 +1,127 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on original Tony Tough source code
|
||||
*
|
||||
* Copyright (c) 1997-2003 Nayma Software
|
||||
*/
|
||||
|
||||
#include "tony/gfxengine.h"
|
||||
#include "tony/tony.h"
|
||||
|
||||
namespace Tony {
|
||||
|
||||
RMInput::RMInput() {
|
||||
_leftClickMouse = _leftReleaseMouse = false;
|
||||
_rightClickMouse = _rightReleaseMouse = false;
|
||||
}
|
||||
|
||||
void RMInput::poll() {
|
||||
_leftClickMouse = _leftReleaseMouse = _rightClickMouse = _rightReleaseMouse = false;
|
||||
|
||||
// Get pending events
|
||||
while (g_system->getEventManager()->pollEvent(_event) && !g_vm->shouldQuit()) {
|
||||
switch (_event.type) {
|
||||
case Common::EVENT_MOUSEMOVE:
|
||||
case Common::EVENT_LBUTTONDOWN:
|
||||
case Common::EVENT_LBUTTONUP:
|
||||
case Common::EVENT_RBUTTONDOWN:
|
||||
case Common::EVENT_RBUTTONUP:
|
||||
_mousePos = _event.mouse;
|
||||
|
||||
if (_event.type == Common::EVENT_LBUTTONDOWN) {
|
||||
_leftClickMouse = true;
|
||||
} else if (_event.type == Common::EVENT_LBUTTONUP) {
|
||||
_leftReleaseMouse = true;
|
||||
} else if (_event.type == Common::EVENT_RBUTTONDOWN) {
|
||||
_rightClickMouse = true;
|
||||
} else if (_event.type == Common::EVENT_RBUTTONUP) {
|
||||
_rightReleaseMouse = true;
|
||||
} else
|
||||
continue;
|
||||
|
||||
// Since a mouse button has changed, don't do any further event processing this frame
|
||||
return;
|
||||
|
||||
case Common::EVENT_KEYDOWN:
|
||||
// Flag the given key as being down
|
||||
_keyDown.push_back(_event.kbd.keycode);
|
||||
return;
|
||||
|
||||
case Common::EVENT_KEYUP:
|
||||
for (uint i = 0; i < _keyDown.size(); i++) {
|
||||
if (_keyDown[i] == _event.kbd.keycode) {
|
||||
_keyDown.remove_at(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if a key has been pressed
|
||||
*/
|
||||
bool RMInput::getAsyncKeyState(Common::KeyCode kc) {
|
||||
// The act of testing for a particular key automatically clears the state, to prevent
|
||||
// the same key being registered in multiple different frames
|
||||
for (uint i = 0; i < _keyDown.size(); i++) {
|
||||
if (_keyDown[i] == kc) {
|
||||
_keyDown.remove_at(i);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reading of the mouse
|
||||
*/
|
||||
RMPoint RMInput::mousePos() {
|
||||
RMPoint p(_mousePos.x, _mousePos.y);
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Events of mouse clicks
|
||||
*/
|
||||
bool RMInput::mouseLeftClicked() {
|
||||
return _leftClickMouse;
|
||||
}
|
||||
|
||||
bool RMInput::mouseRightClicked() {
|
||||
return _rightClickMouse;
|
||||
}
|
||||
|
||||
bool RMInput::mouseLeftReleased() {
|
||||
return _leftReleaseMouse;
|
||||
}
|
||||
|
||||
bool RMInput::mouseRightReleased() {
|
||||
return _rightReleaseMouse;
|
||||
}
|
||||
|
||||
} // End of namespace Tony
|
||||
79
engines/tony/input.h
Normal file
79
engines/tony/input.h
Normal file
@@ -0,0 +1,79 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on original Tony Tough source code
|
||||
*
|
||||
* Copyright (c) 1997-2003 Nayma Software
|
||||
*/
|
||||
|
||||
#ifndef TONY_INPUT_H
|
||||
#define TONY_INPUT_H
|
||||
|
||||
#include "common/events.h"
|
||||
#include "common/rect.h"
|
||||
#include "common/array.h"
|
||||
#include "common/keyboard.h"
|
||||
#include "tony/utils.h"
|
||||
|
||||
namespace Tony {
|
||||
|
||||
class RMInput {
|
||||
private:
|
||||
Common::Event _event;
|
||||
|
||||
// Mouse related fields
|
||||
Common::Point _mousePos;
|
||||
bool _leftClickMouse, _leftReleaseMouse, _rightClickMouse, _rightReleaseMouse;
|
||||
|
||||
// Keyboard related fields
|
||||
Common::Array<Common::KeyCode> _keyDown;
|
||||
|
||||
public:
|
||||
RMInput();
|
||||
|
||||
/**
|
||||
* Polling (must be performed once per frame)
|
||||
*/
|
||||
void poll();
|
||||
|
||||
/**
|
||||
* Reading of the mouse
|
||||
*/
|
||||
RMPoint mousePos();
|
||||
|
||||
/**
|
||||
* Events of mouse clicks
|
||||
*/
|
||||
bool mouseLeftClicked();
|
||||
bool mouseRightClicked();
|
||||
bool mouseLeftReleased();
|
||||
bool mouseRightReleased();
|
||||
|
||||
/**
|
||||
* Returns true if the given key is pressed
|
||||
*/
|
||||
bool getAsyncKeyState(Common::KeyCode kc);
|
||||
};
|
||||
|
||||
} // End of namespace Tony
|
||||
|
||||
#endif
|
||||
934
engines/tony/inventory.cpp
Normal file
934
engines/tony/inventory.cpp
Normal file
@@ -0,0 +1,934 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on original Tony Tough source code
|
||||
*
|
||||
* Copyright (c) 1997-2003 Nayma Software
|
||||
*/
|
||||
|
||||
#include "common/textconsole.h"
|
||||
#include "tony/mpal/mpalutils.h"
|
||||
#include "tony/inventory.h"
|
||||
#include "tony/game.h"
|
||||
#include "tony/tony.h"
|
||||
|
||||
namespace Tony {
|
||||
|
||||
/****************************************************************************\
|
||||
* RMInventory Methods
|
||||
\****************************************************************************/
|
||||
|
||||
RMInventory::RMInventory() {
|
||||
_items = NULL;
|
||||
_state = CLOSED;
|
||||
_bCombining = false;
|
||||
_nItems = 0;
|
||||
|
||||
Common::fill(_inv, _inv + 256, 0);
|
||||
_nInv = 0;
|
||||
_curPutY = 0;
|
||||
_curPutTime = 0;
|
||||
_curPos = 0;
|
||||
_bHasFocus = false;
|
||||
_nSelectObj = 0;
|
||||
_nCombine = 0;
|
||||
_bBlinkingRight = false;
|
||||
_bBlinkingLeft = false;
|
||||
_miniAction = 0;
|
||||
}
|
||||
|
||||
RMInventory::~RMInventory() {
|
||||
close();
|
||||
}
|
||||
|
||||
bool RMInventory::checkPointInside(const RMPoint &pt) {
|
||||
if (!GLOBALS._bCfgInvUp)
|
||||
return pt._y > RM_SY - 70;
|
||||
else
|
||||
return pt._y < 70;
|
||||
}
|
||||
|
||||
void RMInventory::init() {
|
||||
// Create the main buffer
|
||||
create(RM_SX, 68);
|
||||
setPriority(185);
|
||||
|
||||
// Setup the inventory
|
||||
_nInv = 0;
|
||||
_curPos = 0;
|
||||
_bCombining = false;
|
||||
|
||||
// New items
|
||||
_nItems = 78; // @@@ Number of takeable items
|
||||
_items = new RMInventoryItem[_nItems + 1];
|
||||
|
||||
int curres = 10500;
|
||||
|
||||
// Loop through the items
|
||||
for (int i = 0; i <= _nItems; i++) {
|
||||
// Load the items from the resource
|
||||
RMRes res(curres);
|
||||
assert(res.isValid());
|
||||
Common::SeekableReadStream *ds = res.getReadStream();
|
||||
|
||||
// Initialize the MPAL inventory item by reading it in.
|
||||
_items[i]._icon.setInitCurPattern(false);
|
||||
_items[i]._icon.readFromStream(*ds);
|
||||
delete ds;
|
||||
|
||||
// Puts in the default pattern 1
|
||||
_items[i]._pointer = NULL;
|
||||
_items[i]._status = 1;
|
||||
_items[i]._icon.setPattern(1);
|
||||
_items[i]._icon.doFrame(this, false);
|
||||
|
||||
curres++;
|
||||
if (i == 0 || i == 28 || i == 29)
|
||||
continue;
|
||||
|
||||
_items[i]._pointer = new RMGfxSourceBuffer8RLEByteAA[_items[i]._icon.numPattern()];
|
||||
|
||||
for (int j = 0; j < _items[i]._icon.numPattern(); j++) {
|
||||
RMResRaw raw(curres);
|
||||
|
||||
assert(raw.isValid());
|
||||
|
||||
_items[i]._pointer[j].init((const byte *)raw, raw.width(), raw.height(), true);
|
||||
curres++;
|
||||
}
|
||||
}
|
||||
|
||||
_items[28]._icon.setPattern(1);
|
||||
_items[29]._icon.setPattern(1);
|
||||
|
||||
// Download interface
|
||||
RMRes res(RES_I_MINIINTER);
|
||||
assert(res.isValid());
|
||||
Common::SeekableReadStream *ds = res.getReadStream();
|
||||
_miniInterface.readFromStream(*ds);
|
||||
_miniInterface.setPattern(1);
|
||||
delete ds;
|
||||
|
||||
// Create the text for hints on the mini interface
|
||||
_hints[0].setAlignType(RMText::HCENTER, RMText::VTOP);
|
||||
_hints[1].setAlignType(RMText::HCENTER, RMText::VTOP);
|
||||
_hints[2].setAlignType(RMText::HCENTER, RMText::VTOP);
|
||||
|
||||
// The text is taken from MPAL for translation
|
||||
RMMessage msg1(15);
|
||||
RMMessage msg2(13);
|
||||
RMMessage msg3(14);
|
||||
|
||||
_hints[0].writeText(msg1[0], 1); // Examine
|
||||
_hints[1].writeText(msg2[0], 1); // Take
|
||||
_hints[2].writeText(msg3[0], 1); // Use
|
||||
|
||||
// Prepare initial inventory
|
||||
prepare();
|
||||
drawOT(Common::nullContext);
|
||||
clearOT();
|
||||
}
|
||||
|
||||
void RMInventory::close() {
|
||||
// Has memory
|
||||
if (_items != NULL) {
|
||||
// Delete the item pointers
|
||||
for (int i = 0; i <= _nItems; i++)
|
||||
delete[] _items[i]._pointer;
|
||||
|
||||
// Delete the items array
|
||||
delete[] _items;
|
||||
_items = NULL;
|
||||
}
|
||||
|
||||
destroy();
|
||||
}
|
||||
|
||||
void RMInventory::reset() {
|
||||
_state = CLOSED;
|
||||
endCombine();
|
||||
}
|
||||
|
||||
void RMInventory::draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim) {
|
||||
CORO_BEGIN_CONTEXT;
|
||||
RMPoint pos;
|
||||
RMPoint pos2;
|
||||
RMGfxPrimitive *p;
|
||||
RMGfxPrimitive *p2;
|
||||
CORO_END_CONTEXT(_ctx);
|
||||
|
||||
CORO_BEGIN_CODE(_ctx);
|
||||
|
||||
prim->setDst(RMPoint(0, _curPutY));
|
||||
_csModifyInterface.lock();
|
||||
CORO_INVOKE_2(RMGfxWoodyBuffer::draw, bigBuf, prim);
|
||||
_csModifyInterface.unlock();
|
||||
|
||||
if (_state == SELECTING) {
|
||||
|
||||
if (!GLOBALS._bCfgInvUp) {
|
||||
_ctx->pos.set((_nSelectObj + 1) * 64 - 20, RM_SY - 113);
|
||||
_ctx->pos2.set((_nSelectObj + 1) * 64 + 34, RM_SY - 150);
|
||||
} else {
|
||||
_ctx->pos.set((_nSelectObj + 1) * 64 - 20, 72 - 4); // The brown part is at the top :(
|
||||
_ctx->pos2.set((_nSelectObj + 1) * 64 + 34, 119 - 4);
|
||||
}
|
||||
|
||||
_ctx->p = new RMGfxPrimitive(prim->_task, _ctx->pos);
|
||||
_ctx->p2 = new RMGfxPrimitive(prim->_task, _ctx->pos2);
|
||||
|
||||
// Draw the mini interface
|
||||
CORO_INVOKE_2(_miniInterface.draw, bigBuf, _ctx->p);
|
||||
|
||||
if (GLOBALS._bCfgInterTips) {
|
||||
if (_miniAction == 1) // Examine
|
||||
CORO_INVOKE_2(_hints[0].draw, bigBuf, _ctx->p2);
|
||||
else if (_miniAction == 2) // Talk
|
||||
CORO_INVOKE_2(_hints[1].draw, bigBuf, _ctx->p2);
|
||||
else if (_miniAction == 3) // Use
|
||||
CORO_INVOKE_2(_hints[2].draw, bigBuf, _ctx->p2);
|
||||
}
|
||||
|
||||
delete _ctx->p;
|
||||
delete _ctx->p2;
|
||||
}
|
||||
|
||||
CORO_END_CODE;
|
||||
}
|
||||
|
||||
void RMInventory::removeThis(CORO_PARAM, bool &result) {
|
||||
if (_state == CLOSED)
|
||||
result = true;
|
||||
else
|
||||
result = false;
|
||||
}
|
||||
|
||||
void RMInventory::removeItem(int code) {
|
||||
for (int i = 0; i < _nInv; i++) {
|
||||
if (_inv[i] == code - 10000) {
|
||||
_csModifyInterface.lock();
|
||||
|
||||
Common::copy(&_inv[i + 1], &_inv[i + 1] + (_nInv - i), &_inv[i]);
|
||||
_nInv--;
|
||||
|
||||
prepare();
|
||||
drawOT(Common::nullContext);
|
||||
clearOT();
|
||||
_csModifyInterface.unlock();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RMInventory::addItem(int code) {
|
||||
if (code <= 10000 || code >= 10101) {
|
||||
// If we are here, it means that we are adding an item that should not be in the inventory
|
||||
warning("RMInventory::addItem(%d) - Cannot find a valid icon for this item, and then it will not be added to the inventory", code);
|
||||
} else {
|
||||
_csModifyInterface.lock();
|
||||
if (_curPos + 8 == _nInv) {
|
||||
// Break through the inventory! On the flashing pattern
|
||||
_items[28]._icon.setPattern(2);
|
||||
}
|
||||
|
||||
_inv[_nInv++] = code - 10000;
|
||||
|
||||
prepare();
|
||||
drawOT(Common::nullContext);
|
||||
clearOT();
|
||||
_csModifyInterface.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
void RMInventory::changeItemStatus(uint32 code, uint32 dwStatus) {
|
||||
if (code <= 10000 || code >= 10101) {
|
||||
error("RMInventory::changeItemStatus(%d) - Specified object code is not valid", code);
|
||||
} else {
|
||||
_csModifyInterface.lock();
|
||||
_items[code - 10000]._icon.setPattern(dwStatus);
|
||||
_items[code - 10000]._status = dwStatus;
|
||||
|
||||
prepare();
|
||||
drawOT(Common::nullContext);
|
||||
clearOT();
|
||||
_csModifyInterface.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
void RMInventory::prepare() {
|
||||
for (int i = 1; i < RM_SX / 64 - 1; i++) {
|
||||
if (i - 1 + _curPos < _nInv)
|
||||
addPrim(new RMGfxPrimitive(&_items[_inv[i - 1 + _curPos]]._icon, RMPoint(i * 64, 0)));
|
||||
else
|
||||
addPrim(new RMGfxPrimitive(&_items[0]._icon, RMPoint(i * 64, 0)));
|
||||
}
|
||||
|
||||
// Frecce
|
||||
addPrim(new RMGfxPrimitive(&_items[29]._icon, RMPoint(0, 0)));
|
||||
addPrim(new RMGfxPrimitive(&_items[28]._icon, RMPoint(640 - 64, 0)));
|
||||
}
|
||||
|
||||
bool RMInventory::miniActive() {
|
||||
return _state == SELECTING;
|
||||
}
|
||||
|
||||
bool RMInventory::haveFocus(const RMPoint &mpos) {
|
||||
// When we combine, have the focus only if we are on an arrow (to scroll)
|
||||
if (_state == OPENED && _bCombining && checkPointInside(mpos) && (mpos._x < 64 || mpos._x > RM_SX - 64))
|
||||
return true;
|
||||
|
||||
// If the inventory is open, focus we we go over it
|
||||
if (_state == OPENED && !_bCombining && checkPointInside(mpos))
|
||||
return true;
|
||||
|
||||
// If we are selecting a verb (and then right down), we always focus
|
||||
if (_state == SELECTING)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void RMInventory::endCombine() {
|
||||
_bCombining = false;
|
||||
}
|
||||
|
||||
bool RMInventory::leftClick(const RMPoint &mpos, int &nCombineObj) {
|
||||
// The left click picks an item from your inventory to use it with the background
|
||||
int n = mpos._x / 64;
|
||||
|
||||
if (_state == OPENED) {
|
||||
if (n > 0 && n < RM_SX / 64 - 1 && _inv[n - 1 + _curPos] != 0) {
|
||||
_bCombining = true; //m_state = COMBINING;
|
||||
_nCombine = _inv[n - 1 + _curPos];
|
||||
nCombineObj = _nCombine + 10000;
|
||||
|
||||
g_vm->playUtilSFX(1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Click the right arrow
|
||||
if ((_state == OPENED) && _bBlinkingRight) {
|
||||
_csModifyInterface.lock();
|
||||
_curPos++;
|
||||
|
||||
if (_curPos + 8 >= _nInv) {
|
||||
_bBlinkingRight = false;
|
||||
_items[28]._icon.setPattern(1);
|
||||
}
|
||||
|
||||
if (_curPos > 0) {
|
||||
_bBlinkingLeft = true;
|
||||
_items[29]._icon.setPattern(2);
|
||||
}
|
||||
|
||||
prepare();
|
||||
drawOT(Common::nullContext);
|
||||
clearOT();
|
||||
_csModifyInterface.unlock();
|
||||
}
|
||||
|
||||
// Click the left arrow
|
||||
else if ((_state == OPENED) && _bBlinkingLeft) {
|
||||
assert(_curPos > 0);
|
||||
_csModifyInterface.lock();
|
||||
_curPos--;
|
||||
|
||||
if (_curPos == 0) {
|
||||
_bBlinkingLeft = false;
|
||||
_items[29]._icon.setPattern(1);
|
||||
}
|
||||
|
||||
if (_curPos + 8 < _nInv) {
|
||||
_bBlinkingRight = true;
|
||||
_items[28]._icon.setPattern(2);
|
||||
}
|
||||
|
||||
prepare();
|
||||
drawOT(Common::nullContext);
|
||||
clearOT();
|
||||
_csModifyInterface.unlock();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void RMInventory::rightClick(const RMPoint &mpos) {
|
||||
assert(checkPointInside(mpos));
|
||||
|
||||
if (_state == OPENED && !_bCombining) {
|
||||
// Open the context interface
|
||||
int n = mpos._x / 64;
|
||||
|
||||
if (n > 0 && n < RM_SX / 64 - 1 && _inv[n - 1 + _curPos] != 0) {
|
||||
_state = SELECTING;
|
||||
_miniAction = 0;
|
||||
_nSelectObj = n - 1;
|
||||
|
||||
g_vm->playUtilSFX(0);
|
||||
}
|
||||
}
|
||||
|
||||
if ((_state == OPENED) && _bBlinkingRight) {
|
||||
_csModifyInterface.lock();
|
||||
_curPos += 7;
|
||||
if (_curPos + 8 > _nInv)
|
||||
_curPos = _nInv - 8;
|
||||
|
||||
if (_curPos + 8 <= _nInv) {
|
||||
_bBlinkingRight = false;
|
||||
_items[28]._icon.setPattern(1);
|
||||
}
|
||||
|
||||
if (_curPos > 0) {
|
||||
_bBlinkingLeft = true;
|
||||
_items[29]._icon.setPattern(2);
|
||||
}
|
||||
|
||||
prepare();
|
||||
drawOT(Common::nullContext);
|
||||
clearOT();
|
||||
_csModifyInterface.unlock();
|
||||
} else if ((_state == OPENED) && _bBlinkingLeft) {
|
||||
assert(_curPos > 0);
|
||||
_csModifyInterface.lock();
|
||||
_curPos -= 7;
|
||||
if (_curPos < 0)
|
||||
_curPos = 0;
|
||||
|
||||
if (_curPos == 0) {
|
||||
_bBlinkingLeft = false;
|
||||
_items[29]._icon.setPattern(1);
|
||||
}
|
||||
|
||||
if (_curPos + 8 < _nInv) {
|
||||
_bBlinkingRight = true;
|
||||
_items[28]._icon.setPattern(2);
|
||||
}
|
||||
|
||||
prepare();
|
||||
drawOT(Common::nullContext);
|
||||
clearOT();
|
||||
_csModifyInterface.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
bool RMInventory::rightRelease(const RMPoint &mpos, RMTonyAction &curAction) {
|
||||
if (_state == SELECTING) {
|
||||
_state = OPENED;
|
||||
|
||||
if (_miniAction == 1) { // Examine
|
||||
curAction = TA_EXAMINE;
|
||||
return true;
|
||||
} else if (_miniAction == 2) { // Talk
|
||||
curAction = TA_TALK;
|
||||
return true;
|
||||
} else if (_miniAction == 3) { // Use
|
||||
curAction = TA_USE;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#define INVSPEED 20
|
||||
|
||||
void RMInventory::doFrame(RMGfxTargetBuffer &bigBuf, RMPointer &ptr, RMPoint mpos, bool bCanOpen) {
|
||||
if (_state != CLOSED) {
|
||||
// Clean up the OT list
|
||||
_csModifyInterface.lock();
|
||||
clearOT();
|
||||
|
||||
// DoFrame makes all the objects currently in the inventory be displayed
|
||||
// @@@ Maybe we should do all takeable objects? Please does not help
|
||||
bool bNeedRedraw = false;
|
||||
|
||||
for (int i = 0; i < _nInv; i++) {
|
||||
if (_items[_inv[i]]._icon.doFrame(this, false) && (i >= _curPos && i <= _curPos + 7))
|
||||
bNeedRedraw = true;
|
||||
}
|
||||
|
||||
if ((_state == CLOSING || _state == OPENING || _state == OPENED) && checkPointInside(mpos)) {
|
||||
if (mpos._x > RM_SX - 64) {
|
||||
if (_curPos + 8 < _nInv && !_bBlinkingRight) {
|
||||
_items[28]._icon.setPattern(3);
|
||||
_bBlinkingRight = true;
|
||||
bNeedRedraw = true;
|
||||
}
|
||||
} else if (_bBlinkingRight) {
|
||||
_items[28]._icon.setPattern(2);
|
||||
_bBlinkingRight = false;
|
||||
bNeedRedraw = true;
|
||||
}
|
||||
|
||||
if (mpos._x < 64) {
|
||||
if (_curPos > 0 && !_bBlinkingLeft) {
|
||||
_items[29]._icon.setPattern(3);
|
||||
_bBlinkingLeft = true;
|
||||
bNeedRedraw = true;
|
||||
}
|
||||
} else if (_bBlinkingLeft) {
|
||||
_items[29]._icon.setPattern(2);
|
||||
_bBlinkingLeft = false;
|
||||
bNeedRedraw = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (_items[28]._icon.doFrame(this, false))
|
||||
bNeedRedraw = true;
|
||||
|
||||
if (_items[29]._icon.doFrame(this, false))
|
||||
bNeedRedraw = true;
|
||||
|
||||
if (bNeedRedraw)
|
||||
prepare();
|
||||
|
||||
_csModifyInterface.unlock();
|
||||
}
|
||||
|
||||
if (g_vm->getEngine()->getInput().getAsyncKeyState(Common::KEYCODE_i)) {
|
||||
GLOBALS._bCfgInvLocked = !GLOBALS._bCfgInvLocked;
|
||||
}
|
||||
|
||||
if (_bCombining) { // m_state == COMBINING)
|
||||
ptr.setCustomPointer(&_items[_nCombine]._pointer[_items[_nCombine]._status - 1]);
|
||||
ptr.setSpecialPointer(RMPointer::PTR_CUSTOM);
|
||||
}
|
||||
|
||||
if (!GLOBALS._bCfgInvUp) {
|
||||
if ((_state == CLOSED) && (mpos._y > RM_SY - 10 || GLOBALS._bCfgInvLocked) && bCanOpen) {
|
||||
if (!GLOBALS._bCfgInvNoScroll) {
|
||||
_state = OPENING;
|
||||
_curPutY = RM_SY - 1;
|
||||
_curPutTime = g_vm->getTime();
|
||||
} else {
|
||||
_state = OPENED;
|
||||
_curPutY = RM_SY - 68;
|
||||
}
|
||||
} else if (_state == OPENED) {
|
||||
if ((mpos._y < RM_SY - 70 && !GLOBALS._bCfgInvLocked) || !bCanOpen) {
|
||||
if (!GLOBALS._bCfgInvNoScroll) {
|
||||
_state = CLOSING;
|
||||
_curPutY = RM_SY - 68;
|
||||
_curPutTime = g_vm->getTime();
|
||||
} else {
|
||||
_state = CLOSED;
|
||||
}
|
||||
}
|
||||
} else if (_state == OPENING) {
|
||||
while (_curPutTime + INVSPEED < g_vm->getTime()) {
|
||||
_curPutY -= 3;
|
||||
_curPutTime += INVSPEED;
|
||||
}
|
||||
|
||||
if (_curPutY <= RM_SY - 68) {
|
||||
_state = OPENED;
|
||||
_curPutY = RM_SY - 68;
|
||||
}
|
||||
|
||||
} else if (_state == CLOSING) {
|
||||
while (_curPutTime + INVSPEED < g_vm->getTime()) {
|
||||
_curPutY += 3;
|
||||
_curPutTime += INVSPEED;
|
||||
}
|
||||
|
||||
if (_curPutY > 480)
|
||||
_state = CLOSED;
|
||||
}
|
||||
} else {
|
||||
if ((_state == CLOSED) && (mpos._y < 10 || GLOBALS._bCfgInvLocked) && bCanOpen) {
|
||||
if (!GLOBALS._bCfgInvNoScroll) {
|
||||
_state = OPENING;
|
||||
_curPutY = - 68;
|
||||
_curPutTime = g_vm->getTime();
|
||||
} else {
|
||||
_state = OPENED;
|
||||
_curPutY = 0;
|
||||
}
|
||||
} else if (_state == OPENED) {
|
||||
if ((mpos._y > 70 && !GLOBALS._bCfgInvLocked) || !bCanOpen) {
|
||||
if (!GLOBALS._bCfgInvNoScroll) {
|
||||
_state = CLOSING;
|
||||
_curPutY = -2;
|
||||
_curPutTime = g_vm->getTime();
|
||||
} else {
|
||||
_state = CLOSED;
|
||||
}
|
||||
}
|
||||
} else if (_state == OPENING) {
|
||||
while (_curPutTime + INVSPEED < g_vm->getTime()) {
|
||||
_curPutY += 3;
|
||||
_curPutTime += INVSPEED;
|
||||
}
|
||||
|
||||
if (_curPutY >= 0) {
|
||||
_state = OPENED;
|
||||
_curPutY = 0;
|
||||
}
|
||||
} else if (_state == CLOSING) {
|
||||
while (_curPutTime + INVSPEED < g_vm->getTime()) {
|
||||
_curPutY -= 3;
|
||||
_curPutTime += INVSPEED;
|
||||
}
|
||||
|
||||
if (_curPutY < -68)
|
||||
_state = CLOSED;
|
||||
}
|
||||
}
|
||||
|
||||
if (_state == SELECTING) {
|
||||
int startx = (_nSelectObj + 1) * 64 - 20;
|
||||
int starty;
|
||||
|
||||
if (!GLOBALS._bCfgInvUp)
|
||||
starty = RM_SY - 109;
|
||||
else
|
||||
starty = 70;
|
||||
|
||||
// Make sure it is on one of the verbs
|
||||
if (mpos._y > starty && mpos._y < starty + 45) {
|
||||
if (mpos._x > startx && mpos._x < startx + 40) {
|
||||
if (_miniAction != 1) {
|
||||
_miniInterface.setPattern(2);
|
||||
_miniAction = 1;
|
||||
g_vm->playUtilSFX(1);
|
||||
}
|
||||
} else if (mpos._x >= startx + 40 && mpos._x < startx + 80) {
|
||||
if (_miniAction != 2) {
|
||||
_miniInterface.setPattern(3);
|
||||
_miniAction = 2;
|
||||
g_vm->playUtilSFX(1);
|
||||
}
|
||||
} else if (mpos._x >= startx + 80 && mpos._x < startx + 108) {
|
||||
if (_miniAction != 3) {
|
||||
_miniInterface.setPattern(4);
|
||||
_miniAction = 3;
|
||||
g_vm->playUtilSFX(1);
|
||||
}
|
||||
} else {
|
||||
_miniInterface.setPattern(1);
|
||||
_miniAction = 0;
|
||||
}
|
||||
} else {
|
||||
_miniInterface.setPattern(1);
|
||||
_miniAction = 0;
|
||||
}
|
||||
|
||||
// Update the mini-interface
|
||||
_miniInterface.doFrame(&bigBuf, false);
|
||||
}
|
||||
|
||||
if ((_state != CLOSED) && !_nInList) {
|
||||
bigBuf.addPrim(new RMGfxPrimitive(this));
|
||||
}
|
||||
}
|
||||
|
||||
bool RMInventory::itemInFocus(const RMPoint &mpt) {
|
||||
if ((_state == OPENED || _state == OPENING) && checkPointInside(mpt))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
RMItem *RMInventory::whichItemIsIn(const RMPoint &mpt) {
|
||||
if (_state == OPENED) {
|
||||
if (checkPointInside(mpt)) {
|
||||
int n = mpt._x / 64;
|
||||
if (n > 0 && n < RM_SX / 64 - 1 && _inv[n - 1 + _curPos] != 0 && (!_bCombining || _inv[n - 1 + _curPos] != _nCombine))
|
||||
return &_items[_inv[n - 1 + _curPos]]._icon;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int RMInventory::getSaveStateSize() {
|
||||
// m_inv pattern m_nInv
|
||||
return 256 * 4 + 256 * 4 + 4;
|
||||
}
|
||||
|
||||
void RMInventory::saveState(byte *state) {
|
||||
WRITE_LE_UINT32(state, _nInv);
|
||||
state += 4;
|
||||
for (int i = 0; i < 256; ++i) {
|
||||
WRITE_LE_UINT32(state, _inv[i]);
|
||||
state += 4;
|
||||
}
|
||||
|
||||
int x;
|
||||
for (int i = 0; i < 256; i++) {
|
||||
if (i < _nItems)
|
||||
x = _items[i]._status;
|
||||
else
|
||||
x = 0;
|
||||
|
||||
WRITE_LE_UINT32(state, x);
|
||||
state += 4;
|
||||
}
|
||||
}
|
||||
|
||||
int RMInventory::loadState(byte *state) {
|
||||
_nInv = READ_LE_UINT32(state);
|
||||
state += 4;
|
||||
for (int i = 0; i < 256; ++i) {
|
||||
_inv[i] = READ_LE_UINT32(state);
|
||||
state += 4;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 256; i++) {
|
||||
int x = READ_LE_UINT32(state);
|
||||
state += 4;
|
||||
|
||||
if (i < _nItems) {
|
||||
_items[i]._status = x;
|
||||
_items[i]._icon.setPattern(x);
|
||||
}
|
||||
}
|
||||
|
||||
_curPos = 0;
|
||||
_bCombining = false;
|
||||
|
||||
_items[29]._icon.setPattern(1);
|
||||
|
||||
if (_nInv > 8)
|
||||
_items[28]._icon.setPattern(2);
|
||||
else
|
||||
_items[28]._icon.setPattern(1);
|
||||
|
||||
prepare();
|
||||
drawOT(Common::nullContext);
|
||||
clearOT();
|
||||
|
||||
return getSaveStateSize();
|
||||
}
|
||||
|
||||
RMInventory &RMInventory::operator+=(RMItem *item) {
|
||||
addItem(item->mpalCode());
|
||||
return *this;
|
||||
}
|
||||
|
||||
RMInventory &RMInventory::operator+=(RMItem &item) {
|
||||
addItem(item.mpalCode());
|
||||
return *this;
|
||||
}
|
||||
|
||||
RMInventory &RMInventory::operator+=(int code) {
|
||||
addItem(code);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/****************************************************************************\
|
||||
* RMInterface methods
|
||||
\****************************************************************************/
|
||||
|
||||
RMInterface::RMInterface() : RMGfxSourceBuffer8RLEByte() {
|
||||
_bActive = _bPerorate = false;
|
||||
_lastHotZone = -1;
|
||||
}
|
||||
|
||||
RMInterface::~RMInterface() {
|
||||
}
|
||||
|
||||
bool RMInterface::active() {
|
||||
return _bActive;
|
||||
}
|
||||
|
||||
int RMInterface::onWhichBox(RMPoint pt) {
|
||||
pt -= _openStart;
|
||||
|
||||
// Check how many verbs you have to consider
|
||||
int max = 4;
|
||||
if (_bPerorate)
|
||||
max = 5;
|
||||
|
||||
// Find the verb
|
||||
for (int i = 0; i < max; i++) {
|
||||
if (_hotbbox[i].ptInRect(pt))
|
||||
return i;
|
||||
}
|
||||
|
||||
// Found no verb
|
||||
return -1;
|
||||
}
|
||||
|
||||
void RMInterface::draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim) {
|
||||
CORO_BEGIN_CONTEXT;
|
||||
int h;
|
||||
CORO_END_CONTEXT(_ctx);
|
||||
|
||||
CORO_BEGIN_CODE(_ctx);
|
||||
|
||||
prim->getDst().topLeft() = _openStart;
|
||||
CORO_INVOKE_2(RMGfxSourceBuffer8RLEByte::draw, bigBuf, prim);
|
||||
|
||||
// Check if there is a draw hot zone
|
||||
_ctx->h = onWhichBox(_mpos);
|
||||
if (_ctx->h != -1) {
|
||||
prim->getDst().topLeft() = _openStart;
|
||||
CORO_INVOKE_2(_hotzone[_ctx->h].draw, bigBuf, prim);
|
||||
|
||||
if (_lastHotZone != _ctx->h) {
|
||||
_lastHotZone = _ctx->h;
|
||||
g_vm->playUtilSFX(1);
|
||||
}
|
||||
|
||||
if (GLOBALS._bCfgInterTips) {
|
||||
prim->getDst().topLeft() = _openStart + RMPoint(70, 177);
|
||||
CORO_INVOKE_2(_hints[_ctx->h].draw, bigBuf, prim);
|
||||
}
|
||||
} else
|
||||
_lastHotZone = -1;
|
||||
|
||||
CORO_END_CODE;
|
||||
}
|
||||
|
||||
void RMInterface::doFrame(RMGfxTargetBuffer &bigBuf, RMPoint mousepos) {
|
||||
// If needed, add to the OT schedule list
|
||||
if (!_nInList && _bActive)
|
||||
bigBuf.addPrim(new RMGfxPrimitive(this));
|
||||
|
||||
_mpos = mousepos;
|
||||
}
|
||||
|
||||
void RMInterface::clicked(const RMPoint &mousepos) {
|
||||
_bActive = true;
|
||||
_openPos = mousepos;
|
||||
|
||||
// Calculate the top left corner of the interface
|
||||
_openStart = _openPos - RMPoint(_dimx / 2, _dimy / 2);
|
||||
_lastHotZone = -1;
|
||||
|
||||
// Keep it inside the screen
|
||||
if (_openStart._x < 0)
|
||||
_openStart._x = 0;
|
||||
if (_openStart._y < 0)
|
||||
_openStart._y = 0;
|
||||
if (_openStart._x + _dimx > RM_SX)
|
||||
_openStart._x = RM_SX - _dimx;
|
||||
if (_openStart._y + _dimy > RM_SY)
|
||||
_openStart._y = RM_SY - _dimy;
|
||||
|
||||
// Play the sound effect
|
||||
g_vm->playUtilSFX(0);
|
||||
}
|
||||
|
||||
bool RMInterface::released(const RMPoint &mousepos, RMTonyAction &action) {
|
||||
if (!_bActive)
|
||||
return false;
|
||||
|
||||
_bActive = false;
|
||||
|
||||
switch (onWhichBox(mousepos)) {
|
||||
case 0:
|
||||
action = TA_TAKE;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
action = TA_TALK;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
action = TA_USE;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
action = TA_EXAMINE;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
action = TA_PERORATE;
|
||||
break;
|
||||
|
||||
default: // No verb
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void RMInterface::reset() {
|
||||
_bActive = false;
|
||||
}
|
||||
|
||||
void RMInterface::setPerorate(bool bOn) {
|
||||
_bPerorate = bOn;
|
||||
}
|
||||
|
||||
bool RMInterface::getPerorate() {
|
||||
return _bPerorate;
|
||||
}
|
||||
|
||||
void RMInterface::init() {
|
||||
RMResRaw inter(RES_I_INTERFACE);
|
||||
RMRes pal(RES_I_INTERPPAL);
|
||||
|
||||
setPriority(191);
|
||||
|
||||
RMGfxSourceBuffer::init(inter, inter.width(), inter.height());
|
||||
loadPaletteWA(RES_I_INTERPAL);
|
||||
|
||||
for (int i = 0; i < 5; i++) {
|
||||
RMResRaw part(RES_I_INTERP1 + i);
|
||||
|
||||
_hotzone[i].init(part, part.width(), part.height());
|
||||
_hotzone[i].loadPaletteWA(pal);
|
||||
}
|
||||
|
||||
_hotbbox[0].setRect(126, 123, 159, 208); // Take
|
||||
_hotbbox[1].setRect(90, 130, 125, 186); // About
|
||||
_hotbbox[2].setRect(110, 60, 152, 125);
|
||||
_hotbbox[3].setRect(56, 51, 93, 99);
|
||||
_hotbbox[4].setRect(51, 105, 82, 172);
|
||||
|
||||
_hints[0].setAlignType(RMText::HRIGHT, RMText::VTOP);
|
||||
_hints[1].setAlignType(RMText::HRIGHT, RMText::VTOP);
|
||||
_hints[2].setAlignType(RMText::HRIGHT, RMText::VTOP);
|
||||
_hints[3].setAlignType(RMText::HRIGHT, RMText::VTOP);
|
||||
_hints[4].setAlignType(RMText::HRIGHT, RMText::VTOP);
|
||||
|
||||
// The text is taken from MPAL for translation
|
||||
RMMessage msg0(12);
|
||||
RMMessage msg1(13);
|
||||
RMMessage msg2(14);
|
||||
RMMessage msg3(15);
|
||||
RMMessage msg4(16);
|
||||
|
||||
_hints[0].writeText(msg0[0], 1); // Take
|
||||
_hints[1].writeText(msg1[0], 1); // Talk
|
||||
_hints[2].writeText(msg2[0], 1); // Use
|
||||
_hints[3].writeText(msg3[0], 1); // Examine
|
||||
_hints[4].writeText(msg4[0], 1); // Show Yourself
|
||||
|
||||
_bActive = false;
|
||||
_bPerorate = false;
|
||||
_lastHotZone = 0;
|
||||
}
|
||||
|
||||
void RMInterface::close() {
|
||||
destroy();
|
||||
|
||||
for (int i = 0; i < 5; i++)
|
||||
_hotzone[i].destroy();
|
||||
}
|
||||
|
||||
} // End of namespace Tony
|
||||
241
engines/tony/inventory.h
Normal file
241
engines/tony/inventory.h
Normal file
@@ -0,0 +1,241 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on original Tony Tough source code
|
||||
*
|
||||
* Copyright (c) 1997-2003 Nayma Software
|
||||
*/
|
||||
|
||||
#ifndef TONY_INVENTORY_H
|
||||
#define TONY_INVENTORY_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "common/mutex.h"
|
||||
#include "tony/font.h"
|
||||
#include "tony/game.h"
|
||||
#include "tony/gfxcore.h"
|
||||
#include "tony/loc.h"
|
||||
|
||||
namespace Tony {
|
||||
|
||||
struct RMInventoryItem {
|
||||
RMItem _icon;
|
||||
RMGfxSourceBuffer8RLEByteAA *_pointer;
|
||||
int _status;
|
||||
};
|
||||
|
||||
class RMInventory : public RMGfxWoodyBuffer {
|
||||
private:
|
||||
enum InventoryState {
|
||||
CLOSED,
|
||||
OPENING,
|
||||
OPENED,
|
||||
CLOSING,
|
||||
SELECTING
|
||||
};
|
||||
|
||||
protected:
|
||||
int _nItems;
|
||||
RMInventoryItem *_items;
|
||||
|
||||
int _inv[256];
|
||||
int _nInv;
|
||||
int _curPutY;
|
||||
uint32 _curPutTime;
|
||||
|
||||
int _curPos;
|
||||
InventoryState _state;
|
||||
bool _bHasFocus;
|
||||
int _nSelectObj;
|
||||
int _nCombine;
|
||||
bool _bCombining;
|
||||
|
||||
bool _bBlinkingRight, _bBlinkingLeft;
|
||||
|
||||
int _miniAction;
|
||||
RMItem _miniInterface;
|
||||
RMText _hints[3];
|
||||
|
||||
Common::Mutex _csModifyInterface;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Prepare the image inventory. It should be recalled whenever the inventory changes
|
||||
*/
|
||||
void prepare();
|
||||
|
||||
/**
|
||||
* Check if the mouse Y position is conrrect, even under the inventory portion of the screen
|
||||
*/
|
||||
bool checkPointInside(const RMPoint &pt);
|
||||
|
||||
public:
|
||||
RMInventory();
|
||||
~RMInventory() override;
|
||||
|
||||
/**
|
||||
* Prepare a frame
|
||||
*/
|
||||
void doFrame(RMGfxTargetBuffer &bigBuf, RMPointer &ptr, RMPoint mpos, bool bCanOpen);
|
||||
|
||||
/**
|
||||
* Initialization and closing
|
||||
*/
|
||||
using RMGfxWoodyBuffer::init;
|
||||
void init();
|
||||
void close();
|
||||
void reset();
|
||||
|
||||
/**
|
||||
* Overload test for removal from OT list
|
||||
*/
|
||||
void removeThis(CORO_PARAM, bool &result) override;
|
||||
|
||||
/**
|
||||
* Overload the drawing of the inventory
|
||||
*/
|
||||
void draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim) override;
|
||||
|
||||
/**
|
||||
* Method for determining whether the inventory currently has the focus
|
||||
*/
|
||||
bool haveFocus(const RMPoint &mpos);
|
||||
|
||||
/**
|
||||
* Method for determining if the mini interface is active
|
||||
*/
|
||||
bool miniActive();
|
||||
|
||||
/**
|
||||
* Handle the left mouse click (only when the inventory has the focus)
|
||||
*/
|
||||
bool leftClick(const RMPoint &mpos, int &nCombineObj);
|
||||
|
||||
/**
|
||||
* Handle the right mouse button (only when the inventory has the focus)
|
||||
*/
|
||||
void rightClick(const RMPoint &mpos);
|
||||
bool rightRelease(const RMPoint &mpos, RMTonyAction &curAction);
|
||||
|
||||
/**
|
||||
* Warn that an item combine is over
|
||||
*/
|
||||
void endCombine();
|
||||
|
||||
public:
|
||||
/**
|
||||
* Add an item to the inventory
|
||||
*/
|
||||
void addItem(int code);
|
||||
RMInventory &operator+=(RMItem *item);
|
||||
RMInventory &operator+=(RMItem &item);
|
||||
RMInventory &operator+=(int code);
|
||||
|
||||
/**
|
||||
* Removes an item
|
||||
*/
|
||||
void removeItem(int code);
|
||||
|
||||
/**
|
||||
* We are on an object?
|
||||
*/
|
||||
RMItem *whichItemIsIn(const RMPoint &mpt);
|
||||
bool itemInFocus(const RMPoint &mpt);
|
||||
|
||||
/**
|
||||
* Change the icon of an item
|
||||
*/
|
||||
void changeItemStatus(uint32 dwCode, uint32 dwStatus);
|
||||
|
||||
/**
|
||||
* Save methods
|
||||
*/
|
||||
int getSaveStateSize();
|
||||
void saveState(byte *state);
|
||||
int loadState(byte *state);
|
||||
};
|
||||
|
||||
class RMInterface : public RMGfxSourceBuffer8RLEByte {
|
||||
private:
|
||||
bool _bActive;
|
||||
RMPoint _mpos;
|
||||
RMPoint _openPos;
|
||||
RMPoint _openStart;
|
||||
RMText _hints[5];
|
||||
RMGfxSourceBuffer8RLEByte _hotzone[5];
|
||||
RMRect _hotbbox[5];
|
||||
bool _bPerorate;
|
||||
int _lastHotZone;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Return which box a given point is in
|
||||
*/
|
||||
int onWhichBox(RMPoint pt);
|
||||
|
||||
public:
|
||||
RMInterface();
|
||||
~RMInterface() override;
|
||||
|
||||
/**
|
||||
* The usual DoFrame (poll the graphics engine)
|
||||
*/
|
||||
void doFrame(RMGfxTargetBuffer &bigBuf, RMPoint mousepos);
|
||||
|
||||
/**
|
||||
* TRUE if it is active (you can select items)
|
||||
*/
|
||||
bool active();
|
||||
|
||||
/**
|
||||
* Initialization
|
||||
*/
|
||||
using RMGfxSourceBuffer8RLEByte::init;
|
||||
void init();
|
||||
void close();
|
||||
|
||||
/**
|
||||
* Reset the interface
|
||||
*/
|
||||
void reset();
|
||||
|
||||
/**
|
||||
* Warns of mouse clicks and releases
|
||||
*/
|
||||
void clicked(const RMPoint &mousepos);
|
||||
bool released(const RMPoint &mousepos, RMTonyAction &action);
|
||||
|
||||
/**
|
||||
* Enables or disables the fifth verb
|
||||
*/
|
||||
void setPerorate(bool bOn);
|
||||
bool getPerorate();
|
||||
|
||||
/**
|
||||
* Overloaded Draw
|
||||
*/
|
||||
void draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim) override;
|
||||
};
|
||||
|
||||
} // End of namespace Tony
|
||||
|
||||
#endif
|
||||
2248
engines/tony/loc.cpp
Normal file
2248
engines/tony/loc.cpp
Normal file
File diff suppressed because it is too large
Load Diff
571
engines/tony/loc.h
Normal file
571
engines/tony/loc.h
Normal file
@@ -0,0 +1,571 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on original Tony Tough source code
|
||||
*
|
||||
* Copyright (c) 1997-2003 Nayma Software
|
||||
*/
|
||||
|
||||
#ifndef TONY_LOC_H
|
||||
#define TONY_LOC_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "common/mutex.h"
|
||||
#include "common/file.h"
|
||||
#include "tony/sound.h"
|
||||
#include "tony/utils.h"
|
||||
|
||||
namespace Tony {
|
||||
|
||||
/****************************************************************************\
|
||||
* Various defines
|
||||
\****************************************************************************/
|
||||
|
||||
/**
|
||||
* Valid color modes
|
||||
*/
|
||||
typedef enum {
|
||||
CM_256,
|
||||
CM_65K
|
||||
} RMColorMode;
|
||||
|
||||
/****************************************************************************\
|
||||
* Class declarations
|
||||
\****************************************************************************/
|
||||
|
||||
/**
|
||||
* Generic palette
|
||||
*/
|
||||
class RMPalette {
|
||||
public:
|
||||
byte _data[1024];
|
||||
|
||||
public:
|
||||
void readFromStream(Common::ReadStream &ds);
|
||||
};
|
||||
|
||||
/**
|
||||
* Sound effect of an object
|
||||
*/
|
||||
class RMSfx {
|
||||
public:
|
||||
Common::String _name;
|
||||
FPSfx *_fx;
|
||||
bool _bPlayingLoop;
|
||||
|
||||
public:
|
||||
RMSfx();
|
||||
virtual ~RMSfx();
|
||||
|
||||
void play(bool bLoop = false);
|
||||
void setVolume(int vol);
|
||||
void pause(bool bPause);
|
||||
void stop();
|
||||
|
||||
void readFromStream(Common::ReadStream &ds, bool bLOX = false);
|
||||
};
|
||||
|
||||
/**
|
||||
* Object pattern
|
||||
*/
|
||||
class RMPattern {
|
||||
public:
|
||||
// Type of slot
|
||||
enum RMSlotType {
|
||||
DUMMY1 = 0,
|
||||
DUMMY2,
|
||||
SPRITE,
|
||||
SOUND,
|
||||
COMMAND,
|
||||
SPECIAL
|
||||
};
|
||||
|
||||
// Class slot
|
||||
class RMSlot {
|
||||
private:
|
||||
RMPoint _pos; // Child co-ordinates
|
||||
|
||||
public:
|
||||
RMSlotType _type;
|
||||
int _data;
|
||||
byte _flag;
|
||||
|
||||
public:
|
||||
RMPoint pos() {
|
||||
return _pos;
|
||||
}
|
||||
|
||||
void readFromStream(Common::ReadStream &ds, bool bLOX = false);
|
||||
};
|
||||
|
||||
public:
|
||||
Common::String _name;
|
||||
|
||||
private:
|
||||
int _speed;
|
||||
RMPoint _pos; // Parent coordinates
|
||||
RMPoint _curPos; // Parent + child coordinates
|
||||
int _bLoop;
|
||||
int _nSlots;
|
||||
int _nCurSlot;
|
||||
int _nCurSprite;
|
||||
|
||||
RMSlot *_slots;
|
||||
|
||||
uint32 _nStartTime;
|
||||
|
||||
public:
|
||||
RMPattern();
|
||||
virtual ~RMPattern();
|
||||
|
||||
// A warning that the pattern now and the current
|
||||
int init(RMSfx *sfx, bool bPlayP0 = false, byte *bFlag = NULL);
|
||||
|
||||
// Update the pattern, checking to see if it's time to change slot and executing
|
||||
// any associated commands
|
||||
int update(uint32 hEndPattern, byte &bFlag, RMSfx *sfx);
|
||||
|
||||
// Stop a sound effect
|
||||
void stopSfx(RMSfx *sfx);
|
||||
|
||||
// Reads the position of the pattern
|
||||
RMPoint pos();
|
||||
|
||||
void readFromStream(Common::ReadStream &ds, bool bLOX);
|
||||
|
||||
private:
|
||||
void updateCoord();
|
||||
};
|
||||
|
||||
/**
|
||||
* Sprite (frame) animation of an item
|
||||
*/
|
||||
class RMSprite : public RMGfxTask {
|
||||
public:
|
||||
Common::String _name;
|
||||
RMRect _rcBox;
|
||||
|
||||
protected:
|
||||
RMGfxSourceBuffer *_buf;
|
||||
|
||||
public:
|
||||
RMSprite();
|
||||
~RMSprite() override;
|
||||
|
||||
void init(RMGfxSourceBuffer *buf);
|
||||
void draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim) override;
|
||||
void setPalette(byte *lpBuf);
|
||||
void getSizeFromStream(Common::SeekableReadStream &ds, int *dimx, int *dimy);
|
||||
void LOXGetSizeFromStream(Common::SeekableReadStream &ds, int *dimx, int *dimy);
|
||||
|
||||
void readFromStream(Common::SeekableReadStream &ds, bool bLOX = false);
|
||||
};
|
||||
|
||||
/**
|
||||
* Data on an item
|
||||
*/
|
||||
class RMItem : public RMGfxTask {
|
||||
public:
|
||||
Common::String _name;
|
||||
|
||||
protected:
|
||||
int _z;
|
||||
RMPoint _pos; // Coordinate ancestor
|
||||
RMColorMode _cm;
|
||||
RMPoint _curScroll;
|
||||
|
||||
byte _FX;
|
||||
byte _FXparm;
|
||||
|
||||
virtual int getCurPattern();
|
||||
|
||||
private:
|
||||
int _nCurPattern;
|
||||
int _mpalCode;
|
||||
RMPoint _hot;
|
||||
RMRect _rcBox;
|
||||
int _nSprites, _nSfx, _nPatterns;
|
||||
byte _bPal;
|
||||
RMPalette _pal;
|
||||
|
||||
RMSprite *_sprites;
|
||||
RMSfx *_sfx;
|
||||
RMPattern *_patterns;
|
||||
|
||||
byte _bCurFlag;
|
||||
int _nCurSprite;
|
||||
bool _bIsActive;
|
||||
uint32 _hEndPattern;
|
||||
bool _bInitCurPattern;
|
||||
|
||||
public:
|
||||
RMPoint calculatePos();
|
||||
|
||||
public:
|
||||
RMItem();
|
||||
~RMItem() override;
|
||||
|
||||
// Process to make the object move on any animations.
|
||||
// Returns TRUE if it should be redrawn on the next frame
|
||||
bool doFrame(RMGfxTargetBuffer *bigBuf, bool bAddToList = true);
|
||||
|
||||
// Sets the current scrolling position
|
||||
void setScrollPosition(const RMPoint &scroll);
|
||||
|
||||
// Overloading of check whether to remove from active list
|
||||
void removeThis(CORO_PARAM, bool &result) override;
|
||||
|
||||
// Overloaded Draw
|
||||
void draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim) override;
|
||||
|
||||
// Overloaded priority: it's based on Z ordering
|
||||
int priority() override;
|
||||
|
||||
// Pattern number
|
||||
int numPattern();
|
||||
|
||||
// Set anew animation pattern, changing abruptly from the current
|
||||
virtual void setPattern(int nPattern, bool bPlayP0 = false);
|
||||
|
||||
// Set a new status
|
||||
void setStatus(int nStatus);
|
||||
|
||||
bool isIn(const RMPoint &pt, int *size = NULL);
|
||||
RMPoint getHotspot();
|
||||
bool getName(Common::String &name);
|
||||
int mpalCode();
|
||||
|
||||
// Unload
|
||||
void unload();
|
||||
|
||||
// Wait for the end of the current pattern
|
||||
void waitForEndPattern(CORO_PARAM, uint32 hCustomSkip = CORO_INVALID_PID_VALUE);
|
||||
|
||||
// Sets a new hotspot fro the object
|
||||
void changeHotspot(const RMPoint &pt);
|
||||
|
||||
void setInitCurPattern(bool status);
|
||||
|
||||
void playSfx(int nSfx);
|
||||
|
||||
void readFromStream(Common::SeekableReadStream &ds, bool bLOX = false);
|
||||
|
||||
void pauseSound(bool bPause);
|
||||
|
||||
protected:
|
||||
// Create a primitive that has as it's task this item
|
||||
virtual RMGfxPrimitive *newItemPrimitive();
|
||||
|
||||
// Allocate memory for the sprites
|
||||
virtual RMGfxSourceBuffer *newItemSpriteBuffer(int dimx, int dimy, bool bPreRLE);
|
||||
};
|
||||
|
||||
#define MAXBOXES 50 // Maximum number of allowed boxes
|
||||
#define MAXHOTSPOT 20 // Maximum nimber of allowed hotspots
|
||||
|
||||
class RMBox {
|
||||
public:
|
||||
struct Hotspot {
|
||||
int _hotx, _hoty; // Hotspot coordinates
|
||||
int _destination; // Hotspot destination
|
||||
};
|
||||
|
||||
public:
|
||||
int _left, _top, _right, _bottom; // Vertici bounding boxes
|
||||
int _adj[MAXBOXES]; // List of adjacent bounding boxes
|
||||
int _numHotspot; // Hotspot number
|
||||
uint8 _destZ; // Z value for the bounding box
|
||||
Hotspot _hotspot[MAXHOTSPOT]; // List of hotspots
|
||||
|
||||
bool _bActive;
|
||||
bool _bReversed;
|
||||
|
||||
void readFromStream(Common::ReadStream &ds);
|
||||
};
|
||||
|
||||
class RMBoxLoc {
|
||||
public:
|
||||
int _numbBox;
|
||||
RMBox *_boxes;
|
||||
|
||||
void readFromStream(Common::ReadStream &ds);
|
||||
|
||||
public:
|
||||
RMBoxLoc();
|
||||
virtual ~RMBoxLoc();
|
||||
|
||||
void recalcAllAdj();
|
||||
};
|
||||
|
||||
#define GAME_BOXES_SIZE 200
|
||||
|
||||
class RMGameBoxes {
|
||||
protected:
|
||||
RMBoxLoc *_allBoxes[GAME_BOXES_SIZE];
|
||||
int _nLocBoxes;
|
||||
|
||||
public:
|
||||
RMGameBoxes();
|
||||
~RMGameBoxes();
|
||||
|
||||
void init();
|
||||
void close();
|
||||
|
||||
// Get binding boxes for a given location
|
||||
RMBoxLoc *getBoxes(int nLoc);
|
||||
int getLocBoxesCount() const;
|
||||
|
||||
// Return the box which contains a given point
|
||||
int whichBox(int nLoc, const RMPoint &pt);
|
||||
|
||||
// Check whether a point is inside a given box
|
||||
bool isInBox(int nLoc, int nBox, const RMPoint &pt);
|
||||
|
||||
// Change the status of a box
|
||||
void changeBoxStatus(int nLoc, int nBox, int status);
|
||||
|
||||
// Save state handling
|
||||
int getSaveStateSize();
|
||||
void saveState(byte *buf);
|
||||
void loadState(byte *buf);
|
||||
};
|
||||
|
||||
class RMCharacter : protected RMItem {
|
||||
public:
|
||||
enum Patterns {
|
||||
PAT_STANDUP = 1,
|
||||
PAT_STANDDOWN,
|
||||
PAT_STANDLEFT,
|
||||
PAT_STANDRIGHT,
|
||||
PAT_WALKUP,
|
||||
PAT_WALKDOWN,
|
||||
PAT_WALKLEFT,
|
||||
PAT_WALKRIGHT
|
||||
};
|
||||
|
||||
private:
|
||||
enum CharacterStatus {
|
||||
STAND,
|
||||
WALK
|
||||
};
|
||||
|
||||
signed short _walkCount;
|
||||
int _dx, _dy, _olddx, _olddy;
|
||||
float _fx, _fy, _slope;
|
||||
RMPoint _lineStart, _lineEnd, _pathEnd;
|
||||
signed char _walkSpeed, _walkStatus;
|
||||
char _minPath;
|
||||
short _nextBox;
|
||||
short _path[MAXBOXES];
|
||||
short _pathLength, _pathCount;
|
||||
int _curBox;
|
||||
|
||||
CharacterStatus _status;
|
||||
int _curSpeed;
|
||||
bool _bEndOfPath;
|
||||
uint32 _hEndOfPath;
|
||||
Common::Mutex _csMove;
|
||||
int _curLocation;
|
||||
bool _bRemoveFromOT;
|
||||
bool _bMovingWithoutMinpath;
|
||||
RMGameBoxes *_theBoxes;
|
||||
|
||||
RMPoint _fixedScroll;
|
||||
|
||||
private:
|
||||
int inWhichBox(const RMPoint &pt);
|
||||
|
||||
bool findPath(short source, short destination);
|
||||
RMPoint searching(char UP, char DOWN, char RIGHT, char LEFT, RMPoint point);
|
||||
RMPoint nearestPoint(const RMPoint &punto);
|
||||
|
||||
void goTo(CORO_PARAM, RMPoint destcoord, bool bReversed = false);
|
||||
short scanLine(const RMPoint &point);
|
||||
RMPoint invScanLine(const RMPoint &point);
|
||||
RMPoint nearestHotSpot(int sourcebox, int destbox);
|
||||
|
||||
void newBoxEntered(int nBox);
|
||||
|
||||
protected:
|
||||
bool _bMoving;
|
||||
bool _bDrawNow;
|
||||
bool _bNeedToStop;
|
||||
|
||||
public:
|
||||
RMCharacter();
|
||||
~RMCharacter() override;
|
||||
|
||||
void linkToBoxes(RMGameBoxes *theBoxes);
|
||||
|
||||
void removeThis(CORO_PARAM, bool &result) override;
|
||||
|
||||
// Update the position of a character
|
||||
void doFrame(CORO_PARAM, RMGfxTargetBuffer *bigBuf, int loc);
|
||||
|
||||
// Overloaded draw
|
||||
void draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim) override;
|
||||
|
||||
// TRUE if you just stopped
|
||||
bool endOfPath();
|
||||
|
||||
// Change the pattern of a character to STOP
|
||||
virtual void stop(CORO_PARAM);
|
||||
|
||||
// Check if the character is moving
|
||||
bool isMoving();
|
||||
|
||||
// Move the character to a certain position
|
||||
void move(CORO_PARAM, RMPoint pt, bool *result = NULL);
|
||||
|
||||
// Place the character in a certain position WITHOUT moving
|
||||
void setPosition(const RMPoint &pt, int newloc = -1);
|
||||
|
||||
// Wait for the end of movement
|
||||
void waitForEndMovement(CORO_PARAM);
|
||||
|
||||
void setFixedScroll(const RMPoint &fix);
|
||||
void setSpeed(int speed);
|
||||
};
|
||||
|
||||
class RMWipe : public RMGfxTask {
|
||||
private:
|
||||
bool _bFading;
|
||||
bool _bEndFade;
|
||||
bool _bUnregister;
|
||||
uint32 _hUnregistered;
|
||||
int _nFadeStep;
|
||||
uint32 _hEndOfFade;
|
||||
bool _bMustRegister;
|
||||
|
||||
RMItem _wip0r;
|
||||
|
||||
public:
|
||||
RMWipe();
|
||||
~RMWipe() override;
|
||||
|
||||
void doFrame(RMGfxTargetBuffer &bigBuf);
|
||||
void draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim) override;
|
||||
|
||||
void initFade(int type);
|
||||
void closeFade();
|
||||
void waitForFadeEnd(CORO_PARAM);
|
||||
|
||||
void unregister() override;
|
||||
void removeThis(CORO_PARAM, bool &result) override;
|
||||
int priority() override;
|
||||
};
|
||||
|
||||
/**
|
||||
* Location
|
||||
*/
|
||||
class RMLocation : public RMGfxTaskSetPrior {
|
||||
public:
|
||||
Common::String _name; // Name
|
||||
|
||||
private:
|
||||
RMColorMode _cmode; // Color mode
|
||||
RMGfxSourceBuffer *_buf; // Location picture
|
||||
|
||||
int _nItems; // Number of objects
|
||||
RMItem *_items; // Objects
|
||||
|
||||
RMPoint _curScroll; // Current scroll position
|
||||
RMPoint _fixedScroll;
|
||||
|
||||
RMPoint _prevScroll; // Previous scroll position
|
||||
RMPoint _prevFixedScroll;
|
||||
|
||||
public:
|
||||
// @@@@@@@@@@@@@@@@@@@@@@@
|
||||
|
||||
RMPoint TEMPTonyStart;
|
||||
RMPoint TEMPGetTonyStart();
|
||||
|
||||
int TEMPNumLoc;
|
||||
int TEMPGetNumLoc();
|
||||
|
||||
public:
|
||||
RMLocation();
|
||||
~RMLocation() override;
|
||||
|
||||
// Load variations
|
||||
bool load(Common::SeekableReadStream &ds);
|
||||
bool loadLOX(Common::SeekableReadStream &ds);
|
||||
|
||||
// Unload
|
||||
void unload();
|
||||
|
||||
// Overloaded draw
|
||||
void draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim) override;
|
||||
|
||||
// Prepare a frame by drawing the location and all it's items
|
||||
void doFrame(RMGfxTargetBuffer *bigBuf);
|
||||
|
||||
// Return the item at a given point
|
||||
RMItem *whichItemIsIn(const RMPoint &pt);
|
||||
|
||||
// Return the item based on it's MPAL code
|
||||
RMItem *getItemFromCode(uint32 dwCode);
|
||||
|
||||
// Set the current scroll position
|
||||
void setScrollPosition(const RMPoint &scroll);
|
||||
|
||||
// Sets an additinal offset for scrolling
|
||||
void setFixedScroll(const RMPoint &scroll);
|
||||
|
||||
// Update the scrolling coordinates to display the specified point
|
||||
void updateScrolling(const RMPoint &ptShowThis);
|
||||
|
||||
// Read the current scroll position
|
||||
RMPoint scrollPosition();
|
||||
|
||||
// Pause sound
|
||||
void pauseSound(bool bPause);
|
||||
};
|
||||
|
||||
/**
|
||||
* MPAL message, composed of more ASCIIZ
|
||||
*/
|
||||
class RMMessage {
|
||||
private:
|
||||
char *_lpMessage;
|
||||
char *_lpPeriods[256];
|
||||
int _nPeriods;
|
||||
|
||||
private:
|
||||
void parseMessage();
|
||||
|
||||
public:
|
||||
RMMessage();
|
||||
RMMessage(uint32 dwId);
|
||||
virtual ~RMMessage();
|
||||
|
||||
void load(uint32 dwId);
|
||||
bool isValid();
|
||||
int numPeriods();
|
||||
char *period(int num);
|
||||
char *operator[](int num);
|
||||
};
|
||||
|
||||
} // End of namespace Tony
|
||||
|
||||
#endif /* TONY_H */
|
||||
160
engines/tony/metaengine.cpp
Normal file
160
engines/tony/metaengine.cpp
Normal file
@@ -0,0 +1,160 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "base/plugins.h"
|
||||
|
||||
#include "common/memstream.h"
|
||||
#include "engines/advancedDetector.h"
|
||||
#include "common/system.h"
|
||||
#include "graphics/surface.h"
|
||||
|
||||
#include "tony/tony.h"
|
||||
#include "tony/game.h"
|
||||
#include "tony/detection.h"
|
||||
|
||||
namespace Tony {
|
||||
|
||||
uint32 TonyEngine::getFeatures() const {
|
||||
return _gameDescription->desc.flags;
|
||||
}
|
||||
|
||||
Common::Language TonyEngine::getLanguage() const {
|
||||
return _gameDescription->desc.language;
|
||||
}
|
||||
|
||||
bool TonyEngine::getIsDemo() const {
|
||||
return _gameDescription->desc.flags & ADGF_DEMO;
|
||||
}
|
||||
|
||||
bool TonyEngine::isCompressed() const {
|
||||
return _gameDescription->desc.flags & GF_COMPRESSED;
|
||||
}
|
||||
|
||||
} // End of namespace Tony
|
||||
|
||||
class TonyMetaEngine : public AdvancedMetaEngine<Tony::TonyGameDescription> {
|
||||
public:
|
||||
const char *getName() const override {
|
||||
return "tony";
|
||||
}
|
||||
|
||||
bool hasFeature(MetaEngineFeature f) const override;
|
||||
Common::Error createInstance(OSystem *syst, Engine **engine, const Tony::TonyGameDescription *desc) const override;
|
||||
|
||||
SaveStateList listSaves(const char *target) const override;
|
||||
int getMaximumSaveSlot() const override;
|
||||
bool removeSaveState(const char *target, int slot) const override;
|
||||
SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const override;
|
||||
};
|
||||
|
||||
bool TonyMetaEngine::hasFeature(MetaEngineFeature f) const {
|
||||
return
|
||||
(f == kSupportsListSaves) ||
|
||||
(f == kSupportsLoadingDuringStartup) ||
|
||||
(f == kSupportsDeleteSave) ||
|
||||
(f == kSavesSupportMetaInfo) ||
|
||||
(f == kSimpleSavesNames) ||
|
||||
(f == kSavesSupportThumbnail);
|
||||
}
|
||||
|
||||
bool Tony::TonyEngine::hasFeature(EngineFeature f) const {
|
||||
return
|
||||
(f == kSupportsReturnToLauncher) ||
|
||||
(f == kSupportsLoadingDuringRuntime) ||
|
||||
(f == kSupportsSavingDuringRuntime);
|
||||
}
|
||||
|
||||
Common::Error TonyMetaEngine::createInstance(OSystem *syst, Engine **engine, const Tony::TonyGameDescription *desc) const {
|
||||
*engine = new Tony::TonyEngine(syst,desc);
|
||||
return Common::kNoError;
|
||||
}
|
||||
|
||||
SaveStateList TonyMetaEngine::listSaves(const char *target) const {
|
||||
Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
|
||||
Common::StringArray filenames;
|
||||
Common::String saveDesc;
|
||||
Common::String pattern = "tony.0##";
|
||||
|
||||
filenames = saveFileMan->listSavefiles(pattern);
|
||||
|
||||
SaveStateList saveList;
|
||||
for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) {
|
||||
// Obtain the last 3 digits of the filename, since they correspond to the save slot
|
||||
int slotNum = atoi(file->c_str() + file->size() - 3);
|
||||
|
||||
if (slotNum >= 0 && slotNum <= 999) {
|
||||
byte thumbnailData[160 * 120 * 2];
|
||||
Common::String saveName;
|
||||
byte difficulty;
|
||||
|
||||
if (Tony::RMOptionScreen::loadThumbnailFromSaveState(slotNum, thumbnailData, saveName, difficulty)) {
|
||||
// Add the save name to the savegame list
|
||||
saveList.push_back(SaveStateDescriptor(this, slotNum, saveName));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sort saves based on slot number.
|
||||
Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
|
||||
return saveList;
|
||||
}
|
||||
|
||||
int TonyMetaEngine::getMaximumSaveSlot() const {
|
||||
return 99;
|
||||
}
|
||||
|
||||
bool TonyMetaEngine::removeSaveState(const char *target, int slot) const {
|
||||
Common::String filename = Tony::TonyEngine::getSaveStateFileName(slot);
|
||||
|
||||
return g_system->getSavefileManager()->removeSavefile(filename);
|
||||
}
|
||||
|
||||
SaveStateDescriptor TonyMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
|
||||
Common::String saveName;
|
||||
byte difficulty;
|
||||
|
||||
Graphics::Surface *to = new Graphics::Surface();
|
||||
to->create(160, 120, Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0));
|
||||
|
||||
if (Tony::RMOptionScreen::loadThumbnailFromSaveState(slot, (byte *)to->getPixels(), saveName, difficulty)) {
|
||||
#ifdef SCUMM_BIG_ENDIAN
|
||||
uint16 *pixels = (uint16 *)to->getPixels();
|
||||
for (int i = 0; i < to->w * to->h; ++i)
|
||||
pixels[i] = READ_LE_UINT16(pixels + i);
|
||||
#endif
|
||||
// Create the return descriptor
|
||||
SaveStateDescriptor desc(this, slot, saveName);
|
||||
desc.setDeletableFlag(true);
|
||||
desc.setWriteProtectedFlag(false);
|
||||
desc.setThumbnail(to);
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
delete to;
|
||||
return SaveStateDescriptor();
|
||||
}
|
||||
|
||||
#if PLUGIN_ENABLED_DYNAMIC(TONY)
|
||||
REGISTER_PLUGIN_DYNAMIC(TONY, PLUGIN_TYPE_ENGINE, TonyMetaEngine);
|
||||
#else
|
||||
REGISTER_PLUGIN_STATIC(TONY, PLUGIN_TYPE_ENGINE, TonyMetaEngine);
|
||||
#endif
|
||||
36
engines/tony/module.mk
Normal file
36
engines/tony/module.mk
Normal file
@@ -0,0 +1,36 @@
|
||||
MODULE := engines/tony
|
||||
|
||||
MODULE_OBJS := \
|
||||
custom.o \
|
||||
debugger.o \
|
||||
font.o \
|
||||
game.o \
|
||||
gfxcore.o \
|
||||
gfxengine.o \
|
||||
globals.o \
|
||||
input.o \
|
||||
inventory.o \
|
||||
loc.o \
|
||||
metaengine.o \
|
||||
sound.o \
|
||||
tony.o \
|
||||
tonychar.o \
|
||||
utils.o \
|
||||
window.o \
|
||||
mpal/expr.o \
|
||||
mpal/loadmpc.o \
|
||||
mpal/memory.o \
|
||||
mpal/mpal.o \
|
||||
mpal/mpalutils.o \
|
||||
mpal/lzo.o
|
||||
|
||||
# This module can be built as a plugin
|
||||
ifeq ($(ENABLE_TONY), DYNAMIC_PLUGIN)
|
||||
PLUGIN := 1
|
||||
endif
|
||||
|
||||
# Include common rules
|
||||
include $(srcdir)/rules.mk
|
||||
|
||||
# Detection objects
|
||||
DETECT_OBJS += $(MODULE)/detection.o
|
||||
372
engines/tony/mpal/expr.cpp
Normal file
372
engines/tony/mpal/expr.cpp
Normal file
@@ -0,0 +1,372 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* This code is based on original Tony Tough source code
|
||||
*
|
||||
* Copyright (c) 1997-2003 Nayma Software
|
||||
*/
|
||||
|
||||
#include "tony/mpal/mpal.h"
|
||||
#include "tony/mpal/memory.h"
|
||||
#include "tony/mpal/mpaldll.h"
|
||||
#include "tony/tony.h"
|
||||
|
||||
namespace Tony {
|
||||
|
||||
namespace MPAL {
|
||||
|
||||
static const size_t EXPR_LENGTH_SIZE =
|
||||
#ifndef NO_CXX11_ALIGNAS
|
||||
alignof(max_align_t)
|
||||
#else
|
||||
sizeof(byte)
|
||||
#endif
|
||||
;
|
||||
|
||||
|
||||
/**
|
||||
* Duplicate a mathematical expression.
|
||||
*
|
||||
* @param h Handle to the original expression
|
||||
* @retruns Pointer to the cloned expression
|
||||
*/
|
||||
static void *duplicateExpression(MpalHandle h) {
|
||||
byte *orig, *clone;
|
||||
|
||||
orig = (byte *)globalLock(h);
|
||||
|
||||
int num = *orig;
|
||||
LpExpression one = (LpExpression)(orig + EXPR_LENGTH_SIZE);
|
||||
|
||||
clone = (byte *)globalAlloc(GMEM_FIXED, sizeof(Expression) * num + EXPR_LENGTH_SIZE);
|
||||
LpExpression two = (LpExpression)(clone + EXPR_LENGTH_SIZE);
|
||||
|
||||
memcpy(clone, orig, sizeof(Expression) * num + EXPR_LENGTH_SIZE);
|
||||
|
||||
for (int i = 0; i < num; i++) {
|
||||
if (one->_type == ELT_PARENTH) {
|
||||
two->_type = ELT_PARENTH2;
|
||||
two->_val._pson = duplicateExpression(two->_val._son);
|
||||
}
|
||||
|
||||
++one;
|
||||
++two;
|
||||
}
|
||||
|
||||
globalUnlock(h);
|
||||
return clone;
|
||||
}
|
||||
|
||||
static int32 Compute(int32 a, int32 b, byte symbol) {
|
||||
switch (symbol) {
|
||||
case OP_MUL:
|
||||
return a * b;
|
||||
case OP_DIV:
|
||||
return a / b;
|
||||
case OP_MODULE:
|
||||
return a % b;
|
||||
case OP_ADD:
|
||||
return a + b;
|
||||
case OP_SUB:
|
||||
return a - b;
|
||||
case OP_SHL:
|
||||
return a << b;
|
||||
case OP_SHR:
|
||||
return a >> b;
|
||||
case OP_MINOR:
|
||||
return a < b;
|
||||
case OP_MAJOR:
|
||||
return a > b;
|
||||
case OP_MINEQ:
|
||||
return a <= b;
|
||||
case OP_MAJEQ:
|
||||
return a >= b;
|
||||
case OP_EQUAL:
|
||||
return a == b;
|
||||
case OP_NOEQUAL:
|
||||
return a != b;
|
||||
case OP_BITAND:
|
||||
return a & b;
|
||||
case OP_BITXOR:
|
||||
return a ^ b;
|
||||
case OP_BITOR:
|
||||
return a | b;
|
||||
case OP_AND:
|
||||
return a && b;
|
||||
case OP_OR:
|
||||
return a || b;
|
||||
default:
|
||||
GLOBALS._mpalError = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void solve(LpExpression one, int num) {
|
||||
LpExpression two, three;
|
||||
|
||||
while (num > 1) {
|
||||
two = one + 1;
|
||||
if ((two->_symbol == 0) || (one->_symbol & 0xF0) <= (two->_symbol & 0xF0)) {
|
||||
two->_val._num = Compute(one->_val._num, two->_val._num, one->_symbol);
|
||||
memmove(one, two, (num - 1) * sizeof(Expression));
|
||||
--num;
|
||||
} else {
|
||||
int j = 1;
|
||||
three = two + 1;
|
||||
while ((three->_symbol != 0) && (two->_symbol & 0xF0) > (three->_symbol & 0xF0)) {
|
||||
++two;
|
||||
++three;
|
||||
++j;
|
||||
}
|
||||
|
||||
three->_val._num = Compute(two->_val._num, three->_val._num, two->_symbol);
|
||||
memmove(two, three, (num - j - 1) * sizeof(Expression));
|
||||
--num;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the result of a mathematical expression, replacing the current
|
||||
* value of any variable.
|
||||
*
|
||||
* @param expr Pointer to an expression duplicated by DuplicateExpression
|
||||
* @returns Value
|
||||
*/
|
||||
static int32 evaluateAndFreeExpression(void *expr) {
|
||||
int num = *(byte *)expr;
|
||||
LpExpression one = (LpExpression)((byte *)expr + EXPR_LENGTH_SIZE);
|
||||
|
||||
// 1) Substitutions of variables
|
||||
LpExpression cur = one;
|
||||
for (int i = 0; i < num; i++, cur++) {
|
||||
if (cur->_type == ELT_VAR) {
|
||||
cur->_type = ELT_NUMBER;
|
||||
cur->_val._num = varGetValue(cur->_val._name);
|
||||
}
|
||||
}
|
||||
|
||||
// 2) Replacement of brackets (using recursive calls)
|
||||
cur = one;
|
||||
for (int i = 0; i < num; i++, cur++) {
|
||||
if (cur->_type == ELT_PARENTH2) {
|
||||
cur->_type = ELT_NUMBER;
|
||||
cur->_val._num = evaluateAndFreeExpression(cur->_val._pson);
|
||||
}
|
||||
}
|
||||
|
||||
// 3) algebraic resolution
|
||||
solve(one, num);
|
||||
int32 val = one->_val._num;
|
||||
globalDestroy(expr);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a mathematical expression from the MPC file
|
||||
*
|
||||
* @param buf Buffer containing the expression to evaluate
|
||||
* @param h Pointer to a handle that, at the end of execution,
|
||||
* will point to the area of memory containing the parsed expression
|
||||
* @returns Pointer to the buffer immediately after the expression, or NULL if error.
|
||||
*/
|
||||
const byte *parseExpression(const byte *lpBuf, const Common::UnalignedPtr<MpalHandle> &h) {
|
||||
byte *start;
|
||||
|
||||
byte num = *lpBuf;
|
||||
lpBuf++;
|
||||
|
||||
if (num == 0)
|
||||
return NULL;
|
||||
|
||||
h.store(globalAllocate(GMEM_MOVEABLE | GMEM_ZEROINIT, num * sizeof(Expression) + EXPR_LENGTH_SIZE));
|
||||
if (h.load() == NULL)
|
||||
return NULL;
|
||||
|
||||
start = (byte *)globalLock(h.load());
|
||||
*start = num;
|
||||
|
||||
LpExpression cur = (LpExpression)(start + EXPR_LENGTH_SIZE);
|
||||
|
||||
for (uint32 i = 0;i < num; i++) {
|
||||
cur->_type = *(lpBuf);
|
||||
|
||||
// *(lpBuf + 1) contains the unary operator, unused => skipped
|
||||
lpBuf += 2;
|
||||
|
||||
switch (cur->_type) {
|
||||
case ELT_NUMBER:
|
||||
cur->_val._num = (int32)READ_LE_UINT32(lpBuf);
|
||||
lpBuf += 4;
|
||||
break;
|
||||
|
||||
case ELT_VAR:
|
||||
// As name is a byte, there is no alignment rule
|
||||
cur->_val._name = (char *)globalAlloc(GMEM_FIXED | GMEM_ZEROINIT, (*lpBuf) + 1);
|
||||
if (cur->_val._name == NULL)
|
||||
return NULL;
|
||||
memcpy(cur->_val._name, lpBuf + 1, *lpBuf);
|
||||
lpBuf += *lpBuf + 1;
|
||||
break;
|
||||
|
||||
case ELT_PARENTH:
|
||||
lpBuf = parseExpression(lpBuf, &cur->_val._son);
|
||||
if (lpBuf == NULL)
|
||||
return NULL;
|
||||
break;
|
||||
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cur->_symbol = *lpBuf;
|
||||
lpBuf++;
|
||||
|
||||
cur++;
|
||||
}
|
||||
|
||||
if (*lpBuf != 0)
|
||||
return NULL;
|
||||
|
||||
lpBuf++;
|
||||
|
||||
return lpBuf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the value of a mathematical expression
|
||||
*
|
||||
* @param h Handle to the expression
|
||||
* @returns Numeric value
|
||||
*/
|
||||
int32 evaluateExpression(MpalHandle h) {
|
||||
lockVar();
|
||||
int32 ret = evaluateAndFreeExpression(duplicateExpression(h));
|
||||
unlockVar();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare two mathematical expressions together
|
||||
*
|
||||
* @param h1 Expression to be compared
|
||||
* @param h2 Expression to be compared
|
||||
*/
|
||||
bool compareExpressions(MpalHandle h1, MpalHandle h2) {
|
||||
byte *e1, *e2;
|
||||
|
||||
e1 = (byte *)globalLock(h1);
|
||||
e2 = (byte *)globalLock(h2);
|
||||
|
||||
int num1 = *e1;
|
||||
int num2 = *e2;
|
||||
|
||||
if (num1 != num2) {
|
||||
globalUnlock(h1);
|
||||
globalUnlock(h2);
|
||||
return false;
|
||||
}
|
||||
|
||||
LpExpression one = (LpExpression)(e1 + EXPR_LENGTH_SIZE);
|
||||
LpExpression two = (LpExpression)(e2 + EXPR_LENGTH_SIZE);
|
||||
|
||||
for (int i = 0; i < num1; i++) {
|
||||
if (one->_type != two->_type || (i != num1 - 1 && one->_symbol != two->_symbol)) {
|
||||
globalUnlock(h1);
|
||||
globalUnlock(h2);
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (one->_type) {
|
||||
case ELT_NUMBER:
|
||||
if (one->_val._num != two->_val._num) {
|
||||
globalUnlock(h1);
|
||||
globalUnlock(h2);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case ELT_VAR:
|
||||
if (strcmp(one->_val._name, two->_val._name) != 0) {
|
||||
globalUnlock(h1);
|
||||
globalUnlock(h2);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case ELT_PARENTH:
|
||||
if (!compareExpressions(one->_val._son, two->_val._son)) {
|
||||
globalUnlock(h1);
|
||||
globalUnlock(h2);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
++one;
|
||||
++two;
|
||||
}
|
||||
|
||||
globalUnlock(h1);
|
||||
globalUnlock(h2);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Frees an expression that was previously parsed
|
||||
*
|
||||
* @param h Handle for the expression
|
||||
*/
|
||||
void freeExpression(MpalHandle h) {
|
||||
byte *data = (byte *)globalLock(h);
|
||||
int num = *data;
|
||||
LpExpression cur = (LpExpression)(data + EXPR_LENGTH_SIZE);
|
||||
|
||||
for (int i = 0; i < num; ++i, ++cur) {
|
||||
switch (cur->_type) {
|
||||
case ELT_VAR:
|
||||
globalDestroy(cur->_val._name);
|
||||
break;
|
||||
|
||||
case ELT_PARENTH:
|
||||
freeExpression(cur->_val._son);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
globalUnlock(h);
|
||||
globalFree(h);
|
||||
}
|
||||
|
||||
} // end of namespace MPAL
|
||||
|
||||
} // end of namespace Tony
|
||||
138
engines/tony/mpal/expr.h
Normal file
138
engines/tony/mpal/expr.h
Normal file
@@ -0,0 +1,138 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* This code is based on original Tony Tough source code
|
||||
*
|
||||
* Copyright (c) 1997-2003 Nayma Software
|
||||
*/
|
||||
|
||||
#ifndef MPAL_EXPR_H
|
||||
#define MPAL_EXPR_H
|
||||
|
||||
#include "tony/mpal/memory.h"
|
||||
|
||||
namespace Tony {
|
||||
|
||||
namespace MPAL {
|
||||
|
||||
/**
|
||||
* @defgroup Mathematical operations
|
||||
*/
|
||||
//@{
|
||||
|
||||
#define OP_MUL ((1 << 4) | 0)
|
||||
#define OP_DIV ((1 << 4) | 1)
|
||||
#define OP_MODULE ((1 << 4) | 2)
|
||||
#define OP_ADD ((2 << 4) | 0)
|
||||
#define OP_SUB ((2 << 4) | 1)
|
||||
#define OP_SHL ((3 << 4) | 0)
|
||||
#define OP_SHR ((3 << 4) | 1)
|
||||
#define OP_MINOR ((4 << 4) | 0)
|
||||
#define OP_MAJOR ((4 << 4) | 1)
|
||||
#define OP_MINEQ ((4 << 4) | 2)
|
||||
#define OP_MAJEQ ((4 << 4) | 3)
|
||||
#define OP_EQUAL ((5 << 4) | 0)
|
||||
#define OP_NOEQUAL ((5 << 4) | 1)
|
||||
#define OP_BITAND ((6 << 4) | 0)
|
||||
#define OP_BITXOR ((7 << 4) | 0)
|
||||
#define OP_BITOR ((8 << 4) | 0)
|
||||
#define OP_AND ((9 << 4) | 0)
|
||||
#define OP_OR ((10 << 4) | 0)
|
||||
|
||||
//@}
|
||||
|
||||
/**
|
||||
* @defgroup Structures
|
||||
*/
|
||||
|
||||
//@{
|
||||
/**
|
||||
* Mathematical framework to manage operations
|
||||
*/
|
||||
typedef struct {
|
||||
byte _type; // Object Type (see enum ExprListTypes)
|
||||
|
||||
union {
|
||||
int32 _num; // Identifier (if type == ELT_NUMBER)
|
||||
char *_name; // Variable name (if type == ELT_VAR)
|
||||
MpalHandle _son; // Handle expressions (if type == ELT_PARENTH)
|
||||
void *_pson; // Handle lockato (if type == ELT_PARENTH2)
|
||||
} _val;
|
||||
|
||||
byte _symbol; // Mathematic symbols (see #define OP_*)
|
||||
|
||||
} Expression;
|
||||
typedef Expression *LpExpression;
|
||||
|
||||
//@}
|
||||
|
||||
/**
|
||||
* Object types that can be contained in an EXPRESSION structure
|
||||
*/
|
||||
enum ExprListTypes {
|
||||
ELT_NUMBER = 1,
|
||||
ELT_VAR = 2,
|
||||
ELT_PARENTH = 3,
|
||||
ELT_PARENTH2 = 4
|
||||
};
|
||||
|
||||
/****************************************************************************\
|
||||
* Function Prototypes
|
||||
\****************************************************************************/
|
||||
|
||||
/**
|
||||
* Parses a mathematical expression from the MPC file
|
||||
*
|
||||
* @param buf Buffer containing the expression to evaluate
|
||||
* @param h Pointer to a handle that, at the end of execution,
|
||||
* will point to the area of memory containing the parsed expression
|
||||
* @returns Pointer to the buffer immediately after the expression, or NULL if error.
|
||||
*/
|
||||
const byte *parseExpression(const byte *lpBuf, const Common::UnalignedPtr<MpalHandle> &h);
|
||||
|
||||
/**
|
||||
* Calculate the value of a mathematical expression
|
||||
*
|
||||
* @param h Handle to the expression
|
||||
* @returns Numeric value
|
||||
*/
|
||||
int32 evaluateExpression(MpalHandle h);
|
||||
|
||||
/**
|
||||
* Compare two mathematical expressions together
|
||||
*
|
||||
* @param h1 Expression to be compared
|
||||
* @param h2 Expression to be compared
|
||||
*/
|
||||
bool compareExpressions(MpalHandle h1, MpalHandle h2);
|
||||
|
||||
/**
|
||||
* Frees an expression that was previously parsed
|
||||
*
|
||||
* @param h Handle for the expression
|
||||
*/
|
||||
void freeExpression(MpalHandle h);
|
||||
|
||||
} // end of namespace MPAL
|
||||
|
||||
} // end of namespace Tony
|
||||
|
||||
#endif
|
||||
786
engines/tony/mpal/loadmpc.cpp
Normal file
786
engines/tony/mpal/loadmpc.cpp
Normal file
@@ -0,0 +1,786 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* This code is based on original Tony Tough source code
|
||||
*
|
||||
* Copyright (c) 1997-2003 Nayma Software
|
||||
*/
|
||||
|
||||
#include "mpal.h"
|
||||
#include "mpaldll.h"
|
||||
#include "memory.h"
|
||||
#include "tony/tony.h"
|
||||
|
||||
namespace Tony {
|
||||
|
||||
namespace MPAL {
|
||||
|
||||
/****************************************************************************\
|
||||
* Static functions
|
||||
\****************************************************************************/
|
||||
|
||||
static bool compareCommands(struct Command *cmd1, struct Command *cmd2) {
|
||||
if (cmd1->_type == 2 && cmd2->_type == 2) {
|
||||
if (strcmp(cmd1->_lpszVarName, cmd2->_lpszVarName) == 0 &&
|
||||
compareExpressions(cmd1->_expr, cmd2->_expr))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
} else
|
||||
return (memcmp(cmd1, cmd2, sizeof(struct Command)) == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a script from the MPC file, and inserts its data into a structure
|
||||
*
|
||||
* @param lpBuf Buffer containing the compiled script.
|
||||
* @param lpmsScript Pointer to a structure that will be filled with the
|
||||
* data of the script.
|
||||
* @returns Pointer to the buffer after the item, or NULL on failure.
|
||||
*/
|
||||
static const byte *ParseScript(const byte *lpBuf, LpMpalScript lpmsScript) {
|
||||
lpmsScript->_nObj = (int32)READ_LE_UINT32(lpBuf);
|
||||
lpBuf += 4;
|
||||
|
||||
lpmsScript->_nMoments = READ_LE_UINT16(lpBuf);
|
||||
lpBuf += 2;
|
||||
|
||||
int curCmd = 0;
|
||||
|
||||
for (uint i = 0; i < lpmsScript->_nMoments; i++) {
|
||||
lpmsScript->_moment[i]._dwTime = (int32)READ_LE_UINT32(lpBuf);
|
||||
lpBuf += 4;
|
||||
lpmsScript->_moment[i]._nCmds = *lpBuf;
|
||||
lpBuf++;
|
||||
|
||||
for (int j = 0; j < lpmsScript->_moment[i]._nCmds; j++) {
|
||||
lpmsScript->_command[curCmd]._type = *lpBuf;
|
||||
lpBuf++;
|
||||
switch (lpmsScript->_command[curCmd]._type) {
|
||||
case 1:
|
||||
lpmsScript->_command[curCmd]._nCf = READ_LE_UINT16(lpBuf);
|
||||
lpBuf += 2;
|
||||
lpmsScript->_command[curCmd]._arg1 = (int32)READ_LE_UINT32(lpBuf);
|
||||
lpBuf += 4;
|
||||
lpmsScript->_command[curCmd]._arg2 = (int32)READ_LE_UINT32(lpBuf);
|
||||
lpBuf += 4;
|
||||
lpmsScript->_command[curCmd]._arg3 = (int32)READ_LE_UINT32(lpBuf);
|
||||
lpBuf += 4;
|
||||
lpmsScript->_command[curCmd]._arg4 = (int32)READ_LE_UINT32(lpBuf);
|
||||
lpBuf += 4;
|
||||
break;
|
||||
|
||||
case 2: { // Variable assign
|
||||
int len = *lpBuf;
|
||||
lpBuf++;
|
||||
lpmsScript->_command[curCmd]._lpszVarName = (char *)globalAlloc(GMEM_FIXED | GMEM_ZEROINIT, len + 1);
|
||||
if (lpmsScript->_command[curCmd]._lpszVarName == NULL)
|
||||
return NULL;
|
||||
memcpy(lpmsScript->_command[curCmd]._lpszVarName, lpBuf, len);
|
||||
lpBuf += len;
|
||||
|
||||
lpBuf = parseExpression(lpBuf, &lpmsScript->_command[curCmd]._expr);
|
||||
if (lpBuf == NULL)
|
||||
return NULL;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lpmsScript->_moment[i]._cmdNum[j] = curCmd;
|
||||
curCmd++;
|
||||
}
|
||||
}
|
||||
return lpBuf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Frees a script allocated via a previous call to ParseScript
|
||||
*
|
||||
* @param lpmsScript Pointer to a script structure
|
||||
*/
|
||||
static void FreeScript(LpMpalScript lpmsScript) {
|
||||
for (int i = 0; i < MAX_COMMANDS_PER_SCRIPT && (lpmsScript->_command[i]._type); ++i, ++lpmsScript) {
|
||||
if (lpmsScript->_command[i]._type == 2) {
|
||||
// Variable Assign
|
||||
globalDestroy(lpmsScript->_command[i]._lpszVarName);
|
||||
freeExpression(lpmsScript->_command[i]._expr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a dialog from the MPC file, and inserts its data into a structure
|
||||
*
|
||||
* @param lpBuf Buffer containing the compiled dialog.
|
||||
* @param lpmdDialog Pointer to a structure that will be filled with the
|
||||
* data of the dialog.
|
||||
* @returns Pointer to the buffer after the item, or NULL on failure.
|
||||
*/
|
||||
static const byte *parseDialog(const byte *lpBuf, LpMpalDialog lpmdDialog) {
|
||||
lpmdDialog->_nObj = READ_LE_UINT32(lpBuf);
|
||||
lpBuf += 4;
|
||||
|
||||
// Periods
|
||||
uint32 num = READ_LE_UINT16(lpBuf);
|
||||
lpBuf += 2;
|
||||
|
||||
if (num >= MAX_PERIODS_PER_DIALOG - 1)
|
||||
error("Too much periods in dialog #%d", lpmdDialog->_nObj);
|
||||
|
||||
uint32 i;
|
||||
for (i = 0; i < num; i++) {
|
||||
lpmdDialog->_periodNums[i] = READ_LE_UINT16(lpBuf);
|
||||
lpBuf += 2;
|
||||
lpmdDialog->_periods[i] = globalAllocate(GMEM_MOVEABLE | GMEM_ZEROINIT, *lpBuf + 1);
|
||||
byte *lpLock = (byte *)globalLock(lpmdDialog->_periods[i]);
|
||||
Common::copy(lpBuf + 1, lpBuf + 1 + *lpBuf, lpLock);
|
||||
globalUnlock(lpmdDialog->_periods[i]);
|
||||
lpBuf += (*lpBuf) + 1;
|
||||
}
|
||||
|
||||
lpmdDialog->_periodNums[i] = 0;
|
||||
lpmdDialog->_periods[i] = NULL;
|
||||
|
||||
// Groups
|
||||
num = READ_LE_UINT16(lpBuf);
|
||||
lpBuf += 2;
|
||||
uint32 curCmd = 0;
|
||||
|
||||
if (num >= MAX_GROUPS_PER_DIALOG)
|
||||
error("Too much groups in dialog #%d", lpmdDialog->_nObj);
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
lpmdDialog->_group[i]._num = READ_LE_UINT16(lpBuf);
|
||||
lpBuf += 2;
|
||||
lpmdDialog->_group[i]._nCmds = *lpBuf; lpBuf++;
|
||||
|
||||
if (lpmdDialog->_group[i]._nCmds >= MAX_COMMANDS_PER_GROUP)
|
||||
error("Too much commands in group #%d in dialog #%d", lpmdDialog->_group[i]._num, lpmdDialog->_nObj);
|
||||
|
||||
for (uint32 j = 0; j < lpmdDialog->_group[i]._nCmds; j++) {
|
||||
lpmdDialog->_command[curCmd]._type = *lpBuf;
|
||||
lpBuf++;
|
||||
|
||||
switch (lpmdDialog->_command[curCmd]._type) {
|
||||
// Call custom function
|
||||
case 1:
|
||||
lpmdDialog->_command[curCmd]._nCf = READ_LE_UINT16(lpBuf);
|
||||
lpBuf += 2;
|
||||
lpmdDialog->_command[curCmd]._arg1 = READ_LE_UINT32(lpBuf);
|
||||
lpBuf += 4;
|
||||
lpmdDialog->_command[curCmd]._arg2 = READ_LE_UINT32(lpBuf);
|
||||
lpBuf += 4;
|
||||
lpmdDialog->_command[curCmd]._arg3 = READ_LE_UINT32(lpBuf);
|
||||
lpBuf += 4;
|
||||
lpmdDialog->_command[curCmd]._arg4 = READ_LE_UINT32(lpBuf);
|
||||
lpBuf += 4;
|
||||
break;
|
||||
|
||||
// Variable assign
|
||||
case 2: {
|
||||
uint32 len = *lpBuf;
|
||||
lpBuf++;
|
||||
lpmdDialog->_command[curCmd]._lpszVarName = (char *)globalAlloc(GMEM_FIXED | GMEM_ZEROINIT, len + 1);
|
||||
if (lpmdDialog->_command[curCmd]._lpszVarName == NULL)
|
||||
return NULL;
|
||||
|
||||
Common::copy(lpBuf, lpBuf + len, lpmdDialog->_command[curCmd]._lpszVarName);
|
||||
lpBuf += len;
|
||||
|
||||
lpBuf = parseExpression(lpBuf, &lpmdDialog->_command[curCmd]._expr);
|
||||
if (lpBuf == NULL)
|
||||
return NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
// Do Choice
|
||||
case 3:
|
||||
lpmdDialog->_command[curCmd]._nChoice = READ_LE_UINT16(lpBuf);
|
||||
lpBuf += 2;
|
||||
break;
|
||||
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint32 kk;
|
||||
for (kk = 0;kk < curCmd; kk++) {
|
||||
if (compareCommands(&lpmdDialog->_command[kk], &lpmdDialog->_command[curCmd])) {
|
||||
lpmdDialog->_group[i]._cmdNum[j] = kk;
|
||||
|
||||
// Free any data allocated for the duplictaed command
|
||||
if (lpmdDialog->_command[curCmd]._type == 2) {
|
||||
globalDestroy(lpmdDialog->_command[curCmd]._lpszVarName);
|
||||
freeExpression(lpmdDialog->_command[curCmd]._expr);
|
||||
|
||||
lpmdDialog->_command[curCmd]._lpszVarName = NULL;
|
||||
lpmdDialog->_command[curCmd]._expr = 0;
|
||||
lpmdDialog->_command[curCmd]._type = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (kk == curCmd) {
|
||||
lpmdDialog->_group[i]._cmdNum[j] = curCmd;
|
||||
curCmd++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (curCmd >= MAX_COMMANDS_PER_DIALOG)
|
||||
error("Too much commands in dialog #%d", lpmdDialog->_nObj);
|
||||
|
||||
// Choices
|
||||
num = READ_LE_UINT16(lpBuf);
|
||||
lpBuf += 2;
|
||||
|
||||
if (num >= MAX_CHOICES_PER_DIALOG)
|
||||
error("Too much choices in dialog #%d", lpmdDialog->_nObj);
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
lpmdDialog->_choice[i]._nChoice = READ_LE_UINT16(lpBuf);
|
||||
lpBuf += 2;
|
||||
|
||||
uint32 num2 = *lpBuf++;
|
||||
|
||||
if (num2 >= MAX_SELECTS_PER_CHOICE)
|
||||
error("Too much selects in choice #%d in dialog #%d", lpmdDialog->_choice[i]._nChoice, lpmdDialog->_nObj);
|
||||
|
||||
for (uint32 j = 0; j < num2; j++) {
|
||||
// When
|
||||
switch (*lpBuf++) {
|
||||
case 0:
|
||||
lpmdDialog->_choice[i]._select[j]._when = NULL;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
lpBuf = parseExpression(lpBuf, &lpmdDialog->_choice[i]._select[j]._when);
|
||||
if (lpBuf == NULL)
|
||||
return NULL;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
return NULL;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Attrib
|
||||
lpmdDialog->_choice[i]._select[j]._attr = *lpBuf++;
|
||||
|
||||
// Data
|
||||
lpmdDialog->_choice[i]._select[j]._dwData = READ_LE_UINT32(lpBuf);
|
||||
lpBuf += 4;
|
||||
|
||||
// PlayGroup
|
||||
uint32 num3 = *lpBuf++;
|
||||
|
||||
if (num3 >= MAX_PLAYGROUPS_PER_SELECT)
|
||||
error("Too much playgroups in select #%d in choice #%d in dialog #%d", j, lpmdDialog->_choice[i]._nChoice, lpmdDialog->_nObj);
|
||||
|
||||
for (uint32 z = 0; z < num3; z++) {
|
||||
lpmdDialog->_choice[i]._select[j]._wPlayGroup[z] = READ_LE_UINT16(lpBuf);
|
||||
lpBuf += 2;
|
||||
}
|
||||
|
||||
lpmdDialog->_choice[i]._select[j]._wPlayGroup[num3] = 0;
|
||||
}
|
||||
|
||||
// Mark the last selection
|
||||
lpmdDialog->_choice[i]._select[num2]._dwData = 0;
|
||||
}
|
||||
|
||||
lpmdDialog->_choice[num]._nChoice = 0;
|
||||
|
||||
return lpBuf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an item from the MPC file, and inserts its data into a structure
|
||||
*
|
||||
* @param lpBuf Buffer containing the compiled dialog.
|
||||
* @param lpmiItem Pointer to a structure that will be filled with the
|
||||
* data of the item.
|
||||
* @returns Pointer to the buffer after the item, or NULL on failure.
|
||||
* @remarks It's necessary that the structure that is passed has been
|
||||
* completely initialized to 0 beforehand.
|
||||
*/
|
||||
static const byte *parseItem(const byte *lpBuf, LpMpalItem lpmiItem) {
|
||||
lpmiItem->_nObj = (int32)READ_LE_UINT32(lpBuf);
|
||||
lpBuf += 4;
|
||||
|
||||
byte len = *lpBuf;
|
||||
lpBuf++;
|
||||
memcpy(lpmiItem->_lpszDescribe, lpBuf, MIN((byte)MAX_DESCRIBE_SIZE, len));
|
||||
lpBuf += len;
|
||||
|
||||
if (len >= MAX_DESCRIBE_SIZE)
|
||||
error("Describe too long in item #%d", lpmiItem->_nObj);
|
||||
|
||||
lpmiItem->_nActions=*lpBuf;
|
||||
lpBuf++;
|
||||
|
||||
// Allocation action
|
||||
if (lpmiItem->_nActions > 0)
|
||||
lpmiItem->_action = (ItemAction *)globalAlloc(GMEM_FIXED | GMEM_ZEROINIT, sizeof(struct ItemAction) * (int)lpmiItem->_nActions);
|
||||
|
||||
uint32 curCmd = 0;
|
||||
|
||||
for (uint32 i = 0; i < lpmiItem->_nActions; i++) {
|
||||
lpmiItem->_action[i]._num = *lpBuf;
|
||||
lpBuf++;
|
||||
|
||||
lpmiItem->_action[i]._wParm = READ_LE_UINT16(lpBuf);
|
||||
lpBuf += 2;
|
||||
|
||||
if (lpmiItem->_action[i]._num == 0xFF) {
|
||||
lpmiItem->_action[i]._wTime = READ_LE_UINT16(lpBuf);
|
||||
lpBuf += 2;
|
||||
|
||||
lpmiItem->_action[i]._perc = *lpBuf;
|
||||
lpBuf++;
|
||||
}
|
||||
|
||||
if (*lpBuf == 0) {
|
||||
lpBuf++;
|
||||
lpmiItem->_action[i]._when = NULL;
|
||||
} else {
|
||||
lpBuf++;
|
||||
lpBuf = parseExpression(lpBuf,&lpmiItem->_action[i]._when);
|
||||
if (lpBuf == NULL)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lpmiItem->_action[i]._nCmds=*lpBuf;
|
||||
lpBuf++;
|
||||
|
||||
if (lpmiItem->_action[i]._nCmds >= MAX_COMMANDS_PER_ACTION)
|
||||
error("Too much commands in action #%d in item #%d", lpmiItem->_action[i]._num, lpmiItem->_nObj);
|
||||
|
||||
for (uint32 j = 0; j < lpmiItem->_action[i]._nCmds; j++) {
|
||||
lpmiItem->_command[curCmd]._type = *lpBuf;
|
||||
lpBuf++;
|
||||
switch (lpmiItem->_command[curCmd]._type) {
|
||||
case 1: // Call custom function
|
||||
lpmiItem->_command[curCmd]._nCf = READ_LE_UINT16(lpBuf);
|
||||
lpBuf += 2;
|
||||
lpmiItem->_command[curCmd]._arg1 = (int32)READ_LE_UINT32(lpBuf);
|
||||
lpBuf += 4;
|
||||
lpmiItem->_command[curCmd]._arg2 = (int32)READ_LE_UINT32(lpBuf);
|
||||
lpBuf += 4;
|
||||
lpmiItem->_command[curCmd]._arg3 = (int32)READ_LE_UINT32(lpBuf);
|
||||
lpBuf += 4;
|
||||
lpmiItem->_command[curCmd]._arg4 = (int32)READ_LE_UINT32(lpBuf);
|
||||
lpBuf += 4;
|
||||
break;
|
||||
|
||||
case 2: // Variable assign
|
||||
len = *lpBuf;
|
||||
lpBuf++;
|
||||
lpmiItem->_command[curCmd]._lpszVarName = (char *)globalAlloc(GMEM_FIXED | GMEM_ZEROINIT, len + 1);
|
||||
if (lpmiItem->_command[curCmd]._lpszVarName == NULL)
|
||||
return NULL;
|
||||
memcpy(lpmiItem->_command[curCmd]._lpszVarName, lpBuf, len);
|
||||
lpBuf += len;
|
||||
|
||||
lpBuf = parseExpression(lpBuf, &lpmiItem->_command[curCmd]._expr);
|
||||
if (lpBuf == NULL)
|
||||
return NULL;
|
||||
break;
|
||||
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint32 kk;
|
||||
for (kk = 0; kk < curCmd; kk++) {
|
||||
if (compareCommands(&lpmiItem->_command[kk], &lpmiItem->_command[curCmd])) {
|
||||
lpmiItem->_action[i]._cmdNum[j] = kk;
|
||||
|
||||
// Free any data allocated for the duplictaed command
|
||||
if (lpmiItem->_command[curCmd]._type == 2) {
|
||||
globalDestroy(lpmiItem->_command[curCmd]._lpszVarName);
|
||||
freeExpression(lpmiItem->_command[curCmd]._expr);
|
||||
|
||||
lpmiItem->_command[curCmd]._lpszVarName = NULL;
|
||||
lpmiItem->_command[curCmd]._expr = 0;
|
||||
lpmiItem->_command[curCmd]._type = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (kk == curCmd) {
|
||||
lpmiItem->_action[i]._cmdNum[j] = curCmd;
|
||||
curCmd++;
|
||||
|
||||
if (curCmd >= MAX_COMMANDS_PER_ITEM) {
|
||||
error("Too much commands in item #%d", lpmiItem->_nObj);
|
||||
//curCmd=0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lpmiItem->_dwRes = READ_LE_UINT32(lpBuf);
|
||||
lpBuf += 4;
|
||||
|
||||
return lpBuf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Frees an item parsed from a prior call to ParseItem
|
||||
*
|
||||
* @param lpmiItem Pointer to an item structure
|
||||
*/
|
||||
static void freeItem(LpMpalItem lpmiItem) {
|
||||
// Free the actions
|
||||
if (lpmiItem->_action) {
|
||||
for (int i = 0; i < lpmiItem->_nActions; ++i) {
|
||||
if (lpmiItem->_action[i]._when != 0)
|
||||
freeExpression(lpmiItem->_action[i]._when);
|
||||
}
|
||||
|
||||
globalDestroy(lpmiItem->_action);
|
||||
}
|
||||
|
||||
// Free the commands
|
||||
for (int i = 0; i < MAX_COMMANDS_PER_ITEM && (lpmiItem->_command[i]._type); ++i) {
|
||||
if (lpmiItem->_command[i]._type == 2) {
|
||||
// Variable Assign
|
||||
globalDestroy(lpmiItem->_command[i]._lpszVarName);
|
||||
freeExpression(lpmiItem->_command[i]._expr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a location from the MPC file, and inserts its data into a structure
|
||||
*
|
||||
* @param lpBuf Buffer containing the compiled location.
|
||||
* @param lpmiLocation Pointer to a structure that will be filled with the
|
||||
* data of the location.
|
||||
* @returns Pointer to the buffer after the location, or NULL on failure.
|
||||
*/
|
||||
static const byte *ParseLocation(const byte *lpBuf, LpMpalLocation lpmlLocation) {
|
||||
lpmlLocation->_nObj = (int32)READ_LE_UINT32(lpBuf);
|
||||
lpBuf += 4;
|
||||
lpmlLocation->_dwXlen = READ_LE_UINT16(lpBuf);
|
||||
lpBuf += 2;
|
||||
lpmlLocation->_dwYlen = READ_LE_UINT16(lpBuf);
|
||||
lpBuf += 2;
|
||||
lpmlLocation->_dwPicRes = READ_LE_UINT32(lpBuf);
|
||||
lpBuf += 4;
|
||||
|
||||
return lpBuf;
|
||||
}
|
||||
|
||||
/****************************************************************************\
|
||||
* Exported functions
|
||||
\****************************************************************************/
|
||||
/**
|
||||
* @defgroup Exported functions
|
||||
*/
|
||||
//@{
|
||||
|
||||
/**
|
||||
* Reads and interprets the MPC file, and create structures for various directives
|
||||
* in the global variables
|
||||
*
|
||||
* @param lpBuf Buffer containing the MPC file data, excluding the header.
|
||||
* @returns True if succeeded OK, false if failure.
|
||||
*/
|
||||
bool parseMpc(const byte *lpBuf) {
|
||||
byte *lpTemp;
|
||||
|
||||
// 1. Variables
|
||||
if (lpBuf[0] != 'V' || lpBuf[1] != 'A' || lpBuf[2] != 'R' || lpBuf[3] != 'S')
|
||||
return false;
|
||||
|
||||
lpBuf += 4;
|
||||
GLOBALS._nVars = READ_LE_UINT16(lpBuf);
|
||||
lpBuf += 2;
|
||||
|
||||
GLOBALS._hVars = globalAllocate(GMEM_MOVEABLE | GMEM_ZEROINIT, sizeof(MpalVar) * (uint32)GLOBALS._nVars);
|
||||
if (GLOBALS._hVars == NULL)
|
||||
return false;
|
||||
|
||||
GLOBALS._lpmvVars = (LpMpalVar)globalLock(GLOBALS._hVars);
|
||||
|
||||
for (uint16 i = 0; i < GLOBALS._nVars; i++) {
|
||||
uint16 wLen = *(const byte *)lpBuf;
|
||||
lpBuf++;
|
||||
memcpy(GLOBALS._lpmvVars->_lpszVarName, lpBuf, MIN(wLen, (uint16)32));
|
||||
lpBuf += wLen;
|
||||
GLOBALS._lpmvVars->_dwVal = READ_LE_UINT32(lpBuf);
|
||||
lpBuf += 4;
|
||||
|
||||
lpBuf++; // Skip 'ext'
|
||||
GLOBALS._lpmvVars++;
|
||||
}
|
||||
|
||||
globalUnlock(GLOBALS._hVars);
|
||||
|
||||
// 2. Messages
|
||||
if (lpBuf[0] != 'M' || lpBuf[1] != 'S' || lpBuf[2] != 'G' || lpBuf[3] != 'S')
|
||||
return false;
|
||||
|
||||
lpBuf += 4;
|
||||
GLOBALS._nMsgs = READ_LE_UINT16(lpBuf);
|
||||
lpBuf += 2;
|
||||
|
||||
#ifdef NEED_LOCK_MSGS
|
||||
GLOBALS._hMsgs = globalAllocate(GMEM_MOVEABLE | GMEM_ZEROINIT, sizeof(MpalMsg) * (uint32)GLOBALS._nMsgs);
|
||||
if (GLOBALS._hMsgs == NULL)
|
||||
return false;
|
||||
|
||||
GLOBALS._lpmmMsgs = (LpMpalMsg)globalLock(GLOBALS._hMsgs);
|
||||
#else
|
||||
GLOBALS._lpmmMsgs=(LPMPALMSG)globalAlloc(GMEM_FIXED | GMEM_ZEROINIT, sizeof(MPALMSG) * (uint32)GLOBALS._nMsgs);
|
||||
if (GLOBALS._lpmmMsgs==NULL)
|
||||
return false;
|
||||
#endif
|
||||
|
||||
for (uint16 i = 0; i < GLOBALS._nMsgs; i++) {
|
||||
GLOBALS._lpmmMsgs->_wNum = READ_LE_UINT16(lpBuf);
|
||||
lpBuf += 2;
|
||||
|
||||
uint16 j;
|
||||
for (j = 0; lpBuf[j] != 0;)
|
||||
j += lpBuf[j] + 1;
|
||||
|
||||
GLOBALS._lpmmMsgs->_hText = globalAllocate(GMEM_MOVEABLE | GMEM_ZEROINIT, j + 1);
|
||||
lpTemp = (byte *)globalLock(GLOBALS._lpmmMsgs->_hText);
|
||||
|
||||
for (j = 0; lpBuf[j] != 0;) {
|
||||
memcpy(lpTemp, &lpBuf[j + 1], lpBuf[j]);
|
||||
lpTemp += lpBuf[j];
|
||||
*lpTemp ++= '\0';
|
||||
j += lpBuf[j] + 1;
|
||||
}
|
||||
|
||||
lpBuf += j + 1;
|
||||
*lpTemp = '\0';
|
||||
|
||||
globalUnlock(GLOBALS._lpmmMsgs->_hText);
|
||||
GLOBALS._lpmmMsgs++;
|
||||
}
|
||||
|
||||
#ifdef NEED_LOCK_MSGS
|
||||
globalUnlock(GLOBALS._hMsgs);
|
||||
#endif
|
||||
|
||||
// 3. Objects
|
||||
if (lpBuf[0] != 'O' || lpBuf[1] != 'B' || lpBuf[2] != 'J' || lpBuf[3] != 'S')
|
||||
return false;
|
||||
|
||||
lpBuf += 4;
|
||||
GLOBALS._nObjs = READ_LE_UINT16(lpBuf);
|
||||
lpBuf += 2;
|
||||
|
||||
// Check out the dialogs
|
||||
GLOBALS._nDialogs = 0;
|
||||
GLOBALS._hDialogs = GLOBALS._lpmdDialogs = NULL;
|
||||
if (*((const byte *)lpBuf + 2) == 6 && strncmp((const char *)lpBuf + 3, "Dialog", 6) == 0) {
|
||||
GLOBALS._nDialogs = READ_LE_UINT16(lpBuf);
|
||||
lpBuf += 2;
|
||||
|
||||
GLOBALS._hDialogs = globalAllocate(GMEM_MOVEABLE | GMEM_ZEROINIT, (uint32)GLOBALS._nDialogs * sizeof(MpalDialog));
|
||||
if (GLOBALS._hDialogs == NULL)
|
||||
return false;
|
||||
|
||||
GLOBALS._lpmdDialogs = (LpMpalDialog)globalLock(GLOBALS._hDialogs);
|
||||
|
||||
for (uint16 i = 0; i < GLOBALS._nDialogs; i++) {
|
||||
if ((lpBuf = parseDialog(lpBuf + 7, &GLOBALS._lpmdDialogs[i])) == NULL)
|
||||
return false;
|
||||
}
|
||||
|
||||
globalUnlock(GLOBALS._hDialogs);
|
||||
}
|
||||
|
||||
// Check the items
|
||||
GLOBALS._nItems = 0;
|
||||
GLOBALS._hItems = GLOBALS._lpmiItems = NULL;
|
||||
if (*(lpBuf + 2) == 4 && strncmp((const char *)lpBuf + 3, "Item", 4) == 0) {
|
||||
GLOBALS._nItems = READ_LE_UINT16(lpBuf);
|
||||
lpBuf += 2;
|
||||
|
||||
// Allocate memory and read them in
|
||||
GLOBALS._hItems = globalAllocate(GMEM_MOVEABLE | GMEM_ZEROINIT, (uint32)GLOBALS._nItems * sizeof(MpalItem));
|
||||
if (GLOBALS._hItems == NULL)
|
||||
return false;
|
||||
|
||||
GLOBALS._lpmiItems = (LpMpalItem)globalLock(GLOBALS._hItems);
|
||||
|
||||
for (uint16 i = 0; i < GLOBALS._nItems; i++) {
|
||||
if ((lpBuf = parseItem(lpBuf + 5, &GLOBALS._lpmiItems[i])) == NULL)
|
||||
return false;
|
||||
}
|
||||
|
||||
globalUnlock(GLOBALS._hItems);
|
||||
}
|
||||
|
||||
// Check the locations
|
||||
GLOBALS._nLocations = 0;
|
||||
GLOBALS._hLocations = GLOBALS._lpmlLocations = NULL;
|
||||
if (*(lpBuf + 2) == 8 && strncmp((const char *)lpBuf + 3, "Location", 8) == 0) {
|
||||
GLOBALS._nLocations = READ_LE_UINT16(lpBuf);
|
||||
lpBuf += 2;
|
||||
|
||||
// Allocate memory and read them in
|
||||
GLOBALS._hLocations = globalAllocate(GMEM_MOVEABLE | GMEM_ZEROINIT, (uint32)GLOBALS._nLocations * sizeof(MpalLocation));
|
||||
if (GLOBALS._hLocations == NULL)
|
||||
return false;
|
||||
|
||||
GLOBALS._lpmlLocations = (LpMpalLocation)globalLock(GLOBALS._hLocations);
|
||||
|
||||
for (uint16 i = 0; i < GLOBALS._nLocations; i++) {
|
||||
if ((lpBuf = ParseLocation(lpBuf + 9, &GLOBALS._lpmlLocations[i])) == NULL)
|
||||
return false;
|
||||
}
|
||||
|
||||
globalUnlock(GLOBALS._hLocations);
|
||||
}
|
||||
|
||||
// Check the scripts
|
||||
GLOBALS._nScripts = 0;
|
||||
GLOBALS._hScripts = GLOBALS._lpmsScripts = NULL;
|
||||
if (*(lpBuf + 2) == 6 && strncmp((const char *)lpBuf + 3, "Script", 6) == 0) {
|
||||
GLOBALS._nScripts = READ_LE_UINT16(lpBuf);
|
||||
lpBuf += 2;
|
||||
|
||||
// Allocate memory
|
||||
GLOBALS._hScripts = globalAllocate(GMEM_MOVEABLE | GMEM_ZEROINIT, (uint32)GLOBALS._nScripts * sizeof(MpalScript));
|
||||
if (GLOBALS._hScripts == NULL)
|
||||
return false;
|
||||
|
||||
GLOBALS._lpmsScripts = (LpMpalScript)globalLock(GLOBALS._hScripts);
|
||||
|
||||
for (uint16 i = 0; i < GLOBALS._nScripts; i++) {
|
||||
if ((lpBuf = ParseScript(lpBuf + 7, &GLOBALS._lpmsScripts[i])) == NULL)
|
||||
return false;
|
||||
|
||||
// Sort the various moments of the script
|
||||
//qsort(
|
||||
//GLOBALS.lpmsScripts[i].Moment,
|
||||
//GLOBALS.lpmsScripts[i].nMoments,
|
||||
//sizeof(GLOBALS.lpmsScripts[i].Moment[0]),
|
||||
//(int (*)(const void *, const void *))CompareMoments
|
||||
//);
|
||||
}
|
||||
|
||||
globalUnlock(GLOBALS._hScripts);
|
||||
}
|
||||
|
||||
if (lpBuf[0] != 'E' || lpBuf[1] != 'N' || lpBuf[2] != 'D' || lpBuf[3] != '0')
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free the given dialog
|
||||
*/
|
||||
static void freeDialog(LpMpalDialog lpmdDialog) {
|
||||
// Free the periods
|
||||
for (int i = 0; i < MAX_PERIODS_PER_DIALOG && (lpmdDialog->_periods[i]); ++i)
|
||||
globalFree(lpmdDialog->_periods[i]);
|
||||
|
||||
for (int i = 0; i < MAX_COMMANDS_PER_DIALOG && (lpmdDialog->_command[i]._type); i++) {
|
||||
if (lpmdDialog->_command[i]._type == 2) {
|
||||
// Variable assign
|
||||
globalDestroy(lpmdDialog->_command[i]._lpszVarName);
|
||||
freeExpression(lpmdDialog->_command[i]._expr);
|
||||
}
|
||||
}
|
||||
|
||||
// Free the choices
|
||||
for (int i = 0; i < MAX_CHOICES_PER_DIALOG; ++i) {
|
||||
for (int j = 0; j < MAX_SELECTS_PER_CHOICE; j++) {
|
||||
if (lpmdDialog->_choice[i]._select[j]._when)
|
||||
freeExpression(lpmdDialog->_choice[i]._select[j]._when);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Frees any data allocated from the parsing of the MPC file
|
||||
*/
|
||||
void freeMpc() {
|
||||
// Free variables
|
||||
globalFree(GLOBALS._hVars);
|
||||
|
||||
// Free messages
|
||||
LpMpalMsg lpmmMsgs = (LpMpalMsg)globalLock(GLOBALS._hMsgs);
|
||||
for (int i = 0; i < GLOBALS._nMsgs; i++, ++lpmmMsgs)
|
||||
globalFree(lpmmMsgs->_hText);
|
||||
|
||||
globalUnlock(GLOBALS._hMsgs);
|
||||
globalFree(GLOBALS._hMsgs);
|
||||
|
||||
// Free objects
|
||||
if (GLOBALS._hDialogs) {
|
||||
LpMpalDialog lpmdDialogs = (LpMpalDialog)globalLock(GLOBALS._hDialogs);
|
||||
|
||||
for (int i = 0; i < GLOBALS._nDialogs; i++, ++lpmdDialogs)
|
||||
freeDialog(lpmdDialogs);
|
||||
|
||||
globalFree(GLOBALS._hDialogs);
|
||||
}
|
||||
|
||||
// Free items
|
||||
if (GLOBALS._hItems) {
|
||||
LpMpalItem lpmiItems = (LpMpalItem)globalLock(GLOBALS._hItems);
|
||||
|
||||
for (int i = 0; i < GLOBALS._nItems; ++i, ++lpmiItems)
|
||||
freeItem(lpmiItems);
|
||||
|
||||
globalUnlock(GLOBALS._hItems);
|
||||
globalFree(GLOBALS._hItems);
|
||||
}
|
||||
|
||||
// Free the locations
|
||||
if (GLOBALS._hLocations) {
|
||||
globalFree(GLOBALS._hLocations);
|
||||
}
|
||||
|
||||
// Free the scripts
|
||||
if (GLOBALS._hScripts) {
|
||||
LpMpalScript lpmsScripts = (LpMpalScript)globalLock(GLOBALS._hScripts);
|
||||
|
||||
for (int i = 0; i < GLOBALS._nScripts; ++i, ++lpmsScripts) {
|
||||
FreeScript(lpmsScripts);
|
||||
}
|
||||
|
||||
globalUnlock(GLOBALS._hScripts);
|
||||
}
|
||||
}
|
||||
|
||||
//@}
|
||||
|
||||
} // end of namespace MPAL
|
||||
|
||||
} // end of namespace Tony
|
||||
57
engines/tony/mpal/loadmpc.h
Normal file
57
engines/tony/mpal/loadmpc.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* This code is based on original Tony Tough source code
|
||||
*
|
||||
* Copyright (c) 1997-2003 Nayma Software
|
||||
*/
|
||||
|
||||
#ifndef __LOADMPC_H
|
||||
#define __LOADMPC_H
|
||||
|
||||
namespace Tony {
|
||||
|
||||
namespace MPAL {
|
||||
|
||||
/****************************************************************************\
|
||||
* Function prototypes
|
||||
\****************************************************************************/
|
||||
|
||||
/**
|
||||
* Reads and interprets the MPC file, and create structures for various directives
|
||||
* in the global variables
|
||||
*
|
||||
* @param lpBuf Buffer containing the MPC file data, excluding the header.
|
||||
* @returns True if succeeded OK, false if failure.
|
||||
*/
|
||||
bool parseMpc(const byte *lpBuf);
|
||||
|
||||
/**
|
||||
* Frees any data allocated from the parsing of the MPC file
|
||||
*/
|
||||
void freeMpc();
|
||||
|
||||
} // end of namespace MPAL
|
||||
|
||||
} // end of namespace Tony
|
||||
|
||||
#endif
|
||||
|
||||
220
engines/tony/mpal/lzo.cpp
Normal file
220
engines/tony/mpal/lzo.cpp
Normal file
@@ -0,0 +1,220 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
/* minilzo.c -- mini subset of the LZO real-time data compression library
|
||||
|
||||
This file is part of the LZO real-time data compression library.
|
||||
|
||||
Copyright (C) 2011 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 2010 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 2009 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer
|
||||
All Rights Reserved.
|
||||
|
||||
The LZO library is free software; you can 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.
|
||||
|
||||
The LZO library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with the LZO library; see the file COPYING.
|
||||
If not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
Markus F.X.J. Oberhumer
|
||||
<markus@oberhumer.com>
|
||||
http://www.oberhumer.com/opensource/lzo/
|
||||
*/
|
||||
|
||||
#include "lzo.h"
|
||||
#include "common/textconsole.h"
|
||||
|
||||
namespace Tony {
|
||||
|
||||
namespace MPAL {
|
||||
|
||||
#define pd(a, b) ((uint32) ((a) - (b)))
|
||||
#define TEST_IP (ip < ip_end)
|
||||
|
||||
#define M2_MAX_OFFSET 0x0800
|
||||
|
||||
/**
|
||||
* Decompresses an LZO compressed resource
|
||||
*/
|
||||
int lzo1x_decompress(const byte *in, uint32 in_len, byte *out, uint32 *out_len) {
|
||||
byte *op;
|
||||
const byte *ip;
|
||||
uint32 t = 0;
|
||||
const byte *m_pos;
|
||||
|
||||
const byte * const ip_end = in + in_len;
|
||||
|
||||
*out_len = 0;
|
||||
|
||||
op = out;
|
||||
ip = in;
|
||||
|
||||
if (*ip > 17) {
|
||||
t = *ip++ - 17;
|
||||
if (t < 4)
|
||||
goto match_next;
|
||||
assert(t > 0);
|
||||
do {
|
||||
*op++ = *ip++;
|
||||
} while (--t > 0);
|
||||
goto first_literal_run;
|
||||
}
|
||||
|
||||
while (TEST_IP) {
|
||||
t = *ip++;
|
||||
if (t >= 16)
|
||||
goto match;
|
||||
if (t == 0) {
|
||||
while (*ip == 0) {
|
||||
t += 255;
|
||||
ip++;
|
||||
}
|
||||
t += 15 + *ip++;
|
||||
}
|
||||
assert(t > 0);
|
||||
|
||||
*op++ = *ip++;
|
||||
*op++ = *ip++;
|
||||
*op++ = *ip++;
|
||||
do {
|
||||
*op++ = *ip++;
|
||||
} while (--t > 0);
|
||||
|
||||
first_literal_run:
|
||||
t = *ip++;
|
||||
if (t >= 16)
|
||||
goto match;
|
||||
|
||||
m_pos = op - (1 + M2_MAX_OFFSET);
|
||||
m_pos -= t >> 2;
|
||||
m_pos -= *ip++ << 2;
|
||||
|
||||
*op++ = *m_pos++;
|
||||
*op++ = *m_pos++;
|
||||
*op++ = *m_pos;
|
||||
|
||||
goto match_done;
|
||||
|
||||
do {
|
||||
match:
|
||||
if (t >= 64) {
|
||||
m_pos = op - 1;
|
||||
m_pos -= (t >> 2) & 7;
|
||||
m_pos -= *ip++ << 3;
|
||||
t = (t >> 5) - 1;
|
||||
assert(t > 0);
|
||||
goto copy_match;
|
||||
} else if (t >= 32) {
|
||||
t &= 31;
|
||||
if (t == 0) {
|
||||
while (*ip == 0) {
|
||||
t += 255;
|
||||
ip++;
|
||||
}
|
||||
t += 31 + *ip++;
|
||||
}
|
||||
m_pos = op - 1;
|
||||
m_pos -= (ip[0] >> 2) + (ip[1] << 6);
|
||||
ip += 2;
|
||||
} else if (t >= 16) {
|
||||
m_pos = op;
|
||||
m_pos -= (t & 8) << 11;
|
||||
t &= 7;
|
||||
if (t == 0) {
|
||||
while (*ip == 0) {
|
||||
t += 255;
|
||||
ip++;
|
||||
}
|
||||
t += 7 + *ip++;
|
||||
}
|
||||
m_pos -= (ip[0] >> 2) + (ip[1] << 6);
|
||||
ip += 2;
|
||||
if (m_pos == op)
|
||||
goto eof_found;
|
||||
m_pos -= 0x4000;
|
||||
} else {
|
||||
m_pos = op - 1;
|
||||
m_pos -= t >> 2;
|
||||
m_pos -= *ip++ << 2;
|
||||
*op++ = *m_pos++;
|
||||
*op++ = *m_pos;
|
||||
goto match_done;
|
||||
}
|
||||
|
||||
assert(t > 0);
|
||||
{
|
||||
copy_match:
|
||||
*op++ = *m_pos++;
|
||||
*op++ = *m_pos++;
|
||||
do {
|
||||
*op++ = *m_pos++;
|
||||
} while (--t > 0);
|
||||
}
|
||||
|
||||
match_done:
|
||||
t = ip[-2] & 3;
|
||||
if (t == 0)
|
||||
break;
|
||||
|
||||
match_next:
|
||||
assert(t > 0);
|
||||
assert(t < 4);
|
||||
*op++ = *ip++;
|
||||
if (t > 1) {
|
||||
*op++ = *ip++;
|
||||
if (t > 2)
|
||||
*op++ = *ip++;
|
||||
}
|
||||
t = *ip++;
|
||||
} while (TEST_IP);
|
||||
}
|
||||
|
||||
eof_found:
|
||||
assert(t == 1);
|
||||
*out_len = pd(op, out);
|
||||
return (ip == ip_end ? LZO_E_OK :
|
||||
(ip < ip_end ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN));
|
||||
|
||||
}
|
||||
|
||||
} // end of namespace MPAL
|
||||
} // end of namespace Tony
|
||||
88
engines/tony/mpal/lzo.h
Normal file
88
engines/tony/mpal/lzo.h
Normal file
@@ -0,0 +1,88 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
/* minilzo.c -- mini subset of the LZO real-time data compression library
|
||||
|
||||
This file is part of the LZO real-time data compression library.
|
||||
|
||||
Copyright (C) 2011 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 2010 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 2009 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer
|
||||
All Rights Reserved.
|
||||
|
||||
The LZO library is free software; you can 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.
|
||||
|
||||
The LZO library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with the LZO library; see the file COPYING.
|
||||
If not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
Markus F.X.J. Oberhumer
|
||||
<markus@oberhumer.com>
|
||||
http://www.oberhumer.com/opensource/lzo/
|
||||
*/
|
||||
|
||||
#ifndef TONY_MPAL_LZO_H
|
||||
#define TONY_MPAL_LZO_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
|
||||
namespace Tony {
|
||||
|
||||
namespace MPAL {
|
||||
|
||||
/* Error codes for the compression/decompression functions. Negative
|
||||
* values are errors, positive values will be used for special but
|
||||
* normal events.
|
||||
*/
|
||||
#define LZO_E_OK 0
|
||||
#define LZO_E_INPUT_OVERRUN (-4)
|
||||
#define LZO_E_INPUT_NOT_CONSUMED (-8)
|
||||
|
||||
/**
|
||||
* Decompresses an LZO compressed resource
|
||||
*/
|
||||
int lzo1x_decompress(const byte *src, uint32 src_len, byte *dst, uint32 *dst_len);
|
||||
|
||||
} // end of namespace MPAL
|
||||
} // end of namespace Tony
|
||||
|
||||
#endif /* already included */
|
||||
124
engines/tony/mpal/memory.cpp
Normal file
124
engines/tony/mpal/memory.cpp
Normal file
@@ -0,0 +1,124 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/algorithm.h"
|
||||
#include "common/textconsole.h"
|
||||
#include "tony/mpal/memory.h"
|
||||
|
||||
namespace Tony {
|
||||
|
||||
namespace MPAL {
|
||||
|
||||
/****************************************************************************\
|
||||
* MemoryManager methods
|
||||
\****************************************************************************/
|
||||
|
||||
/**
|
||||
* Allocates a new memory block
|
||||
* @return Returns a MemoryItem instance for the new block
|
||||
*/
|
||||
MpalHandle MemoryManager::allocate(uint32 size, uint flags) {
|
||||
MemoryItem *newItem = (MemoryItem *)malloc(sizeof(MemoryItem) - sizeof(byte[1]) + size);
|
||||
newItem->_id = BLOCK_ID;
|
||||
newItem->_size = size;
|
||||
newItem->_lockCount = 0;
|
||||
|
||||
// If requested, clear the allocated data block
|
||||
if ((flags & GMEM_ZEROINIT) != 0) {
|
||||
byte *dataP = newItem->_data;
|
||||
Common::fill(dataP, dataP + size, 0);
|
||||
}
|
||||
|
||||
return (MpalHandle)newItem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocates a new memory block and returns its data pointer
|
||||
* @return Data pointer to allocated block
|
||||
*/
|
||||
void *MemoryManager::alloc(uint32 size, uint flags) {
|
||||
MemoryItem *item = (MemoryItem *)allocate(size, flags);
|
||||
++item->_lockCount;
|
||||
return &item->_data[0];
|
||||
}
|
||||
|
||||
#define OFFSETOF(type, field) ((size_t) &(((type *) 0)->field))
|
||||
|
||||
/**
|
||||
* Returns a reference to the MemoryItem for a gien byte pointer
|
||||
* @param block Byte pointer
|
||||
*/
|
||||
MemoryItem *MemoryManager::getItem(MpalHandle handle) {
|
||||
MemoryItem *rec = (MemoryItem *)((byte *)handle - OFFSETOF(MemoryItem, _data));
|
||||
assert(rec->_id == BLOCK_ID);
|
||||
return rec;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a size of a memory block given its pointer
|
||||
*/
|
||||
uint32 MemoryManager::getSize(MpalHandle handle) {
|
||||
MemoryItem *item = (MemoryItem *)handle;
|
||||
assert(item->_id == BLOCK_ID);
|
||||
return item->_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Erases a given item
|
||||
*/
|
||||
void MemoryManager::freeBlock(MpalHandle handle) {
|
||||
MemoryItem *item = (MemoryItem *)handle;
|
||||
assert(item->_id == BLOCK_ID);
|
||||
free(item);
|
||||
}
|
||||
|
||||
/**
|
||||
* Erases a given item
|
||||
*/
|
||||
void MemoryManager::destroyItem(MpalHandle handle) {
|
||||
MemoryItem *item = getItem(handle);
|
||||
assert(item->_id == BLOCK_ID);
|
||||
free(item);
|
||||
}
|
||||
|
||||
/**
|
||||
* Locks an item for access
|
||||
*/
|
||||
void *MemoryManager::lockItem(MpalHandle handle) {
|
||||
MemoryItem *item = (MemoryItem *)handle;
|
||||
assert(item->_id == BLOCK_ID);
|
||||
++item->_lockCount;
|
||||
return &item->_data[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlocks a locked item
|
||||
*/
|
||||
void MemoryManager::unlockItem(MpalHandle handle) {
|
||||
MemoryItem *item = (MemoryItem *)handle;
|
||||
assert(item->_id == BLOCK_ID);
|
||||
assert(item->_lockCount > 0);
|
||||
--item->_lockCount;
|
||||
}
|
||||
|
||||
} // end of namespace MPAL
|
||||
|
||||
} // end of namespace Tony
|
||||
79
engines/tony/mpal/memory.h
Normal file
79
engines/tony/mpal/memory.h
Normal file
@@ -0,0 +1,79 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TONY_MPAL_MEMORY
|
||||
#define TONY_MPAL_MEMORY
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "common/list.h"
|
||||
|
||||
namespace Tony {
|
||||
|
||||
namespace MPAL {
|
||||
|
||||
typedef void *MpalHandle;
|
||||
|
||||
struct MemoryItem {
|
||||
uint32 _id;
|
||||
uint32 _size;
|
||||
int _lockCount;
|
||||
#ifndef NO_CXX11_ALIGNAS
|
||||
alignas(max_align_t)
|
||||
#endif
|
||||
byte _data[1];
|
||||
|
||||
// Casting for access to data
|
||||
operator void *() { return &_data[0]; }
|
||||
};
|
||||
|
||||
class MemoryManager {
|
||||
private:
|
||||
static MemoryItem *getItem(MpalHandle handle);
|
||||
public:
|
||||
static MpalHandle allocate(uint32 size, uint flags);
|
||||
static void *alloc(uint32 size, uint flags);
|
||||
static void freeBlock(MpalHandle handle);
|
||||
static void destroyItem(MpalHandle handle);
|
||||
static uint32 getSize(MpalHandle handle);
|
||||
static void *lockItem(MpalHandle handle);
|
||||
static void unlockItem(MpalHandle handle);
|
||||
};
|
||||
|
||||
// defines
|
||||
#define globalAlloc(flags, size) MemoryManager::alloc(size, flags)
|
||||
#define globalAllocate(flags, size) MemoryManager::allocate(size, flags)
|
||||
#define globalFree(handle) MemoryManager::freeBlock(handle)
|
||||
#define globalDestroy(handle) MemoryManager::destroyItem(handle)
|
||||
#define globalLock(handle) MemoryManager::lockItem(handle)
|
||||
#define globalUnlock(handle) MemoryManager::unlockItem(handle)
|
||||
#define globalSize(handle) MemoryManager::getSize(handle)
|
||||
|
||||
#define GMEM_FIXED 1
|
||||
#define GMEM_MOVEABLE 2
|
||||
#define GMEM_ZEROINIT 4
|
||||
|
||||
const uint32 BLOCK_ID = 0x12345678;
|
||||
|
||||
} // end of namespace MPAL
|
||||
|
||||
} // end of namespace Tony
|
||||
|
||||
#endif
|
||||
2096
engines/tony/mpal/mpal.cpp
Normal file
2096
engines/tony/mpal/mpal.cpp
Normal file
File diff suppressed because it is too large
Load Diff
501
engines/tony/mpal/mpal.h
Normal file
501
engines/tony/mpal/mpal.h
Normal file
@@ -0,0 +1,501 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* This code is based on original Tony Tough source code
|
||||
*
|
||||
* Copyright (c) 1997-2003 Nayma Software
|
||||
*/
|
||||
|
||||
/****************************************************************************\
|
||||
* General Introduction
|
||||
\****************************************************************************/
|
||||
|
||||
/*
|
||||
* MPAL (MultiPurpose Adventure Language) is a high level language
|
||||
* for the definition of adventure. Through the use of MPAL you can describe
|
||||
* storyboard the adventure, and then use it with any user interface.
|
||||
* In fact, unlike many other similar products, MPAL is not programmed through
|
||||
* the whole adventure, but are defined only the locations, objects, as they may
|
||||
* interact with each other, etc.. thus making MPAL useful for any type of adventure.
|
||||
*/
|
||||
|
||||
/****************************************************************************\
|
||||
* Structure
|
||||
\****************************************************************************/
|
||||
|
||||
/*
|
||||
* MPAL consists of two main files: MPAL.DLL and MPAL.H
|
||||
* The first is the DLL that contains the code to interface with MPAL
|
||||
* adventures, the second is the header that defines the prototypes
|
||||
* functions. MPAL is compiled for Win32, and it can therefore be used with
|
||||
* any compiler that supports Win32 DLL (Watcom C++, Visual C++,
|
||||
* Delphi, etc.), and therefore compatible with both Windows 95 and Windows NT.
|
||||
*
|
||||
* To use the DLL, and 'obviously need to create a library for symbols to export.
|
||||
*
|
||||
*/
|
||||
|
||||
/****************************************************************************\
|
||||
* Custom Functions
|
||||
\****************************************************************************/
|
||||
|
||||
/*
|
||||
* A custom function and a function specified by the program that uses the
|
||||
* library, to perform the particular code. The custom functions are
|
||||
* retrieved from the library as specified in the source MPAL, and in particular
|
||||
* in defining the behavior of an item with some action.
|
||||
*
|
||||
* To use the custom functions, you need to prepare an array of
|
||||
* pointers to functions (such as using the type casting LPCUSTOMFUNCTION,
|
||||
* (defined below), and pass it as second parameter to mpalInit (). Note you
|
||||
* must specify the size of the array, as elements of pointers and which do not
|
||||
* contain the same: the library will call it only those functions specified in
|
||||
* the source MPAL. It can be useful, for debugging reasons, do not bet
|
||||
* the shares of arrays used to debugging function, to avoid unpleasant crash,
|
||||
* if it has been made an error in source and / or some oversight in the code.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TONY_MPAL_H
|
||||
#define TONY_MPAL_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "common/coroutines.h"
|
||||
#include "common/rect.h"
|
||||
#include "common/str.h"
|
||||
#include "tony/mpal/memory.h"
|
||||
|
||||
namespace Tony {
|
||||
|
||||
namespace MPAL {
|
||||
|
||||
/****************************************************************************\
|
||||
* Macro definitions and structures
|
||||
\****************************************************************************/
|
||||
|
||||
// OK value for the error codes
|
||||
#define OK 0
|
||||
|
||||
#define MAXFRAMES 400 // frame animation of an object
|
||||
#define MAXPATTERN 40 // pattern of animation of an object
|
||||
#define MAXPOLLINGLOCATIONS 64
|
||||
|
||||
#define GETARG(type) va_arg(v, type)
|
||||
|
||||
/**
|
||||
* Macro for use with queries that may refer to X and Y co-ordinates
|
||||
*/
|
||||
enum QueryCoordinates {
|
||||
MPQ_X,
|
||||
MPQ_Y
|
||||
};
|
||||
|
||||
/**
|
||||
* Query can be used with mpalQuery methods. In practice corresponds all claims
|
||||
* that can do at the library
|
||||
*/
|
||||
enum QueryTypes {
|
||||
// General Query
|
||||
MPQ_VERSION = 10,
|
||||
|
||||
MPQ_GLOBAL_VAR = 50,
|
||||
MPQ_RESOURCE,
|
||||
MPQ_MESSAGE,
|
||||
|
||||
// Query on leases
|
||||
MPQ_LOCATION_IMAGE = 100,
|
||||
MPQ_LOCATION_SIZE,
|
||||
|
||||
// Queries about items
|
||||
MPQ_ITEM_LIST = 200,
|
||||
MPQ_ITEM_DATA,
|
||||
MPQ_ITEM_PATTERN,
|
||||
MPQ_ITEM_NAME,
|
||||
MPQ_ITEM_IS_ACTIVE,
|
||||
|
||||
// Query dialog
|
||||
MPQ_DIALOG_PERIOD = 300,
|
||||
MPQ_DIALOG_WAITFORCHOICE,
|
||||
MPQ_DIALOG_SELECTLIST,
|
||||
MPQ_DIALOG_SELECTION,
|
||||
|
||||
// Query execution
|
||||
MPQ_DO_ACTION = 400,
|
||||
MPQ_DO_DIALOG
|
||||
};
|
||||
|
||||
/**
|
||||
* Framework to manage the animation of an item
|
||||
*/
|
||||
typedef struct {
|
||||
char *_frames[MAXFRAMES];
|
||||
Common::Rect _frameslocations[MAXFRAMES];
|
||||
Common::Rect _bbox[MAXFRAMES];
|
||||
short _pattern[MAXPATTERN][MAXFRAMES];
|
||||
short _speed;
|
||||
char _numframe;
|
||||
char _numpattern;
|
||||
char _curframe;
|
||||
char _curpattern;
|
||||
short _destX, _destY;
|
||||
signed char _destZ;
|
||||
short _objectID;
|
||||
} Item;
|
||||
typedef Item *LpItem;
|
||||
|
||||
/**
|
||||
* Define a custom function, to use the language MPAL to perform various controls as a result of an action
|
||||
*/
|
||||
typedef void (*LPCUSTOMFUNCTION)(CORO_PARAM, uint32, uint32, uint32, uint32);
|
||||
typedef LPCUSTOMFUNCTION *LPLPCUSTOMFUNCTION;
|
||||
|
||||
/**
|
||||
*
|
||||
* Define an IRQ of an item that is called when the pattern changes or the status of an item
|
||||
*/
|
||||
typedef void (*LPITEMIRQFUNCTION)(uint32, int, int);
|
||||
typedef LPITEMIRQFUNCTION* LPLPITEMIRQFUNCTION;
|
||||
|
||||
/**
|
||||
* @defgroup Macrofunctions query
|
||||
*
|
||||
* The following are defines used for simplifying calling the mpalQuery variants
|
||||
*/
|
||||
//@{
|
||||
|
||||
/**
|
||||
* Gets the current version of MPAL
|
||||
*
|
||||
* @returns Version number (0x1232 = 1.2.3b)
|
||||
*/
|
||||
#define mpalQueryVersion() \
|
||||
(uint16)mpalQueryDWORD(MPQ_VERSION)
|
||||
|
||||
/**
|
||||
* Gets the numerical value of a global variable
|
||||
*
|
||||
* @param lpszVarName Variable name (ASCIIZ)
|
||||
* @returns Global variable value
|
||||
* @remarks This query was implemented for debugging. The program,
|
||||
* if well designed, should not need to access variables from
|
||||
* within the library.
|
||||
*/
|
||||
#define mpalQueryGlobalVar(lpszVarName) \
|
||||
mpalQueryDWORD(MPQ_GLOBAL_VAR, (const char *)(lpszVarName))
|
||||
|
||||
/**
|
||||
* Provides access to a resource inside the .MPC file
|
||||
*
|
||||
* @param dwResId Resource Id
|
||||
* @returns Handle to a memory area containing the resource, ready for use.
|
||||
*/
|
||||
#define mpalQueryResource(dwResId) \
|
||||
mpalQueryHANDLE(MPQ_RESOURCE, (uint32)(dwResId))
|
||||
|
||||
/**
|
||||
* Returns a message.
|
||||
*
|
||||
* @param nMsg Message number
|
||||
* @returns ASCIIZ message
|
||||
* @remarks The returned pointer must be freed via the memory manager
|
||||
* after use. The message will be in ASCIIZ format.
|
||||
*/
|
||||
#define mpalQueryMessage(nMsg) \
|
||||
(char *)mpalQueryHANDLE(MPQ_MESSAGE, (uint32)(nMsg))
|
||||
|
||||
/**
|
||||
* Provides a location image
|
||||
* @return Returns a picture handle
|
||||
*/
|
||||
#define mpalQueryLocationImage(nLoc) \
|
||||
mpalQueryHANDLE(MPQ_LOCATION_IMAGE, (uint32)(nLoc))
|
||||
|
||||
/**
|
||||
* Request the x or y size of a location in pixels
|
||||
*
|
||||
* @param nLoc Location number
|
||||
* @param dwCoord MPQ_X or MPQ_Y coordinate to retrieve
|
||||
* @returns Size
|
||||
*/
|
||||
#define mpalQueryLocationSize(nLoc, dwCoord) \
|
||||
mpalQueryDWORD(MPQ_LOCATION_SIZE, (uint32)(nLoc), (uint32)(dwCoord))
|
||||
|
||||
/**
|
||||
* Provides the list of objects in a location.
|
||||
*
|
||||
* @param nLoc Location number
|
||||
* @returns List of objects (accessible by Item [0], Item [1], etc.)
|
||||
*/
|
||||
// TODO: Determine if this is endian safe
|
||||
#define mpalQueryItemList(nLoc) \
|
||||
(uint32 *)mpalQueryHANDLE(MPQ_ITEM_LIST, (uint32)(nLoc))
|
||||
|
||||
/**
|
||||
* Provides information on an item
|
||||
*
|
||||
* @param nItem Item number
|
||||
* @returns Structure filled with requested information
|
||||
*/
|
||||
#define mpalQueryItemData(nItem) \
|
||||
(LpItem)mpalQueryHANDLE(MPQ_ITEM_DATA, (uint32)(nItem))
|
||||
|
||||
/**
|
||||
* Provides the current pattern of an item
|
||||
*
|
||||
* @param nItem Item number
|
||||
* @returns Number of animation patterns to be executed.
|
||||
* @remarks By default, the pattern of 0 indicates that we should do nothing.
|
||||
*/
|
||||
#define mpalQueryItemPattern(nItem) \
|
||||
mpalQueryDWORD(MPQ_ITEM_PATTERN, (uint32)(nItem))
|
||||
|
||||
/**
|
||||
* Returns true if an item is active
|
||||
*
|
||||
* @param nItem Item number
|
||||
* @returns TRUE if the item is active, FALSE otherwise
|
||||
*/
|
||||
#define mpalQueryItemIsActive(nItem) \
|
||||
(bool)mpalQueryDWORD(MPQ_ITEM_IS_ACTIVE, (uint32)(nItem))
|
||||
|
||||
/**
|
||||
* Returns the name of an item
|
||||
*
|
||||
* @param nItem Item number
|
||||
* @param lpszName Pointer to a buffer of at least 33 bytes
|
||||
* that will be filled with the name
|
||||
* @remarks If the item is not active (ie. if its status or number
|
||||
* is less than or equal to 0), the string will be empty.
|
||||
*/
|
||||
#define mpalQueryItemName(nItem, lpszName) \
|
||||
mpalQueryHANDLE(MPQ_ITEM_NAME, (uint32)(nItem), (char *)(lpszName))
|
||||
|
||||
/**
|
||||
* Returns a sentence of dialog.
|
||||
*
|
||||
* @param nDialog Dialog number
|
||||
* @param nPeriod Number of words
|
||||
* @returns A pointer to the string of words, or NULL on failure.
|
||||
* @remarks The string must be freed after use using the memory manager.
|
||||
* Unlike normal messages, the sentences of dialogue are formed by a single
|
||||
* string terminated with 0.
|
||||
*/
|
||||
#define mpalQueryDialogPeriod(nPeriod) \
|
||||
(char *)mpalQueryHANDLE(MPQ_DIALOG_PERIOD, (uint32)(nPeriod))
|
||||
|
||||
/**
|
||||
* Wait until the moment in which the need is signaled to make a choice by the user.
|
||||
* @returns Number of choice to be made, or -1 if the dialogue is finished.
|
||||
*/
|
||||
#define mpalQueryDialogWaitForChoice(dwRet) \
|
||||
CORO_INVOKE_2(mpalQueryCORO, MPQ_DIALOG_WAITFORCHOICE, dwRet)
|
||||
|
||||
/**
|
||||
* Requires a list of various options for some choice within the current dialog.
|
||||
*
|
||||
* @param nChoice Choice number
|
||||
* @returns A pointer to an array containing the data matched to each option.
|
||||
* @remarks The figure 'a uint32 specified in the source to which MPAL
|
||||
* You can assign meaning that the more' suits.
|
||||
* The pointer msut be freed after use using the memory memory.
|
||||
*/
|
||||
#define mpalQueryDialogSelectList(nChoice) \
|
||||
(uint32 *)mpalQueryHANDLE(MPQ_DIALOG_SELECTLIST, (uint32)(nChoice))
|
||||
|
||||
/**
|
||||
* Warns the library that the user has selected, in a certain choice of the current dialog,
|
||||
* corresponding option at a certain given.
|
||||
*
|
||||
* @param nChoice Choice number of the choice that was in progress
|
||||
* @param dwData Option that was selected by the user.
|
||||
* @returns TRUE if all OK, FALSE on failure.
|
||||
* @remarks After execution of this query, MPAL continue
|
||||
* Groups according to the execution of the dialogue. And necessary so the game
|
||||
* remains on hold again for another chosen by mpalQueryDialogWaitForChoice ().
|
||||
*/
|
||||
#define mpalQueryDialogSelection(nChoice, dwData) \
|
||||
(bool)mpalQueryDWORD(MPQ_DIALOG_SELECTION, (uint32)(nChoice), (uint32)(dwData))
|
||||
|
||||
#define mpalQueryDialogSelectionDWORD(nChoice, dwData) \
|
||||
mpalQueryDWORD(MPQ_DIALOG_SELECTION, (uint32)(nChoice), (uint32)(dwData))
|
||||
|
||||
/**
|
||||
* Warns the library an action was performed on a Object.
|
||||
* The library will call custom functions, if necessary.
|
||||
*
|
||||
* @param nAction Action number
|
||||
* @param nItem Item number
|
||||
* @param dwParam Action parameter
|
||||
* @returns Handle to the thread that is performing the action, or CORO_INVALID_PID_VALUE
|
||||
* if the action is not defined for the item, or the item is inactive.
|
||||
* @remarks The parameter is used primarily to implement actions
|
||||
* as "U.S." involving two objects together. The action will be executed only
|
||||
* if the item is active, ie if its status is a positive number greater than 0.
|
||||
*/
|
||||
#define mpalQueryDoAction(nAction, nItem, dwParam) \
|
||||
mpalQueryDWORD(MPQ_DO_ACTION, (uint32)(nAction), (uint32)(nItem), (uint32)(dwParam))
|
||||
|
||||
/**
|
||||
* Warns the library a dialogue was required.
|
||||
*
|
||||
* @param nDialog Dialog number
|
||||
* @param nGroup Group number to use
|
||||
* @returns Handle to the thread that is running the box, or
|
||||
* CORO_INVALID_PID_VALUE if the dialogue does not exist.
|
||||
*/
|
||||
#define mpalQueryDoDialog(nDialog, nGroup) \
|
||||
mpalQueryDWORD(MPQ_DO_DIALOG, (uint32)(nDialog), (uint32)(nGroup))
|
||||
|
||||
/**
|
||||
* @defgroup Functions exported to the main game
|
||||
*/
|
||||
//@{
|
||||
|
||||
/**
|
||||
* Initializes the MPAL library, and opens an .MPC file, which will be 'used for all queries
|
||||
* @param lpszMpcFileName Name of the .MPC file, including extension
|
||||
* @param lpszMprFileName Name of the .MPR file, including extension
|
||||
* @param lplpcfArray Array of pointers to custom functions
|
||||
* @returns TRUE if all OK, FALSE on failure
|
||||
*/
|
||||
bool mpalInit(const char *lpszFileName, const char *lpszMprFileName,
|
||||
LPLPCUSTOMFUNCTION lplpcfArray, Common::String *lpcfStrings);
|
||||
|
||||
/**
|
||||
* Frees resources allocated by the MPAL subsystem
|
||||
*/
|
||||
void mpalFree();
|
||||
|
||||
/**
|
||||
* This is a general function to communicate with the library, to request information
|
||||
* about what is in the .MPC file
|
||||
*
|
||||
* @param wQueryType Type of query. The list is in the QueryTypes enum.
|
||||
* @returns 4 bytes depending on the type of query
|
||||
* @remarks This is the specialized version of the original single mpalQuery
|
||||
* method that returns numeric results.
|
||||
*/
|
||||
uint32 mpalQueryDWORD(uint wQueryType, ...);
|
||||
|
||||
/**
|
||||
* This is a general function to communicate with the library, to request information
|
||||
* about what is in the .MPC file
|
||||
*
|
||||
* @param wQueryType Type of query. The list is in the QueryTypes enum.
|
||||
* @returns 4 bytes depending on the type of query
|
||||
* @remarks This is the specialized version of the original single mpalQuery
|
||||
* method that returns a pointer or handle.
|
||||
*/
|
||||
MpalHandle mpalQueryHANDLE(uint wQueryType, ...);
|
||||
|
||||
/**
|
||||
* This is a general function to communicate with the library, to request information
|
||||
* about what is in the .MPC file
|
||||
*
|
||||
* @param wQueryType Type of query. The list is in the QueryTypes enum.
|
||||
* @returns 4 bytes depending on the type of query
|
||||
* @remarks This is the specialized version of the original single mpalQuery
|
||||
* method that needs to run within a co-routine context.
|
||||
*/
|
||||
void mpalQueryCORO(CORO_PARAM, uint16 wQueryType, uint32 *dwRet);
|
||||
|
||||
/**
|
||||
* Execute a script. The script runs on multitasking by a thread.
|
||||
*
|
||||
* @param nScript Script number to run
|
||||
* @returns TRUE if the script 'was launched, FALSE on failure
|
||||
*/
|
||||
bool mpalExecuteScript(int nScript);
|
||||
|
||||
/**
|
||||
* Returns the current MPAL error code
|
||||
*
|
||||
* @returns Error code
|
||||
*/
|
||||
uint32 mpalGetError();
|
||||
|
||||
/**
|
||||
* Install a custom routine That will be called by MPAL every time the pattern
|
||||
* of an item has been changed.
|
||||
*
|
||||
* @param lpiifCustom Custom function to install
|
||||
*/
|
||||
void mpalInstallItemIrq(LPITEMIRQFUNCTION lpiifCustom);
|
||||
|
||||
/**
|
||||
* Process the idle actions of the items on one location.
|
||||
*
|
||||
* @param nLoc Number of the location whose items must be processed
|
||||
* for idle actions.
|
||||
* @returns TRUE if all OK, and FALSE if it exceeded the maximum limit.
|
||||
* @remarks The maximum number of locations that can be polled
|
||||
* simultaneously is defined defined by MAXPOLLINGFUNCIONS
|
||||
*/
|
||||
bool mpalStartIdlePoll(int nLoc);
|
||||
|
||||
/**
|
||||
* Stop processing the idle actions of the items on one location.
|
||||
*
|
||||
* @param nLo Number of the location
|
||||
* @returns TRUE if all OK, FALSE if the specified location was not
|
||||
* in the process of polling
|
||||
*/
|
||||
void mpalEndIdlePoll(CORO_PARAM, int nLoc, bool *result);
|
||||
|
||||
/**
|
||||
* Load a save state from a buffer.
|
||||
*
|
||||
* @param buf Buffer where to store the state
|
||||
* @returns Length of the state buffer in bytes
|
||||
*/
|
||||
int mpalLoadState(byte *buf);
|
||||
|
||||
/**
|
||||
* Store the save state into a buffer. The buffer must be
|
||||
* length at least the size specified with mpalGetSaveStateSize
|
||||
*
|
||||
* @param buf Buffer where to store the state
|
||||
*/
|
||||
void mpalSaveState(byte *buf);
|
||||
|
||||
/**
|
||||
* Retrieve the length of a save state
|
||||
*
|
||||
* @returns Length in bytes
|
||||
*/
|
||||
int mpalGetSaveStateSize();
|
||||
|
||||
/**
|
||||
* Locks the variables for access
|
||||
*/
|
||||
void lockVar();
|
||||
|
||||
/**
|
||||
* Unlocks variables after use
|
||||
*/
|
||||
void unlockVar();
|
||||
|
||||
} // end of namespace MPAL
|
||||
|
||||
} // end of namespace Tony
|
||||
|
||||
#endif
|
||||
|
||||
246
engines/tony/mpal/mpaldll.h
Normal file
246
engines/tony/mpal/mpaldll.h
Normal file
@@ -0,0 +1,246 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* This code is based on original Tony Tough source code
|
||||
*
|
||||
* Copyright (c) 1997-2003 Nayma Software
|
||||
*/
|
||||
|
||||
#ifndef __MPALDLL_H
|
||||
#define __MPALDLL_H
|
||||
|
||||
#include "common/file.h"
|
||||
#include "tony/mpal/memory.h"
|
||||
#include "tony/mpal/loadmpc.h"
|
||||
#include "tony/mpal/expr.h"
|
||||
|
||||
namespace Tony {
|
||||
|
||||
namespace MPAL {
|
||||
|
||||
/****************************************************************************\
|
||||
* Defines
|
||||
\****************************************************************************/
|
||||
|
||||
#define HEX_VERSION 0x0170
|
||||
|
||||
#define MAX_ACTIONS_PER_ITEM 40
|
||||
#define MAX_COMMANDS_PER_ITEM 128
|
||||
#define MAX_COMMANDS_PER_ACTION 128
|
||||
#define MAX_DESCRIBE_SIZE 64
|
||||
|
||||
#define MAX_MOMENTS_PER_SCRIPT 256
|
||||
#define MAX_COMMANDS_PER_SCRIPT 256
|
||||
#define MAX_COMMANDS_PER_MOMENT 32
|
||||
|
||||
#define MAX_GROUPS_PER_DIALOG 128
|
||||
#define MAX_COMMANDS_PER_DIALOG 480
|
||||
#define MAX_COMMANDS_PER_GROUP 64
|
||||
#define MAX_CHOICES_PER_DIALOG 64
|
||||
#define MAX_SELECTS_PER_CHOICE 64
|
||||
#define MAX_PLAYGROUPS_PER_SELECT 9
|
||||
#define MAX_PERIODS_PER_DIALOG 400
|
||||
|
||||
#define NEED_LOCK_MSGS
|
||||
|
||||
/****************************************************************************\
|
||||
* Structures
|
||||
\****************************************************************************/
|
||||
|
||||
#include "common/pack-start.h"
|
||||
|
||||
/**
|
||||
* MPAL global variables
|
||||
*/
|
||||
struct MpalVar {
|
||||
uint32 _dwVal; // Variable value
|
||||
char _lpszVarName[33]; // Variable name
|
||||
} PACKED_STRUCT;
|
||||
typedef MpalVar *LpMpalVar;
|
||||
|
||||
/**
|
||||
* MPAL Messages
|
||||
*/
|
||||
struct MpalMsg {
|
||||
MpalHandle _hText; // Handle to the message text
|
||||
uint16 _wNum; // Message number
|
||||
} PACKED_STRUCT;
|
||||
typedef MpalMsg *LpMpalMsg;
|
||||
|
||||
/**
|
||||
* MPAL Locations
|
||||
*/
|
||||
struct MpalLocation {
|
||||
uint32 _nObj; // Location number
|
||||
uint32 _dwXlen, _dwYlen; // Dimensions
|
||||
uint32 _dwPicRes; // Resource that contains the image
|
||||
} PACKED_STRUCT;
|
||||
typedef MpalLocation *LpMpalLocation;
|
||||
|
||||
/**
|
||||
* All the data for a command, ie. tags used by OnAction in the item, the time
|
||||
* in the script, and in the group dialog.
|
||||
*/
|
||||
struct Command {
|
||||
/*
|
||||
* Types of commands that are recognized
|
||||
*
|
||||
* #1 -> Custom function call (ITEM, SCRIPT, DIALOG)
|
||||
* #2 -> Variable assignment (ITEM, SCRIPT, DIALOG)
|
||||
* #3 -> Making a choice (DIALOG)
|
||||
*
|
||||
*/
|
||||
byte _type; // Type of control
|
||||
|
||||
union {
|
||||
int32 _nCf; // Custom function call [#1]
|
||||
char *_lpszVarName; // Variable name [#2]
|
||||
int32 _nChoice; // Number of choice you make [#3]
|
||||
};
|
||||
|
||||
union {
|
||||
int32 _arg1; // Argument for custom function [#1]
|
||||
MpalHandle _expr; // Expression to assign to a variable [#2]
|
||||
};
|
||||
|
||||
int32 _arg2, _arg3, _arg4; // Arguments for custom function [#1]
|
||||
} PACKED_STRUCT;
|
||||
|
||||
/**
|
||||
* MPAL dialog
|
||||
*/
|
||||
struct MpalDialog {
|
||||
uint32 _nObj; // Dialog number
|
||||
|
||||
struct Command _command[MAX_COMMANDS_PER_DIALOG];
|
||||
|
||||
struct {
|
||||
uint16 _num;
|
||||
byte _nCmds;
|
||||
uint16 _cmdNum[MAX_COMMANDS_PER_GROUP];
|
||||
|
||||
} _group[MAX_GROUPS_PER_DIALOG];
|
||||
|
||||
struct {
|
||||
// The last choice has nChoice == 0
|
||||
uint16 _nChoice;
|
||||
|
||||
// The select number (we're pretty stingy with RAM). The last select has dwData == 0
|
||||
struct {
|
||||
MpalHandle _when;
|
||||
uint32 _dwData;
|
||||
uint16 _wPlayGroup[MAX_PLAYGROUPS_PER_SELECT];
|
||||
|
||||
// Bit 0=endchoice Bit 1=enddialog
|
||||
byte _attr;
|
||||
|
||||
// Modified at run-time: 0 if the select is currently disabled,
|
||||
// and 1 if currently active
|
||||
byte _curActive;
|
||||
} _select[MAX_SELECTS_PER_CHOICE];
|
||||
|
||||
} _choice[MAX_CHOICES_PER_DIALOG];
|
||||
|
||||
uint16 _periodNums[MAX_PERIODS_PER_DIALOG];
|
||||
MpalHandle _periods[MAX_PERIODS_PER_DIALOG];
|
||||
|
||||
} PACKED_STRUCT;
|
||||
typedef MpalDialog *LpMpalDialog;
|
||||
|
||||
/**
|
||||
* MPAL Item
|
||||
*/
|
||||
struct ItemAction {
|
||||
byte _num; // Action number
|
||||
uint16 _wTime; // If idle, the time which must pass
|
||||
byte _perc; // Percentage of the idle run
|
||||
MpalHandle _when; // Expression to compute. If != 0, then action can be done
|
||||
uint16 _wParm; // Parameter for action
|
||||
|
||||
byte _nCmds; // Number of commands to be executed
|
||||
uint32 _cmdNum[MAX_COMMANDS_PER_ACTION]; // Commands to execute
|
||||
} PACKED_STRUCT;
|
||||
|
||||
struct MpalItem {
|
||||
uint32 _nObj; // Item number
|
||||
|
||||
byte _lpszDescribe[MAX_DESCRIBE_SIZE]; // Name
|
||||
byte _nActions; // Number of managed actions
|
||||
uint32 _dwRes; // Resource that contains frames and patterns
|
||||
|
||||
struct Command _command[MAX_COMMANDS_PER_ITEM];
|
||||
|
||||
// Pointer to array of structures containing various managed activities. In practice, of
|
||||
// every action we know what commands to run, including those defined in structures above
|
||||
struct ItemAction *_action;
|
||||
|
||||
} PACKED_STRUCT;
|
||||
typedef MpalItem *LpMpalItem;
|
||||
|
||||
/**
|
||||
* MPAL Script
|
||||
*/
|
||||
struct MpalScript {
|
||||
uint32 _nObj;
|
||||
uint32 _nMoments;
|
||||
|
||||
struct Command _command[MAX_COMMANDS_PER_SCRIPT];
|
||||
|
||||
struct {
|
||||
int32 _dwTime;
|
||||
byte _nCmds;
|
||||
uint32 _cmdNum[MAX_COMMANDS_PER_MOMENT];
|
||||
|
||||
} _moment[MAX_MOMENTS_PER_SCRIPT];
|
||||
|
||||
} PACKED_STRUCT;
|
||||
typedef MpalScript *LpMpalScript;
|
||||
|
||||
#include "common/pack-end.h"
|
||||
|
||||
/****************************************************************************\
|
||||
* Function prototypes
|
||||
\****************************************************************************/
|
||||
|
||||
/**
|
||||
* Returns the current value of a global variable
|
||||
*
|
||||
* @param lpszVarName Name of the variable
|
||||
* @returns Current value
|
||||
* @remarks Before using this method, you must call LockVar() to
|
||||
* lock the global variablves for use. Then afterwards, you will
|
||||
* need to remember to call UnlockVar()
|
||||
*/
|
||||
extern int32 varGetValue(const char *lpszVarName);
|
||||
|
||||
/**
|
||||
* Sets the value of a MPAL global variable
|
||||
* @param lpszVarName Name of the variable
|
||||
* @param val Value to set
|
||||
*/
|
||||
extern void varSetValue(const char *lpszVarName, int32 val);
|
||||
|
||||
} // end of namespace MPAL
|
||||
|
||||
} // end of namespace Tony
|
||||
|
||||
#endif
|
||||
|
||||
115
engines/tony/mpal/mpalutils.cpp
Normal file
115
engines/tony/mpal/mpalutils.cpp
Normal file
@@ -0,0 +1,115 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "tony/mpal/mpalutils.h"
|
||||
#include "tony/tony.h"
|
||||
#include "common/memstream.h"
|
||||
|
||||
namespace Tony {
|
||||
|
||||
namespace MPAL {
|
||||
|
||||
/****************************************************************************\
|
||||
* RMRes methods
|
||||
\****************************************************************************/
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param resId MPAL resource to open
|
||||
*/
|
||||
RMRes::RMRes(uint32 resID) {
|
||||
_buf = NULL;
|
||||
|
||||
_h = g_vm->_resUpdate.queryResource(resID);
|
||||
if (_h == NULL)
|
||||
_h = mpalQueryResource(resID);
|
||||
if (_h != NULL)
|
||||
_buf = (byte *)globalLock(_h);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
RMRes::~RMRes() {
|
||||
if (_h != NULL) {
|
||||
globalUnlock(_h);
|
||||
globalFree(_h);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a pointer to the resource
|
||||
*/
|
||||
const byte *RMRes::dataPointer() {
|
||||
return _buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a pointer to the resource
|
||||
*/
|
||||
RMRes::operator const byte *() {
|
||||
return dataPointer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size of the resource
|
||||
*/
|
||||
unsigned int RMRes::size() {
|
||||
return globalSize(_h);
|
||||
}
|
||||
|
||||
Common::SeekableReadStream *RMRes::getReadStream() {
|
||||
return new Common::MemoryReadStream(_buf, size());
|
||||
}
|
||||
|
||||
bool RMRes::isValid() {
|
||||
return _h != NULL;
|
||||
}
|
||||
|
||||
/****************************************************************************\
|
||||
* RMResRaw methods
|
||||
\****************************************************************************/
|
||||
|
||||
RMResRaw::RMResRaw(uint32 resID) : RMRes(resID) {
|
||||
}
|
||||
|
||||
RMResRaw::~RMResRaw() {
|
||||
}
|
||||
|
||||
const byte *RMResRaw::dataPointer() {
|
||||
return _buf + 8;
|
||||
}
|
||||
|
||||
RMResRaw::operator const byte *() {
|
||||
return dataPointer();
|
||||
}
|
||||
|
||||
int RMResRaw::width() {
|
||||
return READ_LE_UINT16(_buf + 4);
|
||||
}
|
||||
|
||||
int RMResRaw::height() {
|
||||
return READ_LE_UINT16(_buf + 6);
|
||||
}
|
||||
|
||||
} // end of namespace MPAL
|
||||
|
||||
} // end of namespace Tony
|
||||
72
engines/tony/mpal/mpalutils.h
Normal file
72
engines/tony/mpal/mpalutils.h
Normal file
@@ -0,0 +1,72 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TONY_MPAL_MPALUTILS
|
||||
#define TONY_MPAL_MPALUTILS
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "tony/mpal/memory.h"
|
||||
|
||||
namespace Common {
|
||||
class SeekableReadStream;
|
||||
}
|
||||
|
||||
namespace Tony {
|
||||
|
||||
namespace MPAL {
|
||||
|
||||
class RMRes {
|
||||
protected:
|
||||
MpalHandle _h;
|
||||
byte *_buf;
|
||||
|
||||
public:
|
||||
RMRes(uint32 resID);
|
||||
virtual ~RMRes();
|
||||
|
||||
// Attributes
|
||||
unsigned int size();
|
||||
const byte *dataPointer();
|
||||
bool isValid();
|
||||
|
||||
// Casting for access to data
|
||||
operator const byte*();
|
||||
|
||||
Common::SeekableReadStream *getReadStream();
|
||||
};
|
||||
|
||||
class RMResRaw : public RMRes {
|
||||
public:
|
||||
RMResRaw(uint32 resID);
|
||||
~RMResRaw() override;
|
||||
|
||||
const byte *dataPointer();
|
||||
operator const byte*();
|
||||
|
||||
int width();
|
||||
int height();
|
||||
};
|
||||
|
||||
} // end of namespace MPAL
|
||||
|
||||
} // end of namespace Tony
|
||||
|
||||
#endif
|
||||
69
engines/tony/resid.h
Normal file
69
engines/tony/resid.h
Normal file
@@ -0,0 +1,69 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on original Tony Tough source code
|
||||
*
|
||||
* Copyright (c) 1997-2003 Nayma Software
|
||||
*/
|
||||
|
||||
// From 10500 onwards there are .OGG for inventory and scrap
|
||||
#ifndef TONY_RESID_H
|
||||
#define TONY_RESID_H
|
||||
|
||||
#define RES_I_INTERFACE 10300
|
||||
#define RES_I_INTERPAL 10301
|
||||
#define RES_I_INTERPPAL 10302
|
||||
#define RES_I_INTERP1 10303
|
||||
#define RES_I_INTERP2 10304
|
||||
#define RES_I_INTERP3 10305
|
||||
#define RES_I_INTERP4 10306
|
||||
#define RES_I_INTERP5 10307
|
||||
|
||||
#define RES_I_DLGTEXT 10350
|
||||
#define RES_I_DLGTEXTLINE 10351
|
||||
#define RES_I_DLGTEXTPAL 10352
|
||||
|
||||
#define RES_I_MINIINTER 10360
|
||||
|
||||
#define RES_P_PAL 10410
|
||||
#define RES_P_GO 10400
|
||||
#define RES_P_TAKE 10401
|
||||
#define RES_P_USE 10402
|
||||
#define RES_P_EXAM 10403
|
||||
#define RES_P_TALK 10404
|
||||
|
||||
#define RES_P_PAP1 10420
|
||||
#define RES_P_PAP2 10421
|
||||
#define RES_P_PAP3 10422
|
||||
#define RES_P_PAP4 10423
|
||||
#define RES_P_FRMAP 10424
|
||||
|
||||
#define RES_F_PAL 10700
|
||||
#define RES_F_PARL 10701
|
||||
#define RES_F_OBJ 10702
|
||||
#define RES_F_MACC 10703
|
||||
#define RES_F_CREDITS 10704
|
||||
#define RES_F_CPAL 10705
|
||||
|
||||
#define RES_W_CIRCLE 10800
|
||||
|
||||
#endif
|
||||
778
engines/tony/sound.cpp
Normal file
778
engines/tony/sound.cpp
Normal file
@@ -0,0 +1,778 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on original Tony Tough source code
|
||||
*
|
||||
* Copyright (c) 1997-2003 Nayma Software
|
||||
*/
|
||||
|
||||
#include "audio/audiostream.h"
|
||||
#include "audio/decoders/adpcm.h"
|
||||
#include "audio/decoders/flac.h"
|
||||
#include "audio/decoders/mp3.h"
|
||||
#include "audio/decoders/vorbis.h"
|
||||
#include "audio/decoders/wave.h"
|
||||
#include "common/textconsole.h"
|
||||
#include "tony/game.h"
|
||||
#include "tony/tony.h"
|
||||
|
||||
namespace Tony {
|
||||
|
||||
/*
|
||||
* Tony uses a [0,63] volume scale (where 0 is silent and 63 is loudest).
|
||||
* The original game engine linearly mapped this scale into DirectSound's
|
||||
* [-10000, 0] scale (where -10000 is silent), which is a logarithmic scale.
|
||||
*
|
||||
* This means that Tony's scale is logarithmic as well, and must be converted
|
||||
* to the linear scale used by the mixer.
|
||||
*/
|
||||
static int remapVolume(int volume) {
|
||||
double dsvol = (double)(63 - volume) * -10000.0 / 63.0;
|
||||
return (int)((double)Audio::Mixer::kMaxChannelVolume * pow(10.0, dsvol / 2000.0) + 0.5);
|
||||
}
|
||||
|
||||
// Another obvious rip from gob engine. Hi DrMcCoy!
|
||||
Common::Path setExtension(const Common::String &str, const Common::String &ext) {
|
||||
if (str.empty())
|
||||
return Common::Path();
|
||||
|
||||
const char *dot = strrchr(str.c_str(), '.');
|
||||
if (dot)
|
||||
return Common::Path(str.c_str(), dot - str.c_str()).appendInPlace(ext);
|
||||
|
||||
return Common::Path(str + ext);
|
||||
}
|
||||
|
||||
/****************************************************************************\
|
||||
* FPSOUND Methods
|
||||
\****************************************************************************/
|
||||
|
||||
/**
|
||||
* Default constructor. Initializes the attributes.
|
||||
*
|
||||
*/
|
||||
FPSound::FPSound() {
|
||||
_soundSupported = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the object, and prepare everything you need to create streams and sound effects.
|
||||
*
|
||||
* @returns True is everything is OK, False otherwise
|
||||
*/
|
||||
bool FPSound::init() {
|
||||
_soundSupported = g_system->getMixer()->isReady();
|
||||
return _soundSupported;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy the object and free the memory
|
||||
*
|
||||
*/
|
||||
FPSound::~FPSound() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocates an object of type FPStream, and return its pointer
|
||||
*
|
||||
* @param streamPtr Will contain a pointer to the object you just created.
|
||||
*
|
||||
* @returns True is everything is OK, False otherwise
|
||||
*/
|
||||
bool FPSound::createStream(FPStream **streamPtr) {
|
||||
(*streamPtr) = new FPStream(_soundSupported);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocates an object of type FpSfx, and return its pointer
|
||||
*
|
||||
* @param soundPtr Will contain a pointer to the object you just created.
|
||||
*
|
||||
* @returns True is everything is OK, False otherwise
|
||||
*/
|
||||
bool FPSound::createSfx(FPSfx **sfxPtr) {
|
||||
(*sfxPtr) = new FPSfx(_soundSupported);
|
||||
|
||||
return (*sfxPtr != NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the general volume
|
||||
*
|
||||
* @param volume Volume to set (0-63)
|
||||
*/
|
||||
void FPSound::setMasterVolume(int volume) {
|
||||
if (!_soundSupported)
|
||||
return;
|
||||
|
||||
// WORKAROUND: We don't use remapVolume() here, so that the main option screen exposes
|
||||
// a linear scale to the user. This is an improvement over the original game
|
||||
// where the user had to deal with a logarithmic volume scale.
|
||||
g_system->getMixer()->setVolumeForSoundType(Audio::Mixer::kPlainSoundType, CLIP<int>(volume, 0, 63) * Audio::Mixer::kMaxChannelVolume / 63);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the general volume
|
||||
*
|
||||
* @param volumePtr Variable that will contain the volume (0-63)
|
||||
*/
|
||||
void FPSound::getMasterVolume(int *volumePtr) {
|
||||
if (!_soundSupported)
|
||||
return;
|
||||
|
||||
*volumePtr = g_system->getMixer()->getVolumeForSoundType(Audio::Mixer::kPlainSoundType) * 63 / Audio::Mixer::kMaxChannelVolume;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*
|
||||
* @remarks Do *NOT* declare an object directly, but rather
|
||||
* create it using FPSound::CreateSfx()
|
||||
*
|
||||
*/
|
||||
FPSfx::FPSfx(bool soundOn) {
|
||||
_soundSupported = soundOn;
|
||||
_fileLoaded = false;
|
||||
_lastVolume = 63;
|
||||
_hEndOfBuffer = CoroScheduler.createEvent(true, false);
|
||||
_isVoice = false;
|
||||
_loopStream = 0;
|
||||
_rewindableStream = 0;
|
||||
_paused = false;
|
||||
_loop = 0;
|
||||
|
||||
g_vm->_activeSfx.push_back(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Default Destructor.
|
||||
*
|
||||
* @remarks It is also stops the sound effect that may be
|
||||
* currently played, and free the memory it uses.
|
||||
*
|
||||
*/
|
||||
FPSfx::~FPSfx() {
|
||||
if (!_soundSupported)
|
||||
return;
|
||||
|
||||
g_system->getMixer()->stopHandle(_handle);
|
||||
g_vm->_activeSfx.remove(this);
|
||||
|
||||
if (_loopStream)
|
||||
delete _loopStream; // _rewindableStream is deleted by deleting _loopStream
|
||||
else
|
||||
delete _rewindableStream;
|
||||
|
||||
// Free the buffer end event
|
||||
CoroScheduler.closeEvent(_hEndOfBuffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases the memory used by the object.
|
||||
*
|
||||
* @remarks Must be called when the object is no longer used and
|
||||
* **ONLY** if the object was created by
|
||||
* FPSound::CreateStream().
|
||||
* Object pointers are no longer valid after this call.
|
||||
*/
|
||||
void FPSfx::release() {
|
||||
delete this;
|
||||
}
|
||||
|
||||
bool FPSfx::loadWave(Common::SeekableReadStream *stream) {
|
||||
if (!stream)
|
||||
return false;
|
||||
|
||||
_rewindableStream = Audio::makeWAVStream(stream, DisposeAfterUse::YES);
|
||||
|
||||
if (!_rewindableStream)
|
||||
return false;
|
||||
|
||||
_fileLoaded = true;
|
||||
setVolume(_lastVolume);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FPSfx::loadVoiceFromVDB(Common::File &vdbFP) {
|
||||
if (!_soundSupported)
|
||||
return true;
|
||||
|
||||
switch (g_vm->_vdbCodec) {
|
||||
case FPCODEC_ADPCM: {
|
||||
uint32 size = vdbFP.readUint32LE();
|
||||
uint32 rate = vdbFP.readUint32LE();
|
||||
|
||||
_rewindableStream = Audio::makeADPCMStream(vdbFP.readStream(size), DisposeAfterUse::YES, 0, Audio::kADPCMDVI, rate, 1);
|
||||
}
|
||||
break;
|
||||
case FPCODEC_MP3 : {
|
||||
#ifdef USE_MAD
|
||||
uint32 size = vdbFP.readUint32LE();
|
||||
_rewindableStream = Audio::makeMP3Stream(vdbFP.readStream(size), DisposeAfterUse::YES);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case FPCODEC_OGG : {
|
||||
#ifdef USE_VORBIS
|
||||
uint32 size = vdbFP.readUint32LE();
|
||||
_rewindableStream = Audio::makeVorbisStream(vdbFP.readStream(size), DisposeAfterUse::YES);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case FPCODEC_FLAC : {
|
||||
#ifdef USE_FLAC
|
||||
uint32 size = vdbFP.readUint32LE();
|
||||
_rewindableStream = Audio::makeFLACStream(vdbFP.readStream(size), DisposeAfterUse::YES);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
_isVoice = true;
|
||||
_fileLoaded = true;
|
||||
setVolume(62);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a file and loads a sound effect.
|
||||
*
|
||||
* @param fileName Sfx filename
|
||||
*
|
||||
* @returns True is everything is OK, False otherwise
|
||||
*/
|
||||
bool FPSfx::loadFile(const char *fileName) {
|
||||
if (!_soundSupported)
|
||||
return true;
|
||||
|
||||
SoundCodecs codec = FPCODEC_UNKNOWN;
|
||||
|
||||
Common::File file;
|
||||
if (file.open(fileName))
|
||||
codec = FPCODEC_ADPCM;
|
||||
else if (file.open(setExtension(fileName, ".MP3")))
|
||||
codec = FPCODEC_MP3;
|
||||
else if (file.open(setExtension(fileName, ".OGG")))
|
||||
codec = FPCODEC_OGG;
|
||||
else if (file.open(setExtension(fileName, ".FLA")))
|
||||
codec = FPCODEC_FLAC;
|
||||
else {
|
||||
warning("FPSfx::LoadFile(): Cannot open sfx file!");
|
||||
return false;
|
||||
}
|
||||
|
||||
Common::SeekableReadStream *buffer;
|
||||
switch (codec) {
|
||||
case FPCODEC_ADPCM: {
|
||||
if (file.readUint32BE() != MKTAG('A', 'D', 'P', 0x10)) {
|
||||
warning("FPSfx::LoadFile(): Invalid ADP header!");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32 rate = file.readUint32LE();
|
||||
uint32 channels = file.readUint32LE();
|
||||
|
||||
buffer = file.readStream(file.size() - file.pos());
|
||||
_rewindableStream = Audio::makeADPCMStream(buffer, DisposeAfterUse::YES, 0, Audio::kADPCMDVI, rate, channels);
|
||||
}
|
||||
break;
|
||||
case FPCODEC_MP3:
|
||||
#ifdef USE_MAD
|
||||
buffer = file.readStream(file.size());
|
||||
_rewindableStream = Audio::makeMP3Stream(buffer, DisposeAfterUse::YES);
|
||||
#endif
|
||||
break;
|
||||
case FPCODEC_OGG:
|
||||
#ifdef USE_VORBIS
|
||||
buffer = file.readStream(file.size());
|
||||
_rewindableStream = Audio::makeVorbisStream(buffer, DisposeAfterUse::YES);
|
||||
#endif
|
||||
break;
|
||||
case FPCODEC_FLAC:
|
||||
buffer = file.readStream(file.size());
|
||||
#ifdef USE_FLAC
|
||||
_rewindableStream = Audio::makeFLACStream(buffer, DisposeAfterUse::YES);
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
_fileLoaded = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Play the Sfx in memory.
|
||||
*
|
||||
* @returns True is everything is OK, False otherwise
|
||||
*/
|
||||
bool FPSfx::play() {
|
||||
stop(); // sanity check
|
||||
|
||||
if (_fileLoaded) {
|
||||
CoroScheduler.resetEvent(_hEndOfBuffer);
|
||||
|
||||
_rewindableStream->rewind();
|
||||
|
||||
Audio::AudioStream *stream = _rewindableStream;
|
||||
|
||||
if (_loop) {
|
||||
if (!_loopStream)
|
||||
_loopStream = Audio::makeLoopingAudioStream(_rewindableStream, 0);
|
||||
|
||||
stream = _loopStream;
|
||||
}
|
||||
|
||||
g_system->getMixer()->playStream(Audio::Mixer::kPlainSoundType, &_handle, stream, -1,
|
||||
Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO);
|
||||
|
||||
setVolume(_lastVolume);
|
||||
|
||||
if (_paused)
|
||||
g_system->getMixer()->pauseHandle(_handle, true);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops a Sfx.
|
||||
*
|
||||
* @returns True is everything is OK, False otherwise
|
||||
*/
|
||||
bool FPSfx::stop() {
|
||||
if (_fileLoaded) {
|
||||
g_system->getMixer()->stopHandle(_handle);
|
||||
_paused = false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables or disables the Sfx loop.
|
||||
*
|
||||
* @param loop True to enable the loop, False to disable
|
||||
*
|
||||
* @remarks The loop must be activated BEFORE the sfx starts
|
||||
* playing. Any changes made during the play will have
|
||||
* no effect until the sfx is stopped then played again.
|
||||
*/
|
||||
void FPSfx::setLoop(bool loop) {
|
||||
_loop = loop;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pauses a Sfx.
|
||||
*
|
||||
*/
|
||||
void FPSfx::setPause(bool pause) {
|
||||
if (_fileLoaded) {
|
||||
if (g_system->getMixer()->isSoundHandleActive(_handle) && (pause ^ _paused))
|
||||
g_system->getMixer()->pauseHandle(_handle, pause);
|
||||
|
||||
_paused = pause;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the volume of Sfx
|
||||
*
|
||||
* @param volume Volume to be set (0-63)
|
||||
*
|
||||
*/
|
||||
void FPSfx::setVolume(int volume) {
|
||||
volume = CLIP(volume, 0, 63);
|
||||
|
||||
_lastVolume = volume;
|
||||
|
||||
if (_isVoice) {
|
||||
if (!GLOBALS._bCfgDubbing)
|
||||
volume = 0;
|
||||
else {
|
||||
volume -= (10 - GLOBALS._nCfgDubbingVolume) * 2;
|
||||
if (volume < 0)
|
||||
volume = 0;
|
||||
}
|
||||
} else {
|
||||
if (!GLOBALS._bCfgSFX)
|
||||
volume = 0;
|
||||
else {
|
||||
volume -= (10 - GLOBALS._nCfgSFXVolume) * 2;
|
||||
if (volume < 0)
|
||||
volume = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (g_system->getMixer()->isSoundHandleActive(_handle))
|
||||
g_system->getMixer()->setChannelVolume(_handle, remapVolume(volume));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Sfx volume
|
||||
*
|
||||
* @param volumePtr Will contain the current Sfx volume
|
||||
*
|
||||
*/
|
||||
void FPSfx::getVolume(int *volumePtr) {
|
||||
if (g_system->getMixer()->isSoundHandleActive(_handle))
|
||||
*volumePtr = _lastVolume;
|
||||
else
|
||||
*volumePtr = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the underlying sound has ended
|
||||
*/
|
||||
bool FPSfx::endOfBuffer() const {
|
||||
return !g_system->getMixer()->isSoundHandleActive(_handle) && (!_rewindableStream || _rewindableStream->endOfData());
|
||||
}
|
||||
|
||||
/**
|
||||
* Continually checks to see if active sounds have finished playing
|
||||
* Sets the event signalling the sound has ended
|
||||
*/
|
||||
void FPSfx::soundCheckProcess(CORO_PARAM, const void *param) {
|
||||
CORO_BEGIN_CONTEXT;
|
||||
Common::List<FPSfx *>::iterator i;
|
||||
CORO_END_CONTEXT(_ctx);
|
||||
|
||||
CORO_BEGIN_CODE(_ctx);
|
||||
|
||||
for (;;) {
|
||||
// Check each active sound
|
||||
for (_ctx->i = g_vm->_activeSfx.begin(); _ctx->i != g_vm->_activeSfx.end(); ++_ctx->i) {
|
||||
FPSfx *sfx = *_ctx->i;
|
||||
if (sfx->endOfBuffer())
|
||||
CoroScheduler.setEvent(sfx->_hEndOfBuffer);
|
||||
}
|
||||
|
||||
// Delay until the next check is done
|
||||
CORO_INVOKE_1(CoroScheduler.sleep, 50);
|
||||
}
|
||||
|
||||
CORO_END_CODE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*
|
||||
* @remarks Do *NOT* declare an object directly, but rather
|
||||
* create it using FPSound::CreateStream()
|
||||
*/
|
||||
FPStream::FPStream(bool soundOn) {
|
||||
_soundSupported = soundOn;
|
||||
_fileLoaded = false;
|
||||
_paused = false;
|
||||
_loop = false;
|
||||
_doFadeOut = false;
|
||||
_syncExit = false;
|
||||
_bufferSize = _size = 0;
|
||||
_lastVolume = 0;
|
||||
_syncToPlay = NULL;
|
||||
_loopStream = NULL;
|
||||
_rewindableStream = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default destructor.
|
||||
*
|
||||
* @remarks It calls CloseFile() if needed.
|
||||
*/
|
||||
FPStream::~FPStream() {
|
||||
if (!_soundSupported)
|
||||
return;
|
||||
|
||||
if (g_system->getMixer()->isSoundHandleActive(_handle))
|
||||
stop();
|
||||
|
||||
if (_fileLoaded)
|
||||
unloadFile();
|
||||
|
||||
_syncToPlay = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases the memory object.
|
||||
*
|
||||
* @remarks Must be called when the object is no longer used
|
||||
* and **ONLY** if the object was created by
|
||||
* FPSound::CreateStream().
|
||||
* Object pointers are no longer valid after this call.
|
||||
*/
|
||||
void FPStream::release() {
|
||||
delete this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a file stream
|
||||
*
|
||||
* @param fileName Filename to be opened
|
||||
* @param bufSize Buffer size
|
||||
*
|
||||
* @returns True is everything is OK, False otherwise
|
||||
*/
|
||||
bool FPStream::loadFile(const Common::String &fileName, int bufSize) {
|
||||
if (!_soundSupported)
|
||||
return true;
|
||||
|
||||
if (_fileLoaded)
|
||||
unloadFile();
|
||||
|
||||
SoundCodecs codec = FPCODEC_UNKNOWN;
|
||||
|
||||
// Open the file stream for reading
|
||||
if (_file.open(Common::Path(fileName)))
|
||||
codec = FPCODEC_ADPCM;
|
||||
else if (_file.open(setExtension(fileName, ".MP3")))
|
||||
codec = FPCODEC_MP3;
|
||||
else if (_file.open(setExtension(fileName, ".OGG")))
|
||||
codec = FPCODEC_OGG;
|
||||
else if (_file.open(setExtension(fileName, ".FLA")))
|
||||
codec = FPCODEC_FLAC;
|
||||
// Fallback: try with an extra '0' prefix
|
||||
else if (_file.open(Common::Path("0" + fileName))) {
|
||||
codec = FPCODEC_ADPCM;
|
||||
warning("FPStream::loadFile(): Fallback from %s to %s", fileName.c_str(), _file.getName());
|
||||
} else if (_file.open(setExtension("0" + fileName, ".MP3"))) {
|
||||
codec = FPCODEC_MP3;
|
||||
warning("FPStream::loadFile(): Fallback from %s to %s", fileName.c_str(), _file.getName());
|
||||
} else if (_file.open(setExtension("0" + fileName, ".OGG"))) {
|
||||
codec = FPCODEC_OGG;
|
||||
warning("FPStream::loadFile(): Fallback from %s to %s", fileName.c_str(), _file.getName());
|
||||
} else if (_file.open(setExtension("0" + fileName, ".FLA"))) {
|
||||
codec = FPCODEC_FLAC;
|
||||
warning("FPStream::loadFile(): Fallback from %s to %s", fileName.c_str(), _file.getName());
|
||||
} else
|
||||
return false;
|
||||
|
||||
// Save the size of the stream
|
||||
_size = _file.size();
|
||||
|
||||
switch (codec) {
|
||||
case FPCODEC_ADPCM:
|
||||
_rewindableStream = Audio::makeADPCMStream(&_file, DisposeAfterUse::NO, 0, Audio::kADPCMDVI, 44100, 2);
|
||||
break;
|
||||
case FPCODEC_MP3:
|
||||
#ifdef USE_MAD
|
||||
_rewindableStream = Audio::makeMP3Stream(&_file, DisposeAfterUse::NO);
|
||||
#endif
|
||||
break;
|
||||
case FPCODEC_OGG:
|
||||
#ifdef USE_VORBIS
|
||||
_rewindableStream = Audio::makeVorbisStream(&_file, DisposeAfterUse::NO);
|
||||
#endif
|
||||
break;
|
||||
case FPCODEC_FLAC:
|
||||
#ifdef USE_FLAC
|
||||
_rewindableStream = Audio::makeFLACStream(&_file, DisposeAfterUse::NO);
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// All done
|
||||
_fileLoaded = true;
|
||||
_paused = false;
|
||||
|
||||
setVolume(63);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes a file stream (opened or not).
|
||||
*
|
||||
* @returns For safety, the destructor calls unloadFile() if it has not
|
||||
* been mentioned explicitly.
|
||||
*
|
||||
* @remarks It is necessary to call this function to free the
|
||||
* memory used by the stream.
|
||||
*/
|
||||
bool FPStream::unloadFile() {
|
||||
if (!_soundSupported || !_fileLoaded)
|
||||
return true;
|
||||
|
||||
assert(!g_system->getMixer()->isSoundHandleActive(_handle));
|
||||
|
||||
// Closes the file handle stream
|
||||
delete _loopStream;
|
||||
delete _rewindableStream;
|
||||
_loopStream = NULL;
|
||||
_rewindableStream = NULL;
|
||||
_file.close();
|
||||
|
||||
// Flag that the file is no longer in memory
|
||||
_fileLoaded = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Play the stream.
|
||||
*
|
||||
* @returns True is everything is OK, False otherwise
|
||||
*/
|
||||
|
||||
bool FPStream::play() {
|
||||
if (!_soundSupported || !_fileLoaded)
|
||||
return false;
|
||||
|
||||
stop();
|
||||
|
||||
_rewindableStream->rewind();
|
||||
|
||||
Audio::AudioStream *stream = _rewindableStream;
|
||||
|
||||
if (_loop) {
|
||||
if (!_loopStream)
|
||||
_loopStream = new Audio::LoopingAudioStream(_rewindableStream, 0, DisposeAfterUse::NO);
|
||||
|
||||
stream = _loopStream;
|
||||
}
|
||||
|
||||
// FIXME: Should this be kMusicSoundType or KPlainSoundType?
|
||||
g_system->getMixer()->playStream(Audio::Mixer::kMusicSoundType, &_handle, stream, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO);
|
||||
setVolume(_lastVolume);
|
||||
_paused = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the stream.
|
||||
*
|
||||
* @returns True is everything is OK, False otherwise
|
||||
*
|
||||
*/
|
||||
bool FPStream::stop() {
|
||||
if (!_soundSupported)
|
||||
return true;
|
||||
|
||||
if (!_fileLoaded)
|
||||
return false;
|
||||
|
||||
if (!g_system->getMixer()->isSoundHandleActive(_handle))
|
||||
return false;
|
||||
|
||||
g_system->getMixer()->stopHandle(_handle);
|
||||
|
||||
_paused = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void FPStream::waitForSync(FPStream *toPlay) {
|
||||
// FIXME: The idea here is that you wait for this stream to reach
|
||||
// a buffer which is a multiple of nBufSize/nSync, and then the
|
||||
// thread stops it and immediately starts the 'toplay' stream.
|
||||
|
||||
stop();
|
||||
toPlay->play();
|
||||
}
|
||||
|
||||
/**
|
||||
* Unables or disables stream loop.
|
||||
*
|
||||
* @param loop True enable loop, False disables it
|
||||
*
|
||||
* @remarks The loop must be activated BEFORE the stream starts
|
||||
* playing. Any changes made during the play will have no
|
||||
* effect until the stream is stopped then played again.
|
||||
*/
|
||||
void FPStream::setLoop(bool loop) {
|
||||
_loop = loop;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pause sound effect
|
||||
*
|
||||
* @param pause True enables pause, False disables it
|
||||
*/
|
||||
void FPStream::setPause(bool pause) {
|
||||
if (!_fileLoaded)
|
||||
return;
|
||||
|
||||
if (pause == _paused)
|
||||
return;
|
||||
|
||||
if (g_system->getMixer()->isSoundHandleActive(_handle))
|
||||
g_system->getMixer()->pauseHandle(_handle, pause);
|
||||
|
||||
_paused = pause;
|
||||
|
||||
// Trick to reset the volume after a possible new sound configuration
|
||||
setVolume(_lastVolume);
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the volume of the stream
|
||||
*
|
||||
* @param volume Volume to be set (0-63)
|
||||
*
|
||||
*/
|
||||
void FPStream::setVolume(int volume) {
|
||||
if (volume > 63)
|
||||
volume = 63;
|
||||
|
||||
if (volume < 0)
|
||||
volume = 0;
|
||||
|
||||
_lastVolume = volume;
|
||||
|
||||
if (!GLOBALS._bCfgMusic)
|
||||
volume = 0;
|
||||
else {
|
||||
volume -= (10 - GLOBALS._nCfgMusicVolume) * 2;
|
||||
if (volume < 0)
|
||||
volume = 0;
|
||||
}
|
||||
|
||||
if (g_system->getMixer()->isSoundHandleActive(_handle))
|
||||
g_system->getMixer()->setChannelVolume(_handle, remapVolume(volume));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the volume of the stream
|
||||
*
|
||||
* @param volumePtr Variable that will contain the current volume
|
||||
*
|
||||
*/
|
||||
void FPStream::getVolume(int *volumePtr) {
|
||||
if (g_system->getMixer()->isSoundHandleActive(_handle))
|
||||
*volumePtr = _lastVolume;
|
||||
else
|
||||
*volumePtr = 0;
|
||||
}
|
||||
|
||||
} // End of namespace Tony
|
||||
377
engines/tony/sound.h
Normal file
377
engines/tony/sound.h
Normal file
@@ -0,0 +1,377 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on original Tony Tough source code
|
||||
*
|
||||
* Copyright (c) 1997-2003 Nayma Software
|
||||
*/
|
||||
|
||||
#ifndef TONY_SOUND_H
|
||||
#define TONY_SOUND_H
|
||||
|
||||
#include "audio/mixer.h"
|
||||
#include "common/file.h"
|
||||
#include "tony/gfxcore.h"
|
||||
#include "tony/loc.h"
|
||||
#include "tony/utils.h"
|
||||
|
||||
namespace Audio {
|
||||
class RewindableAudioStream;
|
||||
}
|
||||
|
||||
namespace Tony {
|
||||
|
||||
class FPStream;
|
||||
class FPSfx;
|
||||
|
||||
enum SoundCodecs {
|
||||
FPCODEC_UNKNOWN,
|
||||
FPCODEC_ADPCM,
|
||||
FPCODEC_MP3,
|
||||
FPCODEC_OGG,
|
||||
FPCODEC_FLAC
|
||||
};
|
||||
|
||||
/**
|
||||
* Sound driver For Tony Tough
|
||||
*/
|
||||
|
||||
class FPSound {
|
||||
private:
|
||||
bool _soundSupported;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Default constructor. Initializes the attributes.
|
||||
*
|
||||
*/
|
||||
|
||||
FPSound();
|
||||
|
||||
/**
|
||||
* Destroy the object and free the memory
|
||||
*
|
||||
*/
|
||||
|
||||
~FPSound();
|
||||
|
||||
/**
|
||||
* Initializes the object, and prepare everything you need to create streams and sound effects.
|
||||
*
|
||||
* @returns True is everything is OK, False otherwise
|
||||
*/
|
||||
|
||||
bool init();
|
||||
|
||||
/**
|
||||
* Allocates an object of type FPStream, and return its pointer
|
||||
*
|
||||
* @param streamPtr Will contain a pointer to the object you just created.
|
||||
*
|
||||
* @returns True is everything is OK, False otherwise
|
||||
*/
|
||||
|
||||
bool createStream(FPStream **streamPtr);
|
||||
|
||||
/**
|
||||
* Allocates an object of type FpSfx, and return its pointer
|
||||
*
|
||||
* @param sfxPtr Will contain a pointer to the object you just created.
|
||||
*
|
||||
* @returns True is everything is OK, False otherwise
|
||||
*/
|
||||
|
||||
bool createSfx(FPSfx **sfxPtr);
|
||||
|
||||
/**
|
||||
* Set the general volume
|
||||
*
|
||||
* @param volume Volume to set (0-63)
|
||||
*/
|
||||
|
||||
void setMasterVolume(int volume);
|
||||
|
||||
/**
|
||||
* Get the general volume
|
||||
*
|
||||
* @param volume Variable that will contain the volume (0-63)
|
||||
*/
|
||||
|
||||
void getMasterVolume(int *volume);
|
||||
};
|
||||
|
||||
class FPSfx {
|
||||
private:
|
||||
bool _soundSupported; // True if the sound is active
|
||||
bool _fileLoaded; // True is a file is opened
|
||||
bool _loop; // True is sound effect should loop
|
||||
int _lastVolume;
|
||||
|
||||
bool _isVoice;
|
||||
bool _paused;
|
||||
|
||||
Audio::AudioStream *_loopStream;
|
||||
Audio::RewindableAudioStream *_rewindableStream;
|
||||
Audio::SoundHandle _handle;
|
||||
|
||||
public:
|
||||
uint32 _hEndOfBuffer;
|
||||
|
||||
/**
|
||||
* Check process for whether sounds have finished playing
|
||||
*/
|
||||
static void soundCheckProcess(CORO_PARAM, const void *param);
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*
|
||||
* @remarks Do *NOT* declare an object directly, but rather
|
||||
* create it using FPSound::CreateSfx()
|
||||
*
|
||||
*/
|
||||
|
||||
FPSfx(bool soundOn);
|
||||
|
||||
/**
|
||||
* Default Destructor.
|
||||
*
|
||||
* @remarks It is also stops the sound effect that may be
|
||||
* currently played, and free the memory it uses.
|
||||
*
|
||||
*/
|
||||
|
||||
~FPSfx();
|
||||
|
||||
/**
|
||||
* Releases the memory used by the object.
|
||||
*
|
||||
* @remarks Must be called when the object is no longer used and
|
||||
* **ONLY** if the object was created by
|
||||
* FPSound::CreateStream().
|
||||
* Object pointers are no longer valid after this call.
|
||||
*/
|
||||
|
||||
void release();
|
||||
|
||||
/**
|
||||
* Opens a file and loads a sound effect.
|
||||
*
|
||||
* @param fileName Sfx filename
|
||||
* @param codec CODEC used to uncompress the samples
|
||||
*
|
||||
* @returns True is everything is OK, False otherwise
|
||||
*/
|
||||
|
||||
bool loadFile(const char *fileName);
|
||||
bool loadWave(Common::SeekableReadStream *stream);
|
||||
bool loadVoiceFromVDB(Common::File &vdbFP);
|
||||
|
||||
/**
|
||||
* Play the Sfx in memory.
|
||||
*
|
||||
* @returns True is everything is OK, False otherwise
|
||||
*/
|
||||
|
||||
bool play();
|
||||
|
||||
/**
|
||||
* Stops a Sfx.
|
||||
*
|
||||
* @returns True is everything is OK, False otherwise
|
||||
*/
|
||||
|
||||
bool stop();
|
||||
|
||||
/**
|
||||
* Pauses a Sfx.
|
||||
*
|
||||
*/
|
||||
|
||||
void setPause(bool pause);
|
||||
|
||||
/**
|
||||
* Enables or disables the Sfx loop.
|
||||
*
|
||||
* @param loop True to enable the loop, False to disable
|
||||
*
|
||||
* @remarks The loop must be activated BEFORE the sfx starts
|
||||
* playing. Any changes made during the play will have
|
||||
* no effect until the sfx is stopped then played again.
|
||||
*/
|
||||
|
||||
void setLoop(bool loop);
|
||||
|
||||
/**
|
||||
* Change the volume of Sfx
|
||||
*
|
||||
* @param volume Volume to be set (0-63)
|
||||
*
|
||||
*/
|
||||
|
||||
void setVolume(int volume);
|
||||
|
||||
/**
|
||||
* Gets the Sfx volume
|
||||
*
|
||||
* @param volumePtr Will contain the current Sfx volume
|
||||
*
|
||||
*/
|
||||
|
||||
void getVolume(int *volumePtr);
|
||||
|
||||
/**
|
||||
* Returns true if the underlying sound has ended
|
||||
*/
|
||||
bool endOfBuffer() const;
|
||||
};
|
||||
|
||||
class FPStream {
|
||||
private:
|
||||
uint32 _bufferSize; // Buffer size (bytes)
|
||||
uint32 _size; // Stream size (bytes)
|
||||
|
||||
Common::File _file; // File handle used for the stream
|
||||
|
||||
bool _soundSupported; // True if the sound is active
|
||||
bool _fileLoaded; // True if the file is open
|
||||
bool _loop; // True if the stream should loop
|
||||
bool _doFadeOut; // True if fade out is required
|
||||
bool _syncExit;
|
||||
bool _paused;
|
||||
int _lastVolume;
|
||||
FPStream *_syncToPlay;
|
||||
|
||||
Audio::AudioStream *_loopStream;
|
||||
Audio::RewindableAudioStream *_rewindableStream;
|
||||
Audio::SoundHandle _handle;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*
|
||||
* @remarks Do *NOT* declare an object directly, but rather
|
||||
* create it using FPSound::CreateStream()
|
||||
*/
|
||||
|
||||
FPStream(bool soundOn);
|
||||
|
||||
/**
|
||||
* Default destructor.
|
||||
*
|
||||
* @remarks It calls CloseFile() if needed.
|
||||
*/
|
||||
|
||||
~FPStream();
|
||||
|
||||
/**
|
||||
* Releases the memory object.
|
||||
*
|
||||
* @remarks Must be called when the object is no longer used
|
||||
* and **ONLY** if the object was created by
|
||||
* FPSound::CreateStream().
|
||||
* Object pointers are no longer valid after this call.
|
||||
*/
|
||||
|
||||
void release();
|
||||
|
||||
/**
|
||||
* Opens a file stream
|
||||
*
|
||||
* @param fileName Filename to be opened
|
||||
*
|
||||
* @returns True is everything is OK, False otherwise
|
||||
*/
|
||||
|
||||
bool loadFile(const Common::String &fileName, int sync);
|
||||
|
||||
/**
|
||||
* Closes a file stream (opened or not).
|
||||
*
|
||||
* @returns For safety, the destructor calls unloadFile() if it has not
|
||||
* been mentioned explicitly.
|
||||
*
|
||||
* @remarks It is necessary to call this function to free the
|
||||
* memory used by the stream.
|
||||
*/
|
||||
|
||||
bool unloadFile();
|
||||
|
||||
/**
|
||||
* Play the stream.
|
||||
*
|
||||
* @returns True is everything is OK, False otherwise
|
||||
*/
|
||||
|
||||
bool play();
|
||||
void playFast();
|
||||
|
||||
/**
|
||||
* Closes the stream.
|
||||
*
|
||||
* @returns True is everything is OK, False otherwise
|
||||
*/
|
||||
|
||||
bool stop();
|
||||
void waitForSync(FPStream *toPlay);
|
||||
|
||||
/**
|
||||
* Pause sound effect
|
||||
*
|
||||
* @param pause True enables pause, False disables it
|
||||
*/
|
||||
|
||||
void setPause(bool pause);
|
||||
|
||||
/**
|
||||
* Unables or disables stream loop.
|
||||
*
|
||||
* @param loop True enable loop, False disables it
|
||||
*
|
||||
* @remarks The loop must be activated BEFORE the stream starts
|
||||
* playing. Any changes made during the play will have no
|
||||
* effect until the stream is stopped then played again.
|
||||
*/
|
||||
|
||||
void setLoop(bool loop);
|
||||
|
||||
/**
|
||||
* Change the volume of the stream
|
||||
*
|
||||
* @param volume Volume to be set (0-63)
|
||||
*/
|
||||
|
||||
void setVolume(int volume);
|
||||
|
||||
/**
|
||||
* Gets the volume of the stream
|
||||
*
|
||||
* @param volumePtr Variable that will contain the current volume
|
||||
*
|
||||
*/
|
||||
|
||||
void getVolume(int *volumePtr);
|
||||
};
|
||||
|
||||
} // End of namespace Tony
|
||||
|
||||
#endif
|
||||
800
engines/tony/tony.cpp
Normal file
800
engines/tony/tony.cpp
Normal file
@@ -0,0 +1,800 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "common/algorithm.h"
|
||||
#include "common/config-manager.h"
|
||||
#include "common/debug-channels.h"
|
||||
#include "common/events.h"
|
||||
#include "common/file.h"
|
||||
#include "common/compression/installshield_cab.h"
|
||||
#include "common/translation.h"
|
||||
#include "tony/tony.h"
|
||||
#include "tony/custom.h"
|
||||
#include "tony/debugger.h"
|
||||
#include "tony/game.h"
|
||||
#include "tony/mpal/mpal.h"
|
||||
|
||||
namespace Tony {
|
||||
|
||||
TonyEngine *g_vm;
|
||||
|
||||
TonyEngine::TonyEngine(OSystem *syst, const TonyGameDescription *gameDesc) : Engine(syst),
|
||||
_gameDescription(gameDesc), _randomSource("tony") {
|
||||
g_vm = this;
|
||||
_loadSlotNumber = -1;
|
||||
|
||||
// Set the up the debugger
|
||||
setDebugger(new Debugger());
|
||||
|
||||
// Add folders to the search directory list
|
||||
const Common::FSNode gameDataDir(ConfMan.getPath("path"));
|
||||
SearchMan.addSubDirectoryMatching(gameDataDir, "Voices");
|
||||
SearchMan.addSubDirectoryMatching(gameDataDir, "Roasted");
|
||||
SearchMan.addSubDirectoryMatching(gameDataDir, "Music");
|
||||
SearchMan.addSubDirectoryMatching(gameDataDir, "Music/utilsfx");
|
||||
SearchMan.addSubDirectoryMatching(gameDataDir, "Music/Layer");
|
||||
|
||||
// Set up load slot number
|
||||
_initialLoadSlotNumber = -1;
|
||||
if (ConfMan.hasKey("save_slot")) {
|
||||
int slotNumber = ConfMan.getInt("save_slot");
|
||||
if (slotNumber >= 0 && slotNumber <= 99)
|
||||
_initialLoadSlotNumber = slotNumber;
|
||||
}
|
||||
|
||||
// Load the ScummVM sound settings
|
||||
syncSoundSettings();
|
||||
|
||||
_hEndOfFrame = 0;
|
||||
for (int i = 0; i < 6; i++)
|
||||
_stream[i] = NULL;
|
||||
for (int i = 0; i < MAX_SFX_CHANNELS; i++) {
|
||||
_sfx[i] = NULL;
|
||||
_utilSfx[i] = NULL;
|
||||
}
|
||||
_bPaused = false;
|
||||
_bDrawLocation = false;
|
||||
_startTime = 0;
|
||||
_curThumbnail = NULL;
|
||||
_bQuitNow = false;
|
||||
_bTimeFreezed = false;
|
||||
_nTimeFreezed = 0;
|
||||
_vdbCodec = FPCODEC_UNKNOWN;
|
||||
|
||||
memset(_funcList, 0, sizeof(_funcList));
|
||||
}
|
||||
|
||||
TonyEngine::~TonyEngine() {
|
||||
// Close the voice database
|
||||
closeVoiceDatabase();
|
||||
|
||||
// Reset the coroutine scheduler
|
||||
CoroScheduler.reset();
|
||||
CoroScheduler.setResourceCallback(NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the game
|
||||
*/
|
||||
Common::Error TonyEngine::run() {
|
||||
Common::ErrorCode result = init();
|
||||
if (result != Common::kNoError)
|
||||
return result;
|
||||
|
||||
play();
|
||||
close();
|
||||
|
||||
return Common::kNoError;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the game
|
||||
*/
|
||||
Common::ErrorCode TonyEngine::init() {
|
||||
// Load DAT file (used by font manager)
|
||||
if (!loadTonyDat())
|
||||
return Common::kUnknownError;
|
||||
|
||||
if (isCompressed()) {
|
||||
Common::Archive *cabinet = Common::makeInstallShieldArchive("data");
|
||||
if (!cabinet)
|
||||
error("Failed to open the InstallShield cabinet");
|
||||
|
||||
SearchMan.add("data1.cab", cabinet);
|
||||
}
|
||||
|
||||
_hEndOfFrame = CoroScheduler.createEvent(false, false);
|
||||
|
||||
_bPaused = false;
|
||||
_bDrawLocation = true;
|
||||
_startTime = g_system->getMillis();
|
||||
|
||||
// Init static class fields
|
||||
RMText::initStatics();
|
||||
RMTony::initStatics();
|
||||
|
||||
// Reset the scheduler
|
||||
CoroScheduler.reset();
|
||||
|
||||
// Initialize the graphics window
|
||||
_window.init();
|
||||
|
||||
// Initialize the function list
|
||||
Common::fill(_funcList, _funcList + 300, (LPCUSTOMFUNCTION)NULL);
|
||||
initCustomFunctionMap();
|
||||
|
||||
// Initializes MPAL system, passing the custom functions list
|
||||
Common::File f;
|
||||
if (!f.open("ROASTED.MPC"))
|
||||
return Common::kReadingFailed;
|
||||
f.close();
|
||||
|
||||
if (!mpalInit("ROASTED.MPC", "ROASTED.MPR", _funcList, _funcListStrings))
|
||||
return Common::kUnknownError;
|
||||
|
||||
// Initialize the update resources
|
||||
_resUpdate.init("ROASTED.MPU");
|
||||
|
||||
// Initialize the music
|
||||
initMusic();
|
||||
|
||||
// Initialize the voices database
|
||||
if (!openVoiceDatabase())
|
||||
return Common::kReadingFailed;
|
||||
|
||||
// Initialize the boxes
|
||||
_theBoxes.init();
|
||||
|
||||
// Link to the custom graphics engine
|
||||
_theEngine.initCustomDll();
|
||||
_theEngine.init();
|
||||
|
||||
// Allocate space for thumbnails when saving the game
|
||||
_curThumbnail = new uint16[160 * 120];
|
||||
|
||||
_bQuitNow = false;
|
||||
|
||||
return Common::kNoError;
|
||||
}
|
||||
|
||||
bool TonyEngine::loadTonyDat() {
|
||||
Common::U32String errorMessage;
|
||||
Common::File in;
|
||||
Common::String filename = "tony.dat";
|
||||
|
||||
in.open(filename.c_str());
|
||||
|
||||
if (!in.isOpen()) {
|
||||
const char *msg = _s("Unable to locate the '%s' engine data file.");
|
||||
errorMessage = Common::U32String::format(_(msg), filename.c_str());
|
||||
GUIErrorMessage(errorMessage);
|
||||
warning(msg, filename.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read header
|
||||
char buf[4+1];
|
||||
in.read(buf, 4);
|
||||
buf[4] = '\0';
|
||||
|
||||
if (strcmp(buf, "TONY")) {
|
||||
const char *msg = _s("The '%s' engine data file is corrupt.");
|
||||
errorMessage = Common::U32String::format(_(msg), filename.c_str());
|
||||
GUIErrorMessage(errorMessage);
|
||||
warning(msg, filename.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
int majVer = in.readByte();
|
||||
int minVer = in.readByte();
|
||||
|
||||
if ((majVer != TONY_DAT_VER_MAJ) || (minVer != TONY_DAT_VER_MIN)) {
|
||||
const char *msg = _s("Incorrect version of the '%s' engine data file found. Expected %d.%d but got %d.%d.");
|
||||
errorMessage = Common::U32String::format(_(msg), filename.c_str(), TONY_DAT_VER_MAJ, TONY_DAT_VER_MIN, majVer, minVer);
|
||||
GUIErrorMessage(errorMessage);
|
||||
warning(msg, filename.c_str(), TONY_DAT_VER_MAJ, TONY_DAT_VER_MIN, majVer, minVer);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int expectedLangVariant = -1;
|
||||
switch (g_vm->getLanguage()) {
|
||||
case Common::IT_ITA:
|
||||
case Common::EN_ANY:
|
||||
expectedLangVariant = 0;
|
||||
break;
|
||||
case Common::PL_POL:
|
||||
expectedLangVariant = 1;
|
||||
break;
|
||||
case Common::RU_RUS:
|
||||
expectedLangVariant = 2;
|
||||
break;
|
||||
case Common::CS_CZE:
|
||||
expectedLangVariant = 3;
|
||||
break;
|
||||
case Common::FR_FRA:
|
||||
expectedLangVariant = 4;
|
||||
break;
|
||||
case Common::DE_DEU:
|
||||
expectedLangVariant = 5;
|
||||
break;
|
||||
default:
|
||||
warning("Unhandled language, falling back to English/Italian fonts.");
|
||||
expectedLangVariant = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
int numVariant = in.readUint16BE();
|
||||
if (expectedLangVariant > numVariant - 1) {
|
||||
const char *msg = _s("Font variant not present in '%s' engine data file.");
|
||||
errorMessage = Common::U32String::format(_(msg), filename.c_str());
|
||||
GUIErrorMessage(errorMessage);
|
||||
warning(msg, filename.c_str());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
in.seek(in.pos() + (2 * 256 * 8 * expectedLangVariant));
|
||||
for (int i = 0; i < 256; i++) {
|
||||
_cTableDialog[i] = in.readSint16BE();
|
||||
_lTableDialog[i] = in.readSint16BE();
|
||||
_cTableMacc[i] = in.readSint16BE();
|
||||
_lTableMacc[i] = in.readSint16BE();
|
||||
_cTableCred[i] = in.readSint16BE();
|
||||
_lTableCred[i] = in.readSint16BE();
|
||||
_cTableObj[i] = in.readSint16BE();
|
||||
_lTableObj[i] = in.readSint16BE();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void TonyEngine::initCustomFunctionMap() {
|
||||
INIT_CUSTOM_FUNCTION(_funcList, _funcListStrings);
|
||||
}
|
||||
|
||||
void TonyEngine::playMusic(int nChannel, const Common::String &fname, int nFX, bool bLoop, int nSync) {
|
||||
if (nChannel < 4) {
|
||||
if (GLOBALS._flipflop)
|
||||
nChannel = nChannel + 1;
|
||||
}
|
||||
|
||||
switch (nFX) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
_stream[nChannel]->stop();
|
||||
_stream[nChannel]->unloadFile();
|
||||
break;
|
||||
|
||||
case 22:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (nFX == 22) { // Sync a tempo
|
||||
GLOBALS._curChannel = nChannel;
|
||||
GLOBALS._nextLoop = bLoop;
|
||||
GLOBALS._nextSync = nSync;
|
||||
GLOBALS._nextMusic = fname;
|
||||
|
||||
if (GLOBALS._flipflop)
|
||||
GLOBALS._nextChannel = nChannel - 1;
|
||||
else
|
||||
GLOBALS._nextChannel = nChannel + 1;
|
||||
|
||||
uint32 hThread = CoroScheduler.createProcess(doNextMusic, NULL, 0);
|
||||
assert(hThread != CORO_INVALID_PID_VALUE);
|
||||
|
||||
} else if (nFX == 44) { // Change the channel and let the first finish
|
||||
if (GLOBALS._flipflop)
|
||||
GLOBALS._nextChannel = nChannel - 1;
|
||||
else
|
||||
GLOBALS._nextChannel = nChannel + 1;
|
||||
|
||||
_stream[GLOBALS._nextChannel]->stop();
|
||||
_stream[GLOBALS._nextChannel]->unloadFile();
|
||||
|
||||
if (!getIsDemo()) {
|
||||
if (!_stream[GLOBALS._nextChannel]->loadFile(fname, nSync))
|
||||
error("failed to open music file '%s'", fname.c_str());
|
||||
} else {
|
||||
_stream[GLOBALS._nextChannel]->loadFile(fname, nSync);
|
||||
}
|
||||
|
||||
_stream[GLOBALS._nextChannel]->setLoop(bLoop);
|
||||
_stream[GLOBALS._nextChannel]->play();
|
||||
|
||||
GLOBALS._flipflop = 1 - GLOBALS._flipflop;
|
||||
} else {
|
||||
if (!getIsDemo()) {
|
||||
if (!_stream[nChannel]->loadFile(fname, nSync))
|
||||
error("failed to open music file '%s'", fname.c_str());
|
||||
} else {
|
||||
_stream[nChannel]->loadFile(fname, nSync);
|
||||
}
|
||||
|
||||
_stream[nChannel]->setLoop(bLoop);
|
||||
_stream[nChannel]->play();
|
||||
}
|
||||
}
|
||||
|
||||
void TonyEngine::doNextMusic(CORO_PARAM, const void *param) {
|
||||
CORO_BEGIN_CONTEXT;
|
||||
Common::String fn;
|
||||
CORO_END_CONTEXT(_ctx);
|
||||
|
||||
FPStream **streams = g_vm->_stream;
|
||||
|
||||
CORO_BEGIN_CODE(_ctx);
|
||||
|
||||
if (!g_vm->getIsDemo()) {
|
||||
if (!streams[GLOBALS._nextChannel]->loadFile(GLOBALS._nextMusic, GLOBALS._nextSync))
|
||||
error("failed to open next music file '%s'", GLOBALS._nextMusic.c_str());
|
||||
} else {
|
||||
streams[GLOBALS._nextChannel]->loadFile(GLOBALS._nextMusic, GLOBALS._nextSync);
|
||||
}
|
||||
|
||||
streams[GLOBALS._nextChannel]->setLoop(GLOBALS._nextLoop);
|
||||
//streams[GLOBALS._nextChannel]->prefetch();
|
||||
|
||||
streams[GLOBALS._curChannel]->waitForSync(streams[GLOBALS._nextChannel]);
|
||||
|
||||
streams[GLOBALS._curChannel]->unloadFile();
|
||||
|
||||
GLOBALS._flipflop = 1 - GLOBALS._flipflop;
|
||||
|
||||
CORO_END_CODE;
|
||||
}
|
||||
|
||||
void TonyEngine::playSFX(int nChannel, int nFX) {
|
||||
if (_sfx[nChannel] == NULL)
|
||||
return;
|
||||
|
||||
switch (nFX) {
|
||||
case 0:
|
||||
_sfx[nChannel]->setLoop(false);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
_sfx[nChannel]->setLoop(true);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
_sfx[nChannel]->play();
|
||||
}
|
||||
|
||||
void TonyEngine::stopMusic(int nChannel) {
|
||||
if (nChannel < 4)
|
||||
_stream[nChannel + GLOBALS._flipflop]->stop();
|
||||
else
|
||||
_stream[nChannel]->stop();
|
||||
}
|
||||
|
||||
void TonyEngine::stopSFX(int nChannel) {
|
||||
_sfx[nChannel]->stop();
|
||||
}
|
||||
|
||||
void TonyEngine::playUtilSFX(int nChannel, int nFX) {
|
||||
if (_utilSfx[nChannel] == NULL)
|
||||
return;
|
||||
|
||||
switch (nFX) {
|
||||
case 0:
|
||||
_utilSfx[nChannel]->setLoop(false);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
_utilSfx[nChannel]->setLoop(true);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
_utilSfx[nChannel]->setVolume(52);
|
||||
_utilSfx[nChannel]->play();
|
||||
}
|
||||
|
||||
void TonyEngine::stopUtilSFX(int nChannel) {
|
||||
_utilSfx[nChannel]->stop();
|
||||
}
|
||||
|
||||
void TonyEngine::preloadSFX(int nChannel, const char *fn) {
|
||||
if (_sfx[nChannel] != NULL) {
|
||||
_sfx[nChannel]->stop();
|
||||
_sfx[nChannel]->release();
|
||||
_sfx[nChannel] = NULL;
|
||||
}
|
||||
|
||||
_theSound.createSfx(&_sfx[nChannel]);
|
||||
|
||||
_sfx[nChannel]->loadFile(fn);
|
||||
}
|
||||
|
||||
FPSfx *TonyEngine::createSFX(Common::SeekableReadStream *stream) {
|
||||
FPSfx *sfx;
|
||||
|
||||
_theSound.createSfx(&sfx);
|
||||
sfx->loadWave(stream);
|
||||
return sfx;
|
||||
}
|
||||
|
||||
void TonyEngine::preloadUtilSFX(int nChannel, const char *fn) {
|
||||
if (_utilSfx[nChannel] != NULL) {
|
||||
_utilSfx[nChannel]->stop();
|
||||
_utilSfx[nChannel]->release();
|
||||
_utilSfx[nChannel] = NULL;
|
||||
}
|
||||
|
||||
_theSound.createSfx(&_utilSfx[nChannel]);
|
||||
|
||||
_utilSfx[nChannel]->loadFile(fn);
|
||||
_utilSfx[nChannel]->setVolume(63);
|
||||
}
|
||||
|
||||
void TonyEngine::unloadAllSFX() {
|
||||
for (int i = 0; i < MAX_SFX_CHANNELS; i++) {
|
||||
if (_sfx[i] != NULL) {
|
||||
_sfx[i]->stop();
|
||||
_sfx[i]->release();
|
||||
_sfx[i] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TonyEngine::unloadAllUtilSFX() {
|
||||
for (int i = 0; i < MAX_SFX_CHANNELS; i++) {
|
||||
if (_utilSfx[i] != NULL) {
|
||||
_utilSfx[i]->stop();
|
||||
_utilSfx[i]->release();
|
||||
_utilSfx[i] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TonyEngine::initMusic() {
|
||||
int i;
|
||||
|
||||
_theSound.init();
|
||||
_theSound.setMasterVolume(63);
|
||||
|
||||
for (i = 0; i < 6; i++)
|
||||
_theSound.createStream(&_stream[i]);
|
||||
|
||||
for (i = 0; i < MAX_SFX_CHANNELS; i++) {
|
||||
_sfx[i] = _utilSfx[i] = NULL;
|
||||
}
|
||||
|
||||
// Preload sound effects
|
||||
preloadUtilSFX(0, "U01.ADP"); // Reversed!!
|
||||
preloadUtilSFX(1, "U02.ADP");
|
||||
|
||||
// Start check processes for sound
|
||||
CoroScheduler.createProcess(FPSfx::soundCheckProcess, NULL);
|
||||
}
|
||||
|
||||
void TonyEngine::closeMusic() {
|
||||
for (int i = 0; i < 6; i++) {
|
||||
_stream[i]->stop();
|
||||
_stream[i]->unloadFile();
|
||||
_stream[i]->release();
|
||||
}
|
||||
|
||||
unloadAllSFX();
|
||||
unloadAllUtilSFX();
|
||||
}
|
||||
|
||||
void TonyEngine::pauseSound(bool bPause) {
|
||||
_theEngine.pauseSound(bPause);
|
||||
|
||||
for (uint i = 0; i < 6; i++)
|
||||
if (_stream[i])
|
||||
_stream[i]->setPause(bPause);
|
||||
|
||||
for (uint i = 0; i < MAX_SFX_CHANNELS; i++) {
|
||||
if (_sfx[i])
|
||||
_sfx[i]->setPause(bPause);
|
||||
if (_utilSfx[i])
|
||||
_utilSfx[i]->setPause(bPause);
|
||||
}
|
||||
}
|
||||
|
||||
void TonyEngine::setMusicVolume(int nChannel, int volume) {
|
||||
_stream[nChannel + GLOBALS._flipflop]->setVolume(volume);
|
||||
}
|
||||
|
||||
int TonyEngine::getMusicVolume(int nChannel) {
|
||||
int volume;
|
||||
_stream[nChannel + GLOBALS._flipflop]->getVolume(&volume);
|
||||
return volume;
|
||||
}
|
||||
|
||||
Common::String TonyEngine::getSaveStateFileName(int n) {
|
||||
return Common::String::format("tony.%03d", n);
|
||||
}
|
||||
|
||||
Common::String TonyEngine::getSaveStateName(int slot) const {
|
||||
return getSaveStateFileName(slot);
|
||||
}
|
||||
|
||||
void TonyEngine::autoSave(CORO_PARAM) {
|
||||
CORO_BEGIN_CONTEXT;
|
||||
Common::String buf;
|
||||
CORO_END_CONTEXT(_ctx);
|
||||
|
||||
CORO_BEGIN_CODE(_ctx);
|
||||
|
||||
grabThumbnail();
|
||||
CORO_INVOKE_2(CoroScheduler.waitForSingleObject, g_vm->_hEndOfFrame, CORO_INFINITE);
|
||||
CORO_INVOKE_2(CoroScheduler.waitForSingleObject, g_vm->_hEndOfFrame, CORO_INFINITE);
|
||||
_ctx->buf = getSaveStateFileName(0);
|
||||
_theEngine.saveState(_ctx->buf, (byte *)_curThumbnail, "Autosave");
|
||||
|
||||
CORO_END_CODE;
|
||||
}
|
||||
|
||||
void TonyEngine::saveState(int n, const char *name) {
|
||||
Common::String buf = getSaveStateFileName(n);
|
||||
_theEngine.saveState(buf.c_str(), (byte *)_curThumbnail, name);
|
||||
}
|
||||
|
||||
void TonyEngine::loadState(CORO_PARAM, int n) {
|
||||
CORO_BEGIN_CONTEXT;
|
||||
Common::String buf;
|
||||
CORO_END_CONTEXT(_ctx);
|
||||
|
||||
CORO_BEGIN_CODE(_ctx);
|
||||
|
||||
_ctx->buf = getSaveStateFileName(n);
|
||||
CORO_INVOKE_1(_theEngine.loadState, _ctx->buf.c_str());
|
||||
|
||||
CORO_END_CODE;
|
||||
}
|
||||
|
||||
bool TonyEngine::openVoiceDatabase() {
|
||||
// Open the voices database
|
||||
if (!_vdbFP.open("voices.vdb"))
|
||||
if (!_vdbFP.open("voices.mdb"))
|
||||
if (!_vdbFP.open("voices.odb"))
|
||||
if (!_vdbFP.open("voices.fdb"))
|
||||
return false;
|
||||
|
||||
_vdbFP.seek(-8, SEEK_END);
|
||||
uint32 numfiles = _vdbFP.readUint32LE();
|
||||
int32 id = _vdbFP.readUint32BE();
|
||||
|
||||
if (id == MKTAG('V', 'D', 'B', '1'))
|
||||
_vdbCodec = FPCODEC_ADPCM;
|
||||
else if (id == MKTAG('M', 'D', 'B', '1'))
|
||||
_vdbCodec = FPCODEC_MP3;
|
||||
else if (id == MKTAG('O', 'D', 'B', '1'))
|
||||
_vdbCodec = FPCODEC_OGG;
|
||||
else if (id == MKTAG('F', 'D', 'B', '1'))
|
||||
_vdbCodec = FPCODEC_FLAC;
|
||||
else {
|
||||
_vdbFP.close();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read in the index
|
||||
_vdbFP.seek(-8 - (int64)(numfiles * VOICE_HEADER_SIZE), SEEK_END);
|
||||
|
||||
for (uint32 i = 0; i < numfiles; ++i) {
|
||||
VoiceHeader vh;
|
||||
vh._offset = _vdbFP.readUint32LE();
|
||||
vh._code = _vdbFP.readUint32LE();
|
||||
vh._parts = _vdbFP.readUint32LE();
|
||||
|
||||
_voices.push_back(vh);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void TonyEngine::closeVoiceDatabase() {
|
||||
if (_vdbFP.isOpen())
|
||||
_vdbFP.close();
|
||||
|
||||
if (_voices.size() > 0)
|
||||
_voices.clear();
|
||||
}
|
||||
|
||||
void TonyEngine::grabThumbnail() {
|
||||
_window.grabThumbnail(_curThumbnail);
|
||||
}
|
||||
|
||||
uint16 *TonyEngine::getThumbnail() {
|
||||
return _curThumbnail;
|
||||
}
|
||||
|
||||
void TonyEngine::quitGame() {
|
||||
_bQuitNow = true;
|
||||
}
|
||||
|
||||
void TonyEngine::openInitLoadMenu(CORO_PARAM) {
|
||||
_theEngine.openOptionScreen(coroParam, 1);
|
||||
}
|
||||
|
||||
void TonyEngine::openInitOptions(CORO_PARAM) {
|
||||
_theEngine.openOptionScreen(coroParam, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Main process for playing the game.
|
||||
*
|
||||
* @remarks This needs to be in a separate process, since there are some things that can briefly
|
||||
* block the execution of process. For now, all ScummVm event handling is dispatched to within the context of this
|
||||
* process. If it ever proves a problem, we may have to look into whether it's feasible to have it still remain
|
||||
* in the outer 'main' process.
|
||||
*/
|
||||
void TonyEngine::playProcess(CORO_PARAM, const void *param) {
|
||||
CORO_BEGIN_CONTEXT;
|
||||
Common::String fn;
|
||||
CORO_END_CONTEXT(_ctx);
|
||||
|
||||
|
||||
CORO_BEGIN_CODE(_ctx);
|
||||
|
||||
// Game loop. We rely on the outer main process to detect if a shutdown is required,
|
||||
// and kill the scheudler and all the processes, including this one
|
||||
for (;;) {
|
||||
// If a savegame needs to be loaded, then do so
|
||||
if (g_vm->_loadSlotNumber != -1 && GLOBALS._gfxEngine != NULL) {
|
||||
_ctx->fn = getSaveStateFileName(g_vm->_loadSlotNumber);
|
||||
CORO_INVOKE_1(GLOBALS._gfxEngine->loadState, _ctx->fn);
|
||||
g_vm->_loadSlotNumber = -1;
|
||||
}
|
||||
|
||||
// Wait for the next frame
|
||||
CORO_INVOKE_1(CoroScheduler.sleep, 50);
|
||||
|
||||
// Call the engine to handle the next frame
|
||||
CORO_INVOKE_1(g_vm->_theEngine.doFrame, g_vm->_bDrawLocation);
|
||||
|
||||
// Warns that a frame is finished
|
||||
CoroScheduler.pulseEvent(g_vm->_hEndOfFrame);
|
||||
|
||||
// Handle drawing the frame
|
||||
if (!g_vm->_bPaused) {
|
||||
if (!g_vm->_theEngine._bWiping)
|
||||
g_vm->_window.getNewFrame(g_vm->_theEngine, NULL);
|
||||
else
|
||||
g_vm->_window.getNewFrame(g_vm->_theEngine, &g_vm->_theEngine._rcWipeEllipse);
|
||||
}
|
||||
|
||||
// Paint the frame onto the screen
|
||||
g_vm->_window.repaint();
|
||||
}
|
||||
|
||||
CORO_END_CODE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Play the game
|
||||
*/
|
||||
void TonyEngine::play() {
|
||||
// Create the game player process
|
||||
CoroScheduler.createProcess(playProcess, NULL);
|
||||
|
||||
// Loop through calling the scheduler until it's time for the game to quit
|
||||
while (!shouldQuit() && !_bQuitNow) {
|
||||
// Delay for a brief amount
|
||||
g_system->delayMillis(10);
|
||||
|
||||
// Call any scheduled processes
|
||||
CoroScheduler.schedule();
|
||||
}
|
||||
}
|
||||
|
||||
void TonyEngine::close() {
|
||||
closeMusic();
|
||||
CoroScheduler.closeEvent(_hEndOfFrame);
|
||||
_theBoxes.close();
|
||||
_theEngine.close();
|
||||
_window.close();
|
||||
mpalFree();
|
||||
freeMpc();
|
||||
delete[] _curThumbnail;
|
||||
}
|
||||
|
||||
void TonyEngine::freezeTime() {
|
||||
_bTimeFreezed = true;
|
||||
_nTimeFreezed = getTime() - _startTime;
|
||||
}
|
||||
|
||||
void TonyEngine::unfreezeTime() {
|
||||
_bTimeFreezed = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the millisecond timer
|
||||
*/
|
||||
uint32 TonyEngine::getTime() {
|
||||
return g_system->getMillis();
|
||||
}
|
||||
|
||||
bool TonyEngine::canLoadGameStateCurrently(Common::U32String *msg) {
|
||||
return GLOBALS._gfxEngine != NULL && GLOBALS._gfxEngine->canLoadSave();
|
||||
}
|
||||
|
||||
bool TonyEngine::canSaveGameStateCurrently(Common::U32String *msg) {
|
||||
return GLOBALS._gfxEngine != NULL && GLOBALS._gfxEngine->canLoadSave();
|
||||
}
|
||||
|
||||
Common::Error TonyEngine::loadGameState(int slot) {
|
||||
_loadSlotNumber = slot;
|
||||
return Common::kNoError;
|
||||
}
|
||||
|
||||
Common::Error TonyEngine::saveGameState(int slot, const Common::String &desc, bool isAutosave) {
|
||||
if (!GLOBALS._gfxEngine)
|
||||
return Common::kUnknownError;
|
||||
|
||||
RMGfxTargetBuffer &bigBuf = *GLOBALS._gfxEngine;
|
||||
RMSnapshot s;
|
||||
s.grabScreenshot(bigBuf, 4, _curThumbnail);
|
||||
|
||||
GLOBALS._gfxEngine->saveState(getSaveStateFileName(slot), (byte *)_curThumbnail, desc);
|
||||
return Common::kNoError;
|
||||
}
|
||||
|
||||
void TonyEngine::syncSoundSettings() {
|
||||
Engine::syncSoundSettings();
|
||||
|
||||
GLOBALS._bCfgDubbing = !ConfMan.getBool("mute") && !ConfMan.getBool("speech_mute");
|
||||
GLOBALS._bCfgSFX = !ConfMan.getBool("mute") && !ConfMan.getBool("sfx_mute");
|
||||
GLOBALS._bCfgMusic = !ConfMan.getBool("mute") && !ConfMan.getBool("music_mute");
|
||||
|
||||
GLOBALS._nCfgDubbingVolume = ConfMan.getInt("speech_volume") * 10 / 256;
|
||||
GLOBALS._nCfgSFXVolume = ConfMan.getInt("sfx_volume") * 10 / 256;
|
||||
GLOBALS._nCfgMusicVolume = ConfMan.getInt("music_volume") * 10 / 256;
|
||||
|
||||
GLOBALS._bShowSubtitles = ConfMan.getBool("subtitles");
|
||||
GLOBALS._nCfgTextSpeed = ConfMan.getInt("talkspeed") * 10 / 256;
|
||||
}
|
||||
|
||||
void TonyEngine::saveSoundSettings() {
|
||||
ConfMan.setBool("speech_mute", !GLOBALS._bCfgDubbing);
|
||||
ConfMan.setBool("sfx_mute", !GLOBALS._bCfgSFX);
|
||||
ConfMan.setBool("music_mute", !GLOBALS._bCfgMusic);
|
||||
|
||||
ConfMan.setInt("speech_volume", GLOBALS._nCfgDubbingVolume * 256 / 10);
|
||||
ConfMan.setInt("sfx_volume", GLOBALS._nCfgSFXVolume * 256 / 10);
|
||||
ConfMan.setInt("music_volume", GLOBALS._nCfgMusicVolume * 256 / 10);
|
||||
|
||||
ConfMan.setBool("subtitles", GLOBALS._bShowSubtitles);
|
||||
ConfMan.setInt("talkspeed", GLOBALS._nCfgTextSpeed * 256 / 10);
|
||||
}
|
||||
|
||||
void TonyEngine::showLocation() {
|
||||
_bDrawLocation = true;
|
||||
}
|
||||
|
||||
void TonyEngine::hideLocation() {
|
||||
_bDrawLocation = false;
|
||||
}
|
||||
|
||||
} // End of namespace Tony
|
||||
242
engines/tony/tony.h
Normal file
242
engines/tony/tony.h
Normal file
@@ -0,0 +1,242 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TONY_TONY_H
|
||||
#define TONY_TONY_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "common/system.h"
|
||||
#include "common/array.h"
|
||||
#include "common/coroutines.h"
|
||||
#include "common/error.h"
|
||||
#include "common/random.h"
|
||||
#include "common/util.h"
|
||||
#include "engines/engine.h"
|
||||
#include "gui/debugger.h"
|
||||
|
||||
#include "tony/mpal/mpal.h"
|
||||
#include "tony/mpal/memory.h"
|
||||
#include "tony/debugger.h"
|
||||
#include "tony/gfxengine.h"
|
||||
#include "tony/loc.h"
|
||||
#include "tony/utils.h"
|
||||
#include "tony/window.h"
|
||||
#include "tony/globals.h"
|
||||
|
||||
/**
|
||||
* This is the namespace of the Tony engine.
|
||||
*
|
||||
* Status of this engine: In Development
|
||||
*
|
||||
* Games using this engine:
|
||||
* - Tony Tough
|
||||
*/
|
||||
namespace Tony {
|
||||
|
||||
using namespace MPAL;
|
||||
|
||||
class Globals;
|
||||
|
||||
enum {
|
||||
kTonyDebugAnimations = 1,
|
||||
kTonyDebugActions,
|
||||
kTonyDebugSound,
|
||||
kTonyDebugMusic,
|
||||
kTonyDebugMPAL,
|
||||
};
|
||||
|
||||
#define DEBUG_BASIC 1
|
||||
#define DEBUG_INTERMEDIATE 2
|
||||
#define DEBUG_DETAILED 3
|
||||
|
||||
struct TonyGameDescription;
|
||||
|
||||
#define MAX_SFX_CHANNELS 32
|
||||
#define TONY_DAT_VER_MAJ 0
|
||||
#define TONY_DAT_VER_MIN 3
|
||||
|
||||
struct VoiceHeader {
|
||||
int _offset;
|
||||
int _code;
|
||||
int _parts;
|
||||
};
|
||||
#define VOICE_HEADER_SIZE 12
|
||||
|
||||
class TonyEngine : public Engine {
|
||||
private:
|
||||
Common::ErrorCode init();
|
||||
bool loadTonyDat();
|
||||
void initMusic();
|
||||
void closeMusic();
|
||||
bool openVoiceDatabase();
|
||||
void closeVoiceDatabase();
|
||||
void initCustomFunctionMap();
|
||||
static void playProcess(CORO_PARAM, const void *param);
|
||||
static void doNextMusic(CORO_PARAM, const void *param);
|
||||
|
||||
protected:
|
||||
// Engine APIs
|
||||
Common::Error run() override;
|
||||
bool hasFeature(EngineFeature f) const override;
|
||||
public:
|
||||
LPCUSTOMFUNCTION _funcList[300];
|
||||
Common::String _funcListStrings[300];
|
||||
Common::RandomSource _randomSource;
|
||||
RMResUpdate _resUpdate;
|
||||
uint32 _hEndOfFrame;
|
||||
Common::File _vdbFP;
|
||||
SoundCodecs _vdbCodec;
|
||||
Common::Array<VoiceHeader> _voices;
|
||||
FPSound _theSound;
|
||||
Common::List<FPSfx *> _activeSfx;
|
||||
Globals _globals;
|
||||
|
||||
int16 _cTableDialog[256];
|
||||
int16 _lTableDialog[256];
|
||||
int16 _cTableMacc[256];
|
||||
int16 _lTableMacc[256];
|
||||
int16 _cTableCred[256];
|
||||
int16 _lTableCred[256];
|
||||
int16 _cTableObj[256];
|
||||
int16 _lTableObj[256];
|
||||
|
||||
enum DataDir {
|
||||
DD_BASE = 1,
|
||||
DD_SAVE,
|
||||
DD_SHOTS,
|
||||
DD_MUSIC,
|
||||
DD_LAYER,
|
||||
DD_UTILSFX,
|
||||
DD_VOICES,
|
||||
DD_BASE2
|
||||
};
|
||||
|
||||
FPStream *_stream[6];
|
||||
FPSfx *_sfx[MAX_SFX_CHANNELS];
|
||||
FPSfx *_utilSfx[MAX_SFX_CHANNELS];
|
||||
bool _bPaused;
|
||||
bool _bDrawLocation;
|
||||
int _startTime;
|
||||
uint16 *_curThumbnail;
|
||||
int _initialLoadSlotNumber;
|
||||
int _loadSlotNumber;
|
||||
|
||||
// Bounding box list manager
|
||||
RMGameBoxes _theBoxes;
|
||||
RMWindow _window;
|
||||
RMGfxEngine _theEngine;
|
||||
|
||||
bool _bQuitNow;
|
||||
bool _bTimeFreezed;
|
||||
int _nTimeFreezed;
|
||||
public:
|
||||
TonyEngine(OSystem *syst, const TonyGameDescription *gameDesc);
|
||||
~TonyEngine() override;
|
||||
|
||||
const TonyGameDescription *_gameDescription;
|
||||
uint32 getFeatures() const;
|
||||
Common::Language getLanguage() const;
|
||||
uint16 getVersion() const;
|
||||
bool getIsDemo() const;
|
||||
bool isCompressed() const;
|
||||
RMGfxEngine *getEngine() {
|
||||
return &_theEngine;
|
||||
}
|
||||
|
||||
bool canLoadGameStateCurrently(Common::U32String *msg = nullptr) override;
|
||||
bool canSaveGameStateCurrently(Common::U32String *msg = nullptr) override;
|
||||
Common::Error loadGameState(int slot) override;
|
||||
Common::Error saveGameState(int slot, const Common::String &desc, bool isAutosave = false) override;
|
||||
|
||||
void play();
|
||||
void close();
|
||||
|
||||
void getDataDirectory(DataDir dir, char *path);
|
||||
|
||||
void showLocation();
|
||||
void hideLocation();
|
||||
|
||||
/**
|
||||
* Reads the time
|
||||
*/
|
||||
uint32 getTime();
|
||||
void freezeTime();
|
||||
void unfreezeTime();
|
||||
|
||||
// Music
|
||||
// ******
|
||||
void playMusic(int nChannel, const Common::String &fn, int nFX, bool bLoop, int nSync);
|
||||
void stopMusic(int nChannel);
|
||||
|
||||
void playSFX(int nSfx, int nFX = 0);
|
||||
void stopSFX(int nSfx);
|
||||
|
||||
void playUtilSFX(int nSfx, int nFX = 0);
|
||||
void stopUtilSFX(int nSfx);
|
||||
|
||||
FPSfx *createSFX(Common::SeekableReadStream *stream);
|
||||
|
||||
void preloadSFX(int nSfx, const char *fn);
|
||||
void unloadAllSFX();
|
||||
|
||||
void preloadUtilSFX(int nSfx, const char *fn);
|
||||
void unloadAllUtilSFX();
|
||||
|
||||
/**
|
||||
* Stop all the audio
|
||||
*/
|
||||
void pauseSound(bool bPause);
|
||||
|
||||
void setMusicVolume(int nChannel, int volume);
|
||||
int getMusicVolume(int nChannel);
|
||||
|
||||
/**
|
||||
* Handle saving
|
||||
*/
|
||||
void autoSave(CORO_PARAM);
|
||||
void saveState(int n, const char *name);
|
||||
void loadState(CORO_PARAM, int n);
|
||||
static Common::String getSaveStateFileName(int n);
|
||||
Common::String getSaveStateName(int slot) const override;
|
||||
|
||||
/**
|
||||
* Get a thumbnail
|
||||
*/
|
||||
void grabThumbnail();
|
||||
uint16 *getThumbnail();
|
||||
|
||||
void quitGame();
|
||||
|
||||
void openInitLoadMenu(CORO_PARAM);
|
||||
void openInitOptions(CORO_PARAM);
|
||||
|
||||
void syncSoundSettings() override;
|
||||
void saveSoundSettings();
|
||||
};
|
||||
|
||||
// Global reference to the TonyEngine object
|
||||
extern TonyEngine *g_vm;
|
||||
|
||||
#define GLOBALS g_vm->_globals
|
||||
|
||||
} // End of namespace Tony
|
||||
|
||||
#endif /* TONY_TONY_H */
|
||||
2098
engines/tony/tonychar.cpp
Normal file
2098
engines/tony/tonychar.cpp
Normal file
File diff suppressed because it is too large
Load Diff
481
engines/tony/tonychar.h
Normal file
481
engines/tony/tonychar.h
Normal file
@@ -0,0 +1,481 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on original Tony Tough source code
|
||||
*
|
||||
* Copyright (c) 1997-2003 Nayma Software
|
||||
*/
|
||||
|
||||
#ifndef TONY_TONYCHAR_H
|
||||
#define TONY_TONYCHAR_H
|
||||
|
||||
#include "common/coroutines.h"
|
||||
#include "tony/loc.h"
|
||||
|
||||
namespace Tony {
|
||||
|
||||
class RMTony : public RMCharacter {
|
||||
private:
|
||||
enum CharacterDirection {
|
||||
UP, DOWN, LEFT, RIGHT
|
||||
};
|
||||
|
||||
public:
|
||||
enum CharacterTalkType {
|
||||
TALK_NORMAL,
|
||||
TALK_HIPS,
|
||||
TALK_SING,
|
||||
TALK_LAUGH,
|
||||
TALK_INDICATE,
|
||||
TALK_SCARED,
|
||||
TALK_SCARED2,
|
||||
TALK_WITHGLASSES,
|
||||
TALK_WITHHAMMER,
|
||||
TALK_WITHWORM,
|
||||
TALK_WITHROPE,
|
||||
TALK_WITHRABBIT,
|
||||
TALK_WITHRECIPE,
|
||||
TALK_WITHCARDS,
|
||||
TALK_WITHSNOWMAN,
|
||||
TALK_WITHSNOWMANSTATIC,
|
||||
TALK_WITHRABBITSTATIC,
|
||||
TALK_WITHRECIPESTATIC,
|
||||
TALK_WITHCARDSSTATIC,
|
||||
TALK_WITH_NOTEBOOK,
|
||||
TALK_WITHMEGAPHONESTATIC,
|
||||
TALK_WITHBEARDSTATIC,
|
||||
TALK_LAUGH2,
|
||||
TALK_DISGUSTED,
|
||||
TALK_SARCASTIC,
|
||||
TALK_MACBETH1,
|
||||
TALK_MACBETH2,
|
||||
TALK_MACBETH3,
|
||||
TALK_MACBETH4,
|
||||
TALK_MACBETH5,
|
||||
TALK_MACBETH6,
|
||||
TALK_MACBETH7,
|
||||
TALK_MACBETH8,
|
||||
TALK_MACBETH9,
|
||||
TALK_SCAREDSTATIC,
|
||||
TALK_WITHSECRETARY
|
||||
};
|
||||
|
||||
private:
|
||||
bool _bShow;
|
||||
bool _bShowShadow;
|
||||
bool _bBodyFront;
|
||||
// Useless variable?
|
||||
// RMGfxSourceBuffer8AB _shadow;
|
||||
bool _bActionPending;
|
||||
RMItem *_actionItem;
|
||||
int _action;
|
||||
int _actionParm;
|
||||
static bool _bAction;
|
||||
|
||||
bool _bShepherdess;
|
||||
|
||||
bool _bIsStaticTalk;
|
||||
bool _bIsTalking;
|
||||
int _nPatB4Talking;
|
||||
CharacterTalkType _nTalkType;
|
||||
CharacterDirection _talkDirection;
|
||||
RMPoint _nBodyOffset;
|
||||
|
||||
int _nTimeLastStep;
|
||||
|
||||
RMItem _body;
|
||||
uint32 _hActionThread;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Overload of the allocation allocation of sprites
|
||||
*/
|
||||
RMGfxSourceBuffer *newItemSpriteBuffer(int dimx, int dimy, bool bPreRLE) override;
|
||||
|
||||
/**
|
||||
* Watch thread which waits for the end of an action
|
||||
*/
|
||||
static void waitEndOfAction(CORO_PARAM, const void *param);
|
||||
|
||||
public:
|
||||
enum CharacterPatterns {
|
||||
PAT_TAKEUP_UP1 = 9,
|
||||
PAT_TAKEUP_UP2,
|
||||
PAT_TAKEUP_MID1,
|
||||
PAT_TAKEUP_MID2,
|
||||
PAT_TAKEUP_DOWN1,
|
||||
PAT_TAKEUP_DOWN2,
|
||||
|
||||
PAT_TAKELEFT_UP1,
|
||||
PAT_TAKELEFT_UP2,
|
||||
PAT_TAKELEFT_MID1,
|
||||
PAT_TAKELEFT_MID2,
|
||||
PAT_TAKELEFT_DOWN1,
|
||||
PAT_TAKELEFT_DOWN2,
|
||||
|
||||
PAT_TAKERIGHT_UP1,
|
||||
PAT_TAKERIGHT_UP2,
|
||||
PAT_TAKERIGHT_MID1,
|
||||
PAT_TAKERIGHT_MID2,
|
||||
PAT_TAKERIGHT_DOWN1,
|
||||
PAT_TAKERIGHT_DOWN2,
|
||||
|
||||
PAT_GETUPLEFT,
|
||||
PAT_ONTHEFLOORLEFT,
|
||||
PAT_GETUPRIGHT,
|
||||
PAT_ONTHEFLOORRIGHT,
|
||||
|
||||
// Sheperdess!
|
||||
PAT_PAST_WALKUP,
|
||||
PAT_PAST_WALKDOWN,
|
||||
PAT_PAST_WALKLEFT,
|
||||
PAT_PAST_WALKRIGHT,
|
||||
|
||||
PAT_PAST_STANDUP,
|
||||
PAT_PAST_STANDDOWN,
|
||||
PAT_PAST_STANDLEFT,
|
||||
PAT_PAST_STANDRIGHT,
|
||||
|
||||
// Speech
|
||||
PAT_TALK_UP,
|
||||
PAT_TALK_DOWN,
|
||||
PAT_TALK_LEFT,
|
||||
PAT_TALK_RIGHT,
|
||||
|
||||
// Static head
|
||||
PAT_HEAD_UP,
|
||||
PAT_HEAD_DOWN,
|
||||
PAT_HEAD_LEFT,
|
||||
PAT_HEAD_RIGHT,
|
||||
|
||||
// Laugh
|
||||
PAT_LAUGHLEFT_START,
|
||||
PAT_LAUGHLEFT_LOOP,
|
||||
PAT_LAUGHLEFT_END,
|
||||
PAT_LAUGHRIGHT_START,
|
||||
PAT_LAUGHRIGHT_LOOP,
|
||||
PAT_LAUGHRIGHT_END,
|
||||
|
||||
// Speaking as a shepherdess
|
||||
PAT_PAST_TALKUP,
|
||||
PAT_PAST_TALKDOWN,
|
||||
PAT_PAST_TALKLEFT,
|
||||
PAT_PAST_TALKRIGHT,
|
||||
|
||||
// Fear
|
||||
PAT_SCAREDLEFT_START,
|
||||
PAT_SCAREDLEFT_LOOP,
|
||||
PAT_SCAREDLEFT_END,
|
||||
PAT_SCAREDRIGHT_START,
|
||||
PAT_SCAREDRIGHT_LOOP,
|
||||
PAT_SCAREDRIGHT_END,
|
||||
PAT_SCAREDDOWN_START,
|
||||
PAT_SCAREDDOWN_LOOP,
|
||||
PAT_SCAREDDOWN_END,
|
||||
|
||||
// With objects: full body
|
||||
PAT_WITHGLASSES,
|
||||
PAT_WITHROPE,
|
||||
PAT_WITHWORM,
|
||||
PAT_WITHHAMMER,
|
||||
|
||||
// Sound the whistle
|
||||
PAT_WHISTLERIGHT,
|
||||
|
||||
// Head with beard
|
||||
PAT_TALKBEARD_LEFT,
|
||||
PAT_TALKBEARD_RIGHT,
|
||||
|
||||
// Sniff
|
||||
PAT_SNIFF_LEFT,
|
||||
PAT_SNIFF_RIGHT,
|
||||
|
||||
// Disgusted
|
||||
PAT_DISGUSTEDLEFT_START,
|
||||
PAT_DISGUSTEDLEFT_LOOP,
|
||||
PAT_DISGUSTEDLEFT_END,
|
||||
PAT_DISGUSTEDRIGHT_START,
|
||||
PAT_DISGUSTEDRIGHT_LOOP,
|
||||
PAT_DISGUSTEDRIGHT_END,
|
||||
PAT_SARCASTICLEFT_START,
|
||||
PAT_SARCASTICLEFT_LOOP,
|
||||
PAT_SARCASTICLEFT_END,
|
||||
PAT_SARCASTICRIGHT_START,
|
||||
PAT_SARCASTICRIGHT_LOOP,
|
||||
PAT_SARCASTICRIGHT_END,
|
||||
|
||||
// Stand scared
|
||||
PAT_SCAREDLEFT_STAND,
|
||||
PAT_SCAREDRIGHT_STAND,
|
||||
PAT_SCAREDDOWN_STAND,
|
||||
|
||||
PAT_PUTLEFT_UP1,
|
||||
PAT_PUTLEFT_UP2,
|
||||
PAT_PUTRIGHT_UP1,
|
||||
PAT_PUTRIGHT_UP2,
|
||||
PAT_PUTLEFT_MID1,
|
||||
PAT_PUTLEFT_MID2,
|
||||
PAT_PUTRIGHT_MID1,
|
||||
PAT_PUTRIGHT_MID2,
|
||||
PAT_PUTLEFT_DOWN1,
|
||||
PAT_PUTLEFT_DOWN2,
|
||||
PAT_PUTRIGHT_DOWN1,
|
||||
PAT_PUTRIGHT_DOWN2,
|
||||
PAT_PUTUP_UP1,
|
||||
PAT_PUTUP_UP2,
|
||||
PAT_PUTUP_MID1,
|
||||
PAT_PUTUP_MID2,
|
||||
PAT_PUTUP_DOWN1,
|
||||
PAT_PUTUP_DOWN2,
|
||||
|
||||
PAT_WITHSECRETARY
|
||||
};
|
||||
|
||||
enum CharacterBodyPatterns {
|
||||
BPAT_STANDUP = 1,
|
||||
BPAT_STANDDOWN,
|
||||
BPAT_STANDLEFT,
|
||||
BPAT_STANDRIGHT,
|
||||
|
||||
BPAT_HAMMER,
|
||||
BPAT_SNOWMAN,
|
||||
BPAT_WORM,
|
||||
BPAT_GLASS,
|
||||
|
||||
BPAT_SINGLEFT_START,
|
||||
BPAT_SINGLEFT_LOOP,
|
||||
BPAT_SINGLEFT_END,
|
||||
|
||||
BPAT_HIPSLEFT_START,
|
||||
BPAT_HIPSLEFT_LOOP,
|
||||
BPAT_HIPSLEFT_END,
|
||||
BPAT_HIPSRIGHT_START,
|
||||
BPAT_HIPSRIGHT_LOOP,
|
||||
BPAT_HIPSRIGHT_END,
|
||||
BPAT_HIPSUP_START,
|
||||
BPAT_HIPSUP_LOOP,
|
||||
BPAT_HIPSUP_END,
|
||||
BPAT_HIPSDOWN_START,
|
||||
BPAT_HIPSDOWN_LOOP,
|
||||
BPAT_HIPSDOWN_END,
|
||||
|
||||
BPAT_LAUGHLEFT,
|
||||
BPAT_LAUGHRIGHT,
|
||||
|
||||
BPAT_INDICATELEFT,
|
||||
BPAT_INDICATERIGHT,
|
||||
|
||||
BPAT_SCAREDDOWN_START,
|
||||
BPAT_SCAREDDOWN_LOOP,
|
||||
BPAT_SCAREDDOWN_END,
|
||||
BPAT_SCAREDLEFT_START,
|
||||
BPAT_SCAREDLEFT_LOOP,
|
||||
BPAT_SCAREDLEFT_END,
|
||||
BPAT_SCAREDRIGHT_START,
|
||||
BPAT_SCAREDRIGHT_LOOP,
|
||||
BPAT_SCAREDRIGHT_END,
|
||||
BPAT_SCAREDUP_START,
|
||||
BPAT_SCAREDUP_LOOP,
|
||||
BPAT_SCAREDUP_END,
|
||||
|
||||
BPAT_ROPE,
|
||||
|
||||
BPAT_WITHRABBITLEFT_START,
|
||||
BPAT_WITHRABBITLEFT_LOOP,
|
||||
BPAT_WITHRABBITLEFT_END,
|
||||
BPAT_WITHRABBITRIGHT_START,
|
||||
BPAT_WITHRABBITRIGHT_LOOP,
|
||||
BPAT_WITHRABBITRIGHT_END,
|
||||
|
||||
BPAT_WITHRECIPELEFT_START,
|
||||
BPAT_WITHRECIPELEFT_LOOP,
|
||||
BPAT_WITHRECIPELEFT_END,
|
||||
BPAT_WITHRECIPERIGHT_START,
|
||||
BPAT_WITHRECIPERIGHT_LOOP,
|
||||
BPAT_WITHRECIPERIGHT_END,
|
||||
|
||||
BPAT_WITHCARDSLEFT_START,
|
||||
BPAT_WITHCARDSLEFT_LOOP,
|
||||
BPAT_WITHCARDSLEFT_END,
|
||||
BPAT_WITHCARDSRIGHT_START,
|
||||
BPAT_WITHCARDSRIGHT_LOOP,
|
||||
BPAT_WITHCARDSRIGHT_END,
|
||||
|
||||
BPAT_WITHSNOWMANLEFT_START,
|
||||
BPAT_WITHSNOWMANLEFT_LOOP,
|
||||
BPAT_WITHSNOWMANLEFT_END,
|
||||
BPAT_WITHSNOWMANRIGHT_START,
|
||||
BPAT_WITHSNOWMANRIGHT_LOOP,
|
||||
BPAT_WITHSNOWMANRIGHT_END,
|
||||
|
||||
BPAT_WITHNOTEBOOKLEFT_START,
|
||||
BPAT_WITHNOTEBOOKLEFT_LOOP,
|
||||
BPAT_WITHNOTEBOOKLEFT_END,
|
||||
BPAT_WITHNOTEBOOKRIGHT_START,
|
||||
BPAT_WITHNOTEBOOKRIGHT_LOOP,
|
||||
BPAT_WITHNOTEBOOKRIGHT_END,
|
||||
|
||||
BPAT_WITHMEGAPHONELEFT_START,
|
||||
BPAT_WITHMEGAPHONELEFT_LOOP,
|
||||
BPAT_WITHMEGAPHONELEFT_END,
|
||||
BPAT_WITHMEGAPHONERIGHT_START,
|
||||
BPAT_WITHMEGAPHONERIGHT_LOOP,
|
||||
BPAT_WITHMEGAPHONERIGHT_END,
|
||||
|
||||
BPAT_WITHBEARDLEFT_START,
|
||||
BPAT_WITHBEARDLEFT_END,
|
||||
BPAT_WITHBEARDRIGHT_START,
|
||||
BPAT_WITHBEARDRIGHT_END,
|
||||
BPAT_WITHBEARDLEFT_STATIC,
|
||||
BPAT_WITHBEARDRIGHT_STATIC,
|
||||
|
||||
BPAT_MACBETH1,
|
||||
BPAT_MACBETH2,
|
||||
BPAT_MACBETH3,
|
||||
BPAT_MACBETH4,
|
||||
BPAT_MACBETH5,
|
||||
BPAT_MACBETH6,
|
||||
BPAT_MACBETH7,
|
||||
BPAT_MACBETH8,
|
||||
BPAT_MACBETH9,
|
||||
|
||||
BPAT_WITHSECRETARY
|
||||
};
|
||||
|
||||
public:
|
||||
static void initStatics();
|
||||
RMTony();
|
||||
|
||||
/**
|
||||
* Initialize Tony
|
||||
*/
|
||||
void init();
|
||||
|
||||
/**
|
||||
* Free all memory
|
||||
*/
|
||||
void close();
|
||||
|
||||
/**
|
||||
* Tony makes a frame, updating the movement, etc.
|
||||
*/
|
||||
void doFrame(CORO_PARAM, RMGfxTargetBuffer *bigBuf, int curLoc);
|
||||
|
||||
/**
|
||||
* Draw method, which controls chararacter display
|
||||
*/
|
||||
void draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim) override;
|
||||
|
||||
/**
|
||||
* Show or hide
|
||||
*/
|
||||
void show();
|
||||
void hide(bool bShowShadow = false);
|
||||
|
||||
/**
|
||||
* Move and make an action, if necessary
|
||||
*/
|
||||
void moveAndDoAction(CORO_PARAM, RMPoint dst, RMItem *item, int nAction, int nActionParm = 0);
|
||||
|
||||
/**
|
||||
* Tony stops (on the right side with respect to any subject)
|
||||
*/
|
||||
void stop(CORO_PARAM) override;
|
||||
void stopNoAction(CORO_PARAM);
|
||||
|
||||
/**
|
||||
* Set a pattern
|
||||
*/
|
||||
void setPattern(int npatt, bool bPlayP0 = false) override;
|
||||
|
||||
/**
|
||||
* Reads the current pattern
|
||||
*/
|
||||
int getCurPattern() override;
|
||||
|
||||
/**
|
||||
* Waits until the end of a pattern
|
||||
*/
|
||||
void waitForEndPattern(CORO_PARAM, uint32 hCustomSkip = CORO_INVALID_PID_VALUE);
|
||||
|
||||
/**
|
||||
* Check if currently in an action
|
||||
*/
|
||||
bool inAction();
|
||||
|
||||
/**
|
||||
* Check if there needs to be an update for scrolling movement
|
||||
*/
|
||||
bool mustUpdateScrolling();
|
||||
|
||||
/**
|
||||
* Returns Tony's position
|
||||
*/
|
||||
RMPoint position();
|
||||
|
||||
/**
|
||||
* Set the scrolling position
|
||||
*/
|
||||
void setScrollPosition(const RMPoint &pt);
|
||||
|
||||
/**
|
||||
* Set the take animation
|
||||
*/
|
||||
void take(int nWhere, int nPart);
|
||||
void put(int nWhere, int nPart);
|
||||
|
||||
/**
|
||||
* Start or End Talk
|
||||
*/
|
||||
bool startTalkCalculate(CharacterTalkType nTalkType, int &headStartPat, int &bodyStartPat,
|
||||
int &headLoopPat, int &bodyLoopPat);
|
||||
void startTalk(CORO_PARAM, CharacterTalkType nTalkType);
|
||||
bool endTalkCalculate(int &headStandPat, int &headEndPat, int &bodyEndPat, int &finalPat, bool &bStatic);
|
||||
void endTalk(CORO_PARAM);
|
||||
|
||||
/**
|
||||
* Start or End Static
|
||||
*/
|
||||
void startStaticCalculate(CharacterTalkType nTalk, int &headPat, int &headLoopPat,
|
||||
int &bodyStartPat, int &bodyLoopPat);
|
||||
void startStatic(CORO_PARAM, CharacterTalkType nTalkType);
|
||||
void endStaticCalculate(CharacterTalkType nTalk, int &bodyEndPat, int &finalPat, int &headEndPat);
|
||||
void endStatic(CORO_PARAM, CharacterTalkType nTalkType);
|
||||
|
||||
/**
|
||||
* Tony disguises himself!
|
||||
*/
|
||||
void setShepherdess(bool bIsPast);
|
||||
|
||||
int getShepherdess();
|
||||
|
||||
/**
|
||||
* Perform an action
|
||||
*/
|
||||
void executeAction(int nAction, int nActionItem, int nParm);
|
||||
|
||||
void playSfx(int nSfx);
|
||||
};
|
||||
|
||||
} // End of namespace Tony
|
||||
|
||||
#endif
|
||||
447
engines/tony/utils.cpp
Normal file
447
engines/tony/utils.cpp
Normal file
@@ -0,0 +1,447 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on original Tony Tough source code
|
||||
*
|
||||
* Copyright (c) 1997-2003 Nayma Software
|
||||
*/
|
||||
|
||||
#include "tony/utils.h"
|
||||
#include "tony/tony.h"
|
||||
#include "tony/mpal/lzo.h"
|
||||
|
||||
namespace Tony {
|
||||
|
||||
/**
|
||||
* Extracts a string from a data stream
|
||||
* @param df data stream
|
||||
*/
|
||||
Common::String readString(Common::ReadStream &df) {
|
||||
Common::String var;
|
||||
uint8 len = df.readByte();
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
char c;
|
||||
c = df.readByte();
|
||||
var += c;
|
||||
}
|
||||
|
||||
return var;
|
||||
}
|
||||
|
||||
/****************************************************************************\
|
||||
* RMPoint methods
|
||||
\****************************************************************************/
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
RMPoint::RMPoint() {
|
||||
_x = _y = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy constructor
|
||||
*/
|
||||
RMPoint::RMPoint(const RMPoint &p) {
|
||||
_x = p._x;
|
||||
_y = p._y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor with integer parameters
|
||||
*/
|
||||
RMPoint::RMPoint(int x1, int y1) {
|
||||
_x = x1;
|
||||
_y = y1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy operator
|
||||
*/
|
||||
RMPoint &RMPoint::operator=(RMPoint p) {
|
||||
_x = p._x;
|
||||
_y = p._y;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a point
|
||||
*/
|
||||
void RMPoint::set(int x1, int y1) {
|
||||
_x = x1;
|
||||
_y = y1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Offsets the point by another point
|
||||
*/
|
||||
void RMPoint::offset(const RMPoint &p) {
|
||||
_x += p._x;
|
||||
_y += p._y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Offsets the point by a specified offset
|
||||
*/
|
||||
void RMPoint::offset(int xOff, int yOff) {
|
||||
_x += xOff;
|
||||
_y += yOff;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sums together two points
|
||||
*/
|
||||
RMPoint operator+(RMPoint p1, RMPoint p2) {
|
||||
RMPoint p(p1);
|
||||
|
||||
return (p += p2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtracts two points
|
||||
*/
|
||||
RMPoint operator-(RMPoint p1, RMPoint p2) {
|
||||
RMPoint p(p1);
|
||||
|
||||
return (p -= p2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sum (offset) of a point
|
||||
*/
|
||||
RMPoint &RMPoint::operator+=(RMPoint p) {
|
||||
offset(p);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtract (offset) of a point
|
||||
*/
|
||||
RMPoint &RMPoint::operator-=(RMPoint p) {
|
||||
offset(-p);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inverts a point
|
||||
*/
|
||||
RMPoint RMPoint::operator-() {
|
||||
RMPoint p;
|
||||
|
||||
p._x = -_x;
|
||||
p._y = -_y;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Equality operator
|
||||
*/
|
||||
bool RMPoint::operator==(RMPoint p) {
|
||||
return ((_x == p._x) && (_y == p._y));
|
||||
}
|
||||
|
||||
/**
|
||||
* Not equal operator
|
||||
*/
|
||||
bool RMPoint::operator!=(RMPoint p) {
|
||||
return ((_x != p._x) || (_y != p._y));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a point from a stream
|
||||
*/
|
||||
void RMPoint::readFromStream(Common::ReadStream &ds) {
|
||||
_x = ds.readSint32LE();
|
||||
_y = ds.readSint32LE();
|
||||
}
|
||||
|
||||
/****************************************************************************\
|
||||
* RMPointReference methods
|
||||
\****************************************************************************/
|
||||
|
||||
RMPointReference::RMPointReference(int &x, int &y): _x(x), _y(y) {
|
||||
}
|
||||
|
||||
RMPointReference &RMPointReference::operator=(const RMPoint &p) {
|
||||
_x = p._x; _y = p._y;
|
||||
return *this;
|
||||
}
|
||||
|
||||
RMPointReference &RMPointReference::operator-=(const RMPoint &p) {
|
||||
_x -= p._x; _y -= p._y;
|
||||
return *this;
|
||||
}
|
||||
|
||||
RMPointReference::operator RMPoint() const {
|
||||
return RMPoint(_x, _y);
|
||||
}
|
||||
|
||||
/****************************************************************************\
|
||||
* RMRect methods
|
||||
\****************************************************************************/
|
||||
|
||||
RMRect::RMRect(): _topLeft(_x1, _y1), _bottomRight(_x2, _y2) {
|
||||
setEmpty();
|
||||
}
|
||||
|
||||
void RMRect::setEmpty() {
|
||||
_x1 = _y1 = _x2 = _y2 = 0;
|
||||
}
|
||||
|
||||
RMRect::RMRect(const RMPoint &p1, const RMPoint &p2): _topLeft(_x1, _y1), _bottomRight(_x2, _y2) {
|
||||
setRect(p1, p2);
|
||||
}
|
||||
|
||||
RMRect::RMRect(int X1, int Y1, int X2, int Y2): _topLeft(_x1, _y1), _bottomRight(_x2, _y2) {
|
||||
setRect(X1, Y1, X2, Y2);
|
||||
}
|
||||
|
||||
RMRect::RMRect(const RMRect &rc): _topLeft(_x1, _y1), _bottomRight(_x2, _y2) {
|
||||
copyRect(rc);
|
||||
}
|
||||
|
||||
void RMRect::setRect(const RMPoint &p1, const RMPoint &p2) {
|
||||
_x1 = p1._x;
|
||||
_y1 = p1._y;
|
||||
_x2 = p2._x;
|
||||
_y2 = p2._y;
|
||||
}
|
||||
|
||||
void RMRect::setRect(int X1, int Y1, int X2, int Y2) {
|
||||
_x1 = X1;
|
||||
_y1 = Y1;
|
||||
_x2 = X2;
|
||||
_y2 = Y2;
|
||||
}
|
||||
|
||||
void RMRect::setRect(const RMRect &rc) {
|
||||
copyRect(rc);
|
||||
}
|
||||
|
||||
void RMRect::copyRect(const RMRect &rc) {
|
||||
_x1 = rc._x1;
|
||||
_y1 = rc._y1;
|
||||
_x2 = rc._x2;
|
||||
_y2 = rc._y2;
|
||||
}
|
||||
|
||||
RMPointReference &RMRect::topLeft() {
|
||||
return _topLeft;
|
||||
}
|
||||
|
||||
RMPointReference &RMRect::bottomRight() {
|
||||
return _bottomRight;
|
||||
}
|
||||
|
||||
RMPoint RMRect::center() {
|
||||
return RMPoint((_x2 - _x1) / 2, (_y2 - _y1) / 2);
|
||||
}
|
||||
|
||||
int RMRect::width() const {
|
||||
return _x2 - _x1;
|
||||
}
|
||||
|
||||
int RMRect::height() const {
|
||||
return _y2 - _y1;
|
||||
}
|
||||
|
||||
int RMRect::size() const {
|
||||
return width() * height();
|
||||
}
|
||||
|
||||
RMRect::operator Common::Rect() const {
|
||||
return Common::Rect(_x1, _y1, _x2, _y2);
|
||||
}
|
||||
|
||||
bool RMRect::isEmpty() const {
|
||||
return (_x1 == 0 && _y1 == 0 && _x2 == 0 && _y2 == 0);
|
||||
}
|
||||
|
||||
const RMRect &RMRect::operator=(const RMRect &rc) {
|
||||
copyRect(rc);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void RMRect::offset(int xOff, int yOff) {
|
||||
_x1 += xOff;
|
||||
_y1 += yOff;
|
||||
_x2 += xOff;
|
||||
_y2 += yOff;
|
||||
}
|
||||
|
||||
void RMRect::offset(const RMPoint &p) {
|
||||
_x1 += p._x;
|
||||
_y1 += p._y;
|
||||
_x2 += p._x;
|
||||
_y2 += p._y;
|
||||
}
|
||||
|
||||
const RMRect &RMRect::operator+=(RMPoint p) {
|
||||
offset(p);
|
||||
return *this;
|
||||
}
|
||||
|
||||
const RMRect &RMRect::operator-=(RMPoint p) {
|
||||
offset(-p);
|
||||
return *this;
|
||||
}
|
||||
|
||||
RMRect operator+(const RMRect &rc, RMPoint p) {
|
||||
RMRect r(rc);
|
||||
return (r += p);
|
||||
}
|
||||
|
||||
RMRect operator-(const RMRect &rc, RMPoint p) {
|
||||
RMRect r(rc);
|
||||
|
||||
return (r -= p);
|
||||
}
|
||||
|
||||
RMRect operator+(RMPoint p, const RMRect &rc) {
|
||||
RMRect r(rc);
|
||||
|
||||
return (r += p);
|
||||
}
|
||||
|
||||
RMRect operator-(RMPoint p, const RMRect &rc) {
|
||||
RMRect r(rc);
|
||||
|
||||
return (r += p);
|
||||
}
|
||||
|
||||
bool RMRect::operator==(const RMRect &rc) {
|
||||
return ((_x1 == rc._x1) && (_y1 == rc._y1) && (_x2 == rc._x2) && (_y2 == rc._y2));
|
||||
}
|
||||
|
||||
bool RMRect::operator!=(const RMRect &rc) {
|
||||
return ((_x1 != rc._x1) || (_y1 != rc._y1) || (_x2 != rc._x2) || (_y2 != rc._y2));
|
||||
}
|
||||
|
||||
void RMRect::normalizeRect() {
|
||||
setRect(MIN(_x1, _x2), MIN(_y1, _y2), MAX(_x1, _x2), MAX(_y1, _y2));
|
||||
}
|
||||
|
||||
void RMRect::readFromStream(Common::ReadStream &ds) {
|
||||
_x1 = ds.readSint32LE();
|
||||
_y1 = ds.readSint32LE();
|
||||
_x2 = ds.readSint32LE();
|
||||
_y2 = ds.readSint32LE();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if RMPoint is in RMRect
|
||||
*/
|
||||
bool RMRect::ptInRect(const RMPoint &pt) {
|
||||
return (pt._x >= _x1 && pt._x <= _x2 && pt._y >= _y1 && pt._y <= _y2);
|
||||
}
|
||||
|
||||
/****************************************************************************\
|
||||
* Resource Update
|
||||
\****************************************************************************/
|
||||
|
||||
RMResUpdate::RMResUpdate() {
|
||||
_infos = NULL;
|
||||
_numUpd = 0;
|
||||
}
|
||||
|
||||
RMResUpdate::~RMResUpdate() {
|
||||
if (_infos) {
|
||||
delete[] _infos;
|
||||
_infos = NULL;
|
||||
}
|
||||
|
||||
if (_hFile.isOpen())
|
||||
_hFile.close();
|
||||
}
|
||||
|
||||
void RMResUpdate::init(const Common::Path &fileName) {
|
||||
// Open the resource update file
|
||||
if (!_hFile.open(fileName))
|
||||
// It doesn't exist, so exit immediately
|
||||
return;
|
||||
|
||||
_hFile.readByte(); // Version, unused
|
||||
|
||||
_numUpd = _hFile.readUint32LE();
|
||||
|
||||
_infos = new ResUpdInfo[_numUpd];
|
||||
|
||||
// Load the index of the resources in the file
|
||||
for (uint32 i = 0; i < _numUpd; ++i) {
|
||||
ResUpdInfo &info = _infos[i];
|
||||
|
||||
info._dwRes = _hFile.readUint32LE();
|
||||
info._offset = _hFile.readUint32LE();
|
||||
info._size = _hFile.readUint32LE();
|
||||
info._cmpSize = _hFile.readUint32LE();
|
||||
}
|
||||
}
|
||||
|
||||
MpalHandle RMResUpdate::queryResource(uint32 dwRes) {
|
||||
// If there isn't an update file, return NULL
|
||||
if (!_hFile.isOpen())
|
||||
return NULL;
|
||||
|
||||
uint32 i;
|
||||
for (i = 0; i < _numUpd; ++i)
|
||||
if (_infos[i]._dwRes == dwRes)
|
||||
// Found the index
|
||||
break;
|
||||
|
||||
if (i == _numUpd)
|
||||
// Couldn't find a matching resource, so return NULL
|
||||
return NULL;
|
||||
|
||||
const ResUpdInfo &info = _infos[i];
|
||||
byte *cmpBuf = new byte[info._cmpSize];
|
||||
uint32 dwRead;
|
||||
|
||||
// Move to the correct offset and read in the compressed data
|
||||
_hFile.seek(info._offset);
|
||||
dwRead = _hFile.read(cmpBuf, info._cmpSize);
|
||||
|
||||
if (info._cmpSize > dwRead) {
|
||||
// Error occurred reading data, so return NULL
|
||||
delete[] cmpBuf;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Allocate space for the output resource
|
||||
MpalHandle destBuf = globalAllocate(0, info._size);
|
||||
byte *lpDestBuf = (byte *)globalLock(destBuf);
|
||||
uint32 dwSize;
|
||||
|
||||
// Decompress the data
|
||||
lzo1x_decompress(cmpBuf, info._cmpSize, lpDestBuf, &dwSize);
|
||||
|
||||
// Delete buffer for compressed data
|
||||
delete [] cmpBuf;
|
||||
|
||||
// Return the resource
|
||||
globalUnlock(destBuf);
|
||||
return destBuf;
|
||||
}
|
||||
|
||||
} // End of namespace Tony
|
||||
175
engines/tony/utils.h
Normal file
175
engines/tony/utils.h
Normal file
@@ -0,0 +1,175 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on original Tony Tough source code
|
||||
*
|
||||
* Copyright (c) 1997-2003 Nayma Software
|
||||
*/
|
||||
|
||||
#ifndef TONY_UTILS_H
|
||||
#define TONY_UTILS_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "common/file.h"
|
||||
#include "common/rect.h"
|
||||
#include "common/str.h"
|
||||
#include "tony/mpal/memory.h"
|
||||
|
||||
namespace Tony {
|
||||
|
||||
using namespace ::Tony::MPAL;
|
||||
|
||||
Common::String readString(Common::ReadStream &ds);
|
||||
|
||||
/**
|
||||
* Point class
|
||||
*/
|
||||
class RMPoint {
|
||||
public:
|
||||
int _x, _y;
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
RMPoint();
|
||||
RMPoint(const RMPoint &p);
|
||||
RMPoint(int x1, int y1);
|
||||
|
||||
// Copy
|
||||
RMPoint &operator=(RMPoint p);
|
||||
|
||||
// Set
|
||||
void set(int x1, int y1);
|
||||
|
||||
// Offset
|
||||
void offset(int xOff, int yOff);
|
||||
void offset(const RMPoint &p);
|
||||
friend RMPoint operator+(RMPoint p1, RMPoint p2);
|
||||
friend RMPoint operator-(RMPoint p1, RMPoint p2);
|
||||
RMPoint &operator+=(RMPoint p);
|
||||
RMPoint &operator-=(RMPoint p);
|
||||
RMPoint operator-();
|
||||
|
||||
// Comparison
|
||||
bool operator==(RMPoint p);
|
||||
bool operator!=(RMPoint p);
|
||||
|
||||
// Casting a POINT
|
||||
operator Common::Point() const;
|
||||
|
||||
// Extraction from data streams
|
||||
void readFromStream(Common::ReadStream &ds);
|
||||
};
|
||||
|
||||
class RMPointReference {
|
||||
public:
|
||||
int &_x;
|
||||
int &_y;
|
||||
|
||||
RMPointReference(int &x, int &y);
|
||||
RMPointReference &operator=(const RMPoint &p);
|
||||
RMPointReference &operator-=(const RMPoint &p);
|
||||
operator RMPoint() const;
|
||||
};
|
||||
|
||||
class RMRect {
|
||||
public:
|
||||
int _x1, _y1;
|
||||
int _x2, _y2;
|
||||
RMPointReference _topLeft;
|
||||
RMPointReference _bottomRight;
|
||||
|
||||
public:
|
||||
RMRect();
|
||||
RMRect(int x1, int y1, int x2, int y2);
|
||||
RMRect(const RMPoint &p1, const RMPoint &p2);
|
||||
RMRect(const RMRect &rc);
|
||||
|
||||
// Attributes
|
||||
RMPointReference &topLeft();
|
||||
RMPointReference &bottomRight();
|
||||
RMPoint center();
|
||||
int width() const;
|
||||
int height() const;
|
||||
bool isEmpty() const;
|
||||
int size() const;
|
||||
operator Common::Rect() const;
|
||||
|
||||
// Set
|
||||
void setRect(int x1, int y1, int x2, int y2);
|
||||
void setRect(const RMPoint &p1, const RMPoint &p2);
|
||||
void setEmpty();
|
||||
|
||||
// Copiers
|
||||
void setRect(const RMRect &rc);
|
||||
void copyRect(const RMRect &rc);
|
||||
const RMRect &operator=(const RMRect &rc);
|
||||
|
||||
// Offset
|
||||
void offset(int xOff, int yOff);
|
||||
void offset(const RMPoint &p);
|
||||
friend RMRect operator+(const RMRect &rc, RMPoint p);
|
||||
friend RMRect operator-(const RMRect &rc, RMPoint p);
|
||||
friend RMRect operator+(RMPoint p, const RMRect &rc);
|
||||
friend RMRect operator-(RMPoint p, const RMRect &rc);
|
||||
const RMRect &operator+=(RMPoint p);
|
||||
const RMRect &operator-=(RMPoint p);
|
||||
|
||||
// Comparison
|
||||
bool operator==(const RMRect &rc);
|
||||
bool operator!=(const RMRect &rc);
|
||||
|
||||
// Normalize
|
||||
void normalizeRect();
|
||||
|
||||
// Point in rect
|
||||
bool ptInRect(const RMPoint &pt);
|
||||
|
||||
// Extract from data stream
|
||||
void readFromStream(Common::ReadStream &ds);
|
||||
};
|
||||
|
||||
/**
|
||||
* Resource update manager
|
||||
*/
|
||||
class RMResUpdate {
|
||||
struct ResUpdInfo {
|
||||
uint32 _dwRes;
|
||||
uint32 _offset;
|
||||
uint32 _size;
|
||||
uint32 _cmpSize;
|
||||
};
|
||||
|
||||
uint32 _numUpd;
|
||||
ResUpdInfo *_infos;
|
||||
Common::File _hFile;
|
||||
|
||||
public:
|
||||
RMResUpdate();
|
||||
~RMResUpdate();
|
||||
|
||||
void init(const Common::Path &fileName);
|
||||
MpalHandle queryResource(uint32 dwRes);
|
||||
};
|
||||
|
||||
} // End of namespace Tony
|
||||
|
||||
#endif /* TONY_H */
|
||||
352
engines/tony/window.cpp
Normal file
352
engines/tony/window.cpp
Normal file
@@ -0,0 +1,352 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on original Tony Tough source code
|
||||
*
|
||||
* Copyright (c) 1997-2003 Nayma Software
|
||||
*/
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "graphics/surface.h"
|
||||
#include "engines/util.h"
|
||||
#include "tony/window.h"
|
||||
#include "tony/game.h"
|
||||
#include "tony/tony.h"
|
||||
|
||||
namespace Tony {
|
||||
|
||||
/****************************************************************************\
|
||||
* RMWindow Methods
|
||||
\****************************************************************************/
|
||||
|
||||
RMWindow::RMWindow() {
|
||||
reset();
|
||||
}
|
||||
|
||||
RMWindow::~RMWindow() {
|
||||
close();
|
||||
RMText::unload();
|
||||
RMGfxTargetBuffer::freeBWPrecalcTable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the graphics window
|
||||
*/
|
||||
void RMWindow::init() {
|
||||
Graphics::PixelFormat pixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0);
|
||||
initGraphics(RM_SX, RM_SY, &pixelFormat);
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the variables
|
||||
*/
|
||||
void RMWindow::reset() {
|
||||
_showDirtyRects = false;
|
||||
_bGrabScreenshot = false;
|
||||
_bGrabThumbnail = false;
|
||||
_bGrabMovie = false;
|
||||
_wiping = false;
|
||||
|
||||
_wThumbBuf = nullptr;
|
||||
}
|
||||
|
||||
void RMWindow::copyRectToScreen(const byte *buf, int pitch, int x, int y, int w, int h) {
|
||||
if (GLOBALS._bCfgAnni30) {
|
||||
if (!RMGfxTargetBuffer::_precalcTable) {
|
||||
RMGfxTargetBuffer::createBWPrecalcTable();
|
||||
g_vm->getEngine()->getPointer().updateCursor();
|
||||
}
|
||||
Graphics::Surface *screen = g_system->lockScreen();
|
||||
const uint16 *src = (const uint16 *)buf;
|
||||
for (int i = 0; i < h; i++) {
|
||||
uint16 *dst = (uint16 *)screen->getBasePtr(x, y + i);
|
||||
for (int j = 0; j < w; j++) {
|
||||
dst[j] = RMGfxTargetBuffer::_precalcTable[src[j]];
|
||||
}
|
||||
src += (pitch / 2);
|
||||
}
|
||||
g_system->unlockScreen();
|
||||
} else {
|
||||
if (RMGfxTargetBuffer::_precalcTable) {
|
||||
RMGfxTargetBuffer::freeBWPrecalcTable();
|
||||
g_vm->getEngine()->getPointer().updateCursor();
|
||||
}
|
||||
g_system->copyRectToScreen(buf, pitch, x, y, w, h);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the window
|
||||
*/
|
||||
void RMWindow::close() {
|
||||
}
|
||||
|
||||
void RMWindow::grabThumbnail(uint16 *thumbmem) {
|
||||
_bGrabThumbnail = true;
|
||||
_wThumbBuf = thumbmem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Repaint the screen
|
||||
*/
|
||||
void RMWindow::repaint() {
|
||||
g_system->updateScreen();
|
||||
}
|
||||
|
||||
/**
|
||||
* Wipes an area of the screen
|
||||
*/
|
||||
void RMWindow::wipeEffect(Common::Rect &rcBoundEllipse) {
|
||||
if ((rcBoundEllipse.left == 0) && (rcBoundEllipse.top == 0) &&
|
||||
(rcBoundEllipse.right == RM_SX) && (rcBoundEllipse.bottom == RM_SY)) {
|
||||
// Full screen clear wanted, so use shortcut method
|
||||
g_system->fillScreen(0);
|
||||
} else {
|
||||
// Clear the designated area a line at a time
|
||||
uint16 line[RM_SX];
|
||||
Common::fill(line, line + RM_SX, 0);
|
||||
|
||||
// Loop through each line
|
||||
for (int yp = rcBoundEllipse.top; yp < rcBoundEllipse.bottom; ++yp) {
|
||||
copyRectToScreen((const byte *)&line[0], RM_SX * 2, rcBoundEllipse.left, yp, rcBoundEllipse.width(), 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RMWindow::getNewFrame(RMGfxTargetBuffer &bigBuf, Common::Rect *rcBoundEllipse) {
|
||||
// Get a pointer to the bytes of the source buffer
|
||||
byte *lpBuf = bigBuf;
|
||||
|
||||
if (rcBoundEllipse != NULL) {
|
||||
// Circular wipe effect
|
||||
getNewFrameWipe(lpBuf, *rcBoundEllipse);
|
||||
_wiping = true;
|
||||
} else if (_wiping) {
|
||||
// Just finished a wiping effect, so copy the full screen
|
||||
copyRectToScreen(lpBuf, RM_SX * 2, 0, 0, RM_SX, RM_SY);
|
||||
_wiping = false;
|
||||
|
||||
} else {
|
||||
// Standard screen copy - iterate through the dirty rects
|
||||
Common::List<Common::Rect> dirtyRects = bigBuf.getDirtyRects();
|
||||
Common::List<Common::Rect>::iterator i;
|
||||
|
||||
// If showing dirty rects, copy the entire screen background and set up a surface pointer
|
||||
Graphics::Surface *s = NULL;
|
||||
if (_showDirtyRects) {
|
||||
copyRectToScreen(lpBuf, RM_SX * 2, 0, 0, RM_SX, RM_SY);
|
||||
s = g_system->lockScreen();
|
||||
}
|
||||
|
||||
for (i = dirtyRects.begin(); i != dirtyRects.end(); ++i) {
|
||||
Common::Rect &r = *i;
|
||||
const byte *lpSrc = lpBuf + (RM_SX * 2) * r.top + (r.left * 2);
|
||||
copyRectToScreen(lpSrc, RM_SX * 2, r.left, r.top, r.width(), r.height());
|
||||
}
|
||||
|
||||
if (_showDirtyRects) {
|
||||
for (i = dirtyRects.begin(); i != dirtyRects.end(); ++i) {
|
||||
// Frame the copied area with a rectangle
|
||||
s->frameRect(*i, 0xffffff);
|
||||
}
|
||||
|
||||
g_system->unlockScreen();
|
||||
}
|
||||
}
|
||||
|
||||
if (_bGrabThumbnail) {
|
||||
// Need to generate a thumbnail
|
||||
RMSnapshot s;
|
||||
|
||||
s.grabScreenshot(lpBuf, 4, _wThumbBuf);
|
||||
_bGrabThumbnail = false;
|
||||
}
|
||||
|
||||
// Clear the dirty rect list
|
||||
bigBuf.clearDirtyRects();
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies a section of the game frame in a circle bounded by the specified rectangle
|
||||
*/
|
||||
void RMWindow::getNewFrameWipe(byte *lpBuf, Common::Rect &rcBoundEllipse) {
|
||||
// Clear the screen
|
||||
g_system->fillScreen(0);
|
||||
|
||||
if (!rcBoundEllipse.isValidRect())
|
||||
return;
|
||||
|
||||
Common::Point center(rcBoundEllipse.left + rcBoundEllipse.width() / 2,
|
||||
rcBoundEllipse.top + rcBoundEllipse.height() / 2);
|
||||
|
||||
// The rectangle technically defines the area inside the ellipse, with the corners touching
|
||||
// the ellipse boundary. Since we're currently simulating the ellipse using a plain circle,
|
||||
// we need to calculate a necessary width using the hypotenuse of X/2 & Y/2
|
||||
int x2y2 = (rcBoundEllipse.width() / 2) * (rcBoundEllipse.width() / 2) +
|
||||
(rcBoundEllipse.height() / 2) * (rcBoundEllipse.height() / 2);
|
||||
int radius = 0;
|
||||
while ((radius * radius) < x2y2)
|
||||
++radius;
|
||||
|
||||
// Proceed copying a circular area of the frame with the calculated radius onto the screen
|
||||
int error = -radius;
|
||||
int x = radius;
|
||||
int y = 0;
|
||||
|
||||
while (x >= y) {
|
||||
plotSplices(lpBuf, center, x, y);
|
||||
|
||||
error += y;
|
||||
++y;
|
||||
error += y;
|
||||
|
||||
if (error >= 0) {
|
||||
error -= x;
|
||||
--x;
|
||||
error -= x;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles drawing the line splices for the circle of viewable area
|
||||
*/
|
||||
void RMWindow::plotSplices(const byte *lpBuf, const Common::Point ¢er, int x, int y) {
|
||||
plotLines(lpBuf, center, x, y);
|
||||
if (x != y)
|
||||
plotLines(lpBuf, center, y, x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles drawing the line splices for the circle of viewable area
|
||||
*/
|
||||
void RMWindow::plotLines(const byte *lpBuf, const Common::Point ¢er, int x, int y) {
|
||||
// Skips lines that have no width (i.e. at the top of the circle)
|
||||
if ((x == 0) || (y > center.y))
|
||||
return;
|
||||
|
||||
const byte *pSrc;
|
||||
int xs = MAX(center.x - x, 0);
|
||||
int width = MIN(RM_SX - xs, x * 2);
|
||||
|
||||
if ((center.y - y) >= 0) {
|
||||
// Draw line in top half of circle
|
||||
pSrc = lpBuf + ((center.y - y) * RM_SX * 2) + xs * 2;
|
||||
copyRectToScreen(pSrc, RM_SX * 2, xs, center.y - y, width, 1);
|
||||
}
|
||||
|
||||
if ((center.y + y) < RM_SY) {
|
||||
// Draw line in bottom half of circle
|
||||
pSrc = lpBuf + ((center.y + y) * RM_SX * 2) + xs * 2;
|
||||
copyRectToScreen(pSrc, RM_SX * 2, xs, center.y + y, width, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void RMWindow::showDirtyRects(bool v) {
|
||||
_showDirtyRects = v;
|
||||
}
|
||||
|
||||
/****************************************************************************\
|
||||
* RMSnapshot Methods
|
||||
\****************************************************************************/
|
||||
|
||||
void RMSnapshot::grabScreenshot(byte *lpBuf, int dezoom, uint16 *lpDestBuf) {
|
||||
uint16 *src = (uint16 *)lpBuf;
|
||||
|
||||
int dimx = RM_SX / dezoom;
|
||||
int dimy = RM_SY / dezoom;
|
||||
|
||||
uint16 *cursrc;
|
||||
|
||||
if (lpDestBuf == NULL)
|
||||
src += (RM_SY - 1) * RM_BBX;
|
||||
|
||||
if (dezoom == 1 && 0) {
|
||||
byte *curOut = _rgb;
|
||||
|
||||
for (int y = 0; y < dimy; y++) {
|
||||
for (int x = 0; x < dimx; x++) {
|
||||
cursrc = &src[RM_SKIPX + x];
|
||||
|
||||
*curOut++ = ((*cursrc) & 0x1F) << 3;
|
||||
*curOut++ = (((*cursrc) >> 5) & 0x3F) << 3;
|
||||
*curOut++ = (((*cursrc) >> 11) & 0x1F) << 3;
|
||||
|
||||
if (lpDestBuf)
|
||||
*lpDestBuf++ = *cursrc;
|
||||
}
|
||||
|
||||
if (lpDestBuf == NULL)
|
||||
src -= RM_BBX;
|
||||
else
|
||||
src += RM_BBX;
|
||||
}
|
||||
} else {
|
||||
uint32 k = 0;
|
||||
for (int y = 0; y < dimy; y++) {
|
||||
for (int x = 0; x < dimx; x++) {
|
||||
cursrc = &src[RM_SKIPX + x * dezoom];
|
||||
int sommar, sommab, sommag, curv;
|
||||
sommar = sommab = sommag = 0;
|
||||
|
||||
for (int v = 0; v < dezoom; v++) {
|
||||
for (int u = 0; u < dezoom; u++) {
|
||||
if (lpDestBuf == NULL)
|
||||
curv = -v;
|
||||
else
|
||||
curv = v;
|
||||
|
||||
sommab += cursrc[curv * RM_BBX + u] & 0x1F;
|
||||
sommag += (cursrc[curv * RM_BBX + u] >> 6) & 0x1F;
|
||||
sommar += (cursrc[curv * RM_BBX + u] >> 11) & 0x1F;
|
||||
}
|
||||
}
|
||||
_rgb[k + 0] = (byte)(sommab * 8 / (dezoom * dezoom));
|
||||
_rgb[k + 1] = (byte)(sommag * 8 / (dezoom * dezoom));
|
||||
_rgb[k + 2] = (byte)(sommar * 8 / (dezoom * dezoom));
|
||||
|
||||
if (lpDestBuf != NULL)
|
||||
lpDestBuf[k / 3] = ((int)_rgb[k + 0] >> 3) | (((int)_rgb[k + 1] >> 3) << 5) |
|
||||
(((int)_rgb[k + 2] >> 3) << 10);
|
||||
|
||||
k += 3;
|
||||
}
|
||||
|
||||
if (lpDestBuf == NULL)
|
||||
src -= RM_BBX * dezoom;
|
||||
else
|
||||
src += RM_BBX * dezoom;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SCUMM_BIG_ENDIAN
|
||||
if (lpDestBuf != NULL) {
|
||||
for (int i = 0; i < dimx * dimy; i++) {
|
||||
lpDestBuf[i] = SWAP_BYTES_16(lpDestBuf[i]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
} // End of namespace Tony
|
||||
103
engines/tony/window.h
Normal file
103
engines/tony/window.h
Normal file
@@ -0,0 +1,103 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on original Tony Tough source code
|
||||
*
|
||||
* Copyright (c) 1997-2003 Nayma Software
|
||||
*/
|
||||
|
||||
#ifndef TONY_WINDOW_H
|
||||
#define TONY_WINDOW_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "common/rect.h"
|
||||
#include "tony/game.h"
|
||||
|
||||
namespace Tony {
|
||||
|
||||
class RMSnapshot {
|
||||
private:
|
||||
static const int BUFFER_SIZE = RM_SX *RM_SY * 3;
|
||||
// Buffer used to convert to RGB
|
||||
byte *_rgb;
|
||||
public:
|
||||
RMSnapshot() : _rgb(new byte[BUFFER_SIZE]) {}
|
||||
~RMSnapshot() {
|
||||
delete[] _rgb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Take a screenshot
|
||||
*/
|
||||
void grabScreenshot(byte *lpBuf, int dezoom = 1, uint16 *lpDestBuf = NULL);
|
||||
};
|
||||
|
||||
class RMWindow {
|
||||
private:
|
||||
void plotSplices(const byte *lpBuf, const Common::Point ¢er, int x, int y);
|
||||
void plotLines(const byte *lpBuf, const Common::Point ¢er, int x, int y);
|
||||
|
||||
protected:
|
||||
bool _wiping;
|
||||
bool _showDirtyRects;
|
||||
|
||||
bool _bGrabScreenshot;
|
||||
bool _bGrabThumbnail;
|
||||
bool _bGrabMovie;
|
||||
uint16 *_wThumbBuf;
|
||||
|
||||
void copyRectToScreen(const byte *buf, int pitch, int x, int y, int w, int h);
|
||||
void wipeEffect(Common::Rect &rcBoundEllipse);
|
||||
void getNewFrameWipe(byte *lpBuf, Common::Rect &rcBoundEllipse);
|
||||
|
||||
public:
|
||||
RMWindow();
|
||||
~RMWindow();
|
||||
|
||||
/**
|
||||
* Initialization
|
||||
*/
|
||||
void init();
|
||||
void reset();
|
||||
void close();
|
||||
|
||||
/**
|
||||
* Drawing
|
||||
*/
|
||||
void repaint();
|
||||
|
||||
/**
|
||||
* Reads the next frame
|
||||
*/
|
||||
void getNewFrame(RMGfxTargetBuffer &lpBuf, Common::Rect *rcBoundEllipse);
|
||||
|
||||
/**
|
||||
* Request a thumbnail be grabbed during the next frame
|
||||
*/
|
||||
void grabThumbnail(uint16 *buf);
|
||||
|
||||
void showDirtyRects(bool v);
|
||||
};
|
||||
|
||||
} // End of namespace Tony
|
||||
|
||||
#endif /* TONY_WINDOW_H */
|
||||
Reference in New Issue
Block a user