From 4e7b6f0cc3e2f9ccf3ba7160c9157f3bc78bcdef Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Wed, 12 Apr 2023 21:08:45 -0400 Subject: [PATCH] Add ring shooter tire grabbers + more player logic --- src/d_clisrv.c | 1 + src/d_player.h | 3 +- src/g_game.c | 1 + src/k_objects.h | 3 +- src/objects/ring-shooter.c | 303 ++++++++++++++++++++++++++++++++++--- src/p_mobj.c | 82 ++++++---- src/p_saveg.c | 33 +++- 7 files changed, 366 insertions(+), 60 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 37f0db6f2..24e8a5166 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -2776,6 +2776,7 @@ void CL_ClearPlayer(INT32 playernum) P_SetTarget(&players[playernum].hoverhyudoro, NULL); P_SetTarget(&players[playernum].stumbleIndicator, NULL); P_SetTarget(&players[playernum].sliptideZipIndicator, NULL); + P_SetTarget(&players[playernum].ringShooter, NULL); } // Handle parties. diff --git a/src/d_player.h b/src/d_player.h index 6e165c75f..4ecfef161 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -505,7 +505,8 @@ struct player_t UINT32 distancetofinish; waypoint_t *currentwaypoint; waypoint_t *nextwaypoint; - respawnvars_t respawn; // Respawn info + respawnvars_t respawn; // Respawn info + mobj_t *ringShooter; // DEZ respawner object tic_t airtime; // Used to track just air time, but has evolved over time into a general "karted" timer. Rename this variable? UINT8 startboost; // (0 to 125) - Boost you get from start of race or respawn drop dash diff --git a/src/g_game.c b/src/g_game.c index 9f198c33b..97cc64c64 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -2645,6 +2645,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) P_SetTarget(&players[player].follower, NULL); P_SetTarget(&players[player].awayview.mobj, NULL); P_SetTarget(&players[player].stumbleIndicator, NULL); + P_SetTarget(&players[player].ringShooter, NULL); P_SetTarget(&players[player].followmobj, NULL); hoverhyudoro = players[player].hoverhyudoro; diff --git a/src/k_objects.h b/src/k_objects.h index 7e7c3871b..6b45dbb55 100644 --- a/src/k_objects.h +++ b/src/k_objects.h @@ -107,8 +107,9 @@ void Obj_BeginDropTargetMorph(mobj_t *target, skincolornum_t color); boolean Obj_DropTargetMorphThink(mobj_t *morph); /* Ring Shooter */ -void Obj_RingShooterThinker(mobj_t *mo); +boolean Obj_RingShooterThinker(mobj_t *mo); void Obj_RingShooterInput(player_t *player); +void Obj_RingShooterDelete(mobj_t *mo); #ifdef __cplusplus } // extern "C" diff --git a/src/objects/ring-shooter.c b/src/objects/ring-shooter.c index 53e1d077b..740fa3cd1 100644 --- a/src/objects/ring-shooter.c +++ b/src/objects/ring-shooter.c @@ -25,33 +25,76 @@ #include "../k_waypoint.h" #include "../r_skins.h" #include "../k_respawn.h" +#include "../lua_hook.h" #define RS_FUSE_TIME (4*TICRATE) -static void ActivateRingShooter(mobj_t *mo) -{ - mobj_t *part = mo->tracer; +#define RS_GRABBER_START (16 << FRACBITS) +#define RS_GRABBER_SLIDE (RS_GRABBER_START >> 4) +#define RS_GRABBER_EXTRA (18 << FRACBITS) - while (!P_MobjWasRemoved(part->tracer)) - { - part = part->tracer; - part->renderflags &= ~RF_DONTDRAW; - part->frame += 4; - } -} +#define RS_KARTED_INC (3) #define rs_base_scalespeed(o) ((o)->scalespeed) #define rs_base_scalestate(o) ((o)->threshold) #define rs_base_xscale(o) ((o)->extravalue1) #define rs_base_yscale(o) ((o)->extravalue2) +#define rs_base_playerid(o) ((o)->lastlook) +#define rs_base_karted(o) ((o)->movecount) +#define rs_base_grabberdist(o) ((o)->movefactor) +#define rs_base_canceled(o) ((o)->cvmem) + #define rs_part_xoffset(o) ((o)->extravalue1) #define rs_part_yoffset(o) ((o)->extravalue2) +static void RemoveRingShooterPointer(mobj_t *base) +{ + player_t *player = NULL; + + if (rs_base_playerid(base) < 0 || rs_base_playerid(base) >= MAXPLAYERS) + { + // No pointer set + return; + } + + // NULL the player's pointer. + player = &players[ rs_base_playerid(base) ]; + P_SetTarget(&player->ringShooter, NULL); + + // Remove our player ID + rs_base_playerid(base) = -1; +} + + +static void ChangeRingShooterPointer(mobj_t *base, player_t *player) +{ + // Remove existing pointer first. + RemoveRingShooterPointer(base); + + if (player == NULL) + { + // Just remove it. + return; + } + + // Set new player pointer. + P_SetTarget(&player->ringShooter, base); + + // Set new player ID. + rs_base_playerid(base) = (player - players); +} + static void ScalePart(mobj_t *part, mobj_t *base) { part->spritexscale = rs_base_xscale(base); part->spriteyscale = rs_base_yscale(base); + + if (part->type == MT_TIREGRABBER) + { + part->spritexscale /= 2; + part->spriteyscale /= 2; + } } static void MovePart(mobj_t *part, mobj_t *base, mobj_t *refNipple) @@ -64,12 +107,43 @@ static void MovePart(mobj_t *part, mobj_t *base, mobj_t *refNipple) ); } +static void ShowHidePart(mobj_t *part, mobj_t *base) +{ + part->renderflags = (part->renderflags & ~RF_DONTDRAW) | (base->renderflags & RF_DONTDRAW); +} + +static fixed_t GetTireDist(mobj_t *base) +{ + return -(RS_GRABBER_EXTRA + rs_base_grabberdist(base)); +} + +static void MoveTire(mobj_t *part, mobj_t *base) +{ + const fixed_t dis = FixedMul(GetTireDist(base), base->scale); + const fixed_t c = FINECOSINE(part->angle >> ANGLETOFINESHIFT); + const fixed_t s = FINESINE(part->angle >> ANGLETOFINESHIFT); + P_MoveOrigin( + part, + base->x + FixedMul(dis, c), + base->y + FixedMul(dis, s), + part->z + ); +} + // I've tried to reduce redundancy as much as I can, // but check K_SpawnRingShooter if you edit this static void UpdateRingShooterParts(mobj_t *mo) { mobj_t *part, *refNipple; + part = mo; + while (!P_MobjWasRemoved(part->target)) + { + part = part->target; + ScalePart(part, mo); + MoveTire(part, mo); + } + part = mo; while (!P_MobjWasRemoved(part->hprev)) { @@ -92,6 +166,47 @@ static void UpdateRingShooterParts(mobj_t *mo) ScalePart(part, mo); } +static void UpdateRingShooterPartsVisibility(mobj_t *mo) +{ + mobj_t *part; + + part = mo; + while (!P_MobjWasRemoved(part->target)) + { + part = part->target; + ShowHidePart(part, mo); + } + + part = mo; + while (!P_MobjWasRemoved(part->hprev)) + { + part = part->hprev; + ShowHidePart(part, mo); + } + + part = mo; + while (!P_MobjWasRemoved(part->hnext)) + { + part = part->hnext; + ShowHidePart(part, mo); + } + + part = mo->tracer; + ShowHidePart(part, mo); +} + +static void ActivateRingShooter(mobj_t *mo) +{ + mobj_t *part = mo->tracer; + + while (!P_MobjWasRemoved(part->tracer)) + { + part = part->tracer; + part->renderflags &= ~RF_DONTDRAW; + part->frame += 4; + } +} + static boolean RingShooterInit(mobj_t *mo) { if (rs_base_scalestate(mo) == -1) @@ -129,10 +244,26 @@ static boolean RingShooterInit(mobj_t *mo) rs_base_xscale(mo) -= rs_base_scalespeed(mo); if (rs_base_yscale(mo) >= FRACUNIT) { - rs_base_scalestate(mo) = -1; + rs_base_scalestate(mo)++; rs_base_xscale(mo) = rs_base_yscale(mo) = FRACUNIT; + } + break; + } + case 3: + { + rs_base_grabberdist(mo) -= RS_GRABBER_SLIDE; + if (rs_base_grabberdist(mo) <= 0) + { + rs_base_scalestate(mo) = -1; + rs_base_grabberdist(mo) = 0; ActivateRingShooter(mo); } + break; + } + default: + { + rs_base_scalestate(mo) = 0; // fix invalid states + break; } } @@ -206,13 +337,87 @@ static void RingShooterFlicker(mobj_t *mo) part->target->frame = (part->target->frame & ~FF_TRANSMASK) | trans; } -void Obj_RingShooterThinker(mobj_t *mo) +boolean Obj_RingShooterThinker(mobj_t *mo) { - if (P_MobjWasRemoved(mo->tracer) || RingShooterInit(mo)) - return; + if (RingShooterInit(mo) == true) + { + return true; + } - RingShooterCountdown(mo); - RingShooterFlicker(mo); + if (mo->fuse > 0) + { + mo->fuse--; + + if (mo->fuse == 0) + { + P_RemoveMobj(mo); + return false; + } + } + + if (rs_base_canceled(mo) != 0) + { + rs_base_karted(mo) += RS_KARTED_INC; + + if (P_MobjWasRemoved(mo->tracer) == false) + { + RingShooterCountdown(mo); + RingShooterFlicker(mo); + } + } + + if (mo->fuse < TICRATE) + { + if (leveltime & 1) + { + mo->renderflags |= RF_DONTDRAW; + } + else + { + mo->renderflags &= ~RF_DONTDRAW; + } + + UpdateRingShooterPartsVisibility(mo); + } + + return true; +} + +void Obj_RingShooterDelete(mobj_t *mo) +{ + mobj_t *part; + + RemoveRingShooterPointer(mo); + + part = mo->target; + while (P_MobjWasRemoved(part) == false) + { + mobj_t *delete = part; + part = part->target; + P_RemoveMobj(delete); + } + + part = mo->hprev; + while (P_MobjWasRemoved(part) == false) + { + mobj_t *delete = part; + part = part->hprev; + P_RemoveMobj(delete); + } + + part = mo->hnext; + while (P_MobjWasRemoved(part) == false) + { + mobj_t *delete = part; + part = part->hnext; + P_RemoveMobj(delete); + } + + part = mo->tracer; + if (P_MobjWasRemoved(part) == false) + { + P_RemoveMobj(part); + } } static boolean AllowRingShooter(player_t *player) @@ -254,8 +459,11 @@ static void SpawnRingShooter(player_t *player) vector2_t offset; SINT8 i; + rs_base_playerid(base) = -1; + rs_base_karted(base) = -(RS_KARTED_INC * TICRATE); // wait for "3" + rs_base_grabberdist(base) = RS_GRABBER_START; + K_FlipFromObject(base, mo); - P_SetTarget(&base->target, mo); P_SetScale(base, base->destscale = FixedMul(base->destscale, scale)); base->angle = mo->angle; base->scalespeed = FRACUNIT/2; @@ -264,10 +472,11 @@ static void SpawnRingShooter(player_t *player) base->fuse = RS_FUSE_TIME; // the ring shooter object itself is invisible and acts as the thinker - // each ring shooter uses three linked lists to keep track of its parts + // each ring shooter uses four linked lists to keep track of its parts // the hprev chain stores the two NIPPLE BARS // the hnext chain stores the four sides of the box // the tracer chain stores the screen and the screen layers + // the target chain stores the tire grabbers // spawn the RING NIPPLES part = base; @@ -343,14 +552,66 @@ static void SpawnRingShooter(player_t *player) P_SetMobjState(part, S_RINGSHOOTER_NUMBERBACK + i); part->renderflags |= RF_DONTDRAW; } + + // spawn the grabbers + part = base; + angle = base->angle + ANGLE_45; + for (i = 0; i < 4; i++) + { + const fixed_t dis = GetTireDist(base); + P_SetTarget( + &part->target, + P_SpawnMobjFromMobj( + base, + P_ReturnThrustX(NULL, angle, dis), + P_ReturnThrustY(NULL, angle, dis), + 0, + MT_TIREGRABBER + ) + ); + part = part->target; + P_SetTarget(&part->tracer, base); + + angle -= ANGLE_90; + part->angle = angle; + part->extravalue1 = part->extravalue2 = 0; + part->old_spriteyscale = part->spriteyscale = 0; + } + + ChangeRingShooterPointer(base, player); } void Obj_RingShooterInput(player_t *player) { + mobj_t *const base = player->ringShooter; + if (AllowRingShooter(player) == true - && (player->cmd.buttons & BT_RESPAWN) == BT_RESPAWN - && (player->oldcmd.buttons & BT_RESPAWN) == 0) + && (player->cmd.buttons & BT_RESPAWN) == BT_RESPAWN) { - SpawnRingShooter(player); + if (P_MobjWasRemoved(base) == true) + { + SpawnRingShooter(player); + return; + } + + if (rs_base_canceled(base) != 0) + { + if (base->fuse < TICRATE) + { + base->renderflags &= ~RF_DONTDRAW; + UpdateRingShooterPartsVisibility(base); + } + + base->fuse = RS_FUSE_TIME; + } + } + else if (P_MobjWasRemoved(base) == false) + { + if (rs_base_scalestate(base) != -1) + { + // We released during the intro animation. + // Cancel it entirely. + rs_base_canceled(base) = 1; + } } } diff --git a/src/p_mobj.c b/src/p_mobj.c index f26eeaea6..af2394298 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -6642,7 +6642,10 @@ static void P_MobjSceneryThink(mobj_t *mobj) } break; case MT_RINGSHOOTER: - Obj_RingShooterThinker(mobj); + if (Obj_RingShooterThinker(mobj) == false) + { + return; + } break; case MT_SPINDASHWIND: case MT_DRIFTELECTRICSPARK: @@ -11143,26 +11146,10 @@ void P_RemoveMobj(mobj_t *mobj) iquetail = (iquetail+1)&(ITEMQUESIZE-1); } - if (mobj->type == MT_KARMAHITBOX) // Remove linked list objects for certain types - { - mobj_t *cur = mobj->hnext; - - while (cur && !P_MobjWasRemoved(cur)) - { - mobj_t *prev = cur; // Kind of a dumb var, but we need to set cur before we remove the mobj - cur = cur->hnext; - P_RemoveMobj(prev); - } - } - - if (mobj->type == MT_OVERLAY) - P_RemoveOverlay(mobj); - - if (mobj->type == MT_SPB) - spbplace = -1; - if (P_IsTrackerType(mobj->type)) + { P_RemoveTracker(mobj); + } if (mobj->player && mobj->player->followmobj) { @@ -11170,19 +11157,56 @@ void P_RemoveMobj(mobj_t *mobj) P_SetTarget(&mobj->player->followmobj, NULL); } - if (mobj->type == MT_SHRINK_POHBEE) + // Remove linked list objects for certain types + switch (mobj->type) { - Obj_PohbeeRemoved(mobj); - } + case MT_KARMAHITBOX: + { + mobj_t *cur = mobj->hnext; - if (mobj->type == MT_SHRINK_GUN) - { - Obj_ShrinkGunRemoved(mobj); - } + while (cur && !P_MobjWasRemoved(cur)) + { + mobj_t *prev = cur; // Kind of a dumb var, but we need to set cur before we remove the mobj + cur = cur->hnext; + P_RemoveMobj(prev); + } - if (mobj->type == MT_SPECIAL_UFO_PIECE) - { - Obj_UFOPieceRemoved(mobj); + break; + } + case MT_OVERLAY: + { + P_RemoveOverlay(mobj); + break; + } + case MT_SPB: + { + spbplace = -1; + break; + } + case MT_SHRINK_POHBEE: + { + Obj_PohbeeRemoved(mobj); + break; + } + case MT_SHRINK_GUN: + { + Obj_ShrinkGunRemoved(mobj); + break; + } + case MT_SPECIAL_UFO_PIECE: + { + Obj_UFOPieceRemoved(mobj); + break; + } + case MT_RINGSHOOTER: + { + Obj_RingShooterDelete(mobj); + break; + } + default: + { + break; + } } mobj->health = 0; // Just because diff --git a/src/p_saveg.c b/src/p_saveg.c index c31161f40..0e335c210 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -63,14 +63,15 @@ savedata_t savedata; // than an UINT16 typedef enum { - AWAYVIEW = 0x01, - FOLLOWITEM = 0x02, - FOLLOWER = 0x04, - SKYBOXVIEW = 0x08, - SKYBOXCENTER = 0x10, - HOVERHYUDORO = 0x20, - STUMBLE = 0x40, - SLIPTIDEZIP = 0x80 + AWAYVIEW = 0x0001, + FOLLOWITEM = 0x0002, + FOLLOWER = 0x0004, + SKYBOXVIEW = 0x0008, + SKYBOXCENTER = 0x0010, + HOVERHYUDORO = 0x0020, + STUMBLE = 0x0040, + SLIPTIDEZIP = 0x0080, + RINGSHOOTER = 0x0100 } player_saveflags; static inline void P_ArchivePlayer(savebuffer_t *save) @@ -217,6 +218,9 @@ static void P_NetArchivePlayers(savebuffer_t *save) if (players[i].sliptideZipIndicator) flags |= SLIPTIDEZIP; + if (players[i].ringShooter) + flags |= RINGSHOOTER; + WRITEUINT16(save->p, flags); if (flags & SKYBOXVIEW) @@ -240,6 +244,9 @@ static void P_NetArchivePlayers(savebuffer_t *save) if (flags & SLIPTIDEZIP) WRITEUINT32(save->p, players[i].sliptideZipIndicator->mobjnum); + if (flags & RINGSHOOTER) + WRITEUINT32(save->p, players[i].ringShooter->mobjnum); + WRITEUINT32(save->p, (UINT32)players[i].followitem); WRITEUINT32(save->p, players[i].charflags); @@ -613,6 +620,9 @@ static void P_NetUnArchivePlayers(savebuffer_t *save) if (flags & SLIPTIDEZIP) players[i].sliptideZipIndicator = (mobj_t *)(size_t)READUINT32(save->p); + if (flags & RINGSHOOTER) + players[i].ringShooter = (mobj_t *)(size_t)READUINT32(save->p); + players[i].followitem = (mobjtype_t)READUINT32(save->p); //SetPlayerSkinByNum(i, players[i].skin); @@ -4823,6 +4833,13 @@ static void P_RelinkPointers(void) if (!P_SetTarget(&players[i].sliptideZipIndicator, P_FindNewPosition(temp))) CONS_Debug(DBG_GAMELOGIC, "sliptideZipIndicator not found on player %d\n", i); } + if (players[i].ringShooter) + { + temp = (UINT32)(size_t)players[i].ringShooter; + players[i].ringShooter = NULL; + if (!P_SetTarget(&players[i].ringShooter, P_FindNewPosition(temp))) + CONS_Debug(DBG_GAMELOGIC, "ringShooter not found on player %d\n", i); + } } }