RingRacers/src/k_boss.c
Sally Coolatta 7dfa597c7d SRB2 -> DRRR copyright in src, acs, android folder
Be consistent with toaster's recent changes to copyright
2024-04-05 02:08:23 -04:00

241 lines
6.4 KiB
C

// DR. ROBOTNIK'S RING RACERS
//-----------------------------------------------------------------------------
// Copyright (C) 2024 by Vivian "toastergrl" Grannell
// Copyright (C) 2024 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_ResetBossInfo(void)
See header file for description.
--------------------------------------------------*/
void K_ResetBossInfo(void)
{
Z_Free(bossinfo.enemyname);
Z_Free(bossinfo.subtitle);
memset(&bossinfo, 0, sizeof(struct bossinfo));
bossinfo.barlen = BOSSHEALTHBARLEN;
bossinfo.titlesound = sfx_typri1;
}
/*--------------------------------------------------
void K_BossInfoTicker(void)
See header file for description.
--------------------------------------------------*/
void K_BossInfoTicker(void)
{
UINT8 i;
if (bossinfo.valid == 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;
// Damaged quickly? Make it disappear immediately (making sure to match the flashing).
if ((bossinfo.weakspots[i].spot->hitlag > 0) && (bossinfo.weakspots[i].time > TICRATE/2))
bossinfo.weakspots[i].time = (TICRATE/2) & ~(bossinfo.weakspots[i].time & 1);
// 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 (!(gametyperules & GTR_BOSS))
{
return;
}
bossinfo.valid = true;
if (!leveltime)
{
bossinfo.coolintro = true;
}
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 (bossinfo.valid == false)
return;
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;
if (bossinfo.valid == false)
return;
// 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;
}
}
/*--------------------------------------------------
boolean K_CheckBossIntro(void);
See header file for description.
--------------------------------------------------*/
boolean K_CheckBossIntro(void)
{
if (bossinfo.valid == false)
return false;
return bossinfo.coolintro;
}