// BLANKART
//-----------------------------------------------------------------------------
// Copyright (C) 2018-2022 by Viv "toaster" Grannell
// Copyright (C) 2018-2022 by Kart Krew
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file  k_boss.c
/// \brief Boss battle game logic

#include "k_boss.h"
#include "doomdef.h"
#include "d_player.h"
#include "g_game.h"
#include "p_local.h"
#include "k_kart.h"
#include "s_sound.h"
#include "st_stuff.h"
#include "z_zone.h"

struct bossinfo bossinfo;

/*--------------------------------------------------
	void K_ClearBossInfo(void)

		See header file for description.
--------------------------------------------------*/
void K_ResetBossInfo(void)
{
	Z_Free(bossinfo.enemyname);
	Z_Free(bossinfo.subtitle);
	memset(&bossinfo, 0, sizeof(struct bossinfo));
}

/*--------------------------------------------------
	void K_BossInfoTicker(void)

		See header file for description.
--------------------------------------------------*/
void K_BossInfoTicker(void)
{
	UINT8 i;

	if (bossinfo.boss == false)
		return;

	// Update healthbar data. (only if the hud is visible)
	if (leveltime > (TICRATE/2)+3)
	{
		// Greater than the actual health?
		if (bossinfo.visualbar > bossinfo.healthbar)
		{
			bossinfo.visualbar--;
			// If the boss is dying, start shrinking the healthbar.
			if (bossinfo.visualbar == 0)
				bossinfo.barlen-= 2;
		}
		// Less than the actual health?
		else if (bossinfo.visualbar < bossinfo.healthbar)
			bossinfo.visualbar++;
		// Continue to shrink the healthbar.
		else if (bossinfo.barlen > 1  && bossinfo.barlen < BOSSHEALTHBARLEN)
			bossinfo.barlen -= 2;

		// Jitter timer.
		if (bossinfo.visualbarimpact)
			bossinfo.visualbarimpact--;
	}

	if (bossinfo.doweakspotsound != SPOT_NONE)
	{
		//S_StartSound(NULL, sfx_mbs55); // may change for bump option
		bossinfo.doweakspotsound = SPOT_NONE;
	}

	// Update weakspot data.
	for (i = 0; i < NUMWEAKSPOTS; i++)
	{
		// Clean out invalid references.
		if ((bossinfo.weakspots[i].spot && P_MobjWasRemoved(bossinfo.weakspots[i].spot)))
			P_SetTarget(&bossinfo.weakspots[i].spot, NULL);

		if (bossinfo.weakspots[i].spot == NULL)
			continue;

		// Handle counter.
		if (!bossinfo.weakspots[i].time)
			continue;
		bossinfo.weakspots[i].time--;

		// Get rid of concluded spots.
		if (!bossinfo.weakspots[i].time && !bossinfo.weakspots[i].minimap)
			P_SetTarget(&bossinfo.weakspots[i].spot, NULL);
	}
}

/*--------------------------------------------------
	void K_InitBossHealthBar(const char *enemyname, const char *subtitle, sfxenum_t titlesound, fixed_t pinchmagnitude, UINT8 divisions)

		See header file for description.
--------------------------------------------------*/

void K_InitBossHealthBar(const char *enemyname, const char *subtitle, sfxenum_t titlesound, fixed_t pinchmagnitude, UINT8 divisions)
{
	if (enemyname && enemyname[0])
	{
		Z_Free(bossinfo.enemyname);
		bossinfo.enemyname = Z_StrDup(enemyname);
	}

	if (subtitle && subtitle[0])
	{
		Z_Free(bossinfo.subtitle);
		bossinfo.subtitle = Z_StrDup(subtitle);
	}

	if (titlesound)
	{
		bossinfo.titlesound = titlesound;
	}

	bossinfo.barlen = BOSSHEALTHBARLEN;
	K_UpdateBossHealthBar(FRACUNIT, 0);

	if (pinchmagnitude > FRACUNIT)
		pinchmagnitude = FRACUNIT;
	else if (pinchmagnitude < 0)
		pinchmagnitude = 0;

	bossinfo.healthbarpinch = FixedMul(pinchmagnitude, BOSSHEALTHBARLEN*FRACUNIT)>>FRACBITS;

	// we do this here so we can fudge our working a bit
	if (divisions > 0)
	{
		if (divisions > (BOSSHEALTHBARLEN/2)) // megamanification
		{
			divisions = (BOSSHEALTHBARLEN/2);
		}
		bossinfo.visualdiv = FixedDiv(BOSSHEALTHBARLEN*FRACUNIT, divisions*FRACUNIT);
	}
	else
	{
		bossinfo.visualdiv = 0;
	}
}

/*--------------------------------------------------
	void K_UpdateBossHealthBar(fixed_t magnitude, tic_t jitterlen)

		See header file for description.
--------------------------------------------------*/

void K_UpdateBossHealthBar(fixed_t magnitude, tic_t jitterlen)
{
	if (magnitude > FRACUNIT)
		magnitude = FRACUNIT;
	else if (magnitude < 0)
		magnitude = 0;

	if (jitterlen > bossinfo.visualbarimpact)
		bossinfo.visualbarimpact = jitterlen;
	bossinfo.healthbar = FixedMul(magnitude, BOSSHEALTHBARLEN);
}

/*--------------------------------------------------
	void K_DeclareWeakspot(mobj_t *weakspot, spottype_t spottype, boolean minimap)

		See header file for description.
--------------------------------------------------*/
void K_DeclareWeakspot(mobj_t *spot, spottype_t spottype, UINT16 color, boolean minimap)
{
	UINT8 i;

	// First check whether the spot is already in the list and simply redeclaring weakness (for example, a vulnerable moment in the pattern).
	for (i = 0; i < NUMWEAKSPOTS; i++)
		if (bossinfo.weakspots[i].spot == spot)
			break;

	// If it's not redeclaring, check for an empty spot.
	if (i == NUMWEAKSPOTS)
	{
		for (i = 0; i < NUMWEAKSPOTS; i++)
			if (!bossinfo.weakspots[i].spot || P_MobjWasRemoved(bossinfo.weakspots[i].spot))
				break;
	}

	// If you've crammed up the list with minimap entries (the only ones that will persist), give up.
	if (i == NUMWEAKSPOTS)
		return;

	// OK, now we can slot in the weakspot data...
	P_SetTarget(&bossinfo.weakspots[i].spot, spot);
	bossinfo.weakspots[i].type = spottype;
	bossinfo.weakspots[i].time = WEAKSPOTANIMTIME;
	bossinfo.weakspots[i].color = color;
	bossinfo.weakspots[i].minimap = minimap;

	if (spottype && bossinfo.doweakspotsound != SPOT_WEAK)
	{
		bossinfo.doweakspotsound = spottype;
	}
}
