Merge branch 'dashrings' into 'master'

Hardcode MT_DASHRING & MT_RAINBOWDASHRING

See merge request KartKrew/Kart!1345
This commit is contained in:
Oni 2023-07-29 18:29:08 +00:00 committed by NepDisk
parent b4a2215711
commit f6914942e7
18 changed files with 541 additions and 8 deletions

View file

@ -127,6 +127,7 @@ typedef enum
// Specific level gimmicks.
CR_SLIDING,
CR_ZOOMTUBE,
CR_DASHRING,
} carrytype_t; // carry
typedef enum
@ -684,6 +685,9 @@ struct player_t
UINT8 confirmVictim; // Player ID that you dealt damage to
UINT8 confirmVictimDelay; // Delay before playing the sound
UINT8 dashRingPullTics; // Timer during which the player is pulled towards a dash ring
UINT8 dashRingPushTics; // Timer during which the player displays effects and has no gravity after being thrust by a dash ring
INT32 interpoints; // BlanKart (port from SRB2Kart CEP): override for number of points earned in intermission
UINT32 roundscore; // battle score this round
UINT8 emeralds;

View file

@ -163,9 +163,7 @@ actionpointer_t actionpointers[] =
#define _(name, upper, ...) {name, "A_"#upper},
#include "info/actions.h"
#undef _
{NULL, "NONE"},
// This NULL entry must be the last in the list
{NULL, NULL},
};

View file

@ -222,3 +222,4 @@ _(A_RoamingShadowThinker, ROAMINGSHADOWTHINKER)
_(A_MayonakaArrow, MAYONAKAARROW)
_(A_MementosTPParticles, MEMENTOSTPPARTICLES)
_(A_ReaperThinker, REAPERTHINKER)
_(A_SpawnSneakerPanel, SPAWNSNEAKERPANEL)

View file

@ -860,3 +860,11 @@ _(LOOPENDPOINT)
_(LOOPCENTERPOINT)
_(SCRIPT_THING)
// Dash Rings
_(DASHRING)
_(RAINBOWDASHRING)
// Sneaker Panels
_(SNEAKERPANEL)
_(SNEAKERPANELSPAWNER)

View file

@ -641,5 +641,13 @@ _(BKAD) // Airdrop Dust
_(TRCK)
// Dash Rings
_(RAIR)
// Sneaker Panels
_(BSTP)
_(BSTS)
_(BSTT)
// First person view sprites; this is a sprite so that it can be replaced by a specialized MD2 draw later
_(VIEW)

View file

@ -3593,3 +3593,23 @@ _(AIRDROPDUST2)
_(SLIPSPARK1)
_(SLIPSPARK2)
_(SLIPSPARK3)
// Dash Rings
_(DASHRING_HORIZONTAL)
_(DASHRING_30DEGREES)
_(DASHRING_60DEGREES)
_(DASHRING_VERTICAL)
_(DASHRING_HORIZONTAL_FLASH1)
_(DASHRING_HORIZONTAL_FLASH2)
_(DASHRING_30DEGREES_FLASH1)
_(DASHRING_30DEGREES_FLASH2)
_(DASHRING_60DEGREES_FLASH1)
_(DASHRING_60DEGREES_FLASH2)
_(DASHRING_VERTICAL_FLASH1)
_(DASHRING_VERTICAL_FLASH2)
// Sneaker Panels
_(SNEAKERPANEL)
_(SNEAKERPANEL_SMALL)
_(SNEAKERPANEL_TINY)
_(SNEAKERPANELSPAWNER)

View file

@ -3385,7 +3385,6 @@ void K_SquishPlayer(player_t *player, mobj_t *inflictor, mobj_t *source)
}
player->mo->flags |= MF_NOCLIP;
player->instashield = 15;
}
@ -3420,6 +3419,7 @@ INT32 K_ExplodePlayer(player_t *player, mobj_t *inflictor, mobj_t *source) // A
player->mo->momz = 18*mapobjectscale*P_MobjFlip(player->mo); // please stop forgetting mobjflip checks!!!!
if (player->mo->eflags & MFE_UNDERWATER)
player->mo->momz = (117 * player->mo->momz) / 200;
player->mo->momx = player->mo->momy = 0;
player->spinouttype = KSPIN_EXPLOSION;
@ -6802,6 +6802,8 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
K_UpdateEngineSounds(player); // Thanks, VAda!
Obj_DashRingPlayerThink(player);
// update boost angle if not spun out
if (!K_IsPlayerDamaged(player) && !player->wipeoutslow)
player->boostangle = player->mo->angle;

