aboutsummaryrefslogtreecommitdiff
path: root/engines/parallaction
diff options
context:
space:
mode:
Diffstat (limited to 'engines/parallaction')
-rw-r--r--engines/parallaction/balloons.cpp456
-rw-r--r--engines/parallaction/callables_ns.cpp3
-rw-r--r--engines/parallaction/dialogue.cpp390
-rw-r--r--engines/parallaction/disk.h10
-rw-r--r--engines/parallaction/disk_br.cpp19
-rw-r--r--engines/parallaction/disk_ns.cpp8
-rw-r--r--engines/parallaction/exec.h241
-rw-r--r--engines/parallaction/exec_br.cpp159
-rw-r--r--engines/parallaction/exec_ns.cpp290
-rw-r--r--engines/parallaction/gfxbase.cpp44
-rw-r--r--engines/parallaction/graphics.cpp185
-rw-r--r--engines/parallaction/graphics.h49
-rw-r--r--engines/parallaction/gui_br.cpp2
-rw-r--r--engines/parallaction/input.cpp59
-rw-r--r--engines/parallaction/input.h11
-rw-r--r--engines/parallaction/module.mk1
-rw-r--r--engines/parallaction/objects.cpp3
-rw-r--r--engines/parallaction/parallaction.cpp136
-rw-r--r--engines/parallaction/parallaction.h168
-rw-r--r--engines/parallaction/parallaction_br.cpp37
-rw-r--r--engines/parallaction/parallaction_ns.cpp21
-rw-r--r--engines/parallaction/parser_br.cpp2
-rw-r--r--engines/parallaction/parser_ns.cpp2
-rw-r--r--engines/parallaction/sound.cpp4
-rw-r--r--engines/parallaction/walk.cpp174
25 files changed, 1581 insertions, 893 deletions
diff --git a/engines/parallaction/balloons.cpp b/engines/parallaction/balloons.cpp
new file mode 100644
index 0000000000..fab92dada9
--- /dev/null
+++ b/engines/parallaction/balloons.cpp
@@ -0,0 +1,456 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "parallaction/graphics.h"
+#include "parallaction/parallaction.h"
+
+namespace Parallaction {
+
+
+#define BALLOON_TRANSPARENT_COLOR_NS 2
+#define BALLOON_TRANSPARENT_COLOR_BR 0
+
+#define BALLOON_TAIL_WIDTH 12
+#define BALLOON_TAIL_HEIGHT 10
+
+
+byte _resBalloonTail[2][BALLOON_TAIL_WIDTH*BALLOON_TAIL_HEIGHT] = {
+ {
+ 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02,
+ 0x02, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02,
+ 0x02, 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x02, 0x00, 0x01, 0x01, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x00, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+ },
+ {
+ 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02,
+ 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x02, 0x02, 0x02,
+ 0x02, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x02, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x02, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x01, 0x01, 0x00, 0x02, 0x02,
+ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x02, 0x02
+ }
+};
+
+class BalloonManager_ns : public BalloonManager {
+
+ static int16 _dialogueBalloonX[5];
+
+ struct Balloon {
+ Common::Rect outerBox;
+ Common::Rect innerBox;
+ Graphics::Surface *surface;
+ GfxObj *obj;
+ } _intBalloons[5];
+
+ uint _numBalloons;
+
+ void drawWrappedText(Font *font, Graphics::Surface* surf, char *text, byte color, int16 wrapwidth);
+ int createBalloon(int16 w, int16 h, int16 winding, uint16 borderThickness);
+ Balloon *getBalloon(uint id);
+
+ Gfx *_gfx;
+
+public:
+ BalloonManager_ns(Gfx *gfx);
+ ~BalloonManager_ns();
+
+ void freeBalloons();
+ int setLocationBalloon(char *text, bool endGame);
+ int setDialogueBalloon(char *text, uint16 winding, byte textColor);
+ int setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, byte textColor);
+ void setBalloonText(uint id, char *text, byte textColor);
+ int hitTestDialogueBalloon(int x, int y);
+};
+
+int16 BalloonManager_ns::_dialogueBalloonX[5] = { 80, 120, 150, 150, 150 };
+
+BalloonManager_ns::BalloonManager_ns(Gfx *gfx) : _numBalloons(0), _gfx(gfx) {
+
+}
+
+BalloonManager_ns::~BalloonManager_ns() {
+
+}
+
+
+BalloonManager_ns::Balloon* BalloonManager_ns::getBalloon(uint id) {
+ assert(id < _numBalloons);
+ return &_intBalloons[id];
+}
+
+int BalloonManager_ns::createBalloon(int16 w, int16 h, int16 winding, uint16 borderThickness) {
+ assert(_numBalloons < 5);
+
+ int id = _numBalloons;
+
+ Balloon *balloon = &_intBalloons[id];
+
+ int16 real_h = (winding == -1) ? h : h + 9;
+ balloon->surface = new Graphics::Surface;
+ balloon->surface->create(w, real_h, 1);
+ balloon->surface->fillRect(Common::Rect(w, real_h), BALLOON_TRANSPARENT_COLOR_NS);
+
+ Common::Rect r(w, h);
+ balloon->surface->fillRect(r, 0);
+ balloon->outerBox = r;
+
+ r.grow(-borderThickness);
+ balloon->surface->fillRect(r, 1);
+ balloon->innerBox = r;
+
+ if (winding != -1) {
+ // draws tail
+ // TODO: this bitmap tail should only be used for Dos games. Amiga should use a polygon fill.
+ winding = (winding == 0 ? 1 : 0);
+ Common::Rect s(BALLOON_TAIL_WIDTH, BALLOON_TAIL_HEIGHT);
+ s.moveTo(r.width()/2 - 5, r.bottom - 1);
+ _gfx->blt(s, _resBalloonTail[winding], balloon->surface, LAYER_FOREGROUND, BALLOON_TRANSPARENT_COLOR_NS);
+ }
+
+ _numBalloons++;
+
+ return id;
+}
+
+
+int BalloonManager_ns::setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, byte textColor) {
+
+ int16 w, h;
+
+ _gfx->getStringExtent(_vm->_dialogueFont, text, MAX_BALLOON_WIDTH, &w, &h);
+
+ int id = createBalloon(w+5, h, winding, 1);
+ Balloon *balloon = &_intBalloons[id];
+
+ _gfx->drawWrappedText(_vm->_dialogueFont, balloon->surface, text, textColor, MAX_BALLOON_WIDTH);
+
+ // TODO: extract some text to make a name for obj
+ balloon->obj = _gfx->registerBalloon(new SurfaceToFrames(balloon->surface), 0);
+ balloon->obj->x = x;
+ balloon->obj->y = y;
+ balloon->obj->transparentKey = BALLOON_TRANSPARENT_COLOR_NS;
+
+ return id;
+}
+
+int BalloonManager_ns::setDialogueBalloon(char *text, uint16 winding, byte textColor) {
+
+ int16 w, h;
+
+ _gfx->getStringExtent(_vm->_dialogueFont, text, MAX_BALLOON_WIDTH, &w, &h);
+
+ int id = createBalloon(w+5, h, winding, 1);
+ Balloon *balloon = &_intBalloons[id];
+
+ _gfx->drawWrappedText(_vm->_dialogueFont, balloon->surface, text, textColor, MAX_BALLOON_WIDTH);
+
+ // TODO: extract some text to make a name for obj
+ balloon->obj = _gfx->registerBalloon(new SurfaceToFrames(balloon->surface), 0);
+ balloon->obj->x = _dialogueBalloonX[id];
+ balloon->obj->y = 10;
+ balloon->obj->transparentKey = BALLOON_TRANSPARENT_COLOR_NS;
+
+ if (id > 0) {
+ balloon->obj->y += _intBalloons[id - 1].obj->y + _intBalloons[id - 1].outerBox.height();
+ }
+
+
+ return id;
+}
+
+void BalloonManager_ns::setBalloonText(uint id, char *text, byte textColor) {
+ Balloon *balloon = getBalloon(id);
+ balloon->surface->fillRect(balloon->innerBox, 1);
+ _gfx->drawWrappedText(_vm->_dialogueFont, balloon->surface, text, textColor, MAX_BALLOON_WIDTH);
+}
+
+
+int BalloonManager_ns::setLocationBalloon(char *text, bool endGame) {
+
+ int16 w, h;
+
+ _gfx->getStringExtent(_vm->_dialogueFont, text, MAX_BALLOON_WIDTH, &w, &h);
+
+ int id = createBalloon(w+(endGame ? 5 : 10), h+5, -1, BALLOON_TRANSPARENT_COLOR_NS);
+ Balloon *balloon = &_intBalloons[id];
+ _gfx->drawWrappedText(_vm->_dialogueFont, balloon->surface, text, 0, MAX_BALLOON_WIDTH);
+
+ // TODO: extract some text to make a name for obj
+ balloon->obj = _gfx->registerBalloon(new SurfaceToFrames(balloon->surface), 0);
+ balloon->obj->x = 5;
+ balloon->obj->y = 5;
+ balloon->obj->transparentKey = BALLOON_TRANSPARENT_COLOR_NS;
+
+ return id;
+}
+
+int BalloonManager_ns::hitTestDialogueBalloon(int x, int y) {
+
+ Common::Point p;
+
+ for (uint i = 0; i < _numBalloons; i++) {
+ p.x = x - _intBalloons[i].obj->x;
+ p.y = y - _intBalloons[i].obj->y;
+
+ if (_intBalloons[i].innerBox.contains(p))
+ return i;
+ }
+
+ return -1;
+}
+
+void BalloonManager_ns::freeBalloons() {
+ _gfx->destroyBalloons();
+
+ for (uint i = 0; i < _numBalloons; i++) {
+ _intBalloons[i].obj = 0;
+ _intBalloons[i].surface = 0; // no need to delete surface, since it is done by destroyBalloons
+ }
+
+ _numBalloons = 0;
+}
+
+
+
+
+
+
+
+
+class BalloonManager_br : public BalloonManager {
+
+ struct Balloon {
+ Common::Rect box;
+ Graphics::Surface *surface;
+ GfxObj *obj;
+ } _intBalloons[3];
+
+ uint _numBalloons;
+
+ Frames *_leftBalloon;
+ Frames *_rightBalloon;
+ Disk *_disk;
+ Gfx *_gfx;
+
+ void cacheAnims();
+ void drawWrappedText(Font *font, Graphics::Surface* surf, char *text, byte color, int16 wrapwidth);
+ int createBalloon(int16 w, int16 h, int16 winding, uint16 borderThickness);
+ Balloon *getBalloon(uint id);
+ Graphics::Surface *expandBalloon(Frames *data, int frameNum);
+
+
+public:
+ BalloonManager_br(Disk *disk, Gfx *gfx);
+ ~BalloonManager_br();
+
+ void freeBalloons();
+ int setLocationBalloon(char *text, bool endGame);
+ int setDialogueBalloon(char *text, uint16 winding, byte textColor);
+ int setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, byte textColor);
+ void setBalloonText(uint id, char *text, byte textColor);
+ int hitTestDialogueBalloon(int x, int y);
+};
+
+
+
+BalloonManager_br::Balloon* BalloonManager_br::getBalloon(uint id) {
+ assert(id < _numBalloons);
+ return &_intBalloons[id];
+}
+
+Graphics::Surface *BalloonManager_br::expandBalloon(Frames *data, int frameNum) {
+
+ Common::Rect rect;
+ data->getRect(frameNum, rect);
+
+ rect.translate(-rect.left, -rect.top);
+
+ Graphics::Surface *surf = new Graphics::Surface;
+ surf->create(rect.width(), rect.height(), 1);
+
+ _gfx->unpackBlt(rect, data->getData(frameNum), data->getRawSize(frameNum), surf, 0, BALLOON_TRANSPARENT_COLOR_BR);
+
+ return surf;
+}
+
+int BalloonManager_br::setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, byte textColor) {
+ cacheAnims();
+
+ int id = _numBalloons;
+ Frames *src = 0;
+ int srcFrame = 0;
+
+ Balloon *balloon = &_intBalloons[id];
+
+ if (winding == 0) {
+ src = _leftBalloon;
+ srcFrame = 0;
+ } else
+ if (winding == 1) {
+ src = _rightBalloon;
+ srcFrame = 0;
+ }
+
+ assert(src);
+
+ balloon->surface = expandBalloon(src, srcFrame);
+ src->getRect(srcFrame, balloon->box);
+
+// drawWrappedText(_vm->_dialogueFont, balloon->surface, text, textColor, MAX_BALLOON_WIDTH);
+
+ // TODO: extract some text to make a name for obj
+ balloon->obj = _gfx->registerBalloon(new SurfaceToFrames(balloon->surface), 0);
+ balloon->obj->x = x;
+ balloon->obj->y = y;
+ balloon->obj->transparentKey = BALLOON_TRANSPARENT_COLOR_BR;
+
+ _numBalloons++;
+
+ return id;
+}
+
+int BalloonManager_br::setDialogueBalloon(char *text, uint16 winding, byte textColor) {
+ cacheAnims();
+
+ int id = _numBalloons;
+ Frames *src = 0;
+ int srcFrame = 0;
+
+ Balloon *balloon = &_intBalloons[id];
+
+ if (winding == 0) {
+ src = _leftBalloon;
+ srcFrame = id;
+ } else
+ if (winding == 1) {
+ src = _rightBalloon;
+ srcFrame = 0;
+ }
+
+ assert(src);
+
+ balloon->surface = expandBalloon(src, srcFrame);
+ src->getRect(srcFrame, balloon->box);
+
+// drawWrappedText(_vm->_dialogueFont, balloon->surface, text, textColor, MAX_BALLOON_WIDTH);
+
+ // TODO: extract some text to make a name for obj
+ balloon->obj = _gfx->registerBalloon(new SurfaceToFrames(balloon->surface), 0);
+ balloon->obj->x = 0;
+ balloon->obj->y = 10;
+ balloon->obj->transparentKey = BALLOON_TRANSPARENT_COLOR_BR;
+
+ if (id > 0) {
+ balloon->obj->y += _intBalloons[id - 1].obj->y + _intBalloons[id - 1].box.height();
+ }
+
+ _numBalloons++;
+
+ return id;
+}
+
+void BalloonManager_br::setBalloonText(uint id, char *text, byte textColor) { }
+
+int BalloonManager_br::setLocationBalloon(char *text, bool endGame) {
+/*
+ int16 w, h;
+
+ getStringExtent(_vm->_dialogueFont, text, MAX_BALLOON_WIDTH, &w, &h);
+
+ int id = createBalloon(w+(endGame ? 5 : 10), h+5, -1, BALLOON_TRANSPARENT_COLOR);
+ Balloon *balloon = &_intBalloons[id];
+ drawWrappedText(_vm->_dialogueFont, balloon->surface, text, 0, MAX_BALLOON_WIDTH);
+
+ // TODO: extract some text to make a name for obj
+ balloon->obj = _gfx->registerBalloon(new SurfaceToFrames(balloon->surface), 0);
+ balloon->obj->x = 5;
+ balloon->obj->y = 5;
+*/
+ return 0;
+}
+
+int BalloonManager_br::hitTestDialogueBalloon(int x, int y) {
+
+ Common::Point p;
+
+ for (uint i = 0; i < _numBalloons; i++) {
+ p.x = x - _intBalloons[i].obj->x;
+ p.y = y - _intBalloons[i].obj->y;
+
+ if (_intBalloons[i].box.contains(p))
+ return i;
+ }
+
+ return -1;
+}
+
+void BalloonManager_br::freeBalloons() {
+ _gfx->destroyBalloons();
+
+ for (uint i = 0; i < _numBalloons; i++) {
+ _intBalloons[i].obj = 0;
+ _intBalloons[i].surface = 0; // no need to delete surface, since it is done by destroyBalloons
+ }
+
+ _numBalloons = 0;
+}
+
+void BalloonManager_br::cacheAnims() {
+ if (!_leftBalloon) {
+ _leftBalloon = _disk->loadFrames("fumetto.ani");
+ _rightBalloon = _disk->loadFrames("fumdx.ani");
+ }
+}
+
+BalloonManager_br::BalloonManager_br(Disk *disk, Gfx *gfx) : _numBalloons(0), _disk(disk), _gfx(gfx), _leftBalloon(0), _rightBalloon(0) {
+}
+
+BalloonManager_br::~BalloonManager_br() {
+ delete _leftBalloon;
+ delete _rightBalloon;
+}
+
+void Parallaction::setupBalloonManager() {
+ if (_vm->getGameType() == GType_Nippon) {
+ _balloonMan = new BalloonManager_ns(_vm->_gfx);
+ } else
+ if (_vm->getGameType() == GType_BRA) {
+ _balloonMan = new BalloonManager_br(_vm->_disk, _vm->_gfx);
+ } else {
+ error("Unknown game type");
+ }
+}
+
+} // namespace Parallaction
diff --git a/engines/parallaction/callables_ns.cpp b/engines/parallaction/callables_ns.cpp
index 3ecc7a9534..ed60a193ce 100644
--- a/engines/parallaction/callables_ns.cpp
+++ b/engines/parallaction/callables_ns.cpp
@@ -341,7 +341,7 @@ void Parallaction_ns::_c_endComment(void *param) {
}
_input->waitUntilLeftClick();
- _gfx->freeBalloons();
+ _balloonMan->freeBalloons();
return;
}
@@ -424,6 +424,7 @@ void Parallaction_ns::_c_testResult(void *parm) {
}
_inTestResult = true;
+ _gfx->freeLabels();
_gfx->updateScreen();
_disk->selectArchive("disk1");
diff --git a/engines/parallaction/dialogue.cpp b/engines/parallaction/dialogue.cpp
index 3b6c35d3bb..290f8cfd4f 100644
--- a/engines/parallaction/dialogue.cpp
+++ b/engines/parallaction/dialogue.cpp
@@ -42,13 +42,23 @@ namespace Parallaction {
#define ANSWER_CHARACTER_X 10
#define ANSWER_CHARACTER_Y 80
+
class DialogueManager {
+ enum {
+ RUN_QUESTION,
+ RUN_ANSWER,
+ NEXT_QUESTION,
+ NEXT_ANSWER,
+ DIALOGUE_OVER
+ } _state;
+
Parallaction *_vm;
- SpeakData *_data;
Dialogue *_dialogue;
bool _askPassword;
+ int _passwordLen;
+ bool _passwordChanged;
bool isNpc;
GfxObj *_questioner;
@@ -59,98 +69,70 @@ class DialogueManager {
uint16 _visAnswers[5];
int _numVisAnswers;
+ int _answerId;
+
+ int _selection, _oldSelection;
+
+ uint32 _mouseButtons;
+ Common::Point _mousePos;
+ bool _isKeyDown;
+ uint16 _downKey;
+
+
public:
- DialogueManager(Parallaction *vm, SpeakData *data) : _vm(vm), _data(data) {
- _dialogue = _data->_dialogue;
- isNpc = scumm_stricmp(_data->_name, "yourself") && _data->_name[0] != '\0';
- _questioner = isNpc ? _vm->_disk->loadTalk(_data->_name) : _vm->_char._talk;
- _answerer = _vm->_char._talk;
- }
+ DialogueManager(Parallaction *vm, ZonePtr z);
+ ~DialogueManager();
- ~DialogueManager() {
- if (isNpc) {
- delete _questioner;
- }
+ bool isOver() {
+ return _state == DIALOGUE_OVER;
}
-
void run();
+ ZonePtr _z;
+ CommandList *_cmdList;
+
protected:
- void displayQuestion();
+ bool displayQuestion();
bool displayAnswers();
bool displayAnswer(uint16 i);
- uint16 getAnswer();
- int16 selectAnswer();
- uint16 askPassword();
+ int16 selectAnswer1();
+ int16 selectAnswerN();
+ int16 askPassword();
int16 getHoverAnswer(int16 x, int16 y);
-};
-
-uint16 DialogueManager::askPassword() {
- debugC(3, kDebugExec, "checkDialoguePassword()");
-
- uint16 passwordLen = 0;
- _password[0] = '\0';
-
- _vm->_gfx->setDialogueBalloon(_q->_answers[0]->_text, 1, 3);
- int id = _vm->_gfx->setItem(_answerer, ANSWER_CHARACTER_X, ANSWER_CHARACTER_Y);
- _vm->_gfx->setItemFrame(id, 0);
-
- Common::Event e;
- bool changed = true; // force first refresh
-
- while (true) {
- e.kbd.ascii = 0;
-
- if (g_system->getEventManager()->pollEvent(e)) {
- if (e.type == Common::EVENT_QUIT) {
- _engineFlags |= kEngineQuit;
- break;
- }
-
- if ((e.type == Common::EVENT_KEYDOWN) && isdigit(e.kbd.ascii)) {
- _password[passwordLen] = e.kbd.ascii;
- passwordLen++;
- _password[passwordLen] = '\0';
- changed = true;
- }
- }
-
- if (changed) {
- _vm->_gfx->setBalloonText(0, _q->_answers[0]->_text, 3);
- _vm->_gfx->updateScreen();
- changed = false;
- }
-
- if ((passwordLen == MAX_PASSWORD_LENGTH) || (e.kbd.ascii == Common::KEYCODE_RETURN)) {
+ void runQuestion();
+ void runAnswer();
+ void nextQuestion();
+ void nextAnswer();
- if ((!scumm_stricmp(_vm->_char.getBaseName(), _doughName) && !scumm_strnicmp(_password, "1732461", 7)) ||
- (!scumm_stricmp(_vm->_char.getBaseName(), _donnaName) && !scumm_strnicmp(_password, "1622", 4)) ||
- (!scumm_stricmp(_vm->_char.getBaseName(), _dinoName) && !scumm_strnicmp(_password, "179", 3))) {
+ bool checkPassword();
+ void resetPassword();
+ void accumPassword(uint16 ascii);
+};
- break;
+DialogueManager::DialogueManager(Parallaction *vm, ZonePtr z) : _vm(vm), _z(z) {
+ _dialogue = _z->u.speak->_dialogue;
+ isNpc = scumm_stricmp(_z->u.speak->_name, "yourself") && _z->u.speak->_name[0] != '\0';
+ _questioner = isNpc ? _vm->_disk->loadTalk(_z->u.speak->_name) : _vm->_char._talk;
+ _answerer = _vm->_char._talk;
- } else {
- passwordLen = 0;
- _password[0] = '\0';
- changed = true;
- }
+ _askPassword = false;
+ _q = _dialogue->_questions[0];
- }
+ _cmdList = 0;
+ _answerId = 0;
- g_system->delayMillis(20);
+ _state = displayQuestion() ? RUN_QUESTION : NEXT_ANSWER;
+}
+DialogueManager::~DialogueManager() {
+ if (isNpc) {
+ delete _questioner;
}
-
- _vm->_gfx->hideDialogueStuff();
-
- return 0;
-
+ _z = nullZonePtr;
}
-
-
bool DialogueManager::displayAnswer(uint16 i) {
Answer *a = _q->_answers[i];
@@ -162,11 +144,11 @@ bool DialogueManager::displayAnswer(uint16 i) {
// display suitable answers
if (((a->_yesFlags & flags) == a->_yesFlags) && ((a->_noFlags & ~flags) == a->_noFlags)) {
- int id = _vm->_gfx->setDialogueBalloon(a->_text, 1, 3);
+ int id = _vm->_balloonMan->setDialogueBalloon(a->_text, 1, 3);
assert(id >= 0);
_visAnswers[id] = i;
- _askPassword = (strstr(a->_text, "%p") != NULL);
+ _askPassword = (strstr(a->_text, "%P") != NULL);
_numVisAnswers++;
return true;
@@ -183,134 +165,242 @@ bool DialogueManager::displayAnswers() {
displayAnswer(i);
}
+ if (_askPassword) {
+ resetPassword();
+// _vm->_balloonMan->setDialogueBalloon(_q->_answers[0]->_text, 1, 3);
+ int id = _vm->_gfx->setItem(_answerer, ANSWER_CHARACTER_X, ANSWER_CHARACTER_Y);
+ _vm->_gfx->setItemFrame(id, 0);
+ } else
+ if (_numVisAnswers == 1) {
+ int id = _vm->_gfx->setItem(_answerer, ANSWER_CHARACTER_X, ANSWER_CHARACTER_Y);
+ _vm->_gfx->setItemFrame(id, _q->_answers[0]->_mood & 0xF);
+ _vm->_balloonMan->setBalloonText(0, _q->_answers[_visAnswers[0]]->_text, 0);
+ } else
+ if (_numVisAnswers > 1) {
+ int id = _vm->_gfx->setItem(_answerer, ANSWER_CHARACTER_X, ANSWER_CHARACTER_Y);
+ _vm->_gfx->setItemFrame(id, _q->_answers[_visAnswers[0]]->_mood & 0xF);
+ _oldSelection = -1;
+ _selection = 0;
+ }
+
return _numVisAnswers > 0;
}
-void DialogueManager::displayQuestion() {
-
- if (!scumm_stricmp(_q->_text, "NULL")) return;
+bool DialogueManager::displayQuestion() {
+ if (!scumm_stricmp(_q->_text, "NULL")) return false;
- _vm->_gfx->setSingleBalloon(_q->_text, QUESTION_BALLOON_X, QUESTION_BALLOON_Y, _q->_mood & 0x10, 0);
+ _vm->_balloonMan->setSingleBalloon(_q->_text, QUESTION_BALLOON_X, QUESTION_BALLOON_Y, _q->_mood & 0x10, 0);
int id = _vm->_gfx->setItem(_questioner, QUESTION_CHARACTER_X, QUESTION_CHARACTER_Y);
_vm->_gfx->setItemFrame(id, _q->_mood & 0xF);
- _vm->_gfx->updateScreen();
- _vm->_input->waitUntilLeftClick();
- _vm->_gfx->hideDialogueStuff();
+ return true;
+}
- return;
+
+bool DialogueManager::checkPassword() {
+ return ((!scumm_stricmp(_vm->_char.getBaseName(), _doughName) && !scumm_strnicmp(_password, "1732461", 7)) ||
+ (!scumm_stricmp(_vm->_char.getBaseName(), _donnaName) && !scumm_strnicmp(_password, "1622", 4)) ||
+ (!scumm_stricmp(_vm->_char.getBaseName(), _dinoName) && !scumm_strnicmp(_password, "179", 3)));
}
-uint16 DialogueManager::getAnswer() {
+void DialogueManager::resetPassword() {
+ _passwordLen = 0;
+ _password[0] = '\0';
+ _passwordChanged = true;
+}
- uint16 answer = 0;
+void DialogueManager::accumPassword(uint16 ascii) {
+ if (!isdigit(ascii)) {
+ return;
+ }
- if (_askPassword == false) {
- answer = selectAnswer();
- } else {
- answer = askPassword();
+ _password[_passwordLen] = ascii;
+ _passwordLen++;
+ _password[_passwordLen] = '\0';
+ _passwordChanged = true;
+}
+
+int16 DialogueManager::askPassword() {
+
+ if (_isKeyDown) {
+ accumPassword(_downKey);
+ }
+
+ if (_passwordChanged) {
+ _vm->_balloonMan->setBalloonText(0, _q->_answers[0]->_text, 3);
+ _passwordChanged = false;
}
- debugC(3, kDebugExec, "runDialogue: user selected answer #%i", answer);
+ if ((_passwordLen == MAX_PASSWORD_LENGTH) || ((_isKeyDown) && (_downKey == Common::KEYCODE_RETURN))) {
+ if (checkPassword()) {
+ return 0;
+ } else {
+ resetPassword();
+ }
+ }
- return answer;
+ return -1;
}
-void DialogueManager::run() {
+int16 DialogueManager::selectAnswer1() {
- _askPassword = false;
- CommandList *cmdlist = NULL;
+ if (_mouseButtons == kMouseLeftUp) {
+ return 0;
+ }
- _q = _dialogue->_questions[0];
- int16 answer;
+ return -1;
+}
- while (_q) {
+int16 DialogueManager::selectAnswerN() {
- answer = 0;
+ _selection = _vm->_balloonMan->hitTestDialogueBalloon(_mousePos.x, _mousePos.y);
- displayQuestion();
+ if (_selection != _oldSelection) {
+ if (_oldSelection != -1) {
+ _vm->_balloonMan->setBalloonText(_oldSelection, _q->_answers[_visAnswers[_oldSelection]]->_text, 3);
+ }
- if (_engineFlags & kEngineQuit)
- return;
+ if (_selection != -1) {
+ _vm->_balloonMan->setBalloonText(_selection, _q->_answers[_visAnswers[_selection]]->_text, 0);
+ _vm->_gfx->setItemFrame(0, _q->_answers[_visAnswers[_selection]]->_mood & 0xF);
+ }
+ }
- if (_q->_answers[0] == NULL) break;
+ _oldSelection = _selection;
- if (scumm_stricmp(_q->_answers[0]->_text, "NULL")) {
- if (!displayAnswers()) break;
- answer = getAnswer();
+ if ((_mouseButtons == kMouseLeftUp) && (_selection != -1)) {
+ return _visAnswers[_selection];
+ }
- if (_engineFlags & kEngineQuit)
- return;
+ return -1;
+}
- cmdlist = &_q->_answers[answer]->_commands;
- }
+void DialogueManager::runQuestion() {
+ debugC(9, kDebugDialogue, "runQuestion\n");
+
+ if (_mouseButtons == kMouseLeftUp) {
+ _vm->hideDialogueStuff();
+ _state = NEXT_ANSWER;
+ }
+
+}
- _q = _q->_answers[answer]->_following._question;
+
+void DialogueManager::nextAnswer() {
+ debugC(9, kDebugDialogue, "nextAnswer\n");
+
+ if (_q->_answers[0] == NULL) {
+ _state = DIALOGUE_OVER;
+ return;
}
- if (cmdlist)
- _vm->runCommands(*cmdlist);
+ if (!scumm_stricmp(_q->_answers[0]->_text, "NULL")) {
+ _answerId = 0;
+ _state = NEXT_QUESTION;
+ return;
+ }
+ _state = displayAnswers() ? RUN_ANSWER : DIALOGUE_OVER;
}
-int16 DialogueManager::selectAnswer() {
+void DialogueManager::runAnswer() {
+ debugC(9, kDebugDialogue, "runAnswer\n");
- int16 numAvailableAnswers = _numVisAnswers;
+ if (_askPassword) {
+ _answerId = askPassword();
+ } else
+ if (_numVisAnswers == 1) {
+ _answerId = selectAnswer1();
+ } else {
+ _answerId = selectAnswerN();
+ }
- int id = _vm->_gfx->setItem(_answerer, ANSWER_CHARACTER_X, ANSWER_CHARACTER_Y);
- _vm->_gfx->setItemFrame(id, _q->_answers[0]->_mood & 0xF);
+ if (_answerId != -1) {
+ _cmdList = &_q->_answers[_answerId]->_commands;
+ _vm->hideDialogueStuff();
+ _state = NEXT_QUESTION;
+ }
+}
- if (numAvailableAnswers == 1) {
- _vm->_gfx->setBalloonText(0, _q->_answers[0]->_text, 0);
- _vm->_input->waitUntilLeftClick();
- _vm->_gfx->hideDialogueStuff();
- return 0;
+void DialogueManager::nextQuestion() {
+ debugC(9, kDebugDialogue, "nextQuestion\n");
+
+ _q = _q->_answers[_answerId]->_following._question;
+ if (_q == 0) {
+ _state = DIALOGUE_OVER;
+ } else {
+ _state = displayQuestion() ? RUN_QUESTION : NEXT_ANSWER;
}
+}
- int oldSelection = -1;
- int selection = 0;
- uint32 event;
- Common::Point p;
- while ((_engineFlags & kEngineQuit) == 0) {
+void DialogueManager::run() {
- _vm->_input->readInput();
- _vm->_input->getCursorPos(p);
- event = _vm->_input->getLastButtonEvent();
- selection = _vm->_gfx->hitTestDialogueBalloon(p.x, p.y);
+ // cache event data
+ _mouseButtons = _vm->_input->getLastButtonEvent();
+ _vm->_input->getCursorPos(_mousePos);
+ _isKeyDown = _vm->_input->getLastKeyDown(_downKey);
- if (selection != oldSelection) {
- if (oldSelection != -1) {
- _vm->_gfx->setBalloonText(oldSelection, _q->_answers[_visAnswers[oldSelection]]->_text, 3);
- }
+ switch (_state) {
+ case RUN_QUESTION:
+ runQuestion();
+ break;
- if (selection != -1) {
- _vm->_gfx->setBalloonText(selection, _q->_answers[_visAnswers[selection]]->_text, 0);
- _vm->_gfx->setItemFrame(0, _q->_answers[_visAnswers[selection]]->_mood & 0xF);
- }
- }
+ case NEXT_ANSWER:
+ nextAnswer();
+ break;
+
+ case NEXT_QUESTION:
+ nextQuestion();
+ break;
- if ((selection != -1) && (event == kMouseLeftUp)) {
- break;
+ case RUN_ANSWER:
+ runAnswer();
+ break;
+
+ case DIALOGUE_OVER:
+ if (_cmdList) {
+ _vm->_cmdExec->run(*_cmdList);
}
+ break;
- _vm->_gfx->updateScreen();
- g_system->delayMillis(20);
+ default:
+ error("unknown state in DialogueManager");
- oldSelection = selection;
}
- _vm->_gfx->hideDialogueStuff();
+}
- return _visAnswers[selection];
+void Parallaction::enterDialogueMode(ZonePtr z) {
+ debugC(1, kDebugDialogue, "Parallaction::enterDialogueMode(%s)", z->u.speak->_name);
+ _dialogueMan = new DialogueManager(this, z);
+ _input->_inputMode = Input::kInputModeDialogue;
}
+void Parallaction::exitDialogueMode() {
+ debugC(1, kDebugDialogue, "Parallaction::exitDialogueMode()");
+ _input->_inputMode = Input::kInputModeGame;
-void Parallaction::runDialogue(SpeakData *data) {
- debugC(1, kDebugExec, "runDialogue: starting dialogue '%s'", data->_name);
+ // The current instance of _dialogueMan must be destroyed before the zone commands
+ // are executed, because they may create another instance of _dialogueMan that
+ // overwrite the current one. This would cause headaches (and it did, actually).
+ ZonePtr z = _dialogueMan->_z;
+ delete _dialogueMan;
+ _dialogueMan = 0;
- DialogueManager man(this, data);
- man.run();
+ _cmdExec->run(z->_commands, z);
+}
+
+void Parallaction::runDialogueFrame() {
+ if (_input->_inputMode != Input::kInputModeDialogue) {
+ return;
+ }
+
+ _dialogueMan->run();
+
+ if (_dialogueMan->isOver()) {
+ exitDialogueMode();
+ }
return;
}
diff --git a/engines/parallaction/disk.h b/engines/parallaction/disk.h
index 176f10aa10..694d4efa6d 100644
--- a/engines/parallaction/disk.h
+++ b/engines/parallaction/disk.h
@@ -61,7 +61,7 @@ public:
virtual GfxObj* loadHead(const char* name) = 0;
virtual Font* loadFont(const char* name) = 0;
virtual GfxObj* loadStatic(const char* name) = 0;
- virtual GfxObj* loadFrames(const char* name) = 0;
+ virtual Frames* loadFrames(const char* name) = 0;
virtual void loadSlide(BackgroundInfo& info, const char *filename) = 0;
virtual void loadScenery(BackgroundInfo& info, const char* background, const char* mask, const char* path) = 0;
virtual Table* loadTable(const char* name) = 0;
@@ -153,7 +153,7 @@ public:
GfxObj* loadHead(const char* name);
Font* loadFont(const char* name);
GfxObj* loadStatic(const char* name);
- GfxObj* loadFrames(const char* name);
+ Frames* loadFrames(const char* name);
void loadSlide(BackgroundInfo& info, const char *filename);
void loadScenery(BackgroundInfo& info, const char* background, const char* mask, const char* path);
Table* loadTable(const char* name);
@@ -187,7 +187,7 @@ public:
GfxObj* loadHead(const char* name);
Font* loadFont(const char* name);
GfxObj* loadStatic(const char* name);
- GfxObj* loadFrames(const char* name);
+ Frames* loadFrames(const char* name);
void loadSlide(BackgroundInfo& info, const char *filename);
void loadScenery(BackgroundInfo& info, const char* background, const char* mask, const char* path);
Table* loadTable(const char* name);
@@ -226,7 +226,7 @@ public:
GfxObj* loadHead(const char* name);
Font* loadFont(const char* name);
GfxObj* loadStatic(const char* name);
- GfxObj* loadFrames(const char* name);
+ Frames* loadFrames(const char* name);
void loadSlide(BackgroundInfo& info, const char *filename);
void loadScenery(BackgroundInfo& info, const char* name, const char* mask, const char* path);
Table* loadTable(const char* name);
@@ -251,7 +251,7 @@ public:
GfxObj* loadTalk(const char *name);
Font* loadFont(const char* name);
GfxObj* loadStatic(const char* name);
- GfxObj* loadFrames(const char* name);
+ Frames* loadFrames(const char* name);
void loadSlide(BackgroundInfo& info, const char *filename);
void loadScenery(BackgroundInfo& info, const char* name, const char* mask, const char* path);
};
diff --git a/engines/parallaction/disk_br.cpp b/engines/parallaction/disk_br.cpp
index 0159d9d406..ee1e111139 100644
--- a/engines/parallaction/disk_br.cpp
+++ b/engines/parallaction/disk_br.cpp
@@ -58,7 +58,7 @@ struct Sprites : public Frames {
}
~Sprites() {
- delete _sprites;
+ delete[] _sprites;
}
uint16 getNum() {
@@ -280,18 +280,21 @@ Sprites* DosDisk_br::createSprites(Common::ReadStream &stream) {
return sprites;
}
-GfxObj* DosDisk_br::loadFrames(const char* name) {
+Frames* DosDisk_br::loadFrames(const char* name) {
debugC(5, kDebugDisk, "DosDisk_br::loadFrames");
char path[PATH_LEN];
sprintf(path, "%s/ani/%s", _partPath, name);
Common::File stream;
- if (!stream.open(path))
- errorFileNotFound(path);
-
+ if (!stream.open(path)) {
+ sprintf(path, "%s/ani/%s.ani", _partPath, name);
+ if (!stream.open(path)) {
+ errorFileNotFound(path);
+ }
+ }
- return new GfxObj(0, createSprites(stream), name);
+ return createSprites(stream);
}
// Slides in Nippon Safes are basically screen-sized pictures with valid
@@ -600,13 +603,13 @@ Sprites* AmigaDisk_br::createSprites(const char *path) {
return sprites;
}
-GfxObj* AmigaDisk_br::loadFrames(const char* name) {
+Frames* AmigaDisk_br::loadFrames(const char* name) {
debugC(1, kDebugDisk, "AmigaDisk_br::loadFrames '%s'", name);
char path[PATH_LEN];
sprintf(path, "%s/anims/%s", _partPath, name);
- return new GfxObj(0, createSprites(path));
+ return createSprites(path);
}
GfxObj* AmigaDisk_br::loadTalk(const char *name) {
diff --git a/engines/parallaction/disk_ns.cpp b/engines/parallaction/disk_ns.cpp
index f45cf83f56..55e6fc5e77 100644
--- a/engines/parallaction/disk_ns.cpp
+++ b/engines/parallaction/disk_ns.cpp
@@ -490,8 +490,8 @@ GfxObj* DosDisk_ns::loadStatic(const char* name) {
return new GfxObj(0, new SurfaceToFrames(cnv), name);
}
-GfxObj* DosDisk_ns::loadFrames(const char* name) {
- return new GfxObj(0, loadCnv(name), name);
+Frames* DosDisk_ns::loadFrames(const char* name) {
+ return loadCnv(name);
}
//
@@ -1258,7 +1258,7 @@ void AmigaDisk_ns::loadSlide(BackgroundInfo& info, const char *name) {
return;
}
-GfxObj* AmigaDisk_ns::loadFrames(const char* name) {
+Frames* AmigaDisk_ns::loadFrames(const char* name) {
debugC(1, kDebugDisk, "AmigaDisk_ns::loadFrames '%s'", name);
Common::SeekableReadStream *s;
@@ -1273,7 +1273,7 @@ GfxObj* AmigaDisk_ns::loadFrames(const char* name) {
Cnv *cnv = makeCnv(*s);
delete s;
- return new GfxObj(0, cnv, name);
+ return cnv;
}
GfxObj* AmigaDisk_ns::loadHead(const char* name) {
diff --git a/engines/parallaction/exec.h b/engines/parallaction/exec.h
new file mode 100644
index 0000000000..887d6be526
--- /dev/null
+++ b/engines/parallaction/exec.h
@@ -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 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+
+#ifndef PARALLACTION_EXEC_H
+#define PARALLACTION_EXEC_H
+
+#include "common/util.h"
+#include "parallaction/objects.h"
+
+
+namespace Parallaction {
+
+typedef Common::Functor0<void> Opcode;
+typedef Common::Array<const Opcode*> OpcodeSet;
+
+#define DECLARE_UNQUALIFIED_COMMAND_OPCODE(op) void cmdOp_##op()
+#define DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(op) void instOp_##op()
+
+class Parallaction_ns;
+class Parallaction_br;
+
+class CommandExec {
+protected:
+ struct ParallactionStruct1 {
+ CommandPtr cmd;
+ ZonePtr z;
+ } _ctxt;
+
+ OpcodeSet _opcodes;
+
+public:
+ virtual void init() = 0;
+ virtual void run(CommandList &list, ZonePtr z = nullZonePtr);
+ CommandExec() {
+ }
+ virtual ~CommandExec() {
+ for (Common::Array<const Opcode*>::iterator i = _opcodes.begin(); i != _opcodes.end(); ++i)
+ delete *i;
+ _opcodes.clear();
+ }
+};
+
+class CommandExec_ns : public CommandExec {
+
+ Parallaction_ns *_vm;
+
+protected:
+ void updateGetZone(ZonePtr z, bool visible);
+
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(invalid);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(set);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(clear);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(start);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(speak);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(get);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(location);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(open);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(close);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(on);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(off);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(call);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(toggle);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(drop);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(quit);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(move);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(stop);
+
+public:
+ void init();
+
+ CommandExec_ns(Parallaction_ns* vm);
+ ~CommandExec_ns();
+};
+
+class CommandExec_br : public CommandExec_ns {
+
+protected:
+ Parallaction_br *_vm;
+
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(location);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(open);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(close);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(on);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(off);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(call);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(drop);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(move);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(start);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(stop);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(character);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(followme);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(onmouse);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(offmouse);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(add);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(leave);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(inc);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(dec);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(ifeq);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(iflt);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(ifgt);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(let);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(music);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(fix);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(unfix);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(zeta);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(scroll);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(swap);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(give);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(text);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(part);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(testsfx);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(ret);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(onsave);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(offsave);
+
+public:
+ void init();
+
+ CommandExec_br(Parallaction_br* vm);
+ ~CommandExec_br();
+};
+
+
+
+
+
+class ProgramExec {
+protected:
+ struct ParallactionStruct2 {
+ AnimationPtr anim;
+ ProgramPtr program;
+ InstructionList::iterator inst;
+ uint16 modCounter;
+ bool suspend;
+ } _ctxt;
+
+ OpcodeSet _opcodes;
+
+ uint16 _modCounter;
+
+public:
+ virtual void init() = 0;
+ virtual void runScripts(ProgramList::iterator first, ProgramList::iterator last);
+ ProgramExec() : _modCounter(0) {
+ }
+ virtual ~ProgramExec() {
+ for (Common::Array<const Opcode*>::iterator i = _opcodes.begin(); i != _opcodes.end(); ++i)
+ delete *i;
+ _opcodes.clear();
+ }
+};
+
+class ProgramExec_ns : public ProgramExec {
+
+ Parallaction_ns *_vm;
+
+protected:
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(invalid);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(on);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(off);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(loop);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(endloop);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(null);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(call);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(inc);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(set);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(put);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(wait);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(start);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(sound);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(move);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(endscript);
+
+public:
+ void init();
+
+ ProgramExec_ns(Parallaction_ns *vm);
+ ~ProgramExec_ns();
+};
+
+class ProgramExec_br : public ProgramExec_ns {
+
+ Parallaction_br *_vm;
+
+protected:
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(on);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(off);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(loop);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(inc);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(dec);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(set);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(put);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(wait);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(start);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(process);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(move);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(color);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(mask);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(print);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(text);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(mul);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(div);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(ifeq);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(iflt);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(ifgt);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(endif);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(stop);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(endscript);
+
+public:
+ void init();
+ ProgramExec_br(Parallaction_br *vm);
+ ~ProgramExec_br();
+};
+
+} // namespace Parallaction
+
+#endif
diff --git a/engines/parallaction/exec_br.cpp b/engines/parallaction/exec_br.cpp
index 348af2b731..edb832cffc 100644
--- a/engines/parallaction/exec_br.cpp
+++ b/engines/parallaction/exec_br.cpp
@@ -23,6 +23,7 @@
*
*/
+#include "parallaction/exec.h"
#include "parallaction/input.h"
#include "parallaction/parallaction.h"
@@ -64,12 +65,13 @@ namespace Parallaction {
#define SetOpcodeTable(x) table = &x;
-typedef Common::Functor0Mem<void, Parallaction_br> OpcodeV2;
-#define COMMAND_OPCODE(op) table->push_back(new OpcodeV2(this, &Parallaction_br::cmdOp_##op))
-#define DECLARE_COMMAND_OPCODE(op) void Parallaction_br::cmdOp_##op()
+typedef Common::Functor0Mem<void, CommandExec_br> OpcodeV1;
+#define COMMAND_OPCODE(op) table->push_back(new OpcodeV1(this, &CommandExec_br::cmdOp_##op))
+#define DECLARE_COMMAND_OPCODE(op) void CommandExec_br::cmdOp_##op()
-#define INSTRUCTION_OPCODE(op) table->push_back(new OpcodeV2(this, &Parallaction_br::instOp_##op))
-#define DECLARE_INSTRUCTION_OPCODE(op) void Parallaction_br::instOp_##op()
+typedef Common::Functor0Mem<void, ProgramExec_br> OpcodeV2;
+#define INSTRUCTION_OPCODE(op) table->push_back(new OpcodeV2(this, &ProgramExec_br::instOp_##op))
+#define DECLARE_INSTRUCTION_OPCODE(op) void ProgramExec_br::instOp_##op()
void Parallaction_br::setupSubtitles(char *s, char *s2, int y) {
debugC(5, kDebugExec, "setupSubtitles(%s, %s, %i)", s, s2, y);
@@ -100,8 +102,13 @@ void Parallaction_br::setupSubtitles(char *s, char *s2, int y) {
}
void Parallaction_br::clearSubtitles() {
- _gfx->hideLabel(_subtitle[0]);
- _gfx->hideLabel(_subtitle[1]);
+ if (_subtitle[0] != -1) {
+ _gfx->hideLabel(_subtitle[0]);
+ }
+
+ if (_subtitle[1] != -1) {
+ _gfx->hideLabel(_subtitle[1]);
+ }
}
@@ -109,7 +116,7 @@ DECLARE_COMMAND_OPCODE(location) {
warning("Parallaction_br::cmdOp_location command not yet implemented");
// TODO: handle startPos and startPos2
- scheduleLocationSwitch(_cmdRunCtxt.cmd->u._string);
+ _vm->scheduleLocationSwitch(_ctxt.cmd->u._string);
}
@@ -124,7 +131,7 @@ DECLARE_COMMAND_OPCODE(close) {
DECLARE_COMMAND_OPCODE(on) {
- CommandData *data = &_cmdRunCtxt.cmd->u;
+ CommandData *data = &_ctxt.cmd->u;
ZonePtr z = data->_zone;
if (z) {
@@ -132,28 +139,28 @@ DECLARE_COMMAND_OPCODE(on) {
z->_flags &= ~kFlagsRemove;
if ((z->_type & 0xFFFF) & kZoneGet) {
- _gfx->showGfxObj(z->u.get->gfxobj, true);
+ _vm->_gfx->showGfxObj(z->u.get->gfxobj, true);
}
}
}
DECLARE_COMMAND_OPCODE(off) {
- CommandData *data = &_cmdRunCtxt.cmd->u;
+ CommandData *data = &_ctxt.cmd->u;
ZonePtr z = data->_zone;
if (z) {
z->_flags |= kFlagsRemove;
if ((z->_type & 0xFFFF) & kZoneGet) {
- _gfx->showGfxObj(z->u.get->gfxobj, false);
+ _vm->_gfx->showGfxObj(z->u.get->gfxobj, false);
}
}
}
DECLARE_COMMAND_OPCODE(call) {
- callFunction(_cmdRunCtxt.cmd->u._callable, &_cmdRunCtxt.z);
+ _vm->callFunction(_ctxt.cmd->u._callable, &_ctxt.z);
}
@@ -167,17 +174,17 @@ DECLARE_COMMAND_OPCODE(move) {
}
DECLARE_COMMAND_OPCODE(start) {
- _cmdRunCtxt.cmd->u._zone->_flags |= kFlagsActing;
+ _ctxt.cmd->u._zone->_flags |= kFlagsActing;
}
DECLARE_COMMAND_OPCODE(stop) {
- _cmdRunCtxt.cmd->u._zone->_flags &= ~kFlagsActing;
+ _ctxt.cmd->u._zone->_flags &= ~kFlagsActing;
}
DECLARE_COMMAND_OPCODE(character) {
- debugC(9, kDebugExec, "Parallaction_br::cmdOp_character(%s)", _cmdRunCtxt.cmd->u._string);
- changeCharacter(_cmdRunCtxt.cmd->u._string);
+ debugC(9, kDebugExec, "Parallaction_br::cmdOp_character(%s)", _ctxt.cmd->u._string);
+ _vm->changeCharacter(_ctxt.cmd->u._string);
}
@@ -187,12 +194,12 @@ DECLARE_COMMAND_OPCODE(followme) {
DECLARE_COMMAND_OPCODE(onmouse) {
- _input->showCursor(true);
+ _vm->_input->showCursor(true);
}
DECLARE_COMMAND_OPCODE(offmouse) {
- _input->showCursor(false);
+ _vm->_input->showCursor(false);
}
@@ -207,42 +214,42 @@ DECLARE_COMMAND_OPCODE(leave) {
DECLARE_COMMAND_OPCODE(inc) {
- _counters[_cmdRunCtxt.cmd->u._lvalue] += _cmdRunCtxt.cmd->u._rvalue;
+ _vm->_counters[_ctxt.cmd->u._lvalue] += _ctxt.cmd->u._rvalue;
}
DECLARE_COMMAND_OPCODE(dec) {
- _counters[_cmdRunCtxt.cmd->u._lvalue] -= _cmdRunCtxt.cmd->u._rvalue;
+ _vm->_counters[_ctxt.cmd->u._lvalue] -= _ctxt.cmd->u._rvalue;
}
DECLARE_COMMAND_OPCODE(ifeq) {
- if (_counters[_cmdRunCtxt.cmd->u._lvalue] == _cmdRunCtxt.cmd->u._rvalue) {
- setLocationFlags(kFlagsTestTrue);
+ if (_vm->_counters[_ctxt.cmd->u._lvalue] == _ctxt.cmd->u._rvalue) {
+ _vm->setLocationFlags(kFlagsTestTrue);
} else {
- clearLocationFlags(kFlagsTestTrue);
+ _vm->clearLocationFlags(kFlagsTestTrue);
}
}
DECLARE_COMMAND_OPCODE(iflt) {
- if (_counters[_cmdRunCtxt.cmd->u._lvalue] < _cmdRunCtxt.cmd->u._rvalue) {
- setLocationFlags(kFlagsTestTrue);
+ if (_vm->_counters[_ctxt.cmd->u._lvalue] < _ctxt.cmd->u._rvalue) {
+ _vm->setLocationFlags(kFlagsTestTrue);
} else {
- clearLocationFlags(kFlagsTestTrue);
+ _vm->clearLocationFlags(kFlagsTestTrue);
}
}
DECLARE_COMMAND_OPCODE(ifgt) {
- if (_counters[_cmdRunCtxt.cmd->u._lvalue] > _cmdRunCtxt.cmd->u._rvalue) {
- setLocationFlags(kFlagsTestTrue);
+ if (_vm->_counters[_ctxt.cmd->u._lvalue] > _ctxt.cmd->u._rvalue) {
+ _vm->setLocationFlags(kFlagsTestTrue);
} else {
- clearLocationFlags(kFlagsTestTrue);
+ _vm->clearLocationFlags(kFlagsTestTrue);
}
}
DECLARE_COMMAND_OPCODE(let) {
- _counters[_cmdRunCtxt.cmd->u._lvalue] = _cmdRunCtxt.cmd->u._rvalue;
+ _vm->_counters[_ctxt.cmd->u._lvalue] = _ctxt.cmd->u._rvalue;
}
@@ -252,25 +259,25 @@ DECLARE_COMMAND_OPCODE(music) {
DECLARE_COMMAND_OPCODE(fix) {
- _cmdRunCtxt.cmd->u._zone->_flags |= kFlagsFixed;
+ _ctxt.cmd->u._zone->_flags |= kFlagsFixed;
}
DECLARE_COMMAND_OPCODE(unfix) {
- _cmdRunCtxt.cmd->u._zone->_flags &= ~kFlagsFixed;
+ _ctxt.cmd->u._zone->_flags &= ~kFlagsFixed;
}
DECLARE_COMMAND_OPCODE(zeta) {
- _location._zeta0 = _cmdRunCtxt.cmd->u._zeta0;
- _location._zeta1 = _cmdRunCtxt.cmd->u._zeta1;
- _location._zeta2 = _cmdRunCtxt.cmd->u._zeta2;
+ _vm->_location._zeta0 = _ctxt.cmd->u._zeta0;
+ _vm->_location._zeta1 = _ctxt.cmd->u._zeta1;
+ _vm->_location._zeta2 = _ctxt.cmd->u._zeta2;
}
DECLARE_COMMAND_OPCODE(scroll) {
warning("Parallaction_br::cmdOp_scroll not yet implemented");
- _gfx->setVar("scroll_x", _cmdRunCtxt.cmd->u._rvalue );
+ _vm->_gfx->setVar("scroll_x", _ctxt.cmd->u._rvalue );
}
@@ -285,8 +292,8 @@ DECLARE_COMMAND_OPCODE(give) {
DECLARE_COMMAND_OPCODE(text) {
- CommandData *data = &_cmdRunCtxt.cmd->u;
- setupSubtitles(data->_string, data->_string2, data->_zeta0);
+ CommandData *data = &_ctxt.cmd->u;
+ _vm->setupSubtitles(data->_string, data->_string2, data->_zeta0);
}
@@ -297,7 +304,7 @@ DECLARE_COMMAND_OPCODE(part) {
DECLARE_COMMAND_OPCODE(testsfx) {
warning("Parallaction_br::cmdOp_testsfx not completely implemented");
- clearLocationFlags(kFlagsTestTrue); // should test if sfx are enabled
+ _vm->clearLocationFlags(kFlagsTestTrue); // should test if sfx are enabled
}
@@ -319,7 +326,7 @@ DECLARE_COMMAND_OPCODE(offsave) {
DECLARE_INSTRUCTION_OPCODE(on) {
- InstructionPtr inst = *_instRunCtxt.inst;
+ InstructionPtr inst = *_ctxt.inst;
ZonePtr z = inst->_z;
if (z) {
@@ -327,28 +334,28 @@ DECLARE_INSTRUCTION_OPCODE(on) {
z->_flags &= ~kFlagsRemove;
if ((z->_type & 0xFFFF) & kZoneGet) {
- _gfx->showGfxObj(z->u.get->gfxobj, true);
+ _vm->_gfx->showGfxObj(z->u.get->gfxobj, true);
}
}
}
DECLARE_INSTRUCTION_OPCODE(off) {
- InstructionPtr inst = *_instRunCtxt.inst;
+ InstructionPtr inst = *_ctxt.inst;
ZonePtr z = inst->_z;
if (z) {
z->_flags |= kFlagsRemove;
if ((z->_type & 0xFFFF) & kZoneGet) {
- _gfx->showGfxObj(z->u.get->gfxobj, false);
+ _vm->_gfx->showGfxObj(z->u.get->gfxobj, false);
}
}
}
DECLARE_INSTRUCTION_OPCODE(set) {
- InstructionPtr inst = *_instRunCtxt.inst;
+ InstructionPtr inst = *_ctxt.inst;
int16 rvalue = inst->_opB.getRValue();
int16* lvalue = inst->_opA.getLValue();
@@ -359,21 +366,21 @@ DECLARE_INSTRUCTION_OPCODE(set) {
DECLARE_INSTRUCTION_OPCODE(loop) {
- InstructionPtr inst = *_instRunCtxt.inst;
+ InstructionPtr inst = *_ctxt.inst;
- _instRunCtxt.program->_loopCounter = inst->_opB.getRValue();
- _instRunCtxt.program->_loopStart = _instRunCtxt.inst;
+ _ctxt.program->_loopCounter = inst->_opB.getRValue();
+ _ctxt.program->_loopStart = _ctxt.inst;
}
DECLARE_INSTRUCTION_OPCODE(inc) {
- InstructionPtr inst = *_instRunCtxt.inst;
+ InstructionPtr inst = *_ctxt.inst;
int16 rvalue = inst->_opB.getRValue();
if (inst->_flags & kInstMod) { // mod
int16 _bx = (rvalue > 0 ? rvalue : -rvalue);
- if (_instRunCtxt.modCounter % _bx != 0) return;
+ if (_ctxt.modCounter % _bx != 0) return;
rvalue = (rvalue > 0 ? 1 : -1);
}
@@ -420,12 +427,12 @@ DECLARE_INSTRUCTION_OPCODE(wait) {
DECLARE_INSTRUCTION_OPCODE(start) {
- (*_instRunCtxt.inst)->_z->_flags |= kFlagsActing;
+ (*_ctxt.inst)->_z->_flags |= kFlagsActing;
}
DECLARE_INSTRUCTION_OPCODE(process) {
- _activeZone2 = (*_instRunCtxt.inst)->_z;
+ _vm->_activeZone2 = (*_ctxt.inst)->_z;
}
@@ -435,18 +442,18 @@ DECLARE_INSTRUCTION_OPCODE(move) {
DECLARE_INSTRUCTION_OPCODE(color) {
- InstructionPtr inst = *_instRunCtxt.inst;
+ InstructionPtr inst = *_ctxt.inst;
int16 entry = inst->_opB.getRValue();
- _gfx->_palette.setEntry(entry, inst->_colors[0], inst->_colors[1], inst->_colors[2]);
+ _vm->_gfx->_palette.setEntry(entry, inst->_colors[0], inst->_colors[1], inst->_colors[2]);
}
DECLARE_INSTRUCTION_OPCODE(mask) {
#if 0
- Instruction *inst = *_instRunCtxt.inst;
+ Instruction *inst = *_ctxt.inst;
_gfx->_bgLayers[0] = inst->_opA.getRValue();
_gfx->_bgLayers[1] = inst->_opB.getRValue();
_gfx->_bgLayers[2] = inst->_opC.getRValue();
@@ -459,8 +466,8 @@ DECLARE_INSTRUCTION_OPCODE(print) {
}
DECLARE_INSTRUCTION_OPCODE(text) {
- InstructionPtr inst = (*_instRunCtxt.inst);
- setupSubtitles(inst->_text, inst->_text2, inst->_y);
+ InstructionPtr inst = (*_ctxt.inst);
+ _vm->setupSubtitles(inst->_text, inst->_text2, inst->_y);
}
@@ -489,21 +496,20 @@ DECLARE_INSTRUCTION_OPCODE(stop) {
}
DECLARE_INSTRUCTION_OPCODE(endscript) {
- if ((_instRunCtxt.anim->_flags & kFlagsLooping) == 0) {
- _instRunCtxt.anim->_flags &= ~kFlagsActing;
- runCommands(_instRunCtxt.anim->_commands, _instRunCtxt.anim);
- _instRunCtxt.program->_status = kProgramDone;
+ if ((_ctxt.anim->_flags & kFlagsLooping) == 0) {
+ _ctxt.anim->_flags &= ~kFlagsActing;
+ _vm->_cmdExec->run(_ctxt.anim->_commands, _ctxt.anim);
+ _ctxt.program->_status = kProgramDone;
}
- _instRunCtxt.program->_ip = _instRunCtxt.program->_instructions.begin();
+ _ctxt.program->_ip = _ctxt.program->_instructions.begin();
- _instRunCtxt.suspend = true;
+ _ctxt.suspend = true;
}
-void Parallaction_br::initOpcodes() {
-
+void CommandExec_br::init() {
Common::Array<const Opcode*> *table = 0;
- SetOpcodeTable(_commandOpcodes);
+ SetOpcodeTable(_opcodes);
COMMAND_OPCODE(invalid);
COMMAND_OPCODE(set);
COMMAND_OPCODE(clear);
@@ -546,8 +552,21 @@ void Parallaction_br::initOpcodes() {
COMMAND_OPCODE(ret);
COMMAND_OPCODE(onsave);
COMMAND_OPCODE(offsave);
+}
+
+CommandExec_br::CommandExec_br(Parallaction_br* vm) : CommandExec_ns(vm), _vm(vm) {
+
+}
+
+CommandExec_br::~CommandExec_br() {
- SetOpcodeTable(_instructionOpcodes);
+}
+
+void ProgramExec_br::init() {
+
+ Common::Array<const Opcode*> *table = 0;
+
+ SetOpcodeTable(_opcodes);
INSTRUCTION_OPCODE(invalid);
INSTRUCTION_OPCODE(on);
INSTRUCTION_OPCODE(off);
@@ -582,6 +601,12 @@ void Parallaction_br::initOpcodes() {
INSTRUCTION_OPCODE(endscript);
}
+ProgramExec_br::ProgramExec_br(Parallaction_br *vm) : ProgramExec_ns(vm), _vm(vm) {
+}
+
+ProgramExec_br::~ProgramExec_br() {
+}
+
#if 0
void Parallaction_br::jobWaitRemoveLabelJob(void *parm, Job *job) {
diff --git a/engines/parallaction/exec_ns.cpp b/engines/parallaction/exec_ns.cpp
index bd2d54c0a0..9cde27a853 100644
--- a/engines/parallaction/exec_ns.cpp
+++ b/engines/parallaction/exec_ns.cpp
@@ -23,6 +23,7 @@
*
*/
+#include "parallaction/exec.h"
#include "parallaction/input.h"
#include "parallaction/parallaction.h"
#include "parallaction/sound.h"
@@ -52,18 +53,19 @@ namespace Parallaction {
#define SetOpcodeTable(x) table = &x;
-typedef Common::Functor0Mem<void, Parallaction_ns> OpcodeV2;
-#define COMMAND_OPCODE(op) table->push_back(new OpcodeV2(this, &Parallaction_ns::cmdOp_##op))
-#define DECLARE_COMMAND_OPCODE(op) void Parallaction_ns::cmdOp_##op()
+typedef Common::Functor0Mem<void, CommandExec_ns> OpcodeV1;
+#define COMMAND_OPCODE(op) table->push_back(new OpcodeV1(this, &CommandExec_ns::cmdOp_##op))
+#define DECLARE_COMMAND_OPCODE(op) void CommandExec_ns::cmdOp_##op()
-#define INSTRUCTION_OPCODE(op) table->push_back(new OpcodeV2(this, &Parallaction_ns::instOp_##op))
-#define DECLARE_INSTRUCTION_OPCODE(op) void Parallaction_ns::instOp_##op()
+typedef Common::Functor0Mem<void, ProgramExec_ns> OpcodeV2;
+#define INSTRUCTION_OPCODE(op) table->push_back(new OpcodeV2(this, &ProgramExec_ns::instOp_##op))
+#define DECLARE_INSTRUCTION_OPCODE(op) void ProgramExec_ns::instOp_##op()
DECLARE_INSTRUCTION_OPCODE(on) {
- InstructionPtr inst = *_instRunCtxt.inst;
+ InstructionPtr inst = *_ctxt.inst;
inst->_a->_flags |= kFlagsActive;
inst->_a->_flags &= ~kFlagsRemove;
@@ -71,31 +73,31 @@ DECLARE_INSTRUCTION_OPCODE(on) {
DECLARE_INSTRUCTION_OPCODE(off) {
- (*_instRunCtxt.inst)->_a->_flags |= kFlagsRemove;
+ (*_ctxt.inst)->_a->_flags |= kFlagsRemove;
}
DECLARE_INSTRUCTION_OPCODE(loop) {
- InstructionPtr inst = *_instRunCtxt.inst;
+ InstructionPtr inst = *_ctxt.inst;
- _instRunCtxt.program->_loopCounter = inst->_opB.getRValue();
- _instRunCtxt.program->_loopStart = _instRunCtxt.inst;
+ _ctxt.program->_loopCounter = inst->_opB.getRValue();
+ _ctxt.program->_loopStart = _ctxt.inst;
}
DECLARE_INSTRUCTION_OPCODE(endloop) {
- if (--_instRunCtxt.program->_loopCounter > 0) {
- _instRunCtxt.inst = _instRunCtxt.program->_loopStart;
+ if (--_ctxt.program->_loopCounter > 0) {
+ _ctxt.inst = _ctxt.program->_loopStart;
}
}
DECLARE_INSTRUCTION_OPCODE(inc) {
- InstructionPtr inst = *_instRunCtxt.inst;
+ InstructionPtr inst = *_ctxt.inst;
int16 _si = inst->_opB.getRValue();
if (inst->_flags & kInstMod) { // mod
int16 _bx = (_si > 0 ? _si : -_si);
- if (_instRunCtxt.modCounter % _bx != 0) return;
+ if (_modCounter % _bx != 0) return;
_si = (_si > 0 ? 1 : -1);
}
@@ -116,7 +118,7 @@ DECLARE_INSTRUCTION_OPCODE(inc) {
DECLARE_INSTRUCTION_OPCODE(set) {
- InstructionPtr inst = *_instRunCtxt.inst;
+ InstructionPtr inst = *_ctxt.inst;
int16 _si = inst->_opB.getRValue();
int16 *lvalue = inst->_opA.getLValue();
@@ -127,7 +129,7 @@ DECLARE_INSTRUCTION_OPCODE(set) {
DECLARE_INSTRUCTION_OPCODE(put) {
- InstructionPtr inst = *_instRunCtxt.inst;
+ InstructionPtr inst = *_ctxt.inst;
Graphics::Surface v18;
v18.w = inst->_a->width();
v18.h = inst->_a->height();
@@ -137,7 +139,7 @@ DECLARE_INSTRUCTION_OPCODE(put) {
int16 y = inst->_opB.getRValue();
bool mask = (inst->_flags & kInstMaskedPut) == kInstMaskedPut;
- _gfx->patchBackground(v18, x, y, mask);
+ _vm->_gfx->patchBackground(v18, x, y, mask);
}
DECLARE_INSTRUCTION_OPCODE(null) {
@@ -145,154 +147,165 @@ DECLARE_INSTRUCTION_OPCODE(null) {
}
DECLARE_INSTRUCTION_OPCODE(invalid) {
- error("Can't execute invalid opcode %i", (*_instRunCtxt.inst)->_index);
+ error("Can't execute invalid opcode %i", (*_ctxt.inst)->_index);
}
DECLARE_INSTRUCTION_OPCODE(call) {
- callFunction((*_instRunCtxt.inst)->_immediate, 0);
+ _vm->callFunction((*_ctxt.inst)->_immediate, 0);
}
DECLARE_INSTRUCTION_OPCODE(wait) {
if (_engineFlags & kEngineWalking)
- _instRunCtxt.suspend = true;
+ _ctxt.suspend = true;
}
DECLARE_INSTRUCTION_OPCODE(start) {
- (*_instRunCtxt.inst)->_a->_flags |= (kFlagsActing | kFlagsActive);
+ (*_ctxt.inst)->_a->_flags |= (kFlagsActing | kFlagsActive);
}
DECLARE_INSTRUCTION_OPCODE(sound) {
- _activeZone = (*_instRunCtxt.inst)->_z;
+ _vm->_activeZone = (*_ctxt.inst)->_z;
}
DECLARE_INSTRUCTION_OPCODE(move) {
- InstructionPtr inst = (*_instRunCtxt.inst);
+ InstructionPtr inst = (*_ctxt.inst);
int16 x = inst->_opA.getRValue();
int16 y = inst->_opB.getRValue();
- _char.scheduleWalk(x, y);
+ _vm->_char.scheduleWalk(x, y);
}
DECLARE_INSTRUCTION_OPCODE(endscript) {
- if ((_instRunCtxt.anim->_flags & kFlagsLooping) == 0) {
- _instRunCtxt.anim->_flags &= ~kFlagsActing;
- runCommands(_instRunCtxt.anim->_commands, _instRunCtxt.anim);
- _instRunCtxt.program->_status = kProgramDone;
+ if ((_ctxt.anim->_flags & kFlagsLooping) == 0) {
+ _ctxt.anim->_flags &= ~kFlagsActing;
+ _vm->_cmdExec->run(_ctxt.anim->_commands, _ctxt.anim);
+ _ctxt.program->_status = kProgramDone;
}
- _instRunCtxt.program->_ip = _instRunCtxt.program->_instructions.begin();
+ _ctxt.program->_ip = _ctxt.program->_instructions.begin();
- _instRunCtxt.suspend = true;
+ _ctxt.suspend = true;
}
DECLARE_COMMAND_OPCODE(invalid) {
- error("Can't execute invalid command '%i'", _cmdRunCtxt.cmd->_id);
+ error("Can't execute invalid command '%i'", _ctxt.cmd->_id);
}
DECLARE_COMMAND_OPCODE(set) {
- if (_cmdRunCtxt.cmd->u._flags & kFlagsGlobal) {
- _cmdRunCtxt.cmd->u._flags &= ~kFlagsGlobal;
- _commandFlags |= _cmdRunCtxt.cmd->u._flags;
+ if (_ctxt.cmd->u._flags & kFlagsGlobal) {
+ _ctxt.cmd->u._flags &= ~kFlagsGlobal;
+ _commandFlags |= _ctxt.cmd->u._flags;
} else {
- setLocationFlags(_cmdRunCtxt.cmd->u._flags);
+ _vm->setLocationFlags(_ctxt.cmd->u._flags);
}
}
DECLARE_COMMAND_OPCODE(clear) {
- if (_cmdRunCtxt.cmd->u._flags & kFlagsGlobal) {
- _cmdRunCtxt.cmd->u._flags &= ~kFlagsGlobal;
- _commandFlags &= ~_cmdRunCtxt.cmd->u._flags;
+ if (_ctxt.cmd->u._flags & kFlagsGlobal) {
+ _ctxt.cmd->u._flags &= ~kFlagsGlobal;
+ _commandFlags &= ~_ctxt.cmd->u._flags;
} else {
- clearLocationFlags(_cmdRunCtxt.cmd->u._flags);
+ _vm->clearLocationFlags(_ctxt.cmd->u._flags);
}
}
DECLARE_COMMAND_OPCODE(start) {
- _cmdRunCtxt.cmd->u._zone->_flags |= kFlagsActing;
+ _ctxt.cmd->u._zone->_flags |= kFlagsActing;
}
DECLARE_COMMAND_OPCODE(speak) {
- _activeZone = _cmdRunCtxt.cmd->u._zone;
+ if ((_ctxt.cmd->u._zone->_type & 0xFFFF) == kZoneSpeak) {
+ _vm->enterDialogueMode(_ctxt.cmd->u._zone);
+ } else {
+ _vm->_activeZone = _ctxt.cmd->u._zone;
+ }
}
DECLARE_COMMAND_OPCODE(get) {
- _cmdRunCtxt.cmd->u._zone->_flags &= ~kFlagsFixed;
- runZone(_cmdRunCtxt.cmd->u._zone);
+ _ctxt.cmd->u._zone->_flags &= ~kFlagsFixed;
+ _vm->runZone(_ctxt.cmd->u._zone);
}
DECLARE_COMMAND_OPCODE(location) {
- scheduleLocationSwitch(_cmdRunCtxt.cmd->u._string);
+ _vm->scheduleLocationSwitch(_ctxt.cmd->u._string);
}
DECLARE_COMMAND_OPCODE(open) {
- _cmdRunCtxt.cmd->u._zone->_flags &= ~kFlagsClosed;
- if (_cmdRunCtxt.cmd->u._zone->u.door->gfxobj) {
- updateDoor(_cmdRunCtxt.cmd->u._zone);
+ _ctxt.cmd->u._zone->_flags &= ~kFlagsClosed;
+ if (_ctxt.cmd->u._zone->u.door->gfxobj) {
+ _vm->updateDoor(_ctxt.cmd->u._zone);
}
}
DECLARE_COMMAND_OPCODE(close) {
- _cmdRunCtxt.cmd->u._zone->_flags |= kFlagsClosed;
- if (_cmdRunCtxt.cmd->u._zone->u.door->gfxobj) {
- updateDoor(_cmdRunCtxt.cmd->u._zone);
+ _ctxt.cmd->u._zone->_flags |= kFlagsClosed;
+ if (_ctxt.cmd->u._zone->u.door->gfxobj) {
+ _vm->updateDoor(_ctxt.cmd->u._zone);
}
}
+void CommandExec_ns::updateGetZone(ZonePtr z, bool visible) {
+ if (!z) {
+ return;
+ }
+
+ if ((z->_type & 0xFFFF) == kZoneGet) {
+ _vm->_gfx->showGfxObj(z->u.get->gfxobj, visible);
+ }
+}
DECLARE_COMMAND_OPCODE(on) {
- ZonePtr z = _cmdRunCtxt.cmd->u._zone;
- // WORKAROUND: the original DOS-based engine didn't check u->_zone before dereferencing
- // the pointer to get structure members, thus leading to crashes in systems with memory
- // protection.
- // As a side note, the overwritten address is the 5th entry in the DOS interrupt table
- // (print screen handler): this suggests that a system would hang when the print screen
- // key is pressed after playing Nippon Safes, provided that this code path is taken.
+ ZonePtr z = _ctxt.cmd->u._zone;
+
if (z) {
z->_flags &= ~kFlagsRemove;
z->_flags |= kFlagsActive;
- if ((z->_type & 0xFFFF) == kZoneGet) {
- _gfx->showGfxObj(z->u.get->gfxobj, true);
- }
+ updateGetZone(z, true);
}
}
DECLARE_COMMAND_OPCODE(off) {
- _cmdRunCtxt.cmd->u._zone->_flags |= kFlagsRemove;
+ ZonePtr z = _ctxt.cmd->u._zone;
+
+ if (z) {
+ _ctxt.cmd->u._zone->_flags |= kFlagsRemove;
+ updateGetZone(z, false);
+ }
}
DECLARE_COMMAND_OPCODE(call) {
- callFunction(_cmdRunCtxt.cmd->u._callable, &_cmdRunCtxt.z);
+ _vm->callFunction(_ctxt.cmd->u._callable, &_ctxt.z);
}
DECLARE_COMMAND_OPCODE(toggle) {
- if (_cmdRunCtxt.cmd->u._flags & kFlagsGlobal) {
- _cmdRunCtxt.cmd->u._flags &= ~kFlagsGlobal;
- _commandFlags ^= _cmdRunCtxt.cmd->u._flags;
+ if (_ctxt.cmd->u._flags & kFlagsGlobal) {
+ _ctxt.cmd->u._flags &= ~kFlagsGlobal;
+ _commandFlags ^= _ctxt.cmd->u._flags;
} else {
- toggleLocationFlags(_cmdRunCtxt.cmd->u._flags);
+ _vm->toggleLocationFlags(_ctxt.cmd->u._flags);
}
}
DECLARE_COMMAND_OPCODE(drop){
- dropItem( _cmdRunCtxt.cmd->u._object );
+ _vm->dropItem( _ctxt.cmd->u._object );
}
@@ -302,16 +315,17 @@ DECLARE_COMMAND_OPCODE(quit) {
DECLARE_COMMAND_OPCODE(move) {
- _char.scheduleWalk(_cmdRunCtxt.cmd->u._move.x, _cmdRunCtxt.cmd->u._move.y);
+ _vm->_char.scheduleWalk(_ctxt.cmd->u._move.x, _ctxt.cmd->u._move.y);
}
DECLARE_COMMAND_OPCODE(stop) {
- _cmdRunCtxt.cmd->u._zone->_flags &= ~kFlagsActing;
+ _ctxt.cmd->u._zone->_flags &= ~kFlagsActing;
}
void Parallaction_ns::drawAnimations() {
+ debugC(9, kDebugExec, "Parallaction_ns::drawAnimations()\n");
uint16 layer = 0;
@@ -352,20 +366,20 @@ void Parallaction_ns::drawAnimations() {
}
}
+ debugC(9, kDebugExec, "Parallaction_ns::drawAnimations done()\n");
+
return;
}
-void Parallaction_ns::runScripts() {
+void ProgramExec::runScripts(ProgramList::iterator first, ProgramList::iterator last) {
if (_engineFlags & kEnginePauseJobs) {
return;
}
debugC(9, kDebugExec, "runScripts");
- static uint16 modCounter = 0;
-
- for (ProgramList::iterator it = _location._programs.begin(); it != _location._programs.end(); it++) {
+ for (ProgramList::iterator it = first; it != last; it++) {
AnimationPtr a = (*it)->_anim;
@@ -382,17 +396,16 @@ void Parallaction_ns::runScripts() {
debugC(9, kDebugExec, "Animation: %s, instruction: %i", a->_name, (*inst)->_index); //_instructionNamesRes[(*inst)->_index - 1]);
- _instRunCtxt.inst = inst;
- _instRunCtxt.anim = AnimationPtr(a);
- _instRunCtxt.program = *it;
- _instRunCtxt.modCounter = modCounter;
- _instRunCtxt.suspend = false;
+ _ctxt.inst = inst;
+ _ctxt.anim = AnimationPtr(a);
+ _ctxt.program = *it;
+ _ctxt.suspend = false;
- (*_instructionOpcodes[(*inst)->_index])();
+ (*_opcodes[(*inst)->_index])();
- inst = _instRunCtxt.inst; // handles endloop correctly
+ inst = _ctxt.inst; // handles endloop correctly
- if (_instRunCtxt.suspend)
+ if (_ctxt.suspend)
goto label1;
inst++;
@@ -405,44 +418,49 @@ label1:
a->_z = a->_top + a->height();
}
- _char._ani->_z = _char._ani->height() + _char._ani->_top;
- if (_char._ani->gfxobj) {
- _char._ani->gfxobj->z = _char._ani->_z;
- }
- modCounter++;
+ _modCounter++;
return;
}
-
-void Parallaction::runCommands(CommandList& list, ZonePtr z) {
- if (list.size() == 0)
+void CommandExec::run(CommandList& list, ZonePtr z) {
+ if (list.size() == 0) {
+ debugC(3, kDebugExec, "runCommands: nothing to do");
return;
+ }
- debugC(3, kDebugExec, "runCommands");
+ debugC(3, kDebugExec, "runCommands starting");
+
+ uint32 useFlags = 0;
+ bool useLocalFlags;
CommandList::iterator it = list.begin();
for ( ; it != list.end(); it++) {
-
- CommandPtr cmd = *it;
- uint32 v8 = getLocationFlags();
-
if (_engineFlags & kEngineQuit)
break;
+ CommandPtr cmd = *it;
+
if (cmd->_flagsOn & kFlagsGlobal) {
- v8 = _commandFlags | kFlagsGlobal;
+ useFlags = _commandFlags | kFlagsGlobal;
+ useLocalFlags = false;
+ } else {
+ useFlags = _vm->getLocationFlags();
+ useLocalFlags = true;
}
- if ((cmd->_flagsOn & v8) != cmd->_flagsOn) continue;
- if ((cmd->_flagsOff & ~v8) != cmd->_flagsOff) continue;
+ bool onMatch = (cmd->_flagsOn & useFlags) == cmd->_flagsOn;
+ bool offMatch = (cmd->_flagsOff & ~useFlags) == cmd->_flagsOff;
+
+ debugC(3, kDebugExec, "runCommands[%i] (on: %x, off: %x), (%s = %x)", cmd->_id, cmd->_flagsOn, cmd->_flagsOff,
+ useLocalFlags ? "LOCALFLAGS" : "GLOBALFLAGS", useFlags);
-// debugC(3, kDebugExec, "runCommands[%i]: %s (on: %x, off: %x)", cmd->_id, _commandsNamesRes[cmd->_id-1], cmd->_flagsOn, cmd->_flagsOff);
+ if (!onMatch || !offMatch) continue;
- _cmdRunCtxt.z = z;
- _cmdRunCtxt.cmd = cmd;
+ _ctxt.z = z;
+ _ctxt.cmd = cmd;
- (*_commandOpcodes[cmd->_id])();
+ (*_opcodes[cmd->_id])();
}
debugC(3, kDebugExec, "runCommands completed");
@@ -451,6 +469,13 @@ void Parallaction::runCommands(CommandList& list, ZonePtr z) {
}
+CommandExec_ns::CommandExec_ns(Parallaction_ns* vm) : _vm(vm) {
+
+}
+
+CommandExec_ns::~CommandExec_ns() {
+
+}
//
// ZONE TYPE: EXAMINE
@@ -469,7 +494,7 @@ void Parallaction::displayComment(ExamineData *data) {
}
_gfx->setHalfbriteMode(true);
- _gfx->setSingleBalloon(data->_description, 0, 90, 0, 0);
+ _balloonMan->setSingleBalloon(data->_description, 0, 90, 0, 0);
Common::Rect r;
data->_cnv->getRect(0, r);
id = _gfx->setItem(data->_cnv, 140, (_screenHeight - r.height())/2);
@@ -477,7 +502,7 @@ void Parallaction::displayComment(ExamineData *data) {
id = _gfx->setItem(_char._head, 100, 152);
_gfx->setItemFrame(id, 0);
} else {
- _gfx->setSingleBalloon(data->_description, 140, 10, 0, 0);
+ _balloonMan->setSingleBalloon(data->_description, 140, 10, 0, 0);
id = _gfx->setItem(_char._talk, 190, 80);
_gfx->setItemFrame(id, 0);
}
@@ -518,16 +543,13 @@ uint16 Parallaction::runZone(ZonePtr z) {
break;
case kZoneSpeak:
- runDialogue(z->u.speak);
- if (_engineFlags & kEngineQuit)
- return 0;
- break;
-
+ enterDialogueMode(z);
+ return 0;
}
debugC(3, kDebugExec, "runZone completed");
- runCommands(z->_commands, z);
+ _cmdExec->run(z->_commands, z);
return 0;
}
@@ -654,11 +676,34 @@ ZonePtr Parallaction::hitZone(uint32 type, uint16 x, uint16 y) {
}
-void Parallaction_ns::initOpcodes() {
+void CommandExec_ns::init() {
+ Common::Array<const Opcode*> *table = 0;
+
+ SetOpcodeTable(_opcodes);
+ COMMAND_OPCODE(invalid);
+ COMMAND_OPCODE(set);
+ COMMAND_OPCODE(clear);
+ COMMAND_OPCODE(start);
+ COMMAND_OPCODE(speak);
+ COMMAND_OPCODE(get);
+ COMMAND_OPCODE(location);
+ COMMAND_OPCODE(open);
+ COMMAND_OPCODE(close);
+ COMMAND_OPCODE(on);
+ COMMAND_OPCODE(off);
+ COMMAND_OPCODE(call);
+ COMMAND_OPCODE(toggle);
+ COMMAND_OPCODE(drop);
+ COMMAND_OPCODE(quit);
+ COMMAND_OPCODE(move);
+ COMMAND_OPCODE(stop);
+}
+
+void ProgramExec_ns::init() {
Common::Array<const Opcode*> *table = 0;
- SetOpcodeTable(_instructionOpcodes);
+ SetOpcodeTable(_opcodes);
INSTRUCTION_OPCODE(invalid);
INSTRUCTION_OPCODE(on);
INSTRUCTION_OPCODE(off);
@@ -680,25 +725,12 @@ void Parallaction_ns::initOpcodes() {
INSTRUCTION_OPCODE(move);
INSTRUCTION_OPCODE(endscript);
- SetOpcodeTable(_commandOpcodes);
- COMMAND_OPCODE(invalid);
- COMMAND_OPCODE(set);
- COMMAND_OPCODE(clear);
- COMMAND_OPCODE(start);
- COMMAND_OPCODE(speak);
- COMMAND_OPCODE(get);
- COMMAND_OPCODE(location);
- COMMAND_OPCODE(open);
- COMMAND_OPCODE(close);
- COMMAND_OPCODE(on);
- COMMAND_OPCODE(off);
- COMMAND_OPCODE(call);
- COMMAND_OPCODE(toggle);
- COMMAND_OPCODE(drop);
- COMMAND_OPCODE(quit);
- COMMAND_OPCODE(move);
- COMMAND_OPCODE(stop);
}
+ProgramExec_ns::ProgramExec_ns(Parallaction_ns *vm) : _vm(vm) {
+}
+
+ProgramExec_ns::~ProgramExec_ns() {
+}
} // namespace Parallaction
diff --git a/engines/parallaction/gfxbase.cpp b/engines/parallaction/gfxbase.cpp
index 383f5d549c..e8250ac8fd 100644
--- a/engines/parallaction/gfxbase.cpp
+++ b/engines/parallaction/gfxbase.cpp
@@ -32,7 +32,7 @@
namespace Parallaction {
-GfxObj::GfxObj(uint objType, Frames *frames, const char* name) : type(objType), _frames(frames), x(0), y(0), z(0), frame(0), layer(3), _flags(0), _keep(true) {
+GfxObj::GfxObj(uint objType, Frames *frames, const char* name) : type(objType), _frames(frames), x(0), y(0), z(0), frame(0), layer(3), _flags(kGfxObjNormal), _keep(true) {
if (name) {
_name = strdup(name);
} else {
@@ -86,12 +86,14 @@ void GfxObj::clearFlags(uint32 flags) {
}
GfxObj* Gfx::loadAnim(const char *name) {
- GfxObj *obj = _disk->loadFrames(name);
+ Frames* frames = _disk->loadFrames(name);
+ assert(frames);
+
+ GfxObj *obj = new GfxObj(kGfxObjTypeAnim, frames, name);
assert(obj);
// animation Z is not set here, but controlled by game scripts and user interaction.
// it is always >=0 and <screen height
- obj->type = kGfxObjTypeAnim;
obj->transparentKey = 0;
_gfxobjList.push_back(obj);
return obj;
@@ -110,34 +112,43 @@ GfxObj* Gfx::loadGet(const char *name) {
}
GfxObj* Gfx::loadDoor(const char *name) {
- GfxObj *obj = _disk->loadFrames(name);
+ Frames *frames = _disk->loadFrames(name);
+ assert(frames);
+
+ GfxObj *obj = new GfxObj(kGfxObjTypeDoor, frames, name);
assert(obj);
obj->z = kGfxObjDoorZ; // this preset Z value ensures that doors are drawn first
- obj->type = kGfxObjTypeDoor;
obj->transparentKey = 0;
_gfxobjList.push_back(obj);
return obj;
}
-void Gfx::clearGfxObjects() {
- _gfxobjList.clear();
+void Gfx::clearGfxObjects(uint filter) {
+
+ GfxObjList::iterator b = _gfxobjList.begin();
+ GfxObjList::iterator e = _gfxobjList.end();
+
+ for ( ; b != e; ) {
+ if (((*b)->_flags & filter) != 0) {
+ b = _gfxobjList.erase(b);
+ } else {
+ b++;
+ }
+ }
+
}
void Gfx::showGfxObj(GfxObj* obj, bool visible) {
-// if (!obj || obj->isVisible() == visible) {
-// return;
-// }
-
- assert(obj);
+ if (!obj) {
+ return;
+ }
if (visible) {
obj->setFlags(kGfxObjVisible);
} else {
obj->clearFlags(kGfxObjVisible);
-// _gfxobjList.remove(obj);
}
-
}
@@ -181,8 +192,6 @@ void Gfx::drawGfxObjects(Graphics::Surface &surf) {
sortAnimations();
// TODO: some zones don't appear because of wrong masking (3 or 0?)
- // TODO: Dr.Ki is not visible inside the club
-
GfxObjList::iterator b = _gfxobjList.begin();
GfxObjList::iterator e = _gfxobjList.end();
@@ -258,9 +267,6 @@ void Gfx::drawWrappedText(Font *font, Graphics::Surface* surf, char *text, byte
}
-// this is the maximum size of an unpacked frame in BRA
-byte _unpackedBitmap[640*401];
-
#if 0
void Gfx::unpackBlt(const Common::Rect& r, byte *data, uint size, Graphics::Surface *surf, uint16 z, byte transparentColor) {
diff --git a/engines/parallaction/graphics.cpp b/engines/parallaction/graphics.cpp
index 838827b19f..9b9ea8605a 100644
--- a/engines/parallaction/graphics.cpp
+++ b/engines/parallaction/graphics.cpp
@@ -33,6 +33,11 @@
namespace Parallaction {
+// this is the size of the receiving buffer for unpacked frames,
+// since BRA uses some insanely big animations.
+#define MAXIMUM_UNPACKED_BITMAP_SIZE 640*401
+
+
void Gfx::registerVar(const Common::String &name, int32 initialValue) {
if (_vars.contains(name)) {
warning("Variable '%s' already registered, ignoring initial value.\n", name.c_str());
@@ -64,10 +69,6 @@ int32 Gfx::getVar(const Common::String &name) {
#define LABEL_TRANSPARENT_COLOR 0xFF
-#define BALLOON_TRANSPARENT_COLOR 2
-
-
-int16 Gfx::_dialogueBalloonX[5] = { 80, 120, 150, 150, 150 };
void halfbritePixel(int x, int y, int color, void *data) {
byte *buffer = (byte*)data;
@@ -238,37 +239,6 @@ void Palette::rotate(uint first, uint last, bool forward) {
}
-#define BALLOON_TAIL_WIDTH 12
-#define BALLOON_TAIL_HEIGHT 10
-
-
-byte _resBalloonTail[2][BALLOON_TAIL_WIDTH*BALLOON_TAIL_HEIGHT] = {
- {
- 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02,
- 0x02, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02,
- 0x02, 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02,
- 0x02, 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02,
- 0x02, 0x02, 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02,
- 0x02, 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02,
- 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02,
- 0x02, 0x00, 0x01, 0x01, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
- 0x00, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
- 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
- },
- {
- 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02,
- 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x02, 0x02, 0x02,
- 0x02, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02,
- 0x02, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02,
- 0x02, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
- 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02,
- 0x02, 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02,
- 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02,
- 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x01, 0x01, 0x00, 0x02, 0x02,
- 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x02, 0x02
- }
-};
-
void Gfx::setPalette(Palette pal) {
byte sysPal[256*4];
@@ -362,15 +332,13 @@ void Gfx::drawItems() {
}
void Gfx::drawBalloons() {
- if (_numBalloons == 0) {
+ if (_balloons.size() == 0) {
return;
}
Graphics::Surface *surf = g_system->lockScreen();
- for (uint i = 0; i < _numBalloons; i++) {
- Common::Rect r(_balloons[i].surface.w, _balloons[i].surface.h);
- r.moveTo(_balloons[i].x, _balloons[i].y);
- blt(r, (byte*)_balloons[i].surface.getBasePtr(0, 0), surf, LAYER_FOREGROUND, BALLOON_TRANSPARENT_COLOR);
+ for (uint i = 0; i < _balloons.size(); i++) {
+ drawGfxObject(_balloons[i], *surf, false);
}
g_system->unlockScreen();
}
@@ -686,6 +654,7 @@ void Gfx::freeLabels() {
delete _labels[i];
}
_labels.clear();
+ _floatingLabel = NO_FLOATING_LABEL;
}
void Gfx::drawLabels() {
@@ -779,7 +748,6 @@ Gfx::Gfx(Parallaction* vm) :
setPalette(_palette);
- _numBalloons = 0;
_numItems = 0;
_floatingLabel = NO_FLOATING_LABEL;
@@ -789,6 +757,9 @@ Gfx::Gfx(Parallaction* vm) :
_halfbrite = false;
_hbCircleRadius = 0;
+ _unpackedBitmap = new byte[MAXIMUM_UNPACKED_BITMAP_SIZE];
+ assert(_unpackedBitmap);
+
registerVar("background_mode", 1);
_varBackgroundMode = 1;
@@ -804,6 +775,9 @@ Gfx::Gfx(Parallaction* vm) :
Gfx::~Gfx() {
freeBackground();
+ freeLabels();
+
+ delete []_unpackedBitmap;
return;
}
@@ -830,138 +804,31 @@ void Gfx::setItemFrame(uint item, uint16 f) {
_items[item].data->setFlags(kGfxObjVisible);
}
-Gfx::Balloon* Gfx::getBalloon(uint id) {
- assert(id < _numBalloons);
- return &_balloons[id];
-}
-
-int Gfx::createBalloon(int16 w, int16 h, int16 winding, uint16 borderThickness) {
- assert(_numBalloons < 5);
-
- int id = _numBalloons;
-
- Gfx::Balloon *balloon = &_balloons[id];
-
- int16 real_h = (winding == -1) ? h : h + 9;
- balloon->surface.create(w, real_h, 1);
- balloon->surface.fillRect(Common::Rect(w, real_h), BALLOON_TRANSPARENT_COLOR);
- Common::Rect r(w, h);
- balloon->surface.fillRect(r, 0);
- balloon->outerBox = r;
+GfxObj* Gfx::registerBalloon(Frames *frames, const char *text) {
- r.grow(-borderThickness);
- balloon->surface.fillRect(r, 1);
- balloon->innerBox = r;
-
- if (winding != -1) {
- // draws tail
- // TODO: this bitmap tail should only be used for Dos games. Amiga should use a polygon fill.
- winding = (winding == 0 ? 1 : 0);
- Common::Rect s(BALLOON_TAIL_WIDTH, BALLOON_TAIL_HEIGHT);
- s.moveTo(r.width()/2 - 5, r.bottom - 1);
- blt(s, _resBalloonTail[winding], &balloon->surface, LAYER_FOREGROUND, BALLOON_TRANSPARENT_COLOR);
- }
-
- _numBalloons++;
-
- return id;
-}
-
-int Gfx::setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, byte textColor) {
-
- int16 w, h;
-
- getStringExtent(_vm->_dialogueFont, text, MAX_BALLOON_WIDTH, &w, &h);
-
- int id = createBalloon(w+5, h, winding, 1);
- Gfx::Balloon *balloon = &_balloons[id];
-
- drawWrappedText(_vm->_dialogueFont, &balloon->surface, text, textColor, MAX_BALLOON_WIDTH);
-
- balloon->x = x;
- balloon->y = y;
-
- return id;
-}
+ GfxObj *obj = new GfxObj(kGfxObjTypeBalloon, frames, text);
-int Gfx::setDialogueBalloon(char *text, uint16 winding, byte textColor) {
-
- int16 w, h;
-
- getStringExtent(_vm->_dialogueFont, text, MAX_BALLOON_WIDTH, &w, &h);
-
- int id = createBalloon(w+5, h, winding, 1);
- Gfx::Balloon *balloon = &_balloons[id];
-
- drawWrappedText(_vm->_dialogueFont, &balloon->surface, text, textColor, MAX_BALLOON_WIDTH);
-
- balloon->x = _dialogueBalloonX[id];
- balloon->y = 10;
-
- if (id > 0) {
- balloon->y += _balloons[id - 1].y + _balloons[id - 1].outerBox.height();
- }
-
-
- return id;
-}
-
-void Gfx::setBalloonText(uint id, char *text, byte textColor) {
- Gfx::Balloon *balloon = getBalloon(id);
- balloon->surface.fillRect(balloon->innerBox, 1);
- drawWrappedText(_vm->_dialogueFont, &balloon->surface, text, textColor, MAX_BALLOON_WIDTH);
-}
-
-
-int Gfx::setLocationBalloon(char *text, bool endGame) {
-
- int16 w, h;
-
- getStringExtent(_vm->_dialogueFont, text, MAX_BALLOON_WIDTH, &w, &h);
-
- int id = createBalloon(w+(endGame ? 5 : 10), h+5, -1, BALLOON_TRANSPARENT_COLOR);
- Gfx::Balloon *balloon = &_balloons[id];
- drawWrappedText(_vm->_dialogueFont, &balloon->surface, text, 0, MAX_BALLOON_WIDTH);
-
- balloon->x = 5;
- balloon->y = 5;
-
- return id;
-}
-
-int Gfx::hitTestDialogueBalloon(int x, int y) {
-
- Common::Point p;
-
- for (uint i = 0; i < _numBalloons; i++) {
- p.x = x - _balloons[i].x;
- p.y = y - _balloons[i].y;
+ obj->layer = LAYER_FOREGROUND;
+ obj->frame = 0;
+ obj->setFlags(kGfxObjVisible);
- if (_balloons[i].innerBox.contains(p))
- return i;
- }
+ _balloons.push_back(obj);
- return -1;
+ return obj;
}
-
-void Gfx::freeBalloons() {
- for (uint i = 0; i < _numBalloons; i++) {
- _balloons[i].surface.free();
+void Gfx::destroyBalloons() {
+ for (uint i = 0; i < _balloons.size(); i++) {
+ delete _balloons[i];
}
- _numBalloons = 0;
+ _balloons.clear();
}
void Gfx::freeItems() {
_numItems = 0;
}
-void Gfx::hideDialogueStuff() {
- freeItems();
- freeBalloons();
-}
-
void Gfx::freeBackground() {
_backgroundInfo.free();
}
diff --git a/engines/parallaction/graphics.h b/engines/parallaction/graphics.h
index df4cab4caf..a7242ba6f4 100644
--- a/engines/parallaction/graphics.h
+++ b/engines/parallaction/graphics.h
@@ -340,11 +340,15 @@ class Disk;
enum {
kGfxObjVisible = 1,
+ kGfxObjNormal = 2,
+ kGfxObjCharacter = 4,
kGfxObjTypeDoor = 0,
kGfxObjTypeGet = 1,
kGfxObjTypeAnim = 2,
- kGfxObjTypeLabel = 3
+ kGfxObjTypeLabel = 3,
+ kGfxObjTypeBalloon = 4,
+ kGfxObjTypeCharacter = 8
};
enum {
@@ -355,7 +359,6 @@ enum {
class GfxObj {
char *_name;
Frames *_frames;
- uint32 _flags;
bool _keep;
@@ -364,6 +367,7 @@ public:
int32 z;
+ uint32 _flags;
uint type;
uint frame;
@@ -449,6 +453,20 @@ enum {
kBackgroundSlide = 2
};
+
+class BalloonManager {
+public:
+ virtual ~BalloonManager() { }
+
+ virtual void freeBalloons() = 0;
+ virtual int setLocationBalloon(char *text, bool endGame) = 0;
+ virtual int setDialogueBalloon(char *text, uint16 winding, byte textColor) = 0;
+ virtual int setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, byte textColor) = 0;
+ virtual void setBalloonText(uint id, char *text, byte textColor) = 0;
+ virtual int hitTestDialogueBalloon(int x, int y) = 0;
+};
+
+
typedef Common::HashMap<Common::String, int32, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> VarMap;
class Gfx {
@@ -463,7 +481,7 @@ public:
GfxObj* loadDoor(const char *name);
void drawGfxObjects(Graphics::Surface &surf);
void showGfxObj(GfxObj* obj, bool visible);
- void clearGfxObjects();
+ void clearGfxObjects(uint filter);
void sortAnimations();
@@ -478,12 +496,9 @@ public:
void freeLabels();
// dialogue balloons
- int setLocationBalloon(char *text, bool endGame);
- int setDialogueBalloon(char *text, uint16 winding, byte textColor);
- int setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, byte textColor);
- void setBalloonText(uint id, char *text, byte textColor);
- int hitTestDialogueBalloon(int x, int y);
void getStringExtent(Font *font, char *text, uint16 maxwidth, int16* width, int16* height);
+ GfxObj* registerBalloon(Frames *frames, const char *text);
+ void destroyBalloons();
// other items
int setItem(GfxObj* obj, uint16 x, uint16 y, byte transparentColor = 0);
@@ -532,6 +547,8 @@ public:
uint _screenX; // scrolling position
uint _screenY;
+ byte *_unpackedBitmap;
+
protected:
Parallaction* _vm;
bool _halfbrite;
@@ -549,18 +566,6 @@ protected:
int32 getRenderMode(const char *type);
public:
- static int16 _dialogueBalloonX[5];
-
- struct Balloon {
- uint16 x;
- uint16 y;
- Common::Rect outerBox;
- Common::Rect innerBox;
- uint16 winding;
- Graphics::Surface surface;
- } _balloons[5];
-
- uint _numBalloons;
struct Item {
GfxObj *data;
@@ -573,6 +578,7 @@ public:
typedef Common::Array<GfxObj*> GfxObjArray;
GfxObjArray _labels;
+ GfxObjArray _balloons;
uint _floatingLabel;
@@ -584,9 +590,6 @@ public:
void copyRect(const Common::Rect &r, Graphics::Surface &src, Graphics::Surface &dst);
- int createBalloon(int16 w, int16 h, int16 winding, uint16 borderThickness);
- Balloon *getBalloon(uint id);
-
// low level text and patches
void drawText(Font *font, Graphics::Surface* surf, uint16 x, uint16 y, const char *text, byte color);
void drawWrappedText(Font *font, Graphics::Surface* surf, char *text, byte color, int16 wrapwidth);
diff --git a/engines/parallaction/gui_br.cpp b/engines/parallaction/gui_br.cpp
index 5551108693..0be070e345 100644
--- a/engines/parallaction/gui_br.cpp
+++ b/engines/parallaction/gui_br.cpp
@@ -195,7 +195,7 @@ int Parallaction_br::guiShowMenu() {
}
_system->showMouse(false);
- _gfx->hideDialogueStuff();
+ hideDialogueStuff();
for (i = 0; i < availItems; i++) {
delete _lines[i];
diff --git a/engines/parallaction/input.cpp b/engines/parallaction/input.cpp
index e758bbd41c..9601ae3b36 100644
--- a/engines/parallaction/input.cpp
+++ b/engines/parallaction/input.cpp
@@ -42,12 +42,14 @@ uint16 Input::readInput() {
uint16 KeyDown = 0;
_mouseButtons = kMouseNone;
+ _lastKeyDownAscii = -1;
Common::EventManager *eventMan = _vm->_system->getEventManager();
while (eventMan->pollEvent(e)) {
switch (e.type) {
case Common::EVENT_KEYDOWN:
+ _lastKeyDownAscii = e.kbd.ascii;
if (e.kbd.flags == Common::KBD_CTRL && e.kbd.keycode == 'd')
_vm->_debugger->attach();
if (_vm->getFeatures() & GF_DEMO) break;
@@ -97,6 +99,11 @@ uint16 Input::readInput() {
}
+bool Input::getLastKeyDown(uint16 &ascii) {
+ ascii = _lastKeyDownAscii;
+ return (_lastKeyDownAscii != -1);
+}
+
// FIXME: see comment for readInput()
void Input::waitForButtonEvent(uint32 buttonEventMask, int32 timeout) {
@@ -174,7 +181,7 @@ void Input::updateGameInput() {
void Input::updateCommentInput() {
waitUntilLeftClick();
- _vm->_gfx->hideDialogueStuff();
+ _vm->hideDialogueStuff();
_vm->_gfx->setHalfbriteMode(false);
_inputMode = kInputModeGame;
@@ -192,11 +199,38 @@ InputData* Input::updateInput() {
case kInputModeGame:
updateGameInput();
break;
+
+ case kInputModeDialogue:
+ readInput();
+ break;
}
return &_inputData;
}
+void Input::trackMouse(ZonePtr z) {
+ if ((z != _hoverZone) && (_hoverZone)) {
+ stopHovering();
+ return;
+ }
+
+ if (!z) {
+ return;
+ }
+
+ if ((!_hoverZone) && ((z->_flags & kFlagsNoName) == 0)) {
+ _hoverZone = z;
+ _vm->_gfx->showFloatingLabel(_hoverZone->_label);
+ return;
+ }
+}
+
+void Input::stopHovering() {
+ _hoverZone = nullZonePtr;
+ _vm->_gfx->hideFloatingLabel();
+}
+
+
bool Input::translateGameInput() {
if ((_engineFlags & kEnginePauseJobs) || (_engineFlags & kEngineInventory)) {
@@ -231,23 +265,10 @@ bool Input::translateGameInput() {
return true;
}
- if ((z != _hoverZone) && (_hoverZone)) {
- _hoverZone = nullZonePtr;
- _inputData._event = kEvExitZone;
- return true;
- }
-
- if (!z) {
- _inputData._event = kEvNone;
- return true;
- }
-
- if ((!_hoverZone) && ((z->_flags & kFlagsNoName) == 0)) {
- _hoverZone = z;
- _inputData._event = kEvEnterZone;
- _inputData._label = z->_label;
- return true;
- }
+ trackMouse(z);
+ if (!z) {
+ return true;
+ }
if ((_mouseButtons == kMouseLeftUp) && ((_activeItem._id != 0) || ((z->_type & 0xFFFF) == kZoneCommand))) {
@@ -302,7 +323,7 @@ bool Input::translateInventoryInput() {
_vm->dropItem(z->u.merge->_obj1);
_vm->dropItem(z->u.merge->_obj2);
_vm->addInventoryItem(z->u.merge->_obj3);
- _vm->runCommands(z->_commands);
+ _vm->_cmdExec->run(z->_commands);
}
return true;
diff --git a/engines/parallaction/input.h b/engines/parallaction/input.h
index e06fe96705..f260352dba 100644
--- a/engines/parallaction/input.h
+++ b/engines/parallaction/input.h
@@ -66,6 +66,7 @@ class Input {
Common::Point _mousePos;
uint16 _mouseButtons;
+ int32 _lastKeyDownAscii;
bool _mouseHidden;
ZonePtr _hoverZone;
@@ -73,7 +74,8 @@ class Input {
public:
enum {
kInputModeGame = 0,
- kInputModeComment = 1
+ kInputModeComment = 1,
+ kInputModeDialogue = 2
};
@@ -99,14 +101,13 @@ public:
uint16 readInput();
InputData* updateInput();
+ void trackMouse(ZonePtr z);
void waitUntilLeftClick();
void waitForButtonEvent(uint32 buttonEventMask, int32 timeout = -1);
uint32 getLastButtonEvent() { return _mouseButtons; }
+ bool getLastKeyDown(uint16 &ascii);
- void stopHovering() {
- _hoverZone = nullZonePtr;
- }
-
+ void stopHovering();
};
} // namespace Parallaction
diff --git a/engines/parallaction/module.mk b/engines/parallaction/module.mk
index 2478b4b2e1..fb867f5285 100644
--- a/engines/parallaction/module.mk
+++ b/engines/parallaction/module.mk
@@ -1,6 +1,7 @@
MODULE := engines/parallaction
MODULE_OBJS := \
+ balloons.o \
callables_br.o \
callables_ns.o \
debug.o \
diff --git a/engines/parallaction/objects.cpp b/engines/parallaction/objects.cpp
index 54afabc318..66025cf0f7 100644
--- a/engines/parallaction/objects.cpp
+++ b/engines/parallaction/objects.cpp
@@ -54,6 +54,7 @@ Animation::Animation() {
Animation::~Animation() {
free(_scriptName);
+ gfxobj->release();
}
uint16 Animation::width() const {
@@ -182,6 +183,8 @@ Zone::~Zone() {
break;
}
+
+ free(_linkedName);
}
void Zone::getRect(Common::Rect& r) const {
diff --git a/engines/parallaction/parallaction.cpp b/engines/parallaction/parallaction.cpp
index 5f5cfdb820..cd852f7c84 100644
--- a/engines/parallaction/parallaction.cpp
+++ b/engines/parallaction/parallaction.cpp
@@ -84,13 +84,15 @@ Parallaction::Parallaction(OSystem *syst, const PARALLACTIONGameDescription *gam
Parallaction::~Parallaction() {
- clearSet(_commandOpcodes);
- clearSet(_instructionOpcodes);
-
delete _debugger;
delete _globalTable;
delete _callableNames;
+ delete _cmdExec;
+ delete _programExec;
+ _gfx->clearGfxObjects(kGfxObjCharacter | kGfxObjNormal);
+ hideDialogueStuff();
+ delete _balloonMan;
freeLocation();
freeCharacter();
@@ -134,6 +136,8 @@ int Parallaction::init() {
_debugger = new Debugger(this);
+ setupBalloonManager();
+
return 0;
}
@@ -157,6 +161,11 @@ void Parallaction::updateView() {
}
+void Parallaction::hideDialogueStuff() {
+ _gfx->freeItems();
+ _balloonMan->freeBalloons();
+}
+
void Parallaction::freeCharacter() {
debugC(1, kDebugExec, "freeCharacter()");
@@ -164,6 +173,8 @@ void Parallaction::freeCharacter() {
delete _objectsNames;
_objectsNames = 0;
+ _gfx->clearGfxObjects(kGfxObjCharacter);
+
_char.free();
return;
@@ -246,7 +257,7 @@ void Parallaction::freeLocation() {
_location._walkNodes.clear();
- _gfx->clearGfxObjects();
+ _gfx->clearGfxObjects(kGfxObjNormal);
freeBackground();
_location._programs.clear();
@@ -281,23 +292,13 @@ void Parallaction::setBackground(const char* name, const char* mask, const char*
}
void Parallaction::showLocationComment(const char *text, bool end) {
- _gfx->setLocationBalloon(const_cast<char*>(text), end);
+ _balloonMan->setLocationBalloon(const_cast<char*>(text), end);
}
void Parallaction::processInput(InputData *data) {
switch (data->_event) {
- case kEvEnterZone:
- debugC(2, kDebugInput, "processInput: kEvEnterZone");
- _gfx->showFloatingLabel(data->_label);
- break;
-
- case kEvExitZone:
- debugC(2, kDebugInput, "processInput: kEvExitZone");
- _gfx->hideFloatingLabel();
- break;
-
case kEvAction:
debugC(2, kDebugInput, "processInput: kEvAction");
_input->stopHovering();
@@ -308,7 +309,6 @@ void Parallaction::processInput(InputData *data) {
case kEvOpenInventory:
_input->stopHovering();
- _gfx->hideFloatingLabel();
if (hitZone(kZoneYou, data->_mousePos.x, data->_mousePos.y) == 0) {
setArrowCursor();
}
@@ -357,36 +357,43 @@ void Parallaction::processInput(InputData *data) {
void Parallaction::runGame() {
InputData *data = _input->updateInput();
- if (data->_event != kEvNone) {
- processInput(data);
- }
-
if (_engineFlags & kEngineQuit)
return;
- runPendingZones();
+ if (_input->_inputMode == Input::kInputModeDialogue) {
+ runDialogueFrame();
+ } else {
+ if (data->_event != kEvNone) {
+ processInput(data);
+ }
- if (_engineFlags & kEngineQuit)
- return;
+ if (_engineFlags & kEngineQuit)
+ return;
- if (_engineFlags & kEngineChangeLocation) {
- changeLocation(_location._name);
- }
+ runPendingZones();
- if (_engineFlags & kEngineQuit)
- return;
+ if (_engineFlags & kEngineQuit)
+ return;
+
+ if (_engineFlags & kEngineChangeLocation) {
+ changeLocation(_location._name);
+ }
+ }
_gfx->beginFrame();
if (_input->_inputMode == Input::kInputModeGame) {
- runScripts();
- walk();
+ _programExec->runScripts(_location._programs.begin(), _location._programs.end());
+ _char._ani->_z = _char._ani->height() + _char._ani->_top;
+ if (_char._ani->gfxobj) {
+ _char._ani->gfxobj->z = _char._ani->_z;
+ }
+ walk(_char);
drawAnimations();
}
// change this to endFrame?
updateView();
-
}
@@ -415,14 +422,14 @@ void Parallaction::doLocationEnterTransition() {
pal.makeGrayscale();
_gfx->setPalette(pal);
- runScripts();
+ _programExec->runScripts(_location._programs.begin(), _location._programs.end());
drawAnimations();
_gfx->updateScreen();
showLocationComment(_location._comment, false);
_input->waitUntilLeftClick();
- _gfx->freeBalloons();
+ _balloonMan->freeBalloons();
// fades maximum intensity palette towards approximation of main palette
for (uint16 _si = 0; _si<6; _si++) {
@@ -493,6 +500,34 @@ void Parallaction::freeZones() {
}
+enum {
+ WALK_LEFT = 0,
+ WALK_RIGHT = 1,
+ WALK_DOWN = 2,
+ WALK_UP = 3
+};
+
+struct WalkFrames {
+ int16 stillFrame[4];
+ int16 firstWalkFrame[4];
+ int16 numWalkFrames[4];
+ int16 frameRepeat[4];
+};
+
+WalkFrames _char20WalkFrames = {
+ { 0, 7, 14, 17 },
+ { 1, 8, 15, 18 },
+ { 6, 6, 2, 2 },
+ { 2, 2, 4, 4 }
+};
+
+WalkFrames _char24WalkFrames = {
+ { 0, 9, 18, 21 },
+ { 1, 10, 19, 22 },
+ { 8, 8, 2, 2 },
+ { 2, 2, 4, 4 }
+};
+
const char Character::_prefixMini[] = "mini";
const char Character::_suffixTras[] = "tras";
const char Character::_empty[] = "\0";
@@ -503,6 +538,9 @@ Character::Character(Parallaction *vm) : _vm(vm), _ani(new Animation), _builder(
_head = NULL;
_objs = NULL;
+ _direction = WALK_DOWN;
+ _step = 0;
+
_dummy = false;
_ani->_left = 150;
@@ -567,10 +605,14 @@ void Character::setName(const char *name) {
const char *end = begin + strlen(name);
_prefix = _empty;
+ _suffix = _empty;
_dummy = IS_DUMMY_CHARACTER(name);
if (!_dummy) {
+ if (!strstr(name, "donna")) {
+ _engineFlags &= ~kEngineTransformedDonna;
+ } else
if (_engineFlags & kEngineTransformedDonna) {
_suffix = _suffixTras;
} else {
@@ -579,8 +621,6 @@ void Character::setName(const char *name) {
_engineFlags |= kEngineTransformedDonna;
_suffix = _suffixTras;
end = s;
- } else {
- _suffix = _empty;
}
}
if (IS_MINI_CHARACTER(name)) {
@@ -616,9 +656,35 @@ void Parallaction::beep() {
}
void Parallaction::scheduleLocationSwitch(const char *location) {
+ debugC(9, kDebugExec, "scheduleLocationSwitch(%s)\n", location);
strcpy(_location._name, location);
_engineFlags |= kEngineChangeLocation;
}
+
+
+
+void Character::updateDirection(const Common::Point& pos, const Common::Point& to) {
+
+ Common::Point dist(to.x - pos.x, to.y - pos.y);
+ WalkFrames *frames = (_ani->getFrameNum() == 20) ? &_char20WalkFrames : &_char24WalkFrames;
+
+ _step++;
+
+ if (dist.x == 0 && dist.y == 0) {
+ _ani->_frame = frames->stillFrame[_direction];
+ return;
+ }
+
+ if (dist.x < 0)
+ dist.x = -dist.x;
+ if (dist.y < 0)
+ dist.y = -dist.y;
+
+ _direction = (dist.x > dist.y) ? ((to.x > pos.x) ? WALK_LEFT : WALK_RIGHT) : ((to.y > pos.y) ? WALK_DOWN : WALK_UP);
+ _ani->_frame = frames->firstWalkFrame[_direction] + (_step / frames->frameRepeat[_direction]) % frames->numWalkFrames[_direction];
+}
+
+
} // namespace Parallaction
diff --git a/engines/parallaction/parallaction.h b/engines/parallaction/parallaction.h
index b1a5995e28..c45d32b013 100644
--- a/engines/parallaction/parallaction.h
+++ b/engines/parallaction/parallaction.h
@@ -33,6 +33,7 @@
#include "engines/engine.h"
+#include "parallaction/exec.h"
#include "parallaction/input.h"
#include "parallaction/inventory.h"
#include "parallaction/parser.h"
@@ -113,8 +114,6 @@ enum EngineFlags {
enum {
kEvNone = 0,
- kEvEnterZone = 1,
- kEvExitZone = 2,
kEvAction = 3,
kEvOpenInventory = 4,
kEvCloseInventory = 5,
@@ -164,6 +163,7 @@ class Debugger;
class Gfx;
class SoundMan;
class Input;
+class DialogueManager;
struct Location {
@@ -228,18 +228,19 @@ protected:
static const char _suffixTras[];
static const char _empty[];
+ int16 _direction, _step;
+
public:
void setName(const char *name);
const char *getName() const;
const char *getBaseName() const;
const char *getFullName() const;
bool dummy() const;
-};
+ void updateDirection(const Common::Point& pos, const Common::Point& to);
+};
-#define DECLARE_UNQUALIFIED_COMMAND_OPCODE(op) void cmdOp_##op()
-#define DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(op) void instOp_##op()
#define NUM_LOCATIONS 120
@@ -259,41 +260,20 @@ public:
Input *_input;
- OpcodeSet _commandOpcodes;
-
- struct ParallactionStruct1 {
- CommandPtr cmd;
- ZonePtr z;
- } _cmdRunCtxt;
-
- OpcodeSet _instructionOpcodes;
-
- struct ParallactionStruct2 {
- AnimationPtr anim;
- ProgramPtr program;
- InstructionList::iterator inst;
- uint16 modCounter;
- bool suspend;
- } _instRunCtxt;
-
void processInput(InputData* data);
void pauseJobs();
void resumeJobs();
- void finalizeWalk(WalkNodeList *list);
- int16 selectWalkFrame(const Common::Point& pos, const WalkNodePtr from);
- void clipMove(Common::Point& pos, const WalkNodePtr from);
+ void finalizeWalk(Character &character);
+ int16 selectWalkFrame(Character &character, const Common::Point& pos, const WalkNodePtr to);
+ void clipMove(Common::Point& pos, const Common::Point& to);
ZonePtr findZone(const char *name);
ZonePtr hitZone(uint32 type, uint16 x, uint16 y);
uint16 runZone(ZonePtr z);
void freeZones();
- void runDialogue(SpeakData*);
-
- void runCommands(CommandList& list, ZonePtr z = nullZonePtr);
-
AnimationPtr findAnimation(const char *name);
void freeAnimations();
@@ -327,6 +307,8 @@ public:
Gfx* _gfx;
Disk* _disk;
+ CommandExec* _cmdExec;
+ ProgramExec* _programExec;
Character _char;
void setLocationFlags(uint32 flags);
@@ -367,10 +349,8 @@ protected: // members
void runGame();
void updateView();
- void scheduleLocationSwitch(const char *location);
void doLocationEnterTransition();
virtual void changeLocation(char *location) = 0;
- virtual void changeCharacter(const char *name) = 0;
virtual void runPendingZones() = 0;
void allocateLocationSlot(const char *name);
void finalizeLocationParsing();
@@ -379,7 +359,7 @@ protected: // members
void displayComment(ExamineData *data);
- uint16 checkDoor();
+ void checkDoor(const Common::Point &foot);
void freeCharacter();
@@ -389,6 +369,9 @@ protected: // members
public:
+ void scheduleLocationSwitch(const char *location);
+ virtual void changeCharacter(const char *name) = 0;
+
virtual void callFunction(uint index, void* parm) { }
virtual void setArrowCursor() = 0;
@@ -398,12 +381,12 @@ public:
void updateDoor(ZonePtr z);
- virtual void runScripts() = 0;
- virtual void walk() = 0;
+ virtual void walk(Character &character) = 0;
virtual void drawAnimations() = 0;
void beep();
+ ZonePtr _zoneTrap;
public:
// const char **_zoneFlagNamesRes;
@@ -429,6 +412,16 @@ public:
Inventory *_inventory;
InventoryRenderer *_inventoryRenderer;
+ BalloonManager *_balloonMan;
+
+ void setupBalloonManager();
+
+ void hideDialogueStuff();
+ DialogueManager *_dialogueMan;
+ void enterDialogueMode(ZonePtr z);
+ void exitDialogueMode();
+ void runDialogueFrame();
+
};
@@ -524,7 +517,6 @@ private:
void initResources();
void initCursors();
- void initParsers();
static byte _resMouseArrow[256];
byte *_mouseArrow;
@@ -587,49 +579,12 @@ private:
const Callable *_callables;
protected:
- void runScripts();
- void walk();
+ void walk(Character &character);
void drawAnimations();
void parseLocation(const char *filename);
void loadProgram(AnimationPtr a, const char *filename);
- void initOpcodes();
-
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(invalid);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(set);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(clear);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(start);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(speak);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(get);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(location);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(open);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(close);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(on);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(off);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(call);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(toggle);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(drop);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(quit);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(move);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(stop);
-
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(invalid);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(on);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(off);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(loop);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(endloop);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(null);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(call);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(inc);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(set);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(put);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(wait);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(start);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(sound);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(move);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(endscript);
-
void selectStartLocation();
void guiStart();
@@ -662,6 +617,9 @@ public:
typedef void (Parallaction_br::*Callable)(void*);
virtual void callFunction(uint index, void* parm);
void changeCharacter(const char *name);
+ void setupSubtitles(char *s, char *s2, int y);
+ void clearSubtitles();
+
public:
Table *_countersNames;
@@ -689,8 +647,6 @@ private:
void initResources();
void initFonts();
void freeFonts();
- void initOpcodes();
- void initParsers();
void setArrowCursor();
void setInventoryCursor(int pos);
@@ -732,68 +688,6 @@ private:
void parseLocation(const char* name);
void loadProgram(AnimationPtr a, const char *filename);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(location);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(open);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(close);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(on);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(off);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(call);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(drop);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(move);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(start);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(stop);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(character);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(followme);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(onmouse);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(offmouse);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(add);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(leave);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(inc);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(dec);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(ifeq);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(iflt);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(ifgt);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(let);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(music);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(fix);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(unfix);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(zeta);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(scroll);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(swap);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(give);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(text);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(part);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(testsfx);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(ret);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(onsave);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(offsave);
-
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(on);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(off);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(loop);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(inc);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(dec);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(set);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(put);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(wait);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(start);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(process);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(move);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(color);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(mask);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(print);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(text);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(mul);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(div);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(ifeq);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(iflt);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(ifgt);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(endif);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(stop);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(endscript);
-
- void setupSubtitles(char *s, char *s2, int y);
- void clearSubtitles();
#if 0
void jobWaitRemoveLabelJob(void *parm, Job *job);
void jobPauseSfx(void *parm, Job *job);
diff --git a/engines/parallaction/parallaction_br.cpp b/engines/parallaction/parallaction_br.cpp
index b22e1b0f2d..9e2a0f10f1 100644
--- a/engines/parallaction/parallaction_br.cpp
+++ b/engines/parallaction/parallaction_br.cpp
@@ -72,14 +72,21 @@ int Parallaction_br::init() {
initResources();
initFonts();
initCursors();
- initOpcodes();
_locationParser = new LocationParser_br(this);
_locationParser->init();
_programParser = new ProgramParser_br(this);
_programParser->init();
+ _cmdExec = new CommandExec_br(this);
+ _cmdExec->init();
+ _programExec = new ProgramExec_br(this);
+ _programExec->init();
+
_part = -1;
+ _subtitle[0] = -1;
+ _subtitle[1] = -1;
+
Parallaction::init();
return 0;
@@ -205,13 +212,21 @@ void Parallaction_br::runPendingZones() {
if (_activeZone) {
z = _activeZone; // speak Zone or sound
_activeZone = nullZonePtr;
- runZone(z); // FIXME: BRA doesn't handle sound yet
+ if ((z->_type & 0xFFFF) == kZoneSpeak) {
+ enterDialogueMode(z);
+ } else {
+ runZone(z); // FIXME: BRA doesn't handle sound yet
+ }
}
if (_activeZone2) {
z = _activeZone2; // speak Zone or sound
_activeZone2 = nullZonePtr;
- runZone(z);
+ if ((z->_type & 0xFFFF) == kZoneSpeak) {
+ enterDialogueMode(z);
+ } else {
+ runZone(z); // FIXME: BRA doesn't handle sound yet
+ }
}
}
@@ -221,10 +236,16 @@ void Parallaction_br::changeLocation(char *location) {
// free open location stuff
clearSubtitles();
freeBackground();
- _gfx->clearGfxObjects();
+ _gfx->clearGfxObjects(kGfxObjNormal | kGfxObjCharacter);
_location._programs.clear();
+
+ _location._animations.remove(_char._ani);
+
freeZones();
freeAnimations();
+
+ _location._animations.push_front(_char._ani);
+
// free(_location._comment);
// _location._comment = 0;
// _location._commands.clear();
@@ -233,9 +254,9 @@ void Parallaction_br::changeLocation(char *location) {
// load new location
parseLocation(location);
- runCommands(_location._commands);
+ _cmdExec->run(_location._commands);
// doLocationEnterTransition();
- runCommands(_location._aCommands);
+ _cmdExec->run(_location._aCommands);
_engineFlags &= ~kEngineChangeLocation;
}
@@ -284,12 +305,16 @@ void Parallaction_br::loadProgram(AnimationPtr a, const char *filename) {
void Parallaction_br::changeCharacter(const char *name) {
+ printf("changeCharacter(%s)\n", name);
+
const char *charName = _char.getName();
if (!scumm_stricmp(charName, name)) {
return;
}
_char.setName(name);
+ _char._ani->gfxobj = _gfx->loadAnim(name);
+ _char._ani->gfxobj->setFlags(kGfxObjCharacter);
_char._talk = _disk->loadTalk(name);
}
diff --git a/engines/parallaction/parallaction_ns.cpp b/engines/parallaction/parallaction_ns.cpp
index af848aa6af..9e925d1e1d 100644
--- a/engines/parallaction/parallaction_ns.cpp
+++ b/engines/parallaction/parallaction_ns.cpp
@@ -135,12 +135,16 @@ int Parallaction_ns::init() {
initResources();
initFonts();
initCursors();
- initOpcodes();
_locationParser = new LocationParser_ns(this);
_locationParser->init();
_programParser = new ProgramParser_ns(this);
_programParser->init();
+ _cmdExec = new CommandExec_ns(this);
+ _cmdExec->init();
+ _programExec = new ProgramExec_ns(this);
+ _programExec->init();
+
_introSarcData1 = 0;
_introSarcData2 = 1;
_introSarcData3 = 200;
@@ -187,7 +191,7 @@ void Parallaction_ns::setArrowCursor() {
debugC(1, kDebugInput, "setting mouse cursor to arrow");
// this stuff is needed to avoid artifacts with labels and selected items when switching cursors
- _gfx->hideFloatingLabel();
+ _input->stopHovering();
_input->_activeItem._id = 0;
_system->setMouseCursor(_mouseArrow, MOUSEARROW_WIDTH, MOUSEARROW_HEIGHT, 0, 0, 0);
@@ -298,14 +302,16 @@ void Parallaction_ns::changeLocation(char *location) {
_soundMan->playLocationMusic(location);
- _gfx->hideFloatingLabel();
+ _input->stopHovering();
_gfx->freeLabels();
- _input->stopHovering();
+ _zoneTrap = nullZonePtr;
+
if (_engineFlags & kEngineBlockInput) {
setArrowCursor();
}
+ _gfx->showGfxObj(_char._ani->gfxobj, false);
_location._animations.remove(_char._ani);
freeLocation();
@@ -327,6 +333,7 @@ void Parallaction_ns::changeLocation(char *location) {
}
_location._animations.push_front(_char._ani);
+ _gfx->showGfxObj(_char._ani->gfxobj, true);
strcpy(_saveData1, locname.location());
parseLocation(_saveData1);
@@ -351,11 +358,11 @@ void Parallaction_ns::changeLocation(char *location) {
// and acommands are executed, so that it can be set again if needed.
_engineFlags &= ~kEngineChangeLocation;
- runCommands(_location._commands);
+ _cmdExec->run(_location._commands);
doLocationEnterTransition();
- runCommands(_location._aCommands);
+ _cmdExec->run(_location._aCommands);
if (_location._hasSound)
_soundMan->playSfx(_location._soundFile, 0, true);
@@ -411,6 +418,8 @@ void Parallaction_ns::changeCharacter(const char *name) {
Common::String oldArchive = _disk->selectArchive((getFeatures() & GF_DEMO) ? "disk0" : "disk1");
_char._ani->gfxobj = _gfx->loadAnim(_char.getFullName());
+ _char._ani->gfxobj->setFlags(kGfxObjCharacter);
+ _char._ani->gfxobj->clearFlags(kGfxObjNormal);
if (!_char.dummy()) {
if (getPlatform() == Common::kPlatformAmiga) {
diff --git a/engines/parallaction/parser_br.cpp b/engines/parallaction/parser_br.cpp
index 51da7eb396..defc917a72 100644
--- a/engines/parallaction/parser_br.cpp
+++ b/engines/parallaction/parser_br.cpp
@@ -390,7 +390,7 @@ DECLARE_LOCATION_PARSER(flags) {
if ((_vm->getLocationFlags() & kFlagsVisited) == 0) {
// only for 1st visit
- _vm->clearLocationFlags(kFlagsAll);
+ _vm->clearLocationFlags((uint32)kFlagsAll);
int _si = 1;
do {
diff --git a/engines/parallaction/parser_ns.cpp b/engines/parallaction/parser_ns.cpp
index c654e3008e..2f4d2df776 100644
--- a/engines/parallaction/parser_ns.cpp
+++ b/engines/parallaction/parser_ns.cpp
@@ -1059,7 +1059,7 @@ DECLARE_LOCATION_PARSER(flags) {
if ((_vm->getLocationFlags() & kFlagsVisited) == 0) {
// only for 1st visit
- _vm->clearLocationFlags(kFlagsAll);
+ _vm->clearLocationFlags((uint32)kFlagsAll);
int _si = 1;
do {
diff --git a/engines/parallaction/sound.cpp b/engines/parallaction/sound.cpp
index dd74e8f7aa..df6867a90c 100644
--- a/engines/parallaction/sound.cpp
+++ b/engines/parallaction/sound.cpp
@@ -175,6 +175,7 @@ void MidiPlayer::close() {
_mutex.lock();
_driver->setTimerCallback(NULL, NULL);
_driver->close();
+ delete _driver;
_driver = 0;
_parser->setMidiDriver(NULL);
delete _parser;
@@ -249,6 +250,9 @@ void DosSoundMan::stopMusic() {
}
void DosSoundMan::playCharacterMusic(const char *character) {
+ if (character == NULL) {
+ return;
+ }
if (!scumm_stricmp(_vm->_location._name, "night") ||
!scumm_stricmp(_vm->_location._name, "intsushi")) {
diff --git a/engines/parallaction/walk.cpp b/engines/parallaction/walk.cpp
index 0a8ded9e29..a717b615e6 100644
--- a/engines/parallaction/walk.cpp
+++ b/engines/parallaction/walk.cpp
@@ -27,12 +27,6 @@
namespace Parallaction {
-static uint16 _doorData1 = 1000;
-static ZonePtr _zoneTrap;
-
-static uint16 walkData1 = 0;
-static uint16 walkData2 = 0; // next walk frame
-
inline byte PathBuffer::getValue(uint16 x, uint16 y) {
byte m = data[(x >> 3) + y * internalWidth];
@@ -259,172 +253,118 @@ uint16 PathBuilder::walkFunc1(int16 x, int16 y, WalkNodePtr Node) {
return 1;
}
-void Parallaction::clipMove(Common::Point& pos, const WalkNodePtr from) {
+void Parallaction::clipMove(Common::Point& pos, const Common::Point& to) {
- if ((pos.x < from->_x) && (pos.x < _pathBuffer->w) && (_pathBuffer->getValue(pos.x + 2, pos.y) != 0)) {
- pos.x = (pos.x + 2 < from->_x) ? pos.x + 2 : from->_x;
+ if ((pos.x < to.x) && (pos.x < _pathBuffer->w) && (_pathBuffer->getValue(pos.x + 2, pos.y) != 0)) {
+ pos.x = (pos.x + 2 < to.x) ? pos.x + 2 : to.x;
}
- if ((pos.x > from->_x) && (pos.x > 0) && (_pathBuffer->getValue(pos.x - 2, pos.y) != 0)) {
- pos.x = (pos.x - 2 > from->_x) ? pos.x - 2 : from->_x;
+ if ((pos.x > to.x) && (pos.x > 0) && (_pathBuffer->getValue(pos.x - 2, pos.y) != 0)) {
+ pos.x = (pos.x - 2 > to.x) ? pos.x - 2 : to.x;
}
- if ((pos.y < from->_y) && (pos.y < _pathBuffer->h) && (_pathBuffer->getValue(pos.x, pos.y + 2) != 0)) {
- pos.y = (pos.y + 2 <= from->_y) ? pos.y + 2 : from->_y;
+ if ((pos.y < to.y) && (pos.y < _pathBuffer->h) && (_pathBuffer->getValue(pos.x, pos.y + 2) != 0)) {
+ pos.y = (pos.y + 2 <= to.y) ? pos.y + 2 : to.y;
}
- if ((pos.y > from->_y) && (pos.y > 0) && (_pathBuffer->getValue(pos.x, pos.y - 2) != 0)) {
- pos.y = (pos.y - 2 >= from->_y) ? pos.y - 2 :from->_y;
+ if ((pos.y > to.y) && (pos.y > 0) && (_pathBuffer->getValue(pos.x, pos.y - 2) != 0)) {
+ pos.y = (pos.y - 2 >= to.y) ? pos.y - 2 : to.y;
}
return;
}
-int16 Parallaction::selectWalkFrame(const Common::Point& pos, const WalkNodePtr from) {
-
- Common::Point dist(from->_x - pos.x, from->_y - pos.y);
-
- if (dist.x < 0)
- dist.x = -dist.x;
- if (dist.y < 0)
- dist.y = -dist.y;
- walkData1++;
-
- // walk frame selection
- int16 v16;
- if (_char._ani->getFrameNum() == 20) {
-
- if (dist.x > dist.y) {
- walkData2 = (from->_x > pos.x) ? 0 : 7;
- walkData1 %= 12;
- v16 = walkData1 / 2;
- } else {
- walkData2 = (from->_y > pos.y) ? 14 : 17;
- walkData1 %= 8;
- v16 = walkData1 / 4;
- }
-
- } else {
-
- if (dist.x > dist.y) {
- walkData2 = (from->_x > pos.x) ? 0 : 9;
- walkData1 %= 16;
- v16 = walkData1 / 2;
- } else {
- walkData2 = (from->_y > pos.y) ? 18 : 21;
- walkData1 %= 8;
- v16 = walkData1 / 4;
- }
-
- }
-
- return v16;
-}
-
-uint16 Parallaction::checkDoor() {
-// printf("checkDoor()...");
-
- if (_currentLocationIndex != _doorData1) {
- _doorData1 = _currentLocationIndex;
- _zoneTrap = nullZonePtr;
- }
-
- _engineFlags &= ~kEngineWalking;
-
- Common::Point foot;
+void Parallaction::checkDoor(const Common::Point &foot) {
- _char.getFoot(foot);
ZonePtr z = hitZone(kZoneDoor, foot.x, foot.y);
-
if (z) {
-
if ((z->_flags & kFlagsClosed) == 0) {
_location._startPosition = z->u.door->_startPos;
_location._startFrame = z->u.door->_startFrame;
-
scheduleLocationSwitch(z->u.door->_location);
_zoneTrap = nullZonePtr;
-
} else {
- runCommands(z->_commands, z);
+ _cmdExec->run(z->_commands, z);
}
}
- _char.getFoot(foot);
z = hitZone(kZoneTrap, foot.x, foot.y);
-
if (z) {
setLocationFlags(kFlagsEnter);
- runCommands(z->_commands, z);
+ _cmdExec->run(z->_commands, z);
clearLocationFlags(kFlagsEnter);
_zoneTrap = z;
} else
if (_zoneTrap) {
setLocationFlags(kFlagsExit);
- runCommands(_zoneTrap->_commands, _zoneTrap);
+ _cmdExec->run(_zoneTrap->_commands, _zoneTrap);
clearLocationFlags(kFlagsExit);
_zoneTrap = nullZonePtr;
}
-// printf("done\n");
-
- _char._ani->_frame = walkData2;
- return _char._ani->_frame;
}
-void Parallaction::finalizeWalk(WalkNodeList *list) {
- checkDoor();
- delete list;
+void Parallaction::finalizeWalk(Character &character) {
+ _engineFlags &= ~kEngineWalking;
+
+ Common::Point foot;
+ character.getFoot(foot);
+ checkDoor(foot);
+
+ delete character._walkPath;
+ character._walkPath = 0;
}
-void Parallaction_ns::walk() {
+void Parallaction_ns::walk(Character &character) {
if ((_engineFlags & kEngineWalking) == 0) {
return;
}
- WalkNodeList *list = _char._walkPath;
-
- _char._ani->_oldPos.x = _char._ani->_left;
- _char._ani->_oldPos.y = _char._ani->_top;
-
- Common::Point pos;
- _char.getFoot(pos);
-
- WalkNodeList::iterator it = list->begin();
+ Common::Point curPos;
+ character.getFoot(curPos);
- if (it != list->end()) {
- if ((*it)->_x == pos.x && (*it)->_y == pos.y) {
+ // update target, if previous was reached
+ WalkNodeList::iterator it = character._walkPath->begin();
+ if (it != character._walkPath->end()) {
+ if ((*it)->_x == curPos.x && (*it)->_y == curPos.y) {
debugC(1, kDebugWalk, "walk reached node (%i, %i)", (*it)->_x, (*it)->_y);
- it = list->erase(it);
+ it = character._walkPath->erase(it);
}
}
- if (it == list->end()) {
- debugC(1, kDebugWalk, "walk reached last node");
-// j->_finished = 1;
- finalizeWalk(list);
- return;
- }
- _char._walkPath = list;
-
- // selectWalkFrame must be performed before position is changed by clipMove
- int16 v16 = selectWalkFrame(pos, *it);
- clipMove(pos, *it);
- _char.setFoot(pos);
+ // advance character towards the target
+ Common::Point targetPos;
+ if (it == character._walkPath->end()) {
+ debugC(1, kDebugWalk, "walk reached last node");
+ finalizeWalk(character);
+ targetPos = curPos;
+ } else {
+ if (*it) {
+ // targetPos is saved to help setting character direction
+ targetPos.x = (*it)->_x;
+ targetPos.y = (*it)->_y;
+ }
- Common::Point newpos(_char._ani->_left, _char._ani->_top);
+ Common::Point newPos(curPos);
+ clipMove(newPos, targetPos);
+ character.setFoot(newPos);
- if (newpos == _char._ani->_oldPos) {
- debugC(1, kDebugWalk, "walk was blocked by an unforeseen obstacle");
-// j->_finished = 1;
- finalizeWalk(list);
- } else {
- _char._ani->_frame = v16 + walkData2 + 1;
+ if (newPos == curPos) {
+ debugC(1, kDebugWalk, "walk was blocked by an unforeseen obstacle");
+ finalizeWalk(character);
+ targetPos = newPos; // when walking is interrupted, targetPos must be hacked so that a still frame can be selected
+ }
}
- return;
+ // targetPos is used to select the direction (and the walkFrame) of a character,
+ // since it doesn't cause the sudden changes in orientation that newPos would.
+ // Since newPos is 'adjusted' according to walkable areas, an imaginary line drawn
+ // from curPos to newPos is prone to abrutply change in direction, thus making the
+ // code select 'too different' frames when walking diagonally against obstacles,
+ // and yielding an annoying shaking effect in the character.
+ character.updateDirection(curPos, targetPos);
}