1 
2 #include "Maelstrom_Globals.h"
3 #include "object.h"
4 #include "player.h"
5 #include "netplay.h"
6 #include "make.h"
7 #include "load.h"
8 
9 
10 #ifdef MOVIE_SUPPORT
11 extern int gMovie;
12 static SDL_Rect gMovieRect;
SelectMovieRect(void)13 int SelectMovieRect(void)
14 {
15 	SDL_Event event;
16 	SDL_Surface *saved;
17 	Uint32 white;
18 	int center_x, center_y;
19 	int width, height;
20 
21 	/* Wait for initial button press */
22 	screen->ShowCursor();
23 	center_x = 0;
24 	center_y = 0;
25 	while ( ! center_x && ! center_y ) {
26 		screen->WaitEvent(&event);
27 
28 		/* Check for escape key */
29 		if ( (event.type == SDL_KEYEVENT) &&
30 				(event.key.state == SDL_PRESSED) &&
31 				(event.key.keysym.sym == SDL_ESCAPE) ) {
32 			screen->HideCursor();
33 			return(0);
34 		}
35 
36 		/* Wait for button press */
37 		if ( (event.type == SDL_MOUSEBUTTONEVENT) &&
38 				(event.button.state == SDL_PRESSED) ) {
39 			center_x = event.button.x;
40 			center_y = event.button.y;
41 			break;
42 		}
43 	}
44 
45 	/* Save the screen */
46 	white = screen->MapRGB(0xFFFF, 0xFFFF, 0xFFFF);
47 	saved = screen->GrabArea(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
48 
49 	/* As the box moves... */
50 	width = height = 0;
51 	while ( 1 ) {
52 		win->GetEvent(&event);
53 
54 		/* Check for escape key */
55 		if ( (event.type == SDL_KEYEVENT) &&
56 				(event.key.state == SDL_PRESSED) &&
57 				(event.key.keysym.sym == SDL_ESCAPE) ) {
58 			screen->QueueBlit(0, 0, saved, NOCLIP);
59 			screen->Update();
60 			screen->FreeImage(saved);
61 			win->HideCursor();
62 			return(0);
63 		}
64 
65 		/* Check for ending button press */
66 		if ( event.type == ButtonPress ) {
67 			gMovieRect.x = center_x - width;
68 			gMovieRect.y = center_y - height;
69 			gMovieRect.w = 2*width;
70 			gMovieRect.h = 2*height;
71 			screen->QueueBlit(0, 0, saved, NOCLIP);
72 			screen->Update();
73 			screen->FreeImage(saved);
74 			win->HideCursor();
75 			return(1);
76 		}
77 
78 		if ( event.type == MotionNotify ) {
79 			screen->QueueBlit(0, 0, saved, NOCLIP);
80 			screen->Update();
81 			width = abs(event.motion.x - center_x);
82 			height = abs(event.motion.y - center_y);
83 			screen->DrawRect(center_x-width, center_y-height,
84 						2*width, 2*height, white);
85 			screen->Update();
86 		}
87 	}
88 	/* NEVERREACHED */
89 
90 }
91 #endif
92 extern int RunFrame(void);	/* The heart of blit.cc */
93 
94 // Global variables set in this file...
95 int	gGameOn;
96 int	gPaused;
97 int	gWave;
98 int	gBoomDelay;
99 int	gNextBoom;
100 int	gBoomPhase;
101 int	gNumRocks;
102 int	gLastStar;
103 int	gWhenDone;
104 int	gDisplayed;
105 
106 int	gMultiplierShown;
107 int	gPrizeShown;
108 int	gBonusShown;
109 int	gWhenHoming;
110 int	gWhenGrav;
111 int	gWhenDamaged;
112 int	gWhenNova;
113 int	gShakeTime;
114 int	gFreezeTime;
115 Object *gEnemySprite;
116 int	gWhenEnemy;
117 
118 // Local global variables;
119 static MFont *geneva=NULL;
120 static Uint32 ourGrey, ourWhite, ourBlack;
121 static int text_height;
122 
123 // Local functions used in the game module of Maelstrom
124 static void DoHouseKeeping(void);
125 static void NextWave(void);
126 static void DoGameOver(void);
127 static void DoBonus(void);
128 static void TwinkleStars(void);
129 
130 /* ----------------------------------------------------------------- */
131 /* -- Draw the status display */
132 
DrawStatus(Bool first,Bool ForceDraw)133 void DrawStatus(Bool first, Bool ForceDraw)
134 {
135 	static int nextDraw;
136 	static int lastDisplayed;
137 	int		Score;
138 	static int	lastScore, lastScores[MAX_PLAYERS];
139 	static int	lastWave;
140 	int		Lives;
141 	static	int	lastLives;
142 	static int	lastLife[MAX_PLAYERS];
143 	int		Bonus;
144 	static int	lastBonus;
145 	int		Frags;
146 	static int	lastFrags;
147 	int		AutoFire;
148 	static int	lastGun;
149 	int		AirBrakes;
150 	static int	lastBrakes;
151 	int		ShieldLevel;
152 	static int	lastShield;
153 	int		MultFactor;
154 	static int	lastMult;
155 	int		LongFire;
156 	static int	lastLong;
157 	int		TripleFire;
158 	static int	lastTriple;
159 	int		LuckOfTheIrish;
160 	static int	lastLuck;
161 	static int	fragoff;
162 	static int score_width, wave_width;
163 	static int lives_width, bonus_width;
164 	static int frags_width;
165 	int i;
166 	char numbuf[128];
167 
168 	if (first) {
169 		int x;
170 
171 		nextDraw = 1;
172 		lastDisplayed = -1;
173 		OBJ_LOOP(i, gNumPlayers)
174 			lastScores[i] = -1;
175 		lastScore = -1;
176 		lastWave = -1;
177 		lastShield = -1;
178 		lastLives = -1;
179 		lastBonus = -1;
180 		lastFrags = -1;
181 		lastGun = -1;
182 		lastBrakes = -1;
183 		lastMult = -1;
184 		lastLuck = -1;
185 		if (gWave == 1) {
186 			OBJ_LOOP(i, gNumPlayers)
187 				lastLife[i] = 0;
188 		}
189 		lastLong = -1;
190 		lastTriple = -1;
191 
192 		score_width = 0;
193 		wave_width = 0;
194 		lives_width = 0;
195 		bonus_width = 0;
196 		frags_width = 0;
197 
198 /* -- Draw the status display */
199 
200 		screen->DrawLine(0, gStatusLine, SCREEN_WIDTH-1,
201 							gStatusLine, ourWhite);
202 		x = 3;
203 		i = DrawText(x, gStatusLine+11, "Score:", geneva, STYLE_BOLD,
204 						30000>>8, 30000>>8, 0xFF);
205 		x += (i+70);
206 		i = DrawText(x, gStatusLine+11, "Shield:", geneva, STYLE_BOLD,
207 						30000>>8, 30000>>8, 0xFF);
208 		x += (i+70);
209 		i = DrawText(x, gStatusLine+11, "Wave:", geneva, STYLE_BOLD,
210 						30000>>8, 30000>>8, 0xFF);
211 		x += (i+30);
212 		i = DrawText(x, gStatusLine+11, "Lives:", geneva, STYLE_BOLD,
213 						30000>>8, 30000>>8, 0xFF);
214 		x += (i+30);
215 		DrawText(x, gStatusLine+11, "Bonus:", geneva, STYLE_BOLD,
216 						30000>>8, 30000>>8, 0xFF);
217 		/* Heh, DOOM style frag count */
218 		if ( gNumPlayers > 1 ) {
219 			x = 530;
220 			i = DrawText(x, gStatusLine+11, "Frags:", geneva,
221 					STYLE_BOLD, 30000>>8, 30000>>8, 0xFF);
222 			fragoff = x+i+4;
223 		}
224 	}
225 
226 	if ( ForceDraw || (--nextDraw == 0) ) {
227 		nextDraw = DISPLAY_DELAY+1;
228 		/* -- Do incremental updates */
229 
230 		if ( (gNumPlayers > 1) && (lastDisplayed != gDisplayed) ) {
231 			char caption[BUFSIZ];
232 
233 			lastDisplayed = gDisplayed;
234 			screen->FillRect(0, 0, SCREEN_WIDTH, 12, ourBlack);
235 			snprintf(caption, sizeof(caption),
236 				"You are player %d --- displaying player %d",
237 						gOurPlayer+1, gDisplayed+1);
238 			DrawText(SPRITES_WIDTH, 11, caption, geneva,
239 					STYLE_BOLD, 30000>>8, 30000>>8, 0xFF);
240 
241 			/* Fill in the color by the frag count */
242 			screen->FillRect(518, gStatusLine+4, 4, 8,
243 							TheShip->Color());
244 		}
245 
246 		ShieldLevel = TheShip->GetShieldLevel();
247 		if (lastShield != ShieldLevel) {
248 			int	fact;
249 
250 			lastShield = ShieldLevel;
251 			screen->DrawRect(152, gStatusLine+4, SHIELD_WIDTH,
252 								8, ourWhite);
253 			fact = ((SHIELD_WIDTH - 2) * ShieldLevel) / MAX_SHIELD;
254 			screen->FillRect(152+1,gStatusLine+4+1, fact, 6,
255 								ourGrey);
256 			screen->FillRect(152+1+fact, gStatusLine+4+1,
257 					SHIELD_WIDTH-2-fact, 6, ourBlack);
258 		}
259 
260 		MultFactor = TheShip->GetBonusMult();
261 		if (lastMult != MultFactor) {
262 			lastMult = MultFactor;
263 
264 			switch (MultFactor) {
265 				case 1:	screen->FillRect(424,
266 						gStatusLine+4, 8, 8, ourBlack);
267 					break;
268 				case 2:	screen->QueueBlit(424, gStatusLine+4,
269 							gMult2Icon, NOCLIP);
270 					break;
271 				case 3:	screen->QueueBlit(424, gStatusLine+4,
272 							gMult3Icon, NOCLIP);
273 					break;
274 				case 4:	screen->QueueBlit(424, gStatusLine+4,
275 							gMult4Icon, NOCLIP);
276 					break;
277 				case 5:	screen->QueueBlit(424, gStatusLine+4,
278 							gMult5Icon, NOCLIP);
279 					break;
280 				default:  /* WHAT? */
281 					break;
282 			}
283 		}
284 
285 		/* -- Do incremental updates */
286 
287 		AutoFire = TheShip->GetSpecial(MACHINE_GUNS);
288 		if (lastGun != AutoFire) {
289 			lastGun = AutoFire;
290 
291 			if ( AutoFire > 0 ) {
292 				screen->QueueBlit(438, gStatusLine+4,
293 						gAutoFireIcon, NOCLIP);
294 			} else {
295 				screen->FillRect(438, gStatusLine+4, 8, 8,
296 								ourBlack);
297 			}
298 		}
299 
300 		AirBrakes = TheShip->GetSpecial(AIR_BRAKES);
301 		if (lastBrakes != AirBrakes) {
302 			lastBrakes = AirBrakes;
303 
304 			if ( AirBrakes > 0 ) {
305 				screen->QueueBlit(454, gStatusLine+4,
306 						gAirBrakesIcon, NOCLIP);
307 			} else {
308 				screen->FillRect(454, gStatusLine+4, 8, 8,
309 								ourBlack);
310 			}
311 		}
312 
313 		LuckOfTheIrish = TheShip->GetSpecial(LUCKY_IRISH);
314 		if (lastLuck != LuckOfTheIrish) {
315 			lastLuck = LuckOfTheIrish;
316 
317 			if ( LuckOfTheIrish > 0 ) {
318 				screen->QueueBlit(470, gStatusLine+4,
319 						gLuckOfTheIrishIcon, NOCLIP);
320 			} else {
321 				screen->FillRect(470, gStatusLine+4, 8, 8,
322 								ourBlack);
323 			}
324 		}
325 
326 		TripleFire = TheShip->GetSpecial(TRIPLE_FIRE);
327 		if (lastTriple != TripleFire) {
328 			lastTriple = TripleFire;
329 
330 			if ( TripleFire > 0 ) {
331 				screen->QueueBlit(486, gStatusLine+4,
332 						gTripleFireIcon, NOCLIP);
333 			} else {
334 				screen->FillRect(486, gStatusLine+4, 8, 8,
335 								ourBlack);
336 			}
337 		}
338 
339 		LongFire = TheShip->GetSpecial(LONG_RANGE);
340 		if (lastLong != LongFire) {
341 			lastLong = LongFire;
342 
343 			if ( LongFire > 0 ) {
344 				screen->QueueBlit(502, gStatusLine+4,
345 						gLongFireIcon, NOCLIP);
346 			} else {
347 				screen->FillRect(502, gStatusLine+4, 8, 8,
348 								ourBlack);
349 			}
350 		}
351 
352 		/* Check for everyone else's new lives */
353 		OBJ_LOOP(i, gNumPlayers) {
354 			Score = gPlayers[i]->GetScore();
355 
356 			if ( (i == gDisplayed) && (Score != lastScore) ) {
357 				/* -- Erase old and draw new score */
358 				screen->FillRect(45, gStatusLine+1,
359 					score_width, text_height, ourBlack);
360 				snprintf(numbuf, sizeof(numbuf), "%d", Score);
361 				score_width = DrawText(45, gStatusLine+11,
362 						numbuf, geneva, STYLE_BOLD,
363 							0xFF, 0xFF, 0xFF);
364 				lastScore = Score;
365 			}
366 
367 			if (lastScores[i] == Score)
368 				continue;
369 
370 			/* -- See if they got a new life */
371 			lastScores[i] = Score;
372 			if ((Score - lastLife[i]) >= NEW_LIFE) {
373 				gPlayers[i]->IncrLives(1);
374 				lastLife[i] = (Score / NEW_LIFE) * NEW_LIFE;
375 				if ( i == gOurPlayer )
376 					sound->PlaySound(gNewLife, 5);
377 			}
378 		}
379 
380 		if (lastWave != gWave) {
381 			screen->FillRect(255, gStatusLine+1,
382 					wave_width, text_height, ourBlack);
383 			snprintf(numbuf, sizeof(numbuf), "%d", gWave);
384 			wave_width = DrawText(255, gStatusLine+11,
385 					numbuf, geneva, STYLE_BOLD,
386 							0xFF, 0xFF, 0xFF);
387 			lastWave = gWave;
388 		}
389 
390 		Lives = TheShip->GetLives();
391 		if (lastLives != Lives) {
392 			screen->FillRect(319, gStatusLine+1,
393 					lives_width, text_height, ourBlack);
394 			snprintf(numbuf, sizeof(numbuf), "%-3.1d", Lives);
395 			lives_width = DrawText(319, gStatusLine+11,
396 					numbuf, geneva, STYLE_BOLD,
397 							0xFF, 0xFF, 0xFF);
398 			lastLives = Lives;
399 		}
400 
401 		Bonus = TheShip->GetBonus();
402 		if (lastBonus != Bonus) {
403 			screen->FillRect(384, gStatusLine+1,
404 					bonus_width, text_height, ourBlack);
405 			snprintf(numbuf, sizeof(numbuf), "%-7.1d", Bonus);
406 			bonus_width = DrawText(384, gStatusLine+11,
407 					numbuf, geneva, STYLE_BOLD,
408 							0xFF, 0xFF, 0xFF);
409 			lastBonus = Bonus;
410 		}
411 
412 		if ( gNumPlayers > 1 ) {
413 			Frags = TheShip->GetFrags();
414 			if (lastFrags != Frags) {
415 				screen->FillRect(fragoff, gStatusLine+1,
416 					frags_width, text_height, ourBlack);
417 				snprintf(numbuf, sizeof(numbuf), "%-3.1d", Frags);
418 				frags_width = DrawText(fragoff, gStatusLine+11,
419 						numbuf, geneva, STYLE_BOLD,
420 							0xFF, 0xFF, 0xFF);
421 				lastFrags = Frags;
422 			}
423 		}
424 	}
425 }	/* -- DrawStatus */
426 
427 
428 /* ----------------------------------------------------------------- */
429 /* -- Start a new game */
430 
NewGame(void)431 void NewGame(void)
432 {
433 	int i;
434 
435 	/* Send a "NEW_GAME" packet onto the network */
436 	if ( gNumPlayers > 1 ) {
437 		if ( gOurPlayer == 0 ) {
438 			if ( Send_NewGame(&gStartLevel,&gStartLives,&gNoDelay)
439 									< 0)
440 				return;
441 		} else {
442 			if ( Await_NewGame(&gStartLevel,&gStartLives,&gNoDelay)
443 									< 0 )
444 				return;
445 		}
446 	}
447 
448 	/* Load the font and colors we use everywhere */
449 	if ( (geneva = fontserv->NewFont("Geneva", 9)) == NULL ) {
450 		error("Can't use Geneva font! -- Exiting.\n");
451 		exit(255);
452 	}
453 	text_height = fontserv->TextHeight(geneva);
454 	ourGrey = screen->MapRGB(30000>>8, 30000>>8, 0xFF);
455 	ourWhite = screen->MapRGB(0xFF, 0xFF, 0xFF);
456 	ourBlack = screen->MapRGB(0x00, 0x00, 0x00);
457 
458 	/* Fade into game mode */
459 	screen->Fade();
460 	screen->HideCursor();
461 
462 	/* Initialize some game variables */
463 	gGameOn = 1;
464 	gPaused = 0;
465 	gWave = gStartLevel - 1;
466 	for ( i=gNumPlayers; i--; )
467 		gPlayers[i]->NewGame(gStartLives);
468 	gLastStar = STAR_DELAY;
469 	gLastDrawn = 0L;
470 	gNumSprites = 0;
471 
472 	NextWave();
473 
474 	/* Play the game, dammit! */
475 	while ( (RunFrame() > 0) && gGameOn )
476 		DoHouseKeeping();
477 
478 /* -- Do the game over stuff */
479 
480 	DoGameOver();
481 	screen->ShowCursor();
482 	delete geneva;
483 }	/* -- NewGame */
484 
485 
486 /* ----------------------------------------------------------------- */
487 /* -- Do some housekeeping! */
488 
DoHouseKeeping(void)489 static void DoHouseKeeping(void)
490 {
491 	/* Don't do anything if we're paused */
492 	if ( gPaused ) {
493 		/* Give up the CPU for a frame duration */
494 		Delay(FRAME_DELAY);
495 		return;
496 	}
497 
498 #ifdef MOVIE_SUPPORT
499 	if ( gMovie )
500 		win->ScreenDump("MovieFrame", &gMovieRect);
501 #endif
502 	/* -- Maybe throw a multiplier up on the screen */
503 	if (gMultiplierShown && (--gMultiplierShown == 0) )
504 		MakeMultiplier();
505 
506 	/* -- Maybe throw a prize(!) up on the screen */
507 	if (gPrizeShown && (--gPrizeShown == 0) )
508 		MakePrize();
509 
510 	/* -- Maybe throw a bonus up on the screen */
511 	if (gBonusShown && (--gBonusShown == 0) )
512 		MakeBonus();
513 
514 	/* -- Maybe make a nasty enemy fighter? */
515 	if (gWhenEnemy && (--gWhenEnemy == 0) )
516 		MakeEnemy();
517 
518 	/* -- Maybe create a transcenfugal vortex */
519 	if (gWhenGrav && (--gWhenGrav == 0) )
520 		MakeGravity();
521 
522 	/* -- Maybe create a recified space vehicle */
523 	if (gWhenDamaged && (--gWhenDamaged == 0) )
524 		MakeDamagedShip();
525 
526 	/* -- Maybe create a autonominous tracking device */
527 	if (gWhenHoming && (--gWhenHoming == 0) )
528 		MakeHoming();
529 
530 	/* -- Maybe make a supercranial destruction thang */
531 	if (gWhenNova && (--gWhenNova == 0) )
532 		MakeNova();
533 
534 	/* -- Maybe create a new star ? */
535 	if ( --gLastStar == 0 ) {
536 		gLastStar = STAR_DELAY;
537 		TwinkleStars();
538 	}
539 
540 	/* -- Time for the next wave? */
541 	if (gNumRocks == 0) {
542 		if ( gWhenDone == 0 )
543 			gWhenDone = DEAD_DELAY;
544 		else if ( --gWhenDone == 0 )
545 			NextWave();
546 	}
547 
548 	/* -- Housekeping */
549 	DrawStatus(false, false);
550 }	/* -- DoHouseKeeping */
551 
552 
553 /* ----------------------------------------------------------------- */
554 /* -- Start the next wave! */
555 
NextWave(void)556 static void NextWave(void)
557 {
558 	int	index, x, y;
559 	int	NewRoids;
560 	short	temp;
561 
562 	gEnemySprite = NULL;
563 
564 	/* -- Initialize some variables */
565 	gDisplayed = gOurPlayer;
566 	gNumRocks = 0;
567 	gShakeTime = 0;
568 	gFreezeTime = 0;
569 
570 	if (gWave != (gStartLevel - 1))
571 		DoBonus();
572 
573 	gWave++;
574 
575 	/* See about the Multiplier */
576 	if ( FastRandom(2) )
577 		gMultiplierShown = ((FastRandom(30) * 60)/FRAME_DELAY);
578 	else
579 		gMultiplierShown = 0;
580 
581 	/* See about the Prize */
582 	if ( FastRandom(2) )
583 		gPrizeShown = ((FastRandom(30) * 60)/FRAME_DELAY);
584 	else
585 		gPrizeShown = 0;
586 
587 	/* See about the Bonus */
588 	if ( FastRandom(2) )
589 		gBonusShown = ((FastRandom(30) * 60)/FRAME_DELAY);
590 	else
591 		gBonusShown = 0;
592 
593 	/* See about the Gravity */
594 	if (FastRandom(10 + gWave) > 11)
595 		gWhenGrav = ((FastRandom(30) * 60)/FRAME_DELAY);
596 	else
597 		gWhenGrav = 0;
598 
599 	/* See about the Nova */
600 	if (FastRandom(10 + gWave) > 13)
601 		gWhenNova = ((FastRandom(30) * 60)/FRAME_DELAY);
602 	else
603 		gWhenNova = 0;
604 
605 	/* See about the Enemy */
606 	if (FastRandom(3) == 0)
607 		gWhenEnemy = ((FastRandom(30) * 60)/FRAME_DELAY);
608 	else
609 		gWhenEnemy = 0;
610 
611 	/* See about the Damaged Ship */
612 	if (FastRandom(10) == 0)
613 		gWhenDamaged = ((FastRandom(60) * 60L)/FRAME_DELAY);
614 	else
615 		gWhenDamaged = 0;
616 
617 	/* See about the Homing Mine */
618 	if (FastRandom(10 + gWave) > 12)
619 		gWhenHoming = ((FastRandom(60) * 60L)/FRAME_DELAY);
620 	else
621 		gWhenHoming = 0;
622 
623 	temp = gWave / 4;
624 	if (temp < 1)
625 		temp = 1;
626 
627 	NewRoids = FastRandom(temp) + (gWave / 5) + 3;
628 
629 	/* -- Black the screen out and draw the wave */
630 	screen->Clear();
631 
632 	/* -- Kill any existing sprites */
633 	while (gNumSprites > 0)
634 		delete gSprites[gNumSprites-1];
635 
636 	/* -- Initialize some variables */
637 	gLastDrawn = 0L;
638 	gBoomDelay = (60/FRAME_DELAY);
639 	gNextBoom = gBoomDelay;
640 	gBoomPhase = 0;
641 	gWhenDone = 0;
642 
643 	/* -- Create the ship's sprite */
644 	for ( index=gNumPlayers; index--; )
645 		gPlayers[index]->NewWave();
646 	DrawStatus(true, false);
647 	screen->Update();
648 
649 	/* -- Create some asteroids */
650 	for (index = 0; index < NewRoids; index++) {
651 		int	randval;
652 
653 		x = FastRandom(SCREEN_WIDTH) * SCALE_FACTOR;
654 		y = 0;
655 
656 		randval = FastRandom(10);
657 
658 		/* -- See what kind of asteroid to make */
659 		if (randval == 0)
660 			MakeSteelRoid(x, y);
661 		else
662 			MakeLargeRock(x, y);
663 	}
664 
665 	/* -- Create the star field */
666 	screen->FocusBG();
667 	for ( index=0; index<MAX_STARS; ++index ) {
668 		screen->DrawPoint(gTheStars[index]->xCoord,
669 			gTheStars[index]->yCoord, gTheStars[index]->color);
670 	}
671 	screen->Update(1);
672 	screen->FocusFG();
673 	screen->Fade();
674 }	/* -- NextWave */
675 
676 /* ----------------------------------------------------------------- */
677 /* -- Do the game over display */
678 
679 struct FinalScore {
680 	int Player;
681 	int Score;
682 	int Frags;
683 };
684 
cmp_byscore(const void * A,const void * B)685 static int cmp_byscore(const void *A, const void *B)
686 {
687 	return(((struct FinalScore *)B)->Score-((struct FinalScore *)A)->Score);
688 }
cmp_byfrags(const void * A,const void * B)689 static int cmp_byfrags(const void *A, const void *B)
690 {
691 	return(((struct FinalScore *)B)->Frags-((struct FinalScore *)A)->Frags);
692 }
693 
DoGameOver(void)694 static void DoGameOver(void)
695 {
696 	SDL_Event event;
697 	SDL_Surface *gameover;
698 	MFont *newyork;
699 	int newyork_height, w, x;
700 	int which = -1, i;
701 	char handle[20];
702 	Uint8 key;
703 	int chars_in_handle = 0;
704 	Bool done = false;
705 
706 	/* Get the final scoring */
707 	struct FinalScore *final = new struct FinalScore[gNumPlayers];
708 	for ( i=0; i<gNumPlayers; ++i ) {
709 		final[i].Player = i+1;
710 		final[i].Score = gPlayers[i]->GetScore();
711 		final[i].Frags = gPlayers[i]->GetFrags();
712 	}
713 #ifndef macintosh
714 	if ( gDeathMatch )
715 		qsort(final,gNumPlayers,sizeof(struct FinalScore),cmp_byfrags);
716 	else
717 		qsort(final,gNumPlayers,sizeof(struct FinalScore),cmp_byscore);
718 #endif
719 
720 	screen->Fade();
721 	sound->HaltSound();
722 
723 	/* -- Kill any existing sprites */
724 	while (gNumSprites > 0)
725 		delete gSprites[gNumSprites-1];
726 
727 	/* -- Clear the screen */
728 	screen->FillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, ourBlack);
729 
730 	/* -- Draw the game over picture */
731 	gameover = Load_Title(screen, 128);
732 	if ( gameover == NULL ) {
733 		error("Can't load 'gameover' title!\n");
734 		exit(255);
735 	}
736 	screen->QueueBlit((SCREEN_WIDTH-gameover->w)/2,
737 			((SCREEN_HEIGHT-gameover->h)/2)-80, gameover, NOCLIP);
738 	screen->FreeImage(gameover);
739 
740 	/* Show the player ranking */
741 	if ( gNumPlayers > 1 ) {
742 		if ( (newyork = fontserv->NewFont("New York", 18)) == NULL ) {
743                         error("Can't use New York font! -- Exiting.\n");
744                         exit(255);
745                 }
746 		newyork_height = fontserv->TextHeight(newyork);
747 		for ( i=0; i<gNumPlayers; ++i ) {
748 			char buffer[BUFSIZ], num1[12], num2[12];
749 
750 			snprintf(num1, sizeof(num1), "%7.1d", final[i].Score);
751 			snprintf(num2, sizeof(num2), "%3.1d", final[i].Frags);
752 			snprintf(buffer, sizeof(buffer),
753 				 "Player %d: %-.7s Points, %-.3s Frags",
754 				 final[i].Player, num1, num2);
755 			DrawText(160, 380+i*newyork_height, buffer,
756 				newyork, STYLE_NORM, 30000>>8, 30000>>8, 0xFF);
757 		}
758 		delete newyork;
759 	}
760 	screen->Update();
761 
762 	/* -- Play the game over sound */
763 	sound->PlaySound(gGameOver, 5);
764 	screen->Fade();
765 
766 	while( sound->Playing() )
767 		Delay(SOUND_DELAY);
768 
769 	/* -- See if they got a high score */
770 	LoadScores();
771 	for ( i = 0; i<10; ++i ) {
772 		if ( OurShip->GetScore() > hScores[i].score ) {
773 			which = i;
774 			break;
775 		}
776 	}
777 
778 	/* -- They got a high score! */
779 	gLastHigh = which;
780 
781 	if ((which != -1) && (gStartLevel == 1) && (gStartLives == 3) &&
782 					(gNumPlayers == 1) && !gDeathMatch ) {
783 		sound->PlaySound(gBonusShot, 5);
784 		for ( i = 8; i >= which ; --i ) {
785 			hScores[i + 1].score = hScores[i].score;
786 			hScores[i + 1].wave = hScores[i].wave;
787 			strcpy(hScores[i+1].name, hScores[i].name);
788 		}
789 
790 		/* -- Draw the "Enter your name" string */
791 		if ( (newyork = fontserv->NewFont("New York", 18)) == NULL ) {
792                         error("Can't use New York font! -- Exiting.\n");
793                         exit(255);
794                 }
795 		newyork_height = fontserv->TextHeight(newyork);
796 		x = (SCREEN_WIDTH-(fontserv->TextWidth("Enter your name: ",
797 						newyork, STYLE_NORM)*2))/2;
798 		x += DrawText(x, 300, "Enter your name: ",
799 				newyork, STYLE_NORM, 30000>>8, 30000>>8, 0xFF);
800 		screen->Update();
801 
802 		/* -- Let them enter their name */
803 		w = 0;
804 		chars_in_handle = 0;
805 
806 		while ( screen->PollEvent(&event) ) /* Loop, flushing events */;
807 		SDL_EnableUNICODE(1);
808 		while ( !done ) {
809 			screen->WaitEvent(&event);
810 
811 			/* -- Handle key down's (no UNICODE support) */
812 			if ( event.type == SDL_KEYDOWN ) {
813 				key = (Uint8)event.key.keysym.unicode;
814 				switch ( key  ) {
815 					case '\0':	// Ignore NUL char
816 					case '\033':	// Ignore ESC char
817 					case '\t':	// Ignore TAB too.
818 						continue;
819 					case '\003':
820 					case '\r':
821 					case '\n':
822 						done = true;
823 						continue;
824 					case 127:
825 					case '\b':
826 						if ( chars_in_handle ) {
827 							sound->PlaySound(gExplosionSound, 5);
828 							--chars_in_handle;
829 						}
830 						break;
831 					default:
832 						if ( chars_in_handle < 15 ) {
833 							sound->PlaySound(gShotSound, 5);
834 							handle[chars_in_handle++] = (char)key;
835 						} else
836 							sound->PlaySound(gBonk, 5);
837 						break;
838 				}
839 				screen->FillRect(x, 300-newyork_height+2,
840 						w, newyork_height, ourBlack);
841 
842 				handle[chars_in_handle] = '\0';
843 				w = DrawText(x, 300, handle,
844 					newyork, STYLE_NORM, 0xFF, 0xFF, 0xFF);
845 				screen->Update();
846 			}
847 		}
848 		delete newyork;
849 		SDL_EnableUNICODE(0);
850 
851 		/* In case the user just pressed <Return> */
852 		handle[chars_in_handle] = '\0';
853 
854 		hScores[which].wave = gWave;
855 		hScores[which].score = OurShip->GetScore();
856 		strcpy(hScores[which].name, handle);
857 
858 		sound->HaltSound();
859 		sound->PlaySound(gGotPrize, 6);
860 		if ( gNetScores )	// All time high!
861 			RegisterHighScore(hScores[which]);
862 		else
863 			SaveScores();
864 	} else
865 	if ( gNumPlayers > 1 )	/* Let them watch their ranking */
866 		SDL_Delay(3000);
867 
868 	while ( sound->Playing() )
869 		Delay(SOUND_DELAY);
870 	HandleEvents(0);
871 
872 	screen->Fade();
873 	gUpdateBuffer = true;
874 }	/* -- DoGameOver */
875 
876 
877 /* ----------------------------------------------------------------- */
878 /* -- Do the bonus display */
879 
DoBonus(void)880 static void DoBonus(void)
881 {
882 	int i, x, sw, xs, xt;
883 	int bonus_width;
884 	int score_width;
885 	char numbuf[128];
886 
887 	DrawStatus(false, true);
888 	screen->Update();
889 
890 	/* -- Now do the bonus */
891 	sound->HaltSound();
892 	sound->PlaySound(gRiff, 6);
893 
894 	/* Fade out */
895 	screen->Fade();
896 
897 	/* -- Clear the screen */
898 	screen->FillRect(0, 0, SCREEN_WIDTH, gStatusLine-1, ourBlack);
899 
900 
901 	/* -- Draw the wave completed message */
902 	snprintf(numbuf, sizeof(numbuf), "Wave %d completed.", gWave);
903 	sw = fontserv->TextWidth(numbuf, geneva, STYLE_BOLD);
904 	x = (SCREEN_WIDTH - sw) / 2;
905 	DrawText(x,  150, numbuf, geneva, STYLE_BOLD, 0xFF, 0xFF, 0x00);
906 
907 	/* -- Draw the bonus */
908 	sw = fontserv->TextWidth("Bonus Score:     ", geneva, STYLE_BOLD);
909 	x = ((SCREEN_WIDTH - sw) / 2) - 20;
910 	DrawText(x, 200, "Bonus Score:     ", geneva, STYLE_BOLD,
911 						30000>>8, 30000>>8, 0xFF);
912 	xt = x+sw;
913 
914 	/* -- Draw the score */
915 	sw = fontserv->TextWidth("Score:     ", geneva, STYLE_BOLD);
916 	x = ((SCREEN_WIDTH - sw) / 2) - 3;
917 	DrawText(x, 220, "Score:     ", geneva, STYLE_BOLD,
918 						30000>>8, 30000>>8, 0xFF);
919 	xs = x+sw;
920 	screen->Update();
921 
922 	/* Fade in */
923 	screen->Fade();
924 	while ( sound->Playing() )
925 		Delay(SOUND_DELAY);
926 
927 	/* -- Count the score down */
928 	x = xs;
929 
930 	OBJ_LOOP(i, gNumPlayers) {
931 		if ( i != gOurPlayer ) {
932 			gPlayers[i]->MultBonus();
933 			continue;
934 		}
935 
936 		if (OurShip->GetBonusMult() != 1) {
937 			SDL_Surface *sprite;
938 
939 			snprintf(numbuf, sizeof(numbuf), "%-5.1d", OurShip->GetBonus());
940 			DrawText(x, 200, numbuf, geneva, STYLE_BOLD,
941 							0xFF, 0xFF, 0xFF);
942 			x += 75;
943 			OurShip->MultBonus();
944 			Delay(SOUND_DELAY);
945 			sound->PlaySound(gMultiplier, 5);
946 			sprite = gMult[OurShip->GetBonusMult()-2]->sprite[0];
947 			screen->QueueBlit(xs+34, 180, sprite);
948 			screen->Update();
949 			Delay(60);
950 		}
951 	}
952 	Delay(SOUND_DELAY);
953 	sound->PlaySound(gFunk, 5);
954 
955 	snprintf(numbuf, sizeof(numbuf), "%-5.1d", OurShip->GetBonus());
956 	bonus_width = DrawText(x, 200, numbuf, geneva, STYLE_BOLD,
957 							0xFF, 0xFF, 0xFF);
958 	snprintf(numbuf, sizeof(numbuf), "%-5.1d", OurShip->GetScore());
959 	score_width = DrawText(xt, 220, numbuf, geneva, STYLE_BOLD,
960 							0xFF, 0xFF, 0xFF);
961 	screen->Update();
962 	Delay(60);
963 
964 	/* -- Praise them or taunt them as the case may be */
965 	if (OurShip->GetBonus() == 0) {
966 		Delay(SOUND_DELAY);
967 		sound->PlaySound(gNoBonus, 5);
968 	}
969 	if (OurShip->GetBonus() > 10000) {
970 		Delay(SOUND_DELAY);
971 		sound->PlaySound(gPrettyGood, 5);
972 	}
973 	while ( sound->Playing() )
974 		Delay(SOUND_DELAY);
975 
976 	/* -- Count the score down */
977 	OBJ_LOOP(i, gNumPlayers) {
978 		if ( i != gOurPlayer ) {
979 			while ( gPlayers[i]->GetBonus() > 500 ) {
980 				gPlayers[i]->IncrScore(500);
981 				gPlayers[i]->IncrBonus(-500);
982 			}
983 			continue;
984 		}
985 
986 		while (OurShip->GetBonus() > 0) {
987 			while ( sound->Playing() )
988 				Delay(SOUND_DELAY);
989 
990 			sound->PlaySound(gBonk, 5);
991 			if ( OurShip->GetBonus() >= 500 ) {
992 				OurShip->IncrScore(500);
993 				OurShip->IncrBonus(-500);
994 			} else {
995 				OurShip->IncrScore(OurShip->GetBonus());
996 				OurShip->IncrBonus(-OurShip->GetBonus());
997 			}
998 
999 			screen->FillRect(x, 200-text_height+2,
1000 					bonus_width, text_height, ourBlack);
1001 			snprintf(numbuf, sizeof(numbuf), "%-5.1d", OurShip->GetBonus());
1002 			bonus_width = DrawText(x, 200, numbuf,
1003 					geneva, STYLE_BOLD, 0xFF, 0xFF, 0xFF);
1004 			screen->FillRect(xt, 220-text_height+2,
1005 					score_width, text_height, ourBlack);
1006 			snprintf(numbuf, sizeof(numbuf), "%-5.1d", OurShip->GetScore());
1007 			score_width = DrawText(xt, 220, numbuf,
1008 					geneva, STYLE_BOLD, 0xFF, 0xFF, 0xFF);
1009 
1010 			DrawStatus(false, true);
1011 			screen->Update();
1012 		}
1013 	}
1014 	while ( sound->Playing() )
1015 		Delay(SOUND_DELAY);
1016 	HandleEvents(10);
1017 
1018 	/* -- Draw the "next wave" message */
1019 	snprintf(numbuf, sizeof(numbuf), "Prepare for Wave %d...", gWave+1);
1020 	sw = fontserv->TextWidth(numbuf, geneva, STYLE_BOLD);
1021 	x = (SCREEN_WIDTH - sw)/2;
1022 	DrawText(x, 259, numbuf, geneva, STYLE_BOLD, 0xFF, 0xFF, 0x00);
1023 	screen->Update();
1024 	HandleEvents(100);
1025 
1026 	screen->Fade();
1027 }	/* -- DoBonus */
1028 
1029 
1030 /* ----------------------------------------------------------------- */
1031 /* -- Flash the stars on the screen */
1032 
TwinkleStars(void)1033 static void TwinkleStars(void)
1034 {
1035 	int theStar;
1036 
1037 	theStar = FastRandom(MAX_STARS);
1038 
1039 	/* -- Draw the star */
1040 	screen->FocusBG();
1041 	screen->DrawPoint(gTheStars[theStar]->xCoord,
1042 					gTheStars[theStar]->yCoord, ourBlack);
1043 	SetStar(theStar);
1044 	screen->DrawPoint(gTheStars[theStar]->xCoord,
1045 			gTheStars[theStar]->yCoord, gTheStars[theStar]->color);
1046 	screen->Update(1);
1047 	screen->FocusFG();
1048 }	/* -- TwinkleStars */
1049 
1050