View file

@ -15,6 +15,21 @@ void Obj_InitLoopCenter(mobj_t *center);
void Obj_LinkLoopAnchor(mobj_t *anchor, mobj_t *center, UINT8 type);
void Obj_LoopEndpointCollide(mobj_t *special, mobj_t *toucher);
/* Dash Rings */
void Obj_RegularDashRingSpawn(mobj_t *mobj);
void Obj_RainbowDashRingSpawn(mobj_t *mobj);
void Obj_DashRingSetup(mobj_t *mobj, mapthing_t *mthing);
void Obj_RainbowDashRingThink(mobj_t *mobj);
void Obj_DashRingTouch(mobj_t *mobj, player_t *player);
void Obj_DashRingPlayerThink(player_t *player);
boolean Obj_DashRingPlayerHasNoGravity(player_t *player);
/* Sneaker Panels */
void Obj_SneakerPanelSpriteScale(mobj_t *mobj);
void Obj_SneakerPanelSpawn(mobj_t *mobj);
void Obj_SneakerPanelSetup(mobj_t *mobj, mapthing_t *mthing);
void Obj_SneakerPanelCollide(mobj_t *pad, mobj_t *mo);
#ifdef __cplusplus
} // extern "C"
#endif

View file

@ -1,3 +1,5 @@
target_sources(SRB2SDL2 PRIVATE
loops.cpp
dash-rings.c
sneaker-panel.c
)

267
src/objects/dash-rings.c Normal file
View file

