/******************************************************************************************
	CRTEST PS   (c) 1999-2001 ISL

	deth.c:
******************************************************************************************/

#include "global.h"
#include "main.h"

#include "enemies.h"
#include "scenics.h"
#include "charactr.h"
#include "dogchase.h"
#include "overlay.h"
#include "help.h"
#include "gametext.h"
#include "map_play.h"
#include "maths.h"
#include "camera.h"
#include "puzzles.h"
#include "inventory.h"
#include "sound.h"
#include "card.h"
#include "deth.h"


static CHARACTER *pKillChar = NULL;
static int fade=255;
static int life=0;
static int startLife = 0;

int death_reason = 0;
int death_message = 0;
int death_lost_item = 0;	// 0 for nothing, -1 for everything, +ve for object number

int deathDying = FALSE;
int deathSkip = FALSE;

VECTOR *pDeathCamPosition;
VECTOR *pDeathCamLookAt;
PSIOBJECT *pDogHead;

#if PALMODE == 1
 #define DEATH_PANEL_Y -120
#else
 #define DEATH_PANEL_Y -100
#endif


char *psHut17Names[4] = {
	"A1_HUT17",
	"A2_HUT17",
	"MARK'S MUM",
	"A4_HUT17"};

void deathDontDie(void)
{
	pKillChar = NULL;
	deathDying = 0;
}

void deathScreenAdd(int b, int g, int r, int transp, int depth)
{
	{
		POLY_F4 *f4;
		BEGINPRIM(f4, POLY_F4);
		setPolyF4(f4);
		f4->x0=f4->x2=0;
		f4->x1=f4->x3=640;
		f4->y0=f4->y1=0;
		f4->y2=f4->y3=480;
		f4->tag = transp;
		setRGB0(f4, r,g,b);
		ENDPRIM(f4, depth, POLY_F4);
	//	f4->code = f4->code | 2;
	}

	{
  //		DR_TPAGE *tp;
  //		BEGINPRIM(tp, DR_TPAGE);
  //		setDrawTPage(tp,1,1,((transp-1)<<5));
  //		ENDPRIM(tp,depth,DR_TPAGE);
	}
}

// Remove stuff from inventory on death...

void deathRespot(int item)
{
	if(item != WIRE_CUTTERS)
	{
		inventoryRemoveItem(item);
		scenicInventoryNotification(item,SCENIC_INVENTORY_RESPOT);
	}

	if(item == TENNIS_RACKET)
	{
		scenicInventoryNotification(BONE,SCENIC_INVENTORY_RESPOT);
	}
}

// When you're killed, drop things from your inventory
// Everything if you're the rats
// One object, with safety checks, when you're the chicken
void deathInventoryMadness()
{
	int yourname;
	int i;
	int p;
	int item;
	int items[6];
	int n_items;

	yourname = pKillChar->pEnemy->readData.nameCRC;

	n_items = 0;
	for(i = 0; i < 6; i++)
	{
		item = currentInv->slot_contents[i];
		for(p = 0; p < n_items; p++)
		{
			if(item == items[p])
				break;
		}
// Note - "6 eggs" will also cause problems if they're stored as individuals
		if(p == n_items && item != WIRE_CUTTERS && item != EMPTY && item != GNOME)	// Gnome added to list at JonW / Jogu's request
		{
			items[n_items] = item;
			n_items++;
		}
	}

#ifdef DEBUG
	DB("Your Death Inventory is...\n");
	for(i = 0; i < n_items; i++)
	{
		DB("  %d\n",items[i]);
	}
#endif

	death_lost_item = 0;


	switch(yourname)
	{
	case CRC_NICK:
	case CRC_FETCHER:
	case CRC_GNOME:

/*
// Respot everything. Removed. All characters now follow the "lost one item" paradigm
// CPW: Swallowed a dictionary, have we Fred? ;)

		for(i = 0; i < n_items; i++)
		{
			DB(" You lost item %d\n",items[i]);

			deathRespot(items[i]);
		}
		death_lost_item = -1;
		break;
*/

	case CRC_GINGER:
	case CRC_ROCKY:
	case CRC_WELLY:
// Respot an item at random
// But not the wirecutters
// And if you lose the tennis racket, respot the bone as well.

		if(n_items != 0)
		{
			if(n_items == 1)
				i = 0;
			else
				i = utilRandomInt(n_items-1);	// Coo, ISL's random routine returns (0....n) INCLUSIVE. How strange!
			deathRespot(items[i]);
			death_lost_item = items[i];
			DB(" You lost item %d, which is inventory no %d\n",i,death_lost_item);
		}
		break;
	}
}

