DRAGONS: Started work on script logic

This commit is contained in:
Eric Fry 2019-01-22 22:11:00 +11:00 committed by Eugene Sandulenko
parent c0f1d70393
commit 534fdd0640
11 changed files with 433 additions and 24 deletions

View File

@ -0,0 +1,43 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "dragonobd.h"
#include "bigfile.h"
namespace Dragons {
DragonOBD::DragonOBD(BigfileArchive *bigfileArchive) {
_data = bigfileArchive->load("dragon.obd", _dataSize);
}
byte *DragonOBD::getObdAtOffset(uint32 offset) {
assert(_data);
assert(offset < _dataSize);
return &_data[offset];
}
DragonOBD::~DragonOBD() {
if (_data) {
delete _data;
}
}
} // End of namespace Dragons

View File

@ -0,0 +1,44 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef SCUMMVM_DRAGONOBD_H
#define SCUMMVM_DRAGONOBD_H
#include "common/system.h"
namespace Dragons {
class BigfileArchive;
class DragonOBD {
private:
byte *_data;
uint32_t _dataSize;
public:
virtual ~DragonOBD();
DragonOBD(BigfileArchive *bigfileArchive);
byte *getObdAtOffset(uint32 offset);
};
} // End of namespace Dragons
#endif //SCUMMVM_DRAGONOBD_H

View File

