Merge branch 'more-powerups' into 'splitscreen-timer'

Battle: add remaining power-ups, Aura and HUD

See merge request KartKrew/Kart!1310
This commit is contained in:
Oni 2023-06-30 04:24:07 +00:00
commit 36bb219196
19 changed files with 482 additions and 43 deletions

View file

@ -189,6 +189,8 @@ typedef enum
POWERUP_BUMPER,
POWERUP_BADGE,
POWERUP_SUPERFLICKY,
ENDOFPOWERUPS,
NUMPOWERUPS = ENDOFPOWERUPS - FIRSTPOWERUP,
} kartitems_t;
typedef enum
@ -463,6 +465,9 @@ typedef struct {
// player_t struct for power-ups
struct powerupvars_t {
UINT16 superTimer;
UINT16 barrierTimer;
UINT16 rhythmBadgeTimer;
mobj_t *flickyController;
};

View file

@ -4586,6 +4586,8 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi
"S_GACHABOM_RETURNING",
"S_SUPER_FLICKY",
"S_POWERUP_AURA",
};
// RegEx to generate this from info.h: ^\tMT_([^,]+), --> \t"MT_\1",
@ -5717,6 +5719,8 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t
"MT_SUPER_FLICKY",
"MT_SUPER_FLICKY_CONTROLLER",
"MT_POWERUP_AURA",
};
const char *const MOBJFLAG_LIST[] = {
@ -6880,6 +6884,8 @@ struct int_const_s const INT_CONST[] = {
{"POWERUP_BUMPER",POWERUP_BUMPER},
{"POWERUP_BADGE",POWERUP_BADGE},
{"POWERUP_SUPERFLICKY",POWERUP_SUPERFLICKY},
{"ENDOFPOWERUPS",ENDOFPOWERUPS},
{"NUMPOWERUPS",NUMPOWERUPS},
// kartshields_t
{"KSHIELD_NONE",KSHIELD_NONE},

View file

@ -1,3 +1,4 @@
target_sources(SRB2SDL2 PRIVATE
powerup.cpp
timer.cpp
)

133
src/hud/powerup.cpp Normal file
View file

@ -0,0 +1,133 @@
#include <algorithm>
#include <functional>
#include <fmt/format.h>
#include "../core/static_vec.hpp"
#include "../doomstat.h"
#include "../g_game.h"
#include "../k_hud.h"
#include "../k_powerup.h"
#include "../p_local.h"
#include "../r_fps.h"
#include "../v_draw.hpp"
using srb2::Draw;
namespace
{
struct Icon
{
kartitems_t powerup;
tic_t time;
Icon() {}
explicit Icon(int k) :
powerup(static_cast<kartitems_t>(k)),
time(K_PowerUpRemaining(stplyr, powerup))
{
}
int letter() const { return 'A' + (powerup - FIRSTPOWERUP); }
bool operator <(const Icon& b) const { return time < b.time; }
bool operator >(const Icon& b) const { return time > b.time; }
};
srb2::StaticVec<Icon, NUMPOWERUPS> get_powerup_list(bool ascending)
{
srb2::StaticVec<Icon, NUMPOWERUPS> v;
for (int k = FIRSTPOWERUP; k < ENDOFPOWERUPS; ++k)
{
Icon ico(k);
if (ico.time)
{
v.push_back(ico);
}
}
if (ascending)
{
std::sort(v.begin(), v.end(), std::less<Icon>());
}
else
{
std::sort(v.begin(), v.end(), std::greater<Icon>());
}
return v;
}
}; // namespace
void K_drawKartPowerUps(void)
{
struct Offsets
{
Draw row;
const char* sprite;
int spr_x;
int spr_y;
int shift_x;
int dir;
};
auto make_offsets = []() -> Offsets
{
auto make_drawer = [](int x, int y, Draw::Font font) -> Draw
{
return Draw(x, y).font(font).align(Draw::Align::kRight);
};
const int viewnum = R_GetViewNumber();
// 1/2P
switch (r_splitscreen)
{
case 0:
return { make_drawer(307, 55, Draw::Font::kZVote), "PWRU", -17, 7, -35, -1 };
case 1:
return { make_drawer(318, viewnum == 0 ? 55 : 155, Draw::Font::kPing), "PWRS", -9, 6, -19, -1 };
}
// 3/4P
int x = 21;
int y = 47;
int dir = 1;
switch (viewnum)
{
case 1:
case 3:
x = 318;
dir = -1;
}
switch (viewnum)
{
case 2:
case 3:
y += 100;
}
return { make_drawer(x, y, Draw::Font::kPing), "PWRS", -9, 5, 19 * dir, dir };
};
Offsets i = make_offsets();
for (const Icon& ico : get_powerup_list(i.dir == -1))
{
i.row.xy(i.spr_x, i.spr_y)
.colormap(static_cast<skincolornum_t>(stplyr->skincolor))
.patch(fmt::format("{0}{1:c}L{1:c}R", i.sprite, ico.letter()).c_str());
i.row.text("{}", (ico.time + (TICRATE / 2)) / TICRATE);
i.row = i.row.x(i.shift_x);
}
}

View file

@ -652,6 +652,7 @@ char sprnames[NUMSPRITES + 1][5] =
"ITMI",
"ITMN",
"PWRB",
"RBOW", // power-up aura
"WANT",
"PBOM", // player bomb
@ -5256,6 +5257,8 @@ state_t states[NUMSTATES] =
{SPR_GBOM, FF_INVERT, -1, {A_SetScale}, FRACUNIT/2, 1, S_NULL}, // S_GACHABOM_RETURNING
{SPR_3DFR, 1|FF_ANIMATE, -1, {NULL}, 2, 5, S_NULL}, // S_SUPER_FLICKY
{SPR_RBOW, FF_PAPERSPRITE|FF_ADD|FF_FULLBRIGHT|FF_ANIMATE, -1, {NULL}, 14, 2, S_NULL}, // S_POWERUP_AURA
};
mobjinfo_t mobjinfo[NUMMOBJTYPES] =
@ -29896,6 +29899,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
MF_NOSECTOR|MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_SCENERY, // flags
S_NULL // raisestate
},
{ // MT_POWERUP_AURA
-1, // doomednum
S_POWERUP_AURA, // spawnstate
1000, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
0, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
0, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_NULL, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
0, // speed
16*FRACUNIT, // radius
106*FRACUNIT, // height
0, // display offset
0, // mass
0, // damage
sfx_None, // activesound
MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_SCENERY, // flags
S_NULL // raisestate
},
};
skincolor_t skincolors[MAXSKINCOLORS] = {

View file

@ -1203,6 +1203,7 @@ typedef enum sprite
SPR_ITMI,
SPR_ITMN,
SPR_PWRB,
SPR_RBOW, // power-up aura
SPR_WANT,
SPR_PBOM, // player bomb
@ -5687,6 +5688,8 @@ typedef enum state
S_SUPER_FLICKY,
S_POWERUP_AURA,
S_FIRSTFREESLOT,
S_LASTFREESLOT = S_FIRSTFREESLOT + NUMSTATEFREESLOTS - 1,
NUMSTATES
@ -6837,6 +6840,8 @@ typedef enum mobj_type
MT_SUPER_FLICKY,
MT_SUPER_FLICKY_CONTROLLER,
MT_POWERUP_AURA,
MT_FIRSTFREESLOT,
MT_LASTFREESLOT = MT_FIRSTFREESLOT + NUMMOBJFREESLOTS - 1,
NUMMOBJTYPES

View file

@ -5521,6 +5521,8 @@ void K_drawKartHUD(void)
K_drawMiniPing();
}
K_drawKartPowerUps();
if (G_IsPartyLocal(displayplayers[viewnum]) == false && !demo.playback)
{
K_drawDirectorHUD();

View file

@ -40,6 +40,7 @@ const char *K_GetItemPatch(UINT8 item, boolean tiny);
void K_LoadKartHUDGraphics(void);
void K_drawKartHUD(void);
void K_drawKartFreePlay(void);
void K_drawKartPowerUps(void);
void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT32 splitflags, UINT8 mode);
void K_drawKart2PTimestamp(void);
void K_drawKart4PTimestamp(void);

