From 661d8818d698bf76711bf6efe57fe71e8151dc67 Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 10 Apr 2021 19:37:20 -0700 Subject: [PATCH 01/20] Squash and stretch player sprite with sudden changes in vertical momentum Stretch with a sudden increase of momentum, squash with a decrease. --- src/d_player.h | 1 + src/k_kart.c | 1 + src/p_user.c | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 39 insertions(+) diff --git a/src/d_player.h b/src/d_player.h index 08a0f1cde..a245bf096 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -597,6 +597,7 @@ typedef struct player_s fixed_t speed; // Player's speed (distance formula of MOMX and MOMY values) fixed_t lastspeed; + fixed_t lastmomz; UINT8 secondjump; // Jump counter UINT8 fly1; // Tails flying diff --git a/src/k_kart.c b/src/k_kart.c index 280916f57..bf8065e49 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -2288,6 +2288,7 @@ void K_KartMoveAnimation(player_t *player) // Update lastspeed value -- we use to display slow driving frames instead of fast driving when slowing down. player->lastspeed = player->speed; + player->lastmomz = player->mo->momz; } static void K_TauntVoiceTimers(player_t *player) diff --git a/src/p_user.c b/src/p_user.c index 0ea75e3bf..9c3c7a30f 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1845,6 +1845,41 @@ static void P_DoBubbleBreath(player_t *player) } } +static void squish(player_t *player) +{ + const fixed_t maxstretch = 2*FRACUNIT; + const fixed_t factor = 3 * player->mo->height / 2; + const fixed_t threshold = factor / 6; + + const fixed_t old3dspeed = abs(player->lastmomz); + const fixed_t new3dspeed = abs(player->mo->momz); + + const fixed_t delta = abs(old3dspeed - new3dspeed); + + if (delta > threshold) + { + player->mo->spritexscale = + FRACUNIT + FixedDiv(delta, factor); + + if (player->mo->spritexscale > maxstretch) + player->mo->spritexscale = maxstretch; + + if (abs(new3dspeed) > abs(old3dspeed)) + { + player->mo->spritexscale = + FixedDiv(FRACUNIT, player->mo->spritexscale); + } + } + else + { + player->mo->spritexscale -= + (player->mo->spritexscale - FRACUNIT) / 8; + } + + player->mo->spriteyscale = + FixedDiv(FRACUNIT, player->mo->spritexscale); +} + //#define OLD_MOVEMENT_CODE 1 static void P_3dMovement(player_t *player) { @@ -2031,6 +2066,8 @@ static void P_3dMovement(player_t *player) } } } + + squish(player); } // From 9771a6405320ab5f02293648cf9641dd2fca91c3 Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 11 Apr 2021 01:04:33 -0700 Subject: [PATCH 02/20] Unsquash the player more quickly Also don't apply squashing/stretching on slope launches. --- src/p_user.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/p_user.c b/src/p_user.c index 9c3c7a30f..0cba996ff 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1873,7 +1873,8 @@ static void squish(player_t *player) else { player->mo->spritexscale -= - (player->mo->spritexscale - FRACUNIT) / 8; + (player->mo->spritexscale - FRACUNIT) + / (player->mo->spritexscale < FRACUNIT ? 8 : 2); } player->mo->spriteyscale = @@ -2067,7 +2068,10 @@ static void P_3dMovement(player_t *player) } } - squish(player); + if (!player->powers[pw_justlaunched]) + { + squish(player); + } } // From e2c0f6638f66094586e7fd3d4d2b1b29d3d3d64b Mon Sep 17 00:00:00 2001 From: lachablock Date: Mon, 2 Aug 2021 13:57:27 +1000 Subject: [PATCH 03/20] Fix item capsules in reverse gravity --- src/deh_tables.c | 7 +- src/info.c | 10 +-- src/info.h | 8 +- src/p_enemy.c | 189 --------------------------------------- src/p_local.h | 2 - src/p_mobj.c | 228 ++++++++++++++++++++++++++++++++++++++++++++--- 6 files changed, 228 insertions(+), 216 deletions(-) diff --git a/src/deh_tables.c b/src/deh_tables.c index a97d56865..154455a83 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -334,7 +334,6 @@ actionpointer_t actionpointers[] = {{A_ReaperThinker}, "A_REAPERTHINKER"}, {{A_FlameShieldPaper}, "A_FLAMESHIELDPAPER"}, {{A_InvincSparkleRotate}, "A_INVINCSPARKLEROTATE"}, - {{A_SpawnItemCapsuleParts}, "A_SPAWNITEMCAPSULEPARTS"}, {{NULL}, "NONE"}, @@ -3490,9 +3489,9 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi "S_ITEMCAPSULE_TOP_SIDE", "S_ITEMCAPSULE_BOTTOM_SIDE_AIR", "S_ITEMCAPSULE_BOTTOM_SIDE_GROUND", - "S_ITEMCAPSULE_TOP", - "S_ITEMCAPSULE_BOTTOM", - "S_ITEMCAPSULE_INSIDE", + //"S_ITEMCAPSULE_TOP", + //"S_ITEMCAPSULE_BOTTOM", + //"S_ITEMCAPSULE_INSIDE", // Signpost sparkles "S_SIGNSPARK1", diff --git a/src/info.c b/src/info.c index 7f2e06f56..67596f9b4 100644 --- a/src/info.c +++ b/src/info.c @@ -4067,13 +4067,13 @@ state_t states[NUMSTATES] = {SPR_NULL, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_ITEMICON - {SPR_ICAP, FF_ADD|0, -1, {A_SpawnItemCapsuleParts}, 0, 0, S_NULL}, // S_ITEMCAPSULE + {SPR_ICAP, FF_ADD|0, -1, {NULL}, 0, 0, S_NULL}, // S_ITEMCAPSULE {SPR_ICAP, FF_PAPERSPRITE|1, -1, {NULL}, 0, 0, S_NULL}, // S_ITEMCAPSULE_TOP_SIDE {SPR_ICAP, FF_VERTICALFLIP|FF_PAPERSPRITE|1, -1, {NULL}, 0, 0, S_NULL}, // S_ITEMCAPSULE_BOTTOM_SIDE_AIR {SPR_ICAP, FF_PAPERSPRITE|2, -1, {NULL}, 0, 0, S_NULL}, // S_ITEMCAPSULE_BOTTOM_SIDE_GROUND - {SPR_ICAP, FF_FLOORSPRITE|3, -1, {NULL}, 0, 0, S_NULL}, // S_ITEMCAPSULE_TOP - {SPR_ICAP, FF_FLOORSPRITE|4, -1, {NULL}, 0, 0, S_NULL}, // S_ITEMCAPSULE_BOTTOM - {SPR_ICAP, FF_FLOORSPRITE|5, -1, {NULL}, 0, 0, S_NULL}, // S_ITEMCAPSULE_INSIDE + //{SPR_ICAP, FF_FLOORSPRITE|3, -1, {NULL}, 0, 0, S_NULL}, // S_ITEMCAPSULE_TOP + //{SPR_ICAP, FF_FLOORSPRITE|4, -1, {NULL}, 0, 0, S_NULL}, // S_ITEMCAPSULE_BOTTOM + //{SPR_ICAP, FF_FLOORSPRITE|5, -1, {NULL}, 0, 0, S_NULL}, // S_ITEMCAPSULE_INSIDE {SPR_SGNS, FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_SIGNSPARK2}, // S_SIGNSPARK1 {SPR_SGNS, FF_FULLBRIGHT|1, 1, {NULL}, 0, 0, S_SIGNSPARK3}, // S_SIGNSPARK2 @@ -23088,7 +23088,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 0, // damage sfx_None, // activesound - MF_SLIDEME|MF_SPECIAL|MF_RUNSPAWNFUNC|MF_DONTENCOREMAP, // flags + MF_SLIDEME|MF_SPECIAL|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, diff --git a/src/info.h b/src/info.h index ab9456cae..8435889a5 100644 --- a/src/info.h +++ b/src/info.h @@ -287,7 +287,6 @@ enum actionnum A_REAPERTHINKER, A_FLAMESHIELDPAPER, A_INVINCSPARKLEROTATE, - A_SPAWNITEMCAPSULEPARTS, NUMACTIONS }; @@ -558,7 +557,6 @@ void A_ReaperThinker(); void A_MementosTPParticles(); void A_FlameShieldPaper(); void A_InvincSparkleRotate(); -void A_SpawnItemCapsuleParts(); extern boolean actionsoverridden[NUMACTIONS]; @@ -4465,9 +4463,9 @@ typedef enum state S_ITEMCAPSULE_TOP_SIDE, S_ITEMCAPSULE_BOTTOM_SIDE_AIR, S_ITEMCAPSULE_BOTTOM_SIDE_GROUND, - S_ITEMCAPSULE_TOP, - S_ITEMCAPSULE_BOTTOM, - S_ITEMCAPSULE_INSIDE, + //S_ITEMCAPSULE_TOP, + //S_ITEMCAPSULE_BOTTOM, + //S_ITEMCAPSULE_INSIDE, // Signpost sparkles S_SIGNSPARK1, diff --git a/src/p_enemy.c b/src/p_enemy.c index 9f5fc86d8..9dbeb8f5b 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -321,7 +321,6 @@ void A_ReaperThinker(mobj_t *actor); void A_MementosTPParticles(mobj_t *actor); void A_FlameShieldPaper(mobj_t *actor); void A_InvincSparkleRotate(mobj_t *actor); -void A_SpawnItemCapsuleParts(mobj_t *actor); //for p_enemy.c @@ -14652,191 +14651,3 @@ void A_InvincSparkleRotate(mobj_t *actor) actor->angle += ANG1*10*(actor->extravalue2); // Arbitrary value, change this if you want, I suppose. } - -void P_RefreshItemCapsuleParts(mobj_t *mobj) -{ - UINT8 numNumbers = 0; - INT32 count = 0; - INT32 itemType = mobj->threshold; - mobj_t *part; - skincolornum_t color; - UINT32 newRenderFlags = 0; - boolean colorized; - - if (itemType < 1 || itemType >= NUMKARTITEMS) - itemType = KITEM_SAD; - - // update invincibility properties - if (itemType == KITEM_INVINCIBILITY) - { - mobj->renderflags = (mobj->renderflags & ~RF_BRIGHTMASK) | RF_FULLBRIGHT; - mobj->colorized = true; - } - else - { - mobj->renderflags = (mobj->renderflags & ~RF_BRIGHTMASK) | RF_SEMIBRIGHT; - mobj->color = SKINCOLOR_NONE; - mobj->colorized = false; - } - - // update cap colors - if (itemType == KITEM_SUPERRING) - { - color = SKINCOLOR_GOLD; - newRenderFlags |= RF_SEMIBRIGHT; - } - else if (mobj->spawnpoint && (mobj->spawnpoint->options & MTF_EXTRA)) - color = SKINCOLOR_SAPPHIRE; - else if (itemType == KITEM_SPB) - color = SKINCOLOR_JET; - else - color = SKINCOLOR_NONE; - - colorized = (color != SKINCOLOR_NONE); - part = mobj; - while (!P_MobjWasRemoved(part->hnext)) - { - part = part->hnext; - part->color = color; - part->colorized = colorized; - part->renderflags = (part->renderflags & ~RF_BRIGHTMASK) | newRenderFlags; - } - - // update inside item frame - part = mobj->tracer; - if (P_MobjWasRemoved(part)) - return; - - part->threshold = mobj->threshold; - part->movecount = mobj->movecount; - - switch (itemType) - { - case KITEM_ORBINAUT: - part->sprite = SPR_ITMO; - part->frame = FF_FULLBRIGHT|FF_PAPERSPRITE|K_GetOrbinautItemFrame(mobj->movecount); - break; - case KITEM_INVINCIBILITY: - part->sprite = SPR_ITMI; - part->frame = FF_FULLBRIGHT|FF_PAPERSPRITE|K_GetInvincibilityItemFrame(); - break; - case KITEM_SAD: - part->sprite = SPR_ITEM; - part->frame = FF_FULLBRIGHT|FF_PAPERSPRITE; - break; - default: - part->sprite = SPR_ITEM; - part->frame = FF_FULLBRIGHT|FF_PAPERSPRITE|(itemType); - break; - } - - // update number frame - if (K_GetShieldFromItem(itemType) != KSHIELD_NONE) // shields don't stack, so don't show a number - ; - else - { - switch (itemType) - { - case KITEM_ORBINAUT: // only display the number when the sprite no longer changes - if (mobj->movecount - 1 > K_GetOrbinautItemFrame(mobj->movecount)) - count = mobj->movecount; - break; - case KITEM_SUPERRING: // always display the number, and multiply it by 5 - count = mobj->movecount * 5; - break; - case KITEM_SAD: // never display the number - case KITEM_SPB: - break; - default: - if (mobj->movecount > 1) - count = mobj->movecount; - break; - } - } - - while (count > 0) - { - if (P_MobjWasRemoved(part->tracer)) - { - P_SetTarget(&part->tracer, P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_OVERLAY)); - P_SetTarget(&part->tracer->target, part); - P_SetMobjState(part->tracer, S_INVISIBLE); - part->tracer->spriteyoffset = 10*FRACUNIT; - part->tracer->spritexoffset = 13*numNumbers*FRACUNIT; - } - part = part->tracer; - part->sprite = SPR_ITMN; - part->frame = FF_FULLBRIGHT|(count % 10); - count /= 10; - numNumbers++; - } - - // delete any extra overlays (I guess in case the number changes?) - if (part->tracer) - { - P_RemoveMobj(part->tracer); - P_SetTarget(&part->tracer, NULL); - } -} - -#define CAPSULESIDES 5 -#define ANG_CAPSULE (UINT32_MAX / CAPSULESIDES) -#define ROTATIONSPEED (2*ANG2) -void A_SpawnItemCapsuleParts(mobj_t *actor) -{ - UINT8 i; - mobj_t *part; - fixed_t buttScale = 0; - statenum_t buttState = S_ITEMCAPSULE_BOTTOM_SIDE_AIR; - angle_t spin = ANGLE_MAX - ROTATIONSPEED; - - if (LUA_CallAction(A_SPAWNITEMCAPSULEPARTS, actor)) - return; - - if (P_IsObjectOnGround(actor)) - { - buttScale = 13*FRACUNIT/10; - buttState = S_ITEMCAPSULE_BOTTOM_SIDE_GROUND; - spin = 0; - } - - // inside item - part = P_SpawnMobjFromMobj(actor, 0, 0, 0, MT_ITEMCAPSULE_PART); - P_SetTarget(&part->target, actor); - P_SetMobjState(part, S_ITEMICON); - part->movedir = ROTATIONSPEED; // rotation speed - part->extravalue1 = 175*FRACUNIT/100; // relative scale - part->flags2 |= MF2_CLASSICPUSH; // classicpush = centered horizontally - P_SetTarget(&actor->tracer, part); // pointer to this item, so we can modify its sprite/frame - - // capsule caps - part = actor; - for (i = 0; i < CAPSULESIDES; i++) - { - // a bottom side - P_SetTarget(&part->hnext, P_SpawnMobjFromMobj(actor, 0, 0, 0, MT_ITEMCAPSULE_PART)); - P_SetTarget(&part->hnext->hprev, part); - part = part->hnext; - P_SetTarget(&part->target, actor); - P_SetMobjState(part, buttState); - part->angle = i * ANG_CAPSULE; - part->movedir = spin; // rotation speed - part->movefactor = 0; // z offset - part->extravalue1 = buttScale; // relative scale - - // a top side - P_SetTarget(&part->hnext, P_SpawnMobjFromMobj(actor, 0, 0, 0, MT_ITEMCAPSULE_PART)); - P_SetTarget(&part->hnext->hprev, part); - part = part->hnext; - P_SetTarget(&part->target, actor); - P_SetMobjState(part, S_ITEMCAPSULE_TOP_SIDE); - part->angle = i * ANG_CAPSULE; - part->movedir = spin; // rotation speed - part->movefactor = actor->info->height - part->info->height; // z offset - } - - P_RefreshItemCapsuleParts(actor); -} -#undef CAPSULESIDES -#undef ANG_CAPSULE -#undef ROTATIONSPEED diff --git a/src/p_local.h b/src/p_local.h index 9c282499f..a143ba9ab 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -365,8 +365,6 @@ void P_InternalFlickyBubble(mobj_t *actor); void P_InternalFlickyFly(mobj_t *actor, fixed_t flyspeed, fixed_t targetdist, fixed_t chasez); void P_InternalFlickyHop(mobj_t *actor, fixed_t momz, fixed_t momh, angle_t angle); -void P_RefreshItemCapsuleParts(mobj_t *mobj); - // // P_MAP // diff --git a/src/p_mobj.c b/src/p_mobj.c index 91f8c9403..629775908 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -3781,8 +3781,12 @@ static void P_ItemCapsulePartThinker(mobj_t *mobj) P_SetScale(mobj, mobj->destscale = targetScale); // find z position - K_GenericExtraFlagsNoZAdjust(mobj, target); - if (mobj->flags & MFE_VERTICALFLIP) + if (mobj->flags2 & MF2_CLASSICPUSH) // centered items should not be flipped + mobj->renderflags = (mobj->renderflags & ~RF_DONTDRAW) | (target->renderflags & RF_DONTDRAW); + else + K_GenericExtraFlagsNoZAdjust(mobj, target); + + if (mobj->eflags & MFE_VERTICALFLIP) z = target->z + target->height - mobj->height - FixedMul(mobj->scale, mobj->movefactor); else z = target->z + FixedMul(mobj->scale, mobj->movefactor); @@ -3799,6 +3803,193 @@ static void P_ItemCapsulePartThinker(mobj_t *mobj) } } +static void P_RefreshItemCapsuleParts(mobj_t *mobj) +{ + UINT8 numNumbers = 0; + INT32 count = 0; + INT32 itemType = mobj->threshold; + mobj_t *part; + skincolornum_t color; + UINT32 newRenderFlags = 0; + boolean colorized; + + if (itemType < 1 || itemType >= NUMKARTITEMS) + itemType = KITEM_SAD; + + // update invincibility properties + if (itemType == KITEM_INVINCIBILITY) + { + mobj->renderflags = (mobj->renderflags & ~RF_BRIGHTMASK) | RF_FULLBRIGHT; + mobj->colorized = true; + } + else + { + mobj->renderflags = (mobj->renderflags & ~RF_BRIGHTMASK) | RF_SEMIBRIGHT; + mobj->color = SKINCOLOR_NONE; + mobj->colorized = false; + } + + // update cap colors + if (itemType == KITEM_SUPERRING) + { + color = SKINCOLOR_GOLD; + newRenderFlags |= RF_SEMIBRIGHT; + } + else if (mobj->spawnpoint && (mobj->spawnpoint->options & MTF_EXTRA)) + color = SKINCOLOR_SAPPHIRE; + else if (itemType == KITEM_SPB) + color = SKINCOLOR_JET; + else + color = SKINCOLOR_NONE; + + colorized = (color != SKINCOLOR_NONE); + part = mobj; + while (!P_MobjWasRemoved(part->hnext)) + { + part = part->hnext; + part->color = color; + part->colorized = colorized; + part->renderflags = (part->renderflags & ~RF_BRIGHTMASK) | newRenderFlags; + } + + // update inside item frame + part = mobj->tracer; + if (P_MobjWasRemoved(part)) + return; + + part->threshold = mobj->threshold; + part->movecount = mobj->movecount; + + switch (itemType) + { + case KITEM_ORBINAUT: + part->sprite = SPR_ITMO; + part->frame = FF_FULLBRIGHT|FF_PAPERSPRITE|K_GetOrbinautItemFrame(mobj->movecount); + break; + case KITEM_INVINCIBILITY: + part->sprite = SPR_ITMI; + part->frame = FF_FULLBRIGHT|FF_PAPERSPRITE|K_GetInvincibilityItemFrame(); + break; + case KITEM_SAD: + part->sprite = SPR_ITEM; + part->frame = FF_FULLBRIGHT|FF_PAPERSPRITE; + break; + default: + part->sprite = SPR_ITEM; + part->frame = FF_FULLBRIGHT|FF_PAPERSPRITE|(itemType); + break; + } + + // update number frame + if (K_GetShieldFromItem(itemType) != KSHIELD_NONE) // shields don't stack, so don't show a number + ; + else + { + switch (itemType) + { + case KITEM_ORBINAUT: // only display the number when the sprite no longer changes + if (mobj->movecount - 1 > K_GetOrbinautItemFrame(mobj->movecount)) + count = mobj->movecount; + break; + case KITEM_SUPERRING: // always display the number, and multiply it by 5 + count = mobj->movecount * 5; + break; + case KITEM_SAD: // never display the number + case KITEM_SPB: + break; + default: + if (mobj->movecount > 1) + count = mobj->movecount; + break; + } + } + + while (count > 0) + { + if (P_MobjWasRemoved(part->tracer)) + { + P_SetTarget(&part->tracer, P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_OVERLAY)); + P_SetTarget(&part->tracer->target, part); + P_SetMobjState(part->tracer, S_INVISIBLE); + part->tracer->spriteyoffset = 10*FRACUNIT; + part->tracer->spritexoffset = 13*numNumbers*FRACUNIT; + } + part = part->tracer; + part->sprite = SPR_ITMN; + part->frame = FF_FULLBRIGHT|(count % 10); + count /= 10; + numNumbers++; + } + + // delete any extra overlays (I guess in case the number changes?) + if (part->tracer) + { + P_RemoveMobj(part->tracer); + P_SetTarget(&part->tracer, NULL); + } +} + +#define CAPSULESIDES 5 +#define ANG_CAPSULE (UINT32_MAX / CAPSULESIDES) +#define ROTATIONSPEED (2*ANG2) +static void P_SpawnItemCapsuleParts(mobj_t *mobj) +{ + UINT8 i; + mobj_t *part; + fixed_t buttScale = 0; + statenum_t buttState = S_ITEMCAPSULE_BOTTOM_SIDE_AIR; + angle_t spin = ANGLE_MAX - ROTATIONSPEED; + + if (P_IsObjectOnGround(mobj)) + { + buttScale = 13*FRACUNIT/10; + buttState = S_ITEMCAPSULE_BOTTOM_SIDE_GROUND; + spin = 0; + } + + // inside item + part = P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_ITEMCAPSULE_PART); + P_SetTarget(&part->target, mobj); + P_SetMobjState(part, S_ITEMICON); + part->movedir = ROTATIONSPEED; // rotation speed + part->extravalue1 = 175*FRACUNIT/100; // relative scale + part->flags2 |= MF2_CLASSICPUSH; // classicpush = centered horizontally + part->flags2 &= ~MF2_OBJECTFLIP; // centered item should not be flipped + part->eflags &= ~MFE_VERTICALFLIP; + P_SetTarget(&mobj->tracer, part); // pointer to this item, so we can modify its sprite/frame + + // capsule caps + part = mobj; + for (i = 0; i < CAPSULESIDES; i++) + { + // a bottom side + P_SetTarget(&part->hnext, P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_ITEMCAPSULE_PART)); + P_SetTarget(&part->hnext->hprev, part); + part = part->hnext; + P_SetTarget(&part->target, mobj); + P_SetMobjState(part, buttState); + part->angle = i * ANG_CAPSULE; + part->movedir = spin; // rotation speed + part->movefactor = 0; // z offset + part->extravalue1 = buttScale; // relative scale + + // a top side + P_SetTarget(&part->hnext, P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_ITEMCAPSULE_PART)); + P_SetTarget(&part->hnext->hprev, part); + part = part->hnext; + P_SetTarget(&part->target, mobj); + P_SetMobjState(part, S_ITEMCAPSULE_TOP_SIDE); + part->angle = i * ANG_CAPSULE; + part->movedir = spin; // rotation speed + part->movefactor = mobj->info->height - part->info->height; // z offset + } + + P_RefreshItemCapsuleParts(mobj); +} +#undef CAPSULESIDES +#undef ANG_CAPSULE +#undef ROTATIONSPEED + // // P_BossTargetPlayer // If closest is true, find the closest player. @@ -6153,6 +6344,14 @@ static boolean P_MobjRegularThink(mobj_t *mobj) mobj->z -= (mobj->height - oldHeight); } + // spawn parts if not done yet + // (this SHOULD be done when the capsule is spawned, but gravflip isn't set up at that point) + if (!(mobj->flags2 & MF2_JUSTATTACKED)) + { + mobj->flags2 |= MF2_JUSTATTACKED; + P_SpawnItemCapsuleParts(mobj); + } + // update & animate capsule if (!P_MobjWasRemoved(mobj->tracer)) { @@ -9433,8 +9632,6 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) // SRB2Kart case MT_ITEMCAPSULE: { - fixed_t oldHeight = mobj->height; - // set default item & count #if 0 // set to 1 to test capsules with random items, e.g. with objectplace if (P_RandomChance(FRACUNIT/3)) @@ -9451,17 +9648,10 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) mobj->movecount = 1; #endif - // grounded/aerial properties - P_AdjustMobjFloorZ_FFloors(mobj, mobj->subsector->sector, 0); - if (!P_IsObjectOnGround(mobj)) - mobj->flags |= MF_NOGRAVITY; - // set starting scale mobj->extravalue1 = mobj->scale; // this acts as the capsule's destscale; we're avoiding P_MobjScaleThink because we want aerial capsules not to scale from their center mobj->scalespeed >>= 1; P_SetScale(mobj, mobj->destscale = mapobjectscale >> 4); - if (mobj->eflags & MFE_VERTICALFLIP) - mobj->z += (oldHeight - mobj->height); break; } @@ -11721,6 +11911,22 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean } case MT_ITEMCAPSULE: { + // we have to adjust for reverse gravity early so that the below grounded checks work + if (mthing->options & MTF_OBJECTFLIP) + { + mobj->eflags |= MFE_VERTICALFLIP; + mobj->flags2 |= MF2_OBJECTFLIP; + mobj->z += FixedMul(mobj->extravalue1, mobj->info->height) - mobj->height; + } + + // determine whether this capsule is grounded or aerial + if (mobj->subsector->sector->ffloors) + P_AdjustMobjFloorZ_FFloors(mobj, mobj->subsector->sector, 0); + if (mobj->subsector->polyList) + P_AdjustMobjFloorZ_PolyObjs(mobj, mobj->subsector); + if (!P_IsObjectOnGround(mobj)) + mobj->flags |= MF_NOGRAVITY; + // Angle = item type if (mthing->angle > 0 && mthing->angle < NUMKARTITEMS) mobj->threshold = mthing->angle; From caf1ed37ac01714d6bbf108b276db5536d2d8b71 Mon Sep 17 00:00:00 2001 From: SinnamonLat Date: Thu, 2 Sep 2021 08:17:43 +0200 Subject: [PATCH 04/20] fix janky follower movements due to lag type being changed from int32 to uint32 in the struct --- src/p_user.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/p_user.c b/src/p_user.c index d577faab2..a8523bdf6 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -3918,9 +3918,10 @@ static void P_HandleFollower(player_t *player) P_SetFollowerState(player->follower, player->follower->state->nextstate); // move the follower next to us (yes, this is really basic maths but it looks pretty damn clean in practice)! - player->follower->momx = (sx - player->follower->x)/fl.horzlag; - player->follower->momy = (sy - player->follower->y)/fl.horzlag; - player->follower->momz = (sz - player->follower->z)/fl.vertlag; + // 02/09/2021: cast lag to int32 otherwise funny things happen since it was changed to uint32 in the struct + player->follower->momx = (sx - player->follower->x)/ (INT32)fl.horzlag; + player->follower->momy = (sy - player->follower->y)/ (INT32)fl.horzlag; + player->follower->momz = (sz - player->follower->z)/ (INT32)fl.vertlag; player->follower->angle = player->mo->angle; if (player->mo->colorized) From 2df8aa69b7653c1d328365018f658dca77f8681c Mon Sep 17 00:00:00 2001 From: SinnamonLat Date: Thu, 2 Sep 2021 08:33:49 +0200 Subject: [PATCH 05/20] missing follower check in SendNameAndColor --- src/d_netcmd.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 4ed110f35..cd6189e8a 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -1398,7 +1398,9 @@ static void SendNameAndColor(UINT8 n) if (!strcmp(cv_playername[n].string, player_names[playernum]) && cv_playercolor[n].value == player->skincolor - && !strcmp(cv_skin[n].string, skins[player->skin].name)) + && !strcmp(cv_skin[n].string, skins[player->skin].name) + && cv_follower[n].value == player->followerskin + && cv_followercolor[n].value == player->followercolor) return; player->availabilities = R_GetSkinAvailabilities(); From f96f7c6ba3ce0064076507deb88da47440229da6 Mon Sep 17 00:00:00 2001 From: SinnamonLat Date: Thu, 2 Sep 2021 13:34:17 +0200 Subject: [PATCH 06/20] Fix follower colours 'Match' and 'Opposite' not working --- src/d_netcmd.c | 18 ++++++++++++------ src/p_user.c | 9 ++++----- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index cd6189e8a..2556ab0ac 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -768,15 +768,21 @@ void D_RegisterClientCommands(void) for (i = 0; i < MAXSKINCOLORS; i++) { - Color_cons_t[i].value = Followercolor_cons_t[i].value = i; - Color_cons_t[i].strvalue = Followercolor_cons_t[i].strvalue = skincolors[i].name; + Color_cons_t[i].value = i; + Color_cons_t[i].strvalue = skincolors[i].name; } - Followercolor_cons_t[MAXSKINCOLORS].value = MAXSKINCOLORS; - Followercolor_cons_t[MAXSKINCOLORS].strvalue = "Match"; // Add "Match" option, which will make the follower color match the player's + for (i = 2; i < MAXSKINCOLORS; i++) + { + Followercolor_cons_t[i].value = i-2; + Followercolor_cons_t[i].strvalue = skincolors[i-2].name; + } - Followercolor_cons_t[MAXSKINCOLORS+1].value = MAXSKINCOLORS+1; - Followercolor_cons_t[MAXSKINCOLORS+1].strvalue = "Opposite"; // Add "Opposite" option, ...which is like "Match", but for coloropposite. + Followercolor_cons_t[1].value = -1; + Followercolor_cons_t[1].strvalue = "Match"; // Add "Match" option, which will make the follower color match the player's + + Followercolor_cons_t[0].value = -2; + Followercolor_cons_t[0].strvalue = "Opposite"; // Add "Opposite" option, ...which is like "Match", but for coloropposite. Color_cons_t[MAXSKINCOLORS].value = Followercolor_cons_t[MAXSKINCOLORS+2].value = 0; Color_cons_t[MAXSKINCOLORS].strvalue = Followercolor_cons_t[MAXSKINCOLORS+2].strvalue = NULL; diff --git a/src/p_user.c b/src/p_user.c index a8523bdf6..bbc28a504 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -3804,7 +3804,7 @@ static void P_HandleFollower(player_t *player) angle_t an; fixed_t zoffs; fixed_t sx, sy, sz; - UINT16 color; + INT16 color; fixed_t bubble; // bubble scale (0 if no bubble) mobj_t *bmobj; // temp bubble mobj @@ -3851,19 +3851,18 @@ static void P_HandleFollower(player_t *player) } // Set follower colour - switch (player->followercolor) { - case MAXSKINCOLORS: // "Match" + case 255: // "Match" (-1) color = player->skincolor; break; - case MAXSKINCOLORS+1: // "Opposite" + case 254: // "Opposite" (-2) color = skincolors[player->skincolor].invcolor; break; default: color = player->followercolor; - if (!color || color > MAXSKINCOLORS+2) // Make sure this isn't garbage + if (color < -2 || !color || color > MAXSKINCOLORS+2) // Make sure this isn't garbage color = player->skincolor; // "Match" as fallback. break; From 647dfd98fbe78cddf6830c5e1d3c77f7c0889e11 Mon Sep 17 00:00:00 2001 From: SinnamonLat Date: Thu, 2 Sep 2021 13:40:57 +0200 Subject: [PATCH 07/20] forgot to change something back --- src/p_user.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/p_user.c b/src/p_user.c index bbc28a504..f748a04bb 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -3804,7 +3804,7 @@ static void P_HandleFollower(player_t *player) angle_t an; fixed_t zoffs; fixed_t sx, sy, sz; - INT16 color; + UINT16 color; fixed_t bubble; // bubble scale (0 if no bubble) mobj_t *bmobj; // temp bubble mobj @@ -3862,7 +3862,7 @@ static void P_HandleFollower(player_t *player) default: color = player->followercolor; - if (color < -2 || !color || color > MAXSKINCOLORS+2) // Make sure this isn't garbage + if (!color || color > MAXSKINCOLORS+2) // Make sure this isn't garbage color = player->skincolor; // "Match" as fallback. break; From c142648d0320a228277953ebe9044ce7744b6dce Mon Sep 17 00:00:00 2001 From: SteelT Date: Sat, 27 Nov 2021 20:36:40 -0500 Subject: [PATCH 08/20] Add cmake config option to compile a dev build --- src/CMakeLists.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 39b71cda7..1355c85ee 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -41,6 +41,8 @@ set(SRB2_CONFIG_YASM OFF CACHE BOOL "Use YASM in place of NASM.") set(SRB2_CONFIG_STATIC_OPENGL OFF CACHE BOOL "Use statically linked OpenGL. NOT RECOMMENDED.") +set(SRB2_CONFIG_DEV_BUILD OFF CACHE BOOL + "Compile a development build of SRB2Kart.") ### use internal libraries? if(${CMAKE_SYSTEM} MATCHES "Windows") ###set on Windows only @@ -280,6 +282,10 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") set(CMAKE_C_FLAGS ${CMAKE_C_FLAGS} -Wno-absolute-value) endif() +if(${SRB2_CONFIG_DEV_BUILD}) + target_compile_definitions(SRB2SDL2 PRIVATE -DDEVELOP) +endif() + set(CMAKE_C_FLAGS ${CMAKE_C_FLAGS} -Wno-trigraphs) target_compile_definitions(SRB2SDL2 PRIVATE -DCMAKECONFIG) From 0b744767077d7d3537c7ff47f6ab5c0290c0d1b5 Mon Sep 17 00:00:00 2001 From: SteelT Date: Sat, 27 Nov 2021 21:02:04 -0500 Subject: [PATCH 09/20] Don't make asset hashing be required under dev builds --- CMakeLists.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b58101f7f..bc4f6ec6b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -118,8 +118,9 @@ set(SRB2_SDL2_EXE_NAME srb2kart CACHE STRING "Executable binary output name") include_directories(${CMAKE_CURRENT_BINARY_DIR}/src) add_subdirectory(src) -add_subdirectory(assets) - +if(NOT ${SRB2_CONFIG_DEV_BUILD}) + add_subdirectory(assets) +endif() ## config.h generation set(GIT_EXECUTABLE "git" CACHE FILEPATH "Path to git binary") From 3141ca022117cb3bb5d62b2d3d31c260c54e6e26 Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 28 Nov 2021 20:03:49 +0000 Subject: [PATCH 10/20] Replay fixes mark whatever Not a pancaea for EVERYTHING, just a bunch of good stuff. * Some issues with spectators not == true because the assignment wasn't casted. * Netgame status (or rather its inverse) is recorded in netreplays now, to allow for power levels controlling spawn position. * Fixed tally screen for replays to not scream infinitely at you. * P_IsLocalPlayer now uses display players in replays. * A bunch of good testing prints that helped me find these problems, commented out for now just in case we need them again soonish. --- src/g_demo.c | 35 +++++++++++++++++++++++++++-------- src/g_demo.h | 1 + src/g_game.c | 6 +++--- src/k_kart.c | 5 ++++- src/k_pwrlv.c | 4 ++-- src/p_user.c | 4 ++++ src/y_inter.c | 12 +++++------- 7 files changed, 46 insertions(+), 21 deletions(-) diff --git a/src/g_demo.c b/src/g_demo.c index 16ca2a859..eda590420 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -112,6 +112,10 @@ demoghost *ghosts = NULL; #define DF_BREAKTHECAPSULES 0x04 // This demo is from Break the Capsules and contains its final completion time! #define DF_ATTACKMASK 0x06 // This demo is from ??? attack and contains ??? +// 0x08 free + +#define DF_NONETMP 0x10 // multiplayer but not netgame + #define DF_LUAVARS 0x20 // this demo contains extra lua vars #define DF_ATTACKSHIFT 1 @@ -309,6 +313,7 @@ void G_ReadDemoExtraData(void) switch (extradata) { case DXD_PST_PLAYING: players[p].pflags |= PF_WANTSTOJOIN; // fuck you + //CONS_Printf("player %s is despectating on tic %d\n", player_names[p], leveltime); break; case DXD_PST_SPECTATING: @@ -319,9 +324,11 @@ void G_ReadDemoExtraData(void) playeringame[p] = true; G_AddPlayer(p); players[p].spectator = true; + //CONS_Printf("player %s is joining server on tic %d\n", player_names[p], leveltime); } else { + //CONS_Printf("player %s is spectating on tic %d\n", player_names[p], leveltime); players[p].spectator = true; if (players[p].mo) P_DamageMobj(players[p].mo, NULL, NULL, 1, DMG_INSTAKILL); @@ -366,7 +373,7 @@ void G_ReadDemoExtraData(void) P_SetRandSeed(rng); if (demosynced) - CONS_Alert(CONS_WARNING, M_GetText("Demo playback has desynced!\n")); + CONS_Alert(CONS_WARNING, M_GetText("Demo playback has desynced (RNG)!\n")); demosynced = false; } } @@ -863,7 +870,12 @@ void G_WriteGhostTic(mobj_t *ghost, INT32 playernum) void G_ConsAllGhostTics(void) { - UINT8 p = READUINT8(demo_p); + UINT8 p; + + if (!demo_p || !demo.deferstart) + return; + + p = READUINT8(demo_p); while (p != 0xFF) { @@ -888,8 +900,6 @@ void G_ConsGhostTic(INT32 playernum) mobj_t *testmo; UINT32 syncleeway; - if (!demo_p || !demo.deferstart) - return; if (!(demoflags & DF_GHOST)) return; // No ghost data to use. @@ -966,7 +976,7 @@ void G_ConsGhostTic(INT32 playernum) if (th != &thlist[THINK_MOBJ] && mobj->health != health) // Wasn't damaged?! This is desync! Fix it! { if (demosynced) - CONS_Alert(CONS_WARNING, M_GetText("Demo playback has desynced!\n")); + CONS_Alert(CONS_WARNING, M_GetText("Demo playback has desynced (health)!\n")); demosynced = false; P_DamageMobj(mobj, players[0].mo, players[0].mo, 1, DMG_NORMAL); } @@ -1019,7 +1029,7 @@ void G_ConsGhostTic(INT32 playernum) if (ghostext[playernum].desyncframes >= 2) { if (demosynced) - CONS_Alert(CONS_WARNING, M_GetText("Demo playback has desynced!\n")); + CONS_Alert(CONS_WARNING, "Demo playback has desynced (player %s)!\n", player_names[playernum]); demosynced = false; P_UnsetThingPosition(testmo); @@ -1042,7 +1052,7 @@ void G_ConsGhostTic(INT32 playernum) || players[playernum].bumpers != ghostext[playernum].kartbumpers) { if (demosynced) - CONS_Alert(CONS_WARNING, M_GetText("Demo playback has desynced!\n")); + CONS_Alert(CONS_WARNING, M_GetText("Demo playback has desynced (item/bumpers)!\n")); demosynced = false; players[playernum].itemtype = ghostext[playernum].kartitem; @@ -1921,6 +1931,9 @@ void G_BeginRecording(void) demo_p = demobuffer; demoflags = DF_GHOST|(multiplayer ? DF_MULTIPLAYER : (modeattacking<>DF_ATTACKSHIFT; multiplayer = !!(demoflags & DF_MULTIPLAYER); + demo.netgame = (multiplayer && !(demoflags & DF_NONETMP)); CON_ToggleOff(); hu_demotime = UINT32_MAX; @@ -2927,7 +2941,7 @@ void G_DoPlayDemo(char *defdemoname) while (p != 0xFF) { - if ((spectator = (p & DEMO_SPECTATOR))) + if ((spectator = !!(p & DEMO_SPECTATOR))) { p &= ~DEMO_SPECTATOR; @@ -2975,6 +2989,11 @@ void G_DoPlayDemo(char *defdemoname) M_Memcpy(player_names[p],demo_p,16); demo_p += 16; + /*if (players[p].spectator) + { + CONS_Printf("player %s is spectator at start\n", player_names[p]); + }*/ + // Skin M_Memcpy(skin,demo_p,16); demo_p += 16; diff --git a/src/g_demo.h b/src/g_demo.h index 03d75cf4b..53f49be4d 100644 --- a/src/g_demo.h +++ b/src/g_demo.h @@ -41,6 +41,7 @@ struct demovars_s { boolean inreplayhut; // Go back to replayhut after demos boolean quitafterplaying; // quit after playing a demo from cmdline boolean deferstart; // don't start playing demo right away + boolean netgame; // multiplayer netgame tic_t savebutton; // Used to determine when the local player can choose to save the replay while the race is still going enum { diff --git a/src/g_game.c b/src/g_game.c index c675e9a22..6c3d8650b 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -2551,7 +2551,7 @@ mapthing_t *G_FindRaceStart(INT32 playernum) if (j == i) continue; - if (netgame && cv_kartusepwrlv.value) + if ((netgame || (demo.playback && demo.netgame)) && cv_kartusepwrlv.value) { if (clientpowerlevels[j][PWRLV_RACE] == clientpowerlevels[i][PWRLV_RACE]) num++; @@ -2572,7 +2572,7 @@ mapthing_t *G_FindRaceStart(INT32 playernum) pos++; else { - if (netgame && cv_kartusepwrlv.value) + if ((netgame || (demo.playback && demo.netgame)) && cv_kartusepwrlv.value) { if (clientpowerlevels[i][PWRLV_RACE] > clientpowerlevels[playernum][PWRLV_RACE]) pos++; @@ -3112,7 +3112,7 @@ boolean G_GametypeHasTeams(void) // boolean G_GametypeHasSpectators(void) { - return (netgame || (multiplayer && demo.playback)); + return (netgame || (multiplayer && demo.netgame)); } // diff --git a/src/k_kart.c b/src/k_kart.c index 4ab844c2d..09c666dc5 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -52,7 +52,7 @@ void K_TimerReset(void) void K_TimerInit(void) { UINT8 i; - UINT8 numPlayers = 0; + UINT8 numPlayers = 0;//, numspec = 0; for (i = 0; i < MAXPLAYERS; i++) { @@ -63,6 +63,7 @@ void K_TimerInit(void) if (players[i].spectator == true) { + //numspec++; continue; } @@ -98,6 +99,7 @@ void K_TimerInit(void) // NOW you can try to spawn in the Battle capsules, if there's not enough players for a match K_SpawnBattleCapsules(); + //CONS_Printf("numbulbs set to %d (%d players, %d spectators) on tic %d\n", numbulbs, numPlayers, numspec, leveltime); } UINT32 K_GetPlayerDontDrawFlag(player_t *player) @@ -9387,6 +9389,7 @@ void K_CheckSpectateStatus(void) { if (cv_ingamecap.value && numingame+i >= cv_ingamecap.value) // Hit the in-game player cap while adding people? break; + //CONS_Printf("player %s is joining on tic %d\n", player_names[respawnlist[i]], leveltime); P_SpectatorJoinGame(&players[respawnlist[i]]); } diff --git a/src/k_pwrlv.c b/src/k_pwrlv.c index ac2d009bc..860727184 100644 --- a/src/k_pwrlv.c +++ b/src/k_pwrlv.c @@ -30,7 +30,7 @@ SINT8 K_UsingPowerLevels(void) { SINT8 pt = PWRLV_DISABLED; - if (!cv_kartusepwrlv.value || !netgame || grandprixinfo.gp == true) + if (!cv_kartusepwrlv.value || !(netgame || (demo.playback && demo.netgame)) || grandprixinfo.gp == true) { return PWRLV_DISABLED; } @@ -346,7 +346,7 @@ void K_PlayerForfeit(UINT8 playernum, boolean pointloss) clientpowerlevels[playernum][powertype] += inc; - if (playernum == consoleplayer) + if (!demo.playback && playernum == consoleplayer) { vspowerlevel[powertype] = clientpowerlevels[playernum][powertype]; if (M_UpdateUnlockablesAndExtraEmblems()) diff --git a/src/p_user.c b/src/p_user.c index c58e61b4d..b67b23781 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1058,6 +1058,9 @@ boolean P_IsLocalPlayer(player_t *player) { UINT8 i; + if (demo.playback) + return P_IsDisplayPlayer(player); + for (i = 0; i <= r_splitscreen; i++) // DON'T skip P1 { if (player == &players[g_localplayers[i]]) @@ -4352,6 +4355,7 @@ void P_PlayerThink(player_t *player) player->flashing = TICRATE/2 + 1; /*if (P_SpectatorJoinGame(player)) return; // player->mo was removed.*/ + //CONS_Printf("player %s wants to join on tic %d\n", player_names[player-players], leveltime); } if (player->respawn.state != RESPAWNST_NONE) diff --git a/src/y_inter.c b/src/y_inter.c index 68a6019ad..e050deddc 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -481,7 +481,7 @@ void Y_IntermissionDrawer(void) else hilicol = ((intertype == int_race) ? V_SKYMAP : V_REDMAP); - if (sorttic != -1 && intertic > sorttic && !demo.playback) + if (sorttic != -1 && intertic > sorttic && multiplayer) { INT32 count = (intertic - sorttic); @@ -586,7 +586,7 @@ void Y_IntermissionDrawer(void) y2 = y; - if (netgame && playerconsole[data.num[i]] == 0 && server_lagless && !players[data.num[i]].bot) + if ((netgame || (demo.playback && demo.netgame)) && playerconsole[data.num[i]] == 0 && server_lagless && !players[data.num[i]].bot) { static int alagles_timer = 0; patch_t *alagles; @@ -799,7 +799,7 @@ void Y_Ticker(void) if (intertype == int_race || intertype == int_battle) { - if (!(multiplayer && demo.playback)) // Don't advance to rankings in replays + //if (!(multiplayer && demo.playback)) // Don't advance to rankings in replays { if (!data.rankingsmode && (intertic >= sorttic + 8)) { @@ -868,8 +868,6 @@ void Y_Ticker(void) endtic = intertic + 3*TICRATE; // 3 second pause after end of tally } } - else if (!(intertic & 1)) - S_StartSound(NULL, sfx_ptally); // tally sound effect } } @@ -1013,7 +1011,7 @@ static void K_UpdatePowerLevels(void) data.increase[i] = increment[i]; clientpowerlevels[i][powertype] += data.increase[i]; - if (i == consoleplayer) + if (!demo.playback && i == consoleplayer) { CONS_Debug(DBG_GAMELOGIC, "Player %d is you! Saving...\n", i); vspowerlevel[powertype] = clientpowerlevels[i][powertype]; @@ -1069,7 +1067,7 @@ void Y_StartIntermission(void) { if (cv_inttime.value == 0) timer = 0; - else if (demo.playback) // Override inttime (which is pulled from the replay anyway + else if (demo.playback && !multiplayer) // Override inttime (which is pulled from the replay anyway timer = 10*TICRATE; else { From ba3e89665534d5ab6a38e9a86e1874631e4a1fe8 Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 28 Nov 2021 20:15:42 +0000 Subject: [PATCH 11/20] Make the game loading-bar miniwindow do OS polling, to allow you to tab back into it without it being considered frozen by the OS. --- src/console.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/console.c b/src/console.c index 5eda4f7fa..4d71e74d3 100644 --- a/src/console.c +++ b/src/console.c @@ -1916,6 +1916,8 @@ void CON_SetLoadingProgress(con_loadprogress_t newStep) if (con_startup_loadprogress < LOADED_ISTARTUPGRAPHICS) // rendering not possible? return; CON_DrawLoadBar(); // here we display the console text + I_OsPolling(); + I_UpdateNoBlit(); I_FinishUpdate(); // page flip or blit buffer } From 15741da0a486b4724cca4eb19acf15c3d26275d6 Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 28 Nov 2021 20:18:41 +0000 Subject: [PATCH 12/20] Improve some of the efficiency loss in F_DoWipe compared to K.S.'s 2.1 code by seperating out some of the loops. --- src/f_wipe.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/f_wipe.c b/src/f_wipe.c index ddc719e6d..db343d050 100644 --- a/src/f_wipe.c +++ b/src/f_wipe.c @@ -299,16 +299,23 @@ static void F_DoWipe(fademask_t *fademask, lighttable_t *fadecolormap, boolean r e = e_base + relativepos; draw_rowstogo = draw_rowend - draw_rowstart; - while (draw_rowstogo--) + if (fadecolormap) { - if (fadecolormap != NULL) + if (reverse) + s = e; + while (draw_rowstogo--) + *w++ = fadecolormap[ ( m << 8 ) + *s++ ]; + } + else while (draw_rowstogo--) + { + /*if (fadecolormap != NULL) { if (reverse) *w++ = fadecolormap[ ( m << 8 ) + *e++ ]; else *w++ = fadecolormap[ ( m << 8 ) + *s++ ]; } - else + else*/ *w++ = transtbl[ ( *e++ << 8 ) + *s++ ]; } From 88528744650482f469488b3bf80716a95e6a222b Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 28 Nov 2021 20:27:32 +0000 Subject: [PATCH 13/20] KHUD NOT NETSYNCED, hyuu cannot safely use it as a reference point --- src/d_player.h | 2 +- src/k_kart.c | 16 +++++++--------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index 3d9ac11dc..94310f06e 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -202,7 +202,7 @@ typedef enum { // Unsynced, HUD or clientsided effects // Item box - khud_itemblink, // Item flashing after roulette, prevents Hyudoro stealing AND serves as a mashing indicator + khud_itemblink, // Item flashing after roulette, serves as a mashing indicator khud_itemblinkmode, // Type of flashing: 0 = white (normal), 1 = red (mashing), 2 = rainbow (enhanced items) // Rings diff --git a/src/k_kart.c b/src/k_kart.c index 4ab844c2d..e702be207 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -4885,8 +4885,7 @@ static void K_DoHyudoroSteal(player_t *player) // Has an item && (players[i].itemtype && players[i].itemamount - && !(players[i].pflags & PF_ITEMOUT) - && !players[i].karthud[khud_itemblink])) + && !(players[i].pflags & PF_ITEMOUT)) { playerswappable[numplayers] = i; numplayers++; @@ -6355,6 +6354,12 @@ void K_KartPlayerHUDUpdate(player_t *player) else if (player->karthud[khud_fault] > 0 && player->karthud[khud_fault] < 2*TICRATE) player->karthud[khud_fault]++; + if (player->karthud[khud_itemblink] && player->karthud[khud_itemblink]-- <= 0) + { + player->karthud[khud_itemblinkmode] = 0; + player->karthud[khud_itemblink] = 0; + } + if (gametype == GT_RACE) { // 0 is the fast spin animation, set at 30 tics of ring boost or higher! @@ -6873,13 +6878,6 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) K_HandleTumbleBounce(player); } - // This doesn't go in HUD update because it has potential gameplay ramifications - if (player->karthud[khud_itemblink] && player->karthud[khud_itemblink]-- <= 0) - { - player->karthud[khud_itemblinkmode] = 0; - player->karthud[khud_itemblink] = 0; - } - K_KartPlayerHUDUpdate(player); if (battleovertime.enabled && !(player->pflags & PF_ELIMINATED) && player->bumpers <= 0 && player->karmadelay <= 0) From 72ded01ac835107d8d9094e14b1c11cef3222bc3 Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 28 Nov 2021 20:23:03 -0800 Subject: [PATCH 14/20] Smoother ceiling clipping - Apply some gravity immediately. - Play the bump (like against walls) effect. --- src/k_kart.c | 12 ++++++++++++ src/k_kart.h | 1 + src/p_map.c | 9 +-------- src/p_mobj.c | 9 +++++++++ 4 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index e8b424179..1865487f3 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -2077,6 +2077,18 @@ void K_SpawnInvincibilitySpeedLines(mobj_t *mo) fast->destscale = 6*((mo->player->invincibilitytimer/TICRATE)*FRACUNIT)/8; } +void K_SpawnBumpEffect(mobj_t *mo) +{ + mobj_t *fx = P_SpawnMobj(mo->x, mo->y, mo->z, MT_BUMP); + if (mo->eflags & MFE_VERTICALFLIP) + fx->eflags |= MFE_VERTICALFLIP; + else + fx->eflags &= ~MFE_VERTICALFLIP; + fx->scale = mo->scale; + + S_StartSound(mo, sfx_s3k49); +} + static SINT8 K_GlanceAtPlayers(player_t *glancePlayer) { const fixed_t maxdistance = FixedMul(1280 * mapobjectscale, K_GetKartGameSpeedScalar(gamespeed)); diff --git a/src/k_kart.h b/src/k_kart.h index b8e74539b..98d948d7e 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -51,6 +51,7 @@ void K_SpawnDriftBoostClip(player_t *player); void K_SpawnDriftBoostClipSpark(mobj_t *clip); void K_SpawnNormalSpeedLines(player_t *player); void K_SpawnInvincibilitySpeedLines(mobj_t *mo); +void K_SpawnBumpEffect(mobj_t *mo); void K_KartMoveAnimation(player_t *player); void K_KartPlayerHUDUpdate(player_t *player); void K_KartPlayerThink(player_t *player, ticcmd_t *cmd); diff --git a/src/p_map.c b/src/p_map.c index 42fa89b73..de1337f2b 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -3695,14 +3695,7 @@ void P_BouncePlayerMove(mobj_t *mo) } else { - mobj_t *fx = P_SpawnMobj(mo->x, mo->y, mo->z, MT_BUMP); - if (mo->eflags & MFE_VERTICALFLIP) - fx->eflags |= MFE_VERTICALFLIP; - else - fx->eflags &= ~MFE_VERTICALFLIP; - fx->scale = mo->scale; - - S_StartSound(mo, sfx_s3k49); + K_SpawnBumpEffect(mo); } P_PlayerHitBounceLine(bestslideline); diff --git a/src/p_mobj.c b/src/p_mobj.c index 2b2cfc251..63179523d 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -2775,6 +2775,15 @@ void P_PlayerZMovement(mobj_t *mo) P_CheckMarioBlocks(mo); mo->momz = 0; + P_CheckGravity(mo, true); + + if (abs(mo->momz) < 15 * mapobjectscale) + { + mo->momz = 15 * mapobjectscale + * -(P_MobjFlip(mo)); + } + + K_SpawnBumpEffect(mo); } } } From 696ca049d89609078eb23b0983d2f0f3ad3478f4 Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 28 Nov 2021 22:43:48 -0800 Subject: [PATCH 15/20] Apply momentum based squash and stretch to every object Also netsave. --- src/d_player.h | 1 - src/k_kart.c | 37 ++++++++++++++++++++++++++++++++++++- src/k_kart.h | 1 + src/p_mobj.c | 7 ++++++- src/p_mobj.h | 3 +++ src/p_saveg.c | 13 ++++++++++++- src/p_slopes.c | 2 ++ src/p_user.c | 41 ----------------------------------------- 8 files changed, 60 insertions(+), 45 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index f5808a166..be16320cd 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -487,7 +487,6 @@ typedef struct player_s fixed_t speed; // Player's speed (distance formula of MOMX and MOMY values) fixed_t lastspeed; - fixed_t lastmomz; INT32 deadtimer; // End game if game over lasts too long tic_t exiting; // Exitlevel timer diff --git a/src/k_kart.c b/src/k_kart.c index bb709a850..85b62c4c2 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -2536,7 +2536,6 @@ void K_KartMoveAnimation(player_t *player) // Update lastspeed value -- we use to display slow driving frames instead of fast driving when slowing down. player->lastspeed = player->speed; - player->lastmomz = player->mo->momz; } static void K_TauntVoiceTimers(player_t *player) @@ -4509,6 +4508,42 @@ void K_DriftDustHandling(mobj_t *spawner) } } +void K_Squish(mobj_t *mo) +{ + const fixed_t maxstretch = 2*FRACUNIT; + const fixed_t factor = 3 * mo->height / 2; + const fixed_t threshold = factor / 6; + + const fixed_t old3dspeed = abs(mo->lastmomz); + const fixed_t new3dspeed = abs(mo->momz); + + const fixed_t delta = abs(old3dspeed - new3dspeed); + + if (delta > threshold) + { + mo->spritexscale = + FRACUNIT + FixedDiv(delta, factor); + + if (mo->spritexscale > maxstretch) + mo->spritexscale = maxstretch; + + if (abs(new3dspeed) > abs(old3dspeed)) + { + mo->spritexscale = + FixedDiv(FRACUNIT, mo->spritexscale); + } + } + else + { + mo->spritexscale -= + (mo->spritexscale - FRACUNIT) + / (mo->spritexscale < FRACUNIT ? 8 : 2); + } + + mo->spriteyscale = + FixedDiv(FRACUNIT, mo->spritexscale); +} + static mobj_t *K_FindLastTrailMobj(player_t *player) { mobj_t *trail; diff --git a/src/k_kart.h b/src/k_kart.h index b8e74539b..9a07fe609 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -76,6 +76,7 @@ void K_SpawnSparkleTrail(mobj_t *mo); void K_SpawnWipeoutTrail(mobj_t *mo, boolean offroad); void K_SpawnDraftDust(mobj_t *mo); void K_DriftDustHandling(mobj_t *spawner); +void K_Squish(mobj_t *mo); mobj_t *K_ThrowKartItem(player_t *player, boolean missile, mobjtype_t mapthing, INT32 defaultDir, INT32 altthrow); void K_PuntMine(mobj_t *mine, mobj_t *punter); void K_DoSneaker(player_t *player, INT32 type); diff --git a/src/p_mobj.c b/src/p_mobj.c index 2b2cfc251..ee1fa0890 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -8616,7 +8616,7 @@ void P_MobjThinker(mobj_t *mobj) return; } - mobj->eflags &= ~(MFE_PUSHED|MFE_SPRUNG|MFE_JUSTBOUNCEDWALL|MFE_DAMAGEHITLAG); + mobj->eflags &= ~(MFE_PUSHED|MFE_SPRUNG|MFE_JUSTBOUNCEDWALL|MFE_DAMAGEHITLAG|MFE_SLOPELAUNCHED); tmfloorthing = tmhitthing = NULL; @@ -8867,6 +8867,11 @@ void P_MobjThinker(mobj_t *mobj) default: break; } + + if (!(mobj->eflags & MFE_SLOPELAUNCHED)) + K_Squish(mobj); + + mobj->lastmomz = mobj->momz; } // Quick, optimized function for the Rail Rings diff --git a/src/p_mobj.h b/src/p_mobj.h index 16055907b..28395f85a 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -249,6 +249,8 @@ typedef enum MFE_JUSTBOUNCEDWALL = 1<<12, // SRB2Kart: In damage hitlag (displays different visual efx) MFE_DAMAGEHITLAG = 1<<13, + // Slope physics sent you airborne + MFE_SLOPELAUNCHED = 1<<14, // free: to and including 1<<15 } mobjeflag_t; @@ -360,6 +362,7 @@ typedef struct mobj_s fixed_t friction; fixed_t movefactor; + fixed_t lastmomz; INT32 fuse; // Does something in P_MobjThinker on reaching 0. fixed_t watertop; // top of the water FOF the mobj is in diff --git a/src/p_saveg.c b/src/p_saveg.c index ce1093061..83625026d 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -1534,7 +1534,8 @@ typedef enum MD2_HITLAG = 1<<24, MD2_WAYPOINTCAP = 1<<25, MD2_KITEMCAP = 1<<26, - MD2_ITNEXT = 1<<27 + MD2_ITNEXT = 1<<27, + MD2_LASTMOMZ = 1<<28, } mobj_diff2_t; typedef enum @@ -1775,6 +1776,8 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type) diff2 |= MD2_KITEMCAP; if (mobj->itnext) diff2 |= MD2_ITNEXT; + if (mobj->lastmomz) + diff2 |= MD2_LASTMOMZ; if (diff2 != 0) diff |= MD_MORE; @@ -1968,6 +1971,10 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type) { WRITEINT32(save_p, mobj->hitlag); } + if (diff2 & MD2_LASTMOMZ) + { + WRITEINT32(save_p, mobj->lastmomz); + } WRITEUINT32(save_p, mobj->mobjnum); } @@ -3062,6 +3069,10 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker) { mobj->hitlag = READINT32(save_p); } + if (diff2 & MD2_LASTMOMZ) + { + mobj->lastmomz = READINT32(save_p); + } if (diff & MD_REDFLAG) { diff --git a/src/p_slopes.c b/src/p_slopes.c index d1e8f5f54..1bde8f4ee 100644 --- a/src/p_slopes.c +++ b/src/p_slopes.c @@ -844,6 +844,8 @@ void P_SlopeLaunch(mobj_t *mo) mo->momy = slopemom.y; mo->momz = slopemom.z; #endif + + mo->eflags |= MFE_SLOPELAUNCHED; } //CONS_Printf("Launched off of slope.\n"); diff --git a/src/p_user.c b/src/p_user.c index 63bd09c96..c58e61b4d 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1658,42 +1658,6 @@ static void P_DoBubbleBreath(player_t *player) } } -static void squish(player_t *player) -{ - const fixed_t maxstretch = 2*FRACUNIT; - const fixed_t factor = 3 * player->mo->height / 2; - const fixed_t threshold = factor / 6; - - const fixed_t old3dspeed = abs(player->lastmomz); - const fixed_t new3dspeed = abs(player->mo->momz); - - const fixed_t delta = abs(old3dspeed - new3dspeed); - - if (delta > threshold) - { - player->mo->spritexscale = - FRACUNIT + FixedDiv(delta, factor); - - if (player->mo->spritexscale > maxstretch) - player->mo->spritexscale = maxstretch; - - if (abs(new3dspeed) > abs(old3dspeed)) - { - player->mo->spritexscale = - FixedDiv(FRACUNIT, player->mo->spritexscale); - } - } - else - { - player->mo->spritexscale -= - (player->mo->spritexscale - FRACUNIT) - / (player->mo->spritexscale < FRACUNIT ? 8 : 2); - } - - player->mo->spriteyscale = - FixedDiv(FRACUNIT, player->mo->spritexscale); -} - //#define OLD_MOVEMENT_CODE 1 static void P_3dMovement(player_t *player) { @@ -1890,11 +1854,6 @@ static void P_3dMovement(player_t *player) } } } - - if (!player->powers[pw_justlaunched]) - { - squish(player); - } } // From 1e73c842e2132ac23c46516c2e252cfa174640c6 Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 28 Nov 2021 23:14:31 -0800 Subject: [PATCH 16/20] Run squish effect for players too This is ironic. --- src/p_mobj.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index ee1fa0890..27b668a46 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -3511,6 +3511,16 @@ static void P_CheckFloatbobPlatforms(mobj_t *mobj) } } +static void P_SquishThink(mobj_t *mobj) +{ + if (!(mobj->eflags & MFE_SLOPELAUNCHED)) + { + K_Squish(mobj); + } + + mobj->lastmomz = mobj->momz; +} + static void P_PlayerMobjThinker(mobj_t *mobj) { I_Assert(mobj != NULL); @@ -3576,6 +3586,8 @@ static void P_PlayerMobjThinker(mobj_t *mobj) mobj->eflags &= ~MFE_JUSTHITFLOOR; } + P_SquishThink(mobj); + animonly: P_CyclePlayerMobjState(mobj); } @@ -8805,6 +8817,8 @@ void P_MobjThinker(mobj_t *mobj) P_ButteredSlope(mobj); } + P_SquishThink(mobj); + if (mobj->flags & (MF_ENEMY|MF_BOSS) && mobj->health && P_CheckDeathPitCollide(mobj)) // extra pit check in case these didn't have momz { @@ -8867,11 +8881,6 @@ void P_MobjThinker(mobj_t *mobj) default: break; } - - if (!(mobj->eflags & MFE_SLOPELAUNCHED)) - K_Squish(mobj); - - mobj->lastmomz = mobj->momz; } // Quick, optimized function for the Rail Rings From 0e25de897d02ba496df0f663b854f3b373d81695 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Mon, 29 Nov 2021 05:27:44 -0500 Subject: [PATCH 17/20] Instead of gentlemens dropping packets, it simply delays what it sends --- src/d_clisrv.c | 70 +++++++++++++++++++++++++++----------------------- src/d_clisrv.h | 9 +++++++ 2 files changed, 47 insertions(+), 32 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 5b4141328..f33649cc7 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -141,7 +141,7 @@ UINT8 adminpassmd5[16]; boolean adminpasswordset = false; // Client specific -static ticcmd_t localcmds[MAXSPLITSCREENPLAYERS]; +static ticcmd_t localcmds[MAXSPLITSCREENPLAYERS][MAXGENTLEMENDELAY]; static boolean cl_packetmissed; // here it is for the secondary local player (splitscreen) static UINT8 mynode; // my address pointofview server @@ -440,10 +440,15 @@ static void D_Clearticcmd(tic_t tic) void D_ResetTiccmds(void) { - INT32 i; + INT32 i, j; for (i = 0; i < MAXSPLITSCREENPLAYERS; i++) - memset(&localcmds[i], 0, sizeof(ticcmd_t)); + { + for (j = 0; j < MAXGENTLEMENDELAY; j++) + { + memset(&localcmds[i][j], 0, sizeof(ticcmd_t)); + } + } // Reset the net command list for (i = 0; i < TEXTCMD_HASH_SIZE; i++) @@ -4934,12 +4939,6 @@ static void CL_SendClientCmd(void) size_t packetsize = 0; boolean mis = false; - if (lowest_lag && ( gametic % lowest_lag )) - { - cl_packetmissed = true; - return; - } - netbuffer->packettype = PT_CLIENTCMD; if (cl_packetmissed) @@ -4960,27 +4959,35 @@ static void CL_SendClientCmd(void) } else if (gamestate != GS_NULL && (addedtogame || dedicated)) { + UINT8 lagDelay = 0; + + if (lowest_lag > 0) + { + // Gentlemens' ping. + lagDelay = min(lowest_lag, MAXGENTLEMENDELAY); + } + packetsize = sizeof (clientcmd_pak); - G_MoveTiccmd(&netbuffer->u.clientpak.cmd, &localcmds[0], 1); - netbuffer->u.clientpak.consistancy = SHORT(consistancy[gametic%TICQUEUE]); + G_MoveTiccmd(&netbuffer->u.clientpak.cmd, &localcmds[0][lagDelay], 1); + netbuffer->u.clientpak.consistancy = SHORT(consistancy[gametic % TICQUEUE]); if (splitscreen) // Send a special packet with 2 cmd for splitscreen { netbuffer->packettype = (mis ? PT_CLIENT2MIS : PT_CLIENT2CMD); packetsize = sizeof (client2cmd_pak); - G_MoveTiccmd(&netbuffer->u.client2pak.cmd2, &localcmds[1], 1); + G_MoveTiccmd(&netbuffer->u.client2pak.cmd2, &localcmds[1][lagDelay], 1); if (splitscreen > 1) { netbuffer->packettype = (mis ? PT_CLIENT3MIS : PT_CLIENT3CMD); packetsize = sizeof (client3cmd_pak); - G_MoveTiccmd(&netbuffer->u.client3pak.cmd3, &localcmds[2], 1); + G_MoveTiccmd(&netbuffer->u.client3pak.cmd3, &localcmds[2][lagDelay], 1); if (splitscreen > 2) { netbuffer->packettype = (mis ? PT_CLIENT4MIS : PT_CLIENT4CMD); packetsize = sizeof (client4cmd_pak); - G_MoveTiccmd(&netbuffer->u.client4pak.cmd4, &localcmds[3], 1); + G_MoveTiccmd(&netbuffer->u.client4pak.cmd4, &localcmds[3][lagDelay], 1); } } } @@ -5143,8 +5150,23 @@ static void SV_SendTics(void) // // TryRunTics // +static void CreateNewLocalCMD(UINT8 p, INT32 realtics) +{ + INT32 i; + + for (i = MAXGENTLEMENDELAY-1; i > 0; i--) + { + G_MoveTiccmd(&localcmds[p][i], &localcmds[p][i-1], 1); + } + + G_BuildTiccmd(&localcmds[p][0], realtics, p+1); + localcmds[p][0].flags |= TICCMD_RECEIVED; +} + static void Local_Maketic(INT32 realtics) { + INT32 i; + I_OsPolling(); // I_Getevent D_ProcessEvents(); // menu responder, cons responder, // game responder calls HU_Responder, AM_Responder, @@ -5153,25 +5175,9 @@ static void Local_Maketic(INT32 realtics) if (!dedicated) rendergametic = gametic; // translate inputs (keyboard/mouse/joystick) into game controls - G_BuildTiccmd(&localcmds[0], realtics, 1); - localcmds[0].flags |= TICCMD_RECEIVED; - - if (splitscreen) + for (i = 0; i <= splitscreen; i++) { - G_BuildTiccmd(&localcmds[1], realtics, 2); - localcmds[1].flags |= TICCMD_RECEIVED; - - if (splitscreen > 1) - { - G_BuildTiccmd(&localcmds[2], realtics, 3); - localcmds[2].flags |= TICCMD_RECEIVED; - - if (splitscreen > 2) - { - G_BuildTiccmd(&localcmds[3], realtics, 4); - localcmds[3].flags |= TICCMD_RECEIVED; - } - } + CreateNewLocalCMD(i, realtics); } } diff --git a/src/d_clisrv.h b/src/d_clisrv.h index 93593d736..88712f01c 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -39,6 +39,15 @@ applications may follow different packet versions. // Networking and tick handling related. #define TICQUEUE 512 // more than enough for most timeouts.... #define MAXTEXTCMD 256 + +// No. of tics your controls can be delayed by. + +// TODO: Instead of storing a ton of extra cmds for gentlemens' delay, +// keep them in a linked-list, with timestamps to discard everything that's older than already sent. +// That will support any amount of lag, and be less wasteful for clients who don't use it. +// This just works as a quick implementation. +#define MAXGENTLEMENDELAY TICRATE + // // Packet structure // From 4b42f99ca75c3427da5149132a5d77f204f5c9a7 Mon Sep 17 00:00:00 2001 From: toaster Date: Mon, 29 Nov 2021 19:41:11 +0000 Subject: [PATCH 18/20] Fix player removal not being recorded in netreplays. (Will not work with existing replays that lack this data) --- src/d_clisrv.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 5b4141328..1bb3675cf 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -2390,6 +2390,7 @@ void CL_RemovePlayer(INT32 playernum, kickreason_t reason) // remove avatar of player playeringame[playernum] = false; + demo_extradata[playernum] |= DXD_PLAYSTATE; playernode[playernum] = UINT8_MAX; while (!playeringame[doomcom->numslots-1] && doomcom->numslots > 1) doomcom->numslots--; From 9e121958405b3b389d861667868e56a81e20d3a3 Mon Sep 17 00:00:00 2001 From: toaster Date: Mon, 29 Nov 2021 19:45:01 +0000 Subject: [PATCH 19/20] Fix two more minor issues with reading and writing replays. * DXD_PLAYSTATE and DXD_WEAPONPREF no longer conflict when both are read during the same tic. (VERY rare bug, but was possible) * Fixed G_WriteDemoTiccmd not considering the sign of forwardmove properly. (Of basically no consequence r/n, but could bite us down the line if not caught) --- src/g_demo.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/g_demo.c b/src/g_demo.c index eda590420..99e6e2622 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -308,9 +308,9 @@ void G_ReadDemoExtraData(void) } if (extradata & DXD_PLAYSTATE) { - extradata = READUINT8(demo_p); + i = READUINT8(demo_p); - switch (extradata) { + switch (i) { case DXD_PST_PLAYING: players[p].pflags |= PF_WANTSTOJOIN; // fuck you //CONS_Printf("player %s is despectating on tic %d\n", player_names[p], leveltime); @@ -350,11 +350,11 @@ void G_ReadDemoExtraData(void) } if (extradata & DXD_WEAPONPREF) { - extradata = READUINT8(demo_p); + i = READUINT8(demo_p); players[p].pflags &= ~(PF_KICKSTARTACCEL); - if (extradata & 1) + if (i & 1) players[p].pflags |= PF_KICKSTARTACCEL; - //CONS_Printf("weaponpref is %d for player %d\n", extradata, p); + //CONS_Printf("weaponpref is %d for player %d\n", i, p); } p = READUINT8(demo_p); @@ -500,6 +500,7 @@ void G_ReadDemoTiccmd(ticcmd_t *cmd, INT32 playernum) if (!demo_p || !demo.deferstart) return; + ziptic = READUINT8(demo_p); if (ziptic & ZT_FWD) @@ -537,7 +538,7 @@ void G_WriteDemoTiccmd(ticcmd_t *cmd, INT32 playernum) if (cmd->forwardmove != oldcmd[playernum].forwardmove) { - WRITEUINT8(demo_p,cmd->forwardmove); + WRITESINT8(demo_p,cmd->forwardmove); oldcmd[playernum].forwardmove = cmd->forwardmove; ziptic |= ZT_FWD; } From 6457ab0a9cdd6f50d815e6d31a8f7918f21145f8 Mon Sep 17 00:00:00 2001 From: James R Date: Mon, 29 Nov 2021 19:56:33 -0800 Subject: [PATCH 20/20] Raise squish max --- src/k_kart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/k_kart.c b/src/k_kart.c index 85b62c4c2..bd2f33220 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -4510,7 +4510,7 @@ void K_DriftDustHandling(mobj_t *spawner) void K_Squish(mobj_t *mo) { - const fixed_t maxstretch = 2*FRACUNIT; + const fixed_t maxstretch = 4*FRACUNIT; const fixed_t factor = 3 * mo->height / 2; const fixed_t threshold = factor / 6;