@ -0,0 +1,267 @@
#include "../p_local.h"
#include "../k_kart.h"
#include "../k_objects.h"
#include "../s_sound.h"
// Dash Rings are scaled by this much relative to the map scale
#define DASHRING_SCALE (3*FRACUNIT/2)
// Dash Ring angles are defined by their mapthing's args[0] (previously used mapthing->options flags, hence the selections)
#define DASHRING_TYPE_HORIZONTAL 0
#define DASHRING_TYPE_30DEGREES 1
#define DASHRING_TYPE_60DEGREES 4
#define DASHRING_TYPE_VERTICAL 8
// Dash Rings must be this far apart for players to interact with them in succession
#define DASHRING_MIN_SPACING_HORIZONTAL (512*FRACUNIT)
#define DASHRING_MIN_SPACING_VERTICAL (384*FRACUNIT)
// timer values
#define DASHRING_PULL_TICS 5
#define DASHRING_PUSH_TICS (TICRATE/2)
#define DASHRING_ANTIGRAVITY_TICS 5
// base launch speed
#define DASHRING_BASE_LAUNCH_SPEED (48*FRACUNIT)
// factor of distance traveled per tic while being pulled towards a Dash Ring
#define DASHRING_PULL_FACTOR (FRACUNIT/3)
static const skincolornum_t ring_colors[] = {
SKINCOLOR_GREY, // 1x
SKINCOLOR_TAN, // 1.25x
SKINCOLOR_YELLOW, // 1.5x
SKINCOLOR_TANGERINE, // 1.75x
SKINCOLOR_KETCHUP, // 2x
SKINCOLOR_MOONSET, // 2.25x
SKINCOLOR_ULTRAMARINE, // 2.5x +
};
static const skincolornum_t rainbow_colors[] = {
SKINCOLOR_PINK,
SKINCOLOR_CREAMSICLE,
SKINCOLOR_TAN,
SKINCOLOR_TURTLE,
SKINCOLOR_TURQUOISE,
SKINCOLOR_THISTLE,
};
void Obj_RegularDashRingSpawn(mobj_t *mobj)
{
P_SetScale(mobj, mobj->destscale = FixedMul(mobj->scale, DASHRING_SCALE));
mobj->renderflags |= RF_SEMIBRIGHT;
P_SetTarget(&mobj->tracer, P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_OVERLAY));
P_SetTarget(&mobj->tracer->target, mobj);
P_SetMobjState(mobj->tracer, S_DASHRING_HORIZONTAL_FLASH1);
mobj->tracer->color = SKINCOLOR_WHITE;
mobj->tracer->renderflags |= RF_SEMIBRIGHT;
}
void Obj_RainbowDashRingSpawn(mobj_t *mobj)
{
P_SetScale(mobj, mobj->destscale = FixedMul(mobj->scale, DASHRING_SCALE));
mobj->renderflags |= RF_FULLBRIGHT;
}
void Obj_DashRingSetup(mobj_t *mobj, mapthing_t *mthing)
{
static const UINT8 numColors = sizeof(rainbow_colors) / sizeof(skincolornum_t);
const UINT8 additionalThrust = mthing->args[1];
statenum_t ringState, overlayState;
mobj->extravalue1 = mthing->args[0];
mobj->cusval = 4 + additionalThrust;
switch (mobj->extravalue1)
{
case DASHRING_TYPE_30DEGREES:
ringState = S_DASHRING_30DEGREES;
overlayState = S_DASHRING_30DEGREES_FLASH1;
break;
case DASHRING_TYPE_60DEGREES:
ringState = S_DASHRING_60DEGREES;
overlayState = S_DASHRING_60DEGREES_FLASH1;
break;
case DASHRING_TYPE_VERTICAL:
ringState = S_DASHRING_VERTICAL;
overlayState = S_DASHRING_VERTICAL_FLASH1;
break;
case DASHRING_TYPE_HORIZONTAL:
default:
ringState = S_DASHRING_HORIZONTAL;
overlayState = S_DASHRING_HORIZONTAL_FLASH1;
break;
}
P_SetMobjState(mobj, ringState);
if (!P_MobjWasRemoved(mobj->tracer))
P_SetMobjState(mobj->tracer, overlayState);
mobj->spriteyoffset = mobj->info->height >> 1; // I think this is to center the sprite within its hitbox regardless of height
mobj->color = ring_colors[min(additionalThrust, numColors - 1)];
}
void Obj_RainbowDashRingThink(mobj_t *mobj)
{
static const UINT8 numColors = sizeof(rainbow_colors) / sizeof(skincolornum_t);
mobj->color = rainbow_colors[(leveltime / 2) % numColors];
}
static boolean DashRingsAreTooClose(mobj_t *ring1, mobj_t *ring2)
{
if (ring1 == ring2)
return true;
if ((FixedHypot(ring2->x - ring1->x, ring2->y - ring1->y) < FixedMul(DASHRING_MIN_SPACING_HORIZONTAL, mapobjectscale))
&& (abs(ring1->z - ring2->z) < FixedMul(DASHRING_MIN_SPACING_VERTICAL, mapobjectscale)))
return true;
return false;
}
void Obj_DashRingTouch(mobj_t *ring, player_t *player)
{
if (player->carry != CR_NONE)
{
if (player->carry != CR_DASHRING) // being carried by something else
return;
if (player->dashRingPullTics > 0) // being pulled into a dash ring already
return;
if (player->dashRingPushTics > 0 && !P_MobjWasRemoved(player->mo->tracer) && DashRingsAreTooClose(player->mo->tracer, ring)) // dash ring is too close to recently used dash ring
return;
}
P_SetTarget(&player->mo->tracer, ring);
player->carry = CR_DASHRING;
player->dashRingPullTics = DASHRING_PULL_TICS;
player->dashRingPushTics = 0;
}
static fixed_t GetPlayerDashRingZ(player_t *player, mobj_t *ring)
{
return (ring->z + (ring->height >> 1) - (player->mo->height >> 1));
}
static void DashRingLaunch(player_t *player, mobj_t *ring)
{
mobj_t *ghost = P_SpawnGhostMobj(ring);
const fixed_t launchSpeed = FixedMul(DASHRING_BASE_LAUNCH_SPEED * ring->cusval / 4, mapobjectscale);
angle_t pitch;
ghost->destscale = ring->scale * 8;
ghost->scalespeed = ring->scale / 12;
ghost->old_z = ghost->z += P_MobjFlip(ring) * FixedMul(ghost->spriteyoffset, ghost->scale); // apply sprite offset to physical position instead, so ghost is centered
ghost->spriteyoffset = 0;
P_MoveOrigin(player->mo, ring->x, ring->y, GetPlayerDashRingZ(player, ring));
player->dashRingPullTics = 0;
player->dashRingPushTics = DASHRING_PUSH_TICS;
player->mo->rollangle = 0;
player->flashing = 0;
player->fastfall = 0;
switch (ring->extravalue1)
{
case DASHRING_TYPE_30DEGREES:
pitch = 30 * ANG1;
break;
case DASHRING_TYPE_60DEGREES:
pitch = 60 * ANG1;
break;
case DASHRING_TYPE_VERTICAL:
pitch = 90 * ANG1;
break;
case DASHRING_TYPE_HORIZONTAL:
default:
pitch = 0;
break;
}
P_InstaThrust(player->mo, ring->angle, P_ReturnThrustX(NULL, pitch, launchSpeed));
player->mo->momz = P_MobjFlip(ring) * P_ReturnThrustY(NULL, pitch, launchSpeed);
S_StartSound(player->mo, ring->info->seesound);
}
static void RegularDashRingLaunch(player_t *player, mobj_t *ring)
{
player->springstars = TICRATE/2;
player->springcolor = ring->color;
DashRingLaunch(player, ring);
}
static void RainbowDashRingLaunch(player_t *player, mobj_t *ring)
{
player->mo->eflags &= ~MFE_SPRUNG;
player->trickpanel = 1;
player->pflags |= PF_TRICKDELAY;
K_DoPogoSpring(player->mo, 0, 0);
DashRingLaunch(player, ring);
}
void Obj_DashRingPlayerThink(player_t *player)
{
if (player->carry != CR_DASHRING)
return;
if (player->dashRingPullTics > 0)
{
mobj_t *ring = player->mo->tracer;
if (P_MobjWasRemoved(player->mo->tracer))
{
player->carry = CR_NONE;
player->dashRingPullTics = 0;
}
else
{
player->mo->momx = FixedMul(DASHRING_PULL_FACTOR, ring->x - player->mo->x);
player->mo->momy = FixedMul(DASHRING_PULL_FACTOR, ring->y - player->mo->y);
player->mo->momz = FixedMul(DASHRING_PULL_FACTOR, GetPlayerDashRingZ(player, ring) - player->mo->z);
player->mo->rollangle = (angle_t)FixedMul(DASHRING_PULL_FACTOR, (fixed_t)player->mo->rollangle);
if (--player->dashRingPullTics == 0)
{
if (ring->type == MT_DASHRING)
{
RegularDashRingLaunch(player, ring);
}
else
{
RainbowDashRingLaunch(player, ring);
}
}
}
}
if (player->dashRingPushTics > 0)
{
if (leveltime & 1)
{
mobj_t *ghost = P_SpawnGhostMobj(player->mo);
ghost->colorized = true;
ghost->fuse = 3;
}
if (--player->dashRingPushTics == 0)
{
player->carry = CR_NONE;
P_SetTarget(&player->mo->tracer, NULL);
}
}
}
boolean Obj_DashRingPlayerHasNoGravity(player_t *player)
{
if (player->dashRingPullTics > 0)
return true;
if (player->dashRingPushTics >= DASHRING_PUSH_TICS - DASHRING_ANTIGRAVITY_TICS)
return true;
return false;
}