View file

@ -45,6 +45,7 @@
#include "k_specialstage.h"
#include "k_roulette.h"
#include "k_podium.h"
#include "k_powerup.h"
// SOME IMPORTANT VARIABLES DEFINED IN DOOMDEF.H:
// gamespeed is cc (0 for easy, 1 for normal, 2 for hard)
@ -4482,19 +4483,12 @@ void K_DebtStingPlayer(player_t *player, mobj_t *source)
P_SetPlayerMobjState(player->mo, S_KART_SPINOUT);
}
void K_TakeBumpersFromPlayer(player_t *player, player_t *victim, UINT8 amount)
void K_GiveBumpersToPlayer(player_t *player, player_t *victim, UINT8 amount)
{
const UINT8 oldPlayerBumpers = K_Bumpers(player);
UINT8 tookBumpers = 0;
amount = min(amount, K_Bumpers(victim));
if (amount == 0)
{
return;
}
while (tookBumpers < amount)
{
const UINT8 newbumper = (oldPlayerBumpers + tookBumpers);
@ -4520,11 +4514,15 @@ void K_TakeBumpersFromPlayer(player_t *player, player_t *victim, UINT8 amount)
newmo = P_SpawnMobj(newx, newy, player->mo->z, MT_BATTLEBUMPER);
newmo->threshold = newbumper;
P_SetTarget(&newmo->tracer, victim->mo);
if (victim)
{
P_SetTarget(&newmo->tracer, victim->mo);
}
P_SetTarget(&newmo->target, player->mo);
newmo->angle = (diff * (newbumper-1));
newmo->color = victim->skincolor;
newmo->color = (victim ? victim : player)->skincolor;
if (newbumper+1 < 2)
{
@ -4544,6 +4542,18 @@ void K_TakeBumpersFromPlayer(player_t *player, player_t *victim, UINT8 amount)
// :jartcookiedance:
player->mo->health += tookBumpers;
}
void K_TakeBumpersFromPlayer(player_t *player, player_t *victim, UINT8 amount)
{
amount = min(amount, K_Bumpers(victim));
if (amount == 0)
{
return;
}
K_GiveBumpersToPlayer(player, victim, amount);
// Play steal sound
S_StartSound(player->mo, sfx_3db06);
@ -7997,7 +8007,7 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
player->spheredigestion = spheredigestion;
}
if (K_PlayerGuard(player) && (player->ebrakefor%6 == 0))
if (K_PlayerGuard(player) && !K_PowerUpRemaining(player, POWERUP_BARRIER) && (player->ebrakefor%6 == 0))
player->spheres--;
}
else
@ -8090,6 +8100,22 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
}
}
if (player->powerup.rhythmBadgeTimer > 0)
{
player->instaShieldCooldown = min(player->instaShieldCooldown, 1);
player->powerup.rhythmBadgeTimer--;
}
if (player->powerup.barrierTimer > 0)
{
player->powerup.barrierTimer--;
}
if (player->powerup.superTimer > 0)
{
player->powerup.superTimer--;
}
if (player->guardCooldown)
player->guardCooldown--;
@ -8334,7 +8360,7 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
player->pflags &= ~PF_DRIFTINPUT;
}
if (K_PlayerGuard(player))
if (K_PlayerGuard(player) && !K_PowerUpRemaining(player, POWERUP_BARRIER))
player->instaShieldCooldown = max(player->instaShieldCooldown, INSTAWHIP_DROPGUARD);
// Roulette Code
@ -10057,7 +10083,17 @@ boolean K_PlayerEBrake(player_t *player)
boolean K_PlayerGuard(player_t *player)
{
return (K_PlayerEBrake(player) && player->spheres > 0 && player->guardCooldown == 0);
if (player->guardCooldown != 0)
{
return false;
}
if (K_PowerUpRemaining(player, POWERUP_BARRIER))
{
return true;
}
return (K_PlayerEBrake(player) && player->spheres > 0);
}
SINT8 K_Sliptiding(player_t *player)
@ -10101,26 +10137,6 @@ void K_KartEbrakeVisuals(player_t *p)
if (!S_SoundPlaying(p->mo, sfx_s3kd9s))
S_ReducedVFXSound(p->mo, sfx_s3kd9s, p);
// Block visuals
// (These objects track whether a player is block-eligible on their own, no worries)
if (!p->ebrakefor)
{
mobj_t *ring = P_SpawnMobj(p->mo->x, p->mo->y, p->mo->z, MT_BLOCKRING);
P_SetTarget(&ring->target, p->mo);
P_SetScale(ring, p->mo->scale);
K_MatchGenericExtraFlags(ring, p->mo);
ring->renderflags &= ~RF_DONTDRAW;
mobj_t *body = P_SpawnMobj(p->mo->x, p->mo->y, p->mo->z, MT_BLOCKBODY);
P_SetTarget(&body->target, p->mo);
P_SetScale(body, p->mo->scale);
K_MatchGenericExtraFlags(body, p->mo);
body->renderflags |= RF_DONTDRAW;
if (K_PlayerGuard(p))
S_StartSound(body, sfx_s1af);
}
// HOLD! bubble.
if (!p->ebrakefor)
{
@ -10864,7 +10880,12 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
else
{
player->instaShieldCooldown = INSTAWHIP_COOLDOWN;
player->guardCooldown = INSTAWHIP_COOLDOWN;
if (!K_PowerUpRemaining(player, POWERUP_BARRIER))
{
player->guardCooldown = INSTAWHIP_COOLDOWN;
}
S_StartSound(player->mo, sfx_iwhp);
mobj_t *whip = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_INSTAWHIP);
P_SetTarget(&player->whip, whip);
@ -10876,10 +10897,13 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
player->flashing = max(player->flashing, 12);
player->mo->momz += 4*mapobjectscale;
// Spawn in triangle formation
Obj_SpawnInstaWhipRecharge(player, 0);
Obj_SpawnInstaWhipRecharge(player, ANGLE_120);
Obj_SpawnInstaWhipRecharge(player, ANGLE_240);
if (!K_PowerUpRemaining(player, POWERUP_BADGE))
{
// Spawn in triangle formation
Obj_SpawnInstaWhipRecharge(player, 0);
Obj_SpawnInstaWhipRecharge(player, ANGLE_120);
Obj_SpawnInstaWhipRecharge(player, ANGLE_240);
}
}
}