@ -21,13 +21,14 @@
*/
#include <common/memstream.h>
#include "dragonrms.h"
#include "dragonobd.h"
#include "bigfile.h"
namespace Dragons {
#define DRAGON_RMS_STRUCT_SIZE 0x1c
DragonRMS::DragonRMS(BigfileArchive *bigfileArchive) {
DragonRMS::DragonRMS(BigfileArchive *bigfileArchive, DragonOBD *dragonOBD) : _dragonOBD(dragonOBD) {
uint32 fileSize;
byte *data = bigfileArchive->load("dragon.rms", fileSize);
Common::SeekableReadStream *readStream = new Common::MemoryReadStream(data, fileSize, DisposeAfterUse::YES);
@ -49,9 +50,23 @@ DragonRMS::DragonRMS(BigfileArchive *bigfileArchive) {
}
char *DragonRMS::getSceneName(uint32 sceneId) {
if(sceneId > 1 && sceneId - 2 < _count) {
return _rmsObjects[sceneId - 2]._sceneName;
}
return NULL;
return getRMS(sceneId)->_sceneName;
}
byte *DragonRMS::getObdData(uint32 sceneId) {
return _dragonOBD->getObdAtOffset(getRMS(sceneId)->_obdOffset);
}
byte *DragonRMS::getObdDataField10(uint32 sceneId) {
return _dragonOBD->getObdAtOffset(getRMS(sceneId)->_field10ObdOffset);
}
RMS *DragonRMS::getRMS(uint32 sceneId) {
sceneId &= 0x7fff;
assert(sceneId > 1);
assert(sceneId - 2 < _count);
return &_rmsObjects[sceneId - 2];
}
} // End of namespace Dragons

View File

@ -29,23 +29,30 @@ namespace Dragons {
struct RMS {
int32 _field0;
char _sceneName[4];
int32 _obdOffset;
uint32 _obdOffset;
int32 _fieldC;
int32 _field10ObdOffset;
uint32 _field10ObdOffset;
int16 _inventoryBagPosition;
int32 _field16;
int16 _field1a;
};
class BigfileArchive;
class DragonOBD;
class DragonRMS {
private:
int16 _count;
RMS *_rmsObjects;
DragonOBD *_dragonOBD;
public:
DragonRMS(BigfileArchive *bigfileArchive);
DragonRMS(BigfileArchive *bigfileArchive, DragonOBD *dragonOBD);
char *getSceneName(uint32 sceneId);
byte *getObdData(uint32 sceneId);
byte *getObdDataField10(uint32 sceneId);
private:
RMS *getRMS(uint32 sceneId);
};
} // End of namespace Dragons

View File

@ -27,12 +27,14 @@
#include "actorresource.h"
#include "background.h"
#include "bigfile.h"
#include "dragonrms.h"
#include "dragonini.h"
#include "dragonobd.h"
#include "dragonrms.h"
#include "dragons.h"
#include "scene.h"
#include "screen.h"
#include "sequenceopcodes.h"
#include "scriptopcodes.h"
namespace Dragons {
@ -53,12 +55,14 @@ DragonsEngine::DragonsEngine(OSystem *syst) : Engine(syst) {
_flags = 0;
_unkFlags1 = 0;
_sequenceOpcodes = new SequenceOpcodes(this);
_scriptOpcodes = new ScriptOpcodes(this);
_engine = this;
_cursorPosition = Common::Point();
}
DragonsEngine::~DragonsEngine() {
delete _sequenceOpcodes;
delete _scriptOpcodes;
}
void DragonsEngine::updateEvents() {
@ -77,11 +81,12 @@ void DragonsEngine::updateEvents() {
Common::Error DragonsEngine::run() {
_screen = new Screen();
_bigfileArchive = new BigfileArchive("bigfile.dat", Common::Language::EN_ANY);
_dragonRMS = new DragonRMS(_bigfileArchive);
_dragonOBD = new DragonOBD(_bigfileArchive);
_dragonRMS = new DragonRMS(_bigfileArchive, _dragonOBD);
_dragonINIResource = new DragonINIResource(_bigfileArchive);
ActorResourceLoader *actorResourceLoader = new ActorResourceLoader(_bigfileArchive);
_actorManager = new ActorManager(actorResourceLoader);
_scene = new Scene(this, _screen, _bigfileArchive, _actorManager, _dragonRMS, _dragonINIResource);
_scene = new Scene(this, _screen, _scriptOpcodes, _bigfileArchive, _actorManager, _dragonRMS, _dragonINIResource);
_flags = 0x1046;
Actor *cursor = _actorManager->loadActor(0, 0); //Load cursor
@ -293,4 +298,8 @@ byte *DragonsEngine::getBackgroundPalette() {
return _scene->getPalette();
}
bool DragonsEngine::isFlagSet(uint32 flag) {
return (bool)(_flags & flag);
}
} // End of namespace Dragons

View File

@ -58,10 +58,13 @@ enum Flags {
ENGINE_FLAG_2 = 2,
ENGINE_FLAG_4 = 4,
ENGINE_FLAG_8 = 8,
ENGINE_FLAG_10 = 10,
ENGINE_FLAG_20 = 20,
ENGINE_FLAG_40 = 40,
ENGINE_FLAG_80 = 80
ENGINE_FLAG_10 = 0x10,
ENGINE_FLAG_20 = 0x20,
ENGINE_FLAG_40 = 0x40,
ENGINE_FLAG_80 = 0x80,
ENGINE_FLAG_80000 = 0x80000,
ENGINE_FLAG_100000 = 0x100000
};
enum UnkFlags {
@ -69,31 +72,35 @@ enum UnkFlags {
ENGINE_UNK1_FLAG_2 = 2,
ENGINE_UNK1_FLAG_4 = 4,
ENGINE_UNK1_FLAG_8 = 8,
ENGINE_UNK1_FLAG_10 = 10,
ENGINE_UNK1_FLAG_20 = 20,
ENGINE_UNK1_FLAG_40 = 40,
ENGINE_UNK1_FLAG_80 = 80
ENGINE_UNK1_FLAG_10 = 0x10,
ENGINE_UNK1_FLAG_20 = 0x20,
ENGINE_UNK1_FLAG_40 = 0x40,
ENGINE_UNK1_FLAG_80 = 0x80
};
class BigfileArchive;
class BackgroundResourceLoader;
class DragonOBD;
class DragonRMS;
class DragonINIResource;
class Scene;
class Screen;
class ActorManager;
class SequenceOpcodes;
class ScriptOpcodes;
class DragonsEngine : public Engine {
private:
Screen *_screen;
BigfileArchive *_bigfileArchive;
DragonOBD *_dragonOBD;
DragonRMS *_dragonRMS;
DragonINIResource *_dragonINIResource;
BackgroundResourceLoader *_backgroundResourceLoader;
ActorManager *_actorManager;
Scene *_scene;
SequenceOpcodes *_sequenceOpcodes;
ScriptOpcodes *_scriptOpcodes;
uint32 _nextUpdatetime;
uint32 _flags;
uint32 _unkFlags1;
@ -113,6 +120,7 @@ public:
void updateActorSequences();
void setFlags(uint32 flags);
void clearFlags(uint32 flags);
bool isFlagSet(uint32 flag);
void setUnkFlags(uint32 flags);
void clearUnkFlags(uint32 flags);

View File

@ -7,10 +7,12 @@ MODULE_OBJS := \
bigfile.o \
detection.o \
dragonini.o \
dragonobd.o \
dragonrms.o \
dragons.o \
scene.o \
screen.o \
scriptopcodes.o
sequenceopcodes.o
MODULE_DIRS += \

View File

@ -26,12 +26,13 @@
#include "dragonini.h"
#include "screen.h"
#include "actorresource.h"
#include "scriptopcodes.h"
namespace Dragons {
Scene::Scene(DragonsEngine *vm, Screen *screen, BigfileArchive *bigfileArchive, ActorManager *actorManager, DragonRMS *dragonRMS, DragonINIResource *dragonINIResource)
: _vm(vm), _screen(screen), _stage(0), _bigfileArchive(bigfileArchive), _actorManager(actorManager), _dragonRMS(dragonRMS), _dragonINIResource(dragonINIResource) {
Scene::Scene(DragonsEngine *vm, Screen *screen, ScriptOpcodes *scriptOpcodes, BigfileArchive *bigfileArchive, ActorManager *actorManager, DragonRMS *dragonRMS, DragonINIResource *dragonINIResource)
: _vm(vm), _screen(screen), _scriptOpcodes(scriptOpcodes), _stage(0), _bigfileArchive(bigfileArchive), _actorManager(actorManager), _dragonRMS(dragonRMS), _dragonINIResource(dragonINIResource) {
_backgroundLoader = new BackgroundResourceLoader(_bigfileArchive, _dragonRMS);
}
@ -45,7 +46,13 @@ void Scene::loadScene(uint32 sceneId, uint32 cameraPointId) {
}
if (!(sceneId & 0x8000)) {
// TODO opcodes here.
byte *obd = _dragonRMS->getObdDataField10(sceneId);
ScriptOpCall scriptOpCall;
scriptOpCall._code = obd + 4;
scriptOpCall._codeEnd = scriptOpCall._code + READ_LE_UINT32(obd);
_currentSceneId = -1;
_scriptOpcodes->runScript(scriptOpCall);
_currentSceneId = (uint16)(sceneId & 0x7fff);
}
_actorManager->clearActorFlags(2);
@ -141,6 +148,17 @@ void Scene::loadScene(uint32 sceneId, uint32 cameraPointId) {
_currentSceneId = (uint16)(sceneId & 0x7fff);
}
if (!(sceneId & 0x8000)) {
byte *obd = _dragonRMS->getObdData(sceneId);
ScriptOpCall scriptOpCall;
scriptOpCall._code = obd + 4;
scriptOpCall._codeEnd = scriptOpCall._code + READ_LE_UINT32(obd);
_currentSceneId = -1;
_scriptOpcodes->runScript(scriptOpCall);
_currentSceneId = (uint16)(sceneId & 0x7fff);
}
}
void Scene::draw() {

View File

@ -35,6 +35,7 @@ class BackgroundResourceLoader;
class DragonINIResource;
class BigfileArchive;
class Screen;
class ScriptOpcodes;
struct DragonINI;
class Scene {
@ -47,12 +48,13 @@ private:
DragonRMS *_dragonRMS;
DragonINIResource *_dragonINIResource;
BackgroundResourceLoader *_backgroundLoader;
ScriptOpcodes *_scriptOpcodes;
uint16 _currentSceneId;
int16 _currentSceneId;
Common::Point _camera;
public:
Scene(DragonsEngine *vm, Screen *screen, BigfileArchive *bigfileArchive, ActorManager *actorManager, DragonRMS *_dragonRMS, DragonINIResource *_dragonINIResource);
Scene(DragonsEngine *vm, Screen *screen, ScriptOpcodes *scriptOpcodes, BigfileArchive *bigfileArchive, ActorManager *actorManager, DragonRMS *_dragonRMS, DragonINIResource *_dragonINIResource);
void loadScene(uint32 sceneId, uint32 cameraPointId);
int16 getPriorityAtPosition(Common::Point pos);

View File

@ -0,0 +1,177 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "dragons/dragons.h"
#include "dragons/scriptopcodes.h"
#include "dragons/actor.h"
#include "scriptopcodes.h"
namespace Dragons {
// ScriptOpCall
void ScriptOpCall::skip(uint size) {
_code += size;
}
byte ScriptOpCall::readByte() {
return *_code++;
}
int16 ScriptOpCall::readSint16() {
int16 value = READ_LE_UINT16(_code);
_code += 2;
return value;
}
uint32 ScriptOpCall::readUint32() {
uint32 value = READ_LE_UINT32(_code);
_code += 4;
return value;
}
// ScriptOpcodes
ScriptOpcodes::ScriptOpcodes(DragonsEngine *vm)
: _vm(vm), _data_80071f5c(0) {
initOpcodes();
}
ScriptOpcodes::~ScriptOpcodes() {
freeOpcodes();
}
void ScriptOpcodes::execOpcode(ScriptOpCall &scriptOpCall) {
if (!_opcodes[scriptOpCall._op])
error("ScriptOpcodes::execOpcode() Unimplemented opcode %d (0x%X)", scriptOpCall._op, scriptOpCall._op);
debug(3, "execScriptOpcode(%d) %s", scriptOpCall._op, _opcodeNames[scriptOpCall._op].c_str());
(*_opcodes[scriptOpCall._op])(scriptOpCall);
}
typedef Common::Functor1Mem<ScriptOpCall&, void, ScriptOpcodes> ScriptOpcodeI;
#define OPCODE(op, func) \
_opcodes[op] = new ScriptOpcodeI(this, &ScriptOpcodes::func); \
_opcodeNames[op] = #func;
void ScriptOpcodes::initOpcodes() {
// First clear everything
for (uint i = 0; i < DRAGONS_NUM_SCRIPT_OPCODES; ++i) {
_opcodes[i] = 0;
}
// Register opcodes
OPCODE(1, opUnk1);
OPCODE(19, opUnk13PropertiesRelated);
OPCODE(31, opPlayMusic);
}
#undef OPCODE
void ScriptOpcodes::freeOpcodes() {
for (uint i = 0; i < DRAGONS_NUM_SCRIPT_OPCODES; ++i) {
delete _opcodes[i];
}
}
void ScriptOpcodes::updateReturn(ScriptOpCall &scriptOpCall, uint16 size) {
// scriptOpCall._deltaOfs = size * 2 + 2;
}
void ScriptOpcodes::runScript(ScriptOpCall &scriptOpCall) {
scriptOpCall._field8 = 0;
scriptOpCall._result = 0;
_data_80071f5c = 0;
executeScriptLoop(scriptOpCall);
}
void ScriptOpcodes::executeScriptLoop(ScriptOpCall &scriptOpCall) {
if (scriptOpCall._code >= scriptOpCall._codeEnd || scriptOpCall._result & 1) {
return;
}
if (Dragons::getEngine()->isFlagSet(Dragons::ENGINE_FLAG_100000)) {
return;
}
if (Dragons::getEngine()->isFlagSet(Dragons::ENGINE_FLAG_80000)) {
//TODO
// if (IsPressedStart(0)) {
// Dragons::getEngine()->setFlags(Dragons::ENGINE_FLAG_100000);
// }
}
uint16 opcode = READ_LE_INT16(scriptOpCall._code);
scriptOpCall._op = (byte) opcode;
if (opcode < DRAGONS_NUM_SCRIPT_OPCODES) {
execOpcode(scriptOpCall);
}
while (scriptOpCall._code < scriptOpCall._codeEnd && !(scriptOpCall._result & 1) && _data_80071f5c == 0) {
if (Dragons::getEngine()->isFlagSet(Dragons::ENGINE_FLAG_100000)) {
return;
}
if (Dragons::getEngine()->isFlagSet(Dragons::ENGINE_FLAG_80000)) {
//TODO
// if (IsPressedStart(0)) {
// Dragons::getEngine()->setFlags(Dragons::ENGINE_FLAG_100000);
// }
}
uint16 opcode = READ_LE_INT16(scriptOpCall._code);
if (opcode >= DRAGONS_NUM_SCRIPT_OPCODES) {
return; //TODO should continue here.
}
scriptOpCall._op = (byte) opcode;
execOpcode(scriptOpCall);
}
}
// Opcodes
void ScriptOpcodes::opUnk1(ScriptOpCall &scriptOpCall) {
// ARG_INT16(framePointer);
// debug(3, "set frame pointer %X", framePointer);
// actor->loadFrame((uint16)framePointer);
// actor->flags |= Dragons::ACTOR_FLAG_2;
// actor->sequenceTimer = actor->field_c;
// updateReturn(scriptOpCall, 1);
}
void ScriptOpcodes::opPlayMusic(ScriptOpCall &scriptOpCall) {
byte *code = scriptOpCall._code;
scriptOpCall._code += 4;
if (scriptOpCall._field8 == 0) {
//TODO play music here.
}
}
void ScriptOpcodes::opUnk13PropertiesRelated(ScriptOpCall &scriptOpCall) {
//TODO sub_8002f02c()
}
} // End of namespace Dragons

View 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 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef DRAGONS_SCRIPTOPCODES_H
#define DRAGONS_SCRIPTOPCODES_H
#include "common/func.h"
#include "common/str.h"
namespace Dragons {
#define DRAGONS_NUM_SCRIPT_OPCODES 0x22
class DragonsEngine;
struct ScriptOpCall {
byte _op;
byte *_code;
byte *_codeEnd;
int _field8;
int _result;
void skip(uint size);
byte readByte();
int16 readSint16();
uint32 readUint32();
};
// Convenience macros
#define ARG_SKIP(x) opCall.skip(x);
#define ARG_BYTE(name) byte name = scriptOpCall.readByte(); debug(5, "ARG_BYTE(" #name " = %d)", name);
#define ARG_INT8(name) int8 name = scriptOpCall.readByte(); debug(5, "ARG_INT8(" #name " = %d)", name);
#define ARG_INT16(name) int16 name = scriptOpCall.readSint16(); debug(5, "ARG_INT16(" #name " = %d)", name);
#define ARG_UINT32(name) uint32 name = scriptOpCall.readUint32(); debug(5, "ARG_UINT32(" #name " = %08X)", name);
typedef Common::Functor1<ScriptOpCall&, void> ScriptOpcode;
class ScriptOpcodes {
public:
ScriptOpcodes(DragonsEngine *vm);
~ScriptOpcodes();
void runScript(ScriptOpCall &scriptOpCall);
void execOpcode(ScriptOpCall &scriptOpCall);
protected:
DragonsEngine *_vm;
ScriptOpcode *_opcodes[DRAGONS_NUM_SCRIPT_OPCODES];
Common::String _opcodeNames[DRAGONS_NUM_SCRIPT_OPCODES];
int16 _data_80071f5c;
void initOpcodes();
void freeOpcodes();
void updateReturn(ScriptOpCall &scriptOpCall, uint16 size);
void executeScriptLoop(ScriptOpCall &scriptOpCall);
// Opcodes
void opUnk1(ScriptOpCall &scriptOpCall);
void opUnk13PropertiesRelated(ScriptOpCall &scriptOpCall);
void opPlayMusic(ScriptOpCall &scriptOpCall);
};
} // End of namespace Dragons
#endif // DRAGONS_SCRIPTOPCODES_H