MUTATIONOFJB: Add support for CHANGED, CHANGEO and CHANGES commands.

This commit is contained in:
Ľubomír Remák 2018-02-26 23:52:13 +01:00 committed by Eugene Sandulenko
parent 3672ea5572
commit 6d926ff55b
9 changed files with 482 additions and 3 deletions

View file

@ -0,0 +1,334 @@
/* 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 "mutationofjb/commands/changecommand.h"
#include "common/translation.h"
namespace MutationOfJB {
// CHANGEe rr ss ii val
// <e> 1B Entity to change register for.
// D door
// O object
// S static
// <rr> 2B Register name.
// <ss> 2B Scene ID.
// <ii> 2B Entity ID.
// <val> VL Value.
bool ChangeCommandParser::parseValueString(const Common::String &valueString, uint8 &sceneId, uint8 &entityId, ChangeCommand::ChangeRegister &reg, ChangeCommand::ChangeOperation &op, ChangeCommandValue &ccv) {
if (valueString.size() < 8) {
return false;
}
sceneId = atoi(valueString.c_str() + 3);
entityId = atoi(valueString.c_str() + 6);
const char *val = nullptr;
if (valueString.size() >= 9) {
val = valueString.c_str() + 9;
}
if (valueString.hasPrefix("NM")) {
reg = ChangeCommand::NM;
op = ChangeCommand::SetValue;
strncpy(ccv._strVal, val, MAX_STR_LENGTH);
} else if (valueString.hasPrefix("LT")) {
reg = ChangeCommand::LT;
ccv._byteVal = parseInteger(val, op);
} else if (valueString.hasPrefix("SX")) {
reg = ChangeCommand::SX;
ccv._wordVal = parseInteger(val, op);
} else if (valueString.hasPrefix("SY")) {
reg = ChangeCommand::SY;
ccv._wordVal = parseInteger(val, op);
} else if (valueString.hasPrefix("XX")) {
reg = ChangeCommand::XX;
ccv._wordVal = parseInteger(val, op);
} else if (valueString.hasPrefix("YY")) {
reg = ChangeCommand::YY;
ccv._byteVal = parseInteger(val, op);
} else if (valueString.hasPrefix("XL")) {
reg = ChangeCommand::XL;
ccv._wordVal = parseInteger(val, op);
} else if (valueString.hasPrefix("YL")) {
reg = ChangeCommand::YL;
ccv._byteVal = parseInteger(val, op);
} else if (valueString.hasPrefix("WX")) {
reg = ChangeCommand::WX;
ccv._wordVal = parseInteger(val, op);
} else if (valueString.hasPrefix("WY")) {
reg = ChangeCommand::WY;
ccv._byteVal = parseInteger(val, op);
} else if (valueString.hasPrefix("AC")) {
reg = ChangeCommand::AC;
ccv._byteVal = parseInteger(val, op);
} else if (valueString.hasPrefix("FA")) {
reg = ChangeCommand::FA;
ccv._byteVal = parseInteger(val, op);
} else if (valueString.hasPrefix("FR")) {
reg = ChangeCommand::FR;
ccv._byteVal = parseInteger(val, op);
} else if (valueString.hasPrefix("NA")) {
reg = ChangeCommand::NA;
ccv._byteVal = parseInteger(val, op);
} else if (valueString.hasPrefix("FS")) {
reg = ChangeCommand::FS;
ccv._byteVal = parseInteger(val, op);
} else if (valueString.hasPrefix("CA")) {
reg = ChangeCommand::CA;
ccv._byteVal = parseInteger(val, op);
}
return true;
}
bool ChangeDoorCommandParser::parse(const Common::String &line, ScriptParseContext &, Command *&command) {
if (!line.hasPrefix("CHANGED ")) {
return false;
}
uint8 sceneId = 0;
uint8 objectId = 0;
ChangeCommand::ChangeRegister reg;
ChangeCommand::ChangeOperation op;
ChangeCommandValue val;
if (!parseValueString(line.c_str() + 8, sceneId, objectId, reg, op, val)) {
return false;
}
command = new ChangeObjectCommand(sceneId, objectId, reg, op, val);
return true;
}
bool ChangeObjectCommandParser::parse(const Common::String &line, ScriptParseContext &, Command *&command) {
if (!line.hasPrefix("CHANGEO ")) {
return false;
}
uint8 sceneId = 0;
uint8 objectId = 0;
ChangeCommand::ChangeRegister reg;
ChangeCommand::ChangeOperation op;
ChangeCommandValue val;
if (!parseValueString(line.c_str() + 8, sceneId, objectId, reg, op, val)) {
return false;
}
command = new ChangeObjectCommand(sceneId, objectId, reg, op, val);
return true;
}
bool ChangeStaticCommandParser::parse(const Common::String &line, ScriptParseContext &, Command *&command) {
if (!line.hasPrefix("CHANGES ")) {
return false;
}
uint8 sceneId = 0;
uint8 objectId = 0;
ChangeCommand::ChangeRegister reg;
ChangeCommand::ChangeOperation op;
ChangeCommandValue val;
if (!parseValueString(line.c_str() + 8, sceneId, objectId, reg, op, val)) {
return false;
}
command = new ChangeObjectCommand(sceneId, objectId, reg, op, val);
return true;
}
int ChangeCommandParser::parseInteger(const char *val, ChangeCommand::ChangeOperation &op) {
if (!val || !(*val)) {
op = ChangeCommand::SetValue;
return 0;
}
if (val[0] == '\\') {
op = ChangeCommand::SetValue;
val++;
} else if (val[0] == '+') {
op = ChangeCommand::AddValue;
val++;
} else if (val[0] == '-') {
op = ChangeCommand::SubtractValue;
val++;
}
return atoi(val);
}
Command::ExecuteResult ChangeDoorCommand::execute(GameData &gameData) {
Scene *const scene = gameData.getScene(_sceneId);
if (!scene) {
return Finished;
}
Door *const door = scene->getDoor(_entityId);
if (!door) {
return Finished;
}
switch (_register) {
case NM:
strncpy(door->_name, _value._strVal, MAX_STR_LENGTH);
break;
case LT:
door->_destSceneId = _value._byteVal;
break;
case SX:
door->_destX = _value._wordVal;
break;
case SY:
door->_destY = _value._wordVal;
break;
case XX:
door->_x = _value._wordVal;
break;
case YY:
door->_y = _value._byteVal;
break;
case XL:
door->_width = _value._wordVal;
break;
case YL:
door->_height = _value._byteVal;
break;
case WX:
door->_walkToX = _value._wordVal;
break;
case WY:
door->_walkToY = _value._byteVal;
break;
case SP:
door->_SP = _value._byteVal;
break;
default:
warning("Object does not support changing this register.");
break;
}
return Finished;
}
Command::ExecuteResult ChangeObjectCommand::execute(GameData &gameData) {
Scene *const scene = gameData.getScene(_sceneId);
if (!scene) {
return Finished;
}
Object *const object = scene->getObject(_entityId);
if (!object) {
return Finished;
}
switch (_register) {
case AC:
object->_AC = _value._byteVal;
break;
case FA:
object->_FA = _value._byteVal;
break;
case FR:
object->_FR = _value._byteVal;
break;
case NA:
object->_NA = _value._byteVal;
break;
case FS:
object->_FS = _value._byteVal;
break;
case CA:
object->_CA = _value._byteVal;
break;
case XX:
object->_x = _value._wordVal;
break;
case YY:
object->_y = _value._byteVal;
break;
case XL:
object->_XL = _value._wordVal;
break;
case YL:
object->_YL = _value._byteVal;
break;
case WX:
object->_WX = _value._wordVal;
break;
case WY:
object->_WY = _value._byteVal;
break;
case SP:
object->_SP = _value._byteVal;
break;
default:
warning("Object does not support changing this register.");
break;
}
return Finished;
}
Command::ExecuteResult ChangeStaticCommand::execute(GameData &gameData) {
Scene *const scene = gameData.getScene(_sceneId);
if (!scene) {
return Finished;
}
Static *const stat = scene->getStatic(_entityId);
if (!stat) {
return Finished;
}
switch (_register) {
case AC:
stat->_active = _value._byteVal;
break;
case NM:
strncpy(stat->_name, _value._strVal, MAX_STR_LENGTH);
break;
case XX:
stat->_x = _value._wordVal;
break;
case YY:
stat->_y = _value._byteVal;
break;
case XL:
stat->_width = _value._wordVal;
break;
case YL:
stat->_height = _value._byteVal;
break;
case WX:
stat->_walkToX = _value._wordVal;
break;
case WY:
stat->_walkToY = _value._byteVal;
break;
case SP:
stat->_SP = _value._byteVal;
break;
default:
warning("Object does not support changing this register.");
break;
}
return Finished;
}
}

View file

@ -0,0 +1,120 @@
/* 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 "mutationofjb/commands/seqcommand.h"
#include "mutationofjb/game.h"
namespace MutationOfJB {
union ChangeCommandValue {
uint8 _byteVal;
uint16 _wordVal;
char _strVal[MAX_STR_LENGTH + 1];
};
class ChangeCommand : public SeqCommand {
public:
enum ChangeRegister {
NM, // Name
LT, // Destination scene ID
SX, // Destination X
SY, // Destination Y
XX, // X
YY, // Y
XL, // Width
YL, // Height
WX, // Walk to X
WY, // Walk to Y
SP, //
AC, // Active
FA, // First animation
FR,
NA,
FS,
CA
};
enum ChangeOperation {
SetValue,
AddValue,
SubtractValue
};
ChangeCommand(uint8 sceneId, uint8 entityId, ChangeRegister reg, ChangeOperation op, const ChangeCommandValue& val) :
_sceneId(sceneId), _entityId(entityId), _register(reg), _operation(op), _value(val)
{}
protected:
uint8 _sceneId;
uint8 _entityId;
ChangeRegister _register;
ChangeOperation _operation;
ChangeCommandValue _value;
};
class ChangeCommandParser : public SeqCommandParser {
protected:
bool parseValueString(const Common::String &valueString, uint8 &sceneId, uint8 &entityId, ChangeCommand::ChangeRegister &reg, ChangeCommand::ChangeOperation &op, ChangeCommandValue &ccv);
int parseInteger(const char *val, ChangeCommand::ChangeOperation &op);
};
class ChangeObjectCommandParser : public ChangeCommandParser {
public:
virtual bool parse(const Common::String &line, ScriptParseContext &parseCtx, Command *&command) override;
};
class ChangeDoorCommandParser : public ChangeCommandParser {
public:
virtual bool parse(const Common::String &line, ScriptParseContext &parseCtx, Command *&command) override;
};
class ChangeStaticCommandParser : public ChangeCommandParser {
public:
virtual bool parse(const Common::String &line, ScriptParseContext &parseCtx, Command *&command) override;
};
class ChangeDoorCommand : public ChangeCommand {
public:
ChangeDoorCommand(uint8 sceneId, uint8 doorId, ChangeRegister reg, ChangeOperation op, const ChangeCommandValue& val)
: ChangeCommand(sceneId, doorId, reg, op, val)
{}
virtual ExecuteResult execute(GameData &gameData) override;
};
class ChangeObjectCommand : public ChangeCommand {
public:
ChangeObjectCommand(uint8 sceneId, uint8 objectId, ChangeRegister reg, ChangeOperation op, const ChangeCommandValue& val)
: ChangeCommand(sceneId, objectId, reg, op, val)
{}
virtual ExecuteResult execute(GameData &gameData) override;
};
class ChangeStaticCommand : public ChangeCommand {
public:
ChangeStaticCommand(uint8 sceneId, uint8 staticId, ChangeRegister reg, ChangeOperation op, const ChangeCommandValue& val)
: ChangeCommand(sceneId, staticId, reg, op, val)
{}
virtual ExecuteResult execute(GameData &gameData) override;
};
}

View file

@ -36,8 +36,6 @@ class CallMacroCommand;
class ScriptParseContext;
class Command;
typedef bool (*CommandParseFunc)(const Common::String &line, ScriptParseContext &parseContext, Command *&command);
class CommandParser {
public:
virtual ~CommandParser();

View file

@ -40,7 +40,7 @@ bool IfCommandParser::parse(const Common::String &line, ScriptParseContext &pars
return false;
}
if (strncmp(line.c_str(), "IF", 2) != 0) {
if (!line.hasPrefix("IF")) {
return false;
}

View file

@ -30,6 +30,7 @@ namespace MutationOfJB {
class SeqCommandParser : public CommandParser
{
public:
virtual void transition(ScriptParseContext &parseCtx, Command *oldCommand, Command *newCommand) override;
};

View file

@ -143,6 +143,15 @@ bool Scene::loadFromStream(Common::ReadStream &stream) {
return true;
}
Door *Scene::getDoor(uint8 doorId) {
if (doorId == 0 || doorId > _noDoors) {
warning(_("Door %d does not exist"), doorId);
return nullptr;
}
return &_doors[doorId - 1];
}
Object *Scene::getObject(uint8 objectId) {
if (objectId == 0 || objectId > _noObjects) {
warning(_("Object %d does not exist"), objectId);
@ -152,6 +161,15 @@ Object *Scene::getObject(uint8 objectId) {
return &_objects[objectId - 1];
}
Static *Scene::getStatic(uint8 staticId) {
if (staticId == 0 || staticId > _noStatics) {
warning(_("Static %d does not exist"), staticId);
return nullptr;
}
return &_statics[staticId - 1];
}
GameData::GameData() : _currentScene(0) {}
Scene *GameData::getScene(uint8 sceneId)

View file

@ -93,7 +93,9 @@ struct Bitmap {
struct Scene {
Door *getDoor(uint8 objectId);
Object *getObject(uint8 objectId);
Static *getStatic(uint8 staticId);
uint8 _startup;
uint8 _unknown001;

View file

@ -1,6 +1,7 @@
MODULE := engines/mutationofjb
MODULE_OBJS := \
commands/changecommand.o \
commands/command.o \
commands/conditionalcommand.o \
commands/endblockcommand.o \

View file

@ -29,6 +29,7 @@
#include "mutationofjb/commands/command.h"
#include "mutationofjb/commands/ifcommand.h"
#include "mutationofjb/commands/endblockcommand.h"
#include "mutationofjb/commands/changecommand.h"
namespace MutationOfJB {
@ -36,6 +37,9 @@ static CommandParser** getParsers() {
static CommandParser* parsers[] = {
new IfCommandParser,
new EndBlockCommandParser,
new ChangeDoorCommandParser,
new ChangeObjectCommandParser,
new ChangeStaticCommandParser,
nullptr
};
@ -101,6 +105,7 @@ bool Script::loadFromStream(Common::SeekableReadStream &stream) {
_allCommands.push_back(currentCmd);
}
lastCmd = currentCmd;
lastParser = currentParser;
}