122
src/objects/sneaker-panel.c Normal file
View file

@ -0,0 +1,122 @@
#include "../r_main.h"
#include "../p_slopes.h"
#include "../p_local.h"
#include "../k_kart.h"
#define SNEAKERPANEL_RADIUS (64*FRACUNIT)
void Obj_SneakerPanelSpriteScale(mobj_t *mobj)
{
statenum_t newState;
fixed_t spriteScale;
if (mobj->scale == mobj->movefactor)
return;
mobj->movefactor = mobj->scale;
if (mobj->scale > FRACUNIT >> 1)
{
newState = S_SNEAKERPANEL;
spriteScale = FRACUNIT;
}
else if (mobj->scale > FRACUNIT >> 2)
{
newState = S_SNEAKERPANEL_SMALL;
spriteScale = FRACUNIT << 1;
}
else
{
newState = S_SNEAKERPANEL_TINY;
spriteScale = FRACUNIT << 2;
}
if (((statenum_t)(mobj->state - states)) != newState)
{
P_SetMobjState(mobj, newState);
mobj->spritexscale = mobj->spriteyscale = spriteScale;
}
}
void Obj_SneakerPanelSpawn(mobj_t *mobj)
{
mobj->renderflags |= RF_OBJECTSLOPESPLAT | RF_NOSPLATBILLBOARD;
Obj_SneakerPanelSpriteScale(mobj);
}
void Obj_SneakerPanelSetup(mobj_t *mobj, mapthing_t *mthing)
{
if (mthing->options & MTF_OBJECTFLIP)
{
mobj->eflags |= MFE_VERTICALFLIP;
mobj->flags2 |= MF2_OBJECTFLIP;
}
P_TryMove(mobj, mobj->x, mobj->y, true, NULL); // sets standingslope
Obj_SneakerPanelSpriteScale(mobj);
}
void Obj_SneakerPanelCollide(mobj_t *panel, mobj_t *mo)
{
pslope_t *slope = panel->standingslope;
player_t *player = mo->player;
fixed_t playerTop = mo->z + mo->height, playerBottom = mo->z;
fixed_t panelTop, panelBottom, dist, x, y, radius;
angle_t angle;
// only players can boost!
if (player == NULL)
return;
// these aren't aerial boosters, so you do need to be on the ground
if (!P_IsObjectOnGround(mo))
return;
// player needs to have the same gravflip status as the panel
if ((panel->eflags & MFE_VERTICALFLIP) != (mo->eflags & MFE_VERTICALFLIP))
return;
// find the x and y coordinates of the player relative to the booster's angle
dist = R_PointToDist2(panel->x, panel->y, mo->x, mo->y);
angle = R_PointToAngle2(panel->x, panel->y, mo->x, mo->y) - panel->angle;
x = P_ReturnThrustX(NULL, angle, dist);
y = P_ReturnThrustY(NULL, angle, dist);
// check that these coordinates fall within the square panel
radius = FixedMul(SNEAKERPANEL_RADIUS, panel->scale);
if (x < -radius || x > radius || y < -radius || y > radius)
return; // out of bounds
// check that the player is within reasonable vertical bounds
if (slope == NULL)
{
panelTop = panel->z + panel->height;
panelBottom = panel->z;
}
else
{
x = P_ReturnThrustX(NULL, slope->xydirection, panel->radius);
y = P_ReturnThrustY(NULL, slope->xydirection, panel->radius);
panelTop = P_GetSlopeZAt(slope, panel->x + x, panel->y + y);
panelBottom = P_GetSlopeZAt(slope, panel->x - x, panel->y - y);
if (panelTop < panelBottom)
{
// variable swap
panelTop = panelTop + panelBottom;
panelBottom = panelTop - panelBottom;
panelTop = panelTop - panelBottom;
}
}
if ((playerBottom > panelTop) || (playerTop < panelBottom))
return;
// boost!
if (player->floorboost == 0)
player->floorboost = 3;
else
player->floorboost = 2;
K_DoSneaker(player, 0);
}

