Drop power-ups when whipped

- Dropped power-ups become paper items (overloaded to
  store power-ups instead of items).
- The dropped power-up stores its remaining duration.
- The power-up can be picked up during any state.
  - If you already have the same kind of power-up, the
    duration is simply extended.
This commit is contained in:
James R 2023-06-27 00:43:55 -07:00
parent a0b0891009
commit 919c669863
10 changed files with 120 additions and 17 deletions

View file

@ -146,6 +146,7 @@ add_executable(SRB2SDL2 MACOSX_BUNDLE WIN32
k_serverstats.c
k_zvote.c
k_mapuser.c
k_powerup.cpp
)
if(SRB2_CONFIG_ENABLE_WEBM_MOVIES)

View file

@ -648,6 +648,7 @@ char sprnames[NUMSPRITES + 1][5] =
"ITMO",
"ITMI",
"ITMN",
"PWRB",
"WANT",
"PBOM", // player bomb

View file

@ -1201,6 +1201,7 @@ typedef enum sprite
SPR_ITMO,
SPR_ITMI,
SPR_ITMN,
SPR_PWRB,
SPR_WANT,
SPR_PBOM, // player bomb

View file

@ -10,6 +10,7 @@ extern "C" {
#define BATTLE_SPAWN_INTERVAL (4*TICRATE)
#define BATTLE_DESPAWN_TIME (15*TICRATE)
#define BATTLE_POWERUP_TIME (20*TICRATE)
extern struct battleovertime
{

View file

@ -16,6 +16,7 @@
#include "k_objects.h"
#include "k_roulette.h"
#include "k_podium.h"
#include "k_powerup.h"
angle_t K_GetCollideAngle(mobj_t *t1, mobj_t *t2)
{
@ -888,6 +889,8 @@ boolean K_InstaWhipCollide(mobj_t *shield, mobj_t *victim)
P_PlayerRingBurst(victimPlayer, 5);
P_DamageMobj(victim, shield, attacker, 1, DMG_STUMBLE); // There's a special exception in P_DamageMobj for type==MT_INSTAWHIP
K_DropPowerUps(victimPlayer);
angle_t thrangle = ANGLE_180 + R_PointToAngle2(victim->x, victim->y, shield->x, shield->y);
P_Thrust(victim, thrangle, FRACUNIT*10);

View file

@ -6532,13 +6532,26 @@ SINT8 K_GetTotallyRandomResult(UINT8 useodds)
return i;
}
mobj_t *K_CreatePaperItem(fixed_t x, fixed_t y, fixed_t z, angle_t angle, SINT8 flip, UINT8 type, UINT8 amount)
mobj_t *K_CreatePaperItem(fixed_t x, fixed_t y, fixed_t z, angle_t angle, SINT8 flip, UINT8 type, UINT16 amount)
{
mobj_t *drop = P_SpawnMobj(x, y, z, MT_FLOATINGITEM);
mobj_t *backdrop = P_SpawnMobjFromMobj(drop, 0, 0, 0, MT_OVERLAY);
P_SetTarget(&backdrop->target, drop);
P_SetMobjState(backdrop, S_ITEMBACKDROP);
// FIXME: due to linkdraw sucking major ass, I was unable
// to make a backdrop render behind dropped power-ups
// (which use a smaller sprite than normal items). So
// dropped power-ups have the backdrop baked into the
// sprite for now.
if (type < FIRSTPOWERUP)
{
mobj_t *backdrop = P_SpawnMobjFromMobj(drop, 0, 0, 0, MT_OVERLAY);
P_SetTarget(&backdrop->target, drop);
P_SetMobjState(backdrop, S_ITEMBACKDROP);
backdrop->dispoffset = 1;
P_SetTarget(&backdrop->tracer, drop);
backdrop->flags2 |= MF2_LINKDRAW;
}
P_SetScale(drop, drop->scale>>4);
drop->destscale = (3*drop->destscale)/2;
@ -6587,9 +6600,6 @@ mobj_t *K_CreatePaperItem(fixed_t x, fixed_t y, fixed_t z, angle_t angle, SINT8
}
drop->flags |= MF_NOCLIPTHING;
backdrop->dispoffset = 1;
P_SetTarget(&backdrop->tracer, drop);
backdrop->flags2 |= MF2_LINKDRAW;
if (gametyperules & GTR_CLOSERPLAYERS)
{
@ -12004,8 +12014,17 @@ void K_UpdateMobjItemOverlay(mobj_t *part, SINT8 itemType, UINT8 itemCount)
part->frame = FF_FULLBRIGHT|FF_PAPERSPRITE;
break;
default:
part->sprite = SPR_ITEM;
part->frame = FF_FULLBRIGHT|FF_PAPERSPRITE|(itemType);
if (itemType >= FIRSTPOWERUP)
{
part->sprite = SPR_PWRB;
// Not a papersprite. See K_CreatePaperItem for why.
part->frame = FF_FULLBRIGHT|(itemType - FIRSTPOWERUP);
}
else
{
part->sprite = SPR_ITEM;
part->frame = FF_FULLBRIGHT|FF_PAPERSPRITE|(itemType);
}
break;
}
}

View file

@ -150,7 +150,7 @@ void K_SpawnDriftElectricSparks(player_t *player, int color, boolean shockwave);
void K_KartUpdatePosition(player_t *player);
void K_UpdateAllPlayerPositions(void);
SINT8 K_GetTotallyRandomResult(UINT8 useodds);
mobj_t *K_CreatePaperItem(fixed_t x, fixed_t y, fixed_t z, angle_t angle, SINT8 flip, UINT8 type, UINT8 amount);
mobj_t *K_CreatePaperItem(fixed_t x, fixed_t y, fixed_t z, angle_t angle, SINT8 flip, UINT8 type, UINT16 amount);
void K_DropPaperItem(player_t *player, UINT8 itemtype, UINT16 itemamount);
void K_PopPlayerShield(player_t *player);
void K_DropItems(player_t *player);

50
src/k_powerup.cpp Normal file
View file

@ -0,0 +1,50 @@
/// \brief Battle mode power-up code
#include "k_kart.h"
#include "k_objects.h"
#include "k_powerup.h"
tic_t K_PowerUpRemaining(const player_t* player, kartitems_t powerup)
{
switch (powerup)
{
case POWERUP_SUPERFLICKY:
return Obj_SuperFlickySwarmTime(player->powerup.flickyController);
default:
return 0u;
}
}
void K_GivePowerUp(player_t* player, kartitems_t powerup, tic_t time)
{
switch (powerup)
{
case POWERUP_SUPERFLICKY:
if (K_PowerUpRemaining(player, POWERUP_SUPERFLICKY))
{
Obj_ExtendSuperFlickySwarm(player->powerup.flickyController, time);
}
else
{
Obj_SpawnSuperFlickySwarm(player, time);
}
break;
default:
break;
}
}
void K_DropPowerUps(player_t* player)
{
if (K_PowerUpRemaining(player, POWERUP_SUPERFLICKY))
{
mobj_t* swarm = player->powerup.flickyController;
// Be sure to measure the remaining time before ending the power-up
K_DropPaperItem(player, POWERUP_SUPERFLICKY, Obj_SuperFlickySwarmTime(swarm));
Obj_EndSuperFlickySwarm(swarm);
}
}

19
src/k_powerup.h Normal file
View file

@ -0,0 +1,19 @@
#ifndef __K_POWERUP__
#define __K_POWERUP__
#include "doomtype.h"
#include "d_player.h"
#ifdef __cplusplus
extern "C" {
#endif
tic_t K_PowerUpRemaining(const player_t *player, kartitems_t powerup);
void K_GivePowerUp(player_t *player, kartitems_t powerup, tic_t timer);
void K_DropPowerUps(player_t *player);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // __K_POWERUP__

View file

@ -41,6 +41,7 @@
#include "k_roulette.h"
#include "k_boss.h"
#include "acs/interface.h"
#include "k_powerup.h"
// CTF player names
#define CTFTEAMCODE(pl) pl->ctfteam ? (pl->ctfteam == 1 ? "\x85" : "\x84") : ""
@ -276,14 +277,21 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
P_InstaThrust(player->mo, player->mo->angle, 20<<FRACBITS);
return;
case MT_FLOATINGITEM: // SRB2Kart
if (!P_CanPickupItem(player, 3) || (player->itemamount && player->itemtype != special->threshold))
return;
player->itemtype = special->threshold;
if ((UINT16)(player->itemamount) + special->movecount > 255)
player->itemamount = 255;
if (special->threshold >= FIRSTPOWERUP)
{
K_GivePowerUp(player, special->threshold, special->movecount);
}
else
player->itemamount += special->movecount;
{
if (!P_CanPickupItem(player, 3) || (player->itemamount && player->itemtype != special->threshold))
return;
player->itemtype = special->threshold;
if ((UINT16)(player->itemamount) + special->movecount > 255)
player->itemamount = 255;
else
player->itemamount += special->movecount;
}
S_StartSound(special, special->info->deathsound);