/* 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. * */ #include "sludge/debug.h" #include "sludge/allfiles.h" #include "sludge/sludger.h" #include "sludge/builtin.h" #include "sludge/stringy.h" #include "sludge/newfatal.h" #include "sludge/cursors.h" #include "sludge/statusba.h" #include "sludge/loadsave.h" #include "sludge/backdrop.h" #include "sludge/bg_effects.h" #include "sludge/sprites.h" #include "sludge/fonttext.h" #include "sludge/sprbanks.h" #include "sludge/people.h" #include "sludge/sound.h" #include "sludge/objtypes.h" #include "sludge/floor.h" #include "sludge/zbuffer.h" #include "sludge/talk.h" #include "sludge/region.h" #include "sludge/language.h" #include "sludge/moreio.h" #include "sludge/movie.h" #include "sludge/savedata.h" #include "sludge/freeze.h" #include "sludge/language.h" #include "sludge/thumbnail.h" #include "sludge/graphics.h" #include "sludge/sludge.h" #include "sludge/CommonCode/utf8.h" namespace Sludge { 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; #if 0 extern unsigned int currentBlankColour; #endif 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 0 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); } } #endif // Return value setVariable(fun->reg, SVT_INT, 0/*(fp != NULL)*/); //TODO:false value #if 0 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 (failSecurityCheck(loadNow)) return BR_ERROR; Common::File fd; if (fd.open(loadNow)) { fd.close(); return BR_KEEP_AND_PAUSE; } delete loadNow; loadNow = NULL; 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 (killResizeBackdrop(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; #if 0 currentBlankColour = g_sludge->getOrigPixelFormat()->RGBToColor(red & 255, green & 255, blue & 255); #endif 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; gameDir = joinStrings(gamePath, "/"); 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; } } // End of namespace Sludge