View file

@ -11953,3 +11953,35 @@ void A_ReaperThinker(void *thing)
}
}
}
// Function: A_SpawnSneakerPanel
//
// Description: Spawns a sneaker panel object relative to the location of the actor
//
// var1:
// var1 >> 16 = x offset
// var1 & 65535 = y offset
// var2:
// var2 >> 16 = z
// var2 & 65535 = unused
//
void A_SpawnSneakerPanel(mobj_t *actor)
{
INT16 x, y, z;
mobj_t *mo;
INT32 locvar1 = var1;
INT32 locvar2 = var2;
if (LUA_CallAction(A_SPAWNSNEAKERPANEL, actor))
{
return;
}
x = (INT16)(locvar1 >> 16);
y = (INT16)(locvar1 & 65535);
z = (INT16)(locvar2 >> 16);
mo = P_SpawnMobjFromMobj(actor, x << FRACBITS, y << FRACBITS, z << FRACBITS, MT_SNEAKERPANEL);
mo->angle = actor->angle;
Obj_SneakerPanelSpriteScale(mo);
}

View file

@ -921,6 +921,11 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
}
return;
case MT_DASHRING:
case MT_RAINBOWDASHRING:
Obj_DashRingTouch(special, player);
return;
default: // SOC or script pickup
P_SetTarget(&special->target, toucher);
break;

View file

