2014-05-05 16:59:17 +00:00
|
|
|
/* 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.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This code is based on original Sfinx source code
|
|
|
|
* Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "sound.h"
|
|
|
|
#include "cge2/cge2_main.h"
|
|
|
|
#include "cge2/cge2.h"
|
|
|
|
#include "cge2/vga13h.h"
|
|
|
|
#include "cge2/text.h"
|
2014-05-08 12:32:51 +00:00
|
|
|
#include "cge2/snail.h"
|
2014-05-08 17:23:36 +00:00
|
|
|
#include "cge2/hero.h"
|
2014-05-13 07:07:32 +00:00
|
|
|
#include "cge2/spare.h"
|
2014-05-19 15:10:18 +00:00
|
|
|
#include "cge2/events.h"
|
2014-06-08 07:53:47 +00:00
|
|
|
#include "cge2/map.h"
|
2014-06-20 23:57:18 +00:00
|
|
|
#include "cge2/vmenu.h"
|
2014-05-05 16:59:17 +00:00
|
|
|
|
|
|
|
namespace CGE2 {
|
|
|
|
|
2014-05-26 07:37:52 +00:00
|
|
|
System::System(CGE2Engine *vm) : Sprite(vm), _vm(vm) {
|
2014-06-19 09:34:25 +00:00
|
|
|
_blinkCounter = 0;
|
|
|
|
_blinkSprite = nullptr;
|
|
|
|
tick();
|
2014-05-26 07:37:52 +00:00
|
|
|
}
|
|
|
|
|
2014-06-07 18:33:52 +00:00
|
|
|
void System::touch(uint16 mask, V2D pos, Common::KeyCode keyCode) {
|
|
|
|
if (mask & kEventKeyb) {
|
|
|
|
if (keyCode == Common::KEYCODE_ESCAPE) {
|
|
|
|
// The original was calling keyClick()
|
|
|
|
// The sound is uselessly annoying and noisy, so it has been removed
|
|
|
|
_vm->killText();
|
|
|
|
if (_vm->_startupMode == 1) {
|
|
|
|
_vm->_commandHandler->addCommand(kCmdClear, -1, 0, NULL);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (_vm->_startupMode)
|
|
|
|
return;
|
|
|
|
_vm->_infoLine->setText(nullptr);
|
|
|
|
|
|
|
|
if (mask & kMouseLeftUp) {
|
|
|
|
if (pos.y >= 0) { // world
|
|
|
|
if (!_vm->_talk && pos.y < _vm->_mouseTop)
|
|
|
|
_vm->_heroTab[_vm->_sex]->_ptr->walkTo(pos);
|
|
|
|
} else { // panel
|
|
|
|
if (_vm->_commandHandler->idle()) {
|
|
|
|
int sex = pos.x < kPocketsWidth;
|
|
|
|
if (sex || pos.x >= kScrWidth - kPocketsWidth) {
|
|
|
|
_vm->switchHero(sex);
|
|
|
|
if (_vm->_sex == sex) {
|
|
|
|
int dx = kPocketsWidth >> 1,
|
|
|
|
dy = 1 - (kPanHeight >> 1);
|
|
|
|
Sprite *s;
|
|
|
|
if (!sex)
|
|
|
|
pos.x -= kScrWidth - kPocketsWidth;
|
|
|
|
dx -= pos.x;
|
|
|
|
dy -= pos.y;
|
|
|
|
if (dx * dx + dy * dy > 10 * 10) {
|
|
|
|
int n = 0;
|
|
|
|
if (1 - pos.y >= (kPanHeight >> 1))
|
|
|
|
n += 2;
|
|
|
|
if (pos.x >= (kPocketsWidth >> 1))
|
|
|
|
++n;
|
|
|
|
s = _vm->_heroTab[_vm->_sex]->_pocket[n];
|
2014-06-19 09:34:25 +00:00
|
|
|
if (_vm->_sys->_blinkSprite)
|
|
|
|
_vm->_sys->_blinkSprite->_flags._hide = false;
|
|
|
|
if (_vm->_sys->_blinkSprite == s)
|
|
|
|
_vm->_sys->_blinkSprite = nullptr;
|
2014-06-07 18:33:52 +00:00
|
|
|
else
|
2014-06-19 09:34:25 +00:00
|
|
|
_vm->_sys->_blinkSprite = s;
|
2014-06-07 18:33:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-05-26 07:37:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void System::tick() {
|
2014-06-19 09:34:25 +00:00
|
|
|
_time = kSysTimeRate;
|
|
|
|
|
|
|
|
if (_blinkCounter)
|
|
|
|
--_blinkCounter;
|
|
|
|
else {
|
|
|
|
if (_blinkSprite)
|
|
|
|
_blinkSprite->_flags._hide ^= 1;
|
|
|
|
_blinkCounter = kBlinkRate;
|
|
|
|
}
|
2014-05-26 07:37:52 +00:00
|
|
|
}
|
|
|
|
|
2014-05-23 08:05:02 +00:00
|
|
|
int CGE2Engine::number(char *s) { // TODO: Rework it later to include the preceding token() call!
|
2014-05-13 08:37:23 +00:00
|
|
|
int r = atoi(s);
|
|
|
|
char *pp = strchr(s, ':');
|
|
|
|
if (pp)
|
|
|
|
r = (r << 8) + atoi(pp + 1);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
char *CGE2Engine::token(char *s) {
|
|
|
|
return strtok(s, " =\t,;/()");
|
|
|
|
}
|
|
|
|
|
2014-05-23 08:05:02 +00:00
|
|
|
char *CGE2Engine::tail(char *s) {
|
|
|
|
if (s && (*s == '='))
|
|
|
|
s++;
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
2014-05-13 08:37:23 +00:00
|
|
|
int CGE2Engine::takeEnum(const char **tab, const char *text) {
|
|
|
|
if (text) {
|
|
|
|
for (const char **e = tab; *e; e++) {
|
|
|
|
if (scumm_stricmp(text, *e) == 0) {
|
|
|
|
return e - tab;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
ID CGE2Engine::ident(const char *s) {
|
|
|
|
return ID(takeEnum(EncryptedStream::kIdTab, s));
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CGE2Engine::testBool(char *s) {
|
|
|
|
return number(s) != 0;
|
|
|
|
}
|
|
|
|
|
2014-05-09 11:11:50 +00:00
|
|
|
void CGE2Engine::badLab(const char *fn) {
|
|
|
|
error("Misplaced label in %s!", fn);
|
|
|
|
}
|
|
|
|
|
2014-05-08 12:32:51 +00:00
|
|
|
void CGE2Engine::loadSprite(const char *fname, int ref, int scene, V3D &pos) {
|
|
|
|
int shpcnt = 0;
|
|
|
|
int seqcnt = 0;
|
|
|
|
int cnt[kActions];
|
2014-05-08 17:23:36 +00:00
|
|
|
for (int i = 0; i < kActions; i++)
|
|
|
|
cnt[i] = 0;
|
2014-05-09 11:11:50 +00:00
|
|
|
ID section = kIdPhase;
|
2014-05-08 12:32:51 +00:00
|
|
|
bool frnt = true;
|
|
|
|
bool east = false;
|
|
|
|
bool port = false;
|
|
|
|
bool tran = false;
|
2014-05-08 17:23:36 +00:00
|
|
|
Hero *h;
|
2014-05-09 11:11:50 +00:00
|
|
|
ID id;
|
2014-05-08 17:23:36 +00:00
|
|
|
|
2014-05-09 11:11:50 +00:00
|
|
|
char tmpStr[kLineMax + 1];
|
2014-05-08 17:23:36 +00:00
|
|
|
mergeExt(tmpStr, fname, kSprExt);
|
|
|
|
|
|
|
|
if (_resman->exist(tmpStr)) { // sprite description file exist
|
|
|
|
EncryptedStream sprf(this, tmpStr);
|
|
|
|
if (sprf.err())
|
|
|
|
error("Bad SPR [%s]", tmpStr);
|
|
|
|
|
2014-05-09 11:11:50 +00:00
|
|
|
int label = kNoByte;
|
|
|
|
Common::String line;
|
|
|
|
|
|
|
|
for (line = sprf.readLine(); !sprf.eos(); line = sprf.readLine()){
|
2014-06-08 10:55:19 +00:00
|
|
|
if (line.empty())
|
2014-05-09 11:11:50 +00:00
|
|
|
continue;
|
2014-05-26 14:30:32 +00:00
|
|
|
Common::strlcpy(tmpStr, line.c_str(), sizeof(tmpStr));
|
|
|
|
|
2014-05-09 11:11:50 +00:00
|
|
|
char *p;
|
2014-05-13 08:37:23 +00:00
|
|
|
p = token(tmpStr);
|
2014-05-09 11:11:50 +00:00
|
|
|
if (*p == '@') {
|
|
|
|
if (label != kNoByte)
|
|
|
|
badLab(fname);
|
|
|
|
label = atoi(p + 1);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2014-05-13 08:37:23 +00:00
|
|
|
id = ident(p);
|
2014-05-09 11:11:50 +00:00
|
|
|
switch (id) {
|
|
|
|
case kIdName: // will be taken in Expand routine
|
|
|
|
if (label != kNoByte)
|
|
|
|
badLab(fname);
|
|
|
|
break;
|
|
|
|
case kIdType:
|
|
|
|
if (label != kNoByte)
|
|
|
|
badLab(fname);
|
|
|
|
break;
|
|
|
|
case kIdNear:
|
|
|
|
case kIdMTake:
|
|
|
|
case kIdFTake:
|
|
|
|
case kIdPhase:
|
|
|
|
case kIdSeq:
|
|
|
|
if (label != kNoByte)
|
|
|
|
badLab(fname);
|
|
|
|
section = id;
|
|
|
|
break;
|
|
|
|
case kIdFront:
|
|
|
|
if (label != kNoByte)
|
|
|
|
badLab(fname);
|
2014-05-13 08:37:23 +00:00
|
|
|
p = token(nullptr);
|
|
|
|
frnt = testBool(p);
|
2014-05-09 11:11:50 +00:00
|
|
|
break;
|
|
|
|
case kIdEast:
|
|
|
|
if (label != kNoByte)
|
|
|
|
badLab(fname);
|
2014-05-13 08:37:23 +00:00
|
|
|
p = token(nullptr);
|
|
|
|
east = testBool(p);
|
2014-05-09 11:11:50 +00:00
|
|
|
break;
|
|
|
|
case kIdPortable:
|
|
|
|
if (label != kNoByte)
|
|
|
|
badLab(fname);
|
2014-05-13 08:37:23 +00:00
|
|
|
p = token(nullptr);
|
|
|
|
port = testBool(p);
|
2014-05-09 11:11:50 +00:00
|
|
|
break;
|
|
|
|
case kIdTransparent:
|
|
|
|
if (label != kNoByte)
|
|
|
|
badLab(fname);
|
2014-05-13 08:37:23 +00:00
|
|
|
p = token(nullptr);
|
|
|
|
tran = testBool(p);
|
2014-05-09 11:11:50 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
if (id >= kIdNear)
|
|
|
|
break;
|
|
|
|
switch (section) {
|
|
|
|
case kIdNear:
|
|
|
|
case kIdMTake:
|
|
|
|
case kIdFTake:
|
2014-06-03 15:39:10 +00:00
|
|
|
if (_commandHandler->getComId(p) >= 0)
|
2014-05-09 11:11:50 +00:00
|
|
|
++cnt[section];
|
|
|
|
else
|
|
|
|
error("Bad line %d [%s]", sprf.getLineCount(), tmpStr);
|
|
|
|
break;
|
|
|
|
case kIdPhase:
|
|
|
|
if (label != kNoByte)
|
|
|
|
badLab(fname);
|
|
|
|
++shpcnt;
|
|
|
|
break;
|
|
|
|
case kIdSeq:
|
|
|
|
if (label != kNoByte)
|
|
|
|
badLab(fname);
|
|
|
|
++seqcnt;
|
|
|
|
break;
|
2014-06-03 20:34:39 +00:00
|
|
|
default:
|
|
|
|
break;
|
2014-05-09 11:11:50 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
label = kNoByte;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!shpcnt) {
|
|
|
|
error("No shapes - %s", fname);
|
|
|
|
}
|
|
|
|
} else // No sprite description: mono-shaped sprite with only .BMP file.
|
|
|
|
++shpcnt;
|
|
|
|
|
|
|
|
// Make sprite of choosen type:
|
|
|
|
char c = *fname | 0x20;
|
|
|
|
if (c >= 'a' && c <= 'z' && fname[1] == '0' && fname[2] == '\0') {
|
|
|
|
h = new Hero(this);
|
|
|
|
if (h) {
|
|
|
|
h->gotoxyz(pos);
|
|
|
|
_sprite = h;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
_sprite = new Sprite(this);
|
|
|
|
if (_sprite)
|
|
|
|
_sprite->gotoxyz(pos);
|
2014-05-08 17:23:36 +00:00
|
|
|
}
|
|
|
|
|
2014-05-09 11:11:50 +00:00
|
|
|
if (_sprite) {
|
2014-05-13 07:07:32 +00:00
|
|
|
_sprite->_ref = ref;
|
2014-05-19 15:56:19 +00:00
|
|
|
_sprite->_scene = scene;
|
2014-05-13 07:07:32 +00:00
|
|
|
|
2014-05-09 11:11:50 +00:00
|
|
|
_sprite->_flags._frnt = frnt;
|
|
|
|
_sprite->_flags._east = east;
|
|
|
|
_sprite->_flags._port = port;
|
|
|
|
_sprite->_flags._tran = tran;
|
|
|
|
_sprite->_flags._kill = true;
|
|
|
|
|
|
|
|
// Extract the filename, without the extension
|
|
|
|
Common::strlcpy(_sprite->_file, fname, sizeof(_sprite->_file));
|
|
|
|
char *p = strchr(_sprite->_file, '.');
|
|
|
|
if (p)
|
|
|
|
*p = '\0';
|
|
|
|
|
|
|
|
_sprite->_shpCnt = shpcnt;
|
2014-05-23 08:05:02 +00:00
|
|
|
_sprite->_seqCnt = seqcnt;
|
2014-05-09 11:11:50 +00:00
|
|
|
|
|
|
|
for (int i = 0; i < kActions; i++)
|
|
|
|
_sprite->_actionCtrl[i]._cnt = cnt[i];
|
|
|
|
}
|
2014-05-06 19:02:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CGE2Engine::loadScript(const char *fname) {
|
|
|
|
EncryptedStream scrf(this, fname);
|
|
|
|
|
|
|
|
if (scrf.err())
|
|
|
|
return;
|
|
|
|
|
|
|
|
bool ok = true;
|
|
|
|
int lcnt = 0;
|
|
|
|
|
|
|
|
char tmpStr[kLineMax + 1];
|
|
|
|
Common::String line;
|
|
|
|
|
|
|
|
for (line = scrf.readLine(); !scrf.eos(); line = scrf.readLine()) {
|
2014-06-08 10:55:19 +00:00
|
|
|
if (line.empty())
|
2014-05-26 14:30:32 +00:00
|
|
|
continue;
|
|
|
|
|
2014-05-06 19:02:58 +00:00
|
|
|
char *p;
|
|
|
|
|
|
|
|
lcnt++;
|
|
|
|
Common::strlcpy(tmpStr, line.c_str(), sizeof(tmpStr));
|
2014-05-26 14:30:32 +00:00
|
|
|
|
2014-05-06 19:02:58 +00:00
|
|
|
ok = false; // not OK if break
|
|
|
|
|
2014-05-08 12:32:51 +00:00
|
|
|
V3D P;
|
|
|
|
|
2014-05-06 19:02:58 +00:00
|
|
|
// sprite ident number
|
2014-05-13 08:37:23 +00:00
|
|
|
if ((p = token(tmpStr)) == NULL)
|
2014-05-06 19:02:58 +00:00
|
|
|
break;
|
2014-05-13 08:37:23 +00:00
|
|
|
int SpI = number(p);
|
2014-05-06 19:02:58 +00:00
|
|
|
|
|
|
|
// sprite file name
|
|
|
|
char *SpN;
|
2014-05-13 08:37:23 +00:00
|
|
|
if ((SpN = token(nullptr)) == NULL)
|
2014-05-06 19:02:58 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
// sprite scene
|
2014-05-13 08:37:23 +00:00
|
|
|
if ((p = token(nullptr)) == NULL)
|
2014-05-06 19:02:58 +00:00
|
|
|
break;
|
2014-05-13 08:37:23 +00:00
|
|
|
int SpA = number(p);
|
2014-05-06 19:02:58 +00:00
|
|
|
|
|
|
|
// sprite column
|
2014-05-13 08:37:23 +00:00
|
|
|
if ((p = token(nullptr)) == NULL)
|
2014-05-06 19:02:58 +00:00
|
|
|
break;
|
2014-05-13 08:37:23 +00:00
|
|
|
P._x = number(p);
|
2014-05-06 19:02:58 +00:00
|
|
|
|
|
|
|
// sprite row
|
2014-05-13 08:37:23 +00:00
|
|
|
if ((p = token(nullptr)) == NULL)
|
2014-05-06 19:02:58 +00:00
|
|
|
break;
|
2014-05-13 08:37:23 +00:00
|
|
|
P._y = number(p);
|
2014-05-06 19:02:58 +00:00
|
|
|
|
|
|
|
// sprite Z pos
|
2014-05-13 08:37:23 +00:00
|
|
|
if ((p = token(nullptr)) == NULL)
|
2014-05-06 19:02:58 +00:00
|
|
|
break;
|
2014-05-13 08:37:23 +00:00
|
|
|
P._z = number(p);
|
2014-05-06 19:02:58 +00:00
|
|
|
|
|
|
|
// sprite life
|
2014-05-13 08:37:23 +00:00
|
|
|
if ((p = token(nullptr)) == NULL)
|
2014-05-06 19:02:58 +00:00
|
|
|
break;
|
2014-05-13 08:37:23 +00:00
|
|
|
bool BkG = number(p) == 0;
|
2014-05-06 19:02:58 +00:00
|
|
|
|
|
|
|
ok = true; // no break: OK
|
|
|
|
|
|
|
|
_sprite = NULL;
|
2014-05-08 12:32:51 +00:00
|
|
|
loadSprite(SpN, SpI, SpA, P);
|
2014-05-06 19:02:58 +00:00
|
|
|
if (_sprite) {
|
|
|
|
if (BkG)
|
|
|
|
_sprite->_flags._back = true;
|
2014-05-13 07:07:32 +00:00
|
|
|
|
|
|
|
int n = _spare->count();
|
|
|
|
if (_spare->locate(_sprite->_ref) == nullptr)
|
2014-06-14 17:46:18 +00:00
|
|
|
_spare->dispose(_sprite);
|
2014-05-13 07:07:32 +00:00
|
|
|
_sprite = nullptr;
|
|
|
|
if (_spare->count() == n)
|
|
|
|
error("Durplicated reference! %s", SpN);
|
2014-05-06 19:02:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!ok)
|
2014-05-08 17:23:36 +00:00
|
|
|
error("Bad INI line %d [%s]", scrf.getLineCount(), fname);
|
2014-05-06 19:02:58 +00:00
|
|
|
}
|
|
|
|
|
2014-05-05 16:59:17 +00:00
|
|
|
void CGE2Engine::movie(const char *ext) {
|
2014-05-06 19:02:58 +00:00
|
|
|
assert(ext);
|
|
|
|
|
|
|
|
if (_quitFlag)
|
|
|
|
return;
|
|
|
|
|
|
|
|
char fn[12];
|
|
|
|
sprintf(fn, "CGE.%s", (*ext == '.') ? ext + 1 : ext);
|
|
|
|
|
|
|
|
if (_resman->exist(fn)) {
|
|
|
|
int now = _now;
|
2014-05-13 07:27:50 +00:00
|
|
|
_now = atoi(ext + 2);
|
2014-05-06 19:02:58 +00:00
|
|
|
loadScript(fn);
|
2014-06-15 19:23:14 +00:00
|
|
|
sceneUp(_now);
|
2014-05-06 19:02:58 +00:00
|
|
|
|
2014-05-23 08:55:58 +00:00
|
|
|
while (!_commandHandler->idle() && !_quitFlag)
|
|
|
|
mainLoop();
|
|
|
|
|
2014-05-08 08:45:38 +00:00
|
|
|
warning("STUB: CGE2Engine::movie()");
|
2014-05-06 19:02:58 +00:00
|
|
|
|
2014-05-23 08:55:58 +00:00
|
|
|
_commandHandler->addCommand(kCmdClear, -1, 0, nullptr);
|
|
|
|
_commandHandlerTurbo->addCommand(kCmdClear, -1, 0, nullptr);
|
|
|
|
_spare->clear();
|
2014-05-06 19:02:58 +00:00
|
|
|
_now = now;
|
|
|
|
}
|
2014-05-05 16:59:17 +00:00
|
|
|
}
|
|
|
|
|
2014-06-15 19:23:14 +00:00
|
|
|
void CGE2Engine::sceneUp(int cav) {
|
2014-05-13 07:27:50 +00:00
|
|
|
_now = cav;
|
|
|
|
int bakRef = _now << 8;
|
|
|
|
if (_music)
|
|
|
|
_midiPlayer->loadMidi(bakRef);
|
|
|
|
showBak(bakRef);
|
2014-05-30 10:48:58 +00:00
|
|
|
*_eye = *(_eyeTab[_now]);
|
2014-05-17 20:34:31 +00:00
|
|
|
_mouseTop = V2D(this, V3D(0, 1, kScrDepth)).y;
|
2014-06-08 07:53:47 +00:00
|
|
|
_map->load(_now);
|
2014-06-15 19:23:14 +00:00
|
|
|
_spare->takeScene(_now);
|
2014-05-17 21:33:46 +00:00
|
|
|
openPocket();
|
|
|
|
|
2014-06-07 17:44:16 +00:00
|
|
|
for (int i = 0; i < 2; i++) {
|
|
|
|
Hero *h = _heroTab[i]->_ptr;
|
|
|
|
if (h && h->_scene == _now) {
|
|
|
|
V2D p = *_heroTab[i]->_posTab[_now];
|
|
|
|
h->gotoxyz(V3D(p.x, 0, p.y));
|
|
|
|
h->clrHide();
|
|
|
|
_vga->_showQ->insert(h);
|
|
|
|
h->park();
|
|
|
|
h->setCurrent();
|
|
|
|
h->setContact();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-19 14:16:24 +00:00
|
|
|
_sound->stop();
|
|
|
|
_fx->clear();
|
|
|
|
|
|
|
|
selectPocket(-1);
|
2014-05-19 14:32:53 +00:00
|
|
|
_infoLine->setText(nullptr);
|
2014-05-19 14:38:26 +00:00
|
|
|
busy(false);
|
2014-05-17 20:34:31 +00:00
|
|
|
|
2014-05-19 15:10:18 +00:00
|
|
|
if (!_dark)
|
|
|
|
_vga->sunset();
|
2014-05-23 09:19:42 +00:00
|
|
|
_vga->show();
|
2014-05-19 15:10:18 +00:00
|
|
|
_vga->copyPage(1, 0);
|
2014-05-23 09:19:42 +00:00
|
|
|
_vga->show();
|
2014-05-13 07:27:50 +00:00
|
|
|
|
2014-05-19 16:02:30 +00:00
|
|
|
_sprite = _vga->_showQ->first();
|
2014-05-29 16:19:01 +00:00
|
|
|
_vga->sunrise(_vga->_sysPal);
|
2014-05-19 21:24:23 +00:00
|
|
|
|
2014-06-01 19:44:07 +00:00
|
|
|
_dark = false;
|
|
|
|
|
|
|
|
if (!_startupMode)
|
|
|
|
_mouse->on();
|
|
|
|
|
2014-05-19 21:24:23 +00:00
|
|
|
feedSnail(_vga->_showQ->locate(bakRef + 255), kNear, _heroTab[_sex]->_ptr);
|
2014-05-23 08:12:48 +00:00
|
|
|
//setDrawColors(); - It's only for debugging purposes. Can be left out for now.
|
2014-05-13 07:27:50 +00:00
|
|
|
}
|
|
|
|
|
2014-06-17 13:37:55 +00:00
|
|
|
void CGE2Engine::sceneDown() {
|
|
|
|
busy(true);
|
|
|
|
_commandStat._wait = nullptr; // unlock snail
|
|
|
|
Sprite *spr = _vga->_showQ->locate((_now << 8) | 254);
|
|
|
|
if (spr)
|
|
|
|
feedSnail(spr, kNear, _heroTab[_sex]->_ptr);
|
|
|
|
while (!(_commandHandler->idle() && _commandHandlerTurbo->idle())) {
|
|
|
|
_commandHandlerTurbo->runCommand();
|
|
|
|
_commandHandler->runCommand();
|
|
|
|
}
|
|
|
|
closePocket();
|
|
|
|
for (int i = 0; i < 2; i++)
|
|
|
|
_spare->update(_vga->_showQ->remove(_heroTab[i]->_ptr));
|
|
|
|
_spare->dispose();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CGE2Engine::switchScene(int scene) {
|
|
|
|
if (scene == _now)
|
|
|
|
return;
|
|
|
|
|
2014-06-19 08:44:00 +00:00
|
|
|
/* TODO:: Recheck this flag-thing! As far as it seems it's only for checking if the game
|
|
|
|
is being run from the CD-ROM. In this context, it's useless for us.
|
|
|
|
|
2014-06-17 13:37:55 +00:00
|
|
|
if (scene >= 0) {
|
|
|
|
if (!_flag[2]) // PROT
|
|
|
|
_flag[2] = true;
|
|
|
|
else {
|
|
|
|
int t = _text->getText(kCrackedText) ? kCrackedText : kExitOkText;
|
|
|
|
_commandHandler->addCommand(kCmdInf, -1, t, nullptr);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2014-06-19 08:44:00 +00:00
|
|
|
*/
|
2014-06-17 13:37:55 +00:00
|
|
|
|
|
|
|
_req = scene;
|
2014-07-02 20:57:49 +00:00
|
|
|
|
|
|
|
saveHeroPos();
|
|
|
|
|
2014-06-17 13:37:55 +00:00
|
|
|
*(_eyeTab[_now]) = *_eye;
|
|
|
|
if (scene < 0)
|
|
|
|
_commandHandler->addCallback(kCmdExec, -1, 0, kQGame); // quit game
|
|
|
|
else {
|
|
|
|
if (_heroTab[_sex]->_ptr->_scene == _now) {
|
|
|
|
_heroTab[_sex]->_ptr->setScene(scene);
|
|
|
|
if (_heroTab[!_sex]->_ptr->_scene == _now)
|
|
|
|
_heroTab[!_sex]->_ptr->setScene(scene);
|
|
|
|
}
|
|
|
|
_mouse->off();
|
|
|
|
if (_heroTab[_sex]->_ptr)
|
|
|
|
_heroTab[_sex]->_ptr->park();
|
|
|
|
killText();
|
|
|
|
_commandHandler->addCallback(kCmdExec, -1, 0, kXScene); // switch scene
|
|
|
|
}
|
2014-05-23 13:23:19 +00:00
|
|
|
}
|
|
|
|
|
2014-07-02 20:57:49 +00:00
|
|
|
void CGE2Engine::saveHeroPos() {
|
|
|
|
for (int i = 0; i < 2; i++) {
|
|
|
|
Hero *h = _heroTab[i]->_ptr;
|
|
|
|
if (h->_scene == _now) {
|
|
|
|
delete _heroTab[i]->_posTab[_now];
|
|
|
|
V2D *temp = new V2D(this, h->_pos3D._x.trunc(), h->_pos3D._z.trunc());
|
|
|
|
_heroTab[i]->_posTab[_now] = temp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-13 07:27:50 +00:00
|
|
|
void CGE2Engine::showBak(int ref) {
|
2014-06-02 12:33:30 +00:00
|
|
|
Sprite *spr = _spare->take(ref);
|
2014-05-13 07:27:50 +00:00
|
|
|
if (spr != nullptr) {
|
|
|
|
_bitmapPalette = _vga->_sysPal;
|
|
|
|
spr->expand();
|
|
|
|
_bitmapPalette = NULL;
|
2014-05-15 13:03:59 +00:00
|
|
|
spr->show(2);
|
2014-05-13 07:27:50 +00:00
|
|
|
_vga->copyPage(1, 2);
|
|
|
|
_spare->dispose(spr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-23 08:55:58 +00:00
|
|
|
void CGE2Engine::mainLoop() {
|
|
|
|
_vga->show();
|
|
|
|
_commandHandlerTurbo->runCommand();
|
|
|
|
_commandHandler->runCommand();
|
|
|
|
|
|
|
|
// Handle a delay between game frames
|
|
|
|
handleFrame();
|
|
|
|
|
|
|
|
// Handle any pending events
|
2014-06-01 19:44:07 +00:00
|
|
|
_eventManager->poll();
|
2014-05-23 08:55:58 +00:00
|
|
|
|
|
|
|
// Check shouldQuit()
|
|
|
|
_quitFlag = shouldQuit();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CGE2Engine::handleFrame() {
|
|
|
|
// Game frame delay
|
|
|
|
uint32 millis = g_system->getMillis();
|
|
|
|
while (!_quitFlag && (millis < (_lastFrame + kGameFrameDelay))) {
|
|
|
|
// Handle any pending events
|
2014-06-01 19:44:07 +00:00
|
|
|
_eventManager->poll();
|
2014-05-23 08:55:58 +00:00
|
|
|
|
|
|
|
if (millis >= (_lastTick + kGameTickDelay)) {
|
|
|
|
// Dispatch the tick to any active objects
|
|
|
|
tick();
|
|
|
|
_lastTick = millis;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Slight delay
|
|
|
|
g_system->delayMillis(5);
|
|
|
|
millis = g_system->getMillis();
|
|
|
|
}
|
|
|
|
_lastFrame = millis;
|
|
|
|
|
|
|
|
if (millis >= (_lastTick + kGameTickDelay)) {
|
|
|
|
// Dispatch the tick to any active objects
|
|
|
|
tick();
|
|
|
|
_lastTick = millis;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-23 13:23:19 +00:00
|
|
|
Sprite *CGE2Engine::locate(int ref) {
|
|
|
|
_taken = false;
|
|
|
|
Sprite *spr = _vga->_showQ->locate(ref);
|
|
|
|
if (!spr) {
|
|
|
|
spr = _spare->locate(ref);
|
|
|
|
if (spr)
|
|
|
|
_taken = true;
|
|
|
|
}
|
|
|
|
return spr;
|
|
|
|
}
|
|
|
|
|
2014-05-24 07:04:41 +00:00
|
|
|
bool CGE2Engine::isHero(Sprite *spr) {
|
|
|
|
return spr && spr->_ref / 10 == 14;
|
|
|
|
}
|
|
|
|
|
2014-05-23 08:55:58 +00:00
|
|
|
void CGE2Engine::tick() {
|
2014-06-19 09:34:25 +00:00
|
|
|
// system pseudo-sprite
|
|
|
|
if (_sys && _sys->_time && (--_sys->_time == 0))
|
|
|
|
_sys->tick();
|
|
|
|
|
2014-05-23 08:55:58 +00:00
|
|
|
for (Sprite *spr = _vga->_showQ->first(); spr; spr = spr->_next) {
|
2014-06-09 21:34:40 +00:00
|
|
|
if (spr->_time && (--spr->_time == 0))
|
2014-05-24 06:59:06 +00:00
|
|
|
spr->tick();
|
2014-06-09 21:34:40 +00:00
|
|
|
|
2014-05-24 06:59:06 +00:00
|
|
|
if (_waitRef) {
|
2014-06-09 21:34:40 +00:00
|
|
|
if (_waitRef == spr->_ref && spr->seqTest(_waitSeq))
|
2014-05-24 06:59:06 +00:00
|
|
|
_waitRef = 0;
|
2014-05-23 08:55:58 +00:00
|
|
|
}
|
|
|
|
}
|
2014-05-24 06:59:06 +00:00
|
|
|
|
2014-06-01 19:44:07 +00:00
|
|
|
_mouse->tick();
|
2014-05-23 08:55:58 +00:00
|
|
|
}
|
|
|
|
|
2014-05-17 21:33:46 +00:00
|
|
|
void CGE2Engine::openPocket() {
|
2014-06-18 20:37:54 +00:00
|
|
|
for (int i = 0; i < 2; i++) {
|
|
|
|
for (int j = 0; j < kPocketMax + 1; j++) {
|
2014-06-26 19:07:24 +00:00
|
|
|
int ref = (int)_heroTab[i]->_downPocketId[j];
|
2014-06-18 20:37:54 +00:00
|
|
|
_heroTab[i]->_pocket[j] = (ref == -1) ? nullptr : _vga->_showQ->locate(ref);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CGE2Engine::closePocket() {
|
|
|
|
for (int i = 0; i < 2; i++) {
|
|
|
|
for (int j = 0; j < kPocketMax + 1; j++) {
|
|
|
|
Sprite *spr = _heroTab[i]->_pocket[j];
|
2014-06-26 19:07:24 +00:00
|
|
|
_heroTab[i]->_downPocketId[j] = (spr) ? spr->_ref : -1;
|
2014-06-18 20:37:54 +00:00
|
|
|
}
|
|
|
|
}
|
2014-05-17 21:33:46 +00:00
|
|
|
}
|
|
|
|
|
2014-06-18 20:37:54 +00:00
|
|
|
|
2014-05-19 14:16:24 +00:00
|
|
|
void CGE2Engine::selectPocket(int n) {
|
2014-06-18 20:37:54 +00:00
|
|
|
Sprite **p = _heroTab[_sex]->_pocket;
|
|
|
|
int &pp = _heroTab[_sex]->_pocPtr;
|
|
|
|
if (n < 0 || pp == n) {
|
|
|
|
n = findActivePocket(-1);
|
|
|
|
if (n >= 0)
|
|
|
|
pp = n;
|
|
|
|
} else if (p[n]) {
|
|
|
|
pp = n;
|
|
|
|
}
|
2014-05-19 14:16:24 +00:00
|
|
|
}
|
|
|
|
|
2014-05-19 14:38:26 +00:00
|
|
|
void CGE2Engine::busy(bool on) {
|
2014-06-23 09:50:49 +00:00
|
|
|
if (on) {
|
|
|
|
_spriteNotify = _midiNotify = &CGE2::CGE2Engine::busyStep;
|
|
|
|
busyStep();
|
|
|
|
} else {
|
|
|
|
if (_busyPtr)
|
|
|
|
_busyPtr->step(0);
|
|
|
|
_spriteNotify = _midiNotify = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CGE2Engine::busyStep() {
|
|
|
|
if (_busyPtr) {
|
|
|
|
_busyPtr->step((_busyPtr->_seqPtr) ? -1 : 1);
|
|
|
|
_busyPtr->show(0);
|
|
|
|
}
|
2014-05-19 14:38:26 +00:00
|
|
|
}
|
|
|
|
|
2014-05-05 16:59:17 +00:00
|
|
|
void CGE2Engine::runGame() {
|
2014-05-26 08:33:47 +00:00
|
|
|
if (_quitFlag)
|
|
|
|
return;
|
|
|
|
|
|
|
|
selectPocket(-1);
|
|
|
|
|
|
|
|
loadUser();
|
|
|
|
|
|
|
|
_commandHandlerTurbo->addCommand(kCmdSeq, kMusicRef, _music, nullptr);
|
|
|
|
if (!_music)
|
|
|
|
_midiPlayer->killMidi();
|
|
|
|
|
|
|
|
checkSaySwitch();
|
|
|
|
|
|
|
|
_infoLine->gotoxyz(V3D(kInfoX, kInfoY, 0));
|
|
|
|
_infoLine->setText(nullptr);
|
2014-06-06 20:07:32 +00:00
|
|
|
_vga->_showQ->insert(_infoLine);
|
2014-05-26 08:33:47 +00:00
|
|
|
|
2014-06-15 19:23:14 +00:00
|
|
|
sceneUp(_now);
|
2014-05-26 08:33:47 +00:00
|
|
|
_startupMode = 0;
|
|
|
|
_mouse->center();
|
|
|
|
_mouse->off();
|
|
|
|
_mouse->on();
|
|
|
|
|
|
|
|
_keyboard->setClient(_sys);
|
|
|
|
_commandHandler->addCommand(kCmdSeq, kPowerRef, 1, nullptr);
|
|
|
|
|
|
|
|
_busyPtr = _vga->_showQ->locate(kBusyRef);
|
|
|
|
|
|
|
|
_vol[0] = _vga->_showQ->locate(kDvolRef);
|
|
|
|
_vol[1] = _vga->_showQ->locate(kMvolRef);
|
|
|
|
|
|
|
|
// these sprites are loaded with SeqPtr==0 (why?!)
|
|
|
|
if (_vol[0])
|
|
|
|
_vol[0]->step((/*(int)SNDDrvInfo.VOL4.DL * */ _vol[0]->_seqCnt + _vol[0]->_seqCnt / 2) >> 4);
|
|
|
|
if (_vol[1])
|
|
|
|
_vol[1]->step((/*(int)SNDDrvInfo.VOL4.ML * */ _vol[1]->_seqCnt + _vol[1]->_seqCnt / 2) >> 4);
|
|
|
|
// TODO: Recheck these! ^
|
|
|
|
|
|
|
|
// main loop
|
|
|
|
while (!_endGame && !_quitFlag) {
|
|
|
|
if (_flag[3]) // Flag FINIS
|
|
|
|
_commandHandler->addCallback(kCmdExec, -1, 0, kQGame);
|
|
|
|
mainLoop();
|
|
|
|
}
|
|
|
|
|
|
|
|
// If finishing game due to closing ScummVM window, explicitly save the game
|
|
|
|
if (!_endGame && canSaveGameStateCurrently())
|
|
|
|
qGame();
|
|
|
|
|
|
|
|
_keyboard->setClient(nullptr);
|
|
|
|
_commandHandler->addCommand(kCmdClear, -1, 0, nullptr);
|
|
|
|
_commandHandlerTurbo->addCommand(kCmdClear, -1, 0, nullptr);
|
|
|
|
_mouse->off();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CGE2Engine::loadUser() {
|
2014-05-26 14:09:49 +00:00
|
|
|
warning("STUB: CGE2Engine::loadUser()");
|
|
|
|
// Missing loading from file. TODO: Implement it with the saving/loading!
|
|
|
|
loadScript("CGE.INI");
|
2014-06-29 18:36:54 +00:00
|
|
|
loadHeroes();
|
2014-05-26 13:58:07 +00:00
|
|
|
}
|
|
|
|
|
2014-06-29 18:36:54 +00:00
|
|
|
void CGE2Engine::loadHeroes() { // Original name: loadGame()
|
|
|
|
warning("STUB: CGE2Engine::loadHeroes()");
|
2014-06-02 12:37:41 +00:00
|
|
|
|
|
|
|
// load sprites & pocket
|
|
|
|
|
|
|
|
Sprite *s;
|
2014-06-03 20:12:59 +00:00
|
|
|
Hero *h = nullptr;
|
2014-06-02 12:37:41 +00:00
|
|
|
|
2014-06-03 05:42:17 +00:00
|
|
|
// initialize Andzia/Anna
|
2014-06-02 12:37:41 +00:00
|
|
|
s = _spare->take(142);
|
|
|
|
if (s) {
|
|
|
|
h = new Hero(this);
|
|
|
|
*(Sprite*)h = *s;
|
|
|
|
delete s;
|
|
|
|
h->expand();
|
|
|
|
_spare->update(h);
|
|
|
|
}
|
|
|
|
_heroTab[0]->_ptr = h;
|
|
|
|
s = _spare->take(152);
|
|
|
|
_vga->_showQ->insert(s);
|
|
|
|
_heroTab[0]->_face = s;
|
2014-07-02 22:39:23 +00:00
|
|
|
_spare->update(s);
|
2014-06-02 12:37:41 +00:00
|
|
|
|
2014-06-03 05:42:17 +00:00
|
|
|
// initialize Wacek/Vincent
|
2014-06-02 12:37:41 +00:00
|
|
|
s = _spare->take(141);
|
|
|
|
if (s) {
|
|
|
|
h = new Hero(this);
|
|
|
|
*(Sprite*)h = *s;
|
|
|
|
delete s;
|
|
|
|
h->expand();
|
|
|
|
_spare->update(h);
|
|
|
|
}
|
|
|
|
_heroTab[1]->_ptr = h;
|
|
|
|
s = _spare->take(151);
|
|
|
|
_vga->_showQ->insert(s);
|
|
|
|
_heroTab[1]->_face = s;
|
2014-07-02 22:39:23 +00:00
|
|
|
_spare->update(s);
|
2014-06-02 12:37:41 +00:00
|
|
|
|
|
|
|
//--- start!
|
|
|
|
switchHero(_sex);
|
2014-06-29 19:38:46 +00:00
|
|
|
|
|
|
|
loadPos();
|
2014-06-02 12:37:41 +00:00
|
|
|
}
|
|
|
|
|
2014-05-26 13:58:07 +00:00
|
|
|
void CGE2Engine::loadPos() {
|
|
|
|
if (_resman->exist("CGE.HXY")) {
|
2014-06-15 19:23:14 +00:00
|
|
|
for (int cav = 0; cav < kSceneMax; cav++)
|
2014-05-26 13:58:07 +00:00
|
|
|
_heroTab[1]->_posTab[cav] = new V2D(this, 180, 10);
|
|
|
|
|
|
|
|
EncryptedStream file(this, "CGE.HXY");
|
|
|
|
|
2014-06-15 19:23:14 +00:00
|
|
|
for (int cav = 0; cav < kSceneMax; cav++) {
|
2014-06-17 13:38:24 +00:00
|
|
|
_heroTab[0]->_posTab[cav] = new V2D(this);
|
2014-05-26 13:58:07 +00:00
|
|
|
_heroTab[0]->_posTab[cav]->x = file.readSint16LE();
|
|
|
|
_heroTab[0]->_posTab[cav]->y = file.readSint16LE();
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int cav = 0; cav < 41; cav++) { // (564 - 400) / 4 = 41
|
|
|
|
_heroTab[1]->_posTab[cav]->x = file.readSint16LE();
|
|
|
|
_heroTab[1]->_posTab[cav]->y = file.readSint16LE();
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
error("Missing file: CGE.HXY");
|
2014-05-26 08:33:47 +00:00
|
|
|
}
|
|
|
|
|
2014-05-29 17:58:38 +00:00
|
|
|
void CGE2Engine::releasePocket(Sprite *spr) {
|
2014-06-13 17:52:28 +00:00
|
|
|
for (int i = 0; i < 2; i++) {
|
|
|
|
for (int j = 0; j < kPocketMax; j++) {
|
2014-06-23 11:11:54 +00:00
|
|
|
Sprite *&poc = _heroTab[i]->_pocket[j];
|
2014-06-13 17:52:28 +00:00
|
|
|
if (poc == spr) {
|
|
|
|
spr->_flags._kept = false;
|
|
|
|
poc = nullptr;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-05-29 17:58:38 +00:00
|
|
|
}
|
|
|
|
|
2014-05-26 08:33:47 +00:00
|
|
|
void CGE2Engine::checkSaySwitch() {
|
2014-06-24 20:14:19 +00:00
|
|
|
// if (SNDDrvInfo.DDEV == DEV_QUIET)
|
|
|
|
// _sayVox = !(_sayCap = true);
|
|
|
|
_commandHandlerTurbo->addCommand(kCmdSeq, 129, _sayVox, nullptr);
|
|
|
|
_commandHandlerTurbo->addCommand(kCmdSeq, 128, _sayCap, nullptr);
|
2014-05-26 08:33:47 +00:00
|
|
|
}
|
|
|
|
|
2014-05-15 08:59:46 +00:00
|
|
|
void CGE2Engine::loadTab() {
|
|
|
|
setEye(_text->getText(240));
|
2014-06-15 19:23:14 +00:00
|
|
|
for (int i = 0; i < kSceneMax; i++)
|
2014-05-30 10:48:58 +00:00
|
|
|
*(_eyeTab[i]) = *_eye;
|
2014-05-15 08:59:46 +00:00
|
|
|
|
2014-06-14 23:34:30 +00:00
|
|
|
if (_resman->exist(kTabName)) {
|
2014-05-15 23:04:01 +00:00
|
|
|
EncryptedStream f(this, kTabName);
|
2014-06-14 23:34:30 +00:00
|
|
|
uint32 v;
|
|
|
|
|
2014-06-15 19:23:14 +00:00
|
|
|
for (int i = 0; i < kSceneMax; i++) {
|
2014-06-14 23:34:30 +00:00
|
|
|
v = f.readUint32LE();
|
|
|
|
_eyeTab[i]->_x = FXP(v >> 8, static_cast<int>((int8)(v & 0xff)));
|
2014-06-12 05:20:55 +00:00
|
|
|
|
2014-06-14 23:34:30 +00:00
|
|
|
v = f.readUint32LE();
|
|
|
|
_eyeTab[i]->_y = FXP(v >> 8, static_cast<int>((int8)(v & 0xff)));
|
2014-06-12 05:20:55 +00:00
|
|
|
|
2014-06-14 23:34:30 +00:00
|
|
|
v = f.readUint32LE();
|
|
|
|
_eyeTab[i]->_z = FXP(v >> 8, static_cast<int>((int8)(v & 0xff)));
|
2014-05-15 23:04:01 +00:00
|
|
|
}
|
|
|
|
}
|
2014-05-15 08:59:46 +00:00
|
|
|
}
|
|
|
|
|
2014-05-05 16:59:17 +00:00
|
|
|
void CGE2Engine::cge2_main() {
|
|
|
|
warning("STUB: CGE2Engine::cge2_main()");
|
|
|
|
|
2014-05-15 08:59:46 +00:00
|
|
|
loadTab();
|
|
|
|
|
2014-05-05 16:59:17 +00:00
|
|
|
_mode++;
|
|
|
|
|
|
|
|
if (showTitle("WELCOME")) {
|
2014-05-26 13:57:23 +00:00
|
|
|
#if 0
|
2014-05-05 16:59:17 +00:00
|
|
|
if (_mode == 1)
|
|
|
|
movie(kIntroExt);
|
2014-05-26 13:57:23 +00:00
|
|
|
#endif
|
2014-05-05 16:59:17 +00:00
|
|
|
if (_text->getText(255) != NULL) {
|
|
|
|
runGame();
|
|
|
|
_startupMode = 2;
|
|
|
|
} else
|
|
|
|
_vga->sunset();
|
|
|
|
} else
|
|
|
|
_vga->sunset();
|
|
|
|
}
|
|
|
|
|
|
|
|
char *CGE2Engine::mergeExt(char *buf, const char *name, const char *ext) {
|
|
|
|
strcpy(buf, name);
|
|
|
|
char *dot = strrchr(buf, '.');
|
|
|
|
if (!dot)
|
|
|
|
strcat(buf, ext);
|
|
|
|
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
2014-05-30 10:48:58 +00:00
|
|
|
void CGE2Engine::setEye(const V3D &e) {
|
|
|
|
*_eye = e;
|
2014-05-15 08:58:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CGE2Engine::setEye(const V2D& e2, int z) {
|
|
|
|
_eye->_x = e2.x;
|
|
|
|
_eye->_y = e2.y;
|
|
|
|
_eye->_z = z;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CGE2Engine::setEye(const char *s) {
|
|
|
|
char tempStr[kLineMax];
|
|
|
|
strcpy(tempStr, s);
|
|
|
|
_eye->_x = atoi(token(tempStr));
|
|
|
|
_eye->_y = atoi(token(NULL));
|
|
|
|
_eye->_z = atoi(token(NULL));
|
|
|
|
}
|
|
|
|
|
2014-05-15 10:21:24 +00:00
|
|
|
int CGE2Engine::newRandom(int range) {
|
|
|
|
if (!range)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return _randomSource.getRandomNumber(range - 1);
|
|
|
|
}
|
|
|
|
|
2014-05-15 10:23:27 +00:00
|
|
|
bool CGE2Engine::showTitle(const char *name) {
|
|
|
|
if (_quitFlag)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
_bitmapPalette = _vga->_sysPal;
|
2014-06-06 12:57:34 +00:00
|
|
|
BitmapPtr LB = new Bitmap[1];
|
|
|
|
LB[0] = Bitmap(this, name);
|
|
|
|
_bitmapPalette = nullptr;
|
2014-05-15 10:23:27 +00:00
|
|
|
|
|
|
|
Sprite D(this, LB, 1);
|
|
|
|
D._flags._kill = true;
|
2014-06-06 12:57:34 +00:00
|
|
|
strcpy(D._file, "hatter");
|
2014-05-15 10:23:27 +00:00
|
|
|
warning("STUB: Sprite::showTitle() - Flags changed compared to CGE1's Sprite type.");
|
|
|
|
D.gotoxyz(kScrWidth >> 1, -(kPanHeight >> 1));
|
|
|
|
_vga->sunset();
|
|
|
|
|
|
|
|
D.show(2);
|
|
|
|
|
|
|
|
_vga->copyPage(1, 2);
|
|
|
|
_vga->copyPage(0, 1);
|
|
|
|
|
|
|
|
_vga->sunrise(_vga->_sysPal);
|
|
|
|
|
|
|
|
_vga->update();
|
|
|
|
|
|
|
|
warning("STUB: CGE2Engine::showTitle()");
|
2014-06-06 12:57:34 +00:00
|
|
|
|
2014-05-15 10:23:27 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-05-19 21:24:23 +00:00
|
|
|
int CGE2Engine::freePockets(int sx) {
|
|
|
|
int n = 0;
|
|
|
|
for (int i = 0; i < kPocketMax; i++){
|
|
|
|
if (_heroTab[sx]->_pocket[i] == nullptr)
|
|
|
|
++n;
|
|
|
|
}
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
|
|
|
int CGE2Engine::findActivePocket(int ref) {
|
|
|
|
for (int i = 0; i < kPocketMax; i++) {
|
|
|
|
Sprite *spr = _heroTab[_sex]->_pocket[i];
|
|
|
|
if (ref >= 0) {
|
|
|
|
if (spr && spr->_ref == ref)
|
|
|
|
return i;
|
|
|
|
} else if (!spr)
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CGE2Engine::pocFul() {
|
|
|
|
Hero *h = _heroTab[_sex]->_ptr;
|
|
|
|
h->park();
|
|
|
|
_commandHandler->addCommand(kCmdWait, -1, -1, h);
|
|
|
|
_commandHandler->addCommand(kCmdSound, -1, 2, h);
|
|
|
|
_commandHandler->addCommand(kCmdSay, -1, kPocketFull + _sex, h);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CGE2Engine::killText() {
|
|
|
|
if (!_talk)
|
|
|
|
return;
|
|
|
|
|
|
|
|
_commandHandlerTurbo->addCommand(kCmdKill, -1, 0, _talk);
|
|
|
|
_talk = NULL;
|
|
|
|
}
|
|
|
|
|
2014-06-03 05:42:17 +00:00
|
|
|
void CGE2Engine::switchHero(int sex) {
|
2014-06-02 11:58:52 +00:00
|
|
|
if (sex != _sex) {
|
|
|
|
int scene = _heroTab[sex]->_ptr->_scene;
|
2014-06-19 09:34:25 +00:00
|
|
|
if (_sys->_blinkSprite) {
|
|
|
|
_sys->_blinkSprite->_flags._hide = false;
|
|
|
|
_sys->_blinkSprite = nullptr;
|
2014-06-02 11:58:52 +00:00
|
|
|
}
|
|
|
|
if (scene >= 0) {
|
|
|
|
_commandHandler->addCommand(kCmdSeq, -1, 2, _heroTab[_sex]->_face);
|
2014-06-03 05:42:17 +00:00
|
|
|
_sex ^= 1;
|
2014-06-15 19:23:14 +00:00
|
|
|
switchScene(scene);
|
2014-06-02 11:58:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
Sprite *face = _heroTab[_sex]->_face;
|
|
|
|
if (face->_seqPtr == 0)
|
|
|
|
_commandHandler->addCommand(kCmdSeq, -1, 1, face);
|
2014-05-29 17:58:38 +00:00
|
|
|
}
|
|
|
|
|
2014-06-02 12:46:59 +00:00
|
|
|
#pragma argsused
|
2014-06-15 19:29:32 +00:00
|
|
|
void Sprite::touch(uint16 mask, V2D pos, Common::KeyCode keyCode) {
|
2014-06-02 12:46:59 +00:00
|
|
|
if ((mask & kEventAttn) != 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!_vm->_startupMode)
|
|
|
|
_vm->_infoLine->setText(name());
|
|
|
|
|
|
|
|
if (_ref < 0)
|
|
|
|
return; // cannot access system sprites
|
|
|
|
|
|
|
|
if (_ref / 10 == 12) {
|
|
|
|
_vm->optionTouch(_ref % 10, mask);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-06-13 20:19:41 +00:00
|
|
|
if ((mask & kMouseLeftUp) && _vm->_commandHandler->idle()) {
|
2014-06-19 09:34:25 +00:00
|
|
|
if (_vm->isHero(this) && !_vm->_sys->_blinkSprite) {
|
2014-06-13 20:19:41 +00:00
|
|
|
_vm->switchHero((this == _vm->_heroTab[1]->_ptr) ? 1 : 0);
|
|
|
|
} else if (_flags._kept) { // sprite in pocket
|
|
|
|
for (int sex = 0; sex < 2; ++sex) {
|
|
|
|
for (int p = 0; p < kPocketMax; ++p) {
|
|
|
|
if (_vm->_heroTab[sex]->_pocket[p] == this) {
|
|
|
|
_vm->switchHero(sex);
|
|
|
|
if (_vm->_sex == sex) {
|
2014-06-19 09:34:25 +00:00
|
|
|
if (_vm->_sys->_blinkSprite)
|
|
|
|
_vm->_sys->_blinkSprite->_flags._hide = false;
|
|
|
|
if (_vm->_sys->_blinkSprite == this)
|
|
|
|
_vm->_sys->_blinkSprite = nullptr;
|
2014-06-13 20:19:41 +00:00
|
|
|
else
|
2014-06-19 09:34:25 +00:00
|
|
|
_vm->_sys->_blinkSprite = this;
|
2014-06-13 20:19:41 +00:00
|
|
|
}
|
2014-06-02 12:46:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-06-13 20:19:41 +00:00
|
|
|
} else { // sprite NOT in pocket
|
|
|
|
Hero *h = _vm->_heroTab[_vm->_sex]->_ptr;
|
|
|
|
if (!_vm->_talk) {
|
2014-06-23 16:10:05 +00:00
|
|
|
// HACK: the "+3" is a ugly hack used to compensate a pathfinding issue. To be fixed!!
|
|
|
|
if ((_ref & 0xFF) < 200 && h->distance(this) > (h->_maxDist << 1) + 3)
|
2014-06-13 20:19:41 +00:00
|
|
|
h->walkTo(this);
|
2014-06-19 09:34:25 +00:00
|
|
|
else if (_vm->_sys->_blinkSprite) {
|
|
|
|
if (works(_vm->_sys->_blinkSprite)) {
|
|
|
|
_vm->feedSnail(_vm->_sys->_blinkSprite, (_vm->_sex) ? kMTake : kFTake, _vm->_heroTab[_vm->_sex]->_ptr);
|
|
|
|
_vm->_sys->_blinkSprite->_flags._hide = false;
|
|
|
|
_vm->_sys->_blinkSprite = nullptr;
|
2014-06-13 20:19:41 +00:00
|
|
|
} else
|
2014-06-03 05:35:21 +00:00
|
|
|
_vm->offUse();
|
2014-06-13 20:19:41 +00:00
|
|
|
|
|
|
|
_vm->selectPocket(-1);
|
|
|
|
// else, no pocket sprite selected
|
|
|
|
} else if (_flags._port) { // portable
|
|
|
|
if (_vm->findActivePocket(-1) < 0)
|
|
|
|
_vm->pocFul();
|
|
|
|
else {
|
|
|
|
_vm->_commandHandler->addCommand(kCmdReach, -2, _ref, nullptr);
|
|
|
|
_vm->_commandHandler->addCommand(kCmdKeep, -1, -1, this);
|
|
|
|
_flags._port = false;
|
|
|
|
}
|
|
|
|
} else { // non-portable
|
|
|
|
Action a = h->action();
|
|
|
|
if (_actionCtrl[a]._cnt) {
|
|
|
|
CommandHandler::Command *cmdList = snList(a);
|
|
|
|
if (cmdList[_actionCtrl[a]._ptr]._commandType == kCmdNext)
|
|
|
|
_vm->offUse();
|
|
|
|
else
|
|
|
|
_vm->feedSnail(this, a, h);
|
|
|
|
} else
|
|
|
|
_vm->offUse();
|
|
|
|
}
|
2014-06-02 12:46:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CGE2Engine::optionTouch(int opt, uint16 mask) {
|
2014-06-19 10:30:44 +00:00
|
|
|
switch (opt) {
|
|
|
|
case 1:
|
|
|
|
if (mask & kMouseLeftUp)
|
|
|
|
switchColorMode();
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
if (mask & kMouseLeftUp)
|
|
|
|
switchMusic();
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
if (mask & kMouseLeftUp)
|
|
|
|
quit();
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
if (mask & (kMouseLeftUp | kMouseRightUp))
|
|
|
|
setVolume(opt - 4, (mask & kMouseLeftUp) ? 1 : -1);
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
if (mask & (kMouseLeftUp | kMouseRightUp))
|
|
|
|
setVolume(opt - 4, (mask & kMouseLeftUp) ? 1 : -1);
|
|
|
|
break;
|
|
|
|
case 8:
|
|
|
|
if (mask & kMouseLeftUp)
|
|
|
|
switchCap();
|
|
|
|
break;
|
|
|
|
case 9:
|
|
|
|
if (mask & kMouseLeftUp)
|
|
|
|
switchVox();
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CGE2Engine::switchColorMode() {
|
|
|
|
warning("STUB: CGE2Engine::switchColorMode()");
|
|
|
|
}
|
|
|
|
|
|
|
|
void CGE2Engine::switchMusic() {
|
|
|
|
warning("STUB: CGE2Engine::switchMusic()");
|
|
|
|
}
|
|
|
|
|
|
|
|
void CGE2Engine::quit() {
|
2014-06-20 23:57:18 +00:00
|
|
|
Common::Array<Choice *> quitMenu; // Deleted in VMenu's destructor.
|
|
|
|
quitMenu.push_back(new StartCountDownChoice(this));
|
|
|
|
quitMenu.push_back(new ResetQSwitchChoice(this));
|
|
|
|
|
|
|
|
if (_commandHandler->idle()) {
|
|
|
|
if (VMenu::_addr) {
|
|
|
|
_commandHandlerTurbo->addCommand(kCmdKill, -1, 0, VMenu::_addr);
|
|
|
|
ResetQSwitchChoice rqsChoice(this);
|
|
|
|
rqsChoice.proc();
|
|
|
|
} else {
|
|
|
|
quitMenu[0]->_text = _text->getText(kQuitText);
|
|
|
|
quitMenu[1]->_text = _text->getText(kNoQuitText);
|
|
|
|
(new VMenu(this, quitMenu, V2D(this, -1, -1), kCBMnu))->setName(_text->getText(kQuitTitle));
|
|
|
|
_commandHandlerTurbo->addCommand(kCmdSeq, kPowerRef, 0, nullptr);
|
|
|
|
keyClick();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CGE2Engine::keyClick() {
|
|
|
|
_commandHandlerTurbo->addCommand(kCmdSound, -1, 5, nullptr);
|
2014-06-19 10:30:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CGE2Engine::setVolume(int idx, int cnt) {
|
|
|
|
warning("STUB: CGE2Engine::setVolume()");
|
|
|
|
}
|
|
|
|
|
|
|
|
void CGE2Engine::switchCap() {
|
|
|
|
warning("STUB: CGE2Engine::switchCap()");
|
|
|
|
}
|
|
|
|
|
|
|
|
void CGE2Engine::switchVox() {
|
|
|
|
warning("STUB: CGE2Engine::switchVox()");
|
2014-06-02 12:46:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CGE2Engine::offUse() {
|
2014-06-18 21:34:26 +00:00
|
|
|
int seq = 0;
|
|
|
|
int offUseCount = atoi(_text->getText(kOffUseCount));
|
|
|
|
|
|
|
|
// This fixes the issue of empty speech bubbles in the original.
|
|
|
|
// Now we only let this cycle pass if it randoms a valid value for getText().
|
|
|
|
int txt = 0;
|
|
|
|
do {
|
|
|
|
txt = kOffUseText + _sex * offUseCount + newRandom(offUseCount);
|
|
|
|
} while (_text->getText(txt) == nullptr);
|
|
|
|
|
|
|
|
Hero *h = _heroTab[_sex]->_ptr;
|
|
|
|
h->park();
|
|
|
|
_commandHandler->addCommand(kCmdWait, -1, -1, h);
|
|
|
|
_commandHandler->addCommand(kCmdSeq, -1, seq, h);
|
|
|
|
if (!_sayVox)
|
|
|
|
_commandHandler->addCommand(kCmdSound, -1, 6 + _sex, h);
|
|
|
|
_commandHandler->addCommand(kCmdWait, -1, -1, h);
|
|
|
|
_commandHandler->addCommand(kCmdSay, -1, txt, h);
|
2014-06-02 12:46:59 +00:00
|
|
|
}
|
|
|
|
|
2014-06-15 19:11:27 +00:00
|
|
|
Sprite *CGE2Engine::spriteAt(V2D pos) {
|
|
|
|
Sprite *spr;
|
|
|
|
|
|
|
|
for (spr = _vga->_showQ->last(); spr; spr = spr->_prev) {
|
|
|
|
if (!spr->_flags._hide && !spr->_flags._tran) {
|
|
|
|
if (spr->getShp()->solidAt(pos - spr->_pos2D))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return spr;
|
|
|
|
}
|
2014-06-02 12:46:59 +00:00
|
|
|
|
2014-05-05 16:59:17 +00:00
|
|
|
} // End of namespace CGE2
|