mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-14 21:59:17 +00:00
459 lines
8.5 KiB
C++
459 lines
8.5 KiB
C++
/* 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/textconsole.h"
|
|
|
|
#include "parallaction/parallaction.h"
|
|
#include "parallaction/objects.h"
|
|
#include "parallaction/parser.h"
|
|
|
|
namespace Parallaction {
|
|
|
|
|
|
Command::Command() {
|
|
_id = 0;
|
|
_flagsOn = 0;
|
|
_flagsOff = 0;
|
|
_valid = false;
|
|
|
|
_flags = 0;
|
|
_callable = 0;
|
|
_object = 0;
|
|
_counterValue = 0;
|
|
_zeta0 = 0;
|
|
_zeta1 = 0;
|
|
_zeta2 = 0;
|
|
_musicCommand = 0;
|
|
_musicParm = 0;
|
|
}
|
|
|
|
Animation::Animation() {
|
|
gfxobj = nullptr;
|
|
_frame = 0;
|
|
_z = 0;
|
|
}
|
|
|
|
Animation::~Animation() {
|
|
if (gfxobj) {
|
|
gfxobj->release();
|
|
}
|
|
}
|
|
|
|
void Animation::getFrameRect(Common::Rect &r) const {
|
|
r.setWidth(0); r.setHeight(0);
|
|
if (!gfxobj) {
|
|
return;
|
|
}
|
|
gfxobj->getRect(_frame, r);
|
|
r.translate(_left, _top);
|
|
}
|
|
|
|
bool Animation::hitFrameRect(int x, int y) const {
|
|
if (!gfxobj) {
|
|
return false;
|
|
}
|
|
Common::Rect r;
|
|
getFrameRect(r);
|
|
return r.contains(x, y);
|
|
}
|
|
|
|
int16 Animation::getBottom() const {
|
|
int bottom = _top;
|
|
if (gfxobj) {
|
|
Common::Rect r;
|
|
getFrameRect(r);
|
|
bottom = r.bottom;
|
|
}
|
|
return bottom;
|
|
}
|
|
|
|
void Animation::resetZ() {
|
|
setZ(getBottom());
|
|
}
|
|
|
|
uint16 Animation::getFrameNum() const {
|
|
if (!gfxobj) return 0;
|
|
return gfxobj->getNum();
|
|
}
|
|
|
|
byte* Animation::getFrameData() const {
|
|
if (!gfxobj) return nullptr;
|
|
return gfxobj->getData(_frame);
|
|
}
|
|
|
|
void Animation::setF(int16 value) {
|
|
int16 min = MIN(0, getFrameNum() - 1);
|
|
int16 max = MAX(0, getFrameNum() - 1);
|
|
_frame = CLIP(value, min, max);
|
|
}
|
|
|
|
void Animation::forceXYZF(int16 x, int16 y, int16 z, int16 f) {
|
|
_left = x;
|
|
_top = y;
|
|
_z = z;
|
|
_frame = f;
|
|
}
|
|
|
|
void Animation::getFoot(Common::Point &foot) {
|
|
Common::Rect rect;
|
|
gfxobj->getRect(_frame, rect);
|
|
foot.x = getX() + (rect.left + rect.width() / 2);
|
|
foot.y = getY() + (rect.top + rect.height());
|
|
}
|
|
|
|
void Animation::setFoot(const Common::Point &foot) {
|
|
Common::Rect rect;
|
|
gfxobj->getRect(_frame, rect);
|
|
|
|
setX(foot.x - (rect.left + rect.width() / 2));
|
|
setY(foot.y - (rect.top + rect.height()));
|
|
}
|
|
|
|
#define NUM_LOCALS 10
|
|
char _localNames[NUM_LOCALS][10];
|
|
|
|
Program::Program() {
|
|
_loopCounter = 0;
|
|
_locals = new LocalVariable[NUM_LOCALS];
|
|
_numLocals = 0;
|
|
_status = kProgramIdle;
|
|
_ip = 0;
|
|
_loopStart = 0;
|
|
}
|
|
|
|
Program::~Program() {
|
|
delete[] _locals;
|
|
}
|
|
|
|
int16 Program::findLocal(const char* name) {
|
|
for (uint16 _si = 0; _si < NUM_LOCALS; _si++) {
|
|
if (!scumm_stricmp(name, _localNames[_si]))
|
|
return _si;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
int16 Program::addLocal(const char *name, int16 value, int16 min, int16 max) {
|
|
assert(_numLocals < NUM_LOCALS);
|
|
|
|
Common::strlcpy(_localNames[_numLocals], name, 10);
|
|
_locals[_numLocals].setRange(min, max);
|
|
_locals[_numLocals].setValue(value);
|
|
|
|
return _numLocals++;
|
|
}
|
|
|
|
void LocalVariable::setValue(int16 value) {
|
|
if (value >= _max)
|
|
value = _min;
|
|
if (value < _min)
|
|
value = _max - 1;
|
|
|
|
_value = value;
|
|
}
|
|
|
|
void LocalVariable::setRange(int16 min, int16 max) {
|
|
_max = max;
|
|
_min = min;
|
|
}
|
|
|
|
int16 LocalVariable::getValue() const {
|
|
return _value;
|
|
}
|
|
|
|
|
|
Zone::Zone() {
|
|
_left = _top = _right = _bottom = 0;
|
|
|
|
_type = 0;
|
|
|
|
_flags = kFlagsNoName;
|
|
_label = nullptr;
|
|
|
|
// BRA specific
|
|
_index = INVALID_ZONE_INDEX;
|
|
_locationIndex = INVALID_LOCATION_INDEX;
|
|
}
|
|
|
|
Zone::~Zone() {
|
|
g_vm->_gfx->unregisterLabel(_label);
|
|
delete _label;
|
|
}
|
|
|
|
void Zone::translate(int16 x, int16 y) {
|
|
_left += x;
|
|
_right += x;
|
|
_top += y;
|
|
_bottom += y;
|
|
}
|
|
|
|
bool Zone::hitRect(int x, int y) const {
|
|
// The scripts of Nippon Safes are full of invalid rectangles, used to
|
|
// provide 'special' features.
|
|
if (_right < _left || _bottom < _top) {
|
|
return false;
|
|
}
|
|
|
|
Common::Rect r(_left, _top, _right + 1, _bottom + 1);
|
|
r.grow(-1);
|
|
|
|
return r.contains(x, y);
|
|
}
|
|
|
|
Dialogue::Dialogue() {
|
|
memset(_questions, 0, sizeof(_questions));
|
|
_numQuestions = 0;
|
|
}
|
|
|
|
Dialogue::~Dialogue() {
|
|
for (int i = 0; i < NUM_QUESTIONS; i++) {
|
|
delete _questions[i];
|
|
}
|
|
}
|
|
|
|
Question *Dialogue::findQuestion(const Common::String &name) const {
|
|
for (uint i = 0; _questions[i]; ++i) {
|
|
if (_questions[i]->_name == name) {
|
|
return _questions[i];
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
void Dialogue::addQuestion(Question *q) {
|
|
assert(_numQuestions < NUM_QUESTIONS);
|
|
assert(q);
|
|
_questions[_numQuestions] = q;
|
|
_numQuestions++;
|
|
}
|
|
|
|
Answer::Answer() {
|
|
_mood = 0;
|
|
_noFlags = 0;
|
|
_yesFlags = 0;
|
|
_hasCounterCondition = false;
|
|
_counterValue = 0;
|
|
_counterOp = 0;
|
|
}
|
|
|
|
bool Answer::textIsNull() {
|
|
return (_text.equalsIgnoreCase("NULL"));
|
|
}
|
|
|
|
int Answer::speakerMood() {
|
|
return _mood & 0xF;
|
|
}
|
|
|
|
Question::Question(const Common::String &name) : _name(name), _mood(0) {
|
|
memset(_answers, 0, sizeof(_answers));
|
|
}
|
|
|
|
Question::~Question() {
|
|
for (uint32 i = 0; i < NUM_ANSWERS; i++) {
|
|
delete _answers[i];
|
|
}
|
|
}
|
|
|
|
bool Question::textIsNull() {
|
|
return (_text.equalsIgnoreCase("NULL"));
|
|
}
|
|
|
|
int Question::speakerMood() {
|
|
return _mood & 0xF;
|
|
}
|
|
|
|
int Question::balloonWinding() {
|
|
return _mood & 0x10;
|
|
}
|
|
|
|
|
|
Instruction::Instruction() {
|
|
_index = 0;
|
|
_flags = 0;
|
|
|
|
// common
|
|
_immediate = 0;
|
|
_endif = 0;
|
|
|
|
// BRA specific
|
|
_y = 0;
|
|
}
|
|
|
|
int16 ScriptVar::getValue() {
|
|
|
|
if (_flags & kParaImmediate) {
|
|
return _value;
|
|
}
|
|
|
|
if (_flags & kParaLocal) {
|
|
return _local->getValue();
|
|
}
|
|
|
|
if (_flags & kParaField) {
|
|
return _field->getValue();
|
|
}
|
|
|
|
if (_flags & kParaRandom) {
|
|
return (g_vm->_rnd.getRandomNumber(65536) * _value) >> 16;
|
|
}
|
|
|
|
error("Parameter is not an r-value");
|
|
return 0; // for compilers that don't support NORETURN
|
|
}
|
|
|
|
void ScriptVar::setValue(int16 value) {
|
|
if ((_flags & kParaLValue) == 0) {
|
|
error("Only l-value can be set");
|
|
}
|
|
|
|
if (_flags & kParaLocal) {
|
|
_local->setValue(value);
|
|
}
|
|
|
|
if (_flags & kParaField) {
|
|
_field->setValue(value);
|
|
}
|
|
|
|
}
|
|
|
|
void ScriptVar::setLocal(LocalVariable *local) {
|
|
_local = local;
|
|
_flags |= (kParaLocal | kParaLValue);
|
|
}
|
|
|
|
void ScriptVar::setField(Animation *anim, AnimationField::AccessorFunc accessor, AnimationField::MutatorFunc mutator) {
|
|
_field = new AnimationField(anim, accessor, mutator);
|
|
_flags |= (kParaField | kParaLValue);
|
|
}
|
|
|
|
void ScriptVar::setField(Animation *anim, AnimationField::AccessorFunc accessor) {
|
|
_field = new AnimationField(anim, accessor);
|
|
_flags |= kParaField;
|
|
}
|
|
|
|
void ScriptVar::setImmediate(int16 value) {
|
|
_value = value;
|
|
_flags |= kParaImmediate;
|
|
}
|
|
|
|
void ScriptVar::setRandom(int16 seed) {
|
|
_value = seed;
|
|
_flags |= kParaRandom;
|
|
}
|
|
|
|
|
|
ScriptVar::ScriptVar() {
|
|
_flags = 0;
|
|
_local = nullptr;
|
|
_value = 0;
|
|
_field = nullptr;
|
|
}
|
|
|
|
ScriptVar::~ScriptVar() {
|
|
delete _field;
|
|
}
|
|
|
|
|
|
Table::Table(uint32 size) : _size(size), _used(0), _disposeMemory(true) {
|
|
_data = (char**)calloc(size, sizeof(char *));
|
|
}
|
|
|
|
Table::Table(uint32 size, const char **data) : _size(size), _used(size), _disposeMemory(false) {
|
|
_data = const_cast<char **>(data);
|
|
}
|
|
|
|
Table::~Table() {
|
|
|
|
if (!_disposeMemory) return;
|
|
|
|
clear();
|
|
|
|
free(_data);
|
|
|
|
}
|
|
|
|
void Table::addData(const char* s) {
|
|
|
|
if (!(_used < _size))
|
|
error("Table overflow");
|
|
|
|
size_t ln = strlen(s) + 1;
|
|
char *data = (char *)malloc(ln);
|
|
Common::strcpy_s(data, ln, s);
|
|
_data[_used++] = data;
|
|
}
|
|
|
|
uint16 Table::lookup(const char* s) {
|
|
|
|
for (uint16 i = 0; i < _used; i++) {
|
|
if (!scumm_stricmp(_data[i], s)) return i + 1;
|
|
}
|
|
|
|
return notFound;
|
|
}
|
|
|
|
void Table::clear() {
|
|
for (uint32 i = 0; i < _used; i++)
|
|
free(_data[i]);
|
|
|
|
_used = 0;
|
|
}
|
|
|
|
const char *Table::item(uint index) const {
|
|
assert(index < _used);
|
|
return _data[index];
|
|
}
|
|
|
|
|
|
FixedTable::FixedTable(uint32 size, uint32 fixed) : Table(size), _numFixed(fixed) {
|
|
}
|
|
|
|
void FixedTable::clear() {
|
|
uint32 deleted = 0;
|
|
for (uint32 i = _numFixed; i < _used; i++) {
|
|
free(_data[i]);
|
|
_data[i] = nullptr;
|
|
deleted++;
|
|
}
|
|
|
|
_used -= deleted;
|
|
}
|
|
|
|
Table* createTableFromStream(uint32 size, Common::SeekableReadStream *stream) {
|
|
assert(stream);
|
|
|
|
Table *t = new Table(size);
|
|
assert(t);
|
|
|
|
Script s(stream, false);
|
|
s.readLineToken();
|
|
while (scumm_stricmp(_tokens[0], "ENDTABLE")) {
|
|
t->addData(_tokens[0]);
|
|
s.readLineToken();
|
|
}
|
|
delete stream;
|
|
return t;
|
|
}
|
|
|
|
|
|
} // namespace Parallaction
|