From ccffdae9fdca7736f7e966b0cb893a165fcdc75a Mon Sep 17 00:00:00 2001
From: Allanis <allanis@saracraft.net>
Date: Wed, 20 Mar 2013 20:23:39 +0000
Subject: [PATCH] [Add] Player death with short cinematic.

---
 src/input.c  |  3 ++-
 src/menu.c   | 38 ++++++++++++++++++++++++++++-----
 src/menu.h   |  3 ++-
 src/pilot.c  | 26 +++++++++++++++--------
 src/player.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/player.h |  1 +
 src/space.c  | 14 +++++++++----
 7 files changed, 124 insertions(+), 20 deletions(-)

diff --git a/src/input.c b/src/input.c
index aafb3d3..c7a4eff 100644
--- a/src/input.c
+++ b/src/input.c
@@ -256,9 +256,10 @@ static void input_key(int keynum, double value, int abs) {
   }
 	// Show pilot information.
 	else if(KEY("info") && NOHYP()) {
-		if(value == KEY_PRESS) info_menu();
+		if(value == KEY_PRESS) menu_info();
 	}
 }
+#undef KEY
 
 // --Events--
 
diff --git a/src/menu.c b/src/menu.c
index 23905b7..93a7552 100644
--- a/src/menu.c
+++ b/src/menu.c
@@ -19,11 +19,15 @@
 #define OUTFITS_WIDTH  	400
 #define OUTFITS_HEIGHT 	200
 
+#define DEATH_WIDTH			120
+#define DEATH_HEIGHT		160
+
 #define BUTTON_WIDTH		80
 #define BUTTON_HEIGHT		30
 
 #define MENU_SMALL				(1<<0)
 #define MENU_INFO					(1<<1)
+#define MENU_DEATH				(1<<2)
 #define menu_isOpen(f)		(menu_open  & (f))
 #define menu_Open(f)			(menu_open |= (f))
 #define menu_Close(f)			(menu_open ^= (f))
@@ -33,14 +37,16 @@ static int menu_open = 0;
 static void menu_small_close(char* str);
 static void edit_options(void);
 static void exit_game(void);
-static void info_menu_close(char* str);
+static void menu_info_close(char* str);
 static void info_outfits_menu(char* str);
 static void info_outfits_menu_close(char* str);
