1
0
Fork 0
mirror of https://codeberg.org/demostf/parser.git synced 2026-06-04 02:24:12 +02:00

player condition handling

This commit is contained in:
Robin Appelman 2025-06-26 00:17:05 +02:00
commit 809d2504f5
7 changed files with 499 additions and 4 deletions

141
src/demo/data/cond.rs Normal file
View file

@ -0,0 +1,141 @@
use num_enum::TryFromPrimitive;
use serde::{Deserialize, Serialize};
#[derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, TryFromPrimitive)]
#[repr(u8)]
pub enum PlayerCondition {
Aiming = 0,
Zoomed = 1,
Disguising = 2,
Disguised = 3,
Stealthed = 4,
Invulnerable = 5,
Teleported = 6,
Taunting = 7,
InvulnerableWearingOff = 8,
StealthedBlink = 9,
SelectedToTeleport = 10,
CritBoosted = 11,
TmpDamageBonus = 12,
FeignDeath = 13,
Phase = 14,
Stunned = 15,
OffensiveBuff = 16,
ShieldCharge = 17,
DemoBuff = 18,
EnergyBuff = 19,
RadiusHeal = 20,
HealthBuff = 21,
Burning = 22,
HealthOverHealed = 23,
Urine = 24,
Bleeding = 25,
DefensiveBuff = 26,
MadMilk = 27,
MegaHeal = 28,
RegenOnDamageBuff = 29,
MarkedForDeath = 30,
NoHealingDamageBuff = 31,
SpeedBoost = 32,
CritBoostedPumpkin = 33,
CritBoostedUserBuff = 34,
CritBoostedDemoCharge = 35,
SodaPopperHype = 36,
CritBoostedFirstBlood = 37,
CritBoostedBonusTime = 38,
CritBoostedCtfCapture = 39,
CritBoostedOnKill = 40,
CannotSwitchFromMelee = 41,
DefenseBuffNoCritBlock = 42,
Reprogrammed = 43,
CritBoostedRageBuff = 44,
DefenseBuffHigh = 45,
SniperChargeRageBuff = 46,
DisguiseWearingOff = 47,
MarkedForDeathSilent = 48,
DisguisedAsDispenser = 49,
Sapped = 50,
InvulnerableHideUnlessDamaged = 51,
InvulnerableUserBuff = 52,
HalloweenBombHead = 53,
HalloweenThriller = 54,
RadiusHealOnDamage = 55,
CritBoostedCardEffect = 56,
InvulnerableCardEffect = 57,
MedigunUberBulletResist = 58,
MedigunUberBlastResist = 59,
MedigunUberFireResist = 60,
MedigunSmallBulletResist = 61,
MedigunSmallBlastResist = 62,
MedigunSmallFireResist = 63,
StealthedUserBuff = 64,
MedigunDebuff = 65,
StealthedUserBuffFading = 66,
BulletImmune = 67,
BlastImmune = 68,
FireImmune = 69,
PreventDeath = 70,
MvmBotStunRadiowave = 71,
HalloweenSpeedBoost = 72,
HalloweenQuickHeal = 73,
HalloweenGiant = 74,
HalloweenTiny = 75,
HalloweenInHell = 76,
HalloweenGhostMode = 77,
MiniCritBoostedOnKill = 78,
ObscuredSmoke = 79,
ParachuteActive = 80,
BlastJumping = 81,
HalloweenKart = 82,
HalloweenKartDash = 83,
BalloonHead = 84,
MeleeOnly = 85,
SwimmingCurse = 86,
FreezeInput = 87,
HalloweenKartCage = 88,
RuneStrength = 90,
RuneHaste = 91,
RuneRegen = 92,
RuneResist = 93,
RuneVampire = 94,
RuneReflect = 95,
RunePrecision = 96,
RuneAgility = 97,
GrapplingHook = 98,
GrapplingHookSafeFall = 99,
GrapplingHookLatched = 100,
GrapplingHookBleeding = 101,
AfterburnImmune = 102,
RuneKnockout = 103,
RuneImbalance = 104,
CritBoostedRuneTemp = 105,
PasstimeInterception = 106,
SwimmingNoEffects = 107,
PURGATORY = 108,
RuneKing = 109,
RunePlague = 110,
RuneSupernova = 111,
PLAGUE = 112,
KingBuffed = 113,
TeamGlows = 114,
KnockedIntoAir = 115,
CompetitiveWinner = 116,
CompetitiveLoser = 117,
HealingDebuff = 118,
PasstimePenaltyDebuff = 119,
GrappledToPlayer = 120,
GrappledByPlayer = 121,
ParachuteDeployed = 122,
GAS = 123,
BurningPyro = 124,
RocketPack = 125,
LostFooting = 126,
AirCurrent = 127,
HalloweenHellHeal = 128,
PowerUpModeDominant = 129,
ImmuneToPushback = 130,
}
impl PlayerCondition {
pub const MAX: PlayerCondition = PlayerCondition::ImmuneToPushback;
}

View file

@ -1,3 +1,4 @@
pub use super::cond::PlayerCondition;
use crate::demo::data::DemoTick;
use crate::demo::gameevent_gen::PlayerDeathEvent;
use crate::demo::gamevent::GameEvent;
@ -8,6 +9,7 @@ use crate::demo::vector::Vector;
use parse_display::Display;
use serde::{Deserialize, Serialize};
use std::collections::{BTreeMap, HashMap};
use std::ops::Rem;
#[derive(Default, Serialize, Deserialize, Debug, Copy, Clone, Eq, PartialEq, Hash, Display)]
pub struct Handle(pub i64);
@ -73,6 +75,7 @@ pub struct Player {
pub in_pvs: bool,
pub bounds: Box,
pub weapons: [Handle; 3],
pub(crate) conditions: [u8; 20],
}
pub const PLAYER_BOX_DEFAULT: Box = Box {
@ -108,6 +111,31 @@ impl Player {
}
}
}
pub fn conditions(&self) -> impl Iterator<Item = PlayerCondition> + '_ {
(1..=(PlayerCondition::MAX as u8)).filter_map(|cond_int| {
let byte = cond_int / 8;
let bit = cond_int.rem(8);
let cond_byte = *self.conditions.get(byte as usize)?;
if (cond_byte >> bit as usize) == 1 {
PlayerCondition::try_from(cond_byte).ok()
} else {
None
}
})
}
pub fn has_condition(&self, condition: PlayerCondition) -> bool {
let cond_int = condition as u8;
let byte = cond_int / 8;
let bit = cond_int.rem(8);
let cond_byte = self
.conditions
.get(byte as usize)
.copied()
.unwrap_or_default();
cond_byte >> bit as usize == 1
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]

View file

@ -1,3 +1,4 @@
mod cond;
pub mod game_state;
pub mod userinfo;