scummvm/engines/sludge/builtin.cpp
2023-12-24 13:19:25 +01:00

2589 lines
62 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 "common/config-manager.h"
#include "common/random.h"
#include "common/savefile.h"
#include "common/system.h"
#include "sludge/builtin.h"
#include "sludge/cursors.h"
#include "sludge/event.h"
#include "sludge/floor.h"
#include "sludge/fonttext.h"
#include "sludge/function.h"
#include "sludge/graphics.h"
#include "sludge/moreio.h"
#include "sludge/movie.h"
#include "sludge/newfatal.h"
#include "sludge/objtypes.h"
#include "sludge/people.h"
#include "sludge/region.h"
#include "sludge/savedata.h"
#include "sludge/sludger.h"
#include "sludge/sound.h"
#include "sludge/speech.h"
#include "sludge/statusba.h"
#include "sludge/sludge.h"
#include "sludge/timing.h"
namespace Sludge {
extern bool allowAnyFilename;
extern VariableStack *noStack;
extern int numBIFNames, numUserFunc;
extern Common::String *allUserFunc;
extern Common::String *allBIFNames;
bool failSecurityCheck(const Common::String &fn) {
if (fn.empty())
return true;
for (uint i = 0; i < fn.size(); ++i) {
switch (fn[i]) {
case ':':
case '\\':
case '/':
case '*':
case '?':
case '"':
case '<':
case '>':
case '|':
fatal("Filenames may not contain the following characters: \n\n\\ / : \" < > | ? *\n\nConsequently, the following filename is not allowed:", fn);
return true;
default:
break;
}
}
return false;
}
extern LoadedFunction *saverFunc;
typedef BuiltReturn (*builtInSludgeFunc)(int numParams, LoadedFunction *fun);
struct builtInFunctionData {
const char *name;
builtInSludgeFunc func;
int paramNum;
};
#define builtIn(a) static BuiltReturn builtIn_ ## a (int numParams, LoadedFunction *fun)
#define UNUSEDALL (void) (0 && sizeof(numParams) && sizeof (fun));
static BuiltReturn sayCore(int numParams, LoadedFunction *fun, bool sayIt) {
int fileNum = -1;
Common::String newText;
int objT, p;
killSpeechTimers();
switch (numParams) {
case 3:
if (!fun->stack->thisVar.getValueType(fileNum, SVT_FILE))
return BR_ERROR;
trimStack(fun->stack);
// fall through
case 2:
newText = fun->stack->thisVar.getTextFromAnyVar();
trimStack(fun->stack);
if (!fun->stack->thisVar.getValueType(objT, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
p = g_sludge->_speechMan->wrapSpeech(newText, objT, fileNum, sayIt);
fun->timeLeft = p;
//debugOut ("BUILTIN: sayCore: %s (%i)\n", newText, p);
fun->isSpeech = true;
return BR_KEEP_AND_PAUSE;
default:
break;
}
fatal("Function should have either 2 or 3 parameters");
return BR_ERROR;
}
#pragma mark -
#pragma mark Built in functions
builtIn(say) {
UNUSEDALL
return sayCore(numParams, fun, true);
}
builtIn(think) {
UNUSEDALL
return sayCore(numParams, fun, false);
}
builtIn(freeze) {
UNUSEDALL
g_sludge->_gfxMan->freeze();
freezeSubs();
fun->freezerLevel = 0;
return BR_CONTINUE;
}
builtIn(unfreeze) {
UNUSEDALL
g_sludge->_gfxMan->unfreeze();
unfreezeSubs();
return BR_CONTINUE;
}
builtIn(howFrozen) {
UNUSEDALL
fun->reg.setVariable(SVT_INT, g_sludge->_gfxMan->howFrozen());
return BR_CONTINUE;
}
builtIn(setCursor) {
UNUSEDALL
PersonaAnimation *aa = fun->stack->thisVar.getAnimationFromVar();
g_sludge->_cursorMan->pickAnimCursor(aa);
trimStack(fun->stack);
return BR_CONTINUE;
}
builtIn(getMouseX) {
UNUSEDALL
fun->reg.setVariable(SVT_INT, g_sludge->_evtMan->mouseX() + g_sludge->_gfxMan->getCamX());
return BR_CONTINUE;
}
builtIn(getMouseY) {
UNUSEDALL
fun->reg.setVariable(SVT_INT, g_sludge->_evtMan->mouseY() + g_sludge->_gfxMan->getCamY());
return BR_CONTINUE;
}
builtIn(getMouseScreenX) {
UNUSEDALL
fun->reg.setVariable(SVT_INT, g_sludge->_evtMan->mouseX() * g_sludge->_gfxMan->getCamZoom());
return BR_CONTINUE;
}
builtIn(getMouseScreenY) {
UNUSEDALL
fun->reg.setVariable(SVT_INT, g_sludge->_evtMan->mouseY() * g_sludge->_gfxMan->getCamZoom());
return BR_CONTINUE;
}
builtIn(getStatusText) {
UNUSEDALL
fun->reg.makeTextVar(g_sludge->_statusBar->statusBarText());
return BR_CONTINUE;
}
builtIn(getMatchingFiles) {
UNUSEDALL
Common::String newText = fun->stack->thisVar.getTextFromAnyVar();
trimStack(fun->stack);
fun->reg.unlinkVar();
// Return value
fun->reg.varType = SVT_STACK;
fun->reg.varData.theStack = new StackHandler;
if (!checkNew(fun->reg.varData.theStack))
return BR_ERROR;
fun->reg.varData.theStack->first = NULL;
fun->reg.varData.theStack->last = NULL;
fun->reg.varData.theStack->timesUsed = 1;
if (!fun->reg.varData.theStack->getSavedGamesStack(newText))
return BR_ERROR;
return BR_CONTINUE;
}
builtIn(saveGame) {
UNUSEDALL
if (g_sludge->_gfxMan->isFrozen()) {
fatal("Can't save game state while the engine is frozen");
}
g_sludge->loadNow = fun->stack->thisVar.getTextFromAnyVar();
trimStack(fun->stack);
Common::String aaaaa = encodeFilename(g_sludge->loadNow);
g_sludge->loadNow.clear();
if (failSecurityCheck(aaaaa))
return BR_ERROR; // Won't fail if encoded, how cool is that? OK, not very.
g_sludge->loadNow = ":" + aaaaa;
fun->reg.setVariable(SVT_INT, 0);
saverFunc = fun;
return BR_KEEP_AND_PAUSE;
}
builtIn(fileExists) {
UNUSEDALL
g_sludge->loadNow = fun->stack->thisVar.getTextFromAnyVar();
trimStack(fun->stack);
Common::String aaaaa = encodeFilename(g_sludge->loadNow);
g_sludge->loadNow.clear();
if (failSecurityCheck(aaaaa))
return BR_ERROR;
bool exist = false;
Common::File fd;
if (fd.open(Common::Path(aaaaa))) {
exist = true;
fd.close();
} else {
Common::InSaveFile *fp = g_system->getSavefileManager()->openForLoading(aaaaa);
if (fp) {
exist = true;
delete fp;
}
}
// Return value
fun->reg.setVariable(SVT_INT, exist);
return BR_CONTINUE;
}
builtIn(loadGame) {
UNUSEDALL
Common::String aaaaa = fun->stack->thisVar.getTextFromAnyVar();
trimStack(fun->stack);
g_sludge->loadNow.clear();
g_sludge->loadNow = encodeFilename(aaaaa);
if (g_sludge->_gfxMan->isFrozen()) {
fatal("Can't load a saved game while the engine is frozen");
}
if (failSecurityCheck(g_sludge->loadNow))
return BR_ERROR;
Common::InSaveFile *fp = g_system->getSavefileManager()->openForLoading(g_sludge->loadNow);
if (fp) {
delete fp;
return BR_KEEP_AND_PAUSE;
}
debug("not find sav file");
g_sludge->loadNow.clear();
return BR_CONTINUE;
}
//--------------------------------------
#pragma mark -
#pragma mark Background image - Painting
builtIn(blankScreen) {
UNUSEDALL
g_sludge->_gfxMan->blankAllScreen();
return BR_CONTINUE;
}
builtIn(blankArea) {
UNUSEDALL
int x1, y1, x2, y2;
if (!fun->stack->thisVar.getValueType(y2, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
if (!fun->stack->thisVar.getValueType(x2, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
if (!fun->stack->thisVar.getValueType(y1, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
if (!fun->stack->thisVar.getValueType(x1, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
g_sludge->_gfxMan->blankScreen(x1, y1, x2, y2);
return BR_CONTINUE;
}
builtIn(darkBackground) {
UNUSEDALL
g_sludge->_gfxMan->darkScreen();
return BR_CONTINUE;
}
builtIn(addOverlay) {
UNUSEDALL
int fileNumber, xPos, yPos;
if (!fun->stack->thisVar.getValueType(yPos, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
if (!fun->stack->thisVar.getValueType(xPos, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
if (!fun->stack->thisVar.getValueType(fileNumber, SVT_FILE))
return BR_ERROR;
trimStack(fun->stack);
g_sludge->_gfxMan->loadBackDrop(fileNumber, xPos, yPos);
return BR_CONTINUE;
}
builtIn(mixOverlay) {
UNUSEDALL
int fileNumber, xPos, yPos;
if (!fun->stack->thisVar.getValueType(yPos, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
if (!fun->stack->thisVar.getValueType(xPos, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
if (!fun->stack->thisVar.getValueType(fileNumber, SVT_FILE))
return BR_ERROR;
trimStack(fun->stack);
g_sludge->_gfxMan->mixBackDrop(fileNumber, xPos, yPos);
return BR_CONTINUE;
}
builtIn(pasteImage) {
UNUSEDALL
int x, y;
if (!fun->stack->thisVar.getValueType(y, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
if (!fun->stack->thisVar.getValueType(x, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
PersonaAnimation *pp = fun->stack->thisVar.getAnimationFromVar();
trimStack(fun->stack);
if (pp == NULL)
return BR_CONTINUE;
g_sludge->_cursorMan->pasteCursor(x, y, pp);
delete pp;
return BR_CONTINUE;
}
#pragma mark -
#pragma mark Background Image - Scrolling
builtIn(setSceneDimensions) {
UNUSEDALL
int x, y;
if (!fun->stack->thisVar.getValueType(y, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
if (!fun->stack->thisVar.getValueType(x, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
if (g_sludge->_gfxMan->killResizeBackdrop(x, y)) {
g_sludge->_gfxMan->blankScreen(0, 0, x, y);
return BR_CONTINUE;
}
fatal("Out of memory creating new backdrop.");
return BR_ERROR;
}
builtIn(aimCamera) {
UNUSEDALL
int cameraX, cameraY;
if (!fun->stack->thisVar.getValueType(cameraY, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
if (!fun->stack->thisVar.getValueType(cameraX, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
g_sludge->_gfxMan->aimCamera(cameraX, cameraY);
return BR_CONTINUE;
}
builtIn(zoomCamera) {
UNUSEDALL
int z;
if (!fun->stack->thisVar.getValueType(z, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
g_sludge->_gfxMan->zoomCamera(z);
return BR_CONTINUE;
}
#pragma mark -
#pragma mark Variables
builtIn(pickOne) {
UNUSEDALL
if (!numParams) {
fatal("Built-in function should have at least 1 parameter");
return BR_ERROR;
}
int i;
i = g_sludge->getRandomSource()->getRandomNumber(numParams - 1);
// Return value
while (numParams--) {
if (i == numParams)
fun->reg.copyFrom(fun->stack->thisVar);
trimStack(fun->stack);
}
return BR_CONTINUE;
}
builtIn(substring) {
UNUSEDALL
Common::String wholeString;
int start, length;
//debugOut ("BUILTIN: substring\n");
if (!fun->stack->thisVar.getValueType(length, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
if (!fun->stack->thisVar.getValueType(start, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
wholeString = fun->stack->thisVar.getTextFromAnyVar();
trimStack(fun->stack);
Common::U32String str32 = wholeString.decode(Common::kUtf8);
if ((int)str32.size() < start + length) {
length = str32.size() - start;
if ((int)str32.size() < start) {
start = 0;
}
}
if (length < 0) {
length = 0;
}
Common::String newString = str32.substr(start, length).encode(Common::kUtf8);
fun->reg.makeTextVar(newString);
return BR_CONTINUE;
}
builtIn(stringLength) {
UNUSEDALL
Common::String newText = fun->stack->thisVar.getTextFromAnyVar();
trimStack(fun->stack);
fun->reg.setVariable(SVT_INT, g_sludge->_txtMan->stringLength(newText));
return BR_CONTINUE;
}
builtIn(newStack) {
UNUSEDALL
fun->reg.unlinkVar();
// Return value
fun->reg.varType = SVT_STACK;
fun->reg.varData.theStack = new StackHandler;
if (!checkNew(fun->reg.varData.theStack))
return BR_ERROR;
fun->reg.varData.theStack->first = NULL;
fun->reg.varData.theStack->last = NULL;
fun->reg.varData.theStack->timesUsed = 1;
while (numParams--) {
if (!addVarToStack(fun->stack->thisVar, fun->reg.varData.theStack->first))
return BR_ERROR;
if (fun->reg.varData.theStack->last == NULL) {
fun->reg.varData.theStack->last = fun->reg.varData.theStack->first;
}
trimStack(fun->stack);
}
return BR_CONTINUE;
}
// wait is exactly the same function, but limited to 2 parameters
#define builtIn_wait builtIn_newStack
builtIn(stackSize) {
UNUSEDALL
switch (fun->stack->thisVar.varType) {
case SVT_STACK:
// Return value
fun->reg.setVariable(SVT_INT, fun->stack->thisVar.varData.theStack->getStackSize());
trimStack(fun->stack);
return BR_CONTINUE;
case SVT_FASTARRAY:
// Return value
fun->reg.setVariable(SVT_INT, fun->stack->thisVar.varData.fastArray->size);
trimStack(fun->stack);
return BR_CONTINUE;
default:
break;
}
fatal("Parameter isn't a stack or a fast array.");
return BR_ERROR;
}
builtIn(copyStack) {
UNUSEDALL
if (fun->stack->thisVar.varType != SVT_STACK) {
fatal("Parameter isn't a stack.");
return BR_ERROR;
}
// Return value
if (!fun->reg.copyStack(fun->stack->thisVar))
return BR_ERROR;
trimStack(fun->stack);
return BR_CONTINUE;
}
builtIn(pushToStack) {
UNUSEDALL
if (fun->stack->next->thisVar.varType != SVT_STACK) {
fatal("Parameter isn't a stack");
return BR_ERROR;
}
if (!addVarToStack(fun->stack->thisVar, fun->stack->next->thisVar.varData.theStack->first))
return BR_ERROR;
if (fun->stack->next->thisVar.varData.theStack->first->next == NULL)
fun->stack->next->thisVar.varData.theStack->last = fun->stack->next->thisVar.varData.theStack->first;
trimStack(fun->stack);
trimStack(fun->stack);
return BR_CONTINUE;
}
builtIn(enqueue) {
UNUSEDALL
if (fun->stack->next->thisVar.varType != SVT_STACK) {
fatal("Parameter isn't a stack");
return BR_ERROR;
}
if (fun->stack->next->thisVar.varData.theStack->first == NULL) {
if (!addVarToStack(fun->stack->thisVar, fun->stack->next->thisVar.varData.theStack->first))
return BR_ERROR;
fun->stack->next->thisVar.varData.theStack->last = fun->stack->next->thisVar.varData.theStack->first;
} else {
if (!addVarToStack(fun->stack->thisVar, fun->stack->next->thisVar.varData.theStack->last->next))
return BR_ERROR;
fun->stack->next->thisVar.varData.theStack->last = fun->stack->next->thisVar.varData.theStack->last->next;
}
trimStack(fun->stack);
trimStack(fun->stack);
return BR_CONTINUE;
}
builtIn(deleteFromStack) {
UNUSEDALL
if (fun->stack->next->thisVar.varType != SVT_STACK) {
fatal("Parameter isn't a stack.");
return BR_ERROR;
}
// Return value
fun->reg.setVariable(SVT_INT, deleteVarFromStack(fun->stack->thisVar, fun->stack->next->thisVar.varData.theStack->first, false));
// Horrible hacking because 'last' value might now be wrong!
VariableStack *nextFirstStack = fun->stack->next->thisVar.varData.theStack->first;
fun->stack->next->thisVar.varData.theStack->last = (nextFirstStack == NULL) ? NULL : nextFirstStack->stackFindLast();
trimStack(fun->stack);
trimStack(fun->stack);
return BR_CONTINUE;
}
builtIn(deleteAllFromStack) {
UNUSEDALL
if (fun->stack->next->thisVar.varType != SVT_STACK) {
fatal("Parameter isn't a stack.");
return BR_ERROR;
}
// Return value
fun->reg.setVariable(SVT_INT, deleteVarFromStack(fun->stack->thisVar, fun->stack->next->thisVar.varData.theStack->first, true));
// Horrible hacking because 'last' value might now be wrong!
VariableStack *nextFirstStack = fun->stack->next->thisVar.varData.theStack->first;
fun->stack->next->thisVar.varData.theStack->last = (nextFirstStack == NULL) ? NULL : nextFirstStack->stackFindLast();
trimStack(fun->stack);
trimStack(fun->stack);
return BR_CONTINUE;
}
builtIn(popFromStack) {
UNUSEDALL
if (fun->stack->thisVar.varType != SVT_STACK) {
fatal("Parameter isn't a stack.");
return BR_ERROR;
}
if (fun->stack->thisVar.varData.theStack->first == NULL) {
fatal("The stack's empty.");
return BR_ERROR;
}
// Return value
fun->reg.copyFrom(fun->stack->thisVar.varData.theStack->first->thisVar);
trimStack(fun->stack->thisVar.varData.theStack->first);
trimStack(fun->stack);
return BR_CONTINUE;
}
builtIn(peekStart) {
UNUSEDALL
if (fun->stack->thisVar.varType != SVT_STACK) {
fatal("Parameter isn't a stack.");
return BR_ERROR;
}
if (fun->stack->thisVar.varData.theStack->first == NULL) {
fatal("The stack's empty.");
return BR_ERROR;
}
// Return value
fun->reg.copyFrom(fun->stack->thisVar.varData.theStack->first->thisVar);
trimStack(fun->stack);
return BR_CONTINUE;
}
builtIn(peekEnd) {
UNUSEDALL
if (fun->stack->thisVar.varType != SVT_STACK) {
fatal("Parameter isn't a stack.");
return BR_ERROR;
}
if (fun->stack->thisVar.varData.theStack->first == NULL) {
fatal("The stack's empty.");
return BR_ERROR;
}
// Return value
fun->reg.copyFrom(fun->stack->thisVar.varData.theStack->last->thisVar);
trimStack(fun->stack);
return BR_CONTINUE;
}
builtIn(random) {
UNUSEDALL
int num;
if (!fun->stack->thisVar.getValueType(num, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
if (num <= 0)
num = 1;
fun->reg.setVariable(SVT_INT, g_sludge->getRandomSource()->getRandomNumber(num - 1));
return BR_CONTINUE;
}
static bool getRGBParams(int &red, int &green, int &blue, LoadedFunction *fun) {
if (!fun->stack->thisVar.getValueType(blue, SVT_INT))
return false;
trimStack(fun->stack);
if (!fun->stack->thisVar.getValueType(green, SVT_INT))
return false;
trimStack(fun->stack);
if (!fun->stack->thisVar.getValueType(red, SVT_INT))
return false;
trimStack(fun->stack);
return true;
}
builtIn(setStatusColour) {
UNUSEDALL
int red, green, blue;
if (!getRGBParams(red, green, blue, fun))
return BR_ERROR;
g_sludge->_statusBar->statusBarColour((byte)red, (byte)green, (byte)blue);
return BR_CONTINUE;
}
builtIn(setLitStatusColour) {
UNUSEDALL
int red, green, blue;
if (!getRGBParams(red, green, blue, fun))
return BR_ERROR;
g_sludge->_statusBar->statusBarLitColour((byte)red, (byte)green, (byte)blue);
return BR_CONTINUE;
}
builtIn(setPasteColour) {
UNUSEDALL
int red, green, blue;
if (!getRGBParams(red, green, blue, fun))
return BR_ERROR;
g_sludge->_txtMan->setPasterColor((byte)red, (byte)green, (byte)blue);
return BR_CONTINUE;
}
builtIn(setBlankColour) {
UNUSEDALL
int red, green, blue;
if (!getRGBParams(red, green, blue, fun))
return BR_ERROR;
g_sludge->_gfxMan->setBlankColor(red, green, blue);
fun->reg.setVariable(SVT_INT, 1);
return BR_CONTINUE;
}
builtIn(setBurnColour) {
UNUSEDALL
int red, green, blue;
if (!getRGBParams(red, green, blue, fun))
return BR_ERROR;
g_sludge->_gfxMan->setBurnColor(red, green, blue);
fun->reg.setVariable(SVT_INT, 1);
return BR_CONTINUE;
}
builtIn(setFont) {
UNUSEDALL
int fileNumber, newHeight;
if (!fun->stack->thisVar.getValueType(newHeight, SVT_INT))
return BR_ERROR;
// newDebug (" Height:", newHeight);
trimStack(fun->stack);
Common::String newText = fun->stack->thisVar.getTextFromAnyVar();
// newDebug (" Character supported:", newText);
trimStack(fun->stack);
if (!fun->stack->thisVar.getValueType(fileNumber, SVT_FILE))
return BR_ERROR;
// newDebug (" File:", fileNumber);
trimStack(fun->stack);
if (!g_sludge->_txtMan->loadFont(fileNumber, newText, newHeight))
return BR_ERROR;
// newDebug (" Done!");
return BR_CONTINUE;
}
builtIn(inFont) {
UNUSEDALL
Common::String newText = fun->stack->thisVar.getTextFromAnyVar();
trimStack(fun->stack);
// Return value
fun->reg.setVariable(SVT_INT, g_sludge->_txtMan->isInFont(newText));
return BR_CONTINUE;
}
builtIn(pasteString) {
UNUSEDALL
Common::String newText = fun->stack->thisVar.getTextFromAnyVar();
trimStack(fun->stack);
int y, x;
if (!fun->stack->thisVar.getValueType(y, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
if (!fun->stack->thisVar.getValueType(x, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
if (x == IN_THE_CENTRE)
x = g_sludge->_gfxMan->getCenterX(g_sludge->_txtMan->stringWidth(newText));
g_sludge->_txtMan->pasteStringToBackdrop(newText, x, y);
return BR_CONTINUE;
}
builtIn(anim) {
UNUSEDALL
if (numParams < 2) {
fatal("Built-in function anim() must have at least 2 parameters.");
return BR_ERROR;
}
// First store the frame numbers and take 'em off the stack
PersonaAnimation *ba = new PersonaAnimation(numParams - 1, fun->stack);
// Only remaining parameter is the file number
int fileNumber;
if (!fun->stack->thisVar.getValueType(fileNumber, SVT_FILE)) {
delete ba;
return BR_ERROR;
}
trimStack(fun->stack);
// Load the required sprite bank
LoadedSpriteBank *sprBanky = g_sludge->_gfxMan->loadBankForAnim(fileNumber);
if (!sprBanky) {
delete ba;
return BR_ERROR; // File not found, fatal done already
}
ba->theSprites = sprBanky;
// Return value
fun->reg.makeAnimationVariable(ba);
return BR_CONTINUE;
}
builtIn(costume) {
UNUSEDALL
Persona *newPersona = new Persona;
if (!checkNew(newPersona))
return BR_ERROR;
newPersona->numDirections = numParams / 3;
if (numParams == 0 || newPersona->numDirections * 3 != numParams) {
fatal("Illegal number of parameters (should be greater than 0 and divisible by 3)");
return BR_ERROR;
}
int iii;
newPersona->animation = new PersonaAnimation *[numParams];
if (!checkNew(newPersona->animation))
return BR_ERROR;
for (iii = numParams - 1; iii >= 0; iii--) {
newPersona->animation[iii] = fun->stack->thisVar.getAnimationFromVar();
trimStack(fun->stack);
}
// Return value
fun->reg.makeCostumeVariable(newPersona);
return BR_CONTINUE;
}
builtIn(launch) {
UNUSEDALL
Common::String newTextA = fun->stack->thisVar.getTextFromAnyVar();
Common::String newText = encodeFilename(newTextA);
trimStack(fun->stack);
if (newTextA[0] == 'h' && newTextA[1] == 't' && newTextA[2] == 't' && newTextA[3] == 'p' &&
(newTextA[4] == ':' || (newTextA[4] == 's' && newTextA[5] == ':'))) {
// IT'S A WEBSITE!
bool success = g_sludge->_system->openUrl(newTextA);
fun->reg.setVariable(SVT_INT, success);
return BR_CONTINUE;
}
// Convert game path to URL
Common::String gameDir = ConfMan.getPath("path").toString('/');
newText = gameDir + newText;
// local webpage?
if (newText.hasSuffixIgnoreCase(".htm") || newText.hasSuffixIgnoreCase(".html")) {
bool success = g_sludge->_system->openUrl("file:///" + newText);
fun->reg.setVariable(SVT_INT, success);
} else {
fun->reg.setVariable(SVT_INT, 0);
}
return BR_CONTINUE;
}
builtIn(pause) {
UNUSEDALL
int theTime;
if (!fun->stack->thisVar.getValueType(theTime, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
if (theTime > 0) {
fun->timeLeft = theTime - 1;
fun->isSpeech = false;
return BR_KEEP_AND_PAUSE;
}
return BR_CONTINUE;
}
builtIn(completeTimers) {
UNUSEDALL
completeTimers();
return BR_CONTINUE;
}
builtIn(callEvent) {
UNUSEDALL
int obj1, obj2;
if (!fun->stack->thisVar.getValueType(obj2, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
if (!fun->stack->thisVar.getValueType(obj1, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
int fNum = g_sludge->_objMan->getCombinationFunction(obj1, obj2);
// Return value
if (fNum) {
fun->reg.setVariable(SVT_FUNC, fNum);
return BR_CALLAFUNC;
}
fun->reg.setVariable(SVT_INT, 0);
return BR_CONTINUE;
}
builtIn(quitGame) {
UNUSEDALL
g_sludge->_evtMan->quitGame();
return BR_CONTINUE;
}
#pragma mark -
#pragma mark Movie functions
// The old movie functions are deprecated and does nothing.
builtIn(_rem_movieStart) {
UNUSEDALL
trimStack(fun->stack);
return BR_CONTINUE;
}
builtIn(_rem_movieAbort) {
UNUSEDALL
fun->reg.setVariable(SVT_INT, 0);
return BR_CONTINUE;
}
builtIn(_rem_moviePlaying) {
UNUSEDALL
fun->reg.setVariable(SVT_INT, 0);
return BR_CONTINUE;
}
builtIn(playMovie) {
UNUSEDALL
int fileNumber, r;
if (movieIsPlaying)
return BR_PAUSE;
if (!fun->stack->thisVar.getValueType(fileNumber, SVT_FILE))
return BR_ERROR;
trimStack(fun->stack);
r = playMovie(fileNumber);
fun->reg.setVariable(SVT_INT, r);
if (r && (!fun->next)) {
restartFunction(fun);
return BR_ALREADY_GONE;
}
return BR_CONTINUE;
}
builtIn(stopMovie) {
UNUSEDALL
stopMovie();
fun->reg.setVariable(SVT_INT, 0);
return BR_CONTINUE;
}
builtIn(pauseMovie) {
UNUSEDALL
pauseMovie();
fun->reg.setVariable(SVT_INT, 0);
return BR_CONTINUE;
}
#pragma mark -
#pragma mark Audio functions
builtIn(startMusic) {
UNUSEDALL
int fromTrack, musChan, fileNumber;
if (!fun->stack->thisVar.getValueType(fromTrack, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
if (!fun->stack->thisVar.getValueType(musChan, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
if (!fun->stack->thisVar.getValueType(fileNumber, SVT_FILE))
return BR_ERROR;
trimStack(fun->stack);
if (!g_sludge->_soundMan->playMOD(fileNumber, musChan, fromTrack))
return BR_CONTINUE; //BR_ERROR;
return BR_CONTINUE;
}
builtIn(stopMusic) {
UNUSEDALL
int v;
if (!fun->stack->thisVar.getValueType(v, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
g_sludge->_soundMan->stopMOD(v);
return BR_CONTINUE;
}
builtIn(setMusicVolume) {
UNUSEDALL
int musChan, v;
if (!fun->stack->thisVar.getValueType(v, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
if (!fun->stack->thisVar.getValueType(musChan, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
g_sludge->_soundMan->setMusicVolume(musChan, v);
return BR_CONTINUE;
}
builtIn(setDefaultMusicVolume) {
UNUSEDALL
int v;
if (!fun->stack->thisVar.getValueType(v, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
g_sludge->_soundMan->setDefaultMusicVolume(v);
return BR_CONTINUE;
}
builtIn(playSound) {
UNUSEDALL
int fileNumber;
if (!fun->stack->thisVar.getValueType(fileNumber, SVT_FILE))
return BR_ERROR;
trimStack(fun->stack);
if (!g_sludge->_soundMan->startSound(fileNumber, false))
return BR_CONTINUE; // Was BR_ERROR
return BR_CONTINUE;
}
builtIn(loopSound) {
UNUSEDALL
int fileNumber;
if (numParams < 1) {
fatal("Built-in function loopSound() must have at least 1 parameter.");
return BR_ERROR;
} else if (numParams < 2) {
if (!fun->stack->thisVar.getValueType(fileNumber, SVT_FILE))
return BR_ERROR;
trimStack(fun->stack);
if (!g_sludge->_soundMan->startSound(fileNumber, true))
return BR_CONTINUE; // Was BR_ERROR
return BR_CONTINUE;
} else {
// We have more than one sound to play!
int doLoop = 2;
SoundList*s = NULL;
SoundList*old = NULL;
// Should we loop?
if (fun->stack->thisVar.varType != SVT_FILE) {
fun->stack->thisVar.getValueType(doLoop, SVT_INT);
trimStack(fun->stack);
numParams--;
}
while (numParams) {
if (!fun->stack->thisVar.getValueType(fileNumber, SVT_FILE)) {
fatal("Illegal parameter given built-in function loopSound().");
return BR_ERROR;
}
s = new SoundList;
if (!checkNew(s))
return BR_ERROR;
s->next = old;
s->prev = NULL;
s->sound = fileNumber;
old = s;
trimStack(fun->stack);
numParams--;
}
while (s->next)
s = s->next;
if (doLoop > 1) {
s->next = old;
old->prev = s;
} else if (doLoop) {
s->next = s;
}
old->vol = -1;
g_sludge->_soundMan->playSoundList(old);
return BR_CONTINUE;
}
}
builtIn(stopSound) {
UNUSEDALL
int v;
if (!fun->stack->thisVar.getValueType(v, SVT_FILE))
return BR_ERROR;
trimStack(fun->stack);
g_sludge->_soundMan->huntKillSound(v);
return BR_CONTINUE;
}
builtIn(setDefaultSoundVolume) {
UNUSEDALL
int v;
if (!fun->stack->thisVar.getValueType(v, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
g_sludge->_soundMan->setDefaultSoundVolume(v);
return BR_CONTINUE;
}
builtIn(setSoundVolume) {
UNUSEDALL
int musChan, v;
if (!fun->stack->thisVar.getValueType(v, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
if (!fun->stack->thisVar.getValueType(musChan, SVT_FILE))
return BR_ERROR;
trimStack(fun->stack);
g_sludge->_soundMan->setSoundVolume(musChan, v);
return BR_CONTINUE;
}
builtIn(setSoundLoopPoints) {
UNUSEDALL
int musChan, theEnd, theStart;
if (!fun->stack->thisVar.getValueType(theEnd, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
if (!fun->stack->thisVar.getValueType(theStart, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
if (!fun->stack->thisVar.getValueType(musChan, SVT_FILE))
return BR_ERROR;
trimStack(fun->stack);
g_sludge->_soundMan->setSoundLoop(musChan, theStart, theEnd);
return BR_CONTINUE;
}
#pragma mark -
#pragma mark Extra room bits
builtIn(setFloor) {
UNUSEDALL
if (fun->stack->thisVar.varType == SVT_FILE) {
int v;
fun->stack->thisVar.getValueType(v, SVT_FILE);
trimStack(fun->stack);
if (!g_sludge->_floorMan->setFloor(v))
return BR_ERROR;
} else {
trimStack(fun->stack);
g_sludge->_floorMan->setFloorNull();
}
return BR_CONTINUE;
}
builtIn(showFloor) {
UNUSEDALL
g_sludge->_floorMan->drawFloor();
return BR_CONTINUE;
}
builtIn(setZBuffer) {
UNUSEDALL
if (fun->stack->thisVar.varType == SVT_FILE) {
int v;
fun->stack->thisVar.getValueType(v, SVT_FILE);
trimStack(fun->stack);
if (!g_sludge->_gfxMan->setZBuffer(v))
return BR_ERROR;
} else {
trimStack(fun->stack);
g_sludge->_gfxMan->killZBuffer();
}
return BR_CONTINUE;
}
builtIn(setLightMap) {
UNUSEDALL
switch (numParams) {
case 2:
if (!fun->stack->thisVar.getValueType(g_sludge->_gfxMan->_lightMapMode, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
g_sludge->_gfxMan->_lightMapMode %= LIGHTMAPMODE_NUM;
// fall through
case 1:
if (fun->stack->thisVar.varType == SVT_FILE) {
int v;
fun->stack->thisVar.getValueType(v, SVT_FILE);
trimStack(fun->stack);
if (!g_sludge->_gfxMan->loadLightMap(v))
return BR_ERROR;
fun->reg.setVariable(SVT_INT, 1);
} else {
trimStack(fun->stack);
g_sludge->_gfxMan->killLightMap();
fun->reg.setVariable(SVT_INT, 0);
}
break;
default:
fatal("Function should have either 2 or 3 parameters");
return BR_ERROR;
}
return BR_CONTINUE;
}
#pragma mark -
#pragma mark Objects
builtIn(setSpeechMode) {
UNUSEDALL
int speechMode;
if (!fun->stack->thisVar.getValueType(speechMode, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
if (speechMode < 0 || speechMode > 2) {
fatal("Valid parameters are be SPEECHANDTEXT, SPEECHONLY or TEXTONLY");
return BR_ERROR;
}
g_sludge->_speechMan->setSpeechMode(speechMode);
return BR_CONTINUE;
}
builtIn(somethingSpeaking) {
UNUSEDALL
int i = g_sludge->_speechMan->isThereAnySpeechGoingOn();
if (i == -1) {
fun->reg.setVariable(SVT_INT, 0);
} else {
fun->reg.setVariable(SVT_OBJTYPE, i);
}
return BR_CONTINUE;
}
builtIn(skipSpeech) {
UNUSEDALL
killSpeechTimers();
return BR_CONTINUE;
}
builtIn(getOverObject) {
UNUSEDALL
if (g_sludge->_regionMan->getOverRegion())
// Return value
fun->reg.setVariable(SVT_OBJTYPE, g_sludge->_regionMan->getOverRegion()->thisType->objectNum);
else
// Return value
fun->reg.setVariable(SVT_INT, 0);
return BR_CONTINUE;
}
builtIn(rename) {
UNUSEDALL
Common::String newText = fun->stack->thisVar.getTextFromAnyVar();
int objT;
trimStack(fun->stack);
if (!fun->stack->thisVar.getValueType(objT, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
ObjectType *o = g_sludge->_objMan->findObjectType(objT);
o->screenName.clear();
o->screenName = newText;
return BR_CONTINUE;
}
builtIn(getObjectX) {
UNUSEDALL
int objectNumber;
if (!fun->stack->thisVar.getValueType(objectNumber, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
OnScreenPerson *pers = g_sludge->_peopleMan->findPerson(objectNumber);
if (pers) {
fun->reg.setVariable(SVT_INT, pers->x);
} else {
ScreenRegion *la = g_sludge->_regionMan->getRegionForObject(objectNumber);
if (la) {
fun->reg.setVariable(SVT_INT, la->sX);
} else {
fun->reg.setVariable(SVT_INT, 0);
}
}
return BR_CONTINUE;
}
builtIn(getObjectY) {
UNUSEDALL
int objectNumber;
if (!fun->stack->thisVar.getValueType(objectNumber, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
OnScreenPerson *pers = g_sludge->_peopleMan->findPerson(objectNumber);
if (pers) {
fun->reg.setVariable(SVT_INT, pers->y);
} else {
ScreenRegion *la = g_sludge->_regionMan->getRegionForObject(objectNumber);
if (la) {
fun->reg.setVariable(SVT_INT, la->sY);
} else {
fun->reg.setVariable(SVT_INT, 0);
}
}
return BR_CONTINUE;
}
builtIn(addScreenRegion) {
UNUSEDALL
int sX, sY, x1, y1, x2, y2, di, objectNumber;
if (!fun->stack->thisVar.getValueType(di, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
if (!fun->stack->thisVar.getValueType(sY, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
if (!fun->stack->thisVar.getValueType(sX, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
if (!fun->stack->thisVar.getValueType(y2, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
if (!fun->stack->thisVar.getValueType(x2, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
if (!fun->stack->thisVar.getValueType(y1, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
if (!fun->stack->thisVar.getValueType(x1, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
if (!fun->stack->thisVar.getValueType(objectNumber, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
if (g_sludge->_regionMan->addScreenRegion(x1, y1, x2, y2, sX, sY, di, objectNumber))
return BR_CONTINUE;
return BR_ERROR;
}
builtIn(removeScreenRegion) {
UNUSEDALL
int objectNumber;
if (!fun->stack->thisVar.getValueType(objectNumber, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
g_sludge->_regionMan->removeScreenRegion(objectNumber);
return BR_CONTINUE;
}
builtIn(showBoxes) {
UNUSEDALL
g_sludge->_regionMan->showBoxes();
return BR_CONTINUE;
}
builtIn(removeAllScreenRegions) {
UNUSEDALL
g_sludge->_regionMan->kill();
return BR_CONTINUE;
}
builtIn(addCharacter) {
UNUSEDALL
Persona *p;
int x, y, objectNumber;
p = fun->stack->thisVar.getCostumeFromVar();
if (p == NULL)
return BR_ERROR;
trimStack(fun->stack);
if (!fun->stack->thisVar.getValueType(y, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
if (!fun->stack->thisVar.getValueType(x, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
if (!fun->stack->thisVar.getValueType(objectNumber, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
if (g_sludge->_peopleMan->addPerson(x, y, objectNumber, p))
return BR_CONTINUE;
return BR_ERROR;
}
builtIn(hideCharacter) {
UNUSEDALL
int objectNumber;
if (!fun->stack->thisVar.getValueType(objectNumber, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
g_sludge->_peopleMan->setShown(false, objectNumber);
return BR_CONTINUE;
}
builtIn(showCharacter) {
UNUSEDALL
int objectNumber;
if (!fun->stack->thisVar.getValueType(objectNumber, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
g_sludge->_peopleMan->setShown(true, objectNumber);
return BR_CONTINUE;
}
builtIn(removeAllCharacters) {
UNUSEDALL
killSpeechTimers();
g_sludge->_peopleMan->killMostPeople();
return BR_CONTINUE;
}
builtIn(setCharacterDrawMode) {
UNUSEDALL
int obj, di;
if (!fun->stack->thisVar.getValueType(di, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
if (!fun->stack->thisVar.getValueType(obj, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
g_sludge->_peopleMan->setDrawMode(di, obj);
return BR_CONTINUE;
}
builtIn(setCharacterTransparency) {
UNUSEDALL
int obj, x;
if (!fun->stack->thisVar.getValueType(x, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
if (!fun->stack->thisVar.getValueType(obj, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
g_sludge->_peopleMan->setPersonTransparency(obj, x);
return BR_CONTINUE;
}
builtIn(setCharacterColourise) {
UNUSEDALL
int obj, r, g, b, mix;
if (!fun->stack->thisVar.getValueType(mix, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
if (!fun->stack->thisVar.getValueType(b, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
if (!fun->stack->thisVar.getValueType(g, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
if (!fun->stack->thisVar.getValueType(r, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
if (!fun->stack->thisVar.getValueType(obj, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
g_sludge->_peopleMan->setPersonColourise(obj, r, g, b, mix);
return BR_CONTINUE;
}
builtIn(setScale) {
UNUSEDALL
int val1, val2;
if (!fun->stack->thisVar.getValueType(val2, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
if (!fun->stack->thisVar.getValueType(val1, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
g_sludge->_peopleMan->setScale((int16)val1, (int16)val2);
return BR_CONTINUE;
}
builtIn(stopCharacter) {
UNUSEDALL
int obj;
if (!fun->stack->thisVar.getValueType(obj, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
// Return value
fun->reg.setVariable(SVT_INT, g_sludge->_peopleMan->stopPerson(obj));
return BR_CONTINUE;
}
builtIn(pasteCharacter) {
UNUSEDALL
int obj;
if (!fun->stack->thisVar.getValueType(obj, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
OnScreenPerson *thisPerson = g_sludge->_peopleMan->findPerson(obj);
if (thisPerson) {
PersonaAnimation *myAnim;
myAnim = thisPerson->myAnim;
if (myAnim != thisPerson->lastUsedAnim) {
thisPerson->lastUsedAnim = myAnim;
thisPerson->frameNum = 0;
thisPerson->frameTick = myAnim->frames[0].howMany;
}
int fNum = myAnim->frames[thisPerson->frameNum].frameNum;
g_sludge->_gfxMan->fixScaleSprite(thisPerson->x, thisPerson->y, myAnim->theSprites->bank.sprites[ABS(fNum)], myAnim->theSprites->bank.myPalette, thisPerson, 0, 0, fNum < 0);
fun->reg.setVariable(SVT_INT, 1);
} else {
fun->reg.setVariable(SVT_INT, 0);
}
return BR_CONTINUE;
}
builtIn(animate) {
UNUSEDALL
int obj;
PersonaAnimation *pp = fun->stack->thisVar.getAnimationFromVar();
if (pp == NULL)
return BR_ERROR;
trimStack(fun->stack);
if (!fun->stack->thisVar.getValueType(obj, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
g_sludge->_peopleMan->animatePerson(obj, pp);
fun->reg.setVariable(SVT_INT, pp->getTotalTime());
return BR_CONTINUE;
}
builtIn(setCostume) {
UNUSEDALL
int obj;
Persona *pp = fun->stack->thisVar.getCostumeFromVar();
if (pp == NULL)
return BR_ERROR;
trimStack(fun->stack);
if (!fun->stack->thisVar.getValueType(obj, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
g_sludge->_peopleMan->animatePerson(obj, pp);
return BR_CONTINUE;
}
builtIn(floatCharacter) {
UNUSEDALL
int obj, di;
if (!fun->stack->thisVar.getValueType(di, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
if (!fun->stack->thisVar.getValueType(obj, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
fun->reg.setVariable(SVT_INT, g_sludge->_peopleMan->floatCharacter(di, obj));
return BR_CONTINUE;
}
builtIn(setCharacterWalkSpeed) {
UNUSEDALL
int obj, di;
if (!fun->stack->thisVar.getValueType(di, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
if (!fun->stack->thisVar.getValueType(obj, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
fun->reg.setVariable(SVT_INT, g_sludge->_peopleMan->setCharacterWalkSpeed(di, obj));
return BR_CONTINUE;
}
builtIn(turnCharacter) {
UNUSEDALL
int obj, di;
if (!fun->stack->thisVar.getValueType(di, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
if (!fun->stack->thisVar.getValueType(obj, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
fun->reg.setVariable(SVT_INT, g_sludge->_peopleMan->turnPersonToFace(obj, di));
return BR_CONTINUE;
}
builtIn(setCharacterExtra) {
UNUSEDALL
int obj, di;
if (!fun->stack->thisVar.getValueType(di, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
if (!fun->stack->thisVar.getValueType(obj, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
fun->reg.setVariable(SVT_INT, g_sludge->_peopleMan->setPersonExtra(obj, di));
return BR_CONTINUE;
}
builtIn(removeCharacter) {
UNUSEDALL
int objectNumber;
if (!fun->stack->thisVar.getValueType(objectNumber, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
g_sludge->_peopleMan->removeOneCharacter(objectNumber);
return BR_CONTINUE;
}
static BuiltReturn moveChr(int numParams, LoadedFunction *fun, bool force, bool immediate) {
switch (numParams) {
case 3: {
int x, y, objectNumber;
if (!fun->stack->thisVar.getValueType(y, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
if (!fun->stack->thisVar.getValueType(x, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
if (!fun->stack->thisVar.getValueType(objectNumber, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
if (force) {
if (g_sludge->_peopleMan->forceWalkingPerson(x, y, objectNumber, fun, -1))
return BR_PAUSE;
} else if (immediate) {
g_sludge->_peopleMan->jumpPerson(x, y, objectNumber);
} else {
if (g_sludge->_peopleMan->makeWalkingPerson(x, y, objectNumber, fun, -1))
return BR_PAUSE;
}
return BR_CONTINUE;
}
case 2: {
int toObj, objectNumber;
ScreenRegion*reggie;
if (!fun->stack->thisVar.getValueType(toObj, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
if (!fun->stack->thisVar.getValueType(objectNumber, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
reggie = g_sludge->_regionMan->getRegionForObject(toObj);
if (reggie == NULL)
return BR_CONTINUE;
if (force) {
if (g_sludge->_peopleMan->forceWalkingPerson(reggie->sX, reggie->sY, objectNumber, fun, reggie->di))
return BR_PAUSE;
} else if (immediate) {
g_sludge->_peopleMan->jumpPerson(reggie->sX, reggie->sY, objectNumber);
} else {
if (g_sludge->_peopleMan->makeWalkingPerson(reggie->sX, reggie->sY, objectNumber, fun, reggie->di))
return BR_PAUSE;
}
return BR_CONTINUE;
}
default:
fatal("Built-in function must have either 2 or 3 parameters.");
return BR_ERROR;
}
}
builtIn(moveCharacter) {
UNUSEDALL
return moveChr(numParams, fun, false, false);
}
builtIn(forceCharacter) {
UNUSEDALL
return moveChr(numParams, fun, true, false);
}
builtIn(jumpCharacter) {
UNUSEDALL
return moveChr(numParams, fun, false, true);
}
builtIn(clearStatus) {
UNUSEDALL
g_sludge->_statusBar->clear();
return BR_CONTINUE;
}
builtIn(removeLastStatus) {
UNUSEDALL
g_sludge->_statusBar->killLastStatus();
return BR_CONTINUE;
}
builtIn(addStatus) {
UNUSEDALL
g_sludge->_statusBar->addStatusBar();
return BR_CONTINUE;
}
builtIn(statusText) {
UNUSEDALL
Common::String newText = fun->stack->thisVar.getTextFromAnyVar();
trimStack(fun->stack);
g_sludge->_statusBar->set(newText);
return BR_CONTINUE;
}
builtIn(lightStatus) {
UNUSEDALL
int val;
if (!fun->stack->thisVar.getValueType(val, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
g_sludge->_statusBar->setLitStatus(val);
return BR_CONTINUE;
}
builtIn(positionStatus) {
UNUSEDALL
int x, y;
if (!fun->stack->thisVar.getValueType(y, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
if (!fun->stack->thisVar.getValueType(x, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
g_sludge->_statusBar->positionStatus(x, y);
return BR_CONTINUE;
}
builtIn(alignStatus) {
UNUSEDALL
int val;
if (!fun->stack->thisVar.getValueType(val, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
g_sludge->_statusBar->setAlignStatus(val);
return BR_CONTINUE;
}
static bool getFuncNumForCallback(int numParams, LoadedFunction *fun, int &functionNum) {
switch (numParams) {
case 0:
functionNum = 0;
break;
case 1:
if (!fun->stack->thisVar.getValueType(functionNum, SVT_FUNC))
return false;
trimStack(fun->stack);
break;
default:
fatal("Too many parameters.");
return false;
}
return true;
}
builtIn(onLeftMouse) {
UNUSEDALL
int functionNum;
if (getFuncNumForCallback(numParams, fun, functionNum)) {
g_sludge->_evtMan->setEventFunction(kLeftMouse, functionNum);
return BR_CONTINUE;
}
return BR_ERROR;
}
builtIn(onLeftMouseUp) {
UNUSEDALL
int functionNum;
if (getFuncNumForCallback(numParams, fun, functionNum)) {
g_sludge->_evtMan->setEventFunction(kLeftMouseUp, functionNum);
return BR_CONTINUE;
}
return BR_ERROR;
}
builtIn(onRightMouse) {
UNUSEDALL
int functionNum;
if (getFuncNumForCallback(numParams, fun, functionNum)) {
g_sludge->_evtMan->setEventFunction(kRightMouse, functionNum);
return BR_CONTINUE;
}
return BR_ERROR;
}
builtIn(onRightMouseUp) {
UNUSEDALL
int functionNum;
if (getFuncNumForCallback(numParams, fun, functionNum)) {
g_sludge->_evtMan->setEventFunction(kRightMouseUp, functionNum);
return BR_CONTINUE;
}
return BR_ERROR;
}
builtIn(onFocusChange) {
UNUSEDALL
int functionNum;
if (getFuncNumForCallback(numParams, fun, functionNum)) {
g_sludge->_evtMan->setEventFunction(kFocus, functionNum);
return BR_CONTINUE;
}
return BR_ERROR;
}
builtIn(onMoveMouse) {
UNUSEDALL
int functionNum;
if (getFuncNumForCallback(numParams, fun, functionNum)) {
g_sludge->_evtMan->setEventFunction(kMoveMouse, functionNum);
return BR_CONTINUE;
}
return BR_ERROR;
}
builtIn(onKeyboard) {
UNUSEDALL
int functionNum;
if (getFuncNumForCallback(numParams, fun, functionNum)) {
g_sludge->_evtMan->setEventFunction(kSpace, functionNum);
return BR_CONTINUE;
}
return BR_ERROR;
}
builtIn(spawnSub) {
UNUSEDALL
int functionNum;
if (getFuncNumForCallback(numParams, fun, functionNum)) {
if (!startNewFunctionNum(functionNum, 0, NULL, noStack))
return BR_ERROR;
return BR_CONTINUE;
}
return BR_ERROR;
}
builtIn(cancelSub) {
UNUSEDALL
int functionNum;
if (getFuncNumForCallback(numParams, fun, functionNum)) {
bool killedMyself;
cancelAFunction(functionNum, fun, killedMyself);
if (killedMyself) {
abortFunction(fun);
return BR_ALREADY_GONE;
}
return BR_CONTINUE;
}
return BR_ERROR;
}
builtIn(stringWidth) {
UNUSEDALL
Common::String theText = fun->stack->thisVar.getTextFromAnyVar();
trimStack(fun->stack);
// Return value
fun->reg.setVariable(SVT_INT, g_sludge->_txtMan->stringWidth(theText));
return BR_CONTINUE;
}
builtIn(hardScroll) {
UNUSEDALL
int v;
if (!fun->stack->thisVar.getValueType(v, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
g_sludge->_gfxMan->hardScroll(v);
return BR_CONTINUE;
}
builtIn(isScreenRegion) {
UNUSEDALL
int objectNumber;
if (!fun->stack->thisVar.getValueType(objectNumber, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
fun->reg.setVariable(SVT_INT, g_sludge->_regionMan->getRegionForObject(objectNumber) != NULL);
return BR_CONTINUE;
}
builtIn(setSpeechSpeed) {
UNUSEDALL
int number;
if (!fun->stack->thisVar.getValueType(number, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
g_sludge->_speechMan->setSpeechSpeed(number * 0.01);
fun->reg.setVariable(SVT_INT, 1);
return BR_CONTINUE;
}
builtIn(setFontSpacing) {
UNUSEDALL
int fontSpaceI;
if (!fun->stack->thisVar.getValueType(fontSpaceI, SVT_INT))
return BR_ERROR;
g_sludge->_txtMan->setFontSpace(fontSpaceI);
trimStack(fun->stack);
fun->reg.setVariable(SVT_INT, 1);
return BR_CONTINUE;
}
builtIn(transitionLevel) {
UNUSEDALL
int brightnessLevel;
if (!fun->stack->thisVar.getValueType(brightnessLevel, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
g_sludge->_gfxMan->setBrightnessLevel(brightnessLevel);
fun->reg.setVariable(SVT_INT, 1);
return BR_CONTINUE;
}
builtIn(captureAllKeys) {
UNUSEDALL
// This built-in function doesn't have any effect any more, we capture all keys by default
bool captureAllKeysDeprecated = fun->stack->thisVar.getBoolean();
trimStack(fun->stack);
fun->reg.setVariable(SVT_INT, captureAllKeysDeprecated);
return BR_CONTINUE;
}
builtIn(spinCharacter) {
UNUSEDALL
int number, objectNumber;
if (!fun->stack->thisVar.getValueType(number, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
if (!fun->stack->thisVar.getValueType(objectNumber, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
OnScreenPerson *thisPerson = g_sludge->_peopleMan->findPerson(objectNumber);
if (thisPerson) {
thisPerson->wantAngle = number;
thisPerson->spinning = true;
thisPerson->continueAfterWalking = fun;
fun->reg.setVariable(SVT_INT, 1);
return BR_PAUSE;
} else {
fun->reg.setVariable(SVT_INT, 0);
return BR_CONTINUE;
}
}
builtIn(getCharacterDirection) {
UNUSEDALL
int objectNumber;
if (!fun->stack->thisVar.getValueType(objectNumber, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
OnScreenPerson *thisPerson = g_sludge->_peopleMan->findPerson(objectNumber);
if (thisPerson) {
fun->reg.setVariable(SVT_INT, thisPerson->direction);
} else {
fun->reg.setVariable(SVT_INT, 0);
}
return BR_CONTINUE;
}
builtIn(isCharacter) {
UNUSEDALL
int objectNumber;
if (!fun->stack->thisVar.getValueType(objectNumber, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
OnScreenPerson *thisPerson = g_sludge->_peopleMan->findPerson(objectNumber);
fun->reg.setVariable(SVT_INT, thisPerson != NULL);
return BR_CONTINUE;
}
builtIn(normalCharacter) {
UNUSEDALL
int objectNumber;
if (!fun->stack->thisVar.getValueType(objectNumber, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
OnScreenPerson *thisPerson = g_sludge->_peopleMan->findPerson(objectNumber);
if (thisPerson) {
thisPerson->myAnim = thisPerson->myPersona->animation[thisPerson->direction];
fun->reg.setVariable(SVT_INT, 1);
} else {
fun->reg.setVariable(SVT_INT, 0);
}
return BR_CONTINUE;
}
builtIn(isMoving) {
UNUSEDALL
int objectNumber;
if (!fun->stack->thisVar.getValueType(objectNumber, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
OnScreenPerson *thisPerson = g_sludge->_peopleMan->findPerson(objectNumber);
if (thisPerson) {
fun->reg.setVariable(SVT_INT, thisPerson->walking);
} else {
fun->reg.setVariable(SVT_INT, 0);
}
return BR_CONTINUE;
}
builtIn(fetchEvent) {
UNUSEDALL
int obj1, obj2;
if (!fun->stack->thisVar.getValueType(obj2, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
if (!fun->stack->thisVar.getValueType(obj1, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
int fNum = g_sludge->_objMan->getCombinationFunction(obj1, obj2);
// Return value
if (fNum) {
fun->reg.setVariable(SVT_FUNC, fNum);
} else {
fun->reg.setVariable(SVT_INT, 0);
}
return BR_CONTINUE;
}
builtIn(deleteFile) {
UNUSEDALL
Common::String namNormal = fun->stack->thisVar.getTextFromAnyVar();
trimStack(fun->stack);
Common::String nam = encodeFilename(namNormal);
namNormal.clear();
if (failSecurityCheck(nam))
return BR_ERROR;
fun->reg.setVariable(SVT_INT, !g_system->getSavefileManager()->removeSavefile(nam));
return BR_CONTINUE;
}
builtIn(renameFile) {
UNUSEDALL
Common::String temp;
temp.clear();
temp = fun->stack->thisVar.getTextFromAnyVar();
Common::String newnam = encodeFilename(temp);
trimStack(fun->stack);
if (failSecurityCheck(newnam))
return BR_ERROR;
temp.clear();
temp = fun->stack->thisVar.getTextFromAnyVar();
Common::String nam = encodeFilename(temp);
trimStack(fun->stack);
if (failSecurityCheck(nam))
return BR_ERROR;
fun->reg.setVariable(SVT_INT, !g_system->getSavefileManager()->renameSavefile(nam, newnam));
return BR_CONTINUE;
}
builtIn(cacheSound) {
UNUSEDALL
int fileNumber;
if (!fun->stack->thisVar.getValueType(fileNumber, SVT_FILE))
return BR_ERROR;
trimStack(fun->stack);
if (g_sludge->_soundMan->cacheSound(fileNumber) == -1)
return BR_ERROR;
return BR_CONTINUE;
}
builtIn(burnString) {
UNUSEDALL
Common::String newText = fun->stack->thisVar.getTextFromAnyVar();
trimStack(fun->stack);
int y, x;
if (!fun->stack->thisVar.getValueType(y, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
if (!fun->stack->thisVar.getValueType(x, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
if (x == IN_THE_CENTRE)
x = g_sludge->_gfxMan->getCenterX(g_sludge->_txtMan->stringWidth(newText));
g_sludge->_txtMan->burnStringToBackdrop(newText, x, y);
return BR_CONTINUE;
}
builtIn(setCharacterSpinSpeed) {
UNUSEDALL
int speed, who;
if (!fun->stack->thisVar.getValueType(speed, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
if (!fun->stack->thisVar.getValueType(who, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
OnScreenPerson *thisPerson = g_sludge->_peopleMan->findPerson(who);
if (thisPerson) {
thisPerson->spinSpeed = speed;
fun->reg.setVariable(SVT_INT, 1);
} else {
fun->reg.setVariable(SVT_INT, 0);
}
return BR_CONTINUE;
}
builtIn(setCharacterAngleOffset) {
UNUSEDALL
int angle, who;
if (!fun->stack->thisVar.getValueType(angle, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
if (!fun->stack->thisVar.getValueType(who, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
OnScreenPerson *thisPerson = g_sludge->_peopleMan->findPerson(who);
if (thisPerson) {
thisPerson->angleOffset = angle;
fun->reg.setVariable(SVT_INT, 1);
} else {
fun->reg.setVariable(SVT_INT, 0);
}
return BR_CONTINUE;
}
builtIn(transitionMode) {
UNUSEDALL
int n;
if (!fun->stack->thisVar.getValueType(n, SVT_INT))
return BR_ERROR;
g_sludge->_gfxMan->setFadeMode(n);
trimStack(fun->stack);
fun->reg.setVariable(SVT_INT, 1);
return BR_CONTINUE;
}
// Removed function - does nothing
builtIn(_rem_updateDisplay) {
UNUSEDALL
trimStack(fun->stack);
fun->reg.setVariable(SVT_INT, true);
return BR_CONTINUE;
}
builtIn(getSoundCache) {
UNUSEDALL
fun->reg.varType = SVT_STACK;
fun->reg.varData.theStack = new StackHandler;
if (!checkNew(fun->reg.varData.theStack))
return BR_ERROR;
fun->reg.varData.theStack->first = NULL;
fun->reg.varData.theStack->last = NULL;
fun->reg.varData.theStack->timesUsed = 1;
if (!g_sludge->_soundMan->getSoundCacheStack(fun->reg.varData.theStack))
return BR_ERROR;
return BR_CONTINUE;
}
builtIn(saveCustomData) {
UNUSEDALL
// saveCustomData (thisStack, fileName);
Common::String fileNameB = fun->stack->thisVar.getTextFromAnyVar();
Common::String fileName = encodeFilename(fileNameB);
if (failSecurityCheck(fileName))
return BR_ERROR;
trimStack(fun->stack);
if (fun->stack->thisVar.varType != SVT_STACK) {
fatal("First parameter isn't a stack");
return BR_ERROR;
}
if (!CustomSaveHelper::stackToFile(fileName, fun->stack->thisVar))
return BR_ERROR;
trimStack(fun->stack);
return BR_CONTINUE;
}
builtIn(loadCustomData) {
UNUSEDALL
Common::String newTextA = fun->stack->thisVar.getTextFromAnyVar();
Common::String newText = encodeFilename(newTextA);
if (failSecurityCheck(newText))
return BR_ERROR;
trimStack(fun->stack);
fun->reg.unlinkVar();
fun->reg.varType = SVT_STACK;
fun->reg.varData.theStack = new StackHandler;
if (!checkNew(fun->reg.varData.theStack))
return BR_ERROR;
fun->reg.varData.theStack->first = NULL;
fun->reg.varData.theStack->last = NULL;
fun->reg.varData.theStack->timesUsed = 1;
if (!CustomSaveHelper::fileToStack(newText, fun->reg.varData.theStack))
return BR_ERROR;
return BR_CONTINUE;
}
builtIn(setCustomEncoding) {
UNUSEDALL
int n;
if (!fun->stack->thisVar.getValueType(n, SVT_INT))
return BR_ERROR;
CustomSaveHelper::_saveEncoding = n;
trimStack(fun->stack);
fun->reg.setVariable(SVT_INT, 1);
return BR_CONTINUE;
}
builtIn(freeSound) {
UNUSEDALL
int v;
if (!fun->stack->thisVar.getValueType(v, SVT_FILE))
return BR_ERROR;
trimStack(fun->stack);
g_sludge->_soundMan->huntKillFreeSound(v);
return BR_CONTINUE;
}
builtIn(parallaxAdd) {
UNUSEDALL
if (g_sludge->_gfxMan->isFrozen()) {
fatal("Can't set background parallax image while frozen");
return BR_ERROR;
} else {
int wrapX, wrapY, v;
if (!fun->stack->thisVar.getValueType(wrapY, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
if (!fun->stack->thisVar.getValueType(wrapX, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
if (!fun->stack->thisVar.getValueType(v, SVT_FILE))
return BR_ERROR;
trimStack(fun->stack);
if (!g_sludge->_gfxMan->loadParallax(v, wrapX, wrapY))
return BR_ERROR;
fun->reg.setVariable(SVT_INT, 1);
}
return BR_CONTINUE;
}
builtIn(parallaxClear) {
UNUSEDALL
g_sludge->_gfxMan->killParallax();
fun->reg.setVariable(SVT_INT, 1);
return BR_CONTINUE;
}
builtIn(getPixelColour) {
UNUSEDALL
int x, y;
if (!fun->stack->thisVar.getValueType(y, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
if (!fun->stack->thisVar.getValueType(x, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
fun->reg.unlinkVar();
fun->reg.varType = SVT_STACK;
fun->reg.varData.theStack = new StackHandler;
if (!checkNew(fun->reg.varData.theStack))
return BR_ERROR;
fun->reg.varData.theStack->first = NULL;
fun->reg.varData.theStack->last = NULL;
fun->reg.varData.theStack->timesUsed = 1;
if (!g_sludge->_gfxMan->getRGBIntoStack(x, y, fun->reg.varData.theStack))
return BR_ERROR;
return BR_CONTINUE;
}
builtIn(makeFastArray) {
UNUSEDALL
switch (fun->stack->thisVar.varType) {
case SVT_STACK: {
bool success = fun->reg.makeFastArrayFromStack(fun->stack->thisVar.varData.theStack);
trimStack(fun->stack);
return success ? BR_CONTINUE : BR_ERROR;
}
break;
case SVT_INT: {
int i = fun->stack->thisVar.varData.intValue;
trimStack(fun->stack);
return fun->reg.makeFastArraySize(i) ? BR_CONTINUE : BR_ERROR;
}
break;
default:
break;
}
fatal("Parameter must be a number or a stack.");
return BR_ERROR;
}
builtIn(getCharacterScale) {
UNUSEDALL
int objectNumber;
if (!fun->stack->thisVar.getValueType(objectNumber, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
OnScreenPerson *pers = g_sludge->_peopleMan->findPerson(objectNumber);
if (pers) {
fun->reg.setVariable(SVT_INT, pers->scale * 100);
} else {
fun->reg.setVariable(SVT_INT, 0);
}
return BR_CONTINUE;
}
builtIn(getLanguageID) {
UNUSEDALL
fun->reg.setVariable(SVT_INT, g_sludge->getLanguageID());
return BR_CONTINUE;
}
// Removed function
builtIn(_rem_launchWith) {
UNUSEDALL
trimStack(fun->stack);
// To support some windows only games
Common::String filename = fun->stack->thisVar.getTextFromAnyVar();
trimStack(fun->stack);
if (filename.hasSuffix(".exe")) {
const Common::FSNode gameDataDir(ConfMan.getPath("path"));
Common::FSList files;
gameDataDir.getChildren(files, Common::FSNode::kListFilesOnly);
if (!files.empty()) {
for (Common::FSList::const_iterator file = files.begin(); file != files.end(); ++file) {
Common::String fileName = file->getName();
fileName.toLowercase();
if (fileName.hasSuffix(".dat") || fileName == "data") {
g_sludge->launchNext = file->getName();
return BR_CONTINUE;
}
}
}
}
g_sludge->launchNext.clear();
fun->reg.setVariable(SVT_INT, false);
return BR_CONTINUE;
}
builtIn(getFramesPerSecond) {
UNUSEDALL
fun->reg.setVariable(SVT_INT, g_sludge->_timer->getLastFps());
return BR_CONTINUE;
}
builtIn(showThumbnail) {
UNUSEDALL
int x, y;
if (!fun->stack->thisVar.getValueType(y, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
if (!fun->stack->thisVar.getValueType(x, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
// Encode the name!Encode the name!
Common::String aaaaa = fun->stack->thisVar.getTextFromAnyVar();
trimStack(fun->stack);
Common::String file = encodeFilename(aaaaa);
g_sludge->_gfxMan->showThumbnail(file, x, y);
return BR_CONTINUE;
}
builtIn(setThumbnailSize) {
UNUSEDALL
int thumbHeight, thumbWidth;
if (!fun->stack->thisVar.getValueType(thumbHeight, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
if (!fun->stack->thisVar.getValueType(thumbWidth, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
if (!g_sludge->_gfxMan->setThumbnailSize(thumbWidth, thumbHeight)) {
Common::String buff = Common::String::format("%i x %i", thumbWidth, thumbWidth);
fatal("Invalid thumbnail size", buff);
return BR_ERROR;
}
return BR_CONTINUE;
}
builtIn(hasFlag) {
UNUSEDALL
int objNum, flagIndex;
if (!fun->stack->thisVar.getValueType(flagIndex, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
if (!fun->stack->thisVar.getValueType(objNum, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
ObjectType *objT = g_sludge->_objMan->findObjectType(objNum);
if (!objT)
return BR_ERROR;
fun->reg.setVariable(SVT_INT, objT->flags & (1 << flagIndex));
return BR_CONTINUE;
}
builtIn(snapshotGrab) {
UNUSEDALL
return g_sludge->_gfxMan->snapshot() ? BR_CONTINUE : BR_ERROR;
}
builtIn(snapshotClear) {
UNUSEDALL
g_sludge->_gfxMan->nosnapshot();
return BR_CONTINUE;
}
builtIn(bodgeFilenames) {
UNUSEDALL
bool lastValue = allowAnyFilename;
allowAnyFilename = fun->stack->thisVar.getBoolean();
trimStack(fun->stack);
fun->reg.setVariable(SVT_INT, lastValue);
return BR_CONTINUE;
}
// Deprecated - does nothing.
builtIn(_rem_registryGetString) {
UNUSEDALL
trimStack(fun->stack);
trimStack(fun->stack);
fun->reg.setVariable(SVT_INT, 0);
return BR_CONTINUE;
}
builtIn(quitWithFatalError) {
UNUSEDALL
Common::String mess = fun->stack->thisVar.getTextFromAnyVar();
trimStack(fun->stack);
fatal(mess);
return BR_ERROR;
}
builtIn(_rem_setCharacterAA) {
UNUSEDALL
trimStack(fun->stack);
trimStack(fun->stack);
trimStack(fun->stack);
trimStack(fun->stack);
return BR_CONTINUE;
}
builtIn(_rem_setMaximumAA) {
UNUSEDALL
trimStack(fun->stack);
trimStack(fun->stack);
trimStack(fun->stack);
return BR_CONTINUE;
}
builtIn(setBackgroundEffect) {
UNUSEDALL
bool done = g_sludge->_gfxMan->blur_createSettings(numParams, fun->stack);
fun->reg.setVariable(SVT_INT, done ? 1 : 0);
return BR_CONTINUE;
}
builtIn(doBackgroundEffect) {
UNUSEDALL
bool done = g_sludge->_gfxMan->blurScreen();
fun->reg.setVariable(SVT_INT, done ? 1 : 0);
return BR_CONTINUE;
}
#pragma mark -
#pragma mark Other functions
//-------------------------------------
} // End of namespace Sludge
#include "functionlist.h"
namespace Sludge {
BuiltReturn callBuiltIn(int whichFunc, int numParams, LoadedFunction *fun) {
if (numBIFNames) {
setFatalInfo((fun->originalNumber < numUserFunc) ? allUserFunc[fun->originalNumber] : "Unknown user function",
(whichFunc < numBIFNames) ? allBIFNames[whichFunc] : "Unknown built-in function");
}
if (whichFunc < NUM_FUNCS) {
if (builtInFunctionArray[whichFunc].paramNum != -1) {
if (builtInFunctionArray[whichFunc].paramNum != numParams) {
Common::String buff = Common::String::format("Built in function must have %i parameter%s", builtInFunctionArray[whichFunc].paramNum, (builtInFunctionArray[whichFunc].paramNum == 1) ? "" : "s");
Common::String msg = buff;
fatal(msg);
return BR_ERROR;
}
}
if (builtInFunctionArray[whichFunc].func) {
debugC(3, kSludgeDebugBuiltin,
"Run built-in function %i : %s",
whichFunc, (whichFunc < numBIFNames) ? allBIFNames[whichFunc].c_str() : builtInFunctionArray[whichFunc].name);
return builtInFunctionArray[whichFunc].func(numParams, fun);
}
}
fatal("Unknown / unimplemented built-in function.");
return BR_ERROR;
}
const char *getBuiltInName(int num) {
if (num >= NUM_FUNCS)
error("getBuiltInName: incorrect builtin number. %d > %d", num, NUM_FUNCS);
return builtInFunctionArray[num].name;
}
} // End of namespace Sludge