aboutsummaryrefslogtreecommitdiff
path: root/engines/parallaction
diff options
context:
space:
mode:
Diffstat (limited to 'engines/parallaction')
-rw-r--r--engines/parallaction/balloons.cpp310
-rw-r--r--engines/parallaction/callables_ns.cpp110
-rw-r--r--engines/parallaction/detection.cpp36
-rw-r--r--engines/parallaction/dialogue.cpp48
-rw-r--r--engines/parallaction/disk.h52
-rw-r--r--engines/parallaction/disk_br.cpp553
-rw-r--r--engines/parallaction/exec.h28
-rw-r--r--engines/parallaction/exec_br.cpp43
-rw-r--r--engines/parallaction/exec_ns.cpp254
-rw-r--r--engines/parallaction/font.cpp140
-rw-r--r--engines/parallaction/gfxbase.cpp59
-rw-r--r--engines/parallaction/graphics.cpp166
-rw-r--r--engines/parallaction/graphics.h13
-rw-r--r--engines/parallaction/gui.cpp92
-rw-r--r--engines/parallaction/gui.h93
-rw-r--r--engines/parallaction/gui_br.cpp335
-rw-r--r--engines/parallaction/gui_ns.cpp941
-rw-r--r--engines/parallaction/input.cpp222
-rw-r--r--engines/parallaction/input.h47
-rw-r--r--engines/parallaction/inventory.cpp142
-rw-r--r--engines/parallaction/inventory.h27
-rw-r--r--engines/parallaction/module.mk1
-rw-r--r--engines/parallaction/objects.cpp10
-rw-r--r--engines/parallaction/objects.h22
-rw-r--r--engines/parallaction/parallaction.cpp121
-rw-r--r--engines/parallaction/parallaction.h83
-rw-r--r--engines/parallaction/parallaction_br.cpp130
-rw-r--r--engines/parallaction/parallaction_ns.cpp59
-rw-r--r--engines/parallaction/parser.h10
-rw-r--r--engines/parallaction/parser_br.cpp67
-rw-r--r--engines/parallaction/parser_ns.cpp23
-rw-r--r--engines/parallaction/walk.cpp490
-rw-r--r--engines/parallaction/walk.h84
33 files changed, 3305 insertions, 1506 deletions
diff --git a/engines/parallaction/balloons.cpp b/engines/parallaction/balloons.cpp
index fab92dada9..81b32adb15 100644
--- a/engines/parallaction/balloons.cpp
+++ b/engines/parallaction/balloons.cpp
@@ -23,6 +23,8 @@
*
*/
+#include "common/util.h"
+
#include "parallaction/graphics.h"
#include "parallaction/parallaction.h"
@@ -76,6 +78,7 @@ class BalloonManager_ns : public BalloonManager {
uint _numBalloons;
+ void getStringExtent(Font *font, char *text, uint16 maxwidth, int16* width, int16* height);
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);
@@ -149,12 +152,12 @@ int BalloonManager_ns::setSingleBalloon(char *text, uint16 x, uint16 y, uint16 w
int16 w, h;
- _gfx->getStringExtent(_vm->_dialogueFont, text, MAX_BALLOON_WIDTH, &w, &h);
+ 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);
+ 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);
@@ -169,12 +172,12 @@ int BalloonManager_ns::setDialogueBalloon(char *text, uint16 winding, byte textC
int16 w, h;
- _gfx->getStringExtent(_vm->_dialogueFont, text, MAX_BALLOON_WIDTH, &w, &h);
+ 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);
+ 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);
@@ -193,7 +196,7 @@ int BalloonManager_ns::setDialogueBalloon(char *text, uint16 winding, byte textC
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);
+ drawWrappedText(_vm->_dialogueFont, balloon->surface, text, textColor, MAX_BALLOON_WIDTH);
}
@@ -201,11 +204,11 @@ int BalloonManager_ns::setLocationBalloon(char *text, bool endGame) {
int16 w, h;
- _gfx->getStringExtent(_vm->_dialogueFont, text, MAX_BALLOON_WIDTH, &w, &h);
+ 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);
+ 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);
@@ -242,8 +245,105 @@ void BalloonManager_ns::freeBalloons() {
_numBalloons = 0;
}
+void BalloonManager_ns::drawWrappedText(Font *font, Graphics::Surface* surf, char *text, byte color, int16 wrapwidth) {
+
+ uint16 lines = 0;
+ uint16 linewidth = 0;
+
+ uint16 rx = 10;
+ uint16 ry = 4;
+
+ uint16 blankWidth = font->getStringWidth(" ");
+ uint16 tokenWidth = 0;
+
+ char token[MAX_TOKEN_LEN];
+
+ if (wrapwidth == -1)
+ wrapwidth = _vm->_screenWidth;
+
+ while (strlen(text) > 0) {
+
+ text = parseNextToken(text, token, MAX_TOKEN_LEN, " ", true);
+
+ if (!scumm_stricmp(token, "%p")) {
+ lines++;
+ rx = 10;
+ ry = 4 + lines*10; // y
+
+ strcpy(token, "> .......");
+ strncpy(token+2, _password, strlen(_password));
+ tokenWidth = font->getStringWidth(token);
+ } else {
+ tokenWidth = font->getStringWidth(token);
+
+ linewidth += tokenWidth;
+
+ if (linewidth > wrapwidth) {
+ // wrap line
+ lines++;
+ rx = 10; // x
+ ry = 4 + lines*10; // y
+ linewidth = tokenWidth;
+ }
+
+ if (!scumm_stricmp(token, "%s")) {
+ sprintf(token, "%d", _score);
+ }
+
+ }
+
+ _gfx->drawText(font, surf, rx, ry, token, color);
+
+ rx += tokenWidth + blankWidth;
+ linewidth += blankWidth;
+
+ text = Common::ltrim(text);
+ }
+
+}
+void BalloonManager_ns::getStringExtent(Font *font, char *text, uint16 maxwidth, int16* width, int16* height) {
+ uint16 lines = 0;
+ uint16 w = 0;
+ *width = 0;
+
+ uint16 blankWidth = font->getStringWidth(" ");
+ uint16 tokenWidth = 0;
+
+ char token[MAX_TOKEN_LEN];
+
+ while (strlen(text) != 0) {
+
+ text = parseNextToken(text, token, MAX_TOKEN_LEN, " ", true);
+ tokenWidth = font->getStringWidth(token);
+
+ w += tokenWidth;
+
+ if (!scumm_stricmp(token, "%p")) {
+ lines++;
+ } else {
+ if (w > maxwidth) {
+ w -= tokenWidth;
+ lines++;
+ if (w > *width)
+ *width = w;
+
+ w = tokenWidth;
+ }
+ }
+
+ w += blankWidth;
+ text = Common::ltrim(text);
+ }
+
+ if (*width < w) *width = w;
+ *width += 10;
+
+ *height = lines * 10 + 20;
+
+ return;
+}
@@ -259,17 +359,36 @@ class BalloonManager_br : public BalloonManager {
uint _numBalloons;
- Frames *_leftBalloon;
- Frames *_rightBalloon;
Disk *_disk;
Gfx *_gfx;
+ Frames *_leftBalloon;
+ Frames *_rightBalloon;
+
void cacheAnims();
+ void getStringExtent(Font *font, const char *text, uint16 maxwidth, int16* width, int16* height);
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);
+ void textSetupRendering(const Common::String &text, Graphics::Surface *dest, Font *font, byte color);
+ void textEmitCenteredLine();
+ void textAccum(const Common::String &token, uint16 width);
+ void textNewLine();
+
+ Common::String _textLine;
+ Graphics::Surface *_textSurf;
+ Font *_textFont;
+ uint16 _textX, _textY;
+ byte _textColor;
+ uint16 _textLines, _textWidth;
+
+ void extentSetup(Font *font, int16 *width, int16 *height);
+ void extentAction();
+
+ int16 *_extentWidth, *_extentHeight;
+
public:
BalloonManager_br(Disk *disk, Gfx *gfx);
@@ -315,11 +434,11 @@ int BalloonManager_br::setSingleBalloon(char *text, uint16 x, uint16 y, uint16 w
Balloon *balloon = &_intBalloons[id];
if (winding == 0) {
- src = _leftBalloon;
+ src = _rightBalloon;
srcFrame = 0;
} else
if (winding == 1) {
- src = _rightBalloon;
+ src = _leftBalloon;
srcFrame = 0;
}
@@ -328,14 +447,16 @@ int BalloonManager_br::setSingleBalloon(char *text, uint16 x, uint16 y, uint16 w
balloon->surface = expandBalloon(src, srcFrame);
src->getRect(srcFrame, balloon->box);
-// drawWrappedText(_vm->_dialogueFont, balloon->surface, text, textColor, MAX_BALLOON_WIDTH);
+ 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->x = x + balloon->box.left;
+ balloon->obj->y = y + balloon->box.top;
balloon->obj->transparentKey = BALLOON_TRANSPARENT_COLOR_BR;
+ printf("balloon (%i, %i)\n", balloon->obj->x, balloon->obj->y);
+
_numBalloons++;
return id;
@@ -351,11 +472,11 @@ int BalloonManager_br::setDialogueBalloon(char *text, uint16 winding, byte textC
Balloon *balloon = &_intBalloons[id];
if (winding == 0) {
- src = _leftBalloon;
+ src = _rightBalloon;
srcFrame = id;
} else
if (winding == 1) {
- src = _rightBalloon;
+ src = _leftBalloon;
srcFrame = 0;
}
@@ -364,12 +485,12 @@ int BalloonManager_br::setDialogueBalloon(char *text, uint16 winding, byte textC
balloon->surface = expandBalloon(src, srcFrame);
src->getRect(srcFrame, balloon->box);
-// drawWrappedText(_vm->_dialogueFont, balloon->surface, text, textColor, MAX_BALLOON_WIDTH);
+ 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->x = balloon->box.left;
+ balloon->obj->y = balloon->box.top;
balloon->obj->transparentKey = BALLOON_TRANSPARENT_COLOR_BR;
if (id > 0) {
@@ -434,6 +555,155 @@ void BalloonManager_br::cacheAnims() {
}
}
+
+void BalloonManager_br::extentSetup(Font *font, int16 *width, int16 *height) {
+ _extentWidth = width;
+ _extentHeight = height;
+
+ _textLine.clear();
+ _textLines = 0;
+ _textWidth = 0;
+ _textFont = font;
+}
+
+void BalloonManager_br::extentAction() {
+ if (_textWidth > *_extentWidth) {
+ *_extentWidth = _textWidth;
+ }
+ *_extentHeight = _textLines * _textFont->height();
+}
+
+void BalloonManager_br::textSetupRendering(const Common::String &text, Graphics::Surface *dest, Font *font, byte color) {
+ uint16 maxWidth = 216;
+
+ int16 w, h;
+ getStringExtent(font, text.c_str(), maxWidth, &w, &h);
+
+ w += 10;
+ h += 12;
+
+ _textLine.clear();
+ _textSurf = dest;
+ _textFont = font;
+ _textX = 0;
+ _textY = (_textSurf->h - h) / 2;
+ _textColor = color;
+ _textLines = 0;
+ _textWidth = 0;
+}
+
+void BalloonManager_br::textEmitCenteredLine() {
+ if (_textLine.empty()) {
+ return;
+ }
+ uint16 rx = _textX + (_textSurf->w - _textWidth) / 2;
+ uint16 ry = _textY + _textLines * _textFont->height(); // y
+ _gfx->drawText(_textFont, _textSurf, rx, ry, _textLine.c_str(), _textColor);
+}
+
+void BalloonManager_br::textAccum(const Common::String &token, uint16 width) {
+ if (token.empty()) {
+ return;
+ }
+
+ _textWidth += width;
+ _textLine += token;
+}
+
+void BalloonManager_br::textNewLine() {
+ _textLines++;
+ _textWidth = 0;
+ _textLine.clear();
+}
+
+
+// TODO: really, base this and getStringExtent on some kind of LineTokenizer, instead of
+// repeating the algorithm and changing a couple of lines.
+void BalloonManager_br::drawWrappedText(Font *font, Graphics::Surface* surf, char *text, byte color, int16 wrapWidth) {
+ textSetupRendering(text, surf, font, color);
+
+ wrapWidth = 216;
+
+ Common::StringTokenizer tokenizer(text, " ");
+ Common::String token;
+ Common::String blank(" ");
+
+ uint16 blankWidth = font->getStringWidth(" ");
+ uint16 tokenWidth = 0;
+
+ while (!tokenizer.empty()) {
+ token = tokenizer.nextToken();
+
+ if (token == '/') {
+ tokenWidth = 0;
+ textEmitCenteredLine();
+ textNewLine();
+ } else {
+ // todo: expand '%'
+ tokenWidth = font->getStringWidth(token.c_str());
+
+ if (_textWidth == 0) {
+ textAccum(token, tokenWidth);
+ } else {
+ if (_textWidth + blankWidth + tokenWidth <= wrapWidth) {
+ textAccum(blank, blankWidth);
+ textAccum(token, tokenWidth);
+ } else {
+ textEmitCenteredLine();
+ textNewLine();
+ textAccum(token, tokenWidth);
+ }
+ }
+ }
+ }
+
+ textEmitCenteredLine();
+}
+
+
+
+void BalloonManager_br::getStringExtent(Font *font, const char *text, uint16 maxwidth, int16* width, int16* height) {
+ extentSetup(font, width, height);
+
+ Common::StringTokenizer tokenizer(text, " ");
+ Common::String token;
+ Common::String blank(" ");
+
+ uint16 blankWidth = font->getStringWidth(" ");
+ uint16 tokenWidth = 0;
+
+ while (!tokenizer.empty()) {
+ token = tokenizer.nextToken();
+
+ if (token == '/') {
+ tokenWidth = 0;
+ extentAction();
+ textNewLine();
+ } else {
+ // todo: expand '%'
+ tokenWidth = font->getStringWidth(token.c_str());
+
+ if (_textWidth == 0) {
+ textAccum(token, tokenWidth);
+ } else {
+ if (_textWidth + blankWidth + tokenWidth <= maxwidth) {
+ textAccum(blank, blankWidth);
+ textAccum(token, tokenWidth);
+ } else {
+ extentAction();
+ textNewLine();
+ textAccum(token, tokenWidth);
+ }
+ }
+ }
+ }
+
+ extentAction();
+}
+
+
+
+
BalloonManager_br::BalloonManager_br(Disk *disk, Gfx *gfx) : _numBalloons(0), _disk(disk), _gfx(gfx), _leftBalloon(0), _rightBalloon(0) {
}
@@ -453,4 +723,6 @@ void Parallaction::setupBalloonManager() {
}
}
+
+
} // namespace Parallaction
diff --git a/engines/parallaction/callables_ns.cpp b/engines/parallaction/callables_ns.cpp
index ed60a193ce..9cd6b610ff 100644
--- a/engines/parallaction/callables_ns.cpp
+++ b/engines/parallaction/callables_ns.cpp
@@ -37,18 +37,6 @@
namespace Parallaction {
-// part completion messages
-static const char *endMsg0[] = {"COMPLIMENTI!", "BRAVO!", "CONGRATULATIONS!", "PRIMA!"};
-static const char *endMsg1[] = {"HAI FINITO QUESTA PARTE", "TU AS COMPLETE' CETTE AVENTURE", "YOU HAVE COMPLETED THIS PART", "DU HAST EIN ABENTEUER ERFOLGREICH"};
-static const char *endMsg2[] = {"ORA COMPLETA IL RESTO ", "AVEC SUCCES.", "NOW GO ON WITH THE REST OF", "ZU ENDE GEFUHRT"};
-static const char *endMsg3[] = {"DELL' AVVENTURA", "CONTINUE AVEC LES AUTRES", "THIS ADVENTURE", "MACH' MIT DEN ANDEREN WEITER"};
-// game completion messages
-static const char *endMsg4[] = {"COMPLIMENTI!", "BRAVO!", "CONGRATULATIONS!", "PRIMA!"};
-static const char *endMsg5[] = {"HAI FINITO LE TRE PARTI", "TU AS COMPLETE' LES TROIS PARTIES", "YOU HAVE COMPLETED THE THREE PARTS", "DU HAST DREI ABENTEURE ERFOLGREICH"};
-static const char *endMsg6[] = {"DELL' AVVENTURA", "DE L'AVENTURE", "OF THIS ADVENTURE", "ZU ENDE GEFUHRT"};
-static const char *endMsg7[] = {"ED ORA IL GRAN FINALE ", "ET MAINTENANT LE GRAND FINAL", "NOW THE GREAT FINAL", "UND YETZT DER GROSSE SCHLUSS!"};
-
-
/*
intro callables data members
*/
@@ -143,18 +131,6 @@ static uint16 _rightHandPositions[684] = {
0x00e0, 0x007b, 0x00e0, 0x0077
};
-struct Credit {
- const char *_role;
- const char *_name;
-} _credits[] = {
- {"Music and Sound Effects", "MARCO CAPRELLI"},
- {"PC Version", "RICCARDO BALLARINO"},
- {"Project Manager", "LOVRANO CANEPA"},
- {"Production", "BRUNO BOZ"},
- {"Special Thanks to", "LUIGI BENEDICENTI - GILDA and DANILO"},
- {"Copyright 1992 Euclidea s.r.l ITALY", "All rights reserved"}
-};
-
/*
game callables
*/
@@ -304,15 +280,11 @@ void Parallaction_ns::_c_trasformata(void *parm) {
}
void Parallaction_ns::_c_offMouse(void *parm) {
- _input->showCursor(false);
- _engineFlags |= kEngineBlockInput;
- return;
+ _input->setMouseState(MOUSE_DISABLED);
}
void Parallaction_ns::_c_onMouse(void *parm) {
- _engineFlags &= ~kEngineBlockInput;
- _input->showCursor(true);
- return;
+ _input->setMouseState(MOUSE_ENABLED_SHOW);
}
@@ -340,7 +312,7 @@ void Parallaction_ns::_c_endComment(void *param) {
g_system->delayMillis(20);
}
- _input->waitUntilLeftClick();
+ _input->waitForButtonEvent(kMouseLeftUp);
_balloonMan->freeBalloons();
return;
@@ -376,37 +348,12 @@ void Parallaction_ns::_c_finito(void *parm) {
setPartComplete(_char);
cleanInventory();
- _gfx->setPalette(_gfx->_palette);
-
- uint id[4];
-
- if (allPartsComplete()) {
- id[0] = _gfx->createLabel(_menuFont, endMsg4[_language], 1);
- id[1] = _gfx->createLabel(_menuFont, endMsg5[_language], 1);
- id[2] = _gfx->createLabel(_menuFont, endMsg6[_language], 1);
- id[3] = _gfx->createLabel(_menuFont, endMsg7[_language], 1);
- } else {
- id[0] = _gfx->createLabel(_menuFont, endMsg0[_language], 1);
- id[1] = _gfx->createLabel(_menuFont, endMsg1[_language], 1);
- id[2] = _gfx->createLabel(_menuFont, endMsg2[_language], 1);
- id[3] = _gfx->createLabel(_menuFont, endMsg3[_language], 1);
- }
-
- _gfx->showLabel(id[0], CENTER_LABEL_HORIZONTAL, 70);
- _gfx->showLabel(id[1], CENTER_LABEL_HORIZONTAL, 100);
- _gfx->showLabel(id[2], CENTER_LABEL_HORIZONTAL, 130);
- _gfx->showLabel(id[3], CENTER_LABEL_HORIZONTAL, 160);
- _input->waitUntilLeftClick();
+ cleanupGame();
- _gfx->freeLabels();
+ _gfx->setPalette(_gfx->_palette);
- if (allPartsComplete()) {
- scheduleLocationSwitch("estgrotta.drki");
- } else {
- selectStartLocation();
- }
+ startEndPartSequence();
- cleanupGame();
return;
}
@@ -467,52 +414,11 @@ void Parallaction_ns::_c_startIntro(void *parm) {
_soundMan->playMusic();
}
- _engineFlags |= kEngineBlockInput;
-
- return;
+ _input->setMouseState(MOUSE_DISABLED);
}
void Parallaction_ns::_c_endIntro(void *parm) {
-
- debugC(1, kDebugExec, "endIntro()");
-
- uint id[2];
- for (uint16 _si = 0; _si < 6; _si++) {
- id[0] = _gfx->createLabel(_menuFont, _credits[_si]._role, 1);
- id[1] = _gfx->createLabel(_menuFont, _credits[_si]._name, 1);
-
- _gfx->showLabel(id[0], CENTER_LABEL_HORIZONTAL, 80);
- _gfx->showLabel(id[1], CENTER_LABEL_HORIZONTAL, 100);
-
- _gfx->updateScreen();
-
- _input->waitForButtonEvent(kMouseLeftUp, 5500);
-
- _gfx->freeLabels();
- }
- debugC(1, kDebugExec, "endIntro(): done showing credits");
-
- _soundMan->stopMusic();
-
- if ((getFeatures() & GF_DEMO) == 0) {
-
- id[0] = _gfx->createLabel(_menuFont, "CLICK MOUSE BUTTON TO START", 1);
- _gfx->showLabel(id[0], CENTER_LABEL_HORIZONTAL, 80);
-
- _input->waitUntilLeftClick();
-
- _gfx->freeLabels();
-
- _engineFlags &= ~kEngineBlockInput;
- selectStartLocation();
-
- cleanupGame();
-
- } else {
- _input->waitUntilLeftClick();
- }
-
- return;
+ startCreditSequence();
}
void Parallaction_ns::_c_moveSheet(void *parm) {
diff --git a/engines/parallaction/detection.cpp b/engines/parallaction/detection.cpp
index 8841b9ca40..0476b01454 100644
--- a/engines/parallaction/detection.cpp
+++ b/engines/parallaction/detection.cpp
@@ -154,7 +154,23 @@ static const PARALLACTIONGameDescription gameDescriptions[] = {
Common::ADGF_NO_FLAGS
},
GType_BRA,
- GF_LANG_EN | GF_LANG_FR | GF_LANG_DE | GF_LANG_IT | GF_LANG_MULT
+ GF_LANG_EN | GF_LANG_FR | GF_LANG_DE | GF_LANG_IT | GF_LANG_MULT,
+ },
+
+ {
+ {
+ "bra",
+ "Demo",
+ {
+ { "russia.fnt", 0, "0dd55251d2886d6783718df2b184bf97", 10649 },
+ { NULL, 0, NULL, 0}
+ },
+ Common::UNK_LANG,
+ Common::kPlatformPC,
+ Common::ADGF_DEMO
+ },
+ GType_BRA,
+ GF_LANG_EN | GF_DEMO,
},
// TODO: Base the detection of Amiga BRA on actual data file, not executable file.
@@ -171,9 +187,25 @@ static const PARALLACTIONGameDescription gameDescriptions[] = {
Common::ADGF_NO_FLAGS
},
GType_BRA,
- GF_LANG_EN | GF_LANG_FR | GF_LANG_DE | GF_LANG_IT | GF_LANG_MULT
+ GF_LANG_EN | GF_LANG_FR | GF_LANG_DE | GF_LANG_IT | GF_LANG_MULT,
},
+ // TODO: Base the detection of Amiga BRA demo on actual data file, not executable file.
+ {
+ {
+ "bra",
+ "Demo",
+ {
+ { "bigred", 0, "b62a7b589fb5e9071f021227640893bf", 97004 },
+ { NULL, 0, NULL, 0}
+ },
+ Common::UNK_LANG,
+ Common::kPlatformAmiga,
+ Common::ADGF_DEMO
+ },
+ GType_BRA,
+ GF_LANG_EN | GF_DEMO,
+ },
{ AD_TABLE_END_MARKER, 0, 0 }
};
diff --git a/engines/parallaction/dialogue.cpp b/engines/parallaction/dialogue.cpp
index 290f8cfd4f..21584a0525 100644
--- a/engines/parallaction/dialogue.cpp
+++ b/engines/parallaction/dialogue.cpp
@@ -33,7 +33,7 @@
namespace Parallaction {
#define MAX_PASSWORD_LENGTH 7
-
+/*
#define QUESTION_BALLOON_X 140
#define QUESTION_BALLOON_Y 10
#define QUESTION_CHARACTER_X 190
@@ -41,6 +41,25 @@ namespace Parallaction {
#define ANSWER_CHARACTER_X 10
#define ANSWER_CHARACTER_Y 80
+*/
+struct BalloonPositions {
+ Common::Point _questionBalloon;
+ Common::Point _questionChar;
+
+ Common::Point _answerChar;
+};
+
+BalloonPositions _balloonPositions_NS = {
+ Common::Point(140, 10),
+ Common::Point(190, 80),
+ Common::Point(10, 80)
+};
+
+BalloonPositions _balloonPositions_BR = {
+ Common::Point(0, 0),
+ Common::Point(380, 80),
+ Common::Point(10, 80)
+};
class DialogueManager {
@@ -78,6 +97,7 @@ class DialogueManager {
bool _isKeyDown;
uint16 _downKey;
+ BalloonPositions _ballonPos;
public:
DialogueManager(Parallaction *vm, ZonePtr z);
@@ -112,6 +132,15 @@ protected:
};
DialogueManager::DialogueManager(Parallaction *vm, ZonePtr z) : _vm(vm), _z(z) {
+ int gtype = vm->getGameType();
+ if (gtype == GType_Nippon) {
+ _ballonPos = _balloonPositions_NS;
+ } else
+ if (gtype == GType_BRA) {
+ _ballonPos = _balloonPositions_BR;
+ } else
+ error("unsupported game in DialogueManager");
+
_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;
@@ -168,16 +197,16 @@ bool DialogueManager::displayAnswers() {
if (_askPassword) {
resetPassword();
// _vm->_balloonMan->setDialogueBalloon(_q->_answers[0]->_text, 1, 3);
- int id = _vm->_gfx->setItem(_answerer, ANSWER_CHARACTER_X, ANSWER_CHARACTER_Y);
+ int id = _vm->_gfx->setItem(_answerer, _ballonPos._answerChar.x, _ballonPos._answerChar.y);
_vm->_gfx->setItemFrame(id, 0);
} else
if (_numVisAnswers == 1) {
- int id = _vm->_gfx->setItem(_answerer, ANSWER_CHARACTER_X, ANSWER_CHARACTER_Y);
+ int id = _vm->_gfx->setItem(_answerer, _ballonPos._answerChar.x, _ballonPos._answerChar.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);
+ int id = _vm->_gfx->setItem(_answerer, _ballonPos._answerChar.x, _ballonPos._answerChar.y);
_vm->_gfx->setItemFrame(id, _q->_answers[_visAnswers[0]]->_mood & 0xF);
_oldSelection = -1;
_selection = 0;
@@ -189,8 +218,8 @@ bool DialogueManager::displayAnswers() {
bool DialogueManager::displayQuestion() {
if (!scumm_stricmp(_q->_text, "NULL")) return false;
- _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->_balloonMan->setSingleBalloon(_q->_text, _ballonPos._questionBalloon.x, _ballonPos._questionBalloon.y, _q->_mood & 0x10, 0);
+ int id = _vm->_gfx->setItem(_questioner, _ballonPos._questionChar.x, _ballonPos._questionChar.y);
_vm->_gfx->setItemFrame(id, _q->_mood & 0xF);
return true;
@@ -359,9 +388,6 @@ void DialogueManager::run() {
break;
case DIALOGUE_OVER:
- if (_cmdList) {
- _vm->_cmdExec->run(*_cmdList);
- }
break;
default:
@@ -381,6 +407,10 @@ void Parallaction::exitDialogueMode() {
debugC(1, kDebugDialogue, "Parallaction::exitDialogueMode()");
_input->_inputMode = Input::kInputModeGame;
+ if (_dialogueMan->_cmdList) {
+ _vm->_cmdExec->run(*_dialogueMan->_cmdList);
+ }
+
// 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).
diff --git a/engines/parallaction/disk.h b/engines/parallaction/disk.h
index 694d4efa6d..ee393afd6a 100644
--- a/engines/parallaction/disk.h
+++ b/engines/parallaction/disk.h
@@ -28,6 +28,8 @@
#define PATH_LEN 200
+#include "common/fs.h"
+
#include "common/file.h"
#include "graphics/surface.h"
@@ -202,15 +204,29 @@ public:
class DosDisk_br : public Disk {
protected:
+ uint16 _language;
+
Parallaction *_vm;
- char _partPath[PATH_LEN];
- char _languageDir[2];
+
+ FilesystemNode _baseDir;
+ FilesystemNode _partDir;
+
+ FilesystemNode _aniDir;
+ FilesystemNode _bkgDir;
+ FilesystemNode _mscDir;
+ FilesystemNode _mskDir;
+ FilesystemNode _pthDir;
+ FilesystemNode _rasDir;
+ FilesystemNode _scrDir;
+ FilesystemNode _sfxDir;
+ FilesystemNode _talDir;
protected:
- void errorFileNotFound(const char *s);
+ void errorFileNotFound(const FilesystemNode &dir, const Common::String &filename);
Font *createFont(const char *name, Common::ReadStream &stream);
Sprites* createSprites(Common::ReadStream &stream);
void loadBitmap(Common::SeekableReadStream &stream, Graphics::Surface &surf, byte *palette);
+ GfxObj* createInventoryObjects(Common::SeekableReadStream &stream);
public:
DosDisk_br(Parallaction *vm);
@@ -234,15 +250,34 @@ public:
Common::ReadStream* loadSound(const char* name);
};
+class DosDemo_br : public DosDisk_br {
+
+public:
+ DosDemo_br(Parallaction *vm);
+ virtual ~DosDemo_br();
+
+ Common::String selectArchive(const Common::String& name);
+
+};
+
class AmigaDisk_br : public DosDisk_br {
protected:
BackgroundInfo _backgroundTemp;
- Sprites* createSprites(const char *name);
+ Sprites* createSprites(Common::ReadStream &stream);
Font *createFont(const char *name, Common::SeekableReadStream &stream);
- void loadMask(BackgroundInfo& info, const char *name);
- void loadBackground(BackgroundInfo& info, const char *name);
+ void loadMask(BackgroundInfo& info, Common::SeekableReadStream &stream);
+ void loadBackground(BackgroundInfo& info, Common::SeekableReadStream &stream);
+
+ FilesystemNode _baseBkgDir;
+ FilesystemNode _fntDir;
+ FilesystemNode _commonAniDir;
+ FilesystemNode _commonBkgDir;
+ FilesystemNode _commonMscDir;
+ FilesystemNode _commonMskDir;
+ FilesystemNode _commonPthDir;
+ FilesystemNode _commonTalDir;
public:
AmigaDisk_br(Parallaction *vm);
@@ -254,6 +289,11 @@ public:
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);
+ GfxObj* loadObjects(const char *name);
+ Common::SeekableReadStream* loadMusic(const char* name);
+ Common::ReadStream* loadSound(const char* name);
+ Common::String selectArchive(const Common::String& name);
+
};
} // namespace Parallaction
diff --git a/engines/parallaction/disk_br.cpp b/engines/parallaction/disk_br.cpp
index ee1e111139..2285c5608e 100644
--- a/engines/parallaction/disk_br.cpp
+++ b/engines/parallaction/disk_br.cpp
@@ -25,6 +25,7 @@
#include "graphics/iff.h"
+#include "common/config-manager.h"
#include "parallaction/parallaction.h"
@@ -90,49 +91,40 @@ struct Sprites : public Frames {
-void DosDisk_br::errorFileNotFound(const char *s) {
- error("File '%s' not found", s);
+void DosDisk_br::errorFileNotFound(const FilesystemNode &dir, const Common::String &filename) {
+ error("File '%s' not found in directory '%s'", filename.c_str(), dir.getDisplayName().c_str());
}
Common::String DosDisk_br::selectArchive(const Common::String& name) {
debugC(5, kDebugDisk, "DosDisk_br::selectArchive");
- Common::String oldPath(_partPath);
- strcpy(_partPath, name.c_str());
+ Common::String oldPath;
+ if (_partDir.exists()) {
+ oldPath = _partDir.getDisplayName();
+ }
+
+ _partDir = _baseDir.getChild(name);
+
+ _aniDir = _partDir.getChild("ani");
+ _bkgDir = _partDir.getChild("bkg");
+ _mscDir = _partDir.getChild("msc");
+ _mskDir = _partDir.getChild("msk");
+ _pthDir = _partDir.getChild("pth");
+ _rasDir = _partDir.getChild("ras");
+ _scrDir = _partDir.getChild("scripts");
+ _sfxDir = _partDir.getChild("sfx");
+ _talDir = _partDir.getChild("tal");
return oldPath;
}
void DosDisk_br::setLanguage(uint16 language) {
debugC(5, kDebugDisk, "DosDisk_br::setLanguage");
-
- switch (language) {
- case 0:
- strcpy(_languageDir, "it");
- break;
-
- case 1:
- strcpy(_languageDir, "fr");
- break;
-
- case 2:
- strcpy(_languageDir, "en");
- break;
-
- case 3:
- strcpy(_languageDir, "ge");
- break;
-
- default:
- error("unknown language");
-
- }
-
- return;
+ assert(language < 4);
+ _language = language;
}
-DosDisk_br::DosDisk_br(Parallaction* vm) : _vm(vm) {
-
+DosDisk_br::DosDisk_br(Parallaction* vm) : _vm(vm), _baseDir(ConfMan.get("path")) {
}
DosDisk_br::~DosDisk_br() {
@@ -141,45 +133,63 @@ DosDisk_br::~DosDisk_br() {
GfxObj* DosDisk_br::loadTalk(const char *name) {
debugC(5, kDebugDisk, "DosDisk_br::loadTalk(%s)", name);
- Common::File stream;
-
- char path[PATH_LEN];
- sprintf(path, "%s/tal/%s", _partPath, name);
- if (!stream.open(path)) {
- sprintf(path, "%s/tal/%s.tal", _partPath, name);
- if (!stream.open(path))
- errorFileNotFound(path);
+ Common::String path(name);
+ FilesystemNode node = _talDir.getChild(path);
+ if (!node.exists()) {
+ path += ".tal";
+ node = _talDir.getChild(path);
+ if (!node.exists())
+ errorFileNotFound(_talDir, path);
}
- return new GfxObj(0, createSprites(stream), name);
+ Common::File stream;
+ stream.open(node);
+
+ // talk position is set to (0,0), because talks are always displayed at
+ // absolute coordinates, set in the dialogue manager. The original used
+ // to null out coordinates every time they were needed. We do it better!
+ Sprites *spr = createSprites(stream);
+ for (int i = 0; i < spr->getNum(); i++) {
+ spr->_sprites[i].x = 0;
+ spr->_sprites[i].y = 0;
+ }
+ return new GfxObj(0, spr, name);
}
Script* DosDisk_br::loadLocation(const char *name) {
debugC(5, kDebugDisk, "DosDisk_br::loadLocation");
- Common::File *stream = new Common::File;
-
- char path[PATH_LEN];
- sprintf(path, "%s/%s/%s.slf", _partPath, _languageDir, name);
- if (!stream->open(path)) {
- sprintf(path, "%s/%s/%s.loc", _partPath, _languageDir, name);
- if (!stream->open(path))
- errorFileNotFound(path);
+ Common::String langs[4] = { "it", "fr", "en", "ge" };
+ FilesystemNode locDir = _partDir.getChild(langs[_language]);
+
+ Common::String path(name);
+ path += ".slf";
+ FilesystemNode node = locDir.getChild(path);
+ if (!node.exists()) {
+ path = Common::String(name) + ".loc";
+ node = locDir.getChild(path);
+ if (!node.exists()) {
+ errorFileNotFound(locDir, path);
+ }
}
+ Common::File *stream = new Common::File;
+ stream->open(node);
return new Script(stream, true);
}
Script* DosDisk_br::loadScript(const char* name) {
debugC(5, kDebugDisk, "DosDisk_br::loadScript");
- Common::File *stream = new Common::File;
-
- char path[PATH_LEN];
- sprintf(path, "%s/scripts/%s.scr", _partPath, name);
- if (!stream->open(path))
- errorFileNotFound(path);
+ Common::String path(name);
+ path += ".scr";
+ FilesystemNode node = _scrDir.getChild(path);
+ if (!node.exists()) {
+ errorFileNotFound(_scrDir, path);
+ }
+ Common::File *stream = new Common::File;
+ stream->open(node);
return new Script(stream, true);
}
@@ -192,6 +202,7 @@ GfxObj* DosDisk_br::loadHead(const char* name) {
void DosDisk_br::loadBitmap(Common::SeekableReadStream &stream, Graphics::Surface &surf, byte *palette) {
stream.skip(4);
uint width = stream.readUint32BE();
+ if (width & 1) width++;
uint height = stream.readUint32BE();
stream.skip(20);
@@ -208,12 +219,15 @@ void DosDisk_br::loadBitmap(Common::SeekableReadStream &stream, Graphics::Surfac
Frames* DosDisk_br::loadPointer(const char *name) {
debugC(5, kDebugDisk, "DosDisk_br::loadPointer");
- char path[PATH_LEN];
- sprintf(path, "%s.ras", name);
+ Common::String path(name);
+ path += ".ras";
+ FilesystemNode node = _baseDir.getChild(path);
+ if (!node.exists()) {
+ errorFileNotFound(_baseDir, path);
+ }
Common::File stream;
- if (!stream.open(path))
- errorFileNotFound(path);
+ stream.open(node);
Graphics::Surface *surf = new Graphics::Surface;
loadBitmap(stream, *surf, 0);
@@ -224,20 +238,32 @@ Frames* DosDisk_br::loadPointer(const char *name) {
Font* DosDisk_br::loadFont(const char* name) {
debugC(5, kDebugDisk, "DosDisk_br::loadFont");
- char path[PATH_LEN];
- sprintf(path, "%s.fnt", name);
+ Common::String path(name);
+ path += ".fnt";
+ FilesystemNode node = _baseDir.getChild(path);
+ if (!node.exists()) {
+ errorFileNotFound(_baseDir, path);
+ }
Common::File stream;
- if (!stream.open(path))
- errorFileNotFound(path);
-
+ stream.open(node);
return createFont(name, stream);
}
GfxObj* DosDisk_br::loadObjects(const char *name) {
debugC(5, kDebugDisk, "DosDisk_br::loadObjects");
- return 0;
+
+ Common::String path(name);
+ FilesystemNode node = _partDir.getChild(path);
+ if (!node.exists()) {
+ errorFileNotFound(_partDir, path);
+ }
+
+ Common::File stream;
+ stream.open(node);
+
+ return createInventoryObjects(stream);
}
void genSlidePath(char *path, const char* name) {
@@ -247,13 +273,15 @@ void genSlidePath(char *path, const char* name) {
GfxObj* DosDisk_br::loadStatic(const char* name) {
debugC(5, kDebugDisk, "DosDisk_br::loadStatic");
- char path[PATH_LEN];
- sprintf(path, "%s/ras/%s", _partPath, name);
- Common::File stream;
- if (!stream.open(path)) {
- errorFileNotFound(path);
+ Common::String path(name);
+ FilesystemNode node = _rasDir.getChild(path);
+ if (!node.exists()) {
+ errorFileNotFound(_rasDir, path);
}
+ Common::File stream;
+ stream.open(node);
+
Graphics::Surface *surf = new Graphics::Surface;
loadBitmap(stream, *surf, 0);
return new GfxObj(0, new SurfaceToFrames(surf), name);
@@ -283,17 +311,18 @@ Sprites* DosDisk_br::createSprites(Common::ReadStream &stream) {
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)) {
- sprintf(path, "%s/ani/%s.ani", _partPath, name);
- if (!stream.open(path)) {
- errorFileNotFound(path);
+ Common::String path(name);
+ FilesystemNode node = _aniDir.getChild(path);
+ if (!node.exists()) {
+ path += ".ani";
+ node = _aniDir.getChild(path);
+ if (!node.exists()) {
+ errorFileNotFound(_aniDir, path);
}
}
+ Common::File stream;
+ stream.open(node);
return createSprites(stream);
}
@@ -305,12 +334,15 @@ Frames* DosDisk_br::loadFrames(const char* name) {
void DosDisk_br::loadSlide(BackgroundInfo& info, const char *name) {
debugC(5, kDebugDisk, "DosDisk_br::loadSlide");
- char path[PATH_LEN];
- genSlidePath(path, name);
+ Common::String path(name);
+ path += ".bmp";
+ FilesystemNode node = _baseDir.getChild(path);
+ if (!node.exists()) {
+ errorFileNotFound(_baseDir, path);
+ }
Common::File stream;
- if (!stream.open(path))
- errorFileNotFound(path);
+ stream.open(node);
byte rgb[768];
@@ -328,13 +360,17 @@ void DosDisk_br::loadSlide(BackgroundInfo& info, const char *name) {
void DosDisk_br::loadScenery(BackgroundInfo& info, const char *name, const char *mask, const char* path) {
debugC(5, kDebugDisk, "DosDisk_br::loadScenery");
- char filename[PATH_LEN];
+ Common::String filepath;
+ FilesystemNode node;
Common::File stream;
if (name) {
- sprintf(filename, "%s/bkg/%s.bkg", _partPath, name);
- if (!stream.open(filename))
- errorFileNotFound(filename);
+ filepath = Common::String(name) + ".bkg";
+ node = _bkgDir.getChild(filepath);
+ if (!node.exists()) {
+ errorFileNotFound(_bkgDir, filepath);
+ }
+ stream.open(node);
byte rgb[768];
@@ -350,9 +386,12 @@ void DosDisk_br::loadScenery(BackgroundInfo& info, const char *name, const char
}
if (mask) {
- sprintf(filename, "%s/msk/%s.msk", _partPath, mask);
- if (!stream.open(filename))
- errorFileNotFound(filename);
+ filepath = Common::String(mask) + ".msk";
+ node = _mskDir.getChild(filepath);
+ if (!node.exists()) {
+ errorFileNotFound(_mskDir, filepath);
+ }
+ stream.open(node);
// NOTE: info.width and info.height are only valid if the background graphics
// have already been loaded
@@ -363,9 +402,12 @@ void DosDisk_br::loadScenery(BackgroundInfo& info, const char *name, const char
}
if (path) {
- sprintf(filename, "%s/pth/%s.pth", _partPath, path);
- if (!stream.open(filename))
- errorFileNotFound(filename);
+ filepath = Common::String(path) + ".pth";
+ node = _pthDir.getChild(filepath);
+ if (!node.exists()) {
+ errorFileNotFound(_pthDir, filepath);
+ }
+ stream.open(node);
// NOTE: info.width and info.height are only valid if the background graphics
// have already been loaded
@@ -380,15 +422,16 @@ void DosDisk_br::loadScenery(BackgroundInfo& info, const char *name, const char
Table* DosDisk_br::loadTable(const char* name) {
debugC(5, kDebugDisk, "DosDisk_br::loadTable");
- char path[PATH_LEN];
- sprintf(path, "%s/%s.tab", _partPath, name);
-
- Common::File stream;
- if (!stream.open(path))
- errorFileNotFound(path);
+ Common::String path(name);
+ path += ".tab";
+ FilesystemNode node = _partDir.getChild(path);
+ if (!node.exists()) {
+ errorFileNotFound(_partDir, path);
+ }
+ Common::File stream;
+ stream.open(node);
Table *t = createTableFromStream(100, stream);
-
stream.close();
return t;
@@ -410,8 +453,55 @@ Common::ReadStream* DosDisk_br::loadSound(const char* name) {
+DosDemo_br::DosDemo_br(Parallaction *vm) : DosDisk_br(vm) {
+
+}
+
+
+DosDemo_br::~DosDemo_br() {
+
+}
+
+Common::String DosDemo_br::selectArchive(const Common::String& name) {
+ debugC(5, kDebugDisk, "DosDemo_br::selectArchive");
+
+ Common::String oldPath;
+ if (_partDir.exists()) {
+ oldPath = _partDir.getDisplayName();
+ }
+
+ _partDir = _baseDir;
+
+ _aniDir = _partDir.getChild("ani");
+ _bkgDir = _partDir.getChild("bkg");
+ _mscDir = _partDir.getChild("msc");
+ _mskDir = _partDir.getChild("msk");
+ _pthDir = _partDir.getChild("pth");
+ _rasDir = _partDir.getChild("ras");
+ _scrDir = _partDir.getChild("scripts");
+ _sfxDir = _partDir.getChild("sfx");
+ _talDir = _partDir.getChild("tal");
+
+ return oldPath;
+}
+
+
+
+
+
+
AmigaDisk_br::AmigaDisk_br(Parallaction *vm) : DosDisk_br(vm) {
+ _fntDir = _baseDir.getChild("fonts");
+ _baseBkgDir = _baseDir.getChild("backs");
+
+ FilesystemNode commonDir = _baseDir.getChild("common");
+ _commonAniDir = commonDir.getChild("anims");
+ _commonBkgDir = commonDir.getChild("backs");
+ _commonMscDir = commonDir.getChild("msc");
+ _commonMskDir = commonDir.getChild("msk");
+ _commonPthDir = commonDir.getChild("pth");
+ _commonTalDir = commonDir.getChild("talks");
}
@@ -447,19 +537,11 @@ void buildMask2(byte* buf) {
}
}
-void AmigaDisk_br::loadBackground(BackgroundInfo& info, const char *name) {
-
- char path[PATH_LEN];
- sprintf(path, "%s", name);
-
- Common::File s;
-
- if (!s.open(path))
- errorFileNotFound(path);
+void AmigaDisk_br::loadBackground(BackgroundInfo& info, Common::SeekableReadStream &stream) {
byte *pal;
- Graphics::ILBMDecoder decoder(s, info.bg, pal);
+ Graphics::ILBMDecoder decoder(stream, info.bg, pal);
decoder.decode();
uint i;
@@ -483,30 +565,23 @@ void AmigaDisk_br::loadBackground(BackgroundInfo& info, const char *name) {
return;
}
-void AmigaDisk_br::loadMask(BackgroundInfo& info, const char *name) {
- debugC(5, kDebugDisk, "AmigaDisk_br::loadMask(%s)", name);
-
- Common::File s;
-
- if (!s.open(name))
- return;
-
- s.seek(0x30, SEEK_SET);
+void AmigaDisk_br::loadMask(BackgroundInfo& info, Common::SeekableReadStream &stream) {
+ stream.seek(0x30, SEEK_SET);
byte r, g, b;
for (uint i = 0; i < 4; i++) {
- r = s.readByte();
- g = s.readByte();
- b = s.readByte();
+ r = stream.readByte();
+ g = stream.readByte();
+ b = stream.readByte();
info.layers[i] = (((r << 4) & 0xF00) | (g & 0xF0) | (b >> 4)) & 0xFF;
}
- s.seek(0x126, SEEK_SET); // HACK: skipping IFF/ILBM header should be done by analysis, not magic
- Graphics::PackBitsReadStream stream(s);
+ stream.seek(0x126, SEEK_SET); // HACK: skipping IFF/ILBM header should be done by analysis, not magic
+ Graphics::PackBitsReadStream unpackedStream(stream);
info.mask.create(info.width, info.height);
- stream.read(info.mask.data, info.mask.size);
+ unpackedStream.read(info.mask.data, info.mask.size);
buildMask2(info.mask.data);
return;
@@ -515,26 +590,51 @@ void AmigaDisk_br::loadMask(BackgroundInfo& info, const char *name) {
void AmigaDisk_br::loadScenery(BackgroundInfo& info, const char* name, const char* mask, const char* path) {
debugC(1, kDebugDisk, "AmigaDisk_br::loadScenery '%s', '%s' '%s'", name, mask, path);
- char filename[PATH_LEN];
+ Common::String filepath;
+ FilesystemNode node;
Common::File stream;
if (name) {
- sprintf(filename, "%s/backs/%s.bkg", _partPath, name);
-
- loadBackground(info, filename);
+ filepath = Common::String(name) + ".bkg";
+ node = _bkgDir.getChild(filepath);
+ if (!node.exists()) {
+ filepath = Common::String(name) + ".bkg";
+ node = _commonBkgDir.getChild(filepath);
+ if (!node.exists()) {
+ errorFileNotFound(_bkgDir, filepath);
+ }
+ }
+ stream.open(node);
+ loadBackground(info, stream);
+ stream.close();
}
- if (mask) {
- sprintf(filename, "%s/msk/%s.msk", _partPath, name);
+ if (mask && _mskDir.exists()) {
+ filepath = Common::String(mask) + ".msk";
+ node = _mskDir.getChild(filepath);
+ if (!node.exists()) {
+ filepath = Common::String(mask) + ".msk";
+ node = _commonMskDir.getChild(filepath);
+ }
- loadMask(info, filename);
+ if (node.exists()) {
+ stream.open(node);
+ loadMask(info, stream);
+ stream.close();
+ }
}
- if (path) {
- sprintf(filename, "%s/pth/%s.pth", _partPath, path);
- if (!stream.open(filename))
- errorFileNotFound(filename);
-
+ if (path && _pthDir.exists()) {
+ filepath = Common::String(path) + ".pth";
+ node = _pthDir.getChild(filepath);
+ if (!node.exists()) {
+ filepath = Common::String(path) + ".pth";
+ node = _commonPthDir.getChild(filepath);
+ if (!node.exists()) {
+ errorFileNotFound(_pthDir, filepath);
+ }
+ }
+ stream.open(node);
// NOTE: info.width and info.height are only valid if the background graphics
// have already been loaded
info.path.create(info.width, info.height);
@@ -548,22 +648,28 @@ void AmigaDisk_br::loadScenery(BackgroundInfo& info, const char* name, const cha
void AmigaDisk_br::loadSlide(BackgroundInfo& info, const char *name) {
debugC(1, kDebugDisk, "AmigaDisk_br::loadSlide '%s'", name);
- char path[PATH_LEN];
- sprintf(path, "backs/%s.bkg", name);
-
- loadBackground(info, path);
+ Common::String path(name);
+ path += ".bkg";
+ FilesystemNode node = _baseBkgDir.getChild(path);
+ if (!node.exists()) {
+ errorFileNotFound(_baseBkgDir, path);
+ }
+ Common::File stream;
+ stream.open(node);
+ loadBackground(info, stream);
return;
}
GfxObj* AmigaDisk_br::loadStatic(const char* name) {
debugC(1, kDebugDisk, "AmigaDisk_br::loadStatic '%s'", name);
- char path[PATH_LEN];
- sprintf(path, "%s/ras/%s", _partPath, name);
- Common::File stream;
- if (!stream.open(path)) {
- errorFileNotFound(path);
+ Common::String path(name);
+ FilesystemNode node = _rasDir.getChild(path);
+ if (!node.exists()) {
+ errorFileNotFound(_rasDir, path);
}
+ Common::File stream;
+ stream.open(node);
byte *pal = 0;
Graphics::Surface* surf = new Graphics::Surface;
@@ -576,13 +682,7 @@ GfxObj* AmigaDisk_br::loadStatic(const char* name) {
return new GfxObj(0, new SurfaceToFrames(surf));
}
-Sprites* AmigaDisk_br::createSprites(const char *path) {
-
- Common::File stream;
- if (!stream.open(path)) {
- errorFileNotFound(path);
- }
-
+Sprites* AmigaDisk_br::createSprites(Common::ReadStream &stream) {
uint16 num = stream.readUint16BE();
Sprites *sprites = new Sprites(num);
@@ -606,32 +706,165 @@ Sprites* AmigaDisk_br::createSprites(const char *path) {
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);
+ Common::String path(name);
+ FilesystemNode node = _aniDir.getChild(path);
+ if (!node.exists()) {
+ path += ".ani";
+ node = _aniDir.getChild(path);
+ if (!node.exists()) {
+ path = Common::String(name);
+ node = _commonAniDir.getChild(path);
+ if (!node.exists()) {
+ path += ".ani";
+ node = _commonAniDir.getChild(path);
+ if (!node.exists()) {
+ errorFileNotFound(_aniDir, path);
+ }
+ }
+ }
+ }
- return createSprites(path);
+ Common::File stream;
+ stream.open(node);
+ return createSprites(stream);
}
GfxObj* AmigaDisk_br::loadTalk(const char *name) {
debugC(1, kDebugDisk, "AmigaDisk_br::loadTalk '%s'", name);
- char path[PATH_LEN];
- sprintf(path, "%s/talks/%s.tal", _partPath, name);
+ Common::String path(name);
+ FilesystemNode node = _talDir.getChild(path);
+ if (!node.exists()) {
+ path += ".tal";
+ node = _talDir.getChild(path);
+ if (!node.exists()) {
+ path = Common::String(name);
+ node = _commonTalDir.getChild(path);
+ if (!node.exists()) {
+ path += ".tal";
+ node = _commonTalDir.getChild(path);
+ if (!node.exists()) {
+ errorFileNotFound(_talDir, path);
+ }
+ }
+ }
+ }
- return new GfxObj(0, createSprites(path));
+ Common::File stream;
+ stream.open(node);
+ return new GfxObj(0, createSprites(stream));
}
Font* AmigaDisk_br::loadFont(const char* name) {
debugC(1, kDebugDisk, "AmigaFullDisk::loadFont '%s'", name);
- char path[PATH_LEN];
- sprintf(path, "%s", name);
+ Common::String path(name);
+ path += ".font";
+ FilesystemNode node = _fntDir.getChild(path);
+ if (!node.exists()) {
+ errorFileNotFound(_fntDir, path);
+ }
+
+ Common::String fontDir;
+ Common::String fontFile;
+ byte ch;
Common::File stream;
- if (!stream.open(path))
- errorFileNotFound(path);
+ stream.open(node);
+ stream.seek(4, SEEK_SET);
+ while ((ch = stream.readByte()) != 0x2F) fontDir += ch;
+ while ((ch = stream.readByte()) != 0) fontFile += ch;
+ stream.close();
+ printf("fontDir = %s, fontFile = %s\n", fontDir.c_str(), fontFile.c_str());
+
+ node = _fntDir.getChild(fontDir);
+ if (!node.exists()) {
+ errorFileNotFound(_fntDir, fontDir);
+ }
+ node = node.getChild(fontFile);
+ if (!node.exists()) {
+ errorFileNotFound(node, fontFile);
+ }
+
+ stream.open(node);
return createFont(name, stream);
}
+Common::SeekableReadStream* AmigaDisk_br::loadMusic(const char* name) {
+ debugC(5, kDebugDisk, "AmigaDisk_br::loadMusic");
+
+ Common::String path(name);
+ FilesystemNode node = _mscDir.getChild(path);
+ if (!node.exists()) {
+ // TODO (Kirben): error out when music file is not found?
+ return 0;
+ }
+
+ Common::File *stream = new Common::File;
+ stream->open(node);
+ return stream;
+}
+
+
+Common::ReadStream* AmigaDisk_br::loadSound(const char* name) {
+ debugC(5, kDebugDisk, "AmigaDisk_br::loadSound");
+
+ Common::String path(name);
+ FilesystemNode node = _sfxDir.getChild(path);
+ if (!node.exists()) {
+ errorFileNotFound(_sfxDir, path);
+ }
+
+ Common::File *stream = new Common::File;
+ stream->open(node);
+ return stream;
+}
+
+GfxObj* AmigaDisk_br::loadObjects(const char *name) {
+ debugC(5, kDebugDisk, "AmigaDisk_br::loadObjects");
+
+ Common::String path(name);
+ FilesystemNode node = _partDir.getChild(path);
+ if (!node.exists()) {
+ errorFileNotFound(_partDir, path);
+ }
+
+ Common::File stream;
+ stream.open(node);
+
+ byte *pal = 0;
+ Graphics::Surface* surf = new Graphics::Surface;
+
+ Graphics::ILBMDecoder decoder(stream, *surf, pal);
+ decoder.decode();
+
+ free(pal);
+
+ return new GfxObj(0, new SurfaceToFrames(surf));
+}
+
+Common::String AmigaDisk_br::selectArchive(const Common::String& name) {
+ debugC(5, kDebugDisk, "AmigaDisk_br::selectArchive");
+
+ Common::String oldPath;
+ if (_partDir.exists()) {
+ oldPath = _partDir.getDisplayName();
+ }
+
+ _partDir = _baseDir.getChild(name);
+
+ _aniDir = _partDir.getChild("anims");
+ _bkgDir = _partDir.getChild("backs");
+ _mscDir = _partDir.getChild("msc");
+ _mskDir = _partDir.getChild("msk");
+ _pthDir = _partDir.getChild("pth");
+ _rasDir = _partDir.getChild("ras");
+ _scrDir = _partDir.getChild("scripts");
+ _sfxDir = _partDir.getChild("sfx");
+ _talDir = _partDir.getChild("talks");
+
+ return oldPath;
+}
+
} // namespace Parallaction
diff --git a/engines/parallaction/exec.h b/engines/parallaction/exec.h
index 887d6be526..22e75744f1 100644
--- a/engines/parallaction/exec.h
+++ b/engines/parallaction/exec.h
@@ -47,14 +47,30 @@ protected:
struct ParallactionStruct1 {
CommandPtr cmd;
ZonePtr z;
+ bool suspend;
} _ctxt;
OpcodeSet _opcodes;
+ struct SuspendedContext {
+ bool valid;
+ CommandList::iterator first;
+ CommandList::iterator last;
+ ZonePtr zone;
+ } _suspendedCtxt;
+
+ ZonePtr _execZone;
+ void runList(CommandList::iterator first, CommandList::iterator last);
+ void createSuspendList(CommandList::iterator first, CommandList::iterator last);
+ void cleanSuspendedList();
+
public:
virtual void init() = 0;
virtual void run(CommandList &list, ZonePtr z = nullZonePtr);
+ void runSuspended();
+
CommandExec() {
+ _suspendedCtxt.valid = false;
}
virtual ~CommandExec() {
for (Common::Array<const Opcode*>::iterator i = _opcodes.begin(); i != _opcodes.end(); ++i)
@@ -143,23 +159,23 @@ public:
~CommandExec_br();
};
-
-
-
-
class ProgramExec {
protected:
struct ParallactionStruct2 {
AnimationPtr anim;
ProgramPtr program;
InstructionList::iterator inst;
+ InstructionList::iterator ip;
uint16 modCounter;
bool suspend;
} _ctxt;
+ const char **_instructionNames;
+
OpcodeSet _opcodes;
uint16 _modCounter;
+ void runScript(ProgramPtr script, AnimationPtr a);
public:
virtual void init() = 0;
@@ -183,7 +199,7 @@ protected:
DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(off);
DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(loop);
DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(endloop);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(null);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(show);
DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(call);
DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(inc);
DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(set);
@@ -208,7 +224,6 @@ class ProgramExec_br : public ProgramExec_ns {
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);
@@ -228,7 +243,6 @@ protected:
DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(ifgt);
DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(endif);
DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(stop);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(endscript);
public:
void init();
diff --git a/engines/parallaction/exec_br.cpp b/engines/parallaction/exec_br.cpp
index edb832cffc..0b7400f0f7 100644
--- a/engines/parallaction/exec_br.cpp
+++ b/engines/parallaction/exec_br.cpp
@@ -61,8 +61,6 @@ namespace Parallaction {
#define INST_STOP 30
#define INST_ENDSCRIPT 31
-
-
#define SetOpcodeTable(x) table = &x;
typedef Common::Functor0Mem<void, CommandExec_br> OpcodeV1;
@@ -73,6 +71,8 @@ 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()
+extern const char *_instructionNamesRes_br[];
+
void Parallaction_br::setupSubtitles(char *s, char *s2, int y) {
debugC(5, kDebugExec, "setupSubtitles(%s, %s, %i)", s, s2, y);
@@ -122,11 +122,19 @@ DECLARE_COMMAND_OPCODE(location) {
DECLARE_COMMAND_OPCODE(open) {
warning("Parallaction_br::cmdOp_open command not yet implemented");
+ _ctxt.cmd->u._zone->_flags &= ~kFlagsClosed;
+ if (_ctxt.cmd->u._zone->u.door->gfxobj) {
+ _vm->updateDoor(_ctxt.cmd->u._zone);
+ }
}
DECLARE_COMMAND_OPCODE(close) {
warning("Parallaction_br::cmdOp_close not yet implemented");
+ _ctxt.cmd->u._zone->_flags |= kFlagsClosed;
+ if (_ctxt.cmd->u._zone->u.door->gfxobj) {
+ _vm->updateDoor(_ctxt.cmd->u._zone);
+ }
}
@@ -165,12 +173,13 @@ DECLARE_COMMAND_OPCODE(call) {
DECLARE_COMMAND_OPCODE(drop) {
- warning("Parallaction_br::cmdOp_drop not yet implemented");
+ _vm->dropItem(_ctxt.cmd->u._object);
}
DECLARE_COMMAND_OPCODE(move) {
- warning("Parallaction_br::cmdOp_move not yet implemented");
+ _vm->_char.scheduleWalk(_ctxt.cmd->u._move.x, _ctxt.cmd->u._move.y);
+ _ctxt.suspend = true;
}
DECLARE_COMMAND_OPCODE(start) {
@@ -194,17 +203,17 @@ DECLARE_COMMAND_OPCODE(followme) {
DECLARE_COMMAND_OPCODE(onmouse) {
- _vm->_input->showCursor(true);
+ _vm->_input->setMouseState(MOUSE_ENABLED_SHOW);
}
DECLARE_COMMAND_OPCODE(offmouse) {
- _vm->_input->showCursor(false);
+ _vm->_input->setMouseState(MOUSE_DISABLED);
}
DECLARE_COMMAND_OPCODE(add) {
- warning("Parallaction_br::cmdOp_add not yet implemented");
+ _vm->addInventoryItem(_ctxt.cmd->u._object);
}
@@ -365,13 +374,6 @@ DECLARE_INSTRUCTION_OPCODE(set) {
}
-DECLARE_INSTRUCTION_OPCODE(loop) {
- InstructionPtr inst = *_ctxt.inst;
-
- _ctxt.program->_loopCounter = inst->_opB.getRValue();
- _ctxt.program->_loopStart = _ctxt.inst;
-}
-
DECLARE_INSTRUCTION_OPCODE(inc) {
InstructionPtr inst = *_ctxt.inst;
@@ -495,16 +497,6 @@ DECLARE_INSTRUCTION_OPCODE(stop) {
warning("Parallaction_br::instOp_stop not yet implemented");
}
-DECLARE_INSTRUCTION_OPCODE(endscript) {
- if ((_ctxt.anim->_flags & kFlagsLooping) == 0) {
- _ctxt.anim->_flags &= ~kFlagsActing;
- _vm->_cmdExec->run(_ctxt.anim->_commands, _ctxt.anim);
- _ctxt.program->_status = kProgramDone;
- }
- _ctxt.program->_ip = _ctxt.program->_instructions.begin();
-
- _ctxt.suspend = true;
-}
void CommandExec_br::init() {
Common::Array<const Opcode*> *table = 0;
@@ -576,7 +568,7 @@ void ProgramExec_br::init() {
INSTRUCTION_OPCODE(set); // f
INSTRUCTION_OPCODE(loop);
INSTRUCTION_OPCODE(endloop);
- INSTRUCTION_OPCODE(null); // show
+ INSTRUCTION_OPCODE(show); // show
INSTRUCTION_OPCODE(inc);
INSTRUCTION_OPCODE(inc); // dec
INSTRUCTION_OPCODE(set);
@@ -602,6 +594,7 @@ void ProgramExec_br::init() {
}
ProgramExec_br::ProgramExec_br(Parallaction_br *vm) : ProgramExec_ns(vm), _vm(vm) {
+ _instructionNames = _instructionNamesRes_br;
}
ProgramExec_br::~ProgramExec_br() {
diff --git a/engines/parallaction/exec_ns.cpp b/engines/parallaction/exec_ns.cpp
index 9cde27a853..3e3ee19a03 100644
--- a/engines/parallaction/exec_ns.cpp
+++ b/engines/parallaction/exec_ns.cpp
@@ -61,7 +61,7 @@ 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()
-
+extern const char *_instructionNamesRes_ns[];
DECLARE_INSTRUCTION_OPCODE(on) {
@@ -81,13 +81,13 @@ DECLARE_INSTRUCTION_OPCODE(loop) {
InstructionPtr inst = *_ctxt.inst;
_ctxt.program->_loopCounter = inst->_opB.getRValue();
- _ctxt.program->_loopStart = _ctxt.inst;
+ _ctxt.program->_loopStart = _ctxt.ip;
}
DECLARE_INSTRUCTION_OPCODE(endloop) {
if (--_ctxt.program->_loopCounter > 0) {
- _ctxt.inst = _ctxt.program->_loopStart;
+ _ctxt.ip = _ctxt.program->_loopStart;
}
}
@@ -97,7 +97,7 @@ DECLARE_INSTRUCTION_OPCODE(inc) {
if (inst->_flags & kInstMod) { // mod
int16 _bx = (_si > 0 ? _si : -_si);
- if (_modCounter % _bx != 0) return;
+ if (_ctxt.modCounter % _bx != 0) return;
_si = (_si > 0 ? 1 : -1);
}
@@ -142,8 +142,8 @@ DECLARE_INSTRUCTION_OPCODE(put) {
_vm->_gfx->patchBackground(v18, x, y, mask);
}
-DECLARE_INSTRUCTION_OPCODE(null) {
-
+DECLARE_INSTRUCTION_OPCODE(show) {
+ _ctxt.suspend = true;
}
DECLARE_INSTRUCTION_OPCODE(invalid) {
@@ -156,8 +156,10 @@ DECLARE_INSTRUCTION_OPCODE(call) {
DECLARE_INSTRUCTION_OPCODE(wait) {
- if (_engineFlags & kEngineWalking)
+ if (_engineFlags & kEngineWalking) {
+ _ctxt.ip--;
_ctxt.suspend = true;
+ }
}
@@ -186,8 +188,8 @@ DECLARE_INSTRUCTION_OPCODE(endscript) {
_vm->_cmdExec->run(_ctxt.anim->_commands, _ctxt.anim);
_ctxt.program->_status = kProgramDone;
}
- _ctxt.program->_ip = _ctxt.program->_instructions.begin();
+ _ctxt.ip = _ctxt.program->_instructions.begin();
_ctxt.suspend = true;
}
@@ -331,35 +333,40 @@ void Parallaction_ns::drawAnimations() {
for (AnimationList::iterator it = _location._animations.begin(); it != _location._animations.end(); it++) {
- AnimationPtr v18 = *it;
- GfxObj *obj = v18->gfxobj;
+ AnimationPtr anim = *it;
+ GfxObj *obj = anim->gfxobj;
+
+ // Validation is performed here, so that every animation is affected, instead that only the ones
+ // who *own* a script. In fact, some scripts can change values in other animations.
+ // The right way to do this would be to enforce validation when any variable is modified from
+ // a script.
+ anim->validateScriptVars();
- if ((v18->_flags & kFlagsActive) && ((v18->_flags & kFlagsRemove) == 0)) {
+ if ((anim->_flags & kFlagsActive) && ((anim->_flags & kFlagsRemove) == 0)) {
- int16 frame = CLIP((int)v18->_frame, 0, v18->getFrameNum()-1);
- if (v18->_flags & kFlagsNoMasked)
+ if (anim->_flags & kFlagsNoMasked)
layer = 3;
else
- layer = _gfx->_backgroundInfo.getLayer(v18->_top + v18->height());
+ layer = _gfx->_backgroundInfo.getLayer(anim->_top + anim->height());
if (obj) {
_gfx->showGfxObj(obj, true);
- obj->frame = frame;
- obj->x = v18->_left;
- obj->y = v18->_top;
- obj->z = v18->_z;
+ obj->frame = anim->_frame;
+ obj->x = anim->_left;
+ obj->y = anim->_top;
+ obj->z = anim->_z;
obj->layer = layer;
}
}
- if (((v18->_flags & kFlagsActive) == 0) && (v18->_flags & kFlagsRemove)) {
- v18->_flags &= ~kFlagsRemove;
- v18->_oldPos.x = -1000;
+ if (((anim->_flags & kFlagsActive) == 0) && (anim->_flags & kFlagsRemove)) {
+ anim->_flags &= ~kFlagsRemove;
+ anim->_oldPos.x = -1000;
}
- if ((v18->_flags & kFlagsActive) && (v18->_flags & kFlagsRemove)) {
- v18->_flags &= ~kFlagsActive;
- v18->_flags |= kFlagsRemove;
+ if ((anim->_flags & kFlagsActive) && (anim->_flags & kFlagsRemove)) {
+ anim->_flags &= ~kFlagsActive;
+ anim->_flags |= kFlagsRemove;
if (obj) {
_gfx->showGfxObj(obj, false);
}
@@ -371,14 +378,41 @@ void Parallaction_ns::drawAnimations() {
return;
}
+void ProgramExec::runScript(ProgramPtr script, AnimationPtr a) {
+ debugC(9, kDebugExec, "runScript(Animation = %s)", a->_name);
+
+ _ctxt.ip = script->_ip;
+ _ctxt.anim = a;
+ _ctxt.program = script;
+ _ctxt.suspend = false;
+ _ctxt.modCounter = _modCounter;
+
+ InstructionList::iterator inst;
+ for ( ; (a->_flags & kFlagsActing) ; ) {
+
+ inst = _ctxt.ip;
+ _ctxt.inst = inst;
+ _ctxt.ip++;
+
+ debugC(9, kDebugExec, "inst [%02i] %s\n", (*inst)->_index, _instructionNames[(*inst)->_index - 1]);
+
+ script->_status = kProgramRunning;
+
+ (*_opcodes[(*inst)->_index])();
+
+ if (_ctxt.suspend)
+ break;
+
+ }
+ script->_ip = _ctxt.ip;
+
+}
void ProgramExec::runScripts(ProgramList::iterator first, ProgramList::iterator last) {
if (_engineFlags & kEnginePauseJobs) {
return;
}
- debugC(9, kDebugExec, "runScripts");
-
for (ProgramList::iterator it = first; it != last; it++) {
AnimationPtr a = (*it)->_anim;
@@ -389,31 +423,8 @@ void ProgramExec::runScripts(ProgramList::iterator first, ProgramList::iterator
if ((a->_flags & kFlagsActing) == 0)
continue;
- InstructionList::iterator inst = (*it)->_ip;
- while (((*inst)->_index != INST_SHOW) && (a->_flags & kFlagsActing)) {
-
- (*it)->_status = kProgramRunning;
-
- debugC(9, kDebugExec, "Animation: %s, instruction: %i", a->_name, (*inst)->_index); //_instructionNamesRes[(*inst)->_index - 1]);
-
- _ctxt.inst = inst;
- _ctxt.anim = AnimationPtr(a);
- _ctxt.program = *it;
- _ctxt.suspend = false;
-
- (*_opcodes[(*inst)->_index])();
+ runScript(*it, a);
- inst = _ctxt.inst; // handles endloop correctly
-
- if (_ctxt.suspend)
- goto label1;
-
- inst++;
- }
-
- (*it)->_ip = ++inst;
-
-label1:
if (a->_flags & kFlagsCharacter)
a->_z = a->_top + a->height();
}
@@ -423,23 +434,18 @@ label1:
return;
}
-void CommandExec::run(CommandList& list, ZonePtr z) {
- if (list.size() == 0) {
- debugC(3, kDebugExec, "runCommands: nothing to do");
- return;
- }
-
- debugC(3, kDebugExec, "runCommands starting");
+void CommandExec::runList(CommandList::iterator first, CommandList::iterator last) {
uint32 useFlags = 0;
bool useLocalFlags;
- CommandList::iterator it = list.begin();
- for ( ; it != list.end(); it++) {
+ _ctxt.suspend = false;
+
+ for ( ; first != last; first++) {
if (_engineFlags & kEngineQuit)
break;
- CommandPtr cmd = *it;
+ CommandPtr cmd = *first;
if (cmd->_flagsOn & kFlagsGlobal) {
useFlags = _commandFlags | kFlagsGlobal;
@@ -457,16 +463,65 @@ void CommandExec::run(CommandList& list, ZonePtr z) {
if (!onMatch || !offMatch) continue;
- _ctxt.z = z;
+ _ctxt.z = _execZone;
_ctxt.cmd = cmd;
(*_opcodes[cmd->_id])();
+
+ if (_ctxt.suspend) {
+ createSuspendList(++first, last);
+ return;
+ }
+ }
+
+}
+
+void CommandExec::run(CommandList& list, ZonePtr z) {
+ if (list.size() == 0) {
+ debugC(3, kDebugExec, "runCommands: nothing to do");
+ return;
}
+ _execZone = z;
+
+ debugC(3, kDebugExec, "runCommands starting");
+ runList(list.begin(), list.end());
debugC(3, kDebugExec, "runCommands completed");
+}
- return;
+void CommandExec::createSuspendList(CommandList::iterator first, CommandList::iterator last) {
+ if (first == last) {
+ return;
+ }
+
+ debugC(3, kDebugExec, "CommandExec::createSuspendList()");
+
+ _suspendedCtxt.valid = true;
+ _suspendedCtxt.first = first;
+ _suspendedCtxt.last = last;
+ _suspendedCtxt.zone = _execZone;
+}
+void CommandExec::cleanSuspendedList() {
+ debugC(3, kDebugExec, "CommandExec::cleanSuspended()");
+
+ _suspendedCtxt.valid = false;
+ _suspendedCtxt.first = _suspendedCtxt.last;
+ _suspendedCtxt.zone = nullZonePtr;
+}
+
+void CommandExec::runSuspended() {
+ if (_engineFlags & kEngineWalking) {
+ return;
+ }
+
+ if (_suspendedCtxt.valid) {
+ debugC(3, kDebugExec, "CommandExec::runSuspended()");
+
+ _execZone = _suspendedCtxt.zone;
+ runList(_suspendedCtxt.first, _suspendedCtxt.last);
+ cleanSuspendedList();
+ }
}
CommandExec_ns::CommandExec_ns(Parallaction_ns* vm) : _vm(vm) {
@@ -481,35 +536,69 @@ CommandExec_ns::~CommandExec_ns() {
// ZONE TYPE: EXAMINE
//
-void Parallaction::displayComment(ExamineData *data) {
+void Parallaction::enterCommentMode(ZonePtr z) {
+ if (!z) {
+ return;
+ }
+
+ _commentZone = z;
+
+ ExamineData *data = _commentZone->u.examine;
+
if (!data->_description) {
return;
}
- int id;
+ // TODO: move this balloons stuff into DialogueManager and BalloonManager
+ if (getGameType() == GType_Nippon) {
+ int id;
+ if (data->_filename) {
+ if (data->_cnv == 0) {
+ data->_cnv = _disk->loadStatic(data->_filename);
+ }
- if (data->_filename) {
- if (data->_cnv == 0) {
- data->_cnv = _disk->loadStatic(data->_filename);
+ _gfx->setHalfbriteMode(true);
+ _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);
+ _gfx->setItemFrame(id, 0);
+ id = _gfx->setItem(_char._head, 100, 152);
+ _gfx->setItemFrame(id, 0);
+ } else {
+ _balloonMan->setSingleBalloon(data->_description, 140, 10, 0, 0);
+ id = _gfx->setItem(_char._talk, 190, 80);
+ _gfx->setItemFrame(id, 0);
}
-
- _gfx->setHalfbriteMode(true);
- _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);
- _gfx->setItemFrame(id, 0);
- id = _gfx->setItem(_char._head, 100, 152);
- _gfx->setItemFrame(id, 0);
- } else {
- _balloonMan->setSingleBalloon(data->_description, 140, 10, 0, 0);
- id = _gfx->setItem(_char._talk, 190, 80);
+ } else
+ if (getGameType() == GType_BRA) {
+ _balloonMan->setSingleBalloon(data->_description, 0, 0, 1, 0);
+ int id = _gfx->setItem(_char._talk, 10, 80);
_gfx->setItemFrame(id, 0);
}
_input->_inputMode = Input::kInputModeComment;
}
+void Parallaction::exitCommentMode() {
+ _input->_inputMode = Input::kInputModeGame;
+
+ hideDialogueStuff();
+ _gfx->setHalfbriteMode(false);
+
+ _cmdExec->run(_commentZone->_commands, _commentZone);
+ _commentZone = nullZonePtr;
+}
+
+void Parallaction::runCommentFrame() {
+ if (_input->_inputMode != Input::kInputModeComment) {
+ return;
+ }
+
+ if (_input->getLastButtonEvent() == kMouseLeftUp) {
+ exitCommentMode();
+ }
+}
uint16 Parallaction::runZone(ZonePtr z) {
@@ -521,8 +610,8 @@ uint16 Parallaction::runZone(ZonePtr z) {
switch(subtype) {
case kZoneExamine:
- displayComment(z->u.examine);
- break;
+ enterCommentMode(z);
+ return 0;
case kZoneGet:
if (z->_flags & kFlagsFixed) break;
@@ -713,7 +802,7 @@ void ProgramExec_ns::init() {
INSTRUCTION_OPCODE(set); // f
INSTRUCTION_OPCODE(loop);
INSTRUCTION_OPCODE(endloop);
- INSTRUCTION_OPCODE(null);
+ INSTRUCTION_OPCODE(show);
INSTRUCTION_OPCODE(inc);
INSTRUCTION_OPCODE(inc); // dec
INSTRUCTION_OPCODE(set);
@@ -728,6 +817,7 @@ void ProgramExec_ns::init() {
}
ProgramExec_ns::ProgramExec_ns(Parallaction_ns *vm) : _vm(vm) {
+ _instructionNames = _instructionNamesRes_ns;
}
ProgramExec_ns::~ProgramExec_ns() {
diff --git a/engines/parallaction/font.cpp b/engines/parallaction/font.cpp
index 91848b30a4..2a379828ae 100644
--- a/engines/parallaction/font.cpp
+++ b/engines/parallaction/font.cpp
@@ -35,6 +35,7 @@ extern byte _amigaTopazFont[];
class BraFont : public Font {
+protected:
byte *_cp;
uint _bufPitch;
@@ -45,15 +46,15 @@ class BraFont : public Font {
uint *_offsets;
byte *_data;
-
- static byte _charMap[];
+ const byte *_charMap;
byte mapChar(byte c) {
- return _charMap[c];
+ return (_charMap == 0) ? c : _charMap[c];
}
public:
- BraFont(Common::ReadStream &stream) {
+ BraFont(Common::ReadStream &stream, const byte *charMap = 0) {
+ _charMap = charMap;
_numGlyphs = stream.readByte();
_height = stream.readUint32BE();
@@ -137,7 +138,7 @@ public:
};
-byte BraFont::_charMap[] = {
+const byte _braDosFullCharMap[256] = {
// 0
0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34,
// 1
@@ -172,6 +173,111 @@ byte BraFont::_charMap[] = {
0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34
};
+const byte _braDosDemoComicCharMap[] = {
+// 0
+ 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34,
+// 1
+ 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34,
+// 2
+ 0x34, 0x49, 0x48, 0x34, 0x34, 0x34, 0x34, 0x47, 0x34, 0x34, 0x34, 0x34, 0x40, 0x34, 0x3F, 0x34,
+// 3
+ 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x46, 0x45, 0x34, 0x34, 0x34, 0x42,
+// 4
+ 0x34, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
+// 5
+ 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x34, 0x34, 0x34, 0x34, 0x34,
+// 6
+ 0x34, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
+// 7
+ 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x34, 0x34, 0x34, 0x34,
+// 8
+ 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34,
+// 9
+ 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34,
+// A
+ 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34,
+// B
+ 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34,
+// C
+ 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34,
+// D
+ 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34,
+// E
+ 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34,
+// F
+ 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34
+};
+
+const byte _braDosDemoRussiaCharMap[] = {
+// 0
+ 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34,
+// 1
+ 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34,
+// 2
+ 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34,
+// 3
+ 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34,
+// 4
+ 0x34, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
+// 5
+ 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x34, 0x34, 0x34, 0x34, 0x34,
+// 6
+ 0x34, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
+// 7
+ 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x34, 0x34, 0x34, 0x34,
+// 8
+ 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34,
+// 9
+ 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34,
+// A
+ 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34,
+// B
+ 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34,
+// C
+ 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34,
+// D
+ 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34,
+// E
+ 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34,
+// F
+ 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34
+};
+
+class BraInventoryObjects : public BraFont, public Frames {
+
+public:
+ BraInventoryObjects(Common::ReadStream &stream) : BraFont(stream) {
+ }
+
+ // Frames implementation
+ uint16 getNum() {
+ return _numGlyphs;
+ }
+
+ byte* getData(uint16 index) {
+ assert(index < _numGlyphs);
+ return _data + (_height * _widths[index]) * index;;
+ }
+
+ void getRect(uint16 index, Common::Rect &r) {
+ assert(index < _numGlyphs);
+ r.left = 0;
+ r.top = 0;
+ r.setWidth(_widths[index]);
+ r.setHeight(_height);
+ }
+
+ uint getRawSize(uint16 index) {
+ assert(index < _numGlyphs);
+ return _widths[index] * _height;
+ }
+
+ uint getSize(uint16 index) {
+ assert(index < _numGlyphs);
+ return _widths[index] * _height;
+ }
+
+};
class DosFont : public Font {
@@ -537,7 +643,19 @@ Font *AmigaDisk_ns::createFont(const char *name, Common::SeekableReadStream &str
Font *DosDisk_br::createFont(const char *name, Common::ReadStream &stream) {
// printf("DosDisk_br::createFont(%s)\n", name);
- return new BraFont(stream);
+ Font *font;
+
+ if (_vm->getFeatures() & GF_DEMO) {
+ if (!scumm_stricmp(name, "russia")) {
+ font = new BraFont(stream, _braDosDemoRussiaCharMap);
+ } else {
+ font = new BraFont(stream, _braDosDemoComicCharMap);
+ }
+ } else {
+ font = new BraFont(stream, _braDosFullCharMap);
+ }
+
+ return font;
}
Font *AmigaDisk_br::createFont(const char *name, Common::SeekableReadStream &stream) {
@@ -545,6 +663,12 @@ Font *AmigaDisk_br::createFont(const char *name, Common::SeekableReadStream &str
return new AmigaFont(stream);
}
+GfxObj* DosDisk_br::createInventoryObjects(Common::SeekableReadStream &stream) {
+ Frames *frames = new BraInventoryObjects(stream);
+ return new GfxObj(0, frames, "inventoryobjects");
+}
+
+
void Parallaction_ns::initFonts() {
if (getPlatform() == Common::kPlatformPC) {
@@ -573,8 +697,8 @@ void Parallaction_br::initFonts() {
// fonts/sonya/18
// fonts/vanya/16
- _menuFont = _disk->loadFont("fonts/natasha/16");
- _dialogueFont = _disk->loadFont("fonts/sonya/18");
+ _menuFont = _disk->loadFont("natasha");
+ _dialogueFont = _disk->loadFont("sonya");
Common::MemoryReadStream stream(_amigaTopazFont, 2600, false);
_labelFont = new AmigaFont(stream);
}
diff --git a/engines/parallaction/gfxbase.cpp b/engines/parallaction/gfxbase.cpp
index e8250ac8fd..aa02253cb1 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(kGfxObjNormal), _keep(true) {
+GfxObj::GfxObj(uint objType, Frames *frames, const char* name) : _frames(frames), _keep(true), x(0), y(0), z(0), _flags(kGfxObjNormal), type(objType), frame(0), layer(3) {
if (name) {
_name = strdup(name);
} else {
@@ -209,63 +209,6 @@ void Gfx::drawText(Font *font, Graphics::Surface* surf, uint16 x, uint16 y, cons
font->drawString(dst, surf->w, text);
}
-void Gfx::drawWrappedText(Font *font, Graphics::Surface* surf, char *text, byte color, int16 wrapwidth) {
-
- uint16 lines = 0;
- uint16 linewidth = 0;
-
- uint16 rx = 10;
- uint16 ry = 4;
-
- uint16 blankWidth = font->getStringWidth(" ");
- uint16 tokenWidth = 0;
-
- char token[MAX_TOKEN_LEN];
-
- if (wrapwidth == -1)
- wrapwidth = _vm->_screenWidth;
-
- while (strlen(text) > 0) {
-
- text = parseNextToken(text, token, MAX_TOKEN_LEN, " ", true);
-
- if (!scumm_stricmp(token, "%p")) {
- lines++;
- rx = 10;
- ry = 4 + lines*10; // y
-
- strcpy(token, "> .......");
- strncpy(token+2, _password, strlen(_password));
- tokenWidth = font->getStringWidth(token);
- } else {
- tokenWidth = font->getStringWidth(token);
-
- linewidth += tokenWidth;
-
- if (linewidth > wrapwidth) {
- // wrap line
- lines++;
- rx = 10; // x
- ry = 4 + lines*10; // y
- linewidth = tokenWidth;
- }
-
- if (!scumm_stricmp(token, "%s")) {
- sprintf(token, "%d", _score);
- }
-
- }
-
- drawText(font, surf, rx, ry, token, color);
-
- rx += tokenWidth + blankWidth;
- linewidth += blankWidth;
-
- text = Common::ltrim(text);
- }
-
-}
-
#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 9b9ea8605a..a31b7f4994 100644
--- a/engines/parallaction/graphics.cpp
+++ b/engines/parallaction/graphics.cpp
@@ -153,6 +153,13 @@ void Palette::setEntry(uint index, int red, int green, int blue) {
_data[index*3+2] = blue & 0xFF;
}
+void Palette::getEntry(uint index, int &red, int &green, int &blue) {
+ assert(index < _colors);
+ red = _data[index*3];
+ green = _data[index*3+1];
+ blue = _data[index*3+2];
+}
+
void Palette::makeGrayscale() {
byte v;
for (uint16 i = 0; i < _colors; i++) {
@@ -307,10 +314,14 @@ void Gfx::setProjectorProgram(int16 *data) {
}
void Gfx::drawInventory() {
-
+/*
if ((_engineFlags & kEngineInventory) == 0) {
return;
}
+*/
+ if (_vm->_input->_inputMode != Input::kInputModeInventory) {
+ return;
+ }
Common::Rect r;
_vm->_inventoryRenderer->getRect(r);
@@ -348,29 +359,37 @@ void Gfx::clearScreen() {
}
void Gfx::beginFrame() {
-
- int32 oldBackgroundMode = _varBackgroundMode;
- _varBackgroundMode = getVar("background_mode");
-
- if (oldBackgroundMode != _varBackgroundMode) {
- switch (_varBackgroundMode) {
- case 1:
- _bitmapMask.free();
- break;
- case 2:
- _bitmapMask.create(_backgroundInfo.width, _backgroundInfo.height, 1);
- byte *data = (byte*)_bitmapMask.pixels;
- for (uint y = 0; y < _bitmapMask.h; y++) {
- for (uint x = 0; x < _bitmapMask.w; x++) {
- *data++ = _backgroundInfo.mask.getValue(x, y);
+ _skipBackground = (_backgroundInfo.bg.pixels == 0); // don't render frame if background is missing
+
+ if (!_skipBackground) {
+ int32 oldBackgroundMode = _varBackgroundMode;
+ _varBackgroundMode = getVar("background_mode");
+ if (oldBackgroundMode != _varBackgroundMode) {
+ switch (_varBackgroundMode) {
+ case 1:
+ _bitmapMask.free();
+ break;
+ case 2:
+ _bitmapMask.create(_backgroundInfo.width, _backgroundInfo.height, 1);
+ byte *data = (byte*)_bitmapMask.pixels;
+ for (uint y = 0; y < _bitmapMask.h; y++) {
+ for (uint x = 0; x < _bitmapMask.w; x++) {
+ *data++ = _backgroundInfo.mask.getValue(x, y);
+ }
}
+ break;
}
- break;
}
}
+ _varDrawPathZones = getVar("draw_path_zones");
+ if (_varDrawPathZones == 1 && _vm->getGameType() != GType_BRA) {
+ setVar("draw_path_zones", 0);
+ _varDrawPathZones = 0;
+ warning("Path zones are supported only in Big Red Adventure");
+ }
- if (_vm->_screenWidth >= _backgroundInfo.width) {
+ if (_skipBackground || (_vm->_screenWidth >= _backgroundInfo.width)) {
_varScrollX = 0;
} else {
_varScrollX = getVar("scroll_x");
@@ -395,24 +414,38 @@ int32 Gfx::getRenderMode(const char *type) {
void Gfx::updateScreen() {
- // background may not cover the whole screen, so adjust bulk update size
- uint w = MIN(_vm->_screenWidth, (int32)_backgroundInfo.width);
- uint h = MIN(_vm->_screenHeight, (int32)_backgroundInfo.height);
+ if (!_skipBackground) {
+ // background may not cover the whole screen, so adjust bulk update size
+ uint w = MIN(_vm->_screenWidth, (int32)_backgroundInfo.width);
+ uint h = MIN(_vm->_screenHeight, (int32)_backgroundInfo.height);
- byte *backgroundData = 0;
- uint16 backgroundPitch = 0;
- switch (_varBackgroundMode) {
- case 1:
- backgroundData = (byte*)_backgroundInfo.bg.getBasePtr(_varScrollX, 0);
- backgroundPitch = _backgroundInfo.bg.pitch;
- break;
- case 2:
- backgroundData = (byte*)_bitmapMask.getBasePtr(_varScrollX, 0);
- backgroundPitch = _bitmapMask.pitch;
- break;
+ byte *backgroundData = 0;
+ uint16 backgroundPitch = 0;
+ switch (_varBackgroundMode) {
+ case 1:
+ backgroundData = (byte*)_backgroundInfo.bg.getBasePtr(_varScrollX, 0);
+ backgroundPitch = _backgroundInfo.bg.pitch;
+ break;
+ case 2:
+ backgroundData = (byte*)_bitmapMask.getBasePtr(_varScrollX, 0);
+ backgroundPitch = _bitmapMask.pitch;
+ break;
+ }
+ g_system->copyRectToScreen(backgroundData, backgroundPitch, _backgroundInfo.x, _backgroundInfo.y, w, h);
}
- g_system->copyRectToScreen(backgroundData, backgroundPitch, _backgroundInfo.x, _backgroundInfo.y, w, h);
+ if (_varDrawPathZones == 1) {
+ Graphics::Surface *surf = g_system->lockScreen();
+ ZoneList::iterator b = _vm->_location._zones.begin();
+ ZoneList::iterator e = _vm->_location._zones.end();
+ for (; b != e; b++) {
+ ZonePtr z = *b;
+ if (z->_type & kZonePath) {
+ surf->frameRect(Common::Rect(z->_left, z->_top, z->_right, z->_bottom), 2);
+ }
+ }
+ g_system->unlockScreen();
+ }
_varRenderMode = _varAnimRenderMode;
@@ -674,49 +707,6 @@ void Gfx::drawLabels() {
}
-void Gfx::getStringExtent(Font *font, char *text, uint16 maxwidth, int16* width, int16* height) {
-
- uint16 lines = 0;
- uint16 w = 0;
- *width = 0;
-
- uint16 blankWidth = font->getStringWidth(" ");
- uint16 tokenWidth = 0;
-
- char token[MAX_TOKEN_LEN];
-
- while (strlen(text) != 0) {
-
- text = parseNextToken(text, token, MAX_TOKEN_LEN, " ", true);
- tokenWidth = font->getStringWidth(token);
-
- w += tokenWidth;
-
- if (!scumm_stricmp(token, "%p")) {
- lines++;
- } else {
- if (w > maxwidth) {
- w -= tokenWidth;
- lines++;
- if (w > *width)
- *width = w;
-
- w = tokenWidth;
- }
- }
-
- w += blankWidth;
- text = Common::ltrim(text);
- }
-
- if (*width < w) *width = w;
- *width += 10;
-
- *height = lines * 10 + 20;
-
- return;
-}
-
void Gfx::copyRect(const Common::Rect &r, Graphics::Surface &src, Graphics::Surface &dst) {
@@ -769,6 +759,16 @@ Gfx::Gfx(Parallaction* vm) :
registerVar("anim_render_mode", 1);
registerVar("misc_render_mode", 1);
+ registerVar("draw_path_zones", 0);
+
+ if ((_vm->getGameType() == GType_BRA) && (_vm->getPlatform() == Common::kPlatformPC)) {
+ // this loads the backup palette needed by the PC version of BRA (see setBackground()).
+ BackgroundInfo paletteInfo;
+ _disk->loadSlide(paletteInfo, "pointer");
+ _backupPal.clone(paletteInfo.palette);
+ paletteInfo.free();
+ }
+
return;
}
@@ -839,10 +839,24 @@ void Gfx::setBackground(uint type, const char* name, const char* mask, const cha
if (type == kBackgroundLocation) {
_disk->loadScenery(_backgroundInfo, name, mask, path);
+
+ // The PC version of BRA needs the entries 20-31 of the palette to be constant, but
+ // the background resource files are screwed up. The right colors come from an unused
+ // bitmap (pointer.bmp). Nothing is known about the Amiga version so far.
+ if ((_vm->getGameType() == GType_BRA) && (_vm->getPlatform() == Common::kPlatformPC)) {
+ int r, g, b;
+ for (uint i = 16; i < 32; i++) {
+ _backupPal.getEntry(i, r, g, b);
+ _backgroundInfo.palette.setEntry(i, r, g, b);
+ }
+ }
+
setPalette(_backgroundInfo.palette);
_palette.clone(_backgroundInfo.palette);
} else {
_disk->loadSlide(_backgroundInfo, name);
+ for (uint i = 0; i < 6; i++)
+ _backgroundInfo.ranges[i]._flags = 0; // disable palette cycling for slides
setPalette(_backgroundInfo.palette);
}
diff --git a/engines/parallaction/graphics.h b/engines/parallaction/graphics.h
index a7242ba6f4..52b7a4b870 100644
--- a/engines/parallaction/graphics.h
+++ b/engines/parallaction/graphics.h
@@ -261,6 +261,7 @@ public:
void makeBlack();
void setEntries(byte* data, uint first, uint num);
+ void getEntry(uint index, int &red, int &green, int &blue);
void setEntry(uint index, int red, int green, int blue);
void makeGrayscale();
void fadeTo(const Palette& target, uint step);
@@ -471,6 +472,9 @@ typedef Common::HashMap<Common::String, int32, Common::IgnoreCase_Hash, Common::
class Gfx {
+protected:
+ Parallaction* _vm;
+
public:
Disk *_disk;
VarMap _vars;
@@ -496,7 +500,6 @@ public:
void freeLabels();
// dialogue balloons
- void getStringExtent(Font *font, char *text, uint16 maxwidth, int16* width, int16* height);
GfxObj* registerBalloon(Frames *frames, const char *text);
void destroyBalloons();
@@ -550,18 +553,23 @@ public:
byte *_unpackedBitmap;
protected:
- Parallaction* _vm;
bool _halfbrite;
+ bool _skipBackground;
+
Common::Point _hbCirclePos;
int _hbCircleRadius;
+ // BRA specific
+ Palette _backupPal;
+
// frame data stored in programmable variables
int32 _varBackgroundMode; // 1 = normal, 2 = only mask
int32 _varScrollX;
int32 _varAnimRenderMode; // 1 = normal, 2 = flat
int32 _varMiscRenderMode; // 1 = normal, 2 = flat
int32 _varRenderMode;
+ int32 _varDrawPathZones; // 0 = don't draw, 1 = draw
Graphics::Surface _bitmapMask;
int32 getRenderMode(const char *type);
@@ -592,7 +600,6 @@ public:
// 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);
void drawGfxObject(GfxObj *obj, Graphics::Surface &surf, bool scene);
void blt(const Common::Rect& r, byte *data, Graphics::Surface *surf, uint16 z, byte transparentColor);
diff --git a/engines/parallaction/gui.cpp b/engines/parallaction/gui.cpp
new file mode 100644
index 0000000000..2dbe64fcf6
--- /dev/null
+++ b/engines/parallaction/gui.cpp
@@ -0,0 +1,92 @@
+/* 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/gui.h"
+
+namespace Parallaction {
+
+bool MenuInputHelper::run() {
+ if (_newState == 0) {
+ debugC(3, kDebugExec, "MenuInputHelper has set NULL state");
+ return false;
+ }
+
+ if (_newState != _state) {
+ debugC(3, kDebugExec, "MenuInputHelper changing state to '%s'", _newState->_name.c_str());
+
+ _newState->enter();
+ _state = _newState;
+ }
+
+ _newState = _state->run();
+
+ return true;
+}
+
+MenuInputHelper::~MenuInputHelper() {
+ StateMap::iterator b = _map.begin();
+ for ( ; b != _map.end(); b++) {
+ delete b->_value;
+ }
+ _map.clear();
+}
+
+
+void Parallaction::runGuiFrame() {
+ if (_input->_inputMode != Input::kInputModeMenu) {
+ return;
+ }
+
+ if (!_menuHelper) {
+ error("No menu helper defined!");
+ }
+
+ bool res = _menuHelper->run();
+
+ if (!res) {
+ cleanupGui();
+ _input->_inputMode = Input::kInputModeGame;
+ }
+
+}
+
+void Parallaction::cleanupGui() {
+ delete _menuHelper;
+ _menuHelper = 0;
+}
+
+void Parallaction::setInternLanguage(uint id) {
+ //TODO: assert id!
+
+ _language = id;
+ _disk->setLanguage(id);
+}
+
+uint Parallaction::getInternLanguage() {
+ return _language;
+}
+
+
+} // namespace Parallaction
diff --git a/engines/parallaction/gui.h b/engines/parallaction/gui.h
new file mode 100644
index 0000000000..dc6d1bc71b
--- /dev/null
+++ b/engines/parallaction/gui.h
@@ -0,0 +1,93 @@
+/* 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_GUI_H
+#define PARALLACTION_GUI_H
+
+#include "common/system.h"
+#include "common/hashmap.h"
+
+#include "parallaction/input.h"
+#include "parallaction/parallaction.h"
+#include "parallaction/sound.h"
+
+
+namespace Parallaction {
+
+class MenuInputState;
+
+class MenuInputHelper {
+ typedef Common::HashMap<Common::String, MenuInputState*> StateMap;
+
+ StateMap _map;
+ MenuInputState *_state;
+ MenuInputState *_newState;
+
+public:
+ MenuInputHelper() : _state(0) {
+ }
+
+ ~MenuInputHelper();
+
+ void setState(const Common::String &name) {
+ // bootstrap routine
+ _newState = getState(name);
+ assert(_newState);
+ }
+
+ void addState(const Common::String &name, MenuInputState *state) {
+ _map.setVal(name, state);
+ }
+
+ MenuInputState *getState(const Common::String &name) {
+ return _map[name];
+ }
+
+ bool run();
+};
+
+class MenuInputState {
+
+protected:
+ MenuInputHelper *_helper;
+
+public:
+ MenuInputState(const Common::String &name, MenuInputHelper *helper) : _helper(helper), _name(name) {
+ debugC(3, kDebugExec, "MenuInputState(%s)", name.c_str());
+ _helper->addState(name, this);
+ }
+
+ Common::String _name;
+
+ virtual ~MenuInputState() { }
+
+ virtual MenuInputState* run() = 0;
+ virtual void enter() = 0;
+};
+
+
+} // namespace Parallaction
+
+#endif
diff --git a/engines/parallaction/gui_br.cpp b/engines/parallaction/gui_br.cpp
index 0be070e345..b10237046e 100644
--- a/engines/parallaction/gui_br.cpp
+++ b/engines/parallaction/gui_br.cpp
@@ -25,184 +25,269 @@
#include "common/system.h"
-
+#include "parallaction/gui.h"
#include "parallaction/input.h"
#include "parallaction/parallaction.h"
namespace Parallaction {
-enum MenuOptions {
- kMenuPart0 = 0,
- kMenuPart1 = 1,
- kMenuPart2 = 2,
- kMenuPart3 = 3,
- kMenuPart4 = 4,
- kMenuLoadGame = 5,
- kMenuQuit = 6
-};
-
+class SplashInputState_BR : public MenuInputState {
+protected:
+ Common::String _slideName;
+ uint32 _timeOut;
+ Common::String _nextState;
+ uint32 _startTime;
+ Palette blackPal;
+ Palette pal;
-void Parallaction_br::guiStart() {
+ Parallaction_br *_vm;
+ int _fadeSteps;
- // TODO: load progress value from special save game
- _progress = 3;
+public:
+ SplashInputState_BR(Parallaction_br *vm, const Common::String &name, MenuInputHelper *helper) : MenuInputState(name, helper), _vm(vm) {
+ }
- int option = guiShowMenu();
- switch (option) {
- case kMenuQuit:
- _engineFlags |= kEngineQuit;
- break;
+ virtual MenuInputState* run() {
+ if (_fadeSteps > 0) {
+ pal.fadeTo(blackPal, 1);
+ _vm->_gfx->setPalette(pal);
+ _fadeSteps--;
+ // TODO: properly implement timers to avoid delay calls
+ _vm->_system->delayMillis(20);
+ return this;
+ }
- case kMenuLoadGame:
- warning("loadgame not yet implemented");
- break;
+ if (_fadeSteps == 0) {
+ _vm->freeBackground();
+ return _helper->getState(_nextState);
+ }
- default:
- _part = option;
- _disk->selectArchive(_partNames[_part]);
- startPart();
+ uint32 curTime = _vm->_system->getMillis();
+ if (curTime - _startTime > _timeOut) {
+ _fadeSteps = 64;
+ pal.clone(_vm->_gfx->_backgroundInfo.palette);
+ }
+ return this;
}
-}
-void Parallaction_br::guiSplash(const char *name) {
+ virtual void enter() {
+ _vm->_gfx->clearScreen();
+ _vm->_gfx->setBackground(kBackgroundSlide, _slideName.c_str(), 0, 0);
+ _vm->_gfx->_backgroundInfo.x = (_vm->_screenWidth - _vm->_gfx->_backgroundInfo.width) >> 1;
+ _vm->_gfx->_backgroundInfo.y = (_vm->_screenHeight - _vm->_gfx->_backgroundInfo.height) >> 1;
+ _vm->_input->setMouseState(MOUSE_DISABLED);
- _gfx->clearScreen();
- _gfx->setBackground(kBackgroundSlide, name, 0, 0);
- _gfx->_backgroundInfo.x = (_screenWidth - _gfx->_backgroundInfo.width) >> 1;
- _gfx->_backgroundInfo.y = (_screenHeight - _gfx->_backgroundInfo.height) >> 1;
- _gfx->updateScreen();
- _system->delayMillis(600);
+ _startTime = g_system->getMillis();
+ _fadeSteps = -1;
+ }
+};
- Palette blackPal;
- Palette pal(_gfx->_backgroundInfo.palette);
- for (uint i = 0; i < 64; i++) {
- pal.fadeTo(blackPal, 1);
- _gfx->setPalette(pal);
- _gfx->updateScreen();
- _system->delayMillis(20);
+class SplashInputState0_BR : public SplashInputState_BR {
+
+public:
+ SplashInputState0_BR(Parallaction_br *vm, MenuInputHelper *helper) : SplashInputState_BR(vm, "intro0", helper) {
+ _slideName = "dyna";
+ _timeOut = 600;
+ _nextState = "intro1";
}
+};
-}
+class SplashInputState1_BR : public SplashInputState_BR {
-#define MENUITEMS_X 250
-#define MENUITEMS_Y 200
+public:
+ SplashInputState1_BR(Parallaction_br *vm, MenuInputHelper *helper) : SplashInputState_BR(vm, "intro1", helper) {
+ _slideName = "core";
+ _timeOut = 600;
+ _nextState = "mainmenu";
+ }
+};
-#define MENUITEM_WIDTH 190
-#define MENUITEM_HEIGHT 18
+class MainMenuInputState_BR : public MenuInputState {
+ Parallaction_br *_vm;
-Frames* Parallaction_br::guiRenderMenuItem(const char *text) {
- // this builds a surface containing two copies of the text.
- // one is in normal color, the other is inverted.
- // the two 'frames' are used to display selected/unselected menu items
+ #define MENUITEMS_X 250
+ #define MENUITEMS_Y 200
- Graphics::Surface *surf = new Graphics::Surface;
- surf->create(MENUITEM_WIDTH, MENUITEM_HEIGHT*2, 1);
+ #define MENUITEM_WIDTH 190
+ #define MENUITEM_HEIGHT 18
- // build first frame to be displayed when item is not selected
- if (getPlatform() == Common::kPlatformPC) {
- _menuFont->setColor(0);
- } else {
- _menuFont->setColor(7);
- }
- _menuFont->drawString((byte*)surf->getBasePtr(5, 2), MENUITEM_WIDTH, text);
+ Frames* renderMenuItem(const char *text) {
+ // this builds a surface containing two copies of the text.
+ // one is in normal color, the other is inverted.
+ // the two 'frames' are used to display selected/unselected menu items
- // build second frame to be displayed when item is selected
- _menuFont->drawString((byte*)surf->getBasePtr(5, 2 + MENUITEM_HEIGHT), MENUITEM_WIDTH, text);
- byte *s = (byte*)surf->getBasePtr(0, MENUITEM_HEIGHT);
- for (int i = 0; i < surf->w * MENUITEM_HEIGHT; i++) {
- *s++ ^= 0xD;
- }
+ Graphics::Surface *surf = new Graphics::Surface;
+ surf->create(MENUITEM_WIDTH, MENUITEM_HEIGHT*2, 1);
- // wrap the surface into the suitable Frames adapter
- return new SurfaceToMultiFrames(2, MENUITEM_WIDTH, MENUITEM_HEIGHT, surf);
-}
+ // build first frame to be displayed when item is not selected
+ if (_vm->getPlatform() == Common::kPlatformPC) {
+ _vm->_menuFont->setColor(0);
+ } else {
+ _vm->_menuFont->setColor(7);
+ }
+ _vm->_menuFont->drawString((byte*)surf->getBasePtr(5, 2), MENUITEM_WIDTH, text);
+
+ // build second frame to be displayed when item is selected
+ _vm->_menuFont->drawString((byte*)surf->getBasePtr(5, 2 + MENUITEM_HEIGHT), MENUITEM_WIDTH, text);
+ byte *s = (byte*)surf->getBasePtr(0, MENUITEM_HEIGHT);
+ for (int i = 0; i < surf->w * MENUITEM_HEIGHT; i++) {
+ *s++ ^= 0xD;
+ }
+ // wrap the surface into the suitable Frames adapter
+ return new SurfaceToMultiFrames(2, MENUITEM_WIDTH, MENUITEM_HEIGHT, surf);
+ }
-int Parallaction_br::guiShowMenu() {
- // TODO: filter menu entries according to progress in game
+ enum MenuOptions {
+ kMenuPart0 = 0,
+ kMenuPart1 = 1,
+ kMenuPart2 = 2,
+ kMenuPart3 = 3,
+ kMenuPart4 = 4,
+ kMenuLoadGame = 5,
+ kMenuQuit = 6
+ };
#define NUM_MENULINES 7
GfxObj *_lines[NUM_MENULINES];
- const char *menuStrings[NUM_MENULINES] = {
- "SEE INTRO",
- "NEW GAME",
- "SAVED GAME",
- "EXIT TO DOS",
- "PART 2",
- "PART 3",
- "PART 4"
- };
+ static const char *_menuStrings[NUM_MENULINES];
+ static const MenuOptions _options[NUM_MENULINES];
- MenuOptions options[NUM_MENULINES] = {
- kMenuPart0,
- kMenuPart1,
- kMenuLoadGame,
- kMenuQuit,
- kMenuPart2,
- kMenuPart3,
- kMenuPart4
- };
+ int _availItems;
+ int _selection;
- _gfx->clearScreen();
- _gfx->setBackground(kBackgroundSlide, "tbra", 0, 0);
- if (getPlatform() == Common::kPlatformPC) {
- _gfx->_backgroundInfo.x = 20;
- _gfx->_backgroundInfo.y = 50;
+ void cleanup() {
+ _vm->_system->showMouse(false);
+ _vm->hideDialogueStuff();
+
+ for (int i = 0; i < _availItems; i++) {
+ delete _lines[i];
+ }
}
- int availItems = 4 + _progress;
+ void performChoice(int selectedItem) {
+ switch (selectedItem) {
+ case kMenuQuit:
+ _engineFlags |= kEngineQuit;
+ break;
- // TODO: keep track of and destroy menu item frames/surfaces
+ case kMenuLoadGame:
+ warning("loadgame not yet implemented");
+ break;
- int i;
- for (i = 0; i < availItems; i++) {
- _lines[i] = new GfxObj(0, guiRenderMenuItem(menuStrings[i]), "MenuItem");
- uint id = _gfx->setItem(_lines[i], MENUITEMS_X, MENUITEMS_Y + MENUITEM_HEIGHT * i, 0xFF);
- _gfx->setItemFrame(id, 0);
+ default:
+ _vm->startPart(selectedItem);
+ }
}
- int selectedItem = -1;
-
- setMousePointer(0);
-
- uint32 event;
- Common::Point p;
- while (true) {
+public:
+ MainMenuInputState_BR(Parallaction_br *vm, MenuInputHelper *helper) : MenuInputState("mainmenu", helper), _vm(vm) {
+ }
- _input->readInput();
+ virtual MenuInputState* run() {
- event = _input->getLastButtonEvent();
- if ((event == kMouseLeftUp) && selectedItem >= 0)
- break;
+ int event = _vm->_input->getLastButtonEvent();
+ if ((event == kMouseLeftUp) && _selection >= 0) {
+ cleanup();
+ performChoice(_options[_selection]);
+ return 0;
+ }
- _input->getCursorPos(p);
+ Common::Point p;
+ _vm->_input->getCursorPos(p);
if ((p.x > MENUITEMS_X) && (p.x < (MENUITEMS_X+MENUITEM_WIDTH)) && (p.y > MENUITEMS_Y)) {
- selectedItem = (p.y - MENUITEMS_Y) / MENUITEM_HEIGHT;
+ _selection = (p.y - MENUITEMS_Y) / MENUITEM_HEIGHT;
- if (!(selectedItem < availItems))
- selectedItem = -1;
+ if (!(_selection < _availItems))
+ _selection = -1;
} else
- selectedItem = -1;
+ _selection = -1;
- for (i = 0; i < availItems; i++) {
- _gfx->setItemFrame(i, selectedItem == i ? 1 : 0);
+ for (int i = 0; i < _availItems; i++) {
+ _vm->_gfx->setItemFrame(i, _selection == i ? 1 : 0);
}
- _gfx->updateScreen();
- _system->delayMillis(20);
+
+ return this;
}
- _system->showMouse(false);
- hideDialogueStuff();
+ virtual void enter() {
+ _vm->_gfx->clearScreen();
+ _vm->_gfx->setBackground(kBackgroundSlide, "tbra", 0, 0);
+ if (_vm->getPlatform() == Common::kPlatformPC) {
+ _vm->_gfx->_backgroundInfo.x = 20;
+ _vm->_gfx->_backgroundInfo.y = 50;
+ }
+
+ // TODO: load progress from savefile
+ int progress = 3;
+ _availItems = 4 + progress;
- for (i = 0; i < availItems; i++) {
- delete _lines[i];
+ // TODO: keep track of and destroy menu item frames/surfaces
+ int i;
+ for (i = 0; i < _availItems; i++) {
+ _lines[i] = new GfxObj(0, renderMenuItem(_menuStrings[i]), "MenuItem");
+ uint id = _vm->_gfx->setItem(_lines[i], MENUITEMS_X, MENUITEMS_Y + MENUITEM_HEIGHT * i, 0xFF);
+ _vm->_gfx->setItemFrame(id, 0);
+ }
+ _selection = -1;
+ _vm->setArrowCursor();
+ _vm->_input->setMouseState(MOUSE_ENABLED_SHOW);
}
- return options[selectedItem];
+};
+
+const char *MainMenuInputState_BR::_menuStrings[NUM_MENULINES] = {
+ "SEE INTRO",
+ "NEW GAME",
+ "SAVED GAME",
+ "EXIT TO DOS",
+ "PART 2",
+ "PART 3",
+ "PART 4"
+};
+
+const MainMenuInputState_BR::MenuOptions MainMenuInputState_BR::_options[NUM_MENULINES] = {
+ kMenuPart0,
+ kMenuPart1,
+ kMenuLoadGame,
+ kMenuQuit,
+ kMenuPart2,
+ kMenuPart3,
+ kMenuPart4
+};
+
+
+
+
+
+
+
+void Parallaction_br::startGui() {
+ _menuHelper = new MenuInputHelper;
+ new SplashInputState0_BR(this, _menuHelper);
+ new SplashInputState1_BR(this, _menuHelper);
+ new MainMenuInputState_BR(this, _menuHelper);
+
+ _menuHelper->setState("intro0");
+ _input->_inputMode = Input::kInputModeMenu;
+
+ do {
+ _input->readInput();
+ if (!_menuHelper->run()) break;
+ _gfx->beginFrame();
+ _gfx->updateScreen();
+ } while (true);
+
+ delete _menuHelper;
+ _menuHelper = 0;
+
+ _input->_inputMode = Input::kInputModeGame;
}
+
+
} // namespace Parallaction
diff --git a/engines/parallaction/gui_ns.cpp b/engines/parallaction/gui_ns.cpp
index 9c48586dbc..815c27bd1c 100644
--- a/engines/parallaction/gui_ns.cpp
+++ b/engines/parallaction/gui_ns.cpp
@@ -24,7 +24,9 @@
*/
#include "common/system.h"
+#include "common/hashmap.h"
+#include "parallaction/gui.h"
#include "parallaction/input.h"
#include "parallaction/parallaction.h"
#include "parallaction/sound.h"
@@ -32,313 +34,567 @@
namespace Parallaction {
-const char *introMsg1[] = {
- "INSERISCI IL CODICE",
- "ENTREZ CODE",
- "ENTER CODE",
- "GIB DEN KODE EIN"
-};
+class SplashInputState_NS : public MenuInputState {
+protected:
+ Common::String _slideName;
+ uint32 _timeOut;
+ Common::String _nextState;
+ uint32 _startTime;
-const char *introMsg2[] = {
- "CODICE ERRATO",
- "CODE ERRONE",
- "WRONG CODE",
- "GIB DEN KODE EIN"
-};
+ Parallaction_ns *_vm;
-const char *introMsg3[] = {
- "PRESS LEFT MOUSE BUTTON",
- "TO SEE INTRO",
- "PRESS RIGHT MOUSE BUTTON",
- "TO START"
+public:
+ SplashInputState_NS(Parallaction_ns *vm, const Common::String &name, MenuInputHelper *helper) : MenuInputState(name, helper), _vm(vm) {
+ }
+
+ virtual MenuInputState* run() {
+ uint32 curTime = g_system->getMillis();
+ if (curTime - _startTime > _timeOut) {
+ _vm->freeBackground();
+ return _helper->getState(_nextState);
+ }
+ return this;
+ }
+
+ virtual void enter() {
+ _vm->_input->setMouseState(MOUSE_DISABLED);
+ _vm->showSlide(_slideName.c_str());
+ _startTime = g_system->getMillis();
+ }
};
-const char *newGameMsg[] = {
- "NUOVO GIOCO",
- "NEUF JEU",
- "NEW GAME",
- "NEUES SPIEL"
+class SplashInputState0_NS : public SplashInputState_NS {
+
+public:
+ SplashInputState0_NS(Parallaction_ns *vm, MenuInputHelper *helper) : SplashInputState_NS(vm, "intro0", helper) {
+ _slideName = "intro";
+ _timeOut = 2000;
+ _nextState = "intro1";
+ }
};
-const char *loadGameMsg[] = {
- "GIOCO SALVATO",
- "JEU SAUVE'",
- "SAVED GAME",
- "SPIEL GESPEICHERT"
+class SplashInputState1_NS : public SplashInputState_NS {
+
+public:
+ SplashInputState1_NS(Parallaction_ns *vm, MenuInputHelper *helper) : SplashInputState_NS(vm, "intro1", helper) {
+ _slideName = "minintro";
+ _timeOut = 2000;
+ _nextState = "chooselanguage";
+ }
};
-#define BLOCK_WIDTH 16
-#define BLOCK_HEIGHT 24
+class ChooseLanguageInputState_NS : public MenuInputState {
+ #define BLOCK_WIDTH 16
+ #define BLOCK_HEIGHT 24
-#define BLOCK_X 112
-#define BLOCK_Y 130
+ #define BLOCK_X 112
+ #define BLOCK_Y 130
-#define BLOCK_SELECTION_X (BLOCK_X-1)
-#define BLOCK_SELECTION_Y (BLOCK_Y-1)
+ #define BLOCK_SELECTION_X (BLOCK_X-1)
+ #define BLOCK_SELECTION_Y (BLOCK_Y-1)
-#define BLOCK_X_OFFSET (BLOCK_WIDTH+1)
-#define BLOCK_Y_OFFSET 9
+ #define BLOCK_X_OFFSET (BLOCK_WIDTH+1)
+ #define BLOCK_Y_OFFSET 9
-// destination slots for code blocks
-//
-#define SLOT_X 61
-#define SLOT_Y 64
-#define SLOT_WIDTH (BLOCK_WIDTH+2)
+ // destination slots for code blocks
+ //
+ #define SLOT_X 61
+ #define SLOT_Y 64
+ #define SLOT_WIDTH (BLOCK_WIDTH+2)
-#define PASSWORD_LEN 6
+ int _language;
+ bool _allowChoice;
+ Common::String _nextState;
-#define CHAR_DINO 0
-#define CHAR_DONNA 1
-#define CHAR_DOUGH 2
+ static const Common::Rect _dosLanguageSelectBlocks[4];
+ static const Common::Rect _amigaLanguageSelectBlocks[4];
+ const Common::Rect *_blocks;
-static const uint16 _amigaKeys[][PASSWORD_LEN] = {
- { 5, 3, 6, 2, 2, 7 }, // dino
- { 0, 3, 6, 2, 2, 6 }, // donna
- { 1, 3 ,7, 2, 4, 6 } // dough
-};
+ Parallaction_ns *_vm;
-static const uint16 _pcKeys[][PASSWORD_LEN] = {
- { 5, 3, 6, 1, 4, 7 }, // dino
- { 0, 2, 8, 5, 5, 1 }, // donna
- { 1, 7 ,7, 2, 2, 6 } // dough
-};
+public:
+ ChooseLanguageInputState_NS(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("chooselanguage", helper), _vm(vm) {
+ _allowChoice = false;
+ _nextState = "selectgame";
-static const char *_charStartLocation[] = {
- "test.dino",
- "test.donna",
- "test.dough"
+ if (_vm->getPlatform() == Common::kPlatformAmiga) {
+ if (!(_vm->getFeatures() & GF_LANG_MULT)) {
+ if (_vm->getFeatures() & GF_DEMO) {
+ _language = 1; // Amiga Demo supports English
+ _nextState = "startdemo";
+ return;
+ } else {
+ _language = 0; // The only other non multi-lingual version just supports Italian
+ return;
+ }
+ }
+
+ _blocks = _amigaLanguageSelectBlocks;
+ } else {
+ _blocks = _dosLanguageSelectBlocks;
+ }
+
+ _language = -1;
+ _allowChoice = true;
+ }
+
+ virtual MenuInputState* run() {
+ if (!_allowChoice) {
+ _vm->setInternLanguage(_language);
+ return _helper->getState(_nextState);
+ }
+
+ int event = _vm->_input->getLastButtonEvent();
+ if (event != kMouseLeftUp) {
+ return this;
+ }
+
+ Common::Point p;
+ _vm->_input->getCursorPos(p);
+
+ for (uint16 i = 0; i < 4; i++) {
+ if (_blocks[i].contains(p)) {
+ _vm->setInternLanguage(i);
+ _vm->beep();
+ _vm->_gfx->freeLabels();
+ return _helper->getState(_nextState);
+ }
+ }
+
+ return this;
+ }
+
+ virtual void enter() {
+ if (!_allowChoice) {
+ return;
+ }
+
+ _vm->_input->setMouseState(MOUSE_ENABLED_SHOW);
+
+ // user can choose language in this version
+ _vm->showSlide("lingua");
+
+ uint id = _vm->_gfx->createLabel(_vm->_introFont, "SELECT LANGUAGE", 1);
+ _vm->_gfx->showLabel(id, 60, 30);
+
+ _vm->setArrowCursor();
+ }
};
-enum {
- NEW_GAME,
- LOAD_GAME
+const Common::Rect ChooseLanguageInputState_NS::_dosLanguageSelectBlocks[4] = {
+ Common::Rect( 80, 110, 128, 180 ), // Italian
+ Common::Rect( 129, 85, 177, 155 ), // French
+ Common::Rect( 178, 60, 226, 130 ), // English
+ Common::Rect( 227, 35, 275, 105 ) // German
};
-enum {
- START_DEMO,
- START_INTRO,
- GAME_LOADED,
- SELECT_CHARACTER
+const Common::Rect ChooseLanguageInputState_NS::_amigaLanguageSelectBlocks[4] = {
+ Common::Rect( -1, -1, -1, -1 ), // Italian: not supported by Amiga multi-lingual version
+ Common::Rect( 129, 85, 177, 155 ), // French
+ Common::Rect( 178, 60, 226, 130 ), // English
+ Common::Rect( 227, 35, 275, 105 ) // German
};
-void Parallaction_ns::guiStart() {
+class SelectGameInputState_NS : public MenuInputState {
- _disk->selectArchive((getFeatures() & GF_DEMO) ? "disk0" : "disk1");
+ int _choice, _oldChoice;
+ Common::String _nextState[2];
- guiSplash();
+ uint _labels[2];
- _language = guiChooseLanguage();
- _disk->setLanguage(_language);
+ Parallaction_ns *_vm;
- int event;
+ static const char *newGameMsg[4];
+ static const char *loadGameMsg[4];
- if (getFeatures() & GF_DEMO) {
- event = START_DEMO;
- } else {
- if (guiSelectGame() == NEW_GAME) {
- event = guiNewGame();
- } else {
- event = loadGame() ? GAME_LOADED : START_INTRO;
- }
+public:
+ SelectGameInputState_NS(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("selectgame", helper), _vm(vm) {
+ _choice = 0;
+ _oldChoice = -1;
+
+ _nextState[0] = "newgame";
+ _nextState[1] = "loadgame";
}
- switch (event) {
- case START_DEMO:
- strcpy(_location._name, "fognedemo.dough");
- break;
- case START_INTRO:
- strcpy(_location._name, "fogne.dough");
- break;
+ virtual MenuInputState *run() {
+ int event = _vm->_input->getLastButtonEvent();
+
+ if (event == kMouseLeftUp) {
+ _vm->_gfx->freeLabels();
+ return _helper->getState(_nextState[_choice]);
+ }
- case GAME_LOADED:
- // nothing to do here
- return;
+ Common::Point p;
+ _vm->_input->getCursorPos(p);
+ _choice = (p.x > 160) ? 1 : 0;
- case SELECT_CHARACTER:
- selectStartLocation();
- break;
+ if (_choice != _oldChoice) {
+ if (_oldChoice != -1)
+ _vm->_gfx->hideLabel(_labels[_oldChoice]);
+ if (_choice != -1)
+ _vm->_gfx->showLabel(_labels[_choice], 60, 30);
+
+ _oldChoice = _choice;
+ }
+
+ return this;
}
- return;
-}
+ virtual void enter() {
+ _vm->showSlide("restore");
+ _vm->_input->setMouseState(MOUSE_ENABLED_SHOW);
-void Parallaction_ns::selectStartLocation() {
- _inTestResult = false;
+ _labels[0] = _vm->_gfx->createLabel(_vm->_introFont, newGameMsg[_vm->getInternLanguage()], 1);
+ _labels[1] = _vm->_gfx->createLabel(_vm->_introFont, loadGameMsg[_vm->getInternLanguage()], 1);
+ }
- int character = guiSelectCharacter();
- if (character == -1)
- error("invalid character selected from menu screen");
+};
- scheduleLocationSwitch(_charStartLocation[character]);
-}
+const char *SelectGameInputState_NS::newGameMsg[4] = {
+ "NUOVO GIOCO",
+ "NEUF JEU",
+ "NEW GAME",
+ "NEUES SPIEL"
+};
+const char *SelectGameInputState_NS::loadGameMsg[4] = {
+ "GIOCO SALVATO",
+ "JEU SAUVE'",
+ "SAVED GAME",
+ "SPIEL GESPEICHERT"
+};
-void Parallaction_ns::guiSplash() {
- showSlide("intro");
- _gfx->updateScreen();
- g_system->delayMillis(2000);
- freeBackground();
- showSlide("minintro");
- _gfx->updateScreen();
- g_system->delayMillis(2000);
- freeBackground();
-}
+class LoadGameInputState_NS : public MenuInputState {
+ bool _result;
+ Parallaction_ns *_vm;
-int Parallaction_ns::guiNewGame() {
+public:
+ LoadGameInputState_NS(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("loadgame", helper), _vm(vm) { }
- const char **v14 = introMsg3;
+ virtual MenuInputState* run() {
+ if (!_result) {
+ _vm->scheduleLocationSwitch("fogne.dough");
+ }
+ return 0;
+ }
- _disk->selectArchive("disk1");
+ virtual void enter() {
+ _result = _vm->loadGame();
+ }
+};
- setBackground("test", NULL, NULL);
- _gfx->updateScreen();
- uint id[4];
- id[0] = _gfx->createLabel(_menuFont, v14[0], 1);
- id[1] = _gfx->createLabel(_menuFont, v14[1], 1);
- id[2] = _gfx->createLabel(_menuFont, v14[2], 1);
- id[3] = _gfx->createLabel(_menuFont, v14[3], 1);
- _gfx->showLabel(id[0], CENTER_LABEL_HORIZONTAL, 50);
- _gfx->showLabel(id[1], CENTER_LABEL_HORIZONTAL, 70);
- _gfx->showLabel(id[2], CENTER_LABEL_HORIZONTAL, 100);
- _gfx->showLabel(id[3], CENTER_LABEL_HORIZONTAL, 120);
+class NewGameInputState_NS : public MenuInputState {
+ Parallaction_ns *_vm;
- _input->showCursor(false);
+ static const char *introMsg3[4];
- _gfx->updateScreen();
+public:
+ NewGameInputState_NS(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("newgame", helper), _vm(vm) {
+ }
- _input->waitForButtonEvent(kMouseLeftUp | kMouseRightUp);
- uint32 event = _input->getLastButtonEvent();
+ virtual MenuInputState* run() {
+ int event = _vm->_input->getLastButtonEvent();
- _input->showCursor(true);
+ if (event == kMouseLeftUp || event == kMouseRightUp) {
+ _vm->_input->setMouseState(MOUSE_ENABLED_SHOW);
+ _vm->_gfx->freeLabels();
- _gfx->freeLabels();
+ if (event == kMouseLeftUp) {
+ _vm->scheduleLocationSwitch("fogne.dough");
+ return 0;
+ }
- if (event != kMouseRightUp) {
- return START_INTRO;
- }
+ return _helper->getState("selectcharacter");
+ }
- return SELECT_CHARACTER;
-}
+ return this;
+ }
-static const Common::Rect _dosLanguageSelectBlocks[4] = {
- Common::Rect( 80, 110, 128, 180 ), // Italian
- Common::Rect( 129, 85, 177, 155 ), // French
- Common::Rect( 178, 60, 226, 130 ), // English
- Common::Rect( 227, 35, 275, 105 ) // German
+ virtual void enter() {
+ _vm->_disk->selectArchive("disk1");
+ _vm->setBackground("test", NULL, NULL);
+ _vm->_input->setMouseState(MOUSE_ENABLED_HIDE);
+
+ uint id[4];
+ id[0] = _vm->_gfx->createLabel(_vm->_menuFont, introMsg3[0], 1);
+ id[1] = _vm->_gfx->createLabel(_vm->_menuFont, introMsg3[1], 1);
+ id[2] = _vm->_gfx->createLabel(_vm->_menuFont, introMsg3[2], 1);
+ id[3] = _vm->_gfx->createLabel(_vm->_menuFont, introMsg3[3], 1);
+ _vm->_gfx->showLabel(id[0], CENTER_LABEL_HORIZONTAL, 50);
+ _vm->_gfx->showLabel(id[1], CENTER_LABEL_HORIZONTAL, 70);
+ _vm->_gfx->showLabel(id[2], CENTER_LABEL_HORIZONTAL, 100);
+ _vm->_gfx->showLabel(id[3], CENTER_LABEL_HORIZONTAL, 120);
+ }
};
-static const Common::Rect _amigaLanguageSelectBlocks[4] = {
- Common::Rect( -1, -1, -1, -1 ), // Italian: not supported by Amiga multi-lingual version
- Common::Rect( 129, 85, 177, 155 ), // French
- Common::Rect( 178, 60, 226, 130 ), // English
- Common::Rect( 227, 35, 275, 105 ) // German
+const char *NewGameInputState_NS::introMsg3[4] = {
+ "PRESS LEFT MOUSE BUTTON",
+ "TO SEE INTRO",
+ "PRESS RIGHT MOUSE BUTTON",
+ "TO START"
};
-uint16 Parallaction_ns::guiChooseLanguage() {
- const Common::Rect *blocks;
+class StartDemoInputState_NS : public MenuInputState {
+ Parallaction_ns *_vm;
- if (getPlatform() == Common::kPlatformAmiga) {
- if (!(getFeatures() & GF_LANG_MULT)) {
- if (getFeatures() & GF_DEMO) {
- return 1; // Amiga Demo supports English
- } else {
- return 0; // The only other non multi-lingual version just supports Italian
- }
- }
+public:
+ StartDemoInputState_NS(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("startdemo", helper), _vm(vm) {
+ }
- blocks = _amigaLanguageSelectBlocks;
- } else {
- blocks = _dosLanguageSelectBlocks;
+ virtual MenuInputState* run() {
+ _vm->scheduleLocationSwitch("fognedemo.dough");
+ return 0;
}
- // user can choose language in dos version
- showSlide("lingua");
+ virtual void enter() {
+ _vm->_input->setMouseState(MOUSE_DISABLED);
+ }
+};
- uint id = _gfx->createLabel(_introFont, "SELECT LANGUAGE", 1);
- _gfx->showLabel(id, 60, 30);
+class SelectCharacterInputState_NS : public MenuInputState {
- setArrowCursor();
+ #define PASSWORD_LEN 6
- Common::Point p;
+ #define CHAR_DINO 0
+ #define CHAR_DONNA 1
+ #define CHAR_DOUGH 2
- int selection = -1;
- while (selection == -1) {
- _input->waitUntilLeftClick();
- _input->getCursorPos(p);
- for (uint16 i = 0; i < 4; i++) {
- if (blocks[i].contains(p)) {
+ static const Common::Rect codeSelectBlocks[9];
+ static const Common::Rect codeTrueBlocks[9];
+
+ Parallaction_ns *_vm;
+
+ int guiGetSelectedBlock(const Common::Point &p) {
+
+ int selection = -1;
+
+ for (uint16 i = 0; i < 9; i++) {
+ if (codeSelectBlocks[i].contains(p)) {
selection = i;
break;
}
}
+
+ if ((selection != -1) && (_vm->getPlatform() == Common::kPlatformAmiga)) {
+ _vm->_gfx->invertBackground(codeTrueBlocks[selection]);
+ _vm->_gfx->updateScreen();
+ _vm->beep();
+ g_system->delayMillis(100);
+ _vm->_gfx->invertBackground(codeTrueBlocks[selection]);
+ _vm->_gfx->updateScreen();
+ }
+
+ return selection;
}
- beep();
+ byte _points[3];
+ bool _fail;
+ const uint16 (*_keys)[PASSWORD_LEN];
+ Graphics::Surface _block;
+ Graphics::Surface _emptySlots;
- _gfx->freeLabels();
+ uint _labels[2];
+ uint _len;
+ uint32 _startTime;
- return selection;
-}
+ enum {
+ CHOICE,
+ FAIL,
+ SUCCESS,
+ DELAY
+ };
+ uint _state;
+ static const char *introMsg1[4];
+ static const char *introMsg2[4];
-uint16 Parallaction_ns::guiSelectGame() {
-// printf("selectGame()\n");
+ static const uint16 _amigaKeys[3][PASSWORD_LEN];
+ static const uint16 _pcKeys[3][PASSWORD_LEN];
+ static const char *_charStartLocation[3];
- showSlide("restore");
- uint16 _si = 0;
- uint16 _di = 3;
+public:
+ SelectCharacterInputState_NS(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("selectcharacter", helper), _vm(vm) {
+ _keys = (_vm->getPlatform() == Common::kPlatformAmiga && (_vm->getFeatures() & GF_LANG_MULT)) ? _amigaKeys : _pcKeys;
+ _block.create(BLOCK_WIDTH, BLOCK_HEIGHT, 1);
+ }
- uint id0, id1;
- id0 = _gfx->createLabel(_introFont, loadGameMsg[_language], 1);
- id1 = _gfx->createLabel(_introFont, newGameMsg[_language], 1);
+ ~SelectCharacterInputState_NS() {
+ _block.free();
+ _emptySlots.free();
+ }
- Common::Point p;
+ void cleanup() {
+ _points[0] = _points[1] = _points[2] = 0;
+ _vm->_gfx->hideLabel(_labels[1]);
+ _vm->_gfx->showLabel(_labels[0], 60, 30);
+ _fail = false;
+ _len = 0;
+ }
- _input->readInput();
- uint32 event = _input->getLastButtonEvent();
+ void delay() {
+ if (g_system->getMillis() - _startTime < 2000) {
+ return;
+ }
+ cleanup();
+ _state = CHOICE;
+ }
- while (event != kMouseLeftUp) {
+ void choice() {
+ int event = _vm->_input->getLastButtonEvent();
+ if (event != kMouseLeftUp) {
+ return;
+ }
- _input->readInput();
- _input->getCursorPos(p);
- event = _input->getLastButtonEvent();
+ Common::Point p;
+ _vm->_input->getCursorPos(p);
+ int _si = guiGetSelectedBlock(p);
- _si = (p.x > 160) ? 1 : 0;
+ if (_si != -1) {
+ _vm->_gfx->grabBackground(codeTrueBlocks[_si], _block);
+ _vm->_gfx->patchBackground(_block, _len * SLOT_WIDTH + SLOT_X, SLOT_Y, false);
- if (_si != _di) {
- if (_si != 0) {
- // load a game
- _gfx->hideLabel(id1);
- _gfx->showLabel(id0, 60, 30);
- } else {
- // new game
- _gfx->hideLabel(id0);
- _gfx->showLabel(id1, 60, 30);
+ if (_keys[0][_len] != _si && _keys[1][_len] != _si && _keys[2][_len] != _si) {
+ _fail = true;
}
- _di = _si;
+
+ // build user preference
+ _points[0] += (_keys[0][_len] == _si);
+ _points[1] += (_keys[1][_len] == _si);
+ _points[2] += (_keys[2][_len] == _si);
+
+ _len++;
}
- _gfx->updateScreen();
- g_system->delayMillis(30);
+ if (_len == PASSWORD_LEN) {
+ _state = _fail ? FAIL : SUCCESS;
+ }
}
- _gfx->freeLabels();
+ void fail() {
+ _vm->_gfx->patchBackground(_emptySlots, SLOT_X, SLOT_Y, false);
+ _vm->_gfx->hideLabel(_labels[0]);
+ _vm->_gfx->showLabel(_labels[1], 60, 30);
+ _startTime = g_system->getMillis();
+ _state = DELAY;
+ }
+
+ void success() {
+ _vm->_gfx->freeLabels();
+ _vm->_gfx->setBlackPalette();
+ _emptySlots.free();
+
+ // actually select character
+ int character = -1;
+ if (_points[0] >= _points[1] && _points[0] >= _points[2]) {
+ character = CHAR_DINO;
+ } else
+ if (_points[1] >= _points[0] && _points[1] >= _points[2]) {
+ character = CHAR_DONNA;
+ } else
+ if (_points[2] >= _points[0] && _points[2] >= _points[1]) {
+ character = CHAR_DOUGH;
+ } else {
+ error("If you read this, either your CPU or transivity is broken (we believe the former).");
+ }
+
+ _vm->_inTestResult = false;
+ _vm->cleanupGame();
+ _vm->scheduleLocationSwitch(_charStartLocation[character]);
+ }
+
+ virtual MenuInputState* run() {
+ MenuInputState* nextState = this;
+
+ switch (_state) {
+ case DELAY:
+ delay();
+ break;
+
+ case CHOICE:
+ choice();
+ break;
+
+ case FAIL:
+ fail();
+ break;
+
+ case SUCCESS:
+ success();
+ nextState = 0;
+ break;
+
+ default:
+ error("unknown state in SelectCharacterInputState");
+ }
+
+ return nextState;
+ }
+
+ virtual void enter() {
+ _vm->_soundMan->stopMusic();
+ _vm->_disk->selectArchive((_vm->getFeatures() & GF_DEMO) ? "disk0" : "disk1");
+ _vm->showSlide("password");
+
+ _emptySlots.create(BLOCK_WIDTH * 8, BLOCK_HEIGHT, 1);
+ Common::Rect rect(SLOT_X, SLOT_Y, SLOT_X + BLOCK_WIDTH * 8, SLOT_Y + BLOCK_HEIGHT);
+ _vm->_gfx->grabBackground(rect, _emptySlots);
+
+ _labels[0] = _vm->_gfx->createLabel(_vm->_introFont, introMsg1[_vm->getInternLanguage()], 1);
+ _labels[1] = _vm->_gfx->createLabel(_vm->_introFont, introMsg2[_vm->getInternLanguage()], 1);
+
+ cleanup();
+
+ _vm->setArrowCursor();
+ _vm->_input->setMouseState(MOUSE_ENABLED_SHOW);
+ _state = CHOICE;
+ }
+};
+
+const char *SelectCharacterInputState_NS::introMsg1[4] = {
+ "INSERISCI IL CODICE",
+ "ENTREZ CODE",
+ "ENTER CODE",
+ "GIB DEN KODE EIN"
+};
+
+const char *SelectCharacterInputState_NS::introMsg2[4] = {
+ "CODICE ERRATO",
+ "CODE ERRONE",
+ "WRONG CODE",
+ "GIB DEN KODE EIN"
+};
+
+const uint16 SelectCharacterInputState_NS::_amigaKeys[][PASSWORD_LEN] = {
+ { 5, 3, 6, 2, 2, 7 }, // dino
+ { 0, 3, 6, 2, 2, 6 }, // donna
+ { 1, 3 ,7, 2, 4, 6 } // dough
+};
+
+const uint16 SelectCharacterInputState_NS::_pcKeys[][PASSWORD_LEN] = {
+ { 5, 3, 6, 1, 4, 7 }, // dino
+ { 0, 2, 8, 5, 5, 1 }, // donna
+ { 1, 7 ,7, 2, 2, 6 } // dough
+};
+
+const char *SelectCharacterInputState_NS::_charStartLocation[] = {
+ "test.dino",
+ "test.donna",
+ "test.dough"
+};
- return _si ? LOAD_GAME : NEW_GAME;
-}
-static const Common::Rect codeSelectBlocks[9] = {
+const Common::Rect SelectCharacterInputState_NS::codeSelectBlocks[9] = {
Common::Rect( 111, 129, 127, 153 ), // na
Common::Rect( 128, 120, 144, 144 ), // wa
Common::Rect( 145, 111, 161, 135 ), // ra
@@ -350,7 +606,7 @@ static const Common::Rect codeSelectBlocks[9] = {
Common::Rect( 247, 57, 263, 81 ) // ka
};
-static const Common::Rect codeTrueBlocks[9] = {
+const Common::Rect SelectCharacterInputState_NS::codeTrueBlocks[9] = {
Common::Rect( 112, 130, 128, 154 ),
Common::Rect( 129, 121, 145, 145 ),
Common::Rect( 146, 112, 162, 136 ),
@@ -363,146 +619,219 @@ static const Common::Rect codeTrueBlocks[9] = {
};
-int Parallaction_ns::guiGetSelectedBlock(const Common::Point &p) {
+class ShowCreditsInputState_NS : public MenuInputState {
+ Parallaction_ns *_vm;
+ int _current;
+ uint32 _startTime;
- int selection = -1;
+ struct Credit {
+ const char *_role;
+ const char *_name;
+ };
- for (uint16 i = 0; i < 9; i++) {
- if (codeSelectBlocks[i].contains(p)) {
- selection = i;
- break;
- }
+ static const Credit _credits[6];
+
+public:
+ ShowCreditsInputState_NS(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("showcredits", helper), _vm(vm) {
}
- if ((selection != -1) && (getPlatform() == Common::kPlatformAmiga)) {
- _gfx->invertBackground(codeTrueBlocks[selection]);
- _gfx->updateScreen();
- beep();
- g_system->delayMillis(100);
- _gfx->invertBackground(codeTrueBlocks[selection]);
- _gfx->updateScreen();
+ void drawCurrentLabel() {
+ uint id[2];
+ id[0] = _vm->_gfx->createLabel(_vm->_menuFont, _credits[_current]._role, 1);
+ id[1] = _vm->_gfx->createLabel(_vm->_menuFont, _credits[_current]._name, 1);
+ _vm->_gfx->showLabel(id[0], CENTER_LABEL_HORIZONTAL, 80);
+ _vm->_gfx->showLabel(id[1], CENTER_LABEL_HORIZONTAL, 100);
}
- return selection;
-}
+ virtual MenuInputState* run() {
+ if (_current == -1) {
+ _startTime = g_system->getMillis();
+ _current = 0;
+ drawCurrentLabel();
+ return this;
+ }
-//
-// character selection and protection
-//
-int Parallaction_ns::guiSelectCharacter() {
- debugC(1, kDebugMenu, "Parallaction_ns::guiselectCharacter()");
+ int event = _vm->_input->getLastButtonEvent();
+ uint32 curTime = g_system->getMillis();
+ if ((event == kMouseLeftUp) || (curTime - _startTime > 5500)) {
+ _current++;
+ _startTime = curTime;
+ _vm->_gfx->freeLabels();
- setArrowCursor();
- _soundMan->stopMusic();
+ if (_current == 6) {
+ return _helper->getState("endintro");
+ }
- _disk->selectArchive((getFeatures() & GF_DEMO) ? "disk0" : "disk1");
+ drawCurrentLabel();
+ }
- showSlide("password");
+ return this;
+ }
+ virtual void enter() {
+ _current = -1;
+ _vm->_input->setMouseState(MOUSE_DISABLED);
+ }
+};
- const uint16 (*keys)[PASSWORD_LEN] = (getPlatform() == Common::kPlatformAmiga && (getFeatures() & GF_LANG_MULT)) ? _amigaKeys : _pcKeys;
- uint16 _di = 0;
- byte points[3] = { 0, 0, 0 };
+const ShowCreditsInputState_NS::Credit ShowCreditsInputState_NS::_credits[6] = {
+ {"Music and Sound Effects", "MARCO CAPRELLI"},
+ {"PC Version", "RICCARDO BALLARINO"},
+ {"Project Manager", "LOVRANO CANEPA"},
+ {"Production", "BRUNO BOZ"},
+ {"Special Thanks to", "LUIGI BENEDICENTI - GILDA and DANILO"},
+ {"Copyright 1992 Euclidea s.r.l ITALY", "All rights reserved"}
+};
- bool fail;
+class EndIntroInputState_NS : public MenuInputState {
+ Parallaction_ns *_vm;
+ bool _isDemo;
- uint id[2];
- id[0] = _gfx->createLabel(_introFont, introMsg1[_language], 1);
- id[1] = _gfx->createLabel(_introFont, introMsg2[_language], 1);
+public:
+ EndIntroInputState_NS(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("endintro", helper), _vm(vm) {
+ _isDemo = (_vm->getFeatures() & GF_DEMO) != 0;
+ }
- Graphics::Surface v14;
- v14.create(BLOCK_WIDTH * 8, BLOCK_HEIGHT, 1);
- Common::Rect rect(SLOT_X, SLOT_Y, SLOT_X + BLOCK_WIDTH * 8, SLOT_Y + BLOCK_HEIGHT);
- _gfx->grabBackground(rect, v14);
+ virtual MenuInputState* run() {
- Graphics::Surface block;
- block.create(BLOCK_WIDTH, BLOCK_HEIGHT, 1);
+ int event = _vm->_input->getLastButtonEvent();
+ if (event != kMouseLeftUp) {
+ return this;
+ }
- Common::Point p;
+ if (_isDemo) {
+ _engineFlags |= kEngineQuit;
+ return 0;
+ }
- while (true) {
+ _vm->_gfx->freeLabels();
+ return _helper->getState("selectcharacter");
+ }
- points[0] = 0;
- points[1] = 0;
- points[2] = 0;
- fail = false;
+ virtual void enter() {
+ _vm->_soundMan->stopMusic();
+ _vm->_input->setMouseState(MOUSE_DISABLED);
- _gfx->hideLabel(id[1]);
- _gfx->showLabel(id[0], 60, 30);
+ if (!_isDemo) {
+ int label = _vm->_gfx->createLabel(_vm->_menuFont, "CLICK MOUSE BUTTON TO START", 1);
+ _vm->_gfx->showLabel(label, CENTER_LABEL_HORIZONTAL, 80);
+ }
+ }
+};
- _di = 0;
- while (_di < PASSWORD_LEN) {
- _input->waitUntilLeftClick();
- _input->getCursorPos(p);
+class EndPartInputState_NS : public MenuInputState {
+ Parallaction_ns *_vm;
+ bool _allPartsComplete;
- int _si = guiGetSelectedBlock(p);
+ // part completion messages
+ static const char *endMsg0[4];
+ static const char *endMsg1[4];
+ static const char *endMsg2[4];
+ static const char *endMsg3[4];
+ // game completion messages
+ static const char *endMsg4[4];
+ static const char *endMsg5[4];
+ static const char *endMsg6[4];
+ static const char *endMsg7[4];
- if (_si != -1) {
- _gfx->grabBackground(codeTrueBlocks[_si], block);
- _gfx->patchBackground(block, _di * SLOT_WIDTH + SLOT_X, SLOT_Y, false);
- if (keys[0][_di] == _si) {
- points[0]++;
- } else
- if (keys[1][_di] == _si) {
- points[1]++;
- } else
- if (keys[2][_di] == _si) {
- points[2]++;
- } else {
- fail = true;
- }
+public:
+ EndPartInputState_NS(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("endpart", helper), _vm(vm) {
+ }
- // build user preference
- points[0] += (keys[0][_di] == _si);
- points[1] += (keys[1][_di] == _si);
- points[2] += (keys[2][_di] == _si);
+ virtual MenuInputState* run() {
+ int event = _vm->_input->getLastButtonEvent();
+ if (event != kMouseLeftUp) {
+ return this;
+ }
- _di++;
- }
+ _vm->_gfx->freeLabels();
+ if (_allPartsComplete) {
+ _vm->scheduleLocationSwitch("estgrotta.drki");
+ return 0;
}
- if (!fail) {
- break;
+ return _helper->getState("selectcharacter");
+ }
+
+ virtual void enter() {
+ _allPartsComplete = _vm->allPartsComplete();
+ _vm->_input->setMouseState(MOUSE_DISABLED);
+
+ uint id[4];
+ if (_allPartsComplete) {
+ id[0] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg4[_language], 1);
+ id[1] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg5[_language], 1);
+ id[2] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg6[_language], 1);
+ id[3] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg7[_language], 1);
+ } else {
+ id[0] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg0[_language], 1);
+ id[1] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg1[_language], 1);
+ id[2] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg2[_language], 1);
+ id[3] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg3[_language], 1);
}
- _gfx->patchBackground(v14, SLOT_X, SLOT_Y, false);
+ _vm->_gfx->showLabel(id[0], CENTER_LABEL_HORIZONTAL, 70);
+ _vm->_gfx->showLabel(id[1], CENTER_LABEL_HORIZONTAL, 100);
+ _vm->_gfx->showLabel(id[2], CENTER_LABEL_HORIZONTAL, 130);
+ _vm->_gfx->showLabel(id[3], CENTER_LABEL_HORIZONTAL, 160);
+ }
+};
- _gfx->hideLabel(id[0]);
- _gfx->showLabel(id[1], 60, 30);
+// part completion messages
+const char *EndPartInputState_NS::endMsg0[] = {"COMPLIMENTI!", "BRAVO!", "CONGRATULATIONS!", "PRIMA!"};
+const char *EndPartInputState_NS::endMsg1[] = {"HAI FINITO QUESTA PARTE", "TU AS COMPLETE' CETTE AVENTURE", "YOU HAVE COMPLETED THIS PART", "DU HAST EIN ABENTEUER ERFOLGREICH"};
+const char *EndPartInputState_NS::endMsg2[] = {"ORA COMPLETA IL RESTO ", "AVEC SUCCES.", "NOW GO ON WITH THE REST OF", "ZU ENDE GEFUHRT"};
+const char *EndPartInputState_NS::endMsg3[] = {"DELL' AVVENTURA", "CONTINUE AVEC LES AUTRES", "THIS ADVENTURE", "MACH' MIT DEN ANDEREN WEITER"};
+// game completion messages
+const char *EndPartInputState_NS::endMsg4[] = {"COMPLIMENTI!", "BRAVO!", "CONGRATULATIONS!", "PRIMA!"};
+const char *EndPartInputState_NS::endMsg5[] = {"HAI FINITO LE TRE PARTI", "TU AS COMPLETE' LES TROIS PARTIES", "YOU HAVE COMPLETED THE THREE PARTS", "DU HAST DREI ABENTEURE ERFOLGREICH"};
+const char *EndPartInputState_NS::endMsg6[] = {"DELL' AVVENTURA", "DE L'AVENTURE", "OF THIS ADVENTURE", "ZU ENDE GEFUHRT"};
+const char *EndPartInputState_NS::endMsg7[] = {"ED ORA IL GRAN FINALE ", "ET MAINTENANT LE GRAND FINAL", "NOW THE GREAT FINAL", "UND YETZT DER GROSSE SCHLUSS!"};
+
+void Parallaction_ns::startGui() {
+ _disk->selectArchive((getFeatures() & GF_DEMO) ? "disk0" : "disk1");
- _gfx->updateScreen();
+ _menuHelper = new MenuInputHelper;
+ assert(_menuHelper);
- g_system->delayMillis(2000);
- }
+ new SelectGameInputState_NS(this, _menuHelper);
+ new LoadGameInputState_NS(this, _menuHelper);
+ new NewGameInputState_NS(this, _menuHelper);
+ new StartDemoInputState_NS(this, _menuHelper);
+ new SelectCharacterInputState_NS(this, _menuHelper);
+ new ChooseLanguageInputState_NS(this, _menuHelper);
+ new SplashInputState1_NS(this, _menuHelper);
+ new SplashInputState0_NS(this, _menuHelper);
+ _menuHelper->setState("intro0");
- _gfx->freeLabels();
+ _input->_inputMode = Input::kInputModeMenu;
+}
- _gfx->setBlackPalette();
- _gfx->updateScreen();
+void Parallaction_ns::startCreditSequence() {
+ _menuHelper = new MenuInputHelper;
+ assert(_menuHelper);
- v14.free();
+ new ShowCreditsInputState_NS(this, _menuHelper);
+ new EndIntroInputState_NS(this, _menuHelper);
+ new SelectCharacterInputState_NS(this, _menuHelper);
+ _menuHelper->setState("showcredits");
+ _input->_inputMode = Input::kInputModeMenu;
+}
- // actually select character
+void Parallaction_ns::startEndPartSequence() {
+ _menuHelper = new MenuInputHelper;
+ assert(_menuHelper);
- int character = -1;
- if (points[0] >= points[1] && points[0] >= points[2]) {
- character = CHAR_DINO;
- } else
- if (points[1] >= points[0] && points[1] >= points[2]) {
- character = CHAR_DONNA;
- } else
- if (points[2] >= points[0] && points[2] >= points[1]) {
- character = CHAR_DOUGH;
- } else {
- error("If you read this, either your CPU or transivity is broken (we believe the former).");
- }
+ new EndPartInputState_NS(this, _menuHelper);
+ new SelectCharacterInputState_NS(this, _menuHelper);
+ _menuHelper->setState("endpart");
- return character;
+ _input->_inputMode = Input::kInputModeMenu;
}
diff --git a/engines/parallaction/input.cpp b/engines/parallaction/input.cpp
index 9601ae3b36..287618e803 100644
--- a/engines/parallaction/input.cpp
+++ b/engines/parallaction/input.cpp
@@ -36,25 +36,23 @@ namespace Parallaction {
// loops which could possibly be merged into this one with some effort in changing
// caller code, i.e. adding condition checks.
//
-uint16 Input::readInput() {
+void Input::readInput() {
Common::Event e;
- uint16 KeyDown = 0;
_mouseButtons = kMouseNone;
- _lastKeyDownAscii = -1;
+ _hasKeyPressEvent = false;
Common::EventManager *eventMan = _vm->_system->getEventManager();
while (eventMan->pollEvent(e)) {
switch (e.type) {
case Common::EVENT_KEYDOWN:
- _lastKeyDownAscii = e.kbd.ascii;
+ _hasKeyPressEvent = true;
+ _keyPressed = e.kbd;
+
if (e.kbd.flags == Common::KBD_CTRL && e.kbd.keycode == 'd')
_vm->_debugger->attach();
- if (_vm->getFeatures() & GF_DEMO) break;
- if (e.kbd.keycode == Common::KEYCODE_l) KeyDown = kEvLoadGame;
- if (e.kbd.keycode == Common::KEYCODE_s) KeyDown = kEvSaveGame;
break;
case Common::EVENT_LBUTTONDOWN:
@@ -83,7 +81,7 @@ uint16 Input::readInput() {
case Common::EVENT_QUIT:
_engineFlags |= kEngineQuit;
- return KeyDown;
+ return;
default:
break;
@@ -95,13 +93,13 @@ uint16 Input::readInput() {
if (_vm->_debugger->isAttached())
_vm->_debugger->onFrame();
- return KeyDown;
+ return;
}
bool Input::getLastKeyDown(uint16 &ascii) {
- ascii = _lastKeyDownAscii;
- return (_lastKeyDownAscii != -1);
+ ascii = _keyPressed.ascii;
+ return (_hasKeyPressEvent);
}
// FIXME: see comment for readInput()
@@ -128,64 +126,36 @@ void Input::waitForButtonEvent(uint32 buttonEventMask, int32 timeout) {
}
-// FIXME: see comment for readInput()
-void Input::waitUntilLeftClick() {
-
- do {
- readInput();
- _vm->_gfx->updateScreen();
- _vm->_system->delayMillis(30);
- } while (_mouseButtons != kMouseLeftUp);
-
- return;
-}
-
void Input::updateGameInput() {
- int16 keyDown = readInput();
+ readInput();
- debugC(3, kDebugInput, "translateInput: input flags (%i, %i, %i, %i)",
- !_mouseHidden,
- (_engineFlags & kEngineBlockInput) == 0,
- (_engineFlags & kEngineWalking) == 0,
- (_engineFlags & kEngineChangeLocation) == 0
- );
-
- if ((_mouseHidden) ||
- (_engineFlags & kEngineBlockInput) ||
+ if (!isMouseEnabled() ||
(_engineFlags & kEngineWalking) ||
(_engineFlags & kEngineChangeLocation)) {
+ debugC(3, kDebugInput, "updateGameInput: input flags (mouse: %i, walking: %i, changeloc: %i)",
+ isMouseEnabled(),
+ (_engineFlags & kEngineWalking) == 0,
+ (_engineFlags & kEngineChangeLocation) == 0
+ );
+
return;
}
- if (keyDown == kEvQuitGame) {
- _inputData._event = kEvQuitGame;
- } else
- if (keyDown == kEvSaveGame) {
- _inputData._event = kEvSaveGame;
- } else
- if (keyDown == kEvLoadGame) {
- _inputData._event = kEvLoadGame;
- } else {
+ if (_hasKeyPressEvent && (_vm->getFeatures() & GF_DEMO) == 0) {
+ if (_keyPressed.keycode == Common::KEYCODE_l) _inputData._event = kEvLoadGame;
+ if (_keyPressed.keycode == Common::KEYCODE_s) _inputData._event = kEvSaveGame;
+ }
+
+ if (_inputData._event == kEvNone) {
_inputData._mousePos = _mousePos;
- _inputData._event = kEvNone;
- if (!translateGameInput()) {
- translateInventoryInput();
- }
+ translateGameInput();
}
}
-void Input::updateCommentInput() {
- waitUntilLeftClick();
-
- _vm->hideDialogueStuff();
- _vm->_gfx->setHalfbriteMode(false);
-
- _inputMode = kInputModeGame;
-}
InputData* Input::updateInput() {
@@ -193,15 +163,18 @@ InputData* Input::updateInput() {
switch (_inputMode) {
case kInputModeComment:
- updateCommentInput();
+ case kInputModeDialogue:
+ case kInputModeMenu:
+ readInput();
break;
case kInputModeGame:
updateGameInput();
break;
- case kInputModeDialogue:
+ case kInputModeInventory:
readInput();
+ updateInventoryInput();
break;
}
@@ -230,38 +203,45 @@ void Input::stopHovering() {
_vm->_gfx->hideFloatingLabel();
}
+void Input::takeAction(ZonePtr z) {
+ stopHovering();
+ _vm->pauseJobs();
+ _vm->runZone(z);
+ _vm->resumeJobs();
+}
+
+void Input::walkTo(const Common::Point &dest) {
+ stopHovering();
+ _vm->setArrowCursor();
+ _vm->_char.scheduleWalk(dest.x, dest.y);
+}
bool Input::translateGameInput() {
- if ((_engineFlags & kEnginePauseJobs) || (_engineFlags & kEngineInventory)) {
+ if (_engineFlags & kEnginePauseJobs) {
return false;
}
- if (_actionAfterWalk) {
+ if (_hasDelayedAction) {
// if walking is over, then take programmed action
- _inputData._event = kEvAction;
- _actionAfterWalk = false;
+ takeAction(_delayedActionZone);
+ _hasDelayedAction = false;
+ _delayedActionZone = nullZonePtr;
return true;
}
if (_mouseButtons == kMouseRightDown) {
// right button down shows inventory
-
- if (_vm->hitZone(kZoneYou, _mousePos.x, _mousePos.y) && (_activeItem._id != 0)) {
- _activeItem._index = (_activeItem._id >> 16) & 0xFFFF;
- _engineFlags |= kEngineDragging;
- }
-
- _inputData._event = kEvOpenInventory;
- _transCurrentHoverItem = -1;
+ enterInventoryMode();
return true;
}
// test if mouse is hovering on an interactive zone for the currently selected inventory item
ZonePtr z = _vm->hitZone(_activeItem._id, _mousePos.x, _mousePos.y);
+ Common::Point dest(_mousePos);
if (((_mouseButtons == kMouseLeftUp) && (_activeItem._id == 0) && ((_engineFlags & kEngineWalking) == 0)) && ((!z) || ((z->_type & 0xFFFF) != kZoneCommand))) {
- _inputData._event = kEvWalk;
+ walkTo(dest);
return true;
}
@@ -275,16 +255,17 @@ bool Input::translateGameInput() {
_inputData._zone = z;
if (z->_flags & kFlagsNoWalk) {
// character doesn't need to walk to take specified action
- _inputData._event = kEvAction;
-
+ takeAction(z);
} else {
// action delayed: if Zone defined a moveto position the character is programmed to move there,
// else it will move to the mouse position
- _inputData._event = kEvWalk;
- _actionAfterWalk = true;
+ _delayedActionZone = z;
+ _hasDelayedAction = true;
if (z->_moveTo.y != 0) {
- _inputData._mousePos = z->_moveTo;
+ dest = z->_moveTo;
}
+
+ walkTo(dest);
}
_vm->beep();
@@ -293,31 +274,40 @@ bool Input::translateGameInput() {
}
return true;
-
}
-bool Input::translateInventoryInput() {
- if ((_engineFlags & kEngineInventory) == 0) {
- return false;
+void Input::enterInventoryMode() {
+ bool hitCharacter = _vm->hitZone(kZoneYou, _mousePos.x, _mousePos.y);
+
+ if (hitCharacter) {
+ if (_activeItem._id != 0) {
+ _activeItem._index = (_activeItem._id >> 16) & 0xFFFF;
+ _engineFlags |= kEngineDragging;
+ } else {
+ _vm->setArrowCursor();
+ }
}
- // in inventory
- int16 _si = _vm->getHoverInventoryItem(_mousePos.x, _mousePos.y);
+ stopHovering();
+ _vm->pauseJobs();
+ _vm->openInventory();
- if (_mouseButtons == kMouseRightUp) {
- // right up hides inventory
+ _transCurrentHoverItem = -1;
- _inputData._event = kEvCloseInventory;
- _inputData._inventoryIndex = _vm->getHoverInventoryItem(_mousePos.x, _mousePos.y);
- _vm->highlightInventoryItem(-1); // disable
+ _inputMode = kInputModeInventory;
+}
- if ((_engineFlags & kEngineDragging) == 0) {
- return true;
- }
+void Input::exitInventoryMode() {
+ // right up hides inventory
+
+ int pos = _vm->getHoverInventoryItem(_mousePos.x, _mousePos.y);
+ _vm->highlightInventoryItem(-1); // disable
+
+ if ((_engineFlags & kEngineDragging)) {
_engineFlags &= ~kEngineDragging;
- ZonePtr z = _vm->hitZone(kZoneMerge, _activeItem._index, _vm->getInventoryItemIndex(_inputData._inventoryIndex));
+ ZonePtr z = _vm->hitZone(kZoneMerge, _activeItem._index, _vm->getInventoryItemIndex(pos));
if (z) {
_vm->dropItem(z->u.merge->_obj1);
@@ -326,25 +316,61 @@ bool Input::translateInventoryInput() {
_vm->_cmdExec->run(z->_commands);
}
- return true;
}
- if (_si == _transCurrentHoverItem) {
- _inputData._event = kEvNone;
+ _vm->closeInventory();
+ if (pos == -1) {
+ _vm->setArrowCursor();
+ } else {
+ const InventoryItem *item = _vm->getInventoryItem(pos);
+ if (item->_index != 0) {
+ _activeItem._id = item->_id;
+ _vm->setInventoryCursor(item->_index);
+ }
+ }
+ _vm->resumeJobs();
+
+ _inputMode = kInputModeGame;
+}
+
+bool Input::updateInventoryInput() {
+ if (_mouseButtons == kMouseRightUp) {
+ exitInventoryMode();
return true;
}
- _transCurrentHoverItem = _si;
- _inputData._event = kEvHoverInventory;
- _inputData._inventoryIndex = _si;
+ int16 _si = _vm->getHoverInventoryItem(_mousePos.x, _mousePos.y);
+ if (_si != _transCurrentHoverItem) {
+ _transCurrentHoverItem = _si;
+ _vm->highlightInventoryItem(_si); // enable
+ }
+
return true;
}
-void Input::showCursor(bool visible) {
- _mouseHidden = !visible;
- _vm->_system->showMouse(visible);
+void Input::setMouseState(MouseTriState state) {
+ assert(state == MOUSE_ENABLED_SHOW || state == MOUSE_ENABLED_HIDE || state == MOUSE_DISABLED);
+ _mouseState = state;
+
+ switch (_mouseState) {
+ case MOUSE_ENABLED_HIDE:
+ case MOUSE_DISABLED:
+ _vm->_system->showMouse(false);
+ break;
+
+ case MOUSE_ENABLED_SHOW:
+ _vm->_system->showMouse(true);
+ break;
+ }
+}
+
+MouseTriState Input::getMouseState() {
+ return _mouseState;
}
+bool Input::isMouseEnabled() {
+ return (_mouseState == MOUSE_ENABLED_SHOW) || (_mouseState == MOUSE_ENABLED_HIDE);
+}
} // namespace Parallaction
diff --git a/engines/parallaction/input.h b/engines/parallaction/input.h
index f260352dba..c1e912db74 100644
--- a/engines/parallaction/input.h
+++ b/engines/parallaction/input.h
@@ -26,6 +26,8 @@
#ifndef PARALLACTION_INPUT_H
#define PARALLACTION_INPUT_H
+#include "common/keyboard.h"
+
#include "parallaction/objects.h"
#include "parallaction/inventory.h"
@@ -47,51 +49,65 @@ struct InputData {
uint _label;
};
+enum MouseTriState {
+ MOUSE_ENABLED_SHOW,
+ MOUSE_ENABLED_HIDE,
+ MOUSE_DISABLED
+};
+
class Input {
void updateGameInput();
- void updateCommentInput();
// input-only
InputData _inputData;
- bool _actionAfterWalk; // actived when the character needs to move before taking an action
- // these two could/should be merged as they carry on the same duty in two member functions,
- // respectively processInput and translateInput
+
+ bool _hasKeyPressEvent;
+ Common::KeyState _keyPressed;
+
+ bool _hasDelayedAction; // actived when the character needs to move before taking an action
+ ZonePtr _delayedActionZone;
+
int16 _transCurrentHoverItem;
InputData *translateInput();
bool translateGameInput();
- bool translateInventoryInput();
+ bool updateInventoryInput();
+ void takeAction(ZonePtr z);
+ void walkTo(const Common::Point &dest);
Parallaction *_vm;
Common::Point _mousePos;
uint16 _mouseButtons;
- int32 _lastKeyDownAscii;
- bool _mouseHidden;
ZonePtr _hoverZone;
+ void enterInventoryMode();
+ void exitInventoryMode();
+
public:
enum {
kInputModeGame = 0,
kInputModeComment = 1,
- kInputModeDialogue = 2
+ kInputModeDialogue = 2,
+ kInputModeInventory = 3,
+ kInputModeMenu = 4
};
Input(Parallaction *vm) : _vm(vm) {
_transCurrentHoverItem = 0;
- _actionAfterWalk = false; // actived when the character needs to move before taking an action
- _mouseHidden = false;
+ _hasDelayedAction = false; // actived when the character needs to move before taking an action
+ _mouseState = MOUSE_DISABLED;
_activeItem._index = 0;
_activeItem._id = 0;
_mouseButtons = 0;
+ _delayedActionZone = nullZonePtr;
}
virtual ~Input() { }
- void showCursor(bool visible);
void getCursorPos(Common::Point& p) {
p = _mousePos;
}
@@ -99,15 +115,20 @@ public:
int _inputMode;
InventoryItem _activeItem;
- uint16 readInput();
+ void 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();
+
+ MouseTriState _mouseState;
+
+ void setMouseState(MouseTriState state);
+ MouseTriState getMouseState();
+ bool isMouseEnabled();
};
} // namespace Parallaction
diff --git a/engines/parallaction/inventory.cpp b/engines/parallaction/inventory.cpp
index 58848196d7..7b92974205 100644
--- a/engines/parallaction/inventory.cpp
+++ b/engines/parallaction/inventory.cpp
@@ -30,23 +30,58 @@
namespace Parallaction {
-//
-// inventory is a grid made of (at most) 30 cells, 24x24 pixels each,
-// arranged in 6 lines
-//
-// inventory items are stored in cnv files in a 32x24 grid
-// but only 24x24 pixels are actually copied to graphic memory
-//
+
+/*
+#define INVENTORYITEM_PITCH 32
+#define INVENTORYITEM_WIDTH 24
+#define INVENTORYITEM_HEIGHT 24
#define INVENTORY_MAX_ITEMS 30
-#define INVENTORY_FIRST_ITEM 4 // first four entries are used up by verbs
#define INVENTORY_ITEMS_PER_LINE 5
#define INVENTORY_LINES 6
#define INVENTORY_WIDTH (INVENTORY_ITEMS_PER_LINE*INVENTORYITEM_WIDTH)
#define INVENTORY_HEIGHT (INVENTORY_LINES*INVENTORYITEM_HEIGHT)
-
+*/
+
+InventoryItem _verbs_NS[] = {
+ { 1, kZoneDoor },
+ { 3, kZoneExamine },
+ { 2, kZoneGet },
+ { 4, kZoneSpeak },
+ { 0, 0 }
+};
+
+InventoryItem _verbs_BR[] = {
+ { 1, kZoneBox },
+ { 2, kZoneGet },
+ { 3, kZoneExamine },
+ { 4, kZoneSpeak },
+ { 0, 0 }
+};
+
+InventoryProperties _invProps_NS = {
+ 32, // INVENTORYITEM_PITCH
+ 24, // INVENTORYITEM_WIDTH
+ 24, // INVENTORYITEM_HEIGHT
+ 30, // INVENTORY_MAX_ITEMS
+ 5, // INVENTORY_ITEMS_PER_LINE
+ 6, // INVENTORY_LINES
+ 5 * 24, // INVENTORY_WIDTH =(INVENTORY_ITEMS_PER_LINE*INVENTORYITEM_WIDTH)
+ 6 * 24 // INVENTORY_HEIGHT = (INVENTORY_LINES*INVENTORYITEM_HEIGHT)
+};
+
+InventoryProperties _invProps_BR = {
+ 51, // INVENTORYITEM_PITCH
+ 51, // INVENTORYITEM_WIDTH
+ 51, // INVENTORYITEM_HEIGHT
+ 48, // INVENTORY_MAX_ITEMS
+ 6, // INVENTORY_ITEMS_PER_LINE
+ 8, // INVENTORY_LINES
+ 6 * 51, // INVENTORY_WIDTH =(INVENTORY_ITEMS_PER_LINE*INVENTORYITEM_WIDTH)
+ 8 * 51 // INVENTORY_HEIGHT = (INVENTORY_LINES*INVENTORYITEM_HEIGHT)
+};
int16 Parallaction::getHoverInventoryItem(int16 x, int16 y) {
return _inventoryRenderer->hitTest(Common::Point(x,y));
@@ -91,8 +126,19 @@ int16 Parallaction::getInventoryItemIndex(int16 pos) {
}
void Parallaction::initInventory() {
- _inventory = new Inventory(INVENTORY_MAX_ITEMS);
- _inventoryRenderer = new InventoryRenderer(this);
+ InventoryProperties *props;
+ InventoryItem *verbs;
+
+ if (getGameType() == GType_Nippon) {
+ props = &_invProps_NS;
+ verbs = _verbs_NS;
+ } else {
+ props = &_invProps_BR;
+ verbs = _verbs_BR;
+ }
+
+ _inventory = new Inventory(props, verbs);
+ _inventoryRenderer = new InventoryRenderer(this, props);
_inventoryRenderer->bindInventory(_inventory);
}
@@ -119,8 +165,8 @@ void Parallaction::closeInventory() {
-InventoryRenderer::InventoryRenderer(Parallaction *vm) : _vm(vm) {
- _surf.create(INVENTORY_WIDTH, INVENTORY_HEIGHT, 1);
+InventoryRenderer::InventoryRenderer(Parallaction *vm, InventoryProperties *props) : _vm(vm), _props(props) {
+ _surf.create(_props->_width, _props->_height, 1);
}
InventoryRenderer::~InventoryRenderer() {
@@ -131,15 +177,13 @@ void InventoryRenderer::showInventory() {
if (!_inv)
error("InventoryRenderer not bound to inventory");
- _engineFlags |= kEngineInventory;
-
uint16 lines = getNumLines();
Common::Point p;
_vm->_input->getCursorPos(p);
- _pos.x = CLIP(p.x - (INVENTORY_WIDTH / 2), 0, (int)(_vm->_screenWidth - INVENTORY_WIDTH));
- _pos.y = CLIP(p.y - 2 - (lines * INVENTORYITEM_HEIGHT), 0, (int)(_vm->_screenHeight - lines * INVENTORYITEM_HEIGHT));
+ _pos.x = CLIP((int)(p.x - (_props->_width / 2)), 0, (int)(_vm->_screenWidth - _props->_width));
+ _pos.y = CLIP((int)(p.y - 2 - (lines * _props->_itemHeight)), 0, (int)(_vm->_screenHeight - lines * _props->_itemHeight));
refresh();
}
@@ -147,13 +191,11 @@ void InventoryRenderer::showInventory() {
void InventoryRenderer::hideInventory() {
if (!_inv)
error("InventoryRenderer not bound to inventory");
-
- _engineFlags &= ~kEngineInventory;
}
void InventoryRenderer::getRect(Common::Rect& r) const {
- r.setWidth(INVENTORY_WIDTH);
- r.setHeight(INVENTORYITEM_HEIGHT * getNumLines());
+ r.setWidth(_props->_width);
+ r.setHeight(_props->_itemHeight * getNumLines());
r.moveTo(_pos);
}
@@ -163,35 +205,36 @@ ItemPosition InventoryRenderer::hitTest(const Common::Point &p) const {
if (!r.contains(p))
return -1;
- return ((p.x - _pos.x) / INVENTORYITEM_WIDTH) + (INVENTORY_ITEMS_PER_LINE * ((p.y - _pos.y) / INVENTORYITEM_HEIGHT));
+ return ((p.x - _pos.x) / _props->_itemWidth) + (_props->_itemsPerLine * ((p.y - _pos.y) / _props->_itemHeight));
}
-
void InventoryRenderer::drawItem(ItemPosition pos, ItemName name) {
-
Common::Rect r;
getItemRect(pos, r);
+ byte* d = (byte*)_surf.getBasePtr(r.left, r.top);
+ drawItem(name, d, _surf.pitch);
+}
- // FIXME: this will end up in a general blit function
-
+void InventoryRenderer::drawItem(ItemName name, byte *buffer, uint pitch) {
byte* s = _vm->_char._objs->getData(name);
- byte* d = (byte*)_surf.getBasePtr(r.left, r.top);
- for (uint32 i = 0; i < INVENTORYITEM_HEIGHT; i++) {
- memcpy(d, s, INVENTORYITEM_WIDTH);
+ byte* d = buffer;
+ for (uint i = 0; i < _props->_itemHeight; i++) {
+ memcpy(d, s, _props->_itemWidth);
- d += INVENTORY_WIDTH;
- s += INVENTORYITEM_PITCH;
+ s += _props->_itemPitch;
+ d += pitch;
}
}
+
int16 InventoryRenderer::getNumLines() const {
int16 num = _inv->getNumItems();
- return (num / INVENTORY_ITEMS_PER_LINE) + ((num % INVENTORY_ITEMS_PER_LINE) > 0 ? 1 : 0);
+ return (num / _props->_itemsPerLine) + ((num % _props->_itemsPerLine) > 0 ? 1 : 0);
}
void InventoryRenderer::refresh() {
- for (uint16 i = 0; i < INVENTORY_MAX_ITEMS; i++) {
+ for (uint16 i = 0; i < _props->_maxItems; i++) {
ItemName name = _inv->getItemName(i);
drawItem(i, name);
}
@@ -212,25 +255,24 @@ void InventoryRenderer::highlightItem(ItemPosition pos, byte color) {
void InventoryRenderer::getItemRect(ItemPosition pos, Common::Rect &r) {
- r.setHeight(INVENTORYITEM_HEIGHT);
- r.setWidth(INVENTORYITEM_WIDTH);
+ r.setHeight(_props->_itemHeight);
+ r.setWidth(_props->_itemWidth);
- uint16 line = pos / INVENTORY_ITEMS_PER_LINE;
- uint16 col = pos % INVENTORY_ITEMS_PER_LINE;
+ uint16 line = pos / _props->_itemsPerLine;
+ uint16 col = pos % _props->_itemsPerLine;
- r.moveTo(col * INVENTORYITEM_WIDTH, line * INVENTORYITEM_HEIGHT);
+ r.moveTo(col * _props->_itemWidth, line * _props->_itemHeight);
}
+Inventory::Inventory(InventoryProperties *props, InventoryItem *verbs) : _numItems(0), _props(props) {
+ _items = (InventoryItem*)calloc(_props->_maxItems, sizeof(InventoryItem));
-
-Inventory::Inventory(uint16 maxItems) : _maxItems(maxItems), _numItems(0) {
- _items = (InventoryItem*)calloc(_maxItems, sizeof(InventoryItem));
-
- addItem(1, kZoneDoor);
- addItem(3, kZoneExamine);
- addItem(2, kZoneGet);
- addItem(4, kZoneSpeak);
+ int i = 0;
+ for ( ; verbs[i]._id; i++) {
+ addItem(verbs[i]._id, verbs[i]._index);
+ }
+ _numVerbs = i;
}
@@ -241,7 +283,7 @@ Inventory::~Inventory() {
ItemPosition Inventory::addItem(ItemName name, uint32 value) {
debugC(1, kDebugInventory, "addItem(%i, %i)", name, value);
- if (_numItems == INVENTORY_MAX_ITEMS) {
+ if (_numItems == _props->_maxItems) {
debugC(3, kDebugInventory, "addItem: inventory is full");
return -1;
}
@@ -300,9 +342,9 @@ void Inventory::removeItem(ItemName name) {
void Inventory::clear(bool keepVerbs) {
debugC(1, kDebugInventory, "clearInventory()");
- uint first = (keepVerbs ? INVENTORY_FIRST_ITEM : 0);
+ uint first = (keepVerbs ? _numVerbs : 0);
- for (uint16 slot = first; slot < _maxItems; slot++) {
+ for (uint16 slot = first; slot < _numVerbs; slot++) {
_items[slot]._id = 0;
_items[slot]._index = 0;
}
@@ -312,7 +354,7 @@ void Inventory::clear(bool keepVerbs) {
ItemName Inventory::getItemName(ItemPosition pos) const {
- return (pos >= 0 && pos < INVENTORY_MAX_ITEMS) ? _items[pos]._index : 0;
+ return (pos >= 0 && pos < _props->_maxItems) ? _items[pos]._index : 0;
}
const InventoryItem* Inventory::getItem(ItemPosition pos) const {
diff --git a/engines/parallaction/inventory.h b/engines/parallaction/inventory.h
index 8c32c09219..f041627810 100644
--- a/engines/parallaction/inventory.h
+++ b/engines/parallaction/inventory.h
@@ -38,9 +38,19 @@ struct InventoryItem {
uint16 _index; // index to frame in objs file
};
-#define INVENTORYITEM_PITCH 32
-#define INVENTORYITEM_WIDTH 24
-#define INVENTORYITEM_HEIGHT 24
+struct InventoryProperties {
+ uint _itemPitch;
+ uint _itemWidth;
+ uint _itemHeight;
+
+ int _maxItems;
+
+ int _itemsPerLine;
+ int _maxLines;
+
+ int _width;
+ int _height;
+};
#define MAKE_INVENTORY_ID(x) (((x) & 0xFFFF) << 16)
@@ -50,12 +60,14 @@ typedef uint16 ItemName;
class Inventory {
protected:
+ uint16 _numVerbs;
+
InventoryItem *_items;
- uint16 _maxItems;
uint16 _numItems;
+ InventoryProperties *_props;
public:
- Inventory(uint16 maxItems);
+ Inventory(InventoryProperties *props, InventoryItem *verbs);
virtual ~Inventory();
ItemPosition addItem(ItemName name, uint32 value);
@@ -75,6 +87,8 @@ public:
class InventoryRenderer {
Parallaction *_vm;
+ InventoryProperties *_props;
+
Inventory *_inv;
Common::Point _pos;
@@ -87,7 +101,7 @@ protected:
void refresh();
public:
- InventoryRenderer(Parallaction *vm);
+ InventoryRenderer(Parallaction *vm, InventoryProperties *props);
virtual ~InventoryRenderer();
void bindInventory(Inventory *inv) { _inv = inv; }
@@ -97,6 +111,7 @@ public:
ItemPosition hitTest(const Common::Point &p) const;
void highlightItem(ItemPosition pos, byte color);
+ void drawItem(ItemName name, byte *buffer, uint pitch);
byte* getData() const { return (byte*)_surf.pixels; }
diff --git a/engines/parallaction/module.mk b/engines/parallaction/module.mk
index fb867f5285..9d44422541 100644
--- a/engines/parallaction/module.mk
+++ b/engines/parallaction/module.mk
@@ -14,6 +14,7 @@ MODULE_OBJS := \
font.o \
gfxbase.o \
graphics.o \
+ gui.o \
gui_br.o \
gui_ns.o \
input.o \
diff --git a/engines/parallaction/objects.cpp b/engines/parallaction/objects.cpp
index 66025cf0f7..c387484de7 100644
--- a/engines/parallaction/objects.cpp
+++ b/engines/parallaction/objects.cpp
@@ -60,14 +60,14 @@ Animation::~Animation() {
uint16 Animation::width() const {
if (!gfxobj) return 0;
Common::Rect r;
- gfxobj->getRect(0, r);
+ gfxobj->getRect(_frame, r);
return r.width();
}
uint16 Animation::height() const {
if (!gfxobj) return 0;
Common::Rect r;
- gfxobj->getRect(0, r);
+ gfxobj->getRect(_frame, r);
return r.height();
}
@@ -81,6 +81,12 @@ byte* Animation::getFrameData(uint32 index) const {
return gfxobj->getData(index);
}
+void Animation::validateScriptVars() {
+ // this is used to clip values of _frame, _left and _top
+ // which can be screwed up by buggy scripts.
+
+ _frame = CLIP(_frame, (int16)0, (int16)(getFrameNum() - 1));
+}
#define NUM_LOCALS 10
char _localNames[NUM_LOCALS][10];
diff --git a/engines/parallaction/objects.h b/engines/parallaction/objects.h
index 19835da9d0..7e7a811ba6 100644
--- a/engines/parallaction/objects.h
+++ b/engines/parallaction/objects.h
@@ -54,6 +54,7 @@ typedef Common::SharedPtr<Instruction> InstructionPtr;
typedef Common::List<InstructionPtr> InstructionList;
extern InstructionPtr nullInstructionPtr;
+typedef Common::List<Common::Point> PointList;
enum ZoneTypes {
kZoneExamine = 1, // zone displays comment if activated
@@ -67,7 +68,11 @@ enum ZoneTypes {
kZoneNone = 0x100, // used to prevent parsing on peculiar Animations
kZoneTrap = 0x200, // zone activated when character enters
kZoneYou = 0x400, // marks the character
- kZoneCommand = 0x800
+ kZoneCommand = 0x800,
+
+ // BRA specific
+ kZonePath = 0x1000, // defines nodes for assisting walk calculation routines
+ kZoneBox = 0x2000
};
@@ -89,6 +94,7 @@ enum ZoneFlags {
kFlagsYourself = 0x1000,
kFlagsScaled = 0x2000,
kFlagsSelfuse = 0x4000,
+ kFlagsIsAnimation = 0x1000000, // BRA: used in walk code (trap check), to tell is a Zone is an Animation
kFlagsAnimLinked = 0x2000000
};
@@ -256,6 +262,15 @@ struct MergeData { // size = 12
_obj1 = _obj2 = _obj3 = 0;
}
};
+#define MAX_WALKPOINT_LISTS 20
+struct PathData {
+ int _numLists;
+ PointList _lists[MAX_WALKPOINT_LISTS];
+
+ PathData() {
+ _numLists = 0;
+ }
+};
struct TypeData {
GetData *get;
@@ -264,6 +279,8 @@ struct TypeData {
DoorData *door;
HearData *hear;
MergeData *merge;
+ // BRA specific field
+ PathData *path;
TypeData() {
get = NULL;
@@ -272,6 +289,7 @@ struct TypeData {
door = NULL;
hear = NULL;
merge = NULL;
+ path = NULL;
}
};
@@ -432,6 +450,8 @@ struct Animation : public Zone {
virtual uint16 height() const;
uint16 getFrameNum() const;
byte* getFrameData(uint32 index) const;
+
+ void validateScriptVars();
};
class Table {
diff --git a/engines/parallaction/parallaction.cpp b/engines/parallaction/parallaction.cpp
index cd852f7c84..54cb175e46 100644
--- a/engines/parallaction/parallaction.cpp
+++ b/engines/parallaction/parallaction.cpp
@@ -98,6 +98,10 @@ Parallaction::~Parallaction() {
freeCharacter();
destroyInventory();
+ cleanupGui();
+
+ delete _comboArrow;
+
delete _localFlagNames;
delete _gfx;
delete _soundMan;
@@ -136,6 +140,8 @@ int Parallaction::init() {
_debugger = new Debugger(this);
+ _menuHelper = 0;
+
setupBalloonManager();
return 0;
@@ -151,7 +157,7 @@ void Parallaction::clearSet(OpcodeSet &opcodes) {
void Parallaction::updateView() {
- if ((_engineFlags & kEnginePauseJobs) && (_engineFlags & kEngineInventory) == 0) {
+ if ((_engineFlags & kEnginePauseJobs) && (_input->_inputMode != Input::kInputModeInventory)) {
return;
}
@@ -255,7 +261,7 @@ void Parallaction::freeLocation() {
_localFlagNames->clear();
- _location._walkNodes.clear();
+ _location._walkPoints.clear();
_gfx->clearGfxObjects(kGfxObjNormal);
freeBackground();
@@ -297,46 +303,11 @@ void Parallaction::showLocationComment(const char *text, bool end) {
void Parallaction::processInput(InputData *data) {
+ if (!data) {
+ return;
+ }
switch (data->_event) {
- case kEvAction:
- debugC(2, kDebugInput, "processInput: kEvAction");
- _input->stopHovering();
- pauseJobs();
- runZone(data->_zone);
- resumeJobs();
- break;
-
- case kEvOpenInventory:
- _input->stopHovering();
- if (hitZone(kZoneYou, data->_mousePos.x, data->_mousePos.y) == 0) {
- setArrowCursor();
- }
- pauseJobs();
- openInventory();
- break;
-
- case kEvCloseInventory: // closes inventory and possibly select item
- closeInventory();
- setInventoryCursor(data->_inventoryIndex);
- resumeJobs();
- break;
-
- case kEvHoverInventory:
- highlightInventoryItem(data->_inventoryIndex); // enable
- break;
-
- case kEvWalk:
- debugC(2, kDebugInput, "processInput: kEvWalk");
- _input->stopHovering();
- setArrowCursor();
- _char.scheduleWalk(data->_mousePos.x, data->_mousePos.y);
- break;
-
- case kEvQuitGame:
- _engineFlags |= kEngineQuit;
- break;
-
case kEvSaveGame:
_input->stopHovering();
saveGame();
@@ -360,16 +331,12 @@ void Parallaction::runGame() {
if (_engineFlags & kEngineQuit)
return;
- if (_input->_inputMode == Input::kInputModeDialogue) {
- runDialogueFrame();
- } else {
- if (data->_event != kEvNone) {
- processInput(data);
- }
-
- if (_engineFlags & kEngineQuit)
- return;
+ runGuiFrame();
+ runDialogueFrame();
+ runCommentFrame();
+ if (_input->_inputMode == Input::kInputModeGame) {
+ processInput(data);
runPendingZones();
if (_engineFlags & kEngineQuit)
@@ -388,7 +355,7 @@ void Parallaction::runGame() {
if (_char._ani->gfxobj) {
_char._ani->gfxobj->z = _char._ani->_z;
}
- walk(_char);
+ _char._walker->walk();
drawAnimations();
}
@@ -424,11 +391,10 @@ void Parallaction::doLocationEnterTransition() {
_programExec->runScripts(_location._programs.begin(), _location._programs.end());
drawAnimations();
-
+ showLocationComment(_location._comment, false);
_gfx->updateScreen();
- showLocationComment(_location._comment, false);
- _input->waitUntilLeftClick();
+ _input->waitForButtonEvent(kMouseLeftUp);
_balloonMan->freeBalloons();
// fades maximum intensity palette towards approximation of main palette
@@ -533,7 +499,7 @@ const char Character::_suffixTras[] = "tras";
const char Character::_empty[] = "\0";
-Character::Character(Parallaction *vm) : _vm(vm), _ani(new Animation), _builder(_ani) {
+Character::Character(Parallaction *vm) : _vm(vm), _ani(new Animation) {
_talk = NULL;
_head = NULL;
_objs = NULL;
@@ -552,24 +518,61 @@ Character::Character(Parallaction *vm) : _vm(vm), _ani(new Animation), _builder(
_ani->_flags = kFlagsActive | kFlagsNoName;
_ani->_type = kZoneYou;
strncpy(_ani->_name, "yourself", ZONENAME_LENGTH);
+
+ // TODO: move creation into Parallaction. Needs to make Character a pointer first.
+ if (_vm->getGameType() == GType_Nippon) {
+ _builder = new PathBuilder_NS(this);
+ _walker = new PathWalker_NS(this);
+ } else {
+ _builder = new PathBuilder_BR(this);
+ _walker = new PathWalker_BR(this);
+ }
+}
+
+Character::~Character() {
+ delete _builder;
+ _builder = 0;
+
+ delete _walker;
+ _walker = 0;
+
+ free();
}
void Character::getFoot(Common::Point &foot) {
- foot.x = _ani->_left + _ani->width() / 2;
- foot.y = _ani->_top + _ani->height();
+ Common::Rect rect;
+ _ani->gfxobj->getRect(_ani->_frame, rect);
+
+ foot.x = _ani->_left + (rect.left + rect.width() / 2);
+ foot.y = _ani->_top + (rect.top + rect.height());
}
void Character::setFoot(const Common::Point &foot) {
- _ani->_left = foot.x - _ani->width() / 2;
- _ani->_top = foot.y - _ani->height();
+ Common::Rect rect;
+ _ani->gfxobj->getRect(_ani->_frame, rect);
+
+ _ani->_left = foot.x - (rect.left + rect.width() / 2);
+ _ani->_top = foot.y - (rect.top + rect.height());
+}
+
+#if 0
+void dumpPath(const PointList &list, const char* text) {
+ for (PointList::iterator it = list.begin(); it != list.end(); it++)
+ printf("node (%i, %i)\n", it->x, it->y);
+
+ return;
}
+#endif
void Character::scheduleWalk(int16 x, int16 y) {
if ((_ani->_flags & kFlagsRemove) || (_ani->_flags & kFlagsActive) == 0) {
return;
}
- _walkPath = _builder.buildPath(x, y);
+ _builder->buildPath(x, y);
+#if 0
+ dumpPath(_walkPath, _name);
+#endif
_engineFlags |= kEngineWalking;
}
diff --git a/engines/parallaction/parallaction.h b/engines/parallaction/parallaction.h
index c45d32b013..d8e4da5baf 100644
--- a/engines/parallaction/parallaction.h
+++ b/engines/parallaction/parallaction.h
@@ -101,10 +101,8 @@ enum {
enum EngineFlags {
kEngineQuit = (1 << 0),
kEnginePauseJobs = (1 << 1),
- kEngineInventory = (1 << 2),
kEngineWalking = (1 << 3),
kEngineChangeLocation = (1 << 4),
- kEngineBlockInput = (1 << 5),
kEngineDragging = (1 << 6),
kEngineTransformedDonna = (1 << 7),
@@ -114,12 +112,6 @@ enum EngineFlags {
enum {
kEvNone = 0,
- kEvAction = 3,
- kEvOpenInventory = 4,
- kEvCloseInventory = 5,
- kEvHoverInventory = 6,
- kEvWalk = 7,
- kEvQuitGame = 1000,
kEvSaveGame = 2000,
kEvLoadGame = 4000
};
@@ -164,6 +156,7 @@ class Gfx;
class SoundMan;
class Input;
class DialogueManager;
+class MenuInputHelper;
struct Location {
@@ -184,7 +177,7 @@ struct Location {
char _soundFile[50];
// NS specific
- WalkNodeList _walkNodes;
+ PointList _walkPoints;
char _slideText[2][MAX_TOKEN_LEN];
// BRA specific
@@ -205,10 +198,13 @@ struct Character {
GfxObj *_head;
GfxObj *_talk;
GfxObj *_objs;
- PathBuilder _builder;
- WalkNodeList *_walkPath;
+ PathBuilder *_builder;
+ PathWalker *_walker;
+ PointList _walkPath;
Character(Parallaction *vm);
+ ~Character();
+
void getFoot(Common::Point &foot);
void setFoot(const Common::Point &foot);
void scheduleWalk(int16 x, int16 y);
@@ -265,10 +261,6 @@ public:
void pauseJobs();
void resumeJobs();
- 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);
@@ -333,6 +325,7 @@ public:
Common::RandomSource _rnd;
Debugger *_debugger;
+ Frames *_comboArrow;
protected: // data
@@ -359,8 +352,6 @@ protected: // members
void displayComment(ExamineData *data);
- void checkDoor(const Common::Point &foot);
-
void freeCharacter();
int16 pickupItem(ZonePtr z);
@@ -375,18 +366,18 @@ public:
virtual void callFunction(uint index, void* parm) { }
virtual void setArrowCursor() = 0;
- virtual void setInventoryCursor(int pos) = 0;
+ virtual void setInventoryCursor(ItemName name) = 0;
virtual void parseLocation(const char* name) = 0;
void updateDoor(ZonePtr z);
- virtual void walk(Character &character) = 0;
virtual void drawAnimations() = 0;
void beep();
ZonePtr _zoneTrap;
+ PathBuilder* getPathBuilder(Character *ch);
public:
// const char **_zoneFlagNamesRes;
@@ -422,6 +413,17 @@ public:
void exitDialogueMode();
void runDialogueFrame();
+ MenuInputHelper *_menuHelper;
+ void runGuiFrame();
+ void cleanupGui();
+
+ ZonePtr _commentZone;
+ void enterCommentMode(ZonePtr z);
+ void exitCommentMode();
+ void runCommentFrame();
+
+ void setInternLanguage(uint id);
+ uint getInternLanguage();
};
@@ -480,12 +482,18 @@ public:
typedef void (Parallaction_ns::*Callable)(void*);
virtual void callFunction(uint index, void* parm);
- void setMousePointer(uint32 value);
bool loadGame();
bool saveGame();
void switchBackground(const char* background, const char* mask);
+ void showSlide(const char *name);
+ void setArrowCursor();
+
+ // TODO: this should be private!!!!!!!
+ bool _inTestResult;
+ void cleanupGame();
+ bool allPartsComplete();
private:
LocationParser_ns *_locationParser;
@@ -497,17 +505,14 @@ private:
Common::String genSaveFileName(uint slot, bool oldStyle = false);
Common::InSaveFile *getInSaveFile(uint slot);
Common::OutSaveFile *getOutSaveFile(uint slot);
- bool allPartsComplete();
void setPartComplete(const Character& character);
private:
void changeLocation(char *location);
void changeCharacter(const char *name);
void runPendingZones();
- void cleanupGame();
- void setArrowCursor();
- void setInventoryCursor(int pos);
+ void setInventoryCursor(ItemName name);
void doLoadGame(uint16 slot);
@@ -520,7 +525,6 @@ private:
static byte _resMouseArrow[256];
byte *_mouseArrow;
- Frames *_mouseComposedArrow;
static const Callable _dosCallables[25];
static const Callable _amigaCallables[25];
@@ -540,9 +544,6 @@ private:
ZonePtr _moveSarcExaZones[5];
AnimationPtr _rightHandAnim;
- bool _inTestResult;
-
-
// common callables
void _c_play_boogie(void*);
void _c_startIntro(void*);
@@ -579,7 +580,6 @@ private:
const Callable *_callables;
protected:
- void walk(Character &character);
void drawAnimations();
void parseLocation(const char *filename);
@@ -587,15 +587,9 @@ protected:
void selectStartLocation();
- void guiStart();
- int guiSelectCharacter();
- void guiSplash();
- int guiNewGame();
- uint16 guiChooseLanguage();
- uint16 guiSelectGame();
- int guiGetSelectedBlock(const Common::Point &p);
-
- void showSlide(const char *name);
+ void startGui();
+ void startCreditSequence();
+ void startEndPartSequence();
};
@@ -639,7 +633,8 @@ public:
int32 _counters[32];
uint32 _zoneFlags[NUM_LOCATIONS][NUM_ZONES];
-
+ void startPart(uint part);
+ void setArrowCursor();
private:
LocationParser_br *_locationParser;
ProgramParser_br *_programParser;
@@ -648,17 +643,14 @@ private:
void initFonts();
void freeFonts();
- void setArrowCursor();
- void setInventoryCursor(int pos);
+ void setInventoryCursor(ItemName name);
void changeLocation(char *location);
void runPendingZones();
void initPart();
void freePart();
- void startPart();
- void setMousePointer(int16 index);
void initCursors();
Frames *_dinoCursor;
@@ -669,10 +661,7 @@ private:
static const char *_partNames[];
- void guiStart();
- int guiShowMenu();
- void guiSplash(const char *name);
- Frames* guiRenderMenuItem(const char *text);
+ void startGui();
static const Callable _dosCallables[6];
diff --git a/engines/parallaction/parallaction_br.cpp b/engines/parallaction/parallaction_br.cpp
index 9e2a0f10f1..761c8d1b74 100644
--- a/engines/parallaction/parallaction_br.cpp
+++ b/engines/parallaction/parallaction_br.cpp
@@ -32,6 +32,27 @@
namespace Parallaction {
+struct MouseComboProperties {
+ int _xOffset;
+ int _yOffset;
+ int _width;
+ int _height;
+};
+/*
+// TODO: improve NS's handling of normal cursor before merging cursor code.
+MouseComboProperties _mouseComboProps_NS = {
+ 7, // combo x offset (the icon from the inventory will be rendered from here)
+ 7, // combo y offset (ditto)
+ 32, // combo (arrow + icon) width
+ 32 // combo (arrow + icon) height
+};
+*/
+MouseComboProperties _mouseComboProps_BR = {
+ 8, // combo x offset (the icon from the inventory will be rendered from here)
+ 8, // combo y offset (ditto)
+ 68, // combo (arrow + icon) width
+ 68 // combo (arrow + icon) height
+};
const char *Parallaction_br::_partNames[] = {
"PART0",
@@ -56,7 +77,11 @@ int Parallaction_br::init() {
if (getGameType() == GType_BRA) {
if (getPlatform() == Common::kPlatformPC) {
- _disk = new DosDisk_br(this);
+ if (getFeatures() & GF_DEMO) {
+ _disk = new DosDemo_br(this);
+ } else {
+ _disk = new DosDisk_br(this);
+ }
_disk->setLanguage(2); // NOTE: language is now hardcoded to English. Original used command-line parameters.
_soundMan = new DummySoundMan(this);
} else {
@@ -99,6 +124,7 @@ Parallaction_br::~Parallaction_br() {
delete _dougCursor;
delete _donnaCursor;
+ delete _mouseArrow;
}
void Parallaction_br::callFunction(uint index, void* parm) {
@@ -109,16 +135,14 @@ void Parallaction_br::callFunction(uint index, void* parm) {
int Parallaction_br::go() {
- guiSplash("dyna");
- guiSplash("core");
+ if (getFeatures() & GF_DEMO) {
+ startPart(1);
+ } else {
+ startGui();
+ }
while ((_engineFlags & kEngineQuit) == 0) {
- guiStart();
-
- if (_engineFlags & kEngineQuit)
- return 0;
-
// initCharacter();
_input->_inputMode = Input::kInputModeGame;
@@ -152,6 +176,12 @@ void Parallaction_br::initCursors() {
_dougCursor = _disk->loadPointer("pointer2");
_donnaCursor = _disk->loadPointer("pointer3");
+ Graphics::Surface *surf = new Graphics::Surface;
+ surf->create(_mouseComboProps_BR._width, _mouseComboProps_BR._height, 1);
+ _comboArrow = new SurfaceToFrames(surf);
+
+ // TODO: choose the pointer depending on the active character
+ // For now, we pick Donna's
_mouseArrow = _donnaCursor;
} else {
// TODO: Where are the Amiga cursors?
@@ -159,19 +189,6 @@ void Parallaction_br::initCursors() {
}
-void Parallaction_br::setMousePointer(int16 index) {
- // FIXME: Where are the Amiga cursors?
- if (getPlatform() == Common::kPlatformAmiga)
- return;
-
- Common::Rect r;
- _mouseArrow->getRect(0, r);
-
- _system->setMouseCursor(_mouseArrow->getData(0), r.width(), r.height(), 0, 0, 0);
- _system->showMouse(true);
-
-}
-
void Parallaction_br::initPart() {
memset(_counters, 0, ARRAYSIZE(_counters));
@@ -180,7 +197,12 @@ void Parallaction_br::initPart() {
_objectsNames = _disk->loadTable("objects");
_countersNames = _disk->loadTable("counters");
-// _disk->loadObjects("icone.ico");
+ // TODO: maybe handle this into Disk
+ if (getPlatform() == Common::kPlatformPC) {
+ _char._objs = _disk->loadObjects("icone.ico");
+ } else {
+ _char._objs = _disk->loadObjects("icons.ico");
+ }
}
@@ -195,11 +217,17 @@ void Parallaction_br::freePart() {
_countersNames = 0;
}
-void Parallaction_br::startPart() {
+void Parallaction_br::startPart(uint part) {
+ _part = part;
+ _disk->selectArchive(_partNames[_part]);
initPart();
- strcpy(_location._name, partFirstLocation[_part]);
+ if (getFeatures() & GF_DEMO) {
+ strcpy(_location._name, "camalb");
+ } else {
+ strcpy(_location._name, partFirstLocation[_part]);
+ }
parseLocation("common");
changeLocation(_location._name);
@@ -209,6 +237,8 @@ void Parallaction_br::startPart() {
void Parallaction_br::runPendingZones() {
ZonePtr z;
+ _cmdExec->runSuspended();
+
if (_activeZone) {
z = _activeZone; // speak Zone or sound
_activeZone = nullZonePtr;
@@ -236,7 +266,10 @@ void Parallaction_br::changeLocation(char *location) {
// free open location stuff
clearSubtitles();
freeBackground();
- _gfx->clearGfxObjects(kGfxObjNormal | kGfxObjCharacter);
+ _gfx->clearGfxObjects(kGfxObjNormal);
+ _gfx->freeLabels();
+ _subtitle[0] = _subtitle[1] = -1;
+
_location._programs.clear();
_location._animations.remove(_char._ani);
@@ -248,12 +281,17 @@ void Parallaction_br::changeLocation(char *location) {
// free(_location._comment);
// _location._comment = 0;
-// _location._commands.clear();
-// _location._aCommands.clear();
-
+ _location._commands.clear();
+ _location._aCommands.clear();
// load new location
parseLocation(location);
+
+ // kFlagsRemove is cleared because the character defaults to visible on new locations
+ // script command can hide the character, anyway, so that's why the flag is cleared
+ // before _location._commands are executed
+ _char._ani->_flags &= ~kFlagsRemove;
+
_cmdExec->run(_location._commands);
// doLocationEnterTransition();
_cmdExec->run(_location._aCommands);
@@ -305,30 +343,46 @@ 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;
+
+ if (scumm_stricmp(charName, name)) {
+ debugC(1, kDebugExec, "changeCharacter(%s)", name);
+
+ _char.setName(name);
+ _char._ani->gfxobj = _gfx->loadAnim(name);
+ _char._ani->gfxobj->setFlags(kGfxObjCharacter);
+ _char._ani->gfxobj->clearFlags(kGfxObjNormal);
+ _char._talk = _disk->loadTalk(name);
}
- _char.setName(name);
- _char._ani->gfxobj = _gfx->loadAnim(name);
- _char._ani->gfxobj->setFlags(kGfxObjCharacter);
- _char._talk = _disk->loadTalk(name);
+ _char._ani->_flags |= kFlagsActive;
}
void Parallaction_br::setArrowCursor() {
+ // FIXME: Where are the Amiga cursors?
+ if (getPlatform() == Common::kPlatformAmiga)
+ return;
+ Common::Rect r;
+ _mouseArrow->getRect(0, r);
+ _system->setMouseCursor(_mouseArrow->getData(0), r.width(), r.height(), 0, 0, 0);
+ _system->showMouse(true);
+ _input->_activeItem._id = 0;
}
-void Parallaction_br::setInventoryCursor(int pos) {
-
+void Parallaction_br::setInventoryCursor(ItemName name) {
+ assert(name > 0);
+ byte *src = _mouseArrow->getData(0);
+ byte *dst = _comboArrow->getData(0);
+ memcpy(dst, src, _comboArrow->getSize(0));
+ // FIXME: destination offseting is not clear
+ _inventoryRenderer->drawItem(name, dst + _mouseComboProps_BR._yOffset * _mouseComboProps_BR._width + _mouseComboProps_BR._xOffset, _mouseComboProps_BR._width);
+ _system->setMouseCursor(dst, _mouseComboProps_BR._width, _mouseComboProps_BR._height, 0, 0, 0);
}
} // namespace Parallaction
diff --git a/engines/parallaction/parallaction_ns.cpp b/engines/parallaction/parallaction_ns.cpp
index 9e925d1e1d..851fe38138 100644
--- a/engines/parallaction/parallaction_ns.cpp
+++ b/engines/parallaction/parallaction_ns.cpp
@@ -34,6 +34,7 @@
namespace Parallaction {
+
#define MOUSEARROW_WIDTH 16
#define MOUSEARROW_HEIGHT 16
@@ -165,7 +166,6 @@ Parallaction_ns::~Parallaction_ns() {
delete _locationParser;
delete _programParser;
- delete _mouseComposedArrow;
_location._animations.remove(_char._ani);
@@ -182,7 +182,7 @@ void Parallaction_ns::freeFonts() {
}
void Parallaction_ns::initCursors() {
- _mouseComposedArrow = _disk->loadPointer("pointer");
+ _comboArrow = _disk->loadPointer("pointer");
_mouseArrow = _resMouseArrow;
}
@@ -195,36 +195,16 @@ void Parallaction_ns::setArrowCursor() {
_input->_activeItem._id = 0;
_system->setMouseCursor(_mouseArrow, MOUSEARROW_WIDTH, MOUSEARROW_HEIGHT, 0, 0, 0);
- _system->showMouse(true);
-
}
-void Parallaction_ns::setInventoryCursor(int pos) {
-
- if (pos == -1)
- return;
-
- const InventoryItem *item = getInventoryItem(pos);
- if (item->_index == 0)
- return;
-
- _input->_activeItem._id = item->_id;
+void Parallaction_ns::setInventoryCursor(ItemName name) {
+ assert(name > 0);
- byte *v8 = _mouseComposedArrow->getData(0);
+ byte *v8 = _comboArrow->getData(0);
// FIXME: destination offseting is not clear
- byte* s = _char._objs->getData(item->_index);
- byte* d = v8 + 7 + MOUSECOMBO_WIDTH * 7;
-
- for (uint i = 0; i < INVENTORYITEM_HEIGHT; i++) {
- memcpy(d, s, INVENTORYITEM_WIDTH);
-
- s += INVENTORYITEM_PITCH;
- d += MOUSECOMBO_WIDTH;
- }
-
+ _inventoryRenderer->drawItem(name, v8 + 7 * MOUSECOMBO_WIDTH + 7, MOUSECOMBO_WIDTH);
_system->setMouseCursor(v8, MOUSECOMBO_WIDTH, MOUSECOMBO_HEIGHT, 0, 0, 0);
-
}
@@ -240,17 +220,8 @@ int Parallaction_ns::go() {
_globalTable = _disk->loadTable("global");
- guiStart();
+ startGui();
- if (_engineFlags & kEngineQuit)
- return 0;
-
- changeLocation(_location._name);
-
- if (_engineFlags & kEngineQuit)
- return 0;
-
- _input->_inputMode = Input::kInputModeGame;
while ((_engineFlags & kEngineQuit) == 0) {
runGame();
}
@@ -300,6 +271,9 @@ void Parallaction_ns::runPendingZones() {
void Parallaction_ns::changeLocation(char *location) {
debugC(1, kDebugExec, "changeLocation(%s)", location);
+ MouseTriState oldMouseState = _input->getMouseState();
+ _input->setMouseState(MOUSE_DISABLED);
+
_soundMan->playLocationMusic(location);
_input->stopHovering();
@@ -307,9 +281,7 @@ void Parallaction_ns::changeLocation(char *location) {
_zoneTrap = nullZonePtr;
- if (_engineFlags & kEngineBlockInput) {
- setArrowCursor();
- }
+ setArrowCursor();
_gfx->showGfxObj(_char._ani->gfxobj, false);
_location._animations.remove(_char._ani);
@@ -323,7 +295,9 @@ void Parallaction_ns::changeLocation(char *location) {
showSlide(locname.slide());
uint id = _gfx->createLabel(_menuFont, _location._slideText[0], 1);
_gfx->showLabel(id, CENTER_LABEL_HORIZONTAL, 14);
- _input->waitUntilLeftClick();
+ _gfx->updateScreen();
+
+ _input->waitForButtonEvent(kMouseLeftUp);
_gfx->freeLabels();
freeBackground();
}
@@ -367,10 +341,9 @@ void Parallaction_ns::changeLocation(char *location) {
if (_location._hasSound)
_soundMan->playSfx(_location._soundFile, 0, true);
- debugC(1, kDebugExec, "changeLocation() done");
-
- return;
+ _input->setMouseState(oldMouseState);
+ debugC(1, kDebugExec, "changeLocation() done");
}
diff --git a/engines/parallaction/parser.h b/engines/parallaction/parser.h
index 1541fb89b2..488d437deb 100644
--- a/engines/parallaction/parser.h
+++ b/engines/parallaction/parser.h
@@ -171,7 +171,7 @@ protected:
DECLARE_UNQUALIFIED_COMMAND_PARSER(animation);
DECLARE_UNQUALIFIED_COMMAND_PARSER(zone);
DECLARE_UNQUALIFIED_COMMAND_PARSER(location);
- DECLARE_UNQUALIFIED_COMMAND_PARSER(drop);
+ DECLARE_UNQUALIFIED_COMMAND_PARSER(invObject);
DECLARE_UNQUALIFIED_COMMAND_PARSER(call);
DECLARE_UNQUALIFIED_COMMAND_PARSER(simple);
DECLARE_UNQUALIFIED_COMMAND_PARSER(move);
@@ -192,8 +192,8 @@ protected:
Question *parseQuestion();
void parseZone(ZoneList &list, char *name);
- void parseZoneTypeBlock(ZonePtr z);
- void parseWalkNodes(WalkNodeList &list);
+ virtual void parseZoneTypeBlock(ZonePtr z);
+ void parsePointList(PointList &list);
void parseAnimation(AnimationList &list, char *name);
void parseCommands(CommandList&);
void parseCommandFlags();
@@ -284,6 +284,9 @@ protected:
DECLARE_UNQUALIFIED_ANIM_PARSER(moveto);
DECLARE_UNQUALIFIED_ANIM_PARSER(endanimation);
+ virtual void parseZoneTypeBlock(ZonePtr z);
+ void parsePathData(ZonePtr z);
+
public:
LocationParser_br(Parallaction_br *vm) : LocationParser_ns((Parallaction_ns*)vm), _vm(vm) {
}
@@ -307,6 +310,7 @@ protected:
Parser *_parser;
Parallaction_ns *_vm;
+
Script *_script;
ProgramPtr _program;
diff --git a/engines/parallaction/parser_br.cpp b/engines/parallaction/parser_br.cpp
index defc917a72..3ba2beb288 100644
--- a/engines/parallaction/parser_br.cpp
+++ b/engines/parallaction/parser_br.cpp
@@ -442,7 +442,7 @@ DECLARE_LOCATION_PARSER(redundant) {
DECLARE_LOCATION_PARSER(character) {
debugC(7, kDebugParser, "LOCATION_PARSER(character) ");
- ctxt.characterName = strdup(_tokens[0]);
+ ctxt.characterName = strdup(_tokens[1]);
}
@@ -750,6 +750,67 @@ DECLARE_ZONE_PARSER(type) {
_parser->popTables();
}
+void LocationParser_br::parsePathData(ZonePtr z) {
+
+ PathData *data = new PathData;
+
+ do {
+
+ if (!scumm_stricmp("zone", _tokens[0])) {
+ int id = atoi(_tokens[1]);
+ parsePointList(data->_lists[id]);
+ data->_numLists++;
+ }
+
+ _script->readLineToken(true);
+ } while (scumm_stricmp("endzone", _tokens[0]));
+
+ z->u.path = data;
+}
+
+void LocationParser_br::parseZoneTypeBlock(ZonePtr z) {
+ debugC(7, kDebugParser, "parseZoneTypeBlock(name: %s, type: %x)", z->_name, z->_type);
+
+ switch (z->_type & 0xFFFF) {
+ case kZoneExamine: // examine Zone alloc
+ parseExamineData(z);
+ break;
+
+ case kZoneDoor: // door Zone alloc
+ parseDoorData(z);
+ break;
+
+ case kZoneGet: // get Zone alloc
+ parseGetData(z);
+ break;
+
+ case kZoneMerge: // merge Zone alloc
+ parseMergeData(z);
+ break;
+
+ case kZoneHear: // hear Zone alloc
+ parseHearData(z);
+ break;
+
+ case kZoneSpeak: // speak Zone alloc
+ parseSpeakData(z);
+ break;
+
+ // BRA specific zone
+ case kZonePath:
+ parsePathData(z);
+ break;
+
+ default:
+ // eats up 'ENDZONE' line for unprocessed zone types
+ _script->readLineToken(true);
+ break;
+ }
+
+ debugC(7, kDebugParser, "parseZoneTypeBlock() done");
+
+ return;
+}
DECLARE_ANIM_PARSER(file) {
debugC(7, kDebugParser, "ANIM_PARSER(file) ");
@@ -983,7 +1044,7 @@ void LocationParser_br::init() {
COMMAND_PARSER(zone); // off
COMMAND_PARSER(call);
COMMAND_PARSER(flags); // toggle
- COMMAND_PARSER(drop);
+ COMMAND_PARSER(invObject); // drop
COMMAND_PARSER(simple); // quit
COMMAND_PARSER(move);
COMMAND_PARSER(zone); // stop
@@ -991,7 +1052,7 @@ void LocationParser_br::init() {
COMMAND_PARSER(string); // followme
COMMAND_PARSER(simple); // onmouse
COMMAND_PARSER(simple); // offmouse
- COMMAND_PARSER(drop); // add
+ COMMAND_PARSER(invObject); // add
COMMAND_PARSER(zone); // leave
COMMAND_PARSER(math); // inc
COMMAND_PARSER(math); // dec
diff --git a/engines/parallaction/parser_ns.cpp b/engines/parallaction/parser_ns.cpp
index 2f4d2df776..ad0f714fdc 100644
--- a/engines/parallaction/parser_ns.cpp
+++ b/engines/parallaction/parser_ns.cpp
@@ -299,6 +299,7 @@ void LocationParser_ns::parseAnimation(AnimationList &list, char *name) {
AnimationPtr a(new Animation);
strncpy(a->_name, name, ZONENAME_LENGTH);
+ a->_flags |= kFlagsIsAnimation;
list.push_front(AnimationPtr(a));
@@ -658,7 +659,7 @@ DECLARE_COMMAND_PARSER(location) {
}
-DECLARE_COMMAND_PARSER(drop) {
+DECLARE_COMMAND_PARSER(invObject) {
debugC(7, kDebugParser, "COMMAND_PARSER(drop) ");
createCommand(_parser->_lookup);
@@ -1011,7 +1012,7 @@ DECLARE_LOCATION_PARSER(disk) {
DECLARE_LOCATION_PARSER(nodes) {
debugC(7, kDebugParser, "LOCATION_PARSER(nodes) ");
- parseWalkNodes(_vm->_location._walkNodes);
+ parsePointList(_vm->_location._walkPoints);
}
@@ -1124,26 +1125,20 @@ void LocationParser_ns::parse(Script *script) {
resolveCommandForwards();
}
-void LocationParser_ns::parseWalkNodes(WalkNodeList &list) {
- debugC(5, kDebugParser, "parseWalkNodes()");
+void LocationParser_ns::parsePointList(PointList &list) {
+ debugC(5, kDebugParser, "parsePointList()");
_script->readLineToken(true);
while (scumm_stricmp(_tokens[0], "ENDNODES")) {
if (!scumm_stricmp(_tokens[0], "COORD")) {
-
- WalkNodePtr v4(new WalkNode(
- atoi(_tokens[1]),
- atoi(_tokens[2])
- ));
-
- list.push_front(v4);
+ list.push_front(Common::Point(atoi(_tokens[1]), atoi(_tokens[2])));
}
_script->readLineToken(true);
}
- debugC(5, kDebugParser, "parseWalkNodes() done");
+ debugC(5, kDebugParser, "parsePointList() done");
return;
}
@@ -1203,7 +1198,7 @@ void LocationParser_ns::init() {
COMMAND_PARSER(zone); // off
COMMAND_PARSER(call); // call
COMMAND_PARSER(flags); // toggle
- COMMAND_PARSER(drop); // drop
+ COMMAND_PARSER(invObject); // drop
COMMAND_PARSER(simple); // quit
COMMAND_PARSER(move); // move
COMMAND_PARSER(zone); // stop
@@ -1397,7 +1392,7 @@ void LocationParser_ns::parseZone(ZoneList &list, char *name) {
list.push_front(z);
_parser->pushTables(&_locationZoneParsers, _locationZoneStmt);
-
+
return;
}
diff --git a/engines/parallaction/walk.cpp b/engines/parallaction/walk.cpp
index a717b615e6..bf8f423fd5 100644
--- a/engines/parallaction/walk.cpp
+++ b/engines/parallaction/walk.cpp
@@ -28,26 +28,42 @@
namespace Parallaction {
+
+#define IS_PATH_CLEAR(x,y) _vm->_pathBuffer->getValue((x), (y))
+
inline byte PathBuffer::getValue(uint16 x, uint16 y) {
byte m = data[(x >> 3) + y * internalWidth];
- uint n = (_vm->getPlatform() == Common::kPlatformPC) ? (x & 7) : (7 - (x & 7));
- return ((1 << n) & m) >> n;
+ uint bit = 0;
+ switch (_vm->getGameType()) {
+ case GType_Nippon:
+ bit = (_vm->getPlatform() == Common::kPlatformPC) ? (x & 7) : (7 - (x & 7));
+ break;
+
+ case GType_BRA:
+ // Amiga and PC versions pack the path bits the same way in BRA
+ bit = 7 - (x & 7);
+ break;
+
+ default:
+ error("path mask not yet implemented for this game type");
+ }
+ return ((1 << bit) & m) >> bit;
}
// adjusts position towards nearest walkable point
//
-void PathBuilder::correctPathPoint(Common::Point &to) {
+void PathBuilder_NS::correctPathPoint(Common::Point &to) {
- if (_vm->_pathBuffer->getValue(to.x, to.y)) return;
+ if (IS_PATH_CLEAR(to.x, to.y)) return;
int16 right = to.x;
int16 left = to.x;
do {
right++;
- } while ((_vm->_pathBuffer->getValue(right, to.y) == 0) && (right < _vm->_pathBuffer->w));
+ } while (!IS_PATH_CLEAR(right, to.y) && (right < _vm->_pathBuffer->w));
do {
left--;
- } while ((_vm->_pathBuffer->getValue(left, to.y) == 0) && (left > 0));
+ } while (!IS_PATH_CLEAR(left, to.y) && (left > 0));
right = (right == _vm->_pathBuffer->w) ? 1000 : right - to.x;
left = (left == 0) ? 1000 : to.x - left;
@@ -56,10 +72,10 @@ void PathBuilder::correctPathPoint(Common::Point &to) {
int16 bottom = to.y;
do {
top--;
- } while ((_vm->_pathBuffer->getValue(to.x, top) == 0) && (top > 0));
+ } while (!IS_PATH_CLEAR(to.x, top) && (top > 0));
do {
bottom++;
- } while ((_vm->_pathBuffer->getValue(to.x, bottom) == 0) && (bottom < _vm->_pathBuffer->h));
+ } while (!IS_PATH_CLEAR(to.x, bottom) && (bottom < _vm->_pathBuffer->h));
top = (top == 0) ? 1000 : to.y - top;
bottom = (bottom == _vm->_pathBuffer->h) ? 1000 : bottom - to.y;
@@ -84,7 +100,7 @@ void PathBuilder::correctPathPoint(Common::Point &to) {
}
-uint32 PathBuilder::buildSubPath(const Common::Point& pos, const Common::Point& stop) {
+uint32 PathBuilder_NS::buildSubPath(const Common::Point& pos, const Common::Point& stop) {
uint32 v28 = 0;
uint32 v2C = 0;
@@ -97,16 +113,15 @@ uint32 PathBuilder::buildSubPath(const Common::Point& pos, const Common::Point&
while (true) {
- WalkNodeList::iterator nearest = _vm->_location._walkNodes.end();
- WalkNodeList::iterator locNode = _vm->_location._walkNodes.begin();
+ PointList::iterator nearest = _vm->_location._walkPoints.end();
+ PointList::iterator locNode = _vm->_location._walkPoints.begin();
// scans location path nodes searching for the nearest Node
// which can't be farther than the target position
// otherwise no _closest_node is selected
- while (locNode != _vm->_location._walkNodes.end()) {
+ while (locNode != _vm->_location._walkPoints.end()) {
- Common::Point v8;
- (*locNode)->getPoint(v8);
+ Common::Point v8 = *locNode;
v2C = v8.sqrDist(stop);
v28 = v8.sqrDist(v20);
@@ -118,80 +133,59 @@ uint32 PathBuilder::buildSubPath(const Common::Point& pos, const Common::Point&
locNode++;
}
- if (nearest == _vm->_location._walkNodes.end()) break;
+ if (nearest == _vm->_location._walkPoints.end()) break;
- (*nearest)->getPoint(v20);
+ v20 = *nearest;
v34 = v30 = v20.sqrDist(stop);
- _subPath.push_back(WalkNodePtr(new WalkNode(**nearest)));
+ _subPath.push_back(*nearest);
}
return v34;
}
-#if 0
-void printNodes(WalkNodeList *list, const char* text) {
- printf("%s\n-------------------\n", text);
- for (WalkNodeList::iterator it = list->begin(); it != list->end(); it++)
- printf("node [%p] (%i, %i)\n", *it, (*it)->_x, (*it)->_y);
- return;
-}
-#endif
//
// x, y: mouse click (foot) coordinates
//
-WalkNodeList *PathBuilder::buildPath(uint16 x, uint16 y) {
+void PathBuilder_NS::buildPath(uint16 x, uint16 y) {
debugC(1, kDebugWalk, "PathBuilder::buildPath to (%i, %i)", x, y);
+ _ch->_walkPath.clear();
+
Common::Point to(x, y);
correctPathPoint(to);
debugC(1, kDebugWalk, "found closest path point at (%i, %i)", to.x, to.y);
- WalkNodePtr v48(new WalkNode(to.x, to.y));
- WalkNodePtr v44 = v48;
+ Common::Point v48(to);
+ Common::Point v44(to);
- uint16 v38 = walkFunc1(to.x, to.y, v44);
+ uint16 v38 = walkFunc1(to, v44);
if (v38 == 1) {
// destination directly reachable
debugC(1, kDebugWalk, "direct move to (%i, %i)", to.x, to.y);
-
- _list = new WalkNodeList;
- _list->push_back(v48);
- return _list;
+ _ch->_walkPath.push_back(v48);
+ return;
}
// path is obstructed: look for alternative
- _list = new WalkNodeList;
- _list->push_back(v48);
-#if 0
- printNodes(_list, "start");
-#endif
-
- Common::Point stop(v48->_x, v48->_y);
+ _ch->_walkPath.push_back(v48);
Common::Point pos;
- _vm->_char.getFoot(pos);
+ _ch->getFoot(pos);
- uint32 v34 = buildSubPath(pos, stop);
+ uint32 v34 = buildSubPath(pos, v48);
if (v38 != 0 && v34 > v38) {
// no alternative path (gap?)
- _list->clear();
- _list->push_back(v44);
- return _list;
+ _ch->_walkPath.clear();
+ _ch->_walkPath.push_back(v44);
+ return;
}
- _list->insert(_list->begin(), _subPath.begin(), _subPath.end());
-#if 0
- printNodes(_list, "first segment");
-#endif
+ _ch->_walkPath.insert(_ch->_walkPath.begin(), _subPath.begin(), _subPath.end());
- (*_list->begin())->getPoint(stop);
- buildSubPath(pos, stop);
- _list->insert(_list->begin(), _subPath.begin(), _subPath.end());
-#if 0
- printNodes(_list, "complete");
-#endif
+ buildSubPath(pos, *_ch->_walkPath.begin());
+ _ch->_walkPath.insert(_ch->_walkPath.begin(), _subPath.begin(), _subPath.end());
- return _list;
+ return;
}
@@ -202,23 +196,23 @@ WalkNodeList *PathBuilder::buildPath(uint16 x, uint16 y) {
// 1 : Point reachable in a straight line
// other values: square distance to target (point not reachable in a straight line)
//
-uint16 PathBuilder::walkFunc1(int16 x, int16 y, WalkNodePtr Node) {
+uint16 PathBuilder_NS::walkFunc1(const Common::Point &to, Common::Point& node) {
- Common::Point arg(x, y);
+ Common::Point arg(to);
- Common::Point v4(0, 0);
+ Common::Point v4;
Common::Point foot;
- _vm->_char.getFoot(foot);
+ _ch->getFoot(foot);
Common::Point v8(foot);
while (foot != arg) {
- if (foot.x < x && _vm->_pathBuffer->getValue(foot.x + 1, foot.y) != 0) foot.x++;
- if (foot.x > x && _vm->_pathBuffer->getValue(foot.x - 1, foot.y) != 0) foot.x--;
- if (foot.y < y && _vm->_pathBuffer->getValue(foot.x, foot.y + 1) != 0) foot.y++;
- if (foot.y > y && _vm->_pathBuffer->getValue(foot.x, foot.y - 1) != 0) foot.y--;
+ if (foot.x < to.x && IS_PATH_CLEAR(foot.x + 1, foot.y)) foot.x++;
+ if (foot.x > to.x && IS_PATH_CLEAR(foot.x - 1, foot.y)) foot.x--;
+ if (foot.y < to.y && IS_PATH_CLEAR(foot.x, foot.y + 1)) foot.y++;
+ if (foot.y > to.y && IS_PATH_CLEAR(foot.x, foot.y - 1)) foot.y--;
if (foot == v8 && foot != arg) {
@@ -228,10 +222,10 @@ uint16 PathBuilder::walkFunc1(int16 x, int16 y, WalkNodePtr Node) {
while (foot != arg) {
- if (foot.x < x && _vm->_pathBuffer->getValue(foot.x + 1, foot.y) == 0) foot.x++;
- if (foot.x > x && _vm->_pathBuffer->getValue(foot.x - 1, foot.y) == 0) foot.x--;
- if (foot.y < y && _vm->_pathBuffer->getValue(foot.x, foot.y + 1) == 0) foot.y++;
- if (foot.y > y && _vm->_pathBuffer->getValue(foot.x, foot.y - 1) == 0) foot.y--;
+ if (foot.x < to.x && !IS_PATH_CLEAR(foot.x + 1, foot.y)) foot.x++;
+ if (foot.x > to.x && !IS_PATH_CLEAR(foot.x - 1, foot.y)) foot.x--;
+ if (foot.y < to.y && !IS_PATH_CLEAR(foot.x, foot.y + 1)) foot.y++;
+ if (foot.y > to.y && !IS_PATH_CLEAR(foot.x, foot.y - 1)) foot.y--;
if (foot == v8 && foot != arg)
return 0;
@@ -239,10 +233,8 @@ uint16 PathBuilder::walkFunc1(int16 x, int16 y, WalkNodePtr Node) {
v8 = foot;
}
- Node->_x = v4.x;
- Node->_y = v4.y;
-
- return (x - v4.x) * (x - v4.x) + (y - v4.y) * (y - v4.y);
+ node = v4;
+ return v4.sqrDist(to);
}
v8 = foot;
@@ -253,21 +245,21 @@ uint16 PathBuilder::walkFunc1(int16 x, int16 y, WalkNodePtr Node) {
return 1;
}
-void Parallaction::clipMove(Common::Point& pos, const Common::Point& to) {
+void PathWalker_NS::clipMove(Common::Point& pos, const Common::Point& to) {
- if ((pos.x < to.x) && (pos.x < _pathBuffer->w) && (_pathBuffer->getValue(pos.x + 2, pos.y) != 0)) {
+ if ((pos.x < to.x) && (pos.x < _vm->_pathBuffer->w) && IS_PATH_CLEAR(pos.x + 2, pos.y)) {
pos.x = (pos.x + 2 < to.x) ? pos.x + 2 : to.x;
}
- if ((pos.x > to.x) && (pos.x > 0) && (_pathBuffer->getValue(pos.x - 2, pos.y) != 0)) {
+ if ((pos.x > to.x) && (pos.x > 0) && IS_PATH_CLEAR(pos.x - 2, pos.y)) {
pos.x = (pos.x - 2 > to.x) ? pos.x - 2 : to.x;
}
- if ((pos.y < to.y) && (pos.y < _pathBuffer->h) && (_pathBuffer->getValue(pos.x, pos.y + 2) != 0)) {
+ if ((pos.y < to.y) && (pos.y < _vm->_pathBuffer->h) && IS_PATH_CLEAR(pos.x, pos.y + 2)) {
pos.y = (pos.y + 2 <= to.y) ? pos.y + 2 : to.y;
}
- if ((pos.y > to.y) && (pos.y > 0) && (_pathBuffer->getValue(pos.x, pos.y - 2) != 0)) {
+ if ((pos.y > to.y) && (pos.y > 0) && IS_PATH_CLEAR(pos.x, pos.y - 2)) {
pos.y = (pos.y - 2 >= to.y) ? pos.y - 2 : to.y;
}
@@ -275,85 +267,81 @@ void Parallaction::clipMove(Common::Point& pos, const Common::Point& to) {
}
-void Parallaction::checkDoor(const Common::Point &foot) {
+void PathWalker_NS::checkDoor(const Common::Point &foot) {
- ZonePtr z = hitZone(kZoneDoor, foot.x, foot.y);
+ ZonePtr z = _vm->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;
+ _vm->_location._startPosition = z->u.door->_startPos;
+ _vm->_location._startFrame = z->u.door->_startFrame;
+ _vm->scheduleLocationSwitch(z->u.door->_location);
+ _vm->_zoneTrap = nullZonePtr;
} else {
- _cmdExec->run(z->_commands, z);
+ _vm->_cmdExec->run(z->_commands, z);
}
}
- z = hitZone(kZoneTrap, foot.x, foot.y);
+ z = _vm->hitZone(kZoneTrap, foot.x, foot.y);
if (z) {
- setLocationFlags(kFlagsEnter);
- _cmdExec->run(z->_commands, z);
- clearLocationFlags(kFlagsEnter);
- _zoneTrap = z;
+ _vm->setLocationFlags(kFlagsEnter);
+ _vm->_cmdExec->run(z->_commands, z);
+ _vm->clearLocationFlags(kFlagsEnter);
+ _vm->_zoneTrap = z;
} else
- if (_zoneTrap) {
- setLocationFlags(kFlagsExit);
- _cmdExec->run(_zoneTrap->_commands, _zoneTrap);
- clearLocationFlags(kFlagsExit);
- _zoneTrap = nullZonePtr;
+ if (_vm->_zoneTrap) {
+ _vm->setLocationFlags(kFlagsExit);
+ _vm->_cmdExec->run(_vm->_zoneTrap->_commands, _vm->_zoneTrap);
+ _vm->clearLocationFlags(kFlagsExit);
+ _vm->_zoneTrap = nullZonePtr;
}
}
-void Parallaction::finalizeWalk(Character &character) {
+void PathWalker_NS::finalizeWalk() {
_engineFlags &= ~kEngineWalking;
Common::Point foot;
- character.getFoot(foot);
+ _ch->getFoot(foot);
checkDoor(foot);
- delete character._walkPath;
- character._walkPath = 0;
+ _ch->_walkPath.clear();
}
-void Parallaction_ns::walk(Character &character) {
+void PathWalker_NS::walk() {
if ((_engineFlags & kEngineWalking) == 0) {
return;
}
Common::Point curPos;
- character.getFoot(curPos);
+ _ch->getFoot(curPos);
// 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 = character._walkPath->erase(it);
+ PointList::iterator it = _ch->_walkPath.begin();
+ if (it != _ch->_walkPath.end()) {
+ if (*it == curPos) {
+ debugC(1, kDebugWalk, "walk reached node (%i, %i)", (*it).x, (*it).y);
+ it = _ch->_walkPath.erase(it);
}
}
// advance character towards the target
Common::Point targetPos;
- if (it == character._walkPath->end()) {
+ if (it == _ch->_walkPath.end()) {
debugC(1, kDebugWalk, "walk reached last node");
- finalizeWalk(character);
+ finalizeWalk();
targetPos = curPos;
} else {
- if (*it) {
- // targetPos is saved to help setting character direction
- targetPos.x = (*it)->_x;
- targetPos.y = (*it)->_y;
- }
+ // targetPos is saved to help setting character direction
+ targetPos = *it;
Common::Point newPos(curPos);
clipMove(newPos, targetPos);
- character.setFoot(newPos);
+ _ch->setFoot(newPos);
if (newPos == curPos) {
debugC(1, kDebugWalk, "walk was blocked by an unforeseen obstacle");
- finalizeWalk(character);
+ finalizeWalk();
targetPos = newPos; // when walking is interrupted, targetPos must be hacked so that a still frame can be selected
}
}
@@ -364,25 +352,283 @@ void Parallaction_ns::walk(Character &character) {
// 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);
+ _ch->updateDirection(curPos, targetPos);
}
-WalkNode::WalkNode() : _x(0), _y(0) {
+
+PathBuilder_NS::PathBuilder_NS(Character *ch) : PathBuilder(ch), _list(0) {
}
-WalkNode::WalkNode(int16 x, int16 y) : _x(x), _y(y) {
+
+bool PathBuilder_BR::directPathExists(const Common::Point &from, const Common::Point &to) {
+
+ Common::Point copy(from);
+ Common::Point p(copy);
+
+ while (p != to) {
+
+ if (p.x < to.x && IS_PATH_CLEAR(p.x + 1, p.y)) p.x++;
+ if (p.x > to.x && IS_PATH_CLEAR(p.x - 1, p.y)) p.x--;
+ if (p.y < to.y && IS_PATH_CLEAR(p.x, p.y + 1)) p.y++;
+ if (p.y > to.y && IS_PATH_CLEAR(p.x, p.y - 1)) p.y--;
+
+ if (p == copy && p != to) {
+ return false;
+ }
+
+ copy = p;
+ }
+
+ return true;
}
-WalkNode::WalkNode(const WalkNode& w) : _x(w._x), _y(w._y) {
+void PathBuilder_BR::buildPath(uint16 x, uint16 y) {
+ Common::Point foot;
+ _ch->getFoot(foot);
+
+ debugC(1, kDebugWalk, "buildPath: from (%i, %i) to (%i, %i)", foot.x, foot.y, x, y);
+ _ch->_walkPath.clear();
+
+ // look for easy path first
+ Common::Point dest(x, y);
+ if (directPathExists(foot, dest)) {
+ _ch->_walkPath.push_back(dest);
+ debugC(3, kDebugWalk, "buildPath: direct path found");
+ return;
+ }
+
+ // look for short circuit cases
+ ZonePtr z0 = _vm->hitZone(kZonePath, x, y);
+ if (!z0) {
+ _ch->_walkPath.push_back(dest);
+ debugC(3, kDebugWalk, "buildPath: corner case 0");
+ return;
+ }
+ ZonePtr z1 = _vm->hitZone(kZonePath, foot.x, foot.y);
+ if (!z1 || z1 == z0) {
+ _ch->_walkPath.push_back(dest);
+ debugC(3, kDebugWalk, "buildPath: corner case 1");
+ return;
+ }
+
+ // build complex path
+ int id = atoi(z0->_name);
+
+ if (z1->u.path->_lists[id].empty()) {
+ _ch->_walkPath.clear();
+ debugC(3, kDebugWalk, "buildPath: no path");
+ return;
+ }
+
+ PointList::iterator b = z1->u.path->_lists[id].begin();
+ PointList::iterator e = z1->u.path->_lists[id].end();
+ for ( ; b != e; b++) {
+ _ch->_walkPath.push_front(*b);
+ }
+ _ch->_walkPath.push_back(dest);
+ debugC(3, kDebugWalk, "buildPath: complex path");
+
+ return;
+}
+
+PathBuilder_BR::PathBuilder_BR(Character *ch) : PathBuilder(ch) {
+}
+
+void PathWalker_BR::finalizeWalk() {
+ _engineFlags &= ~kEngineWalking;
+ _first = true;
+ _fieldC = 1;
+
+ Common::Point foot;
+ _ch->getFoot(foot);
+
+ ZonePtr z = _vm->hitZone(kZoneDoor, foot.x, foot.y);
+ if (z && ((z->_flags & kFlagsClosed) == 0)) {
+ _vm->_location._startPosition = z->u.door->_startPos; // foot pos
+ _vm->_location._startFrame = z->u.door->_startFrame;
+
+#if 0
+ // TODO: implement working follower. Must find out a location in which the code is
+ // used and which is stable enough.
+ _followerFootInit.x = -1;
+ if (_follower && z->u.door->startPos2.x != -1) {
+ _followerFootInit.x = z->u.door->startPos2.x; // foot pos
+ _followerFootInit.y = z->u.door->startPos2.y; // foot pos
+ }
+ _followerFootInit.z = -1;
+ if (_follower && z->u.door->startPos2.z != -1) {
+ _followerFootInit.z = z->u.door->startPos2.z; // foot pos
+ }
+#endif
+
+ _vm->scheduleLocationSwitch(z->u.door->_location);
+ _vm->_cmdExec->run(z->_commands, z);
+ }
+
+#if 0
+ // TODO: Input::walkTo must be extended to support destination frame in addition to coordinates
+ // TODO: the frame argument must be passed to PathWalker through PathBuilder, so probably
+ // a merge between the two Path managers is the right solution
+ if (_engineFlags & FINAL_WALK_FRAME) { // this flag is set in readInput()
+ _engineFlags &= ~FINAL_WALK_FRAME;
+ _char.ani->_frame = _moveToF; // from readInput()...
+ } else {
+ _char.ani->_frame = _dirFrame; // from walk()
+ }
+ _char.setFoot(foot);
+#endif
+
+ _ch->_ani->_frame = _dirFrame; // temporary solution
+
+#if 0
+ // TODO: support scrolling ;)
+ if (foot.x > _gfx->hscroll + 600) _gfx->scrollRight(78);
+ if (foot.x < _gfx->hscroll + 40) _gfx->scrollLeft(78);
+ if (foot.y > 350) _gfx->scrollDown(100);
+ if (foot.y < 80) _gfx->scrollUp(100);
+#endif
+
+ return;
}
-void WalkNode::getPoint(Common::Point &p) const {
- p.x = _x;
- p.y = _y;
+
+void PathWalker_BR::walk() {
+ if ((_engineFlags & kEngineWalking) == 0) {
+ return;
+ }
+
+#if 0
+ // TODO: support delays in walking. This requires extending Input::walkIo().
+ if (ch._walkDelay > 0) {
+ ch._walkDelay--;
+ if (ch._walkDelay == 0 && _ch._ani->_scriptName) {
+ // stop script and reset
+ _ch._ani->_flags &= ~kFlagsActing;
+ Script *script = findScript(_ch._ani->_scriptName);
+ script->_nextCommand = script->firstCommand;
+ }
+ return;
+ }
+#endif
+
+ GfxObj *obj = _ch->_ani->gfxobj;
+
+ Common::Rect rect;
+ obj->getRect(_ch->_ani->_frame, rect);
+
+ uint scale;
+ if (rect.bottom > _vm->_location._zeta0) {
+ scale = 100;
+ } else
+ if (rect.bottom < _vm->_location._zeta1) {
+ scale = _vm->_location._zeta2;
+ } else {
+ scale = _vm->_location._zeta2 + ((rect.bottom - _vm->_location._zeta1) * (100 - _vm->_location._zeta2)) / (_vm->_location._zeta0 - _vm->_location._zeta1);
+ }
+ int xStep = (scale * 16) / 100 + 1;
+ int yStep = (scale * 10) / 100 + 1;
+
+ debugC(9, kDebugWalk, "calculated step: (%i, %i)\n", xStep, yStep);
+
+ if (_fieldC == 0) {
+ _ch->_walkPath.erase(_ch->_walkPath.begin());
+
+ if (_ch->_walkPath.empty()) {
+ finalizeWalk();
+ debugC(3, kDebugWalk, "PathWalker_BR::walk, case 0\n");
+ return;
+ } else {
+ debugC(3, kDebugWalk, "PathWalker_BR::walk, moving to next node\n");
+ }
+ }
+
+ _ch->getFoot(_startFoot);
+
+ _fieldC = 0;
+ _step++;
+ _step %= 8;
+
+ int walkFrame = _step;
+ _dirFrame = 0;
+ Common::Point newpos(_startFoot), delta;
+
+ Common::Point p(*_ch->_walkPath.begin());
+
+ if (_startFoot.y < p.y && _startFoot.y < 400 && IS_PATH_CLEAR(_startFoot.x, yStep + _startFoot.y)) {
+ if (yStep + _startFoot.y <= p.y) {
+ _fieldC = 1;
+ delta.y = yStep;
+ newpos.y = yStep + _startFoot.y;
+ } else {
+ delta.y = p.y - _startFoot.y;
+ newpos.y = p.y;
+ }
+ _dirFrame = 9;
+ } else
+ if (_startFoot.y > p.y && _startFoot.y > 0 && IS_PATH_CLEAR(_startFoot.x, _startFoot.y - yStep)) {
+ if (_startFoot.y - yStep >= p.y) {
+ _fieldC = 1;
+ delta.y = yStep;
+ newpos.y = _startFoot.y - yStep;
+ } else {
+ delta.y = _startFoot.y - p.y;
+ newpos.y = p.y;
+ }
+ _dirFrame = 0;
+ }
+
+ if (_startFoot.x < p.x && _startFoot.x < 640 && IS_PATH_CLEAR(_startFoot.x + xStep, _startFoot.y)) {
+ if (_startFoot.x + xStep <= p.x) {
+ _fieldC = 1;
+ delta.x = xStep;
+ newpos.x = xStep + _startFoot.x;
+ } else {
+ delta.x = p.x - _startFoot.x;
+ newpos.x = p.x;
+ }
+ if (delta.y < delta.x) {
+ _dirFrame = 18; // right
+ }
+ } else
+ if (_startFoot.x > p.x && _startFoot.x > 0 && IS_PATH_CLEAR(_startFoot.x - xStep, _startFoot.y)) {
+ if (_startFoot.x - xStep >= p.x) {
+ _fieldC = 1;
+ delta.x = xStep;
+ newpos.x = _startFoot.x - xStep;
+ } else {
+ delta.x = _startFoot.x - p.x;
+ newpos.x = p.x;
+ }
+ if (delta.y < delta.x) {
+ _dirFrame = 27; // left
+ }
+ }
+
+ debugC(9, kDebugWalk, "foot (%i, %i) dest (%i, %i) deltas = %i/%i \n", _startFoot.x, _startFoot.y, p.x, p.y, delta.x, delta.y);
+
+ if (_fieldC) {
+ debugC(9, kDebugWalk, "PathWalker_BR::walk, foot moved from (%i, %i) to (%i, %i)\n", _startFoot.x, _startFoot.y, newpos.x, newpos.y);
+ _ch->_ani->_frame = walkFrame + _dirFrame + 1;
+ _startFoot.x = newpos.x;
+ _startFoot.y = newpos.y;
+ _ch->setFoot(_startFoot);
+ _ch->_ani->_z = newpos.y;
+ }
+
+ if (_fieldC || !_ch->_walkPath.empty()) {
+// checkTrap();
+ debugC(3, kDebugWalk, "PathWalker_BR::walk, case 1\n");
+ return;
+ }
+
+ debugC(3, kDebugWalk, "PathWalker_BR::walk, case 2\n");
+ finalizeWalk();
+ return;
}
-PathBuilder::PathBuilder(AnimationPtr anim) : _anim(anim), _list(0) {
+PathWalker_BR::PathWalker_BR(Character *ch) : PathWalker(ch), _fieldC(1), _first(true) {
+
}
diff --git a/engines/parallaction/walk.h b/engines/parallaction/walk.h
index 788a6e1375..8d21e5ebbd 100644
--- a/engines/parallaction/walk.h
+++ b/engines/parallaction/walk.h
@@ -29,43 +29,89 @@
#include "common/ptr.h"
#include "common/list.h"
+#include "parallaction/objects.h"
+
+
namespace Parallaction {
-struct Animation;
+struct Character;
+
+class PathBuilder {
-struct WalkNode {
- int16 _x;
- int16 _y;
+protected:
+ Character *_ch;
public:
- WalkNode();
- WalkNode(int16 x, int16 y);
- WalkNode(const WalkNode& w);
+ PathBuilder(Character *ch) : _ch(ch) { }
+ virtual ~PathBuilder() { }
- void getPoint(Common::Point &p) const;
+ virtual void buildPath(uint16 x, uint16 y) = 0;
};
-typedef Common::SharedPtr<WalkNode> WalkNodePtr;
-typedef Common::List<WalkNodePtr> WalkNodeList;
+class PathBuilder_NS : public PathBuilder {
-class PathBuilder {
-
- AnimationPtr _anim;
-
- WalkNodeList *_list;
- WalkNodeList _subPath;
+ PointList *_list;
+ PointList _subPath;
void correctPathPoint(Common::Point &to);
uint32 buildSubPath(const Common::Point& pos, const Common::Point& stop);
- uint16 walkFunc1(int16 x, int16 y, WalkNodePtr Node);
+ uint16 walkFunc1(const Common::Point &to, Common::Point& node);
public:
- PathBuilder(AnimationPtr anim);
- WalkNodeList* buildPath(uint16 x, uint16 y);
+ PathBuilder_NS(Character *ch);
+ void buildPath(uint16 x, uint16 y);
+};
+
+class PathBuilder_BR : public PathBuilder {
+
+ bool directPathExists(const Common::Point &from, const Common::Point &to);
+
+public:
+ PathBuilder_BR(Character *ch);
+ void buildPath(uint16 x, uint16 y);
+};
+
+class PathWalker {
+protected:
+ Character *_ch;
+public:
+ PathWalker(Character *ch) : _ch(ch) { }
+ virtual ~PathWalker() { }
+ virtual void walk() = 0;
};
+class PathWalker_NS : public PathWalker {
+
+
+ void finalizeWalk();
+ void clipMove(Common::Point& pos, const Common::Point& to);
+ void checkDoor(const Common::Point &foot);
+
+public:
+ PathWalker_NS(Character *ch) : PathWalker(ch) { }
+ void walk();
+};
+
+
+class PathWalker_BR : public PathWalker {
+
+
+ int _walkDelay;
+ int _fieldC;
+ Common::Point _startFoot;
+ bool _first;
+ int _step;
+
+ int _dirFrame;
+
+ void finalizeWalk();
+
+public:
+ PathWalker_BR(Character *ch);
+ void walk();
+};
}