Files
2026-02-02 04:50:13 +01:00

1266 lines
22 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "got/game/script.h"
#include "common/textconsole.h"
#include "got/events.h"
#include "got/game/back.h"
#include "got/game/main.h"
#include "got/game/object.h"
#include "got/game/status.h"
#include "got/gfx/image.h"
#include "got/utils/file.h"
#include "got/vars.h"
#include "got/views/dialogs/ask.h"
#include "got/views/dialogs/say.h"
namespace Got {
#define ERROR_MAX 10
#define SCR_BUFF_SIZE 5000
static const char *SCR_COMMAND[] = {
"!@#$%", "END", "GOTO", "GOSUB", "RETURN", "FOR", "NEXT",
"IF", "ELSE", "RUN",
"ADDJEWELS", "ADDHEALTH", "ADDMAGIC", "ADDKEYS",
"ADDSCORE", "SAY", "ASK", "SOUND", "PLACETILE",
"ITEMGIVE", "ITEMTAKE", "ITEMSAY", "SETFLAG", "LTOA",
"PAUSE", "TEXT", "EXEC", "VISIBLE", "RANDOM",
nullptr};
static const char *INTERNAL_VARIABLE[] = {
"@JEWELS", "@HEALTH", "@MAGIC", "@SCORE",
"@SCREEN", "@KEYS",
"@OW", "@GULP", "@SWISH", "@YAH", "@ELECTRIC",
"@THUNDER", "@DOOR", "@FALL", "@ANGEL", "@WOOP",
"@DEAD", "@BRAAPP", "@WIND", "@PUNCH", "@CLANG",
"@EXPLODE", "@FLAG", "@ITEM", "@THORTILE",
"@THORPOS",
nullptr};
static const char *SCR_ERROR[] = {
"!@#$%", "Out of Memory", "Can't Read Script",
"Too Many Labels", "No END",
"Syntax", "Out of Range", "Undefined Label",
"RETURN Without GOSUB", "Nesting",
"NEXT Without FOR",
nullptr};
static const char *OFFENSE[] = {
"Cussing", "Rebellion", "Kissing Your Mother Goodbye",
"Being a Thunder God", "Door-to-Door Sales",
"Carrying a Concealed Hammer"};
static const char *REASON[] = {
"We heard you say 'Booger'.",
"You look kind of rebellious.",
"Your mother turned you in.",
"We don't want you here.",
"Nobody wants your sweepers.",
"That's a dangerous weapon."};
Scripts::ScrFunction Scripts::scr_func[5] = {
&Scripts::scr_func1,
&Scripts::scr_func2,
&Scripts::scr_func3,
&Scripts::scr_func4,
&Scripts::scr_func5
};
Scripts *g_scripts;
void executeScript(long index, const Gfx::Pics &speakerIcon, ScriptEndFn endFn) {
g_scripts->executeScript(index, speakerIcon, endFn);
}
Scripts::Scripts() {
g_scripts = this;
}
Scripts::~Scripts() {
g_scripts = nullptr;
}
void Scripts::executeScript(long index, const Gfx::Pics &speakerIcon, ScriptEndFn endFn) {
// Firstly disable any on-screen actors
for (int i = 0; i < MAX_ACTORS; i++)
_G(actor[i])._show = 0;
_endFn = endFn;
_scrIndex = index;
_scrPic = speakerIcon;
Common::fill(_numVar, _numVar + 26, 0);
Common::fill((char *)_strVar, (char *)_strVar + 81 * 26, 0);
runScript();
}
void Scripts::runScript(bool firstTime) {
// Clear line label buffer, line ptrs, and the gosub stack
Common::fill((char *)_lineLabel, (char *)_lineLabel + 32 * 9, 0);
Common::fill(_linePtr, _linePtr + 32, (char *)nullptr);
Common::fill(_gosubStack, _gosubStack + 32, (char *)nullptr);
_gosubPtr = 0;
Common::fill(_forVar, _forVar + 11, 0);
Common::fill(_forVal, _forVal + 11, 0);
Common::fill(_forStack, _forStack + 11, (char *)nullptr);
_forPtr = 0;
int i = readScriptFile();
if (i != 0) {
scriptError(i);
scriptExit();
return;
}
if (firstTime)
scriptEntry();
_buffPtr = _buffer;
scriptLoop();
}
void Scripts::scriptLoop() {
while (_paused == SCRIPT_READY) {
if (_G(cheat) && _G(keyFlag[GOT_B]))
break;
int ret = getCommand();
if (ret == -1)
break; // Ignore NO END error
if (ret == -2) {
scriptError(5); // Syntax error
break;
}
if (ret > 0) {
ret = execCommand(ret);
if (ret == -100) { // RUN command
if (_buffer)
free(_buffer);
runScript(false);
return;
}
if (!ret)
break;
}
}
if (_paused == SCRIPT_READY)
scriptExit();
}
void Scripts::scriptExit() {
if (_buffer) {
free(_buffer);
_buffer = nullptr;
}
if (_endFn)
_endFn();
}
int Scripts::skipColon() {
while (*_buffPtr == 0 || *_buffPtr == ':') {
_buffPtr++;
if (_buffPtr > _buffEnd)
return 0;
}
return 1;
}
int Scripts::getCommand() {
if (!skipColon())
return -1;
int i = 0;
while (true) {
if (!SCR_COMMAND[i])
break; // Lookup command
int len = strlen(SCR_COMMAND[i]);
if (!strncmp(_buffPtr, SCR_COMMAND[i], len)) {
_buffPtr += len;
return i;
}
i++;
}
if (Common::isAlpha(*_buffPtr)) {
int ret;
if (*(_buffPtr + 1) == '=') { // Num var assignment
i = (*_buffPtr) - 65;
_buffPtr += 2;
ret = calcValue();
if (!ret)
return -2;
_numVar[i] = _lValue;
return 0;
}
if (*(_buffPtr + 1) == '$' && *(_buffPtr + 2) == '=') {
i = (*_buffPtr) - 65;
_buffPtr += 3;
ret = calcString(0); // String var assignment
if (ret == 0)
return -2;
if (ret == -1)
return -3;
if (strlen(_tempS) > 80)
return -3;
Common::strcpy_s(_strVar[i], _tempS);
return 0;
}
}
return -2;
}
int Scripts::calcString(int mode) {
// if mode==1 stop at comma
char varString[255];
uint varNumber;
Common::strcpy_s(varString, "");
if (!skipColon())
return 0;
strloop:
if (*_buffPtr == '"') {
getStr();
if (strlen(varString) + strlen(_tempS) < 255)
Common::strcat_s(varString, _tempS);
goto nextstr;
}
if (Common::isAlpha(*_buffPtr)) {
if (*(_buffPtr + 1) == '$') {
varNumber = (*_buffPtr) - 65;
if (strlen(varString) + strlen(_strVar[varNumber]) < 255)
Common::strcat_s(varString, _strVar[varNumber]);
_buffPtr += 2;
goto nextstr;
}
}
return 0;
nextstr:
if (*_buffPtr == 0 || *_buffPtr == 58) {
_buffPtr++;
goto strdone;
}
if (*_buffPtr == ',' && mode == 1)
goto strdone;
if (*_buffPtr == '+') {
_buffPtr++;
goto strloop;
}
return 0;
strdone:
Common::strcpy_s(_tempS, (char *)varString);
return 1;
}
void Scripts::getStr() {
_buffPtr++;
int t = 0;
while (true) {
if (*_buffPtr == '"' || *_buffPtr == 0) {
_tempS[t] = 0;
if (*_buffPtr == '"')
_buffPtr++;
return;
}
_tempS[t++] = *_buffPtr;
_buffPtr++;
}
}
int Scripts::calcValue() {
long tmpVal2 = 0;
char expType = 1;
while (true) {
if (!getNextValue())
return 0;
switch (expType) {
case 0:
tmpVal2 = tmpVal2 * _lTemp;
break;
case 1:
tmpVal2 = tmpVal2 + _lTemp;
break;
case 2:
tmpVal2 = tmpVal2 - _lTemp;
break;
case 3:
if (_lTemp != 0)
tmpVal2 = tmpVal2 / _lTemp;
break;
default:
break;
}
const char ch = *_buffPtr;
switch (ch) {
case 42:
expType = 0; /* multiply */
break;
case 43:
expType = 1; /* add */
break;
case 45:
expType = 2; /* minus */
break;
case 47:
expType = 3; /* divide */
break;
default:
_lValue = tmpVal2;
return 1;
}
_buffPtr++;
}
}
int Scripts::getNextValue() {
const char ch = *_buffPtr;
if (ch == 0 || ch == ':')
return 0;
if (ch == 64)
return getInternalVariable();
if (Common::isAlpha(ch)) {
_buffPtr++;
_lTemp = _numVar[ch - 65];
return 1;
}
if (strchr("0123456789-", ch)) {
char tmpString[25];
int tmpIndex = 0;
tmpString[tmpIndex] = ch;
_buffPtr++;
tmpIndex++;
while (strchr("0123456789", *_buffPtr) && *_buffPtr != 0) {
tmpString[tmpIndex] = *_buffPtr;
_buffPtr++;
tmpIndex++;
}
tmpString[tmpIndex] = 0;
if (tmpIndex > 10)
return 0;
_lTemp = atol(tmpString);
return 1;
}
return 0;
}
int Scripts::getInternalVariable() {
int i = 0;
while (true) {
if (!INTERNAL_VARIABLE[i])
return 0; // Lookup internal variable
const int len = strlen(INTERNAL_VARIABLE[i]);
if (!strncmp(_buffPtr, INTERNAL_VARIABLE[i], len)) {
_buffPtr += len;
break;
}
i++;
}
switch (i) {
case 0:
_lTemp = _G(thorInfo)._jewels;
break;
case 1:
_lTemp = _G(thor)->_health;
break;
case 2:
_lTemp = _G(thorInfo)._magic;
break;
case 3:
_lTemp = _G(thorInfo)._score;
break;
case 4:
_lTemp = _G(currentLevel);
break;
case 5:
_lTemp = _G(thorInfo)._keys;
break;
case 6:
case 7:
case 8:
case 9:
case 10:
case 11:
case 12:
case 13:
case 14:
case 15:
case 16:
case 17:
case 18:
case 19:
case 20:
case 21:
_lTemp = (long)(i - 5l);
break;
case 22:
if (!calcValue())
return 0;
i = (int)_lValue;
if (i < 1 || i > 64)
return 0;
_lTemp = _G(setup)._flags[i - 1] ? 1 : 0;
break;
case 23:
if (_G(thorInfo)._inventory & 64)
_lTemp = _G(thorInfo)._object;
else
_lTemp = 0;
break;
case 24:
_lTemp = _G(scrn)._iconGrid[(_G(thor)->_y + 8) / 16][(_G(thor)->_x + 7) / 16];
break;
case 25:
_lTemp = (((_G(thor)->_y + 8) / 16) * 20) + ((_G(thor)->_x + 7) / 16);
break;
default:
return 0;
}
return 1;
}
int Scripts::getLine(char *src, char *dst) {
int cnt = 0;
if (!src)
return cnt;
while (*src != 13) {
if (*src != 10) {
*dst = *src;
dst++;
}
cnt++;
src++;
}
*dst = 0;
cnt++;
return cnt;
}
int Scripts::readScriptFile() {
char tmpBuffer[255];
char quoteFlag;
int len, p, ret, cnt;
Common::String str;
char tmps[255];
char *sbuff = nullptr;
char *sb;
_buffer = (char *)malloc(SCR_BUFF_SIZE);
if (!_buffer) {
ret = 1;
goto done;
};
_buffPtr = _buffer;
Common::fill(_buffer, _buffer + SCR_BUFF_SIZE, 0);
sbuff = (char *)malloc(25000l);
sb = sbuff;
if (!sb) {
ret = 1;
goto done;
};
str = Common::String::format("SPEAK%d", _G(area));
if (resourceRead(str.c_str(), sb) < 0) {
ret = 6;
goto done;
}
str = Common::String::format("|%ld", _scrIndex);
Common::strcpy_s(tmpBuffer, str.c_str());
while (true) {
cnt = getLine(sb, (char *)tmps);
sb += cnt;
if (!strcmp(tmps, "|EOF")) {
ret = 2;
goto done;
}
if (!strcmp(tmps, tmpBuffer))
break;
}
_numLabels = 0;
while (true) {
cnt = getLine(sb, (char *)tmps);
if (!strcmp(tmps, "|STOP")) {
if (_buffPtr != _buffer) {
_buffEnd = _buffPtr;
ret = 0;
goto done;
}
ret = 2;
goto done;
}
sb += cnt;
len = strlen(tmps);
if (len < 2) {
*_buffPtr = 0;
_buffPtr++;
continue;
}
quoteFlag = 0;
p = 0;
for (int i = 0; i < len; i++) {
char ch = tmps[i];
if (ch == 34)
quoteFlag ^= 1;
else if (ch == 13 || ch == 10) { // Check for CR
tmpBuffer[p] = 0;
break;
}
if ((ch == 39 || ch == 96) && !quoteFlag) {
tmpBuffer[p] = 0;
break;
}
if (!quoteFlag)
ch = toupper(ch);
if (quoteFlag || ch > 32) {
tmpBuffer[p++] = ch;
}
}
tmpBuffer[p] = 0;
len = strlen(tmpBuffer);
if (len > 0 && len < 10 && tmpBuffer[len - 1] == ':') { //line label
tmpBuffer[len - 1] = 0;
_linePtr[_numLabels] = _buffPtr;
Common::strcpy_s(_lineLabel[_numLabels++], (char *)tmpBuffer);
if (_numLabels > 31) {
ret = 3;
goto done;
}
*_buffPtr = 0;
_buffPtr++;
continue;
}
Common::strcpy_s(_buffPtr, SCR_BUFF_SIZE, tmpBuffer);
_buffPtr += strlen(tmpBuffer);
*_buffPtr = 0;
_buffPtr++;
}
done:
if (sbuff)
free(sbuff);
return ret;
}
void Scripts::scriptError(int err_num) {
int lineNum = 1;
char *tb = _buffer;
while (1) {
if (*tb == 0)
lineNum++;
if (tb >= _buffPtr)
break;
tb++;
}
if (err_num > ERROR_MAX)
err_num = 5; // Unknown=syntax
warning("%s in Line #%d", SCR_ERROR[err_num], lineNum);
}
int Scripts::cmd_goto() {
char s[255];
Common::strcpy_s(s, _buffPtr);
char *p = strchr(s, ':');
if (p)
*p = 0;
for (int i = 0; i < _numLabels; i++) {
int len = strlen(s);
if (len == 0)
break;
if (!strcmp(s, _lineLabel[i])) {
_newPtr = _linePtr[i];
_buffPtr += len;
return 0;
}
}
return 8;
}
int Scripts::cmd_if() {
if (!calcValue())
return 5;
const long tmpVal1 = _lValue;
char expType = *_buffPtr;
_buffPtr++;
const char ch = *_buffPtr;
if (ch == 60 || ch == 61 || ch == 62) {
if (expType == *_buffPtr)
return 5;
expType += *_buffPtr;
_buffPtr++;
}
if (!calcValue())
return 5;
const long tmpVal2 = _lValue;
_buffPtr += 4;
switch (expType) {
case 60: /* less than */
if (tmpVal1 < tmpVal2)
goto iftrue;
goto iffalse;
case 61: /* equal */
if (tmpVal1 == tmpVal2)
goto iftrue;
goto iffalse;
case 62: /* greater than */
if (tmpVal1 > tmpVal2)
goto iftrue;
goto iffalse;
case 121: /* less than or equal */
if (tmpVal1 <= tmpVal2)
goto iftrue;
goto iffalse;
case 122: /* less or greater (not equal) */
if (tmpVal1 != tmpVal2)
goto iftrue;
goto iffalse;
case 123: /* greater than or equal */
if (tmpVal1 >= tmpVal2)
goto iftrue;
goto iffalse;
default:
return 5;
}
iffalse:
while (*_buffPtr != 0)
_buffPtr++;
while (*_buffPtr == 0)
_buffPtr++;
if (!strncmp(_buffPtr, "ELSE", 4))
_buffPtr += 4;
iftrue:
return 0;
}
int Scripts::cmd_run() {
if (!calcValue())
return 5;
_buffPtr++;
_scrIndex = _lValue;
return -100;
}
int Scripts::cmd_addJewels() {
if (!calcValue())
return 5;
_buffPtr++;
addJewels(_lValue);
return 0;
}
int Scripts::cmd_addHealth() {
if (!calcValue())
return 5;
_buffPtr++;
addHealth((int)_lValue);
return 0;
}
int Scripts::cmd_addMagic() {
if (!calcValue())
return 5;
_buffPtr++;
addMagic((int)_lValue);
return 0;
}
int Scripts::cmd_addKeys() {
if (!calcValue())
return 5;
_buffPtr++;
addKeys((int)_lValue);
return 0;
}
int Scripts::cmd_addScore() {
if (!calcValue())
return 5;
_buffPtr++;
addScore((int)_lValue);
return 0;
}
int Scripts::cmd_say(int mode, int type) {
int obj = 0;
if (mode) {
if (!calcValue())
return 5;
_buffPtr++;
obj = (int)_lValue;
if (obj < 0 || obj > 32)
return 6;
if (obj)
obj += 10;
}
Common::fill(_G(tmpBuff), _G(tmpBuff) + TMP_SIZE, 0);
char *p = (char *)_G(tmpBuff);
while (calcString(0)) {
Common::strcpy_s(p, TMP_SIZE, _tempS);
p += strlen(_tempS);
*(p) = 10;
p++;
}
*(p - 1) = 0;
pause();
Views::Dialogs::Say::show(obj, _scrPic, type);
return 0;
}
int Scripts::cmd_ask() {
int v = 0;
char title[41], opt[41];
Common::StringArray opts;
memset(_G(tmpBuff), 0, TMP_SIZE);
if (!skipColon())
return 5;
if (Common::isAlpha(*_buffPtr)) {
v = *_buffPtr - 65;
_buffPtr++;
if (*_buffPtr != ',')
return 5;
_buffPtr++;
} else {
return 5;
}
if (!calcString(1))
return 5;
strncpy(title, _tempS, 41);
title[40] = 0;
if (*_buffPtr == ',') {
_buffPtr++;
if (!calcValue())
return 5;
_buffPtr++;
} else {
return 5;
}
_askVar = v;
while (calcString(0)) {
Common::strcpy_s(opt, _tempS);
opts.push_back(opt);
if (opts.size() > 9)
return 3;
}
// Pause the script execution, and open up an ask window.
// Execution of the script will resume after a selection.
pause();
Views::Dialogs::Ask::show(title, opts);
return 0;
}
void Scripts::pause() {
_paused = SCRIPT_PAUSED;
}
void Scripts::resume() {
_paused = SCRIPT_RESUMING;
}
void Scripts::setAskResponse(int option) {
_numVar[_askVar] = option;
resume();
}
void Scripts::runIfResuming() {
if (_paused == SCRIPT_RESUMING) {
_paused = SCRIPT_READY;
scriptLoop();
}
}
int Scripts::cmd_sound() {
if (!calcValue())
return 5;
_buffPtr++;
if (_lValue < 1 || _lValue > 16)
return 6;
playSound((int)_lValue - 1, true);
return 0;
}
int Scripts::cmd_setTile() {
if (!calcValue())
return 5;
_buffPtr++;
const int screen = (int)_lValue;
if (!calcValue())
return 5;
_buffPtr++;
const int pos = (int)_lValue;
if (!calcValue())
return 5;
const int tile = (int)_lValue;
if (screen < 0 || screen > 119)
return 6;
if (pos < 0 || pos > 239)
return 6;
if (tile < 0 || tile > 230)
return 6;
if (screen == _G(currentLevel)) {
placeTile(pos % 20, pos / 20, tile);
} else {
Level tmp;
tmp.load(screen);
tmp._iconGrid[pos / 20][pos % 20] = tile;
tmp.save(screen);
}
return 0;
}
int Scripts::cmd_itemGive() {
if (!calcValue())
return 5;
_buffPtr++;
int i = (int)_lValue;
if (i < 1 || i > 15)
return 6;
_G(thorInfo)._inventory |= 64;
_G(thorInfo)._selectedItem = 7;
_G(thorInfo)._object = i;
_G(thorInfo)._objectName = OBJECT_NAMES[_G(thorInfo)._object - 1];
return 0;
}
int Scripts::cmd_itemTake() {
deleteObject();
return 0;
}
int Scripts::cmd_setFlag() {
if (!calcValue())
return 5;
int i = (int)_lValue;
if (i < 1 || i > 64)
return 6;
_G(setup)._flags[i - 1] = true;
return 0;
}
int Scripts::cmd_ltoa() {
int sv;
if (!calcValue())
return 5;
_buffPtr++;
if (Common::isAlpha(*_buffPtr)) {
if (*(_buffPtr + 1) == '$') {
sv = (*_buffPtr) - 65;
_buffPtr += 2;
} else {
return 5;
}
} else {
return 5;
}
Common::String str = Common::String::format("%ld", _lValue);
Common::strcpy_s(_strVar[sv], str.c_str());
return 0;
}
int Scripts::cmd_pause() {
if (!calcValue())
return 5;
_buffPtr++;
if (_lValue < 1 || _lValue > 65535l)
return 6;
Got::pause((int)_lValue);
return 0;
}
int Scripts::cmd_visible() {
if (!calcValue())
return 5;
_buffPtr++;
if (_lValue < 1 || _lValue > 16)
return 6;
actorVisible((int)_lValue);
return 0;
}
int Scripts::cmd_random() {
int v;
if (Common::isAlpha(*_buffPtr)) {
v = *_buffPtr - 65;
_buffPtr++;
if (*_buffPtr != ',')
return 5;
_buffPtr++;
} else {
return 5;
}
if (!calcValue())
return 5;
_buffPtr++;
int r = (int)_lValue;
if (r < 1 || r > 1000)
return 6;
_numVar[v] = g_events->getRandomNumber(r - 1);
return 0;
}
void Scripts::scr_func1() {
playSound(FALL, true);
_G(newLevel) = 109;
_G(newLevelTile) = 215;
_G(thor)->_x = (_G(newLevelTile) % 20) * 16;
_G(thor)->_y = ((_G(newLevelTile) / 20) * 16) - 2;
_G(thor)->_lastX[0] = _G(thor)->_x;
_G(thor)->_lastX[1] = _G(thor)->_x;
_G(thor)->_lastY[0] = _G(thor)->_y;
_G(thor)->_lastY[1] = _G(thor)->_y;
_G(thor)->_show = 2;
}
void Scripts::scr_func2() {
int r = g_events->getRandomNumber(5);
Common::strcpy_s(_strVar[0], 81, OFFENSE[r]);
Common::strcpy_s(_strVar[1], 81, REASON[r]);
}
void Scripts::scr_func3() {
int p = (((_G(thor)->_y + 8) / 16) * 20) + ((_G(thor)->_x + 7) / 16);
int y = p / 20;
int x = p % 20;
if (y < 0 || x < 0 || y > 11) {
playSound(BRAAPP, true);
_G(keyFlag[key_magic]) = false;
return;
}
if (_G(scrn)._iconGrid[y][x] < 174 || _G(scrn)._iconGrid[y][x] > 178) {
playSound(BRAAPP, true);
_G(keyFlag[key_magic]) = false;
return;
}
_numVar[0] = 1;
playSound(WOOP, true);
if (_G(currentLevel) == 106 && p == 69) {
placeTile(x, y, 220);
_G(keyFlag[key_magic]) = false;
return;
}
_G(keyFlag[key_magic]) = false;
placeTile(x, y, 191);
if ((g_events->getRandomNumber(99)) < 25 ||
(_G(currentLevel) == 13 && p == 150 && !_G(setup).f26 && _G(setup).f28)) {
if (!_G(objectMap[p]) && _G(scrn)._iconGrid[y][x] >= 140) { // nothing there and solid
int o = g_events->getRandomNumber(1, 5);
if (_G(currentLevel) == 13 && p == 150 && !_G(setup).f26 && _G(setup).f28)
o = 20;
_G(objectMap[p]) = o;
_G(objectIndex[p]) = 31; // actor is 3-15
}
}
}
void Scripts::scr_func4() {
_G(thunderSnakeCounter) = 60;
}
void Scripts::scr_func5() {
_G(scrn)._actorLoc[0] -= 2;
_G(scrn)._actorLoc[1] -= 2;
_G(scrn)._actorLoc[2] -= 2;
_G(scrn)._actorLoc[3] -= 2;
_G(actor[3])._i1 = 16;
}
int Scripts::cmd_exec() {
if (!calcValue())
return 5;
_buffPtr++;
if (_lValue < 1 || _lValue > 10)
return 6;
if (_lValue > 5) {
error("cmd_exec - unhandled lValue %ld", _lValue);
}
(this->*scr_func[_lValue - 1])();
return 0;
}
int Scripts::execCommand(int num) {
char ch;
int ret = 0;
switch (num) {
case 1: // end
return 0;
case 2: // goto
ret = cmd_goto();
if (!ret)
_buffPtr = _newPtr;
break;
case 3: // gosub
ret = cmd_goto();
if (!ret) {
_gosubPtr++;
if (_gosubPtr > 31) {
ret = 10;
break;
}
_gosubStack[_gosubPtr] = _buffPtr;
_buffPtr = _newPtr;
}
break;
case 4: // return
if (!_gosubPtr) {
ret = 9;
break;
}
_buffPtr = _gosubStack[_gosubPtr--];
break;
case 5: // for
_forPtr++;
if (_forPtr > 10) {
ret = 10;
break;
}
ch = *_buffPtr;
if (!Common::isAlpha(ch)) {
ret = 5;
break;
}
ch -= 65;
_forVar[_forPtr] = ch;
_buffPtr += 2;
if (!calcValue()) {
ret = 5;
break;
}
_numVar[_forVar[_forPtr]] = _lValue;
_buffPtr += 2;
if (!calcValue()) {
ret = 5;
break;
}
_forVal[_forPtr] = _lValue;
_forStack[_forPtr] = _buffPtr;
break;
case 6: // next
if (!_forPtr) {
ret = 11;
break;
}
_numVar[_forVar[_forPtr]] = _numVar[_forVar[_forPtr]] + 1;
if (_numVar[_forVar[_forPtr]] <= _forVal[_forPtr])
_buffPtr = _forStack[_forPtr];
else
_forPtr--;
break;
case 7: // if
ret = cmd_if();
break;
case 8: // else
while (*_buffPtr != 0)
_buffPtr++;
break;
case 9: // run
ret = cmd_run();
if (ret < 0)
return -100;
break;
case 10: // addjewels
ret = cmd_addJewels();
break;
case 11: // addhealth
ret = cmd_addHealth();
break;
case 12: // addmagic
ret = cmd_addMagic();
break;
case 13: // addkeys
ret = cmd_addKeys();
break;
case 14: // addscore
ret = cmd_addScore();
break;
case 15: // say
ret = cmd_say(0, 1);
break;
case 16: // ask
ret = cmd_ask();
break;
case 17: // sound
ret = cmd_sound();
break;
case 18: // settile
ret = cmd_setTile();
break;
case 19: // itemgive
ret = cmd_itemGive();
break;
case 20: // itemtake
ret = cmd_itemTake();
break;
case 21: // itemsay
ret = cmd_say(1, 1);
break;
case 22: // setflag
ret = cmd_setFlag();
break;
case 23: // ltoa
ret = cmd_ltoa();
break;
case 24: // pause
ret = cmd_pause();
break;
case 25: // text
ret = cmd_say(0, 0);
break;
case 26: // exec
ret = cmd_exec();
break;
case 27: // visible
ret = cmd_visible();
break;
case 28: // random
ret = cmd_random();
break;
default:
ret = 5;
}
if (ret > 0) {
scriptError(ret);
return 0;
}
return 1;
}
} // namespace Got