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"
This commit is contained in:
toaster 2023-10-16 17:09:12 +01:00
parent 3c5e03428a
commit d4e3d8433d
6 changed files with 98 additions and 4 deletions

View file

@ -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

View file

@ -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);

View file

@ -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",

View file

@ -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;

View file

@ -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))

View file

@ -32,9 +32,6 @@ extern "C" {
//#define VIEWHEIGHTS "41"
// Maximum laps per map.
#define MAX_LAPS 99
// Maximum player score.
#define MAXSCORE 99999990 // 999999990