1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #include "common/config-manager.h"
24 #include "common/random.h"
25 #include "common/savefile.h"
26 #include "common/system.h"
27 
28 #include "sludge/builtin.h"
29 #include "sludge/cursors.h"
30 #include "sludge/event.h"
31 #include "sludge/floor.h"
32 #include "sludge/fonttext.h"
33 #include "sludge/function.h"
34 #include "sludge/graphics.h"
35 #include "sludge/moreio.h"
36 #include "sludge/movie.h"
37 #include "sludge/newfatal.h"
38 #include "sludge/objtypes.h"
39 #include "sludge/people.h"
40 #include "sludge/region.h"
41 #include "sludge/savedata.h"
42 #include "sludge/sludger.h"
43 #include "sludge/sound.h"
44 #include "sludge/speech.h"
45 #include "sludge/statusba.h"
46 #include "sludge/sludge.h"
47 #include "sludge/timing.h"
48 
49 namespace Sludge {
50 
51 Variable *launchResult = NULL;
52 
53 extern bool allowAnyFilename;
54 extern VariableStack *noStack;
55 extern int numBIFNames, numUserFunc;
56 
57 extern Common::String *allUserFunc;
58 extern Common::String *allBIFNames;
59 
failSecurityCheck(const Common::String & fn)60 bool failSecurityCheck(const Common::String &fn) {
61 	if (fn.empty())
62 		return true;
63 
64 	for (uint i = 0; i < fn.size(); ++i) {
65 		switch (fn[i]) {
66 		case ':':
67 		case '\\':
68 		case '/':
69 		case '*':
70 		case '?':
71 		case '"':
72 		case '<':
73 		case '>':
74 		case '|':
75 			fatal("Filenames may not contain the following characters: \n\n\\  /  :  \"  <  >  |  ?  *\n\nConsequently, the following filename is not allowed:", fn);
76 			return true;
77 		default:
78 			break;
79 		}
80 	}
81 	return false;
82 }
83 
84 extern LoadedFunction *saverFunc;
85 
86 typedef BuiltReturn (*builtInSludgeFunc)(int numParams, LoadedFunction *fun);
87 struct builtInFunctionData {
88 	const char *name;
89 	builtInSludgeFunc func;
90 	int paramNum;
91 };
92 
93 #define builtIn(a)          static BuiltReturn builtIn_ ## a (int numParams, LoadedFunction *fun)
94 #define UNUSEDALL           (void) (0 && sizeof(numParams) && sizeof (fun));
95 
96 
sayCore(int numParams,LoadedFunction * fun,bool sayIt)97 static BuiltReturn sayCore(int numParams, LoadedFunction *fun, bool sayIt) {
98 	int fileNum = -1;
99 	Common::String newText;
100 	int objT, p;
101 	killSpeechTimers();
102 
103 	switch (numParams) {
104 	case 3:
105 		if (!fun->stack->thisVar.getValueType(fileNum, SVT_FILE))
106 			return BR_ERROR;
107 		trimStack(fun->stack);
108 		// fall through
109 
110 	case 2:
111 		newText = fun->stack->thisVar.getTextFromAnyVar();
112 		trimStack(fun->stack);
113 		if (!fun->stack->thisVar.getValueType(objT, SVT_OBJTYPE))
114 			return BR_ERROR;
115 		trimStack(fun->stack);
116 		p = g_sludge->_speechMan->wrapSpeech(newText, objT, fileNum, sayIt);
117 		fun->timeLeft = p;
118 		//debugOut ("BUILTIN: sayCore: %s (%i)\n", newText, p);
119 		fun->isSpeech = true;
120 		return BR_KEEP_AND_PAUSE;
121 
122 	default:
123 		break;
124 	}
125 
126 	fatal("Function should have either 2 or 3 parameters");
127 	return BR_ERROR;
128 }
129 
130 #pragma mark -
131 #pragma mark Built in functions
132 
builtIn(say)133 builtIn(say) {
134 	UNUSEDALL
135 	return sayCore(numParams, fun, true);
136 }
137 
builtIn(think)138 builtIn(think) {
139 	UNUSEDALL
140 	return sayCore(numParams, fun, false);
141 }
142 
builtIn(freeze)143 builtIn(freeze) {
144 	UNUSEDALL
145 	g_sludge->_gfxMan->freeze();
146 	freezeSubs();
147 	fun->freezerLevel = 0;
148 	return BR_CONTINUE;
149 }
150 
builtIn(unfreeze)151 builtIn(unfreeze) {
152 	UNUSEDALL
153 	g_sludge->_gfxMan->unfreeze();
154 	unfreezeSubs();
155 	return BR_CONTINUE;
156 }
157 
builtIn(howFrozen)158 builtIn(howFrozen) {
159 	UNUSEDALL
160 	fun->reg.setVariable(SVT_INT, g_sludge->_gfxMan->howFrozen());
161 	return BR_CONTINUE;
162 }
163 
builtIn(setCursor)164 builtIn(setCursor) {
165 	UNUSEDALL
166 	PersonaAnimation *aa = fun->stack->thisVar.getAnimationFromVar();
167 	g_sludge->_cursorMan->pickAnimCursor(aa);
168 	trimStack(fun->stack);
169 	return BR_CONTINUE;
170 }
171 
builtIn(getMouseX)172 builtIn(getMouseX) {
173 	UNUSEDALL
174 	fun->reg.setVariable(SVT_INT, g_sludge->_evtMan->mouseX() + g_sludge->_gfxMan->getCamX());
175 	return BR_CONTINUE;
176 }
177 
builtIn(getMouseY)178 builtIn(getMouseY) {
179 	UNUSEDALL
180 	fun->reg.setVariable(SVT_INT, g_sludge->_evtMan->mouseY() + g_sludge->_gfxMan->getCamY());
181 	return BR_CONTINUE;
182 }
183 
builtIn(getMouseScreenX)184 builtIn(getMouseScreenX) {
185 	UNUSEDALL
186 	fun->reg.setVariable(SVT_INT, g_sludge->_evtMan->mouseX() * g_sludge->_gfxMan->getCamZoom());
187 	return BR_CONTINUE;
188 }
189 
builtIn(getMouseScreenY)190 builtIn(getMouseScreenY) {
191 	UNUSEDALL
192 	fun->reg.setVariable(SVT_INT, g_sludge->_evtMan->mouseY() * g_sludge->_gfxMan->getCamZoom());
193 	return BR_CONTINUE;
194 }
195 
builtIn(getStatusText)196 builtIn(getStatusText) {
197 	UNUSEDALL
198 	fun->reg.makeTextVar(g_sludge->_statusBar->statusBarText());
199 	return BR_CONTINUE;
200 }
201 
builtIn(getMatchingFiles)202 builtIn(getMatchingFiles) {
203 	UNUSEDALL
204 	Common::String newText = fun->stack->thisVar.getTextFromAnyVar();
205 	trimStack(fun->stack);
206 	fun->reg.unlinkVar();
207 
208 	// Return value
209 	fun->reg.varType = SVT_STACK;
210 	fun->reg.varData.theStack = new StackHandler;
211 	if (!checkNew(fun->reg.varData.theStack))
212 		return BR_ERROR;
213 	fun->reg.varData.theStack->first = NULL;
214 	fun->reg.varData.theStack->last = NULL;
215 	fun->reg.varData.theStack->timesUsed = 1;
216 	if (!fun->reg.varData.theStack->getSavedGamesStack(newText))
217 		return BR_ERROR;
218 	return BR_CONTINUE;
219 }
220 
builtIn(saveGame)221 builtIn(saveGame) {
222 	UNUSEDALL
223 
224 	if (g_sludge->_gfxMan->isFrozen()) {
225 		fatal("Can't save game state while the engine is frozen");
226 	}
227 
228 	g_sludge->loadNow = fun->stack->thisVar.getTextFromAnyVar();
229 	trimStack(fun->stack);
230 
231 	Common::String aaaaa = encodeFilename(g_sludge->loadNow);
232 	g_sludge->loadNow.clear();
233 	if (failSecurityCheck(aaaaa))
234 		return BR_ERROR;      // Won't fail if encoded, how cool is that? OK, not very.
235 
236 	g_sludge->loadNow = ":" + aaaaa;
237 
238 	fun->reg.setVariable(SVT_INT, 0);
239 	saverFunc = fun;
240 	return BR_KEEP_AND_PAUSE;
241 }
242 
builtIn(fileExists)243 builtIn(fileExists) {
244 	UNUSEDALL
245 	g_sludge->loadNow = fun->stack->thisVar.getTextFromAnyVar();
246 	trimStack(fun->stack);
247 	Common::String aaaaa = encodeFilename(g_sludge->loadNow);
248 	g_sludge->loadNow.clear();
249 
250 	if (failSecurityCheck(aaaaa))
251 		return BR_ERROR;
252 
253 	bool exist = false;
254 
255 	Common::File fd;
256 	if (fd.open(aaaaa)) {
257 		exist = true;
258 		fd.close();
259 	} else {
260 		Common::InSaveFile *fp = g_system->getSavefileManager()->openForLoading(aaaaa);
261 		if (fp) {
262 			exist = true;
263 			delete fp;
264 		}
265 	}
266 
267 	// Return value
268 	fun->reg.setVariable(SVT_INT, exist);
269 	return BR_CONTINUE;
270 }
271 
builtIn(loadGame)272 builtIn(loadGame) {
273 	UNUSEDALL
274 	Common::String aaaaa = fun->stack->thisVar.getTextFromAnyVar();
275 	trimStack(fun->stack);
276 	g_sludge->loadNow.clear();
277 	g_sludge->loadNow = encodeFilename(aaaaa);
278 
279 	if (g_sludge->_gfxMan->isFrozen()) {
280 		fatal("Can't load a saved game while the engine is frozen");
281 	}
282 	if (failSecurityCheck(g_sludge->loadNow))
283 		return BR_ERROR;
284 	Common::InSaveFile *fp = g_system->getSavefileManager()->openForLoading(g_sludge->loadNow);
285 	if (fp) {
286 		delete fp;
287 		return BR_KEEP_AND_PAUSE;
288 	}
289 	debug("not find sav file");
290 
291 	g_sludge->loadNow.clear();
292 	return BR_CONTINUE;
293 }
294 
295 //--------------------------------------
296 #pragma mark -
297 #pragma mark Background image - Painting
298 
builtIn(blankScreen)299 builtIn(blankScreen) {
300 	UNUSEDALL
301 	g_sludge->_gfxMan->blankAllScreen();
302 	return BR_CONTINUE;
303 }
304 
builtIn(blankArea)305 builtIn(blankArea) {
306 	UNUSEDALL
307 	int x1, y1, x2, y2;
308 	if (!fun->stack->thisVar.getValueType(y2, SVT_INT))
309 		return BR_ERROR;
310 	trimStack(fun->stack);
311 	if (!fun->stack->thisVar.getValueType(x2, SVT_INT))
312 		return BR_ERROR;
313 	trimStack(fun->stack);
314 	if (!fun->stack->thisVar.getValueType(y1, SVT_INT))
315 		return BR_ERROR;
316 	trimStack(fun->stack);
317 	if (!fun->stack->thisVar.getValueType(x1, SVT_INT))
318 		return BR_ERROR;
319 	trimStack(fun->stack);
320 	g_sludge->_gfxMan->blankScreen(x1, y1, x2, y2);
321 	return BR_CONTINUE;
322 }
323 
builtIn(darkBackground)324 builtIn(darkBackground) {
325 	UNUSEDALL
326 	g_sludge->_gfxMan->darkScreen();
327 	return BR_CONTINUE;
328 }
329 
builtIn(addOverlay)330 builtIn(addOverlay) {
331 	UNUSEDALL
332 	int fileNumber, xPos, yPos;
333 	if (!fun->stack->thisVar.getValueType(yPos, SVT_INT))
334 		return BR_ERROR;
335 	trimStack(fun->stack);
336 	if (!fun->stack->thisVar.getValueType(xPos, SVT_INT))
337 		return BR_ERROR;
338 	trimStack(fun->stack);
339 	if (!fun->stack->thisVar.getValueType(fileNumber, SVT_FILE))
340 		return BR_ERROR;
341 	trimStack(fun->stack);
342 	g_sludge->_gfxMan->loadBackDrop(fileNumber, xPos, yPos);
343 	return BR_CONTINUE;
344 }
345 
builtIn(mixOverlay)346 builtIn(mixOverlay) {
347 	UNUSEDALL
348 	int fileNumber, xPos, yPos;
349 	if (!fun->stack->thisVar.getValueType(yPos, SVT_INT))
350 		return BR_ERROR;
351 	trimStack(fun->stack);
352 	if (!fun->stack->thisVar.getValueType(xPos, SVT_INT))
353 		return BR_ERROR;
354 	trimStack(fun->stack);
355 	if (!fun->stack->thisVar.getValueType(fileNumber, SVT_FILE))
356 		return BR_ERROR;
357 	trimStack(fun->stack);
358 	g_sludge->_gfxMan->mixBackDrop(fileNumber, xPos, yPos);
359 	return BR_CONTINUE;
360 }
361 
builtIn(pasteImage)362 builtIn(pasteImage) {
363 	UNUSEDALL
364 	int x, y;
365 	if (!fun->stack->thisVar.getValueType(y, SVT_INT))
366 		return BR_ERROR;
367 	trimStack(fun->stack);
368 	if (!fun->stack->thisVar.getValueType(x, SVT_INT))
369 		return BR_ERROR;
370 	trimStack(fun->stack);
371 	PersonaAnimation *pp = fun->stack->thisVar.getAnimationFromVar();
372 	trimStack(fun->stack);
373 	if (pp == NULL)
374 		return BR_CONTINUE;
375 
376 	g_sludge->_cursorMan->pasteCursor(x, y, pp);
377 
378 	delete pp;
379 
380 	return BR_CONTINUE;
381 }
382 
383 #pragma mark -
384 #pragma mark Background Image - Scrolling
385 
builtIn(setSceneDimensions)386 builtIn(setSceneDimensions) {
387 	UNUSEDALL
388 	int x, y;
389 	if (!fun->stack->thisVar.getValueType(y, SVT_INT))
390 		return BR_ERROR;
391 	trimStack(fun->stack);
392 	if (!fun->stack->thisVar.getValueType(x, SVT_INT))
393 		return BR_ERROR;
394 	trimStack(fun->stack);
395 	if (g_sludge->_gfxMan->killResizeBackdrop(x, y)) {
396 		g_sludge->_gfxMan->blankScreen(0, 0, x, y);
397 		return BR_CONTINUE;
398 	}
399 	fatal("Out of memory creating new backdrop.");
400 	return BR_ERROR;
401 }
402 
builtIn(aimCamera)403 builtIn(aimCamera) {
404 	UNUSEDALL
405 	int cameraX, cameraY;
406 	if (!fun->stack->thisVar.getValueType(cameraY, SVT_INT))
407 		return BR_ERROR;
408 	trimStack(fun->stack);
409 	if (!fun->stack->thisVar.getValueType(cameraX, SVT_INT))
410 		return BR_ERROR;
411 	trimStack(fun->stack);
412 
413 	g_sludge->_gfxMan->aimCamera(cameraX, cameraY);
414 
415 	return BR_CONTINUE;
416 }
417 
builtIn(zoomCamera)418 builtIn(zoomCamera) {
419 	UNUSEDALL
420 	int z;
421 	if (!fun->stack->thisVar.getValueType(z, SVT_INT))
422 		return BR_ERROR;
423 	trimStack(fun->stack);
424 
425 	g_sludge->_gfxMan->zoomCamera(z);
426 
427 	return BR_CONTINUE;
428 }
429 
430 #pragma mark -
431 #pragma mark Variables
432 
builtIn(pickOne)433 builtIn(pickOne) {
434 	UNUSEDALL
435 	if (!numParams) {
436 		fatal("Built-in function should have at least 1 parameter");
437 		return BR_ERROR;
438 	}
439 
440 	int i;
441 
442 	i = g_sludge->getRandomSource()->getRandomNumber(numParams - 1);
443 
444 	// Return value
445 	while (numParams--) {
446 		if (i == numParams)
447 			fun->reg.copyFrom(fun->stack->thisVar);
448 		trimStack(fun->stack);
449 	}
450 	return BR_CONTINUE;
451 }
452 
builtIn(substring)453 builtIn(substring) {
454 	UNUSEDALL
455 	Common::String wholeString;
456 	int start, length;
457 
458 	//debugOut ("BUILTIN: substring\n");
459 
460 	if (!fun->stack->thisVar.getValueType(length, SVT_INT))
461 		return BR_ERROR;
462 	trimStack(fun->stack);
463 	if (!fun->stack->thisVar.getValueType(start, SVT_INT))
464 		return BR_ERROR;
465 	trimStack(fun->stack);
466 	wholeString = fun->stack->thisVar.getTextFromAnyVar();
467 	trimStack(fun->stack);
468 
469 	Common::U32String str32 = wholeString.decode(Common::kUtf8);
470 
471 	if ((int)str32.size() < start + length) {
472 		length = str32.size() - start;
473 		if ((int)str32.size() < start) {
474 			start = 0;
475 		}
476 	}
477 	if (length < 0) {
478 		length = 0;
479 	}
480 
481 	Common::String newString = str32.substr(start, length).encode(Common::kUtf8);
482 
483 	fun->reg.makeTextVar(newString);
484 	return BR_CONTINUE;
485 }
486 
builtIn(stringLength)487 builtIn(stringLength) {
488 	UNUSEDALL
489 	Common::String newText = fun->stack->thisVar.getTextFromAnyVar();
490 	trimStack(fun->stack);
491 	fun->reg.setVariable(SVT_INT, g_sludge->_txtMan->stringLength(newText));
492 	return BR_CONTINUE;
493 }
494 
builtIn(newStack)495 builtIn(newStack) {
496 	UNUSEDALL
497 	fun->reg.unlinkVar();
498 
499 	// Return value
500 	fun->reg.varType = SVT_STACK;
501 	fun->reg.varData.theStack = new StackHandler;
502 	if (!checkNew(fun->reg.varData.theStack))
503 		return BR_ERROR;
504 	fun->reg.varData.theStack->first = NULL;
505 	fun->reg.varData.theStack->last = NULL;
506 	fun->reg.varData.theStack->timesUsed = 1;
507 	while (numParams--) {
508 		if (!addVarToStack(fun->stack->thisVar, fun->reg.varData.theStack->first))
509 			return BR_ERROR;
510 		if (fun->reg.varData.theStack->last == NULL) {
511 			fun->reg.varData.theStack->last = fun->reg.varData.theStack->first;
512 		}
513 		trimStack(fun->stack);
514 	}
515 	return BR_CONTINUE;
516 }
517 
518 // wait is exactly the same function, but limited to 2 parameters
519 #define builtIn_wait builtIn_newStack
520 
builtIn(stackSize)521 builtIn(stackSize) {
522 	UNUSEDALL
523 	switch (fun->stack->thisVar.varType) {
524 	case SVT_STACK:
525 		// Return value
526 		fun->reg.setVariable(SVT_INT, fun->stack->thisVar.varData.theStack->getStackSize());
527 		trimStack(fun->stack);
528 		return BR_CONTINUE;
529 
530 	case SVT_FASTARRAY:
531 		// Return value
532 		fun->reg.setVariable(SVT_INT, fun->stack->thisVar.varData.fastArray->size);
533 		trimStack(fun->stack);
534 		return BR_CONTINUE;
535 
536 	default:
537 		break;
538 	}
539 	fatal("Parameter isn't a stack or a fast array.");
540 	return BR_ERROR;
541 }
542 
builtIn(copyStack)543 builtIn(copyStack) {
544 	UNUSEDALL
545 	if (fun->stack->thisVar.varType != SVT_STACK) {
546 		fatal("Parameter isn't a stack.");
547 		return BR_ERROR;
548 	}
549 	// Return value
550 	if (!fun->reg.copyStack(fun->stack->thisVar))
551 		return BR_ERROR;
552 	trimStack(fun->stack);
553 	return BR_CONTINUE;
554 }
555 
builtIn(pushToStack)556 builtIn(pushToStack) {
557 	UNUSEDALL
558 	if (fun->stack->next->thisVar.varType != SVT_STACK) {
559 		fatal("Parameter isn't a stack");
560 		return BR_ERROR;
561 	}
562 
563 	if (!addVarToStack(fun->stack->thisVar, fun->stack->next->thisVar.varData.theStack->first))
564 		return BR_ERROR;
565 
566 	if (fun->stack->next->thisVar.varData.theStack->first->next == NULL)
567 		fun->stack->next->thisVar.varData.theStack->last = fun->stack->next->thisVar.varData.theStack->first;
568 
569 	trimStack(fun->stack);
570 	trimStack(fun->stack);
571 	return BR_CONTINUE;
572 }
573 
builtIn(enqueue)574 builtIn(enqueue) {
575 	UNUSEDALL
576 	if (fun->stack->next->thisVar.varType != SVT_STACK) {
577 		fatal("Parameter isn't a stack");
578 		return BR_ERROR;
579 	}
580 
581 	if (fun->stack->next->thisVar.varData.theStack->first == NULL) {
582 		if (!addVarToStack(fun->stack->thisVar, fun->stack->next->thisVar.varData.theStack->first))
583 			return BR_ERROR;
584 
585 		fun->stack->next->thisVar.varData.theStack->last = fun->stack->next->thisVar.varData.theStack->first;
586 	} else {
587 		if (!addVarToStack(fun->stack->thisVar, fun->stack->next->thisVar.varData.theStack->last->next))
588 			return BR_ERROR;
589 		fun->stack->next->thisVar.varData.theStack->last = fun->stack->next->thisVar.varData.theStack->last->next;
590 	}
591 
592 	trimStack(fun->stack);
593 	trimStack(fun->stack);
594 	return BR_CONTINUE;
595 }
596 
builtIn(deleteFromStack)597 builtIn(deleteFromStack) {
598 	UNUSEDALL
599 	if (fun->stack->next->thisVar.varType != SVT_STACK) {
600 		fatal("Parameter isn't a stack.");
601 		return BR_ERROR;
602 	}
603 
604 	// Return value
605 	fun->reg.setVariable(SVT_INT, deleteVarFromStack(fun->stack->thisVar, fun->stack->next->thisVar.varData.theStack->first, false));
606 
607 	// Horrible hacking because 'last' value might now be wrong!
608 	VariableStack *nextFirstStack = fun->stack->next->thisVar.varData.theStack->first;
609 	fun->stack->next->thisVar.varData.theStack->last = (nextFirstStack == NULL) ? NULL : nextFirstStack->stackFindLast();
610 
611 	trimStack(fun->stack);
612 	trimStack(fun->stack);
613 	return BR_CONTINUE;
614 }
615 
builtIn(deleteAllFromStack)616 builtIn(deleteAllFromStack) {
617 	UNUSEDALL
618 	if (fun->stack->next->thisVar.varType != SVT_STACK) {
619 		fatal("Parameter isn't a stack.");
620 		return BR_ERROR;
621 	}
622 
623 	// Return value
624 	fun->reg.setVariable(SVT_INT, deleteVarFromStack(fun->stack->thisVar, fun->stack->next->thisVar.varData.theStack->first, true));
625 
626 	// Horrible hacking because 'last' value might now be wrong!
627 	VariableStack *nextFirstStack = fun->stack->next->thisVar.varData.theStack->first;
628 	fun->stack->next->thisVar.varData.theStack->last = (nextFirstStack == NULL) ? NULL : nextFirstStack->stackFindLast();
629 
630 	trimStack(fun->stack);
631 	trimStack(fun->stack);
632 	return BR_CONTINUE;
633 }
634 
builtIn(popFromStack)635 builtIn(popFromStack) {
636 	UNUSEDALL
637 	if (fun->stack->thisVar.varType != SVT_STACK) {
638 		fatal("Parameter isn't a stack.");
639 		return BR_ERROR;
640 	}
641 	if (fun->stack->thisVar.varData.theStack->first == NULL) {
642 		fatal("The stack's empty.");
643 		return BR_ERROR;
644 	}
645 
646 	// Return value
647 	fun->reg.copyFrom(fun->stack->thisVar.varData.theStack->first->thisVar);
648 	trimStack(fun->stack->thisVar.varData.theStack->first);
649 	trimStack(fun->stack);
650 	return BR_CONTINUE;
651 }
652 
builtIn(peekStart)653 builtIn(peekStart) {
654 	UNUSEDALL
655 	if (fun->stack->thisVar.varType != SVT_STACK) {
656 		fatal("Parameter isn't a stack.");
657 		return BR_ERROR;
658 	}
659 	if (fun->stack->thisVar.varData.theStack->first == NULL) {
660 		fatal("The stack's empty.");
661 		return BR_ERROR;
662 	}
663 
664 	// Return value
665 	fun->reg.copyFrom(fun->stack->thisVar.varData.theStack->first->thisVar);
666 	trimStack(fun->stack);
667 	return BR_CONTINUE;
668 }
669 
builtIn(peekEnd)670 builtIn(peekEnd) {
671 	UNUSEDALL
672 	if (fun->stack->thisVar.varType != SVT_STACK) {
673 		fatal("Parameter isn't a stack.");
674 		return BR_ERROR;
675 	}
676 	if (fun->stack->thisVar.varData.theStack->first == NULL) {
677 		fatal("The stack's empty.");
678 		return BR_ERROR;
679 	}
680 
681 	// Return value
682 	fun->reg.copyFrom(fun->stack->thisVar.varData.theStack->last->thisVar);
683 	trimStack(fun->stack);
684 	return BR_CONTINUE;
685 }
686 
builtIn(random)687 builtIn(random) {
688 	UNUSEDALL
689 	int num;
690 
691 	if (!fun->stack->thisVar.getValueType(num, SVT_INT))
692 		return BR_ERROR;
693 
694 	trimStack(fun->stack);
695 	if (num <= 0)
696 		num = 1;
697 	fun->reg.setVariable(SVT_INT, g_sludge->getRandomSource()->getRandomNumber(num - 1));
698 	return BR_CONTINUE;
699 }
700 
getRGBParams(int & red,int & green,int & blue,LoadedFunction * fun)701 static bool getRGBParams(int &red, int &green, int &blue, LoadedFunction *fun) {
702 	if (!fun->stack->thisVar.getValueType(blue, SVT_INT))
703 		return false;
704 	trimStack(fun->stack);
705 	if (!fun->stack->thisVar.getValueType(green, SVT_INT))
706 		return false;
707 	trimStack(fun->stack);
708 	if (!fun->stack->thisVar.getValueType(red, SVT_INT))
709 		return false;
710 	trimStack(fun->stack);
711 	return true;
712 }
713 
builtIn(setStatusColour)714 builtIn(setStatusColour) {
715 	UNUSEDALL
716 	int red, green, blue;
717 
718 	if (!getRGBParams(red, green, blue, fun))
719 		return BR_ERROR;
720 
721 	g_sludge->_statusBar->statusBarColour((byte)red, (byte)green, (byte)blue);
722 	return BR_CONTINUE;
723 }
724 
builtIn(setLitStatusColour)725 builtIn(setLitStatusColour) {
726 	UNUSEDALL
727 	int red, green, blue;
728 
729 	if (!getRGBParams(red, green, blue, fun))
730 		return BR_ERROR;
731 
732 	g_sludge->_statusBar->statusBarLitColour((byte)red, (byte)green, (byte)blue);
733 	return BR_CONTINUE;
734 }
735 
builtIn(setPasteColour)736 builtIn(setPasteColour) {
737 	UNUSEDALL
738 	int red, green, blue;
739 
740 	if (!getRGBParams(red, green, blue, fun))
741 		return BR_ERROR;
742 
743 	g_sludge->_txtMan->setPasterColor((byte)red, (byte)green, (byte)blue);
744 	return BR_CONTINUE;
745 }
746 
builtIn(setBlankColour)747 builtIn(setBlankColour) {
748 	UNUSEDALL
749 	int red, green, blue;
750 
751 	if (!getRGBParams(red, green, blue, fun))
752 		return BR_ERROR;
753 
754 	g_sludge->_gfxMan->setBlankColor(red, green, blue);
755 	fun->reg.setVariable(SVT_INT, 1);
756 	return BR_CONTINUE;
757 }
758 
builtIn(setBurnColour)759 builtIn(setBurnColour) {
760 	UNUSEDALL
761 	int red, green, blue;
762 
763 	if (!getRGBParams(red, green, blue, fun))
764 		return BR_ERROR;
765 
766 	g_sludge->_gfxMan->setBurnColor(red, green, blue);
767 	fun->reg.setVariable(SVT_INT, 1);
768 	return BR_CONTINUE;
769 }
770 
builtIn(setFont)771 builtIn(setFont) {
772 	UNUSEDALL
773 	int fileNumber, newHeight;
774 	if (!fun->stack->thisVar.getValueType(newHeight, SVT_INT))
775 		return BR_ERROR;
776 	//              newDebug ("  Height:", newHeight);
777 	trimStack(fun->stack);
778 	Common::String newText = fun->stack->thisVar.getTextFromAnyVar();
779 	//              newDebug ("  Character supported:", newText);
780 	trimStack(fun->stack);
781 	if (!fun->stack->thisVar.getValueType(fileNumber, SVT_FILE))
782 		return BR_ERROR;
783 	//              newDebug ("  File:", fileNumber);
784 	trimStack(fun->stack);
785 	if (!g_sludge->_txtMan->loadFont(fileNumber, newText, newHeight))
786 		return BR_ERROR;
787 	//              newDebug ("  Done!");
788 	return BR_CONTINUE;
789 }
790 
builtIn(inFont)791 builtIn(inFont) {
792 	UNUSEDALL
793 	Common::String newText = fun->stack->thisVar.getTextFromAnyVar();
794 	trimStack(fun->stack);
795 
796 	// Return value
797 	fun->reg.setVariable(SVT_INT, g_sludge->_txtMan->isInFont(newText));
798 	return BR_CONTINUE;
799 }
800 
builtIn(pasteString)801 builtIn(pasteString) {
802 	UNUSEDALL
803 	Common::String newText = fun->stack->thisVar.getTextFromAnyVar();
804 	trimStack(fun->stack);
805 	int y, x;
806 	if (!fun->stack->thisVar.getValueType(y, SVT_INT))
807 		return BR_ERROR;
808 	trimStack(fun->stack);
809 	if (!fun->stack->thisVar.getValueType(x, SVT_INT))
810 		return BR_ERROR;
811 	trimStack(fun->stack);
812 	if (x == IN_THE_CENTRE)
813 		x = g_sludge->_gfxMan->getCenterX(g_sludge->_txtMan->stringWidth(newText));
814 	g_sludge->_txtMan->pasteStringToBackdrop(newText, x, y);
815 	return BR_CONTINUE;
816 }
817 
builtIn(anim)818 builtIn(anim) {
819 	UNUSEDALL
820 	if (numParams < 2) {
821 		fatal("Built-in function anim() must have at least 2 parameters.");
822 		return BR_ERROR;
823 	}
824 
825 	// First store the frame numbers and take 'em off the stack
826 	PersonaAnimation *ba = new PersonaAnimation(numParams - 1, fun->stack);
827 
828 	// Only remaining paramter is the file number
829 	int fileNumber;
830 	if (!fun->stack->thisVar.getValueType(fileNumber, SVT_FILE))
831 		return BR_ERROR;
832 	trimStack(fun->stack);
833 
834 	// Load the required sprite bank
835 	LoadedSpriteBank *sprBanky = g_sludge->_gfxMan->loadBankForAnim(fileNumber);
836 	if (!sprBanky) {
837 		delete ba;
838 		return BR_ERROR;    // File not found, fatal done already
839 	}
840 	ba->theSprites = sprBanky;
841 
842 	// Return value
843 	fun->reg.makeAnimationVariable(ba);
844 
845 	return BR_CONTINUE;
846 }
847 
builtIn(costume)848 builtIn(costume) {
849 	UNUSEDALL
850 	Persona *newPersona = new Persona;
851 	if (!checkNew(newPersona))
852 		return BR_ERROR;
853 	newPersona->numDirections = numParams / 3;
854 	if (numParams == 0 || newPersona->numDirections * 3 != numParams) {
855 		fatal("Illegal number of parameters (should be greater than 0 and divisible by 3)");
856 		return BR_ERROR;
857 	}
858 	int iii;
859 	newPersona->animation = new PersonaAnimation  *[numParams];
860 	if (!checkNew(newPersona->animation))
861 		return BR_ERROR;
862 	for (iii = numParams - 1; iii >= 0; iii--) {
863 		newPersona->animation[iii] = fun->stack->thisVar.getAnimationFromVar();
864 		trimStack(fun->stack);
865 	}
866 
867 	// Return value
868 	fun->reg.makeCostumeVariable(newPersona);
869 	return BR_CONTINUE;
870 }
871 
builtIn(launch)872 builtIn(launch) {
873 	UNUSEDALL
874 	Common::String newTextA = fun->stack->thisVar.getTextFromAnyVar();
875 
876 	Common::String newText = encodeFilename(newTextA);
877 
878 	trimStack(fun->stack);
879 	if (newTextA[0] == 'h' && newTextA[1] == 't' && newTextA[2] == 't' && newTextA[3] == 'p' &&
880 		(newTextA[4] == ':' || (newTextA[4] == 's' && newTextA[5] == ':'))) {
881 
882 		// IT'S A WEBSITE!
883 		g_sludge->launchMe.clear();
884 		g_sludge->launchMe = newTextA;
885 	} else {
886 		Common::String gameDir = g_sludge->gamePath;
887 		gameDir += "/";
888 		g_sludge->launchMe.clear();
889 		g_sludge->launchMe = gameDir + newText;
890 		if (g_sludge->launchMe.empty())
891 			return BR_ERROR;
892 	}
893 	fun->reg.setVariable(SVT_INT, 1);
894 	launchResult = &fun->reg;
895 
896 	return BR_KEEP_AND_PAUSE;
897 }
898 
builtIn(pause)899 builtIn(pause) {
900 	UNUSEDALL
901 	int theTime;
902 	if (!fun->stack->thisVar.getValueType(theTime, SVT_INT))
903 		return BR_ERROR;
904 	trimStack(fun->stack);
905 	if (theTime > 0) {
906 		fun->timeLeft = theTime - 1;
907 		fun->isSpeech = false;
908 		return BR_KEEP_AND_PAUSE;
909 	}
910 	return BR_CONTINUE;
911 }
912 
builtIn(completeTimers)913 builtIn(completeTimers) {
914 	UNUSEDALL
915 	completeTimers();
916 	return BR_CONTINUE;
917 }
918 
builtIn(callEvent)919 builtIn(callEvent) {
920 	UNUSEDALL
921 	int obj1, obj2;
922 	if (!fun->stack->thisVar.getValueType(obj2, SVT_OBJTYPE))
923 		return BR_ERROR;
924 	trimStack(fun->stack);
925 	if (!fun->stack->thisVar.getValueType(obj1, SVT_OBJTYPE))
926 		return BR_ERROR;
927 	trimStack(fun->stack);
928 
929 	int fNum = g_sludge->_objMan->getCombinationFunction(obj1, obj2);
930 
931 	// Return value
932 	if (fNum) {
933 		fun->reg.setVariable(SVT_FUNC, fNum);
934 		return BR_CALLAFUNC;
935 	}
936 	fun->reg.setVariable(SVT_INT, 0);
937 	return BR_CONTINUE;
938 }
939 
builtIn(quitGame)940 builtIn(quitGame) {
941 	UNUSEDALL
942 	g_sludge->_evtMan->quitGame();
943 	return BR_CONTINUE;
944 }
945 
946 #pragma mark -
947 #pragma mark Movie functions
948 
949 // The old movie functions are deprecated and does nothing.
builtIn(_rem_movieStart)950 builtIn(_rem_movieStart) {
951 	UNUSEDALL
952 	trimStack(fun->stack);
953 	return BR_CONTINUE;
954 }
955 
builtIn(_rem_movieAbort)956 builtIn(_rem_movieAbort) {
957 	UNUSEDALL
958 	fun->reg.setVariable(SVT_INT, 0);
959 	return BR_CONTINUE;
960 }
961 
builtIn(_rem_moviePlaying)962 builtIn(_rem_moviePlaying) {
963 	UNUSEDALL
964 	fun->reg.setVariable(SVT_INT, 0);
965 	return BR_CONTINUE;
966 }
967 
builtIn(playMovie)968 builtIn(playMovie) {
969 	UNUSEDALL
970 	int fileNumber, r;
971 
972 	if (movieIsPlaying)
973 		return BR_PAUSE;
974 
975 	if (!fun->stack->thisVar.getValueType(fileNumber, SVT_FILE))
976 		return BR_ERROR;
977 	trimStack(fun->stack);
978 
979 	r = playMovie(fileNumber);
980 
981 	fun->reg.setVariable(SVT_INT, r);
982 
983 	if (r && (!fun->next)) {
984 		restartFunction(fun);
985 		return BR_ALREADY_GONE;
986 	}
987 	return BR_CONTINUE;
988 }
989 
builtIn(stopMovie)990 builtIn(stopMovie) {
991 	UNUSEDALL
992 
993 	stopMovie();
994 
995 	fun->reg.setVariable(SVT_INT, 0);
996 	return BR_CONTINUE;
997 }
998 
builtIn(pauseMovie)999 builtIn(pauseMovie) {
1000 	UNUSEDALL
1001 
1002 	pauseMovie();
1003 
1004 	fun->reg.setVariable(SVT_INT, 0);
1005 	return BR_CONTINUE;
1006 }
1007 
1008 #pragma mark -
1009 #pragma mark Audio functions
1010 
builtIn(startMusic)1011 builtIn(startMusic) {
1012 	UNUSEDALL
1013 	int fromTrack, musChan, fileNumber;
1014 	if (!fun->stack->thisVar.getValueType(fromTrack, SVT_INT))
1015 		return BR_ERROR;
1016 	trimStack(fun->stack);
1017 	if (!fun->stack->thisVar.getValueType(musChan, SVT_INT))
1018 		return BR_ERROR;
1019 	trimStack(fun->stack);
1020 	if (!fun->stack->thisVar.getValueType(fileNumber, SVT_FILE))
1021 		return BR_ERROR;
1022 	trimStack(fun->stack);
1023 	if (!g_sludge->_soundMan->playMOD(fileNumber, musChan, fromTrack))
1024 		return BR_CONTINUE;  //BR_ERROR;
1025 	return BR_CONTINUE;
1026 }
1027 
builtIn(stopMusic)1028 builtIn(stopMusic) {
1029 	UNUSEDALL
1030 	int v;
1031 	if (!fun->stack->thisVar.getValueType(v, SVT_INT))
1032 		return BR_ERROR;
1033 	trimStack(fun->stack);
1034 	g_sludge->_soundMan->stopMOD(v);
1035 	return BR_CONTINUE;
1036 }
1037 
builtIn(setMusicVolume)1038 builtIn(setMusicVolume) {
1039 	UNUSEDALL
1040 	int musChan, v;
1041 	if (!fun->stack->thisVar.getValueType(v, SVT_INT))
1042 		return BR_ERROR;
1043 	trimStack(fun->stack);
1044 	if (!fun->stack->thisVar.getValueType(musChan, SVT_INT))
1045 		return BR_ERROR;
1046 	trimStack(fun->stack);
1047 	g_sludge->_soundMan->setMusicVolume(musChan, v);
1048 	return BR_CONTINUE;
1049 }
1050 
builtIn(setDefaultMusicVolume)1051 builtIn(setDefaultMusicVolume) {
1052 	UNUSEDALL
1053 	int v;
1054 	if (!fun->stack->thisVar.getValueType(v, SVT_INT))
1055 		return BR_ERROR;
1056 	trimStack(fun->stack);
1057 	g_sludge->_soundMan->setDefaultMusicVolume(v);
1058 	return BR_CONTINUE;
1059 }
1060 
builtIn(playSound)1061 builtIn(playSound) {
1062 	UNUSEDALL
1063 	int fileNumber;
1064 	if (!fun->stack->thisVar.getValueType(fileNumber, SVT_FILE))
1065 		return BR_ERROR;
1066 	trimStack(fun->stack);
1067 	if (!g_sludge->_soundMan->startSound(fileNumber, false))
1068 		return BR_CONTINUE;    // Was BR_ERROR
1069 	return BR_CONTINUE;
1070 }
builtIn(loopSound)1071 builtIn(loopSound) {
1072 	UNUSEDALL
1073 	int fileNumber;
1074 
1075 	if (numParams < 1) {
1076 		fatal("Built-in function loopSound() must have at least 1 parameter.");
1077 		return BR_ERROR;
1078 	} else if (numParams < 2) {
1079 
1080 		if (!fun->stack->thisVar.getValueType(fileNumber, SVT_FILE))
1081 			return BR_ERROR;
1082 		trimStack(fun->stack);
1083 		if (!g_sludge->_soundMan->startSound(fileNumber, true))
1084 			return BR_CONTINUE;     // Was BR_ERROR
1085 		return BR_CONTINUE;
1086 	} else {
1087 		// We have more than one sound to play!
1088 
1089 		int doLoop = 2;
1090 		SoundList*s = NULL;
1091 		SoundList*old = NULL;
1092 
1093 		// Should we loop?
1094 		if (fun->stack->thisVar.varType != SVT_FILE) {
1095 			fun->stack->thisVar.getValueType(doLoop, SVT_INT);
1096 			trimStack(fun->stack);
1097 			numParams--;
1098 		}
1099 		while (numParams) {
1100 			if (!fun->stack->thisVar.getValueType(fileNumber, SVT_FILE)) {
1101 				fatal("Illegal parameter given built-in function loopSound().");
1102 				return BR_ERROR;
1103 			}
1104 			s = new SoundList;
1105 			if (!checkNew(s))
1106 				return BR_ERROR;
1107 
1108 			s->next = old;
1109 			s->prev = NULL;
1110 			s->sound = fileNumber;
1111 			old = s;
1112 
1113 			trimStack(fun->stack);
1114 			numParams--;
1115 		}
1116 		while (s->next)
1117 			s = s->next;
1118 		if (doLoop > 1) {
1119 			s->next = old;
1120 			old->prev = s;
1121 		} else if (doLoop) {
1122 			s->next = s;
1123 		}
1124 		old->vol = -1;
1125 		g_sludge->_soundMan->playSoundList(old);
1126 		return BR_CONTINUE;
1127 	}
1128 }
1129 
builtIn(stopSound)1130 builtIn(stopSound) {
1131 	UNUSEDALL
1132 	int v;
1133 	if (!fun->stack->thisVar.getValueType(v, SVT_FILE))
1134 		return BR_ERROR;
1135 	trimStack(fun->stack);
1136 	g_sludge->_soundMan->huntKillSound(v);
1137 	return BR_CONTINUE;
1138 }
1139 
builtIn(setDefaultSoundVolume)1140 builtIn(setDefaultSoundVolume) {
1141 	UNUSEDALL
1142 	int v;
1143 	if (!fun->stack->thisVar.getValueType(v, SVT_INT))
1144 		return BR_ERROR;
1145 	trimStack(fun->stack);
1146 	g_sludge->_soundMan->setDefaultSoundVolume(v);
1147 	return BR_CONTINUE;
1148 }
1149 
builtIn(setSoundVolume)1150 builtIn(setSoundVolume) {
1151 	UNUSEDALL
1152 	int musChan, v;
1153 	if (!fun->stack->thisVar.getValueType(v, SVT_INT))
1154 		return BR_ERROR;
1155 	trimStack(fun->stack);
1156 	if (!fun->stack->thisVar.getValueType(musChan, SVT_FILE))
1157 		return BR_ERROR;
1158 	trimStack(fun->stack);
1159 	g_sludge->_soundMan->setSoundVolume(musChan, v);
1160 	return BR_CONTINUE;
1161 }
1162 
builtIn(setSoundLoopPoints)1163 builtIn(setSoundLoopPoints) {
1164 	UNUSEDALL
1165 	int musChan, theEnd, theStart;
1166 	if (!fun->stack->thisVar.getValueType(theEnd, SVT_INT))
1167 		return BR_ERROR;
1168 	trimStack(fun->stack);
1169 	if (!fun->stack->thisVar.getValueType(theStart, SVT_INT))
1170 		return BR_ERROR;
1171 	trimStack(fun->stack);
1172 	if (!fun->stack->thisVar.getValueType(musChan, SVT_FILE))
1173 		return BR_ERROR;
1174 	trimStack(fun->stack);
1175 	g_sludge->_soundMan->setSoundLoop(musChan, theStart, theEnd);
1176 	return BR_CONTINUE;
1177 }
1178 
1179 #pragma mark -
1180 #pragma mark Extra room bits
1181 
builtIn(setFloor)1182 builtIn(setFloor) {
1183 	UNUSEDALL
1184 	if (fun->stack->thisVar.varType == SVT_FILE) {
1185 		int v;
1186 		fun->stack->thisVar.getValueType(v, SVT_FILE);
1187 		trimStack(fun->stack);
1188 		if (!g_sludge->_floorMan->setFloor(v))
1189 			return BR_ERROR;
1190 	} else {
1191 		trimStack(fun->stack);
1192 		g_sludge->_floorMan->setFloorNull();
1193 	}
1194 	return BR_CONTINUE;
1195 }
1196 
builtIn(showFloor)1197 builtIn(showFloor) {
1198 	UNUSEDALL
1199 	g_sludge->_floorMan->drawFloor();
1200 	return BR_CONTINUE;
1201 }
1202 
builtIn(setZBuffer)1203 builtIn(setZBuffer) {
1204 	UNUSEDALL
1205 	if (fun->stack->thisVar.varType == SVT_FILE) {
1206 		int v;
1207 		fun->stack->thisVar.getValueType(v, SVT_FILE);
1208 		trimStack(fun->stack);
1209 		if (!g_sludge->_gfxMan->setZBuffer(v))
1210 			return BR_ERROR;
1211 	} else {
1212 		trimStack(fun->stack);
1213 		g_sludge->_gfxMan->killZBuffer();
1214 	}
1215 	return BR_CONTINUE;
1216 }
1217 
builtIn(setLightMap)1218 builtIn(setLightMap) {
1219 	UNUSEDALL
1220 	switch (numParams) {
1221 	case 2:
1222 		if (!fun->stack->thisVar.getValueType(g_sludge->_gfxMan->_lightMapMode, SVT_INT))
1223 			return BR_ERROR;
1224 		trimStack(fun->stack);
1225 		g_sludge->_gfxMan->_lightMapMode %= LIGHTMAPMODE_NUM;
1226 		// fall through
1227 
1228 	case 1:
1229 		if (fun->stack->thisVar.varType == SVT_FILE) {
1230 			int v;
1231 			fun->stack->thisVar.getValueType(v, SVT_FILE);
1232 			trimStack(fun->stack);
1233 			if (!g_sludge->_gfxMan->loadLightMap(v))
1234 				return BR_ERROR;
1235 			fun->reg.setVariable(SVT_INT, 1);
1236 		} else {
1237 			trimStack(fun->stack);
1238 			g_sludge->_gfxMan->killLightMap();
1239 			fun->reg.setVariable(SVT_INT, 0);
1240 		}
1241 		break;
1242 
1243 	default:
1244 		fatal("Function should have either 2 or 3 parameters");
1245 		return BR_ERROR;
1246 	}
1247 	return BR_CONTINUE;
1248 }
1249 
1250 #pragma mark -
1251 #pragma mark Objects
1252 
builtIn(setSpeechMode)1253 builtIn(setSpeechMode) {
1254 	UNUSEDALL
1255 	int speechMode;
1256 	if (!fun->stack->thisVar.getValueType(speechMode, SVT_INT))
1257 		return BR_ERROR;
1258 	trimStack(fun->stack);
1259 	if (speechMode < 0 || speechMode > 2) {
1260 		fatal("Valid parameters are be SPEECHANDTEXT, SPEECHONLY or TEXTONLY");
1261 		return BR_ERROR;
1262 	}
1263 	g_sludge->_speechMan->setSpeechMode(speechMode);
1264 	return BR_CONTINUE;
1265 }
1266 
builtIn(somethingSpeaking)1267 builtIn(somethingSpeaking) {
1268 	UNUSEDALL
1269 	int i = g_sludge->_speechMan->isThereAnySpeechGoingOn();
1270 	if (i == -1) {
1271 		fun->reg.setVariable(SVT_INT, 0);
1272 	} else {
1273 		fun->reg.setVariable(SVT_OBJTYPE, i);
1274 	}
1275 	return BR_CONTINUE;
1276 }
1277 
builtIn(skipSpeech)1278 builtIn(skipSpeech) {
1279 	UNUSEDALL
1280 	killSpeechTimers();
1281 	return BR_CONTINUE;
1282 }
1283 
builtIn(getOverObject)1284 builtIn(getOverObject) {
1285 	UNUSEDALL
1286 	if (g_sludge->_regionMan->getOverRegion())
1287 		// Return value
1288 		fun->reg.setVariable(SVT_OBJTYPE, g_sludge->_regionMan->getOverRegion()->thisType->objectNum);
1289 	else
1290 		// Return value
1291 		fun->reg.setVariable(SVT_INT, 0);
1292 	return BR_CONTINUE;
1293 }
1294 
builtIn(rename)1295 builtIn(rename) {
1296 	UNUSEDALL
1297 	Common::String newText = fun->stack->thisVar.getTextFromAnyVar();
1298 	int objT;
1299 	trimStack(fun->stack);
1300 	if (!fun->stack->thisVar.getValueType(objT, SVT_OBJTYPE))
1301 		return BR_ERROR;
1302 	trimStack(fun->stack);
1303 	ObjectType *o = g_sludge->_objMan->findObjectType(objT);
1304 	o->screenName.clear();
1305 	o->screenName = newText;
1306 	return BR_CONTINUE;
1307 }
1308 
builtIn(getObjectX)1309 builtIn(getObjectX) {
1310 	UNUSEDALL
1311 	int objectNumber;
1312 	if (!fun->stack->thisVar.getValueType(objectNumber, SVT_OBJTYPE))
1313 		return BR_ERROR;
1314 	trimStack(fun->stack);
1315 
1316 	OnScreenPerson *pers = g_sludge->_peopleMan->findPerson(objectNumber);
1317 	if (pers) {
1318 		fun->reg.setVariable(SVT_INT, pers->x);
1319 	} else {
1320 		ScreenRegion *la = g_sludge->_regionMan->getRegionForObject(objectNumber);
1321 		if (la) {
1322 			fun->reg.setVariable(SVT_INT, la->sX);
1323 		} else {
1324 			fun->reg.setVariable(SVT_INT, 0);
1325 		}
1326 	}
1327 	return BR_CONTINUE;
1328 }
1329 
builtIn(getObjectY)1330 builtIn(getObjectY) {
1331 	UNUSEDALL
1332 	int objectNumber;
1333 	if (!fun->stack->thisVar.getValueType(objectNumber, SVT_OBJTYPE))
1334 		return BR_ERROR;
1335 	trimStack(fun->stack);
1336 
1337 	OnScreenPerson *pers = g_sludge->_peopleMan->findPerson(objectNumber);
1338 	if (pers) {
1339 		fun->reg.setVariable(SVT_INT, pers->y);
1340 	} else {
1341 		ScreenRegion *la = g_sludge->_regionMan->getRegionForObject(objectNumber);
1342 		if (la) {
1343 			fun->reg.setVariable(SVT_INT, la->sY);
1344 		} else {
1345 			fun->reg.setVariable(SVT_INT, 0);
1346 		}
1347 	}
1348 	return BR_CONTINUE;
1349 }
1350 
builtIn(addScreenRegion)1351 builtIn(addScreenRegion) {
1352 	UNUSEDALL
1353 	int sX, sY, x1, y1, x2, y2, di, objectNumber;
1354 	if (!fun->stack->thisVar.getValueType(di, SVT_INT))
1355 		return BR_ERROR;
1356 	trimStack(fun->stack);
1357 	if (!fun->stack->thisVar.getValueType(sY, SVT_INT))
1358 		return BR_ERROR;
1359 	trimStack(fun->stack);
1360 	if (!fun->stack->thisVar.getValueType(sX, SVT_INT))
1361 		return BR_ERROR;
1362 	trimStack(fun->stack);
1363 	if (!fun->stack->thisVar.getValueType(y2, SVT_INT))
1364 		return BR_ERROR;
1365 	trimStack(fun->stack);
1366 	if (!fun->stack->thisVar.getValueType(x2, SVT_INT))
1367 		return BR_ERROR;
1368 	trimStack(fun->stack);
1369 	if (!fun->stack->thisVar.getValueType(y1, SVT_INT))
1370 		return BR_ERROR;
1371 	trimStack(fun->stack);
1372 	if (!fun->stack->thisVar.getValueType(x1, SVT_INT))
1373 		return BR_ERROR;
1374 	trimStack(fun->stack);
1375 	if (!fun->stack->thisVar.getValueType(objectNumber, SVT_OBJTYPE))
1376 		return BR_ERROR;
1377 	trimStack(fun->stack);
1378 	if (g_sludge->_regionMan->addScreenRegion(x1, y1, x2, y2, sX, sY, di, objectNumber))
1379 		return BR_CONTINUE;
1380 	return BR_ERROR;
1381 
1382 }
1383 
builtIn(removeScreenRegion)1384 builtIn(removeScreenRegion) {
1385 	UNUSEDALL
1386 	int objectNumber;
1387 	if (!fun->stack->thisVar.getValueType(objectNumber, SVT_OBJTYPE))
1388 		return BR_ERROR;
1389 	trimStack(fun->stack);
1390 	g_sludge->_regionMan->removeScreenRegion(objectNumber);
1391 	return BR_CONTINUE;
1392 }
1393 
builtIn(showBoxes)1394 builtIn(showBoxes) {
1395 	UNUSEDALL
1396 	g_sludge->_regionMan->showBoxes();
1397 	return BR_CONTINUE;
1398 }
1399 
builtIn(removeAllScreenRegions)1400 builtIn(removeAllScreenRegions) {
1401 	UNUSEDALL
1402 	g_sludge->_regionMan->kill();
1403 	return BR_CONTINUE;
1404 }
1405 
builtIn(addCharacter)1406 builtIn(addCharacter) {
1407 	UNUSEDALL
1408 	Persona *p;
1409 	int x, y, objectNumber;
1410 
1411 	p = fun->stack->thisVar.getCostumeFromVar();
1412 	if (p == NULL)
1413 		return BR_ERROR;
1414 
1415 	trimStack(fun->stack);
1416 	if (!fun->stack->thisVar.getValueType(y, SVT_INT))
1417 		return BR_ERROR;
1418 	trimStack(fun->stack);
1419 	if (!fun->stack->thisVar.getValueType(x, SVT_INT))
1420 		return BR_ERROR;
1421 	trimStack(fun->stack);
1422 	if (!fun->stack->thisVar.getValueType(objectNumber, SVT_OBJTYPE))
1423 		return BR_ERROR;
1424 	trimStack(fun->stack);
1425 	if (g_sludge->_peopleMan->addPerson(x, y, objectNumber, p))
1426 		return BR_CONTINUE;
1427 	return BR_ERROR;
1428 }
1429 
builtIn(hideCharacter)1430 builtIn(hideCharacter) {
1431 	UNUSEDALL
1432 	int objectNumber;
1433 	if (!fun->stack->thisVar.getValueType(objectNumber, SVT_OBJTYPE))
1434 		return BR_ERROR;
1435 	trimStack(fun->stack);
1436 	g_sludge->_peopleMan->setShown(false, objectNumber);
1437 	return BR_CONTINUE;
1438 }
1439 
builtIn(showCharacter)1440 builtIn(showCharacter) {
1441 	UNUSEDALL
1442 	int objectNumber;
1443 	if (!fun->stack->thisVar.getValueType(objectNumber, SVT_OBJTYPE))
1444 		return BR_ERROR;
1445 	trimStack(fun->stack);
1446 	g_sludge->_peopleMan->setShown(true, objectNumber);
1447 	return BR_CONTINUE;
1448 }
1449 
builtIn(removeAllCharacters)1450 builtIn(removeAllCharacters) {
1451 	UNUSEDALL
1452 	killSpeechTimers();
1453 	g_sludge->_peopleMan->killMostPeople();
1454 	return BR_CONTINUE;
1455 }
1456 
builtIn(setCharacterDrawMode)1457 builtIn(setCharacterDrawMode) {
1458 	UNUSEDALL
1459 	int obj, di;
1460 	if (!fun->stack->thisVar.getValueType(di, SVT_INT))
1461 		return BR_ERROR;
1462 	trimStack(fun->stack);
1463 	if (!fun->stack->thisVar.getValueType(obj, SVT_OBJTYPE))
1464 		return BR_ERROR;
1465 	trimStack(fun->stack);
1466 	g_sludge->_peopleMan->setDrawMode(di, obj);
1467 	return BR_CONTINUE;
1468 }
builtIn(setCharacterTransparency)1469 builtIn(setCharacterTransparency) {
1470 	UNUSEDALL
1471 	int obj, x;
1472 	if (!fun->stack->thisVar.getValueType(x, SVT_INT))
1473 		return BR_ERROR;
1474 	trimStack(fun->stack);
1475 	if (!fun->stack->thisVar.getValueType(obj, SVT_OBJTYPE))
1476 		return BR_ERROR;
1477 	trimStack(fun->stack);
1478 	g_sludge->_peopleMan->setPersonTransparency(obj, x);
1479 	return BR_CONTINUE;
1480 }
builtIn(setCharacterColourise)1481 builtIn(setCharacterColourise) {
1482 	UNUSEDALL
1483 	int obj, r, g, b, mix;
1484 	if (!fun->stack->thisVar.getValueType(mix, SVT_INT))
1485 		return BR_ERROR;
1486 	trimStack(fun->stack);
1487 	if (!fun->stack->thisVar.getValueType(b, SVT_INT))
1488 		return BR_ERROR;
1489 	trimStack(fun->stack);
1490 	if (!fun->stack->thisVar.getValueType(g, SVT_INT))
1491 		return BR_ERROR;
1492 	trimStack(fun->stack);
1493 	if (!fun->stack->thisVar.getValueType(r, SVT_INT))
1494 		return BR_ERROR;
1495 	trimStack(fun->stack);
1496 	if (!fun->stack->thisVar.getValueType(obj, SVT_OBJTYPE))
1497 		return BR_ERROR;
1498 	trimStack(fun->stack);
1499 	g_sludge->_peopleMan->setPersonColourise(obj, r, g, b, mix);
1500 	return BR_CONTINUE;
1501 }
1502 
builtIn(setScale)1503 builtIn(setScale) {
1504 	UNUSEDALL
1505 	int val1, val2;
1506 	if (!fun->stack->thisVar.getValueType(val2, SVT_INT))
1507 		return BR_ERROR;
1508 	trimStack(fun->stack);
1509 	if (!fun->stack->thisVar.getValueType(val1, SVT_INT))
1510 		return BR_ERROR;
1511 	trimStack(fun->stack);
1512 	g_sludge->_peopleMan->setScale((int16)val1, (int16)val2);
1513 	return BR_CONTINUE;
1514 }
1515 
builtIn(stopCharacter)1516 builtIn(stopCharacter) {
1517 	UNUSEDALL
1518 	int obj;
1519 	if (!fun->stack->thisVar.getValueType(obj, SVT_OBJTYPE))
1520 		return BR_ERROR;
1521 	trimStack(fun->stack);
1522 
1523 	// Return value
1524 	fun->reg.setVariable(SVT_INT, g_sludge->_peopleMan->stopPerson(obj));
1525 	return BR_CONTINUE;
1526 }
1527 
builtIn(pasteCharacter)1528 builtIn(pasteCharacter) {
1529 	UNUSEDALL
1530 	int obj;
1531 	if (!fun->stack->thisVar.getValueType(obj, SVT_OBJTYPE))
1532 		return BR_ERROR;
1533 	trimStack(fun->stack);
1534 
1535 	OnScreenPerson *thisPerson = g_sludge->_peopleMan->findPerson(obj);
1536 	if (thisPerson) {
1537 		PersonaAnimation  *myAnim;
1538 		myAnim = thisPerson->myAnim;
1539 		if (myAnim != thisPerson->lastUsedAnim) {
1540 			thisPerson->lastUsedAnim = myAnim;
1541 			thisPerson->frameNum = 0;
1542 			thisPerson->frameTick = myAnim->frames[0].howMany;
1543 		}
1544 
1545 		int fNum = myAnim->frames[thisPerson->frameNum].frameNum;
1546 		g_sludge->_gfxMan->fixScaleSprite(thisPerson->x, thisPerson->y, myAnim->theSprites->bank.sprites[ABS(fNum)], myAnim->theSprites->bank.myPalette, thisPerson, 0, 0, fNum < 0);
1547 		fun->reg.setVariable(SVT_INT, 1);
1548 	} else {
1549 		fun->reg.setVariable(SVT_INT, 0);
1550 	}
1551 	return BR_CONTINUE;
1552 }
1553 
builtIn(animate)1554 builtIn(animate) {
1555 	UNUSEDALL
1556 	int obj;
1557 	PersonaAnimation *pp = fun->stack->thisVar.getAnimationFromVar();
1558 	if (pp == NULL)
1559 		return BR_ERROR;
1560 	trimStack(fun->stack);
1561 	if (!fun->stack->thisVar.getValueType(obj, SVT_OBJTYPE))
1562 		return BR_ERROR;
1563 	trimStack(fun->stack);
1564 	g_sludge->_peopleMan->animatePerson(obj, pp);
1565 	fun->reg.setVariable(SVT_INT, pp->getTotalTime());
1566 	return BR_CONTINUE;
1567 }
1568 
builtIn(setCostume)1569 builtIn(setCostume) {
1570 	UNUSEDALL
1571 	int obj;
1572 	Persona *pp = fun->stack->thisVar.getCostumeFromVar();
1573 	if (pp == NULL)
1574 		return BR_ERROR;
1575 	trimStack(fun->stack);
1576 	if (!fun->stack->thisVar.getValueType(obj, SVT_OBJTYPE))
1577 		return BR_ERROR;
1578 	trimStack(fun->stack);
1579 	g_sludge->_peopleMan->animatePerson(obj, pp);
1580 	return BR_CONTINUE;
1581 }
1582 
builtIn(floatCharacter)1583 builtIn(floatCharacter) {
1584 	UNUSEDALL
1585 	int obj, di;
1586 	if (!fun->stack->thisVar.getValueType(di, SVT_INT))
1587 		return BR_ERROR;
1588 	trimStack(fun->stack);
1589 	if (!fun->stack->thisVar.getValueType(obj, SVT_OBJTYPE))
1590 		return BR_ERROR;
1591 	trimStack(fun->stack);
1592 	fun->reg.setVariable(SVT_INT, g_sludge->_peopleMan->floatCharacter(di, obj));
1593 	return BR_CONTINUE;
1594 }
1595 
builtIn(setCharacterWalkSpeed)1596 builtIn(setCharacterWalkSpeed) {
1597 	UNUSEDALL
1598 	int obj, di;
1599 	if (!fun->stack->thisVar.getValueType(di, SVT_INT))
1600 		return BR_ERROR;
1601 	trimStack(fun->stack);
1602 	if (!fun->stack->thisVar.getValueType(obj, SVT_OBJTYPE))
1603 		return BR_ERROR;
1604 	trimStack(fun->stack);
1605 	fun->reg.setVariable(SVT_INT, g_sludge->_peopleMan->setCharacterWalkSpeed(di, obj));
1606 	return BR_CONTINUE;
1607 }
1608 
builtIn(turnCharacter)1609 builtIn(turnCharacter) {
1610 	UNUSEDALL
1611 	int obj, di;
1612 	if (!fun->stack->thisVar.getValueType(di, SVT_INT))
1613 		return BR_ERROR;
1614 	trimStack(fun->stack);
1615 	if (!fun->stack->thisVar.getValueType(obj, SVT_OBJTYPE))
1616 		return BR_ERROR;
1617 	trimStack(fun->stack);
1618 	fun->reg.setVariable(SVT_INT, g_sludge->_peopleMan->turnPersonToFace(obj, di));
1619 	return BR_CONTINUE;
1620 }
1621 
builtIn(setCharacterExtra)1622 builtIn(setCharacterExtra) {
1623 	UNUSEDALL
1624 	int obj, di;
1625 	if (!fun->stack->thisVar.getValueType(di, SVT_INT))
1626 		return BR_ERROR;
1627 	trimStack(fun->stack);
1628 	if (!fun->stack->thisVar.getValueType(obj, SVT_OBJTYPE))
1629 		return BR_ERROR;
1630 	trimStack(fun->stack);
1631 	fun->reg.setVariable(SVT_INT, g_sludge->_peopleMan->setPersonExtra(obj, di));
1632 	return BR_CONTINUE;
1633 }
1634 
builtIn(removeCharacter)1635 builtIn(removeCharacter) {
1636 	UNUSEDALL
1637 	int objectNumber;
1638 	if (!fun->stack->thisVar.getValueType(objectNumber, SVT_OBJTYPE))
1639 		return BR_ERROR;
1640 	trimStack(fun->stack);
1641 	g_sludge->_peopleMan->removeOneCharacter(objectNumber);
1642 	return BR_CONTINUE;
1643 }
1644 
moveChr(int numParams,LoadedFunction * fun,bool force,bool immediate)1645 static BuiltReturn moveChr(int numParams, LoadedFunction *fun, bool force, bool immediate) {
1646 	switch (numParams) {
1647 	case 3: {
1648 		int x, y, objectNumber;
1649 
1650 		if (!fun->stack->thisVar.getValueType(y, SVT_INT))
1651 			return BR_ERROR;
1652 		trimStack(fun->stack);
1653 		if (!fun->stack->thisVar.getValueType(x, SVT_INT))
1654 			return BR_ERROR;
1655 		trimStack(fun->stack);
1656 		if (!fun->stack->thisVar.getValueType(objectNumber, SVT_OBJTYPE))
1657 			return BR_ERROR;
1658 		trimStack(fun->stack);
1659 
1660 		if (force) {
1661 			if (g_sludge->_peopleMan->forceWalkingPerson(x, y, objectNumber, fun, -1))
1662 				return BR_PAUSE;
1663 		} else if (immediate) {
1664 			g_sludge->_peopleMan->jumpPerson(x, y, objectNumber);
1665 		} else {
1666 			if (g_sludge->_peopleMan->makeWalkingPerson(x, y, objectNumber, fun, -1))
1667 				return BR_PAUSE;
1668 		}
1669 		return BR_CONTINUE;
1670 	}
1671 
1672 	case 2: {
1673 		int toObj, objectNumber;
1674 		ScreenRegion*reggie;
1675 
1676 		if (!fun->stack->thisVar.getValueType(toObj, SVT_OBJTYPE))
1677 			return BR_ERROR;
1678 		trimStack(fun->stack);
1679 		if (!fun->stack->thisVar.getValueType(objectNumber, SVT_OBJTYPE))
1680 			return BR_ERROR;
1681 		trimStack(fun->stack);
1682 		reggie = g_sludge->_regionMan->getRegionForObject(toObj);
1683 		if (reggie == NULL)
1684 			return BR_CONTINUE;
1685 
1686 		if (force) {
1687 			if (g_sludge->_peopleMan->forceWalkingPerson(reggie->sX, reggie->sY, objectNumber, fun, reggie->di))
1688 				return BR_PAUSE;
1689 		} else if (immediate) {
1690 			g_sludge->_peopleMan->jumpPerson(reggie->sX, reggie->sY, objectNumber);
1691 		} else {
1692 			if (g_sludge->_peopleMan->makeWalkingPerson(reggie->sX, reggie->sY, objectNumber, fun, reggie->di))
1693 				return BR_PAUSE;
1694 		}
1695 		return BR_CONTINUE;
1696 	}
1697 
1698 	default:
1699 		fatal("Built-in function must have either 2 or 3 parameters.");
1700 		return BR_ERROR;
1701 	}
1702 }
1703 
builtIn(moveCharacter)1704 builtIn(moveCharacter) {
1705 	UNUSEDALL
1706 	return moveChr(numParams, fun, false, false);
1707 }
1708 
builtIn(forceCharacter)1709 builtIn(forceCharacter) {
1710 	UNUSEDALL
1711 	return moveChr(numParams, fun, true, false);
1712 }
1713 
builtIn(jumpCharacter)1714 builtIn(jumpCharacter) {
1715 	UNUSEDALL
1716 	return moveChr(numParams, fun, false, true);
1717 }
1718 
builtIn(clearStatus)1719 builtIn(clearStatus) {
1720 	UNUSEDALL
1721 	g_sludge->_statusBar->clear();
1722 	return BR_CONTINUE;
1723 }
1724 
builtIn(removeLastStatus)1725 builtIn(removeLastStatus) {
1726 	UNUSEDALL
1727 	g_sludge->_statusBar->killLastStatus();
1728 	return BR_CONTINUE;
1729 }
1730 
builtIn(addStatus)1731 builtIn(addStatus) {
1732 	UNUSEDALL
1733 	g_sludge->_statusBar->addStatusBar();
1734 	return BR_CONTINUE;
1735 }
1736 
builtIn(statusText)1737 builtIn(statusText) {
1738 	UNUSEDALL
1739 	Common::String newText = fun->stack->thisVar.getTextFromAnyVar();
1740 	trimStack(fun->stack);
1741 	g_sludge->_statusBar->set(newText);
1742 	return BR_CONTINUE;
1743 }
1744 
builtIn(lightStatus)1745 builtIn(lightStatus) {
1746 	UNUSEDALL
1747 	int val;
1748 	if (!fun->stack->thisVar.getValueType(val, SVT_INT))
1749 		return BR_ERROR;
1750 	trimStack(fun->stack);
1751 	g_sludge->_statusBar->setLitStatus(val);
1752 	return BR_CONTINUE;
1753 }
1754 
builtIn(positionStatus)1755 builtIn(positionStatus) {
1756 	UNUSEDALL
1757 	int x, y;
1758 	if (!fun->stack->thisVar.getValueType(y, SVT_INT))
1759 		return BR_ERROR;
1760 	trimStack(fun->stack);
1761 	if (!fun->stack->thisVar.getValueType(x, SVT_INT))
1762 		return BR_ERROR;
1763 	trimStack(fun->stack);
1764 	g_sludge->_statusBar->positionStatus(x, y);
1765 	return BR_CONTINUE;
1766 }
1767 
builtIn(alignStatus)1768 builtIn(alignStatus) {
1769 	UNUSEDALL
1770 	int val;
1771 	if (!fun->stack->thisVar.getValueType(val, SVT_INT))
1772 		return BR_ERROR;
1773 	trimStack(fun->stack);
1774 	g_sludge->_statusBar->setAlignStatus(val);
1775 	return BR_CONTINUE;
1776 }
1777 
getFuncNumForCallback(int numParams,LoadedFunction * fun,int & functionNum)1778 static bool getFuncNumForCallback(int numParams, LoadedFunction *fun, int &functionNum) {
1779 	switch (numParams) {
1780 	case 0:
1781 		functionNum = 0;
1782 		break;
1783 
1784 	case 1:
1785 		if (!fun->stack->thisVar.getValueType(functionNum, SVT_FUNC))
1786 			return false;
1787 		trimStack(fun->stack);
1788 		break;
1789 
1790 	default:
1791 		fatal("Too many parameters.");
1792 		return false;
1793 	}
1794 	return true;
1795 }
1796 
builtIn(onLeftMouse)1797 builtIn(onLeftMouse) {
1798 	UNUSEDALL
1799 	int functionNum;
1800 	if (getFuncNumForCallback(numParams, fun, functionNum)) {
1801 		g_sludge->_evtMan->setEventFunction(kLeftMouse, functionNum);
1802 		return BR_CONTINUE;
1803 	}
1804 	return BR_ERROR;
1805 }
1806 
builtIn(onLeftMouseUp)1807 builtIn(onLeftMouseUp) {
1808 	UNUSEDALL
1809 	int functionNum;
1810 	if (getFuncNumForCallback(numParams, fun, functionNum)) {
1811 		g_sludge->_evtMan->setEventFunction(kLeftMouseUp, functionNum);
1812 		return BR_CONTINUE;
1813 	}
1814 	return BR_ERROR;
1815 }
1816 
builtIn(onRightMouse)1817 builtIn(onRightMouse) {
1818 	UNUSEDALL
1819 	int functionNum;
1820 	if (getFuncNumForCallback(numParams, fun, functionNum)) {
1821 		g_sludge->_evtMan->setEventFunction(kRightMouse, functionNum);
1822 		return BR_CONTINUE;
1823 	}
1824 	return BR_ERROR;
1825 }
1826 
builtIn(onRightMouseUp)1827 builtIn(onRightMouseUp) {
1828 	UNUSEDALL
1829 	int functionNum;
1830 	if (getFuncNumForCallback(numParams, fun, functionNum)) {
1831 		g_sludge->_evtMan->setEventFunction(kRightMouseUp, functionNum);
1832 		return BR_CONTINUE;
1833 	}
1834 	return BR_ERROR;
1835 }
1836 
builtIn(onFocusChange)1837 builtIn(onFocusChange) {
1838 	UNUSEDALL
1839 	int functionNum;
1840 	if (getFuncNumForCallback(numParams, fun, functionNum)) {
1841 		g_sludge->_evtMan->setEventFunction(kFocus, functionNum);
1842 		return BR_CONTINUE;
1843 	}
1844 	return BR_ERROR;
1845 }
1846 
builtIn(onMoveMouse)1847 builtIn(onMoveMouse) {
1848 	UNUSEDALL
1849 	int functionNum;
1850 	if (getFuncNumForCallback(numParams, fun, functionNum)) {
1851 		g_sludge->_evtMan->setEventFunction(kMoveMouse, functionNum);
1852 		return BR_CONTINUE;
1853 	}
1854 	return BR_ERROR;
1855 }
1856 
builtIn(onKeyboard)1857 builtIn(onKeyboard) {
1858 	UNUSEDALL
1859 	int functionNum;
1860 	if (getFuncNumForCallback(numParams, fun, functionNum)) {
1861 		g_sludge->_evtMan->setEventFunction(kSpace, functionNum);
1862 		return BR_CONTINUE;
1863 	}
1864 	return BR_ERROR;
1865 }
1866 
builtIn(spawnSub)1867 builtIn(spawnSub) {
1868 	UNUSEDALL
1869 	int functionNum;
1870 	if (getFuncNumForCallback(numParams, fun, functionNum)) {
1871 		if (!startNewFunctionNum(functionNum, 0, NULL, noStack))
1872 			return BR_ERROR;
1873 		return BR_CONTINUE;
1874 	}
1875 	return BR_ERROR;
1876 }
1877 
builtIn(cancelSub)1878 builtIn(cancelSub) {
1879 	UNUSEDALL
1880 	int functionNum;
1881 	if (getFuncNumForCallback(numParams, fun, functionNum)) {
1882 		bool killedMyself;
1883 		cancelAFunction(functionNum, fun, killedMyself);
1884 		if (killedMyself) {
1885 			abortFunction(fun);
1886 			return BR_ALREADY_GONE;
1887 		}
1888 		return BR_CONTINUE;
1889 	}
1890 	return BR_ERROR;
1891 }
1892 
builtIn(stringWidth)1893 builtIn(stringWidth) {
1894 	UNUSEDALL
1895 	Common::String theText = fun->stack->thisVar.getTextFromAnyVar();
1896 	trimStack(fun->stack);
1897 
1898 	// Return value
1899 	fun->reg.setVariable(SVT_INT, g_sludge->_txtMan->stringWidth(theText));
1900 	return BR_CONTINUE;
1901 }
1902 
builtIn(hardScroll)1903 builtIn(hardScroll) {
1904 	UNUSEDALL
1905 	int v;
1906 	if (!fun->stack->thisVar.getValueType(v, SVT_INT))
1907 		return BR_ERROR;
1908 	trimStack(fun->stack);
1909 	g_sludge->_gfxMan->hardScroll(v);
1910 	return BR_CONTINUE;
1911 }
1912 
builtIn(isScreenRegion)1913 builtIn(isScreenRegion) {
1914 	UNUSEDALL
1915 	int objectNumber;
1916 	if (!fun->stack->thisVar.getValueType(objectNumber, SVT_OBJTYPE))
1917 		return BR_ERROR;
1918 	trimStack(fun->stack);
1919 	fun->reg.setVariable(SVT_INT, g_sludge->_regionMan->getRegionForObject(objectNumber) != NULL);
1920 	return BR_CONTINUE;
1921 }
1922 
builtIn(setSpeechSpeed)1923 builtIn(setSpeechSpeed) {
1924 	UNUSEDALL
1925 	int number;
1926 	if (!fun->stack->thisVar.getValueType(number, SVT_INT))
1927 		return BR_ERROR;
1928 	trimStack(fun->stack);
1929 	g_sludge->_speechMan->setSpeechSpeed(number * 0.01);
1930 	fun->reg.setVariable(SVT_INT, 1);
1931 	return BR_CONTINUE;
1932 }
1933 
builtIn(setFontSpacing)1934 builtIn(setFontSpacing) {
1935 	UNUSEDALL
1936 	int fontSpaceI;
1937 	if (!fun->stack->thisVar.getValueType(fontSpaceI, SVT_INT))
1938 		return BR_ERROR;
1939 	g_sludge->_txtMan->setFontSpace(fontSpaceI);
1940 	trimStack(fun->stack);
1941 	fun->reg.setVariable(SVT_INT, 1);
1942 	return BR_CONTINUE;
1943 }
1944 
builtIn(transitionLevel)1945 builtIn(transitionLevel) {
1946 	UNUSEDALL
1947 	int brightnessLevel;
1948 	if (!fun->stack->thisVar.getValueType(brightnessLevel, SVT_INT))
1949 		return BR_ERROR;
1950 	trimStack(fun->stack);
1951 
1952 	g_sludge->_gfxMan->setBrightnessLevel(brightnessLevel);
1953 
1954 	fun->reg.setVariable(SVT_INT, 1);
1955 	return BR_CONTINUE;
1956 }
1957 
builtIn(captureAllKeys)1958 builtIn(captureAllKeys) {
1959 	UNUSEDALL
1960 	// This built-in function doesn't have any effect any more, we capture all keys by default
1961 	bool captureAllKeysDeprecated = fun->stack->thisVar.getBoolean();
1962 	trimStack(fun->stack);
1963 	fun->reg.setVariable(SVT_INT, captureAllKeysDeprecated);
1964 	return BR_CONTINUE;
1965 }
1966 
builtIn(spinCharacter)1967 builtIn(spinCharacter) {
1968 	UNUSEDALL
1969 	int number, objectNumber;
1970 	if (!fun->stack->thisVar.getValueType(number, SVT_INT))
1971 		return BR_ERROR;
1972 	trimStack(fun->stack);
1973 	if (!fun->stack->thisVar.getValueType(objectNumber, SVT_OBJTYPE))
1974 		return BR_ERROR;
1975 	trimStack(fun->stack);
1976 
1977 	OnScreenPerson *thisPerson = g_sludge->_peopleMan->findPerson(objectNumber);
1978 	if (thisPerson) {
1979 		thisPerson->wantAngle = number;
1980 		thisPerson->spinning = true;
1981 		thisPerson->continueAfterWalking = fun;
1982 		fun->reg.setVariable(SVT_INT, 1);
1983 		return BR_PAUSE;
1984 	} else {
1985 		fun->reg.setVariable(SVT_INT, 0);
1986 		return BR_CONTINUE;
1987 	}
1988 }
1989 
builtIn(getCharacterDirection)1990 builtIn(getCharacterDirection) {
1991 	UNUSEDALL
1992 	int objectNumber;
1993 	if (!fun->stack->thisVar.getValueType(objectNumber, SVT_OBJTYPE))
1994 		return BR_ERROR;
1995 	trimStack(fun->stack);
1996 	OnScreenPerson *thisPerson = g_sludge->_peopleMan->findPerson(objectNumber);
1997 	if (thisPerson) {
1998 		fun->reg.setVariable(SVT_INT, thisPerson->direction);
1999 	} else {
2000 		fun->reg.setVariable(SVT_INT, 0);
2001 	}
2002 	return BR_CONTINUE;
2003 }
2004 
builtIn(isCharacter)2005 builtIn(isCharacter) {
2006 	UNUSEDALL
2007 	int objectNumber;
2008 	if (!fun->stack->thisVar.getValueType(objectNumber, SVT_OBJTYPE))
2009 		return BR_ERROR;
2010 	trimStack(fun->stack);
2011 	OnScreenPerson *thisPerson = g_sludge->_peopleMan->findPerson(objectNumber);
2012 	fun->reg.setVariable(SVT_INT, thisPerson != NULL);
2013 	return BR_CONTINUE;
2014 }
2015 
builtIn(normalCharacter)2016 builtIn(normalCharacter) {
2017 	UNUSEDALL
2018 	int objectNumber;
2019 	if (!fun->stack->thisVar.getValueType(objectNumber, SVT_OBJTYPE))
2020 		return BR_ERROR;
2021 	trimStack(fun->stack);
2022 	OnScreenPerson *thisPerson = g_sludge->_peopleMan->findPerson(objectNumber);
2023 	if (thisPerson) {
2024 		thisPerson->myAnim = thisPerson->myPersona->animation[thisPerson->direction];
2025 		fun->reg.setVariable(SVT_INT, 1);
2026 	} else {
2027 		fun->reg.setVariable(SVT_INT, 0);
2028 	}
2029 	return BR_CONTINUE;
2030 }
2031 
builtIn(isMoving)2032 builtIn(isMoving) {
2033 	UNUSEDALL
2034 	int objectNumber;
2035 	if (!fun->stack->thisVar.getValueType(objectNumber, SVT_OBJTYPE))
2036 		return BR_ERROR;
2037 	trimStack(fun->stack);
2038 	OnScreenPerson *thisPerson = g_sludge->_peopleMan->findPerson(objectNumber);
2039 	if (thisPerson) {
2040 		fun->reg.setVariable(SVT_INT, thisPerson->walking);
2041 	} else {
2042 		fun->reg.setVariable(SVT_INT, 0);
2043 	}
2044 	return BR_CONTINUE;
2045 }
2046 
builtIn(fetchEvent)2047 builtIn(fetchEvent) {
2048 	UNUSEDALL
2049 	int obj1, obj2;
2050 	if (!fun->stack->thisVar.getValueType(obj2, SVT_OBJTYPE))
2051 		return BR_ERROR;
2052 	trimStack(fun->stack);
2053 	if (!fun->stack->thisVar.getValueType(obj1, SVT_OBJTYPE))
2054 		return BR_ERROR;
2055 	trimStack(fun->stack);
2056 
2057 	int fNum = g_sludge->_objMan->getCombinationFunction(obj1, obj2);
2058 
2059 	// Return value
2060 	if (fNum) {
2061 		fun->reg.setVariable(SVT_FUNC, fNum);
2062 	} else {
2063 		fun->reg.setVariable(SVT_INT, 0);
2064 	}
2065 	return BR_CONTINUE;
2066 }
2067 
builtIn(deleteFile)2068 builtIn(deleteFile) {
2069 	UNUSEDALL
2070 
2071 	Common::String namNormal = fun->stack->thisVar.getTextFromAnyVar();
2072 	trimStack(fun->stack);
2073 	Common::String nam = encodeFilename(namNormal);
2074 	namNormal.clear();
2075 	if (failSecurityCheck(nam))
2076 		return BR_ERROR;
2077 
2078 	fun->reg.setVariable(SVT_INT, !g_system->getSavefileManager()->removeSavefile(nam));
2079 
2080 	return BR_CONTINUE;
2081 }
2082 
builtIn(renameFile)2083 builtIn(renameFile) {
2084 	UNUSEDALL
2085 	Common::String temp;
2086 
2087 	temp.clear();
2088 	temp = fun->stack->thisVar.getTextFromAnyVar();
2089 	Common::String newnam = encodeFilename(temp);
2090 	trimStack(fun->stack);
2091 	if (failSecurityCheck(newnam))
2092 		return BR_ERROR;
2093 	temp.clear();
2094 
2095 	temp = fun->stack->thisVar.getTextFromAnyVar();
2096 	Common::String nam = encodeFilename(temp);
2097 	trimStack(fun->stack);
2098 	if (failSecurityCheck(nam))
2099 		return BR_ERROR;
2100 
2101 	fun->reg.setVariable(SVT_INT, !g_system->getSavefileManager()->renameSavefile(nam, newnam));
2102 
2103 	return BR_CONTINUE;
2104 }
2105 
builtIn(cacheSound)2106 builtIn(cacheSound) {
2107 	UNUSEDALL
2108 	int fileNumber;
2109 	if (!fun->stack->thisVar.getValueType(fileNumber, SVT_FILE))
2110 		return BR_ERROR;
2111 	trimStack(fun->stack);
2112 	if (g_sludge->_soundMan->cacheSound(fileNumber) == -1)
2113 		return BR_ERROR;
2114 	return BR_CONTINUE;
2115 }
2116 
builtIn(burnString)2117 builtIn(burnString) {
2118 	UNUSEDALL
2119 	Common::String newText = fun->stack->thisVar.getTextFromAnyVar();
2120 	trimStack(fun->stack);
2121 	int y, x;
2122 	if (!fun->stack->thisVar.getValueType(y, SVT_INT))
2123 		return BR_ERROR;
2124 	trimStack(fun->stack);
2125 	if (!fun->stack->thisVar.getValueType(x, SVT_INT))
2126 		return BR_ERROR;
2127 	trimStack(fun->stack);
2128 	if (x == IN_THE_CENTRE)
2129 		x = g_sludge->_gfxMan->getCenterX(g_sludge->_txtMan->stringWidth(newText));
2130 	g_sludge->_txtMan->burnStringToBackdrop(newText, x, y);
2131 	return BR_CONTINUE;
2132 }
2133 
builtIn(setCharacterSpinSpeed)2134 builtIn(setCharacterSpinSpeed) {
2135 	UNUSEDALL
2136 	int speed, who;
2137 	if (!fun->stack->thisVar.getValueType(speed, SVT_INT))
2138 		return BR_ERROR;
2139 	trimStack(fun->stack);
2140 	if (!fun->stack->thisVar.getValueType(who, SVT_OBJTYPE))
2141 		return BR_ERROR;
2142 	trimStack(fun->stack);
2143 
2144 	OnScreenPerson *thisPerson = g_sludge->_peopleMan->findPerson(who);
2145 
2146 	if (thisPerson) {
2147 		thisPerson->spinSpeed = speed;
2148 		fun->reg.setVariable(SVT_INT, 1);
2149 	} else {
2150 		fun->reg.setVariable(SVT_INT, 0);
2151 	}
2152 	return BR_CONTINUE;
2153 }
2154 
builtIn(setCharacterAngleOffset)2155 builtIn(setCharacterAngleOffset) {
2156 	UNUSEDALL
2157 	int angle, who;
2158 	if (!fun->stack->thisVar.getValueType(angle, SVT_INT))
2159 		return BR_ERROR;
2160 	trimStack(fun->stack);
2161 	if (!fun->stack->thisVar.getValueType(who, SVT_OBJTYPE))
2162 		return BR_ERROR;
2163 	trimStack(fun->stack);
2164 
2165 	OnScreenPerson *thisPerson = g_sludge->_peopleMan->findPerson(who);
2166 
2167 	if (thisPerson) {
2168 		thisPerson->angleOffset = angle;
2169 		fun->reg.setVariable(SVT_INT, 1);
2170 	} else {
2171 		fun->reg.setVariable(SVT_INT, 0);
2172 	}
2173 	return BR_CONTINUE;
2174 }
2175 
builtIn(transitionMode)2176 builtIn(transitionMode) {
2177 	UNUSEDALL
2178 	int n;
2179 	if (!fun->stack->thisVar.getValueType(n, SVT_INT))
2180 		return BR_ERROR;
2181 	g_sludge->_gfxMan->setFadeMode(n);
2182 	trimStack(fun->stack);
2183 	fun->reg.setVariable(SVT_INT, 1);
2184 	return BR_CONTINUE;
2185 }
2186 
2187 // Removed function - does nothing
builtIn(_rem_updateDisplay)2188 builtIn(_rem_updateDisplay) {
2189 	UNUSEDALL
2190 	trimStack(fun->stack);
2191 	fun->reg.setVariable(SVT_INT, true);
2192 	return BR_CONTINUE;
2193 }
2194 
builtIn(getSoundCache)2195 builtIn(getSoundCache) {
2196 	UNUSEDALL
2197 	fun->reg.varType = SVT_STACK;
2198 	fun->reg.varData.theStack = new StackHandler;
2199 	if (!checkNew(fun->reg.varData.theStack))
2200 		return BR_ERROR;
2201 	fun->reg.varData.theStack->first = NULL;
2202 	fun->reg.varData.theStack->last = NULL;
2203 	fun->reg.varData.theStack->timesUsed = 1;
2204 	if (!g_sludge->_soundMan->getSoundCacheStack(fun->reg.varData.theStack))
2205 		return BR_ERROR;
2206 	return BR_CONTINUE;
2207 }
2208 
builtIn(saveCustomData)2209 builtIn(saveCustomData) {
2210 	UNUSEDALL
2211 	// saveCustomData (thisStack, fileName);
2212 	Common::String fileNameB = fun->stack->thisVar.getTextFromAnyVar();
2213 
2214 	Common::String fileName = encodeFilename(fileNameB);
2215 
2216 	if (failSecurityCheck(fileName))
2217 		return BR_ERROR;
2218 	trimStack(fun->stack);
2219 
2220 	if (fun->stack->thisVar.varType != SVT_STACK) {
2221 		fatal("First parameter isn't a stack");
2222 		return BR_ERROR;
2223 	}
2224 	if (!CustomSaveHelper::stackToFile(fileName, fun->stack->thisVar))
2225 		return BR_ERROR;
2226 	trimStack(fun->stack);
2227 	return BR_CONTINUE;
2228 }
2229 
builtIn(loadCustomData)2230 builtIn(loadCustomData) {
2231 	UNUSEDALL
2232 
2233 	Common::String newTextA = fun->stack->thisVar.getTextFromAnyVar();
2234 
2235 	Common::String newText = encodeFilename(newTextA);
2236 
2237 	if (failSecurityCheck(newText))
2238 		return BR_ERROR;
2239 	trimStack(fun->stack);
2240 
2241 	fun->reg.unlinkVar();
2242 	fun->reg.varType = SVT_STACK;
2243 	fun->reg.varData.theStack = new StackHandler;
2244 	if (!checkNew(fun->reg.varData.theStack))
2245 		return BR_ERROR;
2246 	fun->reg.varData.theStack->first = NULL;
2247 	fun->reg.varData.theStack->last = NULL;
2248 	fun->reg.varData.theStack->timesUsed = 1;
2249 	if (!CustomSaveHelper::fileToStack(newText, fun->reg.varData.theStack))
2250 		return BR_ERROR;
2251 	return BR_CONTINUE;
2252 }
2253 
builtIn(setCustomEncoding)2254 builtIn(setCustomEncoding) {
2255 	UNUSEDALL
2256 	int n;
2257 	if (!fun->stack->thisVar.getValueType(n, SVT_INT))
2258 		return BR_ERROR;
2259 	CustomSaveHelper::_saveEncoding = n;
2260 	trimStack(fun->stack);
2261 	fun->reg.setVariable(SVT_INT, 1);
2262 	return BR_CONTINUE;
2263 }
2264 
builtIn(freeSound)2265 builtIn(freeSound) {
2266 	UNUSEDALL
2267 	int v;
2268 	if (!fun->stack->thisVar.getValueType(v, SVT_FILE))
2269 		return BR_ERROR;
2270 	trimStack(fun->stack);
2271 	g_sludge->_soundMan->huntKillFreeSound(v);
2272 	return BR_CONTINUE;
2273 }
2274 
builtIn(parallaxAdd)2275 builtIn(parallaxAdd) {
2276 	UNUSEDALL
2277 	if (g_sludge->_gfxMan->isFrozen()) {
2278 		fatal("Can't set background parallax image while frozen");
2279 		return BR_ERROR;
2280 	} else {
2281 		int wrapX, wrapY, v;
2282 		if (!fun->stack->thisVar.getValueType(wrapY, SVT_INT))
2283 			return BR_ERROR;
2284 		trimStack(fun->stack);
2285 		if (!fun->stack->thisVar.getValueType(wrapX, SVT_INT))
2286 			return BR_ERROR;
2287 		trimStack(fun->stack);
2288 		if (!fun->stack->thisVar.getValueType(v, SVT_FILE))
2289 			return BR_ERROR;
2290 		trimStack(fun->stack);
2291 
2292 		if (!g_sludge->_gfxMan->loadParallax(v, wrapX, wrapY))
2293 			return BR_ERROR;
2294 		fun->reg.setVariable(SVT_INT, 1);
2295 	}
2296 	return BR_CONTINUE;
2297 }
2298 
builtIn(parallaxClear)2299 builtIn(parallaxClear) {
2300 	UNUSEDALL
2301 	g_sludge->_gfxMan->killParallax();
2302 	fun->reg.setVariable(SVT_INT, 1);
2303 	return BR_CONTINUE;
2304 }
2305 
builtIn(getPixelColour)2306 builtIn(getPixelColour) {
2307 	UNUSEDALL
2308 	int x, y;
2309 	if (!fun->stack->thisVar.getValueType(y, SVT_INT))
2310 		return BR_ERROR;
2311 	trimStack(fun->stack);
2312 	if (!fun->stack->thisVar.getValueType(x, SVT_INT))
2313 		return BR_ERROR;
2314 	trimStack(fun->stack);
2315 
2316 	fun->reg.unlinkVar();
2317 	fun->reg.varType = SVT_STACK;
2318 	fun->reg.varData.theStack = new StackHandler;
2319 	if (!checkNew(fun->reg.varData.theStack))
2320 		return BR_ERROR;
2321 	fun->reg.varData.theStack->first = NULL;
2322 	fun->reg.varData.theStack->last = NULL;
2323 	fun->reg.varData.theStack->timesUsed = 1;
2324 	if (!g_sludge->_gfxMan->getRGBIntoStack(x, y, fun->reg.varData.theStack))
2325 		return BR_ERROR;
2326 
2327 	return BR_CONTINUE;
2328 }
2329 
builtIn(makeFastArray)2330 builtIn(makeFastArray) {
2331 	UNUSEDALL
2332 	switch (fun->stack->thisVar.varType) {
2333 	case SVT_STACK: {
2334 		bool success = fun->reg.makeFastArrayFromStack(fun->stack->thisVar.varData.theStack);
2335 		trimStack(fun->stack);
2336 		return success ? BR_CONTINUE : BR_ERROR;
2337 	}
2338 		break;
2339 
2340 	case SVT_INT: {
2341 		int i = fun->stack->thisVar.varData.intValue;
2342 		trimStack(fun->stack);
2343 		return fun->reg.makeFastArraySize(i) ? BR_CONTINUE : BR_ERROR;
2344 	}
2345 		break;
2346 
2347 	default:
2348 		break;
2349 	}
2350 	fatal("Parameter must be a number or a stack.");
2351 	return BR_ERROR;
2352 }
2353 
builtIn(getCharacterScale)2354 builtIn(getCharacterScale) {
2355 	UNUSEDALL
2356 	int objectNumber;
2357 	if (!fun->stack->thisVar.getValueType(objectNumber, SVT_OBJTYPE))
2358 		return BR_ERROR;
2359 	trimStack(fun->stack);
2360 
2361 	OnScreenPerson *pers = g_sludge->_peopleMan->findPerson(objectNumber);
2362 	if (pers) {
2363 		fun->reg.setVariable(SVT_INT, pers->scale * 100);
2364 	} else {
2365 		fun->reg.setVariable(SVT_INT, 0);
2366 	}
2367 	return BR_CONTINUE;
2368 }
2369 
builtIn(getLanguageID)2370 builtIn(getLanguageID) {
2371 	UNUSEDALL
2372 	fun->reg.setVariable(SVT_INT, g_sludge->getLanguageID());
2373 	return BR_CONTINUE;
2374 }
2375 
2376 // Removed function
builtIn(_rem_launchWith)2377 builtIn(_rem_launchWith) {
2378 	UNUSEDALL
2379 
2380 	trimStack(fun->stack);
2381 
2382 	// To support some windows only games
2383 	Common::String filename = fun->stack->thisVar.getTextFromAnyVar();
2384 	trimStack(fun->stack);
2385 
2386 	if (filename.hasSuffix(".exe")) {
2387 		const Common::FSNode gameDataDir(ConfMan.get("path"));
2388 		Common::FSList files;
2389 		gameDataDir.getChildren(files, Common::FSNode::kListFilesOnly);
2390 
2391 		if (!files.empty()) {
2392 			for (Common::FSList::const_iterator file = files.begin(); file != files.end(); ++file) {
2393 				Common::String fileName = file->getName();
2394 				fileName.toLowercase();
2395 				if (fileName.hasSuffix(".dat") || fileName == "data") {
2396 					g_sludge->launchNext = file->getName();
2397 					return BR_CONTINUE;
2398 				}
2399 			}
2400 		}
2401 	}
2402 
2403 	g_sludge->launchNext.clear();
2404 	fun->reg.setVariable(SVT_INT, false);
2405 	return BR_CONTINUE;
2406 }
2407 
builtIn(getFramesPerSecond)2408 builtIn(getFramesPerSecond) {
2409 	UNUSEDALL
2410 	fun->reg.setVariable(SVT_INT, g_sludge->_timer->getLastFps());
2411 	return BR_CONTINUE;
2412 }
2413 
builtIn(showThumbnail)2414 builtIn(showThumbnail) {
2415 	UNUSEDALL
2416 	int x, y;
2417 	if (!fun->stack->thisVar.getValueType(y, SVT_INT))
2418 		return BR_ERROR;
2419 	trimStack(fun->stack);
2420 	if (!fun->stack->thisVar.getValueType(x, SVT_INT))
2421 		return BR_ERROR;
2422 	trimStack(fun->stack);
2423 
2424 	// Encode the name!Encode the name!
2425 	Common::String aaaaa = fun->stack->thisVar.getTextFromAnyVar();
2426 	trimStack(fun->stack);
2427 	Common::String file = encodeFilename(aaaaa);
2428 	g_sludge->_gfxMan->showThumbnail(file, x, y);
2429 	return BR_CONTINUE;
2430 }
2431 
builtIn(setThumbnailSize)2432 builtIn(setThumbnailSize) {
2433 	UNUSEDALL
2434 	int thumbHeight, thumbWidth;
2435 	if (!fun->stack->thisVar.getValueType(thumbHeight, SVT_INT))
2436 		return BR_ERROR;
2437 	trimStack(fun->stack);
2438 	if (!fun->stack->thisVar.getValueType(thumbWidth, SVT_INT))
2439 		return BR_ERROR;
2440 	trimStack(fun->stack);
2441 	if (!g_sludge->_gfxMan->setThumbnailSize(thumbWidth, thumbHeight)) {
2442 		Common::String buff = Common::String::format("%i x %i", thumbWidth, thumbWidth);
2443 		fatal("Invalid thumbnail size", buff);
2444 		return BR_ERROR;
2445 	}
2446 	return BR_CONTINUE;
2447 }
2448 
builtIn(hasFlag)2449 builtIn(hasFlag) {
2450 	UNUSEDALL
2451 	int objNum, flagIndex;
2452 	if (!fun->stack->thisVar.getValueType(flagIndex, SVT_INT))
2453 		return BR_ERROR;
2454 	trimStack(fun->stack);
2455 	if (!fun->stack->thisVar.getValueType(objNum, SVT_OBJTYPE))
2456 		return BR_ERROR;
2457 	trimStack(fun->stack);
2458 	ObjectType *objT = g_sludge->_objMan->findObjectType(objNum);
2459 	if (!objT)
2460 		return BR_ERROR;
2461 	fun->reg.setVariable(SVT_INT, objT->flags & (1 << flagIndex));
2462 	return BR_CONTINUE;
2463 }
2464 
builtIn(snapshotGrab)2465 builtIn(snapshotGrab) {
2466 	UNUSEDALL
2467 	return g_sludge->_gfxMan->snapshot() ? BR_CONTINUE : BR_ERROR;
2468 }
2469 
builtIn(snapshotClear)2470 builtIn(snapshotClear) {
2471 	UNUSEDALL
2472 	g_sludge->_gfxMan->nosnapshot();
2473 	return BR_CONTINUE;
2474 }
2475 
builtIn(bodgeFilenames)2476 builtIn(bodgeFilenames) {
2477 	UNUSEDALL
2478 	bool lastValue = allowAnyFilename;
2479 	allowAnyFilename = fun->stack->thisVar.getBoolean();
2480 	trimStack(fun->stack);
2481 	fun->reg.setVariable(SVT_INT, lastValue);
2482 	return BR_CONTINUE;
2483 }
2484 
2485 // Deprecated - does nothing.
builtIn(_rem_registryGetString)2486 builtIn(_rem_registryGetString) {
2487 	UNUSEDALL
2488 	trimStack(fun->stack);
2489 	trimStack(fun->stack);
2490 	fun->reg.setVariable(SVT_INT, 0);
2491 
2492 	return BR_CONTINUE;
2493 }
2494 
builtIn(quitWithFatalError)2495 builtIn(quitWithFatalError) {
2496 	UNUSEDALL
2497 	Common::String mess = fun->stack->thisVar.getTextFromAnyVar();
2498 	trimStack(fun->stack);
2499 	fatal(mess);
2500 	return BR_ERROR;
2501 }
2502 
builtIn(_rem_setCharacterAA)2503 builtIn(_rem_setCharacterAA) {
2504 	UNUSEDALL
2505 
2506 	trimStack(fun->stack);
2507 	trimStack(fun->stack);
2508 	trimStack(fun->stack);
2509 	trimStack(fun->stack);
2510 
2511 	return BR_CONTINUE;
2512 }
2513 
builtIn(_rem_setMaximumAA)2514 builtIn(_rem_setMaximumAA) {
2515 	UNUSEDALL
2516 
2517 	trimStack(fun->stack);
2518 	trimStack(fun->stack);
2519 	trimStack(fun->stack);
2520 
2521 	return BR_CONTINUE;
2522 
2523 }
2524 
builtIn(setBackgroundEffect)2525 builtIn(setBackgroundEffect) {
2526 	UNUSEDALL
2527 	bool done = g_sludge->_gfxMan->blur_createSettings(numParams, fun->stack);
2528 	fun->reg.setVariable(SVT_INT, done ? 1 : 0);
2529 	return BR_CONTINUE;
2530 }
2531 
builtIn(doBackgroundEffect)2532 builtIn(doBackgroundEffect) {
2533 	UNUSEDALL
2534 	bool done = g_sludge->_gfxMan->blurScreen();
2535 	fun->reg.setVariable(SVT_INT, done ? 1 : 0);
2536 	return BR_CONTINUE;
2537 }
2538 
2539 #pragma mark -
2540 #pragma mark Other functions
2541 
2542 //-------------------------------------
2543 
2544 } // End of namespace Sludge
2545 
2546 #include "functionlist.h"
2547 
2548 namespace Sludge {
2549 
callBuiltIn(int whichFunc,int numParams,LoadedFunction * fun)2550 BuiltReturn callBuiltIn(int whichFunc, int numParams, LoadedFunction *fun) {
2551 	if (numBIFNames) {
2552 		setFatalInfo((fun->originalNumber < numUserFunc) ? allUserFunc[fun->originalNumber] : "Unknown user function",
2553 				(whichFunc < numBIFNames) ? allBIFNames[whichFunc] : "Unknown built-in function");
2554 	}
2555 
2556 	if (whichFunc < NUM_FUNCS) {
2557 		if (builtInFunctionArray[whichFunc].paramNum != -1) {
2558 			if (builtInFunctionArray[whichFunc].paramNum != numParams) {
2559 				Common::String buff = Common::String::format("Built in function must have %i parameter%s", builtInFunctionArray[whichFunc].paramNum, (builtInFunctionArray[whichFunc].paramNum == 1) ? "" : "s");
2560 				Common::String msg = buff;
2561 				fatal(msg);
2562 				return BR_ERROR;
2563 			}
2564 		}
2565 
2566 		if (builtInFunctionArray[whichFunc].func) {
2567 			debugC(3, kSludgeDebugBuiltin,
2568 					"Run built-in function %i : %s",
2569 					whichFunc, (whichFunc < numBIFNames) ? allBIFNames[whichFunc].c_str() : "Unknown");
2570 			return builtInFunctionArray[whichFunc].func(numParams, fun);
2571 		}
2572 	}
2573 
2574 	fatal("Unknown / unimplemented built-in function.");
2575 	return BR_ERROR;
2576 }
2577 
getBuiltInName(int num)2578 const char *getBuiltInName(int num) {
2579 	if (num >= NUM_FUNCS)
2580 		error("getBuiltInName: incorrect builtin number. %d > %d", num, NUM_FUNCS);
2581 
2582 	return builtInFunctionArray[num].name;
2583 }
2584 
2585 } // End of namespace Sludge
2586