+static void menu_death_respawn(char* str);
 
 // Ze ingame menu.
 // Small ingame menu.
 void menu_small(void) {
-  if(menu_isOpen(MENU_SMALL)) return; // It's already open..
+  if(menu_isOpen(MENU_SMALL) || menu_isOpen(MENU_DEATH))
+		return; // It's already open..
 	pause();
 
   unsigned int wid;
@@ -82,7 +88,7 @@ static void exit_game(void) {
 }
 
 // Info menu.
-void info_menu(void) {
+void menu_info(void) {
 	if(menu_isOpen(MENU_INFO)) return;
 	pause();
 
@@ -120,13 +126,13 @@ void info_menu(void) {
 				"btnMissions", "Missions", NULL);
 	window_addButton(wid, -20, 20,
 				BUTTON_WIDTH, BUTTON_HEIGHT,
-				"btnClose", "Close", info_menu_close);
+				"btnClose", "Close", menu_info_close);
 	
 
 	menu_Open(MENU_INFO);
 }
 
-static void info_menu_close(char* str) {
+static void menu_info_close(char* str) {
 	if(strcmp(str, "btnClose")==0)
 		window_destroy(window_get("Info"));
 	
@@ -169,3 +175,25 @@ static void info_outfits_menu_close(char* str) {
 	window_destroy(window_get(str+5)); // closeFoo -> Foo.
 }
 
+// Pilot dead.
+void menu_death(void) {
+	unsigned int wid;
+	wid = window_create("Death", -1, -1, DEATH_WIDTH, DEATH_HEIGHT);
+
+	window_addButton(wid, 20, 20 + BUTTON_HEIGHT + 20,
+				BUTTON_WIDTH, BUTTON_HEIGHT,
+				"btnNew", "New Game", menu_death_respawn);
+	window_addButton(wid, 20, 20, BUTTON_WIDTH, BUTTON_HEIGHT,
+				"btnExit", "Exit", (void(*)(char*)) exit_game);
+
+	menu_Open(MENU_DEATH);
+}
+
+static void menu_death_respawn(char* str) {
+	(void)str;
+	window_destroy(window_get("Death"));
+	menu_Close(MENU_DEATH);
+
+	player_new();
+}
+
diff --git a/src/menu.h b/src/menu.h
index a9c8746..1231040 100644
--- a/src/menu.h
+++ b/src/menu.h
@@ -2,5 +2,6 @@
 
 void menu_small(void);
 
-void info_menu(void);
+void menu_info(void);
+void menu_deah(void);
 
diff --git a/src/pilot.c b/src/pilot.c
index f6f8cb2..41bb6fc 100644
--- a/src/pilot.c
+++ b/src/pilot.c
@@ -32,13 +32,17 @@ static Fleet* fleet_stack = NULL;
 static int nfleets = 0;
 
 // External.
-extern void ai_destroy(Pilot* p); // Ai.
-extern void ai_think(Pilot* pilot); // Ai.c
-extern void ai_create(Pilot* pilot); // ai.c
-extern void player_think(Pilot* pilot); // Player.c
-extern void player_brokeHyperspace(void); // Player.c
-extern double player_faceHyperspace(void); // Player.c
-extern int gui_load(const char* name); // Player.c
+// AI.
+extern void ai_destroy(Pilot* p);
+extern void ai_think(Pilot* pilot);
+extern void ai_create(Pilot* pilot);
+// Player.
+extern void player_think(Pilot* pilot);
+extern void player_brokeHyperspace(void);
+extern double player_faceHyperspace(void);
+extern void player_dead(void);
+extern void player_destroyed(void);
+extern int gui_load(const char* name);
 // Internal.
 static void pilot_shootWeapon(Pilot* p, PilotOutfit* w, const unsigned int t);
 static void pilot_update(Pilot* pilot, const double dt);
@@ -244,6 +248,7 @@ void pilot_hit(Pilot* p, const Solid* w, const unsigned int shooter,
 
 void pilot_dead(Pilot* p) {
 	// Basically just set the timers..
+	if(p->id == PLAYER_ID) player_dead();
 	p->timer[0] = SDL_GetTicks(); // No need for AI anymore.
 	p->ptimer = p->timer[0] + 1000 + (unsigned int)sqrt(10*p->armour_max*p->shield_max);
 	p->timer[1] = p->timer[0]; // Explosion timer.
@@ -305,10 +310,12 @@ static void pilot_update(Pilot* pilot, const double dt) {
 	unsigned int t;
 	double px, py, vx, vy;
 
-	if((pilot != player) && pilot_isFlag(pilot, PILOT_DEAD)) {
+	if(pilot_isFlag(pilot, PILOT_DEAD)) {
 		t = SDL_GetTicks();
 
 		if(t > pilot->ptimer) {
+			if(pilot->id == PLAYER_ID)
+				player_destroyed();
 			pilot_setFlag(pilot, PILOT_DELETE); // It'll get deleted next frame.
 			return;
 		}
@@ -338,7 +345,7 @@ static void pilot_update(Pilot* pilot, const double dt) {
 				spfx_add(spfx_get("ExpS"), px, py, vx, vy, SPFX_LAYER_BACK);
 		}
 	}
-	else if((pilot != player) && (pilot->armour <= 0.)) // PWNED!
+	else if(pilot->armour <= 0.) // PWNED!
 		pilot_dead(pilot);
 
 	// Pupose fallthrough to get the movement similar to disabled.
@@ -733,6 +740,7 @@ unsigned int pilot_create(Ship* ship, char* name, Faction* faction,
 
 // Frees and cleans up a pilot.
 static void pilot_free(Pilot* p) {
+	if(player == p) player = NULL;
   solid_free(p->solid);
   if(p->outfits) free(p->outfits);
   free(p->name);
diff --git a/src/player.c b/src/player.c
index a138452..a3ed44c 100644
--- a/src/player.c
+++ b/src/player.c
@@ -13,6 +13,8 @@
 #include "sound.h"
 #include "economy.h"
 #include "pause.h"
+#include "menu.h"
+#include "toolkit.h"
 #include "player.h"
 
 #define XML_GUI_ID    "GUIs" // XML section identifier.
@@ -39,6 +41,9 @@ unsigned int player_target = PLAYER_ID; // Targetted pilot.
 // Internal
 int planet_target			= -1; // Targetted planet.
 int hyperspace_target = -1; // Target hyperspace route.
+// For death etc.
+static unsigned int player_timer = 0;
+static Vec2 player_cam;
 
 // Pilot stuff for GUI.
 extern Pilot** pilot_stack;
@@ -111,6 +116,9 @@ static void rect_parse(const xmlNodePtr parent,
 static int gui_parse(const xmlNodePtr parent, const char* name);
 static void gui_renderPilot(const Pilot* p);
 static void gui_renderBar(const glColour* c, const Rect* r, const double w);
+// Externed.
+void player_dead(void);
+void player_destroyed(void);
 
 // Create a new player.
 void player_new(void) {
@@ -169,6 +177,9 @@ void player_new(void) {
   free(buf);
   xmlCleanupParser();
 
+	// In case we are respawning.
+	player_rmFlag(PLAYER_DESTROYED);
+
   // Money.
   player_credits = RNG(l, h);
 
@@ -286,6 +297,9 @@ void player_renderBG(void) {
   glColour* c;
   Planet* planet;
 
+	if(player_isFlag(PLAYER_DESTROYED) ||
+				pilot_isFlag(player, PILOT_DEAD)) return;
+
   if(planet_target >= 0) {
     planet = &cur_system->planets[planet_target];
 
@@ -316,6 +330,34 @@ void player_render(void) {
   glColour* c;
   glFont* f;
 
+	if(player_isFlag(PLAYER_DESTROYED) || pilot_isFlag(player, PILOT_DEAD)) {
+		if(player_isFlag(PLAYER_DESTROYED)) {
+			if(!toolkit && (SDL_GetTicks() > player_timer))
+				menu_death();
+		} else
+			pilot_render(player);
+		
+		// Fancy cinematic scene borders.
+		glMatrixMode(GL_MODELVIEW);
+		glPushMatrix(); // Translation matrix.
+		glTranslated(x-(double)gl_screen.w/2., y-(double)gl_screen.h/2., 0);
+
+		COLOUR(cBlack);
+		glBegin(GL_QUADS);
+			glVertex2d(0., 						0.);
+			glVertex2d(0., 						gl_screen.h*0.2);
+			glVertex2d(gl_screen.w, 	gl_screen.h*0.2);
+			glVertex2d(gl_screen.w,		0.);
+			glVertex2d(0.,						gl_screen.h);
+			glVertex2d(gl_screen.w,		gl_screen.h);
+			glVertex2d(0.,						gl_screen.h*0.8);
+		glEnd();
+
+		glPopMatrix(); // Translation matrix.
+
+		return;
+	}
+
   // Render the player target graphics.
   if(player_target != PLAYER_ID) p = pilot_get(player_target);
 	else p = NULL;
@@ -880,6 +922,9 @@ void gui_free(void) {
 // Used in pilot.c
 // Basically uses keyboard input instead of AI input.
 void player_think(Pilot* player) {
+	// Last I checked, the dead didn't think..
+	if(pilot_isFlag(player, PILOT_DEAD)) return;
+
   // PLAYER_FACE will take over navigation.
 	if(player_isFlag(PLAYER_FACE)) {
 		if(player_target != PLAYER_ID)
@@ -1128,3 +1173,17 @@ void player_screenshot(void) {
   gl_screenshot(filename);
 }
 
+// Player go pwned.
+void player_dead(void) {
+	gui_xoff = 0.;
+	gui_yoff = 0.;
+}
+
+// Player blew up in a nice fireball.
+void player_destroyed(void) {
+	vectcpy(&player_cam, &player->solid->pos);
+	gl_bindCamera(&player_cam);
+	player_setFlag(PLAYER_DESTROYED);
+	player_timer = SDL_GetTicks() + 2000;
+}
+
diff --git a/src/player.h b/src/player.h
index 163b817..95ce9ff 100644
--- a/src/player.h
+++ b/src/player.h
@@ -6,6 +6,7 @@
 #define PLAYER_TURN_RIGHT 	(1<<1)    // Player is turning right.
 #define PLAYER_REVERSE    	(1<<2)    // Player is facint opposite vel.
 #define PLAYER_AFTERBURNER	(1<<3)		// Player is burning it up.
+#define PLAYER_DESTROYED		(1<<9)		// Player goes BOOM!
 #define PLAYER_FACE       	(1<<10)   // Player is facing target.
 #define PLAYER_PRIMARY    	(1<<11)   // Player is shooting primary weapon.
 #define PLAYER_SECONDARY  	(1<<12)   // Player is shooting secondary weapon.
diff --git a/src/space.c b/src/space.c
index 3293e49..842fc0f 100644
--- a/src/space.c
+++ b/src/space.c
@@ -649,8 +649,12 @@ void space_render(double dt) {
 	glTranslated(-(double)gl_screen.w/2., -(double)gl_screen.h/2., 0);
 
 	t = SDL_GetTicks();
-	timer = player->ptimer - HYPERSPACE_STARS_BLUR;
-	if(pilot_isFlag(player, PILOT_HYPERSPACE) && !paused && (timer < t)) {
+	if(!player_isFlag(PLAYER_DESTROYED) &&
+				pilot_isFlag(player, PILOT_HYPERSPACE) && // Hyperspace fancy effect.
+				!paused && (player->ptimer-HYPERSPACE_STARS_BLUR < t)) {
+
+		timer = player->ptimer - HYPERSPACE_STARS_BLUR;
+
 		// Fancy hyperspace effects.
 		glShadeModel(GL_SMOOTH);
 
@@ -677,8 +681,10 @@ void space_render(double dt) {
 		for(i = 0; i < nstars; i++) {
 			if(!paused && !toolkit) {
 				// Update position.
-				stars[i].x -= VX(player->solid->vel)/(13.-10.*stars[i].brightness)*dt;
-      	stars[i].y -= VY(player->solid->vel)/(13.-10.*stars[i].brightness)*dt;
+				if(!player_isFlag(PLAYER_DESTROYED)) {
+					stars[i].x -= VX(player->solid->vel)/(13.-10.*stars[i].brightness)*dt;
+      		stars[i].y -= VY(player->solid->vel)/(13.-10.*stars[i].brightness)*dt;
+				}
       	// Scroll those stars bitch!
       	if(stars[i].x > gl_screen.w + STAR_BUF) stars[i].x = -STAR_BUF;
       	else if(stars[i].x < -STAR_BUF) stars[i].x = gl_screen.w + STAR_BUF;