mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-21 01:08:25 +00:00
711f925f69
If it is, all that happens is that it silences the music. Otherwise, the current music that was playing before the game was restored will keep playing afterwards. (One example of this: I went into the Hotel Ubu and restored a savegame at the hospital. The piano music kept playing in the background.) svn-id: r13230
1690 lines
56 KiB
C++
1690 lines
56 KiB
C++
/* ScummVM - Scumm Interpreter
|
|
* Copyright (C) 2003-2004 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 "logic.h"
|
|
#include "text.h"
|
|
#include "sound.h"
|
|
#include "eventman.h"
|
|
#include "menu.h"
|
|
#include "common/util.h"
|
|
#include "router.h"
|
|
#include "screen.h"
|
|
#include "mouse.h"
|
|
#include "sword1.h"
|
|
#include "music.h"
|
|
#include "swordres.h"
|
|
#include "animation.h"
|
|
|
|
#include "debug.h"
|
|
|
|
namespace Sword1 {
|
|
|
|
#define MAX_STACK_SIZE 10
|
|
#define SCRIPT_VERSION 13
|
|
#define LAST_FRAME 999
|
|
|
|
uint32 Logic::_scriptVars[NUM_SCRIPT_VARS];
|
|
|
|
Logic::Logic(ObjectMan *pObjMan, ResMan *resMan, Screen *pScreen, Mouse *pMouse, Sound *pSound, Music *pMusic, Menu *pMenu, OSystem *system, SoundMixer *mixer) {
|
|
_objMan = pObjMan;
|
|
_resMan = resMan;
|
|
_screen = pScreen;
|
|
_mouse = pMouse;
|
|
_music = pMusic;
|
|
_sound = pSound;
|
|
_menu = pMenu;
|
|
_textMan = NULL;
|
|
_screen->useTextManager(_textMan);
|
|
_router = new Router(_objMan, _resMan);
|
|
_eventMan = NULL;
|
|
_system = system;
|
|
_mixer = mixer;
|
|
}
|
|
|
|
void Logic::initialize(void) {
|
|
memset(_scriptVars, 0, NUM_SCRIPT_VARS * sizeof(uint32));
|
|
for (uint8 cnt = 0; cnt < NON_ZERO_SCRIPT_VARS; cnt++)
|
|
_scriptVars[_scriptVarInit[cnt][0]] = _scriptVarInit[cnt][1];
|
|
|
|
delete _eventMan;
|
|
_eventMan = new EventManager();
|
|
|
|
delete _textMan;
|
|
_textMan = new Text(_objMan, _resMan,
|
|
(SwordEngine::_systemVars.language == BS1_CZECH) ? true : false);
|
|
_screen->useTextManager(_textMan);
|
|
_textRunning = _speechRunning = false;
|
|
_speechFinished = true;
|
|
_router->resetExtraData();
|
|
}
|
|
|
|
void Logic::newScreen(uint32 screen) {
|
|
Object *compact = (Object*)_objMan->fetchObject(PLAYER);
|
|
|
|
// work around script bug #911508
|
|
if (((screen == 25) || (_scriptVars[SCREEN] == 25)) && (_scriptVars[SAND_FLAG] == 4)) {
|
|
Object *cpt = _objMan->fetchObject(SAND_25);
|
|
Object *george = _objMan->fetchObject(PLAYER);
|
|
if (george->o_place == HOLDING_REPLICA_25) // is george holding the replica in his hands?
|
|
fnFullSetFrame(cpt, SAND_25, IMPFLRCDT, IMPFLR, 0, 0, 0, 0); // empty impression in floor
|
|
else
|
|
fnFullSetFrame(cpt, SAND_25, IMPPLSCDT, IMPPLS, 0, 0, 0, 0); // impression filled with plaster
|
|
}
|
|
|
|
if (SwordEngine::_systemVars.justRestoredGame) { // if we've just restored a game - we want George to be exactly as saved
|
|
fnAddHuman(NULL, 0, 0, 0, 0, 0, 0, 0);
|
|
if (_scriptVars[GEORGE_WALKING]) { // except that if George was walking when we saveed the game
|
|
fnStandAt(compact, PLAYER, _scriptVars[CHANGE_X], _scriptVars[CHANGE_Y], _scriptVars[CHANGE_DIR], _scriptVars[CHANGE_STANCE], 0,0);
|
|
fnIdle(compact,PLAYER,0,0,0,0,0,0);
|
|
_scriptVars[GEORGE_WALKING] = 0;
|
|
}
|
|
SwordEngine::_systemVars.justRestoredGame = 0;
|
|
_music->startMusic(_scriptVars[CURRENT_MUSIC], 1);
|
|
} else { // if we haven't just restored a game, set George to stand, etc
|
|
compact->o_screen = _scriptVars[NEW_SCREEN]; //move the mega/player at this point between screens
|
|
fnStandAt(compact, PLAYER, _scriptVars[CHANGE_X], _scriptVars[CHANGE_Y], _scriptVars[CHANGE_DIR], _scriptVars[CHANGE_STANCE], 0,0);
|
|
fnChangeFloor(compact, PLAYER, _scriptVars[CHANGE_PLACE], 0, 0, 0, 0, 0);
|
|
}
|
|
}
|
|
|
|
void Logic::engine(void) {
|
|
debug(8, "\n\nNext logic cycle");
|
|
_eventMan->serviceGlobalEventList();
|
|
|
|
for (uint16 sectCnt = 0; sectCnt < TOTAL_SECTIONS; sectCnt++) {
|
|
if (_objMan->sectionAlive(sectCnt)) {
|
|
uint32 numCpts = _objMan->fetchNoObjects(sectCnt);
|
|
for (uint32 cptCnt = 0; cptCnt < numCpts; cptCnt++) {
|
|
uint32 currentId = sectCnt * ITM_PER_SEC + cptCnt;
|
|
Object *compact = _objMan->fetchObject(currentId);
|
|
|
|
if (compact->o_status & STAT_LOGIC) { // does the object want to be processed?
|
|
if (compact->o_status & STAT_EVENTS) {
|
|
//subscribed to the global-event-switcher? and in logic mode
|
|
switch(compact->o_logic) {
|
|
case LOGIC_pause_for_event:
|
|
case LOGIC_idle:
|
|
case LOGIC_AR_animate:
|
|
_eventMan->checkForEvent(compact);
|
|
break;
|
|
}
|
|
}
|
|
debug(7, "Logic::engine: handling compact %d (%X)", currentId, currentId);
|
|
processLogic(compact, currentId);
|
|
compact->o_sync = 0; // syncs are only available for 1 cycle.
|
|
}
|
|
|
|
if ((uint32)compact->o_screen == _scriptVars[SCREEN]) {
|
|
if (compact->o_status & STAT_FORE)
|
|
_screen->addToGraphicList(0, currentId);
|
|
if (compact->o_status & STAT_SORT)
|
|
_screen->addToGraphicList(1, currentId);
|
|
if (compact->o_status & STAT_BACK)
|
|
_screen->addToGraphicList(2, currentId);
|
|
|
|
if (compact->o_status & STAT_MOUSE)
|
|
_mouse->addToList(currentId, compact);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//_collision->checkCollisions();
|
|
|
|
}
|
|
|
|
void Logic::processLogic(Object *compact, uint32 id) {
|
|
int logicRet;
|
|
do {
|
|
switch(compact->o_logic) {
|
|
case LOGIC_idle:
|
|
logicRet = 0;
|
|
break;
|
|
case LOGIC_pause:
|
|
case LOGIC_pause_for_event:
|
|
if (compact->o_pause) {
|
|
compact->o_pause--;
|
|
logicRet = 0;
|
|
} else {
|
|
compact->o_logic = LOGIC_script;
|
|
logicRet = 1;
|
|
}
|
|
break;
|
|
case LOGIC_quit:
|
|
compact->o_logic = LOGIC_script;
|
|
logicRet = 0;
|
|
break;
|
|
case LOGIC_wait_for_sync:
|
|
if (compact->o_sync) {
|
|
logicRet = 1;
|
|
compact->o_logic = LOGIC_script;
|
|
} else
|
|
logicRet = 0;
|
|
break;
|
|
case LOGIC_choose:
|
|
_scriptVars[CUR_ID] = id;
|
|
logicRet = _menu->logicChooser(compact);
|
|
break;
|
|
case LOGIC_wait_for_talk:
|
|
logicRet = logicWaitTalk(compact);
|
|
break;
|
|
case LOGIC_start_talk:
|
|
logicRet = logicStartTalk(compact);
|
|
break;
|
|
case LOGIC_script:
|
|
_scriptVars[CUR_ID] = id;
|
|
logicRet = scriptManager(compact, id);
|
|
break;
|
|
case LOGIC_new_script:
|
|
compact->o_tree.o_script_pc[compact->o_tree.o_script_level] = _newScript;
|
|
compact->o_tree.o_script_id[compact->o_tree.o_script_level] = _newScript;
|
|
compact->o_logic = LOGIC_script;
|
|
logicRet = 1;
|
|
break;
|
|
case LOGIC_AR_animate:
|
|
logicRet = logicArAnimate(compact, id);
|
|
break;
|
|
case LOGIC_restart:
|
|
compact->o_tree.o_script_pc[compact->o_tree.o_script_level] = compact->o_tree.o_script_id[compact->o_tree.o_script_level];
|
|
compact->o_logic = LOGIC_script;
|
|
logicRet=1;
|
|
break;
|
|
case LOGIC_bookmark:
|
|
memcpy(&(compact->o_tree.o_script_level), &(compact->o_bookmark.o_script_level), sizeof(ScriptTree));
|
|
if (id == GMASTER_79) {
|
|
// workaround for ending script.
|
|
// GMASTER_79 is not prepared for mega_interact receiving INS_quit
|
|
fnSuicide(compact, id, 0, 0, 0, 0, 0, 0);
|
|
logicRet = 0;
|
|
} else {
|
|
compact->o_logic = LOGIC_script;
|
|
logicRet = 1;
|
|
}
|
|
break;
|
|
case LOGIC_speech:
|
|
logicRet = speechDriver(compact);
|
|
break;
|
|
case LOGIC_full_anim:
|
|
logicRet = fullAnimDriver(compact);
|
|
break;
|
|
case LOGIC_anim:
|
|
logicRet = animDriver(compact);
|
|
break;
|
|
|
|
default:
|
|
error("Fatal error: compact %d's logic == %X!", id, compact->o_logic);
|
|
break;
|
|
}
|
|
} while(logicRet);
|
|
}
|
|
|
|
int Logic::logicWaitTalk(Object *compact) {
|
|
Object *target = _objMan->fetchObject(compact->o_down_flag);
|
|
|
|
if (target->o_status & STAT_TALK_WAIT) {
|
|
compact->o_logic = LOGIC_script;
|
|
return 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
int Logic::logicStartTalk(Object *compact) {
|
|
Object *target = _objMan->fetchObject(compact->o_down_flag); //holds id of person we're waiting for
|
|
if (target->o_status & STAT_TALK_WAIT) { //response?
|
|
compact->o_logic = LOGIC_script; //back to script again
|
|
return SCRIPT_CONT;
|
|
}
|
|
if (_eventMan->eventValid(compact->o_down_flag))
|
|
return SCRIPT_STOP; //event still valid - keep waiting
|
|
//the event has gone - so back to script with error code
|
|
compact->o_down_flag = 0;
|
|
compact->o_logic = LOGIC_script;
|
|
return SCRIPT_CONT;
|
|
}
|
|
|
|
int Logic::logicArAnimate(Object *compact, uint32 id) {
|
|
WalkData *route;
|
|
int32 walkPc;
|
|
if ((_scriptVars[GEORGE_WALKING] == 0) && (id == PLAYER))
|
|
_scriptVars[GEORGE_WALKING] = 1;
|
|
|
|
compact->o_resource = compact->o_walk_resource;
|
|
compact->o_status |= STAT_SHRINK;
|
|
route = compact->o_route;
|
|
|
|
walkPc =compact->o_walk_pc;
|
|
compact->o_frame =route[walkPc].frame;
|
|
compact->o_dir =route[walkPc].dir;
|
|
compact->o_xcoord =route[walkPc].x;
|
|
compact->o_ycoord =route[walkPc].y;
|
|
compact->o_anim_x =compact->o_xcoord;
|
|
compact->o_anim_y =compact->o_ycoord;
|
|
|
|
if (((_scriptVars[GEORGE_WALKING] == 2) && (walkPc > 5) && (id == PLAYER) &&
|
|
(route[walkPc - 1].step == 5) && (route[walkPc].step == 0)) ||
|
|
((_scriptVars[GEORGE_WALKING] == 3) && (id == PLAYER))) {
|
|
|
|
compact->o_frame = 96 + compact->o_dir; //reset
|
|
if ((compact->o_dir != 2) && (compact->o_dir != 6)) { // on verticals and diagonals stand where george is
|
|
compact->o_xcoord = route[walkPc - 1].x;
|
|
compact->o_ycoord = route[walkPc - 1].y;
|
|
compact->o_anim_x = compact->o_xcoord;
|
|
compact->o_anim_y = compact->o_ycoord;
|
|
}
|
|
compact->o_logic = LOGIC_script;
|
|
compact->o_down_flag = 0; //0 means error
|
|
_scriptVars[GEORGE_WALKING] = 0;
|
|
route[compact->o_walk_pc+1].frame = 512; //end of sequence
|
|
if (_scriptVars[MEGA_ON_GRID] == 2)
|
|
_scriptVars[MEGA_ON_GRID] = 0;
|
|
}
|
|
compact->o_walk_pc++;
|
|
|
|
if (route[compact->o_walk_pc].frame == 512) //end of sequence
|
|
{
|
|
compact->o_logic = LOGIC_script;
|
|
if (((_scriptVars[GEORGE_WALKING] == 2) || (_scriptVars[GEORGE_WALKING] == 1)) &&
|
|
(id == PLAYER)) {
|
|
_scriptVars[GEORGE_WALKING] = 0;
|
|
if (_scriptVars[MEGA_ON_GRID] == 2)
|
|
_scriptVars[MEGA_ON_GRID] = 0;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int Logic::speechDriver(Object *compact) {
|
|
if ((!_speechClickDelay) && (_mouse->testEvent() & BS1L_BUTTON_DOWN))
|
|
_speechFinished = true;
|
|
if (_speechClickDelay)
|
|
_speechClickDelay--;
|
|
|
|
if (_speechRunning) {
|
|
if (_sound->speechFinished())
|
|
_speechFinished = true;
|
|
} else {
|
|
if (!compact->o_speech_time)
|
|
_speechFinished = true;
|
|
else
|
|
compact->o_speech_time--;
|
|
}
|
|
if (_speechFinished) {
|
|
if (_speechRunning)
|
|
_sound->stopSpeech();
|
|
compact->o_logic = LOGIC_script;
|
|
if (_textRunning) {
|
|
_textMan->releaseText(compact->o_text_id);
|
|
_objMan->fetchObject(compact->o_text_id)->o_status = 0; // kill compact linking text sprite
|
|
}
|
|
_speechRunning = _textRunning = false;
|
|
_speechFinished = true;
|
|
}
|
|
if (compact->o_anim_resource) {
|
|
uint8 *animData = ((uint8*)_resMan->openFetchRes(compact->o_anim_resource)) + sizeof(Header);
|
|
int32 numFrames = READ_LE_UINT32(animData);
|
|
animData += 4;
|
|
compact->o_anim_pc++; // go to next frame of anim
|
|
|
|
if (_speechFinished || (compact->o_anim_pc >= numFrames) ||
|
|
(_speechRunning && (_sound->amISpeaking() == 0)))
|
|
compact->o_anim_pc = 0; //set to frame 0, closed mouth
|
|
|
|
AnimUnit *animPtr = (AnimUnit*)(animData + sizeof(AnimUnit) * compact->o_anim_pc);
|
|
if (!(compact->o_status & STAT_SHRINK)) {
|
|
compact->o_anim_x = FROM_LE_32(animPtr->animX);
|
|
compact->o_anim_y = FROM_LE_32(animPtr->animY);
|
|
}
|
|
compact->o_frame = FROM_LE_32(animPtr->animFrame);
|
|
_resMan->resClose(compact->o_anim_resource);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int Logic::fullAnimDriver(Object *compact) {
|
|
if (compact->o_sync) { // return to script immediately if we've received a sync
|
|
compact->o_logic = LOGIC_script;
|
|
return 1;
|
|
}
|
|
uint8 *data = ((uint8*)_resMan->openFetchRes(compact->o_anim_resource)) + sizeof(Header);
|
|
uint32 numFrames = READ_LE_UINT32(data);
|
|
data += 4;
|
|
AnimUnit *animPtr = (AnimUnit*)(data + compact->o_anim_pc * sizeof(AnimUnit));
|
|
|
|
compact->o_anim_x = compact->o_xcoord = FROM_LE_32(animPtr->animX);
|
|
compact->o_anim_y = compact->o_ycoord = FROM_LE_32(animPtr->animY);
|
|
compact->o_frame = FROM_LE_32(animPtr->animFrame);
|
|
|
|
compact->o_anim_pc++;
|
|
if (compact->o_anim_pc == (int)numFrames)
|
|
compact->o_logic = LOGIC_script;
|
|
|
|
_resMan->resClose(compact->o_anim_resource);
|
|
return 0;
|
|
}
|
|
|
|
int Logic::animDriver(Object *compact) {
|
|
if (compact->o_sync) {
|
|
compact->o_logic = LOGIC_script;
|
|
return 1;
|
|
}
|
|
uint8 *data = ((uint8*)_resMan->openFetchRes(compact->o_anim_resource)) + sizeof(Header);
|
|
uint32 numFrames = READ_LE_UINT32(data);
|
|
AnimUnit *animPtr = (AnimUnit*)(data + 4 + compact->o_anim_pc * sizeof(AnimUnit));
|
|
|
|
if (!(compact->o_status & STAT_SHRINK)) {
|
|
compact->o_anim_x = FROM_LE_32(animPtr->animX);
|
|
compact->o_anim_y = FROM_LE_32(animPtr->animY);
|
|
}
|
|
|
|
compact->o_frame = FROM_LE_32(animPtr->animFrame);
|
|
compact->o_anim_pc++;
|
|
if (compact->o_anim_pc == (int)numFrames)
|
|
compact->o_logic = LOGIC_script;
|
|
|
|
_resMan->resClose(compact->o_anim_resource);
|
|
return 0;
|
|
}
|
|
|
|
void Logic::updateScreenParams(void) {
|
|
Object *compact = (Object*)_objMan->fetchObject(PLAYER);
|
|
_screen->setScrolling((int16)(compact->o_xcoord - _scriptVars[FEET_X]),
|
|
(int16)(compact->o_ycoord - _scriptVars[FEET_Y]));
|
|
}
|
|
|
|
int Logic::scriptManager(Object *compact, uint32 id) {
|
|
int ret;
|
|
do {
|
|
uint32 level = compact->o_tree.o_script_level;
|
|
uint32 script = compact->o_tree.o_script_id[level];
|
|
Debug::interpretScript(id, level, script, compact->o_tree.o_script_pc[level] & ITM_ID);
|
|
ret = interpretScript(compact, id, _resMan->lockScript(script), script, compact->o_tree.o_script_pc[level] & ITM_ID);
|
|
_resMan->unlockScript(script);
|
|
if (!ret) {
|
|
if (compact->o_tree.o_script_level)
|
|
compact->o_tree.o_script_level--;
|
|
else
|
|
error("ScriptManager: basescript %d for cpt %d ended!", script, id);
|
|
} else
|
|
compact->o_tree.o_script_pc[level] = ret;
|
|
} while (!ret);
|
|
return 1;
|
|
//Logic continues - but the script must have changed logic mode
|
|
//this is a radical change from S2.0 where once a script finished there
|
|
//was no more processing for that object on that cycle - the Logic_engine terminated.
|
|
//This meant that new logics that needed immediate action got a first call from the
|
|
//setup function. This was a bit tweeky. This technique ensures that the script is a
|
|
//totally seamless concept that takes up zero cycle time. The only downside is that
|
|
//an FN_quit becomes slightly more convoluted, but so what you might ask.
|
|
}
|
|
|
|
void Logic::runMouseScript(Object *cpt, int32 scriptId) {
|
|
Header *script = _resMan->lockScript(scriptId);
|
|
debug(9, "running mouse script %d", scriptId);
|
|
interpretScript(cpt, _scriptVars[SPECIAL_ITEM], script, scriptId, scriptId);
|
|
_resMan->unlockScript(scriptId);
|
|
}
|
|
|
|
int Logic::interpretScript(Object *compact, int id, Header *scriptModule, int scriptBase, int scriptNum) {
|
|
int32 *scriptCode = (int32*)(((uint8*)scriptModule) + sizeof(Header));
|
|
int32 stack[MAX_STACK_SIZE];
|
|
int32 stackIdx = 0;
|
|
int32 offset;
|
|
int32 pc;
|
|
if (memcmp(scriptModule->type, "Script", 6))
|
|
error("Invalid script module!");
|
|
if (scriptModule->version != SCRIPT_VERSION)
|
|
error("Illegal script version!");
|
|
if (scriptNum < 0)
|
|
error("negative script number");
|
|
if ((uint32)scriptNum >= scriptModule->decomp_length)
|
|
error("Script number out of bounds");
|
|
|
|
if (scriptNum < scriptCode[0])
|
|
pc = scriptCode[scriptNum + 1];
|
|
else
|
|
pc = scriptNum;
|
|
int32 startOfScript = scriptCode[(scriptBase & ITM_ID) + 1];
|
|
|
|
int32 a, b, c, d, e, f;
|
|
int mCodeReturn = 0;
|
|
int32 mCodeNumber = 0, mCodeArguments = 0;
|
|
while (1) {
|
|
assert((stackIdx >= 0) && (stackIdx <= MAX_STACK_SIZE));
|
|
switch (scriptCode[pc++]) {
|
|
case IT_MCODE:
|
|
a = b = c = d = e = f = 0;
|
|
mCodeNumber = scriptCode[pc++];
|
|
mCodeArguments = scriptCode[pc++];
|
|
switch (mCodeArguments) {
|
|
case 6: f = stack[--stackIdx];
|
|
case 5: e = stack[--stackIdx];
|
|
case 4: d = stack[--stackIdx];
|
|
case 3: c = stack[--stackIdx];
|
|
case 2: b = stack[--stackIdx];
|
|
case 1: a = stack[--stackIdx];
|
|
case 0:
|
|
Debug::callMCode(mCodeNumber, mCodeArguments, a, b, c, d, e, f);
|
|
mCodeReturn = (this->*_mcodeTable[mCodeNumber])(compact, id, a, b, c, d, e, f);
|
|
break;
|
|
default:
|
|
warning("mcode[%d]: too many arguments(%d)", mCodeNumber, mCodeArguments);
|
|
}
|
|
if (mCodeReturn == 0)
|
|
return pc;
|
|
break;
|
|
case IT_PUSHNUMBER:
|
|
debug(9, "IT_PUSH: %d", scriptCode[pc]);
|
|
stack[stackIdx++] = scriptCode[pc++];
|
|
break;
|
|
case IT_PUSHVARIABLE:
|
|
debug(9, "IT_PUSHVARIABLE: ScriptVar[%d] => %d", scriptCode[pc], _scriptVars[scriptCode[pc]]);
|
|
stack[stackIdx++] = _scriptVars[scriptCode[pc++]];
|
|
break;
|
|
case IT_NOTEQUAL:
|
|
stackIdx--;
|
|
debug(9, "IT_NOTEQUAL: RESULT = %d", stack[stackIdx - 1] != stack[stackIdx]);
|
|
stack[stackIdx - 1] = (stack[stackIdx - 1] != stack[stackIdx]);
|
|
break;
|
|
case IT_ISEQUAL:
|
|
stackIdx--;
|
|
debug(9, "IT_ISEQUAL: RESULT = %d", stack[stackIdx - 1] == stack[stackIdx]);
|
|
stack[stackIdx - 1] = (stack[stackIdx - 1] == stack[stackIdx]);
|
|
break;
|
|
case IT_PLUS:
|
|
stackIdx--;
|
|
debug(9, "IT_PLUS: RESULT = %d", stack[stackIdx - 1] + stack[stackIdx]);
|
|
stack[stackIdx - 1] = (stack[stackIdx - 1] + stack[stackIdx]);
|
|
break;
|
|
case IT_TIMES:
|
|
stackIdx--;
|
|
debug(9, "IT_TIMES: RESULT = %d", stack[stackIdx - 1] * stack[stackIdx]);
|
|
stack[stackIdx - 1] = (stack[stackIdx - 1] * stack[stackIdx]);
|
|
break;
|
|
case IT_ANDAND:
|
|
stackIdx--;
|
|
debug(9, "IT_ANDAND: RESULT = %d", stack[stackIdx - 1] && stack[stackIdx]);
|
|
stack[stackIdx - 1] = (stack[stackIdx - 1] && stack[stackIdx]);
|
|
break;
|
|
case IT_OROR: // ||
|
|
stackIdx--;
|
|
debug(9, "IT_OROR: RESULT = %d", stack[stackIdx - 1] || stack[stackIdx]);
|
|
stack[stackIdx - 1] = (stack[stackIdx - 1] || stack[stackIdx]);
|
|
break;
|
|
case IT_LESSTHAN:
|
|
stackIdx--;
|
|
debug(9, "IT_LESSTHAN: RESULT = %d", stack[stackIdx - 1] < stack[stackIdx]);
|
|
stack[stackIdx - 1] = (stack[stackIdx - 1] < stack[stackIdx]);
|
|
break;
|
|
case IT_NOT:
|
|
debug(9, "IT_NOT: RESULT = %d", stack[stackIdx - 1] ? 0 : 1);
|
|
if (stack[stackIdx - 1])
|
|
stack[stackIdx - 1] = 0;
|
|
else
|
|
stack[stackIdx - 1] = 1;
|
|
break;
|
|
case IT_MINUS:
|
|
stackIdx--;
|
|
debug(9, "IT_MINUS: RESULT = %d", stack[stackIdx - 1] - stack[stackIdx]);
|
|
stack[stackIdx - 1] = (stack[stackIdx - 1] - stack[stackIdx]);
|
|
break;
|
|
case IT_AND:
|
|
stackIdx--;
|
|
debug(9, "IT_AND: RESULT = %d", stack[stackIdx - 1] & stack[stackIdx]);
|
|
stack[stackIdx - 1] = (stack[stackIdx - 1] & stack[stackIdx]);
|
|
break;
|
|
case IT_OR:
|
|
stackIdx--;
|
|
debug(9, "IT_OR: RESULT = %d", stack[stackIdx - 1] | stack[stackIdx]);
|
|
stack[stackIdx - 1] = (stack[stackIdx - 1] | stack[stackIdx]);
|
|
break;
|
|
case IT_GTE:
|
|
stackIdx--;
|
|
debug(9, "IT_GTE: RESULT = %d", stack[stackIdx - 1] >= stack[stackIdx]);
|
|
stack[stackIdx - 1] = (stack[stackIdx - 1] >= stack[stackIdx]);
|
|
break;
|
|
case IT_LTE:
|
|
stackIdx--;
|
|
debug(9, "IT_LTE: RESULT = %d", stack[stackIdx - 1] <= stack[stackIdx]);
|
|
stack[stackIdx - 1] = (stack[stackIdx - 1] <= stack[stackIdx]);
|
|
break;
|
|
case IT_DEVIDE:
|
|
stackIdx--;
|
|
debug(9, "IT_DEVIDE: RESULT = %d", stack[stackIdx - 1] / stack[stackIdx]);
|
|
stack[stackIdx - 1] = (stack[stackIdx - 1] / stack[stackIdx]);
|
|
break;
|
|
case IT_GT:
|
|
stackIdx--;
|
|
debug(9, "IT_GT: RESULT = %d", stack[stackIdx - 1] > stack[stackIdx]);
|
|
stack[stackIdx - 1] = (stack[stackIdx - 1] > stack[stackIdx]);
|
|
break;
|
|
case IT_SCRIPTEND:
|
|
debug(9, "IT_SCRIPTEND");
|
|
return 0;
|
|
case IT_POPVAR: // pop a variable
|
|
debug(9, "IT_POPVAR: ScriptVars[%d] = %d", scriptCode[pc], stack[stackIdx-1]);
|
|
_scriptVars[scriptCode[pc++]] = stack[--stackIdx];
|
|
break;
|
|
case IT_POPLONGOFFSET:
|
|
offset = scriptCode[pc++];
|
|
debug(9, "IT_POPLONGOFFSET: Cpt[%d] = %d", offset, stack[stackIdx - 1]);
|
|
*((int32 *)((uint8*)compact + offset)) = stack[--stackIdx];
|
|
break;
|
|
case IT_PUSHLONGOFFSET:
|
|
offset = scriptCode[pc++];
|
|
debug(9, "IT_PUSHLONGOFFSET: PUSH Cpt[%d] (==%d)", offset, *((int32 *)((uint8*)compact + offset)));
|
|
stack[stackIdx++] = *((int32 *)((uint8*)compact + offset));
|
|
break;
|
|
case IT_SKIPONFALSE:
|
|
debug(9, "IT_SKIPONFALSE: %d (%s)", scriptCode[pc], (stack[stackIdx-1] ? "IS TRUE (NOT SKIPPED)" : "IS FALSE (SKIPPED)"));
|
|
if (stack[--stackIdx])
|
|
pc++;
|
|
else
|
|
pc += scriptCode[pc];
|
|
break;
|
|
case IT_SKIP:
|
|
debug(9, "IT_SKIP: %d", scriptCode[pc]);
|
|
pc += scriptCode[pc];
|
|
break;
|
|
case IT_SWITCH: // The mega switch statement
|
|
debug(9, "IT_SWITCH: [SORRY, NO DEBUG INFO]");
|
|
{
|
|
int switchValue = stack[--stackIdx];
|
|
int switchCount = scriptCode[pc++];
|
|
int doneSwitch=0;
|
|
|
|
for (int cnt = 0; (cnt < switchCount) && (doneSwitch==0); cnt++) {
|
|
if (switchValue == scriptCode[pc]) {
|
|
pc += scriptCode[pc+1];
|
|
doneSwitch=1;
|
|
} else
|
|
pc += 2;
|
|
|
|
}
|
|
if (doneSwitch == 0)
|
|
pc += scriptCode[pc];
|
|
}
|
|
break;
|
|
case IT_SKIPONTRUE: // skip if expression true
|
|
debug(9, "IT_SKIPONTRUE: %d (%s)", scriptCode[pc], (stack[stackIdx-1] ? "IS TRUE (SKIPPED)" : "IS FALSE (NOT SKIPPED)"));
|
|
stackIdx--;
|
|
if (stack[stackIdx])
|
|
pc += scriptCode[pc];
|
|
else
|
|
pc++;
|
|
break;
|
|
case IT_PRINTF:
|
|
debug(0, "IT_PRINTF(%d)",stack[stackIdx]);
|
|
break;
|
|
case IT_RESTARTSCRIPT:
|
|
debug(9, "IT_RESTARTSCRIPT");
|
|
pc = startOfScript;
|
|
break;
|
|
case IT_POPWORDOFFSET:
|
|
offset = scriptCode[pc++];
|
|
debug(9, "IT_POPWORDOFFSET: Cpt[%d] = %d", offset, stack[stackIdx - 1] & 0xFFFF);
|
|
*((int32 *)((uint8*)compact + offset)) = stack[--stackIdx] & 0xffff;
|
|
break;
|
|
case IT_PUSHWORDOFFSET:
|
|
offset = scriptCode[pc++];
|
|
debug(9, "IT_PUSHWORDOFFSET: PUSH Cpt[%d] == %d", offset, (*((int32 *)((uint8*)compact + offset))) & 0xffff);
|
|
stack[stackIdx++] = (*((int32 *)((uint8*)compact + offset))) & 0xffff;
|
|
break;
|
|
default:
|
|
error("Invalid operator %d",scriptCode[pc-1]);
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
BSMcodeTable Logic::_mcodeTable[100] = {
|
|
&Logic::fnBackground,
|
|
&Logic::fnForeground,
|
|
&Logic::fnSort,
|
|
&Logic::fnNoSprite,
|
|
&Logic::fnMegaSet,
|
|
&Logic::fnAnim,
|
|
&Logic::fnSetFrame,
|
|
&Logic::fnFullAnim,
|
|
&Logic::fnFullSetFrame,
|
|
&Logic::fnFadeDown,
|
|
&Logic::fnFadeUp,
|
|
&Logic::fnCheckFade,
|
|
&Logic::fnSetSpritePalette,
|
|
&Logic::fnSetWholePalette,
|
|
&Logic::fnSetFadeTargetPalette,
|
|
&Logic::fnSetPaletteToFade,
|
|
&Logic::fnSetPaletteToCut,
|
|
&Logic::fnPlaySequence,
|
|
&Logic::fnIdle,
|
|
&Logic::fnPause,
|
|
&Logic::fnPauseSeconds,
|
|
&Logic::fnQuit,
|
|
&Logic::fnKillId,
|
|
&Logic::fnSuicide,
|
|
&Logic::fnNewScript,
|
|
&Logic::fnSubScript,
|
|
&Logic::fnRestartScript,
|
|
&Logic::fnSetBookmark,
|
|
&Logic::fnGotoBookmark,
|
|
&Logic::fnSendSync,
|
|
&Logic::fnWaitSync,
|
|
&Logic::cfnClickInteract,
|
|
&Logic::cfnSetScript,
|
|
&Logic::cfnPresetScript,
|
|
&Logic::fnInteract,
|
|
&Logic::fnIssueEvent,
|
|
&Logic::fnCheckForEvent,
|
|
&Logic::fnWipeHands,
|
|
&Logic::fnISpeak,
|
|
&Logic::fnTheyDo,
|
|
&Logic::fnTheyDoWeWait,
|
|
&Logic::fnWeWait,
|
|
&Logic::fnChangeSpeechText,
|
|
&Logic::fnTalkError,
|
|
&Logic::fnStartTalk,
|
|
&Logic::fnCheckForTextLine,
|
|
&Logic::fnAddTalkWaitStatusBit,
|
|
&Logic::fnRemoveTalkWaitStatusBit,
|
|
&Logic::fnNoHuman,
|
|
&Logic::fnAddHuman,
|
|
&Logic::fnBlankMouse,
|
|
&Logic::fnNormalMouse,
|
|
&Logic::fnLockMouse,
|
|
&Logic::fnUnlockMouse,
|
|
&Logic::fnSetMousePointer,
|
|
&Logic::fnSetMouseLuggage,
|
|
&Logic::fnMouseOn,
|
|
&Logic::fnMouseOff,
|
|
&Logic::fnChooser,
|
|
&Logic::fnEndChooser,
|
|
&Logic::fnStartMenu,
|
|
&Logic::fnEndMenu,
|
|
&Logic::cfnReleaseMenu,
|
|
&Logic::fnAddSubject,
|
|
&Logic::fnAddObject,
|
|
&Logic::fnRemoveObject,
|
|
&Logic::fnEnterSection,
|
|
&Logic::fnLeaveSection,
|
|
&Logic::fnChangeFloor,
|
|
&Logic::fnWalk,
|
|
&Logic::fnTurn,
|
|
&Logic::fnStand,
|
|
&Logic::fnStandAt,
|
|
&Logic::fnFace,
|
|
&Logic::fnFaceXy,
|
|
&Logic::fnIsFacing,
|
|
&Logic::fnGetTo,
|
|
&Logic::fnGetToError,
|
|
&Logic::fnGetPos,
|
|
&Logic::fnGetGamepadXy,
|
|
&Logic::fnPlayFx,
|
|
&Logic::fnStopFx,
|
|
&Logic::fnPlayMusic,
|
|
&Logic::fnStopMusic,
|
|
&Logic::fnInnerSpace,
|
|
&Logic::fnRandom,
|
|
&Logic::fnSetScreen,
|
|
&Logic::fnPreload,
|
|
&Logic::fnCheckCD,
|
|
&Logic::fnRestartGame,
|
|
&Logic::fnQuitGame,
|
|
&Logic::fnDeathScreen,
|
|
&Logic::fnSetParallax,
|
|
&Logic::fnTdebug,
|
|
&Logic::fnRedFlash,
|
|
&Logic::fnBlueFlash,
|
|
&Logic::fnYellow,
|
|
&Logic::fnGreen,
|
|
&Logic::fnPurple,
|
|
&Logic::fnBlack
|
|
};
|
|
|
|
int Logic::fnBackground(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
|
|
|
|
cpt->o_status &= ~(STAT_FORE | STAT_SORT);
|
|
cpt->o_status |= STAT_BACK;
|
|
return SCRIPT_CONT;
|
|
}
|
|
|
|
int Logic::fnForeground(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
|
|
cpt->o_status &= ~(STAT_BACK | STAT_SORT);
|
|
cpt->o_status |= STAT_FORE;
|
|
return SCRIPT_CONT;
|
|
}
|
|
|
|
int Logic::fnSort(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
|
|
cpt->o_status &= ~(STAT_BACK | STAT_FORE);
|
|
cpt->o_status |= STAT_SORT;
|
|
return SCRIPT_CONT;
|
|
}
|
|
|
|
int Logic::fnNoSprite(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
|
|
cpt->o_status &= ~(STAT_BACK | STAT_FORE | STAT_SORT);
|
|
return SCRIPT_CONT;
|
|
}
|
|
|
|
int Logic::fnMegaSet(Object *cpt, int32 id, int32 walk_data, int32 spr, int32 e, int32 f, int32 z, int32 x) {
|
|
cpt->o_mega_resource = walk_data;
|
|
cpt->o_walk_resource = spr;
|
|
return SCRIPT_CONT;
|
|
}
|
|
|
|
int Logic::fnAnim(Object *cpt, int32 id, int32 cdt, int32 spr, int32 e, int32 f, int32 z, int32 x) {
|
|
AnimSet *animTab;
|
|
|
|
if (cdt && (!spr)) {
|
|
animTab = (AnimSet*)((uint8*)_resMan->openFetchRes(cdt) + sizeof(Header));
|
|
animTab += cpt->o_dir;
|
|
|
|
cpt->o_anim_resource = FROM_LE_32(animTab->cdt);
|
|
cpt->o_resource = FROM_LE_32(animTab->spr);
|
|
_resMan->resClose(cdt);
|
|
} else {
|
|
cpt->o_anim_resource = cdt;
|
|
cpt->o_resource = spr;
|
|
}
|
|
if ((cpt->o_anim_resource == 0) || (cpt->o_resource == 0))
|
|
error("fnAnim called width (%d/%d) => (%d/%d)", cdt, spr, cpt->o_anim_resource, cpt->o_resource);
|
|
|
|
FrameHeader *frameHead = _resMan->fetchFrame(_resMan->openFetchRes(cpt->o_resource), 0);
|
|
if (frameHead->offsetX || frameHead->offsetY) { // boxed mega anim?
|
|
cpt->o_status |= STAT_SHRINK;
|
|
cpt->o_anim_x = cpt->o_xcoord; // set anim coords to 'feet' coords - only need to do this once
|
|
cpt->o_anim_y = cpt->o_ycoord;
|
|
} else {
|
|
// Anim_driver sets anim coords to cdt coords for every frame of a loose anim
|
|
cpt->o_status &= ~STAT_SHRINK;
|
|
}
|
|
_resMan->resClose(cpt->o_resource);
|
|
|
|
cpt->o_logic = LOGIC_anim;
|
|
cpt->o_anim_pc = 0;
|
|
cpt->o_sync = 0;
|
|
return SCRIPT_STOP;
|
|
}
|
|
|
|
int Logic::fnSetFrame(Object *cpt, int32 id, int32 cdt, int32 spr, int32 frameNo, int32 f, int32 z, int32 x) {
|
|
|
|
AnimUnit *animPtr;
|
|
|
|
uint8 *data = (uint8*)_resMan->openFetchRes(cdt);
|
|
data += sizeof(Header);
|
|
if (frameNo == LAST_FRAME)
|
|
frameNo = READ_LE_UINT32(data) - 1;
|
|
|
|
data += 4;
|
|
animPtr = (AnimUnit*)(data + frameNo * sizeof(AnimUnit));
|
|
|
|
cpt->o_anim_x = FROM_LE_32(animPtr->animX);
|
|
cpt->o_anim_y = FROM_LE_32(animPtr->animY);
|
|
cpt->o_frame = FROM_LE_32(animPtr->animFrame);
|
|
|
|
cpt->o_resource = spr;
|
|
cpt->o_status &= ~STAT_SHRINK;
|
|
_resMan->resClose(cdt);
|
|
return SCRIPT_CONT;
|
|
}
|
|
|
|
int Logic::fnFullAnim(Object *cpt, int32 id, int32 anim, int32 graphic, int32 e, int32 f, int32 z, int32 x) {
|
|
cpt->o_logic = LOGIC_full_anim;
|
|
|
|
cpt->o_anim_pc = 0;
|
|
cpt->o_anim_resource = anim;
|
|
cpt->o_resource = graphic;
|
|
cpt->o_status &= ~STAT_SHRINK;
|
|
cpt->o_sync = 0;
|
|
return SCRIPT_STOP;
|
|
}
|
|
|
|
int Logic::fnFullSetFrame(Object *cpt, int32 id, int32 cdt, int32 spr, int32 frameNo, int32 f, int32 z, int32 x) {
|
|
uint8 *data = (uint8*)_resMan->openFetchRes(cdt) + sizeof(Header);
|
|
|
|
if (frameNo == LAST_FRAME)
|
|
frameNo = READ_LE_UINT32(data) - 1;
|
|
data += 4;
|
|
|
|
AnimUnit *animPtr = (AnimUnit*)(data + sizeof(AnimUnit) * frameNo);
|
|
cpt->o_anim_x = cpt->o_xcoord = FROM_LE_32(animPtr->animX);
|
|
cpt->o_anim_y = cpt->o_ycoord = FROM_LE_32(animPtr->animY);
|
|
cpt->o_frame = FROM_LE_32(animPtr->animFrame);
|
|
|
|
cpt->o_resource = spr;
|
|
cpt->o_status &= ~STAT_SHRINK;
|
|
|
|
_resMan->resClose(cdt);
|
|
return SCRIPT_CONT;
|
|
}
|
|
|
|
int Logic::fnFadeDown(Object *cpt, int32 id, int32 speed, int32 d, int32 e, int32 f, int32 z, int32 x) {
|
|
_screen->fadeDownPalette();
|
|
return SCRIPT_CONT;
|
|
}
|
|
|
|
int Logic::fnFadeUp(Object *cpt, int32 id, int32 speed, int32 d, int32 e, int32 f, int32 z, int32 x) {
|
|
_screen->fadeUpPalette();
|
|
return SCRIPT_CONT;
|
|
}
|
|
|
|
int Logic::fnCheckFade(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
|
|
_scriptVars[RETURN_VALUE] = (uint8)_screen->stillFading();
|
|
return SCRIPT_CONT;
|
|
}
|
|
|
|
int Logic::fnSetSpritePalette(Object *cpt, int32 id, int32 spritePal, int32 d, int32 e, int32 f, int32 z, int32 x) {
|
|
_screen->fnSetPalette(184, 72, spritePal, false);
|
|
return SCRIPT_CONT;
|
|
}
|
|
|
|
int Logic::fnSetWholePalette(Object *cpt, int32 id, int32 spritePal, int32 d, int32 e, int32 f, int32 z, int32 x) {
|
|
_screen->fnSetPalette(0, 256, spritePal, false);
|
|
return SCRIPT_CONT;
|
|
}
|
|
|
|
int Logic::fnSetFadeTargetPalette(Object *cpt, int32 id, int32 spritePal, int32 d, int32 e, int32 f, int32 z, int32 x) {
|
|
_screen->fnSetPalette(0, 184, spritePal, true);
|
|
return SCRIPT_CONT;
|
|
}
|
|
|
|
int Logic::fnSetPaletteToFade(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
|
|
SwordEngine::_systemVars.wantFade = true;
|
|
return SCRIPT_CONT;
|
|
}
|
|
|
|
int Logic::fnSetPaletteToCut(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
|
|
SwordEngine::_systemVars.wantFade = false;
|
|
return SCRIPT_CONT;
|
|
}
|
|
|
|
int Logic::fnPlaySequence(Object *cpt, int32 id, int32 sequenceId, int32 d, int32 e, int32 f, int32 z, int32 x) {
|
|
|
|
static const char *sequence_list[20] = {
|
|
"ferrari", // 0 CD2 ferrari running down fitz in sc19
|
|
"ladder", // 1 CD2 george walking down ladder to dig sc24->sc$
|
|
"steps", // 2 CD2 george walking down steps sc23->sc24
|
|
"sewer", // 3 CD1 george entering sewer sc2->sc6
|
|
"intro", // 4 CD1 intro sequence ->sc1
|
|
"river", // 5 CD1 george being thrown into river by flap & g$
|
|
"truck", // 6 CD2 truck arriving at bull's head sc45->sc53/4
|
|
"grave", // 7 BOTH george's grave in scotland, from sc73 + from sc38 $
|
|
"montfcon", // 8 CD2 monfaucon clue in ireland dig, sc25
|
|
"tapestry", // 9 CD2 tapestry room beyond spain well, sc61
|
|
"ireland", // 10 CD2 ireland establishing shot europe_map->sc19
|
|
"finale", // 11 CD2 grand finale at very end, from sc73
|
|
"history", // 12 CD1 George's history lesson from Nico, in sc10
|
|
"spanish", // 13 CD2 establishing shot for 1st visit to Spain, europe_m$
|
|
"well", // 14 CD2 first time being lowered down well in Spai$
|
|
"candle", // 15 CD2 Candle burning down in Spain mausoleum sc59
|
|
"geodrop", // 16 CD2 from sc54, George jumping down onto truck
|
|
"vulture", // 17 CD2 from sc54, vultures circling George's dead body
|
|
"enddemo", // 18 --- for end of single CD demo
|
|
"credits", // 19 CD2 credits, to follow "finale" sequence
|
|
// etc.
|
|
};
|
|
|
|
MoviePlayer player(_screen, _mixer, _system);
|
|
|
|
player.play(sequence_list[sequenceId]);
|
|
|
|
//_scriptVars[NEW_PALETTE] = 1;
|
|
/* the logic usually calls fnFadeDown before playing the sequence, so we have to
|
|
set NEW_PALETTE now to force a palette refresh */
|
|
return SCRIPT_CONT;
|
|
}
|
|
|
|
int Logic::fnIdle(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
|
|
cpt->o_tree.o_script_level = 0; // force to level 0
|
|
cpt->o_logic = LOGIC_idle;
|
|
return SCRIPT_STOP;
|
|
}
|
|
|
|
int Logic::fnPause(Object *cpt, int32 id, int32 pause, int32 d, int32 e, int32 f, int32 z, int32 x) {
|
|
cpt->o_pause = pause;
|
|
cpt->o_logic = LOGIC_pause;
|
|
return SCRIPT_STOP;
|
|
}
|
|
|
|
int Logic::fnPauseSeconds(Object *cpt, int32 id, int32 pause, int32 d, int32 e, int32 f, int32 z, int32 x) {
|
|
cpt->o_pause = pause * FRAME_RATE;
|
|
cpt->o_logic = LOGIC_pause;
|
|
return SCRIPT_STOP;
|
|
}
|
|
|
|
int Logic::fnQuit(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
|
|
cpt->o_logic = LOGIC_quit;
|
|
return SCRIPT_STOP;
|
|
}
|
|
|
|
int Logic::fnKillId(Object *cpt, int32 id, int32 target, int32 d, int32 e, int32 f, int32 z, int32 x) {
|
|
Object *targetObj = _objMan->fetchObject(target);
|
|
targetObj->o_status = 0;
|
|
return SCRIPT_CONT;
|
|
}
|
|
|
|
int Logic::fnSuicide(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
|
|
cpt->o_status = 0;
|
|
cpt->o_logic = LOGIC_quit;
|
|
return SCRIPT_STOP;
|
|
}
|
|
|
|
int Logic::fnNewScript(Object *cpt, int32 id, int32 script, int32 d, int32 e, int32 f, int32 z, int32 x) {
|
|
cpt->o_logic = LOGIC_new_script;
|
|
_newScript = script;
|
|
return SCRIPT_STOP;
|
|
}
|
|
|
|
int Logic::fnSubScript(Object *cpt, int32 id, int32 script, int32 d, int32 e, int32 f, int32 z, int32 x) {
|
|
cpt->o_tree.o_script_level++;
|
|
if (cpt->o_tree.o_script_level == TOTAL_script_levels)
|
|
error("Compact %d: script level exceeded in fnSubScript.", id);
|
|
cpt->o_tree.o_script_pc[cpt->o_tree.o_script_level] = script;
|
|
cpt->o_tree.o_script_id[cpt->o_tree.o_script_level] = script;
|
|
return SCRIPT_STOP;
|
|
}
|
|
|
|
int Logic::fnRestartScript(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
|
|
cpt->o_logic = LOGIC_restart;
|
|
return SCRIPT_STOP;
|
|
}
|
|
|
|
int Logic::fnSetBookmark(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
|
|
memcpy(&cpt->o_bookmark.o_script_level, &cpt->o_tree.o_script_level, sizeof(ScriptTree));
|
|
return SCRIPT_CONT;
|
|
}
|
|
|
|
int Logic::fnGotoBookmark(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
|
|
cpt->o_logic = LOGIC_bookmark;
|
|
return SCRIPT_STOP;
|
|
}
|
|
|
|
int Logic::fnSendSync(Object *cpt, int32 id, int32 sendId, int32 syncValue, int32 e, int32 f, int32 z, int32 x) {
|
|
Object *target = _objMan->fetchObject(sendId);
|
|
target->o_sync = syncValue;
|
|
return SCRIPT_CONT;
|
|
}
|
|
|
|
int Logic::fnWaitSync(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
|
|
cpt->o_logic = LOGIC_wait_for_sync;
|
|
return SCRIPT_STOP;
|
|
}
|
|
|
|
int Logic::cfnClickInteract(Object *cpt, int32 id, int32 target, int32 d, int32 e, int32 f, int32 z, int32 x) {
|
|
Object *tar = _objMan->fetchObject(target);
|
|
cpt = _objMan->fetchObject(PLAYER);
|
|
cpt->o_tree.o_script_level = 0;
|
|
cpt->o_tree.o_script_pc[0] = tar->o_interact;
|
|
cpt->o_tree.o_script_id[0] = tar->o_interact;
|
|
cpt->o_logic = LOGIC_script;
|
|
return SCRIPT_STOP;
|
|
}
|
|
|
|
int Logic::cfnSetScript(Object *cpt, int32 id, int32 target, int32 script, int32 e, int32 f, int32 z, int32 x) {
|
|
Object *tar = _objMan->fetchObject(target);
|
|
tar->o_tree.o_script_level = 0;
|
|
tar->o_tree.o_script_pc[0] = script;
|
|
tar->o_tree.o_script_id[0] = script;
|
|
tar->o_logic = LOGIC_script;
|
|
return SCRIPT_CONT;
|
|
}
|
|
|
|
int Logic::cfnPresetScript(Object *cpt, int32 id, int32 target, int32 script, int32 e, int32 f, int32 z, int32 x) {
|
|
Object *tar = _objMan->fetchObject(target);
|
|
tar->o_tree.o_script_level = 0;
|
|
tar->o_tree.o_script_pc[0] = script;
|
|
tar->o_tree.o_script_id[0] = script;
|
|
if (tar->o_logic == LOGIC_idle)
|
|
tar->o_logic = LOGIC_script;
|
|
return SCRIPT_CONT;
|
|
}
|
|
|
|
int Logic::fnInteract(Object *cpt, int32 id, int32 target, int32 d, int32 e, int32 f, int32 z, int32 x) {
|
|
Object *tar = _objMan->fetchObject(target);
|
|
cpt->o_place = tar->o_place;
|
|
|
|
Object *floorObject = _objMan->fetchObject(tar->o_place);
|
|
cpt->o_scale_a = floorObject->o_scale_a;
|
|
cpt->o_scale_b = floorObject->o_scale_b;
|
|
|
|
cpt->o_tree.o_script_level++;
|
|
cpt->o_tree.o_script_pc[cpt->o_tree.o_script_level] = tar->o_interact;
|
|
cpt->o_tree.o_script_id[cpt->o_tree.o_script_level] = tar->o_interact;
|
|
|
|
return SCRIPT_STOP;
|
|
}
|
|
|
|
int Logic::fnIssueEvent(Object *cpt, int32 id, int32 event, int32 delay, int32 e, int32 f, int32 z, int32 x) {
|
|
_eventMan->fnIssueEvent(cpt, id, event, delay);
|
|
return SCRIPT_CONT;
|
|
}
|
|
|
|
int Logic::fnCheckForEvent(Object *cpt, int32 id, int32 pause, int32 d, int32 e, int32 f, int32 z, int32 x) {
|
|
return _eventMan->fnCheckForEvent(cpt, id, pause);
|
|
}
|
|
|
|
int Logic::fnWipeHands(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
|
|
_scriptVars[OBJECT_HELD] = 0;
|
|
_mouse->setLuggage(0, 0);
|
|
_menu->refresh(MENU_TOP);
|
|
return SCRIPT_CONT;
|
|
}
|
|
|
|
int Logic::fnISpeak(Object *cpt, int32 id, int32 cdt, int32 textNo, int32 spr, int32 f, int32 z, int32 x) {
|
|
_speechClickDelay = 3;
|
|
if (((textNo & ~1) == 0x3f0012) && (!cdt) && (!spr)) {
|
|
cdt = GEOSTDLCDT; // workaround for missing animation when examining
|
|
spr = GEOSTDL; // the conductor on the train roof
|
|
}
|
|
cpt->o_logic = LOGIC_speech;
|
|
|
|
// first setup the talk animation
|
|
if (cdt && (!spr)) { // if 'cdt' is non-zero but 'spr' is zero - 'cdt' is an anim table tag
|
|
AnimSet *animTab = (AnimSet*)((uint8*)_resMan->openFetchRes(cdt) + sizeof(Header));
|
|
animTab += cpt->o_dir;
|
|
|
|
cpt->o_anim_resource = FROM_LE_32(animTab->cdt);
|
|
if (animTab->cdt)
|
|
cpt->o_resource = FROM_LE_32(animTab->spr);
|
|
_resMan->resClose(cdt);
|
|
} else {
|
|
cpt->o_anim_resource = cdt;
|
|
if (cdt)
|
|
cpt->o_resource = spr;
|
|
}
|
|
cpt->o_anim_pc = 0; // start anim from first frame
|
|
if (cpt->o_anim_resource) {
|
|
if (!cpt->o_resource)
|
|
error("ID %d: Can't run anim with cdt=%d, spr=%d", id, cdt, spr);
|
|
|
|
FrameHeader *frameHead = _resMan->fetchFrame(_resMan->openFetchRes(cpt->o_resource), 0);
|
|
if (frameHead->offsetX && frameHead->offsetY) { // is this a boxed mega?
|
|
cpt->o_status |= STAT_SHRINK;
|
|
cpt->o_anim_x = cpt->o_xcoord;
|
|
cpt->o_anim_y = cpt->o_ycoord;
|
|
} else
|
|
cpt->o_status &= ~STAT_SHRINK;
|
|
|
|
_resMan->resClose(cpt->o_resource);
|
|
}
|
|
if (SwordEngine::_systemVars.playSpeech)
|
|
_speechRunning = _sound->startSpeech(textNo >> 16, textNo & 0xFFFF);
|
|
else
|
|
_speechRunning = false;
|
|
_speechFinished = false;
|
|
if (SwordEngine::_systemVars.showText || (!_speechRunning)) {
|
|
_textRunning = true;
|
|
|
|
char *text = _objMan->lockText(textNo);
|
|
cpt->o_speech_time = strlen(text) + 5;
|
|
uint32 textCptId = _textMan->lowTextManager((uint8*)text, cpt->o_speech_width, (uint8)cpt->o_speech_pen);
|
|
_objMan->unlockText(textNo);
|
|
|
|
Object * textCpt = _objMan->fetchObject(textCptId);
|
|
textCpt->o_screen = cpt->o_screen;
|
|
textCpt->o_target = textCptId;
|
|
|
|
// the graphic is a property of Text, so we don't lock/unlock it.
|
|
uint16 textSpriteWidth = FROM_LE_16(_textMan->giveSpriteData(textCpt->o_target)->width);
|
|
uint16 textSpriteHeight = FROM_LE_16(_textMan->giveSpriteData(textCpt->o_target)->height);
|
|
|
|
cpt->o_text_id = textCptId;
|
|
|
|
// now set text coords, above the player, usually
|
|
|
|
#define TEXT_MARGIN 3 // distance kept from edges of screen
|
|
#define ABOVE_HEAD 20 // distance kept above talking sprite
|
|
uint16 textX, textY;
|
|
if (((id == GEORGE) || ((id == NICO) && (_scriptVars[SCREEN] == 10))) && (!cpt->o_anim_resource)) {
|
|
// if George is doing Voice-Over text (centered at the bottom of the screen)
|
|
textX = _scriptVars[SCROLL_OFFSET_X] + 128 + (640 / 2) - textSpriteWidth / 2;
|
|
textY = _scriptVars[SCROLL_OFFSET_Y] + 128 + 400;
|
|
} else {
|
|
if ((id == GEORGE) && (_scriptVars[SCREEN] == 79))
|
|
textX = cpt->o_mouse_x2; // move it off george's head
|
|
else
|
|
textX = (cpt->o_mouse_x1 + cpt->o_mouse_x2) / 2 - textSpriteWidth / 2;
|
|
|
|
textY = cpt->o_mouse_y1 - textSpriteHeight - ABOVE_HEAD;
|
|
}
|
|
// now ensure text is within visible screen
|
|
uint16 textLeftMargin, textRightMargin, textTopMargin, textBottomMargin;
|
|
textLeftMargin = SCREEN_LEFT_EDGE + TEXT_MARGIN + _scriptVars[SCROLL_OFFSET_X];
|
|
textRightMargin = SCREEN_RIGHT_EDGE - TEXT_MARGIN + _scriptVars[SCROLL_OFFSET_X] - textSpriteWidth;
|
|
textTopMargin = SCREEN_TOP_EDGE + TEXT_MARGIN + _scriptVars[SCROLL_OFFSET_Y];
|
|
textBottomMargin = SCREEN_BOTTOM_EDGE - TEXT_MARGIN + _scriptVars[SCROLL_OFFSET_Y] - textSpriteHeight;
|
|
|
|
textCpt->o_anim_x = textCpt->o_xcoord = inRange(textLeftMargin, textX, textRightMargin);
|
|
textCpt->o_anim_y = textCpt->o_ycoord = inRange(textTopMargin, textY, textBottomMargin);
|
|
}
|
|
return SCRIPT_STOP;
|
|
}
|
|
|
|
//send instructions to mega in conversation with player
|
|
//the instruction is interpreted by the script mega_interact
|
|
int Logic::fnTheyDo(Object *cpt, int32 id, int32 tar, int32 instruc, int32 param1, int32 param2, int32 param3, int32 x) {
|
|
Object *target;
|
|
target = _objMan->fetchObject(tar);
|
|
target->o_down_flag = instruc; // instruction for the mega
|
|
target->o_ins1 = param1;
|
|
target->o_ins2 = param2;
|
|
target->o_ins3 = param3;
|
|
return SCRIPT_CONT;
|
|
}
|
|
|
|
//send an instruction to mega we're talking to and wait
|
|
//until it has finished before returning to script
|
|
int Logic::fnTheyDoWeWait(Object *cpt, int32 id, int32 tar, int32 instruc, int32 param1, int32 param2, int32 param3, int32 x) {
|
|
Object *target;
|
|
target = _objMan->fetchObject(tar);
|
|
target->o_down_flag = instruc; // instruction for the mega
|
|
target->o_ins1 = param1;
|
|
target->o_ins2 = param2;
|
|
target->o_ins3 = param3;
|
|
target->o_status &= ~STAT_TALK_WAIT;
|
|
|
|
cpt->o_logic = LOGIC_wait_for_talk;
|
|
cpt->o_down_flag = tar;
|
|
return SCRIPT_STOP;
|
|
}
|
|
|
|
int Logic::fnWeWait(Object *cpt, int32 id, int32 tar, int32 d, int32 e, int32 f, int32 z, int32 x) {
|
|
Object *target = _objMan->fetchObject(tar);
|
|
target->o_status &= ~STAT_TALK_WAIT;
|
|
|
|
cpt->o_logic = LOGIC_wait_for_talk;
|
|
cpt->o_down_flag = tar;
|
|
|
|
return SCRIPT_STOP;
|
|
}
|
|
|
|
int Logic::fnChangeSpeechText(Object *cpt, int32 id, int32 tar, int32 width, int32 pen, int32 f, int32 z, int32 x) {
|
|
Object *target = _objMan->fetchObject(tar);
|
|
target->o_speech_width = width;
|
|
target->o_speech_pen = pen;
|
|
return SCRIPT_STOP;
|
|
}
|
|
|
|
//mega_interact has received an instruction it does not understand -
|
|
//The game is halted for debugging. Maybe we'll remove this later.
|
|
int Logic::fnTalkError(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
|
|
error("fnTalkError for id %d, instruction %d", id, cpt->o_down_flag);
|
|
return SCRIPT_STOP;
|
|
}
|
|
|
|
int Logic::fnStartTalk(Object *cpt, int32 id, int32 target, int32 d, int32 e, int32 f, int32 z, int32 x) {
|
|
cpt->o_down_flag = target;
|
|
cpt->o_logic = LOGIC_start_talk;
|
|
return SCRIPT_STOP;
|
|
}
|
|
|
|
int Logic::fnCheckForTextLine(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
|
|
_scriptVars[RETURN_VALUE] = _objMan->fnCheckForTextLine(id);
|
|
return SCRIPT_CONT;
|
|
}
|
|
|
|
int Logic::fnAddTalkWaitStatusBit(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
|
|
cpt->o_status |= STAT_TALK_WAIT;
|
|
return SCRIPT_CONT;
|
|
}
|
|
|
|
int Logic::fnRemoveTalkWaitStatusBit(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
|
|
cpt->o_status &= ~STAT_TALK_WAIT;
|
|
return SCRIPT_CONT;
|
|
}
|
|
|
|
int Logic::fnNoHuman(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
|
|
_mouse->fnNoHuman();
|
|
return SCRIPT_CONT;
|
|
}
|
|
|
|
int Logic::fnAddHuman(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
|
|
_mouse->fnAddHuman();
|
|
return SCRIPT_CONT;
|
|
}
|
|
|
|
int Logic::fnBlankMouse(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
|
|
_mouse->fnBlankMouse();
|
|
return SCRIPT_CONT;
|
|
}
|
|
|
|
int Logic::fnNormalMouse(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
|
|
_mouse->fnNormalMouse();
|
|
return SCRIPT_CONT;
|
|
}
|
|
|
|
int Logic::fnLockMouse(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
|
|
_mouse->fnLockMouse();
|
|
return SCRIPT_CONT;
|
|
}
|
|
|
|
int Logic::fnUnlockMouse(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
|
|
_mouse->fnUnlockMouse();
|
|
return SCRIPT_CONT;
|
|
}
|
|
|
|
int Logic::fnSetMousePointer(Object *cpt, int32 id, int32 tag, int32 rate, int32 e, int32 f, int32 z, int32 x) {
|
|
_mouse->setPointer(tag, rate);
|
|
return SCRIPT_CONT;
|
|
}
|
|
|
|
int Logic::fnSetMouseLuggage(Object *cpt, int32 id, int32 tag, int32 rate, int32 e, int32 f, int32 z, int32 x) {
|
|
_mouse->setLuggage(tag, rate);
|
|
return SCRIPT_CONT;
|
|
}
|
|
|
|
int Logic::fnMouseOn(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
|
|
cpt->o_status |= STAT_MOUSE;
|
|
return SCRIPT_CONT;
|
|
}
|
|
|
|
int Logic::fnMouseOff(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
|
|
cpt->o_status &= ~STAT_MOUSE;
|
|
return SCRIPT_CONT;
|
|
}
|
|
|
|
int Logic::fnChooser(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
|
|
_menu->fnChooser(cpt);
|
|
return SCRIPT_STOP;
|
|
}
|
|
|
|
int Logic::fnEndChooser(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
|
|
_menu->fnEndChooser();
|
|
return SCRIPT_CONT;
|
|
}
|
|
|
|
int Logic::fnStartMenu(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
|
|
_menu->fnStartMenu();
|
|
return SCRIPT_CONT;
|
|
}
|
|
|
|
int Logic::fnEndMenu(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
|
|
_menu->fnEndMenu();
|
|
return SCRIPT_CONT;
|
|
}
|
|
|
|
int Logic::cfnReleaseMenu(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
|
|
_menu->cfnReleaseMenu();
|
|
return SCRIPT_STOP;
|
|
}
|
|
|
|
int Logic::fnAddSubject(Object *cpt, int32 id, int32 sub, int32 d, int32 e, int32 f, int32 z, int32 x) {
|
|
_menu->fnAddSubject(sub);
|
|
return SCRIPT_CONT;
|
|
}
|
|
|
|
int Logic::fnAddObject(Object *cpt, int32 id, int32 objectNo, int32 d, int32 e, int32 f, int32 z, int32 x) {
|
|
_scriptVars[POCKET_1 + objectNo - 1] = 1; // basically means: carrying object objectNo = true;
|
|
return SCRIPT_CONT;
|
|
}
|
|
|
|
int Logic::fnRemoveObject(Object *cpt, int32 id, int32 objectNo, int32 d, int32 e, int32 f, int32 z, int32 x) {
|
|
_scriptVars[POCKET_1 + objectNo - 1] = 0;
|
|
return SCRIPT_CONT;
|
|
}
|
|
|
|
int Logic::fnEnterSection(Object *cpt, int32 id, int32 screen, int32 d, int32 e, int32 f, int32 z, int32 x) {
|
|
if (screen >= TOTAL_SECTIONS)
|
|
error("mega %d tried entering section %d", id, screen);
|
|
|
|
/* if (cpt->o_type == TYPE_PLAYER)
|
|
^= this was the original condition from the game sourcecode.
|
|
not sure why it doesn't work*/
|
|
if (id == PLAYER)
|
|
_scriptVars[NEW_SCREEN] = screen;
|
|
else
|
|
cpt->o_screen = screen; // move the mega
|
|
_objMan->megaEntering(screen);
|
|
return SCRIPT_CONT;
|
|
}
|
|
|
|
int Logic::fnLeaveSection(Object *cpt, int32 id, int32 oldScreen, int32 d, int32 e, int32 f, int32 z, int32 x) {
|
|
if (oldScreen >= TOTAL_SECTIONS)
|
|
error("mega %d leaving section %d", id, oldScreen);
|
|
_objMan->megaLeaving(oldScreen, id);
|
|
return SCRIPT_CONT;
|
|
}
|
|
|
|
int Logic::fnChangeFloor(Object *cpt, int32 id, int32 floor, int32 d, int32 e, int32 f, int32 z, int32 x) {
|
|
cpt->o_place = floor;
|
|
Object *floorCpt = _objMan->fetchObject(floor);
|
|
cpt->o_scale_a = floorCpt->o_scale_a;
|
|
cpt->o_scale_b = floorCpt->o_scale_b;
|
|
return SCRIPT_CONT;
|
|
}
|
|
|
|
int Logic::fnWalk(Object *cpt, int32 id, int32 x, int32 y, int32 dir, int32 stance, int32 a, int32 b) {
|
|
if (stance > 0)
|
|
dir = 9;
|
|
cpt->o_walk_pc = 0;
|
|
cpt->o_route[1].frame = 512; // end of sequence
|
|
if (id == PLAYER)
|
|
_router->setPlayerTarget(x, y, dir, stance);
|
|
|
|
int32 routeRes = _router->routeFinder(id, cpt, x, y, dir);
|
|
|
|
if (id == PLAYER) {
|
|
_router->resetExtraData();
|
|
if ((routeRes == 1) || (routeRes == 2)) {
|
|
_scriptVars[MEGA_ON_GRID] = 0;
|
|
_scriptVars[REROUTE_GEORGE] = 0;
|
|
}
|
|
}
|
|
if ((routeRes == 1) || (routeRes == 2)) {
|
|
cpt->o_down_flag = 1; // 1 means okay.
|
|
// if both mouse buttons were pressed on an exit => skip george's walk
|
|
if ((id == GEORGE) && (_mouse->testEvent() == MOUSE_BOTH_BUTTONS)) {
|
|
int32 target = _scriptVars[CLICK_ID];
|
|
// exceptions: compacts that use hand pointers but are not actually exits
|
|
if ((target != LEFT_SCROLL_POINTER) && (target != RIGHT_SCROLL_POINTER) &&
|
|
(target != FLOOR_63) && (target != ROOF_63) && (target != GUARD_ROOF_63) &&
|
|
(target != LEFT_TREE_POINTER_71) && (target != RIGHT_TREE_POINTER_71)) {
|
|
|
|
target = _objMan->fetchObject(_scriptVars[CLICK_ID])->o_mouse_on;
|
|
if ((target >= SCR_exit0) && (target <= SCR_exit9)) {
|
|
fnStandAt(cpt,id,x,y,dir,stance,0,0);
|
|
return SCRIPT_STOP;
|
|
}
|
|
}
|
|
}
|
|
cpt->o_logic = LOGIC_AR_animate;
|
|
return SCRIPT_STOP;
|
|
} else if (routeRes == 3)
|
|
cpt->o_down_flag = 1; // pretend it was successful
|
|
else
|
|
cpt->o_down_flag = 0; // 0 means error
|
|
|
|
return SCRIPT_CONT;
|
|
}
|
|
|
|
int Logic::fnTurn(Object *cpt, int32 id, int32 dir, int32 stance, int32 c, int32 d, int32 a, int32 b) {
|
|
if (stance > 0)
|
|
dir = 9;
|
|
int route = _router->routeFinder(id, cpt, cpt->o_xcoord, cpt->o_ycoord, dir);
|
|
|
|
if (route)
|
|
cpt->o_down_flag = 1; //1 means ok
|
|
else
|
|
cpt->o_down_flag = 0; //0 means error
|
|
|
|
cpt->o_logic = LOGIC_AR_animate;
|
|
cpt->o_walk_pc = 0; //reset
|
|
|
|
return SCRIPT_STOP;
|
|
}
|
|
|
|
int Logic::fnStand(Object *cpt, int32 id, int32 dir, int32 stance, int32 c, int32 d, int32 a, int32 b) {
|
|
if ((dir < 0) || (dir > 8)) {
|
|
warning("fnStand:: invalid direction %d", dir);
|
|
return SCRIPT_CONT;
|
|
}
|
|
if (dir == 8)
|
|
dir = cpt->o_dir;
|
|
cpt->o_resource = cpt->o_walk_resource;
|
|
cpt->o_status |= STAT_SHRINK;
|
|
cpt->o_anim_x = cpt->o_xcoord;
|
|
cpt->o_anim_y = cpt->o_ycoord;
|
|
cpt->o_frame = 96 + dir;
|
|
cpt->o_dir = dir;
|
|
return SCRIPT_STOP;
|
|
}
|
|
|
|
int Logic::fnStandAt(Object *cpt, int32 id, int32 x, int32 y, int32 dir, int32 stance, int32 a, int32 b) {
|
|
if ((dir < 0) || (dir > 8)) {
|
|
warning("fnStandAt:: invalid direction %d", dir);
|
|
return SCRIPT_CONT;
|
|
}
|
|
if (dir == 8)
|
|
dir = cpt->o_dir;
|
|
cpt->o_xcoord = x;
|
|
cpt->o_ycoord = y;
|
|
return fnStand(cpt, id, dir, stance, 0, 0, 0, 0);
|
|
}
|
|
|
|
int Logic::fnFace(Object *cpt, int32 id, int32 targetId, int32 b, int32 c, int32 d, int32 a, int32 z) {
|
|
Object *target = _objMan->fetchObject(targetId);
|
|
int32 x, y;
|
|
if ((target->o_type == TYPE_MEGA) || (target->o_type == TYPE_PLAYER)) {
|
|
x = target->o_xcoord;
|
|
y = target->o_ycoord;
|
|
} else {
|
|
x = (target->o_mouse_x1 + target->o_mouse_x2) / 2;
|
|
y = target->o_mouse_y2;
|
|
}
|
|
int32 megaTarDir = whatTarget(cpt->o_xcoord, cpt->o_ycoord, x, y);
|
|
fnTurn(cpt, id, megaTarDir, 0, 0, 0, 0, 0);
|
|
return SCRIPT_STOP;
|
|
}
|
|
|
|
int Logic::fnFaceXy(Object *cpt, int32 id, int32 x, int32 y, int32 c, int32 d, int32 a, int32 b) {
|
|
int megaTarDir = whatTarget(cpt->o_xcoord, cpt->o_ycoord, x, y);
|
|
fnTurn(cpt, id, megaTarDir, 0, 0, 0, 0, 0);
|
|
return SCRIPT_STOP;
|
|
}
|
|
|
|
int Logic::fnIsFacing(Object *cpt, int32 id, int32 targetId, int32 b, int32 c, int32 d, int32 a, int32 z) {
|
|
Object *target = _objMan->fetchObject(targetId);
|
|
int32 x, y, dir;
|
|
if ((target->o_type == TYPE_MEGA) || (target->o_type == TYPE_PLAYER)) {
|
|
x = target->o_xcoord;
|
|
y = target->o_ycoord;
|
|
dir = target->o_dir;
|
|
} else
|
|
error("fnIsFacing:: Target isn't a mega!");
|
|
|
|
int32 lookDir = whatTarget(x, y, cpt->o_xcoord, cpt->o_ycoord);
|
|
lookDir -= dir;
|
|
lookDir = ABS(lookDir);
|
|
|
|
if (lookDir > 4)
|
|
lookDir = 8 - lookDir;
|
|
|
|
_scriptVars[RETURN_VALUE] = lookDir;
|
|
return SCRIPT_STOP;
|
|
}
|
|
|
|
int Logic::fnGetTo(Object *cpt, int32 id, int32 a, int32 b, int32 c, int32 d, int32 z, int32 x) {
|
|
Object *place = _objMan->fetchObject(cpt->o_place);
|
|
|
|
cpt->o_tree.o_script_level++;
|
|
cpt->o_tree.o_script_pc[cpt->o_tree.o_script_level] = place->o_get_to_script;
|
|
cpt->o_tree.o_script_id[cpt->o_tree.o_script_level] = place->o_get_to_script;
|
|
return SCRIPT_STOP;
|
|
}
|
|
|
|
int Logic::fnGetToError(Object *cpt, int32 id, int32 a, int32 b, int32 c, int32 d, int32 z, int32 x) {
|
|
debug(1, "fnGetToError: compact %d at place %d no get-to for target %d, click_id %d\n", id, cpt->o_place, cpt->o_target, _scriptVars[CLICK_ID]);
|
|
return SCRIPT_CONT;
|
|
}
|
|
|
|
int Logic::fnRandom(Object *compact, int32 id, int32 min, int32 max, int32 e, int32 f, int32 z, int32 x) {
|
|
_scriptVars[RETURN_VALUE] = _rnd.getRandomNumberRng(min, max);
|
|
return SCRIPT_CONT;
|
|
}
|
|
|
|
int Logic::fnGetPos(Object *cpt, int32 id, int32 targetId, int32 b, int32 c, int32 d, int32 z, int32 x) {
|
|
Object *target = _objMan->fetchObject(targetId);
|
|
if ((target->o_type == TYPE_MEGA) || (target->o_type == TYPE_PLAYER)) {
|
|
_scriptVars[RETURN_VALUE] = target->o_xcoord;
|
|
_scriptVars[RETURN_VALUE_2] = target->o_ycoord;
|
|
} else {
|
|
_scriptVars[RETURN_VALUE] = (target->o_mouse_x1 + target->o_mouse_x2) / 2;
|
|
_scriptVars[RETURN_VALUE_2] = target->o_mouse_y2;
|
|
}
|
|
_scriptVars[RETURN_VALUE_3] = target->o_dir;
|
|
|
|
int32 megaSeperation;
|
|
if (targetId == DUANE)
|
|
megaSeperation = 70; // George & Duane stand with feet 70 pixels apart when at full scale
|
|
else if (targetId == BENOIR)
|
|
megaSeperation = 61; // George & Benoir
|
|
else
|
|
megaSeperation = 42; // George & Nico/Goinfre stand with feet 42 pixels apart when at full scale
|
|
|
|
if (target->o_status & STAT_SHRINK) {
|
|
int32 scale = (target->o_scale_a * target->o_ycoord + target->o_scale_b) / 256;
|
|
_scriptVars[RETURN_VALUE_4] = (megaSeperation * scale) / 256;
|
|
} else
|
|
_scriptVars[RETURN_VALUE_4] = megaSeperation;
|
|
return SCRIPT_CONT;
|
|
}
|
|
|
|
int Logic::fnGetGamepadXy(Object *cpt, int32 id, int32 a, int32 b, int32 c, int32 d, int32 z, int32 x) {
|
|
// playstation only
|
|
return SCRIPT_CONT;
|
|
}
|
|
|
|
int Logic::fnPlayFx(Object *cpt, int32 id, int32 fxNo, int32 b, int32 c, int32 d, int32 z, int32 x) {
|
|
_scriptVars[RETURN_VALUE] = _sound->addToQueue(fxNo);
|
|
return SCRIPT_CONT;
|
|
}
|
|
|
|
int Logic::fnStopFx(Object *cpt, int32 id, int32 fxNo, int32 b, int32 c, int32 d, int32 z, int32 x) {
|
|
_sound->fnStopFx(fxNo);
|
|
//_sound->removeFromQueue(fxNo);
|
|
return SCRIPT_CONT;
|
|
}
|
|
|
|
int Logic::fnPlayMusic(Object *cpt, int32 id, int32 tuneId, int32 loopFlag, int32 c, int32 d, int32 z, int32 x) {
|
|
if (tuneId == 153)
|
|
return SCRIPT_CONT;
|
|
if (loopFlag == LOOPED)
|
|
_scriptVars[CURRENT_MUSIC] = tuneId; // so it gets restarted when saving & reloading
|
|
else
|
|
_scriptVars[CURRENT_MUSIC] = 0;
|
|
|
|
_music->startMusic(tuneId, loopFlag);
|
|
return SCRIPT_CONT;
|
|
}
|
|
|
|
int Logic::fnStopMusic(Object *cpt, int32 id, int32 a, int32 b, int32 c, int32 d, int32 z, int32 x) {
|
|
_scriptVars[CURRENT_MUSIC] = 0;
|
|
_music->fadeDown();
|
|
return SCRIPT_CONT;
|
|
}
|
|
|
|
int Logic::fnInnerSpace(Object *cpt, int32 id, int32 a, int32 b, int32 c, int32 d, int32 z, int32 x) {
|
|
error("fnInnerSpace() not working.");
|
|
return SCRIPT_STOP;
|
|
}
|
|
|
|
int Logic::fnSetScreen(Object *cpt, int32 id, int32 target, int32 screen, int32 c, int32 d, int32 z, int32 x) {
|
|
_objMan->fetchObject(target)->o_screen = screen;
|
|
return SCRIPT_CONT;
|
|
}
|
|
|
|
int Logic::fnPreload(Object *cpt, int32 id, int32 resId, int32 b, int32 c, int32 d, int32 z, int32 x) {
|
|
_resMan->resOpen(resId);
|
|
_resMan->resClose(resId);
|
|
return SCRIPT_CONT;
|
|
}
|
|
|
|
int Logic::fnCheckCD(Object *cpt, int32 id, int32 screen, int32 b, int32 c, int32 d, int32 z, int32 x) {
|
|
// only a dummy, here.
|
|
// the check is done in the mainloop
|
|
return SCRIPT_CONT;
|
|
}
|
|
|
|
int Logic::fnRestartGame(Object *cpt, int32 id, int32 a, int32 b, int32 c, int32 d, int32 z, int32 x) {
|
|
SwordEngine::_systemVars.forceRestart = true;
|
|
cpt->o_logic = LOGIC_quit;
|
|
return SCRIPT_STOP;
|
|
}
|
|
|
|
int Logic::fnQuitGame(Object *cpt, int32 id, int32 a, int32 b, int32 c, int32 d, int32 z, int32 x) {
|
|
error("fnQuitGame() called");
|
|
return SCRIPT_STOP;
|
|
}
|
|
|
|
int Logic::fnDeathScreen(Object *cpt, int32 id, int32 a, int32 b, int32 c, int32 d, int32 z, int32 x) {
|
|
|
|
if (_scriptVars[FINALE_OPTION_FLAG] == 4) // successful end of game!
|
|
SwordEngine::_systemVars.deathScreenFlag = 2;
|
|
else
|
|
SwordEngine::_systemVars.deathScreenFlag = 1;
|
|
|
|
cpt->o_logic = LOGIC_quit;
|
|
return SCRIPT_STOP;
|
|
}
|
|
|
|
int Logic::fnSetParallax(Object *cpt, int32 id, int32 screen, int32 resId, int32 c, int32 d, int32 z, int32 x) {
|
|
_screen->fnSetParallax(screen, resId);
|
|
return SCRIPT_CONT;
|
|
}
|
|
|
|
int Logic::fnTdebug(Object *cpt, int32 id, int32 a, int32 b, int32 c, int32 d, int32 z, int32 x) {
|
|
debug(1, "Script TDebug id %d code %d, %d", id, a, b);
|
|
return SCRIPT_CONT;
|
|
}
|
|
|
|
int Logic::fnRedFlash(Object *cpt, int32 id, int32 a, int32 b, int32 c, int32 d, int32 z, int32 x) {
|
|
_screen->fnFlash(FLASH_RED);
|
|
return SCRIPT_CONT;
|
|
}
|
|
|
|
int Logic::fnBlueFlash(Object *cpt, int32 id, int32 a, int32 b, int32 c, int32 d, int32 z, int32 x) {
|
|
_screen->fnFlash(FLASH_BLUE);
|
|
return SCRIPT_CONT;
|
|
}
|
|
|
|
int Logic::fnYellow(Object *cpt, int32 id, int32 a, int32 b, int32 c, int32 d, int32 z, int32 x) {
|
|
_screen->fnFlash(BORDER_YELLOW);
|
|
return SCRIPT_CONT;
|
|
}
|
|
|
|
int Logic::fnGreen(Object *cpt, int32 id, int32 a, int32 b, int32 c, int32 d, int32 z, int32 x) {
|
|
_screen->fnFlash(BORDER_GREEN);
|
|
return SCRIPT_CONT;
|
|
}
|
|
|
|
int Logic::fnPurple(Object *cpt, int32 id, int32 a, int32 b, int32 c, int32 d, int32 z, int32 x) {
|
|
_screen->fnFlash(BORDER_PURPLE);
|
|
return SCRIPT_CONT;
|
|
}
|
|
|
|
int Logic::fnBlack(Object *cpt, int32 id, int32 a, int32 b, int32 c, int32 d, int32 z, int32 x) {
|
|
_screen->fnFlash(BORDER_BLACK);
|
|
return SCRIPT_CONT;
|
|
}
|
|
|
|
uint16 Logic::inRange(uint16 a, uint16 b, uint16 c) {
|
|
return (a > b)? a : (((b > c) ? c : b));
|
|
}
|
|
|
|
const uint32 Logic::_scriptVarInit[NON_ZERO_SCRIPT_VARS][2] = {
|
|
{ 42, 448}, { 43, 378}, { 51, 1}, { 92, 1}, { 147, 71}, { 201, 1},
|
|
{ 209, 1}, { 215, 1}, { 242, 2}, { 244, 1}, { 246, 3}, { 247, 1},
|
|
{ 253, 1}, { 297, 1}, { 398, 1}, { 508, 1}, { 605, 1}, { 606, 1},
|
|
{ 701, 1}, { 709, 1}, { 773, 1}, { 843, 1}, { 907, 1}, { 923, 1},
|
|
{ 966, 1}, { 988, 2}, {1058, 1}, {1059, 2}, {1060, 3}, {1061, 4},
|
|
{1062, 5}, {1063, 6}, {1064, 7}, {1065, 8}, {1066, 9}, {1067, 10},
|
|
{1068, 11}, {1069, 12}, {1070, 13}, {1071, 14}, {1072, 15}, {1073, 16},
|
|
{1074, 17}, {1075, 18}, {1076, 19}, {1077, 20}, {1078, 21}, {1079, 22},
|
|
{1080, 23}, {1081, 24}, {1082, 25}, {1083, 26}, {1084, 27}, {1085, 28},
|
|
{1086, 29}, {1087, 30}, {1088, 31}, {1089, 32}, {1090, 33}, {1091, 34},
|
|
{1092, 35}, {1093, 36}, {1094, 37}, {1095, 38}, {1096, 39}, {1097, 40},
|
|
{1098, 41}, {1099, 42}, {1100, 43}, {1101, 44}, {1102, 48}, {1103, 45},
|
|
{1104, 47}, {1105, 49}, {1106, 50}, {1107, 52}, {1108, 54}, {1109, 56},
|
|
{1110, 57}, {1111, 58}, {1112, 59}, {1113, 60}, {1114, 61}, {1115, 62},
|
|
{1116, 63}, {1117, 64}, {1118, 65}, {1119, 66}, {1120, 67}, {1121, 68},
|
|
{1122, 69}, {1123, 71}, {1124, 72}, {1125, 73}, {1126, 74}
|
|
};
|
|
|
|
} // End of namespace Sword1
|