// tbd - make the platform-puzzle state not reset, but do reset things like Mrs T in the eggroom to their original position?

void deathSortOutWhereToGo()
{
	globalDeathOn=0;

	if((pKillChar->pEnemy->readData.nameCRC == CRC_NICK) ||
		(pKillChar->pEnemy->readData.nameCRC == CRC_FETCHER) ||
		(pKillChar->pEnemy->readData.nameCRC == CRC_GNOME) ||
		(levinfo->level_number == LEVNUMBER_A1_DOGCHASE) ||
		(levinfo->level_number == LEVNUMBER_A2_COGCHASE) ||
		(levinfo->level_number == LEVNUMBER_A4_FLYMACHINE))
	{
		strcpy(&mapplay_next_level[0], sLevelName);
		mapplay_next_marker = 0;

		if(levinfo->level_number == LEVNUMBER_A2_COGCHASE)
		{
			mapplay_next_marker = PuzzleVars.variables[5];	// Variable number 5 used for restart
		}
	}
	else
	{
//		strcpy(&mapplay_next_level[0], psHut17Names[levinfoGetAct(-1)-1]);

// New death seq is a respawn at level entry point one
		strcpy(&mapplay_next_level[0], sLevelName);

		if ( (levinfo->level_number == LEVNUMBER_A2_TOOLEXT_D) || (levinfo->level_number == LEVNUMBER_A2_HOUSEXT_D) )
		{
			//if (levinfo->level_number == LEVNUMBER_A2_TOOLEXT_D)
				mapplay_next_marker = 99;	// stops rocky death restart inside fma box
		}
		else
			mapplay_next_marker = level_start_marker;
	}

	DB("NEW LEVEL = %s\n", &mapplay_next_level[0]);
	

//	mapplay_next_marker = 0;
	mapplay_leave_level_flag = 1;
	pKillChar=NULL;
}

void deathKill(CHARACTER *pC, int reason, ENEMY *pE)
{
	deathDying = TRUE;

	if(pKillChar)	// you're already being killed
		return;

	if(!pC)
	{
		pKillChar=characterGetMainCharacter();
		ASSERT(pKillChar);
	}
	else
		pKillChar=pC;


	fade = 255;
// CPW: 	helpOn = 0;
	death_reason = reason;
	death_lost_item = 0;

	gamePlayData->times_captured_this_act++;	// Needed by the splash screen

	switch(death_reason)
	{
		case DEATH_REASON_PERSUIT_DOG_MAUL:
		case DEATH_REASON_SLEEPY_DOG_MAUL:
		case DEATH_REASON_GUARDDOG_SEEN:
			death_message = TEXTSTR_DEATH_DOGGED;
			break;

		case DEATH_REASON_MRST_INLIGHT:
		case DEATH_REASON_MRST_LOOM:
			death_message = TEXTSTR_DEATH_MRS_TWEEDIED;
			break;

		case DEATH_REASON_MRT_LOOM:
		case DEATH_REASON_MRT_SEEN:
			death_message = TEXTSTR_DEATH_MR_TWEEDIED;
			break;

		case DEATH_REASON_HARMFUL_PLATFORM:
		case DEATH_REASON_DEADLY_PLATFORM:
		case DEATH_REASON_FELL_OUT_OF_WORLD:
			death_message = TEXTSTR_DEATH_DEADLY_PLATFORM;
			break;

		default:
			death_message = TEXTSTR_DEATH_GENERIC;
			break;
	}


	if(levinfo->level_number == LEVNUMBER_A2_COGCHASE)
	{
		pKillChar->pEnemy->runFlags|=RUNFLAGS_FORCETOFRONT;

		// CPW: Start death animation
		actorFlushQueue(pKillChar->pEnemy->readData.pActor);
		actorAnimate(pKillChar->pEnemy->readData.pActor, ROCKY_COGDIE, 0, 0, 256, 0, 1024);
		DB("Setting ROCKY animation to ROCKY_COGDIE\n");

		startLife = 60;
		life = startLife;
	}
	else
	{
		if(!pE)
		{
			// Killed by deadly platformness
			deathSortOutWhereToGo();
			deathDying = FALSE;
			return;
		}

		resetFma();
		deathInventoryMadness();
		
		pE->runFlags|=RUNFLAGS_FORCETOFRONT;
		pKillChar->pEnemy->runFlags|=RUNFLAGS_FORCETOFRONT;

		pKillChar->pEnemy->pKilledBy = pE;

		// CPW: tbd  turn radar off

		pDeathCamPosition = &pKillChar->pEnemy->pos;
		pDeathCamLookAt = &pKillChar->pEnemy->pKilledBy->pos;

		pDogHead = pKillChar->pEnemy->pKilledBy->readData.pHead;

		// CPW: turn Ginger off
		pKillChar->pEnemy->runFlags &= ~RUNFLAGS_VISIBLE;

		startLife = 100;
		life = startLife;
	}

	currentInv->selected_item = EMPTY;
	DB("Killing character %p\n", pKillChar);

	sound_XA_Start(TUNE_12_DIES + SOUND_XA_NOLOOP);
}