View file

@ -113,6 +113,7 @@ void K_UpdateStumbleIndicator(player_t *player);
void K_UpdateSliptideZipIndicator(player_t *player);
INT32 K_ExplodePlayer(player_t *player, mobj_t *inflictor, mobj_t *source);
void K_DebtStingPlayer(player_t *player, mobj_t *source);
void K_GiveBumpersToPlayer(player_t *player, player_t *victim, UINT8 amount);
void K_TakeBumpersFromPlayer(player_t *player, player_t *victim, UINT8 amount);
void K_MineFlashScreen(mobj_t *source);
void K_SpawnMineExplosion(mobj_t *source, UINT8 color, tic_t delay);

View file

@ -161,6 +161,10 @@ void Obj_SuperFlickyPlayerCollide(mobj_t *flicky, mobj_t *player);
void Obj_SuperFlickyLanding(mobj_t *flicky);
boolean Obj_IsSuperFlickyWhippable(const mobj_t *flicky);
/* Power-Up Aura */
void Obj_SpawnPowerUpAura(player_t* player);
void Obj_PowerUpAuraThink(mobj_t* mobj);
#ifdef __cplusplus
} // extern "C"
#endif

View file

@ -8,6 +8,15 @@ tic_t K_PowerUpRemaining(const player_t* player, kartitems_t powerup)
{
switch (powerup)
{
case POWERUP_SMONITOR:
return player->powerup.superTimer;
case POWERUP_BARRIER:
return player->powerup.barrierTimer;
case POWERUP_BADGE:
return player->powerup.rhythmBadgeTimer;
case POWERUP_SUPERFLICKY:
return Obj_SuperFlickySwarmTime(player->powerup.flickyController);
@ -16,10 +25,45 @@ tic_t K_PowerUpRemaining(const player_t* player, kartitems_t powerup)
}
}
boolean K_AnyPowerUpRemaining(const player_t* player)
{
for (int k = FIRSTPOWERUP; k < ENDOFPOWERUPS; ++k)
{
if (K_PowerUpRemaining(player, static_cast<kartitems_t>(k)))
{
return true;
}
}
return false;
}
void K_GivePowerUp(player_t* player, kartitems_t powerup, tic_t time)
{
if (!K_AnyPowerUpRemaining(player))
{
Obj_SpawnPowerUpAura(player);
}
switch (powerup)
{
case POWERUP_SMONITOR:
K_DoInvincibility(player, time);
player->powerup.superTimer += time;
break;
case POWERUP_BARRIER:
player->powerup.barrierTimer += time;
break;
case POWERUP_BUMPER:
K_GiveBumpersToPlayer(player, nullptr, 5);
break;
case POWERUP_BADGE:
player->powerup.rhythmBadgeTimer += time;
break;
case POWERUP_SUPERFLICKY:
if (K_PowerUpRemaining(player, POWERUP_SUPERFLICKY))
{
@ -38,6 +82,21 @@ void K_GivePowerUp(player_t* player, kartitems_t powerup, tic_t time)
void K_DropPowerUps(player_t* player)
{
auto simple_drop = [player](kartitems_t powerup, auto& timer)
{
tic_t remaining = K_PowerUpRemaining(player, powerup);
if (remaining)
{
K_DropPaperItem(player, powerup, remaining);
timer = 0;
}
};
simple_drop(POWERUP_SMONITOR, player->powerup.superTimer);
simple_drop(POWERUP_BARRIER, player->powerup.barrierTimer);
simple_drop(POWERUP_BADGE, player->powerup.rhythmBadgeTimer);
if (K_PowerUpRemaining(player, POWERUP_SUPERFLICKY))
{
mobj_t* swarm = player->powerup.flickyController;

View file

@ -9,6 +9,7 @@ extern "C" {
#endif
tic_t K_PowerUpRemaining(const player_t *player, kartitems_t powerup);
boolean K_AnyPowerUpRemaining(const player_t *player);
void K_GivePowerUp(player_t *player, kartitems_t powerup, tic_t timer);
void K_DropPowerUps(player_t *player);

View file

@ -22,4 +22,5 @@ target_sources(SRB2SDL2 PRIVATE
gachabom-rebound.cpp
servant-hand.c
super-flicky.cpp
powerup-aura.cpp
)

View file

@ -3,10 +3,16 @@
#include "../k_objects.h"
#include "../p_local.h"
#include "../k_kart.h"
#include "../k_powerup.h"
static INT16 guard_upscale (player_t *player)
{
return K_PowerUpRemaining(player, POWERUP_BARRIER) ? 40 : player->spheres;
}
void Obj_BlockRingThink (mobj_t *ring)
{
if (P_MobjWasRemoved(ring->target) || !ring->target->player || !ring->target->player->ebrakefor)
if (P_MobjWasRemoved(ring->target) || !ring->target->player)
{
P_RemoveMobj(ring);
}
@ -22,7 +28,7 @@ void Obj_BlockRingThink (mobj_t *ring)
ring->color = mo->color;
fixed_t baseScale = mo->scale / 2;
baseScale += (mo->scale / 30) * player->spheres;
baseScale += (mo->scale / 30) * guard_upscale(player);
P_SetScale(ring, baseScale);
// Twirl
@ -42,7 +48,7 @@ void Obj_BlockRingThink (mobj_t *ring)
void Obj_BlockBodyThink (mobj_t *body)
{
if (P_MobjWasRemoved(body->target) || !body->target->player || !body->target->player->ebrakefor)
if (P_MobjWasRemoved(body->target) || !body->target->player)
{
P_RemoveMobj(body);
}
@ -55,7 +61,7 @@ void Obj_BlockBodyThink (mobj_t *body)
body->flags &= ~(MF_NOCLIPTHING);
fixed_t baseScale = mo->scale / 2;
baseScale += (mo->scale / 30) * player->spheres;
baseScale += (mo->scale / 30) * guard_upscale(player);
P_SetScale(body, baseScale);
P_MoveOrigin(body, mo->x, mo->y, mo->z + mo->height/2);

View file

@ -0,0 +1,121 @@
#include "../info.h"
#include "../g_game.h"
#include "../m_fixed.h"
#include "../k_objects.h"
#include "../k_powerup.h"
#include "../p_local.h"
#include "../p_mobj.h"
#include "../tables.h"
// copied from objects/monitor.c
#define FINE90 (FINEANGLES/4)
#define FINE180 (FINEANGLES/2)
#define TRUETAN(n) FINETANGENT(FINE90 + (n)) // bruh
#define part_theta(o) ((o)->movedir)
#define part_seek(o) ((o)->extravalue1)
namespace
{
constexpr int kSpriteWidth = 32;
constexpr int kNumSides = 6;
struct Aura : mobj_t
{
angle_t theta() const { return part_theta(this); }
void theta(angle_t n) { part_theta(this) = n; }
unsigned seek() const { return part_seek(this); }
void seek(unsigned n) { part_seek(this) = n; }
mobj_t* origin() const { return players[seek()].mo; }
static void spawn(int player)
{
const fixed_t angle_factor = ANGLE_MAX / kNumSides;
angle_t ang = 0u;
for (int i = 0; i < kNumSides; ++i)
{
Aura* x = static_cast<Aura*>(P_SpawnMobj(0, 0, 0, MT_POWERUP_AURA));
x->theta(ang);
x->seek(player);
ang += angle_factor;
}
}
// copied from objects/monitor.c
static fixed_t get_inradius(fixed_t length)
{
return FixedDiv(length, 2 * TRUETAN(FINE180 / kNumSides));
}
bool valid() const
{
if (seek() >= MAXPLAYERS)
{
return false;
}
if (!playeringame[seek()])
{
return false;
}
if (!K_AnyPowerUpRemaining(&players[seek()]))
{
return false;
}
return true;
}
void move()
{
if (P_MobjWasRemoved(origin()))
{
return;
}
P_MoveOrigin(this, origin()->x, origin()->y, origin()->z);
P_InstaScale(this, 11 * origin()->scale / 10);
translate();
}
void translate()
{
const fixed_t width = scale * kSpriteWidth;
const fixed_t rad = get_inradius(width);
const angle_t ang = theta() + origin()->angle;
angle = (ang - ANGLE_90);
sprxoff = FixedMul(FCOS(ang), rad);
spryoff = FixedMul(FSIN(ang), rad);
}
};
}; // namespace
void Obj_SpawnPowerUpAura(player_t* player)
{
Aura::spawn(player - players);
}
void Obj_PowerUpAuraThink(mobj_t* mobj)
{
Aura* x = static_cast<Aura*>(mobj);
if (!x->valid())
{
P_RemoveMobj(x);
return;
}
x->move();
}

View file

@ -2418,7 +2418,8 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
if (source && source != player->mo && source->player)
{
// Extend the invincibility if the hit was a direct hit.
if (inflictor == source && source->player->invincibilitytimer)
if (inflictor == source && source->player->invincibilitytimer &&
!K_PowerUpRemaining(player, POWERUP_SMONITOR))
{
tic_t kinvextend;

View file

@ -6698,6 +6698,14 @@ static void P_MobjSceneryThink(mobj_t *mobj)
case MT_SUPER_FLICKY_CONTROLLER:
Obj_SuperFlickyControllerThink(mobj);
if (P_MobjWasRemoved(mobj))
{
return;
}
break;
case MT_POWERUP_AURA:
Obj_PowerUpAuraThink(mobj);
if (P_MobjWasRemoved(mobj))
{
return;
@ -11866,6 +11874,26 @@ void P_SpawnPlayer(INT32 playernum)
}
}
// Block visuals
// (These objects track whether a player is block-eligible on their own, no worries)
if (!p->spectator)
{
mobj_t *ring = P_SpawnMobj(p->mo->x, p->mo->y, p->mo->z, MT_BLOCKRING);
P_SetTarget(&ring->target, p->mo);
P_SetScale(ring, p->mo->scale);
K_MatchGenericExtraFlags(ring, p->mo);
ring->renderflags &= ~RF_DONTDRAW;
mobj_t *body = P_SpawnMobj(p->mo->x, p->mo->y, p->mo->z, MT_BLOCKBODY);
P_SetTarget(&body->target, p->mo);
P_SetScale(body, p->mo->scale);
K_MatchGenericExtraFlags(body, p->mo);
body->renderflags |= RF_DONTDRAW;
if (K_PlayerGuard(p))
S_StartSound(body, sfx_s1af);
}
// I'm not refactoring the loop at the top of this file.
pcount = 0;

View file

@ -634,6 +634,11 @@ static void P_NetArchivePlayers(savebuffer_t *save)
// ACS has read access to this, so it has to be net-communicated.
// It is the ONLY roundcondition that is sent over the wire and I'd like it to stay that way.
WRITEUINT32(save->p, players[i].roundconditions.unlocktriggers);
// powerupvars_t
WRITEUINT16(save->p, players[i].powerup.superTimer);
WRITEUINT16(save->p, players[i].powerup.barrierTimer);
WRITEUINT16(save->p, players[i].powerup.rhythmBadgeTimer);
}
}
@ -1059,6 +1064,11 @@ static void P_NetUnArchivePlayers(savebuffer_t *save)
// It is the ONLY roundcondition that is sent over the wire and I'd like it to stay that way.
players[i].roundconditions.unlocktriggers = READUINT32(save->p);
// powerupvars_t
players[i].powerup.superTimer = READUINT16(save->p);
players[i].powerup.barrierTimer = READUINT16(save->p);
players[i].powerup.rhythmBadgeTimer = READUINT16(save->p);
//players[i].viewheight = P_GetPlayerViewHeight(players[i]); // scale cannot be factored in at this point
}
}