scummvm/engines/cge/snail.cpp
Tomasz Długosz eaab877d66 JANITORIAL: fix the name of original author of cge and cge2
The first name is Janusz, not Janus.
The correct name was used in AUTHORS and credits.
In case of doubts, see his personal webpage: https://www.jbw.pl/ - name is in the page footer
2020-04-18 20:59:57 +02:00

1283 lines
35 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 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 Soltys source code
* Copyright (c) 1994-1995 Janusz B. Wisniewski and L.K. Avalon
*/
#include "cge/general.h"
#include "cge/sound.h"
#include "cge/snail.h"
#include "cge/vga13h.h"
#include "cge/text.h"
#include "cge/cge_main.h"
#include "cge/events.h"
#include "cge/walk.h"
namespace CGE {
const char *CommandHandler::_commandText[] = {
"LABEL", "PAUSE", "WAIT", "LEVEL", "HIDE",
"SAY", "INF", "TIME", "CAVE", "KILL",
"RSEQ", "SEQ", "SEND", "SWAP", "KEEP",
"GIVE", "IF", "GAME", "SETX0", "SETY0",
"SLAVE", "SETXY", "RELX", "RELY", "RELZ",
"SETX", "SETY", "SETZ", "TRANS", "PORT",
"NEXT", "NNEXT", "TNEXT", "RNNEXT", "RTNEXT",
"RMNEAR", "RMTAKE", "FLAG", "SETREF", "BACKPT",
"FLASH", "LIGHT", "SETHB", "SETVB", "WALK",
"REACH", "COVER", "UNCOVER", "CLEAR", "TALK",
"MOUSE", "SOUND", "COUNT", NULL
};
CommandHandler::CommandHandler(CGEEngine *vm, bool turbo)
: _turbo(turbo), _busy(false), _textDelay(false),
_timerExpiry(0), _talkEnable(true),
_head(0), _tail(0), _commandList((Command *)malloc(sizeof(Command) * 256)), _vm(vm) {
}
CommandHandler::~CommandHandler() {
free(_commandList);
}
/**
* Add a Command on the head of _commandList
* @param com Command
* @param ref Reference
* @param val Value
* @param ptr Sprite pointer
*/
void CommandHandler::addCommand(CommandType com, int ref, int val, void *ptr) {
Command *headCmd = &_commandList[_head++];
headCmd->_commandType = com;
headCmd->_ref = ref;
headCmd->_val = val;
headCmd->_spritePtr = ptr;
headCmd->_cbType = kNullCB;
if (headCmd->_commandType == kCmdClear) {
_tail = _head;
_vm->killText();
_timerExpiry = 0;
}
}
/**
* Add a Callback on the head of _commandList
* @param com Command
* @param ref Reference
* @param val Value
* @param CallbackType Callback type
*/
void CommandHandler::addCallback(CommandType com, int ref, int val, CallbackType cbType) {
Command *headCmd = &_commandList[_head++];
headCmd->_commandType = com;
headCmd->_ref = ref;
headCmd->_val = val;
headCmd->_spritePtr = NULL;
headCmd->_cbType = cbType;
if (headCmd->_commandType == kCmdClear) {
_tail = _head;
_vm->killText();
_timerExpiry = 0;
}
}
/**
* Add a Command on the tail of _commandList
* @param com Command
* @param ref Reference
* @param val Value
* @param ptr Sprite pointer
*/
void CommandHandler::insertCommand(CommandType com, int ref, int val, void *ptr) {
Command *tailCmd;
if (_busy) {
_commandList[(_tail - 1) & 0xFF] = _commandList[_tail];
tailCmd = &_commandList[_tail];
} else
tailCmd = &_commandList[(_tail - 1) & 0xFF];
_tail--;
tailCmd->_commandType = com;
tailCmd->_ref = ref;
tailCmd->_val = val;
tailCmd->_spritePtr = ptr;
tailCmd->_cbType = kNullCB;
if (tailCmd->_commandType == kCmdClear) {
_tail = _head;
_vm->killText();
_timerExpiry = 0;
}
}
void CommandHandler::runCommand() {
if (_busy)
return;
_busy = true;
uint8 tmpHead = _head;
while (_tail != tmpHead) {
Command *tailCmd = &_commandList[_tail];
if (!_turbo) { // only for the slower one
if (_timerExpiry) {
// Delay in progress
if (_timerExpiry > g_system->getMillis())
// Delay not yet ended
break;
// Delay is finished
_timerExpiry = 0;
} else {
if (_textDelay) {
_vm->killText();
_textDelay = false;
}
}
if (_vm->_talk && tailCmd->_commandType != kCmdPause)
break;
}
Sprite *spr = ((tailCmd->_ref >= 0) ? _vm->locate(tailCmd->_ref) : ((Sprite *) tailCmd->_spritePtr));
switch (tailCmd->_commandType) {
case kCmdLabel:
break;
case kCmdPause:
_timerExpiry = g_system->getMillis() + tailCmd->_val * kCommandFrameDelay;
if (_vm->_talk)
_textDelay = true;
break;
case kCmdWait:
if (spr) {
if (spr->seqTest(tailCmd->_val) &&
(tailCmd->_val >= 0 || spr != _vm->_hero || _vm->_hero->_tracePtr < 0)) {
_timerExpiry = g_system->getMillis() + spr->_time * kCommandFrameDelay;
} else {
_busy = false;
return;
}
}
break;
case kCmdLevel:
_vm->snLevel(spr, tailCmd->_val);
break;
case kCmdHide:
_vm->snHide(spr, tailCmd->_val);
break;
case kCmdSay:
if (spr && _talkEnable) {
if (spr == _vm->_hero && spr->seqTest(-1))
spr->step(kSeqHTalk);
_vm->_text->say(_vm->_text->getText(tailCmd->_val), spr);
_vm->_sys->_funDel = kHeroFun0;
}
break;
case kCmdInf:
if (_talkEnable) {
_vm->inf(_vm->_text->getText(tailCmd->_val), true);
_vm->_sys->_funDel = kHeroFun0;
}
break;
case kCmdTime:
if (spr && _talkEnable) {
if (spr == _vm->_hero && spr->seqTest(-1))
spr->step(kSeqHTalk);
_vm->_text->sayTime(spr);
}
break;
case kCmdCave:
_vm->switchScene(tailCmd->_val);
break;
case kCmdKill:
_vm->snKill(spr);
break;
case kCmdSeq:
_vm->snSeq(spr, tailCmd->_val);
break;
case kCmdRSeq:
_vm->snRSeq(spr, tailCmd->_val);
break;
case kCmdSend:
_vm->snSend(spr, tailCmd->_val);
break;
case kCmdSwap:
_vm->snSwap(spr, tailCmd->_val);
break;
case kCmdCover:
_vm->snCover(spr, tailCmd->_val);
break;
case kCmdUncover:
_vm->snUncover(spr, (tailCmd->_val >= 0) ? _vm->locate(tailCmd->_val) : ((Sprite *) tailCmd->_spritePtr));
break;
case kCmdKeep:
_vm->snKeep(spr, tailCmd->_val);
break;
case kCmdGive:
_vm->snGive(spr, tailCmd->_val);
break;
case kCmdGame:
_vm->snGame(spr, tailCmd->_val);
break;
case kCmdSetX0:
_vm->snSetX0(tailCmd->_ref, tailCmd->_val);
break;
case kCmdSetY0:
_vm->snSetY0(tailCmd->_ref, tailCmd->_val);
break;
case kCmdSetXY:
_vm->snSetXY(spr, tailCmd->_val);
break;
case kCmdRelX:
_vm->snRelX(spr, tailCmd->_val);
break;
case kCmdRelY:
_vm->snRelY(spr, tailCmd->_val);
break;
case kCmdRelZ:
_vm->snRelZ(spr, tailCmd->_val);
break;
case kCmdSetX:
_vm->snSetX(spr, tailCmd->_val);
break;
case kCmdSetY:
_vm->snSetY(spr, tailCmd->_val);
break;
case kCmdSetZ:
_vm->snSetZ(spr, tailCmd->_val);
break;
case kCmdSlave:
_vm->snSlave(spr, tailCmd->_val);
break;
case kCmdTrans:
_vm->snTrans(spr, tailCmd->_val);
break;
case kCmdPort:
_vm->snPort(spr, tailCmd->_val);
break;
case kCmdNext:
case kCmdIf:
case kCmdTalk:
break;
case kCmdMouse:
_vm->snMouse(tailCmd->_val != 0);
break;
case kCmdNNext:
_vm->snNNext(spr, tailCmd->_val);
break;
case kCmdTNext:
_vm->snTNext(spr, tailCmd->_val);
break;
case kCmdRNNext:
_vm->snRNNext(spr, tailCmd->_val);
break;
case kCmdRTNext:
_vm->snRTNext(spr, tailCmd->_val);
break;
case kCmdRMNear:
_vm->snRmNear(spr);
break;
case kCmdRmTake:
_vm->snRmTake(spr);
break;
case kCmdFlag:
_vm->snFlag(tailCmd->_ref & 3, tailCmd->_val != 0);
break;
case kCmdSetRef:
_vm->snSetRef(spr, tailCmd->_val);
break;
case kCmdBackPt:
_vm->snBackPt(spr, tailCmd->_val);
break;
case kCmdFlash:
_vm->snFlash(tailCmd->_val != 0);
break;
case kCmdLight:
_vm->snLight(tailCmd->_val != 0);
break;
case kCmdSetHBarrier:
_vm->snHBarrier(tailCmd->_ref, tailCmd->_val);
break;
case kCmdSetVBarrier:
_vm->snVBarrier(tailCmd->_ref, tailCmd->_val);
break;
case kCmdWalk:
_vm->snWalk(spr, tailCmd->_ref, tailCmd->_val);
break;
case kCmdReach:
_vm->snReach(spr, tailCmd->_val);
break;
case kCmdSound:
_vm->snSound(spr, tailCmd->_val);
break;
case kCmdCount:
_vm->_sound->setRepeat(tailCmd->_val);
break;
case kCmdExec:
switch (tailCmd->_cbType) {
case kQGame:
_vm->qGame();
break;
case kMiniStep:
_vm->miniStep(tailCmd->_val);
break;
case kXScene:
_vm->xScene();
break;
case kSoundSetVolume:
_vm->sndSetVolume();
break;
default:
error("Unknown Callback Type in SNEXEC");
}
break;
case kCmdStep:
spr->step();
break;
case kCmdZTrim:
_vm->snZTrim(spr);
break;
case kCmdGhost:
_vm->snGhost((Bitmap *) tailCmd->_spritePtr);
break;
default:
warning("Unhandled snc->_com in SNMouse(bool)");
break;
}
_tail++;
if (!_turbo)
break;
}
_busy = false;
}
bool CommandHandler::idle() {
return (_head == _tail);
}
void CommandHandler::reset() {
_tail = _head;
}
/**
* Handles mini-Games logic
* @param com Command
* @param num mini game number
*/
void CGEEngine::snGame(Sprite *spr, int num) {
debugC(1, kCGEDebugEngine, "CGEEngine::snGame(spr, %d)", num);
switch (num) {
case 1: {
static Sprite *dup[3] = { NULL, NULL, NULL };
int buref = 0;
int Stage = 0;
for (dup[0] = _vga->_showQ->first(); dup[0]; dup[0] = dup[0]->_next) {
buref = dup[0]->_ref;
if (buref / 1000 == 16 && buref % 100 == 6) {
Stage = (buref / 100) % 10;
break;
}
}
if (dup[1] == NULL) {
dup[1] = _vga->_showQ->locate(16003); // pan
dup[2] = _vga->_showQ->locate(16004); // pani
}
if (_game) { // continue game
int i = newRandom(3), hand = (dup[0]->_shpCnt == 6);
Stage++;
if (hand && Stage > kDressed)
++hand;
if (i >= 0 && (dup[i] == spr && newRandom(3) == 0)) {
_commandHandler->addCommand(kCmdSeq, -1, 3, dup[0]); // Yes
_commandHandler->addCommand(kCmdSeq, -1, 3, dup[1]); // Yes
_commandHandler->addCommand(kCmdSeq, -1, 3, dup[2]); // Yes
_commandHandler->addCommand(kCmdTNext, -1, 0, dup[0]); // Reset Take
_commandHandler->addCommand(kCmdTNext, -1, 0, dup[1]); // Reset Take
_commandHandler->addCommand(kCmdTNext, -1, 0, dup[2]); // Reset Take
_commandHandler->addCommand(kCmdNNext, -1, 0, dup[0]); // Reset Near
_commandHandler->addCommand(kCmdPause, -1, 72, NULL); // Pause the game for 72/80 second
_commandHandler->addCommand(kCmdSay, 1, 16009, NULL); // Say "I win.."
_commandHandler->addCommand(kCmdSay, buref, 16010, NULL); // Say "Go Sit..."
_commandHandler->addCommand(kCmdSay, 1, 16011, NULL); // Say "I prefer not"
if (hand) {
_commandHandler->addCommand(kCmdSend, 16060 + hand, 16, NULL); // Give hand
_commandHandler->addCommand(kCmdSeq, buref, 4, NULL); // Take off
_commandHandler->addCommand(kCmdSeq, 16060 + hand, 1, NULL); // start one of the Bartender animations
_commandHandler->addCommand(kCmdSound, 16060 + hand, 16002, NULL); // Play tear sound
_commandHandler->addCommand(kCmdWait, 16060 + hand, 3, NULL); // Take up
_commandHandler->addCommand(kCmdSwap, buref, buref + 100, NULL); // Open hand
_commandHandler->addCommand(kCmdSeq, 16016, Stage, NULL); // Start Belongings animation
_commandHandler->addCommand(kCmdSend, 16060 + hand, -1, NULL); // Hide hand
_commandHandler->addCommand(kCmdWait, 16060 + hand, -1, NULL); // Stop moving hand
} else {
_commandHandler->addCommand(kCmdSeq, buref, 4, NULL); // Take off
_commandHandler->addCommand(kCmdSound, 16060 + hand, 16002, NULL); // Play tear sound
_commandHandler->addCommand(kCmdWait, buref, -1, NULL); // Will take off
_commandHandler->addCommand(kCmdSwap, buref, buref + 100, NULL); // Open hand
_commandHandler->addCommand(kCmdSeq, 16016, Stage, NULL); // Start Belongings animation
}
_commandHandler->addCommand(kCmdPause, -1, 72, NULL); // Pause the game for 72/80 second
_commandHandler->addCommand(kCmdSeq, -1, 0, dup[1]); // Get away (Him)
_commandHandler->addCommand(kCmdSetXY, -1, 203 + kScrWidth * 49, dup[1]);
_commandHandler->addCommand(kCmdSetZ, -1, 7, dup[1]);
_commandHandler->addCommand(kCmdSeq, -1, 0, dup[2]); // Get Away (Her)
_commandHandler->addCommand(kCmdSetXY, -1, 182 + kScrWidth * 62, dup[2]);
_commandHandler->addCommand(kCmdSetZ, -1, 9, dup[2]);
_game = false;
return;
} else {
_commandHandler->addCommand(kCmdSeq, -1, 2, dup[0]); // reset animation sequence
_commandHandler->addCommand(kCmdSeq, -1, 2, dup[1]); // reset animation sequence
_commandHandler->addCommand(kCmdSeq, -1, 2, dup[2]); // reset animation sequence
_commandHandler->addCommand(kCmdPause, -1, 72, NULL); // Pause the game for 72/80 second
}
}
_commandHandler->addCommand(kCmdWalk, 198, 134, NULL); // Go to place
_commandHandler->addCommand(kCmdWait, 1, -1, NULL); // Stop moving
_commandHandler->addCommand(kCmdCover, 1, 16101, NULL); // Man to beat
_commandHandler->addCommand(kCmdSeq, 16101, 1, NULL); // Start Chief animation (16dupnia)
_commandHandler->addCommand(kCmdWait, 16101, 5, NULL); // wait
_commandHandler->addCommand(kCmdPause, 16101, 24, NULL); // Pause the game for 24/80 second
_commandHandler->addCommand(kCmdSeq, 16040, 1, NULL); // Start Slap animation (16plask)
_commandHandler->addCommand(kCmdSound, 16101, 16001, NULL); // Play "Slap" sound
_commandHandler->addCommand(kCmdPause, 16101, 24, NULL); // Pause the game for 24/80 second
_commandHandler->addCommand(kCmdSeq, 16040, 0, NULL); // Reset animation sequence
_commandHandler->addCommand(kCmdWait, 16101, -1, NULL); // stay
_commandHandler->addCommand(kCmdUncover, 1, 16101, NULL); // SDS
if (!_game) {
_commandHandler->addCommand(kCmdSay, buref, 16008, NULL); // say "Guess!"
_game = true;
}
}
break;
case 2:
if (_sprTv == NULL) {
_sprTv = _vga->_showQ->locate(20700);
_sprK1 = _vga->_showQ->locate(20701);
_sprK2 = _vga->_showQ->locate(20702);
_sprK3 = _vga->_showQ->locate(20703);
}
if (!_game) { // init
_commandHandler->addCommand(kCmdGame, 20002, 2, NULL);
_game = true;
break;
}
// cont
_sprK1->step(newRandom(6));
_sprK2->step(newRandom(6));
_sprK3->step(newRandom(6));
// check the ALT key as it's the solution of the puzzle
// the test has been restricted to some specific OSes
// in order to avoid some obvious issues (like Android, iOS, NDS, N64...)
// Not perfect, but at least better than nothing.
#if defined(WIN32) || defined(UNIX) || defined(MACOSX)
if (spr->_ref == 1 && _keyboard->_keyAlt) {
#else
if (spr->_ref == 1 && _gameCase2Cpt > 1) {
#endif
_sprK1->step(5);
_sprK2->step(5);
_sprK3->step(5);
}
_commandHandler->addCommand(kCmdSetZ, 20700, 0, NULL);
{
bool hit = (_sprK1->_seqPtr + _sprK2->_seqPtr + _sprK3->_seqPtr == 15);
if (hit) {
if (spr->_ref == 1) {
_commandHandler->addCommand(kCmdSay, 1, 20003, NULL); // hurray!
_commandHandler->addCommand(kCmdSeq, 20011, 2, NULL); // Camera away
_commandHandler->addCommand(kCmdSend, 20701, -1, NULL); // move dice1 to scene -1
_commandHandler->addCommand(kCmdSend, 20702, -1, NULL); // move dice2 to scene -1
_commandHandler->addCommand(kCmdSend, 20703, -1, NULL); // move dice3 to scene -1
_commandHandler->addCommand(kCmdSend, 20700, -1, NULL); // move TV to scene -1
_commandHandler->addCommand(kCmdKeep, 20007, 0, NULL); // to pocket
_commandHandler->addCommand(kCmdSend, 20006, 20, NULL); // Move Coin to scene 20
_commandHandler->addCommand(kCmdSound, 20006, 20002, NULL); // Play Coin sound
_commandHandler->addCommand(kCmdSay, 20002, 20004, NULL); // Say "Luck guy..."
_commandHandler->addCommand(kCmdSend, 20010, 20, NULL); // Move Paper to scene 20
_commandHandler->addCommand(kCmdSound, 20010, 20003, NULL); // Play "ksh" sound! (fx20003.wav)
_commandHandler->addCommand(kCmdSay, 20001, 20005, NULL); // Say "Congratulations"
_game = false;
return;
} else {
_sprK3->step(newRandom(5));
}
}
}
if (_gameCase2Cpt < 100) {
switch (_gameCase2Cpt) {
case 15:
// Give hint about ALTered dice
_commandHandler->addCommand(kCmdSay, 20003, 20021, NULL);
break;
case 30:
case 45:
case 60:
case 75:
// Tell to use ALT key
_commandHandler->addCommand(kCmdSay, 20003, 20022, NULL);
break;
default:
break;
}
_gameCase2Cpt++;
}
switch (spr->_ref) {
case 1:
_commandHandler->addCommand(kCmdSay, 20001, 20011, NULL); // Say "It'a my turn"
_commandHandler->addCommand(kCmdSeq, 20001, 1, NULL); // Throw dice
_commandHandler->addCommand(kCmdWait, 20001, 1, NULL); // wait
_commandHandler->addCommand(kCmdSetZ, 20700, 2, NULL); // hide dice
_commandHandler->addCommand(kCmdHide, 20007, 1, NULL); // hide dice
_commandHandler->addCommand(kCmdWait, 20001, 16, NULL); // wait
_commandHandler->addCommand(kCmdSeq, 20007, 1, NULL); // Start dice animation (20kosci)
_commandHandler->addCommand(kCmdHide, 20007, 0, NULL); // unhide
_commandHandler->addCommand(kCmdSound, 20007, 20001, NULL); // Play Dice sound
_commandHandler->addCommand(kCmdWait, 20007, -1, NULL); // the end
_commandHandler->addCommand(kCmdGame, 20001, 2, NULL); // again!
break;
case 20001:
_commandHandler->addCommand(kCmdSay, 20002, 20012, NULL); // Say "Now it's mine"
_commandHandler->addCommand(kCmdSeq, 20002, 1, NULL); // Throw dice
_commandHandler->addCommand(kCmdWait, 20002, 3, NULL); // wait
_commandHandler->addCommand(kCmdSetZ, 20700, 2, NULL); // hide dice
_commandHandler->addCommand(kCmdHide, 20007, 1, NULL); // hide dice
_commandHandler->addCommand(kCmdWait, 20002, 10, NULL); // wait
_commandHandler->addCommand(kCmdSeq, 20007, 2, NULL); // Start dice animation (20kosci)
_commandHandler->addCommand(kCmdHide, 20007, 0, NULL); // unhide
_commandHandler->addCommand(kCmdSound, 20007, 20001, NULL); // Play Dice sound
_commandHandler->addCommand(kCmdWait, 20007, -1, NULL); // the end
_commandHandler->addCommand(kCmdGame, 20002, 2, NULL); // again!
break;
case 20002:
_commandHandler->addCommand(kCmdSay, 20002, 20010, NULL); // "Roll the bones!"
_commandHandler->addCommand(kCmdWalk, 20005, -1, NULL); // Walk to table
_commandHandler->addCommand(kCmdWait, 1, -1, NULL); // Wait
_commandHandler->addCommand(kCmdCover, 1, 20101, NULL); // grasol ??
_commandHandler->addCommand(kCmdSeq, 20101, 1, NULL); // Start Chief animation (20solgra)
_commandHandler->addCommand(kCmdWait, 20101, 5, NULL); // Wait
_commandHandler->addCommand(kCmdSetZ, 20700, 2, NULL); // Hide dice
_commandHandler->addCommand(kCmdHide, 20007, 1, NULL); // Hide dice
_commandHandler->addCommand(kCmdWait, 20101, 15, NULL); // wait
_commandHandler->addCommand(kCmdSeq, 20007, 1, NULL); // Start dice animation (20kosci)
_commandHandler->addCommand(kCmdHide, 20007, 0, NULL); // Unhide
_commandHandler->addCommand(kCmdSound, 20007, 20001, NULL); // Play Dice sound
_commandHandler->addCommand(kCmdWait, 20101, -1, NULL); // the end
_commandHandler->addCommand(kCmdUncover, 1, 20101, NULL); // SDS ??
_commandHandler->addCommand(kCmdGame, 1, 2, NULL); // again!
break;
default:
break;
}
default:
break;
}
}
void CGEEngine::expandSprite(Sprite *spr) {
debugC(5, kCGEDebugEngine, "CGEEngine::expandSprite(spr)");
if (spr)
_vga->_showQ->insert(_vga->_spareQ->remove(spr));
}
void CGEEngine::contractSprite(Sprite *spr) {
debugC(1, kCGEDebugEngine, "CGEEngine::contractSprite(spr)");
if (spr)
_vga->_spareQ->append(_vga->_showQ->remove(spr));
}
/**
* Check if an item is in the inventory, and returns its position
* @param spr Sprite pointer
* @return -1 if not found, else index.
*/
int CGEEngine::findPocket(Sprite *spr) {
debugC(1, kCGEDebugEngine, "CGEEngine::findPocket(spr)");
for (int i = 0; i < kPocketNX; i++)
if (_pocket[i] == spr)
return i;
return -1;
}
/**
* Check if an item is in the inventory, and returns its position
* @param Inventory slot number Sprite pointer
*/
void CGEEngine::selectPocket(int n) {
debugC(1, kCGEDebugEngine, "CGEEngine::selectPocket(%d)", n);
if (n < 0 || (_pocLight->_seqPtr && _pocPtr == n)) {
// If no slot specified, or another slot already selected
// stop the blinking animation
_pocLight->step(0);
n = findPocket(NULL);
if (n >= 0)
_pocPtr = n;
} else {
// If slot specified, check if the slot if used.
// Is so, start the blinking animation
if (_pocket[n] != NULL) {
_pocPtr = n;
_pocLight->step(1);
}
}
_pocLight->gotoxy(kPocketX + _pocPtr * kPocketDX + kPocketSX, kPocketY + kPocketSY);
}
/**
* Logic used when all the inventory slots are full and the user tries to pick
* another object.
* @param Inventory slot number Sprite pointer
*/
void CGEEngine::pocFul() {
debugC(1, kCGEDebugEngine, "CGEEngine::pocFul()");
if (!_hero)
error("pocFul - Unexpected null _hero");
_hero->park();
_commandHandler->addCommand(kCmdWait, -1, -1, _hero);
_commandHandler->addCommand(kCmdSeq, -1, kSeqPocketFull, _hero);
_commandHandler->addCommand(kCmdSound, -1, 2, _hero); // Play the 'hum-hum" sound (fx00002)
_commandHandler->addCommand(kCmdWait, -1, -1, _hero);
_commandHandler->addCommand(kCmdSay, 1, kPocketFull, _hero);
}
void CGEEngine::hide1(Sprite *spr) {
debugC(1, kCGEDebugEngine, "CGEEngine::hide1(spr)");
_commandHandlerTurbo->addCommand(kCmdGhost, -1, 0, spr->ghost());
}
void CGEEngine::snGhost(Bitmap *bmp) {
debugC(1, kCGEDebugEngine, "CGEEngine::snGhost(bmp)");
bmp->hide(bmp->_map & 0xFFFF, bmp->_map >> 16);
bmp->_m = NULL;
bmp->_map = 0;
delete bmp;
}
void CGEEngine::feedSnail(Sprite *spr, SnList snq) {
debugC(1, kCGEDebugEngine, "CGEEngine::feedSnail(spr, snq)");
if (!spr || !spr->active())
return;
uint8 ptr = (snq == kTake) ? spr->_takePtr : spr->_nearPtr;
if (ptr == kNoPtr)
return;
CommandHandler::Command *comtab = spr->snList(snq);
CommandHandler::Command *c = comtab + ptr;
if (findPocket(NULL) < 0) { // no empty pockets?
CommandHandler::Command *p;
for (p = c; p->_commandType != kCmdNext; p++) { // find KEEP command
if (p->_commandType == kCmdKeep) {
pocFul();
return;
}
if (p->_spritePtr)
break;
}
}
while (true) {
if (c->_commandType == kCmdTalk) {
if ((_commandHandler->_talkEnable = (c->_val != 0)) == false)
killText();
}
if (c->_commandType == kCmdNext) {
Sprite *s = (c->_ref < 0) ? spr : locate(c->_ref);
if (s) {
uint8 *idx = (snq == kTake) ? &s->_takePtr : &s->_nearPtr;
if (*idx != kNoPtr) {
int v;
switch (c->_val) {
case -1 :
v = c - comtab + 1;
break;
case -2 :
v = c - comtab;
break;
case -3 :
v = -1;
break;
default :
v = c->_val;
break;
}
if (v >= 0)
*idx = v;
}
}
if (s == spr)
break;
}
if (c->_commandType == kCmdIf) {
Sprite *s = (c->_ref < 0) ? spr : locate(c->_ref);
if (s) { // sprite extsts
if (! s->seqTest(-1))
c = comtab + c->_val; // not parked
else
++c;
} else
++c;
} else {
_commandHandler->addCommand(c->_commandType, c->_ref, c->_val, spr);
if (c->_spritePtr)
break;
else
c++;
}
}
}
void CGEEngine::snNNext(Sprite *spr, int p) {
debugC(1, kCGEDebugEngine, "CGEEngine::snNNext(spr, %d)", p);
if (spr)
if (spr->_nearPtr != kNoPtr)
spr->_nearPtr = p;
}
void CGEEngine::snTNext(Sprite *spr, int p) {
debugC(1, kCGEDebugEngine, "CGEEngine::snTNext(spr, %d)", p);
if (spr)
if (spr->_takePtr != kNoPtr)
spr->_takePtr = p;
}
void CGEEngine::snRNNext(Sprite *spr, int p) {
debugC(1, kCGEDebugEngine, "CGEEngine::snRNNext(spr, %d)", p);
if (spr)
if (spr->_nearPtr != kNoPtr)
spr->_nearPtr += p;
}
void CGEEngine::snRTNext(Sprite *spr, int p) {
debugC(1, kCGEDebugEngine, "CGEEngine::snRTNext(spr, %d)", p);
if (spr)
if (spr->_takePtr != kNoPtr)
spr->_takePtr += p;
}
void CGEEngine::snZTrim(Sprite *spr) {
debugC(4, kCGEDebugEngine, "CGEEngine::snZTrim(spr)");
if (!spr || !spr->active())
return;
Sprite *s = (spr->_flags._shad) ? spr->_prev : NULL;
_vga->_showQ->insert(_vga->_showQ->remove(spr));
if (s) {
s->_z = spr->_z;
_vga->_showQ->insert(_vga->_showQ->remove(s), spr);
}
}
void CGEEngine::snHide(Sprite *spr, int val) {
debugC(1, kCGEDebugEngine, "CGEEngine::snHide(spr, %d)", val);
if (spr) {
spr->_flags._hide = (val >= 0) ? (val != 0) : (!spr->_flags._hide);
if (spr->_flags._shad)
spr->_prev->_flags._hide = spr->_flags._hide;
}
}
void CGEEngine::snRmNear(Sprite *spr) {
debugC(1, kCGEDebugEngine, "CGEEngine::snRmNear(spr)");
if (spr)
spr->_nearPtr = kNoPtr;
}
void CGEEngine::snRmTake(Sprite *spr) {
debugC(1, kCGEDebugEngine, "CGEEngine::snRmTake(spr)");
if (spr)
spr->_takePtr = kNoPtr;
}
void CGEEngine::snSeq(Sprite *spr, int val) {
debugC(1, kCGEDebugEngine, "CGEEngine::snSeq(spr, %d)", val);
if (spr) {
if (spr == _hero && val == 0)
_hero->park();
else
spr->step(val);
}
}
void CGEEngine::snRSeq(Sprite *spr, int val) {
debugC(1, kCGEDebugEngine, "CGEEngine::snRSeq(spr, %d)", val);
if (spr)
snSeq(spr, spr->_seqPtr + val);
}
void CGEEngine::snSend(Sprite *spr, int val) {
debugC(1, kCGEDebugEngine, "CGEEngine::snSend(spr, %d)", val);
if (!spr)
return;
int was = spr->_scene;
bool was1 = (was == 0 || was == _now);
bool val1 = (val == 0 || val == _now);
spr->_scene = val;
if (val1 != was1) {
if (was1) {
if (spr->_flags._kept) {
int n = findPocket(spr);
if (n >= 0)
_pocket[n] = NULL;
}
hide1(spr);
contractSprite(spr);
spr->_flags._slav = false;
} else {
if (spr->_ref % 1000 == 0)
_bitmapPalette = _vga->_sysPal;
if (spr->_flags._back)
spr->backShow(true);
else
expandSprite(spr);
_bitmapPalette = NULL;
}
}
}
void CGEEngine::snSwap(Sprite *spr, int xref) {
debugC(1, kCGEDebugEngine, "CGEEngine::snSwap(spr, %d)", xref);
Sprite *xspr = locate(xref);
if (!spr || !xspr)
return;
int was = spr->_scene;
int xwas = xspr->_scene;
bool was1 = (was == 0 || was == _now);
bool xwas1 = (xwas == 0 || xwas == _now);
SWAP(spr->_scene, xspr->_scene);
SWAP(spr->_x, xspr->_x);
SWAP(spr->_y, xspr->_y);
SWAP(spr->_z, xspr->_z);
if (spr->_flags._kept) {
int n = findPocket(spr);
if (n >= 0)
_pocket[n] = xspr;
xspr->_flags._kept = true;
xspr->_flags._port = false;
}
if (xwas1 != was1) {
if (was1) {
hide1(spr);
contractSprite(spr);
} else
expandSprite(spr);
if (xwas1) {
hide1(xspr);
contractSprite(xspr);
} else
expandSprite(xspr);
}
}
void CGEEngine::snCover(Sprite *spr, int xref) {
debugC(1, kCGEDebugEngine, "CGEEngine::snCover(spr, %d)", xref);
Sprite *xspr = locate(xref);
if (!spr || !xspr)
return;
spr->_flags._hide = true;
xspr->_z = spr->_z;
xspr->_scene = spr->_scene;
xspr->gotoxy(spr->_x, spr->_y);
expandSprite(xspr);
if ((xspr->_flags._shad = spr->_flags._shad) == 1) {
_vga->_showQ->insert(_vga->_showQ->remove(spr->_prev), xspr);
spr->_flags._shad = false;
}
feedSnail(xspr, kNear);
}
void CGEEngine::snUncover(Sprite *spr, Sprite *xspr) {
debugC(1, kCGEDebugEngine, "CGEEngine::snUncover(spr, xspr)");
if (!spr || !xspr)
return;
spr->_flags._hide = false;
spr->_scene = xspr->_scene;
spr->gotoxy(xspr->_x, xspr->_y);
if ((spr->_flags._shad = xspr->_flags._shad) == 1) {
_vga->_showQ->insert(_vga->_showQ->remove(xspr->_prev), spr);
xspr->_flags._shad = false;
}
spr->_z = xspr->_z;
snSend(xspr, -1);
if (spr->_time == 0)
spr->_time++;
}
void CGEEngine::snSetX0(int scene, int x0) {
debugC(1, kCGEDebugEngine, "CGEEngine::snSetX0(%d, %d)", scene, x0);
_heroXY[scene - 1].x = x0;
}
void CGEEngine::snSetY0(int scene, int y0) {
debugC(1, kCGEDebugEngine, "CGEEngine::snSetY0(%d, %d)", scene, y0);
_heroXY[scene - 1].y = y0;
}
void CGEEngine::snSetXY(Sprite *spr, uint16 xy) {
debugC(1, kCGEDebugEngine, "CGEEngine::snSetXY(spr, %d)", xy);
if (spr)
spr->gotoxy(xy % kScrWidth, xy / kScrWidth);
}
void CGEEngine::snRelX(Sprite *spr, int x) {
debugC(1, kCGEDebugEngine, "CGEEngine::snRelX(spr, %d)", x);
if (spr && _hero)
spr->gotoxy(_hero->_x + x, spr->_y);
}
void CGEEngine::snRelY(Sprite *spr, int y) {
debugC(1, kCGEDebugEngine, "CGEEngine::snRelY(spr, %d)", y);
if (spr && _hero)
spr->gotoxy(spr->_x, _hero->_y + y);
}
void CGEEngine::snRelZ(Sprite *spr, int z) {
debugC(1, kCGEDebugEngine, "CGEEngine::snRelZ(spr, %d)", z);
if (spr && _hero) {
spr->_z = _hero->_z + z;
snZTrim(spr);
}
}
void CGEEngine::snSetX(Sprite *spr, int x) {
debugC(1, kCGEDebugEngine, "CGEEngine::snSetX(spr, %d)", x);
if (spr)
spr->gotoxy(x, spr->_y);
}
void CGEEngine::snSetY(Sprite *spr, int y) {
debugC(1, kCGEDebugEngine, "CGEEngine::snSetY(spr, %d)", y);
if (spr)
spr->gotoxy(spr->_x, y);
}
void CGEEngine::snSetZ(Sprite *spr, int z) {
debugC(1, kCGEDebugEngine, "CGEEngine::snSetZ(spr, %d)", z);
if (spr) {
spr->_z = z;
snZTrim(spr);
}
}
void CGEEngine::snSlave(Sprite *spr, int ref) {
debugC(1, kCGEDebugEngine, "CGEEngine::snSlave(spr, %d)", ref);
Sprite *slv = locate(ref);
if (spr && slv) {
if (spr->active()) {
snSend(slv, spr->_scene);
slv->_flags._slav = true;
slv->_z = spr->_z;
_vga->_showQ->insert(_vga->_showQ->remove(slv), spr->_next);
}
}
}
void CGEEngine::snTrans(Sprite *spr, int trans) {
debugC(1, kCGEDebugEngine, "CGEEngine::snTrans(spr, %d)", trans);
if (spr)
spr->_flags._tran = (trans < 0) ? !spr->_flags._tran : (trans != 0);
}
void CGEEngine::snPort(Sprite *spr, int port) {
debugC(1, kCGEDebugEngine, "CGEEngine::snPort(spr, %d)", port);
if (spr)
spr->_flags._port = (port < 0) ? !spr->_flags._port : (port != 0);
}
void CGEEngine::snKill(Sprite *spr) {
debugC(1, kCGEDebugEngine, "CGEEngine::snKill(spr)");
if (!spr)
return;
if (spr->_flags._kept) {
int n = findPocket(spr);
if (n >= 0)
_pocket[n] = NULL;
}
Sprite *nx = spr->_next;
hide1(spr);
_vga->_showQ->remove(spr);
_eventManager->clearEvent(spr);
if (spr->_flags._kill) {
delete spr;
} else {
spr->_scene = -1;
_vga->_spareQ->append(spr);
}
if (nx) {
if (nx->_flags._slav)
snKill(nx);
}
}
/**
* Play a FX sound
* @param spr Sprite pointer
* @param wav FX index
*/
void CGEEngine::snSound(Sprite *spr, int wav) {
debugC(1, kCGEDebugEngine, "CGEEngine::snSound(spr, %d)", wav);
if (wav == -1)
_sound->stop();
else
_sound->play((*_fx)[wav], (spr) ? ((spr->_x + spr->_w / 2) / (kScrWidth / 16)) : 8);
_sound->setRepeat(1);
}
void CGEEngine::snKeep(Sprite *spr, int stp) {
debugC(1, kCGEDebugEngine, "CGEEngine::snKeep(spr, %d)", stp);
selectPocket(-1);
if (spr && ! spr->_flags._kept && _pocket[_pocPtr] == NULL) {
int16 oldRepeat = _sound->getRepeat();
_sound->setRepeat(1);
snSound(spr, 3);
_sound->setRepeat(oldRepeat);
_pocket[_pocPtr] = spr;
spr->_scene = 0;
spr->_flags._kept = true;
spr->gotoxy(kPocketX + kPocketDX * _pocPtr + kPocketDX / 2 - spr->_w / 2,
kPocketY + kPocketDY / 2 - spr->_h / 2);
if (stp >= 0)
spr->step(stp);
}
selectPocket(-1);
}
/**
* Remove an object from the inventory and (if specified) trigger an animation
* @param spr Inventory item
* @param stp Animation
*/
void CGEEngine::snGive(Sprite *spr, int stp) {
debugC(1, kCGEDebugEngine, "CGEEngine::snGive(spr, %d)", stp);
if (spr) {
int p = findPocket(spr);
if (p >= 0) {
_pocket[p] = NULL;
spr->_scene = _now;
spr->_flags._kept = false;
if (stp >= 0)
spr->step(stp);
}
}
selectPocket(-1);
}
void CGEEngine::snBackPt(Sprite *spr, int stp) {
debugC(1, kCGEDebugEngine, "CGEEngine::snBackPt(spr, %d)", stp);
if (spr) {
if (stp >= 0)
spr->step(stp);
spr->backShow(true);
}
}
void CGEEngine::snLevel(Sprite *spr, int lev) {
debugC(1, kCGEDebugEngine, "CGEEngine::snLevel(spr, %d)", lev);
assert((lev >= 0) && (lev < 5));
for (int i = 0; i < 5; i++) {
spr = _vga->_spareQ->locate(100 + i);
if (spr) {
if (i <= lev) {
spr->backShow(true);
spr->_scene = 0;
spr->_flags._hide = false;
} else {
spr->_flags._hide = true;
spr->_scene = -1;
}
} else {
warning("SPR not found! ref: %d", 100 + i);
}
}
_lev = lev;
_maxScene = _maxSceneArr[_lev];
}
/**
* Set a flag to a value
* @param indx Flag index
* @param val Flag value
*/
void CGEEngine::snFlag(int indx, bool val) {
_flag[indx] = val;
}
void CGEEngine::snSetRef(Sprite *spr, int nr) {
debugC(1, kCGEDebugEngine, "CGEEngine::snSetRef(spr, %d)", nr);
if (spr)
spr->_ref = nr;
}
void CGEEngine::snFlash(bool on) {
debugC(1, kCGEDebugEngine, "CGEEngine::snFlash(%s)", on ? "true" : "false");
if (on) {
Dac *pal = (Dac *)malloc(sizeof(Dac) * kPalCount);
if (pal) {
memcpy(pal, _vga->_sysPal, kPalSize);
for (int i = 0; i < kPalCount; i++) {
int c;
c = pal[i]._r << 1;
pal[i]._r = (c < 64) ? c : 63;
c = pal[i]._g << 1;
pal[i]._g = (c < 64) ? c : 63;
c = pal[i]._b << 1;
pal[i]._b = (c < 64) ? c : 63;
}
_vga->setColors(pal, 64);
}
free(pal);
} else
_vga->setColors(_vga->_sysPal, 64);
_dark = false;
}
void CGEEngine::snLight(bool in) {
debugC(1, kCGEDebugEngine, "CGEEngine::snLight(%s)", in ? "true" : "false");
if (in)
_vga->sunrise(_vga->_sysPal);
else
_vga->sunset();
_dark = !in;
}
/**
* Set an horizontal boundary
* @param scene Scene number
* @param barX Horizontal boundary value
*/
void CGEEngine::snHBarrier(const int scene, const int barX) {
debugC(1, kCGEDebugEngine, "CGEEngine::snHBarrier(%d, %d)", scene, barX);
_barriers[(scene > 0) ? scene : _now]._horz = barX;
}
/**
* Set a vertical boundary
* @param scene Scene number
* @param barY Vertical boundary value
*/
void CGEEngine::snVBarrier(const int scene, const int barY) {
debugC(1, kCGEDebugEngine, "CGEEngine::snVBarrier(%d, %d)", scene, barY);
_barriers[(scene > 0) ? scene : _now]._vert = barY;
}
void CGEEngine::snWalk(Sprite *spr, int x, int y) {
debugC(1, kCGEDebugEngine, "CGEEngine::snWalk(spr, %d, %d)", x, y);
if (_hero) {
if (spr && y < 0)
_hero->findWay(spr);
else
_hero->findWay(XZ(x, y));
}
}
void CGEEngine::snReach(Sprite *spr, int mode) {
debugC(1, kCGEDebugEngine, "CGEEngine::snReach(spr, %d)", mode);
if (_hero)
_hero->reach(spr, mode);
}
void CGEEngine::snMouse(bool on) {
debugC(1, kCGEDebugEngine, "CGEEngine::snMouse(%s)", on ? "true" : "false");
if (on)
_mouse->on();
else
_mouse->off();
}
} // End of namespace CGE