From f0d1813752c31421163ae417b67f21b5fa57b391 Mon Sep 17 00:00:00 2001 From: toaster Date: Mon, 16 Oct 2023 18:04:23 +0100 Subject: [PATCH] UCRP_TRACKHAZARD: Optimise implementation to not be 100 booleans Much like player->availabilities, use a set of bits on UINT8. --- src/d_player.h | 2 +- src/m_cond.c | 56 ++++++++++++++++++++++++++++++++++++++------------ src/p_inter.c | 11 ++++++---- 3 files changed, 51 insertions(+), 18 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index f0b3e4edc..548ed8f7c 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -402,7 +402,7 @@ struct roundconditions_t boolean landmine_dunk; boolean hit_midair; - boolean hittrackhazard[MAX_LAPS+1]; + UINT8 hittrackhazard[((MAX_LAPS+1)/8) + 1]; mobjeflag_t wet_player; diff --git a/src/m_cond.c b/src/m_cond.c index 3f38e696a..6d867e254 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -1630,27 +1630,57 @@ boolean M_CheckCondition(condition_t *cn, player_t *player) if (player->laps <= (requiredlap - cn->requirement)) return false; - const boolean desired = (cn->requirement == 1); + UINT8 requiredbit = 1<<(requiredlap & 7); + requiredlap /= 8; + 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 (cn->requirement == 0) { - if (player->roundconditions.hittrackhazard[requiredlap] != desired) + // The "don't get hit on any lap" check is trivial. + for (; requiredlap > 0; requiredlap--) + { + if (player->roundconditions.hittrackhazard[requiredlap] != 0) + return false; + } + + return (player->roundconditions.hittrackhazard[0] == 0); + } + + // The following is my attempt at a major optimisation. + // The naive version was MAX_LAP bools, which is ridiculous. + + // Check the highest relevant byte for all necessary bits. + // We only do this if an == 0xFF/0xFE check wouldn't satisfy. + if (requiredbit != 7) + { + // Last bit MAYBE not needed, POSITION doesn't count. + const UINT8 finalbit = (requiredlap == 0) ? 1 : 0; + while (requiredbit != finalbit) + { + if (!(player->roundconditions.hittrackhazard[requiredlap] & requiredbit)) + return false; + requiredbit /= 2; + } + + if (requiredlap == 0) + return true; + + requiredlap--; + } + + // All bytes between the top and the bottom need to be checked for saturation. + for (; requiredlap > 0; requiredlap--) + { + if (player->roundconditions.hittrackhazard[requiredlap] != 0xFF) return false; } - return true; + // Last bit not needed, POSITION doesn't count. + return (player->roundconditions.hittrackhazard[0] == 0xFE); } - return (player->roundconditions.hittrackhazard[requiredlap] == desired); + return (!(player->roundconditions.hittrackhazard[requiredlap] & requiredbit) != (cn->requirement == 1)); } case UCRP_WETPLAYER: diff --git a/src/p_inter.c b/src/p_inter.c index 7b763ff62..6b2f248d8 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -2632,11 +2632,14 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da } else if (!(inflictor && inflictor->player) && player->laps <= numlaps - && damagetype != DMG_DEATHPIT - && player->roundconditions.hittrackhazard[player->laps] == false) + && damagetype != DMG_DEATHPIT) { - player->roundconditions.hittrackhazard[player->laps] = true; - player->roundconditions.checkthisframe = true; + const UINT8 requiredbit = 1<<(player->laps & 7); + if (!(player->roundconditions.hittrackhazard[player->laps/8] & requiredbit)) + { + player->roundconditions.hittrackhazard[player->laps/8] |= requiredbit; + player->roundconditions.checkthisframe = true; + } } // Instant-Death