1 // BlinkenSisters - Hunt for the Lost Pixels
2 //     Bringing back the fun of the 80s
3 //
4 // (C) 2005-08 Rene Schickbauer, Wolfgang Dautermann
5 //
6 // See LICENSE for licensing information
7 //
8 
9 
10 #include "globals.h"
11 #include "engine.h"
12 #include "levelhandler.h"
13 #include "background.h"
14 #include "background2.h"
15 #include "drawprimitives.h"
16 #include "showtext.h"
17 #include "debug.h"
18 #include "tiles.h"
19 #include "playersprite.h"
20 #include "colission.h"
21 #include "showloading.h"
22 #include "gameengine.h"
23 #include "showpicture.h"
24 #include "joystick.h"
25 #ifdef ALLOW_ACTIONCAPTURE
26 #include "actioncapture.h"
27 #endif // ALLOW_ACTIONCAPTURE
28 #include "sound.h"
29 #include "fgobjects.h"
30 #include "bl_lua.h"
31 #include "fonthandler.h"
32 #include "showvideo.h"
33 #include "fginlay.h"
34 #include "bmfconvert.h"
35 #include "errorhandler.h"
36 #include "triggers.h"
37 #include "outputfilter.h"
38 #include "blending.h"
39 #include "bl_lua_objbindings.h"
40 #ifndef DISABLE_NETWORK
41 #include "blpstream.h"
42 #include "mcufstream.h"
43 #endif // DISABLE_NETWORK
44 #include "bsgui.h"
45 #include "fonthandler.h"
46 #include "bsscreen.h"
47 
48 #include <math.h>
49 #include <string.h>
50 
51 Uint32 fgXoffs = 0;
52 Uint32 fgYoffs = 0;
53 double fgXoffsOld = 0;
54 double fgYoffsOld = 0;
55 double fgXoffsTmp = 0;
56 double fgYoffsTmp = 0;
57 
58 Uint32 spriterelx;
59 Uint32 spriterely;
60 PLAYERSPRITETYPE mtype = PLAYERSPRITE_NOMOVE;
61 double spritex, spritey, spritevx, spritevy;
62 Uint32 mcoltype;
63 bool isJumping;
64 bool gameRunning;
65 double blinkdir = BLINKSPEED;
66 double blinkbright = 100;
67 Uint32 foundPixels = 0;
68 char errorMessage[100];
69 Sint32 leftright = 0;
70 Sint32 updown = 0;
71 bool leftpressed = false;
72 bool rightpressed = false;
73 bool uppressed = false;
74 bool downpressed = false;
75 bool lockedBG;
76 bool hasGravity;
77 bool freeMovement;
78 bool touchFGObject;
79 bool firstLoop;
80 bool canPaintSpecialTiles;
81 bool allowedToExit;
82 bool displayPlayerCoords;
83 bool isEditMode;
84 bool isGodMode;
85 bool attracktModeRunning;
86 bool killPlayer;
87 bool turboMode;
88 bool turboKeyPressed;
89 bool isPauseMode = false;
90 bool hasScriptPhysics;
91 bool enableQuickDraw = false;
92 Uint32 BS_MyTick = 0;
93 Uint32 BS_MyLastTick = 0;
94 
95 FILE* poscapfh = 0;
96 #ifdef ALLOW_POSITIONCAPTURE
97 Uint32 poscapcount;
98 #endif // ALLOW_POSITIONCAPTURE
99 bool isAttrackMode;
100 SDL_Color PLAYMECOLOR_ACTIVE	= { 0xff, 0xff, 0xff, 0 };
101 SDL_Color TEXTINFO_COLOR	= { 0xe0, 0xe0, 0xe0, 0 };
102 SDL_Color TEXTINFO_TIMEALERT	= { 0xff, 0x00, 0x00, 0 };
initEngine(bool initForAttractMode)103 void initEngine(bool initForAttractMode)
104 {
105 	lockedBG = false;
106 	hasGravity = true;
107 	freeMovement = false;
108 	allowedToExit = false;
109 	canPaintSpecialTiles = true;
110 	leftpressed = false;
111 	rightpressed = false;
112 	uppressed = false;
113 	downpressed = false;
114 	turboMode = false;
115 	turboKeyPressed = false;
116 	hasScriptPhysics = false;
117 
118 	loadMonsterSprites();
119 	initLevel(gamedata.player->level);
120 	initMonsters();
121 #ifndef DISABLE_NETWORK
122 	if (blpport != 0) {
123 		initBLPFrames();
124 	} ;
125 	if (mcufport != 0) {
126 		initMCUFFrames();
127 	} ;
128 #endif // DISABLE_NETWORK
129 
130 	spritex = lhandle.respawn_x;
131 	spritey = lhandle.respawn_y;
132 	spritevx = 0;
133 	spritevy = 0;
134 	leftright = 0;
135 	updown = 0;
136 	isJumping = false;
137 	gameRunning = true;
138 	foundPixels = 0;
139 	firstLoop = true;
140 	hasEatenPixel = false;
141 	resetFGInlay();
142 	isAttrackMode = false;
143 	displayPlayerCoords = false;
144 	isEditMode = false;
145 	isGodMode = false;
146 	killPlayer = false;
147 	poscapfh = 0;
148 
149 #ifdef ALLOW_POSITIONCAPTURE
150 	if(!initForAttractMode) {
151 		char poscapname[100];
152 		sprintf(poscapname, "poscap_level_%d.bin", gamedata.player->level);
153 		poscapfh = fopen(configGetPath(poscapname), "wb");
154 		if(!poscapfh) {
155 			DIE(ERROR_FILE_WRITE, configGetPath(poscapname));
156 		}
157 		poscapcount = 0;
158 	}
159 #endif // ALLOW_POSITIONCAPTURE
160 
161 }
162 
deInitEngine()163 void deInitEngine ()
164 {
165 #ifndef DISABLE_NETWORK
166 	if (blpport != 0) {
167 		deInitBLPFrames();
168 	} ;
169 	if (mcufport != 0) {
170 		deInitMCUFFrames();
171 	} ;
172 #endif // DISABLE_NETWORK
173 	if(poscapfh != 0) {
174 		fclose(poscapfh);
175 		poscapfh = 0;
176 	}
177 	deInitLevel();
178 	unloadMonsterSprites();
179 
180 	if(enableColor3D) {
181 		BS_Set3DMode(COLOR3D_NONE);
182 	}
183 }
184 
185 
engineFullPhysics()186 void engineFullPhysics() {
187 	// Full Physics-Engine
188 	if(!turboMode) {
189 		gLastTick += 1000 / PHYSICSFPS;
190 	} else {
191 		gLastTick += 1000 / (PHYSICSFPS*4);
192 	}
193 
194 	if(lhandle.leveltime > 0) {
195 		if (!isEditMode) {
196 			if(!turboMode) {
197 				lhandle.remaintime -= 0.01;
198 			} else {
199 				lhandle.remaintime -= 0.04;
200 			}
201 		}
202 		if(lhandle.remaintime <= 0) {
203 			displaymessage(displaymessage_INFO, "Level timeout - play faster!!!", 800);
204 			spritevx = 0;
205 			spritevy = 0;
206 			spritex = lhandle.respawn_x;
207 			spritey = lhandle.respawn_y;
208 			gamedata.player->lives--;
209 			leftpressed = false;
210 			rightpressed = false;
211 			uppressed = false;
212 			downpressed = false;
213 			firstLoop = true;
214 			hasEatenPixel = false;
215 			hasGravity = true;
216 			isGodMode = false;
217 			killPlayer = false;
218 			turboMode = false;
219 			turboKeyPressed = false;
220 			lhandle.remaintime = (double)lhandle.leveltime;
221 			// it costs some score if kate looses a life
222 			gamedata.player->score -= lhandle.timemalusifkatedies;
223 			if (gamedata.player->score < 0) gamedata.player->score = 0 ; /* no negative score? why not? :-) */
224 			// Reset sprite display to default starting position
225 			resetSpriteGFX();
226 
227 
228 			// OO-LUA LUA Livelost Callback
229 			if(lhandle.luaCB[CB_PLAYER_LIVELOST].cbName[0] != 0) {
230 				blLuaCall(lhandle.blOOLuaState, lhandle.luaCB[CB_PLAYER_LIVELOST].cbName, "");
231 			}
232 			if(!showVideo("livelost.bmf", false, false)) {
233 				soundPlayFX(FX_KILL_PLAYER);
234 				showPicture("livelost.jpg", 2000);
235 			}
236 #ifdef ALLOW_ACTIONCAPTURE
237 			stopActionCapture();
238 #endif // ALLOW_ACTIONCAPTURE
239 			gLastTick = BS_GetTicks();
240 		}
241 	}
242 
243 	// Blinking of pixels
244 	blinkbright += blinkdir;
245 	if(blinkbright < 10 || blinkbright > 250) {
246 		blinkdir = 0 - blinkdir;
247 	}
248 	advanceFGObjAnim();
249 
250 	// Inlay message
251 	calcFGInlay();
252 
253 	// Monsters
254 	monsterPhysics((Uint32)spritex, (Uint32)spritey);
255 	if(lhandle.hasScript) {
256 		blLuaCall(lhandle.blLuaState, "scriptPhysics", "");
257 	}
258 
259 	// OO-LUA LUA Physics Callback
260 	if(lhandle.luaCB[CB_ENGINE_PHYSICS].cbName[0] != 0) {
261 		blLuaCall(lhandle.blOOLuaState, lhandle.luaCB[CB_ENGINE_PHYSICS].cbName, "");
262 	}
263 
264 	if(lhandle.hasScript || lhandle.hasOOScript) {
265 		handleTriggers();
266 	}
267 
268 	if(lhandle.hasOOScript) {
269 		handlePlayerFGObjCallbacks();
270 	}
271 
272 	// Left/Right movement with smooth acceleration/braking
273 
274 	if(leftright > 0) {
275 		spritevx += SPRITE_ACCEL;
276 	} else if(leftright < 0) {
277 		spritevx -= SPRITE_ACCEL;
278 	} else {
279 		if(spritevx > SPRITE_ACCEL) {
280 			spritevx -= SPRITE_ACCEL;
281 		} else if(spritevx < -SPRITE_ACCEL) {
282 			spritevx += SPRITE_ACCEL;
283 		} else {
284 			spritevx = 0;
285 		}
286 	}
287 
288 	if(freeMovement) {
289 		if(updown > 0) {
290 			spritevy += SPRITE_ACCEL;
291 		} else if(updown < 0) {
292 			spritevy -= SPRITE_ACCEL;
293 		} else {
294 			if(spritevy > SPRITE_ACCEL) {
295 				spritevy -= SPRITE_ACCEL;
296 			} else if(spritevy < -SPRITE_ACCEL) {
297 				spritevy += SPRITE_ACCEL;
298 			} else {
299 				spritevy = 0;
300 			}
301 		}
302 	}
303 
304 
305 	// Gravity
306 	if(hasGravity && !freeMovement) {
307 		spritevy += SPRITE_GRAVITY;
308 	}
309 
310 	// Limit speed
311 	if(spritevx > SPRITE_MAXSPEED) {
312 		spritevx = SPRITE_MAXSPEED;
313 	} else if(spritevx < -SPRITE_MAXSPEED) {
314 		spritevx = -SPRITE_MAXSPEED;
315 	}
316 	spritex += spritevx;
317 
318 	if(spritevy > SPRITE_MAXSPEED) {
319 		spritevy = SPRITE_MAXSPEED;
320 	} else if(spritevy < -SPRITE_MAXSPEED) {
321 		spritevy = -SPRITE_MAXSPEED;
322 	}
323 
324 	spritey += spritevy;
325 
326 	// Limit movement to stay within game-area
327 	if(spritex > (lhandle.width - 32)) {
328 		spritevx = 0;
329 		spritex = lhandle.width - 32;
330 	} else if(spritex < 0) {
331 		spritevx = 0;
332 		spritex = 0;
333 	}
334 
335 
336 	if(spritey > (lhandle.height - 32)) {
337 		spritevy = 0;
338 		spritey = lhandle.height - 32;
339 	} else if(spritey < 0) {
340 		spritevy = 0;
341 		spritey = 0;
342 	}
343 
344 
345 	// Decide on playersprite movement/gfx selection
346 	mtype = PLAYERSPRITE_NOMOVE;
347 
348 	if(leftright > 0) {
349 		if(updown > 0) {
350 			mtype = PLAYERSPRITE_RIGHTDOWN;
351 		} else if(updown < 0) {
352 			mtype = PLAYERSPRITE_RIGHTUP;
353 		} else {
354 			mtype = PLAYERSPRITE_RIGHT;
355 		}
356 	} else if(leftright < 0) {
357 		if(updown > 0) {
358 			mtype = PLAYERSPRITE_LEFTDOWN;
359 		} else if(updown < 0) {
360 			mtype = PLAYERSPRITE_LEFTUP;
361 		} else {
362 			mtype = PLAYERSPRITE_LEFT;
363 		}
364 	} else {
365 		if(updown > 0) {
366 			mtype = PLAYERSPRITE_DOWN;
367 		} else if(updown < 0) {
368 			mtype = PLAYERSPRITE_UP;
369 		} else {
370 			mtype = PLAYERSPRITE_NOMOVE;
371 		}
372 	}
373 
374 	if(isAttrackMode) {
375 		spritex = (double)bmfReadInt(poscapfh);
376 		spritey = (double)bmfReadInt(poscapfh);
377 		mtype = (PLAYERSPRITETYPE)bmfReadInt(poscapfh);
378 		if(spritex == 0 && spritey == 0) {
379 			fclose(poscapfh);
380 			poscapfh = 0;
381 			gamedata.player->lives = 0;
382 			gameRunning = false;
383 			return;
384 		}
385 	}
386 
387 #ifdef ALLOW_POSITIONCAPTURE
388 	if(!isAttrackMode && poscapfh) {
389 		bmfWriteInt(poscapfh, (Uint32)spritex);
390 		bmfWriteInt(poscapfh, (Uint32)spritey);
391 		bmfWriteInt(poscapfh, (Uint32)mtype);
392 		poscapcount++;
393 		if(poscapcount == 1700) {
394 			bmfWriteInt(poscapfh, (Uint32)0);
395 			bmfWriteInt(poscapfh, (Uint32)0);
396 			bmfWriteInt(poscapfh, (Uint32)0);
397 			fclose(poscapfh);
398 			poscapfh = 0;
399 		}
400 	}
401 #endif // ALLOW_POSITIONCAPTURE
402 
403 	updateSpriteGFX(mtype);
404 
405 	handlePlayerTilesColission();
406 	handlePlayerFGColission();
407 
408 	mcoltype = getPlayerMonsterColission();
409 	if(mcoltype & COL_UP || mcoltype & COL_LEFT || mcoltype & COL_RIGHT || getPlayerFGKillColission() || killPlayer) {
410 		if (!isGodMode) {
411 			spritevx = 0;
412 			spritevy = 0;
413 			spritex = lhandle.respawn_x;
414 			spritey = lhandle.respawn_y;
415 			gamedata.player->lives--;
416 			leftpressed = false;
417 			rightpressed = false;
418 			uppressed = false;
419 			downpressed = false;
420 			firstLoop = true;
421 			hasEatenPixel = false;
422 			hasGravity = true;
423 			freeMovement = isEditMode;
424 			isGodMode = false;
425 			killPlayer = false;
426 			turboMode = false;
427 			turboKeyPressed = false;
428 			lhandle.remaintime = (double)lhandle.leveltime;
429 			//it costs some score if kate looses a life
430 			gamedata.player->score -= lhandle.timemalusifkatedies;
431 			if (gamedata.player->score < 0) gamedata.player->score = 0 ; /* no negative score? why not? :-) */
432 			// Reset sprite display to default starting position
433 			resetSpriteGFX();
434 
435 			// OO-LUA LUA Livelost Callback
436 			if(lhandle.luaCB[CB_PLAYER_LIVELOST].cbName[0] != 0) {
437 				blLuaCall(lhandle.blOOLuaState, lhandle.luaCB[CB_PLAYER_LIVELOST].cbName, "");
438 			}
439 			if(!showVideo("livelost.bmf", false, false)) {
440 				soundPlayFX(FX_KILL_PLAYER);
441 				showPicture("livelost.jpg", 2000);
442 			}
443 #ifdef ALLOW_ACTIONCAPTURE
444 			stopActionCapture();
445 #endif // ALLOW_ACTIONCAPTURE
446 			gLastTick = BS_GetTicks();
447 			return;
448 		}
449 	}
450 
451 	touchFGObject = false;
452 
453 	// Check if the player has enough pixels to exit
454 	if(foundPixels == lhandle.numPixels) {
455 		allowedToExit = true;
456 	}
457 
458 	bool colWithExit = handlePixelCollission();
459 	if(colWithExit) {
460 		if(allowedToExit) {
461 			printf("LEVEL FINISHED\n");
462 			gameRunning = false;
463 		} else {
464 			sprintf(errorMessage, "Level not finished!");
465 		}
466 	}
467 
468 
469 	// Calculate relative positions of sprite, tiles and background
470 	spriterelx = SCR_WIDTH / 2;
471 	spriterely = SCR_HEIGHT / 2;
472 
473 	if(spritex < spriterelx) {
474 		fgXoffs = 0;
475 		spriterelx = (Uint32)spritex;
476 	} else if(spritex > (lhandle.width - spriterelx)) {
477 		spriterelx = SCR_WIDTH - (lhandle.width - (Uint32)spritex);
478 		fgXoffs = lhandle.width - SCR_WIDTH;
479 	} else {
480 		fgXoffs = (Uint32)spritex - spriterelx;
481 	}
482 
483 	if(spritey < spriterely) {
484 		fgYoffs = 0;
485 		spriterely = (Uint32)spritey;
486 	} else if(spritey > (lhandle.height - spriterely)) {
487 		spriterely = SCR_HEIGHT - (lhandle.height - (Uint32)spritey);
488 		fgYoffs = lhandle.height - SCR_HEIGHT;
489 	} else {
490 		fgYoffs = (Uint32)spritey - spriterely;
491 	}
492 
493 
494 #ifdef ALLOW_SMOOTHPANNING
495 	// --- Start of smooth panning feature
496 	if(firstLoop) {
497 		firstLoop = false;
498 		fgXoffsOld = (double)fgXoffs;
499 		fgYoffsOld = (double)fgYoffs;
500 	}
501 
502 	fgXoffsTmp = fgXoffsOld - (fgXoffsOld - (double)fgXoffs) / SMOOTHPANNING_FACTOR;
503 	if(fgXoffsTmp < 0.0) {
504 		fgXoffsTmp = 0.0;
505 	}
506 
507 	fgYoffsTmp = fgYoffsOld - (fgYoffsOld - (double)fgYoffs) / SMOOTHPANNING_FACTOR;
508 	if(fgYoffsTmp < 0.0) {
509 		fgYoffsTmp = 0.0;
510 	}
511 
512 	//spriterelx = spriterelx + (Uint32)(fgXoffsTmp) - fgXoffs;
513 	//spriterely = spriterely + ((Uint32)(fgYoffsTmp) - fgYoffs);
514 
515 	fgXoffsOld = fgXoffsTmp;
516 	fgYoffsOld = fgYoffsTmp;
517 
518 	Sint32 tmpSX = (Sint32)spritex - (Sint32)fgXoffsTmp;
519 	if(tmpSX < 0) {
520 		tmpSX = 0;
521 	} else if(tmpSX > SCR_WIDTH - TILESIZE) {
522 		tmpSX = SCR_WIDTH - TILESIZE;
523 	}
524 	spriterelx = tmpSX;
525 
526 	Sint32 tmpSY = (Sint32)spritey - (Sint32)fgYoffsTmp;
527 	if(tmpSY < 0) {
528 		tmpSY = 0;
529 	} else if(tmpSY > SCR_HEIGHT - TILESIZE) {
530 		tmpSY = SCR_HEIGHT - TILESIZE;
531 	}
532 	spriterely = tmpSY;
533 
534 	//printf("X: %d Y: %d\n", spriterelx, spriterely);
535 
536 
537 	fgXoffs = (Uint32)fgXoffsTmp;
538 	fgYoffs = (Uint32)fgYoffsTmp;
539 
540 	// --- End of smooth panning feature
541 #endif // ALLOW_SMOOTHPANNING
542 
543 
544 }
545 
engineMinimalPhysics()546 void engineMinimalPhysics() {
547 	// Minimal Physics-Engine
548 	if(!turboMode) {
549 		gLastTick += 1000 / PHYSICSFPS;
550 	} else {
551 		gLastTick += 1000 / (PHYSICSFPS*4);
552 	}
553 
554 	advanceFGObjAnim();
555 
556 	// Inlay message
557 	calcFGInlay();
558 
559 	if(lhandle.hasScript) {
560 		blLuaCall(lhandle.blLuaState, "scriptPhysics", "");
561 	}
562 
563 	// OO-LUA LUA Physics Callback
564 	if(lhandle.luaCB[CB_ENGINE_PHYSICS].cbName[0] != 0) {
565 		blLuaCall(lhandle.blOOLuaState, lhandle.luaCB[CB_ENGINE_PHYSICS].cbName, "");
566 	}
567 
568 	if(lhandle.hasScript || lhandle.hasOOScript) {
569 		handleTriggers();
570 	}
571 
572 	if(lhandle.hasOOScript) {
573 		handlePlayerFGObjCallbacks();
574 	}
575 
576 
577 
578 	// Decide on playersprite movement/gfx selection
579 /*
580 	mtype = PLAYERSPRITE_NOMOVE;
581 
582 	if(leftright > 0) {
583 		if(updown > 0) {
584 			mtype = PLAYERSPRITE_RIGHTDOWN;
585 		} else if(updown < 0) {
586 			mtype = PLAYERSPRITE_RIGHTUP;
587 		} else {
588 			mtype = PLAYERSPRITE_RIGHT;
589 		}
590 	} else if(leftright < 0) {
591 		if(updown > 0) {
592 			mtype = PLAYERSPRITE_LEFTDOWN;
593 		} else if(updown < 0) {
594 			mtype = PLAYERSPRITE_LEFTUP;
595 		} else {
596 			mtype = PLAYERSPRITE_LEFT;
597 		}
598 	} else {
599 		if(updown > 0) {
600 			mtype = PLAYERSPRITE_DOWN;
601 		} else if(updown < 0) {
602 			mtype = PLAYERSPRITE_UP;
603 		} else {
604 			mtype = PLAYERSPRITE_NOMOVE;
605 		}
606 	}
607 */
608 
609 
610 
611 
612 }
613 
renderEngine()614 void renderEngine() {
615 
616 	errorMessage[0] = 0;
617 
618 	// Ask SDL for the time in milliseconds
619 	Uint32 tick = BS_GetTicks();
620 
621 	// Delay a bit if we're too fast
622 	if(!isPauseMode) {
623 		while (tick <= gLastTick) {
624 			SDL_Delay(1);
625 			tick = BS_GetTicks();
626 		}
627 	}
628 
629 	while (gameRunning && gLastTick < tick) {
630 		if(!hasScriptPhysics) {
631 			engineFullPhysics();
632 		} else {
633 			engineMinimalPhysics();
634 		}
635 	}
636 
637 
638 
639 	// We are painting; allow LUA paint calls
640 	allowLUAPaint = true;
641 
642 
643 
644 
645 	if(enableColor3D) {
646 		BS_Set3DMode(COLOR3D_LEFT);
647 		engineDoRender(COLOR3D_LEFT);
648 		BS_Set3DMode(COLOR3D_RIGHT);
649 		engineDoRender(COLOR3D_RIGHT);
650 		// BS_Set3DMode(COLOR3D_NONE); // Don't need this?
651 	} else {
652 		engineDoRender(COLOR3D_NONE);
653 	}
654 
655 
656 	allowLUAPaint = false;
657 
658 
659 	// Tell SDL to update the whole screen
660 	BS_Flip(gScreen);
661 
662 #ifdef ALLOW_ACTIONCAPTURE
663 	renderActionCapture(spriterelx, spriterely);
664 #endif // ALLOW_ACTIONCAPTURE
665 
666 #ifndef DISABLE_NETWORK
667 	if (blpport != 0) {
668 		sendBLPFrame();
669 	} ;
670 	if (mcufport != 0) {
671 		sendMCUFFrame();
672 	} ;
673 #endif // DISABLE_NETWORK
674 
675 
676 }
677 
engineDoRender(COLOR3D mode3D)678 void engineDoRender(COLOR3D mode3D)
679 {
680 
681 	Uint32 bg2offs, bgoffs, fgoffs, txtoffs;
682 
683 	if(mode3D == COLOR3D_NONE) {
684 		bg2offs = bgoffs = fgoffs = txtoffs = 0;
685 	} else if(mode3D == COLOR3D_LEFT) {
686 		bg2offs = bgoffs = 0;
687 		fgoffs = 5;
688 		txtoffs = 2;
689 	} else {
690 		bg2offs = 20;
691 		bgoffs = 10;
692 		fgoffs = txtoffs = 0;
693 	}
694 
695 
696 	if(!lockedBG) {
697 		if(!lhandle.hasBG2) {
698 			drawBackground((fgXoffs / 2) + bgoffs, fgYoffs / 2);
699 		} else {
700 			drawBackground((fgXoffs / 4) + bg2offs, fgYoffs / 4);
701 			drawBackground2((fgXoffs / 2) + bgoffs, fgYoffs / 2);
702 		}
703 	} else {
704 		drawBackground(fgXoffs + bgoffs, fgYoffs);
705 	}
706 
707 	// LUA Painting - STAGE 1
708 	if(lhandle.luaCB[CB_RENDER_STAGE_1].cbName[0] != 0) {
709       	// Lock screen if needed
710     	if (SDL_MUSTLOCK(gScreen))
711     		if (SDL_LockSurface(gScreen) < 0)
712     			return;
713 		blLuaCall(lhandle.blOOLuaState, lhandle.luaCB[CB_RENDER_STAGE_1].cbName, "");
714     	// Unlock screen if needed
715     	if (SDL_MUSTLOCK(gScreen))
716     		SDL_UnlockSurface(gScreen);
717 	}
718 
719 	paintFGObjs(fgXoffs, fgYoffs, false);
720 	paintLevelTiles(fgXoffs, fgYoffs);
721 
722 	// LUA Painting - STAGE 2
723 	if(lhandle.luaCB[CB_RENDER_STAGE_2].cbName[0] != 0) {
724        	// Lock screen if needed
725     	if (SDL_MUSTLOCK(gScreen))
726     		if (SDL_LockSurface(gScreen) < 0)
727     			return;
728 		blLuaCall(lhandle.blOOLuaState, lhandle.luaCB[CB_RENDER_STAGE_2].cbName, "");
729     	// Unlock screen if needed
730     	if (SDL_MUSTLOCK(gScreen))
731     		SDL_UnlockSurface(gScreen);
732 	}
733 
734 	if(!hasScriptPhysics) {
735 		// Paint pixels only if it's internal engine physics
736 		paintLevelPixels(fgXoffs, fgYoffs, (Uint32)blinkbright);
737 	}
738 
739 	// LUA Painting - STAGE 3
740 	if(lhandle.luaCB[CB_RENDER_STAGE_3].cbName[0] != 0) {
741        	// Lock screen if needed
742     	if (SDL_MUSTLOCK(gScreen))
743     		if (SDL_LockSurface(gScreen) < 0)
744     			return;
745 		blLuaCall(lhandle.blOOLuaState, lhandle.luaCB[CB_RENDER_STAGE_3].cbName, "");
746     	// Unlock screen if needed
747     	if (SDL_MUSTLOCK(gScreen))
748     		SDL_UnlockSurface(gScreen);
749 	}
750 
751 	if(!hasScriptPhysics) {
752 		// Paint sprites only if it's internal engine physics
753 		showMonsterSprites(fgXoffs, fgYoffs);
754 		showSprite(spriterelx, spriterely);
755 	}
756 
757 	// LUA Painting - STAGE 4
758 	if(lhandle.luaCB[CB_RENDER_STAGE_4].cbName[0] != 0) {
759        	// Lock screen if needed
760     	if (SDL_MUSTLOCK(gScreen))
761     		if (SDL_LockSurface(gScreen) < 0)
762     			return;
763 		blLuaCall(lhandle.blOOLuaState, lhandle.luaCB[CB_RENDER_STAGE_4].cbName, "");
764     	// Unlock screen if needed
765     	if (SDL_MUSTLOCK(gScreen))
766     		SDL_UnlockSurface(gScreen);
767 	}
768 
769 	// LUA Painting - STAGE 5
770 	if(lhandle.luaCB[CB_RENDER_STAGE_5].cbName[0] != 0) {
771        	// Lock screen if needed
772     	if (SDL_MUSTLOCK(gScreen))
773     		if (SDL_LockSurface(gScreen) < 0)
774     			return;
775 		blLuaCall(lhandle.blOOLuaState, lhandle.luaCB[CB_RENDER_STAGE_5].cbName, "");
776     	// Unlock screen if needed
777     	if (SDL_MUSTLOCK(gScreen))
778     		SDL_UnlockSurface(gScreen);
779 	}
780 
781 
782 	// HUD ("Head-up-display")
783 		// LUA Painting - STAGE HUD
784 	if(lhandle.luaCB[CB_RENDER_STAGE_HUD].cbName[0] != 0) {
785        	// Lock screen if needed
786     	if (SDL_MUSTLOCK(gScreen))
787     		if (SDL_LockSurface(gScreen) < 0)
788     			return;
789 		blLuaCall(lhandle.blOOLuaState, lhandle.luaCB[CB_RENDER_STAGE_HUD].cbName, "");
790     	// Unlock if needed
791     	if (SDL_MUSTLOCK(gScreen))
792     		SDL_UnlockSurface(gScreen);
793 	} else {
794 		if(!enableQuickDraw) {
795 			if(!turboMode) {
796 				if(lhandle.leveltime <= 0) {
797 					blend_darkenRect(3, 3, SCR_WIDTH-6, 24, 0x00606060);
798 				} else {
799 					blend_darkenRect(3, 3, SCR_WIDTH-6, 48, 0x00606060);
800 				}
801 			} else {
802 				if(lhandle.leveltime <= 0) {
803 					blend_darkenRect(3, 3, SCR_WIDTH-6, 24, 0x00808080);
804 					blend_brightenRect(3, 3, SCR_WIDTH-6, 24, 0x00500000);
805 				} else {
806 					blend_darkenRect(3, 3, SCR_WIDTH-6, 48, 0x00808080);
807 					blend_brightenRect(3, 3, SCR_WIDTH-6, 48, 0x00500000);
808 				}
809 			}
810 		}
811 	}
812 
813 
814 	char printString[100];
815 	sprintf(printString, "Pixels: %u (%u)", foundPixels, lhandle.numPixels);
816 	renderFontHandlerText(20 + txtoffs, 2, printString, TEXTINFO_COLOR, false, false, FONT_textfont_20);
817 
818 	sprintf(printString, "Lives: %u", gamedata.player->lives);
819 	renderFontHandlerText(190 + txtoffs, 2, printString, TEXTINFO_COLOR, false, false, FONT_textfont_20);
820 
821 	sprintf(printString, "Level: %u", gamedata.player->level);
822 	renderFontHandlerText(310 + txtoffs, 2, printString, TEXTINFO_COLOR, false, false, FONT_textfont_20);
823 
824 	sprintf(printString, "Score: %u", gamedata.player->score);
825 	renderFontHandlerText(440 + txtoffs, 2, printString, TEXTINFO_COLOR, false, false, FONT_textfont_20);
826 
827 	if(enteringCheat) {
828 		if(!enableQuickDraw) {
829 			blend_darkenRect(5, SCR_HEIGHT-35, SCR_WIDTH-10, 30, 0x00808080);
830 			blend_brightenRect(5, SCR_HEIGHT-35, SCR_WIDTH-10, 30, 0x00500000);
831 		}
832 		if (SDL_GetTicks() % 200 < 100) { // blinking cursor
833 			sprintf(printString, "CHEAT: %s_", cheatCode);
834 		} else {
835 			sprintf(printString, "CHEAT: %s ", cheatCode);
836 		} ;
837 		renderFontHandlerText(20 + txtoffs, SCR_HEIGHT-30, printString, TEXTINFO_COLOR, false, false, FONT_textfont_20);
838 	}
839 
840 	if(lhandle.leveltime > 0) {
841 		sprintf(printString, "Rem. Time: %d", (Uint32)lhandle.remaintime);
842 		if(lhandle.remaintime <= 10) { /* red font, if the leveltime <= 10 sec */
843 			renderFontHandlerText(20 + txtoffs, 25, printString, TEXTINFO_TIMEALERT, false, false, FONT_textfont_20);
844 		} else {
845 			renderFontHandlerText(20 + txtoffs, 25, printString, TEXTINFO_COLOR, false, false, FONT_textfont_20) ;
846 		} ;
847 		Uint32 timebar = 0;
848 		if(lhandle.remaintime <= lhandle.leveltime) {
849 			timebar = (Uint32)(((lhandle.leveltime - lhandle.remaintime) * 300.0) / lhandle.leveltime);
850 			drawrect(200, 35, timebar, 7, 0xff0000);
851 			drawrect(200 + timebar, 35, 300-timebar, 7, 0x00ff00);
852 		} else {
853 			drawrect(200, 35, 300, 7, 0x00ff00);
854 			drawrect(201, 36, 298, 5, (Uint32)(blinkbright + blinkbright * 256 + blinkbright * 65536));
855 			SDL_Color blibri1 = {(Uint8)blinkbright, (Uint8)blinkbright, (Uint8)blinkbright, 0};
856 			SDL_Color blibri2 = {(Uint8)(255 - blinkbright), (Uint8)(255 - blinkbright), (Uint8)(255 - blinkbright), (Uint8)blinkbright};
857 			renderFontHandlerText(520 + txtoffs, 27, "Bonus", blibri1, false, false, FONT_textfont_8);
858 			renderFontHandlerText(530 + txtoffs, 33, "Time", blibri2, false, false, FONT_textfont_8) ;
859 		}
860 
861 	}
862 
863 	renderFontHandlerText(20 + txtoffs, 45, errorMessage, TEXTINFO_TIMEALERT, true, true, FONT_menufont_20);
864 
865 	paintFGObjs(fgXoffs + fgoffs, fgYoffs, true);
866 
867 
868 
869 #ifdef ALLOW_POSITIONCAPTURE
870 	if(!isAttrackMode && poscapfh) {
871 		renderFontHandlerText(20 + txtoffs, 60, "Position Capture (smile, please)", TEXTINFO_COLOR, false, false, FONT_textfont_20);
872 	}
873 #endif // ALLOW_POSITIONCAPTURE
874 
875 
876 #ifdef DISPLAY_PLAYERCOORDS
877 	if(displayPlayerCoords && !enteringCheat) {
878 		if(!enableQuickDraw) {
879 			blend_darkenRect(5 + txtoffs, 445, SCR_WIDTH-10, 30, 0x00808080);
880 			blend_brightenRect(5 + txtoffs, 445, SCR_WIDTH-10, 30, 0x00500000);
881 		}
882 		sprintf(printString, "X: %u", (Uint32)spritex);
883 		renderFontHandlerText(20 + txtoffs, 450, printString, TEXTINFO_COLOR, false, false, FONT_textfont_20);
884 		sprintf(printString, "Y: %u", (Uint32)spritey);
885 		renderFontHandlerText(120 + txtoffs, 450, printString, TEXTINFO_COLOR, false, false, FONT_textfont_20);
886 		sprintf(printString, "X: %u", (Uint32)((spritex/TILESIZE)+1));
887 		renderFontHandlerText(330 + txtoffs, 450, printString, TEXTINFO_COLOR, false, false, FONT_textfont_20);
888 		sprintf(printString, "Y: %u", (Uint32)((spritey/TILESIZE)+1));
889 		renderFontHandlerText(420 + txtoffs, 450, printString, TEXTINFO_COLOR, false, false, FONT_textfont_20);
890 	}
891 #endif // DISPLAY_PLAYERCOORDS
892 
893 
894 	if(isAttrackMode) {
895 		// These texts are handled like fgobjects in Color3D
896 		if((BS_GetTicks() % 10000) < 5000) {
897 			renderFontHandlerText(50 + fgoffs, 200, "PLAY ME!", PLAYMECOLOR_ACTIVE, true, true, FONT_menufont_50);
898 		} else {
899 			renderFontHandlerText(50 + fgoffs, 200, "SPIEL MICH!", PLAYMECOLOR_ACTIVE, true, true, FONT_menufont_50);
900 		}
901 	}
902 #ifdef SHOW_INLAY
903 	if(!enteringCheat && !displayPlayerCoords) {
904 		renderFGInlay();
905 	}
906 #endif // SHOW_INLAY
907 
908 
909 	if(isPauseMode) {
910 		// Handle text like fgobj in Color3D
911 		if(!enableQuickDraw) {
912 			blend_darkenRect(10, 10, SCR_WIDTH-20, SCR_HEIGHT-20, 0x00808080);
913 		}
914 		renderFontHandlerText(50 + fgoffs, 200, "PAUSE MODE", PLAYMECOLOR_ACTIVE, true, true, FONT_menufont_50);
915 		SDL_Delay(100);
916 	} else if(lhandle.leveltime > 0 && lhandle.remaintime <= 10) {
917 		// Handle text like fgobj in Color3D
918 		if((int)lhandle.remaintime % 2) {
919 			renderFontHandlerText(50 + fgoffs, 200, "! HURRY UP !", TEXTINFO_TIMEALERT, true, true, FONT_menufont_50);
920 		}
921 	}
922 
923 #ifdef SHOWFRAMERATE
924 	if(mode3D == COLOR3D_RIGHT) {
925 		displayFPSCounter(true);
926 	} else {
927 		displayFPSCounter();
928 	}
929 #endif // SHOWFRAMERATE
930 
931 	applyOutputFilter();
932 
933 }
934 
935 char cheatCode[MAX_STRING_LENGTH];
936 bool enteringCheat = false;
displayEngine(const char * attrackModeFile)937 void displayEngine(const char* attrackModeFile)
938 {
939 
940 	leftpressed = false;
941 	rightpressed = false;
942 	SDL_Event event;
943 
944 	// Special for attrack mode
945 	if(attrackModeFile) {
946 		gLastTick = BS_GetTicks();
947 		isAttrackMode = true;
948 		poscapfh = fopen(configGetPath(attrackModeFile), "rb");
949 		if(!poscapfh) {
950 			DIE(ERROR_FILE_READ, configGetPath(attrackModeFile));
951 		}
952 
953 		// Catch all user input. Poll for events, and handle the ones we care about.
954 		while(gameRunning) {
955 			while(SDL_PollEvent(&event)) {
956 				switch (event.type)
957 				{
958 					case SDL_KEYUP:
959 						gameRunning = false;
960 						attracktModeRunning = false;
961 						break;
962 					case SDL_QUIT:
963 						exit(0);
964 				}
965 			}
966 			Uint32 joymove = getJoystickMoves();
967 			if(joymove & JOYSTICK_JUMP || joymove & JOYSTICK_ACTION) {
968 				gameRunning = false;
969 				attracktModeRunning = false;
970 			}
971 			renderEngine();
972 		}
973 		return;
974 	}
975 
976 
977 	Uint32 cheatTick = 0;
978 	gLastTick = BS_GetTicks();
979 
980 	while (gameRunning && gamedata.player->lives > 0)
981 	{
982 		Uint32 ticks = BS_GetTicks();
983 		// Render stuff
984 
985 		// Get Joystick moves
986 		Uint32 joymove = getJoystickMoves();
987 		if(!freeMovement) {
988 			if((joymove & JOYSTICK_JUMP) && !isJumping && (touchFGObject || (spritevy < SPRITE_FALLSILENTTHRESHOLD))) {
989 				isJumping = true;
990 				spritevy = SPRITE_JUMPSPEED;
991 			}
992 		}
993 
994 		// Calculate reftright offset
995 		if((leftpressed && !rightpressed) || (joymove & JOYSTICK_LEFT)){
996 			leftright = -1;
997 		} else if((!leftpressed && rightpressed) || (joymove & JOYSTICK_RIGHT)){
998 			leftright = 1;
999 		} else {
1000 			leftright = 0;
1001 		}
1002 
1003 		if(freeMovement) {
1004 			// Calculate updown offset
1005 			if((uppressed && !downpressed) || (joymove & JOYSTICK_UP)){
1006 				updown = -1;
1007 			} else if((!uppressed && downpressed) || (joymove & JOYSTICK_DOWN)){
1008 				updown = 1;
1009 			} else {
1010 				updown = 0;
1011 			}
1012 			isJumping = 0;
1013 		} else {
1014 			uppressed = false;
1015 			downpressed = false;
1016 			updown = 0;
1017 		}
1018 
1019 		if(joymove & JOYSTICK_ACTION) {
1020 			doFGPlayerAction((Uint32)spritex, (Uint32)spritey);
1021 		}
1022 
1023 		if(joymove & JOYSTICK_PAUSE) {
1024 			isPauseMode = !isPauseMode;
1025 		}
1026 
1027 		renderEngine();
1028 		if(ticks > cheatTick) {
1029 			cheatTick = BS_GetTicks() + CHEATTIMEOUT;
1030 			cheatCode[0] = 0;
1031 			enteringCheat = false;
1032 		}
1033 
1034 		// Poll for events, and handle the ones we care about.
1035 		while (SDL_PollEvent(&event) && gameRunning)
1036 		{
1037 			switch (event.type)
1038 			{
1039 				case SDL_KEYDOWN:
1040 					if (event.key.keysym.sym == SDLK_LEFT ||
1041 							event.key.keysym.sym == SDLK_KP4) {
1042 						//leftright -= 1;
1043 						leftpressed = true;
1044 					} else if (event.key.keysym.sym == SDLK_RIGHT ||
1045 								event.key.keysym.sym == SDLK_KP6) {
1046 						//leftright += 1;
1047 						rightpressed = true;
1048 					} else if (event.key.keysym.sym == SDLK_UP ||
1049 								event.key.keysym.sym == SDLK_KP8) {
1050 						if(!freeMovement && event.key.keysym.sym != SDLK_KP8) {
1051 							if(touchFGObject || (!isJumping && spritevy < SPRITE_FALLSILENTTHRESHOLD)) {
1052 								isJumping = true;
1053 								spritevy = SPRITE_JUMPSPEED;
1054 							}
1055 						} else {
1056 							uppressed = true;
1057 						}
1058 					} else if (event.key.keysym.sym == SDLK_KP1) {
1059 						if(!freeMovement) {
1060 							if(touchFGObject || (!isJumping && spritevy < SPRITE_FALLSILENTTHRESHOLD)) {
1061 								isJumping = true;
1062 								spritevy = SPRITE_JUMPSPEED;
1063 							}
1064 						}
1065 
1066 					} else if (event.key.keysym.sym == SDLK_DOWN ||
1067 								event.key.keysym.sym == SDLK_KP2) {
1068 						if(freeMovement) {
1069 							downpressed = true;
1070 						}
1071 					} else if (event.key.keysym.sym == SDLK_PLUS ||
1072                               event.key.keysym.sym == SDLK_RIGHTBRACKET) {
1073 						turboKeyPressed = true;
1074 					}
1075 
1076 
1077 					break;
1078 				case SDL_KEYUP:
1079 					//printf("Key pressed: %d\n", event.key.keysym.sym);
1080 					// If escape is pressed, return (and thus, quit)
1081 					if (event.key.keysym.sym == SDLK_LEFT ||
1082 							event.key.keysym.sym == SDLK_KP4) {
1083 						//leftright += 1;
1084 						leftpressed = false;
1085 					} else if (event.key.keysym.sym == SDLK_RIGHT ||
1086 								event.key.keysym.sym == SDLK_KP6) {
1087 						rightpressed = false;
1088 						//leftright -= 1;
1089 					} else if (event.key.keysym.sym == SDLK_UP ||
1090 								event.key.keysym.sym == SDLK_KP8) {
1091 						if(freeMovement || event.key.keysym.sym == SDLK_KP8) {
1092 							uppressed = false;
1093 						}
1094 					} else if (event.key.keysym.sym == SDLK_DOWN ||
1095 								event.key.keysym.sym == SDLK_KP2) {
1096 						if(freeMovement) {
1097 							downpressed = false;
1098 						}
1099 					} else if (event.key.keysym.sym == SDLK_PLUS ||
1100 						event.key.keysym.sym == SDLK_RIGHTBRACKET) {
1101 						turboKeyPressed = false;
1102 					} else if (enteringCheat == false && event.key.keysym.sym == SDLK_RETURN) {
1103  	   					if(lhandle.musicPlaying == true) {
1104 				 			lhandle.musicPlaying = false;
1105 				 			soundStopMusic();
1106 						} else {
1107 							lhandle.musicPlaying = true;
1108 							soundStartMusic(lhandle.sndfile);
1109 						}
1110                         // Handle the BOSS-Key (ESC) - fast EXIT.
1111 #ifdef ALLOW_BOSSKEY
1112 					} else if (event.key.keysym.sym == SDLK_ESCAPE) {
1113 						displaymessage(displaymessage_INFO, "Boss-key (ESC) hit - fast exit", 800);
1114 						exit(0);
1115 #endif // ALLOW_BOSSKEY
1116 #ifdef ENABLE_FULLSCREEN
1117 					} else if ((event.key.keysym.sym == SDLK_f) && (enteringCheat == false)) {
1118 						/* Switching between fullscreen and
1119 						* windowing not allowed, if we are entering a cheatcode now
1120 						* (otherwise a cheatcode may not contain the character 'f' */
1121 						isFullscreen = !isFullscreen;
1122 						if(isFullscreen) {
1123 							gScreen = BS_SetVideoMode(SCR_WIDTH, SCR_HEIGHT, 32, SDL_SWSURFACE | SDL_FULLSCREEN);
1124 						} else {
1125 							gScreen = BS_SetVideoMode(SCR_WIDTH, SCR_HEIGHT, 32, SDL_SWSURFACE);
1126 						}
1127 #endif // ENABLE_FULLSCREEN
1128 #ifdef ALLOW_ACTIONCAPTURE
1129 					} else if (event.key.keysym.sym == SDLK_y) {
1130 						startActionCapture();
1131 					} else if (event.key.keysym.sym == SDLK_x) {
1132 						stopActionCapture();
1133 #endif // ALLOW_ACTIONCAPTURE
1134 					} else if (!enteringCheat && (event.key.keysym.sym == SDLK_SPACE ||
1135 								event.key.keysym.sym == SDLK_KP3)) {
1136 						doFGPlayerAction((Uint32)spritex, (Uint32)spritey);
1137 #ifdef ALLOW_CHEATCODES
1138 					} else if (!enteringCheat && event.key.keysym.sym == SDLK_q) {
1139 					    if(guiYesNoDialog("End the running game?", "Are you sure?", false)) {
1140 					        gamedata.player->lives = 0;
1141 							gameRunning = false;;
1142                         }
1143 					} else if (!enteringCheat && event.key.keysym.sym == SDLK_p) {
1144 						isPauseMode = !isPauseMode;
1145 					} else if (event.key.keysym.sym == SDLK_TAB && !isPauseMode) {
1146 						enteringCheat = !enteringCheat;
1147 						cheatCode[0] = 0;
1148 					} else if (enteringCheat == true && event.key.keysym.sym == SDLK_RETURN) {
1149 						if(strcmp(cheatCode, "nuke") == 0) {
1150 							printf("Nuking all monsters and adding them to your score...\n");
1151 							MONSTERS* monster = lhandle.monsters;
1152 							while(monster) {
1153 								if(monster->isAlive) {
1154 									gamedata.player->score += monster->score;
1155 									monster->isAlive = false;
1156 									monster->isDying = true;
1157 								}
1158 								monster = monster->next;
1159 							}
1160 							gamedata.bphuc = true;
1161 						} else if(strcmp(cheatCode, "skip") == 0) {
1162 							gameRunning = false;
1163 							gamedata.bphuc = true;
1164 							gamedata.player->score = 0;
1165 							showLoading();
1166 						} else if(strncmp(cheatCode, "goto ", 5) == 0) {
1167 							Uint32 lnum = (Uint32)atoi(((char*)cheatCode)+sizeof("goto"));
1168 							if(lnum > 0) {
1169 								gamedata.player->level = lnum - 1;
1170 								lhandle.nextlevels[0] = lnum;
1171 								gameRunning = false;
1172 							}
1173 							gamedata.bphuc = true;
1174 							gamedata.player->score = 0;
1175 							showLoading();
1176 						} else if(strcmp(cheatCode, "lives") == 0) {
1177 							gamedata.player->lives = 99;
1178 							gamedata.bphuc = true;
1179 						} else if(strcmp(cheatCode, "die") == 0) {
1180 							gamedata.player->lives = 0;
1181 							gameRunning = false;
1182 							showLoading();
1183 						} else if(strcmp(cheatCode, "quit") == 0) {
1184 							printf("Trying fast exit....\n");
1185 							displaymessage(displaymessage_INFO, "Exit using cheat code", 1000);
1186 							exit(0);
1187 						} else if(strcmp(cheatCode, "coords") == 0) {
1188 							displayPlayerCoords = !displayPlayerCoords;
1189 						} else if(strcmp(cheatCode, "freemode") == 0) {
1190 							freeMovement = !freeMovement;
1191 							gamedata.bphuc = true;
1192 						} else if(strcmp(cheatCode, "godmode") == 0) {
1193 							isGodMode = !isGodMode;
1194 							gamedata.bphuc = true;
1195 						} else if(strcmp(cheatCode, "timebonus") == 0) {
1196 							if (gamedata.player->score > 5000) {
1197 								gamedata.player->score -= 5000;
1198 							} else {
1199 								gamedata.player->score = 0;
1200 							}
1201 							lhandle.remaintime = lhandle.remaintime + 50;
1202 							gamedata.bphuc = true;
1203 						} else if(strcmp(cheatCode, "edit") == 0) {
1204 							gamedata.player->score = 0;
1205 							isEditMode = !isEditMode;
1206 							freeMovement = isEditMode;
1207 							isGodMode = isEditMode;
1208 							displayPlayerCoords = isEditMode;
1209 							soundPlayFX(FX_KILL_PLAYER);
1210 							showPicture("livelost.jpg", 200);
1211 							gLastTick = BS_GetTicks();
1212 							gamedata.bphuc = true;
1213 							if (isEditMode) {
1214 								gamedata.player->lives = 999;
1215 							}
1216 						}
1217 						cheatCode[0] = 0;
1218 						enteringCheat = false;
1219 					} else if(enteringCheat) {
1220 						/* Cheatcode may only contain the characters in CHEATCODECHARS */
1221 						if(strchr(CHEATCODECHARS, event.key.keysym.sym) && strlen(cheatCode) < 30) {
1222 							sprintf(cheatCode, "%s%c", cheatCode,event.key.keysym.sym);
1223 						} ;
1224 						if ((event.key.keysym.sym == SDLK_BACKSPACE)  && (strlen(cheatCode)>0)) { /* Backspace - delete last char */
1225 							cheatCode[strlen(cheatCode)-1] = '\0' ;
1226 						} ;
1227 						cheatTick = BS_GetTicks() + CHEATTIMEOUT;
1228 #endif // ALLOW_CHEATCODES
1229 					}
1230 
1231 
1232 					break;
1233 				case SDL_QUIT:
1234 					exit(0);
1235 			}
1236 		}
1237 
1238 		if(turboKeyPressed || (joymove & JOYSTICK_TURBO)) {
1239 			turboMode = true;
1240 		} else {
1241 			turboMode = false;
1242 		}
1243 	}
1244 
1245 	if(lhandle.leveltime > 0 && gamedata.player->lives > 0) {
1246 		addTimeToScore(); // Visibly add remaining time to score
1247 	}
1248 }
1249 
1250 
addTimeToScore()1251 void addTimeToScore() {
1252 	char tmp1[100];
1253 	SDL_Event event;
1254 	SDL_Color BONUSCOLOR_ACTIVE   = { 0xff, 0xff, 0xff, 0 };
1255 	Uint32 wtick = BS_GetTicks() + 50;
1256 	bool beep = true;
1257 
1258 	if(enableColor3D) {
1259 		BS_Set3DMode(COLOR3D_NONE);
1260 	}
1261 
1262 	while(lhandle.remaintime > 0) {
1263 		lhandle.remaintime--;
1264 		gamedata.player->score += lhandle.timebonusmultiplicator;
1265 		sprintf(tmp1, "Remaining time: %d\n\nScore: %d\n\nPress space to continue immediately.", (Uint32)lhandle.remaintime, gamedata.player->score);
1266 
1267 		drawrect(0, 0, SCR_WIDTH, SCR_HEIGHT, 0x00000000);
1268 		renderFontHandlerText(0, 50, "SCORE", BONUSCOLOR_ACTIVE, true, false, FONT_menufont_50);
1269 		renderFontHandlerText(50, 200, tmp1, BONUSCOLOR_ACTIVE, false, false, FONT_menufont_20);
1270 		BS_Flip(gScreen);
1271 		if(beep) {
1272 			soundPlayFX(FX_COLLECT_PIXEL);
1273 		}
1274 		beep = !beep;
1275 		while(wtick > BS_GetTicks()) {
1276 			SDL_Delay(1);
1277 		}
1278 		wtick = BS_GetTicks() + 50;
1279                // Handle Keyboard
1280                 SDL_PollEvent(&event) ;
1281 		if(event.type == SDL_KEYUP) {
1282 #ifdef ALLOW_BOSSKEY
1283 			if (event.key.keysym.sym == SDLK_ESCAPE) {
1284 				displaymessage(displaymessage_INFO, "Boss-key (ESC) hit - fast exit", 800);
1285 				exit(0);
1286 			}
1287 #endif // ALLOW_BOSSKEY
1288 			if (event.key.keysym.sym == SDLK_SPACE) {
1289 				/* Add score and continue game immediately */
1290 				gamedata.player->score += lhandle.timebonusmultiplicator * ((Uint32)lhandle.remaintime) ;
1291 				lhandle.remaintime = 0 ;
1292 			}
1293 		}
1294 	}
1295 	SDL_Delay(1000);
1296 }
1297 
BS_GetTicks()1298 Uint32 BS_GetTicks() {
1299 	if(!isPauseMode) {
1300 		BS_MyTick += (SDL_GetTicks() - BS_MyLastTick);
1301 	}
1302 	BS_MyLastTick = SDL_GetTicks();
1303 	return BS_MyTick;
1304 }
1305