From d4e3d8433d8c46dc5287ceca7b8c88c7079c3d5e Mon Sep 17 00:00:00 2001 From: toaster Date: Mon, 16 Oct 2023 17:09:12 +0100 Subject: [PATCH] UCRP_TRACKHAZARD A series of 100 booleans on the roundconditions struct, one per possible lap. Allows for a full suite of track hazard touching conditions - see the following examples. - `Condition1 = Prefix_IsMap RR_MOTOBUGMOTORWAY - `Condition1 = TrackHazard No` - `Condition1 = IsMap RR_MOTOBUGMOTORWAY` - "MOTOBUG MOTORWAY: Don't touch any track hazard" - `Condition1 = Prefix_GrandPrix` - `Condition1 = IsMap RR_HARDBOILEDSTADIUM` - `Condition1 = TrackHazard Yes` - `Condition1 = And` - `Condition1 = FinishPlace 1` - "GRAND PRIX: On HARD-BOILED STADIUM, touch a track hazard every lap & finish in 1st" - `Condition1 = Prefix IsMap RR_DEATHEGG` - `Condition1 = Trackhazard No 8` - "DEATH EGG ZONE: Don't touch any track hazard on lap 8" - `Condition1 = Prefix_IsMap RR_SPEEDHIGHWAY - `Condition1 = TrackHazard No Final` - "SPEED HIGHWAY: Don't touch any track hazard on the final lap" --- src/d_player.h | 6 ++++++ src/deh_soc.c | 26 ++++++++++++++++++++++++ src/m_cond.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/m_cond.h | 2 ++ src/p_inter.c | 11 +++++++++- src/p_local.h | 3 --- 6 files changed, 98 insertions(+), 4 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index 89161e23c..f0b3e4edc 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -39,6 +39,10 @@ extern "C" { #endif +// Maximum laps per map. +// (done here as p_local.h, the previous host, has this as a dependency - but we must use it here) +#define MAX_LAPS 99 + // Extra abilities/settings for skins (combinable stuff) typedef enum { @@ -398,6 +402,8 @@ struct roundconditions_t boolean landmine_dunk; boolean hit_midair; + boolean hittrackhazard[MAX_LAPS+1]; + mobjeflag_t wet_player; // 32 triggers, one bit each, for map execution diff --git a/src/deh_soc.c b/src/deh_soc.c index 7475b7e1d..d6d92a031 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -2981,6 +2981,32 @@ static void readcondition(UINT16 set, UINT32 id, char *word2) //PARAMCHECK(1); ty = UCRP_TRIPWIREHYUU + offset; } + else if (fastcmp(params[0], "TRACKHAZARD")) + { + PARAMCHECK(1); + ty = UCRP_TRACKHAZARD; + re = 1; + x1 = -1; + + if (params[1][0] == 'F' || params[1][0] == 'N' || params[1][0] == '0') + re = 0; + + if (params[2]) + { + if (fastcmp(params[2], "FINAL")) + x1 = -2; + else + { + x1 = atoi(params[2]); + + if (re < 0 || re > MAX_LAPS) + { + deh_warning("Lap number %d out of range (0 - %u) for condition ID %d", x1, MAX_LAPS, id+1); + return; + } + } + } + } else { deh_warning("Invalid condition name %s for condition ID %d", params[0], id+1); diff --git a/src/m_cond.c b/src/m_cond.c index 1dffc05c2..3f38e696a 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -1611,6 +1611,48 @@ boolean M_CheckCondition(condition_t *cn, player_t *player) case UCRP_HITMIDAIR: return (player->roundconditions.hit_midair); + case UCRP_TRACKHAZARD: + { + INT16 requiredlap = cn->extrainfo1; + + if (requiredlap < 0) + { + // Prevents lowered numlaps from activating it + // (this also handles exiting, for all-laps situations) + requiredlap = max(mapheaderinfo[gamemap-1]->numlaps, numlaps); + } + + // cn->requirement is used as an offset here + // so if you need to get hit on lap x, the + // condition can fire while that lap is active + // but if you need to NOT get hit on lap X, + // it only fires once the lap is complete + if (player->laps <= (requiredlap - cn->requirement)) + return false; + + const boolean desired = (cn->requirement == 1); + if (cn->extrainfo1 == -1) + { + // Using cn->requirement as the first + // counted lap means that for conditions + // that require you to get hit every lap, + // that doesn't count POSITION - + // but if you can't get hit by a track + // hazard at all during the race, + // you're forbidden from getting hurt + // by a track hazard during POSITION. + for (; requiredlap >= cn->requirement; requiredlap--) + { + if (player->roundconditions.hittrackhazard[requiredlap] != desired) + return false; + } + + return true; + } + + return (player->roundconditions.hittrackhazard[requiredlap] == desired); + } + 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 @@ -2293,6 +2335,18 @@ static const char *M_GetConditionString(condition_t *cn) case UCRP_HITMIDAIR: return "hit another racer with a projectile while you're both in the air"; + case UCRP_TRACKHAZARD: + { + work = (cn->requirement == 1) ? "touch a track hazard" : "don't touch any track hazards"; + if (cn->extrainfo1 == -1) + return va("%s%s", work, (cn->requirement == 1) ? " on every lap" : ""); + if (cn->extrainfo1 == -2) + return va("%s on the final lap", work); + if (cn->extrainfo1 == 0) + return va("%s during POSITION", work); + return va("%s on lap %u", work, cn->extrainfo1); + } + case UCRP_WETPLAYER: return va("without %s %s", (cn->requirement & MFE_TOUCHWATER) ? "touching any" : "going into", diff --git a/src/m_cond.h b/src/m_cond.h index 41a05e159..0a78c3ad2 100644 --- a/src/m_cond.h +++ b/src/m_cond.h @@ -122,6 +122,8 @@ typedef enum 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_TRACKHAZARD, // (Don't) get hit by a track hazard (maybe specific lap) + UCRP_WETPLAYER, // Don't touch [strictness] [fluid] } conditiontype_t; diff --git a/src/p_inter.c b/src/p_inter.c index a843a8490..7b763ff62 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -2618,9 +2618,10 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da } } - if (inflictor && source && source->player) + if (source && source->player) { if (source->player->roundconditions.hit_midair == false + && inflictor && K_IsMissileOrKartItem(inflictor) && target->player->airtime > TICRATE/2 && source->player->airtime > TICRATE/2) @@ -2629,6 +2630,14 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da source->player->roundconditions.checkthisframe = true; } } + else if (!(inflictor && inflictor->player) + && player->laps <= numlaps + && damagetype != DMG_DEATHPIT + && player->roundconditions.hittrackhazard[player->laps] == false) + { + player->roundconditions.hittrackhazard[player->laps] = true; + player->roundconditions.checkthisframe = true; + } // Instant-Death if ((damagetype & DMG_DEATHMASK)) diff --git a/src/p_local.h b/src/p_local.h index 15b338f9d..3c809034f 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -32,9 +32,6 @@ extern "C" { //#define VIEWHEIGHTS "41" -// Maximum laps per map. -#define MAX_LAPS 99 - // Maximum player score. #define MAXSCORE 99999990 // 999999990