mirror of
https://github.com/libretro/scummvm.git
synced 2024-11-27 11:20:40 +00:00
b99af18bd5
svn-id: r11213
2541 lines
64 KiB
C++
2541 lines
64 KiB
C++
/* ScummVM - Scumm Interpreter
|
|
* Copyright (C) 2003 The ScummVM project
|
|
*
|
|
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*
|
|
* $Header$
|
|
*
|
|
*/
|
|
|
|
#include "stdafx.h"
|
|
#include "sky/autoroute.h"
|
|
#include "sky/compact.h"
|
|
#include "sky/control.h"
|
|
#include "sky/debug.h"
|
|
#include "sky/disk.h"
|
|
#include "sky/grid.h"
|
|
#include "sky/logic.h"
|
|
#include "sky/mouse.h"
|
|
#include "sky/music/musicbase.h"
|
|
#include "sky/text.h"
|
|
#include "sky/screen.h"
|
|
#include "sky/sky.h"
|
|
#include "sky/sound.h"
|
|
#include "sky/struc.h"
|
|
#include "sky/talks.h"
|
|
/*
|
|
#include "sky/skydefs.h"
|
|
#include "base/gameDetector.h"
|
|
*/
|
|
|
|
uint32 SkyLogic::_scriptVariables[838];
|
|
|
|
typedef void (SkyLogic::*LogicTable) ();
|
|
static const LogicTable logicTable[] = {
|
|
&SkyLogic::nop,
|
|
&SkyLogic::logicScript, // 1 script processor
|
|
&SkyLogic::autoRoute, // 2 Make a route
|
|
&SkyLogic::arAnim, // 3 Follow a route
|
|
&SkyLogic::arTurn, // 4 Mega turns araound
|
|
&SkyLogic::alt, // 5 Set up new get-to script
|
|
&SkyLogic::anim, // 6 Follow a sequence
|
|
&SkyLogic::turn, // 7 Mega turning
|
|
&SkyLogic::cursor, // 8 id tracks the pointer
|
|
&SkyLogic::talk, // 9 count down and animate
|
|
&SkyLogic::listen, // 10 player waits for talking id
|
|
&SkyLogic::stopped, // 11 wait for id to move
|
|
&SkyLogic::choose, // 12 wait for player to click
|
|
&SkyLogic::frames, // 13 animate just frames
|
|
&SkyLogic::pause, // 14 Count down to 0 and go
|
|
&SkyLogic::waitSync, // 15 Set to l_script when sync!=0
|
|
&SkyLogic::simpleAnim, // 16 Module anim without x,y's
|
|
};
|
|
|
|
SkyLogic::SkyLogic(SkyScreen *skyScreen, SkyDisk *skyDisk, SkyText *skyText, SkyMusicBase *skyMusic, SkyMouse *skyMouse, SkySound *skySound) {
|
|
_skyScreen = skyScreen;
|
|
_skyDisk = skyDisk;
|
|
_skyText = skyText;
|
|
_skyMusic = skyMusic;
|
|
_skySound = skySound;
|
|
_skyMouse = skyMouse;
|
|
_skyGrid = new SkyGrid(_skyDisk);
|
|
_skyAutoRoute = new SkyAutoRoute(_skyGrid);
|
|
|
|
memset(_objectList, 0, 30 * sizeof(uint32));
|
|
|
|
for (int i = 0; i < ARRAYSIZE(_moduleList); i++)
|
|
_moduleList[i] = 0;
|
|
_stackPtr = 0;
|
|
|
|
_currentSection = 0xFF; //force music & sound reload
|
|
initScriptVariables();
|
|
}
|
|
|
|
bool SkyLogic::checkProtection(void) {
|
|
|
|
if (!_scriptVariables[ENTER_DIGITS]) return false;
|
|
if (_scriptVariables[CONSOLE_TYPE] == 5) { // reactor code
|
|
_scriptVariables[FS_COMMAND] = 240;
|
|
_scriptVariables[ENTER_DIGITS] = 0;
|
|
return true;
|
|
} else { // copy protection
|
|
_scriptVariables[FS_COMMAND] = 337;
|
|
_scriptVariables[ENTER_DIGITS] = 0;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
void SkyLogic::engine() {
|
|
uint16 *logicList = (uint16 *)SkyEngine::fetchCompact(_scriptVariables[LOGIC_LIST_NO]);
|
|
|
|
while (uint16 id = *logicList++) { // 0 means end of list
|
|
if (id == 0xffff) {
|
|
// Change logic data address
|
|
logicList = (uint16 *)SkyEngine::fetchCompact(*logicList);
|
|
continue;
|
|
}
|
|
|
|
_scriptVariables[CUR_ID] = id;
|
|
_compact = SkyEngine::fetchCompact(id);
|
|
|
|
// check the id actually wishes to be processed
|
|
if (!(_compact->status & (1 << 6)))
|
|
continue;
|
|
|
|
// ok, here we process the logic bit system
|
|
|
|
if (_compact->status & (1 << 7))
|
|
_skyGrid->removeObjectFromWalk(_compact);
|
|
|
|
SkyDebug::logic(_compact->logic);
|
|
(this->*logicTable[_compact->logic]) ();
|
|
|
|
if (_compact->status & (1 << 7))
|
|
_skyGrid->objectToWalk(_compact);
|
|
|
|
// a sync sent to the compact is available for one cycle
|
|
// only. that cycle has just ended so remove the sync.
|
|
// presumably the mega has just reacted to it.
|
|
_compact->sync = 0;
|
|
}
|
|
}
|
|
|
|
void SkyLogic::nop() {}
|
|
|
|
/**
|
|
* This function is basicly a wrapper around the real script engine. It runs
|
|
* the script engine until a script has finished.
|
|
* @see script()
|
|
*/
|
|
void SkyLogic::logicScript() {
|
|
/// Process the current mega's script
|
|
/// If the script finishes then drop back a level
|
|
|
|
for (;;) {
|
|
uint16 mode = _compact->mode; // get pointer to current script
|
|
uint16 *scriptNo = SkyCompact::getSub(_compact, mode);
|
|
uint16 *offset = SkyCompact::getSub(_compact, mode + 2);
|
|
|
|
*offset = script(*scriptNo, *offset);
|
|
|
|
if (!*offset) // script finished
|
|
_compact->mode -= 4;
|
|
else if (_compact->mode == mode)
|
|
return;
|
|
}
|
|
}
|
|
|
|
void SkyLogic::autoRoute() {
|
|
|
|
_compact->downFlag = _skyAutoRoute->autoRoute(_compact);
|
|
if (_compact->downFlag != 1) { // route ok
|
|
_compact->grafixProg.pos = 0;
|
|
_compact->grafixProg.ptrTarget = 0;
|
|
_compact->grafixProg.ptrType = AUTOROUTE;
|
|
}
|
|
|
|
_compact->logic = L_SCRIPT; // continue the script
|
|
|
|
logicScript();
|
|
return;
|
|
}
|
|
|
|
void SkyLogic::arAnim() {
|
|
/// Follow a route
|
|
/// Mega should be in getToMode
|
|
|
|
// only check collisions on character boundaries
|
|
if ((_compact->xcood & 7) || (_compact->ycood & 7)) {
|
|
mainAnim();
|
|
return;
|
|
}
|
|
|
|
// On character boundary. Have we been told to wait?
|
|
// if not - are WE colliding?
|
|
|
|
if (_compact->extCompact->waitingFor == 0xffff) { // 1st cycle of re-route does
|
|
mainAnim();
|
|
return;
|
|
}
|
|
|
|
if (_compact->extCompact->waitingFor) {
|
|
// ok, we've been told we've hit someone
|
|
// we will wait until we are no longer colliding
|
|
// with them. here we check to see if we are (still) colliding.
|
|
// if we are then run the stop script. if not clear the flag
|
|
// and continue.
|
|
|
|
// remember - this could be the first ar cycle for some time,
|
|
// we might have been told to wait months ago. if we are
|
|
// waiting for one person then another hits us then
|
|
// c_waiting_for will be replaced by the new mega - this is
|
|
// fine because the later collision will almost certainly
|
|
// take longer to clear than the earlier one.
|
|
|
|
if (collide(SkyEngine::fetchCompact(_compact->extCompact->waitingFor))) {
|
|
stopAndWait();
|
|
return;
|
|
}
|
|
|
|
// we are not in fact hitting this person so clr & continue
|
|
// it must have registered some time ago
|
|
|
|
_compact->extCompact->waitingFor = 0; // clear id flag
|
|
}
|
|
|
|
// ok, our turn to check for collisions
|
|
|
|
uint16 *logicList = (uint16 *)SkyEngine::fetchCompact(_scriptVariables[LOGIC_LIST_NO]);
|
|
Compact *cpt = 0;
|
|
|
|
while (uint16 id = *logicList++) { // get an id
|
|
|
|
if (id == 0xffff) { // address change?
|
|
logicList = (uint16 *)SkyEngine::fetchCompact(*logicList); // get new logic list
|
|
continue;
|
|
}
|
|
|
|
if (id == (uint16)(_scriptVariables[CUR_ID] & 0xffff)) // is it us?
|
|
continue;
|
|
|
|
_scriptVariables[HIT_ID] = id; // save target id for any possible c_mini_bump
|
|
cpt = SkyEngine::fetchCompact(id); // let's have a closer look
|
|
|
|
if (!(cpt->status & (1 << ST_COLLISION_BIT))) // can it collide?
|
|
continue;
|
|
|
|
if (cpt->screen != _compact->screen) // is it on our screen?
|
|
continue;
|
|
|
|
if (collide(cpt)) { // check for a hit
|
|
// ok, we've hit a mega
|
|
// is it moving... or something else?
|
|
|
|
if (cpt->logic != L_AR_ANIM) { // check for following route
|
|
// it is doing something else
|
|
// we restart our get-to script
|
|
// first tell it to wait for us - in case it starts moving
|
|
// ( *it may have already hit us and stopped to wait )
|
|
|
|
_compact->extCompact->waitingFor = 0xffff; // effect 1 cycle collision skip
|
|
// tell it it is waiting for us
|
|
cpt->extCompact->waitingFor = (uint16)(_scriptVariables[CUR_ID] & 0xffff);
|
|
// restart current script
|
|
*SkyCompact::getSub(_compact, _compact->mode + 2) = 0;
|
|
_compact->logic = L_SCRIPT;
|
|
logicScript();
|
|
return;
|
|
}
|
|
|
|
script(_compact->extCompact->miniBump, 0);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// ok, there was no collisions
|
|
// now check for interaction request
|
|
// *note: the interaction is always set up as an action script
|
|
|
|
if (_compact->extCompact->request) {
|
|
_compact->mode = C_ACTION_MODE; // put into action mode
|
|
_compact->extCompact->actionSub = _compact->extCompact->request;
|
|
_compact->extCompact->actionSub_off = 0;
|
|
_compact->extCompact->request = 0; // trash request
|
|
_compact->logic = L_SCRIPT;
|
|
logicScript();
|
|
return;
|
|
}
|
|
|
|
// any flag? - or any change?
|
|
// if change then re-run the current script, which must be
|
|
// a position independent get-to ----
|
|
|
|
if (!_compact->extCompact->atWatch) { // any flag set?
|
|
mainAnim();
|
|
return;
|
|
}
|
|
|
|
// ok, there is an at watch - see if it's changed
|
|
|
|
if (_compact->extCompact->atWas == _scriptVariables[_compact->extCompact->atWatch/4]) { // still the same?
|
|
mainAnim();
|
|
return;
|
|
}
|
|
|
|
// changed so restart the current script
|
|
// *not suitable for base initiated ARing
|
|
*SkyCompact::getSub(_compact, _compact->mode + 2) = 0;
|
|
|
|
_compact->logic = L_SCRIPT;
|
|
logicScript();
|
|
}
|
|
|
|
void SkyLogic::mainAnim() {
|
|
/// Extension of arAnim()
|
|
_compact->extCompact->waitingFor = 0; // clear possible zero-zero skip
|
|
|
|
//uint16 *sequence = _compact->grafixProg;
|
|
uint16 *sequence = SkyCompact::getGrafixPtr(_compact);
|
|
if (!*sequence) {
|
|
// ok, move to new anim segment
|
|
sequence += 2;
|
|
_compact->grafixProg.pos += 2;
|
|
if (!*sequence) { // end of route?
|
|
// ok, sequence has finished
|
|
|
|
// will start afresh if new sequence continues in last direction
|
|
_compact->extCompact->arAnimIndex = 0;
|
|
|
|
_compact->downFlag = 0; // pass back ok to script
|
|
_compact->logic = L_SCRIPT;
|
|
logicScript();
|
|
return;
|
|
}
|
|
|
|
_compact->extCompact->arAnimIndex = 0; // reset position
|
|
}
|
|
|
|
uint16 dir;
|
|
while ((dir = _compact->extCompact->dir) != *(sequence + 1)) {
|
|
// ok, setup turning
|
|
_compact->extCompact->dir = *(sequence + 1);
|
|
|
|
uint16 **tt = SkyCompact::getTurnTable(_compact,_compact->extCompact->megaSet, dir);
|
|
if (tt[_compact->extCompact->dir]) {
|
|
_compact->extCompact->turnProg = tt[_compact->extCompact->dir];
|
|
_compact->logic = L_AR_TURNING;
|
|
arTurn();
|
|
return;
|
|
}
|
|
};
|
|
|
|
uint16 *animList = *(uint16 **)SkyCompact::getCompactElem(_compact,
|
|
C_ANIM_UP + _compact->extCompact->megaSet + dir * 4);
|
|
|
|
uint16 arAnimIndex = _compact->extCompact->arAnimIndex;
|
|
if (!animList[arAnimIndex / 2]) {
|
|
arAnimIndex = 0;
|
|
_compact->extCompact->arAnimIndex = 0; // reset
|
|
}
|
|
|
|
_compact->extCompact->arAnimIndex += S_LENGTH;
|
|
|
|
*sequence -= animList[(S_COUNT + arAnimIndex)/2]; // reduce the distance to travel
|
|
_compact->frame = animList[(S_FRAME + arAnimIndex)/2]; // new graphic frame
|
|
_compact->xcood += animList[(S_AR_X + arAnimIndex)/2]; // update x coordinate
|
|
_compact->ycood += animList[(S_AR_Y + arAnimIndex)/2]; // update y coordinate
|
|
}
|
|
|
|
void SkyLogic::arTurn() {
|
|
_compact->frame = *_compact->extCompact->turnProg++;
|
|
|
|
if (!*_compact->extCompact->turnProg) { // turn done?
|
|
// Back to ar mode
|
|
_compact->extCompact->arAnimIndex = 0;
|
|
_compact->logic = L_AR_ANIM;
|
|
}
|
|
}
|
|
|
|
void SkyLogic::alt() {
|
|
/// change the current script
|
|
_compact->logic = L_SCRIPT;
|
|
*SkyCompact::getSub(_compact, _compact->mode) = _compact->extCompact->alt;
|
|
*SkyCompact::getSub(_compact, _compact->mode + 2) = 0;
|
|
logicScript();
|
|
}
|
|
|
|
void SkyLogic::anim() {
|
|
/// Follow an animation sequence
|
|
|
|
//uint16 *grafixProg = _compact->grafixProg;
|
|
uint16 *grafixProg = SkyCompact::getGrafixPtr(_compact);
|
|
|
|
while (*grafixProg) {
|
|
_compact->grafixProg.pos += 3; // all types are 3 words.
|
|
if (*grafixProg == LF_START_FX) { // do fx
|
|
grafixProg++;
|
|
uint16 sound = *grafixProg++;
|
|
uint16 volume = *grafixProg++;
|
|
|
|
// channel 0
|
|
fnStartFx(sound, 0, volume);
|
|
} else if (*grafixProg >= LF_START_FX) { // do sync
|
|
grafixProg++;
|
|
|
|
Compact *cpt = SkyEngine::fetchCompact(*grafixProg++);
|
|
|
|
cpt->sync = *grafixProg++;
|
|
} else { // put coordinates and frame in
|
|
_compact->xcood = *grafixProg++;
|
|
_compact->ycood = *grafixProg++;
|
|
|
|
_compact->frame = *grafixProg++ | _compact->offset;
|
|
return;
|
|
}
|
|
}
|
|
|
|
_compact->downFlag = 0;
|
|
_compact->logic = L_SCRIPT;
|
|
logicScript();
|
|
}
|
|
|
|
void SkyLogic::turn() {
|
|
if (*_compact->extCompact->turnProg) {
|
|
_compact->frame = *_compact->extCompact->turnProg++;
|
|
return;
|
|
}
|
|
|
|
// turn_to_script:
|
|
_compact->extCompact->arAnimIndex = 0;
|
|
_compact->logic = L_SCRIPT;
|
|
|
|
logicScript();
|
|
}
|
|
|
|
void SkyLogic::cursor() {
|
|
_skyText->logicCursor(_compact, _skyMouse->giveMouseX(), _skyMouse->giveMouseY());
|
|
}
|
|
|
|
static uint16 clickTable[46] = {
|
|
ID_FOSTER,
|
|
ID_JOEY,
|
|
ID_JOBS,
|
|
ID_LAMB,
|
|
ID_ANITA,
|
|
ID_SON,
|
|
ID_DAD,
|
|
ID_MONITOR,
|
|
ID_SHADES,
|
|
MINI_SS,
|
|
FULL_SS,
|
|
ID_FOREMAN,
|
|
ID_RADMAN,
|
|
ID_GALLAGER_BEL,
|
|
ID_BURKE,
|
|
ID_BODY,
|
|
ID_HOLO,
|
|
ID_TREVOR,
|
|
ID_ANCHOR,
|
|
ID_WRECK_GUARD,
|
|
ID_SKORL_GUARD,
|
|
|
|
// BASE LEVEL
|
|
ID_SC30_HENRI,
|
|
ID_SC31_GUARD,
|
|
ID_SC32_VINCENT,
|
|
ID_SC32_GARDENER,
|
|
ID_SC32_BUZZER,
|
|
ID_SC36_BABS,
|
|
ID_SC36_BARMAN,
|
|
ID_SC36_COLSTON,
|
|
ID_SC36_GALLAGHER,
|
|
ID_SC36_JUKEBOX,
|
|
ID_DANIELLE,
|
|
ID_SC42_JUDGE,
|
|
ID_SC42_CLERK,
|
|
ID_SC42_PROSECUTION,
|
|
ID_SC42_JOBSWORTH,
|
|
|
|
// UNDERWORLD
|
|
ID_MEDI,
|
|
ID_WITNESS,
|
|
ID_GALLAGHER,
|
|
ID_KEN,
|
|
ID_SC76_ANDROID_2,
|
|
ID_SC76_ANDROID_3,
|
|
ID_SC81_FATHER,
|
|
ID_SC82_JOBSWORTH,
|
|
|
|
// LINC WORLD
|
|
ID_HOLOGRAM_B,
|
|
12289
|
|
};
|
|
|
|
void SkyLogic::talk() {
|
|
// first count through the frames
|
|
// just frames - nothing tweeky
|
|
// the speech finishes when the timer runs out &
|
|
// not when the animation finishes
|
|
// this routine is very task specific
|
|
|
|
// TODO: Check for mouse clicking
|
|
|
|
// Are we allowed to click
|
|
|
|
if (_skyMouse->wasClicked())
|
|
for (int i = 0; i < ARRAYSIZE(clickTable); i++)
|
|
if (clickTable[i] == (uint16)_scriptVariables[CUR_ID]) {
|
|
if ((SkyEngine::_systemVars.systemFlags & SF_ALLOW_SPEECH) && (!_skySound->speechFinished()))
|
|
_skySound->stopSpeech();
|
|
if ((SkyEngine::_systemVars.systemFlags & SF_ALLOW_TEXT) &&
|
|
(_compact->extCompact->spTextId > 0) &&
|
|
(_compact->extCompact->spTextId < 0xFFFF)) {
|
|
|
|
SkyEngine::fetchCompact(_compact->extCompact->spTextId)->status = 0;
|
|
}
|
|
if (SkyCompact::getGrafixPtr(_compact)) {
|
|
_compact->frame = _compact->getToFlag; // set character to stand
|
|
_compact->grafixProg.ptrType = PTR_NULL;
|
|
}
|
|
|
|
_compact->logic = L_SCRIPT;
|
|
logicScript();
|
|
return;
|
|
}
|
|
|
|
// If speech is allowed then check for it to finish before finishing animations
|
|
|
|
if ((_compact->extCompact->spTextId == 0xFFFF) && // is this a voc file?
|
|
(_skySound->speechFinished())) { // finished?
|
|
|
|
_compact->logic = L_SCRIPT; // restart character control
|
|
|
|
if (SkyCompact::getGrafixPtr(_compact)) {
|
|
_compact->frame = _compact->getToFlag; // set character to stand
|
|
_compact->grafixProg.ptrType = PTR_NULL;
|
|
}
|
|
|
|
logicScript();
|
|
return;
|
|
}
|
|
|
|
//uint16 *graphixProg = _compact->grafixProg; // no anim file?
|
|
uint16 *graphixProg = SkyCompact::getGrafixPtr(_compact);
|
|
if (graphixProg) {
|
|
if ((*graphixProg) && ((_compact->extCompact->spTime != 3) || (!_skySound->speechFinished()))) {
|
|
// we will force the animation to finish 3 game cycles
|
|
// before the speech actually finishes - because it looks good.
|
|
|
|
_compact->frame = *(graphixProg + 2) + _compact->offset;
|
|
graphixProg += 3;
|
|
_compact->grafixProg.pos += 3;
|
|
} else {
|
|
// we ran out of frames or finished speech, let actor stand still.
|
|
_compact->frame = _compact->getToFlag;
|
|
_compact->grafixProg.ptrType = PTR_NULL;
|
|
}
|
|
}
|
|
|
|
if (_skySound->speechFinished()) _compact->extCompact->spTime--;
|
|
|
|
if (_compact->extCompact->spTime == 0) {
|
|
|
|
// ok, speech has finished
|
|
|
|
if (_compact->extCompact->spTextId) {
|
|
Compact *cpt = SkyEngine::fetchCompact(_compact->extCompact->spTextId); // get text id to kill
|
|
cpt->status = 0; // kill the text
|
|
}
|
|
|
|
_compact->logic = L_SCRIPT;
|
|
logicScript();
|
|
}
|
|
}
|
|
|
|
void SkyLogic::listen() {
|
|
/// Stay in this mode until id in getToFlag leaves L_TALK mode
|
|
|
|
Compact *cpt = SkyEngine::fetchCompact(_compact->flag);
|
|
|
|
if (cpt->logic == L_TALK)
|
|
return;
|
|
|
|
_compact->logic = L_SCRIPT;
|
|
logicScript();
|
|
}
|
|
|
|
void SkyLogic::stopped() {
|
|
/// waiting for another mega to move or give-up trying
|
|
///
|
|
/// this mode will always be set up from a special script
|
|
/// that will be one level higher than the script we
|
|
/// would wish to restart from
|
|
|
|
Compact *cpt = SkyEngine::fetchCompact(_compact->extCompact->waitingFor);
|
|
|
|
if (cpt)
|
|
if (!cpt->mood && collide(cpt))
|
|
return;
|
|
|
|
// we are free, continue processing the script
|
|
|
|
// restart script one level below
|
|
*SkyCompact::getSub(_compact, _compact->mode - 2) = 0;
|
|
_compact->extCompact->waitingFor = 0xffff;
|
|
|
|
_compact->logic = L_SCRIPT;
|
|
logicScript();
|
|
}
|
|
|
|
void SkyLogic::choose() {
|
|
// Remain in this mode until player selects some text
|
|
if (!_scriptVariables[THE_CHOSEN_ONE])
|
|
return;
|
|
|
|
fnNoHuman(0, 0, 0); // kill mouse again
|
|
|
|
SkyEngine::_systemVars.systemFlags &= ~SF_CHOOSING; // restore save/restore
|
|
|
|
_compact->logic = L_SCRIPT; // and continue script
|
|
logicScript();
|
|
}
|
|
|
|
void SkyLogic::frames() {
|
|
if (!_compact->sync)
|
|
simpleAnim();
|
|
else {
|
|
_compact->downFlag = 0; // return 'ok' to script
|
|
_compact->logic = L_SCRIPT;
|
|
logicScript();
|
|
}
|
|
}
|
|
|
|
void SkyLogic::pause() {
|
|
if (--_compact->flag)
|
|
return;
|
|
|
|
_compact->logic = L_SCRIPT;
|
|
logicScript();
|
|
return;
|
|
}
|
|
|
|
void SkyLogic::waitSync() {
|
|
/// checks c_sync, when its non 0
|
|
/// the id is put back into script mode
|
|
// use this instead of loops in the script
|
|
|
|
if (!_compact->sync)
|
|
return;
|
|
|
|
_compact->logic = L_SCRIPT;
|
|
logicScript();
|
|
}
|
|
|
|
void SkyLogic::simpleAnim() {
|
|
/// follow an animation sequence module whilst ignoring the coordinate data
|
|
|
|
uint16 *grafixProg = SkyCompact::getGrafixPtr(_compact);
|
|
|
|
// *grafix_prog: command
|
|
while (*grafixProg) {
|
|
_compact->grafixProg.pos += 3;
|
|
if (*grafixProg != SEND_SYNC) {
|
|
grafixProg++;
|
|
grafixProg++; // skip coordinates
|
|
|
|
// *grafix_prog: frame
|
|
if (*grafixProg >= 64)
|
|
_compact->frame = *grafixProg;
|
|
else
|
|
_compact->frame = *grafixProg + _compact->offset;
|
|
|
|
return;
|
|
}
|
|
|
|
grafixProg++;
|
|
// *grafix_prog: id to sync
|
|
Compact *compact2 = SkyEngine::fetchCompact(*grafixProg);
|
|
grafixProg++;
|
|
|
|
// *grafix_prog: sync
|
|
compact2->sync = *grafixProg;
|
|
grafixProg++;
|
|
}
|
|
|
|
_compact->downFlag = 0; // return 'ok' to script
|
|
_compact->logic = L_SCRIPT;
|
|
logicScript();
|
|
}
|
|
|
|
bool SkyLogic::collide(Compact *cpt) {
|
|
MegaSet *m1 = SkyCompact::getMegaSet(_compact, _compact->extCompact->megaSet);
|
|
MegaSet *m2 = SkyCompact::getMegaSet(cpt, cpt->extCompact->megaSet);
|
|
|
|
// target's base coordinates
|
|
uint16 x = cpt->xcood & 0xfff8;
|
|
uint16 y = cpt->ycood & 0xfff8;
|
|
|
|
// The collision is direction dependent
|
|
switch (_compact->extCompact->dir) {
|
|
case 0: // looking up
|
|
x -= m1->colOffset; // compensate for inner x offsets
|
|
x += m2->colOffset;
|
|
|
|
if ((x + m2->colWidth) < _compact->xcood) // their rightmost
|
|
return false;
|
|
|
|
x -= m1->colWidth; // our left, their right
|
|
if (x >= _compact->xcood)
|
|
return false;
|
|
|
|
y += 8; // bring them down a line
|
|
if (y == _compact->ycood)
|
|
return true;
|
|
|
|
y += 8; // bring them down a line
|
|
if (y == _compact->ycood)
|
|
return true;
|
|
|
|
return false;
|
|
case 1: // looking down
|
|
x -= m1->colOffset; // compensate for inner x offsets
|
|
x += m2->colOffset;
|
|
|
|
if ((x + m2->colWidth) < _compact->xcood) // their rightmoast
|
|
return false;
|
|
|
|
x -= m1->colWidth; // our left, their right
|
|
if (x >= _compact->xcood)
|
|
return false;
|
|
|
|
y -= 8; // bring them up a line
|
|
if (y == _compact->ycood)
|
|
return true;
|
|
|
|
y -= 8; // bring them up a line
|
|
if (y == _compact->ycood)
|
|
return true;
|
|
|
|
return false;
|
|
case 2: // looking left
|
|
|
|
if (y != _compact->ycood)
|
|
return false;
|
|
|
|
x += m2->lastChr;
|
|
if (x == _compact->xcood)
|
|
return true;
|
|
|
|
x -= 8; // out another one
|
|
if (x == _compact->xcood)
|
|
return true;
|
|
|
|
return false;
|
|
case 3: // looking right
|
|
case 4: // talking (not sure if this makes sense...)
|
|
|
|
if (y != _compact->ycood)
|
|
return false;
|
|
|
|
x -= m1->lastChr; // last block
|
|
if (x == _compact->xcood)
|
|
return true;
|
|
|
|
x -= 8; // out another block
|
|
if (x != _compact->xcood)
|
|
return false;
|
|
|
|
return true;
|
|
default:
|
|
error("Unknown Direction: %d", _compact->extCompact->dir);
|
|
}
|
|
}
|
|
|
|
void SkyLogic::runGetOff() {
|
|
uint32 getOff = _scriptVariables[GET_OFF];
|
|
_scriptVariables[GET_OFF] = 0;
|
|
if (getOff)
|
|
script((uint16)(getOff & 0xffff), (uint16)(getOff >> 16));
|
|
}
|
|
|
|
void SkyLogic::stopAndWait() {
|
|
_compact->mode += 4;
|
|
|
|
uint16 *scriptNo = SkyCompact::getSub(_compact, _compact->mode);
|
|
uint16 *offset = SkyCompact::getSub(_compact, _compact->mode + 2);
|
|
|
|
*scriptNo = (uint16)(_compact->extCompact->stopScript & 0xffff);
|
|
*offset = (uint16)(_compact->extCompact->stopScript >> 16);
|
|
|
|
_compact->logic = L_SCRIPT;
|
|
logicScript();
|
|
}
|
|
|
|
void SkyLogic::checkModuleLoaded(uint16 moduleNo) {
|
|
if (!_moduleList[moduleNo])
|
|
_moduleList[moduleNo] = (uint16 *)_skyDisk->loadFile((uint16)moduleNo + F_MODULE_0, NULL);
|
|
}
|
|
|
|
void SkyLogic::push(uint32 a) {
|
|
if (_stackPtr > ARRAYSIZE(_stack) - 2)
|
|
error("Stack overflow");
|
|
_stack[_stackPtr++] = a;
|
|
}
|
|
|
|
uint32 SkyLogic::pop() {
|
|
if (_stackPtr < 1 || _stackPtr > ARRAYSIZE(_stack) - 1)
|
|
error("No items on Stack to pop");
|
|
return _stack[--_stackPtr];
|
|
}
|
|
|
|
typedef bool (SkyLogic::*McodeTable) (uint32, uint32, uint32);
|
|
static McodeTable mcodeTable[] = {
|
|
&SkyLogic::fnCacheChip,
|
|
&SkyLogic::fnCacheFast,
|
|
&SkyLogic::fnDrawScreen,
|
|
&SkyLogic::fnAr,
|
|
&SkyLogic::fnArAnimate,
|
|
&SkyLogic::fnIdle,
|
|
&SkyLogic::fnInteract,
|
|
&SkyLogic::fnStartSub,
|
|
&SkyLogic::fnTheyStartSub,
|
|
&SkyLogic::fnAssignBase,
|
|
&SkyLogic::fnDiskMouse,
|
|
&SkyLogic::fnNormalMouse,
|
|
&SkyLogic::fnBlankMouse,
|
|
&SkyLogic::fnCrossMouse,
|
|
&SkyLogic::fnCursorRight,
|
|
&SkyLogic::fnCursorLeft,
|
|
&SkyLogic::fnCursorDown,
|
|
&SkyLogic::fnOpenHand,
|
|
&SkyLogic::fnCloseHand,
|
|
&SkyLogic::fnGetTo,
|
|
&SkyLogic::fnSetToStand,
|
|
&SkyLogic::fnTurnTo,
|
|
&SkyLogic::fnArrived,
|
|
&SkyLogic::fnLeaving,
|
|
&SkyLogic::fnSetAlternate,
|
|
&SkyLogic::fnAltSetAlternate,
|
|
&SkyLogic::fnKillId,
|
|
&SkyLogic::fnNoHuman,
|
|
&SkyLogic::fnAddHuman,
|
|
&SkyLogic::fnAddButtons,
|
|
&SkyLogic::fnNoButtons,
|
|
&SkyLogic::fnSetStop,
|
|
&SkyLogic::fnClearStop,
|
|
&SkyLogic::fnPointerText,
|
|
&SkyLogic::fnQuit,
|
|
&SkyLogic::fnSpeakMe,
|
|
&SkyLogic::fnSpeakMeDir,
|
|
&SkyLogic::fnSpeakWait,
|
|
&SkyLogic::fnSpeakWaitDir,
|
|
&SkyLogic::fnChooser,
|
|
&SkyLogic::fnHighlight,
|
|
&SkyLogic::fnTextKill,
|
|
&SkyLogic::fnStopMode,
|
|
&SkyLogic::fnWeWait,
|
|
&SkyLogic::fnSendSync,
|
|
&SkyLogic::fnSendFastSync,
|
|
&SkyLogic::fnSendRequest,
|
|
&SkyLogic::fnClearRequest,
|
|
&SkyLogic::fnCheckRequest,
|
|
&SkyLogic::fnStartMenu,
|
|
&SkyLogic::fnUnhighlight,
|
|
&SkyLogic::fnFaceId,
|
|
&SkyLogic::fnForeground,
|
|
&SkyLogic::fnBackground,
|
|
&SkyLogic::fnNewBackground,
|
|
&SkyLogic::fnSort,
|
|
&SkyLogic::fnNoSpriteEngine,
|
|
&SkyLogic::fnNoSpritesA6,
|
|
&SkyLogic::fnResetId,
|
|
&SkyLogic::fnToggleGrid,
|
|
&SkyLogic::fnPause,
|
|
&SkyLogic::fnRunAnimMod,
|
|
&SkyLogic::fnSimpleMod,
|
|
&SkyLogic::fnRunFrames,
|
|
&SkyLogic::fnAwaitSync,
|
|
&SkyLogic::fnIncMegaSet,
|
|
&SkyLogic::fnDecMegaSet,
|
|
&SkyLogic::fnSetMegaSet,
|
|
&SkyLogic::fnMoveItems,
|
|
&SkyLogic::fnNewList,
|
|
&SkyLogic::fnAskThis,
|
|
&SkyLogic::fnRandom,
|
|
&SkyLogic::fnPersonHere,
|
|
&SkyLogic::fnToggleMouse,
|
|
&SkyLogic::fnMouseOn,
|
|
&SkyLogic::fnMouseOff,
|
|
&SkyLogic::fnFetchX,
|
|
&SkyLogic::fnFetchY,
|
|
&SkyLogic::fnTestList,
|
|
&SkyLogic::fnFetchPlace,
|
|
&SkyLogic::fnCustomJoey,
|
|
&SkyLogic::fnSetPalette,
|
|
&SkyLogic::fnTextModule,
|
|
&SkyLogic::fnChangeName,
|
|
&SkyLogic::fnMiniLoad,
|
|
&SkyLogic::fnFlushBuffers,
|
|
&SkyLogic::fnFlushChip,
|
|
&SkyLogic::fnSaveCoods,
|
|
&SkyLogic::fnPlotGrid,
|
|
&SkyLogic::fnRemoveGrid,
|
|
&SkyLogic::fnEyeball,
|
|
&SkyLogic::fnCursorUp,
|
|
&SkyLogic::fnLeaveSection,
|
|
&SkyLogic::fnEnterSection,
|
|
&SkyLogic::fnRestoreGame,
|
|
&SkyLogic::fnRestartGame,
|
|
&SkyLogic::fnNewSwingSeq,
|
|
&SkyLogic::fnWaitSwingEnd,
|
|
&SkyLogic::fnSkipIntroCode,
|
|
&SkyLogic::fnBlankScreen,
|
|
&SkyLogic::fnPrintCredit,
|
|
&SkyLogic::fnLookAt,
|
|
&SkyLogic::fnLincTextModule,
|
|
&SkyLogic::fnTextKill2,
|
|
&SkyLogic::fnSetFont,
|
|
&SkyLogic::fnStartFx,
|
|
&SkyLogic::fnStopFx,
|
|
&SkyLogic::fnStartMusic,
|
|
&SkyLogic::fnStopMusic,
|
|
&SkyLogic::fnFadeDown,
|
|
&SkyLogic::fnFadeUp,
|
|
&SkyLogic::fnQuitToDos,
|
|
&SkyLogic::fnPauseFx,
|
|
&SkyLogic::fnUnPauseFx,
|
|
&SkyLogic::fnPrintf
|
|
};
|
|
|
|
static const uint32 forwardList1b[] = {
|
|
JOBS_SPEECH,
|
|
JOBS_S4,
|
|
JOBS_ALARMED,
|
|
JOEY_RECYCLE,
|
|
SHOUT_SSS,
|
|
JOEY_MISSION,
|
|
TRANS_MISSION,
|
|
SLOT_MISSION,
|
|
CORNER_MISSION,
|
|
JOEY_LOGIC,
|
|
GORDON_SPEECH,
|
|
JOEY_BUTTON_MISSION,
|
|
LOB_DAD_SPEECH,
|
|
LOB_SON_SPEECH,
|
|
GUARD_SPEECH,
|
|
MANTRACH_SPEECH,
|
|
WRECK_SPEECH,
|
|
ANITA_SPEECH,
|
|
LAMB_FACTORY,
|
|
FORE_SPEECH,
|
|
JOEY_42_MISS,
|
|
JOEY_JUNCTION_MISS,
|
|
WELDER_MISSION,
|
|
JOEY_WELD_MISSION,
|
|
RADMAN_SPEECH,
|
|
LINK_7_29,
|
|
LINK_29_7,
|
|
LAMB_TO_3,
|
|
LAMB_TO_2,
|
|
BURKE_SPEECH,
|
|
BURKE_1,
|
|
BURKE_2,
|
|
DR_BURKE_1,
|
|
JASON_SPEECH,
|
|
JOEY_BELLEVUE,
|
|
ANCHOR_SPEECH,
|
|
ANCHOR_MISSION,
|
|
JOEY_PC_MISSION,
|
|
HOOK_MISSION,
|
|
TREVOR_SPEECH,
|
|
JOEY_FACTORY,
|
|
HELGA_SPEECH,
|
|
JOEY_HELGA_MISSION,
|
|
GALL_BELLEVUE,
|
|
GLASS_MISSION,
|
|
LAMB_FACT_RETURN,
|
|
LAMB_LEAVE_GARDEN,
|
|
LAMB_START_29,
|
|
LAMB_BELLEVUE,
|
|
CABLE_MISSION,
|
|
FOSTER_TOUR,
|
|
LAMB_TOUR,
|
|
FOREMAN_LOGIC,
|
|
LAMB_LEAVE_FACTORY,
|
|
LAMB_BELL_LOGIC,
|
|
LAMB_FACT_2,
|
|
START90,
|
|
0,
|
|
0,
|
|
LINK_28_31,
|
|
LINK_31_28,
|
|
EXIT_LINC,
|
|
DEATH_SCRIPT
|
|
};
|
|
|
|
static uint32 forwardList1b288[] = {
|
|
JOBS_SPEECH,
|
|
JOBS_S4,
|
|
JOBS_ALARMED,
|
|
JOEY_RECYCLE,
|
|
SHOUT_SSS,
|
|
JOEY_MISSION,
|
|
TRANS_MISSION,
|
|
SLOT_MISSION,
|
|
CORNER_MISSION,
|
|
JOEY_LOGIC,
|
|
GORDON_SPEECH,
|
|
JOEY_BUTTON_MISSION,
|
|
LOB_DAD_SPEECH,
|
|
LOB_SON_SPEECH,
|
|
GUARD_SPEECH,
|
|
0x68,
|
|
WRECK_SPEECH,
|
|
ANITA_SPEECH,
|
|
LAMB_FACTORY,
|
|
FORE_SPEECH,
|
|
JOEY_42_MISS,
|
|
JOEY_JUNCTION_MISS,
|
|
WELDER_MISSION,
|
|
JOEY_WELD_MISSION,
|
|
RADMAN_SPEECH,
|
|
LINK_7_29,
|
|
LINK_29_7,
|
|
LAMB_TO_3,
|
|
LAMB_TO_2,
|
|
0x3147,
|
|
0x3100,
|
|
0x3101,
|
|
0x3102,
|
|
0x3148,
|
|
0x3149,
|
|
0x314A,
|
|
0x30C5,
|
|
0x30C6,
|
|
0x30CB,
|
|
0x314B,
|
|
JOEY_FACTORY,
|
|
0x314C,
|
|
0x30E2,
|
|
0x314D,
|
|
0x310C,
|
|
LAMB_FACT_RETURN,
|
|
0x3139,
|
|
0x313A,
|
|
0x004F,
|
|
CABLE_MISSION,
|
|
FOSTER_TOUR,
|
|
LAMB_TOUR,
|
|
FOREMAN_LOGIC,
|
|
LAMB_LEAVE_FACTORY,
|
|
0x3138,
|
|
LAMB_FACT_2,
|
|
0x004D,
|
|
0,
|
|
0,
|
|
LINK_28_31,
|
|
LINK_31_28,
|
|
0x004E,
|
|
DEATH_SCRIPT
|
|
};
|
|
|
|
static const uint32 forwardList2b[] = {
|
|
STD_ON,
|
|
STD_EXIT_LEFT_ON,
|
|
STD_EXIT_RIGHT_ON,
|
|
ADVISOR_188,
|
|
SHOUT_ACTION,
|
|
MEGA_CLICK,
|
|
MEGA_ACTION
|
|
};
|
|
|
|
static const uint32 forwardList3b[] = {
|
|
DANI_SPEECH,
|
|
DANIELLE_GO_HOME,
|
|
SPUNKY_GO_HOME,
|
|
HENRI_SPEECH,
|
|
BUZZER_SPEECH,
|
|
FOSTER_VISIT_DANI,
|
|
DANIELLE_LOGIC,
|
|
JUKEBOX_SPEECH,
|
|
VINCENT_SPEECH,
|
|
EDDIE_SPEECH,
|
|
BLUNT_SPEECH,
|
|
DANI_ANSWER_PHONE,
|
|
SPUNKY_SEE_VIDEO,
|
|
SPUNKY_BARK_AT_FOSTER,
|
|
SPUNKY_SMELLS_FOOD,
|
|
BARRY_SPEECH,
|
|
COLSTON_SPEECH,
|
|
GALL_SPEECH,
|
|
BABS_SPEECH,
|
|
CHUTNEY_SPEECH,
|
|
FOSTER_ENTER_COURT
|
|
};
|
|
|
|
static const uint32 forwardList4b[] = {
|
|
WALTER_SPEECH,
|
|
JOEY_MEDIC,
|
|
JOEY_MED_LOGIC,
|
|
JOEY_MED_MISSION72,
|
|
KEN_LOGIC,
|
|
KEN_SPEECH,
|
|
KEN_MISSION_HAND,
|
|
SC70_IRIS_OPENED,
|
|
SC70_IRIS_CLOSED,
|
|
FOSTER_ENTER_BOARDROOM,
|
|
BORED_ROOM,
|
|
FOSTER_ENTER_NEW_BOARDROOM,
|
|
HOBS_END,
|
|
SC82_JOBS_SSS
|
|
};
|
|
|
|
static const uint32 forwardList5b[] = {
|
|
SET_UP_INFO_WINDOW,
|
|
SLAB_ON,
|
|
UP_MOUSE,
|
|
DOWN_MOUSE,
|
|
LEFT_MOUSE,
|
|
RIGHT_MOUSE,
|
|
DISCONNECT_FOSTER
|
|
};
|
|
|
|
void SkyLogic::initScriptVariables() {
|
|
for (int i = 0; i < ARRAYSIZE(_scriptVariables); i++)
|
|
_scriptVariables[i] = 0;
|
|
|
|
_scriptVariables[2] = 141;
|
|
_scriptVariables[109] = 62;
|
|
_scriptVariables[145] = 1;
|
|
_scriptVariables[146] = 2;
|
|
_scriptVariables[450] = 8371;
|
|
_scriptVariables[640] = 1;
|
|
_scriptVariables[678] = 1;
|
|
_scriptVariables[693] = 3;
|
|
_scriptVariables[704] = 1;
|
|
_scriptVariables[709] = 1;
|
|
_scriptVariables[710] = 1;
|
|
_scriptVariables[711] = 1;
|
|
_scriptVariables[719] = 1;
|
|
_scriptVariables[720] = 1;
|
|
_scriptVariables[793] = 1;
|
|
_scriptVariables[797] = 1;
|
|
_scriptVariables[798] = 1;
|
|
_scriptVariables[804] = 1;
|
|
_scriptVariables[805] = 1;
|
|
_scriptVariables[806] = 16731;
|
|
_scriptVariables[807] = 1;
|
|
_scriptVariables[808] = 2;
|
|
_scriptVariables[817] = 1;
|
|
_scriptVariables[818] = 1;
|
|
_scriptVariables[819] = 1;
|
|
_scriptVariables[820] = 1;
|
|
_scriptVariables[821] = 1;
|
|
|
|
if (SkyEngine::_systemVars.gameVersion == 288)
|
|
memcpy(_scriptVariables + 352, forwardList1b288, sizeof(forwardList1b288));
|
|
else
|
|
memcpy(_scriptVariables + 352, forwardList1b, sizeof(forwardList1b));
|
|
|
|
memcpy(_scriptVariables + 656, forwardList2b, sizeof(forwardList2b));
|
|
memcpy(_scriptVariables + 721, forwardList3b, sizeof(forwardList3b));
|
|
memcpy(_scriptVariables + 663, forwardList4b, sizeof(forwardList4b));
|
|
memcpy(_scriptVariables + 505, forwardList5b, sizeof(forwardList5b));
|
|
}
|
|
|
|
uint16 SkyLogic::mouseScript(uint32 scrNum, Compact *scriptComp) {
|
|
|
|
Compact *tmpComp = _compact;
|
|
_compact = scriptComp;
|
|
uint16 retVal = script((uint16)(scrNum & 0xFFFF), (uint16)(scrNum >> 16));
|
|
_compact = tmpComp;
|
|
return retVal;
|
|
}
|
|
|
|
/**
|
|
* This is the actual script engine. It interprets script \a scriptNo starting at \a offset
|
|
*
|
|
* @param scriptNo The script to interpret.
|
|
* @arg Bits 0-11 - Script number
|
|
* @arg Bits 12-15 - Module number
|
|
* @param offset At which offset to start interpreting the script.
|
|
*
|
|
* @return 0 if script finished. Else offset where to continue.
|
|
*/
|
|
uint16 SkyLogic::script(uint16 scriptNo, uint16 offset) {
|
|
script:
|
|
/// process a script
|
|
/// low level interface to interpreter
|
|
|
|
uint16 moduleNo = (uint16)((scriptNo & 0xff00) >> 12);
|
|
debug(3, "Doing Script %x", (offset << 16) | scriptNo);
|
|
uint16 *scriptData = _moduleList[moduleNo]; // get module address
|
|
|
|
if (!scriptData) { // The module has not been loaded
|
|
scriptData = (uint16 *)_skyDisk->loadFile(moduleNo + F_MODULE_0, NULL);
|
|
_moduleList[moduleNo] = scriptData; // module has been loaded
|
|
}
|
|
|
|
uint16 *moduleStart = scriptData;
|
|
|
|
// Check whether we have an offset or what
|
|
if (offset)
|
|
scriptData = moduleStart + offset;
|
|
else
|
|
scriptData += READ_LE_UINT16(scriptData + (scriptNo & 0x0fff));
|
|
|
|
uint32 a = 0, b = 0, c = 0;
|
|
uint16 command, s;
|
|
|
|
for (;;) {
|
|
command = READ_LE_UINT16(scriptData++); // get a command
|
|
SkyDebug::script(command, scriptData);
|
|
|
|
switch (command) {
|
|
case 0: // push_variable
|
|
push( _scriptVariables[READ_LE_UINT16(scriptData++) / 4] );
|
|
break;
|
|
case 1: // less_than
|
|
a = pop();
|
|
b = pop();
|
|
if (a > b)
|
|
push(1);
|
|
else
|
|
push(0);
|
|
break;
|
|
case 2: // push_number
|
|
push(READ_LE_UINT16(scriptData++));
|
|
break;
|
|
case 3: // not_equal
|
|
a = pop();
|
|
b = pop();
|
|
if (a != b)
|
|
push(1);
|
|
else
|
|
push(0);
|
|
break;
|
|
case 4: // if_and
|
|
a = pop();
|
|
b = pop();
|
|
if (a && b)
|
|
push(1);
|
|
else
|
|
push(0);
|
|
break;
|
|
case 5: // skip_zero
|
|
s = READ_LE_UINT16(scriptData++);
|
|
|
|
a = pop();
|
|
if (!a)
|
|
scriptData += s / 2;
|
|
break;
|
|
case 6: // pop_var
|
|
b = _scriptVariables[READ_LE_UINT16(scriptData++) / 4] = pop();
|
|
break;
|
|
case 7: // minus
|
|
a = pop();
|
|
b = pop();
|
|
push(b-a);
|
|
break;
|
|
case 8: // plus
|
|
a = pop();
|
|
b = pop();
|
|
push(b+a);
|
|
break;
|
|
case 9: // skip_always
|
|
s = READ_LE_UINT16(scriptData++);
|
|
scriptData += s / 2;
|
|
break;
|
|
case 10: // if_or
|
|
a = pop();
|
|
b = pop();
|
|
if (a || b)
|
|
push(1);
|
|
else
|
|
push(0);
|
|
break;
|
|
case 11: // call_mcode
|
|
{
|
|
a = READ_LE_UINT16(scriptData++);
|
|
assert(a <= 3);
|
|
// No, I did not forget the "break"s
|
|
switch (a) {
|
|
case 3:
|
|
c = pop();
|
|
case 2:
|
|
b = pop();
|
|
case 1:
|
|
a = pop();
|
|
}
|
|
|
|
uint16 mcode = READ_LE_UINT16(scriptData++)/4; // get mcode number
|
|
SkyDebug::mcode(mcode, a, b, c);
|
|
|
|
Compact *saveCpt = _compact;
|
|
bool ret = (this->*mcodeTable[mcode]) (a, b, c);
|
|
_compact = saveCpt;
|
|
|
|
if (!ret)
|
|
return (scriptData - moduleStart);
|
|
}
|
|
break;
|
|
case 12: // more_than
|
|
a = pop();
|
|
b = pop();
|
|
if (a < b)
|
|
push(1);
|
|
else
|
|
push(0);
|
|
break;
|
|
case 14: // switch
|
|
c = s = READ_LE_UINT16(scriptData++); // get number of cases
|
|
|
|
a = pop(); // and value to switch on
|
|
|
|
do {
|
|
if (a == READ_LE_UINT16(scriptData)) {
|
|
scriptData += READ_LE_UINT16(scriptData + 1) / 2;
|
|
scriptData++;
|
|
break;
|
|
}
|
|
scriptData += 2;
|
|
} while (--s);
|
|
|
|
if (s == 0)
|
|
scriptData += READ_LE_UINT16(scriptData++)/2 - 1; // use the default
|
|
break;
|
|
case 15: // push_offset
|
|
push( *(uint16 *)SkyCompact::getCompactElem(_compact, READ_LE_UINT16(scriptData++)) );
|
|
break;
|
|
case 16: // pop_offset
|
|
// pop a value into a compact
|
|
*(uint16 *)SkyCompact::getCompactElem(_compact, READ_LE_UINT16(scriptData++)) = (uint16)pop();
|
|
break;
|
|
case 17: // is_equal
|
|
a = pop();
|
|
b = pop();
|
|
if (a == b)
|
|
push(1);
|
|
else
|
|
push(0);
|
|
break;
|
|
case 18: { // skip_nz
|
|
int16 t = READ_LE_UINT16(scriptData++);
|
|
a = pop();
|
|
if (a)
|
|
scriptData += t / 2;
|
|
break;
|
|
}
|
|
case 13:
|
|
case 19: // script_exit
|
|
return 0;
|
|
case 20: // restart_script
|
|
offset = 0;
|
|
goto script;
|
|
default:
|
|
error("Unknown script command: %d", command);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool SkyLogic::fnCacheChip(uint32 a, uint32 b, uint32 c) {
|
|
_skySound->fnStopFx();
|
|
_skyDisk->fnCacheChip(a);
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnCacheFast(uint32 a, uint32 b, uint32 c) {
|
|
_skyDisk->fnCacheFast(a);
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnDrawScreen(uint32 a, uint32 b, uint32 c) {
|
|
debug(5, "Call: fnDrawScreen(%X, %X)",a,b);
|
|
SkyEngine::_systemVars.currentPalette = a;
|
|
_skyScreen->fnDrawScreen(a, b);
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnAr(uint32 x, uint32 y, uint32 c) {
|
|
_compact->downFlag = 1; // assume failure in-case logic is interupted by speech (esp Joey)
|
|
|
|
_compact->extCompact->arTargetX = (uint16)x;
|
|
_compact->extCompact->arTargetY = (uint16)y;
|
|
_compact->logic = L_AR; // Set to AR mode
|
|
|
|
_compact->xcood &= 0xfff8;
|
|
_compact->ycood &= 0xfff8;
|
|
|
|
return false; // drop out of script
|
|
}
|
|
|
|
bool SkyLogic::fnArAnimate(uint32 a, uint32 b, uint32 c) {
|
|
_compact->mood = 0; // high level 'not stood still'
|
|
_compact->logic = L_AR_ANIM;
|
|
return false; // drop out of script
|
|
}
|
|
|
|
bool SkyLogic::fnIdle(uint32 a, uint32 b, uint32 c) {
|
|
// set the player idling
|
|
_compact->logic = 0;
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnInteract(uint32 targetId, uint32 b, uint32 c) {
|
|
_compact->mode += 4; // next level up
|
|
_compact->logic = L_SCRIPT;
|
|
Compact *cpt = SkyEngine::fetchCompact(targetId);
|
|
|
|
*SkyCompact::getSub(_compact, _compact->mode) = cpt->actionScript;
|
|
*SkyCompact::getSub(_compact, _compact->mode + 2) = 0;
|
|
|
|
return false;
|
|
}
|
|
|
|
bool SkyLogic::fnStartSub(uint32 scr, uint32 b, uint32 c) {
|
|
_compact->mode += 4;
|
|
*SkyCompact::getSub(_compact, _compact->mode) = (uint16)(scr & 0xffff);
|
|
*SkyCompact::getSub(_compact, _compact->mode + 2) = (uint16)(scr >> 16);
|
|
return false;
|
|
}
|
|
|
|
bool SkyLogic::fnTheyStartSub(uint32 mega, uint32 scr, uint32 c) {
|
|
Compact *cpt = SkyEngine::fetchCompact(mega);
|
|
cpt->mode += 4;
|
|
*SkyCompact::getSub(cpt, cpt->mode) = (uint16)(scr & 0xffff);
|
|
*SkyCompact::getSub(cpt, cpt->mode + 2) = (uint16)(scr >> 16);
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnAssignBase(uint32 id, uint32 scr, uint32 c) {
|
|
Compact *cpt = SkyEngine::fetchCompact(id);
|
|
cpt->mode = C_BASE_MODE;
|
|
cpt->logic = L_SCRIPT;
|
|
cpt->baseSub = (uint16)(scr & 0xffff);
|
|
cpt->baseSub_off = (uint16)(scr >> 16);
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnDiskMouse(uint32 a, uint32 b, uint32 c) {
|
|
_skyMouse->spriteMouse(MOUSE_DISK, 11, 11);
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnNormalMouse(uint32 a, uint32 b, uint32 c) {
|
|
_skyMouse->spriteMouse(MOUSE_NORMAL, 0, 0);
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnBlankMouse(uint32 a, uint32 b, uint32 c) {
|
|
_skyMouse->spriteMouse(MOUSE_BLANK, 0, 0);
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnCrossMouse(uint32 a, uint32 b, uint32 c) {
|
|
if (_scriptVariables[OBJECT_HELD])
|
|
_skyMouse->fnOpenCloseHand(false);
|
|
else
|
|
_skyMouse->spriteMouse(MOUSE_CROSS, 4, 4);
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnCursorRight(uint32 a, uint32 b, uint32 c) {
|
|
_skyMouse->spriteMouse(MOUSE_RIGHT, 9, 4);
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnCursorLeft(uint32 a, uint32 b, uint32 c) {
|
|
_skyMouse->spriteMouse(MOUSE_LEFT, 0, 5);
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnCursorDown(uint32 a, uint32 b, uint32 c) {
|
|
_skyMouse->spriteMouse(MOUSE_DOWN, 9, 4);
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnCursorUp(uint32 a, uint32 b, uint32 c) {
|
|
_skyMouse->spriteMouse(MOUSE_UP, 9, 4);
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnOpenHand(uint32 a, uint32 b, uint32 c) {
|
|
_skyMouse->fnOpenCloseHand(true);
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnCloseHand(uint32 a, uint32 b, uint32 c) {
|
|
_skyMouse->fnOpenCloseHand(false);
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnGetTo(uint32 targetPlaceId, uint32 mode, uint32 c) {
|
|
_compact->upFlag = (uint16)mode; // save mode for action script
|
|
_compact->mode += 4; // next level up
|
|
Compact *cpt = SkyEngine::fetchCompact(_compact->place);
|
|
if (!cpt) {
|
|
warning("can't find _compact's getToTable. Place compact is NULL");
|
|
return false;
|
|
}
|
|
uint16 *getToTable = cpt->getToTable;
|
|
if (!getToTable) {
|
|
warning("Place compact's getToTable is NULL!");
|
|
return false;
|
|
}
|
|
|
|
while (*getToTable != targetPlaceId)
|
|
getToTable += 2;
|
|
|
|
// get new script
|
|
*SkyCompact::getSub(_compact, _compact->mode) = *(getToTable + 1);
|
|
*SkyCompact::getSub(_compact, _compact->mode + 2) = 0;
|
|
|
|
return false; // drop out of script
|
|
}
|
|
|
|
bool SkyLogic::fnSetToStand(uint32 a, uint32 b, uint32 c) {
|
|
_compact->mood = 1; // high level stood still
|
|
|
|
_compact->grafixProg.ptrType = COMPACTELEM;
|
|
_compact->grafixProg.pos = 0;
|
|
_compact->grafixProg.ptrTarget =
|
|
C_STAND_UP + _compact->extCompact->megaSet + _compact->extCompact->dir * 4;
|
|
|
|
uint16 *standList = SkyCompact::getGrafixPtr(_compact);
|
|
|
|
_compact->offset = *standList; // get frames offset
|
|
_compact->logic = L_SIMPLE_MOD;
|
|
_compact->grafixProg.pos++;
|
|
simpleAnim();
|
|
return false; // drop out of script
|
|
}
|
|
|
|
bool SkyLogic::fnTurnTo(uint32 dir, uint32 b, uint32 c) {
|
|
/// turn compact to direction dir
|
|
|
|
uint16 curDir = _compact->extCompact->dir; // get current direction
|
|
_compact->extCompact->dir = (uint16)(dir & 0xffff); // set new direction
|
|
|
|
uint16 **tt = SkyCompact::getTurnTable(_compact, _compact->extCompact->megaSet, curDir);
|
|
|
|
if (!tt[dir])
|
|
return true; // keep going
|
|
|
|
_compact->extCompact->turnProg = tt[dir]; // put turn program in
|
|
_compact->logic = L_TURNING;
|
|
|
|
turn();
|
|
|
|
return false; // drop out of script
|
|
}
|
|
|
|
bool SkyLogic::fnArrived(uint32 scriptVar, uint32 b, uint32 c) {
|
|
_compact->extCompact->leaving = (uint16)(scriptVar & 0xffff);
|
|
_scriptVariables[scriptVar/4]++;
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnLeaving(uint32 a, uint32 b, uint32 c) {
|
|
_compact->extCompact->atWatch = 0;
|
|
|
|
if (_compact->extCompact->leaving) {
|
|
_scriptVariables[_compact->extCompact->leaving/4]--;
|
|
_compact->extCompact->leaving = 0; // I shall do this only once
|
|
}
|
|
|
|
return true; // keep going
|
|
}
|
|
|
|
bool SkyLogic::fnSetAlternate(uint32 scr, uint32 b, uint32 c) {
|
|
_compact->extCompact->alt = (uint16)(scr & 0xffff);
|
|
_compact->logic = L_ALT;
|
|
return false;
|
|
}
|
|
|
|
bool SkyLogic::fnAltSetAlternate(uint32 target, uint32 scr, uint32 c) {
|
|
Compact *cpt = SkyEngine::fetchCompact(target);
|
|
cpt->extCompact->alt = (uint16)(scr & 0xffff);
|
|
cpt->logic = L_ALT;
|
|
return false;
|
|
}
|
|
|
|
bool SkyLogic::fnKillId(uint32 id, uint32 b, uint32 c) {
|
|
if (id) {
|
|
Compact *cpt = SkyEngine::fetchCompact(id);
|
|
if (cpt->status & (1 << 7))
|
|
_skyGrid->removeObjectFromWalk(cpt);
|
|
cpt->status = 0;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnNoHuman(uint32 a, uint32 b, uint32 c) {
|
|
if (!_scriptVariables[MOUSE_STOP]) {
|
|
_scriptVariables[MOUSE_STATUS] &= 1;
|
|
runGetOff();
|
|
fnBlankMouse(0, 0, 0);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnAddHuman(uint32 a, uint32 b, uint32 c) {
|
|
return _skyMouse->fnAddHuman();
|
|
}
|
|
|
|
bool SkyLogic::fnAddButtons(uint32 a, uint32 b, uint32 c) {
|
|
_scriptVariables[MOUSE_STATUS] |= 4;
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnNoButtons(uint32 a, uint32 b, uint32 c) {
|
|
//remove the mouse buttons
|
|
_scriptVariables[MOUSE_STATUS] &= 0xFFFFFFFB;
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnSetStop(uint32 a, uint32 b, uint32 c) {
|
|
_scriptVariables[MOUSE_STOP] |= 1;
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnClearStop(uint32 a, uint32 b, uint32 c) {
|
|
_scriptVariables[MOUSE_STOP] = 0;
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnPointerText(uint32 a, uint32 b, uint32 c) {
|
|
|
|
_skyText->fnPointerText(a, _skyMouse->giveMouseX(), _skyMouse->giveMouseY());
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnQuit(uint32 a, uint32 b, uint32 c) {
|
|
return false;
|
|
}
|
|
|
|
bool SkyLogic::fnSpeakMe(uint32 targetId, uint32 mesgNum, uint32 animNum) {
|
|
stdSpeak(SkyEngine::fetchCompact(targetId), mesgNum, animNum, 0);
|
|
return false; //drop out of script
|
|
}
|
|
|
|
bool SkyLogic::fnSpeakMeDir(uint32 targetId, uint32 mesgNum, uint32 animNum) {
|
|
//must be player so don't cause script to drop out
|
|
//this function sets the directional option whereby
|
|
//the anim chosen is linked to c_dir
|
|
animNum += _compact->extCompact->dir << 1; //2 sizes (large and small)
|
|
return fnSpeakMe(targetId, mesgNum, animNum);
|
|
}
|
|
|
|
bool SkyLogic::fnSpeakWait(uint32 id, uint32 message, uint32 animation) {
|
|
// non player mega char speaks
|
|
// player will wait for it to finish before continuing script processing
|
|
_compact->flag = (uint16)(id & 0xffff);
|
|
_compact->logic = L_LISTEN;
|
|
return fnSpeakMe(id, message, animation);
|
|
}
|
|
|
|
bool SkyLogic::fnSpeakWaitDir(uint32 a, uint32 b, uint32 c) {
|
|
/* non player mega chr$ speaks S2(20Jan93tw)
|
|
the player will wait for it to finish
|
|
before continuing script processing
|
|
this function sets the directional option whereby
|
|
the anim chosen is linked to c_dir -
|
|
|
|
_compact is player
|
|
a is ID to speak (not us)
|
|
b is text message number
|
|
c is base of mini table within anim_talk_table */
|
|
|
|
#ifdef __DC__
|
|
__builtin_alloca(4); // Works around a gcc bug (wrong-code/11736)
|
|
#endif
|
|
|
|
_compact->flag = (uint16)a;
|
|
_compact->logic = L_LISTEN;
|
|
|
|
Compact *speaker = SkyEngine::fetchCompact(a);
|
|
if (c) {
|
|
c += speaker->extCompact->dir << 1;
|
|
stdSpeak(speaker, b, c, speaker->extCompact->dir << 1);
|
|
} else
|
|
stdSpeak(speaker, b, c, 0);
|
|
|
|
return false;
|
|
}
|
|
|
|
bool SkyLogic::fnChooser(uint32 a, uint32 b, uint32 c) {
|
|
|
|
// setup the text questions to be clicked on
|
|
// read from TEXT1 until 0
|
|
|
|
SkyEngine::_systemVars.systemFlags |= SF_CHOOSING; // can't save/restore while choosing
|
|
|
|
_scriptVariables[THE_CHOSEN_ONE] = 0; // clear result
|
|
|
|
uint32 *p = _scriptVariables + TEXT1;
|
|
uint16 ycood = TOP_LEFT_Y; // rolling coordinate
|
|
|
|
while (*p) {
|
|
uint32 textNum = *p++;
|
|
|
|
struct lowTextManager_t lowText = _skyText->lowTextManager(textNum, GAME_SCREEN_WIDTH, 0, 241, 0);
|
|
|
|
uint8 *data = lowText.textData;
|
|
|
|
// stipple the text
|
|
|
|
uint32 size = ((dataFileHeader *)data)->s_height * ((dataFileHeader *)data)->s_width;
|
|
uint32 index = 0;
|
|
uint32 width = ((dataFileHeader *)data)->s_width;
|
|
|
|
data += sizeof(dataFileHeader);
|
|
|
|
while (index < size) {
|
|
if (index % width <= 1)
|
|
index ^= 1; //index++;
|
|
if (!data[index])
|
|
data[index] = 1;
|
|
index += 2;
|
|
}
|
|
|
|
Compact *textCompact = SkyEngine::fetchCompact(lowText.compactNum);
|
|
|
|
textCompact->getToFlag = (uint16)textNum;
|
|
textCompact->downFlag = (uint16)*p++; // get animation number
|
|
|
|
textCompact->status |= ST_MOUSE; // mouse detects
|
|
|
|
textCompact->xcood = TOP_LEFT_X; // set coordinates
|
|
textCompact->ycood = ycood;
|
|
ycood += 12;
|
|
}
|
|
|
|
if (p == _scriptVariables + TEXT1)
|
|
return true;
|
|
|
|
_compact->logic = L_CHOOSE; // player frozen until choice made
|
|
fnAddHuman(0, 0, 0); // bring back mouse
|
|
|
|
return false;
|
|
}
|
|
|
|
bool SkyLogic::fnHighlight(uint32 itemNo, uint32 pen, uint32 c) {
|
|
pen -= 11;
|
|
pen ^= 1;
|
|
pen += 241;
|
|
Compact *textCompact = SkyEngine::fetchCompact(itemNo);
|
|
uint8 *sprData = (uint8 *)SkyEngine::fetchItem(textCompact->flag);
|
|
_skyText->changeTextSpriteColour(sprData, (uint8)pen);
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnTextKill(uint32 a, uint32 b, uint32 c) {
|
|
/// Kill of text items that are mouse detectable
|
|
|
|
uint32 id = FIRST_TEXT_COMPACT;
|
|
|
|
for (int i = 10; i > 0; i--) {
|
|
Compact *cpt = SkyEngine::fetchCompact(id);
|
|
if (cpt->status & (1 << 4))
|
|
cpt->status = 0;
|
|
id++;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnStopMode(uint32 a, uint32 b, uint32 c) {
|
|
_compact->logic = L_STOPPED;
|
|
return false;
|
|
}
|
|
|
|
bool SkyLogic::fnWeWait(uint32 id, uint32 b, uint32 c) {
|
|
/// We have hit another mega
|
|
/// we are going to wait for it to move
|
|
|
|
_compact->extCompact->waitingFor = (uint16) id;
|
|
stopAndWait();
|
|
return true; // not sure about this
|
|
}
|
|
|
|
bool SkyLogic::fnSendSync(uint32 mega, uint32 sync, uint32 c) {
|
|
Compact *cpt = SkyEngine::fetchCompact(mega);
|
|
cpt->sync = (uint16)(sync & 0xffff);
|
|
return false;
|
|
}
|
|
|
|
bool SkyLogic::fnSendFastSync(uint32 mega, uint32 sync, uint32 c) {
|
|
Compact *cpt = SkyEngine::fetchCompact(mega);
|
|
cpt->sync = (uint16)(sync & 0xffff);
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnSendRequest(uint32 target, uint32 scr, uint32 c) {
|
|
Compact *cpt = SkyEngine::fetchCompact(target);
|
|
cpt->extCompact->request = (uint16)(scr & 0xffff);
|
|
return false;
|
|
}
|
|
|
|
bool SkyLogic::fnClearRequest(uint32 target, uint32 b, uint32 c) {
|
|
Compact *cpt = SkyEngine::fetchCompact(target);
|
|
cpt->extCompact->request = 0;
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnCheckRequest(uint32 a, uint32 b, uint32 c) {
|
|
/// check for interaction request
|
|
|
|
if (!_compact->extCompact->request)
|
|
return true;
|
|
|
|
_compact->mode = C_ACTION_MODE; // into action mode
|
|
|
|
_compact->extCompact->actionSub = _compact->extCompact->request;
|
|
_compact->extCompact->actionSub_off = 0;
|
|
|
|
_compact->extCompact->request = 0; // trash request
|
|
return false; // drop from script
|
|
}
|
|
|
|
bool SkyLogic::fnStartMenu(uint32 firstObject, uint32 b, uint32 c) {
|
|
/// initialise the top menu bar
|
|
// firstObject is o0 for game menu, k0 for linc
|
|
|
|
uint i;
|
|
firstObject /= 4;
|
|
|
|
// (1) FIRST, SET UP THE 2 ARROWS SO THEY APPEAR ON SCREEN
|
|
|
|
Compact *cpt = SkyEngine::fetchCompact(47);
|
|
cpt->status = ST_MOUSE + ST_FOREGROUND + ST_LOGIC + ST_RECREATE;
|
|
cpt->screen = (uint16)(_scriptVariables[SCREEN] & 0xffff);
|
|
|
|
cpt = SkyEngine::fetchCompact(48);
|
|
cpt->status = ST_MOUSE + ST_FOREGROUND + ST_LOGIC + ST_RECREATE;
|
|
cpt->screen = (uint16)(_scriptVariables[SCREEN] & 0xffff);
|
|
|
|
// (2) COPY OBJECTS FROM NON-ZERO INVENTORY VARIABLES INTO OBJECT DISPLAY LIST (& COUNT THEM)
|
|
|
|
// sort the objects and pad with blanks
|
|
|
|
uint32 menuLength = 0;
|
|
for (i = firstObject; i < firstObject + ARRAYSIZE(_objectList); i++) {
|
|
if ( _scriptVariables[i] )
|
|
_objectList[menuLength++] = _scriptVariables[i];
|
|
}
|
|
_scriptVariables[MENU_LENGTH] = menuLength;
|
|
|
|
// (3) OK, NOW TOP UP THE LIST WITH THE REQUIRED NO. OF BLANK OBJECTS (for min display length 11)
|
|
|
|
uint32 blankID = 51;
|
|
for (i = menuLength; i < 11; i++)
|
|
_objectList[i] = blankID++;
|
|
|
|
// (4) KILL ID's OF ALL 20 OBJECTS SO UNWANTED ICONS (SCROLLED OFF) DON'T REMAIN ON SCREEN
|
|
// (There should be a better way of doing this - only kill id of 12th item when menu has scrolled right)
|
|
|
|
for (i = 0; i < ARRAYSIZE(_objectList); i++) {
|
|
if (_objectList[i])
|
|
(SkyEngine::fetchCompact(_objectList[i]))->status = ST_LOGIC;
|
|
else break;
|
|
}
|
|
|
|
// (5) NOW FIND OUT WHICH OBJECT TO START THE DISPLAY FROM (depending on scroll offset)
|
|
|
|
if (menuLength < 11) // check we can scroll
|
|
_scriptVariables[SCROLL_OFFSET] = 0;
|
|
else if (menuLength < _scriptVariables[SCROLL_OFFSET] + 11)
|
|
_scriptVariables[SCROLL_OFFSET] = menuLength - 11;
|
|
|
|
// (6) AND FINALLY, INITIALISE THE 11 OBJECTS SO THEY APPEAR ON SCREEEN
|
|
|
|
uint16 rollingX = TOP_LEFT_X + 28;
|
|
for (i = 0; i < 11; i++) {
|
|
cpt = SkyEngine::fetchCompact(
|
|
_objectList[_scriptVariables[SCROLL_OFFSET] + i]);
|
|
|
|
cpt->status = ST_MOUSE + ST_FOREGROUND + ST_LOGIC + ST_RECREATE;
|
|
cpt->screen = (uint16)(_scriptVariables[SCREEN] & 0xffff);
|
|
|
|
cpt->xcood = rollingX;
|
|
rollingX += 24;
|
|
|
|
if (_scriptVariables[MENU] == 2)
|
|
cpt->ycood = 136;
|
|
else
|
|
cpt->ycood = 112;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnUnhighlight(uint32 item, uint32 b, uint32 c) {
|
|
Compact *cpt = SkyEngine::fetchCompact(item);
|
|
cpt->frame--;
|
|
cpt->getToFlag = 0;
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnFaceId(uint32 otherId, uint32 b, uint32 c) {
|
|
/// return the direction to turn to face another id
|
|
/// pass back result in c_just_flag
|
|
|
|
Compact *cpt = SkyEngine::fetchCompact(otherId);
|
|
|
|
int16 x = _compact->xcood - cpt->xcood;
|
|
|
|
if (x < 0) { // we're to the left
|
|
x = -x;
|
|
_compact->getToFlag = 3;
|
|
} else { // it's to the left
|
|
_compact->getToFlag = 2;
|
|
}
|
|
|
|
// now check y
|
|
|
|
// we must find the true bottom of the sprite
|
|
// it is not enough to use y coord because changing
|
|
// sprite offsets can ruin the formula - instead we
|
|
// will use the bottom of the mouse collision area
|
|
|
|
int16 y = _compact->ycood - (cpt->ycood + cpt->mouseRelY + cpt->mouseSizeY);
|
|
|
|
if (y < 0) { // it's below
|
|
y = -y;
|
|
if (y >= x)
|
|
_compact->getToFlag = 1;
|
|
} else { // it's above
|
|
if (y >= x)
|
|
_compact->getToFlag = 0;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnForeground(uint32 sprite, uint32 b, uint32 c) {
|
|
/// Make sprite a foreground sprite
|
|
Compact *cpt = SkyEngine::fetchCompact(sprite);
|
|
cpt->status &= 0xfff8;
|
|
cpt->status |= ST_FOREGROUND;
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnBackground(uint32 a, uint32 b, uint32 c) {
|
|
/// Make us a background sprite
|
|
_compact->status &= 0xfff8;
|
|
_compact->status |= ST_BACKGROUND;
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnNewBackground(uint32 sprite, uint32 b, uint32 c) {
|
|
/// Make sprite a background sprite
|
|
Compact *cpt = SkyEngine::fetchCompact(sprite);
|
|
cpt->status &= 0xfff8;
|
|
cpt->status |= ST_BACKGROUND;
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnSort(uint32 mega, uint32 b, uint32 c) {
|
|
Compact *cpt = SkyEngine::fetchCompact(mega);
|
|
cpt->status &= 0xfff8;
|
|
cpt->status |= ST_SORT;
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnNoSpriteEngine(uint32 a, uint32 b, uint32 c) {
|
|
/// stop the compact printing
|
|
/// remove foreground, background & sort
|
|
_compact->status &= 0xfff8;
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnNoSpritesA6(uint32 us, uint32 b, uint32 c) {
|
|
/// stop the compact printing
|
|
/// remove foreground, background & sort
|
|
Compact *cpt = SkyEngine::fetchCompact(us);
|
|
cpt->status &= 0xfff8;
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnResetId(uint32 id, uint32 resetBlock, uint32 c) {
|
|
/// used when a mega is to be restarted
|
|
/// eg - when a smaller mega turn to larger
|
|
/// - a mega changes rooms...
|
|
|
|
Compact *cpt = SkyEngine::fetchCompact(id);
|
|
uint16 *rst = (uint16 *)SkyEngine::fetchCompact(resetBlock);
|
|
|
|
if (!cpt) {
|
|
warning("fnResetId(): Compact %d (id) == NULL",id);
|
|
return true;
|
|
}
|
|
if (!rst) {
|
|
warning("fnResetId(): Compact %d (resetBlock) == NULL",resetBlock);
|
|
return true;
|
|
}
|
|
|
|
uint16 off;
|
|
while ((off = *rst++) != 0xffff)
|
|
*(uint16 *)SkyCompact::getCompactElem(cpt, off) = *rst++;
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnToggleGrid(uint32 a, uint32 b, uint32 c) {
|
|
/// Toggle a mega's grid plotting
|
|
_compact->status ^= ST_GRID_PLOT;
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnPause(uint32 cycles, uint32 b, uint32 c) {
|
|
/// Set mega to L_PAUSE
|
|
_compact->flag = (uint16)(cycles & 0xffff);
|
|
_compact->logic = L_PAUSE;
|
|
return false; // drop out of script
|
|
}
|
|
|
|
bool SkyLogic::fnRunAnimMod(uint32 animNo, uint32 b, uint32 c) {
|
|
_compact->grafixProg.ptrType = COMPACT;
|
|
_compact->grafixProg.ptrTarget = animNo;
|
|
_compact->grafixProg.pos = 0;
|
|
|
|
//uint16 *animation = (uint16 *)SkyEngine::fetchCompact(animNo);
|
|
//uint16 sprite = *animation++; // get sprite set
|
|
//_compact->offset = sprite;
|
|
_compact->offset = *SkyCompact::getGrafixPtr(_compact);
|
|
//_compact->grafixProg = animation;
|
|
_compact->grafixProg.pos++;
|
|
_compact->logic = L_MOD_ANIMATE;
|
|
anim();
|
|
return false; // drop from script
|
|
}
|
|
|
|
bool SkyLogic::fnSimpleMod(uint32 animSeqNo, uint32 b, uint32 c) {
|
|
|
|
_compact->grafixProg.ptrType = COMPACT;
|
|
_compact->grafixProg.ptrTarget = animSeqNo;
|
|
_compact->grafixProg.pos = 0;
|
|
//uint16 *animSeq = (uint16 *)SkyEngine::fetchCompact(animSeqNo);
|
|
//_compact->offset = *animSeq++;
|
|
//assert(*animSeq != 0);
|
|
_compact->offset = *SkyCompact::getGrafixPtr(_compact);
|
|
//_compact->grafixProg = animSeq;
|
|
_compact->grafixProg.pos++;
|
|
_compact->logic = L_SIMPLE_MOD;
|
|
simpleAnim();
|
|
return false;
|
|
}
|
|
|
|
bool SkyLogic::fnRunFrames(uint32 sequenceNo, uint32 b, uint32 c) {
|
|
_compact->grafixProg.ptrType = COMPACT;
|
|
_compact->grafixProg.ptrTarget = sequenceNo;
|
|
_compact->grafixProg.pos = 0;
|
|
//uint16 *sequence = (uint16 *)SkyEngine::fetchCompact(sequenceNo);
|
|
|
|
_compact->logic = L_FRAMES;
|
|
//_compact->offset = *sequence++;
|
|
_compact->offset = *SkyCompact::getGrafixPtr(_compact);
|
|
_compact->grafixProg.pos++;
|
|
//_compact->grafixProg = sequence;
|
|
simpleAnim();
|
|
return false;
|
|
}
|
|
|
|
bool SkyLogic::fnAwaitSync(uint32 a, uint32 b, uint32 c) {
|
|
if (_compact->sync)
|
|
return true;
|
|
|
|
_compact->logic = L_WAIT_SYNC;
|
|
return false;
|
|
}
|
|
|
|
bool SkyLogic::fnIncMegaSet(uint32 a, uint32 b, uint32 c) {
|
|
_compact->extCompact->megaSet += NEXT_MEGA_SET;
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnDecMegaSet(uint32 a, uint32 b, uint32 c) {
|
|
_compact->extCompact->megaSet -= NEXT_MEGA_SET;
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnSetMegaSet(uint32 mega, uint32 setNo, uint32 c) {
|
|
Compact *cpt = SkyEngine::fetchCompact(mega);
|
|
cpt->extCompact->megaSet = (uint16) (setNo * NEXT_MEGA_SET);
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnMoveItems(uint32 listNo, uint32 screenNo, uint32 c) {
|
|
/// Move a list of id's to another screen
|
|
uint16 *p = SkyCompact::move_list[listNo];
|
|
for (int i = 0; i < 2; i++) {
|
|
if (!*p)
|
|
return true;
|
|
Compact *cpt = SkyEngine::fetchCompact(*p++);
|
|
cpt->screen = (uint16)(screenNo & 0xffff);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnNewList(uint32 a, uint32 b, uint32 c) {
|
|
/// Reset the chooser list
|
|
for (int i = 0; i < 16; i++)
|
|
_scriptVariables[TEXT1 + i] = 0;
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnAskThis(uint32 textNo, uint32 animNo, uint32 c) {
|
|
// find first free position
|
|
uint32 *p = _scriptVariables + TEXT1;
|
|
while (*p)
|
|
p += 2;
|
|
*p++ = textNo;
|
|
*p = animNo;
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnRandom(uint32 a, uint32 b, uint32 c) {
|
|
_scriptVariables[RND] = _rnd.getRandomNumber(65536) & a;
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnPersonHere(uint32 id, uint32 room, uint32 c) {
|
|
Compact *cpt = SkyEngine::fetchCompact(id);
|
|
_scriptVariables[RESULT] = cpt->screen == room ? 1 : 0;
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnToggleMouse(uint32 a, uint32 b, uint32 c) {
|
|
|
|
SkyEngine::fetchCompact(a)->status ^= ST_MOUSE;
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnMouseOn(uint32 a, uint32 b, uint32 c) {
|
|
//switch on the mouse highlight
|
|
Compact *cpt = SkyEngine::fetchCompact(a);
|
|
cpt->status |= ST_MOUSE;
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnMouseOff(uint32 a, uint32 b, uint32 c) {
|
|
//switch on (off??) the mouse highlight
|
|
Compact *cpt = SkyEngine::fetchCompact(a);
|
|
cpt->status &= ~ST_MOUSE;
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnFetchX(uint32 id, uint32 b, uint32 c) {
|
|
Compact *cpt = SkyEngine::fetchCompact(id);
|
|
_scriptVariables[RESULT] = cpt->xcood;
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnFetchY(uint32 id, uint32 b, uint32 c) {
|
|
Compact *cpt = SkyEngine::fetchCompact(id);
|
|
_scriptVariables[RESULT] = cpt->ycood;
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnTestList(uint32 id, uint32 x, uint32 y) {
|
|
_scriptVariables[RESULT] = 0; // assume fail
|
|
uint16 *list = (uint16 *)SkyEngine::fetchCompact(id);
|
|
|
|
while (*list) {
|
|
if ((x >= list[0]) && (x < list[1]) && (y >= list[2]) && (y < list[3]))
|
|
_scriptVariables[RESULT] = list[4];
|
|
list += 5;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnFetchPlace(uint32 id, uint32 b, uint32 c) {
|
|
Compact *cpt = SkyEngine::fetchCompact(id);
|
|
_scriptVariables[RESULT] = cpt->place;
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnCustomJoey(uint32 id, uint32 b, uint32 c) {
|
|
/// return id's x & y coordinate & c_mood (i.e. stood still yes/no)
|
|
/// used by Joey-Logic - done in code like this because scripts can't
|
|
/// get access to another megas compact as easily
|
|
|
|
Compact *cpt = SkyEngine::fetchCompact(id);
|
|
|
|
_scriptVariables[PLAYER_X] = cpt->xcood;
|
|
_scriptVariables[PLAYER_Y] = cpt->ycood;
|
|
_scriptVariables[PLAYER_MOOD] = cpt->mood;
|
|
_scriptVariables[PLAYER_SCREEN] = cpt->screen;
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnSetPalette(uint32 a, uint32 b, uint32 c) {
|
|
_skyScreen->setPaletteEndian((uint8 *)SkyEngine::fetchCompact(a));
|
|
SkyEngine::_systemVars.currentPalette = a;
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnTextModule(uint32 a, uint32 b, uint32 c) {
|
|
_skyText->fnTextModule(a, b);
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnChangeName(uint32 id, uint32 textNo, uint32 c) {
|
|
Compact *cpt = SkyEngine::fetchCompact(id);
|
|
cpt->cursorText = (uint16) textNo;
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnMiniLoad(uint32 a, uint32 b, uint32 c) {
|
|
_skyDisk->fnMiniLoad((uint16)a);
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnFlushBuffers(uint32 a, uint32 b, uint32 c) {
|
|
_skyDisk->fnFlushBuffers();
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnFlushChip(uint32 a, uint32 b, uint32 c) {
|
|
// this should be done automatically
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnSaveCoods(uint32 a, uint32 b, uint32 c) {
|
|
_skyMouse->fnSaveCoods();
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnPlotGrid(uint32 x, uint32 y, uint32 width) {
|
|
_skyGrid->plotGrid(x, y, width, _compact);
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnRemoveGrid(uint32 x, uint32 y, uint32 width) {
|
|
_skyGrid->removeGrid(x, y, width, _compact);
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnEyeball(uint32 id, uint32 b, uint32 c) {
|
|
// set 'result' to frame no. pointing to foster, according to table used
|
|
// eg. FN_eyeball (id_eye_90_table);
|
|
|
|
uint16 *eyeTable = (uint16 *)SkyEngine::fetchCompact(id);
|
|
Compact *cpt = SkyEngine::fetchCompact(ID_BLUE_FOSTER);
|
|
|
|
uint32 x = cpt->xcood; // 168 < x < 416
|
|
x -= 168;
|
|
x >>= 3;
|
|
|
|
uint32 y = cpt->ycood; // 256 < y < 296
|
|
y -= 256;
|
|
y <<= 2;
|
|
|
|
_scriptVariables[RESULT] = eyeTable[x + y] + S91;
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnLeaveSection(uint32 sectionNo, uint32 b, uint32 c) {
|
|
if (SkyEngine::isDemo())
|
|
_skyControl->showGameQuitMsg();
|
|
|
|
if (sectionNo == 5) //linc section - has different mouse icons
|
|
_skyMouse->replaceMouseCursors(60301);
|
|
|
|
//_currentSection = 0xFF; // force music-, sound- and gridreload
|
|
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnEnterSection(uint32 sectionNo, uint32 b, uint32 c) {
|
|
|
|
if (SkyEngine::isDemo() && (sectionNo > 2))
|
|
_skyControl->showGameQuitMsg();
|
|
|
|
_scriptVariables[CUR_SECTION] = sectionNo;
|
|
SkyEngine::_systemVars.currentMusic = 0;
|
|
|
|
if (sectionNo == 5) //linc section - has different mouse icons
|
|
_skyMouse->replaceMouseCursors(60302);
|
|
|
|
if ((sectionNo != _currentSection) || (SkyEngine::_systemVars.systemFlags & SF_GAME_RESTORED)) {
|
|
_currentSection = sectionNo;
|
|
|
|
sectionNo++;
|
|
_skyMusic->loadSection((byte)sectionNo);
|
|
_skySound->loadSection((byte)sectionNo);
|
|
_skyGrid->loadGrids();
|
|
SkyEngine::_systemVars.systemFlags &= ~SF_GAME_RESTORED;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnRestoreGame(uint32 a, uint32 b, uint32 c) {
|
|
|
|
_skyControl->doLoadSavePanel();
|
|
return false;
|
|
}
|
|
|
|
bool SkyLogic::fnRestartGame(uint32 a, uint32 b, uint32 c) {
|
|
|
|
_skyControl->restartGame();
|
|
return false;
|
|
}
|
|
|
|
bool SkyLogic::fnNewSwingSeq(uint32 a, uint32 b, uint32 c) {
|
|
// only certain files work on pc. (huh?! something we should take care of?)
|
|
if ((a == 85) || (a == 106) || (a == 75) || (a == 15)) {
|
|
_skyScreen->startSequenceItem((uint16)a);
|
|
} else {
|
|
debug(1,"SkyLogic::fnNewSwingSeq: ignored seq %d",a);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnWaitSwingEnd(uint32 a, uint32 b, uint32 c) {
|
|
_skyScreen->waitForSequence();
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnSkipIntroCode(uint32 a, uint32 b, uint32 c) {
|
|
SkyEngine::_systemVars.pastIntro = true;
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnBlankScreen(uint32 a, uint32 b, uint32 c) {
|
|
_skyScreen->clearScreen();
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnPrintCredit(uint32 a, uint32 b, uint32 c) {
|
|
|
|
lowTextManager_t creditText = _skyText->lowTextManager(a , 240, 0, 248, true);
|
|
Compact *credCompact = SkyEngine::fetchCompact(creditText.compactNum);
|
|
credCompact->xcood = 168;
|
|
if ((a == 558) && (c == 215))
|
|
credCompact->ycood = 211;
|
|
else
|
|
credCompact->ycood = (uint16)c;
|
|
_scriptVariables[RESULT] = creditText.compactNum;
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnLookAt(uint32 a, uint32 b, uint32 c) {
|
|
|
|
struct lowTextManager_t textInfo = _skyText->lowTextManager(a, 240, 0, 248, true);
|
|
Compact *textCpt = SkyEngine::fetchCompact(textInfo.compactNum);
|
|
textCpt->xcood = 168;
|
|
textCpt->ycood = (uint16)c;
|
|
|
|
_skyScreen->recreate();
|
|
_skyScreen->spriteEngine();
|
|
_skyScreen->flip();
|
|
|
|
fnNoHuman(0, 0, 0);
|
|
_skyMouse->lockMouse();
|
|
|
|
_skyMouse->waitMouseNotPressed();
|
|
|
|
_skyMouse->unlockMouse();
|
|
fnAddHuman(0, 0, 0);
|
|
textCpt->status = 0;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnLincTextModule(uint32 textPos, uint32 textNo, uint32 buttonAction) {
|
|
|
|
uint16 cnt;
|
|
if (buttonAction & 0x8000)
|
|
for (cnt = LINC_DIGIT_0; cnt <= LINC_DIGIT_9; cnt++)
|
|
_scriptVariables[cnt] = 0;
|
|
buttonAction &= 0x7FFF;
|
|
if (buttonAction < 10)
|
|
_scriptVariables[LINC_DIGIT_0 + buttonAction] = textNo;
|
|
|
|
lowTextManager_t text = _skyText->lowTextManager(textNo, 220, 0, 215, false);
|
|
|
|
Compact *textCpt = SkyEngine::fetchCompact(text.compactNum);
|
|
|
|
if (textPos < 20) { // line number (for text)
|
|
textCpt->xcood = 152;
|
|
textCpt->ycood = (uint16)textPos * 13 + 170;
|
|
} else if (textPos > 20) { // x coordinate (for numbers)
|
|
textCpt->xcood = (uint16)textPos;
|
|
textCpt->ycood = 214;
|
|
} else warning("::fnLincTextModule: textPos == 20");
|
|
textCpt->getToFlag = (uint16)textNo;
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnTextKill2(uint32 a, uint32 b, uint32 c) {
|
|
/// Kill all text items
|
|
|
|
uint32 id = FIRST_TEXT_COMPACT;
|
|
|
|
for (int i = 10; i > 0; i--) {
|
|
Compact *cpt = SkyEngine::fetchCompact(id);
|
|
cpt->status = 0;
|
|
id++;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnSetFont(uint32 font, uint32 b, uint32 c) {
|
|
_skyText->fnSetFont(font);
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnStartFx(uint32 sound, uint32 b, uint32 c) {
|
|
_skySound->fnStartFx(sound, (uint8)(b & 1));
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnStopFx(uint32 a, uint32 b, uint32 c) {
|
|
_skySound->fnStopFx();
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnStartMusic(uint32 a, uint32 b, uint32 c) {
|
|
if (!(SkyEngine::_systemVars.systemFlags & SF_MUS_OFF))
|
|
_skyMusic->startMusic((uint16)a);
|
|
SkyEngine::_systemVars.currentMusic = (uint16)a;
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnStopMusic(uint32 a, uint32 b, uint32 c) {
|
|
_skyMusic->startMusic(0);
|
|
SkyEngine::_systemVars.currentMusic = 0;
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnFadeDown(uint32 a, uint32 b, uint32 c) {
|
|
_skyScreen->fnFadeDown(a);
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnFadeUp(uint32 a, uint32 b, uint32 c) {
|
|
SkyEngine::_systemVars.currentPalette = a;
|
|
_skyScreen->fnFadeUp(a,b);
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnQuitToDos(uint32 a, uint32 b, uint32 c) {
|
|
_skyControl->showGameQuitMsg(); // calls _system->quit()
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnPauseFx(uint32 a, uint32 b, uint32 c) {
|
|
_skySound->fnPauseFx();
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnUnPauseFx(uint32 a, uint32 b, uint32 c) {
|
|
_skySound->fnUnPauseFx();
|
|
return true;
|
|
}
|
|
|
|
bool SkyLogic::fnPrintf(uint32 a, uint32 b, uint32 c) {
|
|
printf("fnPrintf: %d", a);
|
|
return true;
|
|
}
|
|
|
|
void SkyLogic::stdSpeak(Compact *target, uint32 textNum, uint32 animNum, uint32 base) {
|
|
|
|
uint16 *animPtr;
|
|
|
|
animNum += target->extCompact->megaSet / NEXT_MEGA_SET;
|
|
animNum &= 0xFF;
|
|
if (SkyTalkAnims::animTalkTableIsPointer[animNum]) { //is it a pointer?
|
|
//animPtr = (uint16 *)SkyTalkAnims::animTalkTablePtr[animNum];
|
|
target->grafixProg.ptrType = TALKTABLE;
|
|
target->grafixProg.ptrTarget = animNum;
|
|
} else { //then it must be a value
|
|
//animPtr = (uint16 *)SkyEngine::fetchCompact(SkyTalkAnims::animTalkTableVal[animNum]);
|
|
target->grafixProg.ptrType = COMPACT;
|
|
target->grafixProg.ptrTarget = SkyTalkAnims::animTalkTableVal[animNum];
|
|
}
|
|
target->grafixProg.pos = 0;
|
|
animPtr = SkyCompact::getGrafixPtr(target);
|
|
|
|
if (animPtr) {
|
|
target->offset = *animPtr++;
|
|
target->getToFlag = *animPtr++;
|
|
target->grafixProg.pos += 2;
|
|
} else {
|
|
target->grafixProg.ptrType = PTR_NULL;
|
|
}
|
|
|
|
bool speechUsed = false;
|
|
// startSpeech returns false if no speech file exists for that text
|
|
if (SkyEngine::isCDVersion())
|
|
speechUsed = _skySound->startSpeech((uint16)textNum);
|
|
|
|
// if sky is configured to speech-only return now - except if we're running another
|
|
// language than english
|
|
if (speechUsed && (!(SkyEngine::_systemVars.systemFlags & SF_ALLOW_TEXT))) {
|
|
target->extCompact->spTime = 10;
|
|
target->logic = L_TALK;
|
|
return ;
|
|
}
|
|
|
|
//now form the text sprite
|
|
struct lowTextManager_t textInfo;
|
|
textInfo = _skyText->lowTextManager(textNum, FIXED_TEXT_WIDTH, 0, (uint8)target->extCompact->spColour, true);
|
|
Compact *textCompact = SkyEngine::fetchCompact(textInfo.compactNum);
|
|
target->extCompact->spTextId = textInfo.compactNum; //So we know what text to kill
|
|
byte *textGfx = textInfo.textData;
|
|
|
|
//create the x coordinate for the speech text
|
|
//we need the talkers sprite information
|
|
textCompact->screen = target->screen; //put our screen in
|
|
|
|
if (_scriptVariables[SCREEN] == target->screen) { // Only use coordinates if we are on the current screen
|
|
//talking on-screen
|
|
byte *targetGfx = (byte *)SkyEngine::fetchItem(target->frame >> 6);
|
|
uint16 xPos = target->xcood + ((struct dataFileHeader *)targetGfx)->s_offset_x;
|
|
uint16 width = (((struct dataFileHeader *)targetGfx)->s_width >> 1);
|
|
|
|
xPos += width - (FIXED_TEXT_WIDTH / 2); //middle of talker
|
|
|
|
if (xPos < TOP_LEFT_X)
|
|
xPos = TOP_LEFT_X;
|
|
|
|
width = xPos + FIXED_TEXT_WIDTH;
|
|
if ((TOP_LEFT_X + FULL_SCREEN_WIDTH) <= width) {
|
|
xPos = TOP_LEFT_X + FULL_SCREEN_WIDTH;
|
|
xPos -= FIXED_TEXT_WIDTH;
|
|
}
|
|
|
|
textCompact->xcood = xPos;
|
|
uint16 yPos = target->ycood + ((struct dataFileHeader *)targetGfx)->s_offset_y - 6 - ((struct dataFileHeader *)textGfx)->s_height;
|
|
|
|
if (yPos < TOP_LEFT_Y)
|
|
yPos = TOP_LEFT_Y;
|
|
|
|
textCompact->ycood = yPos;
|
|
|
|
} else {
|
|
//talking off-screen
|
|
target->extCompact->spTextId = 0; //don't kill any text 'cos none was made
|
|
textCompact->status = 0; //don't display text
|
|
}
|
|
// In CD version, we're doing the timing by checking when the VOC has stopped playing.
|
|
// Setting spTime to 10 thus means that we're doing a pause of 10 gamecycles between
|
|
// each sentence.
|
|
if (speechUsed) target->extCompact->spTime = 10;
|
|
else target->extCompact->spTime = (uint16)_skyText->_dtLetters + 5;
|
|
target->logic = L_TALK;
|
|
}
|
|
|