From baeb48ca1f9168ea7e85a6a6093f7730894d5e81 Mon Sep 17 00:00:00 2001 From: toaster Date: Mon, 6 Mar 2023 22:31:35 +0000 Subject: [PATCH] roundconditions_t - State tracking for events which occour mid-match and don't stay that way - Exists on every player struct to simplify writes, but A) not netsynced and B) only checked for local players - Updated in the relevant locations - no centralised ticking at the moment - Has a number of new associated conditions that require playing (UCRP's). - The following require [True/False] as supplementary information. - FallOff - TouchOffroad - TouchSneakerPanel - RingDebt - The following have no supplementary information because they're universally a specific achievement. - TripwireHyuu - SPBNeuter - LandmineDunk - HitMidair - The following has specific requirements that can be set. - WetPlayer [name of fluid] - Append "Strict" to forbid even skimming the surface of the map's fluid. --- src/d_player.h | 16 +++++++++++++ src/deh_soc.c | 39 +++++++++++++++++++++++++++++++ src/g_game.c | 11 +++++++++ src/k_collide.c | 5 ++++ src/k_kart.c | 10 ++++++++ src/m_cond.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++ src/m_cond.h | 12 ++++++++++ src/p_inter.c | 20 +++++++++++++++- src/p_mobj.c | 4 ++++ src/p_user.c | 5 ++++ src/typedef.h | 1 + 11 files changed, 184 insertions(+), 1 deletion(-) diff --git a/src/d_player.h b/src/d_player.h index 98dee8e9a..303013da1 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -333,6 +333,21 @@ struct botvars_t tic_t spindashconfirm; // When high enough, they will try spindashing }; +// player_t struct for round-specific condition tracking + +struct roundconditions_t +{ + // Trivial Yes/no events across multiple UCRP's + boolean fell_off; + boolean touched_offroad; + boolean touched_sneakerpanel; + boolean debt_rings; + boolean tripwire_hyuu; + boolean spb_neuter; + boolean landmine_dunk; + boolean hit_midair; +}; + // player_t struct for all skybox variables struct skybox_t { mobj_t * viewpoint; @@ -682,6 +697,7 @@ struct player_t #endif sonicloopvars_t loop; + roundconditions_t roundconditions; }; #ifdef __cplusplus diff --git a/src/deh_soc.c b/src/deh_soc.c index 8ace8c162..9c853e0ab 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -2617,6 +2617,45 @@ static void readcondition(UINT8 set, UINT32 id, char *word2) return; } } + else if ((offset=0) || fastcmp(params[0], "FALLOFF") + || (++offset && fastcmp(params[0], "TOUCHOFFROAD")) + || (++offset && fastcmp(params[0], "TOUCHSNEAKERPANEL")) + || (++offset && fastcmp(params[0], "RINGDEBT"))) + { + PARAMCHECK(1); + ty = UCRP_FALLOFF + offset; + re = 1; + + if (params[1][0] == 'F' || params[1][0] == 'N' || params[1][0] == '0') + re = 0; + } + else if ((offset=0) || fastcmp(params[0], "TRIPWIREHYUU") + || (++offset && fastcmp(params[0], "SPBNEUTER")) + || (++offset && fastcmp(params[0], "LANDMINEDUNK")) + || (++offset && fastcmp(params[0], "HITMIDAIR"))) + { + //PARAMCHECK(1); + ty = UCRP_TRIPWIREHYUU + offset; + } + else if (fastcmp(params[0], "WETPLAYER")) + { + PARAMCHECK(1); + ty = UCRP_WETPLAYER; + re = MFE_UNDERWATER; + x1 = 1; + stringvar = Z_StrDup(params[1]); + + if (params[2]) + { + if (fastcmp(params[2], "STRICT")) + re |= MFE_TOUCHWATER; + else + { + deh_warning("liquid strictness requirement \"%s\" invalid for condition ID %d", params[2], id+1); + return; + } + } + } else { deh_warning("Invalid condition name %s for condition ID %d", params[0], id+1); diff --git a/src/g_game.c b/src/g_game.c index adc0efd48..86efdd11c 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -2371,6 +2371,9 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) INT32 khudfault; INT32 kickstartaccel; + roundconditions_t roundconditions; + boolean saveroundconditions; + score = players[player].score; lives = players[player].lives; ctfteam = players[player].ctfteam; @@ -2461,6 +2464,8 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) khudfinish = 0; khudcardanimation = 0; starpostnum = 0; + + saveroundconditions = false; } else { @@ -2509,6 +2514,9 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) starpostnum = players[player].starpostnum; pflags |= (players[player].pflags & (PF_STASIS|PF_ELIMINATED|PF_NOCONTEST|PF_FAULT|PF_LOSTLIFE)); + + memcpy(&roundconditions, &players[player].roundconditions, sizeof (roundconditions)); + saveroundconditions = true; } if (!betweenmaps) @@ -2592,6 +2600,9 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) memcpy(&p->itemRoulette, &itemRoulette, sizeof (p->itemRoulette)); memcpy(&p->respawn, &respawn, sizeof (p->respawn)); + if (saveroundconditions) + memcpy(&p->roundconditions, &roundconditions, sizeof (p->roundconditions)); + if (follower) P_RemoveMobj(follower); diff --git a/src/k_collide.c b/src/k_collide.c index ee773dfa3..cea3497c4 100644 --- a/src/k_collide.c +++ b/src/k_collide.c @@ -411,7 +411,12 @@ boolean K_LandMineCollide(mobj_t *t1, mobj_t *t2) // Banana snipe! if (t1->health > 1) + { + if (t1->target && t1->target->player) + t1->target->player->roundconditions.landmine_dunk = true; + S_StartSound(t2, sfx_bsnipe); + } if (t2->player->flamedash && t2->player->itemtype == KITEM_FLAMESHIELD) { diff --git a/src/k_kart.c b/src/k_kart.c index 5e9982648..05755dcbe 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -1118,6 +1118,9 @@ static void K_UpdateOffroad(player_t *player) if (player->offroad > offroadstrength) player->offroad = offroadstrength; + + if (player->offroad > (2*offroadstrength) / TICRATE) + player->roundconditions.touched_offroad = true; } else player->offroad = 0; @@ -4065,7 +4068,11 @@ void K_ApplyTripWire(player_t *player, tripwirestate_t state) K_TumblePlayer(player, NULL, NULL); if (state == TRIPSTATE_PASSED) + { S_StartSound(player->mo, sfx_ssa015); + if (player->hyudorotimer > 0) + player->roundconditions.tripwire_hyuu = true; + } else if (state == TRIPSTATE_BLOCKED) { S_StartSound(player->mo, sfx_kc40); @@ -5731,6 +5738,9 @@ void K_DoSneaker(player_t *player, INT32 type) { const fixed_t intendedboost = FRACUNIT/2; + if (player->floorboost != 0) + player->roundconditions.touched_sneakerpanel = true; + if (player->floorboost == 0 || player->floorboost == 3) { const sfxenum_t normalsfx = sfx_cdfm01; diff --git a/src/m_cond.c b/src/m_cond.c index aedc2583e..c06fa5cc0 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -593,6 +593,23 @@ void M_UpdateConditionSetsPending(void) break; } + + case UCRP_WETPLAYER: + { + if (cn->extrainfo1) + { + char *l; + + for (l = cn->stringvar; *l != '\0'; l++) + { + *l = tolower(*l); + } + + cn->extrainfo1 = 0; + } + break; + } + default: break; } @@ -773,6 +790,28 @@ boolean M_CheckCondition(condition_t *cn, player_t *player) && !K_CanChangeRules(false) // too easy to change cv_timelimit && player->realtime < timelimitintics && (timelimitintics + extratimeintics + secretextratime - player->realtime) >= (unsigned)cn->requirement); + + case UCRP_FALLOFF: + return (player->roundconditions.fell_off == (cn->requirement == 1)); + case UCRP_TOUCHOFFROAD: + return (player->roundconditions.touched_offroad == (cn->requirement == 1)); + case UCRP_TOUCHSNEAKERPANEL: + return (player->roundconditions.touched_sneakerpanel == (cn->requirement == 1)); + case UCRP_RINGDEBT: + return (!(gametyperules & GTR_SPHERES) && (player->roundconditions.debt_rings == (cn->requirement == 1))); + + case UCRP_TRIPWIREHYUU: + return (player->roundconditions.tripwire_hyuu); + case UCRP_SPBNEUTER: + return (player->roundconditions.spb_neuter); + case UCRP_LANDMINEDUNK: + return (player->roundconditions.landmine_dunk); + case UCRP_HITMIDAIR: + return (player->roundconditions.hit_midair); + + case UCRP_WETPLAYER: + return (((player->roundconditions.wet_player & cn->requirement) == 0) + || player->roundconditions.fell_off); // Levels with water tend to texture their pits as water too } return false; } @@ -1137,6 +1176,29 @@ static const char *M_GetConditionString(condition_t *cn) G_TicsToSeconds(cn->requirement), G_TicsToCentiseconds(cn->requirement)); + case UCRP_FALLOFF: + return (cn->requirement == 1) ? "fall off the course" : "without falling off"; + case UCRP_TOUCHOFFROAD: + return (cn->requirement == 1) ? "touch offroad" : "without touching any offroad"; + case UCRP_TOUCHSNEAKERPANEL: + return (cn->requirement == 1) ? "touch a Sneaker Panel" : "without touching any Sneaker Panels"; + case UCRP_RINGDEBT: + return (cn->requirement == 1) ? "go into Ring debt" : "without going into Ring debt"; + + case UCRP_TRIPWIREHYUU: + return "go through Tripwire after getting snared by Hyudoro"; + case UCRP_SPBNEUTER: + return "shock a Self Propelled Bomb into submission"; + case UCRP_LANDMINEDUNK: + return "dunk a Landmine on another racer's head"; + case UCRP_HITMIDAIR: + return "hit another racer with a projectile while you're both in the air"; + + case UCRP_WETPLAYER: + return va("without %s %s", + (cn->requirement & MFE_TOUCHWATER) ? "touching any" : "going into", + cn->stringvar); + default: break; } diff --git a/src/m_cond.h b/src/m_cond.h index ef183734a..e5e9e0412 100644 --- a/src/m_cond.h +++ b/src/m_cond.h @@ -75,6 +75,18 @@ typedef enum UCRP_FINISHTIME, // Finish <= [time, tics] UCRP_FINISHTIMEEXACT, // Finish == [time, tics] UCRP_FINISHTIMELEFT, // Finish with at least [time, tics] to spare + + UCRP_FALLOFF, // Fall off (or don't) + UCRP_TOUCHOFFROAD, // Touch offroad (or don't) + UCRP_TOUCHSNEAKERPANEL, // Either touch sneaker panel (or don't) + UCRP_RINGDEBT, // Go into debt (or don't) + + UCRP_TRIPWIREHYUU, // Go through tripwire with Hyudoro + UCRP_SPBNEUTER, // Kill an SPB with Lightning + UCRP_LANDMINEDUNK, // huh? you died? that's weird. all i did was try to hug you... + UCRP_HITMIDAIR, // Hit another player mid-air with a kartfielditem + + UCRP_WETPLAYER, // Touch [fluid] } conditiontype_t; // Condition Set information diff --git a/src/p_inter.c b/src/p_inter.c index 75f0ab487..576825002 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -1940,6 +1940,7 @@ static boolean P_KillPlayer(player_t *player, mobj_t *inflictor, mobj_t *source, { case DMG_DEATHPIT: // Respawn kill types + player->roundconditions.fell_off = true; K_DoIngameRespawn(player); return false; case DMG_SPECTATOR: @@ -2025,6 +2026,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da { player_t *player; boolean force = false; + boolean spbpop = false; INT32 laglength = 6; @@ -2058,6 +2060,14 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da Obj_MonitorOnDamage(target, inflictor, damage); break; + case MT_SPB: + spbpop = (damagetype & DMG_TYPEMASK) == DMG_VOLTAGE; + if (spbpop && source && source->player) + { + source->player->roundconditions.spb_neuter = true; + } + break; + default: break; } @@ -2076,7 +2086,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da if (!force) { - if (!(target->type == MT_SPB && (damagetype & DMG_TYPEMASK) == DMG_VOLTAGE)) + if (!spbpop) { if (!(target->flags & MF_SHOOTABLE)) return false; // shouldn't happen... @@ -2130,6 +2140,14 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da } } + if (inflictor && source && source->player) + { + if (P_IsKartFieldItem(source->type) + && target->player->airtime > TICRATE/2 + && source->player->airtime > TICRATE/2) + source->player->roundconditions.hit_midair = true; + } + // Instant-Death if ((damagetype & DMG_DEATHMASK)) { diff --git a/src/p_mobj.c b/src/p_mobj.c index 8fe24ffed..9594935bc 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -3421,6 +3421,10 @@ void P_MobjCheckWater(mobj_t *mobj) { return; } + + p->roundconditions.wet_player |= (mobj->eflags & (MFE_TOUCHWATER|MFE_UNDERWATER|MFE_GOOWATER)); + if (p->roundconditions.wet_player) + CONS_Printf("%u\n", p->roundconditions.wet_player); } if (mobj->flags & MF_APPLYTERRAIN) diff --git a/src/p_user.c b/src/p_user.c index 94e96a45b..2d374e060 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -518,6 +518,11 @@ INT32 P_GivePlayerRings(player_t *player, INT32 num_rings) player->rings += num_rings; + if (player->rings < 0) + { + player->roundconditions.debt_rings = true; + } + return num_rings; } diff --git a/src/typedef.h b/src/typedef.h index 632684d1e..c3b404b03 100644 --- a/src/typedef.h +++ b/src/typedef.h @@ -44,6 +44,7 @@ TYPEDEF (discordRequest_t); // d_player.h TYPEDEF (respawnvars_t); TYPEDEF (botvars_t); +TYPEDEF (roundconditions_t); TYPEDEF (skybox_t); TYPEDEF (itemroulette_t); TYPEDEF (player_t);