diff options
Diffstat (limited to 'engines/sludge/builtin.cpp')
-rw-r--r-- | engines/sludge/builtin.cpp | 2545 |
1 files changed, 2545 insertions, 0 deletions
diff --git a/engines/sludge/builtin.cpp b/engines/sludge/builtin.cpp new file mode 100644 index 0000000000..9ba633de65 --- /dev/null +++ b/engines/sludge/builtin.cpp @@ -0,0 +1,2545 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#if 0 +#include <SDL/SDL.h> +#endif + +#include "debug.h" +#include "allfiles.h" +#include "sludger.h" +#include "builtin.h" +#include "stringy.h" +#include "newfatal.h" +#include "cursors.h" +#include "statusba.h" +#include "loadsave.h" +#include "backdrop.h" +#include "bg_effects.h" +#include "sprites.h" +#include "fonttext.h" +#include "sprbanks.h" +#include "people.h" +#include "sound.h" +#include "objtypes.h" +#include "floor.h" +#include "zbuffer.h" +#include "talk.h" +#include "region.h" +#include "language.h" +#include "moreio.h" +#include "movie.h" +#include "savedata.h" +#include "freeze.h" +#include "colours.h" +#include "language.h" +#include "thumbnail.h" +#include "graphics.h" +#include "CommonCode/utf8.h" + +extern char *gamePath; + +int speechMode = 0; +int cameraX, cameraY; +float cameraZoom = 1.0; +spritePalette pastePalette; + +char *launchMe = NULL; +variable *launchResult = NULL; + +extern int lastFramesPerSecond, thumbWidth, thumbHeight; +extern bool allowAnyFilename; +extern bool captureAllKeys; +extern short fontSpace; +extern eventHandlers *currentEvents; +extern variableStack *noStack; +extern statusStuff *nowStatus; +extern screenRegion *overRegion; +extern HWND hMainWindow; +extern unsigned int sceneWidth, sceneHeight; +extern int numBIFNames, numUserFunc; +extern char builtInFunctionNames[][25]; + +extern char * *allUserFunc; +extern char * *allBIFNames; +extern inputType input; +extern char *loadNow; + +#if 0 +extern GLuint backdropTextureName; +#endif + +extern float speechSpeed; +extern unsigned char brightnessLevel; +extern unsigned char fadeMode; +extern unsigned short saveEncoding; +extern frozenStuffStruct *frozenStuff; +extern unsigned int currentBlankColour; +extern unsigned int languageID; +extern unsigned char currentBurnR, currentBurnG, currentBurnB; + +int paramNum[] = { -1, 0, 1, 1, -1, -1, 1, 3, 4, 1, 0, 0, 8, -1, // SAY -> MOVEMOUSE + -1, 0, 0, -1, -1, 1, 1, 1, 1, 4, 1, 1, 2, 1,// FOCUS -> REMOVEREGION + 2, 2, 0, 0, 2, // ANIMATE -> SETSCALE + -1, 2, 1, 0, 0, 0, 1, 0, 3, // new/push/pop stack, status stuff + 2, 0, 0, 3, 1, 0, 2, // delFromStack -> completeTimers + -1, -1, -1, 2, 2, 0, 3, 1, // anim, costume, pO, setC, wait, sS, substring, stringLength + 0, 1, 1, 0, 2, // dark, save, load, quit, rename + 1, 3, 3, 1, 2, 1, 1, 3, 1, 0, 0, 2, 1, // stackSize, pasteString, startMusic, defvol, vol, stopmus, stopsound, setfont, alignStatus, show x 2, pos'Status, setFloor + -1, -1, 1, 1, 2, 1, 1, 1, -1, -1, -1, 1, 1, // force, jump, peekstart, peekend, enqueue, getSavedGames, inFont, loopSound, removeChar, stopCharacter + 1, 0, 3, 3, 1, 2, 1, 2, 2, // launch, howFrozen, pastecol, litcol, checksaved, float, cancelfunc, walkspeed, delAll + 2, 3, 1, 2, 2, 0, 0, 1, 2, 3, 1, -1, // extras, mixoverlay, pastebloke, getMScreenX/Y, setSound(Default/-)Volume, looppoints, speechMode, setLightMap + -1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, // think, getCharacterDirection, is(char/region/moving), deleteGame, renameGame, hardScroll, stringWidth, speechSpeed, normalCharacter + 2, 1, 2, 1, 3, 1, 1, 2, 1, // fetchEvent, setBrightness, spin, fontSpace, burnString, captureAll, cacheSound, setSpinSpeed, transitionMode + 1, 0, 0, 1, 0, 2, 1, 1, 1, // movie(Start/Abort/Playing), updateDisplay, getSoundCache, savedata, loaddata, savemode, freeSound + 3, 0, 3, 3, 2, 1, 1, // setParallax, clearParallax, setBlankColour, setBurnColour, getPixelColour, makeFastArray, getCharacterScale + 0, 2, 0, // getLanguage, launchWith, getFramesPerSecond + 3, 2, 2, 0, 0, 1, // readThumbnail, setThumbnailSize, hasFlag, snapshot, clearSnapshot, anyFilename + 2, 1, // regGet, fatal + 4, 3, -1, 0, // chr AA, max AA, setBackgroundEffect, doBackgroundEffect + 2, // setCharacterAngleOffset + 2, 5, // setCharacterTransparency, setCharacterColourise + 1, // zoomCamera + 1, 0, 0 // playMovie, stopMovie, pauseMovie + }; + +bool failSecurityCheck(char *fn) { + if (fn == NULL) return true; + + int a = 0; + + while (fn[a]) { + switch (fn[a]) { + 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; + } + a ++; + } + return false; +} + +loadedFunction *saverFunc; + +typedef builtReturn(* builtInSludgeFunc)(int numParams, loadedFunction *fun); +struct builtInFunctionData { + builtInSludgeFunc func; +}; + +#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; + char *newText; + int objT, p; + killSpeechTimers(); + + switch (numParams) { + case 3: + if (!getValueType(fileNum, SVT_FILE, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + // No break; here + + case 2: + newText = getTextFromAnyVar(fun -> stack -> thisVar); + if (!newText) return BR_ERROR; + trimStack(fun -> stack); + if (!getValueType(objT, SVT_OBJTYPE, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + p = wrapSpeech(newText, objT, fileNum, sayIt); + fun -> timeLeft = p; + //debugOut ("BUILTIN: sayCore: %s (%i)\n", newText, p); + fun -> isSpeech = true; + delete newText; + newText = NULL; + return BR_KEEP_AND_PAUSE; + } + + 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 + freeze(); + freezeSubs(); + fun -> freezerLevel = 0; + return BR_CONTINUE; +} + +builtIn(unfreeze) { + UNUSEDALL + unfreeze(); + unfreezeSubs(); + return BR_CONTINUE; +} + +builtIn(howFrozen) { + UNUSEDALL + setVariable(fun -> reg, SVT_INT, howFrozen()); + return BR_CONTINUE; +} + +builtIn(setCursor) { + UNUSEDALL + personaAnimation *aa = getAnimationFromVar(fun -> stack -> thisVar); + pickAnimCursor(aa); + trimStack(fun -> stack); + return BR_CONTINUE; +} + +builtIn(getMouseX) { + UNUSEDALL + setVariable(fun -> reg, SVT_INT, input.mouseX + cameraX); + return BR_CONTINUE; +} + +builtIn(getMouseY) { + UNUSEDALL + setVariable(fun -> reg, SVT_INT, input.mouseY + cameraY); + return BR_CONTINUE; +} + +builtIn(getMouseScreenX) { + UNUSEDALL + setVariable(fun -> reg, SVT_INT, input.mouseX * cameraZoom); + return BR_CONTINUE; +} + +builtIn(getMouseScreenY) { + UNUSEDALL + setVariable(fun -> reg, SVT_INT, input.mouseY * cameraZoom); + return BR_CONTINUE; +} + +builtIn(getStatusText) { + UNUSEDALL + makeTextVar(fun -> reg, statusBarText()); + return BR_CONTINUE; +} + +builtIn(getMatchingFiles) { + UNUSEDALL + char *newText = getTextFromAnyVar(fun -> stack -> thisVar); + if (!newText) return BR_ERROR; + trimStack(fun -> stack); + unlinkVar(fun -> reg); + + // 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 (!getSavedGamesStack(fun -> reg.varData.theStack, newText)) return BR_ERROR; + delete newText; + newText = NULL; + return BR_CONTINUE; +} + +builtIn(saveGame) { + UNUSEDALL + + if (frozenStuff) { + fatal("Can't save game state while the engine is frozen"); + } + + loadNow = getTextFromAnyVar(fun -> stack -> thisVar); + trimStack(fun -> stack); + + char *aaaaa = encodeFilename(loadNow); + delete[] loadNow; + if (failSecurityCheck(aaaaa)) return BR_ERROR; // Won't fail if encoded, how cool is that? OK, not very. + + loadNow = joinStrings(":", aaaaa); + delete[] aaaaa; + + setVariable(fun -> reg, SVT_INT, 0); + saverFunc = fun; + return BR_KEEP_AND_PAUSE; +} + +builtIn(fileExists) { + UNUSEDALL + loadNow = getTextFromAnyVar(fun -> stack -> thisVar); + trimStack(fun -> stack); + char *aaaaa = encodeFilename(loadNow); + delete loadNow; + if (failSecurityCheck(aaaaa)) return BR_ERROR; +#if ALLOW_FILE + FILE *fp = fopen(aaaaa, "rb"); + if (!fp) { + char currentDir[1000]; + if (!getcwd(currentDir, 998)) { + debugOut("Can't get current directory.\n"); + } + + if (chdir(gamePath)) { + debugOut("Error: Failed changing to directory %s\n", gamePath); + } + fp = fopen(aaaaa, "rb"); + if (chdir(currentDir)) { + debugOut("Error: Failed changing to directory %s\n", currentDir); + } + } + // Return value + setVariable(fun -> reg, SVT_INT, (fp != NULL)); + if (fp) fclose(fp); + delete[] aaaaa; + loadNow = NULL; +#endif + return BR_CONTINUE; +} + +builtIn(loadGame) { + UNUSEDALL + char *aaaaa = getTextFromAnyVar(fun -> stack -> thisVar); + trimStack(fun -> stack); + loadNow = encodeFilename(aaaaa); + delete aaaaa; + + if (frozenStuff) { + fatal("Can't load a saved game while the engine is frozen"); + } +#if ALLOW_FILE + if (failSecurityCheck(loadNow)) return BR_ERROR; + FILE *fp = fopen(loadNow, "rb"); + if (fp) { + fclose(fp); + return BR_KEEP_AND_PAUSE; + } + delete loadNow; + loadNow = NULL; +#endif + return BR_CONTINUE; +} + +//-------------------------------------- +#pragma mark - +#pragma mark Background image - Painting + +builtIn(blankScreen) { + UNUSEDALL + blankScreen(0, 0, sceneWidth, sceneHeight); + return BR_CONTINUE; +} + +builtIn(blankArea) { + UNUSEDALL + int x1, y1, x2, y2; + if (!getValueType(y2, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + if (!getValueType(x2, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + if (!getValueType(y1, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + if (!getValueType(x1, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + blankScreen(x1, y1, x2, y2); + return BR_CONTINUE; +} + +builtIn(darkBackground) { + UNUSEDALL + darkScreen(); + return BR_CONTINUE; +} + +builtIn(addOverlay) { + UNUSEDALL + int fileNumber, xPos, yPos; + if (!getValueType(yPos, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + if (!getValueType(xPos, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + if (!getValueType(fileNumber, SVT_FILE, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + loadBackDrop(fileNumber, xPos, yPos); + return BR_CONTINUE; +} + +builtIn(mixOverlay) { + UNUSEDALL + int fileNumber, xPos, yPos; + if (!getValueType(yPos, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + if (!getValueType(xPos, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + if (!getValueType(fileNumber, SVT_FILE, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + mixBackDrop(fileNumber, xPos, yPos); + return BR_CONTINUE; +} + +builtIn(pasteImage) { + UNUSEDALL + int x, y; + if (!getValueType(y, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + if (!getValueType(x, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + personaAnimation *pp = getAnimationFromVar(fun -> stack -> thisVar); + trimStack(fun -> stack); + if (pp == NULL) return BR_CONTINUE; + + pasteCursor(x, y, pp); + return BR_CONTINUE; +} + +#pragma mark - +#pragma mark Background Image - Scrolling + +builtIn(setSceneDimensions) { + UNUSEDALL + int x, y; + if (!getValueType(y, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + if (!getValueType(x, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + if (resizeBackdrop(x, y)) { + blankScreen(0, 0, x, y); + return BR_CONTINUE; + } + fatal("Out of memory creating new backdrop."); + return BR_ERROR; +} + +builtIn(aimCamera) { + UNUSEDALL + if (!getValueType(cameraY, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + if (!getValueType(cameraX, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + + cameraX -= (float)(winWidth >> 1) / cameraZoom; + cameraY -= (float)(winHeight >> 1) / cameraZoom; + + if (cameraX < 0) cameraX = 0; + else if (cameraX > sceneWidth - (float)winWidth / cameraZoom) cameraX = sceneWidth - (float)winWidth / cameraZoom; + if (cameraY < 0) cameraY = 0; + else if (cameraY > sceneHeight - (float)winHeight / cameraZoom) cameraY = sceneHeight - (float)winHeight / cameraZoom; + return BR_CONTINUE; +} + + +builtIn(zoomCamera) { + UNUSEDALL + int z; + if (!getValueType(z, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + + input.mouseX = input.mouseX * cameraZoom; + input.mouseY = input.mouseY * cameraZoom; + + + cameraZoom = (float) z * 0.01; + if ((float) winWidth / cameraZoom > sceneWidth) cameraZoom = (float)winWidth / sceneWidth; + if ((float) winHeight / cameraZoom > sceneHeight) cameraZoom = (float)winHeight / sceneHeight; + setPixelCoords(false); + + input.mouseX = input.mouseX / cameraZoom; + input.mouseY = input.mouseY / cameraZoom; + + 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; +#if 0 + i = rand() % numParams; +#endif + + // Return value + while (numParams --) { + if (i == numParams) copyVariable(fun -> stack -> thisVar, fun -> reg); + trimStack(fun -> stack); + } + return BR_CONTINUE; +} + +builtIn(substring) { + UNUSEDALL + char *wholeString; + char *newString; + int start, length; + + //debugOut ("BUILTIN: substring\n"); + + if (!getValueType(length, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + if (!getValueType(start, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + wholeString = getTextFromAnyVar(fun -> stack -> thisVar); + trimStack(fun -> stack); + + if (u8_strlen(wholeString) < start + length) { + length = u8_strlen(wholeString) - start; + if (u8_strlen(wholeString) < start) { + start = 0; + } + } + if (length < 0) { + length = 0; + } + + int startoffset = u8_offset(wholeString, start); + int endoffset = u8_offset(wholeString, start + length); + + newString = new char[endoffset - startoffset + 1]; + if (!checkNew(newString)) { + return BR_ERROR; + } + + memcpy(newString, wholeString + startoffset, endoffset - startoffset); + newString[endoffset - startoffset] = 0; + + makeTextVar(fun -> reg, newString); + delete newString; + return BR_CONTINUE; +} + +builtIn(stringLength) { + UNUSEDALL + char *newText = getTextFromAnyVar(fun -> stack -> thisVar); + trimStack(fun -> stack); + setVariable(fun -> reg, SVT_INT, stringLength(newText)); + delete[] newText; + return BR_CONTINUE; +} + +builtIn(newStack) { + UNUSEDALL + unlinkVar(fun -> reg); + + // 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 + setVariable(fun -> reg, SVT_INT, stackSize(fun -> stack -> thisVar.varData.theStack)); + trimStack(fun -> stack); + return BR_CONTINUE; + + case SVT_FASTARRAY: + // Return value + setVariable(fun -> reg, 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 (!copyStack(fun -> stack -> thisVar, fun -> reg)) 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 + setVariable(fun -> reg, SVT_INT, + deleteVarFromStack(fun -> stack -> thisVar, + fun -> stack -> next -> thisVar.varData.theStack -> first, false)); + + // Horrible hacking because 'last' value might now be wrong! + fun->stack->next->thisVar.varData.theStack->last = stackFindLast(fun->stack->next->thisVar.varData.theStack->first); + + 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 + setVariable(fun -> reg, SVT_INT, + deleteVarFromStack(fun -> stack -> thisVar, + fun -> stack -> next -> thisVar.varData.theStack -> first, true)); + + // Horrible hacking because 'last' value might now be wrong! + fun->stack->next->thisVar.varData.theStack->last = stackFindLast(fun->stack->next->thisVar.varData.theStack->first); + + 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 + copyVariable(fun -> stack -> thisVar.varData.theStack -> first -> thisVar, fun -> reg); + 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 + copyVariable(fun -> stack -> thisVar.varData.theStack -> first -> thisVar, fun -> reg); + 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 + copyVariable(fun -> stack -> thisVar.varData.theStack -> last -> thisVar, fun -> reg); + trimStack(fun -> stack); + return BR_CONTINUE; +} + +builtIn(random) { + UNUSEDALL + int num; + + if (!getValueType(num, SVT_INT, fun -> stack -> thisVar)) + return BR_ERROR; + + trimStack(fun -> stack); + if (num <= 0) num = 1; + setVariable(fun -> reg, SVT_INT, 0 /*rand() % num*/); //TODO:false value + return BR_CONTINUE; +} + +static bool getRGBParams(int &red, int &green, int &blue, loadedFunction *fun) { + if (!getValueType(blue, SVT_INT, fun -> stack -> thisVar)) return false; + trimStack(fun -> stack); + if (!getValueType(green, SVT_INT, fun -> stack -> thisVar)) return false; + trimStack(fun -> stack); + if (!getValueType(red, SVT_INT, fun -> stack -> thisVar)) return false; + trimStack(fun -> stack); + return true; +} + +builtIn(setStatusColour) { + UNUSEDALL + int red, green, blue; + + if (!getRGBParams(red, green, blue, fun)) + return BR_ERROR; + + 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; + + 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; + + setFontColour(pastePalette, (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; + + currentBlankColour = makeColour(red & 255, green & 255, blue & 255); + setVariable(fun -> reg, SVT_INT, 1); + return BR_CONTINUE; +} + +builtIn(setBurnColour) { + UNUSEDALL + int red, green, blue; + + if (!getRGBParams(red, green, blue, fun)) + return BR_ERROR; + + currentBurnR = red; + currentBurnG = green; + currentBurnB = blue; + setVariable(fun -> reg, SVT_INT, 1); + return BR_CONTINUE; +} + + +builtIn(setFont) { + UNUSEDALL + int fileNumber, newHeight; + if (!getValueType(newHeight, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + // newDebug (" Height:", newHeight); + trimStack(fun -> stack); + char *newText = getTextFromAnyVar(fun -> stack -> thisVar); + if (!newText) return BR_ERROR; + // newDebug (" Character supported:", newText); + trimStack(fun -> stack); + if (!getValueType(fileNumber, SVT_FILE, fun -> stack -> thisVar)) return BR_ERROR; + // newDebug (" File:", fileNumber); + trimStack(fun -> stack); + if (!loadFont(fileNumber, newText, newHeight)) return BR_ERROR; + // newDebug (" Done!"); + delete newText; + + return BR_CONTINUE; +} + +builtIn(inFont) { + UNUSEDALL + char *newText = getTextFromAnyVar(fun -> stack -> thisVar); + if (!newText) return BR_ERROR; + trimStack(fun -> stack); + + // Return value + + setVariable(fun -> reg, SVT_INT, isInFont(newText)); + return BR_CONTINUE; +} + +builtIn(pasteString) { + UNUSEDALL + char *newText = getTextFromAnyVar(fun -> stack -> thisVar); + trimStack(fun -> stack); + int y, x; + if (!getValueType(y, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + if (!getValueType(x, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + if (x == IN_THE_CENTRE) x = (winWidth - stringWidth(newText)) >> 1; + fixFont(pastePalette); + pasteStringToBackdrop(newText, x, y, pastePalette); + delete[] newText; + 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 = createPersonaAnim(numParams - 1, fun -> stack); + + // Only remaining paramter is the file number + int fileNumber; + if (!getValueType(fileNumber, SVT_FILE, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + + // Load the required sprite bank + loadedSpriteBank *sprBanky = loadBankForAnim(fileNumber); + if (!sprBanky) return BR_ERROR; // File not found, fatal done already + setBankFile(ba, sprBanky); + + // Return value + newAnimationVariable(fun -> reg, 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] = getAnimationFromVar(fun -> stack -> thisVar); + trimStack(fun -> stack); + } + + // Return value + newCostumeVariable(fun -> reg, newPersona); + return BR_CONTINUE; +} + +builtIn(launch) { + UNUSEDALL + char *newTextA = getTextFromAnyVar(fun -> stack -> thisVar); + if (!newTextA) return BR_ERROR; + + char *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! + launchMe = copyString(newTextA); + } else { + char *gameDir; +#ifdef _WIN32 + gameDir = joinStrings(gamePath, "\\"); +#else + gameDir = joinStrings(gamePath, "/"); +#endif + launchMe = joinStrings(gameDir, newText); + delete newText; + if (!launchMe) return BR_ERROR; + } + delete newTextA; + setGraphicsWindow(false); + setVariable(fun -> reg, SVT_INT, 1); + launchResult = &fun->reg; + + return BR_KEEP_AND_PAUSE; +} + +builtIn(pause) { + UNUSEDALL + int theTime; + if (!getValueType(theTime, SVT_INT, fun -> stack -> thisVar)) 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 (!getValueType(obj2, SVT_OBJTYPE, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + if (!getValueType(obj1, SVT_OBJTYPE, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + + int fNum = getCombinationFunction(obj1, obj2); + + // Return value + if (fNum) { + setVariable(fun -> reg, SVT_FUNC, fNum); + return BR_CALLAFUNC; + } + setVariable(fun -> reg, SVT_INT, 0); + return BR_CONTINUE; +} + +#if 0 +SDL_Event quit_event; +#endif + +bool reallyWantToQuit = false; + +builtIn(quitGame) { + UNUSEDALL + reallyWantToQuit = true; +#if 0 + quit_event.type = SDL_QUIT; + SDL_PushEvent(&quit_event); +#endif + 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 + setVariable(fun -> reg, SVT_INT, 0); + return BR_CONTINUE; +} + +builtIn(_rem_moviePlaying) { + UNUSEDALL + setVariable(fun -> reg, SVT_INT, 0); + return BR_CONTINUE; +} + +builtIn(playMovie) { + UNUSEDALL + int fileNumber, r; + + if (movieIsPlaying) return BR_PAUSE; + + if (!getValueType(fileNumber, SVT_FILE, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + + r = playMovie(fileNumber); + + setVariable(fun -> reg, SVT_INT, r); + + if (r && (!fun->next)) { + restartFunction(fun); + return BR_ALREADY_GONE; + } + return BR_CONTINUE; +} + +builtIn(stopMovie) { + UNUSEDALL + int r; + + r = stopMovie(); + + setVariable(fun -> reg, SVT_INT, 0); + return BR_CONTINUE; +} + +builtIn(pauseMovie) { + UNUSEDALL + int r; + + r = pauseMovie(); + + setVariable(fun -> reg, SVT_INT, 0); + return BR_CONTINUE; +} + + +#pragma mark - +#pragma mark Audio functions + +builtIn(startMusic) { + UNUSEDALL + int fromTrack, musChan, fileNumber; + if (!getValueType(fromTrack, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + if (!getValueType(musChan, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + if (!getValueType(fileNumber, SVT_FILE, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + if (!playMOD(fileNumber, musChan, fromTrack)) return BR_CONTINUE; //BR_ERROR; + return BR_CONTINUE; +} + +builtIn(stopMusic) { + UNUSEDALL + int v; + if (!getValueType(v, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + stopMOD(v); + return BR_CONTINUE; +} + +builtIn(setMusicVolume) { + UNUSEDALL + int musChan, v; + if (!getValueType(v, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + if (!getValueType(musChan, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + setMusicVolume(musChan, v); + return BR_CONTINUE; +} + +builtIn(setDefaultMusicVolume) { + UNUSEDALL + int v; + if (!getValueType(v, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + setDefaultMusicVolume(v); + return BR_CONTINUE; +} + +builtIn(playSound) { + UNUSEDALL + int fileNumber; + if (!getValueType(fileNumber, SVT_FILE, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + if (!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 (!getValueType(fileNumber, SVT_FILE, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + if (!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) { + getValueType(doLoop, SVT_INT, fun -> stack -> thisVar); + trimStack(fun -> stack); + numParams--; + } + while (numParams) { + if (!getValueType(fileNumber, SVT_FILE, fun -> stack -> thisVar)) { + 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; + playSoundList(old); + return BR_CONTINUE; + } +} + +builtIn(stopSound) { + UNUSEDALL + int v; + if (!getValueType(v, SVT_FILE, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + huntKillSound(v); + return BR_CONTINUE; +} + +builtIn(setDefaultSoundVolume) { + UNUSEDALL + int v; + if (!getValueType(v, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + setDefaultSoundVolume(v); + return BR_CONTINUE; +} + +builtIn(setSoundVolume) { + UNUSEDALL + int musChan, v; + if (!getValueType(v, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + if (!getValueType(musChan, SVT_FILE, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + setSoundVolume(musChan, v); + return BR_CONTINUE; +} + + +builtIn(setSoundLoopPoints) { + UNUSEDALL + int musChan, theEnd, theStart; + if (!getValueType(theEnd, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + if (!getValueType(theStart, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + if (!getValueType(musChan, SVT_FILE, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + 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; + getValueType(v, SVT_FILE, fun -> stack -> thisVar); + trimStack(fun -> stack); + if (!setFloor(v)) return BR_ERROR; + } else { + trimStack(fun -> stack); + setFloorNull(); + } + return BR_CONTINUE; +} + +builtIn(showFloor) { + UNUSEDALL + drawFloor(); + return BR_CONTINUE; +} + +builtIn(setZBuffer) { + UNUSEDALL + if (fun -> stack -> thisVar.varType == SVT_FILE) { + int v; + getValueType(v, SVT_FILE, fun -> stack -> thisVar); + trimStack(fun -> stack); + if (!setZBuffer(v)) return BR_ERROR; + } else { + trimStack(fun -> stack); + killZBuffer(); + } + return BR_CONTINUE; +} + +builtIn(setLightMap) { + UNUSEDALL + switch (numParams) { + case 2: + if (!getValueType(lightMapMode, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + lightMapMode %= LIGHTMAPMODE_NUM; + // No break; + + case 1: + if (fun -> stack -> thisVar.varType == SVT_FILE) { + int v; + getValueType(v, SVT_FILE, fun -> stack -> thisVar); + trimStack(fun -> stack); + if (!loadLightMap(v)) return BR_ERROR; + setVariable(fun -> reg, SVT_INT, 1); + } else { + trimStack(fun -> stack); + killLightMap(); + setVariable(fun -> reg, 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 + if (!getValueType(speechMode, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + if (speechMode < 0 || speechMode > 2) { + fatal("Valid parameters are be SPEECHANDTEXT, SPEECHONLY or TEXTONLY"); + return BR_ERROR; + } + return BR_CONTINUE; +} + +builtIn(somethingSpeaking) { + UNUSEDALL + int i = isThereAnySpeechGoingOn(); + if (i == -1) { + setVariable(fun -> reg, SVT_INT, 0); + } else { + setVariable(fun -> reg, SVT_OBJTYPE, i); + } + return BR_CONTINUE; +} + +builtIn(skipSpeech) { + UNUSEDALL + killSpeechTimers(); + return BR_CONTINUE; +} + +builtIn(getOverObject) { + UNUSEDALL + if (overRegion) + // Return value + setVariable(fun -> reg, SVT_OBJTYPE, overRegion -> thisType -> objectNum); + else + // Return value + setVariable(fun -> reg, SVT_INT, 0); + return BR_CONTINUE; +} + +builtIn(rename) { + UNUSEDALL + char *newText = getTextFromAnyVar(fun -> stack -> thisVar); + int objT; + if (!newText) return BR_ERROR; + trimStack(fun -> stack); + if (!getValueType(objT, SVT_OBJTYPE, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + objectType *o = findObjectType(objT); + delete o -> screenName; + o -> screenName = newText; + return BR_CONTINUE; +} + +builtIn(getObjectX) { + UNUSEDALL + int objectNumber; + if (!getValueType(objectNumber, SVT_OBJTYPE, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + + onScreenPerson *pers = findPerson(objectNumber); + if (pers) { + setVariable(fun -> reg, SVT_INT, pers -> x); + } else { + screenRegion *la = getRegionForObject(objectNumber); + if (la) { + setVariable(fun -> reg, SVT_INT, la -> sX); + } else { + setVariable(fun -> reg, SVT_INT, 0); + } + } + return BR_CONTINUE; +} + +builtIn(getObjectY) { + UNUSEDALL + int objectNumber; + if (!getValueType(objectNumber, SVT_OBJTYPE, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + + onScreenPerson *pers = findPerson(objectNumber); + if (pers) { + setVariable(fun -> reg, SVT_INT, pers -> y); + } else { + screenRegion *la = getRegionForObject(objectNumber); + if (la) { + setVariable(fun -> reg, SVT_INT, la -> sY); + } else { + setVariable(fun -> reg, SVT_INT, 0); + } + } + return BR_CONTINUE; +} + + +builtIn(addScreenRegion) { + UNUSEDALL + int sX, sY, x1, y1, x2, y2, di, objectNumber; + if (!getValueType(di, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + if (!getValueType(sY, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + if (!getValueType(sX, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + if (!getValueType(y2, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + if (!getValueType(x2, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + if (!getValueType(y1, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + if (!getValueType(x1, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + if (!getValueType(objectNumber, SVT_OBJTYPE, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + if (addScreenRegion(x1, y1, x2, y2, sX, sY, di, objectNumber)) return BR_CONTINUE; + return BR_ERROR; + +} + +builtIn(removeScreenRegion) { + UNUSEDALL + int objectNumber; + if (!getValueType(objectNumber, SVT_OBJTYPE, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + removeScreenRegion(objectNumber); + return BR_CONTINUE; +} + +builtIn(showBoxes) { + UNUSEDALL + showBoxes(); + return BR_CONTINUE; +} + +builtIn(removeAllScreenRegions) { + UNUSEDALL + killAllRegions(); + return BR_CONTINUE; +} + +builtIn(addCharacter) { + UNUSEDALL + persona *p; + int x, y, objectNumber; + + p = getCostumeFromVar(fun -> stack -> thisVar); + if (p == NULL) return BR_ERROR; + + trimStack(fun -> stack); + if (!getValueType(y, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + if (!getValueType(x, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + if (!getValueType(objectNumber, SVT_OBJTYPE, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + if (addPerson(x, y, objectNumber, p)) return BR_CONTINUE; + return BR_ERROR; +} + +builtIn(hideCharacter) { + UNUSEDALL + int objectNumber; + if (!getValueType(objectNumber, SVT_OBJTYPE, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + setShown(false, objectNumber); + return BR_CONTINUE; +} + +builtIn(showCharacter) { + UNUSEDALL + int objectNumber; + if (!getValueType(objectNumber, SVT_OBJTYPE, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + setShown(true, objectNumber); + return BR_CONTINUE; +} + +builtIn(removeAllCharacters) { + UNUSEDALL + killSpeechTimers(); + killMostPeople(); + return BR_CONTINUE; +} + +builtIn(setCharacterDrawMode) { + UNUSEDALL + int obj, di; + if (!getValueType(di, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + if (!getValueType(obj, SVT_OBJTYPE, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + setDrawMode(di, obj); + return BR_CONTINUE; +} +builtIn(setCharacterTransparency) { + UNUSEDALL + int obj, x; + if (!getValueType(x, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + if (!getValueType(obj, SVT_OBJTYPE, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + setPersonTransparency(obj, x); + return BR_CONTINUE; +} +builtIn(setCharacterColourise) { + UNUSEDALL + int obj, r, g, b, mix; + if (!getValueType(mix, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + if (!getValueType(b, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + if (!getValueType(g, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + if (!getValueType(r, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + if (!getValueType(obj, SVT_OBJTYPE, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + setPersonColourise(obj, r, g, b, mix); + return BR_CONTINUE; +} + +builtIn(setScale) { + UNUSEDALL + int val1, val2; + if (!getValueType(val2, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + if (!getValueType(val1, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + setScale((short int) val1, (short int) val2); + return BR_CONTINUE; +} + +builtIn(stopCharacter) { + UNUSEDALL + int obj; + if (!getValueType(obj, SVT_OBJTYPE, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + + // Return value + setVariable(fun -> reg, SVT_INT, stopPerson(obj)); + return BR_CONTINUE; +} + +builtIn(pasteCharacter) { + UNUSEDALL + int obj; + if (!getValueType(obj, SVT_OBJTYPE, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + + onScreenPerson *thisPerson = 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; + fixScaleSprite(thisPerson -> x, thisPerson -> y, myAnim -> theSprites -> bank.sprites[abs(fNum)], myAnim -> theSprites -> bank.myPalette, thisPerson, 0, 0, fNum < 0); + setVariable(fun -> reg, SVT_INT, 1); + } else { + setVariable(fun -> reg, SVT_INT, 0); + } + return BR_CONTINUE; +} + +builtIn(animate) { + UNUSEDALL + int obj; + personaAnimation *pp = getAnimationFromVar(fun -> stack -> thisVar); + if (pp == NULL) return BR_ERROR; + trimStack(fun -> stack); + if (!getValueType(obj, SVT_OBJTYPE, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + animatePerson(obj, pp); + setVariable(fun -> reg, SVT_INT, timeForAnim(pp)); + return BR_CONTINUE; +} + +builtIn(setCostume) { + UNUSEDALL + int obj; + persona *pp = getCostumeFromVar(fun -> stack -> thisVar); + if (pp == NULL) return BR_ERROR; + trimStack(fun -> stack); + if (!getValueType(obj, SVT_OBJTYPE, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + animatePerson(obj, pp); + return BR_CONTINUE; +} + +builtIn(floatCharacter) { + UNUSEDALL + int obj, di; + if (!getValueType(di, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + if (!getValueType(obj, SVT_OBJTYPE, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + setVariable(fun -> reg, SVT_INT, floatCharacter(di, obj)); + return BR_CONTINUE; +} + +builtIn(setCharacterWalkSpeed) { + UNUSEDALL + int obj, di; + if (!getValueType(di, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + if (!getValueType(obj, SVT_OBJTYPE, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + setVariable(fun -> reg, SVT_INT, setCharacterWalkSpeed(di, obj)); + return BR_CONTINUE; +} + +builtIn(turnCharacter) { + UNUSEDALL + int obj, di; + if (!getValueType(di, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + if (!getValueType(obj, SVT_OBJTYPE, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + setVariable(fun -> reg, SVT_INT, turnPersonToFace(obj, di)); + return BR_CONTINUE; +} + +builtIn(setCharacterExtra) { + UNUSEDALL + int obj, di; + if (!getValueType(di, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + if (!getValueType(obj, SVT_OBJTYPE, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + setVariable(fun -> reg, SVT_INT, setPersonExtra(obj, di)); + return BR_CONTINUE; +} + +builtIn(removeCharacter) { + UNUSEDALL + int objectNumber; + if (!getValueType(objectNumber, SVT_OBJTYPE, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + 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 (!getValueType(y, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + if (!getValueType(x, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + if (!getValueType(objectNumber, SVT_OBJTYPE, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + + if (force) { + if (forceWalkingPerson(x, y, objectNumber, fun, -1)) return BR_PAUSE; + } else if (immediate) { + jumpPerson(x, y, objectNumber); + } else { + if (makeWalkingPerson(x, y, objectNumber, fun, -1)) return BR_PAUSE; + } + return BR_CONTINUE; + } + + case 2: { + int toObj, objectNumber; + screenRegion *reggie; + + if (!getValueType(toObj, SVT_OBJTYPE, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + if (!getValueType(objectNumber, SVT_OBJTYPE, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + reggie = getRegionForObject(toObj); + if (reggie == NULL) return BR_CONTINUE; + + if (force) { + if (forceWalkingPerson(reggie -> sX, reggie -> sY, objectNumber, fun, reggie -> di)) return BR_PAUSE; + } else if (immediate) { + jumpPerson(reggie -> sX, reggie -> sY, objectNumber); + } else { + if (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 + clearStatusBar(); + return BR_CONTINUE; +} + +builtIn(removeLastStatus) { + UNUSEDALL + killLastStatus(); + return BR_CONTINUE; +} + +builtIn(addStatus) { + UNUSEDALL + addStatusBar(); + return BR_CONTINUE; +} + +builtIn(statusText) { + UNUSEDALL + char *newText = getTextFromAnyVar(fun -> stack -> thisVar); + if (!newText) return BR_ERROR; + trimStack(fun -> stack); + setStatusBar(newText); + delete newText; + return BR_CONTINUE; +} + +builtIn(lightStatus) { + UNUSEDALL + int val; + if (!getValueType(val, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + setLitStatus(val); + return BR_CONTINUE; +} + +builtIn(positionStatus) { + UNUSEDALL + int x, y; + if (!getValueType(y, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + if (!getValueType(x, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + positionStatus(x, y); + return BR_CONTINUE; +} + +builtIn(alignStatus) { + UNUSEDALL + int val; + if (!getValueType(val, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + nowStatus -> alignStatus = (short) val; + return BR_CONTINUE; +} + +static bool getFuncNumForCallback(int numParams, loadedFunction *fun, int &functionNum) { + switch (numParams) { + case 0: + functionNum = 0; + break; + + case 1: + if (!getValueType(functionNum, SVT_FUNC, fun -> stack -> thisVar)) 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)) { + currentEvents -> leftMouseFunction = functionNum; + return BR_CONTINUE; + } + return BR_ERROR; +} + +builtIn(onLeftMouseUp) { + UNUSEDALL + int functionNum; + if (getFuncNumForCallback(numParams, fun, functionNum)) { + currentEvents -> leftMouseUpFunction = functionNum; + return BR_CONTINUE; + } + return BR_ERROR; +} + +builtIn(onRightMouse) { + UNUSEDALL + int functionNum; + if (getFuncNumForCallback(numParams, fun, functionNum)) { + currentEvents -> rightMouseFunction = functionNum; + return BR_CONTINUE; + } + return BR_ERROR; +} + +builtIn(onRightMouseUp) { + UNUSEDALL + int functionNum; + if (getFuncNumForCallback(numParams, fun, functionNum)) { + currentEvents -> rightMouseUpFunction = functionNum; + return BR_CONTINUE; + } + return BR_ERROR; +} + +builtIn(onFocusChange) { + UNUSEDALL + int functionNum; + if (getFuncNumForCallback(numParams, fun, functionNum)) { + currentEvents -> focusFunction = functionNum; + return BR_CONTINUE; + } + return BR_ERROR; +} + +builtIn(onMoveMouse) { + UNUSEDALL + int functionNum; + if (getFuncNumForCallback(numParams, fun, functionNum)) { + currentEvents -> moveMouseFunction = functionNum; + return BR_CONTINUE; + } + return BR_ERROR; +} + +builtIn(onKeyboard) { + UNUSEDALL + int functionNum; + if (getFuncNumForCallback(numParams, fun, functionNum)) { + currentEvents -> spaceFunction = 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 + char *theText = getTextFromAnyVar(fun -> stack -> thisVar); + if (!theText) return BR_ERROR; + trimStack(fun -> stack); + + // Return value + setVariable(fun -> reg, SVT_INT, stringWidth(theText)); + delete theText; + return BR_CONTINUE; +} + +builtIn(hardScroll) { + UNUSEDALL + int v; + if (!getValueType(v, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + hardScroll(v); + return BR_CONTINUE; +} + + +builtIn(isScreenRegion) { + UNUSEDALL + int objectNumber; + if (!getValueType(objectNumber, SVT_OBJTYPE, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + setVariable(fun -> reg, SVT_INT, getRegionForObject(objectNumber) != NULL); + return BR_CONTINUE; +} + +builtIn(setSpeechSpeed) { + UNUSEDALL + int number; + if (!getValueType(number, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + speechSpeed = number * 0.01; + setVariable(fun -> reg, SVT_INT, 1); + return BR_CONTINUE; +} + +builtIn(setFontSpacing) { + UNUSEDALL + int fontSpaceI; + if (!getValueType(fontSpaceI, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + fontSpace = fontSpaceI; + trimStack(fun -> stack); + setVariable(fun -> reg, SVT_INT, 1); + return BR_CONTINUE; +} + +builtIn(transitionLevel) { + UNUSEDALL + int number; + if (!getValueType(number, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + + if (number < 0) + brightnessLevel = 0; + else if (number > 255) + brightnessLevel = 255; + else + brightnessLevel = number; + + setVariable(fun -> reg, SVT_INT, 1); + return BR_CONTINUE; +} + +builtIn(captureAllKeys) { + UNUSEDALL + captureAllKeys = getBoolean(fun -> stack -> thisVar); + trimStack(fun -> stack); + setVariable(fun -> reg, SVT_INT, captureAllKeys); + return BR_CONTINUE; +} + + +builtIn(spinCharacter) { + UNUSEDALL + int number, objectNumber; + if (!getValueType(number, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + if (!getValueType(objectNumber, SVT_OBJTYPE, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + + onScreenPerson *thisPerson = findPerson(objectNumber); + if (thisPerson) { + thisPerson -> wantAngle = number; + thisPerson -> spinning = true; + thisPerson -> continueAfterWalking = fun; + setVariable(fun -> reg, SVT_INT, 1); + return BR_PAUSE; + } else { + setVariable(fun -> reg, SVT_INT, 0); + return BR_CONTINUE; + } +} + +builtIn(getCharacterDirection) { + UNUSEDALL + int objectNumber; + if (!getValueType(objectNumber, SVT_OBJTYPE, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + onScreenPerson *thisPerson = findPerson(objectNumber); + if (thisPerson) { + setVariable(fun -> reg, SVT_INT, thisPerson -> direction); + } else { + setVariable(fun -> reg, SVT_INT, 0); + } + return BR_CONTINUE; +} + +builtIn(isCharacter) { + UNUSEDALL + int objectNumber; + if (!getValueType(objectNumber, SVT_OBJTYPE, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + onScreenPerson *thisPerson = findPerson(objectNumber); + setVariable(fun -> reg, SVT_INT, thisPerson != NULL); + return BR_CONTINUE; +} + +builtIn(normalCharacter) { + UNUSEDALL + int objectNumber; + if (!getValueType(objectNumber, SVT_OBJTYPE, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + onScreenPerson *thisPerson = findPerson(objectNumber); + if (thisPerson) { + thisPerson -> myAnim = thisPerson -> myPersona -> animation[thisPerson -> direction]; + setVariable(fun -> reg, SVT_INT, 1); + } else { + setVariable(fun -> reg, SVT_INT, 0); + } + return BR_CONTINUE; +} + +builtIn(isMoving) { + UNUSEDALL + int objectNumber; + if (!getValueType(objectNumber, SVT_OBJTYPE, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + onScreenPerson *thisPerson = findPerson(objectNumber); + if (thisPerson) { + setVariable(fun -> reg, SVT_INT, thisPerson -> walking); + } else { + setVariable(fun -> reg, SVT_INT, 0); + } + return BR_CONTINUE; +} + +builtIn(fetchEvent) { + UNUSEDALL + int obj1, obj2; + if (!getValueType(obj2, SVT_OBJTYPE, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + if (!getValueType(obj1, SVT_OBJTYPE, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + + int fNum = getCombinationFunction(obj1, obj2); + + // Return value + if (fNum) { + setVariable(fun -> reg, SVT_FUNC, fNum); + } else { + setVariable(fun -> reg, SVT_INT, 0); + } + return BR_CONTINUE; +} + +builtIn(deleteFile) { + UNUSEDALL + + char *namNormal = getTextFromAnyVar(fun -> stack -> thisVar); + trimStack(fun -> stack); + char *nam = encodeFilename(namNormal); + delete namNormal; + if (failSecurityCheck(nam)) return BR_ERROR; + setVariable(fun -> reg, SVT_INT, remove(nam)); + delete nam; + + return BR_CONTINUE; +} + +builtIn(renameFile) { + UNUSEDALL + char *temp; + + temp = getTextFromAnyVar(fun -> stack -> thisVar); + char *newnam = encodeFilename(temp); + trimStack(fun -> stack); + if (failSecurityCheck(newnam)) return BR_ERROR; + delete temp; + + temp = getTextFromAnyVar(fun -> stack -> thisVar); + char *nam = encodeFilename(temp); + trimStack(fun -> stack); + if (failSecurityCheck(nam)) return BR_ERROR; + delete temp; + + setVariable(fun -> reg, SVT_INT, rename(nam, newnam)); + delete nam; + delete newnam; + + + return BR_CONTINUE; +} + +builtIn(cacheSound) { + UNUSEDALL + int fileNumber; + if (!getValueType(fileNumber, SVT_FILE, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + if (cacheSound(fileNumber) == -1) return BR_ERROR; + return BR_CONTINUE; +} + +builtIn(burnString) { + UNUSEDALL + char *newText = getTextFromAnyVar(fun -> stack -> thisVar); + trimStack(fun -> stack); + int y, x; + if (!getValueType(y, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + if (!getValueType(x, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + if (x == IN_THE_CENTRE) x = (winWidth - stringWidth(newText)) >> 1; + fixFont(pastePalette); + burnStringToBackdrop(newText, x, y, pastePalette); + delete[] newText; + return BR_CONTINUE; +} + +builtIn(setCharacterSpinSpeed) { + UNUSEDALL + int speed, who; + if (!getValueType(speed, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + if (!getValueType(who, SVT_OBJTYPE, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + + onScreenPerson *thisPerson = findPerson(who); + + if (thisPerson) { + thisPerson -> spinSpeed = speed; + setVariable(fun -> reg, SVT_INT, 1); + } else { + setVariable(fun -> reg, SVT_INT, 0); + } + return BR_CONTINUE; +} + +builtIn(setCharacterAngleOffset) { + UNUSEDALL + int angle, who; + if (!getValueType(angle, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + if (!getValueType(who, SVT_OBJTYPE, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + + onScreenPerson *thisPerson = findPerson(who); + + if (thisPerson) { + thisPerson -> angleOffset = angle; + setVariable(fun -> reg, SVT_INT, 1); + } else { + setVariable(fun -> reg, SVT_INT, 0); + } + return BR_CONTINUE; +} + + +builtIn(transitionMode) { + UNUSEDALL + int n; + if (!getValueType(n, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + fadeMode = n; + trimStack(fun -> stack); + setVariable(fun -> reg, SVT_INT, 1); + return BR_CONTINUE; +} + + +// Removed function - does nothing +builtIn(_rem_updateDisplay) { + UNUSEDALL + trimStack(fun -> stack); + setVariable(fun -> reg, 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 (!getSoundCacheStack(fun -> reg.varData.theStack)) return BR_ERROR; + return BR_CONTINUE; +} + +builtIn(saveCustomData) { + UNUSEDALL + // saveCustomData (thisStack, fileName); + char *fileNameB = getTextFromAnyVar(fun -> stack -> thisVar); + if (!checkNew(fileNameB)) return BR_ERROR; + + char *fileName = encodeFilename(fileNameB); + delete 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 (!stackToFile(fileName, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + delete fileName; + return BR_CONTINUE; +} + +builtIn(loadCustomData) { + UNUSEDALL + + char *newTextA = getTextFromAnyVar(fun -> stack -> thisVar); + if (!checkNew(newTextA)) return BR_ERROR; + + char *newText = encodeFilename(newTextA); + delete newTextA; + + if (failSecurityCheck(newText)) return BR_ERROR; + trimStack(fun -> stack); + + unlinkVar(fun -> reg); + 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 (!fileToStack(newText, fun -> reg.varData.theStack)) return BR_ERROR; + delete newText; + return BR_CONTINUE; +} + +builtIn(setCustomEncoding) { + UNUSEDALL + int n; + if (!getValueType(n, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + saveEncoding = n; + trimStack(fun -> stack); + setVariable(fun -> reg, SVT_INT, 1); + return BR_CONTINUE; +} + +builtIn(freeSound) { + UNUSEDALL + int v; + if (!getValueType(v, SVT_FILE, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + huntKillFreeSound(v); + return BR_CONTINUE; +} + +builtIn(parallaxAdd) { + UNUSEDALL + if (frozenStuff) { + fatal("Can't set background parallax image while frozen"); + return BR_ERROR; + } else { + int wrapX, wrapY, v; + if (!getValueType(wrapY, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + if (!getValueType(wrapX, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + if (!getValueType(v, SVT_FILE, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + + if (!loadParallax(v, wrapX, wrapY)) return BR_ERROR; + setVariable(fun -> reg, SVT_INT, 1); + } + return BR_CONTINUE; +} + +builtIn(parallaxClear) { + UNUSEDALL + killParallax(); + setVariable(fun -> reg, SVT_INT, 1); + return BR_CONTINUE; +} + +builtIn(getPixelColour) { + UNUSEDALL + int x, y; + if (!getValueType(y, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + if (!getValueType(x, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + + unlinkVar(fun -> reg); + 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 (!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 = makeFastArrayFromStack(fun -> reg, 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 makeFastArraySize(fun -> reg, 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 (!getValueType(objectNumber, SVT_OBJTYPE, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + + onScreenPerson *pers = findPerson(objectNumber); + if (pers) { + setVariable(fun -> reg, SVT_INT, pers -> scale * 100); + } else { + setVariable(fun -> reg, SVT_INT, 0); + } + return BR_CONTINUE; +} + +builtIn(getLanguageID) { + UNUSEDALL + setVariable(fun -> reg, SVT_INT, gameSettings.languageID); + return BR_CONTINUE; +} + +// Removed function +builtIn(_rem_launchWith) { + UNUSEDALL + + trimStack(fun -> stack); + trimStack(fun -> stack); + setVariable(fun -> reg, SVT_INT, false); + + return BR_CONTINUE; + +} + +builtIn(getFramesPerSecond) { + UNUSEDALL + setVariable(fun -> reg, SVT_INT, lastFramesPerSecond); + return BR_CONTINUE; +} + +builtIn(showThumbnail) { + UNUSEDALL + int x, y; + if (!getValueType(y, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + if (!getValueType(x, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + + // Encode the name!Encode the name! + char *aaaaa = getTextFromAnyVar(fun -> stack -> thisVar); + // deb ("Got name:", aaaaa;) + trimStack(fun -> stack); + // deb ("About to encode", aaaaa); + char *file = encodeFilename(aaaaa); + // deb ("Made new name", file); + // deb ("aaaaa is still ", aaaaa); + delete[] aaaaa; + // deb ("Deleted", "aaaaa"); + showThumbnail(file, x, y); + delete[] file; + return BR_CONTINUE; +} + +builtIn(setThumbnailSize) { + UNUSEDALL + if (!getValueType(thumbHeight, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + if (!getValueType(thumbWidth, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + if (thumbWidth < 0 || thumbHeight < 0 || thumbWidth > winWidth || thumbHeight > winHeight) { + char buff[50]; + sprintf(buff, "%d x %d", thumbWidth, thumbHeight); + fatal("Invalid thumbnail size", buff); + return BR_ERROR; + } + return BR_CONTINUE; +} + +builtIn(hasFlag) { + UNUSEDALL + int objNum, flagIndex; + if (!getValueType(flagIndex, SVT_INT, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + if (!getValueType(objNum, SVT_OBJTYPE, fun -> stack -> thisVar)) return BR_ERROR; + trimStack(fun -> stack); + objectType *objT = findObjectType(objNum); + if (!objT) return BR_ERROR; + setVariable(fun -> reg, SVT_INT, objT->flags & (1 << flagIndex)); + return BR_CONTINUE; +} + +builtIn(snapshotGrab) { + UNUSEDALL + return snapshot() ? BR_CONTINUE : BR_ERROR; +} + +builtIn(snapshotClear) { + UNUSEDALL + nosnapshot(); + return BR_CONTINUE; +} + +builtIn(bodgeFilenames) { + UNUSEDALL + bool lastValue = allowAnyFilename; + allowAnyFilename = getBoolean(fun -> stack -> thisVar); + trimStack(fun -> stack); + setVariable(fun -> reg, SVT_INT, lastValue); + return BR_CONTINUE; +} + +// Deprecated - does nothing. +builtIn(_rem_registryGetString) { + UNUSEDALL + trimStack(fun -> stack); + trimStack(fun -> stack); + setVariable(fun -> reg, SVT_INT, 0); + + return BR_CONTINUE; +} + +builtIn(quitWithFatalError) { + UNUSEDALL + char *mess = getTextFromAnyVar(fun -> stack -> thisVar); + 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 = blur_createSettings(numParams, fun->stack); + setVariable(fun -> reg, SVT_INT, done ? 1 : 0); + return BR_CONTINUE; +} + +builtIn(doBackgroundEffect) { + UNUSEDALL + bool done = blurScreen(); + setVariable(fun -> reg, SVT_INT, done ? 1 : 0); + return BR_CONTINUE; +} + +#pragma mark - +#pragma mark Other functions + +//------------------------------------- + +#define FUNC(special,name) {builtIn_ ## name}, +static builtInFunctionData builtInFunctionArray[] = { +#include "CommonCode/functionlist.h" +}; +#undef FUNC + +#define FUNC(special,name) {#name}, +char builtInFunctionNames[][25] = { +#include "CommonCode/functionlist.h" +}; +#undef FUNC + +#define NUM_FUNCS (sizeof (builtInFunctionArray) / sizeof (builtInFunctionArray[0])) + + + +builtReturn callBuiltIn(int whichFunc, int numParams, loadedFunction *fun) { + // fprintf (stderr, "Calling function %d: %s\n", whichFunc, builtInFunctionNames[whichFunc]); fflush (stderr); + if (numBIFNames) { + + // deb ("IN:", (fun -> originalNumber < numUserFunc) ? allUserFunc[fun -> originalNumber] : "Unknown user function"); + // deb ("GO:", (whichFunc < numBIFNames) ? allBIFNames[whichFunc] : "Unknown built-in function"); + + setFatalInfo( + (fun -> originalNumber < numUserFunc) ? allUserFunc[fun -> originalNumber] : "Unknown user function", + (whichFunc < numBIFNames) ? allBIFNames[whichFunc] : "Unknown built-in function"); + } + + if (whichFunc < NUM_FUNCS) { + if (paramNum[whichFunc] != -1) { + if (paramNum[whichFunc] != numParams) { + char buff[100]; + sprintf(buff, "Built in function must have %i parameter%s", + paramNum[whichFunc], + (paramNum[whichFunc] == 1) ? "" : "s"); + + fatal(copyString(buff)); + return BR_ERROR; + } + } + + if (builtInFunctionArray[whichFunc].func) { + //fprintf (stderr, "Calling %i: %s\n", whichFunc, builtInFunctionNames[whichFunc]); + return builtInFunctionArray[whichFunc].func(numParams, fun); + } + } + + fatal("Unknown / unimplemented built-in function."); + return BR_ERROR; +} + |