@ -874,6 +874,17 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing)
return K_FallingRockCollide(thing, g_tm.thing) ? BMIT_CONTINUE : BMIT_ABORT;
}
if (thing->type == MT_SNEAKERPANEL)
{
Obj_SneakerPanelCollide(thing, tm.thing);
return BMIT_CONTINUE;
}
else if (tm.thing->type == MT_SNEAKERPANEL)
{
Obj_SneakerPanelCollide(tm.thing, thing);
return BMIT_CONTINUE;
}
//}
if ((thing->type == MT_SPRINGSHELL || thing->type == MT_YELLOWSHELL) && thing->health > 0

View file

@ -133,11 +133,10 @@ static void P_SetupStateAnimation(mobj_t *mobj, state_t *st)
if (st->frame & FF_GLOBALANIM)
{
// Attempt to account for the pre-ticker for objects spawned on load
if (!leveltime) return;
mobj->anim_duration -= (leveltime + 2) % st->var2; // Duration synced to timer
mobj->frame += ((leveltime + 2) / st->var2) % (animlength + 1); // Frame synced to timer (duration taken into account)
mobj->anim_duration -= (leveltime % st->var2); // Duration synced to timer
mobj->frame += (leveltime / st->var2) % (animlength + 1); // Frame synced to timer (duration taken into account)
if (!thinkersCompleted) // objects spawned BEFORE (or during) thinkers will think during this tic...
mobj->anim_duration++; // ...so increase the duration of their current frame by 1 to sync with objects spawned AFTER thinkers
}
else if (st->frame & FF_RANDOMANIM)
{
@ -1175,6 +1174,11 @@ fixed_t P_GetMobjGravity(mobj_t *mo)
{
gravityadd = (5*gravityadd)/2;
}
if (mo->player->carry == CR_DASHRING && Obj_DashRingPlayerHasNoGravity(mo->player))
{
gravityadd = 0;
}
}
else
{
@ -10160,6 +10164,9 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
trail->color = mobj->color;
}
break;
case MT_RAINBOWDASHRING:
Obj_RainbowDashRingThink(mobj);
break;
default:
// check mobj against possible water content, before movement code
P_MobjCheckWater(mobj);
@ -10986,6 +10993,9 @@ static void P_DefaultMobjShadowScale(mobj_t *thing)
case MT_EMBLEM:
thing->shadowscale = FRACUNIT/3;
break;
case MT_SNEAKERPANEL:
thing->shadowscale = 0;
break;
default:
if (thing->flags & (MF_ENEMY|MF_BOSS))
thing->shadowscale = FRACUNIT;
@ -11484,6 +11494,15 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
break;
case MT_TUMBLEGEM:
mobj->color = P_RandomKey(numskincolors - 1) + 1;
case MT_DASHRING:
Obj_RegularDashRingSpawn(mobj);
break;
case MT_RAINBOWDASHRING:
Obj_RainbowDashRingSpawn(mobj);
break;
case MT_SNEAKERPANEL:
Obj_SneakerPanelSpawn(mobj);
break;
default:
break;
}
@ -13731,6 +13750,17 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean
if (mapnamespace == MNS_SRB2KART)
mobj->flags ^= MF_NOGRAVITY;
}
case MT_DASHRING:
case MT_RAINBOWDASHRING:
{
Obj_DashRingSetup(mobj, mthing);
break;
}
case MT_SNEAKERPANEL:
{
Obj_SneakerPanelSetup(mobj, mthing);
break;
}
default:
break;
}

View file

@ -712,6 +712,9 @@ static void P_NetSyncPlayers(savebuffer_t *save)
SYNC(players[i].karmapoints);
SYNC(players[i].wanted);
SYNC(players[i].dashRingPullTics);
SYNC(players[i].dashRingPushTics);
SYNC(players[i].glanceDir);
SYNC(players[i].breathTimer);

View file

@ -50,6 +50,7 @@
#endif
tic_t leveltime;
boolean thinkersCompleted;
UINT32 thinker_era = 0;
@ -660,6 +661,8 @@ void P_Ticker(boolean run)
{
INT32 i;
thinkersCompleted = false;
// Increment jointime and quittime even if paused
for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i])
@ -782,6 +785,7 @@ void P_Ticker(boolean run)
ps_thinkertime = I_GetPreciseTime();
P_RunThinkers();
ps_thinkertime = I_GetPreciseTime() - ps_thinkertime;
thinkersCompleted = true;
// Run any "after all the other thinkers" stuff
for (i = 0; i < MAXPLAYERS; i++)

View file

@ -21,6 +21,7 @@ extern "C" {
#endif
extern tic_t leveltime;
extern boolean thinkersCompleted;
// Called by G_Ticker. Carries out all thinking of enemies and players.
void Command_Numthinkers_f(void);