// Called from the cycle routine
void deathPoll(void)
{
	VECTOR diff, headPos;

	if(pKillChar==NULL)
		return;

/*	fontPrint(font, -230, -116, "DeathCam", 127, 127, 127);

	if(frame & 0x20)
	{
		fontPrint(font, 120, -116, "Recording", 127, 0, 0);
	}
*/

	camVars.specialOveride = TRUE;
	globalDeathOn=1;

	if(levinfo->level_number == LEVNUMBER_A2_COGCHASE)
	{
		// CPW: if player (Rocky) dies in this level, pan the camera around him ...

		static int panAngle = 0;

		COPYVECTOR(&camVars.specialView, &pKillChar->pEnemy->pos);

		camVars.specialPos.vx = rsin(panAngle) /2 ;
		camVars.specialPos.vz = rcos(panAngle) /2;

		camVars.specialPos.vy = pKillChar->pEnemy->pos.vy - 600;	// CPW: A bit above ground

		ADDVECTOR(&camVars.specialPos, &camVars.specialPos, &camVars.specialView);

		panAngle+=32;
	}
	else
	{
		COPYVECTOR(&camVars.specialView, pDeathCamLookAt);
		camVars.specialPos.vy = camVars.specialView.vy;

		camVars.specialView.vy -= 512;

		camVars.specialPos.vx = camVars.specialView.vx + (rsin(pKillChar->pEnemy->pKilledBy->dir + 2048) / 3);
		camVars.specialPos.vz = camVars.specialView.vz + (rcos(pKillChar->pEnemy->pKilledBy->dir + 2048) / 3);

		pKillChar->pEnemy->runFlags &= ~RUNFLAGS_VISIBLE;
	}

	// CPW: DB("Target = %d, %d, %d,    Actual = %d, %d, %d\n", deathCamPosition.vx, deathCamPosition.vy, deathCamPosition.vz,
	// CPW: 													mycamera.vpx, mycamera.vpy, mycamera.vpz);

// CPW: 	if(fade < -1400)

	if(life <= 0)
	{
		if(!XAcheckPlay() || !XAgetStatus())
		{
			deathDying = FALSE;
			deathSortOutWhereToGo();
		}
		else
		{
			fade += 16;
			deathDying = TRUE;
		}
	}
	else
	{
		deathDying = TRUE;
	}

	life--;
	fade-=16;


// CPW: 	DB("pad 0 = %d\n", padData.digital[0]);

	if(deathSkip && (life < (startLife - 20)))
	{
		DB("Skipping death ...\n");
		deathDying = FALSE;
		deathSkip = FALSE;
		deathSortOutWhereToGo();
	}
}


void deathDraw()
{
	TextureType *tex;

	if(pKillChar==NULL)
		return;

	if(fade < 0)
	{
		deathScreenAdd(255, 255, 255, SEMITRANS_SUB, DEATH_FADEPOLY_SORTDEPTH);
	}
	else
	{
		deathScreenAdd(255-fade, 255-fade, 255-fade, SEMITRANS_SUB, DEATH_FADEPOLY_SORTDEPTH);
	}

	fontPrintCentred(font, 0,DEATH_PANEL_Y, TEXTSTR(death_message), 128,128,128);

// Inventory Items Lost...
	switch(death_lost_item)
	{
		case 0:
			// Didn't lose anything
			break;
		case -1:
			fontPrintCentred(font, 0,DEATH_PANEL_Y+10, TEXTSTR(TEXTSTR_DEATH_LOST_ALL), 128,128,128);
// plot the list of sprites?
			break;
		default:
			fontPrintCentred(font, 0,DEATH_PANEL_Y+10, TEXTSTR(TEXTSTR_DEATH_LOST_ONE), 128,128,128);
			fontPrintCentred(font, 140 ,DEATH_PANEL_Y+68, TEXTSTR(TEXTSTR_INVENTORY_ITEM_NOTHING + death_lost_item), 128,128,128);

			tex = objectpics[death_lost_item];

			DB("spr %i = &%8x\n",death_lost_item,tex);
			if(tex)
			{
				overlaySprite(tex, (0 - tex->w/2) + 140, DEATH_PANEL_Y+22, 0,0xff808080);
			}

			break;
	}
}
