#[cfg(test)]
#[path = "../tests/tf2/conditions.rs"]
mod tests;
use crate::Server;
use crate::datatables::{ServerClass, Storage};
use crate::entities::Entity;
use crate::entities::EntityHandle;
use crate::tf2::player_methods;
use crate::tf2::script_instances::{ScriptInstance, ScriptInstanceError};
use sdk_raw::tf2::conditions as raw;
use sdk_raw::tf2::script_binding::BindingError;
use std::cell::Cell;
use std::collections::HashMap;
use std::ffi::CStr;
use std::ptr::NonNull;
const WORD_NAMES: [&CStr; WORDS] = [
c"m_nPlayerCond",
c"m_nPlayerCondEx",
c"m_nPlayerCondEx2",
c"m_nPlayerCondEx3",
c"m_nPlayerCondEx4",
];
const WORDS: usize = (sys::ETFCond_TF_COND_LAST as usize).div_ceil(32);
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[doc(alias("ETFCond"))]
pub struct Condition(i32);
impl Condition {
#[doc(alias("TF_COND_AFTERBURN_IMMUNE"))]
pub const AFTERBURN_IMMUNE: Self = Self(sys::ETFCond_TF_COND_AFTERBURN_IMMUNE);
#[doc(alias("TF_COND_AIMING"))]
pub const AIMING: Self = Self(sys::ETFCond_TF_COND_AIMING);
#[doc(alias("TF_COND_AIR_CURRENT"))]
pub const AIR_CURRENT: Self = Self(sys::ETFCond_TF_COND_AIR_CURRENT);
#[doc(alias("TF_COND_BALLOON_HEAD"))]
pub const BALLOON_HEAD: Self = Self(sys::ETFCond_TF_COND_BALLOON_HEAD);
#[doc(alias("TF_COND_BLAST_IMMUNE"))]
pub const BLAST_IMMUNE: Self = Self(sys::ETFCond_TF_COND_BLAST_IMMUNE);
#[doc(alias("TF_COND_BLASTJUMPING"))]
pub const BLAST_JUMPING: Self = Self(sys::ETFCond_TF_COND_BLASTJUMPING);
#[doc(alias("TF_COND_BLEEDING"))]
pub const BLEEDING: Self = Self(sys::ETFCond_TF_COND_BLEEDING);
#[doc(alias("TF_COND_BULLET_IMMUNE"))]
pub const BULLET_IMMUNE: Self = Self(sys::ETFCond_TF_COND_BULLET_IMMUNE);
#[doc(alias("TF_COND_BURNING"))]
pub const BURNING: Self = Self(sys::ETFCond_TF_COND_BURNING);
#[doc(alias("TF_COND_BURNING_PYRO"))]
pub const BURNING_PYRO: Self = Self(sys::ETFCond_TF_COND_BURNING_PYRO);
#[doc(alias("TF_COND_CANNOT_SWITCH_FROM_MELEE"))]
pub const CANNOT_SWITCH_FROM_MELEE: Self = Self(sys::ETFCond_TF_COND_CANNOT_SWITCH_FROM_MELEE);
#[doc(alias("TF_COND_COMPETITIVE_LOSER"))]
pub const COMPETITIVE_LOSER: Self = Self(sys::ETFCond_TF_COND_COMPETITIVE_LOSER);
#[doc(alias("TF_COND_COMPETITIVE_WINNER"))]
pub const COMPETITIVE_WINNER: Self = Self(sys::ETFCond_TF_COND_COMPETITIVE_WINNER);
#[doc(alias("TF_COND_CRITBOOSTED"))]
pub const CRITBOOSTED: Self = Self(sys::ETFCond_TF_COND_CRITBOOSTED);
#[doc(alias("TF_COND_CRITBOOSTED_BONUS_TIME"))]
pub const CRITBOOSTED_BONUS_TIME: Self = Self(sys::ETFCond_TF_COND_CRITBOOSTED_BONUS_TIME);
#[doc(alias("TF_COND_CRITBOOSTED_CARD_EFFECT"))]
pub const CRITBOOSTED_CARD_EFFECT: Self = Self(sys::ETFCond_TF_COND_CRITBOOSTED_CARD_EFFECT);
#[doc(alias("TF_COND_CRITBOOSTED_CTF_CAPTURE"))]
pub const CRITBOOSTED_CTF_CAPTURE: Self = Self(sys::ETFCond_TF_COND_CRITBOOSTED_CTF_CAPTURE);
#[doc(alias("TF_COND_CRITBOOSTED_DEMO_CHARGE"))]
pub const CRITBOOSTED_DEMO_CHARGE: Self = Self(sys::ETFCond_TF_COND_CRITBOOSTED_DEMO_CHARGE);
#[doc(alias("TF_COND_CRITBOOSTED_FIRST_BLOOD"))]
pub const CRITBOOSTED_FIRST_BLOOD: Self = Self(sys::ETFCond_TF_COND_CRITBOOSTED_FIRST_BLOOD);
#[doc(alias("TF_COND_CRITBOOSTED_ON_KILL"))]
pub const CRITBOOSTED_ON_KILL: Self = Self(sys::ETFCond_TF_COND_CRITBOOSTED_ON_KILL);
#[doc(alias("TF_COND_CRITBOOSTED_PUMPKIN"))]
pub const CRITBOOSTED_PUMPKIN: Self = Self(sys::ETFCond_TF_COND_CRITBOOSTED_PUMPKIN);
#[doc(alias("TF_COND_CRITBOOSTED_RAGE_BUFF"))]
pub const CRITBOOSTED_RAGE_BUFF: Self = Self(sys::ETFCond_TF_COND_CRITBOOSTED_RAGE_BUFF);
#[doc(alias("TF_COND_CRITBOOSTED_RUNE_TEMP"))]
pub const CRITBOOSTED_RUNE_TEMP: Self = Self(sys::ETFCond_TF_COND_CRITBOOSTED_RUNE_TEMP);
#[doc(alias("TF_COND_CRITBOOSTED_USER_BUFF"))]
pub const CRITBOOSTED_USER_BUFF: Self = Self(sys::ETFCond_TF_COND_CRITBOOSTED_USER_BUFF);
#[doc(alias("TF_COND_DEFENSEBUFF"))]
pub const DEFENSE_BUFF: Self = Self(sys::ETFCond_TF_COND_DEFENSEBUFF);
#[doc(alias("TF_COND_DEFENSEBUFF_HIGH"))]
pub const DEFENSE_BUFF_HIGH: Self = Self(sys::ETFCond_TF_COND_DEFENSEBUFF_HIGH);
#[doc(alias("TF_COND_DEFENSEBUFF_NO_CRIT_BLOCK"))]
pub const DEFENSE_BUFF_NO_CRIT_BLOCK: Self =
Self(sys::ETFCond_TF_COND_DEFENSEBUFF_NO_CRIT_BLOCK);
#[doc(alias("TF_COND_DEMO_BUFF"))]
pub const DEMO_BUFF: Self = Self(sys::ETFCond_TF_COND_DEMO_BUFF);
#[doc(alias("TF_COND_DISGUISE_WEARINGOFF"))]
pub const DISGUISE_WEARING_OFF: Self = Self(sys::ETFCond_TF_COND_DISGUISE_WEARINGOFF);
#[doc(alias("TF_COND_DISGUISED"))]
pub const DISGUISED: Self = Self(sys::ETFCond_TF_COND_DISGUISED);
#[doc(alias("TF_COND_DISGUISED_AS_DISPENSER"))]
pub const DISGUISED_AS_DISPENSER: Self = Self(sys::ETFCond_TF_COND_DISGUISED_AS_DISPENSER);
#[doc(alias("TF_COND_DISGUISING"))]
pub const DISGUISING: Self = Self(sys::ETFCond_TF_COND_DISGUISING);
#[doc(alias("TF_COND_DONOTUSE_0"))]
pub const DO_NOT_USE_0: Self = Self(sys::ETFCond_TF_COND_DONOTUSE_0);
#[doc(alias("TF_COND_ENERGY_BUFF"))]
pub const ENERGY_BUFF: Self = Self(sys::ETFCond_TF_COND_ENERGY_BUFF);
#[doc(alias("TF_COND_FEIGN_DEATH"))]
pub const FEIGN_DEATH: Self = Self(sys::ETFCond_TF_COND_FEIGN_DEATH);
#[doc(alias("TF_COND_FIRE_IMMUNE"))]
pub const FIRE_IMMUNE: Self = Self(sys::ETFCond_TF_COND_FIRE_IMMUNE);
#[doc(alias("TF_COND_FREEZE_INPUT"))]
pub const FREEZE_INPUT: Self = Self(sys::ETFCond_TF_COND_FREEZE_INPUT);
#[doc(alias("TF_COND_GAS"))]
pub const GAS: Self = Self(sys::ETFCond_TF_COND_GAS);
#[doc(alias("TF_COND_GRAPPLED_BY_PLAYER"))]
pub const GRAPPLED_BY_PLAYER: Self = Self(sys::ETFCond_TF_COND_GRAPPLED_BY_PLAYER);
#[doc(alias("TF_COND_GRAPPLED_TO_PLAYER"))]
pub const GRAPPLED_TO_PLAYER: Self = Self(sys::ETFCond_TF_COND_GRAPPLED_TO_PLAYER);
#[doc(alias("TF_COND_GRAPPLINGHOOK"))]
pub const GRAPPLING_HOOK: Self = Self(sys::ETFCond_TF_COND_GRAPPLINGHOOK);
#[doc(alias("TF_COND_GRAPPLINGHOOK_BLEEDING"))]
pub const GRAPPLING_HOOK_BLEEDING: Self = Self(sys::ETFCond_TF_COND_GRAPPLINGHOOK_BLEEDING);
#[doc(alias("TF_COND_GRAPPLINGHOOK_LATCHED"))]
pub const GRAPPLING_HOOK_LATCHED: Self = Self(sys::ETFCond_TF_COND_GRAPPLINGHOOK_LATCHED);
#[doc(alias("TF_COND_GRAPPLINGHOOK_SAFEFALL"))]
pub const GRAPPLING_HOOK_SAFE_FALL: Self = Self(sys::ETFCond_TF_COND_GRAPPLINGHOOK_SAFEFALL);
#[doc(alias("TF_COND_HALLOWEEN_BOMB_HEAD"))]
pub const HALLOWEEN_BOMB_HEAD: Self = Self(sys::ETFCond_TF_COND_HALLOWEEN_BOMB_HEAD);
#[doc(alias("TF_COND_HALLOWEEN_GHOST_MODE"))]
pub const HALLOWEEN_GHOST_MODE: Self = Self(sys::ETFCond_TF_COND_HALLOWEEN_GHOST_MODE);
#[doc(alias("TF_COND_HALLOWEEN_GIANT"))]
pub const HALLOWEEN_GIANT: Self = Self(sys::ETFCond_TF_COND_HALLOWEEN_GIANT);
#[doc(alias("TF_COND_HALLOWEEN_HELL_HEAL"))]
pub const HALLOWEEN_HELL_HEAL: Self = Self(sys::ETFCond_TF_COND_HALLOWEEN_HELL_HEAL);
#[doc(alias("TF_COND_HALLOWEEN_IN_HELL"))]
pub const HALLOWEEN_IN_HELL: Self = Self(sys::ETFCond_TF_COND_HALLOWEEN_IN_HELL);
#[doc(alias("TF_COND_HALLOWEEN_KART"))]
pub const HALLOWEEN_KART: Self = Self(sys::ETFCond_TF_COND_HALLOWEEN_KART);
#[doc(alias("TF_COND_HALLOWEEN_KART_CAGE"))]
pub const HALLOWEEN_KART_CAGE: Self = Self(sys::ETFCond_TF_COND_HALLOWEEN_KART_CAGE);
#[doc(alias("TF_COND_HALLOWEEN_KART_DASH"))]
pub const HALLOWEEN_KART_DASH: Self = Self(sys::ETFCond_TF_COND_HALLOWEEN_KART_DASH);
#[doc(alias("TF_COND_HALLOWEEN_QUICK_HEAL"))]
pub const HALLOWEEN_QUICK_HEAL: Self = Self(sys::ETFCond_TF_COND_HALLOWEEN_QUICK_HEAL);
#[doc(alias("TF_COND_HALLOWEEN_SPEED_BOOST"))]
pub const HALLOWEEN_SPEED_BOOST: Self = Self(sys::ETFCond_TF_COND_HALLOWEEN_SPEED_BOOST);
#[doc(alias("TF_COND_HALLOWEEN_THRILLER"))]
pub const HALLOWEEN_THRILLER: Self = Self(sys::ETFCond_TF_COND_HALLOWEEN_THRILLER);
#[doc(alias("TF_COND_HALLOWEEN_TINY"))]
pub const HALLOWEEN_TINY: Self = Self(sys::ETFCond_TF_COND_HALLOWEEN_TINY);
#[doc(alias("TF_COND_HEALING_DEBUFF"))]
pub const HEALING_DEBUFF: Self = Self(sys::ETFCond_TF_COND_HEALING_DEBUFF);
#[doc(alias("TF_COND_HEALTH_BUFF"))]
pub const HEALTH_BUFF: Self = Self(sys::ETFCond_TF_COND_HEALTH_BUFF);
#[doc(alias("TF_COND_HEALTH_OVERHEALED"))]
pub const HEALTH_OVERHEALED: Self = Self(sys::ETFCond_TF_COND_HEALTH_OVERHEALED);
#[doc(alias("TF_COND_IMMUNE_TO_PUSHBACK"))]
pub const IMMUNE_TO_PUSHBACK: Self = Self(sys::ETFCond_TF_COND_IMMUNE_TO_PUSHBACK);
#[doc(alias("TF_COND_INVULNERABLE"))]
pub const INVULNERABLE: Self = Self(sys::ETFCond_TF_COND_INVULNERABLE);
#[doc(alias("TF_COND_INVULNERABLE_CARD_EFFECT"))]
pub const INVULNERABLE_CARD_EFFECT: Self = Self(sys::ETFCond_TF_COND_INVULNERABLE_CARD_EFFECT);
#[doc(alias("TF_COND_INVULNERABLE_HIDE_UNLESS_DAMAGED"))]
pub const INVULNERABLE_HIDE_UNLESS_DAMAGED: Self =
Self(sys::ETFCond_TF_COND_INVULNERABLE_HIDE_UNLESS_DAMAGED);
#[doc(alias("TF_COND_INVULNERABLE_USER_BUFF"))]
pub const INVULNERABLE_USER_BUFF: Self = Self(sys::ETFCond_TF_COND_INVULNERABLE_USER_BUFF);
#[doc(alias("TF_COND_INVULNERABLE_WEARINGOFF"))]
pub const INVULNERABLE_WEARING_OFF: Self = Self(sys::ETFCond_TF_COND_INVULNERABLE_WEARINGOFF);
#[doc(alias("TF_COND_KING_BUFFED"))]
pub const KING_BUFFED: Self = Self(sys::ETFCond_TF_COND_KING_BUFFED);
#[doc(alias("TF_COND_KNOCKED_INTO_AIR"))]
pub const KNOCKED_INTO_AIR: Self = Self(sys::ETFCond_TF_COND_KNOCKED_INTO_AIR);
#[doc(alias("TF_COND_LOST_FOOTING"))]
pub const LOST_FOOTING: Self = Self(sys::ETFCond_TF_COND_LOST_FOOTING);
#[doc(alias("TF_COND_MAD_MILK"))]
pub const MAD_MILK: Self = Self(sys::ETFCond_TF_COND_MAD_MILK);
#[doc(alias("TF_COND_MARKEDFORDEATH"))]
pub const MARKED_FOR_DEATH: Self = Self(sys::ETFCond_TF_COND_MARKEDFORDEATH);
#[doc(alias("TF_COND_MARKEDFORDEATH_SILENT"))]
pub const MARKED_FOR_DEATH_SILENT: Self = Self(sys::ETFCond_TF_COND_MARKEDFORDEATH_SILENT);
#[doc(alias("TF_COND_MEDIGUN_DEBUFF"))]
pub const MEDIGUN_DEBUFF: Self = Self(sys::ETFCond_TF_COND_MEDIGUN_DEBUFF);
#[doc(alias("TF_COND_MEDIGUN_SMALL_BLAST_RESIST"))]
pub const MEDIGUN_SMALL_BLAST_RESIST: Self =
Self(sys::ETFCond_TF_COND_MEDIGUN_SMALL_BLAST_RESIST);
#[doc(alias("TF_COND_MEDIGUN_SMALL_BULLET_RESIST"))]
pub const MEDIGUN_SMALL_BULLET_RESIST: Self =
Self(sys::ETFCond_TF_COND_MEDIGUN_SMALL_BULLET_RESIST);
#[doc(alias("TF_COND_MEDIGUN_SMALL_FIRE_RESIST"))]
pub const MEDIGUN_SMALL_FIRE_RESIST: Self =
Self(sys::ETFCond_TF_COND_MEDIGUN_SMALL_FIRE_RESIST);
#[doc(alias("TF_COND_MEDIGUN_UBER_BLAST_RESIST"))]
pub const MEDIGUN_UBER_BLAST_RESIST: Self =
Self(sys::ETFCond_TF_COND_MEDIGUN_UBER_BLAST_RESIST);
#[doc(alias("TF_COND_MEDIGUN_UBER_BULLET_RESIST"))]
pub const MEDIGUN_UBER_BULLET_RESIST: Self =
Self(sys::ETFCond_TF_COND_MEDIGUN_UBER_BULLET_RESIST);
#[doc(alias("TF_COND_MEDIGUN_UBER_FIRE_RESIST"))]
pub const MEDIGUN_UBER_FIRE_RESIST: Self = Self(sys::ETFCond_TF_COND_MEDIGUN_UBER_FIRE_RESIST);
#[doc(alias("TF_COND_MEGAHEAL"))]
pub const MEGAHEAL: Self = Self(sys::ETFCond_TF_COND_MEGAHEAL);
#[doc(alias("TF_COND_MELEE_ONLY"))]
pub const MELEE_ONLY: Self = Self(sys::ETFCond_TF_COND_MELEE_ONLY);
#[doc(alias("TF_COND_MINICRITBOOSTED_ON_KILL"))]
pub const MINI_CRITBOOSTED_ON_KILL: Self = Self(sys::ETFCond_TF_COND_MINICRITBOOSTED_ON_KILL);
#[doc(alias("TF_COND_MVM_BOT_STUN_RADIOWAVE"))]
pub const MVM_BOT_STUN_RADIOWAVE: Self = Self(sys::ETFCond_TF_COND_MVM_BOT_STUN_RADIOWAVE);
#[doc(alias("TF_COND_NOHEALINGDAMAGEBUFF"))]
pub const NO_HEALING_DAMAGE_BUFF: Self = Self(sys::ETFCond_TF_COND_NOHEALINGDAMAGEBUFF);
#[doc(alias("TF_COND_OBSCURED_SMOKE"))]
pub const OBSCURED_SMOKE: Self = Self(sys::ETFCond_TF_COND_OBSCURED_SMOKE);
#[doc(alias("TF_COND_OFFENSEBUFF"))]
pub const OFFENSE_BUFF: Self = Self(sys::ETFCond_TF_COND_OFFENSEBUFF);
#[doc(alias("TF_COND_PARACHUTE_ACTIVE"))]
pub const PARACHUTE_ACTIVE: Self = Self(sys::ETFCond_TF_COND_PARACHUTE_ACTIVE);
#[doc(alias("TF_COND_PARACHUTE_DEPLOYED"))]
pub const PARACHUTE_DEPLOYED: Self = Self(sys::ETFCond_TF_COND_PARACHUTE_DEPLOYED);
#[doc(alias("TF_COND_PASSTIME_INTERCEPTION"))]
pub const PASSTIME_INTERCEPTION: Self = Self(sys::ETFCond_TF_COND_PASSTIME_INTERCEPTION);
#[doc(alias("TF_COND_PASSTIME_PENALTY_DEBUFF"))]
pub const PASSTIME_PENALTY_DEBUFF: Self = Self(sys::ETFCond_TF_COND_PASSTIME_PENALTY_DEBUFF);
#[doc(alias("TF_COND_PHASE"))]
pub const PHASE: Self = Self(sys::ETFCond_TF_COND_PHASE);
#[doc(alias("TF_COND_PLAGUE"))]
pub const PLAGUE: Self = Self(sys::ETFCond_TF_COND_PLAGUE);
#[doc(alias("TF_COND_POWERUPMODE_DOMINANT"))]
pub const POWERUP_MODE_DOMINANT: Self = Self(sys::ETFCond_TF_COND_POWERUPMODE_DOMINANT);
#[doc(alias("TF_COND_PREVENT_DEATH"))]
pub const PREVENT_DEATH: Self = Self(sys::ETFCond_TF_COND_PREVENT_DEATH);
#[doc(alias("TF_COND_PURGATORY"))]
pub const PURGATORY: Self = Self(sys::ETFCond_TF_COND_PURGATORY);
#[doc(alias("TF_COND_RADIUSHEAL"))]
pub const RADIUS_HEAL: Self = Self(sys::ETFCond_TF_COND_RADIUSHEAL);
#[doc(alias("TF_COND_RADIUSHEAL_ON_DAMAGE"))]
pub const RADIUS_HEAL_ON_DAMAGE: Self = Self(sys::ETFCond_TF_COND_RADIUSHEAL_ON_DAMAGE);
#[doc(alias("TF_COND_REGENONDAMAGEBUFF"))]
pub const REGEN_ON_DAMAGE_BUFF: Self = Self(sys::ETFCond_TF_COND_REGENONDAMAGEBUFF);
#[doc(alias("TF_COND_REPROGRAMMED"))]
pub const REPROGRAMMED: Self = Self(sys::ETFCond_TF_COND_REPROGRAMMED);
#[doc(alias("TF_COND_ROCKETPACK"))]
pub const ROCKET_PACK: Self = Self(sys::ETFCond_TF_COND_ROCKETPACK);
#[doc(alias("TF_COND_RUNE_AGILITY"))]
pub const RUNE_AGILITY: Self = Self(sys::ETFCond_TF_COND_RUNE_AGILITY);
#[doc(alias("TF_COND_RUNE_HASTE"))]
pub const RUNE_HASTE: Self = Self(sys::ETFCond_TF_COND_RUNE_HASTE);
#[doc(alias("TF_COND_RUNE_IMBALANCE"))]
pub const RUNE_IMBALANCE: Self = Self(sys::ETFCond_TF_COND_RUNE_IMBALANCE);
#[doc(alias("TF_COND_RUNE_KING"))]
pub const RUNE_KING: Self = Self(sys::ETFCond_TF_COND_RUNE_KING);
#[doc(alias("TF_COND_RUNE_KNOCKOUT"))]
pub const RUNE_KNOCKOUT: Self = Self(sys::ETFCond_TF_COND_RUNE_KNOCKOUT);
#[doc(alias("TF_COND_RUNE_PLAGUE"))]
pub const RUNE_PLAGUE: Self = Self(sys::ETFCond_TF_COND_RUNE_PLAGUE);
#[doc(alias("TF_COND_RUNE_PRECISION"))]
pub const RUNE_PRECISION: Self = Self(sys::ETFCond_TF_COND_RUNE_PRECISION);
#[doc(alias("TF_COND_RUNE_REFLECT"))]
pub const RUNE_REFLECT: Self = Self(sys::ETFCond_TF_COND_RUNE_REFLECT);
#[doc(alias("TF_COND_RUNE_REGEN"))]
pub const RUNE_REGEN: Self = Self(sys::ETFCond_TF_COND_RUNE_REGEN);
#[doc(alias("TF_COND_RUNE_RESIST"))]
pub const RUNE_RESIST: Self = Self(sys::ETFCond_TF_COND_RUNE_RESIST);
#[doc(alias("TF_COND_RUNE_STRENGTH"))]
pub const RUNE_STRENGTH: Self = Self(sys::ETFCond_TF_COND_RUNE_STRENGTH);
#[doc(alias("TF_COND_RUNE_SUPERNOVA"))]
pub const RUNE_SUPERNOVA: Self = Self(sys::ETFCond_TF_COND_RUNE_SUPERNOVA);
#[doc(alias("TF_COND_RUNE_VAMPIRE"))]
pub const RUNE_VAMPIRE: Self = Self(sys::ETFCond_TF_COND_RUNE_VAMPIRE);
#[doc(alias("TF_COND_SAPPED"))]
pub const SAPPED: Self = Self(sys::ETFCond_TF_COND_SAPPED);
#[doc(alias("TF_COND_SELECTED_TO_TELEPORT"))]
pub const SELECTED_TO_TELEPORT: Self = Self(sys::ETFCond_TF_COND_SELECTED_TO_TELEPORT);
#[doc(alias("TF_COND_SHIELD_CHARGE"))]
pub const SHIELD_CHARGE: Self = Self(sys::ETFCond_TF_COND_SHIELD_CHARGE);
#[doc(alias("TF_COND_SNIPERCHARGE_RAGE_BUFF"))]
pub const SNIPER_CHARGE_RAGE_BUFF: Self = Self(sys::ETFCond_TF_COND_SNIPERCHARGE_RAGE_BUFF);
#[doc(alias("TF_COND_SODAPOPPER_HYPE"))]
pub const SODA_POPPER_HYPE: Self = Self(sys::ETFCond_TF_COND_SODAPOPPER_HYPE);
#[doc(alias("TF_COND_SPEED_BOOST"))]
pub const SPEED_BOOST: Self = Self(sys::ETFCond_TF_COND_SPEED_BOOST);
#[doc(alias("TF_COND_STEALTHED"))]
pub const STEALTHED: Self = Self(sys::ETFCond_TF_COND_STEALTHED);
#[doc(alias("TF_COND_STEALTHED_BLINK"))]
pub const STEALTHED_BLINK: Self = Self(sys::ETFCond_TF_COND_STEALTHED_BLINK);
#[doc(alias("TF_COND_STEALTHED_USER_BUFF"))]
pub const STEALTHED_USER_BUFF: Self = Self(sys::ETFCond_TF_COND_STEALTHED_USER_BUFF);
#[doc(alias("TF_COND_STEALTHED_USER_BUFF_FADING"))]
pub const STEALTHED_USER_BUFF_FADING: Self =
Self(sys::ETFCond_TF_COND_STEALTHED_USER_BUFF_FADING);
#[doc(alias("TF_COND_STUNNED"))]
pub const STUNNED: Self = Self(sys::ETFCond_TF_COND_STUNNED);
#[doc(alias("TF_COND_SWIMMING_CURSE"))]
pub const SWIMMING_CURSE: Self = Self(sys::ETFCond_TF_COND_SWIMMING_CURSE);
#[doc(alias("TF_COND_SWIMMING_NO_EFFECTS"))]
pub const SWIMMING_NO_EFFECTS: Self = Self(sys::ETFCond_TF_COND_SWIMMING_NO_EFFECTS);
#[doc(alias("TF_COND_TAUNTING"))]
pub const TAUNTING: Self = Self(sys::ETFCond_TF_COND_TAUNTING);
#[doc(alias("TF_COND_TEAM_GLOWS"))]
pub const TEAM_GLOWS: Self = Self(sys::ETFCond_TF_COND_TEAM_GLOWS);
#[doc(alias("TF_COND_TELEPORTED"))]
pub const TELEPORTED: Self = Self(sys::ETFCond_TF_COND_TELEPORTED);
#[doc(alias("TF_COND_TMPDAMAGEBONUS"))]
pub const TEMPORARY_DAMAGE_BONUS: Self = Self(sys::ETFCond_TF_COND_TMPDAMAGEBONUS);
#[doc(alias("TF_COND_URINE"))]
pub const URINE: Self = Self(sys::ETFCond_TF_COND_URINE);
#[doc(alias("TF_COND_ZOOMED"))]
pub const ZOOMED: Self = Self(sys::ETFCond_TF_COND_ZOOMED);
pub fn all() -> impl ExactSizeIterator<Item = Self> + DoubleEndedIterator {
(0..sys::ETFCond_TF_COND_LAST).map(Self)
}
pub const fn from_raw(raw: sys::ETFCond) -> Option<Self> {
if raw >= 0 && raw < sys::ETFCond_TF_COND_LAST {
Some(Self(raw))
} else {
None
}
}
#[doc(alias("GetTFConditionName"))]
pub const fn name(self) -> &'static str {
match self.0 {
sys::ETFCond_TF_COND_AIMING => "TF_COND_AIMING",
sys::ETFCond_TF_COND_ZOOMED => "TF_COND_ZOOMED",
sys::ETFCond_TF_COND_DISGUISING => "TF_COND_DISGUISING",
sys::ETFCond_TF_COND_DISGUISED => "TF_COND_DISGUISED",
sys::ETFCond_TF_COND_STEALTHED => "TF_COND_STEALTHED",
sys::ETFCond_TF_COND_INVULNERABLE => "TF_COND_INVULNERABLE",
sys::ETFCond_TF_COND_TELEPORTED => "TF_COND_TELEPORTED",
sys::ETFCond_TF_COND_TAUNTING => "TF_COND_TAUNTING",
sys::ETFCond_TF_COND_INVULNERABLE_WEARINGOFF => "TF_COND_INVULNERABLE_WEARINGOFF",
sys::ETFCond_TF_COND_STEALTHED_BLINK => "TF_COND_STEALTHED_BLINK",
sys::ETFCond_TF_COND_SELECTED_TO_TELEPORT => "TF_COND_SELECTED_TO_TELEPORT",
sys::ETFCond_TF_COND_CRITBOOSTED => "TF_COND_CRITBOOSTED",
sys::ETFCond_TF_COND_TMPDAMAGEBONUS => "TF_COND_TMPDAMAGEBONUS",
sys::ETFCond_TF_COND_FEIGN_DEATH => "TF_COND_FEIGN_DEATH",
sys::ETFCond_TF_COND_PHASE => "TF_COND_PHASE",
sys::ETFCond_TF_COND_STUNNED => "TF_COND_STUNNED",
sys::ETFCond_TF_COND_OFFENSEBUFF => "TF_COND_OFFENSEBUFF",
sys::ETFCond_TF_COND_SHIELD_CHARGE => "TF_COND_SHIELD_CHARGE",
sys::ETFCond_TF_COND_DEMO_BUFF => "TF_COND_DEMO_BUFF",
sys::ETFCond_TF_COND_ENERGY_BUFF => "TF_COND_ENERGY_BUFF",
sys::ETFCond_TF_COND_RADIUSHEAL => "TF_COND_RADIUSHEAL",
sys::ETFCond_TF_COND_HEALTH_BUFF => "TF_COND_HEALTH_BUFF",
sys::ETFCond_TF_COND_BURNING => "TF_COND_BURNING",
sys::ETFCond_TF_COND_HEALTH_OVERHEALED => "TF_COND_HEALTH_OVERHEALED",
sys::ETFCond_TF_COND_URINE => "TF_COND_URINE",
sys::ETFCond_TF_COND_BLEEDING => "TF_COND_BLEEDING",
sys::ETFCond_TF_COND_DEFENSEBUFF => "TF_COND_DEFENSEBUFF",
sys::ETFCond_TF_COND_MAD_MILK => "TF_COND_MAD_MILK",
sys::ETFCond_TF_COND_MEGAHEAL => "TF_COND_MEGAHEAL",
sys::ETFCond_TF_COND_REGENONDAMAGEBUFF => "TF_COND_REGENONDAMAGEBUFF",
sys::ETFCond_TF_COND_MARKEDFORDEATH => "TF_COND_MARKEDFORDEATH",
sys::ETFCond_TF_COND_NOHEALINGDAMAGEBUFF => "TF_COND_NOHEALINGDAMAGEBUFF",
sys::ETFCond_TF_COND_SPEED_BOOST => "TF_COND_SPEED_BOOST",
sys::ETFCond_TF_COND_CRITBOOSTED_PUMPKIN => "TF_COND_CRITBOOSTED_PUMPKIN",
sys::ETFCond_TF_COND_CRITBOOSTED_USER_BUFF => "TF_COND_CRITBOOSTED_USER_BUFF",
sys::ETFCond_TF_COND_CRITBOOSTED_DEMO_CHARGE => "TF_COND_CRITBOOSTED_DEMO_CHARGE",
sys::ETFCond_TF_COND_SODAPOPPER_HYPE => "TF_COND_SODAPOPPER_HYPE",
sys::ETFCond_TF_COND_CRITBOOSTED_FIRST_BLOOD => "TF_COND_CRITBOOSTED_FIRST_BLOOD",
sys::ETFCond_TF_COND_CRITBOOSTED_BONUS_TIME => "TF_COND_CRITBOOSTED_BONUS_TIME",
sys::ETFCond_TF_COND_CRITBOOSTED_CTF_CAPTURE => "TF_COND_CRITBOOSTED_CTF_CAPTURE",
sys::ETFCond_TF_COND_CRITBOOSTED_ON_KILL => "TF_COND_CRITBOOSTED_ON_KILL",
sys::ETFCond_TF_COND_CANNOT_SWITCH_FROM_MELEE => "TF_COND_CANNOT_SWITCH_FROM_MELEE",
sys::ETFCond_TF_COND_DEFENSEBUFF_NO_CRIT_BLOCK => "TF_COND_DEFENSEBUFF_NO_CRIT_BLOCK",
sys::ETFCond_TF_COND_REPROGRAMMED => "TF_COND_REPROGRAMMED",
sys::ETFCond_TF_COND_CRITBOOSTED_RAGE_BUFF => "TF_COND_CRITBOOSTED_RAGE_BUFF",
sys::ETFCond_TF_COND_DEFENSEBUFF_HIGH => "TF_COND_DEFENSEBUFF_HIGH",
sys::ETFCond_TF_COND_SNIPERCHARGE_RAGE_BUFF => "TF_COND_SNIPERCHARGE_RAGE_BUFF",
sys::ETFCond_TF_COND_DISGUISE_WEARINGOFF => "TF_COND_DISGUISE_WEARINGOFF",
sys::ETFCond_TF_COND_MARKEDFORDEATH_SILENT => "TF_COND_MARKEDFORDEATH_SILENT",
sys::ETFCond_TF_COND_DISGUISED_AS_DISPENSER => "TF_COND_DISGUISED_AS_DISPENSER",
sys::ETFCond_TF_COND_SAPPED => "TF_COND_SAPPED",
sys::ETFCond_TF_COND_INVULNERABLE_HIDE_UNLESS_DAMAGED => {
"TF_COND_INVULNERABLE_HIDE_UNLESS_DAMAGED"
}
sys::ETFCond_TF_COND_INVULNERABLE_USER_BUFF => "TF_COND_INVULNERABLE_USER_BUFF",
sys::ETFCond_TF_COND_HALLOWEEN_BOMB_HEAD => "TF_COND_HALLOWEEN_BOMB_HEAD",
sys::ETFCond_TF_COND_HALLOWEEN_THRILLER => "TF_COND_HALLOWEEN_THRILLER",
sys::ETFCond_TF_COND_RADIUSHEAL_ON_DAMAGE => "TF_COND_RADIUSHEAL_ON_DAMAGE",
sys::ETFCond_TF_COND_CRITBOOSTED_CARD_EFFECT => "TF_COND_CRITBOOSTED_CARD_EFFECT",
sys::ETFCond_TF_COND_INVULNERABLE_CARD_EFFECT => "TF_COND_INVULNERABLE_CARD_EFFECT",
sys::ETFCond_TF_COND_MEDIGUN_UBER_BULLET_RESIST => "TF_COND_MEDIGUN_UBER_BULLET_RESIST",
sys::ETFCond_TF_COND_MEDIGUN_UBER_BLAST_RESIST => "TF_COND_MEDIGUN_UBER_BLAST_RESIST",
sys::ETFCond_TF_COND_MEDIGUN_UBER_FIRE_RESIST => "TF_COND_MEDIGUN_UBER_FIRE_RESIST",
sys::ETFCond_TF_COND_MEDIGUN_SMALL_BULLET_RESIST => {
"TF_COND_MEDIGUN_SMALL_BULLET_RESIST"
}
sys::ETFCond_TF_COND_MEDIGUN_SMALL_BLAST_RESIST => "TF_COND_MEDIGUN_SMALL_BLAST_RESIST",
sys::ETFCond_TF_COND_MEDIGUN_SMALL_FIRE_RESIST => "TF_COND_MEDIGUN_SMALL_FIRE_RESIST",
sys::ETFCond_TF_COND_STEALTHED_USER_BUFF => "TF_COND_STEALTHED_USER_BUFF",
sys::ETFCond_TF_COND_MEDIGUN_DEBUFF => "TF_COND_MEDIGUN_DEBUFF",
sys::ETFCond_TF_COND_STEALTHED_USER_BUFF_FADING => "TF_COND_STEALTHED_USER_BUFF_FADING",
sys::ETFCond_TF_COND_BULLET_IMMUNE => "TF_COND_BULLET_IMMUNE",
sys::ETFCond_TF_COND_BLAST_IMMUNE => "TF_COND_BLAST_IMMUNE",
sys::ETFCond_TF_COND_FIRE_IMMUNE => "TF_COND_FIRE_IMMUNE",
sys::ETFCond_TF_COND_PREVENT_DEATH => "TF_COND_PREVENT_DEATH",
sys::ETFCond_TF_COND_MVM_BOT_STUN_RADIOWAVE => "TF_COND_MVM_BOT_STUN_RADIOWAVE",
sys::ETFCond_TF_COND_HALLOWEEN_SPEED_BOOST => "TF_COND_HALLOWEEN_SPEED_BOOST",
sys::ETFCond_TF_COND_HALLOWEEN_QUICK_HEAL => "TF_COND_HALLOWEEN_QUICK_HEAL",
sys::ETFCond_TF_COND_HALLOWEEN_GIANT => "TF_COND_HALLOWEEN_GIANT",
sys::ETFCond_TF_COND_HALLOWEEN_TINY => "TF_COND_HALLOWEEN_TINY",
sys::ETFCond_TF_COND_HALLOWEEN_IN_HELL => "TF_COND_HALLOWEEN_IN_HELL",
sys::ETFCond_TF_COND_HALLOWEEN_GHOST_MODE => "TF_COND_HALLOWEEN_GHOST_MODE",
sys::ETFCond_TF_COND_MINICRITBOOSTED_ON_KILL => "TF_COND_MINICRITBOOSTED_ON_KILL",
sys::ETFCond_TF_COND_OBSCURED_SMOKE => "TF_COND_OBSCURED_SMOKE",
sys::ETFCond_TF_COND_PARACHUTE_ACTIVE => "TF_COND_PARACHUTE_ACTIVE",
sys::ETFCond_TF_COND_BLASTJUMPING => "TF_COND_BLASTJUMPING",
sys::ETFCond_TF_COND_HALLOWEEN_KART => "TF_COND_HALLOWEEN_KART",
sys::ETFCond_TF_COND_HALLOWEEN_KART_DASH => "TF_COND_HALLOWEEN_KART_DASH",
sys::ETFCond_TF_COND_BALLOON_HEAD => "TF_COND_BALLOON_HEAD",
sys::ETFCond_TF_COND_MELEE_ONLY => "TF_COND_MELEE_ONLY",
sys::ETFCond_TF_COND_SWIMMING_CURSE => "TF_COND_SWIMMING_CURSE",
sys::ETFCond_TF_COND_FREEZE_INPUT => "TF_COND_FREEZE_INPUT",
sys::ETFCond_TF_COND_HALLOWEEN_KART_CAGE => "TF_COND_HALLOWEEN_KART_CAGE",
sys::ETFCond_TF_COND_DONOTUSE_0 => "TF_COND_DONOTUSE_0",
sys::ETFCond_TF_COND_RUNE_STRENGTH => "TF_COND_RUNE_STRENGTH",
sys::ETFCond_TF_COND_RUNE_HASTE => "TF_COND_RUNE_HASTE",
sys::ETFCond_TF_COND_RUNE_REGEN => "TF_COND_RUNE_REGEN",
sys::ETFCond_TF_COND_RUNE_RESIST => "TF_COND_RUNE_RESIST",
sys::ETFCond_TF_COND_RUNE_VAMPIRE => "TF_COND_RUNE_VAMPIRE",
sys::ETFCond_TF_COND_RUNE_REFLECT => "TF_COND_RUNE_REFLECT",
sys::ETFCond_TF_COND_RUNE_PRECISION => "TF_COND_RUNE_PRECISION",
sys::ETFCond_TF_COND_RUNE_AGILITY => "TF_COND_RUNE_AGILITY",
sys::ETFCond_TF_COND_GRAPPLINGHOOK => "TF_COND_GRAPPLINGHOOK",
sys::ETFCond_TF_COND_GRAPPLINGHOOK_SAFEFALL => "TF_COND_GRAPPLINGHOOK_SAFEFALL",
sys::ETFCond_TF_COND_GRAPPLINGHOOK_LATCHED => "TF_COND_GRAPPLINGHOOK_LATCHED",
sys::ETFCond_TF_COND_GRAPPLINGHOOK_BLEEDING => "TF_COND_GRAPPLINGHOOK_BLEEDING",
sys::ETFCond_TF_COND_AFTERBURN_IMMUNE => "TF_COND_AFTERBURN_IMMUNE",
sys::ETFCond_TF_COND_RUNE_KNOCKOUT => "TF_COND_RUNE_KNOCKOUT",
sys::ETFCond_TF_COND_RUNE_IMBALANCE => "TF_COND_RUNE_IMBALANCE",
sys::ETFCond_TF_COND_CRITBOOSTED_RUNE_TEMP => "TF_COND_CRITBOOSTED_RUNE_TEMP",
sys::ETFCond_TF_COND_PASSTIME_INTERCEPTION => "TF_COND_PASSTIME_INTERCEPTION",
sys::ETFCond_TF_COND_SWIMMING_NO_EFFECTS => "TF_COND_SWIMMING_NO_EFFECTS",
sys::ETFCond_TF_COND_PURGATORY => "TF_COND_PURGATORY",
sys::ETFCond_TF_COND_RUNE_KING => "TF_COND_RUNE_KING",
sys::ETFCond_TF_COND_RUNE_PLAGUE => "TF_COND_RUNE_PLAGUE",
sys::ETFCond_TF_COND_RUNE_SUPERNOVA => "TF_COND_RUNE_SUPERNOVA",
sys::ETFCond_TF_COND_PLAGUE => "TF_COND_PLAGUE",
sys::ETFCond_TF_COND_KING_BUFFED => "TF_COND_KING_BUFFED",
sys::ETFCond_TF_COND_TEAM_GLOWS => "TF_COND_TEAM_GLOWS",
sys::ETFCond_TF_COND_KNOCKED_INTO_AIR => "TF_COND_KNOCKED_INTO_AIR",
sys::ETFCond_TF_COND_COMPETITIVE_WINNER => "TF_COND_COMPETITIVE_WINNER",
sys::ETFCond_TF_COND_COMPETITIVE_LOSER => "TF_COND_COMPETITIVE_LOSER",
sys::ETFCond_TF_COND_HEALING_DEBUFF => "TF_COND_HEALING_DEBUFF",
sys::ETFCond_TF_COND_PASSTIME_PENALTY_DEBUFF => "TF_COND_PASSTIME_PENALTY_DEBUFF",
sys::ETFCond_TF_COND_GRAPPLED_TO_PLAYER => "TF_COND_GRAPPLED_TO_PLAYER",
sys::ETFCond_TF_COND_GRAPPLED_BY_PLAYER => "TF_COND_GRAPPLED_BY_PLAYER",
sys::ETFCond_TF_COND_PARACHUTE_DEPLOYED => "TF_COND_PARACHUTE_DEPLOYED",
sys::ETFCond_TF_COND_GAS => "TF_COND_GAS",
sys::ETFCond_TF_COND_BURNING_PYRO => "TF_COND_BURNING_PYRO",
sys::ETFCond_TF_COND_ROCKETPACK => "TF_COND_ROCKETPACK",
sys::ETFCond_TF_COND_LOST_FOOTING => "TF_COND_LOST_FOOTING",
sys::ETFCond_TF_COND_AIR_CURRENT => "TF_COND_AIR_CURRENT",
sys::ETFCond_TF_COND_HALLOWEEN_HELL_HEAL => "TF_COND_HALLOWEEN_HELL_HEAL",
sys::ETFCond_TF_COND_POWERUPMODE_DOMINANT => "TF_COND_POWERUPMODE_DOMINANT",
sys::ETFCond_TF_COND_IMMUNE_TO_PUSHBACK => "TF_COND_IMMUNE_TO_PUSHBACK",
_ => unreachable!(),
}
}
#[doc(alias("GetTFConditionFromName"))]
pub fn from_name(name: &str) -> Option<Self> {
Self::all().find(|condition| condition.name().eq_ignore_ascii_case(name))
}
pub const fn to_raw(self) -> sys::ETFCond {
self.0
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct ConditionDuration(f32);
impl ConditionDuration {
#[doc(alias("PERMANENT_CONDITION"))]
pub const PERMANENT: Self = Self(raw::PERMANENT_CONDITION);
pub fn seconds(seconds: f32) -> Option<Self> {
(seconds.is_finite() && seconds >= 0.0).then_some(Self(seconds))
}
pub const fn as_raw(self) -> f32 {
self.0
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)]
pub enum ConditionError {
#[error("conditions require a TF2 player")]
NotTfPlayer,
#[error("the game does not expose the expected native condition method")]
UnsupportedMethod,
#[error("the native condition method rejected its arguments")]
Rejected,
#[error("the player's condition bits could not be located")]
UnsupportedLayout,
#[error("the condition's provider has no script instance: {0}")]
Provider(#[source] ScriptInstanceError),
}
impl From<BindingError> for ConditionError {
fn from(error: BindingError) -> Self {
match error {
BindingError::Unavailable | BindingError::SignatureMismatch => Self::UnsupportedMethod,
BindingError::Rejected => Self::Rejected,
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct PlayerConditions<'s> {
server: Server<'s>,
player: Entity<'s>,
}
impl<'s> PlayerConditions<'s> {
pub fn new(server: Server<'s>, player: Entity<'s>) -> Result<Self, ConditionError> {
if !player_methods::is_tf_player(server, player) {
return Err(ConditionError::NotTfPlayer);
}
Ok(Self { server, player })
}
#[doc(alias("AddCond", "AddCondEx"))]
pub fn add(
self,
condition: Condition,
duration: ConditionDuration,
) -> Result<bool, ConditionError> {
self.add_raw(condition, duration, std::ptr::null_mut())
}
fn add_raw(
self,
condition: Condition,
duration: ConditionDuration,
provider: sys::HSCRIPT,
) -> Result<bool, ConditionError> {
unsafe { raw::add_cond_ex(self.raw_player(), condition.0, duration.0, provider) }?;
self.in_cond(condition)
}
#[doc(alias("AddCondEx", "GetConditionProvider"))]
pub fn add_with_provider(
self,
condition: Condition,
duration: ConditionDuration,
provider: Entity<'s>,
) -> Result<bool, ConditionError> {
let provider =
ScriptInstance::of(self.server, provider).map_err(ConditionError::Provider)?;
self.add_raw(condition, duration, provider.as_raw())
}
#[doc(alias("m_nPlayerCond", "m_nPlayerCondEx", "_condition_bits"))]
pub fn bits(self) -> Result<ConditionBits, ConditionError> {
let class = self
.player
.server_class()
.ok_or(ConditionError::UnsupportedLayout)?;
let layout = ConditionLayout::of(self.server, class)?;
Ok(unsafe { layout.read(self.player) })
}
#[doc(alias("CanBeDebuffed"))]
pub fn can_be_debuffed(self) -> Result<bool, ConditionError> {
self.predicate(c"CanBeDebuffed")
}
pub fn cleanse(self, conditions: ConditionBits) -> Result<ConditionBits, ConditionError> {
let mut removed = ConditionBits::EMPTY;
for condition in self.bits()?.intersection(conditions).iter() {
if self.remove(condition, true)? {
removed.insert(condition);
}
}
Ok(removed)
}
#[doc(alias("GetCondDuration"))]
pub fn duration(self, condition: Condition) -> Result<ConditionDuration, ConditionError> {
let seconds = unsafe { raw::get_cond_duration(self.raw_player(), condition.0) }?;
if seconds < 0.0 {
Ok(ConditionDuration::PERMANENT)
} else {
ConditionDuration::seconds(seconds).ok_or(ConditionError::Rejected)
}
}
#[doc(alias("InCond"))]
pub fn in_cond(self, condition: Condition) -> Result<bool, ConditionError> {
Ok(unsafe { raw::in_cond(self.raw_player(), condition.0) }?)
}
#[doc(alias("IsControlStunned"))]
pub fn is_control_stunned(self) -> Result<bool, ConditionError> {
self.predicate(c"IsControlStunned")
}
#[doc(alias("IsCritBoosted"))]
pub fn is_crit_boosted(self) -> Result<bool, ConditionError> {
self.predicate(c"IsCritBoosted")
}
#[doc(alias("IsFullyInvisible"))]
pub fn is_fully_invisible(self) -> Result<bool, ConditionError> {
self.predicate(c"IsFullyInvisible")
}
#[doc(alias("IsImmuneToPushback"))]
pub fn is_immune_to_pushback(self) -> Result<bool, ConditionError> {
self.predicate(c"IsImmuneToPushback")
}
#[doc(alias("IsInvulnerable"))]
pub fn is_invulnerable(self) -> Result<bool, ConditionError> {
self.predicate(c"IsInvulnerable")
}
#[doc(alias("IsSnared"))]
pub fn is_snared(self) -> Result<bool, ConditionError> {
self.predicate(c"IsSnared")
}
#[doc(alias("IsStealthed"))]
pub fn is_stealthed(self) -> Result<bool, ConditionError> {
self.predicate(c"IsStealthed")
}
pub const fn player(self) -> Entity<'s> {
self.player
}
fn predicate(self, method: &CStr) -> Result<bool, ConditionError> {
Ok(unsafe { player_methods::call_bool(self.player, method, &mut []) }?)
}
fn raw_player(self) -> NonNull<sys::CBaseEntity> {
unsafe { NonNull::new_unchecked(self.player.as_ptr()) }
}
#[doc(alias("RemoveCond", "RemoveCondEx"))]
pub fn remove(
self,
condition: Condition,
ignore_duration: bool,
) -> Result<bool, ConditionError> {
unsafe { raw::remove_cond_ex(self.raw_player(), condition.0, ignore_duration) }?;
Ok(!self.in_cond(condition)?)
}
#[doc(alias("RemoveAllCond"))]
pub fn remove_all(self) -> Result<(), ConditionError> {
unsafe { raw::remove_all_cond(self.raw_player()) }?;
Ok(())
}
#[doc(alias("SetCondDuration"))]
pub fn set_duration(
self,
condition: Condition,
duration: ConditionDuration,
) -> Result<bool, ConditionError> {
if condition == Condition::CRITBOOSTED || !self.in_cond(condition)? {
return Ok(false);
}
unsafe { raw::set_cond_duration(self.raw_player(), condition.0, duration.0) }?;
Ok(true)
}
}
thread_local! {
static LAYOUT: Cell<Option<ConditionLayout>> = const { Cell::new(None) };
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
pub struct ConditionBits([u32; WORDS]);
impl ConditionBits {
#[doc(alias("g_aDebuffConditions"))]
pub const DEBUFFS: Self = Self::of(&[
Condition::BURNING,
Condition::URINE,
Condition::BLEEDING,
Condition::MAD_MILK,
Condition::GAS,
]);
pub const EMPTY: Self = Self([0; WORDS]);
pub const fn of(conditions: &[Condition]) -> Self {
let mut bits = Self::EMPTY;
let mut index = 0;
while index < conditions.len() {
bits.insert(conditions[index]);
index += 1;
}
bits
}
const fn position(condition: Condition) -> (usize, u32) {
let raw = condition.0 as usize;
(raw / 32, 1 << (raw % 32))
}
pub const fn changes_since(self, previous: Self) -> ConditionChanges {
ConditionChanges {
added: self.difference(previous),
removed: previous.difference(self),
}
}
pub const fn contains(self, condition: Condition) -> bool {
let (word, bit) = Self::position(condition);
self.0[word] & bit != 0
}
pub const fn difference(self, other: Self) -> Self {
let mut words = self.0;
let mut word = 0;
while word < WORDS {
words[word] &= !other.0[word];
word += 1;
}
Self(words)
}
pub const fn insert(&mut self, condition: Condition) -> bool {
let (word, bit) = Self::position(condition);
let lacked = self.0[word] & bit == 0;
self.0[word] |= bit;
lacked
}
pub const fn intersection(self, other: Self) -> Self {
let mut words = self.0;
let mut word = 0;
while word < WORDS {
words[word] &= other.0[word];
word += 1;
}
Self(words)
}
pub const fn is_empty(self) -> bool {
let mut word = 0;
while word < WORDS {
if self.0[word] != 0 {
return false;
}
word += 1;
}
true
}
pub fn iter(self) -> impl Iterator<Item = Condition> {
Condition::all().filter(move |&condition| self.contains(condition))
}
pub const fn len(self) -> usize {
let mut count = 0;
let mut word = 0;
while word < WORDS {
count += self.0[word].count_ones() as usize;
word += 1;
}
count
}
pub const fn remove(&mut self, condition: Condition) -> bool {
let (word, bit) = Self::position(condition);
let held = self.0[word] & bit != 0;
self.0[word] &= !bit;
held
}
pub const fn union(self, other: Self) -> Self {
let mut words = self.0;
let mut word = 0;
while word < WORDS {
words[word] |= other.0[word];
word += 1;
}
Self(words)
}
}
impl Extend<Condition> for ConditionBits {
fn extend<I: IntoIterator<Item = Condition>>(&mut self, conditions: I) {
for condition in conditions {
self.insert(condition);
}
}
}
impl FromIterator<Condition> for ConditionBits {
fn from_iter<I: IntoIterator<Item = Condition>>(conditions: I) -> Self {
let mut bits = Self::EMPTY;
bits.extend(conditions);
bits
}
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
pub struct ConditionChanges {
pub added: ConditionBits,
pub removed: ConditionBits,
}
impl ConditionChanges {
pub const fn is_empty(self) -> bool {
self.added.is_empty() && self.removed.is_empty()
}
}
#[derive(Debug, Clone, Copy)]
struct ConditionLayout {
class: usize,
list: usize,
words: [usize; WORDS],
}
impl ConditionLayout {
fn of(server: Server<'_>, class: ServerClass<'_>) -> Result<Self, ConditionError> {
if let Some(layout) = LAYOUT.get()
&& layout.class == class.as_ptr().addr()
{
return Ok(layout);
}
let layout = Self::resolve(server, class)?;
LAYOUT.set(Some(layout));
Ok(layout)
}
fn resolve(server: Server<'_>, class: ServerClass<'_>) -> Result<Self, ConditionError> {
let dll = server
.server_game_dll()
.map_err(|_| ConditionError::UnsupportedLayout)?;
let offset = |name: &CStr| match dll.net_prop(class, name) {
Ok(variable) if variable.storage().is_compatible(Storage::U32) => Ok(variable.offset()),
_ => Err(ConditionError::UnsupportedLayout),
};
let mut words = [0; WORDS];
for (word, name) in words.iter_mut().zip(WORD_NAMES) {
*word = offset(name)?;
}
Ok(Self {
class: class.as_ptr().addr(),
list: offset(c"_condition_bits")?,
words,
})
}
unsafe fn read(self, player: Entity<'_>) -> ConditionBits {
let read = |offset: usize| {
unsafe {
player
.as_ptr()
.cast::<u8>()
.add(offset)
.cast::<u32>()
.read_unaligned()
}
};
let mut words = self.words.map(read);
words[0] |= read(self.list);
ConditionBits(words)
}
}
#[derive(Debug, Default, Clone)]
pub struct ConditionWatcher {
previous: HashMap<EntityHandle, ConditionBits>,
}
impl ConditionWatcher {
pub fn new() -> Self {
Self::default()
}
pub fn clear(&mut self) {
self.previous.clear();
}
pub fn forget(&mut self, player: Entity<'_>) {
self.previous.remove(&player.handle());
}
pub fn update(
&mut self,
conditions: PlayerConditions<'_>,
) -> Result<ConditionChanges, ConditionError> {
let current = conditions.bits()?;
let previous = self
.previous
.insert(conditions.player().handle(), current)
.unwrap_or_default();
Ok(current.changes_since(previous))
}
}